@mastra/factory 0.10.0-alpha.2 → 0.10.0-alpha.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (116) hide show
  1. package/CHANGELOG.md +112 -0
  2. package/dist/factory.d.ts +8 -0
  3. package/dist/factory.d.ts.map +1 -1
  4. package/dist/factory.js +24 -8
  5. package/dist/factory.js.map +1 -1
  6. package/dist/index.d.ts +2 -0
  7. package/dist/index.d.ts.map +1 -1
  8. package/dist/index.js +2 -1
  9. package/dist/integrations/github/integration.d.ts.map +1 -1
  10. package/dist/integrations/github/integration.js +1 -0
  11. package/dist/integrations/github/integration.js.map +1 -1
  12. package/dist/integrations/github/provenance.d.ts +7 -2
  13. package/dist/integrations/github/provenance.d.ts.map +1 -1
  14. package/dist/integrations/github/provenance.js +16 -2
  15. package/dist/integrations/github/provenance.js.map +1 -1
  16. package/dist/integrations/github/routes.d.ts +3 -0
  17. package/dist/integrations/github/routes.d.ts.map +1 -1
  18. package/dist/integrations/github/routes.js +75 -6
  19. package/dist/integrations/github/routes.js.map +1 -1
  20. package/dist/integrations/github/rules.d.ts.map +1 -1
  21. package/dist/integrations/github/rules.js +193 -127
  22. package/dist/integrations/github/rules.js.map +1 -1
  23. package/dist/integrations/platform/github/integration.d.ts.map +1 -1
  24. package/dist/integrations/platform/github/integration.js +1 -0
  25. package/dist/integrations/platform/github/integration.js.map +1 -1
  26. package/dist/routes/attention.d.ts +17 -0
  27. package/dist/routes/attention.d.ts.map +1 -0
  28. package/dist/routes/attention.js +305 -0
  29. package/dist/routes/attention.js.map +1 -0
  30. package/dist/routes/surface.d.ts +2 -3
  31. package/dist/routes/surface.d.ts.map +1 -1
  32. package/dist/routes/surface.js +61 -43
  33. package/dist/routes/surface.js.map +1 -1
  34. package/dist/routes/work-items.d.ts.map +1 -1
  35. package/dist/routes/work-items.js +35 -14
  36. package/dist/routes/work-items.js.map +1 -1
  37. package/dist/rules/defaults.js +5 -5
  38. package/dist/rules/defaults.js.map +1 -1
  39. package/dist/rules/dispatch-errors.d.ts +13 -0
  40. package/dist/rules/dispatch-errors.d.ts.map +1 -0
  41. package/dist/rules/dispatch-errors.js +77 -0
  42. package/dist/rules/dispatch-errors.js.map +1 -0
  43. package/dist/rules/dispatcher.d.ts +9 -0
  44. package/dist/rules/dispatcher.d.ts.map +1 -1
  45. package/dist/rules/dispatcher.js +118 -45
  46. package/dist/rules/dispatcher.js.map +1 -1
  47. package/dist/rules/processor.d.ts.map +1 -1
  48. package/dist/rules/processor.js +30 -14
  49. package/dist/rules/processor.js.map +1 -1
  50. package/dist/rules/terminal-cleanup.d.ts +1 -1
  51. package/dist/rules/terminal-cleanup.d.ts.map +1 -1
  52. package/dist/rules/terminal-cleanup.js +2 -2
  53. package/dist/rules/terminal-cleanup.js.map +1 -1
  54. package/dist/rules/transition-service.d.ts +2 -1
  55. package/dist/rules/transition-service.d.ts.map +1 -1
  56. package/dist/rules/transition-service.js +1 -1
  57. package/dist/rules/transition-service.js.map +1 -1
  58. package/dist/rules/types.d.ts +2 -0
  59. package/dist/rules/types.d.ts.map +1 -1
  60. package/dist/rules/types.js +9 -1
  61. package/dist/rules/types.js.map +1 -1
  62. package/dist/secret-encryption.d.ts +25 -0
  63. package/dist/secret-encryption.d.ts.map +1 -0
  64. package/dist/secret-encryption.js +96 -0
  65. package/dist/secret-encryption.js.map +1 -0
  66. package/dist/session/factory-session.d.ts +13 -3
  67. package/dist/session/factory-session.d.ts.map +1 -1
  68. package/dist/session/factory-session.js +15 -6
  69. package/dist/session/factory-session.js.map +1 -1
  70. package/dist/session/first-exec-capture.d.ts +16 -10
  71. package/dist/session/first-exec-capture.d.ts.map +1 -1
  72. package/dist/session/first-exec-capture.js +74 -14
  73. package/dist/session/first-exec-capture.js.map +1 -1
  74. package/dist/session/first-message-capture.d.ts +14 -10
  75. package/dist/session/first-message-capture.d.ts.map +1 -1
  76. package/dist/session/first-message-capture.js +17 -11
  77. package/dist/session/first-message-capture.js.map +1 -1
  78. package/dist/session/session-title.d.ts +7 -0
  79. package/dist/session/session-title.d.ts.map +1 -0
  80. package/dist/session/session-title.js +14 -0
  81. package/dist/session/session-title.js.map +1 -0
  82. package/dist/session/thread-title-mirror.d.ts +35 -0
  83. package/dist/session/thread-title-mirror.d.ts.map +1 -0
  84. package/dist/session/thread-title-mirror.js +51 -0
  85. package/dist/session/thread-title-mirror.js.map +1 -0
  86. package/dist/storage/domains/credentials/base.d.ts +3 -1
  87. package/dist/storage/domains/credentials/base.d.ts.map +1 -1
  88. package/dist/storage/domains/credentials/base.js +33 -15
  89. package/dist/storage/domains/credentials/base.js.map +1 -1
  90. package/dist/storage/domains/custom-providers/base.d.ts +3 -1
  91. package/dist/storage/domains/custom-providers/base.d.ts.map +1 -1
  92. package/dist/storage/domains/custom-providers/base.js +45 -25
  93. package/dist/storage/domains/custom-providers/base.js.map +1 -1
  94. package/dist/storage/domains/integrations/base.d.ts +3 -1
  95. package/dist/storage/domains/integrations/base.d.ts.map +1 -1
  96. package/dist/storage/domains/integrations/base.js +28 -12
  97. package/dist/storage/domains/integrations/base.js.map +1 -1
  98. package/dist/storage/domains/source-control/base.d.ts +8 -0
  99. package/dist/storage/domains/source-control/base.d.ts.map +1 -1
  100. package/dist/storage/domains/source-control/base.js +14 -2
  101. package/dist/storage/domains/source-control/base.js.map +1 -1
  102. package/dist/storage/domains/source-control/inmemory.d.ts +4 -0
  103. package/dist/storage/domains/source-control/inmemory.d.ts.map +1 -1
  104. package/dist/storage/domains/source-control/inmemory.js +7 -0
  105. package/dist/storage/domains/source-control/inmemory.js.map +1 -1
  106. package/dist/storage/domains/work-items/base.d.ts +115 -12
  107. package/dist/storage/domains/work-items/base.d.ts.map +1 -1
  108. package/dist/storage/domains/work-items/base.js +497 -43
  109. package/dist/storage/domains/work-items/base.js.map +1 -1
  110. package/dist/work-item-branch.d.ts +23 -0
  111. package/dist/work-item-branch.d.ts.map +1 -0
  112. package/dist/work-item-branch.js +39 -0
  113. package/dist/work-item-branch.js.map +1 -0
  114. package/factory-skills/factory-rereview/SKILL.md +2 -0
  115. package/factory-skills/factory-review/SKILL.md +2 -0
  116. package/package.json +7 -7
@@ -1 +1 @@
1
- {"version":3,"file":"surface.js","names":[],"sources":["../../src/routes/surface.ts"],"sourcesContent":["import type { AuthStorage } from '@mastra/code-sdk/auth/storage';\nimport type { MastraCodeState } from '@mastra/code-sdk/schema';\nimport type { AgentController } from '@mastra/core/agent-controller';\nimport type { ApiRoute } from '@mastra/core/server';\nimport { registerApiRoute } from '@mastra/core/server';\nimport type { FactoryStorage } from '@mastra/core/storage';\n\nimport type { FactoryIntegration, IntegrationContext } from '../integrations/base.js';\nimport { getGithubFeatureDiagnostics } from '../integrations/github/config.js';\nimport type { GithubIntegration } from '../integrations/github/integration.js';\nimport type { FactoryBindingPreparationInput } from '../rules/dispatcher.js';\nimport { FactoryStartCoordinator } from '../rules/start-coordinator.js';\nimport { FactoryTransitionService } from '../rules/transition-service.js';\nimport type { FactoryRules } from '../rules/types.js';\nimport { isFactoryRuleStage } from '../rules/types.js';\nimport type { BaseCheckpointTriggers } from '../sandbox/base-checkpoint-triggers.js';\nimport type { SandboxFleet } from '../sandbox/fleet.js';\nimport { ensureFactorySourceSession, resolveFactoryDefaultModelId } from '../session/factory-session.js';\nimport { LiveSessions } from '../session/live-sessions.js';\nimport type { StateSigner } from '../state-signing.js';\nimport type { AuditEmitter } from '../storage/domains/audit/domain.js';\nimport type { ChannelIdentityStorage } from '../storage/domains/channel-identity/base.js';\nimport type { ModelCredentialsStorage } from '../storage/domains/credentials/base.js';\nimport type { CustomProvidersStorage } from '../storage/domains/custom-providers/base.js';\nimport type { FilesystemStorage } from '../storage/domains/filesystem/base.js';\nimport type { IntakeStorage } from '../storage/domains/intake/base.js';\nimport type { IntegrationStorage } from '../storage/domains/integrations/base.js';\nimport type { MemorySettingsStorage } from '../storage/domains/memory-settings/base.js';\nimport type { ModelPacksStorage } from '../storage/domains/model-packs/base.js';\nimport type { FactoryProjectsStorage } from '../storage/domains/projects/base.js';\nimport type { QueueHealthStorage } from '../storage/domains/queue-health/base.js';\nimport type { SourceControlStorage } from '../storage/domains/source-control/base.js';\nimport type { WorkItemsStorage } from '../storage/domains/work-items/base.js';\nimport { ConfigRoutes } from './config.js';\nimport { invalidateCustomProvidersSnapshots } from './custom-provider-source.js';\nimport { buildFsRoutes } from './fs.js';\nimport { IntakeRoutes } from './intake.js';\nimport { KnowledgeRoutes } from './knowledge.js';\nimport { OAuthRoutes } from './oauth.js';\nimport type { RouteAuth } from './route.js';\nimport { SkillRoutes } from './skills.js';\nimport { invalidateTenantCredentialSnapshots } from './tenant-credentials.js';\nimport { WorkItemRoutes } from './work-items.js';\n\nexport interface IntegrationRegistration {\n integration: FactoryIntegration;\n ready: boolean;\n ensureReady: () => Promise<void>;\n}\n\nexport interface FactoryApiRoutesDeps {\n controllerId: string;\n controller: AgentController<MastraCodeState>;\n /** Request-auth seam threaded from the host (no service locator). */\n auth: RouteAuth;\n authStorage: AuthStorage;\n audit: AuditEmitter;\n fsRoot?: string;\n publicOrigin: string;\n stateSigner?: StateSigner;\n /** Sandbox fleet constructed by the factory (disabled when no machine). */\n fleet: SandboxFleet;\n /** Base-checkpoint trigger surface, when the factory constructed one. */\n baseCheckpoints?: BaseCheckpointTriggers;\n /** Root factory storage backend (distributed locks, app-db diagnostics). */\n factoryStorage?: FactoryStorage;\n integrationStorage: IntegrationStorage;\n sourceControlStorage: SourceControlStorage;\n /** App-table domain handles, registered and owned by `MastraFactory.prepare()`. */\n domains: {\n intake: IntakeStorage;\n modelCredentials: ModelCredentialsStorage;\n memorySettings: MemorySettingsStorage;\n customProviders: CustomProvidersStorage;\n filesystem: FilesystemStorage;\n modelPacks: ModelPacksStorage;\n projects: FactoryProjectsStorage;\n queueHealth: QueueHealthStorage;\n workItems: WorkItemsStorage;\n channelIdentity: ChannelIdentityStorage;\n };\n integrations?: IntegrationRegistration[];\n intakeReady: boolean;\n factoryReady: boolean;\n knowledgeEnabled: boolean;\n /** Resolved Factory rule set, threaded from the host (no service locator). */\n rules: FactoryRules;\n factoryTransitionService?: FactoryTransitionService;\n sessionRetirement?: import('../sandbox/session-retirement.js').SessionRetirementCoordinator;\n onFactoryRuntime?: (runtime: {\n transitionService: FactoryTransitionService;\n prepareBinding?: (input: FactoryBindingPreparationInput) => Promise<void>;\n }) => void;\n}\n\nfunction guardIntegrationRoutes({\n integration,\n ready,\n ensureReady,\n routes,\n}: IntegrationRegistration & { routes: ApiRoute[] }): ApiRoute[] {\n if (ready) return routes;\n return routes.map(route => {\n if ('handler' in route) {\n const handler = route.handler;\n return {\n ...route,\n handler: async (context: Parameters<typeof handler>[0]) => {\n try {\n await ensureReady();\n } catch {\n return context.json(\n { error: 'integration_unavailable', message: `${integration.id} integration is unavailable.` },\n 503,\n );\n }\n return handler(context, async () => {});\n },\n };\n }\n\n const createHandler = route.createHandler;\n return {\n ...route,\n createHandler: async (args: Parameters<typeof createHandler>[0]) => {\n const handler = await createHandler(args);\n return async (context: Parameters<typeof handler>[0]) => {\n try {\n await ensureReady();\n } catch {\n return context.json(\n { error: 'integration_unavailable', message: `${integration.id} integration is unavailable.` },\n 503,\n );\n }\n return handler(context);\n };\n },\n };\n });\n}\n\nexport function factoryRuleBranch(item: FactoryBindingPreparationInput['item']): string {\n const metadata = item.metadata ?? {};\n const issueNumber = metadata.githubIssueNumber ?? metadata.number;\n if (\n item.externalSource?.integrationId === 'github' &&\n item.externalSource.type === 'issue' &&\n typeof issueNumber === 'number'\n ) {\n return `factory/issue-${issueNumber}`;\n }\n const pullRequestNumber = metadata.githubPullRequestNumber ?? metadata.number;\n if (\n item.externalSource?.integrationId === 'github' &&\n item.externalSource.type === 'pull-request' &&\n typeof pullRequestNumber === 'number'\n ) {\n return `factory/pr-${pullRequestNumber}`;\n }\n if (item.externalSource?.integrationId === 'linear' && typeof metadata.identifier === 'string') {\n return `factory/linear-${metadata.identifier.toLowerCase()}`;\n }\n throw new Error('Factory skill invocation requires a supported issue or pull request identifier.');\n}\n\n/**\n * Start a factory run for a rule binding: ensure the source-control session the\n * coordinator requires, then hand it to `prepare` along with the factory's\n * default model. Exported for tests — this is the autonomous entry point with no\n * browser and no interactive user, so nothing else would catch a regression in\n * what it forwards.\n */\nexport async function prepareFactoryRuleBinding(\n github: GithubIntegration,\n coordinator: FactoryStartCoordinator,\n projects: FactoryProjectsStorage,\n input: FactoryBindingPreparationInput,\n): Promise<void> {\n const branch = factoryRuleBranch(input.item);\n const repositorySlug =\n typeof input.item.metadata?.repository === 'string' ? input.item.metadata.repository : undefined;\n const preparedSession = await ensureFactorySourceSession({\n sourceControl: github.sourceControlStorage,\n orgId: input.record.orgId,\n factoryProjectId: input.record.factoryProjectId,\n repositorySlug,\n branch,\n });\n const destinationStage = input.item.stages.length === 1 ? input.item.stages[0] : undefined;\n if (!isFactoryRuleStage(destinationStage))\n throw new Error('Factory skill invocation requires one exclusive board stage.');\n\n await coordinator.prepare({\n orgId: input.record.orgId,\n userId: preparedSession.userId,\n factoryProjectId: input.record.factoryProjectId,\n sessionId: preparedSession.sessionId,\n defaultModelId: await resolveFactoryDefaultModelId(projects, input.record.factoryProjectId),\n threadTitle: `${input.role === 'review' ? 'PR' : 'Issue'}: ${input.item.title}`,\n kickoffKey: input.record.id,\n destinationStage,\n workItem: {\n id: input.item.id,\n role: input.role,\n input: {\n externalSource: input.item.externalSource,\n parentWorkItemId: input.item.parentWorkItemId,\n title: input.item.title,\n stages: ['intake'],\n sessions: input.item.sessions,\n metadata: input.item.metadata,\n },\n },\n });\n}\n\n/**\n * Build the {@link IntegrationContext} handed to an integration when the\n * factory collects its capabilities (routes, workers). One shape everywhere:\n * `assembleFactoryApiRoutes` uses it per registration, and `MastraFactory` uses it\n * when collecting integration workers at finalize.\n */\nexport function buildIntegrationContext(\n deps: Pick<\n FactoryApiRoutesDeps,\n 'controller' | 'publicOrigin' | 'auth' | 'fleet' | 'factoryStorage' | 'integrationStorage' | 'sourceControlStorage'\n > & {\n stateSigner: StateSigner;\n emitAudit?: AuditEmitter['emit'];\n rules: FactoryRules;\n factoryReady: boolean;\n domains: Pick<\n FactoryApiRoutesDeps['domains'],\n 'projects' | 'intake' | 'workItems' | 'channelIdentity' | 'memorySettings'\n >;\n /**\n * Stable id of the registered source-control-owning integration (today:\n * `'github'` when registered). Every call site must derive and pass it so\n * `routes()`, `channels()`, and `workers()` all see the same context shape.\n */\n sourceControlOwnerId?: string;\n /** Base-checkpoint trigger surface, when the factory constructed one. */\n baseCheckpoints?: BaseCheckpointTriggers;\n },\n integrationId: string,\n): IntegrationContext {\n return {\n auth: deps.auth,\n fleet: deps.fleet,\n ...(deps.baseCheckpoints ? { baseCheckpoints: deps.baseCheckpoints } : {}),\n factoryStorage: deps.factoryStorage,\n baseUrl: deps.publicOrigin,\n controller: deps.controller,\n stateSigner: deps.stateSigner,\n storage: {\n generic: deps.integrationStorage.forIntegration(integrationId),\n sourceControl: deps.sourceControlStorage.forIntegration(integrationId),\n ...(deps.sourceControlOwnerId\n ? { sourceControlOwner: deps.sourceControlStorage.forIntegration(deps.sourceControlOwnerId) }\n : {}),\n projects: deps.domains.projects,\n intake: deps.domains.intake,\n channelIdentity: deps.domains.channelIdentity,\n memorySettings: deps.domains.memorySettings,\n },\n ...(deps.factoryReady ? { rules: { config: deps.rules, workItems: deps.domains.workItems } } : {}),\n ...(deps.emitAudit ? { hooks: { emitAudit: deps.emitAudit } } : {}),\n };\n}\n\n/**\n * Disabled-status stub for the well-known integration ids. The SPA polls\n * `/web/github/status` and `/web/linear/status` unconditionally, so when an\n * integration is absent (or not ready) the status contract must still hold.\n * Unknown custom ids get no stub — the SPA doesn't poll them.\n */\nfunction disabledIntegrationStatusRoutes(deps: FactoryApiRoutesDeps, id: string, configured = false): ApiRoute[] {\n if (id === 'github') {\n return [\n registerApiRoute('/web/github/status', {\n method: 'GET',\n requiresAuth: false,\n handler: c =>\n c.json({\n enabled: false,\n connected: false,\n installations: [],\n reason: 'missing_config',\n diagnostics: getGithubFeatureDiagnostics({\n github: undefined,\n auth: deps.auth,\n appDbConfigured: deps.factoryStorage !== undefined,\n stateSigner: deps.stateSigner,\n fleet: deps.fleet,\n }),\n }),\n }),\n ];\n }\n if (id === 'linear') {\n return [\n registerApiRoute('/web/linear/status', {\n method: 'GET',\n requiresAuth: false,\n handler: c =>\n c.json({\n enabled: false,\n connected: false,\n workspace: null,\n reason: 'missing_config',\n diagnostics: {\n linearAppConfigured: configured,\n factoryAuthEnabled: deps.auth.enabled(),\n appDbConfigured: true,\n },\n }),\n }),\n ];\n }\n return [];\n}\n\n/**\n * Stub for `GET /web/channel-accounts` when NO Slack integration is\n * registered. The SPA's Connections section polls the path unconditionally;\n * without a stub the SPA fallback serves HTML, which the UI can only read as\n * \"old server / unknown\". The machine-readable reason lets it say the truth:\n * the integration isn't registered.\n *\n * Mounted only for ABSENT slack — a registered integration owns the path via\n * its connect routes (or, when the state signer is unstable, gets no routes\n * at all and the UI falls back to the generic copy). Static payload, leaks\n * nothing → no auth needed, same posture as the github/linear stubs.\n */\nfunction absentSlackChannelAccountsRoutes(): ApiRoute[] {\n return [\n registerApiRoute('/web/channel-accounts', {\n method: 'GET',\n requiresAuth: false,\n handler: c => c.json({ accounts: [], canConnect: false, reason: 'not_registered' }),\n }),\n ];\n}\n\n/**\n * Assemble the custom `/web/*` API routes as Mastra `server.apiRoutes`:\n * - fs browser routes (project picker), confined to `fsRoot`\n * - config routes (provider/API-key/model-pack/OM management)\n * - every registered integration's `routes()` surface (full set when ready,\n * disabled-status stub otherwise), plus stubs for absent known ids\n */\nexport function assembleFactoryApiRoutes(deps: FactoryApiRoutesDeps): ApiRoute[] {\n const emitAudit: AuditEmitter['emit'] = args => deps.audit.emit(args);\n const registrations = deps.integrations ?? [];\n const githubRegistration = registrations.find(({ integration }) => integration.id === 'github');\n const githubStorage = githubRegistration ? deps.sourceControlStorage.forIntegration('github') : undefined;\n const githubIntegration = githubRegistration?.integration as GithubIntegration | undefined;\n\n const integrationRoutes = registrations.flatMap(registration => {\n const { integration } = registration;\n if (!deps.stateSigner) return disabledIntegrationStatusRoutes(deps, integration.id, true);\n const context = buildIntegrationContext(\n {\n ...deps,\n stateSigner: deps.stateSigner,\n emitAudit,\n ...(githubRegistration ? { sourceControlOwnerId: 'github' } : {}),\n },\n integration.id,\n );\n return guardIntegrationRoutes({ ...registration, routes: integration.routes(context) });\n });\n // Absent known integrations still get their disabled-status stub.\n const absentStubs = ['github', 'linear']\n .filter(id => !registrations.some(({ integration }) => integration.id === id))\n .flatMap(id => disabledIntegrationStatusRoutes(deps, id));\n // Absent slack gets the channel-accounts not-registered stub (registered\n // slack owns the path via its own connect routes).\n const slackAbsentStubs = registrations.some(({ integration }) => integration.id === 'slack')\n ? []\n : absentSlackChannelAccountsRoutes();\n\n const transitionService = deps.factoryReady\n ? (deps.factoryTransitionService ??\n new FactoryTransitionService({ rules: deps.rules, storage: deps.domains.workItems }))\n : undefined;\n const startCoordinator = transitionService\n ? new FactoryStartCoordinator(\n deps.controller,\n deps.domains.workItems,\n transitionService,\n githubIntegration?.sourceControlStorage,\n deps.domains.memorySettings,\n )\n : undefined;\n if (transitionService && startCoordinator) {\n deps.onFactoryRuntime?.({\n transitionService,\n ...(githubIntegration\n ? {\n prepareBinding: (input: FactoryBindingPreparationInput) =>\n prepareFactoryRuleBinding(githubIntegration, startCoordinator, deps.domains.projects, input),\n }\n : {}),\n });\n }\n\n return [\n ...buildFsRoutes({\n root: deps.fsRoot,\n sessionFs: {\n auth: deps.auth,\n fleet: deps.fleet,\n sessions: deps.sourceControlStorage.forIntegration('github').sessions,\n filesystem: deps.domains.filesystem,\n },\n }),\n ...new ConfigRoutes({\n auth: deps.auth,\n controller: deps.controller,\n authStorage: deps.authStorage,\n modelCredentials: deps.domains.modelCredentials,\n modelPacks: deps.domains.modelPacks,\n sourceControlSessions: deps.sourceControlStorage.forIntegration('github').sessions,\n memorySettings: deps.domains.memorySettings,\n factoryProjects: deps.domains.projects,\n customProviders: deps.domains.customProviders,\n features: { knowledge: deps.knowledgeEnabled },\n onCredentialsChanged: invalidateTenantCredentialSnapshots,\n onCustomProvidersChanged: invalidateCustomProvidersSnapshots,\n }).routes(),\n ...new OAuthRoutes({\n auth: deps.auth,\n authStorage: deps.authStorage,\n modelCredentials: deps.domains.modelCredentials,\n onCredentialsChanged: invalidateTenantCredentialSnapshots,\n }).routes(),\n ...new SkillRoutes({\n auth: deps.auth,\n controllerId: deps.controllerId,\n controller: deps.controller,\n sourceControlStorage: githubStorage,\n ensureSourceControlReady: githubRegistration?.ensureReady,\n }).routes(),\n ...integrationRoutes,\n ...absentStubs,\n ...slackAbsentStubs,\n ...(deps.intakeReady\n ? new IntakeRoutes({\n auth: deps.auth,\n audit: deps.audit,\n intake: deps.domains.intake,\n projects: deps.domains.projects,\n integrations: (deps.integrations ?? []).flatMap(({ integration }) =>\n integration.intake ? [{ id: integration.id, intake: integration.intake }] : [],\n ),\n }).routes()\n : []),\n ...(deps.factoryReady && deps.knowledgeEnabled\n ? new KnowledgeRoutes({\n auth: deps.auth,\n projects: deps.domains.projects,\n knowledge: async () => deps.factoryStorage?.getMastraStorage().getStore('knowledge'),\n }).routes()\n : []),\n ...(deps.factoryReady\n ? new WorkItemRoutes({\n auth: deps.auth,\n audit: deps.audit,\n projects: deps.domains.projects,\n workItems: deps.domains.workItems,\n queueHealth: deps.domains.queueHealth,\n transitionService,\n startCoordinator,\n liveSessions: new LiveSessions(deps.controller),\n }).routes()\n : []),\n ];\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AA+FA,SAAS,uBAAuB,EAC9B,aACA,OACA,aACA,UAC+D;CAC/D,IAAI,OAAO,OAAO;CAClB,OAAO,OAAO,KAAI,UAAS;EACzB,IAAI,aAAa,OAAO;GACtB,MAAM,UAAU,MAAM;GACtB,OAAO;IACL,GAAG;IACH,SAAS,OAAO,YAA2C;KACzD,IAAI;MACF,MAAM,YAAY;KACpB,QAAQ;MACN,OAAO,QAAQ,KACb;OAAE,OAAO;OAA2B,SAAS,GAAG,YAAY,GAAG;MAA8B,GAC7F,GACF;KACF;KACA,OAAO,QAAQ,SAAS,YAAY,CAAC,CAAC;IACxC;GACF;EACF;EAEA,MAAM,gBAAgB,MAAM;EAC5B,OAAO;GACL,GAAG;GACH,eAAe,OAAO,SAA8C;IAClE,MAAM,UAAU,MAAM,cAAc,IAAI;IACxC,OAAO,OAAO,YAA2C;KACvD,IAAI;MACF,MAAM,YAAY;KACpB,QAAQ;MACN,OAAO,QAAQ,KACb;OAAE,OAAO;OAA2B,SAAS,GAAG,YAAY,GAAG;MAA8B,GAC7F,GACF;KACF;KACA,OAAO,QAAQ,OAAO;IACxB;GACF;EACF;CACF,CAAC;AACH;AAEA,SAAgB,kBAAkB,MAAsD;CACtF,MAAM,WAAW,KAAK,YAAY,CAAC;CACnC,MAAM,cAAc,SAAS,qBAAqB,SAAS;CAC3D,IACE,KAAK,gBAAgB,kBAAkB,YACvC,KAAK,eAAe,SAAS,WAC7B,OAAO,gBAAgB,UAEvB,OAAO,iBAAiB;CAE1B,MAAM,oBAAoB,SAAS,2BAA2B,SAAS;CACvE,IACE,KAAK,gBAAgB,kBAAkB,YACvC,KAAK,eAAe,SAAS,kBAC7B,OAAO,sBAAsB,UAE7B,OAAO,cAAc;CAEvB,IAAI,KAAK,gBAAgB,kBAAkB,YAAY,OAAO,SAAS,eAAe,UACpF,OAAO,kBAAkB,SAAS,WAAW,YAAY;CAE3D,MAAM,IAAI,MAAM,iFAAiF;AACnG;;;;;;;;AASA,eAAsB,0BACpB,QACA,aACA,UACA,OACe;CACf,MAAM,SAAS,kBAAkB,MAAM,IAAI;CAC3C,MAAM,iBACJ,OAAO,MAAM,KAAK,UAAU,eAAe,WAAW,MAAM,KAAK,SAAS,aAAa,KAAA;CACzF,MAAM,kBAAkB,MAAM,2BAA2B;EACvD,eAAe,OAAO;EACtB,OAAO,MAAM,OAAO;EACpB,kBAAkB,MAAM,OAAO;EAC/B;EACA;CACF,CAAC;CACD,MAAM,mBAAmB,MAAM,KAAK,OAAO,WAAW,IAAI,MAAM,KAAK,OAAO,KAAK,KAAA;CACjF,IAAI,CAAC,mBAAmB,gBAAgB,GACtC,MAAM,IAAI,MAAM,8DAA8D;CAEhF,MAAM,YAAY,QAAQ;EACxB,OAAO,MAAM,OAAO;EACpB,QAAQ,gBAAgB;EACxB,kBAAkB,MAAM,OAAO;EAC/B,WAAW,gBAAgB;EAC3B,gBAAgB,MAAM,6BAA6B,UAAU,MAAM,OAAO,gBAAgB;EAC1F,aAAa,GAAG,MAAM,SAAS,WAAW,OAAO,QAAQ,IAAI,MAAM,KAAK;EACxE,YAAY,MAAM,OAAO;EACzB;EACA,UAAU;GACR,IAAI,MAAM,KAAK;GACf,MAAM,MAAM;GACZ,OAAO;IACL,gBAAgB,MAAM,KAAK;IAC3B,kBAAkB,MAAM,KAAK;IAC7B,OAAO,MAAM,KAAK;IAClB,QAAQ,CAAC,QAAQ;IACjB,UAAU,MAAM,KAAK;IACrB,UAAU,MAAM,KAAK;GACvB;EACF;CACF,CAAC;AACH;;;;;;;AAQA,SAAgB,wBACd,MAqBA,eACoB;CACpB,OAAO;EACL,MAAM,KAAK;EACX,OAAO,KAAK;EACZ,GAAI,KAAK,kBAAkB,EAAE,iBAAiB,KAAK,gBAAgB,IAAI,CAAC;EACxE,gBAAgB,KAAK;EACrB,SAAS,KAAK;EACd,YAAY,KAAK;EACjB,aAAa,KAAK;EAClB,SAAS;GACP,SAAS,KAAK,mBAAmB,eAAe,aAAa;GAC7D,eAAe,KAAK,qBAAqB,eAAe,aAAa;GACrE,GAAI,KAAK,uBACL,EAAE,oBAAoB,KAAK,qBAAqB,eAAe,KAAK,oBAAoB,EAAE,IAC1F,CAAC;GACL,UAAU,KAAK,QAAQ;GACvB,QAAQ,KAAK,QAAQ;GACrB,iBAAiB,KAAK,QAAQ;GAC9B,gBAAgB,KAAK,QAAQ;EAC/B;EACA,GAAI,KAAK,eAAe,EAAE,OAAO;GAAE,QAAQ,KAAK;GAAO,WAAW,KAAK,QAAQ;EAAU,EAAE,IAAI,CAAC;EAChG,GAAI,KAAK,YAAY,EAAE,OAAO,EAAE,WAAW,KAAK,UAAU,EAAE,IAAI,CAAC;CACnE;AACF;;;;;;;AAQA,SAAS,gCAAgC,MAA4B,IAAY,aAAa,OAAmB;CAC/G,IAAI,OAAO,UACT,OAAO,CACL,iBAAiB,sBAAsB;EACrC,QAAQ;EACR,cAAc;EACd,UAAS,MACP,EAAE,KAAK;GACL,SAAS;GACT,WAAW;GACX,eAAe,CAAC;GAChB,QAAQ;GACR,aAAa,4BAA4B;IACvC,QAAQ,KAAA;IACR,MAAM,KAAK;IACX,iBAAiB,KAAK,mBAAmB,KAAA;IACzC,aAAa,KAAK;IAClB,OAAO,KAAK;GACd,CAAC;EACH,CAAC;CACL,CAAC,CACH;CAEF,IAAI,OAAO,UACT,OAAO,CACL,iBAAiB,sBAAsB;EACrC,QAAQ;EACR,cAAc;EACd,UAAS,MACP,EAAE,KAAK;GACL,SAAS;GACT,WAAW;GACX,WAAW;GACX,QAAQ;GACR,aAAa;IACX,qBAAqB;IACrB,oBAAoB,KAAK,KAAK,QAAQ;IACtC,iBAAiB;GACnB;EACF,CAAC;CACL,CAAC,CACH;CAEF,OAAO,CAAC;AACV;;;;;;;;;;;;;AAcA,SAAS,mCAA+C;CACtD,OAAO,CACL,iBAAiB,yBAAyB;EACxC,QAAQ;EACR,cAAc;EACd,UAAS,MAAK,EAAE,KAAK;GAAE,UAAU,CAAC;GAAG,YAAY;GAAO,QAAQ;EAAiB,CAAC;CACpF,CAAC,CACH;AACF;;;;;;;;AASA,SAAgB,yBAAyB,MAAwC;CAC/E,MAAM,aAAkC,SAAQ,KAAK,MAAM,KAAK,IAAI;CACpE,MAAM,gBAAgB,KAAK,gBAAgB,CAAC;CAC5C,MAAM,qBAAqB,cAAc,MAAM,EAAE,kBAAkB,YAAY,OAAO,QAAQ;CAC9F,MAAM,gBAAgB,qBAAqB,KAAK,qBAAqB,eAAe,QAAQ,IAAI,KAAA;CAChG,MAAM,oBAAoB,oBAAoB;CAE9C,MAAM,oBAAoB,cAAc,SAAQ,iBAAgB;EAC9D,MAAM,EAAE,gBAAgB;EACxB,IAAI,CAAC,KAAK,aAAa,OAAO,gCAAgC,MAAM,YAAY,IAAI,IAAI;EACxF,MAAM,UAAU,wBACd;GACE,GAAG;GACH,aAAa,KAAK;GAClB;GACA,GAAI,qBAAqB,EAAE,sBAAsB,SAAS,IAAI,CAAC;EACjE,GACA,YAAY,EACd;EACA,OAAO,uBAAuB;GAAE,GAAG;GAAc,QAAQ,YAAY,OAAO,OAAO;EAAE,CAAC;CACxF,CAAC;CAED,MAAM,cAAc,CAAC,UAAU,QAAQ,CAAC,CACrC,QAAO,OAAM,CAAC,cAAc,MAAM,EAAE,kBAAkB,YAAY,OAAO,EAAE,CAAC,CAAC,CAC7E,SAAQ,OAAM,gCAAgC,MAAM,EAAE,CAAC;CAG1D,MAAM,mBAAmB,cAAc,MAAM,EAAE,kBAAkB,YAAY,OAAO,OAAO,IACvF,CAAC,IACD,iCAAiC;CAErC,MAAM,oBAAoB,KAAK,eAC1B,KAAK,4BACN,IAAI,yBAAyB;EAAE,OAAO,KAAK;EAAO,SAAS,KAAK,QAAQ;CAAU,CAAC,IACnF,KAAA;CACJ,MAAM,mBAAmB,oBACrB,IAAI,wBACF,KAAK,YACL,KAAK,QAAQ,WACb,mBACA,mBAAmB,sBACnB,KAAK,QAAQ,cACf,IACA,KAAA;CACJ,IAAI,qBAAqB,kBACvB,KAAK,mBAAmB;EACtB;EACA,GAAI,oBACA,EACE,iBAAiB,UACf,0BAA0B,mBAAmB,kBAAkB,KAAK,QAAQ,UAAU,KAAK,EAC/F,IACA,CAAC;CACP,CAAC;CAGH,OAAO;EACL,GAAG,cAAc;GACf,MAAM,KAAK;GACX,WAAW;IACT,MAAM,KAAK;IACX,OAAO,KAAK;IACZ,UAAU,KAAK,qBAAqB,eAAe,QAAQ,CAAC,CAAC;IAC7D,YAAY,KAAK,QAAQ;GAC3B;EACF,CAAC;EACD,GAAG,IAAI,aAAa;GAClB,MAAM,KAAK;GACX,YAAY,KAAK;GACjB,aAAa,KAAK;GAClB,kBAAkB,KAAK,QAAQ;GAC/B,YAAY,KAAK,QAAQ;GACzB,uBAAuB,KAAK,qBAAqB,eAAe,QAAQ,CAAC,CAAC;GAC1E,gBAAgB,KAAK,QAAQ;GAC7B,iBAAiB,KAAK,QAAQ;GAC9B,iBAAiB,KAAK,QAAQ;GAC9B,UAAU,EAAE,WAAW,KAAK,iBAAiB;GAC7C,sBAAsB;GACtB,0BAA0B;EAC5B,CAAC,CAAC,CAAC,OAAO;EACV,GAAG,IAAI,YAAY;GACjB,MAAM,KAAK;GACX,aAAa,KAAK;GAClB,kBAAkB,KAAK,QAAQ;GAC/B,sBAAsB;EACxB,CAAC,CAAC,CAAC,OAAO;EACV,GAAG,IAAI,YAAY;GACjB,MAAM,KAAK;GACX,cAAc,KAAK;GACnB,YAAY,KAAK;GACjB,sBAAsB;GACtB,0BAA0B,oBAAoB;EAChD,CAAC,CAAC,CAAC,OAAO;EACV,GAAG;EACH,GAAG;EACH,GAAG;EACH,GAAI,KAAK,cACL,IAAI,aAAa;GACf,MAAM,KAAK;GACX,OAAO,KAAK;GACZ,QAAQ,KAAK,QAAQ;GACrB,UAAU,KAAK,QAAQ;GACvB,eAAe,KAAK,gBAAgB,CAAC,EAAA,CAAG,SAAS,EAAE,kBACjD,YAAY,SAAS,CAAC;IAAE,IAAI,YAAY;IAAI,QAAQ,YAAY;GAAO,CAAC,IAAI,CAAC,CAC/E;EACF,CAAC,CAAC,CAAC,OAAO,IACV,CAAC;EACL,GAAI,KAAK,gBAAgB,KAAK,mBAC1B,IAAI,gBAAgB;GAClB,MAAM,KAAK;GACX,UAAU,KAAK,QAAQ;GACvB,WAAW,YAAY,KAAK,gBAAgB,iBAAiB,CAAC,CAAC,SAAS,WAAW;EACrF,CAAC,CAAC,CAAC,OAAO,IACV,CAAC;EACL,GAAI,KAAK,eACL,IAAI,eAAe;GACjB,MAAM,KAAK;GACX,OAAO,KAAK;GACZ,UAAU,KAAK,QAAQ;GACvB,WAAW,KAAK,QAAQ;GACxB,aAAa,KAAK,QAAQ;GAC1B;GACA;GACA,cAAc,IAAI,aAAa,KAAK,UAAU;EAChD,CAAC,CAAC,CAAC,OAAO,IACV,CAAC;CACP;AACF"}
1
+ {"version":3,"file":"surface.js","names":[],"sources":["../../src/routes/surface.ts"],"sourcesContent":["import type { AuthStorage } from '@mastra/code-sdk/auth/storage';\nimport type { MastraCodeState } from '@mastra/code-sdk/schema';\nimport type { AgentController } from '@mastra/core/agent-controller';\nimport type { ApiRoute } from '@mastra/core/server';\nimport { registerApiRoute } from '@mastra/core/server';\nimport type { FactoryStorage } from '@mastra/core/storage';\n\nimport type { FactoryIntegration, IntegrationContext } from '../integrations/base.js';\nimport { getGithubFeatureDiagnostics } from '../integrations/github/config.js';\nimport type { GithubIntegration } from '../integrations/github/integration.js';\nimport { MaterializeError } from '../integrations/github/sandbox.js';\nimport { FactoryDispatchError } from '../rules/dispatch-errors.js';\nimport type { FactoryBindingPreparationInput } from '../rules/dispatcher.js';\nimport { FactoryStartCoordinator } from '../rules/start-coordinator.js';\nimport { FactoryTransitionService } from '../rules/transition-service.js';\nimport type { FactoryRules } from '../rules/types.js';\nimport { factoryRuleStage } from '../rules/types.js';\nimport type { BaseCheckpointTriggers } from '../sandbox/base-checkpoint-triggers.js';\nimport type { SandboxFleet } from '../sandbox/fleet.js';\nimport {\n ensureFactorySourceSession,\n FactorySourceSessionResolutionError,\n resolveFactoryDefaultModelId,\n} from '../session/factory-session.js';\nimport { LiveSessions } from '../session/live-sessions.js';\nimport type { StateSigner } from '../state-signing.js';\nimport type { AuditEmitter } from '../storage/domains/audit/domain.js';\nimport type { ChannelIdentityStorage } from '../storage/domains/channel-identity/base.js';\nimport type { ModelCredentialsStorage } from '../storage/domains/credentials/base.js';\nimport type { CustomProvidersStorage } from '../storage/domains/custom-providers/base.js';\nimport type { FilesystemStorage } from '../storage/domains/filesystem/base.js';\nimport type { IntakeStorage } from '../storage/domains/intake/base.js';\nimport type { IntegrationStorage } from '../storage/domains/integrations/base.js';\nimport type { MemorySettingsStorage } from '../storage/domains/memory-settings/base.js';\nimport type { ModelPacksStorage } from '../storage/domains/model-packs/base.js';\nimport type { FactoryProjectsStorage } from '../storage/domains/projects/base.js';\nimport type { QueueHealthStorage } from '../storage/domains/queue-health/base.js';\nimport {\n SourceControlConnectionNotFoundError,\n type SourceControlStorage,\n} from '../storage/domains/source-control/base.js';\nimport type { FactoryDispatchFailureCode, WorkItemsStorage } from '../storage/domains/work-items/base.js';\nimport { workItemBranch, workItemBranchSource } from '../work-item-branch.js';\nimport { ConfigRoutes } from './config.js';\nimport { invalidateCustomProvidersSnapshots } from './custom-provider-source.js';\nimport { buildFsRoutes } from './fs.js';\nimport { IntakeRoutes } from './intake.js';\nimport { KnowledgeRoutes } from './knowledge.js';\nimport { OAuthRoutes } from './oauth.js';\nimport type { RouteAuth } from './route.js';\nimport { SkillRoutes } from './skills.js';\nimport { invalidateTenantCredentialSnapshots } from './tenant-credentials.js';\nimport { WorkItemRoutes } from './work-items.js';\n\nconst MATERIALIZE_FAILURE_CODE = {\n 'git-missing': 'repository_git_missing',\n 'egress-blocked': 'repository_egress_blocked',\n 'clone-failed': 'repository_clone_failed',\n 'pull-failed': 'repository_pull_failed',\n 'push-failed': 'repository_push_failed',\n 'commit-failed': 'repository_commit_failed',\n 'gh-missing': 'repository_cli_missing',\n 'pr-failed': 'repository_pr_failed',\n} satisfies Record<MaterializeError['code'], FactoryDispatchFailureCode>;\nexport interface IntegrationRegistration {\n integration: FactoryIntegration;\n ready: boolean;\n ensureReady: () => Promise<void>;\n}\n\nexport interface FactoryApiRoutesDeps {\n controllerId: string;\n controller: AgentController<MastraCodeState>;\n /** Request-auth seam threaded from the host (no service locator). */\n auth: RouteAuth;\n authStorage: AuthStorage;\n audit: AuditEmitter;\n fsRoot?: string;\n publicOrigin: string;\n stateSigner?: StateSigner;\n /** Sandbox fleet constructed by the factory (disabled when no machine). */\n fleet: SandboxFleet;\n /** Base-checkpoint trigger surface, when the factory constructed one. */\n baseCheckpoints?: BaseCheckpointTriggers;\n /** Root factory storage backend (distributed locks, app-db diagnostics). */\n factoryStorage?: FactoryStorage;\n integrationStorage: IntegrationStorage;\n sourceControlStorage: SourceControlStorage;\n /** App-table domain handles, registered and owned by `MastraFactory.prepare()`. */\n domains: {\n intake: IntakeStorage;\n modelCredentials: ModelCredentialsStorage;\n memorySettings: MemorySettingsStorage;\n customProviders: CustomProvidersStorage;\n filesystem: FilesystemStorage;\n modelPacks: ModelPacksStorage;\n projects: FactoryProjectsStorage;\n queueHealth: QueueHealthStorage;\n workItems: WorkItemsStorage;\n channelIdentity: ChannelIdentityStorage;\n };\n integrations?: IntegrationRegistration[];\n intakeReady: boolean;\n factoryReady: boolean;\n knowledgeEnabled: boolean;\n /** Resolved Factory rule set, threaded from the host (no service locator). */\n rules: FactoryRules;\n factoryTransitionService?: FactoryTransitionService;\n sessionRetirement?: import('../sandbox/session-retirement.js').SessionRetirementCoordinator;\n onFactoryRuntime?: (runtime: {\n transitionService: FactoryTransitionService;\n prepareBinding?: (input: FactoryBindingPreparationInput) => Promise<void>;\n }) => void;\n}\n\nfunction guardIntegrationRoutes({\n integration,\n ready,\n ensureReady,\n routes,\n}: IntegrationRegistration & { routes: ApiRoute[] }): ApiRoute[] {\n if (ready) return routes;\n return routes.map(route => {\n if ('handler' in route) {\n const handler = route.handler;\n return {\n ...route,\n handler: async (context: Parameters<typeof handler>[0]) => {\n try {\n await ensureReady();\n } catch {\n return context.json(\n { error: 'integration_unavailable', message: `${integration.id} integration is unavailable.` },\n 503,\n );\n }\n return handler(context, async () => {});\n },\n };\n }\n\n const createHandler = route.createHandler;\n return {\n ...route,\n createHandler: async (args: Parameters<typeof createHandler>[0]) => {\n const handler = await createHandler(args);\n return async (context: Parameters<typeof handler>[0]) => {\n try {\n await ensureReady();\n } catch {\n return context.json(\n { error: 'integration_unavailable', message: `${integration.id} integration is unavailable.` },\n 503,\n );\n }\n return handler(context);\n };\n },\n };\n });\n}\n\n/**\n * Start a factory run for a rule binding: ensure the source-control session the\n * coordinator requires, then hand it to `prepare` along with the factory's\n * default model. Exported for tests — this is the autonomous entry point with no\n * browser and no interactive user, so nothing else would catch a regression in\n * what it forwards.\n */\nexport async function prepareFactoryRuleBinding(\n github: GithubIntegration,\n coordinator: Pick<FactoryStartCoordinator, 'prepare'>,\n projects: FactoryProjectsStorage,\n input: FactoryBindingPreparationInput,\n): Promise<void> {\n try {\n const branch = workItemBranch({\n id: input.item.id,\n source: workItemBranchSource(input.item.externalSource),\n metadata: input.item.metadata,\n });\n const destinationStage = factoryRuleStage(input.item.stages);\n if (!destinationStage) {\n throw new FactoryDispatchError(\n 'unsupported_provider_item',\n 'Factory skill invocation requires one exclusive board stage.',\n );\n }\n const repositorySlug =\n typeof input.item.metadata?.repository === 'string' ? input.item.metadata.repository : undefined;\n const preparedSession = await ensureFactorySourceSession({\n sourceControl: github.sourceControlStorage,\n orgId: input.record.orgId,\n factoryProjectId: input.record.factoryProjectId,\n repositorySlug,\n branch,\n // A human-approved proposal has an interactive user: attribute the run to\n // the approver, not the repo connector.\n attributeToUserId: input.record.approvedBy ?? undefined,\n });\n\n await coordinator.prepare({\n orgId: input.record.orgId,\n userId: preparedSession.userId,\n factoryProjectId: input.record.factoryProjectId,\n sessionId: preparedSession.sessionId,\n defaultModelId: await resolveFactoryDefaultModelId(projects, input.record.factoryProjectId),\n threadTitle: `${input.role === 'review' ? 'PR' : 'Issue'}: ${input.item.title}`,\n kickoffKey: input.record.id,\n destinationStage,\n workItem: {\n id: input.item.id,\n role: input.role,\n input: {\n externalSource: input.item.externalSource,\n parentWorkItemId: input.item.parentWorkItemId,\n title: input.item.title,\n stages: ['intake'],\n sessions: input.item.sessions,\n metadata: input.item.metadata,\n },\n },\n });\n } catch (error) {\n if (error instanceof FactoryDispatchError) throw error;\n if (error instanceof FactorySourceSessionResolutionError) {\n const code = error.reason === 'connection' ? 'source_control_missing' : 'source_repository_missing';\n throw new FactoryDispatchError(code, error.message, { cause: error });\n }\n if (error instanceof SourceControlConnectionNotFoundError) {\n throw new FactoryDispatchError('source_control_missing', error.message, { cause: error });\n }\n if (error instanceof MaterializeError) {\n throw new FactoryDispatchError(MATERIALIZE_FAILURE_CODE[error.code], error.message, { cause: error });\n }\n throw error;\n }\n}\n\n/**\n * Build the {@link IntegrationContext} handed to an integration when the\n * factory collects its capabilities (routes, workers). One shape everywhere:\n * `assembleFactoryApiRoutes` uses it per registration, and `MastraFactory` uses it\n * when collecting integration workers at finalize.\n */\nexport function buildIntegrationContext(\n deps: Pick<\n FactoryApiRoutesDeps,\n 'controller' | 'publicOrigin' | 'auth' | 'fleet' | 'factoryStorage' | 'integrationStorage' | 'sourceControlStorage'\n > & {\n stateSigner: StateSigner;\n emitAudit?: AuditEmitter['emit'];\n rules: FactoryRules;\n factoryReady: boolean;\n domains: Pick<\n FactoryApiRoutesDeps['domains'],\n 'projects' | 'intake' | 'workItems' | 'channelIdentity' | 'memorySettings'\n >;\n /**\n * Stable id of the registered source-control-owning integration (today:\n * `'github'` when registered). Every call site must derive and pass it so\n * `routes()`, `channels()`, and `workers()` all see the same context shape.\n */\n sourceControlOwnerId?: string;\n /** Base-checkpoint trigger surface, when the factory constructed one. */\n baseCheckpoints?: BaseCheckpointTriggers;\n },\n integrationId: string,\n): IntegrationContext {\n return {\n auth: deps.auth,\n fleet: deps.fleet,\n ...(deps.baseCheckpoints ? { baseCheckpoints: deps.baseCheckpoints } : {}),\n factoryStorage: deps.factoryStorage,\n baseUrl: deps.publicOrigin,\n controller: deps.controller,\n stateSigner: deps.stateSigner,\n storage: {\n generic: deps.integrationStorage.forIntegration(integrationId),\n sourceControl: deps.sourceControlStorage.forIntegration(integrationId),\n ...(deps.sourceControlOwnerId\n ? { sourceControlOwner: deps.sourceControlStorage.forIntegration(deps.sourceControlOwnerId) }\n : {}),\n projects: deps.domains.projects,\n intake: deps.domains.intake,\n channelIdentity: deps.domains.channelIdentity,\n memorySettings: deps.domains.memorySettings,\n },\n ...(deps.factoryReady ? { rules: { config: deps.rules, workItems: deps.domains.workItems } } : {}),\n ...(deps.emitAudit ? { hooks: { emitAudit: deps.emitAudit } } : {}),\n };\n}\n\n/**\n * Disabled-status stub for the well-known integration ids. The SPA polls\n * `/web/github/status` and `/web/linear/status` unconditionally, so when an\n * integration is absent (or not ready) the status contract must still hold.\n * Unknown custom ids get no stub — the SPA doesn't poll them.\n */\nfunction disabledIntegrationStatusRoutes(deps: FactoryApiRoutesDeps, id: string, configured = false): ApiRoute[] {\n if (id === 'github') {\n return [\n registerApiRoute('/web/github/status', {\n method: 'GET',\n requiresAuth: false,\n handler: c =>\n c.json({\n enabled: false,\n connected: false,\n installations: [],\n reason: 'missing_config',\n diagnostics: getGithubFeatureDiagnostics({\n github: undefined,\n auth: deps.auth,\n appDbConfigured: deps.factoryStorage !== undefined,\n stateSigner: deps.stateSigner,\n fleet: deps.fleet,\n }),\n }),\n }),\n ];\n }\n if (id === 'linear') {\n return [\n registerApiRoute('/web/linear/status', {\n method: 'GET',\n requiresAuth: false,\n handler: c =>\n c.json({\n enabled: false,\n connected: false,\n workspace: null,\n reason: 'missing_config',\n diagnostics: {\n linearAppConfigured: configured,\n factoryAuthEnabled: deps.auth.enabled(),\n appDbConfigured: true,\n },\n }),\n }),\n ];\n }\n return [];\n}\n\n/**\n * Stub for `GET /web/channel-accounts` when NO Slack integration is\n * registered. The SPA's Connections section polls the path unconditionally;\n * without a stub the SPA fallback serves HTML, which the UI can only read as\n * \"old server / unknown\". The machine-readable reason lets it say the truth:\n * the integration isn't registered.\n *\n * Mounted only for ABSENT slack — a registered integration owns the path via\n * its connect routes (or, when the state signer is unstable, gets no routes\n * at all and the UI falls back to the generic copy). Static payload, leaks\n * nothing → no auth needed, same posture as the github/linear stubs.\n */\nfunction absentSlackChannelAccountsRoutes(): ApiRoute[] {\n return [\n registerApiRoute('/web/channel-accounts', {\n method: 'GET',\n requiresAuth: false,\n handler: c => c.json({ accounts: [], canConnect: false, reason: 'not_registered' }),\n }),\n ];\n}\n\n/**\n * Assemble the custom `/web/*` API routes as Mastra `server.apiRoutes`:\n * - fs browser routes (project picker), confined to `fsRoot`\n * - config routes (provider/API-key/model-pack/OM management)\n * - every registered integration's `routes()` surface (full set when ready,\n * disabled-status stub otherwise), plus stubs for absent known ids\n */\nexport function assembleFactoryApiRoutes(deps: FactoryApiRoutesDeps): ApiRoute[] {\n const emitAudit: AuditEmitter['emit'] = args => deps.audit.emit(args);\n const registrations = deps.integrations ?? [];\n const githubRegistration = registrations.find(({ integration }) => integration.id === 'github');\n const githubStorage = githubRegistration ? deps.sourceControlStorage.forIntegration('github') : undefined;\n const githubIntegration = githubRegistration?.integration as GithubIntegration | undefined;\n\n const integrationRoutes = registrations.flatMap(registration => {\n const { integration } = registration;\n if (!deps.stateSigner) return disabledIntegrationStatusRoutes(deps, integration.id, true);\n const context = buildIntegrationContext(\n {\n ...deps,\n stateSigner: deps.stateSigner,\n emitAudit,\n ...(githubRegistration ? { sourceControlOwnerId: 'github' } : {}),\n },\n integration.id,\n );\n return guardIntegrationRoutes({ ...registration, routes: integration.routes(context) });\n });\n // Absent known integrations still get their disabled-status stub.\n const absentStubs = ['github', 'linear']\n .filter(id => !registrations.some(({ integration }) => integration.id === id))\n .flatMap(id => disabledIntegrationStatusRoutes(deps, id));\n // Absent slack gets the channel-accounts not-registered stub (registered\n // slack owns the path via its own connect routes).\n const slackAbsentStubs = registrations.some(({ integration }) => integration.id === 'slack')\n ? []\n : absentSlackChannelAccountsRoutes();\n\n const transitionService = deps.factoryReady\n ? (deps.factoryTransitionService ??\n new FactoryTransitionService({ rules: deps.rules, storage: deps.domains.workItems }))\n : undefined;\n const startCoordinator = transitionService\n ? new FactoryStartCoordinator(\n deps.controller,\n deps.domains.workItems,\n transitionService,\n githubIntegration?.sourceControlStorage,\n deps.domains.memorySettings,\n )\n : undefined;\n if (transitionService && startCoordinator) {\n deps.onFactoryRuntime?.({\n transitionService,\n ...(githubIntegration\n ? {\n prepareBinding: (input: FactoryBindingPreparationInput) =>\n prepareFactoryRuleBinding(githubIntegration, startCoordinator, deps.domains.projects, input),\n }\n : {}),\n });\n }\n\n return [\n ...buildFsRoutes({\n root: deps.fsRoot,\n sessionFs: {\n auth: deps.auth,\n fleet: deps.fleet,\n sessions: deps.sourceControlStorage.forIntegration('github').sessions,\n filesystem: deps.domains.filesystem,\n },\n }),\n ...new ConfigRoutes({\n auth: deps.auth,\n controller: deps.controller,\n authStorage: deps.authStorage,\n modelCredentials: deps.domains.modelCredentials,\n modelPacks: deps.domains.modelPacks,\n sourceControlSessions: deps.sourceControlStorage.forIntegration('github').sessions,\n memorySettings: deps.domains.memorySettings,\n factoryProjects: deps.domains.projects,\n customProviders: deps.domains.customProviders,\n features: { knowledge: deps.knowledgeEnabled },\n onCredentialsChanged: invalidateTenantCredentialSnapshots,\n onCustomProvidersChanged: invalidateCustomProvidersSnapshots,\n }).routes(),\n ...new OAuthRoutes({\n auth: deps.auth,\n authStorage: deps.authStorage,\n modelCredentials: deps.domains.modelCredentials,\n onCredentialsChanged: invalidateTenantCredentialSnapshots,\n }).routes(),\n ...new SkillRoutes({\n auth: deps.auth,\n controllerId: deps.controllerId,\n controller: deps.controller,\n sourceControlStorage: githubStorage,\n ensureSourceControlReady: githubRegistration?.ensureReady,\n }).routes(),\n ...integrationRoutes,\n ...absentStubs,\n ...slackAbsentStubs,\n ...(deps.intakeReady\n ? new IntakeRoutes({\n auth: deps.auth,\n audit: deps.audit,\n intake: deps.domains.intake,\n projects: deps.domains.projects,\n integrations: (deps.integrations ?? []).flatMap(({ integration }) =>\n integration.intake ? [{ id: integration.id, intake: integration.intake }] : [],\n ),\n }).routes()\n : []),\n ...(deps.factoryReady && deps.knowledgeEnabled\n ? new KnowledgeRoutes({\n auth: deps.auth,\n projects: deps.domains.projects,\n knowledge: async () => deps.factoryStorage?.getMastraStorage().getStore('knowledge'),\n }).routes()\n : []),\n ...(deps.factoryReady\n ? new WorkItemRoutes({\n auth: deps.auth,\n audit: deps.audit,\n projects: deps.domains.projects,\n workItems: deps.domains.workItems,\n queueHealth: deps.domains.queueHealth,\n transitionService,\n startCoordinator,\n liveSessions: new LiveSessions(deps.controller),\n }).routes()\n : []),\n ];\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAsDA,MAAM,2BAA2B;CAC/B,eAAe;CACf,kBAAkB;CAClB,gBAAgB;CAChB,eAAe;CACf,eAAe;CACf,iBAAiB;CACjB,cAAc;CACd,aAAa;AACf;AAoDA,SAAS,uBAAuB,EAC9B,aACA,OACA,aACA,UAC+D;CAC/D,IAAI,OAAO,OAAO;CAClB,OAAO,OAAO,KAAI,UAAS;EACzB,IAAI,aAAa,OAAO;GACtB,MAAM,UAAU,MAAM;GACtB,OAAO;IACL,GAAG;IACH,SAAS,OAAO,YAA2C;KACzD,IAAI;MACF,MAAM,YAAY;KACpB,QAAQ;MACN,OAAO,QAAQ,KACb;OAAE,OAAO;OAA2B,SAAS,GAAG,YAAY,GAAG;MAA8B,GAC7F,GACF;KACF;KACA,OAAO,QAAQ,SAAS,YAAY,CAAC,CAAC;IACxC;GACF;EACF;EAEA,MAAM,gBAAgB,MAAM;EAC5B,OAAO;GACL,GAAG;GACH,eAAe,OAAO,SAA8C;IAClE,MAAM,UAAU,MAAM,cAAc,IAAI;IACxC,OAAO,OAAO,YAA2C;KACvD,IAAI;MACF,MAAM,YAAY;KACpB,QAAQ;MACN,OAAO,QAAQ,KACb;OAAE,OAAO;OAA2B,SAAS,GAAG,YAAY,GAAG;MAA8B,GAC7F,GACF;KACF;KACA,OAAO,QAAQ,OAAO;IACxB;GACF;EACF;CACF,CAAC;AACH;;;;;;;;AASA,eAAsB,0BACpB,QACA,aACA,UACA,OACe;CACf,IAAI;EACF,MAAM,SAAS,eAAe;GAC5B,IAAI,MAAM,KAAK;GACf,QAAQ,qBAAqB,MAAM,KAAK,cAAc;GACtD,UAAU,MAAM,KAAK;EACvB,CAAC;EACD,MAAM,mBAAmB,iBAAiB,MAAM,KAAK,MAAM;EAC3D,IAAI,CAAC,kBACH,MAAM,IAAI,qBACR,6BACA,8DACF;EAEF,MAAM,iBACJ,OAAO,MAAM,KAAK,UAAU,eAAe,WAAW,MAAM,KAAK,SAAS,aAAa,KAAA;EACzF,MAAM,kBAAkB,MAAM,2BAA2B;GACvD,eAAe,OAAO;GACtB,OAAO,MAAM,OAAO;GACpB,kBAAkB,MAAM,OAAO;GAC/B;GACA;GAGA,mBAAmB,MAAM,OAAO,cAAc,KAAA;EAChD,CAAC;EAED,MAAM,YAAY,QAAQ;GACxB,OAAO,MAAM,OAAO;GACpB,QAAQ,gBAAgB;GACxB,kBAAkB,MAAM,OAAO;GAC/B,WAAW,gBAAgB;GAC3B,gBAAgB,MAAM,6BAA6B,UAAU,MAAM,OAAO,gBAAgB;GAC1F,aAAa,GAAG,MAAM,SAAS,WAAW,OAAO,QAAQ,IAAI,MAAM,KAAK;GACxE,YAAY,MAAM,OAAO;GACzB;GACA,UAAU;IACR,IAAI,MAAM,KAAK;IACf,MAAM,MAAM;IACZ,OAAO;KACL,gBAAgB,MAAM,KAAK;KAC3B,kBAAkB,MAAM,KAAK;KAC7B,OAAO,MAAM,KAAK;KAClB,QAAQ,CAAC,QAAQ;KACjB,UAAU,MAAM,KAAK;KACrB,UAAU,MAAM,KAAK;IACvB;GACF;EACF,CAAC;CACH,SAAS,OAAO;EACd,IAAI,iBAAiB,sBAAsB,MAAM;EACjD,IAAI,iBAAiB,qCAEnB,MAAM,IAAI,qBADG,MAAM,WAAW,eAAe,2BAA2B,6BACnC,MAAM,SAAS,EAAE,OAAO,MAAM,CAAC;EAEtE,IAAI,iBAAiB,sCACnB,MAAM,IAAI,qBAAqB,0BAA0B,MAAM,SAAS,EAAE,OAAO,MAAM,CAAC;EAE1F,IAAI,iBAAiB,kBACnB,MAAM,IAAI,qBAAqB,yBAAyB,MAAM,OAAO,MAAM,SAAS,EAAE,OAAO,MAAM,CAAC;EAEtG,MAAM;CACR;AACF;;;;;;;AAQA,SAAgB,wBACd,MAqBA,eACoB;CACpB,OAAO;EACL,MAAM,KAAK;EACX,OAAO,KAAK;EACZ,GAAI,KAAK,kBAAkB,EAAE,iBAAiB,KAAK,gBAAgB,IAAI,CAAC;EACxE,gBAAgB,KAAK;EACrB,SAAS,KAAK;EACd,YAAY,KAAK;EACjB,aAAa,KAAK;EAClB,SAAS;GACP,SAAS,KAAK,mBAAmB,eAAe,aAAa;GAC7D,eAAe,KAAK,qBAAqB,eAAe,aAAa;GACrE,GAAI,KAAK,uBACL,EAAE,oBAAoB,KAAK,qBAAqB,eAAe,KAAK,oBAAoB,EAAE,IAC1F,CAAC;GACL,UAAU,KAAK,QAAQ;GACvB,QAAQ,KAAK,QAAQ;GACrB,iBAAiB,KAAK,QAAQ;GAC9B,gBAAgB,KAAK,QAAQ;EAC/B;EACA,GAAI,KAAK,eAAe,EAAE,OAAO;GAAE,QAAQ,KAAK;GAAO,WAAW,KAAK,QAAQ;EAAU,EAAE,IAAI,CAAC;EAChG,GAAI,KAAK,YAAY,EAAE,OAAO,EAAE,WAAW,KAAK,UAAU,EAAE,IAAI,CAAC;CACnE;AACF;;;;;;;AAQA,SAAS,gCAAgC,MAA4B,IAAY,aAAa,OAAmB;CAC/G,IAAI,OAAO,UACT,OAAO,CACL,iBAAiB,sBAAsB;EACrC,QAAQ;EACR,cAAc;EACd,UAAS,MACP,EAAE,KAAK;GACL,SAAS;GACT,WAAW;GACX,eAAe,CAAC;GAChB,QAAQ;GACR,aAAa,4BAA4B;IACvC,QAAQ,KAAA;IACR,MAAM,KAAK;IACX,iBAAiB,KAAK,mBAAmB,KAAA;IACzC,aAAa,KAAK;IAClB,OAAO,KAAK;GACd,CAAC;EACH,CAAC;CACL,CAAC,CACH;CAEF,IAAI,OAAO,UACT,OAAO,CACL,iBAAiB,sBAAsB;EACrC,QAAQ;EACR,cAAc;EACd,UAAS,MACP,EAAE,KAAK;GACL,SAAS;GACT,WAAW;GACX,WAAW;GACX,QAAQ;GACR,aAAa;IACX,qBAAqB;IACrB,oBAAoB,KAAK,KAAK,QAAQ;IACtC,iBAAiB;GACnB;EACF,CAAC;CACL,CAAC,CACH;CAEF,OAAO,CAAC;AACV;;;;;;;;;;;;;AAcA,SAAS,mCAA+C;CACtD,OAAO,CACL,iBAAiB,yBAAyB;EACxC,QAAQ;EACR,cAAc;EACd,UAAS,MAAK,EAAE,KAAK;GAAE,UAAU,CAAC;GAAG,YAAY;GAAO,QAAQ;EAAiB,CAAC;CACpF,CAAC,CACH;AACF;;;;;;;;AASA,SAAgB,yBAAyB,MAAwC;CAC/E,MAAM,aAAkC,SAAQ,KAAK,MAAM,KAAK,IAAI;CACpE,MAAM,gBAAgB,KAAK,gBAAgB,CAAC;CAC5C,MAAM,qBAAqB,cAAc,MAAM,EAAE,kBAAkB,YAAY,OAAO,QAAQ;CAC9F,MAAM,gBAAgB,qBAAqB,KAAK,qBAAqB,eAAe,QAAQ,IAAI,KAAA;CAChG,MAAM,oBAAoB,oBAAoB;CAE9C,MAAM,oBAAoB,cAAc,SAAQ,iBAAgB;EAC9D,MAAM,EAAE,gBAAgB;EACxB,IAAI,CAAC,KAAK,aAAa,OAAO,gCAAgC,MAAM,YAAY,IAAI,IAAI;EACxF,MAAM,UAAU,wBACd;GACE,GAAG;GACH,aAAa,KAAK;GAClB;GACA,GAAI,qBAAqB,EAAE,sBAAsB,SAAS,IAAI,CAAC;EACjE,GACA,YAAY,EACd;EACA,OAAO,uBAAuB;GAAE,GAAG;GAAc,QAAQ,YAAY,OAAO,OAAO;EAAE,CAAC;CACxF,CAAC;CAED,MAAM,cAAc,CAAC,UAAU,QAAQ,CAAC,CACrC,QAAO,OAAM,CAAC,cAAc,MAAM,EAAE,kBAAkB,YAAY,OAAO,EAAE,CAAC,CAAC,CAC7E,SAAQ,OAAM,gCAAgC,MAAM,EAAE,CAAC;CAG1D,MAAM,mBAAmB,cAAc,MAAM,EAAE,kBAAkB,YAAY,OAAO,OAAO,IACvF,CAAC,IACD,iCAAiC;CAErC,MAAM,oBAAoB,KAAK,eAC1B,KAAK,4BACN,IAAI,yBAAyB;EAAE,OAAO,KAAK;EAAO,SAAS,KAAK,QAAQ;CAAU,CAAC,IACnF,KAAA;CACJ,MAAM,mBAAmB,oBACrB,IAAI,wBACF,KAAK,YACL,KAAK,QAAQ,WACb,mBACA,mBAAmB,sBACnB,KAAK,QAAQ,cACf,IACA,KAAA;CACJ,IAAI,qBAAqB,kBACvB,KAAK,mBAAmB;EACtB;EACA,GAAI,oBACA,EACE,iBAAiB,UACf,0BAA0B,mBAAmB,kBAAkB,KAAK,QAAQ,UAAU,KAAK,EAC/F,IACA,CAAC;CACP,CAAC;CAGH,OAAO;EACL,GAAG,cAAc;GACf,MAAM,KAAK;GACX,WAAW;IACT,MAAM,KAAK;IACX,OAAO,KAAK;IACZ,UAAU,KAAK,qBAAqB,eAAe,QAAQ,CAAC,CAAC;IAC7D,YAAY,KAAK,QAAQ;GAC3B;EACF,CAAC;EACD,GAAG,IAAI,aAAa;GAClB,MAAM,KAAK;GACX,YAAY,KAAK;GACjB,aAAa,KAAK;GAClB,kBAAkB,KAAK,QAAQ;GAC/B,YAAY,KAAK,QAAQ;GACzB,uBAAuB,KAAK,qBAAqB,eAAe,QAAQ,CAAC,CAAC;GAC1E,gBAAgB,KAAK,QAAQ;GAC7B,iBAAiB,KAAK,QAAQ;GAC9B,iBAAiB,KAAK,QAAQ;GAC9B,UAAU,EAAE,WAAW,KAAK,iBAAiB;GAC7C,sBAAsB;GACtB,0BAA0B;EAC5B,CAAC,CAAC,CAAC,OAAO;EACV,GAAG,IAAI,YAAY;GACjB,MAAM,KAAK;GACX,aAAa,KAAK;GAClB,kBAAkB,KAAK,QAAQ;GAC/B,sBAAsB;EACxB,CAAC,CAAC,CAAC,OAAO;EACV,GAAG,IAAI,YAAY;GACjB,MAAM,KAAK;GACX,cAAc,KAAK;GACnB,YAAY,KAAK;GACjB,sBAAsB;GACtB,0BAA0B,oBAAoB;EAChD,CAAC,CAAC,CAAC,OAAO;EACV,GAAG;EACH,GAAG;EACH,GAAG;EACH,GAAI,KAAK,cACL,IAAI,aAAa;GACf,MAAM,KAAK;GACX,OAAO,KAAK;GACZ,QAAQ,KAAK,QAAQ;GACrB,UAAU,KAAK,QAAQ;GACvB,eAAe,KAAK,gBAAgB,CAAC,EAAA,CAAG,SAAS,EAAE,kBACjD,YAAY,SAAS,CAAC;IAAE,IAAI,YAAY;IAAI,QAAQ,YAAY;GAAO,CAAC,IAAI,CAAC,CAC/E;EACF,CAAC,CAAC,CAAC,OAAO,IACV,CAAC;EACL,GAAI,KAAK,gBAAgB,KAAK,mBAC1B,IAAI,gBAAgB;GAClB,MAAM,KAAK;GACX,UAAU,KAAK,QAAQ;GACvB,WAAW,YAAY,KAAK,gBAAgB,iBAAiB,CAAC,CAAC,SAAS,WAAW;EACrF,CAAC,CAAC,CAAC,OAAO,IACV,CAAC;EACL,GAAI,KAAK,eACL,IAAI,eAAe;GACjB,MAAM,KAAK;GACX,OAAO,KAAK;GACZ,UAAU,KAAK,QAAQ;GACvB,WAAW,KAAK,QAAQ;GACxB,aAAa,KAAK,QAAQ;GAC1B;GACA;GACA,cAAc,IAAI,aAAa,KAAK,UAAU;EAChD,CAAC,CAAC,CAAC,OAAO,IACV,CAAC;CACP;AACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"work-items.d.ts","sourceRoot":"","sources":["../../src/routes/work-items.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAIpD,OAAO,KAAK,EACV,uBAAuB,EAGxB,MAAM,+BAA+B,CAAC;AAEvC,OAAO,KAAK,EAA4B,wBAAwB,EAAE,MAAM,gCAAgC,CAAC;AAGzG,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAChE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oCAAoC,CAAC;AACvE,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,qCAAqC,CAAC;AAClF,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yCAAyC,CAAC;AAElF,OAAO,KAAK,EACV,mBAAmB,EAInB,mBAAmB,EAKnB,gBAAgB,EACjB,MAAM,uCAAuC,CAAC;AAG/C,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AACpD,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAEnC,MAAM,WAAW,kBAAmB,SAAQ,iBAAiB;IAC3D,KAAK,EAAE,YAAY,CAAC;IACpB,yFAAyF;IACzF,QAAQ,EAAE,sBAAsB,CAAC;IACjC,kDAAkD;IAClD,SAAS,EAAE,gBAAgB,CAAC;IAC5B,iDAAiD;IACjD,WAAW,EAAE,kBAAkB,CAAC;IAChC,sEAAsE;IACtE,iBAAiB,CAAC,EAAE,IAAI,CAAC,wBAAwB,EAAE,YAAY,GAAG,gBAAgB,CAAC,CAAC;IACpF,2EAA2E;IAC3E,gBAAgB,CAAC,EAAE,IAAI,CAAC,uBAAuB,EAAE,SAAS,CAAC,CAAC;IAC5D,wFAAwF;IACxF,YAAY,EAAE,IAAI,CAAC,YAAY,EAAE,WAAW,CAAC,CAAC;CAC/C;AAuFD,mEAAmE;AACnE,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,OAAO,GAAG,mBAAmB,GAAG,IAAI,CAuB7E;AAED,kEAAkE;AAClE,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,OAAO,GAAG,mBAAmB,GAAG,IAAI,CA4B7E;AA2LD,qBAAa,cAAe,SAAQ,KAAK,CAAC,kBAAkB,CAAC;;IAwJ3D,gEAAgE;IAChE,MAAM,IAAI,QAAQ,EAAE;CAkXrB"}
1
+ {"version":3,"file":"work-items.d.ts","sourceRoot":"","sources":["../../src/routes/work-items.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAKpD,OAAO,KAAK,EACV,uBAAuB,EAGxB,MAAM,+BAA+B,CAAC;AAEvC,OAAO,KAAK,EAA4B,wBAAwB,EAAE,MAAM,gCAAgC,CAAC;AAGzG,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAChE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oCAAoC,CAAC;AACvE,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,qCAAqC,CAAC;AAClF,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yCAAyC,CAAC;AAElF,OAAO,KAAK,EACV,mBAAmB,EAInB,mBAAmB,EAKnB,gBAAgB,EACjB,MAAM,uCAAuC,CAAC;AAQ/C,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AACpD,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAEnC,MAAM,WAAW,kBAAmB,SAAQ,iBAAiB;IAC3D,KAAK,EAAE,YAAY,CAAC;IACpB,yFAAyF;IACzF,QAAQ,EAAE,sBAAsB,CAAC;IACjC,kDAAkD;IAClD,SAAS,EAAE,gBAAgB,CAAC;IAC5B,iDAAiD;IACjD,WAAW,EAAE,kBAAkB,CAAC;IAChC,sEAAsE;IACtE,iBAAiB,CAAC,EAAE,IAAI,CAAC,wBAAwB,EAAE,YAAY,GAAG,gBAAgB,CAAC,CAAC;IACpF,2EAA2E;IAC3E,gBAAgB,CAAC,EAAE,IAAI,CAAC,uBAAuB,EAAE,SAAS,CAAC,CAAC;IAC5D,wFAAwF;IACxF,YAAY,EAAE,IAAI,CAAC,YAAY,EAAE,WAAW,CAAC,CAAC;CAC/C;AAsGD,mEAAmE;AACnE,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,OAAO,GAAG,mBAAmB,GAAG,IAAI,CA2B7E;AAED,kEAAkE;AAClE,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,OAAO,GAAG,mBAAmB,GAAG,IAAI,CAgC7E;AA2LD,qBAAa,cAAe,SAAQ,KAAK,CAAC,kBAAkB,CAAC;;IAyJ3D,gEAAgE;IAChE,MAAM,IAAI,QAAQ,EAAE;CA+XrB"}
@@ -1,18 +1,19 @@
1
1
  import { FACTORY_RULE_BOARDS, isFactoryRuleStage } from "../rules/types.js";
2
+ import { FACTORY_PULL_REQUEST_RECONCILIATION_KEY, FACTORY_RULE_MATERIALIZATION_KEY, WorkItemRelationError } from "../storage/domains/work-items/base.js";
2
3
  import { Route } from "./route.js";
4
+ import { factoryDispatchFailureMetadata } from "../rules/dispatch-errors.js";
3
5
  import { FactoryStartTransitionError } from "../rules/start-coordinator.js";
4
6
  import { thresholdsOrDefault } from "../storage/domains/queue-health/base.js";
5
- import { FACTORY_RULE_MATERIALIZATION_KEY, WorkItemRelationError } from "../storage/domains/work-items/base.js";
6
7
  import { computeFactoryMetrics, parseMetricsRange } from "../storage/domains/work-items/metrics.js";
8
+ import { buildAttentionRoutes, factoryDecisionType } from "./attention.js";
7
9
  import { registerApiRoute } from "@mastra/core/server";
8
10
  //#region src/routes/work-items.ts
9
11
  /** The card as clients see it, without the dispatcher's internal bookkeeping. */
10
12
  function toWireWorkItem(item) {
11
- if (!item.metadata || !("factoryRuleMaterializationKey" in item.metadata)) return item;
12
- const { [FACTORY_RULE_MATERIALIZATION_KEY]: _internal, ...metadata } = item.metadata;
13
+ if (!item.metadata || !("factoryRuleMaterializationKey" in item.metadata) && !("factoryPullRequestReconciliation" in item.metadata)) return item;
13
14
  return {
14
15
  ...item,
15
- metadata
16
+ metadata: publicWorkItemMetadata(item.metadata) ?? {}
16
17
  };
17
18
  }
18
19
  /** Session ids of the listed cards whose agent run is in flight. */
@@ -43,6 +44,11 @@ function validMetadata(value) {
43
44
  return false;
44
45
  }
45
46
  }
47
+ function publicWorkItemMetadata(value) {
48
+ if (value === null) return null;
49
+ const { [FACTORY_RULE_MATERIALIZATION_KEY]: _materialization, [FACTORY_PULL_REQUEST_RECONCILIATION_KEY]: _reconciliation, ...metadata } = value;
50
+ return metadata;
51
+ }
46
52
  function parseExternalSource(value) {
47
53
  if (value === void 0 || value === null) return value;
48
54
  if (!isRecord(value)) return void 0;
@@ -93,14 +99,18 @@ function parseCreateWorkItem(body) {
93
99
  if (stages !== void 0 && !validStages(stages)) return null;
94
100
  const parsedSessions = sessions === void 0 ? void 0 : parseSessions(sessions);
95
101
  if (sessions !== void 0 && parsedSessions === void 0) return null;
96
- if (metadata !== void 0 && !validMetadata(metadata)) return null;
102
+ let parsedMetadata;
103
+ if (metadata !== void 0) {
104
+ if (!validMetadata(metadata)) return null;
105
+ parsedMetadata = publicWorkItemMetadata(metadata);
106
+ }
97
107
  return {
98
108
  title: title.trim(),
99
109
  ...parsedSource !== void 0 ? { externalSource: parsedSource } : {},
100
110
  ...hasParentWorkItemId ? { parentWorkItemId: parentWorkItemId ?? null } : {},
101
111
  ...stages !== void 0 ? { stages } : {},
102
112
  ...parsedSessions !== void 0 ? { sessions: parsedSessions } : {},
103
- ...metadata !== void 0 ? { metadata } : {}
113
+ ...parsedMetadata !== void 0 ? { metadata: parsedMetadata } : {}
104
114
  };
105
115
  }
106
116
  /** Validate an untrusted patch body. Unknown keys are dropped. */
@@ -115,13 +125,17 @@ function parseUpdateWorkItem(body) {
115
125
  if (stages !== void 0 && !validStages(stages)) return null;
116
126
  const parsedSessions = sessions === void 0 ? void 0 : parseSessions(sessions);
117
127
  if (sessions !== void 0 && parsedSessions === void 0) return null;
118
- if (metadata !== void 0 && !validMetadata(metadata)) return null;
128
+ let parsedMetadata;
129
+ if (metadata !== void 0) {
130
+ if (!validMetadata(metadata)) return null;
131
+ parsedMetadata = publicWorkItemMetadata(metadata);
132
+ }
119
133
  return {
120
134
  ...hasParentWorkItemId ? { parentWorkItemId: parentWorkItemId ?? null } : {},
121
135
  ...title !== void 0 ? { title: title.trim() } : {},
122
136
  ...stages !== void 0 ? { stages } : {},
123
137
  ...parsedSessions !== void 0 ? { sessions: parsedSessions } : {},
124
- ...metadata !== void 0 ? { metadata } : {}
138
+ ...parsedMetadata !== void 0 ? { metadata: parsedMetadata } : {}
125
139
  };
126
140
  }
127
141
  async function readJson(c) {
@@ -212,6 +226,7 @@ const DECISION_STATUSES = /* @__PURE__ */ new Set([
212
226
  "pending",
213
227
  "proposed",
214
228
  "dismissed",
229
+ "superseded",
215
230
  "leased",
216
231
  "retry",
217
232
  "succeeded",
@@ -247,18 +262,18 @@ function parseDecisionCursor(raw) {
247
262
  return;
248
263
  }
249
264
  }
250
- function decisionType(decision) {
251
- return typeof decision.decision.type === "string" ? decision.decision.type.slice(0, 64) : "unknown";
252
- }
253
265
  function decisionSummary(decision) {
254
266
  return {
255
267
  id: decision.id,
256
268
  evaluationId: decision.evaluationId,
257
269
  workItemId: decision.workItemId,
258
- type: decisionType(decision),
270
+ type: factoryDecisionType(decision),
259
271
  role: typeof decision.decision.role === "string" ? decision.decision.role.slice(0, 32) : null,
260
272
  status: decision.status,
261
273
  attempts: decision.attempts,
274
+ failureOccurrence: decision.failureOccurrence,
275
+ failureCode: decision.failureCode,
276
+ canRetry: factoryDispatchFailureMetadata(decision.failureCode).canRetry,
262
277
  lastError: decision.lastError?.slice(0, 512) ?? null,
263
278
  createdAt: decision.createdAt.toISOString(),
264
279
  updatedAt: decision.updatedAt.toISOString(),
@@ -369,7 +384,7 @@ var WorkItemRoutes = class extends Route {
369
384
  if (!decisionId || !UUID_RE.test(decisionId)) return c.json({ error: "invalid_decision_id" }, 422);
370
385
  await workItems.ensureReady();
371
386
  const now = /* @__PURE__ */ new Date();
372
- const decision = await settle(resolved.orgId, resolved.factoryProjectId, decisionId, now);
387
+ const decision = await settle(resolved.orgId, resolved.factoryProjectId, decisionId, now, resolved.userId);
373
388
  if (!decision) return c.json({ error: "decision_not_proposed" }, 409);
374
389
  await audit.emit({
375
390
  context,
@@ -385,7 +400,7 @@ var WorkItemRoutes = class extends Route {
385
400
  }],
386
401
  metadata: {
387
402
  decisionId: decision.id,
388
- effect: decisionType(decision)
403
+ effect: factoryDecisionType(decision)
389
404
  }
390
405
  }
391
406
  });
@@ -468,6 +483,10 @@ var WorkItemRoutes = class extends Route {
468
483
  });
469
484
  }
470
485
  }),
486
+ ...buildAttentionRoutes({
487
+ workItems,
488
+ resolveProject: (context) => this.#resolveProject(loose(context))
489
+ }),
471
490
  this.#proposalRoute({
472
491
  verb: "approve",
473
492
  settle: workItems.approveDeferredDecision.bind(workItems)
@@ -486,6 +505,8 @@ var WorkItemRoutes = class extends Route {
486
505
  const decisionId = context.req.param("decisionId");
487
506
  if (!decisionId || !UUID_RE.test(decisionId)) return c.json({ error: "invalid_decision_id" }, 422);
488
507
  await workItems.ensureReady();
508
+ const current = await workItems.getDeferredDecision(resolved.orgId, resolved.factoryProjectId, decisionId);
509
+ if (!current || current.status !== "failed" || !factoryDispatchFailureMetadata(current.failureCode).canRetry) return c.json({ error: "decision_not_retryable" }, 409);
489
510
  const decision = await workItems.retryDeferredDecision(resolved.orgId, resolved.factoryProjectId, decisionId, /* @__PURE__ */ new Date());
490
511
  if (!decision) return c.json({ error: "decision_not_retryable" }, 409);
491
512
  return c.json({ decision: decisionSummary(decision) });
@@ -1 +1 @@
1
- {"version":3,"file":"work-items.js","names":["#resolveTenant","#resolveProject","#auditWorkItemPatch","#proposalRoute"],"sources":["../../src/routes/work-items.ts"],"sourcesContent":["/**\n * Mastra `apiRoutes` for Factory work items (the kanban board).\n *\n * Registered alongside the other `/web/*` routes behind the host auth gate.\n * The board is org-wide: every route re-resolves the caller's `(orgId, userId)`\n * tenant and scopes reads/writes by `orgId`, so any org member sees and moves\n * the same cards while `created_by` / stage history record who acted.\n */\n\nimport type { ApiRoute } from '@mastra/core/server';\nimport { registerApiRoute } from '@mastra/core/server';\nimport type { Context } from 'hono';\n\nimport type {\n FactoryStartCoordinator,\n FactoryStartPreparedResult,\n FactoryStartRequest,\n} from '../rules/start-coordinator.js';\nimport { FactoryStartTransitionError } from '../rules/start-coordinator.js';\nimport type { FactoryTransitionRequest, FactoryTransitionService } from '../rules/transition-service.js';\nimport type { FactoryRuleBoard } from '../rules/types.js';\nimport { FACTORY_RULE_BOARDS, isFactoryRuleStage } from '../rules/types.js';\nimport type { LiveSessions } from '../session/live-sessions.js';\nimport type { AuditEmitter } from '../storage/domains/audit/domain.js';\nimport type { FactoryProjectsStorage } from '../storage/domains/projects/base.js';\nimport type { QueueHealthStorage } from '../storage/domains/queue-health/base.js';\nimport { thresholdsOrDefault } from '../storage/domains/queue-health/base.js';\nimport type {\n CreateWorkItemInput,\n ExternalWorkItemSource,\n FactoryDeferredDecisionRecord,\n FactoryDispatchStatus,\n UpdateWorkItemInput,\n WorkItemPriorState,\n WorkItemRow,\n WorkItemSessionInput,\n WorkItemStage,\n WorkItemsStorage,\n} from '../storage/domains/work-items/base.js';\nimport { FACTORY_RULE_MATERIALIZATION_KEY, WorkItemRelationError } from '../storage/domains/work-items/base.js';\nimport { computeFactoryMetrics, parseMetricsRange } from '../storage/domains/work-items/metrics.js';\nimport type { RouteDependencies } from './route.js';\nimport { Route } from './route.js';\n\nexport interface WorkItemRoutesDeps extends RouteDependencies {\n audit: AuditEmitter;\n /** Factory projects domain — validates the `:id` project belongs to the caller's org. */\n projects: FactoryProjectsStorage;\n /** Work-items domain backing the kanban board. */\n workItems: WorkItemsStorage;\n /** Per-project queue-health threshold config. */\n queueHealth: QueueHealthStorage;\n /** Governed stage-transition service. Stage moves 503 when absent. */\n transitionService?: Pick<FactoryTransitionService, 'transition' | 'ruleSetVersion'>;\n /** Coordinator that binds a Factory run before dispatching its kickoff. */\n startCoordinator?: Pick<FactoryStartCoordinator, 'prepare'>;\n /** Materialized sessions, read to report which of the listed cards are being worked. */\n liveSessions: Pick<LiveSessions, 'isRunning'>;\n}\n\n/** The card as clients see it, without the dispatcher's internal bookkeeping. */\nfunction toWireWorkItem(item: WorkItemRow): WorkItemRow {\n if (!item.metadata || !(FACTORY_RULE_MATERIALIZATION_KEY in item.metadata)) return item;\n const { [FACTORY_RULE_MATERIALIZATION_KEY]: _internal, ...metadata } = item.metadata;\n return { ...item, metadata };\n}\n\n/** Session ids of the listed cards whose agent run is in flight. */\nfunction runningSessionIds(items: WorkItemRow[], liveSessions: Pick<LiveSessions, 'isRunning'>): string[] {\n const running = new Set<string>();\n for (const item of items) {\n for (const { sessionId } of Object.values(item.sessions)) {\n if (liveSessions.isRunning(sessionId)) running.add(sessionId);\n }\n }\n return [...running];\n}\n\nfunction loose(c: unknown): Context {\n return c as Context;\n}\n\nconst UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;\n\nconst MAX_STAGES = 16;\nconst MAX_STAGE_LENGTH = 64;\nconst MAX_METADATA_BYTES = 16 * 1024;\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction validStages(value: unknown): value is WorkItemStage[] {\n return (\n Array.isArray(value) &&\n value.length > 0 &&\n value.length <= MAX_STAGES &&\n value.every(\n stage => typeof stage === 'string' && stage.length <= MAX_STAGE_LENGTH && /^[a-z0-9][a-z0-9_-]*$/i.test(stage),\n ) &&\n new Set(value).size === value.length\n );\n}\n\nfunction validMetadata(value: unknown): value is Record<string, unknown> | null {\n if (value === null) return true;\n if (!isRecord(value)) return false;\n try {\n return JSON.stringify(value).length <= MAX_METADATA_BYTES;\n } catch {\n return false;\n }\n}\n\nfunction parseExternalSource(value: unknown): ExternalWorkItemSource | null | undefined {\n if (value === undefined || value === null) return value;\n if (!isRecord(value)) return undefined;\n const { integrationId, type, externalId, url } = value;\n if (typeof integrationId !== 'string' || integrationId.length === 0 || integrationId.length > 128) return undefined;\n if (typeof type !== 'string' || type.length === 0 || type.length > 128) return undefined;\n if (typeof externalId !== 'string' || externalId.length === 0 || externalId.length > 512) return undefined;\n if (url !== undefined && (typeof url !== 'string' || url.length > 2048)) return undefined;\n return { integrationId, type, externalId, ...(url !== undefined ? { url } : {}) };\n}\n\nfunction parseParentWorkItemId(value: unknown): string | null | undefined {\n if (value === null) return null;\n if (typeof value !== 'string' || !UUID_RE.test(value)) return undefined;\n return value;\n}\n\nfunction parseSessions(value: unknown): Record<string, WorkItemSessionInput> | undefined {\n if (!isRecord(value)) return undefined;\n const out: Record<string, WorkItemSessionInput> = {};\n for (const [role, session] of Object.entries(value)) {\n if (!role || role.length > 64 || !isRecord(session)) return undefined;\n const { sessionId, branch, threadId } = session;\n if (typeof sessionId !== 'string' || sessionId.length === 0 || sessionId.length > 512) return undefined;\n if (typeof branch !== 'string' || branch.length === 0 || branch.length > 512) return undefined;\n if (typeof threadId !== 'string' || threadId.length === 0 || threadId.length > 512) return undefined;\n out[role] = { sessionId, branch, threadId };\n }\n return out;\n}\n\n/** Validate an untrusted create body. Unknown keys are dropped. */\nexport function parseCreateWorkItem(body: unknown): CreateWorkItemInput | null {\n if (!isRecord(body)) return null;\n const { externalSource, title, stages, sessions, metadata } = body;\n if (typeof title !== 'string' || title.trim().length === 0 || title.length > 500) return null;\n\n const hasParentWorkItemId = 'parentWorkItemId' in body;\n const parentWorkItemId = hasParentWorkItemId ? parseParentWorkItemId(body.parentWorkItemId) : undefined;\n if (hasParentWorkItemId && parentWorkItemId === undefined) return null;\n const parsedSource = parseExternalSource(externalSource);\n if (externalSource !== undefined && parsedSource === undefined) return null;\n if (stages !== undefined && !validStages(stages)) return null;\n const parsedSessions = sessions === undefined ? undefined : parseSessions(sessions);\n if (sessions !== undefined && parsedSessions === undefined) return null;\n if (metadata !== undefined && !validMetadata(metadata)) return null;\n\n return {\n title: title.trim(),\n ...(parsedSource !== undefined ? { externalSource: parsedSource } : {}),\n ...(hasParentWorkItemId ? { parentWorkItemId: parentWorkItemId ?? null } : {}),\n ...(stages !== undefined ? { stages } : {}),\n ...(parsedSessions !== undefined ? { sessions: parsedSessions } : {}),\n ...(metadata !== undefined ? { metadata } : {}),\n };\n}\n\n/** Validate an untrusted patch body. Unknown keys are dropped. */\nexport function parseUpdateWorkItem(body: unknown): UpdateWorkItemInput | null {\n if (!isRecord(body)) return null;\n const { title, stages, sessions, metadata } = body;\n const hasParentWorkItemId = 'parentWorkItemId' in body;\n if (\n title === undefined &&\n stages === undefined &&\n sessions === undefined &&\n metadata === undefined &&\n !hasParentWorkItemId\n )\n return null;\n const parentWorkItemId = hasParentWorkItemId ? parseParentWorkItemId(body.parentWorkItemId) : undefined;\n if (hasParentWorkItemId && parentWorkItemId === undefined) return null;\n if (title !== undefined && (typeof title !== 'string' || title.trim().length === 0 || title.length > 500))\n return null;\n if (stages !== undefined && !validStages(stages)) return null;\n const parsedSessions = sessions === undefined ? undefined : parseSessions(sessions);\n if (sessions !== undefined && parsedSessions === undefined) return null;\n if (metadata !== undefined && !validMetadata(metadata)) return null;\n\n return {\n ...(hasParentWorkItemId ? { parentWorkItemId: parentWorkItemId ?? null } : {}),\n ...(title !== undefined ? { title: title.trim() } : {}),\n ...(stages !== undefined ? { stages } : {}),\n ...(parsedSessions !== undefined ? { sessions: parsedSessions } : {}),\n ...(metadata !== undefined ? { metadata } : {}),\n };\n}\n\nasync function readJson(c: Context): Promise<unknown | undefined> {\n try {\n return await c.req.json();\n } catch {\n return undefined;\n }\n}\n\n/** Fields a PATCH touched, for the bounded `updated` event summary. */\nfunction patchedFields(patch: Record<string, unknown>): string[] {\n return Object.keys(patch).filter(key => patch[key] !== undefined);\n}\n\nfunction boundedText(value: unknown, max: number): string | undefined {\n if (typeof value !== 'string') return undefined;\n const normalized = value.trim();\n return normalized.length > 0 && normalized.length <= max ? normalized : undefined;\n}\n\nfunction parseTransitionBody(\n body: unknown,\n): Omit<FactoryTransitionRequest, 'orgId' | 'factoryProjectId' | 'workItemId' | 'actor'> | null {\n if (!isRecord(body)) return null;\n const board = FACTORY_RULE_BOARDS.includes(body.board as FactoryRuleBoard)\n ? (body.board as FactoryRuleBoard)\n : undefined;\n const stage = isFactoryRuleStage(body.stage) ? body.stage : undefined;\n const requestId = boundedText(body.requestId, 256);\n const cause = boundedText(body.cause, 256);\n if (\n !board ||\n !stage ||\n !requestId ||\n !UUID_RE.test(requestId) ||\n !cause ||\n !Number.isInteger(body.expectedRevision) ||\n Number(body.expectedRevision) < 1\n ) {\n return null;\n }\n return {\n board,\n stage,\n expectedRevision: Number(body.expectedRevision),\n ingress: { type: 'human', identity: requestId },\n cause,\n };\n}\n\nfunction parseInvocation(value: unknown): FactoryStartRequest['invocation'] | undefined | null {\n if (value === undefined) return undefined;\n if (!isRecord(value)) return null;\n if (value.type === 'prompt') {\n const prompt = boundedText(value.prompt, 16_384);\n return prompt ? { type: 'prompt', prompt } : null;\n }\n if (value.type === 'skill') {\n const skillName = boundedText(value.skillName, 64);\n const args = typeof value.arguments === 'string' && value.arguments.length <= 16_384 ? value.arguments : undefined;\n return skillName && args !== undefined ? { type: 'skill', skillName, arguments: args } : null;\n }\n return null;\n}\n\nfunction parseStartBody(\n body: unknown,\n tenant: { orgId: string; userId: string },\n factoryProjectId: string,\n): FactoryStartRequest | null {\n if (!isRecord(body) || !isRecord(body.workItem)) return null;\n const input = parseCreateWorkItem(body.workItem.input);\n const sessionId = boundedText(body.sessionId, 256);\n const threadTitle = boundedText(body.threadTitle, 512);\n const kickoffKey = boundedText(body.kickoffKey, 256);\n const invocation = parseInvocation(body.invocation);\n const destinationStage = isFactoryRuleStage(body.destinationStage) ? body.destinationStage : undefined;\n const role = boundedText(body.workItem.role, 32);\n const id = body.workItem.id === undefined ? undefined : boundedText(body.workItem.id, 64);\n if (body.workItem.id !== undefined && (!id || !UUID_RE.test(id))) return null;\n if (\n !input ||\n !sessionId ||\n !UUID_RE.test(sessionId) ||\n !threadTitle ||\n !kickoffKey ||\n !UUID_RE.test(kickoffKey) ||\n invocation === null ||\n !destinationStage ||\n !role\n ) {\n return null;\n }\n const threadTags = isRecord(body.threadTags)\n ? Object.fromEntries(\n Object.entries(body.threadTags)\n .filter(\n (entry): entry is [string, string] =>\n boundedText(entry[0], 64) !== undefined && boundedText(entry[1], 256) !== undefined,\n )\n .map(([key, value]) => [key, value.trim()]),\n )\n : undefined;\n return {\n ...tenant,\n factoryProjectId,\n sessionId,\n threadTitle,\n threadTags,\n kickoffKey,\n invocation,\n destinationStage,\n workItem: { id, role, input },\n };\n}\n\nconst DECISION_STATUSES = new Set<FactoryDispatchStatus>([\n 'pending',\n 'proposed',\n 'dismissed',\n 'leased',\n 'retry',\n 'succeeded',\n 'failed',\n]);\nconst DEFAULT_DECISION_PAGE_SIZE = 25;\nconst MAX_DECISION_PAGE_SIZE = 50;\n\nfunction parseDecisionStatuses(raw: string | undefined): FactoryDispatchStatus[] | undefined {\n if (!raw) return undefined;\n const statuses = [...new Set(raw.split(',').map(status => status.trim()))].filter(\n (status): status is FactoryDispatchStatus => DECISION_STATUSES.has(status as FactoryDispatchStatus),\n );\n return statuses.length > 0 ? statuses : undefined;\n}\n\nfunction parseDecisionLimit(raw: string | undefined): number {\n const parsed = raw ? Number.parseInt(raw, 10) : DEFAULT_DECISION_PAGE_SIZE;\n if (!Number.isFinite(parsed)) return DEFAULT_DECISION_PAGE_SIZE;\n return Math.max(1, Math.min(MAX_DECISION_PAGE_SIZE, parsed));\n}\n\nfunction encodeDecisionCursor(decision: FactoryDeferredDecisionRecord): string {\n return Buffer.from(JSON.stringify([decision.createdAt.toISOString(), decision.id]), 'utf8').toString('base64url');\n}\n\nfunction parseDecisionCursor(raw: string | undefined): { createdAt: Date; id: string } | undefined {\n if (!raw) return undefined;\n try {\n const decoded = JSON.parse(Buffer.from(raw, 'base64url').toString('utf8')) as unknown;\n if (\n !Array.isArray(decoded) ||\n decoded.length !== 2 ||\n typeof decoded[0] !== 'string' ||\n typeof decoded[1] !== 'string'\n ) {\n return undefined;\n }\n const createdAt = new Date(decoded[0]);\n if (Number.isNaN(createdAt.getTime()) || !UUID_RE.test(decoded[1])) return undefined;\n return { createdAt, id: decoded[1] };\n } catch {\n return undefined;\n }\n}\n\nfunction decisionType(decision: FactoryDeferredDecisionRecord): string {\n return typeof decision.decision.type === 'string' ? decision.decision.type.slice(0, 64) : 'unknown';\n}\n\nfunction decisionSummary(decision: FactoryDeferredDecisionRecord) {\n return {\n id: decision.id,\n evaluationId: decision.evaluationId,\n workItemId: decision.workItemId,\n type: decisionType(decision),\n role: typeof decision.decision.role === 'string' ? decision.decision.role.slice(0, 32) : null,\n status: decision.status,\n attempts: decision.attempts,\n lastError: decision.lastError?.slice(0, 512) ?? null,\n createdAt: decision.createdAt.toISOString(),\n updatedAt: decision.updatedAt.toISOString(),\n completedAt: decision.completedAt?.toISOString() ?? null,\n };\n}\n\nexport class WorkItemRoutes extends Route<WorkItemRoutesDeps> {\n /** Resolve the `(orgId, userId)` tenant or a ready-to-return error response. */\n async #resolveTenant(c: Context): Promise<{ orgId: string; userId: string } | { response: Response }> {\n await this.deps.auth.ensureUser(c);\n const tenant = this.deps.auth.tenant(c);\n if (!tenant) return { response: c.json({ error: 'unauthorized' }, 401) };\n if (!tenant.orgId) {\n return {\n response: c.json(\n { error: 'organization_required', message: 'The Factory board requires an organization.' },\n 403,\n ),\n };\n }\n return { orgId: tenant.orgId, userId: tenant.userId };\n }\n\n /**\n * Resolve the tenant AND the org-owned project from the `:id` param. Work\n * items hang off a project, so listing/creating requires the project to\n * exist in the caller's org.\n */\n async #resolveProject(\n c: Context,\n ): Promise<\n { orgId: string; userId: string; factoryProjectId: string; defaultModelId: string | null } | { response: Response }\n > {\n const tenant = await this.#resolveTenant(c);\n if ('response' in tenant) return tenant;\n\n const projectId = c.req.param('id');\n if (!projectId || !UUID_RE.test(projectId)) {\n return { response: c.json({ error: 'Project not found' }, 404) };\n }\n const { projects } = this.deps;\n await projects.ensureReady();\n const project = await projects.get({ orgId: tenant.orgId, id: projectId });\n if (!project) {\n return { response: c.json({ error: 'Project not found' }, 404) };\n }\n return { ...tenant, factoryProjectId: projectId, defaultModelId: project.defaultModelId };\n }\n\n /**\n * Emit the audit events a successful work-item PATCH implies: always\n * `updated`, plus `stage_moved` when the stages actually changed and one\n * `run.started` per session role the patch introduced.\n */\n async #auditWorkItemPatch({\n context,\n item,\n previous,\n patch,\n }: {\n context: Context;\n item: WorkItemRow;\n previous: WorkItemPriorState;\n patch: Record<string, unknown>;\n }): Promise<void> {\n const { audit } = this.deps;\n const target = { type: 'work_item', id: item.id, name: item.title };\n await audit.emit({\n context,\n input: {\n action: 'factory.work_item.updated',\n factoryProjectId: item.factoryProjectId,\n targets: [target],\n metadata: { fields: patchedFields(patch) },\n },\n });\n\n const stagesChanged =\n patch.stages !== undefined &&\n (previous.stages.length !== item.stages.length || previous.stages.some((s, i) => s !== item.stages[i]));\n if (stagesChanged) {\n await audit.emit({\n context,\n input: {\n action: 'factory.work_item.stage_moved',\n factoryProjectId: item.factoryProjectId,\n targets: [target],\n metadata: { from: previous.stages, to: item.stages },\n },\n });\n }\n\n const newRoles = Object.keys(item.sessions).filter(role => !previous.sessionRoles.includes(role));\n for (const role of newRoles) {\n const session = item.sessions[role];\n await audit.emit({\n context,\n input: {\n action: 'factory.run.started',\n factoryProjectId: item.factoryProjectId,\n targets: [target],\n metadata: {\n role,\n branch: session?.branch,\n threadId: session?.threadId,\n sessionId: session?.sessionId,\n },\n },\n });\n }\n }\n\n /** Releasing a parked run and dropping it: same request, opposite outcomes, both audited as consent. */\n #proposalRoute({\n verb,\n settle,\n }: {\n verb: 'approve' | 'dismiss';\n settle: (\n orgId: string,\n factoryProjectId: string,\n decisionId: string,\n now: Date,\n ) => Promise<FactoryDeferredDecisionRecord | null>;\n }): ApiRoute {\n const { audit, workItems } = this.deps;\n return registerApiRoute(`/web/factory/projects/:id/decisions/:decisionId/${verb}`, {\n method: 'POST',\n requiresAuth: false,\n handler: async c => {\n const context = loose(c);\n const resolved = await this.#resolveProject(context);\n if ('response' in resolved) return resolved.response;\n const decisionId = context.req.param('decisionId');\n if (!decisionId || !UUID_RE.test(decisionId)) return c.json({ error: 'invalid_decision_id' }, 422);\n await workItems.ensureReady();\n const now = new Date();\n const decision = await settle(resolved.orgId, resolved.factoryProjectId, decisionId, now);\n if (!decision) return c.json({ error: 'decision_not_proposed' }, 409);\n // Releasing a proposal is a person taking the item on. Approval arms the\n // item's autonomy inside the same storage transaction (see\n // approveDeferredDecision), so follow-up runs no longer wait for approval.\n await audit.emit({\n context,\n input: {\n action: verb === 'approve' ? 'factory.run.approved' : 'factory.run.dismissed',\n factoryProjectId: resolved.factoryProjectId,\n targets: decision.workItemId\n ? [{ type: 'work_item', id: decision.workItemId }]\n : [{ type: 'rule_decision', id: decision.id }],\n metadata: { decisionId: decision.id, effect: decisionType(decision) },\n },\n });\n return c.json({ decision: decisionSummary(decision) });\n },\n });\n }\n\n /** Build the Factory work-item routes as Mastra `apiRoutes`. */\n routes(): ApiRoute[] {\n const { audit, workItems, queueHealth, transitionService, startCoordinator, liveSessions } = this.deps;\n return [\n // ── List the org's work items for a project, and which are being worked ─\n registerApiRoute('/web/factory/projects/:id/work-items', {\n method: 'GET',\n requiresAuth: false,\n handler: async c => {\n const resolved = await this.#resolveProject(loose(c));\n if ('response' in resolved) return resolved.response;\n await workItems.ensureReady();\n const items = await workItems.list({\n orgId: resolved.orgId,\n factoryProjectId: resolved.factoryProjectId,\n });\n return c.json({\n workItems: items.map(toWireWorkItem),\n runningSessionIds: runningSessionIds(items, liveSessions),\n });\n },\n }),\n\n // ── Flow metrics aggregated over the project's work items ───────────────\n registerApiRoute('/web/factory/projects/:id/metrics', {\n method: 'GET',\n requiresAuth: false,\n handler: async c => {\n const resolved = await this.#resolveProject(loose(c));\n if ('response' in resolved) return resolved.response;\n const { windowStart, windowEnd } = parseMetricsRange(\n loose(c).req.query('from'),\n loose(c).req.query('to'),\n new Date(),\n );\n await workItems.ensureReady();\n const items = await workItems.list({\n orgId: resolved.orgId,\n factoryProjectId: resolved.factoryProjectId,\n });\n return c.json({ metrics: computeFactoryMetrics(items, { windowStart, windowEnd }) });\n },\n }),\n\n // ── Per-project queue-health age-threshold config (seconds) ─────────────\n registerApiRoute('/web/factory/projects/:id/health/thresholds', {\n method: 'GET',\n requiresAuth: false,\n handler: async c => {\n const resolved = await this.#resolveProject(loose(c));\n if ('response' in resolved) return resolved.response;\n await queueHealth.ensureReady();\n const stored = await queueHealth.getConfig(resolved.orgId, resolved.factoryProjectId);\n // Validate at the read choke point: `getConfig` round-trips a stored\n // JSONB row, and only `saveConfig` validates on write — a corrupted or\n // hand-edited row (empty / non-ascending) would otherwise flow to the\n // chart and invert bucket colors. Fall back to the default on invalid.\n return c.json({ thresholds: thresholdsOrDefault(stored) });\n },\n }),\n\n // ── Bounded durable rule-decision status ────────────────────────────────\n registerApiRoute('/web/factory/projects/:id/decisions', {\n method: 'GET',\n requiresAuth: false,\n handler: async c => {\n const context = loose(c);\n const resolved = await this.#resolveProject(context);\n if ('response' in resolved) return resolved.response;\n\n const cursorRaw = context.req.query('before');\n const before = parseDecisionCursor(cursorRaw);\n if (cursorRaw && !before) return c.json({ error: 'invalid_cursor' }, 400);\n await workItems.ensureReady();\n const page = await workItems.listDeferredDecisionPage({\n orgId: resolved.orgId,\n factoryProjectId: resolved.factoryProjectId,\n statuses: parseDecisionStatuses(context.req.query('statuses')),\n before,\n limit: parseDecisionLimit(context.req.query('limit')),\n });\n const last = page.decisions.at(-1);\n return c.json({\n decisions: page.decisions.map(decisionSummary),\n ...(page.hasMore && last ? { nextCursor: encodeDecisionCursor(last) } : {}),\n });\n },\n }),\n\n this.#proposalRoute({ verb: 'approve', settle: workItems.approveDeferredDecision.bind(workItems) }),\n this.#proposalRoute({ verb: 'dismiss', settle: workItems.dismissDeferredDecision.bind(workItems) }),\n\n registerApiRoute('/web/factory/projects/:id/decisions/:decisionId/retry', {\n method: 'POST',\n requiresAuth: false,\n handler: async c => {\n const context = loose(c);\n const resolved = await this.#resolveProject(context);\n if ('response' in resolved) return resolved.response;\n const decisionId = context.req.param('decisionId');\n if (!decisionId || !UUID_RE.test(decisionId)) return c.json({ error: 'invalid_decision_id' }, 422);\n await workItems.ensureReady();\n const decision = await workItems.retryDeferredDecision(\n resolved.orgId,\n resolved.factoryProjectId,\n decisionId,\n new Date(),\n );\n if (!decision) return c.json({ error: 'decision_not_retryable' }, 409);\n return c.json({ decision: decisionSummary(decision) });\n },\n }),\n\n // ── Create (upsert on sourceKey) a work item ─────────────────────────────\n registerApiRoute('/web/factory/projects/:id/work-items', {\n method: 'POST',\n requiresAuth: false,\n handler: async c => {\n const resolved = await this.#resolveProject(loose(c));\n if ('response' in resolved) return resolved.response;\n\n const body = await readJson(loose(c));\n if (body === undefined) return c.json({ error: 'Invalid JSON body' }, 400);\n const input = parseCreateWorkItem(body);\n if (!input) return c.json({ error: 'invalid_work_item' }, 400);\n if ((input.stages ?? ['intake']).length !== 1 || (input.stages ?? ['intake'])[0] !== 'intake') {\n return c.json(\n { error: 'governed_transition_required', message: 'New work items must enter through Factory intake.' },\n 409,\n );\n }\n\n await workItems.ensureReady();\n try {\n const result = await workItems.upsert({\n orgId: resolved.orgId,\n userId: resolved.userId,\n factoryProjectId: resolved.factoryProjectId,\n input,\n reuseMode: 'non-stage',\n });\n let item = result.item;\n if (result.created) {\n if (!transitionService) {\n await workItems.delete({ orgId: resolved.orgId, id: item.id });\n return c.json({ error: 'factory_transitions_unavailable' }, 503);\n }\n const entered = await transitionService.transition({\n orgId: resolved.orgId,\n factoryProjectId: resolved.factoryProjectId,\n workItemId: item.id,\n board: item.externalSource?.type === 'pull-request' ? 'review' : 'work',\n stage: 'intake',\n expectedRevision: item.revision,\n actor: { type: 'human', id: resolved.userId },\n ingress: { type: 'human', identity: `work-item:${item.id}:initial-entry` },\n cause: 'work_item_created',\n initialEntry: true,\n });\n if (entered.status === 'rejected') {\n await workItems.delete({ orgId: resolved.orgId, id: item.id });\n return c.json({ status: 'rejected', code: entered.code, reason: entered.reason }, 422);\n }\n item = (await workItems.getForProject(resolved.orgId, resolved.factoryProjectId, item.id)) ?? item;\n await audit.emit({\n context: loose(c),\n input: {\n action: 'factory.work_item.created',\n factoryProjectId: resolved.factoryProjectId,\n targets: [{ type: 'work_item', id: item.id, name: item.title }],\n metadata: { externalSource: item.externalSource, stages: item.stages },\n },\n });\n } else {\n // Source-key reuse: the POST updated an existing card, so audit it\n // as an update (plus stage/run events) instead of a false creation.\n const { stages: _stages, sessions: _sessions, ...boundedPatch } = input;\n await this.#auditWorkItemPatch({\n context: loose(c),\n item,\n previous: result.previous,\n patch: boundedPatch as unknown as Record<string, unknown>,\n });\n }\n return c.json({ workItem: toWireWorkItem(item) });\n } catch (error) {\n if (error instanceof WorkItemRelationError) {\n return c.json({ error: error.code, message: error.message }, 400);\n }\n throw error;\n }\n },\n }),\n\n // ── Authoritative stage transition ──────────────────────────────────────\n registerApiRoute('/web/factory/projects/:id/work-items/:workItemId/transition', {\n method: 'POST',\n requiresAuth: false,\n handler: async c => {\n const resolved = await this.#resolveProject(loose(c));\n if ('response' in resolved) return resolved.response;\n const workItemId = loose(c).req.param('workItemId');\n if (!workItemId || !UUID_RE.test(workItemId)) return c.json({ error: 'Work item not found' }, 404);\n const parsed = parseTransitionBody(await readJson(loose(c)));\n if (!parsed) return c.json({ error: 'invalid_transition_request' }, 400);\n if (!transitionService) {\n return c.json({ error: 'factory_transition_unavailable' }, 503);\n }\n await workItems.ensureReady();\n const result = await transitionService.transition({\n ...parsed,\n orgId: resolved.orgId,\n factoryProjectId: resolved.factoryProjectId,\n workItemId,\n actor: { type: 'human', id: resolved.userId },\n ingress: {\n ...parsed.ingress,\n identity: `human:${resolved.userId}:${parsed.ingress.identity}`,\n },\n });\n await audit.emit({\n context: loose(c),\n input: {\n action:\n result.status === 'accepted'\n ? 'factory.work_item.stage_moved'\n : 'factory.work_item.transition_rejected',\n factoryProjectId: resolved.factoryProjectId,\n targets: [{ type: 'work_item', id: workItemId }],\n metadata: {\n transitionId: result.transitionId,\n ingressType: parsed.ingress.type,\n ruleSetVersion: transitionService.ruleSetVersion,\n ...(result.status === 'accepted'\n ? { to: result.stage, revision: result.revision }\n : { code: result.code, reason: result.reason }),\n },\n },\n });\n if (result.status === 'accepted') return c.json({ result });\n return c.json({ result }, result.code === 'stale' ? 409 : 422);\n },\n }),\n\n // ── Bind a Factory run before dispatching its kickoff ────────────────────\n registerApiRoute('/web/factory/projects/:id/runs/start', {\n method: 'POST',\n requiresAuth: false,\n handler: async c => {\n const resolved = await this.#resolveProject(loose(c));\n if ('response' in resolved) return resolved.response;\n if (!startCoordinator) {\n return c.json({ error: 'factory_start_unavailable' }, 503);\n }\n const input = parseStartBody(await readJson(loose(c)), resolved, resolved.factoryProjectId);\n if (!input) return c.json({ error: 'invalid_factory_start' }, 400);\n input.requestContext = loose(c).get('requestContext');\n input.defaultModelId = resolved.defaultModelId ?? undefined;\n // This route is only reached by a person pressing a run action, so\n // reaching it is the commitment the approval gate is asking for.\n // Arming rides inside prepareRunStart's transaction so a crash can't\n // start the run while leaving its follow-up work waiting on approval.\n input.armAutonomy = true;\n if (\n !input.workItem.id &&\n ((input.workItem.input.stages ?? ['intake']).length !== 1 ||\n (input.workItem.input.stages ?? ['intake'])[0] !== 'intake')\n ) {\n return c.json(\n { error: 'governed_transition_required', message: 'Create the work item in Intake before starting it.' },\n 409,\n );\n }\n await workItems.ensureReady();\n let prepared: FactoryStartPreparedResult;\n try {\n prepared = await startCoordinator.prepare(input);\n } catch (error) {\n if (error instanceof FactoryStartTransitionError) {\n return c.json({ result: error.result }, error.result.code === 'stale' ? 409 : 422);\n }\n throw error;\n }\n await audit.emit({\n context: loose(c),\n input: {\n action: 'factory.run.started',\n factoryProjectId: resolved.factoryProjectId,\n targets: [{ type: 'work_item', id: prepared.workItemId }],\n metadata: {\n role: input.workItem.role,\n branch: prepared.branch,\n threadId: prepared.threadId,\n sessionId: prepared.sessionId,\n bindingId: prepared.bindingId,\n },\n },\n });\n return c.json({ prepared }, 202);\n },\n }),\n\n // ── Patch non-stage metadata / sessions / title ──────────────────────────\n registerApiRoute('/web/factory/work-items/:id', {\n method: 'PATCH',\n requiresAuth: false,\n handler: async c => {\n const tenant = await this.#resolveTenant(loose(c));\n if ('response' in tenant) return tenant.response;\n\n const id = loose(c).req.param('id');\n if (!id || !UUID_RE.test(id)) return c.json({ error: 'Work item not found' }, 404);\n\n const body = await readJson(loose(c));\n if (body === undefined) return c.json({ error: 'Invalid JSON body' }, 400);\n const patch = parseUpdateWorkItem(body);\n if (!patch) return c.json({ error: 'invalid_work_item_patch' }, 400);\n if (patch.stages !== undefined) {\n return c.json(\n { error: 'governed_transition_required', message: 'Use the Factory transition endpoint to move stages.' },\n 409,\n );\n }\n\n await workItems.ensureReady();\n try {\n const updated = await workItems.update({ orgId: tenant.orgId, id, userId: tenant.userId, patch });\n if (!updated) return c.json({ error: 'Work item not found' }, 404);\n await this.#auditWorkItemPatch({\n context: loose(c),\n item: updated.item,\n previous: updated.previous,\n patch: patch as Record<string, unknown>,\n });\n return c.json({ workItem: toWireWorkItem(updated.item) });\n } catch (error) {\n if (error instanceof WorkItemRelationError) {\n return c.json({ error: error.code, message: error.message }, 400);\n }\n throw error;\n }\n },\n }),\n\n // ── Remove a work item ───────────────────────────────────────────────────\n registerApiRoute('/web/factory/work-items/:id', {\n method: 'DELETE',\n requiresAuth: false,\n handler: async c => {\n const tenant = await this.#resolveTenant(loose(c));\n if ('response' in tenant) return tenant.response;\n\n const id = loose(c).req.param('id');\n if (!id || !UUID_RE.test(id)) return c.json({ error: 'Work item not found' }, 404);\n\n await workItems.ensureReady();\n const deleted = await workItems.delete({ orgId: tenant.orgId, id });\n if (!deleted) return c.json({ error: 'Work item not found' }, 404);\n await audit.emit({\n context: loose(c),\n input: {\n action: 'factory.work_item.deleted',\n factoryProjectId: deleted.factoryProjectId,\n targets: [{ type: 'work_item', id: deleted.id, name: deleted.title }],\n },\n });\n return c.json({ ok: true });\n },\n }),\n ];\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"work-items.js","names":["#resolveTenant","#resolveProject","#auditWorkItemPatch","#proposalRoute"],"sources":["../../src/routes/work-items.ts"],"sourcesContent":["/**\n * Mastra `apiRoutes` for Factory work items (the kanban board).\n *\n * Registered alongside the other `/web/*` routes behind the host auth gate.\n * The board is org-wide: every route re-resolves the caller's `(orgId, userId)`\n * tenant and scopes reads/writes by `orgId`, so any org member sees and moves\n * the same cards while `created_by` / stage history record who acted.\n */\n\nimport type { ApiRoute } from '@mastra/core/server';\nimport { registerApiRoute } from '@mastra/core/server';\nimport type { Context } from 'hono';\n\nimport { factoryDispatchFailureMetadata } from '../rules/dispatch-errors.js';\nimport type {\n FactoryStartCoordinator,\n FactoryStartPreparedResult,\n FactoryStartRequest,\n} from '../rules/start-coordinator.js';\nimport { FactoryStartTransitionError } from '../rules/start-coordinator.js';\nimport type { FactoryTransitionRequest, FactoryTransitionService } from '../rules/transition-service.js';\nimport type { FactoryRuleBoard } from '../rules/types.js';\nimport { FACTORY_RULE_BOARDS, isFactoryRuleStage } from '../rules/types.js';\nimport type { LiveSessions } from '../session/live-sessions.js';\nimport type { AuditEmitter } from '../storage/domains/audit/domain.js';\nimport type { FactoryProjectsStorage } from '../storage/domains/projects/base.js';\nimport type { QueueHealthStorage } from '../storage/domains/queue-health/base.js';\nimport { thresholdsOrDefault } from '../storage/domains/queue-health/base.js';\nimport type {\n CreateWorkItemInput,\n ExternalWorkItemSource,\n FactoryDeferredDecisionRecord,\n FactoryDispatchStatus,\n UpdateWorkItemInput,\n WorkItemPriorState,\n WorkItemRow,\n WorkItemSessionInput,\n WorkItemStage,\n WorkItemsStorage,\n} from '../storage/domains/work-items/base.js';\nimport {\n FACTORY_PULL_REQUEST_RECONCILIATION_KEY,\n FACTORY_RULE_MATERIALIZATION_KEY,\n WorkItemRelationError,\n} from '../storage/domains/work-items/base.js';\nimport { computeFactoryMetrics, parseMetricsRange } from '../storage/domains/work-items/metrics.js';\nimport { buildAttentionRoutes, factoryDecisionType } from './attention.js';\nimport type { RouteDependencies } from './route.js';\nimport { Route } from './route.js';\n\nexport interface WorkItemRoutesDeps extends RouteDependencies {\n audit: AuditEmitter;\n /** Factory projects domain — validates the `:id` project belongs to the caller's org. */\n projects: FactoryProjectsStorage;\n /** Work-items domain backing the kanban board. */\n workItems: WorkItemsStorage;\n /** Per-project queue-health threshold config. */\n queueHealth: QueueHealthStorage;\n /** Governed stage-transition service. Stage moves 503 when absent. */\n transitionService?: Pick<FactoryTransitionService, 'transition' | 'ruleSetVersion'>;\n /** Coordinator that binds a Factory run before dispatching its kickoff. */\n startCoordinator?: Pick<FactoryStartCoordinator, 'prepare'>;\n /** Materialized sessions, read to report which of the listed cards are being worked. */\n liveSessions: Pick<LiveSessions, 'isRunning'>;\n}\n\n/** The card as clients see it, without the dispatcher's internal bookkeeping. */\nfunction toWireWorkItem(item: WorkItemRow): WorkItemRow {\n if (\n !item.metadata ||\n (!(FACTORY_RULE_MATERIALIZATION_KEY in item.metadata) &&\n !(FACTORY_PULL_REQUEST_RECONCILIATION_KEY in item.metadata))\n ) {\n return item;\n }\n return { ...item, metadata: publicWorkItemMetadata(item.metadata) ?? {} };\n}\n\n/** Session ids of the listed cards whose agent run is in flight. */\nfunction runningSessionIds(items: WorkItemRow[], liveSessions: Pick<LiveSessions, 'isRunning'>): string[] {\n const running = new Set<string>();\n for (const item of items) {\n for (const { sessionId } of Object.values(item.sessions)) {\n if (liveSessions.isRunning(sessionId)) running.add(sessionId);\n }\n }\n return [...running];\n}\n\nfunction loose(c: unknown): Context {\n return c as Context;\n}\n\nconst UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;\n\nconst MAX_STAGES = 16;\nconst MAX_STAGE_LENGTH = 64;\nconst MAX_METADATA_BYTES = 16 * 1024;\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction validStages(value: unknown): value is WorkItemStage[] {\n return (\n Array.isArray(value) &&\n value.length > 0 &&\n value.length <= MAX_STAGES &&\n value.every(\n stage => typeof stage === 'string' && stage.length <= MAX_STAGE_LENGTH && /^[a-z0-9][a-z0-9_-]*$/i.test(stage),\n ) &&\n new Set(value).size === value.length\n );\n}\n\nfunction validMetadata(value: unknown): value is Record<string, unknown> | null {\n if (value === null) return true;\n if (!isRecord(value)) return false;\n try {\n return JSON.stringify(value).length <= MAX_METADATA_BYTES;\n } catch {\n return false;\n }\n}\n\nfunction publicWorkItemMetadata(value: Record<string, unknown> | null): Record<string, unknown> | null {\n if (value === null) return null;\n const {\n [FACTORY_RULE_MATERIALIZATION_KEY]: _materialization,\n [FACTORY_PULL_REQUEST_RECONCILIATION_KEY]: _reconciliation,\n ...metadata\n } = value;\n return metadata;\n}\n\nfunction parseExternalSource(value: unknown): ExternalWorkItemSource | null | undefined {\n if (value === undefined || value === null) return value;\n if (!isRecord(value)) return undefined;\n const { integrationId, type, externalId, url } = value;\n if (typeof integrationId !== 'string' || integrationId.length === 0 || integrationId.length > 128) return undefined;\n if (typeof type !== 'string' || type.length === 0 || type.length > 128) return undefined;\n if (typeof externalId !== 'string' || externalId.length === 0 || externalId.length > 512) return undefined;\n if (url !== undefined && (typeof url !== 'string' || url.length > 2048)) return undefined;\n return { integrationId, type, externalId, ...(url !== undefined ? { url } : {}) };\n}\n\nfunction parseParentWorkItemId(value: unknown): string | null | undefined {\n if (value === null) return null;\n if (typeof value !== 'string' || !UUID_RE.test(value)) return undefined;\n return value;\n}\n\nfunction parseSessions(value: unknown): Record<string, WorkItemSessionInput> | undefined {\n if (!isRecord(value)) return undefined;\n const out: Record<string, WorkItemSessionInput> = {};\n for (const [role, session] of Object.entries(value)) {\n if (!role || role.length > 64 || !isRecord(session)) return undefined;\n const { sessionId, branch, threadId } = session;\n if (typeof sessionId !== 'string' || sessionId.length === 0 || sessionId.length > 512) return undefined;\n if (typeof branch !== 'string' || branch.length === 0 || branch.length > 512) return undefined;\n if (typeof threadId !== 'string' || threadId.length === 0 || threadId.length > 512) return undefined;\n out[role] = { sessionId, branch, threadId };\n }\n return out;\n}\n\n/** Validate an untrusted create body. Unknown keys are dropped. */\nexport function parseCreateWorkItem(body: unknown): CreateWorkItemInput | null {\n if (!isRecord(body)) return null;\n const { externalSource, title, stages, sessions, metadata } = body;\n if (typeof title !== 'string' || title.trim().length === 0 || title.length > 500) return null;\n\n const hasParentWorkItemId = 'parentWorkItemId' in body;\n const parentWorkItemId = hasParentWorkItemId ? parseParentWorkItemId(body.parentWorkItemId) : undefined;\n if (hasParentWorkItemId && parentWorkItemId === undefined) return null;\n const parsedSource = parseExternalSource(externalSource);\n if (externalSource !== undefined && parsedSource === undefined) return null;\n if (stages !== undefined && !validStages(stages)) return null;\n const parsedSessions = sessions === undefined ? undefined : parseSessions(sessions);\n if (sessions !== undefined && parsedSessions === undefined) return null;\n let parsedMetadata: Record<string, unknown> | null | undefined;\n if (metadata !== undefined) {\n if (!validMetadata(metadata)) return null;\n parsedMetadata = publicWorkItemMetadata(metadata);\n }\n\n return {\n title: title.trim(),\n ...(parsedSource !== undefined ? { externalSource: parsedSource } : {}),\n ...(hasParentWorkItemId ? { parentWorkItemId: parentWorkItemId ?? null } : {}),\n ...(stages !== undefined ? { stages } : {}),\n ...(parsedSessions !== undefined ? { sessions: parsedSessions } : {}),\n ...(parsedMetadata !== undefined ? { metadata: parsedMetadata } : {}),\n };\n}\n\n/** Validate an untrusted patch body. Unknown keys are dropped. */\nexport function parseUpdateWorkItem(body: unknown): UpdateWorkItemInput | null {\n if (!isRecord(body)) return null;\n const { title, stages, sessions, metadata } = body;\n const hasParentWorkItemId = 'parentWorkItemId' in body;\n if (\n title === undefined &&\n stages === undefined &&\n sessions === undefined &&\n metadata === undefined &&\n !hasParentWorkItemId\n )\n return null;\n const parentWorkItemId = hasParentWorkItemId ? parseParentWorkItemId(body.parentWorkItemId) : undefined;\n if (hasParentWorkItemId && parentWorkItemId === undefined) return null;\n if (title !== undefined && (typeof title !== 'string' || title.trim().length === 0 || title.length > 500))\n return null;\n if (stages !== undefined && !validStages(stages)) return null;\n const parsedSessions = sessions === undefined ? undefined : parseSessions(sessions);\n if (sessions !== undefined && parsedSessions === undefined) return null;\n let parsedMetadata: Record<string, unknown> | null | undefined;\n if (metadata !== undefined) {\n if (!validMetadata(metadata)) return null;\n parsedMetadata = publicWorkItemMetadata(metadata);\n }\n\n return {\n ...(hasParentWorkItemId ? { parentWorkItemId: parentWorkItemId ?? null } : {}),\n ...(title !== undefined ? { title: title.trim() } : {}),\n ...(stages !== undefined ? { stages } : {}),\n ...(parsedSessions !== undefined ? { sessions: parsedSessions } : {}),\n ...(parsedMetadata !== undefined ? { metadata: parsedMetadata } : {}),\n };\n}\n\nasync function readJson(c: Context): Promise<unknown | undefined> {\n try {\n return await c.req.json();\n } catch {\n return undefined;\n }\n}\n\n/** Fields a PATCH touched, for the bounded `updated` event summary. */\nfunction patchedFields(patch: Record<string, unknown>): string[] {\n return Object.keys(patch).filter(key => patch[key] !== undefined);\n}\n\nfunction boundedText(value: unknown, max: number): string | undefined {\n if (typeof value !== 'string') return undefined;\n const normalized = value.trim();\n return normalized.length > 0 && normalized.length <= max ? normalized : undefined;\n}\n\nfunction parseTransitionBody(\n body: unknown,\n): Omit<FactoryTransitionRequest, 'orgId' | 'factoryProjectId' | 'workItemId' | 'actor'> | null {\n if (!isRecord(body)) return null;\n const board = FACTORY_RULE_BOARDS.includes(body.board as FactoryRuleBoard)\n ? (body.board as FactoryRuleBoard)\n : undefined;\n const stage = isFactoryRuleStage(body.stage) ? body.stage : undefined;\n const requestId = boundedText(body.requestId, 256);\n const cause = boundedText(body.cause, 256);\n if (\n !board ||\n !stage ||\n !requestId ||\n !UUID_RE.test(requestId) ||\n !cause ||\n !Number.isInteger(body.expectedRevision) ||\n Number(body.expectedRevision) < 1\n ) {\n return null;\n }\n return {\n board,\n stage,\n expectedRevision: Number(body.expectedRevision),\n ingress: { type: 'human', identity: requestId },\n cause,\n };\n}\n\nfunction parseInvocation(value: unknown): FactoryStartRequest['invocation'] | undefined | null {\n if (value === undefined) return undefined;\n if (!isRecord(value)) return null;\n if (value.type === 'prompt') {\n const prompt = boundedText(value.prompt, 16_384);\n return prompt ? { type: 'prompt', prompt } : null;\n }\n if (value.type === 'skill') {\n const skillName = boundedText(value.skillName, 64);\n const args = typeof value.arguments === 'string' && value.arguments.length <= 16_384 ? value.arguments : undefined;\n return skillName && args !== undefined ? { type: 'skill', skillName, arguments: args } : null;\n }\n return null;\n}\n\nfunction parseStartBody(\n body: unknown,\n tenant: { orgId: string; userId: string },\n factoryProjectId: string,\n): FactoryStartRequest | null {\n if (!isRecord(body) || !isRecord(body.workItem)) return null;\n const input = parseCreateWorkItem(body.workItem.input);\n const sessionId = boundedText(body.sessionId, 256);\n const threadTitle = boundedText(body.threadTitle, 512);\n const kickoffKey = boundedText(body.kickoffKey, 256);\n const invocation = parseInvocation(body.invocation);\n const destinationStage = isFactoryRuleStage(body.destinationStage) ? body.destinationStage : undefined;\n const role = boundedText(body.workItem.role, 32);\n const id = body.workItem.id === undefined ? undefined : boundedText(body.workItem.id, 64);\n if (body.workItem.id !== undefined && (!id || !UUID_RE.test(id))) return null;\n if (\n !input ||\n !sessionId ||\n !UUID_RE.test(sessionId) ||\n !threadTitle ||\n !kickoffKey ||\n !UUID_RE.test(kickoffKey) ||\n invocation === null ||\n !destinationStage ||\n !role\n ) {\n return null;\n }\n const threadTags = isRecord(body.threadTags)\n ? Object.fromEntries(\n Object.entries(body.threadTags)\n .filter(\n (entry): entry is [string, string] =>\n boundedText(entry[0], 64) !== undefined && boundedText(entry[1], 256) !== undefined,\n )\n .map(([key, value]) => [key, value.trim()]),\n )\n : undefined;\n return {\n ...tenant,\n factoryProjectId,\n sessionId,\n threadTitle,\n threadTags,\n kickoffKey,\n invocation,\n destinationStage,\n workItem: { id, role, input },\n };\n}\n\nconst DECISION_STATUSES = new Set<FactoryDispatchStatus>([\n 'pending',\n 'proposed',\n 'dismissed',\n 'superseded',\n 'leased',\n 'retry',\n 'succeeded',\n 'failed',\n]);\nconst DEFAULT_DECISION_PAGE_SIZE = 25;\nconst MAX_DECISION_PAGE_SIZE = 50;\n\nfunction parseDecisionStatuses(raw: string | undefined): FactoryDispatchStatus[] | undefined {\n if (!raw) return undefined;\n const statuses = [...new Set(raw.split(',').map(status => status.trim()))].filter(\n (status): status is FactoryDispatchStatus => DECISION_STATUSES.has(status as FactoryDispatchStatus),\n );\n return statuses.length > 0 ? statuses : undefined;\n}\n\nfunction parseDecisionLimit(raw: string | undefined): number {\n const parsed = raw ? Number.parseInt(raw, 10) : DEFAULT_DECISION_PAGE_SIZE;\n if (!Number.isFinite(parsed)) return DEFAULT_DECISION_PAGE_SIZE;\n return Math.max(1, Math.min(MAX_DECISION_PAGE_SIZE, parsed));\n}\n\nfunction encodeDecisionCursor(decision: FactoryDeferredDecisionRecord): string {\n return Buffer.from(JSON.stringify([decision.createdAt.toISOString(), decision.id]), 'utf8').toString('base64url');\n}\n\nfunction parseDecisionCursor(raw: string | undefined): { createdAt: Date; id: string } | undefined {\n if (!raw) return undefined;\n try {\n const decoded = JSON.parse(Buffer.from(raw, 'base64url').toString('utf8')) as unknown;\n if (\n !Array.isArray(decoded) ||\n decoded.length !== 2 ||\n typeof decoded[0] !== 'string' ||\n typeof decoded[1] !== 'string'\n ) {\n return undefined;\n }\n const createdAt = new Date(decoded[0]);\n if (Number.isNaN(createdAt.getTime()) || !UUID_RE.test(decoded[1])) return undefined;\n return { createdAt, id: decoded[1] };\n } catch {\n return undefined;\n }\n}\n\nfunction decisionSummary(decision: FactoryDeferredDecisionRecord) {\n return {\n id: decision.id,\n evaluationId: decision.evaluationId,\n workItemId: decision.workItemId,\n type: factoryDecisionType(decision),\n role: typeof decision.decision.role === 'string' ? decision.decision.role.slice(0, 32) : null,\n status: decision.status,\n attempts: decision.attempts,\n failureOccurrence: decision.failureOccurrence,\n failureCode: decision.failureCode,\n canRetry: factoryDispatchFailureMetadata(decision.failureCode).canRetry,\n lastError: decision.lastError?.slice(0, 512) ?? null,\n createdAt: decision.createdAt.toISOString(),\n updatedAt: decision.updatedAt.toISOString(),\n completedAt: decision.completedAt?.toISOString() ?? null,\n };\n}\n\nexport class WorkItemRoutes extends Route<WorkItemRoutesDeps> {\n /** Resolve the `(orgId, userId)` tenant or a ready-to-return error response. */\n async #resolveTenant(c: Context): Promise<{ orgId: string; userId: string } | { response: Response }> {\n await this.deps.auth.ensureUser(c);\n const tenant = this.deps.auth.tenant(c);\n if (!tenant) return { response: c.json({ error: 'unauthorized' }, 401) };\n if (!tenant.orgId) {\n return {\n response: c.json(\n { error: 'organization_required', message: 'The Factory board requires an organization.' },\n 403,\n ),\n };\n }\n return { orgId: tenant.orgId, userId: tenant.userId };\n }\n\n /**\n * Resolve the tenant AND the org-owned project from the `:id` param. Work\n * items hang off a project, so listing/creating requires the project to\n * exist in the caller's org.\n */\n async #resolveProject(\n c: Context,\n ): Promise<\n { orgId: string; userId: string; factoryProjectId: string; defaultModelId: string | null } | { response: Response }\n > {\n const tenant = await this.#resolveTenant(c);\n if ('response' in tenant) return tenant;\n\n const projectId = c.req.param('id');\n if (!projectId || !UUID_RE.test(projectId)) {\n return { response: c.json({ error: 'Project not found' }, 404) };\n }\n const { projects } = this.deps;\n await projects.ensureReady();\n const project = await projects.get({ orgId: tenant.orgId, id: projectId });\n if (!project) {\n return { response: c.json({ error: 'Project not found' }, 404) };\n }\n return { ...tenant, factoryProjectId: projectId, defaultModelId: project.defaultModelId };\n }\n\n /**\n * Emit the audit events a successful work-item PATCH implies: always\n * `updated`, plus `stage_moved` when the stages actually changed and one\n * `run.started` per session role the patch introduced.\n */\n async #auditWorkItemPatch({\n context,\n item,\n previous,\n patch,\n }: {\n context: Context;\n item: WorkItemRow;\n previous: WorkItemPriorState;\n patch: Record<string, unknown>;\n }): Promise<void> {\n const { audit } = this.deps;\n const target = { type: 'work_item', id: item.id, name: item.title };\n await audit.emit({\n context,\n input: {\n action: 'factory.work_item.updated',\n factoryProjectId: item.factoryProjectId,\n targets: [target],\n metadata: { fields: patchedFields(patch) },\n },\n });\n\n const stagesChanged =\n patch.stages !== undefined &&\n (previous.stages.length !== item.stages.length || previous.stages.some((s, i) => s !== item.stages[i]));\n if (stagesChanged) {\n await audit.emit({\n context,\n input: {\n action: 'factory.work_item.stage_moved',\n factoryProjectId: item.factoryProjectId,\n targets: [target],\n metadata: { from: previous.stages, to: item.stages },\n },\n });\n }\n\n const newRoles = Object.keys(item.sessions).filter(role => !previous.sessionRoles.includes(role));\n for (const role of newRoles) {\n const session = item.sessions[role];\n await audit.emit({\n context,\n input: {\n action: 'factory.run.started',\n factoryProjectId: item.factoryProjectId,\n targets: [target],\n metadata: {\n role,\n branch: session?.branch,\n threadId: session?.threadId,\n sessionId: session?.sessionId,\n },\n },\n });\n }\n }\n\n /** Releasing a parked run and dropping it: same request, opposite outcomes, both audited as consent. */\n #proposalRoute({\n verb,\n settle,\n }: {\n verb: 'approve' | 'dismiss';\n settle: (\n orgId: string,\n factoryProjectId: string,\n decisionId: string,\n now: Date,\n userId: string,\n ) => Promise<FactoryDeferredDecisionRecord | null>;\n }): ApiRoute {\n const { audit, workItems } = this.deps;\n return registerApiRoute(`/web/factory/projects/:id/decisions/:decisionId/${verb}`, {\n method: 'POST',\n requiresAuth: false,\n handler: async c => {\n const context = loose(c);\n const resolved = await this.#resolveProject(context);\n if ('response' in resolved) return resolved.response;\n const decisionId = context.req.param('decisionId');\n if (!decisionId || !UUID_RE.test(decisionId)) return c.json({ error: 'invalid_decision_id' }, 422);\n await workItems.ensureReady();\n const now = new Date();\n const decision = await settle(resolved.orgId, resolved.factoryProjectId, decisionId, now, resolved.userId);\n if (!decision) return c.json({ error: 'decision_not_proposed' }, 409);\n // Releasing a proposal is a person taking the item on. Approval arms the\n // item's autonomy inside the same storage transaction (see\n // approveDeferredDecision), so follow-up runs no longer wait for approval.\n await audit.emit({\n context,\n input: {\n action: verb === 'approve' ? 'factory.run.approved' : 'factory.run.dismissed',\n factoryProjectId: resolved.factoryProjectId,\n targets: decision.workItemId\n ? [{ type: 'work_item', id: decision.workItemId }]\n : [{ type: 'rule_decision', id: decision.id }],\n metadata: { decisionId: decision.id, effect: factoryDecisionType(decision) },\n },\n });\n return c.json({ decision: decisionSummary(decision) });\n },\n });\n }\n\n /** Build the Factory work-item routes as Mastra `apiRoutes`. */\n routes(): ApiRoute[] {\n const { audit, workItems, queueHealth, transitionService, startCoordinator, liveSessions } = this.deps;\n return [\n // ── List the org's work items for a project, and which are being worked ─\n registerApiRoute('/web/factory/projects/:id/work-items', {\n method: 'GET',\n requiresAuth: false,\n handler: async c => {\n const resolved = await this.#resolveProject(loose(c));\n if ('response' in resolved) return resolved.response;\n await workItems.ensureReady();\n const items = await workItems.list({\n orgId: resolved.orgId,\n factoryProjectId: resolved.factoryProjectId,\n });\n return c.json({\n workItems: items.map(toWireWorkItem),\n runningSessionIds: runningSessionIds(items, liveSessions),\n });\n },\n }),\n\n // ── Flow metrics aggregated over the project's work items ───────────────\n registerApiRoute('/web/factory/projects/:id/metrics', {\n method: 'GET',\n requiresAuth: false,\n handler: async c => {\n const resolved = await this.#resolveProject(loose(c));\n if ('response' in resolved) return resolved.response;\n const { windowStart, windowEnd } = parseMetricsRange(\n loose(c).req.query('from'),\n loose(c).req.query('to'),\n new Date(),\n );\n await workItems.ensureReady();\n const items = await workItems.list({\n orgId: resolved.orgId,\n factoryProjectId: resolved.factoryProjectId,\n });\n return c.json({ metrics: computeFactoryMetrics(items, { windowStart, windowEnd }) });\n },\n }),\n\n // ── Per-project queue-health age-threshold config (seconds) ─────────────\n registerApiRoute('/web/factory/projects/:id/health/thresholds', {\n method: 'GET',\n requiresAuth: false,\n handler: async c => {\n const resolved = await this.#resolveProject(loose(c));\n if ('response' in resolved) return resolved.response;\n await queueHealth.ensureReady();\n const stored = await queueHealth.getConfig(resolved.orgId, resolved.factoryProjectId);\n // Validate at the read choke point: `getConfig` round-trips a stored\n // JSONB row, and only `saveConfig` validates on write — a corrupted or\n // hand-edited row (empty / non-ascending) would otherwise flow to the\n // chart and invert bucket colors. Fall back to the default on invalid.\n return c.json({ thresholds: thresholdsOrDefault(stored) });\n },\n }),\n\n // ── Bounded durable rule-decision status ────────────────────────────────\n registerApiRoute('/web/factory/projects/:id/decisions', {\n method: 'GET',\n requiresAuth: false,\n handler: async c => {\n const context = loose(c);\n const resolved = await this.#resolveProject(context);\n if ('response' in resolved) return resolved.response;\n\n const cursorRaw = context.req.query('before');\n const before = parseDecisionCursor(cursorRaw);\n if (cursorRaw && !before) return c.json({ error: 'invalid_cursor' }, 400);\n await workItems.ensureReady();\n const page = await workItems.listDeferredDecisionPage({\n orgId: resolved.orgId,\n factoryProjectId: resolved.factoryProjectId,\n statuses: parseDecisionStatuses(context.req.query('statuses')),\n before,\n limit: parseDecisionLimit(context.req.query('limit')),\n });\n const last = page.decisions.at(-1);\n return c.json({\n decisions: page.decisions.map(decisionSummary),\n ...(page.hasMore && last ? { nextCursor: encodeDecisionCursor(last) } : {}),\n });\n },\n }),\n\n ...buildAttentionRoutes({\n workItems,\n resolveProject: context => this.#resolveProject(loose(context)),\n }),\n\n this.#proposalRoute({ verb: 'approve', settle: workItems.approveDeferredDecision.bind(workItems) }),\n this.#proposalRoute({ verb: 'dismiss', settle: workItems.dismissDeferredDecision.bind(workItems) }),\n\n registerApiRoute('/web/factory/projects/:id/decisions/:decisionId/retry', {\n method: 'POST',\n requiresAuth: false,\n handler: async c => {\n const context = loose(c);\n const resolved = await this.#resolveProject(context);\n if ('response' in resolved) return resolved.response;\n const decisionId = context.req.param('decisionId');\n if (!decisionId || !UUID_RE.test(decisionId)) return c.json({ error: 'invalid_decision_id' }, 422);\n await workItems.ensureReady();\n const current = await workItems.getDeferredDecision(resolved.orgId, resolved.factoryProjectId, decisionId);\n if (\n !current ||\n current.status !== 'failed' ||\n !factoryDispatchFailureMetadata(current.failureCode).canRetry\n ) {\n return c.json({ error: 'decision_not_retryable' }, 409);\n }\n const decision = await workItems.retryDeferredDecision(\n resolved.orgId,\n resolved.factoryProjectId,\n decisionId,\n new Date(),\n );\n if (!decision) return c.json({ error: 'decision_not_retryable' }, 409);\n return c.json({ decision: decisionSummary(decision) });\n },\n }),\n\n // ── Create (upsert on sourceKey) a work item ─────────────────────────────\n registerApiRoute('/web/factory/projects/:id/work-items', {\n method: 'POST',\n requiresAuth: false,\n handler: async c => {\n const resolved = await this.#resolveProject(loose(c));\n if ('response' in resolved) return resolved.response;\n\n const body = await readJson(loose(c));\n if (body === undefined) return c.json({ error: 'Invalid JSON body' }, 400);\n const input = parseCreateWorkItem(body);\n if (!input) return c.json({ error: 'invalid_work_item' }, 400);\n if ((input.stages ?? ['intake']).length !== 1 || (input.stages ?? ['intake'])[0] !== 'intake') {\n return c.json(\n { error: 'governed_transition_required', message: 'New work items must enter through Factory intake.' },\n 409,\n );\n }\n\n await workItems.ensureReady();\n try {\n const result = await workItems.upsert({\n orgId: resolved.orgId,\n userId: resolved.userId,\n factoryProjectId: resolved.factoryProjectId,\n input,\n reuseMode: 'non-stage',\n });\n let item = result.item;\n if (result.created) {\n if (!transitionService) {\n await workItems.delete({ orgId: resolved.orgId, id: item.id });\n return c.json({ error: 'factory_transitions_unavailable' }, 503);\n }\n const entered = await transitionService.transition({\n orgId: resolved.orgId,\n factoryProjectId: resolved.factoryProjectId,\n workItemId: item.id,\n board: item.externalSource?.type === 'pull-request' ? 'review' : 'work',\n stage: 'intake',\n expectedRevision: item.revision,\n actor: { type: 'human', id: resolved.userId },\n ingress: { type: 'human', identity: `work-item:${item.id}:initial-entry` },\n cause: 'work_item_created',\n initialEntry: true,\n });\n if (entered.status === 'rejected') {\n await workItems.delete({ orgId: resolved.orgId, id: item.id });\n return c.json({ status: 'rejected', code: entered.code, reason: entered.reason }, 422);\n }\n item = (await workItems.getForProject(resolved.orgId, resolved.factoryProjectId, item.id)) ?? item;\n await audit.emit({\n context: loose(c),\n input: {\n action: 'factory.work_item.created',\n factoryProjectId: resolved.factoryProjectId,\n targets: [{ type: 'work_item', id: item.id, name: item.title }],\n metadata: { externalSource: item.externalSource, stages: item.stages },\n },\n });\n } else {\n // Source-key reuse: the POST updated an existing card, so audit it\n // as an update (plus stage/run events) instead of a false creation.\n const { stages: _stages, sessions: _sessions, ...boundedPatch } = input;\n await this.#auditWorkItemPatch({\n context: loose(c),\n item,\n previous: result.previous,\n patch: boundedPatch as unknown as Record<string, unknown>,\n });\n }\n return c.json({ workItem: toWireWorkItem(item) });\n } catch (error) {\n if (error instanceof WorkItemRelationError) {\n return c.json({ error: error.code, message: error.message }, 400);\n }\n throw error;\n }\n },\n }),\n\n // ── Authoritative stage transition ──────────────────────────────────────\n registerApiRoute('/web/factory/projects/:id/work-items/:workItemId/transition', {\n method: 'POST',\n requiresAuth: false,\n handler: async c => {\n const resolved = await this.#resolveProject(loose(c));\n if ('response' in resolved) return resolved.response;\n const workItemId = loose(c).req.param('workItemId');\n if (!workItemId || !UUID_RE.test(workItemId)) return c.json({ error: 'Work item not found' }, 404);\n const parsed = parseTransitionBody(await readJson(loose(c)));\n if (!parsed) return c.json({ error: 'invalid_transition_request' }, 400);\n if (!transitionService) {\n return c.json({ error: 'factory_transition_unavailable' }, 503);\n }\n await workItems.ensureReady();\n const result = await transitionService.transition({\n ...parsed,\n orgId: resolved.orgId,\n factoryProjectId: resolved.factoryProjectId,\n workItemId,\n actor: { type: 'human', id: resolved.userId },\n ingress: {\n ...parsed.ingress,\n identity: `human:${resolved.userId}:${parsed.ingress.identity}`,\n },\n });\n await audit.emit({\n context: loose(c),\n input: {\n action:\n result.status === 'accepted'\n ? 'factory.work_item.stage_moved'\n : 'factory.work_item.transition_rejected',\n factoryProjectId: resolved.factoryProjectId,\n targets: [{ type: 'work_item', id: workItemId }],\n metadata: {\n transitionId: result.transitionId,\n ingressType: parsed.ingress.type,\n ruleSetVersion: transitionService.ruleSetVersion,\n ...(result.status === 'accepted'\n ? { to: result.stage, revision: result.revision }\n : { code: result.code, reason: result.reason }),\n },\n },\n });\n if (result.status === 'accepted') return c.json({ result });\n return c.json({ result }, result.code === 'stale' ? 409 : 422);\n },\n }),\n\n // ── Bind a Factory run before dispatching its kickoff ────────────────────\n registerApiRoute('/web/factory/projects/:id/runs/start', {\n method: 'POST',\n requiresAuth: false,\n handler: async c => {\n const resolved = await this.#resolveProject(loose(c));\n if ('response' in resolved) return resolved.response;\n if (!startCoordinator) {\n return c.json({ error: 'factory_start_unavailable' }, 503);\n }\n const input = parseStartBody(await readJson(loose(c)), resolved, resolved.factoryProjectId);\n if (!input) return c.json({ error: 'invalid_factory_start' }, 400);\n input.requestContext = loose(c).get('requestContext');\n input.defaultModelId = resolved.defaultModelId ?? undefined;\n // This route is only reached by a person pressing a run action, so\n // reaching it is the commitment the approval gate is asking for.\n // Arming rides inside prepareRunStart's transaction so a crash can't\n // start the run while leaving its follow-up work waiting on approval.\n input.armAutonomy = true;\n if (\n !input.workItem.id &&\n ((input.workItem.input.stages ?? ['intake']).length !== 1 ||\n (input.workItem.input.stages ?? ['intake'])[0] !== 'intake')\n ) {\n return c.json(\n { error: 'governed_transition_required', message: 'Create the work item in Intake before starting it.' },\n 409,\n );\n }\n await workItems.ensureReady();\n let prepared: FactoryStartPreparedResult;\n try {\n prepared = await startCoordinator.prepare(input);\n } catch (error) {\n if (error instanceof FactoryStartTransitionError) {\n return c.json({ result: error.result }, error.result.code === 'stale' ? 409 : 422);\n }\n throw error;\n }\n await audit.emit({\n context: loose(c),\n input: {\n action: 'factory.run.started',\n factoryProjectId: resolved.factoryProjectId,\n targets: [{ type: 'work_item', id: prepared.workItemId }],\n metadata: {\n role: input.workItem.role,\n branch: prepared.branch,\n threadId: prepared.threadId,\n sessionId: prepared.sessionId,\n bindingId: prepared.bindingId,\n },\n },\n });\n return c.json({ prepared }, 202);\n },\n }),\n\n // ── Patch non-stage metadata / sessions / title ──────────────────────────\n registerApiRoute('/web/factory/work-items/:id', {\n method: 'PATCH',\n requiresAuth: false,\n handler: async c => {\n const tenant = await this.#resolveTenant(loose(c));\n if ('response' in tenant) return tenant.response;\n\n const id = loose(c).req.param('id');\n if (!id || !UUID_RE.test(id)) return c.json({ error: 'Work item not found' }, 404);\n\n const body = await readJson(loose(c));\n if (body === undefined) return c.json({ error: 'Invalid JSON body' }, 400);\n const patch = parseUpdateWorkItem(body);\n if (!patch) return c.json({ error: 'invalid_work_item_patch' }, 400);\n if (patch.stages !== undefined) {\n return c.json(\n { error: 'governed_transition_required', message: 'Use the Factory transition endpoint to move stages.' },\n 409,\n );\n }\n\n await workItems.ensureReady();\n try {\n const updated = await workItems.update({ orgId: tenant.orgId, id, userId: tenant.userId, patch });\n if (!updated) return c.json({ error: 'Work item not found' }, 404);\n await this.#auditWorkItemPatch({\n context: loose(c),\n item: updated.item,\n previous: updated.previous,\n patch: patch as Record<string, unknown>,\n });\n return c.json({ workItem: toWireWorkItem(updated.item) });\n } catch (error) {\n if (error instanceof WorkItemRelationError) {\n return c.json({ error: error.code, message: error.message }, 400);\n }\n throw error;\n }\n },\n }),\n\n // ── Remove a work item ───────────────────────────────────────────────────\n registerApiRoute('/web/factory/work-items/:id', {\n method: 'DELETE',\n requiresAuth: false,\n handler: async c => {\n const tenant = await this.#resolveTenant(loose(c));\n if ('response' in tenant) return tenant.response;\n\n const id = loose(c).req.param('id');\n if (!id || !UUID_RE.test(id)) return c.json({ error: 'Work item not found' }, 404);\n\n await workItems.ensureReady();\n const deleted = await workItems.delete({ orgId: tenant.orgId, id });\n if (!deleted) return c.json({ error: 'Work item not found' }, 404);\n await audit.emit({\n context: loose(c),\n input: {\n action: 'factory.work_item.deleted',\n factoryProjectId: deleted.factoryProjectId,\n targets: [{ type: 'work_item', id: deleted.id, name: deleted.title }],\n },\n });\n return c.json({ ok: true });\n },\n }),\n ];\n }\n}\n"],"mappings":"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"}
@@ -376,8 +376,8 @@ function mergeBoardRules(base, overrides) {
376
376
  const baseLeaf = baseSources?.[source];
377
377
  const overrideLeaf = overrideSources?.[source];
378
378
  mergedSources[source] = {
379
- ...baseLeaf?.onEnter ? { onEnter: baseLeaf.onEnter } : {},
380
- ...baseLeaf?.onExit ? { onExit: baseLeaf.onExit } : {},
379
+ ...baseLeaf && "onEnter" in baseLeaf ? { onEnter: baseLeaf.onEnter } : {},
380
+ ...baseLeaf && "onExit" in baseLeaf ? { onExit: baseLeaf.onExit } : {},
381
381
  ...overrideLeaf && "onEnter" in overrideLeaf ? { onEnter: overrideLeaf.onEnter } : {},
382
382
  ...overrideLeaf && "onExit" in overrideLeaf ? { onExit: overrideLeaf.onExit } : {}
383
383
  };
@@ -392,7 +392,7 @@ function mergeToolRules(base, overrides) {
392
392
  const baseLeaf = base?.[name];
393
393
  const overrideLeaf = overrides?.[name];
394
394
  result[name] = {
395
- ...baseLeaf?.onResult ? { onResult: baseLeaf.onResult } : {},
395
+ ...baseLeaf && "onResult" in baseLeaf ? { onResult: baseLeaf.onResult } : {},
396
396
  ...overrideLeaf && "onResult" in overrideLeaf ? { onResult: overrideLeaf.onResult } : {}
397
397
  };
398
398
  }
@@ -405,7 +405,7 @@ function mergeGithubRules(base, overrides) {
405
405
  const baseLeaf = base?.[event];
406
406
  const overrideLeaf = overrides?.[event];
407
407
  result[event] = {
408
- ...baseLeaf?.onEvent ? { onEvent: baseLeaf.onEvent } : {},
408
+ ...baseLeaf && "onEvent" in baseLeaf ? { onEvent: baseLeaf.onEvent } : {},
409
409
  ...overrideLeaf && "onEvent" in overrideLeaf ? { onEvent: overrideLeaf.onEvent } : {}
410
410
  };
411
411
  }
@@ -418,7 +418,7 @@ function mergeLinearRules(base, overrides) {
418
418
  const baseLeaf = base?.[event];
419
419
  const overrideLeaf = overrides?.[event];
420
420
  result[event] = {
421
- ...baseLeaf?.onEvent ? { onEvent: baseLeaf.onEvent } : {},
421
+ ...baseLeaf && "onEvent" in baseLeaf ? { onEvent: baseLeaf.onEvent } : {},
422
422
  ...overrideLeaf && "onEvent" in overrideLeaf ? { onEvent: overrideLeaf.onEvent } : {}
423
423
  };
424
424
  }