pumuki 6.3.72 → 6.3.75
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/docs/README.md +9 -7
- package/docs/operations/RELEASE_NOTES.md +0 -7
- package/docs/product/USAGE.md +2 -5
- package/docs/validation/README.md +3 -1
- package/integrations/evidence/buildEvidence.ts +14 -0
- package/integrations/evidence/repoState.ts +3 -0
- package/integrations/evidence/schema.ts +18 -0
- package/integrations/evidence/trackingContract.ts +146 -0
- package/integrations/evidence/writeEvidence.ts +14 -0
- package/integrations/gate/evaluateAiGate.ts +166 -3
- package/integrations/gate/governanceActionCatalog.ts +275 -0
- package/integrations/gate/remediationCatalog.ts +8 -0
- package/integrations/git/GitService.ts +0 -25
- package/integrations/git/aiGateRepoPolicyFindings.ts +4 -0
- package/integrations/git/runPlatformGate.ts +9 -1
- package/integrations/git/runPlatformGateFacts.ts +0 -7
- package/integrations/git/runPlatformGateOutput.ts +36 -27
- package/integrations/lifecycle/adapter.ts +24 -0
- package/integrations/lifecycle/bootstrapManifest.ts +248 -0
- package/integrations/lifecycle/cli.ts +45 -11
- package/integrations/lifecycle/cliSdd.ts +4 -3
- package/integrations/lifecycle/doctor.ts +49 -1
- package/integrations/lifecycle/governanceNextAction.ts +164 -0
- package/integrations/lifecycle/governanceObservationSnapshot.ts +315 -0
- package/integrations/lifecycle/install.ts +21 -0
- package/integrations/lifecycle/state.ts +8 -1
- package/integrations/lifecycle/status.ts +29 -2
- package/integrations/mcp/aiGateCheck.ts +140 -10
- package/integrations/mcp/alignedPlatformGate.ts +232 -0
- package/integrations/mcp/autoExecuteAiStart.ts +92 -85
- package/integrations/mcp/enterpriseServer.ts +6 -6
- package/integrations/mcp/preFlightCheck.ts +51 -5
- package/integrations/mcp/readMcpPrePushStdin.ts +7 -0
- package/integrations/policy/experimentalFeatures.ts +1 -1
- package/package.json +2 -4
- package/scripts/build-ruralgo-s1-evidence-pack.ts +85 -0
- package/scripts/consumer-menu-matrix-baseline-report-lib.ts +38 -13
- package/scripts/framework-menu-consumer-actions-lib.ts +4 -28
- package/scripts/framework-menu-consumer-preflight-hints.ts +2 -5
- package/scripts/framework-menu-consumer-preflight-render.ts +6 -0
- package/scripts/framework-menu-consumer-preflight-run.ts +19 -0
- package/scripts/framework-menu-consumer-preflight-types.ts +8 -0
- package/scripts/framework-menu-consumer-runtime-actions.ts +6 -86
- package/scripts/framework-menu-consumer-runtime-audit.ts +2 -36
- package/scripts/framework-menu-consumer-runtime-lib.ts +0 -2
- package/scripts/framework-menu-consumer-runtime-types.ts +1 -3
- package/scripts/framework-menu-evidence-summary-lib.ts +0 -1
- package/scripts/framework-menu-evidence-summary-read.ts +5 -57
- package/scripts/framework-menu-evidence-summary-severity.ts +1 -3
- package/scripts/framework-menu-evidence-summary-types.ts +0 -7
- package/scripts/framework-menu-gate-lib.ts +0 -9
- package/scripts/framework-menu-layout-data.ts +0 -5
- package/scripts/framework-menu-matrix-baseline-lib.ts +14 -15
- package/scripts/framework-menu-matrix-canary-lib.ts +1 -22
- package/scripts/framework-menu-matrix-evidence-lib.ts +0 -1
- package/scripts/framework-menu-matrix-evidence-types.ts +1 -13
- package/scripts/framework-menu-matrix-runner-lib.ts +0 -35
- package/scripts/framework-menu-system-notifications-macos.ts +0 -4
- package/scripts/framework-menu.ts +0 -3
- package/scripts/ruralgo-s1-evidence-pack-lib.ts +200 -0
- package/AGENTS.md +0 -269
- package/CHANGELOG.md +0 -666
- package/docs/tracking/plan-curso-pumuki-stack-my-architecture.md +0 -111
- package/scripts/framework-menu-consumer-runtime-evidence-classic.ts +0 -140
|
@@ -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' | '
|
|
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,
|
|
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:
|
|
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
|
|
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,
|
|
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
|
-
|
|
6
|
-
|
|
7
|
-
|
|
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
|
|
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 =
|
|
60
|
+
const byOption = OPTION_IDS.reduce<Record<MatrixOptionId, MatrixOptionDrift>>((acc, optionId) => {
|
|
68
61
|
acc[optionId] = computeOptionDrift(rounds, optionId);
|
|
69
62
|
return acc;
|
|
70
|
-
},
|
|
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 =
|
|
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'
|
|
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
|
|
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,200 @@
|
|
|
1
|
+
import { mkdirSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import { dirname, resolve } from 'node:path';
|
|
3
|
+
|
|
4
|
+
type RuralGoS1EvidenceEntry = {
|
|
5
|
+
title: string;
|
|
6
|
+
mode: 'shell' | 'mcp';
|
|
7
|
+
command: string;
|
|
8
|
+
capture: ReadonlyArray<string>;
|
|
9
|
+
expectedFragments: ReadonlyArray<string>;
|
|
10
|
+
incs: ReadonlyArray<string>;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export type RuralGoS1EvidencePackOptions = {
|
|
14
|
+
cwd: string;
|
|
15
|
+
consumerRoot: string;
|
|
16
|
+
packageVersion: string;
|
|
17
|
+
generatedAt: string;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
const resolvePumukiPackageSelector = (packageVersion: string): string => {
|
|
21
|
+
const trimmed = packageVersion.trim();
|
|
22
|
+
const isStableSemver = /^\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.-]+)?$/.test(trimmed);
|
|
23
|
+
if (isStableSemver) {
|
|
24
|
+
return `pumuki@${trimmed}`;
|
|
25
|
+
}
|
|
26
|
+
return 'pumuki@latest';
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
const EVIDENCE_ENTRIES: ReadonlyArray<RuralGoS1EvidenceEntry> = [
|
|
30
|
+
{
|
|
31
|
+
title: 'Lifecycle status',
|
|
32
|
+
mode: 'shell',
|
|
33
|
+
command: 'npm run pumuki:status',
|
|
34
|
+
capture: [
|
|
35
|
+
'Bloque `governance truth` completo.',
|
|
36
|
+
'Indicadores de contrato efectivo, rama y skills surface.',
|
|
37
|
+
],
|
|
38
|
+
expectedFragments: [
|
|
39
|
+
'governance truth',
|
|
40
|
+
'governance_effective',
|
|
41
|
+
'contract_surface',
|
|
42
|
+
'current_branch',
|
|
43
|
+
],
|
|
44
|
+
incs: ['PUMUKI-INC-070', 'PUMUKI-INC-071', 'PUMUKI-INC-073', 'PUMUKI-INC-076'],
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
title: 'Lifecycle doctor',
|
|
48
|
+
mode: 'shell',
|
|
49
|
+
command: 'npm run pumuki:doctor',
|
|
50
|
+
capture: [
|
|
51
|
+
'Veredicto humano final.',
|
|
52
|
+
'Bloque `governance truth` con `next_action` visible.',
|
|
53
|
+
],
|
|
54
|
+
expectedFragments: [
|
|
55
|
+
'governance truth',
|
|
56
|
+
'next_action',
|
|
57
|
+
'reason_code',
|
|
58
|
+
'WARN',
|
|
59
|
+
],
|
|
60
|
+
incs: ['PUMUKI-INC-070', 'PUMUKI-INC-071', 'PUMUKI-INC-073'],
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
title: 'PRE_WRITE canónico',
|
|
64
|
+
mode: 'shell',
|
|
65
|
+
command: 'npx --yes --package pumuki@latest pumuki sdd validate --stage=PRE_WRITE --json',
|
|
66
|
+
capture: [
|
|
67
|
+
'Salida JSON completa.',
|
|
68
|
+
'Campos de session/mode y remediación inmediata.',
|
|
69
|
+
],
|
|
70
|
+
expectedFragments: [
|
|
71
|
+
'"stage":"PRE_WRITE"',
|
|
72
|
+
'"decision"',
|
|
73
|
+
'"next_action"',
|
|
74
|
+
],
|
|
75
|
+
incs: ['PUMUKI-INC-070', 'PUMUKI-INC-072'],
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
title: 'Hook pre-commit / gate',
|
|
79
|
+
mode: 'shell',
|
|
80
|
+
command: 'git commit --allow-empty -m "test: pumuki s1 validation"',
|
|
81
|
+
capture: [
|
|
82
|
+
'Bloque de gate con `reason_code`, `instruction` y `next_action`.',
|
|
83
|
+
'Si bloquea, conservar `NEXT:` y `REMEDIATION:`.',
|
|
84
|
+
],
|
|
85
|
+
expectedFragments: [
|
|
86
|
+
'reason_code=',
|
|
87
|
+
'instruction=',
|
|
88
|
+
'next_action=',
|
|
89
|
+
],
|
|
90
|
+
incs: ['PUMUKI-INC-071', 'PUMUKI-INC-073', 'PUMUKI-INC-076'],
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
title: 'MCP pre_flight_check',
|
|
94
|
+
mode: 'mcp',
|
|
95
|
+
command: 'mcp::pre_flight_check(stage=PRE_WRITE)',
|
|
96
|
+
capture: [
|
|
97
|
+
'Payload completo de `result`.',
|
|
98
|
+
'Campos `reason_code`, `instruction`, `next_action`, `hints`.',
|
|
99
|
+
],
|
|
100
|
+
expectedFragments: [
|
|
101
|
+
'reason_code',
|
|
102
|
+
'instruction',
|
|
103
|
+
'next_action',
|
|
104
|
+
'hints',
|
|
105
|
+
],
|
|
106
|
+
incs: ['PUMUKI-INC-071', 'PUMUKI-INC-072', 'PUMUKI-INC-073'],
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
title: 'MCP auto_execute_ai_start',
|
|
110
|
+
mode: 'mcp',
|
|
111
|
+
command: 'mcp::auto_execute_ai_start(stage=PRE_WRITE)',
|
|
112
|
+
capture: [
|
|
113
|
+
'Payload completo de `result`.',
|
|
114
|
+
'Campos `action`, `reason_code`, `next_action`, `confidence_pct`.',
|
|
115
|
+
],
|
|
116
|
+
expectedFragments: [
|
|
117
|
+
'action',
|
|
118
|
+
'reason_code',
|
|
119
|
+
'next_action',
|
|
120
|
+
'confidence_pct',
|
|
121
|
+
],
|
|
122
|
+
incs: ['PUMUKI-INC-071', 'PUMUKI-INC-073', 'PUMUKI-INC-076'],
|
|
123
|
+
},
|
|
124
|
+
];
|
|
125
|
+
|
|
126
|
+
const renderEntry = (params: {
|
|
127
|
+
entry: RuralGoS1EvidenceEntry;
|
|
128
|
+
consumerRoot: string;
|
|
129
|
+
}): string => {
|
|
130
|
+
const command = params.entry.mode === 'shell'
|
|
131
|
+
? `cd ${params.consumerRoot} && ${params.entry.command}`
|
|
132
|
+
: params.entry.command;
|
|
133
|
+
|
|
134
|
+
return [
|
|
135
|
+
`### ${params.entry.title}`,
|
|
136
|
+
'',
|
|
137
|
+
`- mode: ${params.entry.mode}`,
|
|
138
|
+
`- command: \`${command}\``,
|
|
139
|
+
`- incs: ${params.entry.incs.join(', ')}`,
|
|
140
|
+
'- capture:',
|
|
141
|
+
...params.entry.capture.map((item) => ` - ${item}`),
|
|
142
|
+
'- expected_fragments:',
|
|
143
|
+
...params.entry.expectedFragments.map((item) => ` - ${item}`),
|
|
144
|
+
'',
|
|
145
|
+
].join('\n');
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
export const buildRuralGoS1EvidencePackMarkdown = (
|
|
149
|
+
options: RuralGoS1EvidencePackOptions
|
|
150
|
+
): string => {
|
|
151
|
+
const pumukiPackageSelector = resolvePumukiPackageSelector(options.packageVersion);
|
|
152
|
+
const evidenceEntries: ReadonlyArray<RuralGoS1EvidenceEntry> = EVIDENCE_ENTRIES.map((entry) =>
|
|
153
|
+
entry.title === 'PRE_WRITE canónico'
|
|
154
|
+
? {
|
|
155
|
+
...entry,
|
|
156
|
+
command: `npx --yes --package ${pumukiPackageSelector} pumuki sdd validate --stage=PRE_WRITE --json`,
|
|
157
|
+
}
|
|
158
|
+
: entry
|
|
159
|
+
);
|
|
160
|
+
|
|
161
|
+
return [
|
|
162
|
+
'# RuralGo S1 Evidence Pack',
|
|
163
|
+
'',
|
|
164
|
+
`- generated_at: ${options.generatedAt}`,
|
|
165
|
+
`- consumer_root: \`${options.consumerRoot}\``,
|
|
166
|
+
`- package_version: ${options.packageVersion}`,
|
|
167
|
+
'- objective: validar S1 contra PUMUKI-INC-071/073/076 y reunir soporte adicional para 070/072.',
|
|
168
|
+
'',
|
|
169
|
+
'## Uso',
|
|
170
|
+
'',
|
|
171
|
+
'- Ejecuta los comandos shell desde el consumer real tras repinear la semver publicada.',
|
|
172
|
+
'- Captura las respuestas MCP desde una sesión conectada al servidor enterprise.',
|
|
173
|
+
'- No muevas un INC a `FIXED` si falta convergencia entre lifecycle, hooks y MCP.',
|
|
174
|
+
'',
|
|
175
|
+
...evidenceEntries.map((entry) =>
|
|
176
|
+
renderEntry({
|
|
177
|
+
entry,
|
|
178
|
+
consumerRoot: options.consumerRoot,
|
|
179
|
+
})
|
|
180
|
+
),
|
|
181
|
+
'## Criterio rápido de cierre',
|
|
182
|
+
'',
|
|
183
|
+
'- `PUMUKI-INC-071`: candidato a FIXED si lifecycle, hooks y MCP exponen contrato efectivo del repo.',
|
|
184
|
+
'- `PUMUKI-INC-073`: candidato a FIXED si el verde parcial desaparece y se ve governance real.',
|
|
185
|
+
'- `PUMUKI-INC-076`: candidato a FIXED si hooks y surfaces muestran GitFlow/naming como parte del gate.',
|
|
186
|
+
'- `PUMUKI-INC-072`: no cerrar salvo que el pre-edit gate aparezca de forma homogénea y automática.',
|
|
187
|
+
'',
|
|
188
|
+
].join('\n');
|
|
189
|
+
};
|
|
190
|
+
|
|
191
|
+
export const writeRuralGoS1EvidencePack = (params: {
|
|
192
|
+
cwd: string;
|
|
193
|
+
outFile: string;
|
|
194
|
+
markdown: string;
|
|
195
|
+
}): string => {
|
|
196
|
+
const outputPath = resolve(params.cwd, params.outFile);
|
|
197
|
+
mkdirSync(dirname(outputPath), { recursive: true });
|
|
198
|
+
writeFileSync(outputPath, params.markdown, 'utf8');
|
|
199
|
+
return outputPath;
|
|
200
|
+
};
|