@planu/cli 5.3.1 → 5.3.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/CHANGELOG.md +32 -0
  2. package/README.md +1 -1
  3. package/dist/config/official-sdd-tools.d.ts +1 -1
  4. package/dist/config/official-sdd-tools.js +1 -0
  5. package/dist/config/registries/hosts/codex.json +2 -1
  6. package/dist/config/runtime-policy.json +9 -0
  7. package/dist/engine/autopilot/complete-loop.js +4 -1
  8. package/dist/engine/execution/outbox-worker.d.ts +8 -0
  9. package/dist/engine/execution/outbox-worker.js +102 -31
  10. package/dist/engine/handoff-packager.d.ts +3 -0
  11. package/dist/engine/handoff-packager.js +18 -3
  12. package/dist/engine/planu-core.darwin-arm64.node.manifest.json +7 -7
  13. package/dist/engine/planu-core.darwin-arm64.node.sbom.json +4 -4
  14. package/dist/engine/planu-core.darwin-x64.node.manifest.json +7 -7
  15. package/dist/engine/planu-core.darwin-x64.node.sbom.json +4 -4
  16. package/dist/engine/planu-core.linux-arm64-gnu.node.manifest.json +7 -7
  17. package/dist/engine/planu-core.linux-arm64-gnu.node.sbom.json +4 -4
  18. package/dist/engine/planu-core.linux-arm64-musl.node.manifest.json +7 -7
  19. package/dist/engine/planu-core.linux-arm64-musl.node.sbom.json +4 -4
  20. package/dist/engine/planu-core.linux-x64-gnu.node.manifest.json +7 -7
  21. package/dist/engine/planu-core.linux-x64-gnu.node.sbom.json +4 -4
  22. package/dist/engine/planu-core.linux-x64-musl.node.manifest.json +7 -7
  23. package/dist/engine/planu-core.linux-x64-musl.node.sbom.json +4 -4
  24. package/dist/engine/planu-core.win32-arm64-msvc.node.manifest.json +7 -7
  25. package/dist/engine/planu-core.win32-arm64-msvc.node.sbom.json +4 -4
  26. package/dist/engine/planu-core.win32-x64-msvc.node.manifest.json +7 -7
  27. package/dist/engine/planu-core.win32-x64-msvc.node.sbom.json +4 -4
  28. package/dist/engine/runtime-policy.js +14 -0
  29. package/dist/index.js +3 -1
  30. package/dist/storage/runtime-db.d.ts +23 -1
  31. package/dist/storage/runtime-db.js +79 -9
  32. package/dist/tools/create-spec/post-creation.js +7 -2
  33. package/dist/tools/create-spec/spec-created-outbox-consumer.d.ts +2 -0
  34. package/dist/tools/create-spec/spec-created-outbox-consumer.js +94 -6
  35. package/dist/tools/create-spec-helpers.d.ts +2 -2
  36. package/dist/tools/create-spec-helpers.js +2 -2
  37. package/dist/tools/git/branch-ops.d.ts +7 -3
  38. package/dist/tools/git/branch-ops.js +68 -18
  39. package/dist/tools/package-handoff.d.ts +2 -1
  40. package/dist/tools/package-handoff.js +23 -4
  41. package/dist/tools/register-sdd-tools.js +2 -0
  42. package/dist/tools/update-status-actions.js +4 -2
  43. package/dist/types/git.d.ts +4 -0
  44. package/dist/types/outbox-worker.d.ts +2 -0
  45. package/dist/types/readiness.d.ts +1 -0
  46. package/dist/types/runtime-policy.d.ts +9 -0
  47. package/package.json +9 -9
  48. package/planu-native.json +1 -1
  49. package/planu-plugin.json +3 -2
@@ -1,9 +1,9 @@
1
- import type { GitSetupResult } from '../types/index.js';
1
+ import type { GitSetupResult, GitAutoSetupOptions } from '../types/index.js';
2
2
  export declare function slugify(text: string): string;
3
3
  export declare function generateSpecId(existingSpecs: {
4
4
  id: string;
5
5
  }[]): string;
6
6
  export declare function generateBranchName(specId: string, slug: string, type: string): string;
7
7
  /** Try auto-setup git branch. Returns result or undefined on failure. */
8
- export declare function tryAutoSetupGit(projectId: string, specId: string): Promise<GitSetupResult | undefined>;
8
+ export declare function tryAutoSetupGit(projectId: string, specId: string, options?: GitAutoSetupOptions): Promise<GitSetupResult | undefined>;
9
9
  //# sourceMappingURL=create-spec-helpers.d.ts.map
@@ -29,10 +29,10 @@ export function generateBranchName(specId, slug, type) {
29
29
  return `${BRANCH_PREFIXES[type] ?? 'feat'}/${specId.toLowerCase()}-${slug}`;
30
30
  }
31
31
  /** Try auto-setup git branch. Returns result or undefined on failure. */
32
- export async function tryAutoSetupGit(projectId, specId) {
32
+ export async function tryAutoSetupGit(projectId, specId, options) {
33
33
  /* v8 ignore start -- requires real git repo with branches */
34
34
  try {
35
- const r = await handleAutoSetup(projectId, specId);
35
+ const r = await handleAutoSetup(projectId, specId, undefined, options);
36
36
  if (!r.isError && r.content[0]?.type === 'text') {
37
37
  const data = JSON.parse(r.content[0].text);
38
38
  if (typeof data.newBranch !== 'string') {
@@ -1,12 +1,16 @@
1
- import type { ToolResult, GitConfig } from '../../types/index.js';
2
- export declare function handleCreateBranch(projectId: string, specId: string | undefined, config?: GitConfig, resolvedProjectPath?: string): Promise<ToolResult>;
1
+ import type { ToolResult, GitConfig, GitAutoSetupOptions } from '../../types/index.js';
2
+ export declare function handleCreateBranch(projectId: string, specId: string | undefined, config?: GitConfig, resolvedProjectPath?: string, options?: GitAutoSetupOptions): Promise<ToolResult>;
3
3
  export declare function handleCheckBranch(projectId: string, _specId: string | undefined, config?: GitConfig): Promise<ToolResult>;
4
4
  /**
5
5
  * Auto-setup: detect git workflow, sync base branch, create feature branch.
6
6
  * Combines detectGitFlowType + resolveBaseBranch + fetch/pull + create-branch
7
7
  * into a single atomic operation for spec creation.
8
+ *
9
+ * SPEC-1396: `mutateCheckout: false` creates the branch ref without touching HEAD
10
+ * or the working tree. Automatic callers (outbox recovery, cascades) MUST use it —
11
+ * a background checkout silently moves the shared checkout onto a foreign branch.
8
12
  */
9
- export declare function handleAutoSetup(projectId: string, specId: string | undefined, config?: GitConfig): Promise<ToolResult>;
13
+ export declare function handleAutoSetup(projectId: string, specId: string | undefined, config?: GitConfig, options?: GitAutoSetupOptions): Promise<ToolResult>;
10
14
  /**
11
15
  * Returns a structured worktree-start payload with commands/paths so the caller
12
16
  * knows exactly how to spin up an isolated Claude Code session.
@@ -19,10 +19,11 @@ function randomSuffix() {
19
19
  .toString(16)
20
20
  .padStart(8, '0');
21
21
  }
22
- export async function handleCreateBranch(projectId, specId, config, resolvedProjectPath) {
22
+ export async function handleCreateBranch(projectId, specId, config, resolvedProjectPath, options) {
23
23
  if (!specId) {
24
24
  return compactError('❌ Error: specId is required for create-branch action');
25
25
  }
26
+ const mutateCheckout = options?.mutateCheckout ?? true;
26
27
  const suppliedPath = resolvedProjectPath?.trim();
27
28
  const projectPath = suppliedPath && suppliedPath.length > 0 ? suppliedPath : await resolveProjectPath(projectId);
28
29
  const spec = await specStore.getSpec(projectId, specId);
@@ -40,11 +41,18 @@ export async function handleCreateBranch(projectId, specId, config, resolvedProj
40
41
  try {
41
42
  const { stdout } = await git(projectPath, ['branch', '--list', branchName]);
42
43
  if (stdout.trim().length > 0) {
43
- await git(projectPath, ['checkout', branchName]);
44
+ if (mutateCheckout) {
45
+ await git(projectPath, ['checkout', branchName]);
46
+ }
47
+ // Record the branch even when it already exists — otherwise callers keep re-entering
48
+ // this path and a background checkout is retried forever.
49
+ await specStore.updateSpec(projectId, specId, { gitBranch: branchName });
44
50
  const result = {
45
51
  action: 'create-branch',
46
52
  branchName,
47
- message: `Switched to existing branch '${branchName}'`,
53
+ message: mutateCheckout
54
+ ? `Switched to existing branch '${branchName}'`
55
+ : `Branch '${branchName}' already exists (checkout left untouched)`,
48
56
  };
49
57
  return compactResult(formatKeyValue(result));
50
58
  }
@@ -52,7 +60,14 @@ export async function handleCreateBranch(projectId, specId, config, resolvedProj
52
60
  catch {
53
61
  // branch list failed — proceed with creation
54
62
  }
55
- await git(projectPath, ['checkout', '-b', branchName]);
63
+ if (mutateCheckout) {
64
+ await git(projectPath, ['checkout', '-b', branchName]);
65
+ }
66
+ else {
67
+ // SPEC-1396: automatic caller — cut the branch from the resolved base without moving HEAD.
68
+ const base = await resolveBaseBranch(projectPath, mergeConfig(config).baseBranch);
69
+ await git(projectPath, base ? ['branch', branchName, base] : ['branch', branchName]);
70
+ }
56
71
  await specStore.updateSpec(projectId, specId, { gitBranch: branchName });
57
72
  const result = {
58
73
  action: 'create-branch',
@@ -117,14 +132,19 @@ async function hasDirtyState(projectPath) {
117
132
  * Auto-setup: detect git workflow, sync base branch, create feature branch.
118
133
  * Combines detectGitFlowType + resolveBaseBranch + fetch/pull + create-branch
119
134
  * into a single atomic operation for spec creation.
135
+ *
136
+ * SPEC-1396: `mutateCheckout: false` creates the branch ref without touching HEAD
137
+ * or the working tree. Automatic callers (outbox recovery, cascades) MUST use it —
138
+ * a background checkout silently moves the shared checkout onto a foreign branch.
120
139
  */
121
- export async function handleAutoSetup(projectId, specId, config) {
140
+ export async function handleAutoSetup(projectId, specId, config, options) {
122
141
  if (!specId) {
123
142
  return compactError('❌ Error: specId is required for auto-setup action');
124
143
  }
144
+ const mutateCheckout = options?.mutateCheckout ?? true;
125
145
  const projectPath = await resolveProjectPath(projectId);
126
146
  // Check for dirty state — abort if uncommitted changes exist
127
- if (await hasDirtyState(projectPath)) {
147
+ if (mutateCheckout && (await hasDirtyState(projectPath))) {
128
148
  return compactError('❌ Error: Working tree has uncommitted changes. Commit or stash them before auto-setup.\nSuggestion: git stash or git commit your changes first');
129
149
  }
130
150
  const spec = await specStore.getSpec(projectId, specId);
@@ -139,16 +159,39 @@ export async function handleAutoSetup(projectId, specId, config) {
139
159
  if (!baseBranch) {
140
160
  return compactError('❌ Error: No base branch found (develop/main/master). Is this a git repository?');
141
161
  }
142
- // 3. Switch to base branch and sync with remote
143
- await git(projectPath, ['checkout', baseBranch]);
162
+ // 3. Sync base branch with remote (switching only when the caller owns the checkout)
144
163
  let syncedBase = false;
145
- try {
146
- await git(projectPath, ['fetch', 'origin', baseBranch]);
147
- await git(projectPath, ['pull', '--ff-only', 'origin', baseBranch]);
148
- syncedBase = true;
164
+ let baseRef = baseBranch;
165
+ if (mutateCheckout) {
166
+ await git(projectPath, ['checkout', baseBranch]);
167
+ try {
168
+ await git(projectPath, ['fetch', 'origin', baseBranch]);
169
+ await git(projectPath, ['pull', '--ff-only', 'origin', baseBranch]);
170
+ syncedBase = true;
171
+ }
172
+ catch {
173
+ // No remote or fetch failed — continue with local base (offline-friendly)
174
+ }
149
175
  }
150
- catch {
151
- // No remote or fetch failed — continue with local base (offline-friendly)
176
+ else {
177
+ try {
178
+ // Fast-forwards the local base ref without touching HEAD or the working tree.
179
+ await git(projectPath, ['fetch', 'origin', `${baseBranch}:${baseBranch}`]);
180
+ syncedBase = true;
181
+ }
182
+ catch {
183
+ // git refuses the refspec when the base is the branch currently checked out. Fetch the
184
+ // remote-tracking ref instead and cut the feature branch from it.
185
+ try {
186
+ await git(projectPath, ['fetch', 'origin', baseBranch]);
187
+ await git(projectPath, ['rev-parse', '--verify', `origin/${baseBranch}`]);
188
+ baseRef = `origin/${baseBranch}`;
189
+ syncedBase = true;
190
+ }
191
+ catch {
192
+ // No remote or offline — use the local base as-is.
193
+ }
194
+ }
152
195
  }
153
196
  // 4. Create feature branch from the updated base
154
197
  const prefixes = mergedConfig.branchPrefix ?? DEFAULT_BRANCH_PREFIXES;
@@ -160,14 +203,19 @@ export async function handleAutoSetup(projectId, specId, config) {
160
203
  try {
161
204
  const { stdout } = await git(projectPath, ['branch', '--list', branchName]);
162
205
  if (stdout.trim().length > 0) {
163
- await git(projectPath, ['checkout', branchName]);
206
+ if (mutateCheckout) {
207
+ await git(projectPath, ['checkout', branchName]);
208
+ }
209
+ await specStore.updateSpec(projectId, specId, { gitBranch: branchName });
164
210
  const result = {
165
211
  action: 'auto-setup',
166
212
  gitFlowType,
167
213
  baseBranch,
168
214
  newBranch: branchName,
169
215
  syncedBase,
170
- message: `Switched to existing branch '${branchName}' (${gitFlowType} workflow detected)`,
216
+ message: mutateCheckout
217
+ ? `Switched to existing branch '${branchName}' (${gitFlowType} workflow detected)`
218
+ : `Branch '${branchName}' already exists (checkout left untouched)`,
171
219
  };
172
220
  return compactResult(formatKeyValue(result));
173
221
  }
@@ -175,7 +223,7 @@ export async function handleAutoSetup(projectId, specId, config) {
175
223
  catch {
176
224
  // branch list failed — proceed with creation
177
225
  }
178
- await git(projectPath, ['checkout', '-b', branchName]);
226
+ await git(projectPath, mutateCheckout ? ['checkout', '-b', branchName] : ['branch', branchName, baseRef]);
179
227
  await specStore.updateSpec(projectId, specId, { gitBranch: branchName });
180
228
  const result = {
181
229
  action: 'auto-setup',
@@ -183,7 +231,9 @@ export async function handleAutoSetup(projectId, specId, config) {
183
231
  baseBranch,
184
232
  newBranch: branchName,
185
233
  syncedBase,
186
- message: `Created branch '${branchName}' from '${baseBranch}' (${gitFlowType} workflow detected)`,
234
+ message: mutateCheckout
235
+ ? `Created branch '${branchName}' from '${baseBranch}' (${gitFlowType} workflow detected)`
236
+ : `Created branch '${branchName}' from '${baseBranch}' without switching the checkout`,
187
237
  };
188
238
  return compactResult(formatKeyValue(result));
189
239
  }
@@ -1,3 +1,4 @@
1
- import type { ToolResult, PackageHandoffInput } from '../types/index.js';
1
+ import type { ToolResult, PackageHandoffInput, HandoffPackage } from '../types/index.js';
2
+ export declare function formatHandoff(pkg: HandoffPackage): string;
2
3
  export declare function handlePackageHandoff(args: PackageHandoffInput): Promise<ToolResult>;
3
4
  //# sourceMappingURL=package-handoff.d.ts.map
@@ -8,7 +8,7 @@ import { appendTransitionEvent } from '../storage/transition-log.js';
8
8
  import { formatProjectGraphContext, queryProjectGraphSlice, } from '../engine/project-graph/index.js';
9
9
  import { analyzeMinimalImplementation, loadMinimalImplementationPolicy, } from '../engine/minimality/index.js';
10
10
  // ── Formatting helpers ───────────────────────────────────────────────────────
11
- function formatHandoff(pkg) {
11
+ export function formatHandoff(pkg) {
12
12
  const lines = [];
13
13
  lines.push(`# Implementation Handoff Package — ${pkg.specId}`);
14
14
  lines.push('');
@@ -59,6 +59,19 @@ function formatHandoff(pkg) {
59
59
  lines.push('_(None identified)_');
60
60
  }
61
61
  lines.push('');
62
+ lines.push('## Test Files');
63
+ lines.push('');
64
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- compat guard: callers may construct a HandoffPackage object predating this field
65
+ const filesToTest = pkg.filesToTest ?? [];
66
+ if (filesToTest.length > 0) {
67
+ for (const f of filesToTest) {
68
+ lines.push(`- ${f}`);
69
+ }
70
+ }
71
+ else {
72
+ lines.push('_(None identified)_');
73
+ }
74
+ lines.push('');
62
75
  lines.push('## Ownership');
63
76
  lines.push('');
64
77
  if (pkg.ownership.length > 0) {
@@ -152,7 +165,9 @@ function buildHandoffSummaryText(args) {
152
165
  if (args.pkg.contextHash) {
153
166
  lines.push(`Context Hash: ${args.pkg.contextHash}`);
154
167
  }
155
- lines.push(`Counts: ${String(args.pkg.criteria.length)} criteria, ${String(args.pkg.filesToModify.length)} files to modify, ${String(args.pkg.filesToCreate.length)} files to create, ${String(args.pkg.testPlan.length)} tests, ${String(args.pkg.risks.length)} risks.`);
168
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- compat guard: callers may construct a HandoffPackage object predating this field
169
+ const filesToTestCount = (args.pkg.filesToTest ?? []).length;
170
+ lines.push(`Counts: ${String(args.pkg.criteria.length)} criteria, ${String(args.pkg.filesToModify.length)} files to modify, ${String(args.pkg.filesToCreate.length)} files to create, ${String(filesToTestCount)} files to test, ${String(args.pkg.testPlan.length)} tests, ${String(args.pkg.risks.length)} risks.`);
156
171
  if (args.topBlockers.length > 0) {
157
172
  lines.push(`Top blockers: ${args.topBlockers.join('; ')}`);
158
173
  }
@@ -238,7 +253,8 @@ async function buildHandoffTokenWasteReport(pkg, knowledge, spec) {
238
253
  const context = analyzeContextPreflight({
239
254
  action: 'package_handoff',
240
255
  policy,
241
- candidates: [...pkg.filesToModify, ...pkg.filesToCreate].map((path) => ({
256
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- compat guard: callers may construct a HandoffPackage object predating this field
257
+ candidates: [...pkg.filesToModify, ...pkg.filesToCreate, ...(pkg.filesToTest ?? [])].map((path) => ({
242
258
  path,
243
259
  reason: 'Referenced by handoff package.',
244
260
  })),
@@ -297,7 +313,8 @@ async function buildMinimalImplementationReport(pkg, knowledge, spec, handoffTex
297
313
  specId: spec.id,
298
314
  specRisk: spec.risk,
299
315
  handoffText,
300
- files: [...pkg.filesToModify, ...pkg.filesToCreate].map((path) => ({ path, content: path })),
316
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- compat guard: callers may construct a HandoffPackage object predating this field
317
+ files: [...pkg.filesToModify, ...pkg.filesToCreate, ...(pkg.filesToTest ?? [])].map((path) => ({ path, content: path })),
301
318
  evidence,
302
319
  });
303
320
  }
@@ -421,6 +438,8 @@ export async function handlePackageHandoff(args) {
421
438
  criteria: pkgWithScore.criteria.length,
422
439
  filesToModify: pkgWithScore.filesToModify.length,
423
440
  filesToCreate: pkgWithScore.filesToCreate.length,
441
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- compat guard: callers may construct a HandoffPackage object predating this field
442
+ filesToTest: (pkgWithScore.filesToTest ?? []).length,
424
443
  ownership: pkgWithScore.ownership.length,
425
444
  testPlan: pkgWithScore.testPlan.length,
426
445
  risks: pkgWithScore.risks.length,
@@ -11,6 +11,7 @@ import { safe } from './safe-handler.js';
11
11
  import { handleCreateRule } from './create-rule.js';
12
12
  import { handleCreateSkill } from './create-skill.js';
13
13
  import { handleReconcileUniversalRules } from './reconcile-universal-rules.js';
14
+ import { registerBumpSpecVersionTool } from './bump-spec-version.js';
14
15
  import { registerPrompts } from '../prompts/index.js';
15
16
  import { OFFICIAL_SDD_TOOL_NAMES } from './tool-registry/inventory.js';
16
17
  export { OFFICIAL_SDD_TOOL_NAMES } from './tool-registry/inventory.js';
@@ -110,6 +111,7 @@ export function registerSddTools(server) {
110
111
  registerOnly(server, OFFICIAL_SDD_TOOL_SET, registerQualityComplianceGroupTools);
111
112
  registerOnly(server, OFFICIAL_SDD_TOOL_SET, registerInfraGroupTools);
112
113
  registerOnly(server, OFFICIAL_SDD_TOOL_SET, registerUniversalRulesTools);
114
+ registerOnly(server, OFFICIAL_SDD_TOOL_SET, registerBumpSpecVersionTool);
113
115
  registerPrompts(server);
114
116
  }
115
117
  //# sourceMappingURL=register-sdd-tools.js.map
@@ -54,11 +54,13 @@ export async function runImplementingSideEffects(projectId, specId, transitionPr
54
54
  let branchResult;
55
55
  try {
56
56
  const { handleCreateBranch } = await import('./git/branch-ops.js');
57
- branchResult = await withAudit(projectPath, 'update_status(implementing)', 'handleCreateBranch', () => handleCreateBranch(projectId, specId, undefined, projectPath), (r) => ({ isError: r.isError }));
57
+ branchResult = await withAudit(projectPath, 'update_status(implementing)', 'handleCreateBranch', () => handleCreateBranch(projectId, specId, undefined, projectPath, { mutateCheckout: false }), (r) => ({ isError: r.isError }));
58
58
  }
59
59
  catch {
60
60
  const { handleCreateBranch } = await import('./git/branch-ops.js');
61
- branchResult = await handleCreateBranch(projectId, specId, undefined, projectPath);
61
+ branchResult = await handleCreateBranch(projectId, specId, undefined, projectPath, {
62
+ mutateCheckout: false,
63
+ });
62
64
  }
63
65
  if (!branchResult.isError) {
64
66
  try {
@@ -144,6 +144,10 @@ export interface GitSetupResult {
144
144
  data: Record<string, unknown>;
145
145
  branch: string;
146
146
  }
147
+ /** SPEC-1396: automatic callers set `mutateCheckout: false` so the shared checkout never moves. */
148
+ export interface GitAutoSetupOptions {
149
+ mutateCheckout?: boolean;
150
+ }
147
151
  export interface AutoSetupResult {
148
152
  action: 'auto-setup';
149
153
  gitFlowType: GitFlowType;
@@ -12,6 +12,8 @@ export interface OutboxFenceRecord {
12
12
  readonly state: 'leased' | 'failed' | 'dead-letter' | 'delivered';
13
13
  readonly attempts?: number;
14
14
  readonly lastError?: string;
15
+ /** Durable retry deadline (ISO timestamp). Only set for `failed` fences; optional for schemaVersion 1 compatibility. */
16
+ readonly nextAttemptAt?: string;
15
17
  }
16
18
  export declare const SPEC_CREATED_POST_COMMIT_TASKS: readonly ['git-setup', 'analysis', 'quality-score', 'duplicate-detection', 'complexity-advice', 'prior-decisions', 'suggestions', 'challenge-readiness'];
17
19
  export type SpecCreatedPostCommitTask = (typeof SPEC_CREATED_POST_COMMIT_TASKS)[number];
@@ -32,6 +32,7 @@ export interface HandoffPackage {
32
32
  criteria: string[];
33
33
  filesToModify: string[];
34
34
  filesToCreate: string[];
35
+ filesToTest: string[];
35
36
  ownership: string[];
36
37
  testPlan: string[];
37
38
  risks: string[];
@@ -47,5 +47,14 @@ export interface RuntimePolicy {
47
47
  maximumRememberedTransitions: number;
48
48
  minimumHeartbeatMs: number;
49
49
  };
50
+ outbox: {
51
+ sliceRecordBudget: number;
52
+ sliceTimeBudgetMs: number;
53
+ backoffBaseMs: number;
54
+ backoffCapMs: number;
55
+ maxAttempts: number;
56
+ diagnosticMaxLength: number;
57
+ continuationDelayMs: number;
58
+ };
50
59
  }
51
60
  //# sourceMappingURL=runtime-policy.d.ts.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@planu/cli",
3
- "version": "5.3.1",
3
+ "version": "5.3.3",
4
4
  "description": "Planu — MCP Server for Spec Driven Development with native Rust acceleration for hot paths. Cross-platform (Linux/macOS/Windows, x64/arm64, glibc/musl).",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -35,14 +35,14 @@
35
35
  "packageName": "@planu/core"
36
36
  },
37
37
  "optionalDependencies": {
38
- "@planu/core-darwin-arm64": "5.3.1",
39
- "@planu/core-darwin-x64": "5.3.1",
40
- "@planu/core-linux-arm64-gnu": "5.3.1",
41
- "@planu/core-linux-arm64-musl": "5.3.1",
42
- "@planu/core-linux-x64-gnu": "5.3.1",
43
- "@planu/core-linux-x64-musl": "5.3.1",
44
- "@planu/core-win32-arm64-msvc": "5.3.1",
45
- "@planu/core-win32-x64-msvc": "5.3.1"
38
+ "@planu/core-darwin-arm64": "5.3.3",
39
+ "@planu/core-darwin-x64": "5.3.3",
40
+ "@planu/core-linux-arm64-gnu": "5.3.3",
41
+ "@planu/core-linux-arm64-musl": "5.3.3",
42
+ "@planu/core-linux-x64-gnu": "5.3.3",
43
+ "@planu/core-linux-x64-musl": "5.3.3",
44
+ "@planu/core-win32-arm64-msvc": "5.3.3",
45
+ "@planu/core-win32-x64-msvc": "5.3.3"
46
46
  },
47
47
  "engines": {
48
48
  "node": ">=24.0.0"
package/planu-native.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "dev.planu.native",
3
3
  "displayName": "Planu Native Lightweight Surface",
4
- "version": "5.3.1",
4
+ "version": "5.3.3",
5
5
  "packageName": "@planu/cli",
6
6
  "modes": {
7
7
  "lightweight": {
package/planu-plugin.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "dev.planu.cli",
3
3
  "displayName": "Planu — Spec Driven Development",
4
4
  "description": "Manage software specs, estimations, and autonomous SDD workflows. Language-agnostic MCP server for Claude Code.",
5
- "version": "5.3.1",
5
+ "version": "5.3.3",
6
6
  "icon": "assets/plugin/icon.svg",
7
7
  "command": ["npx", "@planu/cli@latest"],
8
8
  "packageName": "@planu/cli",
@@ -35,7 +35,8 @@
35
35
  "triage_feedback",
36
36
  "resolve_feedback",
37
37
  "sync_feedback",
38
- "feedback_status"
38
+ "feedback_status",
39
+ "bump_spec_version"
39
40
  ],
40
41
  "resources": ["planu://specs/list", "planu://specs/{id}", "planu://project/status", "planu://roadmap"],
41
42
  "prompts": ["create-spec-from-idea", "review-spec-readiness", "generate-implementation-plan"],