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.
Files changed (179) hide show
  1. package/CHANGELOG.md +38 -0
  2. package/README-en.md +1 -1
  3. package/README.md +1 -1
  4. package/dist/cli/commands/audit-commands.js +1 -0
  5. package/dist/cli/commands/baseline-commands.js +163 -25
  6. package/dist/cli/commands/core/skill-command.js +53 -4
  7. package/dist/cli/commands/core/standards-command.d.ts +24 -0
  8. package/dist/cli/commands/core/standards-command.js +74 -0
  9. package/dist/cli/commands/hooks-commands.js +55 -38
  10. package/dist/cli/commands/share-commands.js +113 -20
  11. package/dist/cli/commands/web-commands.js +8 -1
  12. package/dist/cli/commands/workflow-lifecycle-commands.d.ts +6 -0
  13. package/dist/cli/commands/workflow-lifecycle-commands.js +64 -3
  14. package/dist/services/adapter/adapter.d.ts +30 -0
  15. package/dist/services/adapter/auto-adapter.d.ts +13 -0
  16. package/dist/services/adapter/claude-adapter.js +12 -0
  17. package/dist/services/adapter/codex-adapter.d.ts +12 -0
  18. package/dist/services/adapter/codex-adapter.js +12 -0
  19. package/dist/services/adapter/copilot-adapter.d.ts +12 -0
  20. package/dist/services/adapter/copilot-adapter.js +12 -0
  21. package/dist/services/audit/backing-detector.d.ts +25 -7
  22. package/dist/services/audit/backing-detector.js +33 -17
  23. package/dist/services/audit/enforcer-liveness.d.ts +12 -0
  24. package/dist/services/audit/enforcer-liveness.js +100 -0
  25. package/dist/services/audit/enforcers/lint-catalog-governance.d.ts +23 -11
  26. package/dist/services/audit/enforcers/lint-catalog-governance.js +10 -14
  27. package/dist/services/audit/enforcers/lint-rd-handoff-coverage.d.ts +5 -15
  28. package/dist/services/audit/enforcers/lint-rd-handoff-coverage.js +94 -25
  29. package/dist/services/audit/enforcers/lint-style.d.ts +9 -1
  30. package/dist/services/audit/enforcers/lint-style.js +38 -2
  31. package/dist/services/audit/prose-ratio-calculator.d.ts +28 -17
  32. package/dist/services/audit/prose-ratio-calculator.js +25 -18
  33. package/dist/services/audit/red-line-catalog-p2-a.js +1 -1
  34. package/dist/services/audit/red-lines-service.js +51 -7
  35. package/dist/services/capability-audit-service/independent-checker.d.ts +15 -0
  36. package/dist/services/capability-audit-service/independent-checker.js +140 -0
  37. package/dist/services/capability-audit-service/index.d.ts +3 -1
  38. package/dist/services/capability-audit-service/index.js +1 -0
  39. package/dist/services/capability-audit-service/runner.d.ts +17 -13
  40. package/dist/services/capability-audit-service/runner.js +76 -15
  41. package/dist/services/capability-audit-service/types.d.ts +48 -0
  42. package/dist/services/capability-guard-runner/contracts/J01.js +21 -22
  43. package/dist/services/capability-guard-runner/contracts/J02.d.ts +1 -1
  44. package/dist/services/capability-guard-runner/contracts/J02.js +114 -28
  45. package/dist/services/capability-guard-runner/contracts/J03.d.ts +13 -0
  46. package/dist/services/capability-guard-runner/contracts/J03.js +72 -21
  47. package/dist/services/capability-guard-runner/contracts/J04.d.ts +6 -0
  48. package/dist/services/capability-guard-runner/contracts/J04.js +65 -32
  49. package/dist/services/capability-guard-runner/contracts/J05.js +118 -16
  50. package/dist/services/capability-guard-runner/contracts/J06.d.ts +14 -0
  51. package/dist/services/capability-guard-runner/contracts/J06.js +57 -39
  52. package/dist/services/capability-guard-runner/contracts/J07.d.ts +9 -0
  53. package/dist/services/capability-guard-runner/contracts/J07.js +76 -47
  54. package/dist/services/capability-guard-runner/contracts/J08.d.ts +11 -0
  55. package/dist/services/capability-guard-runner/contracts/J08.js +66 -39
  56. package/dist/services/capability-guard-runner/contracts/J09.d.ts +13 -0
  57. package/dist/services/capability-guard-runner/contracts/J09.js +95 -39
  58. package/dist/services/capability-guard-runner/contracts/J10.d.ts +12 -0
  59. package/dist/services/capability-guard-runner/contracts/J10.js +69 -35
  60. package/dist/services/capability-guard-runner/contracts/J11.d.ts +8 -0
  61. package/dist/services/capability-guard-runner/contracts/J11.js +73 -33
  62. package/dist/services/capability-guard-runner/contracts/J12.d.ts +12 -0
  63. package/dist/services/capability-guard-runner/contracts/J12.js +66 -30
  64. package/dist/services/capability-guard-runner/contracts/J13.d.ts +11 -0
  65. package/dist/services/capability-guard-runner/contracts/J13.js +62 -40
  66. package/dist/services/capability-guard-runner/contracts/J14.d.ts +11 -0
  67. package/dist/services/capability-guard-runner/contracts/J14.js +60 -31
  68. package/dist/services/capability-guard-runner/contracts/J15.d.ts +11 -0
  69. package/dist/services/capability-guard-runner/contracts/J15.js +70 -35
  70. package/dist/services/capability-guard-runner/contracts/_shared.d.ts +24 -0
  71. package/dist/services/capability-guard-runner/contracts/_shared.js +67 -0
  72. package/dist/services/capability-guard-runner/registry.d.ts +5 -0
  73. package/dist/services/capability-guard-runner/registry.js +140 -0
  74. package/dist/services/capability-guard-runner/runner.d.ts +26 -0
  75. package/dist/services/capability-guard-runner/runner.js +63 -6
  76. package/dist/services/code/auto-compact-modes.d.ts +13 -2
  77. package/dist/services/code/auto-compact-modes.js +20 -4
  78. package/dist/services/code/post-compact-detector.js +20 -11
  79. package/dist/services/code/step-08-gate.js +21 -6
  80. package/dist/services/config/config-safety.js +11 -9
  81. package/dist/services/dispatch/sub-agent-dispatcher.d.ts +11 -30
  82. package/dist/services/dispatch/sub-agent-dispatcher.js +5 -48
  83. package/dist/services/final-review/pre-post-diff.js +10 -2
  84. package/dist/services/ide/adapters/claude-code-adapter.js +0 -1
  85. package/dist/services/ide/adapters/codex-adapter.js +1 -2
  86. package/dist/services/ide/adapters/cursor-adapter.js +1 -2
  87. package/dist/services/ide/adapters/hermes-adapter.js +1 -2
  88. package/dist/services/ide/adapters/openclaw-adapter.js +1 -2
  89. package/dist/services/ide/adapters/qoder-adapter.js +1 -2
  90. package/dist/services/ide/adapters/tongyi-lingma-adapter.js +1 -2
  91. package/dist/services/ide/adapters/trae-adapter.js +1 -2
  92. package/dist/services/ide/adapters/zcode-adapter.js +0 -1
  93. package/dist/services/ide/ide-types.d.ts +0 -2
  94. package/dist/services/observability/observability-service.d.ts +1 -1
  95. package/dist/services/scan/api-diff-types.js +20 -2
  96. package/dist/services/security/safe-settings-path.js +19 -1
  97. package/dist/services/skill/skill-search-service.d.ts +3 -3
  98. package/dist/services/standards/loop-engineering-lint.d.ts +1 -1
  99. package/dist/services/standards/loop-engineering-lint.js +6 -0
  100. package/dist/services/web/daemon-registry.js +27 -2
  101. package/dist/services/workspace/claude-settings-template.d.ts +53 -37
  102. package/dist/services/workspace/claude-settings-template.js +105 -83
  103. package/dist/services/workspace/generated-artifacts-stamp.d.ts +119 -0
  104. package/dist/services/workspace/generated-artifacts-stamp.js +167 -0
  105. package/dist/services/workspace/workspace-claude-settings-materializer.d.ts +8 -0
  106. package/dist/services/workspace/workspace-claude-settings-materializer.js +38 -3
  107. package/dist/services/workspace/workspace-service.js +11 -1
  108. package/dist/shared/fs-utils.d.ts +26 -0
  109. package/dist/shared/fs-utils.js +35 -0
  110. package/package.json +9 -7
  111. package/scripts/copy-templates.mjs +0 -12
  112. package/scripts/install-skills.mjs +154 -53
  113. package/skills/bee/peaks-perf-audit/SKILL.md +2 -2
  114. package/skills/bee/peaks-perf-audit/references/audit-protocol.md +1 -1
  115. package/skills/bee/peaks-prd/SKILL.md +3 -3
  116. package/skills/bee/peaks-prd/references/prd-for-multi-pass.md +1 -1
  117. package/skills/bee/peaks-prd/references/workflow.md +1 -1
  118. package/skills/bee/peaks-qa/SKILL.md +6 -7
  119. package/skills/bee/peaks-qa/references/external-capability-guidance.md +1 -1
  120. package/skills/bee/peaks-qa/references/qa-fanout-contract.md +1 -1
  121. package/skills/bee/peaks-qa/references/reading-handoff-frontmatter.md +2 -2
  122. package/skills/bee/peaks-rd/SKILL.md +2 -3
  123. package/skills/bee/peaks-rd/references/code-reviewer-4dim-hint.md +1 -1
  124. package/skills/bee/peaks-rd/references/external-references.md +1 -1
  125. package/skills/bee/peaks-rd/references/mandatory-perf-baseline.md +1 -1
  126. package/skills/bee/peaks-rd/references/ocr-multilang-1.8.md +2 -2
  127. package/skills/bee/peaks-rd/references/parallel-review-fanout.md +2 -2
  128. package/skills/bee/peaks-rd/references/rd-fanout-contracts.md +11 -8
  129. package/skills/bee/peaks-rd/references/rd-runbook.md +1 -1
  130. package/skills/bee/peaks-rd/references/rd-sub-agent-dispatch.md +7 -7
  131. package/skills/bee/peaks-rd/references/rd-transition-gates.md +1 -1
  132. package/skills/bee/peaks-rd/references/reading-v2-slice-results.md +1 -1
  133. package/skills/bee/peaks-rd/references/v2-12-fanout-collapse.md +7 -5
  134. package/skills/bee/peaks-rd/references/writing-handoff-frontmatter.md +3 -3
  135. package/skills/bee/peaks-reviewer/SKILL.md +1 -1
  136. package/skills/bee/peaks-security-audit/SKILL.md +3 -3
  137. package/skills/bee/peaks-security-audit/references/audit-protocol.md +1 -1
  138. package/skills/bee/peaks-txt/references/context-capsule.md +1 -1
  139. package/skills/bee/peaks-ui/SKILL.md +1 -1
  140. package/skills/peaks-audit/SKILL.md +1 -1
  141. package/skills/peaks-code/SKILL.md +20 -18
  142. package/skills/peaks-code/references/context-governance.md +1 -1
  143. package/skills/peaks-code/references/dag-orchestrator.md +3 -4
  144. package/skills/peaks-code/references/external-references.md +1 -1
  145. package/skills/peaks-code/references/external-skill-invocation.md +2 -2
  146. package/skills/peaks-code/references/fanout-mandatory.md +3 -3
  147. package/skills/peaks-code/references/frontend-only-mode.md +2 -2
  148. package/skills/peaks-code/references/gstack-integration.md +1 -1
  149. package/skills/peaks-code/references/micro-cycle.md +1 -1
  150. package/skills/peaks-code/references/periodic-checkpoint.md +4 -4
  151. package/skills/peaks-code/references/project-scan-checklist.md +1 -1
  152. package/skills/peaks-code/references/resume-detection.md +1 -1
  153. package/skills/peaks-code/references/runbook.md +6 -3
  154. package/skills/peaks-code/references/session-overload-signal-index.md +6 -4
  155. package/skills/peaks-code/references/startup-sequence.md +17 -17
  156. package/skills/peaks-code/references/step-0-8-gate.md +1 -1
  157. package/skills/peaks-code/references/step-11-memory-sediment.md +2 -2
  158. package/skills/peaks-code/references/sub-agent-dispatch.md +26 -25
  159. package/skills/peaks-code/references/swarm-dispatch-contract.md +1 -1
  160. package/skills/peaks-code/references/workflow-gates-and-types.md +3 -3
  161. package/skills/peaks-code/references/worktree-governance.md +1 -1
  162. package/skills/peaks-final-review/SKILL.md +3 -3
  163. package/skills/peaks-ide/references/audit-log-helper.md +5 -4
  164. package/skills/peaks-resume/SKILL.md +1 -1
  165. package/skills/peaks-slice-decompose/SKILL.md +4 -4
  166. package/skills/peaks-slice-decompose/references/cross-pass-edge-interpretation.md +1 -1
  167. package/skills/peaks-slice-decompose/references/granularity-decision.md +1 -1
  168. package/skills/peaks-slice-decompose/references/v2-schema.md +2 -2
  169. package/skills/peaks-solo/SKILL.md +1 -2
  170. package/dist/cli/commands/context-builder-commands.d.ts +0 -11
  171. package/dist/cli/commands/context-builder-commands.js +0 -85
  172. package/dist/services/hooks/write-gate.js +0 -111
  173. package/skills/bee/peaks-prd/references/command-migration.md +0 -3
  174. package/skills/bee/peaks-qa/references/command-migration.md +0 -3
  175. package/skills/bee/peaks-rd/references/command-migration.md +0 -3
  176. package/skills/bee/peaks-sc/references/command-migration.md +0 -3
  177. package/skills/bee/peaks-txt/references/command-migration.md +0 -3
  178. package/skills/bee/peaks-ui/references/command-migration.md +0 -3
  179. 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
- if (realStart !== start) {
177
- // User passed a path through a symlink; reject as non-canonical
178
- // for trust-boundary entry points.
179
- throw new InvalidProjectRootError('non-canonical', startPath);
180
- }
181
- // Delegate to the existing canonicalization (git root → heuristic)
182
- // AFTER the strict pre-checks pass.
183
- const canonical = resolveCanonicalProjectRoot(startPath);
184
- if (canonical === startPath || canonical === realStart) {
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
- * `awaitByLlmFallback` to a real `awaitBatch` (file-based polling,
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 / trae-cn / codex /
205
- * cursor. Same polling loop shape as `awaitClaudeCodeBatch`, with
206
- * per-IDE default timeout + note prefix. The 4 IDEs differ only in
207
- * (a) `defaultTimeoutMs` (Trae / Trae-CN / Cursor = 30s, Codex = 45s
208
- * per slice #13 R-3) and (b) the `note` label surfaced when an IDE
209
- * times out (so 1.4 dogfood can attribute a timeout to the right
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 4 IDEs
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 now a real implementation rather than the 1.2
218
- * `awaitByLlmFallback` marker.
207
+ * `awaitBatch` is a real implementation.
219
208
  */
220
209
  export interface PollDispatchRecordsOptions {
221
- readonly ide: 'trae' | 'trae-cn' | 'codex' | 'cursor';
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
- * `awaitByLlmFallback` to a real `awaitBatch` (file-based polling,
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
- // trae-cn / codex / cursor wrappers below. The new typed outcome
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 4 non-Claude IDEs
255
- // (trae / trae-cn / codex / cursor) prefix the note with their
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 = /\b(it|test)(\.[A-Za-z]+)*\(/;
132
- const TEST_CASE_ERE = '\\b(it|test)(\\.[A-Za-z]+)*\\(';
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 = resolve(projectRoot).split(sep);
42
- const fileParts = resolve(file).split(sep);
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
- return recordPath;
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
- ide: "ide";
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.projectRoot !== projectRoot || info.sessionId !== sessionId) {
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 is a PreToolUse hook allow-list that bypasses the
6
- * Claude Code [Fact-Forcing Gate] for tool calls whose paths target
7
- * the peaks-managed `.peaks/` workspace. Without this bypass,
8
- * `peaks workspace init` (Step 0 of every peaks-code session) is
9
- * unrunnable in a consumer project because the gate blocks the very
10
- * first Write.
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
- * One matcher is emitted:
17
- * 1. `Write|Edit|MultiEdit` — a `node <script>` handler that runs the
18
- * path gate shipped at `src/services/hooks/write-gate.js`. Exits 0
19
- * (allow) for the paths the gate skips, exit 1 (deny → fall through to
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.7.0";
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 AND the on-disk `env` already carries every
112
- * exemption the template declares (extra on-disk keys and extra globs are
113
- * allowed — a user may exempt other trees, and a requirement the file already
114
- * exceeds must not re-trigger a write).
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.2.0, only the `Write|Edit|MultiEdit`
196
- * matcher is emitted. Bash command enforcement is the responsibility
197
- * of `peaks gate enforce`, which `peaks hooks install` injects into
198
- * `.claude/settings.json` (not `.claude/settings.local.json`).
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 {};