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
|
@@ -1,679 +1,27 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* context-now / context-audit / gate-step-08 /
|
|
2
|
+
* context-now / context-audit / post-compact-detect / auto-compact / gate-step-08 /
|
|
3
|
+
* emit-handoff.
|
|
3
4
|
*
|
|
4
5
|
* Owns: 6 sub-commands that read or mutate runtime state.
|
|
5
|
-
* Owns the `readActiveSid` helper (only used by these runtime probes).
|
|
6
6
|
*
|
|
7
|
-
*
|
|
7
|
+
* This module is the registrar only. Each sub-command owns a file, and the pure
|
|
8
|
+
* helpers they share live beside them rather than inside one of them. Both
|
|
9
|
+
* re-exports below are part of the published surface of this module path, so the
|
|
10
|
+
* callers that reach for them keep their specifier.
|
|
8
11
|
*/
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
import { syncHarnessWindowForProject } from '../../services/context/auto-compact-reader.js';
|
|
18
|
-
import { describeHarnessWindowSync, harnessWindowSyncWarning } from '../../services/context/harness-window-config.js';
|
|
19
|
-
import { describeHarnessWitness, readAndCompareHarnessWitness } from '../../services/context/harness-context-witness.js';
|
|
20
|
-
import { resolveCanonicalProjectRoot } from '../../services/config/config-service.js';
|
|
21
|
-
import { buildContextAuditHint } from '../../services/context/context-audit-hint.js';
|
|
22
|
-
import { evaluateStep08, STEP_08_BACKUP_REGEX } from '../../services/code/step-08-gate.js';
|
|
23
|
-
import { evaluateEmitHandoff, JOB_NOT_INITIALIZED, JOB_REMAINING_BLOCKED } from '../../services/code/emit-handoff.js';
|
|
24
|
-
import { readJobShapeDecision, JobShapeDecisionError } from '../../services/code/job-shape-decision.js';
|
|
25
|
-
import { getSkillPresence } from '../../services/skills/skill-presence-service.js';
|
|
26
|
-
import { probeInFlightBatch } from '../../services/workflow/workflow-inflight-probe.js';
|
|
27
|
-
import { resolveOuterSessionId } from '../../services/session/binding-status-service.js';
|
|
28
|
-
/** The one dispatch verb the action and red-line tiers name. */
|
|
29
|
-
const COMPACT_CMD = 'peaks code auto-compact';
|
|
30
|
-
/**
|
|
31
|
-
* Slice H4 (rid=h4-context-now-mode-blind) — the ONE mapping from the shared
|
|
32
|
-
* `CompactTrigger` to this command's `action` vocabulary, so the two cannot
|
|
33
|
-
* drift: the trigger is `evaluateCompactTrigger`, the same function `peaks
|
|
34
|
-
* code auto-compact` decides with.
|
|
35
|
-
*
|
|
36
|
-
* `auto-fire` maps to `soft-warn` in BOTH modes: that tier is `peaks skill
|
|
37
|
-
* presence`'s — the every-turn probe, which reads this same table and mode
|
|
38
|
-
* resolver — so `context-now` has no auto-fire tier of its own (SKILL.md
|
|
39
|
-
* "two probes, two thresholds"). Reporting it as `auto-compact-now` would
|
|
40
|
-
* change every non-24h session's output, which slice H4 forbids.
|
|
41
|
-
*/
|
|
42
|
-
export function contextNowActionFor(ratio, mode) {
|
|
43
|
-
const kind = evaluateCompactTrigger(ratio, mode).kind;
|
|
44
|
-
if (kind === 'red-line')
|
|
45
|
-
return { action: 'red-line', next: COMPACT_CMD };
|
|
46
|
-
if (kind === 'pre-compact')
|
|
47
|
-
return { action: 'auto-compact-now', next: COMPACT_CMD };
|
|
48
|
-
return { action: kind === 'none' ? 'ok' : 'soft-warn', next: null };
|
|
49
|
-
}
|
|
50
|
-
/** Slice H4: the labels `context-now` prints, read out of the table for the mode
|
|
51
|
-
* in force — the old hard-coded "≥0.85 / ≥0.95 / 50–85%" told a 24h operator
|
|
52
|
-
* the wrong lines. `*Ratio` is the `0.85` form `gateModeNotice` uses. */
|
|
53
|
-
function contextNowBandLabels(mode) {
|
|
54
|
-
const pct = (r) => `${(r * 100).toFixed(0)}`;
|
|
55
|
-
const pre = thresholdFor(mode, 'preCompact');
|
|
56
|
-
const red = thresholdFor(mode, 'redLine');
|
|
57
|
-
return {
|
|
58
|
-
softWarn: pct(AUTO_COMPACT_SOFT_WARN_RATIO),
|
|
59
|
-
preCompact: pct(pre),
|
|
60
|
-
redLine: pct(red),
|
|
61
|
-
preCompactRatio: pre.toFixed(2),
|
|
62
|
-
redLineRatio: red.toFixed(2)
|
|
63
|
-
};
|
|
64
|
-
}
|
|
65
|
-
/**
|
|
66
|
-
* Adapt `runAutoCompact`'s domain result to a `ResultEnvelope`.
|
|
67
|
-
*
|
|
68
|
-
* Extracted and exported so the CHANNEL each fact chooses can be asserted
|
|
69
|
-
* directly, without a real red-line probe.
|
|
70
|
-
*
|
|
71
|
-
* The harness-window CONFLICT ("peaks-loop divided this ratio by N but the
|
|
72
|
-
* settings file pins M") is a fact about the STATE, not an instruction, so it
|
|
73
|
-
* rides `warnings` — the very channel `peaks code context-now` already puts it
|
|
74
|
-
* on, via the same `harnessWindowSyncWarning`. Before this, the shim hard-coded
|
|
75
|
-
* `warnings: []`, so the identical fact reached a consumer as a sentence inside
|
|
76
|
-
* `nextActions` on this command and as a `warnings` entry on the other one. One
|
|
77
|
-
* fact, two shapes, depending on which of the two syncing commands a consumer
|
|
78
|
-
* happened to read: two parsers for one mechanism.
|
|
79
|
-
*
|
|
80
|
-
* The prose description (`describeHarnessWindowSync`) stays in `nextActions` on
|
|
81
|
-
* BOTH commands — that half is advice ("what to do about it") and both already
|
|
82
|
-
* agree on it.
|
|
83
|
-
*/
|
|
84
|
-
export function buildAutoCompactEnvelope(result) {
|
|
85
|
-
const data = 'data' in result ? result.data : null;
|
|
86
|
-
const nextActions = 'nextActions' in result ? result.nextActions : [];
|
|
87
|
-
const warning = harnessWindowSyncWarning(data?.harnessWindow ?? null);
|
|
88
|
-
const warnings = warning === null ? [] : [warning];
|
|
89
|
-
if (result.ok) {
|
|
90
|
-
return ok('code.auto-compact', data ?? {}, warnings, [result.message, ...nextActions]);
|
|
91
|
-
}
|
|
92
|
-
// `fail()` hard-codes `warnings: []`, so the warning is spread back over it —
|
|
93
|
-
// a refused write can disagree with the ratio just as easily on the failure
|
|
94
|
-
// path, and the state does not become less true because the dispatch failed.
|
|
95
|
-
return {
|
|
96
|
-
...fail('code.auto-compact', result.code, result.message, data, [...nextActions]),
|
|
97
|
-
warnings
|
|
98
|
-
};
|
|
99
|
-
}
|
|
100
|
-
function printPostCompactNoActiveSession(io, opts) {
|
|
101
|
-
printResult(io, fail('code.post-compact-detect', 'NO_ACTIVE_SESSION', 'no active session id; pass --session-id or set presence via `peaks skill presence:set peaks-code`', null, ['Re-run with --session-id <sid>']), opts.json);
|
|
102
|
-
process.exitCode = 1;
|
|
103
|
-
}
|
|
12
|
+
import { registerCodePostCompactDetectCommand } from './code-post-compact-detect-command.js';
|
|
13
|
+
import { registerCodeAutoCompactCommand } from './code-auto-compact-command.js';
|
|
14
|
+
import { registerCodeContextNowCommand } from './code-context-now-command.js';
|
|
15
|
+
import { registerCodeContextAuditCommand } from './code-context-audit-command.js';
|
|
16
|
+
import { registerCodeGateStep08Command } from './code-gate-step-08-command.js';
|
|
17
|
+
import { registerCodeEmitHandoffCommand } from './code-emit-handoff-command.js';
|
|
18
|
+
export { buildAutoCompactEnvelope } from './code-auto-compact-envelope.js';
|
|
19
|
+
export { contextNowActionFor } from './code-context-now-mapping.js';
|
|
104
20
|
export function registerCodeRuntimeCommands(code, io) {
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
.option('--session-id <sid>', 'override session id (default: read from active presence)')
|
|
112
|
-
.option('--active-skill <skill>', 'override active skill (test seam; default: read from presence)')).action(async (opts) => {
|
|
113
|
-
try {
|
|
114
|
-
const sessionId = opts.sessionId ?? readActiveSid(opts.project);
|
|
115
|
-
if (sessionId === null) {
|
|
116
|
-
printPostCompactNoActiveSession(io, opts);
|
|
117
|
-
return;
|
|
118
|
-
}
|
|
119
|
-
const probe = await detectPostCompactResume({
|
|
120
|
-
sessionId,
|
|
121
|
-
projectRoot: opts.project,
|
|
122
|
-
activeSkill: opts.activeSkill
|
|
123
|
-
});
|
|
124
|
-
const logLine = formatPostCompactResumeLogLine(probe);
|
|
125
|
-
printResult(io, ok('code.post-compact-detect', { ...probe, logLine }, [...probe.warnings], [
|
|
126
|
-
probe.shouldAutoResume
|
|
127
|
-
? `Post-compact match → auto-resume mode=${probe.mode ?? '?'} checkpoint=${probe.checkpointPath ?? '?'}`
|
|
128
|
-
: `No auto-resume: ${probe.reason}`
|
|
129
|
-
]), opts.json);
|
|
130
|
-
}
|
|
131
|
-
catch (err) {
|
|
132
|
-
printResult(io, fail('code.post-compact-detect', 'POST_COMPACT_DETECT_FAILED', getErrorMessage(err), null, ['Verify the project path and try again']), opts.json);
|
|
133
|
-
process.exitCode = 1;
|
|
134
|
-
}
|
|
135
|
-
});
|
|
136
|
-
addJsonOption(code
|
|
137
|
-
.command('auto-compact')
|
|
138
|
-
.description('v2.13.0 AC-4: zero-human-intervention auto-compact. Probes current ' +
|
|
139
|
-
'context-fill % via the active IDE adapter; ≥ 0.85 writes a pre-compact ' +
|
|
140
|
-
'checkpoint + convergence plan + auto-decisions log; ≥ 0.95 ASKS the ' +
|
|
141
|
-
'harness to compact and reports that it is waiting for it — no ratio ' +
|
|
142
|
-
'blocks sub-agent dispatch, because peaks-loop has no way to compact a ' +
|
|
143
|
-
'running session and a gate nobody can satisfy gates nothing. The LLM / ' +
|
|
144
|
-
'runner keeps working at any ratio without human intervention. Pair with `peaks code ' +
|
|
145
|
-
'context-now` (AC-1), the read-only probe that reports the ratio this ' +
|
|
146
|
-
'command acts on. This command is also fired by the installed ' +
|
|
147
|
-
'PreToolUse hook, which passes `--project .` — without that argument ' +
|
|
148
|
-
'the hook could never run at all. rid-027 ' +
|
|
149
|
-
'adds `--mode <mode>`: `standard` (0.85/0.95) or `partial` (0.70/0.85 ' +
|
|
150
|
-
'for 24h long-run mode).')
|
|
151
|
-
.requiredOption('--project <path>', 'target project root')
|
|
152
|
-
.option('--session-id <sid>', 'override session id (default: read from active presence)')
|
|
153
|
-
.option('--in-flight-batch', 'defer if a sub-agent batch is in flight (D6.e)')
|
|
154
|
-
.option('--force', 'force compact at any ratio (test seam)')
|
|
155
|
-
// Accepted and inert. There is no longer a 95% gate to skip: peaks-loop
|
|
156
|
-
// cannot compact a running session, so the red line never blocked
|
|
157
|
-
// dispatch and `bypassRedLine` is read by nothing (slice
|
|
158
|
-
// rather than deleted because it is a published CLI surface — deleting it
|
|
159
|
-
// would make an existing caller fail on an unknown option, which is a
|
|
160
|
-
// harder break than a no-op — and because the honest fix here is to stop
|
|
161
|
-
// advertising it, not to change its meaning.
|
|
162
|
-
.option('--bypass-red-line', 'no-op: the 95% red line no longer gates dispatch, so there is nothing to bypass (accepted for backward compatibility)')
|
|
163
|
-
// No commander default here, deliberately. A declared default makes
|
|
164
|
-
// `opts.mode` permanently defined, which defeats the orchestrator's
|
|
165
|
-
// `input.mode ?? resolveAutoCompactMode(projectRoot)` fallback and
|
|
166
|
-
// silently disables "24h mode auto-selects partial" — the help text
|
|
167
|
-
// below promises it. Absence must stay absent.
|
|
168
|
-
.option('--mode <mode>', 'auto-compact mode (standard | partial). Default: standard. 24h mode auto-selects partial.')).action(async (opts) => {
|
|
169
|
-
try {
|
|
170
|
-
const { isValidMode } = await import('../../services/code/auto-compact-modes.js');
|
|
171
|
-
const modeName = opts.mode ?? 'standard';
|
|
172
|
-
if (!isValidMode(modeName)) {
|
|
173
|
-
printResult(io, fail('code.auto-compact', 'AUTO_COMPACT_INVALID_MODE', `Invalid --mode '${modeName}'. Valid values: standard | partial.`, null, ['Re-run with --mode standard or --mode partial.']), opts.json);
|
|
174
|
-
process.exitCode = 1;
|
|
175
|
-
return;
|
|
176
|
-
}
|
|
177
|
-
// Slice 4.0.8 (D4d): production `inFlightBatch` MUST come from
|
|
178
|
-
// the workflow graph probe. The legacy `--in-flight-batch`
|
|
179
|
-
// boolean CLI flag is a TEST-ONLY seam (gated by
|
|
180
|
-
// `PEAKS_TEST_SEAM === '1'`). When the env flag is unset
|
|
181
|
-
// (the production case), we wire `probeInflightBatch` to the
|
|
182
|
-
// canonical `workflow-inflight-probe.ts` service so the
|
|
183
|
-
// production decision is graph-backed, not lease-age.
|
|
184
|
-
const isTestSeam = process.env.PEAKS_TEST_SEAM === '1';
|
|
185
|
-
const result = await runAutoCompact({
|
|
186
|
-
projectRoot: opts.project,
|
|
187
|
-
sessionId: opts.sessionId ?? readActiveSid(opts.project) ?? undefined,
|
|
188
|
-
...(isTestSeam && opts.inFlightBatch === true
|
|
189
|
-
? { inFlightBatch: { hasInFlightBatch: true } }
|
|
190
|
-
: {}),
|
|
191
|
-
...(!isTestSeam
|
|
192
|
-
? {
|
|
193
|
-
probeInflightBatch: () => {
|
|
194
|
-
// Synchronous probe: the workflow-inflight-probe
|
|
195
|
-
// service is pure / synchronous (no I/O). The
|
|
196
|
-
// empty `graphs` array is the production CLI
|
|
197
|
-
// default — callers that want a richer fixture
|
|
198
|
-
// (e.g. `peaks session 24h-mode`) should hand-roll
|
|
199
|
-
// a probe and pass it via the orchestrator's
|
|
200
|
-
// input. When no graph is materialized, the
|
|
201
|
-
// probe returns `inFlightBatch: false`, matching
|
|
202
|
-
// the 4.0.7 zero-pause contract for stock
|
|
203
|
-
// projects.
|
|
204
|
-
const out = probeInFlightBatch({ now: new Date().toISOString(), graphs: [] });
|
|
205
|
-
return out.inFlightBatch === true;
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
: {}),
|
|
209
|
-
force: opts.force === true,
|
|
210
|
-
bypassRedLine: opts.bypassRedLine === true,
|
|
211
|
-
// Forward the FLAG verbatim — `undefined` when the user named no
|
|
212
|
-
// mode — so the orchestrator's fallback to the presence-derived
|
|
213
|
-
// mode can actually run. Forwarding the validated `modeName` is
|
|
214
|
-
// what disabled 24h → partial.
|
|
215
|
-
mode: opts.mode === undefined ? undefined : modeName
|
|
216
|
-
});
|
|
217
|
-
const code = result.code;
|
|
218
|
-
const exitOk = result.ok || code === 'AUTO_COMPACT_SKIP' || code === 'AUTO_COMPACT_WAIT';
|
|
219
|
-
// Adapt AutoCompactResult → ResultEnvelope so printResult's
|
|
220
|
-
// generic accepts it. The orchestrator envelope carries
|
|
221
|
-
// `data` on success-path and `nextActions` on the error
|
|
222
|
-
// path; surface both directly to the user.
|
|
223
|
-
printResult(io, buildAutoCompactEnvelope(result), opts.json);
|
|
224
|
-
if (!exitOk)
|
|
225
|
-
process.exitCode = 1;
|
|
226
|
-
}
|
|
227
|
-
catch (err) {
|
|
228
|
-
printResult(io, fail('code.auto-compact', 'AUTO_COMPACT_FAILED', getErrorMessage(err), null, [
|
|
229
|
-
'Verify the project path + session id and try again'
|
|
230
|
-
]), opts.json);
|
|
231
|
-
process.exitCode = 1;
|
|
232
|
-
}
|
|
233
|
-
});
|
|
234
|
-
addJsonOption(code
|
|
235
|
-
.command('context-now')
|
|
236
|
-
.description("v2.13.0 AC-1: read the active IDE adapter's context-fill % " +
|
|
237
|
-
'without requiring the LLM to pass --prompt-size <bytes> manually. ' +
|
|
238
|
-
'Adapter-driven (no hard-coded IDE names): Claude Code is the MVP ' +
|
|
239
|
-
'implementation; trae / codex / cursor / qoder / tongyi-lingma / ' +
|
|
240
|
-
'hermes / openclaw register their own env-var via IdeAdapter.compact. ' +
|
|
241
|
-
"v3.1.2 / 2026-09-12: the mode's pre-compact line emits " +
|
|
242
|
-
'action=auto-compact-now (MANDATORY, single-rid included) and ' +
|
|
243
|
-
'the red line emits action=red-line (the installed PreToolUse hook re-runs ' +
|
|
244
|
-
'this command on the next Bash/Task tool call; nothing is blocked). ' +
|
|
245
|
-
'--enforce-job-mode only changes the reported `jobMode` label; ' +
|
|
246
|
-
'the thresholds are identical. ' +
|
|
247
|
-
'Context-window override: set env PEAKS_CONTEXT_WINDOW_TOKENS=<positive int> ' +
|
|
248
|
-
'or `peaks config set --key context.windowTokens --value <positive int>`; ' +
|
|
249
|
-
'the JSON envelope reports the winning layer as capacitySource ' +
|
|
250
|
-
'(env-override | config | model-heuristic | default).')
|
|
251
|
-
.requiredOption('--project <path>', 'target project root')
|
|
252
|
-
.option('--session-id <sid>', 'override session id (default: read from active presence)')
|
|
253
|
-
.option('--enforce-job-mode', 'v3.1.2: label the run as Job-shaped (jobMode=true). Auto-enabled when job-shape.json says isJob=true. Since 2026-09-12 the ≥0.85 MANDATORY auto-compact applies in single-rid mode too, so this flag no longer changes any action.')
|
|
254
|
-
.option('--prompt-size <bytes>', 'override the bytes-from-env path; takes priority over env / statusline / transcript. Useful when CLAUDE_CONTEXT_USAGE_PERCENT is absent (e.g. Mac Claude Code).')).action(async (opts) => {
|
|
255
|
-
try {
|
|
256
|
-
const { readContextPercent } = await import('../../services/context/auto-compact-reader.js');
|
|
257
|
-
// guard rejects non-finite / negative values; only finite
|
|
258
|
-
// non-negative numbers reach the reader. Undefined → no override.
|
|
259
|
-
let promptSizeBytes;
|
|
260
|
-
if (opts.promptSize !== undefined) {
|
|
261
|
-
const parsed = Number(opts.promptSize);
|
|
262
|
-
if (Number.isFinite(parsed) && parsed >= 0) {
|
|
263
|
-
promptSizeBytes = parsed;
|
|
264
|
-
}
|
|
265
|
-
}
|
|
266
|
-
// v3.1.2: detect Job mode from job-shape.json when --enforce-job-mode
|
|
267
|
-
// is not explicitly passed. The LLM is the source of truth for
|
|
268
|
-
// whether the request is Job-shaped; the recorded decision is.
|
|
269
|
-
let isJobMode = opts.enforceJobMode === true;
|
|
270
|
-
if (!isJobMode) {
|
|
271
|
-
try {
|
|
272
|
-
const sessionIdForDecision = opts.sessionId ?? readActiveSid(opts.project);
|
|
273
|
-
if (sessionIdForDecision !== null) {
|
|
274
|
-
const record = readJobShapeDecision(opts.project, sessionIdForDecision);
|
|
275
|
-
if (record.decision.isJob)
|
|
276
|
-
isJobMode = true;
|
|
277
|
-
}
|
|
278
|
-
}
|
|
279
|
-
catch (err) {
|
|
280
|
-
if (!(err instanceof JobShapeDecisionError))
|
|
281
|
-
throw err;
|
|
282
|
-
// missing/malformed decision file is fine — fall back to advisory.
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
const sessionId = opts.sessionId ?? readActiveSid(opts.project) ?? 'unknown';
|
|
286
|
-
const outerSessionId = resolveOuterSessionId(opts.project, sessionId);
|
|
287
|
-
const probe = readContextPercent({
|
|
288
|
-
projectRoot: opts.project,
|
|
289
|
-
sessionId,
|
|
290
|
-
outerSessionId,
|
|
291
|
-
env: process.env,
|
|
292
|
-
promptSizeBytes
|
|
293
|
-
});
|
|
294
|
-
// Promote `--project .` (what the PreToolUse hook passes) to the git
|
|
295
|
-
// root ONCE, for both of the consumers below: the settings path the
|
|
296
|
-
// harness window is written to, and the session directory the witness
|
|
297
|
-
// is read from, must not depend on the caller's cwd — and an absolute
|
|
298
|
-
// path is what the envelope then reports back to the operator. This
|
|
299
|
-
// resolves through `git rev-parse --show-toplevel`, i.e. a whole
|
|
300
|
-
// process spawn (measured 2026-09-14: med 111.8 ms per call on this
|
|
301
|
-
// host), so calling it twice with the same argument charged the witness
|
|
302
|
-
// read it precedes — 0.027 ms — roughly 4,000x its own cost.
|
|
303
|
-
const canonicalProjectRoot = resolveCanonicalProjectRoot(opts.project);
|
|
304
|
-
// the window this probe just divided by into the harness's own settings,
|
|
305
|
-
// so "85%" here and the harness's own trigger are one point on one
|
|
306
|
-
// scale. Idempotent (no write when the value is already in force) and a
|
|
307
|
-
// no-op when the probe carried no token window — peaks-loop never
|
|
308
|
-
// invents a number it did not measure.
|
|
309
|
-
const harnessWindow = syncHarnessWindowForProject({
|
|
310
|
-
projectRoot: canonicalProjectRoot,
|
|
311
|
-
env: process.env,
|
|
312
|
-
tokens: probe.capacityTokens ?? null
|
|
313
|
-
});
|
|
314
|
-
// The machine half of 要告知. A refused write is not automatically a
|
|
315
|
-
// non-event: the file may pin a window that disagrees with the one this
|
|
316
|
-
// probe just divided by, and then the ratio above describes a trigger
|
|
317
|
-
// the harness is not going to fire. `nextActions` carries the full
|
|
318
|
-
// sentence; this one line rides `warnings` so a JSON consumer cannot
|
|
319
|
-
// miss it either.
|
|
320
|
-
const harnessWindowWarning = harnessWindowSyncWarning(harnessWindow);
|
|
321
|
-
// own number for the same quantity, captured by the statusline. This is
|
|
322
|
-
// OBSERVATION ONLY — it never feeds `verdict` / `action` / any threshold
|
|
323
|
-
// below. A wrong reading here must not be able to fire a compact.
|
|
324
|
-
const harnessWitness = readAndCompareHarnessWitness({
|
|
325
|
-
// The same promoted root as the harness-window write above, for the
|
|
326
|
-
// same reason: the statusline resolves its root from the harness
|
|
327
|
-
// payload (absolute), so a `--project .` from a hook would otherwise
|
|
328
|
-
// look for the witness somewhere else and report `absent` forever.
|
|
329
|
-
projectRoot: canonicalProjectRoot,
|
|
330
|
-
sessionId,
|
|
331
|
-
peaksRatio: probe.ratio,
|
|
332
|
-
peaksTokens: probe.rawTokens ?? null,
|
|
333
|
-
peaksWindowTokens: probe.capacityTokens ?? null,
|
|
334
|
-
outerSessionId: outerSessionId ?? null
|
|
335
|
-
});
|
|
336
|
-
const witnessNotice = describeHarnessWitness(harnessWitness);
|
|
337
|
-
const ratioPct = (probe.ratio * 100).toFixed(1);
|
|
338
|
-
// Slice H4 (rid=h4-context-now-mode-blind): ONE table, ONE mode
|
|
339
|
-
// resolver. The hard-coded ladder that used to live here (≥0.95 / ≥0.85
|
|
340
|
-
// / ≥0.5) read no mode at all, so on a 24h run (`partial` =
|
|
341
|
-
// 0.65/0.70/0.85) it answered `soft-warn` + `next: null` across
|
|
342
|
-
// [0.70, 0.85) — the band in which `peaks code auto-compact` had
|
|
343
|
-
// already decided to compact. SKILL.md calls THIS command the "single
|
|
344
|
-
// source of truth", so an LLM obeying it did nothing.
|
|
345
|
-
const compactMode = resolveAutoCompactProfile(canonicalProjectRoot);
|
|
346
|
-
const decided = contextNowActionFor(probe.ratio, compactMode);
|
|
347
|
-
const action = decided.action;
|
|
348
|
-
const next = decided.next;
|
|
349
|
-
const verdict = action === 'red-line'
|
|
350
|
-
? 'red-line'
|
|
351
|
-
: action === 'auto-compact-now'
|
|
352
|
-
? 'pre-compact'
|
|
353
|
-
: action;
|
|
354
|
-
const bands = contextNowBandLabels(compactMode);
|
|
355
|
-
// in behaviour ABOVE 0.50 — both auto-fire at ≥0.85 and both red-line at
|
|
356
|
-
// ≥0.95". That was false: `partial` fires at 0.70, red-lines at 0.85.
|
|
357
|
-
// The lines now come from the table for the mode in force.
|
|
358
|
-
const gateModeNotice = isJobMode
|
|
359
|
-
? `Job mode (job-shape.json isJob=true): the same ≥${bands.preCompactRatio} / ≥${bands.redLineRatio} thresholds apply, and the decision is recorded in job-shape.json.`
|
|
360
|
-
: `Single-rid mode: the same ≥${bands.preCompactRatio} / ≥${bands.redLineRatio} thresholds apply — ≥${bands.preCompactRatio} is MANDATORY auto-compact, not advisory.`;
|
|
361
|
-
printResult(io, ok('code.context-now', {
|
|
362
|
-
ratio: probe.ratio,
|
|
363
|
-
ratioPct: `${ratioPct}%`,
|
|
364
|
-
verdict,
|
|
365
|
-
action,
|
|
366
|
-
next,
|
|
367
|
-
jobMode: isJobMode,
|
|
368
|
-
source: probe.source,
|
|
369
|
-
ide: probe.ide,
|
|
370
|
-
capacityBytes: probe.capacityBytes,
|
|
371
|
-
rawBytes: probe.rawBytes ?? null,
|
|
372
|
-
rawTokens: probe.rawTokens ?? null,
|
|
373
|
-
capacityTokens: probe.capacityTokens ?? null,
|
|
374
|
-
// capacityTokens (env-override | config | model-heuristic |
|
|
375
|
-
// default) — null for byte/percent sources, which have no window.
|
|
376
|
-
capacitySource: probe.capacitySource ?? null,
|
|
377
|
-
bytesPrompt: promptSizeBytes ?? null,
|
|
378
|
-
capturedAt: probe.capturedAt,
|
|
379
|
-
// window sync did on this probe. Reported rather than silent — the
|
|
380
|
-
// harness tells a user who overrides the window only via
|
|
381
|
-
// `/autocompact`, so peaks-loop must be the one that says it.
|
|
382
|
-
harnessWindow,
|
|
383
|
-
harnessWitness
|
|
384
|
-
}, [
|
|
385
|
-
...(harnessWindowWarning === null ? [] : [harnessWindowWarning]),
|
|
386
|
-
// AC3: the disagreement rides `warnings` — it is a fact about the
|
|
387
|
-
// state, not an instruction — and it is one-way. Never an
|
|
388
|
-
// AskUserQuestion (see .peaks/memory/auto-compact-threshold-policy.md).
|
|
389
|
-
...(witnessNotice === null ? [] : [witnessNotice])
|
|
390
|
-
], [
|
|
391
|
-
action === 'red-line'
|
|
392
|
-
? `RED LINE: ≥ ${bands.redLine}%. Next: \`${next}\` — peaks-loop asks the harness to compact and KEEPS WORKING (dispatch is not blocked); re-probe to confirm it landed.`
|
|
393
|
-
: action === 'auto-compact-now'
|
|
394
|
-
? `MANDATORY auto-compact (≥${bands.preCompact}%, every mode). Code MUST call \`${next}\` WITHOUT confirmation.`
|
|
395
|
-
: action === 'soft-warn'
|
|
396
|
-
? `Soft warn (${bands.softWarn}–${bands.preCompact}%). Continue working; the next \`peaks code auto-compact\` will re-check.`
|
|
397
|
-
: `Below ${bands.softWarn}%. No action required.`,
|
|
398
|
-
gateModeNotice,
|
|
399
|
-
// Single wording, shared with `peaks code auto-compact` — see
|
|
400
|
-
// `describeHarnessWindowSync`.
|
|
401
|
-
describeHarnessWindowSync(harnessWindow),
|
|
402
|
-
// AC3: the one-way hint that accompanies the `warnings` entry. Both
|
|
403
|
-
// channels carry the SAME fact in the shape each is read for
|
|
404
|
-
// (machine-readable warning vs human/LLM advice) — see
|
|
405
|
-
// `harnessWindowSyncWarning` / `describeHarnessWindowSync` above for
|
|
406
|
-
// the same split, and note this one never asks a question.
|
|
407
|
-
...(witnessNotice === null
|
|
408
|
-
? []
|
|
409
|
-
: [
|
|
410
|
-
'Re-probe with `peaks code context-now` to confirm; this is reported, not blocking.'
|
|
411
|
-
])
|
|
412
|
-
]),
|
|
413
|
-
// `true`, which made the declared `--json` flag a no-op and left the
|
|
414
|
-
// human with raw JSON and no `next:` lines — so a person running this
|
|
415
|
-
// command could not see that peaks-loop had just written their
|
|
416
|
-
// harness settings. The notices above (including the key, the value
|
|
417
|
-
// and the rollback command) are `nextActions`, which `printResult`
|
|
418
|
-
// prints as `next: …` lines ONLY in the non-JSON path. Honoring the
|
|
419
|
-
// flag is what puts them in front of a human. See the consumer audit
|
|
420
|
-
// in the slice's RD artifact: every in-repo caller (the PreToolUse
|
|
421
|
-
// hooks, `orchestrator-can-do`, the skill runbooks) passes `--json`
|
|
422
|
-
// explicitly, so their byte-for-byte output is unchanged.
|
|
423
|
-
opts.json === true);
|
|
424
|
-
}
|
|
425
|
-
catch (err) {
|
|
426
|
-
printResult(io, fail('code.context-now', 'CONTEXT_NOW_FAILED', getErrorMessage(err), null, [
|
|
427
|
-
'Verify the project path and try again'
|
|
428
|
-
]), opts.json);
|
|
429
|
-
process.exitCode = 1;
|
|
430
|
-
}
|
|
431
|
-
});
|
|
432
|
-
// WHAT fills the orchestrator window. `context-now` returns a ratio; this
|
|
433
|
-
// returns the grouped byte breakdown of tool results from the live
|
|
434
|
-
// transcript. Read-only + fail-soft: an unavailable transcript reports
|
|
435
|
-
// `available:false` with a reason and NEVER sets a non-zero exit code.
|
|
436
|
-
addJsonOption(code
|
|
437
|
-
.command('context-audit')
|
|
438
|
-
.description("Slice 2026-09-10 Slice A: report what fills the current session's " +
|
|
439
|
-
'context window, grouped by tool + short input key (command line / ' +
|
|
440
|
-
"path tail / pattern), sorted by bytes. Locates the CURRENT session's " +
|
|
441
|
-
"IDE transcript through the active adapter's " +
|
|
442
|
-
'`compact.resolveTranscriptPath` (vendor-neutral); emits total bytes, ' +
|
|
443
|
-
'entry count, and the top-N groups ' +
|
|
444
|
-
'(`{tool, key, bytes, pctOfTotal, count}`). Read-only and fail-soft — ' +
|
|
445
|
-
'a missing/oversized/corrupt transcript returns `available:false` ' +
|
|
446
|
-
'with a reason and never blocks. Never dumps tool result content.')
|
|
447
|
-
.requiredOption('--project <path>', 'target project root')
|
|
448
|
-
.option('--session-id <sid>', 'override session id (default: read from active presence)')
|
|
449
|
-
.option('--top <n>', 'number of top entries to emit (default 15, max 100)', (value) => Number(value))
|
|
450
|
-
.option('--transcript <path>', 'override the transcript jsonl path (test seam)')).action((opts) => {
|
|
451
|
-
try {
|
|
452
|
-
// `resolveOuterSessionId` checks the env signal FIRST, so the peaks
|
|
453
|
-
// session id is only a fallback lookup key — mirror context-now's
|
|
454
|
-
// 'unknown' default so an unbound presence still resolves via env.
|
|
455
|
-
const sessionId = opts.sessionId ?? readActiveSid(opts.project) ?? 'unknown';
|
|
456
|
-
const outerSessionId = resolveOuterSessionId(opts.project, sessionId);
|
|
457
|
-
const result = auditContext({
|
|
458
|
-
outerSessionId: outerSessionId ?? null,
|
|
459
|
-
...(opts.top !== undefined ? { topN: opts.top } : {}),
|
|
460
|
-
...(opts.transcript !== undefined ? { transcriptPath: opts.transcript } : {})
|
|
461
|
-
});
|
|
462
|
-
// Fail-soft contract: unavailability is DATA, not an error. The exit
|
|
463
|
-
// code stays 0 so a `context-audit` call can never block a workflow.
|
|
464
|
-
const nextActions = result.available
|
|
465
|
-
? [
|
|
466
|
-
`${result.entryCount} tool result(s) across ${result.groupCount} group(s); showing top ${result.entries.length}.`
|
|
467
|
-
]
|
|
468
|
-
: [
|
|
469
|
-
`context-audit unavailable: ${result.reason ?? 'unknown'} — continue without it (read-only probe).`
|
|
470
|
-
];
|
|
471
|
-
printResult(io, ok('code.context-audit', { ...result }, [], nextActions), opts.json);
|
|
472
|
-
}
|
|
473
|
-
catch (err) {
|
|
474
|
-
printResult(io, ok('code.context-audit', {
|
|
475
|
-
available: false,
|
|
476
|
-
reason: `audit-failed: ${getErrorMessage(err)}`,
|
|
477
|
-
transcriptPath: null,
|
|
478
|
-
totalBytes: 0,
|
|
479
|
-
entryCount: 0,
|
|
480
|
-
groupCount: 0,
|
|
481
|
-
topN: 0,
|
|
482
|
-
entries: []
|
|
483
|
-
}, [], ['context-audit is a read-only probe; continue without it.']), opts.json);
|
|
484
|
-
}
|
|
485
|
-
});
|
|
486
|
-
// v3.1.2 Step 0.8 — Mechanical PreToolUse gate.
|
|
487
|
-
// Wire-installed by `peaks workspace init` (extends the existing hook
|
|
488
|
-
// installer). Exit code is the load-bearing contract:
|
|
489
|
-
// exit 0 → allow (with structured stdout describing the decision)
|
|
490
|
-
// exit 2 → block (stderr contains the BLOCKED: ... reason)
|
|
491
|
-
addJsonOption(code
|
|
492
|
-
.command('gate-step-08')
|
|
493
|
-
.description('v3.1.2: PreToolUse gate for Step 0.8 — allow when job-shape.json exists; ' +
|
|
494
|
-
'fail-closed backup regex when missing. Exit 0 = allow, exit 2 = block. ' +
|
|
495
|
-
'When the decision says isJob=true AND progress.json exists, the stdout ' +
|
|
496
|
-
'also carries `Next: slice #N+1 of M (<currentSlice>)` so the LLM cannot ' +
|
|
497
|
-
'wake up cold. When the context ratio is ≥ 0.70 the stdout gains ONE more ' +
|
|
498
|
-
'line naming the largest context consumer (audit cached ≥ 5 min; fail-soft).')
|
|
499
|
-
.requiredOption('--project <path>', 'target project root (the hook passes "." so resolveCanonicalProjectRoot promotes it to the git root)')
|
|
500
|
-
.option('--session-id <sid>', 'override session id (default: read from active presence)')
|
|
501
|
-
.option('--prompt <text>', 'explicit prompt text (default: read last-prompt.txt; stdin ignored)')).action((opts) => {
|
|
502
|
-
try {
|
|
503
|
-
const sessionId = opts.sessionId ?? readActiveSid(opts.project);
|
|
504
|
-
if (sessionId === null) {
|
|
505
|
-
// No session binding — treat as allow (single-rid mode). The
|
|
506
|
-
// LLM has not yet anchored; we have nothing to gate against.
|
|
507
|
-
const envelope = ok('code.gate-step-08', {
|
|
508
|
-
allow: true,
|
|
509
|
-
mode: 'no-session',
|
|
510
|
-
decision: null,
|
|
511
|
-
nextSlice: null
|
|
512
|
-
}, [], ['No active session id; gate passes through (single-rid mode).']);
|
|
513
|
-
printResult(io, envelope, opts.json);
|
|
514
|
-
return;
|
|
515
|
-
}
|
|
516
|
-
// hint. Runs ONLY when the window is ≥ 0.70 full, caches the audit
|
|
517
|
-
// result for ≥ 5 min so the transcript is scanned at most once per
|
|
518
|
-
// TTL window, and is fail-soft (null → no extra line). It never
|
|
519
|
-
// changes the exit code and never blocks.
|
|
520
|
-
const hintLine = buildContextAuditHint({
|
|
521
|
-
projectRoot: opts.project,
|
|
522
|
-
sessionId,
|
|
523
|
-
outerSessionId: resolveOuterSessionId(opts.project, sessionId)
|
|
524
|
-
});
|
|
525
|
-
const hintActions = hintLine === null ? [] : [hintLine];
|
|
526
|
-
const evalInput = {
|
|
527
|
-
projectRoot: opts.project,
|
|
528
|
-
sessionId
|
|
529
|
-
};
|
|
530
|
-
if (opts.prompt !== undefined)
|
|
531
|
-
evalInput.prompt = opts.prompt;
|
|
532
|
-
const result = evaluateStep08(evalInput);
|
|
533
|
-
const verdict = result.verdict;
|
|
534
|
-
if (verdict.kind === 'allow-job') {
|
|
535
|
-
const envelope = ok('code.gate-step-08', {
|
|
536
|
-
allow: true,
|
|
537
|
-
mode: 'job',
|
|
538
|
-
decision: verdict.decision,
|
|
539
|
-
progress: verdict.progress,
|
|
540
|
-
nextSlice: result.nextSliceLine
|
|
541
|
-
}, [], [...(result.nextSliceLine !== null ? [result.nextSliceLine] : []), ...hintActions]);
|
|
542
|
-
printResult(io, envelope, opts.json);
|
|
543
|
-
return;
|
|
544
|
-
}
|
|
545
|
-
if (verdict.kind === 'allow-single') {
|
|
546
|
-
const envelope = ok('code.gate-step-08', {
|
|
547
|
-
allow: true,
|
|
548
|
-
mode: 'single',
|
|
549
|
-
decision: null,
|
|
550
|
-
nextSlice: null
|
|
551
|
-
}, [], ['job-shape.json says isJob=false; single-rid mode (gate allows).', ...hintActions]);
|
|
552
|
-
printResult(io, envelope, opts.json);
|
|
553
|
-
return;
|
|
554
|
-
}
|
|
555
|
-
// block-missing-decision
|
|
556
|
-
if (verdict.promptHit) {
|
|
557
|
-
// Block: backup regex hit. Exit code 2 is the load-bearing
|
|
558
|
-
// signal for the PreToolUse hook.
|
|
559
|
-
const blockMessage = 'BLOCKED: prompt looks Job-shaped but peaks code detect-job has not been called. Run `peaks code detect-job --is-job true ...` to record your Job-shape verdict, then retry.';
|
|
560
|
-
const envelope = fail('code.gate-step-08', 'STEP_08_BLOCKED', blockMessage, {
|
|
561
|
-
promptSource: verdict.promptSource,
|
|
562
|
-
backupRegex: STEP_08_BACKUP_REGEX.toString()
|
|
563
|
-
}, [
|
|
564
|
-
'Run `peaks code detect-job --is-job true --rationale <text> --suggested-job-id <slug>` to record the Job-shape verdict.',
|
|
565
|
-
'Then re-run the Bash tool call.',
|
|
566
|
-
...hintActions
|
|
567
|
-
]);
|
|
568
|
-
io.stderr(`${blockMessage}\n`);
|
|
569
|
-
printResult(io, envelope, opts.json);
|
|
570
|
-
process.exitCode = 2;
|
|
571
|
-
return;
|
|
572
|
-
}
|
|
573
|
-
// No decision + no regex hit → allow.
|
|
574
|
-
const envelope = ok('code.gate-step-08', {
|
|
575
|
-
allow: true,
|
|
576
|
-
mode: 'undecided-no-regex-hit',
|
|
577
|
-
decision: null,
|
|
578
|
-
nextSlice: null,
|
|
579
|
-
promptSource: verdict.promptSource
|
|
580
|
-
}, [], [
|
|
581
|
-
'No job-shape.json AND no backup-regex match on prompt → allow (most prompts are not Job-shaped).',
|
|
582
|
-
...hintActions
|
|
583
|
-
]);
|
|
584
|
-
printResult(io, envelope, opts.json);
|
|
585
|
-
return;
|
|
586
|
-
}
|
|
587
|
-
catch (err) {
|
|
588
|
-
printResult(io, fail('code.gate-step-08', 'GATE_STEP_08_FAILED', getErrorMessage(err), null, [
|
|
589
|
-
'Verify the project path and try again'
|
|
590
|
-
]), opts.json);
|
|
591
|
-
process.exitCode = 1;
|
|
592
|
-
}
|
|
593
|
-
});
|
|
594
|
-
// v3.1.2 Step 11 / final handoff — Size-fear ban.
|
|
595
|
-
// Refuses to emit a final handoff while a Job has remaining slices.
|
|
596
|
-
addJsonOption(code
|
|
597
|
-
.command('emit-handoff')
|
|
598
|
-
.description('v3.1.2 Step 11 size-fear ban: under Job mode, refuse to emit a final ' +
|
|
599
|
-
'handoff while remaining > 0. Exit 0 = allow, exit 1 = block. Pass ' +
|
|
600
|
-
'--force-under-job to override (requires explicit user approval).')
|
|
601
|
-
.requiredOption('--project <path>', 'target project root')
|
|
602
|
-
.option('--session-id <sid>', 'override session id (default: read from active presence)')
|
|
603
|
-
.option('--job-id <jid>', 'override job id (default: read from job-shape.json decision.suggestedJobId)')
|
|
604
|
-
.option('--force-under-job', 'override the remaining>0 block (explicit user approval required)')).action((opts) => {
|
|
605
|
-
try {
|
|
606
|
-
const sessionId = opts.sessionId ?? readActiveSid(opts.project);
|
|
607
|
-
if (sessionId === null) {
|
|
608
|
-
const envelope = ok('code.emit-handoff', { allow: true, mode: 'no-session' }, [], ['No active session id; gate passes through (single-rid mode).']);
|
|
609
|
-
printResult(io, envelope, opts.json);
|
|
610
|
-
return;
|
|
611
|
-
}
|
|
612
|
-
const evalInput = {
|
|
613
|
-
projectRoot: opts.project,
|
|
614
|
-
sessionId
|
|
615
|
-
};
|
|
616
|
-
if (opts.jobId !== undefined)
|
|
617
|
-
evalInput.jobId = opts.jobId;
|
|
618
|
-
if (opts.forceUnderJob === true)
|
|
619
|
-
evalInput.forceUnderJob = true;
|
|
620
|
-
const verdict = evaluateEmitHandoff(evalInput);
|
|
621
|
-
if (verdict.kind === 'allow-not-job') {
|
|
622
|
-
const envelope = ok('code.emit-handoff', { allow: true, mode: 'single' }, [], ['job-shape.json says isJob=false (or absent); normal handoff allowed.']);
|
|
623
|
-
printResult(io, envelope, opts.json);
|
|
624
|
-
return;
|
|
625
|
-
}
|
|
626
|
-
if (verdict.kind === 'allow-done') {
|
|
627
|
-
const envelope = ok('code.emit-handoff', { allow: true, mode: 'job-done', remaining: verdict.remaining }, [], [`Job is complete (remaining=0); handoff allowed.`]);
|
|
628
|
-
printResult(io, envelope, opts.json);
|
|
629
|
-
return;
|
|
630
|
-
}
|
|
631
|
-
if (verdict.kind === 'allow-force-override') {
|
|
632
|
-
const envelope = ok('code.emit-handoff', { allow: true, mode: 'job-force-override', remaining: verdict.remaining }, [], [
|
|
633
|
-
`Job has ${verdict.remaining} remaining slices; --force-under-job override applied. Handoff allowed (explicit user approval).`
|
|
634
|
-
]);
|
|
635
|
-
printResult(io, envelope, opts.json);
|
|
636
|
-
return;
|
|
637
|
-
}
|
|
638
|
-
if (verdict.kind === 'block-not-initialized') {
|
|
639
|
-
const envelope = fail('code.emit-handoff', JOB_NOT_INITIALIZED, `Job ${verdict.jobId} has no state.json; peaks job init was skipped.`, { jobId: verdict.jobId }, [
|
|
640
|
-
`Run \`peaks job init --job-id ${verdict.jobId} --slice-list <...>\` before emitting handoff.`
|
|
641
|
-
]);
|
|
642
|
-
printResult(io, envelope, opts.json);
|
|
643
|
-
process.exitCode = 1;
|
|
644
|
-
return;
|
|
645
|
-
}
|
|
646
|
-
// block-remaining
|
|
647
|
-
const blockMessage = `BLOCKED: Job ${verdict.jobId} has ${verdict.remaining} remaining slices. Run \`peaks job status\`. Use --force-under-job only with explicit user approval.`;
|
|
648
|
-
const envelope = fail('code.emit-handoff', JOB_REMAINING_BLOCKED, blockMessage, { jobId: verdict.jobId, remaining: verdict.remaining }, [
|
|
649
|
-
`Run \`peaks job status --job-id ${verdict.jobId}\` to see remaining slices.`,
|
|
650
|
-
'Resume Step 0.81 (per-slice checkpoint loop) and continue until remaining === 0.',
|
|
651
|
-
'Use --force-under-job only with explicit user approval (size-fear ban override).'
|
|
652
|
-
]);
|
|
653
|
-
io.stderr(`${blockMessage}\n`);
|
|
654
|
-
printResult(io, envelope, opts.json);
|
|
655
|
-
process.exitCode = 1;
|
|
656
|
-
return;
|
|
657
|
-
}
|
|
658
|
-
catch (err) {
|
|
659
|
-
printResult(io, fail('code.emit-handoff', 'EMIT_HANDOFF_FAILED', getErrorMessage(err), null, [
|
|
660
|
-
'Verify the project path and try again'
|
|
661
|
-
]), opts.json);
|
|
662
|
-
process.exitCode = 1;
|
|
663
|
-
}
|
|
664
|
-
});
|
|
665
|
-
}
|
|
666
|
-
// Only the 5 runtime probes above use it; keeping it local avoids the
|
|
667
|
-
// cross-file helper import.
|
|
668
|
-
function readActiveSid(projectRoot) {
|
|
669
|
-
try {
|
|
670
|
-
const presence = getSkillPresence(projectRoot);
|
|
671
|
-
if (presence === null || presence === undefined)
|
|
672
|
-
return null;
|
|
673
|
-
return presence.sessionId ?? null;
|
|
674
|
-
}
|
|
675
|
-
catch {
|
|
676
|
-
// TODO(g2): legacy silent catch — grace: 1 minor release (v2.14.0)
|
|
677
|
-
return null;
|
|
678
|
-
}
|
|
21
|
+
registerCodePostCompactDetectCommand(code, io);
|
|
22
|
+
registerCodeAutoCompactCommand(code, io);
|
|
23
|
+
registerCodeContextNowCommand(code, io);
|
|
24
|
+
registerCodeContextAuditCommand(code, io);
|
|
25
|
+
registerCodeGateStep08Command(code, io);
|
|
26
|
+
registerCodeEmitHandoffCommand(code, io);
|
|
679
27
|
}
|