@planu/cli 4.11.9 → 4.12.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 +129 -22
- package/dist/engine/abortable-process-runner.d.ts +8 -0
- package/dist/engine/abortable-process-runner.js +107 -0
- package/dist/engine/cascade-hooks/core/append-releases.d.ts +1 -0
- package/dist/engine/cascade-hooks/core/append-releases.js +51 -14
- package/dist/engine/cascade-hooks/hooks/orchestration-plan.hook.js +16 -21
- package/dist/engine/ci-generator/yaml-builder.js +5 -1
- package/dist/engine/context-md-generator.js +3 -1
- package/dist/engine/criterion-identity.d.ts +6 -0
- package/dist/engine/criterion-identity.js +63 -0
- package/dist/engine/evidence-gates/lifecycle-gate.js +22 -44
- package/dist/engine/evidence-index/index-builder.js +7 -19
- package/dist/engine/frontmatter-parser.d.ts +5 -0
- package/dist/engine/frontmatter-parser.js +24 -0
- package/dist/engine/project-command-runtime.d.ts +5 -0
- package/dist/{tools/validate-runtime.js → engine/project-command-runtime.js} +8 -21
- package/dist/engine/project-graph/builder.js +1 -35
- package/dist/engine/project-graph/cache.js +37 -1
- package/dist/engine/qa-gate.d.ts +4 -1
- package/dist/engine/qa-gate.js +72 -59
- package/dist/engine/safety/cross-process-lock.d.ts +1 -6
- package/dist/engine/safety/cross-process-lock.js +18 -16
- package/dist/engine/safety/lock-scavenger.d.ts +9 -0
- package/dist/engine/safety/lock-scavenger.js +114 -0
- package/dist/engine/session-context-generator.js +24 -2
- package/dist/engine/session-safeguard/learnings-buffer.js +7 -2
- package/dist/engine/session-state/writer.js +15 -8
- package/dist/engine/skill-registry/installer.js +1 -1
- package/dist/engine/spec-format/acceptance-criteria.js +8 -26
- package/dist/engine/spec-grounding/contract.d.ts +3 -1
- package/dist/engine/spec-grounding/contract.js +39 -14
- package/dist/engine/universal-rules/installer.js +2 -2
- package/dist/engine/validation-evidence-digest.d.ts +4 -0
- package/dist/engine/validation-evidence-digest.js +83 -0
- package/dist/engine/validation-evidence-ledger.d.ts +30 -0
- package/dist/engine/validation-evidence-ledger.js +274 -0
- package/dist/engine/validation-impact-planner.d.ts +4 -0
- package/dist/engine/validation-impact-planner.js +71 -0
- package/dist/engine/validator/spec-compliance-runner.d.ts +1 -1
- package/dist/engine/validator/spec-compliance-runner.js +37 -40
- package/dist/engine/validator/validation-report-writer.d.ts +1 -0
- package/dist/engine/validator/validation-report-writer.js +1 -1
- package/dist/engine/validator.js +7 -11
- package/dist/storage/convention-baseline.js +5 -0
- package/dist/storage/session-state-store.js +13 -6
- package/dist/storage/spec-store.d.ts +5 -0
- package/dist/storage/spec-store.js +7 -0
- package/dist/tools/git/git-helpers.d.ts +5 -1
- package/dist/tools/git/git-helpers.js +3 -2
- package/dist/tools/init-project/conventions-writer.js +1 -1
- package/dist/tools/init-project/scaffold-writer.js +1 -1
- package/dist/tools/safe-handler.d.ts +5 -1
- package/dist/tools/safe-handler.js +73 -12
- package/dist/tools/status-handler.d.ts +1 -1
- package/dist/tools/status-handler.js +27 -66
- package/dist/tools/update-status/dod-gates.js +7 -31
- package/dist/tools/update-status/evidence-gate.js +2 -4
- package/dist/tools/update-status/force-done-audit.d.ts +2 -0
- package/dist/tools/update-status/force-done-audit.js +23 -0
- package/dist/tools/update-status/qa-gate.d.ts +1 -0
- package/dist/tools/update-status/qa-gate.js +7 -51
- package/dist/tools/update-status-convention-gate.js +132 -97
- package/dist/tools/validate-lint.d.ts +1 -1
- package/dist/tools/validate-lint.js +78 -165
- package/dist/tools/validate.js +3 -1
- package/dist/transports/http-transport.js +22 -8
- package/dist/transports/mcp-types.d.ts +2 -2
- package/dist/transports/transport-factory.js +110 -12
- package/dist/types/abortable-process.d.ts +26 -0
- package/dist/types/abortable-process.js +2 -0
- package/dist/types/criterion-identity.d.ts +12 -0
- package/dist/types/criterion-identity.js +2 -0
- package/dist/types/index.d.ts +2 -0
- package/dist/types/index.js +2 -0
- package/dist/types/qa-gate.d.ts +0 -5
- package/dist/types/spec-format.d.ts +2 -0
- package/dist/types/spec-lock-v2.d.ts +7 -0
- package/dist/types/validation-evidence.d.ts +62 -0
- package/dist/types/validation-evidence.js +2 -0
- package/package.json +43 -23
- package/planu-native.json +1 -1
- package/planu-plugin.json +1 -1
- package/dist/storage/qa-gate-store.d.ts +0 -4
- package/dist/storage/qa-gate-store.js +0 -24
- package/dist/tools/validate-runtime.d.ts +0 -14
- package/dist/types/data/estimation.d.ts +0 -147
- package/dist/types/data/estimation.js +0 -2
- package/dist/types/data/index.d.ts +0 -5
- package/dist/types/data/index.js +0 -6
- package/dist/types/data/velocity.d.ts +0 -168
- package/dist/types/data/velocity.js +0 -4
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
// http-transport.ts — HTTP transport using SDK's
|
|
1
|
+
// http-transport.ts — HTTP transport using the SDK's Web Standard transport and Hono 2.
|
|
2
2
|
import { createServer } from 'node:http';
|
|
3
3
|
import { randomUUID } from 'node:crypto';
|
|
4
|
-
import {
|
|
4
|
+
import { getRequestListener } from '@hono/node-server';
|
|
5
|
+
import { WebStandardStreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/webStandardStreamableHttp.js';
|
|
5
6
|
import { PLANU_VERSION } from '../config/version.js';
|
|
6
7
|
import { runWithSessionContext } from './session-context.js';
|
|
7
8
|
import { checkHttpRateLimit } from './http-rate-limiter.js';
|
|
@@ -10,6 +11,13 @@ import { compactToolsListMessage, isToolsListResponse, } from '../engine/compact
|
|
|
10
11
|
const MAX_BODY_BYTES = 5 * 1024 * 1024; // 5MB
|
|
11
12
|
const SHUTDOWN_GRACE_MS = 5_000;
|
|
12
13
|
const sessions = new Map();
|
|
14
|
+
async function handleNodeTransportRequest(transport, req, res, parsedBody) {
|
|
15
|
+
// The SDK's Node wrapper pins @hono/node-server 1.x. Adapt the Web Standard
|
|
16
|
+
// transport here so the published package executes against our direct Hono 2 dependency.
|
|
17
|
+
const authInfo = req.auth;
|
|
18
|
+
const listener = getRequestListener((webRequest) => transport.handleRequest(webRequest, { authInfo, parsedBody }), { overrideGlobalObjects: false });
|
|
19
|
+
await listener(req, res);
|
|
20
|
+
}
|
|
13
21
|
function setSecurityHeaders(res) {
|
|
14
22
|
res.setHeader('X-Content-Type-Options', 'nosniff');
|
|
15
23
|
}
|
|
@@ -86,14 +94,14 @@ async function handlePost(req, res, sessionId, serverFactory) {
|
|
|
86
94
|
if (sessionId) {
|
|
87
95
|
const entry = sessions.get(sessionId);
|
|
88
96
|
if (entry) {
|
|
89
|
-
await runWithSessionContext({ sessionId, licenseKey: entry.licenseKey }, () => entry.transport
|
|
97
|
+
await runWithSessionContext({ sessionId, licenseKey: entry.licenseKey }, () => handleNodeTransportRequest(entry.transport, req, res, parsedBody));
|
|
90
98
|
return;
|
|
91
99
|
}
|
|
92
100
|
}
|
|
93
101
|
// Extract per-session license key from HTTP header (hosted multi-tenant mode)
|
|
94
102
|
const licenseKey = req.headers['x-planu-license-key']?.trim() ?? undefined;
|
|
95
103
|
// New session — create transport and connect a new server instance
|
|
96
|
-
const transport = new
|
|
104
|
+
const transport = new WebStandardStreamableHTTPServerTransport({
|
|
97
105
|
sessionIdGenerator: () => randomUUID(),
|
|
98
106
|
});
|
|
99
107
|
installToolsListCompaction(transport);
|
|
@@ -105,7 +113,7 @@ async function handlePost(req, res, sessionId, serverFactory) {
|
|
|
105
113
|
};
|
|
106
114
|
const sessionServer = serverFactory();
|
|
107
115
|
await sessionServer.connect(transport);
|
|
108
|
-
await runWithSessionContext({ sessionId: transport.sessionId ?? sessionId ?? 'unknown', licenseKey }, () => transport
|
|
116
|
+
await runWithSessionContext({ sessionId: transport.sessionId ?? sessionId ?? 'unknown', licenseKey }, () => handleNodeTransportRequest(transport, req, res, parsedBody));
|
|
109
117
|
const newSessionId = transport.sessionId;
|
|
110
118
|
if (newSessionId) {
|
|
111
119
|
sessions.set(newSessionId, { transport, server: sessionServer, licenseKey });
|
|
@@ -149,7 +157,7 @@ async function handleMcpRequest(req, res, serverFactory, corsOrigin) {
|
|
|
149
157
|
if (sessionId) {
|
|
150
158
|
const entry = sessions.get(sessionId);
|
|
151
159
|
if (entry) {
|
|
152
|
-
await runWithSessionContext({ sessionId, licenseKey: entry.licenseKey }, () => entry.transport
|
|
160
|
+
await runWithSessionContext({ sessionId, licenseKey: entry.licenseKey }, () => handleNodeTransportRequest(entry.transport, req, res));
|
|
153
161
|
return;
|
|
154
162
|
}
|
|
155
163
|
}
|
|
@@ -238,8 +246,14 @@ export async function createHttpTransport(serverFactory, config) {
|
|
|
238
246
|
console.error('[Planu] Shutdown complete');
|
|
239
247
|
process.exit(0);
|
|
240
248
|
};
|
|
241
|
-
|
|
242
|
-
|
|
249
|
+
const handleSigint = () => void shutdownGracefully();
|
|
250
|
+
const handleSigterm = () => void shutdownGracefully();
|
|
251
|
+
process.on('SIGINT', handleSigint);
|
|
252
|
+
process.on('SIGTERM', handleSigterm);
|
|
253
|
+
httpServer.once('close', () => {
|
|
254
|
+
process.off('SIGINT', handleSigint);
|
|
255
|
+
process.off('SIGTERM', handleSigterm);
|
|
256
|
+
});
|
|
243
257
|
return new Promise((resolve) => {
|
|
244
258
|
httpServer.listen(config.port, config.host, () => {
|
|
245
259
|
console.error(`Planu MCP server listening on http://${config.host}:${config.port}`);
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { WebStandardStreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/webStandardStreamableHttp.js';
|
|
2
2
|
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
3
3
|
export type McpServerFactory = () => McpServer;
|
|
4
4
|
export interface SessionEntry {
|
|
5
|
-
transport:
|
|
5
|
+
transport: WebStandardStreamableHTTPServerTransport;
|
|
6
6
|
server: McpServer;
|
|
7
7
|
/** Per-session license key from HTTP header (hosted multi-tenant mode) */
|
|
8
8
|
licenseKey?: string;
|
|
@@ -1,10 +1,57 @@
|
|
|
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
|
+
import { execFileSync } from 'node:child_process';
|
|
3
4
|
import { createHttpTransport } from './http-transport.js';
|
|
4
5
|
import { compactToolsListMessage, isToolsListResponse, } from '../engine/compact/tool-list-compactor.js';
|
|
5
6
|
const VALID_TRANSPORTS = ['stdio', 'http'];
|
|
6
7
|
const DEFAULT_PORT = 3100;
|
|
7
8
|
const DEFAULT_HOST = '127.0.0.1';
|
|
9
|
+
const SHUTDOWN_GRACE_MS = 100;
|
|
10
|
+
function descendantPids(parentPid) {
|
|
11
|
+
if (process.platform === 'win32') {
|
|
12
|
+
return [];
|
|
13
|
+
}
|
|
14
|
+
try {
|
|
15
|
+
const rows = execFileSync('ps', ['-A', '-o', 'pid=', '-o', 'ppid='], {
|
|
16
|
+
encoding: 'utf8',
|
|
17
|
+
timeout: 250,
|
|
18
|
+
});
|
|
19
|
+
const children = new Map();
|
|
20
|
+
for (const row of rows.split('\n')) {
|
|
21
|
+
const [pidText, ppidText] = row.trim().split(/\s+/);
|
|
22
|
+
const pid = Number(pidText);
|
|
23
|
+
const ppid = Number(ppidText);
|
|
24
|
+
if (!Number.isInteger(pid) || !Number.isInteger(ppid)) {
|
|
25
|
+
continue;
|
|
26
|
+
}
|
|
27
|
+
children.set(ppid, [...(children.get(ppid) ?? []), pid]);
|
|
28
|
+
}
|
|
29
|
+
const descendants = [];
|
|
30
|
+
const pending = [...(children.get(parentPid) ?? [])];
|
|
31
|
+
while (pending.length > 0) {
|
|
32
|
+
const pid = pending.pop();
|
|
33
|
+
if (pid === undefined) {
|
|
34
|
+
continue;
|
|
35
|
+
}
|
|
36
|
+
descendants.push(pid);
|
|
37
|
+
pending.push(...(children.get(pid) ?? []));
|
|
38
|
+
}
|
|
39
|
+
return descendants.reverse();
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
return [];
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
function signalDescendants(signal) {
|
|
46
|
+
for (const pid of descendantPids(process.pid)) {
|
|
47
|
+
try {
|
|
48
|
+
process.kill(pid, signal);
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
// The child may already have exited.
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
8
55
|
function getFlag(args, name) {
|
|
9
56
|
const prefix = `--${name}=`;
|
|
10
57
|
for (let i = 0; i < args.length; i++) {
|
|
@@ -42,8 +89,14 @@ export async function selectTransport(server, args, serverFactory) {
|
|
|
42
89
|
if (config.transport === 'stdio') {
|
|
43
90
|
const transport = new StdioServerTransport();
|
|
44
91
|
installToolsListCompaction(transport);
|
|
45
|
-
|
|
46
|
-
|
|
92
|
+
const removeShutdownHandlers = installStdioShutdownHandlers(server);
|
|
93
|
+
try {
|
|
94
|
+
await server.connect(transport);
|
|
95
|
+
}
|
|
96
|
+
catch (error) {
|
|
97
|
+
removeShutdownHandlers();
|
|
98
|
+
throw error;
|
|
99
|
+
}
|
|
47
100
|
return;
|
|
48
101
|
}
|
|
49
102
|
// HTTP mode: each session needs its own McpServer instance
|
|
@@ -63,32 +116,77 @@ function installToolsListCompaction(transport) {
|
|
|
63
116
|
}
|
|
64
117
|
function installStdioShutdownHandlers(server) {
|
|
65
118
|
let shuttingDown = false;
|
|
119
|
+
const handlers = new Map();
|
|
120
|
+
const removeHandlers = () => {
|
|
121
|
+
const end = handlers.get('end');
|
|
122
|
+
const close = handlers.get('close');
|
|
123
|
+
const sigterm = handlers.get('SIGTERM');
|
|
124
|
+
const sigint = handlers.get('SIGINT');
|
|
125
|
+
if (end) {
|
|
126
|
+
process.stdin.off('end', end);
|
|
127
|
+
}
|
|
128
|
+
if (close) {
|
|
129
|
+
process.stdin.off('close', close);
|
|
130
|
+
}
|
|
131
|
+
if (sigterm) {
|
|
132
|
+
process.off('SIGTERM', sigterm);
|
|
133
|
+
}
|
|
134
|
+
if (sigint) {
|
|
135
|
+
process.off('SIGINT', sigint);
|
|
136
|
+
}
|
|
137
|
+
};
|
|
66
138
|
const shutdown = (reason) => {
|
|
67
139
|
if (shuttingDown) {
|
|
68
140
|
return;
|
|
69
141
|
}
|
|
70
142
|
shuttingDown = true;
|
|
143
|
+
removeHandlers();
|
|
71
144
|
console.error(`[Planu] MCP stdio ${reason}; shutting down.`);
|
|
72
|
-
|
|
73
|
-
|
|
145
|
+
const hardStop = setTimeout(() => {
|
|
146
|
+
signalDescendants('SIGKILL');
|
|
147
|
+
process.exit(0);
|
|
148
|
+
}, 1_500);
|
|
149
|
+
void import('../tools/safe-handler.js')
|
|
150
|
+
.then(({ abortActiveToolExecutions }) => {
|
|
151
|
+
abortActiveToolExecutions(`MCP stdio ${reason}`);
|
|
152
|
+
signalDescendants('SIGTERM');
|
|
153
|
+
})
|
|
154
|
+
.catch(() => {
|
|
155
|
+
/* shutdown remains best-effort */
|
|
156
|
+
})
|
|
157
|
+
.then(() => Promise.all([
|
|
158
|
+
server.close(),
|
|
159
|
+
new Promise((resolveGrace) => setTimeout(resolveGrace, SHUTDOWN_GRACE_MS)),
|
|
160
|
+
]))
|
|
74
161
|
.catch((err) => {
|
|
75
162
|
console.error('[Planu] Error while closing MCP server:', err);
|
|
76
163
|
})
|
|
77
164
|
.finally(() => {
|
|
165
|
+
clearTimeout(hardStop);
|
|
166
|
+
signalDescendants('SIGKILL');
|
|
78
167
|
process.exit(0);
|
|
79
168
|
});
|
|
80
169
|
};
|
|
81
|
-
|
|
170
|
+
const end = () => {
|
|
82
171
|
shutdown('stdin ended');
|
|
83
|
-
}
|
|
84
|
-
|
|
172
|
+
};
|
|
173
|
+
const close = () => {
|
|
85
174
|
shutdown('stdin closed');
|
|
86
|
-
}
|
|
87
|
-
|
|
175
|
+
};
|
|
176
|
+
const sigterm = () => {
|
|
88
177
|
shutdown('received SIGTERM');
|
|
89
|
-
}
|
|
90
|
-
|
|
178
|
+
};
|
|
179
|
+
const sigint = () => {
|
|
91
180
|
shutdown('received SIGINT');
|
|
92
|
-
}
|
|
181
|
+
};
|
|
182
|
+
handlers.set('end', end);
|
|
183
|
+
handlers.set('close', close);
|
|
184
|
+
handlers.set('SIGTERM', sigterm);
|
|
185
|
+
handlers.set('SIGINT', sigint);
|
|
186
|
+
process.stdin.once('end', end);
|
|
187
|
+
process.stdin.once('close', close);
|
|
188
|
+
process.once('SIGTERM', sigterm);
|
|
189
|
+
process.once('SIGINT', sigint);
|
|
190
|
+
return removeHandlers;
|
|
93
191
|
}
|
|
94
192
|
//# sourceMappingURL=transport-factory.js.map
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export interface AbortableProcessResult {
|
|
2
|
+
stdout: string;
|
|
3
|
+
stderr: string;
|
|
4
|
+
status: number | null;
|
|
5
|
+
signal: NodeJS.Signals | null;
|
|
6
|
+
error?: Error;
|
|
7
|
+
timedOut: boolean;
|
|
8
|
+
aborted: boolean;
|
|
9
|
+
}
|
|
10
|
+
export interface AbortableProcessOptions {
|
|
11
|
+
cwd: string;
|
|
12
|
+
timeoutMs: number;
|
|
13
|
+
maxBufferBytes: number;
|
|
14
|
+
signal?: AbortSignal;
|
|
15
|
+
}
|
|
16
|
+
export interface ProjectCommandPlan {
|
|
17
|
+
requestedCommand: string;
|
|
18
|
+
executedCommand: string;
|
|
19
|
+
executable: string;
|
|
20
|
+
args: string[];
|
|
21
|
+
projectPackageManager: string | null;
|
|
22
|
+
source: 'project-package-manager' | 'host-path';
|
|
23
|
+
runtimeNode: string;
|
|
24
|
+
hint?: string;
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=abortable-process.d.ts.map
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export interface CriterionIdentity {
|
|
2
|
+
id: string;
|
|
3
|
+
text: string;
|
|
4
|
+
normalizedText: string;
|
|
5
|
+
stableKey: string;
|
|
6
|
+
aliases: string[];
|
|
7
|
+
}
|
|
8
|
+
export interface CriterionIdentityOptions {
|
|
9
|
+
index?: number;
|
|
10
|
+
defaultKind?: 'AC' | 'AB';
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=criterion-identity.d.ts.map
|
package/dist/types/index.d.ts
CHANGED
|
@@ -68,6 +68,7 @@ export * from './ci.js';
|
|
|
68
68
|
export * from './spec-templates.js';
|
|
69
69
|
export * from './spec-generator.js';
|
|
70
70
|
export * from './spec-grounding.js';
|
|
71
|
+
export * from './criterion-identity.js';
|
|
71
72
|
export * from './registry.js';
|
|
72
73
|
export * from './tool-groups.js';
|
|
73
74
|
export * from './code-transforms.js';
|
|
@@ -267,6 +268,7 @@ export * from './agent-telemetry.js';
|
|
|
267
268
|
export * from './agent-memory.js';
|
|
268
269
|
export * from './agent-spawner.js';
|
|
269
270
|
export * from './qa-gate.js';
|
|
271
|
+
export * from './validation-evidence.js';
|
|
270
272
|
export * from './project-drift.js';
|
|
271
273
|
export * from './technical-enrichment.js';
|
|
272
274
|
export * from './agent-team.js';
|
package/dist/types/index.js
CHANGED
|
@@ -69,6 +69,7 @@ export * from './ci.js';
|
|
|
69
69
|
export * from './spec-templates.js';
|
|
70
70
|
export * from './spec-generator.js';
|
|
71
71
|
export * from './spec-grounding.js';
|
|
72
|
+
export * from './criterion-identity.js';
|
|
72
73
|
export * from './registry.js';
|
|
73
74
|
export * from './tool-groups.js';
|
|
74
75
|
export * from './code-transforms.js';
|
|
@@ -264,6 +265,7 @@ export * from './agent-telemetry.js';
|
|
|
264
265
|
export * from './agent-memory.js';
|
|
265
266
|
export * from './agent-spawner.js';
|
|
266
267
|
export * from './qa-gate.js';
|
|
268
|
+
export * from './validation-evidence.js';
|
|
267
269
|
export * from './project-drift.js';
|
|
268
270
|
export * from './technical-enrichment.js';
|
|
269
271
|
export * from './agent-team.js';
|
package/dist/types/qa-gate.d.ts
CHANGED
|
@@ -50,4 +50,11 @@ export interface LockInfo extends CrossProcessLockMetadata {
|
|
|
50
50
|
stale: boolean;
|
|
51
51
|
staleReason?: 'heartbeat-expired' | 'ttl-expired' | 'pid-dead';
|
|
52
52
|
}
|
|
53
|
+
/** Observable totals and per-run results from stale lock cleanup. */
|
|
54
|
+
export interface LockScavengeMetrics {
|
|
55
|
+
scavengedLocks: number;
|
|
56
|
+
scavengedBackups: number;
|
|
57
|
+
preservedLive: number;
|
|
58
|
+
preservedCorrupt: number;
|
|
59
|
+
}
|
|
53
60
|
//# sourceMappingURL=spec-lock-v2.d.ts.map
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
export declare const VALIDATION_EVIDENCE_SCHEMA_VERSION: '1.0.0';
|
|
2
|
+
export type ValidationGateCapability = 'typecheck' | 'lint' | 'test-related' | 'test-full' | 'security' | 'native' | 'website' | 'reproducibility';
|
|
3
|
+
export type ValidationEvidenceStatus = 'passed' | 'failed' | 'cancelled' | 'invalidated';
|
|
4
|
+
export interface ValidationEvidenceKeyInput {
|
|
5
|
+
projectPath: string;
|
|
6
|
+
capability: ValidationGateCapability;
|
|
7
|
+
command: string;
|
|
8
|
+
scope: readonly string[];
|
|
9
|
+
relevantPaths?: readonly string[];
|
|
10
|
+
platformDependent?: boolean;
|
|
11
|
+
toolchain?: Partial<ValidationToolchain>;
|
|
12
|
+
}
|
|
13
|
+
export interface ValidationToolchain {
|
|
14
|
+
node: string;
|
|
15
|
+
packageManager: string;
|
|
16
|
+
platform: string;
|
|
17
|
+
architecture: string;
|
|
18
|
+
}
|
|
19
|
+
export interface ValidationEvidenceIdentity {
|
|
20
|
+
schemaVersion: typeof VALIDATION_EVIDENCE_SCHEMA_VERSION;
|
|
21
|
+
capability: ValidationGateCapability;
|
|
22
|
+
normalizedCommand: string;
|
|
23
|
+
sourceTreeDigest: string;
|
|
24
|
+
lockDigest: string;
|
|
25
|
+
configDigest: string;
|
|
26
|
+
toolchainDigest: string;
|
|
27
|
+
selectedScopeDigest: string;
|
|
28
|
+
}
|
|
29
|
+
export interface ValidationEvidenceReceipt {
|
|
30
|
+
schemaVersion: typeof VALIDATION_EVIDENCE_SCHEMA_VERSION;
|
|
31
|
+
key: string;
|
|
32
|
+
identity: ValidationEvidenceIdentity;
|
|
33
|
+
producer: string;
|
|
34
|
+
status: ValidationEvidenceStatus;
|
|
35
|
+
durationMs: number;
|
|
36
|
+
outputDigest: string;
|
|
37
|
+
reason: string;
|
|
38
|
+
source: string;
|
|
39
|
+
completedAt: string;
|
|
40
|
+
timeSavedMs: number;
|
|
41
|
+
}
|
|
42
|
+
export interface ValidationEvidenceAudit {
|
|
43
|
+
key: string;
|
|
44
|
+
capability: ValidationGateCapability;
|
|
45
|
+
action: 'executed' | 'reused' | 'skipped' | 'invalidated' | 'aborted';
|
|
46
|
+
producer: string;
|
|
47
|
+
status: ValidationEvidenceStatus;
|
|
48
|
+
durationMs: number;
|
|
49
|
+
outputDigest: string;
|
|
50
|
+
reason: string;
|
|
51
|
+
source: string;
|
|
52
|
+
completedAt: string;
|
|
53
|
+
timeSavedMs: number;
|
|
54
|
+
}
|
|
55
|
+
export interface ValidationImpactPlan {
|
|
56
|
+
kind: 'none' | 'lifecycle' | 'source' | 'dependency' | 'native' | 'website' | 'full';
|
|
57
|
+
gates: ValidationGateCapability[];
|
|
58
|
+
heavy: boolean;
|
|
59
|
+
reason: string;
|
|
60
|
+
changedPaths: string[];
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=validation-evidence.d.ts.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@planu/cli",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.12.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.
|
|
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.12.2",
|
|
38
|
+
"@planu/core-darwin-x64": "4.12.2",
|
|
39
|
+
"@planu/core-linux-arm64-gnu": "4.12.2",
|
|
40
|
+
"@planu/core-linux-arm64-musl": "4.12.2",
|
|
41
|
+
"@planu/core-linux-x64-gnu": "4.12.2",
|
|
42
|
+
"@planu/core-linux-x64-musl": "4.12.2",
|
|
43
|
+
"@planu/core-win32-arm64-msvc": "4.12.2",
|
|
44
|
+
"@planu/core-win32-x64-msvc": "4.12.2"
|
|
45
45
|
},
|
|
46
46
|
"engines": {
|
|
47
47
|
"node": ">=24.0.0"
|
|
@@ -72,10 +72,21 @@
|
|
|
72
72
|
"test:watch": "vitest",
|
|
73
73
|
"test:coverage": "vitest run --coverage --exclude 'tests/integration/**'",
|
|
74
74
|
"test:integration": "vitest run tests/integration",
|
|
75
|
+
"test:website:unit": "vitest run tests/website tests/scripts/generate-website-proof.test.ts tests/scripts/website-tool-counts.test.ts",
|
|
76
|
+
"test:website:browser": "playwright test --config playwright.website.config.ts",
|
|
77
|
+
"test:website:lighthouse": "lhci autorun --config=.lighthouserc.cjs",
|
|
78
|
+
"test:website:lighthouse:production": "PLANU_LIGHTHOUSE_PRODUCTION=1 lhci autorun --config=.lighthouserc.cjs",
|
|
75
79
|
"native:project-graph:e2e": "PLANU_NATIVE_E2E=1 vitest run tests/integration/native-project-graph-e2e.test.ts",
|
|
76
80
|
"native:project-graph:benchmark": "node scripts/benchmark-native-performance.mjs --operation project_graph_query --samples 5 --project-path . --spec-id SPEC-1119 --json",
|
|
77
|
-
"check": "pnpm typecheck && pnpm lint && pnpm format:check",
|
|
78
|
-
"check:strict": "pnpm
|
|
81
|
+
"check": "pnpm typecheck && pnpm lint && pnpm format:check && pnpm check:public-privacy && pnpm check:website-proof && pnpm check:donation-assets && pnpm check:website-public-assets",
|
|
82
|
+
"check:strict": "pnpm check && pnpm audit:deadcode && pnpm audit:circular && pnpm audit:types && pnpm audit:security && pnpm audit:licenses && pnpm audit:i18n",
|
|
83
|
+
"check:website-public-assets": "node scripts/check-website-public-assets.mjs",
|
|
84
|
+
"check:public-privacy": "node scripts/check-public-privacy.mjs",
|
|
85
|
+
"generate:website-proof": "node scripts/generate-website-proof.mjs",
|
|
86
|
+
"generate:donation-assets": "node scripts/generate-crypto-donation-assets.mjs",
|
|
87
|
+
"check:donation-assets": "node scripts/generate-crypto-donation-assets.mjs --check",
|
|
88
|
+
"check:website-proof": "node scripts/generate-website-proof.mjs --check",
|
|
89
|
+
"check:website": "pnpm check:public-privacy && pnpm check:website-proof && pnpm check:donation-assets && pnpm check:website-public-assets && pnpm test:website:unit && pnpm test:website:browser",
|
|
79
90
|
"check:deps:fresh": "bash scripts/check-dependency-freshness.sh",
|
|
80
91
|
"audit:deadcode": "knip",
|
|
81
92
|
"audit:circular": "madge --circular --extensions ts src/",
|
|
@@ -133,43 +144,52 @@
|
|
|
133
144
|
],
|
|
134
145
|
"license": "SEE LICENSE IN LICENSE",
|
|
135
146
|
"dependencies": {
|
|
136
|
-
"@anthropic-ai/sdk": "^0.
|
|
147
|
+
"@anthropic-ai/sdk": "^0.115.0",
|
|
148
|
+
"@hono/node-server": "2.0.11",
|
|
137
149
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
138
150
|
"glob": "^13.0.6",
|
|
139
151
|
"yaml": "^2.9.0",
|
|
140
152
|
"zod": "^4.4.3"
|
|
141
153
|
},
|
|
142
154
|
"devDependencies": {
|
|
155
|
+
"@axe-core/playwright": "4.12.1",
|
|
143
156
|
"@commitlint/cli": "^21.2.1",
|
|
144
157
|
"@commitlint/config-conventional": "^21.2.0",
|
|
145
158
|
"@eslint/js": "^10.0.1",
|
|
146
|
-
"@
|
|
147
|
-
"@
|
|
148
|
-
"@
|
|
159
|
+
"@lhci/cli": "0.15.1",
|
|
160
|
+
"@napi-rs/cli": "^3.7.4",
|
|
161
|
+
"@noble/hashes": "2.2.0",
|
|
162
|
+
"@playwright/test": "1.62.0",
|
|
163
|
+
"@scure/base": "2.2.0",
|
|
164
|
+
"@secretlint/secretlint-rule-no-homedir": "^13.0.4",
|
|
165
|
+
"@secretlint/secretlint-rule-preset-recommend": "^13.0.4",
|
|
149
166
|
"@stryker-mutator/core": "^9.6.1",
|
|
150
167
|
"@stryker-mutator/vitest-runner": "^9.6.1",
|
|
151
|
-
"@supabase/supabase-js": "^2.110.
|
|
168
|
+
"@supabase/supabase-js": "^2.110.8",
|
|
152
169
|
"@types/node": "^26.1.1",
|
|
170
|
+
"@types/qrcode": "1.5.6",
|
|
153
171
|
"@typescript/native": "npm:typescript@^7.0.2",
|
|
154
172
|
"@vitejs/plugin-vue": "^6.0.8",
|
|
155
173
|
"@vitest/coverage-v8": "^4.1.10",
|
|
156
174
|
"@vue/test-utils": "^2.4.11",
|
|
157
|
-
"eslint": "
|
|
175
|
+
"eslint": "10.8.0",
|
|
158
176
|
"eslint-config-prettier": "^10.1.8",
|
|
159
177
|
"eslint-import-resolver-typescript": "^4.4.5",
|
|
160
178
|
"eslint-plugin-import": "^2.32.0",
|
|
161
|
-
"happy-dom": "^20.11.
|
|
179
|
+
"happy-dom": "^20.11.1",
|
|
162
180
|
"husky": "^9.1.7",
|
|
163
181
|
"javascript-obfuscator": "^5.5.0",
|
|
164
|
-
"
|
|
165
|
-
"
|
|
182
|
+
"jiti": "2.7.0",
|
|
183
|
+
"knip": "^6.29.0",
|
|
184
|
+
"lint-staged": "^17.2.0",
|
|
166
185
|
"madge": "^8.0.0",
|
|
167
|
-
"prettier": "^3.9.
|
|
168
|
-
"
|
|
186
|
+
"prettier": "^3.9.6",
|
|
187
|
+
"qrcode": "1.5.4",
|
|
188
|
+
"secretlint": "^13.0.4",
|
|
169
189
|
"tsc-alias": "^1.9.1",
|
|
170
190
|
"type-coverage": "^2.29.7",
|
|
171
191
|
"typescript": "npm:@typescript/typescript6@^6.0.2",
|
|
172
|
-
"typescript-eslint": "^8.
|
|
192
|
+
"typescript-eslint": "^8.65.0",
|
|
173
193
|
"vite": "^8.1.5",
|
|
174
194
|
"vitest": "^4.1.10",
|
|
175
195
|
"vue": "^3.5.40"
|
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.
|
|
5
|
+
"version": "4.12.2",
|
|
6
6
|
"icon": "assets/plugin/icon.svg",
|
|
7
7
|
"command": [
|
|
8
8
|
"npx",
|
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
import type { QaGateState, QaGateResult } from '../types/qa-gate.js';
|
|
2
|
-
export declare function saveGateState(projectPath: string, specId: string, result: QaGateResult): Promise<void>;
|
|
3
|
-
export declare function getGateState(projectPath: string, specId: string): Promise<QaGateState | null>;
|
|
4
|
-
//# sourceMappingURL=qa-gate-store.d.ts.map
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
// storage/qa-gate-store.ts — SPEC-642
|
|
2
|
-
import { readFile, writeFile, mkdir } from 'node:fs/promises';
|
|
3
|
-
import { join, dirname } from 'node:path';
|
|
4
|
-
import { safeJsonParse } from './base-store.js';
|
|
5
|
-
function gatePath(projectPath, specId) {
|
|
6
|
-
return join(projectPath, '.planu', 'qa-gate', `${specId}.json`);
|
|
7
|
-
}
|
|
8
|
-
export async function saveGateState(projectPath, specId, result) {
|
|
9
|
-
const path = gatePath(projectPath, specId);
|
|
10
|
-
await mkdir(dirname(path), { recursive: true });
|
|
11
|
-
const state = { specId, lastResult: result, fingerprint: result.fingerprint };
|
|
12
|
-
await writeFile(path, JSON.stringify(state, null, 2), 'utf-8');
|
|
13
|
-
}
|
|
14
|
-
export async function getGateState(projectPath, specId) {
|
|
15
|
-
try {
|
|
16
|
-
const raw = await readFile(gatePath(projectPath, specId), 'utf-8');
|
|
17
|
-
const parsed = safeJsonParse(raw, null);
|
|
18
|
-
return parsed && typeof parsed === 'object' && 'specId' in parsed ? parsed : null;
|
|
19
|
-
}
|
|
20
|
-
catch {
|
|
21
|
-
return null;
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
//# sourceMappingURL=qa-gate-store.js.map
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
export interface ProjectCommandPlan {
|
|
2
|
-
requestedCommand: string;
|
|
3
|
-
executedCommand: string;
|
|
4
|
-
executable: string;
|
|
5
|
-
args: string[];
|
|
6
|
-
projectPackageManager: string | null;
|
|
7
|
-
source: 'project-package-manager' | 'host-path';
|
|
8
|
-
runtimeNode: string;
|
|
9
|
-
hint?: string;
|
|
10
|
-
}
|
|
11
|
-
export declare function resolveProjectCommandPlan(projectPath: string, requestedCommand: string, corepackAvailable?: boolean): ProjectCommandPlan;
|
|
12
|
-
export declare function formatLintFailureDiagnostics(plan: ProjectCommandPlan, output: string): string;
|
|
13
|
-
export declare function runProjectCommandPlan(plan: ProjectCommandPlan, projectPath: string, timeoutMs: number): void;
|
|
14
|
-
//# sourceMappingURL=validate-runtime.d.ts.map
|