peaks-loop 4.0.8 → 4.0.10

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 (93) hide show
  1. package/CHANGELOG.md +38 -0
  2. package/dist/cli/commands/_register.js +2 -0
  3. package/dist/cli/commands/baseline-commands.d.ts +3 -0
  4. package/dist/cli/commands/baseline-commands.js +146 -0
  5. package/dist/cli/commands/container-commands.js +2 -1
  6. package/dist/cli/commands/core/skill-command.js +32 -5
  7. package/dist/cli/commands/openspec-commands.js +2 -1
  8. package/dist/cli/commands/statusline-commands.js +1 -1
  9. package/dist/services/audit/enforcers/active-skill-resolver.d.ts +11 -0
  10. package/dist/services/audit/enforcers/active-skill-resolver.js +50 -39
  11. package/dist/services/capability-audit-service/cross-check.d.ts +8 -0
  12. package/dist/services/capability-audit-service/cross-check.js +11 -0
  13. package/dist/services/capability-audit-service/index.d.ts +3 -0
  14. package/dist/services/capability-audit-service/index.js +2 -0
  15. package/dist/services/capability-audit-service/runner.d.ts +27 -0
  16. package/dist/services/capability-audit-service/runner.js +40 -0
  17. package/dist/services/capability-audit-service/staleness.d.ts +1 -0
  18. package/dist/services/capability-audit-service/staleness.js +7 -0
  19. package/dist/services/capability-audit-service/types.d.ts +24 -0
  20. package/dist/services/capability-audit-service/types.js +1 -0
  21. package/dist/services/capability-baseline/store.d.ts +33 -0
  22. package/dist/services/capability-baseline/store.js +80 -0
  23. package/dist/services/capability-baseline/types.d.ts +45 -0
  24. package/dist/services/capability-baseline/types.js +5 -0
  25. package/dist/services/capability-baseline/validator.d.ts +19 -0
  26. package/dist/services/capability-baseline/validator.js +38 -0
  27. package/dist/services/capability-guard-runner/contracts/J01.d.ts +2 -0
  28. package/dist/services/capability-guard-runner/contracts/J01.js +48 -0
  29. package/dist/services/capability-guard-runner/contracts/J02.d.ts +2 -0
  30. package/dist/services/capability-guard-runner/contracts/J02.js +34 -0
  31. package/dist/services/capability-guard-runner/contracts/J03.d.ts +2 -0
  32. package/dist/services/capability-guard-runner/contracts/J03.js +24 -0
  33. package/dist/services/capability-guard-runner/contracts/J04.d.ts +2 -0
  34. package/dist/services/capability-guard-runner/contracts/J04.js +40 -0
  35. package/dist/services/capability-guard-runner/contracts/J05.d.ts +2 -0
  36. package/dist/services/capability-guard-runner/contracts/J05.js +21 -0
  37. package/dist/services/capability-guard-runner/contracts/J06.d.ts +2 -0
  38. package/dist/services/capability-guard-runner/contracts/J06.js +43 -0
  39. package/dist/services/capability-guard-runner/contracts/J07.d.ts +2 -0
  40. package/dist/services/capability-guard-runner/contracts/J07.js +53 -0
  41. package/dist/services/capability-guard-runner/contracts/J08.d.ts +2 -0
  42. package/dist/services/capability-guard-runner/contracts/J08.js +43 -0
  43. package/dist/services/capability-guard-runner/contracts/J09.d.ts +2 -0
  44. package/dist/services/capability-guard-runner/contracts/J09.js +44 -0
  45. package/dist/services/capability-guard-runner/contracts/J10.d.ts +2 -0
  46. package/dist/services/capability-guard-runner/contracts/J10.js +40 -0
  47. package/dist/services/capability-guard-runner/contracts/J11.d.ts +2 -0
  48. package/dist/services/capability-guard-runner/contracts/J11.js +39 -0
  49. package/dist/services/capability-guard-runner/contracts/J12.d.ts +2 -0
  50. package/dist/services/capability-guard-runner/contracts/J12.js +34 -0
  51. package/dist/services/capability-guard-runner/contracts/J13.d.ts +2 -0
  52. package/dist/services/capability-guard-runner/contracts/J13.js +45 -0
  53. package/dist/services/capability-guard-runner/contracts/J14.d.ts +2 -0
  54. package/dist/services/capability-guard-runner/contracts/J14.js +36 -0
  55. package/dist/services/capability-guard-runner/contracts/J15.d.ts +2 -0
  56. package/dist/services/capability-guard-runner/contracts/J15.js +40 -0
  57. package/dist/services/capability-guard-runner/diff.d.ts +2 -0
  58. package/dist/services/capability-guard-runner/diff.js +7 -0
  59. package/dist/services/capability-guard-runner/runner.d.ts +9 -0
  60. package/dist/services/capability-guard-runner/runner.js +22 -0
  61. package/dist/services/capability-guard-runner/types.d.ts +39 -0
  62. package/dist/services/capability-guard-runner/types.js +1 -0
  63. package/dist/services/container/container-lease.js +2 -1
  64. package/dist/services/evolution/evolution-types.d.ts +16 -16
  65. package/dist/services/final-review/final-review-service.d.ts +8 -0
  66. package/dist/services/final-review/final-review-service.js +14 -0
  67. package/dist/services/final-review/final-review-types.d.ts +1 -1
  68. package/dist/services/impact/impact-scan-service.js +4 -3
  69. package/dist/services/job/job-progress-store.d.ts +2 -2
  70. package/dist/services/job/job-types.d.ts +26 -26
  71. package/dist/services/migrate-skill-name/migrate.js +2 -1
  72. package/dist/services/observability/observability-service.d.ts +2 -2
  73. package/dist/services/openspec/artifact-boundary.js +3 -2
  74. package/dist/services/openspec/coverage-evidence-reader.js +9 -8
  75. package/dist/services/prd/handoff-auto-regen.js +2 -1
  76. package/dist/services/scan/type-sanity-service.js +2 -1
  77. package/dist/services/sediment/json-schema.d.ts +4 -4
  78. package/dist/services/session/session-binding-bridge.js +17 -19
  79. package/dist/services/session/session-manager.js +36 -12
  80. package/dist/services/session/session-resume-service.d.ts +4 -0
  81. package/dist/services/session/session-resume-service.js +4 -0
  82. package/dist/services/skills/skill-statusline-renderer.d.ts +46 -56
  83. package/dist/services/skills/skill-statusline-renderer.js +335 -126
  84. package/dist/services/skills/skill-statusline-service.d.ts +6 -0
  85. package/dist/services/skills/skill-statusline-service.js +105 -7
  86. package/dist/services/vm/vm-lease.js +2 -1
  87. package/dist/services/workflow/workflow-autonomous-resume-helpers.js +3 -2
  88. package/dist/services/workspace/workspace-service.js +2 -1
  89. package/dist/services/worktree/worktree-lease.js +2 -1
  90. package/dist/shared/path-safety.js +3 -5
  91. package/dist/shared/path-utils.d.ts +48 -0
  92. package/dist/shared/path-utils.js +65 -1
  93. package/package.json +5 -4
@@ -13,6 +13,7 @@
13
13
  * command; `peaks impact must-check` returns the must-check list
14
14
  * subset. Persistence is per-invocation (no state file).
15
15
  */
16
+ import { normalizePath } from '../../shared/path-utils.js';
16
17
  /**
17
18
  * Default business flow map (covers the most common B-end
18
19
  * archetypes; users can override via --flows in the CLI).
@@ -34,7 +35,7 @@ export const DEFAULT_BUSINESS_FLOWS = new Map([
34
35
  * (the file itself, the parent dir, the project-wide pattern).
35
36
  */
36
37
  function pathToGlobs(path) {
37
- const normalized = path.replace(/\\/g, '/');
38
+ const normalized = normalizePath(path);
38
39
  const parts = normalized.split('/');
39
40
  // Drop the filename → get the parent pattern: "src/foo/" → "src/**"
40
41
  const parent = parts.length > 1 ? parts.slice(0, -1).join('/') + '/**' : '**';
@@ -42,7 +43,7 @@ function pathToGlobs(path) {
42
43
  }
43
44
  /** Simple glob matcher supporting `**` and `*`. */
44
45
  export function matchGlob(pattern, path) {
45
- const normalizedPath = path.replace(/\\/g, '/');
46
+ const normalizedPath = normalizePath(path);
46
47
  // Build regex by splitting on glob tokens, escaping the rest.
47
48
  // Order: ** (doublestar) → .* ; * → [^/]* ; other → escape
48
49
  let regexStr = '';
@@ -108,7 +109,7 @@ export function runImpactScan(opts) {
108
109
  // Predict other files that may be affected (siblings of changed files).
109
110
  const impactedFiles = [];
110
111
  for (const f of changed) {
111
- const parts = f.replace(/\\/g, '/').split('/');
112
+ const parts = normalizePath(f).split('/');
112
113
  if (parts.length <= 1)
113
114
  continue;
114
115
  const parent = parts.slice(0, -1).join('/');
@@ -31,16 +31,16 @@ export declare const JobProgressSchema: z.ZodObject<{
31
31
  updatedAt: z.ZodString;
32
32
  }, "strip", z.ZodTypeAny, {
33
33
  updatedAt: string;
34
- done: number;
35
34
  schemaVersion: 1;
35
+ done: number;
36
36
  jobId: string;
37
37
  total: number;
38
38
  currentSlice: string;
39
39
  lastCommitSha: string | null;
40
40
  }, {
41
41
  updatedAt: string;
42
- done: number;
43
42
  schemaVersion: 1;
43
+ done: number;
44
44
  jobId: string;
45
45
  total: number;
46
46
  currentSlice: string;
@@ -9,7 +9,7 @@ export declare const SliceStateSchema: z.ZodEffects<z.ZodEffects<z.ZodEffects<z.
9
9
  repairCycles: z.ZodDefault<z.ZodNumber>;
10
10
  blockedReason: z.ZodOptional<z.ZodString>;
11
11
  }, "strip", z.ZodTypeAny, {
12
- status: "pending" | "blocked" | "failed" | "done" | "skipped" | "in-progress";
12
+ status: "pending" | "blocked" | "failed" | "skipped" | "done" | "in-progress";
13
13
  label: string;
14
14
  sliceId: string;
15
15
  repairCycles: number;
@@ -18,7 +18,7 @@ export declare const SliceStateSchema: z.ZodEffects<z.ZodEffects<z.ZodEffects<z.
18
18
  failureReason?: string | undefined;
19
19
  blockedReason?: string | undefined;
20
20
  }, {
21
- status: "pending" | "blocked" | "failed" | "done" | "skipped" | "in-progress";
21
+ status: "pending" | "blocked" | "failed" | "skipped" | "done" | "in-progress";
22
22
  label: string;
23
23
  sliceId: string;
24
24
  commitSha?: string | undefined;
@@ -27,7 +27,7 @@ export declare const SliceStateSchema: z.ZodEffects<z.ZodEffects<z.ZodEffects<z.
27
27
  repairCycles?: number | undefined;
28
28
  blockedReason?: string | undefined;
29
29
  }>, {
30
- status: "pending" | "blocked" | "failed" | "done" | "skipped" | "in-progress";
30
+ status: "pending" | "blocked" | "failed" | "skipped" | "done" | "in-progress";
31
31
  label: string;
32
32
  sliceId: string;
33
33
  repairCycles: number;
@@ -36,7 +36,7 @@ export declare const SliceStateSchema: z.ZodEffects<z.ZodEffects<z.ZodEffects<z.
36
36
  failureReason?: string | undefined;
37
37
  blockedReason?: string | undefined;
38
38
  }, {
39
- status: "pending" | "blocked" | "failed" | "done" | "skipped" | "in-progress";
39
+ status: "pending" | "blocked" | "failed" | "skipped" | "done" | "in-progress";
40
40
  label: string;
41
41
  sliceId: string;
42
42
  commitSha?: string | undefined;
@@ -45,7 +45,7 @@ export declare const SliceStateSchema: z.ZodEffects<z.ZodEffects<z.ZodEffects<z.
45
45
  repairCycles?: number | undefined;
46
46
  blockedReason?: string | undefined;
47
47
  }>, {
48
- status: "pending" | "blocked" | "failed" | "done" | "skipped" | "in-progress";
48
+ status: "pending" | "blocked" | "failed" | "skipped" | "done" | "in-progress";
49
49
  label: string;
50
50
  sliceId: string;
51
51
  repairCycles: number;
@@ -54,7 +54,7 @@ export declare const SliceStateSchema: z.ZodEffects<z.ZodEffects<z.ZodEffects<z.
54
54
  failureReason?: string | undefined;
55
55
  blockedReason?: string | undefined;
56
56
  }, {
57
- status: "pending" | "blocked" | "failed" | "done" | "skipped" | "in-progress";
57
+ status: "pending" | "blocked" | "failed" | "skipped" | "done" | "in-progress";
58
58
  label: string;
59
59
  sliceId: string;
60
60
  commitSha?: string | undefined;
@@ -63,7 +63,7 @@ export declare const SliceStateSchema: z.ZodEffects<z.ZodEffects<z.ZodEffects<z.
63
63
  repairCycles?: number | undefined;
64
64
  blockedReason?: string | undefined;
65
65
  }>, {
66
- status: "pending" | "blocked" | "failed" | "done" | "skipped" | "in-progress";
66
+ status: "pending" | "blocked" | "failed" | "skipped" | "done" | "in-progress";
67
67
  label: string;
68
68
  sliceId: string;
69
69
  repairCycles: number;
@@ -72,7 +72,7 @@ export declare const SliceStateSchema: z.ZodEffects<z.ZodEffects<z.ZodEffects<z.
72
72
  failureReason?: string | undefined;
73
73
  blockedReason?: string | undefined;
74
74
  }, {
75
- status: "pending" | "blocked" | "failed" | "done" | "skipped" | "in-progress";
75
+ status: "pending" | "blocked" | "failed" | "skipped" | "done" | "in-progress";
76
76
  label: string;
77
77
  sliceId: string;
78
78
  commitSha?: string | undefined;
@@ -117,7 +117,7 @@ export declare const JobStateSchema: z.ZodObject<{
117
117
  repairCycles: z.ZodDefault<z.ZodNumber>;
118
118
  blockedReason: z.ZodOptional<z.ZodString>;
119
119
  }, "strip", z.ZodTypeAny, {
120
- status: "pending" | "blocked" | "failed" | "done" | "skipped" | "in-progress";
120
+ status: "pending" | "blocked" | "failed" | "skipped" | "done" | "in-progress";
121
121
  label: string;
122
122
  sliceId: string;
123
123
  repairCycles: number;
@@ -126,7 +126,7 @@ export declare const JobStateSchema: z.ZodObject<{
126
126
  failureReason?: string | undefined;
127
127
  blockedReason?: string | undefined;
128
128
  }, {
129
- status: "pending" | "blocked" | "failed" | "done" | "skipped" | "in-progress";
129
+ status: "pending" | "blocked" | "failed" | "skipped" | "done" | "in-progress";
130
130
  label: string;
131
131
  sliceId: string;
132
132
  commitSha?: string | undefined;
@@ -135,7 +135,7 @@ export declare const JobStateSchema: z.ZodObject<{
135
135
  repairCycles?: number | undefined;
136
136
  blockedReason?: string | undefined;
137
137
  }>, {
138
- status: "pending" | "blocked" | "failed" | "done" | "skipped" | "in-progress";
138
+ status: "pending" | "blocked" | "failed" | "skipped" | "done" | "in-progress";
139
139
  label: string;
140
140
  sliceId: string;
141
141
  repairCycles: number;
@@ -144,7 +144,7 @@ export declare const JobStateSchema: z.ZodObject<{
144
144
  failureReason?: string | undefined;
145
145
  blockedReason?: string | undefined;
146
146
  }, {
147
- status: "pending" | "blocked" | "failed" | "done" | "skipped" | "in-progress";
147
+ status: "pending" | "blocked" | "failed" | "skipped" | "done" | "in-progress";
148
148
  label: string;
149
149
  sliceId: string;
150
150
  commitSha?: string | undefined;
@@ -153,7 +153,7 @@ export declare const JobStateSchema: z.ZodObject<{
153
153
  repairCycles?: number | undefined;
154
154
  blockedReason?: string | undefined;
155
155
  }>, {
156
- status: "pending" | "blocked" | "failed" | "done" | "skipped" | "in-progress";
156
+ status: "pending" | "blocked" | "failed" | "skipped" | "done" | "in-progress";
157
157
  label: string;
158
158
  sliceId: string;
159
159
  repairCycles: number;
@@ -162,7 +162,7 @@ export declare const JobStateSchema: z.ZodObject<{
162
162
  failureReason?: string | undefined;
163
163
  blockedReason?: string | undefined;
164
164
  }, {
165
- status: "pending" | "blocked" | "failed" | "done" | "skipped" | "in-progress";
165
+ status: "pending" | "blocked" | "failed" | "skipped" | "done" | "in-progress";
166
166
  label: string;
167
167
  sliceId: string;
168
168
  commitSha?: string | undefined;
@@ -171,7 +171,7 @@ export declare const JobStateSchema: z.ZodObject<{
171
171
  repairCycles?: number | undefined;
172
172
  blockedReason?: string | undefined;
173
173
  }>, {
174
- status: "pending" | "blocked" | "failed" | "done" | "skipped" | "in-progress";
174
+ status: "pending" | "blocked" | "failed" | "skipped" | "done" | "in-progress";
175
175
  label: string;
176
176
  sliceId: string;
177
177
  repairCycles: number;
@@ -180,7 +180,7 @@ export declare const JobStateSchema: z.ZodObject<{
180
180
  failureReason?: string | undefined;
181
181
  blockedReason?: string | undefined;
182
182
  }, {
183
- status: "pending" | "blocked" | "failed" | "done" | "skipped" | "in-progress";
183
+ status: "pending" | "blocked" | "failed" | "skipped" | "done" | "in-progress";
184
184
  label: string;
185
185
  sliceId: string;
186
186
  commitSha?: string | undefined;
@@ -200,7 +200,7 @@ export declare const JobStateSchema: z.ZodObject<{
200
200
  rotateEvery: number;
201
201
  mainSessionCycle: number;
202
202
  slices: {
203
- status: "pending" | "blocked" | "failed" | "done" | "skipped" | "in-progress";
203
+ status: "pending" | "blocked" | "failed" | "skipped" | "done" | "in-progress";
204
204
  label: string;
205
205
  sliceId: string;
206
206
  repairCycles: number;
@@ -221,7 +221,7 @@ export declare const JobStateSchema: z.ZodObject<{
221
221
  jobId: string;
222
222
  startedAt: string;
223
223
  slices: {
224
- status: "pending" | "blocked" | "failed" | "done" | "skipped" | "in-progress";
224
+ status: "pending" | "blocked" | "failed" | "skipped" | "done" | "in-progress";
225
225
  label: string;
226
226
  sliceId: string;
227
227
  commitSha?: string | undefined;
@@ -294,8 +294,8 @@ export declare const JobStatusSummarySchema: z.ZodObject<{
294
294
  }, "strip", z.ZodTypeAny, {
295
295
  blocked: number;
296
296
  failed: number;
297
- done: number;
298
297
  skipped: number;
298
+ done: number;
299
299
  total: number;
300
300
  mainLoopStrategy: "single" | "rotating";
301
301
  mainSessionCycle: number;
@@ -312,8 +312,8 @@ export declare const JobStatusSummarySchema: z.ZodObject<{
312
312
  }, {
313
313
  blocked: number;
314
314
  failed: number;
315
- done: number;
316
315
  skipped: number;
316
+ done: number;
317
317
  total: number;
318
318
  mainLoopStrategy: "single" | "rotating";
319
319
  mainSessionCycle: number;
@@ -374,7 +374,7 @@ export declare const JobCheckpointInputSchema: z.ZodEffects<z.ZodEffects<z.ZodOb
374
374
  json: z.ZodDefault<z.ZodBoolean>;
375
375
  }, "strip", z.ZodTypeAny, {
376
376
  project: string;
377
- state: "failed" | "done" | "skipped";
377
+ state: "failed" | "skipped" | "done";
378
378
  json: boolean;
379
379
  jobId: string;
380
380
  sliceId: string;
@@ -382,7 +382,7 @@ export declare const JobCheckpointInputSchema: z.ZodEffects<z.ZodEffects<z.ZodOb
382
382
  commitSha?: string | undefined;
383
383
  }, {
384
384
  project: string;
385
- state: "failed" | "done" | "skipped";
385
+ state: "failed" | "skipped" | "done";
386
386
  jobId: string;
387
387
  sliceId: string;
388
388
  reason?: string | undefined;
@@ -390,7 +390,7 @@ export declare const JobCheckpointInputSchema: z.ZodEffects<z.ZodEffects<z.ZodOb
390
390
  commitSha?: string | undefined;
391
391
  }>, {
392
392
  project: string;
393
- state: "failed" | "done" | "skipped";
393
+ state: "failed" | "skipped" | "done";
394
394
  json: boolean;
395
395
  jobId: string;
396
396
  sliceId: string;
@@ -398,7 +398,7 @@ export declare const JobCheckpointInputSchema: z.ZodEffects<z.ZodEffects<z.ZodOb
398
398
  commitSha?: string | undefined;
399
399
  }, {
400
400
  project: string;
401
- state: "failed" | "done" | "skipped";
401
+ state: "failed" | "skipped" | "done";
402
402
  jobId: string;
403
403
  sliceId: string;
404
404
  reason?: string | undefined;
@@ -406,7 +406,7 @@ export declare const JobCheckpointInputSchema: z.ZodEffects<z.ZodEffects<z.ZodOb
406
406
  commitSha?: string | undefined;
407
407
  }>, {
408
408
  project: string;
409
- state: "failed" | "done" | "skipped";
409
+ state: "failed" | "skipped" | "done";
410
410
  json: boolean;
411
411
  jobId: string;
412
412
  sliceId: string;
@@ -414,7 +414,7 @@ export declare const JobCheckpointInputSchema: z.ZodEffects<z.ZodEffects<z.ZodOb
414
414
  commitSha?: string | undefined;
415
415
  }, {
416
416
  project: string;
417
- state: "failed" | "done" | "skipped";
417
+ state: "failed" | "skipped" | "done";
418
418
  jobId: string;
419
419
  sliceId: string;
420
420
  reason?: string | undefined;
@@ -19,6 +19,7 @@
19
19
  */
20
20
  import { existsSync, readFileSync, readdirSync, statSync, writeFileSync } from 'node:fs';
21
21
  import { join, relative } from 'node:path';
22
+ import { normalizePath } from '../../shared/path-utils.js';
22
23
  /**
23
24
  * Skip-paths are matched against the path relative to `projectRoot`,
24
25
  * forward-slashed (Windows-friendly). Each entry is a SUBSTRING —
@@ -41,7 +42,7 @@ function escapeRe(input) {
41
42
  }
42
43
  /** True iff `absPath` falls under any skip-path (substring match). */
43
44
  export function shouldSkip(projectRoot, absPath) {
44
- const rel = relative(projectRoot, absPath).replace(/\\/g, '/');
45
+ const rel = normalizePath(relative(projectRoot, absPath));
45
46
  return SKIP_DIRS.some((skip) => rel.includes(skip));
46
47
  }
47
48
  /**
@@ -33,17 +33,17 @@ export declare const ObservabilityEventSchema: z.ZodObject<{
33
33
  role: z.ZodOptional<z.ZodEnum<["rd", "qa", "code-reviewer", "karpathy-reviewer", "peaks-security-audit", "peaks-perf-audit"]>>;
34
34
  detail: z.ZodRecord<z.ZodString, z.ZodUnknown>;
35
35
  }, "strip", z.ZodTypeAny, {
36
+ schemaVersion: 1;
36
37
  sessionId: string;
37
38
  detail: Record<string, unknown>;
38
- schemaVersion: 1;
39
39
  ts: string;
40
40
  category: "dispatch" | "slice-transition" | "checkpoint" | "mode-gate" | "context-trigger" | "post-compact" | "cycle" | "token-usage" | "monotonic-trigger" | "lease";
41
41
  role?: "qa" | "rd" | "code-reviewer" | "karpathy-reviewer" | "peaks-security-audit" | "peaks-perf-audit" | undefined;
42
42
  sliceRid?: string | undefined;
43
43
  }, {
44
+ schemaVersion: 1;
44
45
  sessionId: string;
45
46
  detail: Record<string, unknown>;
46
- schemaVersion: 1;
47
47
  ts: string;
48
48
  category: "dispatch" | "slice-transition" | "checkpoint" | "mode-gate" | "context-trigger" | "post-compact" | "cycle" | "token-usage" | "monotonic-trigger" | "lease";
49
49
  role?: "qa" | "rd" | "code-reviewer" | "karpathy-reviewer" | "peaks-security-audit" | "peaks-perf-audit" | undefined;
@@ -22,6 +22,7 @@
22
22
  */
23
23
  import { posix, relative, resolve, isAbsolute as nodeIsAbsolute } from 'node:path';
24
24
  import { isPathInsideArtifactRoot as _isPathInsideArtifactRoot } from '../../shared/path-safety.js';
25
+ import { normalizePath } from '../../shared/path-utils.js';
25
26
  export function ok(value) {
26
27
  return { ok: true, value };
27
28
  }
@@ -111,7 +112,7 @@ export function planArtifactPath(input) {
111
112
  // Always normalize separators to forward-slashes for the JSON-safe output,
112
113
  // then run posix.normalize so empty segments (foo//bar) and `..` segments
113
114
  // collapse to canonical form.
114
- const forwardSlashed = candidateRaw.replace(/\\/g, '/');
115
+ const forwardSlashed = normalizePath(candidateRaw);
115
116
  const normalized = posix.normalize(forwardSlashed);
116
117
  // Resolve against workspaceRoot. If the candidate is already absolute,
117
118
  // posix.normalize preserves the leading `/`; `resolve` keeps it absolute
@@ -129,7 +130,7 @@ export function planArtifactPath(input) {
129
130
  });
130
131
  }
131
132
  const relativePath = relative(workspaceRoot, absolutePath);
132
- const jsonSafeRelativePath = relativePath.replace(/\\/g, '/');
133
+ const jsonSafeRelativePath = normalizePath(relativePath);
133
134
  return ok({ absolutePath, relativePath, jsonSafeRelativePath });
134
135
  }
135
136
  const WORKSPACE_UNAVAILABLE_NEXT_ACTIONS = [
@@ -24,6 +24,7 @@ import { posix, relative, resolve } from 'node:path';
24
24
  import { readFile, stat } from 'node:fs/promises';
25
25
  import { isDirectory } from 'peaks-loop-shared/fs';
26
26
  import { ok, err } from './artifact-boundary.js';
27
+ import { normalizePath } from '../../shared/path-utils.js';
27
28
  // ---------------------------------------------------------------------------
28
29
  // Discovery
29
30
  // ---------------------------------------------------------------------------
@@ -63,7 +64,7 @@ export async function resolveCoverageSummaryPath(input) {
63
64
  return err({ code: 'missing', triedPaths });
64
65
  }
65
66
  function toPosix(p) {
66
- return p.replace(/\\/g, '/').replace(/\/$/, '');
67
+ return normalizePath(p).replace(/\/$/, '');
67
68
  }
68
69
  async function isReadable(p) {
69
70
  try {
@@ -112,7 +113,7 @@ export async function readC8Summary(path) {
112
113
  if (lines === null || statements === null || functions === null || branches === null) {
113
114
  continue;
114
115
  }
115
- const normalizedKey = posix.normalize(key.replace(/\\/g, '/'));
116
+ const normalizedKey = posix.normalize(normalizePath(key));
116
117
  files.set(normalizedKey, {
117
118
  path: normalizePathSep(normalizedKey),
118
119
  relativePath: normalizedKey,
@@ -141,7 +142,7 @@ function asMetric(input) {
141
142
  return { pct, covered, total };
142
143
  }
143
144
  function normalizePathSep(p) {
144
- return p.replace(/\\/g, '/');
145
+ return normalizePath(p);
145
146
  }
146
147
  // ---------------------------------------------------------------------------
147
148
  // Capability Mapping block parser (proposal.md)
@@ -215,7 +216,7 @@ function parseCapabilityRow(line) {
215
216
  return null;
216
217
  const row = {
217
218
  capability,
218
- source: source.replace(/\\/g, '/').replace(/^\.\//, '').replace(/\/$/, ''),
219
+ source: normalizePath(source).replace(/^\.\//, '').replace(/\/$/, ''),
219
220
  };
220
221
  if (testAnchor !== undefined && testAnchor !== '') {
221
222
  row.testAnchor = testAnchor;
@@ -236,7 +237,7 @@ function parseCapabilityRow(line) {
236
237
  export async function resolveCapabilityFiles(input) {
237
238
  const abs = resolve(input.projectRoot, input.row.source);
238
239
  if (!(await isDirectory(abs))) {
239
- const rel = relative(input.projectRoot, abs).replace(/\\/g, '/');
240
+ const rel = normalizePath(relative(input.projectRoot, abs));
240
241
  return [rel];
241
242
  }
242
243
  return await walkTsFiles(abs, input.projectRoot);
@@ -261,7 +262,7 @@ async function walkTsFiles(absRoot, projectRoot) {
261
262
  stack.push(full);
262
263
  }
263
264
  else if (entry.isFile() && entry.name.endsWith('.ts')) {
264
- const rel = relative(projectRoot, full).replace(/\\/g, '/');
265
+ const rel = normalizePath(relative(projectRoot, full));
265
266
  out.push(rel);
266
267
  }
267
268
  }
@@ -339,7 +340,7 @@ export async function validateCapabilityCoverage(input) {
339
340
  export async function findStaleChangeFiles(input) {
340
341
  const { stat: statFn } = await import('node:fs/promises');
341
342
  const summaryMtime = (await statFn(input.summary.path)).mtimeMs;
342
- const changeRoot = `${input.openspecRoot.replace(/\\/g, '/').replace(/\/$/, '')}/changes/${input.changeId}`;
343
+ const changeRoot = `${normalizePath(input.openspecRoot).replace(/\/$/, '')}/changes/${input.changeId}`;
343
344
  const candidates = [
344
345
  `${changeRoot}/proposal.md`,
345
346
  `${changeRoot}/tasks.md`,
@@ -375,7 +376,7 @@ export async function findStaleChangeFiles(input) {
375
376
  try {
376
377
  const m = (await statFn(candidate)).mtimeMs;
377
378
  if (m > summaryMtime) {
378
- stale.push(relative(input.projectRoot, candidate).replace(/\\/g, '/'));
379
+ stale.push(normalizePath(relative(input.projectRoot, candidate)));
379
380
  }
380
381
  }
381
382
  catch {
@@ -16,6 +16,7 @@ import { dirname, join } from 'node:path';
16
16
  import { createHash } from 'node:crypto';
17
17
  import { showRequestArtifact } from '../artifacts/request-artifact-service.js';
18
18
  import { sha256OfBody } from './handoff-service.js';
19
+ import { normalizePath } from '../../shared/path-utils.js';
19
20
  /**
20
21
  * Auto-regen the prd/handoff.md under `.peaks/_runtime/<sid>/prd/`.
21
22
  * Returns the outcome; never throws.
@@ -58,7 +59,7 @@ export async function autoRegenPrdHandoff(opts) {
58
59
  'goals: []',
59
60
  'acceptanceCriteria: []',
60
61
  'preservedBehavior: []',
61
- `handoffPath: ${handoffPath.replace(opts.projectRoot, '').replace(/\\/g, '/').replace(/^\//, '')}`,
62
+ `handoffPath: ${normalizePath(handoffPath.replace(opts.projectRoot, '')).replace(/^\//, '')}`,
62
63
  '---',
63
64
  ''
64
65
  ].join('\n');
@@ -1,5 +1,6 @@
1
1
  import { execFileSync } from 'node:child_process';
2
2
  import { extname, basename } from 'node:path';
3
+ import { normalizePath } from '../../shared/path-utils.js';
3
4
  const SOURCE_EXTENSIONS = new Set(['.ts', '.tsx', '.js', '.jsx', '.mjs', '.cjs', '.vue', '.svelte', '.py', '.go', '.rs', '.java', '.kt', '.swift', '.cpp', '.c', '.h', '.cs', '.rb', '.php', '.scala', '.dart', '.less', '.scss', '.sass', '.css']);
4
5
  const DOCS_EXTENSIONS = new Set(['.md', '.mdx', '.rst', '.txt']);
5
6
  const LOCKFILE_NAMES = new Set(['pnpm-lock.yaml', 'package-lock.json', 'yarn.lock', 'bun.lockb', 'Cargo.lock', 'Gemfile.lock', 'composer.lock', 'go.sum', 'poetry.lock']);
@@ -32,7 +33,7 @@ function classifyFile(filePath) {
32
33
  * wrote `.peaks/**` markdown would be misclassified as a docs change.
33
34
  */
34
35
  function isArtifactWorkspaceFile(filePath) {
35
- const normalized = filePath.replace(/\\/g, '/');
36
+ const normalized = normalizePath(filePath);
36
37
  return normalized === '.peaks' || normalized.startsWith('.peaks/');
37
38
  }
38
39
  function tryGitDiffFiles(projectRoot, baseRef) {
@@ -107,6 +107,7 @@ export declare const BeeManifestSchema: z.ZodEffects<z.ZodObject<{
107
107
  }, "strip", z.ZodTypeAny, {
108
108
  name: string;
109
109
  description: string;
110
+ schemaVersion: "peaks.bee/1";
110
111
  segments: {
111
112
  name: string;
112
113
  outputs: {
@@ -128,7 +129,6 @@ export declare const BeeManifestSchema: z.ZodEffects<z.ZodObject<{
128
129
  retireOnMissesInRow?: number | undefined;
129
130
  };
130
131
  source: "user" | "system";
131
- schemaVersion: "peaks.bee/1";
132
132
  promotion_status: "candidate" | "stable" | "retired" | "system-stable";
133
133
  entrypoint: {
134
134
  preamble: string;
@@ -142,6 +142,7 @@ export declare const BeeManifestSchema: z.ZodEffects<z.ZodObject<{
142
142
  }, {
143
143
  name: string;
144
144
  description: string;
145
+ schemaVersion: "peaks.bee/1";
145
146
  segments: {
146
147
  name: string;
147
148
  outputs: {
@@ -163,7 +164,6 @@ export declare const BeeManifestSchema: z.ZodEffects<z.ZodObject<{
163
164
  retireOnMissesInRow?: number | undefined;
164
165
  };
165
166
  source: "user" | "system";
166
- schemaVersion: "peaks.bee/1";
167
167
  promotion_status: "candidate" | "stable" | "retired" | "system-stable";
168
168
  entrypoint: {
169
169
  preamble: string;
@@ -177,6 +177,7 @@ export declare const BeeManifestSchema: z.ZodEffects<z.ZodObject<{
177
177
  }>, {
178
178
  name: string;
179
179
  description: string;
180
+ schemaVersion: "peaks.bee/1";
180
181
  segments: {
181
182
  name: string;
182
183
  outputs: {
@@ -198,7 +199,6 @@ export declare const BeeManifestSchema: z.ZodEffects<z.ZodObject<{
198
199
  retireOnMissesInRow?: number | undefined;
199
200
  };
200
201
  source: "user" | "system";
201
- schemaVersion: "peaks.bee/1";
202
202
  promotion_status: "candidate" | "stable" | "retired" | "system-stable";
203
203
  entrypoint: {
204
204
  preamble: string;
@@ -212,6 +212,7 @@ export declare const BeeManifestSchema: z.ZodEffects<z.ZodObject<{
212
212
  }, {
213
213
  name: string;
214
214
  description: string;
215
+ schemaVersion: "peaks.bee/1";
215
216
  segments: {
216
217
  name: string;
217
218
  outputs: {
@@ -233,7 +234,6 @@ export declare const BeeManifestSchema: z.ZodEffects<z.ZodObject<{
233
234
  retireOnMissesInRow?: number | undefined;
234
235
  };
235
236
  source: "user" | "system";
236
- schemaVersion: "peaks.bee/1";
237
237
  promotion_status: "candidate" | "stable" | "retired" | "system-stable";
238
238
  entrypoint: {
239
239
  preamble: string;
@@ -18,10 +18,11 @@
18
18
  * Body of every function moved verbatim per Karpathy #3 (Surgical
19
19
  * Changes). No behavior change. The bridge adds nothing of its own.
20
20
  */
21
- import { existsSync, mkdirSync, readFileSync, realpathSync, writeFileSync } from 'node:fs';
22
- import { dirname, join, resolve } from 'node:path';
21
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
22
+ import { dirname, join } from 'node:path';
23
23
  import { randomBytes } from 'node:crypto';
24
24
  import { initWorkspace } from '../workspace/workspace-service.js';
25
+ import { projectRootsMatch, stableRealPath } from '../../shared/path-utils.js';
25
26
  import { getSessionId, getSessionIdCanonical, getSessionMeta, rotateSessionBinding } from './session-manager.js';
26
27
  // --- Lower-level helpers the bridge needs (moved verbatim) ---
27
28
  const SESSION_FILE = join('_runtime', 'session.json');
@@ -30,18 +31,6 @@ const META_FILE = 'session.json';
30
31
  function getLegacySessionFilePath(projectRoot) {
31
32
  return join(projectRoot, '.peaks', LEGACY_SESSION_FILE);
32
33
  }
33
- function canonicalizeProjectRoot(p) {
34
- try {
35
- return realpathSync(p);
36
- }
37
- catch {
38
- return resolve(p);
39
- }
40
- }
41
- function resolveStoredAgainstCaller(stored, caller) {
42
- const resolved = resolve(caller, stored);
43
- return canonicalizeProjectRoot(resolved);
44
- }
45
34
  function generateSessionId() {
46
35
  const now = new Date();
47
36
  const year = now.getFullYear();
@@ -62,7 +51,9 @@ function readSessionFile(projectRoot) {
62
51
  return null;
63
52
  try {
64
53
  const data = JSON.parse(readFileSync(pathToRead, 'utf8'));
65
- if (data.sessionId && data.projectRoot === projectRoot) {
54
+ if (data.sessionId &&
55
+ typeof data.projectRoot === 'string' &&
56
+ projectRootsMatch(data.projectRoot, projectRoot)) {
66
57
  return data;
67
58
  }
68
59
  return null;
@@ -79,10 +70,9 @@ function readSessionFileCanonical(projectRoot) {
79
70
  return null;
80
71
  try {
81
72
  const data = JSON.parse(readFileSync(pathToRead, 'utf8'));
82
- const storedRaw = typeof data.projectRoot === 'string' ? data.projectRoot : null;
83
73
  if (data.sessionId &&
84
- storedRaw !== null &&
85
- resolveStoredAgainstCaller(storedRaw, projectRoot) === resolveStoredAgainstCaller(projectRoot, projectRoot)) {
74
+ typeof data.projectRoot === 'string' &&
75
+ projectRootsMatch(data.projectRoot, projectRoot)) {
86
76
  return data;
87
77
  }
88
78
  return null;
@@ -97,7 +87,15 @@ function writeSessionFile(projectRoot, info) {
97
87
  if (!existsSync(dir)) {
98
88
  mkdirSync(dir, { recursive: true });
99
89
  }
100
- writeFileSync(sessionFile, JSON.stringify(info, null, 2), 'utf8');
90
+ let canonicalProjectRoot;
91
+ try {
92
+ canonicalProjectRoot = stableRealPath(info.projectRoot);
93
+ }
94
+ catch {
95
+ canonicalProjectRoot = info.projectRoot;
96
+ }
97
+ const canonicalInfo = { ...info, projectRoot: canonicalProjectRoot };
98
+ writeFileSync(sessionFile, JSON.stringify(canonicalInfo, null, 2), 'utf8');
101
99
  }
102
100
  function getMetaFilePath(projectRoot, sessionId) {
103
101
  return join(projectRoot, '.peaks', '_runtime', sessionId, META_FILE);