peaks-loop 3.0.0 → 3.0.2

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 (244) hide show
  1. package/.claude-plugin/marketplace.json +3 -3
  2. package/CHANGELOG.md +94 -59
  3. package/README-en.md +2 -2
  4. package/README.md +2 -2
  5. package/agents/karpathy-reviewer.md +2 -2
  6. package/dist/src/cli/commands/agent-commands.js +3 -3
  7. package/dist/src/cli/commands/audit-commands.d.ts +1 -1
  8. package/dist/src/cli/commands/audit-commands.js +6 -6
  9. package/dist/src/cli/commands/classify-classify-commands.js +1 -1
  10. package/dist/src/cli/commands/code-review-commands.d.ts +3 -3
  11. package/dist/src/cli/commands/code-review-commands.js +5 -5
  12. package/dist/src/cli/commands/compact-command.d.ts +21 -0
  13. package/dist/src/cli/commands/compact-command.js +252 -0
  14. package/dist/src/cli/commands/context-commands.d.ts +1 -1
  15. package/dist/src/cli/commands/context-commands.js +1 -1
  16. package/dist/src/cli/commands/contract-commands.d.ts +1 -1
  17. package/dist/src/cli/commands/core/session-command.js +17 -7
  18. package/dist/src/cli/commands/core/skill-command.js +1 -1
  19. package/dist/src/cli/commands/feedback-commands.js +1 -1
  20. package/dist/src/cli/commands/hook-handle.d.ts +1 -1
  21. package/dist/src/cli/commands/hook-handle.js +1 -1
  22. package/dist/src/cli/commands/legacy-commands.d.ts +1 -1
  23. package/dist/src/cli/commands/legacy-commands.js +2 -2
  24. package/dist/src/cli/commands/log-commands.js +2 -2
  25. package/dist/src/cli/commands/loop-commands.d.ts +1 -1
  26. package/dist/src/cli/commands/loop-commands.js +1 -1
  27. package/dist/src/cli/commands/loop-eval-commands.d.ts +1 -1
  28. package/dist/src/cli/commands/loop-eval-commands.js +1 -1
  29. package/dist/src/cli/commands/playwright-commands.d.ts +1 -1
  30. package/dist/src/cli/commands/playwright-commands.js +2 -2
  31. package/dist/src/cli/commands/request-commands.js +40 -1
  32. package/dist/src/cli/commands/role-commands.js +1 -1
  33. package/dist/src/cli/commands/slice-commands.js +5 -5
  34. package/dist/src/cli/commands/understand-commands.js +36 -0
  35. package/dist/src/cli/commands/upgrade-commands.d.ts +1 -1
  36. package/dist/src/cli/commands/upgrade-commands.js +6 -6
  37. package/dist/src/cli/commands/workspace/init-command.js +2 -2
  38. package/dist/src/cli/program.js +10 -1
  39. package/dist/src/services/agent/ecc-agent-service.js +5 -5
  40. package/dist/src/services/audit/artifact-writer.d.ts +1 -1
  41. package/dist/src/services/audit/artifact-writer.js +1 -1
  42. package/dist/src/services/audit/decision-writer.d.ts +1 -1
  43. package/dist/src/services/audit/decision-writer.js +1 -1
  44. package/dist/src/services/audit/enforcers/lint-output-style.js +5 -5
  45. package/dist/src/services/audit/enforcers/mock-placement.d.ts +1 -1
  46. package/dist/src/services/audit/enforcers/mock-placement.js +1 -1
  47. package/dist/src/services/audit/enforcers/no-root-pollution.js +1 -1
  48. package/dist/src/services/audit/red-line-catalog-p2-a.js +2 -2
  49. package/dist/src/services/audit/red-line-catalog-p2-b.js +2 -2
  50. package/dist/src/services/audit/static-service.d.ts +1 -1
  51. package/dist/src/services/audit/static-service.js +5 -5
  52. package/dist/src/services/audit/types.d.ts +1 -1
  53. package/dist/src/services/audit/types.js +1 -1
  54. package/dist/src/services/audit-independent/perf-audit-service.js +1 -1
  55. package/dist/src/services/audit-independent/security-audit-service.js +1 -1
  56. package/dist/src/services/classify/classify-service.d.ts +1 -1
  57. package/dist/src/services/classify/classify-service.js +1 -1
  58. package/dist/src/services/classify/classify-types.d.ts +1 -1
  59. package/dist/src/services/classify/classify-types.js +1 -1
  60. package/dist/src/services/code-review/ecc-bridge.d.ts +2 -2
  61. package/dist/src/services/code-review/ecc-bridge.js +2 -2
  62. package/dist/src/services/code-review/ocr-service.d.ts +9 -9
  63. package/dist/src/services/code-review/ocr-service.js +16 -16
  64. package/dist/src/services/compact/decision-tables.d.ts +66 -0
  65. package/dist/src/services/compact/decision-tables.js +127 -0
  66. package/dist/src/services/compact/request-transition-hook.d.ts +20 -0
  67. package/dist/src/services/compact/request-transition-hook.js +110 -0
  68. package/dist/src/services/compact/suggest-service.d.ts +74 -0
  69. package/dist/src/services/compact/suggest-service.js +203 -0
  70. package/dist/src/services/config/config-migration.js +1 -1
  71. package/dist/src/services/config/config-safety.d.ts +1 -1
  72. package/dist/src/services/config/config-safety.js +1 -1
  73. package/dist/src/services/config/config-service.d.ts +1 -1
  74. package/dist/src/services/config/config-service.js +1 -1
  75. package/dist/src/services/context/auto-compact-dispatcher.js +4 -4
  76. package/dist/src/services/context/auto-compact-types.d.ts +6 -6
  77. package/dist/src/services/context/auto-compact-types.js +5 -5
  78. package/dist/src/services/dispatch/sub-agent-dispatcher.js +1 -1
  79. package/dist/src/services/dispatch/test-tool-detection.d.ts +1 -1
  80. package/dist/src/services/dispatch/test-tool-detection.js +1 -1
  81. package/dist/src/services/doctor/doctor-service.d.ts +1 -1
  82. package/dist/src/services/doctor/doctor-service.js +5 -5
  83. package/dist/src/services/hooks/presence-marker-detector.js +5 -5
  84. package/dist/src/services/ide/adapters/claude-code-adapter.d.ts +1 -1
  85. package/dist/src/services/ide/adapters/claude-code-adapter.js +2 -2
  86. package/dist/src/services/ide/adapters/codex-adapter.d.ts +2 -2
  87. package/dist/src/services/ide/adapters/codex-adapter.js +2 -2
  88. package/dist/src/services/ide/adapters/cursor-adapter.d.ts +2 -2
  89. package/dist/src/services/ide/adapters/cursor-adapter.js +2 -2
  90. package/dist/src/services/ide/adapters/hermes-adapter.d.ts +1 -1
  91. package/dist/src/services/ide/adapters/hermes-adapter.js +1 -1
  92. package/dist/src/services/ide/adapters/openclaw-adapter.d.ts +1 -1
  93. package/dist/src/services/ide/adapters/openclaw-adapter.js +1 -1
  94. package/dist/src/services/ide/adapters/trae-adapter.d.ts +1 -1
  95. package/dist/src/services/ide/adapters/trae-adapter.js +1 -1
  96. package/dist/src/services/ide/ide-types.d.ts +9 -9
  97. package/dist/src/services/legacy/legacy-detector.d.ts +1 -1
  98. package/dist/src/services/legacy/legacy-detector.js +1 -1
  99. package/dist/src/services/log/log-commands-service.d.ts +1 -1
  100. package/dist/src/services/log/log-commands-service.js +1 -1
  101. package/dist/src/services/log/logger.d.ts +3 -3
  102. package/dist/src/services/log/logger.js +3 -3
  103. package/dist/src/services/log/redact.d.ts +1 -1
  104. package/dist/src/services/log/redact.js +1 -1
  105. package/dist/src/services/loop/evaluator-dispatcher.d.ts +1 -1
  106. package/dist/src/services/loop/evaluator-dispatcher.js +16 -15
  107. package/dist/src/services/loop/monotonic-guard.js +35 -18
  108. package/dist/src/services/loop/monotonic-runner.d.ts +3 -0
  109. package/dist/src/services/loop/monotonic-runner.js +62 -28
  110. package/dist/src/services/loop/run-driver.js +45 -24
  111. package/dist/src/services/memory/llm-reranker.d.ts +1 -1
  112. package/dist/src/services/memory/llm-reranker.js +1 -1
  113. package/dist/src/services/mut/production-stryker.d.ts +0 -5
  114. package/dist/src/services/mut/production-stryker.js +19 -10
  115. package/dist/src/services/openspec/openspec-propose-from-doctor-service.d.ts +1 -1
  116. package/dist/src/services/openspec/openspec-propose-from-doctor-service.js +1 -1
  117. package/dist/src/services/perf/perf-baseline-service.d.ts +2 -2
  118. package/dist/src/services/perf/perf-baseline-service.js +2 -2
  119. package/dist/src/services/prd/handoff-auto-regen.js +1 -1
  120. package/dist/src/services/prd/project-scan-sediment.js +3 -3
  121. package/dist/src/services/prd/project-scan-types.d.ts +1 -1
  122. package/dist/src/services/preferences/preferences-types.d.ts +3 -3
  123. package/dist/src/services/preferences/preferences-types.js +2 -2
  124. package/dist/src/services/role/role-registry.d.ts +1 -1
  125. package/dist/src/services/role/role-registry.js +1 -1
  126. package/dist/src/services/sc/sc-service.js +3 -3
  127. package/dist/src/services/skill/resume-detector.js +2 -2
  128. package/dist/src/services/skills/sync-service.d.ts +3 -3
  129. package/dist/src/services/skills/sync-service.js +9 -9
  130. package/dist/src/services/slice/calibration-store.d.ts +1 -1
  131. package/dist/src/services/slice/calibration-store.js +1 -1
  132. package/dist/src/services/solo/auto-compact-orchestrator.d.ts +1 -1
  133. package/dist/src/services/solo/auto-compact-orchestrator.js +7 -7
  134. package/dist/src/services/solo/dag-orchestrator.js +1 -1
  135. package/dist/src/services/solo/mode-gate.d.ts +1 -1
  136. package/dist/src/services/solo/mode-gate.js +4 -4
  137. package/dist/src/services/solo/user-touchpoint-classifier.js +1 -1
  138. package/dist/src/services/standards/migrate-claude-rules-service.js +5 -5
  139. package/dist/src/services/standards/migrate-service.d.ts +3 -3
  140. package/dist/src/services/standards/migrate-service.js +5 -5
  141. package/dist/src/services/standards/project-standards-service.js +1 -1
  142. package/dist/src/services/understand/hybrid-types.d.ts +32 -0
  143. package/dist/src/services/understand/hybrid-types.js +1 -0
  144. package/dist/src/services/understand/understand-hybrid-service.d.ts +10 -0
  145. package/dist/src/services/understand/understand-hybrid-service.js +100 -0
  146. package/dist/src/services/upgrade/gitignore-migrate-service.d.ts +3 -3
  147. package/dist/src/services/upgrade/gitignore-migrate-service.js +4 -4
  148. package/dist/src/services/upgrade/upgrade-service.d.ts +1 -1
  149. package/dist/src/services/upgrade/upgrade-service.js +5 -5
  150. package/dist/src/services/verdict/envelopes.d.ts +1 -1
  151. package/dist/src/services/verdict/envelopes.js +1 -1
  152. package/dist/src/services/workflow/workflow-loader.js +1 -1
  153. package/dist/src/services/workspace/migrate-1-4-1-service.d.ts +1 -1
  154. package/dist/src/services/workspace/migrate-1-4-1-service.js +1 -1
  155. package/dist/src/services/workspace/migrate-types.d.ts +1 -1
  156. package/dist/src/services/workspace/migrate-types.js +1 -1
  157. package/dist/src/services/workspace/workspace-claude-settings-materializer.d.ts +2 -2
  158. package/dist/src/services/workspace/workspace-claude-settings-materializer.js +9 -9
  159. package/dist/src/services/workspace/workspace-service.d.ts +1 -1
  160. package/dist/src/services/workspace/workspace-service.js +1 -1
  161. package/dist/src/shared/path-safety.d.ts +1 -1
  162. package/dist/src/shared/path-safety.js +1 -1
  163. package/dist/src/shared/version.d.ts +1 -1
  164. package/dist/src/shared/version.js +1 -1
  165. package/output-styles/peaks-skill-swarm.md +33 -33
  166. package/package.json +5 -4
  167. package/schemas/decomposition-v1.json +1 -1
  168. package/schemas/decomposition-v2.json +1 -1
  169. package/schemas/replay-fixture.schema.json +1 -1
  170. package/schemas/reviewer-envelope.schema.json +1 -1
  171. package/scripts/install-skills.mjs +11 -11
  172. package/skills/peaks-audit/SKILL.md +2 -2
  173. package/skills/peaks-doctor/SKILL.md +4 -4
  174. package/skills/peaks-final-review/SKILL.md +2 -2
  175. package/skills/peaks-ide/SKILL.md +3 -3
  176. package/skills/peaks-perf-audit/SKILL.md +1 -1
  177. package/skills/peaks-prd/SKILL.md +14 -14
  178. package/skills/peaks-prd/references/workflow.md +1 -1
  179. package/skills/peaks-qa/SKILL.md +17 -17
  180. package/skills/peaks-qa/references/artifact-per-request.md +1 -1
  181. package/skills/peaks-qa/references/browser-validation-contracts.md +2 -2
  182. package/skills/peaks-qa/references/codegraph-regression-focus.md +1 -1
  183. package/skills/peaks-qa/references/external-capability-guidance.md +2 -2
  184. package/skills/peaks-qa/references/qa-fanout-contract.md +1 -1
  185. package/skills/peaks-qa/references/qa-gstack-integration.md +3 -3
  186. package/skills/peaks-qa/references/qa-local-artifacts.md +1 -1
  187. package/skills/peaks-qa/references/qa-matt-pocock-integration.md +1 -1
  188. package/skills/peaks-qa/references/qa-runbook.md +3 -3
  189. package/skills/peaks-qa/references/qa-skill-presence.md +1 -1
  190. package/skills/peaks-qa/references/qa-standards-preflight.md +2 -2
  191. package/skills/peaks-qa/references/qa-transition-gates.md +9 -9
  192. package/skills/peaks-qa/references/regression-gates.md +1 -1
  193. package/skills/peaks-rd/SKILL.md +13 -13
  194. package/skills/peaks-rd/references/artifact-and-standards-output.md +1 -1
  195. package/skills/peaks-rd/references/codegraph-project-analysis.md +1 -1
  196. package/skills/peaks-rd/references/external-references.md +3 -3
  197. package/skills/peaks-rd/references/karpathy-reviewer-prompt.md +1 -1
  198. package/skills/peaks-rd/references/mandatory-perf-baseline.md +1 -1
  199. package/skills/peaks-rd/references/matt-pocock-integration.md +2 -2
  200. package/skills/peaks-rd/references/ocr-integration.md +19 -19
  201. package/skills/peaks-rd/references/openspec-cli.md +2 -2
  202. package/skills/peaks-rd/references/rd-gstack-integration.md +5 -5
  203. package/skills/peaks-rd/references/rd-runbook.md +9 -9
  204. package/skills/peaks-rd/references/rd-standards-preflight.md +1 -1
  205. package/skills/peaks-rd/references/rd-transition-gates.md +13 -13
  206. package/skills/peaks-rd/references/skill-presence-and-title.md +1 -1
  207. package/skills/peaks-reviewer/SKILL.md +2 -2
  208. package/skills/peaks-sc/SKILL.md +9 -9
  209. package/skills/peaks-security-audit/SKILL.md +1 -1
  210. package/skills/peaks-slice-decompose/SKILL.md +2 -2
  211. package/skills/peaks-solo/SKILL.md +49 -49
  212. package/skills/peaks-solo/references/a2a-artifact-mapping.md +8 -8
  213. package/skills/peaks-solo/references/anchoring-and-session-info.md +3 -3
  214. package/skills/peaks-solo/references/boundaries.md +4 -4
  215. package/skills/peaks-solo/references/browser-workflow.md +2 -2
  216. package/skills/peaks-solo/references/codegraph-orchestration.md +1 -1
  217. package/skills/peaks-solo/references/completion-handoff.md +2 -2
  218. package/skills/peaks-solo/references/external-references.md +3 -3
  219. package/skills/peaks-solo/references/external-skill-invocation.md +2 -2
  220. package/skills/peaks-solo/references/frontend-only-mode.md +1 -1
  221. package/skills/peaks-solo/references/gstack-integration.md +4 -4
  222. package/skills/peaks-solo/references/local-artifact-workspace.md +2 -2
  223. package/skills/peaks-solo/references/micro-cycle.md +4 -4
  224. package/skills/peaks-solo/references/mode-selection.md +5 -5
  225. package/skills/peaks-solo/references/openspec-workflow.md +2 -2
  226. package/skills/peaks-solo/references/playwright-mcp-multi-terminal.md +1 -1
  227. package/skills/peaks-solo/references/project-memory-loading.md +1 -1
  228. package/skills/peaks-solo/references/project-scan-checklist.md +1 -1
  229. package/skills/peaks-solo/references/quality-gate-cheatsheet.md +1 -1
  230. package/skills/peaks-solo/references/resume-detection.md +1 -1
  231. package/skills/peaks-solo/references/runbook.md +20 -20
  232. package/skills/peaks-solo/references/skill-presence-and-title.md +2 -2
  233. package/skills/peaks-solo/references/standards-preflight.md +2 -2
  234. package/skills/peaks-solo/references/step-0-55-1x-detection.md +3 -3
  235. package/skills/peaks-solo/references/sub-agent-dispatch.md +3 -3
  236. package/skills/peaks-solo/references/swarm-dispatch-contract.md +3 -3
  237. package/skills/peaks-solo/references/workflow-gates-and-types.md +34 -34
  238. package/skills/peaks-solo-resume/SKILL.md +2 -2
  239. package/skills/peaks-solo-status/SKILL.md +4 -4
  240. package/skills/peaks-solo-test/SKILL.md +4 -4
  241. package/skills/peaks-sop/SKILL.md +5 -5
  242. package/skills/peaks-txt/SKILL.md +17 -17
  243. package/skills/peaks-ui/SKILL.md +17 -17
  244. package/skills/peaks-ui/references/workflow.md +1 -1
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * peaks 自有 hook 协议 + slim IDE adapter 接口。
3
3
  *
4
- * peaks-cli 不再适配 IDE 私有的 hook 协议;反之 peaks 定义自己的 canonical
4
+ * peaks-loop 不再适配 IDE 私有的 hook 协议;反之 peaks 定义自己的 canonical
5
5
  * schema,每个 IDE 只需要填 4 字符串 + 1 settings 函数,新 IDE 适配变成"填表"。
6
6
  *
7
7
  * 不可消除的 per-IDE 字段(诚实交代,见 PRD R-1..R-4):
@@ -97,9 +97,9 @@ export interface IdeAdapter {
97
97
  readonly skillInstall?: IdeSkillInstall;
98
98
  /**
99
99
  * v2.13.0 auto-compact (AC-1 + AC-3): per-IDE compact-capability
100
- * descriptor. When `undefined`, peaks-cli falls back to the
100
+ * descriptor. When `undefined`, peaks-loop falls back to the
101
101
  * `llm-self-compress` pathway (the LLM summarizes its own context).
102
- * Adapters that fill this expose a 4-stage protocol so peaks-cli
102
+ * Adapters that fill this expose a 4-stage protocol so peaks-loop
103
103
  * can drive compact autonomously:
104
104
  *
105
105
  * 1. `envVarForContextPercent` — env-var the IDE sets per turn
@@ -108,10 +108,10 @@ export interface IdeAdapter {
108
108
  * accepts to trigger compact (e.g. `/compact`). Dispatched
109
109
  * by AC-3.
110
110
  * 3. `compactPathway` — `'shell-exec' | 'ide-native' |
111
- * 'llm-self-compress' | 'noop'`. `shell-exec` means peaks-cli
111
+ * 'llm-self-compress' | 'noop'`. `shell-exec` means peaks-loop
112
112
  * spawns `compactCommand` via `child_process.spawn` (zero IDE
113
113
  * hook required). `ide-native` means the IDE exposes a hook
114
- * surface peaks-cli can write to. `llm-self-compress` is the
114
+ * surface peaks-loop can write to. `llm-self-compress` is the
115
115
  * fallback when no compact capability is registered.
116
116
  * 4. `postCompactDetectCommand` (optional) — command the LLM
117
117
  * runner can invoke after compact to confirm ratio dropped.
@@ -142,16 +142,16 @@ export interface IdeCompactProfile {
142
142
  */
143
143
  readonly compactCommand: string;
144
144
  /**
145
- * `shell-exec` — peaks-cli spawns the command via child_process
145
+ * `shell-exec` — peaks-loop spawns the command via child_process
146
146
  * (works for any IDE that accepts a slash command
147
147
  * via a shell-spawnable entry point).
148
- * `ide-native` — peaks-cli writes to an IDE-specific hook file;
148
+ * `ide-native` — peaks-loop writes to an IDE-specific hook file;
149
149
  * used when the IDE requires a registered hook
150
150
  * rather than a runtime command.
151
- * `llm-self-compress` — peaks-cli prompts the LLM to summarize
151
+ * `llm-self-compress` — peaks-loop prompts the LLM to summarize
152
152
  * its own context (no IDE integration required;
153
153
  * least precise but always available).
154
- * `noop` — peaks-cli records the intent but performs no action;
154
+ * `noop` — peaks-loop records the intent but performs no action;
155
155
  * used by IDEs that explicitly opt out (e.g. legacy
156
156
  * adapters still on the v2.11.x model).
157
157
  */
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * v2.15.0 follow-up — G8: legacy code detector.
3
3
  *
4
- * 12 Gaps memory: when peaks-cli is applied to a 存量老项目 (legacy
4
+ * 12 Gaps memory: when peaks-loop is applied to a 存量老项目 (legacy
5
5
  * codebase), it is helpful to surface a quick inventory of "what
6
6
  * smells old" so the LLM / operator knows where to focus.
7
7
  *
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * v2.15.0 follow-up — G8: legacy code detector.
3
3
  *
4
- * 12 Gaps memory: when peaks-cli is applied to a 存量老项目 (legacy
4
+ * 12 Gaps memory: when peaks-loop is applied to a 存量老项目 (legacy
5
5
  * codebase), it is helpful to surface a quick inventory of "what
6
6
  * smells old" so the LLM / operator knows where to focus.
7
7
  *
@@ -12,7 +12,7 @@
12
12
  */
13
13
  import { type LogEntry } from './logger.js';
14
14
  /**
15
- * Return all `peaks-cli-*.log` files in the log dir, sorted by
15
+ * Return all `peaks-loop-*.log` files in the log dir, sorted by
16
16
  * date descending (newest first). Returns `[]` when the dir is
17
17
  * missing or unreadable. Non-matching entries (e.g. a stray
18
18
  * README) are filtered out.
@@ -15,7 +15,7 @@ import { join } from 'node:path';
15
15
  import { buildLogFileName, readLogEntries, resolveLogDir } from './logger.js';
16
16
  const LOG_FILE_NAME_PATTERN = /^peaks-loop-\d{4}-\d{2}-\d{2}\.log$/;
17
17
  /**
18
- * Return all `peaks-cli-*.log` files in the log dir, sorted by
18
+ * Return all `peaks-loop-*.log` files in the log dir, sorted by
19
19
  * date descending (newest first). Returns `[]` when the dir is
20
20
  * missing or unreadable. Non-matching entries (e.g. a stray
21
21
  * README) are filtered out.
@@ -1,10 +1,10 @@
1
1
  /**
2
- * JSONL file logger for peaks-cli.
2
+ * JSONL file logger for peaks-loop.
3
3
  *
4
4
  * Slice 2026-06-16-cli-logging (G1, G2, G5, G6, G7).
5
5
  *
6
- * Default-on file logging: every peaks-cli invocation writes a
7
- * structured log entry to `<homedir>/.peaks/logs/peaks-cli-YYYY-MM-DD.log`
6
+ * Default-on file logging: every peaks-loop invocation writes a
7
+ * structured log entry to `<homedir>/.peaks/logs/peaks-loop-YYYY-MM-DD.log`
8
8
  * (UTC date stamp). One JSON object per line.
9
9
  *
10
10
  * Hard contracts enforced here:
@@ -1,10 +1,10 @@
1
1
  /**
2
- * JSONL file logger for peaks-cli.
2
+ * JSONL file logger for peaks-loop.
3
3
  *
4
4
  * Slice 2026-06-16-cli-logging (G1, G2, G5, G6, G7).
5
5
  *
6
- * Default-on file logging: every peaks-cli invocation writes a
7
- * structured log entry to `<homedir>/.peaks/logs/peaks-cli-YYYY-MM-DD.log`
6
+ * Default-on file logging: every peaks-loop invocation writes a
7
+ * structured log entry to `<homedir>/.peaks/logs/peaks-loop-YYYY-MM-DD.log`
8
8
  * (UTC date stamp). One JSON object per line.
9
9
  *
10
10
  * Hard contracts enforced here:
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Secret redaction for peaks-cli JSONL log lines.
2
+ * Secret redaction for peaks-loop JSONL log lines.
3
3
  *
4
4
  * Slice 2026-06-16-cli-logging (G6). The logger must NEVER write
5
5
  * a raw secret to disk. We redact at two levels:
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Secret redaction for peaks-cli JSONL log lines.
2
+ * Secret redaction for peaks-loop JSONL log lines.
3
3
  *
4
4
  * Slice 2026-06-16-cli-logging (G6). The logger must NEVER write
5
5
  * a raw secret to disk. We redact at two levels:
@@ -19,7 +19,7 @@ export interface EvaluatorVerdictEnvelope {
19
19
  readonly wallSeconds: number;
20
20
  /** When true, the evaluator fell back to a stub because the binary was
21
21
  * unavailable in this environment. Surfaces in the verdict envelope so
22
- * the user can rerun on a real peaks-cli install. */
22
+ * the user can rerun on a real peaks-loop install. */
23
23
  readonly degraded: boolean;
24
24
  }
25
25
  export interface DispatchOptions {
@@ -3,7 +3,7 @@
3
3
  *
4
4
  * Evaluator-as-primitive dispatcher. Each of the 4 evaluator types
5
5
  * (karpathy / code-review / security-review / perf-baseline) maps to
6
- * an existing peaks-cli CLI surface; the dispatcher shells out to the
6
+ * an existing peaks-loop CLI surface; the dispatcher shells out to the
7
7
  * same binary so verdict shape stays byte-compatible with the
8
8
  * `verdict-aggregator` envelope union (`karpathy` / `security` / `perf`).
9
9
  *
@@ -195,7 +195,7 @@ function dispatchCanaryWatch(opts, started) {
195
195
  function parseGenericEnvelope(stdout, exitCode, started, kind, summaryPrefix) {
196
196
  const wall = (Date.now() - started) / 1000;
197
197
  const parsed = safeJson(stdout);
198
- if (parsed === null) {
198
+ if (!parsed.ok) {
199
199
  return {
200
200
  kind,
201
201
  passed: exitCode === 0,
@@ -206,7 +206,7 @@ function parseGenericEnvelope(stdout, exitCode, started, kind, summaryPrefix) {
206
206
  degraded: true
207
207
  };
208
208
  }
209
- const obj = parsed;
209
+ const obj = parsed.value;
210
210
  const data = (obj['data'] ?? obj);
211
211
  return {
212
212
  kind,
@@ -308,7 +308,7 @@ function gateActionFromVerdict(verdict) {
308
308
  function parseKarpathyEnvelope(stdout, exitCode, started) {
309
309
  const wall = (Date.now() - started) / 1000;
310
310
  const parsed = safeJson(stdout);
311
- if (parsed === null) {
311
+ if (!parsed.ok) {
312
312
  return {
313
313
  kind: 'karpathy',
314
314
  passed: exitCode === 0,
@@ -319,7 +319,7 @@ function parseKarpathyEnvelope(stdout, exitCode, started) {
319
319
  degraded: true
320
320
  };
321
321
  }
322
- const obj = parsed;
322
+ const obj = parsed.value;
323
323
  const data = (obj['data'] ?? obj);
324
324
  const passed = data['passed'] === true;
325
325
  const gateAction = typeof data['gateAction'] === 'string' ? gateActionFromVerdict(data['gateAction']) : (passed ? 'pass' : 'block');
@@ -342,7 +342,7 @@ function parseCodeReviewEnvelope(stdout, exitCode, started) {
342
342
  function parseSecurityEnvelope(stdout, exitCode, started) {
343
343
  const wall = (Date.now() - started) / 1000;
344
344
  const parsed = safeJson(stdout);
345
- if (parsed === null) {
345
+ if (!parsed.ok) {
346
346
  return {
347
347
  kind: 'security-review',
348
348
  passed: exitCode === 0,
@@ -353,7 +353,7 @@ function parseSecurityEnvelope(stdout, exitCode, started) {
353
353
  degraded: true
354
354
  };
355
355
  }
356
- const obj = parsed;
356
+ const obj = parsed.value;
357
357
  const data = (obj['data'] ?? obj);
358
358
  const verdict = typeof data['verdict'] === 'string' ? data['verdict'] : (exitCode === 0 ? 'pass' : 'warn');
359
359
  const violationsRaw = Array.isArray(data['violations']) ? data['violations'] : [];
@@ -371,7 +371,7 @@ function parseSecurityEnvelope(stdout, exitCode, started) {
371
371
  function parsePerfEnvelope(stdout, exitCode, started) {
372
372
  const wall = (Date.now() - started) / 1000;
373
373
  const parsed = safeJson(stdout);
374
- if (parsed === null) {
374
+ if (!parsed.ok) {
375
375
  return {
376
376
  kind: 'perf-baseline',
377
377
  passed: exitCode === 0,
@@ -382,7 +382,7 @@ function parsePerfEnvelope(stdout, exitCode, started) {
382
382
  degraded: true
383
383
  };
384
384
  }
385
- const obj = parsed;
385
+ const obj = parsed.value;
386
386
  const data = (obj['data'] ?? obj);
387
387
  const verdict = typeof data['verdict'] === 'string' ? data['verdict'] : (exitCode === 0 ? 'pass' : 'warn');
388
388
  const violationsRaw = Array.isArray(data['violations']) ? data['violations'] : [];
@@ -400,7 +400,7 @@ function parsePerfEnvelope(stdout, exitCode, started) {
400
400
  function parseVerdictAggregateEnvelope(stdout, exitCode, started) {
401
401
  const wall = (Date.now() - started) / 1000;
402
402
  const parsed = safeJson(stdout);
403
- if (parsed === null) {
403
+ if (!parsed.ok) {
404
404
  return {
405
405
  kind: 'verdict-aggregate',
406
406
  passed: exitCode === 0,
@@ -411,7 +411,7 @@ function parseVerdictAggregateEnvelope(stdout, exitCode, started) {
411
411
  degraded: true
412
412
  };
413
413
  }
414
- const obj = parsed;
414
+ const obj = parsed.value;
415
415
  const data = (obj['data'] ?? obj);
416
416
  const verdict = typeof data['verdict'] === 'string' ? data['verdict'] : (exitCode === 0 ? 'pass' : 'block');
417
417
  const reasonsRaw = Array.isArray(data['reasons']) ? data['reasons'] : [];
@@ -457,13 +457,14 @@ function normalizeViolation(raw) {
457
457
  return out;
458
458
  }
459
459
  function safeJson(raw) {
460
- if (typeof raw !== 'string' || raw.length === 0)
461
- return null;
460
+ if (typeof raw !== 'string' || raw.length === 0) {
461
+ return { ok: false, reason: 'PARSE_ERROR' };
462
+ }
462
463
  try {
463
- return JSON.parse(raw);
464
+ return { ok: true, value: JSON.parse(raw) };
464
465
  }
465
466
  catch {
466
- return null;
467
+ return { ok: false, reason: 'PARSE_ERROR' };
467
468
  }
468
469
  }
469
470
  // Tiny ergonomic helper so we can re-emit an envelope with a different `kind`.
@@ -137,6 +137,12 @@ export function checkMonotonicImprovement(previous, current, options = {}) {
137
137
  code: 'MONOTONIC_OK'
138
138
  };
139
139
  }
140
+ function classifyFsError(err) {
141
+ const code = err?.code;
142
+ if (code === 'ENOENT')
143
+ return 'NOT_FOUND';
144
+ return 'IO_ERROR';
145
+ }
140
146
  /** Read `.peaks/_sub_agents/<sid>/shared/` cross-session signal — on
141
147
  * any IO error, return `null` so the guard never crashes on missing
142
148
  * cross-batch signal (per Slice C (b) case "跨 session 读
@@ -149,13 +155,17 @@ export function loadCrossSessionSignal(projectRoot, sid) {
149
155
  const fs = require('node:fs');
150
156
  const path = require('node:path');
151
157
  const sharedDir = path.join(projectRoot, '.peaks', '_sub_agents', sid, 'shared');
152
- let entries;
153
- try {
154
- entries = fs.readdirSync(sharedDir);
155
- }
156
- catch {
158
+ const readdir = (() => {
159
+ try {
160
+ return { ok: true, value: fs.readdirSync(sharedDir) };
161
+ }
162
+ catch (err) {
163
+ return { ok: false, reason: classifyFsError(err) };
164
+ }
165
+ })();
166
+ if (!readdir.ok)
157
167
  return null; // missing dir or permission denied — both are no-ops.
158
- }
168
+ const entries = readdir.value;
159
169
  // Pick the highest cycle number from the filenames; tolerate garbage.
160
170
  let best = null;
161
171
  for (const entry of entries) {
@@ -169,20 +179,27 @@ export function loadCrossSessionSignal(projectRoot, sid) {
169
179
  if (best === null)
170
180
  return null;
171
181
  const target = path.join(sharedDir, `cycle-${best}.json`);
172
- let raw;
173
- try {
174
- raw = fs.readFileSync(target, 'utf8');
175
- }
176
- catch {
182
+ const readFile = (() => {
183
+ try {
184
+ return { ok: true, value: fs.readFileSync(target, 'utf8') };
185
+ }
186
+ catch (err) {
187
+ return { ok: false, reason: classifyFsError(err) };
188
+ }
189
+ })();
190
+ if (!readFile.ok)
177
191
  return null;
178
- }
179
- let parsed;
180
- try {
181
- parsed = JSON.parse(raw);
182
- }
183
- catch {
192
+ const parse = (() => {
193
+ try {
194
+ return { ok: true, value: JSON.parse(readFile.value) };
195
+ }
196
+ catch {
197
+ return { ok: false, reason: 'PARSE_ERROR' };
198
+ }
199
+ })();
200
+ if (!parse.ok)
184
201
  return null;
185
- }
202
+ const parsed = parse.value;
186
203
  if (parsed === null || typeof parsed !== 'object')
187
204
  return null;
188
205
  const obj = parsed;
@@ -26,6 +26,9 @@ export interface RunMonotonicResult {
26
26
  readonly persistedAt: string | null;
27
27
  readonly rows: readonly MonotonicScoreRow[];
28
28
  readonly report: MonotonicReport;
29
+ /** Additive surface for non-fatal persistence warnings (e.g. mkdir
30
+ * failure). Optional so existing destructures keep compiling. */
31
+ readonly warnings?: readonly string[];
29
32
  }
30
33
  /** Resolve the slice dir used by both writer + reader — keeps tests
31
34
  * insulated from real sessions. */
@@ -22,6 +22,12 @@ import { join } from 'node:path';
22
22
  import { dispatchEvaluator } from './evaluator-dispatcher.js';
23
23
  import { checkMonotonicImprovement, toScoreRow, DEFAULT_MONOTONIC_THRESHOLD } from './monotonic-guard.js';
24
24
  import { findProjectRoot } from '../config/config-safety.js';
25
+ function classifyFsError(err) {
26
+ const code = err?.code;
27
+ if (code === 'ENOENT')
28
+ return 'NOT_FOUND';
29
+ return 'IO_ERROR';
30
+ }
25
31
  /** Set of evaluator kinds the loop walker actually scores — keeps the
26
32
  * guard surface tight (the verdict-aggregate is the cross-source merge
27
33
  * and not a per-cycle input). */
@@ -51,13 +57,17 @@ function loadMostRecentCycleFromSubAgents(projectRoot, sid) {
51
57
  function loadMostRecentCycle(dir) {
52
58
  if (!existsSync(dir))
53
59
  return null;
54
- let entries;
55
- try {
56
- entries = require('node:fs').readdirSync(dir);
57
- }
58
- catch {
60
+ const readdir = (() => {
61
+ try {
62
+ return { ok: true, value: require('node:fs').readdirSync(dir) };
63
+ }
64
+ catch (err) {
65
+ return { ok: false, reason: classifyFsError(err) };
66
+ }
67
+ })();
68
+ if (!readdir.ok)
59
69
  return null;
60
- }
70
+ const entries = readdir.value;
61
71
  let bestCycle = null;
62
72
  for (const entry of entries) {
63
73
  const m = entry.match(/^cycle-(\d+)\.json$/);
@@ -70,23 +80,30 @@ function loadMostRecentCycle(dir) {
70
80
  if (bestCycle === null)
71
81
  return null;
72
82
  const target = join(dir, `cycle-${bestCycle}.json`);
73
- let raw;
74
- try {
75
- raw = readFileSync(target, 'utf8');
76
- }
77
- catch {
83
+ const readFile = (() => {
84
+ try {
85
+ return { ok: true, value: readFileSync(target, 'utf8') };
86
+ }
87
+ catch (err) {
88
+ return { ok: false, reason: classifyFsError(err) };
89
+ }
90
+ })();
91
+ if (!readFile.ok)
78
92
  return null;
79
- }
80
- return parseCycle(raw, bestCycle);
93
+ return parseCycle(readFile.value, bestCycle);
81
94
  }
82
95
  function parseCycle(raw, fallbackCycle) {
83
- let parsed;
84
- try {
85
- parsed = JSON.parse(raw);
86
- }
87
- catch {
96
+ const parse = (() => {
97
+ try {
98
+ return { ok: true, value: JSON.parse(raw) };
99
+ }
100
+ catch {
101
+ return { ok: false, reason: 'PARSE_ERROR' };
102
+ }
103
+ })();
104
+ if (!parse.ok)
88
105
  return null;
89
- }
106
+ const parsed = parse.value;
90
107
  if (parsed === null || typeof parsed !== 'object')
91
108
  return null;
92
109
  const obj = parsed;
@@ -155,13 +172,20 @@ export function runMonotonicCheck(options) {
155
172
  const previousCycle = loadPreviousCycle(options.projectRoot, options.sid, options.rid);
156
173
  const report = checkMonotonicImprovement(previousCycle, currentCycle, { threshold });
157
174
  let persistedAt = null;
175
+ const envelopeWarns = [];
158
176
  if (persist) {
159
177
  const dir = sliceDir(options.projectRoot, options.sid, options.rid);
160
- try {
161
- mkdirSync(dir, { recursive: true });
162
- }
163
- catch {
164
- // swallow — persist failure is non-fatal
178
+ const mkdir = (() => {
179
+ try {
180
+ mkdirSync(dir, { recursive: true });
181
+ return { ok: true, value: undefined };
182
+ }
183
+ catch (err) {
184
+ return { ok: false, reason: classifyFsError(err) };
185
+ }
186
+ })();
187
+ if (!mkdir.ok) {
188
+ envelopeWarns.push(`mkdir-failed: ${dir} (${mkdir.reason})`);
165
189
  }
166
190
  const path = join(dir, `cycle-${cycle}.json`);
167
191
  const payload = JSON.stringify({
@@ -171,12 +195,21 @@ export function runMonotonicCheck(options) {
171
195
  persistedAt: new Date().toISOString(),
172
196
  scores: rows
173
197
  });
174
- try {
175
- writeFileSync(path, payload, 'utf8');
198
+ const writeFile = (() => {
199
+ try {
200
+ writeFileSync(path, payload, 'utf8');
201
+ return { ok: true, value: undefined };
202
+ }
203
+ catch (err) {
204
+ return { ok: false, reason: classifyFsError(err) };
205
+ }
206
+ })();
207
+ if (writeFile.ok) {
176
208
  persistedAt = path;
177
209
  }
178
- catch {
210
+ else {
179
211
  persistedAt = null;
212
+ envelopeWarns.push(`write-failed: ${path} (${writeFile.reason})`);
180
213
  }
181
214
  }
182
215
  return {
@@ -187,7 +220,8 @@ export function runMonotonicCheck(options) {
187
220
  previousCycle: previousCycle === null ? null : previousCycle.cycle,
188
221
  persistedAt,
189
222
  rows,
190
- report
223
+ report,
224
+ ...(envelopeWarns.length > 0 ? { warnings: envelopeWarns } : {})
191
225
  };
192
226
  }
193
227
  /** Helper for tests + CLI — resolve project root + sid consistently. */
@@ -33,6 +33,12 @@ import { dispatchEvaluator } from './evaluator-dispatcher.js';
33
33
  import { checkMonotonicImprovement, toScoreRow, DEFAULT_MONOTONIC_THRESHOLD } from './monotonic-guard.js';
34
34
  import { nextCycleIndex, sliceDir } from './monotonic-runner.js';
35
35
  import { findProjectRoot } from '../config/config-safety.js';
36
+ function classifyFsError(err) {
37
+ const code = err?.code;
38
+ if (code === 'ENOENT')
39
+ return 'NOT_FOUND';
40
+ return 'IO_ERROR';
41
+ }
36
42
  const ALLOWED_EVALUATOR_KINDS = new Set([
37
43
  'karpathy',
38
44
  'code-review',
@@ -65,12 +71,17 @@ export function cyclesDir(projectRoot, sid, rid) {
65
71
  * `cycle-<N>.json`. Returns the persisted path on success. */
66
72
  function persistCycleRecord(projectRoot, sid, rid, cycle, rows) {
67
73
  const dir = cyclesDir(projectRoot, sid, rid);
68
- try {
69
- mkdirSync(dir, { recursive: true });
70
- }
71
- catch {
74
+ const mkdir = (() => {
75
+ try {
76
+ mkdirSync(dir, { recursive: true });
77
+ return { ok: true, value: undefined };
78
+ }
79
+ catch (err) {
80
+ return { ok: false, reason: classifyFsError(err) };
81
+ }
82
+ })();
83
+ if (!mkdir.ok)
72
84
  return null;
73
- }
74
85
  const path = join(dir, `cycle-${cycle}.json`);
75
86
  const payload = JSON.stringify({
76
87
  cycle,
@@ -79,13 +90,16 @@ function persistCycleRecord(projectRoot, sid, rid, cycle, rows) {
79
90
  persistedAt: new Date().toISOString(),
80
91
  scores: rows
81
92
  });
82
- try {
83
- writeFileSync(path, payload, 'utf8');
84
- return path;
85
- }
86
- catch {
87
- return null;
88
- }
93
+ const writeFile = (() => {
94
+ try {
95
+ writeFileSync(path, payload, 'utf8');
96
+ return { ok: true, value: undefined };
97
+ }
98
+ catch (err) {
99
+ return { ok: false, reason: classifyFsError(err) };
100
+ }
101
+ })();
102
+ return writeFile.ok ? path : null;
89
103
  }
90
104
  /** Internal: build a CycleRecord from a (current, previous) pair. */
91
105
  function buildCycleRecord(cycle, rows, previous, threshold, persistedAt) {
@@ -332,20 +346,27 @@ function parseCycleFromPath(path, fallbackCycle) {
332
346
  // small and avoids leaking its internals).
333
347
  // eslint-disable-next-line @typescript-eslint/no-var-requires
334
348
  const fs = require('node:fs');
335
- let raw;
336
- try {
337
- raw = fs.readFileSync(path, 'utf8');
338
- }
339
- catch {
349
+ const readFile = (() => {
350
+ try {
351
+ return { ok: true, value: fs.readFileSync(path, 'utf8') };
352
+ }
353
+ catch (err) {
354
+ return { ok: false, reason: classifyFsError(err) };
355
+ }
356
+ })();
357
+ if (!readFile.ok)
340
358
  return null;
341
- }
342
- let parsed;
343
- try {
344
- parsed = JSON.parse(raw);
345
- }
346
- catch {
359
+ const parse = (() => {
360
+ try {
361
+ return { ok: true, value: JSON.parse(readFile.value) };
362
+ }
363
+ catch {
364
+ return { ok: false, reason: 'PARSE_ERROR' };
365
+ }
366
+ })();
367
+ if (!parse.ok)
347
368
  return null;
348
- }
369
+ const parsed = parse.value;
349
370
  if (parsed === null || typeof parsed !== 'object')
350
371
  return null;
351
372
  const obj = parsed;
@@ -8,7 +8,7 @@
8
8
  * Architecture note (locked decision — see
9
9
  * `.peaks/memory/2026-06-18-peaks-zvec-spike-proposal.md` §Y2):
10
10
  *
11
- * - "Active IDE LLM" is a deliberate abstraction: peaks-cli itself
11
+ * - "Active IDE LLM" is a deliberate abstraction: peaks-loop itself
12
12
  * has NO direct LLM API key. The chat call is performed by the
13
13
  * active IDE (Claude Code / Trae / Cursor / Codex / ...) using
14
14
  * its own authentication chain.
@@ -8,7 +8,7 @@
8
8
  * Architecture note (locked decision — see
9
9
  * `.peaks/memory/2026-06-18-peaks-zvec-spike-proposal.md` §Y2):
10
10
  *
11
- * - "Active IDE LLM" is a deliberate abstraction: peaks-cli itself
11
+ * - "Active IDE LLM" is a deliberate abstraction: peaks-loop itself
12
12
  * has NO direct LLM API key. The chat call is performed by the
13
13
  * active IDE (Claude Code / Trae / Cursor / Codex / ...) using
14
14
  * its own authentication chain.
@@ -1,7 +1,2 @@
1
- /**
2
- * Production Stryker invoker. Uses @stryker-mutator/core programmatic API.
3
- * Note: this is a thin wrapper — actual Stryker invocation requires the
4
- * Stryker config in `stryker.conf.js` to live at the project root.
5
- */
6
1
  import type { StrykerInvoker } from './mut-runner.js';
7
2
  export declare function createProductionStrykerInvoker(): StrykerInvoker;