@planu/cli 4.4.3 → 4.6.0
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 +20 -1
- package/dist/config/token-waste-autopilot.json +48 -0
- package/dist/engine/elicitation/answer-extractor.js +53 -1
- package/dist/engine/elicitation/decision-gap-detector.d.ts +3 -0
- package/dist/engine/elicitation/decision-gap-detector.js +162 -0
- package/dist/engine/elicitation/question-grounding-gate.d.ts +3 -0
- package/dist/engine/elicitation/question-grounding-gate.js +54 -0
- package/dist/engine/token-optimizer/autopilot.d.ts +5 -0
- package/dist/engine/token-optimizer/autopilot.js +93 -0
- package/dist/engine/token-optimizer/context-preflight.d.ts +3 -0
- package/dist/engine/token-optimizer/context-preflight.js +64 -0
- package/dist/engine/token-optimizer/index.d.ts +6 -0
- package/dist/engine/token-optimizer/index.js +6 -0
- package/dist/engine/token-optimizer/loop-detector.d.ts +3 -0
- package/dist/engine/token-optimizer/loop-detector.js +32 -0
- package/dist/engine/token-optimizer/output-filter.d.ts +3 -0
- package/dist/engine/token-optimizer/output-filter.js +67 -0
- package/dist/engine/token-optimizer/policy-loader.d.ts +3 -0
- package/dist/engine/token-optimizer/policy-loader.js +83 -0
- package/dist/engine/token-optimizer/tool-relevance.d.ts +6 -0
- package/dist/engine/token-optimizer/tool-relevance.js +57 -0
- package/dist/tools/create-spec/post-creation.d.ts +2 -1
- package/dist/tools/create-spec/post-creation.js +32 -0
- package/dist/tools/create-spec/question-generator.d.ts +1 -1
- package/dist/tools/create-spec/question-generator.js +20 -96
- package/dist/tools/package-handoff.js +47 -1
- package/dist/tools/schemas/token-intelligence.d.ts +1 -0
- package/dist/tools/schemas/token-intelligence.js +3 -2
- package/dist/tools/status-handler.js +17 -2
- package/dist/tools/token-intelligence-handler.js +46 -1
- package/dist/types/clarification.d.ts +8 -0
- package/dist/types/elicitation.d.ts +21 -0
- package/dist/types/index.d.ts +1 -0
- package/dist/types/index.js +1 -0
- package/dist/types/token-waste-autopilot.d.ts +142 -0
- package/dist/types/token-waste-autopilot.js +2 -0
- package/package.json +13 -13
- package/planu-native.json +29 -8
- package/planu-plugin.json +35 -7
|
@@ -13,6 +13,14 @@ export interface DescriptionSignals {
|
|
|
13
13
|
hasUi: boolean;
|
|
14
14
|
namedProvider: string | null;
|
|
15
15
|
hasScope: boolean;
|
|
16
|
+
action: string | null;
|
|
17
|
+
domainObject: string | null;
|
|
18
|
+
actors: string[];
|
|
19
|
+
integrations: string[];
|
|
20
|
+
dataObjects: string[];
|
|
21
|
+
hasPermissionRisk: boolean;
|
|
22
|
+
hasDestructiveAction: boolean;
|
|
23
|
+
riskTerms: string[];
|
|
16
24
|
}
|
|
17
25
|
/** Which host mechanism the LLM should use to relay interactive questions. */
|
|
18
26
|
export type HostHint = 'claude-code' | 'cursor' | 'codex' | 'gemini' | 'universal';
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { InteractiveQuestion } from './clarification.js';
|
|
2
|
+
import type { InteractiveOption } from './interactive-question.js';
|
|
2
3
|
/** Primitive field types supported by the MCP elicitation protocol. */
|
|
3
4
|
export type ElicitationFieldType = 'text' | 'number' | 'boolean' | 'enum' | 'multi-select';
|
|
4
5
|
/** Shared base for all elicitation field definitions. */
|
|
@@ -174,6 +175,26 @@ export type ElicitOrFallbackOutcome = {
|
|
|
174
175
|
* - 'technical': inferred from codebase signals; elicitation is skipped
|
|
175
176
|
*/
|
|
176
177
|
export type DecisionType = 'policy' | 'business' | 'technical';
|
|
178
|
+
export type DecisionGapKind = 'behavior' | 'permission' | 'provider' | 'billing-model' | 'data' | 'failure' | 'scope';
|
|
179
|
+
export interface DecisionGap {
|
|
180
|
+
id: string;
|
|
181
|
+
kind: DecisionGapKind;
|
|
182
|
+
header: string;
|
|
183
|
+
question: string;
|
|
184
|
+
evidence: string[];
|
|
185
|
+
impact: string;
|
|
186
|
+
options: InteractiveOption[];
|
|
187
|
+
multiSelect: boolean;
|
|
188
|
+
blocking: boolean;
|
|
189
|
+
}
|
|
190
|
+
export interface QuestionGroundingContext {
|
|
191
|
+
gap: DecisionGap;
|
|
192
|
+
requestText: string;
|
|
193
|
+
}
|
|
194
|
+
export interface QuestionGroundingResult {
|
|
195
|
+
passed: boolean;
|
|
196
|
+
reason?: string;
|
|
197
|
+
}
|
|
177
198
|
/**
|
|
178
199
|
* Outcome when the decision was already cached in conventions.json.
|
|
179
200
|
* The caller can return this value immediately without prompting the user.
|
package/dist/types/index.d.ts
CHANGED
|
@@ -79,6 +79,7 @@ export * from './runtime-security.js';
|
|
|
79
79
|
export * from './workers.js';
|
|
80
80
|
export * from './orchestration-runtime.js';
|
|
81
81
|
export * from './token-optimization.js';
|
|
82
|
+
export * from './token-waste-autopilot.js';
|
|
82
83
|
export * from './llm-providers.js';
|
|
83
84
|
export * from './plugins.js';
|
|
84
85
|
export * from './github.js';
|
package/dist/types/index.js
CHANGED
|
@@ -80,6 +80,7 @@ export * from './runtime-security.js';
|
|
|
80
80
|
export * from './workers.js';
|
|
81
81
|
export * from './orchestration-runtime.js';
|
|
82
82
|
export * from './token-optimization.js';
|
|
83
|
+
export * from './token-waste-autopilot.js';
|
|
83
84
|
export * from './llm-providers.js';
|
|
84
85
|
export * from './plugins.js';
|
|
85
86
|
export * from './github.js';
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
export type TokenWasteDecisionKind = 'include' | 'summarize' | 'exclude' | 'recommend' | 'avoid' | 'warn' | 'override';
|
|
2
|
+
export type TokenWasteConfidence = 'high' | 'medium' | 'low';
|
|
3
|
+
export type TokenWasteAction = string;
|
|
4
|
+
export interface TokenWastePolicyLoadOptions {
|
|
5
|
+
defaultPolicyPath?: string;
|
|
6
|
+
}
|
|
7
|
+
export interface TokenWasteEvidence {
|
|
8
|
+
source: 'policy' | 'project-config' | 'runtime' | 'spec' | 'tool-registry' | 'host-capability';
|
|
9
|
+
key: string;
|
|
10
|
+
value?: string | number | boolean;
|
|
11
|
+
}
|
|
12
|
+
export interface TokenWasteDecision {
|
|
13
|
+
decision: TokenWasteDecisionKind;
|
|
14
|
+
target: string;
|
|
15
|
+
reason: string;
|
|
16
|
+
evidence: TokenWasteEvidence[];
|
|
17
|
+
confidence: TokenWasteConfidence;
|
|
18
|
+
}
|
|
19
|
+
export interface TokenWasteOutputStrategy {
|
|
20
|
+
maxLines: number;
|
|
21
|
+
keepFailures?: boolean;
|
|
22
|
+
uniqueOnly?: boolean;
|
|
23
|
+
summarizeKeys?: boolean;
|
|
24
|
+
}
|
|
25
|
+
export interface TokenWastePolicy {
|
|
26
|
+
version: 1;
|
|
27
|
+
enabled: boolean;
|
|
28
|
+
context: {
|
|
29
|
+
generatedPatterns: string[];
|
|
30
|
+
stalePatterns: string[];
|
|
31
|
+
summarizePatterns: string[];
|
|
32
|
+
staleSessionMinutes: number;
|
|
33
|
+
safetyOverrideActions: string[];
|
|
34
|
+
};
|
|
35
|
+
outputs: {
|
|
36
|
+
strategies: Record<string, TokenWasteOutputStrategy>;
|
|
37
|
+
};
|
|
38
|
+
tools: {
|
|
39
|
+
groups: Record<string, string[]>;
|
|
40
|
+
maxRecommended: number;
|
|
41
|
+
};
|
|
42
|
+
loops: {
|
|
43
|
+
thresholds: Record<string, number>;
|
|
44
|
+
safetyOverrideActions: string[];
|
|
45
|
+
};
|
|
46
|
+
modelEffort: {
|
|
47
|
+
lowRisk: string;
|
|
48
|
+
default: string;
|
|
49
|
+
highRisk: string;
|
|
50
|
+
maxRisk: string;
|
|
51
|
+
};
|
|
52
|
+
redaction: {
|
|
53
|
+
maxSnippetChars: number;
|
|
54
|
+
redactPatterns: string[];
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
export interface LoadedTokenWastePolicy {
|
|
58
|
+
policy: TokenWastePolicy;
|
|
59
|
+
evidence: TokenWasteEvidence[];
|
|
60
|
+
}
|
|
61
|
+
export interface ContextCandidate {
|
|
62
|
+
path: string;
|
|
63
|
+
reason?: string;
|
|
64
|
+
}
|
|
65
|
+
export interface ContextPreflightInput {
|
|
66
|
+
action: TokenWasteAction;
|
|
67
|
+
policy: TokenWastePolicy;
|
|
68
|
+
candidates: ContextCandidate[];
|
|
69
|
+
spec?: {
|
|
70
|
+
id?: string;
|
|
71
|
+
status?: string;
|
|
72
|
+
risk?: string;
|
|
73
|
+
target?: string;
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
export interface ContextPreflightResult {
|
|
77
|
+
include: TokenWasteDecision[];
|
|
78
|
+
summarize: TokenWasteDecision[];
|
|
79
|
+
exclude: TokenWasteDecision[];
|
|
80
|
+
}
|
|
81
|
+
export interface VerboseOutputInput {
|
|
82
|
+
kind: string;
|
|
83
|
+
text: string;
|
|
84
|
+
policy: TokenWastePolicy;
|
|
85
|
+
fullOutputRef?: string;
|
|
86
|
+
}
|
|
87
|
+
export interface VerboseOutputResult {
|
|
88
|
+
text: string;
|
|
89
|
+
originalLines: number;
|
|
90
|
+
returnedLines: number;
|
|
91
|
+
fullOutputRef?: string;
|
|
92
|
+
decisions: TokenWasteDecision[];
|
|
93
|
+
}
|
|
94
|
+
export interface ToolRelevanceInput {
|
|
95
|
+
action: TokenWasteAction;
|
|
96
|
+
intentSignals: string[];
|
|
97
|
+
tools: {
|
|
98
|
+
name: string;
|
|
99
|
+
description?: string;
|
|
100
|
+
}[];
|
|
101
|
+
policy: TokenWastePolicy;
|
|
102
|
+
hostUnsupportedTools?: string[];
|
|
103
|
+
}
|
|
104
|
+
export interface ToolRelevanceResult {
|
|
105
|
+
recommended: TokenWasteDecision[];
|
|
106
|
+
avoided: TokenWasteDecision[];
|
|
107
|
+
}
|
|
108
|
+
export interface TokenWasteRuntimeEvent {
|
|
109
|
+
type: string;
|
|
110
|
+
key: string;
|
|
111
|
+
timestamp?: string;
|
|
112
|
+
changedSincePrevious?: boolean;
|
|
113
|
+
}
|
|
114
|
+
export interface TokenWasteLoopResult {
|
|
115
|
+
warnings: TokenWasteDecision[];
|
|
116
|
+
}
|
|
117
|
+
export interface TokenWasteModelAdvice {
|
|
118
|
+
effort: string;
|
|
119
|
+
reason: string;
|
|
120
|
+
evidence: TokenWasteEvidence[];
|
|
121
|
+
}
|
|
122
|
+
export interface TokenWasteAutopilotInput {
|
|
123
|
+
action: TokenWasteAction;
|
|
124
|
+
policy: TokenWastePolicy;
|
|
125
|
+
context?: ContextPreflightResult;
|
|
126
|
+
output?: VerboseOutputResult;
|
|
127
|
+
tools?: ToolRelevanceResult;
|
|
128
|
+
loops?: TokenWasteLoopResult;
|
|
129
|
+
spec?: {
|
|
130
|
+
id?: string;
|
|
131
|
+
risk?: string;
|
|
132
|
+
scope?: string;
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
export interface TokenWasteReport {
|
|
136
|
+
actionsTaken: TokenWasteDecision[];
|
|
137
|
+
recommendations: TokenWasteDecision[];
|
|
138
|
+
risks: TokenWasteDecision[];
|
|
139
|
+
evidence: TokenWasteEvidence[];
|
|
140
|
+
modelEffort: TokenWasteModelAdvice;
|
|
141
|
+
}
|
|
142
|
+
//# sourceMappingURL=token-waste-autopilot.d.ts.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@planu/cli",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.6.0",
|
|
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.
|
|
38
|
-
"@planu/core-darwin-x64": "4.
|
|
39
|
-
"@planu/core-linux-arm64-gnu": "4.
|
|
40
|
-
"@planu/core-linux-arm64-musl": "4.
|
|
41
|
-
"@planu/core-linux-x64-gnu": "4.
|
|
42
|
-
"@planu/core-linux-x64-musl": "4.
|
|
43
|
-
"@planu/core-win32-arm64-msvc": "4.
|
|
44
|
-
"@planu/core-win32-x64-msvc": "4.
|
|
37
|
+
"@planu/core-darwin-arm64": "4.6.0",
|
|
38
|
+
"@planu/core-darwin-x64": "4.6.0",
|
|
39
|
+
"@planu/core-linux-arm64-gnu": "4.6.0",
|
|
40
|
+
"@planu/core-linux-arm64-musl": "4.6.0",
|
|
41
|
+
"@planu/core-linux-x64-gnu": "4.6.0",
|
|
42
|
+
"@planu/core-linux-x64-musl": "4.6.0",
|
|
43
|
+
"@planu/core-win32-arm64-msvc": "4.6.0",
|
|
44
|
+
"@planu/core-win32-x64-msvc": "4.6.0"
|
|
45
45
|
},
|
|
46
46
|
"engines": {
|
|
47
47
|
"node": ">=24.0.0"
|
|
@@ -170,7 +170,7 @@
|
|
|
170
170
|
"@commitlint/cli": "^21.0.2",
|
|
171
171
|
"@commitlint/config-conventional": "^21.0.2",
|
|
172
172
|
"@eslint/js": "^10.0.1",
|
|
173
|
-
"@napi-rs/cli": "^3.7.
|
|
173
|
+
"@napi-rs/cli": "^3.7.1",
|
|
174
174
|
"@secretlint/secretlint-rule-no-homedir": "^13.0.2",
|
|
175
175
|
"@secretlint/secretlint-rule-preset-recommend": "^13.0.2",
|
|
176
176
|
"@semantic-release/changelog": "^6.0.3",
|
|
@@ -182,7 +182,7 @@
|
|
|
182
182
|
"@stryker-mutator/core": "^9.6.1",
|
|
183
183
|
"@stryker-mutator/vitest-runner": "^9.6.1",
|
|
184
184
|
"@supabase/supabase-js": "^2.108.1",
|
|
185
|
-
"@types/node": "^25.9.
|
|
185
|
+
"@types/node": "^25.9.3",
|
|
186
186
|
"@vitejs/plugin-vue": "^6.0.7",
|
|
187
187
|
"@vitest/coverage-v8": "^4.1.8",
|
|
188
188
|
"@vue/test-utils": "^2.4.11",
|
|
@@ -198,13 +198,13 @@
|
|
|
198
198
|
"madge": "^8.0.0",
|
|
199
199
|
"prettier": "^3.8.4",
|
|
200
200
|
"secretlint": "^13.0.2",
|
|
201
|
-
"semantic-release": "^25.0.
|
|
201
|
+
"semantic-release": "^25.0.5",
|
|
202
202
|
"tsc-alias": "^1.8.17",
|
|
203
203
|
"type-coverage": "^2.29.7",
|
|
204
204
|
"typescript": "^6.0.3",
|
|
205
205
|
"typescript-eslint": "^8.61.0",
|
|
206
206
|
"vite": "^8.0.16",
|
|
207
207
|
"vitest": "^4.1.8",
|
|
208
|
-
"vue": "^3.5.
|
|
208
|
+
"vue": "^3.5.38"
|
|
209
209
|
}
|
|
210
210
|
}
|
package/planu-native.json
CHANGED
|
@@ -1,20 +1,26 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dev.planu.native",
|
|
3
3
|
"displayName": "Planu Native Lightweight Surface",
|
|
4
|
-
"version": "4.
|
|
4
|
+
"version": "4.6.0",
|
|
5
5
|
"packageName": "@planu/cli",
|
|
6
6
|
"modes": {
|
|
7
7
|
"lightweight": {
|
|
8
8
|
"requiresMcp": false,
|
|
9
9
|
"requiresDaemon": false,
|
|
10
|
-
"hosts": [
|
|
10
|
+
"hosts": [
|
|
11
|
+
"codex",
|
|
12
|
+
"claude-code"
|
|
13
|
+
],
|
|
11
14
|
"commands": [
|
|
12
15
|
{
|
|
13
16
|
"id": "planu.status",
|
|
14
17
|
"title": "Project status",
|
|
15
18
|
"description": "Show the compact Planu project snapshot without loading the MCP tool graph.",
|
|
16
19
|
"invocation": "planu status",
|
|
17
|
-
"hosts": [
|
|
20
|
+
"hosts": [
|
|
21
|
+
"codex",
|
|
22
|
+
"claude-code"
|
|
23
|
+
],
|
|
18
24
|
"requiresMcp": false,
|
|
19
25
|
"requiresDaemon": false,
|
|
20
26
|
"mapsTo": "handlePlanStatus"
|
|
@@ -24,7 +30,10 @@
|
|
|
24
30
|
"title": "Create spec",
|
|
25
31
|
"description": "Create a new spec through the CLI-backed SDD contract.",
|
|
26
32
|
"invocation": "planu spec create \"<title>\"",
|
|
27
|
-
"hosts": [
|
|
33
|
+
"hosts": [
|
|
34
|
+
"codex",
|
|
35
|
+
"claude-code"
|
|
36
|
+
],
|
|
28
37
|
"requiresMcp": false,
|
|
29
38
|
"requiresDaemon": false,
|
|
30
39
|
"mapsTo": "handleCreateSpec"
|
|
@@ -34,7 +43,10 @@
|
|
|
34
43
|
"title": "List specs",
|
|
35
44
|
"description": "List specs in the current project with optional status/type filters.",
|
|
36
45
|
"invocation": "planu spec list",
|
|
37
|
-
"hosts": [
|
|
46
|
+
"hosts": [
|
|
47
|
+
"codex",
|
|
48
|
+
"claude-code"
|
|
49
|
+
],
|
|
38
50
|
"requiresMcp": false,
|
|
39
51
|
"requiresDaemon": false,
|
|
40
52
|
"mapsTo": "handleListSpecs"
|
|
@@ -44,7 +56,10 @@
|
|
|
44
56
|
"title": "Validate spec",
|
|
45
57
|
"description": "Validate a spec against the current codebase from the native CLI surface.",
|
|
46
58
|
"invocation": "planu spec validate SPEC-001",
|
|
47
|
-
"hosts": [
|
|
59
|
+
"hosts": [
|
|
60
|
+
"codex",
|
|
61
|
+
"claude-code"
|
|
62
|
+
],
|
|
48
63
|
"requiresMcp": false,
|
|
49
64
|
"requiresDaemon": false,
|
|
50
65
|
"mapsTo": "handleValidate"
|
|
@@ -54,7 +69,10 @@
|
|
|
54
69
|
"title": "Audit technical debt",
|
|
55
70
|
"description": "Run the read-only project audit path for lightweight debt checks.",
|
|
56
71
|
"invocation": "planu audit debt",
|
|
57
|
-
"hosts": [
|
|
72
|
+
"hosts": [
|
|
73
|
+
"codex",
|
|
74
|
+
"claude-code"
|
|
75
|
+
],
|
|
58
76
|
"requiresMcp": false,
|
|
59
77
|
"requiresDaemon": false,
|
|
60
78
|
"mapsTo": "handleAudit"
|
|
@@ -64,7 +82,10 @@
|
|
|
64
82
|
"title": "Check release readiness",
|
|
65
83
|
"description": "Check local branch cleanliness and main/develop/release sync readiness.",
|
|
66
84
|
"invocation": "planu release check",
|
|
67
|
-
"hosts": [
|
|
85
|
+
"hosts": [
|
|
86
|
+
"codex",
|
|
87
|
+
"claude-code"
|
|
88
|
+
],
|
|
68
89
|
"requiresMcp": false,
|
|
69
90
|
"requiresDaemon": false,
|
|
70
91
|
"mapsTo": "releaseCommand"
|
package/planu-plugin.json
CHANGED
|
@@ -2,9 +2,12 @@
|
|
|
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.
|
|
5
|
+
"version": "4.6.0",
|
|
6
6
|
"icon": "assets/plugin/icon.svg",
|
|
7
|
-
"command": [
|
|
7
|
+
"command": [
|
|
8
|
+
"npx",
|
|
9
|
+
"@planu/cli@latest"
|
|
10
|
+
],
|
|
8
11
|
"packageName": "@planu/cli",
|
|
9
12
|
"capabilities": {
|
|
10
13
|
"tools": [
|
|
@@ -23,17 +26,42 @@
|
|
|
23
26
|
"create_skill",
|
|
24
27
|
"skill_search"
|
|
25
28
|
],
|
|
26
|
-
"resources": [
|
|
27
|
-
|
|
28
|
-
|
|
29
|
+
"resources": [
|
|
30
|
+
"planu://specs/list",
|
|
31
|
+
"planu://specs/{id}",
|
|
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
|
+
]
|
|
29
45
|
},
|
|
30
46
|
"compatibility": {
|
|
31
47
|
"minimumHostVersion": "1.0.0",
|
|
32
|
-
"requiredFeatures": [
|
|
48
|
+
"requiredFeatures": [
|
|
49
|
+
"mcp-tools",
|
|
50
|
+
"file-editing"
|
|
51
|
+
]
|
|
33
52
|
},
|
|
34
53
|
"repository": "https://github.com/planu-dev/planu",
|
|
35
54
|
"author": "Planu",
|
|
36
55
|
"license": "MIT",
|
|
37
56
|
"homepage": "https://planu.dev",
|
|
38
|
-
"keywords": [
|
|
57
|
+
"keywords": [
|
|
58
|
+
"sdd",
|
|
59
|
+
"spec-driven-development",
|
|
60
|
+
"mcp",
|
|
61
|
+
"specs",
|
|
62
|
+
"planning",
|
|
63
|
+
"ai",
|
|
64
|
+
"bdd",
|
|
65
|
+
"tdd"
|
|
66
|
+
]
|
|
39
67
|
}
|