@runfusion/fusion 0.76.0-beta.1 → 0.76.0-beta.3
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.
- package/dist/bin.js +826 -272
- package/dist/child-process-worker.js +740 -249
- package/dist/client/.vite/manifest.json +261 -261
- package/dist/client/assets/{AgentDetailView-Cbl1sw6i.js → AgentDetailView-T767kKTg.js} +1 -1
- package/dist/client/assets/{AgentPermissionPolicyEditor-DD1U5M9p.js → AgentPermissionPolicyEditor--u9jyUf2.js} +1 -1
- package/dist/client/assets/{AgentsView-BMcCbple.js → AgentsView-6Ifu7qDr.js} +5 -5
- package/dist/client/assets/ChatView-BV3lixQi.js +13 -0
- package/dist/client/assets/{CommandCenter-D7mcD61V.js → CommandCenter-CSRYoveB.js} +1 -1
- package/dist/client/assets/{DevServerView-DaqCn0p5.js → DevServerView-B9So_oYx.js} +1 -1
- package/dist/client/assets/{DirectoryPicker-CLdqqqYN.js → DirectoryPicker-BhyDL_2m.js} +1 -1
- package/dist/client/assets/{DocumentsView-BOROVxPm.js → DocumentsView-pbERA7O-.js} +1 -1
- package/dist/client/assets/{EvalsView-BQMXRUlQ.js → EvalsView-DJQ4ltCg.js} +1 -1
- package/dist/client/assets/{ExperimentalAgentOnboardingModal-1GNeCIQT.js → ExperimentalAgentOnboardingModal-BwJuzkzB.js} +1 -1
- package/dist/client/assets/{GoalsView-Cr3c_2GC.js → GoalsView-B6X5_0Ve.js} +1 -1
- package/dist/client/assets/InsightsView-CJgI0J7S.js +11 -0
- package/dist/client/assets/{InsightsView-Gn5lOBA0.css → InsightsView-DAAXuX4v.css} +1 -1
- package/dist/client/assets/{MemoryView-C0VzzMSw.js → MemoryView-BHq1AHPu.js} +1 -1
- package/dist/client/assets/{PiExtensionsManager-D1kkkVtP.js → PiExtensionsManager-B8At6fO8.js} +1 -1
- package/dist/client/assets/{PluginManager-BW-_Zyo5.js → PluginManager-k7hV7_9e.js} +1 -1
- package/dist/client/assets/{PullRequestView-Cmlo4nWA.js → PullRequestView-B1hZFrWo.js} +1 -1
- package/dist/client/assets/{ReportModal-BWuaroTF.js → ReportModal-C46V_zEa.js} +1 -1
- package/dist/client/assets/{ResearchView-BmkF_vZU.js → ResearchView-D8G85BYN.js} +2 -2
- package/dist/client/assets/{SecretsView-DVc8Hky0.js → SecretsView-CTri9LRK.js} +1 -1
- package/dist/client/assets/{SessionTerminal-DCXrxA57.js → SessionTerminal-BRf6r4Vp.js} +1 -1
- package/dist/client/assets/SettingsModal-D0RBeZik.js +21 -0
- package/dist/client/assets/{SettingsModal-DqwpLnDU.js → SettingsModal-rUQcSTJp.js} +1 -1
- package/dist/client/assets/{SettingsTextareaRow-B5spAoOY.js → SettingsTextareaRow-BirlBcem.js} +1 -1
- package/dist/client/assets/{SetupWizardModal-VTBLyFzr.js → SetupWizardModal-xnCBM9EL.js} +2 -2
- package/dist/client/assets/{SkillsView-CR91ey9d.js → SkillsView-O5U0ep50.js} +1 -1
- package/dist/client/assets/{WorkflowNodeEditor-BzGh_Fd9.js → WorkflowNodeEditor-BX4d2qqF.js} +3 -3
- package/dist/client/assets/{agent-import-generation-D27NKQsr.js → agent-import-generation-DnqVkPkz.js} +1 -1
- package/dist/client/assets/{agentsOrgChartLayout-C2K_M3x3.js → agentsOrgChartLayout-CKuzbhFf.js} +1 -1
- package/dist/client/assets/app-B2FwULu2.js +5 -0
- package/dist/client/assets/{app-BA9gw9hx.js → app-B6nJaqAl.js} +2 -2
- package/dist/client/assets/{app-B_lScKc1.js → app-CGXZeIRc.js} +2 -2
- package/dist/client/assets/{app-DG_vjDw5.js → app-CGtkeBF5.js} +3 -3
- package/dist/client/assets/{app-GBgoY-oh.js → app-CNzN1Plu.js} +2 -2
- package/dist/client/assets/{app-B0KFGP8D.js → app-DLs-f5yM.js} +3 -3
- package/dist/client/assets/{app-DeHIOCEP.js → app-DsvtcRUG.js} +2 -2
- package/dist/client/assets/{architectureDiagram-3BPJPVTR-BQy8UcRx.js → architectureDiagram-3BPJPVTR-gi467xY0.js} +1 -1
- package/dist/client/assets/{blockDiagram-GPEHLZMM-CZG1bqFQ.js → blockDiagram-GPEHLZMM-B_gpcYiR.js} +1 -1
- package/dist/client/assets/{c4Diagram-AAUBKEIU-CZmO_kg3.js → c4Diagram-AAUBKEIU-DeylEYsQ.js} +1 -1
- package/dist/client/assets/channel-BoE8DeM4.js +1 -0
- package/dist/client/assets/{chunk-2J33WTMH-jsad6DTE.js → chunk-2J33WTMH-BL2WY0HN.js} +1 -1
- package/dist/client/assets/{chunk-4BX2VUAB-DX7SuvwP.js → chunk-4BX2VUAB-BkLExGMe.js} +1 -1
- package/dist/client/assets/{chunk-55IACEB6-De20xFgU.js → chunk-55IACEB6-CSTvCF5T.js} +1 -1
- package/dist/client/assets/{chunk-727SXJPM-CNiri9yW.js → chunk-727SXJPM-9J8pKk4x.js} +1 -1
- package/dist/client/assets/{chunk-AQP2D5EJ-DvDqG-ax.js → chunk-AQP2D5EJ-DXC1vPWr.js} +1 -1
- package/dist/client/assets/{chunk-FMBD7UC4-DkMdKaUq.js → chunk-FMBD7UC4-CFRUb-zD.js} +1 -1
- package/dist/client/assets/{chunk-ND2GUHAM-Do5BwIrI.js → chunk-ND2GUHAM-B87HFYS8.js} +1 -1
- package/dist/client/assets/{chunk-QZHKN3VN-BnJgt9vl.js → chunk-QZHKN3VN-CTjHiGbd.js} +1 -1
- package/dist/client/assets/classDiagram-4FO5ZUOK-qnbLX_9_.js +1 -0
- package/dist/client/assets/classDiagram-v2-Q7XG4LA2-qnbLX_9_.js +1 -0
- package/dist/client/assets/{cose-bilkent-S5V4N54A-D-ivAzzF.js → cose-bilkent-S5V4N54A-D3Edq3L9.js} +1 -1
- package/dist/client/assets/{dagre-BM42HDAG-Bpd9L0or.js → dagre-BM42HDAG-CwwbeQfN.js} +1 -1
- package/dist/client/assets/{dashboard-view-CgBo8Ctn.js → dashboard-view-BLAoW3D4.js} +1 -1
- package/dist/client/assets/{dashboard-view-DbaRE8Ma.js → dashboard-view-DAlJxqiJ.js} +1 -1
- package/dist/client/assets/{dashboard-view-DSvVO6Vr.js → dashboard-view-QxQwJFLz.js} +1 -1
- package/dist/client/assets/{dashboard-view-C-XU9CVv.js → dashboard-view-aPzfv99T.js} +1 -1
- package/dist/client/assets/{diagram-2AECGRRQ-B6TT1NWU.js → diagram-2AECGRRQ-koJWWXE4.js} +1 -1
- package/dist/client/assets/{diagram-5GNKFQAL-DpRS2yRw.js → diagram-5GNKFQAL-Yob5cOKT.js} +1 -1
- package/dist/client/assets/{diagram-KO2AKTUF-BVbZr02C.js → diagram-KO2AKTUF-DelvFSkK.js} +1 -1
- package/dist/client/assets/{diagram-LMA3HP47-DzENbfal.js → diagram-LMA3HP47-CMput2h2.js} +1 -1
- package/dist/client/assets/{diagram-OG6HWLK6-BIePG5SY.js → diagram-OG6HWLK6-04VXDl79.js} +1 -1
- package/dist/client/assets/{erDiagram-TEJ5UH35-CQo3WBwo.js → erDiagram-TEJ5UH35-C9iP8Uyp.js} +1 -1
- package/dist/client/assets/{flowDiagram-I6XJVG4X-Ct2H4jYo.js → flowDiagram-I6XJVG4X-DENQvu_t.js} +1 -1
- package/dist/client/assets/{folder-open-DAh8mpTX.js → folder-open-D-554oji.js} +1 -1
- package/dist/client/assets/{ganttDiagram-6RSMTGT7-DyOLCG4B.js → ganttDiagram-6RSMTGT7-BqOttZAT.js} +1 -1
- package/dist/client/assets/{gitGraphDiagram-PVQCEYII-sC28-su3.js → gitGraphDiagram-PVQCEYII-CDcydi-5.js} +1 -1
- package/dist/client/assets/{index-BzAldNrK.css → index-CXTd3LAB.css} +1 -1
- package/dist/client/assets/index-CtYRoouR.js +2818 -0
- package/dist/client/assets/{infoDiagram-5YYISTIA-Q81_5aBZ.js → infoDiagram-5YYISTIA-B5LQQnxt.js} +1 -1
- package/dist/client/assets/{ishikawaDiagram-YF4QCWOH-Cwkjs0z5.js → ishikawaDiagram-YF4QCWOH-DpFEt7D2.js} +1 -1
- package/dist/client/assets/{journeyDiagram-JHISSGLW-BXcBV1Bc.js → journeyDiagram-JHISSGLW-MELtgu22.js} +1 -1
- package/dist/client/assets/{kanban-definition-UN3LZRKU-BI7hW892.js → kanban-definition-UN3LZRKU-h33PLATd.js} +1 -1
- package/dist/client/assets/{mermaid.core-B8oDA6jj.js → mermaid.core-Dk2mUPOq.js} +4 -4
- package/dist/client/assets/{mindmap-definition-RKZ34NQL-COG6_9eD.js → mindmap-definition-RKZ34NQL-B_T4O2-B.js} +1 -1
- package/dist/client/assets/{pieDiagram-4H26LBE5-D11brZ_N.js → pieDiagram-4H26LBE5-B1YIFkRl.js} +1 -1
- package/dist/client/assets/{puzzle-D3_Z_rlW.js → puzzle-hvecxlpJ.js} +1 -1
- package/dist/client/assets/{quadrantDiagram-W4KKPZXB-jmhDVZcv.js → quadrantDiagram-W4KKPZXB-BoGQR_hO.js} +1 -1
- package/dist/client/assets/{requirementDiagram-4Y6WPE33-BKCUWI1E.js → requirementDiagram-4Y6WPE33-BSDmUBIx.js} +1 -1
- package/dist/client/assets/{sankeyDiagram-5OEKKPKP-HsZdEl2t.js → sankeyDiagram-5OEKKPKP-Dz_GqOa5.js} +1 -1
- package/dist/client/assets/{sequenceDiagram-3UESZ5HK-CsDf7Fup.js → sequenceDiagram-3UESZ5HK-B6twjYUH.js} +1 -1
- package/dist/client/assets/{shield-alert-C16k8wNu.js → shield-alert-BX4WRJOv.js} +1 -1
- package/dist/client/assets/{standing-instructions-template-BqAyftqe.js → standing-instructions-template-BJY317CC.js} +1 -1
- package/dist/client/assets/{stateDiagram-AJRCARHV-fvzWhltB.js → stateDiagram-AJRCARHV-DuwqWLx-.js} +1 -1
- package/dist/client/assets/{stateDiagram-v2-BHNVJYJU-cnt42Sr_.js → stateDiagram-v2-BHNVJYJU-Bu8Sk187.js} +1 -1
- package/dist/client/assets/{timeline-definition-PNZ67QCA-DsZFCSMb.js → timeline-definition-PNZ67QCA-BS6VnqSI.js} +1 -1
- package/dist/client/assets/{upload-_s5sL5Pq.js → upload-CaDoyaMW.js} +1 -1
- package/dist/client/assets/{users-DH1U5ISc.js → users-C5uCLwVM.js} +1 -1
- package/dist/client/assets/{vennDiagram-CIIHVFJN-B3KDWS-e.js → vennDiagram-CIIHVFJN-CUbzqT5Y.js} +1 -1
- package/dist/client/assets/{wardley-L42UT6IY-BKs5MtQS.js → wardley-L42UT6IY-Mv-NotFS.js} +1 -1
- package/dist/client/assets/{wardleyDiagram-YWT4CUSO-CNsEoXVB.js → wardleyDiagram-YWT4CUSO-DuYpvLZX.js} +1 -1
- package/dist/client/assets/{xychartDiagram-2RQKCTM6-kq_gW4QC.js → xychartDiagram-2RQKCTM6-24_7QXdw.js} +1 -1
- package/dist/client/index.html +2 -2
- package/dist/client/version.json +1 -1
- package/dist/droid-cli/package.json +1 -1
- package/dist/extension.js +932 -254
- package/dist/migrations/0057_fn_9004_project_ownership_default_reconciliation.sql +13 -0
- package/dist/migrations/0058_fn_9014_message_archive.sql +13 -0
- package/dist/pi-claude-cli/package.json +5 -5
- package/dist/plugin-sdk/index.d.ts +23 -0
- package/dist/plugin-sdk/index.js +71 -23
- package/dist/plugins/fusion-plugin-acp-runtime/bundled.js +71 -23
- package/dist/plugins/fusion-plugin-acp-runtime/package.json +1 -1
- package/dist/plugins/fusion-plugin-claude-runtime/bundled.js +71 -23
- package/dist/plugins/fusion-plugin-claude-runtime/package.json +1 -1
- package/dist/plugins/fusion-plugin-cli-printing-press/bundled.js +71 -23
- package/dist/plugins/fusion-plugin-cli-printing-press/package.json +1 -1
- package/dist/plugins/fusion-plugin-compound-engineering/bundled.js +71 -23
- package/dist/plugins/fusion-plugin-compound-engineering/package.json +1 -1
- package/dist/plugins/fusion-plugin-cursor-runtime/bundled.js +71 -23
- package/dist/plugins/fusion-plugin-cursor-runtime/package.json +1 -1
- package/dist/plugins/fusion-plugin-dependency-graph/bundled.js +71 -23
- package/dist/plugins/fusion-plugin-dependency-graph/package.json +1 -1
- package/dist/plugins/fusion-plugin-droid-runtime/bundled.js +73 -25
- package/dist/plugins/fusion-plugin-droid-runtime/package.json +1 -1
- package/dist/plugins/fusion-plugin-grok-runtime/bundled.js +71 -23
- package/dist/plugins/fusion-plugin-grok-runtime/package.json +1 -1
- package/dist/plugins/fusion-plugin-hermes-runtime/bundled.js +71 -23
- package/dist/plugins/fusion-plugin-hermes-runtime/package.json +1 -1
- package/dist/plugins/fusion-plugin-linear-import/bundled.js +71 -23
- package/dist/plugins/fusion-plugin-linear-import/package.json +1 -1
- package/dist/plugins/fusion-plugin-omp-runtime/bundled.js +71 -23
- package/dist/plugins/fusion-plugin-omp-runtime/package.json +1 -1
- package/dist/plugins/fusion-plugin-openclaw-runtime/bundled.js +71 -23
- package/dist/plugins/fusion-plugin-openclaw-runtime/package.json +1 -1
- package/dist/plugins/fusion-plugin-paperclip-runtime/bundled.js +71 -23
- package/dist/plugins/fusion-plugin-paperclip-runtime/package.json +1 -1
- package/dist/plugins/fusion-plugin-quality/bundled.js +71 -23
- package/dist/plugins/fusion-plugin-quality/package.json +1 -1
- package/dist/plugins/fusion-plugin-reports/bundled.js +71 -23
- package/dist/plugins/fusion-plugin-reports/package.json +1 -1
- package/dist/plugins/fusion-plugin-roadmap/bundled.js +71 -23
- package/dist/plugins/fusion-plugin-roadmap/package.json +1 -1
- package/dist/plugins/fusion-plugin-todos/bundled.js +71 -23
- package/dist/plugins/fusion-plugin-todos/package.json +1 -1
- package/dist/plugins/fusion-plugin-whatsapp-chat/bundled.js +71 -23
- package/dist/plugins/fusion-plugin-whatsapp-chat/package.json +1 -1
- package/package.json +3 -3
- package/skill/fusion/SKILL.md +1 -1
- package/skill/fusion/references/extension-tools.md +22 -0
- package/skill/fusion/references/fusion-capabilities.md +2 -0
- package/dist/client/assets/ChatView-DcM-ARpZ.js +0 -13
- package/dist/client/assets/InsightsView-DgVBVQM4.js +0 -11
- package/dist/client/assets/SettingsModal-DZ32F1c-.js +0 -21
- package/dist/client/assets/app-DBCGrz-f.js +0 -5
- package/dist/client/assets/channel-Cwl9FefC.js +0 -1
- package/dist/client/assets/classDiagram-4FO5ZUOK-BZtWCoHC.js +0 -1
- package/dist/client/assets/classDiagram-v2-Q7XG4LA2-BZtWCoHC.js +0 -1
- package/dist/client/assets/index-BlGpMJSZ.js +0 -2818
package/dist/extension.js
CHANGED
|
@@ -2067,6 +2067,8 @@ var init_settings_schema = __esm({
|
|
|
2067
2067
|
DEFAULT_PROJECT_SETTINGS = {
|
|
2068
2068
|
// FNXC:TaskRecommendations 2026-08-08-05:02: completion follows-ups stay bounded by default; 0 disables writing them.
|
|
2069
2069
|
maxRecommendationsPerTask: 3,
|
|
2070
|
+
// FNXC:TaskRecommendations 2026-08-13-03:56: surface completed-task proposals by default; operators can suppress the notice without suppressing capture.
|
|
2071
|
+
recommendationMailboxNoticeEnabled: true,
|
|
2070
2072
|
globalPause: false,
|
|
2071
2073
|
globalPauseReason: void 0,
|
|
2072
2074
|
defaultWorkflowId: void 0,
|
|
@@ -21639,9 +21641,14 @@ var init_project = __esm({
|
|
|
21639
21641
|
// now keyed per-project on `project_id` (the effective PK). `id` is retained
|
|
21640
21642
|
// for column-shape parity (always 1) but is no longer the PK and no longer
|
|
21641
21643
|
// CHECK-constrained. Single-project / SQLite-parity callers leave project_id
|
|
21642
|
-
//
|
|
21644
|
+
// through the database ownership trigger, preserving the pre-isolation behavior.
|
|
21645
|
+
/*
|
|
21646
|
+
FNXC:MultiProjectIsolation 2026-08-12-15:43:
|
|
21647
|
+
Migration 0006 owns config's project_id default and leaves its catalog PK as (project_id).
|
|
21648
|
+
Drizzle emits DEFAULT while the database GUC/trigger selects the effective ownership partition.
|
|
21649
|
+
*/
|
|
21643
21650
|
id: integer("id").default(1),
|
|
21644
|
-
projectId: text("project_id").notNull().default(
|
|
21651
|
+
projectId: text("project_id").notNull().default(sql`current_setting('fusion.project_id', true)`).primaryKey(),
|
|
21645
21652
|
nextId: integer("next_id").default(1),
|
|
21646
21653
|
nextWorkflowStepId: integer("next_workflow_step_id").default(1),
|
|
21647
21654
|
// FNXC:SqliteFinalRemoval 2026-06-28:
|
|
@@ -22035,9 +22042,13 @@ var init_project = __esm({
|
|
|
22035
22042
|
automations = projectSchema.table("automations", {
|
|
22036
22043
|
/*
|
|
22037
22044
|
* 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.
|
|
22045
|
+
* 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.
|
|
22046
|
+
*
|
|
22047
|
+
* FNXC:MultiProjectIsolation 2026-08-12-15:43:
|
|
22048
|
+
* Migration 0006 owns the default through the database GUC/trigger; Drizzle emits DEFAULT
|
|
22049
|
+
* without replacing the physical legacy fallback or the fail-closed bound writer contract.
|
|
22039
22050
|
*/
|
|
22040
|
-
projectId: text("project_id").notNull().default(
|
|
22051
|
+
projectId: text("project_id").notNull().default(sql`current_setting('fusion.project_id', true)`),
|
|
22041
22052
|
id: text("id").notNull(),
|
|
22042
22053
|
name: text("name").notNull(),
|
|
22043
22054
|
description: text("description"),
|
|
@@ -22336,7 +22347,8 @@ var init_project = __esm({
|
|
|
22336
22347
|
index("idxTaskDocumentsTaskId").on(t.taskId)
|
|
22337
22348
|
]);
|
|
22338
22349
|
artifacts = projectSchema.table("artifacts", {
|
|
22339
|
-
|
|
22350
|
+
projectId: text("project_id").notNull().default(sql`current_setting('fusion.project_id', true)`),
|
|
22351
|
+
id: text("id").notNull(),
|
|
22340
22352
|
type: text("type").notNull(),
|
|
22341
22353
|
title: text("title").notNull(),
|
|
22342
22354
|
description: text("description"),
|
|
@@ -22351,7 +22363,8 @@ var init_project = __esm({
|
|
|
22351
22363
|
createdAt: text("created_at").notNull(),
|
|
22352
22364
|
updatedAt: text("updated_at").notNull()
|
|
22353
22365
|
}, (t) => [
|
|
22354
|
-
|
|
22366
|
+
primaryKey({ columns: [t.projectId, t.id] }),
|
|
22367
|
+
foreignKey({ name: "artifacts_task_id_fkey", columns: [t.projectId, t.taskId], foreignColumns: [tasks.projectId, tasks.id] }).onDelete("cascade"),
|
|
22355
22368
|
index("idxArtifactsTaskId").on(t.taskId),
|
|
22356
22369
|
index("idxArtifactsAuthorId").on(t.authorId),
|
|
22357
22370
|
index("idxArtifactsType").on(t.type),
|
|
@@ -22541,7 +22554,8 @@ var init_project = __esm({
|
|
|
22541
22554
|
index("idxEvalRunEventsRunIdSeq").on(t.runId, t.seq)
|
|
22542
22555
|
]);
|
|
22543
22556
|
secrets = projectSchema.table("secrets", {
|
|
22544
|
-
|
|
22557
|
+
projectId: text("project_id").notNull().default(sql`current_setting('fusion.project_id', true)`),
|
|
22558
|
+
id: text("id").notNull(),
|
|
22545
22559
|
key: text("key").notNull(),
|
|
22546
22560
|
valueCiphertext: bytea("value_ciphertext").notNull(),
|
|
22547
22561
|
nonce: bytea("nonce").notNull(),
|
|
@@ -22554,7 +22568,8 @@ var init_project = __esm({
|
|
|
22554
22568
|
lastReadAt: text("last_read_at"),
|
|
22555
22569
|
lastReadBy: text("last_read_by")
|
|
22556
22570
|
}, (t) => [
|
|
22557
|
-
|
|
22571
|
+
primaryKey({ columns: [t.projectId, t.id] }),
|
|
22572
|
+
unique("secrets_key_unique").on(t.projectId, t.key),
|
|
22558
22573
|
check("secrets_access_policy_check", sql`${t.accessPolicy} IN ('auto', 'prompt', 'deny')`),
|
|
22559
22574
|
check("secrets_env_exportable_check", sql`${t.envExportable} IN (0, 1)`)
|
|
22560
22575
|
]);
|
|
@@ -22596,10 +22611,11 @@ var init_project = __esm({
|
|
|
22596
22611
|
updatedAt: text("updated_at").notNull()
|
|
22597
22612
|
}, (t) => [primaryKey({ columns: [t.projectId, t.id] })]);
|
|
22598
22613
|
branchGroups = projectSchema.table("branch_groups", {
|
|
22599
|
-
|
|
22614
|
+
projectId: text("project_id").notNull().default(sql`current_setting('fusion.project_id', true)`),
|
|
22615
|
+
id: text("id").notNull(),
|
|
22600
22616
|
sourceType: text("source_type").notNull(),
|
|
22601
22617
|
sourceId: text("source_id").notNull(),
|
|
22602
|
-
branchName: text("branch_name").notNull()
|
|
22618
|
+
branchName: text("branch_name").notNull(),
|
|
22603
22619
|
worktreePath: text("worktree_path"),
|
|
22604
22620
|
autoMerge: integer("auto_merge").notNull().default(0),
|
|
22605
22621
|
prState: text("pr_state").notNull().default("none"),
|
|
@@ -22615,6 +22631,8 @@ var init_project = __esm({
|
|
|
22615
22631
|
updatedAt: bigint("updated_at", { mode: "number" }).notNull(),
|
|
22616
22632
|
closedAt: bigint("closed_at", { mode: "number" })
|
|
22617
22633
|
}, (t) => [
|
|
22634
|
+
primaryKey({ columns: [t.projectId, t.id] }),
|
|
22635
|
+
unique("branch_groups_branch_name_key").on(t.projectId, t.branchName),
|
|
22618
22636
|
check("branch_groups_source_type_check", sql`${t.sourceType} IN ('mission','planning','new-task')`),
|
|
22619
22637
|
check("branch_groups_pr_state_check", sql`${t.prState} IN ('none','open','merged','closed')`),
|
|
22620
22638
|
check("branch_groups_status_check", sql`${t.status} IN ('open','finalized','abandoned')`),
|
|
@@ -23016,12 +23034,14 @@ var init_project = __esm({
|
|
|
23016
23034
|
index("idxUsageEventsKindTs").on(t.kind, t.ts)
|
|
23017
23035
|
]);
|
|
23018
23036
|
pluginActivations = projectSchema.table("plugin_activations", {
|
|
23019
|
-
|
|
23037
|
+
projectId: text("project_id").notNull().default(sql`current_setting('fusion.project_id', true)`),
|
|
23038
|
+
id: integer("id").generatedAlwaysAsIdentity().notNull(),
|
|
23020
23039
|
pluginId: text("plugin_id").notNull(),
|
|
23021
23040
|
source: text("source").notNull(),
|
|
23022
23041
|
pluginVersion: text("plugin_version"),
|
|
23023
23042
|
activatedAt: text("activated_at").notNull()
|
|
23024
23043
|
}, (t) => [
|
|
23044
|
+
primaryKey({ columns: [t.projectId, t.id] }),
|
|
23025
23045
|
index("idxPluginActivationsActivatedAt").on(t.activatedAt),
|
|
23026
23046
|
index("idxPluginActivationsPluginId").on(t.pluginId)
|
|
23027
23047
|
]);
|
|
@@ -23046,8 +23066,13 @@ var init_project = __esm({
|
|
|
23046
23066
|
index("idxKnowledgePagesUpdatedAt").on(t.updatedAt)
|
|
23047
23067
|
]);
|
|
23048
23068
|
deployments = projectSchema.table("deployments", {
|
|
23049
|
-
id: integer("id").generatedAlwaysAsIdentity().
|
|
23050
|
-
|
|
23069
|
+
id: integer("id").generatedAlwaysAsIdentity().notNull(),
|
|
23070
|
+
/*
|
|
23071
|
+
FNXC:MultiProjectIsolation 2026-08-12-15:43:
|
|
23072
|
+
Migration 0006 rebuilt deployments_pkey as (project_id, id). Drizzle emits DEFAULT while the
|
|
23073
|
+
database GUC/trigger keeps ownership stamping and the physical legacy fallback authoritative.
|
|
23074
|
+
*/
|
|
23075
|
+
projectId: text("project_id").notNull().default(sql`current_setting('fusion.project_id', true)`),
|
|
23051
23076
|
deploymentId: text("deployment_id").notNull(),
|
|
23052
23077
|
service: text("service"),
|
|
23053
23078
|
environment: text("environment"),
|
|
@@ -23058,6 +23083,7 @@ var init_project = __esm({
|
|
|
23058
23083
|
meta: jsonb("meta"),
|
|
23059
23084
|
createdAt: text("created_at").notNull()
|
|
23060
23085
|
}, (t) => [
|
|
23086
|
+
primaryKey({ columns: [t.projectId, t.id], name: "deployments_pkey" }),
|
|
23061
23087
|
uniqueIndex("idxDeploymentsProjectDeploymentId").on(t.projectId, t.deploymentId),
|
|
23062
23088
|
index("idxDeploymentsProjectDeployedAt").on(t.projectId, t.deployedAt),
|
|
23063
23089
|
index("idxDeploymentsDeployedAt").on(t.deployedAt),
|
|
@@ -23065,7 +23091,12 @@ var init_project = __esm({
|
|
|
23065
23091
|
]);
|
|
23066
23092
|
githubCheckStates = projectSchema.table("github_check_states", {
|
|
23067
23093
|
id: integer("id").generatedAlwaysAsIdentity().notNull(),
|
|
23068
|
-
|
|
23094
|
+
/*
|
|
23095
|
+
FNXC:MultiProjectIsolation 2026-08-12-15:43:
|
|
23096
|
+
Migration 0048 post-dated 0006, so FN-9004 reconciles its physical default to the ownership
|
|
23097
|
+
expression. Drizzle emits DEFAULT while the database GUC/trigger remains the stamping authority.
|
|
23098
|
+
*/
|
|
23099
|
+
projectId: text("project_id").notNull().default(sql`current_setting('fusion.project_id', true)`),
|
|
23069
23100
|
repo: text("repo").notNull(),
|
|
23070
23101
|
headSha: text("head_sha").notNull(),
|
|
23071
23102
|
checkName: text("check_name").notNull(),
|
|
@@ -23085,9 +23116,14 @@ var init_project = __esm({
|
|
|
23085
23116
|
index("idxGithubCheckStatesProjectReceived").on(t.projectId, t.receivedAt)
|
|
23086
23117
|
]);
|
|
23087
23118
|
incidents = projectSchema.table("incidents", {
|
|
23088
|
-
id: integer("id").generatedAlwaysAsIdentity().
|
|
23089
|
-
|
|
23090
|
-
|
|
23119
|
+
id: integer("id").generatedAlwaysAsIdentity().notNull(),
|
|
23120
|
+
/*
|
|
23121
|
+
FNXC:MultiProjectIsolation 2026-08-12-15:43:
|
|
23122
|
+
Migration 0006 rebuilt incident keys with project_id first. Drizzle emits DEFAULT while the
|
|
23123
|
+
database GUC/trigger retains ownership stamping and its physical legacy fallback.
|
|
23124
|
+
*/
|
|
23125
|
+
projectId: text("project_id").notNull().default(sql`current_setting('fusion.project_id', true)`),
|
|
23126
|
+
incidentId: text("incident_id").notNull(),
|
|
23091
23127
|
groupingKey: text("grouping_key").notNull(),
|
|
23092
23128
|
title: text("title").notNull(),
|
|
23093
23129
|
severity: text("severity"),
|
|
@@ -23101,6 +23137,8 @@ var init_project = __esm({
|
|
|
23101
23137
|
createdAt: text("created_at").notNull(),
|
|
23102
23138
|
updatedAt: text("updated_at").notNull()
|
|
23103
23139
|
}, (t) => [
|
|
23140
|
+
primaryKey({ columns: [t.projectId, t.id], name: "incidents_pkey" }),
|
|
23141
|
+
unique("incidents_incident_id_key").on(t.projectId, t.incidentId),
|
|
23104
23142
|
index("idxIncidentsProjectOpenedAt").on(t.projectId, t.openedAt),
|
|
23105
23143
|
index("idxIncidentsProjectStatus").on(t.projectId, t.status),
|
|
23106
23144
|
index("idxIncidentsGroupingKey").on(t.groupingKey),
|
|
@@ -23155,12 +23193,14 @@ var init_project = __esm({
|
|
|
23155
23193
|
content: text("content").notNull(),
|
|
23156
23194
|
type: text("type").notNull(),
|
|
23157
23195
|
read: integer("read").default(0),
|
|
23196
|
+
archived: integer("archived").default(0),
|
|
23158
23197
|
metadata: jsonb("metadata"),
|
|
23159
23198
|
createdAt: text("created_at").notNull(),
|
|
23160
23199
|
updatedAt: text("updated_at").notNull()
|
|
23161
23200
|
}, (t) => [
|
|
23162
23201
|
primaryKey({ columns: [t.projectId, t.id] }),
|
|
23163
23202
|
index("idxMessagesTo").on(t.toId, t.toType, t.read),
|
|
23203
|
+
index("idxMessagesToArchived").on(t.toId, t.toType, t.archived),
|
|
23164
23204
|
index("idxMessagesFrom").on(t.fromId, t.fromType),
|
|
23165
23205
|
index("idxMessagesCreatedAt").on(t.createdAt)
|
|
23166
23206
|
]);
|
|
@@ -23261,7 +23301,8 @@ var init_project = __esm({
|
|
|
23261
23301
|
index("idx_cli_sessions_project_state").on(t.projectId, t.agentState)
|
|
23262
23302
|
]);
|
|
23263
23303
|
chatMessages = projectSchema.table("chat_messages", {
|
|
23264
|
-
|
|
23304
|
+
projectId: text("project_id").notNull().default(sql`current_setting('fusion.project_id', true)`),
|
|
23305
|
+
id: text("id").notNull(),
|
|
23265
23306
|
sessionId: text("session_id").notNull(),
|
|
23266
23307
|
role: text("role").notNull(),
|
|
23267
23308
|
content: text("content").notNull(),
|
|
@@ -23270,6 +23311,7 @@ var init_project = __esm({
|
|
|
23270
23311
|
createdAt: text("created_at").notNull(),
|
|
23271
23312
|
attachments: jsonb("attachments")
|
|
23272
23313
|
}, (t) => [
|
|
23314
|
+
primaryKey({ columns: [t.projectId, t.id] }),
|
|
23273
23315
|
index("idxChatMessagesSessionId").on(t.sessionId),
|
|
23274
23316
|
index("idxChatMessagesCreatedAt").on(t.createdAt)
|
|
23275
23317
|
]);
|
|
@@ -23295,7 +23337,8 @@ var init_project = __esm({
|
|
|
23295
23337
|
index("idxChatTokenUsageCreatedAt").on(t.createdAt)
|
|
23296
23338
|
]);
|
|
23297
23339
|
runAuditEvents = projectSchema.table("run_audit_events", {
|
|
23298
|
-
|
|
23340
|
+
projectId: text("project_id").notNull().default(sql`current_setting('fusion.project_id', true)`),
|
|
23341
|
+
id: text("id").notNull(),
|
|
23299
23342
|
timestamp: text("timestamp").notNull(),
|
|
23300
23343
|
taskId: text("task_id"),
|
|
23301
23344
|
agentId: text("agent_id").notNull(),
|
|
@@ -23305,6 +23348,7 @@ var init_project = __esm({
|
|
|
23305
23348
|
target: text("target").notNull(),
|
|
23306
23349
|
metadata: jsonb("metadata")
|
|
23307
23350
|
}, (t) => [
|
|
23351
|
+
primaryKey({ columns: [t.projectId, t.id] }),
|
|
23308
23352
|
index("idxRunAuditEventsRunIdTimestamp").on(t.runId, t.timestamp),
|
|
23309
23353
|
index("idxRunAuditEventsTaskIdTimestamp").on(t.taskId, t.timestamp),
|
|
23310
23354
|
index("idxRunAuditEventsTimestamp").on(t.timestamp)
|
|
@@ -23405,13 +23449,14 @@ var init_project = __esm({
|
|
|
23405
23449
|
index("idxMissionLineageStopsMissionId").on(t.projectId, t.missionId)
|
|
23406
23450
|
]);
|
|
23407
23451
|
verificationCache = projectSchema.table("verification_cache", {
|
|
23452
|
+
projectId: text("project_id").notNull().default(sql`current_setting('fusion.project_id', true)`),
|
|
23408
23453
|
treeSha: text("tree_sha").notNull(),
|
|
23409
23454
|
testCommand: text("test_command").notNull().default(""),
|
|
23410
23455
|
buildCommand: text("build_command").notNull().default(""),
|
|
23411
23456
|
recordedAt: text("recorded_at").notNull(),
|
|
23412
23457
|
taskId: text("task_id")
|
|
23413
23458
|
}, (t) => [
|
|
23414
|
-
primaryKey({ columns: [t.treeSha, t.testCommand, t.buildCommand] }),
|
|
23459
|
+
primaryKey({ columns: [t.projectId, t.treeSha, t.testCommand, t.buildCommand] }),
|
|
23415
23460
|
index("idxVerificationCacheRecordedAt").on(t.recordedAt)
|
|
23416
23461
|
]);
|
|
23417
23462
|
importTranslationCache = projectSchema.table("import_translation_cache", {
|
|
@@ -23444,7 +23489,8 @@ var init_project = __esm({
|
|
|
23444
23489
|
index("idxImportTranslationCacheRecordedAt").on(t.recordedAt)
|
|
23445
23490
|
]);
|
|
23446
23491
|
approvalRequests = projectSchema.table("approval_requests", {
|
|
23447
|
-
|
|
23492
|
+
projectId: text("project_id").notNull().default(sql`current_setting('fusion.project_id', true)`),
|
|
23493
|
+
id: text("id").notNull(),
|
|
23448
23494
|
status: text("status").notNull(),
|
|
23449
23495
|
requesterActorId: text("requester_actor_id").notNull(),
|
|
23450
23496
|
requesterActorType: text("requester_actor_type").notNull(),
|
|
@@ -23463,13 +23509,14 @@ var init_project = __esm({
|
|
|
23463
23509
|
createdAt: text("created_at").notNull(),
|
|
23464
23510
|
updatedAt: text("updated_at").notNull()
|
|
23465
23511
|
}, (t) => [
|
|
23512
|
+
primaryKey({ columns: [t.projectId, t.id] }),
|
|
23466
23513
|
index("idxApprovalRequestsStatusCreatedAt").on(t.status, t.createdAt),
|
|
23467
23514
|
index("idxApprovalRequestsRequesterCreatedAt").on(t.requesterActorId, t.createdAt),
|
|
23468
23515
|
index("idxApprovalRequestsTaskCreatedAt").on(t.taskId, t.createdAt)
|
|
23469
23516
|
]);
|
|
23470
23517
|
approvalRequestAuditEvents = projectSchema.table("approval_request_audit_events", {
|
|
23471
|
-
projectId: text("project_id").notNull().default(
|
|
23472
|
-
id: text("id").
|
|
23518
|
+
projectId: text("project_id").notNull().default(sql`current_setting('fusion.project_id', true)`),
|
|
23519
|
+
id: text("id").notNull(),
|
|
23473
23520
|
requestId: text("request_id").notNull(),
|
|
23474
23521
|
eventType: text("event_type").notNull(),
|
|
23475
23522
|
actorId: text("actor_id").notNull(),
|
|
@@ -23478,6 +23525,7 @@ var init_project = __esm({
|
|
|
23478
23525
|
note: text("note"),
|
|
23479
23526
|
createdAt: text("created_at").notNull()
|
|
23480
23527
|
}, (t) => [
|
|
23528
|
+
primaryKey({ columns: [t.projectId, t.id] }),
|
|
23481
23529
|
index("idxApprovalRequestAuditRequestCreatedAt").on(t.requestId, t.createdAt, t.id),
|
|
23482
23530
|
index("idxApprovalRequestAuditProjectCreatedAt").on(t.projectId, t.createdAt)
|
|
23483
23531
|
]);
|
|
@@ -26967,6 +27015,27 @@ var init_grok_provider = __esm({
|
|
|
26967
27015
|
apiKey: "$GROK_API_KEY",
|
|
26968
27016
|
api: "openai-completions",
|
|
26969
27017
|
models: [
|
|
27018
|
+
/*
|
|
27019
|
+
FNXC:ModelRegistry 2026-08-12-20:17:
|
|
27020
|
+
FN-9008 requires Grok 4.6 to be selectable in every model area. Keep it in this shared
|
|
27021
|
+
catalog because pi's registerProvider() replaces provider model lists wholesale, while every
|
|
27022
|
+
Fusion host seeds and re-merges this export. xAI's model docs verify grok-4.6, its 500k-token
|
|
27023
|
+
context window, and configurable reasoning; max output and per-model image input remain
|
|
27024
|
+
upstream-pending-verification, so retain the conservative text-only and 65536-token defaults.
|
|
27025
|
+
Source: https://docs.x.ai/developers/models
|
|
27026
|
+
*/
|
|
27027
|
+
{
|
|
27028
|
+
id: "grok-4.6",
|
|
27029
|
+
name: "Grok 4.6",
|
|
27030
|
+
reasoning: true,
|
|
27031
|
+
input: ["text"],
|
|
27032
|
+
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
|
27033
|
+
contextWindow: 5e5,
|
|
27034
|
+
maxTokens: 65536,
|
|
27035
|
+
compat: {
|
|
27036
|
+
supportsDeveloperRole: false
|
|
27037
|
+
}
|
|
27038
|
+
},
|
|
26970
27039
|
{
|
|
26971
27040
|
id: "grok-4.5",
|
|
26972
27041
|
name: "Grok 4.5",
|
|
@@ -34925,6 +34994,7 @@ function rowToMessage(row) {
|
|
|
34925
34994
|
content: row.content,
|
|
34926
34995
|
type: row.type,
|
|
34927
34996
|
read: (row.read ?? 0) === 1,
|
|
34997
|
+
archived: (row.archived ?? 0) === 1,
|
|
34928
34998
|
metadata: row.metadata ?? void 0,
|
|
34929
34999
|
createdAt: row.createdAt,
|
|
34930
35000
|
updatedAt: row.updatedAt
|
|
@@ -34936,6 +35006,11 @@ function participantIdsForLookup(ownerId, ownerType) {
|
|
|
34936
35006
|
}
|
|
34937
35007
|
return [ownerId];
|
|
34938
35008
|
}
|
|
35009
|
+
function archivedCondition(archived) {
|
|
35010
|
+
if (archived === true) return eq(project_exports.messages.archived, 1);
|
|
35011
|
+
if (archived === false) return or(eq(project_exports.messages.archived, 0), sql`${project_exports.messages.archived} IS NULL`);
|
|
35012
|
+
return or(eq(project_exports.messages.archived, 0), sql`${project_exports.messages.archived} IS NULL`);
|
|
35013
|
+
}
|
|
34939
35014
|
async function sendMessage(handle, message) {
|
|
34940
35015
|
const sanitizedContent = sanitizeTextValue(message.content);
|
|
34941
35016
|
const sanitizedMetadata = sanitizeJsonbValue(message.metadata);
|
|
@@ -34948,6 +35023,7 @@ async function sendMessage(handle, message) {
|
|
|
34948
35023
|
content: sanitizedContent,
|
|
34949
35024
|
type: message.type,
|
|
34950
35025
|
read: message.read ? 1 : 0,
|
|
35026
|
+
archived: message.archived ? 1 : 0,
|
|
34951
35027
|
metadata: sanitizedMetadata,
|
|
34952
35028
|
createdAt: message.createdAt,
|
|
34953
35029
|
updatedAt: message.updatedAt
|
|
@@ -34956,7 +35032,8 @@ async function sendMessage(handle, message) {
|
|
|
34956
35032
|
...message,
|
|
34957
35033
|
content: sanitizedContent,
|
|
34958
35034
|
metadata: sanitizedMetadata,
|
|
34959
|
-
read: message.read ? 1 : 0
|
|
35035
|
+
read: message.read ? 1 : 0,
|
|
35036
|
+
archived: message.archived ? 1 : 0
|
|
34960
35037
|
});
|
|
34961
35038
|
}
|
|
34962
35039
|
async function sendMessageOnce(handle, message) {
|
|
@@ -34969,6 +35046,7 @@ async function sendMessageOnce(handle, message) {
|
|
|
34969
35046
|
content: message.content,
|
|
34970
35047
|
type: message.type,
|
|
34971
35048
|
read: message.read ? 1 : 0,
|
|
35049
|
+
archived: message.archived ? 1 : 0,
|
|
34972
35050
|
metadata: message.metadata,
|
|
34973
35051
|
createdAt: message.createdAt,
|
|
34974
35052
|
updatedAt: message.updatedAt
|
|
@@ -35020,6 +35098,7 @@ async function queryMessagesByParticipant(handle, direction, ownerId, ownerType,
|
|
|
35020
35098
|
if (filter?.read !== void 0) {
|
|
35021
35099
|
conditions.push(eq(project_exports.messages.read, filter.read ? 1 : 0));
|
|
35022
35100
|
}
|
|
35101
|
+
conditions.push(archivedCondition(filter?.archived));
|
|
35023
35102
|
const limit = filter?.limit ?? 100;
|
|
35024
35103
|
const offset = filter?.offset ?? 0;
|
|
35025
35104
|
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 +35112,13 @@ async function markMessageAsRead(handle, messageId) {
|
|
|
35033
35112
|
await handle.update(project_exports.messages).set({ read: 1, updatedAt: now }).where(eq(project_exports.messages.id, messageId));
|
|
35034
35113
|
return await getMessage(handle, messageId);
|
|
35035
35114
|
}
|
|
35115
|
+
async function setMessageArchived(handle, id, archived) {
|
|
35116
|
+
const existing = await getMessage(handle, id);
|
|
35117
|
+
if (!existing) return null;
|
|
35118
|
+
if (existing.archived === archived) return existing;
|
|
35119
|
+
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);
|
|
35120
|
+
return rows[0] ? rowToMessage(rows[0]) : null;
|
|
35121
|
+
}
|
|
35036
35122
|
async function markAllMessagesAsRead(handle, ownerId, ownerType) {
|
|
35037
35123
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
35038
35124
|
const participantIds = participantIdsForLookup(ownerId, ownerType);
|
|
@@ -35040,7 +35126,8 @@ async function markAllMessagesAsRead(handle, ownerId, ownerType) {
|
|
|
35040
35126
|
and(
|
|
35041
35127
|
inArray(project_exports.messages.toId, participantIds),
|
|
35042
35128
|
eq(project_exports.messages.toType, ownerType),
|
|
35043
|
-
eq(project_exports.messages.read, 0)
|
|
35129
|
+
eq(project_exports.messages.read, 0),
|
|
35130
|
+
archivedCondition()
|
|
35044
35131
|
)
|
|
35045
35132
|
);
|
|
35046
35133
|
const count2 = countRows[0]?.count ?? 0;
|
|
@@ -35048,7 +35135,8 @@ async function markAllMessagesAsRead(handle, ownerId, ownerType) {
|
|
|
35048
35135
|
and(
|
|
35049
35136
|
inArray(project_exports.messages.toId, participantIds),
|
|
35050
35137
|
eq(project_exports.messages.toType, ownerType),
|
|
35051
|
-
eq(project_exports.messages.read, 0)
|
|
35138
|
+
eq(project_exports.messages.read, 0),
|
|
35139
|
+
archivedCondition()
|
|
35052
35140
|
)
|
|
35053
35141
|
);
|
|
35054
35142
|
return count2;
|
|
@@ -35070,19 +35158,22 @@ async function getConversation(handle, participantA, participantB, options) {
|
|
|
35070
35158
|
const aIds = participantIdsForLookup(participantA.id, participantA.type);
|
|
35071
35159
|
const bIds = participantIdsForLookup(participantB.id, participantB.type);
|
|
35072
35160
|
const rows = await handle.select(messageColumns).from(project_exports.messages).where(
|
|
35073
|
-
|
|
35074
|
-
|
|
35075
|
-
|
|
35076
|
-
|
|
35077
|
-
|
|
35078
|
-
|
|
35161
|
+
and(
|
|
35162
|
+
or(
|
|
35163
|
+
and(
|
|
35164
|
+
inArray(project_exports.messages.fromId, aIds),
|
|
35165
|
+
eq(project_exports.messages.fromType, participantA.type),
|
|
35166
|
+
inArray(project_exports.messages.toId, bIds),
|
|
35167
|
+
eq(project_exports.messages.toType, participantB.type)
|
|
35168
|
+
),
|
|
35169
|
+
and(
|
|
35170
|
+
inArray(project_exports.messages.fromId, bIds),
|
|
35171
|
+
eq(project_exports.messages.fromType, participantB.type),
|
|
35172
|
+
inArray(project_exports.messages.toId, aIds),
|
|
35173
|
+
eq(project_exports.messages.toType, participantA.type)
|
|
35174
|
+
)
|
|
35079
35175
|
),
|
|
35080
|
-
|
|
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
|
-
)
|
|
35176
|
+
archivedCondition(options?.archived)
|
|
35086
35177
|
)
|
|
35087
35178
|
).orderBy(desc(project_exports.messages.createdAt)).limit(limit);
|
|
35088
35179
|
return rows.reverse().map((row) => rowToMessage(row));
|
|
@@ -35093,14 +35184,16 @@ async function getMailbox(handle, ownerId, ownerType) {
|
|
|
35093
35184
|
and(
|
|
35094
35185
|
inArray(project_exports.messages.toId, participantIds),
|
|
35095
35186
|
eq(project_exports.messages.toType, ownerType),
|
|
35096
|
-
eq(project_exports.messages.read, 0)
|
|
35187
|
+
eq(project_exports.messages.read, 0),
|
|
35188
|
+
archivedCondition()
|
|
35097
35189
|
)
|
|
35098
35190
|
);
|
|
35099
35191
|
const unreadCount = unreadRows[0]?.count ?? 0;
|
|
35100
35192
|
const lastRows = await handle.select(messageColumns).from(project_exports.messages).where(
|
|
35101
35193
|
and(
|
|
35102
35194
|
inArray(project_exports.messages.toId, participantIds),
|
|
35103
|
-
eq(project_exports.messages.toType, ownerType)
|
|
35195
|
+
eq(project_exports.messages.toType, ownerType),
|
|
35196
|
+
archivedCondition()
|
|
35104
35197
|
)
|
|
35105
35198
|
).orderBy(desc(project_exports.messages.createdAt), desc(project_exports.messages.id)).limit(1);
|
|
35106
35199
|
return {
|
|
@@ -35110,15 +35203,16 @@ async function getMailbox(handle, ownerId, ownerType) {
|
|
|
35110
35203
|
lastMessage: lastRows[0] ? rowToMessage(lastRows[0]) : void 0
|
|
35111
35204
|
};
|
|
35112
35205
|
}
|
|
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));
|
|
35206
|
+
async function getAllAgentToAgentMessages(handle, filter) {
|
|
35207
|
+
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
35208
|
return rows.map((row) => rowToMessage(row));
|
|
35116
35209
|
}
|
|
35117
35210
|
async function getUnreadAgentToAgentCount(handle) {
|
|
35118
35211
|
const rows = await handle.select({ count: sql`count(*)::int` }).from(project_exports.messages).where(
|
|
35119
35212
|
and(
|
|
35120
35213
|
eq(project_exports.messages.type, "agent-to-agent"),
|
|
35121
|
-
eq(project_exports.messages.read, 0)
|
|
35214
|
+
eq(project_exports.messages.read, 0),
|
|
35215
|
+
archivedCondition()
|
|
35122
35216
|
)
|
|
35123
35217
|
);
|
|
35124
35218
|
return rows[0]?.count ?? 0;
|
|
@@ -35140,6 +35234,7 @@ var init_async_message_store = __esm({
|
|
|
35140
35234
|
content: project_exports.messages.content,
|
|
35141
35235
|
type: project_exports.messages.type,
|
|
35142
35236
|
read: project_exports.messages.read,
|
|
35237
|
+
archived: project_exports.messages.archived,
|
|
35143
35238
|
metadata: project_exports.messages.metadata,
|
|
35144
35239
|
createdAt: project_exports.messages.createdAt,
|
|
35145
35240
|
updatedAt: project_exports.messages.updatedAt
|
|
@@ -35325,12 +35420,12 @@ var init_message_store = __esm({
|
|
|
35325
35420
|
}
|
|
35326
35421
|
const sqliteDb = this.db;
|
|
35327
35422
|
this.stmtInsert = sqliteDb.prepare(`
|
|
35328
|
-
INSERT INTO messages (id, fromId, fromType, toId, toType, content, type, read, metadata, createdAt, updatedAt)
|
|
35329
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
35423
|
+
INSERT INTO messages (id, fromId, fromType, toId, toType, content, type, read, archived, metadata, createdAt, updatedAt)
|
|
35424
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
35330
35425
|
`);
|
|
35331
35426
|
this.stmtInsertOnce = sqliteDb.prepare(`
|
|
35332
|
-
INSERT OR IGNORE INTO messages (id, fromId, fromType, toId, toType, content, type, read, metadata, createdAt, updatedAt)
|
|
35333
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
35427
|
+
INSERT OR IGNORE INTO messages (id, fromId, fromType, toId, toType, content, type, read, archived, metadata, createdAt, updatedAt)
|
|
35428
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
35334
35429
|
`);
|
|
35335
35430
|
this.stmtGetById = sqliteDb.prepare(`
|
|
35336
35431
|
SELECT * FROM messages WHERE id = ?
|
|
@@ -35368,6 +35463,7 @@ var init_message_store = __esm({
|
|
|
35368
35463
|
content: row.content,
|
|
35369
35464
|
type: row.type,
|
|
35370
35465
|
read: row.read === 1,
|
|
35466
|
+
archived: (row.archived ?? 0) === 1,
|
|
35371
35467
|
metadata: fromJson(row.metadata),
|
|
35372
35468
|
createdAt: row.createdAt,
|
|
35373
35469
|
updatedAt: row.updatedAt
|
|
@@ -35401,6 +35497,7 @@ var init_message_store = __esm({
|
|
|
35401
35497
|
content: sanitizeTextValue(input.content),
|
|
35402
35498
|
type: input.type,
|
|
35403
35499
|
read: false,
|
|
35500
|
+
archived: false,
|
|
35404
35501
|
metadata: sanitizeJsonbValue(input.metadata),
|
|
35405
35502
|
createdAt: now,
|
|
35406
35503
|
updatedAt: now
|
|
@@ -35416,6 +35513,7 @@ var init_message_store = __esm({
|
|
|
35416
35513
|
content: message.content,
|
|
35417
35514
|
type: message.type,
|
|
35418
35515
|
read: message.read,
|
|
35516
|
+
archived: message.archived,
|
|
35419
35517
|
metadata: message.metadata ?? null,
|
|
35420
35518
|
createdAt: message.createdAt,
|
|
35421
35519
|
updatedAt: message.updatedAt
|
|
@@ -35430,6 +35528,7 @@ var init_message_store = __esm({
|
|
|
35430
35528
|
message.content,
|
|
35431
35529
|
message.type,
|
|
35432
35530
|
message.read ? 1 : 0,
|
|
35531
|
+
message.archived ? 1 : 0,
|
|
35433
35532
|
toJsonNullable(message.metadata),
|
|
35434
35533
|
message.createdAt,
|
|
35435
35534
|
message.updatedAt
|
|
@@ -35488,6 +35587,7 @@ var init_message_store = __esm({
|
|
|
35488
35587
|
content: sanitizeTextValue(input.content),
|
|
35489
35588
|
type: input.type,
|
|
35490
35589
|
read: false,
|
|
35590
|
+
archived: false,
|
|
35491
35591
|
metadata: sanitizeJsonbValue(input.metadata),
|
|
35492
35592
|
createdAt: now,
|
|
35493
35593
|
updatedAt: now
|
|
@@ -35508,6 +35608,7 @@ var init_message_store = __esm({
|
|
|
35508
35608
|
message.content,
|
|
35509
35609
|
message.type,
|
|
35510
35610
|
0,
|
|
35611
|
+
0,
|
|
35511
35612
|
toJsonNullable(message.metadata),
|
|
35512
35613
|
message.createdAt,
|
|
35513
35614
|
message.updatedAt
|
|
@@ -35639,6 +35740,7 @@ var init_message_store = __esm({
|
|
|
35639
35740
|
whereClauses.push("read = ?");
|
|
35640
35741
|
params.push(filter.read ? 1 : 0);
|
|
35641
35742
|
}
|
|
35743
|
+
whereClauses.push(filter?.archived === true ? "archived = 1" : "(archived = 0 OR archived IS NULL)");
|
|
35642
35744
|
const whereSql = whereClauses.join(" AND ");
|
|
35643
35745
|
const limit = filter?.limit ?? 100;
|
|
35644
35746
|
const offset = filter?.offset ?? 0;
|
|
@@ -35689,15 +35791,39 @@ var init_message_store = __esm({
|
|
|
35689
35791
|
const participantIds = this.getParticipantIdsForLookup(ownerId, ownerType);
|
|
35690
35792
|
const toIdPredicate = participantIds.length === 1 ? "toId = ?" : `toId IN (${participantIds.map(() => "?").join(", ")})`;
|
|
35691
35793
|
const unreadRow = this.db.prepare(`
|
|
35692
|
-
SELECT COUNT(*) as count FROM messages WHERE ${toIdPredicate} AND toType = ? AND read = 0
|
|
35794
|
+
SELECT COUNT(*) as count FROM messages WHERE ${toIdPredicate} AND toType = ? AND read = 0 AND (archived = 0 OR archived IS NULL)
|
|
35693
35795
|
`).get(...participantIds, ownerType);
|
|
35694
35796
|
const count2 = unreadRow?.count ?? 0;
|
|
35695
35797
|
this.db.prepare(`
|
|
35696
|
-
UPDATE messages SET read = 1, updatedAt = ? WHERE ${toIdPredicate} AND toType = ? AND read = 0
|
|
35798
|
+
UPDATE messages SET read = 1, updatedAt = ? WHERE ${toIdPredicate} AND toType = ? AND read = 0 AND (archived = 0 OR archived IS NULL)
|
|
35697
35799
|
`).run(now, ...participantIds, ownerType);
|
|
35698
35800
|
this.db.bumpLastModified();
|
|
35699
35801
|
return count2;
|
|
35700
35802
|
}
|
|
35803
|
+
/** Archive a message without destroying its correspondence history. */
|
|
35804
|
+
async archiveMessage(id) {
|
|
35805
|
+
return this.setMessageArchived(id, true);
|
|
35806
|
+
}
|
|
35807
|
+
/** Restore a previously archived message to default mailbox lists. */
|
|
35808
|
+
async unarchiveMessage(id) {
|
|
35809
|
+
return this.setMessageArchived(id, false);
|
|
35810
|
+
}
|
|
35811
|
+
async setMessageArchived(id, archived) {
|
|
35812
|
+
if (this.asyncLayer) {
|
|
35813
|
+
const updated2 = await setMessageArchived(this.asyncLayer.db, id, archived);
|
|
35814
|
+
if (!updated2) throw new Error(`Message ${id} not found`);
|
|
35815
|
+
this.emit(archived ? "message:archived" : "message:unarchived", updated2);
|
|
35816
|
+
return updated2;
|
|
35817
|
+
}
|
|
35818
|
+
const existing = await this.getMessage(id);
|
|
35819
|
+
if (!existing) throw new Error(`Message ${id} not found`);
|
|
35820
|
+
if (existing.archived === archived) return existing;
|
|
35821
|
+
this.db.prepare("UPDATE messages SET archived = ?, updatedAt = ? WHERE id = ?").run(archived ? 1 : 0, (/* @__PURE__ */ new Date()).toISOString(), id);
|
|
35822
|
+
this.db.bumpLastModified();
|
|
35823
|
+
const updated = await this.getMessage(id);
|
|
35824
|
+
this.emit(archived ? "message:archived" : "message:unarchived", updated);
|
|
35825
|
+
return updated;
|
|
35826
|
+
}
|
|
35701
35827
|
/**
|
|
35702
35828
|
* Delete a message by ID.
|
|
35703
35829
|
* @param id - The message ID
|
|
@@ -35788,7 +35914,7 @@ var init_message_store = __esm({
|
|
|
35788
35914
|
(${participantAFromPredicate} AND fromType = ? AND ${participantBToPredicate} AND toType = ?)
|
|
35789
35915
|
OR
|
|
35790
35916
|
(${participantBFromPredicate} AND fromType = ? AND ${participantAToPredicate} AND toType = ?)
|
|
35791
|
-
)
|
|
35917
|
+
) AND ${options?.archived === true ? "archived = 1" : "(archived = 0 OR archived IS NULL)"}
|
|
35792
35918
|
ORDER BY createdAt DESC
|
|
35793
35919
|
LIMIT ?
|
|
35794
35920
|
`).all(
|
|
@@ -35823,11 +35949,11 @@ var init_message_store = __esm({
|
|
|
35823
35949
|
const participantIds = this.getParticipantIdsForLookup(ownerId, ownerType);
|
|
35824
35950
|
const toIdPredicate = participantIds.length === 1 ? "toId = ?" : `toId IN (${participantIds.map(() => "?").join(", ")})`;
|
|
35825
35951
|
const unreadRow = this.db.prepare(`
|
|
35826
|
-
SELECT COUNT(*) as count FROM messages WHERE ${toIdPredicate} AND toType = ? AND read = 0
|
|
35952
|
+
SELECT COUNT(*) as count FROM messages WHERE ${toIdPredicate} AND toType = ? AND read = 0 AND (archived = 0 OR archived IS NULL)
|
|
35827
35953
|
`).get(...participantIds, ownerType);
|
|
35828
35954
|
const unreadCount = unreadRow?.count ?? 0;
|
|
35829
35955
|
const lastRow = this.db.prepare(`
|
|
35830
|
-
SELECT * FROM messages WHERE ${toIdPredicate} AND toType = ? ORDER BY createdAt DESC, rowid DESC LIMIT 1
|
|
35956
|
+
SELECT * FROM messages WHERE ${toIdPredicate} AND toType = ? AND (archived = 0 OR archived IS NULL) ORDER BY createdAt DESC, rowid DESC LIMIT 1
|
|
35831
35957
|
`).get(...participantIds, ownerType);
|
|
35832
35958
|
const lastMessage = lastRow ? this.rowToMessage(lastRow) : void 0;
|
|
35833
35959
|
return {
|
|
@@ -35841,13 +35967,13 @@ var init_message_store = __esm({
|
|
|
35841
35967
|
* Get all agent-to-agent messages across all agents.
|
|
35842
35968
|
* @returns Array of messages (newest first)
|
|
35843
35969
|
*/
|
|
35844
|
-
async getAllAgentToAgentMessages() {
|
|
35970
|
+
async getAllAgentToAgentMessages(filter) {
|
|
35845
35971
|
if (this.asyncLayer) {
|
|
35846
|
-
return getAllAgentToAgentMessages(this.asyncLayer.db);
|
|
35972
|
+
return getAllAgentToAgentMessages(this.asyncLayer.db, filter);
|
|
35847
35973
|
}
|
|
35848
35974
|
const rows = this.db.prepare(`
|
|
35849
35975
|
SELECT * FROM messages
|
|
35850
|
-
WHERE type = ?
|
|
35976
|
+
WHERE type = ? AND ${filter?.archived === true ? "archived = 1" : "(archived = 0 OR archived IS NULL)"}
|
|
35851
35977
|
ORDER BY createdAt DESC, rowid DESC
|
|
35852
35978
|
`).all("agent-to-agent");
|
|
35853
35979
|
return rows.map((row) => this.rowToMessage(row));
|
|
@@ -35861,7 +35987,7 @@ var init_message_store = __esm({
|
|
|
35861
35987
|
}
|
|
35862
35988
|
const row = this.db.prepare(`
|
|
35863
35989
|
SELECT COUNT(*) as count FROM messages
|
|
35864
|
-
WHERE type = ? AND read = 0
|
|
35990
|
+
WHERE type = ? AND read = 0 AND (archived = 0 OR archived IS NULL)
|
|
35865
35991
|
`).get("agent-to-agent");
|
|
35866
35992
|
return row?.count ?? 0;
|
|
35867
35993
|
}
|
|
@@ -35960,6 +36086,7 @@ async function createApprovalRequest(layer, input) {
|
|
|
35960
36086
|
};
|
|
35961
36087
|
await layer.transactionImmediate(async (tx) => {
|
|
35962
36088
|
await tx.insert(project_exports.approvalRequests).values({
|
|
36089
|
+
...layer.projectId?.trim() ? { projectId: layer.projectId } : {},
|
|
35963
36090
|
id: request2.id,
|
|
35964
36091
|
status: request2.status,
|
|
35965
36092
|
requesterActorId: request2.requester.actorId,
|
|
@@ -35983,12 +36110,12 @@ async function createApprovalRequest(layer, input) {
|
|
|
35983
36110
|
});
|
|
35984
36111
|
return request2;
|
|
35985
36112
|
}
|
|
35986
|
-
async function getApprovalRequest(handle, id) {
|
|
35987
|
-
const rows = await handle.select().from(project_exports.approvalRequests).where(eq(project_exports.approvalRequests.id, id));
|
|
36113
|
+
async function getApprovalRequest(handle, id, projectId2) {
|
|
36114
|
+
const rows = await handle.select().from(project_exports.approvalRequests).where(and(eq(project_exports.approvalRequests.id, id), projectScopeFor(project_exports.approvalRequests.projectId, projectId2)));
|
|
35988
36115
|
return rows[0] ? rowToRequest(rows[0]) : null;
|
|
35989
36116
|
}
|
|
35990
|
-
async function listApprovalRequests(handle, input = {}) {
|
|
35991
|
-
const conditions = [];
|
|
36117
|
+
async function listApprovalRequests(handle, input = {}, projectId2) {
|
|
36118
|
+
const conditions = [projectScopeFor(project_exports.approvalRequests.projectId, projectId2)];
|
|
35992
36119
|
if (input.status) conditions.push(eq(project_exports.approvalRequests.status, input.status));
|
|
35993
36120
|
if (input.requesterActorId) conditions.push(eq(project_exports.approvalRequests.requesterActorId, input.requesterActorId));
|
|
35994
36121
|
if (input.taskId) conditions.push(eq(project_exports.approvalRequests.taskId, input.taskId));
|
|
@@ -36002,7 +36129,7 @@ async function listApprovalRequests(handle, input = {}) {
|
|
|
36002
36129
|
async function decideApprovalRequest(layer, requestId, status, input) {
|
|
36003
36130
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
36004
36131
|
return layer.transactionImmediate(async (tx) => {
|
|
36005
|
-
const existing = await getApprovalRequest(tx, requestId);
|
|
36132
|
+
const existing = await getApprovalRequest(tx, requestId, layer.projectId);
|
|
36006
36133
|
if (!existing) throw new Error(`Approval request ${requestId} not found`);
|
|
36007
36134
|
if (!isValidApprovalRequestTransition(existing.status, status)) {
|
|
36008
36135
|
throw new Error(`Invalid approval request transition: ${existing.status} -> ${status}`);
|
|
@@ -36013,23 +36140,24 @@ async function decideApprovalRequest(layer, requestId, status, input) {
|
|
|
36013
36140
|
const updatedRows = await tx.update(project_exports.approvalRequests).set({ status, decidedAt: now, updatedAt: now }).where(
|
|
36014
36141
|
and(
|
|
36015
36142
|
eq(project_exports.approvalRequests.id, requestId),
|
|
36016
|
-
eq(project_exports.approvalRequests.status, existing.status)
|
|
36143
|
+
eq(project_exports.approvalRequests.status, existing.status),
|
|
36144
|
+
projectScopeFor(project_exports.approvalRequests.projectId, layer.projectId)
|
|
36017
36145
|
)
|
|
36018
36146
|
).returning({ id: project_exports.approvalRequests.id });
|
|
36019
36147
|
if (updatedRows.length === 0) {
|
|
36020
|
-
const raced = await getApprovalRequest(tx, requestId);
|
|
36148
|
+
const raced = await getApprovalRequest(tx, requestId, layer.projectId);
|
|
36021
36149
|
throw new Error(
|
|
36022
36150
|
`Invalid approval request transition: ${raced?.status ?? existing.status} -> ${status}`
|
|
36023
36151
|
);
|
|
36024
36152
|
}
|
|
36025
36153
|
await appendAuditEvent(tx, layer.projectId ?? "", requestId, status, input.actor, now, input.note);
|
|
36026
|
-
return await getApprovalRequest(tx, requestId);
|
|
36154
|
+
return await getApprovalRequest(tx, requestId, layer.projectId);
|
|
36027
36155
|
});
|
|
36028
36156
|
}
|
|
36029
36157
|
async function markApprovalRequestCompleted(layer, requestId, input) {
|
|
36030
36158
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
36031
36159
|
return layer.transactionImmediate(async (tx) => {
|
|
36032
|
-
const existing = await getApprovalRequest(tx, requestId);
|
|
36160
|
+
const existing = await getApprovalRequest(tx, requestId, layer.projectId);
|
|
36033
36161
|
if (!existing) throw new Error(`Approval request ${requestId} not found`);
|
|
36034
36162
|
if (!isValidApprovalRequestTransition(existing.status, "completed")) {
|
|
36035
36163
|
throw new Error(`Invalid approval request transition: ${existing.status} -> completed`);
|
|
@@ -36043,21 +36171,22 @@ async function markApprovalRequestCompleted(layer, requestId, input) {
|
|
|
36043
36171
|
const updatedRows = await tx.update(project_exports.approvalRequests).set({ status: "completed", completedAt: now, updatedAt: now }).where(
|
|
36044
36172
|
and(
|
|
36045
36173
|
eq(project_exports.approvalRequests.id, requestId),
|
|
36046
|
-
eq(project_exports.approvalRequests.status, existing.status)
|
|
36174
|
+
eq(project_exports.approvalRequests.status, existing.status),
|
|
36175
|
+
projectScopeFor(project_exports.approvalRequests.projectId, layer.projectId)
|
|
36047
36176
|
)
|
|
36048
36177
|
).returning({ id: project_exports.approvalRequests.id });
|
|
36049
36178
|
if (updatedRows.length === 0) {
|
|
36050
|
-
const raced = await getApprovalRequest(tx, requestId);
|
|
36179
|
+
const raced = await getApprovalRequest(tx, requestId, layer.projectId);
|
|
36051
36180
|
throw new Error(
|
|
36052
36181
|
`Invalid approval request transition: ${raced?.status ?? existing.status} -> completed`
|
|
36053
36182
|
);
|
|
36054
36183
|
}
|
|
36055
36184
|
await appendAuditEvent(tx, layer.projectId ?? "", requestId, "completed", input.actor, now, input.note);
|
|
36056
|
-
return await getApprovalRequest(tx, requestId);
|
|
36185
|
+
return await getApprovalRequest(tx, requestId, layer.projectId);
|
|
36057
36186
|
});
|
|
36058
36187
|
}
|
|
36059
|
-
async function getApprovalAuditHistory(handle, requestId) {
|
|
36060
|
-
const rows = await handle.select().from(project_exports.approvalRequestAuditEvents).where(eq(project_exports.approvalRequestAuditEvents.requestId, requestId)).orderBy(
|
|
36188
|
+
async function getApprovalAuditHistory(handle, requestId, projectId2) {
|
|
36189
|
+
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
36190
|
sql`${project_exports.approvalRequestAuditEvents.createdAt} ASC, ${project_exports.approvalRequestAuditEvents.id} ASC`
|
|
36062
36191
|
);
|
|
36063
36192
|
return rows.map((row) => rowToAuditEvent(row));
|
|
@@ -36067,6 +36196,7 @@ var init_async_approval_request_store = __esm({
|
|
|
36067
36196
|
"use strict";
|
|
36068
36197
|
init_drizzle_orm();
|
|
36069
36198
|
init_schema2();
|
|
36199
|
+
init_data_layer();
|
|
36070
36200
|
init_agents();
|
|
36071
36201
|
init_types();
|
|
36072
36202
|
}
|
|
@@ -36080,6 +36210,7 @@ var init_approval_request_store = __esm({
|
|
|
36080
36210
|
"use strict";
|
|
36081
36211
|
init_drizzle_orm();
|
|
36082
36212
|
init_db2();
|
|
36213
|
+
init_data_layer();
|
|
36083
36214
|
init_async_approval_request_store();
|
|
36084
36215
|
init_schema2();
|
|
36085
36216
|
init_async_agent_activity();
|
|
@@ -36208,23 +36339,26 @@ var init_approval_request_store = __esm({
|
|
|
36208
36339
|
return created;
|
|
36209
36340
|
}
|
|
36210
36341
|
async get(id) {
|
|
36211
|
-
return getApprovalRequest(this.asyncLayer.db, id);
|
|
36342
|
+
return getApprovalRequest(this.asyncLayer.db, id, this.asyncLayer.projectId);
|
|
36212
36343
|
}
|
|
36213
36344
|
async list(input = {}) {
|
|
36214
|
-
return listApprovalRequests(this.asyncLayer.db, input);
|
|
36345
|
+
return listApprovalRequests(this.asyncLayer.db, input, this.asyncLayer.projectId);
|
|
36215
36346
|
}
|
|
36216
36347
|
async getPendingCountsByActor() {
|
|
36217
36348
|
const table = project_exports.approvalRequests;
|
|
36218
36349
|
const rows = await this.asyncLayer.db.select({
|
|
36219
36350
|
actorId: table.requesterActorId,
|
|
36220
36351
|
requestCount: count()
|
|
36221
|
-
}).from(table).where(eq(table.status, "pending")).groupBy(table.requesterActorId);
|
|
36352
|
+
}).from(table).where(and(eq(table.status, "pending"), projectScopeFor(table.projectId, this.asyncLayer.projectId))).groupBy(table.requesterActorId);
|
|
36222
36353
|
return new Map(rows.map((row) => [row.actorId, Number(row.requestCount)]));
|
|
36223
36354
|
}
|
|
36224
36355
|
async findLatestByDedupeKey(input) {
|
|
36225
36356
|
if (this.backendMode) {
|
|
36226
36357
|
const table = project_exports.approvalRequests;
|
|
36227
|
-
const conditions = [
|
|
36358
|
+
const conditions = [
|
|
36359
|
+
eq(table.requesterActorId, input.requesterActorId),
|
|
36360
|
+
projectScopeFor(table.projectId, this.asyncLayer.projectId)
|
|
36361
|
+
];
|
|
36228
36362
|
if (input.taskId !== void 0) {
|
|
36229
36363
|
conditions.push(eq(table.taskId, input.taskId));
|
|
36230
36364
|
}
|
|
@@ -36263,7 +36397,7 @@ var init_approval_request_store = __esm({
|
|
|
36263
36397
|
return markApprovalRequestCompleted(this.asyncLayer, requestId, input);
|
|
36264
36398
|
}
|
|
36265
36399
|
async getAuditHistory(requestId) {
|
|
36266
|
-
return getApprovalAuditHistory(this.asyncLayer.db, requestId);
|
|
36400
|
+
return getApprovalAuditHistory(this.asyncLayer.db, requestId, this.asyncLayer.projectId);
|
|
36267
36401
|
}
|
|
36268
36402
|
};
|
|
36269
36403
|
}
|
|
@@ -40449,6 +40583,8 @@ async function applySchemaBaseline(db, options = {}) {
|
|
|
40449
40583
|
const agentRatingProjectIsolationAlreadyApplied = applied.includes(AGENT_RATING_PROJECT_ISOLATION_VERSION);
|
|
40450
40584
|
const agentRatingsProjectPartitionAlreadyApplied = applied.includes(AGENT_RATINGS_PROJECT_PARTITION_VERSION);
|
|
40451
40585
|
const projectOwnershipDeclarationDriftAlreadyApplied = applied.includes(PROJECT_OWNERSHIP_DECLARATION_DRIFT_VERSION);
|
|
40586
|
+
const projectOwnershipDefaultReconciliationAlreadyApplied = applied.includes(PROJECT_OWNERSHIP_DEFAULT_RECONCILIATION_VERSION);
|
|
40587
|
+
const messageArchiveSchemaAlreadyApplied = applied.includes(MESSAGE_ARCHIVE_SCHEMA_VERSION);
|
|
40452
40588
|
assertBinaryNotOlderThanDatabase(applied);
|
|
40453
40589
|
let schemaChanged = false;
|
|
40454
40590
|
if (!baselineAlreadyApplied) {
|
|
@@ -40932,17 +41068,29 @@ async function applySchemaBaseline(db, options = {}) {
|
|
|
40932
41068
|
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
41069
|
schemaChanged = true;
|
|
40934
41070
|
}
|
|
41071
|
+
if (!projectOwnershipDefaultReconciliationAlreadyApplied) {
|
|
41072
|
+
const migrationSql = await readFile4(PROJECT_OWNERSHIP_DEFAULT_RECONCILIATION_MIGRATION_PATH, "utf8");
|
|
41073
|
+
await tx.execute(sql.raw(migrationSql));
|
|
41074
|
+
await tx.execute(sql`INSERT INTO public.${sql.identifier(MIGRATION_BOOKKEEPING_TABLE)} (version) VALUES (${PROJECT_OWNERSHIP_DEFAULT_RECONCILIATION_VERSION}) ON CONFLICT (version) DO NOTHING`);
|
|
41075
|
+
schemaChanged = true;
|
|
41076
|
+
}
|
|
41077
|
+
if (!messageArchiveSchemaAlreadyApplied) {
|
|
41078
|
+
const migrationSql = await readFile4(MESSAGE_ARCHIVE_SCHEMA_MIGRATION_PATH, "utf8");
|
|
41079
|
+
await tx.execute(sql.raw(migrationSql));
|
|
41080
|
+
await tx.execute(sql`INSERT INTO public.${sql.identifier(MIGRATION_BOOKKEEPING_TABLE)} (version) VALUES (${MESSAGE_ARCHIVE_SCHEMA_VERSION}) ON CONFLICT (version) DO NOTHING`);
|
|
41081
|
+
schemaChanged = true;
|
|
41082
|
+
}
|
|
40935
41083
|
return { applied: schemaChanged, pluginHooksRun: pluginHooks.length };
|
|
40936
41084
|
});
|
|
40937
41085
|
}
|
|
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;
|
|
41086
|
+
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
41087
|
var init_schema_applier = __esm({
|
|
40940
41088
|
"../core/src/postgres/schema-applier.ts"() {
|
|
40941
41089
|
"use strict";
|
|
40942
41090
|
init_drizzle_orm();
|
|
40943
41091
|
init_plugin_schema_hook();
|
|
40944
41092
|
init_advisory_locks();
|
|
40945
|
-
SCHEMA_BASELINE_VERSION = "
|
|
41093
|
+
SCHEMA_BASELINE_VERSION = "0058";
|
|
40946
41094
|
TASK_DECLARED_SYMBOLS_VERSION = "0028";
|
|
40947
41095
|
INITIAL_SCHEMA_VERSION = "0000";
|
|
40948
41096
|
AUTOMATION_ISOLATION_SCHEMA_VERSION = "0001";
|
|
@@ -40999,6 +41147,8 @@ var init_schema_applier = __esm({
|
|
|
40999
41147
|
AGENT_RATING_PROJECT_ISOLATION_VERSION = "0054";
|
|
41000
41148
|
AGENT_RATINGS_PROJECT_PARTITION_VERSION = "0055";
|
|
41001
41149
|
PROJECT_OWNERSHIP_DECLARATION_DRIFT_VERSION = "0056";
|
|
41150
|
+
PROJECT_OWNERSHIP_DEFAULT_RECONCILIATION_VERSION = "0057";
|
|
41151
|
+
MESSAGE_ARCHIVE_SCHEMA_VERSION = "0058";
|
|
41002
41152
|
LEGACY_ADOPTION_DRAINED_MARKER_FUNCTION = "fusion_mark_legacy_adoption_drained";
|
|
41003
41153
|
StaleBinarySchemaError = class extends Error {
|
|
41004
41154
|
constructor(databaseVersion, binaryVersion) {
|
|
@@ -41135,6 +41285,8 @@ var init_schema_applier = __esm({
|
|
|
41135
41285
|
AGENT_RATING_PROJECT_ISOLATION_MIGRATION_PATH = join8(MIGRATIONS_DIR, "0054_fn_8957_agent_rating_project_isolation.sql");
|
|
41136
41286
|
AGENT_RATINGS_PROJECT_PARTITION_MIGRATION_PATH = join8(MIGRATIONS_DIR, "0055_fn_8988_agent_ratings_project_partition.sql");
|
|
41137
41287
|
PROJECT_OWNERSHIP_DECLARATION_DRIFT_MIGRATION_PATH = join8(MIGRATIONS_DIR, "0056_fn_8997_project_ownership_declaration_drift.sql");
|
|
41288
|
+
PROJECT_OWNERSHIP_DEFAULT_RECONCILIATION_MIGRATION_PATH = join8(MIGRATIONS_DIR, "0057_fn_9004_project_ownership_default_reconciliation.sql");
|
|
41289
|
+
MESSAGE_ARCHIVE_SCHEMA_MIGRATION_PATH = join8(MIGRATIONS_DIR, "0058_fn_9014_message_archive.sql");
|
|
41138
41290
|
}
|
|
41139
41291
|
});
|
|
41140
41292
|
|
|
@@ -68490,20 +68642,32 @@ async function replaceActiveTaskWorkflowContinuation(layer, input) {
|
|
|
68490
68642
|
return upsertWorkflowWorkItem(layer, input, tx);
|
|
68491
68643
|
}));
|
|
68492
68644
|
}
|
|
68493
|
-
async function seedStrandedPlanReviewContinuation(layer, input) {
|
|
68645
|
+
async function seedStrandedPlanReviewContinuation(layer, input, options = {}) {
|
|
68494
68646
|
return layer.transactionImmediate(async (tx) => withTaskWorkflowSerialization(tx, layer.projectId, input.taskId, async () => {
|
|
68495
68647
|
const active2 = await tx.select({ id: project_exports.workflowWorkItems.id }).from(project_exports.workflowWorkItems).where(and(
|
|
68496
68648
|
projectScopeFor(project_exports.workflowWorkItems.projectId, layer.projectId),
|
|
68497
68649
|
eq(project_exports.workflowWorkItems.taskId, input.taskId),
|
|
68498
68650
|
inArray(project_exports.workflowWorkItems.state, [...ACTIVE_WORKFLOW_WORK_ITEM_STATES])
|
|
68499
68651
|
));
|
|
68500
|
-
|
|
68652
|
+
const blocking = options.retirePredecessorId ? active2.filter((row) => row.id !== options.retirePredecessorId) : active2;
|
|
68653
|
+
if (blocking.length > 0) return { seeded: false, reason: "active-continuation" };
|
|
68501
68654
|
const taskRows = await tx.select({ workflowStepResults: project_exports.tasks.workflowStepResults }).from(project_exports.tasks).where(and(
|
|
68502
68655
|
projectScopeFor(project_exports.tasks.projectId, layer.projectId),
|
|
68503
68656
|
eq(project_exports.tasks.id, input.taskId)
|
|
68504
68657
|
)).limit(1);
|
|
68505
68658
|
const results = taskRows[0]?.workflowStepResults;
|
|
68506
68659
|
if (results?.some(isPlanReviewSatisfied)) return { seeded: false, reason: "plan-review-passed" };
|
|
68660
|
+
if (options.retirePredecessorId) {
|
|
68661
|
+
const predRows = await tx.select().from(project_exports.workflowWorkItems).where(and(
|
|
68662
|
+
projectScopeFor(project_exports.workflowWorkItems.projectId, layer.projectId),
|
|
68663
|
+
eq(project_exports.workflowWorkItems.id, options.retirePredecessorId),
|
|
68664
|
+
eq(project_exports.workflowWorkItems.taskId, input.taskId)
|
|
68665
|
+
)).limit(1);
|
|
68666
|
+
const pred = predRows[0];
|
|
68667
|
+
if (pred && !isTerminalWorkflowWorkItemState(normalizeWorkflowWorkItemState(pred.state))) {
|
|
68668
|
+
await transitionWorkflowWorkItem(layer, pred.id, "succeeded", { leaseOwner: null, leaseExpiresAt: null, lastError: null }, tx);
|
|
68669
|
+
}
|
|
68670
|
+
}
|
|
68507
68671
|
const item = await upsertWorkflowWorkItem(layer, input, tx);
|
|
68508
68672
|
return { seeded: true, workItemId: item.id };
|
|
68509
68673
|
}));
|
|
@@ -68667,8 +68831,10 @@ function safeJsonParse(value) {
|
|
|
68667
68831
|
return null;
|
|
68668
68832
|
}
|
|
68669
68833
|
}
|
|
68670
|
-
async function queryRunAuditEvents(db, filter = {}) {
|
|
68671
|
-
const conditions = []
|
|
68834
|
+
async function queryRunAuditEvents(db, filter = {}, projectId2) {
|
|
68835
|
+
const conditions = [projectScopeFor(project_exports.runAuditEvents.projectId, projectId2)].filter(
|
|
68836
|
+
(condition) => condition !== void 0
|
|
68837
|
+
);
|
|
68672
68838
|
if (filter.runId) {
|
|
68673
68839
|
conditions.push(eq(project_exports.runAuditEvents.runId, filter.runId));
|
|
68674
68840
|
}
|
|
@@ -68814,6 +68980,7 @@ var init_async_audit = __esm({
|
|
|
68814
68980
|
init_drizzle_orm();
|
|
68815
68981
|
init_schema2();
|
|
68816
68982
|
init_data_layer();
|
|
68983
|
+
init_data_layer();
|
|
68817
68984
|
LEGACY_REVIEW_LANES3 = ["in-review"];
|
|
68818
68985
|
LEGACY_COMPLETE_LANES = ["done"];
|
|
68819
68986
|
}
|
|
@@ -69203,7 +69370,10 @@ async function insertArtifactRow(layer, input, stored, archivedColumns) {
|
|
|
69203
69370
|
createdAt: now,
|
|
69204
69371
|
updatedAt: now
|
|
69205
69372
|
});
|
|
69206
|
-
const rows = await tx.select().from(project_exports.artifacts).where(
|
|
69373
|
+
const rows = await tx.select().from(project_exports.artifacts).where(and(
|
|
69374
|
+
eq(project_exports.artifacts.id, id),
|
|
69375
|
+
projectScopeFor(project_exports.artifacts.projectId, layer.projectId)
|
|
69376
|
+
)).limit(1);
|
|
69207
69377
|
const row = rows[0];
|
|
69208
69378
|
if (!row) throw new Error(`Failed to register artifact ${id}`);
|
|
69209
69379
|
return rowToArtifact2(row);
|
|
@@ -69211,7 +69381,7 @@ async function insertArtifactRow(layer, input, stored, archivedColumns) {
|
|
|
69211
69381
|
}
|
|
69212
69382
|
async function updateArtifactRow(layer, id, updates, archivedColumns) {
|
|
69213
69383
|
return layer.transactionImmediate(async (tx) => {
|
|
69214
|
-
const existing = await getArtifact(tx, id);
|
|
69384
|
+
const existing = await getArtifact(tx, id, layer.projectId);
|
|
69215
69385
|
if (!existing) {
|
|
69216
69386
|
throw new Error(`Artifact ${id} not found`);
|
|
69217
69387
|
}
|
|
@@ -69231,29 +69401,38 @@ async function updateArtifactRow(layer, id, updates, archivedColumns) {
|
|
|
69231
69401
|
description: updates.description !== void 0 ? updates.description : existing.description ?? null,
|
|
69232
69402
|
content: updates.content !== void 0 ? updates.content : existing.content ?? null,
|
|
69233
69403
|
updatedAt: now
|
|
69234
|
-
}).where(
|
|
69235
|
-
|
|
69404
|
+
}).where(and(
|
|
69405
|
+
eq(project_exports.artifacts.id, id),
|
|
69406
|
+
projectScopeFor(project_exports.artifacts.projectId, layer.projectId)
|
|
69407
|
+
));
|
|
69408
|
+
const updated = await getArtifact(tx, id, layer.projectId);
|
|
69236
69409
|
if (!updated) {
|
|
69237
69410
|
throw new Error(`Failed to update artifact ${id}`);
|
|
69238
69411
|
}
|
|
69239
69412
|
return updated;
|
|
69240
69413
|
});
|
|
69241
69414
|
}
|
|
69242
|
-
async function getArtifact(db, id) {
|
|
69243
|
-
const rows = await db.select().from(project_exports.artifacts).where(
|
|
69415
|
+
async function getArtifact(db, id, projectId2) {
|
|
69416
|
+
const rows = await db.select().from(project_exports.artifacts).where(and(
|
|
69417
|
+
eq(project_exports.artifacts.id, id),
|
|
69418
|
+
projectScopeFor(project_exports.artifacts.projectId, projectId2)
|
|
69419
|
+
)).limit(1);
|
|
69244
69420
|
const row = rows[0];
|
|
69245
69421
|
return row ? rowToArtifact2(row) : null;
|
|
69246
69422
|
}
|
|
69247
69423
|
async function getArtifacts(db, taskId, projectId2, archivedColumns) {
|
|
69248
69424
|
const column = await getLiveTaskColumn(db, taskId, projectId2, archivedColumns);
|
|
69249
69425
|
if (column === null || column === "archived") return [];
|
|
69250
|
-
const rows = await db.select().from(project_exports.artifacts).where(
|
|
69426
|
+
const rows = await db.select().from(project_exports.artifacts).where(and(
|
|
69427
|
+
eq(project_exports.artifacts.taskId, taskId),
|
|
69428
|
+
projectScopeFor(project_exports.artifacts.projectId, projectId2)
|
|
69429
|
+
)).orderBy(desc(project_exports.artifacts.createdAt));
|
|
69251
69430
|
return rows.map((row) => rowToArtifact2(row));
|
|
69252
69431
|
}
|
|
69253
|
-
async function listArtifacts(db, options) {
|
|
69432
|
+
async function listArtifacts(db, options, projectId2) {
|
|
69254
69433
|
const limit = Math.min(Math.max(1, options?.limit ?? 200), 1e3);
|
|
69255
69434
|
const offset = Math.max(0, options?.offset ?? 0);
|
|
69256
|
-
const conditions = [];
|
|
69435
|
+
const conditions = [projectScopeFor(project_exports.artifacts.projectId, projectId2)];
|
|
69257
69436
|
if (options?.type) {
|
|
69258
69437
|
conditions.push(eq(project_exports.artifacts.type, options.type));
|
|
69259
69438
|
}
|
|
@@ -69292,7 +69471,10 @@ async function listArtifacts(db, options) {
|
|
|
69292
69471
|
taskColumn: project_exports.tasks.column
|
|
69293
69472
|
}).from(project_exports.artifacts).leftJoin(
|
|
69294
69473
|
project_exports.tasks,
|
|
69295
|
-
|
|
69474
|
+
and(
|
|
69475
|
+
eq(project_exports.artifacts.taskId, project_exports.tasks.id),
|
|
69476
|
+
eq(project_exports.artifacts.projectId, project_exports.tasks.projectId)
|
|
69477
|
+
)
|
|
69296
69478
|
).where(and(...conditions)).orderBy(desc(project_exports.artifacts.createdAt)).limit(limit).offset(offset);
|
|
69297
69479
|
return rows.map((row) => {
|
|
69298
69480
|
const artifact = rowToArtifact2(row);
|
|
@@ -70457,7 +70639,7 @@ function rowToBranchGroup2(row) {
|
|
|
70457
70639
|
closedAt: row.closedAt ?? void 0
|
|
70458
70640
|
};
|
|
70459
70641
|
}
|
|
70460
|
-
async function createBranchGroup(db, input) {
|
|
70642
|
+
async function createBranchGroup(db, input, projectId2) {
|
|
70461
70643
|
validateBranchGroupBranchName(input.branchName);
|
|
70462
70644
|
const now = Date.now();
|
|
70463
70645
|
const id = generateBranchGroupId2();
|
|
@@ -70476,44 +70658,52 @@ async function createBranchGroup(db, input) {
|
|
|
70476
70658
|
updatedAt: now,
|
|
70477
70659
|
closedAt: input.closedAt ?? null
|
|
70478
70660
|
});
|
|
70479
|
-
const created = await getBranchGroup(db, id);
|
|
70661
|
+
const created = await getBranchGroup(db, id, projectId2);
|
|
70480
70662
|
if (!created) throw new Error(`Failed to read branch group ${id} after create`);
|
|
70481
70663
|
return created;
|
|
70482
70664
|
}
|
|
70483
|
-
async function getBranchGroup(db, id) {
|
|
70484
|
-
const rows = await db.select().from(project_exports.branchGroups).where(
|
|
70665
|
+
async function getBranchGroup(db, id, projectId2) {
|
|
70666
|
+
const rows = await db.select().from(project_exports.branchGroups).where(and(
|
|
70667
|
+
eq(project_exports.branchGroups.id, id),
|
|
70668
|
+
projectScopeFor(project_exports.branchGroups.projectId, projectId2)
|
|
70669
|
+
)).limit(1);
|
|
70485
70670
|
const row = rows[0];
|
|
70486
70671
|
return row ? rowToBranchGroup2(row) : null;
|
|
70487
70672
|
}
|
|
70488
|
-
async function getBranchGroupBySource(db, sourceType, sourceId) {
|
|
70673
|
+
async function getBranchGroupBySource(db, sourceType, sourceId, projectId2) {
|
|
70489
70674
|
const rows = await db.select().from(project_exports.branchGroups).where(
|
|
70490
70675
|
and(
|
|
70491
70676
|
eq(project_exports.branchGroups.sourceType, sourceType),
|
|
70492
|
-
eq(project_exports.branchGroups.sourceId, sourceId)
|
|
70677
|
+
eq(project_exports.branchGroups.sourceId, sourceId),
|
|
70678
|
+
projectScopeFor(project_exports.branchGroups.projectId, projectId2)
|
|
70493
70679
|
)
|
|
70494
70680
|
).limit(1);
|
|
70495
70681
|
const row = rows[0];
|
|
70496
70682
|
return row ? rowToBranchGroup2(row) : null;
|
|
70497
70683
|
}
|
|
70498
|
-
async function getBranchGroupByBranchName(db, branchName) {
|
|
70499
|
-
const rows = await db.select().from(project_exports.branchGroups).where(
|
|
70684
|
+
async function getBranchGroupByBranchName(db, branchName, projectId2) {
|
|
70685
|
+
const rows = await db.select().from(project_exports.branchGroups).where(and(
|
|
70686
|
+
eq(project_exports.branchGroups.branchName, branchName),
|
|
70687
|
+
projectScopeFor(project_exports.branchGroups.projectId, projectId2)
|
|
70688
|
+
)).orderBy(sql`${project_exports.branchGroups.createdAt} DESC`).limit(1);
|
|
70500
70689
|
const row = rows[0];
|
|
70501
70690
|
return row ? rowToBranchGroup2(row) : null;
|
|
70502
70691
|
}
|
|
70503
|
-
async function ensureBranchGroupForSource(db, sourceType, sourceId, init) {
|
|
70504
|
-
const existing = await getBranchGroupBySource(db, sourceType, sourceId);
|
|
70692
|
+
async function ensureBranchGroupForSource(db, sourceType, sourceId, init, projectId2) {
|
|
70693
|
+
const existing = await getBranchGroupBySource(db, sourceType, sourceId, projectId2);
|
|
70505
70694
|
if (existing) return existing;
|
|
70506
|
-
const existingByBranch = await getBranchGroupByBranchName(db, init.branchName);
|
|
70695
|
+
const existingByBranch = await getBranchGroupByBranchName(db, init.branchName, projectId2);
|
|
70507
70696
|
if (existingByBranch) return existingByBranch;
|
|
70508
|
-
return createBranchGroup(db, { sourceType, sourceId, ...init });
|
|
70697
|
+
return createBranchGroup(db, { sourceType, sourceId, ...init }, projectId2);
|
|
70509
70698
|
}
|
|
70510
|
-
async function listBranchGroups(db, options) {
|
|
70511
|
-
const
|
|
70512
|
-
|
|
70699
|
+
async function listBranchGroups(db, options, projectId2) {
|
|
70700
|
+
const conditions = [projectScopeFor(project_exports.branchGroups.projectId, projectId2)];
|
|
70701
|
+
if (options?.status) conditions.push(eq(project_exports.branchGroups.status, options.status));
|
|
70702
|
+
const rows = await db.select().from(project_exports.branchGroups).where(and(...conditions)).orderBy(asc(project_exports.branchGroups.createdAt));
|
|
70513
70703
|
return rows.map((row) => rowToBranchGroup2(row));
|
|
70514
70704
|
}
|
|
70515
|
-
async function updateBranchGroup(db, id, patch) {
|
|
70516
|
-
const current = await getBranchGroup(db, id);
|
|
70705
|
+
async function updateBranchGroup(db, id, patch, projectId2) {
|
|
70706
|
+
const current = await getBranchGroup(db, id, projectId2);
|
|
70517
70707
|
if (!current) throw new Error(`Branch group ${id} not found`);
|
|
70518
70708
|
if (patch.branchName !== void 0) {
|
|
70519
70709
|
validateBranchGroupBranchName(patch.branchName);
|
|
@@ -70532,8 +70722,11 @@ async function updateBranchGroup(db, id, patch) {
|
|
|
70532
70722
|
status: nextStatus,
|
|
70533
70723
|
updatedAt: now,
|
|
70534
70724
|
closedAt: nextClosedAt
|
|
70535
|
-
}).where(
|
|
70536
|
-
|
|
70725
|
+
}).where(and(
|
|
70726
|
+
eq(project_exports.branchGroups.id, id),
|
|
70727
|
+
projectScopeFor(project_exports.branchGroups.projectId, projectId2)
|
|
70728
|
+
));
|
|
70729
|
+
const updated = await getBranchGroup(db, id, projectId2);
|
|
70537
70730
|
if (!updated) throw new Error(`Branch group ${id} disappeared after update`);
|
|
70538
70731
|
return updated;
|
|
70539
70732
|
}
|
|
@@ -70690,6 +70883,7 @@ var init_async_branch_groups = __esm({
|
|
|
70690
70883
|
"use strict";
|
|
70691
70884
|
init_drizzle_orm();
|
|
70692
70885
|
init_schema2();
|
|
70886
|
+
init_data_layer();
|
|
70693
70887
|
init_branch_assignment();
|
|
70694
70888
|
}
|
|
70695
70889
|
});
|
|
@@ -80503,6 +80697,9 @@ import { randomUUID as randomUUID21 } from "node:crypto";
|
|
|
80503
80697
|
function tableForScope(scope) {
|
|
80504
80698
|
return scope === "project" ? project_exports.secrets : central_exports.secretsGlobal;
|
|
80505
80699
|
}
|
|
80700
|
+
function scopeForSecretTable(scope, table, projectId2) {
|
|
80701
|
+
return scope === "project" ? projectScopeFor(table.projectId, projectId2) : void 0;
|
|
80702
|
+
}
|
|
80506
80703
|
function isAccessPolicy(value) {
|
|
80507
80704
|
return value === "auto" || value === "prompt" || value === "deny";
|
|
80508
80705
|
}
|
|
@@ -80525,23 +80722,23 @@ function rowToRecord2(row, scope) {
|
|
|
80525
80722
|
lastReadBy: row.lastReadBy
|
|
80526
80723
|
};
|
|
80527
80724
|
}
|
|
80528
|
-
async function getSecretMetadata(handle, id, scope) {
|
|
80725
|
+
async function getSecretMetadata(handle, id, scope, projectId2) {
|
|
80529
80726
|
const table = tableForScope(scope);
|
|
80530
|
-
const rows = await handle.select(metadataColumns(table)).from(table).where(eq(table.id, id)).limit(1);
|
|
80727
|
+
const rows = await handle.select(metadataColumns(table)).from(table).where(and(eq(table.id, id), scopeForSecretTable(scope, table, projectId2))).limit(1);
|
|
80531
80728
|
const row = rows[0];
|
|
80532
80729
|
return row ? rowToRecord2(row, scope) : null;
|
|
80533
80730
|
}
|
|
80534
|
-
async function listSecrets(handle, scope) {
|
|
80731
|
+
async function listSecrets(handle, scope, projectId2) {
|
|
80535
80732
|
if (scope) {
|
|
80536
80733
|
const table = tableForScope(scope);
|
|
80537
|
-
const rows = await handle.select(metadataColumns(table)).from(table).orderBy(asc(sql`lower(${table.key})`));
|
|
80734
|
+
const rows = await handle.select(metadataColumns(table)).from(table).where(scopeForSecretTable(scope, table, projectId2)).orderBy(asc(sql`lower(${table.key})`));
|
|
80538
80735
|
return rows.map((row) => rowToRecord2(row, scope));
|
|
80539
80736
|
}
|
|
80540
|
-
const project = await listSecrets(handle, "project");
|
|
80541
|
-
const global2 = await listSecrets(handle, "global");
|
|
80737
|
+
const project = await listSecrets(handle, "project", projectId2);
|
|
80738
|
+
const global2 = await listSecrets(handle, "global", projectId2);
|
|
80542
80739
|
return [...project, ...global2];
|
|
80543
80740
|
}
|
|
80544
|
-
async function createSecret(handle, cipher, input) {
|
|
80741
|
+
async function createSecret(handle, cipher, input, projectId2) {
|
|
80545
80742
|
const key = input.key.trim();
|
|
80546
80743
|
if (!key) {
|
|
80547
80744
|
throw new SecretsStoreError({ code: "invalid-key", message: "Secret key is required" });
|
|
@@ -80555,6 +80752,7 @@ async function createSecret(handle, cipher, input) {
|
|
|
80555
80752
|
const table = tableForScope(input.scope);
|
|
80556
80753
|
try {
|
|
80557
80754
|
await handle.insert(table).values({
|
|
80755
|
+
...input.scope === "project" && projectId2?.trim() ? { projectId: projectId2 } : {},
|
|
80558
80756
|
id,
|
|
80559
80757
|
key,
|
|
80560
80758
|
valueCiphertext: encrypted.ciphertext,
|
|
@@ -80574,14 +80772,14 @@ async function createSecret(handle, cipher, input) {
|
|
|
80574
80772
|
}
|
|
80575
80773
|
throw error3;
|
|
80576
80774
|
}
|
|
80577
|
-
const created = await getSecretMetadata(handle, id, input.scope);
|
|
80775
|
+
const created = await getSecretMetadata(handle, id, input.scope, projectId2);
|
|
80578
80776
|
if (!created) {
|
|
80579
80777
|
throw new SecretsStoreError({ code: "not-found", message: "Secret insert succeeded but row could not be read back" });
|
|
80580
80778
|
}
|
|
80581
80779
|
return created;
|
|
80582
80780
|
}
|
|
80583
|
-
async function updateSecret(handle, cipher, id, scope, patch) {
|
|
80584
|
-
const existing = await getSecretMetadata(handle, id, scope);
|
|
80781
|
+
async function updateSecret(handle, cipher, id, scope, patch, projectId2) {
|
|
80782
|
+
const existing = await getSecretMetadata(handle, id, scope, projectId2);
|
|
80585
80783
|
if (!existing) {
|
|
80586
80784
|
throw new SecretsStoreError({ code: "not-found", message: "Secret not found" });
|
|
80587
80785
|
}
|
|
@@ -80615,34 +80813,34 @@ async function updateSecret(handle, cipher, id, scope, patch) {
|
|
|
80615
80813
|
updates.nonce = encrypted.nonce;
|
|
80616
80814
|
}
|
|
80617
80815
|
try {
|
|
80618
|
-
await handle.update(table).set(updates).where(eq(table.id, id));
|
|
80816
|
+
await handle.update(table).set(updates).where(and(eq(table.id, id), scopeForSecretTable(scope, table, projectId2)));
|
|
80619
80817
|
} catch (error3) {
|
|
80620
80818
|
if (isPostgresUniqueError(error3)) {
|
|
80621
80819
|
throw new SecretsStoreError({ code: "duplicate-key", message: "Secret key already exists" });
|
|
80622
80820
|
}
|
|
80623
80821
|
throw error3;
|
|
80624
80822
|
}
|
|
80625
|
-
const updated = await getSecretMetadata(handle, id, scope);
|
|
80823
|
+
const updated = await getSecretMetadata(handle, id, scope, projectId2);
|
|
80626
80824
|
if (!updated) {
|
|
80627
80825
|
throw new SecretsStoreError({ code: "not-found", message: "Secret update succeeded but row could not be read back" });
|
|
80628
80826
|
}
|
|
80629
80827
|
return updated;
|
|
80630
80828
|
}
|
|
80631
|
-
async function deleteSecret(handle, id, scope) {
|
|
80632
|
-
const existing = await getSecretMetadata(handle, id, scope);
|
|
80829
|
+
async function deleteSecret(handle, id, scope, projectId2) {
|
|
80830
|
+
const existing = await getSecretMetadata(handle, id, scope, projectId2);
|
|
80633
80831
|
if (!existing) {
|
|
80634
80832
|
throw new SecretsStoreError({ code: "not-found", message: "Secret not found" });
|
|
80635
80833
|
}
|
|
80636
80834
|
const table = tableForScope(scope);
|
|
80637
|
-
await handle.delete(table).where(eq(table.id, id));
|
|
80835
|
+
await handle.delete(table).where(and(eq(table.id, id), scopeForSecretTable(scope, table, projectId2)));
|
|
80638
80836
|
}
|
|
80639
|
-
async function revealSecret(handle, cipher, id, scope, reader) {
|
|
80837
|
+
async function revealSecret(handle, cipher, id, scope, reader, projectId2) {
|
|
80640
80838
|
const table = tableForScope(scope);
|
|
80641
80839
|
const rows = await handle.select({
|
|
80642
80840
|
...metadataColumns(table),
|
|
80643
80841
|
valueCiphertext: table.valueCiphertext,
|
|
80644
80842
|
nonce: table.nonce
|
|
80645
|
-
}).from(table).where(eq(table.id, id)).limit(1);
|
|
80843
|
+
}).from(table).where(and(eq(table.id, id), scopeForSecretTable(scope, table, projectId2))).limit(1);
|
|
80646
80844
|
const row = rows[0];
|
|
80647
80845
|
if (!row) {
|
|
80648
80846
|
throw new SecretsStoreError({ code: "not-found", message: "Secret not found" });
|
|
@@ -80661,7 +80859,7 @@ async function revealSecret(handle, cipher, id, scope, reader) {
|
|
|
80661
80859
|
}
|
|
80662
80860
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
80663
80861
|
const lastReadBy = reader.userId ?? reader.agentId ?? null;
|
|
80664
|
-
await handle.update(table).set({ lastReadAt: now, lastReadBy, updatedAt: now }).where(eq(table.id, id));
|
|
80862
|
+
await handle.update(table).set({ lastReadAt: now, lastReadBy, updatedAt: now }).where(and(eq(table.id, id), scopeForSecretTable(scope, table, projectId2)));
|
|
80665
80863
|
return { key: row.key, plaintextValue };
|
|
80666
80864
|
}
|
|
80667
80865
|
var severityAuditLog10, SecretsStoreError, metadataColumns;
|
|
@@ -80672,6 +80870,7 @@ var init_async_secrets_store = __esm({
|
|
|
80672
80870
|
init_drizzle_orm();
|
|
80673
80871
|
init_postgres_errors();
|
|
80674
80872
|
init_schema2();
|
|
80873
|
+
init_data_layer();
|
|
80675
80874
|
init_secrets_crypto();
|
|
80676
80875
|
severityAuditLog10 = createLogger("core-async-secrets-store");
|
|
80677
80876
|
SecretsStoreError = class extends Error {
|
|
@@ -80767,7 +80966,7 @@ var init_secrets_store = __esm({
|
|
|
80767
80966
|
};
|
|
80768
80967
|
}
|
|
80769
80968
|
async listSecrets(scope) {
|
|
80770
|
-
return listSecrets(this.asyncLayer.db, scope);
|
|
80969
|
+
return listSecrets(this.asyncLayer.db, scope, this.asyncLayer.projectId);
|
|
80771
80970
|
}
|
|
80772
80971
|
async listEnvExportable(opts) {
|
|
80773
80972
|
const keyPrefix = opts?.keyPrefix;
|
|
@@ -80810,7 +81009,7 @@ var init_secrets_store = __esm({
|
|
|
80810
81009
|
return [...exported.values()];
|
|
80811
81010
|
}
|
|
80812
81011
|
async getSecretMetadata(id, scope) {
|
|
80813
|
-
return getSecretMetadata(this.asyncLayer.db, id, scope);
|
|
81012
|
+
return getSecretMetadata(this.asyncLayer.db, id, scope, this.asyncLayer.projectId);
|
|
80814
81013
|
}
|
|
80815
81014
|
async createSecret(input) {
|
|
80816
81015
|
const key = input.key.trim();
|
|
@@ -80820,12 +81019,12 @@ var init_secrets_store = __esm({
|
|
|
80820
81019
|
if (input.accessPolicy && !isAccessPolicy2(input.accessPolicy)) {
|
|
80821
81020
|
throw new SecretsStoreError2({ code: "invalid-policy", message: "Invalid access policy" });
|
|
80822
81021
|
}
|
|
80823
|
-
const created = await createSecret(this.asyncLayer.db, this.cipher, input);
|
|
81022
|
+
const created = await createSecret(this.asyncLayer.db, this.cipher, input, this.asyncLayer.projectId);
|
|
80824
81023
|
this.emitAudit({ mutationType: "secret:create", scope: input.scope, secretId: created.id, key: created.key });
|
|
80825
81024
|
return created;
|
|
80826
81025
|
}
|
|
80827
81026
|
async updateSecret(id, scope, patch) {
|
|
80828
|
-
const updated = await updateSecret(this.asyncLayer.db, this.cipher, id, scope, patch);
|
|
81027
|
+
const updated = await updateSecret(this.asyncLayer.db, this.cipher, id, scope, patch, this.asyncLayer.projectId);
|
|
80829
81028
|
this.emitAudit({ mutationType: "secret:update", scope, secretId: updated.id, key: updated.key });
|
|
80830
81029
|
return updated;
|
|
80831
81030
|
}
|
|
@@ -80834,12 +81033,12 @@ var init_secrets_store = __esm({
|
|
|
80834
81033
|
if (!existing) {
|
|
80835
81034
|
throw new SecretsStoreError2({ code: "not-found", message: "Secret not found" });
|
|
80836
81035
|
}
|
|
80837
|
-
await deleteSecret(this.asyncLayer.db, id, scope);
|
|
81036
|
+
await deleteSecret(this.asyncLayer.db, id, scope, this.asyncLayer.projectId);
|
|
80838
81037
|
this.emitAudit({ mutationType: "secret:delete", scope, secretId: id, key: existing.key });
|
|
80839
81038
|
return;
|
|
80840
81039
|
}
|
|
80841
81040
|
async revealSecret(id, scope, reader) {
|
|
80842
|
-
const revealed = await revealSecret(this.asyncLayer.db, this.cipher, id, scope, reader);
|
|
81041
|
+
const revealed = await revealSecret(this.asyncLayer.db, this.cipher, id, scope, reader, this.asyncLayer.projectId);
|
|
80843
81042
|
this.emitAudit({ mutationType: "secret:read", scope, secretId: id, key: revealed.key, actor: reader });
|
|
80844
81043
|
return revealed;
|
|
80845
81044
|
}
|
|
@@ -81940,6 +82139,7 @@ async function getVerificationCacheHitImpl(store, treeSha, testCommand, buildCom
|
|
|
81940
82139
|
const normalizedBuild = buildCommand2 ?? "";
|
|
81941
82140
|
const table = project_exports.verificationCache;
|
|
81942
82141
|
const rows = await store.asyncLayer.db.select({ recordedAt: table.recordedAt, taskId: table.taskId }).from(table).where(and(
|
|
82142
|
+
projectScopeFor(table.projectId, store.asyncLayer.projectId),
|
|
81943
82143
|
eq(table.treeSha, treeSha),
|
|
81944
82144
|
eq(table.testCommand, normalizedTest),
|
|
81945
82145
|
eq(table.buildCommand, normalizedBuild)
|
|
@@ -82682,7 +82882,7 @@ async function invokeTaskCreatedHookImpl(store, task) {
|
|
|
82682
82882
|
}
|
|
82683
82883
|
async function createBranchGroupImpl(store, input) {
|
|
82684
82884
|
const layer = store.asyncLayer;
|
|
82685
|
-
return createBranchGroup(layer.db, input);
|
|
82885
|
+
return createBranchGroup(layer.db, input, layer.projectId);
|
|
82686
82886
|
}
|
|
82687
82887
|
var init_task_id_integrity2 = __esm({
|
|
82688
82888
|
"../core/src/task-store/task-id-integrity.ts"() {
|
|
@@ -82767,22 +82967,23 @@ import { readFile as readFile7, writeFile as writeFile5 } from "node:fs/promises
|
|
|
82767
82967
|
import { join as join23 } from "node:path";
|
|
82768
82968
|
async function getBranchGroupImpl(store, id) {
|
|
82769
82969
|
const layer = store.asyncLayer;
|
|
82770
|
-
return getBranchGroup(layer.db, id);
|
|
82970
|
+
return getBranchGroup(layer.db, id, layer.projectId);
|
|
82771
82971
|
}
|
|
82772
82972
|
async function getBranchGroupBySourceImpl(store, sourceType, sourceId) {
|
|
82773
82973
|
const layer = store.asyncLayer;
|
|
82774
|
-
return getBranchGroupBySource(layer.db, sourceType, sourceId);
|
|
82974
|
+
return getBranchGroupBySource(layer.db, sourceType, sourceId, layer.projectId);
|
|
82775
82975
|
}
|
|
82776
82976
|
async function getBranchGroupByBranchNameImpl(store, branchName) {
|
|
82777
82977
|
const layer = store.asyncLayer;
|
|
82778
|
-
return getBranchGroupByBranchName(layer.db, branchName);
|
|
82978
|
+
return getBranchGroupByBranchName(layer.db, branchName, layer.projectId);
|
|
82779
82979
|
}
|
|
82780
82980
|
async function ensureBranchGroupForSourceImpl(store, sourceType, sourceId, init) {
|
|
82781
|
-
|
|
82981
|
+
const layer = store.asyncLayer;
|
|
82982
|
+
return ensureBranchGroupForSource(layer.db, sourceType, sourceId, init, layer.projectId);
|
|
82782
82983
|
}
|
|
82783
82984
|
async function listBranchGroupsImpl(store, options) {
|
|
82784
82985
|
const layer = store.asyncLayer;
|
|
82785
|
-
return listBranchGroups(layer.db, options);
|
|
82986
|
+
return listBranchGroups(layer.db, options, layer.projectId);
|
|
82786
82987
|
}
|
|
82787
82988
|
async function listTasksByBranchGroupImpl(store, groupId) {
|
|
82788
82989
|
const tasks2 = await store.listTasks({ includeArchived: true, slim: false });
|
|
@@ -84324,7 +84525,7 @@ function insertArtifactRowImpl(store, input, id, now, stored) {
|
|
|
84324
84525
|
}
|
|
84325
84526
|
async function getArtifactImpl(store, id) {
|
|
84326
84527
|
const layer = store.asyncLayer;
|
|
84327
|
-
return getArtifact(layer.db, id);
|
|
84528
|
+
return getArtifact(layer.db, id, layer.projectId);
|
|
84328
84529
|
}
|
|
84329
84530
|
async function updateArtifactImpl(store, id, updates) {
|
|
84330
84531
|
const layer = store.asyncLayer;
|
|
@@ -89193,6 +89394,7 @@ var init_async_archive_lineage = __esm({
|
|
|
89193
89394
|
"use strict";
|
|
89194
89395
|
init_drizzle_orm();
|
|
89195
89396
|
init_schema2();
|
|
89397
|
+
init_data_layer();
|
|
89196
89398
|
init_async_persistence();
|
|
89197
89399
|
init_async_lifecycle();
|
|
89198
89400
|
init_lineage_approval_invalidation();
|
|
@@ -92660,7 +92862,7 @@ async function _maybeAutoArchiveSameAgentDuplicateBackendImpl(store, task, input
|
|
|
92660
92862
|
}
|
|
92661
92863
|
async function updateBranchGroupImpl(store, id, patch) {
|
|
92662
92864
|
const layer = store.asyncLayer;
|
|
92663
|
-
return updateBranchGroup(layer.db, id, patch);
|
|
92865
|
+
return updateBranchGroup(layer.db, id, patch, layer.projectId);
|
|
92664
92866
|
}
|
|
92665
92867
|
async function updatePrEntityImpl(store, id, patch) {
|
|
92666
92868
|
const layer = store.asyncLayer;
|
|
@@ -93170,13 +93372,19 @@ async function deleteAttachmentArtifactRows(store, taskId, filename) {
|
|
|
93170
93372
|
const linkedArtifactIds = artifacts2.filter((artifact) => artifact.metadata?.source === "attachment" && artifact.metadata.attachmentFilename === filename).map((artifact) => artifact.id);
|
|
93171
93373
|
if (linkedArtifactIds.length === 0) return;
|
|
93172
93374
|
for (const artifactId of linkedArtifactIds) {
|
|
93173
|
-
await layer.db.delete(project_exports.artifacts).where(
|
|
93375
|
+
await layer.db.delete(project_exports.artifacts).where(and(
|
|
93376
|
+
eq(project_exports.artifacts.id, artifactId),
|
|
93377
|
+
projectScopeFor(project_exports.artifacts.projectId, layer.projectId)
|
|
93378
|
+
));
|
|
93174
93379
|
}
|
|
93175
93380
|
return;
|
|
93176
93381
|
}
|
|
93177
93382
|
async function getArtifactsForAttachmentCleanup(store, taskId) {
|
|
93178
93383
|
const layer = store.asyncLayer;
|
|
93179
|
-
const rows = await layer.db.select().from(project_exports.artifacts).where(
|
|
93384
|
+
const rows = await layer.db.select().from(project_exports.artifacts).where(and(
|
|
93385
|
+
eq(project_exports.artifacts.taskId, taskId),
|
|
93386
|
+
projectScopeFor(project_exports.artifacts.projectId, layer.projectId)
|
|
93387
|
+
));
|
|
93180
93388
|
return rows;
|
|
93181
93389
|
}
|
|
93182
93390
|
async function deleteAttachmentImpl(store, id, filename) {
|
|
@@ -95592,7 +95800,7 @@ function clearLinkedAgentTaskIdsImpl(store, taskId, updatedAt = (/* @__PURE__ */
|
|
|
95592
95800
|
`).run(updatedAt, updatedAt, taskId);
|
|
95593
95801
|
}
|
|
95594
95802
|
async function listArtifactsImpl(store, options) {
|
|
95595
|
-
return listArtifacts(store.asyncLayer.db, options);
|
|
95803
|
+
return listArtifacts(store.asyncLayer.db, options, store.asyncLayer.projectId);
|
|
95596
95804
|
}
|
|
95597
95805
|
async function rehomeOccupantImpl(store, taskId, targetColumn, reason, metadata) {
|
|
95598
95806
|
let current;
|
|
@@ -96837,8 +97045,8 @@ async function upsertWorkflowWorkItemImpl(store, input, tx) {
|
|
|
96837
97045
|
async function replaceActiveTaskWorkflowContinuationImpl(store, input) {
|
|
96838
97046
|
return replaceActiveTaskWorkflowContinuation(store.asyncLayer, input);
|
|
96839
97047
|
}
|
|
96840
|
-
async function seedStrandedPlanReviewContinuationImpl(store, input) {
|
|
96841
|
-
return seedStrandedPlanReviewContinuation(store.asyncLayer, input);
|
|
97048
|
+
async function seedStrandedPlanReviewContinuationImpl(store, input, options = {}) {
|
|
97049
|
+
return seedStrandedPlanReviewContinuation(store.asyncLayer, input, options);
|
|
96842
97050
|
}
|
|
96843
97051
|
async function transitionWorkflowWorkItemImpl(store, id, state, patch = {}, tx) {
|
|
96844
97052
|
return transitionWorkflowWorkItem(store.asyncLayer, id, state, patch, tx);
|
|
@@ -100981,6 +101189,37 @@ async function getTaskVerificationRequestAsyncImpl(store, taskId) {
|
|
|
100981
101189
|
const row = rows[0];
|
|
100982
101190
|
return row ? { taskId: row.taskId, requestId: row.requestId, status: row.status, profile: row.profile, command: row.command, scope: row.scope, requestedBy: row.requestedBy, requestedAt: row.requestedAt, ...row.startedAt ? { startedAt: row.startedAt } : {}, ...row.completedAt ? { completedAt: row.completedAt } : {}, ...row.result ? { result: row.result } : {}, ...row.rejectionReason ? { rejectionReason: row.rejectionReason } : {} } : null;
|
|
100983
101191
|
}
|
|
101192
|
+
async function listTaskRecommendationsImpl(store, options) {
|
|
101193
|
+
const layer = store.asyncLayer;
|
|
101194
|
+
const completeColumns = options?.completeColumns ?? await resolveProjectColumnsForRoles(store, ["complete"]);
|
|
101195
|
+
const rawLimit = options?.limit;
|
|
101196
|
+
const rawOffset = options?.offset;
|
|
101197
|
+
const limit = typeof rawLimit === "number" && Number.isFinite(rawLimit) ? Math.min(200, Math.max(1, Math.trunc(rawLimit))) : 50;
|
|
101198
|
+
const offset = typeof rawOffset === "number" && Number.isFinite(rawOffset) ? Math.max(0, Math.trunc(rawOffset)) : 0;
|
|
101199
|
+
const columns = [...completeColumns];
|
|
101200
|
+
if (columns.length === 0) return { items: [], rowOffset: offset, rowLimit: limit, returnedRowCount: 0, totalRowCount: 0, hasMore: false };
|
|
101201
|
+
const filter = and(
|
|
101202
|
+
taskProjectScope(layer),
|
|
101203
|
+
isNull(project_exports.tasks.deletedAt),
|
|
101204
|
+
inArray(project_exports.tasks.column, columns),
|
|
101205
|
+
isNotNull(project_exports.tasks.recommendations),
|
|
101206
|
+
sql`jsonb_array_length(${project_exports.tasks.recommendations}) > 0`
|
|
101207
|
+
);
|
|
101208
|
+
const [countRows, rows] = await Promise.all([
|
|
101209
|
+
layer.db.select({ count: sql`count(*)` }).from(project_exports.tasks).where(filter),
|
|
101210
|
+
layer.db.select({ id: project_exports.tasks.id, title: project_exports.tasks.title, column: project_exports.tasks.column, updatedAt: project_exports.tasks.updatedAt, recommendations: project_exports.tasks.recommendations }).from(project_exports.tasks).where(filter).orderBy(desc(project_exports.tasks.updatedAt), desc(project_exports.tasks.id)).limit(limit).offset(offset)
|
|
101211
|
+
]);
|
|
101212
|
+
const items = [];
|
|
101213
|
+
for (const row of rows) {
|
|
101214
|
+
if (!Array.isArray(row.recommendations) || row.recommendations.length === 0) continue;
|
|
101215
|
+
for (const recommendation of row.recommendations) {
|
|
101216
|
+
items.push({ taskId: row.id, taskTitle: row.title ?? void 0, taskColumn: row.column, updatedAt: row.updatedAt, recommendation });
|
|
101217
|
+
}
|
|
101218
|
+
}
|
|
101219
|
+
const totalRowCount = Number(countRows[0]?.count ?? 0);
|
|
101220
|
+
const returnedRowCount = rows.length;
|
|
101221
|
+
return { items, rowOffset: offset, rowLimit: limit, returnedRowCount, totalRowCount, hasMore: offset + returnedRowCount < totalRowCount };
|
|
101222
|
+
}
|
|
100984
101223
|
var LEGACY_REVIEW_LANES5, LEGACY_ARCHIVE_LANES2;
|
|
100985
101224
|
var init_reads = __esm({
|
|
100986
101225
|
"../core/src/task-store/reads.ts"() {
|
|
@@ -101003,6 +101242,7 @@ var init_reads = __esm({
|
|
|
101003
101242
|
init_retry_summary();
|
|
101004
101243
|
init_errors3();
|
|
101005
101244
|
init_project_lane_vocabulary();
|
|
101245
|
+
init_data_layer();
|
|
101006
101246
|
init_async_persistence();
|
|
101007
101247
|
init_async_search();
|
|
101008
101248
|
init_async_archive_db();
|
|
@@ -103109,6 +103349,9 @@ var init_store = __esm({
|
|
|
103109
103349
|
async clearWorkflowRunStepInstancesAsync(taskId, keepRunId) {
|
|
103110
103350
|
return clearWorkflowRunStepInstancesAsyncImpl(this, taskId, keepRunId);
|
|
103111
103351
|
}
|
|
103352
|
+
async listTaskRecommendations(options) {
|
|
103353
|
+
return listTaskRecommendationsImpl(this, options);
|
|
103354
|
+
}
|
|
103112
103355
|
async listTasksForGithubTrackingReconcile(options) {
|
|
103113
103356
|
return listTasksForGithubTrackingReconcileImpl(this, options);
|
|
103114
103357
|
}
|
|
@@ -103835,8 +104078,8 @@ var init_store = __esm({
|
|
|
103835
104078
|
async replaceActiveTaskWorkflowContinuation(input) {
|
|
103836
104079
|
return replaceActiveTaskWorkflowContinuationImpl(this, input);
|
|
103837
104080
|
}
|
|
103838
|
-
async seedStrandedPlanReviewContinuation(input) {
|
|
103839
|
-
return seedStrandedPlanReviewContinuationImpl(this, input);
|
|
104081
|
+
async seedStrandedPlanReviewContinuation(input, options = {}) {
|
|
104082
|
+
return seedStrandedPlanReviewContinuationImpl(this, input, options);
|
|
103840
104083
|
}
|
|
103841
104084
|
async transitionWorkflowWorkItem(id, state, patch = {}, tx) {
|
|
103842
104085
|
return transitionWorkflowWorkItemImpl(this, id, state, patch, tx);
|
|
@@ -103919,7 +104162,11 @@ var init_store = __esm({
|
|
|
103919
104162
|
/** PostgreSQL-authoritative audit reader; sync fallback remains for test doubles. */
|
|
103920
104163
|
async getRunAuditEventsAsync(options = {}) {
|
|
103921
104164
|
if (this.asyncLayer) {
|
|
103922
|
-
const events = await queryRunAuditEvents(
|
|
104165
|
+
const events = await queryRunAuditEvents(
|
|
104166
|
+
this.asyncLayer.db,
|
|
104167
|
+
options,
|
|
104168
|
+
this.asyncLayer.projectId
|
|
104169
|
+
);
|
|
103923
104170
|
return events.map((event) => ({
|
|
103924
104171
|
...event,
|
|
103925
104172
|
taskId: event.taskId ?? void 0,
|
|
@@ -107497,7 +107744,9 @@ function rangeWhere(query) {
|
|
|
107497
107744
|
async function aggregatePluginActivations(dbOrLayer, query = {}) {
|
|
107498
107745
|
if ("ping" in dbOrLayer) {
|
|
107499
107746
|
const layer = dbOrLayer;
|
|
107500
|
-
const conditions = []
|
|
107747
|
+
const conditions = [projectScopeFor(project_exports.pluginActivations.projectId, layer.projectId)].filter(
|
|
107748
|
+
(condition) => condition !== void 0
|
|
107749
|
+
);
|
|
107501
107750
|
if (query.from !== void 0) conditions.push(gte(project_exports.pluginActivations.activatedAt, query.from));
|
|
107502
107751
|
if (query.to !== void 0) conditions.push(lte(project_exports.pluginActivations.activatedAt, query.to));
|
|
107503
107752
|
const where2 = conditions.length > 0 ? and(...conditions) : void 0;
|
|
@@ -107536,6 +107785,7 @@ async function aggregatePluginActivations(dbOrLayer, query = {}) {
|
|
|
107536
107785
|
var init_plugin_activation_analytics = __esm({
|
|
107537
107786
|
"../core/src/plugins/plugin-activation-analytics.ts"() {
|
|
107538
107787
|
"use strict";
|
|
107788
|
+
init_data_layer();
|
|
107539
107789
|
init_drizzle_orm();
|
|
107540
107790
|
init_schema2();
|
|
107541
107791
|
}
|
|
@@ -130533,6 +130783,18 @@ function rowToMessage2(row) {
|
|
|
130533
130783
|
createdAt: row.createdAt
|
|
130534
130784
|
};
|
|
130535
130785
|
}
|
|
130786
|
+
function chatMessageProjectConditions(handle, projectId2) {
|
|
130787
|
+
const messageScope = projectScopeFor(project_exports.chatMessages.projectId, projectId2);
|
|
130788
|
+
const sessionScope = projectScopeFor(project_exports.chatSessions.projectId, projectId2);
|
|
130789
|
+
if (!messageScope || !sessionScope) return [];
|
|
130790
|
+
return [
|
|
130791
|
+
messageScope,
|
|
130792
|
+
exists(handle.select({ id: project_exports.chatSessions.id }).from(project_exports.chatSessions).where(and(
|
|
130793
|
+
eq(project_exports.chatSessions.id, project_exports.chatMessages.sessionId),
|
|
130794
|
+
sessionScope
|
|
130795
|
+
)))
|
|
130796
|
+
];
|
|
130797
|
+
}
|
|
130536
130798
|
function rowToRoom(row) {
|
|
130537
130799
|
return {
|
|
130538
130800
|
id: row.id,
|
|
@@ -130704,7 +130966,7 @@ async function replaceChatSessionTags(layer, sessionId, projectId2, tagIds) {
|
|
|
130704
130966
|
return attachTags(tx, session);
|
|
130705
130967
|
});
|
|
130706
130968
|
}
|
|
130707
|
-
async function addChatMessage(handle, message) {
|
|
130969
|
+
async function addChatMessage(handle, message, projectId2) {
|
|
130708
130970
|
const sanitizedAttachments = message.attachments === void 0 ? void 0 : sanitizeJsonbValue(message.attachments);
|
|
130709
130971
|
const sanitized = {
|
|
130710
130972
|
...message,
|
|
@@ -130723,15 +130985,24 @@ async function addChatMessage(handle, message) {
|
|
|
130723
130985
|
attachments: sanitizedAttachments ?? null,
|
|
130724
130986
|
createdAt: sanitized.createdAt
|
|
130725
130987
|
});
|
|
130726
|
-
await handle.update(project_exports.chatSessions).set({ updatedAt: sanitized.createdAt }).where(
|
|
130988
|
+
await handle.update(project_exports.chatSessions).set({ updatedAt: sanitized.createdAt }).where(and(
|
|
130989
|
+
eq(project_exports.chatSessions.id, sanitized.sessionId),
|
|
130990
|
+
projectScopeFor(project_exports.chatSessions.projectId, projectId2)
|
|
130991
|
+
));
|
|
130727
130992
|
return sanitized;
|
|
130728
130993
|
}
|
|
130729
|
-
async function getChatMessage(handle, id) {
|
|
130730
|
-
const rows = await handle.select().from(project_exports.chatMessages).where(
|
|
130994
|
+
async function getChatMessage(handle, id, projectId2) {
|
|
130995
|
+
const rows = await handle.select().from(project_exports.chatMessages).where(and(
|
|
130996
|
+
eq(project_exports.chatMessages.id, id),
|
|
130997
|
+
...chatMessageProjectConditions(handle, projectId2)
|
|
130998
|
+
));
|
|
130731
130999
|
return rows[0] ? rowToMessage2(rows[0]) : void 0;
|
|
130732
131000
|
}
|
|
130733
|
-
async function getChatMessages(handle, sessionId, filter) {
|
|
130734
|
-
const conditions = [
|
|
131001
|
+
async function getChatMessages(handle, sessionId, filter, projectId2) {
|
|
131002
|
+
const conditions = [
|
|
131003
|
+
eq(project_exports.chatMessages.sessionId, sessionId),
|
|
131004
|
+
...chatMessageProjectConditions(handle, projectId2)
|
|
131005
|
+
];
|
|
130735
131006
|
if (filter?.before) {
|
|
130736
131007
|
conditions.push(lte(project_exports.chatMessages.createdAt, filter.before));
|
|
130737
131008
|
}
|
|
@@ -130741,9 +131012,12 @@ async function getChatMessages(handle, sessionId, filter) {
|
|
|
130741
131012
|
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
131013
|
return rows.map(rowToMessage2);
|
|
130743
131014
|
}
|
|
130744
|
-
async function getLastMessageForSessions(handle, sessionIds) {
|
|
131015
|
+
async function getLastMessageForSessions(handle, sessionIds, projectId2) {
|
|
130745
131016
|
if (sessionIds.length === 0) return /* @__PURE__ */ new Map();
|
|
130746
|
-
const rows = await handle.select().from(project_exports.chatMessages).where(
|
|
131017
|
+
const rows = await handle.select().from(project_exports.chatMessages).where(and(
|
|
131018
|
+
inArray(project_exports.chatMessages.sessionId, sessionIds),
|
|
131019
|
+
...chatMessageProjectConditions(handle, projectId2)
|
|
131020
|
+
)).orderBy(
|
|
130747
131021
|
desc(project_exports.chatMessages.createdAt),
|
|
130748
131022
|
desc(project_exports.chatMessages.id)
|
|
130749
131023
|
);
|
|
@@ -130909,8 +131183,8 @@ async function setInFlightGeneration(handle, id, inFlightGeneration) {
|
|
|
130909
131183
|
await handle.update(project_exports.chatSessions).set({ inFlightGeneration: sanitizedInFlightGeneration }).where(eq(project_exports.chatSessions.id, id));
|
|
130910
131184
|
return getChatSession(handle, id);
|
|
130911
131185
|
}
|
|
130912
|
-
async function addChatMessageAttachment(handle, sessionId, messageId, attachment) {
|
|
130913
|
-
const message = await getChatMessage(handle, messageId);
|
|
131186
|
+
async function addChatMessageAttachment(handle, sessionId, messageId, attachment, projectId2) {
|
|
131187
|
+
const message = await getChatMessage(handle, messageId, projectId2);
|
|
130914
131188
|
if (!message || message.sessionId !== sessionId) {
|
|
130915
131189
|
throw new Error(`Message ${messageId} not found in session ${sessionId}`);
|
|
130916
131190
|
}
|
|
@@ -130918,25 +131192,35 @@ async function addChatMessageAttachment(handle, sessionId, messageId, attachment
|
|
|
130918
131192
|
...message.attachments ?? [],
|
|
130919
131193
|
attachment
|
|
130920
131194
|
]);
|
|
130921
|
-
await handle.update(project_exports.chatMessages).set({ attachments: updatedAttachments }).where(
|
|
130922
|
-
|
|
131195
|
+
await handle.update(project_exports.chatMessages).set({ attachments: updatedAttachments }).where(and(
|
|
131196
|
+
eq(project_exports.chatMessages.id, messageId),
|
|
131197
|
+
...chatMessageProjectConditions(handle, projectId2)
|
|
131198
|
+
));
|
|
131199
|
+
const updated = await getChatMessage(handle, messageId, projectId2);
|
|
130923
131200
|
if (!updated) throw new Error(`Failed to update message ${messageId}`);
|
|
130924
131201
|
return updated;
|
|
130925
131202
|
}
|
|
130926
|
-
async function deleteChatMessage(handle, id) {
|
|
130927
|
-
const existing = await getChatMessage(handle, id);
|
|
131203
|
+
async function deleteChatMessage(handle, id, projectId2) {
|
|
131204
|
+
const existing = await getChatMessage(handle, id, projectId2);
|
|
130928
131205
|
if (!existing) return false;
|
|
130929
|
-
await handle.delete(project_exports.chatMessages).where(
|
|
130930
|
-
|
|
131206
|
+
await handle.delete(project_exports.chatMessages).where(and(
|
|
131207
|
+
eq(project_exports.chatMessages.id, id),
|
|
131208
|
+
...chatMessageProjectConditions(handle, projectId2)
|
|
131209
|
+
));
|
|
131210
|
+
await handle.update(project_exports.chatSessions).set({ updatedAt: (/* @__PURE__ */ new Date()).toISOString() }).where(and(
|
|
131211
|
+
eq(project_exports.chatSessions.id, existing.sessionId),
|
|
131212
|
+
projectScopeFor(project_exports.chatSessions.projectId, projectId2)
|
|
131213
|
+
));
|
|
130931
131214
|
return true;
|
|
130932
131215
|
}
|
|
130933
|
-
async function searchChatSessionsByMessageContent(handle, query, sessionIds) {
|
|
131216
|
+
async function searchChatSessionsByMessageContent(handle, query, sessionIds, projectId2) {
|
|
130934
131217
|
const trimmed = query.trim();
|
|
130935
131218
|
if (!trimmed || sessionIds.length === 0) return /* @__PURE__ */ new Map();
|
|
130936
131219
|
const escaped = trimmed.replace(/\\/g, "\\\\").replace(/%/g, "\\%").replace(/_/g, "\\_");
|
|
130937
131220
|
const rows = await handle.select().from(project_exports.chatMessages).where(and(
|
|
130938
131221
|
inArray(project_exports.chatMessages.sessionId, sessionIds),
|
|
130939
|
-
ilike(project_exports.chatMessages.content, `%${escaped}%`)
|
|
131222
|
+
ilike(project_exports.chatMessages.content, `%${escaped}%`),
|
|
131223
|
+
...chatMessageProjectConditions(handle, projectId2)
|
|
130940
131224
|
)).orderBy(
|
|
130941
131225
|
desc(project_exports.chatMessages.createdAt),
|
|
130942
131226
|
desc(project_exports.chatMessages.id)
|
|
@@ -130950,13 +131234,16 @@ async function searchChatSessionsByMessageContent(handle, query, sessionIds) {
|
|
|
130950
131234
|
}
|
|
130951
131235
|
return result2;
|
|
130952
131236
|
}
|
|
130953
|
-
async function deleteChatMessagesFrom(handle, sessionId, fromMessageId) {
|
|
130954
|
-
const orderedRows = await handle.select().from(project_exports.chatMessages).where(
|
|
131237
|
+
async function deleteChatMessagesFrom(handle, sessionId, fromMessageId, projectId2) {
|
|
131238
|
+
const orderedRows = await handle.select().from(project_exports.chatMessages).where(and(
|
|
131239
|
+
eq(project_exports.chatMessages.sessionId, sessionId),
|
|
131240
|
+
...chatMessageProjectConditions(handle, projectId2)
|
|
131241
|
+
)).orderBy(
|
|
130955
131242
|
asc(project_exports.chatMessages.createdAt),
|
|
130956
131243
|
asc(project_exports.chatMessages.id)
|
|
130957
131244
|
);
|
|
130958
131245
|
const ordered2 = orderedRows.map(rowToMessage2);
|
|
130959
|
-
const target = await getChatMessage(handle, fromMessageId);
|
|
131246
|
+
const target = await getChatMessage(handle, fromMessageId, projectId2);
|
|
130960
131247
|
if (!target || target.sessionId !== sessionId) {
|
|
130961
131248
|
return { deletedIds: [], retained: ordered2 };
|
|
130962
131249
|
}
|
|
@@ -130969,19 +131256,28 @@ async function deleteChatMessagesFrom(handle, sessionId, fromMessageId) {
|
|
|
130969
131256
|
if (deletedIds.length === 0) {
|
|
130970
131257
|
return { deletedIds: [], retained };
|
|
130971
131258
|
}
|
|
130972
|
-
await handle.delete(project_exports.chatMessages).where(
|
|
130973
|
-
|
|
131259
|
+
await handle.delete(project_exports.chatMessages).where(and(
|
|
131260
|
+
inArray(project_exports.chatMessages.id, deletedIds),
|
|
131261
|
+
...chatMessageProjectConditions(handle, projectId2)
|
|
131262
|
+
));
|
|
131263
|
+
await handle.update(project_exports.chatSessions).set({ updatedAt: (/* @__PURE__ */ new Date()).toISOString() }).where(and(
|
|
131264
|
+
eq(project_exports.chatSessions.id, sessionId),
|
|
131265
|
+
projectScopeFor(project_exports.chatSessions.projectId, projectId2)
|
|
131266
|
+
));
|
|
130974
131267
|
return { deletedIds, retained };
|
|
130975
131268
|
}
|
|
130976
|
-
async function updateChatMessageMetadata(handle, messageId, metadata, options) {
|
|
130977
|
-
const existing = await getChatMessage(handle, messageId);
|
|
131269
|
+
async function updateChatMessageMetadata(handle, messageId, metadata, options, projectId2) {
|
|
131270
|
+
const existing = await getChatMessage(handle, messageId, projectId2);
|
|
130978
131271
|
if (!existing) {
|
|
130979
131272
|
throw new Error(`Message ${messageId} not found`);
|
|
130980
131273
|
}
|
|
130981
131274
|
const merge2 = options?.merge !== false;
|
|
130982
131275
|
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(
|
|
130984
|
-
|
|
131276
|
+
await handle.update(project_exports.chatMessages).set({ metadata: sanitizeJsonbValue(nextMetadata) ?? null }).where(and(
|
|
131277
|
+
eq(project_exports.chatMessages.id, messageId),
|
|
131278
|
+
...chatMessageProjectConditions(handle, projectId2)
|
|
131279
|
+
));
|
|
131280
|
+
const updated = await getChatMessage(handle, messageId, projectId2);
|
|
130985
131281
|
if (!updated) {
|
|
130986
131282
|
throw new Error(`Failed to update message ${messageId}`);
|
|
130987
131283
|
}
|
|
@@ -131363,7 +131659,7 @@ var init_chat_store = __esm({
|
|
|
131363
131659
|
attachments: input.attachments,
|
|
131364
131660
|
createdAt: now
|
|
131365
131661
|
};
|
|
131366
|
-
const created = await addChatMessage(this.asyncLayer.db, message);
|
|
131662
|
+
const created = await addChatMessage(this.asyncLayer.db, message, this.asyncLayer.projectId);
|
|
131367
131663
|
this.emit("chat:message:added", created);
|
|
131368
131664
|
return created;
|
|
131369
131665
|
}
|
|
@@ -131371,7 +131667,7 @@ var init_chat_store = __esm({
|
|
|
131371
131667
|
* Append a file attachment metadata record to an existing message.
|
|
131372
131668
|
*/
|
|
131373
131669
|
async addMessageAttachment(sessionId, messageId, attachment) {
|
|
131374
|
-
const updated = await addChatMessageAttachment(this.asyncLayer.db, sessionId, messageId, attachment);
|
|
131670
|
+
const updated = await addChatMessageAttachment(this.asyncLayer.db, sessionId, messageId, attachment, this.asyncLayer.projectId);
|
|
131375
131671
|
this.emit("chat:message:updated", updated);
|
|
131376
131672
|
return updated;
|
|
131377
131673
|
}
|
|
@@ -131383,7 +131679,7 @@ var init_chat_store = __esm({
|
|
|
131383
131679
|
* @returns Array of messages ordered by createdAt ASC (default) or DESC
|
|
131384
131680
|
*/
|
|
131385
131681
|
async getMessages(sessionId, filter) {
|
|
131386
|
-
return getChatMessages(this.asyncLayer.db, sessionId, filter);
|
|
131682
|
+
return getChatMessages(this.asyncLayer.db, sessionId, filter, this.asyncLayer.projectId);
|
|
131387
131683
|
}
|
|
131388
131684
|
/**
|
|
131389
131685
|
* Get a message by ID.
|
|
@@ -131392,7 +131688,7 @@ var init_chat_store = __esm({
|
|
|
131392
131688
|
* @returns The message, or undefined if not found
|
|
131393
131689
|
*/
|
|
131394
131690
|
async getMessage(id) {
|
|
131395
|
-
return getChatMessage(this.asyncLayer.db, id);
|
|
131691
|
+
return getChatMessage(this.asyncLayer.db, id, this.asyncLayer.projectId);
|
|
131396
131692
|
}
|
|
131397
131693
|
/**
|
|
131398
131694
|
* Get the latest message for each session in the provided list.
|
|
@@ -131402,10 +131698,10 @@ var init_chat_store = __esm({
|
|
|
131402
131698
|
* @returns Map of sessionId -> latest ChatMessage for that session
|
|
131403
131699
|
*/
|
|
131404
131700
|
async getLastMessageForSessions(sessionIds) {
|
|
131405
|
-
return getLastMessageForSessions(this.asyncLayer.db, sessionIds);
|
|
131701
|
+
return getLastMessageForSessions(this.asyncLayer.db, sessionIds, this.asyncLayer.projectId);
|
|
131406
131702
|
}
|
|
131407
131703
|
async hasMessages(sessionId) {
|
|
131408
|
-
return (await getChatMessages(this.asyncLayer.db, sessionId, { limit: 1 })).length > 0;
|
|
131704
|
+
return (await getChatMessages(this.asyncLayer.db, sessionId, { limit: 1 }, this.asyncLayer.projectId)).length > 0;
|
|
131409
131705
|
}
|
|
131410
131706
|
/**
|
|
131411
131707
|
* Search sessions by message content (not just title/agentId).
|
|
@@ -131433,7 +131729,7 @@ var init_chat_store = __esm({
|
|
|
131433
131729
|
if (!trimmed || !sessionIds || sessionIds.length === 0) {
|
|
131434
131730
|
return /* @__PURE__ */ new Map();
|
|
131435
131731
|
}
|
|
131436
|
-
return searchChatSessionsByMessageContent(this.asyncLayer.db, trimmed, sessionIds);
|
|
131732
|
+
return searchChatSessionsByMessageContent(this.asyncLayer.db, trimmed, sessionIds, this.asyncLayer.projectId);
|
|
131437
131733
|
}
|
|
131438
131734
|
/**
|
|
131439
131735
|
* Delete a message by ID.
|
|
@@ -131442,9 +131738,9 @@ var init_chat_store = __esm({
|
|
|
131442
131738
|
* @returns true if deleted, false if not found
|
|
131443
131739
|
*/
|
|
131444
131740
|
async deleteMessage(id) {
|
|
131445
|
-
const existing = await getChatMessage(this.asyncLayer.db, id);
|
|
131741
|
+
const existing = await getChatMessage(this.asyncLayer.db, id, this.asyncLayer.projectId);
|
|
131446
131742
|
if (!existing) return false;
|
|
131447
|
-
const deleted = await deleteChatMessage(this.asyncLayer.db, id);
|
|
131743
|
+
const deleted = await deleteChatMessage(this.asyncLayer.db, id, this.asyncLayer.projectId);
|
|
131448
131744
|
if (deleted) {
|
|
131449
131745
|
this.emit("chat:message:deleted", id);
|
|
131450
131746
|
const updatedSession = await this.getSession(existing.sessionId);
|
|
@@ -131467,7 +131763,7 @@ var init_chat_store = __esm({
|
|
|
131467
131763
|
* @returns deletedIds (in ASC order) and retained messages (pre-edit history, ASC order)
|
|
131468
131764
|
*/
|
|
131469
131765
|
async deleteMessagesFrom(sessionId, fromMessageId) {
|
|
131470
|
-
const result2 = await deleteChatMessagesFrom(this.asyncLayer.db, sessionId, fromMessageId);
|
|
131766
|
+
const result2 = await deleteChatMessagesFrom(this.asyncLayer.db, sessionId, fromMessageId, this.asyncLayer.projectId);
|
|
131471
131767
|
if (result2.deletedIds.length > 0) {
|
|
131472
131768
|
for (const id of result2.deletedIds) {
|
|
131473
131769
|
this.emit("chat:message:deleted", id);
|
|
@@ -131485,7 +131781,7 @@ var init_chat_store = __esm({
|
|
|
131485
131781
|
* is what lets a later edit rewind losslessly via SessionManager.branch()/resetLeaf().
|
|
131486
131782
|
*/
|
|
131487
131783
|
async updateMessageMetadata(messageId, metadata, options) {
|
|
131488
|
-
const updated = await updateChatMessageMetadata(this.asyncLayer.db, messageId, metadata, options);
|
|
131784
|
+
const updated = await updateChatMessageMetadata(this.asyncLayer.db, messageId, metadata, options, this.asyncLayer.projectId);
|
|
131489
131785
|
this.emit("chat:message:updated", updated);
|
|
131490
131786
|
return updated;
|
|
131491
131787
|
}
|
|
@@ -132921,6 +133217,77 @@ var init_task_timing = __esm({
|
|
|
132921
133217
|
}
|
|
132922
133218
|
});
|
|
132923
133219
|
|
|
133220
|
+
// ../core/src/task-recommendation-notice.ts
|
|
133221
|
+
import { createHash as createHash20 } from "node:crypto";
|
|
133222
|
+
function registerTaskRecommendationNoticeMailbox(store, mailbox) {
|
|
133223
|
+
mailboxes2.set(store, mailbox);
|
|
133224
|
+
return () => {
|
|
133225
|
+
if (mailboxes2.get(store) === mailbox) mailboxes2.delete(store);
|
|
133226
|
+
};
|
|
133227
|
+
}
|
|
133228
|
+
function getTaskRecommendationNoticeMailbox(store) {
|
|
133229
|
+
return mailboxes2.get(store);
|
|
133230
|
+
}
|
|
133231
|
+
function buildTaskRecommendationNoticeContent(task, recommendations) {
|
|
133232
|
+
const title = task.title?.trim();
|
|
133233
|
+
const heading = title ? `## Recommendations from ${task.id} \u2014 ${title}` : `## Recommendations from ${task.id}`;
|
|
133234
|
+
return [
|
|
133235
|
+
heading,
|
|
133236
|
+
"",
|
|
133237
|
+
"These are optional, non-blocking out-of-scope proposals that were **not** executed.",
|
|
133238
|
+
"",
|
|
133239
|
+
...recommendations.map((recommendation) => `- **${recommendation.title}** \u2014 \`${recommendation.category}\`: ${recommendation.description}`),
|
|
133240
|
+
"",
|
|
133241
|
+
`Open ${task.id}'s **Recommendations** tab to review them. **Create task** files one through normal guarded intake.`
|
|
133242
|
+
].join("\n");
|
|
133243
|
+
}
|
|
133244
|
+
function buildTaskRecommendationNoticeIdempotencyKey(taskId, recommendations) {
|
|
133245
|
+
const ids = recommendations.map(({ id }) => id).sort().join("\n");
|
|
133246
|
+
const digest = createHash20("sha256").update(ids, "utf8").digest("hex").slice(0, 16);
|
|
133247
|
+
return `task-recommendation-notice:${taskId}:${digest}`;
|
|
133248
|
+
}
|
|
133249
|
+
async function notifyOperatorOfTaskRecommendations(store, task, recommendations, settings) {
|
|
133250
|
+
try {
|
|
133251
|
+
if (settings.recommendationMailboxNoticeEnabled === false || !recommendations?.length) return false;
|
|
133252
|
+
const mailbox = mailboxes2.get(store);
|
|
133253
|
+
if (!mailbox) return false;
|
|
133254
|
+
await mailbox.sendMessageOnce(
|
|
133255
|
+
{
|
|
133256
|
+
fromId: "system",
|
|
133257
|
+
fromType: "system",
|
|
133258
|
+
toId: DASHBOARD_USER_ID,
|
|
133259
|
+
toType: "user",
|
|
133260
|
+
type: "system",
|
|
133261
|
+
content: buildTaskRecommendationNoticeContent(task, recommendations),
|
|
133262
|
+
metadata: {
|
|
133263
|
+
kind: "task-recommendation-notice",
|
|
133264
|
+
taskId: task.id,
|
|
133265
|
+
recommendationCount: recommendations.length,
|
|
133266
|
+
recommendationIds: recommendations.map(({ id }) => id),
|
|
133267
|
+
categories: recommendations.map(({ category }) => category)
|
|
133268
|
+
}
|
|
133269
|
+
},
|
|
133270
|
+
buildTaskRecommendationNoticeIdempotencyKey(task.id, recommendations)
|
|
133271
|
+
);
|
|
133272
|
+
return true;
|
|
133273
|
+
} catch (error3) {
|
|
133274
|
+
noticeLog2.warn(
|
|
133275
|
+
`Operator recommendation notice failed for ${task.id}: ${error3 instanceof Error ? error3.message : String(error3)}`
|
|
133276
|
+
);
|
|
133277
|
+
return false;
|
|
133278
|
+
}
|
|
133279
|
+
}
|
|
133280
|
+
var noticeLog2, mailboxes2;
|
|
133281
|
+
var init_task_recommendation_notice = __esm({
|
|
133282
|
+
"../core/src/task-recommendation-notice.ts"() {
|
|
133283
|
+
"use strict";
|
|
133284
|
+
init_logger();
|
|
133285
|
+
init_types();
|
|
133286
|
+
noticeLog2 = createLogger("task-recommendation-notice");
|
|
133287
|
+
mailboxes2 = /* @__PURE__ */ new WeakMap();
|
|
133288
|
+
}
|
|
133289
|
+
});
|
|
133290
|
+
|
|
132924
133291
|
// ../core/src/session-identity-registry.ts
|
|
132925
133292
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
132926
133293
|
import { resolve as resolve23 } from "node:path";
|
|
@@ -133770,6 +134137,8 @@ __export(src_exports, {
|
|
|
133770
134137
|
buildTaskDeleteNoticeContent: () => buildTaskDeleteNoticeContent,
|
|
133771
134138
|
buildTaskDeleteNoticeIdempotencyKey: () => buildTaskDeleteNoticeIdempotencyKey,
|
|
133772
134139
|
buildTaskLineageTrailer: () => buildTaskLineageTrailer,
|
|
134140
|
+
buildTaskRecommendationNoticeContent: () => buildTaskRecommendationNoticeContent,
|
|
134141
|
+
buildTaskRecommendationNoticeIdempotencyKey: () => buildTaskRecommendationNoticeIdempotencyKey,
|
|
133773
134142
|
buildToolOutputTruncationMarker: () => buildToolOutputTruncationMarker,
|
|
133774
134143
|
buildTriageHeartbeatGuidance: () => buildTriageHeartbeatGuidance,
|
|
133775
134144
|
buildTriageMemoryInstructions: () => buildTriageMemoryInstructions,
|
|
@@ -134100,6 +134469,7 @@ __export(src_exports, {
|
|
|
134100
134469
|
getTaskMergeBlocker: () => getTaskMergeBlocker,
|
|
134101
134470
|
getTaskMoveDisposer: () => getTaskMoveDisposer,
|
|
134102
134471
|
getTaskPriorityRank: () => getTaskPriorityRank,
|
|
134472
|
+
getTaskRecommendationNoticeMailbox: () => getTaskRecommendationNoticeMailbox,
|
|
134103
134473
|
getTemplatesForRole: () => getTemplatesForRole,
|
|
134104
134474
|
getTotalAgentActiveMs: () => getTotalAgentActiveMs,
|
|
134105
134475
|
getTrait: () => getTrait,
|
|
@@ -134350,6 +134720,7 @@ __export(src_exports, {
|
|
|
134350
134720
|
normalizeWorkflowPromptOverrides: () => normalizeWorkflowPromptOverrides,
|
|
134351
134721
|
normalizeWorkflowReviewFindings: () => normalizeWorkflowReviewFindings,
|
|
134352
134722
|
notifyOperatorOfNonOperatorDelete: () => notifyOperatorOfNonOperatorDelete,
|
|
134723
|
+
notifyOperatorOfTaskRecommendations: () => notifyOperatorOfTaskRecommendations,
|
|
134353
134724
|
overseerAdviceSeverityRank: () => overseerAdviceSeverityRank,
|
|
134354
134725
|
parseAgentManifest: () => parseAgentManifest,
|
|
134355
134726
|
parseCompanyArchive: () => parseCompanyArchive,
|
|
@@ -134459,6 +134830,7 @@ __export(src_exports, {
|
|
|
134459
134830
|
registerStepParser: () => registerStepParser,
|
|
134460
134831
|
registerTaskDeleteNoticeMailbox: () => registerTaskDeleteNoticeMailbox,
|
|
134461
134832
|
registerTaskMoveDisposer: () => registerTaskMoveDisposer,
|
|
134833
|
+
registerTaskRecommendationNoticeMailbox: () => registerTaskRecommendationNoticeMailbox,
|
|
134462
134834
|
registerTraitHookImpl: () => registerTraitHookImpl,
|
|
134463
134835
|
rekeyFallbackProjectPartition: () => rekeyFallbackProjectPartition,
|
|
134464
134836
|
releaseEmbeddedRuntimeLease: () => releaseEmbeddedRuntimeLease,
|
|
@@ -135086,6 +135458,7 @@ var init_src2 = __esm({
|
|
|
135086
135458
|
init_task_document_concurrency();
|
|
135087
135459
|
init_task_delete_attribution();
|
|
135088
135460
|
init_task_delete_notice();
|
|
135461
|
+
init_task_recommendation_notice();
|
|
135089
135462
|
init_session_identity_registry();
|
|
135090
135463
|
init_task_lifecycle_event_retention();
|
|
135091
135464
|
init_task_lifecycle_consumer_identity();
|
|
@@ -135177,7 +135550,7 @@ var init_logger3 = __esm({
|
|
|
135177
135550
|
});
|
|
135178
135551
|
|
|
135179
135552
|
// ../engine/src/agents/agent-logger.ts
|
|
135180
|
-
import { createHash as
|
|
135553
|
+
import { createHash as createHash21 } from "node:crypto";
|
|
135181
135554
|
function truncateToolResultDetail(value) {
|
|
135182
135555
|
if (value.length <= TOOL_RESULT_DETAIL_LIMIT) return value;
|
|
135183
135556
|
return `${value.slice(0, TOOL_RESULT_DETAIL_LIMIT)}${TOOL_RESULT_DETAIL_TRUNCATION_NOTICE}`;
|
|
@@ -135266,7 +135639,7 @@ function summarizeToolArgs(name2, args) {
|
|
|
135266
135639
|
const json2 = JSON.stringify(args);
|
|
135267
135640
|
if (!json2 || json2 === "{}" || json2 === "[]") return void 0;
|
|
135268
135641
|
if (json2.length <= STRUCTURED_ARG_SUMMARY_MAX) return json2;
|
|
135269
|
-
const hash3 =
|
|
135642
|
+
const hash3 = createHash21("sha256").update(json2).digest("hex").slice(0, STRUCTURED_ARG_HASH_HEX_LEN);
|
|
135270
135643
|
const suffix = `\u2026#${hash3}`;
|
|
135271
135644
|
const keep = Math.max(0, STRUCTURED_ARG_SUMMARY_MAX - suffix.length);
|
|
135272
135645
|
return `${json2.slice(0, keep)}${suffix}`;
|
|
@@ -135954,7 +136327,13 @@ var init_gating_classifications = __esm({
|
|
|
135954
136327
|
"fn_post_room_message",
|
|
135955
136328
|
"fn_update_identity",
|
|
135956
136329
|
"fn_reflect_on_performance",
|
|
135957
|
-
|
|
136330
|
+
/*
|
|
136331
|
+
FNXC:ToolGovernance 2026-08-12-22:11:
|
|
136332
|
+
fn_agent_read_evaluations is a subtree-scoped read. Authorization is enforced by
|
|
136333
|
+
the extension tool's getChainOfCommand boundary, not by this action classifier.
|
|
136334
|
+
*/
|
|
136335
|
+
"fn_read_evaluations",
|
|
136336
|
+
"fn_agent_read_evaluations"
|
|
135958
136337
|
]);
|
|
135959
136338
|
COORDINATION_EXEMPT_TOOLS = [
|
|
135960
136339
|
"read",
|
|
@@ -136014,6 +136393,8 @@ var init_gating_classifications = __esm({
|
|
|
136014
136393
|
"fn_post_room_message",
|
|
136015
136394
|
"fn_memory_append",
|
|
136016
136395
|
"fn_read_evaluations",
|
|
136396
|
+
// 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.
|
|
136397
|
+
"fn_agent_read_evaluations",
|
|
136017
136398
|
"fn_update_identity",
|
|
136018
136399
|
"fn_reflect_on_performance"
|
|
136019
136400
|
];
|
|
@@ -136038,7 +136419,7 @@ var init_gating_classifications = __esm({
|
|
|
136038
136419
|
});
|
|
136039
136420
|
|
|
136040
136421
|
// ../engine/src/agents/agent-action-gate.ts
|
|
136041
|
-
import { createHash as
|
|
136422
|
+
import { createHash as createHash22 } from "node:crypto";
|
|
136042
136423
|
function getExemptTools() {
|
|
136043
136424
|
if (!_exemptTools) {
|
|
136044
136425
|
_exemptTools = new Set(DEFAULT_EXEMPT_TOOLS);
|
|
@@ -136090,7 +136471,7 @@ function evaluateAgentActionGate(params) {
|
|
|
136090
136471
|
if (params.toolName === "bash") {
|
|
136091
136472
|
const command = extractShellCommand(args);
|
|
136092
136473
|
const git7 = classifyGitCommand(command);
|
|
136093
|
-
resourceId = command ? `cmd:${
|
|
136474
|
+
resourceId = command ? `cmd:${createHash22("sha256").update(command).digest("hex").slice(0, 16)}` : void 0;
|
|
136094
136475
|
if (git7?.write) {
|
|
136095
136476
|
category = "git_write";
|
|
136096
136477
|
operation = git7.operation;
|
|
@@ -139622,11 +140003,11 @@ var init_planning_handoff_recovery = __esm({
|
|
|
139622
140003
|
// ../engine/src/plan-review-continuation.ts
|
|
139623
140004
|
async function seedPreReleasePlanReviewContinuation(store, task, ir2, options = {}) {
|
|
139624
140005
|
const node = resolvePreReleasePlanReviewNode(ir2);
|
|
139625
|
-
if (!node || node.column !== task.column) return { seeded: false };
|
|
140006
|
+
if (!node || node.column !== task.column) return { seeded: false, reason: "no-pre-release-plan-review" };
|
|
139626
140007
|
if (isTaskBlockedOnApproval(task)) return { seeded: false, reason: "awaiting-approval" };
|
|
139627
140008
|
if (task.paused === true || task.userPaused === true) return { seeded: false, reason: "paused" };
|
|
139628
140009
|
const items = await store.listWorkflowWorkItemsForTask(task.id);
|
|
139629
|
-
const active2 = items.filter((item2) => ACTIVE_WORKFLOW_WORK_ITEM_STATES.includes(item2.state));
|
|
140010
|
+
const active2 = items.filter((item2) => ACTIVE_WORKFLOW_WORK_ITEM_STATES.includes(item2.state) && item2.id !== options.retirePredecessorId);
|
|
139630
140011
|
if (active2.length > 0) return { seeded: false, reason: "active-continuation" };
|
|
139631
140012
|
const continuationSequence = items.length;
|
|
139632
140013
|
const input = {
|
|
@@ -139642,6 +140023,9 @@ async function seedPreReleasePlanReviewContinuation(store, task, ir2, options =
|
|
|
139642
140023
|
targetColumn: task.column,
|
|
139643
140024
|
irHash: computeWorkflowIrPin(ir2, node.id).irHash
|
|
139644
140025
|
};
|
|
140026
|
+
if (options.retirePredecessorId) {
|
|
140027
|
+
return store.seedStrandedPlanReviewContinuation(input, { retirePredecessorId: options.retirePredecessorId });
|
|
140028
|
+
}
|
|
139645
140029
|
if (options.atomic) return store.seedStrandedPlanReviewContinuation(input);
|
|
139646
140030
|
const item = await store.replaceActiveTaskWorkflowContinuation(input);
|
|
139647
140031
|
return { seeded: true, workItemId: item.id };
|
|
@@ -139656,7 +140040,7 @@ async function resumeApprovedPlanReviewHandoff(store, task, ir2) {
|
|
|
139656
140040
|
if (seeded.seeded) return { resumed: true, reason: "seeded", workItemId: seeded.workItemId };
|
|
139657
140041
|
return {
|
|
139658
140042
|
resumed: false,
|
|
139659
|
-
reason: seeded.reason
|
|
140043
|
+
reason: seeded.reason === void 0 || seeded.reason === "no-pre-release-plan-review" ? "not-plan-in-place" : seeded.reason
|
|
139660
140044
|
};
|
|
139661
140045
|
}
|
|
139662
140046
|
function evaluateStrandedHoldContinuation(input) {
|
|
@@ -139694,7 +140078,7 @@ var init_plan_review_continuation = __esm({
|
|
|
139694
140078
|
});
|
|
139695
140079
|
|
|
139696
140080
|
// ../engine/src/execution/hold-release.ts
|
|
139697
|
-
import { createHash as
|
|
140081
|
+
import { createHash as createHash23 } from "node:crypto";
|
|
139698
140082
|
import { readFile as readFile31 } from "node:fs/promises";
|
|
139699
140083
|
function findColumn2(ir2, columnId) {
|
|
139700
140084
|
if (ir2.version !== "v2") return void 0;
|
|
@@ -139732,9 +140116,9 @@ async function checkAndRecordUnplannedExecutionBlock(store, task, ir2) {
|
|
|
139732
140116
|
promptContent = "";
|
|
139733
140117
|
}
|
|
139734
140118
|
}
|
|
139735
|
-
const promptMarker = promptContent.length > 0 ?
|
|
140119
|
+
const promptMarker = promptContent.length > 0 ? createHash23("sha256").update(promptContent).digest("hex") : "missing";
|
|
139736
140120
|
const dependencies = [...task.dependencies ?? []].sort();
|
|
139737
|
-
const episode =
|
|
140121
|
+
const episode = createHash23("sha256").update(JSON.stringify({
|
|
139738
140122
|
planReviewNode,
|
|
139739
140123
|
promptMarker,
|
|
139740
140124
|
dependencies,
|
|
@@ -169854,7 +170238,7 @@ ${getErrorStderr(error3) ?? ""}`;
|
|
|
169854
170238
|
});
|
|
169855
170239
|
|
|
169856
170240
|
// ../engine/src/worktree/secrets-env-writer.ts
|
|
169857
|
-
import { createHash as
|
|
170241
|
+
import { createHash as createHash24 } from "node:crypto";
|
|
169858
170242
|
import { execFile as execFile8 } from "node:child_process";
|
|
169859
170243
|
import { promises as fs6 } from "node:fs";
|
|
169860
170244
|
import path2 from "node:path";
|
|
@@ -169863,7 +170247,7 @@ function isValidFilename(filename) {
|
|
|
169863
170247
|
return !!filename && !filename.includes("/") && !filename.includes("\\") && !filename.includes("..") && !filename.includes("\0") && filename !== FINGERPRINT_FILE;
|
|
169864
170248
|
}
|
|
169865
170249
|
function sha2562(content) {
|
|
169866
|
-
return
|
|
170250
|
+
return createHash24("sha256").update(Buffer.from(content, "utf8")).digest("hex");
|
|
169867
170251
|
}
|
|
169868
170252
|
function quote(value) {
|
|
169869
170253
|
return `"${value.replaceAll("\\", "\\\\").replaceAll('"', '\\"').replaceAll("\n", "\\n").replaceAll("\r", "\\r").replaceAll(" ", "\\t")}"`;
|
|
@@ -178003,32 +178387,36 @@ var init_scheduler = __esm({
|
|
|
178003
178387
|
const hierarchy = await missionStore.getMissionWithHierarchy(mission.id);
|
|
178004
178388
|
if (!hierarchy) continue;
|
|
178005
178389
|
for (const slice of hierarchy.milestones.flatMap((milestone) => milestone.slices).filter((slice2) => slice2.status === "active")) {
|
|
178006
|
-
|
|
178007
|
-
|
|
178008
|
-
|
|
178009
|
-
|
|
178010
|
-
|
|
178011
|
-
|
|
178012
|
-
|
|
178390
|
+
try {
|
|
178391
|
+
const superseded = await missionStore.reconcileSupersededGeneratedFixFeatures(slice.id);
|
|
178392
|
+
fixed += superseded.supersededCount;
|
|
178393
|
+
if (superseded.supersededCount > 0) {
|
|
178394
|
+
const refreshed = await missionStore.getSlice(slice.id);
|
|
178395
|
+
if (refreshed?.status === "complete") {
|
|
178396
|
+
await this.onSliceComplete(refreshed);
|
|
178397
|
+
continue;
|
|
178398
|
+
}
|
|
178013
178399
|
}
|
|
178014
|
-
|
|
178015
|
-
|
|
178016
|
-
|
|
178017
|
-
|
|
178018
|
-
|
|
178019
|
-
|
|
178020
|
-
|
|
178021
|
-
|
|
178022
|
-
|
|
178400
|
+
const listFeatures2 = missionStore.listFeatures;
|
|
178401
|
+
const features = listFeatures2 ? await listFeatures2.call(missionStore, slice.id) : slice.features;
|
|
178402
|
+
const supersededFeatureIds = new Set(superseded.featureIds ?? []);
|
|
178403
|
+
const autoTriage = mission.autopilotEnabled === true || mission.autoAdvance === true;
|
|
178404
|
+
for (const feature of features) {
|
|
178405
|
+
if (supersededFeatureIds.has(feature.id) || feature.taskId || !autoTriage || feature.status === "blocked") continue;
|
|
178406
|
+
if (feature.status !== "defined" && this.isGeneratedFixFeature(feature)) {
|
|
178407
|
+
await missionStore.updateFeature(feature.id, { status: "blocked", loopState: "blocked", taskId: void 0 });
|
|
178408
|
+
fixed++;
|
|
178409
|
+
continue;
|
|
178410
|
+
}
|
|
178411
|
+
if (feature.status !== "defined" && feature.status !== "triaged" && feature.status !== "in-progress") continue;
|
|
178412
|
+
const ready = feature.status === "defined" ? feature : await missionStore.updateFeature(feature.id, { status: "defined", loopState: "idle", taskId: void 0 });
|
|
178413
|
+
if (ready !== feature) fixed++;
|
|
178414
|
+
const triaged = await missionStore.triageFeature(ready.id);
|
|
178023
178415
|
fixed++;
|
|
178024
|
-
|
|
178416
|
+
if (triaged.taskId) await this.emitStrandedFeatureTriageAudit(mission.id, slice.id, triaged.id, triaged.taskId);
|
|
178025
178417
|
}
|
|
178026
|
-
|
|
178027
|
-
|
|
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);
|
|
178418
|
+
} catch (error3) {
|
|
178419
|
+
schedulerLog.error(`Error during active mission recovery reconciliation for slice ${slice.id}:`, error3);
|
|
178032
178420
|
}
|
|
178033
178421
|
}
|
|
178034
178422
|
}
|
|
@@ -178266,7 +178654,7 @@ var init_mission_feature_sync = __esm({
|
|
|
178266
178654
|
// ../engine/src/agent-tools.ts
|
|
178267
178655
|
import { appendFile as appendFile3, mkdir as mkdir28, readFile as readFile38, readdir as readdir11, realpath as realpath2, stat as stat11, writeFile as writeFile26 } from "node:fs/promises";
|
|
178268
178656
|
import { existsSync as existsSync52 } from "node:fs";
|
|
178269
|
-
import { createHash as
|
|
178657
|
+
import { createHash as createHash25, randomUUID as randomUUID46 } from "node:crypto";
|
|
178270
178658
|
import { tmpdir as tmpdir5 } from "node:os";
|
|
178271
178659
|
import { extname as extname4, isAbsolute as isAbsolute14, join as join66, relative as relative14, resolve as resolve37, sep as sep10 } from "node:path";
|
|
178272
178660
|
import { Type as Type2 } from "@earendil-works/pi-ai";
|
|
@@ -178310,7 +178698,7 @@ async function readAgentMemoryWorkspaceLongTerm(rootDir, agentId) {
|
|
|
178310
178698
|
}
|
|
178311
178699
|
}
|
|
178312
178700
|
function qmdAgentMemoryCollectionName2(rootDir, agentId) {
|
|
178313
|
-
const hash3 =
|
|
178701
|
+
const hash3 = createHash25("sha1").update(`${rootDir}:${agentId}`).digest("hex").slice(0, 12);
|
|
178314
178702
|
return `fusion-agent-memory-${sanitizeAgentMemoryId(agentId).toLowerCase()}-${hash3}`;
|
|
178315
178703
|
}
|
|
178316
178704
|
function buildQmdAgentMemoryCollectionAddArgs(rootDir, agentId) {
|
|
@@ -189887,7 +190275,7 @@ var init_agent_heartbeat_error_recovery = __esm({
|
|
|
189887
190275
|
|
|
189888
190276
|
// ../engine/src/agent-heartbeat.ts
|
|
189889
190277
|
import { Type as Type3 } from "@earendil-works/pi-ai";
|
|
189890
|
-
import { createHash as
|
|
190278
|
+
import { createHash as createHash26 } from "node:crypto";
|
|
189891
190279
|
async function resolveHeartbeatReboundColumn(taskStore, taskId) {
|
|
189892
190280
|
try {
|
|
189893
190281
|
return resolveReboundTarget(await resolveWorkflowIrForTask(taskStore, taskId)) ?? "todo";
|
|
@@ -190042,7 +190430,7 @@ function truncatePrompt(text2, maxChars) {
|
|
|
190042
190430
|
... (truncated, ${text2.length} chars)`;
|
|
190043
190431
|
}
|
|
190044
190432
|
function shortContentHash(value) {
|
|
190045
|
-
return
|
|
190433
|
+
return createHash26("sha256").update(value).digest("hex").slice(0, 8);
|
|
190046
190434
|
}
|
|
190047
190435
|
function buildIdentitySnapshot(args) {
|
|
190048
190436
|
const { agent, resolvedInstructions, workspaceMemory } = args;
|
|
@@ -197931,7 +198319,7 @@ var init_verification_utils = __esm({
|
|
|
197931
198319
|
|
|
197932
198320
|
// ../engine/src/merge/merge-dependency-sync.ts
|
|
197933
198321
|
import { exec as exec25 } from "node:child_process";
|
|
197934
|
-
import { createHash as
|
|
198322
|
+
import { createHash as createHash27 } from "node:crypto";
|
|
197935
198323
|
import { existsSync as existsSync55, readFileSync as readFileSync17, writeFileSync as writeFileSync6 } from "node:fs";
|
|
197936
198324
|
import { join as join69 } from "node:path";
|
|
197937
198325
|
import { promisify as promisify35 } from "node:util";
|
|
@@ -197958,7 +198346,7 @@ function computeLockfileHash(rootDir) {
|
|
|
197958
198346
|
const p2 = join69(rootDir, name2);
|
|
197959
198347
|
if (existsSync55(p2)) {
|
|
197960
198348
|
try {
|
|
197961
|
-
return
|
|
198349
|
+
return createHash27("sha256").update(readFileSync17(p2)).digest("hex");
|
|
197962
198350
|
} catch {
|
|
197963
198351
|
return null;
|
|
197964
198352
|
}
|
|
@@ -200500,7 +200888,7 @@ var init_mesh_lease_manager = __esm({
|
|
|
200500
200888
|
});
|
|
200501
200889
|
|
|
200502
200890
|
// ../engine/src/merge/merger-integration-worktree.ts
|
|
200503
|
-
import { createHash as
|
|
200891
|
+
import { createHash as createHash28 } from "node:crypto";
|
|
200504
200892
|
import { exec as exec31, execFile as execFile22 } from "node:child_process";
|
|
200505
200893
|
import { promisify as promisify45 } from "node:util";
|
|
200506
200894
|
function quoteAutostashArg(value) {
|
|
@@ -200623,7 +201011,7 @@ async function gitDirtyFingerprintLocal(rootDir) {
|
|
|
200623
201011
|
)
|
|
200624
201012
|
]);
|
|
200625
201013
|
if (!diffOut && !statusOut) return "";
|
|
200626
|
-
return
|
|
201014
|
+
return createHash28("sha256").update(diffOut).update("\0").update(statusOut).digest("hex");
|
|
200627
201015
|
} catch {
|
|
200628
201016
|
return "";
|
|
200629
201017
|
}
|
|
@@ -201609,7 +201997,7 @@ import { execSync as execSync5, exec as exec33 } from "node:child_process";
|
|
|
201609
201997
|
import * as childProcess4 from "node:child_process";
|
|
201610
201998
|
import { promisify as promisify48 } from "node:util";
|
|
201611
201999
|
import { existsSync as existsSync58, readFileSync as readFileSync20, writeFileSync as writeFileSync8, unlinkSync as unlinkSync3, renameSync as renameSync4 } from "node:fs";
|
|
201612
|
-
import { createHash as
|
|
202000
|
+
import { createHash as createHash29 } from "node:crypto";
|
|
201613
202001
|
import { join as join73, resolve as resolve43 } from "node:path";
|
|
201614
202002
|
import { hostname as hostname2 } from "node:os";
|
|
201615
202003
|
import { Type as Type4 } from "typebox";
|
|
@@ -201857,7 +202245,7 @@ async function gitDirtyFingerprint(rootDir) {
|
|
|
201857
202245
|
)
|
|
201858
202246
|
]);
|
|
201859
202247
|
if (!diffOut && !statusOut) return "";
|
|
201860
|
-
return
|
|
202248
|
+
return createHash29("sha256").update(diffOut).update("\0").update(statusOut).digest("hex");
|
|
201861
202249
|
} catch {
|
|
201862
202250
|
return "";
|
|
201863
202251
|
}
|
|
@@ -224280,7 +224668,7 @@ You are ${assignedAgent.name}${assignedAgent.title?.trim() ? `, ${assignedAgent.
|
|
|
224280
224668
|
}
|
|
224281
224669
|
return;
|
|
224282
224670
|
}
|
|
224283
|
-
const duplicateReport = { outcome: "parked" };
|
|
224671
|
+
const duplicateReport = { outcome: "parked", planningWorkItemId };
|
|
224284
224672
|
if (await this.tryFinalizeExplicitDuplicateMarker(task, written, settings, {
|
|
224285
224673
|
isReplan,
|
|
224286
224674
|
feedback
|
|
@@ -224299,6 +224687,7 @@ You are ${assignedAgent.name}${assignedAgent.title?.trim() ? `, ${assignedAgent.
|
|
|
224299
224687
|
isReplan,
|
|
224300
224688
|
feedback
|
|
224301
224689
|
});
|
|
224690
|
+
finalizeReport.planningWorkItemId = planningWorkItemId;
|
|
224302
224691
|
this.options.onSpecifyComplete?.(task, finalizeReport);
|
|
224303
224692
|
} finally {
|
|
224304
224693
|
this.activeSessions.delete(task.id);
|
|
@@ -239870,6 +240259,38 @@ var init_execution_block_classifier = __esm({
|
|
|
239870
240259
|
}
|
|
239871
240260
|
});
|
|
239872
240261
|
|
|
240262
|
+
// ../engine/src/executor/completion-recommendation-notice.ts
|
|
240263
|
+
function dispatchAcceptedCompletionRecommendationNotice(args) {
|
|
240264
|
+
if (!args.recommendations?.length) return;
|
|
240265
|
+
const pending = (async () => {
|
|
240266
|
+
const settings = args.settings ?? await args.store.getSettings();
|
|
240267
|
+
const task = await args.store.getTask(args.taskId);
|
|
240268
|
+
if (!task || task.deletedAt) return;
|
|
240269
|
+
await notifyOperatorOfTaskRecommendations(
|
|
240270
|
+
args.store,
|
|
240271
|
+
{ id: args.taskId, title: args.taskTitle ?? task.title },
|
|
240272
|
+
args.recommendations,
|
|
240273
|
+
settings
|
|
240274
|
+
);
|
|
240275
|
+
})();
|
|
240276
|
+
pendingNotices.add(pending);
|
|
240277
|
+
void pending.catch((error3) => {
|
|
240278
|
+
args.log?.warn(
|
|
240279
|
+
`Failed to dispatch recommendation mailbox notice for ${args.taskId}: ${error3 instanceof Error ? error3.message : String(error3)}`
|
|
240280
|
+
);
|
|
240281
|
+
}).finally(() => {
|
|
240282
|
+
pendingNotices.delete(pending);
|
|
240283
|
+
});
|
|
240284
|
+
}
|
|
240285
|
+
var pendingNotices;
|
|
240286
|
+
var init_completion_recommendation_notice = __esm({
|
|
240287
|
+
"../engine/src/executor/completion-recommendation-notice.ts"() {
|
|
240288
|
+
"use strict";
|
|
240289
|
+
init_src2();
|
|
240290
|
+
pendingNotices = /* @__PURE__ */ new Set();
|
|
240291
|
+
}
|
|
240292
|
+
});
|
|
240293
|
+
|
|
239873
240294
|
// ../engine/src/executor/create-task-done-tool.ts
|
|
239874
240295
|
import { Type as Type9 } from "@earendil-works/pi-ai";
|
|
239875
240296
|
function createTaskDoneTool(deps, taskId, worktreePath, promptContent, codeReviewVerdicts, onDone, audit) {
|
|
@@ -240206,6 +240627,16 @@ ${rerunSuffix}`
|
|
|
240206
240627
|
bulkCompletionRefusalAt: null
|
|
240207
240628
|
});
|
|
240208
240629
|
await store.logEntry(taskId, "Task marked done by agent", void 0, deps.getRunContextFor(taskId));
|
|
240630
|
+
if (completionRecommendations !== void 0) {
|
|
240631
|
+
dispatchAcceptedCompletionRecommendationNotice({
|
|
240632
|
+
store,
|
|
240633
|
+
taskId,
|
|
240634
|
+
taskTitle: task.title,
|
|
240635
|
+
recommendations: completionRecommendations,
|
|
240636
|
+
settings,
|
|
240637
|
+
log: executorLog
|
|
240638
|
+
});
|
|
240639
|
+
}
|
|
240209
240640
|
const latestTask = await store.getTask(taskId);
|
|
240210
240641
|
let latestColumn = latestTask.column;
|
|
240211
240642
|
if (latestColumn === await resolveReboundColumnFor(store, taskId)) {
|
|
@@ -240244,6 +240675,7 @@ var init_create_task_done_tool = __esm({
|
|
|
240244
240675
|
init_completion_predicates();
|
|
240245
240676
|
init_task_done_refusal_handler();
|
|
240246
240677
|
init_validate_completion_recommendations();
|
|
240678
|
+
init_completion_recommendation_notice();
|
|
240247
240679
|
}
|
|
240248
240680
|
});
|
|
240249
240681
|
|
|
@@ -251570,6 +252002,16 @@ ${rerunSuffix}` });
|
|
|
251570
252002
|
if (latestColumn === await resolveWipTargetForTask(deps.store, task.id) && !hardPauseActive && beforeWatchdog && !beforeWatchdog.deletedAt && !(rejectIfPaused && (beforeWatchdog.paused || beforeWatchdog.userPaused))) {
|
|
251571
252003
|
deps.scheduleCompletedTaskWatchdog(task.id, "fn_task_done");
|
|
251572
252004
|
}
|
|
252005
|
+
if (recommendations !== void 0) {
|
|
252006
|
+
dispatchAcceptedCompletionRecommendationNotice({
|
|
252007
|
+
store: deps.store,
|
|
252008
|
+
taskId: task.id,
|
|
252009
|
+
taskTitle: task.title,
|
|
252010
|
+
recommendations,
|
|
252011
|
+
settings,
|
|
252012
|
+
log: executorLog
|
|
252013
|
+
});
|
|
252014
|
+
}
|
|
251573
252015
|
return { completed: true, hardPauseActive };
|
|
251574
252016
|
} catch (error3) {
|
|
251575
252017
|
await restoreNoCommitsExpected();
|
|
@@ -251628,6 +252070,7 @@ var init_plan_review_no_op = __esm({
|
|
|
251628
252070
|
init_src2();
|
|
251629
252071
|
init_logger3();
|
|
251630
252072
|
init_lifecycle_columns();
|
|
252073
|
+
init_completion_recommendation_notice();
|
|
251631
252074
|
}
|
|
251632
252075
|
});
|
|
251633
252076
|
|
|
@@ -255136,14 +255579,14 @@ ${stdout.trim()}`);
|
|
|
255136
255579
|
|
|
255137
255580
|
// ../engine/src/missions/mission-execution-loop.ts
|
|
255138
255581
|
import { EventEmitter as EventEmitter25 } from "node:events";
|
|
255139
|
-
import { createHash as
|
|
255582
|
+
import { createHash as createHash30 } from "node:crypto";
|
|
255140
255583
|
import { exec as exec56 } from "node:child_process";
|
|
255141
255584
|
import { promisify as promisify74 } from "node:util";
|
|
255142
255585
|
function quoteShellArg7(value) {
|
|
255143
255586
|
return `'${value.replace(/'/g, `'\\''`)}'`;
|
|
255144
255587
|
}
|
|
255145
255588
|
function fingerprintMissionValidationInput(landedSha, provider, modelId, systemPrompt, userPrompt) {
|
|
255146
|
-
return
|
|
255589
|
+
return createHash30("sha256").update(Buffer.from(JSON.stringify(["mission-validation-input-v1", landedSha, provider, modelId, systemPrompt, userPrompt]), "utf8")).digest("hex");
|
|
255147
255590
|
}
|
|
255148
255591
|
var execAsync53, loopLog, VALIDATION_TIMEOUT_MS, MAX_VALIDATION_RESPONSE_BYTES, MAX_VALIDATION_JSON_CANDIDATES, VALIDATION_FAILURE_BUDGET_PER_FINGERPRINT, MissionExecutionLoop;
|
|
255149
255592
|
var init_mission_execution_loop = __esm({
|
|
@@ -266682,9 +267125,9 @@ var init_routine_scheduler = __esm({
|
|
|
266682
267125
|
});
|
|
266683
267126
|
|
|
266684
267127
|
// ../engine/src/healing/stuck-task-detector.ts
|
|
266685
|
-
import { createHash as
|
|
267128
|
+
import { createHash as createHash31 } from "node:crypto";
|
|
266686
267129
|
function hashToolDetail(detail) {
|
|
266687
|
-
return
|
|
267130
|
+
return createHash31("sha256").update(detail).digest("hex").slice(0, TOOL_DETAIL_HASH_HEX_LEN);
|
|
266688
267131
|
}
|
|
266689
267132
|
function buildToolFingerprint(toolName, toolDetail) {
|
|
266690
267133
|
const name2 = toolName.trim().toLowerCase() || "tool";
|
|
@@ -270262,7 +270705,7 @@ var init_node_dispatch_validation = __esm({
|
|
|
270262
270705
|
});
|
|
270263
270706
|
|
|
270264
270707
|
// ../engine/src/runtimes/in-process-runtime.ts
|
|
270265
|
-
import { createHash as
|
|
270708
|
+
import { createHash as createHash32 } from "node:crypto";
|
|
270266
270709
|
import { EventEmitter as EventEmitter26 } from "node:events";
|
|
270267
270710
|
import { setImmediate as setImmediateCb4 } from "node:timers";
|
|
270268
270711
|
function createDiscoveryPluginLoaderOptions(scopedStore) {
|
|
@@ -270353,11 +270796,46 @@ async function reactToSpecificationComplete(deps) {
|
|
|
270353
270796
|
return;
|
|
270354
270797
|
}
|
|
270355
270798
|
deps.log(`Specified ${deps.taskId} \u2192 todo`);
|
|
270356
|
-
const
|
|
270357
|
-
|
|
270358
|
-
|
|
270359
|
-
|
|
270360
|
-
|
|
270799
|
+
const sleep9 = deps.sleep ?? ((ms2) => new Promise((resolve60) => setTimeout(resolve60, ms2)));
|
|
270800
|
+
const QUIET_PARK_REASONS = /* @__PURE__ */ new Set([
|
|
270801
|
+
"no-pre-release-plan-review",
|
|
270802
|
+
"awaiting-approval",
|
|
270803
|
+
"paused",
|
|
270804
|
+
"plan-review-passed"
|
|
270805
|
+
]);
|
|
270806
|
+
const RETRY_DELAYS_MS2 = [1e3, 5e3];
|
|
270807
|
+
for (let attempt = 0; ; attempt++) {
|
|
270808
|
+
let failure = null;
|
|
270809
|
+
try {
|
|
270810
|
+
const live = await deps.getTask(deps.taskId);
|
|
270811
|
+
if (!live || live.paused || live.userPaused) return;
|
|
270812
|
+
if (live.status === "needs-replan") {
|
|
270813
|
+
deps.log(`Plan Review handoff for ${deps.taskId} not armed (needs-replan)`);
|
|
270814
|
+
return;
|
|
270815
|
+
}
|
|
270816
|
+
const ir2 = await deps.resolveIr(live.id);
|
|
270817
|
+
const result2 = await deps.seed(live, ir2);
|
|
270818
|
+
if (result2.seeded) {
|
|
270819
|
+
deps.kick();
|
|
270820
|
+
return;
|
|
270821
|
+
}
|
|
270822
|
+
if (result2.reason && QUIET_PARK_REASONS.has(result2.reason)) {
|
|
270823
|
+
deps.log(`Plan Review handoff for ${deps.taskId} not armed (${result2.reason})`);
|
|
270824
|
+
return;
|
|
270825
|
+
}
|
|
270826
|
+
failure = result2.reason ?? "not-seeded";
|
|
270827
|
+
} catch (error3) {
|
|
270828
|
+
failure = error3 instanceof Error ? error3.message : String(error3);
|
|
270829
|
+
}
|
|
270830
|
+
if (attempt >= RETRY_DELAYS_MS2.length) {
|
|
270831
|
+
deps.warn(
|
|
270832
|
+
`Plan Review handoff for ${deps.taskId} failed after ${attempt + 1} attempts (${failure}) \u2014 stranded-continuation self-healing will recover it`
|
|
270833
|
+
);
|
|
270834
|
+
return;
|
|
270835
|
+
}
|
|
270836
|
+
deps.warn(`Plan Review handoff for ${deps.taskId} did not seed (${failure}) \u2014 retrying`);
|
|
270837
|
+
await sleep9(RETRY_DELAYS_MS2[attempt]);
|
|
270838
|
+
}
|
|
270361
270839
|
}
|
|
270362
270840
|
async function drainDuePlanningContinuations(deps) {
|
|
270363
270841
|
const items = await deps.listDue();
|
|
@@ -270492,7 +270970,7 @@ function stableNotificationJson(value) {
|
|
|
270492
270970
|
return `{${fields.join(",")}}`;
|
|
270493
270971
|
}
|
|
270494
270972
|
function buildCliAgentNotificationDedupeKey(input) {
|
|
270495
|
-
const notificationFingerprint =
|
|
270973
|
+
const notificationFingerprint = createHash32("sha256").update(stableNotificationJson(input.info.notification ?? null)).digest("hex").slice(0, 16);
|
|
270496
270974
|
const waitingEpoch = input.session?.updatedAt ?? "unknown-waiting-epoch";
|
|
270497
270975
|
return [
|
|
270498
270976
|
"cli-agent",
|
|
@@ -270647,6 +271125,8 @@ var init_in_process_runtime = __esm({
|
|
|
270647
271125
|
messageStore;
|
|
270648
271126
|
/** FNXC:TaskDeleteNotice 2026-07-26-16:10: identity-guarded teardown for the delete-notice mailbox seam. */
|
|
270649
271127
|
unregisterTaskDeleteNoticeMailbox;
|
|
271128
|
+
/** FNXC:TaskRecommendations 2026-08-13-03:56: identity-guarded teardown for the store-scoped recommendation notice seam. */
|
|
271129
|
+
unregisterTaskRecommendationNoticeMailbox;
|
|
270650
271130
|
chatStore;
|
|
270651
271131
|
detachAgentLinkSync;
|
|
270652
271132
|
/**
|
|
@@ -270705,7 +271185,8 @@ var init_in_process_runtime = __esm({
|
|
|
270705
271185
|
createTaskStoreForBackend: createTaskStoreForBackend2,
|
|
270706
271186
|
buildConsumerId: buildConsumerId2,
|
|
270707
271187
|
createProjectScopedPluginMcpProvider: createProjectScopedPluginMcpProvider2,
|
|
270708
|
-
registerTaskDeleteNoticeMailbox: registerTaskDeleteNoticeMailbox2
|
|
271188
|
+
registerTaskDeleteNoticeMailbox: registerTaskDeleteNoticeMailbox2,
|
|
271189
|
+
registerTaskRecommendationNoticeMailbox: registerTaskRecommendationNoticeMailbox2
|
|
270709
271190
|
} = await Promise.resolve().then(() => (init_src2(), src_exports));
|
|
270710
271191
|
if (this.config.externalTaskStore) {
|
|
270711
271192
|
this.taskStore = this.config.externalTaskStore;
|
|
@@ -270764,6 +271245,10 @@ var init_in_process_runtime = __esm({
|
|
|
270764
271245
|
this.taskStore,
|
|
270765
271246
|
this.messageStore
|
|
270766
271247
|
);
|
|
271248
|
+
this.unregisterTaskRecommendationNoticeMailbox = registerTaskRecommendationNoticeMailbox2(
|
|
271249
|
+
this.taskStore,
|
|
271250
|
+
this.messageStore
|
|
271251
|
+
);
|
|
270767
271252
|
await yieldEventLoop4();
|
|
270768
271253
|
const pluginLayer = this.taskStore.getAsyncLayer();
|
|
270769
271254
|
if (!pluginLayer) {
|
|
@@ -271255,9 +271740,19 @@ var init_in_process_runtime = __esm({
|
|
|
271255
271740
|
outcome: report2.outcome,
|
|
271256
271741
|
getTask: (id) => Promise.resolve(this.taskStore.getTask(id)),
|
|
271257
271742
|
resolveIr: (id) => resolveWorkflowIrForTask(this.taskStore, id),
|
|
271258
|
-
|
|
271743
|
+
/*
|
|
271744
|
+
FNXC:PlanningHandoffAtomicity 2026-08-13-03:49:
|
|
271745
|
+
The report carries the planning session's own durable work item id so the
|
|
271746
|
+
seeder can retire that exact predecessor row atomically with the successor
|
|
271747
|
+
install. Without it the seeder raced triage's finally-block terminal
|
|
271748
|
+
transition and bailed on its own caller (529 stranded cards in 18 days).
|
|
271749
|
+
*/
|
|
271750
|
+
seed: (task, ir2) => seedPreReleasePlanReviewContinuation(this.taskStore, task, ir2, {
|
|
271751
|
+
retirePredecessorId: report2.planningWorkItemId
|
|
271752
|
+
}),
|
|
271259
271753
|
kick: () => this.kickWorkflowContinuationProcessor(),
|
|
271260
|
-
log: (message) => runtimeLog.log(message)
|
|
271754
|
+
log: (message) => runtimeLog.log(message),
|
|
271755
|
+
warn: (message) => runtimeLog.warn(message)
|
|
271261
271756
|
}).catch((error3) => {
|
|
271262
271757
|
runtimeLog.error(`Failed to start Todo plan review for ${t.id}:`, error3);
|
|
271263
271758
|
});
|
|
@@ -271545,6 +272040,8 @@ var init_in_process_runtime = __esm({
|
|
|
271545
272040
|
this.backendShutdown = void 0;
|
|
271546
272041
|
this.unregisterTaskDeleteNoticeMailbox?.();
|
|
271547
272042
|
this.unregisterTaskDeleteNoticeMailbox = void 0;
|
|
272043
|
+
this.unregisterTaskRecommendationNoticeMailbox?.();
|
|
272044
|
+
this.unregisterTaskRecommendationNoticeMailbox = void 0;
|
|
271548
272045
|
let stopError;
|
|
271549
272046
|
try {
|
|
271550
272047
|
if (this.workflowContinuationTimer) {
|
|
@@ -279338,9 +279835,9 @@ import { access as access10, unlink as unlink11, writeFile as writeFile33 } from
|
|
|
279338
279835
|
import net2 from "node:net";
|
|
279339
279836
|
import { platform as platform3, tmpdir as tmpdir12 } from "node:os";
|
|
279340
279837
|
import { join as join91 } from "node:path";
|
|
279341
|
-
import { createHash as
|
|
279838
|
+
import { createHash as createHash33 } from "node:crypto";
|
|
279342
279839
|
function projectHash(projectId2) {
|
|
279343
|
-
return
|
|
279840
|
+
return createHash33("sha1").update(projectId2).digest("hex").slice(0, 16);
|
|
279344
279841
|
}
|
|
279345
279842
|
function computeEngineSocketPath(projectId2) {
|
|
279346
279843
|
const hash3 = projectHash(projectId2);
|
|
@@ -308074,7 +308571,7 @@ var init_types5 = __esm({
|
|
|
308074
308571
|
});
|
|
308075
308572
|
|
|
308076
308573
|
// ../dashboard/src/stt/model-manager.ts
|
|
308077
|
-
import { createHash as
|
|
308574
|
+
import { createHash as createHash34, randomUUID as randomUUID57 } from "node:crypto";
|
|
308078
308575
|
import { mkdir as mkdir33, open as open4, readFile as readFile53, readdir as readdir13, rename as rename12, rm as rm20, stat as stat14, writeFile as writeFile35 } from "node:fs/promises";
|
|
308079
308576
|
import { join as join109, relative as relative23, resolve as resolve57, sep as sep17 } from "node:path";
|
|
308080
308577
|
function parseSafeTarListing(listing) {
|
|
@@ -308163,7 +308660,7 @@ function createVoiceModelManager(options = {}) {
|
|
|
308163
308660
|
if (!response.ok || !response.body) throw Object.assign(new Error("download failed"), { voiceReason: "network" });
|
|
308164
308661
|
if (!current(g2, signal)) return state;
|
|
308165
308662
|
const total = Number(response.headers.get("content-length")) || void 0;
|
|
308166
|
-
const hash3 =
|
|
308663
|
+
const hash3 = createHash34("sha256");
|
|
308167
308664
|
let bytes = 0;
|
|
308168
308665
|
for await (const chunk of response.body) {
|
|
308169
308666
|
if (!current(g2, signal)) return state;
|
|
@@ -312361,6 +312858,50 @@ async function getAgentStore(cwd) {
|
|
|
312361
312858
|
const projectStore = await getStore(cwd);
|
|
312362
312859
|
return new AgentStore({ rootDir: getFusionDir(cwd), asyncLayer: requireProjectLayer(projectStore, "CLI AgentStore") });
|
|
312363
312860
|
}
|
|
312861
|
+
async function resolveManagerEvaluationTarget(agentStore, agentId, ctx) {
|
|
312862
|
+
const target = await agentStore.resolveAgent(agentId);
|
|
312863
|
+
if (!target) {
|
|
312864
|
+
return {
|
|
312865
|
+
kind: "error",
|
|
312866
|
+
response: {
|
|
312867
|
+
content: [{ type: "text", text: `Agent '${agentId}' not found` }],
|
|
312868
|
+
isError: true,
|
|
312869
|
+
details: { outcome: "not_found", error: "Agent not found", agentId }
|
|
312870
|
+
}
|
|
312871
|
+
};
|
|
312872
|
+
}
|
|
312873
|
+
if (isEphemeralAgent(target)) {
|
|
312874
|
+
return {
|
|
312875
|
+
kind: "error",
|
|
312876
|
+
response: {
|
|
312877
|
+
content: [{ type: "text", text: `ERROR: Cannot evaluate ephemeral/runtime agent ${target.id}` }],
|
|
312878
|
+
isError: true,
|
|
312879
|
+
details: { outcome: "invalid", field: "agent_id", agentId: target.id }
|
|
312880
|
+
}
|
|
312881
|
+
};
|
|
312882
|
+
}
|
|
312883
|
+
const callerAgentId = typeof ctx.agentId === "string" && ctx.agentId ? ctx.agentId : void 0;
|
|
312884
|
+
if (callerAgentId) {
|
|
312885
|
+
const chain = await agentStore.getChainOfCommand(target.id);
|
|
312886
|
+
const callerIndex = chain.findIndex((agent) => agent.id === callerAgentId);
|
|
312887
|
+
if (callerAgentId === target.id || callerIndex < 1) {
|
|
312888
|
+
return {
|
|
312889
|
+
kind: "error",
|
|
312890
|
+
response: {
|
|
312891
|
+
content: [{ type: "text", text: "ERROR: You can only access evaluations for your own direct or indirect reports." }],
|
|
312892
|
+
isError: true,
|
|
312893
|
+
details: {
|
|
312894
|
+
outcome: "denied",
|
|
312895
|
+
agentId: target.id,
|
|
312896
|
+
callerAgentId,
|
|
312897
|
+
rule: "direct-or-indirect-reports-only"
|
|
312898
|
+
}
|
|
312899
|
+
}
|
|
312900
|
+
};
|
|
312901
|
+
}
|
|
312902
|
+
}
|
|
312903
|
+
return { kind: "allowed", target, callerAgentId };
|
|
312904
|
+
}
|
|
312364
312905
|
function emitSecretAudit(store, ctx, mutationType, target, metadata) {
|
|
312365
312906
|
if (!ctx.runId || !ctx.agentId) return;
|
|
312366
312907
|
try {
|
|
@@ -316433,6 +316974,143 @@ Status: ${updated.status}`
|
|
|
316433
316974
|
};
|
|
316434
316975
|
}
|
|
316435
316976
|
});
|
|
316977
|
+
pi2.registerTool({
|
|
316978
|
+
name: "fn_agent_read_evaluations",
|
|
316979
|
+
label: "fn: Read Report Evaluations",
|
|
316980
|
+
description: "Read ratings, feedback, reflections, and performance data for a direct or indirect report.",
|
|
316981
|
+
promptSnippet: "Review evaluation and reflection results for an agent in your management subtree",
|
|
316982
|
+
promptGuidelines: [
|
|
316983
|
+
"Use to review evaluation data for a direct or indirect report in your management subtree",
|
|
316984
|
+
"Agent callers cannot target themselves, peers, ancestors, or agents outside their subtree",
|
|
316985
|
+
"Operator and CLI calls are privileged and may read any durable agent"
|
|
316986
|
+
],
|
|
316987
|
+
parameters: Type12.Object({
|
|
316988
|
+
agent_id: Type12.String({ description: "Target agent ID or resolvable name" }),
|
|
316989
|
+
rating_limit: Type12.Optional(Type12.Number({ minimum: 1, maximum: 50, description: "Maximum ratings to return (default 10)" })),
|
|
316990
|
+
reflection_limit: Type12.Optional(Type12.Number({ minimum: 1, maximum: 20, description: "Maximum reflections to return (default 5)" }))
|
|
316991
|
+
}),
|
|
316992
|
+
async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
|
|
316993
|
+
const agentStore = await getAgentStore(ctx.cwd);
|
|
316994
|
+
await agentStore.init();
|
|
316995
|
+
const resolved = await resolveManagerEvaluationTarget(agentStore, params.agent_id, ctx);
|
|
316996
|
+
if (resolved.kind === "error") return resolved.response;
|
|
316997
|
+
const ratingLimit = params.rating_limit ?? 10;
|
|
316998
|
+
const reflectionLimit = params.reflection_limit ?? 5;
|
|
316999
|
+
const reflectionStore = new ReflectionStore({ rootDir: getFusionDir(ctx.cwd) });
|
|
317000
|
+
await reflectionStore.init();
|
|
317001
|
+
const [summary, ratings, latestReflection, reflections, performance4] = await Promise.all([
|
|
317002
|
+
agentStore.getRatingSummary(resolved.target.id),
|
|
317003
|
+
agentStore.getRatings(resolved.target.id, { limit: ratingLimit }),
|
|
317004
|
+
reflectionStore.getLatestReflection(resolved.target.id),
|
|
317005
|
+
reflectionStore.getReflections(resolved.target.id, reflectionLimit),
|
|
317006
|
+
reflectionStore.getPerformanceSummary(resolved.target.id)
|
|
317007
|
+
]);
|
|
317008
|
+
const hasRatings = ratings.length > 0 || summary.totalRatings > 0;
|
|
317009
|
+
const hasReflections = Boolean(latestReflection) || reflections.length > 0;
|
|
317010
|
+
if (!hasRatings && !hasReflections) {
|
|
317011
|
+
return {
|
|
317012
|
+
content: [{ type: "text", text: `${resolved.target.name} (${resolved.target.id})
|
|
317013
|
+
|
|
317014
|
+
No evaluation data available yet.` }],
|
|
317015
|
+
details: { outcome: "empty", agentId: resolved.target.id, agentName: resolved.target.name, summary, ratings, reflections, latestReflection, performance: performance4 }
|
|
317016
|
+
};
|
|
317017
|
+
}
|
|
317018
|
+
const formatScore2 = (score) => typeof score === "number" && Number.isFinite(score) ? score.toFixed(2) : "n/a";
|
|
317019
|
+
const lines = [
|
|
317020
|
+
`Evaluation Summary: ${resolved.target.name} (${resolved.target.id})`,
|
|
317021
|
+
`- Average score: ${formatScore2(summary.averageScore)}`,
|
|
317022
|
+
`- Trend: ${summary.trend}`,
|
|
317023
|
+
`- Total ratings: ${summary.totalRatings}`
|
|
317024
|
+
];
|
|
317025
|
+
const categoryEntries = Object.entries(summary.categoryAverages ?? {});
|
|
317026
|
+
if (categoryEntries.length > 0) {
|
|
317027
|
+
lines.push("", "Category averages:");
|
|
317028
|
+
categoryEntries.forEach(([category, score]) => lines.push(`- ${category}: ${formatScore2(score)}`));
|
|
317029
|
+
}
|
|
317030
|
+
const commentedRatings = ratings.filter((rating) => rating.comment?.trim());
|
|
317031
|
+
if (commentedRatings.length > 0) {
|
|
317032
|
+
lines.push("", "Recent rating comments:");
|
|
317033
|
+
commentedRatings.slice(0, 5).forEach((rating) => lines.push(`- [${rating.score}/5] ${rating.comment.trim()}`));
|
|
317034
|
+
}
|
|
317035
|
+
if (latestReflection) {
|
|
317036
|
+
lines.push("", "Latest reflection:", `- Summary: ${latestReflection.summary}`);
|
|
317037
|
+
if (latestReflection.insights.length > 0) {
|
|
317038
|
+
lines.push("- Insights:");
|
|
317039
|
+
latestReflection.insights.forEach((insight) => lines.push(` - ${insight}`));
|
|
317040
|
+
}
|
|
317041
|
+
if (latestReflection.suggestedImprovements.length > 0) {
|
|
317042
|
+
lines.push("- Suggested improvements:");
|
|
317043
|
+
latestReflection.suggestedImprovements.forEach((item) => lines.push(` - ${item}`));
|
|
317044
|
+
}
|
|
317045
|
+
}
|
|
317046
|
+
if (reflections.length > 0) {
|
|
317047
|
+
lines.push("", "Recent reflection history:");
|
|
317048
|
+
reflections.slice(0, 5).forEach((reflection) => lines.push(`- ${reflection.timestamp}: ${reflection.summary}`));
|
|
317049
|
+
}
|
|
317050
|
+
return {
|
|
317051
|
+
content: [{ type: "text", text: lines.join("\n") }],
|
|
317052
|
+
details: { outcome: "read", agentId: resolved.target.id, agentName: resolved.target.name, summary, ratings, reflections, latestReflection, performance: performance4 }
|
|
317053
|
+
};
|
|
317054
|
+
}
|
|
317055
|
+
});
|
|
317056
|
+
pi2.registerTool({
|
|
317057
|
+
name: "fn_agent_evaluation_followup",
|
|
317058
|
+
label: "fn: Record Evaluation Follow-up",
|
|
317059
|
+
description: "Record a coaching evaluation follow-up for a direct or indirect report to read through its self-improvement loop.",
|
|
317060
|
+
promptSnippet: "Record coaching feedback for an agent in your management subtree",
|
|
317061
|
+
promptGuidelines: [
|
|
317062
|
+
"Use to record actionable coaching feedback for a direct or indirect report",
|
|
317063
|
+
"Agent callers cannot target themselves, peers, ancestors, or agents outside their subtree",
|
|
317064
|
+
"Create or delegate separate implementation work with fn_task_create or fn_delegate_task"
|
|
317065
|
+
],
|
|
317066
|
+
parameters: Type12.Object({
|
|
317067
|
+
agent_id: Type12.String({ description: "Target agent ID or resolvable name" }),
|
|
317068
|
+
score: Type12.Number({ minimum: 1, maximum: 5, description: "Evaluation score from 1 to 5" }),
|
|
317069
|
+
comment: Type12.String({ minLength: 1, maxLength: 4e3, description: "Coaching or follow-up note" }),
|
|
317070
|
+
category: Type12.Optional(Type12.String({ maxLength: 100, description: "Optional evaluation category" })),
|
|
317071
|
+
task_id: Type12.Optional(Type12.String({ description: "Optional related task ID" }))
|
|
317072
|
+
}),
|
|
317073
|
+
async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
|
|
317074
|
+
const gated = await applyAgentPolicyGateForExtensionTool(
|
|
317075
|
+
"fn_agent_evaluation_followup",
|
|
317076
|
+
params,
|
|
317077
|
+
ctx
|
|
317078
|
+
);
|
|
317079
|
+
if (gated) return gated;
|
|
317080
|
+
const agentStore = await getAgentStore(ctx.cwd);
|
|
317081
|
+
await agentStore.init();
|
|
317082
|
+
const resolved = await resolveManagerEvaluationTarget(agentStore, params.agent_id, ctx);
|
|
317083
|
+
if (resolved.kind === "error") return resolved.response;
|
|
317084
|
+
if (!Number.isFinite(params.score) || params.score < 1 || params.score > 5) {
|
|
317085
|
+
return {
|
|
317086
|
+
content: [{ type: "text", text: "ERROR: score must be a finite value from 1 to 5" }],
|
|
317087
|
+
isError: true,
|
|
317088
|
+
details: { outcome: "invalid", field: "score" }
|
|
317089
|
+
};
|
|
317090
|
+
}
|
|
317091
|
+
const comment = params.comment.trim();
|
|
317092
|
+
if (!comment) {
|
|
317093
|
+
return {
|
|
317094
|
+
content: [{ type: "text", text: "ERROR: comment must not be empty" }],
|
|
317095
|
+
isError: true,
|
|
317096
|
+
details: { outcome: "invalid", field: "comment" }
|
|
317097
|
+
};
|
|
317098
|
+
}
|
|
317099
|
+
const raterType = resolved.callerAgentId ? "agent" : "user";
|
|
317100
|
+
const rating = await agentStore.addRating(resolved.target.id, {
|
|
317101
|
+
raterType,
|
|
317102
|
+
...resolved.callerAgentId ? { raterId: resolved.callerAgentId } : {},
|
|
317103
|
+
score: params.score,
|
|
317104
|
+
...params.category !== void 0 ? { category: params.category } : {},
|
|
317105
|
+
comment,
|
|
317106
|
+
...params.task_id !== void 0 ? { taskId: params.task_id } : {}
|
|
317107
|
+
});
|
|
317108
|
+
return {
|
|
317109
|
+
content: [{ type: "text", text: `Recorded evaluation follow-up for ${resolved.target.name} (${resolved.target.id}).` }],
|
|
317110
|
+
details: { outcome: "recorded", agentId: resolved.target.id, ratingId: rating.id, score: rating.score, raterType }
|
|
317111
|
+
};
|
|
317112
|
+
}
|
|
317113
|
+
});
|
|
316436
317114
|
pi2.registerTool({
|
|
316437
317115
|
name: "fn_agent_delete",
|
|
316438
317116
|
label: "fn: Delete Agent",
|