peaks-loop 4.0.0-beta → 4.0.0-beta.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (179) hide show
  1. package/CHANGELOG.md +105 -87
  2. package/README-en.md +17 -4
  3. package/README.md +17 -4
  4. package/dist/src/cli/commands/asset-commands.d.ts +45 -0
  5. package/dist/src/cli/commands/asset-commands.js +404 -0
  6. package/dist/src/cli/commands/bee-commands.d.ts +26 -0
  7. package/dist/src/cli/commands/bee-commands.js +169 -0
  8. package/dist/src/cli/commands/{solo-commands.d.ts → code-commands.d.ts} +24 -24
  9. package/dist/src/cli/commands/{solo-commands.js → code-commands.js} +78 -78
  10. package/dist/src/cli/commands/core/skill-command.js +1 -1
  11. package/dist/src/cli/commands/dispatch-from-dag.js +1 -1
  12. package/dist/src/cli/commands/evolution-commands.d.ts +27 -0
  13. package/dist/src/cli/commands/evolution-commands.js +393 -0
  14. package/dist/src/cli/commands/hook-handle.js +7 -7
  15. package/dist/src/cli/commands/job-commands.js +2 -2
  16. package/dist/src/cli/commands/loop-commands.d.ts +19 -13
  17. package/dist/src/cli/commands/loop-commands.js +147 -13
  18. package/dist/src/cli/commands/sediment-commands.js +9 -0
  19. package/dist/src/cli/commands/session-auto-compact-hook-command.js +2 -2
  20. package/dist/src/cli/commands/skill-loop-engineering-readiness-commands.d.ts +67 -0
  21. package/dist/src/cli/commands/skill-loop-engineering-readiness-commands.js +173 -0
  22. package/dist/src/cli/commands/sub-agent-shared.d.ts +1 -1
  23. package/dist/src/cli/commands/user-touchpoint-commands.d.ts +4 -4
  24. package/dist/src/cli/commands/user-touchpoint-commands.js +14 -14
  25. package/dist/src/cli/commands/workflow-commands.js +22 -22
  26. package/dist/src/cli/program.js +23 -6
  27. package/dist/src/services/artifacts/repair-cycle-service.js +1 -1
  28. package/dist/src/services/audit/enforcers/active-skill-resolver.d.ts +1 -1
  29. package/dist/src/services/audit/enforcers/active-skill-resolver.js +1 -1
  30. package/dist/src/services/audit/enforcers/{solo-code-ban.d.ts → code-ban.d.ts} +6 -6
  31. package/dist/src/services/audit/enforcers/{solo-code-ban.js → code-ban.js} +6 -6
  32. package/dist/src/services/audit/red-line-catalog.d.ts +2 -2
  33. package/dist/src/services/audit/red-line-catalog.js +5 -5
  34. package/dist/src/services/audit/types.d.ts +2 -2
  35. package/dist/src/services/{solo → code}/auto-compact-orchestrator.d.ts +1 -1
  36. package/dist/src/services/{solo → code}/auto-compact-orchestrator.js +3 -3
  37. package/dist/src/services/{solo → code}/dag-orchestrator.d.ts +1 -1
  38. package/dist/src/services/{solo → code}/dag-orchestrator.js +1 -1
  39. package/dist/src/services/{solo → code}/emit-handoff.d.ts +1 -1
  40. package/dist/src/services/{solo → code}/emit-handoff.js +1 -1
  41. package/dist/src/services/{solo → code}/job-shape-decision.d.ts +1 -1
  42. package/dist/src/services/{solo → code}/job-shape-decision.js +5 -5
  43. package/dist/src/services/{solo → code}/mode-gate.d.ts +9 -9
  44. package/dist/src/services/{solo → code}/mode-gate.js +5 -5
  45. package/dist/src/services/{solo → code}/post-compact-detector.d.ts +3 -3
  46. package/dist/src/services/{solo → code}/post-compact-detector.js +4 -4
  47. package/dist/src/services/{solo → code}/step-08-gate.d.ts +4 -4
  48. package/dist/src/services/{solo → code}/step-08-gate.js +4 -4
  49. package/dist/src/services/{solo → code}/user-touchpoint-classifier.d.ts +1 -1
  50. package/dist/src/services/{solo → code}/user-touchpoint-classifier.js +1 -1
  51. package/dist/src/services/context/auto-compact-dispatcher.d.ts +2 -2
  52. package/dist/src/services/context/auto-compact-dispatcher.js +2 -2
  53. package/dist/src/services/context/auto-compact-types.d.ts +1 -1
  54. package/dist/src/services/crystallization/crystallization-service.d.ts +239 -0
  55. package/dist/src/services/crystallization/crystallization-service.js +397 -0
  56. package/dist/src/services/crystallization/crystallization-store.d.ts +75 -0
  57. package/dist/src/services/crystallization/crystallization-store.js +193 -0
  58. package/dist/src/services/crystallization/crystallization-types.d.ts +313 -0
  59. package/dist/src/services/crystallization/crystallization-types.js +299 -0
  60. package/dist/src/services/crystallization/evidence-brief-builder.d.ts +237 -0
  61. package/dist/src/services/crystallization/evidence-brief-builder.js +240 -0
  62. package/dist/src/services/dispatch/slice-dag.d.ts +2 -2
  63. package/dist/src/services/dispatch/test-tool-detection.d.ts +1 -1
  64. package/dist/src/services/dispatch/test-tool-detection.js +1 -1
  65. package/dist/src/services/evolution/evolution-service.d.ts +137 -0
  66. package/dist/src/services/evolution/evolution-service.js +281 -0
  67. package/dist/src/services/evolution/evolution-store.d.ts +57 -0
  68. package/dist/src/services/evolution/evolution-store.js +232 -0
  69. package/dist/src/services/evolution/evolution-types.d.ts +706 -0
  70. package/dist/src/services/evolution/evolution-types.js +286 -0
  71. package/dist/src/services/evolution/independent-evaluator-runner.d.ts +90 -0
  72. package/dist/src/services/evolution/independent-evaluator-runner.js +106 -0
  73. package/dist/src/services/evolution/regression-skeptic-runner.d.ts +64 -0
  74. package/dist/src/services/evolution/regression-skeptic-runner.js +113 -0
  75. package/dist/src/services/feedback/feedback-promotion-service.js +2 -2
  76. package/dist/src/services/job/job-progress-store.d.ts +1 -1
  77. package/dist/src/services/job/job-progress-store.js +1 -1
  78. package/dist/src/services/loop/loop-bee-relation-service.d.ts +107 -0
  79. package/dist/src/services/loop/loop-bee-relation-service.js +211 -0
  80. package/dist/src/services/loop/loop-bee-relation-store.d.ts +53 -0
  81. package/dist/src/services/loop/loop-bee-relation-store.js +130 -0
  82. package/dist/src/services/loop/loop-bee-relation-types.d.ts +118 -0
  83. package/dist/src/services/loop/loop-bee-relation-types.js +114 -0
  84. package/dist/src/services/loop/loop-release-service.d.ts +46 -0
  85. package/dist/src/services/loop/loop-release-service.js +66 -0
  86. package/dist/src/services/loop/loop-release-store.d.ts +55 -0
  87. package/dist/src/services/loop/loop-release-store.js +134 -0
  88. package/dist/src/services/loop/loop-release-types.d.ts +250 -0
  89. package/dist/src/services/loop/loop-release-types.js +162 -0
  90. package/dist/src/services/preferences/preferences-service.d.ts +1 -1
  91. package/dist/src/services/preferences/preferences-types.d.ts +1 -1
  92. package/dist/src/services/rd/standards-diagnostic.d.ts +1 -1
  93. package/dist/src/services/rd/standards-diagnostic.js +2 -2
  94. package/dist/src/services/recommendations/capability-seed-items.js +1 -1
  95. package/dist/src/services/recommendations/capability-seed-mappings.js +1 -1
  96. package/dist/src/services/recommendations/recommendation-service.js +1 -1
  97. package/dist/src/services/refactor/refactor-service.d.ts +1 -1
  98. package/dist/src/services/share/bundle-reader.d.ts +100 -0
  99. package/dist/src/services/share/bundle-reader.js +434 -0
  100. package/dist/src/services/share/bundle-types.d.ts +392 -0
  101. package/dist/src/services/share/bundle-types.js +318 -0
  102. package/dist/src/services/share/bundle-writer.d.ts +97 -0
  103. package/dist/src/services/share/bundle-writer.js +429 -0
  104. package/dist/src/services/share/run-state-contract.d.ts +133 -0
  105. package/dist/src/services/share/run-state-contract.js +138 -0
  106. package/dist/src/services/signal/cancel-handler.js +3 -3
  107. package/dist/src/services/skill/resume-detector.js +1 -1
  108. package/dist/src/services/skillhub/release-import.js +7 -2
  109. package/dist/src/services/skillhub/release-retain.js +6 -1
  110. package/dist/src/services/skillhub/sqlite-store.js +17 -1
  111. package/dist/src/services/skillhub/types.d.ts +10 -0
  112. package/dist/src/services/skills/skill-presence-service.d.ts +1 -1
  113. package/dist/src/services/standards/loop-engineering-lint.d.ts +38 -0
  114. package/dist/src/services/standards/loop-engineering-lint.js +101 -0
  115. package/dist/src/services/standards/loop-engineering-readiness-lint.d.ts +111 -0
  116. package/dist/src/services/standards/loop-engineering-readiness-lint.js +248 -0
  117. package/dist/src/services/upgrade/1x-detector-service.js +1 -1
  118. package/dist/src/services/workflow/pipeline-verify-service.d.ts +1 -1
  119. package/dist/src/services/workflow/pipeline-verify-service.js +3 -3
  120. package/dist/src/services/workflow/workflow-autonomous-service.d.ts +3 -3
  121. package/dist/src/services/workflow/workflow-autonomous-service.js +2 -2
  122. package/dist/src/services/workflow/workflow-router-service.d.ts +6 -6
  123. package/dist/src/services/workflow/workflow-router-service.js +33 -33
  124. package/dist/src/services/workspace/claude-settings-template.d.ts +1 -1
  125. package/dist/src/services/workspace/claude-settings-template.js +5 -5
  126. package/dist/src/shared/version.d.ts +1 -1
  127. package/dist/src/shared/version.js +1 -1
  128. package/examples/video-demo/README.md +57 -0
  129. package/examples/video-demo/out/en-closing-960.png +0 -0
  130. package/examples/video-demo/out/zh-closing-960.png +0 -0
  131. package/examples/video-demo/preview/peaks-loop-demo-en.mp4 +0 -0
  132. package/examples/video-demo/preview/peaks-loop-demo.mp4 +0 -0
  133. package/output-styles/peaks-skill-swarm.md +3 -3
  134. package/package.json +6 -2
  135. package/skills/bee/peaks-qa/SKILL.md +1 -1
  136. package/skills/bee/peaks-qa/references/artifact-per-request.md +3 -3
  137. package/skills/bee/peaks-qa/references/qa-sub-agent-dispatch.md +6 -6
  138. package/skills/bee/peaks-rd/references/rd-fanout-contracts.md +1 -1
  139. package/skills/bee/peaks-rd/references/rd-runbook.md +1 -1
  140. package/skills/bee/peaks-rd/references/rd-sub-agent-dispatch.md +11 -11
  141. package/skills/bee/peaks-rd/references/rd-transition-gates.md +1 -1
  142. package/skills/bee/peaks-sc/SKILL.md +1 -1
  143. package/skills/bee/peaks-txt/SKILL.md +3 -3
  144. package/skills/bee/peaks-ui/SKILL.md +8 -8
  145. package/skills/peaks-code/SKILL.md +34 -21
  146. package/skills/peaks-code/references/anchoring-and-session-info.md +2 -2
  147. package/skills/peaks-code/references/artifact-contracts.md +1 -1
  148. package/skills/peaks-code/references/boundaries.md +3 -3
  149. package/skills/peaks-code/references/codegraph-orchestration.md +1 -1
  150. package/skills/peaks-code/references/dag-orchestrator.md +7 -7
  151. package/skills/peaks-code/references/external-references.md +2 -2
  152. package/skills/peaks-code/references/fanout-mandatory.md +3 -3
  153. package/skills/peaks-code/references/fast-mode.md +2 -2
  154. package/skills/peaks-code/references/frontend-only-mode.md +9 -9
  155. package/skills/peaks-code/references/job-loop.md +1 -1
  156. package/skills/peaks-code/references/local-artifact-workspace.md +2 -2
  157. package/skills/peaks-code/references/micro-cycle.md +14 -14
  158. package/skills/peaks-code/references/mode-selection-with-stale-presence.md +5 -5
  159. package/skills/peaks-code/references/mode-selection.md +3 -3
  160. package/skills/peaks-code/references/openspec-workflow.md +16 -16
  161. package/skills/peaks-code/references/periodic-checkpoint.md +4 -4
  162. package/skills/peaks-code/references/quality-gate-cheatsheet.md +1 -1
  163. package/skills/peaks-code/references/refactor-mode.md +1 -1
  164. package/skills/peaks-code/references/runbook.md +15 -15
  165. package/skills/peaks-code/references/step-0-55-1x-detection.md +1 -1
  166. package/skills/peaks-code/references/step-0-8-gate.md +11 -11
  167. package/skills/peaks-code/references/sub-agent-dispatch.md +8 -8
  168. package/skills/peaks-code/references/swarm-dispatch-contract.md +17 -17
  169. package/skills/peaks-code/references/workflow-gates-and-types.md +2 -2
  170. package/skills/peaks-code/references/workflow.md +5 -5
  171. package/skills/peaks-content/SKILL.md +272 -0
  172. package/skills/peaks-issue-fix-orchestrator/SKILL.md +307 -0
  173. package/skills/peaks-resume/SKILL.md +2 -2
  174. package/skills/peaks-status/SKILL.md +2 -2
  175. package/skills/peaks-test/SKILL.md +2 -2
  176. /package/dist/src/services/{solo → code}/batch-heartbeat-poller.d.ts +0 -0
  177. /package/dist/src/services/{solo → code}/batch-heartbeat-poller.js +0 -0
  178. /package/dist/src/services/{solo → code}/status-line-renderer.d.ts +0 -0
  179. /package/dist/src/services/{solo → code}/status-line-renderer.js +0 -0
@@ -1,23 +1,35 @@
1
1
  /**
2
- * peaks loop * CLI (Slice #14) — L4 Agent Loop Integration.
2
+ * peaks loop * CLI (Slice #14 + M7 add).
3
3
  *
4
- * Per docs/superpowers/specs/2026-06-11-peaks-loop-l1-l2-l3-redesign.md §5.4
5
- * Slice #14, ships 5 sub-features:
4
+ * Slices:
5
+ * #14 sub-features (L4 Agent Loop integration): distill / preflight /
6
+ * detect-pattern / check-consistency / peaks goal compose.
6
7
  *
7
- * 14.1 peaks loop distill — extract patterns from past sessions
8
- * (delegates to peaks memory extract)
9
- * 14.2 peaks loop preflight — pre-run sanity checks (placeholder)
10
- * 14.3 peaks loop detect-pattern — find repeating patterns (placeholder)
11
- * 14.4 peaks loop check-consistency — verify state consistency (placeholder)
12
- * 14.5 peaks goal compose — autonomous goal composition (placeholder;
13
- * requires IDE adapter goalCommand capability
14
- * per Slice #0.7)
8
+ * M7 (2026-07-07 spec §7A.2):
9
+ * peaks loop export --loop <id> --out <path.tar.gz>
10
+ * peaks loop import --in <path.tar.gz> [--as <loop-id>]
15
11
  *
16
- * The 4 placeholders emit a clear nextActions list; the LLM-side UX
17
- * layer composes the actual runtime today.
12
+ * `peaks loop export` reads the source loop_release + relations +
13
+ * related bees + evidence briefs and emits a `peaks.bundle/1`
14
+ * tar.gz. Hard-blocks when the source has `shareable=false`.
15
+ *
16
+ * `peaks loop import` extracts a bundle, validates
17
+ * format_version_major=1, and lands the release as `candidate`
18
+ * (mandatory landing status per spec §7A.2). The receiver must run
19
+ * an independent evaluation before promoting to `stable`.
20
+ *
21
+ * The existing 14.x commands are kept under the same `loop` parent;
22
+ * M7 only ADDs export / import — it does not modify the existing
23
+ * surface.
18
24
  */
25
+ import { existsSync, mkdirSync } from 'node:fs';
26
+ import { join } from 'node:path';
19
27
  import { addJsonOption, getErrorMessage, printResult } from '../cli-helpers.js';
20
28
  import { fail, ok } from '../../shared/result.js';
29
+ import { findProjectRoot } from '../../services/config/config-safety.js';
30
+ import { openStateDb } from '../../services/skillhub/sqlite-store.js';
31
+ import { writeBundle, BundleNotShareableError, BundleAssetNotFoundError, } from '../../services/share/bundle-writer.js';
32
+ import { readBundle, BundleMajorVersionMismatchError, BundleSchemaVersionsMismatchError, BundleImportToStableForbiddenError, BundleMalformedError, } from '../../services/share/bundle-reader.js';
21
33
  export function registerLoopCommands(program, io) {
22
34
  // 14.5 peaks goal compose — registered as a TOP-LEVEL command (not under
23
35
  // `peaks loop`) because IDE adapters expose it as `goalCommand`.
@@ -125,4 +137,126 @@ export function registerLoopCommands(program, io) {
125
137
  'loop.check-consistency is a thin facade; the LLM-side UX layer composes the drift scan.',
126
138
  ]), options.json);
127
139
  });
140
+ // ---------- M7: peaks loop export / import (spec §7A.2) ----------
141
+ const LOOP_EXPORT_IMPORT_OPTS = (cmd) => cmd
142
+ .option('--project <path>', 'target project root (defaults to cwd)')
143
+ .option('--json', 'print machine-readable JSON envelope');
144
+ LOOP_EXPORT_IMPORT_OPTS(loop
145
+ .command('export')
146
+ .description("M7: export a loop_release as a peaks.bundle/1 tarball (spec §7A.2 / §10 RL-9). Refuses to export when shareable=false.")
147
+ .requiredOption('--loop <id>', 'loop_release id (kebab-case)')
148
+ .requiredOption('--out <path>', 'output .tar.gz path')).action((options) => {
149
+ const asJson = options.json === true;
150
+ try {
151
+ const projectRoot = options.project ?? findProjectRoot(process.cwd()) ?? process.cwd();
152
+ if (!existsSync(join(projectRoot, '.peaks'))) {
153
+ mkdirSync(join(projectRoot, '.peaks'), { recursive: true });
154
+ }
155
+ const db = openStateDb(join(projectRoot, '.peaks', 'state.db'));
156
+ try {
157
+ const result = writeBundle({
158
+ db,
159
+ blobsDir: join(projectRoot, '.peaks', 'blobs'),
160
+ kind: 'loop',
161
+ id: options.loop,
162
+ outPath: options.out,
163
+ });
164
+ printResult(io, ok('loop.export', {
165
+ outPath: result.outPath,
166
+ kind: result.kind,
167
+ assetId: result.assetId,
168
+ importedAs: 'candidate',
169
+ }, [], [
170
+ `Receiver must run \`peaks loop import --in ${result.outPath}\` to land this bundle, then run an independent evolution_evaluation before any promote.`,
171
+ ]), asJson);
172
+ }
173
+ finally {
174
+ db.close();
175
+ }
176
+ }
177
+ catch (error) {
178
+ if (error instanceof BundleNotShareableError) {
179
+ printResult(io, fail('loop.export', error.code, error.message, { ok: false, loop: options.loop }, [
180
+ 'Set shareable=true on the loop_release row, or share via desktop_visible=false.',
181
+ ]), asJson);
182
+ process.exitCode = 1;
183
+ return;
184
+ }
185
+ if (error instanceof BundleAssetNotFoundError) {
186
+ printResult(io, fail('loop.export', error.code, error.message, { ok: false, loop: options.loop }, [
187
+ 'Verify the loop id with `peaks asset status --loop <id>`.',
188
+ ]), asJson);
189
+ process.exitCode = 1;
190
+ return;
191
+ }
192
+ printResult(io, fail('loop.export', 'LOOP_EXPORT_FAILED', getErrorMessage(error), { ok: false, loop: options.loop }, ['Verify --loop id and --out path.']), asJson);
193
+ process.exitCode = 1;
194
+ }
195
+ });
196
+ LOOP_EXPORT_IMPORT_OPTS(loop
197
+ .command('import')
198
+ .description("M7: import a peaks.bundle/1 tarball. Lands as candidate only — promotion requires an evolution_evaluation row (spec §7A.2 / §10 RL-9 / AC-25 / AC-26).")
199
+ .requiredOption('--in <path>', 'input .tar.gz path')
200
+ .option('--as <id>', 'optional rename for the loop id when landing')).action((options) => {
201
+ const asJson = options.json === true;
202
+ try {
203
+ const projectRoot = options.project ?? findProjectRoot(process.cwd()) ?? process.cwd();
204
+ if (!existsSync(join(projectRoot, '.peaks'))) {
205
+ mkdirSync(join(projectRoot, '.peaks'), { recursive: true });
206
+ }
207
+ const db = openStateDb(join(projectRoot, '.peaks', 'state.db'));
208
+ try {
209
+ const result = readBundle({
210
+ db,
211
+ blobsDir: join(projectRoot, '.peaks', 'blobs'),
212
+ inPath: options.in,
213
+ ...(options.as !== undefined ? { asName: options.as } : {}),
214
+ });
215
+ printResult(io, ok('loop.import', {
216
+ assetId: result.assetId,
217
+ kind: result.kind,
218
+ importedAs: result.importedAs,
219
+ warnings: result.warnings,
220
+ evidenceBriefCount: result.evidenceBriefCount,
221
+ }, result.warnings, [
222
+ `Run an independent evaluation against this release before promoting; peaks loop promote refuses without an evolution_evaluation row.`,
223
+ ]), asJson);
224
+ }
225
+ finally {
226
+ db.close();
227
+ }
228
+ }
229
+ catch (error) {
230
+ if (error instanceof BundleMajorVersionMismatchError) {
231
+ printResult(io, fail('loop.import', error.code, error.message, { ok: false, receivedMajor: error.receivedMajor }, [
232
+ 'Use the matching peaks.bundle/<major> reader; this peaks build only supports major=1.',
233
+ ]), asJson);
234
+ process.exitCode = 1;
235
+ return;
236
+ }
237
+ if (error instanceof BundleSchemaVersionsMismatchError) {
238
+ printResult(io, fail('loop.import', error.code, error.message, { ok: false }, [
239
+ 'Source bundle did not declare the canonical schema versions; refuse the bundle.',
240
+ ]), asJson);
241
+ process.exitCode = 1;
242
+ return;
243
+ }
244
+ if (error instanceof BundleImportToStableForbiddenError) {
245
+ printResult(io, fail('loop.import', error.code, error.message, { ok: false }, [
246
+ 'Bundles always land as candidate; promotion to stable requires an evolution_evaluation row (AC-26).',
247
+ ]), asJson);
248
+ process.exitCode = 1;
249
+ return;
250
+ }
251
+ if (error instanceof BundleMalformedError) {
252
+ printResult(io, fail('loop.import', error.code, error.message, { ok: false, inPath: options.in }, [
253
+ 'Re-export from the source via `peaks loop export`.',
254
+ ]), asJson);
255
+ process.exitCode = 1;
256
+ return;
257
+ }
258
+ printResult(io, fail('loop.import', 'LOOP_IMPORT_FAILED', getErrorMessage(error), { ok: false, inPath: options.in }, ['Verify the bundle path and integrity.']), asJson);
259
+ process.exitCode = 1;
260
+ }
261
+ });
128
262
  }
@@ -450,6 +450,11 @@ export async function runSediment(argv, { home }) {
450
450
  finally {
451
451
  db.close();
452
452
  }
453
+ // M7 (spec §7A.2 / §10 RL-9): `peaks skill sediment export` is
454
+ // an ALIAS of `peaks loop export` for one release cycle. Emit
455
+ // the deprecation warning to stderr so downstream tooling can
456
+ // upgrade. Future slice removes the alias.
457
+ process.stderr.write("warning: 'peaks skill sediment export' is deprecated; use 'peaks loop export' or 'peaks bee export' (peaks.bundle/1, spec §7A.2)\n");
453
458
  return { ok: true, data: { outPath } };
454
459
  }
455
460
  case "import": {
@@ -479,6 +484,10 @@ export async function runSediment(argv, { home }) {
479
484
  finally {
480
485
  db.close();
481
486
  }
487
+ // M7 (spec §7A.2): `peaks skill sediment import` is an ALIAS of
488
+ // `peaks loop import` for one release cycle. Emit the
489
+ // deprecation warning so downstream tooling can upgrade.
490
+ process.stderr.write("warning: 'peaks skill sediment import' is deprecated; use 'peaks loop import' or 'peaks bee import' (peaks.bundle/1, spec §7A.2)\n");
482
491
  return { ok: true, data: { asName: asName ?? basename(bundlePath) } };
483
492
  }
484
493
  case "gc-blobs": {
@@ -86,7 +86,7 @@ export function registerSessionAutoCompactHookCommand(session) {
86
86
  if (probe.ratio < RED_LINE_RATIO) {
87
87
  // Below red line → exit 0 silent. The orchestrator's
88
88
  // pre-compact zone (0.85–0.95) is handled out-of-band by
89
- // the LLM firing `peaks solo auto-compact --execute`; the
89
+ // the LLM firing `peaks code auto-compact --execute`; the
90
90
  // hook only fires on the synchronous red-line path.
91
91
  return;
92
92
  }
@@ -102,7 +102,7 @@ export function registerSessionAutoCompactHookCommand(session) {
102
102
  // binary), `spawn` raises ENOENT. Catching this MUST NOT crash
103
103
  // the runner's tool call — the hook must exit 0 silently with
104
104
  // a one-line stderr hint so the runner keeps working. The user
105
- // can then run `/compact` manually (or `peaks solo auto-compact`
105
+ // can then run `/compact` manually (or `peaks code auto-compact`
106
106
  // from another terminal).
107
107
  try {
108
108
  const child = spawn('claude', ['--compact'], {
@@ -0,0 +1,67 @@
1
+ /**
2
+ * `peaks skill lint --category loop-engineering-readiness` — M6 / spec §7.5 + §8.4
3
+ *
4
+ * Loop Engineering readiness gate for any new peaks-* skill that
5
+ * participates in Loop Engineering (crystallization or evolution).
6
+ *
7
+ * Usage:
8
+ * peaks skill lint --category loop-engineering-readiness --path <skill-dir>
9
+ * peaks skill lint --category loop-engineering-readiness --path <skill-dir> --json
10
+ *
11
+ * The command:
12
+ * 1. Resolves <skill-dir>/SKILL.md (default if the path is a file).
13
+ * 2. Calls lintSkillLoopEngineeringReadiness() with the file contents.
14
+ * 3. Prints a structured JSON envelope via printResult (or a
15
+ * human-readable summary when --json is omitted).
16
+ * 4. Sets process.exitCode = 1 on a non-ok result, so the LLM
17
+ * gate can short-circuit a future peaks-* skill that fails the
18
+ * lint.
19
+ *
20
+ * The lint asserts three structural properties:
21
+ * 1. the SKILL.md references
22
+ * `.peaks/standards/loop-engineering-guidelines.md`;
23
+ * 2. the SKILL.md does not introduce a CLI verb the user is meant
24
+ * to type (only LLM-coordinated verbs from the sediment /
25
+ * asset / evolution surface are allowed; RL-1);
26
+ * 3. the SKILL.md does not introduce a JSON / manifest
27
+ * hand-authoring surface (RL-1).
28
+ *
29
+ * The user never types `peaks skill lint …` — the LLM runs it on
30
+ * the user's behalf. This command is also reachable as
31
+ * `peaks skill ready --category loop-engineering-readiness
32
+ * --path <skill-dir>`
33
+ * via a small alias added at the bottom of this file.
34
+ */
35
+ import type { Command } from 'commander';
36
+ import { type ProgramIO } from '../cli-helpers.js';
37
+ export declare const LOOP_ENGINEERING_READINESS_CATEGORY = "loop-engineering-readiness";
38
+ /**
39
+ * Resolve the SKILL.md file path from a `--path <skill-dir>` value.
40
+ *
41
+ * Accepts either:
42
+ * - a directory containing a SKILL.md (the common case for a
43
+ * peaks-* skill: `src/skills/<id>/`, `skills/<id>/`, etc.);
44
+ * - a direct file path to a SKILL.md.
45
+ *
46
+ * Returns the absolute path to the SKILL.md, or null if no SKILL.md
47
+ * is found.
48
+ */
49
+ export declare function resolveSkillMdPath(rawPath: string): string | null;
50
+ /**
51
+ * Pure helper: run the readiness lint against the SKILL.md text and
52
+ * return a CLI-shaped envelope. Kept separate from the Commander
53
+ * action so unit + integration tests can drive it without spawning
54
+ * a child process.
55
+ */
56
+ export declare function runReadinessLint(rawPath: string): {
57
+ ok: boolean;
58
+ code: string;
59
+ message: string;
60
+ data: {
61
+ path: string;
62
+ category: string;
63
+ findings: string[];
64
+ };
65
+ nextActions: string[];
66
+ };
67
+ export declare function registerSkillLoopEngineeringReadinessCommands(program: Command, io: ProgramIO): void;
@@ -0,0 +1,173 @@
1
+ /**
2
+ * `peaks skill lint --category loop-engineering-readiness` — M6 / spec §7.5 + §8.4
3
+ *
4
+ * Loop Engineering readiness gate for any new peaks-* skill that
5
+ * participates in Loop Engineering (crystallization or evolution).
6
+ *
7
+ * Usage:
8
+ * peaks skill lint --category loop-engineering-readiness --path <skill-dir>
9
+ * peaks skill lint --category loop-engineering-readiness --path <skill-dir> --json
10
+ *
11
+ * The command:
12
+ * 1. Resolves <skill-dir>/SKILL.md (default if the path is a file).
13
+ * 2. Calls lintSkillLoopEngineeringReadiness() with the file contents.
14
+ * 3. Prints a structured JSON envelope via printResult (or a
15
+ * human-readable summary when --json is omitted).
16
+ * 4. Sets process.exitCode = 1 on a non-ok result, so the LLM
17
+ * gate can short-circuit a future peaks-* skill that fails the
18
+ * lint.
19
+ *
20
+ * The lint asserts three structural properties:
21
+ * 1. the SKILL.md references
22
+ * `.peaks/standards/loop-engineering-guidelines.md`;
23
+ * 2. the SKILL.md does not introduce a CLI verb the user is meant
24
+ * to type (only LLM-coordinated verbs from the sediment /
25
+ * asset / evolution surface are allowed; RL-1);
26
+ * 3. the SKILL.md does not introduce a JSON / manifest
27
+ * hand-authoring surface (RL-1).
28
+ *
29
+ * The user never types `peaks skill lint …` — the LLM runs it on
30
+ * the user's behalf. This command is also reachable as
31
+ * `peaks skill ready --category loop-engineering-readiness
32
+ * --path <skill-dir>`
33
+ * via a small alias added at the bottom of this file.
34
+ */
35
+ import { readFileSync, existsSync, statSync } from 'node:fs';
36
+ import { join, resolve } from 'node:path';
37
+ import { lintSkillLoopEngineeringReadiness, } from '../../services/standards/loop-engineering-readiness-lint.js';
38
+ import { addJsonOption, getErrorMessage, printResult } from '../cli-helpers.js';
39
+ import { fail, ok } from '../../shared/result.js';
40
+ export const LOOP_ENGINEERING_READINESS_CATEGORY = 'loop-engineering-readiness';
41
+ /**
42
+ * Resolve the SKILL.md file path from a `--path <skill-dir>` value.
43
+ *
44
+ * Accepts either:
45
+ * - a directory containing a SKILL.md (the common case for a
46
+ * peaks-* skill: `src/skills/<id>/`, `skills/<id>/`, etc.);
47
+ * - a direct file path to a SKILL.md.
48
+ *
49
+ * Returns the absolute path to the SKILL.md, or null if no SKILL.md
50
+ * is found.
51
+ */
52
+ export function resolveSkillMdPath(rawPath) {
53
+ const abs = resolve(rawPath);
54
+ if (!existsSync(abs))
55
+ return null;
56
+ const st = statSync(abs);
57
+ if (st.isFile()) {
58
+ return abs.toLowerCase().endsWith('skill.md') ? abs : null;
59
+ }
60
+ if (st.isDirectory()) {
61
+ const candidate = join(abs, 'SKILL.md');
62
+ return existsSync(candidate) ? candidate : null;
63
+ }
64
+ return null;
65
+ }
66
+ /**
67
+ * Pure helper: run the readiness lint against the SKILL.md text and
68
+ * return a CLI-shaped envelope. Kept separate from the Commander
69
+ * action so unit + integration tests can drive it without spawning
70
+ * a child process.
71
+ */
72
+ export function runReadinessLint(rawPath) {
73
+ const skillMdPath = resolveSkillMdPath(rawPath);
74
+ if (!skillMdPath) {
75
+ return {
76
+ ok: false,
77
+ code: 'SKILL_FILE_NOT_FOUND',
78
+ message: `could not resolve SKILL.md from --path ${rawPath}`,
79
+ data: { path: rawPath, category: LOOP_ENGINEERING_READINESS_CATEGORY, findings: [] },
80
+ nextActions: [
81
+ 'Pass a directory containing SKILL.md or a direct path to a SKILL.md file.',
82
+ ],
83
+ };
84
+ }
85
+ const text = readFileSync(skillMdPath, 'utf-8');
86
+ const result = lintSkillLoopEngineeringReadiness(text);
87
+ if (result.ok) {
88
+ return {
89
+ ok: true,
90
+ code: 'SKILL_READINESS_OK',
91
+ message: 'SKILL.md passes the Loop Engineering readiness lint',
92
+ data: {
93
+ path: skillMdPath,
94
+ category: LOOP_ENGINEERING_READINESS_CATEGORY,
95
+ findings: [],
96
+ },
97
+ nextActions: [
98
+ 'The skill is allowed to participate in Loop Engineering (crystallization / evolution).',
99
+ ],
100
+ };
101
+ }
102
+ return {
103
+ ok: false,
104
+ code: 'SKILL_READINESS_FAILED',
105
+ message: `SKILL.md failed the Loop Engineering readiness lint (${result.findings.length} finding(s))`,
106
+ data: {
107
+ path: skillMdPath,
108
+ category: LOOP_ENGINEERING_READINESS_CATEGORY,
109
+ findings: result.findings,
110
+ },
111
+ nextActions: [
112
+ 'Address every finding listed in data.findings, then re-run the lint.',
113
+ 'See src/services/standards/loop-engineering-readiness-lint.ts for the rule definitions.',
114
+ 'See .peaks/standards/loop-engineering-guidelines.md for the red lines the lint enforces.',
115
+ ],
116
+ };
117
+ }
118
+ function lintAction(options, io) {
119
+ if (options.category !== LOOP_ENGINEERING_READINESS_CATEGORY) {
120
+ printResult(io, fail('skill.lint', 'UNKNOWN_LINT_CATEGORY', `only --category ${LOOP_ENGINEERING_READINESS_CATEGORY} is implemented in M6`, { category: options.category ?? null }, [
121
+ `Pass --category ${LOOP_ENGINEERING_READINESS_CATEGORY}.`,
122
+ ]), options.json);
123
+ process.exitCode = 1;
124
+ return;
125
+ }
126
+ if (!options.path) {
127
+ printResult(io, fail('skill.lint', 'MISSING_PATH', '--path <skill-dir> is required', { category: options.category }, ['Pass --path pointing at a peaks-* skill directory containing SKILL.md.']), options.json);
128
+ process.exitCode = 1;
129
+ return;
130
+ }
131
+ try {
132
+ const envelope = runReadinessLint(options.path);
133
+ if (envelope.ok) {
134
+ printResult(io, ok('skill.lint', envelope.data, [], envelope.nextActions), options.json);
135
+ return;
136
+ }
137
+ printResult(io, fail('skill.lint', envelope.code, envelope.message, envelope.data, envelope.nextActions), options.json);
138
+ process.exitCode = 1;
139
+ }
140
+ catch (error) {
141
+ printResult(io, fail('skill.lint', 'SKILL_READINESS_ERROR', getErrorMessage(error), { path: options.path }, ['Verify the path is readable.']), options.json);
142
+ process.exitCode = 1;
143
+ }
144
+ }
145
+ export function registerSkillLoopEngineeringReadinessCommands(program, io) {
146
+ // `peaks skill lint --category loop-engineering-readiness --path <skill-dir>`
147
+ // — primary surface, named to match the spec §7.5 / §8.4 wording.
148
+ // We reuse the existing `skill` parent if one is registered; per
149
+ // the add-a-new-subcommand-check-for-existing-top-level-first rule,
150
+ // we never re-create `skill` when it's already there.
151
+ const existingSkill = program.commands.find((c) => c.name() === 'skill');
152
+ const skill = existingSkill ?? program
153
+ .command('skill')
154
+ .description('skill operations (M6: lint --category loop-engineering-readiness)');
155
+ addJsonOption(skill
156
+ .command('lint')
157
+ .description(`M6: lint a peaks-* SKILL.md against a category. Currently supports --category ${LOOP_ENGINEERING_READINESS_CATEGORY} (spec §7.5 / §8.4 / RL-8).`)
158
+ .option('--category <name>', `lint category; the M6 implementation only supports ${LOOP_ENGINEERING_READINESS_CATEGORY}`, LOOP_ENGINEERING_READINESS_CATEGORY)
159
+ .requiredOption('--path <skill-dir>', 'path to a peaks-* skill directory (containing SKILL.md) or directly to a SKILL.md file')).action((options) => lintAction(options, io));
160
+ // `peaks skill ready --category loop-engineering-readiness --path <skill-dir>`
161
+ // — alias verb chosen by M6 for human-facing callouts. It points at
162
+ // the same handler; both verbs are first-class so users (LLM
163
+ // proxies) can pick whichever phrasing fits the conversation.
164
+ // Per the spec, the user never types either verb; the LLM runs the
165
+ // CLI on the user's behalf.
166
+ skill
167
+ .command('ready')
168
+ .description(`M6 alias for \`peaks skill lint --category ${LOOP_ENGINEERING_READINESS_CATEGORY}\`; same flags, same exit codes.`)
169
+ .option('--category <name>', `lint category; the M6 implementation only supports ${LOOP_ENGINEERING_READINESS_CATEGORY}`, LOOP_ENGINEERING_READINESS_CATEGORY)
170
+ .requiredOption('--path <skill-dir>', 'path to a peaks-* skill directory or SKILL.md file')
171
+ .option('--json', 'print machine-readable JSON envelope')
172
+ .action((options) => lintAction(options, io));
173
+ }
@@ -71,7 +71,7 @@ export type AwaitOptions = {
71
71
  * to keep the warm-path dispatch CLI cold-start fast (slice 9).
72
72
  */
73
73
  export type SliceDagModule = typeof import('../../services/dispatch/slice-dag.js');
74
- export type DagOrchestratorModule = typeof import('../../services/solo/dag-orchestrator.js');
74
+ export type DagOrchestratorModule = typeof import('../../services/code/dag-orchestrator.js');
75
75
  export type ContractStoreModule = typeof import('../../services/dispatch/contract-store.js');
76
76
  /**
77
77
  * Validate a role string. Returns `null` when valid, otherwise the
@@ -1,12 +1,12 @@
1
1
  /**
2
2
  * v2.15.0 follow-up — G4: user touchpoint CLI.
3
3
  *
4
- * - `peaks solo gate-classify --step <step-id>` — classify a single
5
- * Solo gate (business / tech / mode-selection / commit-boundary /
4
+ * - `peaks code gate-classify --step <step-id>` — classify a single
5
+ * Code gate (business / tech / mode-selection / commit-boundary /
6
6
  * commit-floor)
7
- * - `peaks solo user-touchpoints` — list all gates the
7
+ * - `peaks code user-touchpoints` — list all gates the
8
8
  * user must review (vs AI auto-decides in full-auto)
9
- * - `peaks solo commit-boundary-actions` — list the 5
9
+ * - `peaks code commit-boundary-actions` — list the 5
10
10
  * hard-floor commit actions (push / tag / publish / global
11
11
  * install)
12
12
  *
@@ -1,45 +1,45 @@
1
1
  /**
2
2
  * v2.15.0 follow-up — G4: user touchpoint CLI.
3
3
  *
4
- * - `peaks solo gate-classify --step <step-id>` — classify a single
5
- * Solo gate (business / tech / mode-selection / commit-boundary /
4
+ * - `peaks code gate-classify --step <step-id>` — classify a single
5
+ * Code gate (business / tech / mode-selection / commit-boundary /
6
6
  * commit-floor)
7
- * - `peaks solo user-touchpoints` — list all gates the
7
+ * - `peaks code user-touchpoints` — list all gates the
8
8
  * user must review (vs AI auto-decides in full-auto)
9
- * - `peaks solo commit-boundary-actions` — list the 5
9
+ * - `peaks code commit-boundary-actions` — list the 5
10
10
  * hard-floor commit actions (push / tag / publish / global
11
11
  * install)
12
12
  *
13
13
  * Surfaces the 12 Gaps positioning memory rule:
14
14
  * "user 在循环里 = 业务/产品审阅者,不参与技术决策"
15
15
  */
16
- import { aiAutoDecidesGates, classifyGate, COMMIT_BOUNDARY_ACTIONS_LIST, userMustReviewGates } from '../../services/solo/user-touchpoint-classifier.js';
16
+ import { aiAutoDecidesGates, classifyGate, COMMIT_BOUNDARY_ACTIONS_LIST, userMustReviewGates } from '../../services/code/user-touchpoint-classifier.js';
17
17
  import { fail, ok } from '../../shared/result.js';
18
18
  import { addJsonOption, printResult } from '../cli-helpers.js';
19
19
  export function registerUserTouchpointCommands(program, io) {
20
20
  // G4 commands are registered as TOP-LEVEL commands (not sub-commands
21
- // of `peaks solo`) because `peaks solo` is a SKILL (consumed by the
21
+ // of `peaks code`) because `peaks code` is a SKILL (consumed by the
22
22
  // LLM in SKILL.md), not a CLI command. Top-level names: gate-classify /
23
23
  // user-touchpoints / commit-boundary-actions.
24
24
  //
25
- // We do NOT create a new `peaks solo` CLI command here because that
25
+ // We do NOT create a new `peaks code` CLI command here because that
26
26
  // would conflict with the peaks-code skill presence tracking (see
27
27
  // `src/services/skills/skill-presence-service.ts`).
28
28
  addJsonOption(program
29
29
  .command('gate-classify')
30
- .description('v2.15.0 follow-up G4: classify a single Solo gate by its decision kind: ' +
30
+ .description('v2.15.0 follow-up G4: classify a single Code gate by its decision kind: ' +
31
31
  'business / tech / mode-selection / commit-boundary / commit-floor. ' +
32
32
  'Returns null when the step is unknown.')
33
33
  .requiredOption('--step <step-id>', 'step id (e.g. step-1-mode-select, phase-2-prd-confirm)')).action((opts) => {
34
34
  const c = classifyGate(opts.step);
35
35
  if (c === null) {
36
- printResult(io, fail('solo.gate-classify', 'UNKNOWN_STEP', `unknown step "${opts.step}"`, {}, [
37
- 'Run `peaks solo user-touchpoints` to list all known steps.'
36
+ printResult(io, fail('code.gate-classify', 'UNKNOWN_STEP', `unknown step "${opts.step}"`, {}, [
37
+ 'Run `peaks code user-touchpoints` to list all known steps.'
38
38
  ]), opts.json ?? false);
39
39
  process.exitCode = 1;
40
40
  return;
41
41
  }
42
- printResult(io, ok('solo.gate-classify', { classification: c }, [], [
42
+ printResult(io, ok('code.gate-classify', { classification: c }, [], [
43
43
  c.userShouldReview === 'always'
44
44
  ? 'User must review this gate in all modes.'
45
45
  : c.userShouldReview === 'business-only'
@@ -49,12 +49,12 @@ export function registerUserTouchpointCommands(program, io) {
49
49
  });
50
50
  addJsonOption(program
51
51
  .command('user-touchpoints')
52
- .description('List all Solo gates the user must review. The 12 Gaps positioning ' +
52
+ .description('List all Code gates the user must review. The 12 Gaps positioning ' +
53
53
  'memory: user 在循环里 = 业务/产品审阅者,不参与技术决策。 ' +
54
54
  'These are the only gates where the user is asked to decide.')).action((opts) => {
55
55
  const must = userMustReviewGates();
56
56
  const auto = aiAutoDecidesGates();
57
- printResult(io, ok('solo.user-touchpoints', {
57
+ printResult(io, ok('code.user-touchpoints', {
58
58
  userMustReview: must,
59
59
  aiAutoDecides: auto,
60
60
  counts: {
@@ -71,7 +71,7 @@ export function registerUserTouchpointCommands(program, io) {
71
71
  .description('List the 5 commit-boundary hard-floor actions. These are the ' +
72
72
  'actions that PAUSE even in full-auto (v2.15.0 slice 002 AC-4 rule: ' +
73
73
  '"full-auto 只做到 commit"). The user is always asked to confirm.')).action((opts) => {
74
- printResult(io, ok('solo.commit-boundary-actions', { actions: COMMIT_BOUNDARY_ACTIONS_LIST }, [], [
74
+ printResult(io, ok('code.commit-boundary-actions', { actions: COMMIT_BOUNDARY_ACTIONS_LIST }, [], [
75
75
  'Even in full-auto, the user must explicitly confirm these actions.'
76
76
  ]), opts.json ?? false);
77
77
  });