diff --git a/IMPLEMENTATION.md b/IMPLEMENTATION.md index 03e704507..b51a8df52 100644 --- a/IMPLEMENTATION.md +++ b/IMPLEMENTATION.md @@ -113,7 +113,7 @@ separate action. ## Workbench Definition (shipped) `WorkbenchDefinition` (`WorkbenchDefinitionSchema` in -`@corbits/workflow-catalog`) is the one type for a named picker row: +`templates/index.ts`) is the one type for a named picker row: default agents, routines, tools, plugins `{required, optional}`, and ordered `onboardingSteps`. A template is a shipped definition, not a second kind. `instantiateWorkbenchTemplate` resolves the definition diff --git a/apps/hub/package.json b/apps/hub/package.json index 49e9c9c77..5b5a0e650 100644 --- a/apps/hub/package.json +++ b/apps/hub/package.json @@ -47,8 +47,8 @@ "@corbits/tool-registry-publish": "workspace:*", "@corbits/turn-artifacts": "workspace:*", "@corbits/url-path": "workspace:*", + "@corbits/code-review-workflow": "workspace:*", "@corbits/webhook-triggers": "workspace:*", - "@corbits/workflow-catalog": "workspace:*", "@corbits/workflows": "workspace:*", "@intx/authz": "0.3.0", "@intx/crypto": "0.3.0", @@ -67,6 +67,7 @@ "@workbench/echo": "workspace:*", "@workbench/hub-client": "workspace:*", "@workbench/onboarding": "workspace:*", + "@workbench/templates": "workspace:*", "arktype": "catalog:", "better-auth": "^1.4.18", "drizzle-orm": "0.45.2", diff --git a/apps/hub/src/index.ts b/apps/hub/src/index.ts index 8bdeddc0f..61a61d3a2 100644 --- a/apps/hub/src/index.ts +++ b/apps/hub/src/index.ts @@ -187,13 +187,13 @@ import { deliveryWorkbenchRequiredForWorkflowName, isConversationalWorkflowName, validateTriggerFieldsAtCreate, - webhookTriggerName, workflowCatalogEntry, workflowDisplayName, workbenchTemplateLibraryEntries, -} from "@corbits/workflow-catalog"; -import { createConnectGithubRoutes } from "@corbits/workflow-catalog/connect-github-routes"; -import { createTemplateBlockRoutes } from "@corbits/workflow-catalog/template-block-routes"; +} from "@workbench/templates"; +import { createConnectGithubRoutes } from "@workbench/connections/connect-github-routes"; +import { webhookTriggerName } from "@workbench/connections/connect-github-setup"; +import { createTemplateBlockRoutes } from "./templates/template-block-routes"; import { createWorkflowDetailRoute, renderWorkflowSourceTree, @@ -2823,7 +2823,7 @@ export async function createHub(config: HubConfig) { const routineStore = createDrizzleRoutineStore(db); // The honest end-to-end delivery-destination rule: a workflow that // never posts to a workbench (e.g. recurring-task, always delivering - // to its creator's Inbox — see @corbits/workflow-catalog's + // to its creator's Inbox — see @workbench/templates's // `deliveryMode`) must never be forced to collect, or block on // missing, a `deliveryWorkbenchId` it would just discard. An unknown // definitionId (row missing, or its asset name isn't catalog-known) diff --git a/packages/workflow-catalog/src/block-workflows.ts b/apps/hub/src/templates/block-workflows.ts similarity index 97% rename from packages/workflow-catalog/src/block-workflows.ts rename to apps/hub/src/templates/block-workflows.ts index 2d9287bec..04434367a 100644 --- a/packages/workflow-catalog/src/block-workflows.ts +++ b/apps/hub/src/templates/block-workflows.ts @@ -19,7 +19,7 @@ import { type CodeReviewWorkflowInput, } from "@corbits/code-review-workflow"; -import { workflowCatalogEntry } from "./index"; +import { workflowCatalogEntry } from "@workbench/templates"; // Matches the conversational default every folded builder in this // codebase uses (`AGENT_DEFINITION_TURN_TIMEOUT_MS`, diff --git a/packages/workflow-catalog/src/template-block-routes.test.ts b/apps/hub/src/templates/template-block-routes.test.ts similarity index 100% rename from packages/workflow-catalog/src/template-block-routes.test.ts rename to apps/hub/src/templates/template-block-routes.test.ts diff --git a/packages/workflow-catalog/src/template-block-routes.ts b/apps/hub/src/templates/template-block-routes.ts similarity index 100% rename from packages/workflow-catalog/src/template-block-routes.ts rename to apps/hub/src/templates/template-block-routes.ts diff --git a/apps/web/package.json b/apps/web/package.json index e2467efb8..0d2a94a51 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -41,7 +41,6 @@ "@corbits/slug": "workspace:*", "@corbits/text-diff": "workspace:*", "@corbits/url-path": "workspace:*", - "@corbits/workflow-catalog": "workspace:*", "@corbits/workflows": "workspace:*", "@corbits/icons": "workspace:*", "@intx/types": "workspace:*", @@ -50,6 +49,7 @@ "@tanstack/react-query": "catalog:", "@workbench/connections": "workspace:*", "@workbench/hub-client": "workspace:*", + "@workbench/templates": "workspace:*", "arktype": "catalog:", "react": "^19.2.0", "react-dom": "^19.2.0", diff --git a/apps/web/src/connect-github-actions.ts b/apps/web/src/connect-github-actions.ts index 95e87d2c2..71a2a0bb0 100644 --- a/apps/web/src/connect-github-actions.ts +++ b/apps/web/src/connect-github-actions.ts @@ -10,7 +10,7 @@ // (`connect-github-block.tsx`'s `DisconnectedBody`) is what actually asks // for the token, so this binding never needs a prompt or a modal of its // own. Reading state and starting reviews call the workbench-scoped routes -// `@corbits/workflow-catalog`'s `createConnectGithubRoutes` exposes. +// `@workbench/connections`'s `createConnectGithubRoutes` exposes. // // `subscribeConnectState` has no server push to fold from yet (connecting a // credential publishes no `chat.settings` event of its own — only diff --git a/apps/web/src/instant-agent-create.test.ts b/apps/web/src/instant-agent-create.test.ts index 7e6221a9c..8d2044478 100644 --- a/apps/web/src/instant-agent-create.test.ts +++ b/apps/web/src/instant-agent-create.test.ts @@ -3,7 +3,7 @@ import { QueryClient } from "@tanstack/react-query"; import { CODE_REVIEW_TEMPLATE, serializeWorkbenchDefinition, -} from "@corbits/workflow-catalog"; +} from "@workbench/templates"; import { createWorkbenchFromTemplate, diff --git a/apps/web/src/instant-agent-create.ts b/apps/web/src/instant-agent-create.ts index 53ad80639..c6152d07f 100644 --- a/apps/web/src/instant-agent-create.ts +++ b/apps/web/src/instant-agent-create.ts @@ -25,7 +25,7 @@ import { templateSettingsPatch, type WorkbenchDefinition, type WorkbenchOnboardingStep, -} from "@corbits/workflow-catalog"; +} from "@workbench/templates"; import { deployWorkbenchTemplateBlock, diff --git a/apps/web/src/myra-workbench.ts b/apps/web/src/myra-workbench.ts index cdd17f711..1a109706e 100644 --- a/apps/web/src/myra-workbench.ts +++ b/apps/web/src/myra-workbench.ts @@ -10,7 +10,7 @@ import { isWorkbenchTitleMatch, type Workbench, } from "@corbits/chat-ui"; -import { WORKFLOW_CATALOG } from "@corbits/workflow-catalog"; +import { WORKFLOW_CATALOG } from "@workbench/templates"; import { listAgentDefinitions, type AgentDefinition } from "./agents-api"; diff --git a/apps/web/src/pages/create-agent-panel.tsx b/apps/web/src/pages/create-agent-panel.tsx index f1814a7a3..0c54160c6 100644 --- a/apps/web/src/pages/create-agent-panel.tsx +++ b/apps/web/src/pages/create-agent-panel.tsx @@ -169,7 +169,7 @@ type Suggestion = { }; /** Every card here names something this workbench can actually deploy - * today (`@corbits/workflow-catalog`'s "Morning brief", "Granola call + * today (`@corbits/workflows`'s "Morning brief", "Granola call * notes", and general conversational research) — plain copy, no * capability this platform can't back up yet. */ const SUGGESTIONS: readonly Suggestion[] = [ diff --git a/apps/web/src/workbench-templates-api.ts b/apps/web/src/workbench-templates-api.ts index dc7abceb7..92f3156bf 100644 --- a/apps/web/src/workbench-templates-api.ts +++ b/apps/web/src/workbench-templates-api.ts @@ -1,6 +1,6 @@ // Reads a workbench template's manifest from the bench library (CL-6344) // — `instant-agent-create.ts` instantiates from this seeded row, never -// from a hardcoded `@corbits/workflow-catalog` import. The read itself +// from a hardcoded `@workbench/templates` import. The read itself // is what converges the shelf (CL-6458), so these routes answer for a // bench of any age. The wire shape is the library's `{id, content}` // entry; the content string re-enters through the catalog's own @@ -11,7 +11,7 @@ import { type } from "arktype"; import { parseWorkbenchDefinition, type WorkbenchDefinition, -} from "@corbits/workflow-catalog"; +} from "@workbench/templates"; import { ApiQueryError } from "@corbits/api-query"; const TemplateLibraryEntry = type({ id: "string > 0", content: "string > 0" }); diff --git a/apps/web/src/workbench-templates.ts b/apps/web/src/workbench-templates.ts index 0e07225bc..ab3a45499 100644 --- a/apps/web/src/workbench-templates.ts +++ b/apps/web/src/workbench-templates.ts @@ -1,7 +1,7 @@ // The picker's prefab catalog: one entry per one-click shortcut card // (CL-6628). `code-review` and `blank` are pinned to the approved mock // (CL-6342) verbatim; `due-diligence` mirrors the backend's -// `DUE_DILIGENCE_TEMPLATE` (`@corbits/workflow-catalog`, CL-6499) — it and +// `DUE_DILIGENCE_TEMPLATE` (`@workbench/templates`, CL-6499) — it and // every other id here are still gated by what this bench's library // actually serves before either is offered as a live card (see // `NewWorkbenchPickerRoute`'s `servedTemplateIds`). See diff --git a/apps/web/test/new-workbench-picker.test.tsx b/apps/web/test/new-workbench-picker.test.tsx index 00345ef4b..c510238ad 100644 --- a/apps/web/test/new-workbench-picker.test.tsx +++ b/apps/web/test/new-workbench-picker.test.tsx @@ -12,7 +12,7 @@ import { CODE_REVIEW_TEMPLATE, DUE_DILIGENCE_TEMPLATE, serializeWorkbenchDefinition, -} from "@corbits/workflow-catalog"; +} from "@workbench/templates"; import { act } from "react"; import { createRoot, type Root } from "react-dom/client"; diff --git a/bun.lock b/bun.lock index 43b5e204b..a3069c029 100644 --- a/bun.lock +++ b/bun.lock @@ -14,12 +14,13 @@ "@corbits/ollama-adapter": "workspace:*", "@corbits/run-scope": "workspace:*", "@corbits/webhook-triggers": "workspace:*", - "@corbits/workflow-catalog": "workspace:*", "@eslint/js": "^10.0.0", "@intx/db": "workspace:*", "@intx/mime": "0.3.0", "@intx/types": "0.3.0", "@types/bun": "1.3.14", + "@workbench/connections": "workspace:*", + "@workbench/templates": "workspace:*", "eslint": "^10.8.0", "jiti": "^2.7.0", "prettier": "^3.6.2", @@ -40,6 +41,7 @@ "@corbits/artifacts-hub": "workspace:*", "@corbits/bench": "workspace:*", "@corbits/chat": "workspace:*", + "@corbits/code-review-workflow": "workspace:*", "@corbits/commands": "workspace:*", "@corbits/credential-providers": "workspace:*", "@corbits/docker-provisioner": "workspace:*", @@ -68,7 +70,6 @@ "@corbits/turn-artifacts": "workspace:*", "@corbits/url-path": "workspace:*", "@corbits/webhook-triggers": "workspace:*", - "@corbits/workflow-catalog": "workspace:*", "@corbits/workflows": "workspace:*", "@intx/authz": "0.3.0", "@intx/crypto": "0.3.0", @@ -87,6 +88,7 @@ "@workbench/echo": "workspace:*", "@workbench/hub-client": "workspace:*", "@workbench/onboarding": "workspace:*", + "@workbench/templates": "workspace:*", "arktype": "catalog:", "better-auth": "^1.4.18", "drizzle-orm": "0.45.2", @@ -162,7 +164,6 @@ "@corbits/slug": "workspace:*", "@corbits/text-diff": "workspace:*", "@corbits/url-path": "workspace:*", - "@corbits/workflow-catalog": "workspace:*", "@corbits/workflows": "workspace:*", "@intx/types": "workspace:*", "@radix-ui/react-dialog": "^1.1.15", @@ -170,6 +171,7 @@ "@tanstack/react-query": "catalog:", "@workbench/connections": "workspace:*", "@workbench/hub-client": "workspace:*", + "@workbench/templates": "workspace:*", "arktype": "catalog:", "react": "^19.2.0", "react-dom": "^19.2.0", @@ -214,7 +216,6 @@ "@corbits/error-sink": "workspace:*", "@corbits/folded-run-one-shot": "workspace:*", "@corbits/skills": "workspace:*", - "@corbits/workflow-catalog": "workspace:*", "@corbits/workflows": "workspace:*", "@intx/agent": "workspace:*", "@intx/db": "workspace:*", @@ -224,6 +225,7 @@ "@intx/types": "workspace:*", "@intx/workflow": "workspace:*", "@workbench/hub-client": "workspace:*", + "@workbench/templates": "workspace:*", "arktype": "catalog:", "drizzle-orm": "catalog:", "hono": "^4.11.9", @@ -434,7 +436,6 @@ "@corbits/memory": "github:corbitsdev/corbits-memory#9e6f213fa2c002b531d3f6af1aa0abd737b8afe3", "@corbits/turn-artifacts": "workspace:*", "@corbits/url-path": "workspace:*", - "@corbits/workflow-catalog": "workspace:*", "@corbits/workflows": "workspace:*", "@intx/agent": "workspace:*", "@intx/authz": "0.3.0", @@ -473,9 +474,9 @@ "@corbits/preferences": "workspace:*", "@corbits/presence": "workspace:*", "@corbits/react-ui": "github:corbitsdev/react-ui#3b122812a307ccb35be31386f7696020c5a84635", - "@corbits/workflow-catalog": "workspace:*", "@tanstack/react-query": "catalog:", "@workbench/connections": "workspace:*", + "@workbench/templates": "workspace:*", "arktype": "catalog:", "react": "^19.2.0", "react-dom": "^19.2.0", @@ -568,8 +569,10 @@ "name": "@workbench/connections", "version": "0.0.1", "dependencies": { + "@corbits/code-review": "workspace:*", "@corbits/credential-providers": "workspace:*", "@corbits/error-sink": "workspace:*", + "@corbits/github-tools": "workspace:*", "@corbits/inference-settings": "workspace:*", "@corbits/mcp-tools": "workspace:*", "@intx/crypto": "0.3.0", @@ -578,9 +581,11 @@ "@intx/types": "workspace:*", "@modelcontextprotocol/sdk": "catalog:", "@workbench/hub-client": "workspace:*", + "@workbench/templates": "workspace:*", "arktype": "catalog:", "drizzle-orm": "catalog:", "hono": "^4.11.9", + "postgres": "catalog:", "simple-icons": "^16.28.0", }, "devDependencies": { @@ -691,7 +696,6 @@ "@corbits/migration-runner": "workspace:*", "@corbits/routines": "workspace:*", "@corbits/webhook-triggers": "workspace:*", - "@corbits/workflow-catalog": "workspace:*", "@intx/agent": "workspace:*", "@intx/db": "workspace:*", "@intx/hub-api": "workspace:*", @@ -703,6 +707,7 @@ "@workbench/connections": "workspace:*", "@workbench/hub-client": "workspace:*", "@workbench/onboarding": "workspace:*", + "@workbench/templates": "workspace:*", "arktype": "catalog:", "drizzle-orm": "catalog:", "hono": "^4.11.9", @@ -819,10 +824,10 @@ "@corbits/last-30-days-research-workflow": "workspace:*", "@corbits/tool-registry-publish": "workspace:*", "@corbits/workbench-digest-workflow": "workspace:*", - "@corbits/workflow-catalog": "workspace:*", "@corbits/workflows": "workspace:*", "@intx/inference": "workspace:*", "@intx/types": "workspace:*", + "@workbench/templates": "workspace:*", "arktype": "catalog:", }, "devDependencies": { @@ -1114,7 +1119,6 @@ "@corbits/icons": "workspace:*", "@corbits/react-ui": "github:corbitsdev/react-ui#3b122812a307ccb35be31386f7696020c5a84635", "@corbits/settings-ui": "workspace:*", - "@corbits/workflow-catalog": "workspace:*", "@workbench/connections": "workspace:*", "arktype": "catalog:", "react": "^19.2.0", @@ -1197,7 +1201,6 @@ "@corbits/folded-run-one-shot": "workspace:*", "@corbits/migration-runner": "workspace:*", "@corbits/slug": "workspace:*", - "@corbits/workflow-catalog": "workspace:*", "@corbits/workflows": "workspace:*", "@intx/authz": "0.3.0", "@intx/db": "workspace:*", @@ -1219,7 +1222,7 @@ }, "packages/routines-tools": { "name": "@corbits/routines-tools", - "version": "0.0.9", + "version": "0.0.10", "dependencies": { "@corbits/routines": "workspace:*", "@corbits/workflows": "workspace:*", @@ -1307,9 +1310,9 @@ "@corbits/icons": "workspace:*", "@corbits/inference-settings": "workspace:*", "@corbits/react-ui": "github:corbitsdev/react-ui#3b122812a307ccb35be31386f7696020c5a84635", - "@corbits/workflow-catalog": "workspace:*", "@intx/types": "workspace:*", "@workbench/connections": "workspace:*", + "@workbench/templates": "workspace:*", "arktype": "catalog:", "react": "^19.2.0", "react-dom": "^19.2.0", @@ -1522,19 +1525,17 @@ "typescript": "catalog:", }, }, - "packages/workflow-catalog": { - "name": "@corbits/workflow-catalog", + "packages/workflows": { + "name": "@corbits/workflows", "version": "0.0.1", "dependencies": { - "@corbits/code-review": "workspace:*", - "@corbits/code-review-workflow": "workspace:*", "@corbits/error-sink": "workspace:*", - "@corbits/github-tools": "workspace:*", - "@corbits/jimmy-agent": "workspace:*", - "@corbits/scout-agent": "workspace:*", - "@corbits/webhook-triggers": "workspace:*", + "@corbits/migration-runner": "workspace:*", + "@intx/authz": "0.3.0", "@intx/db": "workspace:*", "@intx/hub-api": "workspace:*", + "@intx/hub-sessions": "workspace:*", + "@intx/types": "workspace:*", "@workbench/hub-client": "workspace:*", "arktype": "catalog:", "drizzle-orm": "catalog:", @@ -1542,31 +1543,24 @@ "postgres": "catalog:", }, "devDependencies": { - "@intx/crypto": "0.3.0", "@types/bun": "catalog:", "@workbench/connections": "workspace:*", "typescript": "catalog:", }, }, - "packages/workflows": { - "name": "@corbits/workflows", + "templates": { + "name": "@workbench/templates", "version": "0.0.1", "dependencies": { - "@corbits/error-sink": "workspace:*", - "@corbits/migration-runner": "workspace:*", - "@intx/authz": "0.3.0", - "@intx/db": "workspace:*", - "@intx/hub-api": "workspace:*", - "@intx/hub-sessions": "workspace:*", - "@intx/types": "workspace:*", - "@workbench/hub-client": "workspace:*", + "@corbits/code-review": "workspace:*", + "@corbits/jimmy-agent": "workspace:*", + "@corbits/scout-agent": "workspace:*", + "@corbits/workflows": "workspace:*", "arktype": "catalog:", - "drizzle-orm": "catalog:", - "hono": "^4.11.9", - "postgres": "catalog:", }, "devDependencies": { "@types/bun": "catalog:", + "@workbench/connections": "workspace:*", "typescript": "catalog:", }, }, @@ -2335,8 +2329,6 @@ "@corbits/workflow-authoring-tools": ["@corbits/workflow-authoring-tools@workspace:packages/workflow-authoring-tools"], - "@corbits/workflow-catalog": ["@corbits/workflow-catalog@workspace:packages/workflow-catalog"], - "@corbits/workflows": ["@corbits/workflows@workspace:packages/workflows"], "@drizzle-team/brocli": ["@drizzle-team/brocli@0.10.2", "", {}, "sha512-z33Il7l5dKjUgGULTqBsQBQwckHh5AbIuxhdsIxDDiZAzBOrZO6q9ogcWC65kU382AfynTfgNumVcNIjuIua6w=="], @@ -2759,6 +2751,8 @@ "@workbench/sidecar": ["@workbench/sidecar@workspace:apps/sidecar"], + "@workbench/templates": ["@workbench/templates@workspace:templates"], + "@workbench/web": ["@workbench/web@workspace:apps/web"], "@workflow/serde": ["@workflow/serde@4.1.0-beta.2", "", {}, "sha512-8kkeoQKLDaKXefjV5dbhBj2aErfKp1Mc4pb6tj8144cF+Em5SPbyMbyLCHp+BVrFfFVCBluCtMx+jjvaFVZGww=="], diff --git a/docs/GLOSSARY.md b/docs/GLOSSARY.md index d78cab40d..1ec2ee4fa 100644 --- a/docs/GLOSSARY.md +++ b/docs/GLOSSARY.md @@ -17,7 +17,7 @@ lower-level name left to list. | **DM** | kind: chat | The one 1:1 tenant with that agent — two opens never clone a second DM | | **Channel** | kind: workbench | A shared room between people and agents (multi-principal tenant). `+` mints an empty one with nobody hosted; named templates mint the same empty channel, then instantiate their Workbench Definition and run its onboarding walkthrough in the room | | **Definition** | workflow definition | A deployable unit of agent behavior, authored as code — not a template you mint into many conversations | -| **Workbench Definition** | — | The arktype description a named template instantiates: its default agents, routines, tools, required/optional plugins, and its ordered onboarding walkthrough — see `packages/workflow-catalog/src/templates.ts`'s `WorkbenchDefinitionSchema` | +| **Workbench Definition** | — | The arktype description a named template instantiates: its default agents, routines, tools, required/optional plugins, and its ordered onboarding walkthrough — see `templates/index.ts`'s `WorkbenchDefinitionSchema` | | **Run** | workflow run | A definition executing in a bench; interactive runs carry conversations | | **Routine** | — | The named parent entity over runs of one definition — a trigger (or none), launch input, a delivery workbench, enabled state, and an explicit target: the definition's asset id, resolved at each launch to its latest approved deployment; see [`@corbits/routines`](../packages/routines/README.md) and [workflow-model.md](workflow-model.md) | | **Approval** | approval | A human decision gating an external side effect | diff --git a/docs/workflow-detail.md b/docs/workflow-detail.md index dd5774858..3c3e9721a 100644 --- a/docs/workflow-detail.md +++ b/docs/workflow-detail.md @@ -2,7 +2,7 @@ A workflow definition's own page: `GET /api/tenants/:tenantId/workflows/definitions/:definitionAssetId/detail` -(`packages/workflow-catalog/src/detail-route.ts`), read at `/workflows/ +(`packages/workflows/src/detail`), read at `/workflows/ :definitionAssetId` (`apps/web/src/pages/workflow-detail-page.tsx`). First useful version — read-only, no editing surface here. diff --git a/package.json b/package.json index 5d689d777..56af4e10b 100644 --- a/package.json +++ b/package.json @@ -6,6 +6,7 @@ "workspaces": [ "apps/*", "packages/*", + "templates", "tools/*", "vendor/intx/*", "workflows/*" @@ -54,8 +55,9 @@ "@corbits/artifacts-hub": "workspace:*", "@corbits/evals": "workspace:*", "@corbits/ollama-adapter": "workspace:*", - "@corbits/workflow-catalog": "workspace:*", "@intx/db": "workspace:*", + "@workbench/connections": "workspace:*", + "@workbench/templates": "workspace:*", "@eslint/js": "^10.0.0", "@intx/mime": "0.3.0", "@intx/types": "0.3.0", diff --git a/packages/agent-directory/package.json b/packages/agent-directory/package.json index 71f9e23da..2f4c4b657 100644 --- a/packages/agent-directory/package.json +++ b/packages/agent-directory/package.json @@ -18,7 +18,7 @@ "@corbits/error-sink": "workspace:*", "@corbits/folded-run-one-shot": "workspace:*", "@corbits/skills": "workspace:*", - "@corbits/workflow-catalog": "workspace:*", + "@workbench/templates": "workspace:*", "@corbits/workflows": "workspace:*", "@intx/agent": "workspace:*", "@intx/db": "workspace:*", diff --git a/packages/agent-directory/src/client.ts b/packages/agent-directory/src/client.ts index 44bbc1623..57bb62040 100644 --- a/packages/agent-directory/src/client.ts +++ b/packages/agent-directory/src/client.ts @@ -15,7 +15,7 @@ import { withDisplayNames, type WithDisplayName, } from "@corbits/chat/display-name"; -import { isConversationalWorkflowName } from "@corbits/workflow-catalog"; +import { isConversationalWorkflowName } from "@workbench/templates"; // `deriveDisplayName`/`humanizeSlug` (CL-6413) live in `@corbits/chat` // itself, not here: this package already depends on `@corbits/chat` (for diff --git a/packages/agent-directory/src/resolve-myra-definition-id.ts b/packages/agent-directory/src/resolve-myra-definition-id.ts index 5bedb72a7..cc7dde244 100644 --- a/packages/agent-directory/src/resolve-myra-definition-id.ts +++ b/packages/agent-directory/src/resolve-myra-definition-id.ts @@ -7,7 +7,7 @@ import { and, eq } from "drizzle-orm"; import type { DB } from "@intx/db"; import { workflowDefinition } from "@intx/db/schema"; -import { WORKFLOW_CATALOG } from "@corbits/workflow-catalog"; +import { WORKFLOW_CATALOG } from "@workbench/templates"; /** Myra's asset name in the seeded workflow catalog — the same lookup * `apps/web/src/myra-workbench.ts` does client-side, mirrored here for diff --git a/packages/agent-directory/src/validation.ts b/packages/agent-directory/src/validation.ts index d4c71c507..3571f1109 100644 --- a/packages/agent-directory/src/validation.ts +++ b/packages/agent-directory/src/validation.ts @@ -68,7 +68,7 @@ export const CreateAgentDefinitionInput = type({ // core resolves each to `*`, matching `./workflow-create-routes.ts`'s // own handling of the same field). Absent for a person hand-authoring // an agent through a form, which has no affordance for typing one; the - // one caller that supplies it is `@corbits/workflow-catalog`'s + // one caller that supplies it is `@workbench/templates`'s // `instantiateWorkbenchTemplate`, installing a template participant // (Scout, Jimmy) whose tools ship as pinned packages rather than // inline capabilities. diff --git a/packages/agent-directory/src/visible-definitions.ts b/packages/agent-directory/src/visible-definitions.ts index 8f5d27d63..08c01996c 100644 --- a/packages/agent-directory/src/visible-definitions.ts +++ b/packages/agent-directory/src/visible-definitions.ts @@ -11,7 +11,7 @@ import { and, eq } from "drizzle-orm"; import type { DB } from "@intx/db"; import { getAncestorChain, schema } from "@intx/db"; import { isWorkbenchHostDefinitionName } from "@corbits/chat/workbench-host-naming"; -import { isConversationalWorkflowName } from "@corbits/workflow-catalog"; +import { isConversationalWorkflowName } from "@workbench/templates"; import { deriveDisplayName } from "./client"; export type VisibleAgentDefinition = { diff --git a/packages/agent-directory/src/workflow-create-routes.ts b/packages/agent-directory/src/workflow-create-routes.ts index b5079a6b2..4fa886c18 100644 --- a/packages/agent-directory/src/workflow-create-routes.ts +++ b/packages/agent-directory/src/workflow-create-routes.ts @@ -41,7 +41,7 @@ import type { AssetService } from "@intx/hub-sessions"; import { skillNameSchema } from "@corbits/skills"; import { isWorkbenchHostDefinitionName } from "@corbits/chat/workbench-host-naming"; -import { isAutomatableWorkflowName } from "@corbits/workflow-catalog"; +import { isAutomatableWorkflowName } from "@workbench/templates"; import { createAgentDefinitionCore, diff --git a/packages/artifacts-hub/src/template-library.ts b/packages/artifacts-hub/src/template-library.ts index 1b2f604e4..80aca8d01 100644 --- a/packages/artifacts-hub/src/template-library.ts +++ b/packages/artifacts-hub/src/template-library.ts @@ -47,7 +47,7 @@ export const WORKBENCH_TEMPLATE_ARTIFACT_KIND = "workbench-template"; /** One shelf entry to seed: the template's stable id and its serialized * manifest. Kept as plain strings so this package never depends on - * `@corbits/workflow-catalog` — the manifest vocabulary stays there. */ + * `@workbench/templates` — the manifest vocabulary stays there. */ export type TemplateLibraryEntry = { readonly id: string; readonly content: string; @@ -427,7 +427,7 @@ export type CreateTemplateLibraryRoutesDeps = { /** `GET /` lists every seeded template entry; `GET /:templateId` fetches * one. Both converge the tenant's shelf before reading it. Content * travels as the seeded string — the client parses it with - * `@corbits/workflow-catalog`'s manifest schema at its own boundary. */ + * `@workbench/templates`'s manifest schema at its own boundary. */ export function createTemplateLibraryRoutes( deps: CreateTemplateLibraryRoutesDeps, ): Hono { diff --git a/packages/chat-ui/package.json b/packages/chat-ui/package.json index 7fbad1f90..2df47e712 100644 --- a/packages/chat-ui/package.json +++ b/packages/chat-ui/package.json @@ -25,7 +25,7 @@ "@corbits/react-ui": "github:corbitsdev/react-ui#3b122812a307ccb35be31386f7696020c5a84635", "@tanstack/react-query": "catalog:", "@workbench/connections": "workspace:*", - "@corbits/workflow-catalog": "workspace:*", + "@workbench/templates": "workspace:*", "arktype": "catalog:", "@corbits/icons": "workspace:*", "react": "^19.2.0", diff --git a/packages/chat-ui/src/api.ts b/packages/chat-ui/src/api.ts index 60c239d22..db2e1a40a 100644 --- a/packages/chat-ui/src/api.ts +++ b/packages/chat-ui/src/api.ts @@ -15,7 +15,7 @@ import { parseParticipants } from "@corbits/chat/participants"; import type { ParticipantRecord } from "@corbits/chat/participants"; import type { WorkbenchOnboardingStep } from "@corbits/chat/blocks"; import { UnauthenticatedError } from "@corbits/api-query"; -import { jimmyAgentRequest } from "@corbits/workflow-catalog"; +import { jimmyAgentRequest } from "@workbench/templates"; import { CHAT_STRINGS } from "./strings"; export { @@ -742,7 +742,7 @@ export function postWorkbenchOnboardingStep( ); } -// Jimmy's own request shape, the same `@corbits/workflow-catalog` object a +// Jimmy's own request shape, the same `@workbench/templates` object a // workbench template's participant create used to resolve — CL-6499 removed // Jimmy's template (he is not a "kind of workbench"), so this dialog's own // "Add Jimmy" quick-create row (see `invite-agent-dialog.tsx`) is his only @@ -1203,7 +1203,7 @@ export type WorkbenchSettingsPatch = { readonly "chat/contextWindow"?: number | null; /** * `template/*` keys: the room's own record of which template minted - * it and what it still needs connected, per `@corbits/workflow-catalog`'s + * it and what it still needs connected, per `@workbench/templates`'s * own schema for this namespace. `chat`'s settings route validates * only its own `chat/*` keys and passes any other namespace through * opaquely (see `packages/chat/src/workbench-settings.ts`) — a @@ -1228,7 +1228,7 @@ export function patchWorkbenchSettings( } // The room's GitHub connect card (CL-6344): the live read and the -// start-reviewing write, backed by `@corbits/workflow-catalog`'s +// start-reviewing write, backed by `@workbench/templates`'s // `createConnectGithubRoutes` (mounted at // `/api/tenants/:tenantId/workbenches/:workbenchId/github/*`). Connecting // the PAT itself is a separate, already-generic surface — diff --git a/packages/chat-ui/src/blocks/connect-github-actions.ts b/packages/chat-ui/src/blocks/connect-github-actions.ts index 5c10ff775..07fa3e518 100644 --- a/packages/chat-ui/src/blocks/connect-github-actions.ts +++ b/packages/chat-ui/src/blocks/connect-github-actions.ts @@ -6,7 +6,7 @@ // `@workbench/connections`' generic `/:connectorId/complete` route // (`github`'s PAT test-and-store — already fully generic, no bespoke // GitHub route needed), `@corbits/github-tools`' `listRepos`, and -// `@corbits/workflow-catalog`'s `startReviewingRepos`. +// `@workbench/connections`'s `startReviewingRepos`. import type { ConnectGithubRepo } from "./connect-github-block"; export type { ConnectGithubRepo }; @@ -34,7 +34,7 @@ export type ConnectGithubActions = { * `startReviewing`, `skip`) change something, re-reading * `getConnectState`. A credential completed elsewhere (the Plugins * page, another tab) settles this connector's entry on - * `@corbits/workflow-catalog`'s `template/pendingConnections` + * `@workbench/templates`'s `template/pendingConnections` * (CL-6463's `settleConnectedService`) so the *next* fresh * `getConnectState` — e.g. on this card's next mount — already reads * connected, since that read resolves against the real credential, @@ -72,7 +72,7 @@ export type ConnectGithubActions = { { readonly ok: true } | { readonly ok: false; readonly message: string } >; /** Mints a grant and a live webhook trigger per repo id, then - * records the selection — `@corbits/workflow-catalog`'s + * records the selection — `@workbench/templates`'s * `startReviewingRepos`, called through the host's own binding. */ readonly startReviewing: ( repoIds: readonly string[], diff --git a/packages/chat-ui/test/connect-github-flow.test.tsx b/packages/chat-ui/test/connect-github-flow.test.tsx index d9f6c836e..b7c9ccf8e 100644 --- a/packages/chat-ui/test/connect-github-flow.test.tsx +++ b/packages/chat-ui/test/connect-github-flow.test.tsx @@ -4,7 +4,7 @@ // `WorkbenchTimeline` (the real registry, the real container, the real // presentational `ConnectGithubBlockView`), drives it through connect → // list repos → pick three → "Start reviewing", and proves: -// 1. `@corbits/workflow-catalog`'s real `startReviewingRepos` mints +// 1. `@workbench/connections`'s real `startReviewingRepos` mints // one grant and one webhook trigger per selected repo, and records // the selection. // 2. The card settles into its connected state by the host fanning an @@ -18,7 +18,7 @@ import type { Root } from "react-dom/client"; import { startReviewingRepos, type ConnectGithubSetupPorts, -} from "@corbits/workflow-catalog"; +} from "@workbench/connections/connect-github-setup"; import type { MessageItem } from "../src/api"; import type { diff --git a/packages/chat/package.json b/packages/chat/package.json index ea4636823..3abb0a78e 100644 --- a/packages/chat/package.json +++ b/packages/chat/package.json @@ -35,7 +35,6 @@ "@corbits/folded-runs": "workspace:*", "@corbits/memory": "github:corbitsdev/corbits-memory#9e6f213fa2c002b531d3f6af1aa0abd737b8afe3", "@corbits/turn-artifacts": "workspace:*", - "@corbits/workflow-catalog": "workspace:*", "@corbits/workflows": "workspace:*", "@intx/agent": "workspace:*", "@intx/authz": "0.3.0", diff --git a/packages/chat/src/connect-pending.ts b/packages/chat/src/connect-pending.ts index 2ac18d66b..ac75c5f88 100644 --- a/packages/chat/src/connect-pending.ts +++ b/packages/chat/src/connect-pending.ts @@ -9,7 +9,7 @@ // as the connecting person. // // The code-review template's own GitHub connect card registers -// under a second, template-owned key (`@corbits/workflow-catalog`'s +// under a second, template-owned key (`@workbench/templates`'s // `template/pendingConnections`) instead of `connections/pending` — a // credential completed anywhere other than that card's own submit (the // Plugins page, another tab) never reached it. Rather than stand up a @@ -44,7 +44,7 @@ export const CONNECTIONS_PENDING_KEY = "connections/pending"; export const CONNECTION_CONNECTED_EVENT = "connection.connected"; /** The code-review template's own pending-connections key - * (`@corbits/workflow-catalog`'s `templateSettingsPatch`/ + * (`@workbench/templates`'s `templateSettingsPatch`/ * `templateReposSettingsPatch`) — a room minted from that template * tracks its GitHub card's pending state here instead of under * `CONNECTIONS_PENDING_KEY`. `settleConnectedService` knows this one diff --git a/packages/code-review/README.md b/packages/code-review/README.md index 6045a1be3..ceac49359 100644 --- a/packages/code-review/README.md +++ b/packages/code-review/README.md @@ -56,7 +56,7 @@ subpaths (`@corbits/code-review/reviewers`, `@corbits/code-review/agent-requests`), separate from the package root. Both files have zero imports of their own; the root also re-exports the review run and GitHub client, which pull in `@corbits/github-tools` and -`@intx/agent`'s full provider surface. `@corbits/workflow-catalog`'s +`@intx/agent`'s full provider surface. `@workbench/templates`'s `CODE_REVIEW_TEMPLATE` (CL-6344) imports the roster through these subpaths for exactly that reason — see its own module doc. diff --git a/packages/connections/package.json b/packages/connections/package.json index 188faf99b..8992d011a 100644 --- a/packages/connections/package.json +++ b/packages/connections/package.json @@ -11,15 +11,20 @@ "./persist-credential": "./src/persist-credential.ts", "./plugins": "./src/plugins.ts", "./provider-health": "./src/provider-health.ts", - "./mcp-presets": "./src/mcp-presets.ts" + "./mcp-presets": "./src/mcp-presets.ts", + "./connect-github-routes": "./src/connect-github-routes.ts", + "./connect-github-setup": "./src/connect-github-setup.ts", + "./reconcile-duplicate-repo-grants": "./src/reconcile-duplicate-repo-grants.ts" }, "scripts": { "typecheck": "tsc --noEmit", "test": "bun test" }, "dependencies": { + "@corbits/code-review": "workspace:*", "@corbits/credential-providers": "workspace:*", "@corbits/error-sink": "workspace:*", + "@corbits/github-tools": "workspace:*", "@corbits/inference-settings": "workspace:*", "@corbits/mcp-tools": "workspace:*", "@intx/crypto": "0.3.0", @@ -28,9 +33,11 @@ "@intx/types": "workspace:*", "@modelcontextprotocol/sdk": "catalog:", "@workbench/hub-client": "workspace:*", + "@workbench/templates": "workspace:*", "arktype": "catalog:", "drizzle-orm": "catalog:", "hono": "^4.11.9", + "postgres": "catalog:", "simple-icons": "^16.28.0" }, "devDependencies": { diff --git a/packages/workflow-catalog/src/connect-github-credential-link.test.ts b/packages/connections/src/connect-github-credential-link.test.ts similarity index 100% rename from packages/workflow-catalog/src/connect-github-credential-link.test.ts rename to packages/connections/src/connect-github-credential-link.test.ts diff --git a/packages/workflow-catalog/src/connect-github-routes.test.ts b/packages/connections/src/connect-github-routes.test.ts similarity index 100% rename from packages/workflow-catalog/src/connect-github-routes.test.ts rename to packages/connections/src/connect-github-routes.test.ts diff --git a/packages/workflow-catalog/src/connect-github-routes.ts b/packages/connections/src/connect-github-routes.ts similarity index 99% rename from packages/workflow-catalog/src/connect-github-routes.ts rename to packages/connections/src/connect-github-routes.ts index 1880bf95d..f8d0ad81e 100644 --- a/packages/workflow-catalog/src/connect-github-routes.ts +++ b/packages/connections/src/connect-github-routes.ts @@ -40,7 +40,7 @@ import { } from "@corbits/code-review/introductions"; import { startReviewingRepos } from "./connect-github-setup"; -import { templateReposSettingsPatch } from "./settings"; +import { templateReposSettingsPatch } from "@workbench/templates/settings"; // `startReviewingRepos`' own selected-repo mismatch throw and a GitHub // client failure both carry provider/internal detail (a rejected repo id, diff --git a/packages/workflow-catalog/test/connect-github-setup.race.test.ts b/packages/connections/src/connect-github-setup.race.test.ts similarity index 99% rename from packages/workflow-catalog/test/connect-github-setup.race.test.ts rename to packages/connections/src/connect-github-setup.race.test.ts index 2e288d577..2f45bfb5a 100644 --- a/packages/workflow-catalog/test/connect-github-setup.race.test.ts +++ b/packages/connections/src/connect-github-setup.race.test.ts @@ -39,7 +39,7 @@ import { startReviewingRepos, webhookTriggerName, type ConnectGithubSetupPorts, -} from "../src/connect-github-setup"; +} from "./connect-github-setup"; function scratchUrlFor(e2eUrl: string): string { const url = new URL(e2eUrl); diff --git a/packages/workflow-catalog/src/connect-github-setup.test.ts b/packages/connections/src/connect-github-setup.test.ts similarity index 100% rename from packages/workflow-catalog/src/connect-github-setup.test.ts rename to packages/connections/src/connect-github-setup.test.ts diff --git a/packages/workflow-catalog/src/connect-github-setup.ts b/packages/connections/src/connect-github-setup.ts similarity index 100% rename from packages/workflow-catalog/src/connect-github-setup.ts rename to packages/connections/src/connect-github-setup.ts diff --git a/packages/workflow-catalog/test/reconcile-duplicate-repo-grants.test.ts b/packages/connections/src/reconcile-duplicate-repo-grants.test.ts similarity index 98% rename from packages/workflow-catalog/test/reconcile-duplicate-repo-grants.test.ts rename to packages/connections/src/reconcile-duplicate-repo-grants.test.ts index e4cffd809..dd7a0e378 100644 --- a/packages/workflow-catalog/test/reconcile-duplicate-repo-grants.test.ts +++ b/packages/connections/src/reconcile-duplicate-repo-grants.test.ts @@ -13,7 +13,7 @@ import postgres from "postgres"; import { runMigrations } from "@intx/db"; import { e2eDatabaseUrl } from "../../../scripts/e2e/harness"; -import { reconcileDuplicateRepoGrants } from "../src/reconcile-duplicate-repo-grants"; +import { reconcileDuplicateRepoGrants } from "./reconcile-duplicate-repo-grants"; import { dbGate } from "../../../scripts/e2e/db-gate"; function scratchUrlFor(e2eUrl: string): string { diff --git a/packages/workflow-catalog/src/reconcile-duplicate-repo-grants.ts b/packages/connections/src/reconcile-duplicate-repo-grants.ts similarity index 100% rename from packages/workflow-catalog/src/reconcile-duplicate-repo-grants.ts rename to packages/connections/src/reconcile-duplicate-repo-grants.ts diff --git a/packages/echo/README.md b/packages/echo/README.md index 47993b50b..272a01254 100644 --- a/packages/echo/README.md +++ b/packages/echo/README.md @@ -3,7 +3,7 @@ The smallest hub extension, kept deliberately trivial: a tenant-scoped route that echoes a `POST` body back verbatim as plain text. It exists as a wiring check for the mail-triggered contract, not as a real assistant — -the `echo` entry in `@corbits/workflow-catalog`'s `WORKFLOW_CATALOG` +the `echo` entry in `@workbench/templates`'s `WORKFLOW_CATALOG` describes it the same way. ## Composition with @intx/* diff --git a/packages/evals/package.json b/packages/evals/package.json index 85a46e4c8..ad49cd147 100644 --- a/packages/evals/package.json +++ b/packages/evals/package.json @@ -18,7 +18,7 @@ "@corbits/migration-runner": "workspace:*", "@corbits/routines": "workspace:*", "@corbits/webhook-triggers": "workspace:*", - "@corbits/workflow-catalog": "workspace:*", + "@workbench/templates": "workspace:*", "@intx/agent": "workspace:*", "@intx/db": "workspace:*", "@intx/hub-api": "workspace:*", diff --git a/packages/evals/src/targets/real-target.ts b/packages/evals/src/targets/real-target.ts index 306c5c606..dac681ce5 100644 --- a/packages/evals/src/targets/real-target.ts +++ b/packages/evals/src/targets/real-target.ts @@ -33,7 +33,7 @@ import { instantiateWorkbenchTemplate, parseWorkbenchDefinition, templateSettingsPatch, -} from "@corbits/workflow-catalog"; +} from "@workbench/templates"; import { signPayload, WEBHOOK_SIGNATURE_HEADER, diff --git a/packages/hub-client/package.json b/packages/hub-client/package.json index ceb84ec2c..745523f8a 100644 --- a/packages/hub-client/package.json +++ b/packages/hub-client/package.json @@ -24,7 +24,7 @@ "@corbits/last-30-days-research-workflow": "workspace:*", "@corbits/tool-registry-publish": "workspace:*", "@corbits/workbench-digest-workflow": "workspace:*", - "@corbits/workflow-catalog": "workspace:*", + "@workbench/templates": "workspace:*", "@corbits/workflows": "workspace:*", "@intx/inference": "workspace:*", "@intx/types": "workspace:*", diff --git a/packages/hub-client/src/seed.ts b/packages/hub-client/src/seed.ts index bab86992c..ecfbed6e3 100644 --- a/packages/hub-client/src/seed.ts +++ b/packages/hub-client/src/seed.ts @@ -7,7 +7,7 @@ // // Workflow package metadata (automatable, displayName) lives in each // workflows/*/package.json under `corbits.workflow` and is mirrored in -// `@corbits/workflow-catalog`. Seed stamps displayName onto the asset so +// `@workbench/templates`. Seed stamps displayName onto the asset so // the routines picker can show a friendly label without reading package.json. import { @@ -44,7 +44,7 @@ import { buildLast30DaysResearchWorkflow, serializeLast30DaysResearchWorkflow, } from "@corbits/last-30-days-research-workflow"; -import { WORKFLOW_CATALOG } from "@corbits/workflow-catalog"; +import { WORKFLOW_CATALOG } from "@workbench/templates"; import { capabilitiesForDeployment } from "@corbits/inference-catalog/offering-capabilities"; import { quirksForDeployment } from "@corbits/inference-catalog/ollama-context-defaults"; import { type PublishCorbitsToolsRegistryArgs } from "@corbits/tool-registry-publish"; diff --git a/packages/plugins-ui/package.json b/packages/plugins-ui/package.json index 1648f8fa3..05efa6eff 100644 --- a/packages/plugins-ui/package.json +++ b/packages/plugins-ui/package.json @@ -16,7 +16,6 @@ "dependencies": { "@corbits/react-ui": "github:corbitsdev/react-ui#3b122812a307ccb35be31386f7696020c5a84635", "@corbits/settings-ui": "workspace:*", - "@corbits/workflow-catalog": "workspace:*", "@workbench/connections": "workspace:*", "arktype": "catalog:", "@corbits/icons": "workspace:*", diff --git a/packages/routines/README.md b/packages/routines/README.md index b39b699de..f1b4b7cf2 100644 --- a/packages/routines/README.md +++ b/packages/routines/README.md @@ -14,7 +14,7 @@ Built on `@intx/hub-api`'s `TenantEnv`/`requireGrant` route convention and session orchestration directly — launching a run (manual "run now" or a scheduled fire) goes through `@corbits/folded-runs`, the same launch core `@corbits/chat`'s invite flow uses. It also depends on -`@corbits/workflow-catalog` to resolve a definition's delivery mode +`@workbench/templates` to resolve a definition's delivery mode (workbench vs. inbox-only) so a routine's create/fire path never requires a `deliveryWorkbenchId` a workflow would silently discard. @@ -96,7 +96,7 @@ otherwise) only groups the picker. - `listRoutineTargets(deps, query)` authorizes every candidate with `@intx/authz`'s `authorize` on `workflow-definition:` / `read` before it is counted, sorted, or returned — a denied row never shapes the page — - then applies the product filter (`@corbits/workflow-catalog`'s + then applies the product filter (`@workbench/templates`'s `isAutomatableWorkflowName` or `isConversationalWorkflowName`, never a workbench-host anchor name) and orders by `(name asc, definitionAssetId asc)`. Pagination is an opaque cursor over that key; `limit` defaults to diff --git a/packages/routines/package.json b/packages/routines/package.json index 615271a96..a7404ea16 100644 --- a/packages/routines/package.json +++ b/packages/routines/package.json @@ -22,7 +22,6 @@ "@corbits/migration-runner": "workspace:*", "@corbits/slug": "workspace:*", "cronstrue": "^3.24.0", - "@corbits/workflow-catalog": "workspace:*", "@corbits/workflows": "workspace:*", "@intx/authz": "0.3.0", "@intx/db": "workspace:*", diff --git a/packages/routines/src/client.ts b/packages/routines/src/client.ts index 3469ec126..b3534c098 100644 --- a/packages/routines/src/client.ts +++ b/packages/routines/src/client.ts @@ -151,7 +151,7 @@ export type CreateRoutineInput = { readonly trigger: RoutineTriggerT; readonly scope: "personal" | "bench"; /** Omitted only for a workflow whose result never posts to a workbench - * (see `@corbits/workflow-catalog`'s `WorkflowCatalogEntry.deliveryMode`) + * (see `@corbits/workflows`'s `WorkflowCatalogEntry.deliveryMode`) * — the server itself still rejects a missing value for every other * workflow (`deliveryWorkbenchRequired`, routes.ts). */ readonly deliveryWorkbenchId?: string; @@ -198,7 +198,7 @@ export function routineRunsPath(tenantId: string, id: string): string { // `kind` groups the picker without changing execution semantics: an // "agent" is a single-step conversational fold, everything else a // "workflow". `assetName` is the raw catalog key -// (`@corbits/workflow-catalog`'s `workflowCatalogEntry`); `name` is the +// (`@corbits/workflows`'s `workflowCatalogEntry`); `name` is the // display label. export const RoutineTargetKind = type("'agent' | 'workflow'"); export type RoutineTargetKind = typeof RoutineTargetKind.infer; diff --git a/packages/routines/src/targets.ts b/packages/routines/src/targets.ts index 41f099a2f..783c1c193 100644 --- a/packages/routines/src/targets.ts +++ b/packages/routines/src/targets.ts @@ -20,8 +20,6 @@ import { isAutomatableWorkflowName, isConversationalWorkflowName, workflowDisplayName, -} from "@corbits/workflow-catalog"; -import { listLaunchableDefinitions, type LaunchableDefinition, } from "@corbits/workflows"; diff --git a/packages/settings-ui/package.json b/packages/settings-ui/package.json index 195fc707c..923ebd045 100644 --- a/packages/settings-ui/package.json +++ b/packages/settings-ui/package.json @@ -23,7 +23,7 @@ "@corbits/error-sink": "workspace:*", "@corbits/inference-settings": "workspace:*", "@corbits/react-ui": "github:corbitsdev/react-ui#3b122812a307ccb35be31386f7696020c5a84635", - "@corbits/workflow-catalog": "workspace:*", + "@workbench/templates": "workspace:*", "@intx/types": "workspace:*", "@workbench/connections": "workspace:*", "arktype": "catalog:", diff --git a/packages/settings-ui/src/connections-pinned-by.test.ts b/packages/settings-ui/src/connections-pinned-by.test.ts index 2161d2e07..964fca1b8 100644 --- a/packages/settings-ui/src/connections-pinned-by.test.ts +++ b/packages/settings-ui/src/connections-pinned-by.test.ts @@ -1,6 +1,6 @@ import { describe, expect, test } from "bun:test"; -import { WORKFLOW_CATALOG } from "@corbits/workflow-catalog"; +import { WORKFLOW_CATALOG } from "@workbench/templates"; import { CONNECTOR_PINNED_WORKFLOWS } from "./connections-pinned-by"; diff --git a/packages/settings-ui/src/connections-section.tsx b/packages/settings-ui/src/connections-section.tsx index 30b9ca41e..a88c21068 100644 --- a/packages/settings-ui/src/connections-section.tsx +++ b/packages/settings-ui/src/connections-section.tsx @@ -26,7 +26,7 @@ import { type ConnectorDescriptor, } from "@workbench/connections/registry"; import { MCP_PRESET_CONNECTOR_IDS } from "@workbench/connections/mcp-presets"; -import { workflowDisplayName } from "@corbits/workflow-catalog"; +import { workflowDisplayName } from "@workbench/templates"; import { buildEffectiveInferenceRows, computeGlobalRoutePatches, diff --git a/packages/settings-ui/src/granola-webhook-card.tsx b/packages/settings-ui/src/granola-webhook-card.tsx index c438759b0..e50187024 100644 --- a/packages/settings-ui/src/granola-webhook-card.tsx +++ b/packages/settings-ui/src/granola-webhook-card.tsx @@ -8,7 +8,7 @@ // // "Granola-ish" means bound to the `granola-call` workflow definition // specifically — the one automatable Granola workflow in -// `@corbits/workflow-catalog` (`process-granola-call` is a child run, +// `@workbench/templates` (`process-granola-call` is a child run, // never a routine). A routine picker is deliberately not built: with // exactly one candidate workflow, offering a picker over a list of one // would be UI theater, not a real choice. diff --git a/packages/webhook-triggers/src/repo-review-lease.ts b/packages/webhook-triggers/src/repo-review-lease.ts index 6fa2b18ef..2238f5720 100644 --- a/packages/webhook-triggers/src/repo-review-lease.ts +++ b/packages/webhook-triggers/src/repo-review-lease.ts @@ -1,6 +1,6 @@ // Closes a check-then-act race in the GitHub connect card's // start-reviewing step (CL-7242): `startReviewingRepos` -// (`@corbits/workflow-catalog`) loops over selected repos doing +// (`@workbench/connections`) loops over selected repos doing // hasRepoGrant/mintRepoGrant then hasWebhookTrigger/createWebhookTrigger // per repo, each a plain read followed by a conditional write with no // atomic backstop. Two concurrent calls for the same repo (a diff --git a/packages/workflow-catalog/README.md b/packages/workflow-catalog/README.md deleted file mode 100644 index 5f71cbbcd..000000000 --- a/packages/workflow-catalog/README.md +++ /dev/null @@ -1,68 +0,0 @@ -# @corbits/workflow-catalog - -Deploy-layer metadata for every seeded workflow package: display name, -whether it's schedulable as a routine, where its result actually lands -(a channel vs. the creator's Inbox only), required connections, and -optional trigger-input fields. Interchange's `defineWorkflow` has no -automatable/display-name concept of its own, so each `workflows/*/package.json` -carries a `corbits.workflow` block, and this package is the TypeScript -mirror both the seed script and the routines create picker import — the -browser never reads `package.json` at runtime. - -Also the home of **workbench templates** (`src/templates.ts`): a named -workbench worth having, assembled out of several catalog workflows, the -routines and webhook triggers that keep it running, the agents a person -talks to in it, and the open questions only they can answer. `apps/web`'s -`/new` picker and `instant-agent-create.ts` both read this as the single -description of what picking a template actually creates. - -## Composition with @intx/* - -No direct `@intx/*` imports. `src/templates.ts` and `src/instantiate.ts` -depend on `@corbits/code-review`, but only through its `./reviewers` and -`./agent-requests` subpaths — never the package root, which also -re-exports the review run and GitHub client and pulls in -`@corbits/github-tools` and `@intx/agent`'s full provider surface. Those -two files have no imports of their own, so this stays off that graph. -It is also consumed by `@corbits/routines` (to decide whether a routine -needs a delivery channel and to validate trigger input) and by -`@workbench/connections` (dev dependency only, for the connector-id type -trigger fields reference). - -## Key modules - -- `src/index.ts` — the catalog: `WORKFLOW_CATALOG` (the array of - `WorkflowCatalogEntry` records, one per seeded workflow), `WorkflowTriggerField` - (the arktype schema for a named trigger input), and the lookup helpers - `isAutomatableWorkflowName`, `deliveryChannelRequiredForWorkflowName`, - `workflowCatalogEntry`, `workflowDisplayName`, and - `validateTriggerFieldsInput`. -- `src/templates.ts` — `WorkbenchDefinition` (default agents, routines, - tools, plugins, and the ordered `onboardingSteps` walkthrough) and the - shipped definitions themselves (`GTM_TEMPLATE`, - `CODE_REVIEW_TEMPLATE`, `DUE_DILIGENCE_TEMPLATE`), each validated at - module load; `workbenchTemplate(id)` looks one up. -- `src/instantiate.ts` — `instantiateWorkbenchTemplate`: resolves a - definition against a bench over injected ports (create the agent - definitions that don't exist yet, record required plugins as pending, - then begin the definition's onboarding walkthrough). Today this only - supports a definition whose agents are backed by - `@corbits/code-review`'s reviewer roster or a standalone chat agent - this package can build a create request for. -- `src/settings.ts` — the `template/*` workbench-settings vocabulary a - template-instantiated room persists about itself. - -## Keeping the mirror in sync - -Each `workflows/*/package.json`'s `corbits.workflow` block is the -npm-visible source of truth for package authors; `WORKFLOW_CATALOG` here is -what runtime code actually reads. Adding or changing a workflow's catalog -facts means updating both — there is no codegen step keeping them in sync. - -## Running tests - -``` -cd packages/workflow-catalog && bun test -``` - -No drizzle suite; no `DATABASE_URL` needed. diff --git a/packages/workflow-catalog/package.json b/packages/workflow-catalog/package.json deleted file mode 100644 index 938edddfd..000000000 --- a/packages/workflow-catalog/package.json +++ /dev/null @@ -1,39 +0,0 @@ -{ - "name": "@corbits/workflow-catalog", - "private": true, - "description": "Deploy-layer workflow metadata (automatable, display names) mirrored from each workflows/*/package.json corbits.workflow field \u2014 the routines picker and seed share this pure catalog so the browser never reads package.json at runtime", - "version": "0.0.1", - "license": "LGPL-2.1-or-later", - "type": "module", - "exports": { - ".": "./src/index.ts", - "./connect-github-routes": "./src/connect-github-routes.ts", - "./template-block-routes": "./src/template-block-routes.ts" - }, - "scripts": { - "typecheck": "tsc --noEmit", - "test": "bun test" - }, - "dependencies": { - "@corbits/code-review": "workspace:*", - "@corbits/code-review-workflow": "workspace:*", - "@corbits/error-sink": "workspace:*", - "@corbits/github-tools": "workspace:*", - "@corbits/jimmy-agent": "workspace:*", - "@corbits/scout-agent": "workspace:*", - "@corbits/webhook-triggers": "workspace:*", - "@intx/db": "workspace:*", - "@intx/hub-api": "workspace:*", - "@workbench/hub-client": "workspace:*", - "arktype": "catalog:", - "drizzle-orm": "catalog:", - "hono": "^4.11.9", - "postgres": "catalog:" - }, - "devDependencies": { - "@intx/crypto": "0.3.0", - "@types/bun": "catalog:", - "@workbench/connections": "workspace:*", - "typescript": "catalog:" - } -} diff --git a/packages/workflows/package.json b/packages/workflows/package.json index d561f7c95..222647f09 100644 --- a/packages/workflows/package.json +++ b/packages/workflows/package.json @@ -7,7 +7,8 @@ "type": "module", "exports": { ".": "./src/index.ts", - "./client": "./src/client.ts" + "./client": "./src/client.ts", + "./catalog": "./src/catalog.ts" }, "scripts": { "typecheck": "tsc --noEmit", @@ -29,6 +30,7 @@ }, "devDependencies": { "@types/bun": "catalog:", + "@workbench/connections": "workspace:*", "typescript": "catalog:" } } diff --git a/packages/workflow-catalog/test/catalog.test.ts b/packages/workflows/src/catalog.test.ts similarity index 99% rename from packages/workflow-catalog/test/catalog.test.ts rename to packages/workflows/src/catalog.test.ts index 75c6b88b3..bf6c36d1b 100644 --- a/packages/workflow-catalog/test/catalog.test.ts +++ b/packages/workflows/src/catalog.test.ts @@ -13,7 +13,7 @@ import { workflowCatalogEntry, WorkflowTriggerField, WORKFLOW_CATALOG, -} from "../src/index"; +} from "./catalog"; describe("workflow catalog", () => { test("marks workbench-digest, heartbeat, and morning-brief automatable, not echo or assistant", () => { diff --git a/packages/workflow-catalog/src/index.ts b/packages/workflows/src/catalog.ts similarity index 83% rename from packages/workflow-catalog/src/index.ts rename to packages/workflows/src/catalog.ts index 9b1d43e97..8d2fa4770 100644 --- a/packages/workflow-catalog/src/index.ts +++ b/packages/workflows/src/catalog.ts @@ -1,58 +1,56 @@ -// Deploy-layer metadata for seeded workflow packages. Interchange's -// defineWorkflow has no automatable / display-name fields; each -// workflows/*/package.json carries a `corbits.workflow` block, and this -// module is the TypeScript mirror both seed and the web picker import. -// Keep the two in lockstep — the package.json block is the npm-visible -// source of truth for package authors; this list is what runtime code -// reads. - +// Deploy-layer metadata for every seeded workflow package: display name, +// whether it's schedulable as a routine, where its result actually lands +// (a channel vs. the creator's Inbox only), required connections, and +// optional trigger-input fields. Interchange's `defineWorkflow` has no +// automatable/display-name concept of its own. +// +// `assetName`/`displayName`/`automatable` are read straight off each +// `workflows/*/package.json`'s `corbits.workflow` block via a static JSON +// import below — resolved at build time (Vite, tsc, and Bun all support +// `resolveJsonModule`), never at runtime, so this stays importable from +// the browser bundle. There is nothing left to keep "in lockstep": the +// package.json block IS the value this module reads, not a copy of it. +// The remaining fields (`conversational`, `deliveryMode`, `whatItDoes`, +// `requiredConnections`, `exampleOutput`, `typicalDuration`, +// `triggerFields`) have no npm-visible home of their own — they exist +// only here, so there is no second copy for them to drift from. import { type } from "arktype"; -export { - CODE_REVIEW_TEMPLATE, - DUE_DILIGENCE_TEMPLATE, - GTM_TEMPLATE, - WORKBENCH_TEMPLATES, - WorkbenchDefinitionAgent, - WorkbenchDefinitionSchema, - WorkbenchOnboardingStep, - WorkbenchTemplateBlock, - WorkbenchTemplateOpenInput, - WorkbenchTemplateRoutine, - WorkbenchTemplateWebhookTrigger, - parseWorkbenchDefinition, - serializeWorkbenchDefinition, - templateBlockAssetNames, - workbenchTemplate, - workbenchTemplateLibraryEntries, -} from "./templates"; -export type { WorkbenchDefinition } from "./templates"; -export { - instantiateWorkbenchTemplate, - type ParticipantAgentRequest, - type WorkbenchTemplateInstantiationPorts, - type WorkbenchTemplateInstantiationResult, -} from "./instantiate"; -export { - jimmyAgentRequest, - scoutAgentRequest, -} from "./participant-agent-requests"; -export { - TemplateReposSettingsPatch, - TemplateSettingsPatch, - templateReposSettingsPatch, - templateSettingsPatch, -} from "./settings"; -export { - startReviewingRepos, - webhookTriggerName, - type ConnectGithubSetupPorts, - type StartReviewingReposResult, -} from "./connect-github-setup"; -// CL-7373: the workflow definition lifecycle/detail types moved to -// @corbits/workflows (`.` for the detail route, `./client` for the -// browser-safe wire schema and pure lifecycle derivation) alongside the -// deploy-source record they read. +import echoPkg from "../../../workflows/echo/package.json"; +import codeReviewPkg from "../../../workflows/code-review/package.json"; +import assistantPkg from "../../../workflows/assistant/package.json"; +import heartbeatPkg from "../../../workflows/heartbeat/package.json"; +import workbenchDigestPkg from "../../../workflows/workbench-digest/package.json"; +import granolaCallPkg from "../../../workflows/granola-call/package.json"; +import processGranolaCallPkg from "../../../workflows/process-granola-call/package.json"; +import morningBriefPkg from "../../../workflows/morning-brief/package.json"; +import painPointCollateralPkg from "../../../workflows/pain-point-collateral/package.json"; +import collateralGenerationPkg from "../../../workflows/collateral-generation/package.json"; +import redditOpportunityScannerPkg from "../../../workflows/reddit-opportunity-scanner/package.json"; +import last30DaysResearchPkg from "../../../workflows/last-30-days-research/package.json"; +import diligenceBriefPkg from "../../../workflows/diligence-brief/package.json"; +import exaTopicWatchPkg from "../../../workflows/exa-topic-watch/package.json"; +import attioTaskAgentPkg from "../../../workflows/attio-task-agent/package.json"; + +const CorbitsWorkflowBlock = type({ + assetName: "string > 0", + displayName: "string > 0", + automatable: "boolean", +}); +type CorbitsWorkflowBlock = typeof CorbitsWorkflowBlock.infer; + +/** Reads one workflow package's `corbits.workflow` block — the only + * source of truth for `assetName`/`displayName`/`automatable`. Throws on + * a malformed block rather than seeding a broken catalog entry. */ +function workflowBlock(pkg: { + readonly corbits?: { readonly workflow?: unknown }; +}): CorbitsWorkflowBlock { + const parsed = CorbitsWorkflowBlock(pkg.corbits?.workflow); + if (parsed instanceof type.errors) { + throw new Error(`invalid corbits.workflow block: ${parsed.summary}`); + } + return parsed; +} /** * One named field a mail trigger reads by name — the create-time UI's only @@ -141,9 +139,7 @@ export type WorkflowCatalogEntry = { */ export const WORKFLOW_CATALOG: readonly WorkflowCatalogEntry[] = [ { - assetName: "echo", - displayName: "Echo", - automatable: false, + ...workflowBlock(echoPkg), conversational: false, deliveryMode: "workbench", whatItDoes: @@ -153,9 +149,7 @@ export const WORKFLOW_CATALOG: readonly WorkflowCatalogEntry[] = [ typicalDuration: "a few seconds", }, { - assetName: "code-review", - displayName: "Code review", - automatable: false, + ...workflowBlock(codeReviewPkg), conversational: false, deliveryMode: "workbench", whatItDoes: @@ -175,9 +169,7 @@ export const WORKFLOW_CATALOG: readonly WorkflowCatalogEntry[] = [ ], }, { - assetName: "assistant", - displayName: "Myra", - automatable: false, + ...workflowBlock(assistantPkg), conversational: true, deliveryMode: "workbench", whatItDoes: @@ -187,9 +179,7 @@ export const WORKFLOW_CATALOG: readonly WorkflowCatalogEntry[] = [ typicalDuration: "varies with the conversation", }, { - assetName: "heartbeat", - displayName: "Heartbeat", - automatable: true, + ...workflowBlock(heartbeatPkg), conversational: false, deliveryMode: "workbench", whatItDoes: @@ -199,9 +189,7 @@ export const WORKFLOW_CATALOG: readonly WorkflowCatalogEntry[] = [ typicalDuration: "a few seconds", }, { - assetName: "workbench-digest", - displayName: "Workbench digest", - automatable: true, + ...workflowBlock(workbenchDigestPkg), conversational: false, deliveryMode: "workbench", whatItDoes: @@ -211,9 +199,7 @@ export const WORKFLOW_CATALOG: readonly WorkflowCatalogEntry[] = [ typicalDuration: "a few seconds", }, { - assetName: "granola-call", - displayName: "Granola call notes", - automatable: true, + ...workflowBlock(granolaCallPkg), conversational: false, deliveryMode: "workbench", whatItDoes: @@ -223,9 +209,7 @@ export const WORKFLOW_CATALOG: readonly WorkflowCatalogEntry[] = [ typicalDuration: "a few seconds", }, { - assetName: "process-granola-call", - displayName: "Process Granola call", - automatable: false, + ...workflowBlock(processGranolaCallPkg), conversational: false, deliveryMode: "workbench", whatItDoes: @@ -236,9 +220,7 @@ export const WORKFLOW_CATALOG: readonly WorkflowCatalogEntry[] = [ typicalDuration: "1-2 minutes", }, { - assetName: "morning-brief", - displayName: "Morning brief", - automatable: true, + ...workflowBlock(morningBriefPkg), conversational: false, deliveryMode: "workbench", whatItDoes: @@ -249,9 +231,7 @@ export const WORKFLOW_CATALOG: readonly WorkflowCatalogEntry[] = [ typicalDuration: "under a minute", }, { - assetName: "pain-point-collateral", - displayName: "Pain-point collateral", - automatable: false, + ...workflowBlock(painPointCollateralPkg), conversational: false, deliveryMode: "workbench", whatItDoes: @@ -286,9 +266,7 @@ export const WORKFLOW_CATALOG: readonly WorkflowCatalogEntry[] = [ ], }, { - assetName: "collateral-generation", - displayName: "Collateral generation", - automatable: false, + ...workflowBlock(collateralGenerationPkg), conversational: false, deliveryMode: "workbench", whatItDoes: @@ -299,9 +277,7 @@ export const WORKFLOW_CATALOG: readonly WorkflowCatalogEntry[] = [ typicalDuration: "several minutes, plus review and approval time", }, { - assetName: "reddit-opportunity-scanner", - displayName: "Reddit opportunity scanner", - automatable: false, + ...workflowBlock(redditOpportunityScannerPkg), conversational: false, deliveryMode: "workbench", whatItDoes: @@ -311,9 +287,7 @@ export const WORKFLOW_CATALOG: readonly WorkflowCatalogEntry[] = [ typicalDuration: "a few minutes, plus review and approval time", }, { - assetName: "last-30-days-research", - displayName: "Last 30 days research report", - automatable: false, + ...workflowBlock(last30DaysResearchPkg), conversational: false, deliveryMode: "workbench", whatItDoes: @@ -345,9 +319,7 @@ export const WORKFLOW_CATALOG: readonly WorkflowCatalogEntry[] = [ ], }, { - assetName: "diligence-brief", - displayName: "Diligence brief", - automatable: false, + ...workflowBlock(diligenceBriefPkg), conversational: false, deliveryMode: "workbench", whatItDoes: @@ -380,9 +352,7 @@ export const WORKFLOW_CATALOG: readonly WorkflowCatalogEntry[] = [ ], }, { - assetName: "exa-topic-watch", - displayName: "Web topic watch", - automatable: true, + ...workflowBlock(exaTopicWatchPkg), conversational: false, deliveryMode: "workbench", whatItDoes: @@ -405,9 +375,7 @@ export const WORKFLOW_CATALOG: readonly WorkflowCatalogEntry[] = [ ], }, { - assetName: "attio-task-agent", - displayName: "Attio task agent", - automatable: false, + ...workflowBlock(attioTaskAgentPkg), conversational: false, deliveryMode: "workbench", whatItDoes: diff --git a/packages/workflows/src/client.ts b/packages/workflows/src/client.ts index 9147776e2..897be0772 100644 --- a/packages/workflows/src/client.ts +++ b/packages/workflows/src/client.ts @@ -34,3 +34,15 @@ export { type WorkflowLifecycle, type WorkflowLifecycleResult, } from "./detail/definition-lifecycle"; +export { + WorkflowTriggerField, + WORKFLOW_CATALOG, + isAutomatableWorkflowName, + isConversationalWorkflowName, + deliveryWorkbenchRequiredForWorkflowName, + workflowCatalogEntry, + workflowDisplayName, + validateTriggerFieldsAtCreate, + type WorkflowCatalogEntry, + type TriggerFieldsValidation, +} from "./catalog"; diff --git a/packages/workflows/src/index.ts b/packages/workflows/src/index.ts index 70fab5001..d46073880 100644 --- a/packages/workflows/src/index.ts +++ b/packages/workflows/src/index.ts @@ -18,3 +18,15 @@ export { type LaunchableDefinitionResolution, type LaunchableDefinitionResolver, } from "./launchable/target"; +export { + WorkflowTriggerField, + WORKFLOW_CATALOG, + isAutomatableWorkflowName, + isConversationalWorkflowName, + deliveryWorkbenchRequiredForWorkflowName, + workflowCatalogEntry, + workflowDisplayName, + validateTriggerFieldsAtCreate, + type WorkflowCatalogEntry, + type TriggerFieldsValidation, +} from "./catalog"; diff --git a/scripts/checks/error-envelope.ts b/scripts/checks/error-envelope.ts index aa72932a7..8ded99938 100644 --- a/scripts/checks/error-envelope.ts +++ b/scripts/checks/error-envelope.ts @@ -9,7 +9,8 @@ // Documented exceptions live in ALLOWLIST below. Each entry is an // explicit ruling that the named file may keep a helper because it // already wraps the canonical `makeErrorEnvelope` (onboarding, -// workflow-catalog) or *is* the canonical helper (hub-client). +// connections, the hub's own template routes) or *is* the canonical +// helper (hub-client). import { Glob } from "bun"; import path from "node:path"; import { @@ -24,8 +25,8 @@ const SCAN_DIRS = ["apps", "packages", "workflows"]; const ALLOWLIST = new Set([ "packages/hub-client/src/error-envelope.ts", "packages/onboarding/src/routes.ts", - "packages/workflow-catalog/src/connect-github-routes.ts", - "packages/workflow-catalog/src/template-block-routes.ts", + "packages/connections/src/connect-github-routes.ts", + "apps/hub/src/templates/template-block-routes.ts", ]); // Arrow: `const ErrorEnvelope = (code: string, message: string) => ({ diff --git a/scripts/checks/report-error-baseline.txt b/scripts/checks/report-error-baseline.txt index 67c25e6f4..6aa7d7d49 100644 --- a/scripts/checks/report-error-baseline.txt +++ b/scripts/checks/report-error-baseline.txt @@ -34,6 +34,7 @@ apps/hub/src/routine-scheduler.ts 1 const reason = err instanceof Error ? err.me apps/hub/src/routine-scheduler.ts 1 log.error`marking routine ${claimed.id}'s failed fire also failed: ${ apps/hub/src/routine-scheduler.ts 1 log.error`routine scheduler tick failed: ${ apps/hub/src/shutdown.ts 1 return { kind: "failed", error }; +apps/hub/src/templates/template-block-routes.ts 1 const message = cause instanceof Error ? cause.message : String(cause); apps/sidecar/src/atomic-write.ts 1 logger.warn`parent-dir fsync failed for ${path}; durability is degraded but the file is renamed and fsynced — ${err instanceof Error ? err.message : String(err)}`; apps/sidecar/src/concurrency.ts 1 failures.push({ item, error }); apps/sidecar/src/conversation-state.ts 1 logger.warn`connector route for ${opts.agentKey} could not parse the inbound sender; leaving the thread unadvanced: ${cause instanceof Error ? cause.message : String(cause)}`; @@ -157,6 +158,8 @@ packages/connections-tools/src/tool.ts 1 return errorResult(call.id, err); packages/connections-tools/src/tool.ts 2 return errorResult(call.id, err); packages/connections-tools/src/tool.ts 3 return errorResult(call.id, err); packages/connections-tools/src/tool.ts 4 return errorResult(call.id, err); +packages/connections/src/connect-github-routes.ts 1 // A repoId `state.repos` doesn't carry means the card's own +packages/connections/src/connect-github-routes.ts 1 // The GitHub client's own errors (transport, HTTP status, shape packages/error-sink/src/index.ts 1 return context.refId ?? UNKNOWN_OPERATION; packages/folded-run-one-shot/src/one-shot-reply.ts 1 log.error`one-shot run ${triggerAddress}: undeploy failed during teardown (${reason}): ${ packages/folded-run-one-shot/src/one-shot-reply.ts 1 void settle("planning-run-send-failed", () => { @@ -258,9 +261,6 @@ packages/web-search-tools/src/tool.ts 1 return null; packages/web-search-tools/src/tool.ts 1 return { packages/webhook-triggers/src/ingress-routes.ts 1 return c.json( packages/webhook-triggers/src/signature.ts 1 return false; -packages/workflow-catalog/src/connect-github-routes.ts 1 // A repoId `state.repos` doesn't carry means the card's own -packages/workflow-catalog/src/connect-github-routes.ts 1 // The GitHub client's own errors (transport, HTTP status, shape -packages/workflow-catalog/src/template-block-routes.ts 1 const message = cause instanceof Error ? cause.message : String(cause); workflows/attio-task-agent/src/finalize-tool.ts 1 return { workflows/collateral-generation/src/finalize-tool.ts 1 return { workflows/diligence-brief/src/finalize-tool.ts 1 return { diff --git a/scripts/db-setup.ts b/scripts/db-setup.ts index 35ac52433..06cbde988 100644 --- a/scripts/db-setup.ts +++ b/scripts/db-setup.ts @@ -37,7 +37,7 @@ import { listWorkbenchLaunchFoldedRunIds, } from "../packages/chat/src/migrations"; import { applyWebhookTriggersMigrations } from "../packages/webhook-triggers/src/migrations"; -import { reconcileDuplicateRepoGrants } from "../packages/workflow-catalog/src/reconcile-duplicate-repo-grants"; +import { reconcileDuplicateRepoGrants } from "../packages/connections/src/reconcile-duplicate-repo-grants"; import { applyNotifyMigrations } from "../packages/notify/src/migrations"; import { applyRoutineMigrations } from "../packages/routines/src/migrations"; import { diff --git a/packages/workflow-catalog/LICENSE b/templates/LICENSE similarity index 100% rename from packages/workflow-catalog/LICENSE rename to templates/LICENSE diff --git a/templates/README.md b/templates/README.md new file mode 100644 index 000000000..fea840dd7 --- /dev/null +++ b/templates/README.md @@ -0,0 +1,16 @@ +# Workbench templates + +Each subdirectory is one shipped `WorkbenchDefinition`: the agents, +routines, webhook triggers, plugins, and onboarding walkthrough a +"pick a kind of workbench" row creates. `index.ts` is the single +description both `apps/web`'s picker and `./instantiate.ts` read — the +schema, the assembled `WORKBENCH_TEMPLATES` list, and the +parse/serialize helpers a bench-library row round-trips through. + +- `gtm/` — the go-to-market workbench (CL-6349) +- `code-review/` — three reviewer lenses over every pull request +- `due-diligence/` — Scout plus Myra for research and follow-up + +`./instantiate.ts` resolves a definition against a bench over injected +ports; `./settings.ts` is the `template/*` settings vocabulary a room +persists about the template it was minted from. diff --git a/templates/code-review/index.ts b/templates/code-review/index.ts new file mode 100644 index 000000000..a8a75ded9 --- /dev/null +++ b/templates/code-review/index.ts @@ -0,0 +1,74 @@ +// The code-review definition: three reviewer lenses over every pull +// request. Its blocks install the one `code-review` workflow; the +// reviewer roster itself is `@corbits/code-review`'s own +// `CODE_REVIEW_REVIEWERS` — mirrored into `agents` here rather than +// duplicated, so a reviewer's handle, name, and one-line role can never +// drift between the package that runs the review and the definition +// that describes it. +import type { WorkbenchDefinition } from "../index"; +// Imported from the package's own `./reviewers` subpath, never its root +// (`@corbits/code-review`) — the root barrel also re-exports the review +// run and GitHub client, which pull in `@corbits/github-tools` and +// `@intx/agent`'s full provider surface. `reviewers.ts` itself has no +// imports at all, so this subpath keeps every consumer of this +// definition (this package's whole point) off that much heavier graph. +import { CODE_REVIEW_REVIEWERS } from "@corbits/code-review/reviewers"; + +export const CODE_REVIEW_TEMPLATE: WorkbenchDefinition = { + id: "code-review", + title: "Code review", + promise: + "Three reviewers read every pull request and post what they'd change.", + blocks: [{ assetName: "code-review", version: "0.0.1" }], + // GitHub is the one thing this template cannot work without: no + // repository, no diff to read and nowhere to post the review. + plugins: { required: ["github"], optional: [] }, + tools: ["@corbits/github-tools"], + routines: [], + webhookTriggers: [ + { + key: "pull-request-opened", + blockAssetName: "code-review", + label: "Review new pull requests", + why: "A review is worth most posted while the pull request is still open for comment, so this fires the moment GitHub says one exists rather than waiting on a clock.", + triggerFieldKey: "pullRequestUrl", + }, + ], + agents: [ + ...CODE_REVIEW_REVIEWERS.map((reviewer) => ({ + handle: reviewer.handle, + displayName: reviewer.displayName, + blockAssetName: "code-review", + role: reviewer.description, + })), + ], + openInputs: [ + { + key: "repos", + label: "Which repositories?", + placeholder: "corbitsdev/workbench", + help: "The GitHub repositories to watch. Every new pull request there gets reviewed.", + required: true, + appliesToWebhookTrigger: "pull-request-opened", + }, + ], + onboardingSteps: [ + { + kind: "connect-plugin", + connectorId: "github", + title: "Connect GitHub", + why: "Create a token scoped to the repositories you want reviewed — that is what the reviewers will be able to read.", + }, + { + kind: "pick-github-repos", + title: "Choose what gets reviewed", + why: "Of the repositories your token reaches, these are the ones a new pull request starts a review in.", + }, + { + kind: "start-webhook-trigger", + webhookTriggerKey: "pull-request-opened", + title: "Start reviewing", + why: "From now on, every new pull request in those repositories gets a review.", + }, + ], +}; diff --git a/templates/due-diligence/index.ts b/templates/due-diligence/index.ts new file mode 100644 index 000000000..87e8f5690 --- /dev/null +++ b/templates/due-diligence/index.ts @@ -0,0 +1,40 @@ +// The due-diligence template (CL-6499): Scout for the web/firm-memory +// research and Myra to talk through what it found. Scout is a +// standalone chat agent, not a lens over a block workflow — it has no +// cron, no webhook, nothing to schedule — so it carries no +// `blockAssetName` and this template's `blocks` list stays empty. +// Exa (Scout's web-research tool) resolves through the keyless MCP +// preset, so nothing here blocks the create on a connection. +import type { WorkbenchDefinition } from "../index"; +import { + SCOUT_AGENT_HANDLE, + SCOUT_AGENT_DISPLAY_NAME, + SCOUT_AGENT_DESCRIPTION, + SCOUT_TOOL_PACKAGE_PINS, +} from "@corbits/scout-agent/definition"; + +export const DUE_DILIGENCE_TEMPLATE: WorkbenchDefinition = { + id: "due-diligence", + title: "Due Diligence", + promise: + "Scout checks a company, deal, or vendor against the web and what your team already knows, and saves what it finds so you can pick it up later.", + blocks: [], + plugins: { required: [], optional: ["exa"] }, + tools: SCOUT_TOOL_PACKAGE_PINS.map((pin) => pin.name), + routines: [], + webhookTriggers: [], + agents: [ + { + handle: "myra", + displayName: "Myra", + role: "Talks through what Scout found and helps you decide what to do with it.", + }, + { + handle: SCOUT_AGENT_HANDLE, + displayName: SCOUT_AGENT_DISPLAY_NAME, + role: SCOUT_AGENT_DESCRIPTION, + }, + ], + openInputs: [], + onboardingSteps: [], +}; diff --git a/templates/gtm/index.ts b/templates/gtm/index.ts new file mode 100644 index 000000000..4d5c1fe06 --- /dev/null +++ b/templates/gtm/index.ts @@ -0,0 +1,97 @@ +// The GTM template (CL-6349): the go-to-market workbench, ported from the +// OG gtm-workbench's four v1 workflows. +// +// The call backbone (granola-call discovering new calls, process-granola-call +// writing each one up) is what makes the workbench useful on day one, so it +// is the routine that runs on a clock without anyone asking. The web watch +// runs on its own weekly clock. The CRM agent and the collateral drafter are +// on-demand: both start from a specific thing a person points at. +import type { WorkbenchDefinition } from "../index"; + +export const GTM_TEMPLATE: WorkbenchDefinition = { + id: "gtm", + title: "Go to market", + promise: + "Your calls get written up, your CRM tasks get worked, and the web gets watched — you approve anything that leaves the room.", + blocks: [ + { assetName: "granola-call", version: "0.0.1" }, + { assetName: "process-granola-call", version: "0.0.1" }, + { assetName: "attio-task-agent", version: "0.0.1" }, + { assetName: "exa-topic-watch", version: "0.0.1" }, + { assetName: "pain-point-collateral", version: "0.0.1" }, + ], + // Attio and Exa are hard requirements: the CRM agent has nothing to + // work without Attio, and the web watch has nothing to read without + // Exa. Granola is what the call backbone runs on — the create flow + // offers it up front, but a workbench with the CRM agent and the web + // watch alone is still a real workbench, so it never blocks the create. + plugins: { required: ["attio", "exa"], optional: ["granola"] }, + tools: [], + webhookTriggers: [], + routines: [ + { + key: "call-discovery", + blockAssetName: "granola-call", + label: "Check for new calls", + cron: "*/30 9-18 * * 1-5", + why: "Notes are worth most right after the call, so this looks for new ones through the working day rather than once overnight.", + }, + { + key: "topic-watch", + blockAssetName: "exa-topic-watch", + label: "Watch the web", + cron: "0 8 * * 1", + why: "One digest at the start of the week, so a quiet week reads as quiet instead of as five empty runs.", + }, + ], + agents: [ + { + handle: "crm", + displayName: "CRM task agent", + blockAssetName: "attio-task-agent", + role: "Point it at a CRM task and it works the task — reading first, drafting second, and asking before it writes anything back.", + }, + { + handle: "collateral", + displayName: "Pain-point collateral", + blockAssetName: "pain-point-collateral", + role: "Give it a call transcript and it drafts a piece aimed at the pain point the customer actually named.", + }, + ], + openInputs: [ + { + key: "topic", + label: "What should we watch?", + placeholder: "AI coding agents for go-to-market", + help: "One topic, as specific as you can make it. The weekly digest covers this and nothing else.", + required: true, + appliesToRoutine: "topic-watch", + }, + ], + // GTM is not offered by the picker yet, and both its instantiation + // paths say so out loud rather than half-creating a workbench: + // `instantiateWorkbenchTemplate` throws because its agents are lenses + // over deployed workflow definitions with no agent-directory create + // request, and the web `beginOnboarding` binding throws because + // neither Attio nor Exa has an in-room onboarding card. + onboardingSteps: [ + { + kind: "connect-plugin", + connectorId: "attio", + title: "Connect Attio", + why: "The CRM agent reads and works your tasks in Attio — without it there is nothing to work.", + }, + { + kind: "connect-plugin", + connectorId: "exa", + title: "Connect Exa", + why: "The weekly web watch reads the open web through Exa.", + }, + { + kind: "connect-plugin", + connectorId: "granola", + title: "Connect Granola", + why: "Connect it and every new call gets written up on its own; skip it and the rest of the workbench still works.", + }, + ], +}; diff --git a/packages/workflow-catalog/src/templates.ts b/templates/index.ts similarity index 63% rename from packages/workflow-catalog/src/templates.ts rename to templates/index.ts index 2600f11d1..407c0c405 100644 --- a/packages/workflow-catalog/src/templates.ts +++ b/templates/index.ts @@ -3,18 +3,19 @@ // plugins, and the ordered onboarding walkthrough a person works // through once the room exists. // -// `./index.ts`'s `WORKFLOW_CATALOG` describes ONE workflow at a time — -// what it does, what it needs connected, what its trigger carries. A -// definition is the layer above: a named workbench worth having, -// assembled out of several of those workflows. The three shipped -// definitions here are the bench library's templates; a *template* is a -// shipped definition, not a second kind of thing. +// `@corbits/workflows/catalog`'s `WORKFLOW_CATALOG` describes ONE +// workflow at a time — what it does, what it needs connected, what its +// trigger carries. A definition is the layer above: a named workbench +// worth having, assembled out of several of those workflows. The three +// shipped definitions (one per subdirectory here) are the bench +// library's templates; a *template* is a shipped definition, not a +// second kind of thing. // // Everything here is pure data. Creating a workbench from a definition -// is a host concern (`apps/web`'s picker starts the flow); this module -// is the single description both the picker and the creator read, so -// neither hand-types an asset name, a cron, a connector id, or a step -// of onboarding copy. +// is a host concern (`apps/web`'s picker starts the flow, `./instantiate` +// resolves it); this module is the single description both the picker +// and the creator read, so neither hand-types an asset name, a cron, a +// connector id, or a step of onboarding copy. // // Blocks are referenced by asset name AND version. A definition names // the exact `workflows//package.json` version it was designed @@ -22,19 +23,7 @@ // a silent change in what it creates. import { type } from "arktype"; -// Imported from the package's own `./reviewers` subpath, never its root -// (`@corbits/code-review`) — the root barrel also re-exports the review -// run and GitHub client, which pull in `@corbits/github-tools` and -// `@intx/agent`'s full provider surface. `reviewers.ts` itself has no -// imports at all, so this subpath keeps every consumer of this -// definition (this package's whole point) off that much heavier graph. -import { CODE_REVIEW_REVIEWERS } from "@corbits/code-review/reviewers"; -import { - SCOUT_AGENT_HANDLE, - SCOUT_AGENT_DISPLAY_NAME, - SCOUT_AGENT_DESCRIPTION, - SCOUT_TOOL_PACKAGE_PINS, -} from "@corbits/scout-agent/definition"; + /** One workflow a template installs, pinned to the version it was * designed against. `assetName` matches a `WORKFLOW_CATALOG` entry. */ export const WorkbenchTemplateBlock = type({ @@ -84,11 +73,12 @@ export type WorkbenchDefinitionAgent = typeof WorkbenchDefinitionAgent.infer; * clock — the PR-review trigger a code-review template needs, as opposed * to `WorkbenchTemplateRoutine`'s cron-scheduled kind. `triggerFieldKey` * names the block's own `WorkflowCatalogEntry.triggerFields` entry the - * webhook payload fills — see `./index.ts`'s `WorkflowTriggerField`. - * Creating the live `webhook_trigger` row itself (`@corbits/webhook-triggers`) - * needs a repo to scope it to, which only exists once the person has - * answered the template's own open input for it — this is the spec a - * create flow resolves against that answer, not the row. + * webhook payload fills — see `@corbits/workflows/catalog`'s + * `WorkflowTriggerField`. Creating the live `webhook_trigger` row itself + * (`@corbits/webhook-triggers`) needs a repo to scope it to, which only + * exists once the person has answered the template's own open input for + * it — this is the spec a create flow resolves against that answer, not + * the row. */ export const WorkbenchTemplateWebhookTrigger = type({ /** Stable key an open input can point at. Unique within a template. */ @@ -198,206 +188,41 @@ export type WorkbenchDefinition = { readonly onboardingSteps: readonly WorkbenchOnboardingStep[]; }; -/** - * The GTM template (CL-6349): the go-to-market workbench, ported from the - * OG gtm-workbench's four v1 workflows. - * - * The call backbone (granola-call discovering new calls, process-granola-call - * writing each one up) is what makes the workbench useful on day one, so it - * is the routine that runs on a clock without anyone asking. The web watch - * runs on its own weekly clock. The CRM agent and the collateral drafter are - * on-demand: both start from a specific thing a person points at. - */ -export const GTM_TEMPLATE: WorkbenchDefinition = { - id: "gtm", - title: "Go to market", - promise: - "Your calls get written up, your CRM tasks get worked, and the web gets watched — you approve anything that leaves the room.", - blocks: [ - { assetName: "granola-call", version: "0.0.1" }, - { assetName: "process-granola-call", version: "0.0.1" }, - { assetName: "attio-task-agent", version: "0.0.1" }, - { assetName: "exa-topic-watch", version: "0.0.1" }, - { assetName: "pain-point-collateral", version: "0.0.1" }, - ], - // Attio and Exa are hard requirements: the CRM agent has nothing to - // work without Attio, and the web watch has nothing to read without - // Exa. Granola is what the call backbone runs on — the create flow - // offers it up front, but a workbench with the CRM agent and the web - // watch alone is still a real workbench, so it never blocks the create. - plugins: { required: ["attio", "exa"], optional: ["granola"] }, - tools: [], - webhookTriggers: [], - routines: [ - { - key: "call-discovery", - blockAssetName: "granola-call", - label: "Check for new calls", - cron: "*/30 9-18 * * 1-5", - why: "Notes are worth most right after the call, so this looks for new ones through the working day rather than once overnight.", - }, - { - key: "topic-watch", - blockAssetName: "exa-topic-watch", - label: "Watch the web", - cron: "0 8 * * 1", - why: "One digest at the start of the week, so a quiet week reads as quiet instead of as five empty runs.", - }, - ], - agents: [ - { - handle: "crm", - displayName: "CRM task agent", - blockAssetName: "attio-task-agent", - role: "Point it at a CRM task and it works the task — reading first, drafting second, and asking before it writes anything back.", - }, - { - handle: "collateral", - displayName: "Pain-point collateral", - blockAssetName: "pain-point-collateral", - role: "Give it a call transcript and it drafts a piece aimed at the pain point the customer actually named.", - }, - ], - openInputs: [ - { - key: "topic", - label: "What should we watch?", - placeholder: "AI coding agents for go-to-market", - help: "One topic, as specific as you can make it. The weekly digest covers this and nothing else.", - required: true, - appliesToRoutine: "topic-watch", - }, - ], - // GTM is not offered by the picker yet, and both its instantiation - // paths say so out loud rather than half-creating a workbench: - // `instantiateWorkbenchTemplate` throws because its agents are lenses - // over deployed workflow definitions with no agent-directory create - // request, and the web `beginOnboarding` binding throws because - // neither Attio nor Exa has an in-room onboarding card. - onboardingSteps: [ - { - kind: "connect-plugin", - connectorId: "attio", - title: "Connect Attio", - why: "The CRM agent reads and works your tasks in Attio — without it there is nothing to work.", - }, - { - kind: "connect-plugin", - connectorId: "exa", - title: "Connect Exa", - why: "The weekly web watch reads the open web through Exa.", - }, - { - kind: "connect-plugin", - connectorId: "granola", - title: "Connect Granola", - why: "Connect it and every new call gets written up on its own; skip it and the rest of the workbench still works.", - }, - ], -}; +export { GTM_TEMPLATE } from "./gtm"; +export { CODE_REVIEW_TEMPLATE } from "./code-review"; +export { DUE_DILIGENCE_TEMPLATE } from "./due-diligence"; +export { + instantiateWorkbenchTemplate, + type ParticipantAgentRequest, + type WorkbenchTemplateInstantiationPorts, + type WorkbenchTemplateInstantiationResult, +} from "./instantiate"; +export { + jimmyAgentRequest, + scoutAgentRequest, +} from "./participant-agent-requests"; +export { + TemplateReposSettingsPatch, + TemplateSettingsPatch, + templateReposSettingsPatch, + templateSettingsPatch, +} from "./settings"; +export { + WorkflowTriggerField, + WORKFLOW_CATALOG, + isAutomatableWorkflowName, + isConversationalWorkflowName, + deliveryWorkbenchRequiredForWorkflowName, + workflowCatalogEntry, + workflowDisplayName, + validateTriggerFieldsAtCreate, + type WorkflowCatalogEntry, + type TriggerFieldsValidation, +} from "@corbits/workflows/catalog"; -/** - * The code-review definition: three reviewer lenses over every pull - * request. Its blocks install the one `code-review` workflow; the - * reviewer roster itself is `@corbits/code-review`'s own - * `CODE_REVIEW_REVIEWERS` — mirrored into `agents` here rather than - * duplicated, so a reviewer's handle, name, and one-line role can never - * drift between the package that runs the review and the definition - * that describes it. - */ -export const CODE_REVIEW_TEMPLATE: WorkbenchDefinition = { - id: "code-review", - title: "Code review", - promise: - "Three reviewers read every pull request and post what they'd change.", - blocks: [{ assetName: "code-review", version: "0.0.1" }], - // GitHub is the one thing this template cannot work without: no - // repository, no diff to read and nowhere to post the review. - plugins: { required: ["github"], optional: [] }, - tools: ["@corbits/github-tools"], - routines: [], - webhookTriggers: [ - { - key: "pull-request-opened", - blockAssetName: "code-review", - label: "Review new pull requests", - why: "A review is worth most posted while the pull request is still open for comment, so this fires the moment GitHub says one exists rather than waiting on a clock.", - triggerFieldKey: "pullRequestUrl", - }, - ], - agents: [ - ...CODE_REVIEW_REVIEWERS.map((reviewer) => ({ - handle: reviewer.handle, - displayName: reviewer.displayName, - blockAssetName: "code-review", - role: reviewer.description, - })), - ], - openInputs: [ - { - key: "repos", - label: "Which repositories?", - placeholder: "corbitsdev/workbench", - help: "The GitHub repositories to watch. Every new pull request there gets reviewed.", - required: true, - appliesToWebhookTrigger: "pull-request-opened", - }, - ], - onboardingSteps: [ - { - kind: "connect-plugin", - connectorId: "github", - title: "Connect GitHub", - why: "Create a token scoped to the repositories you want reviewed — that is what the reviewers will be able to read.", - }, - { - kind: "pick-github-repos", - title: "Choose what gets reviewed", - why: "Of the repositories your token reaches, these are the ones a new pull request starts a review in.", - }, - { - kind: "start-webhook-trigger", - webhookTriggerKey: "pull-request-opened", - title: "Start reviewing", - why: "From now on, every new pull request in those repositories gets a review.", - }, - ], -}; - -/** - * The due-diligence template (CL-6499): Scout for the web/firm-memory - * research and Myra to talk through what it found. Scout is a - * standalone chat agent, not a lens over a block workflow — it has no - * cron, no webhook, nothing to schedule — so it carries no - * `blockAssetName` and this template's `blocks` list stays empty. - * Exa (Scout's web-research tool) resolves through the keyless MCP - * preset, so nothing here blocks the create on a connection. - */ -export const DUE_DILIGENCE_TEMPLATE: WorkbenchDefinition = { - id: "due-diligence", - title: "Due Diligence", - promise: - "Scout checks a company, deal, or vendor against the web and what your team already knows, and saves what it finds so you can pick it up later.", - blocks: [], - plugins: { required: [], optional: ["exa"] }, - tools: SCOUT_TOOL_PACKAGE_PINS.map((pin) => pin.name), - routines: [], - webhookTriggers: [], - agents: [ - { - handle: "myra", - displayName: "Myra", - role: "Talks through what Scout found and helps you decide what to do with it.", - }, - { - handle: SCOUT_AGENT_HANDLE, - displayName: SCOUT_AGENT_DISPLAY_NAME, - role: SCOUT_AGENT_DESCRIPTION, - }, - ], - openInputs: [], - onboardingSteps: [], -}; +import { GTM_TEMPLATE } from "./gtm"; +import { CODE_REVIEW_TEMPLATE } from "./code-review"; +import { DUE_DILIGENCE_TEMPLATE } from "./due-diligence"; export const WORKBENCH_TEMPLATES: readonly WorkbenchDefinition[] = [ GTM_TEMPLATE, diff --git a/packages/workflow-catalog/test/instantiate.test.ts b/templates/instantiate.test.ts similarity index 99% rename from packages/workflow-catalog/test/instantiate.test.ts rename to templates/instantiate.test.ts index cc11ccac5..45f084f6f 100644 --- a/packages/workflow-catalog/test/instantiate.test.ts +++ b/templates/instantiate.test.ts @@ -6,11 +6,11 @@ import { DUE_DILIGENCE_TEMPLATE, GTM_TEMPLATE, type WorkbenchOnboardingStep, -} from "../src/index"; +} from "./index"; import { instantiateWorkbenchTemplate, type WorkbenchTemplateInstantiationPorts, -} from "../src/instantiate"; +} from "./instantiate"; function fakePorts( existingHandles: readonly string[] = [], diff --git a/packages/workflow-catalog/src/instantiate.ts b/templates/instantiate.ts similarity index 99% rename from packages/workflow-catalog/src/instantiate.ts rename to templates/instantiate.ts index 7370a3bcd..a46b748a7 100644 --- a/packages/workflow-catalog/src/instantiate.ts +++ b/templates/instantiate.ts @@ -35,7 +35,7 @@ import type { WorkbenchDefinition, WorkbenchOnboardingStep, WorkbenchTemplateBlock, -} from "./templates"; +} from "./index"; /** The agent-directory create-request shape every agent resolves * to: `CodeReviewAgentRequest`'s own fields, plus the tool-package pins diff --git a/templates/package.json b/templates/package.json new file mode 100644 index 000000000..3f26e9076 --- /dev/null +++ b/templates/package.json @@ -0,0 +1,29 @@ +{ + "name": "@workbench/templates", + "private": true, + "description": "Workbench templates: the shipped WorkbenchDefinition data (one directory per template, peer of workflows/) plus the pure logic that instantiates one against a bench over injected ports", + "version": "0.0.1", + "license": "LGPL-2.1-or-later", + "type": "module", + "exports": { + ".": "./index.ts", + "./instantiate": "./instantiate.ts", + "./settings": "./settings.ts" + }, + "scripts": { + "typecheck": "tsc --noEmit", + "test": "bun test" + }, + "dependencies": { + "@corbits/code-review": "workspace:*", + "@corbits/jimmy-agent": "workspace:*", + "@corbits/scout-agent": "workspace:*", + "@corbits/workflows": "workspace:*", + "arktype": "catalog:" + }, + "devDependencies": { + "@types/bun": "catalog:", + "@workbench/connections": "workspace:*", + "typescript": "catalog:" + } +} diff --git a/packages/workflow-catalog/src/participant-agent-requests.ts b/templates/participant-agent-requests.ts similarity index 100% rename from packages/workflow-catalog/src/participant-agent-requests.ts rename to templates/participant-agent-requests.ts diff --git a/packages/workflow-catalog/test/templates.test.ts b/templates/schema.test.ts similarity index 99% rename from packages/workflow-catalog/test/templates.test.ts rename to templates/schema.test.ts index 21a941a32..60cd2683d 100644 --- a/packages/workflow-catalog/test/templates.test.ts +++ b/templates/schema.test.ts @@ -14,7 +14,7 @@ import { parseWorkbenchDefinition, serializeWorkbenchDefinition, workflowCatalogEntry, -} from "../src/index"; +} from "./index"; test("every template's blocks are real catalog workflows", () => { const known = new Set(WORKFLOW_CATALOG.map((entry) => entry.assetName)); diff --git a/packages/workflow-catalog/test/settings.test.ts b/templates/settings.test.ts similarity index 87% rename from packages/workflow-catalog/test/settings.test.ts rename to templates/settings.test.ts index b9ea0b0cd..a5c769423 100644 --- a/packages/workflow-catalog/test/settings.test.ts +++ b/templates/settings.test.ts @@ -1,6 +1,6 @@ import { expect, test } from "bun:test"; -import { templateSettingsPatch } from "../src/settings"; +import { templateSettingsPatch } from "./settings"; test("builds a valid template/* settings patch", () => { expect(templateSettingsPatch("code-review", ["github"])).toEqual({ diff --git a/packages/workflow-catalog/src/settings.ts b/templates/settings.ts similarity index 100% rename from packages/workflow-catalog/src/settings.ts rename to templates/settings.ts diff --git a/packages/workflow-catalog/tsconfig.json b/templates/tsconfig.json similarity index 50% rename from packages/workflow-catalog/tsconfig.json rename to templates/tsconfig.json index d7611c122..8b1da8f02 100644 --- a/packages/workflow-catalog/tsconfig.json +++ b/templates/tsconfig.json @@ -1,6 +1,6 @@ { - "extends": "../../tsconfig.base.json", - "include": ["src", "test"], + "extends": "../tsconfig.base.json", + "include": ["**/*.ts"], "compilerOptions": { "types": ["bun"], "noEmit": true diff --git a/workflows/README.md b/workflows/README.md index 1f4d5302a..9da6f5dbf 100644 --- a/workflows/README.md +++ b/workflows/README.md @@ -2,10 +2,13 @@ Each subdirectory is a deployable workflow package: an Interchange `defineWorkflow` plus a `corbits.workflow` block in its `package.json` -that mirrors into `packages/workflow-catalog`'s `WORKFLOW_CATALOG` — the -deploy-layer metadata the seed step and the web Routines picker both -read (see that package's own doc comment for why the two must stay in -lockstep). +(`assetName`, `displayName`, `automatable`). `@workbench/templates`'s +`WORKFLOW_CATALOG` (`templates/catalog.ts`) reads that block straight off +each `package.json` at build time — via a static JSON import, not a +runtime file read, so it stays importable from the browser bundle — and +layers on the fields with no npm-visible home of their own (`whatItDoes`, +`requiredConnections`, trigger fields, …). There is nothing to keep in +lockstep: the `package.json` block IS the value the catalog reads. ## Status note diff --git a/workflows/diligence-brief/README.md b/workflows/diligence-brief/README.md index 028afa46d..41b1fea04 100644 --- a/workflows/diligence-brief/README.md +++ b/workflows/diligence-brief/README.md @@ -87,7 +87,7 @@ round-trip. `bun run typecheck` passes clean. ## Registration -Registered in `packages/workflow-catalog`'s `WORKFLOW_CATALOG` (asset +Registered in `@corbits/workflows`'s `WORKFLOW_CATALOG` (asset name `diligence-brief`) alongside this package's own `corbits.workflow` block, so it shows up wherever that catalog is read: the seed step and the web Routines picker. See [`workflows/README.md`](../README.md#status-note) diff --git a/workflows/last-30-days-research/README.md b/workflows/last-30-days-research/README.md index 1093aa918..239bb2622 100644 --- a/workflows/last-30-days-research/README.md +++ b/workflows/last-30-days-research/README.md @@ -174,7 +174,7 @@ gathering steps to reach real data. Every run is triggered by mail to the deployment's address (`triggerAddress` above); the `ground`/`gather` steps read two fields off -the intake signal payload, matching `packages/workflow-catalog`'s +the intake signal payload, matching `@corbits/workflows`'s `triggerFields` for this workflow exactly: - `topic` (required) — the free-text subject to research. diff --git a/workflows/last-30-days-research/src/index.ts b/workflows/last-30-days-research/src/index.ts index 226ee7c66..c965de2cf 100644 --- a/workflows/last-30-days-research/src/index.ts +++ b/workflows/last-30-days-research/src/index.ts @@ -61,7 +61,7 @@ // provider the OG used) and `github_activity` (`@corbits/github-tools`, // GitHub's public REST search) — the same scope this repo's prior ports // already carried and the same `topic`/`focus` intake shape the OG's own -// `INTAKE_FIELDS` and this repo's `workflow-catalog` entry already agree +// `INTAKE_FIELDS` and this repo's catalog entry already agree // on. The remaining five stay named as "not yet connected" rather than // silently dropped (see `LAST_30_DAYS_RESEARCH_PENDING_SOURCES`). // diff --git a/workflows/pain-point-collateral/src/finalize-tool.ts b/workflows/pain-point-collateral/src/finalize-tool.ts index 483dd7acf..1271aa823 100644 --- a/workflows/pain-point-collateral/src/finalize-tool.ts +++ b/workflows/pain-point-collateral/src/finalize-tool.ts @@ -3,7 +3,7 @@ // a shared tool package — this behavior (what "finalize" means for a // pain-point-collateral run) is specific to this workflow, not a // reusable integration, so it stays folded into the definition per the -// workflow-catalog's "workflow-specific logic lives in the definition" +// @corbits/workflows's "workflow-specific logic lives in the definition" // convention (only genuinely reusable integrations, like // `@corbits/granola-tools`, live outside it). // diff --git a/workflows/process-granola-call/src/finalize-tool.ts b/workflows/process-granola-call/src/finalize-tool.ts index 326c4bbe8..9e8449057 100644 --- a/workflows/process-granola-call/src/finalize-tool.ts +++ b/workflows/process-granola-call/src/finalize-tool.ts @@ -5,7 +5,7 @@ // rather than a shared tool package — this behavior (what "finalize" // means for a process-granola-call run) is specific to this workflow, not // a reusable integration, so it stays folded into the definition per the -// workflow-catalog's "workflow-specific logic lives in the definition" +// @corbits/workflows's "workflow-specific logic lives in the definition" // convention. // // Approval mechanics: `defineTool`'s `definitions` array marks this diff --git a/workflows/process-granola-call/src/index.ts b/workflows/process-granola-call/src/index.ts index bf3203f19..b50c95809 100644 --- a/workflows/process-granola-call/src/index.ts +++ b/workflows/process-granola-call/src/index.ts @@ -7,7 +7,7 @@ // one run per unprocessed call — never scheduled directly, and never // exposed as an independent Routine (see this package's `automatable: // false` in `package.json`'s `corbits.workflow` block, mirrored into -// `@corbits/workflow-catalog`). +// `@corbits/workflows`). // // This package is installable data. It imports only published platform // packages, and nothing imports it statically: a host publishes the