pumuki 6.3.39 → 6.3.40
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/README.md +21 -12
- package/VERSION +1 -1
- package/core/gate/evaluateRules.test.ts +40 -0
- package/core/gate/evaluateRules.ts +7 -1
- package/core/rules/Consequence.ts +1 -0
- package/docs/CONFIGURATION.md +50 -0
- package/docs/INSTALLATION.md +38 -11
- package/docs/MCP_SERVERS.md +1 -1
- package/docs/README.md +1 -0
- package/docs/RELEASE_NOTES.md +44 -0
- package/docs/USAGE.md +191 -9
- package/docs/registro-maestro-de-seguimiento.md +2 -2
- package/docs/seguimiento-activo-pumuki-saas-supermercados.md +1592 -1
- package/docs/validation/README.md +2 -1
- package/docs/validation/ast-intelligence-roadmap.md +96 -0
- package/integrations/config/skillsCustomRules.ts +14 -0
- package/integrations/config/skillsDetectorRegistry.ts +11 -1
- package/integrations/config/skillsLock.ts +30 -0
- package/integrations/config/skillsMarkdownRules.ts +14 -3
- package/integrations/config/skillsRuleSet.ts +25 -3
- package/integrations/evidence/readEvidence.test.ts +3 -2
- package/integrations/evidence/readEvidence.ts +14 -4
- package/integrations/evidence/repoState.ts +10 -2
- package/integrations/evidence/schema.test.ts +3 -2
- package/integrations/evidence/schema.ts +3 -0
- package/integrations/evidence/writeEvidence.test.ts +3 -2
- package/integrations/gate/evaluateAiGate.ts +511 -2
- package/integrations/git/GitService.ts +5 -1
- package/integrations/git/astIntelligenceDualValidation.ts +275 -0
- package/integrations/git/gitAtomicity.ts +42 -9
- package/integrations/git/resolveGitRefs.ts +37 -0
- package/integrations/git/runPlatformGate.ts +228 -1
- package/integrations/git/runPlatformGateEvaluation.ts +4 -0
- package/integrations/git/stageRunners.ts +116 -2
- package/integrations/lifecycle/cli.ts +759 -22
- package/integrations/lifecycle/doctor.ts +62 -0
- package/integrations/lifecycle/index.ts +1 -0
- package/integrations/lifecycle/packageInfo.ts +25 -3
- package/integrations/lifecycle/policyReconcile.ts +304 -0
- package/integrations/lifecycle/preWriteAutomation.ts +42 -2
- package/integrations/lifecycle/watch.ts +365 -0
- package/integrations/mcp/aiGateCheck.ts +59 -2
- package/integrations/mcp/autoExecuteAiStart.ts +25 -1
- package/integrations/mcp/preFlightCheck.ts +13 -0
- package/integrations/sdd/evidenceScaffold.ts +223 -0
- package/integrations/sdd/index.ts +2 -0
- package/integrations/sdd/stateSync.ts +400 -0
- package/integrations/sdd/syncDocs.ts +97 -2
- package/package.json +4 -1
- package/scripts/backlog-action-reasons-lib.ts +38 -0
- package/scripts/backlog-id-issue-map-lib.ts +69 -0
- package/scripts/backlog-json-contract-lib.ts +3 -0
- package/scripts/framework-menu-consumer-preflight-lib.ts +6 -0
- package/scripts/package-install-smoke-command-resolution-lib.ts +64 -0
- package/scripts/package-install-smoke-consumer-npm-lib.ts +43 -0
- package/scripts/package-install-smoke-consumer-repo-setup-lib.ts +2 -0
- package/scripts/package-install-smoke-execution-steps-lib.ts +27 -9
- package/scripts/package-install-smoke-lifecycle-lib.ts +15 -4
- package/scripts/package-install-smoke-workspace-factory-lib.ts +4 -1
- package/scripts/reconcile-consumer-backlog-issues-lib.ts +651 -0
- package/scripts/reconcile-consumer-backlog-issues.ts +348 -0
- package/scripts/watch-consumer-backlog-lib.ts +465 -0
- package/scripts/watch-consumer-backlog.ts +326 -0
|
@@ -32,8 +32,12 @@ import {
|
|
|
32
32
|
readSddStatus,
|
|
33
33
|
refreshSddSession,
|
|
34
34
|
runSddAutoSync,
|
|
35
|
+
runSddEvidenceScaffold,
|
|
35
36
|
runSddLearn,
|
|
37
|
+
runSddStateSync,
|
|
36
38
|
runSddSyncDocs,
|
|
39
|
+
type SddEvidenceScaffoldTestStatus,
|
|
40
|
+
type SddStateSyncStatus,
|
|
37
41
|
type SddStage,
|
|
38
42
|
} from '../sdd';
|
|
39
43
|
import { evaluateAiGate } from '../gate/evaluateAiGate';
|
|
@@ -46,6 +50,12 @@ import {
|
|
|
46
50
|
buildPreWriteAutomationTrace,
|
|
47
51
|
type PreWriteAutomationTrace,
|
|
48
52
|
} from './preWriteAutomation';
|
|
53
|
+
import {
|
|
54
|
+
runLifecycleWatch,
|
|
55
|
+
type LifecycleWatchScope,
|
|
56
|
+
type LifecycleWatchSeverityThreshold,
|
|
57
|
+
type LifecycleWatchStage,
|
|
58
|
+
} from './watch';
|
|
49
59
|
import { buildLocalHotspotsReport, type LocalHotspotsReport } from './analyticsHotspots';
|
|
50
60
|
import { resolveHotspotsSaasIngestionAuditPath } from './saasIngestionAudit';
|
|
51
61
|
import { readHotspotsSaasIngestionPayload } from './saasIngestionContract';
|
|
@@ -58,23 +68,36 @@ import {
|
|
|
58
68
|
collectRemoteCiDiagnostics,
|
|
59
69
|
type RemoteCiDiagnostics,
|
|
60
70
|
} from './remoteCiDiagnostics';
|
|
71
|
+
import { runPolicyReconcile } from './policyReconcile';
|
|
61
72
|
|
|
62
73
|
type LifecycleCommand =
|
|
74
|
+
| 'bootstrap'
|
|
63
75
|
| 'install'
|
|
64
76
|
| 'uninstall'
|
|
65
77
|
| 'remove'
|
|
66
78
|
| 'update'
|
|
67
79
|
| 'doctor'
|
|
68
80
|
| 'status'
|
|
81
|
+
| 'watch'
|
|
69
82
|
| 'loop'
|
|
70
83
|
| 'sdd'
|
|
71
84
|
| 'adapter'
|
|
72
|
-
| 'analytics'
|
|
85
|
+
| 'analytics'
|
|
86
|
+
| 'policy';
|
|
73
87
|
|
|
74
|
-
type SddCommand =
|
|
88
|
+
type SddCommand =
|
|
89
|
+
| 'status'
|
|
90
|
+
| 'validate'
|
|
91
|
+
| 'session'
|
|
92
|
+
| 'sync-docs'
|
|
93
|
+
| 'learn'
|
|
94
|
+
| 'auto-sync'
|
|
95
|
+
| 'evidence'
|
|
96
|
+
| 'state-sync';
|
|
75
97
|
type LoopCommand = 'run' | 'status' | 'stop' | 'resume' | 'list' | 'export';
|
|
76
98
|
type AnalyticsCommand = 'hotspots';
|
|
77
99
|
type AnalyticsHotspotsCommand = 'report' | 'diagnose';
|
|
100
|
+
type PolicyCommand = 'reconcile';
|
|
78
101
|
|
|
79
102
|
type SddSessionAction = 'open' | 'refresh' | 'close';
|
|
80
103
|
|
|
@@ -83,6 +106,10 @@ type ParsedArgs = {
|
|
|
83
106
|
purgeArtifacts: boolean;
|
|
84
107
|
updateSpec?: string;
|
|
85
108
|
json: boolean;
|
|
109
|
+
bootstrapEnterprise?: boolean;
|
|
110
|
+
bootstrapAgent?: AdapterAgent;
|
|
111
|
+
installWithMcp?: boolean;
|
|
112
|
+
installMcpAgent?: AdapterAgent;
|
|
86
113
|
remoteChecks?: boolean;
|
|
87
114
|
doctorDeep?: boolean;
|
|
88
115
|
sddCommand?: SddCommand;
|
|
@@ -99,14 +126,36 @@ type ParsedArgs = {
|
|
|
99
126
|
sddSyncDocsChange?: string;
|
|
100
127
|
sddSyncDocsStage?: SddStage;
|
|
101
128
|
sddSyncDocsTask?: string;
|
|
129
|
+
sddSyncDocsFromEvidence?: string;
|
|
102
130
|
sddLearnDryRun?: boolean;
|
|
103
131
|
sddLearnChange?: string;
|
|
104
132
|
sddLearnStage?: SddStage;
|
|
105
133
|
sddLearnTask?: string;
|
|
134
|
+
sddLearnFromEvidence?: string;
|
|
106
135
|
sddAutoSyncDryRun?: boolean;
|
|
107
136
|
sddAutoSyncChange?: string;
|
|
108
137
|
sddAutoSyncStage?: SddStage;
|
|
109
138
|
sddAutoSyncTask?: string;
|
|
139
|
+
sddAutoSyncFromEvidence?: string;
|
|
140
|
+
sddEvidenceDryRun?: boolean;
|
|
141
|
+
sddEvidenceScenarioId?: string;
|
|
142
|
+
sddEvidenceTestCommand?: string;
|
|
143
|
+
sddEvidenceTestStatus?: SddEvidenceScaffoldTestStatus;
|
|
144
|
+
sddEvidenceTestOutput?: string;
|
|
145
|
+
sddEvidenceFromEvidence?: string;
|
|
146
|
+
sddStateSyncDryRun?: boolean;
|
|
147
|
+
sddStateSyncScenarioId?: string;
|
|
148
|
+
sddStateSyncStatus?: SddStateSyncStatus;
|
|
149
|
+
sddStateSyncFromEvidence?: string;
|
|
150
|
+
sddStateSyncBoardPath?: string;
|
|
151
|
+
sddStateSyncForce?: boolean;
|
|
152
|
+
watchStage?: LifecycleWatchStage;
|
|
153
|
+
watchScope?: LifecycleWatchScope;
|
|
154
|
+
watchIntervalMs?: number;
|
|
155
|
+
watchNotifyCooldownMs?: number;
|
|
156
|
+
watchSeverityThreshold?: LifecycleWatchSeverityThreshold;
|
|
157
|
+
watchNotifyEnabled?: boolean;
|
|
158
|
+
watchIterations?: number;
|
|
110
159
|
adapterCommand?: 'install';
|
|
111
160
|
adapterAgent?: AdapterAgent;
|
|
112
161
|
adapterDryRun?: boolean;
|
|
@@ -116,16 +165,20 @@ type ParsedArgs = {
|
|
|
116
165
|
analyticsSinceDays?: number;
|
|
117
166
|
analyticsJsonOutputPath?: string;
|
|
118
167
|
analyticsMarkdownOutputPath?: string;
|
|
168
|
+
policyCommand?: PolicyCommand;
|
|
169
|
+
policyStrict?: boolean;
|
|
119
170
|
};
|
|
120
171
|
|
|
121
172
|
const HELP_TEXT = `
|
|
122
173
|
Pumuki lifecycle commands:
|
|
123
|
-
pumuki
|
|
174
|
+
pumuki bootstrap [--enterprise] [--agent=<name>] [--json]
|
|
175
|
+
pumuki install [--with-mcp] [--agent=<name>]
|
|
124
176
|
pumuki uninstall [--purge-artifacts]
|
|
125
177
|
pumuki remove
|
|
126
178
|
pumuki update [--latest|--spec=<package-spec>]
|
|
127
179
|
pumuki doctor [--remote-checks] [--deep] [--json]
|
|
128
180
|
pumuki status [--json] [--remote-checks]
|
|
181
|
+
pumuki watch [--stage=PRE_COMMIT|PRE_PUSH|CI] [--scope=workingTree|staged|repoAndStaged|repo] [--severity=critical|high|medium|low] [--interval-ms=<n>] [--notify-cooldown-ms=<n>] [--no-notify] [--once|--iterations=<n>] [--json]
|
|
129
182
|
pumuki loop run --objective=<text> [--max-attempts=<n>] [--json]
|
|
130
183
|
pumuki loop status --session=<session-id> [--json]
|
|
131
184
|
pumuki loop stop --session=<session-id> [--json]
|
|
@@ -135,14 +188,19 @@ Pumuki lifecycle commands:
|
|
|
135
188
|
pumuki adapter install --agent=<name> [--dry-run] [--json]
|
|
136
189
|
pumuki analytics hotspots report [--top=<n>] [--since-days=<n>] [--json] [--output-json=<path>] [--output-markdown=<path>]
|
|
137
190
|
pumuki analytics hotspots diagnose [--json]
|
|
191
|
+
pumuki policy reconcile [--strict] [--json]
|
|
138
192
|
pumuki sdd status [--json]
|
|
139
193
|
pumuki sdd validate [--stage=PRE_WRITE|PRE_COMMIT|PRE_PUSH|CI] [--json]
|
|
140
194
|
pumuki sdd session --open --change=<change-id> [--ttl-minutes=<n>] [--json]
|
|
141
195
|
pumuki sdd session --refresh [--ttl-minutes=<n>] [--json]
|
|
142
196
|
pumuki sdd session --close [--json]
|
|
143
|
-
pumuki sdd sync-docs [--change=<change-id>] [--stage=PRE_WRITE|PRE_COMMIT|PRE_PUSH|CI] [--task=<task-id>] [--dry-run] [--json]
|
|
144
|
-
pumuki sdd
|
|
145
|
-
pumuki sdd
|
|
197
|
+
pumuki sdd sync-docs [--change=<change-id>] [--stage=PRE_WRITE|PRE_COMMIT|PRE_PUSH|CI] [--task=<task-id>] [--from-evidence=<path>] [--dry-run] [--json]
|
|
198
|
+
pumuki sdd sync [--change=<change-id>] [--stage=PRE_WRITE|PRE_COMMIT|PRE_PUSH|CI] [--task=<task-id>] [--from-evidence=<path>] [--dry-run] [--json]
|
|
199
|
+
pumuki sdd learn --change=<change-id> [--stage=PRE_WRITE|PRE_COMMIT|PRE_PUSH|CI] [--task=<task-id>] [--from-evidence=<path>] [--dry-run] [--json]
|
|
200
|
+
pumuki sdd auto-sync --change=<change-id> [--stage=PRE_WRITE|PRE_COMMIT|PRE_PUSH|CI] [--task=<task-id>] [--from-evidence=<path>] [--dry-run] [--json]
|
|
201
|
+
pumuki sdd evidence --scenario-id=<id> --test-command=<command> --test-status=passed|failed [--test-output=<path>] [--from-evidence=<path>] [--dry-run] [--json]
|
|
202
|
+
pumuki sdd state-sync [--scenario-id=<id>] [--status=todo|in_progress|blocked|done] [--from-evidence=<path>] [--board-path=<path>] [--force] [--dry-run] [--json]
|
|
203
|
+
aliases de --stage: RED=PRE_WRITE, GREEN=PRE_COMMIT, REFACTOR=PRE_PUSH, CLOSE=CI
|
|
146
204
|
`.trim();
|
|
147
205
|
|
|
148
206
|
const LOOP_RUN_POLICY: GatePolicy = {
|
|
@@ -167,16 +225,19 @@ const withOptionalLocation = (message: string, location?: string): string => {
|
|
|
167
225
|
};
|
|
168
226
|
|
|
169
227
|
const isLifecycleCommand = (value: string): value is LifecycleCommand =>
|
|
228
|
+
value === 'bootstrap' ||
|
|
170
229
|
value === 'install' ||
|
|
171
230
|
value === 'uninstall' ||
|
|
172
231
|
value === 'remove' ||
|
|
173
232
|
value === 'update' ||
|
|
174
233
|
value === 'doctor' ||
|
|
175
234
|
value === 'status' ||
|
|
235
|
+
value === 'watch' ||
|
|
176
236
|
value === 'loop' ||
|
|
177
237
|
value === 'sdd' ||
|
|
178
238
|
value === 'adapter' ||
|
|
179
|
-
value === 'analytics'
|
|
239
|
+
value === 'analytics' ||
|
|
240
|
+
value === 'policy';
|
|
180
241
|
|
|
181
242
|
const parseAdapterAgent = (value?: string): AdapterAgent => {
|
|
182
243
|
const normalized = (value ?? '').trim();
|
|
@@ -188,17 +249,96 @@ const parseAdapterAgent = (value?: string): AdapterAgent => {
|
|
|
188
249
|
|
|
189
250
|
const parseSddStage = (value?: string): SddStage => {
|
|
190
251
|
const normalized = (value ?? 'PRE_COMMIT').trim().toUpperCase();
|
|
252
|
+
const aliases: Record<string, SddStage> = {
|
|
253
|
+
RED: 'PRE_WRITE',
|
|
254
|
+
GREEN: 'PRE_COMMIT',
|
|
255
|
+
REFACTOR: 'PRE_PUSH',
|
|
256
|
+
CLOSE: 'CI',
|
|
257
|
+
};
|
|
258
|
+
const mapped = aliases[normalized] ?? normalized;
|
|
191
259
|
if (
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
260
|
+
mapped === 'PRE_WRITE' ||
|
|
261
|
+
mapped === 'PRE_COMMIT' ||
|
|
262
|
+
mapped === 'PRE_PUSH' ||
|
|
263
|
+
mapped === 'CI'
|
|
196
264
|
) {
|
|
197
|
-
return
|
|
265
|
+
return mapped;
|
|
198
266
|
}
|
|
199
267
|
throw new Error(`Unsupported SDD stage "${value}". Use PRE_WRITE, PRE_COMMIT, PRE_PUSH or CI.`);
|
|
200
268
|
};
|
|
201
269
|
|
|
270
|
+
const parseSddEvidencePath = (value: string): string => {
|
|
271
|
+
const normalized = value.trim();
|
|
272
|
+
if (normalized.length === 0) {
|
|
273
|
+
throw new Error(`Invalid --from-evidence value "${value}".`);
|
|
274
|
+
}
|
|
275
|
+
return normalized;
|
|
276
|
+
};
|
|
277
|
+
|
|
278
|
+
const parseSddEvidenceTestStatus = (value: string): SddEvidenceScaffoldTestStatus => {
|
|
279
|
+
const normalized = value.trim().toLowerCase();
|
|
280
|
+
if (normalized === 'passed') {
|
|
281
|
+
return 'passed';
|
|
282
|
+
}
|
|
283
|
+
if (normalized === 'failed') {
|
|
284
|
+
return 'failed';
|
|
285
|
+
}
|
|
286
|
+
throw new Error(`Invalid --test-status value "${value}". Use passed|failed.`);
|
|
287
|
+
};
|
|
288
|
+
|
|
289
|
+
const parseSddStateSyncStatus = (value: string): SddStateSyncStatus => {
|
|
290
|
+
const normalized = value.trim().toLowerCase();
|
|
291
|
+
if (
|
|
292
|
+
normalized === 'todo' ||
|
|
293
|
+
normalized === 'in_progress' ||
|
|
294
|
+
normalized === 'blocked' ||
|
|
295
|
+
normalized === 'done'
|
|
296
|
+
) {
|
|
297
|
+
return normalized;
|
|
298
|
+
}
|
|
299
|
+
throw new Error(
|
|
300
|
+
`Invalid --status value "${value}". Use todo|in_progress|blocked|done for "pumuki sdd state-sync".`
|
|
301
|
+
);
|
|
302
|
+
};
|
|
303
|
+
|
|
304
|
+
const parseWatchStage = (value?: string): LifecycleWatchStage => {
|
|
305
|
+
const normalized = (value ?? 'PRE_COMMIT').trim().toUpperCase();
|
|
306
|
+
if (normalized === 'PRE_COMMIT' || normalized === 'PRE_PUSH' || normalized === 'CI') {
|
|
307
|
+
return normalized;
|
|
308
|
+
}
|
|
309
|
+
throw new Error(`Unsupported watch stage "${value}". Use PRE_COMMIT, PRE_PUSH or CI.`);
|
|
310
|
+
};
|
|
311
|
+
|
|
312
|
+
const parseWatchScope = (value?: string): LifecycleWatchScope => {
|
|
313
|
+
const normalized = (value ?? 'workingTree').trim();
|
|
314
|
+
if (
|
|
315
|
+
normalized === 'workingTree' ||
|
|
316
|
+
normalized === 'staged' ||
|
|
317
|
+
normalized === 'repoAndStaged' ||
|
|
318
|
+
normalized === 'repo'
|
|
319
|
+
) {
|
|
320
|
+
return normalized;
|
|
321
|
+
}
|
|
322
|
+
throw new Error(
|
|
323
|
+
`Unsupported watch scope "${value}". Use workingTree, staged, repoAndStaged or repo.`
|
|
324
|
+
);
|
|
325
|
+
};
|
|
326
|
+
|
|
327
|
+
const parseWatchSeverityThreshold = (value?: string): LifecycleWatchSeverityThreshold => {
|
|
328
|
+
const normalized = (value ?? 'high').trim().toLowerCase();
|
|
329
|
+
if (
|
|
330
|
+
normalized === 'critical' ||
|
|
331
|
+
normalized === 'high' ||
|
|
332
|
+
normalized === 'medium' ||
|
|
333
|
+
normalized === 'low'
|
|
334
|
+
) {
|
|
335
|
+
return normalized;
|
|
336
|
+
}
|
|
337
|
+
throw new Error(
|
|
338
|
+
`Unsupported watch severity threshold "${value}". Use critical, high, medium or low.`
|
|
339
|
+
);
|
|
340
|
+
};
|
|
341
|
+
|
|
202
342
|
const parseOutputPathFlag = (value: string, flagName: '--output-json' | '--output-markdown'): string => {
|
|
203
343
|
const normalized = value.trim();
|
|
204
344
|
if (normalized.length === 0) {
|
|
@@ -429,8 +569,19 @@ export const parseLifecycleCliArgs = (argv: ReadonlyArray<string>): ParsedArgs =
|
|
|
429
569
|
let purgeArtifacts = false;
|
|
430
570
|
let updateSpec: ParsedArgs['updateSpec'];
|
|
431
571
|
let json = false;
|
|
572
|
+
let bootstrapEnterprise = false;
|
|
573
|
+
let bootstrapAgent: ParsedArgs['bootstrapAgent'];
|
|
574
|
+
let installWithMcp = false;
|
|
575
|
+
let installMcpAgent: ParsedArgs['installMcpAgent'];
|
|
432
576
|
let remoteChecks = false;
|
|
433
577
|
let doctorDeep = false;
|
|
578
|
+
let watchStage: ParsedArgs['watchStage'];
|
|
579
|
+
let watchScope: ParsedArgs['watchScope'];
|
|
580
|
+
let watchIntervalMs: ParsedArgs['watchIntervalMs'];
|
|
581
|
+
let watchNotifyCooldownMs: ParsedArgs['watchNotifyCooldownMs'];
|
|
582
|
+
let watchSeverityThreshold: ParsedArgs['watchSeverityThreshold'];
|
|
583
|
+
let watchNotifyEnabled: ParsedArgs['watchNotifyEnabled'];
|
|
584
|
+
let watchIterations: ParsedArgs['watchIterations'];
|
|
434
585
|
let sddCommand: ParsedArgs['sddCommand'];
|
|
435
586
|
let loopCommand: ParsedArgs['loopCommand'];
|
|
436
587
|
let loopSessionId: ParsedArgs['loopSessionId'];
|
|
@@ -445,14 +596,29 @@ export const parseLifecycleCliArgs = (argv: ReadonlyArray<string>): ParsedArgs =
|
|
|
445
596
|
let sddSyncDocsChange: ParsedArgs['sddSyncDocsChange'];
|
|
446
597
|
let sddSyncDocsStage: ParsedArgs['sddSyncDocsStage'];
|
|
447
598
|
let sddSyncDocsTask: ParsedArgs['sddSyncDocsTask'];
|
|
599
|
+
let sddSyncDocsFromEvidence: ParsedArgs['sddSyncDocsFromEvidence'];
|
|
448
600
|
let sddLearnDryRun = false;
|
|
449
601
|
let sddLearnChange: ParsedArgs['sddLearnChange'];
|
|
450
602
|
let sddLearnStage: ParsedArgs['sddLearnStage'];
|
|
451
603
|
let sddLearnTask: ParsedArgs['sddLearnTask'];
|
|
604
|
+
let sddLearnFromEvidence: ParsedArgs['sddLearnFromEvidence'];
|
|
452
605
|
let sddAutoSyncDryRun = false;
|
|
453
606
|
let sddAutoSyncChange: ParsedArgs['sddAutoSyncChange'];
|
|
454
607
|
let sddAutoSyncStage: ParsedArgs['sddAutoSyncStage'];
|
|
455
608
|
let sddAutoSyncTask: ParsedArgs['sddAutoSyncTask'];
|
|
609
|
+
let sddAutoSyncFromEvidence: ParsedArgs['sddAutoSyncFromEvidence'];
|
|
610
|
+
let sddEvidenceDryRun = false;
|
|
611
|
+
let sddEvidenceScenarioId: ParsedArgs['sddEvidenceScenarioId'];
|
|
612
|
+
let sddEvidenceTestCommand: ParsedArgs['sddEvidenceTestCommand'];
|
|
613
|
+
let sddEvidenceTestStatus: ParsedArgs['sddEvidenceTestStatus'];
|
|
614
|
+
let sddEvidenceTestOutput: ParsedArgs['sddEvidenceTestOutput'];
|
|
615
|
+
let sddEvidenceFromEvidence: ParsedArgs['sddEvidenceFromEvidence'];
|
|
616
|
+
let sddStateSyncDryRun = false;
|
|
617
|
+
let sddStateSyncScenarioId: ParsedArgs['sddStateSyncScenarioId'];
|
|
618
|
+
let sddStateSyncStatus: ParsedArgs['sddStateSyncStatus'];
|
|
619
|
+
let sddStateSyncFromEvidence: ParsedArgs['sddStateSyncFromEvidence'];
|
|
620
|
+
let sddStateSyncBoardPath: ParsedArgs['sddStateSyncBoardPath'];
|
|
621
|
+
let sddStateSyncForce = false;
|
|
456
622
|
let adapterCommand: ParsedArgs['adapterCommand'];
|
|
457
623
|
let adapterAgent: ParsedArgs['adapterAgent'];
|
|
458
624
|
let adapterDryRun = false;
|
|
@@ -463,6 +629,78 @@ export const parseLifecycleCliArgs = (argv: ReadonlyArray<string>): ParsedArgs =
|
|
|
463
629
|
let analyticsJsonOutputPath: ParsedArgs['analyticsJsonOutputPath'];
|
|
464
630
|
let analyticsMarkdownOutputPath: ParsedArgs['analyticsMarkdownOutputPath'];
|
|
465
631
|
|
|
632
|
+
if (commandRaw === 'watch') {
|
|
633
|
+
for (const arg of argv.slice(1)) {
|
|
634
|
+
if (arg === '--json') {
|
|
635
|
+
json = true;
|
|
636
|
+
continue;
|
|
637
|
+
}
|
|
638
|
+
if (arg === '--no-notify') {
|
|
639
|
+
watchNotifyEnabled = false;
|
|
640
|
+
continue;
|
|
641
|
+
}
|
|
642
|
+
if (arg === '--once') {
|
|
643
|
+
watchIterations = 1;
|
|
644
|
+
continue;
|
|
645
|
+
}
|
|
646
|
+
if (arg.startsWith('--stage=')) {
|
|
647
|
+
watchStage = parseWatchStage(arg.slice('--stage='.length));
|
|
648
|
+
continue;
|
|
649
|
+
}
|
|
650
|
+
if (arg.startsWith('--scope=')) {
|
|
651
|
+
watchScope = parseWatchScope(arg.slice('--scope='.length));
|
|
652
|
+
continue;
|
|
653
|
+
}
|
|
654
|
+
if (arg.startsWith('--severity=')) {
|
|
655
|
+
watchSeverityThreshold = parseWatchSeverityThreshold(
|
|
656
|
+
arg.slice('--severity='.length)
|
|
657
|
+
);
|
|
658
|
+
continue;
|
|
659
|
+
}
|
|
660
|
+
if (arg.startsWith('--interval-ms=')) {
|
|
661
|
+
const parsedInterval = Number.parseInt(arg.slice('--interval-ms='.length), 10);
|
|
662
|
+
if (!Number.isInteger(parsedInterval) || parsedInterval <= 0) {
|
|
663
|
+
throw new Error(`Invalid --interval-ms value "${arg}".`);
|
|
664
|
+
}
|
|
665
|
+
watchIntervalMs = parsedInterval;
|
|
666
|
+
continue;
|
|
667
|
+
}
|
|
668
|
+
if (arg.startsWith('--notify-cooldown-ms=')) {
|
|
669
|
+
const parsedCooldown = Number.parseInt(
|
|
670
|
+
arg.slice('--notify-cooldown-ms='.length),
|
|
671
|
+
10
|
|
672
|
+
);
|
|
673
|
+
if (!Number.isInteger(parsedCooldown) || parsedCooldown < 0) {
|
|
674
|
+
throw new Error(`Invalid --notify-cooldown-ms value "${arg}".`);
|
|
675
|
+
}
|
|
676
|
+
watchNotifyCooldownMs = parsedCooldown;
|
|
677
|
+
continue;
|
|
678
|
+
}
|
|
679
|
+
if (arg.startsWith('--iterations=')) {
|
|
680
|
+
const parsedIterations = Number.parseInt(arg.slice('--iterations='.length), 10);
|
|
681
|
+
if (!Number.isInteger(parsedIterations) || parsedIterations <= 0) {
|
|
682
|
+
throw new Error(`Invalid --iterations value "${arg}".`);
|
|
683
|
+
}
|
|
684
|
+
watchIterations = parsedIterations;
|
|
685
|
+
continue;
|
|
686
|
+
}
|
|
687
|
+
throw new Error(`Unsupported argument "${arg}".\n\n${HELP_TEXT}`);
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
return {
|
|
691
|
+
command: commandRaw,
|
|
692
|
+
purgeArtifacts: false,
|
|
693
|
+
json,
|
|
694
|
+
watchStage: watchStage ?? 'PRE_COMMIT',
|
|
695
|
+
watchScope: watchScope ?? 'workingTree',
|
|
696
|
+
watchIntervalMs: watchIntervalMs ?? 3000,
|
|
697
|
+
watchNotifyCooldownMs: watchNotifyCooldownMs ?? 30_000,
|
|
698
|
+
watchSeverityThreshold: watchSeverityThreshold ?? 'high',
|
|
699
|
+
watchNotifyEnabled: watchNotifyEnabled !== false,
|
|
700
|
+
...(typeof watchIterations === 'number' ? { watchIterations } : {}),
|
|
701
|
+
};
|
|
702
|
+
}
|
|
703
|
+
|
|
466
704
|
if (commandRaw === 'analytics') {
|
|
467
705
|
const subcommandRaw = argv[1] ?? '';
|
|
468
706
|
if (subcommandRaw !== 'hotspots') {
|
|
@@ -535,6 +773,38 @@ export const parseLifecycleCliArgs = (argv: ReadonlyArray<string>): ParsedArgs =
|
|
|
535
773
|
return parsedAnalyticsArgs;
|
|
536
774
|
}
|
|
537
775
|
|
|
776
|
+
if (commandRaw === 'policy') {
|
|
777
|
+
const firstArg = argv[1];
|
|
778
|
+
const subcommandRaw =
|
|
779
|
+
typeof firstArg === 'string' && !firstArg.startsWith('--')
|
|
780
|
+
? firstArg
|
|
781
|
+
: 'reconcile';
|
|
782
|
+
if (subcommandRaw !== 'reconcile') {
|
|
783
|
+
throw new Error(`Unsupported policy subcommand "${subcommandRaw}".\n\n${HELP_TEXT}`);
|
|
784
|
+
}
|
|
785
|
+
let policyStrict = false;
|
|
786
|
+
const policyFlagsOffset =
|
|
787
|
+
typeof firstArg === 'string' && !firstArg.startsWith('--') ? 2 : 1;
|
|
788
|
+
for (const arg of argv.slice(policyFlagsOffset)) {
|
|
789
|
+
if (arg === '--json') {
|
|
790
|
+
json = true;
|
|
791
|
+
continue;
|
|
792
|
+
}
|
|
793
|
+
if (arg === '--strict') {
|
|
794
|
+
policyStrict = true;
|
|
795
|
+
continue;
|
|
796
|
+
}
|
|
797
|
+
throw new Error(`Unsupported argument "${arg}".\n\n${HELP_TEXT}`);
|
|
798
|
+
}
|
|
799
|
+
return {
|
|
800
|
+
command: commandRaw,
|
|
801
|
+
purgeArtifacts: false,
|
|
802
|
+
json,
|
|
803
|
+
policyCommand: 'reconcile',
|
|
804
|
+
policyStrict,
|
|
805
|
+
};
|
|
806
|
+
}
|
|
807
|
+
|
|
538
808
|
if (commandRaw === 'loop') {
|
|
539
809
|
const subcommandRaw = argv[1] ?? '';
|
|
540
810
|
if (
|
|
@@ -632,12 +902,15 @@ export const parseLifecycleCliArgs = (argv: ReadonlyArray<string>): ParsedArgs =
|
|
|
632
902
|
subcommandRaw !== 'validate' &&
|
|
633
903
|
subcommandRaw !== 'session' &&
|
|
634
904
|
subcommandRaw !== 'sync-docs' &&
|
|
905
|
+
subcommandRaw !== 'sync' &&
|
|
635
906
|
subcommandRaw !== 'learn' &&
|
|
636
|
-
subcommandRaw !== 'auto-sync'
|
|
907
|
+
subcommandRaw !== 'auto-sync' &&
|
|
908
|
+
subcommandRaw !== 'evidence' &&
|
|
909
|
+
subcommandRaw !== 'state-sync'
|
|
637
910
|
) {
|
|
638
911
|
throw new Error(`Unsupported SDD subcommand "${subcommandRaw}".\n\n${HELP_TEXT}`);
|
|
639
912
|
}
|
|
640
|
-
sddCommand = subcommandRaw;
|
|
913
|
+
sddCommand = subcommandRaw === 'sync' ? 'sync-docs' : subcommandRaw;
|
|
641
914
|
|
|
642
915
|
for (const arg of argv.slice(2)) {
|
|
643
916
|
if (arg === '--json') {
|
|
@@ -657,7 +930,15 @@ export const parseLifecycleCliArgs = (argv: ReadonlyArray<string>): ParsedArgs =
|
|
|
657
930
|
sddAutoSyncDryRun = true;
|
|
658
931
|
continue;
|
|
659
932
|
}
|
|
660
|
-
|
|
933
|
+
if (sddCommand === 'evidence') {
|
|
934
|
+
sddEvidenceDryRun = true;
|
|
935
|
+
continue;
|
|
936
|
+
}
|
|
937
|
+
if (sddCommand === 'state-sync') {
|
|
938
|
+
sddStateSyncDryRun = true;
|
|
939
|
+
continue;
|
|
940
|
+
}
|
|
941
|
+
throw new Error(`--dry-run is only supported with "pumuki sdd sync-docs", "pumuki sdd learn", "pumuki sdd auto-sync", "pumuki sdd evidence" or "pumuki sdd state-sync".\n\n${HELP_TEXT}`);
|
|
661
942
|
}
|
|
662
943
|
if (arg.startsWith('--stage=')) {
|
|
663
944
|
if (sddCommand === 'validate') {
|
|
@@ -678,6 +959,13 @@ export const parseLifecycleCliArgs = (argv: ReadonlyArray<string>): ParsedArgs =
|
|
|
678
959
|
}
|
|
679
960
|
throw new Error(`--stage is only supported with "pumuki sdd validate", "pumuki sdd sync-docs", "pumuki sdd learn" or "pumuki sdd auto-sync".\n\n${HELP_TEXT}`);
|
|
680
961
|
}
|
|
962
|
+
if (arg.startsWith('--status=')) {
|
|
963
|
+
if (sddCommand !== 'state-sync') {
|
|
964
|
+
throw new Error(`--status is only supported with "pumuki sdd state-sync".\n\n${HELP_TEXT}`);
|
|
965
|
+
}
|
|
966
|
+
sddStateSyncStatus = parseSddStateSyncStatus(arg.slice('--status='.length));
|
|
967
|
+
continue;
|
|
968
|
+
}
|
|
681
969
|
if (arg === '--open') {
|
|
682
970
|
if (sddCommand !== 'session') {
|
|
683
971
|
throw new Error(`--open is only supported with "pumuki sdd session".\n\n${HELP_TEXT}`);
|
|
@@ -757,6 +1045,104 @@ export const parseLifecycleCliArgs = (argv: ReadonlyArray<string>): ParsedArgs =
|
|
|
757
1045
|
}
|
|
758
1046
|
throw new Error(`--task is only supported with "pumuki sdd sync-docs", "pumuki sdd learn" or "pumuki sdd auto-sync".\n\n${HELP_TEXT}`);
|
|
759
1047
|
}
|
|
1048
|
+
if (arg.startsWith('--scenario-id=')) {
|
|
1049
|
+
const scenarioId = arg.slice('--scenario-id='.length).trim();
|
|
1050
|
+
if (scenarioId.length === 0) {
|
|
1051
|
+
throw new Error(`Invalid --scenario-id value "${arg}".`);
|
|
1052
|
+
}
|
|
1053
|
+
if (sddCommand === 'evidence') {
|
|
1054
|
+
sddEvidenceScenarioId = scenarioId;
|
|
1055
|
+
continue;
|
|
1056
|
+
}
|
|
1057
|
+
if (sddCommand === 'state-sync') {
|
|
1058
|
+
sddStateSyncScenarioId = scenarioId;
|
|
1059
|
+
continue;
|
|
1060
|
+
}
|
|
1061
|
+
throw new Error(`--scenario-id is only supported with "pumuki sdd evidence" or "pumuki sdd state-sync".\n\n${HELP_TEXT}`);
|
|
1062
|
+
continue;
|
|
1063
|
+
}
|
|
1064
|
+
if (arg.startsWith('--test-command=')) {
|
|
1065
|
+
if (sddCommand !== 'evidence') {
|
|
1066
|
+
throw new Error(`--test-command is only supported with "pumuki sdd evidence".\n\n${HELP_TEXT}`);
|
|
1067
|
+
}
|
|
1068
|
+
const testCommand = arg.slice('--test-command='.length).trim();
|
|
1069
|
+
if (testCommand.length === 0) {
|
|
1070
|
+
throw new Error(`Invalid --test-command value "${arg}".`);
|
|
1071
|
+
}
|
|
1072
|
+
sddEvidenceTestCommand = testCommand;
|
|
1073
|
+
continue;
|
|
1074
|
+
}
|
|
1075
|
+
if (arg.startsWith('--test-status=')) {
|
|
1076
|
+
if (sddCommand !== 'evidence') {
|
|
1077
|
+
throw new Error(`--test-status is only supported with "pumuki sdd evidence".\n\n${HELP_TEXT}`);
|
|
1078
|
+
}
|
|
1079
|
+
sddEvidenceTestStatus = parseSddEvidenceTestStatus(arg.slice('--test-status='.length));
|
|
1080
|
+
continue;
|
|
1081
|
+
}
|
|
1082
|
+
if (arg.startsWith('--test-output=')) {
|
|
1083
|
+
if (sddCommand !== 'evidence') {
|
|
1084
|
+
throw new Error(`--test-output is only supported with "pumuki sdd evidence".\n\n${HELP_TEXT}`);
|
|
1085
|
+
}
|
|
1086
|
+
const testOutputPath = arg.slice('--test-output='.length).trim();
|
|
1087
|
+
if (testOutputPath.length === 0) {
|
|
1088
|
+
throw new Error(`Invalid --test-output value "${arg}".`);
|
|
1089
|
+
}
|
|
1090
|
+
sddEvidenceTestOutput = testOutputPath;
|
|
1091
|
+
continue;
|
|
1092
|
+
}
|
|
1093
|
+
if (arg.startsWith('--from-evidence=')) {
|
|
1094
|
+
if (sddCommand === 'sync-docs') {
|
|
1095
|
+
sddSyncDocsFromEvidence = parseSddEvidencePath(
|
|
1096
|
+
arg.slice('--from-evidence='.length)
|
|
1097
|
+
);
|
|
1098
|
+
continue;
|
|
1099
|
+
}
|
|
1100
|
+
if (sddCommand === 'learn') {
|
|
1101
|
+
sddLearnFromEvidence = parseSddEvidencePath(
|
|
1102
|
+
arg.slice('--from-evidence='.length)
|
|
1103
|
+
);
|
|
1104
|
+
continue;
|
|
1105
|
+
}
|
|
1106
|
+
if (sddCommand === 'auto-sync') {
|
|
1107
|
+
sddAutoSyncFromEvidence = parseSddEvidencePath(
|
|
1108
|
+
arg.slice('--from-evidence='.length)
|
|
1109
|
+
);
|
|
1110
|
+
continue;
|
|
1111
|
+
}
|
|
1112
|
+
if (sddCommand === 'evidence') {
|
|
1113
|
+
sddEvidenceFromEvidence = parseSddEvidencePath(
|
|
1114
|
+
arg.slice('--from-evidence='.length)
|
|
1115
|
+
);
|
|
1116
|
+
continue;
|
|
1117
|
+
}
|
|
1118
|
+
if (sddCommand === 'state-sync') {
|
|
1119
|
+
sddStateSyncFromEvidence = parseSddEvidencePath(
|
|
1120
|
+
arg.slice('--from-evidence='.length)
|
|
1121
|
+
);
|
|
1122
|
+
continue;
|
|
1123
|
+
}
|
|
1124
|
+
throw new Error(
|
|
1125
|
+
`--from-evidence is only supported with "pumuki sdd sync-docs", "pumuki sdd sync", "pumuki sdd learn", "pumuki sdd auto-sync", "pumuki sdd evidence" or "pumuki sdd state-sync".\n\n${HELP_TEXT}`
|
|
1126
|
+
);
|
|
1127
|
+
}
|
|
1128
|
+
if (arg.startsWith('--board-path=')) {
|
|
1129
|
+
if (sddCommand !== 'state-sync') {
|
|
1130
|
+
throw new Error(`--board-path is only supported with "pumuki sdd state-sync".\n\n${HELP_TEXT}`);
|
|
1131
|
+
}
|
|
1132
|
+
const boardPath = arg.slice('--board-path='.length).trim();
|
|
1133
|
+
if (boardPath.length === 0) {
|
|
1134
|
+
throw new Error(`Invalid --board-path value "${arg}".`);
|
|
1135
|
+
}
|
|
1136
|
+
sddStateSyncBoardPath = boardPath;
|
|
1137
|
+
continue;
|
|
1138
|
+
}
|
|
1139
|
+
if (arg === '--force') {
|
|
1140
|
+
if (sddCommand !== 'state-sync') {
|
|
1141
|
+
throw new Error(`--force is only supported with "pumuki sdd state-sync".\n\n${HELP_TEXT}`);
|
|
1142
|
+
}
|
|
1143
|
+
sddStateSyncForce = true;
|
|
1144
|
+
continue;
|
|
1145
|
+
}
|
|
760
1146
|
if (arg.startsWith('--ttl-minutes=')) {
|
|
761
1147
|
if (sddCommand !== 'session') {
|
|
762
1148
|
throw new Error(`--ttl-minutes is only supported with "pumuki sdd session".\n\n${HELP_TEXT}`);
|
|
@@ -789,9 +1175,13 @@ export const parseLifecycleCliArgs = (argv: ReadonlyArray<string>): ParsedArgs =
|
|
|
789
1175
|
};
|
|
790
1176
|
}
|
|
791
1177
|
if (sddCommand === 'sync-docs') {
|
|
792
|
-
if (
|
|
1178
|
+
if (
|
|
1179
|
+
sddSessionAction ||
|
|
1180
|
+
sddChangeId ||
|
|
1181
|
+
typeof sddTtlMinutes === 'number'
|
|
1182
|
+
) {
|
|
793
1183
|
throw new Error(
|
|
794
|
-
`"pumuki sdd sync-docs" only supports [--change=<change-id>] [--stage=PRE_WRITE|PRE_COMMIT|PRE_PUSH|CI] [--task=<task-id>] [--dry-run] [--json].\n\n${HELP_TEXT}`
|
|
1184
|
+
`"pumuki sdd sync-docs" only supports [--change=<change-id>] [--stage=PRE_WRITE|PRE_COMMIT|PRE_PUSH|CI] [--task=<task-id>] [--from-evidence=<path>] [--dry-run] [--json].\n\n${HELP_TEXT}`
|
|
795
1185
|
);
|
|
796
1186
|
}
|
|
797
1187
|
return {
|
|
@@ -803,12 +1193,15 @@ export const parseLifecycleCliArgs = (argv: ReadonlyArray<string>): ParsedArgs =
|
|
|
803
1193
|
...(sddSyncDocsChange ? { sddSyncDocsChange } : {}),
|
|
804
1194
|
...(sddSyncDocsStage ? { sddSyncDocsStage } : {}),
|
|
805
1195
|
...(sddSyncDocsTask ? { sddSyncDocsTask } : {}),
|
|
1196
|
+
...(sddSyncDocsFromEvidence
|
|
1197
|
+
? { sddSyncDocsFromEvidence }
|
|
1198
|
+
: {}),
|
|
806
1199
|
};
|
|
807
1200
|
}
|
|
808
1201
|
if (sddCommand === 'learn') {
|
|
809
1202
|
if (sddSessionAction || sddChangeId || typeof sddTtlMinutes === 'number') {
|
|
810
1203
|
throw new Error(
|
|
811
|
-
`"pumuki sdd learn" only supports --change=<change-id> [--stage=PRE_WRITE|PRE_COMMIT|PRE_PUSH|CI] [--task=<task-id>] [--dry-run] [--json].\n\n${HELP_TEXT}`
|
|
1204
|
+
`"pumuki sdd learn" only supports --change=<change-id> [--stage=PRE_WRITE|PRE_COMMIT|PRE_PUSH|CI] [--task=<task-id>] [--from-evidence=<path>] [--dry-run] [--json].\n\n${HELP_TEXT}`
|
|
812
1205
|
);
|
|
813
1206
|
}
|
|
814
1207
|
if (!sddLearnChange || sddLearnChange.length === 0) {
|
|
@@ -823,12 +1216,13 @@ export const parseLifecycleCliArgs = (argv: ReadonlyArray<string>): ParsedArgs =
|
|
|
823
1216
|
sddLearnChange,
|
|
824
1217
|
...(sddLearnStage ? { sddLearnStage } : {}),
|
|
825
1218
|
...(sddLearnTask ? { sddLearnTask } : {}),
|
|
1219
|
+
...(sddLearnFromEvidence ? { sddLearnFromEvidence } : {}),
|
|
826
1220
|
};
|
|
827
1221
|
}
|
|
828
1222
|
if (sddCommand === 'auto-sync') {
|
|
829
1223
|
if (sddSessionAction || sddChangeId || typeof sddTtlMinutes === 'number') {
|
|
830
1224
|
throw new Error(
|
|
831
|
-
`"pumuki sdd auto-sync" only supports --change=<change-id> [--stage=PRE_WRITE|PRE_COMMIT|PRE_PUSH|CI] [--task=<task-id>] [--dry-run] [--json].\n\n${HELP_TEXT}`
|
|
1225
|
+
`"pumuki sdd auto-sync" only supports --change=<change-id> [--stage=PRE_WRITE|PRE_COMMIT|PRE_PUSH|CI] [--task=<task-id>] [--from-evidence=<path>] [--dry-run] [--json].\n\n${HELP_TEXT}`
|
|
832
1226
|
);
|
|
833
1227
|
}
|
|
834
1228
|
if (!sddAutoSyncChange || sddAutoSyncChange.length === 0) {
|
|
@@ -843,6 +1237,68 @@ export const parseLifecycleCliArgs = (argv: ReadonlyArray<string>): ParsedArgs =
|
|
|
843
1237
|
sddAutoSyncChange,
|
|
844
1238
|
...(sddAutoSyncStage ? { sddAutoSyncStage } : {}),
|
|
845
1239
|
...(sddAutoSyncTask ? { sddAutoSyncTask } : {}),
|
|
1240
|
+
...(sddAutoSyncFromEvidence ? { sddAutoSyncFromEvidence } : {}),
|
|
1241
|
+
};
|
|
1242
|
+
}
|
|
1243
|
+
if (sddCommand === 'evidence') {
|
|
1244
|
+
if (
|
|
1245
|
+
sddSessionAction ||
|
|
1246
|
+
sddChangeId ||
|
|
1247
|
+
typeof sddTtlMinutes === 'number' ||
|
|
1248
|
+
sddSyncDocsChange ||
|
|
1249
|
+
sddLearnChange ||
|
|
1250
|
+
sddAutoSyncChange
|
|
1251
|
+
) {
|
|
1252
|
+
throw new Error(
|
|
1253
|
+
`"pumuki sdd evidence" only supports --scenario-id=<id> --test-command=<command> --test-status=passed|failed [--test-output=<path>] [--from-evidence=<path>] [--dry-run] [--json].\n\n${HELP_TEXT}`
|
|
1254
|
+
);
|
|
1255
|
+
}
|
|
1256
|
+
if (!sddEvidenceScenarioId) {
|
|
1257
|
+
throw new Error(`Missing --scenario-id=<id> for "pumuki sdd evidence".\n\n${HELP_TEXT}`);
|
|
1258
|
+
}
|
|
1259
|
+
if (!sddEvidenceTestCommand) {
|
|
1260
|
+
throw new Error(`Missing --test-command=<command> for "pumuki sdd evidence".\n\n${HELP_TEXT}`);
|
|
1261
|
+
}
|
|
1262
|
+
if (!sddEvidenceTestStatus) {
|
|
1263
|
+
throw new Error(`Missing --test-status=passed|failed for "pumuki sdd evidence".\n\n${HELP_TEXT}`);
|
|
1264
|
+
}
|
|
1265
|
+
return {
|
|
1266
|
+
command: commandRaw,
|
|
1267
|
+
purgeArtifacts: false,
|
|
1268
|
+
json,
|
|
1269
|
+
sddCommand,
|
|
1270
|
+
sddEvidenceDryRun,
|
|
1271
|
+
sddEvidenceScenarioId,
|
|
1272
|
+
sddEvidenceTestCommand,
|
|
1273
|
+
sddEvidenceTestStatus,
|
|
1274
|
+
...(sddEvidenceTestOutput ? { sddEvidenceTestOutput } : {}),
|
|
1275
|
+
...(sddEvidenceFromEvidence ? { sddEvidenceFromEvidence } : {}),
|
|
1276
|
+
};
|
|
1277
|
+
}
|
|
1278
|
+
if (sddCommand === 'state-sync') {
|
|
1279
|
+
if (
|
|
1280
|
+
sddSessionAction ||
|
|
1281
|
+
sddChangeId ||
|
|
1282
|
+
typeof sddTtlMinutes === 'number' ||
|
|
1283
|
+
sddSyncDocsChange ||
|
|
1284
|
+
sddLearnChange ||
|
|
1285
|
+
sddAutoSyncChange
|
|
1286
|
+
) {
|
|
1287
|
+
throw new Error(
|
|
1288
|
+
`"pumuki sdd state-sync" only supports [--scenario-id=<id>] [--status=todo|in_progress|blocked|done] [--from-evidence=<path>] [--board-path=<path>] [--force] [--dry-run] [--json].\n\n${HELP_TEXT}`
|
|
1289
|
+
);
|
|
1290
|
+
}
|
|
1291
|
+
return {
|
|
1292
|
+
command: commandRaw,
|
|
1293
|
+
purgeArtifacts: false,
|
|
1294
|
+
json,
|
|
1295
|
+
sddCommand,
|
|
1296
|
+
sddStateSyncDryRun,
|
|
1297
|
+
...(sddStateSyncScenarioId ? { sddStateSyncScenarioId } : {}),
|
|
1298
|
+
...(sddStateSyncStatus ? { sddStateSyncStatus } : {}),
|
|
1299
|
+
...(sddStateSyncFromEvidence ? { sddStateSyncFromEvidence } : {}),
|
|
1300
|
+
...(sddStateSyncBoardPath ? { sddStateSyncBoardPath } : {}),
|
|
1301
|
+
...(sddStateSyncForce ? { sddStateSyncForce: true } : {}),
|
|
846
1302
|
};
|
|
847
1303
|
}
|
|
848
1304
|
|
|
@@ -908,6 +1364,31 @@ export const parseLifecycleCliArgs = (argv: ReadonlyArray<string>): ParsedArgs =
|
|
|
908
1364
|
json = true;
|
|
909
1365
|
continue;
|
|
910
1366
|
}
|
|
1367
|
+
if (arg === '--with-mcp') {
|
|
1368
|
+
if (commandRaw !== 'install') {
|
|
1369
|
+
throw new Error(`--with-mcp is only supported with "pumuki install".\n\n${HELP_TEXT}`);
|
|
1370
|
+
}
|
|
1371
|
+
installWithMcp = true;
|
|
1372
|
+
continue;
|
|
1373
|
+
}
|
|
1374
|
+
if (arg === '--enterprise') {
|
|
1375
|
+
if (commandRaw !== 'bootstrap') {
|
|
1376
|
+
throw new Error(`--enterprise is only supported with "pumuki bootstrap".\n\n${HELP_TEXT}`);
|
|
1377
|
+
}
|
|
1378
|
+
bootstrapEnterprise = true;
|
|
1379
|
+
continue;
|
|
1380
|
+
}
|
|
1381
|
+
if (arg.startsWith('--agent=')) {
|
|
1382
|
+
if (commandRaw === 'install') {
|
|
1383
|
+
installMcpAgent = parseAdapterAgent(arg.slice('--agent='.length).trim());
|
|
1384
|
+
continue;
|
|
1385
|
+
}
|
|
1386
|
+
if (commandRaw === 'bootstrap') {
|
|
1387
|
+
bootstrapAgent = parseAdapterAgent(arg.slice('--agent='.length).trim());
|
|
1388
|
+
continue;
|
|
1389
|
+
}
|
|
1390
|
+
throw new Error(`Unsupported argument "${arg}".\n\n${HELP_TEXT}`);
|
|
1391
|
+
}
|
|
911
1392
|
if (arg === '--remote-checks') {
|
|
912
1393
|
remoteChecks = true;
|
|
913
1394
|
continue;
|
|
@@ -938,12 +1419,31 @@ export const parseLifecycleCliArgs = (argv: ReadonlyArray<string>): ParsedArgs =
|
|
|
938
1419
|
if (doctorDeep && commandRaw !== 'doctor') {
|
|
939
1420
|
throw new Error(`--deep is only supported with "pumuki doctor".\n\n${HELP_TEXT}`);
|
|
940
1421
|
}
|
|
1422
|
+
if (commandRaw !== 'bootstrap' && bootstrapEnterprise) {
|
|
1423
|
+
throw new Error(`--enterprise is only supported with "pumuki bootstrap".\n\n${HELP_TEXT}`);
|
|
1424
|
+
}
|
|
1425
|
+
if (commandRaw !== 'bootstrap' && bootstrapAgent) {
|
|
1426
|
+
throw new Error(`--agent is only supported with "pumuki bootstrap" or "pumuki install --with-mcp".\n\n${HELP_TEXT}`);
|
|
1427
|
+
}
|
|
1428
|
+
if (commandRaw !== 'install' && installWithMcp) {
|
|
1429
|
+
throw new Error(`--with-mcp is only supported with "pumuki install".\n\n${HELP_TEXT}`);
|
|
1430
|
+
}
|
|
1431
|
+
if (commandRaw !== 'install' && installMcpAgent) {
|
|
1432
|
+
throw new Error(`--agent is only supported with "pumuki install --with-mcp".\n\n${HELP_TEXT}`);
|
|
1433
|
+
}
|
|
1434
|
+
if (commandRaw === 'install' && installMcpAgent && !installWithMcp) {
|
|
1435
|
+
throw new Error(`--agent is only supported with "pumuki install --with-mcp".\n\n${HELP_TEXT}`);
|
|
1436
|
+
}
|
|
941
1437
|
|
|
942
1438
|
return {
|
|
943
1439
|
command: commandRaw,
|
|
944
1440
|
purgeArtifacts,
|
|
945
1441
|
updateSpec,
|
|
946
1442
|
json,
|
|
1443
|
+
...(commandRaw === 'bootstrap' ? { bootstrapEnterprise: true } : {}),
|
|
1444
|
+
...(bootstrapAgent ? { bootstrapAgent } : {}),
|
|
1445
|
+
...(installWithMcp ? { installWithMcp: true } : {}),
|
|
1446
|
+
...(installMcpAgent ? { installMcpAgent } : {}),
|
|
947
1447
|
...(remoteChecks ? { remoteChecks: true } : {}),
|
|
948
1448
|
...(doctorDeep ? { doctorDeep: true } : {}),
|
|
949
1449
|
};
|
|
@@ -1063,6 +1563,7 @@ type LifecycleCliDependencies = {
|
|
|
1063
1563
|
emitAuditSummaryNotificationFromAiGate: typeof emitAuditSummaryNotificationFromAiGate;
|
|
1064
1564
|
emitGateBlockedNotification: typeof emitGateBlockedNotification;
|
|
1065
1565
|
runPlatformGate: typeof runPlatformGate;
|
|
1566
|
+
runLifecycleWatch: typeof runLifecycleWatch;
|
|
1066
1567
|
collectRemoteCiDiagnostics: typeof collectRemoteCiDiagnostics;
|
|
1067
1568
|
};
|
|
1068
1569
|
|
|
@@ -1070,18 +1571,26 @@ const defaultLifecycleCliDependencies: LifecycleCliDependencies = {
|
|
|
1070
1571
|
emitAuditSummaryNotificationFromAiGate,
|
|
1071
1572
|
emitGateBlockedNotification,
|
|
1072
1573
|
runPlatformGate,
|
|
1574
|
+
runLifecycleWatch,
|
|
1073
1575
|
collectRemoteCiDiagnostics,
|
|
1074
1576
|
};
|
|
1075
1577
|
|
|
1076
1578
|
const PRE_WRITE_HINTS_BY_CODE: Readonly<Record<string, string>> = {
|
|
1077
1579
|
EVIDENCE_MISSING: 'Regenera evidencia ejecutando una auditoría completa antes de continuar.',
|
|
1078
1580
|
EVIDENCE_INVALID: 'Corrige el contrato de .ai_evidence.json y vuelve a ejecutar el gate.',
|
|
1581
|
+
EVIDENCE_INTEGRITY_MISSING: 'Refresca evidencia para regenerar metadatos de integridad.',
|
|
1079
1582
|
EVIDENCE_CHAIN_INVALID: 'Regenera evidencia para restablecer la cadena criptográfica íntegra.',
|
|
1080
1583
|
EVIDENCE_STALE: 'Refresca evidencia para este repo y rama.',
|
|
1081
1584
|
EVIDENCE_REPO_ROOT_MISMATCH: 'Regenera evidencia desde este repositorio.',
|
|
1082
1585
|
EVIDENCE_BRANCH_MISMATCH: 'Regenera evidencia en la rama actual.',
|
|
1083
1586
|
EVIDENCE_RULES_COVERAGE_MISSING: 'Ejecuta auditoría completa para recalcular rules_coverage.',
|
|
1084
1587
|
EVIDENCE_RULES_COVERAGE_INCOMPLETE: 'Asegura unevaluated=0 y coverage_ratio=1.',
|
|
1588
|
+
EVIDENCE_SKILLS_CONTRACT_INCOMPLETE:
|
|
1589
|
+
'Completa contrato skills/policy para el stage actual y vuelve a validar.',
|
|
1590
|
+
EVIDENCE_PREWRITE_WORKTREE_OVER_LIMIT:
|
|
1591
|
+
'Reduce el worktree pendiente en slices atómicos antes de continuar.',
|
|
1592
|
+
EVIDENCE_PREWRITE_WORKTREE_WARN:
|
|
1593
|
+
'Particiona cambios ahora para evitar bloqueos tardíos en commit/push.',
|
|
1085
1594
|
GITFLOW_PROTECTED_BRANCH: 'Trabaja en feature/* y evita ramas protegidas.',
|
|
1086
1595
|
MCP_ENTERPRISE_RECEIPT_MISSING: 'Invoca ai_gate_check desde pumuki-enterprise MCP antes de PRE_WRITE.',
|
|
1087
1596
|
MCP_ENTERPRISE_RECEIPT_INVALID: 'Corrige recibo MCP y vuelve a invocar ai_gate_check.',
|
|
@@ -1187,6 +1696,7 @@ const buildPreWriteValidationPanel = (params: {
|
|
|
1187
1696
|
`Evidence: kind=${params.aiGate.evidence.kind} age=${params.aiGate.evidence.age_seconds ?? 'n/a'}s max=${params.aiGate.evidence.max_age_seconds}s`,
|
|
1188
1697
|
`Evidence source: source=${params.aiGate.evidence.source.source} path=${params.aiGate.evidence.source.path} digest=${params.aiGate.evidence.source.digest ?? 'null'} generated_at=${params.aiGate.evidence.source.generated_at ?? 'null'}`,
|
|
1189
1698
|
`MCP receipt: required=${receipt.required ? 'yes' : 'no'} kind=${receipt.kind} age=${receipt.age_seconds ?? 'n/a'}s max=${receipt.max_age_seconds ?? 'n/a'}s`,
|
|
1699
|
+
`Skills contract: enforced=${params.aiGate.skills_contract?.enforced ? 'yes' : 'no'} status=${params.aiGate.skills_contract?.status ?? 'n/a'} platforms=${params.aiGate.skills_contract?.detected_platforms.join(',') ?? 'none'}`,
|
|
1190
1700
|
`Auto-heal: attempted=${params.automation.attempted ? 'yes' : 'no'} actions=${params.automation.actions.length}`,
|
|
1191
1701
|
`Violations: ${params.aiGate.violations.length}`,
|
|
1192
1702
|
];
|
|
@@ -1322,6 +1832,98 @@ export const runLifecycleCli = async (
|
|
|
1322
1832
|
const parsed = parseLifecycleCliArgs(argv);
|
|
1323
1833
|
|
|
1324
1834
|
switch (parsed.command) {
|
|
1835
|
+
case 'bootstrap': {
|
|
1836
|
+
const installResult = runLifecycleInstall();
|
|
1837
|
+
const agent = parsed.bootstrapAgent ?? 'codex';
|
|
1838
|
+
const adapterResult = runLifecycleAdapterInstall({
|
|
1839
|
+
agent,
|
|
1840
|
+
});
|
|
1841
|
+
const doctorReport = runLifecycleDoctor({
|
|
1842
|
+
deep: true,
|
|
1843
|
+
});
|
|
1844
|
+
const adapterCheck = doctorReport.deep?.checks.find(
|
|
1845
|
+
(check) => check.id === 'adapter-wiring'
|
|
1846
|
+
);
|
|
1847
|
+
const blocking = doctorHasBlockingIssues(doctorReport);
|
|
1848
|
+
|
|
1849
|
+
if (parsed.json) {
|
|
1850
|
+
writeInfo(
|
|
1851
|
+
JSON.stringify(
|
|
1852
|
+
{
|
|
1853
|
+
command: 'bootstrap',
|
|
1854
|
+
enterprise: parsed.bootstrapEnterprise === true,
|
|
1855
|
+
install: {
|
|
1856
|
+
repo_root: installResult.repoRoot,
|
|
1857
|
+
version: installResult.version,
|
|
1858
|
+
hooks_changed: installResult.changedHooks,
|
|
1859
|
+
openspec: installResult.openSpecBootstrap
|
|
1860
|
+
? {
|
|
1861
|
+
installed: installResult.openSpecBootstrap.packageInstalled,
|
|
1862
|
+
project_initialized: installResult.openSpecBootstrap.projectInitialized,
|
|
1863
|
+
actions: installResult.openSpecBootstrap.actions,
|
|
1864
|
+
skipped_reason: installResult.openSpecBootstrap.skippedReason ?? null,
|
|
1865
|
+
}
|
|
1866
|
+
: null,
|
|
1867
|
+
},
|
|
1868
|
+
mcp: {
|
|
1869
|
+
agent: adapterResult.agent,
|
|
1870
|
+
changed_files: adapterResult.changedFiles,
|
|
1871
|
+
adapter_health: adapterCheck
|
|
1872
|
+
? {
|
|
1873
|
+
status: adapterCheck.status,
|
|
1874
|
+
severity: adapterCheck.severity,
|
|
1875
|
+
message: adapterCheck.message,
|
|
1876
|
+
remediation: adapterCheck.remediation ?? null,
|
|
1877
|
+
}
|
|
1878
|
+
: null,
|
|
1879
|
+
},
|
|
1880
|
+
doctor: {
|
|
1881
|
+
blocking,
|
|
1882
|
+
issues: doctorReport.issues,
|
|
1883
|
+
deep: doctorReport.deep ?? null,
|
|
1884
|
+
},
|
|
1885
|
+
},
|
|
1886
|
+
null,
|
|
1887
|
+
2
|
|
1888
|
+
)
|
|
1889
|
+
);
|
|
1890
|
+
} else {
|
|
1891
|
+
writeInfo(
|
|
1892
|
+
`[pumuki] bootstrap enterprise: repo=${installResult.repoRoot} version=${installResult.version}`
|
|
1893
|
+
);
|
|
1894
|
+
writeInfo(
|
|
1895
|
+
`[pumuki] bootstrap install: hooks changed=${installResult.changedHooks.join(', ') || 'none'}`
|
|
1896
|
+
);
|
|
1897
|
+
if (installResult.openSpecBootstrap) {
|
|
1898
|
+
writeInfo(
|
|
1899
|
+
`[pumuki] bootstrap openspec: installed=${installResult.openSpecBootstrap.packageInstalled ? 'yes' : 'no'} project=${installResult.openSpecBootstrap.projectInitialized ? 'yes' : 'no'} actions=${installResult.openSpecBootstrap.actions.join(', ') || 'none'}`
|
|
1900
|
+
);
|
|
1901
|
+
if (installResult.openSpecBootstrap.skippedReason === 'NO_PACKAGE_JSON') {
|
|
1902
|
+
writeInfo('[pumuki] bootstrap openspec skipped npm install (package.json not found)');
|
|
1903
|
+
}
|
|
1904
|
+
}
|
|
1905
|
+
writeInfo(
|
|
1906
|
+
`[pumuki] bootstrap mcp: agent=${adapterResult.agent} changed=${adapterResult.changedFiles.length}`
|
|
1907
|
+
);
|
|
1908
|
+
if (adapterResult.changedFiles.length > 0) {
|
|
1909
|
+
writeInfo(`[pumuki] bootstrap mcp files: ${adapterResult.changedFiles.join(', ')}`);
|
|
1910
|
+
}
|
|
1911
|
+
if (adapterCheck) {
|
|
1912
|
+
writeInfo(
|
|
1913
|
+
`[pumuki] bootstrap doctor deep adapter-wiring: status=${adapterCheck.status.toUpperCase()} severity=${adapterCheck.severity.toUpperCase()} message=${adapterCheck.message}`
|
|
1914
|
+
);
|
|
1915
|
+
if (adapterCheck.remediation) {
|
|
1916
|
+
writeInfo(`[pumuki] bootstrap doctor remediation: ${adapterCheck.remediation}`);
|
|
1917
|
+
}
|
|
1918
|
+
}
|
|
1919
|
+
}
|
|
1920
|
+
|
|
1921
|
+
if (blocking) {
|
|
1922
|
+
writeError('[pumuki] bootstrap enterprise detected blocking issues. Review doctor output.');
|
|
1923
|
+
return 1;
|
|
1924
|
+
}
|
|
1925
|
+
return 0;
|
|
1926
|
+
}
|
|
1325
1927
|
case 'install': {
|
|
1326
1928
|
const result = runLifecycleInstall();
|
|
1327
1929
|
writeInfo(
|
|
@@ -1335,6 +1937,31 @@ export const runLifecycleCli = async (
|
|
|
1335
1937
|
writeInfo('[pumuki] openspec bootstrap skipped npm install (package.json not found)');
|
|
1336
1938
|
}
|
|
1337
1939
|
}
|
|
1940
|
+
if (parsed.installWithMcp) {
|
|
1941
|
+
const adapterResult = runLifecycleAdapterInstall({
|
|
1942
|
+
agent: parsed.installMcpAgent ?? 'codex',
|
|
1943
|
+
});
|
|
1944
|
+
writeInfo(
|
|
1945
|
+
`[pumuki] mcp wiring: agent=${adapterResult.agent} changed=${adapterResult.changedFiles.length}`
|
|
1946
|
+
);
|
|
1947
|
+
if (adapterResult.changedFiles.length > 0) {
|
|
1948
|
+
writeInfo(`[pumuki] mcp files: ${adapterResult.changedFiles.join(', ')}`);
|
|
1949
|
+
}
|
|
1950
|
+
const deepReport = runLifecycleDoctor({
|
|
1951
|
+
deep: true,
|
|
1952
|
+
});
|
|
1953
|
+
const adapterCheck = deepReport.deep?.checks.find(
|
|
1954
|
+
(check) => check.id === 'adapter-wiring'
|
|
1955
|
+
);
|
|
1956
|
+
if (adapterCheck) {
|
|
1957
|
+
writeInfo(
|
|
1958
|
+
`[pumuki] mcp health: status=${adapterCheck.status.toUpperCase()} severity=${adapterCheck.severity.toUpperCase()} message=${adapterCheck.message}`
|
|
1959
|
+
);
|
|
1960
|
+
if (adapterCheck.remediation) {
|
|
1961
|
+
writeInfo(`[pumuki] mcp health remediation: ${adapterCheck.remediation}`);
|
|
1962
|
+
}
|
|
1963
|
+
}
|
|
1964
|
+
}
|
|
1338
1965
|
return 0;
|
|
1339
1966
|
}
|
|
1340
1967
|
case 'uninstall': {
|
|
@@ -1445,6 +2072,35 @@ export const runLifecycleCli = async (
|
|
|
1445
2072
|
}
|
|
1446
2073
|
return 0;
|
|
1447
2074
|
}
|
|
2075
|
+
case 'watch': {
|
|
2076
|
+
const watchResult = await activeDependencies.runLifecycleWatch(
|
|
2077
|
+
{
|
|
2078
|
+
repoRoot: process.cwd(),
|
|
2079
|
+
stage: parsed.watchStage,
|
|
2080
|
+
scope: parsed.watchScope,
|
|
2081
|
+
intervalMs: parsed.watchIntervalMs,
|
|
2082
|
+
notifyCooldownMs: parsed.watchNotifyCooldownMs,
|
|
2083
|
+
severityThreshold: parsed.watchSeverityThreshold,
|
|
2084
|
+
notifyEnabled: parsed.watchNotifyEnabled,
|
|
2085
|
+
maxIterations: parsed.watchIterations,
|
|
2086
|
+
onTick: parsed.json
|
|
2087
|
+
? undefined
|
|
2088
|
+
: (tick) => {
|
|
2089
|
+
writeInfo(
|
|
2090
|
+
`[pumuki][watch] tick=${tick.tick} stage=${tick.stage} scope=${tick.scope} changed=${tick.changed ? 'yes' : 'no'} evaluated=${tick.evaluated ? 'yes' : 'no'} exit=${tick.gateExitCode ?? 'n/a'} threshold=${tick.threshold} matched=${tick.findingsAtOrAboveThreshold} notification=${tick.notification}`
|
|
2091
|
+
);
|
|
2092
|
+
},
|
|
2093
|
+
}
|
|
2094
|
+
);
|
|
2095
|
+
if (parsed.json) {
|
|
2096
|
+
writeInfo(JSON.stringify(watchResult, null, 2));
|
|
2097
|
+
} else {
|
|
2098
|
+
writeInfo(
|
|
2099
|
+
`[pumuki][watch] done ticks=${watchResult.ticks} evaluations=${watchResult.evaluations} sent=${watchResult.notificationsSent} suppressed=${watchResult.notificationsSuppressed}`
|
|
2100
|
+
);
|
|
2101
|
+
}
|
|
2102
|
+
return 0;
|
|
2103
|
+
}
|
|
1448
2104
|
case 'loop': {
|
|
1449
2105
|
const repoRoot = process.cwd();
|
|
1450
2106
|
if (parsed.loopCommand === 'run') {
|
|
@@ -1666,6 +2322,31 @@ export const runLifecycleCli = async (
|
|
|
1666
2322
|
}
|
|
1667
2323
|
return 1;
|
|
1668
2324
|
}
|
|
2325
|
+
case 'policy': {
|
|
2326
|
+
if (parsed.policyCommand === 'reconcile') {
|
|
2327
|
+
const report = runPolicyReconcile({
|
|
2328
|
+
repoRoot: process.cwd(),
|
|
2329
|
+
strict: parsed.policyStrict === true,
|
|
2330
|
+
});
|
|
2331
|
+
if (parsed.json) {
|
|
2332
|
+
writeInfo(JSON.stringify(report, null, 2));
|
|
2333
|
+
} else {
|
|
2334
|
+
writeInfo(
|
|
2335
|
+
`[pumuki][policy] reconcile status=${report.summary.status} total=${report.summary.total} blocking=${report.summary.blocking} warnings=${report.summary.warnings} strict_requested=${report.strictRequested ? 'yes' : 'no'}`
|
|
2336
|
+
);
|
|
2337
|
+
for (const drift of report.drifts) {
|
|
2338
|
+
writeInfo(
|
|
2339
|
+
`[pumuki][policy] ${drift.code} severity=${drift.severity} blocking=${drift.blocking ? 'yes' : 'no'} message=${drift.message}`
|
|
2340
|
+
);
|
|
2341
|
+
if (drift.remediation) {
|
|
2342
|
+
writeInfo(`[pumuki][policy] remediation: ${drift.remediation}`);
|
|
2343
|
+
}
|
|
2344
|
+
}
|
|
2345
|
+
}
|
|
2346
|
+
return report.summary.blocking > 0 ? 1 : 0;
|
|
2347
|
+
}
|
|
2348
|
+
return 1;
|
|
2349
|
+
}
|
|
1669
2350
|
case 'sdd': {
|
|
1670
2351
|
if (parsed.sddCommand === 'status') {
|
|
1671
2352
|
const sddStatus = readSddStatus();
|
|
@@ -1917,12 +2598,13 @@ export const runLifecycleCli = async (
|
|
|
1917
2598
|
change: parsed.sddSyncDocsChange,
|
|
1918
2599
|
stage: parsed.sddSyncDocsStage,
|
|
1919
2600
|
task: parsed.sddSyncDocsTask,
|
|
2601
|
+
fromEvidencePath: parsed.sddSyncDocsFromEvidence,
|
|
1920
2602
|
});
|
|
1921
2603
|
if (parsed.json) {
|
|
1922
2604
|
writeInfo(JSON.stringify(syncResult, null, 2));
|
|
1923
2605
|
} else {
|
|
1924
2606
|
writeInfo(
|
|
1925
|
-
`[pumuki][sdd] sync-docs dry_run=${syncResult.dryRun ? 'yes' : 'no'} updated=${syncResult.updated ? 'yes' : 'no'} files=${syncResult.files.length} change=${syncResult.context.change ?? 'none'} stage=${syncResult.context.stage ?? 'none'} task=${syncResult.context.task ?? 'none'}`
|
|
2607
|
+
`[pumuki][sdd] sync-docs dry_run=${syncResult.dryRun ? 'yes' : 'no'} updated=${syncResult.updated ? 'yes' : 'no'} files=${syncResult.files.length} change=${syncResult.context.change ?? 'none'} stage=${syncResult.context.stage ?? 'none'} task=${syncResult.context.task ?? 'none'} from_evidence=${syncResult.context.fromEvidencePath ?? 'default'}`
|
|
1926
2608
|
);
|
|
1927
2609
|
for (const file of syncResult.files) {
|
|
1928
2610
|
writeInfo(
|
|
@@ -1942,12 +2624,13 @@ export const runLifecycleCli = async (
|
|
|
1942
2624
|
change: parsed.sddLearnChange,
|
|
1943
2625
|
stage: parsed.sddLearnStage,
|
|
1944
2626
|
task: parsed.sddLearnTask,
|
|
2627
|
+
fromEvidencePath: parsed.sddLearnFromEvidence,
|
|
1945
2628
|
});
|
|
1946
2629
|
if (parsed.json) {
|
|
1947
2630
|
writeInfo(JSON.stringify(learnResult, null, 2));
|
|
1948
2631
|
} else {
|
|
1949
2632
|
writeInfo(
|
|
1950
|
-
`[pumuki][sdd] learn dry_run=${learnResult.dryRun ? 'yes' : 'no'} change=${learnResult.context.change} stage=${learnResult.context.stage ?? 'none'} task=${learnResult.context.task ?? 'none'} written=${learnResult.learning.written ? 'yes' : 'no'} digest=${learnResult.learning.digest}`
|
|
2633
|
+
`[pumuki][sdd] learn dry_run=${learnResult.dryRun ? 'yes' : 'no'} change=${learnResult.context.change} stage=${learnResult.context.stage ?? 'none'} task=${learnResult.context.task ?? 'none'} from_evidence=${learnResult.context.fromEvidencePath ?? 'default'} written=${learnResult.learning.written ? 'yes' : 'no'} digest=${learnResult.learning.digest}`
|
|
1951
2634
|
);
|
|
1952
2635
|
writeInfo(
|
|
1953
2636
|
`[pumuki][sdd] learning_path=${learnResult.learning.path} failed=${learnResult.learning.artifact.failed_patterns.length} successful=${learnResult.learning.artifact.successful_patterns.length} anomalies=${learnResult.learning.artifact.gate_anomalies.length} updates=${learnResult.learning.artifact.rule_updates.length}`
|
|
@@ -1962,12 +2645,13 @@ export const runLifecycleCli = async (
|
|
|
1962
2645
|
change: parsed.sddAutoSyncChange,
|
|
1963
2646
|
stage: parsed.sddAutoSyncStage,
|
|
1964
2647
|
task: parsed.sddAutoSyncTask,
|
|
2648
|
+
fromEvidencePath: parsed.sddAutoSyncFromEvidence,
|
|
1965
2649
|
});
|
|
1966
2650
|
if (parsed.json) {
|
|
1967
2651
|
writeInfo(JSON.stringify(autoSyncResult, null, 2));
|
|
1968
2652
|
} else {
|
|
1969
2653
|
writeInfo(
|
|
1970
|
-
`[pumuki][sdd] auto-sync dry_run=${autoSyncResult.dryRun ? 'yes' : 'no'} change=${autoSyncResult.context.change} stage=${autoSyncResult.context.stage ?? 'none'} task=${autoSyncResult.context.task ?? 'none'} updated=${autoSyncResult.syncDocs.updated ? 'yes' : 'no'} files=${autoSyncResult.syncDocs.files.length} learning_written=${autoSyncResult.learning.written ? 'yes' : 'no'}`
|
|
2654
|
+
`[pumuki][sdd] auto-sync dry_run=${autoSyncResult.dryRun ? 'yes' : 'no'} change=${autoSyncResult.context.change} stage=${autoSyncResult.context.stage ?? 'none'} task=${autoSyncResult.context.task ?? 'none'} from_evidence=${autoSyncResult.context.fromEvidencePath ?? 'default'} updated=${autoSyncResult.syncDocs.updated ? 'yes' : 'no'} files=${autoSyncResult.syncDocs.files.length} learning_written=${autoSyncResult.learning.written ? 'yes' : 'no'}`
|
|
1971
2655
|
);
|
|
1972
2656
|
writeInfo(
|
|
1973
2657
|
`[pumuki][sdd] learning_path=${autoSyncResult.learning.path} digest=${autoSyncResult.learning.digest}`
|
|
@@ -1980,6 +2664,59 @@ export const runLifecycleCli = async (
|
|
|
1980
2664
|
}
|
|
1981
2665
|
return 0;
|
|
1982
2666
|
}
|
|
2667
|
+
if (parsed.sddCommand === 'evidence') {
|
|
2668
|
+
const evidenceResult = runSddEvidenceScaffold({
|
|
2669
|
+
repoRoot: process.cwd(),
|
|
2670
|
+
dryRun: parsed.sddEvidenceDryRun === true,
|
|
2671
|
+
scenarioId: parsed.sddEvidenceScenarioId,
|
|
2672
|
+
testCommand: parsed.sddEvidenceTestCommand,
|
|
2673
|
+
testStatus: parsed.sddEvidenceTestStatus,
|
|
2674
|
+
testOutputPath: parsed.sddEvidenceTestOutput,
|
|
2675
|
+
fromEvidencePath: parsed.sddEvidenceFromEvidence,
|
|
2676
|
+
});
|
|
2677
|
+
if (parsed.json) {
|
|
2678
|
+
writeInfo(JSON.stringify(evidenceResult, null, 2));
|
|
2679
|
+
} else {
|
|
2680
|
+
writeInfo(
|
|
2681
|
+
`[pumuki][sdd] evidence dry_run=${evidenceResult.dryRun ? 'yes' : 'no'} scenario=${evidenceResult.context.scenarioId} status=${evidenceResult.context.testStatus} output=${evidenceResult.output.path} written=${evidenceResult.output.written ? 'yes' : 'no'}`
|
|
2682
|
+
);
|
|
2683
|
+
writeInfo(
|
|
2684
|
+
`[pumuki][sdd] test_command=${evidenceResult.context.testCommand} test_output=${evidenceResult.context.testOutputPath ?? 'none'} from_evidence=${evidenceResult.context.fromEvidencePath ?? 'default'}`
|
|
2685
|
+
);
|
|
2686
|
+
writeInfo(
|
|
2687
|
+
`[pumuki][sdd] source_digest=${evidenceResult.artifact.ai_evidence.digest} generated_at=${evidenceResult.artifact.generated_at}`
|
|
2688
|
+
);
|
|
2689
|
+
}
|
|
2690
|
+
return 0;
|
|
2691
|
+
}
|
|
2692
|
+
if (parsed.sddCommand === 'state-sync') {
|
|
2693
|
+
const stateSyncResult = runSddStateSync({
|
|
2694
|
+
repoRoot: process.cwd(),
|
|
2695
|
+
dryRun: parsed.sddStateSyncDryRun === true,
|
|
2696
|
+
scenarioId: parsed.sddStateSyncScenarioId,
|
|
2697
|
+
status: parsed.sddStateSyncStatus,
|
|
2698
|
+
fromEvidencePath: parsed.sddStateSyncFromEvidence,
|
|
2699
|
+
boardPath: parsed.sddStateSyncBoardPath,
|
|
2700
|
+
force: parsed.sddStateSyncForce === true,
|
|
2701
|
+
});
|
|
2702
|
+
if (parsed.json) {
|
|
2703
|
+
writeInfo(JSON.stringify(stateSyncResult, null, 2));
|
|
2704
|
+
} else {
|
|
2705
|
+
writeInfo(
|
|
2706
|
+
`[pumuki][sdd] state-sync dry_run=${stateSyncResult.dryRun ? 'yes' : 'no'} scenario=${stateSyncResult.context.scenarioId} status=${stateSyncResult.context.desiredStatus} updated=${stateSyncResult.board.updated ? 'yes' : 'no'} conflict=${stateSyncResult.board.conflict ? 'yes' : 'no'} written=${stateSyncResult.board.written ? 'yes' : 'no'}`
|
|
2707
|
+
);
|
|
2708
|
+
writeInfo(
|
|
2709
|
+
`[pumuki][sdd] state-sync source=${stateSyncResult.context.fromEvidencePath ?? 'default'} board=${stateSyncResult.context.boardPath} entries=${stateSyncResult.board.entries} decision=${stateSyncResult.decision.code}`
|
|
2710
|
+
);
|
|
2711
|
+
if (stateSyncResult.decision.nextAction) {
|
|
2712
|
+
writeInfo(`[pumuki][sdd] state-sync next action: ${stateSyncResult.decision.nextAction}`);
|
|
2713
|
+
}
|
|
2714
|
+
}
|
|
2715
|
+
if (!stateSyncResult.decision.allowed) {
|
|
2716
|
+
return 1;
|
|
2717
|
+
}
|
|
2718
|
+
return 0;
|
|
2719
|
+
}
|
|
1983
2720
|
return 0;
|
|
1984
2721
|
}
|
|
1985
2722
|
case 'adapter': {
|