peaks-loop 3.1.0 → 3.1.2
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 +44 -0
- package/dist/src/cli/commands/job-commands.js +54 -1
- package/dist/src/cli/commands/solo-commands.js +375 -12
- package/dist/src/services/job/job-progress-store.d.ts +60 -0
- package/dist/src/services/job/job-progress-store.js +70 -0
- package/dist/src/services/job/job-types.d.ts +4 -4
- package/dist/src/services/solo/emit-handoff.d.ts +49 -0
- package/dist/src/services/solo/emit-handoff.js +79 -0
- package/dist/src/services/solo/job-shape-decision.d.ts +71 -0
- package/dist/src/services/solo/job-shape-decision.js +151 -0
- package/dist/src/services/solo/step-08-gate.d.ts +90 -0
- package/dist/src/services/solo/step-08-gate.js +136 -0
- package/dist/src/services/workspace/claude-settings-template.d.ts +6 -1
- package/dist/src/services/workspace/claude-settings-template.js +40 -1
- package/dist/src/shared/version.d.ts +1 -1
- package/dist/src/shared/version.js +1 -1
- package/package.json +1 -1
- package/skills/peaks-solo/SKILL.md +49 -87
- package/skills/peaks-solo/references/runbook.md +46 -1
- package/skills/peaks-solo/references/step-0-8-gate.md +60 -0
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* v3.1.2 Step 0.8 — Mechanical PreToolUse gate.
|
|
3
|
+
*
|
|
4
|
+
* Wire-installed by `peaks workspace init` (extends the existing hook
|
|
5
|
+
* installer; does NOT replace the Write|Edit|MultiEdit fact-forcing
|
|
6
|
+
* bypass). The hook runs `peaks solo gate-step-08 --project .` before
|
|
7
|
+
* every Bash tool call. Exit code is the load-bearing contract:
|
|
8
|
+
*
|
|
9
|
+
* exit 0 → allow (with structured stdout describing the decision)
|
|
10
|
+
* exit 2 → block (stderr contains the BLOCKED: ... reason)
|
|
11
|
+
*
|
|
12
|
+
* Three decision paths:
|
|
13
|
+
*
|
|
14
|
+
* 1. `job-shape.json` exists with `decision.isJob === true`.
|
|
15
|
+
* → allow, print `{ ok, allow, mode: 'job', decision }`. When a
|
|
16
|
+
* matching `job/<jid>/progress.json` exists, also print
|
|
17
|
+
* `Next: slice #<N+1> of <M> (<currentSlice>)` so the LLM sees
|
|
18
|
+
* its resume context BEFORE any Bash call lands.
|
|
19
|
+
* 2. `job-shape.json` exists with `decision.isJob === false`.
|
|
20
|
+
* → allow, print `{ ok, allow, mode: 'single' }`.
|
|
21
|
+
* 3. `job-shape.json` is MISSING — fail-closed guard. The LLM is the
|
|
22
|
+
* source of truth, but if it never recorded a decision we run a
|
|
23
|
+
* lightweight backup regex against the user's prompt:
|
|
24
|
+
* /until|全部|until all done|disavow cost|不用考虑费用|all of them/i
|
|
25
|
+
* match → block (exit 2) with the BLOCKED: stderr message.
|
|
26
|
+
* no match → allow (exit 0) — most prompts are not Job-shaped.
|
|
27
|
+
*
|
|
28
|
+
* Karpathy §2 (Simplicity First): ~120 lines, no LLM call inside. The
|
|
29
|
+
* regex is the FIRST time peaks-loop accepts hardcoded keywords —
|
|
30
|
+
* explicitly scoped as a *fail-closed backup* (case 3), NOT a primary
|
|
31
|
+
* judgement. The LLM still owns the semantic call via
|
|
32
|
+
* `peaks solo detect-job`. The regex is a safety net for the v3.1.1
|
|
33
|
+
* incident class (LLM under load never records the decision at all).
|
|
34
|
+
*/
|
|
35
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
36
|
+
import { join } from 'node:path';
|
|
37
|
+
import { readJobShapeDecision, JobShapeDecisionError, JOB_SHAPE_NOT_DECIDED } from './job-shape-decision.js';
|
|
38
|
+
export const STEP_08_GATE_FILE_NAME = 'job-shape.json';
|
|
39
|
+
export const STEP_08_PROGRESS_FILE_NAME = 'progress.json';
|
|
40
|
+
/**
|
|
41
|
+
* Fail-closed backup regex — see module docstring case 3 for why this
|
|
42
|
+
* exists. Kept short and explicit; if the prompt mentions any of these
|
|
43
|
+
* triggers and `job-shape.json` is missing, the LLM is treated as
|
|
44
|
+
* having skipped `peaks solo detect-job` and the gate blocks.
|
|
45
|
+
*
|
|
46
|
+
* The list mirrors the v3.1.0 / v3.1.1 incident triggers verbatim:
|
|
47
|
+
* 继续执行下个 slice (until next slice) → until / 直到
|
|
48
|
+
* 全部添加完 / all of them → 全部 / all of them
|
|
49
|
+
* 不用考虑费用 → 不用考虑费用 / disavow cost
|
|
50
|
+
* until all done → until all done
|
|
51
|
+
*/
|
|
52
|
+
export const STEP_08_BACKUP_REGEX = /直到|全部|until all done|disavow cost|不用考虑费用|all of them/i;
|
|
53
|
+
export function runtimeSessionDir(projectRoot, sessionId) {
|
|
54
|
+
return join(projectRoot, '.peaks', '_runtime', sessionId);
|
|
55
|
+
}
|
|
56
|
+
function progressPath(projectRoot, sessionId, jid) {
|
|
57
|
+
// The progress file lives under job/<jid>/progress.json. The jid
|
|
58
|
+
// comes from job-shape.json (decision.suggestedJobId) — there is
|
|
59
|
+
// exactly one canonical jid per session under Job mode, so we read
|
|
60
|
+
// the matching path directly rather than enumerating the job/ dir.
|
|
61
|
+
// (Rotating mode spawns new jids but only one is "active" at a time;
|
|
62
|
+
// the active jid is the latest write to job-shape.json.)
|
|
63
|
+
return join(runtimeSessionDir(projectRoot, sessionId), 'job', jid, STEP_08_PROGRESS_FILE_NAME);
|
|
64
|
+
}
|
|
65
|
+
function readProgressIfAny(projectRoot, sessionId, jid) {
|
|
66
|
+
const path = progressPath(projectRoot, sessionId, jid);
|
|
67
|
+
if (!existsSync(path))
|
|
68
|
+
return null;
|
|
69
|
+
try {
|
|
70
|
+
const raw = readFileSync(path, 'utf8');
|
|
71
|
+
const parsed = JSON.parse(raw);
|
|
72
|
+
if (typeof parsed.jobId === 'string' &&
|
|
73
|
+
typeof parsed.done === 'number' &&
|
|
74
|
+
typeof parsed.total === 'number' &&
|
|
75
|
+
typeof parsed.currentSlice === 'string' &&
|
|
76
|
+
typeof parsed.updatedAt === 'string') {
|
|
77
|
+
return {
|
|
78
|
+
jobId: parsed.jobId,
|
|
79
|
+
done: parsed.done,
|
|
80
|
+
total: parsed.total,
|
|
81
|
+
currentSlice: parsed.currentSlice,
|
|
82
|
+
lastCommitSha: typeof parsed.lastCommitSha === 'string' ? parsed.lastCommitSha : null,
|
|
83
|
+
updatedAt: parsed.updatedAt
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
return null;
|
|
87
|
+
}
|
|
88
|
+
catch { // TODO(g2): legacy silent catch — grace: 1 minor release (v2.14.0)
|
|
89
|
+
return null;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
function readPromptFromLastPromptFile(projectRoot, sessionId) {
|
|
93
|
+
const path = join(runtimeSessionDir(projectRoot, sessionId), 'txt', 'last-prompt.txt');
|
|
94
|
+
if (!existsSync(path))
|
|
95
|
+
return '';
|
|
96
|
+
try {
|
|
97
|
+
return readFileSync(path, 'utf8');
|
|
98
|
+
}
|
|
99
|
+
catch {
|
|
100
|
+
return '';
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Pure evaluator — does NOT write, does NOT exit. CLI wrapper in
|
|
105
|
+
* `src/cli/commands/solo-commands.ts` reads `allow` to set the process
|
|
106
|
+
* exit code (0 allow / 2 block) and prints the structured envelope.
|
|
107
|
+
*/
|
|
108
|
+
export function evaluateStep08(input) {
|
|
109
|
+
try {
|
|
110
|
+
const record = readJobShapeDecision(input.projectRoot, input.sessionId);
|
|
111
|
+
if (record.decision.isJob) {
|
|
112
|
+
const progress = readProgressIfAny(input.projectRoot, input.sessionId, record.decision.suggestedJobId);
|
|
113
|
+
const nextSliceLine = progress !== null
|
|
114
|
+
? `Next: slice #${progress.done + 1} of ${progress.total} (${progress.currentSlice})`
|
|
115
|
+
: null;
|
|
116
|
+
return {
|
|
117
|
+
allow: true,
|
|
118
|
+
verdict: { kind: 'allow-job', decision: record.decision, progress },
|
|
119
|
+
nextSliceLine
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
return { allow: true, verdict: { kind: 'allow-single' }, nextSliceLine: null };
|
|
123
|
+
}
|
|
124
|
+
catch (err) {
|
|
125
|
+
if (err instanceof JobShapeDecisionError && err.code === JOB_SHAPE_NOT_DECIDED) {
|
|
126
|
+
const promptText = input.prompt ?? readPromptFromLastPromptFile(input.projectRoot, input.sessionId);
|
|
127
|
+
const hit = promptText.length > 0 && STEP_08_BACKUP_REGEX.test(promptText);
|
|
128
|
+
const source = input.prompt !== undefined ? 'flag' : promptText.length > 0 ? 'last-prompt-file' : 'stdin-empty';
|
|
129
|
+
if (hit) {
|
|
130
|
+
return { allow: false, verdict: { kind: 'block-missing-decision', promptHit: true, promptSource: source }, nextSliceLine: null };
|
|
131
|
+
}
|
|
132
|
+
return { allow: true, verdict: { kind: 'block-missing-decision', promptHit: false, promptSource: source }, nextSliceLine: null };
|
|
133
|
+
}
|
|
134
|
+
throw err;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
@@ -50,8 +50,13 @@ export declare const CLAUDE_SETTINGS_LOCAL_FILENAME = ".claude/settings.local.js
|
|
|
50
50
|
* 1.2.0 — removed the `Bash` matcher; Edit/Write fact-forcing
|
|
51
51
|
* bypass is the only emit. Bash enforcement is owned by
|
|
52
52
|
* `peaks gate enforce` in `settings.json`.
|
|
53
|
+
* 1.3.0 — added the v3.1.2 `Bash` PreToolUse matcher that runs
|
|
54
|
+
* `peaks solo gate-step-08 --project .` (Step 0.8 mechanical
|
|
55
|
+
* gate). The existing Write|Edit|MultiEdit matcher is
|
|
56
|
+
* preserved. The new matcher's exit code is the load-bearing
|
|
57
|
+
* signal: 0 = allow, 2 = block (with stderr BLOCKED reason).
|
|
53
58
|
*/
|
|
54
|
-
export declare const TEMPLATE_VERSION = "1.
|
|
59
|
+
export declare const TEMPLATE_VERSION = "1.3.0";
|
|
55
60
|
/**
|
|
56
61
|
* Compare two serialized template strings for semantic equivalence.
|
|
57
62
|
*
|
|
@@ -50,8 +50,13 @@ export const CLAUDE_SETTINGS_LOCAL_FILENAME = '.claude/settings.local.json';
|
|
|
50
50
|
* 1.2.0 — removed the `Bash` matcher; Edit/Write fact-forcing
|
|
51
51
|
* bypass is the only emit. Bash enforcement is owned by
|
|
52
52
|
* `peaks gate enforce` in `settings.json`.
|
|
53
|
+
* 1.3.0 — added the v3.1.2 `Bash` PreToolUse matcher that runs
|
|
54
|
+
* `peaks solo gate-step-08 --project .` (Step 0.8 mechanical
|
|
55
|
+
* gate). The existing Write|Edit|MultiEdit matcher is
|
|
56
|
+
* preserved. The new matcher's exit code is the load-bearing
|
|
57
|
+
* signal: 0 = allow, 2 = block (with stderr BLOCKED reason).
|
|
53
58
|
*/
|
|
54
|
-
export const TEMPLATE_VERSION = '1.
|
|
59
|
+
export const TEMPLATE_VERSION = '1.3.0';
|
|
55
60
|
/**
|
|
56
61
|
* Compare two serialized template strings for semantic equivalence.
|
|
57
62
|
*
|
|
@@ -208,8 +213,42 @@ export function buildClaudeSettingsLocalJson() {
|
|
|
208
213
|
command: buildWriteHookCommand()
|
|
209
214
|
}
|
|
210
215
|
]
|
|
216
|
+
},
|
|
217
|
+
{
|
|
218
|
+
// v3.1.2 Step 0.8 — Mechanical PreToolUse gate. Runs
|
|
219
|
+
// `peaks solo gate-step-08 --project .` before every Bash
|
|
220
|
+
// tool call. Exit 0 = allow (with structured stdout
|
|
221
|
+
// describing the decision + optional `Next: slice #N+1 of
|
|
222
|
+
// M (<currentSlice>)` line when progress.json exists). Exit
|
|
223
|
+
// 2 = block (stderr contains the BLOCKED: ... reason).
|
|
224
|
+
// The existing Write|Edit|MultiEdit matcher is preserved.
|
|
225
|
+
matcher: 'Bash',
|
|
226
|
+
hooks: [
|
|
227
|
+
{
|
|
228
|
+
type: 'command',
|
|
229
|
+
command: buildBashGateStep08Command()
|
|
230
|
+
}
|
|
231
|
+
]
|
|
211
232
|
}
|
|
212
233
|
]
|
|
213
234
|
}
|
|
214
235
|
};
|
|
215
236
|
}
|
|
237
|
+
/**
|
|
238
|
+
* v3.1.2: build the Bash matcher command that runs `peaks solo
|
|
239
|
+
* gate-step-08`. We invoke the CLI directly (not via `node -e "..."`)
|
|
240
|
+
* because the CLI is the only legitimate source of the structured
|
|
241
|
+
* decision + Next: slice context. Exit code is the load-bearing
|
|
242
|
+
* signal — 0 = allow, 2 = block. The hook installer is idempotent:
|
|
243
|
+
* `templateContentMatches` compares the parsed matcher entries, so
|
|
244
|
+
* re-running `peaks workspace init` on a project that already has the
|
|
245
|
+
* Bash hook is a no-op (already-current).
|
|
246
|
+
*/
|
|
247
|
+
function buildBashGateStep08Command() {
|
|
248
|
+
// The hook receives the tool call on stdin. We ignore stdin and
|
|
249
|
+
// delegate entirely to `peaks solo gate-step-08`, which reads
|
|
250
|
+
// .peaks/_runtime/<sessionId>/job-shape.json and last-prompt.txt.
|
|
251
|
+
// `${CLAUDE_PROJECT_DIR}` resolves to the consumer project's root
|
|
252
|
+
// (Claude Code's standard convention).
|
|
253
|
+
return 'peaks solo gate-step-08 --project "${CLAUDE_PROJECT_DIR}"';
|
|
254
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const CLI_VERSION = "3.1.
|
|
1
|
+
export declare const CLI_VERSION = "3.1.2";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export const CLI_VERSION = "3.1.
|
|
1
|
+
export const CLI_VERSION = "3.1.2";
|
package/package.json
CHANGED
|
@@ -5,17 +5,15 @@ description: Full-auto orchestration facade for the Peaks-Loop skill family. Use
|
|
|
5
5
|
|
|
6
6
|
## Single-scope-axis naming convention (2.7.1)
|
|
7
7
|
|
|
8
|
-
The `.peaks/` workspace has a **single scope axis** (session-id) plus a nested **sub-agent axis** under `.peaks/_sub_agents/<sessionId>/...`. Use `<sessionId>` (NEVER bare `<sid>`).
|
|
9
|
-
|
|
10
|
-
**2.7.1:** `recordBypass` / `isBypassLimitReached` had a legacy write path that bypassed `.peaks/_runtime/` (slice 2.7.1 fix in `request-commands.ts:410`). Now writes canonical `.peaks/_runtime/<sid>/`. `getChangeArtifactRoot` removed. Test `skills-skill-md-naming.test.ts` enforces (a) zero bare `<sid>`, (b) axis labels, (c) this callout.
|
|
8
|
+
The `.peaks/` workspace has a **single scope axis** (session-id) plus a nested **sub-agent axis** under `.peaks/_sub_agents/<sessionId>/...`. Use `<sessionId>` (NEVER bare `<sid>`). Reviewable artifacts live at `.peaks/_runtime/<sessionId>/<role>/...` (gitignored); the change-id is an optional filename slug and does NOT route filesystem writes. CLI: session-id → `peaks session *`; sub-agent → `peaks sub-agent *`. OpenSpec's `openspec/changes/<change-id>/` vocabulary (L4) is preserved. Test `skills-skill-md-naming.test.ts` enforces (a) zero bare `<sid>`, (b) axis labels, (c) this callout.
|
|
11
9
|
|
|
12
10
|
## Karpathy guidance (Slice 1/6 — karpathy prompt-injection-lift)
|
|
13
11
|
|
|
14
|
-
Every sub-agent dispatch (`peaks-prd`, `peaks-rd`, `peaks-qa`, `peaks-ui`, `peaks-sc`, `peaks-txt`) MUST receive the 4 Karpathy guidelines. Append the verbatim block from `peaks-rd/references/rd-sub-agent-dispatch.md` §"Karpathy-guidelines context" to the dispatch prompt. Canonical skill id: `andrej-karpathy-skills:karpathy-guidelines`. Summary: **#1 Think Before Coding**, **#2 Simplicity First
|
|
12
|
+
Every sub-agent dispatch (`peaks-prd`, `peaks-rd`, `peaks-qa`, `peaks-ui`, `peaks-sc`, `peaks-txt`) MUST receive the 4 Karpathy guidelines. Append the verbatim block from `peaks-rd/references/rd-sub-agent-dispatch.md` §"Karpathy-guidelines context" to the dispatch prompt. Canonical skill id: `andrej-karpathy-skills:karpathy-guidelines`. Summary: **#1 Think Before Coding**, **#2 Simplicity First**, **#3 Surgical Changes**, **#4 Goal-Driven Execution**.
|
|
15
13
|
|
|
16
14
|
## Hard ban (effective 2.8.3 — read every session, no exceptions)
|
|
17
15
|
|
|
18
|
-
Never create `.peaks/_runtime/<YYYY-MM-DD-*>/` at the top level of `.peaks/`.
|
|
16
|
+
Never create `.peaks/_runtime/<YYYY-MM-DD-*>/` at the top level of `.peaks/`. ALL reviewable artifact dirs live under `.peaks/_runtime/<sessionId>/<role>/...` (gitignored) — never as siblings of `.peaks/_runtime/`. `peaks workspace init` creates only `.peaks/_runtime/<sessionId>/session.json`. If you find yourself about to write a date-prefixed directory directly under `.peaks/`, STOP and reroute under `.peaks/_runtime/<sessionId>/`. The `.gitignore` rule + vitest guard at `tests/unit/workspace/top-level-change-id-guard.test.ts` enforce this.
|
|
19
17
|
|
|
20
18
|
# Peaks-Loop Solo
|
|
21
19
|
|
|
@@ -31,7 +29,7 @@ This skill is the **primary surface**. The `peaks <cmd>` CLI is **auxiliary**
|
|
|
31
29
|
|
|
32
30
|
## Code-Change Red Line (BLOCKING — read before ANY tool call)
|
|
33
31
|
|
|
34
|
-
**Peaks-Loop Solo is an orchestrator, NOT an implementer. You MUST NOT write, edit, or modify any application source code directly.** Every code change goes through `peaks-solo → RD → QA → verdict`.
|
|
32
|
+
**Peaks-Loop Solo is an orchestrator, NOT an implementer. You MUST NOT write, edit, or modify any application source code directly.** Every code change goes through `peaks-solo → RD → QA → verdict`. **If you catch yourself about to write code, STOP.** Hand off to RD. Before declaring workflow complete, run `peaks workflow verify-pipeline --rid <rid> --project <repo> --json`.
|
|
35
33
|
|
|
36
34
|
## Peaks-Loop Startup sequence (MANDATORY — execute in order)
|
|
37
35
|
|
|
@@ -45,7 +43,7 @@ When a NEW conversation opens on a session whose `lastActivity` is from today AN
|
|
|
45
43
|
|
|
46
44
|
### Peaks-Loop Step N: Periodic checkpoint (auto-fire, no user action)
|
|
47
45
|
|
|
48
|
-
Proactive context-overflow defense. CLI: `peaks session checkpoint [--reason <r>] [...flags]`. Fire `--reason periodic` every 20 tool calls (G1 hard-coded), `--reason artifact-written` per PRD/RD/QA/TXT write
|
|
46
|
+
Proactive context-overflow defense. CLI: `peaks session checkpoint [--reason <r>] [...flags]`. Fire `--reason periodic` every 20 tool calls (G1 hard-coded), `--reason artifact-written` per PRD/RD/QA/TXT write. See `references/periodic-checkpoint.md` (otherwise `tests/unit/solo/checkpoint-periodic-frequency.test.ts` fails).
|
|
49
47
|
|
|
50
48
|
### Peaks-Loop Step 0.5: OpenSpec first-run opt-in (conditional)
|
|
51
49
|
|
|
@@ -55,9 +53,7 @@ Run when `openspec/` is absent and `.peaks/.peaks-openspec-opt-in.json` is missi
|
|
|
55
53
|
|
|
56
54
|
### Peaks-Loop Step 0.6: Audit + Goal (NEW)
|
|
57
55
|
|
|
58
|
-
Invoke peaks-audit after need expressed; store approved goal at `.peaks/_runtime/<sessionId>/audit-goal/<rid>.json`. **All autonomous work requires approved goal.**
|
|
59
|
-
|
|
60
|
-
→ see `references/audit-goal-gate.md`.
|
|
56
|
+
Invoke peaks-audit after need expressed; store approved goal at `.peaks/_runtime/<sessionId>/audit-goal/<rid>.json`. **All autonomous work requires approved goal.** → `references/audit-goal-gate.md`.
|
|
61
57
|
|
|
62
58
|
### Peaks-Loop Step N+1: Final Review (NEW)
|
|
63
59
|
|
|
@@ -65,11 +61,7 @@ After autonomous work (RD, QA, security, perf), invoke peaks-final-review for 4-
|
|
|
65
61
|
|
|
66
62
|
### Peaks-Loop Step N+2: Main-session context monitor (D6 + slice 2026-07-02)
|
|
67
63
|
|
|
68
|
-
After every 4th tool call, probe via `peaks solo context-now --project <repo> --json`. Thresholds: 50% / **0.85 pre-compact / 0.95 red-line** (v2.13.0).
|
|
69
|
-
|
|
70
|
-
**≥ 0.85**, LLM MUST fire `peaks solo auto-compact --execute --project <repo>` autonomously. **≥ 0.95** red line: next Bash/Task tool call fires `peaks session auto-compact-hook` (PreToolUse), which in-band spawns `claude --compact` against the current runner.
|
|
71
|
-
|
|
72
|
-
**Karpathy §4 exception**: compact red line keeps runner alive → zero-intervention wins. LLM does NOT ask user to run `/compact`. Honor `--in-flight-batch` (D6.e).
|
|
64
|
+
After every 4th tool call, probe via `peaks solo context-now --project <repo> --json`. Thresholds: 50% / **0.85 pre-compact / 0.95 red-line** (v2.13.0). **In Job mode ≥ 0.85 is MANDATORY auto-compact** (not advisory): Solo MUST call `peaks session auto-compact --execute --project <repo>` autonomously. Pass `--enforce-job-mode` to force the MANDATORY semantics in single-rid mode too (`job-shape.json` auto-enables it). **≥ 0.95** red line: next Bash/Task call fires `peaks session auto-compact-hook` (PreToolUse), in-band spawning `claude --compact`. **Karpathy §4 exception**: compact red line keeps runner alive → zero-intervention wins; LLM MUST NOT ask user to run `/compact`. Honor `--in-flight-batch` (D6.e).
|
|
73
65
|
|
|
74
66
|
### Peaks-Loop Step 0: Anchor the workflow (MANDATORY FIRST ACTIONS — no bail-out)
|
|
75
67
|
|
|
@@ -87,21 +79,30 @@ Run `peaks workspace init` + `peaks skill presence:set peaks-solo` BEFORE any an
|
|
|
87
79
|
|
|
88
80
|
After Step 0, run the resume-detection probe; surface via `AskUserQuestion` if a slice is in flight.
|
|
89
81
|
|
|
90
|
-
**
|
|
82
|
+
**v3.1.2 resume rule:** if `.peaks/_runtime/<sessionId>/job/<jid>/progress.json` exists, read it FIRST and surface `Next: slice #N of M (<currentSlice>)`. `peaks job progress --job-id <jid> [--allow-missing]` is the canonical reader; the same JSON is surfaced by `peaks solo gate-step-08` on every Bash call.
|
|
83
|
+
|
|
84
|
+
**v2.11.0 D7 override:** if user just `/compact`ed, run `peaks solo post-compact-detect --project <repo> --json` FIRST; `shouldAutoResume: true` skips AskUserQuestion (D7.b). Log to `.peaks/_runtime/<sessionId>/txt/auto-decisions.md`.
|
|
91
85
|
|
|
92
|
-
→ see `references/resume-detection.md
|
|
86
|
+
→ see `references/resume-detection.md`.
|
|
93
87
|
|
|
94
88
|
### Peaks-Loop Step 0.55: 1.x → 2.0 detection (BLOCKING on first invocation per session, when the project is not on a 2.0 layout)
|
|
95
89
|
|
|
96
|
-
|
|
90
|
+
After Step 0.7 returns "fresh", run `peaks upgrade --detect-1x --project <root> --json`. If `isOneX: true`, surface `AskUserQuestion`. Persist to `.peaks/preferences.json`. → `references/step-0-55-1x-detection.md`.
|
|
91
|
+
|
|
92
|
+
### Peaks-Loop Step 0.8 — Job 启动 (BLOCKING on LLM judgement — v3.1.1 patch + v3.1.2 mechanical gates)
|
|
97
93
|
|
|
98
|
-
|
|
94
|
+
The CLI is a **recorder + gate** for job-shape (the LLM judges). LLM calls `peaks solo detect-job --is-job <bool> --rationale <text> --suggested-job-id <jid> --suggested-strategy <single|rotating> --confidence <high|medium|low>`, which writes `.peaks/_runtime/<sessionId>/job-shape.json`. Downstream steps call `read-job-shape` and refuse if missing.
|
|
99
95
|
|
|
100
|
-
|
|
96
|
+
**Hard rule (v3.1.1 red-line #10):** LLM MUST NOT skip `peaks solo detect-job`. If `read-job-shape` throws `JOB_SHAPE_NOT_DECIDED`, record a decision before proceeding.
|
|
101
97
|
|
|
102
|
-
|
|
98
|
+
**v3.1.2 mechanical gates** (recorder-only was bypassed twice):
|
|
103
99
|
|
|
104
|
-
|
|
100
|
+
- **PreToolUse hook** — `peaks workspace init` installs the `Bash` matcher `peaks solo gate-step-08 --project .`. Exits 0 when `job-shape.json` exists (also emits `Next: slice #N+1 of M` from `progress.json`); exits 2 BLOCKED when missing AND prompt matches a fail-closed backup regex; otherwise 0 (allow).
|
|
101
|
+
- **Size-fear ban** — `peaks solo emit-handoff` refuses a final handoff while `remaining > 0` under Job mode.
|
|
102
|
+
- **Forced auto-compact** — `peaks solo context-now --enforce-job-mode` (auto-enabled on `isJob=true`) returns `auto-compact-now` at ≥ 0.85; **In Job mode ≥ 0.85 is MANDATORY auto-compact** (not advisory).
|
|
103
|
+
- **On-disk slice progress** — `peaks job checkpoint --state done` writes `progress.json`; `peaks job progress --job-id <jid> [--allow-missing]` is the canonical reader.
|
|
104
|
+
|
|
105
|
+
Full mechanics (judgement criteria, hook table, backup-regex rationale, hook wiring) at `references/step-0-8-gate.md`.
|
|
105
106
|
|
|
106
107
|
### Peaks-Loop Step 0.81 — per-slice 收尾
|
|
107
108
|
|
|
@@ -113,37 +114,29 @@ Trigger: `repair-status` atCap=true, context-now red-line ≥5min, or `subagent-
|
|
|
113
114
|
|
|
114
115
|
### Peaks-Loop Step 0.86 — main session rotation
|
|
115
116
|
|
|
116
|
-
Active in rotating mode; fires every `rotateEvery` slices or on-demand
|
|
117
|
+
Active in rotating mode; fires every `rotateEvery` slices or on-demand via `peaks job rotate-now`. Sequence: cycle-summary → checkpoint rotate-marker → `peaks session rotate` → next turn resumes via `peaks session resume --job-id <jid>`.
|
|
117
118
|
|
|
118
119
|
### Peaks-Loop Step 0.87 — sub-agent cleanup gate
|
|
119
120
|
|
|
120
121
|
After every `peaks sub-agent dispatch --batch-id <id>` inside a Job, BEFORE next slice checkpoint: `peaks job subagent-cleanup --job-id <jid> --batch-id <id> --force`. Non-zero → block.
|
|
121
122
|
|
|
122
|
-
→ see `references/job-loop.md` for state machine, visibility
|
|
123
|
+
→ see `references/job-loop.md` for state machine, visibility, rotation cadence, cross-day recovery, 9 red lines.
|
|
123
124
|
|
|
124
125
|
### Peaks-Loop Step 1: Mode selection
|
|
125
126
|
|
|
126
|
-
Use `AskUserQuestion` with `Full auto (Recommended)` first when user did not name a profile OR skill presence is stale (run `peaks skill presence:check-stale --project <path> --json` first; `stale: true` ⇒ re-ask).
|
|
127
|
-
|
|
128
|
-
→ see `references/mode-selection.md`, `references/fast-mode.md`, `references/mode-selection-with-stale-presence.md`.
|
|
127
|
+
Use `AskUserQuestion` with `Full auto (Recommended)` first when user did not name a profile OR skill presence is stale (run `peaks skill presence:check-stale --project <path> --json` first; `stale: true` ⇒ re-ask). → `references/mode-selection.md`, `references/fast-mode.md`, `references/mode-selection-with-stale-presence.md`.
|
|
129
128
|
|
|
130
129
|
### Peaks-Loop Step 2: Re-set skill presence with the chosen mode
|
|
131
130
|
|
|
132
|
-
Re-run `peaks skill presence:set peaks-solo --mode <mode-value> --gate startup`. Install statusline on first run (`peaks statusline install`).
|
|
133
|
-
|
|
134
|
-
→ see `references/skill-presence-and-title.md`.
|
|
131
|
+
Re-run `peaks skill presence:set peaks-solo --mode <mode-value> --gate startup`. Install statusline on first run (`peaks statusline install`). → `references/skill-presence-and-title.md`.
|
|
135
132
|
|
|
136
133
|
### Peaks-Loop Step 2.3: Load project memory (durable, LLM-authored memories)
|
|
137
134
|
|
|
138
|
-
Run `peaks project memories --project <repo> --json` to read decisions / conventions / modules / rules / lessons from `.peaks/memory`.
|
|
139
|
-
|
|
140
|
-
→ see `references/project-memory-loading.md` for the kind table.
|
|
135
|
+
Run `peaks project memories --project <repo> --json` to read decisions / conventions / modules / rules / lessons from `.peaks/memory`. → `references/project-memory-loading.md`.
|
|
141
136
|
|
|
142
137
|
### Peaks-Loop Step 2.5: Set session title
|
|
143
138
|
|
|
144
|
-
Extract a short title from the user's first request (8-20 Chinese chars or 4-10 English words). Run `peaks session title` with the active sid. Skip if a title is already set.
|
|
145
|
-
|
|
146
|
-
→ see `references/skill-presence-and-title.md` (same file as Step 2).
|
|
139
|
+
Extract a short title from the user's first request (8-20 Chinese chars or 4-10 English words). Run `peaks session title` with the active sid. Skip if a title is already set. → `references/skill-presence-and-title.md` (same file as Step 2).
|
|
147
140
|
|
|
148
141
|
## Sub-agent session sharing (MANDATORY — one conversation = one sid)
|
|
149
142
|
|
|
@@ -151,11 +144,7 @@ When peaks-solo dispatches a sub-agent (peaks-rd, peaks-qa, peaks-ui, peaks-txt,
|
|
|
151
144
|
|
|
152
145
|
## Boundaries
|
|
153
146
|
|
|
154
|
-
Peaks-Loop Solo may: identify scenarios
|
|
155
|
-
|
|
156
|
-
Peaks-Loop Solo must NOT silently install hooks, create agents, enable MCP servers, modify Claude settings, create GitHub repos, or bypass role-skill artifacts.
|
|
157
|
-
|
|
158
|
-
→ see `references/boundaries.md` for the do / don't list.
|
|
147
|
+
Peaks-Loop Solo may: identify scenarios, recommend profiles, coordinate role skills through artifacts, coordinate project memory extraction, request user confirmation at risk/commit boundaries. Peaks-Loop Solo must NOT silently install hooks / create agents / enable MCP / modify Claude settings / create GitHub repos / bypass role-skill artifacts. → `references/boundaries.md`.
|
|
159
148
|
|
|
160
149
|
## Peaks-Loop GStack integration
|
|
161
150
|
|
|
@@ -163,7 +152,7 @@ Map gstack stages to Peaks-Loop role artifacts; preserve confirmation gates. →
|
|
|
163
152
|
|
|
164
153
|
## Peaks-Loop Local intermediate artifact workspace (MANDATORY)
|
|
165
154
|
|
|
166
|
-
Step 0 creates the workspace; all intermediate artifacts land under `.peaks/_runtime/<sessionId>/`. NEVER write Peaks-Loop intermediate artifacts to the project root
|
|
155
|
+
Step 0 creates the workspace; all intermediate artifacts land under `.peaks/_runtime/<sessionId>/`. NEVER write Peaks-Loop intermediate artifacts to the project root.
|
|
167
156
|
|
|
168
157
|
## Peaks-Loop Pre-RD project scan checklist (MANDATORY)
|
|
169
158
|
|
|
@@ -171,9 +160,7 @@ Before handing off to `peaks-rd`, scan the project and record findings to `.peak
|
|
|
171
160
|
|
|
172
161
|
## Peaks-Loop Frontend-only development mode
|
|
173
162
|
|
|
174
|
-
When the project has no live backend (no swagger.json, no API server), Solo must activate frontend-only mode. The CLI is authoritative — read `frontendOnly` and `frontendOnlyReason` from `peaks scan archetype --json`.
|
|
175
|
-
|
|
176
|
-
→ see `references/frontend-only-mode.md` for the mode contract, mock-data strategy, and the pre-flight keyword scan.
|
|
163
|
+
When the project has no live backend (no swagger.json, no API server), Solo must activate frontend-only mode. The CLI is authoritative — read `frontendOnly` and `frontendOnlyReason` from `peaks scan archetype --json`. → `references/frontend-only-mode.md`.
|
|
177
164
|
|
|
178
165
|
## Peaks-Loop Request type classification + Workflow order + Transition verification gates
|
|
179
166
|
|
|
@@ -183,27 +170,23 @@ The contract for the 6-type classification table, the 11-step workflow order, an
|
|
|
183
170
|
|
|
184
171
|
> **Slice 5:** when the slice DAG has ≥ 2 leaves at one topological level, dispatch via `peaks sub-agent dispatch --from-dag <dag-file>` (wall-time ≈ max, not sum).
|
|
185
172
|
|
|
186
|
-
Write DAG → `.peaks/_runtime/<sessionId>/sc/slice-dag.json`, run `peaks sub-agent dispatch --from-dag <dag-file> --batch-id <id>` once; orchestrator emits N parallel `buildToolCall` (`dispatchCount === N`).
|
|
173
|
+
Write DAG → `.peaks/_runtime/<sessionId>/sc/slice-dag.json`, run `peaks sub-agent dispatch --from-dag <dag-file> --batch-id <id>` once; orchestrator emits N parallel `buildToolCall` (`dispatchCount === N`).
|
|
187
174
|
|
|
188
|
-
> **2026-06-28 校准:** 主路径 = 唯一蜂群;config/docs/chore
|
|
175
|
+
> **2026-06-28 校准:** 主路径 = 唯一蜂群;config/docs/chore 跳过不打断。详见 `.peaks/memory/peaks-loop-24h-ai-programmer-positioning.md`。
|
|
189
176
|
|
|
190
177
|
### Hard constraint: fan-out is mandatory (slice 2026-06-24-audit-5th-p2)
|
|
191
178
|
|
|
192
|
-
> **No serial opt-out.** `preferences.fanout.defaultMode = 'serial'`
|
|
193
|
-
> was removed in 2.8.4; legacy values auto-migrate to `fan-out`. See
|
|
194
|
-
> `references/fanout-mandatory.md` for the rationale + migration contract.
|
|
179
|
+
> **No serial opt-out.** `preferences.fanout.defaultMode = 'serial'` was removed in 2.8.4; legacy values auto-migrate to `fan-out`.
|
|
195
180
|
|
|
196
|
-
→ see `references/swarm-dispatch-contract.md
|
|
181
|
+
→ see `references/swarm-dispatch-contract.md`, `references/sub-agent-dispatch.md` (NOT `Skill` tool), `references/fanout-mandatory.md`.
|
|
197
182
|
|
|
198
183
|
## Slice 调度:分层并行 + 上游同步(2026-06-28 校准)
|
|
199
184
|
|
|
200
|
-
> 分层并行(G12
|
|
185
|
+
> 分层并行(G12)+ 上游同步(G11)见 `.peaks/memory/peaks-loop-fork-sync-and-layered-parallel.md`。
|
|
201
186
|
|
|
202
187
|
## Peaks-Loop Mandatory RD QA repair loop (AUTO-PROCEED)
|
|
203
188
|
|
|
204
|
-
After `peaks-rd` finishes
|
|
205
|
-
|
|
206
|
-
→ see `references/micro-cycle.md` for the full 5-step procedure (transition, re-launch, fix, re-run, restore presence) + 3-cycle cap.
|
|
189
|
+
After `peaks-rd` finishes, Solo MUST auto-route to `peaks-qa` without waiting for confirmation. Cap: 3 cycles; on 3rd failure emit blocked TXT handoff. Full 5-step procedure at `references/micro-cycle.md`.
|
|
207
190
|
|
|
208
191
|
## Default runbook
|
|
209
192
|
|
|
@@ -213,14 +196,11 @@ When adding new CLI commands, mirror into `references/runbook.md` and `tests/uni
|
|
|
213
196
|
|
|
214
197
|
## RD micro-cycle (TDD small-step rapid-test loop)
|
|
215
198
|
|
|
216
|
-
> **Slice 内部**的修复 / refactor / lint 修复走 micro-cycle(5-10s/cycle
|
|
217
|
-
> Slice 边界走 `peaks slice check`(一次性 4 项自检)。
|
|
218
|
-
> 不要把 micro-cycle 跟边界 check 混用——前者 100ms 反馈循环,后者 30s+ 全套。
|
|
219
|
-
> 完整手册:`references/micro-cycle.md`。
|
|
199
|
+
> **Slice 内部**的修复 / refactor / lint 修复走 micro-cycle(5-10s/cycle);Slice 边界走 `peaks slice check`。完整手册:`references/micro-cycle.md`。
|
|
220
200
|
|
|
221
201
|
## Peaks-Loop Project standards preflight
|
|
222
202
|
|
|
223
|
-
Gather
|
|
203
|
+
Gather via `peaks standards init/update --project <path> --dry-run`. Standards must reflect the project scan (component library, CSS, build tool, state, routing) — never emit a generic template.
|
|
224
204
|
|
|
225
205
|
## Peaks-Loop Refactor mode
|
|
226
206
|
|
|
@@ -232,7 +212,7 @@ Five CLI commands harden the workflow against silent skips: `peaks request lint`
|
|
|
232
212
|
|
|
233
213
|
## Peaks-Loop Completion handoff
|
|
234
214
|
|
|
235
|
-
After final validation, refresh project-local standards via `peaks standards init/update` (never hand-write). Use Peaks-Loop TXT for the compact handoff capsule
|
|
215
|
+
After final validation, refresh project-local standards via `peaks standards init/update` (never hand-write). Use Peaks-Loop TXT for the compact handoff capsule. **Presence management is delegated to the last downstream skill** — peaks-solo does not call `peaks skill presence:clear` itself.
|
|
236
216
|
|
|
237
217
|
## Peaks-Loop Step 11: Memory sediment (BLOCKING on workflow complete)
|
|
238
218
|
|
|
@@ -240,45 +220,27 @@ After final validation, refresh project-local standards via `peaks standards ini
|
|
|
240
220
|
|
|
241
221
|
### Substeps (BLOCKING)
|
|
242
222
|
|
|
243
|
-
**11a — Gate A (txt/ inventory):**
|
|
244
|
-
|
|
245
|
-
```bash
|
|
246
|
-
find .peaks/_runtime/<sessionId>/txt/ -type f -name '*.md' | head
|
|
247
|
-
```
|
|
248
|
-
|
|
249
|
-
If **0 files** → STOP. Dispatch `peaks-txt` first to write `handoff.md`, then return to 11c.
|
|
250
|
-
|
|
251
|
-
**11b — Gate B (memory block embed scan, skill-side only):**
|
|
252
|
-
|
|
253
|
-
```bash
|
|
254
|
-
grep -c 'peaks-memory:start' .peaks/_runtime/<sessionId>/txt/handoff.md || true
|
|
255
|
-
```
|
|
256
|
-
|
|
257
|
-
If **0 AND this session surfaced a stable project fact** (decision / convention / approved refactor / hard rule), STOP and tell peaks-txt to embed at least one `<!-- peaks-memory:start -->` block first.
|
|
258
|
-
|
|
259
|
-
**11c — Canonical extract (the only CLI that writes `.peaks/memory/`):**
|
|
223
|
+
**11a — Gate A (txt/ inventory):** `find .peaks/_runtime/<sessionId>/txt/ -type f -name '*.md' | head`. If **0 files** → STOP. Dispatch `peaks-txt` first to write `handoff.md`, then return to 11c.
|
|
260
224
|
|
|
261
|
-
|
|
262
|
-
peaks memory extract --project <repo> --artifact .peaks/_runtime/<sessionId>/txt/handoff.md --apply --json
|
|
263
|
-
```
|
|
225
|
+
**11b — Gate B (memory block embed scan):** `grep -c 'peaks-memory:start' .peaks/_runtime/<sessionId>/txt/handoff.md || true`. If **0 AND this session surfaced a stable project fact** (decision / convention / approved refactor / hard rule), STOP and tell peaks-txt to embed at least one `<!-- peaks-memory:start -->` block first.
|
|
264
226
|
|
|
265
|
-
`--apply` is REQUIRED
|
|
227
|
+
**11c — Canonical extract** (the only CLI that writes `.peaks/memory/`): `peaks memory extract --project <repo> --artifact .peaks/_runtime/<sessionId>/txt/handoff.md --apply --json`. `--apply` is REQUIRED (without it the command only previews — no files land).
|
|
266
228
|
|
|
267
229
|
**11d — Gate C (zero-write outcome):** If `extractedCount === 0` after 11c, fire AskUserQuestion:
|
|
268
230
|
|
|
269
231
|
> "本次 solo 未沉淀任何 `.peaks/memory` 文件。可选: (a) 回去在 handoff.md 嵌入至少 1 个 `peaks-memory:start` block 后重试; (b) 显式接受 no-sediment 并记录为 lesson; (c) 取消完成。"
|
|
270
232
|
|
|
271
|
-
Default option = (a). Solo MUST NOT silently accept (b) without user pick.
|
|
233
|
+
Default option = (a). Solo MUST NOT silently accept (b) without user pick. Full bash + flow at `references/runbook.md` §Step 11.
|
|
272
234
|
|
|
273
|
-
**Why this step exists:** audit 2026-07-03 confirmed 2 consecutive sessions produced zero `.peaks/memory/` files despite completing RD + QA + handoff artifacts
|
|
235
|
+
**Why this step exists:** audit 2026-07-03 confirmed 2 consecutive sessions produced zero `.peaks/memory/` files despite completing RD + QA + handoff artifacts; `assisted` mode silently skipped runbook Step 10 (no STOP condition). **Why `peaks memory extract` (not `peaks project memories:extract`):** the artifact-scoped extract is canonical; the batch-scoped sibling is for non-handoff flows. Always use `peaks memory extract --apply`.
|
|
274
236
|
|
|
275
237
|
## Peaks-Loop External references and lifecycle
|
|
276
238
|
|
|
277
|
-
3rd-party integrations (codegraph, mattpocock/skills, shadcn/ui, MCPs, Context7) follow Discovery → Reference → Side effect through Peaks CLI only. Run `peaks capabilities` for capability discovery; treat external skills as reference material only. MCP servers (Playwright / Chrome DevTools / Figma) are user-installed — check the tool list for `mcp__<server>__*` entries. Do not execute upstream installer / run upstream commands / persist sensitive examples / install upstream resources directly — funnel side effects through the Peaks CLI surface. Peaks-Loop Solo gates
|
|
239
|
+
3rd-party integrations (codegraph, mattpocock/skills, shadcn/ui, MCPs, Context7) follow Discovery → Reference → Side effect through Peaks CLI only. Run `peaks capabilities` for capability discovery; treat external skills as reference material only. MCP servers (Playwright / Chrome DevTools / Figma) are user-installed — check the tool list for `mcp__<server>__*` entries. Do not execute upstream installer / run upstream commands / persist sensitive examples / install upstream resources directly — funnel side effects through the Peaks CLI surface. Peaks-Loop Solo gates remain authoritative. → `references/external-references.md` + `references/external-skill-invocation.md`.
|
|
278
240
|
|
|
279
241
|
## Codegraph orchestration context
|
|
280
242
|
|
|
281
|
-
`peaks codegraph affected` is an optional project-analysis enhancement (untrusted supporting evidence)
|
|
243
|
+
`peaks codegraph affected` is an optional project-analysis enhancement (untrusted supporting evidence) for role handoff. Solo must not treat codegraph output as approval for scope, design, or QA verdict. Never mutate agent settings / hooks from codegraph; do not commit `.codegraph/` artifacts. RD writes `.peaks/_runtime/<sessionId>/rd/codegraph-context.md`; QA / TXT consume the same envelope. → `references/codegraph-orchestration.md`.
|
|
282
244
|
|
|
283
245
|
## Sub-agent context governance (G7 + G7.7 + G8 + G9 — slice #010)
|
|
284
246
|
|
|
@@ -286,7 +248,7 @@ Main LLM reducer sees metadata-only view (~200 chars/sub-agent); on-demand `Read
|
|
|
286
248
|
|
|
287
249
|
## Sub-agent cross-batch signal — G8.4 share / shared-read / await (slice 2026-06-23-audit-3rd)
|
|
288
250
|
|
|
289
|
-
Three CLI primitives let sibling sub-agents coordinate
|
|
251
|
+
Three CLI primitives let sibling sub-agents coordinate: `peaks sub-agent share / shared-read / await` (last-write-wins, ≤ 1KB warn / ≥ 64KB reject). Channel file gitignored under `.peaks/_sub_agents/<sessionId>/shared/`.
|
|
290
252
|
|
|
291
253
|
## References
|
|
292
254
|
|
|
@@ -192,8 +192,36 @@ Repair loop details: see `## Mandatory RD QA repair loop` in SKILL.md for the fu
|
|
|
192
192
|
|
|
193
193
|
# Peaks-Loop Default runbook — Job path (excerpt; full flow in references/job-loop.md)
|
|
194
194
|
|
|
195
|
-
#
|
|
195
|
+
# Step 0.8 (BLOCKING): LLM judges Job-shape, CLI records it.
|
|
196
|
+
# This is a RECORDER, not a detector. The LLM supplies --is-job + --rationale;
|
|
197
|
+
# the CLI writes .peaks/_runtime/<sid>/job-shape.json. Downstream steps call
|
|
198
|
+
# `peaks solo read-job-shape` to enforce the decision exists.
|
|
199
|
+
|
|
200
|
+
# (The LLM does the semantic judgement, e.g.:)
|
|
201
|
+
# "The user named N=35 parallel app/ subdirs, said 'continue until all done',
|
|
202
|
+
# and disavowed cost. isJob=true, rationale=..., suggestedJobId=app-ut-batch,
|
|
203
|
+
# suggestedStrategy=rotating, confidence=high."
|
|
204
|
+
peaks solo detect-job \
|
|
205
|
+
--is-job true \
|
|
206
|
+
--rationale "35 parallel app/ subdirs + 'until all done' + '不用考虑费用'" \
|
|
207
|
+
--suggested-job-id app-ut-batch \
|
|
208
|
+
--suggested-strategy rotating \
|
|
209
|
+
--confidence high
|
|
210
|
+
|
|
211
|
+
# Step 0.81-init: if Job-shaped, init BEFORE Step 1.
|
|
212
|
+
DECISION=$(peaks solo read-job-shape --json)
|
|
213
|
+
if [ "$(echo "$DECISION" | jq -r '.data.decision.isJob')" = "true" ]; then
|
|
214
|
+
JID=$(echo "$DECISION" | jq -r '.data.decision.suggestedJobId')
|
|
215
|
+
STRATEGY=$(echo "$DECISION" | jq -r '.data.decision.suggestedStrategy')
|
|
216
|
+
# LLM-derived slice list (not CLI-derived).
|
|
217
|
+
peaks job init --job-id "$JID" --slice-list "<LLM_DERIVED>" --main-loop-strategy "$STRATEGY" --rotate-every 3 --json
|
|
218
|
+
fi
|
|
219
|
+
|
|
220
|
+
# After Step 7 (RD+QA commit) lands AND Step 0.8 fired (state.json exists):
|
|
196
221
|
peaks job checkpoint --slice-id <rid> --state done --commit-sha $(git rev-parse HEAD)
|
|
222
|
+
# v3.1.2: `peaks job checkpoint --state done` ALSO writes
|
|
223
|
+
# .peaks/_runtime/<sid>/job/<jid>/progress.json. Read it on resume:
|
|
224
|
+
peaks job progress --job-id <jid> --json
|
|
197
225
|
peaks job status --job-id <jid> --json
|
|
198
226
|
peaks job subagent-cleanup --job-id <jid> --batch-id <bid> --force # Step 0.87 gate
|
|
199
227
|
# Loop control:
|
|
@@ -201,4 +229,21 @@ peaks job subagent-cleanup --job-id <jid> --batch-id <bid> --force # Step 0.87
|
|
|
201
229
|
# remaining == 0 → Step 8/9/10/11 (original tail)
|
|
202
230
|
# blocked (strict) → peaks job block + STOP
|
|
203
231
|
# Rotating-mode: every rotateEvery slices → Step 0.86 (peaks session rotate + resume)
|
|
232
|
+
|
|
233
|
+
# v3.1.2 size-fear ban: refuse to emit a final handoff while remaining > 0.
|
|
234
|
+
# The LLM cannot bypass this; --force-under-job requires explicit user approval.
|
|
235
|
+
peaks solo emit-handoff --project <repo> --job-id <jid> --json
|
|
236
|
+
|
|
237
|
+
# v3.1.2 forced auto-compact: when --enforce-job-mode is set OR
|
|
238
|
+
# job-shape.json says isJob=true, ≥0.85 is MANDATORY auto-compact.
|
|
239
|
+
# Solo MUST call this without confirmation under Job mode.
|
|
240
|
+
peaks solo context-now --project <repo> --enforce-job-mode --json
|
|
241
|
+
peaks session auto-compact --execute --project <repo> --json
|
|
242
|
+
|
|
243
|
+
# v3.1.2 PreToolUse gate (installed by `peaks workspace init`):
|
|
244
|
+
# every Bash tool call runs `peaks solo gate-step-08` automatically.
|
|
245
|
+
# Exit 0 = allow (with optional Next: slice #N+1 of M line when
|
|
246
|
+
# progress.json exists). Exit 2 = BLOCKED; LLM must call
|
|
247
|
+
# `peaks solo detect-job` first.
|
|
248
|
+
peaks solo gate-step-08 --project <repo> --json
|
|
204
249
|
```
|