@runfusion/fusion 0.36.0 → 0.38.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin.js +1599 -174
- package/dist/client/.vite/manifest.json +66 -66
- package/dist/client/assets/AgentDetailView-CquLtIia.js +18 -0
- package/dist/client/assets/{AgentPermissionPolicyEditor-BoD6come.js → AgentPermissionPolicyEditor-Dk-oEs1X.js} +1 -1
- package/dist/client/assets/AgentsView-BZVOpQ05.js +29 -0
- package/dist/client/assets/ChatView-CErtz86Y.js +6 -0
- package/dist/client/assets/{DevServerView-Dd613aZ5.js → DevServerView-BRA00XoT.js} +1 -1
- package/dist/client/assets/{DirectoryPicker-H-fUl2dF.js → DirectoryPicker-D496NTjZ.js} +1 -1
- package/dist/client/assets/{DocumentsView-Dshc9e5K.js → DocumentsView-DIRlgdeB.js} +1 -1
- package/dist/client/assets/{EvalsView-50W0K5h7.js → EvalsView-By5mtr80.js} +1 -1
- package/dist/client/assets/{ExperimentalAgentOnboardingModal-BXBljPFj.js → ExperimentalAgentOnboardingModal-Br57oNdX.js} +1 -1
- package/dist/client/assets/GoalsView-B65urz9k.css +1 -0
- package/dist/client/assets/GoalsView-COI14CWJ.js +1 -0
- package/dist/client/assets/{InsightsView-sVbGRKTl.js → InsightsView-Hm7vX2lr.js} +2 -2
- package/dist/client/assets/{MemoryView-006a_sB0.js → MemoryView-BLozyYur.js} +1 -1
- package/dist/client/assets/{NodesView-CiRPqgVx.js → NodesView-bXC6WoE2.js} +1 -1
- package/dist/client/assets/{PiExtensionsManager-Y1ETuTxf.js → PiExtensionsManager-DEiqcMkx.js} +2 -2
- package/dist/client/assets/{PluginManager-Df_KHiXn.js → PluginManager-l4224zxk.js} +1 -1
- package/dist/client/assets/{ResearchView-DU_QuS_-.js → ResearchView-CpsR1Q56.js} +1 -1
- package/dist/client/assets/{SecretsView-D61Jvysn.js → SecretsView-Bwme1zZI.js} +1 -1
- package/dist/client/assets/{SettingsModal-BarzmqNb.js → SettingsModal-32vUNWRe.js} +1 -1
- package/dist/client/assets/SettingsModal-D_uIvf6n.css +1 -0
- package/dist/client/assets/SettingsModal-DdrXxMPW.js +31 -0
- package/dist/client/assets/{SetupWizardModal-BF3iRNq9.js → SetupWizardModal-BFD9E0H_.js} +1 -1
- package/dist/client/assets/{SkillsView-tCKOFw3j.js → SkillsView-CZMLY7F_.js} +1 -1
- package/dist/client/assets/{StashRecoveryView-nGtypd10.js → StashRecoveryView-jgZeWbZo.js} +1 -1
- package/dist/client/assets/{TodoView-IyGPV6AO.js → TodoView-DXdnOymj.js} +2 -2
- package/dist/client/assets/{dashboard-view-DiA5-hnb.js → dashboard-view-H8SnaCPP.js} +2 -2
- package/dist/client/assets/{folder-open-Byqfi_N-.js → folder-open-Dh5_gv6L.js} +1 -1
- package/dist/client/assets/index-B9hAW3eU.css +1 -0
- package/dist/client/assets/index-w1dPHtmq.js +742 -0
- package/dist/client/assets/{upload-D6_BjqVi.js → upload-ntU2YHPl.js} +1 -1
- package/dist/client/assets/{users-CERYgInO.js → users-BWK61s9U.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 +1449 -125
- 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/skill/fusion/SKILL.md +1 -1
- package/skill/fusion/references/extension-tools.md +16 -0
- package/skill/fusion/references/fusion-capabilities.md +1 -0
- package/dist/client/assets/AgentDetailView-CGycokdR.js +0 -18
- package/dist/client/assets/AgentsView-B_afRRfc.js +0 -29
- package/dist/client/assets/ChatView-IjNrSZSf.js +0 -6
- package/dist/client/assets/GoalsView-Cg136Jcn.css +0 -1
- package/dist/client/assets/GoalsView-Dh508Z2s.js +0 -1
- package/dist/client/assets/SettingsModal-0gevFhXV.css +0 -1
- package/dist/client/assets/SettingsModal-Cpur3WpT.js +0 -31
- package/dist/client/assets/index-B9Ro_NwC.js +0 -742
- package/dist/client/assets/index-DVFBXjGT.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();
|
|
@@ -71754,6 +72444,8 @@ var init_gating_classifications = __esm({
|
|
|
71754
72444
|
"fn_insight_show",
|
|
71755
72445
|
"fn_insight_run_list",
|
|
71756
72446
|
"fn_insight_run_show",
|
|
72447
|
+
"fn_goal_list",
|
|
72448
|
+
"fn_goal_show",
|
|
71757
72449
|
"fn_mission_list",
|
|
71758
72450
|
"fn_mission_show",
|
|
71759
72451
|
"fn_list_agents",
|
|
@@ -79794,12 +80486,16 @@ var init_agent_instructions = __esm({
|
|
|
79794
80486
|
|
|
79795
80487
|
// ../engine/src/prompt-layers.ts
|
|
79796
80488
|
function buildPromptLayers(input) {
|
|
79797
|
-
const { basePrompt, agentInstructions, memorySection, pluginContributions, performanceFeedback } = input;
|
|
80489
|
+
const { basePrompt, agentInstructions, memorySection, goalContext, pluginContributions, performanceFeedback } = input;
|
|
79798
80490
|
const dynamicParts = [];
|
|
79799
80491
|
const trimmedMemory = memorySection?.trim() ?? "";
|
|
79800
80492
|
if (trimmedMemory) {
|
|
79801
80493
|
dynamicParts.push(trimmedMemory);
|
|
79802
80494
|
}
|
|
80495
|
+
const trimmedGoalContext = goalContext?.trim() ?? "";
|
|
80496
|
+
if (trimmedGoalContext) {
|
|
80497
|
+
dynamicParts.push(trimmedGoalContext);
|
|
80498
|
+
}
|
|
79803
80499
|
const trimmedInstructions = agentInstructions?.trim() ?? "";
|
|
79804
80500
|
if (trimmedInstructions) {
|
|
79805
80501
|
dynamicParts.push(`## Custom Instructions
|
|
@@ -85127,7 +85823,7 @@ function isInsideWorktreesDir(rootDir, worktreePath, settings) {
|
|
|
85127
85823
|
return isInsideConfiguredWorktreesDir(rootDir, settings, worktreePath);
|
|
85128
85824
|
}
|
|
85129
85825
|
function deriveTaskIdFromBranch(branchName) {
|
|
85130
|
-
const match = branchName.match(/^fusion\/(fn-\d+)(?:-\d+)
|
|
85826
|
+
const match = branchName.match(/^fusion\/(fn-\d+)(?:-\d+)?(?:-[a-z0-9._-]+)*$/i);
|
|
85131
85827
|
return match ? match[1].toUpperCase() : branchName.toUpperCase();
|
|
85132
85828
|
}
|
|
85133
85829
|
async function scanIdleWorktrees(rootDir, store, settings) {
|
|
@@ -92596,6 +93292,7 @@ __export(merger_exports, {
|
|
|
92596
93292
|
VERIFICATION_LOG_MAX_CHARS: () => VERIFICATION_LOG_MAX_CHARS,
|
|
92597
93293
|
VerificationError: () => VerificationError,
|
|
92598
93294
|
__executePostMergeScriptStepForTests: () => __executePostMergeScriptStepForTests,
|
|
93295
|
+
__testOnlyBuildDeterministicMergeMessage: () => buildDeterministicMergeMessage,
|
|
92599
93296
|
__test__: () => __test__,
|
|
92600
93297
|
aiMergeTask: () => aiMergeTask,
|
|
92601
93298
|
applyAutostashBySha: () => applyAutostashBySha,
|
|
@@ -95331,7 +96028,7 @@ async function filterStagedGitignoredPaths(rootDir, taskId) {
|
|
|
95331
96028
|
return { unstaged: [], remainingStaged };
|
|
95332
96029
|
}
|
|
95333
96030
|
}
|
|
95334
|
-
async function commitOrAmendMergeWithFixes(rootDir, taskId, branch, commitLog, includeTaskId, preAttemptHeadSha, authorArg, diffStat, settings, signal, aiSummary, aiSubject, fixModifiedFiles = /* @__PURE__ */ new Set(), store, auditor) {
|
|
96031
|
+
async function commitOrAmendMergeWithFixes(rootDir, taskId, branch, commitLog, includeTaskId, preAttemptHeadSha, authorArg, diffStat, settings, signal, aiSummary, aiBody, aiSubject, fixModifiedFiles = /* @__PURE__ */ new Set(), store, auditor) {
|
|
95335
96032
|
try {
|
|
95336
96033
|
const { stdout: squashStagedOut } = await execAsync26("git diff --cached --name-only", {
|
|
95337
96034
|
cwd: rootDir,
|
|
@@ -95631,7 +96328,7 @@ ${msg}`;
|
|
|
95631
96328
|
diffStat: messageDiffStat,
|
|
95632
96329
|
includeTaskId,
|
|
95633
96330
|
aiSummary,
|
|
95634
|
-
aiBody
|
|
96331
|
+
aiBody,
|
|
95635
96332
|
aiSubject
|
|
95636
96333
|
});
|
|
95637
96334
|
let lineageId;
|
|
@@ -99063,6 +99760,7 @@ async function aiMergeTask(store, rootDir, taskId, options = {}) {
|
|
|
99063
99760
|
settings,
|
|
99064
99761
|
options.signal,
|
|
99065
99762
|
aiMergeSummary,
|
|
99763
|
+
aiMergeBody,
|
|
99066
99764
|
aiMergeSubject,
|
|
99067
99765
|
verificationFixModifiedFiles,
|
|
99068
99766
|
store,
|
|
@@ -99194,6 +99892,7 @@ async function aiMergeTask(store, rootDir, taskId, options = {}) {
|
|
|
99194
99892
|
settings,
|
|
99195
99893
|
options.signal,
|
|
99196
99894
|
aiMergeSummary,
|
|
99895
|
+
aiMergeBody,
|
|
99197
99896
|
aiMergeSubject,
|
|
99198
99897
|
buildFixModifiedFiles,
|
|
99199
99898
|
store,
|
|
@@ -100108,6 +100807,7 @@ async function executeMergeAttempt(params, aiTracker) {
|
|
|
100108
100807
|
diffStat,
|
|
100109
100808
|
includeTaskId,
|
|
100110
100809
|
aiSummary: safeBody,
|
|
100810
|
+
aiBody: aiBody?.trim().length ? aiBody : safeBody,
|
|
100111
100811
|
aiSubject
|
|
100112
100812
|
});
|
|
100113
100813
|
await enforceSquashFileScopeInvariant({
|
|
@@ -100302,6 +101002,7 @@ async function executeMergeAttempt(params, aiTracker) {
|
|
|
100302
101002
|
diffStat: actualContext.diffStat || diffStat,
|
|
100303
101003
|
includeTaskId,
|
|
100304
101004
|
aiSummary,
|
|
101005
|
+
aiBody,
|
|
100305
101006
|
aiSubject
|
|
100306
101007
|
});
|
|
100307
101008
|
const trailerArg = buildTaskTrailerArgs(taskId);
|
|
@@ -101330,6 +102031,12 @@ async function classifyOwnedLandedEvidenceForSelfHealing(rootDir, task, mergeTar
|
|
|
101330
102031
|
const { classifyOwnedLandedEvidence: classifyOwnedLandedEvidence2 } = await Promise.resolve().then(() => (init_merger(), merger_exports));
|
|
101331
102032
|
return classifyOwnedLandedEvidence2(rootDir, task, { mergeTargetBranch });
|
|
101332
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
|
+
}
|
|
101333
102040
|
function formatRecoveryTimestamp(date = /* @__PURE__ */ new Date()) {
|
|
101334
102041
|
const pad = (value) => String(value).padStart(2, "0");
|
|
101335
102042
|
return `${date.getUTCFullYear()}${pad(date.getUTCMonth() + 1)}${pad(date.getUTCDate())}-${pad(date.getUTCHours())}${pad(date.getUTCMinutes())}${pad(date.getUTCSeconds())}`;
|
|
@@ -101544,7 +102251,7 @@ function isNoTaskDoneFailure2(task) {
|
|
|
101544
102251
|
function hasStepProgress2(task) {
|
|
101545
102252
|
return task.steps.some((step) => step.status !== "pending");
|
|
101546
102253
|
}
|
|
101547
|
-
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;
|
|
101548
102255
|
var init_self_healing = __esm({
|
|
101549
102256
|
"../engine/src/self-healing.ts"() {
|
|
101550
102257
|
"use strict";
|
|
@@ -101577,6 +102284,7 @@ var init_self_healing = __esm({
|
|
|
101577
102284
|
STALE_ACTIVE_BRANCH_EXECUTION_GRACE_MS = 10 * 6e4;
|
|
101578
102285
|
COMPLETION_HANDOFF_LIMBO_GRACE_MS = 5 * 6e4;
|
|
101579
102286
|
MAX_COMPLETION_HANDOFF_LIMBO_RECOVERIES = 3;
|
|
102287
|
+
MAX_NO_PROGRESS_RESUME_ATTEMPTS = 2;
|
|
101580
102288
|
APPROVED_TRIAGE_RECOVERY_GRACE_MS = 6e4;
|
|
101581
102289
|
STARVED_REFINEMENT_RECOVERY_GRACE_MS = 10 * 6e4;
|
|
101582
102290
|
STARVED_PEER_PROGRESS_THRESHOLD = 3;
|
|
@@ -103093,13 +103801,71 @@ var init_self_healing = __esm({
|
|
|
103093
103801
|
}
|
|
103094
103802
|
}
|
|
103095
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
|
+
}
|
|
103096
103859
|
await this.store.updateTask(task.id, {
|
|
103097
103860
|
worktree: inspection.livePath,
|
|
103098
103861
|
branch: task.branch,
|
|
103099
103862
|
paused: false,
|
|
103100
103863
|
pausedReason: void 0,
|
|
103101
103864
|
status: null,
|
|
103102
|
-
error: null
|
|
103865
|
+
error: null,
|
|
103866
|
+
resumeLimboCount: resumeAttemptCount,
|
|
103867
|
+
resumeLimboTipSha: inspection.tipSha,
|
|
103868
|
+
resumeLimboStepSignature: stepSignature
|
|
103103
103869
|
});
|
|
103104
103870
|
await this.store.logEntry(
|
|
103105
103871
|
task.id,
|
|
@@ -104331,7 +105097,7 @@ var init_self_healing = __esm({
|
|
|
104331
105097
|
const blockerId = task.blockedBy;
|
|
104332
105098
|
const unresolvedDeps = task.dependencies.filter((depId) => {
|
|
104333
105099
|
const dep = taskById.get(depId);
|
|
104334
|
-
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";
|
|
104335
105101
|
});
|
|
104336
105102
|
const overlapBlocker = task.overlapBlockedBy ? taskById.get(task.overlapBlockedBy) : void 0;
|
|
104337
105103
|
const hasActiveOverlapBlocker = Boolean(
|
|
@@ -104357,6 +105123,9 @@ var init_self_healing = __esm({
|
|
|
104357
105123
|
reasonCode = "missing-blocker";
|
|
104358
105124
|
reason = `blocker ${blockerId} missing`;
|
|
104359
105125
|
}
|
|
105126
|
+
} else if (blocker.deletedAt) {
|
|
105127
|
+
reasonCode = "soft-deleted-blocker";
|
|
105128
|
+
reason = `blocker ${blockerId} soft-deleted at ${blocker.deletedAt}`;
|
|
104360
105129
|
} else if (blocker.column === "done") {
|
|
104361
105130
|
reasonCode = "blocker-done";
|
|
104362
105131
|
reason = `blocker ${blockerId} is done`;
|
|
@@ -105886,6 +106655,12 @@ var init_self_healing = __esm({
|
|
|
105886
106655
|
try {
|
|
105887
106656
|
const hardBlocker = getTaskHardMergeBlocker({
|
|
105888
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,
|
|
105889
106664
|
steps: task.steps ?? [],
|
|
105890
106665
|
workflowStepResults: task.workflowStepResults
|
|
105891
106666
|
});
|
|
@@ -110517,6 +111292,258 @@ var init_token_cap_detector = __esm({
|
|
|
110517
111292
|
}
|
|
110518
111293
|
});
|
|
110519
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
|
+
|
|
110520
111547
|
// ../engine/src/auto-recovery-handlers/branch-worktree.ts
|
|
110521
111548
|
import { exec as exec31 } from "node:child_process";
|
|
110522
111549
|
import { existsSync as existsSync39 } from "node:fs";
|
|
@@ -111381,7 +112408,7 @@ function isTransientMissingTaskJsonError(error, task) {
|
|
|
111381
112408
|
const normalizedTaskJsonPath = resolvePath(filePath);
|
|
111382
112409
|
return normalizedTaskJsonPath.startsWith(`${normalizedWorktree}/`);
|
|
111383
112410
|
}
|
|
111384
|
-
function detectPendingReviewBlock(task,
|
|
112411
|
+
function detectPendingReviewBlock(task, _codeReviewVerdicts) {
|
|
111385
112412
|
const inProgressStepIndices = [];
|
|
111386
112413
|
for (let stepIndex = 0; stepIndex < task.steps.length; stepIndex++) {
|
|
111387
112414
|
if (task.steps[stepIndex]?.status === "in-progress") {
|
|
@@ -111393,9 +112420,6 @@ function detectPendingReviewBlock(task, codeReviewVerdicts) {
|
|
|
111393
112420
|
}
|
|
111394
112421
|
const recentActions = (task.log ?? []).slice(-30).map((entry) => entry.action?.trim()).filter((action) => Boolean(action));
|
|
111395
112422
|
for (const stepIndex of inProgressStepIndices) {
|
|
111396
|
-
if (codeReviewVerdicts.get(stepIndex) === "REVISE") {
|
|
111397
|
-
return { blocked: true, reason: "code-review-revise-outstanding", stepIndex };
|
|
111398
|
-
}
|
|
111399
112423
|
const stepDisplay = stepIndex + 1;
|
|
111400
112424
|
const codeRequest = `code review requested for Step ${stepDisplay}`;
|
|
111401
112425
|
const planRequest = `plan review requested for Step ${stepDisplay}`;
|
|
@@ -111956,6 +112980,8 @@ var init_executor = __esm({
|
|
|
111956
112980
|
init_worktree_hooks();
|
|
111957
112981
|
init_agent_instructions();
|
|
111958
112982
|
init_prompt_layers();
|
|
112983
|
+
init_goal_injection_diagnostics();
|
|
112984
|
+
init_goal_anchoring_audit();
|
|
111959
112985
|
init_run_audit();
|
|
111960
112986
|
init_auto_recovery();
|
|
111961
112987
|
init_restart_recovery_coordinator();
|
|
@@ -112342,6 +113368,11 @@ The tool prevents your session from being killed by the inactivity watchdog duri
|
|
|
112342
113368
|
executorLog.log(`Unpaused ${task.id} in-progress with no session \u2014 resuming execution`);
|
|
112343
113369
|
try {
|
|
112344
113370
|
await this.clearResumeFailureState(task);
|
|
113371
|
+
await this.store.updateTask(task.id, {
|
|
113372
|
+
resumeLimboCount: 0,
|
|
113373
|
+
resumeLimboTipSha: null,
|
|
113374
|
+
resumeLimboStepSignature: null
|
|
113375
|
+
});
|
|
112345
113376
|
await this.store.logEntry(task.id, "Resuming execution after unpause", void 0, this.getRunContextFor(task.id));
|
|
112346
113377
|
await this.recoverApprovedStepsOnResume(task.id);
|
|
112347
113378
|
} catch (clearErr) {
|
|
@@ -114717,8 +115748,30 @@ ${summary}`,
|
|
|
114717
115748
|
if (executorPluginContributions) {
|
|
114718
115749
|
executorLog.log(`${task.id}: applied plugin prompt contributions for executor-system surface`);
|
|
114719
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
|
+
});
|
|
114720
115772
|
const executorLayers = buildPromptLayers({
|
|
114721
115773
|
basePrompt: getExecutorSystemPrompt(settings),
|
|
115774
|
+
goalContext: executorGoalContext,
|
|
114722
115775
|
agentInstructions: executorInstructions,
|
|
114723
115776
|
pluginContributions: executorPluginContributions
|
|
114724
115777
|
});
|
|
@@ -115035,12 +116088,7 @@ ${summary}`,
|
|
|
115035
116088
|
this.tokenUsageBaselines.delete(task.id);
|
|
115036
116089
|
session.dispose();
|
|
115037
116090
|
await this.persistTokenUsage(task.id);
|
|
115038
|
-
await this.store.updateTask(task.id, {
|
|
115039
|
-
status: "failed",
|
|
115040
|
-
error: "executor-exit-while-review-pending"
|
|
115041
|
-
});
|
|
115042
116091
|
await this.handoffTaskToReview(task, "executor-exit-while-review-pending");
|
|
115043
|
-
this.options.onError?.(task, new Error("executor-exit-while-review-pending"));
|
|
115044
116092
|
pendingReviewParked = true;
|
|
115045
116093
|
break;
|
|
115046
116094
|
}
|
|
@@ -120193,7 +121241,8 @@ async function collectTaskEvaluationEvidence(params) {
|
|
|
120193
121241
|
taskDoneRetryCount: task.taskDoneRetryCount ?? 0,
|
|
120194
121242
|
verificationFailureCount: task.verificationFailureCount ?? 0,
|
|
120195
121243
|
mergeConflictBounceCount: task.mergeConflictBounceCount ?? 0,
|
|
120196
|
-
mergeAuditBounceCount: task.mergeAuditBounceCount ?? 0
|
|
121244
|
+
mergeAuditBounceCount: task.mergeAuditBounceCount ?? 0,
|
|
121245
|
+
mergeTransientRetryCount: task.mergeTransientRetryCount ?? 0
|
|
120197
121246
|
}
|
|
120198
121247
|
}],
|
|
120199
121248
|
commits: commitEvidence,
|
|
@@ -120652,6 +121701,25 @@ function filterPathsByIgnoreList(paths, ignorePaths) {
|
|
|
120652
121701
|
}
|
|
120653
121702
|
return paths.filter((path10) => !normalizedIgnorePaths.some((ignore) => isIgnoredOverlapPath(path10, ignore)));
|
|
120654
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
|
+
}
|
|
120655
121723
|
function findHigherPriorityQueuedOverlap(candidate, queuedScopes, overlap) {
|
|
120656
121724
|
let higher = null;
|
|
120657
121725
|
for (const queued of queuedScopes) {
|
|
@@ -121326,34 +122394,47 @@ var init_scheduler = __esm({
|
|
|
121326
122394
|
);
|
|
121327
122395
|
}
|
|
121328
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
|
+
};
|
|
121329
122402
|
const inversionEmitted = /* @__PURE__ */ new Set();
|
|
121330
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
|
+
};
|
|
121331
122415
|
if (settings.groupOverlappingFiles) {
|
|
121332
|
-
const overlapIgnorePaths = settings.overlapIgnorePaths ?? [];
|
|
121333
122416
|
for (const t of inProgress) {
|
|
121334
|
-
const
|
|
121335
|
-
|
|
121336
|
-
|
|
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");
|
|
121337
122426
|
}
|
|
121338
122427
|
for (const t of todo) {
|
|
121339
|
-
|
|
121340
|
-
const scope = await this.store.parseFileScopeFromPrompt(t.id);
|
|
121341
|
-
const filteredScope = filterPathsByIgnoreList(scope, overlapIgnorePaths);
|
|
122428
|
+
const filteredScope = await getFilteredFileScope(t.id);
|
|
121342
122429
|
if (filteredScope.length === 0) continue;
|
|
122430
|
+
if (!isRunnableQueuedOverlapCandidate(t, tasks, now, activeScopes, filteredScope)) continue;
|
|
121343
122431
|
queuedHigherPriorityScopes.push({
|
|
121344
122432
|
id: t.id,
|
|
121345
122433
|
priority: t.priority,
|
|
121346
122434
|
createdAt: t.createdAt,
|
|
121347
122435
|
scope: filteredScope
|
|
121348
122436
|
});
|
|
121349
|
-
|
|
121350
|
-
const inReviewWithWorktree = tasks.filter(
|
|
121351
|
-
(t) => t.column === "in-review" && Boolean(t.worktree) && !t.paused && t.status !== "failed"
|
|
121352
|
-
);
|
|
121353
|
-
for (const t of inReviewWithWorktree) {
|
|
121354
|
-
const scope = await this.store.parseFileScopeFromPrompt(t.id);
|
|
121355
|
-
const filteredScope = filterPathsByIgnoreList(scope, overlapIgnorePaths);
|
|
121356
|
-
if (filteredScope.length > 0) activeScopes.set(t.id, filteredScope);
|
|
122437
|
+
queuedHigherPriorityTaskById.set(t.id, t);
|
|
121357
122438
|
}
|
|
121358
122439
|
}
|
|
121359
122440
|
const ordered = resolveDependencyOrder(todo);
|
|
@@ -121374,10 +122455,7 @@ var init_scheduler = __esm({
|
|
|
121374
122455
|
continue;
|
|
121375
122456
|
}
|
|
121376
122457
|
}
|
|
121377
|
-
const unmetDeps = task
|
|
121378
|
-
const dep = tasks.find((t) => t.id === depId);
|
|
121379
|
-
return dep && dep.column !== "done" && dep.column !== "in-review" && dep.column !== "archived";
|
|
121380
|
-
});
|
|
122458
|
+
const unmetDeps = getUnmetSchedulingDependencies(task, tasks);
|
|
121381
122459
|
if (unmetDeps.length > 0) {
|
|
121382
122460
|
await this.store.updateTask(task.id, {
|
|
121383
122461
|
status: "queued",
|
|
@@ -121411,17 +122489,18 @@ var init_scheduler = __esm({
|
|
|
121411
122489
|
continue;
|
|
121412
122490
|
}
|
|
121413
122491
|
if (settings.groupOverlappingFiles) {
|
|
121414
|
-
const
|
|
121415
|
-
const taskScope = filterPathsByIgnoreList(
|
|
121416
|
-
await this.store.parseFileScopeFromPrompt(task.id),
|
|
121417
|
-
overlapIgnorePaths
|
|
121418
|
-
);
|
|
122492
|
+
const taskScope = await getFilteredFileScope(task.id);
|
|
121419
122493
|
if (taskScope.length > 0) {
|
|
121420
122494
|
const activeScopeEntries = Array.from(activeScopes.entries()).sort(([aId], [bId]) => aId.localeCompare(bId));
|
|
121421
122495
|
const overlapBlockerId = task.overlapBlockedBy || task.blockedBy;
|
|
121422
122496
|
const currentBlockerScope = overlapBlockerId ? activeScopes.get(overlapBlockerId) : void 0;
|
|
121423
122497
|
const hasValidCurrentBlocker = Boolean(overlapBlockerId) && Boolean(currentBlockerScope) && this.pathsOverlap(taskScope, currentBlockerScope);
|
|
121424
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
|
+
});
|
|
121425
122504
|
const higherPriorityQueuedOverlap = findHigherPriorityQueuedOverlap(
|
|
121426
122505
|
{
|
|
121427
122506
|
id: task.id,
|
|
@@ -121429,7 +122508,7 @@ var init_scheduler = __esm({
|
|
|
121429
122508
|
createdAt: task.createdAt,
|
|
121430
122509
|
scope: taskScope
|
|
121431
122510
|
},
|
|
121432
|
-
|
|
122511
|
+
runnableQueuedHigherPriorityScopes,
|
|
121433
122512
|
this.pathsOverlap.bind(this)
|
|
121434
122513
|
);
|
|
121435
122514
|
if (higherPriorityQueuedOverlap) {
|
|
@@ -121444,7 +122523,7 @@ var init_scheduler = __esm({
|
|
|
121444
122523
|
await this.rollbackRunningAgentsForQueuedTodoTask(task.id);
|
|
121445
122524
|
await this.logDispatchQueuedReason(
|
|
121446
122525
|
task.id,
|
|
121447
|
-
`queued \u2014 deferred for higher-priority queued task ${higherPriorityQueuedOverlap.id} (overlap)`
|
|
122526
|
+
`queued \u2014 deferred for higher-priority runnable queued task ${higherPriorityQueuedOverlap.id} (overlap)`
|
|
121448
122527
|
);
|
|
121449
122528
|
continue;
|
|
121450
122529
|
}
|
|
@@ -121476,7 +122555,7 @@ var init_scheduler = __esm({
|
|
|
121476
122555
|
blockerId: overlapBlockerTask.id,
|
|
121477
122556
|
blockerPriority: overlapBlockerTask.priority ?? null,
|
|
121478
122557
|
blockerCreatedAt: overlapBlockerTask.createdAt ?? null,
|
|
121479
|
-
blockerColumn: overlapBlockerTask.column,
|
|
122558
|
+
blockerColumn: activeScopeColumns.get(overlappingTaskId) ?? overlapBlockerTask.column,
|
|
121480
122559
|
source: "scheduler.overlap-priority-inversion"
|
|
121481
122560
|
}
|
|
121482
122561
|
});
|
|
@@ -121487,7 +122566,11 @@ var init_scheduler = __esm({
|
|
|
121487
122566
|
}
|
|
121488
122567
|
}
|
|
121489
122568
|
await this.rollbackRunningAgentsForQueuedTodoTask(task.id);
|
|
121490
|
-
|
|
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
|
+
);
|
|
121491
122574
|
continue;
|
|
121492
122575
|
}
|
|
121493
122576
|
if (task.overlapBlockedBy) {
|
|
@@ -121706,11 +122789,8 @@ var init_scheduler = __esm({
|
|
|
121706
122789
|
this.options.onSchedule?.(task);
|
|
121707
122790
|
started++;
|
|
121708
122791
|
if (settings.groupOverlappingFiles) {
|
|
121709
|
-
const scope =
|
|
121710
|
-
|
|
121711
|
-
settings.overlapIgnorePaths
|
|
121712
|
-
);
|
|
121713
|
-
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");
|
|
121714
122794
|
}
|
|
121715
122795
|
}
|
|
121716
122796
|
await this.emitHighOverlapFanoutWarnings(tasks);
|
|
@@ -122863,7 +123943,10 @@ var init_mission_execution_loop = __esm({
|
|
|
122863
123943
|
try {
|
|
122864
123944
|
await this.missionStore.transitionLoopState(feature.id, "implementing");
|
|
122865
123945
|
if (feature.taskId) {
|
|
122866
|
-
await this.
|
|
123946
|
+
const linkedTask = await this.taskStore.getTask(feature.taskId).catch(() => null);
|
|
123947
|
+
if (linkedTask && (linkedTask.column === "done" || linkedTask.column === "archived")) {
|
|
123948
|
+
await this.processTaskOutcome(feature.taskId);
|
|
123949
|
+
}
|
|
122867
123950
|
}
|
|
122868
123951
|
recoveredCount++;
|
|
122869
123952
|
} catch (err) {
|
|
@@ -122874,7 +123957,10 @@ var init_mission_execution_loop = __esm({
|
|
|
122874
123957
|
loopLog.log(`Recovery: feature ${feature.id} awaiting fix implementation`);
|
|
122875
123958
|
if (feature.taskId) {
|
|
122876
123959
|
try {
|
|
122877
|
-
await this.
|
|
123960
|
+
const linkedTask = await this.taskStore.getTask(feature.taskId).catch(() => null);
|
|
123961
|
+
if (linkedTask && (linkedTask.column === "done" || linkedTask.column === "archived")) {
|
|
123962
|
+
await this.processTaskOutcome(feature.taskId);
|
|
123963
|
+
}
|
|
122878
123964
|
recoveredCount++;
|
|
122879
123965
|
} catch (err) {
|
|
122880
123966
|
loopLog.error(`Recovery failed for needs_fix feature ${feature.id}:`, err);
|
|
@@ -122916,10 +124002,17 @@ var init_mission_execution_loop = __esm({
|
|
|
122916
124002
|
}
|
|
122917
124003
|
if (feature.loopState !== "implementing") {
|
|
122918
124004
|
loopLog.log(`Feature ${feature.id} loopState is "${feature.loopState}"; skipping validation`);
|
|
124005
|
+
this.logFeatureWarningEvent(feature.id, "validation_skipped_loop_state", `Validation skipped: feature ${feature.id} is in loopState "${feature.loopState}" (expected "implementing").`, {
|
|
124006
|
+
taskId,
|
|
124007
|
+
loopState: feature.loopState
|
|
124008
|
+
});
|
|
122919
124009
|
return;
|
|
122920
124010
|
}
|
|
122921
124011
|
if (this.activeValidations.has(feature.id)) {
|
|
122922
124012
|
loopLog.log(`Feature ${feature.id} already has an active validation; skipping duplicate trigger`);
|
|
124013
|
+
this.logFeatureWarningEvent(feature.id, "validation_deduplicated", `Validation already running for feature ${feature.id}; duplicate trigger ignored.`, {
|
|
124014
|
+
taskId
|
|
124015
|
+
});
|
|
122923
124016
|
return;
|
|
122924
124017
|
}
|
|
122925
124018
|
const assertions = this.missionStore.listAssertionsForFeature(feature.id);
|
|
@@ -123387,6 +124480,10 @@ ${taskContext}` : ""}`;
|
|
|
123387
124480
|
this.missionStore.completeValidatorRun(runId, "blocked", blockedReason);
|
|
123388
124481
|
}
|
|
123389
124482
|
loopLog.log(`Feature ${featureId} blocked: ${blockedReason}`);
|
|
124483
|
+
this.logFeatureErrorEvent(featureId, "validation_blocked", `Validation blocked for feature ${featureId}: ${blockedReason ?? "no reason provided"}`, {
|
|
124484
|
+
runId,
|
|
124485
|
+
blockedReason: blockedReason ?? null
|
|
124486
|
+
});
|
|
123390
124487
|
if (this.missionAutopilot?.notifyValidationComplete) {
|
|
123391
124488
|
await this.missionAutopilot.notifyValidationComplete(featureId, "blocked");
|
|
123392
124489
|
}
|
|
@@ -123404,6 +124501,10 @@ ${taskContext}` : ""}`;
|
|
|
123404
124501
|
this.missionStore.completeValidatorRun(runId, "error", error);
|
|
123405
124502
|
}
|
|
123406
124503
|
loopLog.error(`Feature ${featureId} validation error: ${error}`);
|
|
124504
|
+
this.logFeatureErrorEvent(featureId, "validation_error", `Validation error for feature ${featureId}: ${error}`, {
|
|
124505
|
+
runId,
|
|
124506
|
+
error
|
|
124507
|
+
});
|
|
123407
124508
|
if (this.missionAutopilot?.notifyValidationComplete) {
|
|
123408
124509
|
await this.missionAutopilot.notifyValidationComplete(featureId, "error");
|
|
123409
124510
|
}
|
|
@@ -123412,6 +124513,31 @@ ${taskContext}` : ""}`;
|
|
|
123412
124513
|
loopLog.error(`Error handling validation error for ${featureId}:`, err);
|
|
123413
124514
|
}
|
|
123414
124515
|
}
|
|
124516
|
+
logFeatureWarningEvent(featureId, code, description, metadata) {
|
|
124517
|
+
this.logFeatureMissionEvent(featureId, "warning", code, description, metadata);
|
|
124518
|
+
}
|
|
124519
|
+
logFeatureErrorEvent(featureId, code, description, metadata) {
|
|
124520
|
+
this.logFeatureMissionEvent(featureId, "error", code, description, metadata);
|
|
124521
|
+
}
|
|
124522
|
+
logFeatureMissionEvent(featureId, eventType, code, description, metadata) {
|
|
124523
|
+
const feature = this.missionStore.getFeature(featureId);
|
|
124524
|
+
if (!feature) return;
|
|
124525
|
+
const slice = this.missionStore.getSlice(feature.sliceId);
|
|
124526
|
+
if (!slice) return;
|
|
124527
|
+
const milestone = this.missionStore.getMilestone(slice.milestoneId);
|
|
124528
|
+
if (!milestone) return;
|
|
124529
|
+
try {
|
|
124530
|
+
this.missionStore.logMissionEvent?.(milestone.missionId, eventType, description, {
|
|
124531
|
+
code,
|
|
124532
|
+
featureId,
|
|
124533
|
+
sliceId: slice.id,
|
|
124534
|
+
milestoneId: milestone.id,
|
|
124535
|
+
...metadata
|
|
124536
|
+
});
|
|
124537
|
+
} catch (err) {
|
|
124538
|
+
loopLog.warn(`Failed to log mission ${eventType} event for feature ${featureId}:`, err);
|
|
124539
|
+
}
|
|
124540
|
+
}
|
|
123415
124541
|
};
|
|
123416
124542
|
}
|
|
123417
124543
|
});
|
|
@@ -124694,6 +125820,8 @@ var init_agent_heartbeat = __esm({
|
|
|
124694
125820
|
init_agent_instructions();
|
|
124695
125821
|
init_heartbeat_procedure_resolver();
|
|
124696
125822
|
init_prompt_layers();
|
|
125823
|
+
init_goal_injection_diagnostics();
|
|
125824
|
+
init_goal_anchoring_audit();
|
|
124697
125825
|
init_logger2();
|
|
124698
125826
|
init_worktree_acquisition();
|
|
124699
125827
|
init_run_audit();
|
|
@@ -126085,12 +127213,16 @@ Critical: a heartbeat without observable progress (or an explicit no-op reason)
|
|
|
126085
127213
|
engineRunContext.taskId = taskId;
|
|
126086
127214
|
}
|
|
126087
127215
|
let autoClaimCandidates = [];
|
|
127216
|
+
let autoClaimSnapshotCandidateCount = 0;
|
|
127217
|
+
let autoClaimRoleFilteredCount = 0;
|
|
126088
127218
|
const autoClaimEnabled = isAutoClaimRelevantTasksEnabled(agent);
|
|
126089
127219
|
if (!taskId && canRunNoTaskHeartbeat && autoClaimEnabled && this.snapshotManager) {
|
|
126090
127220
|
try {
|
|
126091
127221
|
const snapshot = await this.snapshotManager.getSnapshot();
|
|
127222
|
+
autoClaimSnapshotCandidateCount = snapshot.tasks.length;
|
|
126092
127223
|
const roleCompatibleCandidates = snapshot.tasks.filter((candidate) => canAgentTakeImplementationTask(agent, candidate));
|
|
126093
127224
|
const skippedIncompatibleCount = snapshot.tasks.length - roleCompatibleCandidates.length;
|
|
127225
|
+
autoClaimRoleFilteredCount = skippedIncompatibleCount;
|
|
126094
127226
|
if (skippedIncompatibleCount > 0) {
|
|
126095
127227
|
heartbeatLog.log(
|
|
126096
127228
|
`Agent ${agentId} (role=${agent.role}) skipped auto-claim of ${skippedIncompatibleCount} implementation task(s) \u2014 only executor agents may claim implementation work`
|
|
@@ -126346,8 +127478,29 @@ Critical: a heartbeat without observable progress (or an explicit no-op reason)
|
|
|
126346
127478
|
if (heartbeatPluginContributions) {
|
|
126347
127479
|
heartbeatLog.log(`applied plugin prompt contributions for heartbeat surface`);
|
|
126348
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
|
+
});
|
|
126349
127501
|
const heartbeatLayers = buildPromptLayers({
|
|
126350
127502
|
basePrompt: baseHeartbeatSystemPrompt,
|
|
127503
|
+
goalContext: heartbeatGoalContext,
|
|
126351
127504
|
agentInstructions: [resolvedInstructionsText, memoryInstructions, selfImprovePrompt].filter((part) => part.trim()).join("\n\n"),
|
|
126352
127505
|
pluginContributions: heartbeatPluginContributions
|
|
126353
127506
|
});
|
|
@@ -126622,10 +127775,15 @@ Critical: a heartbeat without observable progress (or an explicit no-op reason)
|
|
|
126622
127775
|
);
|
|
126623
127776
|
}
|
|
126624
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
|
+
] : [];
|
|
126625
127783
|
const candidateLines = promptCandidateLimit > 0 ? [
|
|
126626
127784
|
"",
|
|
126627
127785
|
"Open Task Candidates (auto-claim scan):",
|
|
126628
|
-
...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
|
|
126629
127787
|
] : [];
|
|
126630
127788
|
executionPrompt = [
|
|
126631
127789
|
`Heartbeat execution for agent "${agent.name}" (ID: ${agent.id})`,
|
|
@@ -126641,7 +127799,7 @@ Critical: a heartbeat without observable progress (or an explicit no-op reason)
|
|
|
126641
127799
|
...wakeTriggerSourceLine ? [wakeTriggerSourceLine] : [],
|
|
126642
127800
|
`- pending messages: ${pendingMessages.length}`,
|
|
126643
127801
|
`- pending room messages: ${pendingRoomMessages.total}`,
|
|
126644
|
-
`- auto-claim relevant tasks: ${
|
|
127802
|
+
`- auto-claim relevant tasks: ${autoClaimStatus}`,
|
|
126645
127803
|
"",
|
|
126646
127804
|
"Treat this wake delta as the highest-priority change for this heartbeat.",
|
|
126647
127805
|
"This is an autonomous heartbeat run (manual or automatic): re-anchor on",
|
|
@@ -133007,9 +134165,19 @@ var init_in_process_runtime = __esm({
|
|
|
133007
134165
|
missionAutopilot: missionAutopilot ? {
|
|
133008
134166
|
notifyValidationComplete: async (featureId) => {
|
|
133009
134167
|
const feature = missionStore.getFeature(featureId);
|
|
133010
|
-
if (feature?.taskId) {
|
|
133011
|
-
|
|
134168
|
+
if (!feature?.taskId) {
|
|
134169
|
+
return;
|
|
134170
|
+
}
|
|
134171
|
+
const slice = missionStore.getSlice(feature.sliceId);
|
|
134172
|
+
const milestone = slice ? missionStore.getMilestone(slice.milestoneId) : void 0;
|
|
134173
|
+
const missionId = milestone?.missionId;
|
|
134174
|
+
if (missionId) {
|
|
134175
|
+
const mission = missionStore.getMission(missionId);
|
|
134176
|
+
if (mission?.autopilotEnabled && !missionAutopilot.isWatching(missionId)) {
|
|
134177
|
+
missionAutopilot.watchMission(missionId);
|
|
134178
|
+
}
|
|
133012
134179
|
}
|
|
134180
|
+
await missionAutopilot.handleTaskCompletion(feature.taskId);
|
|
133013
134181
|
}
|
|
133014
134182
|
} : void 0,
|
|
133015
134183
|
rootDir: this.config.workingDirectory,
|
|
@@ -133782,7 +134950,8 @@ var init_in_process_runtime = __esm({
|
|
|
133782
134950
|
this.usageLimitPauser = pauser;
|
|
133783
134951
|
}
|
|
133784
134952
|
/**
|
|
133785
|
-
* 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.
|
|
133786
134955
|
*/
|
|
133787
134956
|
setupEventForwarding() {
|
|
133788
134957
|
this.taskStore.on("task:created", (task) => {
|
|
@@ -133797,6 +134966,10 @@ var init_in_process_runtime = __esm({
|
|
|
133797
134966
|
this.recordActivity();
|
|
133798
134967
|
this.emit("task:updated", task);
|
|
133799
134968
|
});
|
|
134969
|
+
this.taskStore.on("task:deleted", (task, meta) => {
|
|
134970
|
+
this.recordActivity();
|
|
134971
|
+
this.emit("task:deleted", task, meta);
|
|
134972
|
+
});
|
|
133800
134973
|
runtimeLog.log("Event forwarding setup complete");
|
|
133801
134974
|
}
|
|
133802
134975
|
/**
|
|
@@ -133847,7 +135020,7 @@ var init_in_process_runtime = __esm({
|
|
|
133847
135020
|
function generateCorrelationId() {
|
|
133848
135021
|
return `${Date.now()}-${Math.random().toString(36).slice(2, 11)}`;
|
|
133849
135022
|
}
|
|
133850
|
-
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;
|
|
133851
135024
|
var init_ipc_protocol = __esm({
|
|
133852
135025
|
"../engine/src/ipc/ipc-protocol.ts"() {
|
|
133853
135026
|
"use strict";
|
|
@@ -133860,6 +135033,7 @@ var init_ipc_protocol = __esm({
|
|
|
133860
135033
|
TASK_CREATED = "TASK_CREATED";
|
|
133861
135034
|
TASK_MOVED = "TASK_MOVED";
|
|
133862
135035
|
TASK_UPDATED = "TASK_UPDATED";
|
|
135036
|
+
TASK_DELETED = "TASK_DELETED";
|
|
133863
135037
|
ERROR_EVENT = "ERROR_EVENT";
|
|
133864
135038
|
HEALTH_CHANGED = "HEALTH_CHANGED";
|
|
133865
135039
|
}
|
|
@@ -134244,6 +135418,9 @@ var init_child_process_runtime = __esm({
|
|
|
134244
135418
|
this.ipcHost.on(TASK_UPDATED, (payload) => {
|
|
134245
135419
|
this.emit("task:updated", payload.task);
|
|
134246
135420
|
});
|
|
135421
|
+
this.ipcHost.on(TASK_DELETED, (payload) => {
|
|
135422
|
+
this.emit("task:deleted", payload.task, payload.meta);
|
|
135423
|
+
});
|
|
134247
135424
|
this.ipcHost.on(ERROR_EVENT, (payload) => {
|
|
134248
135425
|
const error = new Error(payload.message);
|
|
134249
135426
|
if (payload.code) {
|
|
@@ -135366,6 +136543,9 @@ var init_project_manager = __esm({
|
|
|
135366
136543
|
runtime.on("task:updated", (task) => {
|
|
135367
136544
|
this.emit("task:updated", { projectId, projectName, task });
|
|
135368
136545
|
});
|
|
136546
|
+
runtime.on("task:deleted", (task, meta) => {
|
|
136547
|
+
this.emit("task:deleted", { projectId, projectName, task, meta });
|
|
136548
|
+
});
|
|
135369
136549
|
runtime.on("error", (error) => {
|
|
135370
136550
|
this.emit("error", { projectId, projectName, error });
|
|
135371
136551
|
this.logActivity(
|
|
@@ -135728,6 +136908,10 @@ function buildMergeSystemPrompt2(agentPrompts) {
|
|
|
135728
136908
|
" - The subject line must CONCISELY SUMMARIZE the squashed changes in",
|
|
135729
136909
|
' imperative mood (e.g. "add X", "fix Y") based on the actual diff \u2014 do',
|
|
135730
136910
|
" not just restate the task title.",
|
|
136911
|
+
" - The commit BODY must include:",
|
|
136912
|
+
" 1) one short narrative summary line,",
|
|
136913
|
+
" 2) a bullet list of key changes, and",
|
|
136914
|
+
" 3) a `Files changed:` section populated from `git diff --stat`.",
|
|
135731
136915
|
" - Include the task-id prefix and the trailer lines EXACTLY as given in the",
|
|
135732
136916
|
" task instructions (they associate the commit with the board task)."
|
|
135733
136917
|
].filter((l) => l !== void 0).join("\n");
|
|
@@ -135741,11 +136925,15 @@ function buildMergePrompt2(input) {
|
|
|
135741
136925
|
"Steps:",
|
|
135742
136926
|
` 1. Run: git merge --squash ${input.branch}`,
|
|
135743
136927
|
" 2. If there are conflicts, resolve them (favor the task's intent), then `git add` the resolved files.",
|
|
135744
|
-
" 3.
|
|
135745
|
-
|
|
135746
|
-
|
|
136928
|
+
" 3. Build a merge body from the staged squash diff:",
|
|
136929
|
+
" - one short narrative summary line",
|
|
136930
|
+
" - bullet list of key changes",
|
|
136931
|
+
" - `Files changed:` + the output of `git diff --stat`",
|
|
136932
|
+
" 4. Commit the staged result as a SINGLE commit whose subject summarizes the",
|
|
136933
|
+
` actual changes${input.taskTitle ? ` (task title hint: ${JSON.stringify(input.taskTitle)})` : ""}, including the body above and required trailers:`,
|
|
136934
|
+
` git commit -m ${subjectShape} -m "<narrative + bullet list + Files changed: ...>"${trailerArgs}`,
|
|
135747
136935
|
" Keep the trailer line(s) verbatim \u2014 they link the commit to the board task.",
|
|
135748
|
-
"
|
|
136936
|
+
" 5. Verify `git log --oneline ${tip}..HEAD` shows exactly one new commit and `git status` is clean.".replace("${tip}", short(input.tipSha)),
|
|
135749
136937
|
"",
|
|
135750
136938
|
"If `git merge --squash` reports the branch is already up to date (nothing to",
|
|
135751
136939
|
"merge), do nothing and leave HEAD unchanged."
|
|
@@ -137036,6 +138224,7 @@ var init_project_engine = __esm({
|
|
|
137036
138224
|
init_research_step_runner();
|
|
137037
138225
|
init_run_audit();
|
|
137038
138226
|
init_verification_followup_dedup();
|
|
138227
|
+
init_transient_error_detector();
|
|
137039
138228
|
init_tunnel_process_manager();
|
|
137040
138229
|
execFileAsync12 = promisify45(execFile17);
|
|
137041
138230
|
MERGE_HANDOFF_GRACE_MS = 300;
|
|
@@ -137106,6 +138295,10 @@ var init_project_engine = __esm({
|
|
|
137106
138295
|
manualMergeResolvers = /* @__PURE__ */ new Map();
|
|
137107
138296
|
shuttingDown = false;
|
|
137108
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;
|
|
137109
138302
|
/** Cap on outer in-review→in-progress bounces caused by deterministic
|
|
137110
138303
|
* verification failures during auto-merge. After this many failed merges
|
|
137111
138304
|
* for the same task, we stop bouncing it back, mark it failed, and create
|
|
@@ -138088,7 +139281,15 @@ ${detail}`
|
|
|
138088
139281
|
this.internalEnqueueMerge(taskId);
|
|
138089
139282
|
continue;
|
|
138090
139283
|
}
|
|
138091
|
-
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
|
+
});
|
|
138092
139293
|
if (blockerReason) {
|
|
138093
139294
|
await store.updateTask(taskId, {
|
|
138094
139295
|
status: "failed",
|
|
@@ -138607,6 +139808,16 @@ ${detail}`
|
|
|
138607
139808
|
}
|
|
138608
139809
|
} else {
|
|
138609
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
|
+
}
|
|
138610
139821
|
await store.updateTask(taskId, {
|
|
138611
139822
|
status: "failed",
|
|
138612
139823
|
mergeRetries: _ProjectEngine.MAX_AUTO_MERGE_RETRIES,
|
|
@@ -138625,6 +139836,16 @@ ${detail}`
|
|
|
138625
139836
|
}
|
|
138626
139837
|
} else {
|
|
138627
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
|
+
}
|
|
138628
139849
|
await store.updateTask(taskId, {
|
|
138629
139850
|
status: "failed",
|
|
138630
139851
|
mergeRetries: _ProjectEngine.MAX_AUTO_MERGE_RETRIES,
|
|
@@ -138660,6 +139881,40 @@ ${detail}`
|
|
|
138660
139881
|
this.mergeRunning = false;
|
|
138661
139882
|
}
|
|
138662
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
|
+
}
|
|
138663
139918
|
wireAutoMerge(store, _cwd) {
|
|
138664
139919
|
this.taskMovedHandler = async ({ task, to: to2 }) => {
|
|
138665
139920
|
if (to2 !== "in-review") return;
|
|
@@ -142209,6 +143464,7 @@ __export(src_exports2, {
|
|
|
142209
143464
|
BranchConflictError: () => BranchConflictError,
|
|
142210
143465
|
BranchCrossContaminationError: () => BranchCrossContaminationError,
|
|
142211
143466
|
CronRunner: () => CronRunner,
|
|
143467
|
+
DEFAULT_GOAL_INJECTION_CHAR_BUDGET: () => DEFAULT_GOAL_INJECTION_CHAR_BUDGET,
|
|
142212
143468
|
DEFAULT_NTFY_EVENTS: () => DEFAULT_NTFY_EVENTS,
|
|
142213
143469
|
DiffVolumeRegressionError: () => DiffVolumeRegressionError,
|
|
142214
143470
|
EngineAlreadyRunningError: () => EngineAlreadyRunningError,
|
|
@@ -142223,6 +143479,9 @@ __export(src_exports2, {
|
|
|
142223
143479
|
ExperimentGitNotConfiguredError: () => ExperimentGitNotConfiguredError,
|
|
142224
143480
|
ExperimentMaxIterationsError: () => ExperimentMaxIterationsError,
|
|
142225
143481
|
ExperimentRevertConflictError: () => ExperimentRevertConflictError,
|
|
143482
|
+
GOAL_INJECTION_APPLIED: () => GOAL_INJECTION_APPLIED,
|
|
143483
|
+
GOAL_INJECTION_SKIPPED: () => GOAL_INJECTION_SKIPPED,
|
|
143484
|
+
GOAL_RETRIEVAL_INVOKED: () => GOAL_RETRIEVAL_INVOKED,
|
|
142226
143485
|
GitHubProvider: () => GitHubProvider,
|
|
142227
143486
|
HEARTBEAT_NO_TASK_SYSTEM_PROMPT: () => HEARTBEAT_NO_TASK_SYSTEM_PROMPT,
|
|
142228
143487
|
HEARTBEAT_PROCEDURE: () => HEARTBEAT_PROCEDURE,
|
|
@@ -142233,6 +143492,7 @@ __export(src_exports2, {
|
|
|
142233
143492
|
KNOWN_EXTERNAL_INTEGRATIONS: () => KNOWN_EXTERNAL_INTEGRATIONS,
|
|
142234
143493
|
LLMSynthesisProvider: () => LLMSynthesisProvider,
|
|
142235
143494
|
LocalDocsProvider: () => LocalDocsProvider,
|
|
143495
|
+
MAX_INJECTED_GOALS: () => MAX_INJECTED_GOALS,
|
|
142236
143496
|
MOCK_PROVIDER_ID: () => MOCK_PROVIDER_ID3,
|
|
142237
143497
|
MOCK_SYNTHETIC_TOKEN_USAGE: () => MOCK_SYNTHETIC_TOKEN_USAGE,
|
|
142238
143498
|
MergeAbortedError: () => MergeAbortedError,
|
|
@@ -142308,10 +143568,13 @@ __export(src_exports2, {
|
|
|
142308
143568
|
assertSafeUrl: () => assertSafeUrl,
|
|
142309
143569
|
auditSquashMerge: () => auditSquashMerge,
|
|
142310
143570
|
buildAgentChatPrompt: () => buildAgentChatPrompt,
|
|
143571
|
+
buildGoalContextSection: () => buildGoalContextSection,
|
|
142311
143572
|
buildNtfyClickUrl: () => buildNtfyClickUrl,
|
|
142312
143573
|
buildRuntimeResolutionContext: () => buildRuntimeResolutionContext,
|
|
142313
143574
|
buildSystemPromptWithInstructions: () => buildSystemPromptWithInstructions,
|
|
142314
143575
|
classifyBootstrapMisbinding: () => classifyBootstrapMisbinding,
|
|
143576
|
+
classifyGoalInjectionFailure: () => classifyGoalInjectionFailure,
|
|
143577
|
+
classifyGoalInjectionResult: () => classifyGoalInjectionResult,
|
|
142315
143578
|
classifyTaskError: () => classifyTaskError,
|
|
142316
143579
|
cleanupOrphanedWorktrees: () => cleanupOrphanedWorktrees,
|
|
142317
143580
|
cleanupSecretsEnvFile: () => cleanupSecretsEnvFile,
|
|
@@ -142336,6 +143599,9 @@ __export(src_exports2, {
|
|
|
142336
143599
|
describeModel: () => describeModel,
|
|
142337
143600
|
dropAutostashBySha: () => dropAutostashBySha,
|
|
142338
143601
|
dropAutostashHandle: () => dropAutostashHandle,
|
|
143602
|
+
emitGoalAnchoringAudit: () => emitGoalAnchoringAudit,
|
|
143603
|
+
emitGoalInjectionDiagnostic: () => emitGoalInjectionDiagnostic,
|
|
143604
|
+
emitGoalRetrievalAudit: () => emitGoalRetrievalAudit,
|
|
142339
143605
|
ensureDefaultHeartbeatProcedureFile: () => ensureDefaultHeartbeatProcedureFile,
|
|
142340
143606
|
executeApprovedAgentProvisioning: () => executeApprovedAgentProvisioning,
|
|
142341
143607
|
executeApprovedWorktrunkInstall: () => executeApprovedWorktrunkInstall,
|
|
@@ -142450,6 +143716,9 @@ var init_src2 = __esm({
|
|
|
142450
143716
|
init_external_integrations();
|
|
142451
143717
|
init_web_fetch();
|
|
142452
143718
|
init_error_classifier();
|
|
143719
|
+
init_goal_context_injector();
|
|
143720
|
+
init_goal_injection_diagnostics();
|
|
143721
|
+
init_goal_anchoring_audit();
|
|
142453
143722
|
init_worktrunk_installer();
|
|
142454
143723
|
init_worktrunk_failure_handler();
|
|
142455
143724
|
init_usage_limit_detector();
|
|
@@ -157490,6 +158759,26 @@ var init_register_git_github = __esm({
|
|
|
157490
158759
|
});
|
|
157491
158760
|
|
|
157492
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
|
+
}
|
|
157493
158782
|
function normalizeOptionalBranch(value, fieldName) {
|
|
157494
158783
|
if (value === void 0 || value === null) return void 0;
|
|
157495
158784
|
if (typeof value !== "string") {
|
|
@@ -157506,22 +158795,8 @@ function resolveBranchSelection(selectionInput, fallbackBranch, fallbackBaseBran
|
|
|
157506
158795
|
if (selectionInput === void 0 || selectionInput === null) {
|
|
157507
158796
|
return fallback2;
|
|
157508
158797
|
}
|
|
157509
|
-
|
|
157510
|
-
throw badRequest("branchSelection must be an object");
|
|
157511
|
-
}
|
|
158798
|
+
const mode = getBranchSelectionMode(selectionInput);
|
|
157512
158799
|
const selection = selectionInput;
|
|
157513
|
-
const mode = typeof selection.mode === "string" ? selection.mode : void 0;
|
|
157514
|
-
if (!mode) {
|
|
157515
|
-
throw badRequest("branchSelection.mode is required");
|
|
157516
|
-
}
|
|
157517
|
-
if (![
|
|
157518
|
-
"project-default",
|
|
157519
|
-
"auto-new",
|
|
157520
|
-
"existing",
|
|
157521
|
-
"custom-new"
|
|
157522
|
-
].includes(mode)) {
|
|
157523
|
-
throw badRequest("branchSelection.mode must be one of: project-default, auto-new, existing, custom-new");
|
|
157524
|
-
}
|
|
157525
158800
|
const baseBranch = normalizeOptionalBranch(selection.baseBranch, "branchSelection.baseBranch");
|
|
157526
158801
|
if (mode === "project-default") {
|
|
157527
158802
|
return { branch: void 0, baseBranch };
|
|
@@ -157557,6 +158832,11 @@ function resolveBranchAssignmentContext(input) {
|
|
|
157557
158832
|
function sanitizeSegment(input) {
|
|
157558
158833
|
return input.trim().toLowerCase().replace(/[^a-z0-9._/-]+/g, "-").replace(/-{2,}/g, "-").replace(/^[-/.]+|[-/.]+$/g, "").slice(0, 48);
|
|
157559
158834
|
}
|
|
158835
|
+
function deriveAutoTaskBranch(taskId, shortName) {
|
|
158836
|
+
const base = `fusion/${taskId.toLowerCase()}`;
|
|
158837
|
+
const segment = sanitizeSegment(shortName ?? "");
|
|
158838
|
+
return segment ? `${base}-${segment}` : base;
|
|
158839
|
+
}
|
|
157560
158840
|
function derivePerTaskBranch(sharedBranch, taskSegment) {
|
|
157561
158841
|
const base = normalizeOptionalBranch(sharedBranch, "sharedBranch");
|
|
157562
158842
|
if (!base) return void 0;
|
|
@@ -158196,6 +159476,7 @@ function registerTaskWorkflowRoutes(ctx, deps) {
|
|
|
158196
159476
|
}
|
|
158197
159477
|
} : void 0;
|
|
158198
159478
|
const normalizedSource = source && typeof source === "object" && "sourceType" in source && typeof source.sourceType === "string" ? source : { sourceType: "api" };
|
|
159479
|
+
const requestedBranchMode = getBranchSelectionMode(branchSelection);
|
|
158199
159480
|
const { branch: normalizedBranch, baseBranch: normalizedBaseBranch } = resolveBranchSelection(branchSelection, branch, baseBranch);
|
|
158200
159481
|
let validatedGithubTracking;
|
|
158201
159482
|
if (githubTracking !== void 0 && githubTracking !== null) {
|
|
@@ -158452,8 +159733,14 @@ ${normalizedDescription}`;
|
|
|
158452
159733
|
createInput,
|
|
158453
159734
|
{ onSummarize, settings: { autoSummarizeTitles: settings.autoSummarizeTitles } }
|
|
158454
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;
|
|
158455
159742
|
const deterministicReconcile = await reconcileDeterministicDuplicate(scopedStore, {
|
|
158456
|
-
createdTask:
|
|
159743
|
+
createdTask: taskWithAutoBranch,
|
|
158457
159744
|
fingerprint: bypassDuplicateCheck === true ? null : contentFingerprint,
|
|
158458
159745
|
windowMs: 6e4,
|
|
158459
159746
|
logger: runtimeLogger
|
|
@@ -158466,8 +159753,8 @@ ${normalizedDescription}`;
|
|
|
158466
159753
|
try {
|
|
158467
159754
|
await scopedStore.recordActivity({
|
|
158468
159755
|
type: "task:duplicate-warning-overridden",
|
|
158469
|
-
taskId:
|
|
158470
|
-
taskTitle:
|
|
159756
|
+
taskId: taskWithAutoBranch.id,
|
|
159757
|
+
taskTitle: taskWithAutoBranch.title,
|
|
158471
159758
|
details: `Created despite ${acknowledgedDuplicateIds.length} possible duplicate(s): ${acknowledgedDuplicateIds.join(", ")}`,
|
|
158472
159759
|
metadata: {
|
|
158473
159760
|
acknowledgedDuplicateIds,
|
|
@@ -158481,7 +159768,7 @@ ${normalizedDescription}`;
|
|
|
158481
159768
|
});
|
|
158482
159769
|
}
|
|
158483
159770
|
}
|
|
158484
|
-
res.status(201).json(
|
|
159771
|
+
res.status(201).json(taskWithAutoBranch);
|
|
158485
159772
|
return;
|
|
158486
159773
|
} finally {
|
|
158487
159774
|
deterministicGuard.releaseLock();
|
|
@@ -159609,7 +160896,7 @@ ${normalizedDescription}`;
|
|
|
159609
160896
|
router.patch("/tasks/:id", async (req, res) => {
|
|
159610
160897
|
try {
|
|
159611
160898
|
const { store: scopedStore } = await getProjectContext3(req);
|
|
159612
|
-
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;
|
|
159613
160900
|
const hasBodyField = (field) => Object.prototype.hasOwnProperty.call(req.body, field);
|
|
159614
160901
|
const validateModelField = (value, name) => {
|
|
159615
160902
|
if (value === void 0) return void 0;
|
|
@@ -159650,6 +160937,9 @@ ${normalizedDescription}`;
|
|
|
159650
160937
|
if (hasBodyField("noCommitsExpected") && noCommitsExpected !== void 0 && typeof noCommitsExpected !== "boolean") {
|
|
159651
160938
|
throw new Error("noCommitsExpected must be a boolean");
|
|
159652
160939
|
}
|
|
160940
|
+
if (hasBodyField("autoMerge") && autoMerge !== void 0 && autoMerge !== null && typeof autoMerge !== "boolean") {
|
|
160941
|
+
throw new Error("autoMerge must be a boolean");
|
|
160942
|
+
}
|
|
159653
160943
|
let validatedSourceIssue;
|
|
159654
160944
|
if (hasBodyField("sourceIssue")) {
|
|
159655
160945
|
if (sourceIssue === null) {
|
|
@@ -159771,6 +161061,7 @@ ${normalizedDescription}`;
|
|
|
159771
161061
|
if (dependencies !== void 0) updates.dependencies = dependencies;
|
|
159772
161062
|
if (enabledWorkflowSteps !== void 0) updates.enabledWorkflowSteps = enabledWorkflowSteps;
|
|
159773
161063
|
if (hasBodyField("noCommitsExpected")) updates.noCommitsExpected = noCommitsExpected;
|
|
161064
|
+
if (hasBodyField("autoMerge")) updates.autoMerge = autoMerge === null ? void 0 : autoMerge;
|
|
159774
161065
|
if (hasBodyField("modelProvider")) updates.modelProvider = validatedModelProvider;
|
|
159775
161066
|
if (hasBodyField("modelId")) updates.modelId = validatedModelId;
|
|
159776
161067
|
if (hasBodyField("validatorModelProvider")) updates.validatorModelProvider = validatedValidatorModelProvider;
|
|
@@ -198039,15 +199330,35 @@ async function resolveAuditCommitSha(taskId, scopedStore) {
|
|
|
198039
199330
|
}
|
|
198040
199331
|
return void 0;
|
|
198041
199332
|
}
|
|
198042
|
-
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;
|
|
198043
199346
|
const existing = task.mergeDetails?.commitSha?.trim();
|
|
198044
|
-
if (existing)
|
|
199347
|
+
if (existing) {
|
|
199348
|
+
if (!includeBaseCommitSha && baseCommitSha && existing === baseCommitSha) return void 0;
|
|
199349
|
+
return existing;
|
|
199350
|
+
}
|
|
198045
199351
|
const auditSha = await resolveAuditCommitSha(task.id, scopedStore);
|
|
198046
|
-
if (auditSha)
|
|
199352
|
+
if (auditSha) {
|
|
199353
|
+
if (!includeBaseCommitSha && baseCommitSha && auditSha === baseCommitSha) return void 0;
|
|
199354
|
+
return auditSha;
|
|
199355
|
+
}
|
|
198047
199356
|
if (!task.lineageId) return void 0;
|
|
198048
199357
|
const associations = await scopedStore.getTaskCommitAssociationsByLineageId(task.lineageId);
|
|
198049
199358
|
for (const association of associations) {
|
|
198050
|
-
if (association.commitSha
|
|
199359
|
+
if (!association.commitSha) continue;
|
|
199360
|
+
if (!includeBaseCommitSha && baseCommitSha && association.commitSha === baseCommitSha) continue;
|
|
199361
|
+
if (await isReachableFromHead(association.commitSha, rootDir)) {
|
|
198051
199362
|
return association.commitSha;
|
|
198052
199363
|
}
|
|
198053
199364
|
}
|
|
@@ -198266,7 +199577,15 @@ function registerSessionDiffRoutes(router, deps) {
|
|
|
198266
199577
|
return;
|
|
198267
199578
|
}
|
|
198268
199579
|
if (task.column === "done") {
|
|
199580
|
+
const mergeShaForBaseBoundary = await resolveDoneTaskMergeSha(task, scopedStore, { includeBaseCommitSha: true });
|
|
198269
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
|
+
}
|
|
198270
199589
|
const doneTaskForDiff = resolvedMergeSha ? {
|
|
198271
199590
|
...task,
|
|
198272
199591
|
mergeDetails: {
|
|
@@ -198477,7 +199796,15 @@ function registerSessionDiffRoutes(router, deps) {
|
|
|
198477
199796
|
return;
|
|
198478
199797
|
}
|
|
198479
199798
|
if (task.column === "done") {
|
|
199799
|
+
const mergeShaForBaseBoundary = await resolveDoneTaskMergeSha(task, scopedStore, { includeBaseCommitSha: true });
|
|
198480
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
|
+
}
|
|
198481
199808
|
const doneTaskForDiff = resolvedMergeSha ? {
|
|
198482
199809
|
...task,
|
|
198483
199810
|
mergeDetails: {
|
|
@@ -214951,21 +216278,48 @@ var init_register_auth_routes = __esm({
|
|
|
214951
216278
|
let autoPromptConsumed = false;
|
|
214952
216279
|
let authResolve;
|
|
214953
216280
|
let authReject;
|
|
216281
|
+
let authSettled = false;
|
|
214954
216282
|
const authUrlPromise = new Promise((resolve64, reject2) => {
|
|
214955
216283
|
authResolve = resolve64;
|
|
214956
216284
|
authReject = reject2;
|
|
214957
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;
|
|
214958
216297
|
const loginPromise = storage.login(provider, {
|
|
214959
216298
|
onAuth: (info) => {
|
|
214960
|
-
|
|
214961
|
-
|
|
214962
|
-
|
|
214963
|
-
|
|
214964
|
-
|
|
214965
|
-
|
|
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({
|
|
214966
216309
|
url: info.url,
|
|
214967
216310
|
instructions: appendManualCodeHint(info.instructions, provider, origin),
|
|
214968
|
-
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
|
|
214969
216323
|
});
|
|
214970
216324
|
},
|
|
214971
216325
|
onPrompt: async (_prompt) => {
|
|
@@ -214982,14 +216336,20 @@ var init_register_auth_routes = __esm({
|
|
|
214982
216336
|
onProgress: () => {
|
|
214983
216337
|
},
|
|
214984
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
|
+
},
|
|
214985
216345
|
signal: abortController.signal
|
|
214986
216346
|
});
|
|
214987
216347
|
const timeout2 = setTimeout(() => {
|
|
214988
|
-
|
|
216348
|
+
rejectAuthInfo(new Error("Login initiation timed out"));
|
|
214989
216349
|
}, 3e4);
|
|
214990
216350
|
loginPromise.then(() => {
|
|
214991
216351
|
}).catch((err) => {
|
|
214992
|
-
|
|
216352
|
+
rejectAuthInfo(err instanceof Error ? err : new Error(String(err)));
|
|
214993
216353
|
}).finally(() => {
|
|
214994
216354
|
clearTimeout(timeout2);
|
|
214995
216355
|
loginInProgress.delete(provider);
|
|
@@ -215906,6 +217266,32 @@ function validateBoolean(value, fieldName) {
|
|
|
215906
217266
|
}
|
|
215907
217267
|
return value;
|
|
215908
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
|
+
}
|
|
215909
217295
|
function validateOrderedIds(body) {
|
|
215910
217296
|
if (!body || typeof body !== "object") {
|
|
215911
217297
|
throw new Error("Request body must contain orderedIds array");
|
|
@@ -216005,22 +217391,20 @@ function createMissionRouter(store, missionAutopilot, aiSessionStore, missionExe
|
|
|
216005
217391
|
router.post(
|
|
216006
217392
|
"/",
|
|
216007
217393
|
catchTypedHandler(async (req, res) => {
|
|
216008
|
-
const { title, description, autoAdvance,
|
|
217394
|
+
const { title, description, autoAdvance, baseBranch, branchStrategy } = req.body;
|
|
216009
217395
|
const validatedTitle = validateTitle(title);
|
|
216010
217396
|
const validatedDescription = validateDescription2(description);
|
|
216011
217397
|
const input = {
|
|
216012
217398
|
title: validatedTitle,
|
|
216013
217399
|
description: validatedDescription,
|
|
216014
|
-
baseBranch: validateDescription2(baseBranch)
|
|
217400
|
+
baseBranch: validateDescription2(baseBranch),
|
|
217401
|
+
branchStrategy: validateMissionBranchStrategy(branchStrategy)
|
|
216015
217402
|
};
|
|
216016
217403
|
const mission = missionStore.createMission(input);
|
|
216017
217404
|
const updates = {};
|
|
216018
217405
|
if (autoAdvance !== void 0) {
|
|
216019
217406
|
updates.autoAdvance = validateBoolean(autoAdvance, "autoAdvance");
|
|
216020
217407
|
}
|
|
216021
|
-
if (autopilotEnabled !== void 0) {
|
|
216022
|
-
updates.autopilotEnabled = validateBoolean(autopilotEnabled, "autopilotEnabled");
|
|
216023
|
-
}
|
|
216024
217408
|
if (Object.keys(updates).length > 0) {
|
|
216025
217409
|
const updatedMission = missionStore.updateMission(mission.id, updates);
|
|
216026
217410
|
res.status(201).json(updatedMission);
|
|
@@ -216367,18 +217751,11 @@ function createMissionRouter(store, missionAutopilot, aiSessionStore, missionExe
|
|
|
216367
217751
|
status: "pending"
|
|
216368
217752
|
});
|
|
216369
217753
|
for (const featureData of sliceData.features ?? []) {
|
|
216370
|
-
|
|
217754
|
+
missionStore.addFeature(slice.id, {
|
|
216371
217755
|
title: featureData.title,
|
|
216372
217756
|
description: featureData.description,
|
|
216373
217757
|
acceptanceCriteria: featureData.acceptanceCriteria
|
|
216374
217758
|
});
|
|
216375
|
-
const assertionText = featureData.acceptanceCriteria || featureData.description || `Verify implementation of: ${featureData.title}`;
|
|
216376
|
-
const assertion = missionStore.addContractAssertion(milestone.id, {
|
|
216377
|
-
title: featureData.title,
|
|
216378
|
-
assertion: assertionText,
|
|
216379
|
-
status: "pending"
|
|
216380
|
-
});
|
|
216381
|
-
missionStore.linkFeatureToAssertion(feature.id, assertion.id);
|
|
216382
217759
|
}
|
|
216383
217760
|
}
|
|
216384
217761
|
missionStore.applyDerivedMilestoneAcceptanceCriteria(milestone.id);
|
|
@@ -216418,7 +217795,7 @@ function createMissionRouter(store, missionAutopilot, aiSessionStore, missionExe
|
|
|
216418
217795
|
"/:missionId",
|
|
216419
217796
|
catchTypedHandler(async (req, res) => {
|
|
216420
217797
|
const { missionId } = req.params;
|
|
216421
|
-
const { title, description, status, autoAdvance, autopilotEnabled, baseBranch } = req.body;
|
|
217798
|
+
const { title, description, status, autoAdvance, autopilotEnabled, baseBranch, branchStrategy } = req.body;
|
|
216422
217799
|
if (!validateMissionId(missionId)) {
|
|
216423
217800
|
throw badRequest("Invalid mission ID format");
|
|
216424
217801
|
}
|
|
@@ -216441,11 +217818,18 @@ function createMissionRouter(store, missionAutopilot, aiSessionStore, missionExe
|
|
|
216441
217818
|
if (baseBranch !== void 0) {
|
|
216442
217819
|
updates.baseBranch = validateDescription2(baseBranch);
|
|
216443
217820
|
}
|
|
217821
|
+
if (branchStrategy !== void 0) {
|
|
217822
|
+
updates.branchStrategy = validateMissionBranchStrategy(branchStrategy);
|
|
217823
|
+
}
|
|
216444
217824
|
if (Object.keys(updates).length === 0) {
|
|
216445
217825
|
throw badRequest("No valid fields to update");
|
|
216446
217826
|
}
|
|
216447
217827
|
try {
|
|
217828
|
+
const existingMission = missionStore.getMission(missionId);
|
|
216448
217829
|
const mission = missionStore.updateMission(missionId, updates);
|
|
217830
|
+
if (missionAutopilot && updates.autopilotEnabled === true && existingMission?.autopilotEnabled !== true) {
|
|
217831
|
+
missionAutopilot.watchMission(missionId);
|
|
217832
|
+
}
|
|
216449
217833
|
res.json(mission);
|
|
216450
217834
|
} catch (err) {
|
|
216451
217835
|
const errMsg = err instanceof Error ? err.message : String(err);
|
|
@@ -248129,6 +249513,7 @@ var init_mission = __esm({
|
|
|
248129
249513
|
var goals_exports = {};
|
|
248130
249514
|
__export(goals_exports, {
|
|
248131
249515
|
runGoalsArchive: () => runGoalsArchive,
|
|
249516
|
+
runGoalsCitations: () => runGoalsCitations,
|
|
248132
249517
|
runGoalsCreate: () => runGoalsCreate,
|
|
248133
249518
|
runGoalsList: () => runGoalsList
|
|
248134
249519
|
});
|
|
@@ -248207,6 +249592,31 @@ async function runGoalsCreate(titleArg, descriptionArg, projectName) {
|
|
|
248207
249592
|
throw error;
|
|
248208
249593
|
}
|
|
248209
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
|
+
}
|
|
248210
249620
|
async function runGoalsArchive(idArg, projectName) {
|
|
248211
249621
|
if (!idArg) {
|
|
248212
249622
|
console.error("Usage: fn goals archive <id>");
|
|
@@ -251437,7 +252847,7 @@ async function loadCommandHandlers() {
|
|
|
251437
252847
|
const { runBackupCreate: runBackupCreate2, runBackupList: runBackupList2, runBackupRestore: runBackupRestore2, runBackupCleanup: runBackupCleanup2 } = await Promise.resolve().then(() => (init_backup2(), backup_exports));
|
|
251438
252848
|
const { runMemoryBackupCreate: runMemoryBackupCreate2, runMemoryBackupList: runMemoryBackupList2, runMemoryBackupRestore: runMemoryBackupRestore2 } = await Promise.resolve().then(() => (init_memory_backup2(), memory_backup_exports));
|
|
251439
252849
|
const { runMissionCreate: runMissionCreate2, runMissionList: runMissionList2, runMissionShow: runMissionShow2, runMissionDelete: runMissionDelete2, runMissionActivateSlice: runMissionActivateSlice2 } = await Promise.resolve().then(() => (init_mission(), mission_exports));
|
|
251440
|
-
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));
|
|
251441
252851
|
const { runProjectList: runProjectList2, runProjectAdd: runProjectAdd2, runProjectRemove: runProjectRemove2, runProjectShow: runProjectShow2, runProjectInfo: runProjectInfo2, runProjectSetDefault: runProjectSetDefault2, runProjectDetect: runProjectDetect2 } = await Promise.resolve().then(() => (init_project(), project_exports));
|
|
251442
252852
|
const { runNodeList: runNodeList2, runNodeConnect: runNodeConnect2, runNodeDisconnect: runNodeDisconnect2, runNodeShow: runNodeShow2, runNodeHealth: runNodeHealth2, runMeshStatus: runMeshStatus2 } = await Promise.resolve().then(() => (init_node(), node_exports));
|
|
251443
252853
|
const { runInit: runInit2 } = await Promise.resolve().then(() => (init_init(), init_exports));
|
|
@@ -251505,6 +252915,7 @@ async function loadCommandHandlers() {
|
|
|
251505
252915
|
runGoalsList: runGoalsList2,
|
|
251506
252916
|
runGoalsCreate: runGoalsCreate2,
|
|
251507
252917
|
runGoalsArchive: runGoalsArchive2,
|
|
252918
|
+
runGoalsCitations: runGoalsCitations2,
|
|
251508
252919
|
runProjectList: runProjectList2,
|
|
251509
252920
|
runProjectAdd: runProjectAdd2,
|
|
251510
252921
|
runProjectRemove: runProjectRemove2,
|
|
@@ -251624,6 +253035,7 @@ PR:
|
|
|
251624
253035
|
fn goals list [--status STATE] List goals (default: active)
|
|
251625
253036
|
fn goals create [title] [desc] Create a new goal
|
|
251626
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)
|
|
251627
253039
|
fn project list | ls [--json] List all registered projects
|
|
251628
253040
|
fn project add [name] [path] [opts] Register a new project
|
|
251629
253041
|
fn project remove | rm <name> [--force]
|
|
@@ -251876,6 +253288,7 @@ async function main() {
|
|
|
251876
253288
|
runGoalsList: runGoalsList2,
|
|
251877
253289
|
runGoalsCreate: runGoalsCreate2,
|
|
251878
253290
|
runGoalsArchive: runGoalsArchive2,
|
|
253291
|
+
runGoalsCitations: runGoalsCitations2,
|
|
251879
253292
|
runProjectList: runProjectList2,
|
|
251880
253293
|
runProjectAdd: runProjectAdd2,
|
|
251881
253294
|
runProjectRemove: runProjectRemove2,
|
|
@@ -252641,9 +254054,21 @@ async function main() {
|
|
|
252641
254054
|
await runGoalsArchive2(id, projectName);
|
|
252642
254055
|
break;
|
|
252643
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
|
+
}
|
|
252644
254069
|
default:
|
|
252645
254070
|
console.error(`Unknown subcommand: goals ${subcommand || ""}`);
|
|
252646
|
-
console.log("Try: fn goals list | create | archive");
|
|
254071
|
+
console.log("Try: fn goals list | create | archive | citations");
|
|
252647
254072
|
process.exit(1);
|
|
252648
254073
|
}
|
|
252649
254074
|
break;
|