@mastra/factory 0.17.3-alpha.5 → 0.18.0-alpha.10
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.
- package/dist/auth.d.ts.map +1 -1
- package/dist/auth.js +15 -4
- package/dist/auth.js.map +1 -1
- package/dist/boards/review.d.ts +2 -0
- package/dist/boards/review.d.ts.map +1 -1
- package/dist/boards/review.js +16 -6
- package/dist/boards/review.js.map +1 -1
- package/dist/boards/transition-policy.d.ts +3 -3
- package/dist/boards/transition-policy.d.ts.map +1 -1
- package/dist/boards/transition-policy.js.map +1 -1
- package/dist/boards/work-transition-policy.d.ts.map +1 -1
- package/dist/boards/work-transition-policy.js +13 -3
- package/dist/boards/work-transition-policy.js.map +1 -1
- package/dist/capabilities/intake.d.ts +2 -0
- package/dist/capabilities/intake.d.ts.map +1 -1
- package/dist/factory.d.ts.map +1 -1
- package/dist/factory.js +14 -3
- package/dist/factory.js.map +1 -1
- package/dist/integrations/github/default-rules.d.ts +17 -1
- package/dist/integrations/github/default-rules.d.ts.map +1 -1
- package/dist/integrations/github/default-rules.js +30 -6
- package/dist/integrations/github/default-rules.js.map +1 -1
- package/dist/integrations/github/reconcile-worker.d.ts.map +1 -1
- package/dist/integrations/github/reconcile-worker.js.map +1 -1
- package/dist/integrations/github/routes.d.ts.map +1 -1
- package/dist/integrations/github/routes.js +1 -0
- package/dist/integrations/github/routes.js.map +1 -1
- package/dist/integrations/github/rules.d.ts.map +1 -1
- package/dist/integrations/github/rules.js +48 -2
- package/dist/integrations/github/rules.js.map +1 -1
- package/dist/integrations/github/sandbox.d.ts.map +1 -1
- package/dist/integrations/github/sandbox.js.map +1 -1
- package/dist/integrations/gitlab/api.d.ts.map +1 -1
- package/dist/integrations/gitlab/api.js.map +1 -1
- package/dist/integrations/gitlab/default-rules.d.ts.map +1 -1
- package/dist/integrations/gitlab/default-rules.js +1 -0
- package/dist/integrations/gitlab/default-rules.js.map +1 -1
- package/dist/integrations/gitlab/reconciler.d.ts.map +1 -1
- package/dist/integrations/gitlab/reconciler.js.map +1 -1
- package/dist/integrations/gitlab/reconciliation-config.d.ts.map +1 -1
- package/dist/integrations/gitlab/reconciliation-config.js.map +1 -1
- package/dist/integrations/gitlab/routes.d.ts.map +1 -1
- package/dist/integrations/gitlab/routes.js +1 -0
- package/dist/integrations/gitlab/routes.js.map +1 -1
- package/dist/integrations/gitlab/rules.d.ts.map +1 -1
- package/dist/integrations/gitlab/rules.js +66 -0
- package/dist/integrations/gitlab/rules.js.map +1 -1
- package/dist/integrations/gitlab/version-control.d.ts.map +1 -1
- package/dist/integrations/gitlab/version-control.js.map +1 -1
- package/dist/integrations/incidentio/api.d.ts.map +1 -1
- package/dist/integrations/incidentio/api.js.map +1 -1
- package/dist/integrations/incidentio/intake.d.ts.map +1 -1
- package/dist/integrations/incidentio/intake.js.map +1 -1
- package/dist/integrations/issue-reconcile-worker.d.ts.map +1 -1
- package/dist/integrations/issue-reconcile-worker.js.map +1 -1
- package/dist/integrations/linear/default-rules.d.ts +2 -1
- package/dist/integrations/linear/default-rules.d.ts.map +1 -1
- package/dist/integrations/linear/default-rules.js +1 -0
- package/dist/integrations/linear/default-rules.js.map +1 -1
- package/dist/integrations/linear/integration.d.ts.map +1 -1
- package/dist/integrations/linear/integration.js +2 -0
- package/dist/integrations/linear/integration.js.map +1 -1
- package/dist/integrations/linear/issue-reconciler.d.ts.map +1 -1
- package/dist/integrations/linear/issue-reconciler.js +3 -0
- package/dist/integrations/linear/issue-reconciler.js.map +1 -1
- package/dist/integrations/linear/routes.d.ts.map +1 -1
- package/dist/integrations/linear/routes.js +2 -1
- package/dist/integrations/linear/routes.js.map +1 -1
- package/dist/integrations/linear/rules.d.ts +1 -0
- package/dist/integrations/linear/rules.d.ts.map +1 -1
- package/dist/integrations/linear/rules.js.map +1 -1
- package/dist/integrations/platform/linear/event-worker.js.map +1 -1
- package/dist/integrations/slack/emoji-shortcodes.generated.js.map +1 -1
- package/dist/integrations/slack/feed-publisher.d.ts.map +1 -1
- package/dist/integrations/slack/feed-publisher.js.map +1 -1
- package/dist/integrations/slack/slack.d.ts +7 -7
- package/dist/integrations/slack/slack.d.ts.map +1 -1
- package/dist/integrations/slack/slack.js +157 -23
- package/dist/integrations/slack/slack.js.map +1 -1
- package/dist/integrations/subscription-session.d.ts +3 -1
- package/dist/integrations/subscription-session.d.ts.map +1 -1
- package/dist/integrations/subscription-session.js +4 -2
- package/dist/integrations/subscription-session.js.map +1 -1
- package/dist/platform-auth-host.d.ts +4 -0
- package/dist/platform-auth-host.d.ts.map +1 -0
- package/dist/platform-auth-host.js +18 -0
- package/dist/platform-auth-host.js.map +1 -0
- package/dist/routes/contracts.d.ts +23 -0
- package/dist/routes/contracts.d.ts.map +1 -1
- package/dist/routes/contracts.js +21 -0
- package/dist/routes/contracts.js.map +1 -1
- package/dist/routes/intake.d.ts.map +1 -1
- package/dist/routes/intake.js +15 -1
- package/dist/routes/intake.js.map +1 -1
- package/dist/routes/projects.d.ts +22 -2
- package/dist/routes/projects.d.ts.map +1 -1
- package/dist/routes/projects.js +101 -0
- package/dist/routes/projects.js.map +1 -1
- package/dist/routes/surface.d.ts +1 -1
- package/dist/routes/surface.d.ts.map +1 -1
- package/dist/routes/surface.js +47 -6
- package/dist/routes/surface.js.map +1 -1
- package/dist/routes/work-items.d.ts.map +1 -1
- package/dist/routes/work-items.js +6 -1
- package/dist/routes/work-items.js.map +1 -1
- package/dist/rules/dispatch-errors.d.ts.map +1 -1
- package/dist/rules/dispatch-errors.js +4 -0
- package/dist/rules/dispatch-errors.js.map +1 -1
- package/dist/rules/dispatcher.d.ts.map +1 -1
- package/dist/rules/dispatcher.js +14 -6
- package/dist/rules/dispatcher.js.map +1 -1
- package/dist/rules/processor.d.ts.map +1 -1
- package/dist/rules/processor.js +9 -1
- package/dist/rules/processor.js.map +1 -1
- package/dist/rules/review-source-tool.d.ts +103 -0
- package/dist/rules/review-source-tool.d.ts.map +1 -0
- package/dist/rules/review-source-tool.js +109 -0
- package/dist/rules/review-source-tool.js.map +1 -0
- package/dist/rules/start-coordinator.d.ts +7 -1
- package/dist/rules/start-coordinator.d.ts.map +1 -1
- package/dist/rules/start-coordinator.js +56 -2
- package/dist/rules/start-coordinator.js.map +1 -1
- package/dist/rules/tools.d.ts +1 -0
- package/dist/rules/tools.d.ts.map +1 -1
- package/dist/rules/tools.js +107 -32
- package/dist/rules/tools.js.map +1 -1
- package/dist/rules/transition-service.d.ts +4 -4
- package/dist/rules/transition-service.d.ts.map +1 -1
- package/dist/rules/transition-service.js +3 -2
- package/dist/rules/transition-service.js.map +1 -1
- package/dist/rules/types.d.ts +2 -0
- package/dist/rules/types.d.ts.map +1 -1
- package/dist/rules/types.js.map +1 -1
- package/dist/sandbox/materialization.d.ts +5 -1
- package/dist/sandbox/materialization.d.ts.map +1 -1
- package/dist/sandbox/materialization.js.map +1 -1
- package/dist/sandbox/session-sandbox.d.ts +13 -1
- package/dist/sandbox/session-sandbox.d.ts.map +1 -1
- package/dist/sandbox/session-sandbox.js.map +1 -1
- package/dist/session/factory-session.d.ts +14 -4
- package/dist/session/factory-session.d.ts.map +1 -1
- package/dist/session/factory-session.js +32 -11
- package/dist/session/factory-session.js.map +1 -1
- package/dist/session/work-item-repository.d.ts +21 -0
- package/dist/session/work-item-repository.d.ts.map +1 -0
- package/dist/session/work-item-repository.js +91 -0
- package/dist/session/work-item-repository.js.map +1 -0
- package/dist/skills/service.d.ts.map +1 -1
- package/dist/skills/service.js +16 -6
- package/dist/skills/service.js.map +1 -1
- package/dist/storage/domains/intake/base.d.ts +1 -0
- package/dist/storage/domains/intake/base.d.ts.map +1 -1
- package/dist/storage/domains/intake/base.js.map +1 -1
- package/dist/storage/domains/integrations/base.d.ts.map +1 -1
- package/dist/storage/domains/integrations/base.js.map +1 -1
- package/dist/storage/domains/work-items/base.d.ts +15 -2
- package/dist/storage/domains/work-items/base.d.ts.map +1 -1
- package/dist/storage/domains/work-items/base.js +31 -1
- package/dist/storage/domains/work-items/base.js.map +1 -1
- package/dist/supervisor/session-messaging.d.ts +4 -1
- package/dist/supervisor/session-messaging.d.ts.map +1 -1
- package/dist/supervisor/session-messaging.js +8 -2
- package/dist/supervisor/session-messaging.js.map +1 -1
- package/dist/supervisor/write-tools.d.ts +2 -1
- package/dist/supervisor/write-tools.d.ts.map +1 -1
- package/dist/supervisor/write-tools.js +9 -2
- package/dist/supervisor/write-tools.js.map +1 -1
- package/dist/workspace.d.ts +7 -1
- package/dist/workspace.d.ts.map +1 -1
- package/dist/workspace.js +53 -14
- package/dist/workspace.js.map +1 -1
- package/factory-skills/factory-complete-issue/SKILL.md +4 -2
- package/factory-skills/factory-gitlab-rereview/SKILL.md +3 -2
- package/factory-skills/factory-gitlab-review/SKILL.md +19 -3
- package/factory-skills/factory-plan/SKILL.md +11 -0
- package/factory-skills/factory-rereview/SKILL.md +37 -12
- package/factory-skills/factory-review/SKILL.md +37 -12
- 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<
|
|
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":"
|
|
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
|
-
|
|
10
|
-
|
|
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<
|
|
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<
|
|
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;
|
|
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":"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"}
|
|
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":";;;;;;AA6BA,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;IAE5E,KAAI,MADiB,KAAK,eAAe;KAAE;KAAW;KAAS,QAAQ,KAAK;KAAQ;IAAS,CAAC,EAAA,EAClF,WAAW,eACrB,OAAO;KACL;KACA,WAAW;KACX,QAAQ;KACR;KACA,YAAY,QAAQ;KACpB,MAAM,QAAQ;IAChB;IAEF,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"}
|
package/dist/workspace.d.ts
CHANGED
|
@@ -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, '
|
|
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. */
|
package/dist/workspace.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"workspace.d.ts","sourceRoot":"","sources":["../src/workspace.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,iBAAiB,EAAE,MAAM,4CAA4C,CAAC;AAE/E,OAAO,KAAK,EAAE,mBAAmB,EAA2B,MAAM,mCAAmC,CAAC;AAItG,OAAO,EAAoB,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACrE,OAAO,KAAK,EAEV,WAAW,EACX,gBAAgB,EAChB,eAAe,EACf,gBAAgB,EACjB,MAAM,wBAAwB,CAAC;AAEhC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mCAAmC,CAAC;AACxE,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,cAAc,CAAC;AAC/D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,sCAAsC,CAAC;
|
|
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);
|
|
@@ -273,16 +289,16 @@ function createWorkspaceFactory(options = {}) {
|
|
|
273
289
|
await guardedSetup(args);
|
|
274
290
|
if (workspaceRegistry.generation(session.sessionId) !== workspaceGeneration) throw retiredError();
|
|
275
291
|
const target = requireExec(args.sandbox);
|
|
276
|
-
const publishStartSideEffects = () => {
|
|
277
|
-
storage.sessions.setSandbox({
|
|
292
|
+
const publishStartSideEffects = async () => {
|
|
293
|
+
await storage.sessions.setSandbox({
|
|
278
294
|
id: session.id,
|
|
279
|
-
sandboxId: target.id,
|
|
295
|
+
sandboxId: target.sandboxId ?? target.id,
|
|
280
296
|
sandboxWorkdir: sessionEntry.workdir ?? ""
|
|
281
|
-
})
|
|
297
|
+
});
|
|
282
298
|
constructedWorkspaces.get(workspaceId)?.skills?.refresh().catch(() => {});
|
|
283
299
|
};
|
|
284
300
|
if (!githubProvider) {
|
|
285
|
-
publishStartSideEffects();
|
|
301
|
+
await publishStartSideEffects();
|
|
286
302
|
return;
|
|
287
303
|
}
|
|
288
304
|
const existingRegistration = githubTokenInjectors.get(workspaceId);
|
|
@@ -296,7 +312,7 @@ function createWorkspaceFactory(options = {}) {
|
|
|
296
312
|
existingRegistration.ghToken = freshToken;
|
|
297
313
|
};
|
|
298
314
|
existingRegistration.inject(existingRegistration.ghToken);
|
|
299
|
-
publishStartSideEffects();
|
|
315
|
+
await publishStartSideEffects();
|
|
300
316
|
return;
|
|
301
317
|
}
|
|
302
318
|
const patKind = await resolveGithubPatKind("default");
|
|
@@ -321,11 +337,12 @@ function createWorkspaceFactory(options = {}) {
|
|
|
321
337
|
};
|
|
322
338
|
githubTokenInjectors.set(workspaceId, tokenRegistration);
|
|
323
339
|
registerGithubTokenContext(tokenRegistration);
|
|
324
|
-
publishStartSideEffects();
|
|
340
|
+
await publishStartSideEffects();
|
|
325
341
|
};
|
|
326
342
|
const constructSessionEntry = () => getSessionSandbox(session.id, repoFullName, () => {
|
|
327
343
|
const sandbox = createSessionSandboxInstance({
|
|
328
344
|
sessionId: session.id,
|
|
345
|
+
sandboxId: session.sandboxId ?? void 0,
|
|
329
346
|
repoFullName,
|
|
330
347
|
setupCommand: projectRepository.setupCommand ?? void 0,
|
|
331
348
|
getRepositoryAccess: () => sourceControl.versionControl.getRepositoryAccess({
|
|
@@ -357,19 +374,28 @@ function createWorkspaceFactory(options = {}) {
|
|
|
357
374
|
projectPath: workdir,
|
|
358
375
|
projectName: repoFullName
|
|
359
376
|
});
|
|
377
|
+
const findSessionBinding = async () => {
|
|
378
|
+
const binding = await workItems.findActiveRunBindingForSession({
|
|
379
|
+
orgId: session.orgId,
|
|
380
|
+
factoryProjectId: connection.factoryProjectId,
|
|
381
|
+
sessionId: session.sessionId
|
|
382
|
+
});
|
|
383
|
+
if (!binding || !ctx?.threadId) return binding;
|
|
384
|
+
return binding.threadId === ctx.threadId && binding.resourceId === ctx.resourceId ? binding : null;
|
|
385
|
+
};
|
|
360
386
|
const isReviewSession = async () => {
|
|
361
387
|
if (!workItems) return false;
|
|
362
388
|
try {
|
|
363
|
-
|
|
364
|
-
return isActiveReviewBinding(address ? await workItems.findRunBindingBySession(address) : null, session.orgId);
|
|
389
|
+
return isActiveReviewBinding(await findSessionBinding(), session.orgId);
|
|
365
390
|
} catch {
|
|
366
391
|
return false;
|
|
367
392
|
}
|
|
368
393
|
};
|
|
369
|
-
const effectiveSkillExtension = skillExtension ?? createFactorySkillExtension(isReviewSession);
|
|
394
|
+
const effectiveSkillExtension = skillExtension ?? createFactorySkillExtension(() => (skillReviewChecks.get(workspaceId) ?? isReviewSession)());
|
|
370
395
|
const extensionId = effectiveSkillExtension ? `-${effectiveSkillExtension.id}` : "";
|
|
371
396
|
const workspaceId = `${WORKSPACE_ID_PREFIX}-${projectRepository.id}-${session.id}${extensionId}`;
|
|
372
397
|
const workspaceGeneration = workspaceRegistry.generation(session.sessionId);
|
|
398
|
+
if (!skillExtension) skillReviewChecks.set(workspaceId, isReviewSession);
|
|
373
399
|
const configDir = DEFAULT_CONFIG_DIR;
|
|
374
400
|
const getRepositoryAccess = () => sourceControl.versionControl.getRepositoryAccess({
|
|
375
401
|
orgId: session.orgId,
|
|
@@ -383,8 +409,7 @@ function createWorkspaceFactory(options = {}) {
|
|
|
383
409
|
const resolveGithubPatKind = async (fallback) => {
|
|
384
410
|
if (!workItems) return "default";
|
|
385
411
|
try {
|
|
386
|
-
|
|
387
|
-
return isActiveReviewBinding(address ? await workItems.findRunBindingBySession(address) : null, session.orgId) ? "reviewer" : "default";
|
|
412
|
+
return isActiveReviewBinding(await findSessionBinding(), session.orgId) ? "reviewer" : "default";
|
|
388
413
|
} catch {
|
|
389
414
|
return fallback;
|
|
390
415
|
}
|
|
@@ -464,6 +489,15 @@ function createWorkspaceFactory(options = {}) {
|
|
|
464
489
|
if (existing) {
|
|
465
490
|
existing.setToolsConfig(MASTRACODE_WORKSPACE_TOOLS);
|
|
466
491
|
if (!skillExtension) {
|
|
492
|
+
const consumeOutsideRescan = async () => {
|
|
493
|
+
const outside = existing.skills && rescannedOutsideResolver.get(existing.skills);
|
|
494
|
+
if (!outside) return false;
|
|
495
|
+
await outside;
|
|
496
|
+
if (rescannedOutsideResolver.get(existing.skills) === outside) rescannedOutsideResolver.delete(existing.skills);
|
|
497
|
+
skillCacheReviewState.delete(workspaceId);
|
|
498
|
+
return true;
|
|
499
|
+
};
|
|
500
|
+
await consumeOutsideRescan();
|
|
467
501
|
let isReview = await isReviewSession();
|
|
468
502
|
for (;;) {
|
|
469
503
|
const inFlight = skillCacheRefreshes.get(workspaceId);
|
|
@@ -472,6 +506,10 @@ function createWorkspaceFactory(options = {}) {
|
|
|
472
506
|
isReview = await isReviewSession();
|
|
473
507
|
continue;
|
|
474
508
|
}
|
|
509
|
+
if (await consumeOutsideRescan()) {
|
|
510
|
+
isReview = await isReviewSession();
|
|
511
|
+
continue;
|
|
512
|
+
}
|
|
475
513
|
if (skillCacheReviewState.get(workspaceId) === isReview) break;
|
|
476
514
|
const target = isReview;
|
|
477
515
|
const pending = (async () => {
|
|
@@ -582,6 +620,7 @@ function createWorkspaceFactory(options = {}) {
|
|
|
582
620
|
githubTokenInjectors.delete(workspaceId);
|
|
583
621
|
constructedWorkspaces.delete(workspaceId);
|
|
584
622
|
skillCacheReviewState.delete(workspaceId);
|
|
623
|
+
skillReviewChecks.delete(workspaceId);
|
|
585
624
|
evictSessionSandbox(session.id);
|
|
586
625
|
await mastra?.removeWorkspace?.(workspaceId);
|
|
587
626
|
})) throw new Error(`Factory session ${session.sessionId} was retired during workspace materialization`);
|
|
@@ -590,6 +629,6 @@ function createWorkspaceFactory(options = {}) {
|
|
|
590
629
|
};
|
|
591
630
|
}
|
|
592
631
|
//#endregion
|
|
593
|
-
export { BUNDLED_FACTORY_SKILLS_PATH, FACTORY_SKILL_NAMES, FactorySkillSource, FactoryWorkspaceRegistry, REVIEW_ONLY_FACTORY_SKILLS, createWorkspaceFactory, resolveLocalFactorySkillsPath };
|
|
632
|
+
export { BUNDLED_FACTORY_SKILLS_PATH, FACTORY_SKILL_NAMES, FactorySkillSource, FactoryWorkspaceRegistry, REVIEW_ONLY_FACTORY_SKILLS, createWorkspaceFactory, rescanFactorySkills, resolveLocalFactorySkillsPath };
|
|
594
633
|
|
|
595
634
|
//# sourceMappingURL=workspace.js.map
|