peaks-loop 4.0.49 → 4.0.51
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 +38 -0
- package/README-en.md +1 -1
- package/README.md +1 -1
- package/dist/cli/commands/audit-commands.js +1 -0
- package/dist/cli/commands/baseline-commands.js +163 -25
- package/dist/cli/commands/core/skill-command.js +53 -4
- package/dist/cli/commands/core/standards-command.d.ts +24 -0
- package/dist/cli/commands/core/standards-command.js +74 -0
- package/dist/cli/commands/hooks-commands.js +55 -38
- package/dist/cli/commands/share-commands.js +113 -20
- package/dist/cli/commands/web-commands.js +8 -1
- package/dist/cli/commands/workflow-lifecycle-commands.d.ts +6 -0
- package/dist/cli/commands/workflow-lifecycle-commands.js +64 -3
- package/dist/services/adapter/adapter.d.ts +30 -0
- package/dist/services/adapter/auto-adapter.d.ts +13 -0
- package/dist/services/adapter/claude-adapter.js +12 -0
- package/dist/services/adapter/codex-adapter.d.ts +12 -0
- package/dist/services/adapter/codex-adapter.js +12 -0
- package/dist/services/adapter/copilot-adapter.d.ts +12 -0
- package/dist/services/adapter/copilot-adapter.js +12 -0
- package/dist/services/audit/backing-detector.d.ts +25 -7
- package/dist/services/audit/backing-detector.js +33 -17
- package/dist/services/audit/enforcer-liveness.d.ts +12 -0
- package/dist/services/audit/enforcer-liveness.js +100 -0
- package/dist/services/audit/enforcers/lint-catalog-governance.d.ts +23 -11
- package/dist/services/audit/enforcers/lint-catalog-governance.js +10 -14
- package/dist/services/audit/enforcers/lint-rd-handoff-coverage.d.ts +5 -15
- package/dist/services/audit/enforcers/lint-rd-handoff-coverage.js +94 -25
- package/dist/services/audit/enforcers/lint-style.d.ts +9 -1
- package/dist/services/audit/enforcers/lint-style.js +38 -2
- package/dist/services/audit/prose-ratio-calculator.d.ts +28 -17
- package/dist/services/audit/prose-ratio-calculator.js +25 -18
- package/dist/services/audit/red-line-catalog-p2-a.js +1 -1
- package/dist/services/audit/red-lines-service.js +51 -7
- package/dist/services/capability-audit-service/independent-checker.d.ts +15 -0
- package/dist/services/capability-audit-service/independent-checker.js +140 -0
- package/dist/services/capability-audit-service/index.d.ts +3 -1
- package/dist/services/capability-audit-service/index.js +1 -0
- package/dist/services/capability-audit-service/runner.d.ts +17 -13
- package/dist/services/capability-audit-service/runner.js +76 -15
- package/dist/services/capability-audit-service/types.d.ts +48 -0
- package/dist/services/capability-guard-runner/contracts/J01.js +21 -22
- package/dist/services/capability-guard-runner/contracts/J02.d.ts +1 -1
- package/dist/services/capability-guard-runner/contracts/J02.js +114 -28
- package/dist/services/capability-guard-runner/contracts/J03.d.ts +13 -0
- package/dist/services/capability-guard-runner/contracts/J03.js +72 -21
- package/dist/services/capability-guard-runner/contracts/J04.d.ts +6 -0
- package/dist/services/capability-guard-runner/contracts/J04.js +65 -32
- package/dist/services/capability-guard-runner/contracts/J05.js +118 -16
- package/dist/services/capability-guard-runner/contracts/J06.d.ts +14 -0
- package/dist/services/capability-guard-runner/contracts/J06.js +57 -39
- package/dist/services/capability-guard-runner/contracts/J07.d.ts +9 -0
- package/dist/services/capability-guard-runner/contracts/J07.js +76 -47
- package/dist/services/capability-guard-runner/contracts/J08.d.ts +11 -0
- package/dist/services/capability-guard-runner/contracts/J08.js +66 -39
- package/dist/services/capability-guard-runner/contracts/J09.d.ts +13 -0
- package/dist/services/capability-guard-runner/contracts/J09.js +95 -39
- package/dist/services/capability-guard-runner/contracts/J10.d.ts +12 -0
- package/dist/services/capability-guard-runner/contracts/J10.js +69 -35
- package/dist/services/capability-guard-runner/contracts/J11.d.ts +8 -0
- package/dist/services/capability-guard-runner/contracts/J11.js +73 -33
- package/dist/services/capability-guard-runner/contracts/J12.d.ts +12 -0
- package/dist/services/capability-guard-runner/contracts/J12.js +66 -30
- package/dist/services/capability-guard-runner/contracts/J13.d.ts +11 -0
- package/dist/services/capability-guard-runner/contracts/J13.js +62 -40
- package/dist/services/capability-guard-runner/contracts/J14.d.ts +11 -0
- package/dist/services/capability-guard-runner/contracts/J14.js +60 -31
- package/dist/services/capability-guard-runner/contracts/J15.d.ts +11 -0
- package/dist/services/capability-guard-runner/contracts/J15.js +70 -35
- package/dist/services/capability-guard-runner/contracts/_shared.d.ts +24 -0
- package/dist/services/capability-guard-runner/contracts/_shared.js +67 -0
- package/dist/services/capability-guard-runner/registry.d.ts +5 -0
- package/dist/services/capability-guard-runner/registry.js +140 -0
- package/dist/services/capability-guard-runner/runner.d.ts +26 -0
- package/dist/services/capability-guard-runner/runner.js +63 -6
- package/dist/services/code/auto-compact-modes.d.ts +13 -2
- package/dist/services/code/auto-compact-modes.js +20 -4
- package/dist/services/code/post-compact-detector.js +20 -11
- package/dist/services/code/step-08-gate.js +21 -6
- package/dist/services/config/config-safety.js +11 -9
- package/dist/services/dispatch/sub-agent-dispatcher.d.ts +11 -30
- package/dist/services/dispatch/sub-agent-dispatcher.js +5 -48
- package/dist/services/final-review/pre-post-diff.js +10 -2
- package/dist/services/ide/adapters/claude-code-adapter.js +0 -1
- package/dist/services/ide/adapters/codex-adapter.js +1 -2
- package/dist/services/ide/adapters/cursor-adapter.js +1 -2
- package/dist/services/ide/adapters/hermes-adapter.js +1 -2
- package/dist/services/ide/adapters/openclaw-adapter.js +1 -2
- package/dist/services/ide/adapters/qoder-adapter.js +1 -2
- package/dist/services/ide/adapters/tongyi-lingma-adapter.js +1 -2
- package/dist/services/ide/adapters/trae-adapter.js +1 -2
- package/dist/services/ide/adapters/zcode-adapter.js +0 -1
- package/dist/services/ide/ide-types.d.ts +0 -2
- package/dist/services/observability/observability-service.d.ts +1 -1
- package/dist/services/scan/api-diff-types.js +20 -2
- package/dist/services/security/safe-settings-path.js +19 -1
- package/dist/services/skill/skill-search-service.d.ts +3 -3
- package/dist/services/standards/loop-engineering-lint.d.ts +1 -1
- package/dist/services/standards/loop-engineering-lint.js +6 -0
- package/dist/services/web/daemon-registry.js +27 -2
- package/dist/services/workspace/claude-settings-template.d.ts +53 -37
- package/dist/services/workspace/claude-settings-template.js +105 -83
- package/dist/services/workspace/generated-artifacts-stamp.d.ts +119 -0
- package/dist/services/workspace/generated-artifacts-stamp.js +167 -0
- package/dist/services/workspace/workspace-claude-settings-materializer.d.ts +8 -0
- package/dist/services/workspace/workspace-claude-settings-materializer.js +38 -3
- package/dist/services/workspace/workspace-service.js +11 -1
- package/dist/shared/fs-utils.d.ts +26 -0
- package/dist/shared/fs-utils.js +35 -0
- package/package.json +9 -7
- package/scripts/copy-templates.mjs +0 -12
- package/scripts/install-skills.mjs +154 -53
- package/skills/bee/peaks-perf-audit/SKILL.md +2 -2
- package/skills/bee/peaks-perf-audit/references/audit-protocol.md +1 -1
- package/skills/bee/peaks-prd/SKILL.md +3 -3
- package/skills/bee/peaks-prd/references/prd-for-multi-pass.md +1 -1
- package/skills/bee/peaks-prd/references/workflow.md +1 -1
- package/skills/bee/peaks-qa/SKILL.md +6 -7
- package/skills/bee/peaks-qa/references/external-capability-guidance.md +1 -1
- package/skills/bee/peaks-qa/references/qa-fanout-contract.md +1 -1
- package/skills/bee/peaks-qa/references/reading-handoff-frontmatter.md +2 -2
- package/skills/bee/peaks-rd/SKILL.md +2 -3
- package/skills/bee/peaks-rd/references/code-reviewer-4dim-hint.md +1 -1
- package/skills/bee/peaks-rd/references/external-references.md +1 -1
- package/skills/bee/peaks-rd/references/mandatory-perf-baseline.md +1 -1
- package/skills/bee/peaks-rd/references/ocr-multilang-1.8.md +2 -2
- package/skills/bee/peaks-rd/references/parallel-review-fanout.md +2 -2
- package/skills/bee/peaks-rd/references/rd-fanout-contracts.md +11 -8
- package/skills/bee/peaks-rd/references/rd-runbook.md +1 -1
- package/skills/bee/peaks-rd/references/rd-sub-agent-dispatch.md +7 -7
- package/skills/bee/peaks-rd/references/rd-transition-gates.md +1 -1
- package/skills/bee/peaks-rd/references/reading-v2-slice-results.md +1 -1
- package/skills/bee/peaks-rd/references/v2-12-fanout-collapse.md +7 -5
- package/skills/bee/peaks-rd/references/writing-handoff-frontmatter.md +3 -3
- package/skills/bee/peaks-reviewer/SKILL.md +1 -1
- package/skills/bee/peaks-security-audit/SKILL.md +3 -3
- package/skills/bee/peaks-security-audit/references/audit-protocol.md +1 -1
- package/skills/bee/peaks-txt/references/context-capsule.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 +20 -18
- package/skills/peaks-code/references/context-governance.md +1 -1
- package/skills/peaks-code/references/dag-orchestrator.md +3 -4
- package/skills/peaks-code/references/external-references.md +1 -1
- package/skills/peaks-code/references/external-skill-invocation.md +2 -2
- package/skills/peaks-code/references/fanout-mandatory.md +3 -3
- package/skills/peaks-code/references/frontend-only-mode.md +2 -2
- package/skills/peaks-code/references/gstack-integration.md +1 -1
- package/skills/peaks-code/references/micro-cycle.md +1 -1
- package/skills/peaks-code/references/periodic-checkpoint.md +4 -4
- package/skills/peaks-code/references/project-scan-checklist.md +1 -1
- package/skills/peaks-code/references/resume-detection.md +1 -1
- package/skills/peaks-code/references/runbook.md +6 -3
- package/skills/peaks-code/references/session-overload-signal-index.md +6 -4
- package/skills/peaks-code/references/startup-sequence.md +17 -17
- package/skills/peaks-code/references/step-0-8-gate.md +1 -1
- package/skills/peaks-code/references/step-11-memory-sediment.md +2 -2
- package/skills/peaks-code/references/sub-agent-dispatch.md +26 -25
- package/skills/peaks-code/references/swarm-dispatch-contract.md +1 -1
- package/skills/peaks-code/references/workflow-gates-and-types.md +3 -3
- package/skills/peaks-code/references/worktree-governance.md +1 -1
- package/skills/peaks-final-review/SKILL.md +3 -3
- package/skills/peaks-ide/references/audit-log-helper.md +5 -4
- package/skills/peaks-resume/SKILL.md +1 -1
- package/skills/peaks-slice-decompose/SKILL.md +4 -4
- package/skills/peaks-slice-decompose/references/cross-pass-edge-interpretation.md +1 -1
- package/skills/peaks-slice-decompose/references/granularity-decision.md +1 -1
- package/skills/peaks-slice-decompose/references/v2-schema.md +2 -2
- package/skills/peaks-solo/SKILL.md +1 -2
- package/dist/cli/commands/context-builder-commands.d.ts +0 -11
- package/dist/cli/commands/context-builder-commands.js +0 -85
- package/dist/services/hooks/write-gate.js +0 -111
- package/skills/bee/peaks-prd/references/command-migration.md +0 -3
- package/skills/bee/peaks-qa/references/command-migration.md +0 -3
- package/skills/bee/peaks-rd/references/command-migration.md +0 -3
- package/skills/bee/peaks-sc/references/command-migration.md +0 -3
- package/skills/bee/peaks-txt/references/command-migration.md +0 -3
- package/skills/bee/peaks-ui/references/command-migration.md +0 -3
- package/skills/peaks-code/references/command-migration.md +0 -3
|
@@ -173,15 +173,17 @@ export function resolveCanonicalProjectRootStrict(startPath) {
|
|
|
173
173
|
catch {
|
|
174
174
|
throw new InvalidProjectRootError('non-existent', startPath);
|
|
175
175
|
}
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
//
|
|
182
|
-
//
|
|
183
|
-
|
|
184
|
-
|
|
176
|
+
// Use the realpath form as the canonical input. macOS exposes
|
|
177
|
+
// `/var/folders/...` as a symlink to `/private/var/folders/...`, so any
|
|
178
|
+
// path returned by `os.tmpdir()` (and therefore any `mkdtempSync(...)`
|
|
179
|
+
// result) has `realStart !== start`. Rejecting that case as
|
|
180
|
+
// "non-canonical" would block the legitimate SessionStart hook path
|
|
181
|
+
// and the test fixtures under `tests/unit/hooks/`. The security
|
|
182
|
+
// property is preserved: `realpathSync` collapses any attacker-
|
|
183
|
+
// controlled symlink chain, so `realStart` IS the canonical form
|
|
184
|
+
// regardless of which prefix the caller used.
|
|
185
|
+
const canonical = resolveCanonicalProjectRoot(realStart);
|
|
186
|
+
if (canonical === realStart) {
|
|
185
187
|
return canonical;
|
|
186
188
|
}
|
|
187
189
|
// Canonicalization moved the path (e.g. to a git root) — accept it
|
|
@@ -139,22 +139,13 @@ export declare const claudeCodeSubAgentDispatcher: SubAgentDispatcher;
|
|
|
139
139
|
* stays the same; only the per-IDE wiring breaks (intentionally).
|
|
140
140
|
*/
|
|
141
141
|
export declare const traeSubAgentDispatcher: SubAgentDispatcher;
|
|
142
|
-
/**
|
|
143
|
-
* Trae-CN dispatcher. Mirrors Trae's shape with a separate label so
|
|
144
|
-
* the CLI's IDE detection can distinguish a Trae install region
|
|
145
|
-
* (Trae-CN differs in skill install path / log location only;
|
|
146
|
-
* dispatch surface is identical per slice #011 framework rule).
|
|
147
|
-
*
|
|
148
|
-
* Slice 1.3: real `awaitBatch` — same polling core as Trae.
|
|
149
|
-
*/
|
|
150
|
-
export declare const traeCnSubAgentDispatcher: SubAgentDispatcher;
|
|
151
142
|
/**
|
|
152
143
|
* Codex (OpenAI CLI IDE) dispatcher.
|
|
153
144
|
*
|
|
154
145
|
* Slice #13 noted Codex's sub-agent tool name is TBD; per slice #009
|
|
155
146
|
* rationale, the dispatcher mirrors Claude Code's shape so the
|
|
156
|
-
* adapter contract stays uniform. Slice 1.3 promotes Codex from
|
|
157
|
-
*
|
|
147
|
+
* adapter contract stays uniform. Slice 1.3 promotes Codex from the
|
|
148
|
+
* 1.2 marker to a real `awaitBatch` (file-based polling,
|
|
158
149
|
* Codex default 45s — Codex's documented heartbeat is slightly
|
|
159
150
|
* slower per slice #13 R-3).
|
|
160
151
|
*/
|
|
@@ -201,36 +192,26 @@ export declare class SubAgentNotSupportedError extends Error {
|
|
|
201
192
|
*/
|
|
202
193
|
export declare function awaitClaudeCodeBatch(input: SubAgentAwaitBatchInput): Promise<readonly SubAgentBatchResult[]>;
|
|
203
194
|
/**
|
|
204
|
-
* Slice 1.3 — shared per-IDE polling core for trae /
|
|
205
|
-
*
|
|
206
|
-
*
|
|
207
|
-
* (a) `defaultTimeoutMs` (Trae /
|
|
208
|
-
*
|
|
209
|
-
*
|
|
210
|
-
* IDE).
|
|
195
|
+
* Slice 1.3 — shared per-IDE polling core for trae / codex / cursor.
|
|
196
|
+
* Same polling loop shape as `awaitClaudeCodeBatch`, with per-IDE
|
|
197
|
+
* default timeout + note prefix. The 3 IDEs differ only in
|
|
198
|
+
* (a) `defaultTimeoutMs` (Trae / Cursor = 30s, Codex = 45s per slice
|
|
199
|
+
* #13 R-3) and (b) the `note` label surfaced when an IDE times out
|
|
200
|
+
* (so 1.4 dogfood can attribute a timeout to the right IDE).
|
|
211
201
|
*
|
|
212
|
-
* MVP rationale (per Karpathy §2 Simplicity First): the
|
|
202
|
+
* MVP rationale (per Karpathy §2 Simplicity First): the 3 IDEs
|
|
213
203
|
* currently share the same file-based polling transport. The only
|
|
214
204
|
* per-IDE distinction is the timeout + label. Future per-IDE
|
|
215
205
|
* divergence (real IPC / shell hooks) is a 1.4 dogfood concern —
|
|
216
206
|
* here we keep the dispatcher interface uniform while each IDE's
|
|
217
|
-
* `awaitBatch` is
|
|
218
|
-
* `awaitByLlmFallback` marker.
|
|
207
|
+
* `awaitBatch` is a real implementation.
|
|
219
208
|
*/
|
|
220
209
|
export interface PollDispatchRecordsOptions {
|
|
221
|
-
readonly ide: 'trae' | '
|
|
210
|
+
readonly ide: 'trae' | 'codex' | 'cursor';
|
|
222
211
|
readonly defaultTimeoutMs: number;
|
|
223
212
|
readonly notePrefix: string;
|
|
224
213
|
}
|
|
225
214
|
export declare function pollDispatchRecords(input: SubAgentAwaitBatchInput, opts: PollDispatchRecordsOptions): Promise<readonly SubAgentBatchResult[]>;
|
|
226
|
-
/**
|
|
227
|
-
* 1.2 fallback for trae / trae-cn / codex / cursor. Deprecated by
|
|
228
|
-
* slice 1.3 — kept exported for legacy callers + back-compat tests
|
|
229
|
-
* (the 1.2 marker is still a valid envelope shape; the 1.4 dogfood
|
|
230
|
-
* tests can compare the marker note vs the 1.3 real note to verify
|
|
231
|
-
* per-IDE attribution).
|
|
232
|
-
*/
|
|
233
|
-
export declare function awaitByLlmFallback(input: SubAgentAwaitBatchInput, ide: string): Promise<readonly SubAgentBatchResult[]>;
|
|
234
215
|
/**
|
|
235
216
|
* In-process awaiter registration hook (used by `peaks sub-agent dispatch`
|
|
236
217
|
* to attach a resolver; not part of the dispatcher public surface).
|
|
@@ -106,38 +106,13 @@ export const traeSubAgentDispatcher = {
|
|
|
106
106
|
notePrefix: 'trae 1.3 real awaitBatch'
|
|
107
107
|
})
|
|
108
108
|
};
|
|
109
|
-
/**
|
|
110
|
-
* Trae-CN dispatcher. Mirrors Trae's shape with a separate label so
|
|
111
|
-
* the CLI's IDE detection can distinguish a Trae install region
|
|
112
|
-
* (Trae-CN differs in skill install path / log location only;
|
|
113
|
-
* dispatch surface is identical per slice #011 framework rule).
|
|
114
|
-
*
|
|
115
|
-
* Slice 1.3: real `awaitBatch` — same polling core as Trae.
|
|
116
|
-
*/
|
|
117
|
-
export const traeCnSubAgentDispatcher = {
|
|
118
|
-
label: 'trae-cn',
|
|
119
|
-
supportsRole: (role) => role.length > 0,
|
|
120
|
-
buildToolCall: ({ role, prompt, requestId }) => ({
|
|
121
|
-
name: 'Task',
|
|
122
|
-
args: {
|
|
123
|
-
subagent_type: 'general-purpose',
|
|
124
|
-
description: `${role} for rid=${requestId}`,
|
|
125
|
-
prompt,
|
|
126
|
-
},
|
|
127
|
-
}),
|
|
128
|
-
awaitBatch: async (input) => pollDispatchRecords(input, {
|
|
129
|
-
ide: 'trae-cn',
|
|
130
|
-
defaultTimeoutMs: 30_000,
|
|
131
|
-
notePrefix: 'trae-cn 1.3 real awaitBatch'
|
|
132
|
-
})
|
|
133
|
-
};
|
|
134
109
|
/**
|
|
135
110
|
* Codex (OpenAI CLI IDE) dispatcher.
|
|
136
111
|
*
|
|
137
112
|
* Slice #13 noted Codex's sub-agent tool name is TBD; per slice #009
|
|
138
113
|
* rationale, the dispatcher mirrors Claude Code's shape so the
|
|
139
|
-
* adapter contract stays uniform. Slice 1.3 promotes Codex from
|
|
140
|
-
*
|
|
114
|
+
* adapter contract stays uniform. Slice 1.3 promotes Codex from the
|
|
115
|
+
* 1.2 marker to a real `awaitBatch` (file-based polling,
|
|
141
116
|
* Codex default 45s — Codex's documented heartbeat is slightly
|
|
142
117
|
* slower per slice #13 R-3).
|
|
143
118
|
*/
|
|
@@ -245,14 +220,14 @@ export async function awaitClaudeCodeBatch(input) {
|
|
|
245
220
|
// service. The back-compat envelope shape is preserved (one
|
|
246
221
|
// `SubAgentBatchResult` per record path) so the S3 characterization
|
|
247
222
|
// test stays green; the underlying loop is identical to the trae /
|
|
248
|
-
//
|
|
223
|
+
// codex / cursor wrappers below. The new typed outcome
|
|
249
224
|
// lives on the unified service; the S4 fail-fast test pins it.
|
|
250
225
|
//
|
|
251
226
|
// Slice 2026-07-30-nightshift: claude-code does NOT use a
|
|
252
227
|
// per-IDE note prefix. The 1.4 dogfood contract says the done
|
|
253
228
|
// note is `null` (raw outcome) and the failed note is the raw
|
|
254
|
-
// `outcome` string with no prefix. The
|
|
255
|
-
// (trae /
|
|
229
|
+
// `outcome` string with no prefix. The 3 non-Claude IDEs
|
|
230
|
+
// (trae / codex / cursor) prefix the note with their
|
|
256
231
|
// per-IDE label so cross-IDE attribution is visible to the LLM.
|
|
257
232
|
// Passing no `notePrefix` here keeps the legacy contract.
|
|
258
233
|
const unified = await awaitBatchUnified(input.dispatchCount, input.recordPaths, input.timeoutMs, { defaultTimeoutMs: 60_000 });
|
|
@@ -299,24 +274,6 @@ export async function pollDispatchRecords(input, opts) {
|
|
|
299
274
|
});
|
|
300
275
|
return unified.results;
|
|
301
276
|
}
|
|
302
|
-
/**
|
|
303
|
-
* 1.2 fallback for trae / trae-cn / codex / cursor. Deprecated by
|
|
304
|
-
* slice 1.3 — kept exported for legacy callers + back-compat tests
|
|
305
|
-
* (the 1.2 marker is still a valid envelope shape; the 1.4 dogfood
|
|
306
|
-
* tests can compare the marker note vs the 1.3 real note to verify
|
|
307
|
-
* per-IDE attribution).
|
|
308
|
-
*/
|
|
309
|
-
export async function awaitByLlmFallback(input, ide) {
|
|
310
|
-
const startedAt = Date.now();
|
|
311
|
-
return input.recordPaths.map((p, i) => ({
|
|
312
|
-
dispatchIndex: i,
|
|
313
|
-
recordPath: p,
|
|
314
|
-
status: 'timeout',
|
|
315
|
-
durationMs: 0,
|
|
316
|
-
note: `awaitByLlm: ${ide} 1.2 fallback (real impl in 1.3)`
|
|
317
|
-
}));
|
|
318
|
-
void startedAt;
|
|
319
|
-
}
|
|
320
277
|
/**
|
|
321
278
|
* In-process awaiter registration hook (used by `peaks sub-agent dispatch`
|
|
322
279
|
* to attach a resolver; not part of the dispatcher public surface).
|
|
@@ -123,13 +123,21 @@ function isSourcePath(path) {
|
|
|
123
123
|
* read as two deleted cases; a class that is half-counted is worse than a class
|
|
124
124
|
* that is not counted at all.
|
|
125
125
|
*
|
|
126
|
+
* Word-boundary simulation, not `\b`. The JS regex could spell this as `\b`
|
|
127
|
+
* directly, but the POSIX ERE side of the count has to run on macOS too —
|
|
128
|
+
* where `git grep -E` is BSD grep, and BSD grep's POSIX ERE has no `\b`
|
|
129
|
+
* (it is a literal `b`). The two expressions therefore both spell the boundary
|
|
130
|
+
* as `(^|[^A-Za-z0-9_])`: start of line OR a non-word character. The two
|
|
131
|
+
* sides MUST agree, and `git grep -c` counts matched lines (not occurrences)
|
|
132
|
+
* so the extra prefix group does not shift the count.
|
|
133
|
+
*
|
|
126
134
|
* What is deliberately NOT modelled: an occurrence inside a comment or a string
|
|
127
135
|
* literal still matches. That is symmetric — the same expression is evaluated on
|
|
128
136
|
* both sides — so it cancels out of the DELTA, which is the only thing a removal
|
|
129
137
|
* is ever derived from.
|
|
130
138
|
*/
|
|
131
|
-
const TEST_CASE_LINE_RE =
|
|
132
|
-
const TEST_CASE_ERE = '
|
|
139
|
+
const TEST_CASE_LINE_RE = /(?:^|[^A-Za-z0-9_])(it|test)(\.[A-Za-z]+)*\(/;
|
|
140
|
+
const TEST_CASE_ERE = '(^|[^A-Za-z0-9_])(it|test)(\\.[A-Za-z]+)*\\(';
|
|
133
141
|
/**
|
|
134
142
|
* Column-0 `export` — an export STATEMENT, not a type-checked symbol.
|
|
135
143
|
*
|
|
@@ -591,7 +591,6 @@ export const CLAUDE_CODE_ADAPTER = {
|
|
|
591
591
|
const root = scope === 'global' ? homedir() : resolve(projectRoot ?? homedir());
|
|
592
592
|
return join(root, '.claude', 'settings.json');
|
|
593
593
|
},
|
|
594
|
-
supportsScope: () => true,
|
|
595
594
|
},
|
|
596
595
|
envVar: 'CLAUDE_PROJECT_DIR',
|
|
597
596
|
hookEvent: 'PreToolUse',
|
|
@@ -54,8 +54,7 @@ export const CODEX_ADAPTER = {
|
|
|
54
54
|
resolveSettingsFile: (scope, projectRoot) => {
|
|
55
55
|
const root = scope === 'global' ? homedir() : resolve(projectRoot ?? homedir());
|
|
56
56
|
return join(root, '.codex', 'settings.json');
|
|
57
|
-
}
|
|
58
|
-
supportsScope: (scope) => scope === 'project' || scope === 'global'
|
|
57
|
+
}
|
|
59
58
|
},
|
|
60
59
|
envVar: 'CODEX_PROJECT_DIR', // UNVERIFIED — see slice #13 PRD R-3; fallback path still works
|
|
61
60
|
hookEvent: 'pre_tool_use', // UNVERIFIED — Codex lowercase snake_case pattern; re-verify against Codex docs
|
|
@@ -44,8 +44,7 @@ export const CURSOR_ADAPTER = {
|
|
|
44
44
|
resolveSettingsFile: (scope, projectRoot) => {
|
|
45
45
|
const root = scope === 'global' ? homedir() : resolve(projectRoot ?? homedir());
|
|
46
46
|
return join(root, '.cursor', 'settings.json');
|
|
47
|
-
}
|
|
48
|
-
supportsScope: (scope) => scope === 'project' || scope === 'global'
|
|
47
|
+
}
|
|
49
48
|
},
|
|
50
49
|
envVar: 'CURSOR_PROJECT_DIR', // UNVERIFIED — see slice #12 PRD R-2; fallback path still works
|
|
51
50
|
hookEvent: 'beforeShellExecution', // UNVERIFIED — see slice #12 PRD R-1; re-verify against Cursor's published hook schema
|
|
@@ -29,8 +29,7 @@ export const HERMES_ADAPTER = {
|
|
|
29
29
|
resolveSettingsFile: (scope, projectRoot) => {
|
|
30
30
|
const root = scope === 'global' ? homedir() : resolve(projectRoot ?? homedir());
|
|
31
31
|
return join(root, '.hermes', 'settings.json');
|
|
32
|
-
}
|
|
33
|
-
supportsScope: (scope) => scope === 'project' || scope === 'global'
|
|
32
|
+
}
|
|
34
33
|
},
|
|
35
34
|
envVar: 'HERMES_PROJECT_DIR', // UNVERIFIED
|
|
36
35
|
hookEvent: 'PreToolUse', // UNVERIFIED
|
|
@@ -22,8 +22,7 @@ export const OPENCLAW_ADAPTER = {
|
|
|
22
22
|
resolveSettingsFile: (scope, projectRoot) => {
|
|
23
23
|
const root = scope === 'global' ? homedir() : resolve(projectRoot ?? homedir());
|
|
24
24
|
return join(root, '.openclaw', 'settings.json');
|
|
25
|
-
}
|
|
26
|
-
supportsScope: (scope) => scope === 'project' || scope === 'global'
|
|
25
|
+
}
|
|
27
26
|
},
|
|
28
27
|
envVar: 'OPENCLAW_PROJECT_DIR', // UNVERIFIED
|
|
29
28
|
hookEvent: 'PreToolUse', // UNVERIFIED
|
|
@@ -33,8 +33,7 @@ export const QODER_ADAPTER = {
|
|
|
33
33
|
resolveSettingsFile: (scope, projectRoot) => {
|
|
34
34
|
const root = scope === 'global' ? homedir() : resolve(projectRoot ?? homedir());
|
|
35
35
|
return join(root, '.qoder', 'settings.json');
|
|
36
|
-
}
|
|
37
|
-
supportsScope: (scope) => scope === 'project' || scope === 'global'
|
|
36
|
+
}
|
|
38
37
|
},
|
|
39
38
|
envVar: 'QODER_PROJECT_DIR', // UNVERIFIED
|
|
40
39
|
hookEvent: 'PreToolUse', // UNVERIFIED
|
|
@@ -24,8 +24,7 @@ export const TONGYI_LINGMA_ADAPTER = {
|
|
|
24
24
|
resolveSettingsFile: (scope, projectRoot) => {
|
|
25
25
|
const root = scope === 'global' ? homedir() : resolve(projectRoot ?? homedir());
|
|
26
26
|
return join(root, '.lingma', 'settings.json');
|
|
27
|
-
}
|
|
28
|
-
supportsScope: (scope) => scope === 'project' || scope === 'global'
|
|
27
|
+
}
|
|
29
28
|
},
|
|
30
29
|
envVar: 'TONGYI_LINGMA_PROJECT_DIR', // UNVERIFIED
|
|
31
30
|
hookEvent: 'PreToolUse', // UNVERIFIED
|
|
@@ -50,8 +50,7 @@ export const TRAE_ADAPTER = {
|
|
|
50
50
|
resolveSettingsFile: (scope, projectRoot) => {
|
|
51
51
|
const root = scope === 'global' ? homedir() : resolve(projectRoot ?? homedir());
|
|
52
52
|
return join(root, '.trae', 'settings.json');
|
|
53
|
-
}
|
|
54
|
-
supportsScope: (scope) => scope === 'project' || scope === 'global'
|
|
53
|
+
}
|
|
55
54
|
},
|
|
56
55
|
envVar: 'TRAE_PROJECT_DIR',
|
|
57
56
|
hookEvent: 'beforeToolCall', // VERIFIED against Trae 1.x fixture — slice 009-009-2026-06-07-trae-dogfood (2026-06-07); fixture at tests/fixtures/trae/trae-1x-payload.json
|
|
@@ -159,7 +159,6 @@ export const ZCODE_ADAPTER = {
|
|
|
159
159
|
const root = scope === 'global' ? homedir() : resolve(projectRoot ?? homedir());
|
|
160
160
|
return join(root, '.zcode', 'settings.json');
|
|
161
161
|
},
|
|
162
|
-
supportsScope: (scope) => scope === 'project' || scope === 'global',
|
|
163
162
|
},
|
|
164
163
|
// UNVERIFIED — z-code 桌面应用未公开 `ZCODE_PROJECT_DIR` env var,这里
|
|
165
164
|
// 用占位符,RD 阶段假设 z-code 借用了 Anthropic-compatible 协议并可能
|
|
@@ -41,8 +41,6 @@ export interface IdeSettingsLocation {
|
|
|
41
41
|
readonly localSettingsFileName?: string;
|
|
42
42
|
/** 解析出 settings.json 绝对路径 */
|
|
43
43
|
resolveSettingsFile(scope: 'project' | 'global', projectRoot: string | undefined): string;
|
|
44
|
-
/** 该 IDE 是否支持此 scope(用于清晰报错) */
|
|
45
|
-
supportsScope(scope: 'project' | 'global'): boolean;
|
|
46
44
|
}
|
|
47
45
|
/**
|
|
48
46
|
* Slim IDE adapter 描述。每 IDE 一个静态常量(无需 DI)。
|
|
@@ -29,8 +29,8 @@ export declare const ObservabilityEventSchema: z.ZodObject<{
|
|
|
29
29
|
ts: z.ZodString;
|
|
30
30
|
sessionId: z.ZodString;
|
|
31
31
|
category: z.ZodEnum<{
|
|
32
|
-
dispatch: "dispatch";
|
|
33
32
|
"slice-transition": "slice-transition";
|
|
33
|
+
dispatch: "dispatch";
|
|
34
34
|
checkpoint: "checkpoint";
|
|
35
35
|
"mode-gate": "mode-gate";
|
|
36
36
|
"context-trigger": "context-trigger";
|
|
@@ -8,7 +8,25 @@
|
|
|
8
8
|
* is not merely annotated. `confidence: 'exact'` is reserved for lines where
|
|
9
9
|
* both sides were parsed AND the recorded interface was fully readable.
|
|
10
10
|
*/
|
|
11
|
+
import { realpathSync } from 'node:fs';
|
|
11
12
|
import { resolve, sep } from 'node:path';
|
|
13
|
+
/**
|
|
14
|
+
* Canonicalize through symlinks so two paths that name the same directory through
|
|
15
|
+
* different prefixes (the macOS `/var` <-> `/private/var` quirk the brief calls
|
|
16
|
+
* out) line up as the same literal on both sides of the prefix test below.
|
|
17
|
+
* Falls back to `resolve()` when the path does not exist yet — `realpathSync`
|
|
18
|
+
* throws on missing paths, and several callers in the suite inspect not-yet-
|
|
19
|
+
* created paths (e.g. the "string prefix of a sibling" guard at
|
|
20
|
+
* api-diff-service.test.ts:462).
|
|
21
|
+
*/
|
|
22
|
+
function safeRealpath(p) {
|
|
23
|
+
try {
|
|
24
|
+
return realpathSync(p);
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
return resolve(p);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
12
30
|
/** The honest boundary of the feature. Printed in the output, not just documented. */
|
|
13
31
|
export const NOT_DETECTABLE = [
|
|
14
32
|
'a field whose type is unchanged but whose meaning changed',
|
|
@@ -38,8 +56,8 @@ export function isRecord(value) {
|
|
|
38
56
|
* the misleading `archive/docs/api.json`.
|
|
39
57
|
*/
|
|
40
58
|
export function toDisplayPath(projectRoot, file) {
|
|
41
|
-
const rootParts =
|
|
42
|
-
const fileParts =
|
|
59
|
+
const rootParts = safeRealpath(projectRoot).split(sep);
|
|
60
|
+
const fileParts = safeRealpath(file).split(sep);
|
|
43
61
|
const inside = fileParts.length > rootParts.length
|
|
44
62
|
&& rootParts.every((part, index) => part === fileParts[index]);
|
|
45
63
|
return (inside ? fileParts.slice(rootParts.length) : fileParts).join('/');
|
|
@@ -71,12 +71,30 @@ export function assertSafeDispatchRecordPath(recordPath, projectRoot) {
|
|
|
71
71
|
// to create it). Fall back to lexical comparison against the
|
|
72
72
|
// canonical projectRoot — the write will then create the file,
|
|
73
73
|
// and any symlink in the parent will be caught on the next read.
|
|
74
|
+
//
|
|
75
|
+
// macOS note: the project's own realpath may still resolve the
|
|
76
|
+
// `/var -> /private/var` symlink even when the sub-agent dir does
|
|
77
|
+
// not exist yet, so the caller can compare on a stable prefix
|
|
78
|
+
// instead of having one side of the comparison on `/var/...` and
|
|
79
|
+
// the other on `/private/var/...`. We still validate that the
|
|
80
|
+
// canonical record path lives under the canonical projectRoot.
|
|
74
81
|
const fallback = resolve(projectRoot, '.peaks', SUB_AGENTS_DIR);
|
|
75
82
|
const rel2 = relative(fallback, recordPath);
|
|
76
83
|
if (rel2.startsWith('..') || isAbsolute(rel2)) {
|
|
77
84
|
throw invalidPathError(recordPath, 'must be under .peaks/_sub_agents/');
|
|
78
85
|
}
|
|
79
|
-
|
|
86
|
+
try {
|
|
87
|
+
realRoot = realpathSync(projectRoot);
|
|
88
|
+
const canonicalRecord = resolve(realRoot, '.peaks', SUB_AGENTS_DIR, recordPath.slice(fallback.length + 1));
|
|
89
|
+
const realRel = relative(realRoot, canonicalRecord);
|
|
90
|
+
if (realRel.startsWith('..' + sep) || realRel === '..' || isAbsolute(realRel)) {
|
|
91
|
+
throw invalidPathError(recordPath, 'escapes project root via symlink');
|
|
92
|
+
}
|
|
93
|
+
return canonicalRecord;
|
|
94
|
+
}
|
|
95
|
+
catch {
|
|
96
|
+
return recordPath;
|
|
97
|
+
}
|
|
80
98
|
}
|
|
81
99
|
const realRel = relative(realRoot, realRecord);
|
|
82
100
|
if (realRel.startsWith('..' + sep) || realRel === '..' || isAbsolute(realRel)) {
|
|
@@ -32,14 +32,14 @@ export declare const SkillSearchInputSchema: z.ZodObject<{
|
|
|
32
32
|
status: "status";
|
|
33
33
|
resume: "resume";
|
|
34
34
|
audit: "audit";
|
|
35
|
-
|
|
35
|
+
"final-review": "final-review";
|
|
36
36
|
content: "content";
|
|
37
|
+
ide: "ide";
|
|
37
38
|
test: "test";
|
|
38
|
-
research: "research";
|
|
39
39
|
doctor: "doctor";
|
|
40
|
+
research: "research";
|
|
40
41
|
triage: "triage";
|
|
41
42
|
sop: "sop";
|
|
42
|
-
"final-review": "final-review";
|
|
43
43
|
"slice-decompose": "slice-decompose";
|
|
44
44
|
"issue-fix-orchestrator": "issue-fix-orchestrator";
|
|
45
45
|
"perf-audit": "perf-audit";
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
* `peaks standards lint --category loop-engineering` (registered in M0's
|
|
19
19
|
* plan) will read this file from disk and call this function.
|
|
20
20
|
*/
|
|
21
|
-
export declare const EXPECTED_RED_LINE_IDS: readonly ["RL-0", "RL-1", "RL-2", "RL-3", "RL-4", "RL-5", "RL-6", "RL-7", "RL-8", "RL-9"];
|
|
21
|
+
export declare const EXPECTED_RED_LINE_IDS: readonly ["RL-0", "RL-1", "RL-2", "RL-3", "RL-4", "RL-5", "RL-6", "RL-7", "RL-8", "RL-9", "RL-10"];
|
|
22
22
|
export type RedLineId = (typeof EXPECTED_RED_LINE_IDS)[number];
|
|
23
23
|
export declare const REQUIRED_SECTIONS: readonly ["Failure modes", "Rewrite", "Self-check", "Out-of-scope"];
|
|
24
24
|
export type RedLineSection = (typeof REQUIRED_SECTIONS)[number];
|
|
@@ -29,6 +29,12 @@ export const EXPECTED_RED_LINE_IDS = [
|
|
|
29
29
|
'RL-7',
|
|
30
30
|
'RL-8',
|
|
31
31
|
'RL-9',
|
|
32
|
+
// RL-10 was written into the guideline file (its 4 sections included) but
|
|
33
|
+
// never added here, so the lint could not see it: the closed set stopped one
|
|
34
|
+
// short of the file it was supposed to police. The file's own footer said
|
|
35
|
+
// "Total red lines: 9 (RL-0..RL-9)" while RL-10 sat below it — the two
|
|
36
|
+
// statements contradicted each other and only the file was ever read.
|
|
37
|
+
'RL-10',
|
|
32
38
|
];
|
|
33
39
|
export const REQUIRED_SECTIONS = [
|
|
34
40
|
'Failure modes',
|
|
@@ -5,10 +5,29 @@
|
|
|
5
5
|
* WRITE goes through `assertUnder` first — the slice-wide guard against an
|
|
6
6
|
* artifact escaping `<root>/.peaks/_runtime/<sid>/web/` (AC1).
|
|
7
7
|
*/
|
|
8
|
-
import { existsSync, mkdirSync, readFileSync, unlinkSync, writeFileSync } from 'node:fs';
|
|
8
|
+
import { existsSync, mkdirSync, readFileSync, realpathSync, unlinkSync, writeFileSync } from 'node:fs';
|
|
9
9
|
import { dirname } from 'node:path';
|
|
10
10
|
import { assertUnder, webDaemonDir, webDaemonInfoPath, webSpawnLockPath } from './web-artifact-paths.js';
|
|
11
11
|
import { parseDaemonInfo } from './web-protocol.js';
|
|
12
|
+
/**
|
|
13
|
+
* Canonicalize through symlinks so two paths that name the same directory through
|
|
14
|
+
* different prefixes compare equal — the macOS `/var` <-> `/private/var` quirk
|
|
15
|
+
* makes `mkdtempSync(...)` return `/var/folders/...` while `process.cwd()` after
|
|
16
|
+
* `chdir` returns `/private/var/folders/...`. They are the same directory on
|
|
17
|
+
* disk; without `realpathSync` the ownership check below silently rejects a
|
|
18
|
+
* legitimate record and the CLI cold-starts a real daemon instead of reusing
|
|
19
|
+
* the stub. Falls back to `resolve()` when the path is absent: a planted
|
|
20
|
+
* record naming a directory that does not exist still has to fail the
|
|
21
|
+
* containment test, and a `realpathSync` on it would throw.
|
|
22
|
+
*/
|
|
23
|
+
function safeRealpath(p) {
|
|
24
|
+
try {
|
|
25
|
+
return realpathSync(p);
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
return p;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
12
31
|
/** A spawn lock older than this is reclaimed even if its owner pid is alive. */
|
|
13
32
|
const SPAWN_LOCK_STALE_MS = 120_000;
|
|
14
33
|
/**
|
|
@@ -46,7 +65,13 @@ export function readDaemonInfo(projectRoot, sessionId) {
|
|
|
46
65
|
}
|
|
47
66
|
try {
|
|
48
67
|
const info = parseDaemonInfo(readFileSync(target, 'utf8'));
|
|
49
|
-
if (info === null || info.
|
|
68
|
+
if (info === null || info.sessionId !== sessionId) {
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
71
|
+
// Canonicalize both sides — a record written from one prefix (say
|
|
72
|
+
// `/var/folders/...`) and read from the canonical one (`/private/var/...`)
|
|
73
|
+
// describes the same project on macOS.
|
|
74
|
+
if (safeRealpath(info.projectRoot) !== safeRealpath(projectRoot)) {
|
|
50
75
|
return null;
|
|
51
76
|
}
|
|
52
77
|
return info;
|
|
@@ -2,24 +2,31 @@
|
|
|
2
2
|
* Slice 2.0.1-bug3-fact-forcing-bypass — pure-data template for the
|
|
3
3
|
* consumer-project `.claude/settings.local.json` file.
|
|
4
4
|
*
|
|
5
|
-
* The template
|
|
6
|
-
* Claude Code [Fact-Forcing Gate]
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
5
|
+
* The template exempts the peaks-managed `.peaks/` workspace from the
|
|
6
|
+
* Claude Code [Fact-Forcing Gate], so `peaks workspace init` (Step 0 of
|
|
7
|
+
* every peaks-code session) is runnable in a consumer project — without
|
|
8
|
+
* the exemption the gate blocks the very first Write.
|
|
9
|
+
*
|
|
10
|
+
* The exemption is declared in the `env` block
|
|
11
|
+
* (`EXTERNAL_GATE_EXEMPT_ENV`), which is what the gate actually reads.
|
|
12
|
+
* TEMPLATE_VERSION 1.7.0 moved it there; before that it was declared by a
|
|
13
|
+
* `Write|Edit|MultiEdit` handler that exited non-zero for non-`.peaks/`
|
|
14
|
+
* paths and was documented as "fall through to the gate". That concept does
|
|
15
|
+
* not exist in the Claude Code hook protocol (only exit 2 blocks; any other
|
|
16
|
+
* non-zero exit is a NON-BLOCKING ERROR reported once per edit), so the
|
|
17
|
+
* handler was corrected to abstain on every path — and an abstaining handler
|
|
18
|
+
* that is still INSTALLED is a no-op carrying a machine-specific absolute
|
|
19
|
+
* script path. TEMPLATE_VERSION 1.8.0 removed it rather than re-point it:
|
|
20
|
+
* it decided nothing, and the exemption it was written for lives in `env`.
|
|
11
21
|
*
|
|
12
22
|
* The template is a pure-data function (no filesystem, no clock) so
|
|
13
23
|
* it can be unit-tested in isolation and so the on-disk file matches
|
|
14
24
|
* the in-memory template byte-for-byte.
|
|
15
25
|
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
* gate) for everything else. TEMPLATE_VERSION 1.6.0 moved the decision
|
|
21
|
-
* out of an inlined `node -e "<js>"` one-liner, whose escaping was
|
|
22
|
-
* bash-specific and therefore could not take a platform `shell` pin.
|
|
26
|
+
* Two `Bash` matchers are emitted (the Step 0.8 mechanical gate and the
|
|
27
|
+
* SOP gate-enforce handler). No `Write|Edit|MultiEdit` entry is emitted:
|
|
28
|
+
* that matcher's gate is `peaks code-gate --json`, installed into the
|
|
29
|
+
* committed `.claude/settings.json` by `peaks hooks install`.
|
|
23
30
|
*
|
|
24
31
|
* The previous `Bash` matcher (which whitelisted a fixed `peaks
|
|
25
32
|
* <subcommand>` prefix) was removed in TEMPLATE_VERSION 1.2.0. The
|
|
@@ -80,8 +87,20 @@ export declare const CLAUDE_SETTINGS_LOCAL_FILENAME = ".claude/settings.local.js
|
|
|
80
87
|
* (`EXTERNAL_GATE_EXEMPT_ENV`). The comparator now requires the
|
|
81
88
|
* on-disk file to declare those exemptions too, so a project
|
|
82
89
|
* installed by an earlier release refreshes once and converges.
|
|
90
|
+
* 1.8.0 — REMOVED the `Write|Edit|MultiEdit` handler and the shipped
|
|
91
|
+
* script it invoked (`src/services/hooks/write-gate.js`, also
|
|
92
|
+
* deleted). The handler abstained on every path by design (see
|
|
93
|
+
* that file's header for the rationale — it is the reason this
|
|
94
|
+
* is a deletion and not a repair), so the only things it still
|
|
95
|
+
* contributed were a `node "<abs path>"` command pinned to the
|
|
96
|
+
* Node version directory that happened to be on `$PATH` at
|
|
97
|
+
* install time, and a `shell: powershell` pin. The exemption it
|
|
98
|
+
* was written to provide is declared by the `env` block above.
|
|
99
|
+
* `mergeTemplateOwnedHooks` drops the retired entry from
|
|
100
|
+
* existing on-disk files, so an earlier install converges
|
|
101
|
+
* instead of keeping a no-op with a stale absolute path.
|
|
83
102
|
*/
|
|
84
|
-
export declare const TEMPLATE_VERSION = "1.
|
|
103
|
+
export declare const TEMPLATE_VERSION = "1.8.0";
|
|
85
104
|
/**
|
|
86
105
|
* Compare two serialized template strings: does the on-disk file already
|
|
87
106
|
* declare every entry the generated tree declares?
|
|
@@ -108,10 +127,11 @@ export declare const TEMPLATE_VERSION = "1.7.0";
|
|
|
108
127
|
* detail).
|
|
109
128
|
*
|
|
110
129
|
* Returns `true` iff both strings parse to objects whose `hooks.PreToolUse`
|
|
111
|
-
* arrays satisfy that containment
|
|
112
|
-
*
|
|
113
|
-
*
|
|
114
|
-
*
|
|
130
|
+
* arrays satisfy that containment, the on-disk file carries NO entry this
|
|
131
|
+
* template has retired (`isRetiredTemplateEntry`), AND the on-disk `env`
|
|
132
|
+
* already carries every exemption the template declares (extra on-disk keys
|
|
133
|
+
* and extra globs are allowed — a user may exempt other trees, and a
|
|
134
|
+
* requirement the file already exceeds must not re-trigger a write).
|
|
115
135
|
*
|
|
116
136
|
* Returns `false` on any `JSON.parse` error, shape mismatch, or
|
|
117
137
|
* missing `hooks.PreToolUse`. Whitespace and key order do NOT affect
|
|
@@ -147,23 +167,18 @@ export declare function templateContentMatches(generated: string, onDisk: string
|
|
|
147
167
|
* Non-conforming entries (no string `matcher`, no `hooks` array) are preserved
|
|
148
168
|
* rather than dropped: guessing at their shape is how a user's entry gets
|
|
149
169
|
* deleted.
|
|
170
|
+
*
|
|
171
|
+
* ONE exception to "preserve what I do not declare": an entry this template
|
|
172
|
+
* used to declare and RETIRED (TEMPLATE_VERSION 1.8.0's `Write|Edit|MultiEdit`
|
|
173
|
+
* gate — see `isRetiredTemplateEntry`) is dropped rather than preserved.
|
|
174
|
+
* Declaring less cannot retire an entry on its own, because preserving
|
|
175
|
+
* undeclared entries is exactly what this function does; without the drop, a
|
|
176
|
+
* pre-1.8.0 install would keep the no-op handler and its version-pinned script
|
|
177
|
+
* path forever. The predicate is narrow enough that only the exact command
|
|
178
|
+
* this template emitted matches.
|
|
150
179
|
*/
|
|
151
180
|
export declare function mergeTemplateOwnedHooks(onDisk: ReadonlyArray<unknown>, template: ReadonlyArray<unknown>): unknown[];
|
|
152
|
-
|
|
153
|
-
* Absolute path of the shipped Write|Edit|MultiEdit gate script.
|
|
154
|
-
*
|
|
155
|
-
* `write-gate.js` is a plain `.js` (not a compiled `.ts`) precisely so this
|
|
156
|
-
* single relative filename resolves in BOTH trees: `src/services/hooks/` for
|
|
157
|
-
* `tsx` / vitest, `dist/services/hooks/` for an installed consumer (copied by
|
|
158
|
-
* `scripts/copy-templates.mjs`; the `dist/**` `*.js` glob in
|
|
159
|
-
* `package.json#files` already ships it).
|
|
160
|
-
*
|
|
161
|
-
* Separators are normalized to `/` so the emitted command contains no
|
|
162
|
-
* backslash at all. That is what makes the handler shell-agnostic: bash
|
|
163
|
-
* reduces `\X` inside `"..."` and PowerShell escapes with a backtick, so any
|
|
164
|
-
* backslash in the string is one dialect's problem waiting to happen.
|
|
165
|
-
*/
|
|
166
|
-
export declare function writeGateScriptPath(): string;
|
|
181
|
+
export declare function isRetiredTemplateEntry(entry: unknown): boolean;
|
|
167
182
|
type ClaudeHookCommand = {
|
|
168
183
|
type: 'command';
|
|
169
184
|
command: string;
|
|
@@ -192,10 +207,11 @@ type ClaudeSettingsLocal = {
|
|
|
192
207
|
* forcing gate is a core feature that PreToolUse hooks can short-
|
|
193
208
|
* circuit but that the `permissions` block cannot.
|
|
194
209
|
*
|
|
195
|
-
* As of TEMPLATE_VERSION 1.
|
|
196
|
-
*
|
|
197
|
-
*
|
|
198
|
-
*
|
|
210
|
+
* As of TEMPLATE_VERSION 1.8.0 the template emits the two `Bash` matchers
|
|
211
|
+
* only. The `Write|Edit|MultiEdit` fact-forcing bypass is no longer a hook:
|
|
212
|
+
* it is the `env` exemption above, and that matcher's gate
|
|
213
|
+
* (`peaks code-gate --json`) is installed into the committed
|
|
214
|
+
* `.claude/settings.json` by `peaks hooks install`.
|
|
199
215
|
*/
|
|
200
216
|
export declare function buildClaudeSettingsLocalJson(): ClaudeSettingsLocal;
|
|
201
217
|
export {};
|