@runfusion/fusion 0.76.0-beta.1 → 0.76.0-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (138) hide show
  1. package/dist/bin.js +503 -213
  2. package/dist/child-process-worker.js +466 -207
  3. package/dist/client/.vite/manifest.json +260 -260
  4. package/dist/client/assets/{AgentDetailView-Cbl1sw6i.js → AgentDetailView-gak4EWTI.js} +1 -1
  5. package/dist/client/assets/{AgentPermissionPolicyEditor-DD1U5M9p.js → AgentPermissionPolicyEditor-DP1QbZL-.js} +1 -1
  6. package/dist/client/assets/{AgentsView-BMcCbple.js → AgentsView-DAMRTKzI.js} +3 -3
  7. package/dist/client/assets/ChatView-iE-2gf5P.js +13 -0
  8. package/dist/client/assets/{CommandCenter-D7mcD61V.js → CommandCenter-B6RnkLYm.js} +1 -1
  9. package/dist/client/assets/{DevServerView-DaqCn0p5.js → DevServerView-DcFL_LzK.js} +1 -1
  10. package/dist/client/assets/{DirectoryPicker-CLdqqqYN.js → DirectoryPicker-CtjqrYoO.js} +1 -1
  11. package/dist/client/assets/{DocumentsView-BOROVxPm.js → DocumentsView-BkAe2S4H.js} +1 -1
  12. package/dist/client/assets/{EvalsView-BQMXRUlQ.js → EvalsView-CbGA9dMn.js} +1 -1
  13. package/dist/client/assets/{ExperimentalAgentOnboardingModal-1GNeCIQT.js → ExperimentalAgentOnboardingModal-CMgO_S8T.js} +1 -1
  14. package/dist/client/assets/{GoalsView-Cr3c_2GC.js → GoalsView-_3P9J5sf.js} +1 -1
  15. package/dist/client/assets/{InsightsView-DgVBVQM4.js → InsightsView-DOhO7xH5.js} +1 -1
  16. package/dist/client/assets/{MemoryView-C0VzzMSw.js → MemoryView-DwJas8vi.js} +1 -1
  17. package/dist/client/assets/{PiExtensionsManager-D1kkkVtP.js → PiExtensionsManager-B_LiW_e9.js} +1 -1
  18. package/dist/client/assets/{PluginManager-BW-_Zyo5.js → PluginManager-BkB6WLQc.js} +1 -1
  19. package/dist/client/assets/{PullRequestView-Cmlo4nWA.js → PullRequestView-DcH5tmYc.js} +1 -1
  20. package/dist/client/assets/{ReportModal-BWuaroTF.js → ReportModal-BOEbqtqG.js} +1 -1
  21. package/dist/client/assets/{ResearchView-BmkF_vZU.js → ResearchView-Dp6V42pI.js} +1 -1
  22. package/dist/client/assets/{SecretsView-DVc8Hky0.js → SecretsView-BCqXHB2L.js} +1 -1
  23. package/dist/client/assets/{SessionTerminal-DCXrxA57.js → SessionTerminal-CkdoQv4y.js} +1 -1
  24. package/dist/client/assets/{SettingsModal-DZ32F1c-.js → SettingsModal-D4Fn4GlS.js} +3 -3
  25. package/dist/client/assets/{SettingsModal-DqwpLnDU.js → SettingsModal-Dc7YG6KB.js} +1 -1
  26. package/dist/client/assets/{SettingsTextareaRow-B5spAoOY.js → SettingsTextareaRow-WSkBoAOO.js} +1 -1
  27. package/dist/client/assets/{SetupWizardModal-VTBLyFzr.js → SetupWizardModal-VTrJAsKd.js} +2 -2
  28. package/dist/client/assets/{SkillsView-CR91ey9d.js → SkillsView-CXeXOxfF.js} +1 -1
  29. package/dist/client/assets/{WorkflowNodeEditor-BzGh_Fd9.js → WorkflowNodeEditor-DoxLGPRF.js} +1 -1
  30. package/dist/client/assets/{agent-import-generation-D27NKQsr.js → agent-import-generation-upc0yw-M.js} +1 -1
  31. package/dist/client/assets/{agentsOrgChartLayout-C2K_M3x3.js → agentsOrgChartLayout-C3iumMrW.js} +1 -1
  32. package/dist/client/assets/{architectureDiagram-3BPJPVTR-BQy8UcRx.js → architectureDiagram-3BPJPVTR-D6jqc3fJ.js} +1 -1
  33. package/dist/client/assets/{blockDiagram-GPEHLZMM-CZG1bqFQ.js → blockDiagram-GPEHLZMM-DY3AKuPD.js} +1 -1
  34. package/dist/client/assets/{c4Diagram-AAUBKEIU-CZmO_kg3.js → c4Diagram-AAUBKEIU-CpD52V4g.js} +1 -1
  35. package/dist/client/assets/channel-CaxOu15c.js +1 -0
  36. package/dist/client/assets/{chunk-2J33WTMH-jsad6DTE.js → chunk-2J33WTMH-CPeIHyAX.js} +1 -1
  37. package/dist/client/assets/{chunk-4BX2VUAB-DX7SuvwP.js → chunk-4BX2VUAB-ivAwI4xM.js} +1 -1
  38. package/dist/client/assets/{chunk-55IACEB6-De20xFgU.js → chunk-55IACEB6-BtVQ5XaZ.js} +1 -1
  39. package/dist/client/assets/{chunk-727SXJPM-CNiri9yW.js → chunk-727SXJPM-1eap1vDU.js} +1 -1
  40. package/dist/client/assets/{chunk-AQP2D5EJ-DvDqG-ax.js → chunk-AQP2D5EJ-B2NB3BW9.js} +1 -1
  41. package/dist/client/assets/{chunk-FMBD7UC4-DkMdKaUq.js → chunk-FMBD7UC4-Hk_smNYv.js} +1 -1
  42. package/dist/client/assets/{chunk-ND2GUHAM-Do5BwIrI.js → chunk-ND2GUHAM-BmGCAojk.js} +1 -1
  43. package/dist/client/assets/{chunk-QZHKN3VN-BnJgt9vl.js → chunk-QZHKN3VN-D0aXZ8CV.js} +1 -1
  44. package/dist/client/assets/classDiagram-4FO5ZUOK-DXIkGbsl.js +1 -0
  45. package/dist/client/assets/classDiagram-v2-Q7XG4LA2-DXIkGbsl.js +1 -0
  46. package/dist/client/assets/{cose-bilkent-S5V4N54A-D-ivAzzF.js → cose-bilkent-S5V4N54A-DAbu_gnF.js} +1 -1
  47. package/dist/client/assets/{dagre-BM42HDAG-Bpd9L0or.js → dagre-BM42HDAG-BdmLlrDJ.js} +1 -1
  48. package/dist/client/assets/{dashboard-view-DSvVO6Vr.js → dashboard-view-BoFBSXUn.js} +1 -1
  49. package/dist/client/assets/{dashboard-view-CgBo8Ctn.js → dashboard-view-CULL1yhL.js} +1 -1
  50. package/dist/client/assets/{dashboard-view-C-XU9CVv.js → dashboard-view-CxXMDfNY.js} +1 -1
  51. package/dist/client/assets/{dashboard-view-DbaRE8Ma.js → dashboard-view-PRCWCSLm.js} +1 -1
  52. package/dist/client/assets/{diagram-2AECGRRQ-B6TT1NWU.js → diagram-2AECGRRQ-PpqLbVUA.js} +1 -1
  53. package/dist/client/assets/{diagram-5GNKFQAL-DpRS2yRw.js → diagram-5GNKFQAL-9rkGmTwh.js} +1 -1
  54. package/dist/client/assets/{diagram-KO2AKTUF-BVbZr02C.js → diagram-KO2AKTUF-BT-efOMo.js} +1 -1
  55. package/dist/client/assets/{diagram-LMA3HP47-DzENbfal.js → diagram-LMA3HP47-w79OWFxg.js} +1 -1
  56. package/dist/client/assets/{diagram-OG6HWLK6-BIePG5SY.js → diagram-OG6HWLK6-Bye9I5IO.js} +1 -1
  57. package/dist/client/assets/{erDiagram-TEJ5UH35-CQo3WBwo.js → erDiagram-TEJ5UH35-aodREgDf.js} +1 -1
  58. package/dist/client/assets/{flowDiagram-I6XJVG4X-Ct2H4jYo.js → flowDiagram-I6XJVG4X-D0DKItY3.js} +1 -1
  59. package/dist/client/assets/{folder-open-DAh8mpTX.js → folder-open-CqvaMJvx.js} +1 -1
  60. package/dist/client/assets/{ganttDiagram-6RSMTGT7-DyOLCG4B.js → ganttDiagram-6RSMTGT7-CZVApkvw.js} +1 -1
  61. package/dist/client/assets/{gitGraphDiagram-PVQCEYII-sC28-su3.js → gitGraphDiagram-PVQCEYII-D_ynwJ4p.js} +1 -1
  62. package/dist/client/assets/index-DWRJyaa3.js +2818 -0
  63. package/dist/client/assets/{infoDiagram-5YYISTIA-Q81_5aBZ.js → infoDiagram-5YYISTIA-pJG6zxjk.js} +1 -1
  64. package/dist/client/assets/{ishikawaDiagram-YF4QCWOH-Cwkjs0z5.js → ishikawaDiagram-YF4QCWOH-nFZ5laUo.js} +1 -1
  65. package/dist/client/assets/{journeyDiagram-JHISSGLW-BXcBV1Bc.js → journeyDiagram-JHISSGLW-CWpCaAIe.js} +1 -1
  66. package/dist/client/assets/{kanban-definition-UN3LZRKU-BI7hW892.js → kanban-definition-UN3LZRKU-ATkPspKa.js} +1 -1
  67. package/dist/client/assets/{mermaid.core-B8oDA6jj.js → mermaid.core-CDXPNs7a.js} +4 -4
  68. package/dist/client/assets/{mindmap-definition-RKZ34NQL-COG6_9eD.js → mindmap-definition-RKZ34NQL-BkqS9tpe.js} +1 -1
  69. package/dist/client/assets/{pieDiagram-4H26LBE5-D11brZ_N.js → pieDiagram-4H26LBE5-DEUyVLs-.js} +1 -1
  70. package/dist/client/assets/{puzzle-D3_Z_rlW.js → puzzle-DQ0y1-XK.js} +1 -1
  71. package/dist/client/assets/{quadrantDiagram-W4KKPZXB-jmhDVZcv.js → quadrantDiagram-W4KKPZXB-ESBJNK5c.js} +1 -1
  72. package/dist/client/assets/{requirementDiagram-4Y6WPE33-BKCUWI1E.js → requirementDiagram-4Y6WPE33-CqPs7zcv.js} +1 -1
  73. package/dist/client/assets/{sankeyDiagram-5OEKKPKP-HsZdEl2t.js → sankeyDiagram-5OEKKPKP-CkFN0m14.js} +1 -1
  74. package/dist/client/assets/{sequenceDiagram-3UESZ5HK-CsDf7Fup.js → sequenceDiagram-3UESZ5HK-Dx2nDuMO.js} +1 -1
  75. package/dist/client/assets/{shield-alert-C16k8wNu.js → shield-alert-BS05s4RM.js} +1 -1
  76. package/dist/client/assets/{standing-instructions-template-BqAyftqe.js → standing-instructions-template-xprxYNHm.js} +1 -1
  77. package/dist/client/assets/{stateDiagram-AJRCARHV-fvzWhltB.js → stateDiagram-AJRCARHV-EUPmRFGd.js} +1 -1
  78. package/dist/client/assets/{stateDiagram-v2-BHNVJYJU-cnt42Sr_.js → stateDiagram-v2-BHNVJYJU-DcQ2mhi5.js} +1 -1
  79. package/dist/client/assets/{timeline-definition-PNZ67QCA-DsZFCSMb.js → timeline-definition-PNZ67QCA-D4YO_3V-.js} +1 -1
  80. package/dist/client/assets/{upload-_s5sL5Pq.js → upload-BjyBtxo7.js} +1 -1
  81. package/dist/client/assets/{users-DH1U5ISc.js → users-D5ogZ7WQ.js} +1 -1
  82. package/dist/client/assets/{vennDiagram-CIIHVFJN-B3KDWS-e.js → vennDiagram-CIIHVFJN-BT5_XuQL.js} +1 -1
  83. package/dist/client/assets/{wardley-L42UT6IY-BKs5MtQS.js → wardley-L42UT6IY-X_ZMW457.js} +1 -1
  84. package/dist/client/assets/{wardleyDiagram-YWT4CUSO-CNsEoXVB.js → wardleyDiagram-YWT4CUSO-GK9nONHU.js} +1 -1
  85. package/dist/client/assets/{xychartDiagram-2RQKCTM6-kq_gW4QC.js → xychartDiagram-2RQKCTM6-Dw3zXHAq.js} +1 -1
  86. package/dist/client/index.html +1 -1
  87. package/dist/client/version.json +1 -1
  88. package/dist/droid-cli/package.json +1 -1
  89. package/dist/extension.js +647 -207
  90. package/dist/migrations/0057_fn_9004_project_ownership_default_reconciliation.sql +13 -0
  91. package/dist/migrations/0058_fn_9014_message_archive.sql +13 -0
  92. package/dist/pi-claude-cli/package.json +5 -5
  93. package/dist/plugin-sdk/index.js +69 -23
  94. package/dist/plugins/fusion-plugin-acp-runtime/bundled.js +69 -23
  95. package/dist/plugins/fusion-plugin-acp-runtime/package.json +1 -1
  96. package/dist/plugins/fusion-plugin-claude-runtime/bundled.js +69 -23
  97. package/dist/plugins/fusion-plugin-claude-runtime/package.json +1 -1
  98. package/dist/plugins/fusion-plugin-cli-printing-press/bundled.js +69 -23
  99. package/dist/plugins/fusion-plugin-cli-printing-press/package.json +1 -1
  100. package/dist/plugins/fusion-plugin-compound-engineering/bundled.js +69 -23
  101. package/dist/plugins/fusion-plugin-compound-engineering/package.json +1 -1
  102. package/dist/plugins/fusion-plugin-cursor-runtime/bundled.js +69 -23
  103. package/dist/plugins/fusion-plugin-cursor-runtime/package.json +1 -1
  104. package/dist/plugins/fusion-plugin-dependency-graph/bundled.js +69 -23
  105. package/dist/plugins/fusion-plugin-dependency-graph/package.json +1 -1
  106. package/dist/plugins/fusion-plugin-droid-runtime/bundled.js +71 -25
  107. package/dist/plugins/fusion-plugin-droid-runtime/package.json +1 -1
  108. package/dist/plugins/fusion-plugin-grok-runtime/bundled.js +69 -23
  109. package/dist/plugins/fusion-plugin-grok-runtime/package.json +1 -1
  110. package/dist/plugins/fusion-plugin-hermes-runtime/bundled.js +69 -23
  111. package/dist/plugins/fusion-plugin-hermes-runtime/package.json +1 -1
  112. package/dist/plugins/fusion-plugin-linear-import/bundled.js +69 -23
  113. package/dist/plugins/fusion-plugin-linear-import/package.json +1 -1
  114. package/dist/plugins/fusion-plugin-omp-runtime/bundled.js +69 -23
  115. package/dist/plugins/fusion-plugin-omp-runtime/package.json +1 -1
  116. package/dist/plugins/fusion-plugin-openclaw-runtime/bundled.js +69 -23
  117. package/dist/plugins/fusion-plugin-openclaw-runtime/package.json +1 -1
  118. package/dist/plugins/fusion-plugin-paperclip-runtime/bundled.js +69 -23
  119. package/dist/plugins/fusion-plugin-paperclip-runtime/package.json +1 -1
  120. package/dist/plugins/fusion-plugin-quality/bundled.js +69 -23
  121. package/dist/plugins/fusion-plugin-quality/package.json +1 -1
  122. package/dist/plugins/fusion-plugin-reports/bundled.js +69 -23
  123. package/dist/plugins/fusion-plugin-reports/package.json +1 -1
  124. package/dist/plugins/fusion-plugin-roadmap/bundled.js +69 -23
  125. package/dist/plugins/fusion-plugin-roadmap/package.json +1 -1
  126. package/dist/plugins/fusion-plugin-todos/bundled.js +69 -23
  127. package/dist/plugins/fusion-plugin-todos/package.json +1 -1
  128. package/dist/plugins/fusion-plugin-whatsapp-chat/bundled.js +69 -23
  129. package/dist/plugins/fusion-plugin-whatsapp-chat/package.json +1 -1
  130. package/package.json +3 -3
  131. package/skill/fusion/SKILL.md +1 -1
  132. package/skill/fusion/references/extension-tools.md +22 -0
  133. package/skill/fusion/references/fusion-capabilities.md +2 -0
  134. package/dist/client/assets/ChatView-DcM-ARpZ.js +0 -13
  135. package/dist/client/assets/channel-Cwl9FefC.js +0 -1
  136. package/dist/client/assets/classDiagram-4FO5ZUOK-BZtWCoHC.js +0 -1
  137. package/dist/client/assets/classDiagram-v2-Q7XG4LA2-BZtWCoHC.js +0 -1
  138. package/dist/client/assets/index-BlGpMJSZ.js +0 -2818
package/dist/extension.js CHANGED
@@ -21639,9 +21639,14 @@ var init_project = __esm({
21639
21639
  // now keyed per-project on `project_id` (the effective PK). `id` is retained
21640
21640
  // for column-shape parity (always 1) but is no longer the PK and no longer
21641
21641
  // CHECK-constrained. Single-project / SQLite-parity callers leave project_id
21642
- // at its '' default (one row), preserving the pre-isolation behavior.
21642
+ // through the database ownership trigger, preserving the pre-isolation behavior.
21643
+ /*
21644
+ FNXC:MultiProjectIsolation 2026-08-12-15:43:
21645
+ Migration 0006 owns config's project_id default and leaves its catalog PK as (project_id).
21646
+ Drizzle emits DEFAULT while the database GUC/trigger selects the effective ownership partition.
21647
+ */
21643
21648
  id: integer("id").default(1),
21644
- projectId: text("project_id").notNull().default("").primaryKey(),
21649
+ projectId: text("project_id").notNull().default(sql`current_setting('fusion.project_id', true)`).primaryKey(),
21645
21650
  nextId: integer("next_id").default(1),
21646
21651
  nextWorkflowStepId: integer("next_workflow_step_id").default(1),
21647
21652
  // FNXC:SqliteFinalRemoval 2026-06-28:
@@ -22035,9 +22040,13 @@ var init_project = __esm({
22035
22040
  automations = projectSchema.table("automations", {
22036
22041
  /*
22037
22042
  * FNXC:AutomationIsolation 2026-07-13-22:37:
22038
- * Automations are partitioned by the AsyncDataLayer's project ID because embedded PostgreSQL consolidates the per-project SQLite files into one table. The composite key deliberately permits the same automation ID in two projects without allowing either project's CRUD or cron-claim path to address the other row. The empty default preserves an explicit partition for legacy and project-agnostic callers until startup stamps migrated rows.
22043
+ * Automations are partitioned by the AsyncDataLayer's project ID because embedded PostgreSQL consolidates the per-project SQLite files into one table. The composite key deliberately permits the same automation ID in two projects without allowing either project's CRUD or cron-claim path to address the other row.
22044
+ *
22045
+ * FNXC:MultiProjectIsolation 2026-08-12-15:43:
22046
+ * Migration 0006 owns the default through the database GUC/trigger; Drizzle emits DEFAULT
22047
+ * without replacing the physical legacy fallback or the fail-closed bound writer contract.
22039
22048
  */
22040
- projectId: text("project_id").notNull().default(""),
22049
+ projectId: text("project_id").notNull().default(sql`current_setting('fusion.project_id', true)`),
22041
22050
  id: text("id").notNull(),
22042
22051
  name: text("name").notNull(),
22043
22052
  description: text("description"),
@@ -22336,7 +22345,8 @@ var init_project = __esm({
22336
22345
  index("idxTaskDocumentsTaskId").on(t.taskId)
22337
22346
  ]);
22338
22347
  artifacts = projectSchema.table("artifacts", {
22339
- id: text("id").primaryKey(),
22348
+ projectId: text("project_id").notNull().default(sql`current_setting('fusion.project_id', true)`),
22349
+ id: text("id").notNull(),
22340
22350
  type: text("type").notNull(),
22341
22351
  title: text("title").notNull(),
22342
22352
  description: text("description"),
@@ -22351,7 +22361,8 @@ var init_project = __esm({
22351
22361
  createdAt: text("created_at").notNull(),
22352
22362
  updatedAt: text("updated_at").notNull()
22353
22363
  }, (t) => [
22354
- foreignKey({ columns: [t.taskId], foreignColumns: [tasks.id] }).onDelete("cascade"),
22364
+ primaryKey({ columns: [t.projectId, t.id] }),
22365
+ foreignKey({ name: "artifacts_task_id_fkey", columns: [t.projectId, t.taskId], foreignColumns: [tasks.projectId, tasks.id] }).onDelete("cascade"),
22355
22366
  index("idxArtifactsTaskId").on(t.taskId),
22356
22367
  index("idxArtifactsAuthorId").on(t.authorId),
22357
22368
  index("idxArtifactsType").on(t.type),
@@ -22541,7 +22552,8 @@ var init_project = __esm({
22541
22552
  index("idxEvalRunEventsRunIdSeq").on(t.runId, t.seq)
22542
22553
  ]);
22543
22554
  secrets = projectSchema.table("secrets", {
22544
- id: text("id").primaryKey(),
22555
+ projectId: text("project_id").notNull().default(sql`current_setting('fusion.project_id', true)`),
22556
+ id: text("id").notNull(),
22545
22557
  key: text("key").notNull(),
22546
22558
  valueCiphertext: bytea("value_ciphertext").notNull(),
22547
22559
  nonce: bytea("nonce").notNull(),
@@ -22554,7 +22566,8 @@ var init_project = __esm({
22554
22566
  lastReadAt: text("last_read_at"),
22555
22567
  lastReadBy: text("last_read_by")
22556
22568
  }, (t) => [
22557
- unique("secrets_key_unique").on(t.key),
22569
+ primaryKey({ columns: [t.projectId, t.id] }),
22570
+ unique("secrets_key_unique").on(t.projectId, t.key),
22558
22571
  check("secrets_access_policy_check", sql`${t.accessPolicy} IN ('auto', 'prompt', 'deny')`),
22559
22572
  check("secrets_env_exportable_check", sql`${t.envExportable} IN (0, 1)`)
22560
22573
  ]);
@@ -22596,10 +22609,11 @@ var init_project = __esm({
22596
22609
  updatedAt: text("updated_at").notNull()
22597
22610
  }, (t) => [primaryKey({ columns: [t.projectId, t.id] })]);
22598
22611
  branchGroups = projectSchema.table("branch_groups", {
22599
- id: text("id").primaryKey(),
22612
+ projectId: text("project_id").notNull().default(sql`current_setting('fusion.project_id', true)`),
22613
+ id: text("id").notNull(),
22600
22614
  sourceType: text("source_type").notNull(),
22601
22615
  sourceId: text("source_id").notNull(),
22602
- branchName: text("branch_name").notNull().unique(),
22616
+ branchName: text("branch_name").notNull(),
22603
22617
  worktreePath: text("worktree_path"),
22604
22618
  autoMerge: integer("auto_merge").notNull().default(0),
22605
22619
  prState: text("pr_state").notNull().default("none"),
@@ -22615,6 +22629,8 @@ var init_project = __esm({
22615
22629
  updatedAt: bigint("updated_at", { mode: "number" }).notNull(),
22616
22630
  closedAt: bigint("closed_at", { mode: "number" })
22617
22631
  }, (t) => [
22632
+ primaryKey({ columns: [t.projectId, t.id] }),
22633
+ unique("branch_groups_branch_name_key").on(t.projectId, t.branchName),
22618
22634
  check("branch_groups_source_type_check", sql`${t.sourceType} IN ('mission','planning','new-task')`),
22619
22635
  check("branch_groups_pr_state_check", sql`${t.prState} IN ('none','open','merged','closed')`),
22620
22636
  check("branch_groups_status_check", sql`${t.status} IN ('open','finalized','abandoned')`),
@@ -23016,12 +23032,14 @@ var init_project = __esm({
23016
23032
  index("idxUsageEventsKindTs").on(t.kind, t.ts)
23017
23033
  ]);
23018
23034
  pluginActivations = projectSchema.table("plugin_activations", {
23019
- id: integer("id").generatedAlwaysAsIdentity().primaryKey(),
23035
+ projectId: text("project_id").notNull().default(sql`current_setting('fusion.project_id', true)`),
23036
+ id: integer("id").generatedAlwaysAsIdentity().notNull(),
23020
23037
  pluginId: text("plugin_id").notNull(),
23021
23038
  source: text("source").notNull(),
23022
23039
  pluginVersion: text("plugin_version"),
23023
23040
  activatedAt: text("activated_at").notNull()
23024
23041
  }, (t) => [
23042
+ primaryKey({ columns: [t.projectId, t.id] }),
23025
23043
  index("idxPluginActivationsActivatedAt").on(t.activatedAt),
23026
23044
  index("idxPluginActivationsPluginId").on(t.pluginId)
23027
23045
  ]);
@@ -23046,8 +23064,13 @@ var init_project = __esm({
23046
23064
  index("idxKnowledgePagesUpdatedAt").on(t.updatedAt)
23047
23065
  ]);
23048
23066
  deployments = projectSchema.table("deployments", {
23049
- id: integer("id").generatedAlwaysAsIdentity().primaryKey(),
23050
- projectId: text("project_id").notNull().default(""),
23067
+ id: integer("id").generatedAlwaysAsIdentity().notNull(),
23068
+ /*
23069
+ FNXC:MultiProjectIsolation 2026-08-12-15:43:
23070
+ Migration 0006 rebuilt deployments_pkey as (project_id, id). Drizzle emits DEFAULT while the
23071
+ database GUC/trigger keeps ownership stamping and the physical legacy fallback authoritative.
23072
+ */
23073
+ projectId: text("project_id").notNull().default(sql`current_setting('fusion.project_id', true)`),
23051
23074
  deploymentId: text("deployment_id").notNull(),
23052
23075
  service: text("service"),
23053
23076
  environment: text("environment"),
@@ -23058,6 +23081,7 @@ var init_project = __esm({
23058
23081
  meta: jsonb("meta"),
23059
23082
  createdAt: text("created_at").notNull()
23060
23083
  }, (t) => [
23084
+ primaryKey({ columns: [t.projectId, t.id], name: "deployments_pkey" }),
23061
23085
  uniqueIndex("idxDeploymentsProjectDeploymentId").on(t.projectId, t.deploymentId),
23062
23086
  index("idxDeploymentsProjectDeployedAt").on(t.projectId, t.deployedAt),
23063
23087
  index("idxDeploymentsDeployedAt").on(t.deployedAt),
@@ -23065,7 +23089,12 @@ var init_project = __esm({
23065
23089
  ]);
23066
23090
  githubCheckStates = projectSchema.table("github_check_states", {
23067
23091
  id: integer("id").generatedAlwaysAsIdentity().notNull(),
23068
- projectId: text("project_id").notNull().default(""),
23092
+ /*
23093
+ FNXC:MultiProjectIsolation 2026-08-12-15:43:
23094
+ Migration 0048 post-dated 0006, so FN-9004 reconciles its physical default to the ownership
23095
+ expression. Drizzle emits DEFAULT while the database GUC/trigger remains the stamping authority.
23096
+ */
23097
+ projectId: text("project_id").notNull().default(sql`current_setting('fusion.project_id', true)`),
23069
23098
  repo: text("repo").notNull(),
23070
23099
  headSha: text("head_sha").notNull(),
23071
23100
  checkName: text("check_name").notNull(),
@@ -23085,9 +23114,14 @@ var init_project = __esm({
23085
23114
  index("idxGithubCheckStatesProjectReceived").on(t.projectId, t.receivedAt)
23086
23115
  ]);
23087
23116
  incidents = projectSchema.table("incidents", {
23088
- id: integer("id").generatedAlwaysAsIdentity().primaryKey(),
23089
- projectId: text("project_id").notNull().default(""),
23090
- incidentId: text("incident_id").notNull().unique(),
23117
+ id: integer("id").generatedAlwaysAsIdentity().notNull(),
23118
+ /*
23119
+ FNXC:MultiProjectIsolation 2026-08-12-15:43:
23120
+ Migration 0006 rebuilt incident keys with project_id first. Drizzle emits DEFAULT while the
23121
+ database GUC/trigger retains ownership stamping and its physical legacy fallback.
23122
+ */
23123
+ projectId: text("project_id").notNull().default(sql`current_setting('fusion.project_id', true)`),
23124
+ incidentId: text("incident_id").notNull(),
23091
23125
  groupingKey: text("grouping_key").notNull(),
23092
23126
  title: text("title").notNull(),
23093
23127
  severity: text("severity"),
@@ -23101,6 +23135,8 @@ var init_project = __esm({
23101
23135
  createdAt: text("created_at").notNull(),
23102
23136
  updatedAt: text("updated_at").notNull()
23103
23137
  }, (t) => [
23138
+ primaryKey({ columns: [t.projectId, t.id], name: "incidents_pkey" }),
23139
+ unique("incidents_incident_id_key").on(t.projectId, t.incidentId),
23104
23140
  index("idxIncidentsProjectOpenedAt").on(t.projectId, t.openedAt),
23105
23141
  index("idxIncidentsProjectStatus").on(t.projectId, t.status),
23106
23142
  index("idxIncidentsGroupingKey").on(t.groupingKey),
@@ -23155,12 +23191,14 @@ var init_project = __esm({
23155
23191
  content: text("content").notNull(),
23156
23192
  type: text("type").notNull(),
23157
23193
  read: integer("read").default(0),
23194
+ archived: integer("archived").default(0),
23158
23195
  metadata: jsonb("metadata"),
23159
23196
  createdAt: text("created_at").notNull(),
23160
23197
  updatedAt: text("updated_at").notNull()
23161
23198
  }, (t) => [
23162
23199
  primaryKey({ columns: [t.projectId, t.id] }),
23163
23200
  index("idxMessagesTo").on(t.toId, t.toType, t.read),
23201
+ index("idxMessagesToArchived").on(t.toId, t.toType, t.archived),
23164
23202
  index("idxMessagesFrom").on(t.fromId, t.fromType),
23165
23203
  index("idxMessagesCreatedAt").on(t.createdAt)
23166
23204
  ]);
@@ -23261,7 +23299,8 @@ var init_project = __esm({
23261
23299
  index("idx_cli_sessions_project_state").on(t.projectId, t.agentState)
23262
23300
  ]);
23263
23301
  chatMessages = projectSchema.table("chat_messages", {
23264
- id: text("id").primaryKey(),
23302
+ projectId: text("project_id").notNull().default(sql`current_setting('fusion.project_id', true)`),
23303
+ id: text("id").notNull(),
23265
23304
  sessionId: text("session_id").notNull(),
23266
23305
  role: text("role").notNull(),
23267
23306
  content: text("content").notNull(),
@@ -23270,6 +23309,7 @@ var init_project = __esm({
23270
23309
  createdAt: text("created_at").notNull(),
23271
23310
  attachments: jsonb("attachments")
23272
23311
  }, (t) => [
23312
+ primaryKey({ columns: [t.projectId, t.id] }),
23273
23313
  index("idxChatMessagesSessionId").on(t.sessionId),
23274
23314
  index("idxChatMessagesCreatedAt").on(t.createdAt)
23275
23315
  ]);
@@ -23295,7 +23335,8 @@ var init_project = __esm({
23295
23335
  index("idxChatTokenUsageCreatedAt").on(t.createdAt)
23296
23336
  ]);
23297
23337
  runAuditEvents = projectSchema.table("run_audit_events", {
23298
- id: text("id").primaryKey(),
23338
+ projectId: text("project_id").notNull().default(sql`current_setting('fusion.project_id', true)`),
23339
+ id: text("id").notNull(),
23299
23340
  timestamp: text("timestamp").notNull(),
23300
23341
  taskId: text("task_id"),
23301
23342
  agentId: text("agent_id").notNull(),
@@ -23305,6 +23346,7 @@ var init_project = __esm({
23305
23346
  target: text("target").notNull(),
23306
23347
  metadata: jsonb("metadata")
23307
23348
  }, (t) => [
23349
+ primaryKey({ columns: [t.projectId, t.id] }),
23308
23350
  index("idxRunAuditEventsRunIdTimestamp").on(t.runId, t.timestamp),
23309
23351
  index("idxRunAuditEventsTaskIdTimestamp").on(t.taskId, t.timestamp),
23310
23352
  index("idxRunAuditEventsTimestamp").on(t.timestamp)
@@ -23405,13 +23447,14 @@ var init_project = __esm({
23405
23447
  index("idxMissionLineageStopsMissionId").on(t.projectId, t.missionId)
23406
23448
  ]);
23407
23449
  verificationCache = projectSchema.table("verification_cache", {
23450
+ projectId: text("project_id").notNull().default(sql`current_setting('fusion.project_id', true)`),
23408
23451
  treeSha: text("tree_sha").notNull(),
23409
23452
  testCommand: text("test_command").notNull().default(""),
23410
23453
  buildCommand: text("build_command").notNull().default(""),
23411
23454
  recordedAt: text("recorded_at").notNull(),
23412
23455
  taskId: text("task_id")
23413
23456
  }, (t) => [
23414
- primaryKey({ columns: [t.treeSha, t.testCommand, t.buildCommand] }),
23457
+ primaryKey({ columns: [t.projectId, t.treeSha, t.testCommand, t.buildCommand] }),
23415
23458
  index("idxVerificationCacheRecordedAt").on(t.recordedAt)
23416
23459
  ]);
23417
23460
  importTranslationCache = projectSchema.table("import_translation_cache", {
@@ -23444,7 +23487,8 @@ var init_project = __esm({
23444
23487
  index("idxImportTranslationCacheRecordedAt").on(t.recordedAt)
23445
23488
  ]);
23446
23489
  approvalRequests = projectSchema.table("approval_requests", {
23447
- id: text("id").primaryKey(),
23490
+ projectId: text("project_id").notNull().default(sql`current_setting('fusion.project_id', true)`),
23491
+ id: text("id").notNull(),
23448
23492
  status: text("status").notNull(),
23449
23493
  requesterActorId: text("requester_actor_id").notNull(),
23450
23494
  requesterActorType: text("requester_actor_type").notNull(),
@@ -23463,13 +23507,14 @@ var init_project = __esm({
23463
23507
  createdAt: text("created_at").notNull(),
23464
23508
  updatedAt: text("updated_at").notNull()
23465
23509
  }, (t) => [
23510
+ primaryKey({ columns: [t.projectId, t.id] }),
23466
23511
  index("idxApprovalRequestsStatusCreatedAt").on(t.status, t.createdAt),
23467
23512
  index("idxApprovalRequestsRequesterCreatedAt").on(t.requesterActorId, t.createdAt),
23468
23513
  index("idxApprovalRequestsTaskCreatedAt").on(t.taskId, t.createdAt)
23469
23514
  ]);
23470
23515
  approvalRequestAuditEvents = projectSchema.table("approval_request_audit_events", {
23471
- projectId: text("project_id").notNull().default(""),
23472
- id: text("id").primaryKey(),
23516
+ projectId: text("project_id").notNull().default(sql`current_setting('fusion.project_id', true)`),
23517
+ id: text("id").notNull(),
23473
23518
  requestId: text("request_id").notNull(),
23474
23519
  eventType: text("event_type").notNull(),
23475
23520
  actorId: text("actor_id").notNull(),
@@ -23478,6 +23523,7 @@ var init_project = __esm({
23478
23523
  note: text("note"),
23479
23524
  createdAt: text("created_at").notNull()
23480
23525
  }, (t) => [
23526
+ primaryKey({ columns: [t.projectId, t.id] }),
23481
23527
  index("idxApprovalRequestAuditRequestCreatedAt").on(t.requestId, t.createdAt, t.id),
23482
23528
  index("idxApprovalRequestAuditProjectCreatedAt").on(t.projectId, t.createdAt)
23483
23529
  ]);
@@ -26967,6 +27013,27 @@ var init_grok_provider = __esm({
26967
27013
  apiKey: "$GROK_API_KEY",
26968
27014
  api: "openai-completions",
26969
27015
  models: [
27016
+ /*
27017
+ FNXC:ModelRegistry 2026-08-12-20:17:
27018
+ FN-9008 requires Grok 4.6 to be selectable in every model area. Keep it in this shared
27019
+ catalog because pi's registerProvider() replaces provider model lists wholesale, while every
27020
+ Fusion host seeds and re-merges this export. xAI's model docs verify grok-4.6, its 500k-token
27021
+ context window, and configurable reasoning; max output and per-model image input remain
27022
+ upstream-pending-verification, so retain the conservative text-only and 65536-token defaults.
27023
+ Source: https://docs.x.ai/developers/models
27024
+ */
27025
+ {
27026
+ id: "grok-4.6",
27027
+ name: "Grok 4.6",
27028
+ reasoning: true,
27029
+ input: ["text"],
27030
+ cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
27031
+ contextWindow: 5e5,
27032
+ maxTokens: 65536,
27033
+ compat: {
27034
+ supportsDeveloperRole: false
27035
+ }
27036
+ },
26970
27037
  {
26971
27038
  id: "grok-4.5",
26972
27039
  name: "Grok 4.5",
@@ -34925,6 +34992,7 @@ function rowToMessage(row) {
34925
34992
  content: row.content,
34926
34993
  type: row.type,
34927
34994
  read: (row.read ?? 0) === 1,
34995
+ archived: (row.archived ?? 0) === 1,
34928
34996
  metadata: row.metadata ?? void 0,
34929
34997
  createdAt: row.createdAt,
34930
34998
  updatedAt: row.updatedAt
@@ -34936,6 +35004,11 @@ function participantIdsForLookup(ownerId, ownerType) {
34936
35004
  }
34937
35005
  return [ownerId];
34938
35006
  }
35007
+ function archivedCondition(archived) {
35008
+ if (archived === true) return eq(project_exports.messages.archived, 1);
35009
+ if (archived === false) return or(eq(project_exports.messages.archived, 0), sql`${project_exports.messages.archived} IS NULL`);
35010
+ return or(eq(project_exports.messages.archived, 0), sql`${project_exports.messages.archived} IS NULL`);
35011
+ }
34939
35012
  async function sendMessage(handle, message) {
34940
35013
  const sanitizedContent = sanitizeTextValue(message.content);
34941
35014
  const sanitizedMetadata = sanitizeJsonbValue(message.metadata);
@@ -34948,6 +35021,7 @@ async function sendMessage(handle, message) {
34948
35021
  content: sanitizedContent,
34949
35022
  type: message.type,
34950
35023
  read: message.read ? 1 : 0,
35024
+ archived: message.archived ? 1 : 0,
34951
35025
  metadata: sanitizedMetadata,
34952
35026
  createdAt: message.createdAt,
34953
35027
  updatedAt: message.updatedAt
@@ -34956,7 +35030,8 @@ async function sendMessage(handle, message) {
34956
35030
  ...message,
34957
35031
  content: sanitizedContent,
34958
35032
  metadata: sanitizedMetadata,
34959
- read: message.read ? 1 : 0
35033
+ read: message.read ? 1 : 0,
35034
+ archived: message.archived ? 1 : 0
34960
35035
  });
34961
35036
  }
34962
35037
  async function sendMessageOnce(handle, message) {
@@ -34969,6 +35044,7 @@ async function sendMessageOnce(handle, message) {
34969
35044
  content: message.content,
34970
35045
  type: message.type,
34971
35046
  read: message.read ? 1 : 0,
35047
+ archived: message.archived ? 1 : 0,
34972
35048
  metadata: message.metadata,
34973
35049
  createdAt: message.createdAt,
34974
35050
  updatedAt: message.updatedAt
@@ -35020,6 +35096,7 @@ async function queryMessagesByParticipant(handle, direction, ownerId, ownerType,
35020
35096
  if (filter?.read !== void 0) {
35021
35097
  conditions.push(eq(project_exports.messages.read, filter.read ? 1 : 0));
35022
35098
  }
35099
+ conditions.push(archivedCondition(filter?.archived));
35023
35100
  const limit = filter?.limit ?? 100;
35024
35101
  const offset = filter?.offset ?? 0;
35025
35102
  const rows = await handle.select(messageColumns).from(project_exports.messages).where(and(...conditions)).orderBy(desc(project_exports.messages.createdAt), desc(project_exports.messages.id)).limit(limit).offset(offset);
@@ -35033,6 +35110,13 @@ async function markMessageAsRead(handle, messageId) {
35033
35110
  await handle.update(project_exports.messages).set({ read: 1, updatedAt: now }).where(eq(project_exports.messages.id, messageId));
35034
35111
  return await getMessage(handle, messageId);
35035
35112
  }
35113
+ async function setMessageArchived(handle, id, archived) {
35114
+ const existing = await getMessage(handle, id);
35115
+ if (!existing) return null;
35116
+ if (existing.archived === archived) return existing;
35117
+ const rows = await handle.update(project_exports.messages).set({ archived: archived ? 1 : 0, updatedAt: (/* @__PURE__ */ new Date()).toISOString() }).where(eq(project_exports.messages.id, id)).returning(messageColumns);
35118
+ return rows[0] ? rowToMessage(rows[0]) : null;
35119
+ }
35036
35120
  async function markAllMessagesAsRead(handle, ownerId, ownerType) {
35037
35121
  const now = (/* @__PURE__ */ new Date()).toISOString();
35038
35122
  const participantIds = participantIdsForLookup(ownerId, ownerType);
@@ -35040,7 +35124,8 @@ async function markAllMessagesAsRead(handle, ownerId, ownerType) {
35040
35124
  and(
35041
35125
  inArray(project_exports.messages.toId, participantIds),
35042
35126
  eq(project_exports.messages.toType, ownerType),
35043
- eq(project_exports.messages.read, 0)
35127
+ eq(project_exports.messages.read, 0),
35128
+ archivedCondition()
35044
35129
  )
35045
35130
  );
35046
35131
  const count2 = countRows[0]?.count ?? 0;
@@ -35048,7 +35133,8 @@ async function markAllMessagesAsRead(handle, ownerId, ownerType) {
35048
35133
  and(
35049
35134
  inArray(project_exports.messages.toId, participantIds),
35050
35135
  eq(project_exports.messages.toType, ownerType),
35051
- eq(project_exports.messages.read, 0)
35136
+ eq(project_exports.messages.read, 0),
35137
+ archivedCondition()
35052
35138
  )
35053
35139
  );
35054
35140
  return count2;
@@ -35070,19 +35156,22 @@ async function getConversation(handle, participantA, participantB, options) {
35070
35156
  const aIds = participantIdsForLookup(participantA.id, participantA.type);
35071
35157
  const bIds = participantIdsForLookup(participantB.id, participantB.type);
35072
35158
  const rows = await handle.select(messageColumns).from(project_exports.messages).where(
35073
- or(
35074
- and(
35075
- inArray(project_exports.messages.fromId, aIds),
35076
- eq(project_exports.messages.fromType, participantA.type),
35077
- inArray(project_exports.messages.toId, bIds),
35078
- eq(project_exports.messages.toType, participantB.type)
35159
+ and(
35160
+ or(
35161
+ and(
35162
+ inArray(project_exports.messages.fromId, aIds),
35163
+ eq(project_exports.messages.fromType, participantA.type),
35164
+ inArray(project_exports.messages.toId, bIds),
35165
+ eq(project_exports.messages.toType, participantB.type)
35166
+ ),
35167
+ and(
35168
+ inArray(project_exports.messages.fromId, bIds),
35169
+ eq(project_exports.messages.fromType, participantB.type),
35170
+ inArray(project_exports.messages.toId, aIds),
35171
+ eq(project_exports.messages.toType, participantA.type)
35172
+ )
35079
35173
  ),
35080
- and(
35081
- inArray(project_exports.messages.fromId, bIds),
35082
- eq(project_exports.messages.fromType, participantB.type),
35083
- inArray(project_exports.messages.toId, aIds),
35084
- eq(project_exports.messages.toType, participantA.type)
35085
- )
35174
+ archivedCondition(options?.archived)
35086
35175
  )
35087
35176
  ).orderBy(desc(project_exports.messages.createdAt)).limit(limit);
35088
35177
  return rows.reverse().map((row) => rowToMessage(row));
@@ -35093,14 +35182,16 @@ async function getMailbox(handle, ownerId, ownerType) {
35093
35182
  and(
35094
35183
  inArray(project_exports.messages.toId, participantIds),
35095
35184
  eq(project_exports.messages.toType, ownerType),
35096
- eq(project_exports.messages.read, 0)
35185
+ eq(project_exports.messages.read, 0),
35186
+ archivedCondition()
35097
35187
  )
35098
35188
  );
35099
35189
  const unreadCount = unreadRows[0]?.count ?? 0;
35100
35190
  const lastRows = await handle.select(messageColumns).from(project_exports.messages).where(
35101
35191
  and(
35102
35192
  inArray(project_exports.messages.toId, participantIds),
35103
- eq(project_exports.messages.toType, ownerType)
35193
+ eq(project_exports.messages.toType, ownerType),
35194
+ archivedCondition()
35104
35195
  )
35105
35196
  ).orderBy(desc(project_exports.messages.createdAt), desc(project_exports.messages.id)).limit(1);
35106
35197
  return {
@@ -35110,15 +35201,16 @@ async function getMailbox(handle, ownerId, ownerType) {
35110
35201
  lastMessage: lastRows[0] ? rowToMessage(lastRows[0]) : void 0
35111
35202
  };
35112
35203
  }
35113
- async function getAllAgentToAgentMessages(handle) {
35114
- const rows = await handle.select(messageColumns).from(project_exports.messages).where(eq(project_exports.messages.type, "agent-to-agent")).orderBy(desc(project_exports.messages.createdAt), desc(project_exports.messages.id));
35204
+ async function getAllAgentToAgentMessages(handle, filter) {
35205
+ const rows = await handle.select(messageColumns).from(project_exports.messages).where(and(eq(project_exports.messages.type, "agent-to-agent"), archivedCondition(filter?.archived))).orderBy(desc(project_exports.messages.createdAt), desc(project_exports.messages.id));
35115
35206
  return rows.map((row) => rowToMessage(row));
35116
35207
  }
35117
35208
  async function getUnreadAgentToAgentCount(handle) {
35118
35209
  const rows = await handle.select({ count: sql`count(*)::int` }).from(project_exports.messages).where(
35119
35210
  and(
35120
35211
  eq(project_exports.messages.type, "agent-to-agent"),
35121
- eq(project_exports.messages.read, 0)
35212
+ eq(project_exports.messages.read, 0),
35213
+ archivedCondition()
35122
35214
  )
35123
35215
  );
35124
35216
  return rows[0]?.count ?? 0;
@@ -35140,6 +35232,7 @@ var init_async_message_store = __esm({
35140
35232
  content: project_exports.messages.content,
35141
35233
  type: project_exports.messages.type,
35142
35234
  read: project_exports.messages.read,
35235
+ archived: project_exports.messages.archived,
35143
35236
  metadata: project_exports.messages.metadata,
35144
35237
  createdAt: project_exports.messages.createdAt,
35145
35238
  updatedAt: project_exports.messages.updatedAt
@@ -35325,12 +35418,12 @@ var init_message_store = __esm({
35325
35418
  }
35326
35419
  const sqliteDb = this.db;
35327
35420
  this.stmtInsert = sqliteDb.prepare(`
35328
- INSERT INTO messages (id, fromId, fromType, toId, toType, content, type, read, metadata, createdAt, updatedAt)
35329
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
35421
+ INSERT INTO messages (id, fromId, fromType, toId, toType, content, type, read, archived, metadata, createdAt, updatedAt)
35422
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
35330
35423
  `);
35331
35424
  this.stmtInsertOnce = sqliteDb.prepare(`
35332
- INSERT OR IGNORE INTO messages (id, fromId, fromType, toId, toType, content, type, read, metadata, createdAt, updatedAt)
35333
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
35425
+ INSERT OR IGNORE INTO messages (id, fromId, fromType, toId, toType, content, type, read, archived, metadata, createdAt, updatedAt)
35426
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
35334
35427
  `);
35335
35428
  this.stmtGetById = sqliteDb.prepare(`
35336
35429
  SELECT * FROM messages WHERE id = ?
@@ -35368,6 +35461,7 @@ var init_message_store = __esm({
35368
35461
  content: row.content,
35369
35462
  type: row.type,
35370
35463
  read: row.read === 1,
35464
+ archived: (row.archived ?? 0) === 1,
35371
35465
  metadata: fromJson(row.metadata),
35372
35466
  createdAt: row.createdAt,
35373
35467
  updatedAt: row.updatedAt
@@ -35401,6 +35495,7 @@ var init_message_store = __esm({
35401
35495
  content: sanitizeTextValue(input.content),
35402
35496
  type: input.type,
35403
35497
  read: false,
35498
+ archived: false,
35404
35499
  metadata: sanitizeJsonbValue(input.metadata),
35405
35500
  createdAt: now,
35406
35501
  updatedAt: now
@@ -35416,6 +35511,7 @@ var init_message_store = __esm({
35416
35511
  content: message.content,
35417
35512
  type: message.type,
35418
35513
  read: message.read,
35514
+ archived: message.archived,
35419
35515
  metadata: message.metadata ?? null,
35420
35516
  createdAt: message.createdAt,
35421
35517
  updatedAt: message.updatedAt
@@ -35430,6 +35526,7 @@ var init_message_store = __esm({
35430
35526
  message.content,
35431
35527
  message.type,
35432
35528
  message.read ? 1 : 0,
35529
+ message.archived ? 1 : 0,
35433
35530
  toJsonNullable(message.metadata),
35434
35531
  message.createdAt,
35435
35532
  message.updatedAt
@@ -35488,6 +35585,7 @@ var init_message_store = __esm({
35488
35585
  content: sanitizeTextValue(input.content),
35489
35586
  type: input.type,
35490
35587
  read: false,
35588
+ archived: false,
35491
35589
  metadata: sanitizeJsonbValue(input.metadata),
35492
35590
  createdAt: now,
35493
35591
  updatedAt: now
@@ -35508,6 +35606,7 @@ var init_message_store = __esm({
35508
35606
  message.content,
35509
35607
  message.type,
35510
35608
  0,
35609
+ 0,
35511
35610
  toJsonNullable(message.metadata),
35512
35611
  message.createdAt,
35513
35612
  message.updatedAt
@@ -35639,6 +35738,7 @@ var init_message_store = __esm({
35639
35738
  whereClauses.push("read = ?");
35640
35739
  params.push(filter.read ? 1 : 0);
35641
35740
  }
35741
+ whereClauses.push(filter?.archived === true ? "archived = 1" : "(archived = 0 OR archived IS NULL)");
35642
35742
  const whereSql = whereClauses.join(" AND ");
35643
35743
  const limit = filter?.limit ?? 100;
35644
35744
  const offset = filter?.offset ?? 0;
@@ -35689,15 +35789,39 @@ var init_message_store = __esm({
35689
35789
  const participantIds = this.getParticipantIdsForLookup(ownerId, ownerType);
35690
35790
  const toIdPredicate = participantIds.length === 1 ? "toId = ?" : `toId IN (${participantIds.map(() => "?").join(", ")})`;
35691
35791
  const unreadRow = this.db.prepare(`
35692
- SELECT COUNT(*) as count FROM messages WHERE ${toIdPredicate} AND toType = ? AND read = 0
35792
+ SELECT COUNT(*) as count FROM messages WHERE ${toIdPredicate} AND toType = ? AND read = 0 AND (archived = 0 OR archived IS NULL)
35693
35793
  `).get(...participantIds, ownerType);
35694
35794
  const count2 = unreadRow?.count ?? 0;
35695
35795
  this.db.prepare(`
35696
- UPDATE messages SET read = 1, updatedAt = ? WHERE ${toIdPredicate} AND toType = ? AND read = 0
35796
+ UPDATE messages SET read = 1, updatedAt = ? WHERE ${toIdPredicate} AND toType = ? AND read = 0 AND (archived = 0 OR archived IS NULL)
35697
35797
  `).run(now, ...participantIds, ownerType);
35698
35798
  this.db.bumpLastModified();
35699
35799
  return count2;
35700
35800
  }
35801
+ /** Archive a message without destroying its correspondence history. */
35802
+ async archiveMessage(id) {
35803
+ return this.setMessageArchived(id, true);
35804
+ }
35805
+ /** Restore a previously archived message to default mailbox lists. */
35806
+ async unarchiveMessage(id) {
35807
+ return this.setMessageArchived(id, false);
35808
+ }
35809
+ async setMessageArchived(id, archived) {
35810
+ if (this.asyncLayer) {
35811
+ const updated2 = await setMessageArchived(this.asyncLayer.db, id, archived);
35812
+ if (!updated2) throw new Error(`Message ${id} not found`);
35813
+ this.emit(archived ? "message:archived" : "message:unarchived", updated2);
35814
+ return updated2;
35815
+ }
35816
+ const existing = await this.getMessage(id);
35817
+ if (!existing) throw new Error(`Message ${id} not found`);
35818
+ if (existing.archived === archived) return existing;
35819
+ this.db.prepare("UPDATE messages SET archived = ?, updatedAt = ? WHERE id = ?").run(archived ? 1 : 0, (/* @__PURE__ */ new Date()).toISOString(), id);
35820
+ this.db.bumpLastModified();
35821
+ const updated = await this.getMessage(id);
35822
+ this.emit(archived ? "message:archived" : "message:unarchived", updated);
35823
+ return updated;
35824
+ }
35701
35825
  /**
35702
35826
  * Delete a message by ID.
35703
35827
  * @param id - The message ID
@@ -35788,7 +35912,7 @@ var init_message_store = __esm({
35788
35912
  (${participantAFromPredicate} AND fromType = ? AND ${participantBToPredicate} AND toType = ?)
35789
35913
  OR
35790
35914
  (${participantBFromPredicate} AND fromType = ? AND ${participantAToPredicate} AND toType = ?)
35791
- )
35915
+ ) AND ${options?.archived === true ? "archived = 1" : "(archived = 0 OR archived IS NULL)"}
35792
35916
  ORDER BY createdAt DESC
35793
35917
  LIMIT ?
35794
35918
  `).all(
@@ -35823,11 +35947,11 @@ var init_message_store = __esm({
35823
35947
  const participantIds = this.getParticipantIdsForLookup(ownerId, ownerType);
35824
35948
  const toIdPredicate = participantIds.length === 1 ? "toId = ?" : `toId IN (${participantIds.map(() => "?").join(", ")})`;
35825
35949
  const unreadRow = this.db.prepare(`
35826
- SELECT COUNT(*) as count FROM messages WHERE ${toIdPredicate} AND toType = ? AND read = 0
35950
+ SELECT COUNT(*) as count FROM messages WHERE ${toIdPredicate} AND toType = ? AND read = 0 AND (archived = 0 OR archived IS NULL)
35827
35951
  `).get(...participantIds, ownerType);
35828
35952
  const unreadCount = unreadRow?.count ?? 0;
35829
35953
  const lastRow = this.db.prepare(`
35830
- SELECT * FROM messages WHERE ${toIdPredicate} AND toType = ? ORDER BY createdAt DESC, rowid DESC LIMIT 1
35954
+ SELECT * FROM messages WHERE ${toIdPredicate} AND toType = ? AND (archived = 0 OR archived IS NULL) ORDER BY createdAt DESC, rowid DESC LIMIT 1
35831
35955
  `).get(...participantIds, ownerType);
35832
35956
  const lastMessage = lastRow ? this.rowToMessage(lastRow) : void 0;
35833
35957
  return {
@@ -35841,13 +35965,13 @@ var init_message_store = __esm({
35841
35965
  * Get all agent-to-agent messages across all agents.
35842
35966
  * @returns Array of messages (newest first)
35843
35967
  */
35844
- async getAllAgentToAgentMessages() {
35968
+ async getAllAgentToAgentMessages(filter) {
35845
35969
  if (this.asyncLayer) {
35846
- return getAllAgentToAgentMessages(this.asyncLayer.db);
35970
+ return getAllAgentToAgentMessages(this.asyncLayer.db, filter);
35847
35971
  }
35848
35972
  const rows = this.db.prepare(`
35849
35973
  SELECT * FROM messages
35850
- WHERE type = ?
35974
+ WHERE type = ? AND ${filter?.archived === true ? "archived = 1" : "(archived = 0 OR archived IS NULL)"}
35851
35975
  ORDER BY createdAt DESC, rowid DESC
35852
35976
  `).all("agent-to-agent");
35853
35977
  return rows.map((row) => this.rowToMessage(row));
@@ -35861,7 +35985,7 @@ var init_message_store = __esm({
35861
35985
  }
35862
35986
  const row = this.db.prepare(`
35863
35987
  SELECT COUNT(*) as count FROM messages
35864
- WHERE type = ? AND read = 0
35988
+ WHERE type = ? AND read = 0 AND (archived = 0 OR archived IS NULL)
35865
35989
  `).get("agent-to-agent");
35866
35990
  return row?.count ?? 0;
35867
35991
  }
@@ -35960,6 +36084,7 @@ async function createApprovalRequest(layer, input) {
35960
36084
  };
35961
36085
  await layer.transactionImmediate(async (tx) => {
35962
36086
  await tx.insert(project_exports.approvalRequests).values({
36087
+ ...layer.projectId?.trim() ? { projectId: layer.projectId } : {},
35963
36088
  id: request2.id,
35964
36089
  status: request2.status,
35965
36090
  requesterActorId: request2.requester.actorId,
@@ -35983,12 +36108,12 @@ async function createApprovalRequest(layer, input) {
35983
36108
  });
35984
36109
  return request2;
35985
36110
  }
35986
- async function getApprovalRequest(handle, id) {
35987
- const rows = await handle.select().from(project_exports.approvalRequests).where(eq(project_exports.approvalRequests.id, id));
36111
+ async function getApprovalRequest(handle, id, projectId2) {
36112
+ const rows = await handle.select().from(project_exports.approvalRequests).where(and(eq(project_exports.approvalRequests.id, id), projectScopeFor(project_exports.approvalRequests.projectId, projectId2)));
35988
36113
  return rows[0] ? rowToRequest(rows[0]) : null;
35989
36114
  }
35990
- async function listApprovalRequests(handle, input = {}) {
35991
- const conditions = [];
36115
+ async function listApprovalRequests(handle, input = {}, projectId2) {
36116
+ const conditions = [projectScopeFor(project_exports.approvalRequests.projectId, projectId2)];
35992
36117
  if (input.status) conditions.push(eq(project_exports.approvalRequests.status, input.status));
35993
36118
  if (input.requesterActorId) conditions.push(eq(project_exports.approvalRequests.requesterActorId, input.requesterActorId));
35994
36119
  if (input.taskId) conditions.push(eq(project_exports.approvalRequests.taskId, input.taskId));
@@ -36002,7 +36127,7 @@ async function listApprovalRequests(handle, input = {}) {
36002
36127
  async function decideApprovalRequest(layer, requestId, status, input) {
36003
36128
  const now = (/* @__PURE__ */ new Date()).toISOString();
36004
36129
  return layer.transactionImmediate(async (tx) => {
36005
- const existing = await getApprovalRequest(tx, requestId);
36130
+ const existing = await getApprovalRequest(tx, requestId, layer.projectId);
36006
36131
  if (!existing) throw new Error(`Approval request ${requestId} not found`);
36007
36132
  if (!isValidApprovalRequestTransition(existing.status, status)) {
36008
36133
  throw new Error(`Invalid approval request transition: ${existing.status} -> ${status}`);
@@ -36013,23 +36138,24 @@ async function decideApprovalRequest(layer, requestId, status, input) {
36013
36138
  const updatedRows = await tx.update(project_exports.approvalRequests).set({ status, decidedAt: now, updatedAt: now }).where(
36014
36139
  and(
36015
36140
  eq(project_exports.approvalRequests.id, requestId),
36016
- eq(project_exports.approvalRequests.status, existing.status)
36141
+ eq(project_exports.approvalRequests.status, existing.status),
36142
+ projectScopeFor(project_exports.approvalRequests.projectId, layer.projectId)
36017
36143
  )
36018
36144
  ).returning({ id: project_exports.approvalRequests.id });
36019
36145
  if (updatedRows.length === 0) {
36020
- const raced = await getApprovalRequest(tx, requestId);
36146
+ const raced = await getApprovalRequest(tx, requestId, layer.projectId);
36021
36147
  throw new Error(
36022
36148
  `Invalid approval request transition: ${raced?.status ?? existing.status} -> ${status}`
36023
36149
  );
36024
36150
  }
36025
36151
  await appendAuditEvent(tx, layer.projectId ?? "", requestId, status, input.actor, now, input.note);
36026
- return await getApprovalRequest(tx, requestId);
36152
+ return await getApprovalRequest(tx, requestId, layer.projectId);
36027
36153
  });
36028
36154
  }
36029
36155
  async function markApprovalRequestCompleted(layer, requestId, input) {
36030
36156
  const now = (/* @__PURE__ */ new Date()).toISOString();
36031
36157
  return layer.transactionImmediate(async (tx) => {
36032
- const existing = await getApprovalRequest(tx, requestId);
36158
+ const existing = await getApprovalRequest(tx, requestId, layer.projectId);
36033
36159
  if (!existing) throw new Error(`Approval request ${requestId} not found`);
36034
36160
  if (!isValidApprovalRequestTransition(existing.status, "completed")) {
36035
36161
  throw new Error(`Invalid approval request transition: ${existing.status} -> completed`);
@@ -36043,21 +36169,22 @@ async function markApprovalRequestCompleted(layer, requestId, input) {
36043
36169
  const updatedRows = await tx.update(project_exports.approvalRequests).set({ status: "completed", completedAt: now, updatedAt: now }).where(
36044
36170
  and(
36045
36171
  eq(project_exports.approvalRequests.id, requestId),
36046
- eq(project_exports.approvalRequests.status, existing.status)
36172
+ eq(project_exports.approvalRequests.status, existing.status),
36173
+ projectScopeFor(project_exports.approvalRequests.projectId, layer.projectId)
36047
36174
  )
36048
36175
  ).returning({ id: project_exports.approvalRequests.id });
36049
36176
  if (updatedRows.length === 0) {
36050
- const raced = await getApprovalRequest(tx, requestId);
36177
+ const raced = await getApprovalRequest(tx, requestId, layer.projectId);
36051
36178
  throw new Error(
36052
36179
  `Invalid approval request transition: ${raced?.status ?? existing.status} -> completed`
36053
36180
  );
36054
36181
  }
36055
36182
  await appendAuditEvent(tx, layer.projectId ?? "", requestId, "completed", input.actor, now, input.note);
36056
- return await getApprovalRequest(tx, requestId);
36183
+ return await getApprovalRequest(tx, requestId, layer.projectId);
36057
36184
  });
36058
36185
  }
36059
- async function getApprovalAuditHistory(handle, requestId) {
36060
- const rows = await handle.select().from(project_exports.approvalRequestAuditEvents).where(eq(project_exports.approvalRequestAuditEvents.requestId, requestId)).orderBy(
36186
+ async function getApprovalAuditHistory(handle, requestId, projectId2) {
36187
+ const rows = await handle.select().from(project_exports.approvalRequestAuditEvents).where(and(eq(project_exports.approvalRequestAuditEvents.requestId, requestId), projectScopeFor(project_exports.approvalRequestAuditEvents.projectId, projectId2))).orderBy(
36061
36188
  sql`${project_exports.approvalRequestAuditEvents.createdAt} ASC, ${project_exports.approvalRequestAuditEvents.id} ASC`
36062
36189
  );
36063
36190
  return rows.map((row) => rowToAuditEvent(row));
@@ -36067,6 +36194,7 @@ var init_async_approval_request_store = __esm({
36067
36194
  "use strict";
36068
36195
  init_drizzle_orm();
36069
36196
  init_schema2();
36197
+ init_data_layer();
36070
36198
  init_agents();
36071
36199
  init_types();
36072
36200
  }
@@ -36080,6 +36208,7 @@ var init_approval_request_store = __esm({
36080
36208
  "use strict";
36081
36209
  init_drizzle_orm();
36082
36210
  init_db2();
36211
+ init_data_layer();
36083
36212
  init_async_approval_request_store();
36084
36213
  init_schema2();
36085
36214
  init_async_agent_activity();
@@ -36208,23 +36337,26 @@ var init_approval_request_store = __esm({
36208
36337
  return created;
36209
36338
  }
36210
36339
  async get(id) {
36211
- return getApprovalRequest(this.asyncLayer.db, id);
36340
+ return getApprovalRequest(this.asyncLayer.db, id, this.asyncLayer.projectId);
36212
36341
  }
36213
36342
  async list(input = {}) {
36214
- return listApprovalRequests(this.asyncLayer.db, input);
36343
+ return listApprovalRequests(this.asyncLayer.db, input, this.asyncLayer.projectId);
36215
36344
  }
36216
36345
  async getPendingCountsByActor() {
36217
36346
  const table = project_exports.approvalRequests;
36218
36347
  const rows = await this.asyncLayer.db.select({
36219
36348
  actorId: table.requesterActorId,
36220
36349
  requestCount: count()
36221
- }).from(table).where(eq(table.status, "pending")).groupBy(table.requesterActorId);
36350
+ }).from(table).where(and(eq(table.status, "pending"), projectScopeFor(table.projectId, this.asyncLayer.projectId))).groupBy(table.requesterActorId);
36222
36351
  return new Map(rows.map((row) => [row.actorId, Number(row.requestCount)]));
36223
36352
  }
36224
36353
  async findLatestByDedupeKey(input) {
36225
36354
  if (this.backendMode) {
36226
36355
  const table = project_exports.approvalRequests;
36227
- const conditions = [eq(table.requesterActorId, input.requesterActorId)];
36356
+ const conditions = [
36357
+ eq(table.requesterActorId, input.requesterActorId),
36358
+ projectScopeFor(table.projectId, this.asyncLayer.projectId)
36359
+ ];
36228
36360
  if (input.taskId !== void 0) {
36229
36361
  conditions.push(eq(table.taskId, input.taskId));
36230
36362
  }
@@ -36263,7 +36395,7 @@ var init_approval_request_store = __esm({
36263
36395
  return markApprovalRequestCompleted(this.asyncLayer, requestId, input);
36264
36396
  }
36265
36397
  async getAuditHistory(requestId) {
36266
- return getApprovalAuditHistory(this.asyncLayer.db, requestId);
36398
+ return getApprovalAuditHistory(this.asyncLayer.db, requestId, this.asyncLayer.projectId);
36267
36399
  }
36268
36400
  };
36269
36401
  }
@@ -40449,6 +40581,8 @@ async function applySchemaBaseline(db, options = {}) {
40449
40581
  const agentRatingProjectIsolationAlreadyApplied = applied.includes(AGENT_RATING_PROJECT_ISOLATION_VERSION);
40450
40582
  const agentRatingsProjectPartitionAlreadyApplied = applied.includes(AGENT_RATINGS_PROJECT_PARTITION_VERSION);
40451
40583
  const projectOwnershipDeclarationDriftAlreadyApplied = applied.includes(PROJECT_OWNERSHIP_DECLARATION_DRIFT_VERSION);
40584
+ const projectOwnershipDefaultReconciliationAlreadyApplied = applied.includes(PROJECT_OWNERSHIP_DEFAULT_RECONCILIATION_VERSION);
40585
+ const messageArchiveSchemaAlreadyApplied = applied.includes(MESSAGE_ARCHIVE_SCHEMA_VERSION);
40452
40586
  assertBinaryNotOlderThanDatabase(applied);
40453
40587
  let schemaChanged = false;
40454
40588
  if (!baselineAlreadyApplied) {
@@ -40932,17 +41066,29 @@ async function applySchemaBaseline(db, options = {}) {
40932
41066
  await tx.execute(sql`INSERT INTO public.${sql.identifier(MIGRATION_BOOKKEEPING_TABLE)} (version) VALUES (${PROJECT_OWNERSHIP_DECLARATION_DRIFT_VERSION}) ON CONFLICT (version) DO NOTHING`);
40933
41067
  schemaChanged = true;
40934
41068
  }
41069
+ if (!projectOwnershipDefaultReconciliationAlreadyApplied) {
41070
+ const migrationSql = await readFile4(PROJECT_OWNERSHIP_DEFAULT_RECONCILIATION_MIGRATION_PATH, "utf8");
41071
+ await tx.execute(sql.raw(migrationSql));
41072
+ await tx.execute(sql`INSERT INTO public.${sql.identifier(MIGRATION_BOOKKEEPING_TABLE)} (version) VALUES (${PROJECT_OWNERSHIP_DEFAULT_RECONCILIATION_VERSION}) ON CONFLICT (version) DO NOTHING`);
41073
+ schemaChanged = true;
41074
+ }
41075
+ if (!messageArchiveSchemaAlreadyApplied) {
41076
+ const migrationSql = await readFile4(MESSAGE_ARCHIVE_SCHEMA_MIGRATION_PATH, "utf8");
41077
+ await tx.execute(sql.raw(migrationSql));
41078
+ await tx.execute(sql`INSERT INTO public.${sql.identifier(MIGRATION_BOOKKEEPING_TABLE)} (version) VALUES (${MESSAGE_ARCHIVE_SCHEMA_VERSION}) ON CONFLICT (version) DO NOTHING`);
41079
+ schemaChanged = true;
41080
+ }
40935
41081
  return { applied: schemaChanged, pluginHooksRun: pluginHooks.length };
40936
41082
  });
40937
41083
  }
40938
- var SCHEMA_BASELINE_VERSION, TASK_DECLARED_SYMBOLS_VERSION, INITIAL_SCHEMA_VERSION, AUTOMATION_ISOLATION_SCHEMA_VERSION, ANALYTICS_ISOLATION_SCHEMA_VERSION, MONITOR_APPROVAL_ISOLATION_SCHEMA_VERSION, LEGACY_CUTOVER_PRESERVATION_SCHEMA_VERSION, MULTI_PROJECT_CUTOVER_SCHEMA_VERSION, PROJECT_OWNERSHIP_SCHEMA_VERSION, SQLITE_SCHEMA_PARITY_VERSION, SESSION_ADVISOR_ENABLED_SCHEMA_VERSION, MISSION_FIX_IDEMPOTENCY_VERSION, IMPORT_TRANSLATION_CACHE_VERSION, IMPORT_TRANSLATION_CACHE_SCOPE_FIX_VERSION, IMPORT_TRANSLATION_CACHE_LEGACY_PARTITION_BACKFILL_VERSION, OWNER_PROJECT_ID_SPLIT_VERSION, CHAT_SESSION_PINS_VERSION, EXECUTOR_TOOL_FAILURE_RETRY_VERSION, EXECUTOR_ESCALATION_ATTEMPT_VERSION, GLOBAL_ROUTINES_SCHEMA_VERSION, TASK_MERGER_MODEL_LANE_VERSION, BULK_COMPLETION_REFUSAL_AT_VERSION, TASK_PROPOSAL_CLAIM_VERSION, CONFIGURATION_REVISIONS_VERSION, IDEATION_SCHEMA_VERSION, RESEARCH_FEATURE_PROVENANCE_VERSION, TASK_VERIFICATION_REQUEST_VERSION, SYMBOL_LOCKS_SCHEMA_VERSION, BIGINT_COUNTERS_VERSION, PLANNING_ACTIVE_TIMING_VERSION, SQLITE_MIGRATION_RUNTIME_READ_VERSION, WORKFLOW_TASK_CONTINUATIONS_VERSION, LEGACY_ADOPTION_DRAINED_MARKER_RUNTIME_GRANTS_VERSION, TASK_WEDGE_NOTIFICATION_VERSION, MILESTONE_ASSERTION_PROVENANCE_VERSION, MISSION_LINEAGE_STOP_VERSION, CHAT_SESSION_TAGS_VERSION, DROP_GLOBAL_CONCURRENCY_VERSION, MISSION_TASK_PREFIX_VERSION, CREDENTIAL_INSTANCE_SELECTION_VERSION, TASK_LIFECYCLE_OUTBOX_VERSION, TASK_LIFECYCLE_CONSUMERS_VERSION, VALIDATOR_INPUT_FINGERPRINT_VERSION, UNPLANNED_EXECUTION_BLOCK_DEDUPE_VERSION, QUEUED_EPISODE_SIGNATURE_VERSION, MULTI_ROLE_WORKFLOW_AGENTS_VERSION, WORKFLOW_PRINCIPAL_FENCE_VERSION, TASK_RECOMMENDATIONS_VERSION, GITHUB_CHECK_STATES_VERSION, AGENT_ACTIVITY_EVENTS_VERSION, SPEC_LOCK_DRIFT_REPORT_VERSION, SPEC_LOCK_SOURCE_REVISION_BIGINT_VERSION, MEMORY_RECALL_RECORDS_VERSION, MISSION_FEATURE_SPEC_ALIGNMENT_VERSION, AGENT_RATING_PROJECT_ISOLATION_VERSION, AGENT_RATINGS_PROJECT_PARTITION_VERSION, PROJECT_OWNERSHIP_DECLARATION_DRIFT_VERSION, LEGACY_ADOPTION_DRAINED_MARKER_FUNCTION, StaleBinarySchemaError, MIGRATION_BOOKKEEPING_TABLE, LEGACY_ADOPTION_DRAINED_MARKER, __dirname, MIGRATIONS_DIR, BASELINE_MIGRATION_PATH, AUTOMATION_ISOLATION_MIGRATION_PATH, ANALYTICS_ISOLATION_MIGRATION_PATH, MONITOR_APPROVAL_ISOLATION_MIGRATION_PATH, LEGACY_CUTOVER_PRESERVATION_MIGRATION_PATH, MULTI_PROJECT_CUTOVER_MIGRATION_PATH, PROJECT_OWNERSHIP_MIGRATION_PATH, SQLITE_SCHEMA_PARITY_MIGRATION_PATH, SESSION_ADVISOR_ENABLED_MIGRATION_PATH, MISSION_FIX_IDEMPOTENCY_MIGRATION_PATH, IMPORT_TRANSLATION_CACHE_MIGRATION_PATH, IMPORT_TRANSLATION_CACHE_SCOPE_FIX_MIGRATION_PATH, IMPORT_TRANSLATION_CACHE_LEGACY_PARTITION_BACKFILL_MIGRATION_PATH, OWNER_PROJECT_ID_SPLIT_MIGRATION_PATH, CHAT_SESSION_PINS_MIGRATION_PATH, EXECUTOR_TOOL_FAILURE_RETRY_MIGRATION_PATH, EXECUTOR_ESCALATION_ATTEMPT_MIGRATION_PATH, GLOBAL_ROUTINES_MIGRATION_PATH, TASK_MERGER_MODEL_LANE_MIGRATION_PATH, BULK_COMPLETION_REFUSAL_AT_MIGRATION_PATH, TASK_PROPOSAL_CLAIM_MIGRATION_PATH, CONFIGURATION_REVISIONS_MIGRATION_PATH, IDEATION_MIGRATION_PATH, RESEARCH_FEATURE_PROVENANCE_MIGRATION_PATH, TASK_VERIFICATION_REQUEST_MIGRATION_PATH, SYMBOL_LOCKS_MIGRATION_PATH, BIGINT_COUNTERS_MIGRATION_PATH, WORKFLOW_IR_PIN_AND_LEGACY_ADOPTION_VERSION, WORKFLOW_IR_PIN_AND_LEGACY_ADOPTION_MIGRATION_PATH, PLANNING_ACTIVE_TIMING_MIGRATION_PATH, TASK_DECLARED_SYMBOLS_MIGRATION_PATH, SQLITE_MIGRATION_RUNTIME_READ_PATH, WORKFLOW_TASK_CONTINUATIONS_PATH, LEGACY_ADOPTION_DRAINED_MARKER_RUNTIME_GRANTS_PATH, TASK_WEDGE_NOTIFICATION_MIGRATION_PATH, MILESTONE_ASSERTION_PROVENANCE_MIGRATION_PATH, MISSION_LINEAGE_STOP_MIGRATION_PATH, CHAT_SESSION_TAGS_MIGRATION_PATH, DROP_GLOBAL_CONCURRENCY_MIGRATION_PATH, MISSION_TASK_PREFIX_MIGRATION_PATH, CREDENTIAL_INSTANCE_SELECTION_MIGRATION_PATH, TASK_LIFECYCLE_OUTBOX_MIGRATION_PATH, TASK_LIFECYCLE_CONSUMERS_MIGRATION_PATH, VALIDATOR_INPUT_FINGERPRINT_MIGRATION_PATH, UNPLANNED_EXECUTION_BLOCK_DEDUPE_MIGRATION_PATH, QUEUED_EPISODE_SIGNATURE_MIGRATION_PATH, MULTI_ROLE_WORKFLOW_AGENTS_MIGRATION_PATH, WORKFLOW_PRINCIPAL_FENCE_MIGRATION_PATH, TASK_RECOMMENDATIONS_MIGRATION_PATH, GITHUB_CHECK_STATES_MIGRATION_PATH, AGENT_ACTIVITY_EVENTS_MIGRATION_PATH, SPEC_LOCK_DRIFT_REPORT_MIGRATION_PATH, SPEC_LOCK_SOURCE_REVISION_BIGINT_MIGRATION_PATH, MEMORY_RECALL_RECORDS_MIGRATION_PATH, MISSION_FEATURE_SPEC_ALIGNMENT_MIGRATION_PATH, AGENT_RATING_PROJECT_ISOLATION_MIGRATION_PATH, AGENT_RATINGS_PROJECT_PARTITION_MIGRATION_PATH, PROJECT_OWNERSHIP_DECLARATION_DRIFT_MIGRATION_PATH;
41084
+ var SCHEMA_BASELINE_VERSION, TASK_DECLARED_SYMBOLS_VERSION, INITIAL_SCHEMA_VERSION, AUTOMATION_ISOLATION_SCHEMA_VERSION, ANALYTICS_ISOLATION_SCHEMA_VERSION, MONITOR_APPROVAL_ISOLATION_SCHEMA_VERSION, LEGACY_CUTOVER_PRESERVATION_SCHEMA_VERSION, MULTI_PROJECT_CUTOVER_SCHEMA_VERSION, PROJECT_OWNERSHIP_SCHEMA_VERSION, SQLITE_SCHEMA_PARITY_VERSION, SESSION_ADVISOR_ENABLED_SCHEMA_VERSION, MISSION_FIX_IDEMPOTENCY_VERSION, IMPORT_TRANSLATION_CACHE_VERSION, IMPORT_TRANSLATION_CACHE_SCOPE_FIX_VERSION, IMPORT_TRANSLATION_CACHE_LEGACY_PARTITION_BACKFILL_VERSION, OWNER_PROJECT_ID_SPLIT_VERSION, CHAT_SESSION_PINS_VERSION, EXECUTOR_TOOL_FAILURE_RETRY_VERSION, EXECUTOR_ESCALATION_ATTEMPT_VERSION, GLOBAL_ROUTINES_SCHEMA_VERSION, TASK_MERGER_MODEL_LANE_VERSION, BULK_COMPLETION_REFUSAL_AT_VERSION, TASK_PROPOSAL_CLAIM_VERSION, CONFIGURATION_REVISIONS_VERSION, IDEATION_SCHEMA_VERSION, RESEARCH_FEATURE_PROVENANCE_VERSION, TASK_VERIFICATION_REQUEST_VERSION, SYMBOL_LOCKS_SCHEMA_VERSION, BIGINT_COUNTERS_VERSION, PLANNING_ACTIVE_TIMING_VERSION, SQLITE_MIGRATION_RUNTIME_READ_VERSION, WORKFLOW_TASK_CONTINUATIONS_VERSION, LEGACY_ADOPTION_DRAINED_MARKER_RUNTIME_GRANTS_VERSION, TASK_WEDGE_NOTIFICATION_VERSION, MILESTONE_ASSERTION_PROVENANCE_VERSION, MISSION_LINEAGE_STOP_VERSION, CHAT_SESSION_TAGS_VERSION, DROP_GLOBAL_CONCURRENCY_VERSION, MISSION_TASK_PREFIX_VERSION, CREDENTIAL_INSTANCE_SELECTION_VERSION, TASK_LIFECYCLE_OUTBOX_VERSION, TASK_LIFECYCLE_CONSUMERS_VERSION, VALIDATOR_INPUT_FINGERPRINT_VERSION, UNPLANNED_EXECUTION_BLOCK_DEDUPE_VERSION, QUEUED_EPISODE_SIGNATURE_VERSION, MULTI_ROLE_WORKFLOW_AGENTS_VERSION, WORKFLOW_PRINCIPAL_FENCE_VERSION, TASK_RECOMMENDATIONS_VERSION, GITHUB_CHECK_STATES_VERSION, AGENT_ACTIVITY_EVENTS_VERSION, SPEC_LOCK_DRIFT_REPORT_VERSION, SPEC_LOCK_SOURCE_REVISION_BIGINT_VERSION, MEMORY_RECALL_RECORDS_VERSION, MISSION_FEATURE_SPEC_ALIGNMENT_VERSION, AGENT_RATING_PROJECT_ISOLATION_VERSION, AGENT_RATINGS_PROJECT_PARTITION_VERSION, PROJECT_OWNERSHIP_DECLARATION_DRIFT_VERSION, PROJECT_OWNERSHIP_DEFAULT_RECONCILIATION_VERSION, MESSAGE_ARCHIVE_SCHEMA_VERSION, LEGACY_ADOPTION_DRAINED_MARKER_FUNCTION, StaleBinarySchemaError, MIGRATION_BOOKKEEPING_TABLE, LEGACY_ADOPTION_DRAINED_MARKER, __dirname, MIGRATIONS_DIR, BASELINE_MIGRATION_PATH, AUTOMATION_ISOLATION_MIGRATION_PATH, ANALYTICS_ISOLATION_MIGRATION_PATH, MONITOR_APPROVAL_ISOLATION_MIGRATION_PATH, LEGACY_CUTOVER_PRESERVATION_MIGRATION_PATH, MULTI_PROJECT_CUTOVER_MIGRATION_PATH, PROJECT_OWNERSHIP_MIGRATION_PATH, SQLITE_SCHEMA_PARITY_MIGRATION_PATH, SESSION_ADVISOR_ENABLED_MIGRATION_PATH, MISSION_FIX_IDEMPOTENCY_MIGRATION_PATH, IMPORT_TRANSLATION_CACHE_MIGRATION_PATH, IMPORT_TRANSLATION_CACHE_SCOPE_FIX_MIGRATION_PATH, IMPORT_TRANSLATION_CACHE_LEGACY_PARTITION_BACKFILL_MIGRATION_PATH, OWNER_PROJECT_ID_SPLIT_MIGRATION_PATH, CHAT_SESSION_PINS_MIGRATION_PATH, EXECUTOR_TOOL_FAILURE_RETRY_MIGRATION_PATH, EXECUTOR_ESCALATION_ATTEMPT_MIGRATION_PATH, GLOBAL_ROUTINES_MIGRATION_PATH, TASK_MERGER_MODEL_LANE_MIGRATION_PATH, BULK_COMPLETION_REFUSAL_AT_MIGRATION_PATH, TASK_PROPOSAL_CLAIM_MIGRATION_PATH, CONFIGURATION_REVISIONS_MIGRATION_PATH, IDEATION_MIGRATION_PATH, RESEARCH_FEATURE_PROVENANCE_MIGRATION_PATH, TASK_VERIFICATION_REQUEST_MIGRATION_PATH, SYMBOL_LOCKS_MIGRATION_PATH, BIGINT_COUNTERS_MIGRATION_PATH, WORKFLOW_IR_PIN_AND_LEGACY_ADOPTION_VERSION, WORKFLOW_IR_PIN_AND_LEGACY_ADOPTION_MIGRATION_PATH, PLANNING_ACTIVE_TIMING_MIGRATION_PATH, TASK_DECLARED_SYMBOLS_MIGRATION_PATH, SQLITE_MIGRATION_RUNTIME_READ_PATH, WORKFLOW_TASK_CONTINUATIONS_PATH, LEGACY_ADOPTION_DRAINED_MARKER_RUNTIME_GRANTS_PATH, TASK_WEDGE_NOTIFICATION_MIGRATION_PATH, MILESTONE_ASSERTION_PROVENANCE_MIGRATION_PATH, MISSION_LINEAGE_STOP_MIGRATION_PATH, CHAT_SESSION_TAGS_MIGRATION_PATH, DROP_GLOBAL_CONCURRENCY_MIGRATION_PATH, MISSION_TASK_PREFIX_MIGRATION_PATH, CREDENTIAL_INSTANCE_SELECTION_MIGRATION_PATH, TASK_LIFECYCLE_OUTBOX_MIGRATION_PATH, TASK_LIFECYCLE_CONSUMERS_MIGRATION_PATH, VALIDATOR_INPUT_FINGERPRINT_MIGRATION_PATH, UNPLANNED_EXECUTION_BLOCK_DEDUPE_MIGRATION_PATH, QUEUED_EPISODE_SIGNATURE_MIGRATION_PATH, MULTI_ROLE_WORKFLOW_AGENTS_MIGRATION_PATH, WORKFLOW_PRINCIPAL_FENCE_MIGRATION_PATH, TASK_RECOMMENDATIONS_MIGRATION_PATH, GITHUB_CHECK_STATES_MIGRATION_PATH, AGENT_ACTIVITY_EVENTS_MIGRATION_PATH, SPEC_LOCK_DRIFT_REPORT_MIGRATION_PATH, SPEC_LOCK_SOURCE_REVISION_BIGINT_MIGRATION_PATH, MEMORY_RECALL_RECORDS_MIGRATION_PATH, MISSION_FEATURE_SPEC_ALIGNMENT_MIGRATION_PATH, AGENT_RATING_PROJECT_ISOLATION_MIGRATION_PATH, AGENT_RATINGS_PROJECT_PARTITION_MIGRATION_PATH, PROJECT_OWNERSHIP_DECLARATION_DRIFT_MIGRATION_PATH, PROJECT_OWNERSHIP_DEFAULT_RECONCILIATION_MIGRATION_PATH, MESSAGE_ARCHIVE_SCHEMA_MIGRATION_PATH;
40939
41085
  var init_schema_applier = __esm({
40940
41086
  "../core/src/postgres/schema-applier.ts"() {
40941
41087
  "use strict";
40942
41088
  init_drizzle_orm();
40943
41089
  init_plugin_schema_hook();
40944
41090
  init_advisory_locks();
40945
- SCHEMA_BASELINE_VERSION = "0056";
41091
+ SCHEMA_BASELINE_VERSION = "0058";
40946
41092
  TASK_DECLARED_SYMBOLS_VERSION = "0028";
40947
41093
  INITIAL_SCHEMA_VERSION = "0000";
40948
41094
  AUTOMATION_ISOLATION_SCHEMA_VERSION = "0001";
@@ -40999,6 +41145,8 @@ var init_schema_applier = __esm({
40999
41145
  AGENT_RATING_PROJECT_ISOLATION_VERSION = "0054";
41000
41146
  AGENT_RATINGS_PROJECT_PARTITION_VERSION = "0055";
41001
41147
  PROJECT_OWNERSHIP_DECLARATION_DRIFT_VERSION = "0056";
41148
+ PROJECT_OWNERSHIP_DEFAULT_RECONCILIATION_VERSION = "0057";
41149
+ MESSAGE_ARCHIVE_SCHEMA_VERSION = "0058";
41002
41150
  LEGACY_ADOPTION_DRAINED_MARKER_FUNCTION = "fusion_mark_legacy_adoption_drained";
41003
41151
  StaleBinarySchemaError = class extends Error {
41004
41152
  constructor(databaseVersion, binaryVersion) {
@@ -41135,6 +41283,8 @@ var init_schema_applier = __esm({
41135
41283
  AGENT_RATING_PROJECT_ISOLATION_MIGRATION_PATH = join8(MIGRATIONS_DIR, "0054_fn_8957_agent_rating_project_isolation.sql");
41136
41284
  AGENT_RATINGS_PROJECT_PARTITION_MIGRATION_PATH = join8(MIGRATIONS_DIR, "0055_fn_8988_agent_ratings_project_partition.sql");
41137
41285
  PROJECT_OWNERSHIP_DECLARATION_DRIFT_MIGRATION_PATH = join8(MIGRATIONS_DIR, "0056_fn_8997_project_ownership_declaration_drift.sql");
41286
+ PROJECT_OWNERSHIP_DEFAULT_RECONCILIATION_MIGRATION_PATH = join8(MIGRATIONS_DIR, "0057_fn_9004_project_ownership_default_reconciliation.sql");
41287
+ MESSAGE_ARCHIVE_SCHEMA_MIGRATION_PATH = join8(MIGRATIONS_DIR, "0058_fn_9014_message_archive.sql");
41138
41288
  }
41139
41289
  });
41140
41290
 
@@ -68667,8 +68817,10 @@ function safeJsonParse(value) {
68667
68817
  return null;
68668
68818
  }
68669
68819
  }
68670
- async function queryRunAuditEvents(db, filter = {}) {
68671
- const conditions = [];
68820
+ async function queryRunAuditEvents(db, filter = {}, projectId2) {
68821
+ const conditions = [projectScopeFor(project_exports.runAuditEvents.projectId, projectId2)].filter(
68822
+ (condition) => condition !== void 0
68823
+ );
68672
68824
  if (filter.runId) {
68673
68825
  conditions.push(eq(project_exports.runAuditEvents.runId, filter.runId));
68674
68826
  }
@@ -68814,6 +68966,7 @@ var init_async_audit = __esm({
68814
68966
  init_drizzle_orm();
68815
68967
  init_schema2();
68816
68968
  init_data_layer();
68969
+ init_data_layer();
68817
68970
  LEGACY_REVIEW_LANES3 = ["in-review"];
68818
68971
  LEGACY_COMPLETE_LANES = ["done"];
68819
68972
  }
@@ -69203,7 +69356,10 @@ async function insertArtifactRow(layer, input, stored, archivedColumns) {
69203
69356
  createdAt: now,
69204
69357
  updatedAt: now
69205
69358
  });
69206
- const rows = await tx.select().from(project_exports.artifacts).where(eq(project_exports.artifacts.id, id)).limit(1);
69359
+ const rows = await tx.select().from(project_exports.artifacts).where(and(
69360
+ eq(project_exports.artifacts.id, id),
69361
+ projectScopeFor(project_exports.artifacts.projectId, layer.projectId)
69362
+ )).limit(1);
69207
69363
  const row = rows[0];
69208
69364
  if (!row) throw new Error(`Failed to register artifact ${id}`);
69209
69365
  return rowToArtifact2(row);
@@ -69211,7 +69367,7 @@ async function insertArtifactRow(layer, input, stored, archivedColumns) {
69211
69367
  }
69212
69368
  async function updateArtifactRow(layer, id, updates, archivedColumns) {
69213
69369
  return layer.transactionImmediate(async (tx) => {
69214
- const existing = await getArtifact(tx, id);
69370
+ const existing = await getArtifact(tx, id, layer.projectId);
69215
69371
  if (!existing) {
69216
69372
  throw new Error(`Artifact ${id} not found`);
69217
69373
  }
@@ -69231,29 +69387,38 @@ async function updateArtifactRow(layer, id, updates, archivedColumns) {
69231
69387
  description: updates.description !== void 0 ? updates.description : existing.description ?? null,
69232
69388
  content: updates.content !== void 0 ? updates.content : existing.content ?? null,
69233
69389
  updatedAt: now
69234
- }).where(eq(project_exports.artifacts.id, id));
69235
- const updated = await getArtifact(tx, id);
69390
+ }).where(and(
69391
+ eq(project_exports.artifacts.id, id),
69392
+ projectScopeFor(project_exports.artifacts.projectId, layer.projectId)
69393
+ ));
69394
+ const updated = await getArtifact(tx, id, layer.projectId);
69236
69395
  if (!updated) {
69237
69396
  throw new Error(`Failed to update artifact ${id}`);
69238
69397
  }
69239
69398
  return updated;
69240
69399
  });
69241
69400
  }
69242
- async function getArtifact(db, id) {
69243
- const rows = await db.select().from(project_exports.artifacts).where(eq(project_exports.artifacts.id, id)).limit(1);
69401
+ async function getArtifact(db, id, projectId2) {
69402
+ const rows = await db.select().from(project_exports.artifacts).where(and(
69403
+ eq(project_exports.artifacts.id, id),
69404
+ projectScopeFor(project_exports.artifacts.projectId, projectId2)
69405
+ )).limit(1);
69244
69406
  const row = rows[0];
69245
69407
  return row ? rowToArtifact2(row) : null;
69246
69408
  }
69247
69409
  async function getArtifacts(db, taskId, projectId2, archivedColumns) {
69248
69410
  const column = await getLiveTaskColumn(db, taskId, projectId2, archivedColumns);
69249
69411
  if (column === null || column === "archived") return [];
69250
- const rows = await db.select().from(project_exports.artifacts).where(eq(project_exports.artifacts.taskId, taskId)).orderBy(desc(project_exports.artifacts.createdAt));
69412
+ const rows = await db.select().from(project_exports.artifacts).where(and(
69413
+ eq(project_exports.artifacts.taskId, taskId),
69414
+ projectScopeFor(project_exports.artifacts.projectId, projectId2)
69415
+ )).orderBy(desc(project_exports.artifacts.createdAt));
69251
69416
  return rows.map((row) => rowToArtifact2(row));
69252
69417
  }
69253
- async function listArtifacts(db, options) {
69418
+ async function listArtifacts(db, options, projectId2) {
69254
69419
  const limit = Math.min(Math.max(1, options?.limit ?? 200), 1e3);
69255
69420
  const offset = Math.max(0, options?.offset ?? 0);
69256
- const conditions = [];
69421
+ const conditions = [projectScopeFor(project_exports.artifacts.projectId, projectId2)];
69257
69422
  if (options?.type) {
69258
69423
  conditions.push(eq(project_exports.artifacts.type, options.type));
69259
69424
  }
@@ -69292,7 +69457,10 @@ async function listArtifacts(db, options) {
69292
69457
  taskColumn: project_exports.tasks.column
69293
69458
  }).from(project_exports.artifacts).leftJoin(
69294
69459
  project_exports.tasks,
69295
- eq(project_exports.artifacts.taskId, project_exports.tasks.id)
69460
+ and(
69461
+ eq(project_exports.artifacts.taskId, project_exports.tasks.id),
69462
+ eq(project_exports.artifacts.projectId, project_exports.tasks.projectId)
69463
+ )
69296
69464
  ).where(and(...conditions)).orderBy(desc(project_exports.artifacts.createdAt)).limit(limit).offset(offset);
69297
69465
  return rows.map((row) => {
69298
69466
  const artifact = rowToArtifact2(row);
@@ -70457,7 +70625,7 @@ function rowToBranchGroup2(row) {
70457
70625
  closedAt: row.closedAt ?? void 0
70458
70626
  };
70459
70627
  }
70460
- async function createBranchGroup(db, input) {
70628
+ async function createBranchGroup(db, input, projectId2) {
70461
70629
  validateBranchGroupBranchName(input.branchName);
70462
70630
  const now = Date.now();
70463
70631
  const id = generateBranchGroupId2();
@@ -70476,44 +70644,52 @@ async function createBranchGroup(db, input) {
70476
70644
  updatedAt: now,
70477
70645
  closedAt: input.closedAt ?? null
70478
70646
  });
70479
- const created = await getBranchGroup(db, id);
70647
+ const created = await getBranchGroup(db, id, projectId2);
70480
70648
  if (!created) throw new Error(`Failed to read branch group ${id} after create`);
70481
70649
  return created;
70482
70650
  }
70483
- async function getBranchGroup(db, id) {
70484
- const rows = await db.select().from(project_exports.branchGroups).where(eq(project_exports.branchGroups.id, id)).limit(1);
70651
+ async function getBranchGroup(db, id, projectId2) {
70652
+ const rows = await db.select().from(project_exports.branchGroups).where(and(
70653
+ eq(project_exports.branchGroups.id, id),
70654
+ projectScopeFor(project_exports.branchGroups.projectId, projectId2)
70655
+ )).limit(1);
70485
70656
  const row = rows[0];
70486
70657
  return row ? rowToBranchGroup2(row) : null;
70487
70658
  }
70488
- async function getBranchGroupBySource(db, sourceType, sourceId) {
70659
+ async function getBranchGroupBySource(db, sourceType, sourceId, projectId2) {
70489
70660
  const rows = await db.select().from(project_exports.branchGroups).where(
70490
70661
  and(
70491
70662
  eq(project_exports.branchGroups.sourceType, sourceType),
70492
- eq(project_exports.branchGroups.sourceId, sourceId)
70663
+ eq(project_exports.branchGroups.sourceId, sourceId),
70664
+ projectScopeFor(project_exports.branchGroups.projectId, projectId2)
70493
70665
  )
70494
70666
  ).limit(1);
70495
70667
  const row = rows[0];
70496
70668
  return row ? rowToBranchGroup2(row) : null;
70497
70669
  }
70498
- async function getBranchGroupByBranchName(db, branchName) {
70499
- const rows = await db.select().from(project_exports.branchGroups).where(eq(project_exports.branchGroups.branchName, branchName)).orderBy(sql`${project_exports.branchGroups.createdAt} DESC`).limit(1);
70670
+ async function getBranchGroupByBranchName(db, branchName, projectId2) {
70671
+ const rows = await db.select().from(project_exports.branchGroups).where(and(
70672
+ eq(project_exports.branchGroups.branchName, branchName),
70673
+ projectScopeFor(project_exports.branchGroups.projectId, projectId2)
70674
+ )).orderBy(sql`${project_exports.branchGroups.createdAt} DESC`).limit(1);
70500
70675
  const row = rows[0];
70501
70676
  return row ? rowToBranchGroup2(row) : null;
70502
70677
  }
70503
- async function ensureBranchGroupForSource(db, sourceType, sourceId, init) {
70504
- const existing = await getBranchGroupBySource(db, sourceType, sourceId);
70678
+ async function ensureBranchGroupForSource(db, sourceType, sourceId, init, projectId2) {
70679
+ const existing = await getBranchGroupBySource(db, sourceType, sourceId, projectId2);
70505
70680
  if (existing) return existing;
70506
- const existingByBranch = await getBranchGroupByBranchName(db, init.branchName);
70681
+ const existingByBranch = await getBranchGroupByBranchName(db, init.branchName, projectId2);
70507
70682
  if (existingByBranch) return existingByBranch;
70508
- return createBranchGroup(db, { sourceType, sourceId, ...init });
70683
+ return createBranchGroup(db, { sourceType, sourceId, ...init }, projectId2);
70509
70684
  }
70510
- async function listBranchGroups(db, options) {
70511
- const query = db.select().from(project_exports.branchGroups).orderBy(asc(project_exports.branchGroups.createdAt));
70512
- const rows = options?.status ? await query.where(eq(project_exports.branchGroups.status, options.status)) : await query;
70685
+ async function listBranchGroups(db, options, projectId2) {
70686
+ const conditions = [projectScopeFor(project_exports.branchGroups.projectId, projectId2)];
70687
+ if (options?.status) conditions.push(eq(project_exports.branchGroups.status, options.status));
70688
+ const rows = await db.select().from(project_exports.branchGroups).where(and(...conditions)).orderBy(asc(project_exports.branchGroups.createdAt));
70513
70689
  return rows.map((row) => rowToBranchGroup2(row));
70514
70690
  }
70515
- async function updateBranchGroup(db, id, patch) {
70516
- const current = await getBranchGroup(db, id);
70691
+ async function updateBranchGroup(db, id, patch, projectId2) {
70692
+ const current = await getBranchGroup(db, id, projectId2);
70517
70693
  if (!current) throw new Error(`Branch group ${id} not found`);
70518
70694
  if (patch.branchName !== void 0) {
70519
70695
  validateBranchGroupBranchName(patch.branchName);
@@ -70532,8 +70708,11 @@ async function updateBranchGroup(db, id, patch) {
70532
70708
  status: nextStatus,
70533
70709
  updatedAt: now,
70534
70710
  closedAt: nextClosedAt
70535
- }).where(eq(project_exports.branchGroups.id, id));
70536
- const updated = await getBranchGroup(db, id);
70711
+ }).where(and(
70712
+ eq(project_exports.branchGroups.id, id),
70713
+ projectScopeFor(project_exports.branchGroups.projectId, projectId2)
70714
+ ));
70715
+ const updated = await getBranchGroup(db, id, projectId2);
70537
70716
  if (!updated) throw new Error(`Branch group ${id} disappeared after update`);
70538
70717
  return updated;
70539
70718
  }
@@ -70690,6 +70869,7 @@ var init_async_branch_groups = __esm({
70690
70869
  "use strict";
70691
70870
  init_drizzle_orm();
70692
70871
  init_schema2();
70872
+ init_data_layer();
70693
70873
  init_branch_assignment();
70694
70874
  }
70695
70875
  });
@@ -80503,6 +80683,9 @@ import { randomUUID as randomUUID21 } from "node:crypto";
80503
80683
  function tableForScope(scope) {
80504
80684
  return scope === "project" ? project_exports.secrets : central_exports.secretsGlobal;
80505
80685
  }
80686
+ function scopeForSecretTable(scope, table, projectId2) {
80687
+ return scope === "project" ? projectScopeFor(table.projectId, projectId2) : void 0;
80688
+ }
80506
80689
  function isAccessPolicy(value) {
80507
80690
  return value === "auto" || value === "prompt" || value === "deny";
80508
80691
  }
@@ -80525,23 +80708,23 @@ function rowToRecord2(row, scope) {
80525
80708
  lastReadBy: row.lastReadBy
80526
80709
  };
80527
80710
  }
80528
- async function getSecretMetadata(handle, id, scope) {
80711
+ async function getSecretMetadata(handle, id, scope, projectId2) {
80529
80712
  const table = tableForScope(scope);
80530
- const rows = await handle.select(metadataColumns(table)).from(table).where(eq(table.id, id)).limit(1);
80713
+ const rows = await handle.select(metadataColumns(table)).from(table).where(and(eq(table.id, id), scopeForSecretTable(scope, table, projectId2))).limit(1);
80531
80714
  const row = rows[0];
80532
80715
  return row ? rowToRecord2(row, scope) : null;
80533
80716
  }
80534
- async function listSecrets(handle, scope) {
80717
+ async function listSecrets(handle, scope, projectId2) {
80535
80718
  if (scope) {
80536
80719
  const table = tableForScope(scope);
80537
- const rows = await handle.select(metadataColumns(table)).from(table).orderBy(asc(sql`lower(${table.key})`));
80720
+ const rows = await handle.select(metadataColumns(table)).from(table).where(scopeForSecretTable(scope, table, projectId2)).orderBy(asc(sql`lower(${table.key})`));
80538
80721
  return rows.map((row) => rowToRecord2(row, scope));
80539
80722
  }
80540
- const project = await listSecrets(handle, "project");
80541
- const global2 = await listSecrets(handle, "global");
80723
+ const project = await listSecrets(handle, "project", projectId2);
80724
+ const global2 = await listSecrets(handle, "global", projectId2);
80542
80725
  return [...project, ...global2];
80543
80726
  }
80544
- async function createSecret(handle, cipher, input) {
80727
+ async function createSecret(handle, cipher, input, projectId2) {
80545
80728
  const key = input.key.trim();
80546
80729
  if (!key) {
80547
80730
  throw new SecretsStoreError({ code: "invalid-key", message: "Secret key is required" });
@@ -80555,6 +80738,7 @@ async function createSecret(handle, cipher, input) {
80555
80738
  const table = tableForScope(input.scope);
80556
80739
  try {
80557
80740
  await handle.insert(table).values({
80741
+ ...input.scope === "project" && projectId2?.trim() ? { projectId: projectId2 } : {},
80558
80742
  id,
80559
80743
  key,
80560
80744
  valueCiphertext: encrypted.ciphertext,
@@ -80574,14 +80758,14 @@ async function createSecret(handle, cipher, input) {
80574
80758
  }
80575
80759
  throw error3;
80576
80760
  }
80577
- const created = await getSecretMetadata(handle, id, input.scope);
80761
+ const created = await getSecretMetadata(handle, id, input.scope, projectId2);
80578
80762
  if (!created) {
80579
80763
  throw new SecretsStoreError({ code: "not-found", message: "Secret insert succeeded but row could not be read back" });
80580
80764
  }
80581
80765
  return created;
80582
80766
  }
80583
- async function updateSecret(handle, cipher, id, scope, patch) {
80584
- const existing = await getSecretMetadata(handle, id, scope);
80767
+ async function updateSecret(handle, cipher, id, scope, patch, projectId2) {
80768
+ const existing = await getSecretMetadata(handle, id, scope, projectId2);
80585
80769
  if (!existing) {
80586
80770
  throw new SecretsStoreError({ code: "not-found", message: "Secret not found" });
80587
80771
  }
@@ -80615,34 +80799,34 @@ async function updateSecret(handle, cipher, id, scope, patch) {
80615
80799
  updates.nonce = encrypted.nonce;
80616
80800
  }
80617
80801
  try {
80618
- await handle.update(table).set(updates).where(eq(table.id, id));
80802
+ await handle.update(table).set(updates).where(and(eq(table.id, id), scopeForSecretTable(scope, table, projectId2)));
80619
80803
  } catch (error3) {
80620
80804
  if (isPostgresUniqueError(error3)) {
80621
80805
  throw new SecretsStoreError({ code: "duplicate-key", message: "Secret key already exists" });
80622
80806
  }
80623
80807
  throw error3;
80624
80808
  }
80625
- const updated = await getSecretMetadata(handle, id, scope);
80809
+ const updated = await getSecretMetadata(handle, id, scope, projectId2);
80626
80810
  if (!updated) {
80627
80811
  throw new SecretsStoreError({ code: "not-found", message: "Secret update succeeded but row could not be read back" });
80628
80812
  }
80629
80813
  return updated;
80630
80814
  }
80631
- async function deleteSecret(handle, id, scope) {
80632
- const existing = await getSecretMetadata(handle, id, scope);
80815
+ async function deleteSecret(handle, id, scope, projectId2) {
80816
+ const existing = await getSecretMetadata(handle, id, scope, projectId2);
80633
80817
  if (!existing) {
80634
80818
  throw new SecretsStoreError({ code: "not-found", message: "Secret not found" });
80635
80819
  }
80636
80820
  const table = tableForScope(scope);
80637
- await handle.delete(table).where(eq(table.id, id));
80821
+ await handle.delete(table).where(and(eq(table.id, id), scopeForSecretTable(scope, table, projectId2)));
80638
80822
  }
80639
- async function revealSecret(handle, cipher, id, scope, reader) {
80823
+ async function revealSecret(handle, cipher, id, scope, reader, projectId2) {
80640
80824
  const table = tableForScope(scope);
80641
80825
  const rows = await handle.select({
80642
80826
  ...metadataColumns(table),
80643
80827
  valueCiphertext: table.valueCiphertext,
80644
80828
  nonce: table.nonce
80645
- }).from(table).where(eq(table.id, id)).limit(1);
80829
+ }).from(table).where(and(eq(table.id, id), scopeForSecretTable(scope, table, projectId2))).limit(1);
80646
80830
  const row = rows[0];
80647
80831
  if (!row) {
80648
80832
  throw new SecretsStoreError({ code: "not-found", message: "Secret not found" });
@@ -80661,7 +80845,7 @@ async function revealSecret(handle, cipher, id, scope, reader) {
80661
80845
  }
80662
80846
  const now = (/* @__PURE__ */ new Date()).toISOString();
80663
80847
  const lastReadBy = reader.userId ?? reader.agentId ?? null;
80664
- await handle.update(table).set({ lastReadAt: now, lastReadBy, updatedAt: now }).where(eq(table.id, id));
80848
+ await handle.update(table).set({ lastReadAt: now, lastReadBy, updatedAt: now }).where(and(eq(table.id, id), scopeForSecretTable(scope, table, projectId2)));
80665
80849
  return { key: row.key, plaintextValue };
80666
80850
  }
80667
80851
  var severityAuditLog10, SecretsStoreError, metadataColumns;
@@ -80672,6 +80856,7 @@ var init_async_secrets_store = __esm({
80672
80856
  init_drizzle_orm();
80673
80857
  init_postgres_errors();
80674
80858
  init_schema2();
80859
+ init_data_layer();
80675
80860
  init_secrets_crypto();
80676
80861
  severityAuditLog10 = createLogger("core-async-secrets-store");
80677
80862
  SecretsStoreError = class extends Error {
@@ -80767,7 +80952,7 @@ var init_secrets_store = __esm({
80767
80952
  };
80768
80953
  }
80769
80954
  async listSecrets(scope) {
80770
- return listSecrets(this.asyncLayer.db, scope);
80955
+ return listSecrets(this.asyncLayer.db, scope, this.asyncLayer.projectId);
80771
80956
  }
80772
80957
  async listEnvExportable(opts) {
80773
80958
  const keyPrefix = opts?.keyPrefix;
@@ -80810,7 +80995,7 @@ var init_secrets_store = __esm({
80810
80995
  return [...exported.values()];
80811
80996
  }
80812
80997
  async getSecretMetadata(id, scope) {
80813
- return getSecretMetadata(this.asyncLayer.db, id, scope);
80998
+ return getSecretMetadata(this.asyncLayer.db, id, scope, this.asyncLayer.projectId);
80814
80999
  }
80815
81000
  async createSecret(input) {
80816
81001
  const key = input.key.trim();
@@ -80820,12 +81005,12 @@ var init_secrets_store = __esm({
80820
81005
  if (input.accessPolicy && !isAccessPolicy2(input.accessPolicy)) {
80821
81006
  throw new SecretsStoreError2({ code: "invalid-policy", message: "Invalid access policy" });
80822
81007
  }
80823
- const created = await createSecret(this.asyncLayer.db, this.cipher, input);
81008
+ const created = await createSecret(this.asyncLayer.db, this.cipher, input, this.asyncLayer.projectId);
80824
81009
  this.emitAudit({ mutationType: "secret:create", scope: input.scope, secretId: created.id, key: created.key });
80825
81010
  return created;
80826
81011
  }
80827
81012
  async updateSecret(id, scope, patch) {
80828
- const updated = await updateSecret(this.asyncLayer.db, this.cipher, id, scope, patch);
81013
+ const updated = await updateSecret(this.asyncLayer.db, this.cipher, id, scope, patch, this.asyncLayer.projectId);
80829
81014
  this.emitAudit({ mutationType: "secret:update", scope, secretId: updated.id, key: updated.key });
80830
81015
  return updated;
80831
81016
  }
@@ -80834,12 +81019,12 @@ var init_secrets_store = __esm({
80834
81019
  if (!existing) {
80835
81020
  throw new SecretsStoreError2({ code: "not-found", message: "Secret not found" });
80836
81021
  }
80837
- await deleteSecret(this.asyncLayer.db, id, scope);
81022
+ await deleteSecret(this.asyncLayer.db, id, scope, this.asyncLayer.projectId);
80838
81023
  this.emitAudit({ mutationType: "secret:delete", scope, secretId: id, key: existing.key });
80839
81024
  return;
80840
81025
  }
80841
81026
  async revealSecret(id, scope, reader) {
80842
- const revealed = await revealSecret(this.asyncLayer.db, this.cipher, id, scope, reader);
81027
+ const revealed = await revealSecret(this.asyncLayer.db, this.cipher, id, scope, reader, this.asyncLayer.projectId);
80843
81028
  this.emitAudit({ mutationType: "secret:read", scope, secretId: id, key: revealed.key, actor: reader });
80844
81029
  return revealed;
80845
81030
  }
@@ -81940,6 +82125,7 @@ async function getVerificationCacheHitImpl(store, treeSha, testCommand, buildCom
81940
82125
  const normalizedBuild = buildCommand2 ?? "";
81941
82126
  const table = project_exports.verificationCache;
81942
82127
  const rows = await store.asyncLayer.db.select({ recordedAt: table.recordedAt, taskId: table.taskId }).from(table).where(and(
82128
+ projectScopeFor(table.projectId, store.asyncLayer.projectId),
81943
82129
  eq(table.treeSha, treeSha),
81944
82130
  eq(table.testCommand, normalizedTest),
81945
82131
  eq(table.buildCommand, normalizedBuild)
@@ -82682,7 +82868,7 @@ async function invokeTaskCreatedHookImpl(store, task) {
82682
82868
  }
82683
82869
  async function createBranchGroupImpl(store, input) {
82684
82870
  const layer = store.asyncLayer;
82685
- return createBranchGroup(layer.db, input);
82871
+ return createBranchGroup(layer.db, input, layer.projectId);
82686
82872
  }
82687
82873
  var init_task_id_integrity2 = __esm({
82688
82874
  "../core/src/task-store/task-id-integrity.ts"() {
@@ -82767,22 +82953,23 @@ import { readFile as readFile7, writeFile as writeFile5 } from "node:fs/promises
82767
82953
  import { join as join23 } from "node:path";
82768
82954
  async function getBranchGroupImpl(store, id) {
82769
82955
  const layer = store.asyncLayer;
82770
- return getBranchGroup(layer.db, id);
82956
+ return getBranchGroup(layer.db, id, layer.projectId);
82771
82957
  }
82772
82958
  async function getBranchGroupBySourceImpl(store, sourceType, sourceId) {
82773
82959
  const layer = store.asyncLayer;
82774
- return getBranchGroupBySource(layer.db, sourceType, sourceId);
82960
+ return getBranchGroupBySource(layer.db, sourceType, sourceId, layer.projectId);
82775
82961
  }
82776
82962
  async function getBranchGroupByBranchNameImpl(store, branchName) {
82777
82963
  const layer = store.asyncLayer;
82778
- return getBranchGroupByBranchName(layer.db, branchName);
82964
+ return getBranchGroupByBranchName(layer.db, branchName, layer.projectId);
82779
82965
  }
82780
82966
  async function ensureBranchGroupForSourceImpl(store, sourceType, sourceId, init) {
82781
- return ensureBranchGroupForSource(store.asyncLayer.db, sourceType, sourceId, init);
82967
+ const layer = store.asyncLayer;
82968
+ return ensureBranchGroupForSource(layer.db, sourceType, sourceId, init, layer.projectId);
82782
82969
  }
82783
82970
  async function listBranchGroupsImpl(store, options) {
82784
82971
  const layer = store.asyncLayer;
82785
- return listBranchGroups(layer.db, options);
82972
+ return listBranchGroups(layer.db, options, layer.projectId);
82786
82973
  }
82787
82974
  async function listTasksByBranchGroupImpl(store, groupId) {
82788
82975
  const tasks2 = await store.listTasks({ includeArchived: true, slim: false });
@@ -84324,7 +84511,7 @@ function insertArtifactRowImpl(store, input, id, now, stored) {
84324
84511
  }
84325
84512
  async function getArtifactImpl(store, id) {
84326
84513
  const layer = store.asyncLayer;
84327
- return getArtifact(layer.db, id);
84514
+ return getArtifact(layer.db, id, layer.projectId);
84328
84515
  }
84329
84516
  async function updateArtifactImpl(store, id, updates) {
84330
84517
  const layer = store.asyncLayer;
@@ -89193,6 +89380,7 @@ var init_async_archive_lineage = __esm({
89193
89380
  "use strict";
89194
89381
  init_drizzle_orm();
89195
89382
  init_schema2();
89383
+ init_data_layer();
89196
89384
  init_async_persistence();
89197
89385
  init_async_lifecycle();
89198
89386
  init_lineage_approval_invalidation();
@@ -92660,7 +92848,7 @@ async function _maybeAutoArchiveSameAgentDuplicateBackendImpl(store, task, input
92660
92848
  }
92661
92849
  async function updateBranchGroupImpl(store, id, patch) {
92662
92850
  const layer = store.asyncLayer;
92663
- return updateBranchGroup(layer.db, id, patch);
92851
+ return updateBranchGroup(layer.db, id, patch, layer.projectId);
92664
92852
  }
92665
92853
  async function updatePrEntityImpl(store, id, patch) {
92666
92854
  const layer = store.asyncLayer;
@@ -93170,13 +93358,19 @@ async function deleteAttachmentArtifactRows(store, taskId, filename) {
93170
93358
  const linkedArtifactIds = artifacts2.filter((artifact) => artifact.metadata?.source === "attachment" && artifact.metadata.attachmentFilename === filename).map((artifact) => artifact.id);
93171
93359
  if (linkedArtifactIds.length === 0) return;
93172
93360
  for (const artifactId of linkedArtifactIds) {
93173
- await layer.db.delete(project_exports.artifacts).where(eq(project_exports.artifacts.id, artifactId));
93361
+ await layer.db.delete(project_exports.artifacts).where(and(
93362
+ eq(project_exports.artifacts.id, artifactId),
93363
+ projectScopeFor(project_exports.artifacts.projectId, layer.projectId)
93364
+ ));
93174
93365
  }
93175
93366
  return;
93176
93367
  }
93177
93368
  async function getArtifactsForAttachmentCleanup(store, taskId) {
93178
93369
  const layer = store.asyncLayer;
93179
- const rows = await layer.db.select().from(project_exports.artifacts).where(eq(project_exports.artifacts.taskId, taskId));
93370
+ const rows = await layer.db.select().from(project_exports.artifacts).where(and(
93371
+ eq(project_exports.artifacts.taskId, taskId),
93372
+ projectScopeFor(project_exports.artifacts.projectId, layer.projectId)
93373
+ ));
93180
93374
  return rows;
93181
93375
  }
93182
93376
  async function deleteAttachmentImpl(store, id, filename) {
@@ -95592,7 +95786,7 @@ function clearLinkedAgentTaskIdsImpl(store, taskId, updatedAt = (/* @__PURE__ */
95592
95786
  `).run(updatedAt, updatedAt, taskId);
95593
95787
  }
95594
95788
  async function listArtifactsImpl(store, options) {
95595
- return listArtifacts(store.asyncLayer.db, options);
95789
+ return listArtifacts(store.asyncLayer.db, options, store.asyncLayer.projectId);
95596
95790
  }
95597
95791
  async function rehomeOccupantImpl(store, taskId, targetColumn, reason, metadata) {
95598
95792
  let current;
@@ -103919,7 +104113,11 @@ var init_store = __esm({
103919
104113
  /** PostgreSQL-authoritative audit reader; sync fallback remains for test doubles. */
103920
104114
  async getRunAuditEventsAsync(options = {}) {
103921
104115
  if (this.asyncLayer) {
103922
- const events = await queryRunAuditEvents(this.asyncLayer.db, options);
104116
+ const events = await queryRunAuditEvents(
104117
+ this.asyncLayer.db,
104118
+ options,
104119
+ this.asyncLayer.projectId
104120
+ );
103923
104121
  return events.map((event) => ({
103924
104122
  ...event,
103925
104123
  taskId: event.taskId ?? void 0,
@@ -107497,7 +107695,9 @@ function rangeWhere(query) {
107497
107695
  async function aggregatePluginActivations(dbOrLayer, query = {}) {
107498
107696
  if ("ping" in dbOrLayer) {
107499
107697
  const layer = dbOrLayer;
107500
- const conditions = [];
107698
+ const conditions = [projectScopeFor(project_exports.pluginActivations.projectId, layer.projectId)].filter(
107699
+ (condition) => condition !== void 0
107700
+ );
107501
107701
  if (query.from !== void 0) conditions.push(gte(project_exports.pluginActivations.activatedAt, query.from));
107502
107702
  if (query.to !== void 0) conditions.push(lte(project_exports.pluginActivations.activatedAt, query.to));
107503
107703
  const where2 = conditions.length > 0 ? and(...conditions) : void 0;
@@ -107536,6 +107736,7 @@ async function aggregatePluginActivations(dbOrLayer, query = {}) {
107536
107736
  var init_plugin_activation_analytics = __esm({
107537
107737
  "../core/src/plugins/plugin-activation-analytics.ts"() {
107538
107738
  "use strict";
107739
+ init_data_layer();
107539
107740
  init_drizzle_orm();
107540
107741
  init_schema2();
107541
107742
  }
@@ -130533,6 +130734,18 @@ function rowToMessage2(row) {
130533
130734
  createdAt: row.createdAt
130534
130735
  };
130535
130736
  }
130737
+ function chatMessageProjectConditions(handle, projectId2) {
130738
+ const messageScope = projectScopeFor(project_exports.chatMessages.projectId, projectId2);
130739
+ const sessionScope = projectScopeFor(project_exports.chatSessions.projectId, projectId2);
130740
+ if (!messageScope || !sessionScope) return [];
130741
+ return [
130742
+ messageScope,
130743
+ exists(handle.select({ id: project_exports.chatSessions.id }).from(project_exports.chatSessions).where(and(
130744
+ eq(project_exports.chatSessions.id, project_exports.chatMessages.sessionId),
130745
+ sessionScope
130746
+ )))
130747
+ ];
130748
+ }
130536
130749
  function rowToRoom(row) {
130537
130750
  return {
130538
130751
  id: row.id,
@@ -130704,7 +130917,7 @@ async function replaceChatSessionTags(layer, sessionId, projectId2, tagIds) {
130704
130917
  return attachTags(tx, session);
130705
130918
  });
130706
130919
  }
130707
- async function addChatMessage(handle, message) {
130920
+ async function addChatMessage(handle, message, projectId2) {
130708
130921
  const sanitizedAttachments = message.attachments === void 0 ? void 0 : sanitizeJsonbValue(message.attachments);
130709
130922
  const sanitized = {
130710
130923
  ...message,
@@ -130723,15 +130936,24 @@ async function addChatMessage(handle, message) {
130723
130936
  attachments: sanitizedAttachments ?? null,
130724
130937
  createdAt: sanitized.createdAt
130725
130938
  });
130726
- await handle.update(project_exports.chatSessions).set({ updatedAt: sanitized.createdAt }).where(eq(project_exports.chatSessions.id, sanitized.sessionId));
130939
+ await handle.update(project_exports.chatSessions).set({ updatedAt: sanitized.createdAt }).where(and(
130940
+ eq(project_exports.chatSessions.id, sanitized.sessionId),
130941
+ projectScopeFor(project_exports.chatSessions.projectId, projectId2)
130942
+ ));
130727
130943
  return sanitized;
130728
130944
  }
130729
- async function getChatMessage(handle, id) {
130730
- const rows = await handle.select().from(project_exports.chatMessages).where(eq(project_exports.chatMessages.id, id));
130945
+ async function getChatMessage(handle, id, projectId2) {
130946
+ const rows = await handle.select().from(project_exports.chatMessages).where(and(
130947
+ eq(project_exports.chatMessages.id, id),
130948
+ ...chatMessageProjectConditions(handle, projectId2)
130949
+ ));
130731
130950
  return rows[0] ? rowToMessage2(rows[0]) : void 0;
130732
130951
  }
130733
- async function getChatMessages(handle, sessionId, filter) {
130734
- const conditions = [eq(project_exports.chatMessages.sessionId, sessionId)];
130952
+ async function getChatMessages(handle, sessionId, filter, projectId2) {
130953
+ const conditions = [
130954
+ eq(project_exports.chatMessages.sessionId, sessionId),
130955
+ ...chatMessageProjectConditions(handle, projectId2)
130956
+ ];
130735
130957
  if (filter?.before) {
130736
130958
  conditions.push(lte(project_exports.chatMessages.createdAt, filter.before));
130737
130959
  }
@@ -130741,9 +130963,12 @@ async function getChatMessages(handle, sessionId, filter) {
130741
130963
  const rows = await handle.select().from(project_exports.chatMessages).where(and(...conditions)).orderBy(filter?.order === "desc" ? desc(orderCol) : asc(orderCol)).limit(limit).offset(offset);
130742
130964
  return rows.map(rowToMessage2);
130743
130965
  }
130744
- async function getLastMessageForSessions(handle, sessionIds) {
130966
+ async function getLastMessageForSessions(handle, sessionIds, projectId2) {
130745
130967
  if (sessionIds.length === 0) return /* @__PURE__ */ new Map();
130746
- const rows = await handle.select().from(project_exports.chatMessages).where(inArray(project_exports.chatMessages.sessionId, sessionIds)).orderBy(
130968
+ const rows = await handle.select().from(project_exports.chatMessages).where(and(
130969
+ inArray(project_exports.chatMessages.sessionId, sessionIds),
130970
+ ...chatMessageProjectConditions(handle, projectId2)
130971
+ )).orderBy(
130747
130972
  desc(project_exports.chatMessages.createdAt),
130748
130973
  desc(project_exports.chatMessages.id)
130749
130974
  );
@@ -130909,8 +131134,8 @@ async function setInFlightGeneration(handle, id, inFlightGeneration) {
130909
131134
  await handle.update(project_exports.chatSessions).set({ inFlightGeneration: sanitizedInFlightGeneration }).where(eq(project_exports.chatSessions.id, id));
130910
131135
  return getChatSession(handle, id);
130911
131136
  }
130912
- async function addChatMessageAttachment(handle, sessionId, messageId, attachment) {
130913
- const message = await getChatMessage(handle, messageId);
131137
+ async function addChatMessageAttachment(handle, sessionId, messageId, attachment, projectId2) {
131138
+ const message = await getChatMessage(handle, messageId, projectId2);
130914
131139
  if (!message || message.sessionId !== sessionId) {
130915
131140
  throw new Error(`Message ${messageId} not found in session ${sessionId}`);
130916
131141
  }
@@ -130918,25 +131143,35 @@ async function addChatMessageAttachment(handle, sessionId, messageId, attachment
130918
131143
  ...message.attachments ?? [],
130919
131144
  attachment
130920
131145
  ]);
130921
- await handle.update(project_exports.chatMessages).set({ attachments: updatedAttachments }).where(eq(project_exports.chatMessages.id, messageId));
130922
- const updated = await getChatMessage(handle, messageId);
131146
+ await handle.update(project_exports.chatMessages).set({ attachments: updatedAttachments }).where(and(
131147
+ eq(project_exports.chatMessages.id, messageId),
131148
+ ...chatMessageProjectConditions(handle, projectId2)
131149
+ ));
131150
+ const updated = await getChatMessage(handle, messageId, projectId2);
130923
131151
  if (!updated) throw new Error(`Failed to update message ${messageId}`);
130924
131152
  return updated;
130925
131153
  }
130926
- async function deleteChatMessage(handle, id) {
130927
- const existing = await getChatMessage(handle, id);
131154
+ async function deleteChatMessage(handle, id, projectId2) {
131155
+ const existing = await getChatMessage(handle, id, projectId2);
130928
131156
  if (!existing) return false;
130929
- await handle.delete(project_exports.chatMessages).where(eq(project_exports.chatMessages.id, id));
130930
- await handle.update(project_exports.chatSessions).set({ updatedAt: (/* @__PURE__ */ new Date()).toISOString() }).where(eq(project_exports.chatSessions.id, existing.sessionId));
131157
+ await handle.delete(project_exports.chatMessages).where(and(
131158
+ eq(project_exports.chatMessages.id, id),
131159
+ ...chatMessageProjectConditions(handle, projectId2)
131160
+ ));
131161
+ await handle.update(project_exports.chatSessions).set({ updatedAt: (/* @__PURE__ */ new Date()).toISOString() }).where(and(
131162
+ eq(project_exports.chatSessions.id, existing.sessionId),
131163
+ projectScopeFor(project_exports.chatSessions.projectId, projectId2)
131164
+ ));
130931
131165
  return true;
130932
131166
  }
130933
- async function searchChatSessionsByMessageContent(handle, query, sessionIds) {
131167
+ async function searchChatSessionsByMessageContent(handle, query, sessionIds, projectId2) {
130934
131168
  const trimmed = query.trim();
130935
131169
  if (!trimmed || sessionIds.length === 0) return /* @__PURE__ */ new Map();
130936
131170
  const escaped = trimmed.replace(/\\/g, "\\\\").replace(/%/g, "\\%").replace(/_/g, "\\_");
130937
131171
  const rows = await handle.select().from(project_exports.chatMessages).where(and(
130938
131172
  inArray(project_exports.chatMessages.sessionId, sessionIds),
130939
- ilike(project_exports.chatMessages.content, `%${escaped}%`)
131173
+ ilike(project_exports.chatMessages.content, `%${escaped}%`),
131174
+ ...chatMessageProjectConditions(handle, projectId2)
130940
131175
  )).orderBy(
130941
131176
  desc(project_exports.chatMessages.createdAt),
130942
131177
  desc(project_exports.chatMessages.id)
@@ -130950,13 +131185,16 @@ async function searchChatSessionsByMessageContent(handle, query, sessionIds) {
130950
131185
  }
130951
131186
  return result2;
130952
131187
  }
130953
- async function deleteChatMessagesFrom(handle, sessionId, fromMessageId) {
130954
- const orderedRows = await handle.select().from(project_exports.chatMessages).where(eq(project_exports.chatMessages.sessionId, sessionId)).orderBy(
131188
+ async function deleteChatMessagesFrom(handle, sessionId, fromMessageId, projectId2) {
131189
+ const orderedRows = await handle.select().from(project_exports.chatMessages).where(and(
131190
+ eq(project_exports.chatMessages.sessionId, sessionId),
131191
+ ...chatMessageProjectConditions(handle, projectId2)
131192
+ )).orderBy(
130955
131193
  asc(project_exports.chatMessages.createdAt),
130956
131194
  asc(project_exports.chatMessages.id)
130957
131195
  );
130958
131196
  const ordered2 = orderedRows.map(rowToMessage2);
130959
- const target = await getChatMessage(handle, fromMessageId);
131197
+ const target = await getChatMessage(handle, fromMessageId, projectId2);
130960
131198
  if (!target || target.sessionId !== sessionId) {
130961
131199
  return { deletedIds: [], retained: ordered2 };
130962
131200
  }
@@ -130969,19 +131207,28 @@ async function deleteChatMessagesFrom(handle, sessionId, fromMessageId) {
130969
131207
  if (deletedIds.length === 0) {
130970
131208
  return { deletedIds: [], retained };
130971
131209
  }
130972
- await handle.delete(project_exports.chatMessages).where(inArray(project_exports.chatMessages.id, deletedIds));
130973
- await handle.update(project_exports.chatSessions).set({ updatedAt: (/* @__PURE__ */ new Date()).toISOString() }).where(eq(project_exports.chatSessions.id, sessionId));
131210
+ await handle.delete(project_exports.chatMessages).where(and(
131211
+ inArray(project_exports.chatMessages.id, deletedIds),
131212
+ ...chatMessageProjectConditions(handle, projectId2)
131213
+ ));
131214
+ await handle.update(project_exports.chatSessions).set({ updatedAt: (/* @__PURE__ */ new Date()).toISOString() }).where(and(
131215
+ eq(project_exports.chatSessions.id, sessionId),
131216
+ projectScopeFor(project_exports.chatSessions.projectId, projectId2)
131217
+ ));
130974
131218
  return { deletedIds, retained };
130975
131219
  }
130976
- async function updateChatMessageMetadata(handle, messageId, metadata, options) {
130977
- const existing = await getChatMessage(handle, messageId);
131220
+ async function updateChatMessageMetadata(handle, messageId, metadata, options, projectId2) {
131221
+ const existing = await getChatMessage(handle, messageId, projectId2);
130978
131222
  if (!existing) {
130979
131223
  throw new Error(`Message ${messageId} not found`);
130980
131224
  }
130981
131225
  const merge2 = options?.merge !== false;
130982
131226
  const nextMetadata = metadata === null ? merge2 ? existing.metadata : null : merge2 ? { ...existing.metadata ?? {}, ...metadata } : metadata;
130983
- await handle.update(project_exports.chatMessages).set({ metadata: sanitizeJsonbValue(nextMetadata) ?? null }).where(eq(project_exports.chatMessages.id, messageId));
130984
- const updated = await getChatMessage(handle, messageId);
131227
+ await handle.update(project_exports.chatMessages).set({ metadata: sanitizeJsonbValue(nextMetadata) ?? null }).where(and(
131228
+ eq(project_exports.chatMessages.id, messageId),
131229
+ ...chatMessageProjectConditions(handle, projectId2)
131230
+ ));
131231
+ const updated = await getChatMessage(handle, messageId, projectId2);
130985
131232
  if (!updated) {
130986
131233
  throw new Error(`Failed to update message ${messageId}`);
130987
131234
  }
@@ -131363,7 +131610,7 @@ var init_chat_store = __esm({
131363
131610
  attachments: input.attachments,
131364
131611
  createdAt: now
131365
131612
  };
131366
- const created = await addChatMessage(this.asyncLayer.db, message);
131613
+ const created = await addChatMessage(this.asyncLayer.db, message, this.asyncLayer.projectId);
131367
131614
  this.emit("chat:message:added", created);
131368
131615
  return created;
131369
131616
  }
@@ -131371,7 +131618,7 @@ var init_chat_store = __esm({
131371
131618
  * Append a file attachment metadata record to an existing message.
131372
131619
  */
131373
131620
  async addMessageAttachment(sessionId, messageId, attachment) {
131374
- const updated = await addChatMessageAttachment(this.asyncLayer.db, sessionId, messageId, attachment);
131621
+ const updated = await addChatMessageAttachment(this.asyncLayer.db, sessionId, messageId, attachment, this.asyncLayer.projectId);
131375
131622
  this.emit("chat:message:updated", updated);
131376
131623
  return updated;
131377
131624
  }
@@ -131383,7 +131630,7 @@ var init_chat_store = __esm({
131383
131630
  * @returns Array of messages ordered by createdAt ASC (default) or DESC
131384
131631
  */
131385
131632
  async getMessages(sessionId, filter) {
131386
- return getChatMessages(this.asyncLayer.db, sessionId, filter);
131633
+ return getChatMessages(this.asyncLayer.db, sessionId, filter, this.asyncLayer.projectId);
131387
131634
  }
131388
131635
  /**
131389
131636
  * Get a message by ID.
@@ -131392,7 +131639,7 @@ var init_chat_store = __esm({
131392
131639
  * @returns The message, or undefined if not found
131393
131640
  */
131394
131641
  async getMessage(id) {
131395
- return getChatMessage(this.asyncLayer.db, id);
131642
+ return getChatMessage(this.asyncLayer.db, id, this.asyncLayer.projectId);
131396
131643
  }
131397
131644
  /**
131398
131645
  * Get the latest message for each session in the provided list.
@@ -131402,10 +131649,10 @@ var init_chat_store = __esm({
131402
131649
  * @returns Map of sessionId -> latest ChatMessage for that session
131403
131650
  */
131404
131651
  async getLastMessageForSessions(sessionIds) {
131405
- return getLastMessageForSessions(this.asyncLayer.db, sessionIds);
131652
+ return getLastMessageForSessions(this.asyncLayer.db, sessionIds, this.asyncLayer.projectId);
131406
131653
  }
131407
131654
  async hasMessages(sessionId) {
131408
- return (await getChatMessages(this.asyncLayer.db, sessionId, { limit: 1 })).length > 0;
131655
+ return (await getChatMessages(this.asyncLayer.db, sessionId, { limit: 1 }, this.asyncLayer.projectId)).length > 0;
131409
131656
  }
131410
131657
  /**
131411
131658
  * Search sessions by message content (not just title/agentId).
@@ -131433,7 +131680,7 @@ var init_chat_store = __esm({
131433
131680
  if (!trimmed || !sessionIds || sessionIds.length === 0) {
131434
131681
  return /* @__PURE__ */ new Map();
131435
131682
  }
131436
- return searchChatSessionsByMessageContent(this.asyncLayer.db, trimmed, sessionIds);
131683
+ return searchChatSessionsByMessageContent(this.asyncLayer.db, trimmed, sessionIds, this.asyncLayer.projectId);
131437
131684
  }
131438
131685
  /**
131439
131686
  * Delete a message by ID.
@@ -131442,9 +131689,9 @@ var init_chat_store = __esm({
131442
131689
  * @returns true if deleted, false if not found
131443
131690
  */
131444
131691
  async deleteMessage(id) {
131445
- const existing = await getChatMessage(this.asyncLayer.db, id);
131692
+ const existing = await getChatMessage(this.asyncLayer.db, id, this.asyncLayer.projectId);
131446
131693
  if (!existing) return false;
131447
- const deleted = await deleteChatMessage(this.asyncLayer.db, id);
131694
+ const deleted = await deleteChatMessage(this.asyncLayer.db, id, this.asyncLayer.projectId);
131448
131695
  if (deleted) {
131449
131696
  this.emit("chat:message:deleted", id);
131450
131697
  const updatedSession = await this.getSession(existing.sessionId);
@@ -131467,7 +131714,7 @@ var init_chat_store = __esm({
131467
131714
  * @returns deletedIds (in ASC order) and retained messages (pre-edit history, ASC order)
131468
131715
  */
131469
131716
  async deleteMessagesFrom(sessionId, fromMessageId) {
131470
- const result2 = await deleteChatMessagesFrom(this.asyncLayer.db, sessionId, fromMessageId);
131717
+ const result2 = await deleteChatMessagesFrom(this.asyncLayer.db, sessionId, fromMessageId, this.asyncLayer.projectId);
131471
131718
  if (result2.deletedIds.length > 0) {
131472
131719
  for (const id of result2.deletedIds) {
131473
131720
  this.emit("chat:message:deleted", id);
@@ -131485,7 +131732,7 @@ var init_chat_store = __esm({
131485
131732
  * is what lets a later edit rewind losslessly via SessionManager.branch()/resetLeaf().
131486
131733
  */
131487
131734
  async updateMessageMetadata(messageId, metadata, options) {
131488
- const updated = await updateChatMessageMetadata(this.asyncLayer.db, messageId, metadata, options);
131735
+ const updated = await updateChatMessageMetadata(this.asyncLayer.db, messageId, metadata, options, this.asyncLayer.projectId);
131489
131736
  this.emit("chat:message:updated", updated);
131490
131737
  return updated;
131491
131738
  }
@@ -135954,7 +136201,13 @@ var init_gating_classifications = __esm({
135954
136201
  "fn_post_room_message",
135955
136202
  "fn_update_identity",
135956
136203
  "fn_reflect_on_performance",
135957
- "fn_read_evaluations"
136204
+ /*
136205
+ FNXC:ToolGovernance 2026-08-12-22:11:
136206
+ fn_agent_read_evaluations is a subtree-scoped read. Authorization is enforced by
136207
+ the extension tool's getChainOfCommand boundary, not by this action classifier.
136208
+ */
136209
+ "fn_read_evaluations",
136210
+ "fn_agent_read_evaluations"
135958
136211
  ]);
135959
136212
  COORDINATION_EXEMPT_TOOLS = [
135960
136213
  "read",
@@ -136014,6 +136267,8 @@ var init_gating_classifications = __esm({
136014
136267
  "fn_post_room_message",
136015
136268
  "fn_memory_append",
136016
136269
  "fn_read_evaluations",
136270
+ // FNXC:ToolGovernance 2026-08-12-22:11: The manager read is subtree-authorized in extension.ts; follow-up remains absent so it falls back to task_agent_mutation policy.
136271
+ "fn_agent_read_evaluations",
136017
136272
  "fn_update_identity",
136018
136273
  "fn_reflect_on_performance"
136019
136274
  ];
@@ -178003,32 +178258,36 @@ var init_scheduler = __esm({
178003
178258
  const hierarchy = await missionStore.getMissionWithHierarchy(mission.id);
178004
178259
  if (!hierarchy) continue;
178005
178260
  for (const slice of hierarchy.milestones.flatMap((milestone) => milestone.slices).filter((slice2) => slice2.status === "active")) {
178006
- const superseded = await missionStore.reconcileSupersededGeneratedFixFeatures(slice.id);
178007
- fixed += superseded.supersededCount;
178008
- if (superseded.supersededCount > 0) {
178009
- const refreshed = await missionStore.getSlice(slice.id);
178010
- if (refreshed?.status === "complete") {
178011
- await this.onSliceComplete(refreshed);
178012
- continue;
178261
+ try {
178262
+ const superseded = await missionStore.reconcileSupersededGeneratedFixFeatures(slice.id);
178263
+ fixed += superseded.supersededCount;
178264
+ if (superseded.supersededCount > 0) {
178265
+ const refreshed = await missionStore.getSlice(slice.id);
178266
+ if (refreshed?.status === "complete") {
178267
+ await this.onSliceComplete(refreshed);
178268
+ continue;
178269
+ }
178013
178270
  }
178014
- }
178015
- const listFeatures2 = missionStore.listFeatures;
178016
- const features = listFeatures2 ? await listFeatures2(slice.id) : slice.features;
178017
- const supersededFeatureIds = new Set(superseded.featureIds ?? []);
178018
- const autoTriage = mission.autopilotEnabled === true || mission.autoAdvance === true;
178019
- for (const feature of features) {
178020
- if (supersededFeatureIds.has(feature.id) || feature.taskId || !autoTriage || feature.status === "blocked") continue;
178021
- if (feature.status !== "defined" && this.isGeneratedFixFeature(feature)) {
178022
- await missionStore.updateFeature(feature.id, { status: "blocked", loopState: "blocked", taskId: void 0 });
178271
+ const listFeatures2 = missionStore.listFeatures;
178272
+ const features = listFeatures2 ? await listFeatures2.call(missionStore, slice.id) : slice.features;
178273
+ const supersededFeatureIds = new Set(superseded.featureIds ?? []);
178274
+ const autoTriage = mission.autopilotEnabled === true || mission.autoAdvance === true;
178275
+ for (const feature of features) {
178276
+ if (supersededFeatureIds.has(feature.id) || feature.taskId || !autoTriage || feature.status === "blocked") continue;
178277
+ if (feature.status !== "defined" && this.isGeneratedFixFeature(feature)) {
178278
+ await missionStore.updateFeature(feature.id, { status: "blocked", loopState: "blocked", taskId: void 0 });
178279
+ fixed++;
178280
+ continue;
178281
+ }
178282
+ if (feature.status !== "defined" && feature.status !== "triaged" && feature.status !== "in-progress") continue;
178283
+ const ready = feature.status === "defined" ? feature : await missionStore.updateFeature(feature.id, { status: "defined", loopState: "idle", taskId: void 0 });
178284
+ if (ready !== feature) fixed++;
178285
+ const triaged = await missionStore.triageFeature(ready.id);
178023
178286
  fixed++;
178024
- continue;
178287
+ if (triaged.taskId) await this.emitStrandedFeatureTriageAudit(mission.id, slice.id, triaged.id, triaged.taskId);
178025
178288
  }
178026
- if (feature.status !== "defined" && feature.status !== "triaged" && feature.status !== "in-progress") continue;
178027
- const ready = feature.status === "defined" ? feature : await missionStore.updateFeature(feature.id, { status: "defined", loopState: "idle", taskId: void 0 });
178028
- if (ready !== feature) fixed++;
178029
- const triaged = await missionStore.triageFeature(ready.id);
178030
- fixed++;
178031
- if (triaged.taskId) await this.emitStrandedFeatureTriageAudit(mission.id, slice.id, triaged.id, triaged.taskId);
178289
+ } catch (error3) {
178290
+ schedulerLog.error(`Error during active mission recovery reconciliation for slice ${slice.id}:`, error3);
178032
178291
  }
178033
178292
  }
178034
178293
  }
@@ -312361,6 +312620,50 @@ async function getAgentStore(cwd) {
312361
312620
  const projectStore = await getStore(cwd);
312362
312621
  return new AgentStore({ rootDir: getFusionDir(cwd), asyncLayer: requireProjectLayer(projectStore, "CLI AgentStore") });
312363
312622
  }
312623
+ async function resolveManagerEvaluationTarget(agentStore, agentId, ctx) {
312624
+ const target = await agentStore.resolveAgent(agentId);
312625
+ if (!target) {
312626
+ return {
312627
+ kind: "error",
312628
+ response: {
312629
+ content: [{ type: "text", text: `Agent '${agentId}' not found` }],
312630
+ isError: true,
312631
+ details: { outcome: "not_found", error: "Agent not found", agentId }
312632
+ }
312633
+ };
312634
+ }
312635
+ if (isEphemeralAgent(target)) {
312636
+ return {
312637
+ kind: "error",
312638
+ response: {
312639
+ content: [{ type: "text", text: `ERROR: Cannot evaluate ephemeral/runtime agent ${target.id}` }],
312640
+ isError: true,
312641
+ details: { outcome: "invalid", field: "agent_id", agentId: target.id }
312642
+ }
312643
+ };
312644
+ }
312645
+ const callerAgentId = typeof ctx.agentId === "string" && ctx.agentId ? ctx.agentId : void 0;
312646
+ if (callerAgentId) {
312647
+ const chain = await agentStore.getChainOfCommand(target.id);
312648
+ const callerIndex = chain.findIndex((agent) => agent.id === callerAgentId);
312649
+ if (callerAgentId === target.id || callerIndex < 1) {
312650
+ return {
312651
+ kind: "error",
312652
+ response: {
312653
+ content: [{ type: "text", text: "ERROR: You can only access evaluations for your own direct or indirect reports." }],
312654
+ isError: true,
312655
+ details: {
312656
+ outcome: "denied",
312657
+ agentId: target.id,
312658
+ callerAgentId,
312659
+ rule: "direct-or-indirect-reports-only"
312660
+ }
312661
+ }
312662
+ };
312663
+ }
312664
+ }
312665
+ return { kind: "allowed", target, callerAgentId };
312666
+ }
312364
312667
  function emitSecretAudit(store, ctx, mutationType, target, metadata) {
312365
312668
  if (!ctx.runId || !ctx.agentId) return;
312366
312669
  try {
@@ -316433,6 +316736,143 @@ Status: ${updated.status}`
316433
316736
  };
316434
316737
  }
316435
316738
  });
316739
+ pi2.registerTool({
316740
+ name: "fn_agent_read_evaluations",
316741
+ label: "fn: Read Report Evaluations",
316742
+ description: "Read ratings, feedback, reflections, and performance data for a direct or indirect report.",
316743
+ promptSnippet: "Review evaluation and reflection results for an agent in your management subtree",
316744
+ promptGuidelines: [
316745
+ "Use to review evaluation data for a direct or indirect report in your management subtree",
316746
+ "Agent callers cannot target themselves, peers, ancestors, or agents outside their subtree",
316747
+ "Operator and CLI calls are privileged and may read any durable agent"
316748
+ ],
316749
+ parameters: Type12.Object({
316750
+ agent_id: Type12.String({ description: "Target agent ID or resolvable name" }),
316751
+ rating_limit: Type12.Optional(Type12.Number({ minimum: 1, maximum: 50, description: "Maximum ratings to return (default 10)" })),
316752
+ reflection_limit: Type12.Optional(Type12.Number({ minimum: 1, maximum: 20, description: "Maximum reflections to return (default 5)" }))
316753
+ }),
316754
+ async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
316755
+ const agentStore = await getAgentStore(ctx.cwd);
316756
+ await agentStore.init();
316757
+ const resolved = await resolveManagerEvaluationTarget(agentStore, params.agent_id, ctx);
316758
+ if (resolved.kind === "error") return resolved.response;
316759
+ const ratingLimit = params.rating_limit ?? 10;
316760
+ const reflectionLimit = params.reflection_limit ?? 5;
316761
+ const reflectionStore = new ReflectionStore({ rootDir: getFusionDir(ctx.cwd) });
316762
+ await reflectionStore.init();
316763
+ const [summary, ratings, latestReflection, reflections, performance4] = await Promise.all([
316764
+ agentStore.getRatingSummary(resolved.target.id),
316765
+ agentStore.getRatings(resolved.target.id, { limit: ratingLimit }),
316766
+ reflectionStore.getLatestReflection(resolved.target.id),
316767
+ reflectionStore.getReflections(resolved.target.id, reflectionLimit),
316768
+ reflectionStore.getPerformanceSummary(resolved.target.id)
316769
+ ]);
316770
+ const hasRatings = ratings.length > 0 || summary.totalRatings > 0;
316771
+ const hasReflections = Boolean(latestReflection) || reflections.length > 0;
316772
+ if (!hasRatings && !hasReflections) {
316773
+ return {
316774
+ content: [{ type: "text", text: `${resolved.target.name} (${resolved.target.id})
316775
+
316776
+ No evaluation data available yet.` }],
316777
+ details: { outcome: "empty", agentId: resolved.target.id, agentName: resolved.target.name, summary, ratings, reflections, latestReflection, performance: performance4 }
316778
+ };
316779
+ }
316780
+ const formatScore2 = (score) => typeof score === "number" && Number.isFinite(score) ? score.toFixed(2) : "n/a";
316781
+ const lines = [
316782
+ `Evaluation Summary: ${resolved.target.name} (${resolved.target.id})`,
316783
+ `- Average score: ${formatScore2(summary.averageScore)}`,
316784
+ `- Trend: ${summary.trend}`,
316785
+ `- Total ratings: ${summary.totalRatings}`
316786
+ ];
316787
+ const categoryEntries = Object.entries(summary.categoryAverages ?? {});
316788
+ if (categoryEntries.length > 0) {
316789
+ lines.push("", "Category averages:");
316790
+ categoryEntries.forEach(([category, score]) => lines.push(`- ${category}: ${formatScore2(score)}`));
316791
+ }
316792
+ const commentedRatings = ratings.filter((rating) => rating.comment?.trim());
316793
+ if (commentedRatings.length > 0) {
316794
+ lines.push("", "Recent rating comments:");
316795
+ commentedRatings.slice(0, 5).forEach((rating) => lines.push(`- [${rating.score}/5] ${rating.comment.trim()}`));
316796
+ }
316797
+ if (latestReflection) {
316798
+ lines.push("", "Latest reflection:", `- Summary: ${latestReflection.summary}`);
316799
+ if (latestReflection.insights.length > 0) {
316800
+ lines.push("- Insights:");
316801
+ latestReflection.insights.forEach((insight) => lines.push(` - ${insight}`));
316802
+ }
316803
+ if (latestReflection.suggestedImprovements.length > 0) {
316804
+ lines.push("- Suggested improvements:");
316805
+ latestReflection.suggestedImprovements.forEach((item) => lines.push(` - ${item}`));
316806
+ }
316807
+ }
316808
+ if (reflections.length > 0) {
316809
+ lines.push("", "Recent reflection history:");
316810
+ reflections.slice(0, 5).forEach((reflection) => lines.push(`- ${reflection.timestamp}: ${reflection.summary}`));
316811
+ }
316812
+ return {
316813
+ content: [{ type: "text", text: lines.join("\n") }],
316814
+ details: { outcome: "read", agentId: resolved.target.id, agentName: resolved.target.name, summary, ratings, reflections, latestReflection, performance: performance4 }
316815
+ };
316816
+ }
316817
+ });
316818
+ pi2.registerTool({
316819
+ name: "fn_agent_evaluation_followup",
316820
+ label: "fn: Record Evaluation Follow-up",
316821
+ description: "Record a coaching evaluation follow-up for a direct or indirect report to read through its self-improvement loop.",
316822
+ promptSnippet: "Record coaching feedback for an agent in your management subtree",
316823
+ promptGuidelines: [
316824
+ "Use to record actionable coaching feedback for a direct or indirect report",
316825
+ "Agent callers cannot target themselves, peers, ancestors, or agents outside their subtree",
316826
+ "Create or delegate separate implementation work with fn_task_create or fn_delegate_task"
316827
+ ],
316828
+ parameters: Type12.Object({
316829
+ agent_id: Type12.String({ description: "Target agent ID or resolvable name" }),
316830
+ score: Type12.Number({ minimum: 1, maximum: 5, description: "Evaluation score from 1 to 5" }),
316831
+ comment: Type12.String({ minLength: 1, maxLength: 4e3, description: "Coaching or follow-up note" }),
316832
+ category: Type12.Optional(Type12.String({ maxLength: 100, description: "Optional evaluation category" })),
316833
+ task_id: Type12.Optional(Type12.String({ description: "Optional related task ID" }))
316834
+ }),
316835
+ async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
316836
+ const gated = await applyAgentPolicyGateForExtensionTool(
316837
+ "fn_agent_evaluation_followup",
316838
+ params,
316839
+ ctx
316840
+ );
316841
+ if (gated) return gated;
316842
+ const agentStore = await getAgentStore(ctx.cwd);
316843
+ await agentStore.init();
316844
+ const resolved = await resolveManagerEvaluationTarget(agentStore, params.agent_id, ctx);
316845
+ if (resolved.kind === "error") return resolved.response;
316846
+ if (!Number.isFinite(params.score) || params.score < 1 || params.score > 5) {
316847
+ return {
316848
+ content: [{ type: "text", text: "ERROR: score must be a finite value from 1 to 5" }],
316849
+ isError: true,
316850
+ details: { outcome: "invalid", field: "score" }
316851
+ };
316852
+ }
316853
+ const comment = params.comment.trim();
316854
+ if (!comment) {
316855
+ return {
316856
+ content: [{ type: "text", text: "ERROR: comment must not be empty" }],
316857
+ isError: true,
316858
+ details: { outcome: "invalid", field: "comment" }
316859
+ };
316860
+ }
316861
+ const raterType = resolved.callerAgentId ? "agent" : "user";
316862
+ const rating = await agentStore.addRating(resolved.target.id, {
316863
+ raterType,
316864
+ ...resolved.callerAgentId ? { raterId: resolved.callerAgentId } : {},
316865
+ score: params.score,
316866
+ ...params.category !== void 0 ? { category: params.category } : {},
316867
+ comment,
316868
+ ...params.task_id !== void 0 ? { taskId: params.task_id } : {}
316869
+ });
316870
+ return {
316871
+ content: [{ type: "text", text: `Recorded evaluation follow-up for ${resolved.target.name} (${resolved.target.id}).` }],
316872
+ details: { outcome: "recorded", agentId: resolved.target.id, ratingId: rating.id, score: rating.score, raterType }
316873
+ };
316874
+ }
316875
+ });
316436
316876
  pi2.registerTool({
316437
316877
  name: "fn_agent_delete",
316438
316878
  label: "fn: Delete Agent",