autodev-cli 1.4.97 → 1.4.101
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/media/profile/00-identity.md +8 -20
- package/media/profile/01-learning.md +12 -19
- package/media/profile/02-memory-mcp.md +4 -44
- package/media/profile/03-living-docs.md +10 -13
- package/media/profile/04-skill-files.md +3 -5
- package/media/profile/05-skill-creation.md +3 -14
- package/media/profile/06-core-rules.md +10 -47
- package/media/profile/07-core-loop.md +8 -25
- package/media/profile/08-thinking.md +10 -23
- package/media/profile/09-parallel-panel.md +9 -24
- package/media/profile/10-codebase-verification.md +7 -16
- package/media/profile/11-git-debug-security.md +5 -10
- package/media/profile/12-todo-format.md +3 -16
- package/media/profile/13-workflow-principles.md +3 -7
- package/media/profile/14-contracts.md +9 -12
- package/media/profile/15-soul.md +6 -8
- package/media/profile/16-journal.md +5 -32
- package/media/profile/17-issue-tracking.md +9 -14
- package/media/profile/18-knowledgebase.md +6 -9
- package/media/profile/19-subagent-context-management.md +11 -496
- package/media/profile/20-project-graph.md +23 -49
- package/out/commands/mcpOperate.js +150 -32
- package/out/commands/mcpOperate.js.map +1 -1
- package/out/core/controlSpec.d.ts +56 -0
- package/out/core/controlSpec.js +267 -0
- package/out/core/controlSpec.js.map +1 -0
- package/out/dispatcher.js +3 -1
- package/out/dispatcher.js.map +1 -1
- package/out/graphRender.d.ts +87 -0
- package/out/graphRender.js +279 -0
- package/out/graphRender.js.map +1 -0
- package/out/graphStore.d.ts +377 -2
- package/out/graphStore.js +1240 -64
- package/out/graphStore.js.map +1 -1
- package/out/journal.d.ts +35 -0
- package/out/journal.js +167 -0
- package/out/journal.js.map +1 -0
- package/out/messageBuilder.d.ts +1 -1
- package/out/messageBuilder.js +29 -29
- package/out/messageBuilder.js.map +1 -1
- package/out/periodicActions.d.ts +18 -0
- package/out/periodicActions.js +49 -0
- package/out/periodicActions.js.map +1 -1
- package/out/profileBuilder.d.ts +1 -1
- package/out/profileBuilder.js +31 -4
- package/out/profileBuilder.js.map +1 -1
- package/out/taskLoop.d.ts +19 -0
- package/out/taskLoop.js +214 -4
- package/out/taskLoop.js.map +1 -1
- package/package.json +2 -2
package/out/periodicActions.js
CHANGED
|
@@ -34,8 +34,47 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
36
|
exports.PeriodicActionManager = exports.PERIODIC_ACTIONS = void 0;
|
|
37
|
+
exports.dedupeMemoryIndex = dedupeMemoryIndex;
|
|
37
38
|
const fs = __importStar(require("fs"));
|
|
38
39
|
const path = __importStar(require("path"));
|
|
40
|
+
const journal_1 = require("./journal");
|
|
41
|
+
/**
|
|
42
|
+
* Deterministically de-duplicate the .autodev/MEMORY.md index. Removes repeated
|
|
43
|
+
* index lines (same target path) while preserving order and any header/prose.
|
|
44
|
+
* Returns a short note if it changed anything, else '' (no prompt change).
|
|
45
|
+
*/
|
|
46
|
+
function dedupeMemoryIndex(root) {
|
|
47
|
+
try {
|
|
48
|
+
const file = path.join(root, '.autodev', 'MEMORY.md');
|
|
49
|
+
if (!fs.existsSync(file)) {
|
|
50
|
+
return '';
|
|
51
|
+
}
|
|
52
|
+
const lines = fs.readFileSync(file, 'utf8').split(/\r?\n/);
|
|
53
|
+
const seen = new Set();
|
|
54
|
+
let removed = 0;
|
|
55
|
+
const out = [];
|
|
56
|
+
for (const ln of lines) {
|
|
57
|
+
const m = ln.match(/\]\(([^)]+)\)/); // markdown link target
|
|
58
|
+
if (ln.trim().startsWith('-') && m) {
|
|
59
|
+
const key = m[1].trim();
|
|
60
|
+
if (seen.has(key)) {
|
|
61
|
+
removed++;
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
seen.add(key);
|
|
65
|
+
}
|
|
66
|
+
out.push(ln);
|
|
67
|
+
}
|
|
68
|
+
if (removed > 0) {
|
|
69
|
+
fs.writeFileSync(file, out.join('\n'), 'utf8');
|
|
70
|
+
return `Memory index maintenance (deterministic): removed ${removed} duplicate index line(s) from .autodev/MEMORY.md.`;
|
|
71
|
+
}
|
|
72
|
+
return '';
|
|
73
|
+
}
|
|
74
|
+
catch {
|
|
75
|
+
return '';
|
|
76
|
+
}
|
|
77
|
+
}
|
|
39
78
|
exports.PERIODIC_ACTIONS = [
|
|
40
79
|
// ─── Compact context ─────────────────────────────────────────────────────
|
|
41
80
|
// ⚠️ WARNING: Auto-compact can cause INFINITE LOOPS!
|
|
@@ -72,6 +111,9 @@ exports.PERIODIC_ACTIONS = [
|
|
|
72
111
|
label: 'Update memory',
|
|
73
112
|
settingKey: 'memoryEveryNTasks',
|
|
74
113
|
icon: '🧠',
|
|
114
|
+
// Deterministic pre-pass: the extension maintains/dedupes the MEMORY.md index
|
|
115
|
+
// (mechanical work) so the model only does the durable-fact distillation below.
|
|
116
|
+
preprocess: dedupeMemoryIndex,
|
|
75
117
|
prompt: `Before continuing to the next task, consolidate what you have learned from recent tasks into the dated memory file system.
|
|
76
118
|
|
|
77
119
|
For each new durable fact (architectural discovery, decision, convention, gotcha, runbook, or bug fix) from recent work:
|
|
@@ -117,6 +159,13 @@ Do NOT store credentials in memory files — use Memory MCP for credentials. The
|
|
|
117
159
|
settingKey: 'journalLearnEveryNTasks',
|
|
118
160
|
icon: '🔬',
|
|
119
161
|
type: 'prompt',
|
|
162
|
+
// Deterministic pre-pass: tally keep/discard/partial from the now machine-readable
|
|
163
|
+
// journal rows and hand the model a compact digest instead of "scan every file".
|
|
164
|
+
// Returns '' (no prompt change) when there are no journal rows yet.
|
|
165
|
+
preprocess: (root) => {
|
|
166
|
+
const t = (0, journal_1.tallyJournal)(root);
|
|
167
|
+
return t ? t.digest : '';
|
|
168
|
+
},
|
|
120
169
|
prompt: `You are performing an autonomous research journal review. Follow these steps exactly:
|
|
121
170
|
|
|
122
171
|
1. Read .autodev/JOURNAL.md index. Open all journal files in .autodev/journals/ that do not yet have a '## Auto-learn' marker at the bottom.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"periodicActions.js","sourceRoot":"","sources":["../src/periodicActions.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"periodicActions.js","sourceRoot":"","sources":["../src/periodicActions.ts"],"names":[],"mappings":"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"}
|
package/out/profileBuilder.d.ts
CHANGED
|
@@ -12,7 +12,7 @@ export declare const PROFILE_SECTIONS: ProfileSection[];
|
|
|
12
12
|
/** Returns all section IDs in order — useful as the default "all enabled" value. */
|
|
13
13
|
export declare const ALL_SECTION_IDS: string[];
|
|
14
14
|
/**
|
|
15
|
-
* Assemble
|
|
15
|
+
* Assemble program.md as a compact **index**:
|
|
16
16
|
* - Each enabled section shows its key rules inline (immediate context).
|
|
17
17
|
* - A `@.autodev/profile/<file>` line lets agents load the full section on demand.
|
|
18
18
|
* - Full section files are copied to `<root>/.autodev/profile/` so the `@`
|
package/out/profileBuilder.js
CHANGED
|
@@ -249,7 +249,7 @@ function deploySectionFile(section, root) {
|
|
|
249
249
|
// Profile assembly — index format
|
|
250
250
|
// ---------------------------------------------------------------------------
|
|
251
251
|
/**
|
|
252
|
-
* Assemble
|
|
252
|
+
* Assemble program.md as a compact **index**:
|
|
253
253
|
* - Each enabled section shows its key rules inline (immediate context).
|
|
254
254
|
* - A `@.autodev/profile/<file>` line lets agents load the full section on demand.
|
|
255
255
|
* - Full section files are copied to `<root>/.autodev/profile/` so the `@`
|
|
@@ -264,10 +264,13 @@ function assembleProfileBody(enabledIds, root, customRefs = []) {
|
|
|
264
264
|
const ids = enabledIds && enabledIds.length > 0 ? enabledIds : exports.ALL_SECTION_IDS;
|
|
265
265
|
const orderedSections = exports.PROFILE_SECTIONS.filter(s => ids.includes(s.id));
|
|
266
266
|
const header = [
|
|
267
|
-
'# AutoDev
|
|
267
|
+
'# AutoDev — program.md',
|
|
268
268
|
'',
|
|
269
|
-
'>
|
|
270
|
-
'>
|
|
269
|
+
'> **Master index.** AGENTS.md / CLAUDE.md reference only this file; this file',
|
|
270
|
+
'> describes and links every AutoDev reference. Each section below shows its key',
|
|
271
|
+
'> rules inline and a `file://` link to the full section — **load a section only',
|
|
272
|
+
'> when the task needs it** (small-context-friendly). The control spec and the',
|
|
273
|
+
'> auto-mode loop tools are described at the end.',
|
|
271
274
|
'',
|
|
272
275
|
'---',
|
|
273
276
|
'',
|
|
@@ -280,12 +283,16 @@ function assembleProfileBody(enabledIds, root, customRefs = []) {
|
|
|
280
283
|
sectionPaths.push(refPath);
|
|
281
284
|
}
|
|
282
285
|
const rulesLines = section.keyRules.map(r => `- ${r}`).join('\n');
|
|
286
|
+
// The `file://` ref is what makes program.md self-contained now that the
|
|
287
|
+
// AGENTS.md block lists only program.md: the full section loads on demand.
|
|
288
|
+
const refLine = refPath ? `file://./${refPath.replace(/\\/g, '/')}` : '';
|
|
283
289
|
// Hash over key rules + ref so the marker changes if either is updated
|
|
284
290
|
const hash = md5(rulesLines + (refPath ?? ''));
|
|
285
291
|
const block = [
|
|
286
292
|
`<!-- AUTODEV:section:${section.id}:begin:md5=${hash} -->`,
|
|
287
293
|
`### ${section.label}`,
|
|
288
294
|
rulesLines,
|
|
295
|
+
...(refLine ? [` ↳ full: ${refLine}`] : []),
|
|
289
296
|
`<!-- AUTODEV:section:${section.id}:end -->`,
|
|
290
297
|
].join('\n');
|
|
291
298
|
parts.push(block);
|
|
@@ -306,6 +313,26 @@ function assembleProfileBody(enabledIds, root, customRefs = []) {
|
|
|
306
313
|
}).join('\n');
|
|
307
314
|
body += '\n';
|
|
308
315
|
}
|
|
316
|
+
// Runtime references: the control spec + the auto-mode loop tools. program.md
|
|
317
|
+
// "describes all other references", so these belong here alongside the sections.
|
|
318
|
+
body += [
|
|
319
|
+
'',
|
|
320
|
+
'---',
|
|
321
|
+
'',
|
|
322
|
+
'## Runtime — Control Spec & Auto-Mode Loop Tools',
|
|
323
|
+
'',
|
|
324
|
+
'- **Control spec** (optional): `file://./.autodev/CONTROL.md` — a per-project spec',
|
|
325
|
+
' (verify command, protected files, keep/revert rule, budget, escalation). When it',
|
|
326
|
+
' defines a `verify` command, the loop runs **verify_and_keep** after each task:',
|
|
327
|
+
' green → commit + mark `[x]`; red → auto-revert + reopen. With no control spec the',
|
|
328
|
+
' loop behaves normally. See skill `autodev-core-loop`.',
|
|
329
|
+
'- **Auto-mode cadence tools** — the loop runs these itself every N tasks (set N in',
|
|
330
|
+
' settings); you do NOT hand-run them: **memory-checkpoint** (persist memory + living',
|
|
331
|
+
' docs) and **autolearn** (distil JOURNAL rows → LESSONS/skills/conventions).',
|
|
332
|
+
'- **Journal** — records are appended deterministically (`journal_append`); do not',
|
|
333
|
+
' hand-format the table.',
|
|
334
|
+
'',
|
|
335
|
+
].join('\n');
|
|
309
336
|
// Always append SOUL.md reference so agents load their identity anchor first.
|
|
310
337
|
body += [
|
|
311
338
|
'',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"profileBuilder.js","sourceRoot":"","sources":["../src/profileBuilder.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6OA,
|
|
1
|
+
{"version":3,"file":"profileBuilder.js","sourceRoot":"","sources":["../src/profileBuilder.ts"],"names":[],"mappings":"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"}
|
package/out/taskLoop.d.ts
CHANGED
|
@@ -90,9 +90,28 @@ export declare class TaskLoopRunner {
|
|
|
90
90
|
private _profileSentCounter;
|
|
91
91
|
/** Manages all "every N tasks" periodic action counters. */
|
|
92
92
|
private readonly _periodicMgr;
|
|
93
|
+
/** Parsed .autodev/CONTROL.md, or null when absent (=> today's behavior). */
|
|
94
|
+
private _controlSpec;
|
|
95
|
+
/** taskKey → git HEAD sha captured before the task's FIRST dispatch (revert target). */
|
|
96
|
+
private _preTaskCommit;
|
|
97
|
+
/** taskKey → mechanical auto-fix passes already spent on this task. */
|
|
98
|
+
private _verifyMech;
|
|
99
|
+
/** A verify failure hint to fold into the NEXT dispatch of the matching task. */
|
|
100
|
+
private _pendingFixHint;
|
|
93
101
|
get state(): LoopState;
|
|
94
102
|
get currentTask(): string | undefined;
|
|
95
103
|
get resumeAt(): Date | undefined;
|
|
104
|
+
private _git;
|
|
105
|
+
/** Current HEAD sha, or '' if not a git repo / no commits. */
|
|
106
|
+
private _gitHead;
|
|
107
|
+
/** Hard-reset the working tree back to a previous commit (discard the task's work). */
|
|
108
|
+
private _gitResetHard;
|
|
109
|
+
/** Stage everything and commit; a no-op commit (nothing changed) is swallowed. */
|
|
110
|
+
private _gitCommitAll;
|
|
111
|
+
/** Files changed since `sha` (tracked diff + untracked), repo-relative. */
|
|
112
|
+
private _gitChangedFiles;
|
|
113
|
+
/** Compact "+A/-D" line-delta since `sha` for the journal ΔC column. */
|
|
114
|
+
private _gitDeltaComplexity;
|
|
96
115
|
/** Manually trigger a /compact on the current session for the given provider/root. */
|
|
97
116
|
compact(root: string, provider: ProviderId): Promise<void>;
|
|
98
117
|
/** Manually trigger a /clear on the current Claude session for the given provider/root. */
|
package/out/taskLoop.js
CHANGED
|
@@ -45,6 +45,8 @@ const prompt_1 = require("./prompt");
|
|
|
45
45
|
const messageBuilder_1 = require("./messageBuilder");
|
|
46
46
|
const webhook_1 = require("./webhook");
|
|
47
47
|
const settingsLoader_1 = require("./core/settingsLoader");
|
|
48
|
+
const controlSpec_1 = require("./core/controlSpec");
|
|
49
|
+
const journal_1 = require("./journal");
|
|
48
50
|
const dispatcher_1 = require("./dispatcher");
|
|
49
51
|
const opencodeCliProvider_1 = require("./providers/opencodeCliProvider");
|
|
50
52
|
const openCodeHooksManager_1 = require("./openCodeHooksManager");
|
|
@@ -218,9 +220,68 @@ class TaskLoopRunner {
|
|
|
218
220
|
_profileSentCounter = 0;
|
|
219
221
|
/** Manages all "every N tasks" periodic action counters. */
|
|
220
222
|
_periodicMgr = new periodicActions_1.PeriodicActionManager();
|
|
223
|
+
// ── autoresearch verify_and_keep gate (opt-in via .autodev/CONTROL.md) ──
|
|
224
|
+
// ALL of these are inert unless a CONTROL.md ships a `verify` command. With no
|
|
225
|
+
// spec (_controlSpec null / gate inactive) every path below is skipped and the
|
|
226
|
+
// loop behaves byte-for-byte as it does today.
|
|
227
|
+
/** Parsed .autodev/CONTROL.md, or null when absent (=> today's behavior). */
|
|
228
|
+
_controlSpec = null;
|
|
229
|
+
/** taskKey → git HEAD sha captured before the task's FIRST dispatch (revert target). */
|
|
230
|
+
_preTaskCommit = new Map();
|
|
231
|
+
/** taskKey → mechanical auto-fix passes already spent on this task. */
|
|
232
|
+
_verifyMech = new Map();
|
|
233
|
+
/** A verify failure hint to fold into the NEXT dispatch of the matching task. */
|
|
234
|
+
_pendingFixHint = null;
|
|
221
235
|
get state() { return this._state; }
|
|
222
236
|
get currentTask() { return this._currentTask; }
|
|
223
237
|
get resumeAt() { return this._resumeAt; }
|
|
238
|
+
// ── git primitives for the verify_and_keep gate ───────────────────────────
|
|
239
|
+
// Only ever called on gate-active paths (CONTROL.md present). All swallow
|
|
240
|
+
// errors so a non-git or dirty-index workspace never crashes the loop.
|
|
241
|
+
_git(root, args) {
|
|
242
|
+
try {
|
|
243
|
+
return (0, child_process_1.execSync)(`git ${args}`, { cwd: root, stdio: ['ignore', 'pipe', 'ignore'] }).toString().trim();
|
|
244
|
+
}
|
|
245
|
+
catch {
|
|
246
|
+
return '';
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
/** Current HEAD sha, or '' if not a git repo / no commits. */
|
|
250
|
+
_gitHead(root) { return this._git(root, 'rev-parse HEAD'); }
|
|
251
|
+
/** Hard-reset the working tree back to a previous commit (discard the task's work). */
|
|
252
|
+
_gitResetHard(root, sha) {
|
|
253
|
+
if (sha) {
|
|
254
|
+
this._git(root, `reset --hard ${sha}`);
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
/** Stage everything and commit; a no-op commit (nothing changed) is swallowed. */
|
|
258
|
+
_gitCommitAll(root, message) {
|
|
259
|
+
this._git(root, 'add -A');
|
|
260
|
+
const safe = message.replace(/"/g, "'").split('\n')[0].slice(0, 200);
|
|
261
|
+
this._git(root, `commit -m "${safe}"`);
|
|
262
|
+
}
|
|
263
|
+
/** Files changed since `sha` (tracked diff + untracked), repo-relative. */
|
|
264
|
+
_gitChangedFiles(root, sha) {
|
|
265
|
+
const diff = this._git(root, `diff --name-only ${sha}`);
|
|
266
|
+
const untracked = this._git(root, 'ls-files --others --exclude-standard');
|
|
267
|
+
const set = new Set();
|
|
268
|
+
for (const f of (diff + '\n' + untracked).split(/\r?\n/)) {
|
|
269
|
+
if (f.trim()) {
|
|
270
|
+
set.add(f.trim());
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
return [...set];
|
|
274
|
+
}
|
|
275
|
+
/** Compact "+A/-D" line-delta since `sha` for the journal ΔC column. */
|
|
276
|
+
_gitDeltaComplexity(root, sha) {
|
|
277
|
+
const stat = this._git(root, `diff --shortstat ${sha}`);
|
|
278
|
+
const ins = stat.match(/(\d+) insertion/);
|
|
279
|
+
const del = stat.match(/(\d+) deletion/);
|
|
280
|
+
if (!ins && !del) {
|
|
281
|
+
return '-';
|
|
282
|
+
}
|
|
283
|
+
return `+${ins ? ins[1] : 0}/-${del ? del[1] : 0}`;
|
|
284
|
+
}
|
|
224
285
|
/** Manually trigger a /compact on the current session for the given provider/root. */
|
|
225
286
|
async compact(root, provider) {
|
|
226
287
|
const log = (m) => this._cb?.log(m);
|
|
@@ -358,6 +419,15 @@ class TaskLoopRunner {
|
|
|
358
419
|
this._profileSentCounter = 0;
|
|
359
420
|
this._periodicMgr.resetAndPersist(callbacks.workspaceRoot);
|
|
360
421
|
this._hookLineSeen.clear();
|
|
422
|
+
// Load the opt-in control spec. Absent file ⇒ null ⇒ verify_and_keep gate,
|
|
423
|
+
// pre-task snapshots, and revert logic all stay dormant (today's behavior).
|
|
424
|
+
this._controlSpec = callbacks.workspaceRoot ? (0, controlSpec_1.loadControlSpec)(callbacks.workspaceRoot) : null;
|
|
425
|
+
this._preTaskCommit.clear();
|
|
426
|
+
this._verifyMech.clear();
|
|
427
|
+
this._pendingFixHint = null;
|
|
428
|
+
if ((0, controlSpec_1.isGateActive)(this._controlSpec)) {
|
|
429
|
+
callbacks.log(`🧪 verify_and_keep gate ENABLED — verify: ${this._controlSpec.verify.join(' && ')} (max_fix_rounds=${this._controlSpec.max_fix_rounds})`);
|
|
430
|
+
}
|
|
361
431
|
this._setState('running');
|
|
362
432
|
const settings = (0, settingsLoader_1.loadSettingsForRoot)(callbacks.workspaceRoot);
|
|
363
433
|
// Honor the runtime `-p <provider>` flag when reporting presence. The SDK
|
|
@@ -1498,9 +1568,30 @@ class TaskLoopRunner {
|
|
|
1498
1568
|
this._blockedTasks.delete(taskKey);
|
|
1499
1569
|
const attempts = (this._taskAttempts.get(taskKey) ?? 0) + 1;
|
|
1500
1570
|
this._taskAttempts.set(taskKey, attempts);
|
|
1501
|
-
|
|
1571
|
+
// With the verify gate active, the attempt ceiling becomes the fix-round
|
|
1572
|
+
// budget (initial dispatch + max_fix_rounds + mechanical headroom). Without
|
|
1573
|
+
// a CONTROL.md this is EXACTLY settings.maxTaskAttempts ?? 3 as before.
|
|
1574
|
+
const maxAttempts = (0, controlSpec_1.isGateActive)(this._controlSpec)
|
|
1575
|
+
? 1 + this._controlSpec.max_fix_rounds + this._controlSpec.max_mechanical_fixes
|
|
1576
|
+
: (settings.maxTaskAttempts ?? 3);
|
|
1502
1577
|
if (attempts > maxAttempts) {
|
|
1503
1578
|
this._taskAttempts.delete(taskKey);
|
|
1579
|
+
// Verify gate exhaustion: revert the task's work to its pre-task commit
|
|
1580
|
+
// and journal a discard BEFORE moving on, so no red change is kept.
|
|
1581
|
+
if ((0, controlSpec_1.isGateActive)(this._controlSpec) && this._workspaceRoot) {
|
|
1582
|
+
const pre = this._preTaskCommit.get(taskKey);
|
|
1583
|
+
if (pre) {
|
|
1584
|
+
this._gitResetHard(this._workspaceRoot, pre);
|
|
1585
|
+
this._cb?.log(`↩️ verify gate: fix rounds exhausted — reverted to ${pre.slice(0, 7)} and discarded: ${task.text}`);
|
|
1586
|
+
}
|
|
1587
|
+
(0, journal_1.appendJournalRow)(this._workspaceRoot, {
|
|
1588
|
+
task: discordLabel(task.text), status: 'discard',
|
|
1589
|
+
outcome: 'verify never green', notes: `exhausted ${maxAttempts} attempt(s)`,
|
|
1590
|
+
});
|
|
1591
|
+
this._preTaskCommit.delete(taskKey);
|
|
1592
|
+
this._verifyMech.delete(taskKey);
|
|
1593
|
+
this._pendingFixHint = null;
|
|
1594
|
+
}
|
|
1504
1595
|
this._cb?.log(`⚠️ Task not marked done after ${maxAttempts} attempt(s) — force-marking complete: ${task.text}`);
|
|
1505
1596
|
this._notifyDiscord(`⚠️ Task force-marked done after ${maxAttempts} failed attempt(s):\n${task.text}`);
|
|
1506
1597
|
await todoWriteManager_1.todoWriter.markDone(todoPath, task).catch(() => { });
|
|
@@ -1528,8 +1619,31 @@ class TaskLoopRunner {
|
|
|
1528
1619
|
}
|
|
1529
1620
|
this._profileSentCounter++;
|
|
1530
1621
|
// Build prompt (needed even when not sending, for messageFile path)
|
|
1531
|
-
|
|
1622
|
+
let { prompt, messageFile } = (0, prompt_1.buildPrompt)(task, this._workspaceRoot, path.dirname(todoPath), includeProfile);
|
|
1532
1623
|
const remaining = (0, todo_1.countRemaining)((0, todo_1.parseTodo)(todoPath));
|
|
1624
|
+
// ── verify_and_keep: pre-task snapshot + fold in any fix hint ──────────
|
|
1625
|
+
// Both are no-ops unless a CONTROL.md ships a verify command.
|
|
1626
|
+
if ((0, controlSpec_1.isGateActive)(this._controlSpec) && this._workspaceRoot && !watchingInProgress) {
|
|
1627
|
+
const gateKey = task.id ?? task.text;
|
|
1628
|
+
// Snapshot the commit to revert to — only on the FIRST dispatch of a task.
|
|
1629
|
+
if (!this._preTaskCommit.has(gateKey)) {
|
|
1630
|
+
const head = this._gitHead(this._workspaceRoot);
|
|
1631
|
+
if (head) {
|
|
1632
|
+
this._preTaskCommit.set(gateKey, head);
|
|
1633
|
+
}
|
|
1634
|
+
}
|
|
1635
|
+
// A prior red verify left a fix hint for this task — fold it into the prompt
|
|
1636
|
+
// so the retried dispatch sees the failure and what to fix.
|
|
1637
|
+
if (this._pendingFixHint && this._pendingFixHint.key === gateKey) {
|
|
1638
|
+
const combined = `${prompt}\n\n---\n${this._pendingFixHint.text}`;
|
|
1639
|
+
try {
|
|
1640
|
+
messageFile = (0, messageBuilder_1.writeMessageFile)(this._workspaceRoot, combined);
|
|
1641
|
+
}
|
|
1642
|
+
catch { /* keep original */ }
|
|
1643
|
+
prompt = combined;
|
|
1644
|
+
this._pendingFixHint = null;
|
|
1645
|
+
}
|
|
1646
|
+
}
|
|
1533
1647
|
if (!watchingInProgress) {
|
|
1534
1648
|
this._cb?.log(`▶ Task [${this._iterations}]: ${task.text}`);
|
|
1535
1649
|
this._idleNotified = false;
|
|
@@ -1760,6 +1874,86 @@ class TaskLoopRunner {
|
|
|
1760
1874
|
}
|
|
1761
1875
|
this._cb?.log(`Session ID captured for ${activeProvider}`);
|
|
1762
1876
|
}
|
|
1877
|
+
// ── verify_and_keep gate (autoresearch) ────────────────────────────
|
|
1878
|
+
// OPT-IN + NON-BREAKING: this entire block is skipped unless a
|
|
1879
|
+
// .autodev/CONTROL.md ships a `verify` command (isGateActive === false
|
|
1880
|
+
// otherwise). When skipped, control drops straight into the UNCHANGED
|
|
1881
|
+
// completion path below — byte-for-byte today's behavior.
|
|
1882
|
+
{
|
|
1883
|
+
const spec = this._controlSpec;
|
|
1884
|
+
if ((0, controlSpec_1.isGateActive)(spec) && this._workspaceRoot) {
|
|
1885
|
+
const root = this._workspaceRoot;
|
|
1886
|
+
const gateKey = task.id ?? task.text;
|
|
1887
|
+
const preCommit = this._preTaskCommit.get(gateKey);
|
|
1888
|
+
const elapsedSec = Math.round((Date.now() - taskStartTime) / 1000);
|
|
1889
|
+
const discardAndMoveOn = (reason, outcome) => {
|
|
1890
|
+
if (preCommit) {
|
|
1891
|
+
this._gitResetHard(root, preCommit);
|
|
1892
|
+
}
|
|
1893
|
+
(0, journal_1.appendJournalRow)(root, { task: discordLabel(task.text), status: 'discard', outcome, notes: reason });
|
|
1894
|
+
this._preTaskCommit.delete(gateKey);
|
|
1895
|
+
this._verifyMech.delete(gateKey);
|
|
1896
|
+
this._pendingFixHint = null;
|
|
1897
|
+
this._taskAttempts.delete(gateKey);
|
|
1898
|
+
};
|
|
1899
|
+
// (a) budget kill — only when budget_seconds is set.
|
|
1900
|
+
if (spec.budget_seconds != null && elapsedSec > spec.budget_seconds) {
|
|
1901
|
+
this._cb?.log(`⏱️ verify gate: task over budget (${elapsedSec}s > ${spec.budget_seconds}s) — discard+revert`);
|
|
1902
|
+
this._notifyDiscord(`⏱️ Task over budget (${elapsedSec}s) — reverted & discarded:\n${discordLabel(task.text)}`);
|
|
1903
|
+
discardAndMoveOn(`budget ${spec.budget_seconds}s exceeded`, 'over budget');
|
|
1904
|
+
await todoWriteManager_1.todoWriter.markDone(todoPath, task).catch(() => { }); // move on; code already reverted
|
|
1905
|
+
this._completedCount++;
|
|
1906
|
+
continue;
|
|
1907
|
+
}
|
|
1908
|
+
// (b) protected_files guard — only when protected_files is set.
|
|
1909
|
+
if (preCommit && spec.protected_files.length) {
|
|
1910
|
+
const changed = this._gitChangedFiles(root, preCommit);
|
|
1911
|
+
const hit = changed.find(f => (0, controlSpec_1.matchesAnyGlob)(f, spec.protected_files));
|
|
1912
|
+
if (hit) {
|
|
1913
|
+
this._cb?.log(`🛡️ verify gate: task touched protected file '${hit}' — discard+revert`);
|
|
1914
|
+
this._notifyDiscord(`🛡️ Reverted: task edited protected file \`${hit}\`:\n${discordLabel(task.text)}`);
|
|
1915
|
+
discardAndMoveOn(`touched protected file ${hit}`, 'protected file edited');
|
|
1916
|
+
await todoWriteManager_1.todoWriter.markDone(todoPath, task).catch(() => { });
|
|
1917
|
+
this._completedCount++;
|
|
1918
|
+
continue;
|
|
1919
|
+
}
|
|
1920
|
+
}
|
|
1921
|
+
// (c) run verify. GREEN → advance branch + keep. RED → re-dispatch a fix.
|
|
1922
|
+
const timeoutMs = spec.budget_seconds != null ? spec.budget_seconds * 1000 : 15 * 60_000;
|
|
1923
|
+
this._cb?.log(`🧪 verify: ${spec.verify.join(' && ')}`);
|
|
1924
|
+
const vr = (0, controlSpec_1.runVerify)(spec.verify, root, timeoutMs);
|
|
1925
|
+
if (vr.ok) {
|
|
1926
|
+
const deltaC = preCommit ? this._gitDeltaComplexity(root, preCommit) : '-';
|
|
1927
|
+
this._gitCommitAll(root, `autodev: ${discordLabel(task.text)}`);
|
|
1928
|
+
(0, journal_1.appendJournalRow)(root, { task: discordLabel(task.text), status: 'keep', outcome: 'verify green', deltaComplexity: deltaC });
|
|
1929
|
+
this._preTaskCommit.delete(gateKey);
|
|
1930
|
+
this._verifyMech.delete(gateKey);
|
|
1931
|
+
this._cb?.log('✅ verify GREEN — kept');
|
|
1932
|
+
// fall through to the unchanged completion path.
|
|
1933
|
+
}
|
|
1934
|
+
else {
|
|
1935
|
+
// RED — leave a fix hint and re-dispatch the SAME task. The top-of-loop
|
|
1936
|
+
// attempt ceiling (raised to the fix budget while the gate is active)
|
|
1937
|
+
// bounds retries and performs the final revert+discard on exhaustion.
|
|
1938
|
+
const mechUsed = this._verifyMech.get(gateKey) ?? 0;
|
|
1939
|
+
const mechanical = (0, controlSpec_1.isMechanicalFailure)(vr.output);
|
|
1940
|
+
let tier = 'fix';
|
|
1941
|
+
if (mechanical && mechUsed < spec.max_mechanical_fixes) {
|
|
1942
|
+
this._verifyMech.set(gateKey, mechUsed + 1);
|
|
1943
|
+
tier = 'mechanical-fix';
|
|
1944
|
+
}
|
|
1945
|
+
const errTail = vr.output.length > 2000 ? '…' + vr.output.slice(-2000) : vr.output;
|
|
1946
|
+
this._pendingFixHint = {
|
|
1947
|
+
key: gateKey,
|
|
1948
|
+
text: `⚠️ AUTOMATED VERIFY FAILED (exit ${vr.code}${vr.timedOut ? ', TIMED OUT' : ''}). Your change is NOT accepted until \`${spec.verify.join(' && ')}\` passes. Fix the failure shown below${tier === 'mechanical-fix' ? ' (this looks mechanical — a type/import/syntax error)' : ''}, then re-complete the SAME task.\n\n\`\`\`\n${errTail}\n\`\`\``,
|
|
1949
|
+
};
|
|
1950
|
+
await todoWriteManager_1.todoWriter.resetToTodo(todoPath, task).catch(() => { });
|
|
1951
|
+
this._cb?.log(`❌ verify RED (exit ${vr.code}) — re-dispatching ${tier}: ${task.text}`);
|
|
1952
|
+
this._notifyDiscord(`❌ Verify failed — retrying (${tier}):\n${discordLabel(task.text)}`);
|
|
1953
|
+
continue;
|
|
1954
|
+
}
|
|
1955
|
+
}
|
|
1956
|
+
}
|
|
1763
1957
|
const duration = Math.round((Date.now() - taskStartTime) / 1000);
|
|
1764
1958
|
this._completedCount++;
|
|
1765
1959
|
this._autoCompactCounter++;
|
|
@@ -1767,6 +1961,8 @@ class TaskLoopRunner {
|
|
|
1767
1961
|
this._periodicMgr.increment(this._iterations, this._workspaceRoot);
|
|
1768
1962
|
this._compactedTaskLines.delete(task.line); // allow compact again if task re-appears
|
|
1769
1963
|
this._taskAttempts.delete(task.id ?? task.text); // task done — reset attempt counter
|
|
1964
|
+
this._preTaskCommit.delete(task.id ?? task.text); // gate bookkeeping (no-op without CONTROL.md)
|
|
1965
|
+
this._verifyMech.delete(task.id ?? task.text);
|
|
1770
1966
|
const afterTasks = (0, todo_1.parseTodo)(todoPath);
|
|
1771
1967
|
const afterRemaining = (0, todo_1.countRemaining)(afterTasks);
|
|
1772
1968
|
const totalKnown = this._iterations + afterRemaining;
|
|
@@ -1946,8 +2142,22 @@ class TaskLoopRunner {
|
|
|
1946
2142
|
}
|
|
1947
2143
|
}
|
|
1948
2144
|
else {
|
|
1949
|
-
|
|
1950
|
-
|
|
2145
|
+
// Deterministic pre-pass (if any): the extension does the mechanical
|
|
2146
|
+
// file-scan/index-maintenance and returns a compact digest that is
|
|
2147
|
+
// PREPENDED to the model prompt. Empty digest ⇒ prompt unchanged
|
|
2148
|
+
// (byte-identical to before for low-activity agents).
|
|
2149
|
+
let digest = '';
|
|
2150
|
+
if (action.preprocess && this._workspaceRoot) {
|
|
2151
|
+
try {
|
|
2152
|
+
digest = action.preprocess(this._workspaceRoot) || '';
|
|
2153
|
+
}
|
|
2154
|
+
catch (ppErr) {
|
|
2155
|
+
this._cb?.log(`⚠️ Periodic pre-pass '${action.id}' failed (non-fatal): ${ppErr instanceof Error ? ppErr.message : String(ppErr)}`);
|
|
2156
|
+
}
|
|
2157
|
+
}
|
|
2158
|
+
const finalPrompt = digest ? `${digest}\n\n${action.prompt}` : action.prompt;
|
|
2159
|
+
const msgFile = (0, messageBuilder_1.writeMessageFile)(this._workspaceRoot, finalPrompt);
|
|
2160
|
+
await this._cb.sendToAi(finalPrompt, action.id, false, msgFile);
|
|
1951
2161
|
}
|
|
1952
2162
|
}
|
|
1953
2163
|
catch (paErr) {
|