@mastra/factory 0.12.0-alpha.0 → 0.12.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.
Files changed (174) hide show
  1. package/dist/factory.d.ts.map +1 -1
  2. package/dist/factory.js +37 -15
  3. package/dist/factory.js.map +1 -1
  4. package/dist/feed-events.d.ts +13 -0
  5. package/dist/feed-events.d.ts.map +1 -0
  6. package/dist/feed-events.js +25 -0
  7. package/dist/feed-events.js.map +1 -0
  8. package/dist/integrations/base.d.ts +9 -0
  9. package/dist/integrations/base.d.ts.map +1 -1
  10. package/dist/integrations/github/commits.d.ts +29 -0
  11. package/dist/integrations/github/commits.d.ts.map +1 -0
  12. package/dist/integrations/github/commits.js +29 -0
  13. package/dist/integrations/github/commits.js.map +1 -0
  14. package/dist/integrations/github/integration.d.ts.map +1 -1
  15. package/dist/integrations/github/integration.js +47 -10
  16. package/dist/integrations/github/integration.js.map +1 -1
  17. package/dist/integrations/github/issue-reconciler.d.ts.map +1 -1
  18. package/dist/integrations/github/issue-reconciler.js +22 -14
  19. package/dist/integrations/github/issue-reconciler.js.map +1 -1
  20. package/dist/integrations/github/reconcile-worker.d.ts.map +1 -1
  21. package/dist/integrations/github/reconcile-worker.js +3 -3
  22. package/dist/integrations/github/reconcile-worker.js.map +1 -1
  23. package/dist/integrations/github/routes.d.ts.map +1 -1
  24. package/dist/integrations/github/routes.js +35 -0
  25. package/dist/integrations/github/routes.js.map +1 -1
  26. package/dist/integrations/github/rules.d.ts +6 -0
  27. package/dist/integrations/github/rules.d.ts.map +1 -1
  28. package/dist/integrations/github/rules.js +58 -12
  29. package/dist/integrations/github/rules.js.map +1 -1
  30. package/dist/integrations/github/settle-or-abort.d.ts +7 -0
  31. package/dist/integrations/github/settle-or-abort.d.ts.map +1 -0
  32. package/dist/integrations/github/settle-or-abort.js +25 -0
  33. package/dist/integrations/github/settle-or-abort.js.map +1 -0
  34. package/dist/integrations/issue-reconcile-worker.js +1 -1
  35. package/dist/integrations/platform/github/event-worker.d.ts.map +1 -1
  36. package/dist/integrations/platform/github/event-worker.js +4 -4
  37. package/dist/integrations/platform/github/event-worker.js.map +1 -1
  38. package/dist/integrations/platform/github/integration.d.ts.map +1 -1
  39. package/dist/integrations/platform/github/integration.js +37 -5
  40. package/dist/integrations/platform/github/integration.js.map +1 -1
  41. package/dist/integrations/platform/linear/event-worker.js +1 -1
  42. package/dist/integrations/slack/feed-publisher.d.ts +26 -0
  43. package/dist/integrations/slack/feed-publisher.d.ts.map +1 -0
  44. package/dist/integrations/slack/feed-publisher.js +44 -0
  45. package/dist/integrations/slack/feed-publisher.js.map +1 -0
  46. package/dist/integrations/slack/integration.d.ts +2 -0
  47. package/dist/integrations/slack/integration.d.ts.map +1 -1
  48. package/dist/integrations/slack/integration.js +5 -0
  49. package/dist/integrations/slack/integration.js.map +1 -1
  50. package/dist/integrations/slack/slack.d.ts +13 -1
  51. package/dist/integrations/slack/slack.d.ts.map +1 -1
  52. package/dist/integrations/slack/slack.js +78 -6
  53. package/dist/integrations/slack/slack.js.map +1 -1
  54. package/dist/routes/attention-activity.d.ts +24 -0
  55. package/dist/routes/attention-activity.d.ts.map +1 -0
  56. package/dist/routes/attention-activity.js +143 -0
  57. package/dist/routes/attention-activity.js.map +1 -0
  58. package/dist/routes/attention-providers.d.ts +31 -1
  59. package/dist/routes/attention-providers.d.ts.map +1 -1
  60. package/dist/routes/attention-providers.js +4 -4
  61. package/dist/routes/attention-providers.js.map +1 -1
  62. package/dist/routes/attention.d.ts.map +1 -1
  63. package/dist/routes/attention.js +39 -11
  64. package/dist/routes/attention.js.map +1 -1
  65. package/dist/routes/projects.d.ts.map +1 -1
  66. package/dist/routes/projects.js +4 -0
  67. package/dist/routes/projects.js.map +1 -1
  68. package/dist/routes/skills.d.ts.map +1 -1
  69. package/dist/routes/skills.js +9 -3
  70. package/dist/routes/skills.js.map +1 -1
  71. package/dist/routes/surface.d.ts +5 -0
  72. package/dist/routes/surface.d.ts.map +1 -1
  73. package/dist/routes/surface.js +34 -6
  74. package/dist/routes/surface.js.map +1 -1
  75. package/dist/routes/tenant-credentials.d.ts +4 -4
  76. package/dist/routes/tenant-credentials.d.ts.map +1 -1
  77. package/dist/routes/tenant-credentials.js +22 -7
  78. package/dist/routes/tenant-credentials.js.map +1 -1
  79. package/dist/routes/work-items.d.ts.map +1 -1
  80. package/dist/routes/work-items.js +12 -1
  81. package/dist/routes/work-items.js.map +1 -1
  82. package/dist/rules/defaults.d.ts.map +1 -1
  83. package/dist/rules/defaults.js +20 -8
  84. package/dist/rules/defaults.js.map +1 -1
  85. package/dist/rules/dispatch-errors.d.ts.map +1 -1
  86. package/dist/rules/dispatch-errors.js +8 -0
  87. package/dist/rules/dispatch-errors.js.map +1 -1
  88. package/dist/rules/dispatcher.d.ts +5 -0
  89. package/dist/rules/dispatcher.d.ts.map +1 -1
  90. package/dist/rules/dispatcher.js +125 -62
  91. package/dist/rules/dispatcher.js.map +1 -1
  92. package/dist/rules/processor.d.ts.map +1 -1
  93. package/dist/rules/processor.js +2 -3
  94. package/dist/rules/processor.js.map +1 -1
  95. package/dist/rules/start-coordinator.d.ts +2 -0
  96. package/dist/rules/start-coordinator.d.ts.map +1 -1
  97. package/dist/rules/start-coordinator.js +6 -1
  98. package/dist/rules/start-coordinator.js.map +1 -1
  99. package/dist/rules/transition-service.d.ts +2 -2
  100. package/dist/rules/transition-service.d.ts.map +1 -1
  101. package/dist/rules/transition-service.js +33 -12
  102. package/dist/rules/transition-service.js.map +1 -1
  103. package/dist/rules/types.d.ts +27 -1
  104. package/dist/rules/types.d.ts.map +1 -1
  105. package/dist/rules/types.js +37 -1
  106. package/dist/rules/types.js.map +1 -1
  107. package/dist/rules/validation.d.ts.map +1 -1
  108. package/dist/rules/validation.js +3 -1
  109. package/dist/rules/validation.js.map +1 -1
  110. package/dist/sandbox/session-sandbox.d.ts.map +1 -1
  111. package/dist/sandbox/session-sandbox.js +2 -2
  112. package/dist/sandbox/session-sandbox.js.map +1 -1
  113. package/dist/sandbox/workdir.d.ts +7 -2
  114. package/dist/sandbox/workdir.d.ts.map +1 -1
  115. package/dist/sandbox/workdir.js +11 -4
  116. package/dist/sandbox/workdir.js.map +1 -1
  117. package/dist/skills/catalog.d.ts +4 -1
  118. package/dist/skills/catalog.d.ts.map +1 -1
  119. package/dist/skills/catalog.js +11 -4
  120. package/dist/skills/catalog.js.map +1 -1
  121. package/dist/skills/service.d.ts +2 -1
  122. package/dist/skills/service.d.ts.map +1 -1
  123. package/dist/skills/service.js +5 -2
  124. package/dist/skills/service.js.map +1 -1
  125. package/dist/storage/domains/comments/activity.d.ts +40 -0
  126. package/dist/storage/domains/comments/activity.d.ts.map +1 -0
  127. package/dist/storage/domains/comments/activity.js +94 -0
  128. package/dist/storage/domains/comments/activity.js.map +1 -0
  129. package/dist/storage/domains/comments/base.d.ts +13 -1
  130. package/dist/storage/domains/comments/base.d.ts.map +1 -1
  131. package/dist/storage/domains/comments/base.js +43 -7
  132. package/dist/storage/domains/comments/base.js.map +1 -1
  133. package/dist/storage/domains/comments/domain.d.ts +13 -3
  134. package/dist/storage/domains/comments/domain.d.ts.map +1 -1
  135. package/dist/storage/domains/comments/domain.js +31 -16
  136. package/dist/storage/domains/comments/domain.js.map +1 -1
  137. package/dist/storage/domains/comments/feed-context.d.ts +2 -0
  138. package/dist/storage/domains/comments/feed-context.d.ts.map +1 -1
  139. package/dist/storage/domains/comments/feed-context.js +6 -4
  140. package/dist/storage/domains/comments/feed-context.js.map +1 -1
  141. package/dist/storage/domains/comments/feed-sync.d.ts +9 -26
  142. package/dist/storage/domains/comments/feed-sync.d.ts.map +1 -1
  143. package/dist/storage/domains/comments/parse.d.ts +1 -0
  144. package/dist/storage/domains/comments/parse.d.ts.map +1 -1
  145. package/dist/storage/domains/comments/parse.js +2 -2
  146. package/dist/storage/domains/comments/parse.js.map +1 -1
  147. package/dist/storage/domains/comments/routes.d.ts +2 -0
  148. package/dist/storage/domains/comments/routes.d.ts.map +1 -1
  149. package/dist/storage/domains/comments/routes.js +49 -3
  150. package/dist/storage/domains/comments/routes.js.map +1 -1
  151. package/dist/storage/domains/comments/schema.d.ts +1 -0
  152. package/dist/storage/domains/comments/schema.d.ts.map +1 -1
  153. package/dist/storage/domains/comments/schema.js +45 -1
  154. package/dist/storage/domains/comments/schema.js.map +1 -1
  155. package/dist/storage/domains/projects/base.d.ts +3 -0
  156. package/dist/storage/domains/projects/base.d.ts.map +1 -1
  157. package/dist/storage/domains/projects/base.js +7 -0
  158. package/dist/storage/domains/projects/base.js.map +1 -1
  159. package/dist/storage/domains/source-control/inmemory.d.ts.map +1 -1
  160. package/dist/storage/domains/source-control/inmemory.js +5 -1
  161. package/dist/storage/domains/source-control/inmemory.js.map +1 -1
  162. package/dist/storage/domains/work-items/base.d.ts +46 -4
  163. package/dist/storage/domains/work-items/base.d.ts.map +1 -1
  164. package/dist/storage/domains/work-items/base.js +159 -61
  165. package/dist/storage/domains/work-items/base.js.map +1 -1
  166. package/dist/workspace.d.ts +20 -2
  167. package/dist/workspace.d.ts.map +1 -1
  168. package/dist/workspace.js +49 -15
  169. package/dist/workspace.js.map +1 -1
  170. package/factory-skills/factory-rereview/SKILL.md +13 -12
  171. package/factory-skills/factory-review/SKILL.md +13 -11
  172. package/factory-skills/factory-triage/SKILL.md +27 -6
  173. package/package.json +11 -12
  174. package/CHANGELOG.md +0 -3330
@@ -1,5 +1,5 @@
1
1
  import { isTerminalFactoryRuleStage } from "../../../rules/types.js";
2
- import { WORK_ITEM_COMMENTS_SCHEMA, WORK_ITEM_COMMENT_MENTIONS_SCHEMA } from "../comments/schema.js";
2
+ import { WORK_ITEM_ACTIVITY_SCHEMA, WORK_ITEM_COMMENTS_SCHEMA, WORK_ITEM_COMMENT_MENTIONS_SCHEMA } from "../comments/schema.js";
3
3
  import { createHash } from "crypto";
4
4
  import { FactoryStorageDomain, UniqueViolationError } from "@mastra/core/storage";
5
5
  //#region src/storage/domains/work-items/base.ts
@@ -43,6 +43,8 @@ const FACTORY_DISPATCH_FAILURE_CODES = [
43
43
  "source_repository_missing",
44
44
  "unsupported_provider_item",
45
45
  "notification_delivery_failed",
46
+ "plan_awaiting_approval",
47
+ "run_awaiting_input",
46
48
  "repository_git_missing",
47
49
  "repository_egress_blocked",
48
50
  "repository_clone_failed",
@@ -70,6 +72,14 @@ function factoryMentionAttentionIdentity(commentId) {
70
72
  occurrence: 0
71
73
  };
72
74
  }
75
+ /** Collapsed per work item, so the occurrence is what a new comment bumps. */
76
+ function factoryActivityAttentionIdentity(workItemId, occurrence) {
77
+ return {
78
+ kind: "activity",
79
+ sourceId: workItemId,
80
+ occurrence
81
+ };
82
+ }
73
83
  function factoryAttentionKey(factoryProjectId, identity) {
74
84
  return `factory:${factoryProjectId}:attention:${identity.kind}:${identity.sourceId}:${identity.occurrence}`;
75
85
  }
@@ -119,6 +129,10 @@ const WORK_ITEMS_SCHEMA = {
119
129
  type: "timestamp",
120
130
  nullable: true
121
131
  },
132
+ plans_preapproved_at: {
133
+ type: "timestamp",
134
+ nullable: true
135
+ },
122
136
  comment_count: {
123
137
  type: "integer",
124
138
  default: 0
@@ -139,25 +153,39 @@ const WORK_ITEMS_SCHEMA = {
139
153
  name: "work_items_project_source_key_unique",
140
154
  columns: ["factory_project_id", "source_key"]
141
155
  }],
142
- indexes: [{
143
- name: "work_items_org_project_created_at_id_idx",
144
- columns: [
145
- "org_id",
146
- "factory_project_id",
147
- "created_at",
148
- "id"
149
- ]
150
- }, {
151
- name: "work_items_project_parent_idx",
152
- columns: [
153
- "org_id",
154
- "factory_project_id",
155
- "parent_work_item_id"
156
- ]
157
- }]
156
+ indexes: [
157
+ {
158
+ name: "work_items_org_project_created_at_id_idx",
159
+ columns: [
160
+ "org_id",
161
+ "factory_project_id",
162
+ "created_at",
163
+ "id"
164
+ ]
165
+ },
166
+ {
167
+ name: "work_items_project_parent_idx",
168
+ columns: [
169
+ "org_id",
170
+ "factory_project_id",
171
+ "parent_work_item_id"
172
+ ]
173
+ },
174
+ {
175
+ name: "work_items_source_key_idx",
176
+ columns: ["source_key"]
177
+ }
178
+ ]
158
179
  };
159
- function sourceKey(source) {
160
- return source ? `${source.integrationId}:${source.type}:${source.externalId}` : null;
180
+ /**
181
+ * The one shape a platform id takes in a lookup key, for cards and for the
182
+ * comments mirrored off them alike: whoever writes a second builder reopens the
183
+ * cross-workspace collision the `workspaceId` is here to close.
184
+ */
185
+ function externalSourceKey(source) {
186
+ if (!source) return null;
187
+ const workspace = source.workspaceId ? `${source.workspaceId}:` : "";
188
+ return `${source.integrationId}:${source.type}:${workspace}${source.externalId}`;
161
189
  }
162
190
  function toWorkItem(row) {
163
191
  return {
@@ -173,6 +201,7 @@ function toWorkItem(row) {
173
201
  metadata: row.metadata,
174
202
  triageType: row.triage_type ?? null,
175
203
  autonomyArmedAt: row.autonomy_armed_at ?? null,
204
+ plansPreapprovedAt: row.plans_preapproved_at ?? null,
176
205
  commentCount: row.comment_count ?? 0,
177
206
  feedActivityAt: row.feed_activity_at ?? null,
178
207
  revision: row.revision,
@@ -191,7 +220,7 @@ function patchColumns(changes) {
191
220
  ...changes.sessions !== void 0 ? { sessions: changes.sessions } : {},
192
221
  ...changes.metadata !== void 0 ? { metadata: changes.metadata } : {},
193
222
  ...changes.triageType !== void 0 ? { triage_type: changes.triageType } : {},
194
- ...changes.autonomyArmedAt !== void 0 && changes.autonomyArmedAt !== null ? { autonomy_armed_at: changes.autonomyArmedAt } : {},
223
+ ...changes.autonomyArmedAt !== void 0 ? { autonomy_armed_at: changes.autonomyArmedAt } : {},
195
224
  ...changes.revision !== void 0 ? { revision: changes.revision } : {},
196
225
  ...changes.updatedAt !== void 0 ? { updated_at: changes.updatedAt } : {}
197
226
  };
@@ -577,6 +606,10 @@ const FACTORY_GOVERNANCE_SCHEMAS = [
577
606
  type: "text",
578
607
  nullable: true
579
608
  },
609
+ failure_code: {
610
+ type: "text",
611
+ nullable: true
612
+ },
580
613
  completed_at: {
581
614
  type: "timestamp",
582
615
  nullable: true
@@ -644,7 +677,7 @@ function toDeferredDecision(row) {
644
677
  };
645
678
  }
646
679
  function attentionReceiptKind(value) {
647
- if (value === "automation-failed" || value === "mention") return value;
680
+ if (value === "automation-failed" || value === "mention" || value === "activity") return value;
648
681
  throw new Error(`Unsupported attention receipt kind '${String(value)}'.`);
649
682
  }
650
683
  function attentionReceiptState(value) {
@@ -689,21 +722,32 @@ function toPendingStart(row) {
689
722
  leaseOwner: row.lease_owner ?? null,
690
723
  leaseExpiresAt: row.lease_expires_at ?? null,
691
724
  lastError: row.last_error ?? null,
725
+ failureCode: row.failure_code ?? null,
692
726
  completedAt: row.completed_at ?? null,
693
727
  createdAt: row.created_at,
694
728
  updatedAt: row.updated_at
695
729
  };
696
730
  }
697
731
  var WorkItemsStorage = class extends FactoryStorageDomain {
732
+ #attentionChanged = () => {};
698
733
  constructor() {
699
734
  super("work-items");
700
735
  }
736
+ /**
737
+ * Wired once at boot. Every write below that changes what this project's
738
+ * attention list projects announces it here — the one place a new such write
739
+ * has to remember, since clients stop polling while their stream is up.
740
+ */
741
+ onAttentionChanged(listener) {
742
+ this.#attentionChanged = listener;
743
+ }
701
744
  async init() {
702
745
  await this.ensureCollections([
703
746
  WORK_ITEMS_SCHEMA,
704
747
  ...FACTORY_GOVERNANCE_SCHEMAS,
705
748
  WORK_ITEM_COMMENTS_SCHEMA,
706
- WORK_ITEM_COMMENT_MENTIONS_SCHEMA
749
+ WORK_ITEM_COMMENT_MENTIONS_SCHEMA,
750
+ WORK_ITEM_ACTIVITY_SCHEMA
707
751
  ]);
708
752
  await this.repairLegacyAttentionState();
709
753
  }
@@ -812,7 +856,7 @@ var WorkItemsStorage = class extends FactoryStorageDomain {
812
856
  lease_owner: null,
813
857
  lease_expires_at: null,
814
858
  last_error: input.lastError,
815
- ...table === "factory_deferred_decisions" ? { failure_code: input.failureCode } : {},
859
+ failure_code: input.failureCode,
816
860
  completed_at: input.terminal ? input.now : null,
817
861
  ...table === "factory_deferred_decisions" && input.terminal ? { failure_occurrence: Number(current.failure_occurrence ?? 0) + 1 } : {},
818
862
  updated_at: input.now
@@ -873,6 +917,16 @@ var WorkItemsStorage = class extends FactoryStorageDomain {
873
917
  });
874
918
  return row ? toWorkItem(row) : null;
875
919
  }
920
+ /**
921
+ * Resolve the card a platform thread created, given only its external source.
922
+ * Bare of org/project because an inbound platform message carries neither: an
923
+ * unlinked sender has no tenant. Tenant safety rides on the key's
924
+ * `workspaceId` instead. Ambiguous matches resolve to nothing, not a guess.
925
+ */
926
+ async getBySource(source) {
927
+ const rows = await this.#db.findMany("work_items", { source_key: externalSourceKey(source) });
928
+ return rows.length === 1 ? toWorkItem(rows[0]) : null;
929
+ }
876
930
  async getForProject(orgId, factoryProjectId, id) {
877
931
  const row = await this.#db.findOne("work_items", {
878
932
  id,
@@ -922,19 +976,22 @@ var WorkItemsStorage = class extends FactoryStorageDomain {
922
976
  reason = input.evaluation.reason;
923
977
  return null;
924
978
  }
925
- const arm = input.armAutonomy === true && !existing.autonomyArmedAt;
979
+ const arm = input.autonomy === "arm" && !existing.autonomyArmedAt;
980
+ const disarm = input.autonomy === "disarm" && existing.autonomyArmedAt !== null;
926
981
  const triageType = existing.triageType ?? input.triageType ?? null;
927
982
  const classified = triageType !== existing.triageType;
928
- if (existing.stages.length === 1 && existing.stages[0] === input.destinationStage) return arm || classified ? patchColumns({
983
+ if (existing.stages.length === 1 && existing.stages[0] === input.destinationStage) return arm || disarm || classified ? patchColumns({
929
984
  ...arm ? { autonomyArmedAt: now } : {},
930
- ...classified ? { triageType } : {},
985
+ ...disarm ? { autonomyArmedAt: null } : {},
931
986
  ...classified ? {
987
+ triageType,
932
988
  revision: existing.revision + 1,
933
989
  updatedAt: now
934
990
  } : {}
935
991
  }) : null;
936
992
  return patchColumns({
937
993
  ...arm ? { autonomyArmedAt: now } : {},
994
+ ...disarm ? { autonomyArmedAt: null } : {},
938
995
  ...classified ? { triageType } : {},
939
996
  stages: [input.destinationStage],
940
997
  stageHistory: applyStageTransition(existing.stageHistory, existing.stages, [input.destinationStage], input.actorId, now),
@@ -983,29 +1040,34 @@ var WorkItemsStorage = class extends FactoryStorageDomain {
983
1040
  causal_chain: input.causalChain,
984
1041
  created_at: now
985
1042
  });
986
- if (outcome === "accepted" && input.evaluation.outcome === "accepted") for (const [index, decision] of input.evaluation.decisions.entries()) await ops.insertOne("factory_deferred_decisions", {
987
- org_id: input.orgId,
988
- factory_project_id: input.factoryProjectId,
989
- evaluation_id: evaluation.id,
990
- work_item_id: item.id,
991
- source_key: decisionSourceKey(decision),
992
- idempotency_key: String(decision.idempotencyKey),
993
- effect_ordinal: index,
994
- effect_hash: factoryDecisionHash(decision),
995
- causal_chain: input.causalChain,
996
- actor: null,
997
- decision,
998
- status: "pending",
999
- attempts: 0,
1000
- delivery_generation: 0,
1001
- available_at: now,
1002
- lease_owner: null,
1003
- lease_expires_at: null,
1004
- last_error: null,
1005
- completed_at: null,
1006
- created_at: new Date(now.getTime() + index),
1007
- updated_at: now
1008
- });
1043
+ if (outcome === "accepted" && input.evaluation.outcome === "accepted") for (const [index, decision] of input.evaluation.decisions.entries()) {
1044
+ const approvedBy = decision.type === "invokeSkill" ? input.consentedBy ?? null : null;
1045
+ await ops.insertOne("factory_deferred_decisions", {
1046
+ org_id: input.orgId,
1047
+ factory_project_id: input.factoryProjectId,
1048
+ evaluation_id: evaluation.id,
1049
+ work_item_id: item.id,
1050
+ source_key: decisionSourceKey(decision),
1051
+ idempotency_key: String(decision.idempotencyKey),
1052
+ effect_ordinal: index,
1053
+ effect_hash: factoryDecisionHash(decision),
1054
+ causal_chain: input.causalChain,
1055
+ actor: null,
1056
+ decision,
1057
+ status: "pending",
1058
+ attempts: 0,
1059
+ delivery_generation: 0,
1060
+ available_at: now,
1061
+ lease_owner: null,
1062
+ lease_expires_at: null,
1063
+ last_error: null,
1064
+ approved_at: approvedBy ? now : null,
1065
+ approved_by: approvedBy,
1066
+ completed_at: null,
1067
+ created_at: new Date(now.getTime() + index),
1068
+ updated_at: now
1069
+ });
1070
+ }
1009
1071
  }
1010
1072
  return {
1011
1073
  status: "committed",
@@ -1282,6 +1344,13 @@ var WorkItemsStorage = class extends FactoryStorageDomain {
1282
1344
  });
1283
1345
  return Boolean(decision) && currentOccurrence;
1284
1346
  }
1347
+ if (identity.kind === "activity") return await ops.findOne("work_item_activity", {
1348
+ work_item_id: identity.sourceId,
1349
+ participant_id: userId,
1350
+ org_id: orgId,
1351
+ factory_project_id: factoryProjectId,
1352
+ occurrence: identity.occurrence
1353
+ }) !== null;
1285
1354
  if (identity.occurrence !== 0) return false;
1286
1355
  if (!await ops.findOne("work_item_comment_mentions", {
1287
1356
  comment_id: identity.sourceId,
@@ -1364,7 +1433,10 @@ var WorkItemsStorage = class extends FactoryStorageDomain {
1364
1433
  }
1365
1434
  async failDeferredDecision(input) {
1366
1435
  const row = await this.#failLease("factory_deferred_decisions", input);
1367
- return row ? toDeferredDecision(row) : null;
1436
+ if (!row) return null;
1437
+ const record = toDeferredDecision(row);
1438
+ if (input.terminal) this.#attentionChanged(record);
1439
+ return record;
1368
1440
  }
1369
1441
  /** Park a claimed effect for human approval; the dispatcher never claims `proposed` rows. */
1370
1442
  async proposeDeferredDecision(identity, now) {
@@ -1384,7 +1456,10 @@ var WorkItemsStorage = class extends FactoryStorageDomain {
1384
1456
  updated_at: now
1385
1457
  };
1386
1458
  });
1387
- return proposed && row ? toDeferredDecision(row) : null;
1459
+ if (!proposed || !row) return null;
1460
+ const record = toDeferredDecision(row);
1461
+ this.#attentionChanged(record);
1462
+ return record;
1388
1463
  }
1389
1464
  /**
1390
1465
  * Release an approved effect back to the dispatcher; only `proposed` rows are
@@ -1393,7 +1468,7 @@ var WorkItemsStorage = class extends FactoryStorageDomain {
1393
1468
  * leaving its follow-up work parked for re-approval.
1394
1469
  */
1395
1470
  async approveDeferredDecision(orgId, factoryProjectId, decisionId, now, approvedBy) {
1396
- return this.storage.withTransaction(async (ops) => {
1471
+ const approved = await this.storage.withTransaction(async (ops) => {
1397
1472
  let settled = false;
1398
1473
  const row = await ops.updateAtomic("factory_deferred_decisions", {
1399
1474
  id: decisionId,
@@ -1419,6 +1494,8 @@ var WorkItemsStorage = class extends FactoryStorageDomain {
1419
1494
  }, (current) => current.autonomy_armed_at ? null : { autonomy_armed_at: now });
1420
1495
  return record;
1421
1496
  });
1497
+ if (approved) this.#attentionChanged(approved);
1498
+ return approved;
1422
1499
  }
1423
1500
  /** Retire a proposal nobody wants: `dismissed` is terminal, so the run never happens. */
1424
1501
  async dismissDeferredDecision(orgId, factoryProjectId, decisionId, now) {
@@ -1477,10 +1554,13 @@ var WorkItemsStorage = class extends FactoryStorageDomain {
1477
1554
  settled = true;
1478
1555
  return patch;
1479
1556
  });
1480
- return settled && row ? toDeferredDecision(row) : null;
1557
+ if (!settled || !row) return null;
1558
+ const record = toDeferredDecision(row);
1559
+ this.#attentionChanged(record);
1560
+ return record;
1481
1561
  }
1482
1562
  async #resolveFailedDecision({ orgId, factoryProjectId, decisionId, status, now }) {
1483
- return this.storage.withTransaction(async (ops) => {
1563
+ const resolved = await this.storage.withTransaction(async (ops) => {
1484
1564
  let resolved = false;
1485
1565
  const row = await ops.updateAtomic("factory_deferred_decisions", {
1486
1566
  id: decisionId,
@@ -1504,6 +1584,8 @@ var WorkItemsStorage = class extends FactoryStorageDomain {
1504
1584
  });
1505
1585
  return toDeferredDecision(row);
1506
1586
  });
1587
+ if (resolved) this.#attentionChanged(resolved);
1588
+ return resolved;
1507
1589
  }
1508
1590
  async supersedeTerminalDecisionsForWorkItem(input) {
1509
1591
  await this.supersedeDecisionsForWorkItem(input);
@@ -1560,7 +1642,7 @@ var WorkItemsStorage = class extends FactoryStorageDomain {
1560
1642
  }
1561
1643
  /** Requeue the same idempotent terminal effect; non-failed decisions are never rerun. */
1562
1644
  async retryDeferredDecision(orgId, factoryProjectId, decisionId, now) {
1563
- return this.storage.withTransaction(async (ops) => {
1645
+ const retriedRecord = await this.storage.withTransaction(async (ops) => {
1564
1646
  let retried = false;
1565
1647
  const row = await ops.updateAtomic("factory_deferred_decisions", {
1566
1648
  id: decisionId,
@@ -1592,6 +1674,8 @@ var WorkItemsStorage = class extends FactoryStorageDomain {
1592
1674
  });
1593
1675
  return toDeferredDecision(row);
1594
1676
  });
1677
+ if (retriedRecord) this.#attentionChanged(retriedRecord);
1678
+ return retriedRecord;
1595
1679
  }
1596
1680
  /** Resolve exact active agent authority; partial session matches never authorize. */
1597
1681
  async findActiveRunBinding(address) {
@@ -1769,10 +1853,10 @@ var WorkItemsStorage = class extends FactoryStorageDomain {
1769
1853
  id: input.workItem.id,
1770
1854
  org_id: input.orgId,
1771
1855
  factory_project_id: input.factoryProjectId
1772
- }) : sourceKey(create.externalSource) ? await ops.findOne("work_items", {
1856
+ }) : externalSourceKey(create.externalSource) ? await ops.findOne("work_items", {
1773
1857
  org_id: input.orgId,
1774
1858
  factory_project_id: input.factoryProjectId,
1775
- source_key: sourceKey(create.externalSource)
1859
+ source_key: externalSourceKey(create.externalSource)
1776
1860
  }) : null;
1777
1861
  let item;
1778
1862
  if (row) {
@@ -1794,7 +1878,7 @@ var WorkItemsStorage = class extends FactoryStorageDomain {
1794
1878
  created_by: input.userId,
1795
1879
  factory_project_id: input.factoryProjectId,
1796
1880
  external_source: create.externalSource ?? null,
1797
- source_key: sourceKey(create.externalSource),
1881
+ source_key: externalSourceKey(create.externalSource),
1798
1882
  parent_work_item_id: create.parentWorkItemId ?? null,
1799
1883
  title: create.title,
1800
1884
  stages: create.stages ?? [],
@@ -1811,6 +1895,10 @@ var WorkItemsStorage = class extends FactoryStorageDomain {
1811
1895
  const armedRow = await ops.updateAtomic("work_items", { id: item.id }, (current) => current.autonomy_armed_at ? null : { autonomy_armed_at: now });
1812
1896
  if (armedRow) item = toRow(armedRow);
1813
1897
  }
1898
+ if (input.preapprovePlans && !item.plansPreapprovedAt) {
1899
+ const grantedRow = await ops.updateAtomic("work_items", { id: item.id }, (current) => current.plans_preapproved_at ? null : { plans_preapproved_at: now });
1900
+ if (grantedRow) item = toRow(grantedRow);
1901
+ }
1814
1902
  await ops.updateMany("factory_run_bindings", {
1815
1903
  org_id: input.orgId,
1816
1904
  factory_project_id: input.factoryProjectId,
@@ -1857,6 +1945,7 @@ var WorkItemsStorage = class extends FactoryStorageDomain {
1857
1945
  lease_owner: null,
1858
1946
  lease_expires_at: null,
1859
1947
  last_error: null,
1948
+ failure_code: null,
1860
1949
  completed_at: null,
1861
1950
  created_at: now,
1862
1951
  updated_at: now
@@ -1904,7 +1993,7 @@ var WorkItemsStorage = class extends FactoryStorageDomain {
1904
1993
  }
1905
1994
  }
1906
1995
  async #upsert({ orgId, userId, factoryProjectId, input, reuseMode = "update" }, ops) {
1907
- const key = sourceKey(input.externalSource);
1996
+ const key = externalSourceKey(input.externalSource);
1908
1997
  const reuse = async () => {
1909
1998
  if (!key) return null;
1910
1999
  const existing = await ops.findOne("work_items", {
@@ -2101,6 +2190,13 @@ var WorkItemsStorage = class extends FactoryStorageDomain {
2101
2190
  if (comments.length < ATTENTION_RECEIPT_QUERY_BATCH_SIZE) break;
2102
2191
  }
2103
2192
  await ops.deleteMany("work_item_comment_mentions", where);
2193
+ await ops.deleteMany("factory_attention_receipts", {
2194
+ org_id: orgId,
2195
+ factory_project_id: factoryProjectId,
2196
+ kind: "activity",
2197
+ source_id: workItemId
2198
+ });
2199
+ await ops.deleteMany("work_item_activity", where);
2104
2200
  }
2105
2201
  async delete({ orgId, id }) {
2106
2202
  const candidate = await this.#db.findOne("work_items", {
@@ -2108,7 +2204,7 @@ var WorkItemsStorage = class extends FactoryStorageDomain {
2108
2204
  id
2109
2205
  });
2110
2206
  if (!candidate) return null;
2111
- return this.#withProjectRelationTransaction(orgId, candidate.factory_project_id, async (ops) => {
2207
+ const removed = await this.#withProjectRelationTransaction(orgId, candidate.factory_project_id, async (ops) => {
2112
2208
  const existing = await ops.findOne("work_items", {
2113
2209
  org_id: orgId,
2114
2210
  id
@@ -2137,9 +2233,11 @@ var WorkItemsStorage = class extends FactoryStorageDomain {
2137
2233
  });
2138
2234
  return toWorkItem(existing);
2139
2235
  });
2236
+ if (removed) this.#attentionChanged(removed);
2237
+ return removed;
2140
2238
  }
2141
2239
  };
2142
2240
  //#endregion
2143
- export { FACTORY_PULL_REQUEST_RECONCILIATION_KEY, FACTORY_RULE_MATERIALIZATION_KEY, WORK_ITEMS_SCHEMA, WorkItemRelationError, WorkItemsStorage, applyStageTransition, factoryAttentionKey, factoryDecisionAttentionIdentity, factoryDecisionHash, factoryMentionAttentionIdentity, isAgentActor, stampSessions, validateParentRelation };
2241
+ export { FACTORY_PULL_REQUEST_RECONCILIATION_KEY, FACTORY_RULE_MATERIALIZATION_KEY, WORK_ITEMS_SCHEMA, WorkItemRelationError, WorkItemsStorage, applyStageTransition, externalSourceKey, factoryActivityAttentionIdentity, factoryAttentionKey, factoryDecisionAttentionIdentity, factoryDecisionHash, factoryMentionAttentionIdentity, isAgentActor, stampSessions, validateParentRelation };
2144
2242
 
2145
2243
  //# sourceMappingURL=base.js.map