pan-wizard 3.13.1 → 3.15.0
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/LICENSE +21 -21
- package/README.md +4 -5
- package/commands/pan/audit-deployment.md +384 -384
- package/commands/pan/focus-auto.md +683 -683
- package/commands/pan/focus-doc-audit.md +530 -530
- package/commands/pan/focus-drift-walking.md +525 -525
- package/commands/pan/git.md +1 -1
- package/commands/pan/hud.md +3 -2
- package/commands/pan/report.md +70 -0
- package/hooks/dist/pan-check-update.js +62 -62
- package/hooks/dist/pan-context-monitor.js +134 -122
- package/hooks/dist/pan-statusline.js +7 -1
- package/package.json +5 -5
- package/pan-wizard-core/bin/lib/config.cjs +14 -1
- package/pan-wizard-core/bin/lib/core.cjs +6 -2
- package/pan-wizard-core/bin/lib/doc-lint.cjs +86 -1
- package/pan-wizard-core/bin/lib/focus.cjs +48 -2
- package/pan-wizard-core/bin/lib/frontmatter.cjs +442 -442
- package/pan-wizard-core/bin/lib/hud.cjs +202 -17
- package/pan-wizard-core/bin/lib/knowledge.cjs +2 -2
- package/pan-wizard-core/bin/lib/optimize.cjs +2 -2
- package/pan-wizard-core/bin/lib/phase-remove.cjs +1 -1
- package/pan-wizard-core/bin/lib/phase-report.cjs +723 -0
- package/pan-wizard-core/bin/lib/phase.cjs +4 -4
- package/pan-wizard-core/bin/lib/review-deep.cjs +3 -1
- package/pan-wizard-core/bin/lib/utils.cjs +171 -171
- package/pan-wizard-core/bin/lib/verify.cjs +172 -61
- package/pan-wizard-core/bin/pan-tools.cjs +1499 -1463
- package/pan-wizard-core/references/checkpoints.md +776 -776
- package/pan-wizard-core/references/continuation-format.md +249 -249
- package/pan-wizard-core/references/questioning.md +145 -145
- package/pan-wizard-core/references/tdd.md +263 -263
- package/pan-wizard-core/references/ui-brand.md +160 -160
- package/pan-wizard-core/templates/config.json +38 -38
- package/pan-wizard-core/workflows/exec-phase.md +14 -0
- package/scripts/build-hooks.js +51 -51
- package/scripts/git-hooks/pre-commit +0 -0
- package/scripts/release-check.js +53 -47
- package/scripts/run-tests.cjs +44 -0
|
@@ -1,1463 +1,1499 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* PAN Tools — CLI utility for PAN workflow operations
|
|
5
|
-
*
|
|
6
|
-
* Replaces repetitive inline bash patterns across ~50 PAN command/workflow/agent files.
|
|
7
|
-
* Centralizes: config parsing, model resolution, phase lookup, git commits, summary verification.
|
|
8
|
-
*
|
|
9
|
-
* Usage: node pan-tools.cjs <command> [args] [--raw] [--verbose]
|
|
10
|
-
*
|
|
11
|
-
* Atomic Commands:
|
|
12
|
-
* state load Load project config + state
|
|
13
|
-
* state json Output state.md frontmatter as JSON
|
|
14
|
-
* state update <field> <value> Update a state.md field
|
|
15
|
-
* state get [section] Get state.md content or section
|
|
16
|
-
* state patch --field val ... Batch update state.md fields
|
|
17
|
-
* resolve-model <agent-type> Get model for agent based on profile
|
|
18
|
-
* find-phase <phase> Find phase directory by number
|
|
19
|
-
* commit <message> [--files f1 f2] Commit planning docs
|
|
20
|
-
* verify-summary <path> Verify a summary.md file
|
|
21
|
-
* generate-slug <text> Convert text to URL-safe slug
|
|
22
|
-
* current-timestamp [format] Get timestamp (full|date|filename)
|
|
23
|
-
* list-todos [area] Count and enumerate pending todos
|
|
24
|
-
* verify-path-exists <path> Check file/directory existence
|
|
25
|
-
* config-ensure-section Initialize .planning/config.json
|
|
26
|
-
* config-set <key> <value> Set a config.json key
|
|
27
|
-
* config-get <key> Get a config.json value
|
|
28
|
-
* history-digest Aggregate all summary.md data
|
|
29
|
-
* summary-extract <path> [--fields] Extract structured data from summary.md
|
|
30
|
-
* state-snapshot Structured parse of state.md
|
|
31
|
-
* phase-plan-index <phase> Index plans with waves and status
|
|
32
|
-
* websearch <query> Search web via Brave API (if configured)
|
|
33
|
-
* [--limit N] [--freshness day|week|month]
|
|
34
|
-
*
|
|
35
|
-
* Phase Listing:
|
|
36
|
-
* phases list [--type plan|summary] List phases with optional type filter
|
|
37
|
-
* [--phase N] [--include-archived]
|
|
38
|
-
*
|
|
39
|
-
* Phase Operations:
|
|
40
|
-
* phase next-decimal <phase> Calculate next decimal phase number
|
|
41
|
-
* phase add <description> Append new phase to roadmap + create dir
|
|
42
|
-
* phase insert <after> <description> Insert decimal phase after existing
|
|
43
|
-
* phase remove <phase> [--force] Remove phase, renumber all subsequent
|
|
44
|
-
* phase complete <phase> Mark phase done, update state + roadmap
|
|
45
|
-
*
|
|
46
|
-
* Roadmap Operations:
|
|
47
|
-
* roadmap get-phase <phase> Extract phase section from roadmap.md
|
|
48
|
-
* roadmap analyze Full roadmap parse with disk status
|
|
49
|
-
* roadmap update-plan-progress <N> Update progress table row from disk (PLAN vs SUMMARY counts)
|
|
50
|
-
*
|
|
51
|
-
* Requirements Operations:
|
|
52
|
-
* requirements mark-complete <ids> Mark requirement IDs as complete in requirements.md
|
|
53
|
-
* Accepts: REQ-01,REQ-02 or REQ-01 REQ-02 or [REQ-01, REQ-02]
|
|
54
|
-
*
|
|
55
|
-
* Milestone Operations:
|
|
56
|
-
* milestone complete <version> Archive milestone, create milestones.md
|
|
57
|
-
* [--name <name>]
|
|
58
|
-
* [--archive-phases] Move phase dirs to milestones/vX.Y-phases/
|
|
59
|
-
*
|
|
60
|
-
* Validation:
|
|
61
|
-
* validate consistency Check phase numbering, disk/roadmap sync
|
|
62
|
-
* validate health [--repair] [--full] Check .planning/ integrity, optionally repair or run tests+build
|
|
63
|
-
*
|
|
64
|
-
* Progress:
|
|
65
|
-
* progress [json|table|bar|health] Render progress in various formats
|
|
66
|
-
* context-budget Estimate context utilization for current phase
|
|
67
|
-
*
|
|
68
|
-
* Todos:
|
|
69
|
-
* todo complete <filename> Move todo from pending to completed
|
|
70
|
-
*
|
|
71
|
-
* Scaffolding:
|
|
72
|
-
* scaffold context --phase <N> Create context.md template
|
|
73
|
-
* scaffold uat --phase <N> Create uat.md template
|
|
74
|
-
* scaffold verification --phase <N> Create verification.md template
|
|
75
|
-
* scaffold phase-dir --phase <N> Create phase directory
|
|
76
|
-
* --name <name>
|
|
77
|
-
*
|
|
78
|
-
* Frontmatter CRUD:
|
|
79
|
-
* frontmatter get <file> [--field k] Extract frontmatter as JSON
|
|
80
|
-
* frontmatter set <file> --field k Update single frontmatter field
|
|
81
|
-
* --value jsonVal
|
|
82
|
-
* frontmatter merge <file> Merge JSON into frontmatter
|
|
83
|
-
* --data '{json}'
|
|
84
|
-
* frontmatter validate <file> Validate required fields
|
|
85
|
-
* --schema plan|summary|verification
|
|
86
|
-
*
|
|
87
|
-
* Verification Suite:
|
|
88
|
-
* verify plan-structure <file> Check plan.md structure + tasks
|
|
89
|
-
* verify phase-completeness <phase> Check all plans have summaries
|
|
90
|
-
* verify references <file> Check @-refs + paths resolve
|
|
91
|
-
* verify commits <h1> [h2] ... Batch verify commit hashes
|
|
92
|
-
* verify artifacts <plan-file> Check must_haves.artifacts
|
|
93
|
-
* verify key-links <plan-file> Check must_haves.key_links
|
|
94
|
-
*
|
|
95
|
-
* Template Fill:
|
|
96
|
-
* template fill summary --phase N Create pre-filled summary.md
|
|
97
|
-
* [--plan M] [--name "..."]
|
|
98
|
-
* [--fields '{json}']
|
|
99
|
-
* template fill plan --phase N Create pre-filled plan.md
|
|
100
|
-
* [--plan M] [--type execute|tdd]
|
|
101
|
-
* [--wave N] [--fields '{json}']
|
|
102
|
-
* template fill verification Create pre-filled verification.md
|
|
103
|
-
* --phase N [--fields '{json}']
|
|
104
|
-
*
|
|
105
|
-
* State Progression:
|
|
106
|
-
* state advance-plan Increment plan counter
|
|
107
|
-
* state record-metric --phase N Record execution metrics
|
|
108
|
-
* --plan M --duration Xmin
|
|
109
|
-
* [--tasks N] [--files N]
|
|
110
|
-
* state update-progress Recalculate progress bar
|
|
111
|
-
* state add-decision --summary "..." Add decision to state.md
|
|
112
|
-
* [--phase N] [--rationale "..."]
|
|
113
|
-
* [--summary-file path] [--rationale-file path]
|
|
114
|
-
* state add-blocker --text "..." Add blocker
|
|
115
|
-
* [--text-file path]
|
|
116
|
-
* state resolve-blocker --text "..." Remove blocker
|
|
117
|
-
* state record-session Update session continuity
|
|
118
|
-
* --stopped-at "..."
|
|
119
|
-
* [--resume-file path]
|
|
120
|
-
*
|
|
121
|
-
* Compound Commands (workflow-specific initialization):
|
|
122
|
-
* init execute-phase <phase> All context for execute-phase workflow
|
|
123
|
-
* init plan-phase <phase> All context for plan-phase workflow
|
|
124
|
-
* init new-project All context for new-project workflow
|
|
125
|
-
* init new-milestone All context for new-milestone workflow
|
|
126
|
-
* init quick <description> All context for quick workflow
|
|
127
|
-
* init resume All context for resume-project workflow
|
|
128
|
-
* init verify-work <phase> All context for verify-work workflow
|
|
129
|
-
* init phase-op <phase> Generic phase operation context
|
|
130
|
-
* init todos [area] All context for todo workflows
|
|
131
|
-
* init milestone-op All context for milestone operations
|
|
132
|
-
* init map-codebase All context for map-codebase workflow
|
|
133
|
-
* init progress All context for progress workflow
|
|
134
|
-
*
|
|
135
|
-
* Focus (Strategic Project Management):
|
|
136
|
-
* focus scan [--lean] Collect, classify, and prioritize work items
|
|
137
|
-
* focus plan [--budget N] Create capacity-budgeted execution batch
|
|
138
|
-
* [--mode bugfix|balanced|features|full]
|
|
139
|
-
* [--priority P0-P6] [--lean]
|
|
140
|
-
* focus sync [--check-only] Check documentation staleness
|
|
141
|
-
* focus exec [--dry-run] Load and classify batch for execution
|
|
142
|
-
* focus auto [--category CAT] Auto-runner: init, status, update, stop
|
|
143
|
-
* [--mode MODE] [--budget N] [--max-cycles N] [--total-budget N]
|
|
144
|
-
* [--status] [--stop] [--update] [--continue] [--dry-run]
|
|
145
|
-
* focus design Route to 10-phase investigation workflow
|
|
146
|
-
*
|
|
147
|
-
* Pre-Flight & Dashboard:
|
|
148
|
-
* preflight [phase|batch] Validate execution prerequisites
|
|
149
|
-
* dashboard Aggregated project status overview
|
|
150
|
-
* hud [--out f] [--open] [--stdout] Single-page HTML army + project dashboard
|
|
151
|
-
*
|
|
152
|
-
*
|
|
153
|
-
*
|
|
154
|
-
* learnings
|
|
155
|
-
* learnings
|
|
156
|
-
*
|
|
157
|
-
*
|
|
158
|
-
*
|
|
159
|
-
*
|
|
160
|
-
*
|
|
161
|
-
*
|
|
162
|
-
* standards
|
|
163
|
-
* standards
|
|
164
|
-
* standards
|
|
165
|
-
* standards
|
|
166
|
-
* standards
|
|
167
|
-
* standards
|
|
168
|
-
*
|
|
169
|
-
*
|
|
170
|
-
*
|
|
171
|
-
*
|
|
172
|
-
*
|
|
173
|
-
* optimize trace
|
|
174
|
-
* optimize trace
|
|
175
|
-
* optimize trace
|
|
176
|
-
*
|
|
177
|
-
*
|
|
178
|
-
* optimize
|
|
179
|
-
* optimize
|
|
180
|
-
* optimize
|
|
181
|
-
*
|
|
182
|
-
*
|
|
183
|
-
*
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
const
|
|
188
|
-
const
|
|
189
|
-
const
|
|
190
|
-
const
|
|
191
|
-
const
|
|
192
|
-
const
|
|
193
|
-
const
|
|
194
|
-
const
|
|
195
|
-
const
|
|
196
|
-
const
|
|
197
|
-
const
|
|
198
|
-
const
|
|
199
|
-
const
|
|
200
|
-
const
|
|
201
|
-
const
|
|
202
|
-
const
|
|
203
|
-
const
|
|
204
|
-
const
|
|
205
|
-
const
|
|
206
|
-
const
|
|
207
|
-
const
|
|
208
|
-
const
|
|
209
|
-
const
|
|
210
|
-
const
|
|
211
|
-
const
|
|
212
|
-
const
|
|
213
|
-
const
|
|
214
|
-
const
|
|
215
|
-
const
|
|
216
|
-
const
|
|
217
|
-
const
|
|
218
|
-
const
|
|
219
|
-
const
|
|
220
|
-
const
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
*
|
|
225
|
-
* @param {string}
|
|
226
|
-
* @param {
|
|
227
|
-
* @
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
*
|
|
238
|
-
* @param {string}
|
|
239
|
-
* @
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
const
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
const
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
const
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
const
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
git.
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
const
|
|
391
|
-
const
|
|
392
|
-
const
|
|
393
|
-
const
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
const
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
const
|
|
409
|
-
const
|
|
410
|
-
const
|
|
411
|
-
const
|
|
412
|
-
|
|
413
|
-
if (
|
|
414
|
-
if (
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
const
|
|
439
|
-
const
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
const
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
const
|
|
458
|
-
const
|
|
459
|
-
const
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
const
|
|
463
|
-
const
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
const
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
const
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
const
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
break;
|
|
536
|
-
}
|
|
537
|
-
|
|
538
|
-
case '
|
|
539
|
-
commands.
|
|
540
|
-
break;
|
|
541
|
-
}
|
|
542
|
-
|
|
543
|
-
case '
|
|
544
|
-
commands.
|
|
545
|
-
break;
|
|
546
|
-
}
|
|
547
|
-
|
|
548
|
-
case '
|
|
549
|
-
commands.
|
|
550
|
-
break;
|
|
551
|
-
}
|
|
552
|
-
|
|
553
|
-
case '
|
|
554
|
-
|
|
555
|
-
break;
|
|
556
|
-
}
|
|
557
|
-
|
|
558
|
-
case 'config-
|
|
559
|
-
config.
|
|
560
|
-
break;
|
|
561
|
-
}
|
|
562
|
-
|
|
563
|
-
case 'config-
|
|
564
|
-
config.
|
|
565
|
-
break;
|
|
566
|
-
}
|
|
567
|
-
|
|
568
|
-
case '
|
|
569
|
-
|
|
570
|
-
break;
|
|
571
|
-
}
|
|
572
|
-
|
|
573
|
-
case '
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
if (!args[2]) error('roadmap
|
|
597
|
-
roadmap.
|
|
598
|
-
} else {
|
|
599
|
-
|
|
600
|
-
}
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
if (!args[2]) error('phase
|
|
623
|
-
phase.
|
|
624
|
-
} else if (subcommand === '
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
break;
|
|
689
|
-
}
|
|
690
|
-
|
|
691
|
-
case '
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
case '
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
break;
|
|
762
|
-
}
|
|
763
|
-
|
|
764
|
-
case '
|
|
765
|
-
|
|
766
|
-
break;
|
|
767
|
-
}
|
|
768
|
-
|
|
769
|
-
case '
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
commands.
|
|
779
|
-
break;
|
|
780
|
-
}
|
|
781
|
-
|
|
782
|
-
case '
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
payload
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
break;
|
|
855
|
-
}
|
|
856
|
-
|
|
857
|
-
case '
|
|
858
|
-
|
|
859
|
-
break;
|
|
860
|
-
}
|
|
861
|
-
|
|
862
|
-
case '
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
} else {
|
|
895
|
-
|
|
896
|
-
}
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
getArgValue(args, '--
|
|
966
|
-
getArgValue(args, '--
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
);
|
|
970
|
-
} else {
|
|
971
|
-
error('Unknown
|
|
972
|
-
}
|
|
973
|
-
break;
|
|
974
|
-
}
|
|
975
|
-
|
|
976
|
-
case '
|
|
977
|
-
const subcommand = args[1];
|
|
978
|
-
if (subcommand === '
|
|
979
|
-
const
|
|
980
|
-
const
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
}
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
}
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
if (subcommand === '
|
|
1059
|
-
|
|
1060
|
-
} else if (subcommand === '
|
|
1061
|
-
|
|
1062
|
-
} else
|
|
1063
|
-
|
|
1064
|
-
}
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
const
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
}
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
});
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
const
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
}
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
}
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
if (subcommand === '
|
|
1323
|
-
const
|
|
1324
|
-
if (!
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
const
|
|
1330
|
-
|
|
1331
|
-
const
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
const
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
const
|
|
1362
|
-
const
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
const
|
|
1369
|
-
const
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
const
|
|
1385
|
-
|
|
1386
|
-
const
|
|
1387
|
-
const
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
}
|
|
1425
|
-
if (
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
};
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* PAN Tools — CLI utility for PAN workflow operations
|
|
5
|
+
*
|
|
6
|
+
* Replaces repetitive inline bash patterns across ~50 PAN command/workflow/agent files.
|
|
7
|
+
* Centralizes: config parsing, model resolution, phase lookup, git commits, summary verification.
|
|
8
|
+
*
|
|
9
|
+
* Usage: node pan-tools.cjs <command> [args] [--raw] [--verbose]
|
|
10
|
+
*
|
|
11
|
+
* Atomic Commands:
|
|
12
|
+
* state load Load project config + state
|
|
13
|
+
* state json Output state.md frontmatter as JSON
|
|
14
|
+
* state update <field> <value> Update a state.md field
|
|
15
|
+
* state get [section] Get state.md content or section
|
|
16
|
+
* state patch --field val ... Batch update state.md fields
|
|
17
|
+
* resolve-model <agent-type> Get model for agent based on profile
|
|
18
|
+
* find-phase <phase> Find phase directory by number
|
|
19
|
+
* commit <message> [--files f1 f2] Commit planning docs
|
|
20
|
+
* verify-summary <path> Verify a summary.md file
|
|
21
|
+
* generate-slug <text> Convert text to URL-safe slug
|
|
22
|
+
* current-timestamp [format] Get timestamp (full|date|filename)
|
|
23
|
+
* list-todos [area] Count and enumerate pending todos
|
|
24
|
+
* verify-path-exists <path> Check file/directory existence
|
|
25
|
+
* config-ensure-section Initialize .planning/config.json
|
|
26
|
+
* config-set <key> <value> Set a config.json key
|
|
27
|
+
* config-get <key> Get a config.json value
|
|
28
|
+
* history-digest Aggregate all summary.md data
|
|
29
|
+
* summary-extract <path> [--fields] Extract structured data from summary.md
|
|
30
|
+
* state-snapshot Structured parse of state.md
|
|
31
|
+
* phase-plan-index <phase> Index plans with waves and status
|
|
32
|
+
* websearch <query> Search web via Brave API (if configured)
|
|
33
|
+
* [--limit N] [--freshness day|week|month]
|
|
34
|
+
*
|
|
35
|
+
* Phase Listing:
|
|
36
|
+
* phases list [--type plan|summary] List phases with optional type filter
|
|
37
|
+
* [--phase N] [--include-archived]
|
|
38
|
+
*
|
|
39
|
+
* Phase Operations:
|
|
40
|
+
* phase next-decimal <phase> Calculate next decimal phase number
|
|
41
|
+
* phase add <description> Append new phase to roadmap + create dir
|
|
42
|
+
* phase insert <after> <description> Insert decimal phase after existing
|
|
43
|
+
* phase remove <phase> [--force] Remove phase, renumber all subsequent
|
|
44
|
+
* phase complete <phase> Mark phase done, update state + roadmap
|
|
45
|
+
*
|
|
46
|
+
* Roadmap Operations:
|
|
47
|
+
* roadmap get-phase <phase> Extract phase section from roadmap.md
|
|
48
|
+
* roadmap analyze Full roadmap parse with disk status
|
|
49
|
+
* roadmap update-plan-progress <N> Update progress table row from disk (PLAN vs SUMMARY counts)
|
|
50
|
+
*
|
|
51
|
+
* Requirements Operations:
|
|
52
|
+
* requirements mark-complete <ids> Mark requirement IDs as complete in requirements.md
|
|
53
|
+
* Accepts: REQ-01,REQ-02 or REQ-01 REQ-02 or [REQ-01, REQ-02]
|
|
54
|
+
*
|
|
55
|
+
* Milestone Operations:
|
|
56
|
+
* milestone complete <version> Archive milestone, create milestones.md
|
|
57
|
+
* [--name <name>]
|
|
58
|
+
* [--archive-phases] Move phase dirs to milestones/vX.Y-phases/
|
|
59
|
+
*
|
|
60
|
+
* Validation:
|
|
61
|
+
* validate consistency Check phase numbering, disk/roadmap sync
|
|
62
|
+
* validate health [--repair] [--full] Check .planning/ integrity, optionally repair or run tests+build
|
|
63
|
+
*
|
|
64
|
+
* Progress:
|
|
65
|
+
* progress [json|table|bar|health] Render progress in various formats
|
|
66
|
+
* context-budget Estimate context utilization for current phase
|
|
67
|
+
*
|
|
68
|
+
* Todos:
|
|
69
|
+
* todo complete <filename> Move todo from pending to completed
|
|
70
|
+
*
|
|
71
|
+
* Scaffolding:
|
|
72
|
+
* scaffold context --phase <N> Create context.md template
|
|
73
|
+
* scaffold uat --phase <N> Create uat.md template
|
|
74
|
+
* scaffold verification --phase <N> Create verification.md template
|
|
75
|
+
* scaffold phase-dir --phase <N> Create phase directory
|
|
76
|
+
* --name <name>
|
|
77
|
+
*
|
|
78
|
+
* Frontmatter CRUD:
|
|
79
|
+
* frontmatter get <file> [--field k] Extract frontmatter as JSON
|
|
80
|
+
* frontmatter set <file> --field k Update single frontmatter field
|
|
81
|
+
* --value jsonVal
|
|
82
|
+
* frontmatter merge <file> Merge JSON into frontmatter
|
|
83
|
+
* --data '{json}'
|
|
84
|
+
* frontmatter validate <file> Validate required fields
|
|
85
|
+
* --schema plan|summary|verification
|
|
86
|
+
*
|
|
87
|
+
* Verification Suite:
|
|
88
|
+
* verify plan-structure <file> Check plan.md structure + tasks
|
|
89
|
+
* verify phase-completeness <phase> Check all plans have summaries
|
|
90
|
+
* verify references <file> Check @-refs + paths resolve
|
|
91
|
+
* verify commits <h1> [h2] ... Batch verify commit hashes
|
|
92
|
+
* verify artifacts <plan-file> Check must_haves.artifacts
|
|
93
|
+
* verify key-links <plan-file> Check must_haves.key_links
|
|
94
|
+
*
|
|
95
|
+
* Template Fill:
|
|
96
|
+
* template fill summary --phase N Create pre-filled summary.md
|
|
97
|
+
* [--plan M] [--name "..."]
|
|
98
|
+
* [--fields '{json}']
|
|
99
|
+
* template fill plan --phase N Create pre-filled plan.md
|
|
100
|
+
* [--plan M] [--type execute|tdd]
|
|
101
|
+
* [--wave N] [--fields '{json}']
|
|
102
|
+
* template fill verification Create pre-filled verification.md
|
|
103
|
+
* --phase N [--fields '{json}']
|
|
104
|
+
*
|
|
105
|
+
* State Progression:
|
|
106
|
+
* state advance-plan Increment plan counter
|
|
107
|
+
* state record-metric --phase N Record execution metrics
|
|
108
|
+
* --plan M --duration Xmin
|
|
109
|
+
* [--tasks N] [--files N]
|
|
110
|
+
* state update-progress Recalculate progress bar
|
|
111
|
+
* state add-decision --summary "..." Add decision to state.md
|
|
112
|
+
* [--phase N] [--rationale "..."]
|
|
113
|
+
* [--summary-file path] [--rationale-file path]
|
|
114
|
+
* state add-blocker --text "..." Add blocker
|
|
115
|
+
* [--text-file path]
|
|
116
|
+
* state resolve-blocker --text "..." Remove blocker
|
|
117
|
+
* state record-session Update session continuity
|
|
118
|
+
* --stopped-at "..."
|
|
119
|
+
* [--resume-file path]
|
|
120
|
+
*
|
|
121
|
+
* Compound Commands (workflow-specific initialization):
|
|
122
|
+
* init execute-phase <phase> All context for execute-phase workflow
|
|
123
|
+
* init plan-phase <phase> All context for plan-phase workflow
|
|
124
|
+
* init new-project All context for new-project workflow
|
|
125
|
+
* init new-milestone All context for new-milestone workflow
|
|
126
|
+
* init quick <description> All context for quick workflow
|
|
127
|
+
* init resume All context for resume-project workflow
|
|
128
|
+
* init verify-work <phase> All context for verify-work workflow
|
|
129
|
+
* init phase-op <phase> Generic phase operation context
|
|
130
|
+
* init todos [area] All context for todo workflows
|
|
131
|
+
* init milestone-op All context for milestone operations
|
|
132
|
+
* init map-codebase All context for map-codebase workflow
|
|
133
|
+
* init progress All context for progress workflow
|
|
134
|
+
*
|
|
135
|
+
* Focus (Strategic Project Management):
|
|
136
|
+
* focus scan [--lean] Collect, classify, and prioritize work items
|
|
137
|
+
* focus plan [--budget N] Create capacity-budgeted execution batch
|
|
138
|
+
* [--mode bugfix|balanced|features|full]
|
|
139
|
+
* [--priority P0-P6] [--lean]
|
|
140
|
+
* focus sync [--check-only] Check documentation staleness
|
|
141
|
+
* focus exec [--dry-run] Load and classify batch for execution
|
|
142
|
+
* focus auto [--category CAT] Auto-runner: init, status, update, stop
|
|
143
|
+
* [--mode MODE] [--budget N] [--max-cycles N] [--total-budget N]
|
|
144
|
+
* [--status] [--stop] [--update] [--continue] [--dry-run]
|
|
145
|
+
* focus design Route to 10-phase investigation workflow
|
|
146
|
+
*
|
|
147
|
+
* Pre-Flight & Dashboard:
|
|
148
|
+
* preflight [phase|batch] Validate execution prerequisites
|
|
149
|
+
* dashboard Aggregated project status overview
|
|
150
|
+
* hud [--out f] [--open] [--stdout] Single-page HTML army + project dashboard
|
|
151
|
+
* report phase <N>|index|all Per-phase HTML report + project timeline index
|
|
152
|
+
*
|
|
153
|
+
* Session Learnings:
|
|
154
|
+
* learnings extract Extract patterns from session data
|
|
155
|
+
* learnings list List accumulated learnings
|
|
156
|
+
* learnings prune [--days N] [--id] Remove stale learnings
|
|
157
|
+
*
|
|
158
|
+
* Dependency Validation:
|
|
159
|
+
* deps validate Cross-reference roadmap vs reality
|
|
160
|
+
*
|
|
161
|
+
* Standards (Industry Standards Integration):
|
|
162
|
+
* standards list [--category <cat>] List available standards catalog
|
|
163
|
+
* standards select <id> Add a standard to the project
|
|
164
|
+
* standards remove <id> Remove a standard from the project
|
|
165
|
+
* standards status Report compliance status
|
|
166
|
+
* standards recommend Recommend standards based on project.md
|
|
167
|
+
* standards phase-track <phase> Show standards relevant to a phase
|
|
168
|
+
* standards tools [id] List external scanning tools for standards
|
|
169
|
+
*
|
|
170
|
+
* Circular Optimization Loop:
|
|
171
|
+
* optimize trace init Start a new trace session
|
|
172
|
+
* [--description "..."]
|
|
173
|
+
* optimize trace end Finalize trace session + write summary
|
|
174
|
+
* optimize trace current Show active session ID
|
|
175
|
+
* optimize trace list List all sessions
|
|
176
|
+
* optimize trace log Log a trace event to the active session
|
|
177
|
+
* --type <type> --description "..." [--agent a] [--category c] [--impact i]
|
|
178
|
+
* optimize learn [--session <id>] Analyze session, write analysis JSON
|
|
179
|
+
* optimize apply [--report <path>] Apply safe recommendations from report
|
|
180
|
+
* optimize list List optimization reports
|
|
181
|
+
* optimize stats Cumulative optimization statistics
|
|
182
|
+
*
|
|
183
|
+
* Self-Learn:
|
|
184
|
+
* learn [--session <id>] Alias for optimize learn + invoke pan-optimizer
|
|
185
|
+
*/
|
|
186
|
+
|
|
187
|
+
const fs = require('fs');
|
|
188
|
+
const path = require('path');
|
|
189
|
+
const { error, output, buildCachedContext } = require('./lib/core.cjs');
|
|
190
|
+
const state = require('./lib/state.cjs');
|
|
191
|
+
const phase = require('./lib/phase.cjs');
|
|
192
|
+
const roadmap = require('./lib/roadmap.cjs');
|
|
193
|
+
const verify = require('./lib/verify.cjs');
|
|
194
|
+
const config = require('./lib/config.cjs');
|
|
195
|
+
const template = require('./lib/template.cjs');
|
|
196
|
+
const milestone = require('./lib/milestone.cjs');
|
|
197
|
+
const commands = require('./lib/commands.cjs');
|
|
198
|
+
const init = require('./lib/init.cjs');
|
|
199
|
+
const frontmatter = require('./lib/frontmatter.cjs');
|
|
200
|
+
const contextBudget = require('./lib/context-budget.cjs');
|
|
201
|
+
const focus = require('./lib/focus.cjs');
|
|
202
|
+
const codebase = require('./lib/codebase.cjs');
|
|
203
|
+
const memory = require('./lib/memory.cjs');
|
|
204
|
+
const bus = require('./lib/bus.cjs');
|
|
205
|
+
const cost = require('./lib/cost.cjs');
|
|
206
|
+
const preview = require('./lib/preview.cjs');
|
|
207
|
+
const reviewDeep = require('./lib/review-deep.cjs');
|
|
208
|
+
const knowledge = require('./lib/knowledge.cjs');
|
|
209
|
+
const skillAlign = require('./lib/skill-align.cjs');
|
|
210
|
+
const hygiene = require('./lib/hygiene.cjs');
|
|
211
|
+
const whatif = require('./lib/whatif.cjs');
|
|
212
|
+
const bridge = require('./lib/bridge.cjs');
|
|
213
|
+
const optimize = require('./lib/optimize.cjs');
|
|
214
|
+
const git = require('./lib/git.cjs');
|
|
215
|
+
const distill = require('./lib/distill.cjs');
|
|
216
|
+
const experiment = require('./lib/experiment.cjs');
|
|
217
|
+
const runner = require('./lib/runner.cjs');
|
|
218
|
+
const docLint = require('./lib/doc-lint.cjs');
|
|
219
|
+
const learnLint = require('./lib/learn-lint.cjs');
|
|
220
|
+
const learnIndex = require('./lib/learn-index.cjs');
|
|
221
|
+
const links = require('./lib/links.cjs');
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Get the value following a flag in the args array.
|
|
225
|
+
* @param {string[]} args - CLI arguments
|
|
226
|
+
* @param {string} flag - Flag name (e.g., '--phase')
|
|
227
|
+
* @param {*} [defaultVal=null] - Default if flag missing or no value follows
|
|
228
|
+
* @returns {string|null} The value after the flag, or defaultVal
|
|
229
|
+
*/
|
|
230
|
+
function getArgValue(args, flag, defaultVal = null) {
|
|
231
|
+
const idx = args.indexOf(flag);
|
|
232
|
+
if (idx === -1 || idx + 1 >= args.length) return defaultVal;
|
|
233
|
+
return args[idx + 1];
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* Parse JSON string or call error() with a descriptive message.
|
|
238
|
+
* @param {string} raw - Raw JSON string
|
|
239
|
+
* @param {string} flagName - Flag name for error reporting
|
|
240
|
+
* @returns {*} Parsed JSON value
|
|
241
|
+
*/
|
|
242
|
+
function parseJsonOrError(raw, flagName) {
|
|
243
|
+
try { return JSON.parse(raw); } catch (e) { error(`Invalid JSON for ${flagName}: ${e.message}`); }
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
// ─── CLI Router ───────────────────────────────────────────────────────────────
|
|
247
|
+
|
|
248
|
+
async function main() {
|
|
249
|
+
const args = process.argv.slice(2);
|
|
250
|
+
|
|
251
|
+
// Optional cwd override for sandboxed subagents running outside project root.
|
|
252
|
+
let cwd = process.cwd();
|
|
253
|
+
const cwdEqArg = args.find(arg => arg.startsWith('--cwd='));
|
|
254
|
+
const cwdIdx = args.indexOf('--cwd');
|
|
255
|
+
if (cwdEqArg) {
|
|
256
|
+
const value = cwdEqArg.slice('--cwd='.length).trim();
|
|
257
|
+
if (!value) error('Missing value for --cwd');
|
|
258
|
+
args.splice(args.indexOf(cwdEqArg), 1);
|
|
259
|
+
cwd = path.resolve(value);
|
|
260
|
+
} else if (cwdIdx !== -1) {
|
|
261
|
+
const value = args[cwdIdx + 1];
|
|
262
|
+
if (!value || value.startsWith('--')) error('Missing value for --cwd');
|
|
263
|
+
args.splice(cwdIdx, 2);
|
|
264
|
+
cwd = path.resolve(value);
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
try {
|
|
268
|
+
if (!fs.statSync(cwd).isDirectory()) error(`Invalid --cwd: ${cwd} is not a directory`);
|
|
269
|
+
} catch {
|
|
270
|
+
error(`Invalid --cwd: ${cwd}`);
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
const rawIndex = args.indexOf('--raw');
|
|
274
|
+
const raw = rawIndex !== -1;
|
|
275
|
+
if (rawIndex !== -1) args.splice(rawIndex, 1);
|
|
276
|
+
|
|
277
|
+
const verboseIndex = args.indexOf('--verbose');
|
|
278
|
+
if (verboseIndex !== -1) {
|
|
279
|
+
args.splice(verboseIndex, 1);
|
|
280
|
+
process.env.PAN_VERBOSE = '1';
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
const command = args[0];
|
|
284
|
+
|
|
285
|
+
if (!command) {
|
|
286
|
+
error('Usage: pan-tools <command> [args] [--raw] [--cwd <path>]\nCommands: state, state-snapshot, resolve-model, find-phase, commit, verify-summary, verify, frontmatter, template, generate-slug, current-timestamp, list-todos, verify-path-exists, config-ensure-section, config-set, config-get, history-digest, phases, roadmap, requirements, phase, milestone, validate, progress, context-budget, todo, scaffold, init, phase-plan-index, summary-extract, rollback-snapshot, websearch, focus, preflight, dashboard, learnings, deps, standards');
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
switch (command) {
|
|
290
|
+
case 'state': {
|
|
291
|
+
const subcommand = args[1];
|
|
292
|
+
if (subcommand === 'json') {
|
|
293
|
+
state.cmdStateJson(cwd, raw);
|
|
294
|
+
} else if (subcommand === 'update') {
|
|
295
|
+
state.cmdStateUpdate(cwd, args[2], args[3]);
|
|
296
|
+
} else if (subcommand === 'get') {
|
|
297
|
+
state.cmdStateGet(cwd, args[2], raw);
|
|
298
|
+
} else if (subcommand === 'patch') {
|
|
299
|
+
const patches = {};
|
|
300
|
+
for (let i = 2; i < args.length; i += 2) {
|
|
301
|
+
const key = args[i].replace(/^--/, '');
|
|
302
|
+
const value = args[i + 1];
|
|
303
|
+
if (key && value !== undefined) {
|
|
304
|
+
patches[key] = value;
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
state.cmdStatePatch(cwd, patches, raw);
|
|
308
|
+
} else if (subcommand === 'advance-plan') {
|
|
309
|
+
state.cmdStateAdvancePlan(cwd, raw);
|
|
310
|
+
} else if (subcommand === 'record-metric') {
|
|
311
|
+
state.cmdStateRecordMetric(cwd, {
|
|
312
|
+
phase: getArgValue(args, '--phase'),
|
|
313
|
+
plan: getArgValue(args, '--plan'),
|
|
314
|
+
duration: getArgValue(args, '--duration'),
|
|
315
|
+
tasks: getArgValue(args, '--tasks'),
|
|
316
|
+
files: getArgValue(args, '--files'),
|
|
317
|
+
}, raw);
|
|
318
|
+
} else if (subcommand === 'update-progress') {
|
|
319
|
+
state.cmdStateUpdateProgress(cwd, raw);
|
|
320
|
+
} else if (subcommand === 'add-decision') {
|
|
321
|
+
state.cmdStateAddDecision(cwd, {
|
|
322
|
+
phase: getArgValue(args, '--phase'),
|
|
323
|
+
summary: getArgValue(args, '--summary'),
|
|
324
|
+
summary_file: getArgValue(args, '--summary-file'),
|
|
325
|
+
rationale: getArgValue(args, '--rationale', ''),
|
|
326
|
+
rationale_file: getArgValue(args, '--rationale-file'),
|
|
327
|
+
}, raw);
|
|
328
|
+
} else if (subcommand === 'add-blocker') {
|
|
329
|
+
state.cmdStateAddBlocker(cwd, {
|
|
330
|
+
text: getArgValue(args, '--text'),
|
|
331
|
+
text_file: getArgValue(args, '--text-file'),
|
|
332
|
+
}, raw);
|
|
333
|
+
} else if (subcommand === 'resolve-blocker') {
|
|
334
|
+
state.cmdStateResolveBlocker(cwd, getArgValue(args, '--text'), raw);
|
|
335
|
+
} else if (subcommand === 'record-session') {
|
|
336
|
+
state.cmdStateRecordSession(cwd, {
|
|
337
|
+
stopped_at: getArgValue(args, '--stopped-at'),
|
|
338
|
+
resume_file: getArgValue(args, '--resume-file', 'None'),
|
|
339
|
+
}, raw);
|
|
340
|
+
} else if (subcommand === 'load' || !subcommand) {
|
|
341
|
+
state.cmdStateLoad(cwd, raw);
|
|
342
|
+
} else {
|
|
343
|
+
error(`Unknown state subcommand: ${subcommand}. Available: json, update, get, patch, advance-plan, record-metric, update-progress, add-decision, add-blocker, resolve-blocker, record-session, load`);
|
|
344
|
+
}
|
|
345
|
+
break;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
case 'resolve-model': {
|
|
349
|
+
const metadataIdx = args.indexOf('--metadata');
|
|
350
|
+
const metadataJson = metadataIdx !== -1 ? args[metadataIdx + 1] : undefined;
|
|
351
|
+
commands.cmdResolveModel(cwd, args[1], raw, metadataJson);
|
|
352
|
+
break;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
case 'estimate-cost': {
|
|
356
|
+
commands.cmdEstimateCost(cwd, raw);
|
|
357
|
+
break;
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
case 'find-phase': {
|
|
361
|
+
if (!args[1]) error('find-phase requires a phase number');
|
|
362
|
+
phase.cmdFindPhase(cwd, args[1], raw);
|
|
363
|
+
break;
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
case 'git': {
|
|
367
|
+
const subcommand = args[1];
|
|
368
|
+
if (!subcommand) { error('git subcommand required. Available: commit, branch, push, status, log, stash, diff, rollback, tag, sync'); }
|
|
369
|
+
git.cmdGit(cwd, subcommand, args.slice(1), raw);
|
|
370
|
+
break;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
case 'distill': {
|
|
374
|
+
const subcommand = args[1];
|
|
375
|
+
if (!subcommand) { error('distill subcommand required. Available: scan, analyze, report'); }
|
|
376
|
+
distill.cmdDistill(cwd, subcommand, args.slice(1), raw);
|
|
377
|
+
break;
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
case 'experiment': {
|
|
381
|
+
const subcommand = args[1];
|
|
382
|
+
if (!subcommand) { error('experiment subcommand required. Available: new, list, manifest, run, status, stop, harvest, prune'); }
|
|
383
|
+
const root = getArgValue(args, '--root');
|
|
384
|
+
|
|
385
|
+
if (subcommand === 'new') {
|
|
386
|
+
const slug = args[2];
|
|
387
|
+
if (!slug || slug.startsWith('--')) { error('experiment new <slug> required'); }
|
|
388
|
+
const ideaPath = getArgValue(args, '--idea');
|
|
389
|
+
if (!ideaPath) { error('experiment new requires --idea <path>'); }
|
|
390
|
+
const runtime = getArgValue(args, '--runtime', 'claude');
|
|
391
|
+
const budgetStr = getArgValue(args, '--budget');
|
|
392
|
+
const budget = budgetStr != null ? parseInt(budgetStr, 10) : null;
|
|
393
|
+
const skipInstaller = args.includes('--skip-installer');
|
|
394
|
+
const result = experiment.newExperiment(slug, { ideaPath, runtime, root, budget, skipInstaller });
|
|
395
|
+
output(result, raw);
|
|
396
|
+
} else if (subcommand === 'list') {
|
|
397
|
+
const includeArchived = args.includes('--include-archived');
|
|
398
|
+
const result = experiment.listExperiments({ root, includeArchived });
|
|
399
|
+
output(result, raw);
|
|
400
|
+
} else if (subcommand === 'manifest') {
|
|
401
|
+
const slug = args[2];
|
|
402
|
+
if (!slug || slug.startsWith('--')) { error('experiment manifest <slug> required'); }
|
|
403
|
+
const result = experiment.getExperimentManifest(slug, { root });
|
|
404
|
+
output(result, raw);
|
|
405
|
+
} else if (subcommand === 'run') {
|
|
406
|
+
const slug = args[2];
|
|
407
|
+
if (!slug || slug.startsWith('--')) { error('experiment run <slug> required'); }
|
|
408
|
+
const prompt = getArgValue(args, '--prompt');
|
|
409
|
+
const timeoutStr = getArgValue(args, '--timeout');
|
|
410
|
+
const timeoutMs = timeoutStr ? parseInt(timeoutStr, 10) * 1000 : undefined;
|
|
411
|
+
const runtimeOverride = getArgValue(args, '--runtime-override');
|
|
412
|
+
const runOpts = { root };
|
|
413
|
+
if (prompt) runOpts.prompt = prompt;
|
|
414
|
+
if (timeoutMs) runOpts.timeoutMs = timeoutMs;
|
|
415
|
+
if (runtimeOverride) {
|
|
416
|
+
// For tests/dev: override="bin:arg1,arg2" — split on first colon, args by comma
|
|
417
|
+
const [bin, argsCsv] = runtimeOverride.split(':', 2);
|
|
418
|
+
runOpts.runtimeOverride = {
|
|
419
|
+
bin,
|
|
420
|
+
buildArgs: () => (argsCsv ? argsCsv.split(',') : []),
|
|
421
|
+
};
|
|
422
|
+
}
|
|
423
|
+
const result = runner.runExperiment(slug, runOpts);
|
|
424
|
+
output(result, raw);
|
|
425
|
+
} else if (subcommand === 'status') {
|
|
426
|
+
const slug = args[2];
|
|
427
|
+
if (!slug || slug.startsWith('--')) { error('experiment status <slug> required'); }
|
|
428
|
+
const result = runner.tailExperimentState(slug, { root });
|
|
429
|
+
output(result, raw);
|
|
430
|
+
} else if (subcommand === 'stop') {
|
|
431
|
+
const slug = args[2];
|
|
432
|
+
if (!slug || slug.startsWith('--')) { error('experiment stop <slug> required'); }
|
|
433
|
+
const result = runner.stopExperiment(slug, { root });
|
|
434
|
+
output(result, raw);
|
|
435
|
+
} else if (subcommand === 'harvest') {
|
|
436
|
+
const slug = args[2];
|
|
437
|
+
if (!slug || slug.startsWith('--')) { error('experiment harvest <slug> required'); }
|
|
438
|
+
const sourceRoot = getArgValue(args, '--source-root');
|
|
439
|
+
const force = args.includes('--force');
|
|
440
|
+
const harvestOpts = { root, force };
|
|
441
|
+
if (sourceRoot) harvestOpts.sourceRoot = sourceRoot;
|
|
442
|
+
const result = experiment.harvestExperiment(slug, harvestOpts);
|
|
443
|
+
output(result, raw);
|
|
444
|
+
} else if (subcommand === 'prune') {
|
|
445
|
+
const slug = args[2];
|
|
446
|
+
if (!slug || slug.startsWith('--')) { error('experiment prune <slug> required'); }
|
|
447
|
+
const hard = args.includes('--hard');
|
|
448
|
+
const result = experiment.pruneExperiment(slug, { root, hard });
|
|
449
|
+
output(result, raw);
|
|
450
|
+
} else {
|
|
451
|
+
error(`unknown experiment subcommand: ${subcommand}. Available: new, list, manifest, run, status, stop, harvest, prune`);
|
|
452
|
+
}
|
|
453
|
+
break;
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
case 'commit': {
|
|
457
|
+
const amend = args.includes('--amend');
|
|
458
|
+
const force = args.includes('--force');
|
|
459
|
+
const failOnError = args.includes('--fail-on-error');
|
|
460
|
+
const message = args[1] && !args[1].startsWith('--') ? args[1] : null;
|
|
461
|
+
// Parse --files flag (collect args after --files, stopping at other flags)
|
|
462
|
+
const filesIndex = args.indexOf('--files');
|
|
463
|
+
const files = filesIndex !== -1 ? args.slice(filesIndex + 1).filter(a => !a.startsWith('--')) : [];
|
|
464
|
+
const commitType = getArgValue(args, '--type');
|
|
465
|
+
commands.cmdCommit(cwd, message, files, raw, amend, { type: commitType, force, failOnError });
|
|
466
|
+
break;
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
case 'verify-summary': {
|
|
470
|
+
const summaryPath = args[1];
|
|
471
|
+
const checkCount = Math.max(1, Math.min(parseInt(getArgValue(args, '--check-count', '2'), 10) || 2, 20));
|
|
472
|
+
verify.cmdVerifySummary(cwd, summaryPath, checkCount, raw);
|
|
473
|
+
break;
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
case 'template': {
|
|
477
|
+
const subcommand = args[1];
|
|
478
|
+
if (subcommand === 'select') {
|
|
479
|
+
template.cmdTemplateSelect(cwd, args[2], raw);
|
|
480
|
+
} else if (subcommand === 'fill') {
|
|
481
|
+
const templateType = args[2];
|
|
482
|
+
const fieldsRaw = getArgValue(args, '--fields');
|
|
483
|
+
template.cmdTemplateFill(cwd, templateType, {
|
|
484
|
+
phase: getArgValue(args, '--phase'),
|
|
485
|
+
plan: getArgValue(args, '--plan'),
|
|
486
|
+
name: getArgValue(args, '--name'),
|
|
487
|
+
type: getArgValue(args, '--type', 'execute'),
|
|
488
|
+
wave: getArgValue(args, '--wave', '1'),
|
|
489
|
+
fields: fieldsRaw ? parseJsonOrError(fieldsRaw, '--fields') : {},
|
|
490
|
+
}, raw);
|
|
491
|
+
} else {
|
|
492
|
+
error('Unknown template subcommand. Available: select, fill');
|
|
493
|
+
}
|
|
494
|
+
break;
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
case 'frontmatter': {
|
|
498
|
+
const subcommand = args[1];
|
|
499
|
+
const file = args[2];
|
|
500
|
+
if (subcommand === 'get') {
|
|
501
|
+
frontmatter.cmdFrontmatterGet(cwd, file, getArgValue(args, '--field'), raw);
|
|
502
|
+
} else if (subcommand === 'set') {
|
|
503
|
+
frontmatter.cmdFrontmatterSet(cwd, file, getArgValue(args, '--field'), getArgValue(args, '--value') ?? undefined, raw);
|
|
504
|
+
} else if (subcommand === 'merge') {
|
|
505
|
+
frontmatter.cmdFrontmatterMerge(cwd, file, getArgValue(args, '--data'), raw);
|
|
506
|
+
} else if (subcommand === 'validate') {
|
|
507
|
+
frontmatter.cmdFrontmatterValidate(cwd, file, getArgValue(args, '--schema'), raw);
|
|
508
|
+
} else {
|
|
509
|
+
error('Unknown frontmatter subcommand. Available: get, set, merge, validate');
|
|
510
|
+
}
|
|
511
|
+
break;
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
case 'verify': {
|
|
515
|
+
const subcommand = args[1];
|
|
516
|
+
if (subcommand === 'plan-structure') {
|
|
517
|
+
verify.cmdVerifyPlanStructure(cwd, args[2], raw);
|
|
518
|
+
} else if (subcommand === 'phase-completeness') {
|
|
519
|
+
verify.cmdVerifyPhaseCompleteness(cwd, args[2], raw);
|
|
520
|
+
} else if (subcommand === 'references') {
|
|
521
|
+
verify.cmdVerifyReferences(cwd, args[2], raw);
|
|
522
|
+
} else if (subcommand === 'commits') {
|
|
523
|
+
verify.cmdVerifyCommits(cwd, args.slice(2), raw);
|
|
524
|
+
} else if (subcommand === 'artifacts') {
|
|
525
|
+
verify.cmdVerifyArtifacts(cwd, args[2], raw);
|
|
526
|
+
} else if (subcommand === 'key-links') {
|
|
527
|
+
verify.cmdVerifyKeyLinks(cwd, args[2], raw);
|
|
528
|
+
} else if (subcommand === 'reconcile') {
|
|
529
|
+
verify.cmdVerifyReconcile(cwd, args[2], raw);
|
|
530
|
+
} else if (subcommand === 'stubs') {
|
|
531
|
+
verify.cmdVerifyStubs(cwd, { gate: args.includes('--gate') }, raw);
|
|
532
|
+
} else {
|
|
533
|
+
error('Unknown verify subcommand. Available: plan-structure, phase-completeness, references, commits, artifacts, key-links');
|
|
534
|
+
}
|
|
535
|
+
break;
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
case 'generate-slug': {
|
|
539
|
+
commands.cmdGenerateSlug(args[1], raw);
|
|
540
|
+
break;
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
case 'current-timestamp': {
|
|
544
|
+
commands.cmdCurrentTimestamp(args[1] || 'full', raw);
|
|
545
|
+
break;
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
case 'list-todos': {
|
|
549
|
+
commands.cmdListTodos(cwd, args[1], raw);
|
|
550
|
+
break;
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
case 'verify-path-exists': {
|
|
554
|
+
commands.cmdVerifyPathExists(cwd, args[1], raw);
|
|
555
|
+
break;
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
case 'config-ensure-section': {
|
|
559
|
+
config.cmdConfigEnsureSection(cwd, raw);
|
|
560
|
+
break;
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
case 'config-set': {
|
|
564
|
+
config.cmdConfigSet(cwd, args[1], args[2], raw);
|
|
565
|
+
break;
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
case 'config-get': {
|
|
569
|
+
config.cmdConfigGet(cwd, args[1], raw);
|
|
570
|
+
break;
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
case 'history-digest': {
|
|
574
|
+
commands.cmdHistoryDigest(cwd, raw);
|
|
575
|
+
break;
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
case 'phases': {
|
|
579
|
+
const subcommand = args[1];
|
|
580
|
+
if (subcommand === 'list') {
|
|
581
|
+
const options = {
|
|
582
|
+
type: getArgValue(args, '--type'),
|
|
583
|
+
phase: getArgValue(args, '--phase'),
|
|
584
|
+
includeArchived: args.includes('--include-archived'),
|
|
585
|
+
};
|
|
586
|
+
phase.cmdPhasesList(cwd, options, raw);
|
|
587
|
+
} else {
|
|
588
|
+
error('Unknown phases subcommand. Available: list');
|
|
589
|
+
}
|
|
590
|
+
break;
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
case 'roadmap': {
|
|
594
|
+
const subcommand = args[1];
|
|
595
|
+
if (subcommand === 'get-phase') {
|
|
596
|
+
if (!args[2]) error('roadmap get-phase requires a phase number');
|
|
597
|
+
roadmap.cmdRoadmapGetPhase(cwd, args[2], raw);
|
|
598
|
+
} else if (subcommand === 'analyze') {
|
|
599
|
+
roadmap.cmdRoadmapAnalyze(cwd, raw);
|
|
600
|
+
} else if (subcommand === 'update-plan-progress') {
|
|
601
|
+
if (!args[2]) error('roadmap update-plan-progress requires a phase number');
|
|
602
|
+
roadmap.cmdRoadmapUpdatePlanProgress(cwd, args[2], raw);
|
|
603
|
+
} else {
|
|
604
|
+
error('Unknown roadmap subcommand. Available: get-phase, analyze, update-plan-progress');
|
|
605
|
+
}
|
|
606
|
+
break;
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
case 'requirements': {
|
|
610
|
+
const subcommand = args[1];
|
|
611
|
+
if (subcommand === 'mark-complete') {
|
|
612
|
+
milestone.cmdRequirementsMarkComplete(cwd, args.slice(2), raw);
|
|
613
|
+
} else {
|
|
614
|
+
error('Unknown requirements subcommand. Available: mark-complete');
|
|
615
|
+
}
|
|
616
|
+
break;
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
case 'phase': {
|
|
620
|
+
const subcommand = args[1];
|
|
621
|
+
if (subcommand === 'next-decimal') {
|
|
622
|
+
if (!args[2]) error('phase next-decimal requires a base phase number');
|
|
623
|
+
phase.cmdPhaseNextDecimal(cwd, args[2], raw);
|
|
624
|
+
} else if (subcommand === 'add') {
|
|
625
|
+
phase.cmdPhaseAdd(cwd, args.slice(2).join(' '), raw);
|
|
626
|
+
} else if (subcommand === 'insert') {
|
|
627
|
+
if (!args[2]) error('phase insert requires a phase number');
|
|
628
|
+
phase.cmdPhaseInsert(cwd, args[2], args.slice(3).join(' '), raw);
|
|
629
|
+
} else if (subcommand === 'remove') {
|
|
630
|
+
if (!args[2]) error('phase remove requires a phase number');
|
|
631
|
+
const forceFlag = args.includes('--force');
|
|
632
|
+
phase.cmdPhaseRemove(cwd, args[2], { force: forceFlag }, raw);
|
|
633
|
+
} else if (subcommand === 'complete') {
|
|
634
|
+
if (!args[2]) error('phase complete requires a phase number');
|
|
635
|
+
const noCommit = args.includes('--no-commit');
|
|
636
|
+
phase.cmdPhaseComplete(cwd, args[2], raw, { noCommit });
|
|
637
|
+
} else {
|
|
638
|
+
error('Unknown phase subcommand. Available: next-decimal, add, insert, remove, complete');
|
|
639
|
+
}
|
|
640
|
+
break;
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
case 'milestone': {
|
|
644
|
+
const subcommand = args[1];
|
|
645
|
+
if (subcommand === 'complete') {
|
|
646
|
+
const nameIndex = args.indexOf('--name');
|
|
647
|
+
const archivePhases = args.includes('--archive-phases');
|
|
648
|
+
// Collect --name value (everything after --name until next flag or end)
|
|
649
|
+
let milestoneName = null;
|
|
650
|
+
if (nameIndex !== -1) {
|
|
651
|
+
const nameArgs = [];
|
|
652
|
+
for (let i = nameIndex + 1; i < args.length; i++) {
|
|
653
|
+
if (args[i].startsWith('--')) break;
|
|
654
|
+
nameArgs.push(args[i]);
|
|
655
|
+
}
|
|
656
|
+
milestoneName = nameArgs.join(' ') || null;
|
|
657
|
+
}
|
|
658
|
+
const noCommitMilestone = args.includes('--no-commit');
|
|
659
|
+
milestone.cmdMilestoneComplete(cwd, args[2], { name: milestoneName, archivePhases, noCommit: noCommitMilestone }, raw);
|
|
660
|
+
} else {
|
|
661
|
+
error('Unknown milestone subcommand. Available: complete');
|
|
662
|
+
}
|
|
663
|
+
break;
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
case 'validate': {
|
|
667
|
+
const subcommand = args[1];
|
|
668
|
+
if (subcommand === 'consistency') {
|
|
669
|
+
verify.cmdValidateConsistency(cwd, raw);
|
|
670
|
+
} else if (subcommand === 'health') {
|
|
671
|
+
const repairFlag = args.includes('--repair');
|
|
672
|
+
const standardsFlag = args.includes('--standards');
|
|
673
|
+
const fullFlag = args.includes('--full');
|
|
674
|
+
const driftFlag = args.includes('--drift');
|
|
675
|
+
const linksFlag = args.includes('--links');
|
|
676
|
+
verify.cmdValidateHealth(cwd, { repair: repairFlag, standards: standardsFlag, full: fullFlag, drift: driftFlag, links: linksFlag }, raw);
|
|
677
|
+
} else if (subcommand === 'deployment') {
|
|
678
|
+
verify.cmdValidateDeployment(cwd, raw);
|
|
679
|
+
} else {
|
|
680
|
+
error('Unknown validate subcommand. Available: consistency, health, deployment');
|
|
681
|
+
}
|
|
682
|
+
break;
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
case 'progress': {
|
|
686
|
+
const subcommand = args[1] || 'json';
|
|
687
|
+
commands.cmdProgressRender(cwd, subcommand, raw);
|
|
688
|
+
break;
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
case 'context-budget': {
|
|
692
|
+
contextBudget.cmdContextBudget(cwd, raw);
|
|
693
|
+
break;
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
case 'todo': {
|
|
697
|
+
const subcommand = args[1];
|
|
698
|
+
if (subcommand === 'complete') {
|
|
699
|
+
commands.cmdTodoComplete(cwd, args[2], raw);
|
|
700
|
+
} else {
|
|
701
|
+
error('Unknown todo subcommand. Available: complete');
|
|
702
|
+
}
|
|
703
|
+
break;
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
case 'scaffold': {
|
|
707
|
+
const scaffoldType = args[1];
|
|
708
|
+
const nameIndex = args.indexOf('--name');
|
|
709
|
+
const scaffoldOptions = {
|
|
710
|
+
phase: getArgValue(args, '--phase'),
|
|
711
|
+
name: nameIndex !== -1 ? args.slice(nameIndex + 1).filter(a => !a.startsWith('--')).join(' ') : null,
|
|
712
|
+
};
|
|
713
|
+
commands.cmdScaffold(cwd, scaffoldType, scaffoldOptions, raw);
|
|
714
|
+
break;
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
case 'init': {
|
|
718
|
+
const workflow = args[1];
|
|
719
|
+
switch (workflow) {
|
|
720
|
+
case 'execute-phase': {
|
|
721
|
+
const dryRun = args.includes('--dry-run');
|
|
722
|
+
init.cmdInitExecutePhase(cwd, args[2], raw, { dry_run: dryRun, budget: getArgValue(args, '--budget') ?? undefined });
|
|
723
|
+
break;
|
|
724
|
+
}
|
|
725
|
+
case 'plan-phase':
|
|
726
|
+
init.cmdInitPlanPhase(cwd, args[2], raw);
|
|
727
|
+
break;
|
|
728
|
+
case 'new-project':
|
|
729
|
+
init.cmdInitNewProject(cwd, raw);
|
|
730
|
+
break;
|
|
731
|
+
case 'new-milestone':
|
|
732
|
+
init.cmdInitNewMilestone(cwd, raw);
|
|
733
|
+
break;
|
|
734
|
+
case 'quick':
|
|
735
|
+
init.cmdInitQuick(cwd, args.slice(2).join(' '), raw);
|
|
736
|
+
break;
|
|
737
|
+
case 'resume':
|
|
738
|
+
init.cmdInitResume(cwd, raw);
|
|
739
|
+
break;
|
|
740
|
+
case 'verify-work':
|
|
741
|
+
init.cmdInitVerifyWork(cwd, args[2], raw);
|
|
742
|
+
break;
|
|
743
|
+
case 'phase-op':
|
|
744
|
+
init.cmdInitPhaseOp(cwd, args[2], raw);
|
|
745
|
+
break;
|
|
746
|
+
case 'todos':
|
|
747
|
+
init.cmdInitTodos(cwd, args[2], raw);
|
|
748
|
+
break;
|
|
749
|
+
case 'milestone-op':
|
|
750
|
+
init.cmdInitMilestoneOp(cwd, raw);
|
|
751
|
+
break;
|
|
752
|
+
case 'map-codebase':
|
|
753
|
+
init.cmdInitMapCodebase(cwd, raw);
|
|
754
|
+
break;
|
|
755
|
+
case 'progress':
|
|
756
|
+
init.cmdInitProgress(cwd, raw);
|
|
757
|
+
break;
|
|
758
|
+
default:
|
|
759
|
+
error(`Unknown init workflow: ${workflow}\nAvailable: execute-phase, plan-phase, new-project, new-milestone, quick, resume, verify-work, phase-op, todos, milestone-op, map-codebase, progress`);
|
|
760
|
+
}
|
|
761
|
+
break;
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
case 'phase-plan-index': {
|
|
765
|
+
phase.cmdPhasePlanIndex(cwd, args[1], raw);
|
|
766
|
+
break;
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
case 'state-snapshot': {
|
|
770
|
+
state.cmdStateSnapshot(cwd, raw);
|
|
771
|
+
break;
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
case 'summary-extract': {
|
|
775
|
+
const summaryPath = args[1];
|
|
776
|
+
const fieldsIndex = args.indexOf('--fields');
|
|
777
|
+
const fields = fieldsIndex !== -1 ? args.slice(fieldsIndex + 1).filter(a => !a.startsWith('--')).flatMap(a => a.split(',')) : null;
|
|
778
|
+
commands.cmdSummaryExtract(cwd, summaryPath, fields, raw);
|
|
779
|
+
break;
|
|
780
|
+
}
|
|
781
|
+
|
|
782
|
+
case 'rollback-snapshot': {
|
|
783
|
+
commands.cmdRollbackSnapshot(cwd, args[1], raw);
|
|
784
|
+
break;
|
|
785
|
+
}
|
|
786
|
+
|
|
787
|
+
case 'batch-commit': {
|
|
788
|
+
const itemsJson = args[1];
|
|
789
|
+
let items = [];
|
|
790
|
+
try { items = JSON.parse(itemsJson); } catch { /* empty */ }
|
|
791
|
+
commands.cmdBatchCommit(cwd, items, raw);
|
|
792
|
+
break;
|
|
793
|
+
}
|
|
794
|
+
|
|
795
|
+
case 'websearch': {
|
|
796
|
+
const query = args[1];
|
|
797
|
+
await commands.cmdWebsearch(query, {
|
|
798
|
+
limit: parseInt(getArgValue(args, '--limit', '10'), 10),
|
|
799
|
+
freshness: getArgValue(args, '--freshness'),
|
|
800
|
+
}, raw);
|
|
801
|
+
break;
|
|
802
|
+
}
|
|
803
|
+
|
|
804
|
+
case 'focus': {
|
|
805
|
+
const subcommand = args[1];
|
|
806
|
+
if (subcommand === 'scan') {
|
|
807
|
+
focus.cmdFocusScan(cwd, raw, ...args.slice(2));
|
|
808
|
+
} else if (subcommand === 'plan') {
|
|
809
|
+
focus.cmdFocusPlan(cwd, raw, ...args.slice(2));
|
|
810
|
+
} else if (subcommand === 'sync') {
|
|
811
|
+
focus.cmdFocusSync(cwd, raw, ...args.slice(2));
|
|
812
|
+
} else if (subcommand === 'exec') {
|
|
813
|
+
focus.cmdFocusExec(cwd, raw, ...args.slice(2));
|
|
814
|
+
} else if (subcommand === 'auto') {
|
|
815
|
+
focus.cmdFocusAuto(cwd, raw, ...args.slice(2));
|
|
816
|
+
} else if (subcommand === 'design') {
|
|
817
|
+
// design is a workflow-only command (no core function)
|
|
818
|
+
// The AI reads commands/pan/focus-design.md directly
|
|
819
|
+
output({ command: 'focus-design', type: 'workflow', message: 'Use /pan:focus-design to invoke the 10-phase investigation pipeline' }, raw);
|
|
820
|
+
} else if (subcommand === 'classify-stages') {
|
|
821
|
+
const useStdin = args.includes('--stdin');
|
|
822
|
+
let items;
|
|
823
|
+
if (useStdin) {
|
|
824
|
+
try {
|
|
825
|
+
items = JSON.parse(fs.readFileSync(0, 'utf-8'));
|
|
826
|
+
} catch (e) {
|
|
827
|
+
error(`Failed to parse stdin JSON: ${e.message}`);
|
|
828
|
+
}
|
|
829
|
+
} else {
|
|
830
|
+
const batch = focus.readLatestBatch(cwd);
|
|
831
|
+
if (!batch) {
|
|
832
|
+
output({ error: 'No batch file found. Run focus plan first.' }, raw);
|
|
833
|
+
break;
|
|
834
|
+
}
|
|
835
|
+
items = batch.batch || [];
|
|
836
|
+
}
|
|
837
|
+
output(focus.classifyStageDependencies(items), raw);
|
|
838
|
+
} else if (subcommand === 'reflection') {
|
|
839
|
+
let payload;
|
|
840
|
+
try {
|
|
841
|
+
payload = JSON.parse(fs.readFileSync(0, 'utf-8'));
|
|
842
|
+
} catch (e) {
|
|
843
|
+
error(`Failed to parse stdin JSON for focus reflection: ${e.message}`);
|
|
844
|
+
}
|
|
845
|
+
output(focus.determineContinuation(
|
|
846
|
+
payload.run || {},
|
|
847
|
+
payload.cycle || {},
|
|
848
|
+
payload.batch || [],
|
|
849
|
+
{ tier: payload.tier }
|
|
850
|
+
), raw);
|
|
851
|
+
} else {
|
|
852
|
+
error('Unknown focus subcommand. Available: scan, plan, sync, exec, auto, design, classify-stages, reflection');
|
|
853
|
+
}
|
|
854
|
+
break;
|
|
855
|
+
}
|
|
856
|
+
|
|
857
|
+
case 'preflight': {
|
|
858
|
+
verify.cmdPreflight(cwd, args[1] || null, raw);
|
|
859
|
+
break;
|
|
860
|
+
}
|
|
861
|
+
|
|
862
|
+
case 'dashboard': {
|
|
863
|
+
state.cmdDashboard(cwd, raw);
|
|
864
|
+
break;
|
|
865
|
+
}
|
|
866
|
+
|
|
867
|
+
case 'hud': {
|
|
868
|
+
const hud = require('./lib/hud.cjs');
|
|
869
|
+
hud.cmdHud(cwd, {
|
|
870
|
+
out: getArgValue(args, '--out'),
|
|
871
|
+
open: args.includes('--open'),
|
|
872
|
+
stdout: args.includes('--stdout'),
|
|
873
|
+
}, raw);
|
|
874
|
+
break;
|
|
875
|
+
}
|
|
876
|
+
|
|
877
|
+
case 'report': {
|
|
878
|
+
const phaseReport = require('./lib/phase-report.cjs');
|
|
879
|
+
const subcommand = args[1];
|
|
880
|
+
if (subcommand === 'phase') {
|
|
881
|
+
phaseReport.cmdReport(cwd, {
|
|
882
|
+
action: 'phase', phase: args[2],
|
|
883
|
+
out: getArgValue(args, '--out'),
|
|
884
|
+
open: args.includes('--open'),
|
|
885
|
+
stdout: args.includes('--stdout'),
|
|
886
|
+
}, raw);
|
|
887
|
+
} else if (subcommand === 'index') {
|
|
888
|
+
phaseReport.cmdReport(cwd, {
|
|
889
|
+
action: 'index',
|
|
890
|
+
out: getArgValue(args, '--out'),
|
|
891
|
+
open: args.includes('--open'),
|
|
892
|
+
stdout: args.includes('--stdout'),
|
|
893
|
+
}, raw);
|
|
894
|
+
} else if (subcommand === 'all') {
|
|
895
|
+
phaseReport.cmdReport(cwd, { action: 'all', open: args.includes('--open') }, raw);
|
|
896
|
+
} else {
|
|
897
|
+
error('Unknown report subcommand. Available: phase <N>, index, all');
|
|
898
|
+
}
|
|
899
|
+
break;
|
|
900
|
+
}
|
|
901
|
+
|
|
902
|
+
case 'learnings': {
|
|
903
|
+
const subcommand = args[1];
|
|
904
|
+
if (subcommand === 'extract') {
|
|
905
|
+
commands.cmdLearningsExtract(cwd, raw);
|
|
906
|
+
} else if (subcommand === 'list') {
|
|
907
|
+
commands.cmdLearningsList(cwd, raw);
|
|
908
|
+
} else if (subcommand === 'prune') {
|
|
909
|
+
const daysRaw = getArgValue(args, '--days');
|
|
910
|
+
commands.cmdLearningsPrune(cwd, {
|
|
911
|
+
days: daysRaw !== null ? parseInt(daysRaw, 10) : null,
|
|
912
|
+
id: getArgValue(args, '--id'),
|
|
913
|
+
}, raw);
|
|
914
|
+
} else {
|
|
915
|
+
error('Unknown learnings subcommand. Available: extract, list, prune');
|
|
916
|
+
}
|
|
917
|
+
break;
|
|
918
|
+
}
|
|
919
|
+
|
|
920
|
+
case 'deps': {
|
|
921
|
+
const subcommand = args[1];
|
|
922
|
+
if (subcommand === 'validate') {
|
|
923
|
+
verify.cmdDepsValidate(cwd, raw);
|
|
924
|
+
} else {
|
|
925
|
+
error('Unknown deps subcommand. Available: validate');
|
|
926
|
+
}
|
|
927
|
+
break;
|
|
928
|
+
}
|
|
929
|
+
|
|
930
|
+
case 'drift-check': {
|
|
931
|
+
verify.cmdDriftCheck(cwd, raw, args);
|
|
932
|
+
break;
|
|
933
|
+
}
|
|
934
|
+
|
|
935
|
+
case 'memory': {
|
|
936
|
+
const subcommand = args[1];
|
|
937
|
+
if (subcommand === 'read') {
|
|
938
|
+
memory.cmdMemoryRead(cwd, args[2], raw);
|
|
939
|
+
} else if (subcommand === 'append') {
|
|
940
|
+
memory.cmdMemoryAppend(cwd, args[2], args.slice(3).join(' '), raw);
|
|
941
|
+
} else if (subcommand === 'list') {
|
|
942
|
+
memory.cmdMemoryList(cwd, raw);
|
|
943
|
+
} else if (subcommand === 'compact') {
|
|
944
|
+
memory.cmdMemoryCompact(cwd, args[2], args[3], raw);
|
|
945
|
+
} else if (subcommand === 'select') {
|
|
946
|
+
memory.cmdMemorySelect(cwd, args[2], {
|
|
947
|
+
cue: getArgValue(args, '--cue'),
|
|
948
|
+
tokenBudget: getArgValue(args, '--token-budget'),
|
|
949
|
+
recencyFloor: getArgValue(args, '--recency-floor'),
|
|
950
|
+
}, raw);
|
|
951
|
+
} else if (subcommand === 'budget') {
|
|
952
|
+
memory.cmdMemoryBudget(cwd, raw);
|
|
953
|
+
} else {
|
|
954
|
+
error('Unknown memory subcommand. Available: read, append, list, compact, select, budget');
|
|
955
|
+
}
|
|
956
|
+
break;
|
|
957
|
+
}
|
|
958
|
+
|
|
959
|
+
case 'bridge': {
|
|
960
|
+
const subcommand = args[1];
|
|
961
|
+
if (subcommand === 'list') {
|
|
962
|
+
bridge.cmdBridgeList(cwd, raw);
|
|
963
|
+
} else if (subcommand === 'recommend') {
|
|
964
|
+
bridge.cmdBridgeRecommend(cwd, args[2], {
|
|
965
|
+
max_recommendations: Number(getArgValue(args, '--max') || 10),
|
|
966
|
+
min_score: Number(getArgValue(args, '--min-score') || 1),
|
|
967
|
+
}, raw);
|
|
968
|
+
} else if (subcommand === 'cache') {
|
|
969
|
+
bridge.cmdBridgeCache(cwd, getArgValue(args, '--servers'), getArgValue(args, '--runtime'), raw);
|
|
970
|
+
} else {
|
|
971
|
+
error('Unknown bridge subcommand. Available: list, recommend, cache');
|
|
972
|
+
}
|
|
973
|
+
break;
|
|
974
|
+
}
|
|
975
|
+
|
|
976
|
+
case 'whatif': {
|
|
977
|
+
const subcommand = args[1];
|
|
978
|
+
if (subcommand === 'prepare') {
|
|
979
|
+
const phaseNum = args[2];
|
|
980
|
+
const scenario = args.slice(3).filter(a => !a.startsWith('--')).join(' ');
|
|
981
|
+
whatif.cmdWhatifPrepare(cwd, phaseNum, scenario, raw);
|
|
982
|
+
} else if (subcommand === 'report') {
|
|
983
|
+
const phaseNum = args[2];
|
|
984
|
+
const scenarioParts = [];
|
|
985
|
+
for (let i = 3; i < args.length; i++) {
|
|
986
|
+
if (args[i] === '--comparison') break;
|
|
987
|
+
scenarioParts.push(args[i]);
|
|
988
|
+
}
|
|
989
|
+
const scenario = scenarioParts.join(' ');
|
|
990
|
+
const comparisonJson = getArgValue(args, '--comparison');
|
|
991
|
+
whatif.cmdWhatifReport(cwd, phaseNum, scenario, comparisonJson, raw);
|
|
992
|
+
} else if (subcommand === 'cleanup') {
|
|
993
|
+
whatif.cmdWhatifCleanup(
|
|
994
|
+
cwd,
|
|
995
|
+
getArgValue(args, '--worktree'),
|
|
996
|
+
getArgValue(args, '--branch'),
|
|
997
|
+
args.includes('--force'),
|
|
998
|
+
raw
|
|
999
|
+
);
|
|
1000
|
+
} else {
|
|
1001
|
+
error('Unknown whatif subcommand. Available: prepare, report, cleanup');
|
|
1002
|
+
}
|
|
1003
|
+
break;
|
|
1004
|
+
}
|
|
1005
|
+
|
|
1006
|
+
case 'knowledge': {
|
|
1007
|
+
const subcommand = args[1];
|
|
1008
|
+
if (subcommand === 'ask') {
|
|
1009
|
+
const question = args.slice(2).filter(a => !a.startsWith('--')).join(' ');
|
|
1010
|
+
const maxSources = getArgValue(args, '--max-sources');
|
|
1011
|
+
knowledge.cmdKnowledgeAsk(cwd, question, {
|
|
1012
|
+
max_sources: maxSources ? Number(maxSources) : undefined,
|
|
1013
|
+
recall_cue: getArgValue(args, '--recall-cue'),
|
|
1014
|
+
}, raw);
|
|
1015
|
+
} else if (subcommand === 'discuss') {
|
|
1016
|
+
const phaseNum = args[2];
|
|
1017
|
+
knowledge.cmdKnowledgeDiscuss(cwd, phaseNum, {
|
|
1018
|
+
subcmd: getArgValue(args, '--subcmd'),
|
|
1019
|
+
role: getArgValue(args, '--role'),
|
|
1020
|
+
content: getArgValue(args, '--content'),
|
|
1021
|
+
cites: getArgValue(args, '--cites'),
|
|
1022
|
+
}, raw);
|
|
1023
|
+
} else if (subcommand === 'playbook') {
|
|
1024
|
+
knowledge.cmdKnowledgePlaybook(cwd, {
|
|
1025
|
+
preview: args.includes('--preview'),
|
|
1026
|
+
}, raw);
|
|
1027
|
+
} else {
|
|
1028
|
+
error('Unknown knowledge subcommand. Available: ask, discuss, playbook');
|
|
1029
|
+
}
|
|
1030
|
+
break;
|
|
1031
|
+
}
|
|
1032
|
+
|
|
1033
|
+
case 'skills': {
|
|
1034
|
+
const subcommand = args[1];
|
|
1035
|
+
const skillRoot = getArgValue(args, '--source-root') || skillAlign.resolveSkillRoot();
|
|
1036
|
+
if (subcommand === 'index') {
|
|
1037
|
+
skillAlign.cmdSkillsIndex(skillRoot, raw);
|
|
1038
|
+
} else if (subcommand === 'align') {
|
|
1039
|
+
skillAlign.cmdSkillsAlign(skillRoot, {
|
|
1040
|
+
draft: getArgValue(args, '--draft'),
|
|
1041
|
+
draftFile: getArgValue(args, '--draft-file'),
|
|
1042
|
+
topK: getArgValue(args, '--top'),
|
|
1043
|
+
minScore: getArgValue(args, '--min-score'),
|
|
1044
|
+
tokenBudget: getArgValue(args, '--token-budget'),
|
|
1045
|
+
}, raw);
|
|
1046
|
+
} else {
|
|
1047
|
+
error('Unknown skills subcommand. Available: index, align');
|
|
1048
|
+
}
|
|
1049
|
+
break;
|
|
1050
|
+
}
|
|
1051
|
+
|
|
1052
|
+
case 'hygiene': {
|
|
1053
|
+
const subcommand = args[1];
|
|
1054
|
+
const hygieneOpts = {
|
|
1055
|
+
traceAgeDays: getArgValue(args, '--trace-age-days'),
|
|
1056
|
+
apply: args.includes('--apply'),
|
|
1057
|
+
};
|
|
1058
|
+
if (subcommand === 'scan') {
|
|
1059
|
+
hygiene.cmdHygieneScan(cwd, hygieneOpts, raw);
|
|
1060
|
+
} else if (subcommand === 'clean') {
|
|
1061
|
+
hygiene.cmdHygieneClean(cwd, hygieneOpts, raw);
|
|
1062
|
+
} else {
|
|
1063
|
+
error('Unknown hygiene subcommand. Available: scan, clean [--apply] [--trace-age-days N]');
|
|
1064
|
+
}
|
|
1065
|
+
break;
|
|
1066
|
+
}
|
|
1067
|
+
|
|
1068
|
+
case 'review-deep': {
|
|
1069
|
+
const subcommand = args[1];
|
|
1070
|
+
const phaseNum = args[2];
|
|
1071
|
+
const opts = {
|
|
1072
|
+
reviewerFile: getArgValue(args, '--reviewer-file'),
|
|
1073
|
+
hardenerFile: getArgValue(args, '--hardener-file'),
|
|
1074
|
+
metaFile: getArgValue(args, '--meta-file'),
|
|
1075
|
+
};
|
|
1076
|
+
if (subcommand === 'merge') {
|
|
1077
|
+
reviewDeep.cmdReviewDeepMerge(cwd, phaseNum, opts, raw);
|
|
1078
|
+
} else if (subcommand === 'analyze') {
|
|
1079
|
+
reviewDeep.cmdReviewDeepAnalyze(cwd, phaseNum, opts, raw);
|
|
1080
|
+
} else {
|
|
1081
|
+
error('Unknown review-deep subcommand. Available: merge, analyze');
|
|
1082
|
+
}
|
|
1083
|
+
break;
|
|
1084
|
+
}
|
|
1085
|
+
|
|
1086
|
+
case 'preview': {
|
|
1087
|
+
const subcommand = args[1];
|
|
1088
|
+
if (subcommand === 'phase') {
|
|
1089
|
+
preview.cmdPreviewPhase(cwd, args[2], raw);
|
|
1090
|
+
} else if (subcommand === 'phases') {
|
|
1091
|
+
preview.cmdPreviewPhases(cwd, raw);
|
|
1092
|
+
} else if (subcommand === 'milestone') {
|
|
1093
|
+
preview.cmdPreviewMilestone(cwd, raw);
|
|
1094
|
+
} else {
|
|
1095
|
+
error('Unknown preview subcommand. Available: phase <N>, phases, milestone');
|
|
1096
|
+
}
|
|
1097
|
+
break;
|
|
1098
|
+
}
|
|
1099
|
+
|
|
1100
|
+
case 'cost': {
|
|
1101
|
+
const subcommand = args[1];
|
|
1102
|
+
if (subcommand === 'report' || !subcommand) {
|
|
1103
|
+
const format = getArgValue(args, '--format', 'json');
|
|
1104
|
+
const since = getArgValue(args, '--since');
|
|
1105
|
+
const until = getArgValue(args, '--until');
|
|
1106
|
+
cost.cmdCostReport(cwd, { format, since, until }, raw);
|
|
1107
|
+
} else if (subcommand === 'append') {
|
|
1108
|
+
const rec = {
|
|
1109
|
+
agent: getArgValue(args, '--agent'),
|
|
1110
|
+
command: getArgValue(args, '--command'),
|
|
1111
|
+
model: getArgValue(args, '--model'),
|
|
1112
|
+
tier: getArgValue(args, '--tier'),
|
|
1113
|
+
input_tokens: Number(getArgValue(args, '--input-tokens', 0)),
|
|
1114
|
+
output_tokens: Number(getArgValue(args, '--output-tokens', 0)),
|
|
1115
|
+
cache_read_tokens: Number(getArgValue(args, '--cache-read-tokens', 0)),
|
|
1116
|
+
cache_write_tokens: Number(getArgValue(args, '--cache-write-tokens', 0)),
|
|
1117
|
+
phase: getArgValue(args, '--phase'),
|
|
1118
|
+
session: getArgValue(args, '--session'),
|
|
1119
|
+
};
|
|
1120
|
+
cost.cmdCostAppend(cwd, rec, raw);
|
|
1121
|
+
} else if (subcommand === 'clear') {
|
|
1122
|
+
cost.cmdCostClear(cwd, raw);
|
|
1123
|
+
} else {
|
|
1124
|
+
error('Unknown cost subcommand. Available: report, append, clear');
|
|
1125
|
+
}
|
|
1126
|
+
break;
|
|
1127
|
+
}
|
|
1128
|
+
|
|
1129
|
+
case 'models': {
|
|
1130
|
+
const subcommand = args[1];
|
|
1131
|
+
if (subcommand === 'check' || !subcommand) {
|
|
1132
|
+
cost.cmdModelsCheck(raw);
|
|
1133
|
+
} else {
|
|
1134
|
+
error('Unknown models subcommand. Available: check');
|
|
1135
|
+
}
|
|
1136
|
+
break;
|
|
1137
|
+
}
|
|
1138
|
+
|
|
1139
|
+
case 'squad': {
|
|
1140
|
+
const squads = require('./lib/squads.cjs');
|
|
1141
|
+
const subcommand = args[1];
|
|
1142
|
+
if (subcommand === 'list' || !subcommand) {
|
|
1143
|
+
squads.cmdSquadList(raw);
|
|
1144
|
+
} else if (subcommand === 'show') {
|
|
1145
|
+
squads.cmdSquadShow(args[2], raw);
|
|
1146
|
+
} else {
|
|
1147
|
+
error('Unknown squad subcommand. Available: list, show');
|
|
1148
|
+
}
|
|
1149
|
+
break;
|
|
1150
|
+
}
|
|
1151
|
+
|
|
1152
|
+
case 'worktree': {
|
|
1153
|
+
const worktree = require('./lib/worktree.cjs');
|
|
1154
|
+
const subcommand = args[1];
|
|
1155
|
+
if (subcommand === 'list' || !subcommand) {
|
|
1156
|
+
worktree.cmdWorktreeList(cwd, raw);
|
|
1157
|
+
} else if (subcommand === 'create') {
|
|
1158
|
+
worktree.cmdWorktreeCreate(cwd, args[2], raw, { base: getArgValue(args, '--base') });
|
|
1159
|
+
} else if (subcommand === 'remove') {
|
|
1160
|
+
worktree.cmdWorktreeRemove(cwd, args[2], getArgValue(args, '--branch'), raw, { force: args.includes('--force') });
|
|
1161
|
+
} else {
|
|
1162
|
+
error('Unknown worktree subcommand. Available: list, create, remove');
|
|
1163
|
+
}
|
|
1164
|
+
break;
|
|
1165
|
+
}
|
|
1166
|
+
|
|
1167
|
+
case 'campaign': {
|
|
1168
|
+
const campaign = require('./lib/campaign.cjs');
|
|
1169
|
+
const subcommand = args[1];
|
|
1170
|
+
if (subcommand === 'schedule') {
|
|
1171
|
+
const budget = getArgValue(args, '--daily-budget');
|
|
1172
|
+
campaign.cmdCampaignSchedule(cwd, {
|
|
1173
|
+
goal: getArgValue(args, '--goal'),
|
|
1174
|
+
source: getArgValue(args, '--source'),
|
|
1175
|
+
cadence: getArgValue(args, '--cadence', 'daily'),
|
|
1176
|
+
daily_budget: budget != null ? Number(budget) : undefined,
|
|
1177
|
+
enabled: args.includes('--disable') ? false : undefined,
|
|
1178
|
+
paused: args.includes('--pause') ? true : (args.includes('--resume') ? false : undefined),
|
|
1179
|
+
}, raw);
|
|
1180
|
+
} else if (subcommand === 'status' || !subcommand) {
|
|
1181
|
+
campaign.cmdCampaignStatus(cwd, raw);
|
|
1182
|
+
} else if (subcommand === 'due') {
|
|
1183
|
+
campaign.cmdCampaignDue(cwd, raw);
|
|
1184
|
+
} else if (subcommand === 'record-run') {
|
|
1185
|
+
const r = campaign.recordRun(cwd, {
|
|
1186
|
+
items_landed: Number(getArgValue(args, '--items', 0)),
|
|
1187
|
+
points_used: Number(getArgValue(args, '--points', 0)),
|
|
1188
|
+
});
|
|
1189
|
+
if (r.error) { error(r.error); } else { output(r, raw, `recorded · next ${r.next_due}`); }
|
|
1190
|
+
} else {
|
|
1191
|
+
error('Unknown campaign subcommand. Available: schedule, status, due, record-run');
|
|
1192
|
+
}
|
|
1193
|
+
break;
|
|
1194
|
+
}
|
|
1195
|
+
|
|
1196
|
+
case 'bus': {
|
|
1197
|
+
const subcommand = args[1];
|
|
1198
|
+
if (subcommand === 'publish') {
|
|
1199
|
+
bus.cmdBusPublish(cwd, args[2], args[3], { source: getArgValue(args, '--source') }, raw);
|
|
1200
|
+
} else if (subcommand === 'drain') {
|
|
1201
|
+
const mode = getArgValue(args, '--mode', 'peek');
|
|
1202
|
+
const limit = getArgValue(args, '--limit');
|
|
1203
|
+
const offset = getArgValue(args, '--offset');
|
|
1204
|
+
bus.cmdBusDrain(cwd, args[2], {
|
|
1205
|
+
mode,
|
|
1206
|
+
limit: limit ? Number(limit) : undefined,
|
|
1207
|
+
offset: offset ? Number(offset) : undefined,
|
|
1208
|
+
}, raw);
|
|
1209
|
+
} else if (subcommand === 'list') {
|
|
1210
|
+
bus.cmdBusList(cwd, raw);
|
|
1211
|
+
} else {
|
|
1212
|
+
error('Unknown bus subcommand. Available: publish, drain, list');
|
|
1213
|
+
}
|
|
1214
|
+
break;
|
|
1215
|
+
}
|
|
1216
|
+
|
|
1217
|
+
case 'cache': {
|
|
1218
|
+
const subcommand = args[1];
|
|
1219
|
+
if (subcommand === 'prime') {
|
|
1220
|
+
const result = buildCachedContext(cwd);
|
|
1221
|
+
if (args.includes('--summary')) {
|
|
1222
|
+
// Metadata-only form: hide full block content so agents can decide
|
|
1223
|
+
// whether to request the full payload.
|
|
1224
|
+
const summary = {
|
|
1225
|
+
blocks: result.blocks.map(b => ({ path: b.path, bytes: Buffer.byteLength(b.content, 'utf-8'), cache: b.cache })),
|
|
1226
|
+
total_bytes: result.total_bytes,
|
|
1227
|
+
sha: result.sha,
|
|
1228
|
+
};
|
|
1229
|
+
output(summary, raw);
|
|
1230
|
+
} else {
|
|
1231
|
+
output(result, raw);
|
|
1232
|
+
}
|
|
1233
|
+
} else {
|
|
1234
|
+
error('Unknown cache subcommand. Available: prime [--summary]');
|
|
1235
|
+
}
|
|
1236
|
+
break;
|
|
1237
|
+
}
|
|
1238
|
+
|
|
1239
|
+
|
|
1240
|
+
case 'retro': {
|
|
1241
|
+
verify.cmdRetro(cwd, raw, args);
|
|
1242
|
+
break;
|
|
1243
|
+
}
|
|
1244
|
+
|
|
1245
|
+
case 'codebase': {
|
|
1246
|
+
const subcommand = args[1];
|
|
1247
|
+
if (subcommand === 'analyze-imports') {
|
|
1248
|
+
codebase.cmdAnalyzeImports(cwd, raw, args);
|
|
1249
|
+
} else if (subcommand === 'detect-languages') {
|
|
1250
|
+
codebase.cmdDetectLanguages(cwd, raw);
|
|
1251
|
+
} else if (subcommand === 'best-practices') {
|
|
1252
|
+
codebase.cmdBestPractices(cwd, raw);
|
|
1253
|
+
} else if (subcommand === 'estimate-size') {
|
|
1254
|
+
codebase.cmdEstimateRepoSize(cwd, raw, args);
|
|
1255
|
+
} else {
|
|
1256
|
+
error('Unknown codebase subcommand. Available: analyze-imports, detect-languages, best-practices, estimate-size');
|
|
1257
|
+
}
|
|
1258
|
+
break;
|
|
1259
|
+
}
|
|
1260
|
+
|
|
1261
|
+
case 'standards': {
|
|
1262
|
+
const subcommand = args[1];
|
|
1263
|
+
if (subcommand === 'list') {
|
|
1264
|
+
config.cmdStandardsList(cwd, getArgValue(args, '--category'), raw);
|
|
1265
|
+
} else if (subcommand === 'select') {
|
|
1266
|
+
config.cmdStandardsSelect(cwd, args[2], raw);
|
|
1267
|
+
} else if (subcommand === 'remove') {
|
|
1268
|
+
config.cmdStandardsRemove(cwd, args[2], raw);
|
|
1269
|
+
} else if (subcommand === 'status') {
|
|
1270
|
+
config.cmdStandardsStatus(cwd, raw);
|
|
1271
|
+
} else if (subcommand === 'recommend') {
|
|
1272
|
+
config.cmdStandardsRecommend(cwd, raw);
|
|
1273
|
+
} else if (subcommand === 'phase-track') {
|
|
1274
|
+
config.cmdStandardsPhaseTrack(cwd, args[2], raw);
|
|
1275
|
+
} else if (subcommand === 'tools') {
|
|
1276
|
+
config.cmdStandardsTools(cwd, args[2], raw);
|
|
1277
|
+
} else {
|
|
1278
|
+
error('Unknown standards subcommand. Available: list, select, remove, status, recommend, phase-track, tools');
|
|
1279
|
+
}
|
|
1280
|
+
break;
|
|
1281
|
+
}
|
|
1282
|
+
|
|
1283
|
+
case 'optimize': {
|
|
1284
|
+
const subcommand = args[1];
|
|
1285
|
+
if (subcommand === 'trace') {
|
|
1286
|
+
const traceSub = args[2];
|
|
1287
|
+
optimize.cmdOptimizeTrace(cwd, traceSub, {
|
|
1288
|
+
sessionId: getArgValue(args, '--session'),
|
|
1289
|
+
description: getArgValue(args, '--description'),
|
|
1290
|
+
command: getArgValue(args, '--command'),
|
|
1291
|
+
phase: getArgValue(args, '--phase'),
|
|
1292
|
+
// trace log opts
|
|
1293
|
+
agent: getArgValue(args, '--agent'),
|
|
1294
|
+
type: getArgValue(args, '--type'),
|
|
1295
|
+
category: getArgValue(args, '--category'),
|
|
1296
|
+
impact: getArgValue(args, '--impact'),
|
|
1297
|
+
description: getArgValue(args, '--description'),
|
|
1298
|
+
correction: getArgValue(args, '--correction'),
|
|
1299
|
+
tokens_wasted: getArgValue(args, '--tokens-wasted') ? Number(getArgValue(args, '--tokens-wasted')) : null,
|
|
1300
|
+
context: (() => { const v = getArgValue(args, '--context'); if (!v) return null; try { return JSON.parse(v); } catch { return null; } })(),
|
|
1301
|
+
}, raw);
|
|
1302
|
+
} else if (subcommand === 'learn') {
|
|
1303
|
+
optimize.cmdOptimizeLearn(cwd, {
|
|
1304
|
+
sessionId: getArgValue(args, '--session'),
|
|
1305
|
+
}, raw);
|
|
1306
|
+
} else if (subcommand === 'apply') {
|
|
1307
|
+
optimize.cmdOptimizeApply(cwd, {
|
|
1308
|
+
reportPath: getArgValue(args, '--report'),
|
|
1309
|
+
}, raw);
|
|
1310
|
+
} else if (subcommand === 'list') {
|
|
1311
|
+
optimize.cmdOptimizeList(cwd, raw);
|
|
1312
|
+
} else if (subcommand === 'stats') {
|
|
1313
|
+
optimize.cmdOptimizeStats(cwd, raw);
|
|
1314
|
+
} else {
|
|
1315
|
+
error('Unknown optimize subcommand. Available: trace, learn, apply, list, stats');
|
|
1316
|
+
}
|
|
1317
|
+
break;
|
|
1318
|
+
}
|
|
1319
|
+
|
|
1320
|
+
case 'doc-lint': {
|
|
1321
|
+
const subcommand = args[1];
|
|
1322
|
+
if (subcommand === 'schema-check') {
|
|
1323
|
+
const schemaPath = args[2];
|
|
1324
|
+
if (!schemaPath || schemaPath.startsWith('--')) { error('doc-lint schema-check <path> required'); }
|
|
1325
|
+
docLint.cmdDocLintSchemaCheck(cwd, schemaPath, { raw });
|
|
1326
|
+
break;
|
|
1327
|
+
}
|
|
1328
|
+
if (subcommand === 'counts') {
|
|
1329
|
+
const dir = args[2];
|
|
1330
|
+
if (!dir || dir.startsWith('--')) { error('doc-lint counts <dir> required'); }
|
|
1331
|
+
const exclude = [];
|
|
1332
|
+
for (let k = 0; k < args.length; k++) if (args[k] === '--exclude') exclude.push(args[k + 1]);
|
|
1333
|
+
docLint.cmdDocLintCounts(cwd, dir, { raw, exclude });
|
|
1334
|
+
break;
|
|
1335
|
+
}
|
|
1336
|
+
if (subcommand === 'flags') {
|
|
1337
|
+
const docDirs = [];
|
|
1338
|
+
for (let k = 0; k < args.length; k++) if (args[k] === '--doc-dir') docDirs.push(args[k + 1]);
|
|
1339
|
+
docLint.cmdDocLintFlags(cwd, { docDirs: docDirs.length ? docDirs : undefined }, raw);
|
|
1340
|
+
break;
|
|
1341
|
+
}
|
|
1342
|
+
// Default: lint a directory
|
|
1343
|
+
const dir = args[1];
|
|
1344
|
+
if (!dir || dir.startsWith('--')) { error('doc-lint <dir> required (or doc-lint schema-check <path>, doc-lint counts <dir>)'); }
|
|
1345
|
+
const schema = getArgValue(args, '--schema');
|
|
1346
|
+
const format = getArgValue(args, '--format', 'human');
|
|
1347
|
+
const strict = args.includes('--strict');
|
|
1348
|
+
const exclude = [];
|
|
1349
|
+
for (let k = 0; k < args.length; k++) if (args[k] === '--exclude') exclude.push(args[k + 1]);
|
|
1350
|
+
docLint.cmdDocLint(cwd, dir, { schema, format, strict, exclude: exclude.filter(Boolean), raw });
|
|
1351
|
+
break;
|
|
1352
|
+
}
|
|
1353
|
+
|
|
1354
|
+
case 'learn': {
|
|
1355
|
+
const subcommand = args[1];
|
|
1356
|
+
|
|
1357
|
+
// W4: pan-tools learn promote/unpromote/list-promoted (self-improvement loop)
|
|
1358
|
+
if (subcommand === 'promote') {
|
|
1359
|
+
const patternId = getArgValue(args, '--pattern');
|
|
1360
|
+
if (!patternId) { error('learn promote requires --pattern <id>'); }
|
|
1361
|
+
const scope = getArgValue(args, '--scope');
|
|
1362
|
+
const topic = getArgValue(args, '--topic');
|
|
1363
|
+
if (!scope) { error('learn promote requires --scope universal|internal'); }
|
|
1364
|
+
if (!topic) { error('learn promote requires --topic <name>'); }
|
|
1365
|
+
const summary = getArgValue(args, '--summary') || '';
|
|
1366
|
+
const evidence = getArgValue(args, '--evidence') || '';
|
|
1367
|
+
const rule = getArgValue(args, '--rule') || '';
|
|
1368
|
+
const appliesIn = getArgValue(args, '--applies-in') || '';
|
|
1369
|
+
const sourceExpsCsv = getArgValue(args, '--source-experiments') || '';
|
|
1370
|
+
const sourceExperiments = sourceExpsCsv
|
|
1371
|
+
? sourceExpsCsv.split(',').map(s => s.trim()).filter(Boolean)
|
|
1372
|
+
: [];
|
|
1373
|
+
const sourceRoot = getArgValue(args, '--source-root') || cwd;
|
|
1374
|
+
|
|
1375
|
+
const result = optimize.promotePattern(
|
|
1376
|
+
{ id: patternId, summary, evidence, rule, applies_in: appliesIn, source_experiments: sourceExperiments },
|
|
1377
|
+
{ scope, topic, sourceRoot }
|
|
1378
|
+
);
|
|
1379
|
+
output(result, raw);
|
|
1380
|
+
break;
|
|
1381
|
+
}
|
|
1382
|
+
|
|
1383
|
+
if (subcommand === 'unpromote') {
|
|
1384
|
+
const patternId = getArgValue(args, '--pattern');
|
|
1385
|
+
const scope = getArgValue(args, '--scope');
|
|
1386
|
+
const topic = getArgValue(args, '--topic');
|
|
1387
|
+
const sourceRoot = getArgValue(args, '--source-root') || cwd;
|
|
1388
|
+
if (!patternId || !scope || !topic) {
|
|
1389
|
+
error('learn unpromote requires --pattern <id> --scope <s> --topic <t>');
|
|
1390
|
+
}
|
|
1391
|
+
const result = optimize.unpromotePattern(patternId, { scope, topic, sourceRoot });
|
|
1392
|
+
output(result, raw);
|
|
1393
|
+
break;
|
|
1394
|
+
}
|
|
1395
|
+
|
|
1396
|
+
if (subcommand === 'list-promoted') {
|
|
1397
|
+
const sourceRoot = getArgValue(args, '--source-root') || cwd;
|
|
1398
|
+
const result = optimize.listPromotedPatterns({ sourceRoot });
|
|
1399
|
+
output(result, raw);
|
|
1400
|
+
break;
|
|
1401
|
+
}
|
|
1402
|
+
|
|
1403
|
+
if (subcommand === 'build-index') {
|
|
1404
|
+
const sourceRoot = getArgValue(args, '--source-root') || cwd;
|
|
1405
|
+
const result = learnIndex.cmdBuildIndex(sourceRoot);
|
|
1406
|
+
if (raw) {
|
|
1407
|
+
output(result, true,
|
|
1408
|
+
`Index written: ${result.written_to}\n` +
|
|
1409
|
+
`Topics: ${result.topics}\nPatterns: ${result.patterns}\n` +
|
|
1410
|
+
`Total tokens (est): ${result.total_tokens_est.toLocaleString()}\n` +
|
|
1411
|
+
`Schema version: ${result.schema_version}`);
|
|
1412
|
+
} else {
|
|
1413
|
+
output(result, false);
|
|
1414
|
+
}
|
|
1415
|
+
break;
|
|
1416
|
+
}
|
|
1417
|
+
|
|
1418
|
+
if (subcommand === 'topics-for') {
|
|
1419
|
+
const sourceRoot = getArgValue(args, '--source-root') || cwd;
|
|
1420
|
+
const agent = getArgValue(args, '--agent');
|
|
1421
|
+
if (!agent) { error('learn topics-for requires --agent <name>'); }
|
|
1422
|
+
const minRelevance = getArgValue(args, '--min-relevance', 'medium');
|
|
1423
|
+
const tokenBudget = parseInt(getArgValue(args, '--token-budget', '5000'), 10);
|
|
1424
|
+
const result = learnIndex.cmdTopicsFor(sourceRoot, { agent, minRelevance, tokenBudget });
|
|
1425
|
+
if (raw) {
|
|
1426
|
+
const lines = [`Topics for "${agent}" (min ${minRelevance}, budget ${tokenBudget}):`, ``];
|
|
1427
|
+
for (const t of result.selected) {
|
|
1428
|
+
lines.push(` [${t.relevance.padEnd(6)}] ${t.scope}/${t.name.padEnd(22)} ${t.tokens.toString().padStart(5)}t ${t.patterns.join(', ')}`);
|
|
1429
|
+
}
|
|
1430
|
+
lines.push(``, `Selected: ${result.selected.length} topics, ${result.total_tokens} tokens`);
|
|
1431
|
+
if (result.dropped.length > 0) {
|
|
1432
|
+
lines.push(`Dropped (over budget): ${result.dropped.length} — ${result.dropped.map(d => d.name).join(', ')}`);
|
|
1433
|
+
}
|
|
1434
|
+
output(result, true, lines.join('\n'));
|
|
1435
|
+
} else {
|
|
1436
|
+
output(result, false);
|
|
1437
|
+
}
|
|
1438
|
+
break;
|
|
1439
|
+
}
|
|
1440
|
+
|
|
1441
|
+
if (subcommand === 'lint') {
|
|
1442
|
+
const sourceRoot = getArgValue(args, '--source-root') || cwd;
|
|
1443
|
+
const scope = getArgValue(args, '--scope');
|
|
1444
|
+
const strict = args.includes('--strict');
|
|
1445
|
+
const result = learnLint.cmdLearnLint(sourceRoot, { scope, strict });
|
|
1446
|
+
if (raw) {
|
|
1447
|
+
const lines = [`Learn-Lint: ${result.summary.status.toUpperCase()}`,
|
|
1448
|
+
``,
|
|
1449
|
+
`Patterns scanned: ${result.pattern_count} across ${result.file_count} files`,
|
|
1450
|
+
`Errors: ${result.summary.errors}`,
|
|
1451
|
+
`Warnings: ${result.summary.warnings}`,
|
|
1452
|
+
``,
|
|
1453
|
+
];
|
|
1454
|
+
for (const v of result.violations) {
|
|
1455
|
+
lines.push(`[${v.severity.toUpperCase()}] ${v.code} ${v.pattern_id}: ${v.message}`);
|
|
1456
|
+
}
|
|
1457
|
+
output(result, true, lines.join('\n'));
|
|
1458
|
+
} else {
|
|
1459
|
+
output(result, false);
|
|
1460
|
+
}
|
|
1461
|
+
if (result.summary.status === 'fail') process.exit(1);
|
|
1462
|
+
break;
|
|
1463
|
+
}
|
|
1464
|
+
|
|
1465
|
+
// Default: convenience alias for optimize learn (existing behavior)
|
|
1466
|
+
optimize.cmdOptimizeLearn(cwd, {
|
|
1467
|
+
sessionId: getArgValue(args, '--session'),
|
|
1468
|
+
}, raw);
|
|
1469
|
+
break;
|
|
1470
|
+
}
|
|
1471
|
+
|
|
1472
|
+
case 'links': {
|
|
1473
|
+
const subcommand = args[1];
|
|
1474
|
+
if (subcommand === 'validate' || !subcommand) {
|
|
1475
|
+
const collectMulti = (flag) => {
|
|
1476
|
+
const vals = [];
|
|
1477
|
+
for (let i = 0; i < args.length; i++) {
|
|
1478
|
+
if (args[i] === flag && i + 1 < args.length) vals.push(args[i + 1]);
|
|
1479
|
+
}
|
|
1480
|
+
return vals.length ? vals : null;
|
|
1481
|
+
};
|
|
1482
|
+
const opts = {
|
|
1483
|
+
docRoots: collectMulti('--doc-root'),
|
|
1484
|
+
sourceRoots: collectMulti('--source-root'),
|
|
1485
|
+
strict: args.includes('--strict'),
|
|
1486
|
+
raw,
|
|
1487
|
+
};
|
|
1488
|
+
links.cmdLinksValidate(cwd, opts);
|
|
1489
|
+
break;
|
|
1490
|
+
}
|
|
1491
|
+
error(`Unknown links subcommand: ${subcommand}. Available: validate`);
|
|
1492
|
+
}
|
|
1493
|
+
|
|
1494
|
+
default:
|
|
1495
|
+
error(`Unknown command: ${command}. Run pan-tools without arguments to see available commands.`);
|
|
1496
|
+
}
|
|
1497
|
+
}
|
|
1498
|
+
|
|
1499
|
+
main();
|