@runfusion/fusion 0.76.0-beta.3 → 0.77.0-beta.0

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 (175) hide show
  1. package/dist/bin.js +13802 -9587
  2. package/dist/child-process-worker.js +6472 -4028
  3. package/dist/client/.vite/manifest.json +280 -269
  4. package/dist/client/assets/AgentDetailView-0G9qFd4j.js +13 -0
  5. package/dist/client/assets/{AgentDetailView-Cc3ATg8a.css → AgentDetailView-jzgy1BAS.css} +1 -1
  6. package/dist/client/assets/{AgentPermissionPolicyEditor--u9jyUf2.js → AgentPermissionPolicyEditor-BM68g7wo.js} +1 -1
  7. package/dist/client/assets/AgentsView-DkOUZWw4.js +24 -0
  8. package/dist/client/assets/ChatView-BPSm2JIH.js +13 -0
  9. package/dist/client/assets/{CommandCenter-CSRYoveB.js → CommandCenter-DxRSFWNc.js} +26 -26
  10. package/dist/client/assets/CommandCenter-ilm-DbtI.css +1 -0
  11. package/dist/client/assets/{DevServerView-B9So_oYx.js → DevServerView-DO-bqJFE.js} +1 -1
  12. package/dist/client/assets/{DirectoryPicker-BhyDL_2m.js → DirectoryPicker-Cp2gddTE.js} +1 -1
  13. package/dist/client/assets/DocumentsView-D0E-3G96.js +1 -0
  14. package/dist/client/assets/EvalsView-BoFVq5hw.js +1 -0
  15. package/dist/client/assets/ExperimentalAgentOnboardingModal-CS1Sdogm.js +1 -0
  16. package/dist/client/assets/{GoalsView-B6X5_0Ve.js → GoalsView-sybf7JY4.js} +1 -1
  17. package/dist/client/assets/InsightsView-nHa7aShn.js +11 -0
  18. package/dist/client/assets/{MemoryView-DN_3IFmA.css → MemoryView-CdpQqPJJ.css} +1 -1
  19. package/dist/client/assets/MemoryView-D0IG44za.js +3 -0
  20. package/dist/client/assets/{PiExtensionsManager-B8At6fO8.js → PiExtensionsManager-CU76weJe.js} +2 -2
  21. package/dist/client/assets/PluginManager-DyT8XbcG.js +1 -0
  22. package/dist/client/assets/{PullRequestView-B1hZFrWo.js → PullRequestView-CnxWUSen.js} +2 -2
  23. package/dist/client/assets/{ReportModal-C46V_zEa.js → ReportModal-CMrmMQjD.js} +5 -5
  24. package/dist/client/assets/{ResearchView-D8G85BYN.js → ResearchView-BTytQSgy.js} +2 -2
  25. package/dist/client/assets/{SecretsView-CTri9LRK.js → SecretsView-BuSH5J87.js} +1 -1
  26. package/dist/client/assets/SessionTerminal-D04kYRrT.js +2 -0
  27. package/dist/client/assets/SettingsModal-C0FY8MPW.css +1 -0
  28. package/dist/client/assets/{SettingsModal-rUQcSTJp.js → SettingsModal-Dm-ngbRr.js} +1 -1
  29. package/dist/client/assets/{SettingsModal-DmfMotcd.css → SettingsModal-Ds0Yj47X.css} +1 -1
  30. package/dist/client/assets/SettingsModal-xSLhH7Tr.js +21 -0
  31. package/dist/client/assets/{SettingsTextareaRow-BirlBcem.js → SettingsTextareaRow-CHPgocEp.js} +1 -1
  32. package/dist/client/assets/{SetupWizardModal-xnCBM9EL.js → SetupWizardModal-y88aXNIQ.js} +2 -2
  33. package/dist/client/assets/{SkillsView-O5U0ep50.js → SkillsView-CYyQW1Hv.js} +1 -1
  34. package/dist/client/assets/{WorkflowNodeEditor-BX4d2qqF.js → WorkflowNodeEditor-hYeoz1X8.js} +3 -3
  35. package/dist/client/assets/{agent-import-generation-DnqVkPkz.js → agent-import-generation-CjiYXzCr.js} +1 -1
  36. package/dist/client/assets/agentsOrgChartLayout-C0UP_X3z.js +1 -0
  37. package/dist/client/assets/app-BgpuMvTU.js +13 -0
  38. package/dist/client/assets/app-BlexHhbW.js +13 -0
  39. package/dist/client/assets/app-BsuUOR0P.js +13 -0
  40. package/dist/client/assets/app-DQVOujmO.js +13 -0
  41. package/dist/client/assets/app-DjyTRx1N.js +5 -0
  42. package/dist/client/assets/app-Dniggype.js +13 -0
  43. package/dist/client/assets/app-EV-lyZ0T.js +5 -0
  44. package/dist/client/assets/{architectureDiagram-3BPJPVTR-gi467xY0.js → architectureDiagram-3BPJPVTR-Dd6GPcqM.js} +1 -1
  45. package/dist/client/assets/{blockDiagram-GPEHLZMM-B_gpcYiR.js → blockDiagram-GPEHLZMM-CC6pLxlz.js} +1 -1
  46. package/dist/client/assets/{c4Diagram-AAUBKEIU-DeylEYsQ.js → c4Diagram-AAUBKEIU-DxMP_l6y.js} +1 -1
  47. package/dist/client/assets/channel-DlCEMoEf.js +1 -0
  48. package/dist/client/assets/{chunk-2J33WTMH-BL2WY0HN.js → chunk-2J33WTMH-BKYToL43.js} +1 -1
  49. package/dist/client/assets/{chunk-4BX2VUAB-BkLExGMe.js → chunk-4BX2VUAB-Bg6rjQb3.js} +1 -1
  50. package/dist/client/assets/{chunk-55IACEB6-CSTvCF5T.js → chunk-55IACEB6-CPUwbbGa.js} +1 -1
  51. package/dist/client/assets/{chunk-727SXJPM-9J8pKk4x.js → chunk-727SXJPM-DScQBCvv.js} +1 -1
  52. package/dist/client/assets/{chunk-AQP2D5EJ-DXC1vPWr.js → chunk-AQP2D5EJ-DbX7uaXK.js} +1 -1
  53. package/dist/client/assets/{chunk-FMBD7UC4-CFRUb-zD.js → chunk-FMBD7UC4-DvYKea1c.js} +1 -1
  54. package/dist/client/assets/{chunk-ND2GUHAM-B87HFYS8.js → chunk-ND2GUHAM-CH-Tvw7w.js} +1 -1
  55. package/dist/client/assets/{chunk-QZHKN3VN-CTjHiGbd.js → chunk-QZHKN3VN-CbyEvOoM.js} +1 -1
  56. package/dist/client/assets/classDiagram-4FO5ZUOK-Bc92O8Ks.js +1 -0
  57. package/dist/client/assets/classDiagram-v2-Q7XG4LA2-Bc92O8Ks.js +1 -0
  58. package/dist/client/assets/{cose-bilkent-S5V4N54A-D3Edq3L9.js → cose-bilkent-S5V4N54A-BPB5fV3A.js} +1 -1
  59. package/dist/client/assets/{dagre-BM42HDAG-CwwbeQfN.js → dagre-BM42HDAG-CilYJ3rR.js} +1 -1
  60. package/dist/client/assets/{dashboard-view-QxQwJFLz.js → dashboard-view-BnGe8cWo.js} +1 -1
  61. package/dist/client/assets/{dashboard-view-BLAoW3D4.js → dashboard-view-DnVf3tmI.js} +1 -1
  62. package/dist/client/assets/{dashboard-view-DAlJxqiJ.js → dashboard-view-DoLU6FxZ.js} +1 -1
  63. package/dist/client/assets/{dashboard-view-aPzfv99T.js → dashboard-view-dChSM_So.js} +1 -1
  64. package/dist/client/assets/{diagram-2AECGRRQ-koJWWXE4.js → diagram-2AECGRRQ-m9u1Qhyx.js} +1 -1
  65. package/dist/client/assets/{diagram-5GNKFQAL-Yob5cOKT.js → diagram-5GNKFQAL-DVr7Kf0N.js} +1 -1
  66. package/dist/client/assets/{diagram-KO2AKTUF-DelvFSkK.js → diagram-KO2AKTUF-D7sgJDFx.js} +1 -1
  67. package/dist/client/assets/{diagram-LMA3HP47-CMput2h2.js → diagram-LMA3HP47-DNKNDS6r.js} +1 -1
  68. package/dist/client/assets/{diagram-OG6HWLK6-04VXDl79.js → diagram-OG6HWLK6-1Bff4FWn.js} +1 -1
  69. package/dist/client/assets/{erDiagram-TEJ5UH35-C9iP8Uyp.js → erDiagram-TEJ5UH35-DGua1UHN.js} +1 -1
  70. package/dist/client/assets/{flowDiagram-I6XJVG4X-DENQvu_t.js → flowDiagram-I6XJVG4X-UDfDtwsE.js} +1 -1
  71. package/dist/client/assets/{folder-open-D-554oji.js → folder-open-CteOypVk.js} +1 -1
  72. package/dist/client/assets/{ganttDiagram-6RSMTGT7-BqOttZAT.js → ganttDiagram-6RSMTGT7-COdmD328.js} +1 -1
  73. package/dist/client/assets/{gitGraphDiagram-PVQCEYII-CDcydi-5.js → gitGraphDiagram-PVQCEYII-SUSls7Kw.js} +1 -1
  74. package/dist/client/assets/index-0ovTXt3t.css +1 -0
  75. package/dist/client/assets/index-DpCHwyiD.js +2818 -0
  76. package/dist/client/assets/{infoDiagram-5YYISTIA-B5LQQnxt.js → infoDiagram-5YYISTIA-e_DloXj7.js} +1 -1
  77. package/dist/client/assets/{ishikawaDiagram-YF4QCWOH-DpFEt7D2.js → ishikawaDiagram-YF4QCWOH-DVWqihXg.js} +1 -1
  78. package/dist/client/assets/{journeyDiagram-JHISSGLW-MELtgu22.js → journeyDiagram-JHISSGLW-BcPY-XP0.js} +1 -1
  79. package/dist/client/assets/{kanban-definition-UN3LZRKU-h33PLATd.js → kanban-definition-UN3LZRKU-BCFG2Jle.js} +1 -1
  80. package/dist/client/assets/{mermaid.core-Dk2mUPOq.js → mermaid.core-5yPje9Bi.js} +4 -4
  81. package/dist/client/assets/{mindmap-definition-RKZ34NQL-B_T4O2-B.js → mindmap-definition-RKZ34NQL-DDApeT3K.js} +1 -1
  82. package/dist/client/assets/{pieDiagram-4H26LBE5-B1YIFkRl.js → pieDiagram-4H26LBE5-N61_jyeP.js} +1 -1
  83. package/dist/client/assets/{puzzle-hvecxlpJ.js → puzzle-BkaCP30D.js} +1 -1
  84. package/dist/client/assets/{quadrantDiagram-W4KKPZXB-BoGQR_hO.js → quadrantDiagram-W4KKPZXB-C5qHiApF.js} +1 -1
  85. package/dist/client/assets/{requirementDiagram-4Y6WPE33-BSDmUBIx.js → requirementDiagram-4Y6WPE33-C71okgzt.js} +1 -1
  86. package/dist/client/assets/{sankeyDiagram-5OEKKPKP-Dz_GqOa5.js → sankeyDiagram-5OEKKPKP-B2iKyLjB.js} +1 -1
  87. package/dist/client/assets/{sequenceDiagram-3UESZ5HK-B6twjYUH.js → sequenceDiagram-3UESZ5HK-DfdoYKKk.js} +1 -1
  88. package/dist/client/assets/{shield-alert-BX4WRJOv.js → shield-alert-BNSeDB8l.js} +1 -1
  89. package/dist/client/assets/standing-instructions-template-pZtzo1lK.js +20 -0
  90. package/dist/client/assets/standing-instructions-template-w7Ouw_37.css +1 -0
  91. package/dist/client/assets/{stateDiagram-AJRCARHV-DuwqWLx-.js → stateDiagram-AJRCARHV-lS-sUi12.js} +1 -1
  92. package/dist/client/assets/{stateDiagram-v2-BHNVJYJU-Bu8Sk187.js → stateDiagram-v2-BHNVJYJU-DXJNDrV9.js} +1 -1
  93. package/dist/client/assets/{timeline-definition-PNZ67QCA-BS6VnqSI.js → timeline-definition-PNZ67QCA-CCwvX81K.js} +1 -1
  94. package/dist/client/assets/{upload-CaDoyaMW.js → upload-CDovVbu2.js} +1 -1
  95. package/dist/client/assets/useDiscoveredSkillsCache-BYqP-afh.js +1 -0
  96. package/dist/client/assets/{users-C5uCLwVM.js → users-CTqECGLo.js} +1 -1
  97. package/dist/client/assets/{vennDiagram-CIIHVFJN-CUbzqT5Y.js → vennDiagram-CIIHVFJN-DaiR5nv9.js} +1 -1
  98. package/dist/client/assets/{wardley-L42UT6IY-Mv-NotFS.js → wardley-L42UT6IY-hA5IHyPW.js} +1 -1
  99. package/dist/client/assets/{wardleyDiagram-YWT4CUSO-DuYpvLZX.js → wardleyDiagram-YWT4CUSO-CILUNESc.js} +1 -1
  100. package/dist/client/assets/{xychartDiagram-2RQKCTM6-24_7QXdw.js → xychartDiagram-2RQKCTM6-72eNMmjz.js} +1 -1
  101. package/dist/client/index.html +2 -2
  102. package/dist/client/version.json +1 -1
  103. package/dist/droid-cli/package.json +1 -1
  104. package/dist/extension.js +10671 -6904
  105. package/dist/migrations/0059_fn_9037_tasks_source_agent_index.sql +3 -0
  106. package/dist/migrations/0060_fn_9059_workspace_coordination_leases.sql +10 -0
  107. package/dist/pi-claude-cli/package.json +1 -1
  108. package/dist/plugin-sdk/index.d.ts +190 -9
  109. package/dist/plugin-sdk/index.js +74 -28
  110. package/dist/plugins/fusion-plugin-acp-runtime/bundled.js +83 -29
  111. package/dist/plugins/fusion-plugin-acp-runtime/package.json +1 -1
  112. package/dist/plugins/fusion-plugin-claude-runtime/bundled.js +83 -29
  113. package/dist/plugins/fusion-plugin-claude-runtime/package.json +1 -1
  114. package/dist/plugins/fusion-plugin-cli-printing-press/bundled.js +74 -28
  115. package/dist/plugins/fusion-plugin-cli-printing-press/package.json +1 -1
  116. package/dist/plugins/fusion-plugin-compound-engineering/bundled.js +74 -28
  117. package/dist/plugins/fusion-plugin-compound-engineering/package.json +1 -1
  118. package/dist/plugins/fusion-plugin-cursor-runtime/bundled.js +1096 -73
  119. package/dist/plugins/fusion-plugin-cursor-runtime/package.json +1 -1
  120. package/dist/plugins/fusion-plugin-dependency-graph/bundled.js +74 -28
  121. package/dist/plugins/fusion-plugin-dependency-graph/package.json +1 -1
  122. package/dist/plugins/fusion-plugin-droid-runtime/bundled.js +74 -28
  123. package/dist/plugins/fusion-plugin-droid-runtime/package.json +1 -1
  124. package/dist/plugins/fusion-plugin-grok-runtime/bundled.js +83 -29
  125. package/dist/plugins/fusion-plugin-grok-runtime/package.json +1 -1
  126. package/dist/plugins/fusion-plugin-hermes-runtime/bundled.js +302 -71
  127. package/dist/plugins/fusion-plugin-hermes-runtime/package.json +1 -1
  128. package/dist/plugins/fusion-plugin-linear-import/bundled.js +74 -28
  129. package/dist/plugins/fusion-plugin-linear-import/package.json +1 -1
  130. package/dist/plugins/fusion-plugin-omp-runtime/bundled.js +83 -29
  131. package/dist/plugins/fusion-plugin-omp-runtime/package.json +1 -1
  132. package/dist/plugins/fusion-plugin-openclaw-runtime/bundled.js +74 -28
  133. package/dist/plugins/fusion-plugin-openclaw-runtime/package.json +1 -1
  134. package/dist/plugins/fusion-plugin-paperclip-runtime/bundled.js +74 -28
  135. package/dist/plugins/fusion-plugin-paperclip-runtime/package.json +1 -1
  136. package/dist/plugins/fusion-plugin-quality/bundled.js +176 -46
  137. package/dist/plugins/fusion-plugin-quality/package.json +1 -1
  138. package/dist/plugins/fusion-plugin-reports/bundled.js +74 -28
  139. package/dist/plugins/fusion-plugin-reports/package.json +1 -1
  140. package/dist/plugins/fusion-plugin-roadmap/bundled.js +74 -28
  141. package/dist/plugins/fusion-plugin-roadmap/package.json +1 -1
  142. package/dist/plugins/fusion-plugin-todos/bundled.js +74 -28
  143. package/dist/plugins/fusion-plugin-todos/package.json +1 -1
  144. package/dist/plugins/fusion-plugin-whatsapp-chat/bundled.js +74 -28
  145. package/dist/plugins/fusion-plugin-whatsapp-chat/package.json +1 -1
  146. package/package.json +1 -1
  147. package/skill/fusion/references/extension-tools.md +2 -0
  148. package/dist/client/assets/AgentDetailView-T767kKTg.js +0 -13
  149. package/dist/client/assets/AgentsView-6Ifu7qDr.js +0 -24
  150. package/dist/client/assets/ChatView-BV3lixQi.js +0 -13
  151. package/dist/client/assets/CommandCenter-CE4rYjHn.css +0 -1
  152. package/dist/client/assets/DocumentsView-pbERA7O-.js +0 -1
  153. package/dist/client/assets/EvalsView-DJQ4ltCg.js +0 -1
  154. package/dist/client/assets/ExperimentalAgentOnboardingModal-BwJuzkzB.js +0 -1
  155. package/dist/client/assets/InsightsView-CJgI0J7S.js +0 -11
  156. package/dist/client/assets/MemoryView-BHq1AHPu.js +0 -3
  157. package/dist/client/assets/PluginManager-k7hV7_9e.js +0 -1
  158. package/dist/client/assets/SessionTerminal-BRf6r4Vp.js +0 -2
  159. package/dist/client/assets/SettingsModal-B30rPfYC.css +0 -1
  160. package/dist/client/assets/SettingsModal-D0RBeZik.js +0 -21
  161. package/dist/client/assets/agentsOrgChartLayout-CKuzbhFf.js +0 -1
  162. package/dist/client/assets/app-B2FwULu2.js +0 -5
  163. package/dist/client/assets/app-B6nJaqAl.js +0 -13
  164. package/dist/client/assets/app-CGXZeIRc.js +0 -13
  165. package/dist/client/assets/app-CGtkeBF5.js +0 -13
  166. package/dist/client/assets/app-CNzN1Plu.js +0 -13
  167. package/dist/client/assets/app-DLs-f5yM.js +0 -13
  168. package/dist/client/assets/app-DsvtcRUG.js +0 -5
  169. package/dist/client/assets/channel-BoE8DeM4.js +0 -1
  170. package/dist/client/assets/classDiagram-4FO5ZUOK-qnbLX_9_.js +0 -1
  171. package/dist/client/assets/classDiagram-v2-Q7XG4LA2-qnbLX_9_.js +0 -1
  172. package/dist/client/assets/index-CXTd3LAB.css +0 -1
  173. package/dist/client/assets/index-CtYRoouR.js +0 -2818
  174. package/dist/client/assets/standing-instructions-template-BJY317CC.js +0 -20
  175. package/dist/client/assets/standing-instructions-template-Ddi_4TIk.css +0 -1
@@ -5776,7 +5776,9 @@ __export(project_exports, {
5776
5776
  workflowSettings: () => workflowSettings,
5777
5777
  workflowSteps: () => workflowSteps,
5778
5778
  workflowWorkItems: () => workflowWorkItems,
5779
- workflows: () => workflows
5779
+ workflows: () => workflows,
5780
+ workspaceCoordinationLeases: () => workspaceCoordinationLeases,
5781
+ workspaceLandIntents: () => workspaceLandIntents
5780
5782
  });
5781
5783
  var projectSchema = pgSchema(PROJECT_SCHEMA);
5782
5784
  var tasks = projectSchema.table("tasks", {
@@ -6043,6 +6045,9 @@ var tasks = projectSchema.table("tasks", {
6043
6045
  the gate is a full tasks-table scan. Sparse: most rows have NULL parent.
6044
6046
  */
6045
6047
  index("idxTasksSourceParentTaskId").on(t.sourceParentTaskId),
6048
+ /* FNXC:TaskRecommendations 2026-08-13-22:23: duplicate intake filters source
6049
+ * lineage on recommendation/agent creates; this sparse index avoids a task-table scan. */
6050
+ index("idxTasksProjectSourceAgentId").on(t.projectId, t.sourceAgentId).where(sql`${t.sourceAgentId} IS NOT NULL`),
6046
6051
  // FNXC:EphemeralAgentTaskCreation 2026-07-30-12:00: proposal retries share one stable key, so the database—not a read-before-create race—enforces at-most-once materialization.
6047
6052
  uniqueIndex("uqTasksProjectProposalClaimId").on(t.projectId, t.proposalClaimId).where(sql`${t.proposalClaimId} IS NOT NULL`),
6048
6053
  /*
@@ -6277,6 +6282,52 @@ var distributedTaskIdReservations = projectSchema.table("distributed_task_id_res
6277
6282
  index("idxDistributedTaskIdReservationsPrefixStatus").on(t.prefix, t.status),
6278
6283
  index("idxDistributedTaskIdReservationsExpiry").on(t.status, t.expiresAt)
6279
6284
  ]);
6285
+ var workspaceCoordinationLeases = projectSchema.table("workspace_coordination_leases", {
6286
+ projectId: text("project_id").notNull().default(sql`current_setting('fusion.project_id', true)`),
6287
+ leaseKey: text("lease_key").notNull(),
6288
+ kind: text("kind").notNull(),
6289
+ ownerTaskId: text("owner_task_id").notNull(),
6290
+ ownerNodeId: text("owner_node_id").notNull(),
6291
+ ownerIncarnationId: text("owner_incarnation_id").notNull(),
6292
+ ownerRunId: text("owner_run_id"),
6293
+ fenceToken: bigint("fence_token", { mode: "bigint" }).notNull().default(sql`0`),
6294
+ fenceRefName: text("fence_ref_name"),
6295
+ fenceRefSha: text("fence_ref_sha"),
6296
+ status: text("status").notNull(),
6297
+ acquiredAt: text("acquired_at").notNull(),
6298
+ renewedAt: text("renewed_at").notNull(),
6299
+ expiresAt: text("expires_at").notNull(),
6300
+ createdAt: text("created_at").notNull(),
6301
+ updatedAt: text("updated_at").notNull()
6302
+ }, (t) => [
6303
+ primaryKey({ columns: [t.projectId, t.leaseKey] }),
6304
+ check("workspace_coordination_leases_kind_check", sql`${t.kind} IN ('acquire', 'land', 'merge-dispatch')`),
6305
+ check("workspace_coordination_leases_status_check", sql`${t.status} IN ('held', 'released', 'expired')`),
6306
+ index("idxWorkspaceCoordinationLeasesOwnerTask").on(t.projectId, t.ownerTaskId),
6307
+ index("idxWorkspaceCoordinationLeasesOwnerNode").on(t.projectId, t.ownerNodeId),
6308
+ index("idxWorkspaceCoordinationLeasesExpiry").on(t.status, t.expiresAt)
6309
+ ]);
6310
+ var workspaceLandIntents = projectSchema.table("workspace_land_intents", {
6311
+ projectId: text("project_id").notNull().default(sql`current_setting('fusion.project_id', true)`),
6312
+ taskId: text("task_id").notNull(),
6313
+ repoRelPath: text("repo_rel_path").notNull(),
6314
+ remoteUrl: text("remote_url").notNull(),
6315
+ integrationRef: text("integration_ref").notNull(),
6316
+ intendedSha: text("intended_sha").notNull(),
6317
+ expectedTip: text("expected_tip").notNull(),
6318
+ fenceRefName: text("fence_ref_name").notNull(),
6319
+ fenceRefSha: text("fence_ref_sha").notNull(),
6320
+ ownerTaskId: text("owner_task_id").notNull(),
6321
+ ownerNodeId: text("owner_node_id").notNull(),
6322
+ ownerIncarnationId: text("owner_incarnation_id").notNull(),
6323
+ fenceToken: bigint("fence_token", { mode: "bigint" }).notNull(),
6324
+ status: text("status").notNull(),
6325
+ resolvedSha: text("resolved_sha"),
6326
+ resolution: text("resolution"),
6327
+ createdAt: text("created_at").notNull(),
6328
+ updatedAt: text("updated_at").notNull(),
6329
+ resolvedAt: text("resolved_at")
6330
+ }, (t) => [primaryKey({ columns: [t.projectId, t.taskId, t.repoRelPath] }), check("workspace_land_intents_status_check", sql`${t.status} IN ('pending', 'recorded', 'abandoned')`), check("workspace_land_intents_resolution_check", sql`${t.resolution} IS NULL OR ${t.resolution} IN ('landed', 'not-landed')`), index("idxWorkspaceLandIntentsStatus").on(t.projectId, t.status)]);
6280
6331
  var symbolLocks = projectSchema.table("symbol_locks", {
6281
6332
  projectId: text("project_id").notNull().default(sql`current_setting('fusion.project_id', true)`),
6282
6333
  symbolKey: text("symbol_key").notNull(),
@@ -8851,6 +8902,11 @@ var DEFAULT_GLOBAL_SETTINGS = {
8851
8902
  Critical-action confirmation dialogs stay enabled by default. This global-only preference may opt an operator into primary/default auto-approval, but project settings cannot enable it for collaborators.
8852
8903
  */
8853
8904
  skipConfirmationDialogs: false,
8905
+ /*
8906
+ FNXC:QuickEntry 2026-08-16-03:15:
8907
+ Quick Add keeps its historical Enter-to-submit behavior by default; only an operator's global preference may opt into newline-first entry.
8908
+ */
8909
+ quickAddSubmitOnEnter: true,
8854
8910
  language: void 0,
8855
8911
  defaultProvider: void 0,
8856
8912
  defaultCredentialInstanceId: void 0,
@@ -9313,9 +9369,6 @@ var DEFAULT_PROJECT_SETTINGS = {
9313
9369
  * New and unconfigured projects default AI merge to sync a dirty checked-out integration branch, restoring the legacy stash → fast-forward → restore landing behavior. Explicit persisted merger.allowDirtyLocalCheckoutSync values still win, and no existing-project migration stamps this default into storage.
9314
9370
  */
9315
9371
  merger: { mode: "ai", maxReviewPasses: 3, allowDirtyLocalCheckoutSync: true },
9316
- mergeDiffVolumeMinLines: void 0,
9317
- mergeDiffVolumeThreshold: void 0,
9318
- mergeDiffVolumeAllowlist: void 0,
9319
9372
  requiredChecks: void 0,
9320
9373
  mergeStrategyOverlapBehavior: "flip-to-prefer-branch",
9321
9374
  postMergeAuditMode: "warn",
@@ -17966,10 +18019,6 @@ var AgentStore = class _AgentStore extends EventEmitter {
17966
18019
  };
17967
18020
  await this.writeAgent(updated);
17968
18021
  this.emit("agent:stateChanged", agentId, currentState, newState);
17969
- if (this.asyncLayer) try {
17970
- await appendAgentActivityEvent(this.asyncLayer, { type: "agent:state-changed", attributionClaim: resolveAgentActivityAttribution([{ id: agentId, provenance: "roster" }], "executor"), taskId: updated.taskId, occurredAt: updated.updatedAt, discriminator: updated.updatedAt, metadata: { fromState: currentState, toState: newState, source: "update" } });
17971
- } catch {
17972
- }
17973
18022
  this.emit("agent:updated", updated, currentState);
17974
18023
  return updated;
17975
18024
  });
@@ -18461,10 +18510,10 @@ var AgentStore = class _AgentStore extends EventEmitter {
18461
18510
  return agents2;
18462
18511
  }
18463
18512
  /*
18464
- FNXC:MemoryAgent 2026-08-11-09:41:
18465
- Memory Keeper is custom because it is not a workflow-stage principal. Unlike the four routed
18466
- owners its heartbeat is enabled, while auto-claim remains off because it only maintains memory.
18467
- This runs during init, where createAgent name collisions would abort startup; preflight probes,
18513
+ FNXC:MemoryAgent 2026-08-16-02:31:
18514
+ Memory Keeper is custom because it is not a workflow-stage principal. Its heartbeat defaults off
18515
+ until an operator opts in, while auto-claim remains off because it only maintains memory. This
18516
+ runs during init, where createAgent name collisions would abort startup; preflight probes,
18468
18517
  a fallback name, a null degraded result, and the init-side catch keep an operator's same-named
18469
18518
  agent untouched and the project runnable.
18470
18519
  */
@@ -18490,7 +18539,13 @@ var AgentStore = class _AgentStore extends EventEmitter {
18490
18539
  roles: [...BUILTIN_MEMORY_AGENT_DEFAULT.roles],
18491
18540
  title: BUILTIN_MEMORY_AGENT_DEFAULT.title,
18492
18541
  metadata: { [BUILTIN_MEMORY_AGENT_PROVENANCE_KEY]: true },
18493
- runtimeConfig: { enabled: true, autoClaimRelevantTasks: false, heartbeatIntervalMs: 36e5 },
18542
+ /*
18543
+ FNXC:MemoryAgent 2026-08-16-02:31:
18544
+ Memory consolidation is opt-in: newly provisioned Memory Keepers must not begin
18545
+ hourly autonomous heartbeats until an operator enables the existing heartbeat toggle.
18546
+ Keep auto-claim off and the one-hour interval ready for that later opt-in.
18547
+ */
18548
+ runtimeConfig: { enabled: false, autoClaimRelevantTasks: false, heartbeatIntervalMs: 36e5 },
18494
18549
  instructionsText: BUILTIN_MEMORY_AGENT_DEFAULT.instructionsText,
18495
18550
  soul: BUILTIN_MEMORY_AGENT_DEFAULT.soul,
18496
18551
  bundleConfig: { ...BUILTIN_MEMORY_AGENT_DEFAULT.bundleConfig, files: [...BUILTIN_MEMORY_AGENT_DEFAULT.bundleConfig.files] }
@@ -18505,7 +18560,9 @@ var AgentStore = class _AgentStore extends EventEmitter {
18505
18560
  return owner;
18506
18561
  }
18507
18562
  const metadata = { ...owner.metadata ?? {}, [BUILTIN_MEMORY_AGENT_PROVENANCE_KEY]: true };
18508
- const runtimeConfig = { ...owner.runtimeConfig ?? {}, enabled: true, autoClaimRelevantTasks: false, heartbeatIntervalMs: 36e5 };
18563
+ const currentRuntimeConfig = owner.runtimeConfig ?? {};
18564
+ const enabled = typeof currentRuntimeConfig.enabled === "boolean" ? currentRuntimeConfig.enabled : false;
18565
+ const runtimeConfig = currentRuntimeConfig.enabled === enabled && currentRuntimeConfig.autoClaimRelevantTasks === false && currentRuntimeConfig.heartbeatIntervalMs === DEFAULT_AGENT_HEARTBEAT_INTERVAL_MS ? currentRuntimeConfig : { ...currentRuntimeConfig, enabled, autoClaimRelevantTasks: false, heartbeatIntervalMs: DEFAULT_AGENT_HEARTBEAT_INTERVAL_MS };
18509
18566
  const updates = {
18510
18567
  roles: [...BUILTIN_MEMORY_AGENT_DEFAULT.roles],
18511
18568
  role: "custom",
@@ -18515,7 +18572,9 @@ var AgentStore = class _AgentStore extends EventEmitter {
18515
18572
  instructionsText: owner.instructionsText?.trim() ? owner.instructionsText : BUILTIN_MEMORY_AGENT_DEFAULT.instructionsText,
18516
18573
  soul: owner.soul?.trim() ? owner.soul : BUILTIN_MEMORY_AGENT_DEFAULT.soul
18517
18574
  };
18518
- owner = { ...owner, ...updates, updatedAt: (/* @__PURE__ */ new Date()).toISOString() };
18575
+ const nextOwner = { ...owner, ...updates };
18576
+ if (JSON.stringify(nextOwner) === JSON.stringify(owner)) return owner;
18577
+ owner = { ...nextOwner, updatedAt: (/* @__PURE__ */ new Date()).toISOString() };
18519
18578
  await this.writeAgent(owner, executor);
18520
18579
  return owner;
18521
18580
  };
@@ -19387,19 +19446,6 @@ var AgentStore = class _AgentStore extends EventEmitter {
19387
19446
  this.agentSnapshotCache.set(agent.id, this.watchSnapshotOf(agent));
19388
19447
  if (stateChanged) {
19389
19448
  this.emit("agent:stateChanged", agent.id, previousState, agent.state);
19390
- if (this.asyncLayer) {
19391
- try {
19392
- await appendAgentActivityEvent(this.asyncLayer, {
19393
- type: "agent:state-changed",
19394
- attributionClaim: resolveAgentActivityAttribution([{ id: agent.id, provenance: "roster" }], "executor"),
19395
- taskId: agent.taskId,
19396
- occurredAt: agent.updatedAt,
19397
- discriminator: agent.updatedAt,
19398
- metadata: { fromState: previousState, toState: agent.state, source: "reconciliation" }
19399
- });
19400
- } catch {
19401
- }
19402
- }
19403
19449
  this.emit("agent:updated", agent, previousState);
19404
19450
  } else {
19405
19451
  this.emit("agent:updated", agent);
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fusion-plugin-examples/paperclip-runtime",
3
- "version": "0.2.85-beta.3",
3
+ "version": "0.2.86-beta.0",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": {
@@ -1077,7 +1077,7 @@ function sql(strings, ...params) {
1077
1077
  return new SQL([new StringChunk(str)]);
1078
1078
  }
1079
1079
  sql2.raw = raw;
1080
- function join3(chunks, separator) {
1080
+ function join4(chunks, separator) {
1081
1081
  const result = [];
1082
1082
  for (const [i, chunk] of chunks.entries()) {
1083
1083
  if (i > 0 && separator !== void 0) {
@@ -1087,7 +1087,7 @@ function sql(strings, ...params) {
1087
1087
  }
1088
1088
  return new SQL(result);
1089
1089
  }
1090
- sql2.join = join3;
1090
+ sql2.join = join4;
1091
1091
  function identifier(value) {
1092
1092
  return new Name(value);
1093
1093
  }
@@ -4538,7 +4538,7 @@ var PgSelectQueryBuilderBase = class extends TypedQueryBuilder {
4538
4538
  const baseTableName = this.tableName;
4539
4539
  const tableName = getTableLikeName(table);
4540
4540
  for (const item of extractUsedTable(table)) this.usedTables.add(item);
4541
- if (typeof tableName === "string" && this.config.joins?.some((join3) => join3.alias === tableName)) {
4541
+ if (typeof tableName === "string" && this.config.joins?.some((join4) => join4.alias === tableName)) {
4542
4542
  throw new Error(`Alias "${tableName}" is already used in this query`);
4543
4543
  }
4544
4544
  if (!this.isPartialSelect) {
@@ -5779,7 +5779,9 @@ __export(project_exports, {
5779
5779
  workflowSettings: () => workflowSettings,
5780
5780
  workflowSteps: () => workflowSteps,
5781
5781
  workflowWorkItems: () => workflowWorkItems,
5782
- workflows: () => workflows
5782
+ workflows: () => workflows,
5783
+ workspaceCoordinationLeases: () => workspaceCoordinationLeases,
5784
+ workspaceLandIntents: () => workspaceLandIntents
5783
5785
  });
5784
5786
  var projectSchema = pgSchema(PROJECT_SCHEMA);
5785
5787
  var tasks = projectSchema.table("tasks", {
@@ -6046,6 +6048,9 @@ var tasks = projectSchema.table("tasks", {
6046
6048
  the gate is a full tasks-table scan. Sparse: most rows have NULL parent.
6047
6049
  */
6048
6050
  index("idxTasksSourceParentTaskId").on(t.sourceParentTaskId),
6051
+ /* FNXC:TaskRecommendations 2026-08-13-22:23: duplicate intake filters source
6052
+ * lineage on recommendation/agent creates; this sparse index avoids a task-table scan. */
6053
+ index("idxTasksProjectSourceAgentId").on(t.projectId, t.sourceAgentId).where(sql`${t.sourceAgentId} IS NOT NULL`),
6049
6054
  // FNXC:EphemeralAgentTaskCreation 2026-07-30-12:00: proposal retries share one stable key, so the database—not a read-before-create race—enforces at-most-once materialization.
6050
6055
  uniqueIndex("uqTasksProjectProposalClaimId").on(t.projectId, t.proposalClaimId).where(sql`${t.proposalClaimId} IS NOT NULL`),
6051
6056
  /*
@@ -6280,6 +6285,52 @@ var distributedTaskIdReservations = projectSchema.table("distributed_task_id_res
6280
6285
  index("idxDistributedTaskIdReservationsPrefixStatus").on(t.prefix, t.status),
6281
6286
  index("idxDistributedTaskIdReservationsExpiry").on(t.status, t.expiresAt)
6282
6287
  ]);
6288
+ var workspaceCoordinationLeases = projectSchema.table("workspace_coordination_leases", {
6289
+ projectId: text("project_id").notNull().default(sql`current_setting('fusion.project_id', true)`),
6290
+ leaseKey: text("lease_key").notNull(),
6291
+ kind: text("kind").notNull(),
6292
+ ownerTaskId: text("owner_task_id").notNull(),
6293
+ ownerNodeId: text("owner_node_id").notNull(),
6294
+ ownerIncarnationId: text("owner_incarnation_id").notNull(),
6295
+ ownerRunId: text("owner_run_id"),
6296
+ fenceToken: bigint("fence_token", { mode: "bigint" }).notNull().default(sql`0`),
6297
+ fenceRefName: text("fence_ref_name"),
6298
+ fenceRefSha: text("fence_ref_sha"),
6299
+ status: text("status").notNull(),
6300
+ acquiredAt: text("acquired_at").notNull(),
6301
+ renewedAt: text("renewed_at").notNull(),
6302
+ expiresAt: text("expires_at").notNull(),
6303
+ createdAt: text("created_at").notNull(),
6304
+ updatedAt: text("updated_at").notNull()
6305
+ }, (t) => [
6306
+ primaryKey({ columns: [t.projectId, t.leaseKey] }),
6307
+ check("workspace_coordination_leases_kind_check", sql`${t.kind} IN ('acquire', 'land', 'merge-dispatch')`),
6308
+ check("workspace_coordination_leases_status_check", sql`${t.status} IN ('held', 'released', 'expired')`),
6309
+ index("idxWorkspaceCoordinationLeasesOwnerTask").on(t.projectId, t.ownerTaskId),
6310
+ index("idxWorkspaceCoordinationLeasesOwnerNode").on(t.projectId, t.ownerNodeId),
6311
+ index("idxWorkspaceCoordinationLeasesExpiry").on(t.status, t.expiresAt)
6312
+ ]);
6313
+ var workspaceLandIntents = projectSchema.table("workspace_land_intents", {
6314
+ projectId: text("project_id").notNull().default(sql`current_setting('fusion.project_id', true)`),
6315
+ taskId: text("task_id").notNull(),
6316
+ repoRelPath: text("repo_rel_path").notNull(),
6317
+ remoteUrl: text("remote_url").notNull(),
6318
+ integrationRef: text("integration_ref").notNull(),
6319
+ intendedSha: text("intended_sha").notNull(),
6320
+ expectedTip: text("expected_tip").notNull(),
6321
+ fenceRefName: text("fence_ref_name").notNull(),
6322
+ fenceRefSha: text("fence_ref_sha").notNull(),
6323
+ ownerTaskId: text("owner_task_id").notNull(),
6324
+ ownerNodeId: text("owner_node_id").notNull(),
6325
+ ownerIncarnationId: text("owner_incarnation_id").notNull(),
6326
+ fenceToken: bigint("fence_token", { mode: "bigint" }).notNull(),
6327
+ status: text("status").notNull(),
6328
+ resolvedSha: text("resolved_sha"),
6329
+ resolution: text("resolution"),
6330
+ createdAt: text("created_at").notNull(),
6331
+ updatedAt: text("updated_at").notNull(),
6332
+ resolvedAt: text("resolved_at")
6333
+ }, (t) => [primaryKey({ columns: [t.projectId, t.taskId, t.repoRelPath] }), check("workspace_land_intents_status_check", sql`${t.status} IN ('pending', 'recorded', 'abandoned')`), check("workspace_land_intents_resolution_check", sql`${t.resolution} IS NULL OR ${t.resolution} IN ('landed', 'not-landed')`), index("idxWorkspaceLandIntentsStatus").on(t.projectId, t.status)]);
6283
6334
  var symbolLocks = projectSchema.table("symbol_locks", {
6284
6335
  projectId: text("project_id").notNull().default(sql`current_setting('fusion.project_id', true)`),
6285
6336
  symbolKey: text("symbol_key").notNull(),
@@ -8854,6 +8905,11 @@ var DEFAULT_GLOBAL_SETTINGS = {
8854
8905
  Critical-action confirmation dialogs stay enabled by default. This global-only preference may opt an operator into primary/default auto-approval, but project settings cannot enable it for collaborators.
8855
8906
  */
8856
8907
  skipConfirmationDialogs: false,
8908
+ /*
8909
+ FNXC:QuickEntry 2026-08-16-03:15:
8910
+ Quick Add keeps its historical Enter-to-submit behavior by default; only an operator's global preference may opt into newline-first entry.
8911
+ */
8912
+ quickAddSubmitOnEnter: true,
8857
8913
  language: void 0,
8858
8914
  defaultProvider: void 0,
8859
8915
  defaultCredentialInstanceId: void 0,
@@ -9316,9 +9372,6 @@ var DEFAULT_PROJECT_SETTINGS = {
9316
9372
  * New and unconfigured projects default AI merge to sync a dirty checked-out integration branch, restoring the legacy stash → fast-forward → restore landing behavior. Explicit persisted merger.allowDirtyLocalCheckoutSync values still win, and no existing-project migration stamps this default into storage.
9317
9373
  */
9318
9374
  merger: { mode: "ai", maxReviewPasses: 3, allowDirtyLocalCheckoutSync: true },
9319
- mergeDiffVolumeMinLines: void 0,
9320
- mergeDiffVolumeThreshold: void 0,
9321
- mergeDiffVolumeAllowlist: void 0,
9322
9375
  requiredChecks: void 0,
9323
9376
  mergeStrategyOverlapBehavior: "flip-to-prefer-branch",
9324
9377
  postMergeAuditMode: "warn",
@@ -10655,26 +10708,26 @@ function validateParallelism(nodes2, outgoing, nodesById) {
10655
10708
  }
10656
10709
  const joinsReached = /* @__PURE__ */ new Set();
10657
10710
  for (const edge of branchEdges) {
10658
- const join4 = walkBranchToJoin(edge.to, split.id, outgoing, nodesById);
10659
- if (!join4) {
10711
+ const join5 = walkBranchToJoin(edge.to, split.id, outgoing, nodesById);
10712
+ if (!join5) {
10660
10713
  throw new WorkflowIrError(`split '${split.id}' has a branch with no reachable matching join`);
10661
10714
  }
10662
- joinsReached.add(join4);
10715
+ joinsReached.add(join5);
10663
10716
  }
10664
10717
  if (joinsReached.size !== 1) {
10665
10718
  throw new WorkflowIrError(`split '${split.id}' branches converge on more than one join`);
10666
10719
  }
10667
10720
  const joinId = [...joinsReached][0];
10668
- const join3 = nodesById.get(joinId);
10669
- const mode = join3.config?.mode;
10721
+ const join4 = nodesById.get(joinId);
10722
+ const mode = join4.config?.mode;
10670
10723
  if (mode && typeof mode === "object" && "quorum" in mode) {
10671
10724
  const n = mode.quorum;
10672
10725
  if (typeof n !== "number" || !Number.isInteger(n) || n < 1) {
10673
- throw new WorkflowIrError(`join '${join3.id}' quorum must be a positive integer`);
10726
+ throw new WorkflowIrError(`join '${join4.id}' quorum must be a positive integer`);
10674
10727
  }
10675
10728
  if (n > branchEdges.length) {
10676
10729
  throw new WorkflowIrError(
10677
- `join '${join3.id}' quorum(${n}) exceeds the split's ${branchEdges.length} branches`
10730
+ `join '${join4.id}' quorum(${n}) exceeds the split's ${branchEdges.length} branches`
10678
10731
  );
10679
10732
  }
10680
10733
  }
@@ -17969,10 +18022,6 @@ var AgentStore = class _AgentStore extends EventEmitter {
17969
18022
  };
17970
18023
  await this.writeAgent(updated);
17971
18024
  this.emit("agent:stateChanged", agentId, currentState, newState);
17972
- if (this.asyncLayer) try {
17973
- await appendAgentActivityEvent(this.asyncLayer, { type: "agent:state-changed", attributionClaim: resolveAgentActivityAttribution([{ id: agentId, provenance: "roster" }], "executor"), taskId: updated.taskId, occurredAt: updated.updatedAt, discriminator: updated.updatedAt, metadata: { fromState: currentState, toState: newState, source: "update" } });
17974
- } catch {
17975
- }
17976
18025
  this.emit("agent:updated", updated, currentState);
17977
18026
  return updated;
17978
18027
  });
@@ -18464,10 +18513,10 @@ var AgentStore = class _AgentStore extends EventEmitter {
18464
18513
  return agents2;
18465
18514
  }
18466
18515
  /*
18467
- FNXC:MemoryAgent 2026-08-11-09:41:
18468
- Memory Keeper is custom because it is not a workflow-stage principal. Unlike the four routed
18469
- owners its heartbeat is enabled, while auto-claim remains off because it only maintains memory.
18470
- This runs during init, where createAgent name collisions would abort startup; preflight probes,
18516
+ FNXC:MemoryAgent 2026-08-16-02:31:
18517
+ Memory Keeper is custom because it is not a workflow-stage principal. Its heartbeat defaults off
18518
+ until an operator opts in, while auto-claim remains off because it only maintains memory. This
18519
+ runs during init, where createAgent name collisions would abort startup; preflight probes,
18471
18520
  a fallback name, a null degraded result, and the init-side catch keep an operator's same-named
18472
18521
  agent untouched and the project runnable.
18473
18522
  */
@@ -18493,7 +18542,13 @@ var AgentStore = class _AgentStore extends EventEmitter {
18493
18542
  roles: [...BUILTIN_MEMORY_AGENT_DEFAULT.roles],
18494
18543
  title: BUILTIN_MEMORY_AGENT_DEFAULT.title,
18495
18544
  metadata: { [BUILTIN_MEMORY_AGENT_PROVENANCE_KEY]: true },
18496
- runtimeConfig: { enabled: true, autoClaimRelevantTasks: false, heartbeatIntervalMs: 36e5 },
18545
+ /*
18546
+ FNXC:MemoryAgent 2026-08-16-02:31:
18547
+ Memory consolidation is opt-in: newly provisioned Memory Keepers must not begin
18548
+ hourly autonomous heartbeats until an operator enables the existing heartbeat toggle.
18549
+ Keep auto-claim off and the one-hour interval ready for that later opt-in.
18550
+ */
18551
+ runtimeConfig: { enabled: false, autoClaimRelevantTasks: false, heartbeatIntervalMs: 36e5 },
18497
18552
  instructionsText: BUILTIN_MEMORY_AGENT_DEFAULT.instructionsText,
18498
18553
  soul: BUILTIN_MEMORY_AGENT_DEFAULT.soul,
18499
18554
  bundleConfig: { ...BUILTIN_MEMORY_AGENT_DEFAULT.bundleConfig, files: [...BUILTIN_MEMORY_AGENT_DEFAULT.bundleConfig.files] }
@@ -18508,7 +18563,9 @@ var AgentStore = class _AgentStore extends EventEmitter {
18508
18563
  return owner;
18509
18564
  }
18510
18565
  const metadata = { ...owner.metadata ?? {}, [BUILTIN_MEMORY_AGENT_PROVENANCE_KEY]: true };
18511
- const runtimeConfig = { ...owner.runtimeConfig ?? {}, enabled: true, autoClaimRelevantTasks: false, heartbeatIntervalMs: 36e5 };
18566
+ const currentRuntimeConfig = owner.runtimeConfig ?? {};
18567
+ const enabled = typeof currentRuntimeConfig.enabled === "boolean" ? currentRuntimeConfig.enabled : false;
18568
+ const runtimeConfig = currentRuntimeConfig.enabled === enabled && currentRuntimeConfig.autoClaimRelevantTasks === false && currentRuntimeConfig.heartbeatIntervalMs === DEFAULT_AGENT_HEARTBEAT_INTERVAL_MS ? currentRuntimeConfig : { ...currentRuntimeConfig, enabled, autoClaimRelevantTasks: false, heartbeatIntervalMs: DEFAULT_AGENT_HEARTBEAT_INTERVAL_MS };
18512
18569
  const updates = {
18513
18570
  roles: [...BUILTIN_MEMORY_AGENT_DEFAULT.roles],
18514
18571
  role: "custom",
@@ -18518,7 +18575,9 @@ var AgentStore = class _AgentStore extends EventEmitter {
18518
18575
  instructionsText: owner.instructionsText?.trim() ? owner.instructionsText : BUILTIN_MEMORY_AGENT_DEFAULT.instructionsText,
18519
18576
  soul: owner.soul?.trim() ? owner.soul : BUILTIN_MEMORY_AGENT_DEFAULT.soul
18520
18577
  };
18521
- owner = { ...owner, ...updates, updatedAt: (/* @__PURE__ */ new Date()).toISOString() };
18578
+ const nextOwner = { ...owner, ...updates };
18579
+ if (JSON.stringify(nextOwner) === JSON.stringify(owner)) return owner;
18580
+ owner = { ...nextOwner, updatedAt: (/* @__PURE__ */ new Date()).toISOString() };
18522
18581
  await this.writeAgent(owner, executor);
18523
18582
  return owner;
18524
18583
  };
@@ -19390,19 +19449,6 @@ var AgentStore = class _AgentStore extends EventEmitter {
19390
19449
  this.agentSnapshotCache.set(agent.id, this.watchSnapshotOf(agent));
19391
19450
  if (stateChanged) {
19392
19451
  this.emit("agent:stateChanged", agent.id, previousState, agent.state);
19393
- if (this.asyncLayer) {
19394
- try {
19395
- await appendAgentActivityEvent(this.asyncLayer, {
19396
- type: "agent:state-changed",
19397
- attributionClaim: resolveAgentActivityAttribution([{ id: agent.id, provenance: "roster" }], "executor"),
19398
- taskId: agent.taskId,
19399
- occurredAt: agent.updatedAt,
19400
- discriminator: agent.updatedAt,
19401
- metadata: { fromState: previousState, toState: agent.state, source: "reconciliation" }
19402
- });
19403
- } catch {
19404
- }
19405
- }
19406
19452
  this.emit("agent:updated", agent, previousState);
19407
19453
  } else {
19408
19454
  this.emit("agent:updated", agent);
@@ -19641,6 +19687,8 @@ var qualityPostgresSchema = {
19641
19687
  };
19642
19688
 
19643
19689
  // ../../plugins/fusion-plugin-quality/src/runner/command-presets.ts
19690
+ import { existsSync, readdirSync, readFileSync } from "node:fs";
19691
+ import { join as join2 } from "node:path";
19644
19692
  var QUALITY_PRESET_IDS = [
19645
19693
  "project-test",
19646
19694
  "test-gate",
@@ -19658,6 +19706,88 @@ function isSafeFilePathToken(path) {
19658
19706
  if (/[;&|`$<>\\]/.test(path)) return false;
19659
19707
  return true;
19660
19708
  }
19709
+ function quoteArg(value) {
19710
+ return `'${value.replace(/'/g, "'\\''")}'`;
19711
+ }
19712
+ function parseWorkspaceGlobs(workspaceYaml) {
19713
+ const globs = [];
19714
+ let inPackages = false;
19715
+ for (const rawLine of workspaceYaml.split("\n")) {
19716
+ const line2 = rawLine.trimEnd();
19717
+ if (/^packages\s*:/.test(line2)) {
19718
+ inPackages = true;
19719
+ continue;
19720
+ }
19721
+ if (!inPackages) continue;
19722
+ if (/^\S/.test(line2) && line2.trim() !== "") break;
19723
+ const match = line2.match(/^\s+-\s+['"]?([^'"#\s]+)['"]?/);
19724
+ if (match?.[1]) globs.push(match[1]);
19725
+ }
19726
+ return globs;
19727
+ }
19728
+ function resolveWorkspacePackageRoots(rootDir, globs) {
19729
+ const roots = /* @__PURE__ */ new Set();
19730
+ for (const glob of globs) {
19731
+ const starIndex = glob.indexOf("*");
19732
+ if (starIndex === -1) {
19733
+ if (existsSync(join2(rootDir, glob, "package.json"))) roots.add(glob);
19734
+ continue;
19735
+ }
19736
+ const prefix = glob.slice(0, starIndex).replace(/\/$/, "");
19737
+ let entries;
19738
+ try {
19739
+ entries = readdirSync(join2(rootDir, prefix), { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => entry.name);
19740
+ } catch {
19741
+ continue;
19742
+ }
19743
+ for (const entry of entries) {
19744
+ const packageRoot = `${prefix}/${entry}`;
19745
+ if (existsSync(join2(rootDir, packageRoot, "package.json"))) roots.add(packageRoot);
19746
+ }
19747
+ }
19748
+ return [...roots];
19749
+ }
19750
+ function groupPathsByWorkspacePackage(rootDir, paths) {
19751
+ let workspaceYaml;
19752
+ try {
19753
+ workspaceYaml = readFileSync(join2(rootDir, "pnpm-workspace.yaml"), "utf8");
19754
+ } catch {
19755
+ return [];
19756
+ }
19757
+ const packageRoots = resolveWorkspacePackageRoots(rootDir, parseWorkspaceGlobs(workspaceYaml));
19758
+ const groups = /* @__PURE__ */ new Map();
19759
+ for (const path of paths) {
19760
+ let matchedRoot;
19761
+ for (const packageRoot of packageRoots) {
19762
+ if (path.startsWith(`${packageRoot}/`) && (!matchedRoot || packageRoot.length > matchedRoot.length)) {
19763
+ matchedRoot = packageRoot;
19764
+ }
19765
+ }
19766
+ if (!matchedRoot) continue;
19767
+ let group = groups.get(matchedRoot);
19768
+ if (!group) {
19769
+ try {
19770
+ const parsed = JSON.parse(readFileSync(join2(rootDir, matchedRoot, "package.json"), "utf8"));
19771
+ if (typeof parsed.name !== "string" || !parsed.name) continue;
19772
+ group = { name: parsed.name, paths: /* @__PURE__ */ new Set() };
19773
+ groups.set(matchedRoot, group);
19774
+ } catch {
19775
+ continue;
19776
+ }
19777
+ }
19778
+ group.paths.add(path.slice(matchedRoot.length + 1));
19779
+ }
19780
+ return [...groups.entries()].map(([root, group]) => ({ root, name: group.name, paths: [...group.paths].sort() })).filter((group) => group.paths.length > 0).sort((left, right) => left.root.localeCompare(right.root));
19781
+ }
19782
+ function buildFileScopedCommand(resolutionRoot, paths) {
19783
+ const groups = groupPathsByWorkspacePackage(resolutionRoot, paths);
19784
+ if (groups.length === 0) {
19785
+ return `pnpm exec vitest run ${paths.map(quoteArg).join(" ")}`;
19786
+ }
19787
+ return groups.map(
19788
+ (group) => `pnpm --filter ${quoteArg(group.name)} exec vitest run ${group.paths.map(quoteArg).join(" ")}`
19789
+ ).join(" && ");
19790
+ }
19661
19791
  function resolvePresetCommand(input) {
19662
19792
  switch (input.preset) {
19663
19793
  case "project-test": {
@@ -19680,14 +19810,13 @@ function resolvePresetCommand(input) {
19680
19810
  if (paths.length === 0) {
19681
19811
  return { ok: false, reason: "No changed files for file-scoped run", code: "empty_files" };
19682
19812
  }
19683
- const safe = paths.filter(isSafeFilePathToken);
19813
+ const safe = [...new Set(paths.filter(isSafeFilePathToken))].sort();
19684
19814
  if (safe.length === 0) {
19685
19815
  return { ok: false, reason: "No safe file paths for file-scoped run", code: "empty_files" };
19686
19816
  }
19687
- const joined = safe.map((p) => JSON.stringify(p)).join(" ");
19688
19817
  return {
19689
19818
  ok: true,
19690
- command: `pnpm exec vitest run ${joined}`,
19819
+ command: buildFileScopedCommand(input.cwd ?? input.projectRoot, safe),
19691
19820
  label: "File-scoped tests"
19692
19821
  };
19693
19822
  }
@@ -20485,8 +20614,8 @@ function createPreviewSessionManager() {
20485
20614
  }
20486
20615
 
20487
20616
  // ../../plugins/fusion-plugin-quality/src/preview/task-code-worktree.ts
20488
- import { existsSync, mkdirSync } from "node:fs";
20489
- import { dirname as dirname2, join as join2 } from "node:path";
20617
+ import { existsSync as existsSync2, mkdirSync } from "node:fs";
20618
+ import { dirname as dirname2, join as join3 } from "node:path";
20490
20619
  import { execFile } from "node:child_process";
20491
20620
  import { promisify } from "node:util";
20492
20621
  var execFileAsync = promisify(execFile);
@@ -20511,7 +20640,7 @@ function isCommitSha(ref) {
20511
20640
  }
20512
20641
  function qualityQaWorktreePath(projectRoot, taskId) {
20513
20642
  const safe = taskId.replace(/[^a-zA-Z0-9._-]+/g, "-").toLowerCase();
20514
- return join2(projectRoot, ".fusion", "quality-qa", safe);
20643
+ return join3(projectRoot, ".fusion", "quality-qa", safe);
20515
20644
  }
20516
20645
  function candidateTaskCodeRefs(task) {
20517
20646
  const refs = [];
@@ -20532,7 +20661,7 @@ async function resolveTaskCodeRef(projectRoot, task) {
20532
20661
  async function resolveTaskCodeCwd(input) {
20533
20662
  const projectRoot = input.projectRoot.trim() || process.cwd();
20534
20663
  const live = typeof input.task.worktree === "string" ? input.task.worktree.trim() : "";
20535
- if (live && existsSync(live)) {
20664
+ if (live && existsSync2(live)) {
20536
20665
  return { cwd: live, cwdKind: "worktree", created: false };
20537
20666
  }
20538
20667
  const ref = await resolveTaskCodeRef(projectRoot, input.task);
@@ -20545,7 +20674,7 @@ async function resolveTaskCodeCwd(input) {
20545
20674
  throw err;
20546
20675
  }
20547
20676
  const path = qualityQaWorktreePath(projectRoot, input.task.id);
20548
- if (existsSync(path)) {
20677
+ if (existsSync2(path)) {
20549
20678
  try {
20550
20679
  if (isCommitSha(ref)) {
20551
20680
  await git(path, ["checkout", "--detach", ref]);
@@ -20735,6 +20864,7 @@ function createQualityRoutes() {
20735
20864
  preset,
20736
20865
  testCommand,
20737
20866
  projectRoot: rootDir,
20867
+ cwd,
20738
20868
  filePaths,
20739
20869
  confirmFullSuite
20740
20870
  });
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fusion-plugin-examples/quality",
3
- "version": "0.1.10-beta.3",
3
+ "version": "0.1.11-beta.0",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": {