peaks-loop 4.0.45 → 4.0.47
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +48 -0
- package/README-en.md +1 -1
- package/README.md +1 -1
- package/dist/cli/commands/code-runtime-commands.d.ts +22 -0
- package/dist/cli/commands/code-runtime-commands.js +128 -34
- package/dist/cli/commands/compact-command.js +129 -1
- package/dist/cli/commands/container-commands.js +3 -3
- package/dist/cli/commands/core/skill-command.js +45 -10
- package/dist/cli/commands/cron-commands.js +2 -1
- package/dist/cli/commands/e2e-verify.js +3 -3
- package/dist/cli/commands/governance-classify-contract-commands.js +1 -0
- package/dist/cli/commands/hooks-commands.js +10 -1
- package/dist/cli/commands/loop-commands.js +1 -0
- package/dist/cli/commands/playwright-commands.js +2 -1
- package/dist/cli/commands/reinject-command.d.ts +72 -0
- package/dist/cli/commands/reinject-command.js +174 -0
- package/dist/cli/commands/request-commands.js +6 -3
- package/dist/cli/commands/shadcn-commands.js +1 -0
- package/dist/cli/commands/test-commands.js +2 -1
- package/dist/cli/commands/vm-commands.js +7 -7
- package/dist/cli/commands/workspace/init-command.js +24 -2
- package/dist/cli/commands/worktree-lease-commands.js +4 -4
- package/dist/cli/index.js +49 -2
- package/dist/cli/program.js +5 -0
- package/dist/hooks/pre-tool-use-sub-agent.js +1 -1
- package/dist/services/adapter/adapter-registry.js +1 -1
- package/dist/services/artifacts/artifact-service.js +1 -1
- package/dist/services/capability-guard-runner/contracts/J01.js +2 -1
- package/dist/services/capability-guard-runner/contracts/J02.js +3 -3
- package/dist/services/capability-guard-runner/contracts/J04.js +4 -2
- package/dist/services/capability-guard-runner/contracts/J07.js +2 -1
- package/dist/services/code/auto-compact-lifecycle.d.ts +50 -4
- package/dist/services/code/auto-compact-lifecycle.js +52 -10
- package/dist/services/code/auto-compact-orchestrator.d.ts +53 -9
- package/dist/services/code/auto-compact-orchestrator.js +173 -43
- package/dist/services/code/orchestrator-can-do.d.ts +4 -2
- package/dist/services/code/orchestrator-can-do.js +37 -5
- package/dist/services/codegraph/codegraph-exclude-reconciler.js +2 -1
- package/dist/services/codegraph/codegraph-process-runner.js +3 -2
- package/dist/services/compact/request-transition-hook.js +5 -2
- package/dist/services/compact-history/compact-history-service.d.ts +61 -0
- package/dist/services/compact-history/compact-history-service.js +49 -0
- package/dist/services/compact-statusline/compact-lifecycle-store.d.ts +11 -2
- package/dist/services/compact-statusline/compact-lifecycle-store.js +19 -1
- package/dist/services/compact-statusline/compact-statusline-service.d.ts +1 -1
- package/dist/services/compact-statusline/compact-statusline-service.js +22 -0
- package/dist/services/config/config-safety.d.ts +52 -0
- package/dist/services/config/config-safety.js +75 -1
- package/dist/services/context/auto-compact-dispatcher.d.ts +7 -37
- package/dist/services/context/auto-compact-dispatcher.js +113 -40
- package/dist/services/context/auto-compact-reader.d.ts +68 -28
- package/dist/services/context/auto-compact-reader.js +155 -1
- package/dist/services/context/auto-compact-types.d.ts +89 -12
- package/dist/services/context/auto-compact-types.js +16 -32
- package/dist/services/context/harness-window-config.d.ts +412 -0
- package/dist/services/context/harness-window-config.js +607 -0
- package/dist/services/context/main-session-monitor.d.ts +27 -0
- package/dist/services/context/main-session-monitor.js +32 -1
- package/dist/services/context/post-compact-reinjection.d.ts +221 -0
- package/dist/services/context/post-compact-reinjection.js +491 -0
- package/dist/services/dispatch/merge-back-runner.js +5 -5
- package/dist/services/dispatch/service-shutdown.js +3 -3
- package/dist/services/doc/doc-generator.js +2 -1
- package/dist/services/env/shell-probe.js +1 -1
- package/dist/services/fuzzy-matching/fzf-pick-service.js +2 -0
- package/dist/services/hooks/auto-compact-hook-install.d.ts +10 -2
- package/dist/services/hooks/auto-compact-hook-install.js +8 -0
- package/dist/services/ide/adapters/claude-code-adapter.d.ts +107 -3
- package/dist/services/ide/adapters/claude-code-adapter.js +154 -7
- package/dist/services/ide/ide-registry.d.ts +12 -0
- package/dist/services/ide/ide-registry.js +14 -0
- package/dist/services/ide/ide-types.d.ts +59 -0
- package/dist/services/lint/detect-eslint.js +2 -2
- package/dist/services/lint/eslint-runner.js +3 -1
- package/dist/services/loop/evaluator-dispatcher.js +2 -1
- package/dist/services/memory/project-memory-service/index/kind-dispatch.js +1 -1
- package/dist/services/memory/project-memory-service/store/paths.d.ts +9 -1
- package/dist/services/memory/project-memory-service/store/paths.js +15 -6
- package/dist/services/prd/best-practice-auto-trigger.js +1 -0
- package/dist/services/release/version-precheck-service.d.ts +2 -1
- package/dist/services/release/version-precheck-service.js +82 -12
- package/dist/services/runtime/vendor-adapter.d.ts +29 -4
- package/dist/services/runtime/vendors/claude-code.js +1 -1
- package/dist/services/runtime/vendors/codex.js +1 -1
- package/dist/services/runtime/vendors/copilot.js +1 -1
- package/dist/services/sc/sc-service.js +1 -1
- package/dist/services/scan/diff-scope-service.js +2 -2
- package/dist/services/scan/file-size-scan.js +2 -2
- package/dist/services/scan/orphan-service.js +2 -1
- package/dist/services/scan/type-sanity-service.js +2 -2
- package/dist/services/skillhub/tar-runtime.js +1 -0
- package/dist/services/skills/hooks-codegate-superpowers.d.ts +8 -0
- package/dist/services/skills/hooks-codegate-superpowers.js +40 -3
- package/dist/services/skills/hooks-settings-service.d.ts +12 -0
- package/dist/services/skills/hooks-settings-service.js +77 -10
- package/dist/services/skills/session-start-hook-constants.d.ts +41 -0
- package/dist/services/skills/session-start-hook-constants.js +41 -0
- package/dist/services/skills/skill-presence-service.js +9 -0
- package/dist/services/skills/skill-statusline-renderer.js +30 -5
- package/dist/services/skills/statusline-palette.d.ts +6 -0
- package/dist/services/skills/statusline-palette.js +4 -1
- package/dist/services/slice/slice-check-service.js +2 -1
- package/dist/services/slice/slice-decompose-runners.js +2 -1
- package/dist/services/upgrade/upgrade-service.js +1 -0
- package/dist/services/workflow/workflow-skip-service.js +2 -1
- package/dist/services/workspace/migrate-service.js +1 -1
- package/dist/services/workspace/workspace-claude-settings-materializer.js +51 -7
- package/dist/services/workspace/workspace-service.js +8 -0
- package/dist/services/worktree/host-worktree-reconciler.js +1 -0
- package/dist/services/worktree/long-path-cleanup.js +3 -2
- package/dist/shared/process.js +1 -1
- package/package.json +5 -5
- package/scripts/install-skills.mjs +1 -0
- package/scripts/watch.mjs +3 -1
- package/skills/bee/peaks-perf-audit/SKILL.md +1 -1
- package/skills/bee/peaks-prd/SKILL.md +1 -1
- package/skills/bee/peaks-qa/SKILL.md +2 -2
- package/skills/bee/peaks-rd/SKILL.md +2 -2
- package/skills/bee/peaks-reviewer/SKILL.md +1 -1
- package/skills/bee/peaks-sc/SKILL.md +1 -1
- package/skills/bee/peaks-security-audit/SKILL.md +1 -1
- package/skills/bee/peaks-txt/SKILL.md +1 -1
- package/skills/bee/peaks-ui/SKILL.md +1 -1
- package/skills/peaks-audit/SKILL.md +1 -1
- package/skills/peaks-code/SKILL.md +4 -4
- package/skills/peaks-code/references/sub-agent-dispatch.md +1 -1
- package/skills/peaks-content/SKILL.md +1 -1
- package/skills/peaks-doctor/SKILL.md +1 -1
- package/skills/peaks-final-review/SKILL.md +1 -1
- package/skills/peaks-ide/SKILL.md +1 -1
- package/skills/peaks-issue-fix-orchestrator/SKILL.md +1 -1
- package/skills/peaks-resume/SKILL.md +1 -1
- package/skills/peaks-slice-decompose/SKILL.md +1 -1
- package/skills/peaks-solo/SKILL.md +1 -1
- package/skills/peaks-sop/SKILL.md +1 -1
- package/skills/peaks-status/SKILL.md +1 -1
- package/skills/peaks-test/SKILL.md +1 -1
|
@@ -604,6 +604,15 @@ export function clearSkillPresence(projectRootOverride) {
|
|
|
604
604
|
// shim; the LLM runner calls `peaks workflow terminalize` or
|
|
605
605
|
// `terminalizePresenceLease` directly).
|
|
606
606
|
//
|
|
607
|
+
// That rule is the surrounding DESIGN, not a description of this
|
|
608
|
+
// function: nothing below routes anywhere. This shim has no session
|
|
609
|
+
// lock, no lease argument and no workflow id, so it cannot route —
|
|
610
|
+
// it cleans up deprecated files and returns whether it removed any.
|
|
611
|
+
// The truthful report of what remains is the caller's job
|
|
612
|
+
// (`skill-command.ts` re-reads the live projection and emits
|
|
613
|
+
// `cleared` / `reason`). Do not read the paragraph above as a
|
|
614
|
+
// promise about this function.
|
|
615
|
+
//
|
|
607
616
|
// The shim still removes the legacy `active-skill.json` /
|
|
608
617
|
// `.peaks/.active-skill.json` so a stale marker from a prior CLI
|
|
609
618
|
// version cannot resurrect after a fresh `clear`. The canonical
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { basename } from 'node:path';
|
|
2
|
+
import { AUTO_COMPACT_RED_LINE_RATIO } from '../context/auto-compact-types.js';
|
|
2
3
|
import { computeRootSuffix as computeRootSuffixImpl, } from './skill-statusline-sid-suffix.js';
|
|
3
4
|
// Re-export so existing test imports
|
|
4
5
|
// (`import { formatShortSid, computeRootSuffix } from '.../skill-statusline-renderer'`)
|
|
@@ -181,6 +182,10 @@ function formatRatio(value) {
|
|
|
181
182
|
*
|
|
182
183
|
* <stage-glyph> <bar> <label>[ · <before>%][ → <after>%]
|
|
183
184
|
*
|
|
185
|
+
* `armed` is the one exception: it renders WITHOUT the bar
|
|
186
|
+
* (`<glyph> armed · <before>% · fires at <redLine>%`) because a bar is
|
|
187
|
+
* a progress claim and a registered-but-unfired trigger has no progress.
|
|
188
|
+
*
|
|
184
189
|
* Failed states additionally suffix the stage at which the compact failed.
|
|
185
190
|
* Stalled states keep the active-stage cell count and render a plain
|
|
186
191
|
* "stalled" label. Invalid states surface the read-reason verbatim as a
|
|
@@ -202,6 +207,16 @@ function renderCompact(state, palette) {
|
|
|
202
207
|
return `${palette.compact.compacting} ${renderCompactBar(4, palette)} compacting${typeof state.triggerRatio === 'number'
|
|
203
208
|
? `${palette.inlineSeparator}${formatRatio(state.triggerRatio)}`
|
|
204
209
|
: ''}`;
|
|
210
|
+
case 'armed': {
|
|
211
|
+
// Slice 2026-09-12-compact-band-policy: NO bar. A bar is a
|
|
212
|
+
// progress claim, and a registered-but-unfired trigger has no
|
|
213
|
+
// progress to report — it is waiting for the ratio to reach the
|
|
214
|
+
// red line on its own. Say exactly that instead.
|
|
215
|
+
const now = typeof state.triggerRatio === 'number'
|
|
216
|
+
? `${palette.inlineSeparator}${formatRatio(state.triggerRatio)}`
|
|
217
|
+
: '';
|
|
218
|
+
return `${palette.compact.armed} armed${now}${palette.inlineSeparator}fires at ${formatRatio(AUTO_COMPACT_RED_LINE_RATIO)}`;
|
|
219
|
+
}
|
|
205
220
|
case 'verifying':
|
|
206
221
|
return `${palette.compact.verifying} ${renderCompactBar(6, palette)} verifying`;
|
|
207
222
|
case 'completed':
|
|
@@ -518,7 +533,14 @@ export function renderStatusLine(model, options, env) {
|
|
|
518
533
|
const compactSegment = renderCompact(model.compact, palette);
|
|
519
534
|
let line;
|
|
520
535
|
const hasCompact = compactSegment.length > 0;
|
|
521
|
-
|
|
536
|
+
// Slice 2026-09-12-compact-band-policy: `armed` is a RESTING state, not
|
|
537
|
+
// an in-flight compact. It can hold for the whole band between the
|
|
538
|
+
// auto-fire ratio and the red line, so it is appended to the normal
|
|
539
|
+
// line instead of REPLACING the skill token — hiding which skill is
|
|
540
|
+
// active for many turns would be a regression the user never asked
|
|
541
|
+
// for. Every other (genuinely in-flight) stage keeps replacing it.
|
|
542
|
+
const armedOnly = model.compact.kind === 'armed';
|
|
543
|
+
if (hasCompact && !armedOnly) {
|
|
522
544
|
// Compact state replaces the active / stale / idle skill content.
|
|
523
545
|
// `invalid-presence` still surfaces its own diagnostic when compact
|
|
524
546
|
// is also `invalid` (the compact diagnostic wins, since it's the
|
|
@@ -526,21 +548,24 @@ export function renderStatusLine(model, options, env) {
|
|
|
526
548
|
line = `${brand} ${compactSegment}${rootSuffix}`;
|
|
527
549
|
}
|
|
528
550
|
else {
|
|
551
|
+
let base;
|
|
529
552
|
switch (model.state) {
|
|
530
553
|
case 'active':
|
|
531
|
-
|
|
554
|
+
base = renderActive(model.presence, palette, nowMs, capability, noColor, model.activeLeaf, model.twentyFourHourState);
|
|
532
555
|
break;
|
|
533
556
|
case 'stale':
|
|
534
|
-
|
|
557
|
+
base = renderStale(model.presence, model.ageMs, palette, capability, noColor);
|
|
535
558
|
break;
|
|
536
559
|
case 'invalid-presence':
|
|
537
|
-
|
|
560
|
+
base = renderInvalid(palette);
|
|
538
561
|
break;
|
|
539
562
|
case 'idle':
|
|
540
563
|
default:
|
|
541
|
-
|
|
564
|
+
base = renderIdle(palette);
|
|
542
565
|
break;
|
|
543
566
|
}
|
|
567
|
+
const armedSuffix = armedOnly ? `${palette.inlineSeparator}${compactSegment}` : '';
|
|
568
|
+
line = `${brand} ${base}${armedSuffix}${rootSuffix}`;
|
|
544
569
|
}
|
|
545
570
|
// Marquee is OFF for idle (and only idle). Compact states always
|
|
546
571
|
// carry the band because the compact bar IS the headline. NO_COLOR
|
|
@@ -35,6 +35,12 @@ interface CompactPalette {
|
|
|
35
35
|
readonly queued: string;
|
|
36
36
|
readonly preparing: string;
|
|
37
37
|
readonly compacting: string;
|
|
38
|
+
/**
|
|
39
|
+
* Slice 2026-09-12-compact-band-policy: a trigger is registered but no
|
|
40
|
+
* compaction is running. Rendered WITHOUT a bar — see
|
|
41
|
+
* `renderCompact` in skill-statusline-renderer.ts.
|
|
42
|
+
*/
|
|
43
|
+
readonly armed: string;
|
|
38
44
|
readonly verifying: string;
|
|
39
45
|
readonly completed: string;
|
|
40
46
|
readonly failed: string;
|
|
@@ -117,7 +117,7 @@ function buildPalette(capability, noColor) {
|
|
|
117
117
|
idleLabel: 'empty',
|
|
118
118
|
invalidMessage: 'presence unreadable',
|
|
119
119
|
compact: {
|
|
120
|
-
queued: '[', preparing: '+', compacting: '+', verifying: '+',
|
|
120
|
+
queued: '[', preparing: '+', compacting: '+', armed: '~', verifying: '+',
|
|
121
121
|
completed: '*', failed,
|
|
122
122
|
},
|
|
123
123
|
barFilled: '#',
|
|
@@ -142,6 +142,9 @@ function buildPalette(capability, noColor) {
|
|
|
142
142
|
queued: brandGlyph('◐'),
|
|
143
143
|
preparing: brandGlyph('◑'),
|
|
144
144
|
compacting: brandGlyph('◒'),
|
|
145
|
+
// Distinct from `compacting` on purpose: "waiting for the trigger"
|
|
146
|
+
// must not wear the same face as "a compact is in flight".
|
|
147
|
+
armed: brandGlyph('◔'),
|
|
145
148
|
verifying: brandGlyph('◓'),
|
|
146
149
|
completed: brandGlyph('✓'),
|
|
147
150
|
failed,
|
|
@@ -96,7 +96,8 @@ function runCommand(command, args, cwd, timeoutMs) {
|
|
|
96
96
|
cwd,
|
|
97
97
|
stdio: ['ignore', 'pipe', 'pipe'],
|
|
98
98
|
timeout: timeoutMs,
|
|
99
|
-
maxBuffer: EXEC_MAX_BUFFER_BYTES
|
|
99
|
+
maxBuffer: EXEC_MAX_BUFFER_BYTES,
|
|
100
|
+
windowsHide: true
|
|
100
101
|
}).toString('utf8');
|
|
101
102
|
return {
|
|
102
103
|
status: 'pass',
|
|
@@ -98,7 +98,8 @@ function runCodegraph(args, projectRoot) {
|
|
|
98
98
|
cwd: projectRoot,
|
|
99
99
|
stdio: ['ignore', 'pipe', 'pipe'],
|
|
100
100
|
timeout: 60_000,
|
|
101
|
-
maxBuffer: 32 * 1024 * 1024
|
|
101
|
+
maxBuffer: 32 * 1024 * 1024,
|
|
102
|
+
windowsHide: true
|
|
102
103
|
};
|
|
103
104
|
// Use `peaks codegraph` (the peaks wrapper), which adds --project support.
|
|
104
105
|
// 2026-09-10: no shell. `peaks` on Windows is a `.cmd` shim, which Node >= 20
|
|
@@ -186,7 +186,8 @@ function resolveSkipAppliedBy() {
|
|
|
186
186
|
const { execFileSync } = require('node:child_process');
|
|
187
187
|
const out = execFileSync('git', ['config', '--global', 'user.name'], {
|
|
188
188
|
encoding: 'utf8',
|
|
189
|
-
stdio: ['ignore', 'pipe', 'ignore']
|
|
189
|
+
stdio: ['ignore', 'pipe', 'ignore'],
|
|
190
|
+
windowsHide: true
|
|
190
191
|
});
|
|
191
192
|
const trimmed = out.trim();
|
|
192
193
|
if (trimmed.length > 0) {
|
|
@@ -426,7 +426,7 @@ async function gitMv(from, to, projectRoot) {
|
|
|
426
426
|
// command must be run from inside the project so it can locate
|
|
427
427
|
// .git/ (the migrate target may be a temp dir created by tests).
|
|
428
428
|
try {
|
|
429
|
-
execFileSync('git', ['mv', from, to], { cwd: projectRoot, stdio: 'pipe' });
|
|
429
|
+
execFileSync('git', ['mv', from, to], { cwd: projectRoot, stdio: 'pipe', windowsHide: true });
|
|
430
430
|
}
|
|
431
431
|
catch {
|
|
432
432
|
throw error;
|
|
@@ -24,22 +24,56 @@ function readTextIfPresent(filePath) {
|
|
|
24
24
|
}
|
|
25
25
|
}
|
|
26
26
|
/**
|
|
27
|
-
* The
|
|
28
|
-
* is malformed or
|
|
29
|
-
* must not stop the materialization.
|
|
27
|
+
* The parsed top-level object of a serialized settings file, or `undefined`
|
|
28
|
+
* when the file is malformed or is not a JSON object. Tolerant on purpose: a
|
|
29
|
+
* bad on-disk file must not stop the materialization.
|
|
30
30
|
*/
|
|
31
|
-
function
|
|
31
|
+
function readSettingsObject(serialized) {
|
|
32
32
|
try {
|
|
33
33
|
const parsed = JSON.parse(serialized);
|
|
34
34
|
if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed))
|
|
35
35
|
return undefined;
|
|
36
|
-
|
|
37
|
-
return typeof env === 'object' && env !== null && !Array.isArray(env) ? env : undefined;
|
|
36
|
+
return parsed;
|
|
38
37
|
}
|
|
39
38
|
catch {
|
|
40
39
|
return undefined;
|
|
41
40
|
}
|
|
42
41
|
}
|
|
42
|
+
/** The `env` object of a serialized settings file, or `undefined`. */
|
|
43
|
+
function readEnvObject(serialized) {
|
|
44
|
+
const env = readSettingsObject(serialized)?.env;
|
|
45
|
+
return typeof env === 'object' && env !== null && !Array.isArray(env) ? env : undefined;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* The top-level keys this function's template is allowed to DECIDE. Every other
|
|
49
|
+
* key on disk belongs to whoever put it there and is carried across verbatim.
|
|
50
|
+
*
|
|
51
|
+
* - `hooks` — the tree this function exists to keep in sync. `peaks workspace
|
|
52
|
+
* init` is the writer that converges a consumer's file on the current
|
|
53
|
+
* release's handler set, and `templateContentMatches` (the drift detector
|
|
54
|
+
* that decides whether to rewrite at all) compares exactly this tree. Letting
|
|
55
|
+
* the disk win here would make the rewrite a no-op that reports `refreshed`
|
|
56
|
+
* forever.
|
|
57
|
+
* - `env` — jointly owned with `peaks hooks install`, which unions the user's
|
|
58
|
+
* exemption globs into it. Handled as a union below, not by either side
|
|
59
|
+
* winning outright.
|
|
60
|
+
*
|
|
61
|
+
* This is deliberately an owned-key LIST and not a preserved-key whitelist: the
|
|
62
|
+
* direction matters. A whitelist drops every key it was not told about — which
|
|
63
|
+
* is how `permissions` was lost — whereas anything absent from this list is
|
|
64
|
+
* preserved by default, including keys no release of peaks-loop knows about.
|
|
65
|
+
*/
|
|
66
|
+
const TEMPLATE_OWNED_KEYS = new Set(['hooks', 'env']);
|
|
67
|
+
/** `template`'s own keys, then every on-disk key the template does not own. */
|
|
68
|
+
function carryUserOwnedKeys(onDisk, template) {
|
|
69
|
+
const merged = { ...template };
|
|
70
|
+
for (const [key, value] of Object.entries(onDisk)) {
|
|
71
|
+
if (TEMPLATE_OWNED_KEYS.has(key))
|
|
72
|
+
continue;
|
|
73
|
+
merged[key] = value;
|
|
74
|
+
}
|
|
75
|
+
return merged;
|
|
76
|
+
}
|
|
43
77
|
/**
|
|
44
78
|
* The peaks-managed snippet appended to the consumer project's
|
|
45
79
|
* `.peaks/.gitignore` so the local-only settings file never lands
|
|
@@ -102,8 +136,18 @@ export async function materializeClaudeSettingsLocal(projectRoot, noClaudeHooks)
|
|
|
102
136
|
// the rewrite this function is about to do, or a refresh would silently
|
|
103
137
|
// drop someone else's exemptions. The template's own row is added on top, so
|
|
104
138
|
// the result is a union either way.
|
|
139
|
+
//
|
|
140
|
+
// The same argument applies to every OTHER top-level key on disk, which the
|
|
141
|
+
// rewrite used to drop wholesale: `{ ...template }` emitted only the keys the
|
|
142
|
+
// template declares, so a user's `permissions.allow`, `statusLine`, `model`,
|
|
143
|
+
// … were deleted by an init that had no opinion about them. The user's
|
|
144
|
+
// permission rules are not this function's to remove, and the removal was
|
|
145
|
+
// silent — the envelope reported only `refreshed`. See `carryUserOwnedKeys`
|
|
146
|
+
// for which keys the template still decides.
|
|
147
|
+
const onDisk = existing === undefined ? undefined : readSettingsObject(existing);
|
|
105
148
|
const onDiskEnv = existing === undefined ? undefined : readEnvObject(existing);
|
|
106
|
-
const
|
|
149
|
+
const merged = onDisk === undefined ? template : carryUserOwnedKeys(onDisk, template);
|
|
150
|
+
const serialized = JSON.stringify(withExternalGateExemptions(onDiskEnv === undefined ? merged : { ...merged, env: onDiskEnv }), null, 2) + '\n';
|
|
107
151
|
// Always drop (or self-heal) a copy of the template under .peaks/
|
|
108
152
|
// so the --no-claude-hooks recovery flow has a known source-of-truth
|
|
109
153
|
// on disk. The file is gitignored by the snippet below.
|
|
@@ -6,6 +6,7 @@ import { getSessionIdCanonical, setCurrentSessionBinding, setSessionMeta } from
|
|
|
6
6
|
import { updateCallerBindingSessionId } from '../session/caller-binding-service.js';
|
|
7
7
|
import { resolveCallerProjection } from '../session/resolve-caller-id.js';
|
|
8
8
|
import { normalizePath } from '../../shared/path-utils.js';
|
|
9
|
+
import { assertWritableProjectRoot } from '../config/config-safety.js';
|
|
9
10
|
/**
|
|
10
11
|
* Slice 2026-09-10 (rid=rebind-must-update-caller-binding): repoint the
|
|
11
12
|
* calling process's own per-caller binding at the session id this init just
|
|
@@ -180,6 +181,13 @@ export function validateSessionId(sessionId) {
|
|
|
180
181
|
}
|
|
181
182
|
export async function initWorkspace(options) {
|
|
182
183
|
validateSessionId(options.sessionId);
|
|
184
|
+
// Before anything is created: a project tree must never be materialized into
|
|
185
|
+
// the user's home directory. `--project .` from a fresh terminal (whose cwd
|
|
186
|
+
// is `$HOME`) resolved to `$HOME` and did exactly that — `.peaks/`,
|
|
187
|
+
// `.gitignore`, `.claude/settings.local.json` and a codegraph index, all in
|
|
188
|
+
// the user's home. Enforced here as well as at the CLI so a non-CLI caller
|
|
189
|
+
// (`peaks upgrade`) cannot reach the same write by another door.
|
|
190
|
+
assertWritableProjectRoot(options.projectRoot);
|
|
183
191
|
// Phase 6 refactor (slice 2026-06-05-change-id-as-unit-of-work) +
|
|
184
192
|
// slice 006 (2026-06-06-change-folder-simplify-and-lazy-role-subdirs) +
|
|
185
193
|
// slice 2026-06-22-top-level-change-id-cleanup (2.8.3):
|
|
@@ -14,8 +14,9 @@ export function removeRegisteredWorktree(input) {
|
|
|
14
14
|
execFileSync('git', ['worktree', 'remove', '--force', input.worktreePath], {
|
|
15
15
|
cwd: input.projectRoot,
|
|
16
16
|
stdio: ['ignore', 'pipe', 'pipe'],
|
|
17
|
+
windowsHide: true,
|
|
17
18
|
});
|
|
18
|
-
execFileSync('git', ['worktree', 'prune'], { cwd: input.projectRoot, stdio: 'ignore' });
|
|
19
|
+
execFileSync('git', ['worktree', 'prune'], { cwd: input.projectRoot, stdio: 'ignore', windowsHide: true });
|
|
19
20
|
return { removed: !existsSync(input.worktreePath), strategy: 'git' };
|
|
20
21
|
}
|
|
21
22
|
catch (error) {
|
|
@@ -24,7 +25,7 @@ export function removeRegisteredWorktree(input) {
|
|
|
24
25
|
}
|
|
25
26
|
try {
|
|
26
27
|
rmSync(windowsLongPath(input.worktreePath), { recursive: true, force: true, maxRetries: 3, retryDelay: 100 });
|
|
27
|
-
execFileSync('git', ['worktree', 'prune'], { cwd: input.projectRoot, stdio: 'ignore' });
|
|
28
|
+
execFileSync('git', ['worktree', 'prune'], { cwd: input.projectRoot, stdio: 'ignore', windowsHide: true });
|
|
28
29
|
return { removed: !existsSync(input.worktreePath), strategy: 'windows-long-path' };
|
|
29
30
|
}
|
|
30
31
|
catch (fallbackError) {
|
package/dist/shared/process.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { execFile } from 'node:child_process';
|
|
2
2
|
export async function execCommand(command, args, options) {
|
|
3
3
|
return new Promise((resolve, reject) => {
|
|
4
|
-
execFile(command, args, { cwd: options?.cwd, env: options?.env }, (error, stdout) => {
|
|
4
|
+
execFile(command, args, { cwd: options?.cwd, env: options?.env, windowsHide: true }, (error, stdout) => {
|
|
5
5
|
if (error) {
|
|
6
6
|
reject(error);
|
|
7
7
|
return;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "peaks-loop",
|
|
3
|
-
"version": "4.0.
|
|
3
|
+
"version": "4.0.47",
|
|
4
4
|
"description": "Loop Engineering CLI — workflow primitive / loop guards / evaluators / slice orchestration",
|
|
5
5
|
"author": "SquabbyZ",
|
|
6
6
|
"keywords": [
|
|
@@ -102,10 +102,10 @@
|
|
|
102
102
|
"picomatch": "4.0.4",
|
|
103
103
|
"yaml": "^2.9.0",
|
|
104
104
|
"zod": "^4.4.3",
|
|
105
|
-
"peaks-loop-
|
|
106
|
-
"peaks-loop-shared
|
|
107
|
-
"peaks-loop-
|
|
108
|
-
"peaks-loop-shared": "0.0.
|
|
105
|
+
"peaks-loop-internal-runtime": "0.0.32",
|
|
106
|
+
"peaks-loop-shared": "0.0.81",
|
|
107
|
+
"peaks-loop-mut": "0.1.45",
|
|
108
|
+
"peaks-loop-shared-channel": "0.0.49"
|
|
109
109
|
},
|
|
110
110
|
"devDependencies": {
|
|
111
111
|
"@changesets/cli": "2.31.1",
|
package/scripts/watch.mjs
CHANGED
|
@@ -30,7 +30,9 @@ export function runCommand(command, args, options = {}) {
|
|
|
30
30
|
let child;
|
|
31
31
|
|
|
32
32
|
try {
|
|
33
|
-
|
|
33
|
+
// `windowsHide` is a default, not a lock: a caller that passes its own
|
|
34
|
+
// value in `options` still wins, because the spread comes after it.
|
|
35
|
+
child = spawn(command, args, { stdio: 'inherit', windowsHide: true, ...options });
|
|
34
36
|
} catch (error) {
|
|
35
37
|
rejectPromise(error);
|
|
36
38
|
return;
|
|
@@ -12,7 +12,7 @@ metadata:
|
|
|
12
12
|
- schema: .peaks/project-scan/audit-output-schema.md
|
|
13
13
|
---
|
|
14
14
|
|
|
15
|
-
<!-- peaks:loop-hygiene —
|
|
15
|
+
<!-- peaks:loop-hygiene — HAND-MAINTAINED block, NOT generated; byte-identical in every SKILL.md, enforced by tests/unit/skills/loop-hygiene-block.test.ts. Edit one, edit all 22. -->
|
|
16
16
|
|
|
17
17
|
## Loop hygiene (every turn — MANDATORY)
|
|
18
18
|
|
|
@@ -8,7 +8,7 @@ description: |
|
|
|
8
8
|
visibility: internal
|
|
9
9
|
---
|
|
10
10
|
|
|
11
|
-
<!-- peaks:loop-hygiene —
|
|
11
|
+
<!-- peaks:loop-hygiene — HAND-MAINTAINED block, NOT generated; byte-identical in every SKILL.md, enforced by tests/unit/skills/loop-hygiene-block.test.ts. Edit one, edit all 22. -->
|
|
12
12
|
|
|
13
13
|
## Loop hygiene (every turn — MANDATORY)
|
|
14
14
|
|
|
@@ -8,7 +8,7 @@ description: |
|
|
|
8
8
|
visibility: internal
|
|
9
9
|
---
|
|
10
10
|
|
|
11
|
-
<!-- peaks:loop-hygiene —
|
|
11
|
+
<!-- peaks:loop-hygiene — HAND-MAINTAINED block, NOT generated; byte-identical in every SKILL.md, enforced by tests/unit/skills/loop-hygiene-block.test.ts. Edit one, edit all 22. -->
|
|
12
12
|
|
|
13
13
|
## Loop hygiene (every turn — MANDATORY)
|
|
14
14
|
|
|
@@ -298,4 +298,4 @@ QA contracts to assert on the L2 surface (a minimal acceptance test set):
|
|
|
298
298
|
|
|
299
299
|
## Sub-role detached mode (Phase C, slice 2026-08-10)
|
|
300
300
|
|
|
301
|
-
QA sub-roles (`qa-business`, `qa-perf`, `qa-security`, `qa-business-api`, `qa-business-frontend`, `qa-business-regression`) accept `--mode detached --vendor <vendor>` for parallel test-case execution. Detached mode spawns a real OS process via `peaks sub-agent dispatch --mode detached`, isolated from the orchestrator session. Use detached mode when the test-case writer's expected runtime exceeds 60s OR it processes ≥ 20 source files. The default remains `in-process` (backward compat; existing 106+ dispatch tests untouched). When `--mode detached` is used, the child QA agent receives the
|
|
301
|
+
QA sub-roles (`qa-business`, `qa-perf`, `qa-security`, `qa-business-api`, `qa-business-frontend`, `qa-business-regression`) accept `--mode detached --vendor <vendor>` for parallel test-case execution. Detached mode spawns a real OS process via `peaks sub-agent dispatch --mode detached`, isolated from the orchestrator session. Use detached mode when the test-case writer's expected runtime exceeds 60s OR it processes ≥ 20 source files. The default remains `in-process` (backward compat; existing 106+ dispatch tests untouched). When `--mode detached` is used, the child QA agent receives the `<peaks-auto-compact>` marker (corrected 2026-09-13, rid `2026-09-13-defects-e`): it asks the child to persist durable state to `.peaks/_runtime/<sid>/detached/<rid>/compact/<n>.json` before its own harness compacts the session — the child cannot compact itself, and nothing is spliced back into its prompt. See `peaks-code/references/sub-agent-dispatch.md` §"Detached Mode" for the full contract.
|
|
@@ -9,7 +9,7 @@ description: |
|
|
|
9
9
|
visibility: internal
|
|
10
10
|
---
|
|
11
11
|
|
|
12
|
-
<!-- peaks:loop-hygiene —
|
|
12
|
+
<!-- peaks:loop-hygiene — HAND-MAINTAINED block, NOT generated; byte-identical in every SKILL.md, enforced by tests/unit/skills/loop-hygiene-block.test.ts. Edit one, edit all 22. -->
|
|
13
13
|
|
|
14
14
|
## Loop hygiene (every turn — MANDATORY)
|
|
15
15
|
|
|
@@ -187,7 +187,7 @@ Full dispatch contract (when-to-fan-out rules, dispatch template, prereq gates)
|
|
|
187
187
|
|
|
188
188
|
## Reviewer fan-out detached mode (Phase C, slice 2026-08-10)
|
|
189
189
|
|
|
190
|
-
Reviewer fan-out may run in detached mode for any of the 3-way fan-out roles (`code-reviewer`, `qa-test-cases-writer`, `karpathy-reviewer`). Detached mode spawns a real OS process via `peaks sub-agent dispatch --mode detached --vendor <vendor>`, isolated from the orchestrator session. Use detached mode when the reviewer's expected runtime exceeds 60s OR processes ≥ 20 source files. Pass `--mode detached` explicitly per reviewer role; the default remains `in-process` (backward compat). The karpathy-reviewer's
|
|
190
|
+
Reviewer fan-out may run in detached mode for any of the 3-way fan-out roles (`code-reviewer`, `qa-test-cases-writer`, `karpathy-reviewer`). Detached mode spawns a real OS process via `peaks sub-agent dispatch --mode detached --vendor <vendor>`, isolated from the orchestrator session. Use detached mode when the reviewer's expected runtime exceeds 60s OR processes ≥ 20 source files. Pass `--mode detached` explicitly per reviewer role; the default remains `in-process` (backward compat). The karpathy-reviewer's `<peaks-auto-compact>` marker is honored automatically when `--mode detached` is used. Note what that marker does and does not do (corrected 2026-09-13, rid `2026-09-13-defects-e`): it asks the child to persist durable state to `.peaks/_runtime/<sid>/detached/<rid>/compact/<n>.json` before its own harness compacts the session — the child cannot compact itself, and nothing is spliced back into its prompt. See `peaks-code/references/sub-agent-dispatch.md` §"Detached Mode" for the full contract.
|
|
191
191
|
|
|
192
192
|
## Refactor hard gates
|
|
193
193
|
|
|
@@ -4,7 +4,7 @@ visibility: internal
|
|
|
4
4
|
description: Third-party independent code-review skill for Peaks. Use as a parallel reviewer to karpathy-reviewer when a workflow needs an out-of-band (non-RD-model) review pass to mitigate single-LLM self-dogfood blind spots. Emits a schema-validated ReviewerEnvelope (no free-form LLM JSON). v2.14.0 G4.
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
<!-- peaks:loop-hygiene —
|
|
7
|
+
<!-- peaks:loop-hygiene — HAND-MAINTAINED block, NOT generated; byte-identical in every SKILL.md, enforced by tests/unit/skills/loop-hygiene-block.test.ts. Edit one, edit all 22. -->
|
|
8
8
|
|
|
9
9
|
## Loop hygiene (every turn — MANDATORY)
|
|
10
10
|
|
|
@@ -8,7 +8,7 @@ description: |
|
|
|
8
8
|
visibility: internal
|
|
9
9
|
---
|
|
10
10
|
|
|
11
|
-
<!-- peaks:loop-hygiene —
|
|
11
|
+
<!-- peaks:loop-hygiene — HAND-MAINTAINED block, NOT generated; byte-identical in every SKILL.md, enforced by tests/unit/skills/loop-hygiene-block.test.ts. Edit one, edit all 22. -->
|
|
12
12
|
|
|
13
13
|
## Loop hygiene (every turn — MANDATORY)
|
|
14
14
|
|
|
@@ -12,7 +12,7 @@ metadata:
|
|
|
12
12
|
- schema: .peaks/project-scan/audit-output-schema.md
|
|
13
13
|
---
|
|
14
14
|
|
|
15
|
-
<!-- peaks:loop-hygiene —
|
|
15
|
+
<!-- peaks:loop-hygiene — HAND-MAINTAINED block, NOT generated; byte-identical in every SKILL.md, enforced by tests/unit/skills/loop-hygiene-block.test.ts. Edit one, edit all 22. -->
|
|
16
16
|
|
|
17
17
|
## Loop hygiene (every turn — MANDATORY)
|
|
18
18
|
|
|
@@ -8,7 +8,7 @@ description: |
|
|
|
8
8
|
visibility: internal
|
|
9
9
|
---
|
|
10
10
|
|
|
11
|
-
<!-- peaks:loop-hygiene —
|
|
11
|
+
<!-- peaks:loop-hygiene — HAND-MAINTAINED block, NOT generated; byte-identical in every SKILL.md, enforced by tests/unit/skills/loop-hygiene-block.test.ts. Edit one, edit all 22. -->
|
|
12
12
|
|
|
13
13
|
## Loop hygiene (every turn — MANDATORY)
|
|
14
14
|
|
|
@@ -8,7 +8,7 @@ description: |
|
|
|
8
8
|
visibility: internal
|
|
9
9
|
---
|
|
10
10
|
|
|
11
|
-
<!-- peaks:loop-hygiene —
|
|
11
|
+
<!-- peaks:loop-hygiene — HAND-MAINTAINED block, NOT generated; byte-identical in every SKILL.md, enforced by tests/unit/skills/loop-hygiene-block.test.ts. Edit one, edit all 22. -->
|
|
12
12
|
|
|
13
13
|
## Loop hygiene (every turn — MANDATORY)
|
|
14
14
|
|
|
@@ -3,7 +3,7 @@ name: peaks-audit
|
|
|
3
3
|
description: Gate autonomous LLM work on a 6-dimension audit + user-accepted goal. Use IMMEDIATELY after a need is expressed, BEFORE any PRD/RD/QA work starts.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
<!-- peaks:loop-hygiene —
|
|
6
|
+
<!-- peaks:loop-hygiene — HAND-MAINTAINED block, NOT generated; byte-identical in every SKILL.md, enforced by tests/unit/skills/loop-hygiene-block.test.ts. Edit one, edit all 22. -->
|
|
7
7
|
|
|
8
8
|
## Loop hygiene (every turn — MANDATORY)
|
|
9
9
|
|
|
@@ -3,7 +3,7 @@ name: peaks-code
|
|
|
3
3
|
description: Code-domain loop engineering orchestrator for the Peaks-Loop skill family. Use when the user asks Peaks-Loop to handle a code-repo workflow end-to-end (端到端/全流程/需求开发), especially from a product document (PRD/飞书文档/Feishu doc) through implementation and validation. Coordinates peaks-prd, peaks-rd, peaks-qa, peaks-ui, peaks-sc, and peaks-txt while preserving user confirmation gates. Triggers on `/peaks-code`, "peaks code", "全流程开发", "端到端迭代". General primitives (peaks-resume / peaks-status / peaks-test) are sibling skills, not children.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
<!-- peaks:loop-hygiene —
|
|
6
|
+
<!-- peaks:loop-hygiene — HAND-MAINTAINED block, NOT generated; byte-identical in every SKILL.md, enforced by tests/unit/skills/loop-hygiene-block.test.ts. Edit one, edit all 22. -->
|
|
7
7
|
|
|
8
8
|
## Loop hygiene (every turn — MANDATORY)
|
|
9
9
|
|
|
@@ -37,7 +37,7 @@ of ~30 minutes clears the gate's "already passed" list, so a file you cleared ea
|
|
|
37
37
|
denied again after a long pause. That is the gate resetting, not you regressing.
|
|
38
38
|
<!-- /peaks:loop-hygiene -->
|
|
39
39
|
|
|
40
|
-
> **Detached sub-agent mode (Phase A, slice 2026-08-10).** When the orchestrator requires true parallelism with isolated context windows and survives orchestrator session exit, dispatch sub-agents with `--mode detached --vendor <claude|codex|copilot>`. The CLI spawns a real OS process via `ProcessSupervisor` (Windows `DETACHED_PROCESS` + `CREATE_NEW_PROCESS_GROUP`, POSIX `setsid` + `nohup`); the child vendor LLM receives a 5–8KB minimum prompt slice (no orchestrator session history) and
|
|
40
|
+
> **Detached sub-agent mode (Phase A, slice 2026-08-10).** When the orchestrator requires true parallelism with isolated context windows and survives orchestrator session exit, dispatch sub-agents with `--mode detached --vendor <claude|codex|copilot>`. The CLI spawns a real OS process via `ProcessSupervisor` (Windows `DETACHED_PROCESS` + `CREATE_NEW_PROCESS_GROUP`, POSIX `setsid` + `nohup`); the child vendor LLM receives a 5–8KB minimum prompt slice (no orchestrator session history) and, via the `<peaks-auto-compact>` marker, is told to persist durable state to `.peaks/_runtime/<sid>/detached/<rid>/compact/<n>.json` before its own harness compacts the session (G8, corrected 2026-09-13 rid `2026-09-13-defects-e`: the child cannot compact itself and nothing is spliced back into its prompt; peaks runtime simply has no token-cost throttle, which is not the same as a granted budget). Orchestrator MUST emit one line of prose before every detached dispatch: `⏳ Spawning detached sub-agent via <vendor>: rid=<rid> (ETA ~60s)`. Status is read from `.peaks/_runtime/<sid>/detached/<rid>/status.json`; `LifecycleOwner` enforces 100% cleanup of `pid` / `log.txt` / `status.json` / `owner-session` on every exit path. `--no-throttle --max-concurrent <N>` bypasses `ResourceBudgetGuard` (user accepts risk; default max=8). See `references/sub-agent-dispatch.md` §"Detached Mode" for the full contract. Default mode remains `in-process` for backward compat (existing 106+ dispatch tests untouched).
|
|
41
41
|
---
|
|
42
42
|
|
|
43
43
|
## Scope (RL-8 — red line, locked 2026-07-08)
|
|
@@ -185,7 +185,7 @@ Before the first planning action, run `peaks fresh-context preflight --prompt "<
|
|
|
185
185
|
1. **PreToolUse hook — `peaks code gate-step-08`.** Installed by `peaks workspace init` on the `Bash` matcher; checks `job-shape.json` presence + fail-closed backup regex. If `job-shape.json` AND `progress.json` exist, surfaces `Next: slice #N of M (<currentSlice>)` so the LLM cannot wake up cold.
|
|
186
186
|
2. **Size-fear ban — `peaks code emit-handoff`.** Refuses to emit a final handoff while `remaining > 0` under Job mode. Pass `--force-under-job` only with explicit user approval.
|
|
187
187
|
3. **On-disk slice progress — `peaks job progress`.** `peaks job checkpoint --state done` writes `progress.json`. `peaks job progress --job-id <jid> [--allow-missing]` is the canonical reader.
|
|
188
|
-
4. **Forced auto-compact —
|
|
188
|
+
4. **Forced auto-compact — `peaks code context-now`.** It returns `action: 'auto-compact-now'` at ≥ 0.85. **≥ 0.85 is MANDATORY auto-compact in every mode (single-rid included)** — Code MUST call `peaks code auto-compact` without confirmation. `--enforce-job-mode` (v3.1.2) only labels the run `jobMode=true`; the ≥ 0.85 downgrade that used to apply to single-rid sessions was removed 2026-09-12.
|
|
189
189
|
|
|
190
190
|
**Step 0.7 resume rule (read-FIRST):** on resume, `peaks code gate-step-08` reads `progress.json` first and surfaces `Next: slice #N of M (<currentSlice>)` so the orchestrator picks up at the right slice without re-reading the artifact tree.
|
|
191
191
|
|
|
@@ -209,7 +209,7 @@ Before the first planning action, run `peaks fresh-context preflight --prompt "<
|
|
|
209
209
|
|
|
210
210
|
**Enforcement layers (defense in depth):**
|
|
211
211
|
1. `src/services/code/auto-compact-orchestrator.ts` — `evaluateAutoCompactDecision` default-returns `shouldCompact: true` for both `pre-compact` and `red-line`. Only deferral is `inFlightBatch.hasInFlightBatch` (D6.e); no LLM/human approval branch.
|
|
212
|
-
2. `--enforce-job-mode`
|
|
212
|
+
2. `peaks code context-now` — ≥ 0.85 is MANDATORY (`auto-compact-now`) in every mode; `--enforce-job-mode` no longer gates that (2026-09-12). Only an in-flight sub-agent batch defers it.
|
|
213
213
|
3. `peaks code gate-step-08` (PreToolUse hook) — surfaces `auto-compact-now` on every Bash call when ratio is in the zone, so the LLM cannot wake up cold and forget.
|
|
214
214
|
4. Karpathy §4 exception: `peaks code auto-compact` is fired *by the orchestrator*, not by the user. If you find yourself about to write "ask the user to compact" / "prompt the user to run `/compact`", STOP — that is the regression.
|
|
215
215
|
|
|
@@ -449,7 +449,7 @@ peaks skill presence:set peaks-code --project <repo> --mode <mode> --gate swarm-
|
|
|
449
449
|
|
|
450
450
|
- **Cross-platform spawn**: Windows uses `DETACHED_PROCESS` + `CREATE_NEW_PROCESS_GROUP`; POSIX uses `setsid` + `nohup`. Implementation: `packages/peaks-loop-internal-runtime/src/process-supervisor.ts`.
|
|
451
451
|
- **Minimum-context prompt**: `PromptBuilder` emits a 5–8KB slice `{rid, role, vendor, files, refs}` plus the verbatim `<peaks-auto-compact>` marker. The forbidden marker `@@@ORCHESTRATOR_SESSION_HISTORY_BOUNDARY@@@` MUST NOT appear in any prompt (unit-tested; regression fails vitest).
|
|
452
|
-
- **G8 infinite context**: the child
|
|
452
|
+
- **G8 infinite context (corrected 2026-09-13, rid `2026-09-13-defects-e`)**: the child does **not** and **cannot** compact its own session. `/compact` is not model-invokable, hooks may only observe or veto, there is no `--compact` flag, and no external process can reach a running session's memory — compaction is the child's own harness acting on its own window. What the `<peaks-auto-compact>` marker actually asks for is the reachable half: write the durable state (summary / task state / decisions kept / options discarded) to `.peaks/_runtime/<sid>/detached/<rid>/compact/<n>.json` and heartbeat to `status.json`, so nothing load-bearing lives only in a conversation that will be summarised. Nothing flows back into the child's context — its prompt is the `-p` argv string fixed at spawn. Token cost: peaks runtime has no token-cost throttle to relax (the only guard, `ResourceBudgetGuard`, throttles RSS / CPU / fan-out, never spend), so there is no cost cap — but that is an absence of throttling, not a granted permission with a flag behind it.
|
|
453
453
|
- **Lifecycle closure invariant**: `pid` / `log.txt` / `status.json` / `owner-session` 100% cleaned on every exit path (success / crash / OOM / SIGTERM). `peaks sub-agent cleanup --orphan` is the only orphan-killing path (RL-15: user-only decision; default is "do nothing").
|
|
454
454
|
- **Resource budget guard**: `ResourceBudgetGuard` enforces `runtime RSS ≤ 200MB / idle CPU ≤ 5% / fan-out ≤ 8 (default)`. `--no-throttle` bypasses (user accepts risk; adds warning to envelope). `--max-concurrent <N>` overrides the 8 default.
|
|
455
455
|
- **Vendor-neutral**: `VendorAdapterRegistry` registers `ClaudeAdapter` (Phase A) / `CodexAdapter` + `CopilotAdapter` (Phase B). Missing vendor CLI → fallback to default with `dispatchRecord.warning = 'vendor fallback: <id>→claude'`.
|
|
@@ -3,7 +3,7 @@ name: peaks-content
|
|
|
3
3
|
description: Non-code orchestrator for content workflows (draft / edit / publish / archive). Use when a user wants to drive an end-to-end content-production loop (blog post, newsletter, marketing copy, social thread, doc page) where the LLM must coordinate draft / edit / tone / publish / archive stages with explicit gates between them, and where the user only wants to speak natural language and pick options. NOT for free-form chatting; NOT for code review. Reuses the peaks-loop Loop Engineering primitives (Loop Engineering Asset, Bee Asset, Workflow Trace, Evolution Evaluation) but does NOT import peaks-code internals. Triggers on `/peaks-content`, "peaks content", "content workflow", "publish this to <channel>", "edit the draft", "archive the previous version".
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
<!-- peaks:loop-hygiene —
|
|
6
|
+
<!-- peaks:loop-hygiene — HAND-MAINTAINED block, NOT generated; byte-identical in every SKILL.md, enforced by tests/unit/skills/loop-hygiene-block.test.ts. Edit one, edit all 22. -->
|
|
7
7
|
|
|
8
8
|
## Loop hygiene (every turn — MANDATORY)
|
|
9
9
|
|
|
@@ -4,7 +4,7 @@ description: Orchestrate peaks-loop's L3 doctor (peaks audit + peaks doctor + pe
|
|
|
4
4
|
visibility: internal
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
<!-- peaks:loop-hygiene —
|
|
7
|
+
<!-- peaks:loop-hygiene — HAND-MAINTAINED block, NOT generated; byte-identical in every SKILL.md, enforced by tests/unit/skills/loop-hygiene-block.test.ts. Edit one, edit all 22. -->
|
|
8
8
|
|
|
9
9
|
## Loop hygiene (every turn — MANDATORY)
|
|
10
10
|
|
|
@@ -3,7 +3,7 @@ name: peaks-final-review
|
|
|
3
3
|
description: Final-review skill for Peaks. Use when a workflow needs to assemble 4-dimension business-review evidence (functional-completeness, problem-resolution, no-new-bugs, existing-functionality-intact) for human acceptance at the end of an autonomous slice. Triggers on "/peaks-final-review", "prepare final review", "4-dim review", or peaks-code end-of-workflow handoff.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
<!-- peaks:loop-hygiene —
|
|
6
|
+
<!-- peaks:loop-hygiene — HAND-MAINTAINED block, NOT generated; byte-identical in every SKILL.md, enforced by tests/unit/skills/loop-hygiene-block.test.ts. Edit one, edit all 22. -->
|
|
7
7
|
|
|
8
8
|
## Loop hygiene (every turn — MANDATORY)
|
|
9
9
|
|
|
@@ -4,7 +4,7 @@ description: Orchestrate peaks-loop's IDE-aware behavior (hooks + statusline + h
|
|
|
4
4
|
visibility: internal
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
<!-- peaks:loop-hygiene —
|
|
7
|
+
<!-- peaks:loop-hygiene — HAND-MAINTAINED block, NOT generated; byte-identical in every SKILL.md, enforced by tests/unit/skills/loop-hygiene-block.test.ts. Edit one, edit all 22. -->
|
|
8
8
|
|
|
9
9
|
## Loop hygiene (every turn — MANDATORY)
|
|
10
10
|
|
|
@@ -3,7 +3,7 @@ name: peaks-issue-fix-orchestrator
|
|
|
3
3
|
description: 'End-to-end orchestrator that surveys open issues in a target repo, classifies them by difficulty, mines reference merged-PRs, fixes each issue with real commits (with Repository + AI-modified declaration), writes normalized PR description files, and emits a one-line submit script. Use when the user wants to drive a "fix N open issues and prepare PRs" run on an upstream repo (any language; primarily Python + TypeScript). Reuses Loop Engineering primitives: 4-layer asset model, Darwin ratchet, karpathy-engineered red lines, Human-NL-Choice-Only. Triggers on `/peaks-issue-fix-orchestrator`, "fix 30 issues", "dogfood on <repo>", "open-issue sweep on <repo>".'
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
<!-- peaks:loop-hygiene —
|
|
6
|
+
<!-- peaks:loop-hygiene — HAND-MAINTAINED block, NOT generated; byte-identical in every SKILL.md, enforced by tests/unit/skills/loop-hygiene-block.test.ts. Edit one, edit all 22. -->
|
|
7
7
|
|
|
8
8
|
## Loop hygiene (every turn — MANDATORY)
|
|
9
9
|
|