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
@@ -14,7 +14,6 @@ import {
14
14
  readEvidenceSummaryForMenu,
15
15
  type FrameworkMenuEvidenceSummary,
16
16
  } from './framework-menu-evidence-summary-lib';
17
- import { renderVintageEvidenceReport } from './framework-menu-consumer-runtime-evidence-classic';
18
17
  import type {
19
18
  ConsumerRuntimeBlockedGate,
20
19
  ConsumerRuntimeNotificationDependencies,
@@ -57,36 +56,9 @@ export const renderConsumerRuntimeSummary = (
57
56
  width: resolveLegacyPanelOuterWidth(),
58
57
  color: dependencies.useColor(),
59
58
  })}\n`);
60
-
61
- const vintageSource =
62
- summary.status === 'ok' && !dependencies.summaryOverride
63
- ? readEvidenceSummaryForMenu(dependencies.repoRoot, {
64
- topFindingsLimit: 45,
65
- topFileLocationsLimit: 15,
66
- topFilesLimit: 10,
67
- })
68
- : summary;
69
- renderVintageEvidenceReport({
70
- write: dependencies.write,
71
- summary: vintageSource,
72
- useColor: dependencies.useColor,
73
- });
74
59
  return summary;
75
60
  };
76
61
 
77
- export const printPrePushTrackedEvidenceDiskHint = (params: {
78
- write: ConsumerRuntimeSummaryDependencies['write'];
79
- }): void => {
80
- params.write(
81
- '\n' +
82
- [
83
- 'ℹ PRE_PUSH + `.ai_evidence.json` tracked: on PASS/WARN the gate may skip rewriting the file on disk',
84
- ' (avoids dirty tracked evidence). Local dev: PUMUKI_PRE_PUSH_ALWAYS_WRITE_TRACKED_EVIDENCE=1 forces disk write.',
85
- ].join('\n') +
86
- '\n'
87
- );
88
- };
89
-
90
62
  export const buildConsumerRuntimeBlockedSummary = (
91
63
  blocked: ConsumerRuntimeBlockedGate
92
64
  ): FrameworkMenuEvidenceSummary => ({
@@ -144,18 +116,12 @@ export const printConsumerRuntimeEmptyScopeHint = (
144
116
  }
145
117
  if (scope === 'staged') {
146
118
  dependencies.write(
147
- '\nℹ Scope vacío (staged): no hay archivos soportados en staged para auditar. Resultado PASS por alcance vacío; usa 1, 2 o 14 (repo completo) según necesidad.\n'
148
- );
149
- return;
150
- }
151
- if (scope === 'unstaged') {
152
- dependencies.write(
153
- '\nℹ Scope vacío (unstaged): no hay cambios sin stage ni untracked auditable. Resultado PASS por alcance vacío; usa 1, 14 u opciones 11–13 según el alcance que necesites.\n'
119
+ '\nℹ Scope vacío (staged): no hay archivos soportados en staged para auditar. Resultado PASS por alcance vacío; usa 1 o 2 para validar repo completo.\n'
154
120
  );
155
121
  return;
156
122
  }
157
123
  dependencies.write(
158
- '\nℹ Scope vacío (working tree): no hay archivos soportados en staged/unstaged para auditar. Resultado PASS por alcance vacío; usa 1, 2, 13 o 14 según el alcance que necesites.\n'
124
+ '\nℹ Scope vacío (working tree): no hay archivos soportados en staged/unstaged para auditar. Resultado PASS por alcance vacío; usa 1 o 2 para validar repo completo.\n'
159
125
  );
160
126
  };
161
127
 
@@ -35,9 +35,7 @@ export const createConsumerMenuRuntime = (
35
35
  runRepoGate: params.runRepoGate,
36
36
  runRepoAndStagedGate: params.runRepoAndStagedGate,
37
37
  runStagedGate: params.runStagedGate,
38
- runUnstagedGate: params.runUnstagedGate,
39
38
  runWorkingTreeGate: params.runWorkingTreeGate,
40
- runWorkingTreePreCommitGate: params.runWorkingTreePreCommitGate,
41
39
  runPreflight: params.runPreflight,
42
40
  emitNotification,
43
41
  clearSummaryOverride: () => {
@@ -33,9 +33,7 @@ export type ConsumerMenuRuntimeParams = {
33
33
  runRepoGate: () => Promise<ConsumerRuntimeGateResult | void>;
34
34
  runRepoAndStagedGate: () => Promise<ConsumerRuntimeGateResult | void>;
35
35
  runStagedGate: () => Promise<ConsumerRuntimeGateResult | void>;
36
- runUnstagedGate: () => Promise<ConsumerRuntimeGateResult | void>;
37
36
  runWorkingTreeGate: () => Promise<ConsumerRuntimeGateResult | void>;
38
- runWorkingTreePreCommitGate: () => Promise<ConsumerRuntimeGateResult | void>;
39
37
  runPreflight?: (
40
38
  stage: 'PRE_COMMIT' | 'PRE_PUSH'
41
39
  ) => Promise<string | void> | string | void;
@@ -49,7 +47,7 @@ export type ConsumerMenuRuntime = {
49
47
  readCurrentSummary: () => FrameworkMenuEvidenceSummary | null;
50
48
  };
51
49
 
52
- export type ConsumerRuntimeScope = 'staged' | 'unstaged' | 'workingTree';
50
+ export type ConsumerRuntimeScope = 'staged' | 'workingTree';
53
51
 
54
52
  export type ConsumerRuntimeSummaryDependencies = {
55
53
  repoRoot: string;
@@ -3,6 +3,5 @@ export type {
3
3
  EvidenceSeverity,
4
4
  FrameworkMenuEvidenceSummary,
5
5
  } from './framework-menu-evidence-summary-types';
6
- export type { ReadEvidenceSummaryForMenuOptions } from './framework-menu-evidence-summary-read';
7
6
  export { readEvidenceSummaryForMenu } from './framework-menu-evidence-summary-read';
8
7
  export { formatEvidenceSummaryForMenu } from './framework-menu-evidence-summary-format';
@@ -1,8 +1,4 @@
1
- import type {
2
- EvidenceSnapshot,
3
- FrameworkMenuEvidencePlatformRow,
4
- FrameworkMenuEvidenceSummary,
5
- } from './framework-menu-evidence-summary-types';
1
+ import type { FrameworkMenuEvidenceSummary } from './framework-menu-evidence-summary-types';
6
2
  import { readEvidenceSummaryFile } from './framework-menu-evidence-summary-file';
7
3
  import {
8
4
  asFindings,
@@ -20,55 +16,9 @@ import {
20
16
  toTopFiles,
21
17
  } from './framework-menu-evidence-summary-severity';
22
18
 
23
- export type ReadEvidenceSummaryForMenuOptions = {
24
- topFindingsLimit?: number;
25
- topFileLocationsLimit?: number;
26
- topFilesLimit?: number;
27
- };
28
-
29
- const sumLegacySeverityBand = (row: { by_severity?: unknown }): number => {
30
- const bands = row.by_severity;
31
- if (!bands || typeof bands !== 'object') {
32
- return 0;
33
- }
34
- const b = bands as Record<string, unknown>;
35
- const keys = ['CRITICAL', 'HIGH', 'MEDIUM', 'LOW'] as const;
36
- let total = 0;
37
- for (const key of keys) {
38
- const value = b[key];
39
- if (typeof value === 'number' && Number.isFinite(value)) {
40
- total += value;
41
- }
42
- }
43
- return total;
44
- };
45
-
46
- const parsePlatformAuditRows = (
47
- snapshot: EvidenceSnapshot
48
- ): ReadonlyArray<FrameworkMenuEvidencePlatformRow> => {
49
- const raw = snapshot.platforms;
50
- if (!Array.isArray(raw)) {
51
- return [];
52
- }
53
- const rows: FrameworkMenuEvidencePlatformRow[] = [];
54
- for (const entry of raw) {
55
- if (!entry || typeof entry !== 'object') {
56
- continue;
57
- }
58
- const platform = toStringOrNull((entry as { platform?: unknown }).platform) ?? 'Other';
59
- const violations = sumLegacySeverityBand(entry as { by_severity?: unknown });
60
- rows.push({ platform, violations });
61
- }
62
- return rows;
63
- };
64
-
65
19
  export const readEvidenceSummaryForMenu = (
66
- repoRoot: string = process.cwd(),
67
- options?: ReadEvidenceSummaryForMenuOptions
20
+ repoRoot: string = process.cwd()
68
21
  ): FrameworkMenuEvidenceSummary => {
69
- const topFindingsLimit = options?.topFindingsLimit ?? 10;
70
- const topFileLocationsLimit = options?.topFileLocationsLimit ?? 10;
71
- const topFilesLimit = options?.topFilesLimit ?? 5;
72
22
  const evidence = readEvidenceSummaryFile(repoRoot);
73
23
 
74
24
  if (evidence.status === 'missing') {
@@ -115,13 +65,12 @@ export const readEvidenceSummaryForMenu = (
115
65
  evidence.snapshot.files_affected ?? evidence.snapshot.filesAffected
116
66
  );
117
67
  const topFileLocations = countFiles({ findings, repoRoot })
118
- .slice(0, topFileLocationsLimit)
68
+ .slice(0, 10)
119
69
  .map((entry) => ({
120
70
  file: entry.file,
121
71
  line: entry.line,
122
72
  }));
123
- const topFindings = buildTopFindings({ findings, repoRoot, maxItems: topFindingsLimit });
124
- const platformAuditRows = parsePlatformAuditRows(evidence.snapshot);
73
+ const topFindings = buildTopFindings({ findings, repoRoot, maxItems: 10 });
125
74
 
126
75
  return {
127
76
  status: 'ok',
@@ -132,9 +81,8 @@ export const readEvidenceSummaryForMenu = (
132
81
  filesAffected,
133
82
  bySeverity,
134
83
  byEnterpriseSeverity,
135
- topFiles: toTopFiles({ findings, repoRoot, maxItems: topFilesLimit }),
84
+ topFiles: toTopFiles({ findings, repoRoot }),
136
85
  topFileLocations,
137
86
  topFindings,
138
- ...(platformAuditRows.length > 0 ? { platformAuditRows } : {}),
139
87
  };
140
88
  };
@@ -50,9 +50,7 @@ export const countFindingsBySeverity = (
50
50
  export const toTopFiles = (params: {
51
51
  findings: ReadonlyArray<EvidenceFinding>;
52
52
  repoRoot: string;
53
- maxItems?: number;
54
53
  }): ReadonlyArray<{ file: string; count: number }> => {
55
- const maxItems = params.maxItems ?? 5;
56
54
  const filesMap = new Map<string, number>();
57
55
  for (const finding of params.findings) {
58
56
  const rawFile = toStringOrNull(finding.file);
@@ -68,7 +66,7 @@ export const toTopFiles = (params: {
68
66
 
69
67
  return [...filesMap.entries()]
70
68
  .sort((left, right) => right[1] - left[1] || left[0].localeCompare(right[0]))
71
- .slice(0, maxItems)
69
+ .slice(0, 5)
72
70
  .map(([file, count]) => ({ file, count }));
73
71
  };
74
72
 
@@ -18,18 +18,12 @@ export type EvidenceSnapshot = {
18
18
  stage?: unknown;
19
19
  outcome?: unknown;
20
20
  findings?: unknown;
21
- platforms?: unknown;
22
21
  };
23
22
 
24
23
  export type EvidenceSeverityMetrics = {
25
24
  by_enterprise_severity?: unknown;
26
25
  };
27
26
 
28
- export type FrameworkMenuEvidencePlatformRow = {
29
- platform: string;
30
- violations: number;
31
- };
32
-
33
27
  export type FrameworkMenuEvidenceSummary = {
34
28
  status: 'ok' | 'missing' | 'invalid';
35
29
  stage: string | null;
@@ -47,5 +41,4 @@ export type FrameworkMenuEvidenceSummary = {
47
41
  file: string;
48
42
  line: number;
49
43
  }>;
50
- platformAuditRows?: ReadonlyArray<FrameworkMenuEvidencePlatformRow>;
51
44
  };
@@ -9,7 +9,6 @@ export type MenuStage = 'PRE_COMMIT' | 'PRE_PUSH' | 'CI';
9
9
 
10
10
  export type MenuScope =
11
11
  | { kind: 'staged' }
12
- | { kind: 'unstaged' }
13
12
  | { kind: 'repo' }
14
13
  | { kind: 'repoAndStaged' }
15
14
  | { kind: 'workingTree' }
@@ -142,14 +141,6 @@ export const runWorkingTreePrePushGateSilent = async (): Promise<void> => {
142
141
  await runMenuAuditGate(gateParams);
143
142
  };
144
143
 
145
- export const runUnstagedGateSilent = async (): Promise<void> => {
146
- const gateParams = buildMenuGateParams({
147
- stage: 'PRE_COMMIT',
148
- scope: { kind: 'unstaged' },
149
- });
150
- await runMenuAuditGate(gateParams);
151
- };
152
-
153
144
  const runMenuAuditGate = async (
154
145
  gateParams: ReturnType<typeof buildMenuGateParams>
155
146
  ): Promise<void> => {
@@ -6,11 +6,6 @@ export const CONSUMER_MENU_LAYOUT: ReadonlyArray<MenuLayoutGroup> = [
6
6
  title: 'Read-Only Gate Flows',
7
7
  itemIds: ['1', '2', '3', '4'],
8
8
  },
9
- {
10
- key: 'engine-working-tree-no-preflight',
11
- title: 'Engine · working tree (no preflight)',
12
- itemIds: ['11', '12', '13', '14'],
13
- },
14
9
  {
15
10
  key: 'export',
16
11
  title: 'Legacy Read-Only Export',
@@ -1,11 +1,10 @@
1
1
  import {
2
2
  runConsumerMenuMatrix,
3
3
  } from './framework-menu-matrix-runner-lib';
4
- import {
5
- MATRIX_MENU_OPTION_IDS,
6
- type ConsumerMenuMatrixReport,
7
- type ConsumerMenuMatrixOptionReport,
8
- type MatrixOptionId,
4
+ import type {
5
+ ConsumerMenuMatrixReport,
6
+ ConsumerMenuMatrixOptionReport,
7
+ MatrixOptionId,
9
8
  } from './framework-menu-matrix-evidence-lib';
10
9
 
11
10
  export type MatrixOptionDrift = {
@@ -23,13 +22,7 @@ export type ConsumerMenuMatrixBaselineReport = {
23
22
  analysis: ConsumerMenuMatrixBaselineAnalysis;
24
23
  };
25
24
 
26
- const EMPTY_DRIFT: MatrixOptionDrift = { stable: true, driftFields: [] };
27
-
28
- const seedMatrixOptionDrift = (): Record<MatrixOptionId, MatrixOptionDrift> => {
29
- return Object.fromEntries(
30
- MATRIX_MENU_OPTION_IDS.map((optionId) => [optionId, { ...EMPTY_DRIFT }])
31
- ) as Record<MatrixOptionId, MatrixOptionDrift>;
32
- };
25
+ const OPTION_IDS: ReadonlyArray<MatrixOptionId> = ['1', '2', '3', '4', '9'];
33
26
 
34
27
  const OPTION_FIELDS: ReadonlyArray<keyof ConsumerMenuMatrixOptionReport> = [
35
28
  'stage',
@@ -64,12 +57,18 @@ const computeOptionDrift = (
64
57
  export const analyzeConsumerMenuMatrixBaseline = (
65
58
  rounds: ReadonlyArray<ConsumerMenuMatrixReport>
66
59
  ): ConsumerMenuMatrixBaselineAnalysis => {
67
- const byOption = MATRIX_MENU_OPTION_IDS.reduce<Record<MatrixOptionId, MatrixOptionDrift>>((acc, optionId) => {
60
+ const byOption = OPTION_IDS.reduce<Record<MatrixOptionId, MatrixOptionDrift>>((acc, optionId) => {
68
61
  acc[optionId] = computeOptionDrift(rounds, optionId);
69
62
  return acc;
70
- }, seedMatrixOptionDrift());
63
+ }, {
64
+ '1': { stable: true, driftFields: [] },
65
+ '2': { stable: true, driftFields: [] },
66
+ '3': { stable: true, driftFields: [] },
67
+ '4': { stable: true, driftFields: [] },
68
+ '9': { stable: true, driftFields: [] },
69
+ });
71
70
 
72
- const stable = MATRIX_MENU_OPTION_IDS.every((optionId) => byOption[optionId].stable);
71
+ const stable = OPTION_IDS.every((optionId) => byOption[optionId].stable);
73
72
 
74
73
  return {
75
74
  stable,
@@ -6,8 +6,6 @@ import {
6
6
  runRepoAndStagedPrePushGateSilent,
7
7
  runRepoGateSilent,
8
8
  runStagedGateSilent,
9
- runUnstagedGateSilent,
10
- runWorkingTreeGateSilent,
11
9
  runWorkingTreePrePushGateSilent,
12
10
  } from './framework-menu-gate-lib';
13
11
  import { readMatrixOptionReport, type MatrixOptionId } from './framework-menu-matrix-evidence-lib';
@@ -72,25 +70,6 @@ const runGateByOption = async (option: MatrixOptionId): Promise<void> => {
72
70
  }
73
71
  if (option === '4') {
74
72
  await runWorkingTreePrePushGateSilent();
75
- return;
76
- }
77
- if (option === '9') {
78
- return;
79
- }
80
- if (option === '11') {
81
- await runStagedGateSilent();
82
- return;
83
- }
84
- if (option === '12') {
85
- await runUnstagedGateSilent();
86
- return;
87
- }
88
- if (option === '13') {
89
- await runWorkingTreeGateSilent();
90
- return;
91
- }
92
- if (option === '14') {
93
- await runRepoGateSilent();
94
73
  }
95
74
  };
96
75
 
@@ -125,7 +104,7 @@ export const runConsumerMenuCanary = async (params?: {
125
104
  scenario.canarySource,
126
105
  'utf8'
127
106
  );
128
- if (scenario.option === '1' || scenario.option === '2' || scenario.option === '3' || scenario.option === '11') {
107
+ if (scenario.option === '1' || scenario.option === '2') {
129
108
  stageCanaryPath(repoRoot, canaryRelativePath);
130
109
  }
131
110
 
@@ -8,7 +8,6 @@ export type {
8
8
  MatrixOptionDiagnosis,
9
9
  MatrixOptionId,
10
10
  } from './framework-menu-matrix-evidence-types';
11
- export { MATRIX_MENU_OPTION_IDS } from './framework-menu-matrix-evidence-types';
12
11
  export { toMatrixOptionReport } from './framework-menu-matrix-evidence-diagnosis';
13
12
 
14
13
  export const readMatrixOptionReport = (
@@ -1,16 +1,4 @@
1
- export const MATRIX_MENU_OPTION_IDS = [
2
- '1',
3
- '2',
4
- '3',
5
- '4',
6
- '9',
7
- '11',
8
- '12',
9
- '13',
10
- '14',
11
- ] as const;
12
-
13
- export type MatrixOptionId = (typeof MATRIX_MENU_OPTION_IDS)[number];
1
+ export type MatrixOptionId = '1' | '2' | '3' | '4' | '9';
14
2
  export type MatrixOptionDiagnosis =
15
3
  | 'scope-empty'
16
4
  | 'repo-clean'
@@ -3,8 +3,6 @@ import {
3
3
  runRepoAndStagedPrePushGateSilent,
4
4
  runRepoGateSilent,
5
5
  runStagedGateSilent,
6
- runUnstagedGateSilent,
7
- runWorkingTreeGateSilent,
8
6
  runWorkingTreePrePushGateSilent,
9
7
  } from './framework-menu-gate-lib';
10
8
  import {
@@ -26,8 +24,6 @@ export type ConsumerMenuMatrixRunnerDependencies = {
26
24
  runRepoGateSilent: () => Promise<void>;
27
25
  runRepoAndStagedPrePushGateSilent: () => Promise<void>;
28
26
  runStagedGateSilent: () => Promise<void>;
29
- runUnstagedGateSilent: () => Promise<void>;
30
- runWorkingTreeGateSilent: () => Promise<void>;
31
27
  runWorkingTreePrePushGateSilent: () => Promise<void>;
32
28
  readMatrixOptionReport: (repoRoot: string, optionId: MatrixOptionId) => ConsumerMenuMatrixOptionReport;
33
29
  };
@@ -36,8 +32,6 @@ const createDefaultDependencies = (): ConsumerMenuMatrixRunnerDependencies => ({
36
32
  runRepoGateSilent,
37
33
  runRepoAndStagedPrePushGateSilent,
38
34
  runStagedGateSilent,
39
- runUnstagedGateSilent,
40
- runWorkingTreeGateSilent,
41
35
  runWorkingTreePrePushGateSilent,
42
36
  readMatrixOptionReport,
43
37
  });
@@ -90,31 +84,6 @@ export const runConsumerMenuMatrix = async (params?: {
90
84
  }
91
85
  })();
92
86
 
93
- const option11 = await runOption(
94
- '11',
95
- repoRoot,
96
- dependencies.runStagedGateSilent,
97
- dependencies.readMatrixOptionReport
98
- );
99
- const option12 = await runOption(
100
- '12',
101
- repoRoot,
102
- dependencies.runUnstagedGateSilent,
103
- dependencies.readMatrixOptionReport
104
- );
105
- const option13 = await runOption(
106
- '13',
107
- repoRoot,
108
- dependencies.runWorkingTreeGateSilent,
109
- dependencies.readMatrixOptionReport
110
- );
111
- const option14 = await runOption(
112
- '14',
113
- repoRoot,
114
- dependencies.runRepoGateSilent,
115
- dependencies.readMatrixOptionReport
116
- );
117
-
118
87
  return {
119
88
  byOption: {
120
89
  '1': option1,
@@ -122,10 +91,6 @@ export const runConsumerMenuMatrix = async (params?: {
122
91
  '3': option3,
123
92
  '4': option4,
124
93
  '9': option9,
125
- '11': option11,
126
- '12': option12,
127
- '13': option13,
128
- '14': option14,
129
94
  },
130
95
  };
131
96
  } finally {
@@ -5,7 +5,6 @@ import {
5
5
  type SystemNotificationCommandRunnerWithOutput,
6
6
  type SystemNotificationsConfig,
7
7
  } from './framework-menu-system-notifications-types';
8
- import { isTruthyEnvValue } from './framework-menu-system-notifications-env';
9
8
  import { resolveBlockedDialogEnabled } from './framework-menu-system-notifications-macos-dialog-enabled';
10
9
  import { emitMacOsBannerStage } from './framework-menu-system-notifications-macos-banner-stage';
11
10
  import { emitMacOsBlockedDialogStage } from './framework-menu-system-notifications-macos-blocked-stage';
@@ -20,9 +19,6 @@ const shouldSkipMacOsBannerForInteractiveBlockedDialog = (params: {
20
19
  config: SystemNotificationsConfig;
21
20
  env: NodeJS.ProcessEnv;
22
21
  }): boolean => {
23
- if (!isTruthyEnvValue(params.env.PUMUKI_MACOS_GATE_BLOCKED_BANNER_DEDUPE)) {
24
- return false;
25
- }
26
22
  if (params.event.kind !== 'gate.blocked') {
27
23
  return false;
28
24
  }
@@ -16,7 +16,6 @@ import {
16
16
  runWorkingTreeGateSilent,
17
17
  runRepoAndStagedPrePushGateSilent,
18
18
  runWorkingTreePrePushGateSilent,
19
- runUnstagedGateSilent,
20
19
  } from './framework-menu-gate-lib';
21
20
  import { createFrameworkMenuPrompts } from './framework-menu-prompts';
22
21
  import { resolveDefaultRangeFrom } from './framework-menu-runners';
@@ -63,9 +62,7 @@ const menu = async (): Promise<void> => {
63
62
  runRepoGate: runRepoGateSilent,
64
63
  runRepoAndStagedGate: runRepoAndStagedPrePushGateSilent,
65
64
  runStagedGate: runStagedGateSilent,
66
- runUnstagedGate: runUnstagedGateSilent,
67
65
  runWorkingTreeGate: runWorkingTreePrePushGateSilent,
68
- runWorkingTreePreCommitGate: runWorkingTreeGateSilent,
69
66
  write: (text) => {
70
67
  output.write(text);
71
68
  },
@@ -0,0 +1,37 @@
1
+ import { dirname, join } from 'node:path';
2
+ import { fileURLToPath } from 'node:url';
3
+
4
+ export type SmokeBinStrategy = 'source' | 'installed';
5
+
6
+ export const resolveBinStrategy = (raw: string | undefined): SmokeBinStrategy => {
7
+ const normalized = (raw ?? 'source').trim().toLowerCase();
8
+ if (normalized === 'installed' || normalized === 'consumer') {
9
+ return 'installed';
10
+ }
11
+ return 'source';
12
+ };
13
+
14
+ export type SmokeLayout = {
15
+ pumukiPackageRoot: string;
16
+ smokeCwd: string;
17
+ binStrategy: SmokeBinStrategy;
18
+ binRoot: string;
19
+ };
20
+
21
+ export const resolveSmokeLayout = (params: {
22
+ scriptFileUrl: string;
23
+ env: NodeJS.ProcessEnv;
24
+ }): SmokeLayout => {
25
+ const pumukiPackageRoot = join(dirname(fileURLToPath(params.scriptFileUrl)), '..');
26
+ const smokeCwd =
27
+ (params.env.PUMUKI_SMOKE_REPO_ROOT ?? pumukiPackageRoot).trim() || pumukiPackageRoot;
28
+ const binStrategy = resolveBinStrategy(params.env.PUMUKI_SMOKE_BIN_STRATEGY);
29
+ const binRoot =
30
+ binStrategy === 'installed'
31
+ ? join(smokeCwd, 'node_modules', 'pumuki')
32
+ : pumukiPackageRoot;
33
+ return { pumukiPackageRoot, smokeCwd, binStrategy, binRoot };
34
+ };
35
+
36
+ export const installedBinMarkerPath = (layout: SmokeLayout): string =>
37
+ join(layout.binRoot, 'bin', 'pumuki.js');