@planu/cli 5.3.13 → 5.3.15

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 (50) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/dist/engine/cascade-hooks/hooks/housekeeping-on-done.hook.js +2 -3
  3. package/dist/engine/handoff-packager.d.ts +2 -2
  4. package/dist/engine/handoff-packager.js +5 -4
  5. package/dist/engine/housekeeping/find-stale-branches.d.ts +3 -3
  6. package/dist/engine/housekeeping/find-stale-branches.js +25 -29
  7. package/dist/engine/housekeeping/sweep-runner.js +105 -19
  8. package/dist/engine/planu-core.darwin-arm64.node.manifest.json +7 -7
  9. package/dist/engine/planu-core.darwin-arm64.node.sbom.json +8 -8
  10. package/dist/engine/planu-core.darwin-x64.node.manifest.json +7 -7
  11. package/dist/engine/planu-core.darwin-x64.node.sbom.json +8 -8
  12. package/dist/engine/planu-core.linux-arm64-gnu.node.manifest.json +7 -7
  13. package/dist/engine/planu-core.linux-arm64-gnu.node.sbom.json +8 -8
  14. package/dist/engine/planu-core.linux-arm64-musl.node.manifest.json +7 -7
  15. package/dist/engine/planu-core.linux-arm64-musl.node.sbom.json +8 -8
  16. package/dist/engine/planu-core.linux-x64-gnu.node.manifest.json +7 -7
  17. package/dist/engine/planu-core.linux-x64-gnu.node.sbom.json +8 -8
  18. package/dist/engine/planu-core.linux-x64-musl.node.manifest.json +7 -7
  19. package/dist/engine/planu-core.linux-x64-musl.node.sbom.json +8 -8
  20. package/dist/engine/planu-core.win32-arm64-msvc.node.manifest.json +7 -7
  21. package/dist/engine/planu-core.win32-arm64-msvc.node.sbom.json +8 -8
  22. package/dist/engine/planu-core.win32-x64-msvc.node.manifest.json +7 -7
  23. package/dist/engine/planu-core.win32-x64-msvc.node.sbom.json +8 -8
  24. package/dist/engine/spec-migrator/planu-root-cleaner.d.ts +2 -2
  25. package/dist/engine/spec-migrator/planu-root-cleaner.js +3 -2
  26. package/dist/engine/spec-migrator/strict-planu-cleanup.d.ts +2 -2
  27. package/dist/engine/spec-migrator/strict-planu-cleanup.js +18 -2
  28. package/dist/tools/git/cleanup-ops.d.ts +2 -2
  29. package/dist/tools/git/cleanup-ops.js +123 -58
  30. package/dist/tools/github-release-handler.js +3 -12
  31. package/dist/tools/housekeeping-sweep.d.ts +1 -0
  32. package/dist/tools/housekeeping-sweep.js +17 -10
  33. package/dist/tools/init-project/git-setup.d.ts +1 -0
  34. package/dist/tools/init-project/git-setup.js +7 -23
  35. package/dist/tools/init-project/handler.js +4 -1
  36. package/dist/tools/init-project/migration-runner.js +8 -1
  37. package/dist/tools/init-project/scaffold-writer.d.ts +1 -0
  38. package/dist/tools/init-project/scaffold-writer.js +1 -0
  39. package/dist/tools/update-status/batch.js +1 -1
  40. package/dist/tools/update-status/index.js +1 -0
  41. package/dist/tools/update-status-actions.d.ts +2 -2
  42. package/dist/tools/update-status-actions.js +20 -10
  43. package/dist/types/git.d.ts +19 -0
  44. package/dist/types/housekeeping.d.ts +9 -1
  45. package/dist/types/index.d.ts +1 -0
  46. package/dist/types/index.js +1 -0
  47. package/dist/types/spec-format.d.ts +3 -0
  48. package/package.json +11 -10
  49. package/planu-native.json +1 -1
  50. package/planu-plugin.json +1 -1
package/CHANGELOG.md CHANGED
@@ -1,3 +1,33 @@
1
+ ## [5.3.15] - 2026-08-11
2
+
3
+ ### Bug Fixes
4
+ - fix(spec-1403): apply implementation-review arbitration fixes
5
+ - fix(spec-1403): make destructive housekeeping report-only under typed authority
6
+
7
+ ### Chores
8
+ - chore(spec-1403): record done transition with arbitration evidence
9
+
10
+
11
+ ## [5.3.14] - 2026-08-10
12
+
13
+ ### Bug Fixes
14
+ - fix(spec-1481): bound trapped fixture life per implementation-review arbitration
15
+ - fix(spec-1481): harden stdio abort test vs load and de-vacuize pid asserts
16
+ - fix(spec-1466): apply implementation-review arbitration fixes
17
+ - fix(spec-1467): require positive integer pid in waitForPid per review arbitration
18
+ - fix(spec-1466): legalize test-evidence overlap in ownership gate and handoff agreement
19
+ - fix(spec-1467): harden timing-sensitive receipt and process-runner tests
20
+
21
+ ### Chores
22
+ - chore(specs): file SPEC-1484 durable heartbeat flaky test dogfood bug
23
+ - chore(specs): file SPEC-1483 stale native artifacts after release abort
24
+ - chore(specs): record SPEC-1481 done transition and file SPEC-1482 lint-gate bug
25
+ - chore(specs): file SPEC-1481 flaky stdio lifecycle test under full-suite load
26
+ - chore(specs): record done transitions for SPEC-1466/1467 and file SPEC-1480 debt spec
27
+ - chore(specs): record implementing transitions for SPEC-1466/1467 with handoff evidence
28
+ - chore(specs): approve SPEC-1466/1467 after round 2; file SPEC-1479
29
+
30
+
1
31
  ## [5.3.13] - 2026-08-10
2
32
 
3
33
  ### Bug Fixes
@@ -9,8 +9,7 @@ async function handler(ctx) {
9
9
  try {
10
10
  // Dynamic import keeps module graph lean — housekeeping-sweep is only needed on 'done'.
11
11
  const { runHousekeepingSweep } = await import('../../housekeeping/index.js');
12
- // Housekeeping also auto-triggers via SPEC-790 in github-release-handler.ts
13
- void runHousekeepingSweep({ projectPath, dryRun: false });
12
+ void runHousekeepingSweep({ projectPath });
14
13
  }
15
14
  catch (err) {
16
15
  const error = err instanceof Error ? err.message : String(err);
@@ -29,7 +28,7 @@ export const housekeepingOnDoneHook = {
29
28
  id: 'housekeeping-on-done',
30
29
  triggers: ['done'],
31
30
  requiresProjectPath: true,
32
- label: 'Auto-run housekeeping_sweep on spec done — delete orphan stashes/branches (SPEC-782)',
31
+ label: 'Auto-run report-only housekeeping_sweep on spec done (SPEC-782)',
33
32
  handler,
34
33
  };
35
34
  //# sourceMappingURL=housekeeping-on-done.hook.js.map
@@ -16,8 +16,8 @@ export declare function extractCanonicalFileOwnership(content: string): {
16
16
  toModify: string[];
17
17
  toCreate: string[];
18
18
  toTest: string[];
19
- /** Test paths as declared, before conflict filteringused to exclude conflicted
20
- * paths from other categories even though they no longer appear in `toTest`. */
19
+ /** Test paths as declared, before conflict strippingfeeds the package-level
20
+ * test filter and the ownership-agreement exclusion. */
21
21
  toTestDeclared: string[];
22
22
  blockers: string[];
23
23
  };
@@ -213,7 +213,7 @@ export function extractCanonicalFileOwnership(content) {
213
213
  const toCreate = parseSection('Create');
214
214
  const toModify = parseSection('Modify');
215
215
  const toTest = parseSection('Test');
216
- const conflicts = [...new Set([...toCreate, ...toModify, ...toTest])].filter((path) => [toCreate, toModify, toTest].filter((paths) => paths.includes(path)).length > 1);
216
+ const conflicts = toCreate.filter((path) => toModify.includes(path));
217
217
  for (const path of conflicts) {
218
218
  addBlocker(`CONFLICTING_FILE_OWNERSHIP: ${path}`);
219
219
  }
@@ -411,10 +411,11 @@ function extractFileLevelWorkPlanOwnership(content) {
411
411
  blockers: [...new Set(state.blockers)].sort(),
412
412
  };
413
413
  }
414
- function validateOwnershipAgreement(canonical, workPlan) {
414
+ function validateOwnershipAgreement(canonical, workPlan, testDeclaredPaths) {
415
415
  if (!canonical.present || !workPlan.present) {
416
416
  return [];
417
417
  }
418
+ const testDeclared = new Set(testDeclaredPaths);
418
419
  const classification = (ownership, path) => ownership.toCreate.includes(path)
419
420
  ? 'Create'
420
421
  : ownership.toModify.includes(path)
@@ -425,7 +426,7 @@ function validateOwnershipAgreement(canonical, workPlan) {
425
426
  ...canonical.toModify,
426
427
  ...workPlan.toCreate,
427
428
  ...workPlan.toModify,
428
- ]);
429
+ ].filter((path) => !testDeclared.has(path)));
429
430
  return [...paths].sort().flatMap((path) => {
430
431
  const canonicalClass = classification(canonical, path);
431
432
  const workPlanClass = classification(workPlan, path);
@@ -598,7 +599,7 @@ export async function packageHandoff(spec, knowledge) {
598
599
  ...canonicalFiles.blockers,
599
600
  ...canonicalOwnership.blockers,
600
601
  ...workPlanOwnership.blockers,
601
- ...validateOwnershipAgreement(canonicalOwnership, workPlanOwnership),
602
+ ...validateOwnershipAgreement(canonicalOwnership, workPlanOwnership, canonicalFiles.toTestDeclared),
602
603
  ...(!['draft', 'review', 'approved', 'implementing', 'done', 'discarded'].includes(spec.status)
603
604
  ? [`UNSUPPORTED_LIFECYCLE_STATUS: ${spec.status}`]
604
605
  : []),
@@ -27,9 +27,9 @@ export declare function extractSpecIdFromCommit(projectPath: string, sha: string
27
27
  */
28
28
  export declare function lookupSpecStatus(projectPath: string, specId: string): Promise<string | null>;
29
29
  /**
30
- * Pass 2: for each branch in `skipped` with reason 'not_merged', check if its
31
- * SPEC ID (from name or tip commit message) is `done` or `discarded` in Planu.
32
- * Matching branches are moved from `skipped` to `stale` with reason 'spec-done'.
30
+ * Pass 2: a `not_merged` branch whose spec is done/discarded becomes `stale`
31
+ * only when `git merge-base --is-ancestor` proves every commit is reachable
32
+ * from main, develop, or master. Spec status alone never promotes a branch.
33
33
  * Mutates both arrays in-place.
34
34
  */
35
35
  export declare function applySpecDonePass(projectPath: string, skipped: SkippedBranchInfo[], stale: StaleBranchInfo[], branchShas: Map<string, string>): Promise<void>;
@@ -148,8 +148,6 @@ export async function extractSpecIdFromCommit(projectPath, sha) {
148
148
  return null;
149
149
  }
150
150
  }
151
- /** Terminal statuses that mean the branch work is complete. */
152
- const DONE_STATUSES = new Set(['done', 'discarded']);
153
151
  /**
154
152
  * Look up the status of a spec by reading 'planu/specs/<specId>-star/spec.md' frontmatter.
155
153
  * Returns the raw status string, or null when not found.
@@ -176,43 +174,41 @@ export async function lookupSpecStatus(projectPath, specId) {
176
174
  return null;
177
175
  }
178
176
  }
177
+ async function isProvenIntegrated(projectPath, branch) {
178
+ for (const base of ['main', 'develop', 'master']) {
179
+ try {
180
+ await execFile('git', ['merge-base', '--is-ancestor', branch, base], { cwd: projectPath });
181
+ return true;
182
+ }
183
+ catch {
184
+ continue;
185
+ }
186
+ }
187
+ return false;
188
+ }
179
189
  /**
180
- * Pass 2: for each branch in `skipped` with reason 'not_merged', check if its
181
- * SPEC ID (from name or tip commit message) is `done` or `discarded` in Planu.
182
- * Matching branches are moved from `skipped` to `stale` with reason 'spec-done'.
190
+ * Pass 2: a `not_merged` branch whose spec is done/discarded becomes `stale`
191
+ * only when `git merge-base --is-ancestor` proves every commit is reachable
192
+ * from main, develop, or master. Spec status alone never promotes a branch.
183
193
  * Mutates both arrays in-place.
184
194
  */
185
195
  export async function applySpecDonePass(projectPath, skipped, stale, branchShas) {
186
- // Fast-path: no not_merged branches nothing for Pass 2 to do.
187
- const notMerged = skipped.filter((b) => b.skipReason === 'not_merged');
188
- if (notMerged.length === 0) {
189
- return;
190
- }
191
- const toRemove = new Set();
192
- for (const branch of notMerged) {
193
- // Try branch name first (zero git calls)
194
- let specId = extractSpecIdFromName(branch.name);
195
- // Fall back to commit message if name has no spec id (one git call per branch)
196
- if (!specId) {
197
- const sha = branchShas.get(branch.name) ?? '';
198
- specId = await extractSpecIdFromCommit(projectPath, sha);
199
- }
196
+ const candidates = skipped.filter((entry) => entry.skipReason === 'not_merged');
197
+ for (const candidate of candidates) {
198
+ const sha = branchShas.get(candidate.name) ?? '';
199
+ const specId = extractSpecIdFromName(candidate.name) ?? (await extractSpecIdFromCommit(projectPath, sha));
200
200
  if (!specId) {
201
201
  continue;
202
202
  }
203
203
  const status = await lookupSpecStatus(projectPath, specId);
204
- if (status !== null && DONE_STATUSES.has(status)) {
205
- const sha = branchShas.get(branch.name) ?? '';
206
- stale.push({ name: branch.name, sha, reason: 'spec-done' });
207
- toRemove.add(branch.name);
204
+ if (status !== 'done' && status !== 'discarded') {
205
+ continue;
208
206
  }
209
- }
210
- // Remove promoted branches from skipped
211
- for (let i = skipped.length - 1; i >= 0; i--) {
212
- const entry = skipped[i];
213
- if (entry && toRemove.has(entry.name)) {
214
- skipped.splice(i, 1);
207
+ if (!(await isProvenIntegrated(projectPath, candidate.name))) {
208
+ continue;
215
209
  }
210
+ skipped.splice(skipped.indexOf(candidate), 1);
211
+ stale.push({ name: candidate.name, sha, reason: 'spec-done' });
216
212
  }
217
213
  }
218
214
  export async function findStaleBranches(input) {
@@ -19,9 +19,43 @@ async function deleteBranch(projectPath, branchName) {
19
19
  return false;
20
20
  }
21
21
  }
22
+ async function remoteBranchRefExists(projectPath, branchName) {
23
+ try {
24
+ const { stdout } = await execFile('git', ['ls-remote', '--heads', 'origin', branchName], {
25
+ cwd: projectPath,
26
+ });
27
+ return stdout.trim().length > 0;
28
+ }
29
+ catch {
30
+ return false;
31
+ }
32
+ }
33
+ async function isRemoteBranchProvenMerged(projectPath, branchName) {
34
+ for (const base of ['main', 'develop', 'master']) {
35
+ try {
36
+ await execFile('git', ['merge-base', '--is-ancestor', `origin/${branchName}`, base], {
37
+ cwd: projectPath,
38
+ });
39
+ return true;
40
+ }
41
+ catch {
42
+ continue;
43
+ }
44
+ }
45
+ return false;
46
+ }
47
+ async function deleteRemoteBranch(projectPath, branchName) {
48
+ try {
49
+ await execFile('git', ['push', 'origin', '--delete', branchName], { cwd: projectPath });
50
+ return true;
51
+ }
52
+ catch {
53
+ return false;
54
+ }
55
+ }
22
56
  async function removeWorktree(projectPath, worktreePath) {
23
57
  try {
24
- await execFile('git', ['worktree', 'remove', '--force', worktreePath], { cwd: projectPath });
58
+ await execFile('git', ['worktree', 'remove', worktreePath], { cwd: projectPath });
25
59
  return true;
26
60
  }
27
61
  catch {
@@ -41,7 +75,6 @@ async function dropStash(projectPath, stashRef) {
41
75
  // Backup helpers
42
76
  // ---------------------------------------------------------------------------
43
77
  async function backupAndDeleteBranch(projectPath, branch) {
44
- // Write to history BEFORE deleting (for recovery)
45
78
  try {
46
79
  await appendHousekeepingEntry(projectPath, {
47
80
  projectPath,
@@ -50,10 +83,30 @@ async function backupAndDeleteBranch(projectPath, branch) {
50
83
  sha: branch.sha,
51
84
  });
52
85
  }
53
- catch {
54
- // Log failure is non-fatal — continue with deletion
86
+ catch (error) {
87
+ return {
88
+ ok: false,
89
+ error: `branch ${branch.name}: ${error instanceof Error ? error.message : String(error)}`,
90
+ };
55
91
  }
56
- return deleteBranch(projectPath, branch.name);
92
+ return { ok: await deleteBranch(projectPath, branch.name) };
93
+ }
94
+ async function backupAndDeleteRemoteBranch(projectPath, branch) {
95
+ try {
96
+ await appendHousekeepingEntry(projectPath, {
97
+ projectPath,
98
+ kind: 'branch',
99
+ ref: `origin/${branch.name}`,
100
+ sha: branch.sha,
101
+ });
102
+ }
103
+ catch (error) {
104
+ return {
105
+ ok: false,
106
+ error: `remote branch origin/${branch.name}: ${error instanceof Error ? error.message : String(error)}`,
107
+ };
108
+ }
109
+ return { ok: await deleteRemoteBranch(projectPath, branch.name) };
57
110
  }
58
111
  async function backupAndRemoveWorktree(projectPath, wt) {
59
112
  try {
@@ -64,10 +117,13 @@ async function backupAndRemoveWorktree(projectPath, wt) {
64
117
  sha: wt.branch ?? '',
65
118
  });
66
119
  }
67
- catch {
68
- // non-fatal
120
+ catch (error) {
121
+ return {
122
+ ok: false,
123
+ error: `worktree ${wt.path}: ${error instanceof Error ? error.message : String(error)}`,
124
+ };
69
125
  }
70
- return removeWorktree(projectPath, wt.path);
126
+ return { ok: await removeWorktree(projectPath, wt.path) };
71
127
  }
72
128
  async function backupAndDropStash(projectPath, stash) {
73
129
  try {
@@ -78,16 +134,19 @@ async function backupAndDropStash(projectPath, stash) {
78
134
  sha: String(stash.createdAt),
79
135
  });
80
136
  }
81
- catch {
82
- // non-fatal
137
+ catch (error) {
138
+ return {
139
+ ok: false,
140
+ error: `stash ${stash.ref}: ${error instanceof Error ? error.message : String(error)}`,
141
+ };
83
142
  }
84
- return dropStash(projectPath, stash.ref);
143
+ return { ok: await dropStash(projectPath, stash.ref) };
85
144
  }
86
145
  // ---------------------------------------------------------------------------
87
146
  // Main orchestrator
88
147
  // ---------------------------------------------------------------------------
89
148
  export async function runHousekeepingSweep(input) {
90
- const { projectPath, dryRun = true, aggressive = false, includeStashes = false } = input;
149
+ const { projectPath, authority = { mode: 'report' }, aggressive = false, includeStashes = false, } = input;
91
150
  const sweepAt = new Date().toISOString();
92
151
  // Find stale items in parallel
93
152
  const [{ stale: staleBranches, skipped }, staleWorktrees, staleStashes] = await Promise.all([
@@ -96,6 +155,7 @@ export async function runHousekeepingSweep(input) {
96
155
  includeStashes ? findStaleStashes({ projectPath }) : Promise.resolve([]),
97
156
  ]);
98
157
  const report = {
158
+ mode: authority.mode,
99
159
  sweepAt,
100
160
  projectPath,
101
161
  wouldDelete: {
@@ -108,34 +168,60 @@ export async function runHousekeepingSweep(input) {
108
168
  },
109
169
  executed: false,
110
170
  deleted: { branches: 0, worktrees: 0, stashes: 0, backups: 0 },
171
+ errors: [],
111
172
  };
112
- if (dryRun) {
173
+ if (authority.mode === 'report') {
113
174
  return report;
114
175
  }
115
176
  // Execute deletions
116
177
  report.executed = true;
117
178
  // Delete branches (sequential — each needs a backup entry first)
118
179
  for (const branch of staleBranches) {
119
- const ok = await backupAndDeleteBranch(projectPath, branch);
120
- if (ok) {
180
+ const result = await backupAndDeleteBranch(projectPath, branch);
181
+ if (result.ok) {
121
182
  report.deleted.branches++;
122
183
  }
184
+ else if (result.error) {
185
+ report.errors.push(result.error);
186
+ }
187
+ if (!authority.deleteRemoteRefs) {
188
+ continue;
189
+ }
190
+ if (!(await remoteBranchRefExists(projectPath, branch.name))) {
191
+ continue;
192
+ }
193
+ if (!(await isRemoteBranchProvenMerged(projectPath, branch.name))) {
194
+ continue;
195
+ }
196
+ const remoteResult = await backupAndDeleteRemoteBranch(projectPath, branch);
197
+ if (remoteResult.ok) {
198
+ report.deleted.branches++;
199
+ }
200
+ else if (remoteResult.error) {
201
+ report.errors.push(remoteResult.error);
202
+ }
123
203
  }
124
204
  // Remove worktrees (sequential)
125
205
  for (const wt of staleWorktrees) {
126
- const ok = await backupAndRemoveWorktree(projectPath, wt);
127
- if (ok) {
206
+ const result = await backupAndRemoveWorktree(projectPath, wt);
207
+ if (result.ok) {
128
208
  report.deleted.worktrees++;
129
209
  }
210
+ else if (result.error) {
211
+ report.errors.push(result.error);
212
+ }
130
213
  }
131
214
  // Drop stashes (sequential — must handle index shifting)
132
215
  // Drop in reverse order so indices stay valid
133
216
  const reversedStashes = [...staleStashes].reverse();
134
217
  for (const stash of reversedStashes) {
135
- const ok = await backupAndDropStash(projectPath, stash);
136
- if (ok) {
218
+ const result = await backupAndDropStash(projectPath, stash);
219
+ if (result.ok) {
137
220
  report.deleted.stashes++;
138
221
  }
222
+ else if (result.error) {
223
+ report.errors.push(result.error);
224
+ }
139
225
  }
140
226
  // SPEC-771: clean stale .bak.* backup files from planu/specs/ (best-effort)
141
227
  report.deleted.backups = await cleanStaleBackups(projectPath);
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "schemaVersion": 2,
3
- "cliVersion": "5.3.13",
4
- "engineVersion": "5.3.13",
5
- "buildId": "1-5.3.13-aarch64-apple-darwin",
3
+ "cliVersion": "5.3.15",
4
+ "engineVersion": "5.3.15",
5
+ "buildId": "1-5.3.15-aarch64-apple-darwin",
6
6
  "protocolAbi": 1,
7
7
  "capabilityAbi": 2,
8
8
  "nodeApiAbi": 4,
@@ -17,15 +17,15 @@
17
17
  "platform": "darwin",
18
18
  "arch": "arm64",
19
19
  "libc": null,
20
- "artifactSha256": "63b4e21bd8fd8154d97f9f1a471fd7a731c6bc0514dec2ef9a2a5d9f1a98eb32",
20
+ "artifactSha256": "0fbd8c0babdbfb88cae442db9cc57521f67ee345aa1872ed0cd04f464f992584",
21
21
  "sbom": {
22
22
  "format": "CycloneDX-1.5",
23
23
  "path": "planu-core.darwin-arm64.node.sbom.json",
24
- "sha256": "b25f5ddbd51db18f2bebb1e86e7cd31f174e3613e187ec00c7ebc66132a66d0c"
24
+ "sha256": "41999cac08a7c64a9c899eac628df8e4bc10d70dc1b1923d5951a89f5ac8e878"
25
25
  },
26
26
  "provenance": {
27
27
  "builder": "scripts/build-rust-local.sh",
28
- "sourceCommit": "4c29cf026dcfa833b89a328afa3546aecbc02d22",
28
+ "sourceCommit": "14948c630bfb7a355391c10563934cc79e8bb167",
29
29
  "sourceTreeDirty": false,
30
30
  "sourceDateEpoch": 1,
31
31
  "rustToolchain": "rustc 1.95.0 (59807616e 2026-04-14)",
@@ -34,6 +34,6 @@
34
34
  "signature": {
35
35
  "algorithm": "Ed25519",
36
36
  "keyId": "e2ee765cb5ad9fbdc433ece332bce26d746d5e350b3acde0721a4c8c6337ff7b",
37
- "value": "8h2IO454Azg9cLFFiaQj1bEZ8np+FAUG+F7hZqLueM1Cu8k3lWakVBIB4h10CNEYk59TFsi02SfqUBXiUhr1DQ=="
37
+ "value": "bTat4AK64vTOtmTHrAf9w8z5d8GbFuxJZizc1YuZm05VpDaKzSaHkztZ5Hrb+sKu0lppYebpOGwYqTcFmfUMDQ=="
38
38
  }
39
39
  }
@@ -4,14 +4,14 @@
4
4
  "version": 1,
5
5
  "metadata": {
6
6
  "component": {
7
- "bom-ref": "pkg:cargo/planu-core@5.3.13",
7
+ "bom-ref": "pkg:cargo/planu-core@5.3.15",
8
8
  "type": "library",
9
9
  "name": "planu-core",
10
- "version": "5.3.13",
10
+ "version": "5.3.15",
11
11
  "hashes": [
12
12
  {
13
13
  "alg": "SHA-256",
14
- "content": "63b4e21bd8fd8154d97f9f1a471fd7a731c6bc0514dec2ef9a2a5d9f1a98eb32"
14
+ "content": "0fbd8c0babdbfb88cae442db9cc57521f67ee345aa1872ed0cd04f464f992584"
15
15
  }
16
16
  ]
17
17
  }
@@ -70,9 +70,9 @@
70
70
  },
71
71
  {
72
72
  "type": "library",
73
- "bom-ref": "pkg:cargo/bstr@1.13.0",
73
+ "bom-ref": "pkg:cargo/bstr@1.13.1",
74
74
  "name": "bstr",
75
- "version": "1.13.0",
75
+ "version": "1.13.1",
76
76
  "externalReferences": [
77
77
  {
78
78
  "type": "distribution",
@@ -971,7 +971,7 @@
971
971
  ]
972
972
  },
973
973
  {
974
- "ref": "pkg:cargo/bstr@1.13.0",
974
+ "ref": "pkg:cargo/bstr@1.13.1",
975
975
  "dependsOn": [
976
976
  "pkg:cargo/memchr@2.8.3",
977
977
  "pkg:cargo/serde_core@1.0.228"
@@ -1049,7 +1049,7 @@
1049
1049
  "ref": "pkg:cargo/globset@0.4.20",
1050
1050
  "dependsOn": [
1051
1051
  "pkg:cargo/aho-corasick@1.1.5",
1052
- "pkg:cargo/bstr@1.13.0",
1052
+ "pkg:cargo/bstr@1.13.1",
1053
1053
  "pkg:cargo/log@0.4.33",
1054
1054
  "pkg:cargo/regex-automata@0.4.18",
1055
1055
  "pkg:cargo/regex-syntax@0.8.11"
@@ -1106,7 +1106,7 @@
1106
1106
  "dependsOn": []
1107
1107
  },
1108
1108
  {
1109
- "ref": "pkg:cargo/planu-core@5.3.13",
1109
+ "ref": "pkg:cargo/planu-core@5.3.15",
1110
1110
  "dependsOn": [
1111
1111
  "pkg:cargo/core-foundation@0.10.1",
1112
1112
  "pkg:cargo/hmac@0.12.1",
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "schemaVersion": 2,
3
- "cliVersion": "5.3.13",
4
- "engineVersion": "5.3.13",
5
- "buildId": "1-5.3.13-x86_64-apple-darwin",
3
+ "cliVersion": "5.3.15",
4
+ "engineVersion": "5.3.15",
5
+ "buildId": "1-5.3.15-x86_64-apple-darwin",
6
6
  "protocolAbi": 1,
7
7
  "capabilityAbi": 2,
8
8
  "nodeApiAbi": 4,
@@ -17,15 +17,15 @@
17
17
  "platform": "darwin",
18
18
  "arch": "x64",
19
19
  "libc": null,
20
- "artifactSha256": "6af7f8df49b56c0e440dbb5088a957943d0b1e8bd6d243392d00e224205dab63",
20
+ "artifactSha256": "f2b7904e0e93116b6042e9f67e33ca60f2f054a48ae9f365327209473010a38a",
21
21
  "sbom": {
22
22
  "format": "CycloneDX-1.5",
23
23
  "path": "planu-core.darwin-x64.node.sbom.json",
24
- "sha256": "7fccd089cc1a35511497238f84f697bcee2d0c00534f6fefe3ddfbe770d3d617"
24
+ "sha256": "40bb12bea402c3d433ca284cbb80c122ffcacb68defa17409da65583f9fe0b73"
25
25
  },
26
26
  "provenance": {
27
27
  "builder": "scripts/build-rust-local.sh",
28
- "sourceCommit": "4c29cf026dcfa833b89a328afa3546aecbc02d22",
28
+ "sourceCommit": "14948c630bfb7a355391c10563934cc79e8bb167",
29
29
  "sourceTreeDirty": false,
30
30
  "sourceDateEpoch": 1,
31
31
  "rustToolchain": "rustc 1.95.0 (59807616e 2026-04-14)",
@@ -34,6 +34,6 @@
34
34
  "signature": {
35
35
  "algorithm": "Ed25519",
36
36
  "keyId": "e2ee765cb5ad9fbdc433ece332bce26d746d5e350b3acde0721a4c8c6337ff7b",
37
- "value": "tnN9tivctc9090o+HeQTDhLowV/Z+Kp4mUQcxpxj7CKiLWrClaGzwlcEABXsF8YJcSLHSrxiUnB+397bAOaQDw=="
37
+ "value": "wDC/VmuwtNH7DIZHFeD9JAuHp08V8yDMSOgopr83IQIBnQkWBsqS9lQ2Zchxh7JNiTEfICvSQF7lMxA9Dk6UAQ=="
38
38
  }
39
39
  }
@@ -4,14 +4,14 @@
4
4
  "version": 1,
5
5
  "metadata": {
6
6
  "component": {
7
- "bom-ref": "pkg:cargo/planu-core@5.3.13",
7
+ "bom-ref": "pkg:cargo/planu-core@5.3.15",
8
8
  "type": "library",
9
9
  "name": "planu-core",
10
- "version": "5.3.13",
10
+ "version": "5.3.15",
11
11
  "hashes": [
12
12
  {
13
13
  "alg": "SHA-256",
14
- "content": "6af7f8df49b56c0e440dbb5088a957943d0b1e8bd6d243392d00e224205dab63"
14
+ "content": "f2b7904e0e93116b6042e9f67e33ca60f2f054a48ae9f365327209473010a38a"
15
15
  }
16
16
  ]
17
17
  }
@@ -70,9 +70,9 @@
70
70
  },
71
71
  {
72
72
  "type": "library",
73
- "bom-ref": "pkg:cargo/bstr@1.13.0",
73
+ "bom-ref": "pkg:cargo/bstr@1.13.1",
74
74
  "name": "bstr",
75
- "version": "1.13.0",
75
+ "version": "1.13.1",
76
76
  "externalReferences": [
77
77
  {
78
78
  "type": "distribution",
@@ -971,7 +971,7 @@
971
971
  ]
972
972
  },
973
973
  {
974
- "ref": "pkg:cargo/bstr@1.13.0",
974
+ "ref": "pkg:cargo/bstr@1.13.1",
975
975
  "dependsOn": [
976
976
  "pkg:cargo/memchr@2.8.3",
977
977
  "pkg:cargo/serde_core@1.0.228"
@@ -1049,7 +1049,7 @@
1049
1049
  "ref": "pkg:cargo/globset@0.4.20",
1050
1050
  "dependsOn": [
1051
1051
  "pkg:cargo/aho-corasick@1.1.5",
1052
- "pkg:cargo/bstr@1.13.0",
1052
+ "pkg:cargo/bstr@1.13.1",
1053
1053
  "pkg:cargo/log@0.4.33",
1054
1054
  "pkg:cargo/regex-automata@0.4.18",
1055
1055
  "pkg:cargo/regex-syntax@0.8.11"
@@ -1106,7 +1106,7 @@
1106
1106
  "dependsOn": []
1107
1107
  },
1108
1108
  {
1109
- "ref": "pkg:cargo/planu-core@5.3.13",
1109
+ "ref": "pkg:cargo/planu-core@5.3.15",
1110
1110
  "dependsOn": [
1111
1111
  "pkg:cargo/core-foundation@0.10.1",
1112
1112
  "pkg:cargo/hmac@0.12.1",
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "schemaVersion": 2,
3
- "cliVersion": "5.3.13",
4
- "engineVersion": "5.3.13",
5
- "buildId": "1-5.3.13-aarch64-unknown-linux-gnu",
3
+ "cliVersion": "5.3.15",
4
+ "engineVersion": "5.3.15",
5
+ "buildId": "1-5.3.15-aarch64-unknown-linux-gnu",
6
6
  "protocolAbi": 1,
7
7
  "capabilityAbi": 2,
8
8
  "nodeApiAbi": 4,
@@ -16,15 +16,15 @@
16
16
  "platform": "linux",
17
17
  "arch": "arm64",
18
18
  "libc": "glibc",
19
- "artifactSha256": "6dc15d18af613ad34ab23bc8d36387596c6d4e56a32130500d87581637afc5c6",
19
+ "artifactSha256": "01ea24db6f97e97faeef630279a6ee999acb4a7562771459a2423a7598304253",
20
20
  "sbom": {
21
21
  "format": "CycloneDX-1.5",
22
22
  "path": "planu-core.linux-arm64-gnu.node.sbom.json",
23
- "sha256": "5284d0de91c78b38db90e45d503bdfc1663bdd347d02afa2d4ee077973a558c5"
23
+ "sha256": "02f9bcacd4b15056f3b945e103ed330d231fc9ac0f1a377dd1ec326e60b2b1dc"
24
24
  },
25
25
  "provenance": {
26
26
  "builder": "scripts/build-rust-local.sh",
27
- "sourceCommit": "4c29cf026dcfa833b89a328afa3546aecbc02d22",
27
+ "sourceCommit": "14948c630bfb7a355391c10563934cc79e8bb167",
28
28
  "sourceTreeDirty": false,
29
29
  "sourceDateEpoch": 1,
30
30
  "rustToolchain": "rustc 1.95.0 (59807616e 2026-04-14)",
@@ -33,6 +33,6 @@
33
33
  "signature": {
34
34
  "algorithm": "Ed25519",
35
35
  "keyId": "e2ee765cb5ad9fbdc433ece332bce26d746d5e350b3acde0721a4c8c6337ff7b",
36
- "value": "QBwJ3Bv0Cu43hS/zvTdSyOE9ua2CpkENsXB8xP6XmxGGXvGiJSQkkK2Un6PQ/7EZKt88wuJd95a6bZKfCSzdDw=="
36
+ "value": "LwJ+lJNVWcGsacrsWvGRbBS6WQTC7iMOAg3yfb0AZtdsHLBvAyG1700kh/1E1CbKEUR73CbUmU2TzEzVkesUAw=="
37
37
  }
38
38
  }