peaks-loop 4.0.0-beta → 4.0.0-beta.3
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 +105 -87
- package/README-en.md +17 -4
- package/README.md +17 -4
- package/dist/src/cli/commands/asset-commands.d.ts +45 -0
- package/dist/src/cli/commands/asset-commands.js +404 -0
- package/dist/src/cli/commands/bee-commands.d.ts +26 -0
- package/dist/src/cli/commands/bee-commands.js +169 -0
- package/dist/src/cli/commands/{solo-commands.d.ts → code-commands.d.ts} +24 -24
- package/dist/src/cli/commands/{solo-commands.js → code-commands.js} +78 -78
- package/dist/src/cli/commands/core/skill-command.js +1 -1
- package/dist/src/cli/commands/dispatch-from-dag.js +1 -1
- package/dist/src/cli/commands/evolution-commands.d.ts +27 -0
- package/dist/src/cli/commands/evolution-commands.js +393 -0
- package/dist/src/cli/commands/hook-handle.js +7 -7
- package/dist/src/cli/commands/job-commands.js +2 -2
- package/dist/src/cli/commands/loop-commands.d.ts +19 -13
- package/dist/src/cli/commands/loop-commands.js +147 -13
- package/dist/src/cli/commands/sediment-commands.js +9 -0
- package/dist/src/cli/commands/session-auto-compact-hook-command.js +2 -2
- package/dist/src/cli/commands/skill-loop-engineering-readiness-commands.d.ts +67 -0
- package/dist/src/cli/commands/skill-loop-engineering-readiness-commands.js +173 -0
- package/dist/src/cli/commands/sub-agent-shared.d.ts +1 -1
- package/dist/src/cli/commands/user-touchpoint-commands.d.ts +4 -4
- package/dist/src/cli/commands/user-touchpoint-commands.js +14 -14
- package/dist/src/cli/commands/workflow-commands.js +22 -22
- package/dist/src/cli/program.js +23 -6
- package/dist/src/services/artifacts/repair-cycle-service.js +1 -1
- package/dist/src/services/audit/enforcers/active-skill-resolver.d.ts +1 -1
- package/dist/src/services/audit/enforcers/active-skill-resolver.js +1 -1
- package/dist/src/services/audit/enforcers/{solo-code-ban.d.ts → code-ban.d.ts} +6 -6
- package/dist/src/services/audit/enforcers/{solo-code-ban.js → code-ban.js} +6 -6
- package/dist/src/services/audit/red-line-catalog.d.ts +2 -2
- package/dist/src/services/audit/red-line-catalog.js +5 -5
- package/dist/src/services/audit/types.d.ts +2 -2
- package/dist/src/services/{solo → code}/auto-compact-orchestrator.d.ts +1 -1
- package/dist/src/services/{solo → code}/auto-compact-orchestrator.js +3 -3
- package/dist/src/services/{solo → code}/dag-orchestrator.d.ts +1 -1
- package/dist/src/services/{solo → code}/dag-orchestrator.js +1 -1
- package/dist/src/services/{solo → code}/emit-handoff.d.ts +1 -1
- package/dist/src/services/{solo → code}/emit-handoff.js +1 -1
- package/dist/src/services/{solo → code}/job-shape-decision.d.ts +1 -1
- package/dist/src/services/{solo → code}/job-shape-decision.js +5 -5
- package/dist/src/services/{solo → code}/mode-gate.d.ts +9 -9
- package/dist/src/services/{solo → code}/mode-gate.js +5 -5
- package/dist/src/services/{solo → code}/post-compact-detector.d.ts +3 -3
- package/dist/src/services/{solo → code}/post-compact-detector.js +4 -4
- package/dist/src/services/{solo → code}/step-08-gate.d.ts +4 -4
- package/dist/src/services/{solo → code}/step-08-gate.js +4 -4
- package/dist/src/services/{solo → code}/user-touchpoint-classifier.d.ts +1 -1
- package/dist/src/services/{solo → code}/user-touchpoint-classifier.js +1 -1
- package/dist/src/services/context/auto-compact-dispatcher.d.ts +2 -2
- package/dist/src/services/context/auto-compact-dispatcher.js +2 -2
- package/dist/src/services/context/auto-compact-types.d.ts +1 -1
- package/dist/src/services/crystallization/crystallization-service.d.ts +239 -0
- package/dist/src/services/crystallization/crystallization-service.js +397 -0
- package/dist/src/services/crystallization/crystallization-store.d.ts +75 -0
- package/dist/src/services/crystallization/crystallization-store.js +193 -0
- package/dist/src/services/crystallization/crystallization-types.d.ts +313 -0
- package/dist/src/services/crystallization/crystallization-types.js +299 -0
- package/dist/src/services/crystallization/evidence-brief-builder.d.ts +237 -0
- package/dist/src/services/crystallization/evidence-brief-builder.js +240 -0
- package/dist/src/services/dispatch/slice-dag.d.ts +2 -2
- package/dist/src/services/dispatch/test-tool-detection.d.ts +1 -1
- package/dist/src/services/dispatch/test-tool-detection.js +1 -1
- package/dist/src/services/evolution/evolution-service.d.ts +137 -0
- package/dist/src/services/evolution/evolution-service.js +281 -0
- package/dist/src/services/evolution/evolution-store.d.ts +57 -0
- package/dist/src/services/evolution/evolution-store.js +232 -0
- package/dist/src/services/evolution/evolution-types.d.ts +706 -0
- package/dist/src/services/evolution/evolution-types.js +286 -0
- package/dist/src/services/evolution/independent-evaluator-runner.d.ts +90 -0
- package/dist/src/services/evolution/independent-evaluator-runner.js +106 -0
- package/dist/src/services/evolution/regression-skeptic-runner.d.ts +64 -0
- package/dist/src/services/evolution/regression-skeptic-runner.js +113 -0
- package/dist/src/services/feedback/feedback-promotion-service.js +2 -2
- package/dist/src/services/job/job-progress-store.d.ts +1 -1
- package/dist/src/services/job/job-progress-store.js +1 -1
- package/dist/src/services/loop/loop-bee-relation-service.d.ts +107 -0
- package/dist/src/services/loop/loop-bee-relation-service.js +211 -0
- package/dist/src/services/loop/loop-bee-relation-store.d.ts +53 -0
- package/dist/src/services/loop/loop-bee-relation-store.js +130 -0
- package/dist/src/services/loop/loop-bee-relation-types.d.ts +118 -0
- package/dist/src/services/loop/loop-bee-relation-types.js +114 -0
- package/dist/src/services/loop/loop-release-service.d.ts +46 -0
- package/dist/src/services/loop/loop-release-service.js +66 -0
- package/dist/src/services/loop/loop-release-store.d.ts +55 -0
- package/dist/src/services/loop/loop-release-store.js +134 -0
- package/dist/src/services/loop/loop-release-types.d.ts +250 -0
- package/dist/src/services/loop/loop-release-types.js +162 -0
- package/dist/src/services/preferences/preferences-service.d.ts +1 -1
- package/dist/src/services/preferences/preferences-types.d.ts +1 -1
- package/dist/src/services/rd/standards-diagnostic.d.ts +1 -1
- package/dist/src/services/rd/standards-diagnostic.js +2 -2
- package/dist/src/services/recommendations/capability-seed-items.js +1 -1
- package/dist/src/services/recommendations/capability-seed-mappings.js +1 -1
- package/dist/src/services/recommendations/recommendation-service.js +1 -1
- package/dist/src/services/refactor/refactor-service.d.ts +1 -1
- package/dist/src/services/share/bundle-reader.d.ts +100 -0
- package/dist/src/services/share/bundle-reader.js +434 -0
- package/dist/src/services/share/bundle-types.d.ts +392 -0
- package/dist/src/services/share/bundle-types.js +318 -0
- package/dist/src/services/share/bundle-writer.d.ts +97 -0
- package/dist/src/services/share/bundle-writer.js +429 -0
- package/dist/src/services/share/run-state-contract.d.ts +133 -0
- package/dist/src/services/share/run-state-contract.js +138 -0
- package/dist/src/services/signal/cancel-handler.js +3 -3
- package/dist/src/services/skill/resume-detector.js +1 -1
- package/dist/src/services/skillhub/release-import.js +7 -2
- package/dist/src/services/skillhub/release-retain.js +6 -1
- package/dist/src/services/skillhub/sqlite-store.js +17 -1
- package/dist/src/services/skillhub/types.d.ts +10 -0
- package/dist/src/services/skills/skill-presence-service.d.ts +1 -1
- package/dist/src/services/standards/loop-engineering-lint.d.ts +38 -0
- package/dist/src/services/standards/loop-engineering-lint.js +101 -0
- package/dist/src/services/standards/loop-engineering-readiness-lint.d.ts +111 -0
- package/dist/src/services/standards/loop-engineering-readiness-lint.js +248 -0
- package/dist/src/services/upgrade/1x-detector-service.js +1 -1
- package/dist/src/services/workflow/pipeline-verify-service.d.ts +1 -1
- package/dist/src/services/workflow/pipeline-verify-service.js +3 -3
- package/dist/src/services/workflow/workflow-autonomous-service.d.ts +3 -3
- package/dist/src/services/workflow/workflow-autonomous-service.js +2 -2
- package/dist/src/services/workflow/workflow-router-service.d.ts +6 -6
- package/dist/src/services/workflow/workflow-router-service.js +33 -33
- package/dist/src/services/workspace/claude-settings-template.d.ts +1 -1
- package/dist/src/services/workspace/claude-settings-template.js +5 -5
- package/dist/src/shared/version.d.ts +1 -1
- package/dist/src/shared/version.js +1 -1
- package/examples/video-demo/README.md +57 -0
- package/examples/video-demo/out/en-closing-960.png +0 -0
- package/examples/video-demo/out/zh-closing-960.png +0 -0
- package/examples/video-demo/preview/peaks-loop-demo-en.mp4 +0 -0
- package/examples/video-demo/preview/peaks-loop-demo.mp4 +0 -0
- package/output-styles/peaks-skill-swarm.md +3 -3
- package/package.json +6 -2
- package/skills/bee/peaks-qa/SKILL.md +1 -1
- package/skills/bee/peaks-qa/references/artifact-per-request.md +3 -3
- package/skills/bee/peaks-qa/references/qa-sub-agent-dispatch.md +6 -6
- package/skills/bee/peaks-rd/references/rd-fanout-contracts.md +1 -1
- package/skills/bee/peaks-rd/references/rd-runbook.md +1 -1
- package/skills/bee/peaks-rd/references/rd-sub-agent-dispatch.md +11 -11
- package/skills/bee/peaks-rd/references/rd-transition-gates.md +1 -1
- package/skills/bee/peaks-sc/SKILL.md +1 -1
- package/skills/bee/peaks-txt/SKILL.md +3 -3
- package/skills/bee/peaks-ui/SKILL.md +8 -8
- package/skills/peaks-code/SKILL.md +34 -21
- package/skills/peaks-code/references/anchoring-and-session-info.md +2 -2
- package/skills/peaks-code/references/artifact-contracts.md +1 -1
- package/skills/peaks-code/references/boundaries.md +3 -3
- package/skills/peaks-code/references/codegraph-orchestration.md +1 -1
- package/skills/peaks-code/references/dag-orchestrator.md +7 -7
- package/skills/peaks-code/references/external-references.md +2 -2
- package/skills/peaks-code/references/fanout-mandatory.md +3 -3
- package/skills/peaks-code/references/fast-mode.md +2 -2
- package/skills/peaks-code/references/frontend-only-mode.md +9 -9
- package/skills/peaks-code/references/job-loop.md +1 -1
- package/skills/peaks-code/references/local-artifact-workspace.md +2 -2
- package/skills/peaks-code/references/micro-cycle.md +14 -14
- package/skills/peaks-code/references/mode-selection-with-stale-presence.md +5 -5
- package/skills/peaks-code/references/mode-selection.md +3 -3
- package/skills/peaks-code/references/openspec-workflow.md +16 -16
- package/skills/peaks-code/references/periodic-checkpoint.md +4 -4
- package/skills/peaks-code/references/quality-gate-cheatsheet.md +1 -1
- package/skills/peaks-code/references/refactor-mode.md +1 -1
- package/skills/peaks-code/references/runbook.md +15 -15
- package/skills/peaks-code/references/step-0-55-1x-detection.md +1 -1
- package/skills/peaks-code/references/step-0-8-gate.md +11 -11
- package/skills/peaks-code/references/sub-agent-dispatch.md +8 -8
- package/skills/peaks-code/references/swarm-dispatch-contract.md +17 -17
- package/skills/peaks-code/references/workflow-gates-and-types.md +2 -2
- package/skills/peaks-code/references/workflow.md +5 -5
- package/skills/peaks-content/SKILL.md +272 -0
- package/skills/peaks-issue-fix-orchestrator/SKILL.md +307 -0
- package/skills/peaks-resume/SKILL.md +2 -2
- package/skills/peaks-status/SKILL.md +2 -2
- package/skills/peaks-test/SKILL.md +2 -2
- /package/dist/src/services/{solo → code}/batch-heartbeat-poller.d.ts +0 -0
- /package/dist/src/services/{solo → code}/batch-heartbeat-poller.js +0 -0
- /package/dist/src/services/{solo → code}/status-line-renderer.d.ts +0 -0
- /package/dist/src/services/{solo → code}/status-line-renderer.js +0 -0
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Slice 2 — `peaks
|
|
2
|
+
* Slice 2 — `peaks code [--fast] <change-id>` (peaks-code fast mode).
|
|
3
3
|
*
|
|
4
4
|
* The `peaks-code` SKILL orchestrates an LLM-side workflow:
|
|
5
5
|
* load-memory -> standards-preflight -> rd-cycle -> qa-cycle -> emit-txt
|
|
6
6
|
*
|
|
7
|
-
* The CLI surface here is intentionally narrow: it builds a
|
|
8
|
-
* runs it via `
|
|
7
|
+
* The CLI surface here is intentionally narrow: it builds a CodePlan and
|
|
8
|
+
* runs it via `runCodeFast`. Fast mode skips memory full-load, standards
|
|
9
9
|
* preflight, and the QA repair loop. Round-trip KPI: ≤ 30s.
|
|
10
10
|
*
|
|
11
|
-
* No new service layer — the orchestrator is the in-file `
|
|
11
|
+
* No new service layer — the orchestrator is the in-file `runCodeFast`
|
|
12
12
|
* function. Hooks are injected so tests can mock at the boundary.
|
|
13
13
|
*
|
|
14
14
|
* v2.11.0 Group F (Tier 9) — D5 / D7 additions:
|
|
15
|
-
* - `peaks
|
|
16
|
-
* - `peaks
|
|
15
|
+
* - `peaks code should-pause --step <step> --mode <mode>` (D5)
|
|
16
|
+
* - `peaks code post-compact-detect --project <path>` (D7)
|
|
17
17
|
*/
|
|
18
18
|
import { existsSync, readFileSync } from 'node:fs';
|
|
19
19
|
import { join } from 'node:path';
|
|
@@ -21,13 +21,13 @@ import { addJsonOption, getErrorMessage, printResult } from '../cli-helpers.js';
|
|
|
21
21
|
import { fail, ok } from '../../shared/result.js';
|
|
22
22
|
import { emitObservabilityEvent } from '../../services/observability/observability-service.js';
|
|
23
23
|
import { findProjectRoot } from '../../services/config/config-safety.js';
|
|
24
|
-
import { GATED_STEPS, isHardFloorCategory,
|
|
24
|
+
import { GATED_STEPS, isHardFloorCategory, isCodeMode, isCommitBoundaryAction, shouldPauseAtGate, formatAutoProceedLogLine } from '../../services/code/mode-gate.js';
|
|
25
25
|
import { getSkillPresence, checkStalePresence } from '../../services/skills/skill-presence-service.js';
|
|
26
|
-
import { detectPostCompactResume, formatPostCompactResumeLogLine } from '../../services/
|
|
27
|
-
import { runAutoCompact } from '../../services/
|
|
28
|
-
import { readJobShapeDecision, writeJobShapeDecision, JobShapeDecisionError, JOB_SHAPE_NOT_DECIDED, JOB_SHAPE_ALREADY_DECIDED } from '../../services/
|
|
29
|
-
import { evaluateStep08, STEP_08_BACKUP_REGEX } from '../../services/
|
|
30
|
-
import { evaluateEmitHandoff, JOB_NOT_INITIALIZED, JOB_REMAINING_BLOCKED } from '../../services/
|
|
26
|
+
import { detectPostCompactResume, formatPostCompactResumeLogLine } from '../../services/code/post-compact-detector.js';
|
|
27
|
+
import { runAutoCompact } from '../../services/code/auto-compact-orchestrator.js';
|
|
28
|
+
import { readJobShapeDecision, writeJobShapeDecision, JobShapeDecisionError, JOB_SHAPE_NOT_DECIDED, JOB_SHAPE_ALREADY_DECIDED } from '../../services/code/job-shape-decision.js';
|
|
29
|
+
import { evaluateStep08, STEP_08_BACKUP_REGEX } from '../../services/code/step-08-gate.js';
|
|
30
|
+
import { evaluateEmitHandoff, JOB_NOT_INITIALIZED, JOB_REMAINING_BLOCKED } from '../../services/code/emit-handoff.js';
|
|
31
31
|
const STEP_ORDER = [
|
|
32
32
|
'load-memory',
|
|
33
33
|
'standards-preflight',
|
|
@@ -43,10 +43,10 @@ const STEP_KIND = {
|
|
|
43
43
|
'emit-txt': 'emit'
|
|
44
44
|
};
|
|
45
45
|
/**
|
|
46
|
-
* Build a
|
|
46
|
+
* Build a CodePlan. `fast=true` marks memory + preflight as skipped and
|
|
47
47
|
* disables the QA repair loop. Step order is fixed; emit-txt always last.
|
|
48
48
|
*/
|
|
49
|
-
export function
|
|
49
|
+
export function buildCodePlan(opts) {
|
|
50
50
|
const steps = STEP_ORDER.map((id) => {
|
|
51
51
|
const isSkippable = id === 'load-memory' || id === 'standards-preflight';
|
|
52
52
|
const step = {
|
|
@@ -62,10 +62,10 @@ export function buildSoloPlan(opts) {
|
|
|
62
62
|
return { sessionId: opts.sessionId, steps };
|
|
63
63
|
}
|
|
64
64
|
/**
|
|
65
|
-
* Run the
|
|
65
|
+
* Run the CodePlan. Skipped steps do NOT invoke their hook; emit-txt is
|
|
66
66
|
* always invoked last. Returns timing + skipped ids for KPI measurement.
|
|
67
67
|
*/
|
|
68
|
-
export async function
|
|
68
|
+
export async function runCodeFast(opts) {
|
|
69
69
|
const start = Date.now();
|
|
70
70
|
const skipped = [];
|
|
71
71
|
const { sessionId, plan, hooks } = opts;
|
|
@@ -101,23 +101,23 @@ export async function runSoloFast(opts) {
|
|
|
101
101
|
};
|
|
102
102
|
}
|
|
103
103
|
/**
|
|
104
|
-
* Register the `peaks
|
|
104
|
+
* Register the `peaks code [--fast] <change-id>` command. The actual
|
|
105
105
|
* LLM-side orchestration is driven by the SKILL.md (LLM-side), so this
|
|
106
106
|
* CLI command is a thin surface that builds the plan and emits a JSON
|
|
107
107
|
* envelope for downstream tooling.
|
|
108
108
|
*/
|
|
109
|
-
export function
|
|
110
|
-
const
|
|
111
|
-
.command('
|
|
109
|
+
export function registerCodeCommands(program, io) {
|
|
110
|
+
const code = program
|
|
111
|
+
.command('code')
|
|
112
112
|
.description('peaks-code LLM-side workflow planner (slice 2 fast mode)');
|
|
113
|
-
|
|
113
|
+
code
|
|
114
114
|
.command('plan')
|
|
115
|
-
.description('Build and print a
|
|
115
|
+
.description('Build and print a CodePlan without executing it')
|
|
116
116
|
.argument('<change-id>', 'change id to plan against')
|
|
117
117
|
.option('--fast', 'fast mode: skip memory full-load, standards preflight, and QA repair loop', false)
|
|
118
118
|
.option('--json', 'emit JSON envelope')
|
|
119
119
|
.action((sessionId, opts) => {
|
|
120
|
-
const plan =
|
|
120
|
+
const plan = buildCodePlan({ sessionId, fast: opts.fast === true });
|
|
121
121
|
if (opts.json === true) {
|
|
122
122
|
process.stdout.write(JSON.stringify({ ok: true, data: plan }) + '\n');
|
|
123
123
|
}
|
|
@@ -130,7 +130,7 @@ export function registerSoloCommands(program, io) {
|
|
|
130
130
|
}
|
|
131
131
|
}
|
|
132
132
|
});
|
|
133
|
-
addJsonOption(
|
|
133
|
+
addJsonOption(code
|
|
134
134
|
.command('should-pause')
|
|
135
135
|
.description('v2.11.0 D5: ask the mode-gate whether the LLM should pause for an AskUserQuestion at a given step. ' +
|
|
136
136
|
'full-auto / swarm auto-proceed (recommended = chosen); assisted / strict pause. ' +
|
|
@@ -161,19 +161,19 @@ export function registerSoloCommands(program, io) {
|
|
|
161
161
|
// to know the mode up front. The gate's hard-pause on
|
|
162
162
|
// step-1-mode-select will still pause regardless.
|
|
163
163
|
const mode = opts.mode ?? 'full-auto';
|
|
164
|
-
if (!
|
|
165
|
-
printResult(io, fail('
|
|
164
|
+
if (!isCodeMode(mode)) {
|
|
165
|
+
printResult(io, fail('code.should-pause', 'INVALID_MODE', `mode must be one of full-auto, assisted, swarm, strict (got "${mode}")`, { provided: mode }, ['Pass --mode full-auto | assisted | swarm | strict']), opts.json);
|
|
166
166
|
process.exitCode = 1;
|
|
167
167
|
return;
|
|
168
168
|
}
|
|
169
169
|
if (!GATED_STEPS.includes(opts.step)) {
|
|
170
|
-
printResult(io, fail('
|
|
170
|
+
printResult(io, fail('code.should-pause', 'INVALID_STEP', `step must be one of the 14 GATED_STEPS (got "${opts.step}")`, { provided: opts.step, allowed: [...GATED_STEPS] }, ['Pass --step <one of the 14 GATED_STEPS>']), opts.json);
|
|
171
171
|
process.exitCode = 1;
|
|
172
172
|
return;
|
|
173
173
|
}
|
|
174
174
|
const hardFloor = opts.hardFloor;
|
|
175
175
|
if (hardFloor !== undefined && !isHardFloorCategory(hardFloor)) {
|
|
176
|
-
printResult(io, fail('
|
|
176
|
+
printResult(io, fail('code.should-pause', 'INVALID_HARD_FLOOR', `hard-floor must be one of: irreversible-external-side-effect | authentication-credential | multi-day-investment | commit-boundary-side-effect (got "${hardFloor}")`, { provided: hardFloor }, ['Omit --hard-floor or pass a valid category']), opts.json);
|
|
177
177
|
process.exitCode = 1;
|
|
178
178
|
return;
|
|
179
179
|
}
|
|
@@ -185,7 +185,7 @@ export function registerSoloCommands(program, io) {
|
|
|
185
185
|
// (not silently ignored) so typos fail loud.
|
|
186
186
|
const commitBoundaryActionId = opts.commitBoundaryAction;
|
|
187
187
|
if (commitBoundaryActionId !== undefined && !isCommitBoundaryAction(commitBoundaryActionId)) {
|
|
188
|
-
printResult(io, fail('
|
|
188
|
+
printResult(io, fail('code.should-pause', 'INVALID_COMMIT_BOUNDARY_ACTION', `--commit-boundary-action must be one of: git-push | git-tag | npm-publish | npm-install-global | peaks-global-install (got "${commitBoundaryActionId}")`, { provided: commitBoundaryActionId }, ['Omit --commit-boundary-action or pass a valid action id']), opts.json);
|
|
189
189
|
process.exitCode = 1;
|
|
190
190
|
return;
|
|
191
191
|
}
|
|
@@ -194,7 +194,7 @@ export function registerSoloCommands(program, io) {
|
|
|
194
194
|
// Step 1 AND the recorded presence is stale, OVERRIDE the
|
|
195
195
|
// gate decision to PAUSE with reason='stale-presence'. The
|
|
196
196
|
// hard-pause on step-1-mode-select (defect #1 fix from
|
|
197
|
-
// 2026-06-28-
|
|
197
|
+
// 2026-06-28-code-mode-bypass-fix) is already in effect, so
|
|
198
198
|
// this only adds the structured `stale` reason + an
|
|
199
199
|
// envelope-level `stalePresence` field so downstream tooling
|
|
200
200
|
// (statusline, sub-agent dispatch) can act on it.
|
|
@@ -225,7 +225,7 @@ export function registerSoloCommands(program, io) {
|
|
|
225
225
|
}
|
|
226
226
|
}, { projectRoot: opts.project ?? process.cwd() });
|
|
227
227
|
}
|
|
228
|
-
printResult(io, ok('
|
|
228
|
+
printResult(io, ok('code.should-pause', {
|
|
229
229
|
shouldPause: true,
|
|
230
230
|
reason: `stale-presence — re-ask Step 1 (${stalePresence.reason}; recorded outer session id does not match current)`,
|
|
231
231
|
gateKind: 'mode-selection-itself',
|
|
@@ -287,7 +287,7 @@ export function registerSoloCommands(program, io) {
|
|
|
287
287
|
// action id in the envelope (when provided) so the LLM-side
|
|
288
288
|
// caller can echo which boundary was checked. Null when no
|
|
289
289
|
// --commit-boundary-action flag was passed.
|
|
290
|
-
ok('
|
|
290
|
+
ok('code.should-pause', {
|
|
291
291
|
...decision,
|
|
292
292
|
logLine,
|
|
293
293
|
...(commitBoundaryActionId !== undefined ? { commitBoundaryAction: commitBoundaryActionId } : {})
|
|
@@ -298,11 +298,11 @@ export function registerSoloCommands(program, io) {
|
|
|
298
298
|
]), opts.json);
|
|
299
299
|
}
|
|
300
300
|
catch (err) {
|
|
301
|
-
printResult(io, fail('
|
|
301
|
+
printResult(io, fail('code.should-pause', 'SHOULD_PAUSE_FAILED', getErrorMessage(err), null, ['Re-run with --json for envelope shape']), opts.json);
|
|
302
302
|
process.exitCode = 1;
|
|
303
303
|
}
|
|
304
304
|
});
|
|
305
|
-
addJsonOption(
|
|
305
|
+
addJsonOption(code
|
|
306
306
|
.command('post-compact-detect')
|
|
307
307
|
.description('v2.11.0 D7: detect whether the current invocation is a same-day post-compact resume. ' +
|
|
308
308
|
'Auto-resumes (no AskUserQuestion) when the most-recent checkpoint is from today, has a mode field, ' +
|
|
@@ -313,7 +313,7 @@ export function registerSoloCommands(program, io) {
|
|
|
313
313
|
try {
|
|
314
314
|
const sessionId = opts.sessionId ?? readActiveSid(opts.project);
|
|
315
315
|
if (sessionId === null) {
|
|
316
|
-
printResult(io, fail('
|
|
316
|
+
printResult(io, fail('code.post-compact-detect', 'NO_ACTIVE_SESSION', 'no active session id; pass --session-id or set presence via `peaks skill presence:set peaks-code`', null, ['Re-run with --session-id <sid>']), opts.json);
|
|
317
317
|
process.exitCode = 1;
|
|
318
318
|
return;
|
|
319
319
|
}
|
|
@@ -323,18 +323,18 @@ export function registerSoloCommands(program, io) {
|
|
|
323
323
|
activeSkill: opts.activeSkill
|
|
324
324
|
});
|
|
325
325
|
const logLine = formatPostCompactResumeLogLine(probe);
|
|
326
|
-
printResult(io, ok('
|
|
326
|
+
printResult(io, ok('code.post-compact-detect', { ...probe, logLine }, [...probe.warnings], [
|
|
327
327
|
probe.shouldAutoResume
|
|
328
328
|
? `Post-compact match → auto-resume mode=${probe.mode ?? '?'} checkpoint=${probe.checkpointPath ?? '?'}`
|
|
329
329
|
: `No auto-resume: ${probe.reason}`
|
|
330
330
|
]), opts.json);
|
|
331
331
|
}
|
|
332
332
|
catch (err) {
|
|
333
|
-
printResult(io, fail('
|
|
333
|
+
printResult(io, fail('code.post-compact-detect', 'POST_COMPACT_DETECT_FAILED', getErrorMessage(err), null, ['Verify the project path and try again']), opts.json);
|
|
334
334
|
process.exitCode = 1;
|
|
335
335
|
}
|
|
336
336
|
});
|
|
337
|
-
addJsonOption(
|
|
337
|
+
addJsonOption(code
|
|
338
338
|
.command('auto-compact')
|
|
339
339
|
.description('v2.13.0 AC-4: zero-human-intervention auto-compact. Probes current ' +
|
|
340
340
|
'context-fill % via the active IDE adapter; ≥ 0.85 writes a pre-compact ' +
|
|
@@ -366,20 +366,20 @@ export function registerSoloCommands(program, io) {
|
|
|
366
366
|
const data = 'data' in result ? result.data : null;
|
|
367
367
|
const nextActions = 'nextActions' in result ? result.nextActions : [];
|
|
368
368
|
const envelope = result.ok
|
|
369
|
-
? ok(`
|
|
370
|
-
: fail(`
|
|
369
|
+
? ok(`code.auto-compact`, data ?? {}, [], [result.message, ...nextActions])
|
|
370
|
+
: fail(`code.auto-compact`, code, result.message, data, [...nextActions]);
|
|
371
371
|
printResult(io, envelope, opts.json);
|
|
372
372
|
if (!exitOk)
|
|
373
373
|
process.exitCode = 1;
|
|
374
374
|
}
|
|
375
375
|
catch (err) {
|
|
376
|
-
printResult(io, fail('
|
|
376
|
+
printResult(io, fail('code.auto-compact', 'AUTO_COMPACT_FAILED', getErrorMessage(err), null, [
|
|
377
377
|
'Verify the project path + session id and try again'
|
|
378
378
|
]), opts.json);
|
|
379
379
|
process.exitCode = 1;
|
|
380
380
|
}
|
|
381
381
|
});
|
|
382
|
-
addJsonOption(
|
|
382
|
+
addJsonOption(code
|
|
383
383
|
.command('context-now')
|
|
384
384
|
.description('v2.13.0 AC-1: read the active IDE adapter\'s context-fill % ' +
|
|
385
385
|
'without requiring the LLM to pass --prompt-size <bytes> manually. ' +
|
|
@@ -444,7 +444,7 @@ export function registerSoloCommands(program, io) {
|
|
|
444
444
|
const jobModeNotice = isJobMode
|
|
445
445
|
? 'Job mode enforced: ≥0.85 is MANDATORY auto-compact (v3.1.2).'
|
|
446
446
|
: 'Advisory mode (single-rid): ≥0.85 is recommended, not mandatory.';
|
|
447
|
-
printResult(io, ok('
|
|
447
|
+
printResult(io, ok('code.context-now', {
|
|
448
448
|
ratio: probe.ratio,
|
|
449
449
|
ratioPct: `${ratioPct}%`,
|
|
450
450
|
verdict,
|
|
@@ -460,7 +460,7 @@ export function registerSoloCommands(program, io) {
|
|
|
460
460
|
action === 'red-line'
|
|
461
461
|
? `RED LINE: ≥ 95%. Next: \`${next}\` (PreToolUse hook fires next turn).`
|
|
462
462
|
: action === 'auto-compact-now'
|
|
463
|
-
? `Job-mode MANDATORY auto-compact.
|
|
463
|
+
? `Job-mode MANDATORY auto-compact. Code MUST call \`${next}\` WITHOUT confirmation.`
|
|
464
464
|
: action === 'soft-warn'
|
|
465
465
|
? isJobMode
|
|
466
466
|
? `Job mode soft-warn (50–85%). Continue working; the next \`peaks context now\` will re-check.`
|
|
@@ -470,7 +470,7 @@ export function registerSoloCommands(program, io) {
|
|
|
470
470
|
]), true);
|
|
471
471
|
}
|
|
472
472
|
catch (err) {
|
|
473
|
-
printResult(io, fail('
|
|
473
|
+
printResult(io, fail('code.context-now', 'CONTEXT_NOW_FAILED', getErrorMessage(err), null, [
|
|
474
474
|
'Verify the project path and try again'
|
|
475
475
|
]), opts.json);
|
|
476
476
|
process.exitCode = 1;
|
|
@@ -481,11 +481,11 @@ export function registerSoloCommands(program, io) {
|
|
|
481
481
|
// (--is-job, --rationale, --suggested-job-id, --suggested-strategy,
|
|
482
482
|
// --confidence); the CLI validates the shape, stamps `decidedAt`
|
|
483
483
|
// server-side, and writes to `.peaks/_runtime/<sessionId>/job-shape.json`.
|
|
484
|
-
addJsonOption(
|
|
484
|
+
addJsonOption(code
|
|
485
485
|
.command('detect-job')
|
|
486
486
|
.description('v3.1.1 Step 0.8: record the LLM\'s Job-shape judgement. CLI is a recorder, NOT a detector. ' +
|
|
487
487
|
'Pass --is-job true|false, --rationale <text>, --suggested-job-id <slug>. ' +
|
|
488
|
-
'Downstream steps call `peaks
|
|
488
|
+
'Downstream steps call `peaks code read-job-shape` and refuse to proceed if missing.')
|
|
489
489
|
.requiredOption('--is-job <bool>', 'true | false (the LLM\'s semantic verdict)')
|
|
490
490
|
.requiredOption('--rationale <text>', '1-3 sentences the LLM writes explaining the call')
|
|
491
491
|
.requiredOption('--suggested-job-id <jid>', 'LLM-chosen stable id, slug-safe (/^[a-z0-9][a-z0-9-]{2,40}$/)')
|
|
@@ -497,30 +497,30 @@ export function registerSoloCommands(program, io) {
|
|
|
497
497
|
.option('--prompt <text>', 'override the prompt hashed into promptHash (default: read last-prompt.txt if present, else empty)')).action(async (opts) => {
|
|
498
498
|
try {
|
|
499
499
|
if (opts.isJob !== 'true' && opts.isJob !== 'false') {
|
|
500
|
-
printResult(io, fail('
|
|
500
|
+
printResult(io, fail('code.detect-job', 'INVALID_FLAG', `--is-job must be true | false (got "${opts.isJob}")`, { provided: opts.isJob }, ['Pass --is-job true or --is-job false']), opts.json);
|
|
501
501
|
process.exitCode = 1;
|
|
502
502
|
return;
|
|
503
503
|
}
|
|
504
504
|
if (opts.suggestedStrategy !== 'single' && opts.suggestedStrategy !== 'rotating') {
|
|
505
|
-
printResult(io, fail('
|
|
505
|
+
printResult(io, fail('code.detect-job', 'INVALID_FLAG', `--suggested-strategy must be single | rotating (got "${opts.suggestedStrategy}")`, { provided: opts.suggestedStrategy }, ['Pass --suggested-strategy single or --suggested-strategy rotating']), opts.json);
|
|
506
506
|
process.exitCode = 1;
|
|
507
507
|
return;
|
|
508
508
|
}
|
|
509
509
|
if (opts.confidence !== 'high' && opts.confidence !== 'medium' && opts.confidence !== 'low') {
|
|
510
|
-
printResult(io, fail('
|
|
510
|
+
printResult(io, fail('code.detect-job', 'INVALID_FLAG', `--confidence must be high | medium | low (got "${opts.confidence}")`, { provided: opts.confidence }, ['Pass --confidence high | medium | low']), opts.json);
|
|
511
511
|
process.exitCode = 1;
|
|
512
512
|
return;
|
|
513
513
|
}
|
|
514
514
|
const jidRe = /^[a-z0-9][a-z0-9-]{2,40}$/;
|
|
515
515
|
if (!jidRe.test(opts.suggestedJobId)) {
|
|
516
|
-
printResult(io, fail('
|
|
516
|
+
printResult(io, fail('code.detect-job', 'INVALID_FLAG', `--suggested-job-id must match /^[a-z0-9][a-z0-9-]{2,40}$/ (got "${opts.suggestedJobId}")`, { provided: opts.suggestedJobId }, ['Pass a slug-safe id (lowercase, digits, dashes; 3-41 chars)']), opts.json);
|
|
517
517
|
process.exitCode = 1;
|
|
518
518
|
return;
|
|
519
519
|
}
|
|
520
520
|
const projectRoot = opts.project ?? findProjectRoot(process.cwd()) ?? process.cwd();
|
|
521
521
|
const sessionId = opts.sessionId ?? readActiveSid(projectRoot);
|
|
522
522
|
if (sessionId === null) {
|
|
523
|
-
printResult(io, fail('
|
|
523
|
+
printResult(io, fail('code.detect-job', 'NO_ACTIVE_SESSION', 'no active session id; pass --session-id or set presence via `peaks skill presence:set peaks-code`', null, ['Re-run with --session-id <sid>']), opts.json);
|
|
524
524
|
process.exitCode = 1;
|
|
525
525
|
return;
|
|
526
526
|
}
|
|
@@ -545,7 +545,7 @@ export function registerSoloCommands(program, io) {
|
|
|
545
545
|
confidence: opts.confidence,
|
|
546
546
|
prompt: promptText
|
|
547
547
|
}, { force: opts.force === true });
|
|
548
|
-
printResult(io, ok('
|
|
548
|
+
printResult(io, ok('code.detect-job', {
|
|
549
549
|
sessionId: record.sessionId,
|
|
550
550
|
promptHash: record.promptHash,
|
|
551
551
|
decision: record.decision,
|
|
@@ -558,7 +558,7 @@ export function registerSoloCommands(program, io) {
|
|
|
558
558
|
catch (err) {
|
|
559
559
|
if (err instanceof JobShapeDecisionError) {
|
|
560
560
|
const code = err.code === JOB_SHAPE_ALREADY_DECIDED ? JOB_SHAPE_ALREADY_DECIDED : err.code === JOB_SHAPE_NOT_DECIDED ? JOB_SHAPE_NOT_DECIDED : err.code;
|
|
561
|
-
printResult(io, fail('
|
|
561
|
+
printResult(io, fail('code.detect-job', code, err.message, err.details ?? null, [
|
|
562
562
|
err.code === JOB_SHAPE_ALREADY_DECIDED
|
|
563
563
|
? 'Re-run with --force to overwrite the existing decision.'
|
|
564
564
|
: 'Re-run with valid flags.'
|
|
@@ -566,13 +566,13 @@ export function registerSoloCommands(program, io) {
|
|
|
566
566
|
process.exitCode = 1;
|
|
567
567
|
return;
|
|
568
568
|
}
|
|
569
|
-
printResult(io, fail('
|
|
569
|
+
printResult(io, fail('code.detect-job', 'DETECT_JOB_FAILED', getErrorMessage(err), null, ['Verify the flags and try again']), opts.json);
|
|
570
570
|
process.exitCode = 1;
|
|
571
571
|
}
|
|
572
572
|
});
|
|
573
573
|
// v3.1.1 Step 0.8 — read-only validator. Downstream steps call this
|
|
574
574
|
// to refuse to proceed if the LLM has not yet recorded a decision.
|
|
575
|
-
addJsonOption(
|
|
575
|
+
addJsonOption(code
|
|
576
576
|
.command('read-job-shape')
|
|
577
577
|
.description('v3.1.1 Step 0.8: return the recorded Job-shape decision. ' +
|
|
578
578
|
'Returns JOB_SHAPE_NOT_DECIDED when the LLM has not yet recorded a verdict.')
|
|
@@ -582,12 +582,12 @@ export function registerSoloCommands(program, io) {
|
|
|
582
582
|
const projectRoot = opts.project ?? findProjectRoot(process.cwd()) ?? process.cwd();
|
|
583
583
|
const sessionId = opts.sessionId ?? readActiveSid(projectRoot);
|
|
584
584
|
if (sessionId === null) {
|
|
585
|
-
printResult(io, fail('
|
|
585
|
+
printResult(io, fail('code.read-job-shape', 'NO_ACTIVE_SESSION', 'no active session id; pass --session-id or set presence via `peaks skill presence:set peaks-code`', null, ['Re-run with --session-id <sid>']), opts.json);
|
|
586
586
|
process.exitCode = 1;
|
|
587
587
|
return;
|
|
588
588
|
}
|
|
589
589
|
const record = readJobShapeDecision(projectRoot, sessionId);
|
|
590
|
-
printResult(io, ok('
|
|
590
|
+
printResult(io, ok('code.read-job-shape', {
|
|
591
591
|
sessionId: record.sessionId,
|
|
592
592
|
promptHash: record.promptHash,
|
|
593
593
|
decision: record.decision,
|
|
@@ -598,15 +598,15 @@ export function registerSoloCommands(program, io) {
|
|
|
598
598
|
}
|
|
599
599
|
catch (err) {
|
|
600
600
|
if (err instanceof JobShapeDecisionError) {
|
|
601
|
-
printResult(io, fail('
|
|
601
|
+
printResult(io, fail('code.read-job-shape', err.code, err.message, err.details ?? null, [
|
|
602
602
|
err.code === JOB_SHAPE_NOT_DECIDED
|
|
603
|
-
? 'Run `peaks
|
|
603
|
+
? 'Run `peaks code detect-job` to record a decision.'
|
|
604
604
|
: 'Investigate the decision file integrity.'
|
|
605
605
|
]), opts.json);
|
|
606
606
|
process.exitCode = 1;
|
|
607
607
|
return;
|
|
608
608
|
}
|
|
609
|
-
printResult(io, fail('
|
|
609
|
+
printResult(io, fail('code.read-job-shape', 'READ_JOB_SHAPE_FAILED', getErrorMessage(err), null, ['Verify the project path and try again']), opts.json);
|
|
610
610
|
process.exitCode = 1;
|
|
611
611
|
}
|
|
612
612
|
});
|
|
@@ -615,7 +615,7 @@ export function registerSoloCommands(program, io) {
|
|
|
615
615
|
// installer). Exit code is the load-bearing contract:
|
|
616
616
|
// exit 0 → allow (with structured stdout describing the decision)
|
|
617
617
|
// exit 2 → block (stderr contains the BLOCKED: ... reason)
|
|
618
|
-
addJsonOption(
|
|
618
|
+
addJsonOption(code
|
|
619
619
|
.command('gate-step-08')
|
|
620
620
|
.description('v3.1.2: PreToolUse gate for Step 0.8 — allow when job-shape.json exists; ' +
|
|
621
621
|
'fail-closed backup regex when missing. Exit 0 = allow, exit 2 = block. ' +
|
|
@@ -630,7 +630,7 @@ export function registerSoloCommands(program, io) {
|
|
|
630
630
|
if (sessionId === null) {
|
|
631
631
|
// No session binding — treat as allow (single-rid mode). The
|
|
632
632
|
// LLM has not yet anchored; we have nothing to gate against.
|
|
633
|
-
const envelope = ok('
|
|
633
|
+
const envelope = ok('code.gate-step-08', {
|
|
634
634
|
allow: true,
|
|
635
635
|
mode: 'no-session',
|
|
636
636
|
decision: null,
|
|
@@ -650,7 +650,7 @@ export function registerSoloCommands(program, io) {
|
|
|
650
650
|
const result = evaluateStep08(evalInput);
|
|
651
651
|
const verdict = result.verdict;
|
|
652
652
|
if (verdict.kind === 'allow-job') {
|
|
653
|
-
const envelope = ok('
|
|
653
|
+
const envelope = ok('code.gate-step-08', {
|
|
654
654
|
allow: true,
|
|
655
655
|
mode: 'job',
|
|
656
656
|
decision: verdict.decision,
|
|
@@ -661,7 +661,7 @@ export function registerSoloCommands(program, io) {
|
|
|
661
661
|
return;
|
|
662
662
|
}
|
|
663
663
|
if (verdict.kind === 'allow-single') {
|
|
664
|
-
const envelope = ok('
|
|
664
|
+
const envelope = ok('code.gate-step-08', {
|
|
665
665
|
allow: true,
|
|
666
666
|
mode: 'single',
|
|
667
667
|
decision: null,
|
|
@@ -676,12 +676,12 @@ export function registerSoloCommands(program, io) {
|
|
|
676
676
|
if (verdict.promptHit) {
|
|
677
677
|
// Block: backup regex hit. Exit code 2 is the load-bearing
|
|
678
678
|
// signal for the PreToolUse hook.
|
|
679
|
-
const blockMessage = 'BLOCKED: prompt looks Job-shaped but peaks
|
|
680
|
-
const envelope = fail('
|
|
679
|
+
const blockMessage = 'BLOCKED: prompt looks Job-shaped but peaks code detect-job has not been called. Run `peaks code detect-job --is-job true ...` to record your Job-shape verdict, then retry.';
|
|
680
|
+
const envelope = fail('code.gate-step-08', 'STEP_08_BLOCKED', blockMessage, {
|
|
681
681
|
promptSource: verdict.promptSource,
|
|
682
682
|
backupRegex: STEP_08_BACKUP_REGEX.toString()
|
|
683
683
|
}, [
|
|
684
|
-
'Run `peaks
|
|
684
|
+
'Run `peaks code detect-job --is-job true --rationale <text> --suggested-job-id <slug>` to record the Job-shape verdict.',
|
|
685
685
|
'Then re-run the Bash tool call.'
|
|
686
686
|
]);
|
|
687
687
|
io.stderr(`${blockMessage}\n`);
|
|
@@ -690,7 +690,7 @@ export function registerSoloCommands(program, io) {
|
|
|
690
690
|
return;
|
|
691
691
|
}
|
|
692
692
|
// No decision + no regex hit → allow.
|
|
693
|
-
const envelope = ok('
|
|
693
|
+
const envelope = ok('code.gate-step-08', {
|
|
694
694
|
allow: true,
|
|
695
695
|
mode: 'undecided-no-regex-hit',
|
|
696
696
|
decision: null,
|
|
@@ -703,7 +703,7 @@ export function registerSoloCommands(program, io) {
|
|
|
703
703
|
return;
|
|
704
704
|
}
|
|
705
705
|
catch (err) {
|
|
706
|
-
printResult(io, fail('
|
|
706
|
+
printResult(io, fail('code.gate-step-08', 'GATE_STEP_08_FAILED', getErrorMessage(err), null, [
|
|
707
707
|
'Verify the project path and try again'
|
|
708
708
|
]), opts.json);
|
|
709
709
|
process.exitCode = 1;
|
|
@@ -711,7 +711,7 @@ export function registerSoloCommands(program, io) {
|
|
|
711
711
|
});
|
|
712
712
|
// v3.1.2 Step 11 / final handoff — Size-fear ban.
|
|
713
713
|
// Refuses to emit a final handoff while a Job has remaining slices.
|
|
714
|
-
addJsonOption(
|
|
714
|
+
addJsonOption(code
|
|
715
715
|
.command('emit-handoff')
|
|
716
716
|
.description('v3.1.2 Step 11 size-fear ban: under Job mode, refuse to emit a final ' +
|
|
717
717
|
'handoff while remaining > 0. Exit 0 = allow, exit 1 = block. Pass ' +
|
|
@@ -723,7 +723,7 @@ export function registerSoloCommands(program, io) {
|
|
|
723
723
|
try {
|
|
724
724
|
const sessionId = opts.sessionId ?? readActiveSid(opts.project);
|
|
725
725
|
if (sessionId === null) {
|
|
726
|
-
const envelope = ok('
|
|
726
|
+
const envelope = ok('code.emit-handoff', { allow: true, mode: 'no-session' }, [], [
|
|
727
727
|
'No active session id; gate passes through (single-rid mode).'
|
|
728
728
|
]);
|
|
729
729
|
printResult(io, envelope, opts.json);
|
|
@@ -739,35 +739,35 @@ export function registerSoloCommands(program, io) {
|
|
|
739
739
|
evalInput.forceUnderJob = true;
|
|
740
740
|
const verdict = evaluateEmitHandoff(evalInput);
|
|
741
741
|
if (verdict.kind === 'allow-not-job') {
|
|
742
|
-
const envelope = ok('
|
|
742
|
+
const envelope = ok('code.emit-handoff', { allow: true, mode: 'single' }, [], [
|
|
743
743
|
'job-shape.json says isJob=false (or absent); normal handoff allowed.'
|
|
744
744
|
]);
|
|
745
745
|
printResult(io, envelope, opts.json);
|
|
746
746
|
return;
|
|
747
747
|
}
|
|
748
748
|
if (verdict.kind === 'allow-done') {
|
|
749
|
-
const envelope = ok('
|
|
749
|
+
const envelope = ok('code.emit-handoff', { allow: true, mode: 'job-done', remaining: verdict.remaining }, [], [
|
|
750
750
|
`Job is complete (remaining=0); handoff allowed.`
|
|
751
751
|
]);
|
|
752
752
|
printResult(io, envelope, opts.json);
|
|
753
753
|
return;
|
|
754
754
|
}
|
|
755
755
|
if (verdict.kind === 'allow-force-override') {
|
|
756
|
-
const envelope = ok('
|
|
756
|
+
const envelope = ok('code.emit-handoff', { allow: true, mode: 'job-force-override', remaining: verdict.remaining }, [], [
|
|
757
757
|
`Job has ${verdict.remaining} remaining slices; --force-under-job override applied. Handoff allowed (explicit user approval).`
|
|
758
758
|
]);
|
|
759
759
|
printResult(io, envelope, opts.json);
|
|
760
760
|
return;
|
|
761
761
|
}
|
|
762
762
|
if (verdict.kind === 'block-not-initialized') {
|
|
763
|
-
const envelope = fail('
|
|
763
|
+
const envelope = fail('code.emit-handoff', JOB_NOT_INITIALIZED, `Job ${verdict.jobId} has no state.json; peaks job init was skipped.`, { jobId: verdict.jobId }, [`Run \`peaks job init --job-id ${verdict.jobId} --slice-list <...>\` before emitting handoff.`]);
|
|
764
764
|
printResult(io, envelope, opts.json);
|
|
765
765
|
process.exitCode = 1;
|
|
766
766
|
return;
|
|
767
767
|
}
|
|
768
768
|
// block-remaining
|
|
769
769
|
const blockMessage = `BLOCKED: Job ${verdict.jobId} has ${verdict.remaining} remaining slices. Run \`peaks job status\`. Use --force-under-job only with explicit user approval.`;
|
|
770
|
-
const envelope = fail('
|
|
770
|
+
const envelope = fail('code.emit-handoff', JOB_REMAINING_BLOCKED, blockMessage, { jobId: verdict.jobId, remaining: verdict.remaining }, [
|
|
771
771
|
`Run \`peaks job status --job-id ${verdict.jobId}\` to see remaining slices.`,
|
|
772
772
|
'Resume Step 0.81 (per-slice checkpoint loop) and continue until remaining === 0.',
|
|
773
773
|
'Use --force-under-job only with explicit user approval (size-fear ban override).'
|
|
@@ -778,7 +778,7 @@ export function registerSoloCommands(program, io) {
|
|
|
778
778
|
return;
|
|
779
779
|
}
|
|
780
780
|
catch (err) {
|
|
781
|
-
printResult(io, fail('
|
|
781
|
+
printResult(io, fail('code.emit-handoff', 'EMIT_HANDOFF_FAILED', getErrorMessage(err), null, [
|
|
782
782
|
'Verify the project path and try again'
|
|
783
783
|
]), opts.json);
|
|
784
784
|
process.exitCode = 1;
|
|
@@ -193,7 +193,7 @@ export function registerSkillCommand(program, io) {
|
|
|
193
193
|
printResult(io, ok('skill.presence:clear', { active: false, removed, projectContextUpdated: true }), options.json);
|
|
194
194
|
});
|
|
195
195
|
// Slice 002 (v2.15.0) — AC-1: presence staleness detector.
|
|
196
|
-
// peaks-code Step 1 (and `peaks
|
|
196
|
+
// peaks-code Step 1 (and `peaks code should-pause --step
|
|
197
197
|
// step-1-mode-select`) calls this to decide whether the recorded
|
|
198
198
|
// `mode` field can be trusted or whether the LLM must AskUserQuestion.
|
|
199
199
|
addJsonOption(skill
|
|
@@ -54,7 +54,7 @@ export async function runDispatchFromDag(role, options, asJson, io) {
|
|
|
54
54
|
const [{ readFileSync }, sliceDagMod, dagOrchestratorMod, contractStoreMod] = await Promise.all([
|
|
55
55
|
import('node:fs'),
|
|
56
56
|
import('../../services/dispatch/slice-dag.js'),
|
|
57
|
-
import('../../services/
|
|
57
|
+
import('../../services/code/dag-orchestrator.js'),
|
|
58
58
|
import('../../services/dispatch/contract-store.js')
|
|
59
59
|
]);
|
|
60
60
|
const { validateDag, topologicalLevels, isSliceComplexity } = sliceDagMod;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* peaks evolution * CLI — M4 / spec §4.4 / §6 / §7.4
|
|
3
|
+
*
|
|
4
|
+
* Adds the Darwin-style ratchet CLI surface:
|
|
5
|
+
*
|
|
6
|
+
* peaks evolution propose --target <kind:id> --dimension <name> \
|
|
7
|
+
* --before-score <n> --after-score <n> [--delta-min <n>] \
|
|
8
|
+
* --author <id> [--brief-pointer <path>] [--project <root>] [--json]
|
|
9
|
+
* peaks evolution evaluate --proposal <id> \
|
|
10
|
+
* --evaluator <id> --skeptic <id> \
|
|
11
|
+
* --evaluator-score <n> [--refute-paragraph <text>] \
|
|
12
|
+
* [--risk-tag <tag>]... [--brief-pointer <path>] [--project <root>] [--json]
|
|
13
|
+
* peaks evolution revert --proposal <id> [--user-confirmation <ptr>] [--project <root>] [--json]
|
|
14
|
+
* peaks evolution status [--target <kind:id>] [--project <root>] [--json]
|
|
15
|
+
*
|
|
16
|
+
* Each verb prints a structured JSON envelope (`printResult` with
|
|
17
|
+
* `asJson=true`). The CLI is a thin shim around EvolutionService +
|
|
18
|
+
* the two runner modules. Author / evaluator / skeptic identities
|
|
19
|
+
* are LLM-supplied; the user is NEVER asked to type them.
|
|
20
|
+
*
|
|
21
|
+
* Defense in depth: the EvolutionService enforces the ratchet
|
|
22
|
+
* rules (AC-8 / AC-10 / AC-11); the CLI only translates flags
|
|
23
|
+
* into the service payload.
|
|
24
|
+
*/
|
|
25
|
+
import { Command } from "commander";
|
|
26
|
+
import { type ProgramIO } from "../cli-helpers.js";
|
|
27
|
+
export declare function registerEvolutionCommands(program: Command, io: ProgramIO): void;
|