@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.
- package/CHANGELOG.md +32 -0
- package/README.md +1 -1
- package/dist/config/official-sdd-tools.d.ts +1 -1
- package/dist/config/official-sdd-tools.js +1 -0
- package/dist/config/registries/hosts/codex.json +2 -1
- package/dist/config/runtime-policy.json +9 -0
- package/dist/engine/autopilot/complete-loop.js +4 -1
- package/dist/engine/execution/outbox-worker.d.ts +8 -0
- package/dist/engine/execution/outbox-worker.js +102 -31
- package/dist/engine/handoff-packager.d.ts +3 -0
- package/dist/engine/handoff-packager.js +18 -3
- package/dist/engine/planu-core.darwin-arm64.node.manifest.json +7 -7
- package/dist/engine/planu-core.darwin-arm64.node.sbom.json +4 -4
- package/dist/engine/planu-core.darwin-x64.node.manifest.json +7 -7
- package/dist/engine/planu-core.darwin-x64.node.sbom.json +4 -4
- package/dist/engine/planu-core.linux-arm64-gnu.node.manifest.json +7 -7
- package/dist/engine/planu-core.linux-arm64-gnu.node.sbom.json +4 -4
- package/dist/engine/planu-core.linux-arm64-musl.node.manifest.json +7 -7
- package/dist/engine/planu-core.linux-arm64-musl.node.sbom.json +4 -4
- package/dist/engine/planu-core.linux-x64-gnu.node.manifest.json +7 -7
- package/dist/engine/planu-core.linux-x64-gnu.node.sbom.json +4 -4
- package/dist/engine/planu-core.linux-x64-musl.node.manifest.json +7 -7
- package/dist/engine/planu-core.linux-x64-musl.node.sbom.json +4 -4
- package/dist/engine/planu-core.win32-arm64-msvc.node.manifest.json +7 -7
- package/dist/engine/planu-core.win32-arm64-msvc.node.sbom.json +4 -4
- package/dist/engine/planu-core.win32-x64-msvc.node.manifest.json +7 -7
- package/dist/engine/planu-core.win32-x64-msvc.node.sbom.json +4 -4
- package/dist/engine/runtime-policy.js +14 -0
- package/dist/index.js +3 -1
- package/dist/storage/runtime-db.d.ts +23 -1
- package/dist/storage/runtime-db.js +79 -9
- package/dist/tools/create-spec/post-creation.js +7 -2
- package/dist/tools/create-spec/spec-created-outbox-consumer.d.ts +2 -0
- package/dist/tools/create-spec/spec-created-outbox-consumer.js +94 -6
- package/dist/tools/create-spec-helpers.d.ts +2 -2
- package/dist/tools/create-spec-helpers.js +2 -2
- package/dist/tools/git/branch-ops.d.ts +7 -3
- package/dist/tools/git/branch-ops.js +68 -18
- package/dist/tools/package-handoff.d.ts +2 -1
- package/dist/tools/package-handoff.js +23 -4
- package/dist/tools/register-sdd-tools.js +2 -0
- package/dist/tools/update-status-actions.js +4 -2
- package/dist/types/git.d.ts +4 -0
- package/dist/types/outbox-worker.d.ts +2 -0
- package/dist/types/readiness.d.ts +1 -0
- package/dist/types/runtime-policy.d.ts +9 -0
- package/package.json +9 -9
- package/planu-native.json +1 -1
- 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
|
-
|
|
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:
|
|
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
|
-
|
|
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.
|
|
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
|
-
|
|
146
|
-
|
|
147
|
-
await git(projectPath, ['
|
|
148
|
-
|
|
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
|
-
|
|
151
|
-
|
|
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
|
-
|
|
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:
|
|
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:
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 {
|
package/dist/types/git.d.ts
CHANGED
|
@@ -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];
|
|
@@ -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.
|
|
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.
|
|
39
|
-
"@planu/core-darwin-x64": "5.3.
|
|
40
|
-
"@planu/core-linux-arm64-gnu": "5.3.
|
|
41
|
-
"@planu/core-linux-arm64-musl": "5.3.
|
|
42
|
-
"@planu/core-linux-x64-gnu": "5.3.
|
|
43
|
-
"@planu/core-linux-x64-musl": "5.3.
|
|
44
|
-
"@planu/core-win32-arm64-msvc": "5.3.
|
|
45
|
-
"@planu/core-win32-x64-msvc": "5.3.
|
|
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
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.
|
|
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"],
|