pumuki 6.3.97 → 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.
- package/AGENTS.md +269 -0
- package/CHANGELOG.md +688 -0
- package/README.md +4 -2
- package/VERSION +1 -1
- package/docs/README.md +13 -9
- package/docs/operations/RELEASE_NOTES.md +9 -78
- package/docs/product/HOW_IT_WORKS.md +6 -0
- package/docs/product/INSTALLATION.md +1 -1
- package/docs/product/USAGE.md +41 -4
- package/docs/tracking/plan-curso-pumuki-stack-my-architecture.md +118 -0
- package/docs/validation/README.md +6 -3
- package/integrations/config/skillsCustomRules.ts +18 -99
- package/integrations/evidence/buildEvidence.ts +0 -24
- package/integrations/evidence/repoState.ts +0 -3
- package/integrations/evidence/schema.ts +0 -18
- package/integrations/evidence/writeEvidence.ts +0 -24
- package/integrations/gate/evaluateAiGate.ts +15 -232
- package/integrations/gate/remediationCatalog.ts +0 -8
- package/integrations/git/GitService.ts +44 -5
- package/integrations/git/aiGateRepoPolicyFindings.ts +0 -4
- package/integrations/git/runPlatformGate.ts +1 -9
- package/integrations/git/runPlatformGateFacts.ts +19 -1
- package/integrations/git/runPlatformGateOutput.ts +27 -36
- package/integrations/lifecycle/adapter.templates.json +7 -13
- package/integrations/lifecycle/adapter.ts +0 -24
- package/integrations/lifecycle/artifacts.ts +1 -6
- package/integrations/lifecycle/audit.ts +101 -0
- package/integrations/lifecycle/cli.ts +110 -70
- package/integrations/lifecycle/cliSdd.ts +13 -8
- package/integrations/lifecycle/doctor.ts +16 -48
- package/integrations/lifecycle/hookManager.ts +0 -77
- package/integrations/lifecycle/index.ts +2 -0
- package/integrations/lifecycle/install.ts +0 -21
- package/integrations/lifecycle/npmService.ts +3 -155
- package/integrations/lifecycle/preWriteAutomation.ts +7 -77
- package/integrations/lifecycle/state.ts +1 -8
- package/integrations/lifecycle/status.ts +2 -29
- package/integrations/mcp/aiGateCheck.ts +26 -206
- package/integrations/mcp/autoExecuteAiStart.ts +85 -92
- package/integrations/mcp/enterpriseServer.ts +7 -23
- package/integrations/mcp/enterpriseStdioServer.cli.ts +4 -31
- package/integrations/mcp/preFlightCheck.ts +5 -51
- package/integrations/platform/detectPlatforms.ts +37 -0
- package/integrations/policy/experimentalFeatures.ts +1 -1
- package/integrations/sdd/evidenceScaffold.ts +2 -109
- package/package.json +10 -2
- package/scripts/check-tracking-single-active.sh +1 -1
- package/scripts/consumer-menu-matrix-baseline-report-lib.ts +13 -38
- package/scripts/consumer-postinstall-resolve-args.cjs +44 -0
- package/scripts/consumer-postinstall.cjs +76 -21
- package/scripts/framework-menu-advanced-view-lib.ts +0 -15
- package/scripts/framework-menu-consumer-actions-lib.ts +28 -4
- package/scripts/framework-menu-consumer-preflight-hints.ts +5 -2
- package/scripts/framework-menu-consumer-preflight-render.ts +0 -10
- package/scripts/framework-menu-consumer-preflight-run.ts +0 -23
- package/scripts/framework-menu-consumer-preflight-types.ts +0 -12
- package/scripts/framework-menu-consumer-runtime-actions.ts +87 -17
- package/scripts/framework-menu-consumer-runtime-audit.ts +36 -2
- package/scripts/framework-menu-consumer-runtime-evidence-classic.ts +140 -0
- package/scripts/framework-menu-consumer-runtime-lib.ts +2 -10
- package/scripts/framework-menu-consumer-runtime-menu.ts +4 -18
- package/scripts/framework-menu-consumer-runtime-types.ts +3 -3
- package/scripts/framework-menu-evidence-summary-lib.ts +1 -0
- package/scripts/framework-menu-evidence-summary-read.ts +57 -5
- package/scripts/framework-menu-evidence-summary-severity.ts +3 -1
- package/scripts/framework-menu-evidence-summary-types.ts +7 -0
- package/scripts/framework-menu-gate-lib.ts +9 -0
- package/scripts/framework-menu-layout-data.ts +5 -0
- package/scripts/framework-menu-matrix-baseline-lib.ts +15 -14
- package/scripts/framework-menu-matrix-canary-lib.ts +22 -1
- package/scripts/framework-menu-matrix-evidence-lib.ts +1 -0
- package/scripts/framework-menu-matrix-evidence-types.ts +13 -1
- package/scripts/framework-menu-matrix-runner-lib.ts +35 -0
- package/scripts/framework-menu-system-notifications-cause.ts +0 -24
- package/scripts/framework-menu-system-notifications-macos-swift-source.ts +24 -204
- package/scripts/framework-menu-system-notifications-macos.ts +4 -0
- package/scripts/framework-menu-system-notifications-payloads-blocked.ts +1 -1
- package/scripts/framework-menu-system-notifications-remediation.ts +13 -24
- package/scripts/framework-menu-system-notifications-text.ts +1 -7
- package/scripts/framework-menu.ts +3 -2
- package/scripts/package-install-smoke-consumer-git-repo-lib.ts +1 -10
- package/scripts/package-install-smoke-consumer-npm-lib.ts +9 -46
- package/scripts/pumuki-full-surface-smoke-lib.ts +37 -0
- package/scripts/pumuki-full-surface-smoke.ts +346 -0
- package/scripts/pumuki-smoke-installed-wrapper.cjs +31 -0
- package/integrations/evidence/trackingContract.ts +0 -150
- package/integrations/gate/governanceActionCatalog.ts +0 -275
- package/integrations/lifecycle/bootstrapManifest.ts +0 -248
- package/integrations/lifecycle/cliGovernanceConsole.ts +0 -69
- package/integrations/lifecycle/governanceNextAction.ts +0 -164
- package/integrations/lifecycle/governanceObservationSnapshot.ts +0 -613
- package/integrations/mcp/alignedPlatformGate.ts +0 -232
- package/integrations/mcp/readMcpPrePushStdin.ts +0 -7
- package/scripts/build-ruralgo-s1-evidence-pack.ts +0 -85
- package/scripts/ruralgo-s1-evidence-pack-lib.ts +0 -200
|
@@ -13,9 +13,10 @@ import {
|
|
|
13
13
|
renderBadge,
|
|
14
14
|
} from './framework-menu-ui-components-lib';
|
|
15
15
|
import { isMenuUiV2Enabled } from './framework-menu-ui-version-lib';
|
|
16
|
-
import {
|
|
17
|
-
|
|
18
|
-
|
|
16
|
+
import type {
|
|
17
|
+
ConsumerAction,
|
|
18
|
+
ConsumerRuntimeWrite,
|
|
19
|
+
} from './framework-menu-consumer-runtime-types';
|
|
19
20
|
|
|
20
21
|
const buildConsumerRuntimeMenuStatus = (
|
|
21
22
|
menuSummary: FrameworkMenuEvidenceSummary
|
|
@@ -57,7 +58,6 @@ export const renderConsumerRuntimeModernMenu = (
|
|
|
57
58
|
actions: ReadonlyArray<ConsumerAction>;
|
|
58
59
|
repoRoot: string;
|
|
59
60
|
useColor: () => boolean;
|
|
60
|
-
preflight?: ConsumerPreflightResult | null;
|
|
61
61
|
}
|
|
62
62
|
): string => {
|
|
63
63
|
const menuSummary = readEvidenceSummaryForMenu(params.repoRoot);
|
|
@@ -71,18 +71,6 @@ export const renderConsumerRuntimeModernMenu = (
|
|
|
71
71
|
'PUMUKI — Hook-System (run: npx ast-hooks)',
|
|
72
72
|
'AST Intelligence System Overview',
|
|
73
73
|
`Status: ${renderBadge(menuStatus.label, menuStatus.level, tokens)}`,
|
|
74
|
-
...(params.preflight
|
|
75
|
-
? [
|
|
76
|
-
'',
|
|
77
|
-
'Governance Console',
|
|
78
|
-
...buildGovernanceConsoleSummaryLines({
|
|
79
|
-
governanceObservation: params.preflight.governanceObservation,
|
|
80
|
-
governanceNextAction: params.preflight.governanceNextAction,
|
|
81
|
-
policyValidation: params.preflight.policyValidation,
|
|
82
|
-
experimentalFeatures: params.preflight.experimentalFeatures,
|
|
83
|
-
}).map((line) => ` ${line}`),
|
|
84
|
-
]
|
|
85
|
-
: []),
|
|
86
74
|
'A. Switch to advanced menu',
|
|
87
75
|
'',
|
|
88
76
|
...groupedActions.flatMap((group) => [
|
|
@@ -105,7 +93,6 @@ export const printConsumerRuntimeMenu = (params: {
|
|
|
105
93
|
repoRoot: string;
|
|
106
94
|
useColor: () => boolean;
|
|
107
95
|
write: ConsumerRuntimeWrite;
|
|
108
|
-
preflight?: ConsumerPreflightResult | null;
|
|
109
96
|
}): void => {
|
|
110
97
|
const classicMenu = renderConsumerRuntimeClassicMenu(params.actions, params.useColor);
|
|
111
98
|
if (!isMenuUiV2Enabled()) {
|
|
@@ -118,7 +105,6 @@ export const printConsumerRuntimeMenu = (params: {
|
|
|
118
105
|
actions: params.actions,
|
|
119
106
|
repoRoot: params.repoRoot,
|
|
120
107
|
useColor: params.useColor,
|
|
121
|
-
preflight: params.preflight,
|
|
122
108
|
})}\n`);
|
|
123
109
|
} catch {
|
|
124
110
|
params.write('\n[pumuki][menu-ui-v2] Render failed. Falling back to classic menu.\n');
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import type { FrameworkMenuEvidenceSummary } from './framework-menu-evidence-summary-lib';
|
|
2
|
-
import type { ConsumerPreflightResult } from './framework-menu-consumer-preflight-types';
|
|
3
2
|
import type {
|
|
4
3
|
PumukiCriticalNotificationEvent,
|
|
5
4
|
SystemNotificationEmitResult,
|
|
@@ -34,7 +33,9 @@ export type ConsumerMenuRuntimeParams = {
|
|
|
34
33
|
runRepoGate: () => Promise<ConsumerRuntimeGateResult | void>;
|
|
35
34
|
runRepoAndStagedGate: () => Promise<ConsumerRuntimeGateResult | void>;
|
|
36
35
|
runStagedGate: () => Promise<ConsumerRuntimeGateResult | void>;
|
|
36
|
+
runUnstagedGate: () => Promise<ConsumerRuntimeGateResult | void>;
|
|
37
37
|
runWorkingTreeGate: () => Promise<ConsumerRuntimeGateResult | void>;
|
|
38
|
+
runWorkingTreePreCommitGate: () => Promise<ConsumerRuntimeGateResult | void>;
|
|
38
39
|
runPreflight?: (
|
|
39
40
|
stage: 'PRE_COMMIT' | 'PRE_PUSH'
|
|
40
41
|
) => Promise<string | void> | string | void;
|
|
@@ -46,10 +47,9 @@ export type ConsumerMenuRuntime = {
|
|
|
46
47
|
actions: ReadonlyArray<ConsumerAction>;
|
|
47
48
|
printMenu: () => void;
|
|
48
49
|
readCurrentSummary: () => FrameworkMenuEvidenceSummary | null;
|
|
49
|
-
readLastPreflight: () => ConsumerPreflightResult | null;
|
|
50
50
|
};
|
|
51
51
|
|
|
52
|
-
export type ConsumerRuntimeScope = 'staged' | 'workingTree';
|
|
52
|
+
export type ConsumerRuntimeScope = 'staged' | 'unstaged' | 'workingTree';
|
|
53
53
|
|
|
54
54
|
export type ConsumerRuntimeSummaryDependencies = {
|
|
55
55
|
repoRoot: string;
|
|
@@ -3,5 +3,6 @@ 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';
|
|
6
7
|
export { readEvidenceSummaryForMenu } from './framework-menu-evidence-summary-read';
|
|
7
8
|
export { formatEvidenceSummaryForMenu } from './framework-menu-evidence-summary-format';
|
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type {
|
|
2
|
+
EvidenceSnapshot,
|
|
3
|
+
FrameworkMenuEvidencePlatformRow,
|
|
4
|
+
FrameworkMenuEvidenceSummary,
|
|
5
|
+
} from './framework-menu-evidence-summary-types';
|
|
2
6
|
import { readEvidenceSummaryFile } from './framework-menu-evidence-summary-file';
|
|
3
7
|
import {
|
|
4
8
|
asFindings,
|
|
@@ -16,9 +20,55 @@ import {
|
|
|
16
20
|
toTopFiles,
|
|
17
21
|
} from './framework-menu-evidence-summary-severity';
|
|
18
22
|
|
|
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
|
+
|
|
19
65
|
export const readEvidenceSummaryForMenu = (
|
|
20
|
-
repoRoot: string = process.cwd()
|
|
66
|
+
repoRoot: string = process.cwd(),
|
|
67
|
+
options?: ReadEvidenceSummaryForMenuOptions
|
|
21
68
|
): FrameworkMenuEvidenceSummary => {
|
|
69
|
+
const topFindingsLimit = options?.topFindingsLimit ?? 10;
|
|
70
|
+
const topFileLocationsLimit = options?.topFileLocationsLimit ?? 10;
|
|
71
|
+
const topFilesLimit = options?.topFilesLimit ?? 5;
|
|
22
72
|
const evidence = readEvidenceSummaryFile(repoRoot);
|
|
23
73
|
|
|
24
74
|
if (evidence.status === 'missing') {
|
|
@@ -65,12 +115,13 @@ export const readEvidenceSummaryForMenu = (
|
|
|
65
115
|
evidence.snapshot.files_affected ?? evidence.snapshot.filesAffected
|
|
66
116
|
);
|
|
67
117
|
const topFileLocations = countFiles({ findings, repoRoot })
|
|
68
|
-
.slice(0,
|
|
118
|
+
.slice(0, topFileLocationsLimit)
|
|
69
119
|
.map((entry) => ({
|
|
70
120
|
file: entry.file,
|
|
71
121
|
line: entry.line,
|
|
72
122
|
}));
|
|
73
|
-
const topFindings = buildTopFindings({ findings, repoRoot, maxItems:
|
|
123
|
+
const topFindings = buildTopFindings({ findings, repoRoot, maxItems: topFindingsLimit });
|
|
124
|
+
const platformAuditRows = parsePlatformAuditRows(evidence.snapshot);
|
|
74
125
|
|
|
75
126
|
return {
|
|
76
127
|
status: 'ok',
|
|
@@ -81,8 +132,9 @@ export const readEvidenceSummaryForMenu = (
|
|
|
81
132
|
filesAffected,
|
|
82
133
|
bySeverity,
|
|
83
134
|
byEnterpriseSeverity,
|
|
84
|
-
topFiles: toTopFiles({ findings, repoRoot }),
|
|
135
|
+
topFiles: toTopFiles({ findings, repoRoot, maxItems: topFilesLimit }),
|
|
85
136
|
topFileLocations,
|
|
86
137
|
topFindings,
|
|
138
|
+
...(platformAuditRows.length > 0 ? { platformAuditRows } : {}),
|
|
87
139
|
};
|
|
88
140
|
};
|
|
@@ -50,7 +50,9 @@ export const countFindingsBySeverity = (
|
|
|
50
50
|
export const toTopFiles = (params: {
|
|
51
51
|
findings: ReadonlyArray<EvidenceFinding>;
|
|
52
52
|
repoRoot: string;
|
|
53
|
+
maxItems?: number;
|
|
53
54
|
}): ReadonlyArray<{ file: string; count: number }> => {
|
|
55
|
+
const maxItems = params.maxItems ?? 5;
|
|
54
56
|
const filesMap = new Map<string, number>();
|
|
55
57
|
for (const finding of params.findings) {
|
|
56
58
|
const rawFile = toStringOrNull(finding.file);
|
|
@@ -66,7 +68,7 @@ export const toTopFiles = (params: {
|
|
|
66
68
|
|
|
67
69
|
return [...filesMap.entries()]
|
|
68
70
|
.sort((left, right) => right[1] - left[1] || left[0].localeCompare(right[0]))
|
|
69
|
-
.slice(0,
|
|
71
|
+
.slice(0, maxItems)
|
|
70
72
|
.map(([file, count]) => ({ file, count }));
|
|
71
73
|
};
|
|
72
74
|
|
|
@@ -18,12 +18,18 @@ export type EvidenceSnapshot = {
|
|
|
18
18
|
stage?: unknown;
|
|
19
19
|
outcome?: unknown;
|
|
20
20
|
findings?: unknown;
|
|
21
|
+
platforms?: unknown;
|
|
21
22
|
};
|
|
22
23
|
|
|
23
24
|
export type EvidenceSeverityMetrics = {
|
|
24
25
|
by_enterprise_severity?: unknown;
|
|
25
26
|
};
|
|
26
27
|
|
|
28
|
+
export type FrameworkMenuEvidencePlatformRow = {
|
|
29
|
+
platform: string;
|
|
30
|
+
violations: number;
|
|
31
|
+
};
|
|
32
|
+
|
|
27
33
|
export type FrameworkMenuEvidenceSummary = {
|
|
28
34
|
status: 'ok' | 'missing' | 'invalid';
|
|
29
35
|
stage: string | null;
|
|
@@ -41,4 +47,5 @@ export type FrameworkMenuEvidenceSummary = {
|
|
|
41
47
|
file: string;
|
|
42
48
|
line: number;
|
|
43
49
|
}>;
|
|
50
|
+
platformAuditRows?: ReadonlyArray<FrameworkMenuEvidencePlatformRow>;
|
|
44
51
|
};
|
|
@@ -9,6 +9,7 @@ export type MenuStage = 'PRE_COMMIT' | 'PRE_PUSH' | 'CI';
|
|
|
9
9
|
|
|
10
10
|
export type MenuScope =
|
|
11
11
|
| { kind: 'staged' }
|
|
12
|
+
| { kind: 'unstaged' }
|
|
12
13
|
| { kind: 'repo' }
|
|
13
14
|
| { kind: 'repoAndStaged' }
|
|
14
15
|
| { kind: 'workingTree' }
|
|
@@ -141,6 +142,14 @@ export const runWorkingTreePrePushGateSilent = async (): Promise<void> => {
|
|
|
141
142
|
await runMenuAuditGate(gateParams);
|
|
142
143
|
};
|
|
143
144
|
|
|
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
|
+
|
|
144
153
|
const runMenuAuditGate = async (
|
|
145
154
|
gateParams: ReturnType<typeof buildMenuGateParams>
|
|
146
155
|
): Promise<void> => {
|
|
@@ -6,6 +6,11 @@ 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
|
+
},
|
|
9
14
|
{
|
|
10
15
|
key: 'export',
|
|
11
16
|
title: 'Legacy Read-Only Export',
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import {
|
|
2
2
|
runConsumerMenuMatrix,
|
|
3
3
|
} from './framework-menu-matrix-runner-lib';
|
|
4
|
-
import
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
4
|
+
import {
|
|
5
|
+
MATRIX_MENU_OPTION_IDS,
|
|
6
|
+
type ConsumerMenuMatrixReport,
|
|
7
|
+
type ConsumerMenuMatrixOptionReport,
|
|
8
|
+
type MatrixOptionId,
|
|
8
9
|
} from './framework-menu-matrix-evidence-lib';
|
|
9
10
|
|
|
10
11
|
export type MatrixOptionDrift = {
|
|
@@ -22,7 +23,13 @@ export type ConsumerMenuMatrixBaselineReport = {
|
|
|
22
23
|
analysis: ConsumerMenuMatrixBaselineAnalysis;
|
|
23
24
|
};
|
|
24
25
|
|
|
25
|
-
const
|
|
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
|
+
};
|
|
26
33
|
|
|
27
34
|
const OPTION_FIELDS: ReadonlyArray<keyof ConsumerMenuMatrixOptionReport> = [
|
|
28
35
|
'stage',
|
|
@@ -57,18 +64,12 @@ const computeOptionDrift = (
|
|
|
57
64
|
export const analyzeConsumerMenuMatrixBaseline = (
|
|
58
65
|
rounds: ReadonlyArray<ConsumerMenuMatrixReport>
|
|
59
66
|
): ConsumerMenuMatrixBaselineAnalysis => {
|
|
60
|
-
const byOption =
|
|
67
|
+
const byOption = MATRIX_MENU_OPTION_IDS.reduce<Record<MatrixOptionId, MatrixOptionDrift>>((acc, optionId) => {
|
|
61
68
|
acc[optionId] = computeOptionDrift(rounds, optionId);
|
|
62
69
|
return acc;
|
|
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
|
-
});
|
|
70
|
+
}, seedMatrixOptionDrift());
|
|
70
71
|
|
|
71
|
-
const stable =
|
|
72
|
+
const stable = MATRIX_MENU_OPTION_IDS.every((optionId) => byOption[optionId].stable);
|
|
72
73
|
|
|
73
74
|
return {
|
|
74
75
|
stable,
|
|
@@ -6,6 +6,8 @@ import {
|
|
|
6
6
|
runRepoAndStagedPrePushGateSilent,
|
|
7
7
|
runRepoGateSilent,
|
|
8
8
|
runStagedGateSilent,
|
|
9
|
+
runUnstagedGateSilent,
|
|
10
|
+
runWorkingTreeGateSilent,
|
|
9
11
|
runWorkingTreePrePushGateSilent,
|
|
10
12
|
} from './framework-menu-gate-lib';
|
|
11
13
|
import { readMatrixOptionReport, type MatrixOptionId } from './framework-menu-matrix-evidence-lib';
|
|
@@ -70,6 +72,25 @@ const runGateByOption = async (option: MatrixOptionId): Promise<void> => {
|
|
|
70
72
|
}
|
|
71
73
|
if (option === '4') {
|
|
72
74
|
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();
|
|
73
94
|
}
|
|
74
95
|
};
|
|
75
96
|
|
|
@@ -104,7 +125,7 @@ export const runConsumerMenuCanary = async (params?: {
|
|
|
104
125
|
scenario.canarySource,
|
|
105
126
|
'utf8'
|
|
106
127
|
);
|
|
107
|
-
if (scenario.option === '1' || scenario.option === '2') {
|
|
128
|
+
if (scenario.option === '1' || scenario.option === '2' || scenario.option === '3' || scenario.option === '11') {
|
|
108
129
|
stageCanaryPath(repoRoot, canaryRelativePath);
|
|
109
130
|
}
|
|
110
131
|
|
|
@@ -8,6 +8,7 @@ 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';
|
|
11
12
|
export { toMatrixOptionReport } from './framework-menu-matrix-evidence-diagnosis';
|
|
12
13
|
|
|
13
14
|
export const readMatrixOptionReport = (
|
|
@@ -1,4 +1,16 @@
|
|
|
1
|
-
export
|
|
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];
|
|
2
14
|
export type MatrixOptionDiagnosis =
|
|
3
15
|
| 'scope-empty'
|
|
4
16
|
| 'repo-clean'
|
|
@@ -3,6 +3,8 @@ import {
|
|
|
3
3
|
runRepoAndStagedPrePushGateSilent,
|
|
4
4
|
runRepoGateSilent,
|
|
5
5
|
runStagedGateSilent,
|
|
6
|
+
runUnstagedGateSilent,
|
|
7
|
+
runWorkingTreeGateSilent,
|
|
6
8
|
runWorkingTreePrePushGateSilent,
|
|
7
9
|
} from './framework-menu-gate-lib';
|
|
8
10
|
import {
|
|
@@ -24,6 +26,8 @@ export type ConsumerMenuMatrixRunnerDependencies = {
|
|
|
24
26
|
runRepoGateSilent: () => Promise<void>;
|
|
25
27
|
runRepoAndStagedPrePushGateSilent: () => Promise<void>;
|
|
26
28
|
runStagedGateSilent: () => Promise<void>;
|
|
29
|
+
runUnstagedGateSilent: () => Promise<void>;
|
|
30
|
+
runWorkingTreeGateSilent: () => Promise<void>;
|
|
27
31
|
runWorkingTreePrePushGateSilent: () => Promise<void>;
|
|
28
32
|
readMatrixOptionReport: (repoRoot: string, optionId: MatrixOptionId) => ConsumerMenuMatrixOptionReport;
|
|
29
33
|
};
|
|
@@ -32,6 +36,8 @@ const createDefaultDependencies = (): ConsumerMenuMatrixRunnerDependencies => ({
|
|
|
32
36
|
runRepoGateSilent,
|
|
33
37
|
runRepoAndStagedPrePushGateSilent,
|
|
34
38
|
runStagedGateSilent,
|
|
39
|
+
runUnstagedGateSilent,
|
|
40
|
+
runWorkingTreeGateSilent,
|
|
35
41
|
runWorkingTreePrePushGateSilent,
|
|
36
42
|
readMatrixOptionReport,
|
|
37
43
|
});
|
|
@@ -84,6 +90,31 @@ export const runConsumerMenuMatrix = async (params?: {
|
|
|
84
90
|
}
|
|
85
91
|
})();
|
|
86
92
|
|
|
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
|
+
|
|
87
118
|
return {
|
|
88
119
|
byOption: {
|
|
89
120
|
'1': option1,
|
|
@@ -91,6 +122,10 @@ export const runConsumerMenuMatrix = async (params?: {
|
|
|
91
122
|
'3': option3,
|
|
92
123
|
'4': option4,
|
|
93
124
|
'9': option9,
|
|
125
|
+
'11': option11,
|
|
126
|
+
'12': option12,
|
|
127
|
+
'13': option13,
|
|
128
|
+
'14': option14,
|
|
94
129
|
},
|
|
95
130
|
};
|
|
96
131
|
} finally {
|
|
@@ -5,7 +5,6 @@ import {
|
|
|
5
5
|
} from './framework-menu-system-notifications-text';
|
|
6
6
|
|
|
7
7
|
const BLOCKED_CAUSE_SUMMARY_BY_CODE: Readonly<Record<string, string>> = {
|
|
8
|
-
EVIDENCE_GATE_BLOCKED: 'El gate de evidencia de IA está bloqueado.',
|
|
9
8
|
EVIDENCE_MISSING: 'Falta evidencia para validar este paso.',
|
|
10
9
|
EVIDENCE_INVALID: 'La evidencia actual es inválida.',
|
|
11
10
|
EVIDENCE_CHAIN_INVALID: 'La cadena de evidencia no es válida.',
|
|
@@ -19,14 +18,6 @@ const BLOCKED_CAUSE_SUMMARY_BY_CODE: Readonly<Record<string, string>> = {
|
|
|
19
18
|
OPENSPEC_MISSING: 'OpenSpec no está instalado en este repositorio.',
|
|
20
19
|
MCP_ENTERPRISE_RECEIPT_MISSING: 'Falta el recibo enterprise de MCP.',
|
|
21
20
|
BACKEND_AVOID_EXPLICIT_ANY: 'Se detectó uso de "any" explícito en backend.',
|
|
22
|
-
FRONTEND_NO_CONSOLE_LOG: 'Se detectó uso de "console.log" en frontend.',
|
|
23
|
-
BACKEND_NO_CONSOLE_LOG: 'Se detectó uso de "console.log" en backend.',
|
|
24
|
-
GIT_ATOMICITY_TOO_MANY_SCOPES: 'Se han cambiado demasiados scopes en el mismo commit.',
|
|
25
|
-
SOLID_HEURISTIC: 'Se detectó una violación estructural en el cambio actual.',
|
|
26
|
-
TRACKING_CANONICAL_SOURCE_CONFLICT:
|
|
27
|
-
'Hay varias fuentes canónicas de seguimiento declaradas.',
|
|
28
|
-
TRACKING_CANONICAL_IN_PROGRESS_INVALID:
|
|
29
|
-
'El archivo canónico de seguimiento debe tener exactamente una tarea en construcción.',
|
|
30
21
|
};
|
|
31
22
|
|
|
32
23
|
const ENGLISH_CAUSE_HINTS = [
|
|
@@ -65,27 +56,12 @@ const toKnownSpanishCauseFromMessage = (message: string): string | null => {
|
|
|
65
56
|
if (normalized.includes('avoid explicit any')) {
|
|
66
57
|
return BLOCKED_CAUSE_SUMMARY_BY_CODE.BACKEND_AVOID_EXPLICIT_ANY;
|
|
67
58
|
}
|
|
68
|
-
if (normalized.includes('console.log usage is not allowed in frontend code')) {
|
|
69
|
-
return BLOCKED_CAUSE_SUMMARY_BY_CODE.FRONTEND_NO_CONSOLE_LOG;
|
|
70
|
-
}
|
|
71
|
-
if (normalized.includes('console.log usage is not allowed in backend code')) {
|
|
72
|
-
return BLOCKED_CAUSE_SUMMARY_BY_CODE.BACKEND_NO_CONSOLE_LOG;
|
|
73
|
-
}
|
|
74
59
|
if (normalized.includes('evidence is stale')) {
|
|
75
60
|
return BLOCKED_CAUSE_SUMMARY_BY_CODE.EVIDENCE_STALE;
|
|
76
61
|
}
|
|
77
|
-
if (normalized.includes('evidence ai gate status is blocked')) {
|
|
78
|
-
return BLOCKED_CAUSE_SUMMARY_BY_CODE.EVIDENCE_GATE_BLOCKED;
|
|
79
|
-
}
|
|
80
62
|
if (normalized.includes('no upstream tracking reference')) {
|
|
81
63
|
return BLOCKED_CAUSE_SUMMARY_BY_CODE.PRE_PUSH_UPSTREAM_MISSING;
|
|
82
64
|
}
|
|
83
|
-
if (normalized.includes('too many scopes changed') || normalized.includes('atomicity budget exceeded')) {
|
|
84
|
-
return BLOCKED_CAUSE_SUMMARY_BY_CODE.GIT_ATOMICITY_TOO_MANY_SCOPES;
|
|
85
|
-
}
|
|
86
|
-
if (normalized.includes('heuristic violation')) {
|
|
87
|
-
return BLOCKED_CAUSE_SUMMARY_BY_CODE.SOLID_HEURISTIC;
|
|
88
|
-
}
|
|
89
65
|
return null;
|
|
90
66
|
};
|
|
91
67
|
|