pumuki 6.3.117 → 6.3.119

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,19 @@ This project follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [6.3.119] - 2026-04-28
10
+
11
+ ### Fixed
12
+
13
+ - **Contrato CLI estable para menú:** `pumuki menu --help` deja de fallar como comando desconocido y `pumuki menu` delega en el runtime de menú existente (`pumuki-framework`), cerrando `PUMUKI-INC-111` para consumers como RuralGo.
14
+
15
+ ## [6.3.118] - 2026-04-28
16
+
17
+ ### Fixed
18
+
19
+ - **Guard PRE_WRITE para editores/agentes vía MCP:** el catálogo enterprise expone `pre_write_guard`, una tool no mutante que ejecuta `audit --stage=PRE_WRITE --json` y devuelve `findings` accionables antes de permitir continuar una edición/restauración de ficheros.
20
+ - **Cierre operativo de `PUMUKI-INC-109`:** RuralGo ya tiene una ruta MCP explícita para bloquear antes de escribir, no sólo en commit/gate posterior.
21
+
9
22
  ## [6.3.117] - 2026-04-28
10
23
 
11
24
  ### Fixed
package/VERSION CHANGED
@@ -1 +1 @@
1
- v6.3.117
1
+ v6.3.119
@@ -1,4 +1,5 @@
1
1
  import { mkdirSync, writeFileSync } from 'node:fs';
2
+ import { spawnSync } from 'node:child_process';
2
3
  import { dirname, isAbsolute, relative, resolve } from 'node:path';
3
4
  import type { GatePolicy } from '../../core/gate/GatePolicy';
4
5
  import { runPlatformGate } from '../git/runPlatformGate';
@@ -84,6 +85,7 @@ type LifecycleCommand =
84
85
  | 'update'
85
86
  | 'doctor'
86
87
  | 'status'
88
+ | 'menu'
87
89
  | 'watch'
88
90
  | 'loop'
89
91
  | 'sdd'
@@ -190,6 +192,7 @@ Pumuki lifecycle commands:
190
192
  pumuki doctor [--remote-checks] [--deep] [--parity] [--json]
191
193
  pumuki audit [--stage=PRE_WRITE|PRE_COMMIT|PRE_PUSH|CI] [--engine] [--json]
192
194
  pumuki status [--json] [--remote-checks]
195
+ pumuki menu
193
196
  pumuki watch [--stage=PRE_COMMIT|PRE_PUSH|CI] [--scope=workingTree|staged|repoAndStaged|repo] [--severity=critical|high|medium|low] [--interval-ms=<n>] [--notify-cooldown-ms=<n>] [--no-notify] [--once|--iterations=<n>] [--json]
194
197
  pumuki loop run --objective=<text> [--max-attempts=<n>] [--json]
195
198
  pumuki loop status --session=<session-id> [--json]
@@ -229,6 +232,7 @@ const isLifecycleCommand = (value: string): value is LifecycleCommand =>
229
232
  value === 'update' ||
230
233
  value === 'doctor' ||
231
234
  value === 'status' ||
235
+ value === 'menu' ||
232
236
  value === 'watch' ||
233
237
  value === 'loop' ||
234
238
  value === 'sdd' ||
@@ -559,6 +563,19 @@ const printHotspotsPublishDiagnostics = (diagnostics: HotspotsPublishDiagnostics
559
563
  }
560
564
  };
561
565
 
566
+ const runFrameworkMenuShim = (argv: ReadonlyArray<string>): number => {
567
+ const frameworkMenuBin = resolve(__dirname, '../../bin/pumuki-framework.js');
568
+ const result = spawnSync(process.execPath, [frameworkMenuBin, ...argv], {
569
+ stdio: 'inherit',
570
+ env: process.env,
571
+ });
572
+ if (result.error) {
573
+ writeError(`[pumuki] menu failed to start: ${result.error.message}`);
574
+ return 1;
575
+ }
576
+ return typeof result.status === 'number' ? result.status : 1;
577
+ };
578
+
562
579
  export const parseLifecycleCliArgs = (argv: ReadonlyArray<string>): ParsedArgs => {
563
580
  const commandRaw = argv[0];
564
581
  if (!commandRaw || commandRaw === '--help' || commandRaw === '-h') {
@@ -2463,6 +2480,9 @@ export const runLifecycleCli = async (
2463
2480
  }
2464
2481
  return 0;
2465
2482
  }
2483
+ case 'menu': {
2484
+ return runFrameworkMenuShim(argv.slice(1));
2485
+ }
2466
2486
  case 'watch': {
2467
2487
  const watchResult = await activeDependencies.runLifecycleWatch(
2468
2488
  {
@@ -4,7 +4,7 @@ import type { Server } from 'node:http';
4
4
  import { execFileSync as runBinarySync } from 'node:child_process';
5
5
  import { existsSync } from 'node:fs';
6
6
  import { join } from 'node:path';
7
- import { readLifecycleStatus } from '../lifecycle';
7
+ import { readLifecycleStatus, runLifecycleAudit } from '../lifecycle';
8
8
  import { resolveMcpEnterpriseExperimentalFeature } from '../policy/experimentalFeatures';
9
9
  import { evaluateSddPolicy, readSddStatus } from '../sdd';
10
10
  import type { SddStage } from '../sdd';
@@ -75,6 +75,7 @@ const ENTERPRISE_RESOURCE_DESCRIPTORS: ReadonlyArray<{
75
75
  ];
76
76
 
77
77
  const ENTERPRISE_TOOLS = [
78
+ 'pre_write_guard',
78
79
  'ai_gate_check',
79
80
  'pre_flight_check',
80
81
  'auto_execute_ai_start',
@@ -91,6 +92,12 @@ const ENTERPRISE_TOOL_DESCRIPTORS: ReadonlyArray<{
91
92
  mutating: boolean;
92
93
  safeByDefault: boolean;
93
94
  }> = [
95
+ {
96
+ name: 'pre_write_guard',
97
+ description: 'Runs the PRE_WRITE audit gate and returns actionable findings before an editor/agent writes code.',
98
+ mutating: false,
99
+ safeByDefault: true,
100
+ },
94
101
  {
95
102
  name: 'ai_gate_check',
96
103
  description: 'Reads .ai_evidence.json and reports AI gate compatibility status.',
@@ -382,13 +389,41 @@ const evaluateCriticalToolGuard = (
382
389
  }
383
390
  };
384
391
 
385
- const executeEnterpriseTool = (
392
+ const executeEnterpriseTool = async (
386
393
  repoRoot: string,
387
394
  toolName: EnterpriseToolName,
388
395
  args: Record<string, string | number | boolean | bigint | symbol | null | Date | object>,
389
396
  dryRun: boolean
390
- ): EnterpriseToolExecution => {
397
+ ): Promise<EnterpriseToolExecution> => {
391
398
  switch (toolName) {
399
+ case 'pre_write_guard': {
400
+ const audit = await runLifecycleAudit({
401
+ repoRoot,
402
+ stage: 'PRE_WRITE',
403
+ auditMode: 'gate',
404
+ });
405
+ return {
406
+ name: toolName,
407
+ success: audit.gate_exit_code === 0 && audit.blocking_findings_count === 0,
408
+ dryRun: true,
409
+ executed: true,
410
+ warnings: audit.blocking_findings_count > 0
411
+ ? ['PRE_WRITE guard blocked before editor write; inspect result.findings.']
412
+ : [],
413
+ data: {
414
+ ...audit,
415
+ next_action: audit.blocking_findings_count > 0
416
+ ? {
417
+ kind: 'inspect_findings',
418
+ message: 'Corrige los findings bloqueantes antes de escribir o restaurar ficheros.',
419
+ }
420
+ : {
421
+ kind: 'continue',
422
+ message: 'PRE_WRITE guard passed.',
423
+ },
424
+ },
425
+ };
426
+ }
392
427
  case 'ai_gate_check': {
393
428
  const stage = toSddStage(args.stage, 'PRE_COMMIT');
394
429
  const execution = runEnterpriseAiGateCheck({
@@ -741,7 +776,7 @@ export const startEnterpriseMcpServer = (
741
776
  return;
742
777
  }
743
778
  void readJsonBody(req)
744
- .then((body) => {
779
+ .then(async (body) => {
745
780
  if (typeof body !== 'object' || body === null) {
746
781
  sendJson(res, 400, {
747
782
  error: 'Invalid request body.',
@@ -814,7 +849,7 @@ export const startEnterpriseMcpServer = (
814
849
  }
815
850
  let result: EnterpriseToolExecution;
816
851
  try {
817
- result = executeEnterpriseTool(
852
+ result = await executeEnterpriseTool(
818
853
  repoRoot,
819
854
  toolName,
820
855
  args,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pumuki",
3
- "version": "6.3.117",
3
+ "version": "6.3.119",
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": {