@mastra/factory 0.2.2-alpha.0 → 0.2.2-alpha.2

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 (174) hide show
  1. package/CHANGELOG.md +36 -0
  2. package/dist/auth.d.ts +2 -2
  3. package/dist/auth.d.ts.map +1 -1
  4. package/dist/auth.js +401 -314
  5. package/dist/auth.js.map +1 -1
  6. package/dist/capabilities/connection.js +1 -1
  7. package/dist/capabilities/intake.js +1 -1
  8. package/dist/capabilities/version-control.js +1 -1
  9. package/dist/factory.d.ts.map +1 -1
  10. package/dist/factory.js +441 -39455
  11. package/dist/factory.js.map +1 -1
  12. package/dist/index.js +2 -39466
  13. package/dist/integrations/base.js +1 -1
  14. package/dist/integrations/github/config.js +36 -22
  15. package/dist/integrations/github/config.js.map +1 -1
  16. package/dist/integrations/github/factory-session.js +33 -37
  17. package/dist/integrations/github/factory-session.js.map +1 -1
  18. package/dist/integrations/github/integration.js +1037 -3624
  19. package/dist/integrations/github/integration.js.map +1 -1
  20. package/dist/integrations/github/issue-triage.js +71 -71
  21. package/dist/integrations/github/issue-triage.js.map +1 -1
  22. package/dist/integrations/github/pat.js +47 -36
  23. package/dist/integrations/github/pat.js.map +1 -1
  24. package/dist/integrations/github/provenance.js +72 -101
  25. package/dist/integrations/github/provenance.js.map +1 -1
  26. package/dist/integrations/github/routes.d.ts.map +1 -1
  27. package/dist/integrations/github/routes.js +1272 -1833
  28. package/dist/integrations/github/routes.js.map +1 -1
  29. package/dist/integrations/github/rules.js +203 -471
  30. package/dist/integrations/github/rules.js.map +1 -1
  31. package/dist/integrations/github/sandbox.d.ts +2 -0
  32. package/dist/integrations/github/sandbox.d.ts.map +1 -1
  33. package/dist/integrations/github/sandbox.js +401 -326
  34. package/dist/integrations/github/sandbox.js.map +1 -1
  35. package/dist/integrations/github/session-subscriptions.js +165 -223
  36. package/dist/integrations/github/session-subscriptions.js.map +1 -1
  37. package/dist/integrations/github/subscriptions.js +43 -51
  38. package/dist/integrations/github/subscriptions.js.map +1 -1
  39. package/dist/integrations/github/token-refresh.js +15 -18
  40. package/dist/integrations/github/token-refresh.js.map +1 -1
  41. package/dist/integrations/github/webhook.js +359 -343
  42. package/dist/integrations/github/webhook.js.map +1 -1
  43. package/dist/integrations/linear/agent-tools.js +77 -100
  44. package/dist/integrations/linear/agent-tools.js.map +1 -1
  45. package/dist/integrations/linear/integration.js +611 -1309
  46. package/dist/integrations/linear/integration.js.map +1 -1
  47. package/dist/integrations/linear/routes.js +227 -230
  48. package/dist/integrations/linear/routes.js.map +1 -1
  49. package/dist/integrations/linear/rules.js +126 -346
  50. package/dist/integrations/linear/rules.js.map +1 -1
  51. package/dist/integrations/linear/storage.js +1 -1
  52. package/dist/integrations/platform/api-client.js +131 -135
  53. package/dist/integrations/platform/api-client.js.map +1 -1
  54. package/dist/integrations/platform/github/event-worker.js +275 -573
  55. package/dist/integrations/platform/github/event-worker.js.map +1 -1
  56. package/dist/integrations/platform/github/integration.d.ts.map +1 -1
  57. package/dist/integrations/platform/github/integration.js +845 -3942
  58. package/dist/integrations/platform/github/integration.js.map +1 -1
  59. package/dist/integrations/platform/linear/integration.js +457 -1309
  60. package/dist/integrations/platform/linear/integration.js.map +1 -1
  61. package/dist/integrations/workos/integration.js +80 -85
  62. package/dist/integrations/workos/integration.js.map +1 -1
  63. package/dist/routes/config.d.ts.map +1 -1
  64. package/dist/routes/config.js +933 -915
  65. package/dist/routes/config.js.map +1 -1
  66. package/dist/routes/custom-provider-source.js +110 -93
  67. package/dist/routes/custom-provider-source.js.map +1 -1
  68. package/dist/routes/fs.js +401 -349
  69. package/dist/routes/fs.js.map +1 -1
  70. package/dist/routes/intake.js +165 -165
  71. package/dist/routes/intake.js.map +1 -1
  72. package/dist/routes/oauth.js +447 -25166
  73. package/dist/routes/oauth.js.map +1 -1
  74. package/dist/routes/projects.js +437 -376
  75. package/dist/routes/projects.js.map +1 -1
  76. package/dist/routes/provider-credentials.js +76 -58
  77. package/dist/routes/provider-credentials.js.map +1 -1
  78. package/dist/routes/route.js +12 -8
  79. package/dist/routes/route.js.map +1 -1
  80. package/dist/routes/skills.js +160 -173
  81. package/dist/routes/skills.js.map +1 -1
  82. package/dist/routes/surface.js +250 -28618
  83. package/dist/routes/surface.js.map +1 -1
  84. package/dist/routes/tenant-credentials.js +141 -166
  85. package/dist/routes/tenant-credentials.js.map +1 -1
  86. package/dist/routes/work-items.js +654 -862
  87. package/dist/routes/work-items.js.map +1 -1
  88. package/dist/rules/binding-context.js +23 -35
  89. package/dist/rules/binding-context.js.map +1 -1
  90. package/dist/rules/defaults.js +200 -309
  91. package/dist/rules/defaults.js.map +1 -1
  92. package/dist/rules/dispatcher.d.ts.map +1 -1
  93. package/dist/rules/dispatcher.js +438 -677
  94. package/dist/rules/dispatcher.js.map +1 -1
  95. package/dist/rules/index.js +5 -599
  96. package/dist/rules/processor.js +344 -596
  97. package/dist/rules/processor.js.map +1 -1
  98. package/dist/rules/resolve.js +21 -18
  99. package/dist/rules/resolve.js.map +1 -1
  100. package/dist/rules/start-coordinator.js +168 -157
  101. package/dist/rules/start-coordinator.js.map +1 -1
  102. package/dist/rules/tools.js +50 -85
  103. package/dist/rules/tools.js.map +1 -1
  104. package/dist/rules/transition-service.js +183 -454
  105. package/dist/rules/transition-service.js.map +1 -1
  106. package/dist/rules/types.js +33 -29
  107. package/dist/rules/types.js.map +1 -1
  108. package/dist/rules/validation.js +266 -281
  109. package/dist/rules/validation.js.map +1 -1
  110. package/dist/sandbox/fleet.js +272 -250
  111. package/dist/sandbox/fleet.js.map +1 -1
  112. package/dist/sandbox/reattach.js +13 -6
  113. package/dist/sandbox/reattach.js.map +1 -1
  114. package/dist/server-error.js +12 -16
  115. package/dist/server-error.js.map +1 -1
  116. package/dist/skills/service.js +30 -35
  117. package/dist/skills/service.js.map +1 -1
  118. package/dist/spa-static.d.ts.map +1 -1
  119. package/dist/spa-static.js +91 -64
  120. package/dist/spa-static.js.map +1 -1
  121. package/dist/state-signing.js +73 -44
  122. package/dist/state-signing.js.map +1 -1
  123. package/dist/storage/domains/audit/agent-audit.js +60 -59
  124. package/dist/storage/domains/audit/agent-audit.js.map +1 -1
  125. package/dist/storage/domains/audit/base.js +169 -112
  126. package/dist/storage/domains/audit/base.js.map +1 -1
  127. package/dist/storage/domains/audit/domain.js +155 -153
  128. package/dist/storage/domains/audit/domain.js.map +1 -1
  129. package/dist/storage/domains/credentials/base.js +259 -243
  130. package/dist/storage/domains/credentials/base.js.map +1 -1
  131. package/dist/storage/domains/custom-providers/base.js +138 -143
  132. package/dist/storage/domains/custom-providers/base.js.map +1 -1
  133. package/dist/storage/domains/intake/base.js +75 -57
  134. package/dist/storage/domains/intake/base.js.map +1 -1
  135. package/dist/storage/domains/integrations/base.js +310 -245
  136. package/dist/storage/domains/integrations/base.js.map +1 -1
  137. package/dist/storage/domains/memory-settings/base.js +117 -102
  138. package/dist/storage/domains/memory-settings/base.js.map +1 -1
  139. package/dist/storage/domains/model-packs/base.js +89 -88
  140. package/dist/storage/domains/model-packs/base.js.map +1 -1
  141. package/dist/storage/domains/projects/base.js +97 -92
  142. package/dist/storage/domains/projects/base.js.map +1 -1
  143. package/dist/storage/domains/queue-health/base.js +111 -76
  144. package/dist/storage/domains/queue-health/base.js.map +1 -1
  145. package/dist/storage/domains/source-control/base.d.ts +9 -0
  146. package/dist/storage/domains/source-control/base.d.ts.map +1 -1
  147. package/dist/storage/domains/source-control/base.js +777 -702
  148. package/dist/storage/domains/source-control/base.js.map +1 -1
  149. package/dist/storage/domains/source-control/inmemory.d.ts +4 -0
  150. package/dist/storage/domains/source-control/inmemory.d.ts.map +1 -1
  151. package/dist/storage/domains/source-control/inmemory.js +322 -344
  152. package/dist/storage/domains/source-control/inmemory.js.map +1 -1
  153. package/dist/storage/domains/work-items/base.d.ts.map +1 -1
  154. package/dist/storage/domains/work-items/base.js +1266 -1132
  155. package/dist/storage/domains/work-items/base.js.map +1 -1
  156. package/dist/storage/domains/work-items/metrics.js +202 -184
  157. package/dist/storage/domains/work-items/metrics.js.map +1 -1
  158. package/dist/timing.d.ts +15 -0
  159. package/dist/timing.d.ts.map +1 -0
  160. package/dist/timing.js +34 -0
  161. package/dist/timing.js.map +1 -0
  162. package/dist/workspace.d.ts +2 -3
  163. package/dist/workspace.d.ts.map +1 -1
  164. package/dist/workspace.js +236 -438
  165. package/dist/workspace.js.map +1 -1
  166. package/factory-skills/factory-review/SKILL.md +9 -2
  167. package/package.json +9 -9
  168. package/dist/capabilities/connection.js.map +0 -1
  169. package/dist/capabilities/intake.js.map +0 -1
  170. package/dist/capabilities/version-control.js.map +0 -1
  171. package/dist/index.js.map +0 -1
  172. package/dist/integrations/base.js.map +0 -1
  173. package/dist/integrations/linear/storage.js.map +0 -1
  174. package/dist/rules/index.js.map +0 -1
@@ -1,174 +1,185 @@
1
- // src/rules/start-coordinator.ts
2
1
  import { RequestContext } from "@mastra/core/request-context";
3
2
  import { formatSkillActivation } from "@mastra/core/workspace";
3
+ //#region src/rules/start-coordinator.ts
4
4
  var FactoryStartTransitionError = class extends Error {
5
- result;
6
- constructor(result) {
7
- super(result.reason);
8
- this.name = "FactoryStartTransitionError";
9
- this.result = result;
10
- }
5
+ result;
6
+ constructor(result) {
7
+ super(result.reason);
8
+ this.name = "FactoryStartTransitionError";
9
+ this.result = result;
10
+ }
11
11
  };
12
12
  function escapeSkillBoundary(value) {
13
- return value.replaceAll("</skill>", "&lt;/skill&gt;");
13
+ return value.replaceAll("</skill>", "&lt;/skill&gt;");
14
14
  }
15
15
  async function resolveKickoffMessage(session, invocation) {
16
- if (!invocation) return null;
17
- if (invocation.type === "prompt") return invocation.prompt;
18
- const skills = session.getWorkspace().skills;
19
- await skills?.maybeRefresh();
20
- const skill = await skills?.get(invocation.skillName);
21
- if (!skill || skill["user-invocable"] === false) {
22
- throw new Error(`Skill not found: ${invocation.skillName}.`);
23
- }
24
- const args = invocation.arguments.trim();
25
- const content = `${formatSkillActivation(skill)}${args ? `
26
-
27
- ARGUMENTS: ${args}` : ""}`.trim();
28
- return `<skill name="${skill.name}">
29
- ${escapeSkillBoundary(content)}
30
- </skill>`;
16
+ if (!invocation) return null;
17
+ if (invocation.type === "prompt") return invocation.prompt;
18
+ const skills = session.getWorkspace().skills;
19
+ await skills?.maybeRefresh();
20
+ const skill = await skills?.get(invocation.skillName);
21
+ if (!skill || skill["user-invocable"] === false) throw new Error(`Skill not found: ${invocation.skillName}.`);
22
+ const args = invocation.arguments.trim();
23
+ const content = `${formatSkillActivation(skill)}${args ? `\n\nARGUMENTS: ${args}` : ""}`.trim();
24
+ return `<skill name="${skill.name}">\n${escapeSkillBoundary(content)}\n</skill>`;
31
25
  }
32
26
  async function resolveSourceSession(storage, request) {
33
- const session = await storage.sessions.getBySessionId(request.sessionId);
34
- if (!session || session.orgId !== request.orgId || session.userId !== request.userId) {
35
- throw new Error("Factory session not found");
36
- }
37
- const projectRepository = await storage.projectRepositories.get({
38
- orgId: request.orgId,
39
- id: session.projectRepositoryId
40
- });
41
- if (!projectRepository) throw new Error("Factory session repository not found");
42
- const connection = await storage.connections.get({ orgId: request.orgId, id: projectRepository.connectionId });
43
- if (!connection || connection.factoryProjectId !== request.factoryProjectId) {
44
- throw new Error("Factory session does not belong to this project");
45
- }
46
- return session;
27
+ const session = await storage.sessions.getBySessionId(request.sessionId);
28
+ if (!session || session.orgId !== request.orgId || session.userId !== request.userId) throw new Error("Factory session not found");
29
+ const projectRepository = await storage.projectRepositories.get({
30
+ orgId: request.orgId,
31
+ id: session.projectRepositoryId
32
+ });
33
+ if (!projectRepository) throw new Error("Factory session repository not found");
34
+ const connection = await storage.connections.get({
35
+ orgId: request.orgId,
36
+ id: projectRepository.connectionId
37
+ });
38
+ if (!connection || connection.factoryProjectId !== request.factoryProjectId) throw new Error("Factory session does not belong to this project");
39
+ return session;
47
40
  }
48
41
  async function configureThread(session, request) {
49
- const threadId = session.thread.requireId();
50
- await session.thread.rename({ title: request.threadTitle });
51
- const settings = { ...request.threadTags ?? {}, factorySessionId: request.sessionId };
52
- await Promise.all(Object.entries(settings).map(([key, value]) => session.thread.setSetting({ key, value })));
53
- return threadId;
42
+ const threadId = session.thread.requireId();
43
+ await session.thread.rename({ title: request.threadTitle });
44
+ const settings = {
45
+ ...request.threadTags ?? {},
46
+ factorySessionId: request.sessionId
47
+ };
48
+ await Promise.all(Object.entries(settings).map(([key, value]) => session.thread.setSetting({
49
+ key,
50
+ value
51
+ })));
52
+ return threadId;
54
53
  }
55
54
  async function applyMemorySettings(session, record) {
56
- if (record?.observerModelId) await session.om.observer.switchModel({ modelId: record.observerModelId });
57
- if (record?.reflectorModelId) await session.om.reflector.switchModel({ modelId: record.reflectorModelId });
58
- const state = {
59
- ...record?.observationThreshold != null ? { observationThreshold: record.observationThreshold } : {},
60
- ...record?.reflectionThreshold != null ? { reflectionThreshold: record.reflectionThreshold } : {},
61
- ...record?.observeAttachments != null ? { observeAttachments: record.observeAttachments } : {}
62
- };
63
- if (Object.keys(state).length > 0) await session.state.set(state);
55
+ if (record?.observerModelId) await session.om.observer.switchModel({ modelId: record.observerModelId });
56
+ if (record?.reflectorModelId) await session.om.reflector.switchModel({ modelId: record.reflectorModelId });
57
+ const state = {
58
+ ...record?.observationThreshold != null ? { observationThreshold: record.observationThreshold } : {},
59
+ ...record?.reflectionThreshold != null ? { reflectionThreshold: record.reflectionThreshold } : {},
60
+ ...record?.observeAttachments != null ? { observeAttachments: record.observeAttachments } : {}
61
+ };
62
+ if (Object.keys(state).length > 0) await session.state.set(state);
64
63
  }
65
64
  var FactoryStartCoordinator = class {
66
- #controller;
67
- #storage;
68
- #transitionService;
69
- #sourceControl;
70
- #memorySettings;
71
- constructor(controller, storage, transitionService, sourceControl, memorySettings) {
72
- this.#controller = controller;
73
- this.#storage = storage;
74
- this.#transitionService = transitionService;
75
- this.#sourceControl = sourceControl;
76
- this.#memorySettings = memorySettings;
77
- }
78
- async prepare(request) {
79
- const storage = this.#storage;
80
- if (!this.#sourceControl) throw new Error("Factory source control storage is unavailable");
81
- const sourceSession = await resolveSourceSession(this.#sourceControl, request);
82
- const requestContext = request.requestContext ?? new RequestContext();
83
- if (!request.requestContext) {
84
- requestContext.set("user", { workosId: request.userId, organizationId: request.orgId });
85
- }
86
- const sessionState = {
87
- factoryProjectId: request.factoryProjectId,
88
- projectRepositoryId: sourceSession.projectRepositoryId
89
- };
90
- const session = await this.#controller.createSession({
91
- id: sourceSession.sessionId,
92
- ownerId: request.userId,
93
- resourceId: sourceSession.sessionId,
94
- threadId: sourceSession.sessionId,
95
- requestContext,
96
- tags: sessionState
97
- });
98
- await session.state.set(sessionState);
99
- if (this.#memorySettings) {
100
- try {
101
- const record = await this.#memorySettings.get({ orgId: request.orgId, userId: request.userId });
102
- await applyMemorySettings(session, record);
103
- } catch (error) {
104
- console.warn("[Factory Start] Failed to apply observational-memory settings", {
105
- error: error instanceof Error ? error.message : String(error)
106
- });
107
- }
108
- }
109
- if (request.defaultModelId) {
110
- try {
111
- await session.model.switch({ modelId: request.defaultModelId });
112
- } catch (error) {
113
- console.warn("[Factory Start] Failed to apply factory default model", {
114
- modelId: request.defaultModelId,
115
- error: error instanceof Error ? error.message : String(error)
116
- });
117
- }
118
- }
119
- const threadId = await configureThread(session, request);
120
- const kickoffMessage = await resolveKickoffMessage(session, request.invocation);
121
- const prepared = await storage.prepareRunStart({
122
- orgId: request.orgId,
123
- userId: request.userId,
124
- factoryProjectId: request.factoryProjectId,
125
- workItem: { id: request.workItem.id, input: request.workItem.input },
126
- role: request.workItem.role,
127
- session: { sessionId: sourceSession.sessionId, branch: sourceSession.branch, threadId },
128
- resourceId: sourceSession.sessionId,
129
- kickoffKey: request.kickoffKey,
130
- kickoffMessage
131
- });
132
- await session.thread.setSetting({ key: "factoryWorkItemId", value: prepared.item.id });
133
- let revision = prepared.item.revision;
134
- if (prepared.item.stages.length !== 1 || prepared.item.stages[0] !== request.destinationStage) {
135
- if (!this.#transitionService) throw new Error("Factory transition service is unavailable.");
136
- const transition = await this.#transitionService.transition({
137
- orgId: request.orgId,
138
- factoryProjectId: request.factoryProjectId,
139
- workItemId: prepared.item.id,
140
- board: prepared.item.externalSource?.type === "pull-request" ? "review" : "work",
141
- stage: request.destinationStage,
142
- expectedRevision: prepared.item.revision,
143
- actor: { type: "human", id: request.userId },
144
- ingress: { type: "human", identity: `start:${request.kickoffKey}:transition` },
145
- cause: "run_start"
146
- });
147
- if (transition.status === "rejected") {
148
- await storage.markPendingStart(prepared.binding.id, "failed", transition.reason);
149
- throw new FactoryStartTransitionError(transition);
150
- }
151
- revision = transition.revision;
152
- }
153
- if (kickoffMessage === null) {
154
- await storage.markPendingStart(prepared.binding.id, "sent");
155
- prepared.pendingStart.status = "sent";
156
- }
157
- return {
158
- workItemId: prepared.item.id,
159
- bindingId: prepared.binding.id,
160
- threadId,
161
- resourceId: sourceSession.sessionId,
162
- sessionId: sourceSession.sessionId,
163
- branch: sourceSession.branch,
164
- revision,
165
- kickoffStatus: prepared.pendingStart.status,
166
- replayed: prepared.replayed
167
- };
168
- }
169
- };
170
- export {
171
- FactoryStartCoordinator,
172
- FactoryStartTransitionError
65
+ #controller;
66
+ #storage;
67
+ #transitionService;
68
+ #sourceControl;
69
+ #memorySettings;
70
+ constructor(controller, storage, transitionService, sourceControl, memorySettings) {
71
+ this.#controller = controller;
72
+ this.#storage = storage;
73
+ this.#transitionService = transitionService;
74
+ this.#sourceControl = sourceControl;
75
+ this.#memorySettings = memorySettings;
76
+ }
77
+ async prepare(request) {
78
+ const storage = this.#storage;
79
+ if (!this.#sourceControl) throw new Error("Factory source control storage is unavailable");
80
+ const sourceSession = await resolveSourceSession(this.#sourceControl, request);
81
+ const requestContext = request.requestContext ?? new RequestContext();
82
+ if (!request.requestContext) requestContext.set("user", {
83
+ workosId: request.userId,
84
+ organizationId: request.orgId
85
+ });
86
+ const sessionState = {
87
+ factoryProjectId: request.factoryProjectId,
88
+ projectRepositoryId: sourceSession.projectRepositoryId
89
+ };
90
+ const session = await this.#controller.createSession({
91
+ id: sourceSession.sessionId,
92
+ ownerId: request.userId,
93
+ resourceId: sourceSession.sessionId,
94
+ threadId: sourceSession.sessionId,
95
+ requestContext,
96
+ tags: sessionState
97
+ });
98
+ await session.state.set(sessionState);
99
+ if (this.#memorySettings) try {
100
+ await applyMemorySettings(session, await this.#memorySettings.get({
101
+ orgId: request.orgId,
102
+ userId: request.userId
103
+ }));
104
+ } catch (error) {
105
+ console.warn("[Factory Start] Failed to apply observational-memory settings", { error: error instanceof Error ? error.message : String(error) });
106
+ }
107
+ if (request.defaultModelId) try {
108
+ await session.model.switch({ modelId: request.defaultModelId });
109
+ } catch (error) {
110
+ console.warn("[Factory Start] Failed to apply factory default model", {
111
+ modelId: request.defaultModelId,
112
+ error: error instanceof Error ? error.message : String(error)
113
+ });
114
+ }
115
+ const threadId = await configureThread(session, request);
116
+ const kickoffMessage = await resolveKickoffMessage(session, request.invocation);
117
+ const prepared = await storage.prepareRunStart({
118
+ orgId: request.orgId,
119
+ userId: request.userId,
120
+ factoryProjectId: request.factoryProjectId,
121
+ workItem: {
122
+ id: request.workItem.id,
123
+ input: request.workItem.input
124
+ },
125
+ role: request.workItem.role,
126
+ session: {
127
+ sessionId: sourceSession.sessionId,
128
+ branch: sourceSession.branch,
129
+ threadId
130
+ },
131
+ resourceId: sourceSession.sessionId,
132
+ kickoffKey: request.kickoffKey,
133
+ kickoffMessage
134
+ });
135
+ await session.thread.setSetting({
136
+ key: "factoryWorkItemId",
137
+ value: prepared.item.id
138
+ });
139
+ let revision = prepared.item.revision;
140
+ if (prepared.item.stages.length !== 1 || prepared.item.stages[0] !== request.destinationStage) {
141
+ if (!this.#transitionService) throw new Error("Factory transition service is unavailable.");
142
+ const transition = await this.#transitionService.transition({
143
+ orgId: request.orgId,
144
+ factoryProjectId: request.factoryProjectId,
145
+ workItemId: prepared.item.id,
146
+ board: prepared.item.externalSource?.type === "pull-request" ? "review" : "work",
147
+ stage: request.destinationStage,
148
+ expectedRevision: prepared.item.revision,
149
+ actor: {
150
+ type: "human",
151
+ id: request.userId
152
+ },
153
+ ingress: {
154
+ type: "human",
155
+ identity: `start:${request.kickoffKey}:transition`
156
+ },
157
+ cause: "run_start"
158
+ });
159
+ if (transition.status === "rejected") {
160
+ await storage.markPendingStart(prepared.binding.id, "failed", transition.reason);
161
+ throw new FactoryStartTransitionError(transition);
162
+ }
163
+ revision = transition.revision;
164
+ }
165
+ if (kickoffMessage === null) {
166
+ await storage.markPendingStart(prepared.binding.id, "sent");
167
+ prepared.pendingStart.status = "sent";
168
+ }
169
+ return {
170
+ workItemId: prepared.item.id,
171
+ bindingId: prepared.binding.id,
172
+ threadId,
173
+ resourceId: sourceSession.sessionId,
174
+ sessionId: sourceSession.sessionId,
175
+ branch: sourceSession.branch,
176
+ revision,
177
+ kickoffStatus: prepared.pendingStart.status,
178
+ replayed: prepared.replayed
179
+ };
180
+ }
173
181
  };
182
+ //#endregion
183
+ export { FactoryStartCoordinator, FactoryStartTransitionError };
184
+
174
185
  //# sourceMappingURL=start-coordinator.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/rules/start-coordinator.ts"],"sourcesContent":["import type { MastraCodeState } from '@mastra/code-sdk/schema';\nimport type { AgentController } from '@mastra/core/agent-controller';\nimport { RequestContext } from '@mastra/core/request-context';\nimport { formatSkillActivation } from '@mastra/core/workspace';\n\nimport type { MemorySettingsRecord, MemorySettingsStorage } from '../storage/domains/memory-settings/base.js';\nimport type { SourceControlSession, SourceControlStorageHandle } from '../storage/domains/source-control/base.js';\nimport type { CreateWorkItemInput, WorkItemsStorage } from '../storage/domains/work-items/base.js';\nimport type { FactoryTransitionService } from './transition-service.js';\nimport type { FactoryRuleStage, FactoryTransitionResult } from './types.js';\n\nexport interface FactoryStartRequest {\n orgId: string;\n userId: string;\n factoryProjectId: string;\n sessionId: string;\n threadTitle: string;\n threadTags?: Record<string, string>;\n kickoffKey: string;\n invocation?: { type: 'prompt'; prompt: string } | { type: 'skill'; skillName: string; arguments: string };\n destinationStage: FactoryRuleStage;\n defaultModelId?: string;\n workItem: {\n id?: string;\n role: string;\n input: CreateWorkItemInput;\n };\n requestContext?: RequestContext;\n}\n\nexport class FactoryStartTransitionError extends Error {\n readonly result: Extract<FactoryTransitionResult, { status: 'rejected' }>;\n\n constructor(result: Extract<FactoryTransitionResult, { status: 'rejected' }>) {\n super(result.reason);\n this.name = 'FactoryStartTransitionError';\n this.result = result;\n }\n}\n\nexport interface FactoryStartPreparedResult {\n workItemId: string;\n bindingId: string;\n threadId: string;\n resourceId: string;\n sessionId: string;\n branch: string;\n revision: number;\n kickoffStatus: 'pending' | 'leased' | 'retry' | 'sent' | 'failed';\n replayed: boolean;\n}\n\ntype FactoryController = AgentController<MastraCodeState>;\ntype FactorySession = Awaited<ReturnType<FactoryController['createSession']>>;\n\nfunction escapeSkillBoundary(value: string): string {\n return value.replaceAll('</skill>', '&lt;/skill&gt;');\n}\n\nasync function resolveKickoffMessage(\n session: FactorySession,\n invocation: FactoryStartRequest['invocation'],\n): Promise<string | null> {\n if (!invocation) return null;\n if (invocation.type === 'prompt') return invocation.prompt;\n\n const skills = session.getWorkspace().skills;\n await skills?.maybeRefresh();\n const skill = await skills?.get(invocation.skillName);\n if (!skill || skill['user-invocable'] === false) {\n throw new Error(`Skill not found: ${invocation.skillName}.`);\n }\n const args = invocation.arguments.trim();\n const content = `${formatSkillActivation(skill)}${args ? `\\n\\nARGUMENTS: ${args}` : ''}`.trim();\n return `<skill name=\"${skill.name}\">\\n${escapeSkillBoundary(content)}\\n</skill>`;\n}\n\nasync function resolveSourceSession(\n storage: SourceControlStorageHandle,\n request: FactoryStartRequest,\n): Promise<SourceControlSession> {\n const session = await storage.sessions.getBySessionId(request.sessionId);\n if (!session || session.orgId !== request.orgId || session.userId !== request.userId) {\n throw new Error('Factory session not found');\n }\n const projectRepository = await storage.projectRepositories.get({\n orgId: request.orgId,\n id: session.projectRepositoryId,\n });\n if (!projectRepository) throw new Error('Factory session repository not found');\n const connection = await storage.connections.get({ orgId: request.orgId, id: projectRepository.connectionId });\n if (!connection || connection.factoryProjectId !== request.factoryProjectId) {\n throw new Error('Factory session does not belong to this project');\n }\n return session;\n}\n\nasync function configureThread(session: FactorySession, request: FactoryStartRequest): Promise<string> {\n const threadId = session.thread.requireId();\n await session.thread.rename({ title: request.threadTitle });\n const settings = { ...(request.threadTags ?? {}), factorySessionId: request.sessionId };\n await Promise.all(Object.entries(settings).map(([key, value]) => session.thread.setSetting({ key, value })));\n return threadId;\n}\n\nasync function applyMemorySettings(session: FactorySession, record: MemorySettingsRecord | null): Promise<void> {\n if (record?.observerModelId) await session.om.observer.switchModel({ modelId: record.observerModelId });\n if (record?.reflectorModelId) await session.om.reflector.switchModel({ modelId: record.reflectorModelId });\n\n const state = {\n ...(record?.observationThreshold != null ? { observationThreshold: record.observationThreshold } : {}),\n ...(record?.reflectionThreshold != null ? { reflectionThreshold: record.reflectionThreshold } : {}),\n ...(record?.observeAttachments != null ? { observeAttachments: record.observeAttachments } : {}),\n };\n if (Object.keys(state).length > 0) await session.state.set(state);\n}\n\nexport class FactoryStartCoordinator {\n readonly #controller: FactoryController;\n readonly #storage: WorkItemsStorage;\n readonly #transitionService?: Pick<FactoryTransitionService, 'transition'>;\n readonly #sourceControl?: SourceControlStorageHandle;\n readonly #memorySettings?: MemorySettingsStorage;\n\n constructor(\n controller: FactoryController,\n storage: WorkItemsStorage,\n transitionService?: Pick<FactoryTransitionService, 'transition'>,\n sourceControl?: SourceControlStorageHandle,\n memorySettings?: MemorySettingsStorage,\n ) {\n this.#controller = controller;\n this.#storage = storage;\n this.#transitionService = transitionService;\n this.#sourceControl = sourceControl;\n this.#memorySettings = memorySettings;\n }\n\n async prepare(request: FactoryStartRequest): Promise<FactoryStartPreparedResult> {\n const storage = this.#storage;\n if (!this.#sourceControl) throw new Error('Factory source control storage is unavailable');\n const sourceSession = await resolveSourceSession(this.#sourceControl, request);\n const requestContext = request.requestContext ?? new RequestContext();\n if (!request.requestContext) {\n requestContext.set('user', { workosId: request.userId, organizationId: request.orgId });\n }\n const sessionState = {\n factoryProjectId: request.factoryProjectId,\n projectRepositoryId: sourceSession.projectRepositoryId,\n };\n const session = await this.#controller.createSession({\n id: sourceSession.sessionId,\n ownerId: request.userId,\n resourceId: sourceSession.sessionId,\n threadId: sourceSession.sessionId,\n requestContext,\n tags: sessionState,\n });\n // Bound-agent authority gates (the transition tool, the factory-phase\n // processor, workspace token selection) resolve the session address from\n // controller state. Seed it server-side — `tags` covers fresh creation,\n // the explicit setState covers get-or-create returning a session another\n // caller created without them — so autonomous runs never depend on a\n // browser connecting to populate the state.\n await session.state.set(sessionState);\n if (this.#memorySettings) {\n try {\n const record = await this.#memorySettings.get({ orgId: request.orgId, userId: request.userId });\n await applyMemorySettings(session, record);\n } catch (error) {\n console.warn('[Factory Start] Failed to apply observational-memory settings', {\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n if (request.defaultModelId) {\n try {\n await session.model.switch({ modelId: request.defaultModelId });\n } catch (error) {\n console.warn('[Factory Start] Failed to apply factory default model', {\n modelId: request.defaultModelId,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n const threadId = await configureThread(session, request);\n const kickoffMessage = await resolveKickoffMessage(session, request.invocation);\n const prepared = await storage.prepareRunStart({\n orgId: request.orgId,\n userId: request.userId,\n factoryProjectId: request.factoryProjectId,\n workItem: { id: request.workItem.id, input: request.workItem.input },\n role: request.workItem.role,\n session: { sessionId: sourceSession.sessionId, branch: sourceSession.branch, threadId },\n resourceId: sourceSession.sessionId,\n kickoffKey: request.kickoffKey,\n kickoffMessage,\n });\n await session.thread.setSetting({ key: 'factoryWorkItemId', value: prepared.item.id });\n\n let revision = prepared.item.revision;\n if (prepared.item.stages.length !== 1 || prepared.item.stages[0] !== request.destinationStage) {\n if (!this.#transitionService) throw new Error('Factory transition service is unavailable.');\n const transition = await this.#transitionService.transition({\n orgId: request.orgId,\n factoryProjectId: request.factoryProjectId,\n workItemId: prepared.item.id,\n board: prepared.item.externalSource?.type === 'pull-request' ? 'review' : 'work',\n stage: request.destinationStage,\n expectedRevision: prepared.item.revision,\n actor: { type: 'human', id: request.userId },\n ingress: { type: 'human', identity: `start:${request.kickoffKey}:transition` },\n cause: 'run_start',\n });\n if (transition.status === 'rejected') {\n await storage.markPendingStart(prepared.binding.id, 'failed', transition.reason);\n throw new FactoryStartTransitionError(transition);\n }\n revision = transition.revision;\n }\n\n if (kickoffMessage === null) {\n await storage.markPendingStart(prepared.binding.id, 'sent');\n prepared.pendingStart.status = 'sent';\n }\n\n return {\n workItemId: prepared.item.id,\n bindingId: prepared.binding.id,\n threadId,\n resourceId: sourceSession.sessionId,\n sessionId: sourceSession.sessionId,\n branch: sourceSession.branch,\n revision,\n kickoffStatus: prepared.pendingStart.status,\n replayed: prepared.replayed,\n };\n }\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"file":"start-coordinator.js","names":["#controller","#storage","#transitionService","#sourceControl","#memorySettings"],"sources":["../../src/rules/start-coordinator.ts"],"sourcesContent":["import type { MastraCodeState } from '@mastra/code-sdk/schema';\nimport type { AgentController } from '@mastra/core/agent-controller';\nimport { RequestContext } from '@mastra/core/request-context';\nimport { formatSkillActivation } from '@mastra/core/workspace';\n\nimport type { MemorySettingsRecord, MemorySettingsStorage } from '../storage/domains/memory-settings/base.js';\nimport type { SourceControlSession, SourceControlStorageHandle } from '../storage/domains/source-control/base.js';\nimport type { CreateWorkItemInput, WorkItemsStorage } from '../storage/domains/work-items/base.js';\nimport type { FactoryTransitionService } from './transition-service.js';\nimport type { FactoryRuleStage, FactoryTransitionResult } from './types.js';\n\nexport interface FactoryStartRequest {\n orgId: string;\n userId: string;\n factoryProjectId: string;\n sessionId: string;\n threadTitle: string;\n threadTags?: Record<string, string>;\n kickoffKey: string;\n invocation?: { type: 'prompt'; prompt: string } | { type: 'skill'; skillName: string; arguments: string };\n destinationStage: FactoryRuleStage;\n defaultModelId?: string;\n workItem: {\n id?: string;\n role: string;\n input: CreateWorkItemInput;\n };\n requestContext?: RequestContext;\n}\n\nexport class FactoryStartTransitionError extends Error {\n readonly result: Extract<FactoryTransitionResult, { status: 'rejected' }>;\n\n constructor(result: Extract<FactoryTransitionResult, { status: 'rejected' }>) {\n super(result.reason);\n this.name = 'FactoryStartTransitionError';\n this.result = result;\n }\n}\n\nexport interface FactoryStartPreparedResult {\n workItemId: string;\n bindingId: string;\n threadId: string;\n resourceId: string;\n sessionId: string;\n branch: string;\n revision: number;\n kickoffStatus: 'pending' | 'leased' | 'retry' | 'sent' | 'failed';\n replayed: boolean;\n}\n\ntype FactoryController = AgentController<MastraCodeState>;\ntype FactorySession = Awaited<ReturnType<FactoryController['createSession']>>;\n\nfunction escapeSkillBoundary(value: string): string {\n return value.replaceAll('</skill>', '&lt;/skill&gt;');\n}\n\nasync function resolveKickoffMessage(\n session: FactorySession,\n invocation: FactoryStartRequest['invocation'],\n): Promise<string | null> {\n if (!invocation) return null;\n if (invocation.type === 'prompt') return invocation.prompt;\n\n const skills = session.getWorkspace().skills;\n await skills?.maybeRefresh();\n const skill = await skills?.get(invocation.skillName);\n if (!skill || skill['user-invocable'] === false) {\n throw new Error(`Skill not found: ${invocation.skillName}.`);\n }\n const args = invocation.arguments.trim();\n const content = `${formatSkillActivation(skill)}${args ? `\\n\\nARGUMENTS: ${args}` : ''}`.trim();\n return `<skill name=\"${skill.name}\">\\n${escapeSkillBoundary(content)}\\n</skill>`;\n}\n\nasync function resolveSourceSession(\n storage: SourceControlStorageHandle,\n request: FactoryStartRequest,\n): Promise<SourceControlSession> {\n const session = await storage.sessions.getBySessionId(request.sessionId);\n if (!session || session.orgId !== request.orgId || session.userId !== request.userId) {\n throw new Error('Factory session not found');\n }\n const projectRepository = await storage.projectRepositories.get({\n orgId: request.orgId,\n id: session.projectRepositoryId,\n });\n if (!projectRepository) throw new Error('Factory session repository not found');\n const connection = await storage.connections.get({ orgId: request.orgId, id: projectRepository.connectionId });\n if (!connection || connection.factoryProjectId !== request.factoryProjectId) {\n throw new Error('Factory session does not belong to this project');\n }\n return session;\n}\n\nasync function configureThread(session: FactorySession, request: FactoryStartRequest): Promise<string> {\n const threadId = session.thread.requireId();\n await session.thread.rename({ title: request.threadTitle });\n const settings = { ...(request.threadTags ?? {}), factorySessionId: request.sessionId };\n await Promise.all(Object.entries(settings).map(([key, value]) => session.thread.setSetting({ key, value })));\n return threadId;\n}\n\nasync function applyMemorySettings(session: FactorySession, record: MemorySettingsRecord | null): Promise<void> {\n if (record?.observerModelId) await session.om.observer.switchModel({ modelId: record.observerModelId });\n if (record?.reflectorModelId) await session.om.reflector.switchModel({ modelId: record.reflectorModelId });\n\n const state = {\n ...(record?.observationThreshold != null ? { observationThreshold: record.observationThreshold } : {}),\n ...(record?.reflectionThreshold != null ? { reflectionThreshold: record.reflectionThreshold } : {}),\n ...(record?.observeAttachments != null ? { observeAttachments: record.observeAttachments } : {}),\n };\n if (Object.keys(state).length > 0) await session.state.set(state);\n}\n\nexport class FactoryStartCoordinator {\n readonly #controller: FactoryController;\n readonly #storage: WorkItemsStorage;\n readonly #transitionService?: Pick<FactoryTransitionService, 'transition'>;\n readonly #sourceControl?: SourceControlStorageHandle;\n readonly #memorySettings?: MemorySettingsStorage;\n\n constructor(\n controller: FactoryController,\n storage: WorkItemsStorage,\n transitionService?: Pick<FactoryTransitionService, 'transition'>,\n sourceControl?: SourceControlStorageHandle,\n memorySettings?: MemorySettingsStorage,\n ) {\n this.#controller = controller;\n this.#storage = storage;\n this.#transitionService = transitionService;\n this.#sourceControl = sourceControl;\n this.#memorySettings = memorySettings;\n }\n\n async prepare(request: FactoryStartRequest): Promise<FactoryStartPreparedResult> {\n const storage = this.#storage;\n if (!this.#sourceControl) throw new Error('Factory source control storage is unavailable');\n const sourceSession = await resolveSourceSession(this.#sourceControl, request);\n const requestContext = request.requestContext ?? new RequestContext();\n if (!request.requestContext) {\n requestContext.set('user', { workosId: request.userId, organizationId: request.orgId });\n }\n const sessionState = {\n factoryProjectId: request.factoryProjectId,\n projectRepositoryId: sourceSession.projectRepositoryId,\n };\n const session = await this.#controller.createSession({\n id: sourceSession.sessionId,\n ownerId: request.userId,\n resourceId: sourceSession.sessionId,\n threadId: sourceSession.sessionId,\n requestContext,\n tags: sessionState,\n });\n // Bound-agent authority gates (the transition tool, the factory-phase\n // processor, workspace token selection) resolve the session address from\n // controller state. Seed it server-side — `tags` covers fresh creation,\n // the explicit setState covers get-or-create returning a session another\n // caller created without them — so autonomous runs never depend on a\n // browser connecting to populate the state.\n await session.state.set(sessionState);\n if (this.#memorySettings) {\n try {\n const record = await this.#memorySettings.get({ orgId: request.orgId, userId: request.userId });\n await applyMemorySettings(session, record);\n } catch (error) {\n console.warn('[Factory Start] Failed to apply observational-memory settings', {\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n if (request.defaultModelId) {\n try {\n await session.model.switch({ modelId: request.defaultModelId });\n } catch (error) {\n console.warn('[Factory Start] Failed to apply factory default model', {\n modelId: request.defaultModelId,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n const threadId = await configureThread(session, request);\n const kickoffMessage = await resolveKickoffMessage(session, request.invocation);\n const prepared = await storage.prepareRunStart({\n orgId: request.orgId,\n userId: request.userId,\n factoryProjectId: request.factoryProjectId,\n workItem: { id: request.workItem.id, input: request.workItem.input },\n role: request.workItem.role,\n session: { sessionId: sourceSession.sessionId, branch: sourceSession.branch, threadId },\n resourceId: sourceSession.sessionId,\n kickoffKey: request.kickoffKey,\n kickoffMessage,\n });\n await session.thread.setSetting({ key: 'factoryWorkItemId', value: prepared.item.id });\n\n let revision = prepared.item.revision;\n if (prepared.item.stages.length !== 1 || prepared.item.stages[0] !== request.destinationStage) {\n if (!this.#transitionService) throw new Error('Factory transition service is unavailable.');\n const transition = await this.#transitionService.transition({\n orgId: request.orgId,\n factoryProjectId: request.factoryProjectId,\n workItemId: prepared.item.id,\n board: prepared.item.externalSource?.type === 'pull-request' ? 'review' : 'work',\n stage: request.destinationStage,\n expectedRevision: prepared.item.revision,\n actor: { type: 'human', id: request.userId },\n ingress: { type: 'human', identity: `start:${request.kickoffKey}:transition` },\n cause: 'run_start',\n });\n if (transition.status === 'rejected') {\n await storage.markPendingStart(prepared.binding.id, 'failed', transition.reason);\n throw new FactoryStartTransitionError(transition);\n }\n revision = transition.revision;\n }\n\n if (kickoffMessage === null) {\n await storage.markPendingStart(prepared.binding.id, 'sent');\n prepared.pendingStart.status = 'sent';\n }\n\n return {\n workItemId: prepared.item.id,\n bindingId: prepared.binding.id,\n threadId,\n resourceId: sourceSession.sessionId,\n sessionId: sourceSession.sessionId,\n branch: sourceSession.branch,\n revision,\n kickoffStatus: prepared.pendingStart.status,\n replayed: prepared.replayed,\n };\n }\n}\n"],"mappings":"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"}
@@ -1,93 +1,58 @@
1
- // src/rules/tools.ts
1
+ import { FACTORY_RULE_STAGES } from "./types.js";
2
+ import { getFactorySessionAddress } from "./binding-context.js";
2
3
  import { createTool } from "@mastra/core/tools";
3
4
  import { z } from "zod";
4
-
5
- // src/auth.ts
6
- import { MastraAuthWorkos } from "@mastra/auth-workos";
7
- import {
8
- registerApiRoute,
9
- isAuthHttpHandler,
10
- isCredentialsProvider,
11
- isOrganizationsProvider,
12
- isSessionProvider,
13
- isSSOProvider
14
- } from "@mastra/core/server";
15
- function getFactoryAuthOrgId(user) {
16
- return user?.organizationId;
17
- }
18
-
19
- // src/rules/binding-context.ts
20
- function getFactorySessionCoordinates(requestContext) {
21
- if (!requestContext || typeof requestContext.get !== "function") return null;
22
- const context = requestContext.get("controller");
23
- const factoryProjectId = context?.getState().factoryProjectId;
24
- if (!context?.threadId || !context.resourceId || !factoryProjectId) return null;
25
- return {
26
- factoryProjectId,
27
- threadId: context.threadId,
28
- resourceId: context.resourceId,
29
- sessionId: context.resourceId
30
- };
31
- }
32
- function getFactorySessionAddress(requestContext) {
33
- const coordinates = getFactorySessionCoordinates(requestContext);
34
- if (!coordinates || !requestContext || typeof requestContext.get !== "function") return null;
35
- const user = requestContext.get("user");
36
- const orgId = getFactoryAuthOrgId(user);
37
- if (!orgId) return null;
38
- return { orgId, ...coordinates };
39
- }
40
-
41
- // src/rules/types.ts
42
- var FACTORY_RULE_STAGES = ["intake", "triage", "planning", "execute", "review", "done", "canceled"];
43
-
44
- // src/rules/tools.ts
45
- var transitionInputSchema = z.object({
46
- stage: z.enum(FACTORY_RULE_STAGES),
47
- expectedRevision: z.number().int().positive(),
48
- rationale: z.string().trim().min(1).max(1e3)
5
+ //#region src/rules/tools.ts
6
+ const transitionInputSchema = z.object({
7
+ stage: z.enum(FACTORY_RULE_STAGES),
8
+ expectedRevision: z.number().int().positive(),
9
+ rationale: z.string().trim().min(1).max(1e3)
49
10
  }).strict();
50
11
  function boardForSource(type) {
51
- return type === "pull-request" ? "review" : "work";
12
+ return type === "pull-request" ? "review" : "work";
52
13
  }
53
14
  async function createFactoryTransitionTools(options) {
54
- const address = getFactorySessionAddress(options.requestContext);
55
- if (!address) return {};
56
- const availableBinding = await options.storage.findActiveRunBinding(address);
57
- if (!availableBinding) return {};
58
- return {
59
- factory_transition_work_item: createTool({
60
- id: "factory_transition_work_item",
61
- description: "Request a governed stage transition for the Factory work item exactly bound to this thread. Use the current revision from the factory-phase signal and explain why the transition is appropriate.",
62
- inputSchema: transitionInputSchema,
63
- execute: async ({ stage, expectedRevision, rationale }, execution) => {
64
- const currentAddress = getFactorySessionAddress(execution.requestContext);
65
- const toolCallId = execution.agent?.toolCallId;
66
- if (!currentAddress || !toolCallId) {
67
- throw new Error("Factory transitions require an authenticated bound agent tool call.");
68
- }
69
- const binding = await options.storage.findActiveRunBinding(currentAddress);
70
- if (!binding || binding.id !== availableBinding.id) {
71
- throw new Error("Factory agent binding is unavailable, revoked, or no longer matches this session.");
72
- }
73
- const item = await options.storage.get({ orgId: binding.orgId, id: binding.workItemId });
74
- if (!item) throw new Error("Bound Factory work item not found.");
75
- return options.transitionService.transition({
76
- orgId: binding.orgId,
77
- factoryProjectId: binding.factoryProjectId,
78
- workItemId: binding.workItemId,
79
- board: boardForSource(item.externalSource?.type),
80
- stage,
81
- expectedRevision,
82
- actor: { type: "agent", bindingId: binding.id, role: binding.role },
83
- ingress: { type: "agent", identity: `${binding.id}:${toolCallId}` },
84
- cause: rationale
85
- });
86
- }
87
- })
88
- };
15
+ const address = getFactorySessionAddress(options.requestContext);
16
+ if (!address) return {};
17
+ const availableBinding = await options.storage.findActiveRunBinding(address);
18
+ if (!availableBinding) return {};
19
+ return { factory_transition_work_item: createTool({
20
+ id: "factory_transition_work_item",
21
+ description: "Request a governed stage transition for the Factory work item exactly bound to this thread. Use the current revision from the factory-phase signal and explain why the transition is appropriate.",
22
+ inputSchema: transitionInputSchema,
23
+ execute: async ({ stage, expectedRevision, rationale }, execution) => {
24
+ const currentAddress = getFactorySessionAddress(execution.requestContext);
25
+ const toolCallId = execution.agent?.toolCallId;
26
+ if (!currentAddress || !toolCallId) throw new Error("Factory transitions require an authenticated bound agent tool call.");
27
+ const binding = await options.storage.findActiveRunBinding(currentAddress);
28
+ if (!binding || binding.id !== availableBinding.id) throw new Error("Factory agent binding is unavailable, revoked, or no longer matches this session.");
29
+ const item = await options.storage.get({
30
+ orgId: binding.orgId,
31
+ id: binding.workItemId
32
+ });
33
+ if (!item) throw new Error("Bound Factory work item not found.");
34
+ return options.transitionService.transition({
35
+ orgId: binding.orgId,
36
+ factoryProjectId: binding.factoryProjectId,
37
+ workItemId: binding.workItemId,
38
+ board: boardForSource(item.externalSource?.type),
39
+ stage,
40
+ expectedRevision,
41
+ actor: {
42
+ type: "agent",
43
+ bindingId: binding.id,
44
+ role: binding.role
45
+ },
46
+ ingress: {
47
+ type: "agent",
48
+ identity: `${binding.id}:${toolCallId}`
49
+ },
50
+ cause: rationale
51
+ });
52
+ }
53
+ }) };
89
54
  }
90
- export {
91
- createFactoryTransitionTools
92
- };
55
+ //#endregion
56
+ export { createFactoryTransitionTools };
57
+
93
58
  //# sourceMappingURL=tools.js.map