pumuki 6.3.170 → 6.3.172
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 +0 -44
- package/README.md +342 -161
- package/VERSION +1 -1
- package/core/facts/detectors/text/ios.test.ts +0 -36
- package/core/facts/detectors/text/ios.ts +0 -24
- package/core/facts/detectors/typescript/index.ts +18 -40
- package/core/facts/extractHeuristicFacts.ts +0 -1
- package/docs/operations/RELEASE_NOTES.md +0 -6
- package/integrations/config/coreSkillsLock.ts +1 -11
- package/integrations/config/skillsRuleSet.ts +1 -0
- package/integrations/git/stageRunners.ts +0 -20
- package/integrations/lifecycle/audit.ts +74 -11
- package/integrations/lifecycle/bootstrapManifest.ts +2 -12
- package/integrations/lifecycle/governanceObservationSnapshot.ts +5 -2
- package/integrations/lifecycle/install.ts +0 -21
- package/integrations/mcp/alignedPlatformGate.ts +2 -6
- package/integrations/mcp/evidenceStdioServer.cli.ts +33 -76
- package/package.json +2 -2
- package/assets/readme/current/01-menu-consumer-real.png +0 -0
- package/assets/readme/current/02-option1-audit-block-real.png +0 -0
- package/assets/readme/current/03-option5-pattern-checks-real.png +0 -0
|
@@ -21,31 +21,6 @@ type JsonRpcResponse = {
|
|
|
21
21
|
};
|
|
22
22
|
|
|
23
23
|
const MCP_PROTOCOL_VERSION = '2024-11-05';
|
|
24
|
-
const JSON_RPC_VERSION = '2.0';
|
|
25
|
-
const EVIDENCE_HOST_ENV = 'PUMUKI_EVIDENCE_HOST';
|
|
26
|
-
const EVIDENCE_ROUTE_ENV = 'PUMUKI_EVIDENCE_ROUTE';
|
|
27
|
-
const EVIDENCE_PORT_ENV = 'PUMUKI_EVIDENCE_PORT';
|
|
28
|
-
const PORT_PROBE_TIMEOUT_MS = 600;
|
|
29
|
-
const EPHEMERAL_LISTENER_PORT = 0;
|
|
30
|
-
const EMPTY_TEXT_LENGTH = 0;
|
|
31
|
-
const DECIMAL_RADIX = 10;
|
|
32
|
-
const PROCESS_FAILURE_EXIT_CODE = 1;
|
|
33
|
-
const LINE_BREAK_WIDTH = 1;
|
|
34
|
-
const TOOL_IMPLEMENTATION_VERSION = '1.0.0';
|
|
35
|
-
const JSON_RPC_INVALID_REQUEST = -32600;
|
|
36
|
-
const JSON_RPC_METHOD_NOT_FOUND = -32601;
|
|
37
|
-
const JSON_RPC_INVALID_PARAMS = -32602;
|
|
38
|
-
const JSON_RPC_INTERNAL_ERROR = -32603;
|
|
39
|
-
const JSON_RPC_PARSE_ERROR = -32700;
|
|
40
|
-
const LINE_BREAK_NOT_FOUND = -1;
|
|
41
|
-
|
|
42
|
-
const readRequiredEnv = (name: string): string => {
|
|
43
|
-
const value = process.env[name];
|
|
44
|
-
if (typeof value === 'string' && value.trim().length > EMPTY_TEXT_LENGTH) {
|
|
45
|
-
return value;
|
|
46
|
-
}
|
|
47
|
-
throw new Error(`${name} is required for pumuki MCP evidence stdio bridge.`);
|
|
48
|
-
};
|
|
49
24
|
|
|
50
25
|
const toJsonRpcId = (value: unknown): JsonRpcId => {
|
|
51
26
|
if (typeof value === 'string' || typeof value === 'number' || value === null) {
|
|
@@ -60,7 +35,7 @@ const sendMessage = (message: JsonRpcResponse): void => {
|
|
|
60
35
|
|
|
61
36
|
const sendResult = (id: JsonRpcId, result: unknown): void => {
|
|
62
37
|
sendMessage({
|
|
63
|
-
jsonrpc:
|
|
38
|
+
jsonrpc: '2.0',
|
|
64
39
|
id,
|
|
65
40
|
result,
|
|
66
41
|
});
|
|
@@ -68,7 +43,7 @@ const sendResult = (id: JsonRpcId, result: unknown): void => {
|
|
|
68
43
|
|
|
69
44
|
const sendError = (id: JsonRpcId, code: number, message: string): void => {
|
|
70
45
|
sendMessage({
|
|
71
|
-
jsonrpc:
|
|
46
|
+
jsonrpc: '2.0',
|
|
72
47
|
id,
|
|
73
48
|
error: {
|
|
74
49
|
code,
|
|
@@ -77,10 +52,10 @@ const sendError = (id: JsonRpcId, code: number, message: string): void => {
|
|
|
77
52
|
});
|
|
78
53
|
};
|
|
79
54
|
|
|
80
|
-
const
|
|
55
|
+
const isPortInUse = async (host: string, port: number): Promise<boolean> =>
|
|
81
56
|
await new Promise((resolve) => {
|
|
82
57
|
const socket = new Socket();
|
|
83
|
-
socket.setTimeout(
|
|
58
|
+
socket.setTimeout(600);
|
|
84
59
|
socket.once('connect', () => {
|
|
85
60
|
socket.destroy();
|
|
86
61
|
resolve(true);
|
|
@@ -96,14 +71,13 @@ const canConnectToAddress = async (host: string, port: number): Promise<boolean>
|
|
|
96
71
|
socket.connect(port, host);
|
|
97
72
|
});
|
|
98
73
|
|
|
99
|
-
const
|
|
74
|
+
const findEphemeralPort = async (host: string): Promise<number> =>
|
|
100
75
|
await new Promise((resolve, reject) => {
|
|
101
76
|
const probe = createServer();
|
|
102
77
|
probe.once('error', reject);
|
|
103
|
-
probe.listen(
|
|
78
|
+
probe.listen(0, host, () => {
|
|
104
79
|
const address = probe.address();
|
|
105
|
-
const port =
|
|
106
|
-
address && typeof address === 'object' ? address.port : EPHEMERAL_LISTENER_PORT;
|
|
80
|
+
const port = address && typeof address === 'object' ? address.port : 0;
|
|
107
81
|
probe.close(() => resolve(port));
|
|
108
82
|
});
|
|
109
83
|
});
|
|
@@ -111,62 +85,45 @@ const findAvailableListenerNumber = async (host: string): Promise<number> =>
|
|
|
111
85
|
const fetchJson = async (url: string): Promise<unknown> => {
|
|
112
86
|
const response = await fetch(url);
|
|
113
87
|
const text = await response.text();
|
|
114
|
-
if (text.trim().length ===
|
|
88
|
+
if (text.trim().length === 0) {
|
|
115
89
|
return {};
|
|
116
90
|
}
|
|
117
91
|
return JSON.parse(text) as unknown;
|
|
118
92
|
};
|
|
119
93
|
|
|
120
|
-
const writeDebugHealthProbeFailure = (error: unknown): void => {
|
|
121
|
-
if (process.env.PUMUKI_DEBUG !== '1') {
|
|
122
|
-
return;
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
126
|
-
process.stderr.write(`[pumuki-mcp-evidence-stdio] health probe fallback: ${message}\n`);
|
|
127
|
-
};
|
|
128
|
-
|
|
129
94
|
const startOrReuseEvidenceHttp = async (): Promise<{
|
|
130
95
|
host: string;
|
|
131
96
|
port: number;
|
|
132
97
|
route: string;
|
|
133
98
|
}> => {
|
|
134
|
-
const host =
|
|
135
|
-
const route =
|
|
136
|
-
const
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
}
|
|
140
|
-
const preferredListener = parsedListener;
|
|
141
|
-
const requestedListener =
|
|
142
|
-
preferredListener > EPHEMERAL_LISTENER_PORT
|
|
143
|
-
? preferredListener
|
|
144
|
-
: await findAvailableListenerNumber(host);
|
|
145
|
-
const healthUrl = `http://${host}:${requestedListener}/health`;
|
|
99
|
+
const host = process.env.PUMUKI_EVIDENCE_HOST ?? '127.0.0.1';
|
|
100
|
+
const route = process.env.PUMUKI_EVIDENCE_ROUTE ?? '/ai-evidence';
|
|
101
|
+
const parsedPort = Number.parseInt(process.env.PUMUKI_EVIDENCE_PORT ?? '', 10);
|
|
102
|
+
const preferredPort = Number.isFinite(parsedPort) ? parsedPort : 7341;
|
|
103
|
+
const requestedPort = preferredPort > 0 ? preferredPort : await findEphemeralPort(host);
|
|
104
|
+
const healthUrl = `http://${host}:${requestedPort}/health`;
|
|
146
105
|
|
|
147
106
|
try {
|
|
148
107
|
const health = (await fetchJson(healthUrl)) as { status?: string };
|
|
149
108
|
if (health.status === 'ok') {
|
|
150
|
-
return { host, port:
|
|
109
|
+
return { host, port: requestedPort, route };
|
|
151
110
|
}
|
|
152
|
-
} catch
|
|
153
|
-
|
|
111
|
+
} catch {
|
|
112
|
+
// ignored
|
|
154
113
|
}
|
|
155
114
|
|
|
156
|
-
const
|
|
157
|
-
const
|
|
158
|
-
? await findAvailableListenerNumber(host)
|
|
159
|
-
: requestedListener;
|
|
115
|
+
const portInUse = await isPortInUse(host, requestedPort);
|
|
116
|
+
const resolvedPort = portInUse ? await findEphemeralPort(host) : requestedPort;
|
|
160
117
|
startEvidenceContextServer({
|
|
161
118
|
host,
|
|
162
|
-
port:
|
|
119
|
+
port: resolvedPort,
|
|
163
120
|
route,
|
|
164
121
|
repoRoot: process.cwd(),
|
|
165
122
|
});
|
|
166
123
|
|
|
167
124
|
return {
|
|
168
125
|
host,
|
|
169
|
-
port:
|
|
126
|
+
port: resolvedPort,
|
|
170
127
|
route,
|
|
171
128
|
};
|
|
172
129
|
};
|
|
@@ -234,8 +191,8 @@ const run = async (): Promise<void> => {
|
|
|
234
191
|
] as const;
|
|
235
192
|
|
|
236
193
|
const handleRequest = async (request: JsonRpcRequest): Promise<void> => {
|
|
237
|
-
if (request.jsonrpc !==
|
|
238
|
-
sendError(toJsonRpcId(request.id),
|
|
194
|
+
if (request.jsonrpc !== '2.0') {
|
|
195
|
+
sendError(toJsonRpcId(request.id), -32600, 'Invalid JSON-RPC version.');
|
|
239
196
|
return;
|
|
240
197
|
}
|
|
241
198
|
|
|
@@ -251,7 +208,7 @@ const run = async (): Promise<void> => {
|
|
|
251
208
|
protocolVersion: MCP_PROTOCOL_VERSION,
|
|
252
209
|
serverInfo: {
|
|
253
210
|
name: 'pumuki-evidence-stdio',
|
|
254
|
-
version:
|
|
211
|
+
version: '1.0.0',
|
|
255
212
|
},
|
|
256
213
|
capabilities: {
|
|
257
214
|
tools: {
|
|
@@ -292,7 +249,7 @@ const run = async (): Promise<void> => {
|
|
|
292
249
|
const name = typeof params.name === 'string' ? params.name : '';
|
|
293
250
|
const tool = toolsCatalog.find((entry) => entry.name === name);
|
|
294
251
|
if (!tool) {
|
|
295
|
-
sendError(id,
|
|
252
|
+
sendError(id, -32602, `Unknown tool: ${name}`);
|
|
296
253
|
return;
|
|
297
254
|
}
|
|
298
255
|
const payload = await fetchJson(`${baseUrl}${tool.path}`);
|
|
@@ -327,7 +284,7 @@ const run = async (): Promise<void> => {
|
|
|
327
284
|
const uri = typeof params.uri === 'string' ? params.uri : '';
|
|
328
285
|
const resource = resourcesCatalog.find((entry) => entry.uri === uri);
|
|
329
286
|
if (!resource) {
|
|
330
|
-
sendError(id,
|
|
287
|
+
sendError(id, -32602, `Unknown resource URI: ${uri}`);
|
|
331
288
|
return;
|
|
332
289
|
}
|
|
333
290
|
const payload = await fetchJson(`${baseUrl}${resource.path}`);
|
|
@@ -343,31 +300,31 @@ const run = async (): Promise<void> => {
|
|
|
343
300
|
return;
|
|
344
301
|
}
|
|
345
302
|
|
|
346
|
-
sendError(id,
|
|
303
|
+
sendError(id, -32601, `Method not found: ${method}`);
|
|
347
304
|
};
|
|
348
305
|
|
|
349
306
|
const processBuffer = (): void => {
|
|
350
307
|
while (true) {
|
|
351
308
|
const lineEnd = textBuffer.indexOf('\n');
|
|
352
|
-
if (lineEnd ===
|
|
309
|
+
if (lineEnd === -1) {
|
|
353
310
|
return;
|
|
354
311
|
}
|
|
355
312
|
const rawLine = textBuffer.slice(0, lineEnd).trim();
|
|
356
|
-
textBuffer = textBuffer.slice(lineEnd +
|
|
357
|
-
if (rawLine.length ===
|
|
313
|
+
textBuffer = textBuffer.slice(lineEnd + 1);
|
|
314
|
+
if (rawLine.length === 0) {
|
|
358
315
|
continue;
|
|
359
316
|
}
|
|
360
317
|
let payload: JsonRpcRequest;
|
|
361
318
|
try {
|
|
362
319
|
payload = JSON.parse(rawLine) as JsonRpcRequest;
|
|
363
320
|
} catch {
|
|
364
|
-
sendError(null,
|
|
321
|
+
sendError(null, -32700, 'Parse error');
|
|
365
322
|
continue;
|
|
366
323
|
}
|
|
367
324
|
void handleRequest(payload).catch((error) => {
|
|
368
325
|
const id = toJsonRpcId(payload.id);
|
|
369
326
|
const message = error instanceof Error ? error.message : 'Internal error';
|
|
370
|
-
sendError(id,
|
|
327
|
+
sendError(id, -32603, message);
|
|
371
328
|
});
|
|
372
329
|
}
|
|
373
330
|
};
|
|
@@ -381,5 +338,5 @@ const run = async (): Promise<void> => {
|
|
|
381
338
|
void run().catch((error) => {
|
|
382
339
|
const message = error instanceof Error ? error.message : 'Unknown MCP stdio bridge error';
|
|
383
340
|
process.stderr.write(`[pumuki-mcp-evidence-stdio] ${message}\n`);
|
|
384
|
-
process.exit(
|
|
341
|
+
process.exit(1);
|
|
385
342
|
});
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pumuki",
|
|
3
|
-
"version": "6.3.
|
|
4
|
-
"description": "Enterprise AST Intelligence
|
|
3
|
+
"version": "6.3.172",
|
|
4
|
+
"description": "Enterprise-grade AST Intelligence System with multi-platform support (iOS, Android, Backend, Frontend) and Feature-First + DDD + Clean Architecture enforcement. Includes dynamic violations API for intelligent querying.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"bin": {
|
|
7
7
|
"pumuki": "bin/pumuki.js",
|
|
Binary file
|
|
Binary file
|
|
Binary file
|