pumuki 6.3.72 → 6.3.73

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 (53) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/VERSION +1 -1
  3. package/docs/README.md +1 -1
  4. package/docs/operations/RELEASE_NOTES.md +12 -1
  5. package/docs/product/USAGE.md +2 -5
  6. package/docs/tracking/plan-curso-pumuki-stack-my-architecture.md +56 -105
  7. package/integrations/gate/governanceActionCatalog.ts +230 -0
  8. package/integrations/git/runPlatformGate.ts +9 -1
  9. package/integrations/git/runPlatformGateFacts.ts +1 -7
  10. package/integrations/git/runPlatformGateOutput.ts +36 -27
  11. package/integrations/lifecycle/adapter.templates.json +3 -0
  12. package/integrations/lifecycle/audit.ts +101 -0
  13. package/integrations/lifecycle/cli.ts +80 -8
  14. package/integrations/lifecycle/doctor.ts +64 -1
  15. package/integrations/lifecycle/governanceNextAction.ts +164 -0
  16. package/integrations/lifecycle/governanceObservationSnapshot.ts +288 -0
  17. package/integrations/lifecycle/index.ts +2 -0
  18. package/integrations/lifecycle/status.ts +29 -2
  19. package/integrations/mcp/autoExecuteAiStart.ts +86 -84
  20. package/integrations/mcp/preFlightCheck.ts +41 -5
  21. package/integrations/platform/detectPlatforms.ts +37 -0
  22. package/package.json +8 -1
  23. package/scripts/build-ruralgo-s1-evidence-pack.ts +85 -0
  24. package/scripts/consumer-menu-matrix-baseline-report-lib.ts +38 -13
  25. package/scripts/consumer-postinstall-resolve-args.cjs +38 -0
  26. package/scripts/consumer-postinstall.cjs +10 -1
  27. package/scripts/framework-menu-consumer-actions-lib.ts +4 -28
  28. package/scripts/framework-menu-consumer-preflight-hints.ts +2 -5
  29. package/scripts/framework-menu-consumer-preflight-render.ts +6 -0
  30. package/scripts/framework-menu-consumer-preflight-run.ts +19 -0
  31. package/scripts/framework-menu-consumer-preflight-types.ts +8 -0
  32. package/scripts/framework-menu-consumer-runtime-actions.ts +6 -86
  33. package/scripts/framework-menu-consumer-runtime-audit.ts +2 -36
  34. package/scripts/framework-menu-consumer-runtime-lib.ts +0 -2
  35. package/scripts/framework-menu-consumer-runtime-types.ts +1 -3
  36. package/scripts/framework-menu-evidence-summary-lib.ts +0 -1
  37. package/scripts/framework-menu-evidence-summary-read.ts +5 -57
  38. package/scripts/framework-menu-evidence-summary-severity.ts +1 -3
  39. package/scripts/framework-menu-evidence-summary-types.ts +0 -7
  40. package/scripts/framework-menu-gate-lib.ts +0 -9
  41. package/scripts/framework-menu-layout-data.ts +0 -5
  42. package/scripts/framework-menu-matrix-baseline-lib.ts +14 -15
  43. package/scripts/framework-menu-matrix-canary-lib.ts +1 -22
  44. package/scripts/framework-menu-matrix-evidence-lib.ts +0 -1
  45. package/scripts/framework-menu-matrix-evidence-types.ts +1 -13
  46. package/scripts/framework-menu-matrix-runner-lib.ts +0 -35
  47. package/scripts/framework-menu-system-notifications-macos.ts +0 -4
  48. package/scripts/framework-menu.ts +0 -3
  49. package/scripts/pumuki-full-surface-smoke-lib.ts +37 -0
  50. package/scripts/pumuki-full-surface-smoke.ts +261 -0
  51. package/scripts/pumuki-smoke-installed-wrapper.cjs +31 -0
  52. package/scripts/ruralgo-s1-evidence-pack-lib.ts +200 -0
  53. package/scripts/framework-menu-consumer-runtime-evidence-classic.ts +0 -140
@@ -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
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pumuki",
3
- "version": "6.3.72",
3
+ "version": "6.3.73",
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,11 +146,14 @@
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",
156
+ "validation:ruralgo-s1-evidence-pack": "npx --yes tsx@4.21.0 scripts/build-ruralgo-s1-evidence-pack.ts",
152
157
  "validation:c020-benchmark": "node --import tsx scripts/run-c020-benchmark.ts",
153
158
  "validation:clean-artifacts": "npx --yes tsx@4.21.0 scripts/clean-validation-artifacts.ts",
154
159
  "skills:compile": "npx --yes tsx@4.21.0 scripts/compile-skills-lock.ts",
@@ -248,6 +253,8 @@
248
253
  "integrations/telemetry/*.ts",
249
254
  "scripts/*.ts",
250
255
  "scripts/consumer-postinstall.cjs",
256
+ "scripts/consumer-postinstall-resolve-args.cjs",
257
+ "scripts/pumuki-smoke-installed-wrapper.cjs",
251
258
  "scripts/adapters/*.ts",
252
259
  "scripts/adapters/*.md",
253
260
  "scripts/*.sh",
@@ -0,0 +1,85 @@
1
+ import {
2
+ buildRuralGoS1EvidencePackMarkdown,
3
+ writeRuralGoS1EvidencePack,
4
+ } from './ruralgo-s1-evidence-pack-lib';
5
+
6
+ type CliOptions = {
7
+ consumerRoot: string;
8
+ outFile: string;
9
+ packageVersion: string;
10
+ generatedAt: string;
11
+ };
12
+
13
+ const parseArgs = (argv: ReadonlyArray<string>): CliOptions => {
14
+ const options: CliOptions = {
15
+ consumerRoot: '<RURALGO_REPO_ROOT>',
16
+ outFile: '.audit-reports/ruralgo-s1/ruralgo-s1-evidence-pack.md',
17
+ packageVersion: 'unknown',
18
+ generatedAt: new Date().toISOString(),
19
+ };
20
+
21
+ for (let index = 0; index < argv.length; index += 1) {
22
+ const token = argv[index];
23
+ const next = argv[index + 1];
24
+ switch (token) {
25
+ case '--consumer-root':
26
+ if (!next) {
27
+ throw new Error('missing value for --consumer-root');
28
+ }
29
+ options.consumerRoot = next;
30
+ index += 1;
31
+ break;
32
+ case '--out':
33
+ if (!next) {
34
+ throw new Error('missing value for --out');
35
+ }
36
+ options.outFile = next;
37
+ index += 1;
38
+ break;
39
+ case '--package-version':
40
+ if (!next) {
41
+ throw new Error('missing value for --package-version');
42
+ }
43
+ options.packageVersion = next;
44
+ index += 1;
45
+ break;
46
+ case '--generated-at':
47
+ if (!next) {
48
+ throw new Error('missing value for --generated-at');
49
+ }
50
+ options.generatedAt = next;
51
+ index += 1;
52
+ break;
53
+ default:
54
+ throw new Error(`unknown argument: ${token}`);
55
+ }
56
+ }
57
+
58
+ return options;
59
+ };
60
+
61
+ const main = (): number => {
62
+ const cwd = process.cwd();
63
+ const options = parseArgs(process.argv.slice(2));
64
+ const markdown = buildRuralGoS1EvidencePackMarkdown({
65
+ cwd,
66
+ consumerRoot: options.consumerRoot,
67
+ packageVersion: options.packageVersion,
68
+ generatedAt: options.generatedAt,
69
+ });
70
+ const outputPath = writeRuralGoS1EvidencePack({
71
+ cwd,
72
+ outFile: options.outFile,
73
+ markdown,
74
+ });
75
+ process.stdout.write(`ruralgo s1 evidence pack generated at ${outputPath}\n`);
76
+ return 0;
77
+ };
78
+
79
+ try {
80
+ process.exitCode = main();
81
+ } catch (error) {
82
+ const message = error instanceof Error ? error.message : 'unknown error';
83
+ process.stderr.write(`ruralgo s1 evidence pack failed: ${message}\n`);
84
+ process.exitCode = 1;
85
+ }
@@ -4,11 +4,10 @@ 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';
8
7
  import type { DoctorDeepCheckLayer, LifecycleDoctorReport } from '../integrations/lifecycle/doctor';
9
8
  import type { LifecycleStatus } from '../integrations/lifecycle/status';
10
9
 
11
- const OPTION_IDS: ReadonlyArray<MatrixOptionId> = [...MATRIX_MENU_OPTION_IDS];
10
+ const OPTION_IDS: ReadonlyArray<MatrixOptionId> = ['1', '2', '3', '4', '9'];
12
11
  const DOCTOR_LAYERS: ReadonlyArray<DoctorDeepCheckLayer> = [
13
12
  'core',
14
13
  'operational',
@@ -52,19 +51,45 @@ export type ConsumerMenuMatrixBaselineSnapshot = {
52
51
  };
53
52
  };
54
53
 
55
- const UNKNOWN_OPTION_REPORT = {
56
- stage: 'UNKNOWN',
57
- outcome: 'UNKNOWN',
58
- filesScanned: 0,
59
- totalViolations: 0,
60
- diagnosis: 'unknown' as const,
61
- };
62
-
63
54
  const buildEmptyRound = (): ConsumerMenuMatrixReport => {
64
55
  return {
65
- byOption: Object.fromEntries(
66
- MATRIX_MENU_OPTION_IDS.map((id) => [id, { ...UNKNOWN_OPTION_REPORT }])
67
- ) as ConsumerMenuMatrixReport['byOption'],
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
+ },
68
93
  };
69
94
  };
70
95
 
@@ -0,0 +1,38 @@
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 explicit = normalizeExplicitAgent(env.PUMUKI_POSTINSTALL_MCP_AGENT);
25
+ if (explicit) {
26
+ return { extras: ['--with-mcp', `--agent=${explicit}`], reason: 'explicit_agent' };
27
+ }
28
+ return {
29
+ extras: ['--with-mcp', '--agent=repo'],
30
+ reason: 'default_repo_adapter',
31
+ };
32
+ };
33
+
34
+ module.exports = {
35
+ KNOWN_MCP_AGENTS,
36
+ resolveConsumerPostinstallInstallExtras,
37
+ normalizeExplicitAgent,
38
+ };
@@ -4,6 +4,7 @@
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
9
  const skipReason = () => {
9
10
  if (process.env.PUMUKI_SKIP_POSTINSTALL === '1') {
@@ -41,7 +42,15 @@ const main = () => {
41
42
  PUMUKI_SKIP_OPENSPEC_BOOTSTRAP: process.env.PUMUKI_SKIP_OPENSPEC_BOOTSTRAP ?? '1',
42
43
  };
43
44
 
44
- const result = spawnSync(process.execPath, [pumukiCli, 'install'], {
45
+ const { extras: installExtras, reason: mcpReason } = resolveConsumerPostinstallInstallExtras(
46
+ consumerRoot,
47
+ env
48
+ );
49
+ if (installExtras.length > 0 && env.PUMUKI_VERBOSE_INSTALL === '1') {
50
+ console.debug(`[pumuki] postinstall: mcp wiring (${mcpReason}): ${installExtras.join(' ')}`);
51
+ }
52
+
53
+ const result = spawnSync(process.execPath, [pumukiCli, 'install', ...installExtras], {
45
54
  cwd: consumerRoot,
46
55
  env,
47
56
  stdio: 'inherit',
@@ -9,10 +9,6 @@ export type ConsumerLegacyMenuContext = {
9
9
  runStrictRepoAndStaged: () => Promise<void>;
10
10
  runStrictStagedOnly: () => Promise<void>;
11
11
  runStandardCriticalHigh: () => Promise<void>;
12
- runEngineStagedNoPreflight: () => Promise<void>;
13
- runEngineUnstagedNoPreflight: () => Promise<void>;
14
- runEngineStagedAndUnstagedNoPreflight: () => Promise<void>;
15
- runEngineFullRepoNoPreflight: () => Promise<void>;
16
12
  runPatternChecks: () => Promise<void>;
17
13
  runEslintAudit: () => Promise<void>;
18
14
  runAstIntelligence: () => Promise<void>;
@@ -26,44 +22,24 @@ export const createConsumerLegacyMenuActions = (
26
22
  return [
27
23
  {
28
24
  id: '1',
29
- label: 'Consumer preflight + gate: ALL tracked files (PRE_COMMIT · writes evidence)',
25
+ label: 'Read-only full audit (repo analysis · PRE_COMMIT)',
30
26
  execute: params.runFullAudit,
31
27
  },
32
28
  {
33
29
  id: '2',
34
- label: 'Consumer preflight + gate: REPO+index contract (PRE_PUSH · disk skip risk if evidence tracked)',
30
+ label: 'Read-only strict REPO+STAGING (CI/CD · PRE_PUSH)',
35
31
  execute: params.runStrictRepoAndStaged,
36
32
  },
37
33
  {
38
34
  id: '3',
39
- label: 'Consumer preflight + gate: STAGED only (PRE_COMMIT)',
35
+ label: 'Read-only strict STAGING only (dev · PRE_COMMIT)',
40
36
  execute: params.runStrictStagedOnly,
41
37
  },
42
38
  {
43
39
  id: '4',
44
- label: 'Consumer preflight + gate: working tree (PRE_PUSH policy · disk skip risk if evidence tracked)',
40
+ label: 'Read-only audit of STAGED+UNSTAGED working tree (PRE_PUSH policy)',
45
41
  execute: params.runStandardCriticalHigh,
46
42
  },
47
- {
48
- id: '11',
49
- label: 'Engine audit · STAGED only (no preflight · PRE_COMMIT)',
50
- execute: params.runEngineStagedNoPreflight,
51
- },
52
- {
53
- id: '12',
54
- label: 'Engine audit · UNSTAGED only (no preflight · PRE_COMMIT)',
55
- execute: params.runEngineUnstagedNoPreflight,
56
- },
57
- {
58
- id: '13',
59
- label: 'Engine audit · STAGED + UNSTAGED (no preflight · PRE_COMMIT)',
60
- execute: params.runEngineStagedAndUnstagedNoPreflight,
61
- },
62
- {
63
- id: '14',
64
- label: 'Engine audit · FULL tracked repo (no preflight · PRE_COMMIT)',
65
- execute: params.runEngineFullRepoNoPreflight,
66
- },
67
43
  {
68
44
  id: '5',
69
45
  label: 'Legacy read-only pattern checks snapshot',
@@ -7,8 +7,7 @@ import type {
7
7
  } from './framework-menu-consumer-preflight-types';
8
8
 
9
9
  export const ACTIONABLE_HINTS_BY_CODE: Readonly<Record<string, string>> = {
10
- EVIDENCE_MISSING:
11
- 'ejecuta una auditoría (1/2/3/4 o motor 11–14) para regenerar .ai_evidence.json.',
10
+ EVIDENCE_MISSING: 'ejecuta una auditoría (1/2/3/4) para regenerar .ai_evidence.json.',
12
11
  EVIDENCE_INVALID: 'regenera .ai_evidence.json desde una opción de auditoría.',
13
12
  EVIDENCE_STALE: 'refresca evidencia antes de continuar con commit/push.',
14
13
  EVIDENCE_TIMESTAMP_INVALID: 'regenera evidencia para obtener un timestamp válido.',
@@ -55,9 +54,7 @@ export const buildConsumerPreflightHints = (
55
54
  const actionableHintsByCode = resolveActionableHintsByCode(dependencies);
56
55
 
57
56
  if (hasViolationCode(violations, 'EVIDENCE_MISSING')) {
58
- hints.push(
59
- 'Evidence missing: ejecuta una auditoría (1/2/3/4 o motor 11–14) para regenerar .ai_evidence.json.'
60
- );
57
+ hints.push('Evidence missing: ejecuta una auditoría (1/2/3/4) para regenerar .ai_evidence.json.');
61
58
  handledCodes.add('EVIDENCE_MISSING');
62
59
  }
63
60
  if (hasViolationCode(violations, 'EVIDENCE_INVALID')) {
@@ -1,5 +1,7 @@
1
1
  import { renderLegacyPanel, resolveLegacyPanelOuterWidth } from './framework-menu-legacy-audit-lib';
2
2
  import { buildConsumerPreflightBlockingCauseLines } from './framework-menu-consumer-preflight-hints';
3
+ import { buildGovernanceNextActionSummaryLines } from '../integrations/lifecycle/governanceNextAction';
4
+ import { buildGovernanceObservationSummaryLines } from '../integrations/lifecycle/governanceObservationSnapshot';
3
5
  import type {
4
6
  ConsumerPreflightRenderOptions,
5
7
  ConsumerPreflightResult,
@@ -19,6 +21,10 @@ const buildConsumerPreflightPanelLines = (
19
21
  `Evidence source: source=${evidence.source.source} path=${evidence.source.path} digest=${evidence.source.digest ?? 'null'} generated_at=${evidence.source.generated_at ?? 'null'}`,
20
22
  `Gate: ${preflight.status} (${preflight.result.violations.length} violations)`,
21
23
  ];
24
+ lines.push('', 'Governance truth:');
25
+ lines.push(...buildGovernanceObservationSummaryLines(preflight.governanceObservation));
26
+ lines.push('', 'Governance next action:');
27
+ lines.push(...buildGovernanceNextActionSummaryLines(preflight.governanceNextAction));
22
28
  lines.push(...buildConsumerPreflightBlockingCauseLines(preflight));
23
29
 
24
30
  if (preflight.hints.length > 0) {
@@ -2,6 +2,11 @@ import {
2
2
  evaluateAiGate,
3
3
  type AiGateCheckResult,
4
4
  } from '../integrations/gate/evaluateAiGate';
5
+ import { readLifecycleExperimentalFeaturesSnapshot } from '../integrations/lifecycle/experimentalFeaturesSnapshot';
6
+ import { LifecycleGitService } from '../integrations/lifecycle/gitService';
7
+ import { readGovernanceObservationSnapshot } from '../integrations/lifecycle/governanceObservationSnapshot';
8
+ import { readGovernanceNextAction } from '../integrations/lifecycle/governanceNextAction';
9
+ import { readLifecyclePolicyValidationSnapshot } from '../integrations/lifecycle/policyValidationSnapshot';
5
10
  import {
6
11
  emitSystemNotification,
7
12
  type PumukiCriticalNotificationEvent,
@@ -28,6 +33,7 @@ const defaultDependencies: ConsumerPreflightDependencies = {
28
33
  event: params.event,
29
34
  repoRoot: params.repoRoot,
30
35
  }),
36
+ readGovernanceNextAction,
31
37
  };
32
38
 
33
39
  const buildNotificationEvents = (
@@ -86,6 +92,17 @@ export const runConsumerPreflight = (
86
92
  repoRoot,
87
93
  stage: params.stage,
88
94
  });
95
+ const governanceObservation = readGovernanceObservationSnapshot({
96
+ repoRoot,
97
+ experimentalFeatures: readLifecycleExperimentalFeaturesSnapshot(),
98
+ policyValidation: readLifecyclePolicyValidationSnapshot(repoRoot),
99
+ git: new LifecycleGitService(),
100
+ });
101
+ const governanceNextAction = activeDependencies.readGovernanceNextAction({
102
+ repoRoot,
103
+ stage: params.stage,
104
+ governanceObservation,
105
+ });
89
106
  const hints = buildConsumerPreflightHints(result, params.stage);
90
107
  const notificationEvents = buildNotificationEvents(result);
91
108
  const notificationResults = notificationEvents.map((event) =>
@@ -99,6 +116,8 @@ export const runConsumerPreflight = (
99
116
  stage: params.stage,
100
117
  status: result.status,
101
118
  result,
119
+ governanceObservation,
120
+ governanceNextAction,
102
121
  hints,
103
122
  notificationResults,
104
123
  };
@@ -2,6 +2,11 @@ import type {
2
2
  AiGateCheckResult,
3
3
  AiGateViolation,
4
4
  } from '../integrations/gate/evaluateAiGate';
5
+ import type {
6
+ GovernanceNextActionReader,
7
+ GovernanceNextActionSummary,
8
+ } from '../integrations/lifecycle/governanceNextAction';
9
+ import type { GovernanceObservationSnapshot } from '../integrations/lifecycle/governanceObservationSnapshot';
5
10
  import type {
6
11
  PumukiCriticalNotificationEvent,
7
12
  SystemNotificationEmitResult,
@@ -13,6 +18,8 @@ export type ConsumerPreflightResult = {
13
18
  stage: ConsumerPreflightStage;
14
19
  status: AiGateCheckResult['status'];
15
20
  result: AiGateCheckResult;
21
+ governanceObservation: GovernanceObservationSnapshot;
22
+ governanceNextAction: GovernanceNextActionSummary;
16
23
  hints: ReadonlyArray<string>;
17
24
  notificationResults: ReadonlyArray<SystemNotificationEmitResult>;
18
25
  };
@@ -26,6 +33,7 @@ export type ConsumerPreflightDependencies = {
26
33
  event: PumukiCriticalNotificationEvent;
27
34
  repoRoot: string;
28
35
  }) => SystemNotificationEmitResult;
36
+ readGovernanceNextAction: GovernanceNextActionReader;
29
37
  };
30
38
 
31
39
  export type ConsumerPreflightRenderOptions = {
@@ -5,7 +5,6 @@ import {
5
5
  exportConsumerRuntimeMarkdown,
6
6
  notifyConsumerRuntimeAuditSummary,
7
7
  printConsumerRuntimeEmptyScopeHint,
8
- printPrePushTrackedEvidenceDiskHint,
9
8
  renderConsumerRuntimeAstBreakdown,
10
9
  renderConsumerRuntimeEslintAudit,
11
10
  renderConsumerRuntimeFileDiagnostics,
@@ -21,9 +20,7 @@ type ConsumerRuntimeActionDependencies = {
21
20
  runRepoGate: () => Promise<ConsumerRuntimeGateResult | void>;
22
21
  runRepoAndStagedGate: () => Promise<ConsumerRuntimeGateResult | void>;
23
22
  runStagedGate: () => Promise<ConsumerRuntimeGateResult | void>;
24
- runUnstagedGate: () => Promise<ConsumerRuntimeGateResult | void>;
25
23
  runWorkingTreeGate: () => Promise<ConsumerRuntimeGateResult | void>;
26
- runWorkingTreePreCommitGate: () => Promise<ConsumerRuntimeGateResult | void>;
27
24
  runPreflight?: (
28
25
  stage: 'PRE_COMMIT' | 'PRE_PUSH'
29
26
  ) => Promise<string | void> | string | void;
@@ -91,25 +88,18 @@ export const createConsumerRuntimeActions = (
91
88
  } else {
92
89
  dependencies.clearSummaryOverride();
93
90
  }
94
- const summary = renderConsumerRuntimeSummary({
95
- repoRoot: dependencies.repoRoot,
96
- write: dependencies.write,
97
- useColor: dependencies.useColor,
98
- summaryOverride: dependencies.getSummaryOverride(),
99
- });
100
91
  notifyConsumerRuntimeAuditSummary(
101
92
  {
102
93
  emitNotification: dependencies.emitNotification,
103
94
  repoRoot: dependencies.repoRoot,
104
95
  },
105
- summary
96
+ renderConsumerRuntimeSummary({
97
+ repoRoot: dependencies.repoRoot,
98
+ write: dependencies.write,
99
+ useColor: dependencies.useColor,
100
+ summaryOverride: dependencies.getSummaryOverride(),
101
+ })
106
102
  );
107
- if (
108
- !gateResult?.blocked
109
- && (summary.outcome === 'PASS' || summary.outcome === 'WARN')
110
- ) {
111
- printPrePushTrackedEvidenceDiskHint({ write: dependencies.write });
112
- }
113
103
  },
114
104
  runStrictStagedOnly: async () => {
115
105
  await runConsumerRuntimePreflight(dependencies, 'PRE_COMMIT');
@@ -145,78 +135,8 @@ export const createConsumerRuntimeActions = (
145
135
  },
146
136
  summary
147
137
  );
148
- if (summary.outcome === 'PASS' || summary.outcome === 'WARN') {
149
- printPrePushTrackedEvidenceDiskHint({ write: dependencies.write });
150
- }
151
138
  printConsumerRuntimeEmptyScopeHint({ write: dependencies.write }, summary, 'workingTree');
152
139
  },
153
- runEngineStagedNoPreflight: async () => {
154
- await dependencies.runStagedGate();
155
- dependencies.clearSummaryOverride();
156
- const summary = renderConsumerRuntimeSummary({
157
- repoRoot: dependencies.repoRoot,
158
- write: dependencies.write,
159
- useColor: dependencies.useColor,
160
- });
161
- notifyConsumerRuntimeAuditSummary(
162
- {
163
- emitNotification: dependencies.emitNotification,
164
- repoRoot: dependencies.repoRoot,
165
- },
166
- summary
167
- );
168
- printConsumerRuntimeEmptyScopeHint({ write: dependencies.write }, summary, 'staged');
169
- },
170
- runEngineUnstagedNoPreflight: async () => {
171
- await dependencies.runUnstagedGate();
172
- dependencies.clearSummaryOverride();
173
- const summary = renderConsumerRuntimeSummary({
174
- repoRoot: dependencies.repoRoot,
175
- write: dependencies.write,
176
- useColor: dependencies.useColor,
177
- });
178
- notifyConsumerRuntimeAuditSummary(
179
- {
180
- emitNotification: dependencies.emitNotification,
181
- repoRoot: dependencies.repoRoot,
182
- },
183
- summary
184
- );
185
- printConsumerRuntimeEmptyScopeHint({ write: dependencies.write }, summary, 'unstaged');
186
- },
187
- runEngineStagedAndUnstagedNoPreflight: async () => {
188
- await dependencies.runWorkingTreePreCommitGate();
189
- dependencies.clearSummaryOverride();
190
- const summary = renderConsumerRuntimeSummary({
191
- repoRoot: dependencies.repoRoot,
192
- write: dependencies.write,
193
- useColor: dependencies.useColor,
194
- });
195
- notifyConsumerRuntimeAuditSummary(
196
- {
197
- emitNotification: dependencies.emitNotification,
198
- repoRoot: dependencies.repoRoot,
199
- },
200
- summary
201
- );
202
- printConsumerRuntimeEmptyScopeHint({ write: dependencies.write }, summary, 'workingTree');
203
- },
204
- runEngineFullRepoNoPreflight: async () => {
205
- await dependencies.runRepoGate();
206
- dependencies.clearSummaryOverride();
207
- const summary = renderConsumerRuntimeSummary({
208
- repoRoot: dependencies.repoRoot,
209
- write: dependencies.write,
210
- useColor: dependencies.useColor,
211
- });
212
- notifyConsumerRuntimeAuditSummary(
213
- {
214
- emitNotification: dependencies.emitNotification,
215
- repoRoot: dependencies.repoRoot,
216
- },
217
- summary
218
- );
219
- },
220
140
  runPatternChecks: async () => {
221
141
  dependencies.write(`\n${renderConsumerRuntimePatternChecks(dependencies.repoRoot)}\n`);
222
142
  },