pumuki 6.3.166 → 6.3.167

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 CHANGED
@@ -6,6 +6,12 @@ This project follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [6.3.167] - 2026-05-06
10
+
11
+ ### Fixed
12
+
13
+ - **MCP evidence stdio strict backend gate:** the MCP bridge now uses explicit JSON-RPC constants and requires adapter-provided evidence env vars instead of production defaults, keeping `PRE_PUSH` fail-closed without false backend blockers.
14
+
9
15
  ## [6.3.166] - 2026-05-06
10
16
 
11
17
  ### Fixed
@@ -22,11 +22,30 @@ type JsonRpcResponse = {
22
22
 
23
23
  const MCP_PROTOCOL_VERSION = '2024-11-05';
24
24
  const JSON_RPC_VERSION = '2.0';
25
- const DEFAULT_EVIDENCE_HOST = '127.0.0.1';
26
- const DEFAULT_EVIDENCE_ROUTE = '/ai-evidence';
27
- const DEFAULT_EVIDENCE_PORT = 7341;
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
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';
29
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
+ };
30
49
 
31
50
  const toJsonRpcId = (value: unknown): JsonRpcId => {
32
51
  if (typeof value === 'string' || typeof value === 'number' || value === null) {
@@ -49,7 +68,7 @@ const sendResult = (id: JsonRpcId, result: unknown): void => {
49
68
 
50
69
  const sendError = (id: JsonRpcId, code: number, message: string): void => {
51
70
  sendMessage({
52
- jsonrpc: '2.0',
71
+ jsonrpc: JSON_RPC_VERSION,
53
72
  id,
54
73
  error: {
55
74
  code,
@@ -81,9 +100,10 @@ const findAvailableListenerNumber = async (host: string): Promise<number> =>
81
100
  await new Promise((resolve, reject) => {
82
101
  const probe = createServer();
83
102
  probe.once('error', reject);
84
- probe.listen(0, host, () => {
103
+ probe.listen(EPHEMERAL_LISTENER_PORT, host, () => {
85
104
  const address = probe.address();
86
- const port = address && typeof address === 'object' ? address.port : 0;
105
+ const port =
106
+ address && typeof address === 'object' ? address.port : EPHEMERAL_LISTENER_PORT;
87
107
  probe.close(() => resolve(port));
88
108
  });
89
109
  });
@@ -91,7 +111,7 @@ const findAvailableListenerNumber = async (host: string): Promise<number> =>
91
111
  const fetchJson = async (url: string): Promise<unknown> => {
92
112
  const response = await fetch(url);
93
113
  const text = await response.text();
94
- if (text.trim().length === 0) {
114
+ if (text.trim().length === EMPTY_TEXT_LENGTH) {
95
115
  return {};
96
116
  }
97
117
  return JSON.parse(text) as unknown;
@@ -111,14 +131,17 @@ const startOrReuseEvidenceHttp = async (): Promise<{
111
131
  port: number;
112
132
  route: string;
113
133
  }> => {
114
- const host = process.env.PUMUKI_EVIDENCE_HOST ?? DEFAULT_EVIDENCE_HOST;
115
- const route = process.env.PUMUKI_EVIDENCE_ROUTE ?? DEFAULT_EVIDENCE_ROUTE;
116
- const parsedListener = Number.parseInt(process.env.PUMUKI_EVIDENCE_PORT ?? '', 10);
117
- const preferredListener = Number.isFinite(parsedListener)
118
- ? parsedListener
119
- : DEFAULT_EVIDENCE_PORT;
134
+ const host = readRequiredEnv(EVIDENCE_HOST_ENV);
135
+ const route = readRequiredEnv(EVIDENCE_ROUTE_ENV);
136
+ const parsedListener = Number.parseInt(readRequiredEnv(EVIDENCE_PORT_ENV), DECIMAL_RADIX);
137
+ if (!Number.isFinite(parsedListener)) {
138
+ throw new Error(`${EVIDENCE_PORT_ENV} must be a valid listener number.`);
139
+ }
140
+ const preferredListener = parsedListener;
120
141
  const requestedListener =
121
- preferredListener > 0 ? preferredListener : await findAvailableListenerNumber(host);
142
+ preferredListener > EPHEMERAL_LISTENER_PORT
143
+ ? preferredListener
144
+ : await findAvailableListenerNumber(host);
122
145
  const healthUrl = `http://${host}:${requestedListener}/health`;
123
146
 
124
147
  try {
@@ -228,7 +251,7 @@ const run = async (): Promise<void> => {
228
251
  protocolVersion: MCP_PROTOCOL_VERSION,
229
252
  serverInfo: {
230
253
  name: 'pumuki-evidence-stdio',
231
- version: '1.0.0',
254
+ version: TOOL_IMPLEMENTATION_VERSION,
232
255
  },
233
256
  capabilities: {
234
257
  tools: {
@@ -269,7 +292,7 @@ const run = async (): Promise<void> => {
269
292
  const name = typeof params.name === 'string' ? params.name : '';
270
293
  const tool = toolsCatalog.find((entry) => entry.name === name);
271
294
  if (!tool) {
272
- sendError(id, -32602, `Unknown tool: ${name}`);
295
+ sendError(id, JSON_RPC_INVALID_PARAMS, `Unknown tool: ${name}`);
273
296
  return;
274
297
  }
275
298
  const payload = await fetchJson(`${baseUrl}${tool.path}`);
@@ -304,7 +327,7 @@ const run = async (): Promise<void> => {
304
327
  const uri = typeof params.uri === 'string' ? params.uri : '';
305
328
  const resource = resourcesCatalog.find((entry) => entry.uri === uri);
306
329
  if (!resource) {
307
- sendError(id, -32602, `Unknown resource URI: ${uri}`);
330
+ sendError(id, JSON_RPC_INVALID_PARAMS, `Unknown resource URI: ${uri}`);
308
331
  return;
309
332
  }
310
333
  const payload = await fetchJson(`${baseUrl}${resource.path}`);
@@ -320,31 +343,31 @@ const run = async (): Promise<void> => {
320
343
  return;
321
344
  }
322
345
 
323
- sendError(id, -32601, `Method not found: ${method}`);
346
+ sendError(id, JSON_RPC_METHOD_NOT_FOUND, `Method not found: ${method}`);
324
347
  };
325
348
 
326
349
  const processBuffer = (): void => {
327
350
  while (true) {
328
351
  const lineEnd = textBuffer.indexOf('\n');
329
- if (lineEnd === -1) {
352
+ if (lineEnd === LINE_BREAK_NOT_FOUND) {
330
353
  return;
331
354
  }
332
355
  const rawLine = textBuffer.slice(0, lineEnd).trim();
333
- textBuffer = textBuffer.slice(lineEnd + 1);
334
- if (rawLine.length === 0) {
356
+ textBuffer = textBuffer.slice(lineEnd + LINE_BREAK_WIDTH);
357
+ if (rawLine.length === EMPTY_TEXT_LENGTH) {
335
358
  continue;
336
359
  }
337
360
  let payload: JsonRpcRequest;
338
361
  try {
339
362
  payload = JSON.parse(rawLine) as JsonRpcRequest;
340
363
  } catch {
341
- sendError(null, -32700, 'Parse error');
364
+ sendError(null, JSON_RPC_PARSE_ERROR, 'Parse error');
342
365
  continue;
343
366
  }
344
367
  void handleRequest(payload).catch((error) => {
345
368
  const id = toJsonRpcId(payload.id);
346
369
  const message = error instanceof Error ? error.message : 'Internal error';
347
- sendError(id, -32603, message);
370
+ sendError(id, JSON_RPC_INTERNAL_ERROR, message);
348
371
  });
349
372
  }
350
373
  };
@@ -358,5 +381,5 @@ const run = async (): Promise<void> => {
358
381
  void run().catch((error) => {
359
382
  const message = error instanceof Error ? error.message : 'Unknown MCP stdio bridge error';
360
383
  process.stderr.write(`[pumuki-mcp-evidence-stdio] ${message}\n`);
361
- process.exit(1);
384
+ process.exit(PROCESS_FAILURE_EXIT_CODE);
362
385
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pumuki",
3
- "version": "6.3.166",
3
+ "version": "6.3.167",
4
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": {