@planu/cli 4.10.5 → 4.10.7
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 -0
- package/dist/engine/compact/tool-list-compactor.d.ts +1 -1
- package/dist/engine/evidence-gates/lifecycle-gate.js +17 -1
- package/dist/engine/evidence-index/done-drift.js +4 -1
- package/dist/engine/local-first/tool-classification.d.ts +7 -0
- package/dist/engine/local-first/tool-classification.js +313 -0
- package/dist/engine/qa-gate.js +13 -1
- package/dist/engine/scope-boundaries/scope-validator.js +14 -2
- package/dist/engine/validator/validation-report-writer.js +3 -4
- package/dist/tools/audit.js +1 -1
- package/dist/tools/challenge-spec.js +52 -2
- package/dist/tools/check-readiness.js +15 -8
- package/dist/tools/data-governance/audit-handler.js +21 -6
- package/dist/tools/data-governance/detect-handler.js +32 -15
- package/dist/tools/define-ui-contract.js +1 -4
- package/dist/tools/design-schema.js +1 -4
- package/dist/tools/detect-drift.js +48 -28
- package/dist/tools/flag-spec-gap.js +47 -12
- package/dist/tools/generate-sub-agent.js +2 -4
- package/dist/tools/list-specs.js +15 -59
- package/dist/tools/orchestrate-locking.js +15 -4
- package/dist/tools/output-compressor.d.ts +14 -1
- package/dist/tools/output-compressor.js +121 -2
- package/dist/tools/package-handoff.js +136 -12
- package/dist/tools/reverse-engineer/handler.js +9 -10
- package/dist/tools/rollback-release.js +20 -2
- package/dist/tools/spec-diff-handler.js +3 -3
- package/dist/tools/status-handler.js +6 -1
- package/dist/tools/suggest-mcp-server.js +2 -4
- package/dist/tools/token-recording.d.ts +2 -1
- package/dist/tools/token-recording.js +21 -2
- package/dist/tools/update-status/dod-gates.d.ts +2 -2
- package/dist/tools/update-status/dod-gates.js +47 -52
- package/dist/tools/update-status/evidence-gate.js +6 -4
- package/dist/tools/update-status/index.js +10 -3
- package/dist/tools/update-status/qa-gate.d.ts +5 -0
- package/dist/tools/update-status/qa-gate.js +50 -0
- package/dist/tools/update-status/response-builder.js +96 -2
- package/dist/tools/update-status/transition-guard.js +33 -11
- package/dist/tools/update-status-convention-gate.js +22 -6
- package/dist/tools/validate-team-results.js +23 -1
- package/dist/tools/validate.js +137 -16
- package/dist/transports/http-transport.js +13 -0
- package/dist/transports/transport-factory.js +13 -0
- package/dist/types/qa-gate.d.ts +3 -0
- package/dist/types/tool-classification.d.ts +8 -0
- package/dist/types/tool-classification.js +2 -0
- package/package.json +10 -10
- package/planu-native.json +1 -1
- package/planu-plugin.json +1 -1
package/dist/tools/validate.js
CHANGED
|
@@ -22,13 +22,13 @@ import { checkPlanuUncommittedChanges, runAssuranceGates } from './validate-assu
|
|
|
22
22
|
// Re-export for external use (SPEC-018)
|
|
23
23
|
export { validateContractCompliance };
|
|
24
24
|
// SPEC-595: server? param enables elicitation on failures
|
|
25
|
+
// eslint-disable-next-line max-lines-per-function -- validate orchestrates many existing gates in one handler.
|
|
25
26
|
export async function handleValidate(args, server) {
|
|
26
27
|
const { specId } = args;
|
|
27
28
|
const projectId = resolveProjectId(args);
|
|
28
29
|
if (!projectId) {
|
|
29
30
|
return missingProjectIdError;
|
|
30
31
|
}
|
|
31
|
-
// 1. Load spec
|
|
32
32
|
const spec = await specStore.getSpec(projectId, specId);
|
|
33
33
|
if (!spec) {
|
|
34
34
|
return {
|
|
@@ -42,7 +42,6 @@ export async function handleValidate(args, server) {
|
|
|
42
42
|
},
|
|
43
43
|
};
|
|
44
44
|
}
|
|
45
|
-
// 2. Load project knowledge for project path
|
|
46
45
|
const knowledge = await knowledgeStore.getKnowledge(projectId);
|
|
47
46
|
if (!knowledge) {
|
|
48
47
|
return {
|
|
@@ -66,18 +65,13 @@ export async function handleValidate(args, server) {
|
|
|
66
65
|
if (strictLayoutError !== null) {
|
|
67
66
|
return strictLayoutError;
|
|
68
67
|
}
|
|
69
|
-
// 3. Run validation engine
|
|
70
68
|
const result = await validateSpec(spec, projectPath);
|
|
71
69
|
const graphCoverage = await buildGraphCoverageReport({ projectId, projectPath, specId });
|
|
72
|
-
// 4. Generate DoR and DoD checklists
|
|
73
70
|
const dor = generateDoR(spec);
|
|
74
71
|
const dod = await generateDoD(spec, result, undefined, projectPath);
|
|
75
|
-
// 5. Compute implementation quality score from validated files (SPEC-010 S47)
|
|
76
72
|
const implementationQualityScore = calcQualityScore(result.qualityIssues);
|
|
77
73
|
const auditedFiles = [...new Set(result.qualityIssues.map((i) => i.file))];
|
|
78
|
-
// 6. SPEC-190: Convention compliance check
|
|
79
74
|
const { conventionViolations, regressionDetected } = await scanProjectConventions(projectId, projectPath);
|
|
80
|
-
// 7. Lint check (best-effort — non-blocking)
|
|
81
75
|
const lintCheck = runLintCheck(projectPath, knowledge.lintCommand ?? null);
|
|
82
76
|
const assuranceGates = runAssuranceGates(projectPath);
|
|
83
77
|
const minimalityReport = await buildMinimalityReport({
|
|
@@ -108,7 +102,6 @@ export async function handleValidate(args, server) {
|
|
|
108
102
|
minimalityBlocked: minimalityReport?.blocked === true,
|
|
109
103
|
score: result.score,
|
|
110
104
|
});
|
|
111
|
-
// 8. Build output
|
|
112
105
|
const output = {
|
|
113
106
|
specId,
|
|
114
107
|
title: spec.title,
|
|
@@ -239,13 +232,6 @@ export async function handleValidate(args, server) {
|
|
|
239
232
|
if (minimalityReport?.blocked) {
|
|
240
233
|
suggestions.push(`${minimalityReport.findings.filter((finding) => finding.blocksDone).length} blocking minimality finding(s) detected. Remove avoidable complexity or record accepted debt before marking done.`);
|
|
241
234
|
}
|
|
242
|
-
const outputWithSuggestions = compactObj({
|
|
243
|
-
...output,
|
|
244
|
-
suggestions: suggestions.length > 0 ? suggestions : undefined,
|
|
245
|
-
});
|
|
246
|
-
// `lintCheck.output` is part of the MCP output contract. Keep it even when
|
|
247
|
-
// empty because compactObj removes empty strings recursively.
|
|
248
|
-
outputWithSuggestions.lintCheck = lintCheck;
|
|
249
235
|
// SPEC-012: Dispatch feedback event for auto-improvement loop (best-effort)
|
|
250
236
|
void dispatchFeedbackEvent(projectId, {
|
|
251
237
|
type: 'validate',
|
|
@@ -305,7 +291,26 @@ export async function handleValidate(args, server) {
|
|
|
305
291
|
const graphText = formatGraphCoverageText(graphCoverage);
|
|
306
292
|
// SPEC-512: Compact structuredContent — essential fields only at top level
|
|
307
293
|
const compactSummary = buildCompactSummary(specId, result.score === null ? null : effectiveScore, passedCount, failedCount + (qualityGateSummary.passed ? 0 : 1), totalCriteria);
|
|
308
|
-
const structuredBase = {
|
|
294
|
+
const structuredBase = buildValidateStructuredContent({
|
|
295
|
+
specId,
|
|
296
|
+
title: spec.title,
|
|
297
|
+
score: result.score === null ? null : effectiveScore,
|
|
298
|
+
compactSummary,
|
|
299
|
+
result,
|
|
300
|
+
indeterminate,
|
|
301
|
+
dor,
|
|
302
|
+
dod,
|
|
303
|
+
qualityIssues: output.qualityIssues,
|
|
304
|
+
implementationQualityScore: output.implementationQualityScore,
|
|
305
|
+
conventionCompliance: output.conventionCompliance,
|
|
306
|
+
lintCheck,
|
|
307
|
+
assuranceGates,
|
|
308
|
+
qualityGateSummary,
|
|
309
|
+
validationReport,
|
|
310
|
+
minimalityReport,
|
|
311
|
+
graphCoverage,
|
|
312
|
+
suggestions,
|
|
313
|
+
});
|
|
309
314
|
// SPEC-595: Elicit next action when validation fails and a server is available
|
|
310
315
|
if (server !== undefined && failedCount > 0) {
|
|
311
316
|
const { field, property } = buildEnumSchema('action', ['re-implement', 'ignore', 'mark-manual'], ['Fix failing criteria (Recommended)', 'Ignore failures', 'Mark as manually reviewed'], 'Next action', 're-implement');
|
|
@@ -400,6 +405,122 @@ function buildCompactSummary(specId, score, passedCount, failedCount, totalCrite
|
|
|
400
405
|
status: failedCount === 0 ? 'passing' : 'failing',
|
|
401
406
|
};
|
|
402
407
|
}
|
|
408
|
+
function buildValidateStructuredContent(args) {
|
|
409
|
+
const failedDorItems = args.dor.items.filter((item) => item.status === 'failed').slice(0, 5);
|
|
410
|
+
const failedDodItems = args.dod.items
|
|
411
|
+
.filter((item) => item.required === true && item.status !== 'passed')
|
|
412
|
+
.slice(0, 5);
|
|
413
|
+
const failedGates = args.validationReport.gates.filter((gate) => !gate.passed);
|
|
414
|
+
const minimalityBlockingFindings = args.minimalityReport?.findings.filter((finding) => finding.blocksDone) ?? [];
|
|
415
|
+
const blockers = [
|
|
416
|
+
...args.result.missing.map((missing) => `missing: ${missing}`),
|
|
417
|
+
...args.indeterminate.map((item) => `indeterminate: ${item}`),
|
|
418
|
+
...args.qualityGateSummary.failures.map((failure) => `gate: ${failure}`),
|
|
419
|
+
...args.qualityIssues.map((issue) => `${issue.rule}: ${issue.message}`),
|
|
420
|
+
];
|
|
421
|
+
const risks = [
|
|
422
|
+
...args.conventionCompliance.violations.map((violation) => violation.message),
|
|
423
|
+
...minimalityBlockingFindings.map((finding) => `${finding.ruleId}: ${finding.target}`),
|
|
424
|
+
...args.suggestions,
|
|
425
|
+
];
|
|
426
|
+
const structured = compactObj({
|
|
427
|
+
specId: args.specId,
|
|
428
|
+
title: args.title,
|
|
429
|
+
ready: args.compactSummary.status === 'passing' && args.qualityGateSummary.passed,
|
|
430
|
+
status: args.compactSummary.status,
|
|
431
|
+
score: args.score,
|
|
432
|
+
summary: args.compactSummary,
|
|
433
|
+
counts: {
|
|
434
|
+
matches: args.result.matches.length,
|
|
435
|
+
missing: args.result.missing.length,
|
|
436
|
+
extra: args.result.extra.length,
|
|
437
|
+
indeterminate: args.indeterminate.length,
|
|
438
|
+
qualityIssues: args.qualityIssues.length,
|
|
439
|
+
conventionViolations: args.conventionCompliance.totalViolations,
|
|
440
|
+
graphGaps: args.graphCoverage.gaps.length,
|
|
441
|
+
failedGates: failedGates.length,
|
|
442
|
+
},
|
|
443
|
+
missingTop5: args.result.missing.slice(0, 5),
|
|
444
|
+
extraTop5: args.result.extra.slice(0, 5),
|
|
445
|
+
indeterminateTop5: args.indeterminate.slice(0, 5),
|
|
446
|
+
qualityIssuesTop5: args.qualityIssues.slice(0, 5),
|
|
447
|
+
qualityGateSummary: args.qualityGateSummary,
|
|
448
|
+
blockersCount: blockers.length,
|
|
449
|
+
blockersTop3: blockers.slice(0, 3),
|
|
450
|
+
risksTop5: risks.slice(0, 5),
|
|
451
|
+
autofixable: args.suggestions.length > 0 || args.qualityIssues.length > 0,
|
|
452
|
+
nextAction: args.suggestions[0] ??
|
|
453
|
+
(args.compactSummary.status === 'passing'
|
|
454
|
+
? 'Proceed to update_status(done) after required release checks pass.'
|
|
455
|
+
: 'Fix the top blockers and rerun validate.'),
|
|
456
|
+
artifactRefs: {
|
|
457
|
+
validationReport: args.validationReport.path,
|
|
458
|
+
validationReportSha: args.validationReport.sha,
|
|
459
|
+
},
|
|
460
|
+
validationReport: {
|
|
461
|
+
written: args.validationReport.written,
|
|
462
|
+
path: args.validationReport.path,
|
|
463
|
+
sha: args.validationReport.sha,
|
|
464
|
+
passed: args.validationReport.passed,
|
|
465
|
+
reviewer: args.validationReport.reviewer,
|
|
466
|
+
gatesCount: args.validationReport.gates.length,
|
|
467
|
+
failedGatesTop5: failedGates.slice(0, 5),
|
|
468
|
+
},
|
|
469
|
+
implementationQualityScore: args.implementationQualityScore,
|
|
470
|
+
definitionOfReady: {
|
|
471
|
+
isReady: args.dor.isReady,
|
|
472
|
+
passed: args.dor.passedCount,
|
|
473
|
+
required: args.dor.requiredCount,
|
|
474
|
+
items: failedDorItems,
|
|
475
|
+
failedItemsTop5: failedDorItems,
|
|
476
|
+
},
|
|
477
|
+
definitionOfDone: {
|
|
478
|
+
isDone: args.dod.isDone,
|
|
479
|
+
passed: args.dod.passedCount,
|
|
480
|
+
required: args.dod.requiredCount,
|
|
481
|
+
failedItems: failedDodItems,
|
|
482
|
+
failedItemsTop5: failedDodItems,
|
|
483
|
+
},
|
|
484
|
+
conventionCompliance: {
|
|
485
|
+
totalViolations: args.conventionCompliance.totalViolations,
|
|
486
|
+
regressionDetected: args.conventionCompliance.regressionDetected,
|
|
487
|
+
violationsTop5: args.conventionCompliance.violations.slice(0, 5),
|
|
488
|
+
},
|
|
489
|
+
lintCheck: {
|
|
490
|
+
passed: args.lintCheck.passed,
|
|
491
|
+
issueCount: args.lintCheck.issueCount,
|
|
492
|
+
command: args.lintCheck.command,
|
|
493
|
+
output: args.lintCheck.output ?? '',
|
|
494
|
+
outputPreview: typeof args.lintCheck.output === 'string' ? args.lintCheck.output.slice(0, 500) : undefined,
|
|
495
|
+
},
|
|
496
|
+
assuranceGates: {
|
|
497
|
+
newCode: {
|
|
498
|
+
passed: args.assuranceGates.newCode.passed,
|
|
499
|
+
findingsCount: args.assuranceGates.newCode.findings.length,
|
|
500
|
+
findingsTop5: args.assuranceGates.newCode.findings.slice(0, 5),
|
|
501
|
+
},
|
|
502
|
+
},
|
|
503
|
+
minimalityReport: args.minimalityReport !== null
|
|
504
|
+
? {
|
|
505
|
+
enabled: args.minimalityReport.enabled,
|
|
506
|
+
blocked: args.minimalityReport.blocked,
|
|
507
|
+
findingCount: args.minimalityReport.findings.length,
|
|
508
|
+
blockingFindingCount: minimalityBlockingFindings.length,
|
|
509
|
+
blockingFindingsTop5: minimalityBlockingFindings.slice(0, 5),
|
|
510
|
+
}
|
|
511
|
+
: undefined,
|
|
512
|
+
graphCoverage: {
|
|
513
|
+
gapsCount: args.graphCoverage.gaps.length,
|
|
514
|
+
gapsTop5: args.graphCoverage.gaps.slice(0, 5),
|
|
515
|
+
freshness: args.graphCoverage.freshness,
|
|
516
|
+
summary: args.graphCoverage.summary,
|
|
517
|
+
},
|
|
518
|
+
suggestionsTop5: args.suggestions.slice(0, 5),
|
|
519
|
+
});
|
|
520
|
+
const lintCheck = structured.lintCheck;
|
|
521
|
+
lintCheck.output = args.lintCheck.output ?? '';
|
|
522
|
+
return structured;
|
|
523
|
+
}
|
|
403
524
|
function buildCompactValidateText(args) {
|
|
404
525
|
const { score, passedCount, failedCount, totalCriteria, qualityFailures, missing, indeterminate, commitReminder, planuReminder, } = args;
|
|
405
526
|
if (failedCount === 0 && qualityFailures.length === 0) {
|
|
@@ -6,6 +6,7 @@ import { PLANU_VERSION } from '../config/version.js';
|
|
|
6
6
|
import { runWithSessionContext } from './session-context.js';
|
|
7
7
|
import { checkHttpRateLimit } from './http-rate-limiter.js';
|
|
8
8
|
import { loadOAuthConfig, extractBearerToken, validateToken } from './oauth-validator.js';
|
|
9
|
+
import { compactToolsListMessage, isToolsListResponse, } from '../engine/compact/tool-list-compactor.js';
|
|
9
10
|
const MAX_BODY_BYTES = 5 * 1024 * 1024; // 5MB
|
|
10
11
|
const SHUTDOWN_GRACE_MS = 5_000;
|
|
11
12
|
const sessions = new Map();
|
|
@@ -95,6 +96,7 @@ async function handlePost(req, res, sessionId, serverFactory) {
|
|
|
95
96
|
const transport = new StreamableHTTPServerTransport({
|
|
96
97
|
sessionIdGenerator: () => randomUUID(),
|
|
97
98
|
});
|
|
99
|
+
installToolsListCompaction(transport);
|
|
98
100
|
transport.onclose = () => {
|
|
99
101
|
const sid = transport.sessionId;
|
|
100
102
|
if (sid) {
|
|
@@ -177,6 +179,17 @@ async function handleMcpRequest(req, res, serverFactory, corsOrigin) {
|
|
|
177
179
|
res.writeHead(405, { 'Content-Type': 'application/json' });
|
|
178
180
|
res.end(JSON.stringify({ error: 'Method not allowed' }));
|
|
179
181
|
}
|
|
182
|
+
function installToolsListCompaction(transport) {
|
|
183
|
+
const originalSend = transport.send.bind(transport);
|
|
184
|
+
const compactingSend = (message) => {
|
|
185
|
+
const outgoing = isToolsListResponse(message)
|
|
186
|
+
? compactToolsListMessage(message)
|
|
187
|
+
: message;
|
|
188
|
+
return originalSend(outgoing);
|
|
189
|
+
};
|
|
190
|
+
const wrappedTransport = transport;
|
|
191
|
+
wrappedTransport.send = compactingSend;
|
|
192
|
+
}
|
|
180
193
|
export async function createHttpTransport(serverFactory, config) {
|
|
181
194
|
const httpServer = createServer((req, res) => {
|
|
182
195
|
void (async () => {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// transport-factory.ts — Parses CLI flags and selects the appropriate MCP transport.
|
|
2
2
|
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
3
3
|
import { createHttpTransport } from './http-transport.js';
|
|
4
|
+
import { compactToolsListMessage, isToolsListResponse, } from '../engine/compact/tool-list-compactor.js';
|
|
4
5
|
const VALID_TRANSPORTS = ['stdio', 'http'];
|
|
5
6
|
const DEFAULT_PORT = 3100;
|
|
6
7
|
const DEFAULT_HOST = '127.0.0.1';
|
|
@@ -40,6 +41,7 @@ export async function selectTransport(server, args, serverFactory) {
|
|
|
40
41
|
const config = parseTransportConfig(args);
|
|
41
42
|
if (config.transport === 'stdio') {
|
|
42
43
|
const transport = new StdioServerTransport();
|
|
44
|
+
installToolsListCompaction(transport);
|
|
43
45
|
await server.connect(transport);
|
|
44
46
|
installStdioShutdownHandlers(server);
|
|
45
47
|
return;
|
|
@@ -48,6 +50,17 @@ export async function selectTransport(server, args, serverFactory) {
|
|
|
48
50
|
const factory = serverFactory ?? (() => server);
|
|
49
51
|
await createHttpTransport(factory, config);
|
|
50
52
|
}
|
|
53
|
+
function installToolsListCompaction(transport) {
|
|
54
|
+
const originalSend = transport.send.bind(transport);
|
|
55
|
+
const compactingSend = (message) => {
|
|
56
|
+
const outgoing = isToolsListResponse(message)
|
|
57
|
+
? compactToolsListMessage(message)
|
|
58
|
+
: message;
|
|
59
|
+
return originalSend(outgoing);
|
|
60
|
+
};
|
|
61
|
+
const wrappedTransport = transport;
|
|
62
|
+
wrappedTransport.send = compactingSend;
|
|
63
|
+
}
|
|
51
64
|
function installStdioShutdownHandlers(server) {
|
|
52
65
|
let shuttingDown = false;
|
|
53
66
|
const shutdown = (reason) => {
|
package/dist/types/qa-gate.d.ts
CHANGED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export type ToolExecutionClass = 'local' | 'hybrid' | 'llm-required';
|
|
2
|
+
export interface ToolClassification {
|
|
3
|
+
toolName: string;
|
|
4
|
+
executionClass: ToolExecutionClass;
|
|
5
|
+
tokenPolicy: 'no-llm' | 'summarize-first' | 'llm-product';
|
|
6
|
+
reason: string;
|
|
7
|
+
}
|
|
8
|
+
//# sourceMappingURL=tool-classification.d.ts.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@planu/cli",
|
|
3
|
-
"version": "4.10.
|
|
3
|
+
"version": "4.10.7",
|
|
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.10.
|
|
38
|
-
"@planu/core-darwin-x64": "4.10.
|
|
39
|
-
"@planu/core-linux-arm64-gnu": "4.10.
|
|
40
|
-
"@planu/core-linux-arm64-musl": "4.10.
|
|
41
|
-
"@planu/core-linux-x64-gnu": "4.10.
|
|
42
|
-
"@planu/core-linux-x64-musl": "4.10.
|
|
43
|
-
"@planu/core-win32-arm64-msvc": "4.10.
|
|
44
|
-
"@planu/core-win32-x64-msvc": "4.10.
|
|
37
|
+
"@planu/core-darwin-arm64": "4.10.7",
|
|
38
|
+
"@planu/core-darwin-x64": "4.10.7",
|
|
39
|
+
"@planu/core-linux-arm64-gnu": "4.10.7",
|
|
40
|
+
"@planu/core-linux-arm64-musl": "4.10.7",
|
|
41
|
+
"@planu/core-linux-x64-gnu": "4.10.7",
|
|
42
|
+
"@planu/core-linux-x64-musl": "4.10.7",
|
|
43
|
+
"@planu/core-win32-arm64-msvc": "4.10.7",
|
|
44
|
+
"@planu/core-win32-x64-msvc": "4.10.7"
|
|
45
45
|
},
|
|
46
46
|
"engines": {
|
|
47
47
|
"node": ">=24.0.0"
|
|
@@ -164,7 +164,7 @@
|
|
|
164
164
|
"tsc-alias": "^1.9.0",
|
|
165
165
|
"type-coverage": "^2.29.7",
|
|
166
166
|
"typescript": "^6.0.3",
|
|
167
|
-
"typescript-eslint": "^8.
|
|
167
|
+
"typescript-eslint": "^8.63.0",
|
|
168
168
|
"vite": "^8.1.3",
|
|
169
169
|
"vitest": "^4.1.10",
|
|
170
170
|
"vue": "^3.5.39"
|
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": "4.10.
|
|
5
|
+
"version": "4.10.7",
|
|
6
6
|
"icon": "assets/plugin/icon.svg",
|
|
7
7
|
"command": [
|
|
8
8
|
"npx",
|