@mastra/factory 0.17.3-alpha.6 → 0.18.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 (82) hide show
  1. package/dist/boards/review.d.ts +2 -0
  2. package/dist/boards/review.d.ts.map +1 -1
  3. package/dist/boards/review.js +16 -6
  4. package/dist/boards/review.js.map +1 -1
  5. package/dist/boards/work-transition-policy.d.ts.map +1 -1
  6. package/dist/boards/work-transition-policy.js +10 -0
  7. package/dist/boards/work-transition-policy.js.map +1 -1
  8. package/dist/factory.d.ts.map +1 -1
  9. package/dist/factory.js +9 -1
  10. package/dist/factory.js.map +1 -1
  11. package/dist/integrations/github/default-rules.d.ts +17 -1
  12. package/dist/integrations/github/default-rules.d.ts.map +1 -1
  13. package/dist/integrations/github/default-rules.js +30 -6
  14. package/dist/integrations/github/default-rules.js.map +1 -1
  15. package/dist/integrations/github/reconcile-worker.d.ts.map +1 -1
  16. package/dist/integrations/github/reconcile-worker.js.map +1 -1
  17. package/dist/integrations/github/rules.d.ts.map +1 -1
  18. package/dist/integrations/github/rules.js +48 -2
  19. package/dist/integrations/github/rules.js.map +1 -1
  20. package/dist/integrations/github/sandbox.d.ts.map +1 -1
  21. package/dist/integrations/github/sandbox.js.map +1 -1
  22. package/dist/integrations/gitlab/api.d.ts.map +1 -1
  23. package/dist/integrations/gitlab/api.js.map +1 -1
  24. package/dist/integrations/gitlab/default-rules.d.ts.map +1 -1
  25. package/dist/integrations/gitlab/default-rules.js +1 -0
  26. package/dist/integrations/gitlab/default-rules.js.map +1 -1
  27. package/dist/integrations/gitlab/reconciler.d.ts.map +1 -1
  28. package/dist/integrations/gitlab/reconciler.js.map +1 -1
  29. package/dist/integrations/gitlab/reconciliation-config.d.ts.map +1 -1
  30. package/dist/integrations/gitlab/reconciliation-config.js.map +1 -1
  31. package/dist/integrations/gitlab/rules.d.ts.map +1 -1
  32. package/dist/integrations/gitlab/rules.js +66 -0
  33. package/dist/integrations/gitlab/rules.js.map +1 -1
  34. package/dist/integrations/gitlab/version-control.d.ts.map +1 -1
  35. package/dist/integrations/gitlab/version-control.js.map +1 -1
  36. package/dist/integrations/incidentio/api.d.ts.map +1 -1
  37. package/dist/integrations/incidentio/api.js.map +1 -1
  38. package/dist/integrations/incidentio/intake.d.ts.map +1 -1
  39. package/dist/integrations/incidentio/intake.js.map +1 -1
  40. package/dist/integrations/issue-reconcile-worker.d.ts.map +1 -1
  41. package/dist/integrations/issue-reconcile-worker.js.map +1 -1
  42. package/dist/integrations/platform/linear/event-worker.js.map +1 -1
  43. package/dist/integrations/slack/emoji-shortcodes.generated.js.map +1 -1
  44. package/dist/integrations/slack/feed-publisher.d.ts.map +1 -1
  45. package/dist/integrations/slack/feed-publisher.js.map +1 -1
  46. package/dist/rules/dispatcher.d.ts.map +1 -1
  47. package/dist/rules/dispatcher.js +11 -2
  48. package/dist/rules/dispatcher.js.map +1 -1
  49. package/dist/rules/review-source-tool.d.ts +103 -0
  50. package/dist/rules/review-source-tool.d.ts.map +1 -0
  51. package/dist/rules/review-source-tool.js +109 -0
  52. package/dist/rules/review-source-tool.js.map +1 -0
  53. package/dist/rules/tools.d.ts +1 -0
  54. package/dist/rules/tools.d.ts.map +1 -1
  55. package/dist/rules/tools.js +107 -32
  56. package/dist/rules/tools.js.map +1 -1
  57. package/dist/skills/service.d.ts.map +1 -1
  58. package/dist/skills/service.js +16 -6
  59. package/dist/skills/service.js.map +1 -1
  60. package/dist/storage/domains/integrations/base.d.ts.map +1 -1
  61. package/dist/storage/domains/integrations/base.js.map +1 -1
  62. package/dist/storage/domains/work-items/base.d.ts +11 -0
  63. package/dist/storage/domains/work-items/base.d.ts.map +1 -1
  64. package/dist/storage/domains/work-items/base.js +21 -0
  65. package/dist/storage/domains/work-items/base.js.map +1 -1
  66. package/dist/supervisor/session-messaging.d.ts +4 -1
  67. package/dist/supervisor/session-messaging.d.ts.map +1 -1
  68. package/dist/supervisor/session-messaging.js +8 -2
  69. package/dist/supervisor/session-messaging.js.map +1 -1
  70. package/dist/supervisor/write-tools.d.ts +2 -1
  71. package/dist/supervisor/write-tools.d.ts.map +1 -1
  72. package/dist/supervisor/write-tools.js +9 -2
  73. package/dist/supervisor/write-tools.js.map +1 -1
  74. package/dist/workspace.d.ts +7 -1
  75. package/dist/workspace.d.ts.map +1 -1
  76. package/dist/workspace.js +45 -7
  77. package/dist/workspace.js.map +1 -1
  78. package/factory-skills/factory-gitlab-rereview/SKILL.md +3 -2
  79. package/factory-skills/factory-gitlab-review/SKILL.md +19 -3
  80. package/factory-skills/factory-rereview/SKILL.md +30 -11
  81. package/factory-skills/factory-review/SKILL.md +30 -11
  82. package/package.json +8 -8
@@ -1,4 +1,7 @@
1
1
  import type { RequestContext } from '@mastra/core/request-context';
2
+ export type WorkerMessageResult = void | {
3
+ status: 'interrupted';
4
+ };
2
5
  type WorkerSession = {
3
6
  sendMessage(input: {
4
7
  content: string;
@@ -18,6 +21,6 @@ export declare function messageWorkerSession({ controller, sessionId, message, d
18
21
  message: string;
19
22
  delivery: 'send' | 'queue';
20
23
  requestContext?: RequestContext;
21
- }): Promise<void>;
24
+ }): Promise<WorkerMessageResult>;
22
25
  export {};
23
26
  //# sourceMappingURL=session-messaging.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"session-messaging.d.ts","sourceRoot":"","sources":["../../src/supervisor/session-messaging.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAEnE,KAAK,aAAa,GAAG;IACnB,WAAW,CAAC,KAAK,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,cAAc,CAAC,EAAE,cAAc,CAAA;KAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAC3F,YAAY,CAAC,KAAK,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,cAAc,CAAC,EAAE,cAAc,CAAA;KAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CAC7F,CAAC;AAEF,KAAK,uBAAuB,GAAG;IAC7B,oBAAoB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,GAAG,SAAS,CAAC,CAAC;CAC7E,CAAC;AAEF,wBAAsB,oBAAoB,CAAC,EACzC,UAAU,EACV,SAAS,EACT,OAAO,EACP,QAAQ,EACR,cAAc,GACf,EAAE;IACD,UAAU,EAAE,uBAAuB,CAAC;IACpC,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC;IAC3B,cAAc,CAAC,EAAE,cAAc,CAAC;CACjC,GAAG,OAAO,CAAC,IAAI,CAAC,CAUhB"}
1
+ {"version":3,"file":"session-messaging.d.ts","sourceRoot":"","sources":["../../src/supervisor/session-messaging.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAEnE,MAAM,MAAM,mBAAmB,GAAG,IAAI,GAAG;IAAE,MAAM,EAAE,aAAa,CAAA;CAAE,CAAC;AAEnE,KAAK,aAAa,GAAG;IACnB,WAAW,CAAC,KAAK,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,cAAc,CAAC,EAAE,cAAc,CAAA;KAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAC3F,YAAY,CAAC,KAAK,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,cAAc,CAAC,EAAE,cAAc,CAAA;KAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CAC7F,CAAC;AAEF,KAAK,uBAAuB,GAAG;IAC7B,oBAAoB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,GAAG,SAAS,CAAC,CAAC;CAC7E,CAAC;AAEF,wBAAsB,oBAAoB,CAAC,EACzC,UAAU,EACV,SAAS,EACT,OAAO,EACP,QAAQ,EACR,cAAc,GACf,EAAE;IACD,UAAU,EAAE,uBAAuB,CAAC;IACpC,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC;IAC3B,cAAc,CAAC,EAAE,cAAc,CAAC;CACjC,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAe/B"}
@@ -1,3 +1,4 @@
1
+ import { isSessionStartupCancelledError } from "@mastra/core/agent-controller";
1
2
  //#region src/supervisor/session-messaging.ts
2
3
  async function messageWorkerSession({ controller, sessionId, message, delivery, requestContext }) {
3
4
  const session = await controller.getSessionByResource(sessionId);
@@ -6,8 +7,13 @@ async function messageWorkerSession({ controller, sessionId, message, delivery,
6
7
  content: message,
7
8
  ...requestContext ? { requestContext } : {}
8
9
  };
9
- if (delivery === "queue") await session.queueMessage(input);
10
- else await session.sendMessage(input);
10
+ try {
11
+ if (delivery === "queue") await session.queueMessage(input);
12
+ else await session.sendMessage(input);
13
+ } catch (error) {
14
+ if (isSessionStartupCancelledError(error)) return { status: "interrupted" };
15
+ throw error;
16
+ }
11
17
  }
12
18
  //#endregion
13
19
  export { messageWorkerSession };
@@ -1 +1 @@
1
- {"version":3,"file":"session-messaging.js","names":[],"sources":["../../src/supervisor/session-messaging.ts"],"sourcesContent":["import type { RequestContext } from '@mastra/core/request-context';\n\ntype WorkerSession = {\n sendMessage(input: { content: string; requestContext?: RequestContext }): Promise<unknown>;\n queueMessage(input: { content: string; requestContext?: RequestContext }): Promise<unknown>;\n};\n\ntype WorkerSessionController = {\n getSessionByResource(sessionId: string): Promise<WorkerSession | undefined>;\n};\n\nexport async function messageWorkerSession({\n controller,\n sessionId,\n message,\n delivery,\n requestContext,\n}: {\n controller: WorkerSessionController;\n sessionId: string;\n message: string;\n delivery: 'send' | 'queue';\n requestContext?: RequestContext;\n}): Promise<void> {\n const session = await controller.getSessionByResource(sessionId);\n if (!session) throw new Error('The worker session is not currently available.');\n\n const input = { content: message, ...(requestContext ? { requestContext } : {}) };\n if (delivery === 'queue') {\n await session.queueMessage(input);\n } else {\n await session.sendMessage(input);\n }\n}\n"],"mappings":";AAWA,eAAsB,qBAAqB,EACzC,YACA,WACA,SACA,UACA,kBAOgB;CAChB,MAAM,UAAU,MAAM,WAAW,qBAAqB,SAAS;CAC/D,IAAI,CAAC,SAAS,MAAM,IAAI,MAAM,gDAAgD;CAE9E,MAAM,QAAQ;EAAE,SAAS;EAAS,GAAI,iBAAiB,EAAE,eAAe,IAAI,CAAC;CAAG;CAChF,IAAI,aAAa,SACf,MAAM,QAAQ,aAAa,KAAK;MAEhC,MAAM,QAAQ,YAAY,KAAK;AAEnC"}
1
+ {"version":3,"file":"session-messaging.js","names":[],"sources":["../../src/supervisor/session-messaging.ts"],"sourcesContent":["import { isSessionStartupCancelledError } from '@mastra/core/agent-controller';\nimport type { RequestContext } from '@mastra/core/request-context';\n\nexport type WorkerMessageResult = void | { status: 'interrupted' };\n\ntype WorkerSession = {\n sendMessage(input: { content: string; requestContext?: RequestContext }): Promise<unknown>;\n queueMessage(input: { content: string; requestContext?: RequestContext }): Promise<unknown>;\n};\n\ntype WorkerSessionController = {\n getSessionByResource(sessionId: string): Promise<WorkerSession | undefined>;\n};\n\nexport async function messageWorkerSession({\n controller,\n sessionId,\n message,\n delivery,\n requestContext,\n}: {\n controller: WorkerSessionController;\n sessionId: string;\n message: string;\n delivery: 'send' | 'queue';\n requestContext?: RequestContext;\n}): Promise<WorkerMessageResult> {\n const session = await controller.getSessionByResource(sessionId);\n if (!session) throw new Error('The worker session is not currently available.');\n\n const input = { content: message, ...(requestContext ? { requestContext } : {}) };\n try {\n if (delivery === 'queue') {\n await session.queueMessage(input);\n } else {\n await session.sendMessage(input);\n }\n } catch (error) {\n if (isSessionStartupCancelledError(error)) return { status: 'interrupted' };\n throw error;\n }\n}\n"],"mappings":";;AAcA,eAAsB,qBAAqB,EACzC,YACA,WACA,SACA,UACA,kBAO+B;CAC/B,MAAM,UAAU,MAAM,WAAW,qBAAqB,SAAS;CAC/D,IAAI,CAAC,SAAS,MAAM,IAAI,MAAM,gDAAgD;CAE9E,MAAM,QAAQ;EAAE,SAAS;EAAS,GAAI,iBAAiB,EAAE,eAAe,IAAI,CAAC;CAAG;CAChF,IAAI;EACF,IAAI,aAAa,SACf,MAAM,QAAQ,aAAa,KAAK;OAEhC,MAAM,QAAQ,YAAY,KAAK;CAEnC,SAAS,OAAO;EACd,IAAI,+BAA+B,KAAK,GAAG,OAAO,EAAE,QAAQ,cAAc;EAC1E,MAAM;CACR;AACF"}
@@ -3,6 +3,7 @@ import type { FactoryTransitionService } from '../rules/transition-service.js';
3
3
  import type { AuditRecorder } from '../storage/domains/audit/domain.js';
4
4
  import type { WorkItemRow, WorkItemsStorage } from '../storage/domains/work-items/base.js';
5
5
  import type { SupervisorScope } from './read-tools.js';
6
+ import type { WorkerMessageResult } from './session-messaging.js';
6
7
  interface SupervisorWriteDependencies {
7
8
  scope: SupervisorScope;
8
9
  userId: string;
@@ -19,7 +20,7 @@ interface SupervisorWriteDependencies {
19
20
  message: string;
20
21
  userId: string;
21
22
  delivery: 'send' | 'queue';
22
- }) => Promise<unknown>;
23
+ }) => Promise<WorkerMessageResult>;
23
24
  now?: () => Date;
24
25
  }
25
26
  export declare function createFactorySupervisorWriteTools(deps: SupervisorWriteDependencies): IntegrationTools;
@@ -1 +1 @@
1
- {"version":3,"file":"write-tools.d.ts","sourceRoot":"","sources":["../../src/supervisor/write-tools.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAChE,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,gCAAgC,CAAC;AAG/E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oCAAoC,CAAC;AACxE,OAAO,KAAK,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,uCAAuC,CAAC;AAC3F,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAEvD,UAAU,2BAA2B;IACnC,KAAK,EAAE,eAAe,CAAC;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,gBAAgB,CAAC;IAC5B,KAAK,EAAE,aAAa,CAAC;IACrB,iBAAiB,EAAE,wBAAwB,CAAC;IAC5C,yBAAyB,CAAC,EAAE,CAAC,KAAK,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,gBAAgB,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,WAAW,CAAA;KAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACrH,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE;QACvB,SAAS,EAAE,MAAM,CAAC;QAClB,OAAO,EAAE,MAAM,CAAC;QAChB,MAAM,EAAE,MAAM,CAAC;QACf,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC;KAC5B,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IACvB,GAAG,CAAC,EAAE,MAAM,IAAI,CAAC;CAClB;AAED,wBAAgB,iCAAiC,CAAC,IAAI,EAAE,2BAA2B,GAAG,gBAAgB,CAkMrG"}
1
+ {"version":3,"file":"write-tools.d.ts","sourceRoot":"","sources":["../../src/supervisor/write-tools.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAChE,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,gCAAgC,CAAC;AAG/E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oCAAoC,CAAC;AACxE,OAAO,KAAK,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,uCAAuC,CAAC;AAC3F,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AACvD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAC;AAElE,UAAU,2BAA2B;IACnC,KAAK,EAAE,eAAe,CAAC;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,gBAAgB,CAAC;IAC5B,KAAK,EAAE,aAAa,CAAC;IACrB,iBAAiB,EAAE,wBAAwB,CAAC;IAC5C,yBAAyB,CAAC,EAAE,CAAC,KAAK,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,gBAAgB,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,WAAW,CAAA;KAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACrH,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE;QACvB,SAAS,EAAE,MAAM,CAAC;QAClB,OAAO,EAAE,MAAM,CAAC;QAChB,MAAM,EAAE,MAAM,CAAC;QACf,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC;KAC5B,KAAK,OAAO,CAAC,mBAAmB,CAAC,CAAC;IACnC,GAAG,CAAC,EAAE,MAAM,IAAI,CAAC;CAClB;AAED,wBAAgB,iCAAiC,CAAC,IAAI,EAAE,2BAA2B,GAAG,gBAAgB,CA4MrG"}
@@ -186,12 +186,19 @@ function createFactorySupervisorWriteTools(deps) {
186
186
  if (!deps.messageSession) throw new Error("Worker session messaging is unavailable.");
187
187
  const binding = (await deps.workItems.listRunBindings(deps.scope.orgId, deps.scope.factoryProjectId)).find((row) => row.sessionId === sessionId);
188
188
  if (!binding) throw new Error("The session does not belong to this factory.");
189
- await deps.messageSession({
189
+ if ((await deps.messageSession({
190
190
  sessionId,
191
191
  message,
192
192
  userId: deps.userId,
193
193
  delivery
194
- });
194
+ }))?.status === "interrupted") return {
195
+ sessionId,
196
+ delivered: false,
197
+ status: "interrupted",
198
+ delivery,
199
+ workItemId: binding.workItemId,
200
+ role: binding.role
201
+ };
195
202
  await audit("factory.agent.signaled", {
196
203
  type: "factory_session",
197
204
  id: sessionId
@@ -1 +1 @@
1
- {"version":3,"file":"write-tools.js","names":[],"sources":["../../src/supervisor/write-tools.ts"],"sourcesContent":["import { createTool } from '@mastra/core/tools';\nimport { z } from 'zod';\n\nimport { boardForWorkItem } from '../boards/index.js';\nimport type { IntegrationTools } from '../integrations/base.js';\nimport type { FactoryTransitionService } from '../rules/transition-service.js';\nimport { BOARD_IDENTIFIER_RE, MAX_BOARD_IDENTIFIER_LENGTH } from '../rules/validation.js';\nimport type { AuditAction } from '../storage/domains/audit/actions.js';\nimport type { AuditRecorder } from '../storage/domains/audit/domain.js';\nimport type { WorkItemRow, WorkItemsStorage } from '../storage/domains/work-items/base.js';\nimport type { SupervisorScope } from './read-tools.js';\n\ninterface SupervisorWriteDependencies {\n scope: SupervisorScope;\n userId: string;\n workItems: WorkItemsStorage;\n audit: AuditRecorder;\n transitionService: FactoryTransitionService;\n reconcileAcceptanceLabels?: (input: { orgId: string; factoryProjectId: string; item: WorkItemRow }) => Promise<void>;\n messageSession?: (input: {\n sessionId: string;\n message: string;\n userId: string;\n delivery: 'send' | 'queue';\n }) => Promise<unknown>;\n now?: () => Date;\n}\n\nexport function createFactorySupervisorWriteTools(deps: SupervisorWriteDependencies): IntegrationTools {\n const now = deps.now ?? (() => new Date());\n const audit = async (\n action: AuditAction,\n target: { type: string; id: string },\n metadata: Record<string, unknown> = {},\n ) =>\n deps.audit.record({\n orgId: deps.scope.orgId,\n actorId: deps.userId,\n actorType: 'human',\n action,\n targets: [target],\n factoryProjectId: deps.scope.factoryProjectId,\n metadata: { ...metadata, cause: 'supervisor' },\n occurredAt: now(),\n });\n\n return {\n factory_retry_decision: createTool({\n id: 'factory_retry_decision',\n description: 'Retry one failed Factory decision after the person confirms the repair.',\n inputSchema: z.object({ decisionId: z.string().min(1) }),\n requireApproval: true,\n execute: async ({ decisionId }) => {\n const decision = await deps.workItems.retryDeferredDecision(\n deps.scope.orgId,\n deps.scope.factoryProjectId,\n decisionId,\n now(),\n );\n if (!decision) throw new Error('The decision is not failed, no longer exists, or belongs to another factory.');\n await audit(\n 'factory.run.retry',\n { type: 'rule_decision', id: decisionId },\n { workItemId: decision.workItemId },\n );\n return { decisionId, status: decision.status, workItemId: decision.workItemId };\n },\n }),\n factory_dismiss_decision: createTool({\n id: 'factory_dismiss_decision',\n description: 'Dismiss one parked Factory proposal after the person confirms it is no longer wanted.',\n inputSchema: z.object({ decisionId: z.string().min(1) }),\n requireApproval: true,\n execute: async ({ decisionId }) => {\n const decision = await deps.workItems.dismissDeferredDecision(\n deps.scope.orgId,\n deps.scope.factoryProjectId,\n decisionId,\n now(),\n );\n if (!decision)\n throw new Error('The decision is not proposed, no longer exists, or belongs to another factory.');\n await audit(\n 'factory.run.dismissed',\n { type: 'rule_decision', id: decisionId },\n { workItemId: decision.workItemId },\n );\n return { decisionId, status: decision.status, workItemId: decision.workItemId };\n },\n }),\n factory_resolve_proposal: createTool({\n id: 'factory_resolve_proposal',\n description: 'Approve or dismiss one proposed Factory decision after the person confirms the choice.',\n inputSchema: z.object({ decisionId: z.string().min(1), resolution: z.enum(['approve', 'dismiss']) }),\n requireApproval: true,\n execute: async ({ decisionId, resolution }) => {\n const decision =\n resolution === 'approve'\n ? await deps.workItems.approveDeferredDecision(\n deps.scope.orgId,\n deps.scope.factoryProjectId,\n decisionId,\n now(),\n deps.userId,\n )\n : await deps.workItems.dismissDeferredDecision(\n deps.scope.orgId,\n deps.scope.factoryProjectId,\n decisionId,\n now(),\n );\n if (!decision) throw new Error('The proposal is no longer open or belongs to another factory.');\n await audit(\n resolution === 'approve' ? 'factory.run.approved' : 'factory.run.dismissed',\n {\n type: 'rule_decision',\n id: decisionId,\n },\n { workItemId: decision.workItemId },\n );\n return { decisionId, resolution, status: decision.status, workItemId: decision.workItemId };\n },\n }),\n factory_transition_work_item: createTool({\n id: 'factory_transition_work_item',\n description: 'Move or accept one Factory work item after the person confirms the destination stage.',\n inputSchema: z.object({\n workItemId: z.string().min(1),\n stage: z.string().max(MAX_BOARD_IDENTIFIER_LENGTH).regex(BOARD_IDENTIFIER_RE),\n }),\n requireApproval: true,\n execute: async ({ workItemId, stage }) => {\n const item = await deps.workItems.get({ orgId: deps.scope.orgId, id: workItemId });\n if (!item || item.factoryProjectId !== deps.scope.factoryProjectId) throw new Error('Work item not found.');\n const from = item.stages.length === 1 ? item.stages[0] : undefined;\n if (!from) throw new Error('The work item does not have one valid Factory stage.');\n const result = await deps.transitionService.transition({\n orgId: deps.scope.orgId,\n factoryProjectId: deps.scope.factoryProjectId,\n workItemId,\n board: boardForWorkItem(item),\n stage,\n expectedRevision: item.revision,\n actor: { type: 'human', id: deps.userId },\n ingress: { type: 'human', identity: `supervisor:${deps.userId}:${workItemId}:${item.revision}:${stage}` },\n cause: 'supervisor',\n });\n if (result.status !== 'accepted') {\n throw new Error(`The transition was rejected (${result.code}): ${result.reason}`);\n }\n return result;\n },\n }),\n factory_reconcile_labels: createTool({\n id: 'factory_reconcile_labels',\n description: 'Reconcile stale acceptance labels for one accepted work item after the person confirms the repair.',\n inputSchema: z.object({ workItemId: z.string().min(1) }),\n requireApproval: true,\n execute: async ({ workItemId }) => {\n if (!deps.reconcileAcceptanceLabels) throw new Error('Acceptance-label reconciliation is unavailable.');\n const item = await deps.workItems.get({ orgId: deps.scope.orgId, id: workItemId });\n if (!item || item.factoryProjectId !== deps.scope.factoryProjectId) throw new Error('Work item not found.');\n if (!item.acceptedAt) throw new Error('The work item has not been accepted.');\n await deps.reconcileAcceptanceLabels({ ...deps.scope, item });\n await audit('factory.work_item.labels_reconciled', { type: 'work_item', id: workItemId });\n return { workItemId, reconciled: true };\n },\n }),\n factory_revoke_binding: createTool({\n id: 'factory_revoke_binding',\n description: 'Revoke an orphaned or stale run binding after a health finding and person confirmation.',\n inputSchema: z.object({ bindingId: z.string().min(1) }),\n requireApproval: true,\n execute: async ({ bindingId }) => {\n const binding = await deps.workItems.revokeRunBinding({\n orgId: deps.scope.orgId,\n factoryProjectId: deps.scope.factoryProjectId,\n bindingId,\n revokedAt: now(),\n });\n if (!binding) throw new Error('The binding is not active, no longer exists, or belongs to another factory.');\n await audit(\n 'factory.intake.binding_updated',\n { type: 'run_binding', id: bindingId },\n {\n workItemId: binding.workItemId,\n role: binding.role,\n status: 'revoked',\n },\n );\n return { bindingId, status: binding.status, workItemId: binding.workItemId, role: binding.role };\n },\n }),\n factory_signal_session: createTool({\n id: 'factory_signal_session',\n description:\n 'Send bounded guidance to a worker session after the person confirms the exact message. Use queue only when the guidance should wait for the current run to finish.',\n inputSchema: z.object({\n sessionId: z.string().min(1),\n message: z.string().trim().min(1).max(2000),\n delivery: z.enum(['send', 'queue']).default('send'),\n }),\n requireApproval: true,\n execute: async ({ sessionId, message, delivery }) => {\n if (!deps.messageSession) throw new Error('Worker session messaging is unavailable.');\n const bindings = await deps.workItems.listRunBindings(deps.scope.orgId, deps.scope.factoryProjectId);\n const binding = bindings.find(row => row.sessionId === sessionId);\n if (!binding) throw new Error('The session does not belong to this factory.');\n await deps.messageSession({ sessionId, message, userId: deps.userId, delivery });\n await audit(\n 'factory.agent.signaled',\n { type: 'factory_session', id: sessionId },\n {\n workItemId: binding.workItemId,\n role: binding.role,\n delivery,\n },\n );\n return { sessionId, delivered: true, delivery, workItemId: binding.workItemId, role: binding.role };\n },\n }),\n };\n}\n"],"mappings":";;;;;;AA4BA,SAAgB,kCAAkC,MAAqD;CACrG,MAAM,MAAM,KAAK,8BAAc,IAAI,KAAK;CACxC,MAAM,QAAQ,OACZ,QACA,QACA,WAAoC,CAAC,MAErC,KAAK,MAAM,OAAO;EAChB,OAAO,KAAK,MAAM;EAClB,SAAS,KAAK;EACd,WAAW;EACX;EACA,SAAS,CAAC,MAAM;EAChB,kBAAkB,KAAK,MAAM;EAC7B,UAAU;GAAE,GAAG;GAAU,OAAO;EAAa;EAC7C,YAAY,IAAI;CAClB,CAAC;CAEH,OAAO;EACL,wBAAwB,WAAW;GACjC,IAAI;GACJ,aAAa;GACb,aAAa,EAAE,OAAO,EAAE,YAAY,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC;GACvD,iBAAiB;GACjB,SAAS,OAAO,EAAE,iBAAiB;IACjC,MAAM,WAAW,MAAM,KAAK,UAAU,sBACpC,KAAK,MAAM,OACX,KAAK,MAAM,kBACX,YACA,IAAI,CACN;IACA,IAAI,CAAC,UAAU,MAAM,IAAI,MAAM,8EAA8E;IAC7G,MAAM,MACJ,qBACA;KAAE,MAAM;KAAiB,IAAI;IAAW,GACxC,EAAE,YAAY,SAAS,WAAW,CACpC;IACA,OAAO;KAAE;KAAY,QAAQ,SAAS;KAAQ,YAAY,SAAS;IAAW;GAChF;EACF,CAAC;EACD,0BAA0B,WAAW;GACnC,IAAI;GACJ,aAAa;GACb,aAAa,EAAE,OAAO,EAAE,YAAY,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC;GACvD,iBAAiB;GACjB,SAAS,OAAO,EAAE,iBAAiB;IACjC,MAAM,WAAW,MAAM,KAAK,UAAU,wBACpC,KAAK,MAAM,OACX,KAAK,MAAM,kBACX,YACA,IAAI,CACN;IACA,IAAI,CAAC,UACH,MAAM,IAAI,MAAM,gFAAgF;IAClG,MAAM,MACJ,yBACA;KAAE,MAAM;KAAiB,IAAI;IAAW,GACxC,EAAE,YAAY,SAAS,WAAW,CACpC;IACA,OAAO;KAAE;KAAY,QAAQ,SAAS;KAAQ,YAAY,SAAS;IAAW;GAChF;EACF,CAAC;EACD,0BAA0B,WAAW;GACnC,IAAI;GACJ,aAAa;GACb,aAAa,EAAE,OAAO;IAAE,YAAY,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC;IAAG,YAAY,EAAE,KAAK,CAAC,WAAW,SAAS,CAAC;GAAE,CAAC;GACnG,iBAAiB;GACjB,SAAS,OAAO,EAAE,YAAY,iBAAiB;IAC7C,MAAM,WACJ,eAAe,YACX,MAAM,KAAK,UAAU,wBACnB,KAAK,MAAM,OACX,KAAK,MAAM,kBACX,YACA,IAAI,GACJ,KAAK,MACP,IACA,MAAM,KAAK,UAAU,wBACnB,KAAK,MAAM,OACX,KAAK,MAAM,kBACX,YACA,IAAI,CACN;IACN,IAAI,CAAC,UAAU,MAAM,IAAI,MAAM,+DAA+D;IAC9F,MAAM,MACJ,eAAe,YAAY,yBAAyB,yBACpD;KACE,MAAM;KACN,IAAI;IACN,GACA,EAAE,YAAY,SAAS,WAAW,CACpC;IACA,OAAO;KAAE;KAAY;KAAY,QAAQ,SAAS;KAAQ,YAAY,SAAS;IAAW;GAC5F;EACF,CAAC;EACD,8BAA8B,WAAW;GACvC,IAAI;GACJ,aAAa;GACb,aAAa,EAAE,OAAO;IACpB,YAAY,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC;IAC5B,OAAO,EAAE,OAAO,CAAC,CAAC,IAAA,GAA+B,CAAC,CAAC,MAAM,mBAAmB;GAC9E,CAAC;GACD,iBAAiB;GACjB,SAAS,OAAO,EAAE,YAAY,YAAY;IACxC,MAAM,OAAO,MAAM,KAAK,UAAU,IAAI;KAAE,OAAO,KAAK,MAAM;KAAO,IAAI;IAAW,CAAC;IACjF,IAAI,CAAC,QAAQ,KAAK,qBAAqB,KAAK,MAAM,kBAAkB,MAAM,IAAI,MAAM,sBAAsB;IAE1G,IAAI,EADS,KAAK,OAAO,WAAW,IAAI,KAAK,OAAO,KAAK,KAAA,IAC9C,MAAM,IAAI,MAAM,sDAAsD;IACjF,MAAM,SAAS,MAAM,KAAK,kBAAkB,WAAW;KACrD,OAAO,KAAK,MAAM;KAClB,kBAAkB,KAAK,MAAM;KAC7B;KACA,OAAO,iBAAiB,IAAI;KAC5B;KACA,kBAAkB,KAAK;KACvB,OAAO;MAAE,MAAM;MAAS,IAAI,KAAK;KAAO;KACxC,SAAS;MAAE,MAAM;MAAS,UAAU,cAAc,KAAK,OAAO,GAAG,WAAW,GAAG,KAAK,SAAS,GAAG;KAAQ;KACxG,OAAO;IACT,CAAC;IACD,IAAI,OAAO,WAAW,YACpB,MAAM,IAAI,MAAM,gCAAgC,OAAO,KAAK,KAAK,OAAO,QAAQ;IAElF,OAAO;GACT;EACF,CAAC;EACD,0BAA0B,WAAW;GACnC,IAAI;GACJ,aAAa;GACb,aAAa,EAAE,OAAO,EAAE,YAAY,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC;GACvD,iBAAiB;GACjB,SAAS,OAAO,EAAE,iBAAiB;IACjC,IAAI,CAAC,KAAK,2BAA2B,MAAM,IAAI,MAAM,iDAAiD;IACtG,MAAM,OAAO,MAAM,KAAK,UAAU,IAAI;KAAE,OAAO,KAAK,MAAM;KAAO,IAAI;IAAW,CAAC;IACjF,IAAI,CAAC,QAAQ,KAAK,qBAAqB,KAAK,MAAM,kBAAkB,MAAM,IAAI,MAAM,sBAAsB;IAC1G,IAAI,CAAC,KAAK,YAAY,MAAM,IAAI,MAAM,sCAAsC;IAC5E,MAAM,KAAK,0BAA0B;KAAE,GAAG,KAAK;KAAO;IAAK,CAAC;IAC5D,MAAM,MAAM,uCAAuC;KAAE,MAAM;KAAa,IAAI;IAAW,CAAC;IACxF,OAAO;KAAE;KAAY,YAAY;IAAK;GACxC;EACF,CAAC;EACD,wBAAwB,WAAW;GACjC,IAAI;GACJ,aAAa;GACb,aAAa,EAAE,OAAO,EAAE,WAAW,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC;GACtD,iBAAiB;GACjB,SAAS,OAAO,EAAE,gBAAgB;IAChC,MAAM,UAAU,MAAM,KAAK,UAAU,iBAAiB;KACpD,OAAO,KAAK,MAAM;KAClB,kBAAkB,KAAK,MAAM;KAC7B;KACA,WAAW,IAAI;IACjB,CAAC;IACD,IAAI,CAAC,SAAS,MAAM,IAAI,MAAM,6EAA6E;IAC3G,MAAM,MACJ,kCACA;KAAE,MAAM;KAAe,IAAI;IAAU,GACrC;KACE,YAAY,QAAQ;KACpB,MAAM,QAAQ;KACd,QAAQ;IACV,CACF;IACA,OAAO;KAAE;KAAW,QAAQ,QAAQ;KAAQ,YAAY,QAAQ;KAAY,MAAM,QAAQ;IAAK;GACjG;EACF,CAAC;EACD,wBAAwB,WAAW;GACjC,IAAI;GACJ,aACE;GACF,aAAa,EAAE,OAAO;IACpB,WAAW,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC;IAC3B,SAAS,EAAE,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,GAAI;IAC1C,UAAU,EAAE,KAAK,CAAC,QAAQ,OAAO,CAAC,CAAC,CAAC,QAAQ,MAAM;GACpD,CAAC;GACD,iBAAiB;GACjB,SAAS,OAAO,EAAE,WAAW,SAAS,eAAe;IACnD,IAAI,CAAC,KAAK,gBAAgB,MAAM,IAAI,MAAM,0CAA0C;IAEpF,MAAM,WAAU,MADO,KAAK,UAAU,gBAAgB,KAAK,MAAM,OAAO,KAAK,MAAM,gBAAgB,EAAA,CAC1E,MAAK,QAAO,IAAI,cAAc,SAAS;IAChE,IAAI,CAAC,SAAS,MAAM,IAAI,MAAM,8CAA8C;IAC5E,MAAM,KAAK,eAAe;KAAE;KAAW;KAAS,QAAQ,KAAK;KAAQ;IAAS,CAAC;IAC/E,MAAM,MACJ,0BACA;KAAE,MAAM;KAAmB,IAAI;IAAU,GACzC;KACE,YAAY,QAAQ;KACpB,MAAM,QAAQ;KACd;IACF,CACF;IACA,OAAO;KAAE;KAAW,WAAW;KAAM;KAAU,YAAY,QAAQ;KAAY,MAAM,QAAQ;IAAK;GACpG;EACF,CAAC;CACH;AACF"}
1
+ {"version":3,"file":"write-tools.js","names":[],"sources":["../../src/supervisor/write-tools.ts"],"sourcesContent":["import { createTool } from '@mastra/core/tools';\nimport { z } from 'zod';\n\nimport { boardForWorkItem } from '../boards/index.js';\nimport type { IntegrationTools } from '../integrations/base.js';\nimport type { FactoryTransitionService } from '../rules/transition-service.js';\nimport { BOARD_IDENTIFIER_RE, MAX_BOARD_IDENTIFIER_LENGTH } from '../rules/validation.js';\nimport type { AuditAction } from '../storage/domains/audit/actions.js';\nimport type { AuditRecorder } from '../storage/domains/audit/domain.js';\nimport type { WorkItemRow, WorkItemsStorage } from '../storage/domains/work-items/base.js';\nimport type { SupervisorScope } from './read-tools.js';\nimport type { WorkerMessageResult } from './session-messaging.js';\n\ninterface SupervisorWriteDependencies {\n scope: SupervisorScope;\n userId: string;\n workItems: WorkItemsStorage;\n audit: AuditRecorder;\n transitionService: FactoryTransitionService;\n reconcileAcceptanceLabels?: (input: { orgId: string; factoryProjectId: string; item: WorkItemRow }) => Promise<void>;\n messageSession?: (input: {\n sessionId: string;\n message: string;\n userId: string;\n delivery: 'send' | 'queue';\n }) => Promise<WorkerMessageResult>;\n now?: () => Date;\n}\n\nexport function createFactorySupervisorWriteTools(deps: SupervisorWriteDependencies): IntegrationTools {\n const now = deps.now ?? (() => new Date());\n const audit = async (\n action: AuditAction,\n target: { type: string; id: string },\n metadata: Record<string, unknown> = {},\n ) =>\n deps.audit.record({\n orgId: deps.scope.orgId,\n actorId: deps.userId,\n actorType: 'human',\n action,\n targets: [target],\n factoryProjectId: deps.scope.factoryProjectId,\n metadata: { ...metadata, cause: 'supervisor' },\n occurredAt: now(),\n });\n\n return {\n factory_retry_decision: createTool({\n id: 'factory_retry_decision',\n description: 'Retry one failed Factory decision after the person confirms the repair.',\n inputSchema: z.object({ decisionId: z.string().min(1) }),\n requireApproval: true,\n execute: async ({ decisionId }) => {\n const decision = await deps.workItems.retryDeferredDecision(\n deps.scope.orgId,\n deps.scope.factoryProjectId,\n decisionId,\n now(),\n );\n if (!decision) throw new Error('The decision is not failed, no longer exists, or belongs to another factory.');\n await audit(\n 'factory.run.retry',\n { type: 'rule_decision', id: decisionId },\n { workItemId: decision.workItemId },\n );\n return { decisionId, status: decision.status, workItemId: decision.workItemId };\n },\n }),\n factory_dismiss_decision: createTool({\n id: 'factory_dismiss_decision',\n description: 'Dismiss one parked Factory proposal after the person confirms it is no longer wanted.',\n inputSchema: z.object({ decisionId: z.string().min(1) }),\n requireApproval: true,\n execute: async ({ decisionId }) => {\n const decision = await deps.workItems.dismissDeferredDecision(\n deps.scope.orgId,\n deps.scope.factoryProjectId,\n decisionId,\n now(),\n );\n if (!decision)\n throw new Error('The decision is not proposed, no longer exists, or belongs to another factory.');\n await audit(\n 'factory.run.dismissed',\n { type: 'rule_decision', id: decisionId },\n { workItemId: decision.workItemId },\n );\n return { decisionId, status: decision.status, workItemId: decision.workItemId };\n },\n }),\n factory_resolve_proposal: createTool({\n id: 'factory_resolve_proposal',\n description: 'Approve or dismiss one proposed Factory decision after the person confirms the choice.',\n inputSchema: z.object({ decisionId: z.string().min(1), resolution: z.enum(['approve', 'dismiss']) }),\n requireApproval: true,\n execute: async ({ decisionId, resolution }) => {\n const decision =\n resolution === 'approve'\n ? await deps.workItems.approveDeferredDecision(\n deps.scope.orgId,\n deps.scope.factoryProjectId,\n decisionId,\n now(),\n deps.userId,\n )\n : await deps.workItems.dismissDeferredDecision(\n deps.scope.orgId,\n deps.scope.factoryProjectId,\n decisionId,\n now(),\n );\n if (!decision) throw new Error('The proposal is no longer open or belongs to another factory.');\n await audit(\n resolution === 'approve' ? 'factory.run.approved' : 'factory.run.dismissed',\n {\n type: 'rule_decision',\n id: decisionId,\n },\n { workItemId: decision.workItemId },\n );\n return { decisionId, resolution, status: decision.status, workItemId: decision.workItemId };\n },\n }),\n factory_transition_work_item: createTool({\n id: 'factory_transition_work_item',\n description: 'Move or accept one Factory work item after the person confirms the destination stage.',\n inputSchema: z.object({\n workItemId: z.string().min(1),\n stage: z.string().max(MAX_BOARD_IDENTIFIER_LENGTH).regex(BOARD_IDENTIFIER_RE),\n }),\n requireApproval: true,\n execute: async ({ workItemId, stage }) => {\n const item = await deps.workItems.get({ orgId: deps.scope.orgId, id: workItemId });\n if (!item || item.factoryProjectId !== deps.scope.factoryProjectId) throw new Error('Work item not found.');\n const from = item.stages.length === 1 ? item.stages[0] : undefined;\n if (!from) throw new Error('The work item does not have one valid Factory stage.');\n const result = await deps.transitionService.transition({\n orgId: deps.scope.orgId,\n factoryProjectId: deps.scope.factoryProjectId,\n workItemId,\n board: boardForWorkItem(item),\n stage,\n expectedRevision: item.revision,\n actor: { type: 'human', id: deps.userId },\n ingress: { type: 'human', identity: `supervisor:${deps.userId}:${workItemId}:${item.revision}:${stage}` },\n cause: 'supervisor',\n });\n if (result.status !== 'accepted') {\n throw new Error(`The transition was rejected (${result.code}): ${result.reason}`);\n }\n return result;\n },\n }),\n factory_reconcile_labels: createTool({\n id: 'factory_reconcile_labels',\n description: 'Reconcile stale acceptance labels for one accepted work item after the person confirms the repair.',\n inputSchema: z.object({ workItemId: z.string().min(1) }),\n requireApproval: true,\n execute: async ({ workItemId }) => {\n if (!deps.reconcileAcceptanceLabels) throw new Error('Acceptance-label reconciliation is unavailable.');\n const item = await deps.workItems.get({ orgId: deps.scope.orgId, id: workItemId });\n if (!item || item.factoryProjectId !== deps.scope.factoryProjectId) throw new Error('Work item not found.');\n if (!item.acceptedAt) throw new Error('The work item has not been accepted.');\n await deps.reconcileAcceptanceLabels({ ...deps.scope, item });\n await audit('factory.work_item.labels_reconciled', { type: 'work_item', id: workItemId });\n return { workItemId, reconciled: true };\n },\n }),\n factory_revoke_binding: createTool({\n id: 'factory_revoke_binding',\n description: 'Revoke an orphaned or stale run binding after a health finding and person confirmation.',\n inputSchema: z.object({ bindingId: z.string().min(1) }),\n requireApproval: true,\n execute: async ({ bindingId }) => {\n const binding = await deps.workItems.revokeRunBinding({\n orgId: deps.scope.orgId,\n factoryProjectId: deps.scope.factoryProjectId,\n bindingId,\n revokedAt: now(),\n });\n if (!binding) throw new Error('The binding is not active, no longer exists, or belongs to another factory.');\n await audit(\n 'factory.intake.binding_updated',\n { type: 'run_binding', id: bindingId },\n {\n workItemId: binding.workItemId,\n role: binding.role,\n status: 'revoked',\n },\n );\n return { bindingId, status: binding.status, workItemId: binding.workItemId, role: binding.role };\n },\n }),\n factory_signal_session: createTool({\n id: 'factory_signal_session',\n description:\n 'Send bounded guidance to a worker session after the person confirms the exact message. Use queue only when the guidance should wait for the current run to finish.',\n inputSchema: z.object({\n sessionId: z.string().min(1),\n message: z.string().trim().min(1).max(2000),\n delivery: z.enum(['send', 'queue']).default('send'),\n }),\n requireApproval: true,\n execute: async ({ sessionId, message, delivery }) => {\n if (!deps.messageSession) throw new Error('Worker session messaging is unavailable.');\n const bindings = await deps.workItems.listRunBindings(deps.scope.orgId, deps.scope.factoryProjectId);\n const binding = bindings.find(row => row.sessionId === sessionId);\n if (!binding) throw new Error('The session does not belong to this factory.');\n const result = await deps.messageSession({ sessionId, message, userId: deps.userId, delivery });\n if (result?.status === 'interrupted') {\n return {\n sessionId,\n delivered: false,\n status: 'interrupted',\n delivery,\n workItemId: binding.workItemId,\n role: binding.role,\n };\n }\n await audit(\n 'factory.agent.signaled',\n { type: 'factory_session', id: sessionId },\n {\n workItemId: binding.workItemId,\n role: binding.role,\n delivery,\n },\n );\n return { sessionId, delivered: true, delivery, workItemId: binding.workItemId, role: binding.role };\n },\n }),\n };\n}\n"],"mappings":"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"}
@@ -20,6 +20,12 @@ export declare function resolveLocalFactorySkillsPath(cwd?: string): string | un
20
20
  export declare const FACTORY_SKILL_NAMES: Set<string>;
21
21
  /** Review skills only sessions with an active review run binding may discover or load. */
22
22
  export declare const REVIEW_ONLY_FACTORY_SKILLS: Set<string>;
23
+ /**
24
+ * Rescan a session's skill cache so a role gained after the cache was built
25
+ * (a review binding minted after the session's workspace resolved) takes effect.
26
+ * The source still checks the live binding, so this never widens access.
27
+ */
28
+ export declare function rescanFactorySkills(skills: NonNullable<Workspace['skills']>): Promise<void>;
23
29
  export declare class FactorySkillSource implements SkillSource {
24
30
  #private;
25
31
  readonly fallback: SkillSource;
@@ -63,7 +69,7 @@ export interface CreateWorkspaceFactoryOptions {
63
69
  /** Work-items storage used to resolve the session's run-binding role, so
64
70
  * review-board sessions get the reviewer PAT as `GH_TOKEN`. Optional —
65
71
  * without it every session uses the default (worker) PAT. */
66
- workItems?: Pick<WorkItemsStorage, 'findRunBindingBySession'>;
72
+ workItems?: Pick<WorkItemsStorage, 'findActiveRunBindingForSession'>;
67
73
  /** Projects storage used to authorize workspace-free supervisor sessions. */
68
74
  projects?: Pick<FactoryProjectsStorage, 'get'>;
69
75
  /** Runtime workspace/token registrations invalidated when a session retires. */
@@ -1 +1 @@
1
- {"version":3,"file":"workspace.d.ts","sourceRoot":"","sources":["../src/workspace.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"workspace.d.ts","sourceRoot":"","sources":["../src/workspace.ts"],"names":[],"mappings":"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"}
package/dist/workspace.js CHANGED
@@ -6,7 +6,6 @@ import { registerGithubPatKind, registerGithubTokenInjector } from "./integratio
6
6
  import { requireExec } from "./sandbox/materialization.js";
7
7
  import { createSessionSetupHook, evictSessionSandbox, getSessionSandbox, hasFailedSetupCommand, recordFailedSetupCommand, resolveSessionWorkdir } from "./sandbox/session-sandbox.js";
8
8
  import { DEFAULT_COMMAND_TIMEOUT_MS, SetupCommandError, checkoutSessionBranch, materializeRepo, runSetupCommand, runTeardownCommand } from "./integrations/github/sandbox.js";
9
- import { getFactorySessionAddress } from "./rules/binding-context.js";
10
9
  import { parseSupervisorResourceId } from "./supervisor/session.js";
11
10
  import path, { dirname, join } from "path";
12
11
  import { LocalSkillSource, Workspace } from "@mastra/core/workspace";
@@ -52,6 +51,22 @@ const REVIEW_ONLY_FACTORY_SKILLS = /* @__PURE__ */ new Set([
52
51
  "factory-rereview",
53
52
  "factory-review"
54
53
  ]);
54
+ /**
55
+ * Skill caches rescanned outside the workspace resolver. The resolver records
56
+ * which role each cache was last scanned for; a rescan it did not perform makes
57
+ * that record untrustworthy, so the next reuse must rescan again.
58
+ */
59
+ const rescannedOutsideResolver = /* @__PURE__ */ new WeakMap();
60
+ /**
61
+ * Rescan a session's skill cache so a role gained after the cache was built
62
+ * (a review binding minted after the session's workspace resolved) takes effect.
63
+ * The source still checks the live binding, so this never widens access.
64
+ */
65
+ async function rescanFactorySkills(skills) {
66
+ const pending = skills.refresh();
67
+ rescannedOutsideResolver.set(skills, pending.catch(() => {}));
68
+ await pending;
69
+ }
55
70
  var FactorySkillSource = class {
56
71
  fallback;
57
72
  isReviewSession;
@@ -225,6 +240,7 @@ function createWorkspaceFactory(options = {}) {
225
240
  const constructedWorkspaces = /* @__PURE__ */ new Map();
226
241
  const skillCacheReviewState = /* @__PURE__ */ new Map();
227
242
  const skillCacheRefreshes = /* @__PURE__ */ new Map();
243
+ const skillReviewChecks = /* @__PURE__ */ new Map();
228
244
  return async ({ requestContext, mastra, skillExtension }) => {
229
245
  const ctx = requestContext.get("controller");
230
246
  const supervisorProjectId = parseSupervisorResourceId(ctx?.resourceId);
@@ -357,19 +373,28 @@ function createWorkspaceFactory(options = {}) {
357
373
  projectPath: workdir,
358
374
  projectName: repoFullName
359
375
  });
376
+ const findSessionBinding = async () => {
377
+ const binding = await workItems.findActiveRunBindingForSession({
378
+ orgId: session.orgId,
379
+ factoryProjectId: connection.factoryProjectId,
380
+ sessionId: session.sessionId
381
+ });
382
+ if (!binding || !ctx?.threadId) return binding;
383
+ return binding.threadId === ctx.threadId && binding.resourceId === ctx.resourceId ? binding : null;
384
+ };
360
385
  const isReviewSession = async () => {
361
386
  if (!workItems) return false;
362
387
  try {
363
- const address = getFactorySessionAddress(requestContext);
364
- return isActiveReviewBinding(address ? await workItems.findRunBindingBySession(address) : null, session.orgId);
388
+ return isActiveReviewBinding(await findSessionBinding(), session.orgId);
365
389
  } catch {
366
390
  return false;
367
391
  }
368
392
  };
369
- const effectiveSkillExtension = skillExtension ?? createFactorySkillExtension(isReviewSession);
393
+ const effectiveSkillExtension = skillExtension ?? createFactorySkillExtension(() => (skillReviewChecks.get(workspaceId) ?? isReviewSession)());
370
394
  const extensionId = effectiveSkillExtension ? `-${effectiveSkillExtension.id}` : "";
371
395
  const workspaceId = `${WORKSPACE_ID_PREFIX}-${projectRepository.id}-${session.id}${extensionId}`;
372
396
  const workspaceGeneration = workspaceRegistry.generation(session.sessionId);
397
+ if (!skillExtension) skillReviewChecks.set(workspaceId, isReviewSession);
373
398
  const configDir = DEFAULT_CONFIG_DIR;
374
399
  const getRepositoryAccess = () => sourceControl.versionControl.getRepositoryAccess({
375
400
  orgId: session.orgId,
@@ -383,8 +408,7 @@ function createWorkspaceFactory(options = {}) {
383
408
  const resolveGithubPatKind = async (fallback) => {
384
409
  if (!workItems) return "default";
385
410
  try {
386
- const address = getFactorySessionAddress(requestContext);
387
- return isActiveReviewBinding(address ? await workItems.findRunBindingBySession(address) : null, session.orgId) ? "reviewer" : "default";
411
+ return isActiveReviewBinding(await findSessionBinding(), session.orgId) ? "reviewer" : "default";
388
412
  } catch {
389
413
  return fallback;
390
414
  }
@@ -464,6 +488,15 @@ function createWorkspaceFactory(options = {}) {
464
488
  if (existing) {
465
489
  existing.setToolsConfig(MASTRACODE_WORKSPACE_TOOLS);
466
490
  if (!skillExtension) {
491
+ const consumeOutsideRescan = async () => {
492
+ const outside = existing.skills && rescannedOutsideResolver.get(existing.skills);
493
+ if (!outside) return false;
494
+ await outside;
495
+ if (rescannedOutsideResolver.get(existing.skills) === outside) rescannedOutsideResolver.delete(existing.skills);
496
+ skillCacheReviewState.delete(workspaceId);
497
+ return true;
498
+ };
499
+ await consumeOutsideRescan();
467
500
  let isReview = await isReviewSession();
468
501
  for (;;) {
469
502
  const inFlight = skillCacheRefreshes.get(workspaceId);
@@ -472,6 +505,10 @@ function createWorkspaceFactory(options = {}) {
472
505
  isReview = await isReviewSession();
473
506
  continue;
474
507
  }
508
+ if (await consumeOutsideRescan()) {
509
+ isReview = await isReviewSession();
510
+ continue;
511
+ }
475
512
  if (skillCacheReviewState.get(workspaceId) === isReview) break;
476
513
  const target = isReview;
477
514
  const pending = (async () => {
@@ -582,6 +619,7 @@ function createWorkspaceFactory(options = {}) {
582
619
  githubTokenInjectors.delete(workspaceId);
583
620
  constructedWorkspaces.delete(workspaceId);
584
621
  skillCacheReviewState.delete(workspaceId);
622
+ skillReviewChecks.delete(workspaceId);
585
623
  evictSessionSandbox(session.id);
586
624
  await mastra?.removeWorkspace?.(workspaceId);
587
625
  })) throw new Error(`Factory session ${session.sessionId} was retired during workspace materialization`);
@@ -590,6 +628,6 @@ function createWorkspaceFactory(options = {}) {
590
628
  };
591
629
  }
592
630
  //#endregion
593
- export { BUNDLED_FACTORY_SKILLS_PATH, FACTORY_SKILL_NAMES, FactorySkillSource, FactoryWorkspaceRegistry, REVIEW_ONLY_FACTORY_SKILLS, createWorkspaceFactory, resolveLocalFactorySkillsPath };
631
+ export { BUNDLED_FACTORY_SKILLS_PATH, FACTORY_SKILL_NAMES, FactorySkillSource, FactoryWorkspaceRegistry, REVIEW_ONLY_FACTORY_SKILLS, createWorkspaceFactory, rescanFactorySkills, resolveLocalFactorySkillsPath };
594
632
 
595
633
  //# sourceMappingURL=workspace.js.map