@runfusion/fusion 0.37.0 → 0.38.1
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 +1510 -234
- package/dist/client/.vite/manifest.json +58 -58
- package/dist/client/assets/AgentDetailView-DuRYmHK3.js +18 -0
- package/dist/client/assets/{AgentPermissionPolicyEditor-niLSqGAE.js → AgentPermissionPolicyEditor-ClY32kYN.js} +1 -1
- package/dist/client/assets/AgentsView-UbCAHs_i.js +29 -0
- package/dist/client/assets/ChatView-DDDjYRKc.js +6 -0
- package/dist/client/assets/{DevServerView-0Gb44WOb.js → DevServerView-DY5GlJcD.js} +1 -1
- package/dist/client/assets/{DirectoryPicker-BSQA0XM9.js → DirectoryPicker-B4VRL2BH.js} +1 -1
- package/dist/client/assets/{DocumentsView-XZbaqEFF.js → DocumentsView-tqpIZ9t9.js} +1 -1
- package/dist/client/assets/{EvalsView-CJNtXxX9.js → EvalsView-C_Br3ry8.js} +1 -1
- package/dist/client/assets/{ExperimentalAgentOnboardingModal-DR8E3i36.js → ExperimentalAgentOnboardingModal-lXM--LV-.js} +1 -1
- package/dist/client/assets/GoalsView-B65urz9k.css +1 -0
- package/dist/client/assets/{GoalsView-CN1zQ_Ax.js → GoalsView-CI3Bzs1b.js} +1 -1
- package/dist/client/assets/{InsightsView-D_jRaMyn.js → InsightsView-BYfsVobi.js} +2 -2
- package/dist/client/assets/{MemoryView-D90vdPnp.js → MemoryView-DT4vIhaW.js} +1 -1
- package/dist/client/assets/{NodesView-C1zuedAe.js → NodesView-Dx6HFqjI.js} +1 -1
- package/dist/client/assets/{PiExtensionsManager-DBJDDVfM.js → PiExtensionsManager-BcGBnNiC.js} +2 -2
- package/dist/client/assets/{PluginManager-Ceg64P2Z.js → PluginManager-T_XZ7iNI.js} +1 -1
- package/dist/client/assets/{ResearchView-XRwWdczc.js → ResearchView-Bv4igpnv.js} +1 -1
- package/dist/client/assets/{SecretsView-TCrKyCme.js → SecretsView-C4VX2ZTa.js} +1 -1
- package/dist/client/assets/SettingsModal-CLEkhLK_.js +31 -0
- package/dist/client/assets/{SettingsModal-C1TczsEr.js → SettingsModal-Cy42vswI.js} +1 -1
- package/dist/client/assets/SettingsModal-D_uIvf6n.css +1 -0
- package/dist/client/assets/{SetupWizardModal-D6moSTT3.js → SetupWizardModal-LqloAL4J.js} +1 -1
- package/dist/client/assets/{SkillsView-BDHLPVBi.js → SkillsView-I1SDKaRz.js} +1 -1
- package/dist/client/assets/{StashRecoveryView-DZGa591R.js → StashRecoveryView-DMUUR3cy.js} +1 -1
- package/dist/client/assets/{TodoView-nr_SnCJv.js → TodoView-PKvJKjtV.js} +2 -2
- package/dist/client/assets/{dashboard-view-0XeZ1FTR.js → dashboard-view-D4XVI1XP.js} +2 -2
- package/dist/client/assets/{folder-open-iURwQbEg.js → folder-open-Doam5g-y.js} +1 -1
- package/dist/client/assets/index-BS-jSWPW.js +742 -0
- package/dist/client/assets/index-ktpD_W3I.css +1 -0
- package/dist/client/assets/{upload-Beqg4S4L.js → upload-BUfrZl69.js} +1 -1
- package/dist/client/assets/{users-C2o86ZCR.js → users-XNGnYBJb.js} +1 -1
- package/dist/client/index.html +40 -3
- package/dist/client/version.json +1 -1
- package/dist/droid-cli/package.json +1 -1
- package/dist/extension.js +1326 -182
- package/dist/pi-claude-cli/package.json +1 -1
- package/dist/plugins/fusion-plugin-cli-printing-press/package.json +1 -1
- package/dist/plugins/fusion-plugin-cursor-runtime/package.json +1 -1
- package/dist/plugins/fusion-plugin-dependency-graph/package.json +1 -1
- package/dist/plugins/fusion-plugin-droid-runtime/package.json +1 -1
- package/dist/plugins/fusion-plugin-hermes-runtime/package.json +1 -1
- package/dist/plugins/fusion-plugin-openclaw-runtime/package.json +1 -1
- package/dist/plugins/fusion-plugin-paperclip-runtime/package.json +1 -1
- package/dist/plugins/fusion-plugin-reports/package.json +1 -1
- package/dist/plugins/fusion-plugin-roadmap/package.json +1 -1
- package/dist/plugins/fusion-plugin-whatsapp-chat/package.json +1 -1
- package/package.json +1 -1
- package/dist/client/assets/AgentDetailView-T_AHPxcG.js +0 -18
- package/dist/client/assets/AgentsView-CQhaLHz_.js +0 -29
- package/dist/client/assets/ChatView-B60kYfdk.js +0 -6
- package/dist/client/assets/GoalsView-CtWi0fxE.css +0 -1
- package/dist/client/assets/SettingsModal-0gevFhXV.css +0 -1
- package/dist/client/assets/SettingsModal-B8fRuWdQ.js +0 -31
- package/dist/client/assets/index-CjuQj4qe.js +0 -742
- package/dist/client/assets/index-DmrpDn7c.css +0 -1
package/dist/bin.js
CHANGED
|
@@ -4674,7 +4674,7 @@ var init_db = __esm({
|
|
|
4674
4674
|
DEFAULT_SQLITE_BUSY_TIMEOUT_MS = 5e3;
|
|
4675
4675
|
DEFAULT_SQLITE_LOCK_RECOVERY_WINDOW_MS = 1e3;
|
|
4676
4676
|
DEFAULT_SQLITE_LOCK_RECOVERY_DELAY_MS = 50;
|
|
4677
|
-
SCHEMA_VERSION =
|
|
4677
|
+
SCHEMA_VERSION = 99;
|
|
4678
4678
|
SCHEMA_SQL = `
|
|
4679
4679
|
-- Tasks table with JSON columns for nested data
|
|
4680
4680
|
CREATE TABLE IF NOT EXISTS tasks (
|
|
@@ -4696,6 +4696,7 @@ CREATE TABLE IF NOT EXISTS tasks (
|
|
|
4696
4696
|
pausedReason TEXT,
|
|
4697
4697
|
baseBranch TEXT,
|
|
4698
4698
|
branch TEXT,
|
|
4699
|
+
autoMerge INTEGER,
|
|
4699
4700
|
executionStartBranch TEXT,
|
|
4700
4701
|
baseCommitSha TEXT,
|
|
4701
4702
|
modelPresetId TEXT,
|
|
@@ -4707,12 +4708,16 @@ CREATE TABLE IF NOT EXISTS tasks (
|
|
|
4707
4708
|
planningModelId TEXT,
|
|
4708
4709
|
mergeRetries INTEGER,
|
|
4709
4710
|
workflowStepRetries INTEGER,
|
|
4711
|
+
resumeLimboCount INTEGER DEFAULT 0,
|
|
4712
|
+
resumeLimboTipSha TEXT,
|
|
4713
|
+
resumeLimboStepSignature TEXT,
|
|
4710
4714
|
recoveryRetryCount INTEGER,
|
|
4711
4715
|
taskDoneRetryCount INTEGER DEFAULT 0,
|
|
4712
4716
|
worktreeSessionRetryCount INTEGER DEFAULT 0,
|
|
4713
4717
|
completionHandoffLimboRecoveryCount INTEGER DEFAULT 0,
|
|
4714
4718
|
mergeConflictBounceCount INTEGER DEFAULT 0,
|
|
4715
4719
|
mergeAuditBounceCount INTEGER DEFAULT 0,
|
|
4720
|
+
mergeTransientRetryCount INTEGER DEFAULT 0,
|
|
4716
4721
|
nextRecoveryAt TEXT,
|
|
4717
4722
|
error TEXT,
|
|
4718
4723
|
summary TEXT,
|
|
@@ -5222,11 +5227,31 @@ CREATE TABLE IF NOT EXISTS missions (
|
|
|
5222
5227
|
status TEXT NOT NULL,
|
|
5223
5228
|
interviewState TEXT NOT NULL,
|
|
5224
5229
|
baseBranch TEXT,
|
|
5230
|
+
branchStrategy TEXT,
|
|
5225
5231
|
autoAdvance INTEGER DEFAULT 0,
|
|
5232
|
+
autoMerge INTEGER,
|
|
5226
5233
|
createdAt TEXT NOT NULL,
|
|
5227
5234
|
updatedAt TEXT NOT NULL
|
|
5228
5235
|
);
|
|
5229
5236
|
|
|
5237
|
+
CREATE TABLE IF NOT EXISTS branch_groups (
|
|
5238
|
+
id TEXT PRIMARY KEY,
|
|
5239
|
+
sourceType TEXT NOT NULL CHECK (sourceType IN ('mission','planning')),
|
|
5240
|
+
sourceId TEXT NOT NULL,
|
|
5241
|
+
branchName TEXT NOT NULL UNIQUE,
|
|
5242
|
+
worktreePath TEXT,
|
|
5243
|
+
autoMerge INTEGER NOT NULL DEFAULT 0,
|
|
5244
|
+
prState TEXT NOT NULL DEFAULT 'none' CHECK (prState IN ('none','open','merged','closed')),
|
|
5245
|
+
prUrl TEXT,
|
|
5246
|
+
prNumber INTEGER,
|
|
5247
|
+
status TEXT NOT NULL DEFAULT 'open' CHECK (status IN ('open','finalized','abandoned')),
|
|
5248
|
+
createdAt INTEGER NOT NULL,
|
|
5249
|
+
updatedAt INTEGER NOT NULL,
|
|
5250
|
+
closedAt INTEGER
|
|
5251
|
+
);
|
|
5252
|
+
CREATE INDEX IF NOT EXISTS idxBranchGroupsSource ON branch_groups(sourceType, sourceId);
|
|
5253
|
+
CREATE INDEX IF NOT EXISTS idxBranchGroupsBranchName ON branch_groups(branchName);
|
|
5254
|
+
|
|
5230
5255
|
-- Goals table (strategic intent across mission timelines)
|
|
5231
5256
|
CREATE TABLE IF NOT EXISTS goals (
|
|
5232
5257
|
id TEXT PRIMARY KEY,
|
|
@@ -5238,6 +5263,22 @@ CREATE TABLE IF NOT EXISTS goals (
|
|
|
5238
5263
|
);
|
|
5239
5264
|
CREATE INDEX IF NOT EXISTS idxGoalsStatus ON goals(status);
|
|
5240
5265
|
|
|
5266
|
+
CREATE TABLE IF NOT EXISTS goal_citations (
|
|
5267
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
5268
|
+
goalId TEXT NOT NULL,
|
|
5269
|
+
agentId TEXT NOT NULL,
|
|
5270
|
+
taskId TEXT,
|
|
5271
|
+
surface TEXT NOT NULL,
|
|
5272
|
+
sourceRef TEXT NOT NULL,
|
|
5273
|
+
snippet TEXT NOT NULL,
|
|
5274
|
+
timestamp TEXT NOT NULL
|
|
5275
|
+
);
|
|
5276
|
+
CREATE INDEX IF NOT EXISTS idxGoalCitationsGoalId ON goal_citations(goalId);
|
|
5277
|
+
CREATE INDEX IF NOT EXISTS idxGoalCitationsAgentId ON goal_citations(agentId);
|
|
5278
|
+
CREATE INDEX IF NOT EXISTS idxGoalCitationsTimestamp ON goal_citations(timestamp);
|
|
5279
|
+
CREATE UNIQUE INDEX IF NOT EXISTS uxGoalCitationsDedup
|
|
5280
|
+
ON goal_citations(goalId, surface, sourceRef);
|
|
5281
|
+
|
|
5241
5282
|
-- Milestones table (phases within a mission)
|
|
5242
5283
|
CREATE TABLE IF NOT EXISTS milestones (
|
|
5243
5284
|
id TEXT PRIMARY KEY,
|
|
@@ -5534,6 +5575,7 @@ CREATE INDEX IF NOT EXISTS idxTodoItemsSortOrder ON todo_items(listId, sortOrder
|
|
|
5534
5575
|
assertion: "TEXT NOT NULL",
|
|
5535
5576
|
status: "TEXT NOT NULL DEFAULT 'pending'",
|
|
5536
5577
|
orderIndex: "INTEGER NOT NULL DEFAULT 0",
|
|
5578
|
+
sourceFeatureId: "TEXT",
|
|
5537
5579
|
createdAt: "TEXT NOT NULL",
|
|
5538
5580
|
updatedAt: "TEXT NOT NULL"
|
|
5539
5581
|
},
|
|
@@ -7337,6 +7379,11 @@ This means a caller passed a .fusion directory where a project root was expected
|
|
|
7337
7379
|
}
|
|
7338
7380
|
if (version < 75) {
|
|
7339
7381
|
this.applyMigration(75, () => {
|
|
7382
|
+
this.addColumnIfMissing("tasks", "mergeTransientRetryCount", "INTEGER DEFAULT 0");
|
|
7383
|
+
});
|
|
7384
|
+
}
|
|
7385
|
+
if (version < 76) {
|
|
7386
|
+
this.applyMigration(76, () => {
|
|
7340
7387
|
this.db.exec(`
|
|
7341
7388
|
CREATE TABLE IF NOT EXISTS experiment_sessions (
|
|
7342
7389
|
id TEXT PRIMARY KEY,
|
|
@@ -7377,38 +7424,38 @@ This means a caller passed a .fusion directory where a project root was expected
|
|
|
7377
7424
|
this.db.exec(`CREATE INDEX IF NOT EXISTS idxExperimentRecordsType ON experiment_session_records(sessionId, type)`);
|
|
7378
7425
|
});
|
|
7379
7426
|
}
|
|
7380
|
-
if (version <
|
|
7381
|
-
this.applyMigration(
|
|
7427
|
+
if (version < 77) {
|
|
7428
|
+
this.applyMigration(77, () => {
|
|
7382
7429
|
this.addColumnIfMissing("workflow_steps", "gateMode", "TEXT NOT NULL DEFAULT 'advisory'");
|
|
7383
7430
|
this.db.exec("UPDATE workflow_steps SET gateMode = 'advisory'");
|
|
7384
7431
|
});
|
|
7385
7432
|
}
|
|
7386
|
-
if (version <
|
|
7387
|
-
this.applyMigration(
|
|
7433
|
+
if (version < 78) {
|
|
7434
|
+
this.applyMigration(78, () => {
|
|
7388
7435
|
this.addColumnIfMissing("tasks", "tokenBudgetSoftAlertedAt", "TEXT");
|
|
7389
7436
|
this.addColumnIfMissing("tasks", "tokenBudgetHardAlertedAt", "TEXT");
|
|
7390
7437
|
this.addColumnIfMissing("tasks", "tokenBudgetOverride", "TEXT");
|
|
7391
7438
|
});
|
|
7392
7439
|
}
|
|
7393
|
-
if (version <
|
|
7394
|
-
this.applyMigration(
|
|
7440
|
+
if (version < 79) {
|
|
7441
|
+
this.applyMigration(79, () => {
|
|
7395
7442
|
this.addColumnIfMissing("tasks", "branchConflictRecoveryCount", "INTEGER DEFAULT 0");
|
|
7396
7443
|
this.addColumnIfMissing("tasks", "reviewerContextRetryCount", "INTEGER DEFAULT 0");
|
|
7397
7444
|
this.addColumnIfMissing("tasks", "reviewerFallbackRetryCount", "INTEGER DEFAULT 0");
|
|
7398
7445
|
});
|
|
7399
7446
|
}
|
|
7400
|
-
if (version < 79) {
|
|
7401
|
-
this.applyMigration(79, () => {
|
|
7402
|
-
this.addColumnIfMissing("tasks", "overlapBlockedBy", "TEXT");
|
|
7403
|
-
});
|
|
7404
|
-
}
|
|
7405
7447
|
if (version < 80) {
|
|
7406
7448
|
this.applyMigration(80, () => {
|
|
7407
|
-
this.addColumnIfMissing("
|
|
7449
|
+
this.addColumnIfMissing("tasks", "overlapBlockedBy", "TEXT");
|
|
7408
7450
|
});
|
|
7409
7451
|
}
|
|
7410
7452
|
if (version < 81) {
|
|
7411
7453
|
this.applyMigration(81, () => {
|
|
7454
|
+
this.addColumnIfMissing("milestones", "acceptanceCriteria", "TEXT");
|
|
7455
|
+
});
|
|
7456
|
+
}
|
|
7457
|
+
if (version < 82) {
|
|
7458
|
+
this.applyMigration(82, () => {
|
|
7412
7459
|
this.addColumnIfMissing("tasks", "firstExecutionAt", "TEXT");
|
|
7413
7460
|
this.addColumnIfMissing("tasks", "cumulativeActiveMs", "INTEGER");
|
|
7414
7461
|
if (this.hasColumn("tasks", "executionStartedAt")) {
|
|
@@ -7421,13 +7468,13 @@ This means a caller passed a .fusion directory where a project root was expected
|
|
|
7421
7468
|
}
|
|
7422
7469
|
});
|
|
7423
7470
|
}
|
|
7424
|
-
if (version <
|
|
7425
|
-
this.applyMigration(
|
|
7471
|
+
if (version < 83) {
|
|
7472
|
+
this.applyMigration(83, () => {
|
|
7426
7473
|
this.addColumnIfMissing("tasks", "worktreeSessionRetryCount", "INTEGER DEFAULT 0");
|
|
7427
7474
|
});
|
|
7428
7475
|
}
|
|
7429
|
-
if (version <
|
|
7430
|
-
this.applyMigration(
|
|
7476
|
+
if (version < 84) {
|
|
7477
|
+
this.applyMigration(84, () => {
|
|
7431
7478
|
if (!this.hasTable("secrets")) {
|
|
7432
7479
|
this.db.exec(`
|
|
7433
7480
|
CREATE TABLE secrets (
|
|
@@ -7451,8 +7498,8 @@ This means a caller passed a .fusion directory where a project root was expected
|
|
|
7451
7498
|
}
|
|
7452
7499
|
});
|
|
7453
7500
|
}
|
|
7454
|
-
if (version <
|
|
7455
|
-
this.applyMigration(
|
|
7501
|
+
if (version < 85) {
|
|
7502
|
+
this.applyMigration(85, () => {
|
|
7456
7503
|
if (!this.hasColumn("tasks", "title")) {
|
|
7457
7504
|
console.log("[title-id-drift] db.ts migration normalized 0 active titles");
|
|
7458
7505
|
return;
|
|
@@ -7474,24 +7521,24 @@ This means a caller passed a .fusion directory where a project root was expected
|
|
|
7474
7521
|
console.log(`[title-id-drift] db.ts migration normalized ${normalizedCount} active titles`);
|
|
7475
7522
|
});
|
|
7476
7523
|
}
|
|
7477
|
-
if (version < 85) {
|
|
7478
|
-
this.applyMigration(85, () => {
|
|
7479
|
-
this.addColumnIfMissing("tasks", "completionHandoffLimboRecoveryCount", "INTEGER DEFAULT 0");
|
|
7480
|
-
});
|
|
7481
|
-
}
|
|
7482
7524
|
if (version < 86) {
|
|
7483
7525
|
this.applyMigration(86, () => {
|
|
7484
|
-
this.addColumnIfMissing("tasks", "
|
|
7526
|
+
this.addColumnIfMissing("tasks", "completionHandoffLimboRecoveryCount", "INTEGER DEFAULT 0");
|
|
7485
7527
|
});
|
|
7486
7528
|
}
|
|
7487
7529
|
if (version < 87) {
|
|
7488
7530
|
this.applyMigration(87, () => {
|
|
7489
|
-
this.addColumnIfMissing("tasks", "
|
|
7490
|
-
this.db.exec("CREATE INDEX IF NOT EXISTS idx_tasks_deletedAt ON tasks(deletedAt)");
|
|
7531
|
+
this.addColumnIfMissing("tasks", "prInfos", "TEXT");
|
|
7491
7532
|
});
|
|
7492
7533
|
}
|
|
7493
7534
|
if (version < 88) {
|
|
7494
7535
|
this.applyMigration(88, () => {
|
|
7536
|
+
this.addColumnIfMissing("tasks", "deletedAt", "TEXT");
|
|
7537
|
+
this.db.exec("CREATE INDEX IF NOT EXISTS idx_tasks_deletedAt ON tasks(deletedAt)");
|
|
7538
|
+
});
|
|
7539
|
+
}
|
|
7540
|
+
if (version < 89) {
|
|
7541
|
+
this.applyMigration(89, () => {
|
|
7495
7542
|
this.addColumnIfMissing("tasks", "allowResurrection", "INTEGER DEFAULT 0");
|
|
7496
7543
|
try {
|
|
7497
7544
|
const taskColumns = this.getTableColumns("tasks");
|
|
@@ -7516,8 +7563,8 @@ This means a caller passed a .fusion directory where a project root was expected
|
|
|
7516
7563
|
}
|
|
7517
7564
|
});
|
|
7518
7565
|
}
|
|
7519
|
-
if (version <
|
|
7520
|
-
this.applyMigration(
|
|
7566
|
+
if (version < 90) {
|
|
7567
|
+
this.applyMigration(90, () => {
|
|
7521
7568
|
this.db.exec(`
|
|
7522
7569
|
CREATE TABLE IF NOT EXISTS mergeQueue (
|
|
7523
7570
|
taskId TEXT PRIMARY KEY REFERENCES tasks(id) ON DELETE CASCADE,
|
|
@@ -7540,18 +7587,18 @@ This means a caller passed a .fusion directory where a project root was expected
|
|
|
7540
7587
|
`);
|
|
7541
7588
|
});
|
|
7542
7589
|
}
|
|
7543
|
-
if (version < 90) {
|
|
7544
|
-
this.applyMigration(90, () => {
|
|
7545
|
-
this.addColumnIfMissing("tasks", "scopeAutoWiden", "TEXT DEFAULT '[]'");
|
|
7546
|
-
});
|
|
7547
|
-
}
|
|
7548
7590
|
if (version < 91) {
|
|
7549
7591
|
this.applyMigration(91, () => {
|
|
7550
|
-
this.addColumnIfMissing("
|
|
7592
|
+
this.addColumnIfMissing("tasks", "scopeAutoWiden", "TEXT DEFAULT '[]'");
|
|
7551
7593
|
});
|
|
7552
7594
|
}
|
|
7553
7595
|
if (version < 92) {
|
|
7554
7596
|
this.applyMigration(92, () => {
|
|
7597
|
+
this.addColumnIfMissing("missions", "baseBranch", "TEXT");
|
|
7598
|
+
});
|
|
7599
|
+
}
|
|
7600
|
+
if (version < 93) {
|
|
7601
|
+
this.applyMigration(93, () => {
|
|
7555
7602
|
this.db.exec(`
|
|
7556
7603
|
CREATE TABLE IF NOT EXISTS goals (
|
|
7557
7604
|
id TEXT PRIMARY KEY,
|
|
@@ -7568,6 +7615,88 @@ This means a caller passed a .fusion directory where a project root was expected
|
|
|
7568
7615
|
`);
|
|
7569
7616
|
});
|
|
7570
7617
|
}
|
|
7618
|
+
if (version < 94) {
|
|
7619
|
+
this.applyMigration(94, () => {
|
|
7620
|
+
this.db.exec(`
|
|
7621
|
+
CREATE TABLE IF NOT EXISTS goal_citations (
|
|
7622
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
7623
|
+
goalId TEXT NOT NULL,
|
|
7624
|
+
agentId TEXT NOT NULL,
|
|
7625
|
+
taskId TEXT,
|
|
7626
|
+
surface TEXT NOT NULL,
|
|
7627
|
+
sourceRef TEXT NOT NULL,
|
|
7628
|
+
snippet TEXT NOT NULL,
|
|
7629
|
+
timestamp TEXT NOT NULL
|
|
7630
|
+
)
|
|
7631
|
+
`);
|
|
7632
|
+
this.db.exec(`
|
|
7633
|
+
CREATE INDEX IF NOT EXISTS idxGoalCitationsGoalId
|
|
7634
|
+
ON goal_citations(goalId)
|
|
7635
|
+
`);
|
|
7636
|
+
this.db.exec(`
|
|
7637
|
+
CREATE INDEX IF NOT EXISTS idxGoalCitationsAgentId
|
|
7638
|
+
ON goal_citations(agentId)
|
|
7639
|
+
`);
|
|
7640
|
+
this.db.exec(`
|
|
7641
|
+
CREATE INDEX IF NOT EXISTS idxGoalCitationsTimestamp
|
|
7642
|
+
ON goal_citations(timestamp)
|
|
7643
|
+
`);
|
|
7644
|
+
this.db.exec(`
|
|
7645
|
+
CREATE UNIQUE INDEX IF NOT EXISTS uxGoalCitationsDedup
|
|
7646
|
+
ON goal_citations(goalId, surface, sourceRef)
|
|
7647
|
+
`);
|
|
7648
|
+
});
|
|
7649
|
+
}
|
|
7650
|
+
if (version < 96) {
|
|
7651
|
+
this.applyMigration(96, () => {
|
|
7652
|
+
this.db.exec(`
|
|
7653
|
+
CREATE TABLE IF NOT EXISTS branch_groups (
|
|
7654
|
+
id TEXT PRIMARY KEY,
|
|
7655
|
+
sourceType TEXT NOT NULL CHECK (sourceType IN ('mission','planning')),
|
|
7656
|
+
sourceId TEXT NOT NULL,
|
|
7657
|
+
branchName TEXT NOT NULL UNIQUE,
|
|
7658
|
+
worktreePath TEXT,
|
|
7659
|
+
autoMerge INTEGER NOT NULL DEFAULT 0,
|
|
7660
|
+
prState TEXT NOT NULL DEFAULT 'none' CHECK (prState IN ('none','open','merged','closed')),
|
|
7661
|
+
prUrl TEXT,
|
|
7662
|
+
prNumber INTEGER,
|
|
7663
|
+
status TEXT NOT NULL DEFAULT 'open' CHECK (status IN ('open','finalized','abandoned')),
|
|
7664
|
+
createdAt INTEGER NOT NULL,
|
|
7665
|
+
updatedAt INTEGER NOT NULL,
|
|
7666
|
+
closedAt INTEGER
|
|
7667
|
+
)
|
|
7668
|
+
`);
|
|
7669
|
+
this.db.exec(`
|
|
7670
|
+
CREATE INDEX IF NOT EXISTS idxBranchGroupsSource
|
|
7671
|
+
ON branch_groups(sourceType, sourceId)
|
|
7672
|
+
`);
|
|
7673
|
+
this.db.exec(`
|
|
7674
|
+
CREATE INDEX IF NOT EXISTS idxBranchGroupsBranchName
|
|
7675
|
+
ON branch_groups(branchName)
|
|
7676
|
+
`);
|
|
7677
|
+
this.addColumnIfMissing("tasks", "autoMerge", "INTEGER");
|
|
7678
|
+
this.addColumnIfMissing("missions", "autoMerge", "INTEGER");
|
|
7679
|
+
});
|
|
7680
|
+
}
|
|
7681
|
+
if (version < 97) {
|
|
7682
|
+
this.applyMigration(97, () => {
|
|
7683
|
+
if (this.hasTable("mission_contract_assertions")) {
|
|
7684
|
+
this.addColumnIfMissing("mission_contract_assertions", "sourceFeatureId", "TEXT");
|
|
7685
|
+
}
|
|
7686
|
+
});
|
|
7687
|
+
}
|
|
7688
|
+
if (version < 98) {
|
|
7689
|
+
this.applyMigration(98, () => {
|
|
7690
|
+
this.addColumnIfMissing("missions", "branchStrategy", "TEXT");
|
|
7691
|
+
});
|
|
7692
|
+
}
|
|
7693
|
+
if (version < 99) {
|
|
7694
|
+
this.applyMigration(99, () => {
|
|
7695
|
+
this.addColumnIfMissing("tasks", "resumeLimboCount", "INTEGER DEFAULT 0");
|
|
7696
|
+
this.addColumnIfMissing("tasks", "resumeLimboTipSha", "TEXT");
|
|
7697
|
+
this.addColumnIfMissing("tasks", "resumeLimboStepSignature", "TEXT");
|
|
7698
|
+
});
|
|
7699
|
+
}
|
|
7571
7700
|
}
|
|
7572
7701
|
/**
|
|
7573
7702
|
* Run a single migration step inside a transaction and bump the version.
|
|
@@ -12304,6 +12433,53 @@ var init_db_migrate = __esm({
|
|
|
12304
12433
|
}
|
|
12305
12434
|
});
|
|
12306
12435
|
|
|
12436
|
+
// ../core/src/goal-citation-extractor.ts
|
|
12437
|
+
function extractGoalCitations(text) {
|
|
12438
|
+
const normalized = String(text ?? "");
|
|
12439
|
+
if (normalized.length === 0) {
|
|
12440
|
+
return [];
|
|
12441
|
+
}
|
|
12442
|
+
const matches = [];
|
|
12443
|
+
const seen = /* @__PURE__ */ new Set();
|
|
12444
|
+
const pattern = new RegExp(GOAL_ID_PATTERN.source, GOAL_ID_PATTERN.flags);
|
|
12445
|
+
let match;
|
|
12446
|
+
while ((match = pattern.exec(normalized)) !== null) {
|
|
12447
|
+
const goalId = match[0];
|
|
12448
|
+
if (seen.has(goalId)) {
|
|
12449
|
+
continue;
|
|
12450
|
+
}
|
|
12451
|
+
seen.add(goalId);
|
|
12452
|
+
matches.push({ goalId, index: match.index });
|
|
12453
|
+
}
|
|
12454
|
+
return matches;
|
|
12455
|
+
}
|
|
12456
|
+
function buildSnippet(text, index2, max = GOAL_CITATION_SNIPPET_MAX) {
|
|
12457
|
+
const normalized = String(text ?? "");
|
|
12458
|
+
if (normalized.length === 0 || max <= 0) {
|
|
12459
|
+
return "";
|
|
12460
|
+
}
|
|
12461
|
+
const goalMatch = normalized.slice(Math.max(0, index2)).match(/^G-[0-9A-Z]+(?:-[0-9A-Z]+)*/);
|
|
12462
|
+
const goalEnd = goalMatch ? index2 + goalMatch[0].length : index2;
|
|
12463
|
+
let start = Math.max(0, index2 - Math.floor(max / 2));
|
|
12464
|
+
let end = Math.min(normalized.length, start + max);
|
|
12465
|
+
if (end < goalEnd) {
|
|
12466
|
+
end = Math.min(normalized.length, goalEnd);
|
|
12467
|
+
start = Math.max(0, end - max);
|
|
12468
|
+
} else {
|
|
12469
|
+
start = Math.max(0, end - max);
|
|
12470
|
+
}
|
|
12471
|
+
const snippet = normalized.slice(start, end).replace(/\s+/g, " ").trim();
|
|
12472
|
+
return snippet.length <= max ? snippet : snippet.slice(0, max).trim();
|
|
12473
|
+
}
|
|
12474
|
+
var GOAL_ID_PATTERN, GOAL_CITATION_SNIPPET_MAX;
|
|
12475
|
+
var init_goal_citation_extractor = __esm({
|
|
12476
|
+
"../core/src/goal-citation-extractor.ts"() {
|
|
12477
|
+
"use strict";
|
|
12478
|
+
GOAL_ID_PATTERN = /\bG-[0-9A-Z]+(?:-[0-9A-Z]+)*\b/g;
|
|
12479
|
+
GOAL_CITATION_SNIPPET_MAX = 200;
|
|
12480
|
+
}
|
|
12481
|
+
});
|
|
12482
|
+
|
|
12307
12483
|
// ../core/src/duplicate-detection.ts
|
|
12308
12484
|
import { createHash as createHash4 } from "node:crypto";
|
|
12309
12485
|
function normalizeFingerprintPart(value) {
|
|
@@ -12560,6 +12736,18 @@ var init_duplicate_guard = __esm({
|
|
|
12560
12736
|
|
|
12561
12737
|
// ../core/src/mission-store.ts
|
|
12562
12738
|
import { EventEmitter as EventEmitter4 } from "node:events";
|
|
12739
|
+
function missionBranchStrategyDefaults(strategy) {
|
|
12740
|
+
if (!strategy) {
|
|
12741
|
+
return { assignmentMode: "shared" };
|
|
12742
|
+
}
|
|
12743
|
+
if (strategy.mode === "auto-per-task") {
|
|
12744
|
+
return { assignmentMode: "per-task-derived" };
|
|
12745
|
+
}
|
|
12746
|
+
if ((strategy.mode === "existing" || strategy.mode === "custom-new") && strategy.branchName?.trim()) {
|
|
12747
|
+
return { branch: strategy.branchName.trim(), assignmentMode: "shared" };
|
|
12748
|
+
}
|
|
12749
|
+
return { assignmentMode: "shared" };
|
|
12750
|
+
}
|
|
12563
12751
|
function deriveMilestoneAcceptanceCriteriaFromFeatures(features) {
|
|
12564
12752
|
const lines = features.map((feature) => {
|
|
12565
12753
|
const acceptance = feature.acceptanceCriteria?.trim();
|
|
@@ -12608,6 +12796,14 @@ var init_mission_store = __esm({
|
|
|
12608
12796
|
* Convert a database row to a Mission object.
|
|
12609
12797
|
*/
|
|
12610
12798
|
rowToMission(row) {
|
|
12799
|
+
let branchStrategy;
|
|
12800
|
+
if (row.branchStrategy) {
|
|
12801
|
+
try {
|
|
12802
|
+
branchStrategy = JSON.parse(row.branchStrategy);
|
|
12803
|
+
} catch {
|
|
12804
|
+
branchStrategy = void 0;
|
|
12805
|
+
}
|
|
12806
|
+
}
|
|
12611
12807
|
return {
|
|
12612
12808
|
id: row.id,
|
|
12613
12809
|
title: row.title,
|
|
@@ -12615,6 +12811,8 @@ var init_mission_store = __esm({
|
|
|
12615
12811
|
status: row.status,
|
|
12616
12812
|
interviewState: row.interviewState,
|
|
12617
12813
|
baseBranch: row.baseBranch || void 0,
|
|
12814
|
+
branchStrategy,
|
|
12815
|
+
autoMerge: row.autoMerge === null ? void 0 : Boolean(row.autoMerge),
|
|
12618
12816
|
autoAdvance: Boolean(row.autoAdvance),
|
|
12619
12817
|
autopilotEnabled: Boolean(row.autopilotEnabled),
|
|
12620
12818
|
autopilotState: row.autopilotState || "inactive",
|
|
@@ -12651,6 +12849,7 @@ var init_mission_store = __esm({
|
|
|
12651
12849
|
return {
|
|
12652
12850
|
id: row.id,
|
|
12653
12851
|
milestoneId: row.milestoneId,
|
|
12852
|
+
sourceFeatureId: row.sourceFeatureId || void 0,
|
|
12654
12853
|
title: row.title,
|
|
12655
12854
|
assertion: row.assertion,
|
|
12656
12855
|
status: row.status,
|
|
@@ -12778,7 +12977,8 @@ var init_mission_store = __esm({
|
|
|
12778
12977
|
// ── Mission CRUD Operations ────────────────────────────────────────
|
|
12779
12978
|
/**
|
|
12780
12979
|
* Create a new mission.
|
|
12781
|
-
*
|
|
12980
|
+
* Missions are always created stopped (status `planning`, autopilot disabled).
|
|
12981
|
+
* Autopilot is only enabled via an explicit start/update after creation.
|
|
12782
12982
|
*
|
|
12783
12983
|
* @param input - Mission creation input
|
|
12784
12984
|
* @returns The created mission
|
|
@@ -12793,15 +12993,17 @@ var init_mission_store = __esm({
|
|
|
12793
12993
|
status: "planning",
|
|
12794
12994
|
interviewState: "not_started",
|
|
12795
12995
|
baseBranch: input.baseBranch,
|
|
12996
|
+
branchStrategy: input.branchStrategy,
|
|
12997
|
+
autoMerge: input.autoMerge,
|
|
12796
12998
|
autoAdvance: false,
|
|
12797
|
-
autopilotEnabled:
|
|
12999
|
+
autopilotEnabled: false,
|
|
12798
13000
|
autopilotState: "inactive",
|
|
12799
13001
|
createdAt: now,
|
|
12800
13002
|
updatedAt: now
|
|
12801
13003
|
};
|
|
12802
13004
|
this.db.prepare(`
|
|
12803
|
-
INSERT INTO missions (id, title, description, status, interviewState, baseBranch, autoAdvance, autopilotEnabled, autopilotState, createdAt, updatedAt)
|
|
12804
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
13005
|
+
INSERT INTO missions (id, title, description, status, interviewState, baseBranch, branchStrategy, autoMerge, autoAdvance, autopilotEnabled, autopilotState, createdAt, updatedAt)
|
|
13006
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
12805
13007
|
`).run(
|
|
12806
13008
|
mission.id,
|
|
12807
13009
|
mission.title,
|
|
@@ -12809,6 +13011,8 @@ var init_mission_store = __esm({
|
|
|
12809
13011
|
mission.status,
|
|
12810
13012
|
mission.interviewState,
|
|
12811
13013
|
mission.baseBranch ?? null,
|
|
13014
|
+
mission.branchStrategy ? JSON.stringify(mission.branchStrategy) : null,
|
|
13015
|
+
mission.autoMerge === void 0 ? null : mission.autoMerge ? 1 : 0,
|
|
12812
13016
|
mission.autoAdvance ? 1 : 0,
|
|
12813
13017
|
mission.autopilotEnabled ? 1 : 0,
|
|
12814
13018
|
mission.autopilotState ?? "inactive",
|
|
@@ -13275,6 +13479,8 @@ var init_mission_store = __esm({
|
|
|
13275
13479
|
status = ?,
|
|
13276
13480
|
interviewState = ?,
|
|
13277
13481
|
baseBranch = ?,
|
|
13482
|
+
branchStrategy = ?,
|
|
13483
|
+
autoMerge = ?,
|
|
13278
13484
|
autoAdvance = ?,
|
|
13279
13485
|
autopilotEnabled = ?,
|
|
13280
13486
|
autopilotState = ?,
|
|
@@ -13287,6 +13493,8 @@ var init_mission_store = __esm({
|
|
|
13287
13493
|
updated.status,
|
|
13288
13494
|
updated.interviewState,
|
|
13289
13495
|
updated.baseBranch ?? null,
|
|
13496
|
+
updated.branchStrategy ? JSON.stringify(updated.branchStrategy) : null,
|
|
13497
|
+
updated.autoMerge === void 0 ? null : updated.autoMerge ? 1 : 0,
|
|
13290
13498
|
updated.autoAdvance ? 1 : 0,
|
|
13291
13499
|
updated.autopilotEnabled ? 1 : 0,
|
|
13292
13500
|
updated.autopilotState ?? "inactive",
|
|
@@ -13802,7 +14010,8 @@ var init_mission_store = __esm({
|
|
|
13802
14010
|
this.emit("feature:created", feature);
|
|
13803
14011
|
this.recomputeSliceStatus(sliceId);
|
|
13804
14012
|
this.applyDerivedMilestoneAcceptanceCriteria(slice.milestoneId);
|
|
13805
|
-
|
|
14013
|
+
this.ensureFeatureAssertion(feature);
|
|
14014
|
+
return this.getFeature(feature.id) ?? feature;
|
|
13806
14015
|
}
|
|
13807
14016
|
/**
|
|
13808
14017
|
* Get a feature by ID.
|
|
@@ -13887,6 +14096,11 @@ var init_mission_store = __esm({
|
|
|
13887
14096
|
if (taskIdChanged || statusChanged) {
|
|
13888
14097
|
this.recomputeSliceStatus(updated.sliceId);
|
|
13889
14098
|
}
|
|
14099
|
+
const shouldSyncAssertion = updates.title !== void 0 || updates.description !== void 0 || updates.acceptanceCriteria !== void 0;
|
|
14100
|
+
if (shouldSyncAssertion) {
|
|
14101
|
+
this.ensureFeatureAssertion(updated);
|
|
14102
|
+
return this.getFeature(updated.id) ?? updated;
|
|
14103
|
+
}
|
|
13890
14104
|
return updated;
|
|
13891
14105
|
}
|
|
13892
14106
|
/**
|
|
@@ -13901,11 +14115,115 @@ var init_mission_store = __esm({
|
|
|
13901
14115
|
throw new Error(`Feature ${id} not found`);
|
|
13902
14116
|
}
|
|
13903
14117
|
const sliceId = feature.sliceId;
|
|
14118
|
+
const slice = this.getSlice(sliceId);
|
|
14119
|
+
const milestoneId = slice?.milestoneId;
|
|
14120
|
+
if (milestoneId) {
|
|
14121
|
+
const managedAssertion = this.listContractAssertions(milestoneId).find((assertion) => assertion.sourceFeatureId === feature.id);
|
|
14122
|
+
if (managedAssertion) {
|
|
14123
|
+
this.deleteContractAssertion(managedAssertion.id);
|
|
14124
|
+
}
|
|
14125
|
+
}
|
|
13904
14126
|
this.db.prepare("DELETE FROM mission_features WHERE id = ?").run(id);
|
|
13905
14127
|
this.db.bumpLastModified();
|
|
13906
14128
|
this.emit("feature:deleted", id);
|
|
13907
14129
|
this.recomputeSliceStatus(sliceId);
|
|
13908
14130
|
}
|
|
14131
|
+
deriveFeatureAssertion(feature) {
|
|
14132
|
+
const acceptanceCriteria = feature.acceptanceCriteria?.trim();
|
|
14133
|
+
if (acceptanceCriteria) {
|
|
14134
|
+
return { assertionText: acceptanceCriteria, textSource: "acceptanceCriteria" };
|
|
14135
|
+
}
|
|
14136
|
+
const description = feature.description?.trim();
|
|
14137
|
+
if (description) {
|
|
14138
|
+
return { assertionText: description, textSource: "description" };
|
|
14139
|
+
}
|
|
14140
|
+
return {
|
|
14141
|
+
assertionText: `Verify implementation of: ${feature.title}`,
|
|
14142
|
+
textSource: "fallback"
|
|
14143
|
+
};
|
|
14144
|
+
}
|
|
14145
|
+
ensureFeatureAssertion(feature) {
|
|
14146
|
+
const slice = this.getSlice(feature.sliceId);
|
|
14147
|
+
if (!slice) {
|
|
14148
|
+
throw new Error(`Slice ${feature.sliceId} not found`);
|
|
14149
|
+
}
|
|
14150
|
+
const milestoneId = slice.milestoneId;
|
|
14151
|
+
const { assertionText } = this.deriveFeatureAssertion(feature);
|
|
14152
|
+
const existing = this.listContractAssertions(milestoneId).find((assertion) => assertion.sourceFeatureId === feature.id);
|
|
14153
|
+
if (!existing) {
|
|
14154
|
+
const created = this.addContractAssertion(milestoneId, {
|
|
14155
|
+
title: feature.title,
|
|
14156
|
+
assertion: assertionText,
|
|
14157
|
+
status: "pending",
|
|
14158
|
+
sourceFeatureId: feature.id
|
|
14159
|
+
});
|
|
14160
|
+
this.linkFeatureToAssertion(feature.id, created.id);
|
|
14161
|
+
return;
|
|
14162
|
+
}
|
|
14163
|
+
if (existing.title !== feature.title || existing.assertion !== assertionText) {
|
|
14164
|
+
this.updateContractAssertion(existing.id, {
|
|
14165
|
+
title: feature.title,
|
|
14166
|
+
assertion: assertionText
|
|
14167
|
+
});
|
|
14168
|
+
}
|
|
14169
|
+
}
|
|
14170
|
+
/**
|
|
14171
|
+
* Backfill assertion links for legacy features that predate the FN-5695 creation-path fix.
|
|
14172
|
+
* Reuses deriveFeatureAssertion()/ensureFeatureAssertion text-source rules so create/update
|
|
14173
|
+
* and repair flows stay aligned on canonical assertion content.
|
|
14174
|
+
*/
|
|
14175
|
+
backfillFeatureAssertions(options) {
|
|
14176
|
+
const dryRun = options?.dryRun ?? true;
|
|
14177
|
+
const missionFilter = options?.missionId;
|
|
14178
|
+
const features = missionFilter ? this.listMilestones(missionFilter).flatMap((milestone) => this.listSlices(milestone.id)).flatMap((slice) => this.listFeatures(slice.id)) : this.listMissions().flatMap((mission) => this.listMilestones(mission.id)).flatMap((milestone) => this.listSlices(milestone.id)).flatMap((slice) => this.listFeatures(slice.id));
|
|
14179
|
+
const report = {
|
|
14180
|
+
scanned: features.length,
|
|
14181
|
+
alreadyLinked: 0,
|
|
14182
|
+
repaired: [],
|
|
14183
|
+
skippedErrors: []
|
|
14184
|
+
};
|
|
14185
|
+
for (const feature of features) {
|
|
14186
|
+
try {
|
|
14187
|
+
const linkedAssertions = this.listAssertionsForFeature(feature.id);
|
|
14188
|
+
if (linkedAssertions.length > 0) {
|
|
14189
|
+
report.alreadyLinked += 1;
|
|
14190
|
+
continue;
|
|
14191
|
+
}
|
|
14192
|
+
const slice = this.getSlice(feature.sliceId);
|
|
14193
|
+
if (!slice) {
|
|
14194
|
+
throw new Error(`Slice ${feature.sliceId} not found`);
|
|
14195
|
+
}
|
|
14196
|
+
const milestoneId = slice.milestoneId;
|
|
14197
|
+
const { assertionText, textSource } = this.deriveFeatureAssertion(feature);
|
|
14198
|
+
if (dryRun) {
|
|
14199
|
+
report.repaired.push({
|
|
14200
|
+
featureId: feature.id,
|
|
14201
|
+
milestoneId,
|
|
14202
|
+
assertionId: "(dry-run)",
|
|
14203
|
+
textSource
|
|
14204
|
+
});
|
|
14205
|
+
continue;
|
|
14206
|
+
}
|
|
14207
|
+
const created = this.addContractAssertion(milestoneId, {
|
|
14208
|
+
title: feature.title,
|
|
14209
|
+
assertion: assertionText,
|
|
14210
|
+
status: "pending",
|
|
14211
|
+
sourceFeatureId: feature.id
|
|
14212
|
+
});
|
|
14213
|
+
this.linkFeatureToAssertion(feature.id, created.id);
|
|
14214
|
+
report.repaired.push({
|
|
14215
|
+
featureId: feature.id,
|
|
14216
|
+
milestoneId,
|
|
14217
|
+
assertionId: created.id,
|
|
14218
|
+
textSource
|
|
14219
|
+
});
|
|
14220
|
+
} catch (error) {
|
|
14221
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
14222
|
+
report.skippedErrors.push({ featureId: feature.id, message });
|
|
14223
|
+
}
|
|
14224
|
+
}
|
|
14225
|
+
return report;
|
|
14226
|
+
}
|
|
13909
14227
|
/**
|
|
13910
14228
|
* Resolve the mission hierarchy for a slice.
|
|
13911
14229
|
*
|
|
@@ -14498,6 +14816,7 @@ var init_mission_store = __esm({
|
|
|
14498
14816
|
const assertion = {
|
|
14499
14817
|
id,
|
|
14500
14818
|
milestoneId,
|
|
14819
|
+
sourceFeatureId: input.sourceFeatureId,
|
|
14501
14820
|
title: input.title,
|
|
14502
14821
|
assertion: input.assertion,
|
|
14503
14822
|
status: input.status || "pending",
|
|
@@ -14506,8 +14825,8 @@ var init_mission_store = __esm({
|
|
|
14506
14825
|
updatedAt: now
|
|
14507
14826
|
};
|
|
14508
14827
|
this.db.prepare(`
|
|
14509
|
-
INSERT INTO mission_contract_assertions (id, milestoneId, title, assertion, status, orderIndex, createdAt, updatedAt)
|
|
14510
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
|
14828
|
+
INSERT INTO mission_contract_assertions (id, milestoneId, title, assertion, status, orderIndex, sourceFeatureId, createdAt, updatedAt)
|
|
14829
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
14511
14830
|
`).run(
|
|
14512
14831
|
assertion.id,
|
|
14513
14832
|
assertion.milestoneId,
|
|
@@ -14515,6 +14834,7 @@ var init_mission_store = __esm({
|
|
|
14515
14834
|
assertion.assertion,
|
|
14516
14835
|
assertion.status,
|
|
14517
14836
|
assertion.orderIndex,
|
|
14837
|
+
assertion.sourceFeatureId ?? null,
|
|
14518
14838
|
assertion.createdAt,
|
|
14519
14839
|
assertion.updatedAt
|
|
14520
14840
|
);
|
|
@@ -14956,7 +15276,10 @@ ${feature.acceptanceCriteria}`);
|
|
|
14956
15276
|
const milestone = slice ? this.getMilestone(slice.milestoneId) : void 0;
|
|
14957
15277
|
const missionId = milestone?.missionId;
|
|
14958
15278
|
const mission = missionId ? this.getMission(missionId) : void 0;
|
|
15279
|
+
const strategyDefaults = missionBranchStrategyDefaults(mission?.branchStrategy);
|
|
14959
15280
|
const resolvedBaseBranch = branchOptions?.baseBranch ?? mission?.baseBranch;
|
|
15281
|
+
const resolvedBranch = branchOptions?.branch ?? strategyDefaults.branch;
|
|
15282
|
+
const resolvedAssignmentMode = branchOptions?.assignmentMode ?? strategyDefaults.assignmentMode;
|
|
14960
15283
|
const lockScope = missionId ? `mission:${missionId}` : `mission-store:${this.taskStore.getRootDir()}`;
|
|
14961
15284
|
const guard = await runDeterministicDuplicateGuard(this.taskStore, {
|
|
14962
15285
|
title: taskTitle || feature.title,
|
|
@@ -14970,13 +15293,13 @@ ${feature.acceptanceCriteria}`);
|
|
|
14970
15293
|
const createdTask = await this.taskStore.createTask({
|
|
14971
15294
|
title: taskTitle || feature.title,
|
|
14972
15295
|
description,
|
|
14973
|
-
branch:
|
|
15296
|
+
branch: resolvedBranch,
|
|
14974
15297
|
baseBranch: resolvedBaseBranch,
|
|
14975
15298
|
...missionId ? {
|
|
14976
15299
|
branchContext: {
|
|
14977
15300
|
groupId: `mission:${missionId}`,
|
|
14978
15301
|
source: "mission",
|
|
14979
|
-
assignmentMode:
|
|
15302
|
+
assignmentMode: resolvedAssignmentMode,
|
|
14980
15303
|
inheritedBaseBranch: resolvedBaseBranch
|
|
14981
15304
|
}
|
|
14982
15305
|
} : {}
|
|
@@ -15021,14 +15344,18 @@ ${feature.acceptanceCriteria}`);
|
|
|
15021
15344
|
const definedFeatures = features.filter((f2) => f2.status === "defined");
|
|
15022
15345
|
const milestone = this.getMilestone(slice.milestoneId);
|
|
15023
15346
|
const mission = milestone ? this.getMission(milestone.missionId) : void 0;
|
|
15347
|
+
const strategyDefaults = missionBranchStrategyDefaults(mission?.branchStrategy);
|
|
15024
15348
|
const resolvedBaseBranch = branchOptions?.baseBranch ?? mission?.baseBranch;
|
|
15349
|
+
const resolvedAssignmentMode = branchOptions?.assignmentMode ?? strategyDefaults.assignmentMode;
|
|
15350
|
+
const resolvedBranch = branchOptions?.branch ?? strategyDefaults.branch;
|
|
15025
15351
|
const triaged = [];
|
|
15026
15352
|
for (const feature of definedFeatures) {
|
|
15027
|
-
const
|
|
15353
|
+
const strategyBranch = resolvedAssignmentMode === "per-task-derived" ? resolvedBranch ? `${resolvedBranch}/${feature.id.toLowerCase()}` : void 0 : resolvedBranch;
|
|
15028
15354
|
const updated = await this.triageFeature(feature.id, void 0, void 0, {
|
|
15029
|
-
|
|
15030
|
-
|
|
15031
|
-
|
|
15355
|
+
branch: strategyBranch,
|
|
15356
|
+
baseBranch: resolvedBaseBranch,
|
|
15357
|
+
assignmentMode: resolvedAssignmentMode,
|
|
15358
|
+
...branchOptions
|
|
15032
15359
|
});
|
|
15033
15360
|
triaged.push(updated);
|
|
15034
15361
|
}
|
|
@@ -15180,17 +15507,20 @@ ${feature.acceptanceCriteria}`);
|
|
|
15180
15507
|
validateSnapshotEnvelope(snapshot);
|
|
15181
15508
|
let applied = 0;
|
|
15182
15509
|
for (const mission of snapshot.payload.missions) {
|
|
15183
|
-
this.db.prepare(`INSERT INTO missions (id, title, description, status, interviewState, autoAdvance, autopilotEnabled, autopilotState, lastAutopilotActivityAt, createdAt, updatedAt)
|
|
15184
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
15510
|
+
this.db.prepare(`INSERT INTO missions (id, title, description, status, interviewState, baseBranch, branchStrategy, autoMerge, autoAdvance, autopilotEnabled, autopilotState, lastAutopilotActivityAt, createdAt, updatedAt)
|
|
15511
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
15185
15512
|
ON CONFLICT(id) DO UPDATE SET
|
|
15186
15513
|
title=excluded.title, description=excluded.description, status=excluded.status, interviewState=excluded.interviewState,
|
|
15187
|
-
autoAdvance=excluded.autoAdvance, autopilotEnabled=excluded.autopilotEnabled, autopilotState=excluded.autopilotState,
|
|
15514
|
+
baseBranch=excluded.baseBranch, branchStrategy=excluded.branchStrategy, autoMerge=excluded.autoMerge, autoAdvance=excluded.autoAdvance, autopilotEnabled=excluded.autopilotEnabled, autopilotState=excluded.autopilotState,
|
|
15188
15515
|
lastAutopilotActivityAt=excluded.lastAutopilotActivityAt, updatedAt=excluded.updatedAt`).run(
|
|
15189
15516
|
mission.id,
|
|
15190
15517
|
mission.title,
|
|
15191
15518
|
mission.description ?? null,
|
|
15192
15519
|
mission.status,
|
|
15193
15520
|
mission.interviewState,
|
|
15521
|
+
mission.baseBranch ?? null,
|
|
15522
|
+
mission.branchStrategy ? JSON.stringify(mission.branchStrategy) : null,
|
|
15523
|
+
mission.autoMerge === void 0 ? null : mission.autoMerge ? 1 : 0,
|
|
15194
15524
|
mission.autoAdvance ? 1 : 0,
|
|
15195
15525
|
mission.autopilotEnabled ? 1 : 0,
|
|
15196
15526
|
mission.autopilotState,
|
|
@@ -15276,9 +15606,9 @@ ${feature.acceptanceCriteria}`);
|
|
|
15276
15606
|
}
|
|
15277
15607
|
for (const assertion of snapshot.payload.assertions) {
|
|
15278
15608
|
if (!assertion.id || !assertion.milestoneId) continue;
|
|
15279
|
-
this.db.prepare(`INSERT INTO mission_contract_assertions (id, milestoneId, title, assertion, status, orderIndex, createdAt, updatedAt)
|
|
15280
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
|
15281
|
-
ON CONFLICT(id) DO UPDATE SET title=excluded.title, assertion=excluded.assertion, status=excluded.status, orderIndex=excluded.orderIndex, updatedAt=excluded.updatedAt`).run(assertion.id, assertion.milestoneId, assertion.title, assertion.assertion, assertion.status, assertion.orderIndex, assertion.createdAt, assertion.updatedAt);
|
|
15609
|
+
this.db.prepare(`INSERT INTO mission_contract_assertions (id, milestoneId, title, assertion, status, orderIndex, sourceFeatureId, createdAt, updatedAt)
|
|
15610
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
15611
|
+
ON CONFLICT(id) DO UPDATE SET title=excluded.title, assertion=excluded.assertion, status=excluded.status, orderIndex=excluded.orderIndex, sourceFeatureId=excluded.sourceFeatureId, updatedAt=excluded.updatedAt`).run(assertion.id, assertion.milestoneId, assertion.title, assertion.assertion, assertion.status, assertion.orderIndex, assertion.sourceFeatureId ?? null, assertion.createdAt, assertion.updatedAt);
|
|
15282
15612
|
}
|
|
15283
15613
|
for (const link of snapshot.payload.featureAssertionLinks) {
|
|
15284
15614
|
if (!link.featureId || !link.assertionId) continue;
|
|
@@ -27239,6 +27569,9 @@ var init_secrets_sync_passphrase = __esm({
|
|
|
27239
27569
|
function isFusionSiblingBranch(branch) {
|
|
27240
27570
|
return FUSION_SIBLING_BRANCH_RE.test(branch);
|
|
27241
27571
|
}
|
|
27572
|
+
function resolveEffectiveAutoMerge(task, settings) {
|
|
27573
|
+
return task.autoMerge ?? settings.autoMerge;
|
|
27574
|
+
}
|
|
27242
27575
|
function resolveTaskMergeTarget(task, options = {}) {
|
|
27243
27576
|
let rejected;
|
|
27244
27577
|
const configuredBase = task.baseBranch?.trim();
|
|
@@ -40161,6 +40494,7 @@ var init_store = __esm({
|
|
|
40161
40494
|
init_db();
|
|
40162
40495
|
init_archive_db();
|
|
40163
40496
|
init_db_migrate();
|
|
40497
|
+
init_goal_citation_extractor();
|
|
40164
40498
|
init_mission_store();
|
|
40165
40499
|
init_plugin_store();
|
|
40166
40500
|
init_insight_store();
|
|
@@ -40690,6 +41024,7 @@ var init_store = __esm({
|
|
|
40690
41024
|
baseBranch: row.baseBranch || void 0,
|
|
40691
41025
|
executionStartBranch: row.executionStartBranch || void 0,
|
|
40692
41026
|
branch: row.branch || void 0,
|
|
41027
|
+
autoMerge: row.autoMerge === null ? void 0 : row.autoMerge === 1,
|
|
40693
41028
|
baseCommitSha: row.baseCommitSha || void 0,
|
|
40694
41029
|
scopeOverride: row.scopeOverride ? true : void 0,
|
|
40695
41030
|
scopeOverrideReason: row.scopeOverrideReason || void 0,
|
|
@@ -40704,6 +41039,9 @@ var init_store = __esm({
|
|
|
40704
41039
|
mergeRetries: row.mergeRetries ?? void 0,
|
|
40705
41040
|
workflowStepRetries: row.workflowStepRetries ?? void 0,
|
|
40706
41041
|
stuckKillCount: row.stuckKillCount ?? void 0,
|
|
41042
|
+
resumeLimboCount: row.resumeLimboCount ?? void 0,
|
|
41043
|
+
resumeLimboTipSha: row.resumeLimboTipSha || void 0,
|
|
41044
|
+
resumeLimboStepSignature: row.resumeLimboStepSignature || void 0,
|
|
40707
41045
|
postReviewFixCount: row.postReviewFixCount ?? void 0,
|
|
40708
41046
|
recoveryRetryCount: row.recoveryRetryCount ?? void 0,
|
|
40709
41047
|
taskDoneRetryCount: row.taskDoneRetryCount ?? void 0,
|
|
@@ -40712,6 +41050,7 @@ var init_store = __esm({
|
|
|
40712
41050
|
verificationFailureCount: row.verificationFailureCount ?? void 0,
|
|
40713
41051
|
mergeConflictBounceCount: row.mergeConflictBounceCount ?? void 0,
|
|
40714
41052
|
mergeAuditBounceCount: row.mergeAuditBounceCount ?? void 0,
|
|
41053
|
+
mergeTransientRetryCount: row.mergeTransientRetryCount ?? void 0,
|
|
40715
41054
|
branchConflictRecoveryCount: row.branchConflictRecoveryCount ?? void 0,
|
|
40716
41055
|
reviewerContextRetryCount: row.reviewerContextRetryCount ?? void 0,
|
|
40717
41056
|
reviewerFallbackRetryCount: row.reviewerFallbackRetryCount ?? void 0,
|
|
@@ -40835,6 +41174,28 @@ var init_store = __esm({
|
|
|
40835
41174
|
allowResurrection: row.allowResurrection ? true : void 0
|
|
40836
41175
|
};
|
|
40837
41176
|
}
|
|
41177
|
+
rowToBranchGroup(row) {
|
|
41178
|
+
return {
|
|
41179
|
+
id: row.id,
|
|
41180
|
+
sourceType: row.sourceType,
|
|
41181
|
+
sourceId: row.sourceId,
|
|
41182
|
+
branchName: row.branchName,
|
|
41183
|
+
worktreePath: row.worktreePath ?? void 0,
|
|
41184
|
+
autoMerge: Boolean(row.autoMerge),
|
|
41185
|
+
prState: row.prState,
|
|
41186
|
+
prUrl: row.prUrl ?? void 0,
|
|
41187
|
+
prNumber: row.prNumber ?? void 0,
|
|
41188
|
+
status: row.status,
|
|
41189
|
+
createdAt: row.createdAt,
|
|
41190
|
+
updatedAt: row.updatedAt,
|
|
41191
|
+
closedAt: row.closedAt ?? void 0
|
|
41192
|
+
};
|
|
41193
|
+
}
|
|
41194
|
+
generateBranchGroupId() {
|
|
41195
|
+
const timestamp = Date.now().toString(36).toUpperCase();
|
|
41196
|
+
const random = Math.random().toString(36).slice(2, 8).toUpperCase();
|
|
41197
|
+
return `BG-${timestamp}-${random}`;
|
|
41198
|
+
}
|
|
40838
41199
|
archiveEntryToTask(entry, slim = false) {
|
|
40839
41200
|
return {
|
|
40840
41201
|
id: entry.id,
|
|
@@ -40874,6 +41235,8 @@ var init_store = __esm({
|
|
|
40874
41235
|
planningModelId: entry.planningModelId,
|
|
40875
41236
|
breakIntoSubtasks: entry.breakIntoSubtasks,
|
|
40876
41237
|
noCommitsExpected: entry.noCommitsExpected,
|
|
41238
|
+
branchContext: entry.branchContext,
|
|
41239
|
+
autoMerge: entry.autoMerge,
|
|
40877
41240
|
modifiedFiles: slim ? void 0 : entry.modifiedFiles,
|
|
40878
41241
|
missionId: entry.missionId,
|
|
40879
41242
|
sliceId: entry.sliceId,
|
|
@@ -40987,6 +41350,8 @@ ${recentText}` : void 0
|
|
|
40987
41350
|
noCommitsExpected: task.noCommitsExpected,
|
|
40988
41351
|
baseBranch: task.baseBranch,
|
|
40989
41352
|
branch: task.branch,
|
|
41353
|
+
branchContext: task.branchContext,
|
|
41354
|
+
autoMerge: task.autoMerge,
|
|
40990
41355
|
baseCommitSha: task.baseCommitSha,
|
|
40991
41356
|
mergeRetries: task.mergeRetries,
|
|
40992
41357
|
error: task.error,
|
|
@@ -41027,6 +41392,99 @@ ${recentText}` : void 0
|
|
|
41027
41392
|
createdAt: row.createdAt
|
|
41028
41393
|
};
|
|
41029
41394
|
}
|
|
41395
|
+
rowToGoalCitation(row) {
|
|
41396
|
+
return {
|
|
41397
|
+
id: row.id,
|
|
41398
|
+
goalId: row.goalId,
|
|
41399
|
+
agentId: row.agentId,
|
|
41400
|
+
...row.taskId ? { taskId: row.taskId } : {},
|
|
41401
|
+
surface: row.surface,
|
|
41402
|
+
sourceRef: row.sourceRef,
|
|
41403
|
+
snippet: row.snippet,
|
|
41404
|
+
timestamp: row.timestamp
|
|
41405
|
+
};
|
|
41406
|
+
}
|
|
41407
|
+
recordGoalCitations(inputs) {
|
|
41408
|
+
if (inputs.length === 0) {
|
|
41409
|
+
return [];
|
|
41410
|
+
}
|
|
41411
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
41412
|
+
const stmt = this.db.prepare(`
|
|
41413
|
+
INSERT OR IGNORE INTO goal_citations (goalId, agentId, taskId, surface, sourceRef, snippet, timestamp)
|
|
41414
|
+
VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
41415
|
+
RETURNING *
|
|
41416
|
+
`);
|
|
41417
|
+
const inserted = [];
|
|
41418
|
+
this.db.transaction(() => {
|
|
41419
|
+
for (const input of inputs) {
|
|
41420
|
+
const row = stmt.get(
|
|
41421
|
+
input.goalId,
|
|
41422
|
+
input.agentId,
|
|
41423
|
+
input.taskId ?? null,
|
|
41424
|
+
input.surface,
|
|
41425
|
+
input.sourceRef,
|
|
41426
|
+
input.snippet,
|
|
41427
|
+
input.timestamp ?? now
|
|
41428
|
+
);
|
|
41429
|
+
if (row) {
|
|
41430
|
+
inserted.push(this.rowToGoalCitation(row));
|
|
41431
|
+
}
|
|
41432
|
+
}
|
|
41433
|
+
if (inserted.length > 0) {
|
|
41434
|
+
this.db.bumpLastModified();
|
|
41435
|
+
}
|
|
41436
|
+
});
|
|
41437
|
+
return inserted;
|
|
41438
|
+
}
|
|
41439
|
+
listGoalCitations(filter2 = {}) {
|
|
41440
|
+
const clauses = [];
|
|
41441
|
+
const params = [];
|
|
41442
|
+
if (filter2.goalId) {
|
|
41443
|
+
clauses.push("goalId = ?");
|
|
41444
|
+
params.push(filter2.goalId);
|
|
41445
|
+
}
|
|
41446
|
+
if (filter2.agentId) {
|
|
41447
|
+
clauses.push("agentId = ?");
|
|
41448
|
+
params.push(filter2.agentId);
|
|
41449
|
+
}
|
|
41450
|
+
if (filter2.taskId) {
|
|
41451
|
+
clauses.push("taskId = ?");
|
|
41452
|
+
params.push(filter2.taskId);
|
|
41453
|
+
}
|
|
41454
|
+
if (filter2.surface) {
|
|
41455
|
+
clauses.push("surface = ?");
|
|
41456
|
+
params.push(filter2.surface);
|
|
41457
|
+
}
|
|
41458
|
+
if (filter2.startTime) {
|
|
41459
|
+
clauses.push("timestamp >= ?");
|
|
41460
|
+
params.push(filter2.startTime);
|
|
41461
|
+
}
|
|
41462
|
+
if (filter2.endTime) {
|
|
41463
|
+
clauses.push("timestamp <= ?");
|
|
41464
|
+
params.push(filter2.endTime);
|
|
41465
|
+
}
|
|
41466
|
+
const where = clauses.length > 0 ? `WHERE ${clauses.join(" AND ")}` : "";
|
|
41467
|
+
const limit = Math.max(1, Math.min(filter2.limit ?? 200, 1e3));
|
|
41468
|
+
const rows = this.db.prepare(
|
|
41469
|
+
`SELECT * FROM goal_citations ${where} ORDER BY timestamp DESC, id DESC LIMIT ?`
|
|
41470
|
+
).all(...params, limit);
|
|
41471
|
+
return rows.map((row) => this.rowToGoalCitation(row));
|
|
41472
|
+
}
|
|
41473
|
+
scanAndRecordCitations(text, surface, sourceRef, agentId, taskId, timestamp) {
|
|
41474
|
+
const matches = extractGoalCitations(text);
|
|
41475
|
+
if (matches.length === 0) {
|
|
41476
|
+
return [];
|
|
41477
|
+
}
|
|
41478
|
+
return matches.map((match) => ({
|
|
41479
|
+
goalId: match.goalId,
|
|
41480
|
+
agentId,
|
|
41481
|
+
...taskId ? { taskId } : {},
|
|
41482
|
+
surface,
|
|
41483
|
+
sourceRef,
|
|
41484
|
+
snippet: buildSnippet(text, match.index),
|
|
41485
|
+
...timestamp ? { timestamp } : {}
|
|
41486
|
+
}));
|
|
41487
|
+
}
|
|
41030
41488
|
getTaskSelectClause(slim, tableAlias) {
|
|
41031
41489
|
if (!slim) {
|
|
41032
41490
|
return tableAlias ? `${tableAlias}.*` : "*";
|
|
@@ -41051,6 +41509,7 @@ ${recentText}` : void 0
|
|
|
41051
41509
|
"userPaused",
|
|
41052
41510
|
"baseBranch",
|
|
41053
41511
|
"branch",
|
|
41512
|
+
"autoMerge",
|
|
41054
41513
|
"executionStartBranch",
|
|
41055
41514
|
"baseCommitSha",
|
|
41056
41515
|
"modelPresetId",
|
|
@@ -41063,6 +41522,9 @@ ${recentText}` : void 0
|
|
|
41063
41522
|
"mergeRetries",
|
|
41064
41523
|
"workflowStepRetries",
|
|
41065
41524
|
"stuckKillCount",
|
|
41525
|
+
"resumeLimboCount",
|
|
41526
|
+
"resumeLimboTipSha",
|
|
41527
|
+
"resumeLimboStepSignature",
|
|
41066
41528
|
"postReviewFixCount",
|
|
41067
41529
|
"recoveryRetryCount",
|
|
41068
41530
|
"taskDoneRetryCount",
|
|
@@ -41071,6 +41533,7 @@ ${recentText}` : void 0
|
|
|
41071
41533
|
"verificationFailureCount",
|
|
41072
41534
|
"mergeConflictBounceCount",
|
|
41073
41535
|
"mergeAuditBounceCount",
|
|
41536
|
+
"mergeTransientRetryCount",
|
|
41074
41537
|
"branchConflictRecoveryCount",
|
|
41075
41538
|
"reviewerContextRetryCount",
|
|
41076
41539
|
"reviewerFallbackRetryCount",
|
|
@@ -41195,6 +41658,7 @@ ${outcome}`;
|
|
|
41195
41658
|
"userPaused",
|
|
41196
41659
|
"baseBranch",
|
|
41197
41660
|
"branch",
|
|
41661
|
+
"autoMerge",
|
|
41198
41662
|
"executionStartBranch",
|
|
41199
41663
|
"baseCommitSha",
|
|
41200
41664
|
"modelPresetId",
|
|
@@ -41207,6 +41671,9 @@ ${outcome}`;
|
|
|
41207
41671
|
"mergeRetries",
|
|
41208
41672
|
"workflowStepRetries",
|
|
41209
41673
|
"stuckKillCount",
|
|
41674
|
+
"resumeLimboCount",
|
|
41675
|
+
"resumeLimboTipSha",
|
|
41676
|
+
"resumeLimboStepSignature",
|
|
41210
41677
|
"postReviewFixCount",
|
|
41211
41678
|
"recoveryRetryCount",
|
|
41212
41679
|
"taskDoneRetryCount",
|
|
@@ -41215,6 +41682,7 @@ ${outcome}`;
|
|
|
41215
41682
|
"verificationFailureCount",
|
|
41216
41683
|
"mergeConflictBounceCount",
|
|
41217
41684
|
"mergeAuditBounceCount",
|
|
41685
|
+
"mergeTransientRetryCount",
|
|
41218
41686
|
"branchConflictRecoveryCount",
|
|
41219
41687
|
"reviewerContextRetryCount",
|
|
41220
41688
|
"reviewerFallbackRetryCount",
|
|
@@ -41328,6 +41796,7 @@ ${outcome}`;
|
|
|
41328
41796
|
task.userPaused ? 1 : 0,
|
|
41329
41797
|
task.baseBranch ?? null,
|
|
41330
41798
|
task.branch ?? null,
|
|
41799
|
+
task.autoMerge === void 0 ? null : task.autoMerge ? 1 : 0,
|
|
41331
41800
|
task.executionStartBranch ?? null,
|
|
41332
41801
|
task.baseCommitSha ?? null,
|
|
41333
41802
|
task.modelPresetId ?? null,
|
|
@@ -41340,6 +41809,9 @@ ${outcome}`;
|
|
|
41340
41809
|
task.mergeRetries ?? null,
|
|
41341
41810
|
task.workflowStepRetries ?? null,
|
|
41342
41811
|
task.stuckKillCount ?? 0,
|
|
41812
|
+
task.resumeLimboCount ?? 0,
|
|
41813
|
+
task.resumeLimboTipSha ?? null,
|
|
41814
|
+
task.resumeLimboStepSignature ?? null,
|
|
41343
41815
|
task.postReviewFixCount ?? 0,
|
|
41344
41816
|
task.recoveryRetryCount ?? null,
|
|
41345
41817
|
task.taskDoneRetryCount ?? 0,
|
|
@@ -41348,6 +41820,7 @@ ${outcome}`;
|
|
|
41348
41820
|
task.verificationFailureCount ?? 0,
|
|
41349
41821
|
task.mergeConflictBounceCount ?? 0,
|
|
41350
41822
|
task.mergeAuditBounceCount ?? 0,
|
|
41823
|
+
task.mergeTransientRetryCount ?? 0,
|
|
41351
41824
|
task.branchConflictRecoveryCount ?? 0,
|
|
41352
41825
|
task.reviewerContextRetryCount ?? 0,
|
|
41353
41826
|
task.reviewerFallbackRetryCount ?? 0,
|
|
@@ -41394,6 +41867,7 @@ ${outcome}`;
|
|
|
41394
41867
|
toJsonNullable(task.mergeDetails),
|
|
41395
41868
|
task.breakIntoSubtasks ? 1 : 0,
|
|
41396
41869
|
task.noCommitsExpected ? 1 : 0,
|
|
41870
|
+
task.autoMerge === void 0 ? null : task.autoMerge ? 1 : 0,
|
|
41397
41871
|
toJson(task.enabledWorkflowSteps || []),
|
|
41398
41872
|
toJson(task.modifiedFiles || []),
|
|
41399
41873
|
task.missionId ?? null,
|
|
@@ -41434,16 +41908,16 @@ ${outcome}`;
|
|
|
41434
41908
|
this.db.prepare(`
|
|
41435
41909
|
INSERT INTO tasks (
|
|
41436
41910
|
id, lineageId, title, description, priority, "column", status, size, reviewLevel, currentStep,
|
|
41437
|
-
worktree, blockedBy, overlapBlockedBy, paused, userPaused, baseBranch, branch, executionStartBranch, baseCommitSha, modelPresetId, modelProvider,
|
|
41911
|
+
worktree, blockedBy, overlapBlockedBy, paused, userPaused, baseBranch, branch, autoMerge, executionStartBranch, baseCommitSha, modelPresetId, modelProvider,
|
|
41438
41912
|
modelId, validatorModelProvider, validatorModelId, planningModelProvider, planningModelId, mergeRetries,
|
|
41439
|
-
workflowStepRetries, stuckKillCount, postReviewFixCount, recoveryRetryCount, taskDoneRetryCount, worktreeSessionRetryCount, completionHandoffLimboRecoveryCount, verificationFailureCount, mergeConflictBounceCount, mergeAuditBounceCount, branchConflictRecoveryCount, reviewerContextRetryCount, reviewerFallbackRetryCount, nextRecoveryAt, error,
|
|
41913
|
+
workflowStepRetries, stuckKillCount, resumeLimboCount, resumeLimboTipSha, resumeLimboStepSignature, postReviewFixCount, recoveryRetryCount, taskDoneRetryCount, worktreeSessionRetryCount, completionHandoffLimboRecoveryCount, verificationFailureCount, mergeConflictBounceCount, mergeAuditBounceCount, mergeTransientRetryCount, branchConflictRecoveryCount, reviewerContextRetryCount, reviewerFallbackRetryCount, nextRecoveryAt, error,
|
|
41440
41914
|
summary, thinkingLevel, executionMode, tokenUsageInputTokens, tokenUsageOutputTokens, tokenUsageCachedTokens,
|
|
41441
41915
|
tokenUsageCacheWriteTokens, tokenUsageTotalTokens, tokenUsageFirstUsedAt, tokenUsageLastUsedAt, tokenBudgetSoftAlertedAt, tokenBudgetHardAlertedAt, tokenBudgetOverride, createdAt, updatedAt, columnMovedAt,
|
|
41442
41916
|
firstExecutionAt, cumulativeActiveMs, executionStartedAt, executionCompletedAt,
|
|
41443
41917
|
dependencies, steps, log, attachments, steeringComments,
|
|
41444
41918
|
comments, review, reviewState, workflowStepResults, prInfo, prInfos, issueInfo, githubTracking,
|
|
41445
41919
|
sourceIssueProvider, sourceIssueRepository, sourceIssueExternalIssueId, sourceIssueNumber, sourceIssueUrl,
|
|
41446
|
-
mergeDetails, breakIntoSubtasks, noCommitsExpected, enabledWorkflowSteps, modifiedFiles, missionId, sliceId, scopeOverride, scopeOverrideReason, scopeAutoWiden, assignedAgentId, pausedByAgentId, assigneeUserId, nodeId, effectiveNodeId, effectiveNodeSource, sourceType, sourceAgentId, sourceRunId, sourceSessionId, sourceMessageId, sourceParentTaskId, sourceMetadata, checkedOutBy, checkedOutAt, checkoutNodeId, checkoutRunId, checkoutLeaseRenewedAt, checkoutLeaseEpoch, deletedAt, allowResurrection
|
|
41920
|
+
mergeDetails, breakIntoSubtasks, noCommitsExpected, autoMerge, enabledWorkflowSteps, modifiedFiles, missionId, sliceId, scopeOverride, scopeOverrideReason, scopeAutoWiden, assignedAgentId, pausedByAgentId, assigneeUserId, nodeId, effectiveNodeId, effectiveNodeSource, sourceType, sourceAgentId, sourceRunId, sourceSessionId, sourceMessageId, sourceParentTaskId, sourceMetadata, checkedOutBy, checkedOutAt, checkoutNodeId, checkoutRunId, checkoutLeaseRenewedAt, checkoutLeaseEpoch, deletedAt, allowResurrection
|
|
41447
41921
|
) VALUES (${placeholders})
|
|
41448
41922
|
`).run(...values);
|
|
41449
41923
|
this.db.bumpLastModified();
|
|
@@ -41460,16 +41934,16 @@ ${outcome}`;
|
|
|
41460
41934
|
this.db.prepare(`
|
|
41461
41935
|
INSERT INTO tasks (
|
|
41462
41936
|
id, lineageId, title, description, priority, "column", status, size, reviewLevel, currentStep,
|
|
41463
|
-
worktree, blockedBy, overlapBlockedBy, paused, userPaused, baseBranch, branch, executionStartBranch, baseCommitSha, modelPresetId, modelProvider,
|
|
41937
|
+
worktree, blockedBy, overlapBlockedBy, paused, userPaused, baseBranch, branch, autoMerge, executionStartBranch, baseCommitSha, modelPresetId, modelProvider,
|
|
41464
41938
|
modelId, validatorModelProvider, validatorModelId, planningModelProvider, planningModelId, mergeRetries,
|
|
41465
|
-
workflowStepRetries, stuckKillCount, postReviewFixCount, recoveryRetryCount, taskDoneRetryCount, worktreeSessionRetryCount, completionHandoffLimboRecoveryCount, verificationFailureCount, mergeConflictBounceCount, mergeAuditBounceCount, branchConflictRecoveryCount, reviewerContextRetryCount, reviewerFallbackRetryCount, nextRecoveryAt, error,
|
|
41939
|
+
workflowStepRetries, stuckKillCount, resumeLimboCount, resumeLimboTipSha, resumeLimboStepSignature, postReviewFixCount, recoveryRetryCount, taskDoneRetryCount, worktreeSessionRetryCount, completionHandoffLimboRecoveryCount, verificationFailureCount, mergeConflictBounceCount, mergeAuditBounceCount, mergeTransientRetryCount, branchConflictRecoveryCount, reviewerContextRetryCount, reviewerFallbackRetryCount, nextRecoveryAt, error,
|
|
41466
41940
|
summary, thinkingLevel, executionMode, tokenUsageInputTokens, tokenUsageOutputTokens, tokenUsageCachedTokens,
|
|
41467
41941
|
tokenUsageCacheWriteTokens, tokenUsageTotalTokens, tokenUsageFirstUsedAt, tokenUsageLastUsedAt, tokenBudgetSoftAlertedAt, tokenBudgetHardAlertedAt, tokenBudgetOverride, createdAt, updatedAt, columnMovedAt,
|
|
41468
41942
|
firstExecutionAt, cumulativeActiveMs, executionStartedAt, executionCompletedAt,
|
|
41469
41943
|
dependencies, steps, log, attachments, steeringComments,
|
|
41470
41944
|
comments, review, reviewState, workflowStepResults, prInfo, prInfos, issueInfo, githubTracking,
|
|
41471
41945
|
sourceIssueProvider, sourceIssueRepository, sourceIssueExternalIssueId, sourceIssueNumber, sourceIssueUrl,
|
|
41472
|
-
mergeDetails, breakIntoSubtasks, noCommitsExpected, enabledWorkflowSteps, modifiedFiles, missionId, sliceId, scopeOverride, scopeOverrideReason, scopeAutoWiden, assignedAgentId, pausedByAgentId, assigneeUserId, nodeId, effectiveNodeId, effectiveNodeSource, sourceType, sourceAgentId, sourceRunId, sourceSessionId, sourceMessageId, sourceParentTaskId, sourceMetadata, checkedOutBy, checkedOutAt, checkoutNodeId, checkoutRunId, checkoutLeaseRenewedAt, checkoutLeaseEpoch, deletedAt, allowResurrection
|
|
41946
|
+
mergeDetails, breakIntoSubtasks, noCommitsExpected, autoMerge, enabledWorkflowSteps, modifiedFiles, missionId, sliceId, scopeOverride, scopeOverrideReason, scopeAutoWiden, assignedAgentId, pausedByAgentId, assigneeUserId, nodeId, effectiveNodeId, effectiveNodeSource, sourceType, sourceAgentId, sourceRunId, sourceSessionId, sourceMessageId, sourceParentTaskId, sourceMetadata, checkedOutBy, checkedOutAt, checkoutNodeId, checkoutRunId, checkoutLeaseRenewedAt, checkoutLeaseEpoch, deletedAt, allowResurrection
|
|
41473
41947
|
) VALUES (${placeholders})
|
|
41474
41948
|
ON CONFLICT(id) DO UPDATE SET
|
|
41475
41949
|
lineageId = excluded.lineageId,
|
|
@@ -41488,6 +41962,7 @@ ${outcome}`;
|
|
|
41488
41962
|
userPaused = excluded.userPaused,
|
|
41489
41963
|
baseBranch = excluded.baseBranch,
|
|
41490
41964
|
branch = excluded.branch,
|
|
41965
|
+
autoMerge = excluded.autoMerge,
|
|
41491
41966
|
executionStartBranch = excluded.executionStartBranch,
|
|
41492
41967
|
baseCommitSha = excluded.baseCommitSha,
|
|
41493
41968
|
modelPresetId = excluded.modelPresetId,
|
|
@@ -41500,6 +41975,9 @@ ${outcome}`;
|
|
|
41500
41975
|
mergeRetries = excluded.mergeRetries,
|
|
41501
41976
|
workflowStepRetries = excluded.workflowStepRetries,
|
|
41502
41977
|
stuckKillCount = excluded.stuckKillCount,
|
|
41978
|
+
resumeLimboCount = excluded.resumeLimboCount,
|
|
41979
|
+
resumeLimboTipSha = excluded.resumeLimboTipSha,
|
|
41980
|
+
resumeLimboStepSignature = excluded.resumeLimboStepSignature,
|
|
41503
41981
|
postReviewFixCount = excluded.postReviewFixCount,
|
|
41504
41982
|
recoveryRetryCount = excluded.recoveryRetryCount,
|
|
41505
41983
|
taskDoneRetryCount = excluded.taskDoneRetryCount,
|
|
@@ -41508,6 +41986,7 @@ ${outcome}`;
|
|
|
41508
41986
|
verificationFailureCount = excluded.verificationFailureCount,
|
|
41509
41987
|
mergeConflictBounceCount = excluded.mergeConflictBounceCount,
|
|
41510
41988
|
mergeAuditBounceCount = excluded.mergeAuditBounceCount,
|
|
41989
|
+
mergeTransientRetryCount = excluded.mergeTransientRetryCount,
|
|
41511
41990
|
branchConflictRecoveryCount = excluded.branchConflictRecoveryCount,
|
|
41512
41991
|
reviewerContextRetryCount = excluded.reviewerContextRetryCount,
|
|
41513
41992
|
reviewerFallbackRetryCount = excluded.reviewerFallbackRetryCount,
|
|
@@ -41554,6 +42033,7 @@ ${outcome}`;
|
|
|
41554
42033
|
mergeDetails = excluded.mergeDetails,
|
|
41555
42034
|
breakIntoSubtasks = excluded.breakIntoSubtasks,
|
|
41556
42035
|
noCommitsExpected = excluded.noCommitsExpected,
|
|
42036
|
+
autoMerge = excluded.autoMerge,
|
|
41557
42037
|
enabledWorkflowSteps = excluded.enabledWorkflowSteps,
|
|
41558
42038
|
modifiedFiles = excluded.modifiedFiles,
|
|
41559
42039
|
missionId = excluded.missionId,
|
|
@@ -42829,6 +43309,7 @@ ${outcome}`;
|
|
|
42829
43309
|
sourceParentTaskId: input.source?.sourceParentTaskId,
|
|
42830
43310
|
sourceMetadata: withTaskBranchContextInSourceMetadata(input.source?.sourceMetadata, input.branchContext),
|
|
42831
43311
|
branchContext: input.branchContext,
|
|
43312
|
+
autoMerge: input.autoMerge,
|
|
42832
43313
|
column: input.column || "triage",
|
|
42833
43314
|
dependencies: input.dependencies || [],
|
|
42834
43315
|
breakIntoSubtasks: input.breakIntoSubtasks === true ? true : void 0,
|
|
@@ -43171,6 +43652,99 @@ ${newTask.description}
|
|
|
43171
43652
|
return { ...task, prompt };
|
|
43172
43653
|
});
|
|
43173
43654
|
}
|
|
43655
|
+
createBranchGroup(input) {
|
|
43656
|
+
const now = Date.now();
|
|
43657
|
+
const id = this.generateBranchGroupId();
|
|
43658
|
+
this.db.prepare(`
|
|
43659
|
+
INSERT INTO branch_groups (id, sourceType, sourceId, branchName, worktreePath, autoMerge, prState, prUrl, prNumber, status, createdAt, updatedAt, closedAt)
|
|
43660
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
43661
|
+
`).run(
|
|
43662
|
+
id,
|
|
43663
|
+
input.sourceType,
|
|
43664
|
+
input.sourceId,
|
|
43665
|
+
input.branchName,
|
|
43666
|
+
input.worktreePath ?? null,
|
|
43667
|
+
input.autoMerge ? 1 : 0,
|
|
43668
|
+
input.prState ?? "none",
|
|
43669
|
+
input.prUrl ?? null,
|
|
43670
|
+
input.prNumber ?? null,
|
|
43671
|
+
input.status ?? "open",
|
|
43672
|
+
now,
|
|
43673
|
+
now,
|
|
43674
|
+
input.closedAt ?? null
|
|
43675
|
+
);
|
|
43676
|
+
this.db.bumpLastModified();
|
|
43677
|
+
return this.getBranchGroup(id);
|
|
43678
|
+
}
|
|
43679
|
+
getBranchGroup(id) {
|
|
43680
|
+
const row = this.db.prepare(`SELECT * FROM branch_groups WHERE id = ?`).get(id);
|
|
43681
|
+
return row ? this.rowToBranchGroup(row) : null;
|
|
43682
|
+
}
|
|
43683
|
+
getBranchGroupBySource(sourceType, sourceId) {
|
|
43684
|
+
const row = this.db.prepare(`SELECT * FROM branch_groups WHERE sourceType = ? AND sourceId = ?`).get(sourceType, sourceId);
|
|
43685
|
+
return row ? this.rowToBranchGroup(row) : null;
|
|
43686
|
+
}
|
|
43687
|
+
listBranchGroups(options) {
|
|
43688
|
+
const rows = options?.status ? this.db.prepare(`SELECT * FROM branch_groups WHERE status = ? ORDER BY createdAt ASC`).all(options.status) : this.db.prepare(`SELECT * FROM branch_groups ORDER BY createdAt ASC`).all();
|
|
43689
|
+
return rows.map((row) => this.rowToBranchGroup(row));
|
|
43690
|
+
}
|
|
43691
|
+
updateBranchGroup(id, patch) {
|
|
43692
|
+
const current = this.getBranchGroup(id);
|
|
43693
|
+
if (!current) {
|
|
43694
|
+
throw new Error(`Branch group ${id} not found`);
|
|
43695
|
+
}
|
|
43696
|
+
const nextStatus = patch.status ?? current.status;
|
|
43697
|
+
const now = Date.now();
|
|
43698
|
+
const nextClosedAt = patch.closedAt === null ? null : patch.closedAt ?? (nextStatus !== "open" && current.status === "open" ? now : current.closedAt ?? null);
|
|
43699
|
+
this.db.prepare(`
|
|
43700
|
+
UPDATE branch_groups
|
|
43701
|
+
SET sourceId = ?, branchName = ?, worktreePath = ?, autoMerge = ?, prState = ?, prUrl = ?, prNumber = ?, status = ?, updatedAt = ?, closedAt = ?
|
|
43702
|
+
WHERE id = ?
|
|
43703
|
+
`).run(
|
|
43704
|
+
patch.sourceId ?? current.sourceId,
|
|
43705
|
+
patch.branchName ?? current.branchName,
|
|
43706
|
+
patch.worktreePath === null ? null : patch.worktreePath ?? current.worktreePath ?? null,
|
|
43707
|
+
patch.autoMerge === void 0 ? current.autoMerge ? 1 : 0 : patch.autoMerge ? 1 : 0,
|
|
43708
|
+
patch.prState ?? current.prState,
|
|
43709
|
+
patch.prUrl === null ? null : patch.prUrl ?? current.prUrl ?? null,
|
|
43710
|
+
patch.prNumber === null ? null : patch.prNumber ?? current.prNumber ?? null,
|
|
43711
|
+
nextStatus,
|
|
43712
|
+
now,
|
|
43713
|
+
nextClosedAt,
|
|
43714
|
+
id
|
|
43715
|
+
);
|
|
43716
|
+
this.db.bumpLastModified();
|
|
43717
|
+
return this.getBranchGroup(id);
|
|
43718
|
+
}
|
|
43719
|
+
async setTaskBranchGroup(taskId, branchGroupId) {
|
|
43720
|
+
await this.withTaskLock(taskId, async () => {
|
|
43721
|
+
const dir2 = this.taskDir(taskId);
|
|
43722
|
+
const task = await this.readTaskJson(dir2);
|
|
43723
|
+
let branchContext;
|
|
43724
|
+
if (branchGroupId) {
|
|
43725
|
+
const group = this.getBranchGroup(branchGroupId);
|
|
43726
|
+
if (!group) {
|
|
43727
|
+
throw new Error(`Branch group ${branchGroupId} not found`);
|
|
43728
|
+
}
|
|
43729
|
+
branchContext = {
|
|
43730
|
+
groupId: group.id,
|
|
43731
|
+
source: group.sourceType,
|
|
43732
|
+
assignmentMode: "shared"
|
|
43733
|
+
};
|
|
43734
|
+
}
|
|
43735
|
+
task.branchContext = branchContext;
|
|
43736
|
+
task.sourceMetadata = withTaskBranchContextInSourceMetadata(task.sourceMetadata, branchContext);
|
|
43737
|
+
if (!branchContext && task.sourceMetadata) {
|
|
43738
|
+
const nextSourceMetadata = { ...task.sourceMetadata };
|
|
43739
|
+
delete nextSourceMetadata[TASK_BRANCH_CONTEXT_METADATA_KEY];
|
|
43740
|
+
task.sourceMetadata = Object.keys(nextSourceMetadata).length > 0 ? nextSourceMetadata : void 0;
|
|
43741
|
+
}
|
|
43742
|
+
task.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
43743
|
+
await this.atomicWriteTaskJson(dir2, task);
|
|
43744
|
+
if (this.isWatching) this.taskCache.set(taskId, { ...task });
|
|
43745
|
+
this.emit("task:updated", task);
|
|
43746
|
+
});
|
|
43747
|
+
}
|
|
43174
43748
|
async getTaskColumns(ids) {
|
|
43175
43749
|
if (ids.length === 0) {
|
|
43176
43750
|
return /* @__PURE__ */ new Map();
|
|
@@ -43895,6 +44469,7 @@ ${newTask.description}
|
|
|
43895
44469
|
throw new Error(`Cannot move ${id} to done: ${mergeBlocker}`);
|
|
43896
44470
|
}
|
|
43897
44471
|
}
|
|
44472
|
+
const settingsForInReview = toColumn === "in-review" && task.autoMerge === void 0 ? await this.getSettingsFast() : void 0;
|
|
43898
44473
|
const movedAt = internal.now ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
43899
44474
|
task.column = toColumn;
|
|
43900
44475
|
task.columnMovedAt = movedAt;
|
|
@@ -43954,6 +44529,9 @@ ${newTask.description}
|
|
|
43954
44529
|
}
|
|
43955
44530
|
}
|
|
43956
44531
|
if (toColumn === "in-review") {
|
|
44532
|
+
if (task.autoMerge === void 0 && settingsForInReview) {
|
|
44533
|
+
task.autoMerge = settingsForInReview.autoMerge;
|
|
44534
|
+
}
|
|
43957
44535
|
task.recoveryRetryCount = void 0;
|
|
43958
44536
|
task.nextRecoveryAt = void 0;
|
|
43959
44537
|
if (task.status === "queued") {
|
|
@@ -44337,11 +44915,21 @@ ${newTask.description}
|
|
|
44337
44915
|
} else if (updates.baseBranch !== void 0) {
|
|
44338
44916
|
task.baseBranch = updates.baseBranch;
|
|
44339
44917
|
}
|
|
44918
|
+
if (updates.autoMerge === null) {
|
|
44919
|
+
task.autoMerge = void 0;
|
|
44920
|
+
} else if (updates.autoMerge !== void 0) {
|
|
44921
|
+
task.autoMerge = updates.autoMerge;
|
|
44922
|
+
}
|
|
44340
44923
|
if (updates.branch === null) {
|
|
44341
44924
|
task.branch = void 0;
|
|
44342
44925
|
} else if (updates.branch !== void 0) {
|
|
44343
44926
|
task.branch = updates.branch;
|
|
44344
44927
|
}
|
|
44928
|
+
if (updates.autoMerge === null) {
|
|
44929
|
+
task.autoMerge = void 0;
|
|
44930
|
+
} else if (updates.autoMerge !== void 0) {
|
|
44931
|
+
task.autoMerge = updates.autoMerge;
|
|
44932
|
+
}
|
|
44345
44933
|
if (updates.executionStartBranch === null) {
|
|
44346
44934
|
task.executionStartBranch = void 0;
|
|
44347
44935
|
} else if (updates.executionStartBranch !== void 0) {
|
|
@@ -44361,6 +44949,21 @@ ${newTask.description}
|
|
|
44361
44949
|
} else if (updates.stuckKillCount !== void 0) {
|
|
44362
44950
|
task.stuckKillCount = updates.stuckKillCount;
|
|
44363
44951
|
}
|
|
44952
|
+
if (updates.resumeLimboCount === null) {
|
|
44953
|
+
task.resumeLimboCount = void 0;
|
|
44954
|
+
} else if (updates.resumeLimboCount !== void 0) {
|
|
44955
|
+
task.resumeLimboCount = updates.resumeLimboCount;
|
|
44956
|
+
}
|
|
44957
|
+
if (updates.resumeLimboTipSha === null) {
|
|
44958
|
+
task.resumeLimboTipSha = void 0;
|
|
44959
|
+
} else if (updates.resumeLimboTipSha !== void 0) {
|
|
44960
|
+
task.resumeLimboTipSha = updates.resumeLimboTipSha;
|
|
44961
|
+
}
|
|
44962
|
+
if (updates.resumeLimboStepSignature === null) {
|
|
44963
|
+
task.resumeLimboStepSignature = void 0;
|
|
44964
|
+
} else if (updates.resumeLimboStepSignature !== void 0) {
|
|
44965
|
+
task.resumeLimboStepSignature = updates.resumeLimboStepSignature;
|
|
44966
|
+
}
|
|
44364
44967
|
if (updates.postReviewFixCount === null) {
|
|
44365
44968
|
task.postReviewFixCount = void 0;
|
|
44366
44969
|
} else if (updates.postReviewFixCount !== void 0) {
|
|
@@ -44401,6 +45004,11 @@ ${newTask.description}
|
|
|
44401
45004
|
} else if (updates.mergeAuditBounceCount !== void 0) {
|
|
44402
45005
|
task.mergeAuditBounceCount = updates.mergeAuditBounceCount;
|
|
44403
45006
|
}
|
|
45007
|
+
if (updates.mergeTransientRetryCount === null) {
|
|
45008
|
+
task.mergeTransientRetryCount = void 0;
|
|
45009
|
+
} else if (updates.mergeTransientRetryCount !== void 0) {
|
|
45010
|
+
task.mergeTransientRetryCount = updates.mergeTransientRetryCount;
|
|
45011
|
+
}
|
|
44404
45012
|
if (updates.branchConflictRecoveryCount === null) {
|
|
44405
45013
|
task.branchConflictRecoveryCount = void 0;
|
|
44406
45014
|
} else if (updates.branchConflictRecoveryCount !== void 0) {
|
|
@@ -46452,8 +47060,42 @@ ${newTask.description}
|
|
|
46452
47060
|
INSERT INTO agentLogEntries (taskId, timestamp, text, type, detail, agent)
|
|
46453
47061
|
VALUES (?, ?, ?, ?, ?, ?)
|
|
46454
47062
|
`);
|
|
47063
|
+
const citationInputs = [];
|
|
46455
47064
|
for (const entry of validEntries) {
|
|
46456
|
-
stmt.run(
|
|
47065
|
+
const insertResult = stmt.run(
|
|
47066
|
+
entry.taskId,
|
|
47067
|
+
entry.timestamp,
|
|
47068
|
+
entry.text,
|
|
47069
|
+
entry.type,
|
|
47070
|
+
entry.detail,
|
|
47071
|
+
entry.agent
|
|
47072
|
+
);
|
|
47073
|
+
const insertedId = insertResult.lastInsertRowid;
|
|
47074
|
+
if (insertedId === void 0 || insertedId === null) {
|
|
47075
|
+
continue;
|
|
47076
|
+
}
|
|
47077
|
+
const sourceRef = `agentLog:${String(insertedId)}`;
|
|
47078
|
+
try {
|
|
47079
|
+
citationInputs.push(
|
|
47080
|
+
...this.scanAndRecordCitations(
|
|
47081
|
+
entry.text,
|
|
47082
|
+
"agent_log",
|
|
47083
|
+
sourceRef,
|
|
47084
|
+
entry.agent ?? "unknown",
|
|
47085
|
+
entry.taskId,
|
|
47086
|
+
entry.timestamp
|
|
47087
|
+
)
|
|
47088
|
+
);
|
|
47089
|
+
} catch (err) {
|
|
47090
|
+
console.warn("[fusion] Failed to scan goal citations from agent_log:", err);
|
|
47091
|
+
}
|
|
47092
|
+
}
|
|
47093
|
+
if (citationInputs.length > 0) {
|
|
47094
|
+
try {
|
|
47095
|
+
this.recordGoalCitations(citationInputs);
|
|
47096
|
+
} catch (err) {
|
|
47097
|
+
console.warn("[fusion] Failed to record goal citations from agent_log batch:", err);
|
|
47098
|
+
}
|
|
46457
47099
|
}
|
|
46458
47100
|
this.db.bumpLastModified();
|
|
46459
47101
|
}
|
|
@@ -46491,8 +47133,9 @@ ${newTask.description}
|
|
|
46491
47133
|
VALUES (?, ?, ?, ?, ?, ?)
|
|
46492
47134
|
`);
|
|
46493
47135
|
this.db.transaction(() => {
|
|
47136
|
+
const citationInputs = [];
|
|
46494
47137
|
for (const entry of normalizedEntries) {
|
|
46495
|
-
stmt.run(
|
|
47138
|
+
const insertResult = stmt.run(
|
|
46496
47139
|
entry.taskId,
|
|
46497
47140
|
timestamp,
|
|
46498
47141
|
entry.text,
|
|
@@ -46500,6 +47143,31 @@ ${newTask.description}
|
|
|
46500
47143
|
entry.detail ?? null,
|
|
46501
47144
|
entry.agent ?? null
|
|
46502
47145
|
);
|
|
47146
|
+
const insertedId = insertResult.lastInsertRowid;
|
|
47147
|
+
if (insertedId === void 0 || insertedId === null) {
|
|
47148
|
+
continue;
|
|
47149
|
+
}
|
|
47150
|
+
try {
|
|
47151
|
+
citationInputs.push(
|
|
47152
|
+
...this.scanAndRecordCitations(
|
|
47153
|
+
entry.text,
|
|
47154
|
+
"agent_log",
|
|
47155
|
+
`agentLog:${String(insertedId)}`,
|
|
47156
|
+
entry.agent ?? "unknown",
|
|
47157
|
+
entry.taskId,
|
|
47158
|
+
timestamp
|
|
47159
|
+
)
|
|
47160
|
+
);
|
|
47161
|
+
} catch (err) {
|
|
47162
|
+
console.warn("[fusion] Failed to scan goal citations from agent log batch:", err);
|
|
47163
|
+
}
|
|
47164
|
+
}
|
|
47165
|
+
if (citationInputs.length > 0) {
|
|
47166
|
+
try {
|
|
47167
|
+
this.recordGoalCitations(citationInputs);
|
|
47168
|
+
} catch (err) {
|
|
47169
|
+
console.warn("[fusion] Failed to record goal citations from appendAgentLogBatch:", err);
|
|
47170
|
+
}
|
|
46503
47171
|
}
|
|
46504
47172
|
this.db.bumpLastModified();
|
|
46505
47173
|
});
|
|
@@ -46894,6 +47562,21 @@ ${newTask.description}
|
|
|
46894
47562
|
this.db.bumpLastModified();
|
|
46895
47563
|
const task = await this.getTask(taskId);
|
|
46896
47564
|
this.emit("task:updated", task);
|
|
47565
|
+
try {
|
|
47566
|
+
const citationInputs = this.scanAndRecordCitations(
|
|
47567
|
+
input.content,
|
|
47568
|
+
"task_document",
|
|
47569
|
+
`document:${taskId}:${input.key}:rev${document2.revision}`,
|
|
47570
|
+
input.author ?? "user",
|
|
47571
|
+
taskId,
|
|
47572
|
+
document2.updatedAt
|
|
47573
|
+
);
|
|
47574
|
+
if (citationInputs.length > 0) {
|
|
47575
|
+
this.recordGoalCitations(citationInputs);
|
|
47576
|
+
}
|
|
47577
|
+
} catch (err) {
|
|
47578
|
+
console.warn("[fusion] Failed to scan/record goal citations from task document:", err);
|
|
47579
|
+
}
|
|
46897
47580
|
return document2;
|
|
46898
47581
|
}
|
|
46899
47582
|
/**
|
|
@@ -48744,6 +49427,7 @@ var init_manual_retry_reset = __esm({
|
|
|
48744
49427
|
"use strict";
|
|
48745
49428
|
MANUAL_RETRY_RESET_COUNTER_KEYS = [
|
|
48746
49429
|
"stuckKillCount",
|
|
49430
|
+
"resumeLimboCount",
|
|
48747
49431
|
"recoveryRetryCount",
|
|
48748
49432
|
"taskDoneRetryCount",
|
|
48749
49433
|
"worktreeSessionRetryCount",
|
|
@@ -69678,6 +70362,8 @@ __export(src_exports, {
|
|
|
69678
70362
|
FileMemoryBackend: () => FileMemoryBackend,
|
|
69679
70363
|
FirstRunDetector: () => FirstRunDetector,
|
|
69680
70364
|
GLOBAL_SETTINGS_KEYS: () => GLOBAL_SETTINGS_KEYS,
|
|
70365
|
+
GOAL_CITATION_SNIPPET_MAX: () => GOAL_CITATION_SNIPPET_MAX,
|
|
70366
|
+
GOAL_ID_PATTERN: () => GOAL_ID_PATTERN,
|
|
69681
70367
|
GlobalSettingsStore: () => GlobalSettingsStore,
|
|
69682
70368
|
GoalStore: () => GoalStore,
|
|
69683
70369
|
HIGH_FANOUT_BLOCKER_TODO_THRESHOLD: () => HIGH_FANOUT_BLOCKER_TODO_THRESHOLD,
|
|
@@ -69848,6 +70534,7 @@ __export(src_exports, {
|
|
|
69848
70534
|
buildQmdSearchArgs: () => buildQmdSearchArgs,
|
|
69849
70535
|
buildResearchDocumentKey: () => buildResearchDocumentKey,
|
|
69850
70536
|
buildReviewerMemoryInstructions: () => buildReviewerMemoryInstructions,
|
|
70537
|
+
buildSnippet: () => buildSnippet,
|
|
69851
70538
|
buildTaskLineageTrailer: () => buildTaskLineageTrailer,
|
|
69852
70539
|
buildTriageMemoryInstructions: () => buildTriageMemoryInstructions,
|
|
69853
70540
|
buildUnblockWeightMap: () => buildUnblockWeightMap,
|
|
@@ -69929,6 +70616,7 @@ __export(src_exports, {
|
|
|
69929
70616
|
extractClaudeCliStoredCredential: () => extractClaudeCliStoredCredential,
|
|
69930
70617
|
extractCodexCliStoredCredential: () => extractCodexCliStoredCredential,
|
|
69931
70618
|
extractDreamProcessorResult: () => extractDreamProcessorResult,
|
|
70619
|
+
extractGoalCitations: () => extractGoalCitations,
|
|
69932
70620
|
extractIntentSignature: () => extractIntentSignature,
|
|
69933
70621
|
extractSandboxProvisioningRequest: () => extractSandboxProvisioningRequest,
|
|
69934
70622
|
extractTaskIdTokens: () => extractTaskIdTokens,
|
|
@@ -70122,6 +70810,7 @@ __export(src_exports, {
|
|
|
70122
70810
|
resolveAgentProvisioningPolicy: () => resolveAgentProvisioningPolicy,
|
|
70123
70811
|
resolveDependencyOrder: () => resolveDependencyOrder,
|
|
70124
70812
|
resolveEffectiveAgentPermissionPolicy: () => resolveEffectiveAgentPermissionPolicy,
|
|
70813
|
+
resolveEffectiveAutoMerge: () => resolveEffectiveAutoMerge,
|
|
70125
70814
|
resolveEvalSettings: () => resolveEvalSettings,
|
|
70126
70815
|
resolveExecutionSettingsModel: () => resolveExecutionSettingsModel,
|
|
70127
70816
|
resolveGlobalDir: () => resolveGlobalDir,
|
|
@@ -70322,6 +71011,7 @@ var init_src = __esm({
|
|
|
70322
71011
|
init_mission_store();
|
|
70323
71012
|
init_goal_types();
|
|
70324
71013
|
init_goal_store();
|
|
71014
|
+
init_goal_citation_extractor();
|
|
70325
71015
|
init_central_core();
|
|
70326
71016
|
init_central_db();
|
|
70327
71017
|
init_node_connection();
|
|
@@ -79796,12 +80486,16 @@ var init_agent_instructions = __esm({
|
|
|
79796
80486
|
|
|
79797
80487
|
// ../engine/src/prompt-layers.ts
|
|
79798
80488
|
function buildPromptLayers(input) {
|
|
79799
|
-
const { basePrompt, agentInstructions, memorySection, pluginContributions, performanceFeedback } = input;
|
|
80489
|
+
const { basePrompt, agentInstructions, memorySection, goalContext, pluginContributions, performanceFeedback } = input;
|
|
79800
80490
|
const dynamicParts = [];
|
|
79801
80491
|
const trimmedMemory = memorySection?.trim() ?? "";
|
|
79802
80492
|
if (trimmedMemory) {
|
|
79803
80493
|
dynamicParts.push(trimmedMemory);
|
|
79804
80494
|
}
|
|
80495
|
+
const trimmedGoalContext = goalContext?.trim() ?? "";
|
|
80496
|
+
if (trimmedGoalContext) {
|
|
80497
|
+
dynamicParts.push(trimmedGoalContext);
|
|
80498
|
+
}
|
|
79805
80499
|
const trimmedInstructions = agentInstructions?.trim() ?? "";
|
|
79806
80500
|
if (trimmedInstructions) {
|
|
79807
80501
|
dynamicParts.push(`## Custom Instructions
|
|
@@ -85129,7 +85823,7 @@ function isInsideWorktreesDir(rootDir, worktreePath, settings) {
|
|
|
85129
85823
|
return isInsideConfiguredWorktreesDir(rootDir, settings, worktreePath);
|
|
85130
85824
|
}
|
|
85131
85825
|
function deriveTaskIdFromBranch(branchName) {
|
|
85132
|
-
const match = branchName.match(/^fusion\/(fn-\d+)(?:-\d+)
|
|
85826
|
+
const match = branchName.match(/^fusion\/(fn-\d+)(?:-\d+)?(?:-[a-z0-9._-]+)*$/i);
|
|
85133
85827
|
return match ? match[1].toUpperCase() : branchName.toUpperCase();
|
|
85134
85828
|
}
|
|
85135
85829
|
async function scanIdleWorktrees(rootDir, store, settings) {
|
|
@@ -101337,6 +102031,12 @@ async function classifyOwnedLandedEvidenceForSelfHealing(rootDir, task, mergeTar
|
|
|
101337
102031
|
const { classifyOwnedLandedEvidence: classifyOwnedLandedEvidence2 } = await Promise.resolve().then(() => (init_merger(), merger_exports));
|
|
101338
102032
|
return classifyOwnedLandedEvidence2(rootDir, task, { mergeTargetBranch });
|
|
101339
102033
|
}
|
|
102034
|
+
function buildResumeLimboStepSignature(task) {
|
|
102035
|
+
return JSON.stringify({
|
|
102036
|
+
currentStep: task.currentStep ?? null,
|
|
102037
|
+
steps: Array.isArray(task.steps) ? task.steps.map((step) => step.status) : []
|
|
102038
|
+
});
|
|
102039
|
+
}
|
|
101340
102040
|
function formatRecoveryTimestamp(date = /* @__PURE__ */ new Date()) {
|
|
101341
102041
|
const pad = (value) => String(value).padStart(2, "0");
|
|
101342
102042
|
return `${date.getUTCFullYear()}${pad(date.getUTCMonth() + 1)}${pad(date.getUTCDate())}-${pad(date.getUTCHours())}${pad(date.getUTCMinutes())}${pad(date.getUTCSeconds())}`;
|
|
@@ -101551,7 +102251,7 @@ function isNoTaskDoneFailure2(task) {
|
|
|
101551
102251
|
function hasStepProgress2(task) {
|
|
101552
102252
|
return task.steps.some((step) => step.status !== "pending");
|
|
101553
102253
|
}
|
|
101554
|
-
var log20, worktreeMetadataReconcileLog, execAsync27, yieldEventLoop2, DONE_TASK_INTEGRITY_SWEEP_LIMIT, BOARD_STALL_NOTIFICATION_COOLDOWN_MS, DB_CORRUPTION_NOTIFICATION_COOLDOWN_MS, STALE_ACTIVE_BRANCH_EXECUTION_GRACE_MS, COMPLETION_HANDOFF_LIMBO_GRACE_MS, MAX_COMPLETION_HANDOFF_LIMBO_RECOVERIES, APPROVED_TRIAGE_RECOVERY_GRACE_MS, STARVED_REFINEMENT_RECOVERY_GRACE_MS, STARVED_PEER_PROGRESS_THRESHOLD, STARVED_REFINEMENT_ESCALATION_COOLDOWN_MS, ORPHANED_EXECUTION_RECOVERY_GRACE_MS, ACTIVE_MERGE_STATUSES2, NON_TERMINAL_STEP_STATUSES2, STRANDED_COMPLETED_TODO_ACTIVE_STATUSES, GHOST_REVIEW_PRESERVED_STATUSES, ORPHANED_WITH_WORKTREE_GRACE_MS, MAX_TASK_DONE_RETRIES, MAX_WORKTREE_SESSION_RETRIES, MAX_AUTO_MERGE_RETRIES, MAX_TRANSIENT_MERGE_RECOVERIES, MAX_STARVATION_DROPS, DEADLOCK_RECOVERY_COOLDOWN_MS, DEFAULT_STALE_MERGING_STATUS_MIN_AGE_MS, DEFAULT_STALE_MERGING_FANOUT_MIN_AGE_MS, DEFAULT_UNBACKED_MERGING_FANOUT_GRACE_MS, DURABLE_ERROR_RECOVERY_MAX_RETRIES, DURABLE_ERROR_RECOVERY_BASE_COOLDOWN_MS, DURABLE_ERROR_RECOVERY_MAX_COOLDOWN_MS, RUNNING_ON_INACTIVE_TASK_STALE_RUN_MS, SelfHealingManager;
|
|
102254
|
+
var log20, worktreeMetadataReconcileLog, execAsync27, yieldEventLoop2, DONE_TASK_INTEGRITY_SWEEP_LIMIT, BOARD_STALL_NOTIFICATION_COOLDOWN_MS, DB_CORRUPTION_NOTIFICATION_COOLDOWN_MS, STALE_ACTIVE_BRANCH_EXECUTION_GRACE_MS, COMPLETION_HANDOFF_LIMBO_GRACE_MS, MAX_COMPLETION_HANDOFF_LIMBO_RECOVERIES, MAX_NO_PROGRESS_RESUME_ATTEMPTS, APPROVED_TRIAGE_RECOVERY_GRACE_MS, STARVED_REFINEMENT_RECOVERY_GRACE_MS, STARVED_PEER_PROGRESS_THRESHOLD, STARVED_REFINEMENT_ESCALATION_COOLDOWN_MS, ORPHANED_EXECUTION_RECOVERY_GRACE_MS, ACTIVE_MERGE_STATUSES2, NON_TERMINAL_STEP_STATUSES2, STRANDED_COMPLETED_TODO_ACTIVE_STATUSES, GHOST_REVIEW_PRESERVED_STATUSES, ORPHANED_WITH_WORKTREE_GRACE_MS, MAX_TASK_DONE_RETRIES, MAX_WORKTREE_SESSION_RETRIES, MAX_AUTO_MERGE_RETRIES, MAX_TRANSIENT_MERGE_RECOVERIES, MAX_STARVATION_DROPS, DEADLOCK_RECOVERY_COOLDOWN_MS, DEFAULT_STALE_MERGING_STATUS_MIN_AGE_MS, DEFAULT_STALE_MERGING_FANOUT_MIN_AGE_MS, DEFAULT_UNBACKED_MERGING_FANOUT_GRACE_MS, DURABLE_ERROR_RECOVERY_MAX_RETRIES, DURABLE_ERROR_RECOVERY_BASE_COOLDOWN_MS, DURABLE_ERROR_RECOVERY_MAX_COOLDOWN_MS, RUNNING_ON_INACTIVE_TASK_STALE_RUN_MS, SelfHealingManager;
|
|
101555
102255
|
var init_self_healing = __esm({
|
|
101556
102256
|
"../engine/src/self-healing.ts"() {
|
|
101557
102257
|
"use strict";
|
|
@@ -101584,6 +102284,7 @@ var init_self_healing = __esm({
|
|
|
101584
102284
|
STALE_ACTIVE_BRANCH_EXECUTION_GRACE_MS = 10 * 6e4;
|
|
101585
102285
|
COMPLETION_HANDOFF_LIMBO_GRACE_MS = 5 * 6e4;
|
|
101586
102286
|
MAX_COMPLETION_HANDOFF_LIMBO_RECOVERIES = 3;
|
|
102287
|
+
MAX_NO_PROGRESS_RESUME_ATTEMPTS = 2;
|
|
101587
102288
|
APPROVED_TRIAGE_RECOVERY_GRACE_MS = 6e4;
|
|
101588
102289
|
STARVED_REFINEMENT_RECOVERY_GRACE_MS = 10 * 6e4;
|
|
101589
102290
|
STARVED_PEER_PROGRESS_THRESHOLD = 3;
|
|
@@ -103100,13 +103801,71 @@ var init_self_healing = __esm({
|
|
|
103100
103801
|
}
|
|
103101
103802
|
}
|
|
103102
103803
|
const preservedCommitCount = inspection.kind === "fully-subsumed" ? 0 : inspection.taskAttributedCommitCount;
|
|
103804
|
+
const stepSignature = buildResumeLimboStepSignature(task);
|
|
103805
|
+
const hasActiveSessionSignal = Boolean(task.checkedOutBy) || activeTaskIds.has(task.id.toUpperCase());
|
|
103806
|
+
const hasPriorSnapshot = typeof task.resumeLimboTipSha === "string" && typeof task.resumeLimboStepSignature === "string";
|
|
103807
|
+
const unchangedSincePriorResume = hasPriorSnapshot && task.resumeLimboTipSha === inspection.tipSha && task.resumeLimboStepSignature === stepSignature;
|
|
103808
|
+
const isNoProgressResume = task.column === "in-progress" && unchangedSincePriorResume && !hasActiveSessionSignal;
|
|
103809
|
+
const resumeAttemptCount = isNoProgressResume ? (task.resumeLimboCount ?? 0) + 1 : 0;
|
|
103810
|
+
if (task.column === "in-progress" && isNoProgressResume && resumeAttemptCount >= MAX_NO_PROGRESS_RESUME_ATTEMPTS) {
|
|
103811
|
+
const idleAnchor = task.executionStartedAt ?? task.columnMovedAt ?? task.updatedAt;
|
|
103812
|
+
const idleAnchorMs = Date.parse(idleAnchor ?? "");
|
|
103813
|
+
const idleMs = Number.isFinite(idleAnchorMs) ? Math.max(0, Date.now() - idleAnchorMs) : null;
|
|
103814
|
+
await this.store.moveTask(task.id, "todo", {
|
|
103815
|
+
moveSource: "engine",
|
|
103816
|
+
preserveWorktree: true,
|
|
103817
|
+
preserveProgress: true,
|
|
103818
|
+
preserveResumeState: true
|
|
103819
|
+
});
|
|
103820
|
+
await this.store.updateTask(task.id, {
|
|
103821
|
+
resumeLimboCount: 0,
|
|
103822
|
+
resumeLimboTipSha: inspection.tipSha,
|
|
103823
|
+
resumeLimboStepSignature: stepSignature
|
|
103824
|
+
});
|
|
103825
|
+
await this.store.logEntry(
|
|
103826
|
+
task.id,
|
|
103827
|
+
`[recovery] resume-limbo-escalated ${task.id} moved to todo after ${resumeAttemptCount} no-progress reclaim/resume attempts`,
|
|
103828
|
+
JSON.stringify({
|
|
103829
|
+
frozenTipSha: inspection.tipSha,
|
|
103830
|
+
idleMs,
|
|
103831
|
+
resumeAttemptCount,
|
|
103832
|
+
currentStep: task.currentStep ?? null
|
|
103833
|
+
})
|
|
103834
|
+
);
|
|
103835
|
+
try {
|
|
103836
|
+
await createRunAuditor(this.store, {
|
|
103837
|
+
runId: generateSyntheticRunId("self-heal", task.id),
|
|
103838
|
+
agentId: "self-healing",
|
|
103839
|
+
taskId: task.id,
|
|
103840
|
+
taskLineageId: task.lineageId,
|
|
103841
|
+
phase: "reclaim-self-owned-branch-conflicts"
|
|
103842
|
+
}).database({
|
|
103843
|
+
type: "task:resume-limbo-escalated",
|
|
103844
|
+
target: task.id,
|
|
103845
|
+
metadata: {
|
|
103846
|
+
taskId: task.id,
|
|
103847
|
+
frozenTipSha: inspection.tipSha,
|
|
103848
|
+
idleMs,
|
|
103849
|
+
resumeAttemptCount,
|
|
103850
|
+
currentStep: task.currentStep ?? null
|
|
103851
|
+
}
|
|
103852
|
+
});
|
|
103853
|
+
} catch (auditErr) {
|
|
103854
|
+
log20.warn(`Failed to write task:resume-limbo-escalated run-audit event for ${task.id}: ${auditErr instanceof Error ? auditErr.message : String(auditErr)}`);
|
|
103855
|
+
}
|
|
103856
|
+
recovered++;
|
|
103857
|
+
continue;
|
|
103858
|
+
}
|
|
103103
103859
|
await this.store.updateTask(task.id, {
|
|
103104
103860
|
worktree: inspection.livePath,
|
|
103105
103861
|
branch: task.branch,
|
|
103106
103862
|
paused: false,
|
|
103107
103863
|
pausedReason: void 0,
|
|
103108
103864
|
status: null,
|
|
103109
|
-
error: null
|
|
103865
|
+
error: null,
|
|
103866
|
+
resumeLimboCount: resumeAttemptCount,
|
|
103867
|
+
resumeLimboTipSha: inspection.tipSha,
|
|
103868
|
+
resumeLimboStepSignature: stepSignature
|
|
103110
103869
|
});
|
|
103111
103870
|
await this.store.logEntry(
|
|
103112
103871
|
task.id,
|
|
@@ -104338,7 +105097,7 @@ var init_self_healing = __esm({
|
|
|
104338
105097
|
const blockerId = task.blockedBy;
|
|
104339
105098
|
const unresolvedDeps = task.dependencies.filter((depId) => {
|
|
104340
105099
|
const dep = taskById.get(depId);
|
|
104341
|
-
return dep && dep.column !== "done" && dep.column !== "in-review" && dep.column !== "archived";
|
|
105100
|
+
return dep && !dep.deletedAt && dep.column !== "done" && dep.column !== "in-review" && dep.column !== "archived";
|
|
104342
105101
|
});
|
|
104343
105102
|
const overlapBlocker = task.overlapBlockedBy ? taskById.get(task.overlapBlockedBy) : void 0;
|
|
104344
105103
|
const hasActiveOverlapBlocker = Boolean(
|
|
@@ -104364,6 +105123,9 @@ var init_self_healing = __esm({
|
|
|
104364
105123
|
reasonCode = "missing-blocker";
|
|
104365
105124
|
reason = `blocker ${blockerId} missing`;
|
|
104366
105125
|
}
|
|
105126
|
+
} else if (blocker.deletedAt) {
|
|
105127
|
+
reasonCode = "soft-deleted-blocker";
|
|
105128
|
+
reason = `blocker ${blockerId} soft-deleted at ${blocker.deletedAt}`;
|
|
104367
105129
|
} else if (blocker.column === "done") {
|
|
104368
105130
|
reasonCode = "blocker-done";
|
|
104369
105131
|
reason = `blocker ${blockerId} is done`;
|
|
@@ -105893,6 +106655,12 @@ var init_self_healing = __esm({
|
|
|
105893
106655
|
try {
|
|
105894
106656
|
const hardBlocker = getTaskHardMergeBlocker({
|
|
105895
106657
|
...task,
|
|
106658
|
+
// Merge-confirmed tasks have already landed. Treat stale merge
|
|
106659
|
+
// in-flight statuses as soft state to clear during finalization,
|
|
106660
|
+
// not hard blockers that park an otherwise confirmed merge as failed.
|
|
106661
|
+
paused: false,
|
|
106662
|
+
status: task.status === "merging" || task.status === "merging-pr" ? void 0 : task.status,
|
|
106663
|
+
error: void 0,
|
|
105896
106664
|
steps: task.steps ?? [],
|
|
105897
106665
|
workflowStepResults: task.workflowStepResults
|
|
105898
106666
|
});
|
|
@@ -110524,6 +111292,258 @@ var init_token_cap_detector = __esm({
|
|
|
110524
111292
|
}
|
|
110525
111293
|
});
|
|
110526
111294
|
|
|
111295
|
+
// ../engine/src/goal-context-injector.ts
|
|
111296
|
+
function normalizeTitle(title) {
|
|
111297
|
+
return title.replace(/\s*\n+\s*/g, " ").trim();
|
|
111298
|
+
}
|
|
111299
|
+
function renderGoalContext(goals) {
|
|
111300
|
+
const lines = goals.map((goal) => `- ${goal.id}: ${normalizeTitle(goal.title)}`);
|
|
111301
|
+
return `## Active Goals
|
|
111302
|
+
|
|
111303
|
+
${lines.join("\n")}`;
|
|
111304
|
+
}
|
|
111305
|
+
function buildGoalContextSection(input) {
|
|
111306
|
+
const { activeGoals, onTruncated } = input;
|
|
111307
|
+
if (activeGoals.length === 0) {
|
|
111308
|
+
return { text: "", emittedGoalIds: [], truncated: null };
|
|
111309
|
+
}
|
|
111310
|
+
const sortedGoals = [...activeGoals].sort((a, b2) => {
|
|
111311
|
+
const byCreated = a.createdAt.localeCompare(b2.createdAt);
|
|
111312
|
+
if (byCreated !== 0) {
|
|
111313
|
+
return byCreated;
|
|
111314
|
+
}
|
|
111315
|
+
return a.id.localeCompare(b2.id);
|
|
111316
|
+
});
|
|
111317
|
+
const resolvedMaxGoals = Math.min(input.maxGoals ?? MAX_INJECTED_GOALS, MAX_INJECTED_GOALS);
|
|
111318
|
+
const charBudget = input.charBudget ?? DEFAULT_GOAL_INJECTION_CHAR_BUDGET;
|
|
111319
|
+
const droppedGoalIds = [];
|
|
111320
|
+
let selectedGoals = sortedGoals.slice(0, resolvedMaxGoals);
|
|
111321
|
+
if (sortedGoals.length > resolvedMaxGoals) {
|
|
111322
|
+
droppedGoalIds.push(...sortedGoals.slice(resolvedMaxGoals).map((goal) => goal.id));
|
|
111323
|
+
}
|
|
111324
|
+
let text = renderGoalContext(selectedGoals);
|
|
111325
|
+
let usedBudgetDrop = false;
|
|
111326
|
+
while (selectedGoals.length > 1 && text.length > charBudget) {
|
|
111327
|
+
const dropped = selectedGoals[selectedGoals.length - 1];
|
|
111328
|
+
selectedGoals = selectedGoals.slice(0, -1);
|
|
111329
|
+
droppedGoalIds.push(dropped.id);
|
|
111330
|
+
text = renderGoalContext(selectedGoals);
|
|
111331
|
+
usedBudgetDrop = true;
|
|
111332
|
+
}
|
|
111333
|
+
let truncated = null;
|
|
111334
|
+
if (droppedGoalIds.length > 0) {
|
|
111335
|
+
truncated = {
|
|
111336
|
+
reason: usedBudgetDrop ? "budget" : "cap",
|
|
111337
|
+
requested: activeGoals.length,
|
|
111338
|
+
emitted: selectedGoals.length,
|
|
111339
|
+
droppedGoalIds,
|
|
111340
|
+
charBudget,
|
|
111341
|
+
producedChars: text.length
|
|
111342
|
+
};
|
|
111343
|
+
onTruncated?.(truncated);
|
|
111344
|
+
}
|
|
111345
|
+
return {
|
|
111346
|
+
text,
|
|
111347
|
+
emittedGoalIds: selectedGoals.map((goal) => goal.id),
|
|
111348
|
+
truncated
|
|
111349
|
+
};
|
|
111350
|
+
}
|
|
111351
|
+
var MAX_INJECTED_GOALS, resolvedActiveGoalLimit, DEFAULT_GOAL_INJECTION_CHAR_BUDGET;
|
|
111352
|
+
var init_goal_context_injector = __esm({
|
|
111353
|
+
"../engine/src/goal-context-injector.ts"() {
|
|
111354
|
+
"use strict";
|
|
111355
|
+
init_src();
|
|
111356
|
+
MAX_INJECTED_GOALS = 5;
|
|
111357
|
+
resolvedActiveGoalLimit = "ACTIVE_GOAL_LIMIT" in src_exports && typeof ACTIVE_GOAL_LIMIT === "number" ? ACTIVE_GOAL_LIMIT : MAX_INJECTED_GOALS;
|
|
111358
|
+
if (MAX_INJECTED_GOALS > resolvedActiveGoalLimit) {
|
|
111359
|
+
throw new Error(
|
|
111360
|
+
`MAX_INJECTED_GOALS (${MAX_INJECTED_GOALS}) cannot exceed ACTIVE_GOAL_LIMIT (${resolvedActiveGoalLimit})`
|
|
111361
|
+
);
|
|
111362
|
+
}
|
|
111363
|
+
DEFAULT_GOAL_INJECTION_CHAR_BUDGET = 600;
|
|
111364
|
+
}
|
|
111365
|
+
});
|
|
111366
|
+
|
|
111367
|
+
// ../engine/src/goal-injection-diagnostics.ts
|
|
111368
|
+
function classifyGoalInjectionResult(result) {
|
|
111369
|
+
if (result.emittedGoalIds.length === 0) {
|
|
111370
|
+
return {
|
|
111371
|
+
outcome: "no-goals",
|
|
111372
|
+
goalCount: 0,
|
|
111373
|
+
goalIds: [],
|
|
111374
|
+
truncated: false
|
|
111375
|
+
};
|
|
111376
|
+
}
|
|
111377
|
+
return {
|
|
111378
|
+
outcome: "applied",
|
|
111379
|
+
goalCount: result.emittedGoalIds.length,
|
|
111380
|
+
goalIds: result.emittedGoalIds,
|
|
111381
|
+
truncated: result.truncated !== null
|
|
111382
|
+
};
|
|
111383
|
+
}
|
|
111384
|
+
function classifyGoalInjectionFailure(reason, error) {
|
|
111385
|
+
const resolvedErrorClass = error && typeof error === "object" && "constructor" in error && typeof error.constructor?.name === "string" ? error.constructor.name : void 0;
|
|
111386
|
+
return {
|
|
111387
|
+
outcome: "disabled-or-failed",
|
|
111388
|
+
goalCount: 0,
|
|
111389
|
+
goalIds: [],
|
|
111390
|
+
truncated: false,
|
|
111391
|
+
reason,
|
|
111392
|
+
...resolvedErrorClass ? { errorClass: resolvedErrorClass } : {}
|
|
111393
|
+
};
|
|
111394
|
+
}
|
|
111395
|
+
function resolveGoalContextForDiagnostics(input) {
|
|
111396
|
+
if (!input.listActiveGoals) {
|
|
111397
|
+
return {
|
|
111398
|
+
goalContext: "",
|
|
111399
|
+
classification: classifyGoalInjectionFailure(input.disabledReason ?? "store-unavailable")
|
|
111400
|
+
};
|
|
111401
|
+
}
|
|
111402
|
+
try {
|
|
111403
|
+
const activeGoals = input.listActiveGoals();
|
|
111404
|
+
const injector = input.injector ?? ((goals) => buildGoalContextSection({ activeGoals: goals }));
|
|
111405
|
+
try {
|
|
111406
|
+
const injectionResult = injector(activeGoals);
|
|
111407
|
+
return {
|
|
111408
|
+
goalContext: injectionResult.text,
|
|
111409
|
+
classification: classifyGoalInjectionResult(injectionResult)
|
|
111410
|
+
};
|
|
111411
|
+
} catch (injectorError) {
|
|
111412
|
+
return {
|
|
111413
|
+
goalContext: "",
|
|
111414
|
+
classification: classifyGoalInjectionFailure("injector-threw", injectorError)
|
|
111415
|
+
};
|
|
111416
|
+
}
|
|
111417
|
+
} catch (listError) {
|
|
111418
|
+
return {
|
|
111419
|
+
goalContext: "",
|
|
111420
|
+
classification: classifyGoalInjectionFailure("list-failed", listError)
|
|
111421
|
+
};
|
|
111422
|
+
}
|
|
111423
|
+
}
|
|
111424
|
+
function formatAgentLogLine(input) {
|
|
111425
|
+
const ids = JSON.stringify(input.goalIds);
|
|
111426
|
+
const reason = input.reason ? ` reason=${input.reason}` : "";
|
|
111427
|
+
const errorClass = input.errorClass ? ` err=${input.errorClass}` : "";
|
|
111428
|
+
return `[goal-injection] ${input.outcome} count=${input.goalCount} ids=${ids} truncated=${String(input.truncated)}${reason}${errorClass}`;
|
|
111429
|
+
}
|
|
111430
|
+
async function emitGoalInjectionDiagnostic(input) {
|
|
111431
|
+
const record = {
|
|
111432
|
+
lane: input.lane,
|
|
111433
|
+
outcome: input.outcome,
|
|
111434
|
+
goalCount: input.goalCount,
|
|
111435
|
+
goalIds: [...input.goalIds],
|
|
111436
|
+
truncated: input.truncated,
|
|
111437
|
+
...input.reason ? { reason: input.reason } : {},
|
|
111438
|
+
...input.errorClass ? { errorClass: input.errorClass } : {},
|
|
111439
|
+
...input.runId ? { runId: input.runId } : {},
|
|
111440
|
+
...input.agentId ? { agentId: input.agentId } : {},
|
|
111441
|
+
...input.taskId ? { taskId: input.taskId } : {},
|
|
111442
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
111443
|
+
};
|
|
111444
|
+
if (input.store && record.taskId) {
|
|
111445
|
+
try {
|
|
111446
|
+
await input.store.logEntry(record.taskId, formatAgentLogLine(record), void 0, input.runContext ?? void 0);
|
|
111447
|
+
} catch (error) {
|
|
111448
|
+
diagnosticsLog.warn(
|
|
111449
|
+
`failed to append goal-injection task log for ${record.taskId}: ${error instanceof Error ? error.message : String(error)}`
|
|
111450
|
+
);
|
|
111451
|
+
}
|
|
111452
|
+
}
|
|
111453
|
+
const auditStore = input.store;
|
|
111454
|
+
const hasAuditWriter = Boolean(auditStore && typeof auditStore.recordRunAuditEvent === "function");
|
|
111455
|
+
if (!input.runContext || !hasAuditWriter || !auditStore) {
|
|
111456
|
+
diagnosticsLog.warn(
|
|
111457
|
+
`goal-injection diagnostic emitted without run-audit side effect (lane=${record.lane}, hasContext=${Boolean(input.runContext)}, hasWriter=${Boolean(hasAuditWriter)})`
|
|
111458
|
+
);
|
|
111459
|
+
return record;
|
|
111460
|
+
}
|
|
111461
|
+
try {
|
|
111462
|
+
await auditStore.recordRunAuditEvent({
|
|
111463
|
+
taskId: input.runContext.taskId,
|
|
111464
|
+
agentId: input.runContext.agentId,
|
|
111465
|
+
runId: input.runContext.runId,
|
|
111466
|
+
domain: "database",
|
|
111467
|
+
mutationType: "prompt:goal-injection",
|
|
111468
|
+
target: record.lane,
|
|
111469
|
+
metadata: {
|
|
111470
|
+
lane: record.lane,
|
|
111471
|
+
outcome: record.outcome,
|
|
111472
|
+
goalCount: record.goalCount,
|
|
111473
|
+
goalIds: record.goalIds,
|
|
111474
|
+
truncated: record.truncated,
|
|
111475
|
+
...record.reason ? { reason: record.reason } : {},
|
|
111476
|
+
...record.errorClass ? { errorClass: record.errorClass } : {},
|
|
111477
|
+
...record.runId ? { runId: record.runId } : {},
|
|
111478
|
+
...record.agentId ? { agentId: record.agentId } : {},
|
|
111479
|
+
...record.taskId ? { taskId: record.taskId } : {}
|
|
111480
|
+
}
|
|
111481
|
+
});
|
|
111482
|
+
} catch (error) {
|
|
111483
|
+
diagnosticsLog.warn(
|
|
111484
|
+
`failed to append goal-injection run-audit event for lane=${record.lane}: ${error instanceof Error ? error.message : String(error)}`
|
|
111485
|
+
);
|
|
111486
|
+
}
|
|
111487
|
+
return record;
|
|
111488
|
+
}
|
|
111489
|
+
var diagnosticsLog;
|
|
111490
|
+
var init_goal_injection_diagnostics = __esm({
|
|
111491
|
+
"../engine/src/goal-injection-diagnostics.ts"() {
|
|
111492
|
+
"use strict";
|
|
111493
|
+
init_goal_context_injector();
|
|
111494
|
+
init_logger2();
|
|
111495
|
+
diagnosticsLog = createLogger2("goal-injection-diagnostics");
|
|
111496
|
+
}
|
|
111497
|
+
});
|
|
111498
|
+
|
|
111499
|
+
// ../engine/src/goal-anchoring-audit.ts
|
|
111500
|
+
async function emitGoalAnchoringAudit(auditor, input) {
|
|
111501
|
+
const isApplied = input.goalsInjected > 0;
|
|
111502
|
+
await auditor.database({
|
|
111503
|
+
type: isApplied ? GOAL_INJECTION_APPLIED : GOAL_INJECTION_SKIPPED,
|
|
111504
|
+
target: input.taskId ?? "goals",
|
|
111505
|
+
metadata: {
|
|
111506
|
+
lane: input.lane,
|
|
111507
|
+
count: input.goalsInjected,
|
|
111508
|
+
...typeof input.truncated === "boolean" ? { truncated: input.truncated } : {},
|
|
111509
|
+
...input.reason ? { reason: input.reason } : {}
|
|
111510
|
+
}
|
|
111511
|
+
});
|
|
111512
|
+
}
|
|
111513
|
+
function emitGoalRetrievalAudit(store, ctx, input) {
|
|
111514
|
+
if (!ctx.runId || !ctx.agentId) return;
|
|
111515
|
+
try {
|
|
111516
|
+
store.recordRunAuditEvent({
|
|
111517
|
+
runId: ctx.runId,
|
|
111518
|
+
agentId: ctx.agentId,
|
|
111519
|
+
taskId: ctx.taskId,
|
|
111520
|
+
domain: "database",
|
|
111521
|
+
mutationType: GOAL_RETRIEVAL_INVOKED,
|
|
111522
|
+
target: input.goalId ?? "goals",
|
|
111523
|
+
metadata: {
|
|
111524
|
+
toolName: input.toolName,
|
|
111525
|
+
count: input.resultCount,
|
|
111526
|
+
notFound: input.notFound ?? false
|
|
111527
|
+
}
|
|
111528
|
+
});
|
|
111529
|
+
} catch (error) {
|
|
111530
|
+
console.warn("[fusion-extension] goal retrieval audit emission skipped", error);
|
|
111531
|
+
}
|
|
111532
|
+
}
|
|
111533
|
+
var GOAL_INJECTION_APPLIED, GOAL_INJECTION_SKIPPED, GOAL_RETRIEVAL_INVOKED, GOAL_AUDIT_TYPES;
|
|
111534
|
+
var init_goal_anchoring_audit = __esm({
|
|
111535
|
+
"../engine/src/goal-anchoring-audit.ts"() {
|
|
111536
|
+
"use strict";
|
|
111537
|
+
GOAL_INJECTION_APPLIED = "goal:injection-applied";
|
|
111538
|
+
GOAL_INJECTION_SKIPPED = "goal:injection-skipped";
|
|
111539
|
+
GOAL_RETRIEVAL_INVOKED = "goal:retrieval-invoked";
|
|
111540
|
+
GOAL_AUDIT_TYPES = [GOAL_INJECTION_APPLIED, GOAL_INJECTION_SKIPPED, GOAL_RETRIEVAL_INVOKED];
|
|
111541
|
+
if (new Set(GOAL_AUDIT_TYPES).size !== GOAL_AUDIT_TYPES.length || GOAL_AUDIT_TYPES.some((value) => typeof value !== "string" || !value.startsWith("goal:"))) {
|
|
111542
|
+
throw new Error("Goal anchoring audit mutation types must be unique goal:* strings.");
|
|
111543
|
+
}
|
|
111544
|
+
}
|
|
111545
|
+
});
|
|
111546
|
+
|
|
110527
111547
|
// ../engine/src/auto-recovery-handlers/branch-worktree.ts
|
|
110528
111548
|
import { exec as exec31 } from "node:child_process";
|
|
110529
111549
|
import { existsSync as existsSync39 } from "node:fs";
|
|
@@ -111388,7 +112408,7 @@ function isTransientMissingTaskJsonError(error, task) {
|
|
|
111388
112408
|
const normalizedTaskJsonPath = resolvePath(filePath);
|
|
111389
112409
|
return normalizedTaskJsonPath.startsWith(`${normalizedWorktree}/`);
|
|
111390
112410
|
}
|
|
111391
|
-
function detectPendingReviewBlock(task,
|
|
112411
|
+
function detectPendingReviewBlock(task, _codeReviewVerdicts) {
|
|
111392
112412
|
const inProgressStepIndices = [];
|
|
111393
112413
|
for (let stepIndex = 0; stepIndex < task.steps.length; stepIndex++) {
|
|
111394
112414
|
if (task.steps[stepIndex]?.status === "in-progress") {
|
|
@@ -111400,9 +112420,6 @@ function detectPendingReviewBlock(task, codeReviewVerdicts) {
|
|
|
111400
112420
|
}
|
|
111401
112421
|
const recentActions = (task.log ?? []).slice(-30).map((entry) => entry.action?.trim()).filter((action) => Boolean(action));
|
|
111402
112422
|
for (const stepIndex of inProgressStepIndices) {
|
|
111403
|
-
if (codeReviewVerdicts.get(stepIndex) === "REVISE") {
|
|
111404
|
-
return { blocked: true, reason: "code-review-revise-outstanding", stepIndex };
|
|
111405
|
-
}
|
|
111406
112423
|
const stepDisplay = stepIndex + 1;
|
|
111407
112424
|
const codeRequest = `code review requested for Step ${stepDisplay}`;
|
|
111408
112425
|
const planRequest = `plan review requested for Step ${stepDisplay}`;
|
|
@@ -111963,6 +112980,8 @@ var init_executor = __esm({
|
|
|
111963
112980
|
init_worktree_hooks();
|
|
111964
112981
|
init_agent_instructions();
|
|
111965
112982
|
init_prompt_layers();
|
|
112983
|
+
init_goal_injection_diagnostics();
|
|
112984
|
+
init_goal_anchoring_audit();
|
|
111966
112985
|
init_run_audit();
|
|
111967
112986
|
init_auto_recovery();
|
|
111968
112987
|
init_restart_recovery_coordinator();
|
|
@@ -112349,6 +113368,11 @@ The tool prevents your session from being killed by the inactivity watchdog duri
|
|
|
112349
113368
|
executorLog.log(`Unpaused ${task.id} in-progress with no session \u2014 resuming execution`);
|
|
112350
113369
|
try {
|
|
112351
113370
|
await this.clearResumeFailureState(task);
|
|
113371
|
+
await this.store.updateTask(task.id, {
|
|
113372
|
+
resumeLimboCount: 0,
|
|
113373
|
+
resumeLimboTipSha: null,
|
|
113374
|
+
resumeLimboStepSignature: null
|
|
113375
|
+
});
|
|
112352
113376
|
await this.store.logEntry(task.id, "Resuming execution after unpause", void 0, this.getRunContextFor(task.id));
|
|
112353
113377
|
await this.recoverApprovedStepsOnResume(task.id);
|
|
112354
113378
|
} catch (clearErr) {
|
|
@@ -114724,8 +115748,30 @@ ${summary}`,
|
|
|
114724
115748
|
if (executorPluginContributions) {
|
|
114725
115749
|
executorLog.log(`${task.id}: applied plugin prompt contributions for executor-system surface`);
|
|
114726
115750
|
}
|
|
115751
|
+
const executorGoalResolution = resolveGoalContextForDiagnostics({
|
|
115752
|
+
listActiveGoals: typeof this.store.getGoalStore === "function" ? () => this.store.getGoalStore().listGoals({ status: "active" }) : void 0
|
|
115753
|
+
});
|
|
115754
|
+
const executorGoalContext = executorGoalResolution.goalContext;
|
|
115755
|
+
const executorGoalClassification = executorGoalResolution.classification;
|
|
115756
|
+
await emitGoalAnchoringAudit(audit, {
|
|
115757
|
+
lane: "executor",
|
|
115758
|
+
taskId: task.id,
|
|
115759
|
+
goalsInjected: executorGoalClassification.goalCount,
|
|
115760
|
+
truncated: executorGoalClassification.truncated,
|
|
115761
|
+
reason: executorGoalClassification.outcome === "no-goals" ? "no-active-goals" : void 0
|
|
115762
|
+
});
|
|
115763
|
+
await emitGoalInjectionDiagnostic({
|
|
115764
|
+
lane: "executor",
|
|
115765
|
+
...executorGoalClassification,
|
|
115766
|
+
runId: engineRunContext.runId,
|
|
115767
|
+
agentId: engineRunContext.agentId,
|
|
115768
|
+
taskId: task.id,
|
|
115769
|
+
store: this.store,
|
|
115770
|
+
runContext: engineRunContext
|
|
115771
|
+
});
|
|
114727
115772
|
const executorLayers = buildPromptLayers({
|
|
114728
115773
|
basePrompt: getExecutorSystemPrompt(settings),
|
|
115774
|
+
goalContext: executorGoalContext,
|
|
114729
115775
|
agentInstructions: executorInstructions,
|
|
114730
115776
|
pluginContributions: executorPluginContributions
|
|
114731
115777
|
});
|
|
@@ -120195,7 +121241,8 @@ async function collectTaskEvaluationEvidence(params) {
|
|
|
120195
121241
|
taskDoneRetryCount: task.taskDoneRetryCount ?? 0,
|
|
120196
121242
|
verificationFailureCount: task.verificationFailureCount ?? 0,
|
|
120197
121243
|
mergeConflictBounceCount: task.mergeConflictBounceCount ?? 0,
|
|
120198
|
-
mergeAuditBounceCount: task.mergeAuditBounceCount ?? 0
|
|
121244
|
+
mergeAuditBounceCount: task.mergeAuditBounceCount ?? 0,
|
|
121245
|
+
mergeTransientRetryCount: task.mergeTransientRetryCount ?? 0
|
|
120199
121246
|
}
|
|
120200
121247
|
}],
|
|
120201
121248
|
commits: commitEvidence,
|
|
@@ -120654,6 +121701,25 @@ function filterPathsByIgnoreList(paths, ignorePaths) {
|
|
|
120654
121701
|
}
|
|
120655
121702
|
return paths.filter((path10) => !normalizedIgnorePaths.some((ignore) => isIgnoredOverlapPath(path10, ignore)));
|
|
120656
121703
|
}
|
|
121704
|
+
function getUnmetSchedulingDependencies(task, tasks) {
|
|
121705
|
+
return task.dependencies.filter((depId) => {
|
|
121706
|
+
const dep = tasks.find((candidate) => candidate.id === depId);
|
|
121707
|
+
return dep && dep.column !== "done" && dep.column !== "in-review" && dep.column !== "archived";
|
|
121708
|
+
});
|
|
121709
|
+
}
|
|
121710
|
+
function isRunnableQueuedOverlapCandidate(task, tasks, now = Date.now(), activeScopes, scope = []) {
|
|
121711
|
+
if (task.column !== "todo" || task.status !== "queued") return false;
|
|
121712
|
+
if (task.paused || task.userPaused) return false;
|
|
121713
|
+
if (task.nextRecoveryAt && new Date(task.nextRecoveryAt).getTime() > now) return false;
|
|
121714
|
+
if (getUnmetSchedulingDependencies(task, tasks).length > 0) return false;
|
|
121715
|
+
if (!activeScopes || activeScopes.size === 0) return true;
|
|
121716
|
+
if (scope.length === 0) return true;
|
|
121717
|
+
for (const activeScope of activeScopes.values()) {
|
|
121718
|
+
if (!activeScope.length) continue;
|
|
121719
|
+
if (pathsOverlap2(scope, activeScope)) return false;
|
|
121720
|
+
}
|
|
121721
|
+
return true;
|
|
121722
|
+
}
|
|
120657
121723
|
function findHigherPriorityQueuedOverlap(candidate, queuedScopes, overlap) {
|
|
120658
121724
|
let higher = null;
|
|
120659
121725
|
for (const queued of queuedScopes) {
|
|
@@ -121328,34 +122394,47 @@ var init_scheduler = __esm({
|
|
|
121328
122394
|
);
|
|
121329
122395
|
}
|
|
121330
122396
|
const activeScopes = /* @__PURE__ */ new Map();
|
|
122397
|
+
const activeScopeColumns = /* @__PURE__ */ new Map();
|
|
122398
|
+
const setActiveScopeLease = (taskId, scope, column) => {
|
|
122399
|
+
activeScopes.set(taskId, scope);
|
|
122400
|
+
activeScopeColumns.set(taskId, column);
|
|
122401
|
+
};
|
|
121331
122402
|
const inversionEmitted = /* @__PURE__ */ new Set();
|
|
121332
122403
|
const queuedHigherPriorityScopes = [];
|
|
122404
|
+
const queuedHigherPriorityTaskById = /* @__PURE__ */ new Map();
|
|
122405
|
+
const overlapIgnorePaths = settings.overlapIgnorePaths ?? [];
|
|
122406
|
+
const filteredScopeByTaskId = /* @__PURE__ */ new Map();
|
|
122407
|
+
const getFilteredFileScope = async (taskId) => {
|
|
122408
|
+
const cached = filteredScopeByTaskId.get(taskId);
|
|
122409
|
+
if (cached) return cached;
|
|
122410
|
+
const scope = await this.store.parseFileScopeFromPrompt(taskId);
|
|
122411
|
+
const filteredScope = filterPathsByIgnoreList(scope, overlapIgnorePaths);
|
|
122412
|
+
filteredScopeByTaskId.set(taskId, filteredScope);
|
|
122413
|
+
return filteredScope;
|
|
122414
|
+
};
|
|
121333
122415
|
if (settings.groupOverlappingFiles) {
|
|
121334
|
-
const overlapIgnorePaths = settings.overlapIgnorePaths ?? [];
|
|
121335
122416
|
for (const t of inProgress) {
|
|
121336
|
-
const
|
|
121337
|
-
|
|
121338
|
-
|
|
122417
|
+
const filteredScope = await getFilteredFileScope(t.id);
|
|
122418
|
+
if (filteredScope.length > 0) setActiveScopeLease(t.id, filteredScope, "in-progress");
|
|
122419
|
+
}
|
|
122420
|
+
const inReviewWithWorktree = tasks.filter(
|
|
122421
|
+
(t) => t.column === "in-review" && Boolean(t.worktree) && !t.paused && t.status !== "failed"
|
|
122422
|
+
);
|
|
122423
|
+
for (const t of inReviewWithWorktree) {
|
|
122424
|
+
const filteredScope = await getFilteredFileScope(t.id);
|
|
122425
|
+
if (filteredScope.length > 0) setActiveScopeLease(t.id, filteredScope, "in-review");
|
|
121339
122426
|
}
|
|
121340
122427
|
for (const t of todo) {
|
|
121341
|
-
|
|
121342
|
-
const scope = await this.store.parseFileScopeFromPrompt(t.id);
|
|
121343
|
-
const filteredScope = filterPathsByIgnoreList(scope, overlapIgnorePaths);
|
|
122428
|
+
const filteredScope = await getFilteredFileScope(t.id);
|
|
121344
122429
|
if (filteredScope.length === 0) continue;
|
|
122430
|
+
if (!isRunnableQueuedOverlapCandidate(t, tasks, now, activeScopes, filteredScope)) continue;
|
|
121345
122431
|
queuedHigherPriorityScopes.push({
|
|
121346
122432
|
id: t.id,
|
|
121347
122433
|
priority: t.priority,
|
|
121348
122434
|
createdAt: t.createdAt,
|
|
121349
122435
|
scope: filteredScope
|
|
121350
122436
|
});
|
|
121351
|
-
|
|
121352
|
-
const inReviewWithWorktree = tasks.filter(
|
|
121353
|
-
(t) => t.column === "in-review" && Boolean(t.worktree) && !t.paused && t.status !== "failed"
|
|
121354
|
-
);
|
|
121355
|
-
for (const t of inReviewWithWorktree) {
|
|
121356
|
-
const scope = await this.store.parseFileScopeFromPrompt(t.id);
|
|
121357
|
-
const filteredScope = filterPathsByIgnoreList(scope, overlapIgnorePaths);
|
|
121358
|
-
if (filteredScope.length > 0) activeScopes.set(t.id, filteredScope);
|
|
122437
|
+
queuedHigherPriorityTaskById.set(t.id, t);
|
|
121359
122438
|
}
|
|
121360
122439
|
}
|
|
121361
122440
|
const ordered = resolveDependencyOrder(todo);
|
|
@@ -121376,10 +122455,7 @@ var init_scheduler = __esm({
|
|
|
121376
122455
|
continue;
|
|
121377
122456
|
}
|
|
121378
122457
|
}
|
|
121379
|
-
const unmetDeps = task
|
|
121380
|
-
const dep = tasks.find((t) => t.id === depId);
|
|
121381
|
-
return dep && dep.column !== "done" && dep.column !== "in-review" && dep.column !== "archived";
|
|
121382
|
-
});
|
|
122458
|
+
const unmetDeps = getUnmetSchedulingDependencies(task, tasks);
|
|
121383
122459
|
if (unmetDeps.length > 0) {
|
|
121384
122460
|
await this.store.updateTask(task.id, {
|
|
121385
122461
|
status: "queued",
|
|
@@ -121413,17 +122489,18 @@ var init_scheduler = __esm({
|
|
|
121413
122489
|
continue;
|
|
121414
122490
|
}
|
|
121415
122491
|
if (settings.groupOverlappingFiles) {
|
|
121416
|
-
const
|
|
121417
|
-
const taskScope = filterPathsByIgnoreList(
|
|
121418
|
-
await this.store.parseFileScopeFromPrompt(task.id),
|
|
121419
|
-
overlapIgnorePaths
|
|
121420
|
-
);
|
|
122492
|
+
const taskScope = await getFilteredFileScope(task.id);
|
|
121421
122493
|
if (taskScope.length > 0) {
|
|
121422
122494
|
const activeScopeEntries = Array.from(activeScopes.entries()).sort(([aId], [bId]) => aId.localeCompare(bId));
|
|
121423
122495
|
const overlapBlockerId = task.overlapBlockedBy || task.blockedBy;
|
|
121424
122496
|
const currentBlockerScope = overlapBlockerId ? activeScopes.get(overlapBlockerId) : void 0;
|
|
121425
122497
|
const hasValidCurrentBlocker = Boolean(overlapBlockerId) && Boolean(currentBlockerScope) && this.pathsOverlap(taskScope, currentBlockerScope);
|
|
121426
122498
|
const overlappingTaskId = hasValidCurrentBlocker ? overlapBlockerId : activeScopeEntries.find(([, ipScope]) => this.pathsOverlap(taskScope, ipScope))?.[0] ?? null;
|
|
122499
|
+
const runnableQueuedHigherPriorityScopes = queuedHigherPriorityScopes.filter((queuedCandidate) => {
|
|
122500
|
+
const queuedTask = queuedHigherPriorityTaskById.get(queuedCandidate.id);
|
|
122501
|
+
if (!queuedTask) return false;
|
|
122502
|
+
return isRunnableQueuedOverlapCandidate(queuedTask, tasks, now, activeScopes, queuedCandidate.scope);
|
|
122503
|
+
});
|
|
121427
122504
|
const higherPriorityQueuedOverlap = findHigherPriorityQueuedOverlap(
|
|
121428
122505
|
{
|
|
121429
122506
|
id: task.id,
|
|
@@ -121431,7 +122508,7 @@ var init_scheduler = __esm({
|
|
|
121431
122508
|
createdAt: task.createdAt,
|
|
121432
122509
|
scope: taskScope
|
|
121433
122510
|
},
|
|
121434
|
-
|
|
122511
|
+
runnableQueuedHigherPriorityScopes,
|
|
121435
122512
|
this.pathsOverlap.bind(this)
|
|
121436
122513
|
);
|
|
121437
122514
|
if (higherPriorityQueuedOverlap) {
|
|
@@ -121446,7 +122523,7 @@ var init_scheduler = __esm({
|
|
|
121446
122523
|
await this.rollbackRunningAgentsForQueuedTodoTask(task.id);
|
|
121447
122524
|
await this.logDispatchQueuedReason(
|
|
121448
122525
|
task.id,
|
|
121449
|
-
`queued \u2014 deferred for higher-priority queued task ${higherPriorityQueuedOverlap.id} (overlap)`
|
|
122526
|
+
`queued \u2014 deferred for higher-priority runnable queued task ${higherPriorityQueuedOverlap.id} (overlap)`
|
|
121450
122527
|
);
|
|
121451
122528
|
continue;
|
|
121452
122529
|
}
|
|
@@ -121478,7 +122555,7 @@ var init_scheduler = __esm({
|
|
|
121478
122555
|
blockerId: overlapBlockerTask.id,
|
|
121479
122556
|
blockerPriority: overlapBlockerTask.priority ?? null,
|
|
121480
122557
|
blockerCreatedAt: overlapBlockerTask.createdAt ?? null,
|
|
121481
|
-
blockerColumn: overlapBlockerTask.column,
|
|
122558
|
+
blockerColumn: activeScopeColumns.get(overlappingTaskId) ?? overlapBlockerTask.column,
|
|
121482
122559
|
source: "scheduler.overlap-priority-inversion"
|
|
121483
122560
|
}
|
|
121484
122561
|
});
|
|
@@ -121489,7 +122566,11 @@ var init_scheduler = __esm({
|
|
|
121489
122566
|
}
|
|
121490
122567
|
}
|
|
121491
122568
|
await this.rollbackRunningAgentsForQueuedTodoTask(task.id);
|
|
121492
|
-
|
|
122569
|
+
const activeLeaseColumn = activeScopeColumns.get(overlappingTaskId) ?? overlapBlockerTask?.column ?? "unknown";
|
|
122570
|
+
await this.logDispatchQueuedReason(
|
|
122571
|
+
task.id,
|
|
122572
|
+
`queued \u2014 blocked by active file-scope lease ${overlappingTaskId} (column=${activeLeaseColumn})`
|
|
122573
|
+
);
|
|
121493
122574
|
continue;
|
|
121494
122575
|
}
|
|
121495
122576
|
if (task.overlapBlockedBy) {
|
|
@@ -121708,11 +122789,8 @@ var init_scheduler = __esm({
|
|
|
121708
122789
|
this.options.onSchedule?.(task);
|
|
121709
122790
|
started++;
|
|
121710
122791
|
if (settings.groupOverlappingFiles) {
|
|
121711
|
-
const scope =
|
|
121712
|
-
|
|
121713
|
-
settings.overlapIgnorePaths
|
|
121714
|
-
);
|
|
121715
|
-
if (scope.length > 0) activeScopes.set(task.id, scope);
|
|
122792
|
+
const scope = await getFilteredFileScope(task.id);
|
|
122793
|
+
if (scope.length > 0) setActiveScopeLease(task.id, scope, "in-progress");
|
|
121716
122794
|
}
|
|
121717
122795
|
}
|
|
121718
122796
|
await this.emitHighOverlapFanoutWarnings(tasks);
|
|
@@ -124742,6 +125820,8 @@ var init_agent_heartbeat = __esm({
|
|
|
124742
125820
|
init_agent_instructions();
|
|
124743
125821
|
init_heartbeat_procedure_resolver();
|
|
124744
125822
|
init_prompt_layers();
|
|
125823
|
+
init_goal_injection_diagnostics();
|
|
125824
|
+
init_goal_anchoring_audit();
|
|
124745
125825
|
init_logger2();
|
|
124746
125826
|
init_worktree_acquisition();
|
|
124747
125827
|
init_run_audit();
|
|
@@ -126133,12 +127213,16 @@ Critical: a heartbeat without observable progress (or an explicit no-op reason)
|
|
|
126133
127213
|
engineRunContext.taskId = taskId;
|
|
126134
127214
|
}
|
|
126135
127215
|
let autoClaimCandidates = [];
|
|
127216
|
+
let autoClaimSnapshotCandidateCount = 0;
|
|
127217
|
+
let autoClaimRoleFilteredCount = 0;
|
|
126136
127218
|
const autoClaimEnabled = isAutoClaimRelevantTasksEnabled(agent);
|
|
126137
127219
|
if (!taskId && canRunNoTaskHeartbeat && autoClaimEnabled && this.snapshotManager) {
|
|
126138
127220
|
try {
|
|
126139
127221
|
const snapshot = await this.snapshotManager.getSnapshot();
|
|
127222
|
+
autoClaimSnapshotCandidateCount = snapshot.tasks.length;
|
|
126140
127223
|
const roleCompatibleCandidates = snapshot.tasks.filter((candidate) => canAgentTakeImplementationTask(agent, candidate));
|
|
126141
127224
|
const skippedIncompatibleCount = snapshot.tasks.length - roleCompatibleCandidates.length;
|
|
127225
|
+
autoClaimRoleFilteredCount = skippedIncompatibleCount;
|
|
126142
127226
|
if (skippedIncompatibleCount > 0) {
|
|
126143
127227
|
heartbeatLog.log(
|
|
126144
127228
|
`Agent ${agentId} (role=${agent.role}) skipped auto-claim of ${skippedIncompatibleCount} implementation task(s) \u2014 only executor agents may claim implementation work`
|
|
@@ -126394,8 +127478,29 @@ Critical: a heartbeat without observable progress (or an explicit no-op reason)
|
|
|
126394
127478
|
if (heartbeatPluginContributions) {
|
|
126395
127479
|
heartbeatLog.log(`applied plugin prompt contributions for heartbeat surface`);
|
|
126396
127480
|
}
|
|
127481
|
+
const heartbeatGoalResolution = resolveGoalContextForDiagnostics({
|
|
127482
|
+
listActiveGoals: typeof taskStore.getGoalStore === "function" ? () => taskStore.getGoalStore().listGoals({ status: "active" }) : void 0
|
|
127483
|
+
});
|
|
127484
|
+
const heartbeatGoalContext = heartbeatGoalResolution.goalContext;
|
|
127485
|
+
const heartbeatGoalClassification = heartbeatGoalResolution.classification;
|
|
127486
|
+
await emitGoalAnchoringAudit(audit, {
|
|
127487
|
+
lane: "heartbeat",
|
|
127488
|
+
taskId,
|
|
127489
|
+
goalsInjected: heartbeatGoalClassification.goalCount,
|
|
127490
|
+
truncated: heartbeatGoalClassification.truncated,
|
|
127491
|
+
reason: heartbeatGoalClassification.outcome === "no-goals" ? "no-active-goals" : void 0
|
|
127492
|
+
});
|
|
127493
|
+
await emitGoalInjectionDiagnostic({
|
|
127494
|
+
lane: "heartbeat",
|
|
127495
|
+
...heartbeatGoalClassification,
|
|
127496
|
+
runId: run2.id,
|
|
127497
|
+
agentId,
|
|
127498
|
+
store: taskStore,
|
|
127499
|
+
runContext: engineRunContext
|
|
127500
|
+
});
|
|
126397
127501
|
const heartbeatLayers = buildPromptLayers({
|
|
126398
127502
|
basePrompt: baseHeartbeatSystemPrompt,
|
|
127503
|
+
goalContext: heartbeatGoalContext,
|
|
126399
127504
|
agentInstructions: [resolvedInstructionsText, memoryInstructions, selfImprovePrompt].filter((part) => part.trim()).join("\n\n"),
|
|
126400
127505
|
pluginContributions: heartbeatPluginContributions
|
|
126401
127506
|
});
|
|
@@ -126670,10 +127775,15 @@ Critical: a heartbeat without observable progress (or an explicit no-op reason)
|
|
|
126670
127775
|
);
|
|
126671
127776
|
}
|
|
126672
127777
|
const promptCandidateLimit = resolveAutoClaimCandidatesInPromptLimit(agent, heartbeatModelSettings);
|
|
127778
|
+
const autoClaimStatus = autoClaimEnabled ? promptCandidateLimit === 0 ? "disabled (prompt-suppressed)" : autoClaimCandidates.length === 0 && autoClaimSnapshotCandidateCount > 0 && autoClaimRoleFilteredCount > 0 ? "enabled (no role-compatible candidates; executor role required)" : "enabled" : "disabled";
|
|
127779
|
+
const noRoleCompatibleCandidateLines = autoClaimCandidates.length === 0 && autoClaimSnapshotCandidateCount > 0 && autoClaimRoleFilteredCount > 0 ? [
|
|
127780
|
+
`- Snapshot found ${autoClaimSnapshotCandidateCount} eligible Todo task(s), but this agent role cannot auto-claim implementation work.`,
|
|
127781
|
+
"- Backlog auto-claim is restricted to executor-role agents; use delegation or create coordination follow-up instead of assuming the board is empty."
|
|
127782
|
+
] : [];
|
|
126673
127783
|
const candidateLines = promptCandidateLimit > 0 ? [
|
|
126674
127784
|
"",
|
|
126675
127785
|
"Open Task Candidates (auto-claim scan):",
|
|
126676
|
-
...autoClaimCandidates.slice(0, promptCandidateLimit).map((candidate) => `- ${candidate.id}: ${candidate.title ?? candidate.descriptionFirstLine}`)
|
|
127786
|
+
...autoClaimCandidates.length > 0 ? autoClaimCandidates.slice(0, promptCandidateLimit).map((candidate) => `- ${candidate.id}: ${candidate.title ?? candidate.descriptionFirstLine}`) : noRoleCompatibleCandidateLines
|
|
126677
127787
|
] : [];
|
|
126678
127788
|
executionPrompt = [
|
|
126679
127789
|
`Heartbeat execution for agent "${agent.name}" (ID: ${agent.id})`,
|
|
@@ -126689,7 +127799,7 @@ Critical: a heartbeat without observable progress (or an explicit no-op reason)
|
|
|
126689
127799
|
...wakeTriggerSourceLine ? [wakeTriggerSourceLine] : [],
|
|
126690
127800
|
`- pending messages: ${pendingMessages.length}`,
|
|
126691
127801
|
`- pending room messages: ${pendingRoomMessages.total}`,
|
|
126692
|
-
`- auto-claim relevant tasks: ${
|
|
127802
|
+
`- auto-claim relevant tasks: ${autoClaimStatus}`,
|
|
126693
127803
|
"",
|
|
126694
127804
|
"Treat this wake delta as the highest-priority change for this heartbeat.",
|
|
126695
127805
|
"This is an autonomous heartbeat run (manual or automatic): re-anchor on",
|
|
@@ -127922,78 +129032,6 @@ var init_error_classifier = __esm({
|
|
|
127922
129032
|
}
|
|
127923
129033
|
});
|
|
127924
129034
|
|
|
127925
|
-
// ../engine/src/goal-context-injector.ts
|
|
127926
|
-
function normalizeTitle(title) {
|
|
127927
|
-
return title.replace(/\s*\n+\s*/g, " ").trim();
|
|
127928
|
-
}
|
|
127929
|
-
function renderGoalContext(goals) {
|
|
127930
|
-
const lines = goals.map((goal) => `- ${goal.id}: ${normalizeTitle(goal.title)}`);
|
|
127931
|
-
return `## Active Goals
|
|
127932
|
-
|
|
127933
|
-
${lines.join("\n")}`;
|
|
127934
|
-
}
|
|
127935
|
-
function buildGoalContextSection(input) {
|
|
127936
|
-
const { activeGoals, onTruncated } = input;
|
|
127937
|
-
if (activeGoals.length === 0) {
|
|
127938
|
-
return { text: "", emittedGoalIds: [], truncated: null };
|
|
127939
|
-
}
|
|
127940
|
-
const sortedGoals = [...activeGoals].sort((a, b2) => {
|
|
127941
|
-
const byCreated = a.createdAt.localeCompare(b2.createdAt);
|
|
127942
|
-
if (byCreated !== 0) {
|
|
127943
|
-
return byCreated;
|
|
127944
|
-
}
|
|
127945
|
-
return a.id.localeCompare(b2.id);
|
|
127946
|
-
});
|
|
127947
|
-
const resolvedMaxGoals = Math.min(input.maxGoals ?? MAX_INJECTED_GOALS, MAX_INJECTED_GOALS);
|
|
127948
|
-
const charBudget = input.charBudget ?? DEFAULT_GOAL_INJECTION_CHAR_BUDGET;
|
|
127949
|
-
const droppedGoalIds = [];
|
|
127950
|
-
let selectedGoals = sortedGoals.slice(0, resolvedMaxGoals);
|
|
127951
|
-
if (sortedGoals.length > resolvedMaxGoals) {
|
|
127952
|
-
droppedGoalIds.push(...sortedGoals.slice(resolvedMaxGoals).map((goal) => goal.id));
|
|
127953
|
-
}
|
|
127954
|
-
let text = renderGoalContext(selectedGoals);
|
|
127955
|
-
let usedBudgetDrop = false;
|
|
127956
|
-
while (selectedGoals.length > 1 && text.length > charBudget) {
|
|
127957
|
-
const dropped = selectedGoals[selectedGoals.length - 1];
|
|
127958
|
-
selectedGoals = selectedGoals.slice(0, -1);
|
|
127959
|
-
droppedGoalIds.push(dropped.id);
|
|
127960
|
-
text = renderGoalContext(selectedGoals);
|
|
127961
|
-
usedBudgetDrop = true;
|
|
127962
|
-
}
|
|
127963
|
-
let truncated = null;
|
|
127964
|
-
if (droppedGoalIds.length > 0) {
|
|
127965
|
-
truncated = {
|
|
127966
|
-
reason: usedBudgetDrop ? "budget" : "cap",
|
|
127967
|
-
requested: activeGoals.length,
|
|
127968
|
-
emitted: selectedGoals.length,
|
|
127969
|
-
droppedGoalIds,
|
|
127970
|
-
charBudget,
|
|
127971
|
-
producedChars: text.length
|
|
127972
|
-
};
|
|
127973
|
-
onTruncated?.(truncated);
|
|
127974
|
-
}
|
|
127975
|
-
return {
|
|
127976
|
-
text,
|
|
127977
|
-
emittedGoalIds: selectedGoals.map((goal) => goal.id),
|
|
127978
|
-
truncated
|
|
127979
|
-
};
|
|
127980
|
-
}
|
|
127981
|
-
var MAX_INJECTED_GOALS, resolvedActiveGoalLimit, DEFAULT_GOAL_INJECTION_CHAR_BUDGET;
|
|
127982
|
-
var init_goal_context_injector = __esm({
|
|
127983
|
-
"../engine/src/goal-context-injector.ts"() {
|
|
127984
|
-
"use strict";
|
|
127985
|
-
init_src();
|
|
127986
|
-
MAX_INJECTED_GOALS = 5;
|
|
127987
|
-
resolvedActiveGoalLimit = "ACTIVE_GOAL_LIMIT" in src_exports && typeof ACTIVE_GOAL_LIMIT === "number" ? ACTIVE_GOAL_LIMIT : MAX_INJECTED_GOALS;
|
|
127988
|
-
if (MAX_INJECTED_GOALS > resolvedActiveGoalLimit) {
|
|
127989
|
-
throw new Error(
|
|
127990
|
-
`MAX_INJECTED_GOALS (${MAX_INJECTED_GOALS}) cannot exceed ACTIVE_GOAL_LIMIT (${resolvedActiveGoalLimit})`
|
|
127991
|
-
);
|
|
127992
|
-
}
|
|
127993
|
-
DEFAULT_GOAL_INJECTION_CHAR_BUDGET = 600;
|
|
127994
|
-
}
|
|
127995
|
-
});
|
|
127996
|
-
|
|
127997
129035
|
// ../engine/src/experiment/benchmark-runner.ts
|
|
127998
129036
|
import { spawn as spawn7 } from "node:child_process";
|
|
127999
129037
|
import { mkdtemp, writeFile as writeFile17 } from "node:fs/promises";
|
|
@@ -133912,7 +134950,8 @@ var init_in_process_runtime = __esm({
|
|
|
133912
134950
|
this.usageLimitPauser = pauser;
|
|
133913
134951
|
}
|
|
133914
134952
|
/**
|
|
133915
|
-
* Set up event forwarding from TaskStore to runtime listeners
|
|
134953
|
+
* Set up event forwarding from TaskStore to runtime listeners
|
|
134954
|
+
* for task:created, task:moved, task:updated, and task:deleted.
|
|
133916
134955
|
*/
|
|
133917
134956
|
setupEventForwarding() {
|
|
133918
134957
|
this.taskStore.on("task:created", (task) => {
|
|
@@ -133927,6 +134966,10 @@ var init_in_process_runtime = __esm({
|
|
|
133927
134966
|
this.recordActivity();
|
|
133928
134967
|
this.emit("task:updated", task);
|
|
133929
134968
|
});
|
|
134969
|
+
this.taskStore.on("task:deleted", (task, meta) => {
|
|
134970
|
+
this.recordActivity();
|
|
134971
|
+
this.emit("task:deleted", task, meta);
|
|
134972
|
+
});
|
|
133930
134973
|
runtimeLog.log("Event forwarding setup complete");
|
|
133931
134974
|
}
|
|
133932
134975
|
/**
|
|
@@ -133977,7 +135020,7 @@ var init_in_process_runtime = __esm({
|
|
|
133977
135020
|
function generateCorrelationId() {
|
|
133978
135021
|
return `${Date.now()}-${Math.random().toString(36).slice(2, 11)}`;
|
|
133979
135022
|
}
|
|
133980
|
-
var START_RUNTIME, STOP_RUNTIME, GET_METRICS, OK, ERROR, PONG, TASK_CREATED, TASK_MOVED, TASK_UPDATED, ERROR_EVENT, HEALTH_CHANGED;
|
|
135023
|
+
var START_RUNTIME, STOP_RUNTIME, GET_METRICS, OK, ERROR, PONG, TASK_CREATED, TASK_MOVED, TASK_UPDATED, TASK_DELETED, ERROR_EVENT, HEALTH_CHANGED;
|
|
133981
135024
|
var init_ipc_protocol = __esm({
|
|
133982
135025
|
"../engine/src/ipc/ipc-protocol.ts"() {
|
|
133983
135026
|
"use strict";
|
|
@@ -133990,6 +135033,7 @@ var init_ipc_protocol = __esm({
|
|
|
133990
135033
|
TASK_CREATED = "TASK_CREATED";
|
|
133991
135034
|
TASK_MOVED = "TASK_MOVED";
|
|
133992
135035
|
TASK_UPDATED = "TASK_UPDATED";
|
|
135036
|
+
TASK_DELETED = "TASK_DELETED";
|
|
133993
135037
|
ERROR_EVENT = "ERROR_EVENT";
|
|
133994
135038
|
HEALTH_CHANGED = "HEALTH_CHANGED";
|
|
133995
135039
|
}
|
|
@@ -134374,6 +135418,9 @@ var init_child_process_runtime = __esm({
|
|
|
134374
135418
|
this.ipcHost.on(TASK_UPDATED, (payload) => {
|
|
134375
135419
|
this.emit("task:updated", payload.task);
|
|
134376
135420
|
});
|
|
135421
|
+
this.ipcHost.on(TASK_DELETED, (payload) => {
|
|
135422
|
+
this.emit("task:deleted", payload.task, payload.meta);
|
|
135423
|
+
});
|
|
134377
135424
|
this.ipcHost.on(ERROR_EVENT, (payload) => {
|
|
134378
135425
|
const error = new Error(payload.message);
|
|
134379
135426
|
if (payload.code) {
|
|
@@ -135496,6 +136543,9 @@ var init_project_manager = __esm({
|
|
|
135496
136543
|
runtime.on("task:updated", (task) => {
|
|
135497
136544
|
this.emit("task:updated", { projectId, projectName, task });
|
|
135498
136545
|
});
|
|
136546
|
+
runtime.on("task:deleted", (task, meta) => {
|
|
136547
|
+
this.emit("task:deleted", { projectId, projectName, task, meta });
|
|
136548
|
+
});
|
|
135499
136549
|
runtime.on("error", (error) => {
|
|
135500
136550
|
this.emit("error", { projectId, projectName, error });
|
|
135501
136551
|
this.logActivity(
|
|
@@ -137174,6 +138224,7 @@ var init_project_engine = __esm({
|
|
|
137174
138224
|
init_research_step_runner();
|
|
137175
138225
|
init_run_audit();
|
|
137176
138226
|
init_verification_followup_dedup();
|
|
138227
|
+
init_transient_error_detector();
|
|
137177
138228
|
init_tunnel_process_manager();
|
|
137178
138229
|
execFileAsync12 = promisify45(execFile17);
|
|
137179
138230
|
MERGE_HANDOFF_GRACE_MS = 300;
|
|
@@ -137244,6 +138295,10 @@ var init_project_engine = __esm({
|
|
|
137244
138295
|
manualMergeResolvers = /* @__PURE__ */ new Map();
|
|
137245
138296
|
shuttingDown = false;
|
|
137246
138297
|
static MAX_AUTO_MERGE_RETRIES = 3;
|
|
138298
|
+
/** FN-5697/FN-5674: cap transient provider/network abort retries in auto-merge.
|
|
138299
|
+
* Examples: "This operation was aborted", "socket hang up", `server_error`.
|
|
138300
|
+
* After this cap, the task is parked failed for human visibility. */
|
|
138301
|
+
static MAX_AUTO_MERGE_TRANSIENT_RETRIES = 3;
|
|
137247
138302
|
/** Cap on outer in-review→in-progress bounces caused by deterministic
|
|
137248
138303
|
* verification failures during auto-merge. After this many failed merges
|
|
137249
138304
|
* for the same task, we stop bouncing it back, mark it failed, and create
|
|
@@ -138226,7 +139281,15 @@ ${detail}`
|
|
|
138226
139281
|
this.internalEnqueueMerge(taskId);
|
|
138227
139282
|
continue;
|
|
138228
139283
|
}
|
|
138229
|
-
const blockerReason = getTaskHardMergeBlocker(
|
|
139284
|
+
const blockerReason = getTaskHardMergeBlocker({
|
|
139285
|
+
...task,
|
|
139286
|
+
// Merge-confirmed tasks have already landed. Treat stale merge
|
|
139287
|
+
// in-flight statuses as soft state to clear during finalization,
|
|
139288
|
+
// not hard blockers that park an otherwise confirmed merge as failed.
|
|
139289
|
+
paused: false,
|
|
139290
|
+
status: task.status === "merging" || task.status === "merging-pr" ? void 0 : task.status,
|
|
139291
|
+
error: void 0
|
|
139292
|
+
});
|
|
138230
139293
|
if (blockerReason) {
|
|
138231
139294
|
await store.updateTask(taskId, {
|
|
138232
139295
|
status: "failed",
|
|
@@ -138745,6 +139808,16 @@ ${detail}`
|
|
|
138745
139808
|
}
|
|
138746
139809
|
} else {
|
|
138747
139810
|
try {
|
|
139811
|
+
if (await this.maybeRetryTransientMerge(store, taskId, taskOnErr, errorMsg)) {
|
|
139812
|
+
continue;
|
|
139813
|
+
}
|
|
139814
|
+
if (this.isTransientMergeRetryExhausted(taskOnErr, errorMsg)) {
|
|
139815
|
+
await store.logEntry(
|
|
139816
|
+
taskId,
|
|
139817
|
+
`Auto-merge transient retries exhausted (${_ProjectEngine.MAX_AUTO_MERGE_TRANSIENT_RETRIES}/${_ProjectEngine.MAX_AUTO_MERGE_TRANSIENT_RETRIES}); parking task as failed: ${errorMsg}`,
|
|
139818
|
+
"MergeTransientRetryExhausted"
|
|
139819
|
+
);
|
|
139820
|
+
}
|
|
138748
139821
|
await store.updateTask(taskId, {
|
|
138749
139822
|
status: "failed",
|
|
138750
139823
|
mergeRetries: _ProjectEngine.MAX_AUTO_MERGE_RETRIES,
|
|
@@ -138763,6 +139836,16 @@ ${detail}`
|
|
|
138763
139836
|
}
|
|
138764
139837
|
} else {
|
|
138765
139838
|
try {
|
|
139839
|
+
if (await this.maybeRetryTransientMerge(store, taskId, taskOnErr, errorMsg)) {
|
|
139840
|
+
continue;
|
|
139841
|
+
}
|
|
139842
|
+
if (this.isTransientMergeRetryExhausted(taskOnErr, errorMsg)) {
|
|
139843
|
+
await store.logEntry(
|
|
139844
|
+
taskId,
|
|
139845
|
+
`Auto-merge transient retries exhausted (${_ProjectEngine.MAX_AUTO_MERGE_TRANSIENT_RETRIES}/${_ProjectEngine.MAX_AUTO_MERGE_TRANSIENT_RETRIES}); parking task as failed: ${errorMsg}`,
|
|
139846
|
+
"MergeTransientRetryExhausted"
|
|
139847
|
+
);
|
|
139848
|
+
}
|
|
138766
139849
|
await store.updateTask(taskId, {
|
|
138767
139850
|
status: "failed",
|
|
138768
139851
|
mergeRetries: _ProjectEngine.MAX_AUTO_MERGE_RETRIES,
|
|
@@ -138798,6 +139881,40 @@ ${detail}`
|
|
|
138798
139881
|
this.mergeRunning = false;
|
|
138799
139882
|
}
|
|
138800
139883
|
}
|
|
139884
|
+
isTransientMergeRetryExhausted(task, errorMsg) {
|
|
139885
|
+
if (!task || !isTransientError(errorMsg)) {
|
|
139886
|
+
return false;
|
|
139887
|
+
}
|
|
139888
|
+
const current = task.mergeTransientRetryCount ?? 0;
|
|
139889
|
+
return current >= _ProjectEngine.MAX_AUTO_MERGE_TRANSIENT_RETRIES;
|
|
139890
|
+
}
|
|
139891
|
+
async maybeRetryTransientMerge(store, taskId, taskOnErr, errorMsg) {
|
|
139892
|
+
if (!taskOnErr || !isTransientError(errorMsg)) {
|
|
139893
|
+
return false;
|
|
139894
|
+
}
|
|
139895
|
+
const currentRetries = taskOnErr.mergeTransientRetryCount ?? 0;
|
|
139896
|
+
if (currentRetries >= _ProjectEngine.MAX_AUTO_MERGE_TRANSIENT_RETRIES) {
|
|
139897
|
+
return false;
|
|
139898
|
+
}
|
|
139899
|
+
const nextRetryCount = currentRetries + 1;
|
|
139900
|
+
const delayMs = 5e3 * Math.pow(2, currentRetries);
|
|
139901
|
+
await store.updateTask(taskId, {
|
|
139902
|
+
mergeTransientRetryCount: nextRetryCount,
|
|
139903
|
+
status: null
|
|
139904
|
+
});
|
|
139905
|
+
await store.logEntry(
|
|
139906
|
+
taskId,
|
|
139907
|
+
`Auto-merge transient retry ${nextRetryCount}/${_ProjectEngine.MAX_AUTO_MERGE_TRANSIENT_RETRIES} scheduled in ${delayMs / 1e3}s: ${errorMsg}`,
|
|
139908
|
+
"MergeTransientRetry"
|
|
139909
|
+
);
|
|
139910
|
+
runtimeLog.log(
|
|
139911
|
+
`Auto-merge transient retry ${nextRetryCount}/${_ProjectEngine.MAX_AUTO_MERGE_TRANSIENT_RETRIES} for ${taskId} in ${delayMs / 1e3}s`
|
|
139912
|
+
);
|
|
139913
|
+
setTimeout(() => {
|
|
139914
|
+
if (!this.shuttingDown) this.internalEnqueueMerge(taskId);
|
|
139915
|
+
}, delayMs);
|
|
139916
|
+
return true;
|
|
139917
|
+
}
|
|
138801
139918
|
wireAutoMerge(store, _cwd) {
|
|
138802
139919
|
this.taskMovedHandler = async ({ task, to: to2 }) => {
|
|
138803
139920
|
if (to2 !== "in-review") return;
|
|
@@ -142362,6 +143479,9 @@ __export(src_exports2, {
|
|
|
142362
143479
|
ExperimentGitNotConfiguredError: () => ExperimentGitNotConfiguredError,
|
|
142363
143480
|
ExperimentMaxIterationsError: () => ExperimentMaxIterationsError,
|
|
142364
143481
|
ExperimentRevertConflictError: () => ExperimentRevertConflictError,
|
|
143482
|
+
GOAL_INJECTION_APPLIED: () => GOAL_INJECTION_APPLIED,
|
|
143483
|
+
GOAL_INJECTION_SKIPPED: () => GOAL_INJECTION_SKIPPED,
|
|
143484
|
+
GOAL_RETRIEVAL_INVOKED: () => GOAL_RETRIEVAL_INVOKED,
|
|
142365
143485
|
GitHubProvider: () => GitHubProvider,
|
|
142366
143486
|
HEARTBEAT_NO_TASK_SYSTEM_PROMPT: () => HEARTBEAT_NO_TASK_SYSTEM_PROMPT,
|
|
142367
143487
|
HEARTBEAT_PROCEDURE: () => HEARTBEAT_PROCEDURE,
|
|
@@ -142453,6 +143573,8 @@ __export(src_exports2, {
|
|
|
142453
143573
|
buildRuntimeResolutionContext: () => buildRuntimeResolutionContext,
|
|
142454
143574
|
buildSystemPromptWithInstructions: () => buildSystemPromptWithInstructions,
|
|
142455
143575
|
classifyBootstrapMisbinding: () => classifyBootstrapMisbinding,
|
|
143576
|
+
classifyGoalInjectionFailure: () => classifyGoalInjectionFailure,
|
|
143577
|
+
classifyGoalInjectionResult: () => classifyGoalInjectionResult,
|
|
142456
143578
|
classifyTaskError: () => classifyTaskError,
|
|
142457
143579
|
cleanupOrphanedWorktrees: () => cleanupOrphanedWorktrees,
|
|
142458
143580
|
cleanupSecretsEnvFile: () => cleanupSecretsEnvFile,
|
|
@@ -142477,6 +143599,9 @@ __export(src_exports2, {
|
|
|
142477
143599
|
describeModel: () => describeModel,
|
|
142478
143600
|
dropAutostashBySha: () => dropAutostashBySha,
|
|
142479
143601
|
dropAutostashHandle: () => dropAutostashHandle,
|
|
143602
|
+
emitGoalAnchoringAudit: () => emitGoalAnchoringAudit,
|
|
143603
|
+
emitGoalInjectionDiagnostic: () => emitGoalInjectionDiagnostic,
|
|
143604
|
+
emitGoalRetrievalAudit: () => emitGoalRetrievalAudit,
|
|
142480
143605
|
ensureDefaultHeartbeatProcedureFile: () => ensureDefaultHeartbeatProcedureFile,
|
|
142481
143606
|
executeApprovedAgentProvisioning: () => executeApprovedAgentProvisioning,
|
|
142482
143607
|
executeApprovedWorktrunkInstall: () => executeApprovedWorktrunkInstall,
|
|
@@ -142592,6 +143717,8 @@ var init_src2 = __esm({
|
|
|
142592
143717
|
init_web_fetch();
|
|
142593
143718
|
init_error_classifier();
|
|
142594
143719
|
init_goal_context_injector();
|
|
143720
|
+
init_goal_injection_diagnostics();
|
|
143721
|
+
init_goal_anchoring_audit();
|
|
142595
143722
|
init_worktrunk_installer();
|
|
142596
143723
|
init_worktrunk_failure_handler();
|
|
142597
143724
|
init_usage_limit_detector();
|
|
@@ -157632,6 +158759,26 @@ var init_register_git_github = __esm({
|
|
|
157632
158759
|
});
|
|
157633
158760
|
|
|
157634
158761
|
// ../dashboard/src/routes/branch-selection.ts
|
|
158762
|
+
function getBranchSelectionMode(selectionInput) {
|
|
158763
|
+
if (selectionInput === void 0 || selectionInput === null) return void 0;
|
|
158764
|
+
if (typeof selectionInput !== "object" || Array.isArray(selectionInput)) {
|
|
158765
|
+
throw badRequest("branchSelection must be an object");
|
|
158766
|
+
}
|
|
158767
|
+
const selection = selectionInput;
|
|
158768
|
+
const mode = typeof selection.mode === "string" ? selection.mode : void 0;
|
|
158769
|
+
if (!mode) {
|
|
158770
|
+
throw badRequest("branchSelection.mode is required");
|
|
158771
|
+
}
|
|
158772
|
+
if (![
|
|
158773
|
+
"project-default",
|
|
158774
|
+
"auto-new",
|
|
158775
|
+
"existing",
|
|
158776
|
+
"custom-new"
|
|
158777
|
+
].includes(mode)) {
|
|
158778
|
+
throw badRequest("branchSelection.mode must be one of: project-default, auto-new, existing, custom-new");
|
|
158779
|
+
}
|
|
158780
|
+
return mode;
|
|
158781
|
+
}
|
|
157635
158782
|
function normalizeOptionalBranch(value, fieldName) {
|
|
157636
158783
|
if (value === void 0 || value === null) return void 0;
|
|
157637
158784
|
if (typeof value !== "string") {
|
|
@@ -157648,22 +158795,8 @@ function resolveBranchSelection(selectionInput, fallbackBranch, fallbackBaseBran
|
|
|
157648
158795
|
if (selectionInput === void 0 || selectionInput === null) {
|
|
157649
158796
|
return fallback2;
|
|
157650
158797
|
}
|
|
157651
|
-
|
|
157652
|
-
throw badRequest("branchSelection must be an object");
|
|
157653
|
-
}
|
|
158798
|
+
const mode = getBranchSelectionMode(selectionInput);
|
|
157654
158799
|
const selection = selectionInput;
|
|
157655
|
-
const mode = typeof selection.mode === "string" ? selection.mode : void 0;
|
|
157656
|
-
if (!mode) {
|
|
157657
|
-
throw badRequest("branchSelection.mode is required");
|
|
157658
|
-
}
|
|
157659
|
-
if (![
|
|
157660
|
-
"project-default",
|
|
157661
|
-
"auto-new",
|
|
157662
|
-
"existing",
|
|
157663
|
-
"custom-new"
|
|
157664
|
-
].includes(mode)) {
|
|
157665
|
-
throw badRequest("branchSelection.mode must be one of: project-default, auto-new, existing, custom-new");
|
|
157666
|
-
}
|
|
157667
158800
|
const baseBranch = normalizeOptionalBranch(selection.baseBranch, "branchSelection.baseBranch");
|
|
157668
158801
|
if (mode === "project-default") {
|
|
157669
158802
|
return { branch: void 0, baseBranch };
|
|
@@ -157699,6 +158832,11 @@ function resolveBranchAssignmentContext(input) {
|
|
|
157699
158832
|
function sanitizeSegment(input) {
|
|
157700
158833
|
return input.trim().toLowerCase().replace(/[^a-z0-9._/-]+/g, "-").replace(/-{2,}/g, "-").replace(/^[-/.]+|[-/.]+$/g, "").slice(0, 48);
|
|
157701
158834
|
}
|
|
158835
|
+
function deriveAutoTaskBranch(taskId, shortName) {
|
|
158836
|
+
const base = `fusion/${taskId.toLowerCase()}`;
|
|
158837
|
+
const segment = sanitizeSegment(shortName ?? "");
|
|
158838
|
+
return segment ? `${base}-${segment}` : base;
|
|
158839
|
+
}
|
|
157702
158840
|
function derivePerTaskBranch(sharedBranch, taskSegment) {
|
|
157703
158841
|
const base = normalizeOptionalBranch(sharedBranch, "sharedBranch");
|
|
157704
158842
|
if (!base) return void 0;
|
|
@@ -158338,6 +159476,7 @@ function registerTaskWorkflowRoutes(ctx, deps) {
|
|
|
158338
159476
|
}
|
|
158339
159477
|
} : void 0;
|
|
158340
159478
|
const normalizedSource = source && typeof source === "object" && "sourceType" in source && typeof source.sourceType === "string" ? source : { sourceType: "api" };
|
|
159479
|
+
const requestedBranchMode = getBranchSelectionMode(branchSelection);
|
|
158341
159480
|
const { branch: normalizedBranch, baseBranch: normalizedBaseBranch } = resolveBranchSelection(branchSelection, branch, baseBranch);
|
|
158342
159481
|
let validatedGithubTracking;
|
|
158343
159482
|
if (githubTracking !== void 0 && githubTracking !== null) {
|
|
@@ -158594,8 +159733,14 @@ ${normalizedDescription}`;
|
|
|
158594
159733
|
createInput,
|
|
158595
159734
|
{ onSummarize, settings: { autoSummarizeTitles: settings.autoSummarizeTitles } }
|
|
158596
159735
|
);
|
|
159736
|
+
const taskWithAutoBranch = requestedBranchMode === "auto-new" ? await scopedStore.updateTask(task.id, {
|
|
159737
|
+
branch: deriveAutoTaskBranch(
|
|
159738
|
+
task.id,
|
|
159739
|
+
((task.title ?? "").trim() || task.description).slice(0, 60)
|
|
159740
|
+
)
|
|
159741
|
+
}) : task;
|
|
158597
159742
|
const deterministicReconcile = await reconcileDeterministicDuplicate(scopedStore, {
|
|
158598
|
-
createdTask:
|
|
159743
|
+
createdTask: taskWithAutoBranch,
|
|
158599
159744
|
fingerprint: bypassDuplicateCheck === true ? null : contentFingerprint,
|
|
158600
159745
|
windowMs: 6e4,
|
|
158601
159746
|
logger: runtimeLogger
|
|
@@ -158608,8 +159753,8 @@ ${normalizedDescription}`;
|
|
|
158608
159753
|
try {
|
|
158609
159754
|
await scopedStore.recordActivity({
|
|
158610
159755
|
type: "task:duplicate-warning-overridden",
|
|
158611
|
-
taskId:
|
|
158612
|
-
taskTitle:
|
|
159756
|
+
taskId: taskWithAutoBranch.id,
|
|
159757
|
+
taskTitle: taskWithAutoBranch.title,
|
|
158613
159758
|
details: `Created despite ${acknowledgedDuplicateIds.length} possible duplicate(s): ${acknowledgedDuplicateIds.join(", ")}`,
|
|
158614
159759
|
metadata: {
|
|
158615
159760
|
acknowledgedDuplicateIds,
|
|
@@ -158623,7 +159768,7 @@ ${normalizedDescription}`;
|
|
|
158623
159768
|
});
|
|
158624
159769
|
}
|
|
158625
159770
|
}
|
|
158626
|
-
res.status(201).json(
|
|
159771
|
+
res.status(201).json(taskWithAutoBranch);
|
|
158627
159772
|
return;
|
|
158628
159773
|
} finally {
|
|
158629
159774
|
deterministicGuard.releaseLock();
|
|
@@ -159751,7 +160896,7 @@ ${normalizedDescription}`;
|
|
|
159751
160896
|
router.patch("/tasks/:id", async (req, res) => {
|
|
159752
160897
|
try {
|
|
159753
160898
|
const { store: scopedStore } = await getProjectContext3(req);
|
|
159754
|
-
const { title, description, prompt, priority, dependencies, enabledWorkflowSteps, modelProvider, modelId, validatorModelProvider, validatorModelId, planningModelProvider, planningModelId, thinkingLevel, assigneeUserId, reviewLevel, executionMode, sourceIssue, nodeId, branch, baseBranch, githubTracking, noCommitsExpected, overlapBlockedBy, status } = req.body;
|
|
160899
|
+
const { title, description, prompt, priority, dependencies, enabledWorkflowSteps, modelProvider, modelId, validatorModelProvider, validatorModelId, planningModelProvider, planningModelId, thinkingLevel, assigneeUserId, reviewLevel, executionMode, sourceIssue, nodeId, branch, baseBranch, githubTracking, noCommitsExpected, autoMerge, overlapBlockedBy, status } = req.body;
|
|
159755
160900
|
const hasBodyField = (field) => Object.prototype.hasOwnProperty.call(req.body, field);
|
|
159756
160901
|
const validateModelField = (value, name) => {
|
|
159757
160902
|
if (value === void 0) return void 0;
|
|
@@ -159792,6 +160937,9 @@ ${normalizedDescription}`;
|
|
|
159792
160937
|
if (hasBodyField("noCommitsExpected") && noCommitsExpected !== void 0 && typeof noCommitsExpected !== "boolean") {
|
|
159793
160938
|
throw new Error("noCommitsExpected must be a boolean");
|
|
159794
160939
|
}
|
|
160940
|
+
if (hasBodyField("autoMerge") && autoMerge !== void 0 && autoMerge !== null && typeof autoMerge !== "boolean") {
|
|
160941
|
+
throw new Error("autoMerge must be a boolean");
|
|
160942
|
+
}
|
|
159795
160943
|
let validatedSourceIssue;
|
|
159796
160944
|
if (hasBodyField("sourceIssue")) {
|
|
159797
160945
|
if (sourceIssue === null) {
|
|
@@ -159913,6 +161061,7 @@ ${normalizedDescription}`;
|
|
|
159913
161061
|
if (dependencies !== void 0) updates.dependencies = dependencies;
|
|
159914
161062
|
if (enabledWorkflowSteps !== void 0) updates.enabledWorkflowSteps = enabledWorkflowSteps;
|
|
159915
161063
|
if (hasBodyField("noCommitsExpected")) updates.noCommitsExpected = noCommitsExpected;
|
|
161064
|
+
if (hasBodyField("autoMerge")) updates.autoMerge = autoMerge === null ? void 0 : autoMerge;
|
|
159916
161065
|
if (hasBodyField("modelProvider")) updates.modelProvider = validatedModelProvider;
|
|
159917
161066
|
if (hasBodyField("modelId")) updates.modelId = validatedModelId;
|
|
159918
161067
|
if (hasBodyField("validatorModelProvider")) updates.validatorModelProvider = validatedValidatorModelProvider;
|
|
@@ -198181,15 +199330,35 @@ async function resolveAuditCommitSha(taskId, scopedStore) {
|
|
|
198181
199330
|
}
|
|
198182
199331
|
return void 0;
|
|
198183
199332
|
}
|
|
198184
|
-
async function
|
|
199333
|
+
async function isAtOrBelowTaskBase(sha, baseCommitSha, rootDir) {
|
|
199334
|
+
if (sha === baseCommitSha) return true;
|
|
199335
|
+
try {
|
|
199336
|
+
await runGitCommand(["merge-base", "--is-ancestor", sha, baseCommitSha], rootDir, 5e3);
|
|
199337
|
+
return true;
|
|
199338
|
+
} catch {
|
|
199339
|
+
return false;
|
|
199340
|
+
}
|
|
199341
|
+
}
|
|
199342
|
+
async function resolveDoneTaskMergeSha(task, scopedStore, options) {
|
|
199343
|
+
const rootDir = scopedStore.getRootDir();
|
|
199344
|
+
const baseCommitSha = task.baseCommitSha?.trim();
|
|
199345
|
+
const includeBaseCommitSha = options?.includeBaseCommitSha === true;
|
|
198185
199346
|
const existing = task.mergeDetails?.commitSha?.trim();
|
|
198186
|
-
if (existing)
|
|
199347
|
+
if (existing) {
|
|
199348
|
+
if (!includeBaseCommitSha && baseCommitSha && existing === baseCommitSha) return void 0;
|
|
199349
|
+
return existing;
|
|
199350
|
+
}
|
|
198187
199351
|
const auditSha = await resolveAuditCommitSha(task.id, scopedStore);
|
|
198188
|
-
if (auditSha)
|
|
199352
|
+
if (auditSha) {
|
|
199353
|
+
if (!includeBaseCommitSha && baseCommitSha && auditSha === baseCommitSha) return void 0;
|
|
199354
|
+
return auditSha;
|
|
199355
|
+
}
|
|
198189
199356
|
if (!task.lineageId) return void 0;
|
|
198190
199357
|
const associations = await scopedStore.getTaskCommitAssociationsByLineageId(task.lineageId);
|
|
198191
199358
|
for (const association of associations) {
|
|
198192
|
-
if (association.commitSha
|
|
199359
|
+
if (!association.commitSha) continue;
|
|
199360
|
+
if (!includeBaseCommitSha && baseCommitSha && association.commitSha === baseCommitSha) continue;
|
|
199361
|
+
if (await isReachableFromHead(association.commitSha, rootDir)) {
|
|
198193
199362
|
return association.commitSha;
|
|
198194
199363
|
}
|
|
198195
199364
|
}
|
|
@@ -198408,7 +199577,15 @@ function registerSessionDiffRoutes(router, deps) {
|
|
|
198408
199577
|
return;
|
|
198409
199578
|
}
|
|
198410
199579
|
if (task.column === "done") {
|
|
199580
|
+
const mergeShaForBaseBoundary = await resolveDoneTaskMergeSha(task, scopedStore, { includeBaseCommitSha: true });
|
|
198411
199581
|
const resolvedMergeSha = await resolveDoneTaskMergeSha(task, scopedStore);
|
|
199582
|
+
if (mergeShaForBaseBoundary && task.baseCommitSha) {
|
|
199583
|
+
const atOrBelowBase = await isAtOrBelowTaskBase(mergeShaForBaseBoundary, task.baseCommitSha, scopedStore.getRootDir());
|
|
199584
|
+
if (atOrBelowBase) {
|
|
199585
|
+
res.json({ files: [], stats: { filesChanged: 0, additions: 0, deletions: 0 } });
|
|
199586
|
+
return;
|
|
199587
|
+
}
|
|
199588
|
+
}
|
|
198412
199589
|
const doneTaskForDiff = resolvedMergeSha ? {
|
|
198413
199590
|
...task,
|
|
198414
199591
|
mergeDetails: {
|
|
@@ -198619,7 +199796,15 @@ function registerSessionDiffRoutes(router, deps) {
|
|
|
198619
199796
|
return;
|
|
198620
199797
|
}
|
|
198621
199798
|
if (task.column === "done") {
|
|
199799
|
+
const mergeShaForBaseBoundary = await resolveDoneTaskMergeSha(task, scopedStore, { includeBaseCommitSha: true });
|
|
198622
199800
|
const resolvedMergeSha = await resolveDoneTaskMergeSha(task, scopedStore);
|
|
199801
|
+
if (mergeShaForBaseBoundary && task.baseCommitSha) {
|
|
199802
|
+
const atOrBelowBase = await isAtOrBelowTaskBase(mergeShaForBaseBoundary, task.baseCommitSha, scopedStore.getRootDir());
|
|
199803
|
+
if (atOrBelowBase) {
|
|
199804
|
+
res.json([]);
|
|
199805
|
+
return;
|
|
199806
|
+
}
|
|
199807
|
+
}
|
|
198623
199808
|
const doneTaskForDiff = resolvedMergeSha ? {
|
|
198624
199809
|
...task,
|
|
198625
199810
|
mergeDetails: {
|
|
@@ -215093,21 +216278,48 @@ var init_register_auth_routes = __esm({
|
|
|
215093
216278
|
let autoPromptConsumed = false;
|
|
215094
216279
|
let authResolve;
|
|
215095
216280
|
let authReject;
|
|
216281
|
+
let authSettled = false;
|
|
215096
216282
|
const authUrlPromise = new Promise((resolve64, reject2) => {
|
|
215097
216283
|
authResolve = resolve64;
|
|
215098
216284
|
authReject = reject2;
|
|
215099
216285
|
});
|
|
216286
|
+
const resolveAuthInfo = (info) => {
|
|
216287
|
+
if (authSettled) return;
|
|
216288
|
+
authSettled = true;
|
|
216289
|
+
authResolve(info);
|
|
216290
|
+
};
|
|
216291
|
+
const rejectAuthInfo = (err) => {
|
|
216292
|
+
if (authSettled) return;
|
|
216293
|
+
authSettled = true;
|
|
216294
|
+
authReject(err);
|
|
216295
|
+
};
|
|
216296
|
+
let resolvedDeviceCode;
|
|
215100
216297
|
const loginPromise = storage.login(provider, {
|
|
215101
216298
|
onAuth: (info) => {
|
|
215102
|
-
|
|
215103
|
-
|
|
215104
|
-
|
|
215105
|
-
|
|
215106
|
-
|
|
215107
|
-
|
|
216299
|
+
if (!resolvedDeviceCode) {
|
|
216300
|
+
const parsedUserCode = provider === "github-copilot" && info.instructions ? parseGitHubCopilotDeviceCode(info.instructions) : void 0;
|
|
216301
|
+
if (parsedUserCode) {
|
|
216302
|
+
resolvedDeviceCode = {
|
|
216303
|
+
userCode: parsedUserCode,
|
|
216304
|
+
verificationUri: info.url
|
|
216305
|
+
};
|
|
216306
|
+
}
|
|
216307
|
+
}
|
|
216308
|
+
resolveAuthInfo({
|
|
215108
216309
|
url: info.url,
|
|
215109
216310
|
instructions: appendManualCodeHint(info.instructions, provider, origin),
|
|
215110
|
-
deviceCode
|
|
216311
|
+
deviceCode: resolvedDeviceCode
|
|
216312
|
+
});
|
|
216313
|
+
},
|
|
216314
|
+
onDeviceCode: (info) => {
|
|
216315
|
+
resolvedDeviceCode = {
|
|
216316
|
+
userCode: info.userCode,
|
|
216317
|
+
verificationUri: info.verificationUri
|
|
216318
|
+
};
|
|
216319
|
+
resolveAuthInfo({
|
|
216320
|
+
url: info.verificationUri,
|
|
216321
|
+
instructions: appendManualCodeHint(void 0, provider, origin),
|
|
216322
|
+
deviceCode: resolvedDeviceCode
|
|
215111
216323
|
});
|
|
215112
216324
|
},
|
|
215113
216325
|
onPrompt: async (_prompt) => {
|
|
@@ -215124,14 +216336,20 @@ var init_register_auth_routes = __esm({
|
|
|
215124
216336
|
onProgress: () => {
|
|
215125
216337
|
},
|
|
215126
216338
|
// no-op for web UI
|
|
216339
|
+
onSelect: async (prompt) => {
|
|
216340
|
+
if (prompt.options.length === 1) {
|
|
216341
|
+
return prompt.options[0]?.id;
|
|
216342
|
+
}
|
|
216343
|
+
return void 0;
|
|
216344
|
+
},
|
|
215127
216345
|
signal: abortController.signal
|
|
215128
216346
|
});
|
|
215129
216347
|
const timeout2 = setTimeout(() => {
|
|
215130
|
-
|
|
216348
|
+
rejectAuthInfo(new Error("Login initiation timed out"));
|
|
215131
216349
|
}, 3e4);
|
|
215132
216350
|
loginPromise.then(() => {
|
|
215133
216351
|
}).catch((err) => {
|
|
215134
|
-
|
|
216352
|
+
rejectAuthInfo(err instanceof Error ? err : new Error(String(err)));
|
|
215135
216353
|
}).finally(() => {
|
|
215136
216354
|
clearTimeout(timeout2);
|
|
215137
216355
|
loginInProgress.delete(provider);
|
|
@@ -216048,6 +217266,32 @@ function validateBoolean(value, fieldName) {
|
|
|
216048
217266
|
}
|
|
216049
217267
|
return value;
|
|
216050
217268
|
}
|
|
217269
|
+
function validateMissionBranchStrategy(value) {
|
|
217270
|
+
if (value === void 0 || value === null) return void 0;
|
|
217271
|
+
if (typeof value !== "object") {
|
|
217272
|
+
throw new Error("branchStrategy must be an object");
|
|
217273
|
+
}
|
|
217274
|
+
const input = value;
|
|
217275
|
+
const mode = input.mode;
|
|
217276
|
+
if (mode !== "project-default" && mode !== "existing" && mode !== "custom-new" && mode !== "auto-per-task") {
|
|
217277
|
+
throw new Error("branchStrategy.mode must be one of: project-default, existing, custom-new, auto-per-task");
|
|
217278
|
+
}
|
|
217279
|
+
const branchName = input.branchName;
|
|
217280
|
+
if (branchName !== void 0 && typeof branchName !== "string") {
|
|
217281
|
+
throw new Error("branchStrategy.branchName must be a string when provided");
|
|
217282
|
+
}
|
|
217283
|
+
const trimmedBranchName = branchName?.trim();
|
|
217284
|
+
if ((mode === "existing" || mode === "custom-new") && !trimmedBranchName) {
|
|
217285
|
+
throw new Error("branchStrategy.branchName is required for existing/custom-new");
|
|
217286
|
+
}
|
|
217287
|
+
if (mode === "project-default" || mode === "auto-per-task") {
|
|
217288
|
+
return { mode };
|
|
217289
|
+
}
|
|
217290
|
+
return {
|
|
217291
|
+
mode,
|
|
217292
|
+
branchName: trimmedBranchName
|
|
217293
|
+
};
|
|
217294
|
+
}
|
|
216051
217295
|
function validateOrderedIds(body) {
|
|
216052
217296
|
if (!body || typeof body !== "object") {
|
|
216053
217297
|
throw new Error("Request body must contain orderedIds array");
|
|
@@ -216147,27 +217391,22 @@ function createMissionRouter(store, missionAutopilot, aiSessionStore, missionExe
|
|
|
216147
217391
|
router.post(
|
|
216148
217392
|
"/",
|
|
216149
217393
|
catchTypedHandler(async (req, res) => {
|
|
216150
|
-
const { title, description, autoAdvance,
|
|
217394
|
+
const { title, description, autoAdvance, baseBranch, branchStrategy } = req.body;
|
|
216151
217395
|
const validatedTitle = validateTitle(title);
|
|
216152
217396
|
const validatedDescription = validateDescription2(description);
|
|
216153
217397
|
const input = {
|
|
216154
217398
|
title: validatedTitle,
|
|
216155
217399
|
description: validatedDescription,
|
|
216156
|
-
baseBranch: validateDescription2(baseBranch)
|
|
217400
|
+
baseBranch: validateDescription2(baseBranch),
|
|
217401
|
+
branchStrategy: validateMissionBranchStrategy(branchStrategy)
|
|
216157
217402
|
};
|
|
216158
217403
|
const mission = missionStore.createMission(input);
|
|
216159
217404
|
const updates = {};
|
|
216160
217405
|
if (autoAdvance !== void 0) {
|
|
216161
217406
|
updates.autoAdvance = validateBoolean(autoAdvance, "autoAdvance");
|
|
216162
217407
|
}
|
|
216163
|
-
if (autopilotEnabled !== void 0) {
|
|
216164
|
-
updates.autopilotEnabled = validateBoolean(autopilotEnabled, "autopilotEnabled");
|
|
216165
|
-
}
|
|
216166
217408
|
if (Object.keys(updates).length > 0) {
|
|
216167
217409
|
const updatedMission = missionStore.updateMission(mission.id, updates);
|
|
216168
|
-
if (missionAutopilot && updatedMission.autopilotEnabled) {
|
|
216169
|
-
missionAutopilot.watchMission(updatedMission.id);
|
|
216170
|
-
}
|
|
216171
217410
|
res.status(201).json(updatedMission);
|
|
216172
217411
|
return;
|
|
216173
217412
|
}
|
|
@@ -216512,18 +217751,11 @@ function createMissionRouter(store, missionAutopilot, aiSessionStore, missionExe
|
|
|
216512
217751
|
status: "pending"
|
|
216513
217752
|
});
|
|
216514
217753
|
for (const featureData of sliceData.features ?? []) {
|
|
216515
|
-
|
|
217754
|
+
missionStore.addFeature(slice.id, {
|
|
216516
217755
|
title: featureData.title,
|
|
216517
217756
|
description: featureData.description,
|
|
216518
217757
|
acceptanceCriteria: featureData.acceptanceCriteria
|
|
216519
217758
|
});
|
|
216520
|
-
const assertionText = featureData.acceptanceCriteria || featureData.description || `Verify implementation of: ${featureData.title}`;
|
|
216521
|
-
const assertion = missionStore.addContractAssertion(milestone.id, {
|
|
216522
|
-
title: featureData.title,
|
|
216523
|
-
assertion: assertionText,
|
|
216524
|
-
status: "pending"
|
|
216525
|
-
});
|
|
216526
|
-
missionStore.linkFeatureToAssertion(feature.id, assertion.id);
|
|
216527
217759
|
}
|
|
216528
217760
|
}
|
|
216529
217761
|
missionStore.applyDerivedMilestoneAcceptanceCriteria(milestone.id);
|
|
@@ -216563,7 +217795,7 @@ function createMissionRouter(store, missionAutopilot, aiSessionStore, missionExe
|
|
|
216563
217795
|
"/:missionId",
|
|
216564
217796
|
catchTypedHandler(async (req, res) => {
|
|
216565
217797
|
const { missionId } = req.params;
|
|
216566
|
-
const { title, description, status, autoAdvance, autopilotEnabled, baseBranch } = req.body;
|
|
217798
|
+
const { title, description, status, autoAdvance, autopilotEnabled, baseBranch, branchStrategy } = req.body;
|
|
216567
217799
|
if (!validateMissionId(missionId)) {
|
|
216568
217800
|
throw badRequest("Invalid mission ID format");
|
|
216569
217801
|
}
|
|
@@ -216586,6 +217818,9 @@ function createMissionRouter(store, missionAutopilot, aiSessionStore, missionExe
|
|
|
216586
217818
|
if (baseBranch !== void 0) {
|
|
216587
217819
|
updates.baseBranch = validateDescription2(baseBranch);
|
|
216588
217820
|
}
|
|
217821
|
+
if (branchStrategy !== void 0) {
|
|
217822
|
+
updates.branchStrategy = validateMissionBranchStrategy(branchStrategy);
|
|
217823
|
+
}
|
|
216589
217824
|
if (Object.keys(updates).length === 0) {
|
|
216590
217825
|
throw badRequest("No valid fields to update");
|
|
216591
217826
|
}
|
|
@@ -248278,6 +249513,7 @@ var init_mission = __esm({
|
|
|
248278
249513
|
var goals_exports = {};
|
|
248279
249514
|
__export(goals_exports, {
|
|
248280
249515
|
runGoalsArchive: () => runGoalsArchive,
|
|
249516
|
+
runGoalsCitations: () => runGoalsCitations,
|
|
248281
249517
|
runGoalsCreate: () => runGoalsCreate,
|
|
248282
249518
|
runGoalsList: () => runGoalsList
|
|
248283
249519
|
});
|
|
@@ -248356,6 +249592,31 @@ async function runGoalsCreate(titleArg, descriptionArg, projectName) {
|
|
|
248356
249592
|
throw error;
|
|
248357
249593
|
}
|
|
248358
249594
|
}
|
|
249595
|
+
async function runGoalsCitations(projectName, opts) {
|
|
249596
|
+
const store = await getStore2({ project: projectName });
|
|
249597
|
+
const rows = store.listGoalCitations({
|
|
249598
|
+
goalId: opts.goalId,
|
|
249599
|
+
agentId: opts.agentId,
|
|
249600
|
+
surface: opts.surface,
|
|
249601
|
+
startTime: opts.since,
|
|
249602
|
+
endTime: opts.until,
|
|
249603
|
+
limit: opts.limit ?? 50
|
|
249604
|
+
});
|
|
249605
|
+
if (opts.json) {
|
|
249606
|
+
console.log(JSON.stringify(rows, null, 2));
|
|
249607
|
+
return;
|
|
249608
|
+
}
|
|
249609
|
+
if (rows.length === 0) {
|
|
249610
|
+
console.log("No goal citations match the filter.");
|
|
249611
|
+
return;
|
|
249612
|
+
}
|
|
249613
|
+
for (const row of rows) {
|
|
249614
|
+
console.log(`${row.timestamp} ${row.goalId} ${row.agentId} ${row.surface} ${row.sourceRef}`);
|
|
249615
|
+
console.log(` ${row.snippet}`);
|
|
249616
|
+
}
|
|
249617
|
+
console.log(`
|
|
249618
|
+
${rows.length} citation(s).`);
|
|
249619
|
+
}
|
|
248359
249620
|
async function runGoalsArchive(idArg, projectName) {
|
|
248360
249621
|
if (!idArg) {
|
|
248361
249622
|
console.error("Usage: fn goals archive <id>");
|
|
@@ -251586,7 +252847,7 @@ async function loadCommandHandlers() {
|
|
|
251586
252847
|
const { runBackupCreate: runBackupCreate2, runBackupList: runBackupList2, runBackupRestore: runBackupRestore2, runBackupCleanup: runBackupCleanup2 } = await Promise.resolve().then(() => (init_backup2(), backup_exports));
|
|
251587
252848
|
const { runMemoryBackupCreate: runMemoryBackupCreate2, runMemoryBackupList: runMemoryBackupList2, runMemoryBackupRestore: runMemoryBackupRestore2 } = await Promise.resolve().then(() => (init_memory_backup2(), memory_backup_exports));
|
|
251588
252849
|
const { runMissionCreate: runMissionCreate2, runMissionList: runMissionList2, runMissionShow: runMissionShow2, runMissionDelete: runMissionDelete2, runMissionActivateSlice: runMissionActivateSlice2 } = await Promise.resolve().then(() => (init_mission(), mission_exports));
|
|
251589
|
-
const { runGoalsList: runGoalsList2, runGoalsCreate: runGoalsCreate2, runGoalsArchive: runGoalsArchive2 } = await Promise.resolve().then(() => (init_goals(), goals_exports));
|
|
252850
|
+
const { runGoalsList: runGoalsList2, runGoalsCreate: runGoalsCreate2, runGoalsArchive: runGoalsArchive2, runGoalsCitations: runGoalsCitations2 } = await Promise.resolve().then(() => (init_goals(), goals_exports));
|
|
251590
252851
|
const { runProjectList: runProjectList2, runProjectAdd: runProjectAdd2, runProjectRemove: runProjectRemove2, runProjectShow: runProjectShow2, runProjectInfo: runProjectInfo2, runProjectSetDefault: runProjectSetDefault2, runProjectDetect: runProjectDetect2 } = await Promise.resolve().then(() => (init_project(), project_exports));
|
|
251591
252852
|
const { runNodeList: runNodeList2, runNodeConnect: runNodeConnect2, runNodeDisconnect: runNodeDisconnect2, runNodeShow: runNodeShow2, runNodeHealth: runNodeHealth2, runMeshStatus: runMeshStatus2 } = await Promise.resolve().then(() => (init_node(), node_exports));
|
|
251592
252853
|
const { runInit: runInit2 } = await Promise.resolve().then(() => (init_init(), init_exports));
|
|
@@ -251654,6 +252915,7 @@ async function loadCommandHandlers() {
|
|
|
251654
252915
|
runGoalsList: runGoalsList2,
|
|
251655
252916
|
runGoalsCreate: runGoalsCreate2,
|
|
251656
252917
|
runGoalsArchive: runGoalsArchive2,
|
|
252918
|
+
runGoalsCitations: runGoalsCitations2,
|
|
251657
252919
|
runProjectList: runProjectList2,
|
|
251658
252920
|
runProjectAdd: runProjectAdd2,
|
|
251659
252921
|
runProjectRemove: runProjectRemove2,
|
|
@@ -251773,6 +253035,7 @@ PR:
|
|
|
251773
253035
|
fn goals list [--status STATE] List goals (default: active)
|
|
251774
253036
|
fn goals create [title] [desc] Create a new goal
|
|
251775
253037
|
fn goals archive <id> Archive a goal
|
|
253038
|
+
fn goals citations [flags] List recorded goal-ID citations across agent logs and task documents (Slice 2 success signal)
|
|
251776
253039
|
fn project list | ls [--json] List all registered projects
|
|
251777
253040
|
fn project add [name] [path] [opts] Register a new project
|
|
251778
253041
|
fn project remove | rm <name> [--force]
|
|
@@ -252025,6 +253288,7 @@ async function main() {
|
|
|
252025
253288
|
runGoalsList: runGoalsList2,
|
|
252026
253289
|
runGoalsCreate: runGoalsCreate2,
|
|
252027
253290
|
runGoalsArchive: runGoalsArchive2,
|
|
253291
|
+
runGoalsCitations: runGoalsCitations2,
|
|
252028
253292
|
runProjectList: runProjectList2,
|
|
252029
253293
|
runProjectAdd: runProjectAdd2,
|
|
252030
253294
|
runProjectRemove: runProjectRemove2,
|
|
@@ -252790,9 +254054,21 @@ async function main() {
|
|
|
252790
254054
|
await runGoalsArchive2(id, projectName);
|
|
252791
254055
|
break;
|
|
252792
254056
|
}
|
|
254057
|
+
case "citations": {
|
|
254058
|
+
const goalId = getFlagValue(args, "--goal");
|
|
254059
|
+
const agentId = getFlagValue(args, "--agent");
|
|
254060
|
+
const surface = getFlagValue(args, "--surface");
|
|
254061
|
+
const since = getFlagValue(args, "--since");
|
|
254062
|
+
const until2 = getFlagValue(args, "--until");
|
|
254063
|
+
const limitValue = getFlagValue(args, "--limit");
|
|
254064
|
+
const limit = limitValue ? Number(limitValue) : void 0;
|
|
254065
|
+
const json = args.includes("--json");
|
|
254066
|
+
await runGoalsCitations2(projectName, { goalId, agentId, surface, since, until: until2, limit, json });
|
|
254067
|
+
break;
|
|
254068
|
+
}
|
|
252793
254069
|
default:
|
|
252794
254070
|
console.error(`Unknown subcommand: goals ${subcommand || ""}`);
|
|
252795
|
-
console.log("Try: fn goals list | create | archive");
|
|
254071
|
+
console.log("Try: fn goals list | create | archive | citations");
|
|
252796
254072
|
process.exit(1);
|
|
252797
254073
|
}
|
|
252798
254074
|
break;
|