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,23 +1,35 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* peaks loop * CLI (Slice #14
|
|
2
|
+
* peaks loop * CLI (Slice #14 + M7 add).
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
4
|
+
* Slices:
|
|
5
|
+
* #14 sub-features (L4 Agent Loop integration): distill / preflight /
|
|
6
|
+
* detect-pattern / check-consistency / peaks goal compose.
|
|
6
7
|
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* 14.3 peaks loop detect-pattern — find repeating patterns (placeholder)
|
|
11
|
-
* 14.4 peaks loop check-consistency — verify state consistency (placeholder)
|
|
12
|
-
* 14.5 peaks goal compose — autonomous goal composition (placeholder;
|
|
13
|
-
* requires IDE adapter goalCommand capability
|
|
14
|
-
* per Slice #0.7)
|
|
8
|
+
* M7 (2026-07-07 spec §7A.2):
|
|
9
|
+
* peaks loop export --loop <id> --out <path.tar.gz>
|
|
10
|
+
* peaks loop import --in <path.tar.gz> [--as <loop-id>]
|
|
15
11
|
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
12
|
+
* `peaks loop export` reads the source loop_release + relations +
|
|
13
|
+
* related bees + evidence briefs and emits a `peaks.bundle/1`
|
|
14
|
+
* tar.gz. Hard-blocks when the source has `shareable=false`.
|
|
15
|
+
*
|
|
16
|
+
* `peaks loop import` extracts a bundle, validates
|
|
17
|
+
* format_version_major=1, and lands the release as `candidate`
|
|
18
|
+
* (mandatory landing status per spec §7A.2). The receiver must run
|
|
19
|
+
* an independent evaluation before promoting to `stable`.
|
|
20
|
+
*
|
|
21
|
+
* The existing 14.x commands are kept under the same `loop` parent;
|
|
22
|
+
* M7 only ADDs export / import — it does not modify the existing
|
|
23
|
+
* surface.
|
|
18
24
|
*/
|
|
25
|
+
import { existsSync, mkdirSync } from 'node:fs';
|
|
26
|
+
import { join } from 'node:path';
|
|
19
27
|
import { addJsonOption, getErrorMessage, printResult } from '../cli-helpers.js';
|
|
20
28
|
import { fail, ok } from '../../shared/result.js';
|
|
29
|
+
import { findProjectRoot } from '../../services/config/config-safety.js';
|
|
30
|
+
import { openStateDb } from '../../services/skillhub/sqlite-store.js';
|
|
31
|
+
import { writeBundle, BundleNotShareableError, BundleAssetNotFoundError, } from '../../services/share/bundle-writer.js';
|
|
32
|
+
import { readBundle, BundleMajorVersionMismatchError, BundleSchemaVersionsMismatchError, BundleImportToStableForbiddenError, BundleMalformedError, } from '../../services/share/bundle-reader.js';
|
|
21
33
|
export function registerLoopCommands(program, io) {
|
|
22
34
|
// 14.5 peaks goal compose — registered as a TOP-LEVEL command (not under
|
|
23
35
|
// `peaks loop`) because IDE adapters expose it as `goalCommand`.
|
|
@@ -125,4 +137,126 @@ export function registerLoopCommands(program, io) {
|
|
|
125
137
|
'loop.check-consistency is a thin facade; the LLM-side UX layer composes the drift scan.',
|
|
126
138
|
]), options.json);
|
|
127
139
|
});
|
|
140
|
+
// ---------- M7: peaks loop export / import (spec §7A.2) ----------
|
|
141
|
+
const LOOP_EXPORT_IMPORT_OPTS = (cmd) => cmd
|
|
142
|
+
.option('--project <path>', 'target project root (defaults to cwd)')
|
|
143
|
+
.option('--json', 'print machine-readable JSON envelope');
|
|
144
|
+
LOOP_EXPORT_IMPORT_OPTS(loop
|
|
145
|
+
.command('export')
|
|
146
|
+
.description("M7: export a loop_release as a peaks.bundle/1 tarball (spec §7A.2 / §10 RL-9). Refuses to export when shareable=false.")
|
|
147
|
+
.requiredOption('--loop <id>', 'loop_release id (kebab-case)')
|
|
148
|
+
.requiredOption('--out <path>', 'output .tar.gz path')).action((options) => {
|
|
149
|
+
const asJson = options.json === true;
|
|
150
|
+
try {
|
|
151
|
+
const projectRoot = options.project ?? findProjectRoot(process.cwd()) ?? process.cwd();
|
|
152
|
+
if (!existsSync(join(projectRoot, '.peaks'))) {
|
|
153
|
+
mkdirSync(join(projectRoot, '.peaks'), { recursive: true });
|
|
154
|
+
}
|
|
155
|
+
const db = openStateDb(join(projectRoot, '.peaks', 'state.db'));
|
|
156
|
+
try {
|
|
157
|
+
const result = writeBundle({
|
|
158
|
+
db,
|
|
159
|
+
blobsDir: join(projectRoot, '.peaks', 'blobs'),
|
|
160
|
+
kind: 'loop',
|
|
161
|
+
id: options.loop,
|
|
162
|
+
outPath: options.out,
|
|
163
|
+
});
|
|
164
|
+
printResult(io, ok('loop.export', {
|
|
165
|
+
outPath: result.outPath,
|
|
166
|
+
kind: result.kind,
|
|
167
|
+
assetId: result.assetId,
|
|
168
|
+
importedAs: 'candidate',
|
|
169
|
+
}, [], [
|
|
170
|
+
`Receiver must run \`peaks loop import --in ${result.outPath}\` to land this bundle, then run an independent evolution_evaluation before any promote.`,
|
|
171
|
+
]), asJson);
|
|
172
|
+
}
|
|
173
|
+
finally {
|
|
174
|
+
db.close();
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
catch (error) {
|
|
178
|
+
if (error instanceof BundleNotShareableError) {
|
|
179
|
+
printResult(io, fail('loop.export', error.code, error.message, { ok: false, loop: options.loop }, [
|
|
180
|
+
'Set shareable=true on the loop_release row, or share via desktop_visible=false.',
|
|
181
|
+
]), asJson);
|
|
182
|
+
process.exitCode = 1;
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
if (error instanceof BundleAssetNotFoundError) {
|
|
186
|
+
printResult(io, fail('loop.export', error.code, error.message, { ok: false, loop: options.loop }, [
|
|
187
|
+
'Verify the loop id with `peaks asset status --loop <id>`.',
|
|
188
|
+
]), asJson);
|
|
189
|
+
process.exitCode = 1;
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
printResult(io, fail('loop.export', 'LOOP_EXPORT_FAILED', getErrorMessage(error), { ok: false, loop: options.loop }, ['Verify --loop id and --out path.']), asJson);
|
|
193
|
+
process.exitCode = 1;
|
|
194
|
+
}
|
|
195
|
+
});
|
|
196
|
+
LOOP_EXPORT_IMPORT_OPTS(loop
|
|
197
|
+
.command('import')
|
|
198
|
+
.description("M7: import a peaks.bundle/1 tarball. Lands as candidate only — promotion requires an evolution_evaluation row (spec §7A.2 / §10 RL-9 / AC-25 / AC-26).")
|
|
199
|
+
.requiredOption('--in <path>', 'input .tar.gz path')
|
|
200
|
+
.option('--as <id>', 'optional rename for the loop id when landing')).action((options) => {
|
|
201
|
+
const asJson = options.json === true;
|
|
202
|
+
try {
|
|
203
|
+
const projectRoot = options.project ?? findProjectRoot(process.cwd()) ?? process.cwd();
|
|
204
|
+
if (!existsSync(join(projectRoot, '.peaks'))) {
|
|
205
|
+
mkdirSync(join(projectRoot, '.peaks'), { recursive: true });
|
|
206
|
+
}
|
|
207
|
+
const db = openStateDb(join(projectRoot, '.peaks', 'state.db'));
|
|
208
|
+
try {
|
|
209
|
+
const result = readBundle({
|
|
210
|
+
db,
|
|
211
|
+
blobsDir: join(projectRoot, '.peaks', 'blobs'),
|
|
212
|
+
inPath: options.in,
|
|
213
|
+
...(options.as !== undefined ? { asName: options.as } : {}),
|
|
214
|
+
});
|
|
215
|
+
printResult(io, ok('loop.import', {
|
|
216
|
+
assetId: result.assetId,
|
|
217
|
+
kind: result.kind,
|
|
218
|
+
importedAs: result.importedAs,
|
|
219
|
+
warnings: result.warnings,
|
|
220
|
+
evidenceBriefCount: result.evidenceBriefCount,
|
|
221
|
+
}, result.warnings, [
|
|
222
|
+
`Run an independent evaluation against this release before promoting; peaks loop promote refuses without an evolution_evaluation row.`,
|
|
223
|
+
]), asJson);
|
|
224
|
+
}
|
|
225
|
+
finally {
|
|
226
|
+
db.close();
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
catch (error) {
|
|
230
|
+
if (error instanceof BundleMajorVersionMismatchError) {
|
|
231
|
+
printResult(io, fail('loop.import', error.code, error.message, { ok: false, receivedMajor: error.receivedMajor }, [
|
|
232
|
+
'Use the matching peaks.bundle/<major> reader; this peaks build only supports major=1.',
|
|
233
|
+
]), asJson);
|
|
234
|
+
process.exitCode = 1;
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
237
|
+
if (error instanceof BundleSchemaVersionsMismatchError) {
|
|
238
|
+
printResult(io, fail('loop.import', error.code, error.message, { ok: false }, [
|
|
239
|
+
'Source bundle did not declare the canonical schema versions; refuse the bundle.',
|
|
240
|
+
]), asJson);
|
|
241
|
+
process.exitCode = 1;
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
244
|
+
if (error instanceof BundleImportToStableForbiddenError) {
|
|
245
|
+
printResult(io, fail('loop.import', error.code, error.message, { ok: false }, [
|
|
246
|
+
'Bundles always land as candidate; promotion to stable requires an evolution_evaluation row (AC-26).',
|
|
247
|
+
]), asJson);
|
|
248
|
+
process.exitCode = 1;
|
|
249
|
+
return;
|
|
250
|
+
}
|
|
251
|
+
if (error instanceof BundleMalformedError) {
|
|
252
|
+
printResult(io, fail('loop.import', error.code, error.message, { ok: false, inPath: options.in }, [
|
|
253
|
+
'Re-export from the source via `peaks loop export`.',
|
|
254
|
+
]), asJson);
|
|
255
|
+
process.exitCode = 1;
|
|
256
|
+
return;
|
|
257
|
+
}
|
|
258
|
+
printResult(io, fail('loop.import', 'LOOP_IMPORT_FAILED', getErrorMessage(error), { ok: false, inPath: options.in }, ['Verify the bundle path and integrity.']), asJson);
|
|
259
|
+
process.exitCode = 1;
|
|
260
|
+
}
|
|
261
|
+
});
|
|
128
262
|
}
|
|
@@ -450,6 +450,11 @@ export async function runSediment(argv, { home }) {
|
|
|
450
450
|
finally {
|
|
451
451
|
db.close();
|
|
452
452
|
}
|
|
453
|
+
// M7 (spec §7A.2 / §10 RL-9): `peaks skill sediment export` is
|
|
454
|
+
// an ALIAS of `peaks loop export` for one release cycle. Emit
|
|
455
|
+
// the deprecation warning to stderr so downstream tooling can
|
|
456
|
+
// upgrade. Future slice removes the alias.
|
|
457
|
+
process.stderr.write("warning: 'peaks skill sediment export' is deprecated; use 'peaks loop export' or 'peaks bee export' (peaks.bundle/1, spec §7A.2)\n");
|
|
453
458
|
return { ok: true, data: { outPath } };
|
|
454
459
|
}
|
|
455
460
|
case "import": {
|
|
@@ -479,6 +484,10 @@ export async function runSediment(argv, { home }) {
|
|
|
479
484
|
finally {
|
|
480
485
|
db.close();
|
|
481
486
|
}
|
|
487
|
+
// M7 (spec §7A.2): `peaks skill sediment import` is an ALIAS of
|
|
488
|
+
// `peaks loop import` for one release cycle. Emit the
|
|
489
|
+
// deprecation warning so downstream tooling can upgrade.
|
|
490
|
+
process.stderr.write("warning: 'peaks skill sediment import' is deprecated; use 'peaks loop import' or 'peaks bee import' (peaks.bundle/1, spec §7A.2)\n");
|
|
482
491
|
return { ok: true, data: { asName: asName ?? basename(bundlePath) } };
|
|
483
492
|
}
|
|
484
493
|
case "gc-blobs": {
|
|
@@ -86,7 +86,7 @@ export function registerSessionAutoCompactHookCommand(session) {
|
|
|
86
86
|
if (probe.ratio < RED_LINE_RATIO) {
|
|
87
87
|
// Below red line → exit 0 silent. The orchestrator's
|
|
88
88
|
// pre-compact zone (0.85–0.95) is handled out-of-band by
|
|
89
|
-
// the LLM firing `peaks
|
|
89
|
+
// the LLM firing `peaks code auto-compact --execute`; the
|
|
90
90
|
// hook only fires on the synchronous red-line path.
|
|
91
91
|
return;
|
|
92
92
|
}
|
|
@@ -102,7 +102,7 @@ export function registerSessionAutoCompactHookCommand(session) {
|
|
|
102
102
|
// binary), `spawn` raises ENOENT. Catching this MUST NOT crash
|
|
103
103
|
// the runner's tool call — the hook must exit 0 silently with
|
|
104
104
|
// a one-line stderr hint so the runner keeps working. The user
|
|
105
|
-
// can then run `/compact` manually (or `peaks
|
|
105
|
+
// can then run `/compact` manually (or `peaks code auto-compact`
|
|
106
106
|
// from another terminal).
|
|
107
107
|
try {
|
|
108
108
|
const child = spawn('claude', ['--compact'], {
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `peaks skill lint --category loop-engineering-readiness` — M6 / spec §7.5 + §8.4
|
|
3
|
+
*
|
|
4
|
+
* Loop Engineering readiness gate for any new peaks-* skill that
|
|
5
|
+
* participates in Loop Engineering (crystallization or evolution).
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* peaks skill lint --category loop-engineering-readiness --path <skill-dir>
|
|
9
|
+
* peaks skill lint --category loop-engineering-readiness --path <skill-dir> --json
|
|
10
|
+
*
|
|
11
|
+
* The command:
|
|
12
|
+
* 1. Resolves <skill-dir>/SKILL.md (default if the path is a file).
|
|
13
|
+
* 2. Calls lintSkillLoopEngineeringReadiness() with the file contents.
|
|
14
|
+
* 3. Prints a structured JSON envelope via printResult (or a
|
|
15
|
+
* human-readable summary when --json is omitted).
|
|
16
|
+
* 4. Sets process.exitCode = 1 on a non-ok result, so the LLM
|
|
17
|
+
* gate can short-circuit a future peaks-* skill that fails the
|
|
18
|
+
* lint.
|
|
19
|
+
*
|
|
20
|
+
* The lint asserts three structural properties:
|
|
21
|
+
* 1. the SKILL.md references
|
|
22
|
+
* `.peaks/standards/loop-engineering-guidelines.md`;
|
|
23
|
+
* 2. the SKILL.md does not introduce a CLI verb the user is meant
|
|
24
|
+
* to type (only LLM-coordinated verbs from the sediment /
|
|
25
|
+
* asset / evolution surface are allowed; RL-1);
|
|
26
|
+
* 3. the SKILL.md does not introduce a JSON / manifest
|
|
27
|
+
* hand-authoring surface (RL-1).
|
|
28
|
+
*
|
|
29
|
+
* The user never types `peaks skill lint …` — the LLM runs it on
|
|
30
|
+
* the user's behalf. This command is also reachable as
|
|
31
|
+
* `peaks skill ready --category loop-engineering-readiness
|
|
32
|
+
* --path <skill-dir>`
|
|
33
|
+
* via a small alias added at the bottom of this file.
|
|
34
|
+
*/
|
|
35
|
+
import type { Command } from 'commander';
|
|
36
|
+
import { type ProgramIO } from '../cli-helpers.js';
|
|
37
|
+
export declare const LOOP_ENGINEERING_READINESS_CATEGORY = "loop-engineering-readiness";
|
|
38
|
+
/**
|
|
39
|
+
* Resolve the SKILL.md file path from a `--path <skill-dir>` value.
|
|
40
|
+
*
|
|
41
|
+
* Accepts either:
|
|
42
|
+
* - a directory containing a SKILL.md (the common case for a
|
|
43
|
+
* peaks-* skill: `src/skills/<id>/`, `skills/<id>/`, etc.);
|
|
44
|
+
* - a direct file path to a SKILL.md.
|
|
45
|
+
*
|
|
46
|
+
* Returns the absolute path to the SKILL.md, or null if no SKILL.md
|
|
47
|
+
* is found.
|
|
48
|
+
*/
|
|
49
|
+
export declare function resolveSkillMdPath(rawPath: string): string | null;
|
|
50
|
+
/**
|
|
51
|
+
* Pure helper: run the readiness lint against the SKILL.md text and
|
|
52
|
+
* return a CLI-shaped envelope. Kept separate from the Commander
|
|
53
|
+
* action so unit + integration tests can drive it without spawning
|
|
54
|
+
* a child process.
|
|
55
|
+
*/
|
|
56
|
+
export declare function runReadinessLint(rawPath: string): {
|
|
57
|
+
ok: boolean;
|
|
58
|
+
code: string;
|
|
59
|
+
message: string;
|
|
60
|
+
data: {
|
|
61
|
+
path: string;
|
|
62
|
+
category: string;
|
|
63
|
+
findings: string[];
|
|
64
|
+
};
|
|
65
|
+
nextActions: string[];
|
|
66
|
+
};
|
|
67
|
+
export declare function registerSkillLoopEngineeringReadinessCommands(program: Command, io: ProgramIO): void;
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `peaks skill lint --category loop-engineering-readiness` — M6 / spec §7.5 + §8.4
|
|
3
|
+
*
|
|
4
|
+
* Loop Engineering readiness gate for any new peaks-* skill that
|
|
5
|
+
* participates in Loop Engineering (crystallization or evolution).
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* peaks skill lint --category loop-engineering-readiness --path <skill-dir>
|
|
9
|
+
* peaks skill lint --category loop-engineering-readiness --path <skill-dir> --json
|
|
10
|
+
*
|
|
11
|
+
* The command:
|
|
12
|
+
* 1. Resolves <skill-dir>/SKILL.md (default if the path is a file).
|
|
13
|
+
* 2. Calls lintSkillLoopEngineeringReadiness() with the file contents.
|
|
14
|
+
* 3. Prints a structured JSON envelope via printResult (or a
|
|
15
|
+
* human-readable summary when --json is omitted).
|
|
16
|
+
* 4. Sets process.exitCode = 1 on a non-ok result, so the LLM
|
|
17
|
+
* gate can short-circuit a future peaks-* skill that fails the
|
|
18
|
+
* lint.
|
|
19
|
+
*
|
|
20
|
+
* The lint asserts three structural properties:
|
|
21
|
+
* 1. the SKILL.md references
|
|
22
|
+
* `.peaks/standards/loop-engineering-guidelines.md`;
|
|
23
|
+
* 2. the SKILL.md does not introduce a CLI verb the user is meant
|
|
24
|
+
* to type (only LLM-coordinated verbs from the sediment /
|
|
25
|
+
* asset / evolution surface are allowed; RL-1);
|
|
26
|
+
* 3. the SKILL.md does not introduce a JSON / manifest
|
|
27
|
+
* hand-authoring surface (RL-1).
|
|
28
|
+
*
|
|
29
|
+
* The user never types `peaks skill lint …` — the LLM runs it on
|
|
30
|
+
* the user's behalf. This command is also reachable as
|
|
31
|
+
* `peaks skill ready --category loop-engineering-readiness
|
|
32
|
+
* --path <skill-dir>`
|
|
33
|
+
* via a small alias added at the bottom of this file.
|
|
34
|
+
*/
|
|
35
|
+
import { readFileSync, existsSync, statSync } from 'node:fs';
|
|
36
|
+
import { join, resolve } from 'node:path';
|
|
37
|
+
import { lintSkillLoopEngineeringReadiness, } from '../../services/standards/loop-engineering-readiness-lint.js';
|
|
38
|
+
import { addJsonOption, getErrorMessage, printResult } from '../cli-helpers.js';
|
|
39
|
+
import { fail, ok } from '../../shared/result.js';
|
|
40
|
+
export const LOOP_ENGINEERING_READINESS_CATEGORY = 'loop-engineering-readiness';
|
|
41
|
+
/**
|
|
42
|
+
* Resolve the SKILL.md file path from a `--path <skill-dir>` value.
|
|
43
|
+
*
|
|
44
|
+
* Accepts either:
|
|
45
|
+
* - a directory containing a SKILL.md (the common case for a
|
|
46
|
+
* peaks-* skill: `src/skills/<id>/`, `skills/<id>/`, etc.);
|
|
47
|
+
* - a direct file path to a SKILL.md.
|
|
48
|
+
*
|
|
49
|
+
* Returns the absolute path to the SKILL.md, or null if no SKILL.md
|
|
50
|
+
* is found.
|
|
51
|
+
*/
|
|
52
|
+
export function resolveSkillMdPath(rawPath) {
|
|
53
|
+
const abs = resolve(rawPath);
|
|
54
|
+
if (!existsSync(abs))
|
|
55
|
+
return null;
|
|
56
|
+
const st = statSync(abs);
|
|
57
|
+
if (st.isFile()) {
|
|
58
|
+
return abs.toLowerCase().endsWith('skill.md') ? abs : null;
|
|
59
|
+
}
|
|
60
|
+
if (st.isDirectory()) {
|
|
61
|
+
const candidate = join(abs, 'SKILL.md');
|
|
62
|
+
return existsSync(candidate) ? candidate : null;
|
|
63
|
+
}
|
|
64
|
+
return null;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Pure helper: run the readiness lint against the SKILL.md text and
|
|
68
|
+
* return a CLI-shaped envelope. Kept separate from the Commander
|
|
69
|
+
* action so unit + integration tests can drive it without spawning
|
|
70
|
+
* a child process.
|
|
71
|
+
*/
|
|
72
|
+
export function runReadinessLint(rawPath) {
|
|
73
|
+
const skillMdPath = resolveSkillMdPath(rawPath);
|
|
74
|
+
if (!skillMdPath) {
|
|
75
|
+
return {
|
|
76
|
+
ok: false,
|
|
77
|
+
code: 'SKILL_FILE_NOT_FOUND',
|
|
78
|
+
message: `could not resolve SKILL.md from --path ${rawPath}`,
|
|
79
|
+
data: { path: rawPath, category: LOOP_ENGINEERING_READINESS_CATEGORY, findings: [] },
|
|
80
|
+
nextActions: [
|
|
81
|
+
'Pass a directory containing SKILL.md or a direct path to a SKILL.md file.',
|
|
82
|
+
],
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
const text = readFileSync(skillMdPath, 'utf-8');
|
|
86
|
+
const result = lintSkillLoopEngineeringReadiness(text);
|
|
87
|
+
if (result.ok) {
|
|
88
|
+
return {
|
|
89
|
+
ok: true,
|
|
90
|
+
code: 'SKILL_READINESS_OK',
|
|
91
|
+
message: 'SKILL.md passes the Loop Engineering readiness lint',
|
|
92
|
+
data: {
|
|
93
|
+
path: skillMdPath,
|
|
94
|
+
category: LOOP_ENGINEERING_READINESS_CATEGORY,
|
|
95
|
+
findings: [],
|
|
96
|
+
},
|
|
97
|
+
nextActions: [
|
|
98
|
+
'The skill is allowed to participate in Loop Engineering (crystallization / evolution).',
|
|
99
|
+
],
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
return {
|
|
103
|
+
ok: false,
|
|
104
|
+
code: 'SKILL_READINESS_FAILED',
|
|
105
|
+
message: `SKILL.md failed the Loop Engineering readiness lint (${result.findings.length} finding(s))`,
|
|
106
|
+
data: {
|
|
107
|
+
path: skillMdPath,
|
|
108
|
+
category: LOOP_ENGINEERING_READINESS_CATEGORY,
|
|
109
|
+
findings: result.findings,
|
|
110
|
+
},
|
|
111
|
+
nextActions: [
|
|
112
|
+
'Address every finding listed in data.findings, then re-run the lint.',
|
|
113
|
+
'See src/services/standards/loop-engineering-readiness-lint.ts for the rule definitions.',
|
|
114
|
+
'See .peaks/standards/loop-engineering-guidelines.md for the red lines the lint enforces.',
|
|
115
|
+
],
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
function lintAction(options, io) {
|
|
119
|
+
if (options.category !== LOOP_ENGINEERING_READINESS_CATEGORY) {
|
|
120
|
+
printResult(io, fail('skill.lint', 'UNKNOWN_LINT_CATEGORY', `only --category ${LOOP_ENGINEERING_READINESS_CATEGORY} is implemented in M6`, { category: options.category ?? null }, [
|
|
121
|
+
`Pass --category ${LOOP_ENGINEERING_READINESS_CATEGORY}.`,
|
|
122
|
+
]), options.json);
|
|
123
|
+
process.exitCode = 1;
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
if (!options.path) {
|
|
127
|
+
printResult(io, fail('skill.lint', 'MISSING_PATH', '--path <skill-dir> is required', { category: options.category }, ['Pass --path pointing at a peaks-* skill directory containing SKILL.md.']), options.json);
|
|
128
|
+
process.exitCode = 1;
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
try {
|
|
132
|
+
const envelope = runReadinessLint(options.path);
|
|
133
|
+
if (envelope.ok) {
|
|
134
|
+
printResult(io, ok('skill.lint', envelope.data, [], envelope.nextActions), options.json);
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
printResult(io, fail('skill.lint', envelope.code, envelope.message, envelope.data, envelope.nextActions), options.json);
|
|
138
|
+
process.exitCode = 1;
|
|
139
|
+
}
|
|
140
|
+
catch (error) {
|
|
141
|
+
printResult(io, fail('skill.lint', 'SKILL_READINESS_ERROR', getErrorMessage(error), { path: options.path }, ['Verify the path is readable.']), options.json);
|
|
142
|
+
process.exitCode = 1;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
export function registerSkillLoopEngineeringReadinessCommands(program, io) {
|
|
146
|
+
// `peaks skill lint --category loop-engineering-readiness --path <skill-dir>`
|
|
147
|
+
// — primary surface, named to match the spec §7.5 / §8.4 wording.
|
|
148
|
+
// We reuse the existing `skill` parent if one is registered; per
|
|
149
|
+
// the add-a-new-subcommand-check-for-existing-top-level-first rule,
|
|
150
|
+
// we never re-create `skill` when it's already there.
|
|
151
|
+
const existingSkill = program.commands.find((c) => c.name() === 'skill');
|
|
152
|
+
const skill = existingSkill ?? program
|
|
153
|
+
.command('skill')
|
|
154
|
+
.description('skill operations (M6: lint --category loop-engineering-readiness)');
|
|
155
|
+
addJsonOption(skill
|
|
156
|
+
.command('lint')
|
|
157
|
+
.description(`M6: lint a peaks-* SKILL.md against a category. Currently supports --category ${LOOP_ENGINEERING_READINESS_CATEGORY} (spec §7.5 / §8.4 / RL-8).`)
|
|
158
|
+
.option('--category <name>', `lint category; the M6 implementation only supports ${LOOP_ENGINEERING_READINESS_CATEGORY}`, LOOP_ENGINEERING_READINESS_CATEGORY)
|
|
159
|
+
.requiredOption('--path <skill-dir>', 'path to a peaks-* skill directory (containing SKILL.md) or directly to a SKILL.md file')).action((options) => lintAction(options, io));
|
|
160
|
+
// `peaks skill ready --category loop-engineering-readiness --path <skill-dir>`
|
|
161
|
+
// — alias verb chosen by M6 for human-facing callouts. It points at
|
|
162
|
+
// the same handler; both verbs are first-class so users (LLM
|
|
163
|
+
// proxies) can pick whichever phrasing fits the conversation.
|
|
164
|
+
// Per the spec, the user never types either verb; the LLM runs the
|
|
165
|
+
// CLI on the user's behalf.
|
|
166
|
+
skill
|
|
167
|
+
.command('ready')
|
|
168
|
+
.description(`M6 alias for \`peaks skill lint --category ${LOOP_ENGINEERING_READINESS_CATEGORY}\`; same flags, same exit codes.`)
|
|
169
|
+
.option('--category <name>', `lint category; the M6 implementation only supports ${LOOP_ENGINEERING_READINESS_CATEGORY}`, LOOP_ENGINEERING_READINESS_CATEGORY)
|
|
170
|
+
.requiredOption('--path <skill-dir>', 'path to a peaks-* skill directory or SKILL.md file')
|
|
171
|
+
.option('--json', 'print machine-readable JSON envelope')
|
|
172
|
+
.action((options) => lintAction(options, io));
|
|
173
|
+
}
|
|
@@ -71,7 +71,7 @@ export type AwaitOptions = {
|
|
|
71
71
|
* to keep the warm-path dispatch CLI cold-start fast (slice 9).
|
|
72
72
|
*/
|
|
73
73
|
export type SliceDagModule = typeof import('../../services/dispatch/slice-dag.js');
|
|
74
|
-
export type DagOrchestratorModule = typeof import('../../services/
|
|
74
|
+
export type DagOrchestratorModule = typeof import('../../services/code/dag-orchestrator.js');
|
|
75
75
|
export type ContractStoreModule = typeof import('../../services/dispatch/contract-store.js');
|
|
76
76
|
/**
|
|
77
77
|
* Validate a role string. Returns `null` when valid, otherwise the
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* v2.15.0 follow-up — G4: user touchpoint CLI.
|
|
3
3
|
*
|
|
4
|
-
* - `peaks
|
|
5
|
-
*
|
|
4
|
+
* - `peaks code gate-classify --step <step-id>` — classify a single
|
|
5
|
+
* Code gate (business / tech / mode-selection / commit-boundary /
|
|
6
6
|
* commit-floor)
|
|
7
|
-
* - `peaks
|
|
7
|
+
* - `peaks code user-touchpoints` — list all gates the
|
|
8
8
|
* user must review (vs AI auto-decides in full-auto)
|
|
9
|
-
* - `peaks
|
|
9
|
+
* - `peaks code commit-boundary-actions` — list the 5
|
|
10
10
|
* hard-floor commit actions (push / tag / publish / global
|
|
11
11
|
* install)
|
|
12
12
|
*
|
|
@@ -1,45 +1,45 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* v2.15.0 follow-up — G4: user touchpoint CLI.
|
|
3
3
|
*
|
|
4
|
-
* - `peaks
|
|
5
|
-
*
|
|
4
|
+
* - `peaks code gate-classify --step <step-id>` — classify a single
|
|
5
|
+
* Code gate (business / tech / mode-selection / commit-boundary /
|
|
6
6
|
* commit-floor)
|
|
7
|
-
* - `peaks
|
|
7
|
+
* - `peaks code user-touchpoints` — list all gates the
|
|
8
8
|
* user must review (vs AI auto-decides in full-auto)
|
|
9
|
-
* - `peaks
|
|
9
|
+
* - `peaks code commit-boundary-actions` — list the 5
|
|
10
10
|
* hard-floor commit actions (push / tag / publish / global
|
|
11
11
|
* install)
|
|
12
12
|
*
|
|
13
13
|
* Surfaces the 12 Gaps positioning memory rule:
|
|
14
14
|
* "user 在循环里 = 业务/产品审阅者,不参与技术决策"
|
|
15
15
|
*/
|
|
16
|
-
import { aiAutoDecidesGates, classifyGate, COMMIT_BOUNDARY_ACTIONS_LIST, userMustReviewGates } from '../../services/
|
|
16
|
+
import { aiAutoDecidesGates, classifyGate, COMMIT_BOUNDARY_ACTIONS_LIST, userMustReviewGates } from '../../services/code/user-touchpoint-classifier.js';
|
|
17
17
|
import { fail, ok } from '../../shared/result.js';
|
|
18
18
|
import { addJsonOption, printResult } from '../cli-helpers.js';
|
|
19
19
|
export function registerUserTouchpointCommands(program, io) {
|
|
20
20
|
// G4 commands are registered as TOP-LEVEL commands (not sub-commands
|
|
21
|
-
// of `peaks
|
|
21
|
+
// of `peaks code`) because `peaks code` is a SKILL (consumed by the
|
|
22
22
|
// LLM in SKILL.md), not a CLI command. Top-level names: gate-classify /
|
|
23
23
|
// user-touchpoints / commit-boundary-actions.
|
|
24
24
|
//
|
|
25
|
-
// We do NOT create a new `peaks
|
|
25
|
+
// We do NOT create a new `peaks code` CLI command here because that
|
|
26
26
|
// would conflict with the peaks-code skill presence tracking (see
|
|
27
27
|
// `src/services/skills/skill-presence-service.ts`).
|
|
28
28
|
addJsonOption(program
|
|
29
29
|
.command('gate-classify')
|
|
30
|
-
.description('v2.15.0 follow-up G4: classify a single
|
|
30
|
+
.description('v2.15.0 follow-up G4: classify a single Code gate by its decision kind: ' +
|
|
31
31
|
'business / tech / mode-selection / commit-boundary / commit-floor. ' +
|
|
32
32
|
'Returns null when the step is unknown.')
|
|
33
33
|
.requiredOption('--step <step-id>', 'step id (e.g. step-1-mode-select, phase-2-prd-confirm)')).action((opts) => {
|
|
34
34
|
const c = classifyGate(opts.step);
|
|
35
35
|
if (c === null) {
|
|
36
|
-
printResult(io, fail('
|
|
37
|
-
'Run `peaks
|
|
36
|
+
printResult(io, fail('code.gate-classify', 'UNKNOWN_STEP', `unknown step "${opts.step}"`, {}, [
|
|
37
|
+
'Run `peaks code user-touchpoints` to list all known steps.'
|
|
38
38
|
]), opts.json ?? false);
|
|
39
39
|
process.exitCode = 1;
|
|
40
40
|
return;
|
|
41
41
|
}
|
|
42
|
-
printResult(io, ok('
|
|
42
|
+
printResult(io, ok('code.gate-classify', { classification: c }, [], [
|
|
43
43
|
c.userShouldReview === 'always'
|
|
44
44
|
? 'User must review this gate in all modes.'
|
|
45
45
|
: c.userShouldReview === 'business-only'
|
|
@@ -49,12 +49,12 @@ export function registerUserTouchpointCommands(program, io) {
|
|
|
49
49
|
});
|
|
50
50
|
addJsonOption(program
|
|
51
51
|
.command('user-touchpoints')
|
|
52
|
-
.description('List all
|
|
52
|
+
.description('List all Code gates the user must review. The 12 Gaps positioning ' +
|
|
53
53
|
'memory: user 在循环里 = 业务/产品审阅者,不参与技术决策。 ' +
|
|
54
54
|
'These are the only gates where the user is asked to decide.')).action((opts) => {
|
|
55
55
|
const must = userMustReviewGates();
|
|
56
56
|
const auto = aiAutoDecidesGates();
|
|
57
|
-
printResult(io, ok('
|
|
57
|
+
printResult(io, ok('code.user-touchpoints', {
|
|
58
58
|
userMustReview: must,
|
|
59
59
|
aiAutoDecides: auto,
|
|
60
60
|
counts: {
|
|
@@ -71,7 +71,7 @@ export function registerUserTouchpointCommands(program, io) {
|
|
|
71
71
|
.description('List the 5 commit-boundary hard-floor actions. These are the ' +
|
|
72
72
|
'actions that PAUSE even in full-auto (v2.15.0 slice 002 AC-4 rule: ' +
|
|
73
73
|
'"full-auto 只做到 commit"). The user is always asked to confirm.')).action((opts) => {
|
|
74
|
-
printResult(io, ok('
|
|
74
|
+
printResult(io, ok('code.commit-boundary-actions', { actions: COMMIT_BOUNDARY_ACTIONS_LIST }, [], [
|
|
75
75
|
'Even in full-auto, the user must explicitly confirm these actions.'
|
|
76
76
|
]), opts.json ?? false);
|
|
77
77
|
});
|