peaks-loop 4.0.21 → 4.0.24

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 (57) hide show
  1. package/CHANGELOG.md +109 -0
  2. package/dist/cli/commands/_register.js +2 -1
  3. package/dist/cli/commands/best-practice-scan-command.d.ts +36 -0
  4. package/dist/cli/commands/best-practice-scan-command.js +118 -0
  5. package/dist/cli/commands/request-commands.js +21 -9
  6. package/dist/services/best-practice/language-detector.d.ts +7 -0
  7. package/dist/services/best-practice/language-detector.js +96 -0
  8. package/dist/services/best-practice/output-formatter.d.ts +41 -0
  9. package/dist/services/best-practice/output-formatter.js +116 -0
  10. package/dist/services/best-practice/scan-orchestrator.d.ts +39 -0
  11. package/dist/services/best-practice/scan-orchestrator.js +85 -0
  12. package/dist/services/context/collector.d.ts +5 -12
  13. package/dist/services/context/context-builder.d.ts +12 -20
  14. package/dist/services/context/context-builder.js +1 -1
  15. package/dist/services/context/context-schema.d.ts +51 -364
  16. package/dist/services/context/context-schema.js +3 -3
  17. package/dist/services/crystallization/crystallization-service.d.ts +2 -12
  18. package/dist/services/crystallization/crystallization-service.js +3 -9
  19. package/dist/services/crystallization/crystallization-types.d.ts +45 -153
  20. package/dist/services/crystallization/crystallization-types.js +17 -11
  21. package/dist/services/crystallization/evidence-brief-builder.d.ts +12 -112
  22. package/dist/services/evolution/evolution-types.d.ts +83 -497
  23. package/dist/services/evolution/evolution-types.js +6 -10
  24. package/dist/services/fixture/fixture-sanitize-service.d.ts +10 -36
  25. package/dist/services/fixture/fixture-sanitize-service.js +1 -1
  26. package/dist/services/job/job-progress-store.d.ts +1 -17
  27. package/dist/services/job/job-progress-store.js +2 -2
  28. package/dist/services/job/job-types.d.ts +63 -370
  29. package/dist/services/job/job-types.js +46 -11
  30. package/dist/services/loop/loop-bee-relation-types.d.ts +20 -32
  31. package/dist/services/loop/loop-bee-relation-types.js +2 -2
  32. package/dist/services/loop/loop-release-types.d.ts +31 -110
  33. package/dist/services/migrate-skill-name/schema.d.ts +3 -19
  34. package/dist/services/migrate-skill-name/schema.js +4 -4
  35. package/dist/services/observability/observability-service.d.ts +21 -19
  36. package/dist/services/observability/observability-service.js +1 -1
  37. package/dist/services/prd/best-practice-auto-trigger.d.ts +61 -0
  38. package/dist/services/prd/best-practice-auto-trigger.js +126 -0
  39. package/dist/services/rd/types.d.ts +25 -194
  40. package/dist/services/sediment/json-schema.d.ts +39 -224
  41. package/dist/services/sediment/json-schema.js +2 -2
  42. package/dist/services/session/binding-store.d.ts +5 -47
  43. package/dist/services/session/binding-store.js +1 -1
  44. package/dist/services/share/bundle-types.d.ts +12 -180
  45. package/dist/services/share/bundle-types.js +15 -9
  46. package/dist/services/share/run-state-contract.d.ts +8 -25
  47. package/dist/services/skill/skill-search-service.d.ts +26 -46
  48. package/dist/services/skill/skill-search-service.js +2 -2
  49. package/dist/services/skills/hooks-settings-service.d.ts +9 -0
  50. package/dist/services/skills/hooks-settings-service.js +31 -1
  51. package/dist/services/skills/skill-presence-service.d.ts +24 -0
  52. package/dist/services/skills/skill-presence-service.js +33 -0
  53. package/package.json +8 -8
  54. package/schemas/context.schema.json +17 -8
  55. package/skills/bee/peaks-prd/SKILL.md +17 -0
  56. package/skills/peaks-code/SKILL.md +28 -1
  57. package/skills/peaks-code/references/skill-presence-and-title.md +3 -3
@@ -105,17 +105,7 @@ export declare const SchemaVersionsMappingSchema: z.ZodObject<{
105
105
  bee: z.ZodLiteral<"peaks.bee/1">;
106
106
  loop_bee_relation: z.ZodLiteral<"peaks.loop-bee-relation/1">;
107
107
  crystallization: z.ZodLiteral<"peaks.crystallization/1">;
108
- }, "strict", z.ZodTypeAny, {
109
- loop: "peaks.loop/1";
110
- bee: "peaks.bee/1";
111
- loop_bee_relation: "peaks.loop-bee-relation/1";
112
- crystallization: "peaks.crystallization/1";
113
- }, {
114
- loop: "peaks.loop/1";
115
- bee: "peaks.bee/1";
116
- loop_bee_relation: "peaks.loop-bee-relation/1";
117
- crystallization: "peaks.crystallization/1";
118
- }>;
108
+ }, z.core.$strict>;
119
109
  export type SchemaVersionsMapping = z.infer<typeof SchemaVersionsMappingSchema>;
120
110
  /**
121
111
  * The bundle explicitly excludes private run-state, the user's
@@ -130,15 +120,7 @@ export declare const ExclusionManifestSchema: z.ZodObject<{
130
120
  private_run_state: z.ZodLiteral<"excluded">;
131
121
  personal_memory: z.ZodLiteral<"excluded">;
132
122
  state_db_rows: z.ZodLiteral<"excluded">;
133
- }, "strict", z.ZodTypeAny, {
134
- private_run_state: "excluded";
135
- personal_memory: "excluded";
136
- state_db_rows: "excluded";
137
- }, {
138
- private_run_state: "excluded";
139
- personal_memory: "excluded";
140
- state_db_rows: "excluded";
141
- }>;
123
+ }, z.core.$strict>;
142
124
  export type ExclusionManifest = z.infer<typeof ExclusionManifestSchema>;
143
125
  /**
144
126
  * Bundle kind. A bundle is anchored on exactly one asset: either a
@@ -162,181 +144,31 @@ export type PeaksBundleKind = (typeof PEAKS_BUNDLE_KINDS)[number];
162
144
  * canonical literal.
163
145
  * - `exclusion_manifest` declares the three hard excludes.
164
146
  */
165
- export declare const BundleManifestSchema: z.ZodEffects<z.ZodObject<{
166
- /**
167
- * The format constant. Pinned to `"peaks.bundle/1"`. A future
168
- * format change is a major bump + a new constant value.
169
- */
147
+ export declare const BundleManifestSchema: z.ZodObject<{
170
148
  format_constant: z.ZodLiteral<"peaks.bundle/1">;
171
- /**
172
- * Major version. The reader requires `1`; anything else is a
173
- * HARD block. Enforced at the read boundary, not here.
174
- */
175
149
  format_version_major: z.ZodLiteral<1>;
176
- /**
177
- * Minor version. Defaults to `0`. Major-compatible bumps are a
178
- * non-fatal warn at read time.
179
- */
180
150
  format_version_minor: z.ZodDefault<z.ZodNumber>;
181
- /**
182
- * Schema-version mapping. Every required key MUST be present
183
- * with its canonical literal; unknown keys are rejected by
184
- * `.strict()`.
185
- */
186
151
  schema_versions: z.ZodObject<{
187
152
  loop: z.ZodLiteral<"peaks.loop/1">;
188
153
  bee: z.ZodLiteral<"peaks.bee/1">;
189
154
  loop_bee_relation: z.ZodLiteral<"peaks.loop-bee-relation/1">;
190
155
  crystallization: z.ZodLiteral<"peaks.crystallization/1">;
191
- }, "strict", z.ZodTypeAny, {
192
- loop: "peaks.loop/1";
193
- bee: "peaks.bee/1";
194
- loop_bee_relation: "peaks.loop-bee-relation/1";
195
- crystallization: "peaks.crystallization/1";
196
- }, {
197
- loop: "peaks.loop/1";
198
- bee: "peaks.bee/1";
199
- loop_bee_relation: "peaks.loop-bee-relation/1";
200
- crystallization: "peaks.crystallization/1";
156
+ }, z.core.$strict>;
157
+ kind: z.ZodEnum<{
158
+ loop: "loop";
159
+ bee: "bee";
201
160
  }>;
202
- /**
203
- * Anchor kind. Decides whether `loop_release` or `bee_release`
204
- * is required below.
205
- */
206
- kind: z.ZodEnum<["loop", "bee"]>;
207
- /**
208
- * The loop_release row. Required when `kind === "loop"`,
209
- * omitted (or absent) when `kind === "bee"`. The writer leaves
210
- * it `undefined` for `bee` bundles; the JSON shape is allowed
211
- * to omit it.
212
- */
213
161
  loop_release: z.ZodOptional<z.ZodUnknown>;
214
- /**
215
- * The bee_release row. Required when `kind === "bee"`,
216
- * optional for `kind === "loop"` (a loop bundle may include a
217
- * main bee inline). When present, the reader uses the service
218
- * layer to re-validate the row shape.
219
- */
220
162
  bee_release: z.ZodOptional<z.ZodUnknown>;
221
- /**
222
- * Related bee_release rows for the loop kind (main + supporting
223
- * + candidate + retired). Empty for `kind === "bee"`.
224
- */
225
- related_bee_releases: z.ZodDefault<z.ZodArray<z.ZodUnknown, "many">>;
226
- /**
227
- * Loop↔bee relation rows from `loop_bee_relation`. Always
228
- * present (possibly empty).
229
- */
230
- loop_bee_relations: z.ZodDefault<z.ZodArray<z.ZodUnknown, "many">>;
231
- /**
232
- * Evidence briefs (crystallization_event rows) that back the
233
- * bundle's assets. The receiver uses them to render the
234
- * post-import crystallization prompt + a brief for any
235
- * subsequent independent evaluation.
236
- */
237
- evidence_briefs: z.ZodDefault<z.ZodArray<z.ZodUnknown, "many">>;
238
- /**
239
- * Exclusion manifest — explicit declarations of the three
240
- * hard excludes per spec §7A.2.
241
- */
163
+ related_bee_releases: z.ZodDefault<z.ZodArray<z.ZodUnknown>>;
164
+ loop_bee_relations: z.ZodDefault<z.ZodArray<z.ZodUnknown>>;
165
+ evidence_briefs: z.ZodDefault<z.ZodArray<z.ZodUnknown>>;
242
166
  exclusion_manifest: z.ZodObject<{
243
167
  private_run_state: z.ZodLiteral<"excluded">;
244
168
  personal_memory: z.ZodLiteral<"excluded">;
245
169
  state_db_rows: z.ZodLiteral<"excluded">;
246
- }, "strict", z.ZodTypeAny, {
247
- private_run_state: "excluded";
248
- personal_memory: "excluded";
249
- state_db_rows: "excluded";
250
- }, {
251
- private_run_state: "excluded";
252
- personal_memory: "excluded";
253
- state_db_rows: "excluded";
254
- }>;
255
- }, "strict", z.ZodTypeAny, {
256
- kind: "loop" | "bee";
257
- format_constant: "peaks.bundle/1";
258
- format_version_major: 1;
259
- format_version_minor: number;
260
- schema_versions: {
261
- loop: "peaks.loop/1";
262
- bee: "peaks.bee/1";
263
- loop_bee_relation: "peaks.loop-bee-relation/1";
264
- crystallization: "peaks.crystallization/1";
265
- };
266
- related_bee_releases: unknown[];
267
- loop_bee_relations: unknown[];
268
- evidence_briefs: unknown[];
269
- exclusion_manifest: {
270
- private_run_state: "excluded";
271
- personal_memory: "excluded";
272
- state_db_rows: "excluded";
273
- };
274
- loop_release?: unknown;
275
- bee_release?: unknown;
276
- }, {
277
- kind: "loop" | "bee";
278
- format_constant: "peaks.bundle/1";
279
- format_version_major: 1;
280
- schema_versions: {
281
- loop: "peaks.loop/1";
282
- bee: "peaks.bee/1";
283
- loop_bee_relation: "peaks.loop-bee-relation/1";
284
- crystallization: "peaks.crystallization/1";
285
- };
286
- exclusion_manifest: {
287
- private_run_state: "excluded";
288
- personal_memory: "excluded";
289
- state_db_rows: "excluded";
290
- };
291
- format_version_minor?: number | undefined;
292
- loop_release?: unknown;
293
- bee_release?: unknown;
294
- related_bee_releases?: unknown[] | undefined;
295
- loop_bee_relations?: unknown[] | undefined;
296
- evidence_briefs?: unknown[] | undefined;
297
- }>, {
298
- kind: "loop" | "bee";
299
- format_constant: "peaks.bundle/1";
300
- format_version_major: 1;
301
- format_version_minor: number;
302
- schema_versions: {
303
- loop: "peaks.loop/1";
304
- bee: "peaks.bee/1";
305
- loop_bee_relation: "peaks.loop-bee-relation/1";
306
- crystallization: "peaks.crystallization/1";
307
- };
308
- related_bee_releases: unknown[];
309
- loop_bee_relations: unknown[];
310
- evidence_briefs: unknown[];
311
- exclusion_manifest: {
312
- private_run_state: "excluded";
313
- personal_memory: "excluded";
314
- state_db_rows: "excluded";
315
- };
316
- loop_release?: unknown;
317
- bee_release?: unknown;
318
- }, {
319
- kind: "loop" | "bee";
320
- format_constant: "peaks.bundle/1";
321
- format_version_major: 1;
322
- schema_versions: {
323
- loop: "peaks.loop/1";
324
- bee: "peaks.bee/1";
325
- loop_bee_relation: "peaks.loop-bee-relation/1";
326
- crystallization: "peaks.crystallization/1";
327
- };
328
- exclusion_manifest: {
329
- private_run_state: "excluded";
330
- personal_memory: "excluded";
331
- state_db_rows: "excluded";
332
- };
333
- format_version_minor?: number | undefined;
334
- loop_release?: unknown;
335
- bee_release?: unknown;
336
- related_bee_releases?: unknown[] | undefined;
337
- loop_bee_relations?: unknown[] | undefined;
338
- evidence_briefs?: unknown[] | undefined;
339
- }>;
170
+ }, z.core.$strict>;
171
+ }, z.core.$strict>;
340
172
  export type BundleManifest = z.infer<typeof BundleManifestSchema>;
341
173
  /**
342
174
  * Strict-parse an unknown value as a BundleManifest. Throws
@@ -228,17 +228,23 @@ export const BundleManifestSchema = z
228
228
  exclusion_manifest: ExclusionManifestSchema,
229
229
  })
230
230
  .strict()
231
- .refine((m) => {
231
+ .superRefine((m, ctx) => {
232
232
  // kind === 'loop' implies loop_release is required.
233
- if (m.kind === "loop" && m.loop_release === undefined)
234
- return false;
233
+ if (m.kind === "loop" && m.loop_release === undefined) {
234
+ ctx.addIssue({
235
+ code: 'custom',
236
+ path: [],
237
+ message: "bundle manifest is inconsistent: kind='loop' requires loop_release; kind='bee' requires bee_release (spec §7A.2)",
238
+ });
239
+ }
235
240
  // kind === 'bee' implies bee_release is required.
236
- if (m.kind === "bee" && m.bee_release === undefined)
237
- return false;
238
- return true;
239
- }, {
240
- message: "bundle manifest is inconsistent: kind='loop' requires loop_release; kind='bee' requires bee_release (spec §7A.2)",
241
- path: [],
241
+ if (m.kind === "bee" && m.bee_release === undefined) {
242
+ ctx.addIssue({
243
+ code: 'custom',
244
+ path: [],
245
+ message: "bundle manifest is inconsistent: kind='loop' requires loop_release; kind='bee' requires bee_release (spec §7A.2)",
246
+ });
247
+ }
242
248
  });
243
249
  /* ---------------------------------------------------------------------- */
244
250
  /* Validation helpers */
@@ -60,37 +60,20 @@ export type RunStateStatus = (typeof RUN_STATE_STATUSES)[number];
60
60
  * schema-version bump, not a quiet extension.
61
61
  */
62
62
  export declare const RunStateContractSchema: z.ZodObject<{
63
- /** Stable bee id (kebab-case). */
64
63
  bee_id: z.ZodString;
65
- /** Current run status (running / paused / done / failed / blocked). */
66
- status: z.ZodEnum<["running", "paused", "done", "failed", "blocked"]>;
67
- /** Current step name; NL short label. */
64
+ status: z.ZodEnum<{
65
+ blocked: "blocked";
66
+ failed: "failed";
67
+ running: "running";
68
+ done: "done";
69
+ paused: "paused";
70
+ }>;
68
71
  current_step: z.ZodString;
69
- /** ISO8601 timestamp the run started. */
70
72
  started_at: z.ZodString;
71
- /** ISO8601 timestamp of the latest update. */
72
73
  updated_at: z.ZodString;
73
- /** NL summary of the latest evaluator verdict (or null when none). */
74
74
  last_evaluator_verdict: z.ZodNullable<z.ZodString>;
75
- /** NL summary of the latest user choice (or null when none). */
76
75
  last_user_choice: z.ZodNullable<z.ZodString>;
77
- }, "strict", z.ZodTypeAny, {
78
- status: "blocked" | "failed" | "running" | "done" | "paused";
79
- bee_id: string;
80
- current_step: string;
81
- started_at: string;
82
- updated_at: string;
83
- last_evaluator_verdict: string | null;
84
- last_user_choice: string | null;
85
- }, {
86
- status: "blocked" | "failed" | "running" | "done" | "paused";
87
- bee_id: string;
88
- current_step: string;
89
- started_at: string;
90
- updated_at: string;
91
- last_evaluator_verdict: string | null;
92
- last_user_choice: string | null;
93
- }>;
76
+ }, z.core.$strict>;
94
77
  export type RunStateContract = z.infer<typeof RunStateContractSchema>;
95
78
  /**
96
79
  * Strict-parse an unknown value as a RunStateContract. Throws
@@ -24,60 +24,40 @@
24
24
  */
25
25
  import { z } from 'zod';
26
26
  import { skillsDir } from 'peaks-loop-shared/paths';
27
- export declare const SkillSearchInputSchema: z.ZodEffects<z.ZodObject<{
27
+ export declare const SkillSearchInputSchema: z.ZodObject<{
28
28
  query: z.ZodOptional<z.ZodString>;
29
29
  tag: z.ZodOptional<z.ZodString>;
30
- domain: z.ZodOptional<z.ZodEnum<["code", "content", "doctor", "research", "triage", "sop", "audit", "final-review", "resume", "status", "test", "ide", "slice-decompose", "issue-fix-orchestrator", "perf-audit", "security-audit", "reviewer"]>>;
31
- limit: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
32
- includeInternal: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
33
- }, "strip", z.ZodTypeAny, {
34
- limit: number;
35
- includeInternal: boolean;
36
- query?: string | undefined;
37
- tag?: string | undefined;
38
- domain?: "code" | "status" | "resume" | "audit" | "content" | "test" | "ide" | "research" | "doctor" | "triage" | "sop" | "final-review" | "slice-decompose" | "issue-fix-orchestrator" | "perf-audit" | "security-audit" | "reviewer" | undefined;
39
- }, {
40
- query?: string | undefined;
41
- limit?: number | undefined;
42
- tag?: string | undefined;
43
- domain?: "code" | "status" | "resume" | "audit" | "content" | "test" | "ide" | "research" | "doctor" | "triage" | "sop" | "final-review" | "slice-decompose" | "issue-fix-orchestrator" | "perf-audit" | "security-audit" | "reviewer" | undefined;
44
- includeInternal?: boolean | undefined;
45
- }>, {
46
- limit: number;
47
- includeInternal: boolean;
48
- query?: string | undefined;
49
- tag?: string | undefined;
50
- domain?: "code" | "status" | "resume" | "audit" | "content" | "test" | "ide" | "research" | "doctor" | "triage" | "sop" | "final-review" | "slice-decompose" | "issue-fix-orchestrator" | "perf-audit" | "security-audit" | "reviewer" | undefined;
51
- }, {
52
- query?: string | undefined;
53
- limit?: number | undefined;
54
- tag?: string | undefined;
55
- domain?: "code" | "status" | "resume" | "audit" | "content" | "test" | "ide" | "research" | "doctor" | "triage" | "sop" | "final-review" | "slice-decompose" | "issue-fix-orchestrator" | "perf-audit" | "security-audit" | "reviewer" | undefined;
56
- includeInternal?: boolean | undefined;
57
- }>;
30
+ domain: z.ZodOptional<z.ZodEnum<{
31
+ code: "code";
32
+ status: "status";
33
+ resume: "resume";
34
+ audit: "audit";
35
+ content: "content";
36
+ test: "test";
37
+ ide: "ide";
38
+ research: "research";
39
+ doctor: "doctor";
40
+ triage: "triage";
41
+ sop: "sop";
42
+ "final-review": "final-review";
43
+ "slice-decompose": "slice-decompose";
44
+ "issue-fix-orchestrator": "issue-fix-orchestrator";
45
+ "perf-audit": "perf-audit";
46
+ "security-audit": "security-audit";
47
+ reviewer: "reviewer";
48
+ }>>;
49
+ limit: z.ZodOptional<z.ZodDefault<z.ZodNumber>>;
50
+ includeInternal: z.ZodOptional<z.ZodDefault<z.ZodBoolean>>;
51
+ }, z.core.$strip>;
58
52
  export type SkillSearchInput = z.input<typeof SkillSearchInputSchema>;
59
53
  export declare const SkillSearchResultSchema: z.ZodObject<{
60
54
  name: z.ZodString;
61
55
  description: z.ZodString;
62
- triggers: z.ZodArray<z.ZodString, "many">;
63
- tags: z.ZodArray<z.ZodString, "many">;
56
+ triggers: z.ZodArray<z.ZodString>;
57
+ tags: z.ZodArray<z.ZodString>;
64
58
  domain: z.ZodString;
65
59
  matchScore: z.ZodNumber;
66
- }, "strip", z.ZodTypeAny, {
67
- name: string;
68
- description: string;
69
- domain: string;
70
- triggers: string[];
71
- tags: string[];
72
- matchScore: number;
73
- }, {
74
- name: string;
75
- description: string;
76
- domain: string;
77
- triggers: string[];
78
- tags: string[];
79
- matchScore: number;
80
- }>;
60
+ }, z.core.$strip>;
81
61
  export type SkillSearchResult = z.infer<typeof SkillSearchResultSchema>;
82
62
  /**
83
63
  * Search the in-tree skill pool. Validates `input` against
@@ -51,8 +51,8 @@ export const SkillSearchInputSchema = z
51
51
  query: z.string().min(1).max(500).optional(),
52
52
  tag: z.string().min(1).max(100).optional(),
53
53
  domain: z.enum(SKILL_DOMAINS).optional(),
54
- limit: z.number().int().min(1).max(100).optional().default(20),
55
- includeInternal: z.boolean().optional().default(false)
54
+ limit: z.number().int().min(1).max(100).default(20).optional(),
55
+ includeInternal: z.boolean().default(false).optional()
56
56
  })
57
57
  .refine((v) => v.query !== undefined || v.tag !== undefined || v.domain !== undefined, { message: 'At least one of --query / --tag / --domain is required' });
58
58
  export const SkillSearchResultSchema = z.object({
@@ -173,6 +173,15 @@ export declare const HOOK_CODE_GATE_COMMAND = "peaks code-gate --json";
173
173
  * is also the inverse for uninstall: `removeHookInstall` rebuilds the deny
174
174
  * list by filtering out anything whose wrapped form matches one of these
175
175
  * ids.
176
+ *
177
+ * Slice rid-skill-persistence-001 (2026-08-12): four additional skills
178
+ * denied so the superpowers chain cannot silently override peaks-code.
179
+ * All four are referenced by `superpowers:using-superpowers` as the
180
+ * "bug → systematic-debugging / TDD / verification-before-completion /
181
+ * recursion via using-superpowers" auto-routing pattern — denying the
182
+ * trigger removes the auto-routing surface while leaving all four
183
+ * still readable as reference material from
184
+ * `references/external-skill-invocation.md`.
176
185
  */
177
186
  export declare const SUPERPOWERS_DENIED_SKILLS: ReadonlyArray<string>;
178
187
  /**
@@ -298,13 +298,43 @@ function resolveLegacySentinels(ide) {
298
298
  * is also the inverse for uninstall: `removeHookInstall` rebuilds the deny
299
299
  * list by filtering out anything whose wrapped form matches one of these
300
300
  * ids.
301
+ *
302
+ * Slice rid-skill-persistence-001 (2026-08-12): four additional skills
303
+ * denied so the superpowers chain cannot silently override peaks-code.
304
+ * All four are referenced by `superpowers:using-superpowers` as the
305
+ * "bug → systematic-debugging / TDD / verification-before-completion /
306
+ * recursion via using-superpowers" auto-routing pattern — denying the
307
+ * trigger removes the auto-routing surface while leaving all four
308
+ * still readable as reference material from
309
+ * `references/external-skill-invocation.md`.
301
310
  */
302
311
  export const SUPERPOWERS_DENIED_SKILLS = [
303
312
  // superpowers:using-git-worktrees is the chain's "ground zero" — its
304
313
  // SKILL.md (lines 47-99) literally instructs the LLM to run
305
314
  // `git worktree add`. Denying this Skill at the IDE layer prevents the
306
315
  // LLM from ever receiving that prompt.
307
- 'superpowers:using-git-worktrees'
316
+ 'superpowers:using-git-worktrees',
317
+ // Slice rid-skill-persistence-001: deny the "bug → systematic-debugging"
318
+ // auto-route. Without this entry the chain can preempt the current bee
319
+ // any time a bug report surfaces. Reference-only via
320
+ // references/external-skill-invocation.md §systematic-debugging.
321
+ 'superpowers:systematic-debugging',
322
+ // Slice rid-skill-persistence-001: deny the TDD trigger that the chain
323
+ // pairs with bug reports (write-a-failing-test-first). Reference-only
324
+ // via references/external-skill-invocation.md §test-driven-development.
325
+ 'superpowers:test-driven-development',
326
+ // Slice rid-skill-persistence-001: deny the verification-before-
327
+ // completion trigger that the chain uses to override "declare done"
328
+ // claims from peaks-code. Reference-only via
329
+ // references/external-skill-invocation.md §verification-before-completion.
330
+ 'superpowers:verification-before-completion',
331
+ // Slice rid-skill-persistence-001: deny the recursive chain entrypoint
332
+ // itself. Without this entry the chain auto-spawns another
333
+ // "using-superpowers" Skill call right after the previous chain step,
334
+ // creating the recursive override pattern that peaks-loop's L1 guard
335
+ // cannot see through. Reference-only via
336
+ // references/external-skill-invocation.md §using-superpowers.
337
+ 'superpowers:using-superpowers'
308
338
  ];
309
339
  function formatSuperpowersDenyEntry(skillId) {
310
340
  return `UseSkill(${skillId})`;
@@ -132,7 +132,31 @@ export declare function checkStalePresence(opts?: {
132
132
  * clearing it prevents peaks-code Step 1 from picking up a stale
133
133
  * `mode` field that the user never explicitly chose.
134
134
  *
135
+ * Slice rid-skill-persistence-001 (2026-08-12): added an outerSessionId
136
+ * intent-source guard at the top of the function. The user constraint
137
+ * (preserved in `.peaks/memory/2026-08-11-peaks-code-skill-persistence-pause.md`)
138
+ * requires that "the current bee (peaks-code) can only be replaced or
139
+ * cleared when the user explicitly asks, or when the user invokes
140
+ * another non-bee Peaks skill; superpowers auto-hits, plain bug
141
+ * reports, compact, and outer-session rotations must NOT change the
142
+ * bee." Per the constraint, the `currentOuterSessionId` argument
143
+ * doubles as the caller-binding intent source: when the harness env
144
+ * var is set (`PEAKS_OUTER_SESSION_ID` or `CLAUDE_CODE_SESSION_ID`),
145
+ * the call was user-explicit and the existing 3-branch logic is
146
+ * authoritative; when the env var is absent (currentOuterSessionId
147
+ * is `undefined`), the rotation is system-triggered and MUST NOT
148
+ * mutate user-explicit presence state.
149
+ *
150
+ * The guard is the minimal surface that satisfies the user constraint
151
+ * while preserving the existing reconnect + live-different-outer +
152
+ * stale-clear behavior for the user-explicit path. No new arguments,
153
+ * no signature change — the 2 existing call sites
154
+ * (`init-command.ts:329-334`, `primer-command.ts:128-133`) keep
155
+ * working unchanged.
156
+ *
135
157
  * Only clears when:
158
+ * - the caller supplies a user-explicit intent source
159
+ * (`currentOuterSessionId !== undefined`), AND
136
160
  * - the recorded outer session id does NOT match the current outer
137
161
  * session id (i.e. the presence IS stale), AND
138
162
  * - the recorded outer session id matches the just-rotated-out
@@ -439,7 +439,31 @@ export function checkStalePresence(opts) {
439
439
  * clearing it prevents peaks-code Step 1 from picking up a stale
440
440
  * `mode` field that the user never explicitly chose.
441
441
  *
442
+ * Slice rid-skill-persistence-001 (2026-08-12): added an outerSessionId
443
+ * intent-source guard at the top of the function. The user constraint
444
+ * (preserved in `.peaks/memory/2026-08-11-peaks-code-skill-persistence-pause.md`)
445
+ * requires that "the current bee (peaks-code) can only be replaced or
446
+ * cleared when the user explicitly asks, or when the user invokes
447
+ * another non-bee Peaks skill; superpowers auto-hits, plain bug
448
+ * reports, compact, and outer-session rotations must NOT change the
449
+ * bee." Per the constraint, the `currentOuterSessionId` argument
450
+ * doubles as the caller-binding intent source: when the harness env
451
+ * var is set (`PEAKS_OUTER_SESSION_ID` or `CLAUDE_CODE_SESSION_ID`),
452
+ * the call was user-explicit and the existing 3-branch logic is
453
+ * authoritative; when the env var is absent (currentOuterSessionId
454
+ * is `undefined`), the rotation is system-triggered and MUST NOT
455
+ * mutate user-explicit presence state.
456
+ *
457
+ * The guard is the minimal surface that satisfies the user constraint
458
+ * while preserving the existing reconnect + live-different-outer +
459
+ * stale-clear behavior for the user-explicit path. No new arguments,
460
+ * no signature change — the 2 existing call sites
461
+ * (`init-command.ts:329-334`, `primer-command.ts:128-133`) keep
462
+ * working unchanged.
463
+ *
442
464
  * Only clears when:
465
+ * - the caller supplies a user-explicit intent source
466
+ * (`currentOuterSessionId !== undefined`), AND
443
467
  * - the recorded outer session id does NOT match the current outer
444
468
  * session id (i.e. the presence IS stale), AND
445
469
  * - the recorded outer session id matches the just-rotated-out
@@ -452,6 +476,15 @@ export function checkStalePresence(opts) {
452
476
  * decide what the "rotated-out" id was.
453
477
  */
454
478
  export function clearStalePresenceOnRotation(opts) {
479
+ // Slice rid-skill-persistence-001 (2026-08-12): user-explicit intent
480
+ // guard. When the caller has no caller-binding outerSessionId
481
+ // (env vars unset, system-triggered rotation), refuse the mutation
482
+ // up-front — the recorded presence may belong to a user-explicit
483
+ // invocation and auto-clear would silently destroy user intent.
484
+ // See `.peaks/memory/2026-08-11-peaks-code-skill-persistence-pause.md`.
485
+ if (opts.currentOuterSessionId === undefined) {
486
+ return { cleared: false, reason: 'no-intent-source' };
487
+ }
455
488
  const result = readSkillPresenceFromLease(opts.projectRootOverride);
456
489
  if (result === null) {
457
490
  return { cleared: false, reason: 'no-presence' };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "peaks-loop",
3
- "version": "4.0.21",
3
+ "version": "4.0.24",
4
4
  "description": "Loop Engineering CLI — workflow primitive / loop guards / evaluators / slice orchestration",
5
5
  "author": "SquabbyZ",
6
6
  "keywords": [
@@ -95,16 +95,17 @@
95
95
  "dependencies": {
96
96
  "@alibaba-group/open-code-review": "^1.8.9",
97
97
  "@colbymchenry/codegraph": "0.7.10",
98
+ "@upstash/context7-mcp": "^4.0.2",
98
99
  "better-sqlite3": "^12.11.1",
99
100
  "commander": "^12.1.0",
100
101
  "fzf": "^0.5.2",
101
102
  "headroom-ai": "0.22.4",
102
103
  "yaml": "^2.9.0",
103
- "zod": "^3.25.76",
104
- "peaks-loop-internal-runtime": "0.0.6",
105
- "peaks-loop-mut": "0.1.23",
106
- "peaks-loop-shared": "0.0.55",
107
- "peaks-loop-shared-channel": "0.0.27"
104
+ "zod": "^4.4.3",
105
+ "peaks-loop-internal-runtime": "0.0.9",
106
+ "peaks-loop-mut": "0.1.22",
107
+ "peaks-loop-shared": "0.0.58",
108
+ "peaks-loop-shared-channel": "0.0.26"
108
109
  },
109
110
  "devDependencies": {
110
111
  "@changesets/cli": "2.31.1",
@@ -123,8 +124,7 @@
123
124
  "tsx": "^4.19.2",
124
125
  "typescript": "^5.7.2",
125
126
  "vite": "^6.0.0",
126
- "vitest": "^4.1.10",
127
- "zod-to-json-schema": "^3.25.2"
127
+ "vitest": "^4.1.10"
128
128
  },
129
129
  "scripts": {
130
130
  "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 && node ./scripts/check-build-integrity.mjs",