peaks-loop 3.0.0 → 3.0.1
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/.claude-plugin/marketplace.json +3 -3
- package/CHANGELOG.md +57 -57
- package/README-en.md +2 -2
- package/README.md +2 -2
- package/agents/karpathy-reviewer.md +2 -2
- package/dist/src/cli/commands/agent-commands.js +3 -3
- package/dist/src/cli/commands/audit-commands.d.ts +1 -1
- package/dist/src/cli/commands/audit-commands.js +6 -6
- package/dist/src/cli/commands/classify-classify-commands.js +1 -1
- package/dist/src/cli/commands/code-review-commands.d.ts +3 -3
- package/dist/src/cli/commands/code-review-commands.js +5 -5
- package/dist/src/cli/commands/compact-command.d.ts +21 -0
- package/dist/src/cli/commands/compact-command.js +252 -0
- package/dist/src/cli/commands/context-commands.d.ts +1 -1
- package/dist/src/cli/commands/context-commands.js +1 -1
- package/dist/src/cli/commands/contract-commands.d.ts +1 -1
- package/dist/src/cli/commands/core/session-command.js +17 -7
- package/dist/src/cli/commands/core/skill-command.js +1 -1
- package/dist/src/cli/commands/feedback-commands.js +1 -1
- package/dist/src/cli/commands/hook-handle.d.ts +1 -1
- package/dist/src/cli/commands/hook-handle.js +1 -1
- package/dist/src/cli/commands/legacy-commands.d.ts +1 -1
- package/dist/src/cli/commands/legacy-commands.js +2 -2
- package/dist/src/cli/commands/log-commands.js +2 -2
- package/dist/src/cli/commands/loop-commands.d.ts +1 -1
- package/dist/src/cli/commands/loop-commands.js +1 -1
- package/dist/src/cli/commands/loop-eval-commands.d.ts +1 -1
- package/dist/src/cli/commands/loop-eval-commands.js +1 -1
- package/dist/src/cli/commands/playwright-commands.d.ts +1 -1
- package/dist/src/cli/commands/playwright-commands.js +2 -2
- package/dist/src/cli/commands/request-commands.js +40 -1
- package/dist/src/cli/commands/role-commands.js +1 -1
- package/dist/src/cli/commands/slice-commands.js +5 -5
- package/dist/src/cli/commands/upgrade-commands.d.ts +1 -1
- package/dist/src/cli/commands/upgrade-commands.js +6 -6
- package/dist/src/cli/commands/workspace/init-command.js +2 -2
- package/dist/src/cli/program.js +10 -1
- package/dist/src/services/agent/ecc-agent-service.js +5 -5
- package/dist/src/services/audit/artifact-writer.d.ts +1 -1
- package/dist/src/services/audit/artifact-writer.js +1 -1
- package/dist/src/services/audit/decision-writer.d.ts +1 -1
- package/dist/src/services/audit/decision-writer.js +1 -1
- package/dist/src/services/audit/enforcers/lint-output-style.js +5 -5
- package/dist/src/services/audit/enforcers/mock-placement.d.ts +1 -1
- package/dist/src/services/audit/enforcers/mock-placement.js +1 -1
- package/dist/src/services/audit/enforcers/no-root-pollution.js +1 -1
- package/dist/src/services/audit/red-line-catalog-p2-a.js +2 -2
- package/dist/src/services/audit/red-line-catalog-p2-b.js +2 -2
- package/dist/src/services/audit/static-service.d.ts +1 -1
- package/dist/src/services/audit/static-service.js +5 -5
- package/dist/src/services/audit/types.d.ts +1 -1
- package/dist/src/services/audit/types.js +1 -1
- package/dist/src/services/audit-independent/perf-audit-service.js +1 -1
- package/dist/src/services/audit-independent/security-audit-service.js +1 -1
- package/dist/src/services/classify/classify-service.d.ts +1 -1
- package/dist/src/services/classify/classify-service.js +1 -1
- package/dist/src/services/classify/classify-types.d.ts +1 -1
- package/dist/src/services/classify/classify-types.js +1 -1
- package/dist/src/services/code-review/ecc-bridge.d.ts +2 -2
- package/dist/src/services/code-review/ecc-bridge.js +2 -2
- package/dist/src/services/code-review/ocr-service.d.ts +9 -9
- package/dist/src/services/code-review/ocr-service.js +16 -16
- package/dist/src/services/compact/decision-tables.d.ts +66 -0
- package/dist/src/services/compact/decision-tables.js +127 -0
- package/dist/src/services/compact/request-transition-hook.d.ts +20 -0
- package/dist/src/services/compact/request-transition-hook.js +110 -0
- package/dist/src/services/compact/suggest-service.d.ts +74 -0
- package/dist/src/services/compact/suggest-service.js +203 -0
- package/dist/src/services/config/config-migration.js +1 -1
- package/dist/src/services/config/config-safety.d.ts +1 -1
- package/dist/src/services/config/config-safety.js +1 -1
- package/dist/src/services/config/config-service.d.ts +1 -1
- package/dist/src/services/config/config-service.js +1 -1
- package/dist/src/services/context/auto-compact-dispatcher.js +4 -4
- package/dist/src/services/context/auto-compact-types.d.ts +6 -6
- package/dist/src/services/context/auto-compact-types.js +5 -5
- package/dist/src/services/dispatch/sub-agent-dispatcher.js +1 -1
- 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/doctor/doctor-service.d.ts +1 -1
- package/dist/src/services/doctor/doctor-service.js +5 -5
- package/dist/src/services/hooks/presence-marker-detector.js +5 -5
- package/dist/src/services/ide/adapters/claude-code-adapter.d.ts +1 -1
- package/dist/src/services/ide/adapters/claude-code-adapter.js +2 -2
- package/dist/src/services/ide/adapters/codex-adapter.d.ts +2 -2
- package/dist/src/services/ide/adapters/codex-adapter.js +2 -2
- package/dist/src/services/ide/adapters/cursor-adapter.d.ts +2 -2
- package/dist/src/services/ide/adapters/cursor-adapter.js +2 -2
- package/dist/src/services/ide/adapters/hermes-adapter.d.ts +1 -1
- package/dist/src/services/ide/adapters/hermes-adapter.js +1 -1
- package/dist/src/services/ide/adapters/openclaw-adapter.d.ts +1 -1
- package/dist/src/services/ide/adapters/openclaw-adapter.js +1 -1
- package/dist/src/services/ide/adapters/trae-adapter.d.ts +1 -1
- package/dist/src/services/ide/adapters/trae-adapter.js +1 -1
- package/dist/src/services/ide/ide-types.d.ts +9 -9
- package/dist/src/services/legacy/legacy-detector.d.ts +1 -1
- package/dist/src/services/legacy/legacy-detector.js +1 -1
- package/dist/src/services/log/log-commands-service.d.ts +1 -1
- package/dist/src/services/log/log-commands-service.js +1 -1
- package/dist/src/services/log/logger.d.ts +3 -3
- package/dist/src/services/log/logger.js +3 -3
- package/dist/src/services/log/redact.d.ts +1 -1
- package/dist/src/services/log/redact.js +1 -1
- package/dist/src/services/loop/evaluator-dispatcher.d.ts +1 -1
- package/dist/src/services/loop/evaluator-dispatcher.js +16 -15
- package/dist/src/services/loop/monotonic-guard.js +35 -18
- package/dist/src/services/loop/monotonic-runner.d.ts +3 -0
- package/dist/src/services/loop/monotonic-runner.js +62 -28
- package/dist/src/services/loop/run-driver.js +45 -24
- package/dist/src/services/memory/llm-reranker.d.ts +1 -1
- package/dist/src/services/memory/llm-reranker.js +1 -1
- package/dist/src/services/mut/production-stryker.d.ts +0 -5
- package/dist/src/services/mut/production-stryker.js +19 -10
- package/dist/src/services/openspec/openspec-propose-from-doctor-service.d.ts +1 -1
- package/dist/src/services/openspec/openspec-propose-from-doctor-service.js +1 -1
- package/dist/src/services/perf/perf-baseline-service.d.ts +2 -2
- package/dist/src/services/perf/perf-baseline-service.js +2 -2
- package/dist/src/services/prd/handoff-auto-regen.js +1 -1
- package/dist/src/services/prd/project-scan-sediment.js +3 -3
- package/dist/src/services/prd/project-scan-types.d.ts +1 -1
- package/dist/src/services/preferences/preferences-types.d.ts +3 -3
- package/dist/src/services/preferences/preferences-types.js +2 -2
- package/dist/src/services/role/role-registry.d.ts +1 -1
- package/dist/src/services/role/role-registry.js +1 -1
- package/dist/src/services/sc/sc-service.js +3 -3
- package/dist/src/services/skill/resume-detector.js +2 -2
- package/dist/src/services/skills/sync-service.d.ts +3 -3
- package/dist/src/services/skills/sync-service.js +9 -9
- package/dist/src/services/slice/calibration-store.d.ts +1 -1
- package/dist/src/services/slice/calibration-store.js +1 -1
- package/dist/src/services/solo/auto-compact-orchestrator.d.ts +1 -1
- package/dist/src/services/solo/auto-compact-orchestrator.js +7 -7
- package/dist/src/services/solo/dag-orchestrator.js +1 -1
- package/dist/src/services/solo/mode-gate.d.ts +1 -1
- package/dist/src/services/solo/mode-gate.js +4 -4
- package/dist/src/services/solo/user-touchpoint-classifier.js +1 -1
- package/dist/src/services/standards/migrate-claude-rules-service.js +5 -5
- package/dist/src/services/standards/migrate-service.d.ts +3 -3
- package/dist/src/services/standards/migrate-service.js +5 -5
- package/dist/src/services/standards/project-standards-service.js +1 -1
- package/dist/src/services/upgrade/gitignore-migrate-service.d.ts +3 -3
- package/dist/src/services/upgrade/gitignore-migrate-service.js +4 -4
- package/dist/src/services/upgrade/upgrade-service.d.ts +1 -1
- package/dist/src/services/upgrade/upgrade-service.js +5 -5
- package/dist/src/services/verdict/envelopes.d.ts +1 -1
- package/dist/src/services/verdict/envelopes.js +1 -1
- package/dist/src/services/workflow/workflow-loader.js +1 -1
- package/dist/src/services/workspace/migrate-1-4-1-service.d.ts +1 -1
- package/dist/src/services/workspace/migrate-1-4-1-service.js +1 -1
- package/dist/src/services/workspace/migrate-types.d.ts +1 -1
- package/dist/src/services/workspace/migrate-types.js +1 -1
- package/dist/src/services/workspace/workspace-claude-settings-materializer.d.ts +2 -2
- package/dist/src/services/workspace/workspace-claude-settings-materializer.js +9 -9
- package/dist/src/services/workspace/workspace-service.d.ts +1 -1
- package/dist/src/services/workspace/workspace-service.js +1 -1
- package/dist/src/shared/path-safety.d.ts +1 -1
- package/dist/src/shared/path-safety.js +1 -1
- package/dist/src/shared/version.d.ts +1 -1
- package/dist/src/shared/version.js +1 -1
- package/output-styles/peaks-skill-swarm.md +33 -33
- package/package.json +5 -4
- package/schemas/decomposition-v1.json +1 -1
- package/schemas/decomposition-v2.json +1 -1
- package/schemas/replay-fixture.schema.json +1 -1
- package/schemas/reviewer-envelope.schema.json +1 -1
- package/scripts/install-skills.mjs +11 -11
- package/skills/peaks-audit/SKILL.md +2 -2
- package/skills/peaks-doctor/SKILL.md +4 -4
- package/skills/peaks-final-review/SKILL.md +2 -2
- package/skills/peaks-ide/SKILL.md +3 -3
- package/skills/peaks-perf-audit/SKILL.md +1 -1
- package/skills/peaks-prd/SKILL.md +14 -14
- package/skills/peaks-prd/references/workflow.md +1 -1
- package/skills/peaks-qa/SKILL.md +17 -17
- package/skills/peaks-qa/references/artifact-per-request.md +1 -1
- package/skills/peaks-qa/references/browser-validation-contracts.md +2 -2
- package/skills/peaks-qa/references/codegraph-regression-focus.md +1 -1
- package/skills/peaks-qa/references/external-capability-guidance.md +2 -2
- package/skills/peaks-qa/references/qa-fanout-contract.md +1 -1
- package/skills/peaks-qa/references/qa-gstack-integration.md +3 -3
- package/skills/peaks-qa/references/qa-local-artifacts.md +1 -1
- package/skills/peaks-qa/references/qa-matt-pocock-integration.md +1 -1
- package/skills/peaks-qa/references/qa-runbook.md +3 -3
- package/skills/peaks-qa/references/qa-skill-presence.md +1 -1
- package/skills/peaks-qa/references/qa-standards-preflight.md +2 -2
- package/skills/peaks-qa/references/qa-transition-gates.md +9 -9
- package/skills/peaks-qa/references/regression-gates.md +1 -1
- package/skills/peaks-rd/SKILL.md +13 -13
- package/skills/peaks-rd/references/artifact-and-standards-output.md +1 -1
- package/skills/peaks-rd/references/codegraph-project-analysis.md +1 -1
- package/skills/peaks-rd/references/external-references.md +3 -3
- package/skills/peaks-rd/references/karpathy-reviewer-prompt.md +1 -1
- package/skills/peaks-rd/references/mandatory-perf-baseline.md +1 -1
- package/skills/peaks-rd/references/matt-pocock-integration.md +2 -2
- package/skills/peaks-rd/references/ocr-integration.md +19 -19
- package/skills/peaks-rd/references/openspec-cli.md +2 -2
- package/skills/peaks-rd/references/rd-gstack-integration.md +5 -5
- package/skills/peaks-rd/references/rd-runbook.md +9 -9
- package/skills/peaks-rd/references/rd-standards-preflight.md +1 -1
- package/skills/peaks-rd/references/rd-transition-gates.md +13 -13
- package/skills/peaks-rd/references/skill-presence-and-title.md +1 -1
- package/skills/peaks-reviewer/SKILL.md +2 -2
- package/skills/peaks-sc/SKILL.md +9 -9
- package/skills/peaks-security-audit/SKILL.md +1 -1
- package/skills/peaks-slice-decompose/SKILL.md +2 -2
- package/skills/peaks-solo/SKILL.md +49 -49
- package/skills/peaks-solo/references/a2a-artifact-mapping.md +8 -8
- package/skills/peaks-solo/references/anchoring-and-session-info.md +3 -3
- package/skills/peaks-solo/references/boundaries.md +4 -4
- package/skills/peaks-solo/references/browser-workflow.md +2 -2
- package/skills/peaks-solo/references/codegraph-orchestration.md +1 -1
- package/skills/peaks-solo/references/completion-handoff.md +2 -2
- package/skills/peaks-solo/references/external-references.md +3 -3
- package/skills/peaks-solo/references/external-skill-invocation.md +2 -2
- package/skills/peaks-solo/references/frontend-only-mode.md +1 -1
- package/skills/peaks-solo/references/gstack-integration.md +4 -4
- package/skills/peaks-solo/references/local-artifact-workspace.md +2 -2
- package/skills/peaks-solo/references/micro-cycle.md +4 -4
- package/skills/peaks-solo/references/mode-selection.md +5 -5
- package/skills/peaks-solo/references/openspec-workflow.md +2 -2
- package/skills/peaks-solo/references/playwright-mcp-multi-terminal.md +1 -1
- package/skills/peaks-solo/references/project-memory-loading.md +1 -1
- package/skills/peaks-solo/references/project-scan-checklist.md +1 -1
- package/skills/peaks-solo/references/quality-gate-cheatsheet.md +1 -1
- package/skills/peaks-solo/references/resume-detection.md +1 -1
- package/skills/peaks-solo/references/runbook.md +20 -20
- package/skills/peaks-solo/references/skill-presence-and-title.md +2 -2
- package/skills/peaks-solo/references/standards-preflight.md +2 -2
- package/skills/peaks-solo/references/step-0-55-1x-detection.md +3 -3
- package/skills/peaks-solo/references/sub-agent-dispatch.md +3 -3
- package/skills/peaks-solo/references/swarm-dispatch-contract.md +3 -3
- package/skills/peaks-solo/references/workflow-gates-and-types.md +34 -34
- package/skills/peaks-solo-resume/SKILL.md +2 -2
- package/skills/peaks-solo-status/SKILL.md +4 -4
- package/skills/peaks-solo-test/SKILL.md +4 -4
- package/skills/peaks-sop/SKILL.md +5 -5
- package/skills/peaks-txt/SKILL.md +17 -17
- package/skills/peaks-ui/SKILL.md +17 -17
- package/skills/peaks-ui/references/workflow.md +1 -1
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `peaks compact *` — strategic-compact CLI primitives.
|
|
3
|
+
*
|
|
4
|
+
* Slice 2026-07-01-strategic-compact-cli. Five subcommands under a new
|
|
5
|
+
* top-level `peaks compact` group:
|
|
6
|
+
*
|
|
7
|
+
* - suggest: PreToolUse-style two-signal suggestion (context size
|
|
8
|
+
* + tool-call count), read-only by default.
|
|
9
|
+
* - recommend: Pure (from, to) phase-pair → severity lookup.
|
|
10
|
+
* - survival: Static SKILL.md "What Survives Compaction" table.
|
|
11
|
+
* - dry-run: Composite of (suggest + recommend + survival), no
|
|
12
|
+
* writes.
|
|
13
|
+
* - force: Write a pre-compact checkpoint via
|
|
14
|
+
* `peaks session checkpoint`; the IDE-side `/compact`
|
|
15
|
+
* is still the LLM's call.
|
|
16
|
+
*
|
|
17
|
+
* Each subcommand returns a `--json` envelope via `printResult`.
|
|
18
|
+
*/
|
|
19
|
+
import type { Command } from 'commander';
|
|
20
|
+
import { type ProgramIO } from '../cli-helpers.js';
|
|
21
|
+
export declare function registerCompactCommands(program: Command, io: ProgramIO): void;
|
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
import { resolveCanonicalProjectRoot } from '../../services/config/config-service.js';
|
|
2
|
+
import { findProjectRoot } from '../../services/config/config-safety.js';
|
|
3
|
+
import { fail, ok, getErrorMessage } from '../../shared/result.js';
|
|
4
|
+
import { addJsonOption, printResult } from '../cli-helpers.js';
|
|
5
|
+
import { writeCheckpoint } from '../../services/session/session-checkpoint-service.js';
|
|
6
|
+
import { getSessionIdCanonical } from '../../services/session/session-manager.js';
|
|
7
|
+
import { buildRecommendEnvelopePure, dryRunCompact, suggestCompact } from '../../services/compact/suggest-service.js';
|
|
8
|
+
import { PHASES, SURVIVAL_TABLE, isPhase, lookupPhaseTransition } from '../../services/compact/decision-tables.js';
|
|
9
|
+
function splitList(value) {
|
|
10
|
+
if (!value)
|
|
11
|
+
return [];
|
|
12
|
+
return value
|
|
13
|
+
.split(/\r?\n/)
|
|
14
|
+
.map((s) => s.trim())
|
|
15
|
+
.filter((s) => s.length > 0);
|
|
16
|
+
}
|
|
17
|
+
function resolveSessionId(projectRoot, explicit) {
|
|
18
|
+
if (explicit !== undefined && explicit.length > 0) {
|
|
19
|
+
return { sid: explicit, error: null };
|
|
20
|
+
}
|
|
21
|
+
// Statically-imported `getSessionIdCanonical` (see import block
|
|
22
|
+
// at the top of this file). It is the single source of truth for
|
|
23
|
+
// "what session is bound to this project"; we use it instead of
|
|
24
|
+
// re-implementing the resolution here to keep one fix point when
|
|
25
|
+
// the binding layout changes.
|
|
26
|
+
const sid = getSessionIdCanonical(projectRoot) ?? null;
|
|
27
|
+
if (sid === null) {
|
|
28
|
+
return {
|
|
29
|
+
sid: null,
|
|
30
|
+
error: {
|
|
31
|
+
code: 'NO_ACTIVE_SESSION',
|
|
32
|
+
message: 'No active session bound. Run `peaks workspace init --project <repo> --json` to bind one.',
|
|
33
|
+
nextActions: [`peaks workspace init --project ${projectRoot} --json`]
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
return { sid, error: null };
|
|
38
|
+
}
|
|
39
|
+
export function registerCompactCommands(program, io) {
|
|
40
|
+
const compact = program
|
|
41
|
+
.command('compact')
|
|
42
|
+
.description('Strategic-compact primitives: suggest / recommend / survival / dry-run / force');
|
|
43
|
+
// -----------------------------------------------------------------
|
|
44
|
+
// 1. peaks compact suggest [--json]
|
|
45
|
+
// -----------------------------------------------------------------
|
|
46
|
+
addJsonOption(compact
|
|
47
|
+
.command('suggest')
|
|
48
|
+
.description('Two-signal suggestion (context-size + tool-call-count). ' +
|
|
49
|
+
'Honor COMPACT_THRESHOLD / COMPACT_CONTEXT_THRESHOLD / COMPACT_CONTEXT_INTERVAL env vars. ' +
|
|
50
|
+
'Read-only by default; pass --apply to also append a one-line info row to the session log.')
|
|
51
|
+
.option('--project <path>', 'project root (defaults to git root or cwd)')
|
|
52
|
+
.option('--session-id <sid>', 'override the active session id (defaults to the canonical binding)')
|
|
53
|
+
.option('--apply', 'append a one-line info row to .peaks/_runtime/<sid>/session.json (default: dry-run)')).action((options) => {
|
|
54
|
+
try {
|
|
55
|
+
const projectRoot = options.project !== undefined
|
|
56
|
+
? resolveCanonicalProjectRoot(options.project)
|
|
57
|
+
: (findProjectRoot(process.cwd()) ?? process.cwd());
|
|
58
|
+
const session = resolveSessionId(projectRoot, options.sessionId);
|
|
59
|
+
if (session.error !== null) {
|
|
60
|
+
printResult(io, fail('compact.suggest', session.error.code, session.error.message, { projectRoot }, session.error.nextActions), options.json);
|
|
61
|
+
process.exitCode = 1;
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
const result = suggestCompact({
|
|
65
|
+
projectRoot,
|
|
66
|
+
sessionId: session.sid
|
|
67
|
+
});
|
|
68
|
+
printResult(io, ok('compact.suggest', result, [], [
|
|
69
|
+
result.shouldSuggest
|
|
70
|
+
? `Run \`peaks compact force --reason "<short note>"\` to checkpoint, then /compact.`
|
|
71
|
+
: `Context at ${(result.ratio * 100).toFixed(1)}% (${result.tokensUsed} of ${result.windowKind === '1m' ? '1M' : '200k'}); below threshold.`
|
|
72
|
+
]), options.json);
|
|
73
|
+
}
|
|
74
|
+
catch (error) {
|
|
75
|
+
printResult(io, fail('compact.suggest', 'COMPACT_SUGGEST_FAILED', getErrorMessage(error), {}, ['Verify project root and session binding before retrying']), options.json);
|
|
76
|
+
process.exitCode = 1;
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
// -----------------------------------------------------------------
|
|
80
|
+
// 2. peaks compact recommend --from <phase> --to <phase> [--json]
|
|
81
|
+
// -----------------------------------------------------------------
|
|
82
|
+
addJsonOption(compact
|
|
83
|
+
.command('recommend')
|
|
84
|
+
.description(`Strategic-compact "Compaction Decision Guide" lookup. ` +
|
|
85
|
+
`Valid phases: ${PHASES.join(', ')}. Pure function over (from, to); no I/O.`)
|
|
86
|
+
.requiredOption('--from <phase>', `source phase (one of ${PHASES.join(', ')})`)
|
|
87
|
+
.requiredOption('--to <phase>', `target phase (one of ${PHASES.join(', ')})`)).action((options) => {
|
|
88
|
+
try {
|
|
89
|
+
if (!isPhase(options.from)) {
|
|
90
|
+
printResult(io, fail('compact.recommend', 'INVALID_PHASE', `--from must be one of ${PHASES.join(', ')} (got "${options.from}")`, { from: options.from }, [`Use --from ${PHASES.join('|')}`]), options.json);
|
|
91
|
+
process.exitCode = 1;
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
if (!isPhase(options.to)) {
|
|
95
|
+
printResult(io, fail('compact.recommend', 'INVALID_PHASE', `--to must be one of ${PHASES.join(', ')} (got "${options.to}")`, { to: options.to }, [`Use --to ${PHASES.join('|')}`]), options.json);
|
|
96
|
+
process.exitCode = 1;
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
const envelope = buildRecommendEnvelopePure(options.from, options.to);
|
|
100
|
+
const lookup = lookupPhaseTransition(options.from, options.to);
|
|
101
|
+
printResult(io, ok('compact.recommend', {
|
|
102
|
+
from: envelope.from,
|
|
103
|
+
to: envelope.to,
|
|
104
|
+
shouldCompact: envelope.shouldCompact,
|
|
105
|
+
severity: envelope.severity,
|
|
106
|
+
rationale: envelope.rationale,
|
|
107
|
+
suggestedMessage: envelope.suggestedMessage,
|
|
108
|
+
notInTable: lookup.notInTable
|
|
109
|
+
}, lookup.notInTable ? [`Transition ${options.from} → ${options.to} is not in the strategic-compact table; defaulting to severity=no.`] : []), options.json);
|
|
110
|
+
}
|
|
111
|
+
catch (error) {
|
|
112
|
+
printResult(io, fail('compact.recommend', 'COMPACT_RECOMMEND_FAILED', getErrorMessage(error), { from: options.from, to: options.to }, ['Verify the phase pair against the documented transitions']), options.json);
|
|
113
|
+
process.exitCode = 1;
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
// -----------------------------------------------------------------
|
|
117
|
+
// 3. peaks compact survival [--json]
|
|
118
|
+
// -----------------------------------------------------------------
|
|
119
|
+
addJsonOption(compact
|
|
120
|
+
.command('survival')
|
|
121
|
+
.description('Strategic-compact "What Survives Compaction" table. Pure static data; no I/O.')).action((options) => {
|
|
122
|
+
printResult(io, ok('compact.survival', {
|
|
123
|
+
persists: [...SURVIVAL_TABLE.persists],
|
|
124
|
+
lost: [...SURVIVAL_TABLE.lost]
|
|
125
|
+
}, [], [
|
|
126
|
+
'Persists = guaranteed across `/compact`. Lost = not preserved; persist to disk before compacting.'
|
|
127
|
+
]), options.json);
|
|
128
|
+
});
|
|
129
|
+
// -----------------------------------------------------------------
|
|
130
|
+
// 4. peaks compact dry-run [--from <phase>] [--to <phase>] [--json]
|
|
131
|
+
// -----------------------------------------------------------------
|
|
132
|
+
addJsonOption(compact
|
|
133
|
+
.command('dry-run')
|
|
134
|
+
.description('Composite preview of (suggest + recommend + survival). ' +
|
|
135
|
+
'No writes. The LLM calls this every tool-call cycle to stay informed.')
|
|
136
|
+
.option('--from <phase>', `optional source phase for recommend lookup (one of ${PHASES.join(', ')})`)
|
|
137
|
+
.option('--to <phase>', `optional target phase for recommend lookup (one of ${PHASES.join(', ')})`)
|
|
138
|
+
.option('--project <path>', 'project root (defaults to git root or cwd)')
|
|
139
|
+
.option('--session-id <sid>', 'override the active session id')).action((options) => {
|
|
140
|
+
try {
|
|
141
|
+
const projectRoot = options.project !== undefined
|
|
142
|
+
? resolveCanonicalProjectRoot(options.project)
|
|
143
|
+
: (findProjectRoot(process.cwd()) ?? process.cwd());
|
|
144
|
+
const session = resolveSessionId(projectRoot, options.sessionId);
|
|
145
|
+
if (session.error !== null) {
|
|
146
|
+
printResult(io, fail('compact.dry-run', session.error.code, session.error.message, { projectRoot }, session.error.nextActions), options.json);
|
|
147
|
+
process.exitCode = 1;
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
if ((options.from === undefined) !== (options.to === undefined)) {
|
|
151
|
+
printResult(io, fail('compact.dry-run', 'PHASE_PAIR_INCOMPLETE', 'Both --from and --to must be provided together', { from: options.from, to: options.to }, ['Pass both --from and --to, or omit both for a suggest-only dry-run']), options.json);
|
|
152
|
+
process.exitCode = 1;
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
if (options.from !== undefined && !isPhase(options.from)) {
|
|
156
|
+
printResult(io, fail('compact.dry-run', 'INVALID_PHASE', `--from must be one of ${PHASES.join(', ')} (got "${options.from}")`, { from: options.from }, [`Use --from ${PHASES.join('|')}`]), options.json);
|
|
157
|
+
process.exitCode = 1;
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
if (options.to !== undefined && !isPhase(options.to)) {
|
|
161
|
+
printResult(io, fail('compact.dry-run', 'INVALID_PHASE', `--to must be one of ${PHASES.join(', ')} (got "${options.to}")`, { to: options.to }, [`Use --to ${PHASES.join('|')}`]), options.json);
|
|
162
|
+
process.exitCode = 1;
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
const hasPhasePair = options.from !== undefined && options.to !== undefined;
|
|
166
|
+
const dryRunInput = {
|
|
167
|
+
projectRoot,
|
|
168
|
+
sessionId: session.sid
|
|
169
|
+
};
|
|
170
|
+
if (hasPhasePair) {
|
|
171
|
+
dryRunInput.from = options.from;
|
|
172
|
+
dryRunInput.to = options.to;
|
|
173
|
+
}
|
|
174
|
+
const result = dryRunCompact(dryRunInput);
|
|
175
|
+
printResult(io, ok('compact.dry-run', result, [], [
|
|
176
|
+
result.action === 'compact'
|
|
177
|
+
? `Action=compact: run \`peaks compact force --reason "<note>"\`, then /compact.`
|
|
178
|
+
: `Action=skip: continue without compacting.`
|
|
179
|
+
]), options.json);
|
|
180
|
+
}
|
|
181
|
+
catch (error) {
|
|
182
|
+
printResult(io, fail('compact.dry-run', 'COMPACT_DRY_RUN_FAILED', getErrorMessage(error), {}, ['Verify project root, session binding, and phase pair before retrying']), options.json);
|
|
183
|
+
process.exitCode = 1;
|
|
184
|
+
}
|
|
185
|
+
});
|
|
186
|
+
// -----------------------------------------------------------------
|
|
187
|
+
// 5. peaks compact force [--reason <text>] [--json]
|
|
188
|
+
// -----------------------------------------------------------------
|
|
189
|
+
addJsonOption(compact
|
|
190
|
+
.command('force')
|
|
191
|
+
.description('Write a pre-compact checkpoint via `peaks session checkpoint --reason context-fill`. ' +
|
|
192
|
+
'The IDE-side `/compact` is still the LLM\'s call; this primitive guarantees ' +
|
|
193
|
+
'the pre-compact state is persisted. NO sleep, NO wait for IDE response.')
|
|
194
|
+
.option('--reason <text>', 'human-readable reason for the pre-compact checkpoint', 'pre-force-compact')
|
|
195
|
+
.option('--project <path>', 'project root (defaults to git root or cwd)')
|
|
196
|
+
.option('--session-id <sid>', 'override the active session id')
|
|
197
|
+
.option('--current-plan <text>', 'current plan summary (forwarded to the checkpoint snapshot)')
|
|
198
|
+
.option('--open-questions <list>', 'newline-separated open questions')
|
|
199
|
+
.option('--recent-decisions <list>', 'newline-separated recent decisions')
|
|
200
|
+
.option('--recent-artifact-paths <list>', 'newline-separated recent artifact paths')
|
|
201
|
+
.option('--git-status <text>', 'recent git status')
|
|
202
|
+
.option('--skills-active <list>', 'newline-separated active skill names')
|
|
203
|
+
.option('--todo-state <list>', 'newline-separated todo lines')).action((options) => {
|
|
204
|
+
try {
|
|
205
|
+
const projectRoot = options.project !== undefined
|
|
206
|
+
? resolveCanonicalProjectRoot(options.project)
|
|
207
|
+
: (findProjectRoot(process.cwd()) ?? process.cwd());
|
|
208
|
+
const session = resolveSessionId(projectRoot, options.sessionId);
|
|
209
|
+
if (session.error !== null) {
|
|
210
|
+
printResult(io, fail('compact.force', session.error.code, session.error.message, { projectRoot }, session.error.nextActions), options.json);
|
|
211
|
+
process.exitCode = 1;
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
const reason = (options.reason ?? 'pre-force-compact').slice(0, 200);
|
|
215
|
+
// The session-checkpoint-service restricts `reason` to a fixed
|
|
216
|
+
// enum. The strategic-compact `force` primitive uses
|
|
217
|
+
// 'context-fill' (the closest semantic match: the LLM is
|
|
218
|
+
// compacting because of context pressure) and records the
|
|
219
|
+
// caller's free-form reason in `gitStatus` so the snapshot
|
|
220
|
+
// is self-describing without inventing a new enum value.
|
|
221
|
+
const checkpointOptions = {
|
|
222
|
+
sessionId: session.sid,
|
|
223
|
+
reason: 'context-fill',
|
|
224
|
+
gitStatus: `compact.force: ${reason}`,
|
|
225
|
+
openQuestions: splitList(options.openQuestions),
|
|
226
|
+
recentDecisions: splitList(options.recentDecisions),
|
|
227
|
+
recentArtifactPaths: splitList(options.recentArtifactPaths),
|
|
228
|
+
skillsActive: splitList(options.skillsActive),
|
|
229
|
+
todoState: splitList(options.todoState)
|
|
230
|
+
};
|
|
231
|
+
if (options.currentPlan !== undefined) {
|
|
232
|
+
checkpointOptions.currentPlan = options.currentPlan;
|
|
233
|
+
}
|
|
234
|
+
const result = writeCheckpoint(projectRoot, checkpointOptions);
|
|
235
|
+
printResult(io, ok('compact.force', {
|
|
236
|
+
checkpointPath: result.path,
|
|
237
|
+
reason: 'pre-force-compact',
|
|
238
|
+
callerReason: reason,
|
|
239
|
+
sessionId: result.sessionId,
|
|
240
|
+
createdAt: result.createdAt,
|
|
241
|
+
totalRetained: result.totalRetained,
|
|
242
|
+
message: 'Pre-compact checkpoint written. The IDE-side /compact is still the LLM\'s call; this CLI does NOT invoke the IDE slash command.'
|
|
243
|
+
}, [], [
|
|
244
|
+
'After the LLM fires the IDE-side /compact, call `peaks compact survival` to see what to persist before the next compact.'
|
|
245
|
+
]), options.json);
|
|
246
|
+
}
|
|
247
|
+
catch (error) {
|
|
248
|
+
printResult(io, fail('compact.force', 'COMPACT_FORCE_FAILED', getErrorMessage(error), {}, ['Verify the project path is writable and a session is bound']), options.json);
|
|
249
|
+
process.exitCode = 1;
|
|
250
|
+
}
|
|
251
|
+
});
|
|
252
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* peaks context * CLI (Slice #3 L1c) — context 4-layer loader.
|
|
3
3
|
*
|
|
4
|
-
* Per docs/superpowers/specs/2026-06-11-peaks-
|
|
4
|
+
* Per docs/superpowers/specs/2026-06-11-peaks-loop-l1-l2-l3-redesign.md §4 L1c:
|
|
5
5
|
* - L0: full read (every SKILL.md in full)
|
|
6
6
|
* - L1: summary (one paragraph per skill + the skill list)
|
|
7
7
|
* - L2: index (just names + paths)
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* peaks context * CLI (Slice #3 L1c) — context 4-layer loader.
|
|
3
3
|
*
|
|
4
|
-
* Per docs/superpowers/specs/2026-06-11-peaks-
|
|
4
|
+
* Per docs/superpowers/specs/2026-06-11-peaks-loop-l1-l2-l3-redesign.md §4 L1c:
|
|
5
5
|
* - L0: full read (every SKILL.md in full)
|
|
6
6
|
* - L1: summary (one paragraph per skill + the skill list)
|
|
7
7
|
* - L2: index (just names + paths)
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
* `src/services/dispatch/contract-store.ts`; it accepts the same
|
|
15
15
|
* shape, splits the comma-separated `--exports` / `--types` /
|
|
16
16
|
* `--signatures` flag values into arrays, and surfaces the result
|
|
17
|
-
* via the standard `ok` / `fail` envelope used across peaks-
|
|
17
|
+
* via the standard `ok` / `fail` envelope used across peaks-loop.
|
|
18
18
|
*
|
|
19
19
|
* Skill-first / CLI-auxiliary red line: users do not invoke this
|
|
20
20
|
* directly. The peaks-solo / peaks-rd LLM-side runner (the
|
|
@@ -5,6 +5,14 @@ import { resolveCanonicalProjectRoot } from '../../../services/config/config-ser
|
|
|
5
5
|
import { findProjectRoot } from '../../../services/config/config-safety.js';
|
|
6
6
|
import { fail, ok } from '../../../shared/result.js';
|
|
7
7
|
import { addJsonOption, getErrorMessage, printResult } from '../../cli-helpers.js';
|
|
8
|
+
// Slice 2026-07-01-strategic-compact-cli fix: register the
|
|
9
|
+
// `peaks session checkpoint` and `peaks session resume` subcommands
|
|
10
|
+
// EAGERLY so they appear in `peaks session --help` output. The
|
|
11
|
+
// previous lazy import ran AFTER commander had already produced
|
|
12
|
+
// the help text, so an LLM calling `peaks <TAB>`-discovery never
|
|
13
|
+
// saw them — they were effectively hidden.
|
|
14
|
+
import { registerSessionCheckpointCommand } from '../session-checkpoint-command.js';
|
|
15
|
+
import { registerSessionResumeCommand } from '../session-resume-command.js';
|
|
8
16
|
export function registerSessionCommand(program, io) {
|
|
9
17
|
const session = program.command('session').description('Manage Peaks session directories');
|
|
10
18
|
addJsonOption(session
|
|
@@ -169,13 +177,15 @@ export function registerSessionCommand(program, io) {
|
|
|
169
177
|
});
|
|
170
178
|
// Slice 011: `peaks session checkpoint` and `peaks session resume`.
|
|
171
179
|
// Skill-level primitives — the LLM is the decision-maker; CLI is the muscle.
|
|
172
|
-
//
|
|
173
|
-
void (async () =>
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
180
|
+
// Slice 2026-07-01-strategic-compact-cli fix: register EAGERLY (not
|
|
181
|
+
// via `void (async () => …)`) so commander walks the subcommand
|
|
182
|
+
// tree synchronously and `peaks session --help` includes both
|
|
183
|
+
// `checkpoint` and `resume`. The previous async-IIFE registered
|
|
184
|
+
// them on a microtask tick AFTER the program-level help builder
|
|
185
|
+
// had already serialised its output, so they were hidden from
|
|
186
|
+
// `<TAB>`-discovery and the LLM never saw them.
|
|
187
|
+
registerSessionCheckpointCommand(session, io);
|
|
188
|
+
registerSessionResumeCommand(session, io);
|
|
179
189
|
addJsonOption(session
|
|
180
190
|
.command('rotate')
|
|
181
191
|
.description('Drop the project-level session binding so the next peaks call auto-generates a fresh session id. The on-disk session directory is left intact — only .peaks/.session.json is removed.')
|
|
@@ -264,7 +264,7 @@ export function registerSkillCommand(program, io) {
|
|
|
264
264
|
});
|
|
265
265
|
addJsonOption(skill
|
|
266
266
|
.command('detect-marker-loss')
|
|
267
|
-
.description('Detect whether the latest assistant message lost the Peaks-
|
|
267
|
+
.description('Detect whether the latest assistant message lost the Peaks-Loop status header while a peaks skill is still active (slice 028 detection primitive).')
|
|
268
268
|
.option('--project <path>', 'project root path (auto-detected from cwd when omitted)')
|
|
269
269
|
.option('--message <text>', 'latest assistant message text to scan (defaults to reading the most recent LLM response from the stdin pipe, or empty string when no pipe is attached)')).action((options) => {
|
|
270
270
|
const projectRoot = options.project ?? findProjectRoot(process.cwd()) ?? process.cwd();
|
|
@@ -22,7 +22,7 @@ import { addJsonOption, getErrorMessage, printResult } from '../cli-helpers.js';
|
|
|
22
22
|
export function registerFeedbackCommands(program, io) {
|
|
23
23
|
const feedback = program
|
|
24
24
|
.command('feedback')
|
|
25
|
-
.description('v2.15.0 slice 002 AC-3: promote user-given feedback memories to peaks-
|
|
25
|
+
.description('v2.15.0 slice 002 AC-3: promote user-given feedback memories to peaks-loop enforcement layers (A: sop, B: hooks, C: hard-floor).');
|
|
26
26
|
addJsonOption(feedback
|
|
27
27
|
.command('promote <memory-file>')
|
|
28
28
|
.description('Promote a feedback memory to one of the 3 enforcement layers (A=peaks-sop gate, B=peaks-hooks PreToolUse, C=mode-gate hardFloorCategory). ' +
|
|
@@ -3,7 +3,7 @@ import { type ProgramIO } from '../cli-helpers.js';
|
|
|
3
3
|
/**
|
|
4
4
|
* `peaks hook handle` —— peaks 自有 hook 协议的单一入口。
|
|
5
5
|
*
|
|
6
|
-
* 该命令是 peaks-
|
|
6
|
+
* 该命令是 peaks-loop 拥有的 hook 处理总入口。它:
|
|
7
7
|
* 1. 读 stdin
|
|
8
8
|
* 2. auto-detect 来源 IDE(env / stdin shape / cwd)
|
|
9
9
|
* 3. 归一化到 peaks canonical schema
|
|
@@ -31,7 +31,7 @@ async function readStdin() {
|
|
|
31
31
|
/**
|
|
32
32
|
* `peaks hook handle` —— peaks 自有 hook 协议的单一入口。
|
|
33
33
|
*
|
|
34
|
-
* 该命令是 peaks-
|
|
34
|
+
* 该命令是 peaks-loop 拥有的 hook 处理总入口。它:
|
|
35
35
|
* 1. 读 stdin
|
|
36
36
|
* 2. auto-detect 来源 IDE(env / stdin shape / cwd)
|
|
37
37
|
* 3. 归一化到 peaks canonical schema
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* - `peaks legacy detect --dir <path>` — scan a directory for legacy
|
|
5
5
|
* smells (TODO/FIXME/HACK, console.log, any-type, large files, ts-ignore).
|
|
6
|
-
* Useful as a "where to start" inventory when peaks-
|
|
6
|
+
* Useful as a "where to start" inventory when peaks-loop is applied
|
|
7
7
|
* to a 存量老项目.
|
|
8
8
|
*/
|
|
9
9
|
import type { Command } from 'commander';
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* - `peaks legacy detect --dir <path>` — scan a directory for legacy
|
|
5
5
|
* smells (TODO/FIXME/HACK, console.log, any-type, large files, ts-ignore).
|
|
6
|
-
* Useful as a "where to start" inventory when peaks-
|
|
6
|
+
* Useful as a "where to start" inventory when peaks-loop is applied
|
|
7
7
|
* to a 存量老项目.
|
|
8
8
|
*/
|
|
9
9
|
import { findProjectRoot } from '../../services/config/config-safety.js';
|
|
@@ -17,7 +17,7 @@ export function registerLegacyCommands(program, io) {
|
|
|
17
17
|
'console.log, any-type, large files, ts-ignore). Returns a smell grade ' +
|
|
18
18
|
'(low / medium / high) and per-kind counts. Lightweight heuristics — ' +
|
|
19
19
|
'NOT a replacement for a real linter. Useful as a "where to start" ' +
|
|
20
|
-
'inventory when peaks-
|
|
20
|
+
'inventory when peaks-loop is applied to a legacy codebase.')
|
|
21
21
|
.option('--dir <path>', 'directory to scan (default: src)', 'src')
|
|
22
22
|
.option('--project <path>', 'project root (default: cwd)')).action((opts) => {
|
|
23
23
|
const projectRoot = opts.project ?? findProjectRoot(process.cwd()) ?? process.cwd();
|
|
@@ -20,10 +20,10 @@ import { ok, fail } from '../../shared/result.js';
|
|
|
20
20
|
export function registerLogCommands(program, io) {
|
|
21
21
|
const log = program
|
|
22
22
|
.command('log')
|
|
23
|
-
.description('Inspect the peaks-
|
|
23
|
+
.description('Inspect the peaks-loop JSONL log directory (default: ~/.peaks/logs/)');
|
|
24
24
|
addJsonOption(log
|
|
25
25
|
.command('tail')
|
|
26
|
-
.description('Print the last 50 lines of today\'s peaks-
|
|
26
|
+
.description('Print the last 50 lines of today\'s peaks-loop log (JSONL). Pass --lines N to change the count, --date YYYY-MM-DD to read a different day, --batch <id> to filter by batchId, --json to print a JSON envelope.')
|
|
27
27
|
.option('--lines <n>', 'number of lines to show (default 50)', (value) => Number(value))
|
|
28
28
|
.option('--date <YYYY-MM-DD>', 'read the log for this UTC date instead of today (PRD AC2: PEAKS_LOG_DATE_OVERRIDE)')
|
|
29
29
|
// Slice 2026-06-23-audit-4th #B2: --batch filter for cross-run
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* peaks loop * CLI (Slice #14) — L4 Agent Loop Integration.
|
|
3
3
|
*
|
|
4
|
-
* Per docs/superpowers/specs/2026-06-11-peaks-
|
|
4
|
+
* Per docs/superpowers/specs/2026-06-11-peaks-loop-l1-l2-l3-redesign.md §5.4
|
|
5
5
|
* Slice #14, ships 5 sub-features:
|
|
6
6
|
*
|
|
7
7
|
* 14.1 peaks loop distill — extract patterns from past sessions
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* peaks loop * CLI (Slice #14) — L4 Agent Loop Integration.
|
|
3
3
|
*
|
|
4
|
-
* Per docs/superpowers/specs/2026-06-11-peaks-
|
|
4
|
+
* Per docs/superpowers/specs/2026-06-11-peaks-loop-l1-l2-l3-redesign.md §5.4
|
|
5
5
|
* Slice #14, ships 5 sub-features:
|
|
6
6
|
*
|
|
7
7
|
* 14.1 peaks loop distill — extract patterns from past sessions
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
*
|
|
6
6
|
* New commands (added under the existing `peaks workflow` group and the
|
|
7
7
|
* existing `peaks loop` group — never as new top-level commands, per the
|
|
8
|
-
* peaks-
|
|
8
|
+
* peaks-loop add-a-new-subcommand-check-for-existing-top-level-first rule):
|
|
9
9
|
*
|
|
10
10
|
* peaks workflow run <id> --session <sid> --project <repo> --json
|
|
11
11
|
* peaks workflow plan <id> --session <sid> --json (dry-run)
|
|
@@ -199,7 +199,7 @@ export function registerWorkflowEvalCommands(program, io) {
|
|
|
199
199
|
...(capture !== null ? { score: capture.score, capture } : {})
|
|
200
200
|
}, [], envelope.degraded
|
|
201
201
|
? ['Evaluator ran in degraded mode (peaks CLI unavailable). Verify the verdict by running `peaks verdict aggregate --from-rid ' + rid + '`.',
|
|
202
|
-
'Re-run on a fully-installed peaks-
|
|
202
|
+
'Re-run on a fully-installed peaks-loop environment for a real verdict.']
|
|
203
203
|
: [`Verifier verdict-aggregate can consume this envelope via \`peaks verdict aggregate --from-rid ${rid}\`.`]), options.json);
|
|
204
204
|
process.exitCode = exitCode;
|
|
205
205
|
}
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
* 3. hash(process.ppid + process.env.SSH_TTY || 'no-tty')
|
|
26
26
|
*
|
|
27
27
|
* The CLI does NOT bundle `playwright-mcp`; it shells out to
|
|
28
|
-
* `npx playwright-mcp@latest` (G22 / NG3). peaks-
|
|
28
|
+
* `npx playwright-mcp@latest` (G22 / NG3). peaks-loop is the lifecycle
|
|
29
29
|
* orchestrator, not the install medium.
|
|
30
30
|
*/
|
|
31
31
|
import { spawn } from 'node:child_process';
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
* 3. hash(process.ppid + process.env.SSH_TTY || 'no-tty')
|
|
26
26
|
*
|
|
27
27
|
* The CLI does NOT bundle `playwright-mcp`; it shells out to
|
|
28
|
-
* `npx playwright-mcp@latest` (G22 / NG3). peaks-
|
|
28
|
+
* `npx playwright-mcp@latest` (G22 / NG3). peaks-loop is the lifecycle
|
|
29
29
|
* orchestrator, not the install medium.
|
|
30
30
|
*/
|
|
31
31
|
import { createHash } from 'node:crypto';
|
|
@@ -428,5 +428,5 @@ export function resolveUserDataDir(raw, projectRoot) {
|
|
|
428
428
|
* the `runBrowserAction(..., caller)` overload.
|
|
429
429
|
*/
|
|
430
430
|
async function mockOrPassThroughCaller(tool, args) {
|
|
431
|
-
return { tool, args, routedBy: 'peaks-
|
|
431
|
+
return { tool, args, routedBy: 'peaks-loop-browser-wrapper' };
|
|
432
432
|
}
|
|
@@ -342,6 +342,33 @@ export function registerRequestCommands(program, io) {
|
|
|
342
342
|
process.exitCode = 1;
|
|
343
343
|
return;
|
|
344
344
|
}
|
|
345
|
+
// Slice 2026-07-01-strategic-compact-cli — slice-boundary pre-compact
|
|
346
|
+
// hook. When transitioning across the RD → QA boundary (rd:qa-handoff),
|
|
347
|
+
// check the active session's context-fill ratio. If it is in the
|
|
348
|
+
// 0.85–0.95 pre-compact zone, write a checkpoint BEFORE the
|
|
349
|
+
// transition completes and attach `preCompactCheckpoint: true` to
|
|
350
|
+
// the response envelope. The LLM remains the decision-maker; this
|
|
351
|
+
// hook only surfaces the signal. The 0.95 red-line behaviour is
|
|
352
|
+
// unchanged — the existing auto-compact orchestrator continues to
|
|
353
|
+
// refuse dispatch at ratio ≥ 0.95.
|
|
354
|
+
let preCompact = null;
|
|
355
|
+
if (role === 'rd' && newState === 'qa-handoff') {
|
|
356
|
+
try {
|
|
357
|
+
const { maybePreCompactCheckpoint } = await import('../../services/compact/request-transition-hook.js');
|
|
358
|
+
const hook = maybePreCompactCheckpoint({
|
|
359
|
+
projectRoot: options.project,
|
|
360
|
+
sessionId: result.sessionId,
|
|
361
|
+
transitionKey: `${role}:${newState}`
|
|
362
|
+
});
|
|
363
|
+
preCompact = hook.triggered
|
|
364
|
+
? ok('request.transition.preCompact', hook)
|
|
365
|
+
: null;
|
|
366
|
+
}
|
|
367
|
+
catch {
|
|
368
|
+
// The hook is best-effort; never block the transition.
|
|
369
|
+
preCompact = null;
|
|
370
|
+
}
|
|
371
|
+
}
|
|
345
372
|
// v2.13.2 AC-4 — auto-regen prd/handoff.md on prd:handed-off success.
|
|
346
373
|
// Only fires when the handoff is missing; existing handoffs are not overwritten.
|
|
347
374
|
if (role === 'prd' && newState === 'handed-off' && options.sessionId !== undefined) {
|
|
@@ -365,7 +392,19 @@ export function registerRequestCommands(program, io) {
|
|
|
365
392
|
printResult(io, ok('request.transition', { ...result, handoffAutoRegen: { status: 'failed', reason: regen.reason } }, [`prd handoff auto-regen failed: ${regen.reason}`]), options.json);
|
|
366
393
|
return;
|
|
367
394
|
}
|
|
368
|
-
|
|
395
|
+
// Slice 2026-07-01-strategic-compact-cli: stitch the pre-compact
|
|
396
|
+
// checkpoint signal into the final response envelope. When the
|
|
397
|
+
// hook did not trigger (zone is not pre-compact OR the
|
|
398
|
+
// transition is not a slice boundary), preCompact is null and
|
|
399
|
+
// we emit a `preCompactCheckpoint: null` field so LLM callers
|
|
400
|
+
// can branch on it without re-deriving zone membership.
|
|
401
|
+
printResult(io, ok('request.transition', { ...result, preCompactCheckpoint: preCompact?.data ?? null }, preCompact !== null
|
|
402
|
+
? [
|
|
403
|
+
`Pre-compact checkpoint written at ratio=${typeof preCompact.data === 'object' && preCompact.data !== null && 'ratio' in preCompact.data
|
|
404
|
+
? String(preCompact.data.ratio)
|
|
405
|
+
: 'unknown'} (zone=pre-compact)`
|
|
406
|
+
]
|
|
407
|
+
: []), options.json);
|
|
369
408
|
}
|
|
370
409
|
catch (error) {
|
|
371
410
|
if (error instanceof InvalidArgumentError) {
|
|
@@ -15,7 +15,7 @@ import { addJsonOption, printResult } from '../cli-helpers.js';
|
|
|
15
15
|
export function registerRoleCommands(program, io) {
|
|
16
16
|
const role = program
|
|
17
17
|
.command('role')
|
|
18
|
-
.description('v2.15.0 follow-up G9: lightweight role registry (RBAC for multi-user peaks-
|
|
18
|
+
.description('v2.15.0 follow-up G9: lightweight role registry (RBAC for multi-user peaks-loop teams).');
|
|
19
19
|
addJsonOption(role
|
|
20
20
|
.command('list')
|
|
21
21
|
.description('List all roles in the registry.')
|
|
@@ -133,7 +133,7 @@ export function registerSliceCommands(program, io) {
|
|
|
133
133
|
.option('--project <path>', 'target project root', '.')
|
|
134
134
|
.option('--refresh', 're-run `peaks codegraph index` before reading', false)
|
|
135
135
|
.option('--benchmark', 'record per-run metrics and attach to the result envelope (2.1.1 algorithm optimization comparison)', false)
|
|
136
|
-
.option('--granularity <value>', 'service | file | both | auto. Default "both" keeps the v1 6-stage path; service / file / auto enable v2 multi-pass decomposition (peaks-
|
|
136
|
+
.option('--granularity <value>', 'service | file | both | auto. Default "both" keeps the v1 6-stage path; service / file / auto enable v2 multi-pass decomposition (peaks-loop 2.9+) and emit a DecompositionResultV2 envelope via SchemaRouter', 'both')).action(async (rid, options) => {
|
|
137
137
|
// Validate --granularity BEFORE any I/O so invalid values fail fast with a
|
|
138
138
|
// nextActions hint listing the four allowed strings.
|
|
139
139
|
const granularity = options.granularity ?? 'both';
|
|
@@ -144,7 +144,7 @@ export function registerSliceCommands(program, io) {
|
|
|
144
144
|
printResult(io, fail('slice.decompose', 'SLICE_DECOMPOSE_FAILED', `Invalid --granularity '${options.granularity}'.`, { rid, projectRoot: options.project }, [
|
|
145
145
|
`--granularity accepts one of: service, file, both, auto`,
|
|
146
146
|
`Default (omit the flag or pass "both") keeps the existing v1 path.`,
|
|
147
|
-
`Non-default values (service / file / auto) enable v2 multi-pass decomposition (peaks-
|
|
147
|
+
`Non-default values (service / file / auto) enable v2 multi-pass decomposition (peaks-loop 2.9+).`
|
|
148
148
|
]), options.json ?? false);
|
|
149
149
|
process.exitCode = 1;
|
|
150
150
|
return;
|
|
@@ -166,7 +166,7 @@ export function registerSliceCommands(program, io) {
|
|
|
166
166
|
writeSchemaResult(outPath, v2Result);
|
|
167
167
|
const nextActions = [
|
|
168
168
|
`Decomposition (v2) written to ${outPath}`,
|
|
169
|
-
`peaks slice pick/plan: v2 schemas require SchemaRouter-aware consumers (peaks-
|
|
169
|
+
`peaks slice pick/plan: v2 schemas require SchemaRouter-aware consumers (peaks-loop 2.9+).`
|
|
170
170
|
];
|
|
171
171
|
printResult(io, ok('slice.decompose', { ...v2Result, outputPath: outPath }, [], nextActions), options.json ?? false);
|
|
172
172
|
return;
|
|
@@ -230,9 +230,9 @@ export function registerSliceCommands(program, io) {
|
|
|
230
230
|
const parsed = readDecompositionResult(decompPath);
|
|
231
231
|
if ('schemaVersion' in parsed) {
|
|
232
232
|
throw new Error(`decomposition at ${decompPath} is a v2 envelope (schemaVersion: 'v2'). ` +
|
|
233
|
-
`peaks slice pick supports v1 only in peaks-
|
|
233
|
+
`peaks slice pick supports v1 only in peaks-loop 2.9.0. ` +
|
|
234
234
|
`Re-run \`peaks slice decompose ${rid}\` without --granularity to get a v1 file, ` +
|
|
235
|
-
`or upgrade peaks-
|
|
235
|
+
`or upgrade peaks-loop when v2 pick lands.`);
|
|
236
236
|
}
|
|
237
237
|
const decomposition = parsed;
|
|
238
238
|
const result = await pickSlicesInteractive(rid, decomposition, projectRoot, {
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*
|
|
5
5
|
* Per the "one-key completion" + "minimal-user-operation" tenets
|
|
6
6
|
* (2026-06-11), the user's typical upgrade path is
|
|
7
|
-
* `npm i -g peaks-
|
|
7
|
+
* `npm i -g peaks-loop@2.0` (the postinstall does the upgrade).
|
|
8
8
|
*
|
|
9
9
|
* The `peaks upgrade --to 2.0` CLI is the manual fallback for
|
|
10
10
|
* when the postinstall is skipped (e.g. CI uses
|