@mastra/factory 0.15.0 → 0.16.0-alpha.5

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 (104) hide show
  1. package/dist/boards/index.d.ts +1 -1
  2. package/dist/boards/index.d.ts.map +1 -1
  3. package/dist/boards/index.js +2 -2
  4. package/dist/boards/index.js.map +1 -1
  5. package/dist/boards/review.d.ts.map +1 -1
  6. package/dist/boards/review.js +4 -1
  7. package/dist/boards/review.js.map +1 -1
  8. package/dist/boards/semantics.d.ts +7 -0
  9. package/dist/boards/semantics.d.ts.map +1 -1
  10. package/dist/boards/semantics.js +15 -1
  11. package/dist/boards/semantics.js.map +1 -1
  12. package/dist/boards/transition-policy.d.ts +4 -0
  13. package/dist/boards/transition-policy.d.ts.map +1 -1
  14. package/dist/boards/transition-policy.js.map +1 -1
  15. package/dist/boards/work-transition-policy.d.ts.map +1 -1
  16. package/dist/boards/work-transition-policy.js +6 -1
  17. package/dist/boards/work-transition-policy.js.map +1 -1
  18. package/dist/capabilities/intake.d.ts +4 -0
  19. package/dist/capabilities/intake.d.ts.map +1 -1
  20. package/dist/factory.d.ts.map +1 -1
  21. package/dist/factory.js +51 -12
  22. package/dist/factory.js.map +1 -1
  23. package/dist/integrations/base.d.ts +4 -2
  24. package/dist/integrations/base.d.ts.map +1 -1
  25. package/dist/integrations/linear/claim.d.ts +8 -0
  26. package/dist/integrations/linear/claim.d.ts.map +1 -0
  27. package/dist/integrations/linear/claim.js +14 -0
  28. package/dist/integrations/linear/claim.js.map +1 -0
  29. package/dist/integrations/linear/default-rules.d.ts +1 -0
  30. package/dist/integrations/linear/default-rules.d.ts.map +1 -1
  31. package/dist/integrations/linear/default-rules.js +2 -0
  32. package/dist/integrations/linear/default-rules.js.map +1 -1
  33. package/dist/integrations/linear/integration.d.ts +24 -6
  34. package/dist/integrations/linear/integration.d.ts.map +1 -1
  35. package/dist/integrations/linear/integration.js +257 -37
  36. package/dist/integrations/linear/integration.js.map +1 -1
  37. package/dist/integrations/linear/routes.d.ts +10 -0
  38. package/dist/integrations/linear/routes.d.ts.map +1 -1
  39. package/dist/integrations/linear/routes.js +74 -12
  40. package/dist/integrations/linear/routes.js.map +1 -1
  41. package/dist/integrations/linear/rules.d.ts +1 -1
  42. package/dist/integrations/linear/rules.d.ts.map +1 -1
  43. package/dist/integrations/linear/rules.js +27 -2
  44. package/dist/integrations/linear/rules.js.map +1 -1
  45. package/dist/integrations/platform/linear/integration.d.ts +34 -1
  46. package/dist/integrations/platform/linear/integration.d.ts.map +1 -1
  47. package/dist/integrations/platform/linear/integration.js +271 -48
  48. package/dist/integrations/platform/linear/integration.js.map +1 -1
  49. package/dist/routes/intake.d.ts.map +1 -1
  50. package/dist/routes/intake.js +15 -5
  51. package/dist/routes/intake.js.map +1 -1
  52. package/dist/rules/dispatch-errors.d.ts.map +1 -1
  53. package/dist/rules/dispatch-errors.js +8 -0
  54. package/dist/rules/dispatch-errors.js.map +1 -1
  55. package/dist/rules/dispatcher.d.ts +1 -0
  56. package/dist/rules/dispatcher.d.ts.map +1 -1
  57. package/dist/rules/dispatcher.js +179 -105
  58. package/dist/rules/dispatcher.js.map +1 -1
  59. package/dist/rules/start-coordinator.d.ts.map +1 -1
  60. package/dist/rules/start-coordinator.js +4 -1
  61. package/dist/rules/start-coordinator.js.map +1 -1
  62. package/dist/rules/terminal-cleanup.d.ts +14 -1
  63. package/dist/rules/terminal-cleanup.d.ts.map +1 -1
  64. package/dist/rules/terminal-cleanup.js +20 -0
  65. package/dist/rules/terminal-cleanup.js.map +1 -1
  66. package/dist/rules/tools.d.ts +2 -0
  67. package/dist/rules/tools.d.ts.map +1 -1
  68. package/dist/rules/tools.js +30 -2
  69. package/dist/rules/tools.js.map +1 -1
  70. package/dist/rules/transition-service.d.ts +13 -0
  71. package/dist/rules/transition-service.d.ts.map +1 -1
  72. package/dist/rules/transition-service.js +11 -2
  73. package/dist/rules/transition-service.js.map +1 -1
  74. package/dist/rules/types.d.ts +15 -0
  75. package/dist/rules/types.d.ts.map +1 -1
  76. package/dist/rules/types.js.map +1 -1
  77. package/dist/rules/validation.d.ts.map +1 -1
  78. package/dist/rules/validation.js +11 -2
  79. package/dist/rules/validation.js.map +1 -1
  80. package/dist/session/run-audit.d.ts +9 -0
  81. package/dist/session/run-audit.d.ts.map +1 -1
  82. package/dist/session/run-audit.js +37 -6
  83. package/dist/session/run-audit.js.map +1 -1
  84. package/dist/skills/service.d.ts +12 -0
  85. package/dist/skills/service.d.ts.map +1 -1
  86. package/dist/skills/service.js +27 -1
  87. package/dist/skills/service.js.map +1 -1
  88. package/dist/storage/domains/intake/base.d.ts +11 -8
  89. package/dist/storage/domains/intake/base.d.ts.map +1 -1
  90. package/dist/storage/domains/intake/base.js +69 -24
  91. package/dist/storage/domains/intake/base.js.map +1 -1
  92. package/dist/storage/domains/work-items/base.d.ts +41 -2
  93. package/dist/storage/domains/work-items/base.d.ts.map +1 -1
  94. package/dist/storage/domains/work-items/base.js +159 -12
  95. package/dist/storage/domains/work-items/base.js.map +1 -1
  96. package/dist/supervisor/session-messaging.d.ts +23 -0
  97. package/dist/supervisor/session-messaging.d.ts.map +1 -0
  98. package/dist/supervisor/session-messaging.js +15 -0
  99. package/dist/supervisor/session-messaging.js.map +1 -0
  100. package/dist/supervisor/write-tools.d.ts +2 -1
  101. package/dist/supervisor/write-tools.d.ts.map +1 -1
  102. package/dist/supervisor/write-tools.js +11 -7
  103. package/dist/supervisor/write-tools.js.map +1 -1
  104. package/package.json +12 -12
@@ -42,6 +42,8 @@ const FACTORY_DISPATCH_FAILURE_CODES = [
42
42
  "source_repository_missing",
43
43
  "unsupported_provider_item",
44
44
  "notification_delivery_failed",
45
+ "run_terminal_event_missing",
46
+ "skill_delivery_ambiguous",
45
47
  "run_overdue",
46
48
  "repository_git_missing",
47
49
  "repository_egress_blocked",
@@ -135,6 +137,10 @@ const WORK_ITEMS_SCHEMA = {
135
137
  type: "text",
136
138
  nullable: true
137
139
  },
140
+ claim_key: {
141
+ type: "text",
142
+ nullable: true
143
+ },
138
144
  parent_work_item_id: {
139
145
  type: "text",
140
146
  nullable: true
@@ -182,6 +188,9 @@ const WORK_ITEMS_SCHEMA = {
182
188
  uniqueIndexes: [{
183
189
  name: "work_items_project_source_key_unique",
184
190
  columns: ["factory_project_id", "source_key"]
191
+ }, {
192
+ name: "work_items_org_claim_key_unique",
193
+ columns: ["org_id", "claim_key"]
185
194
  }],
186
195
  indexes: [
187
196
  {
@@ -224,6 +233,7 @@ function toWorkItem(row) {
224
233
  factoryProjectId: String(row.factory_project_id),
225
234
  board: row.board ?? null,
226
235
  externalSource: row.external_source,
236
+ claimKey: row.claim_key ?? null,
227
237
  parentWorkItemId: row.parent_work_item_id,
228
238
  title: row.title,
229
239
  stages: row.stages,
@@ -248,6 +258,7 @@ function patchColumns(changes) {
248
258
  ...changes.board !== void 0 ? { board: changes.board } : {},
249
259
  ...changes.parentWorkItemId !== void 0 ? { parent_work_item_id: changes.parentWorkItemId } : {},
250
260
  ...changes.title !== void 0 ? { title: changes.title } : {},
261
+ ...changes.claimKey !== void 0 ? { claim_key: changes.claimKey } : {},
251
262
  ...changes.stages !== void 0 ? { stages: changes.stages } : {},
252
263
  ...changes.stageHistory !== void 0 ? { stage_history: changes.stageHistory } : {},
253
264
  ...changes.sessions !== void 0 ? { sessions: changes.sessions } : {},
@@ -274,6 +285,15 @@ function priorState(row) {
274
285
  var WorkItemRelationError = class extends Error {
275
286
  code = "invalid_work_item_relation";
276
287
  };
288
+ /** Another card in the org already holds the claim the write asked for. */
289
+ var WorkItemClaimConflictError = class extends Error {
290
+ claimant;
291
+ code = "work_item_claim_conflict";
292
+ constructor(claimant) {
293
+ super(`Work item claim is held by ${claimant.id} in project ${claimant.factoryProjectId}`);
294
+ this.claimant = claimant;
295
+ }
296
+ };
277
297
  var WorkItemUpdateConflictError = class extends Error {
278
298
  reason;
279
299
  code = "work_item_update_conflict";
@@ -842,6 +862,39 @@ var WorkItemsStorage = class extends FactoryStorageDomain {
842
862
  useTerminalPhasePredicate(isTerminal) {
843
863
  this.#isTerminal = isTerminal;
844
864
  }
865
+ /**
866
+ * The claim a new row may carry: the requested key, unless the row is born
867
+ * finished, in which case there is nothing to own and holding the key would
868
+ * only block the next project from filing the record.
869
+ */
870
+ #claimForNewRow(input, stages) {
871
+ if (!input.claimKey) return null;
872
+ const shape = {
873
+ board: input.board ?? null,
874
+ externalSource: input.externalSource ?? null,
875
+ stages
876
+ };
877
+ return this.#isTerminal(shape) ? null : input.claimKey;
878
+ }
879
+ /** The claim an existing unclaimed row adopts from `input`, if it is not finished after `patch`. */
880
+ #claimToAdopt(current, patch, input) {
881
+ if (!input.claimKey || current.claim_key !== null) return null;
882
+ return this.#isTerminal(toWorkItem({
883
+ ...current,
884
+ ...patch
885
+ })) ? null : input.claimKey;
886
+ }
887
+ /** Drop the org-wide claim from a patch that moves the card into a terminal phase. */
888
+ #releaseClaimIfFinished(current, patch) {
889
+ if (patch.stages === void 0 || current.claim_key === null) return patch;
890
+ return this.#isTerminal(toWorkItem({
891
+ ...current,
892
+ ...patch
893
+ })) ? {
894
+ ...patch,
895
+ claim_key: null
896
+ } : patch;
897
+ }
845
898
  async init() {
846
899
  await this.ensureCollections([
847
900
  WORK_ITEMS_SCHEMA,
@@ -1116,6 +1169,56 @@ var WorkItemsStorage = class extends FactoryStorageDomain {
1116
1169
  const rows = await this.#db.findMany("work_items", { source_key: externalSourceKey(source) });
1117
1170
  return rows.length === 1 ? toWorkItem(rows[0]) : null;
1118
1171
  }
1172
+ /**
1173
+ * Every card in the org that was linked from one external source, across
1174
+ * Factory projects. Source keys are unique per project, not per org, so an
1175
+ * issue whose routing moved between projects can own one card in each; intake
1176
+ * consults this before creating another.
1177
+ */
1178
+ async listBySource({ orgId, source }) {
1179
+ return (await this.#db.findMany("work_items", {
1180
+ org_id: orgId,
1181
+ source_key: externalSourceKey(source)
1182
+ })).map(toWorkItem);
1183
+ }
1184
+ /** The one card in the org holding `claimKey`, if any. */
1185
+ async getByClaimKey({ orgId, claimKey }) {
1186
+ const row = await this.#db.findOne("work_items", {
1187
+ org_id: orgId,
1188
+ claim_key: claimKey
1189
+ });
1190
+ return row ? toWorkItem(row) : null;
1191
+ }
1192
+ /**
1193
+ * Give an unclaimed card the org-wide claim for its record. Returns the card
1194
+ * once claimed, or null when the card already carries a different claim or
1195
+ * another card in the org holds this one.
1196
+ */
1197
+ async claimWorkItem({ orgId, id, claimKey }) {
1198
+ const heldBy = async () => {
1199
+ const holder = await this.#db.findOne("work_items", {
1200
+ org_id: orgId,
1201
+ claim_key: claimKey
1202
+ });
1203
+ return holder && holder.id !== id ? holder : null;
1204
+ };
1205
+ if (await heldBy()) return null;
1206
+ try {
1207
+ const row = await this.#db.updateAtomic("work_items", {
1208
+ org_id: orgId,
1209
+ id
1210
+ }, async (current) => {
1211
+ if (current.claim_key === claimKey) return {};
1212
+ if (current.claim_key !== null) throw new WorkItemClaimConflictError(toWorkItem(current));
1213
+ return { claim_key: claimKey };
1214
+ });
1215
+ return row ? toWorkItem(row) : null;
1216
+ } catch (error) {
1217
+ if (error instanceof WorkItemClaimConflictError) return null;
1218
+ if (await heldBy()) return null;
1219
+ throw error;
1220
+ }
1221
+ }
1119
1222
  async getForProject(orgId, factoryProjectId, id) {
1120
1223
  const row = await this.#db.findOne("work_items", {
1121
1224
  id,
@@ -1185,6 +1288,10 @@ var WorkItemsStorage = class extends FactoryStorageDomain {
1185
1288
  ...disarm ? { autonomyArmedAt: null } : {},
1186
1289
  ...accept ? { acceptedAt: now } : {},
1187
1290
  ...classified ? { triageType } : {},
1291
+ ...this.#isTerminal({
1292
+ ...existing,
1293
+ stages: [input.destinationStage]
1294
+ }) ? { claimKey: null } : {},
1188
1295
  stages: [input.destinationStage],
1189
1296
  stageHistory: applyStageTransition(existing.stageHistory, existing.stages, [input.destinationStage], input.actorId, now),
1190
1297
  revision: existing.revision + 1,
@@ -2056,13 +2163,17 @@ var WorkItemsStorage = class extends FactoryStorageDomain {
2056
2163
  org_id: input.orgId,
2057
2164
  factory_project_id: input.factoryProjectId
2058
2165
  });
2059
- if (!bindingRow || !itemRow) throw new Error("Factory start replay references missing state.");
2060
- return {
2166
+ if (bindingRow && itemRow && bindingRow.status === "active") return {
2061
2167
  item: toRow(itemRow),
2062
2168
  binding: toBinding(bindingRow),
2063
2169
  pendingStart: toPendingStart(prior),
2064
2170
  replayed: true
2065
2171
  };
2172
+ await ops.deleteMany("factory_pending_starts", {
2173
+ id: prior.id,
2174
+ org_id: input.orgId,
2175
+ factory_project_id: input.factoryProjectId
2176
+ });
2066
2177
  }
2067
2178
  const now = /* @__PURE__ */ new Date();
2068
2179
  const create = input.workItem.input;
@@ -2078,11 +2189,16 @@ var WorkItemsStorage = class extends FactoryStorageDomain {
2078
2189
  let item;
2079
2190
  if (row) {
2080
2191
  row = await ops.updateAtomic("work_items", { id: row.id }, (current) => {
2081
- return applyUpdate({
2192
+ const next = applyUpdate({
2082
2193
  current,
2083
2194
  userId: input.userId,
2084
2195
  input: { sessions: { [input.role]: input.session } }
2085
2196
  });
2197
+ const adopt = this.#claimToAdopt(current, next, create);
2198
+ return adopt ? {
2199
+ ...next,
2200
+ claim_key: adopt
2201
+ } : next;
2086
2202
  });
2087
2203
  item = toRow(row);
2088
2204
  } else {
@@ -2097,6 +2213,7 @@ var WorkItemsStorage = class extends FactoryStorageDomain {
2097
2213
  board: create.board ?? null,
2098
2214
  external_source: create.externalSource ?? null,
2099
2215
  source_key: externalSourceKey(create.externalSource),
2216
+ claim_key: this.#claimForNewRow(create, create.stages ?? []),
2100
2217
  parent_work_item_id: create.parentWorkItemId ?? null,
2101
2218
  title: create.title,
2102
2219
  stages: create.stages ?? [],
@@ -2172,6 +2289,12 @@ var WorkItemsStorage = class extends FactoryStorageDomain {
2172
2289
  return await prepare();
2173
2290
  } catch (error) {
2174
2291
  if (!(error instanceof UniqueViolationError)) throw error;
2292
+ const claimKey = input.workItem.input.claimKey;
2293
+ const claimant = claimKey ? await this.#db.findOne("work_items", {
2294
+ org_id: input.orgId,
2295
+ claim_key: claimKey
2296
+ }) : null;
2297
+ if (claimant && claimant.factory_project_id !== input.factoryProjectId) throw new WorkItemClaimConflictError(toWorkItem(claimant));
2175
2298
  lastError = error;
2176
2299
  }
2177
2300
  throw lastError;
@@ -2199,6 +2322,17 @@ var WorkItemsStorage = class extends FactoryStorageDomain {
2199
2322
  return await execute();
2200
2323
  } catch (error) {
2201
2324
  if (!(error instanceof UniqueViolationError)) throw error;
2325
+ const claimKey = params.input.claimKey;
2326
+ const claimant = claimKey ? await this.#db.findOne("work_items", {
2327
+ org_id: params.orgId,
2328
+ claim_key: claimKey
2329
+ }) : null;
2330
+ if (claimant && claimant.factory_project_id !== params.factoryProjectId) throw new WorkItemClaimConflictError(toWorkItem(claimant));
2331
+ if (claimant) return {
2332
+ item: toWorkItem(claimant),
2333
+ created: false,
2334
+ previous: priorState(claimant)
2335
+ };
2202
2336
  return execute();
2203
2337
  }
2204
2338
  }
@@ -2212,11 +2346,18 @@ var WorkItemsStorage = class extends FactoryStorageDomain {
2212
2346
  source_key: key
2213
2347
  });
2214
2348
  if (!existing) return null;
2215
- if (reuseMode === "preserve") return {
2216
- created: false,
2217
- item: toWorkItem(existing),
2218
- previous: priorState(existing)
2219
- };
2349
+ if (reuseMode === "preserve") {
2350
+ const adopt = this.#claimToAdopt(existing, {}, input);
2351
+ return {
2352
+ created: false,
2353
+ item: toWorkItem((adopt ? await ops.updateAtomic("work_items", {
2354
+ org_id: orgId,
2355
+ factory_project_id: factoryProjectId,
2356
+ source_key: key
2357
+ }, (current) => current.claim_key === null ? { claim_key: adopt } : null) : null) ?? existing),
2358
+ previous: priorState(existing)
2359
+ };
2360
+ }
2220
2361
  let previous = emptyPrior();
2221
2362
  const updated = await ops.updateAtomic("work_items", {
2222
2363
  org_id: orgId,
@@ -2234,7 +2375,7 @@ var WorkItemsStorage = class extends FactoryStorageDomain {
2234
2375
  metadata: input.metadata
2235
2376
  } : fullPatch;
2236
2377
  if (patch.parentWorkItemId !== void 0) validateParentRelation(await this.#listWithOps(ops, orgId, factoryProjectId), current.id, patch.parentWorkItemId);
2237
- return {
2378
+ const next = {
2238
2379
  board: reuseMode === "non-stage" ? current.board : input.board ?? current.board ?? null,
2239
2380
  external_source: input.externalSource ?? null,
2240
2381
  ...applyUpdate({
@@ -2243,6 +2384,11 @@ var WorkItemsStorage = class extends FactoryStorageDomain {
2243
2384
  input: patch
2244
2385
  })
2245
2386
  };
2387
+ const adopt = this.#claimToAdopt(current, next, input);
2388
+ return adopt ? {
2389
+ ...next,
2390
+ claim_key: adopt
2391
+ } : next;
2246
2392
  });
2247
2393
  return updated ? {
2248
2394
  item: toWorkItem(updated),
@@ -2262,6 +2408,7 @@ var WorkItemsStorage = class extends FactoryStorageDomain {
2262
2408
  board: input.board ?? null,
2263
2409
  external_source: input.externalSource ?? null,
2264
2410
  source_key: key,
2411
+ claim_key: this.#claimForNewRow(input, stages),
2265
2412
  parent_work_item_id: input.parentWorkItemId ?? null,
2266
2413
  title: input.title,
2267
2414
  stages,
@@ -2314,11 +2461,11 @@ var WorkItemsStorage = class extends FactoryStorageDomain {
2314
2461
  if (expectedBoard !== void 0 && current.board !== expectedBoard) throw new WorkItemUpdateConflictError("board");
2315
2462
  if (expectedRevision !== void 0 && current.revision !== expectedRevision) throw new WorkItemUpdateConflictError("revision");
2316
2463
  if (patch.parentWorkItemId !== void 0) validateParentRelation(await this.#listWithOps(ops, orgId, current.factory_project_id), current.id, patch.parentWorkItemId);
2317
- return applyUpdate({
2464
+ return this.#releaseClaimIfFinished(current, applyUpdate({
2318
2465
  current,
2319
2466
  userId,
2320
2467
  input: patch
2321
- });
2468
+ }));
2322
2469
  });
2323
2470
  return row ? {
2324
2471
  item: toWorkItem(row),
@@ -2440,6 +2587,6 @@ var WorkItemsStorage = class extends FactoryStorageDomain {
2440
2587
  }
2441
2588
  };
2442
2589
  //#endregion
2443
- export { FACTORY_PULL_REQUEST_RECONCILIATION_KEY, FACTORY_RULE_MATERIALIZATION_KEY, WORK_ITEMS_SCHEMA, WorkItemRelationError, WorkItemUpdateConflictError, WorkItemsStorage, applyStageTransition, externalSourceKey, factoryActivityAttentionIdentity, factoryAgentWaitingAttentionIdentity, factoryAttentionKey, factoryDecisionAttentionIdentity, factoryDecisionHash, factoryMentionAttentionIdentity, factoryProposalAttentionIdentity, factorySupervisorFindingAttentionIdentity, isAgentActor, stampSessions, validateParentRelation };
2590
+ export { FACTORY_PULL_REQUEST_RECONCILIATION_KEY, FACTORY_RULE_MATERIALIZATION_KEY, WORK_ITEMS_SCHEMA, WorkItemClaimConflictError, WorkItemRelationError, WorkItemUpdateConflictError, WorkItemsStorage, applyStageTransition, externalSourceKey, factoryActivityAttentionIdentity, factoryAgentWaitingAttentionIdentity, factoryAttentionKey, factoryDecisionAttentionIdentity, factoryDecisionHash, factoryMentionAttentionIdentity, factoryProposalAttentionIdentity, factorySupervisorFindingAttentionIdentity, isAgentActor, stampSessions, validateParentRelation };
2444
2591
 
2445
2592
  //# sourceMappingURL=base.js.map