@farmslot/agent-runtime 0.5.1 → 0.6.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/CHANGELOG.md +4 -0
- package/package.json +2 -2
- package/scripts/checklist-target.cjs +71 -0
- package/scripts/mark-checklist-step.cjs +14 -24
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
+
## 0.6.0 - 2026-08-03
|
|
6
|
+
|
|
7
|
+
- fix(mark): step enumeration now skips informational sections (Acceptance Criteria, pre-merge, `<details>`) exactly like the gateway parsers — checkbox-formatted ACs no longer shift `mark N` onto the wrong box. Also tightens checkbox matching to `- [ ]` (no `* [ ]`), matching gateway behavior.
|
|
8
|
+
|
|
5
9
|
## 0.5.1 - 2026-08-02
|
|
6
10
|
|
|
7
11
|
- Align the published protocol dependency with 0.16.0 so downstream installs use one Recipe Protocol version.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@farmslot/agent-runtime",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
"prepublishOnly": "node ../../scripts/quality/check-farmslot-package-readiness.mjs --publish --packages @farmslot/agent-runtime"
|
|
33
33
|
},
|
|
34
34
|
"dependencies": {
|
|
35
|
-
"@farmslot/protocol": "0.
|
|
35
|
+
"@farmslot/protocol": "0.17.0"
|
|
36
36
|
},
|
|
37
37
|
"devDependencies": {
|
|
38
38
|
"@types/node": "^22.0.0",
|
|
@@ -12,6 +12,75 @@ const ROLE_SIGNAL_SUFFIX = '-SIGNAL.json';
|
|
|
12
12
|
const SELF_REVIEW_CHECKLIST = 'SELF-REVIEW.md';
|
|
13
13
|
const SELF_REVIEW_FIX_CHECKLIST = 'SELF-REVIEW-FIX.md';
|
|
14
14
|
const CI_FIX_CHECKLIST = 'CI-FIX.md';
|
|
15
|
+
// Sections whose checkboxes are informational (ACs, descriptions, upstream
|
|
16
|
+
// PR-template fields) — not task steps. Canonical copy lives in
|
|
17
|
+
// @farmslot/protocol/checklist-target CHECKLIST_SKIP_SECTIONS.
|
|
18
|
+
const CHECKLIST_SKIP_SECTIONS =
|
|
19
|
+
/^\**\s*(acceptance criteria|description|task|affected area|screenshots|comments|root cause|rules|recipe acs|pre-merge)/i;
|
|
20
|
+
|
|
21
|
+
// Behavioral mirror of @farmslot/protocol/checklist-target
|
|
22
|
+
// enumerateChecklistCheckboxes — the single definition of which markdown
|
|
23
|
+
// checkboxes are checklist steps. Any drift makes `mark N` check a different
|
|
24
|
+
// box than the one gateway progress reporting counts as step N (see
|
|
25
|
+
// test/checklist-target-sync.test.mjs for the parity fixture).
|
|
26
|
+
function enumerateChecklistCheckboxes(markdown) {
|
|
27
|
+
const items = [];
|
|
28
|
+
const lines = markdown.split('\n');
|
|
29
|
+
let inCodeBlock = false;
|
|
30
|
+
let inDetails = 0;
|
|
31
|
+
let inSkippedSection = false;
|
|
32
|
+
let phase = null;
|
|
33
|
+
let phaseIndex = -1;
|
|
34
|
+
let stepNumber = 0;
|
|
35
|
+
for (let lineIndex = 0; lineIndex < lines.length; lineIndex += 1) {
|
|
36
|
+
const trimmed = lines[lineIndex].trim();
|
|
37
|
+
if (trimmed.startsWith('```')) {
|
|
38
|
+
inCodeBlock = !inCodeBlock;
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
if (inCodeBlock) continue;
|
|
42
|
+
// Only lines STARTING with a details tag are structural — prose that
|
|
43
|
+
// mentions `<details>` (e.g. PR-description instructions) must stay inert.
|
|
44
|
+
// On a structural line, net opens minus closes handles both the plain
|
|
45
|
+
// one-liner (`<details>…</details>` opens nothing) and nested same-line
|
|
46
|
+
// opens that leave a block dangling.
|
|
47
|
+
if (trimmed.startsWith('<details')) {
|
|
48
|
+
const opens = (trimmed.match(/<details\b/g) || []).length;
|
|
49
|
+
const closes = (trimmed.match(/<\/details/g) || []).length;
|
|
50
|
+
inDetails = Math.max(0, inDetails + opens - closes);
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
if (trimmed.startsWith('</details')) {
|
|
54
|
+
inDetails = Math.max(0, inDetails - 1);
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
if (inDetails > 0) continue;
|
|
58
|
+
if (/^#{2,}\s+[^#]/.test(trimmed)) {
|
|
59
|
+
const name = trimmed.replace(/^#{2,}\s+/, '').trim();
|
|
60
|
+
if (CHECKLIST_SKIP_SECTIONS.test(name)) {
|
|
61
|
+
inSkippedSection = true;
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
inSkippedSection = false;
|
|
65
|
+
phase = name;
|
|
66
|
+
phaseIndex += 1;
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
if (inSkippedSection) continue;
|
|
70
|
+
const match = trimmed.match(/^- \[( |x|X)\]\s*(.*)$/);
|
|
71
|
+
if (!match) continue;
|
|
72
|
+
stepNumber += 1;
|
|
73
|
+
items.push({
|
|
74
|
+
lineIndex,
|
|
75
|
+
stepNumber,
|
|
76
|
+
checked: match[1].toLowerCase() === 'x',
|
|
77
|
+
phase,
|
|
78
|
+
phaseIndex,
|
|
79
|
+
rawLabel: match[2],
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
return items;
|
|
83
|
+
}
|
|
15
84
|
const WORKER_TERMINAL_CONTRACT_INPUT = path.join('inputs', 'worker-terminal-contract.json');
|
|
16
85
|
|
|
17
86
|
function signalFileForChecklist(checklistBasename) {
|
|
@@ -196,6 +265,8 @@ function resolveChecklistPaths(taskDir) {
|
|
|
196
265
|
}
|
|
197
266
|
|
|
198
267
|
module.exports = {
|
|
268
|
+
CHECKLIST_SKIP_SECTIONS,
|
|
269
|
+
enumerateChecklistCheckboxes,
|
|
199
270
|
CHECKLIST_TARGET_MANIFEST,
|
|
200
271
|
TASK_PROGRESS_MARKDOWN,
|
|
201
272
|
INTERACTIVE_CHECKLIST_MARKDOWN,
|
|
@@ -7,6 +7,7 @@ const {
|
|
|
7
7
|
resolveWorkerTerminalContract,
|
|
8
8
|
} = require('./worker-terminal-contract.cjs');
|
|
9
9
|
const {
|
|
10
|
+
enumerateChecklistCheckboxes,
|
|
10
11
|
parseTaskDirMarkArgs,
|
|
11
12
|
terminalContractInputForChecklist,
|
|
12
13
|
} = require('./checklist-target.cjs');
|
|
@@ -424,37 +425,26 @@ function stripLabel(raw) {
|
|
|
424
425
|
.trim();
|
|
425
426
|
}
|
|
426
427
|
|
|
428
|
+
// Step enumeration is shared with the gateway parsers (generateTaskSchema in
|
|
429
|
+
// tasks/writer.ts and parseCheckboxStates in methods/task.ts) via the
|
|
430
|
+
// checklist-target enumerator: same skip sections, <details> handling, and
|
|
431
|
+
// checkbox shape. Any divergence makes `mark N` check a different box than
|
|
432
|
+
// the one progress reporting counts as step N (checkbox-formatted Acceptance
|
|
433
|
+
// Criteria used to shift every step by the AC count).
|
|
427
434
|
function parseChecklist(markdown) {
|
|
428
435
|
const lines = markdown.split(/\n/);
|
|
429
|
-
const items =
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
if (/^\s*```/.test(lines[i])) {
|
|
434
|
-
inFence = !inFence;
|
|
435
|
-
continue;
|
|
436
|
-
}
|
|
437
|
-
if (inFence) continue;
|
|
438
|
-
const match = lines[i].match(/^(\s*[-*]\s+\[)( |x|X)(\]\s+)(.*)$/);
|
|
439
|
-
if (!match) continue;
|
|
440
|
-
seen += 1;
|
|
441
|
-
items.push({
|
|
442
|
-
lineIndex: i,
|
|
443
|
-
stepNumber: seen,
|
|
444
|
-
checked: match[2].toLowerCase() === 'x',
|
|
445
|
-
prefix: match[1],
|
|
446
|
-
suffix: match[3],
|
|
447
|
-
rawLabel: match[4],
|
|
448
|
-
label: stripLabel(match[4]),
|
|
449
|
-
});
|
|
450
|
-
}
|
|
436
|
+
const items = enumerateChecklistCheckboxes(markdown).map((item) => ({
|
|
437
|
+
...item,
|
|
438
|
+
label: stripLabel(item.rawLabel),
|
|
439
|
+
}));
|
|
451
440
|
return { lines, items };
|
|
452
441
|
}
|
|
453
442
|
|
|
454
443
|
function markStepInLines(lines, item) {
|
|
455
444
|
if (item.checked) return false;
|
|
456
|
-
lines[item.lineIndex]
|
|
457
|
-
|
|
445
|
+
const before = lines[item.lineIndex];
|
|
446
|
+
lines[item.lineIndex] = before.replace(/^(\s*- \[)( |x|X)(\])/, '$1x$3');
|
|
447
|
+
return lines[item.lineIndex] !== before;
|
|
458
448
|
}
|
|
459
449
|
|
|
460
450
|
function resolveTarget(taskPath, stepNumber, markLast) {
|