peaks-loop 4.1.2 → 4.1.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/.claude-plugin/marketplace.json +136 -47
- package/CHANGELOG.md +56 -0
- package/README-en.md +1 -1
- package/README.md +1 -1
- package/contracts/readonly-argv-whitelist.json +211 -0
- package/dist/cli/commands/audit-artifact-runners.d.ts +16 -0
- package/dist/cli/commands/audit-artifact-runners.js +170 -0
- package/dist/cli/commands/audit-command-shared.d.ts +97 -0
- package/dist/cli/commands/audit-command-shared.js +60 -0
- package/dist/cli/commands/audit-commands.d.ts +7 -31
- package/dist/cli/commands/audit-commands.js +64 -473
- package/dist/cli/commands/audit-goal-runners.d.ts +17 -0
- package/dist/cli/commands/audit-goal-runners.js +114 -0
- package/dist/cli/commands/audit-red-lines-runners.d.ts +11 -0
- package/dist/cli/commands/audit-red-lines-runners.js +43 -0
- package/dist/cli/commands/audit-refusal-data.d.ts +23 -0
- package/dist/cli/commands/audit-refusal-data.js +69 -0
- package/dist/cli/commands/audit-static-runners.d.ts +13 -0
- package/dist/cli/commands/audit-static-runners.js +139 -0
- package/dist/cli/commands/await-runners.d.ts +11 -0
- package/dist/cli/commands/await-runners.js +148 -0
- package/dist/cli/commands/code-auto-compact-command.d.ts +3 -0
- package/dist/cli/commands/code-auto-compact-command.js +124 -0
- package/dist/cli/commands/code-auto-compact-envelope.d.ts +22 -0
- package/dist/cli/commands/code-auto-compact-envelope.js +39 -0
- package/dist/cli/commands/code-context-audit-command.d.ts +3 -0
- package/dist/cli/commands/code-context-audit-command.js +68 -0
- package/dist/cli/commands/code-context-now-command.d.ts +3 -0
- package/dist/cli/commands/code-context-now-command.js +124 -0
- package/dist/cli/commands/code-context-now-envelope.d.ts +66 -0
- package/dist/cli/commands/code-context-now-envelope.js +136 -0
- package/dist/cli/commands/code-context-now-mapping.d.ts +27 -0
- package/dist/cli/commands/code-context-now-mapping.js +43 -0
- package/dist/cli/commands/code-emit-handoff-command.d.ts +3 -0
- package/dist/cli/commands/code-emit-handoff-command.js +99 -0
- package/dist/cli/commands/code-gate-step-08-command.d.ts +3 -0
- package/dist/cli/commands/code-gate-step-08-command.js +139 -0
- package/dist/cli/commands/code-post-compact-detect-command.d.ts +3 -0
- package/dist/cli/commands/code-post-compact-detect-command.js +50 -0
- package/dist/cli/commands/code-runtime-commands.d.ts +9 -43
- package/dist/cli/commands/code-runtime-commands.js +20 -672
- package/dist/cli/commands/code-runtime-session.d.ts +1 -0
- package/dist/cli/commands/code-runtime-session.js +15 -0
- package/dist/cli/commands/compact-command.d.ts +6 -2
- package/dist/cli/commands/compact-command.js +12 -559
- package/dist/cli/commands/compact-dry-run-command.d.ts +3 -0
- package/dist/cli/commands/compact-dry-run-command.js +87 -0
- package/dist/cli/commands/compact-force-command.d.ts +3 -0
- package/dist/cli/commands/compact-force-command.js +98 -0
- package/dist/cli/commands/compact-harness-window-command.d.ts +3 -0
- package/dist/cli/commands/compact-harness-window-command.js +174 -0
- package/dist/cli/commands/compact-history-command.d.ts +3 -0
- package/dist/cli/commands/compact-history-command.js +89 -0
- package/dist/cli/commands/compact-read-commands.d.ts +3 -0
- package/dist/cli/commands/compact-read-commands.js +123 -0
- package/dist/cli/commands/compact-settle-command.d.ts +3 -0
- package/dist/cli/commands/compact-settle-command.js +130 -0
- package/dist/cli/commands/compact-shared.d.ts +9 -0
- package/dist/cli/commands/compact-shared.js +26 -0
- package/dist/cli/commands/core/skill-command.d.ts +1 -44
- package/dist/cli/commands/core/skill-command.js +13 -541
- package/dist/cli/commands/core/skill-context-verdict.d.ts +38 -0
- package/dist/cli/commands/core/skill-context-verdict.js +63 -0
- package/dist/cli/commands/core/skill-generated-config-notice.d.ts +41 -0
- package/dist/cli/commands/core/skill-generated-config-notice.js +75 -0
- package/dist/cli/commands/core/skill-heartbeat-commands.d.ts +3 -0
- package/dist/cli/commands/core/skill-heartbeat-commands.js +50 -0
- package/dist/cli/commands/core/skill-presence-commands.d.ts +3 -0
- package/dist/cli/commands/core/skill-presence-commands.js +123 -0
- package/dist/cli/commands/core/skill-presence-housekeeping-commands.d.ts +3 -0
- package/dist/cli/commands/core/skill-presence-housekeeping-commands.js +165 -0
- package/dist/cli/commands/core/skill-registry-commands.d.ts +3 -0
- package/dist/cli/commands/core/skill-registry-commands.js +117 -0
- package/dist/cli/commands/core/skill-runbook-command.d.ts +3 -0
- package/dist/cli/commands/core/skill-runbook-command.js +29 -0
- package/dist/cli/commands/dispatch-command-spec.d.ts +2 -0
- package/dist/cli/commands/dispatch-command-spec.js +62 -0
- package/dist/cli/commands/dispatch-commands.js +159 -775
- package/dist/cli/commands/dispatch-detached-branch.d.ts +3 -0
- package/dist/cli/commands/dispatch-detached-branch.js +58 -0
- package/dist/cli/commands/dispatch-envelope.d.ts +36 -0
- package/dist/cli/commands/dispatch-envelope.js +104 -0
- package/dist/cli/commands/dispatch-isolation-lease.d.ts +17 -0
- package/dist/cli/commands/dispatch-isolation-lease.js +149 -0
- package/dist/cli/commands/dispatch-preflight.d.ts +7 -0
- package/dist/cli/commands/dispatch-preflight.js +105 -0
- package/dist/cli/commands/dispatch-prompt-blocks.d.ts +10 -0
- package/dist/cli/commands/dispatch-prompt-blocks.js +56 -0
- package/dist/cli/commands/dispatch-prompt-composition.d.ts +30 -0
- package/dist/cli/commands/dispatch-prompt-composition.js +171 -0
- package/dist/cli/commands/dispatch-record-write.d.ts +24 -0
- package/dist/cli/commands/dispatch-record-write.js +96 -0
- package/dist/cli/commands/dispatch-tool-call.d.ts +15 -0
- package/dist/cli/commands/dispatch-tool-call.js +128 -0
- package/dist/cli/commands/evolution-command-shared.d.ts +78 -0
- package/dist/cli/commands/evolution-command-shared.js +107 -0
- package/dist/cli/commands/evolution-commands.d.ts +11 -1
- package/dist/cli/commands/evolution-commands.js +19 -350
- package/dist/cli/commands/evolution-evaluate-command.d.ts +24 -0
- package/dist/cli/commands/evolution-evaluate-command.js +138 -0
- package/dist/cli/commands/evolution-propose-command.d.ts +23 -0
- package/dist/cli/commands/evolution-propose-command.js +145 -0
- package/dist/cli/commands/evolution-status-command.d.ts +17 -0
- package/dist/cli/commands/evolution-status-command.js +41 -0
- package/dist/cli/commands/evolution-verdict-commands.d.ts +30 -0
- package/dist/cli/commands/evolution-verdict-commands.js +100 -0
- package/dist/cli/commands/finalize-accumulator.d.ts +44 -0
- package/dist/cli/commands/finalize-accumulator.js +55 -0
- package/dist/cli/commands/finalize-branches.d.ts +34 -0
- package/dist/cli/commands/finalize-branches.js +119 -0
- package/dist/cli/commands/finalize-runners.d.ts +3 -0
- package/dist/cli/commands/finalize-runners.js +92 -0
- package/dist/cli/commands/finalize-selection.d.ts +65 -0
- package/dist/cli/commands/finalize-selection.js +35 -0
- package/dist/cli/commands/gate-commands.js +26 -8
- package/dist/cli/commands/job-checkpoint-commands.d.ts +3 -0
- package/dist/cli/commands/job-checkpoint-commands.js +157 -0
- package/dist/cli/commands/job-command-shared.d.ts +109 -0
- package/dist/cli/commands/job-command-shared.js +72 -0
- package/dist/cli/commands/job-commands.d.ts +4 -64
- package/dist/cli/commands/job-commands.js +42 -552
- package/dist/cli/commands/job-cost-check-command.d.ts +3 -0
- package/dist/cli/commands/job-cost-check-command.js +41 -0
- package/dist/cli/commands/job-init-status-commands.d.ts +3 -0
- package/dist/cli/commands/job-init-status-commands.js +149 -0
- package/dist/cli/commands/job-run-commands.d.ts +3 -0
- package/dist/cli/commands/job-run-commands.js +97 -0
- package/dist/cli/commands/job-state-root.d.ts +35 -0
- package/dist/cli/commands/job-state-root.js +76 -0
- package/dist/cli/commands/loop-eval-capture-index.d.ts +4 -0
- package/dist/cli/commands/loop-eval-capture-index.js +44 -0
- package/dist/cli/commands/loop-eval-commands.d.ts +8 -5
- package/dist/cli/commands/loop-eval-commands.js +12 -626
- package/dist/cli/commands/loop-eval-eval-command.d.ts +3 -0
- package/dist/cli/commands/loop-eval-eval-command.js +168 -0
- package/dist/cli/commands/loop-eval-monotonic-command.d.ts +3 -0
- package/dist/cli/commands/loop-eval-monotonic-command.js +90 -0
- package/dist/cli/commands/loop-eval-parents.d.ts +7 -0
- package/dist/cli/commands/loop-eval-parents.js +20 -0
- package/dist/cli/commands/loop-eval-run-code.d.ts +7 -0
- package/dist/cli/commands/loop-eval-run-code.js +40 -0
- package/dist/cli/commands/loop-eval-run-command.d.ts +3 -0
- package/dist/cli/commands/loop-eval-run-command.js +113 -0
- package/dist/cli/commands/loop-eval-spec-commands.d.ts +3 -0
- package/dist/cli/commands/loop-eval-spec-commands.js +165 -0
- package/dist/cli/commands/loop-eval-spec-lint-command.d.ts +3 -0
- package/dist/cli/commands/loop-eval-spec-lint-command.js +42 -0
- package/dist/cli/commands/loop-eval-workflow-commands.d.ts +3 -0
- package/dist/cli/commands/loop-eval-workflow-commands.js +141 -0
- package/dist/cli/commands/mcp-commands.d.ts +10 -0
- package/dist/cli/commands/mcp-commands.js +157 -0
- package/dist/cli/commands/request-command-options.d.ts +49 -0
- package/dist/cli/commands/request-command-options.js +1 -0
- package/dist/cli/commands/request-commands.d.ts +3 -9
- package/dist/cli/commands/request-commands.js +17 -522
- package/dist/cli/commands/request-init-command.d.ts +3 -0
- package/dist/cli/commands/request-init-command.js +100 -0
- package/dist/cli/commands/request-lint-command.d.ts +3 -0
- package/dist/cli/commands/request-lint-command.js +50 -0
- package/dist/cli/commands/request-list-command.d.ts +10 -0
- package/dist/cli/commands/request-list-command.js +53 -0
- package/dist/cli/commands/request-repair-status-command.d.ts +3 -0
- package/dist/cli/commands/request-repair-status-command.js +61 -0
- package/dist/cli/commands/request-show-command.d.ts +3 -0
- package/dist/cli/commands/request-show-command.js +56 -0
- package/dist/cli/commands/request-transition-command.d.ts +3 -0
- package/dist/cli/commands/request-transition-command.js +122 -0
- package/dist/cli/commands/request-transition-failures.d.ts +8 -0
- package/dist/cli/commands/request-transition-failures.js +90 -0
- package/dist/cli/commands/request-transition-hooks.d.ts +50 -0
- package/dist/cli/commands/request-transition-hooks.js +115 -0
- package/dist/cli/commands/request-transition-preflight.d.ts +10 -0
- package/dist/cli/commands/request-transition-preflight.js +107 -0
- package/dist/cli/commands/scan-command-shared.d.ts +96 -0
- package/dist/cli/commands/scan-command-shared.js +83 -0
- package/dist/cli/commands/scan-commands.d.ts +3 -2
- package/dist/cli/commands/scan-commands.js +23 -463
- package/dist/cli/commands/scan-inventory-commands.d.ts +3 -0
- package/dist/cli/commands/scan-inventory-commands.js +96 -0
- package/dist/cli/commands/scan-project-commands.d.ts +3 -0
- package/dist/cli/commands/scan-project-commands.js +65 -0
- package/dist/cli/commands/scan-scope-commands.d.ts +3 -0
- package/dist/cli/commands/scan-scope-commands.js +149 -0
- package/dist/cli/commands/scan-scope-helpers.d.ts +8 -0
- package/dist/cli/commands/scan-scope-helpers.js +54 -0
- package/dist/cli/commands/scan-structural-commands.d.ts +3 -0
- package/dist/cli/commands/scan-structural-commands.js +113 -0
- package/dist/cli/commands/share-commands.d.ts +12 -68
- package/dist/cli/commands/share-commands.js +47 -556
- package/dist/cli/commands/share-error-hints.d.ts +14 -0
- package/dist/cli/commands/share-error-hints.js +38 -0
- package/dist/cli/commands/share-identity.d.ts +13 -0
- package/dist/cli/commands/share-identity.js +22 -0
- package/dist/cli/commands/share-record-paths.d.ts +37 -0
- package/dist/cli/commands/share-record-paths.js +68 -0
- package/dist/cli/commands/share-runners.d.ts +3 -0
- package/dist/cli/commands/share-runners.js +158 -0
- package/dist/cli/commands/shared-read-runners.d.ts +3 -0
- package/dist/cli/commands/shared-read-runners.js +51 -0
- package/dist/cli/commands/slice-check-command.d.ts +3 -0
- package/dist/cli/commands/slice-check-command.js +54 -0
- package/dist/cli/commands/slice-commands.d.ts +2 -22
- package/dist/cli/commands/slice-commands.js +18 -517
- package/dist/cli/commands/slice-decompose-artifacts.d.ts +18 -0
- package/dist/cli/commands/slice-decompose-artifacts.js +79 -0
- package/dist/cli/commands/slice-decompose-command.d.ts +3 -0
- package/dist/cli/commands/slice-decompose-command.js +123 -0
- package/dist/cli/commands/slice-list-commands.d.ts +3 -0
- package/dist/cli/commands/slice-list-commands.js +182 -0
- package/dist/cli/commands/slice-pick-command.d.ts +3 -0
- package/dist/cli/commands/slice-pick-command.js +60 -0
- package/dist/cli/commands/slice-plan-command.d.ts +24 -0
- package/dist/cli/commands/slice-plan-command.js +111 -0
- package/dist/cli/commands/workflow-commands.d.ts +10 -1
- package/dist/cli/commands/workflow-commands.js +6 -594
- package/dist/cli/commands/workflow-gate-commands.d.ts +3 -0
- package/dist/cli/commands/workflow-gate-commands.js +116 -0
- package/dist/cli/commands/workflow-plan-helpers.d.ts +48 -0
- package/dist/cli/commands/workflow-plan-helpers.js +103 -0
- package/dist/cli/commands/workflow-planning-commands.d.ts +3 -0
- package/dist/cli/commands/workflow-planning-commands.js +56 -0
- package/dist/cli/commands/workflow-swarm-actions.d.ts +7 -0
- package/dist/cli/commands/workflow-swarm-actions.js +109 -0
- package/dist/cli/commands/workflow-swarm-commands.d.ts +3 -0
- package/dist/cli/commands/workflow-swarm-commands.js +138 -0
- package/dist/cli/commands/workflow-tech-actions.d.ts +10 -0
- package/dist/cli/commands/workflow-tech-actions.js +150 -0
- package/dist/cli/commands/workspace/init-actions.d.ts +10 -0
- package/dist/cli/commands/workspace/init-actions.js +199 -0
- package/dist/cli/commands/workspace/init-codegraph-stake.d.ts +10 -0
- package/dist/cli/commands/workspace/init-codegraph-stake.js +54 -0
- package/dist/cli/commands/workspace/init-command.d.ts +8 -124
- package/dist/cli/commands/workspace/init-command.js +59 -623
- package/dist/cli/commands/workspace/init-context.d.ts +58 -0
- package/dist/cli/commands/workspace/init-context.js +121 -0
- package/dist/cli/commands/workspace/init-envelope.d.ts +3 -0
- package/dist/cli/commands/workspace/init-envelope.js +34 -0
- package/dist/cli/commands/workspace/init-failures.d.ts +3 -0
- package/dist/cli/commands/workspace/init-failures.js +84 -0
- package/dist/cli/commands/workspace/init-hooks-decision.d.ts +24 -0
- package/dist/cli/commands/workspace/init-hooks-decision.js +189 -0
- package/dist/cli/commands/workspace/init-options.d.ts +102 -0
- package/dist/cli/commands/workspace/init-options.js +1 -0
- package/dist/cli/commands/worktree-lease-commands.d.ts +10 -6
- package/dist/cli/commands/worktree-lease-commands.js +42 -512
- package/dist/cli/commands/worktree-lease-gc-command.d.ts +12 -0
- package/dist/cli/commands/worktree-lease-gc-command.js +117 -0
- package/dist/cli/commands/worktree-lease-git.d.ts +22 -0
- package/dist/cli/commands/worktree-lease-git.js +48 -0
- package/dist/cli/commands/worktree-lease-list-command.d.ts +12 -0
- package/dist/cli/commands/worktree-lease-list-command.js +100 -0
- package/dist/cli/commands/worktree-lease-load.d.ts +37 -0
- package/dist/cli/commands/worktree-lease-load.js +28 -0
- package/dist/cli/commands/worktree-lease-release-command.d.ts +13 -0
- package/dist/cli/commands/worktree-lease-release-command.js +105 -0
- package/dist/cli/commands/worktree-lease-renew-command.d.ts +11 -0
- package/dist/cli/commands/worktree-lease-renew-command.js +99 -0
- package/dist/cli/commands/worktree-lease-session.d.ts +22 -0
- package/dist/cli/commands/worktree-lease-session.js +29 -0
- package/dist/cli/commands/worktree-lease-spawn-command.d.ts +11 -0
- package/dist/cli/commands/worktree-lease-spawn-command.js +119 -0
- package/dist/cli/commands/worktree-lease-status-command.d.ts +11 -0
- package/dist/cli/commands/worktree-lease-status-command.js +86 -0
- package/dist/cli/commands/worktree-lease-store.d.ts +19 -0
- package/dist/cli/commands/worktree-lease-store.js +24 -0
- package/dist/cli/program.js +5 -0
- package/dist/services/distribution/mcp-install-runner.d.ts +21 -0
- package/dist/services/distribution/mcp-install-runner.js +59 -0
- package/dist/services/distribution/mcp-install.d.ts +95 -0
- package/dist/services/distribution/mcp-install.js +179 -0
- package/dist/services/distribution/plugin-manifest.d.ts +97 -0
- package/dist/services/distribution/plugin-manifest.js +126 -0
- package/dist/services/hooks/mcp-surface-gate.d.ts +19 -0
- package/dist/services/hooks/mcp-surface-gate.js +87 -0
- package/dist/services/ide/adapters/claude-code-adapter.d.ts +4 -35
- package/dist/services/ide/adapters/claude-code-adapter.js +48 -171
- package/dist/services/ide/adapters/claude-code-local-state.d.ts +28 -0
- package/dist/services/ide/adapters/claude-code-local-state.js +112 -0
- package/dist/services/ide/adapters/claude-code-model-window.d.ts +37 -0
- package/dist/services/ide/adapters/claude-code-model-window.js +113 -0
- package/dist/services/ide/ide-mcp-install-types.d.ts +78 -0
- package/dist/services/ide/ide-mcp-install-types.js +104 -0
- package/dist/services/ide/ide-types.d.ts +45 -1
- package/dist/services/ide/mcp-tool-matcher.d.ts +34 -0
- package/dist/services/ide/mcp-tool-matcher.js +84 -0
- package/dist/services/lint/npx-resolver.js +7 -0
- package/dist/services/mcp/cli-executor.d.ts +36 -0
- package/dist/services/mcp/cli-executor.js +97 -0
- package/dist/services/mcp/json-rpc.d.ts +81 -0
- package/dist/services/mcp/json-rpc.js +116 -0
- package/dist/services/mcp/memory-tool.d.ts +3 -0
- package/dist/services/mcp/memory-tool.js +62 -0
- package/dist/services/mcp/server-main.d.ts +1 -0
- package/dist/services/mcp/server-main.js +66 -0
- package/dist/services/mcp/server.d.ts +22 -0
- package/dist/services/mcp/server.js +152 -0
- package/dist/services/mcp/surface.d.ts +62 -0
- package/dist/services/mcp/surface.js +198 -0
- package/dist/services/mcp/tool-core.d.ts +42 -0
- package/dist/services/mcp/tool-core.js +137 -0
- package/dist/services/mcp/tools.d.ts +13 -0
- package/dist/services/mcp/tools.js +58 -0
- package/dist/services/readonly-surface/argv-guard.d.ts +32 -0
- package/dist/services/readonly-surface/argv-guard.js +164 -0
- package/dist/services/readonly-surface/readonly-whitelist.d.ts +147 -0
- package/dist/services/readonly-surface/readonly-whitelist.js +107 -0
- package/dist/services/readonly-surface/whitelist-generator.d.ts +64 -0
- package/dist/services/readonly-surface/whitelist-generator.js +212 -0
- package/dist/services/skills/hooks-codegate-superpowers.d.ts +1 -0
- package/dist/services/skills/hooks-codegate-superpowers.js +26 -0
- package/dist/services/skills/hooks-settings-service.js +10 -2
- package/package.json +17 -6
- package/scripts/install-skills-bundles.mjs +233 -0
- package/scripts/install-skills-fs.mjs +148 -0
- package/scripts/install-skills-ide.mjs +279 -0
- package/scripts/install-skills-output-style-default.mjs +196 -0
- package/scripts/install-skills-output-styles.mjs +121 -0
- package/scripts/install-skills-report.mjs +42 -0
- package/scripts/install-skills-user-config.mjs +198 -0
- package/scripts/install-skills.mjs +36 -1066
- package/scripts/watch-tree.mjs +140 -0
- package/scripts/watch.mjs +4 -126
- package/skills/peaks-status/SKILL.md +31 -13
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { resolveCanonicalProjectRoot } from '../../services/config/config-service.js';
|
|
2
|
+
import { findProjectRoot } from '../../services/config/config-safety.js';
|
|
3
|
+
import { fail, ok, getErrorMessage } from 'peaks-loop-shared/result';
|
|
4
|
+
import { addJsonOption, printResult } from '../cli-helpers.js';
|
|
5
|
+
import { dryRunCompact } from '../../services/compact/suggest-service.js';
|
|
6
|
+
import { PHASES, isPhase } from '../../services/compact/decision-tables.js';
|
|
7
|
+
import { resolveSessionId } from './compact-shared.js';
|
|
8
|
+
export function registerCompactDryRunCommand(compact, io) {
|
|
9
|
+
// -----------------------------------------------------------------
|
|
10
|
+
// 4. peaks compact dry-run [--from <phase>] [--to <phase>] [--json]
|
|
11
|
+
// -----------------------------------------------------------------
|
|
12
|
+
addJsonOption(compact
|
|
13
|
+
.command('dry-run')
|
|
14
|
+
.description('Composite preview of (suggest + recommend + survival). ' +
|
|
15
|
+
'No writes. The LLM calls this every tool-call cycle to stay informed.')
|
|
16
|
+
.option('--from <phase>', `optional source phase for recommend lookup (one of ${PHASES.join(', ')})`)
|
|
17
|
+
.option('--to <phase>', `optional target phase for recommend lookup (one of ${PHASES.join(', ')})`)
|
|
18
|
+
.option('--project <path>', 'project root (defaults to git root or cwd)')
|
|
19
|
+
.option('--session-id <sid>', 'override the active session id')).action((options) => runCompactDryRun(options, io));
|
|
20
|
+
}
|
|
21
|
+
function runCompactDryRun(options, io) {
|
|
22
|
+
try {
|
|
23
|
+
const projectRoot = options.project !== undefined
|
|
24
|
+
? resolveCanonicalProjectRoot(options.project)
|
|
25
|
+
: (findProjectRoot(process.cwd()) ?? process.cwd());
|
|
26
|
+
const session = resolveSessionId(projectRoot, options.sessionId);
|
|
27
|
+
if (session.error !== null) {
|
|
28
|
+
printCompactDryRunSessionError(session.error, projectRoot, io, options.json);
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
if ((options.from === undefined) !== (options.to === undefined)) {
|
|
32
|
+
printCompactDryRunPhasePairIncomplete(options, io);
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
if (options.from !== undefined && !isPhase(options.from)) {
|
|
36
|
+
printCompactDryRunInvalidFrom(options.from, io, options.json);
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
if (options.to !== undefined && !isPhase(options.to)) {
|
|
40
|
+
printCompactDryRunInvalidTo(options.to, io, options.json);
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
const hasPhasePair = options.from !== undefined && options.to !== undefined;
|
|
44
|
+
const dryRunInput = {
|
|
45
|
+
projectRoot,
|
|
46
|
+
sessionId: session.sid
|
|
47
|
+
};
|
|
48
|
+
if (hasPhasePair) {
|
|
49
|
+
dryRunInput.from = options.from;
|
|
50
|
+
dryRunInput.to = options.to;
|
|
51
|
+
}
|
|
52
|
+
const result = dryRunCompact(dryRunInput);
|
|
53
|
+
printCompactDryRunResult(result, io, options.json);
|
|
54
|
+
}
|
|
55
|
+
catch (error) {
|
|
56
|
+
reportCompactDryRunFailure(io, error, options.json);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
function printCompactDryRunSessionError(error, projectRoot, io, json) {
|
|
60
|
+
printResult(io, fail('compact.dry-run', error.code, error.message, { projectRoot }, error.nextActions), json);
|
|
61
|
+
process.exitCode = 1;
|
|
62
|
+
}
|
|
63
|
+
function printCompactDryRunPhasePairIncomplete(options, io) {
|
|
64
|
+
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);
|
|
65
|
+
process.exitCode = 1;
|
|
66
|
+
}
|
|
67
|
+
function printCompactDryRunInvalidFrom(from, io, json) {
|
|
68
|
+
printResult(io, fail('compact.dry-run', 'INVALID_PHASE', `--from must be one of ${PHASES.join(', ')} (got "${from}")`, { from }, [`Use --from ${PHASES.join('|')}`]), json);
|
|
69
|
+
process.exitCode = 1;
|
|
70
|
+
}
|
|
71
|
+
function printCompactDryRunInvalidTo(to, io, json) {
|
|
72
|
+
printResult(io, fail('compact.dry-run', 'INVALID_PHASE', `--to must be one of ${PHASES.join(', ')} (got "${to}")`, { to }, [`Use --to ${PHASES.join('|')}`]), json);
|
|
73
|
+
process.exitCode = 1;
|
|
74
|
+
}
|
|
75
|
+
function printCompactDryRunResult(result, io, json) {
|
|
76
|
+
printResult(io, ok('compact.dry-run', result, [], [
|
|
77
|
+
result.action === 'compact'
|
|
78
|
+
? `Action=compact: run \`peaks compact force --reason "<note>"\`, then /compact.`
|
|
79
|
+
: `Action=skip: continue without compacting.`
|
|
80
|
+
]), json);
|
|
81
|
+
}
|
|
82
|
+
function reportCompactDryRunFailure(io, error, json) {
|
|
83
|
+
printResult(io, fail('compact.dry-run', 'COMPACT_DRY_RUN_FAILED', getErrorMessage(error), {}, [
|
|
84
|
+
'Verify project root, session binding, and phase pair before retrying'
|
|
85
|
+
]), json);
|
|
86
|
+
process.exitCode = 1;
|
|
87
|
+
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { resolveCanonicalProjectRoot } from '../../services/config/config-service.js';
|
|
2
|
+
import { findProjectRoot } from '../../services/config/config-safety.js';
|
|
3
|
+
import { fail, ok, getErrorMessage } from 'peaks-loop-shared/result';
|
|
4
|
+
import { addJsonOption, printResult } from '../cli-helpers.js';
|
|
5
|
+
import { writeCheckpoint } from '../../services/session/session-checkpoint-service.js';
|
|
6
|
+
import { resolveSessionId } from './compact-shared.js';
|
|
7
|
+
const COMPACT_FORCE_NEXT_ACTIONS = [
|
|
8
|
+
'After the LLM fires the IDE-side /compact, call `peaks compact survival` to see what to persist before the next compact.'
|
|
9
|
+
];
|
|
10
|
+
function splitList(value) {
|
|
11
|
+
if (!value)
|
|
12
|
+
return [];
|
|
13
|
+
return value
|
|
14
|
+
.split(/\r?\n/)
|
|
15
|
+
.map((s) => s.trim())
|
|
16
|
+
.filter((s) => s.length > 0);
|
|
17
|
+
}
|
|
18
|
+
export function registerCompactForceCommand(compact, io) {
|
|
19
|
+
// -----------------------------------------------------------------
|
|
20
|
+
// 5. peaks compact force [--reason <text>] [--json]
|
|
21
|
+
// -----------------------------------------------------------------
|
|
22
|
+
addJsonOption(compact
|
|
23
|
+
.command('force')
|
|
24
|
+
.description('Write a pre-compact checkpoint via `peaks session checkpoint --reason context-fill`. ' +
|
|
25
|
+
"The IDE-side `/compact` is still the LLM's call; this primitive guarantees " +
|
|
26
|
+
'the pre-compact state is persisted. NO sleep, NO wait for IDE response.')
|
|
27
|
+
.option('--reason <text>', 'human-readable reason for the pre-compact checkpoint', 'pre-force-compact')
|
|
28
|
+
.option('--project <path>', 'project root (defaults to git root or cwd)')
|
|
29
|
+
.option('--session-id <sid>', 'override the active session id')
|
|
30
|
+
.option('--current-plan <text>', 'current plan summary (forwarded to the checkpoint snapshot)')
|
|
31
|
+
.option('--open-questions <list>', 'newline-separated open questions')
|
|
32
|
+
.option('--recent-decisions <list>', 'newline-separated recent decisions')
|
|
33
|
+
.option('--recent-artifact-paths <list>', 'newline-separated recent artifact paths')
|
|
34
|
+
.option('--git-status <text>', 'recent git status')
|
|
35
|
+
.option('--skills-active <list>', 'newline-separated active skill names')
|
|
36
|
+
.option('--todo-state <list>', 'newline-separated todo lines')).action((options) => runCompactForce(options, io));
|
|
37
|
+
}
|
|
38
|
+
function runCompactForce(options, io) {
|
|
39
|
+
try {
|
|
40
|
+
const projectRoot = options.project !== undefined
|
|
41
|
+
? resolveCanonicalProjectRoot(options.project)
|
|
42
|
+
: (findProjectRoot(process.cwd()) ?? process.cwd());
|
|
43
|
+
const session = resolveSessionId(projectRoot, options.sessionId);
|
|
44
|
+
if (session.error !== null) {
|
|
45
|
+
printCompactForceSessionError(session.error, projectRoot, io, options.json);
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
const reason = (options.reason ?? 'pre-force-compact').slice(0, 200);
|
|
49
|
+
// The session-checkpoint-service restricts `reason` to a fixed
|
|
50
|
+
// enum. The strategic-compact `force` primitive uses
|
|
51
|
+
// 'context-fill' (the closest semantic match: the LLM is
|
|
52
|
+
// compacting because of context pressure) and records the
|
|
53
|
+
// caller's free-form reason in `gitStatus` so the snapshot
|
|
54
|
+
// is self-describing without inventing a new enum value.
|
|
55
|
+
const checkpointOptions = {
|
|
56
|
+
sessionId: session.sid,
|
|
57
|
+
reason: 'context-fill',
|
|
58
|
+
gitStatus: `compact.force: ${reason}`,
|
|
59
|
+
openQuestions: splitList(options.openQuestions),
|
|
60
|
+
recentDecisions: splitList(options.recentDecisions),
|
|
61
|
+
recentArtifactPaths: splitList(options.recentArtifactPaths),
|
|
62
|
+
skillsActive: splitList(options.skillsActive),
|
|
63
|
+
todoState: splitList(options.todoState)
|
|
64
|
+
};
|
|
65
|
+
if (options.currentPlan !== undefined) {
|
|
66
|
+
checkpointOptions.currentPlan = options.currentPlan;
|
|
67
|
+
}
|
|
68
|
+
const result = writeCheckpoint(projectRoot, checkpointOptions);
|
|
69
|
+
printCompactForceResult(result, reason, io, options.json);
|
|
70
|
+
}
|
|
71
|
+
catch (error) {
|
|
72
|
+
reportCompactForceFailure(io, error, options.json);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
function printCompactForceSessionError(error, projectRoot, io, json) {
|
|
76
|
+
printResult(io, fail('compact.force', error.code, error.message, { projectRoot }, error.nextActions), json);
|
|
77
|
+
process.exitCode = 1;
|
|
78
|
+
}
|
|
79
|
+
function buildCompactForceData(result, reason) {
|
|
80
|
+
return {
|
|
81
|
+
checkpointPath: result.path,
|
|
82
|
+
reason: 'pre-force-compact',
|
|
83
|
+
callerReason: reason,
|
|
84
|
+
sessionId: result.sessionId,
|
|
85
|
+
createdAt: result.createdAt,
|
|
86
|
+
totalRetained: result.totalRetained,
|
|
87
|
+
message: "Pre-compact checkpoint written. The IDE-side /compact is still the LLM's call; this CLI does NOT invoke the IDE slash command."
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
function printCompactForceResult(result, reason, io, json) {
|
|
91
|
+
printResult(io, ok('compact.force', buildCompactForceData(result, reason), [], COMPACT_FORCE_NEXT_ACTIONS), json);
|
|
92
|
+
}
|
|
93
|
+
function reportCompactForceFailure(io, error, json) {
|
|
94
|
+
printResult(io, fail('compact.force', 'COMPACT_FORCE_FAILED', getErrorMessage(error), {}, [
|
|
95
|
+
'Verify the project path is writable and a session is bound'
|
|
96
|
+
]), json);
|
|
97
|
+
process.exitCode = 1;
|
|
98
|
+
}
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
import { resolveCanonicalProjectRoot } from '../../services/config/config-service.js';
|
|
2
|
+
import { findProjectRoot } from '../../services/config/config-safety.js';
|
|
3
|
+
import { fail, ok, getErrorMessage } from 'peaks-loop-shared/result';
|
|
4
|
+
import { addJsonOption, printResult } from '../cli-helpers.js';
|
|
5
|
+
import { readHarnessWindowState, resolveHarnessWindowLocation } from '../../services/context/auto-compact-reader.js';
|
|
6
|
+
import { disableHarnessWindowSync, reenableHarnessWindowSync, resetHarnessWindow } from '../../services/context/harness-window-config.js';
|
|
7
|
+
const HARNESS_WINDOW_DESCRIPTION = 'Report / roll back the auto-compact window peaks-loop writes into the ' +
|
|
8
|
+
"harness's own machine-local settings (the adapter-declared " +
|
|
9
|
+
'autoCompactWindowEnvVar, e.g. CLAUDE_CODE_AUTO_COMPACT_WINDOW in ' +
|
|
10
|
+
'.claude/settings.local.json). peaks-loop computes its context ratio ' +
|
|
11
|
+
'against exactly this number, so the value it reports as "85%" and the ' +
|
|
12
|
+
'point the harness compacts at are the same. Context probes ' +
|
|
13
|
+
'(`peaks code context-now`, `peaks code auto-compact`) materialize it ' +
|
|
14
|
+
'automatically. Two different intentions, two verbs: --reset removes ' +
|
|
15
|
+
'the key AND opts the project out so later probes do not put it back ' +
|
|
16
|
+
'(when the file holds no peaks-loop row at all there is nothing to ' +
|
|
17
|
+
'roll back, so --reset writes nothing); --disable records the opt-out ' +
|
|
18
|
+
'only, leaving whatever value is already there untouched, so "stop ' +
|
|
19
|
+
'managing this key" works on a project peaks-loop has never written ' +
|
|
20
|
+
'to; --reenable undoes either opt-out.';
|
|
21
|
+
function resolveHarnessWindowProject(options) {
|
|
22
|
+
return options.project !== undefined
|
|
23
|
+
? resolveCanonicalProjectRoot(options.project)
|
|
24
|
+
: (findProjectRoot(process.cwd()) ?? process.cwd());
|
|
25
|
+
}
|
|
26
|
+
function reportUnmanagedHarnessWindow(io, project, json) {
|
|
27
|
+
printResult(io, ok('compact.harness-window', {
|
|
28
|
+
projectRoot: project,
|
|
29
|
+
managed: false,
|
|
30
|
+
message: 'The active IDE adapter declares no auto-compact window key, so peaks-loop cannot tie ' +
|
|
31
|
+
'the harness window to its own ratio. Nothing was written and there is nothing to roll back.'
|
|
32
|
+
}), json);
|
|
33
|
+
}
|
|
34
|
+
function buildResetWindowActions(result, location) {
|
|
35
|
+
return [
|
|
36
|
+
result.action === 'removed'
|
|
37
|
+
? `Removed ${location.envVar} from ${result.settingsPath} and opted this project out, so later probes stop writing it. Undo with \`peaks compact harness-window --reenable\`.`
|
|
38
|
+
: `Nothing to remove — ${location.envVar} was already absent from ${result.settingsPath}, so nothing was written and no opt-out row was recorded: if a probe writes a window here later, run --reset again to remove it. To say "never manage this key here" WITHOUT waiting for that first write, run \`peaks compact harness-window --disable\`.`
|
|
39
|
+
];
|
|
40
|
+
}
|
|
41
|
+
function reportResetHarnessWindow(io, project, location, json) {
|
|
42
|
+
const result = resetHarnessWindow({ location, env: process.env });
|
|
43
|
+
printResult(io, ok('compact.harness-window', {
|
|
44
|
+
projectRoot: project,
|
|
45
|
+
action: result.action,
|
|
46
|
+
key: location.envVar,
|
|
47
|
+
settingsPath: result.settingsPath,
|
|
48
|
+
previousTokens: result.previousTokens
|
|
49
|
+
}, [], buildResetWindowActions(result, location)), json);
|
|
50
|
+
}
|
|
51
|
+
function buildDisableWindowActions(result, location) {
|
|
52
|
+
return [
|
|
53
|
+
result.action === 'disabled'
|
|
54
|
+
? `Recorded the opt-out in ${result.settingsPath}: peaks-loop will not write ${location.envVar} here, and left any value already in the file exactly as it was. Undo with \`peaks compact harness-window --reenable\`.`
|
|
55
|
+
: result.action === 'already-opted-out'
|
|
56
|
+
? `Already opted out — ${result.settingsPath} carries ${location.envVar}'s opt-out, so nothing was written. Undo with \`peaks compact harness-window --reenable\`.`
|
|
57
|
+
: result.action === 'refused-unsafe-project-root'
|
|
58
|
+
? `Nothing written: the resolved project root is the user's own home directory, so ${result.settingsPath} is their PERSONAL harness settings, not a project's. peaks-loop already refuses to write ${location.envVar} there, so an opt-out would change nothing except which refusal you see. Point --project at a project (a subdirectory of home is fine) and the opt-out lands there.`
|
|
59
|
+
: `Nothing written — ${result.settingsPath} is not a JSON object peaks-loop can safely edit, so the opt-out could not be recorded there.`
|
|
60
|
+
];
|
|
61
|
+
}
|
|
62
|
+
function reportDisableHarnessWindow(io, project, location, json) {
|
|
63
|
+
const result = disableHarnessWindowSync({ location });
|
|
64
|
+
printResult(io, ok('compact.harness-window', {
|
|
65
|
+
projectRoot: project,
|
|
66
|
+
action: result.action,
|
|
67
|
+
key: location.envVar,
|
|
68
|
+
settingsPath: result.settingsPath
|
|
69
|
+
}, [], buildDisableWindowActions(result, location)), json);
|
|
70
|
+
}
|
|
71
|
+
function buildReenableWindowActions(result) {
|
|
72
|
+
return [
|
|
73
|
+
result.action === 'reenabled'
|
|
74
|
+
? 'Opt-out cleared; the next context probe will materialize the window again.'
|
|
75
|
+
: 'No opt-out was recorded for this project.'
|
|
76
|
+
];
|
|
77
|
+
}
|
|
78
|
+
function reportReenableHarnessWindow(io, project, location, json) {
|
|
79
|
+
const result = reenableHarnessWindowSync({ location });
|
|
80
|
+
printResult(io, ok('compact.harness-window', {
|
|
81
|
+
projectRoot: project,
|
|
82
|
+
action: result.action,
|
|
83
|
+
key: location.envVar,
|
|
84
|
+
settingsPath: result.settingsPath
|
|
85
|
+
}, [], buildReenableWindowActions(result)), json);
|
|
86
|
+
}
|
|
87
|
+
function buildHarnessWindowStateActions(state) {
|
|
88
|
+
return [
|
|
89
|
+
state?.tokens === null || state?.tokens === undefined
|
|
90
|
+
? 'No window is set yet. The next `peaks code context-now` probe materializes the window it computes its ratio against.'
|
|
91
|
+
: `peaks-loop computes its context ratio against ${state.tokens} tokens; the harness fires near the end of that window. ${state.peakWritten
|
|
92
|
+
? 'peaks-loop wrote this value; it may raise it if a session outgrows it.'
|
|
93
|
+
: "This value is not peaks-loop's own write, so peaks-loop will not raise it — it is treated as your setting."}`,
|
|
94
|
+
'Rollback: `peaks compact harness-window --reset`.',
|
|
95
|
+
'Intent-vs-observed calibration: `peaks compact history --json` → windowCalibration.'
|
|
96
|
+
];
|
|
97
|
+
}
|
|
98
|
+
function buildHarnessWindowStateData(project, location, state) {
|
|
99
|
+
return {
|
|
100
|
+
projectRoot: project,
|
|
101
|
+
managed: true,
|
|
102
|
+
key: location.envVar,
|
|
103
|
+
settingsPath: location.settingsPath,
|
|
104
|
+
tokens: state?.tokens ?? null,
|
|
105
|
+
raw: state?.raw ?? null,
|
|
106
|
+
source: state?.source ?? null,
|
|
107
|
+
optedOut: state?.optedOut ?? false,
|
|
108
|
+
// Provenance: whether this value is peaks-loop's own write or
|
|
109
|
+
// one the user set by hand. It decides whether the late 1M
|
|
110
|
+
// rescue may override it, so it is not just diagnostics.
|
|
111
|
+
peakWritten: state?.peakWritten ?? false
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
function reportHarnessWindowState(io, project, location, json) {
|
|
115
|
+
const state = readHarnessWindowState({ projectRoot: project, env: process.env });
|
|
116
|
+
printResult(io, ok('compact.harness-window', buildHarnessWindowStateData(project, location, state), [], buildHarnessWindowStateActions(state)), json);
|
|
117
|
+
}
|
|
118
|
+
function reportHarnessWindowFailure(io, error, json) {
|
|
119
|
+
printResult(io, fail('compact.harness-window', 'COMPACT_HARNESS_WINDOW_FAILED', getErrorMessage(error), {}, [
|
|
120
|
+
'Verify the project path is writable and a session is bound'
|
|
121
|
+
]), json);
|
|
122
|
+
process.exitCode = 1;
|
|
123
|
+
}
|
|
124
|
+
function runCompactHarnessWindow(options, io) {
|
|
125
|
+
try {
|
|
126
|
+
const project = resolveHarnessWindowProject(options);
|
|
127
|
+
const location = resolveHarnessWindowLocation({
|
|
128
|
+
projectRoot: project,
|
|
129
|
+
env: process.env
|
|
130
|
+
});
|
|
131
|
+
if (location === null) {
|
|
132
|
+
reportUnmanagedHarnessWindow(io, project, options.json);
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
if (options.reset === true) {
|
|
136
|
+
reportResetHarnessWindow(io, project, location, options.json);
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
if (options.disable === true) {
|
|
140
|
+
reportDisableHarnessWindow(io, project, location, options.json);
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
if (options.reenable === true) {
|
|
144
|
+
reportReenableHarnessWindow(io, project, location, options.json);
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
reportHarnessWindowState(io, project, location, options.json);
|
|
148
|
+
}
|
|
149
|
+
catch (error) {
|
|
150
|
+
reportHarnessWindowFailure(io, error, options.json);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
export function registerCompactHarnessWindowCommand(compact, io) {
|
|
154
|
+
// 7. peaks compact harness-window [--reset | --disable | --reenable]
|
|
155
|
+
//
|
|
156
|
+
// The window peaks-loop divides by and the window the harness compacts
|
|
157
|
+
// against must be ONE number, or "95%" lands at two different token counts.
|
|
158
|
+
// This command is the visible half of that write: the default reports what
|
|
159
|
+
// is in force, `--reset` removes it, `--disable` stops managing it.
|
|
160
|
+
//
|
|
161
|
+
// There is deliberately NO `--sync` flag. Materializing the window requires
|
|
162
|
+
// the ratio's own denominator, which only a probe has (it is the only place
|
|
163
|
+
// the active model is known). A `--sync` that re-derived the window here
|
|
164
|
+
// would be the second, independent resolution this slice exists to delete —
|
|
165
|
+
// `peaks code context-now` and `peaks code auto-compact` already sync.
|
|
166
|
+
addJsonOption(compact
|
|
167
|
+
.command('harness-window')
|
|
168
|
+
.description(HARNESS_WINDOW_DESCRIPTION)
|
|
169
|
+
.option('--project <path>', 'project root (defaults to git root or cwd)')
|
|
170
|
+
.option('--reset', 'rollback: remove the window key and stop managing it')
|
|
171
|
+
.option('--disable', 'record the opt-out only (do not manage this key), without removing a value that is already there; expressible before the first write')
|
|
172
|
+
.option('--reenable', 'undo a --reset or --disable opt-out (peaks-loop manages it again)')
|
|
173
|
+
.action((options) => runCompactHarnessWindow(options, io)));
|
|
174
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { resolveCanonicalProjectRoot } from '../../services/config/config-service.js';
|
|
2
|
+
import { findProjectRoot } from '../../services/config/config-safety.js';
|
|
3
|
+
import { fail, ok, getErrorMessage } from 'peaks-loop-shared/result';
|
|
4
|
+
import { addJsonOption, printResult } from '../cli-helpers.js';
|
|
5
|
+
import { computeWindowCalibration, readCompactHistory, summarizeCompactHistory } from '../../services/compact-history/compact-history-service.js';
|
|
6
|
+
import { resolveSessionId } from './compact-shared.js';
|
|
7
|
+
const COMPACT_HISTORY_DESCRIPTION = 'Read the per-session compact-history.jsonl and emit a structured ' +
|
|
8
|
+
'summary of every auto-compact dispatch in the current session.';
|
|
9
|
+
function reportCompactHistorySessionFailure(io, error, project, json) {
|
|
10
|
+
printResult(io, fail('compact.history', error.code, error.message, { projectRoot: project }, error.nextActions), json);
|
|
11
|
+
process.exitCode = 1;
|
|
12
|
+
}
|
|
13
|
+
function reportCompactHistoryMissing(io, sessionId, historyPath, json) {
|
|
14
|
+
printResult(io, ok('compact.history', {
|
|
15
|
+
sessionId,
|
|
16
|
+
totalCompacts: 0,
|
|
17
|
+
message: 'No compact-history.jsonl yet; auto-compact has not fired in this session.',
|
|
18
|
+
historyPath
|
|
19
|
+
}), json);
|
|
20
|
+
}
|
|
21
|
+
function reportCompactHistoryEmpty(io, sessionId, historyPath, json) {
|
|
22
|
+
printResult(io, ok('compact.history', {
|
|
23
|
+
sessionId,
|
|
24
|
+
totalCompacts: 0,
|
|
25
|
+
message: 'compact-history.jsonl exists but is empty.',
|
|
26
|
+
historyPath
|
|
27
|
+
}), json);
|
|
28
|
+
}
|
|
29
|
+
function reportCompactHistorySummary(io, sessionId, result, json) {
|
|
30
|
+
const summary = summarizeCompactHistory(result.events);
|
|
31
|
+
// intent-vs-observed record. `pairs[i].requestedTokens` is the token
|
|
32
|
+
// point peaks-loop asked for; `observedTokens` is what the next real
|
|
33
|
+
// session actually measured. Unmeasured pairs are reported as such —
|
|
34
|
+
// this instrument states what happened, it does not predict.
|
|
35
|
+
const windowCalibration = computeWindowCalibration(result.events);
|
|
36
|
+
printResult(io, ok('compact.history', {
|
|
37
|
+
sessionId,
|
|
38
|
+
...summary,
|
|
39
|
+
windowCalibration,
|
|
40
|
+
events: result.events,
|
|
41
|
+
parseErrors: result.parseErrors,
|
|
42
|
+
historyPath: result.path
|
|
43
|
+
}), json);
|
|
44
|
+
}
|
|
45
|
+
function reportCompactHistoryFailure(io, error, json) {
|
|
46
|
+
printResult(io, fail('compact.history', 'COMPACT_HISTORY_READ_FAILED', getErrorMessage(error), {}, [
|
|
47
|
+
'Verify the project path is readable and a session is bound'
|
|
48
|
+
]), json);
|
|
49
|
+
process.exitCode = 1;
|
|
50
|
+
}
|
|
51
|
+
function runCompactHistory(options, io) {
|
|
52
|
+
try {
|
|
53
|
+
const project = options.project !== undefined
|
|
54
|
+
? resolveCanonicalProjectRoot(options.project)
|
|
55
|
+
: (findProjectRoot(process.cwd()) ?? process.cwd());
|
|
56
|
+
const session = resolveSessionId(project, options.sessionId);
|
|
57
|
+
if (session.error !== null) {
|
|
58
|
+
reportCompactHistorySessionFailure(io, session.error, project, options.json);
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
const result = readCompactHistory({
|
|
62
|
+
projectRoot: project,
|
|
63
|
+
sessionId: session.sid
|
|
64
|
+
});
|
|
65
|
+
if (result.kind === 'file-missing') {
|
|
66
|
+
reportCompactHistoryMissing(io, session.sid, result.path, options.json);
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
if (result.kind === 'empty') {
|
|
70
|
+
reportCompactHistoryEmpty(io, session.sid, result.path, options.json);
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
reportCompactHistorySummary(io, session.sid, result, options.json);
|
|
74
|
+
}
|
|
75
|
+
catch (error) {
|
|
76
|
+
reportCompactHistoryFailure(io, error, options.json);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
export function registerCompactHistoryCommand(compact, io) {
|
|
80
|
+
// -----------------------------------------------------------------
|
|
81
|
+
// 6. peaks compact history [--json]
|
|
82
|
+
// -----------------------------------------------------------------
|
|
83
|
+
addJsonOption(compact
|
|
84
|
+
.command('history')
|
|
85
|
+
.description(COMPACT_HISTORY_DESCRIPTION)
|
|
86
|
+
.option('--project <path>', 'project root (defaults to git root or cwd)')
|
|
87
|
+
.option('--session-id <sid>', 'override the active session id (defaults to the canonical binding)')
|
|
88
|
+
.action((options) => runCompactHistory(options, io)));
|
|
89
|
+
}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { resolveCanonicalProjectRoot } from '../../services/config/config-service.js';
|
|
2
|
+
import { findProjectRoot } from '../../services/config/config-safety.js';
|
|
3
|
+
import { fail, ok, getErrorMessage } from 'peaks-loop-shared/result';
|
|
4
|
+
import { addJsonOption, printResult } from '../cli-helpers.js';
|
|
5
|
+
import { buildRecommendEnvelopePure, suggestCompact } from '../../services/compact/suggest-service.js';
|
|
6
|
+
import { PHASES, SURVIVAL_TABLE, isPhase, lookupPhaseTransition } from '../../services/compact/decision-tables.js';
|
|
7
|
+
import { resolveSessionId } from './compact-shared.js';
|
|
8
|
+
const COMPACT_SUGGEST_DESCRIPTION = 'Two-signal suggestion (context-size + tool-call-count). ' +
|
|
9
|
+
'Honor COMPACT_THRESHOLD / COMPACT_CONTEXT_THRESHOLD / COMPACT_CONTEXT_INTERVAL env vars. ' +
|
|
10
|
+
'Read-only by default; pass --apply to also append a one-line info row to the session log.';
|
|
11
|
+
const COMPACT_RECOMMEND_DESCRIPTION = `Strategic-compact "Compaction Decision Guide" lookup. ` +
|
|
12
|
+
`Valid phases: ${PHASES.join(', ')}. Pure function over (from, to); no I/O.`;
|
|
13
|
+
const COMPACT_SURVIVAL_DESCRIPTION = 'Strategic-compact "What Survives Compaction" table. Pure static data; no I/O.';
|
|
14
|
+
function reportCompactSuggestSessionFailure(io, error, projectRoot, json) {
|
|
15
|
+
printResult(io, fail('compact.suggest', error.code, error.message, { projectRoot }, error.nextActions), json);
|
|
16
|
+
process.exitCode = 1;
|
|
17
|
+
}
|
|
18
|
+
function buildCompactSuggestNextActions(result) {
|
|
19
|
+
return [
|
|
20
|
+
result.shouldSuggest
|
|
21
|
+
? `Run \`peaks compact force --reason "<short note>"\` to checkpoint, then /compact.`
|
|
22
|
+
: `Context at ${(result.ratio * 100).toFixed(1)}% (${result.tokensUsed} of ${result.windowKind === '1m' ? '1M' : '200k'}); below threshold.`
|
|
23
|
+
];
|
|
24
|
+
}
|
|
25
|
+
function reportCompactSuggestFailure(io, error, json) {
|
|
26
|
+
printResult(io, fail('compact.suggest', 'COMPACT_SUGGEST_FAILED', getErrorMessage(error), {}, [
|
|
27
|
+
'Verify project root and session binding before retrying'
|
|
28
|
+
]), json);
|
|
29
|
+
process.exitCode = 1;
|
|
30
|
+
}
|
|
31
|
+
function runCompactSuggest(options, io) {
|
|
32
|
+
try {
|
|
33
|
+
const projectRoot = options.project !== undefined
|
|
34
|
+
? resolveCanonicalProjectRoot(options.project)
|
|
35
|
+
: (findProjectRoot(process.cwd()) ?? process.cwd());
|
|
36
|
+
const session = resolveSessionId(projectRoot, options.sessionId);
|
|
37
|
+
if (session.error !== null) {
|
|
38
|
+
reportCompactSuggestSessionFailure(io, session.error, projectRoot, options.json);
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
const result = suggestCompact({
|
|
42
|
+
projectRoot,
|
|
43
|
+
sessionId: session.sid
|
|
44
|
+
});
|
|
45
|
+
printResult(io, ok('compact.suggest', result, [], buildCompactSuggestNextActions(result)), options.json);
|
|
46
|
+
}
|
|
47
|
+
catch (error) {
|
|
48
|
+
reportCompactSuggestFailure(io, error, options.json);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
function reportRecommendInvalidFrom(io, value, json) {
|
|
52
|
+
printResult(io, fail('compact.recommend', 'INVALID_PHASE', `--from must be one of ${PHASES.join(', ')} (got "${value}")`, { from: value }, [`Use --from ${PHASES.join('|')}`]), json);
|
|
53
|
+
process.exitCode = 1;
|
|
54
|
+
}
|
|
55
|
+
function reportRecommendInvalidTo(io, value, json) {
|
|
56
|
+
printResult(io, fail('compact.recommend', 'INVALID_PHASE', `--to must be one of ${PHASES.join(', ')} (got "${value}")`, { to: value }, [`Use --to ${PHASES.join('|')}`]), json);
|
|
57
|
+
process.exitCode = 1;
|
|
58
|
+
}
|
|
59
|
+
function reportCompactRecommendFailure(io, error, options) {
|
|
60
|
+
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);
|
|
61
|
+
process.exitCode = 1;
|
|
62
|
+
}
|
|
63
|
+
function runCompactRecommend(options, io) {
|
|
64
|
+
try {
|
|
65
|
+
if (!isPhase(options.from)) {
|
|
66
|
+
reportRecommendInvalidFrom(io, options.from, options.json);
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
if (!isPhase(options.to)) {
|
|
70
|
+
reportRecommendInvalidTo(io, options.to, options.json);
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
const envelope = buildRecommendEnvelopePure(options.from, options.to);
|
|
74
|
+
const lookup = lookupPhaseTransition(options.from, options.to);
|
|
75
|
+
printResult(io, ok('compact.recommend', {
|
|
76
|
+
from: envelope.from,
|
|
77
|
+
to: envelope.to,
|
|
78
|
+
shouldCompact: envelope.shouldCompact,
|
|
79
|
+
severity: envelope.severity,
|
|
80
|
+
rationale: envelope.rationale,
|
|
81
|
+
suggestedMessage: envelope.suggestedMessage,
|
|
82
|
+
notInTable: lookup.notInTable
|
|
83
|
+
}, lookup.notInTable
|
|
84
|
+
? [
|
|
85
|
+
`Transition ${options.from} → ${options.to} is not in the strategic-compact table; defaulting to severity=no.`
|
|
86
|
+
]
|
|
87
|
+
: []), options.json);
|
|
88
|
+
}
|
|
89
|
+
catch (error) {
|
|
90
|
+
reportCompactRecommendFailure(io, error, options);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
function runCompactSurvival(options, io) {
|
|
94
|
+
printResult(io, ok('compact.survival', {
|
|
95
|
+
persists: [...SURVIVAL_TABLE.persists],
|
|
96
|
+
lost: [...SURVIVAL_TABLE.lost]
|
|
97
|
+
}, [], [
|
|
98
|
+
'Persists = guaranteed across `/compact`. Lost = not preserved; persist to disk before compacting.'
|
|
99
|
+
]), options.json);
|
|
100
|
+
}
|
|
101
|
+
export function registerCompactReadCommands(compact, io) {
|
|
102
|
+
// -----------------------------------------------------------------
|
|
103
|
+
// 1. peaks compact suggest [--json]
|
|
104
|
+
// -----------------------------------------------------------------
|
|
105
|
+
addJsonOption(compact
|
|
106
|
+
.command('suggest')
|
|
107
|
+
.description(COMPACT_SUGGEST_DESCRIPTION)
|
|
108
|
+
.option('--project <path>', 'project root (defaults to git root or cwd)')
|
|
109
|
+
.option('--session-id <sid>', 'override the active session id (defaults to the canonical binding)')
|
|
110
|
+
.option('--apply', 'append a one-line info row to .peaks/_runtime/<sid>/session.json (default: dry-run)')).action((options) => runCompactSuggest(options, io));
|
|
111
|
+
// -----------------------------------------------------------------
|
|
112
|
+
// 2. peaks compact recommend --from <phase> --to <phase> [--json]
|
|
113
|
+
// -----------------------------------------------------------------
|
|
114
|
+
addJsonOption(compact
|
|
115
|
+
.command('recommend')
|
|
116
|
+
.description(COMPACT_RECOMMEND_DESCRIPTION)
|
|
117
|
+
.requiredOption('--from <phase>', `source phase (one of ${PHASES.join(', ')})`)
|
|
118
|
+
.requiredOption('--to <phase>', `target phase (one of ${PHASES.join(', ')})`)).action((options) => runCompactRecommend(options, io));
|
|
119
|
+
// -----------------------------------------------------------------
|
|
120
|
+
// 3. peaks compact survival [--json]
|
|
121
|
+
// -----------------------------------------------------------------
|
|
122
|
+
addJsonOption(compact.command('survival').description(COMPACT_SURVIVAL_DESCRIPTION)).action((options) => runCompactSurvival(options, io));
|
|
123
|
+
}
|