diff --git a/apps/web/public/schema.json b/apps/web/public/schema.json
index a25172e8..74cfc9d8 100644
--- a/apps/web/public/schema.json
+++ b/apps/web/public/schema.json
@@ -35,6 +35,11 @@
"format": "uri",
"description": "Optional URL to the source code of the project (eg, GitHub repo)."
},
+ "websiteUrl": {
+ "type": "string",
+ "format": "uri",
+ "description": "Optional URL to the product's website."
+ },
"origin": {
"anyOf": [
{
diff --git a/apps/web/src/app/marketplace/projects/[namespace]/[project-slug]/marketplace-project-index.tsx b/apps/web/src/app/marketplace/projects/[namespace]/[project-slug]/marketplace-project-index.tsx
index 844de0b1..4cf076aa 100644
--- a/apps/web/src/app/marketplace/projects/[namespace]/[project-slug]/marketplace-project-index.tsx
+++ b/apps/web/src/app/marketplace/projects/[namespace]/[project-slug]/marketplace-project-index.tsx
@@ -1,6 +1,8 @@
'use client'
import { assert, omit, sanitizeSearchParams } from '@agentic/platform-core'
+import { ExternalLinkIcon } from 'lucide-react'
+import Link from 'next/link'
import { useRouter, useSearchParams } from 'next/navigation'
import { useCallback, useEffect, useRef, useState } from 'react'
@@ -8,6 +10,7 @@ import { useAgentic } from '@/components/agentic-provider'
import { LoadingIndicator } from '@/components/loading-indicator'
import { PageContainer } from '@/components/page-container'
import { ProjectPricingPlans } from '@/components/project-pricing-plans'
+import { GitHubIcon } from '@/icons/github'
import { toast, toastError } from '@/lib/notifications'
import { useQuery } from '@/lib/query-client'
@@ -148,13 +151,52 @@ export function MarketplaceProjectIndex({
) : !project ? (
+
+
+

+
+
+ {project.name}
+
+
+
+
+
+ {project.identifier}
+
+
+ {project.lastPublishedDeployment?.websiteUrl && (
+
+
+
+
Homepage
+
+ )}
+
+ {project.lastPublishedDeployment?.sourceUrl && (
+
+
+
+
GitHub
+
+ )}
+
+
@@ -172,7 +214,7 @@ export function MarketplaceProjectIndex({
isLoadingStripeCheckoutForPlan={isLoadingStripeCheckoutForPlan}
onSubscribe={onSubscribe}
/>
- >
+
)}
diff --git a/examples/mcp-servers/search/agentic.config.ts b/examples/mcp-servers/search/agentic.config.ts
index 6e902df2..2a604dde 100644
--- a/examples/mcp-servers/search/agentic.config.ts
+++ b/examples/mcp-servers/search/agentic.config.ts
@@ -11,6 +11,9 @@ export default defineConfig({
type: 'mcp',
url: process.env.MCP_ORIGIN_URL!
},
+ sourceUrl:
+ 'https://github.com/transitive-bullshit/agentic/tree/main/examples/mcp-servers/search',
+ websiteUrl: 'https://agentic.so',
toolConfigs: [
{
name: 'search',
diff --git a/packages/cli/src/commands/deploy.ts b/packages/cli/src/commands/deploy.ts
index 128ba1ec..2a98db44 100644
--- a/packages/cli/src/commands/deploy.ts
+++ b/packages/cli/src/commands/deploy.ts
@@ -19,7 +19,8 @@ export function registerDeployCommand({
'The directory to load the Agentic project config from (defaults to cwd). This directory must contain an "agentic.config.{ts,js,json}" project file.'
)
.option('-d, --debug', 'Print out the parsed agentic config and return.')
- .option('-p, --publish', 'Publishes the deployment after creating it.')
+ // TODO
+ //.option('-p, --publish', 'Publishes the deployment after creating it.')
.action(async (opts) => {
AuthStore.requireAuth()
@@ -47,12 +48,17 @@ export function registerDeployCommand({
return
}
- // Create the deployment on the backend, validate it, and optionally
- // publish it.
+ // Create the deployment on the backend, validating it in the process.
+ // Note that the backend performs more validation than the client does
+ // and is the ultimate source of truth.
const deployment = await oraPromise(
- client.createDeployment(config, {
- publish: opts.publish ? 'true' : 'false'
- }),
+ client.createDeployment(
+ config
+ // TODO: need to prompt to get or confirm version before publishing
+ // {
+ // publish: opts.publish ? 'true' : 'false'
+ // }
+ ),
{
text: `Creating deployment for project "${config.slug}"`,
successText: `Deployment created successfully`,
diff --git a/packages/cli/src/commands/publish.ts b/packages/cli/src/commands/publish.ts
index 15753b77..e1af6726 100644
--- a/packages/cli/src/commands/publish.ts
+++ b/packages/cli/src/commands/publish.ts
@@ -1,11 +1,10 @@
-import { select } from '@clack/prompts'
import { Command } from 'commander'
import { gracefulExit } from 'exit-hook'
import { oraPromise } from 'ora'
-import semver from 'semver'
import type { Context } from '../types'
import { AuthStore } from '../lib/auth-store'
+import { promptForDeploymentVersion } from '../lib/prompt-for-deployment-version'
import { resolveDeployment } from '../lib/resolve-deployment'
export function registerPublishCommand({
@@ -65,39 +64,10 @@ export function registerPublishCommand({
return gracefulExit(1)
}
- const initialVersion = deployment.version
- const baseVersion =
- initialVersion || project.lastPublishedDeploymentVersion || '0.0.0'
-
- const options = [
- initialVersion
- ? { value: initialVersion, label: initialVersion }
- : null,
- {
- value: semver.inc(baseVersion, 'patch'),
- label: `${semver.inc(baseVersion, 'patch')} (patch)`
- },
- {
- value: semver.inc(baseVersion, 'minor'),
- label: `${semver.inc(baseVersion, 'minor')} (minor)`
- },
- {
- value: semver.inc(baseVersion, 'major'),
- label: `${semver.inc(baseVersion, 'major')} (major)`
- }
- ].filter(Boolean)
-
- if (project.lastPublishedDeploymentVersion) {
- logger.info(
- `Project "${project.identifier}" latest published version is "${project.lastPublishedDeploymentVersion}".\n`
- )
- } else {
- logger.info(`Project "${project.identifier}" is not published yet.\n`)
- }
-
- const version = await select({
- message: `Select version of deployment "${deployment.identifier}" to publish:`,
- options
+ const version = await promptForDeploymentVersion({
+ deployment,
+ project,
+ logger
})
if (!version || typeof version !== 'string') {
diff --git a/packages/cli/src/lib/prompt-for-deployment-version.ts b/packages/cli/src/lib/prompt-for-deployment-version.ts
new file mode 100644
index 00000000..fc5b9f30
--- /dev/null
+++ b/packages/cli/src/lib/prompt-for-deployment-version.ts
@@ -0,0 +1,57 @@
+import type { Deployment, Project } from '@agentic/platform-types'
+import { select } from '@clack/prompts'
+import { gracefulExit } from 'exit-hook'
+import semver from 'semver'
+
+import type { Context } from '../types'
+
+export async function promptForDeploymentVersion({
+ deployment,
+ project,
+ logger
+}: {
+ deployment: Deployment
+ project: Project
+ logger: Context['logger']
+}): Promise
{
+ const initialVersion = deployment.version
+ const baseVersion =
+ initialVersion || project.lastPublishedDeploymentVersion || '0.0.0'
+
+ const options = [
+ initialVersion ? { value: initialVersion, label: initialVersion } : null,
+ {
+ value: semver.inc(baseVersion, 'patch'),
+ label: `${semver.inc(baseVersion, 'patch')} (patch)`
+ },
+ {
+ value: semver.inc(baseVersion, 'minor'),
+ label: `${semver.inc(baseVersion, 'minor')} (minor)`
+ },
+ {
+ value: semver.inc(baseVersion, 'major'),
+ label: `${semver.inc(baseVersion, 'major')} (major)`
+ }
+ ].filter(Boolean)
+
+ if (project.lastPublishedDeploymentVersion) {
+ logger.info(
+ `Project "${project.identifier}" latest published version is "${project.lastPublishedDeploymentVersion}".\n`
+ )
+ } else {
+ logger.info(`Project "${project.identifier}" is not published yet.\n`)
+ }
+
+ const version = await select({
+ message: `Select version of deployment "${deployment.identifier}" to publish:`,
+ options
+ })
+
+ if (!version || typeof version !== 'string') {
+ logger.error('No version selected')
+ gracefulExit(1)
+ return
+ }
+
+ return version
+}
diff --git a/packages/types/src/openapi.d.ts b/packages/types/src/openapi.d.ts
index e56ccd4c..a142c857 100644
--- a/packages/types/src/openapi.d.ts
+++ b/packages/types/src/openapi.d.ts
@@ -768,6 +768,11 @@ export interface components {
* @description Optional URL to the source code of the project (eg, GitHub repo).
*/
sourceUrl?: string;
+ /**
+ * Format: uri
+ * @description Optional URL to the product's website.
+ */
+ websiteUrl?: string;
/** @description User id (e.g. "user_tz4a98xxat96iws9zmbrgj3a") */
userId: string;
/** @description Team id (e.g. "team_tz4a98xxat96iws9zmbrgj3a") */
@@ -1040,6 +1045,11 @@ export interface components {
* @description Optional URL to the source code of the project (eg, GitHub repo).
*/
sourceUrl?: string;
+ /**
+ * Format: uri
+ * @description Optional URL to the product's website.
+ */
+ websiteUrl?: string;
/** @description User id (e.g. "user_tz4a98xxat96iws9zmbrgj3a") */
userId: string;
/** @description Team id (e.g. "team_tz4a98xxat96iws9zmbrgj3a") */
@@ -2409,6 +2419,11 @@ export interface operations {
* @description Optional URL to the source code of the project (eg, GitHub repo).
*/
sourceUrl?: string;
+ /**
+ * Format: uri
+ * @description Optional URL to the product's website.
+ */
+ websiteUrl?: string;
origin: components["schemas"]["OriginAdapterConfig"];
/**
* @description List of PricingPlans configuring which Stripe subscriptions should be available for the project. Defaults to a single free plan which is useful for developing and testing your project.
diff --git a/packages/types/src/types.ts b/packages/types/src/types.ts
index bdfeeebd..fc6149b6 100644
--- a/packages/types/src/types.ts
+++ b/packages/types/src/types.ts
@@ -38,11 +38,14 @@ export type Consumer = Simplify<
}
>
export type Project = Simplify<
- components['schemas']['Project'] & {
+ Omit<
+ components['schemas']['Project'],
+ 'lastPublishedDeployment' | 'lastDeployment'
+ > & {
user?: User
team?: Team
- lastPublishedDeployment?: Deployment
- lastDeployment?: Deployment
+ lastPublishedDeployment?: Simplify>
+ lastDeployment?: Simplify>
/**
* The public base HTTP URL for the project supporting HTTP POST requests for
@@ -78,12 +81,14 @@ export type Project = Simplify<
export type Deployment = Simplify<
Omit<
components['schemas']['Deployment'],
- 'pricingPlans' | 'toolConfigs' | 'defaultRateLimit'
+ 'pricingPlans' | 'toolConfigs' | 'defaultRateLimit' | 'project'
> & {
pricingPlans: PricingPlan[]
toolConfigs: ToolConfig[]
defaultRateLimit: RateLimit
- project?: components['schemas']['Project']
+ project?: Simplify<
+ Omit
+ >
/**
* The public base HTTP URL for the deployment supporting HTTP POST requests
@@ -123,16 +128,19 @@ export type Deployment = Simplify<
export type AdminDeployment = Simplify<
Omit<
components['schemas']['AdminDeployment'],
- 'pricingPlans' | 'toolConfigs' | 'defaultRateLimit' | 'origin'
+ 'pricingPlans' | 'toolConfigs' | 'defaultRateLimit' | 'origin' | 'project'
> & {
pricingPlans: PricingPlan[]
toolConfigs: ToolConfig[]
defaultRateLimit: RateLimit
origin: OriginAdapter
- project?: components['schemas']['Project']
} & Pick<
Deployment,
- 'gatewayBaseUrl' | 'gatewayMcpUrl' | 'marketplaceUrl' | 'adminUrl'
+ | 'gatewayBaseUrl'
+ | 'gatewayMcpUrl'
+ | 'marketplaceUrl'
+ | 'adminUrl'
+ | 'project'
>
>
diff --git a/todo.md b/todo.md
index 40e76438..bb5cf60f 100644
--- a/todo.md
+++ b/todo.md
@@ -53,7 +53,7 @@
- stripe
- re-add coupons
- declarative json-based pricing
- - like https://github.com/tierrun/tier and Saasify
+ - like Saasify and https://github.com/tierrun/tier
- https://github.com/tierrun/tier/blob/main/pricing/schema.json
- https://blog.tier.run/tier-hello-world-demo
- stripe connect