@planu/cli 4.4.0 → 4.4.2
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 +17 -1
- package/dist/engine/evidence-gates/artifact-reader.js +6 -27
- package/dist/engine/spec-migrator/planu-canonical-policy.d.ts +1 -0
- package/dist/engine/spec-migrator/planu-canonical-policy.js +7 -0
- package/dist/engine/spec-migrator/strict-planu-cleanup.d.ts +2 -2
- package/dist/engine/spec-migrator/strict-planu-cleanup.js +35 -20
- package/dist/engine/universal-rules/rules/planu-workflow.js +1 -1
- package/dist/tools/update-status/evidence-gate.js +2 -2
- package/dist/tools/validate.js +5 -3
- package/dist/types/spec-format.d.ts +5 -0
- package/package.json +11 -11
- package/planu-native.json +8 -29
- package/planu-plugin.json +7 -35
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,19 @@
|
|
|
1
|
+
## [4.4.2] - 2026-06-05
|
|
2
|
+
|
|
3
|
+
### Bug Fixes
|
|
4
|
+
- fix: keep spec folders spec.md-only and store evidence externally
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
## [4.4.1] - 2026-06-04
|
|
8
|
+
|
|
9
|
+
### Bug Fixes
|
|
10
|
+
- fix: make validate spec-scoped and non-mutating
|
|
11
|
+
|
|
12
|
+
### Chores
|
|
13
|
+
- chore(deps): sync lockfile
|
|
14
|
+
- chore(deps): update patch and minor dependencies
|
|
15
|
+
|
|
16
|
+
|
|
1
17
|
## [4.4.0] - 2026-06-03
|
|
2
18
|
|
|
3
19
|
### Features
|
|
@@ -4019,4 +4035,4 @@ Format: [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) · Versioning:
|
|
|
4019
4035
|
- Mermaid diagram generation (architecture, sequence, state machine, ER, data flow)
|
|
4020
4036
|
- Multi-language i18n (EN/ES/PT) for generated specs
|
|
4021
4037
|
- Clean Architecture (hexagonal) — engine, tools, storage, types layers
|
|
4022
|
-
- 10,857 tests with ≥95% coverage
|
|
4038
|
+
- 10,857 tests with ≥95% coverage
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { readFile } from 'node:fs/promises';
|
|
2
|
-
import {
|
|
2
|
+
import { join } from 'node:path';
|
|
3
3
|
import { z } from 'zod';
|
|
4
4
|
import { projectDataDir } from '../../storage/base-store.js';
|
|
5
5
|
const DiscoverySchema = z.object({
|
|
@@ -49,15 +49,6 @@ const ContractValidationSchema = z.object({
|
|
|
49
49
|
reportPath: z.string().optional(),
|
|
50
50
|
summary: z.string().optional(),
|
|
51
51
|
});
|
|
52
|
-
function resolveSpecPath(spec, projectPath) {
|
|
53
|
-
if (isAbsolute(spec.specPath) || !projectPath) {
|
|
54
|
-
return spec.specPath;
|
|
55
|
-
}
|
|
56
|
-
return join(projectPath, spec.specPath);
|
|
57
|
-
}
|
|
58
|
-
function specEvidencePath(spec, filename, projectPath) {
|
|
59
|
-
return join(dirname(resolveSpecPath(spec, projectPath)), 'evidence', filename);
|
|
60
|
-
}
|
|
61
52
|
function handoffEvidencePath(projectId, specId, filename) {
|
|
62
53
|
return join(projectDataDir(projectId), 'handoffs', specId, filename);
|
|
63
54
|
}
|
|
@@ -81,7 +72,7 @@ async function readUnknown(paths) {
|
|
|
81
72
|
}
|
|
82
73
|
async function readOptional(args) {
|
|
83
74
|
try {
|
|
84
|
-
const found = await readUnknown(args.paths);
|
|
75
|
+
const found = await readUnknown(args.paths.filter((path) => Boolean(path)));
|
|
85
76
|
if (!found) {
|
|
86
77
|
return undefined;
|
|
87
78
|
}
|
|
@@ -103,28 +94,19 @@ export async function readEvidenceArtifacts(args) {
|
|
|
103
94
|
label: 'Discovery evidence',
|
|
104
95
|
invalidArtifacts,
|
|
105
96
|
schema: DiscoverySchema,
|
|
106
|
-
paths: [
|
|
107
|
-
specEvidencePath(args.spec, 'discovery.json', args.projectPath),
|
|
108
|
-
handoffEvidencePath(args.projectId, args.specId, 'discovery.json'),
|
|
109
|
-
],
|
|
97
|
+
paths: [handoffEvidencePath(args.projectId, args.specId, 'discovery.json')],
|
|
110
98
|
});
|
|
111
99
|
const taskPlan = await readOptional({
|
|
112
100
|
label: 'Task plan evidence',
|
|
113
101
|
invalidArtifacts,
|
|
114
102
|
schema: TaskPlanSchema,
|
|
115
|
-
paths: [
|
|
116
|
-
specEvidencePath(args.spec, 'task-plan.json', args.projectPath),
|
|
117
|
-
handoffEvidencePath(args.projectId, args.specId, 'task-plan.json'),
|
|
118
|
-
],
|
|
103
|
+
paths: [handoffEvidencePath(args.projectId, args.specId, 'task-plan.json')],
|
|
119
104
|
});
|
|
120
105
|
const traceabilityMatrix = await readOptional({
|
|
121
106
|
label: 'Traceability matrix evidence',
|
|
122
107
|
invalidArtifacts,
|
|
123
108
|
schema: TraceabilityMatrixSchema,
|
|
124
|
-
paths: [
|
|
125
|
-
specEvidencePath(args.spec, 'traceability-matrix.json', args.projectPath),
|
|
126
|
-
handoffEvidencePath(args.projectId, args.specId, 'traceability-matrix.json'),
|
|
127
|
-
],
|
|
109
|
+
paths: [handoffEvidencePath(args.projectId, args.specId, 'traceability-matrix.json')],
|
|
128
110
|
});
|
|
129
111
|
const contractValidations = [];
|
|
130
112
|
for (const filename of [
|
|
@@ -138,10 +120,7 @@ export async function readEvidenceArtifacts(args) {
|
|
|
138
120
|
label: filename,
|
|
139
121
|
invalidArtifacts,
|
|
140
122
|
schema: ContractValidationSchema,
|
|
141
|
-
paths: [
|
|
142
|
-
specEvidencePath(args.spec, filename, args.projectPath),
|
|
143
|
-
handoffEvidencePath(args.projectId, args.specId, filename),
|
|
144
|
-
],
|
|
123
|
+
paths: [handoffEvidencePath(args.projectId, args.specId, filename)],
|
|
145
124
|
});
|
|
146
125
|
if (evidence) {
|
|
147
126
|
contractValidations.push(evidence);
|
|
@@ -3,6 +3,7 @@ export declare const PLANU_CANONICAL_POLICY: PlanuCanonicalPathPolicy;
|
|
|
3
3
|
export declare function isCanonicalPlanuRootFile(name: string): boolean;
|
|
4
4
|
export declare function isCanonicalPlanuRootDir(name: string): boolean;
|
|
5
5
|
export declare function isCanonicalSpecFile(name: string): boolean;
|
|
6
|
+
export declare function isCanonicalSpecDir(name: string): boolean;
|
|
6
7
|
export declare function mustMergeBeforeDeleteSpecFile(name: string): boolean;
|
|
7
8
|
export declare function isCanonicalReleaseFile(relativeToPlanu: string): boolean;
|
|
8
9
|
export declare function canonicalContractText(): string;
|
|
@@ -4,6 +4,7 @@ export const PLANU_CANONICAL_POLICY = {
|
|
|
4
4
|
canonicalRootFiles: ['conventions.json', 'context.md', 'session-context.md', 'session.json'],
|
|
5
5
|
canonicalRootDirs: ['releases', 'specs'],
|
|
6
6
|
canonicalSpecFiles: ['spec.md'],
|
|
7
|
+
canonicalSpecDirs: [],
|
|
7
8
|
forbiddenHostAssetRootDirs: ['agents', 'skills', 'rules', 'hooks'],
|
|
8
9
|
generatedRuntimePatterns: [
|
|
9
10
|
'planu/index.html',
|
|
@@ -38,6 +39,7 @@ export const PLANU_CANONICAL_POLICY = {
|
|
|
38
39
|
const ROOT_FILE_SET = new Set(PLANU_CANONICAL_POLICY.canonicalRootFiles);
|
|
39
40
|
const ROOT_DIR_SET = new Set(PLANU_CANONICAL_POLICY.canonicalRootDirs);
|
|
40
41
|
const SPEC_FILE_SET = new Set(PLANU_CANONICAL_POLICY.canonicalSpecFiles);
|
|
42
|
+
const SPEC_DIR_SET = new Set(PLANU_CANONICAL_POLICY.canonicalSpecDirs);
|
|
41
43
|
const LEGACY_MERGE_SET = new Set(PLANU_CANONICAL_POLICY.legacyMergeBeforeDeleteFiles);
|
|
42
44
|
export function isCanonicalPlanuRootFile(name) {
|
|
43
45
|
return ROOT_FILE_SET.has(name);
|
|
@@ -48,6 +50,9 @@ export function isCanonicalPlanuRootDir(name) {
|
|
|
48
50
|
export function isCanonicalSpecFile(name) {
|
|
49
51
|
return SPEC_FILE_SET.has(name);
|
|
50
52
|
}
|
|
53
|
+
export function isCanonicalSpecDir(name) {
|
|
54
|
+
return SPEC_DIR_SET.has(name);
|
|
55
|
+
}
|
|
51
56
|
export function mustMergeBeforeDeleteSpecFile(name) {
|
|
52
57
|
return LEGACY_MERGE_SET.has(name);
|
|
53
58
|
}
|
|
@@ -67,6 +72,8 @@ export function canonicalContractText() {
|
|
|
67
72
|
' SPEC-XXX-slug/',
|
|
68
73
|
' spec.md',
|
|
69
74
|
'',
|
|
75
|
+
'Evidence artifacts are Planu runtime data and are stored outside planu/specs/.',
|
|
76
|
+
'',
|
|
70
77
|
'Host adapters are written outside planu/:',
|
|
71
78
|
' Claude Code: .claude/agents, .claude/skills, .claude/rules',
|
|
72
79
|
' Codex: AGENTS.md, .agents/skills, .codex/agents',
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import type { StrictPlanuCleanupResult, StrictPlanuValidationResult } from '../../types/index.js';
|
|
1
|
+
import type { StrictPlanuCleanupResult, StrictPlanuValidationOptions, StrictPlanuValidationResult } from '../../types/index.js';
|
|
2
2
|
import { PLANU_CANONICAL_POLICY } from './planu-canonical-policy.js';
|
|
3
3
|
export declare function runStrictPlanuCleanup(projectPath: string): Promise<StrictPlanuCleanupResult>;
|
|
4
|
-
export declare function validateStrictPlanuLayout(projectPath: string): Promise<StrictPlanuValidationResult>;
|
|
4
|
+
export declare function validateStrictPlanuLayout(projectPath: string, options?: StrictPlanuValidationOptions): Promise<StrictPlanuValidationResult>;
|
|
5
5
|
export { PLANU_CANONICAL_POLICY };
|
|
6
6
|
//# sourceMappingURL=strict-planu-cleanup.d.ts.map
|
|
@@ -4,10 +4,10 @@ import { readdir, readFile, rm, stat } from 'node:fs/promises';
|
|
|
4
4
|
import { existsSync } from 'node:fs';
|
|
5
5
|
import { execFile } from 'node:child_process';
|
|
6
6
|
import { promisify } from 'node:util';
|
|
7
|
-
import { join, relative } from 'node:path';
|
|
7
|
+
import { dirname, isAbsolute, join, relative } from 'node:path';
|
|
8
8
|
import { atomicWriteFile } from '../safety/atomic-write-file.js';
|
|
9
9
|
import { safeUnlink } from './git-aware-fs.js';
|
|
10
|
-
import { PLANU_CANONICAL_POLICY, canonicalContractText, isCanonicalPlanuRootDir, isCanonicalPlanuRootFile, isCanonicalReleaseFile, isCanonicalSpecFile, mustMergeBeforeDeleteSpecFile, } from './planu-canonical-policy.js';
|
|
10
|
+
import { PLANU_CANONICAL_POLICY, canonicalContractText, isCanonicalPlanuRootDir, isCanonicalPlanuRootFile, isCanonicalReleaseFile, isCanonicalSpecDir, isCanonicalSpecFile, mustMergeBeforeDeleteSpecFile, } from './planu-canonical-policy.js';
|
|
11
11
|
const execFileAsync = promisify(execFile);
|
|
12
12
|
async function pathIsDirectory(path) {
|
|
13
13
|
try {
|
|
@@ -125,7 +125,9 @@ async function walkSpecDirectory(projectPath, specDir, result) {
|
|
|
125
125
|
}
|
|
126
126
|
continue;
|
|
127
127
|
}
|
|
128
|
-
|
|
128
|
+
const isDir = await pathIsDirectory(full);
|
|
129
|
+
if (entry === 'reference' ||
|
|
130
|
+
(isDir ? !isCanonicalSpecDir(entry) : !isCanonicalSpecFile(entry))) {
|
|
129
131
|
await removePath(projectPath, full);
|
|
130
132
|
result.deleted.push(relative(projectPath, full));
|
|
131
133
|
}
|
|
@@ -173,33 +175,46 @@ export async function runStrictPlanuCleanup(projectPath) {
|
|
|
173
175
|
result.gitignoreUpdated = await updateGitignore(projectPath);
|
|
174
176
|
return result;
|
|
175
177
|
}
|
|
176
|
-
|
|
178
|
+
function resolveSpecDirsForValidation(projectPath, specPath) {
|
|
179
|
+
if (!specPath?.trim()) {
|
|
180
|
+
return null;
|
|
181
|
+
}
|
|
182
|
+
const resolved = isAbsolute(specPath) ? specPath : join(projectPath, specPath);
|
|
183
|
+
return [dirname(resolved)];
|
|
184
|
+
}
|
|
185
|
+
export async function validateStrictPlanuLayout(projectPath, options = {}) {
|
|
177
186
|
const offenders = [];
|
|
178
187
|
const planuDir = join(projectPath, 'planu');
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
const
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
(
|
|
185
|
-
|
|
188
|
+
if (options.includeRoot !== false) {
|
|
189
|
+
const entries = await readdir(planuDir).catch(() => []);
|
|
190
|
+
for (const entry of entries) {
|
|
191
|
+
const full = join(planuDir, entry);
|
|
192
|
+
const isDir = await pathIsDirectory(full);
|
|
193
|
+
if ((isDir && !isCanonicalPlanuRootDir(entry)) ||
|
|
194
|
+
(!isDir && !isCanonicalPlanuRootFile(entry))) {
|
|
195
|
+
offenders.push(relative(projectPath, full));
|
|
196
|
+
}
|
|
186
197
|
}
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
198
|
+
for (const entry of await readdir(join(planuDir, 'releases')).catch(() => [])) {
|
|
199
|
+
const rel = `releases/${entry}`;
|
|
200
|
+
if (!isCanonicalReleaseFile(rel)) {
|
|
201
|
+
offenders.push(`planu/${rel}`);
|
|
202
|
+
}
|
|
192
203
|
}
|
|
193
204
|
}
|
|
194
|
-
|
|
195
|
-
|
|
205
|
+
const scopedSpecDirs = resolveSpecDirsForValidation(projectPath, options.specPath) ??
|
|
206
|
+
(await readdir(join(planuDir, 'specs')).catch(() => [])).map((specDir) => join(planuDir, 'specs', specDir));
|
|
207
|
+
for (const full of scopedSpecDirs) {
|
|
208
|
+
const specDir = relative(join(planuDir, 'specs'), full);
|
|
196
209
|
if (!(await pathIsDirectory(full)) || specDir === 'data') {
|
|
197
210
|
offenders.push(relative(projectPath, full));
|
|
198
211
|
continue;
|
|
199
212
|
}
|
|
200
213
|
for (const entry of await readdir(full).catch(() => [])) {
|
|
201
|
-
|
|
202
|
-
|
|
214
|
+
const entryPath = join(full, entry);
|
|
215
|
+
const isDir = await pathIsDirectory(entryPath);
|
|
216
|
+
if (isDir ? !isCanonicalSpecDir(entry) : !isCanonicalSpecFile(entry)) {
|
|
217
|
+
offenders.push(relative(projectPath, entryPath));
|
|
203
218
|
}
|
|
204
219
|
}
|
|
205
220
|
}
|
|
@@ -28,7 +28,7 @@ For non-trivial specs, Planu blocks lifecycle transitions unless evidence is pre
|
|
|
28
28
|
| done | Traceability matrix covering every acceptance criterion |
|
|
29
29
|
| done for API/UI/event/MCP work | Passing contract validation evidence |
|
|
30
30
|
|
|
31
|
-
Evidence
|
|
31
|
+
Evidence lives in the external Planu handoff store, not under \`planu/specs/<spec>/\`. Spec folders remain \`spec.md\`-only. Trivial specs may use lightweight evidence, but \`done\` still needs at least one traceability row.
|
|
32
32
|
|
|
33
33
|
## When to use \`facilitate\`
|
|
34
34
|
|
|
@@ -80,7 +80,7 @@ function evidenceGateError(args) {
|
|
|
80
80
|
transition: args.transition,
|
|
81
81
|
issues: args.issues,
|
|
82
82
|
requiredContractKinds: args.requiredContractKinds,
|
|
83
|
-
fixHint: 'Add the missing evidence artifact
|
|
83
|
+
fixHint: 'Add the missing evidence artifact to the external Planu project data handoff store, then retry the transition. Do not create JSON files under planu/specs/<spec>/.',
|
|
84
84
|
}, null, 2),
|
|
85
85
|
},
|
|
86
86
|
],
|
|
@@ -95,7 +95,7 @@ function evidenceGateError(args) {
|
|
|
95
95
|
issues: args.issues,
|
|
96
96
|
requiredContractKinds: args.requiredContractKinds,
|
|
97
97
|
},
|
|
98
|
-
fixHint: 'Add discovery.json, task-plan.json, traceability-matrix.json, and contract-validation-*.json as required for this transition.',
|
|
98
|
+
fixHint: 'Add discovery.json, task-plan.json, traceability-matrix.json, and contract-validation-*.json to the external Planu handoff store as required for this transition. Spec folders remain spec.md-only.',
|
|
99
99
|
},
|
|
100
100
|
};
|
|
101
101
|
}
|
package/dist/tools/validate.js
CHANGED
|
@@ -73,9 +73,11 @@ export async function handleValidate(args, server) {
|
|
|
73
73
|
const projectPath = knowledge.projectPath;
|
|
74
74
|
// SPEC-1017: fail closed when planu/ contains non-canonical artifacts.
|
|
75
75
|
try {
|
|
76
|
-
const {
|
|
77
|
-
await
|
|
78
|
-
|
|
76
|
+
const { validateStrictPlanuLayout } = await import('../engine/spec-migrator/index.js');
|
|
77
|
+
const layout = await validateStrictPlanuLayout(projectPath, {
|
|
78
|
+
specPath: spec.specPath,
|
|
79
|
+
includeRoot: false,
|
|
80
|
+
});
|
|
79
81
|
if (!layout.ok) {
|
|
80
82
|
return {
|
|
81
83
|
content: [
|
|
@@ -54,6 +54,7 @@ export interface PlanuCanonicalPathPolicy {
|
|
|
54
54
|
readonly canonicalRootFiles: readonly string[];
|
|
55
55
|
readonly canonicalRootDirs: readonly string[];
|
|
56
56
|
readonly canonicalSpecFiles: readonly string[];
|
|
57
|
+
readonly canonicalSpecDirs: readonly string[];
|
|
57
58
|
readonly forbiddenHostAssetRootDirs: readonly string[];
|
|
58
59
|
readonly generatedRuntimePatterns: readonly string[];
|
|
59
60
|
readonly legacyMergeBeforeDeleteFiles: readonly string[];
|
|
@@ -68,6 +69,10 @@ export interface StrictPlanuValidationResult {
|
|
|
68
69
|
offenders: string[];
|
|
69
70
|
contract: string;
|
|
70
71
|
}
|
|
72
|
+
export interface StrictPlanuValidationOptions {
|
|
73
|
+
specPath?: string;
|
|
74
|
+
includeRoot?: boolean;
|
|
75
|
+
}
|
|
71
76
|
export interface UpdateStatusBatchInput {
|
|
72
77
|
specIds: string[];
|
|
73
78
|
status: SpecStatus;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@planu/cli",
|
|
3
|
-
"version": "4.4.
|
|
3
|
+
"version": "4.4.2",
|
|
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",
|
|
@@ -34,14 +34,14 @@
|
|
|
34
34
|
"packageName": "@planu/core"
|
|
35
35
|
},
|
|
36
36
|
"optionalDependencies": {
|
|
37
|
-
"@planu/core-darwin-arm64": "4.4.
|
|
38
|
-
"@planu/core-darwin-x64": "4.4.
|
|
39
|
-
"@planu/core-linux-arm64-gnu": "4.4.
|
|
40
|
-
"@planu/core-linux-arm64-musl": "4.4.
|
|
41
|
-
"@planu/core-linux-x64-gnu": "4.4.
|
|
42
|
-
"@planu/core-linux-x64-musl": "4.4.
|
|
43
|
-
"@planu/core-win32-arm64-msvc": "4.4.
|
|
44
|
-
"@planu/core-win32-x64-msvc": "4.4.
|
|
37
|
+
"@planu/core-darwin-arm64": "4.4.2",
|
|
38
|
+
"@planu/core-darwin-x64": "4.4.2",
|
|
39
|
+
"@planu/core-linux-arm64-gnu": "4.4.2",
|
|
40
|
+
"@planu/core-linux-arm64-musl": "4.4.2",
|
|
41
|
+
"@planu/core-linux-x64-gnu": "4.4.2",
|
|
42
|
+
"@planu/core-linux-x64-musl": "4.4.2",
|
|
43
|
+
"@planu/core-win32-arm64-msvc": "4.4.2",
|
|
44
|
+
"@planu/core-win32-x64-msvc": "4.4.2"
|
|
45
45
|
},
|
|
46
46
|
"engines": {
|
|
47
47
|
"node": ">=24.0.0"
|
|
@@ -185,12 +185,12 @@
|
|
|
185
185
|
"@types/node": "^25.9.1",
|
|
186
186
|
"@vitejs/plugin-vue": "^6.0.7",
|
|
187
187
|
"@vitest/coverage-v8": "^4.1.8",
|
|
188
|
-
"@vue/test-utils": "^2.4.
|
|
188
|
+
"@vue/test-utils": "^2.4.11",
|
|
189
189
|
"eslint": "^10.4.1",
|
|
190
190
|
"eslint-config-prettier": "^10.1.8",
|
|
191
191
|
"eslint-import-resolver-typescript": "^4.4.5",
|
|
192
192
|
"eslint-plugin-import": "^2.32.0",
|
|
193
|
-
"happy-dom": "^20.
|
|
193
|
+
"happy-dom": "^20.10.1",
|
|
194
194
|
"husky": "^9.1.7",
|
|
195
195
|
"javascript-obfuscator": "^5.4.3",
|
|
196
196
|
"knip": "^6.15.0",
|
package/planu-native.json
CHANGED
|
@@ -1,26 +1,20 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dev.planu.native",
|
|
3
3
|
"displayName": "Planu Native Lightweight Surface",
|
|
4
|
-
"version": "4.4.
|
|
4
|
+
"version": "4.4.2",
|
|
5
5
|
"packageName": "@planu/cli",
|
|
6
6
|
"modes": {
|
|
7
7
|
"lightweight": {
|
|
8
8
|
"requiresMcp": false,
|
|
9
9
|
"requiresDaemon": false,
|
|
10
|
-
"hosts": [
|
|
11
|
-
"codex",
|
|
12
|
-
"claude-code"
|
|
13
|
-
],
|
|
10
|
+
"hosts": ["codex", "claude-code"],
|
|
14
11
|
"commands": [
|
|
15
12
|
{
|
|
16
13
|
"id": "planu.status",
|
|
17
14
|
"title": "Project status",
|
|
18
15
|
"description": "Show the compact Planu project snapshot without loading the MCP tool graph.",
|
|
19
16
|
"invocation": "planu status",
|
|
20
|
-
"hosts": [
|
|
21
|
-
"codex",
|
|
22
|
-
"claude-code"
|
|
23
|
-
],
|
|
17
|
+
"hosts": ["codex", "claude-code"],
|
|
24
18
|
"requiresMcp": false,
|
|
25
19
|
"requiresDaemon": false,
|
|
26
20
|
"mapsTo": "handlePlanStatus"
|
|
@@ -30,10 +24,7 @@
|
|
|
30
24
|
"title": "Create spec",
|
|
31
25
|
"description": "Create a new spec through the CLI-backed SDD contract.",
|
|
32
26
|
"invocation": "planu spec create \"<title>\"",
|
|
33
|
-
"hosts": [
|
|
34
|
-
"codex",
|
|
35
|
-
"claude-code"
|
|
36
|
-
],
|
|
27
|
+
"hosts": ["codex", "claude-code"],
|
|
37
28
|
"requiresMcp": false,
|
|
38
29
|
"requiresDaemon": false,
|
|
39
30
|
"mapsTo": "handleCreateSpec"
|
|
@@ -43,10 +34,7 @@
|
|
|
43
34
|
"title": "List specs",
|
|
44
35
|
"description": "List specs in the current project with optional status/type filters.",
|
|
45
36
|
"invocation": "planu spec list",
|
|
46
|
-
"hosts": [
|
|
47
|
-
"codex",
|
|
48
|
-
"claude-code"
|
|
49
|
-
],
|
|
37
|
+
"hosts": ["codex", "claude-code"],
|
|
50
38
|
"requiresMcp": false,
|
|
51
39
|
"requiresDaemon": false,
|
|
52
40
|
"mapsTo": "handleListSpecs"
|
|
@@ -56,10 +44,7 @@
|
|
|
56
44
|
"title": "Validate spec",
|
|
57
45
|
"description": "Validate a spec against the current codebase from the native CLI surface.",
|
|
58
46
|
"invocation": "planu spec validate SPEC-001",
|
|
59
|
-
"hosts": [
|
|
60
|
-
"codex",
|
|
61
|
-
"claude-code"
|
|
62
|
-
],
|
|
47
|
+
"hosts": ["codex", "claude-code"],
|
|
63
48
|
"requiresMcp": false,
|
|
64
49
|
"requiresDaemon": false,
|
|
65
50
|
"mapsTo": "handleValidate"
|
|
@@ -69,10 +54,7 @@
|
|
|
69
54
|
"title": "Audit technical debt",
|
|
70
55
|
"description": "Run the read-only project audit path for lightweight debt checks.",
|
|
71
56
|
"invocation": "planu audit debt",
|
|
72
|
-
"hosts": [
|
|
73
|
-
"codex",
|
|
74
|
-
"claude-code"
|
|
75
|
-
],
|
|
57
|
+
"hosts": ["codex", "claude-code"],
|
|
76
58
|
"requiresMcp": false,
|
|
77
59
|
"requiresDaemon": false,
|
|
78
60
|
"mapsTo": "handleAudit"
|
|
@@ -82,10 +64,7 @@
|
|
|
82
64
|
"title": "Check release readiness",
|
|
83
65
|
"description": "Check local branch cleanliness and main/develop/release sync readiness.",
|
|
84
66
|
"invocation": "planu release check",
|
|
85
|
-
"hosts": [
|
|
86
|
-
"codex",
|
|
87
|
-
"claude-code"
|
|
88
|
-
],
|
|
67
|
+
"hosts": ["codex", "claude-code"],
|
|
89
68
|
"requiresMcp": false,
|
|
90
69
|
"requiresDaemon": false,
|
|
91
70
|
"mapsTo": "releaseCommand"
|
package/planu-plugin.json
CHANGED
|
@@ -2,12 +2,9 @@
|
|
|
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": "4.4.
|
|
5
|
+
"version": "4.4.2",
|
|
6
6
|
"icon": "assets/plugin/icon.svg",
|
|
7
|
-
"command": [
|
|
8
|
-
"npx",
|
|
9
|
-
"@planu/cli@latest"
|
|
10
|
-
],
|
|
7
|
+
"command": ["npx", "@planu/cli@latest"],
|
|
11
8
|
"packageName": "@planu/cli",
|
|
12
9
|
"capabilities": {
|
|
13
10
|
"tools": [
|
|
@@ -26,42 +23,17 @@
|
|
|
26
23
|
"create_skill",
|
|
27
24
|
"skill_search"
|
|
28
25
|
],
|
|
29
|
-
"resources": [
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
"planu://project/status",
|
|
33
|
-
"planu://roadmap"
|
|
34
|
-
],
|
|
35
|
-
"prompts": [
|
|
36
|
-
"create-spec-from-idea",
|
|
37
|
-
"review-spec-readiness",
|
|
38
|
-
"generate-implementation-plan"
|
|
39
|
-
],
|
|
40
|
-
"subagents": [
|
|
41
|
-
"sdd-orchestrator",
|
|
42
|
-
"spec-challenger",
|
|
43
|
-
"test-generator"
|
|
44
|
-
]
|
|
26
|
+
"resources": ["planu://specs/list", "planu://specs/{id}", "planu://project/status", "planu://roadmap"],
|
|
27
|
+
"prompts": ["create-spec-from-idea", "review-spec-readiness", "generate-implementation-plan"],
|
|
28
|
+
"subagents": ["sdd-orchestrator", "spec-challenger", "test-generator"]
|
|
45
29
|
},
|
|
46
30
|
"compatibility": {
|
|
47
31
|
"minimumHostVersion": "1.0.0",
|
|
48
|
-
"requiredFeatures": [
|
|
49
|
-
"mcp-tools",
|
|
50
|
-
"file-editing"
|
|
51
|
-
]
|
|
32
|
+
"requiredFeatures": ["mcp-tools", "file-editing"]
|
|
52
33
|
},
|
|
53
34
|
"repository": "https://github.com/planu-dev/planu",
|
|
54
35
|
"author": "Planu",
|
|
55
36
|
"license": "MIT",
|
|
56
37
|
"homepage": "https://planu.dev",
|
|
57
|
-
"keywords": [
|
|
58
|
-
"sdd",
|
|
59
|
-
"spec-driven-development",
|
|
60
|
-
"mcp",
|
|
61
|
-
"specs",
|
|
62
|
-
"planning",
|
|
63
|
-
"ai",
|
|
64
|
-
"bdd",
|
|
65
|
-
"tdd"
|
|
66
|
-
]
|
|
38
|
+
"keywords": ["sdd", "spec-driven-development", "mcp", "specs", "planning", "ai", "bdd", "tdd"]
|
|
67
39
|
}
|