pumuki 6.3.97 → 6.3.99
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 +697 -0
- package/README.md +4 -2
- package/VERSION +1 -1
- package/docs/README.md +13 -9
- package/docs/operations/RELEASE_NOTES.md +12 -76
- 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/policyValidationSnapshot.ts +8 -2
- 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 +87 -94
- 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
|
@@ -0,0 +1,346 @@
|
|
|
1
|
+
import { spawnSync } from 'node:child_process';
|
|
2
|
+
import { existsSync } from 'node:fs';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import {
|
|
5
|
+
installedBinMarkerPath,
|
|
6
|
+
resolveSmokeLayout,
|
|
7
|
+
} from './pumuki-full-surface-smoke-lib';
|
|
8
|
+
|
|
9
|
+
type SmokeRowKind = 'core' | 'diagnostic';
|
|
10
|
+
|
|
11
|
+
type SmokeRow = {
|
|
12
|
+
id: string;
|
|
13
|
+
bin: string;
|
|
14
|
+
args: ReadonlyArray<string>;
|
|
15
|
+
timeoutMs: number;
|
|
16
|
+
allowNonZero?: boolean;
|
|
17
|
+
kind: SmokeRowKind;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
const parseBooleanEnv = (raw: string | undefined): boolean => {
|
|
21
|
+
const value = (raw ?? '').trim().toLowerCase();
|
|
22
|
+
return value === '1' || value === 'true' || value === 'yes';
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const includeDiagnosticRowsInStrict = parseBooleanEnv(
|
|
26
|
+
process.env.PUMUKI_SMOKE_INCLUDE_DIAGNOSTIC_ROWS
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
const layout = resolveSmokeLayout({
|
|
30
|
+
scriptFileUrl: import.meta.url,
|
|
31
|
+
env: process.env,
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
const { pumukiPackageRoot, smokeCwd, binStrategy, binRoot } = layout;
|
|
35
|
+
const node = process.execPath;
|
|
36
|
+
const binPath = (name: string): string => join(binRoot, 'bin', name);
|
|
37
|
+
|
|
38
|
+
const run = (row: SmokeRow): { code: number | null; signal: NodeJS.Signals | null; ms: number } => {
|
|
39
|
+
const started = Date.now();
|
|
40
|
+
const r = spawnSync(node, [binPath(row.bin), ...row.args], {
|
|
41
|
+
cwd: smokeCwd,
|
|
42
|
+
encoding: 'utf8',
|
|
43
|
+
timeout: row.timeoutMs,
|
|
44
|
+
maxBuffer: 50 * 1024 * 1024,
|
|
45
|
+
env: { ...process.env, FORCE_COLOR: '0' },
|
|
46
|
+
});
|
|
47
|
+
return { code: r.status, signal: r.signal, ms: Date.now() - started };
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
const rows: ReadonlyArray<SmokeRow> = [
|
|
51
|
+
{ id: 'cli.help_implicit', bin: 'pumuki.js', args: [], timeoutMs: 15_000, kind: 'core', allowNonZero: true },
|
|
52
|
+
{ id: 'cli.help_explicit', bin: 'pumuki.js', args: ['--help'], timeoutMs: 15_000, kind: 'core' },
|
|
53
|
+
{
|
|
54
|
+
id: 'cli.unknown_subcommand',
|
|
55
|
+
bin: 'pumuki.js',
|
|
56
|
+
args: ['__no_such_lifecycle_command__'],
|
|
57
|
+
timeoutMs: 15_000,
|
|
58
|
+
kind: 'core',
|
|
59
|
+
allowNonZero: true,
|
|
60
|
+
},
|
|
61
|
+
{ id: 'doctor.json', bin: 'pumuki.js', args: ['doctor', '--json'], timeoutMs: 60_000, kind: 'core' },
|
|
62
|
+
{
|
|
63
|
+
id: 'doctor.deep_json',
|
|
64
|
+
bin: 'pumuki.js',
|
|
65
|
+
args: ['doctor', '--deep', '--json'],
|
|
66
|
+
timeoutMs: 180_000,
|
|
67
|
+
kind: 'core',
|
|
68
|
+
allowNonZero: true,
|
|
69
|
+
},
|
|
70
|
+
{ id: 'doctor.parity_json', bin: 'pumuki.js', args: ['doctor', '--parity', '--json'], timeoutMs: 120_000, kind: 'core' },
|
|
71
|
+
{ id: 'status.json', bin: 'pumuki.js', args: ['status', '--json'], timeoutMs: 90_000, kind: 'core' },
|
|
72
|
+
{
|
|
73
|
+
id: 'audit.default_json',
|
|
74
|
+
bin: 'pumuki.js',
|
|
75
|
+
args: ['audit', '--json'],
|
|
76
|
+
timeoutMs: 300_000,
|
|
77
|
+
kind: 'core',
|
|
78
|
+
allowNonZero: true,
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
id: 'audit.pre_push_json',
|
|
82
|
+
bin: 'pumuki.js',
|
|
83
|
+
args: ['audit', '--stage=PRE_PUSH', '--json'],
|
|
84
|
+
timeoutMs: 300_000,
|
|
85
|
+
kind: 'core',
|
|
86
|
+
allowNonZero: true,
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
id: 'audit.ci_engine_json',
|
|
90
|
+
bin: 'pumuki.js',
|
|
91
|
+
args: ['audit', '--stage=CI', '--engine', '--json'],
|
|
92
|
+
timeoutMs: 300_000,
|
|
93
|
+
kind: 'core',
|
|
94
|
+
allowNonZero: true,
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
id: 'watch.once_json',
|
|
98
|
+
bin: 'pumuki.js',
|
|
99
|
+
args: [
|
|
100
|
+
'watch',
|
|
101
|
+
'--once',
|
|
102
|
+
'--json',
|
|
103
|
+
'--stage=PRE_COMMIT',
|
|
104
|
+
'--scope=repo',
|
|
105
|
+
'--interval-ms=200',
|
|
106
|
+
'--no-notify',
|
|
107
|
+
],
|
|
108
|
+
timeoutMs: 180_000,
|
|
109
|
+
kind: 'diagnostic',
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
id: 'watch.once_staged_json',
|
|
113
|
+
bin: 'pumuki.js',
|
|
114
|
+
args: [
|
|
115
|
+
'watch',
|
|
116
|
+
'--once',
|
|
117
|
+
'--json',
|
|
118
|
+
'--stage=PRE_COMMIT',
|
|
119
|
+
'--scope=staged',
|
|
120
|
+
'--interval-ms=200',
|
|
121
|
+
'--no-notify',
|
|
122
|
+
],
|
|
123
|
+
timeoutMs: 180_000,
|
|
124
|
+
kind: 'diagnostic',
|
|
125
|
+
allowNonZero: true,
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
id: 'loop.list_json',
|
|
129
|
+
bin: 'pumuki.js',
|
|
130
|
+
args: ['loop', 'list', '--json'],
|
|
131
|
+
timeoutMs: 30_000,
|
|
132
|
+
kind: 'core',
|
|
133
|
+
},
|
|
134
|
+
{
|
|
135
|
+
id: 'loop.run_smoke',
|
|
136
|
+
bin: 'pumuki.js',
|
|
137
|
+
args: ['loop', 'run', '--objective=smoke-surface', '--max-attempts=1', '--json'],
|
|
138
|
+
timeoutMs: 300_000,
|
|
139
|
+
kind: 'core',
|
|
140
|
+
allowNonZero: true,
|
|
141
|
+
},
|
|
142
|
+
{
|
|
143
|
+
id: 'adapter.install_dry_repo_json',
|
|
144
|
+
bin: 'pumuki.js',
|
|
145
|
+
args: ['adapter', 'install', '--agent=repo', '--dry-run', '--json'],
|
|
146
|
+
timeoutMs: 30_000,
|
|
147
|
+
kind: 'core',
|
|
148
|
+
},
|
|
149
|
+
{
|
|
150
|
+
id: 'adapter.install_dry_codex_json',
|
|
151
|
+
bin: 'pumuki.js',
|
|
152
|
+
args: ['adapter', 'install', '--agent=codex', '--dry-run', '--json'],
|
|
153
|
+
timeoutMs: 30_000,
|
|
154
|
+
kind: 'core',
|
|
155
|
+
},
|
|
156
|
+
{
|
|
157
|
+
id: 'analytics.hotspots_report',
|
|
158
|
+
bin: 'pumuki.js',
|
|
159
|
+
args: ['analytics', 'hotspots', 'report', '--top=3', '--since-days=30', '--json'],
|
|
160
|
+
timeoutMs: 120_000,
|
|
161
|
+
kind: 'diagnostic',
|
|
162
|
+
allowNonZero: true,
|
|
163
|
+
},
|
|
164
|
+
{
|
|
165
|
+
id: 'analytics.hotspots_diagnose',
|
|
166
|
+
bin: 'pumuki.js',
|
|
167
|
+
args: ['analytics', 'hotspots', 'diagnose', '--json'],
|
|
168
|
+
timeoutMs: 120_000,
|
|
169
|
+
kind: 'diagnostic',
|
|
170
|
+
allowNonZero: true,
|
|
171
|
+
},
|
|
172
|
+
{
|
|
173
|
+
id: 'policy.reconcile_json',
|
|
174
|
+
bin: 'pumuki.js',
|
|
175
|
+
args: ['policy', 'reconcile', '--json'],
|
|
176
|
+
timeoutMs: 120_000,
|
|
177
|
+
kind: 'diagnostic',
|
|
178
|
+
allowNonZero: true,
|
|
179
|
+
},
|
|
180
|
+
{
|
|
181
|
+
id: 'policy.reconcile_strict_json',
|
|
182
|
+
bin: 'pumuki.js',
|
|
183
|
+
args: ['policy', 'reconcile', '--strict', '--json'],
|
|
184
|
+
timeoutMs: 120_000,
|
|
185
|
+
kind: 'diagnostic',
|
|
186
|
+
allowNonZero: true,
|
|
187
|
+
},
|
|
188
|
+
{
|
|
189
|
+
id: 'sdd.status_json',
|
|
190
|
+
bin: 'pumuki.js',
|
|
191
|
+
args: ['sdd', 'status', '--json'],
|
|
192
|
+
timeoutMs: 60_000,
|
|
193
|
+
kind: 'diagnostic',
|
|
194
|
+
},
|
|
195
|
+
{
|
|
196
|
+
id: 'sdd.validate_pre_write_json',
|
|
197
|
+
bin: 'pumuki.js',
|
|
198
|
+
args: ['sdd', 'validate', '--stage=PRE_WRITE', '--json'],
|
|
199
|
+
timeoutMs: 120_000,
|
|
200
|
+
kind: 'diagnostic',
|
|
201
|
+
allowNonZero: true,
|
|
202
|
+
},
|
|
203
|
+
{
|
|
204
|
+
id: 'sdd.validate_precommit_json',
|
|
205
|
+
bin: 'pumuki.js',
|
|
206
|
+
args: ['sdd', 'validate', '--stage=PRE_COMMIT', '--json'],
|
|
207
|
+
timeoutMs: 120_000,
|
|
208
|
+
kind: 'diagnostic',
|
|
209
|
+
allowNonZero: true,
|
|
210
|
+
},
|
|
211
|
+
{
|
|
212
|
+
id: 'sdd.validate_prepush_json',
|
|
213
|
+
bin: 'pumuki.js',
|
|
214
|
+
args: ['sdd', 'validate', '--stage=PRE_PUSH', '--json'],
|
|
215
|
+
timeoutMs: 120_000,
|
|
216
|
+
kind: 'diagnostic',
|
|
217
|
+
allowNonZero: true,
|
|
218
|
+
},
|
|
219
|
+
{
|
|
220
|
+
id: 'sdd.validate_ci_json',
|
|
221
|
+
bin: 'pumuki.js',
|
|
222
|
+
args: ['sdd', 'validate', '--stage=CI', '--json'],
|
|
223
|
+
timeoutMs: 120_000,
|
|
224
|
+
kind: 'diagnostic',
|
|
225
|
+
allowNonZero: true,
|
|
226
|
+
},
|
|
227
|
+
{
|
|
228
|
+
id: 'hook.pre_write',
|
|
229
|
+
bin: 'pumuki-pre-write.js',
|
|
230
|
+
args: [],
|
|
231
|
+
timeoutMs: 300_000,
|
|
232
|
+
kind: 'diagnostic',
|
|
233
|
+
allowNonZero: true,
|
|
234
|
+
},
|
|
235
|
+
{
|
|
236
|
+
id: 'hook.pre_commit',
|
|
237
|
+
bin: 'pumuki-pre-commit.js',
|
|
238
|
+
args: [],
|
|
239
|
+
timeoutMs: 300_000,
|
|
240
|
+
kind: 'diagnostic',
|
|
241
|
+
allowNonZero: true,
|
|
242
|
+
},
|
|
243
|
+
{
|
|
244
|
+
id: 'hook.pre_push',
|
|
245
|
+
bin: 'pumuki-pre-push.js',
|
|
246
|
+
args: [],
|
|
247
|
+
timeoutMs: 300_000,
|
|
248
|
+
kind: 'diagnostic',
|
|
249
|
+
allowNonZero: true,
|
|
250
|
+
},
|
|
251
|
+
{
|
|
252
|
+
id: 'hook.ci',
|
|
253
|
+
bin: 'pumuki-ci.js',
|
|
254
|
+
args: [],
|
|
255
|
+
timeoutMs: 300_000,
|
|
256
|
+
kind: 'diagnostic',
|
|
257
|
+
allowNonZero: true,
|
|
258
|
+
},
|
|
259
|
+
];
|
|
260
|
+
|
|
261
|
+
const main = (): number => {
|
|
262
|
+
if (binStrategy === 'installed') {
|
|
263
|
+
const marker = installedBinMarkerPath(layout);
|
|
264
|
+
if (!existsSync(marker)) {
|
|
265
|
+
process.stderr.write(
|
|
266
|
+
`[pumuki] smoke: PUMUKI_SMOKE_BIN_STRATEGY=installed pero no existe ${marker}. ` +
|
|
267
|
+
'Ejecuta npm install en el consumidor o revisa PUMUKI_SMOKE_REPO_ROOT.\n'
|
|
268
|
+
);
|
|
269
|
+
return 2;
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
const lines: string[] = [];
|
|
274
|
+
lines.push('# Pumuki superficie — smoke');
|
|
275
|
+
lines.push('');
|
|
276
|
+
lines.push(`- binStrategy: \`${binStrategy}\` (PUMUKI_SMOKE_BIN_STRATEGY=source|installed)`);
|
|
277
|
+
lines.push(`- binRoot: \`${binRoot}\``);
|
|
278
|
+
lines.push(`- pumukiPackageRoot (script host): \`${pumukiPackageRoot}\``);
|
|
279
|
+
lines.push(`- smokeCwd (gate/doctor cwd): \`${smokeCwd}\``);
|
|
280
|
+
lines.push(`- node: \`${node}\``);
|
|
281
|
+
lines.push(
|
|
282
|
+
`- filas: **${rows.length}** (incluye CLI, doctor/status, audit×3, watch×2, loop, adapter×2, analytics×2, policy×2, sdd×5, hooks×4)`
|
|
283
|
+
);
|
|
284
|
+
lines.push(
|
|
285
|
+
`- modo: \`${includeDiagnosticRowsInStrict ? 'strict+diagnostic' : 'strict-only'}\`` +
|
|
286
|
+
' (activar diagnóstico con `PUMUKI_SMOKE_INCLUDE_DIAGNOSTIC_ROWS=1`)'
|
|
287
|
+
);
|
|
288
|
+
lines.push('');
|
|
289
|
+
lines.push('| id | tipo | exit | ms | ok |');
|
|
290
|
+
lines.push('|----|----|------|----|----|');
|
|
291
|
+
let strictFailed = 0;
|
|
292
|
+
let diagnosticFailed = 0;
|
|
293
|
+
for (const row of rows) {
|
|
294
|
+
const { code, signal, ms } = run(row);
|
|
295
|
+
const exit = signal ? `signal:${signal}` : String(code ?? 'null');
|
|
296
|
+
const ok =
|
|
297
|
+
signal !== null
|
|
298
|
+
? false
|
|
299
|
+
: row.allowNonZero
|
|
300
|
+
? true
|
|
301
|
+
: code === 0;
|
|
302
|
+
const isStrict = row.kind === 'core' || includeDiagnosticRowsInStrict;
|
|
303
|
+
if (!ok) {
|
|
304
|
+
if (isStrict) {
|
|
305
|
+
strictFailed += 1;
|
|
306
|
+
} else {
|
|
307
|
+
diagnosticFailed += 1;
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
lines.push(`| ${row.id} | ${row.kind} | ${exit} | ${ms} | ${ok ? 'yes' : 'no'} |`);
|
|
311
|
+
}
|
|
312
|
+
lines.push('');
|
|
313
|
+
lines.push('## Interpretación de exit codes');
|
|
314
|
+
lines.push('');
|
|
315
|
+
lines.push('- `audit` devuelve el **mismo código que el gate** del alcance auditado (p. ej. 1 si hay `BLOCK` en el repo). Eso es correcto, no indica CLI roto.');
|
|
316
|
+
lines.push('- `doctor --deep` puede devolver **1** si `doctorHasBlockingIssues` (issues `error` o `deep.blocking`) o mismatch de parity esperado.');
|
|
317
|
+
lines.push('- Los comandos de diagnóstico (`diagnostic`) quedan fuera de fallo estricto por defecto.');
|
|
318
|
+
lines.push('- `sdd validate` y `policy reconcile --strict` pueden devolver **1** según política del repo; el smoke los marca con `allowNonZero`.');
|
|
319
|
+
lines.push('');
|
|
320
|
+
lines.push('## No cubierto aquí (manual o destructivo)');
|
|
321
|
+
lines.push('');
|
|
322
|
+
lines.push('- `pumuki install|uninstall|remove|update|bootstrap` (mutan hooks/artefactos).');
|
|
323
|
+
lines.push('- `pumuki framework` / menú interactivo (`pumuki-framework.js`).');
|
|
324
|
+
lines.push('- Servidores MCP stdio (`pumuki-mcp-*-stdio.js`): esperan JSON-RPC por stdin; probar con cliente MCP.');
|
|
325
|
+
lines.push('- `pumuki sdd session|sync|learn|evidence|state-sync|auto-sync`: requieren ids / evidencia / cambios reales.');
|
|
326
|
+
lines.push('- `pumuki doctor|status --remote-checks`: dependen de red / GitHub.');
|
|
327
|
+
lines.push('');
|
|
328
|
+
lines.push('## Otro repo (consumidor)');
|
|
329
|
+
lines.push('');
|
|
330
|
+
lines.push(
|
|
331
|
+
'- **Bins del tree pumuki (desarrollo):** `PUMUKI_SMOKE_REPO_ROOT=/ruta/al/repo npm run -s smoke:pumuki-surface` desde la raíz de **pumuki** (`PUMUKI_SMOKE_BIN_STRATEGY=source` por defecto).'
|
|
332
|
+
);
|
|
333
|
+
lines.push(
|
|
334
|
+
'- **Bins instalados en el consumidor (`node_modules/pumuki`):** `PUMUKI_SMOKE_REPO_ROOT=/ruta/al/repo PUMUKI_SMOKE_BIN_STRATEGY=installed npm run -s smoke:pumuki-surface` o `npm run -s smoke:pumuki-surface-installed` (exige `PUMUKI_SMOKE_REPO_ROOT`).'
|
|
335
|
+
);
|
|
336
|
+
lines.push('');
|
|
337
|
+
lines.push(
|
|
338
|
+
`**Resumen:** ${strictFailed} filas críticas con fallo estricto (sin allowNonZero),` +
|
|
339
|
+
` ${diagnosticFailed} filas diagnósticas con fallo no bloqueante.`
|
|
340
|
+
);
|
|
341
|
+
process.stdout.write(lines.join('\n'));
|
|
342
|
+
process.stdout.write('\n');
|
|
343
|
+
return strictFailed > 0 ? 1 : 0;
|
|
344
|
+
};
|
|
345
|
+
|
|
346
|
+
process.exitCode = main();
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
const { spawnSync } = require('node:child_process');
|
|
5
|
+
const { join } = require('node:path');
|
|
6
|
+
|
|
7
|
+
if (!process.env.PUMUKI_SMOKE_REPO_ROOT || !String(process.env.PUMUKI_SMOKE_REPO_ROOT).trim()) {
|
|
8
|
+
console.error(
|
|
9
|
+
'[pumuki] smoke:pumuki-surface-installed requires PUMUKI_SMOKE_REPO_ROOT (absolute path to consumer repo).'
|
|
10
|
+
);
|
|
11
|
+
process.exit(1);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const root = join(__dirname, '..');
|
|
15
|
+
const env = {
|
|
16
|
+
...process.env,
|
|
17
|
+
PUMUKI_SMOKE_BIN_STRATEGY: 'installed',
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
const result = spawnSync(
|
|
21
|
+
'npx',
|
|
22
|
+
['--yes', 'tsx@4.21.0', 'scripts/pumuki-full-surface-smoke.ts'],
|
|
23
|
+
{
|
|
24
|
+
cwd: root,
|
|
25
|
+
env,
|
|
26
|
+
stdio: 'inherit',
|
|
27
|
+
}
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
const code = typeof result.status === 'number' ? result.status : 1;
|
|
31
|
+
process.exitCode = code;
|
|
@@ -1,150 +0,0 @@
|
|
|
1
|
-
import { existsSync, readFileSync } from 'node:fs';
|
|
2
|
-
import { dirname, relative, resolve, sep } from 'node:path';
|
|
3
|
-
import type { RepoTrackingDeclaration, RepoTrackingState } from './schema';
|
|
4
|
-
|
|
5
|
-
const TRACKING_DECLARATION_SOURCES = [
|
|
6
|
-
'AGENTS.md',
|
|
7
|
-
'docs/README.md',
|
|
8
|
-
'docs/validation/README.md',
|
|
9
|
-
'docs/strategy/README.md',
|
|
10
|
-
] as const;
|
|
11
|
-
|
|
12
|
-
const TRACKING_KEYWORDS =
|
|
13
|
-
/(seguimiento|tracking interno|tracking can[oó]nico|canonical tracking|fuente viva|fuente can[oó]nica|source of truth|single source)/i;
|
|
14
|
-
const TRACKING_PRIORITY_SOURCE = new Set(['AGENTS.md']);
|
|
15
|
-
const IN_PROGRESS_PATTERNS = [
|
|
16
|
-
/^- Estado:\s*🚧/m,
|
|
17
|
-
/^- 🚧 (\`?P[0-9A-Za-z.-]+\`?)/m,
|
|
18
|
-
/^\`?\[\s*🚧\s*\]\s*-\`?/m,
|
|
19
|
-
/^-\s*\`?\[\s*🚧\s*\]\s*-\`?/m,
|
|
20
|
-
/^\|\s*🚧(?:\s|\|)/m,
|
|
21
|
-
/^\|[^|\n]+\|\s*🚧(?:\s|\|)/m,
|
|
22
|
-
/^\|[^|\n]+\|\s*\`?\[\s*🚧\s*\]\s*-\`?/m,
|
|
23
|
-
] as const;
|
|
24
|
-
|
|
25
|
-
const toRepoRelativePath = (repoRoot: string, absolutePath: string): string => {
|
|
26
|
-
const relativePath = relative(repoRoot, absolutePath).replace(/\\/g, '/');
|
|
27
|
-
return relativePath.length > 0 && !relativePath.startsWith('..') ? relativePath : absolutePath.replace(/\\/g, '/');
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
const collectDeclaredPathsFromLine = (line: string): string[] => {
|
|
31
|
-
const matches = new Set<string>();
|
|
32
|
-
for (const regex of [/`([^`]+\.md)`/g, /\[[^\]]+\]\(([^)]+\.md)\)/g]) {
|
|
33
|
-
let match: RegExpExecArray | null;
|
|
34
|
-
while ((match = regex.exec(line)) !== null) {
|
|
35
|
-
const candidate = match[1]?.trim();
|
|
36
|
-
if (candidate) {
|
|
37
|
-
matches.add(candidate);
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
return [...matches];
|
|
42
|
-
};
|
|
43
|
-
|
|
44
|
-
const collectTrackingDeclarations = (repoRoot: string): ReadonlyArray<RepoTrackingDeclaration> => {
|
|
45
|
-
const declarations: RepoTrackingDeclaration[] = [];
|
|
46
|
-
for (const sourceFile of TRACKING_DECLARATION_SOURCES) {
|
|
47
|
-
const absoluteSourcePath = resolve(repoRoot, sourceFile);
|
|
48
|
-
if (!existsSync(absoluteSourcePath)) {
|
|
49
|
-
continue;
|
|
50
|
-
}
|
|
51
|
-
const content = readFileSync(absoluteSourcePath, 'utf8');
|
|
52
|
-
for (const line of content.split(/\r?\n/)) {
|
|
53
|
-
if (!TRACKING_KEYWORDS.test(line)) {
|
|
54
|
-
continue;
|
|
55
|
-
}
|
|
56
|
-
for (const declaredPath of collectDeclaredPathsFromLine(line)) {
|
|
57
|
-
const resolvedPath = declaredPath.startsWith('./') || declaredPath.startsWith('../')
|
|
58
|
-
? resolve(repoRoot, dirname(sourceFile), declaredPath)
|
|
59
|
-
: resolve(repoRoot, declaredPath);
|
|
60
|
-
declarations.push({
|
|
61
|
-
source_file: sourceFile,
|
|
62
|
-
declared_path: declaredPath,
|
|
63
|
-
resolved_path: toRepoRelativePath(repoRoot, resolvedPath),
|
|
64
|
-
});
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
const deduped = new Map<string, RepoTrackingDeclaration>();
|
|
69
|
-
for (const declaration of declarations) {
|
|
70
|
-
deduped.set(
|
|
71
|
-
`${declaration.source_file}::${declaration.resolved_path}`,
|
|
72
|
-
declaration
|
|
73
|
-
);
|
|
74
|
-
}
|
|
75
|
-
return [...deduped.values()];
|
|
76
|
-
};
|
|
77
|
-
|
|
78
|
-
const resolveCanonicalTrackingPath = (
|
|
79
|
-
declarations: ReadonlyArray<RepoTrackingDeclaration>
|
|
80
|
-
): { canonicalPath: string | null; sourceFile: string | null; conflict: boolean } => {
|
|
81
|
-
if (declarations.length === 0) {
|
|
82
|
-
return {
|
|
83
|
-
canonicalPath: null,
|
|
84
|
-
sourceFile: null,
|
|
85
|
-
conflict: false,
|
|
86
|
-
};
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
const agentsDeclarations = declarations.filter((entry) => TRACKING_PRIORITY_SOURCE.has(entry.source_file));
|
|
90
|
-
const preferred = agentsDeclarations.length > 0 ? agentsDeclarations : declarations;
|
|
91
|
-
const preferredPaths = [...new Set(preferred.map((entry) => entry.resolved_path))];
|
|
92
|
-
const allPaths = [...new Set(declarations.map((entry) => entry.resolved_path))];
|
|
93
|
-
|
|
94
|
-
if (preferredPaths.length === 0) {
|
|
95
|
-
return {
|
|
96
|
-
canonicalPath: null,
|
|
97
|
-
sourceFile: null,
|
|
98
|
-
conflict: allPaths.length > 1,
|
|
99
|
-
};
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
const canonicalPath = preferredPaths[0] ?? null;
|
|
103
|
-
const sourceFile =
|
|
104
|
-
preferred.find((entry) => entry.resolved_path === canonicalPath)?.source_file
|
|
105
|
-
?? null;
|
|
106
|
-
return {
|
|
107
|
-
canonicalPath,
|
|
108
|
-
sourceFile,
|
|
109
|
-
conflict: allPaths.length > 1 || preferredPaths.length > 1,
|
|
110
|
-
};
|
|
111
|
-
};
|
|
112
|
-
|
|
113
|
-
const countInProgressMarkers = (absolutePath: string): number => {
|
|
114
|
-
if (!existsSync(absolutePath)) {
|
|
115
|
-
return 0;
|
|
116
|
-
}
|
|
117
|
-
const content = readFileSync(absolutePath, 'utf8');
|
|
118
|
-
const matchedLines = new Set<number>();
|
|
119
|
-
const lines = content.split(/\r?\n/);
|
|
120
|
-
lines.forEach((line, index) => {
|
|
121
|
-
if (IN_PROGRESS_PATTERNS.some((pattern) => pattern.test(line))) {
|
|
122
|
-
matchedLines.add(index);
|
|
123
|
-
}
|
|
124
|
-
});
|
|
125
|
-
return matchedLines.size;
|
|
126
|
-
};
|
|
127
|
-
|
|
128
|
-
export const readRepoTrackingState = (repoRoot: string): RepoTrackingState => {
|
|
129
|
-
const declarations = collectTrackingDeclarations(repoRoot);
|
|
130
|
-
const enforced = declarations.length > 0;
|
|
131
|
-
const resolution = resolveCanonicalTrackingPath(declarations);
|
|
132
|
-
const canonicalAbsolutePath = resolution.canonicalPath
|
|
133
|
-
? resolve(repoRoot, resolution.canonicalPath.split('/').join(sep))
|
|
134
|
-
: null;
|
|
135
|
-
const canonicalPresent = canonicalAbsolutePath ? existsSync(canonicalAbsolutePath) : false;
|
|
136
|
-
const inProgressCount = canonicalPresent && canonicalAbsolutePath
|
|
137
|
-
? countInProgressMarkers(canonicalAbsolutePath)
|
|
138
|
-
: null;
|
|
139
|
-
|
|
140
|
-
return {
|
|
141
|
-
enforced,
|
|
142
|
-
canonical_path: resolution.canonicalPath,
|
|
143
|
-
canonical_present: canonicalPresent,
|
|
144
|
-
source_file: resolution.sourceFile,
|
|
145
|
-
in_progress_count: inProgressCount,
|
|
146
|
-
single_in_progress_valid: inProgressCount === null ? null : inProgressCount === 1,
|
|
147
|
-
conflict: resolution.conflict,
|
|
148
|
-
declarations,
|
|
149
|
-
};
|
|
150
|
-
};
|