peaks-loop 4.0.0-beta.14 → 4.0.0-beta.16

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 (204) hide show
  1. package/CHANGELOG.md +230 -148
  2. package/README-en.md +1 -1
  3. package/README.md +32 -1
  4. package/bin/peaks.js +0 -0
  5. package/dist/cli/cli-helpers.d.ts +1 -1
  6. package/dist/cli/cli-helpers.js +1 -1
  7. package/dist/cli/commands/adapter-commands-s2a.js +1 -1
  8. package/dist/cli/commands/asset-commands.js +33 -16
  9. package/dist/cli/commands/audit-commands.js +1 -1
  10. package/dist/cli/commands/bee-commands.js +1 -1
  11. package/dist/cli/commands/capability-commands.js +1 -1
  12. package/dist/cli/commands/classify-classify-commands.js +1 -1
  13. package/dist/cli/commands/code-commands.js +1 -1
  14. package/dist/cli/commands/code-review-commands.js +1 -1
  15. package/dist/cli/commands/codegraph-commands.js +1 -1
  16. package/dist/cli/commands/compact-command.js +1 -1
  17. package/dist/cli/commands/complexity-commands.js +1 -1
  18. package/dist/cli/commands/config-commands.js +1 -1
  19. package/dist/cli/commands/context-commands.js +1 -1
  20. package/dist/cli/commands/contract-commands.js +1 -1
  21. package/dist/cli/commands/core/artifacts-command.js +1 -1
  22. package/dist/cli/commands/core/binding-commands.js +1 -1
  23. package/dist/cli/commands/core/doctor-command.js +63 -3
  24. package/dist/cli/commands/core/memory-command.js +1 -1
  25. package/dist/cli/commands/core/profile-command.js +1 -1
  26. package/dist/cli/commands/core/proxy-command.js +1 -1
  27. package/dist/cli/commands/core/session-command.js +1 -1
  28. package/dist/cli/commands/core/skill-command.js +2 -2
  29. package/dist/cli/commands/core/standards-command.js +1 -1
  30. package/dist/cli/commands/dispatch-commands.js +2 -2
  31. package/dist/cli/commands/dispatch-from-dag.js +1 -1
  32. package/dist/cli/commands/doc-commands.js +1 -1
  33. package/dist/cli/commands/ecc-commands.js +2 -2
  34. package/dist/cli/commands/evolution-commands.js +1 -1
  35. package/dist/cli/commands/feedback-commands.js +1 -1
  36. package/dist/cli/commands/final-review-commands.js +1 -1
  37. package/dist/cli/commands/fixture-commands.js +1 -1
  38. package/dist/cli/commands/fork-commands.js +1 -1
  39. package/dist/cli/commands/gate-commands.js +1 -1
  40. package/dist/cli/commands/heartbeat-commands.js +1 -1
  41. package/dist/cli/commands/hook-handle.js +1 -1
  42. package/dist/cli/commands/hooks-commands.js +1 -1
  43. package/dist/cli/commands/ide-commands.js +1 -1
  44. package/dist/cli/commands/impact-commands.js +1 -1
  45. package/dist/cli/commands/job-commands.js +1 -1
  46. package/dist/cli/commands/legacy-commands.js +1 -1
  47. package/dist/cli/commands/log-commands.js +1 -1
  48. package/dist/cli/commands/loop-commands.js +1 -1
  49. package/dist/cli/commands/loop-eval-commands.js +1 -1
  50. package/dist/cli/commands/memory-commands.js +1 -1
  51. package/dist/cli/commands/migrate-1-4-1-command.js +1 -1
  52. package/dist/cli/commands/migrate-v2-10-to-v2-11-command.js +1 -1
  53. package/dist/cli/commands/mut-commands.d.ts +1 -1
  54. package/dist/cli/commands/mut-commands.js +1 -5
  55. package/dist/cli/commands/observability-commands.js +1 -1
  56. package/dist/cli/commands/openspec-commands.js +2 -2
  57. package/dist/cli/commands/perf-audit-commands.js +2 -2
  58. package/dist/cli/commands/perf-commands.js +1 -1
  59. package/dist/cli/commands/polyrepo-commands.js +1 -1
  60. package/dist/cli/commands/prd-blocks-commands.js +1 -1
  61. package/dist/cli/commands/prd-commands.js +1 -1
  62. package/dist/cli/commands/project-commands.js +1 -1
  63. package/dist/cli/commands/qa-business-review-commands.js +1 -1
  64. package/dist/cli/commands/qa-commands.d.ts +1 -1
  65. package/dist/cli/commands/qa-commands.js +2 -2
  66. package/dist/cli/commands/release-commands.js +1 -1
  67. package/dist/cli/commands/request-commands.js +1 -1
  68. package/dist/cli/commands/retrospective-commands.js +1 -1
  69. package/dist/cli/commands/reviewer-commands.js +1 -1
  70. package/dist/cli/commands/role-commands.js +1 -1
  71. package/dist/cli/commands/runtime-commands.js +1 -2
  72. package/dist/cli/commands/sc-commands.js +1 -1
  73. package/dist/cli/commands/scan-commands.js +1 -1
  74. package/dist/cli/commands/security-audit-commands.js +2 -2
  75. package/dist/cli/commands/share-commands.d.ts +19 -0
  76. package/dist/cli/commands/share-commands.js +121 -2
  77. package/dist/cli/commands/skill-conformance-commands.js +1 -1
  78. package/dist/cli/commands/skill-loop-engineering-readiness-commands.js +1 -1
  79. package/dist/cli/commands/skill-search-commands.js +1 -1
  80. package/dist/cli/commands/slice-commands.js +1 -1
  81. package/dist/cli/commands/slice-integrate-commands.js +1 -1
  82. package/dist/cli/commands/slice-review-commands.js +1 -1
  83. package/dist/cli/commands/smoke-commands.js +1 -1
  84. package/dist/cli/commands/sop-commands.js +1 -1
  85. package/dist/cli/commands/statusline-commands.js +1 -1
  86. package/dist/cli/commands/sub-agent-commands.js +2 -1
  87. package/dist/cli/commands/understand-commands.js +1 -1
  88. package/dist/cli/commands/upgrade-commands.js +1 -1
  89. package/dist/cli/commands/user-touchpoint-commands.js +1 -1
  90. package/dist/cli/commands/verdict-aggregate-command.js +1 -1
  91. package/dist/cli/commands/workflow-commands.js +1 -1
  92. package/dist/cli/commands/workflow-plan-commands.js +1 -1
  93. package/dist/cli/commands/workspace/init-command.js +1 -1
  94. package/dist/cli/commands/workspace/migrate-command.js +1 -1
  95. package/dist/cli/commands/workspace/reconcile-command.js +1 -1
  96. package/dist/cli/index.js +1 -1
  97. package/dist/cli/program.js +2 -2
  98. package/dist/services/artifacts/artifact-prerequisites.js +1 -1
  99. package/dist/services/artifacts/request-artifact-service.js +1 -1
  100. package/dist/services/artifacts/workspace-service.js +1 -1
  101. package/dist/services/code/auto-compact-orchestrator.js +5 -2
  102. package/dist/services/code-review/ocr-service.d.ts +1 -1
  103. package/dist/services/code-review/ocr-service.js +6 -3
  104. package/dist/services/config/config-types.js +1 -1
  105. package/dist/services/dashboard/project-dashboard-service.js +2 -2
  106. package/dist/services/dispatch/batch-counter.js +1 -1
  107. package/dist/services/dispatch/dispatch-record-writer.js +1 -1
  108. package/dist/services/job/job-progress-store.d.ts +2 -2
  109. package/dist/services/job/job-types.d.ts +27 -27
  110. package/dist/services/log/retention.js +1 -1
  111. package/dist/services/openspec/openspec-archive-service.js +1 -1
  112. package/dist/services/openspec/openspec-bridge-service.js +1 -1
  113. package/dist/services/openspec/openspec-init-service.js +1 -1
  114. package/dist/services/openspec/openspec-propose-from-doctor-service.js +1 -1
  115. package/dist/services/openspec/openspec-render-service.js +1 -1
  116. package/dist/services/openspec/openspec-scan-service.js +1 -1
  117. package/dist/services/openspec/openspec-validate-service.js +1 -1
  118. package/dist/services/scan/acceptance-coverage-service.js +1 -1
  119. package/dist/services/scan/archetype-service.js +1 -1
  120. package/dist/services/scan/existing-system-service.js +1 -1
  121. package/dist/services/scan/libraries-service.js +1 -1
  122. package/dist/services/skill/skill-search-service.d.ts +5 -5
  123. package/dist/services/skill/skill-search-service.js +2 -2
  124. package/dist/services/skills/skill-registry.js +2 -2
  125. package/dist/services/skills/skill-runbook-service.js +1 -1
  126. package/dist/services/slice/slice-check-service.js +1 -1
  127. package/dist/services/understand/understand-hybrid-service.js +1 -1
  128. package/dist/services/understand/understand-scan-service.js +2 -2
  129. package/dist/services/upgrade/upgrade-service.js +4 -3
  130. package/dist/services/verdict/envelopes.d.ts +2 -2
  131. package/dist/services/verdict/envelopes.js +2 -2
  132. package/dist/services/verdict/verdict-aggregator.d.ts +3 -3
  133. package/dist/services/workflow/autonomous-resume-writer.js +1 -1
  134. package/dist/services/workflow/plan-reader.d.ts +1 -1
  135. package/dist/services/workflow/plan-reader.js +1 -1
  136. package/dist/services/workflow/plan-refresher.d.ts +1 -1
  137. package/dist/services/workflow/plan-refresher.js +1 -1
  138. package/dist/services/workflow/plan-trigger-detector.d.ts +1 -1
  139. package/dist/services/workflow/plan-trigger-detector.js +1 -1
  140. package/dist/services/workflow/workflow-router-service.js +11 -9
  141. package/dist/services/workspace/migrate-service.js +1 -1
  142. package/dist/services/workspace/workspace-service.js +1 -1
  143. package/package.json +13 -8
  144. package/scripts/sync-version.mjs +8 -1
  145. package/skills/bee/peaks-rd/SKILL.md +14 -1
  146. package/skills/peaks-code/SKILL.md +44 -0
  147. package/skills/peaks-code/references/sub-agent-dispatch.md +30 -0
  148. package/dist/services/agent/ecc-cache-service.d.ts +0 -97
  149. package/dist/services/agent/ecc-cache-service.js +0 -491
  150. package/dist/services/audit-independent/perf-audit-service.d.ts +0 -151
  151. package/dist/services/audit-independent/perf-audit-service.js +0 -316
  152. package/dist/services/audit-independent/security-audit-service.d.ts +0 -155
  153. package/dist/services/audit-independent/security-audit-service.js +0 -316
  154. package/dist/services/context/dispatch-context-guard.d.ts +0 -27
  155. package/dist/services/context/dispatch-context-guard.js +0 -192
  156. package/dist/services/context/shared-channel.d.ts +0 -93
  157. package/dist/services/context/shared-channel.js +0 -308
  158. package/dist/services/crystallization/crystallization-service.d.ts +0 -239
  159. package/dist/services/crystallization/crystallization-service.js +0 -397
  160. package/dist/services/crystallization/crystallization-store.d.ts +0 -75
  161. package/dist/services/crystallization/crystallization-store.js +0 -193
  162. package/dist/services/crystallization/crystallization-types.d.ts +0 -313
  163. package/dist/services/crystallization/crystallization-types.js +0 -299
  164. package/dist/services/crystallization/evidence-brief-builder.d.ts +0 -237
  165. package/dist/services/crystallization/evidence-brief-builder.js +0 -240
  166. package/dist/services/doctor/doctor-service.d.ts +0 -149
  167. package/dist/services/doctor/doctor-service.js +0 -929
  168. package/dist/services/filesystem/file-lock.d.ts +0 -11
  169. package/dist/services/filesystem/file-lock.js +0 -152
  170. package/dist/services/final-review/final-review-service.d.ts +0 -12
  171. package/dist/services/final-review/final-review-service.js +0 -52
  172. package/dist/services/final-review/final-review-types.d.ts +0 -42
  173. package/dist/services/final-review/final-review-types.js +0 -18
  174. package/dist/services/job/job-resource-snapshot.d.ts +0 -7
  175. package/dist/services/job/job-resource-snapshot.js +0 -75
  176. package/dist/services/mut/assert-scanner.d.ts +0 -6
  177. package/dist/services/mut/assert-scanner.js +0 -116
  178. package/dist/services/mut/index.d.ts +0 -8
  179. package/dist/services/mut/index.js +0 -7
  180. package/dist/services/mut/mut-runner.d.ts +0 -39
  181. package/dist/services/mut/mut-runner.js +0 -29
  182. package/dist/services/mut/production-stryker.d.ts +0 -2
  183. package/dist/services/mut/production-stryker.js +0 -75
  184. package/dist/services/mut/report-builder.d.ts +0 -11
  185. package/dist/services/mut/report-builder.js +0 -110
  186. package/dist/services/mut/report-loader.d.ts +0 -31
  187. package/dist/services/mut/report-loader.js +0 -78
  188. package/dist/services/mut/thresholds.d.ts +0 -21
  189. package/dist/services/mut/thresholds.js +0 -22
  190. package/dist/services/mut/types.d.ts +0 -336
  191. package/dist/services/mut/types.js +0 -59
  192. package/dist/shared/fs.d.ts +0 -4
  193. package/dist/shared/fs.js +0 -26
  194. package/dist/shared/paths.d.ts +0 -6
  195. package/dist/shared/paths.js +0 -50
  196. package/dist/shared/result.d.ts +0 -22
  197. package/dist/shared/result.js +0 -46
  198. package/dist/shared/version.d.ts +0 -1
  199. package/dist/shared/version.js +0 -1
  200. package/examples/video-demo/README.md +0 -142
  201. package/examples/video-demo/out/en-closing-960.png +0 -0
  202. package/examples/video-demo/out/zh-closing-960.png +0 -0
  203. package/examples/video-demo/preview/peaks-loop-demo-en.mp4 +0 -0
  204. package/examples/video-demo/preview/peaks-loop-demo.mp4 +0 -0
@@ -23,7 +23,7 @@
23
23
  * matching, ML-based ranking, pagination, i18n, caching.
24
24
  */
25
25
  import { z } from 'zod';
26
- import { skillsDir } from '../../shared/paths.js';
26
+ import { skillsDir } from 'peaks-loop-shared/paths';
27
27
  export declare const SkillSearchInputSchema: z.ZodEffects<z.ZodObject<{
28
28
  query: z.ZodOptional<z.ZodString>;
29
29
  tag: z.ZodOptional<z.ZodString>;
@@ -35,24 +35,24 @@ export declare const SkillSearchInputSchema: z.ZodEffects<z.ZodObject<{
35
35
  includeInternal: boolean;
36
36
  query?: string | undefined;
37
37
  tag?: string | undefined;
38
- domain?: "code" | "status" | "content" | "test" | "doctor" | "resume" | "ide" | "research" | "triage" | "sop" | "audit" | "final-review" | "slice-decompose" | "issue-fix-orchestrator" | "perf-audit" | "security-audit" | "reviewer" | undefined;
38
+ domain?: "code" | "status" | "doctor" | "test" | "content" | "resume" | "ide" | "research" | "triage" | "sop" | "audit" | "final-review" | "slice-decompose" | "issue-fix-orchestrator" | "perf-audit" | "security-audit" | "reviewer" | undefined;
39
39
  }, {
40
40
  limit?: number | undefined;
41
41
  query?: string | undefined;
42
42
  tag?: string | undefined;
43
- domain?: "code" | "status" | "content" | "test" | "doctor" | "resume" | "ide" | "research" | "triage" | "sop" | "audit" | "final-review" | "slice-decompose" | "issue-fix-orchestrator" | "perf-audit" | "security-audit" | "reviewer" | undefined;
43
+ domain?: "code" | "status" | "doctor" | "test" | "content" | "resume" | "ide" | "research" | "triage" | "sop" | "audit" | "final-review" | "slice-decompose" | "issue-fix-orchestrator" | "perf-audit" | "security-audit" | "reviewer" | undefined;
44
44
  includeInternal?: boolean | undefined;
45
45
  }>, {
46
46
  limit: number;
47
47
  includeInternal: boolean;
48
48
  query?: string | undefined;
49
49
  tag?: string | undefined;
50
- domain?: "code" | "status" | "content" | "test" | "doctor" | "resume" | "ide" | "research" | "triage" | "sop" | "audit" | "final-review" | "slice-decompose" | "issue-fix-orchestrator" | "perf-audit" | "security-audit" | "reviewer" | undefined;
50
+ domain?: "code" | "status" | "doctor" | "test" | "content" | "resume" | "ide" | "research" | "triage" | "sop" | "audit" | "final-review" | "slice-decompose" | "issue-fix-orchestrator" | "perf-audit" | "security-audit" | "reviewer" | undefined;
51
51
  }, {
52
52
  limit?: number | undefined;
53
53
  query?: string | undefined;
54
54
  tag?: string | undefined;
55
- domain?: "code" | "status" | "content" | "test" | "doctor" | "resume" | "ide" | "research" | "triage" | "sop" | "audit" | "final-review" | "slice-decompose" | "issue-fix-orchestrator" | "perf-audit" | "security-audit" | "reviewer" | undefined;
55
+ domain?: "code" | "status" | "doctor" | "test" | "content" | "resume" | "ide" | "research" | "triage" | "sop" | "audit" | "final-review" | "slice-decompose" | "issue-fix-orchestrator" | "perf-audit" | "security-audit" | "reviewer" | undefined;
56
56
  includeInternal?: boolean | undefined;
57
57
  }>;
58
58
  export type SkillSearchInput = z.input<typeof SkillSearchInputSchema>;
@@ -25,8 +25,8 @@
25
25
  import { z } from 'zod';
26
26
  import { listSkills } from '../skills/skill-registry.js';
27
27
  import { parseFrontmatter } from '../../shared/frontmatter.js';
28
- import { readText } from '../../shared/fs.js';
29
- import { skillsDir } from '../../shared/paths.js';
28
+ import { readText } from 'peaks-loop-shared/fs';
29
+ import { skillsDir } from 'peaks-loop-shared/paths';
30
30
  const SKILL_DOMAINS = [
31
31
  'code',
32
32
  'content',
@@ -1,7 +1,7 @@
1
1
  import { join } from 'node:path';
2
- import { listDirectories, pathExists, readText } from '../../shared/fs.js';
2
+ import { listDirectories, pathExists, readText } from 'peaks-loop-shared/fs';
3
3
  import { parseFrontmatter } from '../../shared/frontmatter.js';
4
- import { skillsDir } from '../../shared/paths.js';
4
+ import { skillsDir } from 'peaks-loop-shared/paths';
5
5
  function getLoadFailureMessage(error) {
6
6
  return error instanceof Error ? error.message : 'Unable to parse skill metadata';
7
7
  }
@@ -1,6 +1,6 @@
1
1
  import { dirname, join } from 'node:path';
2
2
  import * as path from 'node:path';
3
- import { readText } from '../../shared/fs.js';
3
+ import { readText } from 'peaks-loop-shared/fs';
4
4
  import { loadSkillRegistry } from './skill-registry.js';
5
5
  const DESTRUCTIVE_APPLY_PATTERNS = [
6
6
  /peaks\s+memory\s+sync[^\n]*--apply/,
@@ -1,7 +1,7 @@
1
1
  import { execFileSync } from 'node:child_process';
2
2
  import { existsSync, readFileSync, statSync } from 'node:fs';
3
3
  import { join } from 'node:path';
4
- import { isDirectory } from '../../shared/fs.js';
4
+ import { isDirectory } from 'peaks-loop-shared/fs';
5
5
  // Slice 2026-06-29-change-id-root-removal: `getCurrentChangeId` was
6
6
  // removed with the change-id axis. Slice check resolves the rid from
7
7
  // `options.rid` only; the binding file at `.peaks/_runtime/current-change`
@@ -1,6 +1,6 @@
1
1
  import { createCodegraphInvocation, executeCodegraphInvocation } from '../codegraph/codegraph-service.js';
2
2
  import { scanUnderstandAnything, summarizeKnowledgeGraph } from './understand-scan-service.js';
3
- import { getErrorMessage } from '../../shared/result.js';
3
+ import { getErrorMessage } from 'peaks-loop-shared/result';
4
4
  const DEFAULT_FILES = ['src/index.ts', 'package.json', 'README.md'];
5
5
  function resolveFiles(files) {
6
6
  if (files !== undefined && files.length > 0) {
@@ -1,7 +1,7 @@
1
1
  import { stat } from 'node:fs/promises';
2
2
  import { join } from 'node:path';
3
- import { isDirectory, pathExists, readText } from '../../shared/fs.js';
4
- import { getErrorMessage } from '../../shared/result.js';
3
+ import { isDirectory, pathExists, readText } from 'peaks-loop-shared/fs';
4
+ import { getErrorMessage } from 'peaks-loop-shared/result';
5
5
  import { loadPreferences } from '../preferences/preferences-service.js';
6
6
  function defaultArtifactDir(projectRoot) {
7
7
  return join(projectRoot, '.understand-anything');
@@ -271,10 +271,11 @@ export function runUpgrade(input) {
271
271
  // a Unix-style environment that can run the shim directly.
272
272
  const here = dirname(fileURLToPath(import.meta.url));
273
273
  // Walk up from the compiled location to find bin/peaks.js.
274
- // The compiled service lives at dist/src/services/upgrade/upgrade-service.js;
275
- // bin/peaks.js is at the peaks-loop root.
274
+ // The compiled service lives at dist/services/upgrade/upgrade-service.js
275
+ // (rootDir=src in tsconfig.build.json trims the "src" segment); bin/peaks.js
276
+ // is at the peaks-loop root, 3 dirs up.
276
277
  const peaksBin = input.peaksBin ??
277
- resolve(here, '..', '..', '..', '..', 'bin', 'peaks.js');
278
+ resolve(here, '..', '..', '..', 'bin', 'peaks.js');
278
279
  const fallbackPeaks = 'peaks';
279
280
  const resolvedPeaksBin = existsSync(peaksBin) ? peaksBin : fallbackPeaks;
280
281
  // Resolve the executor once at the top of runUpgrade so every
@@ -23,8 +23,8 @@
23
23
  * "missing → null" contract). Callers can detect "envelope missing"
24
24
  * without throwing.
25
25
  */
26
- import { type SecurityAuditEnvelope } from '../audit-independent/security-audit-service.js';
27
- import { type PerfAuditEnvelope } from '../audit-independent/perf-audit-service.js';
26
+ import { type SecurityAuditEnvelope } from 'peaks-loop-audit-independent';
27
+ import { type PerfAuditEnvelope } from 'peaks-loop-audit-independent';
28
28
  import { type KarpathyEnvelope, type MutEnvelope, type QaEnvelope, type AggregatorInput } from './verdict-aggregator.js';
29
29
  /**
30
30
  * `kind` is the discriminator. The on-disk file format is unchanged;
@@ -23,8 +23,8 @@
23
23
  * "missing → null" contract). Callers can detect "envelope missing"
24
24
  * without throwing.
25
25
  */
26
- import { isSecurityAuditEnvelope } from '../audit-independent/security-audit-service.js';
27
- import { isPerfAuditEnvelope } from '../audit-independent/perf-audit-service.js';
26
+ import { isSecurityAuditEnvelope } from 'peaks-loop-audit-independent';
27
+ import { isPerfAuditEnvelope } from 'peaks-loop-audit-independent';
28
28
  // ─── 5 parsers (pure, never throw) ─────────────────────────────────────
29
29
  /**
30
30
  * v2.13.3 AC-1 — parse real v2.12.0 audit markdown.
@@ -27,9 +27,9 @@
27
27
  * SecurityAuditEnvelope / PerfAuditEnvelope type re-exports.
28
28
  * - hard precedence; no scoring, no weighting, no RFC voting.
29
29
  */
30
- import type { SecurityAuditEnvelope } from '../audit-independent/security-audit-service.js';
31
- import type { PerfAuditEnvelope } from '../audit-independent/perf-audit-service.js';
32
- import type { ThresholdViolation } from '../mut/thresholds.js';
30
+ import type { SecurityAuditEnvelope } from 'peaks-loop-audit-independent';
31
+ import type { PerfAuditEnvelope } from 'peaks-loop-audit-independent';
32
+ import type { ThresholdViolation } from 'peaks-loop-mut';
33
33
  export interface KarpathyViolation {
34
34
  readonly guideline: 'think-before-coding' | 'simplicity-first' | 'surgical-changes' | 'goal-driven-execution';
35
35
  readonly severity: 'CRITICAL' | 'HIGH' | 'MED' | 'LOW';
@@ -1,7 +1,7 @@
1
1
  import { mkdir, writeFile } from 'node:fs/promises';
2
2
  import { dirname, join } from 'node:path';
3
3
  import { getSessionDir } from '../session/getSessionDir.js';
4
- import { pathExists } from '../../shared/fs.js';
4
+ import { pathExists } from 'peaks-loop-shared/fs';
5
5
  import { isUnsafePathInput } from '../../shared/path-safety.js';
6
6
  function defaultClock() {
7
7
  return new Date().toISOString();
@@ -1,4 +1,4 @@
1
- import { type ResultEnvelope } from '../../shared/result.js';
1
+ import { type ResultEnvelope } from 'peaks-loop-shared/result';
2
2
  export type PlanType = 'security' | 'perf';
3
3
  /** Back-compat env-var. When set to "1", fall back to legacy paths. */
4
4
  export declare const BACK_COMPAT_FLAG = "PEAKS_PLAN_LEGACY_FALLBACK";
@@ -15,7 +15,7 @@
15
15
  import { createHash } from 'node:crypto';
16
16
  import { existsSync, readFileSync, realpathSync, statSync } from 'node:fs';
17
17
  import { join, sep } from 'node:path';
18
- import { fail, ok } from '../../shared/result.js';
18
+ import { fail, ok } from 'peaks-loop-shared/result';
19
19
  import { getSessionDir } from '../session/getSessionDir.js';
20
20
  /** Back-compat env-var. When set to "1", fall back to legacy paths. */
21
21
  export const BACK_COMPAT_FLAG = 'PEAKS_PLAN_LEGACY_FALLBACK';
@@ -1,4 +1,4 @@
1
- import { type ResultEnvelope } from '../../shared/result.js';
1
+ import { type ResultEnvelope } from 'peaks-loop-shared/result';
2
2
  import { normalizePlanBody, type PlanType } from './plan-reader.js';
3
3
  export interface RefreshPlanArgs {
4
4
  readonly type: PlanType;
@@ -11,7 +11,7 @@
11
11
  */
12
12
  import { existsSync, readFileSync, readdirSync, realpathSync, statSync, writeFileSync, mkdirSync } from 'node:fs';
13
13
  import { join, sep } from 'node:path';
14
- import { fail, ok } from '../../shared/result.js';
14
+ import { fail, ok } from 'peaks-loop-shared/result';
15
15
  import { getSessionDir } from '../session/getSessionDir.js';
16
16
  import { hashNormalizedBody, normalizePlanBody } from './plan-reader.js';
17
17
  const PLAN_FILE = {
@@ -11,7 +11,7 @@
11
11
  * supplied, the detector scans the project directly (the same scan the
12
12
  * refresh plan performs).
13
13
  */
14
- import { type ResultEnvelope } from '../../shared/result.js';
14
+ import { type ResultEnvelope } from 'peaks-loop-shared/result';
15
15
  export type TriggerReason = 'new-dependency' | 'auth-surface-added' | 'hot-path-added' | 'manual-override' | 'no-change' | 'no-triggering-change';
16
16
  /** F-1 (slice 025 security): canonical request-id shape. */
17
17
  export declare const REQUEST_ID_PATTERN: RegExp;
@@ -13,7 +13,7 @@
13
13
  */
14
14
  import { existsSync, readFileSync, readdirSync } from 'node:fs';
15
15
  import { join } from 'node:path';
16
- import { fail, ok } from '../../shared/result.js';
16
+ import { fail, ok } from 'peaks-loop-shared/result';
17
17
  /** F-1 (slice 025 security): canonical request-id shape. */
18
18
  export const REQUEST_ID_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._-]*$/;
19
19
  const SENSITIVE_SERVICE_DIRS = ['auth', 'security', 'secrets', 'payments', 'filesystem'];
@@ -78,30 +78,32 @@ function annotateSteps(steps, codeMode) {
78
78
  };
79
79
  });
80
80
  }
81
- function createSoloSteps(executionModelId, strongestModelId) {
81
+ function createSoloSteps(executionModelId, strongestModelId, economyMode) {
82
+ const executionTier = economyMode === false ? 'top-tier' : 'mid-tier';
82
83
  return [
83
84
  step({ id: 'code-product-direction', stage: 'product-direction', owner: 'peaks-code', modelTier: 'top-tier', reason: 'Product direction needs strong judgment before execution work is delegated.', dependsOn: [] }, executionModelId, strongestModelId),
84
85
  step({ id: 'code-design-direction', stage: 'design-direction', owner: 'peaks-code', modelTier: 'top-tier', reason: 'Design direction uses the recommended default before cheaper implementation work.', dependsOn: ['code-product-direction'] }, executionModelId, strongestModelId),
85
86
  step({ id: 'code-tech-direction', stage: 'tech-direction', owner: 'peaks-tech', modelTier: 'top-tier', reason: 'Technical boundaries and approval gates use the recommended default with high-confidence planning.', dependsOn: ['code-design-direction'] }, executionModelId, strongestModelId),
86
87
  step({ id: 'code-tech-review', stage: 'tech-review', owner: 'peaks-tech', modelTier: 'top-tier', reason: 'Tech artifacts and gate decisions require strong review and a recommended default path.', dependsOn: ['code-tech-direction'] }, executionModelId, strongestModelId),
87
88
  step({ id: 'code-rd-planning', stage: 'rd-planning', owner: 'peaks-rd', modelTier: 'top-tier', reason: 'RD task decomposition and acceptance criteria use the recommended default before execution delegation.', dependsOn: ['code-tech-review'] }, executionModelId, strongestModelId),
88
- step({ id: 'code-coding-execution', stage: 'coding-execution', owner: 'peaks-rd', modelTier: executionModelId === strongestModelId ? 'top-tier' : 'mid-tier', reason: `Coding and routine refactoring must use the configured execution worker model ${executionModelId}.`, dependsOn: ['code-rd-planning'] }, executionModelId, strongestModelId),
89
- step({ id: 'code-unit-test-execution', stage: 'unit-test-execution', owner: 'peaks-rd', modelTier: executionModelId === strongestModelId ? 'top-tier' : 'mid-tier', reason: `Unit test authoring and focused test runs must use the configured execution worker model ${executionModelId}.`, dependsOn: ['code-coding-execution'] }, executionModelId, strongestModelId),
89
+ step({ id: 'code-coding-execution', stage: 'coding-execution', owner: 'peaks-rd', modelTier: executionTier, reason: `Coding and routine refactoring must use the configured execution worker model ${executionModelId}.`, dependsOn: ['code-rd-planning'] }, executionModelId, strongestModelId),
90
+ step({ id: 'code-unit-test-execution', stage: 'unit-test-execution', owner: 'peaks-rd', modelTier: executionTier, reason: `Unit test authoring and focused test runs must use the configured execution worker model ${executionModelId}.`, dependsOn: ['code-coding-execution'] }, executionModelId, strongestModelId),
90
91
  step({ id: 'code-quality-review', stage: 'quality-review', owner: 'peaks-code', modelTier: 'top-tier', reason: 'Reducer and final quality gates need strong synthesis and risk review.', dependsOn: ['code-unit-test-execution'] }, executionModelId, strongestModelId)
91
92
  ];
92
93
  }
93
- function createSoloStepsForMode(codeMode, executionModelId, strongestModelId) {
94
- return annotateSteps(createSoloSteps(executionModelId, strongestModelId), codeMode);
94
+ function createSoloStepsForMode(codeMode, executionModelId, strongestModelId, economyMode) {
95
+ return annotateSteps(createSoloSteps(executionModelId, strongestModelId, economyMode), codeMode);
95
96
  }
96
- function createTeamSteps(executionModelId, strongestModelId) {
97
+ function createTeamSteps(executionModelId, strongestModelId, economyMode) {
98
+ const executionTier = economyMode === false ? 'top-tier' : 'mid-tier';
97
99
  return [
98
100
  step({ id: 'team-product-direction', stage: 'product-direction', owner: 'human', modelTier: 'top-tier', reason: 'Team product direction should stay on the governed planning path.', dependsOn: [] }, executionModelId, strongestModelId),
99
101
  step({ id: 'team-design-direction', stage: 'design-direction', owner: 'human', modelTier: 'top-tier', reason: 'Team design direction should preserve reviewability and accountability.', dependsOn: ['team-product-direction'] }, executionModelId, strongestModelId),
100
102
  step({ id: 'team-tech-direction', stage: 'tech-direction', owner: 'peaks-tech', modelTier: 'top-tier', reason: 'Team technical plans should remain strongly governed before RD execution.', dependsOn: ['team-design-direction'] }, executionModelId, strongestModelId),
101
103
  step({ id: 'team-tech-review', stage: 'tech-review', owner: 'peaks-tech', modelTier: 'top-tier', reason: 'Team tech approval requires strong review before execution.', dependsOn: ['team-tech-direction'] }, executionModelId, strongestModelId),
102
104
  step({ id: 'team-rd-planning', stage: 'rd-planning', owner: 'peaks-rd', modelTier: 'top-tier', reason: 'Team RD task decomposition remains on the governed strongest-model path.', dependsOn: ['team-tech-review'] }, executionModelId, strongestModelId),
103
- step({ id: 'team-coding-execution', stage: 'coding-execution', owner: 'peaks-rd', modelTier: executionModelId === strongestModelId ? 'top-tier' : 'mid-tier', reason: `Bounded coding tasks must use the configured execution worker model ${executionModelId}.`, dependsOn: ['team-rd-planning'] }, executionModelId, strongestModelId),
104
- step({ id: 'team-unit-test-execution', stage: 'unit-test-execution', owner: 'peaks-rd', modelTier: executionModelId === strongestModelId ? 'top-tier' : 'mid-tier', reason: `Unit-test tasks must use the configured execution worker model ${executionModelId}.`, dependsOn: ['team-coding-execution'] }, executionModelId, strongestModelId),
105
+ step({ id: 'team-coding-execution', stage: 'coding-execution', owner: 'peaks-rd', modelTier: executionTier, reason: `Bounded coding tasks must use the configured execution worker model ${executionModelId}.`, dependsOn: ['team-rd-planning'] }, executionModelId, strongestModelId),
106
+ step({ id: 'team-unit-test-execution', stage: 'unit-test-execution', owner: 'peaks-rd', modelTier: executionTier, reason: `Unit-test tasks must use the configured execution worker model ${executionModelId}.`, dependsOn: ['team-coding-execution'] }, executionModelId, strongestModelId),
105
107
  step({ id: 'team-quality-review', stage: 'quality-review', owner: 'peaks-rd', modelTier: 'top-tier', reason: 'Team RD outputs still need reducer and quality review gates.', dependsOn: ['team-unit-test-execution'] }, executionModelId, strongestModelId)
106
108
  ];
107
109
  }
@@ -201,7 +203,7 @@ export function createWorkflowRouterPlan(request) {
201
203
  const techStatus = getTechStatus({ sessionId: request.sessionId, ...sharedWorkspaceOptions });
202
204
  const techPlan = createTechPlan({ sessionId: request.sessionId, goal, swarm: swarmMode, dryRun: true, ...sharedWorkspaceOptions });
203
205
  const rdPlan = createRdSwarmPlan({ skill: 'rd', sessionId: request.sessionId, goal, maxWorkers, swarmMode, executionModelId, dryRun: true, ...sharedWorkspaceOptions });
204
- const steps = codeMode ? createSoloStepsForMode(codeMode, executionModelId, strongestModelId) : createTeamSteps(executionModelId, strongestModelId);
206
+ const steps = codeMode ? createSoloStepsForMode(codeMode, executionModelId, strongestModelId, economyMode) : createTeamSteps(executionModelId, strongestModelId, economyMode);
205
207
  const blockedReasons = uniqueStrings([
206
208
  ...techStatus.blockedReasons,
207
209
  ...getTechPlanBlockedReasons(techPlan),
@@ -1,7 +1,7 @@
1
1
  import { execFileSync } from 'node:child_process';
2
2
  import { mkdir, readFile, readdir, rename, rm } from 'node:fs/promises';
3
3
  import { join } from 'node:path';
4
- import { isDirectory, pathExists } from '../../shared/fs.js';
4
+ import { isDirectory, pathExists } from 'peaks-loop-shared/fs';
5
5
  import { isPathInsideArtifactRoot } from '../../shared/path-safety.js';
6
6
  const ROLE_DIRS = new Set(['prd', 'ui', 'rd', 'qa', 'sc', 'system']);
7
7
  /** Top-level dirs in `.peaks/` that are NEVER legacy session dirs
@@ -1,7 +1,7 @@
1
1
  import { mkdir } from 'node:fs/promises';
2
2
  import { existsSync, lstatSync, readdirSync } from 'node:fs';
3
3
  import { join } from 'node:path';
4
- import { isDirectory } from '../../shared/fs.js';
4
+ import { isDirectory } from 'peaks-loop-shared/fs';
5
5
  import { getSessionId, setCurrentSessionBinding, setSessionMeta } from '../session/session-manager.js';
6
6
  /**
7
7
  * Slice 2026-06-29-change-id-root-removal: list the immediate children of
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "peaks-loop",
3
- "version": "4.0.0-beta.14",
3
+ "version": "4.0.0-beta.16",
4
4
  "description": "Loop Engineering CLI — workflow primitive / loop guards / evaluators / slice orchestration",
5
5
  "author": "SquabbyZ",
6
6
  "license": "MIT",
@@ -42,14 +42,10 @@
42
42
  "README.md",
43
43
  "README-en.md",
44
44
  "CHANGELOG.md",
45
- "LICENSE",
46
- "examples/video-demo/preview/peaks-loop-demo.mp4",
47
- "examples/video-demo/preview/peaks-loop-demo-en.mp4",
48
- "examples/video-demo/out/zh-closing-960.png",
49
- "examples/video-demo/out/en-closing-960.png"
45
+ "LICENSE"
50
46
  ],
51
47
  "scripts": {
52
- "build": "node ./scripts/sync-version.mjs && node ./scripts/clean-dist.mjs && tsc -p tsconfig.build.json && node ./scripts/copy-templates.mjs",
48
+ "build": "node ./scripts/sync-version.mjs && node ./scripts/clean-dist.mjs && pnpm -r --filter \"./packages/*\" run build && tsc -p tsconfig.build.json && node ./scripts/copy-templates.mjs",
53
49
  "prepack": "npm run build",
54
50
  "prepublishOnly": "node scripts/prepublish-build.mjs",
55
51
  "prepublish": "node ./scripts/sync-version.mjs",
@@ -71,7 +67,7 @@
71
67
  "test:ci": "node ./scripts/sync-version.mjs && node ./scripts/lint/silent-warning-detector.mjs && vitest run --coverage",
72
68
  "test:changed": "node scripts/test-changed.mjs",
73
69
  "lint:silent-warning": "node ./scripts/lint/silent-warning-detector.mjs",
74
- "test:race": "vitest run --no-file-parallelism tests/unit/g8-shared-channel.test.ts tests/unit/dispatch-record-writer.test.ts tests/unit/services/retrospective/heartbeat.test.ts tests/unit/cli/commands/share-commands.test.ts",
70
+ "test:race": "vitest run --no-file-parallelism packages/peaks-loop-shared-channel/tests/shared-channel.test.ts tests/unit/dispatch-record-writer.test.ts tests/unit/services/retrospective/heartbeat.test.ts tests/unit/cli/commands/share-commands.test.ts",
75
71
  "test:replay": "node scripts/fixture-capture-setup.mjs && vitest run tests/unit/replay tests/unit/fixture",
76
72
  "fixture:capture-setup": "node scripts/fixture-capture-setup.mjs",
77
73
  "test:coverage": "vitest run --coverage",
@@ -98,6 +94,14 @@
98
94
  "commander": "^12.1.0",
99
95
  "fzf": "^0.5.2",
100
96
  "headroom-ai": "0.22.4",
97
+ "peaks-loop-audit-independent": "workspace:*",
98
+ "peaks-loop-crystallization": "workspace:*",
99
+ "peaks-loop-doctor": "workspace:*",
100
+ "peaks-loop-final-review": "workspace:*",
101
+ "peaks-loop-mut": "workspace:*",
102
+ "peaks-loop-job-snapshot": "workspace:*",
103
+ "peaks-loop-shared-channel": "workspace:*",
104
+ "peaks-loop-shared": "workspace:*",
101
105
  "yaml": "^2.9.0",
102
106
  "zod": "^3.25.76"
103
107
  },
@@ -110,6 +114,7 @@
110
114
  }
111
115
  },
112
116
  "devDependencies": {
117
+ "@changesets/cli": "2.31.1",
113
118
  "@jridgewell/trace-mapping": "^0.3.31",
114
119
  "@stryker-mutator/core": "^8.7.1",
115
120
  "@stryker-mutator/typescript-checker": "^8.7.1",
@@ -9,4 +9,11 @@ if (typeof version !== 'string' || version.length === 0) {
9
9
  throw new Error('package.json version must be a non-empty string');
10
10
  }
11
11
 
12
- writeFileSync(resolve('src/shared/version.ts'), `export const CLI_VERSION = ${JSON.stringify(version)};\n`);
12
+ // Slice 3a — version.ts lives in the peaks-loop-shared workspace package.
13
+ // The shared package is `private: true` and is consumed via workspace:*,
14
+ // so its own package.json `version` field is irrelevant for downstream
15
+ // consumers; we always emit the main peaks-loop version.
16
+ writeFileSync(
17
+ resolve('packages/peaks-loop-shared/src/version.ts'),
18
+ `export const CLI_VERSION = ${JSON.stringify(version)};\n`,
19
+ );
@@ -136,7 +136,20 @@ If any gate fails, return to development for fixes or hand off as blocked. Do no
136
136
 
137
137
  ## Parallel review fan-out (v2.12.0 3-way fanout — code-reviewer + qa-test-cases-writer + karpathy-reviewer)
138
138
 
139
- Full content extracted to **`references/parallel-review-fanout.md`** (3-way fan-out dispatch contract, when-to-fan-out rules, dispatch template, prereq gates). Read that file before issuing any 3-way fan-out.
139
+ **v2.12.0 collapse (Group A — Tier 1+2+3):** the previous 5-way fan-out (slice 004 4-way + slice 5/6 `karpathy-reviewer` addition) totalled **5 sub-agents**. The `security-reviewer` and `perf-baseline-reviewer` slots moved out of the RD 3-way fan-out into two new standalone audit skills:
140
+
141
+ - `peaks-security-audit` — CLI: `peaks security-audit run`. Writes `audit/security.md` (under `.peaks/_runtime/<sessionId>/audit/security.md`). Required RD-side prereq `AUDIT_SECURITY`.
142
+ - `peaks-perf-audit` — CLI: `peaks perf-audit run`. Writes `audit/perf.md` (under `.peaks/_runtime/<sessionId>/audit/perf.md`). Required RD-side prereq `AUDIT_PERF`.
143
+
144
+ Both audit skills consume the immutable peaks-prd handoff (`prd/handoff.md`) and the project-scoped audit templates under `.peaks/project-scan/{security-template, perf-template, audit-output-schema}.md`. The handoff presence is enforced by the `AUDIT_REQUIRES_HANDOFF` prereq. The 1-minor-release back-compat window (v2.12.0) keeps the old `rd/security-review.md` and `rd/perf-baseline.md` paths readable via `mustContainAny` — see `references/rd-fanout-contracts.md` §"Deprecated reviewer back-compat".
145
+
146
+ **Current 3-way fan-out** (always runs for feature / refactor / bugfix; no fan-out for config / docs / chore):
147
+
148
+ 1. `code-reviewer` — writes `rd/code-review.md` (Gate B3).
149
+ 2. `qa-test-cases-writer` — writes `qa/test-cases/<rid>.md` (Gate C2).
150
+ 3. `karpathy-reviewer` — writes `rd/karpathy-review.md` (the **hard Karpathy-Gate**, KARPATHY_REVIEW prereq).
151
+
152
+ Full dispatch contract (when-to-fan-out rules, dispatch template, prereq gates) lives in **`references/parallel-review-fanout.md`**. Read that file before issuing any 3-way fan-out.
140
153
 
141
154
  ## Refactor hard gates
142
155
 
@@ -48,6 +48,50 @@ This skill is the **primary surface**. The `peaks <cmd>` CLI is **auxiliary**
48
48
 
49
49
  Full content extracted to **`references/startup-sequence.md`** (Steps 0 / 0.5-0.87 / 1 / 2 / 2.3 / 2.5 / N / N+1 / N+2 + sub-agent sharing + boundaries). Read that file in full at session start; the sequence is MANDATORY.
50
50
 
51
+ ## Peaks-Loop Step 0.8 — Job-shape detection (BLOCKING on LLM judgement)
52
+
53
+ > **BLOCKING on LLM judgement.** Before Step 1 mode selection, Code MUST surface a Job-shape decision via `peaks code detect-job` and persist it to `.peaks/_runtime/<sessionId>/job-shape.json`. The CLI is a recorder + gate — the LLM makes the judgement; downstream steps call `read-job-shape` and refuse if missing. See `references/step-0-8-gate.md` for the full contract (LLM criteria, action sequence, hard rule red-line #10). Failure mode: skipping `peaks code detect-job` blocks the workflow at the next `read-job-shape` call (`JOB_SHAPE_NOT_DECIDED`).
54
+
55
+ **v3.1.2 mechanical gates** (the recorder-only design was bypassed twice under load; the gate must be un-bypassable):
56
+
57
+ 1. **PreToolUse hook — `peaks code gate-step-08`.** Installed by `peaks workspace init` on the `Bash` matcher; checks `job-shape.json` presence + fail-closed backup regex. If `job-shape.json` exists AND `progress.json` exists, surfaces `Next: slice #N of M (<currentSlice>)` so the LLM cannot wake up cold.
58
+ 2. **Size-fear ban — `peaks code emit-handoff`.** Refuses to emit a final handoff while `remaining > 0` under Job mode. Pass `--force-under-job` only with explicit user approval.
59
+ 3. **On-disk slice progress — `peaks job progress`.** `peaks job checkpoint --state done` writes `progress.json`. `peaks job progress --job-id <jid> [--allow-missing]` is the canonical reader; `peaks code gate-step-08` also surfaces it on every Bash call.
60
+ 4. **Forced auto-compact — `--enforce-job-mode`.** `peaks code context-now --enforce-job-mode` returns `action: 'auto-compact-now'` at ≥ 0.85. **Job mode at ≥ 0.85 is MANDATORY auto-compact** — Code MUST call `peaks session auto-compact --execute` without confirmation.
61
+
62
+ **Step 0.7 resume rule (read-FIRST):** on resume, `peaks code gate-step-08` reads `progress.json` first and surfaces `Next: slice #N of M (<currentSlice>)` so the orchestrator picks up at the right slice without re-reading the artifact tree.
63
+
64
+ ### Peaks-Loop Step N+2: Auto-compact at the warning line (v2.13.0 zero-pause contract)
65
+
66
+ > **Zero-pause contract.** When context usage crosses the pre-compact threshold, peaks-loop **automatically fires `peaks session auto-compact --execute` — the LLM does NOT prompt the user to run `/compact` manually**. This is the single biggest UX regression vector in the system: a stale prose that says "ask the user to compact" will silently send the LLM into "wait for human" mode and stall the entire workflow. The v2.13.0 contract makes auto-compact a system responsibility, not a user action.
67
+
68
+ **Thresholds (v2.13.0, replacing legacy 50/75/90):**
69
+
70
+ | ratio zone | zone name | action |
71
+ |---|---|---|
72
+ | `< 0.85` | normal | skip — LLM keeps working, no action |
73
+ | `0.85 ≤ ratio < 0.95` | **pre-compact zone** | `peaks session auto-compact --execute` fires **automatically** (deferred only if an in-flight sub-agent batch is still running; fires the moment the batch lands). The LLM does not prompt the user. |
74
+ | `ratio ≥ 0.95` | **red-line (Karpathy §4 compact-red-line exception)** | synchronous gate — `peaks session auto-compact --execute` is invoked immediately; `peaks code context-now` returns `action: 'red-line'` and refuses to advance until ratio drops below 0.85. **Karpathy §4 treats this as an automatic exception** — the LLM cannot opt out. |
75
+
76
+ **Probe primitive (single source of truth):** `peaks code context-now --json`. Do NOT use `peaks context check --prompt-size` (deprecated, pre-v2.13.0 surface; will silently under-report ratio). The CLI returns `{ ratio, action: 'ok' | 'soft-warn' | 'auto-compact-now' | 'red-line' }` — Code reads `action` and dispatches `peaks session auto-compact --execute` on `auto-compact-now` or `red-line` without any user confirmation.
77
+
78
+ **Enforcement layers (defense in depth — no single layer is the gate):**
79
+
80
+ 1. `src/services/code/auto-compact-orchestrator.ts` — `evaluateAutoCompactDecision` default-returns `shouldCompact: true` for both `pre-compact` and `red-line` zones. The only deferral is `inFlightBatch.hasInFlightBatch` (D6.e); no LLM / human approval branch.
81
+ 2. `--enforce-job-mode` (v3.1.2) — Job mode elevates ≥0.85 to MANDATORY regardless of in-flight batch (see Step 0.8 §4 above).
82
+ 3. `peaks code gate-step-08` (PreToolUse hook) — surfaces `auto-compact-now` on every Bash call when ratio is in the zone, so the LLM cannot wake up cold and forget.
83
+ 4. The Karpathy §4 exception: `peaks session auto-compact --execute` is fired *by the orchestrator*, not by the user running `/compact`. If you find yourself about to write prose that says "ask the user to compact" or "prompt the user to run `/compact`", STOP — that is the regression.
84
+
85
+ **Anti-pattern (regression marker — DO NOT introduce):** any of these strings in skills/* or comments signals the zero-pause contract has been broken:
86
+
87
+ - "ask the user to compact"
88
+ - "prompt the user to run `/compact`"
89
+ - "the user should run `peaks session auto-compact` manually"
90
+ - "the user is responsible for context management"
91
+ - legacy pre-v2.13.0 thresholds (mid / seventy-five / ninety percent tiers; current is 0.85 / 0.95)
92
+
93
+ If the prose audit (`peaks audit red-lines`) flags any of the above, the slice is **blocked** until the prose is rewritten.
94
+
51
95
  ## CLI Drift Index (sediment 2026-07-09)
52
96
 
53
97
  > **Reading guide:** Verified against peaks-loop 4.0.0-beta.6. Each drift below is annotated inline at the relevant step with a `> CLI reality check`. On `error: unknown option ...`, **read the inline reality check first** before guessing.
@@ -248,6 +248,36 @@ once the poller has read them.
248
248
  - AC-25..AC-32: G5 resource lifecycle (RL-1 batch counter, dispatch record schema, reducer dispose, slice archive, cancel dispose)
249
249
  - AC-33..AC-37: G6 heartbeat CLI, schema, poller, status line, E2E
250
250
 
251
+ ## D21 — LLM-side completion signal (mandatory)
252
+
253
+ `peaks sub-agent dispatch` writes the record in `queued` state. The
254
+ dispatcher has no other way to learn that the spawned Task tool
255
+ actually returned. **The LLM runner MUST call `peaks sub-agent finalize`
256
+ once per dispatched Task, in the post-completion branch** (after the
257
+ Task tool's `tool_result` has been received). Without it, the record
258
+ stays `queued, no-execution` forever.
259
+
260
+ ```sh
261
+ # After each Task tool returns:
262
+ peaks sub-agent finalize --request-id <rid> --outcome done
263
+
264
+ # On Task failure:
265
+ peaks sub-agent finalize --request-id <rid> --outcome failed --error "<msg>"
266
+
267
+ # Crash-recovery sweep (only if the runner was interrupted and many
268
+ # records are stuck in queued):
269
+ peaks sub-agent finalize --all-stale --outcome done
270
+ ```
271
+
272
+ `finalize` calls `markCompleted` (in dispatch-record-writer.ts), which
273
+ transitions the record to the chosen status and unregisters the path
274
+ from `active-dispatches.json`. The next runner does not see a stale
275
+ ghost.
276
+
277
+ This was added in slice 2026-07-17-D21 after 13 stale records were
278
+ observed in the peaks-loop repo (`active-dispatches.json` would have
279
+ grown unboundedly without this fix).
280
+
251
281
  ## How to apply
252
282
 
253
283
  When writing a SKILL.md that fans out sub-agents:
@@ -1,97 +0,0 @@
1
- /**
2
- * ECC cache service — Slice 3 of 4.0.0-beta.11.
3
- *
4
- * Drop-in replacement for the deleted `ecc-agent-service.ts`. The
5
- * pre-Slice-3 implementation shelled out to `npx ecc agent run ...`,
6
- * but the upstream `affaan-m/everything-claude-code` v2.0.0 release
7
- * has NO `ecc` binary — the repo is `agents/*.md` flat files plus
8
- * SKILL.md descriptors. The peaks-loop path is therefore download
9
- * + cache only; the LLM consumes cached `agents/*.md` directly
10
- * through `peaks ecc show <name>`.
11
- *
12
- * Six exports per RD §2:
13
- * - setCacheDirPermissions
14
- * - downloadToCache
15
- * - readCacheManifest
16
- * - listCachedAgents
17
- * - readAgentSkill
18
- * - cleanupStaleCache
19
- *
20
- * The cache layout is `~/.peaks/cache/ecc-installed.json` (manifest)
21
- * + `~/.peaks/cache/ecc-<sha>/agents/<name>.md`. The manifest is
22
- * the active-cache pointer; cleanupStaleCache iterates the on-disk
23
- * sha directories and decides based on the manifest's `fetchedAt`
24
- * (active) vs `mtimeMs` (orphan).
25
- *
26
- * Hard contracts (Karpathy #2 Simplicity First):
27
- * - No subprocess plumbing. Network is `fetch()` only.
28
- * - No factory; one module, six functions, six dependencies.
29
- * - Strict selective extract: agents/*.md only, no symlinks, no
30
- * `..`, no absolute paths, no devices.
31
- * - D-009 fallback: parseFrontmatter throws on malformed input —
32
- * wrap it in try/catch and synthesize `{name, description}`
33
- * from the file name + first non-empty body line.
34
- * - D-010 fallback: PRD's `ecc.tar.gz` asset URL does NOT exist
35
- * upstream; try PRD first, fall back to GitHub's `tarball_url`
36
- * on the release JSON.
37
- */
38
- export declare const ECC_REPO_OWNER = "affaan-m";
39
- export declare const ECC_REPO_NAME = "everything-claude-code";
40
- export type CacheManifest = {
41
- version: string;
42
- sha: string;
43
- fetchedAt: string;
44
- agents: string[];
45
- };
46
- export type DownloadResult = {
47
- sha: string;
48
- agents: number;
49
- };
50
- /**
51
- * Cache dir resolution — single source of truth. Tests inject
52
- * via `dirOverride` on the functions that take one.
53
- */
54
- export declare function resolveEccCacheDir(): string;
55
- export declare function resolveManifestPath(dirOverride?: string): string;
56
- export declare function resolveShaDir(sha: string, dirOverride?: string): string;
57
- export declare function resolveAgentsDir(sha: string, dirOverride?: string): string;
58
- /**
59
- * Best-effort chmod 0o700 on POSIX; no-op on Windows (NTFS uses
60
- * ACLs, not POSIX mode bits). Swallows errors with WARN so a
61
- * permissions failure never blocks the CLI.
62
- */
63
- export declare function setCacheDirPermissions(cacheDir: string): void;
64
- /**
65
- * Download ECC into `~/.peaks/cache/ecc-<sha>/agents/`. Returns
66
- * the resolved SHA + the number of agents extracted.
67
- *
68
- * Throws `Error('fetch-failed')` on network failure so the CLI
69
- * layer can render the manual-install instructions.
70
- */
71
- export declare function downloadToCache({ ref }?: {
72
- ref?: string;
73
- }): Promise<DownloadResult>;
74
- export declare function readCacheManifest(): CacheManifest | null;
75
- export declare function listCachedAgents(): {
76
- name: string;
77
- description: string;
78
- }[];
79
- export declare function readAgentSkill(name: string): string | null;
80
- /**
81
- * 7-day TTL sweep over `ecc-<sha>/` directories.
82
- *
83
- * - Active cache (per manifest `sha`): use `fetchedAt` as the
84
- * age source; remove if older than `retentionDays`.
85
- * - Orphan caches (any other `ecc-<40hex>` directory): use
86
- * directory `mtimeMs` as the age source.
87
- * - If the active cache is removed, invalidate the manifest.
88
- *
89
- * Returns the absolute paths of the removed directories.
90
- */
91
- export declare function cleanupStaleCache({ retentionDays, nowMs, dirOverride, }: {
92
- retentionDays: number;
93
- nowMs: number;
94
- dirOverride?: string;
95
- }): {
96
- removed: string[];
97
- };