pumuki 6.3.96 → 6.3.98

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.
Files changed (95) hide show
  1. package/AGENTS.md +269 -0
  2. package/CHANGELOG.md +688 -0
  3. package/README.md +4 -2
  4. package/VERSION +1 -1
  5. package/docs/README.md +13 -9
  6. package/docs/operations/RELEASE_NOTES.md +9 -74
  7. package/docs/product/HOW_IT_WORKS.md +6 -0
  8. package/docs/product/INSTALLATION.md +1 -1
  9. package/docs/product/USAGE.md +41 -4
  10. package/docs/tracking/plan-curso-pumuki-stack-my-architecture.md +118 -0
  11. package/docs/validation/README.md +6 -3
  12. package/integrations/config/skillsCustomRules.ts +18 -99
  13. package/integrations/evidence/buildEvidence.ts +0 -24
  14. package/integrations/evidence/repoState.ts +0 -3
  15. package/integrations/evidence/schema.ts +0 -18
  16. package/integrations/evidence/writeEvidence.ts +0 -24
  17. package/integrations/gate/evaluateAiGate.ts +15 -232
  18. package/integrations/gate/remediationCatalog.ts +0 -8
  19. package/integrations/git/GitService.ts +44 -5
  20. package/integrations/git/aiGateRepoPolicyFindings.ts +0 -4
  21. package/integrations/git/runPlatformGate.ts +1 -9
  22. package/integrations/git/runPlatformGateFacts.ts +19 -1
  23. package/integrations/git/runPlatformGateOutput.ts +27 -36
  24. package/integrations/lifecycle/adapter.templates.json +1 -0
  25. package/integrations/lifecycle/adapter.ts +0 -24
  26. package/integrations/lifecycle/artifacts.ts +1 -6
  27. package/integrations/lifecycle/audit.ts +101 -0
  28. package/integrations/lifecycle/cli.ts +110 -70
  29. package/integrations/lifecycle/cliSdd.ts +13 -8
  30. package/integrations/lifecycle/doctor.ts +16 -48
  31. package/integrations/lifecycle/hookManager.ts +0 -77
  32. package/integrations/lifecycle/index.ts +2 -0
  33. package/integrations/lifecycle/install.ts +0 -21
  34. package/integrations/lifecycle/npmService.ts +3 -155
  35. package/integrations/lifecycle/preWriteAutomation.ts +7 -77
  36. package/integrations/lifecycle/state.ts +1 -8
  37. package/integrations/lifecycle/status.ts +2 -29
  38. package/integrations/mcp/aiGateCheck.ts +26 -206
  39. package/integrations/mcp/autoExecuteAiStart.ts +85 -92
  40. package/integrations/mcp/enterpriseServer.ts +7 -23
  41. package/integrations/mcp/enterpriseStdioServer.cli.ts +4 -31
  42. package/integrations/mcp/preFlightCheck.ts +5 -51
  43. package/integrations/platform/detectPlatforms.ts +37 -0
  44. package/integrations/policy/experimentalFeatures.ts +1 -1
  45. package/integrations/sdd/evidenceScaffold.ts +2 -109
  46. package/package.json +10 -2
  47. package/scripts/check-tracking-single-active.sh +1 -1
  48. package/scripts/consumer-menu-matrix-baseline-report-lib.ts +13 -38
  49. package/scripts/consumer-postinstall-resolve-args.cjs +44 -0
  50. package/scripts/consumer-postinstall.cjs +76 -21
  51. package/scripts/framework-menu-advanced-view-lib.ts +0 -15
  52. package/scripts/framework-menu-consumer-actions-lib.ts +28 -4
  53. package/scripts/framework-menu-consumer-preflight-hints.ts +5 -2
  54. package/scripts/framework-menu-consumer-preflight-render.ts +0 -10
  55. package/scripts/framework-menu-consumer-preflight-run.ts +0 -23
  56. package/scripts/framework-menu-consumer-preflight-types.ts +0 -12
  57. package/scripts/framework-menu-consumer-runtime-actions.ts +87 -17
  58. package/scripts/framework-menu-consumer-runtime-audit.ts +36 -2
  59. package/scripts/framework-menu-consumer-runtime-evidence-classic.ts +140 -0
  60. package/scripts/framework-menu-consumer-runtime-lib.ts +2 -10
  61. package/scripts/framework-menu-consumer-runtime-menu.ts +4 -18
  62. package/scripts/framework-menu-consumer-runtime-types.ts +3 -3
  63. package/scripts/framework-menu-evidence-summary-lib.ts +1 -0
  64. package/scripts/framework-menu-evidence-summary-read.ts +57 -5
  65. package/scripts/framework-menu-evidence-summary-severity.ts +3 -1
  66. package/scripts/framework-menu-evidence-summary-types.ts +7 -0
  67. package/scripts/framework-menu-gate-lib.ts +9 -0
  68. package/scripts/framework-menu-layout-data.ts +5 -0
  69. package/scripts/framework-menu-matrix-baseline-lib.ts +15 -14
  70. package/scripts/framework-menu-matrix-canary-lib.ts +22 -1
  71. package/scripts/framework-menu-matrix-evidence-lib.ts +1 -0
  72. package/scripts/framework-menu-matrix-evidence-types.ts +13 -1
  73. package/scripts/framework-menu-matrix-runner-lib.ts +35 -0
  74. package/scripts/framework-menu-system-notifications-cause.ts +0 -24
  75. package/scripts/framework-menu-system-notifications-macos-swift-source.ts +24 -204
  76. package/scripts/framework-menu-system-notifications-macos.ts +4 -0
  77. package/scripts/framework-menu-system-notifications-payloads-blocked.ts +1 -1
  78. package/scripts/framework-menu-system-notifications-remediation.ts +13 -24
  79. package/scripts/framework-menu-system-notifications-text.ts +1 -7
  80. package/scripts/framework-menu.ts +3 -2
  81. package/scripts/package-install-smoke-consumer-git-repo-lib.ts +1 -10
  82. package/scripts/package-install-smoke-consumer-npm-lib.ts +9 -46
  83. package/scripts/pumuki-full-surface-smoke-lib.ts +37 -0
  84. package/scripts/pumuki-full-surface-smoke.ts +346 -0
  85. package/scripts/pumuki-smoke-installed-wrapper.cjs +31 -0
  86. package/integrations/evidence/trackingContract.ts +0 -150
  87. package/integrations/gate/governanceActionCatalog.ts +0 -275
  88. package/integrations/lifecycle/bootstrapManifest.ts +0 -248
  89. package/integrations/lifecycle/cliGovernanceConsole.ts +0 -69
  90. package/integrations/lifecycle/governanceNextAction.ts +0 -164
  91. package/integrations/lifecycle/governanceObservationSnapshot.ts +0 -613
  92. package/integrations/mcp/alignedPlatformGate.ts +0 -232
  93. package/integrations/mcp/readMcpPrePushStdin.ts +0 -7
  94. package/scripts/build-ruralgo-s1-evidence-pack.ts +0 -85
  95. package/scripts/ruralgo-s1-evidence-pack-lib.ts +0 -200
@@ -1,14 +1,11 @@
1
- import {
2
- resolveGovernanceCatalogAction,
3
- type GovernanceCatalogNextAction,
4
- } from '../gate/governanceActionCatalog';
5
1
  import { evaluateAiGate, type AiGateStage, type AiGateViolation } from '../gate/evaluateAiGate';
6
2
  import { collectWorktreeAtomicSlices } from '../git/worktreeAtomicSlices';
7
3
  import { resolveLearningContextExperimentalFeature } from '../policy/experimentalFeatures';
8
4
  import { readSddLearningContext, type SddLearningContext } from '../sdd/learningInsights';
9
5
 
10
6
  const ACTIONABLE_HINTS_BY_CODE: Readonly<Record<string, string>> = {
11
- EVIDENCE_MISSING: 'Ejecuta una auditoría (1/2/3/4) para regenerar .ai_evidence.json.',
7
+ EVIDENCE_MISSING:
8
+ 'Ejecuta una auditoría (1/2/3/4 u opciones de motor 11–14) para regenerar .ai_evidence.json.',
12
9
  EVIDENCE_INVALID: 'Regenera .ai_evidence.json desde una opción de auditoría.',
13
10
  EVIDENCE_INTEGRITY_MISSING: 'Refresca evidencia para regenerar metadatos de integridad.',
14
11
  EVIDENCE_ACTIVE_RULE_IDS_EMPTY_FOR_CODE_CHANGES:
@@ -42,28 +39,6 @@ const ACTIONABLE_HINTS_BY_CODE: Readonly<Record<string, string>> = {
42
39
  'Mapea todas las reglas AUTO a detectores AST antes de continuar.',
43
40
  EVIDENCE_TIMESTAMP_FUTURE: 'Corrige la hora del sistema y regenera evidencia.',
44
41
  GITFLOW_PROTECTED_BRANCH: 'Evita trabajo directo en ramas protegidas (usa feature/*).',
45
- GITFLOW_BRANCH_NAMING_INVALID:
46
- 'La rama actual no cumple GitFlow. Usa feature/*, bugfix/*, hotfix/*, release/*, chore/*, refactor/* o docs/*.',
47
- TRACKING_CANONICAL_SOURCE_CONFLICT:
48
- 'AGENTS.md y los README del repo no apuntan a la misma fuente canónica de tracking.',
49
- TRACKING_CANONICAL_FILE_MISSING:
50
- 'El repo declara un MD de tracking canónico que ahora mismo no existe.',
51
- TRACKING_CANONICAL_IN_PROGRESS_INVALID:
52
- 'El MD canónico de tracking debe dejar exactamente una task o fase en construcción.',
53
- };
54
-
55
- const normalizeGovernanceCatalogCode = (code: string): string => {
56
- switch (code) {
57
- case 'EVIDENCE_INVALID':
58
- case 'EVIDENCE_CHAIN_INVALID':
59
- return 'EVIDENCE_INVALID_OR_CHAIN';
60
- case 'GITFLOW_PROTECTED_BRANCH':
61
- return 'GITFLOW_PROTECTED_BRANCH_CONTEXT';
62
- case 'GITFLOW_BRANCH_NAMING_INVALID':
63
- return 'GITFLOW_BRANCH_NAMING_INVALID_CONTEXT';
64
- default:
65
- return code;
66
- }
67
42
  };
68
43
 
69
44
  const buildPreFlightHints = (params: {
@@ -140,8 +115,6 @@ export type EnterprisePreFlightCheckResult = {
140
115
  phase: 'GREEN' | 'RED';
141
116
  message: string;
142
117
  instruction: string;
143
- reason_code: string;
144
- next_action: GovernanceCatalogNextAction;
145
118
  stage: ReturnType<typeof evaluateAiGate>['stage'];
146
119
  policy: ReturnType<typeof evaluateAiGate>['policy'];
147
120
  violations: ReturnType<typeof evaluateAiGate>['violations'];
@@ -181,30 +154,13 @@ export const runEnterprisePreFlightCheck = (params: {
181
154
  upstream: evaluation.repo_state.git.upstream,
182
155
  learningContext,
183
156
  });
184
- const firstViolation = evaluation.violations[0];
185
- const reasonCode = firstViolation?.code ?? 'READY';
186
- const governanceAction = firstViolation
187
- ? resolveGovernanceCatalogAction({
188
- code: normalizeGovernanceCatalogCode(firstViolation.code),
189
- stage: evaluation.stage,
190
- })
191
- : resolveGovernanceCatalogAction({
192
- code: 'READY',
193
- stage: evaluation.stage,
194
- });
195
157
  const phase: 'GREEN' | 'RED' = evaluation.allowed ? 'GREEN' : 'RED';
196
158
  const message = evaluation.allowed
197
159
  ? '✅ Pre-flight aprobado: puedes continuar con la implementación.'
198
- : `🔴 Pre-flight bloqueado: corrige ${reasonCode} y vuelve a ejecutar.`;
199
- const instruction = !firstViolation && evaluation.allowed
160
+ : `🔴 Pre-flight bloqueado: corrige ${evaluation.violations[0]?.code ?? 'la causa'} y vuelve a ejecutar.`;
161
+ const instruction = evaluation.allowed
200
162
  ? 'Implementa el cambio mínimo para pasar en verde y vuelve a validar.'
201
- : governanceAction.instruction;
202
- const nextAction: GovernanceCatalogNextAction = evaluation.allowed
203
- ? {
204
- kind: 'info',
205
- message: governanceAction.next_action.message,
206
- }
207
- : governanceAction.next_action;
163
+ : hints[0] ?? 'Corrige la causa bloqueante y vuelve a ejecutar el pre-flight.';
208
164
 
209
165
  return {
210
166
  tool: 'pre_flight_check',
@@ -217,8 +173,6 @@ export const runEnterprisePreFlightCheck = (params: {
217
173
  phase,
218
174
  message,
219
175
  instruction,
220
- reason_code: reasonCode,
221
- next_action: nextAction,
222
176
  stage: evaluation.stage,
223
177
  policy: evaluation.policy,
224
178
  violations: evaluation.violations,
@@ -51,6 +51,38 @@ const collectFilePaths = (facts: ReadonlyArray<Fact>): string[] => {
51
51
  .filter((path): path is string => typeof path === 'string');
52
52
  };
53
53
 
54
+ const ALLOWED_PIN_KEYS = new Set(['ios', 'android', 'backend', 'frontend']);
55
+
56
+ const readPinnedPlatformsFromEnv = (): ReadonlySet<keyof DetectedPlatforms> | null => {
57
+ const raw = process.env.PUMUKI_PIN_PLATFORMS?.trim().toLowerCase();
58
+ if (!raw) {
59
+ return null;
60
+ }
61
+ const tokens = raw
62
+ .split(',')
63
+ .map((token) => token.trim())
64
+ .filter((token) => token.length > 0)
65
+ .filter((token) => ALLOWED_PIN_KEYS.has(token)) as Array<keyof DetectedPlatforms>;
66
+ if (tokens.length === 0) {
67
+ return null;
68
+ }
69
+ return new Set(tokens);
70
+ };
71
+
72
+ const applyPinnedPlatformsFilter = (
73
+ detected: DetectedPlatforms,
74
+ pin: ReadonlySet<keyof DetectedPlatforms>
75
+ ): DetectedPlatforms => {
76
+ const next: DetectedPlatforms = {};
77
+ for (const key of pin) {
78
+ const state = detected[key];
79
+ if (state) {
80
+ next[key] = state;
81
+ }
82
+ }
83
+ return next;
84
+ };
85
+
54
86
  export const detectPlatformsFromFacts = (
55
87
  facts: ReadonlyArray<Fact>
56
88
  ): DetectedPlatforms => {
@@ -102,5 +134,10 @@ export const detectPlatformsFromFacts = (
102
134
  };
103
135
  }
104
136
 
137
+ const pin = readPinnedPlatformsFromEnv();
138
+ if (pin && pin.size > 0) {
139
+ return applyPinnedPlatformsFilter(result, pin);
140
+ }
141
+
105
142
  return result;
106
143
  };
@@ -40,7 +40,7 @@ type ExperimentalFeatureConfig = {
40
40
 
41
41
  const EXPERIMENTAL_FEATURES: Record<ExperimentalFeatureId, ExperimentalFeatureConfig> = {
42
42
  pre_write: {
43
- defaultMode: 'strict',
43
+ defaultMode: 'off',
44
44
  activationVariable: 'PUMUKI_EXPERIMENTAL_PRE_WRITE',
45
45
  legacyActivationVariable: 'PUMUKI_PREWRITE_ENFORCEMENT',
46
46
  },
@@ -1,5 +1,5 @@
1
1
  import { createHash } from 'node:crypto';
2
- import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
2
+ import { mkdirSync, writeFileSync } from 'node:fs';
3
3
  import { basename, dirname, isAbsolute, relative, resolve } from 'node:path';
4
4
  import { readEvidenceResult, type EvidenceReadResult } from '../evidence/readEvidence';
5
5
 
@@ -15,7 +15,6 @@ export type SddEvidenceScaffoldResult = {
15
15
  testStatus: SddEvidenceScaffoldTestStatus;
16
16
  testOutputPath: string | null;
17
17
  fromEvidencePath: string | null;
18
- traceabilityMarkdownPath: string | null;
19
18
  };
20
19
  output: {
21
20
  path: string;
@@ -45,13 +44,6 @@ export type SddEvidenceScaffoldResult = {
45
44
  source: 'pumuki-sdd-evidence';
46
45
  stack: 'sdd-evidence-scaffold';
47
46
  };
48
- traceability: {
49
- required: boolean;
50
- path: string | null;
51
- header_present: boolean;
52
- rows: number;
53
- status: 'valid';
54
- };
55
47
  // Legacy fields kept for state-sync compatibility in existing consumers.
56
48
  scenario_id: string;
57
49
  test_run: {
@@ -73,13 +65,10 @@ export type SddEvidenceScaffoldResult = {
73
65
  const computeDigest = (value: string): string =>
74
66
  `sha256:${createHash('sha256').update(value, 'utf8').digest('hex')}`;
75
67
 
76
- const TRACEABILITY_HEADER = '| ARCHIVO | SKILL | REGLA | EVIDENCIA | ESTADO |';
77
- const TRACEABILITY_CONTRACT_MARKER = 'ARCHIVO | SKILL | REGLA | EVIDENCIA | ESTADO';
78
-
79
68
  const resolveRepoBoundPath = (params: {
80
69
  repoRoot: string;
81
70
  candidatePath: string;
82
- flagName: '--from-evidence' | '--test-output' | '--traceability-markdown';
71
+ flagName: '--from-evidence' | '--test-output';
83
72
  }): string => {
84
73
  const repoRootAbsolute = resolve(params.repoRoot);
85
74
  const resolved = isAbsolute(params.candidatePath)
@@ -152,87 +141,6 @@ const resolveScenarioReference = (scenarioId: string): string => {
152
141
  return `${normalized}.feature`;
153
142
  };
154
143
 
155
- const repoRequiresTraceabilityMatrix = (repoRoot: string): boolean => {
156
- const agentsPath = resolve(repoRoot, 'AGENTS.md');
157
- if (!existsSync(agentsPath)) {
158
- return false;
159
- }
160
- const contents = readFileSync(agentsPath, 'utf8');
161
- return (
162
- contents.includes('Plantilla obligatoria de trazabilidad por turno') ||
163
- contents.includes(TRACEABILITY_CONTRACT_MARKER)
164
- );
165
- };
166
-
167
- const validateTraceabilityMarkdown = (params: {
168
- repoRoot: string;
169
- required: boolean;
170
- traceabilityMarkdownPath?: string;
171
- }): {
172
- path: string | null;
173
- header_present: boolean;
174
- rows: number;
175
- } => {
176
- if (!params.required) {
177
- return {
178
- path: params.traceabilityMarkdownPath?.trim() ? params.traceabilityMarkdownPath.trim() : null,
179
- header_present: false,
180
- rows: 0,
181
- };
182
- }
183
- const candidate = params.traceabilityMarkdownPath?.trim() ?? '';
184
- if (candidate.length === 0) {
185
- throw new Error(
186
- `[pumuki][sdd] evidence requires --traceability-markdown=<path> because this repository declares the contractual traceability matrix (${TRACEABILITY_HEADER}).`
187
- );
188
- }
189
- const absolutePath = resolveRepoBoundPath({
190
- repoRoot: params.repoRoot,
191
- candidatePath: candidate,
192
- flagName: '--traceability-markdown',
193
- });
194
- if (!existsSync(absolutePath)) {
195
- throw new Error(
196
- `[pumuki][sdd] traceability markdown file does not exist: ${candidate}. Add the contractual matrix and retry.`
197
- );
198
- }
199
- const markdown = readFileSync(absolutePath, 'utf8');
200
- const lines = markdown.split(/\r?\n/);
201
- const headerIndex = lines.findIndex((line) => line.trim() === TRACEABILITY_HEADER);
202
- if (headerIndex < 0) {
203
- throw new Error(
204
- `[pumuki][sdd] traceability markdown must include the contractual header ${TRACEABILITY_HEADER}.`
205
- );
206
- }
207
- let rows = 0;
208
- for (const line of lines.slice(headerIndex + 1)) {
209
- const trimmed = line.trim();
210
- if (!trimmed.startsWith('|')) {
211
- if (rows > 0) {
212
- break;
213
- }
214
- continue;
215
- }
216
- if (/^\|\s*-+\s*\|/.test(trimmed)) {
217
- continue;
218
- }
219
- if (trimmed === TRACEABILITY_HEADER) {
220
- continue;
221
- }
222
- rows += 1;
223
- }
224
- if (rows === 0) {
225
- throw new Error(
226
- '[pumuki][sdd] traceability markdown must include at least one data row under the contractual matrix header.'
227
- );
228
- }
229
- return {
230
- path: relative(params.repoRoot, absolutePath).split('\\').join('/'),
231
- header_present: true,
232
- rows,
233
- };
234
- };
235
-
236
144
  export const runSddEvidenceScaffold = (params?: {
237
145
  repoRoot?: string;
238
146
  dryRun?: boolean;
@@ -241,7 +149,6 @@ export const runSddEvidenceScaffold = (params?: {
241
149
  testStatus?: SddEvidenceScaffoldTestStatus;
242
150
  testOutputPath?: string;
243
151
  fromEvidencePath?: string;
244
- traceabilityMarkdownPath?: string;
245
152
  outputPath?: string;
246
153
  now?: () => Date;
247
154
  evidenceReader?: (repoRoot: string) => EvidenceReadResult;
@@ -288,12 +195,6 @@ export const runSddEvidenceScaffold = (params?: {
288
195
  evidenceResult: evidenceReader(repoRoot),
289
196
  fromEvidencePath,
290
197
  });
291
- const traceabilityRequired = repoRequiresTraceabilityMatrix(repoRoot);
292
- const traceability = validateTraceabilityMarkdown({
293
- repoRoot,
294
- required: traceabilityRequired,
295
- traceabilityMarkdownPath: params?.traceabilityMarkdownPath,
296
- });
297
198
 
298
199
  const now = params?.now ?? (() => new Date());
299
200
  const generatedAt = now().toISOString();
@@ -331,13 +232,6 @@ export const runSddEvidenceScaffold = (params?: {
331
232
  source: 'pumuki-sdd-evidence',
332
233
  stack: 'sdd-evidence-scaffold',
333
234
  },
334
- traceability: {
335
- required: traceabilityRequired,
336
- path: traceability.path,
337
- header_present: traceability.header_present,
338
- rows: traceability.rows,
339
- status: 'valid',
340
- },
341
235
  scenario_id: scenarioId,
342
236
  test_run: {
343
237
  command: testCommand,
@@ -373,7 +267,6 @@ export const runSddEvidenceScaffold = (params?: {
373
267
  testStatus,
374
268
  testOutputPath,
375
269
  fromEvidencePath,
376
- traceabilityMarkdownPath: traceability.path,
377
270
  },
378
271
  output: {
379
272
  path: outputRelativePath,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pumuki",
3
- "version": "6.3.96",
3
+ "version": "6.3.98",
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": {
@@ -54,6 +54,8 @@
54
54
  "test:saas-ingestion": "npx --yes tsx@4.21.0 --test integrations/lifecycle/__tests__/saasIngestionContract.test.ts integrations/lifecycle/__tests__/saasIngestionBuilder.test.ts integrations/lifecycle/__tests__/saasIngestionTransport.test.ts integrations/lifecycle/__tests__/saasIngestionIdempotency.test.ts integrations/lifecycle/__tests__/saasIngestionAuth.test.ts integrations/lifecycle/__tests__/saasIngestionAudit.test.ts integrations/lifecycle/__tests__/saasIngestionMetrics.test.ts integrations/lifecycle/__tests__/saasIngestionGovernance.test.ts integrations/lifecycle/__tests__/saasFederation.test.ts integrations/lifecycle/__tests__/saasEnterpriseAnalytics.test.ts integrations/lifecycle/__tests__/cli.test.ts",
55
55
  "test:operational-memory": "npx --yes tsx@4.21.0 --test integrations/lifecycle/__tests__/operationalMemoryContract.test.ts integrations/lifecycle/__tests__/operationalMemorySignals.test.ts integrations/lifecycle/__tests__/operationalMemorySnapshot.test.ts integrations/git/__tests__/runPlatformGate.test.ts integrations/git/__tests__/runPlatformGateEvidence.test.ts integrations/evidence/__tests__/buildEvidence.test.ts integrations/evidence/writeEvidence.test.ts integrations/evidence/generateEvidence.test.ts",
56
56
  "test:stage-gates": "npx --yes tsx@4.21.0 --test integrations/config/__tests__/*.test.ts integrations/gate/__tests__/*.test.ts integrations/git/__tests__/*.test.ts integrations/lifecycle/__tests__/*.test.ts integrations/sdd/__tests__/*.test.ts scripts/__tests__/*.test.ts",
57
+ "smoke:pumuki-surface": "npx --yes tsx@4.21.0 scripts/pumuki-full-surface-smoke.ts",
58
+ "smoke:pumuki-surface-installed": "node scripts/pumuki-smoke-installed-wrapper.cjs",
57
59
  "test:deterministic": "npm run test:evidence && npm run test:mcp && npm run test:heuristics",
58
60
  "ast:refresh": "node bin/pumuki-pre-commit.js",
59
61
  "ast:audit": "node bin/pumuki-pre-commit.js",
@@ -144,12 +146,13 @@
144
146
  "validation:phase5-escalation:payload": "bash scripts/build-phase5-support-portal-payload.sh",
145
147
  "validation:architecture-guardrails": "npx --yes tsx@4.21.0 --test scripts/__tests__/architecture-file-size-guardrails.test.ts",
146
148
  "validation:package-manifest": "node --import tsx scripts/check-package-manifest.ts",
149
+ "validation:pumuki-surface-smoke": "npm run -s smoke:pumuki-surface",
150
+ "validation:local-merge-bar": "npm run -s typecheck && npm run -s validation:pumuki-surface-smoke && npm test",
147
151
  "validation:package-smoke": "node --import tsx scripts/package-install-smoke.ts --mode=block",
148
152
  "validation:package-smoke:minimal": "node --import tsx scripts/package-install-smoke.ts --mode=minimal",
149
153
  "validation:lifecycle-smoke": "node --import tsx scripts/package-install-smoke.ts --mode=minimal",
150
154
  "validation:contract-suite:enterprise": "node --import tsx scripts/run-enterprise-contract-suite.ts",
151
155
  "validation:consumer-matrix-baseline": "node --import tsx scripts/build-consumer-menu-matrix-baseline.ts",
152
- "validation:ruralgo-s1-evidence-pack": "npx --yes tsx@4.21.0 scripts/build-ruralgo-s1-evidence-pack.ts",
153
156
  "validation:c020-benchmark": "node --import tsx scripts/run-c020-benchmark.ts",
154
157
  "validation:clean-artifacts": "npx --yes tsx@4.21.0 scripts/clean-validation-artifacts.ts",
155
158
  "skills:compile": "npx --yes tsx@4.21.0 scripts/compile-skills-lock.ts",
@@ -249,6 +252,8 @@
249
252
  "integrations/telemetry/*.ts",
250
253
  "scripts/*.ts",
251
254
  "scripts/consumer-postinstall.cjs",
255
+ "scripts/consumer-postinstall-resolve-args.cjs",
256
+ "scripts/pumuki-smoke-installed-wrapper.cjs",
252
257
  "scripts/adapters/*.ts",
253
258
  "scripts/adapters/*.md",
254
259
  "scripts/*.sh",
@@ -260,10 +265,13 @@
260
265
  "docs/product/*.md",
261
266
  "docs/rule-packs/*.md",
262
267
  "docs/validation/*.md",
268
+ "docs/tracking/plan-curso-pumuki-stack-my-architecture.md",
263
269
  "assets/**/*",
264
270
  "vendor/skills/**/*",
265
271
  "index.js",
266
272
  "README.md",
273
+ "AGENTS.md",
274
+ "CHANGELOG.md",
267
275
  "LICENSE",
268
276
  "VERSION",
269
277
  "tsconfig.json",
@@ -31,7 +31,7 @@ for FILE in "${FILES[@]}"; do
31
31
  fi
32
32
 
33
33
  if [[ "${FILE}" == "PUMUKI-RESET-MASTER-PLAN.md" ]]; then
34
- ACTIVE_PATTERN='(^- Estado:\s*🚧\b)|(^`?\[\s*🚧\s*\]\s*-`?)|(^\|\s*[^|]+\|\s*`?\[\s*🚧\s*\]\s*-`?)'
34
+ ACTIVE_PATTERN='^- Estado: 🚧'
35
35
  else
36
36
  ACTIVE_PATTERN='^- 🚧 (`?P[0-9A-Za-z.-]+`?)'
37
37
  fi
@@ -4,10 +4,11 @@ import type {
4
4
  ConsumerMenuMatrixReport,
5
5
  MatrixOptionId,
6
6
  } from './framework-menu-matrix-baseline-lib';
7
+ import { MATRIX_MENU_OPTION_IDS } from './framework-menu-matrix-evidence-lib';
7
8
  import type { DoctorDeepCheckLayer, LifecycleDoctorReport } from '../integrations/lifecycle/doctor';
8
9
  import type { LifecycleStatus } from '../integrations/lifecycle/status';
9
10
 
10
- const OPTION_IDS: ReadonlyArray<MatrixOptionId> = ['1', '2', '3', '4', '9'];
11
+ const OPTION_IDS: ReadonlyArray<MatrixOptionId> = [...MATRIX_MENU_OPTION_IDS];
11
12
  const DOCTOR_LAYERS: ReadonlyArray<DoctorDeepCheckLayer> = [
12
13
  'core',
13
14
  'operational',
@@ -51,45 +52,19 @@ export type ConsumerMenuMatrixBaselineSnapshot = {
51
52
  };
52
53
  };
53
54
 
55
+ const UNKNOWN_OPTION_REPORT = {
56
+ stage: 'UNKNOWN',
57
+ outcome: 'UNKNOWN',
58
+ filesScanned: 0,
59
+ totalViolations: 0,
60
+ diagnosis: 'unknown' as const,
61
+ };
62
+
54
63
  const buildEmptyRound = (): ConsumerMenuMatrixReport => {
55
64
  return {
56
- byOption: {
57
- '1': {
58
- stage: 'UNKNOWN',
59
- outcome: 'UNKNOWN',
60
- filesScanned: 0,
61
- totalViolations: 0,
62
- diagnosis: 'unknown',
63
- },
64
- '2': {
65
- stage: 'UNKNOWN',
66
- outcome: 'UNKNOWN',
67
- filesScanned: 0,
68
- totalViolations: 0,
69
- diagnosis: 'unknown',
70
- },
71
- '3': {
72
- stage: 'UNKNOWN',
73
- outcome: 'UNKNOWN',
74
- filesScanned: 0,
75
- totalViolations: 0,
76
- diagnosis: 'unknown',
77
- },
78
- '4': {
79
- stage: 'UNKNOWN',
80
- outcome: 'UNKNOWN',
81
- filesScanned: 0,
82
- totalViolations: 0,
83
- diagnosis: 'unknown',
84
- },
85
- '9': {
86
- stage: 'UNKNOWN',
87
- outcome: 'UNKNOWN',
88
- filesScanned: 0,
89
- totalViolations: 0,
90
- diagnosis: 'unknown',
91
- },
92
- },
65
+ byOption: Object.fromEntries(
66
+ MATRIX_MENU_OPTION_IDS.map((id) => [id, { ...UNKNOWN_OPTION_REPORT }])
67
+ ) as ConsumerMenuMatrixReport['byOption'],
93
68
  };
94
69
  };
95
70
 
@@ -0,0 +1,44 @@
1
+ 'use strict';
2
+
3
+ const KNOWN_MCP_AGENTS = new Set(['cursor', 'codex', 'claude', 'repo']);
4
+
5
+ const normalizeExplicitAgent = (raw) => {
6
+ const trimmed = (raw ?? '').trim();
7
+ if (!trimmed) {
8
+ return '';
9
+ }
10
+ const lower = trimmed.toLowerCase();
11
+ if (lower === '0' || lower === 'none' || lower === 'false') {
12
+ return '';
13
+ }
14
+ if (!KNOWN_MCP_AGENTS.has(lower)) {
15
+ return '';
16
+ }
17
+ return lower;
18
+ };
19
+
20
+ const resolveConsumerPostinstallInstallExtras = (_consumerRoot, env = process.env) => {
21
+ if (env.PUMUKI_POSTINSTALL_SKIP_MCP === '1') {
22
+ return { extras: [], reason: 'skip_mcp' };
23
+ }
24
+ const withMcpFlag =
25
+ env.PUMUKI_POSTINSTALL_WITH_MCP === '1' ||
26
+ env.PUMUKI_POSTINSTALL_WITH_MCP?.toLowerCase() === 'true';
27
+ const explicit = normalizeExplicitAgent(env.PUMUKI_POSTINSTALL_MCP_AGENT);
28
+ if (explicit) {
29
+ return { extras: ['--with-mcp', `--agent=${explicit}`], reason: 'explicit_agent' };
30
+ }
31
+ if (withMcpFlag) {
32
+ return { extras: ['--with-mcp', '--agent=repo'], reason: 'explicit_repo_flag' };
33
+ }
34
+ return {
35
+ extras: [],
36
+ reason: 'disabled_default',
37
+ };
38
+ };
39
+
40
+ module.exports = {
41
+ KNOWN_MCP_AGENTS,
42
+ resolveConsumerPostinstallInstallExtras,
43
+ normalizeExplicitAgent,
44
+ };
@@ -4,56 +4,111 @@
4
4
  const { existsSync } = require('node:fs');
5
5
  const { join, resolve } = require('node:path');
6
6
  const { spawnSync } = require('node:child_process');
7
+ const { resolveConsumerPostinstallInstallExtras } = require('./consumer-postinstall-resolve-args.cjs');
7
8
 
8
- const skipReason = () => {
9
- if (process.env.PUMUKI_SKIP_POSTINSTALL === '1') {
9
+ const skipReason = (env = process.env) => {
10
+ if (env.PUMUKI_SKIP_POSTINSTALL === '1') {
10
11
  return 'PUMUKI_SKIP_POSTINSTALL=1';
11
12
  }
12
- if (process.env.CI === 'true' || process.env.CI === '1') {
13
+ if (env.CI === 'true' || env.CI === '1') {
13
14
  return 'CI';
14
15
  }
15
- if (process.env.npm_config_ignore_scripts === 'true') {
16
+ if (env.npm_config_ignore_scripts === 'true') {
16
17
  return 'npm ignore-scripts';
17
18
  }
18
19
  return '';
19
20
  };
20
21
 
21
- const main = () => {
22
- const reason = skipReason();
22
+ const normalizePumukiInstallResult = (result) => {
23
+ if (result.error) {
24
+ return {
25
+ code: 1,
26
+ errorMessage: result.error.message ?? String(result.error),
27
+ };
28
+ }
29
+
30
+ return { code: typeof result.status === 'number' ? result.status : 1, errorMessage: null };
31
+ };
32
+
33
+ const runPostinstall = ({
34
+ spawnSyncFn = spawnSync,
35
+ packageRoot = resolve(__dirname, '..'),
36
+ consumerRoot = process.env.INIT_CWD || process.cwd(),
37
+ env = process.env,
38
+ logger = console,
39
+ } = {}) => {
40
+ const reason = skipReason(env);
23
41
  if (reason) {
24
42
  return 0;
25
43
  }
26
44
 
27
- const consumerRoot = process.env.INIT_CWD || process.cwd();
28
45
  if (!existsSync(join(consumerRoot, '.git'))) {
29
46
  return 0;
30
47
  }
31
48
 
32
- const packageRoot = resolve(__dirname, '..');
33
49
  const pumukiCli = join(packageRoot, 'bin', 'pumuki.js');
34
50
  if (!existsSync(pumukiCli)) {
35
51
  return 0;
36
52
  }
37
53
 
38
- const env = {
39
- ...process.env,
54
+ const postinstallEnv = {
55
+ ...env,
40
56
  PUMUKI_AUTO_POSTINSTALL: '1',
41
- PUMUKI_SKIP_OPENSPEC_BOOTSTRAP: process.env.PUMUKI_SKIP_OPENSPEC_BOOTSTRAP ?? '1',
57
+ PUMUKI_SKIP_OPENSPEC_BOOTSTRAP: env.PUMUKI_SKIP_OPENSPEC_BOOTSTRAP ?? '1',
42
58
  };
43
59
 
44
- const result = spawnSync(process.execPath, [pumukiCli, 'install'], {
45
- cwd: consumerRoot,
46
- env,
47
- stdio: 'inherit',
48
- });
60
+ const { extras: installExtras, reason: mcpReason } = resolveConsumerPostinstallInstallExtras(
61
+ consumerRoot,
62
+ postinstallEnv
63
+ );
64
+ if (installExtras.length > 0 && postinstallEnv.PUMUKI_VERBOSE_INSTALL === '1') {
65
+ logger.debug(
66
+ `[pumuki] postinstall: mcp wiring (${mcpReason}): ${installExtras.join(' ')}`
67
+ );
68
+ }
69
+
70
+ if (installExtras.length === 0 && postinstallEnv.PUMUKI_VERBOSE_INSTALL === '1') {
71
+ logger.debug('[pumuki] postinstall: no extra args; running baseline install only.');
72
+ }
73
+
74
+ const result = normalizePumukiInstallResult(
75
+ spawnSyncFn(process.execPath, [pumukiCli, 'install', ...installExtras], {
76
+ cwd: consumerRoot,
77
+ env: postinstallEnv,
78
+ stdio: 'inherit',
79
+ })
80
+ );
49
81
 
50
- const code = typeof result.status === 'number' ? result.status : 1;
51
- if (code !== 0) {
52
- console.error(
53
- '[pumuki] postinstall: `pumuki install` exited non-zero; npm install will still succeed. Run `npx pumuki install` or `npx pumuki doctor` from the repo root.'
82
+ if (result.code !== 0) {
83
+ const scope = installExtras.length > 0 ? 'postinstall+extras' : 'postinstall';
84
+ const severityHint =
85
+ installExtras.length > 0
86
+ ? 'Run `pumuki install` manually with the desired options to investigar y resolver el fallo.'
87
+ : 'Run `pumuki install` o `pumuki doctor` desde la raíz del repo.';
88
+ logger.error(
89
+ `[pumuki] postinstall: install exited non-zero (scope=${scope}, reason=${mcpReason}). ${severityHint}`
54
90
  );
91
+ if (result.errorMessage) {
92
+ logger.error(`[pumuki] postinstall: ${result.errorMessage}`);
93
+ }
55
94
  }
56
- return 0;
95
+
96
+ return result.code;
97
+ };
98
+
99
+ const main = () => {
100
+ return runPostinstall({
101
+ spawnSyncFn: spawnSync,
102
+ packageRoot: resolve(__dirname, '..'),
103
+ consumerRoot: process.env.INIT_CWD || process.cwd(),
104
+ env: process.env,
105
+ logger: console,
106
+ });
57
107
  };
58
108
 
59
109
  process.exitCode = main();
110
+
111
+ module.exports = {
112
+ runPostinstall,
113
+ skipReason,
114
+ };
@@ -19,14 +19,11 @@ import {
19
19
  renderActionRow,
20
20
  renderBadge,
21
21
  } from './framework-menu-ui-components-lib';
22
- import { buildGovernanceConsoleSummaryLines } from '../integrations/lifecycle/cliGovernanceConsole';
23
- import type { ConsumerPreflightResult } from './framework-menu-consumer-preflight-types';
24
22
 
25
23
  export const formatAdvancedMenuView = (
26
24
  actions: ReadonlyArray<MenuAction>,
27
25
  options?: {
28
26
  evidenceSummary?: FrameworkMenuEvidenceSummary;
29
- preflight?: ConsumerPreflightResult | null;
30
27
  }
31
28
  ): string => {
32
29
  const evidenceSummary = options?.evidenceSummary ?? readEvidenceSummaryForMenu(process.cwd());
@@ -36,18 +33,6 @@ export const formatAdvancedMenuView = (
36
33
  const lines = [
37
34
  'Pumuki Framework Menu (Advanced)',
38
35
  `Status: ${statusBadge}`,
39
- ...(options?.preflight
40
- ? [
41
- 'Governance Console',
42
- ...buildGovernanceConsoleSummaryLines({
43
- governanceObservation: options.preflight.governanceObservation,
44
- governanceNextAction: options.preflight.governanceNextAction,
45
- policyValidation: options.preflight.policyValidation,
46
- experimentalFeatures: options.preflight.experimentalFeatures,
47
- }).map((line) => ` ${line}`),
48
- '',
49
- ]
50
- : []),
51
36
  'C. Switch to consumer menu',
52
37
  '',
53
38
  ...groupedActions.flatMap((group, groupIndex) => [