gsd-opencode 1.22.1 → 1.33.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/agents/gsd-advisor-researcher.md +112 -0
- package/agents/gsd-assumptions-analyzer.md +110 -0
- package/agents/gsd-codebase-mapper.md +0 -2
- package/agents/gsd-debugger.md +117 -2
- package/agents/gsd-doc-verifier.md +207 -0
- package/agents/gsd-doc-writer.md +608 -0
- package/agents/gsd-executor.md +45 -4
- package/agents/gsd-integration-checker.md +0 -2
- package/agents/gsd-nyquist-auditor.md +0 -2
- package/agents/gsd-phase-researcher.md +191 -5
- package/agents/gsd-plan-checker.md +152 -5
- package/agents/gsd-planner.md +131 -157
- package/agents/gsd-project-researcher.md +28 -3
- package/agents/gsd-research-synthesizer.md +0 -2
- package/agents/gsd-roadmapper.md +29 -2
- package/agents/gsd-security-auditor.md +129 -0
- package/agents/gsd-ui-auditor.md +485 -0
- package/agents/gsd-ui-checker.md +305 -0
- package/agents/gsd-ui-researcher.md +368 -0
- package/agents/gsd-user-profiler.md +173 -0
- package/agents/gsd-verifier.md +207 -22
- package/commands/gsd/gsd-add-backlog.md +76 -0
- package/commands/gsd/gsd-analyze-dependencies.md +34 -0
- package/commands/gsd/gsd-audit-uat.md +24 -0
- package/commands/gsd/gsd-autonomous.md +45 -0
- package/commands/gsd/gsd-cleanup.md +5 -0
- package/commands/gsd/gsd-debug.md +29 -21
- package/commands/gsd/gsd-discuss-phase.md +15 -36
- package/commands/gsd/gsd-do.md +30 -0
- package/commands/gsd/gsd-docs-update.md +48 -0
- package/commands/gsd/gsd-execute-phase.md +24 -2
- package/commands/gsd/gsd-fast.md +30 -0
- package/commands/gsd/gsd-forensics.md +56 -0
- package/commands/gsd/gsd-help.md +2 -0
- package/commands/gsd/gsd-join-discord.md +2 -1
- package/commands/gsd/gsd-list-workspaces.md +19 -0
- package/commands/gsd/gsd-manager.md +40 -0
- package/commands/gsd/gsd-milestone-summary.md +51 -0
- package/commands/gsd/gsd-new-project.md +4 -0
- package/commands/gsd/gsd-new-workspace.md +44 -0
- package/commands/gsd/gsd-next.md +24 -0
- package/commands/gsd/gsd-note.md +34 -0
- package/commands/gsd/gsd-plan-phase.md +8 -1
- package/commands/gsd/gsd-plant-seed.md +28 -0
- package/commands/gsd/gsd-pr-branch.md +25 -0
- package/commands/gsd/gsd-profile-user.md +46 -0
- package/commands/gsd/gsd-quick.md +7 -3
- package/commands/gsd/gsd-reapply-patches.md +178 -45
- package/commands/gsd/gsd-remove-workspace.md +26 -0
- package/commands/gsd/gsd-research-phase.md +7 -12
- package/commands/gsd/gsd-review-backlog.md +62 -0
- package/commands/gsd/gsd-review.md +38 -0
- package/commands/gsd/gsd-secure-phase.md +35 -0
- package/commands/gsd/gsd-session-report.md +19 -0
- package/commands/gsd/gsd-set-profile.md +24 -23
- package/commands/gsd/gsd-ship.md +23 -0
- package/commands/gsd/gsd-stats.md +18 -0
- package/commands/gsd/gsd-thread.md +127 -0
- package/commands/gsd/gsd-ui-phase.md +34 -0
- package/commands/gsd/gsd-ui-review.md +32 -0
- package/commands/gsd/gsd-workstreams.md +71 -0
- package/get-shit-done/bin/gsd-tools.cjs +450 -90
- package/get-shit-done/bin/lib/commands.cjs +489 -24
- package/get-shit-done/bin/lib/config.cjs +329 -48
- package/get-shit-done/bin/lib/core.cjs +1143 -102
- package/get-shit-done/bin/lib/docs.cjs +267 -0
- package/get-shit-done/bin/lib/frontmatter.cjs +125 -43
- package/get-shit-done/bin/lib/init.cjs +918 -106
- package/get-shit-done/bin/lib/milestone.cjs +65 -33
- package/get-shit-done/bin/lib/model-profiles.cjs +70 -0
- package/get-shit-done/bin/lib/phase.cjs +434 -404
- package/get-shit-done/bin/lib/profile-output.cjs +1048 -0
- package/get-shit-done/bin/lib/profile-pipeline.cjs +539 -0
- package/get-shit-done/bin/lib/roadmap.cjs +156 -101
- package/get-shit-done/bin/lib/schema-detect.cjs +238 -0
- package/get-shit-done/bin/lib/security.cjs +384 -0
- package/get-shit-done/bin/lib/state.cjs +711 -79
- package/get-shit-done/bin/lib/template.cjs +2 -2
- package/get-shit-done/bin/lib/uat.cjs +282 -0
- package/get-shit-done/bin/lib/verify.cjs +254 -42
- package/get-shit-done/bin/lib/workstream.cjs +495 -0
- package/get-shit-done/references/agent-contracts.md +79 -0
- package/get-shit-done/references/artifact-types.md +113 -0
- package/get-shit-done/references/checkpoints.md +12 -10
- package/get-shit-done/references/context-budget.md +49 -0
- package/get-shit-done/references/continuation-format.md +15 -15
- package/get-shit-done/references/decimal-phase-calculation.md +2 -3
- package/get-shit-done/references/domain-probes.md +125 -0
- package/get-shit-done/references/gate-prompts.md +100 -0
- package/get-shit-done/references/git-integration.md +47 -0
- package/get-shit-done/references/model-profile-resolution.md +2 -0
- package/get-shit-done/references/model-profiles.md +62 -16
- package/get-shit-done/references/phase-argument-parsing.md +2 -2
- package/get-shit-done/references/planner-gap-closure.md +62 -0
- package/get-shit-done/references/planner-reviews.md +39 -0
- package/get-shit-done/references/planner-revision.md +87 -0
- package/get-shit-done/references/planning-config.md +18 -1
- package/get-shit-done/references/revision-loop.md +97 -0
- package/get-shit-done/references/ui-brand.md +2 -2
- package/get-shit-done/references/universal-anti-patterns.md +58 -0
- package/get-shit-done/references/user-profiling.md +681 -0
- package/get-shit-done/references/workstream-flag.md +111 -0
- package/get-shit-done/templates/SECURITY.md +61 -0
- package/get-shit-done/templates/UAT.md +21 -3
- package/get-shit-done/templates/UI-SPEC.md +100 -0
- package/get-shit-done/templates/VALIDATION.md +3 -3
- package/get-shit-done/templates/claude-md.md +145 -0
- package/get-shit-done/templates/config.json +14 -3
- package/get-shit-done/templates/context.md +61 -6
- package/get-shit-done/templates/debug-subagent-prompt.md +2 -6
- package/get-shit-done/templates/dev-preferences.md +21 -0
- package/get-shit-done/templates/discussion-log.md +63 -0
- package/get-shit-done/templates/phase-prompt.md +46 -5
- package/get-shit-done/templates/planner-subagent-prompt.md +2 -10
- package/get-shit-done/templates/project.md +2 -0
- package/get-shit-done/templates/state.md +2 -2
- package/get-shit-done/templates/user-profile.md +146 -0
- package/get-shit-done/workflows/add-phase.md +4 -4
- package/get-shit-done/workflows/add-tests.md +4 -4
- package/get-shit-done/workflows/add-todo.md +4 -4
- package/get-shit-done/workflows/analyze-dependencies.md +96 -0
- package/get-shit-done/workflows/audit-milestone.md +20 -16
- package/get-shit-done/workflows/audit-uat.md +109 -0
- package/get-shit-done/workflows/autonomous.md +1036 -0
- package/get-shit-done/workflows/check-todos.md +4 -4
- package/get-shit-done/workflows/cleanup.md +4 -4
- package/get-shit-done/workflows/complete-milestone.md +22 -10
- package/get-shit-done/workflows/diagnose-issues.md +21 -7
- package/get-shit-done/workflows/discovery-phase.md +2 -2
- package/get-shit-done/workflows/discuss-phase-assumptions.md +671 -0
- package/get-shit-done/workflows/discuss-phase-power.md +291 -0
- package/get-shit-done/workflows/discuss-phase.md +558 -47
- package/get-shit-done/workflows/do.md +104 -0
- package/get-shit-done/workflows/docs-update.md +1093 -0
- package/get-shit-done/workflows/execute-phase.md +741 -58
- package/get-shit-done/workflows/execute-plan.md +77 -12
- package/get-shit-done/workflows/fast.md +105 -0
- package/get-shit-done/workflows/forensics.md +265 -0
- package/get-shit-done/workflows/health.md +28 -6
- package/get-shit-done/workflows/help.md +127 -7
- package/get-shit-done/workflows/insert-phase.md +4 -4
- package/get-shit-done/workflows/list-phase-assumptions.md +2 -2
- package/get-shit-done/workflows/list-workspaces.md +56 -0
- package/get-shit-done/workflows/manager.md +363 -0
- package/get-shit-done/workflows/map-codebase.md +83 -44
- package/get-shit-done/workflows/milestone-summary.md +223 -0
- package/get-shit-done/workflows/new-milestone.md +133 -25
- package/get-shit-done/workflows/new-project.md +216 -54
- package/get-shit-done/workflows/new-workspace.md +237 -0
- package/get-shit-done/workflows/next.md +97 -0
- package/get-shit-done/workflows/node-repair.md +92 -0
- package/get-shit-done/workflows/note.md +156 -0
- package/get-shit-done/workflows/pause-work.md +132 -15
- package/get-shit-done/workflows/plan-milestone-gaps.md +6 -7
- package/get-shit-done/workflows/plan-phase.md +513 -62
- package/get-shit-done/workflows/plant-seed.md +169 -0
- package/get-shit-done/workflows/pr-branch.md +129 -0
- package/get-shit-done/workflows/profile-user.md +450 -0
- package/get-shit-done/workflows/progress.md +154 -29
- package/get-shit-done/workflows/quick.md +285 -111
- package/get-shit-done/workflows/remove-phase.md +2 -2
- package/get-shit-done/workflows/remove-workspace.md +90 -0
- package/get-shit-done/workflows/research-phase.md +13 -9
- package/get-shit-done/workflows/resume-project.md +37 -18
- package/get-shit-done/workflows/review.md +281 -0
- package/get-shit-done/workflows/secure-phase.md +154 -0
- package/get-shit-done/workflows/session-report.md +146 -0
- package/get-shit-done/workflows/set-profile.md +2 -2
- package/get-shit-done/workflows/settings.md +91 -11
- package/get-shit-done/workflows/ship.md +237 -0
- package/get-shit-done/workflows/stats.md +60 -0
- package/get-shit-done/workflows/transition.md +150 -23
- package/get-shit-done/workflows/ui-phase.md +292 -0
- package/get-shit-done/workflows/ui-review.md +183 -0
- package/get-shit-done/workflows/update.md +262 -30
- package/get-shit-done/workflows/validate-phase.md +14 -17
- package/get-shit-done/workflows/verify-phase.md +143 -11
- package/get-shit-done/workflows/verify-work.md +141 -39
- package/package.json +1 -1
- package/skills/gsd-audit-milestone/SKILL.md +29 -0
- package/skills/gsd-cleanup/SKILL.md +19 -0
- package/skills/gsd-complete-milestone/SKILL.md +131 -0
- package/skills/gsd-discuss-phase/SKILL.md +54 -0
- package/skills/gsd-execute-phase/SKILL.md +49 -0
- package/skills/gsd-plan-phase/SKILL.md +37 -0
- package/skills/gsd-ui-phase/SKILL.md +24 -0
- package/skills/gsd-ui-review/SKILL.md +24 -0
- package/skills/gsd-verify-work/SKILL.md +30 -0
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* Replaces repetitive inline bash patterns across ~50 GSD command/workflow/agent files.
|
|
7
7
|
* Centralizes: config parsing, model resolution, phase lookup, git commits, summary verification.
|
|
8
8
|
*
|
|
9
|
-
* Usage: node gsd-tools.cjs <command> [args] [--raw]
|
|
9
|
+
* Usage: node gsd-tools.cjs <command> [args] [--raw] [--pick <field>]
|
|
10
10
|
*
|
|
11
11
|
* Atomic Commands:
|
|
12
12
|
* state load Load project config + state
|
|
@@ -14,9 +14,13 @@
|
|
|
14
14
|
* state update <field> <value> Update a STATE.md field
|
|
15
15
|
* state get [section] Get STATE.md content or section
|
|
16
16
|
* state patch --field val ... Batch update STATE.md fields
|
|
17
|
+
* state begin-phase --phase N --name S --plans C Update STATE.md for new phase start
|
|
18
|
+
* state signal-waiting --type T --question Q --options "A|B" --phase P write WAITING.json signal
|
|
19
|
+
* state signal-resume Remove WAITING.json signal
|
|
17
20
|
* resolve-model <agent-type> Get model for agent based on profile
|
|
18
21
|
* find-phase <phase> Find phase directory by number
|
|
19
|
-
* commit <message> [--files f1 f2] Commit planning docs
|
|
22
|
+
* commit <message> [--files f1 f2] [--no-verify] Commit planning docs
|
|
23
|
+
* commit-to-subrepo <msg> --files f1 f2 Route commits to sub-repos
|
|
20
24
|
* verify-summary <path> Verify a SUMMARY.md file
|
|
21
25
|
* generate-slug <text> Convert text to URL-safe slug
|
|
22
26
|
* current-timestamp [format] Get timestamp (full|date|filename)
|
|
@@ -32,7 +36,7 @@
|
|
|
32
36
|
*
|
|
33
37
|
* Phase Operations:
|
|
34
38
|
* phase next-decimal <phase> Calculate next decimal phase number
|
|
35
|
-
* phase add <description>
|
|
39
|
+
* phase add <description> [--id ID] Append new phase to roadmap + create dir
|
|
36
40
|
* phase insert <after> <description> Insert decimal phase after existing
|
|
37
41
|
* phase remove <phase> [--force] Remove phase, renumber all subsequent
|
|
38
42
|
* phase complete <phase> Mark phase done, update state + roadmap
|
|
@@ -54,6 +58,7 @@
|
|
|
54
58
|
* Validation:
|
|
55
59
|
* validate consistency Check phase numbering, disk/roadmap sync
|
|
56
60
|
* validate health [--repair] Check .planning/ integrity, optionally repair
|
|
61
|
+
* validate agents Check GSD agent installation status
|
|
57
62
|
*
|
|
58
63
|
* Progress:
|
|
59
64
|
* progress [json|table|bar] Render progress in various formats
|
|
@@ -61,6 +66,10 @@
|
|
|
61
66
|
* Todos:
|
|
62
67
|
* todo complete <filename> Move todo from pending to completed
|
|
63
68
|
*
|
|
69
|
+
* UAT Audit:
|
|
70
|
+
* audit-uat Scan all phases for unresolved UAT/verification items
|
|
71
|
+
* uat render-checkpoint --file <path> Render the current UAT checkpoint block
|
|
72
|
+
*
|
|
64
73
|
* Scaffolding:
|
|
65
74
|
* scaffold context --phase <N> Create CONTEXT.md template
|
|
66
75
|
* scaffold uat --phase <N> Create UAT.md template
|
|
@@ -84,6 +93,7 @@
|
|
|
84
93
|
* verify commits <h1> [h2] ... Batch verify commit hashes
|
|
85
94
|
* verify artifacts <plan-file> Check must_haves.artifacts
|
|
86
95
|
* verify key-links <plan-file> Check must_haves.key_links
|
|
96
|
+
* verify schema-drift <phase> [--skip] Detect schema file changes without push
|
|
87
97
|
*
|
|
88
98
|
* Template Fill:
|
|
89
99
|
* template fill summary --phase N Create pre-filled SUMMARY.md
|
|
@@ -124,11 +134,15 @@
|
|
|
124
134
|
* init milestone-op All context for milestone operations
|
|
125
135
|
* init map-codebase All context for map-codebase workflow
|
|
126
136
|
* init progress All context for progress workflow
|
|
137
|
+
*
|
|
138
|
+
* Documentation:
|
|
139
|
+
* docs-init Project context for docs-update workflow
|
|
127
140
|
*/
|
|
128
141
|
|
|
129
142
|
const fs = require('fs');
|
|
130
143
|
const path = require('path');
|
|
131
|
-
const
|
|
144
|
+
const core = require('./lib/core.cjs');
|
|
145
|
+
const { error, findProjectRoot, getActiveWorkstream } = core;
|
|
132
146
|
const state = require('./lib/state.cjs');
|
|
133
147
|
const phase = require('./lib/phase.cjs');
|
|
134
148
|
const roadmap = require('./lib/roadmap.cjs');
|
|
@@ -139,6 +153,50 @@ const milestone = require('./lib/milestone.cjs');
|
|
|
139
153
|
const commands = require('./lib/commands.cjs');
|
|
140
154
|
const init = require('./lib/init.cjs');
|
|
141
155
|
const frontmatter = require('./lib/frontmatter.cjs');
|
|
156
|
+
const profilePipeline = require('./lib/profile-pipeline.cjs');
|
|
157
|
+
const profileOutput = require('./lib/profile-output.cjs');
|
|
158
|
+
const workstream = require('./lib/workstream.cjs');
|
|
159
|
+
const docs = require('./lib/docs.cjs');
|
|
160
|
+
|
|
161
|
+
// ─── Arg parsing helpers ──────────────────────────────────────────────────────
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Extract named --flag <value> pairs from an args array.
|
|
165
|
+
* Returns an object mapping flag names to their values (null if absent).
|
|
166
|
+
* Flags listed in `booleanFlags` are treated as boolean (no value consumed).
|
|
167
|
+
*
|
|
168
|
+
* parseNamedArgs(args, 'phase', 'plan') → { phase: '3', plan: '1' }
|
|
169
|
+
* parseNamedArgs(args, [], ['amend', 'force']) → { amend: true, force: false }
|
|
170
|
+
*/
|
|
171
|
+
function parseNamedArgs(args, valueFlags = [], booleanFlags = []) {
|
|
172
|
+
const result = {};
|
|
173
|
+
for (const flag of valueFlags) {
|
|
174
|
+
const idx = args.indexOf(`--${flag}`);
|
|
175
|
+
result[flag] = idx !== -1 && args[idx + 1] !== undefined && !args[idx + 1].startsWith('--')
|
|
176
|
+
? args[idx + 1]
|
|
177
|
+
: null;
|
|
178
|
+
}
|
|
179
|
+
for (const flag of booleanFlags) {
|
|
180
|
+
result[flag] = args.includes(`--${flag}`);
|
|
181
|
+
}
|
|
182
|
+
return result;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Collect all tokens after --flag until the next --flag or end of args.
|
|
187
|
+
* Handles multi-word values like --name Foo Bar Version 1.
|
|
188
|
+
* Returns null if the flag is absent.
|
|
189
|
+
*/
|
|
190
|
+
function parseMultiwordArg(args, flag) {
|
|
191
|
+
const idx = args.indexOf(`--${flag}`);
|
|
192
|
+
if (idx === -1) return null;
|
|
193
|
+
const tokens = [];
|
|
194
|
+
for (let i = idx + 1; i < args.length; i++) {
|
|
195
|
+
if (args[i].startsWith('--')) break;
|
|
196
|
+
tokens.push(args[i]);
|
|
197
|
+
}
|
|
198
|
+
return tokens.length > 0 ? tokens.join(' ') : null;
|
|
199
|
+
}
|
|
142
200
|
|
|
143
201
|
// ─── CLI Router ───────────────────────────────────────────────────────────────
|
|
144
202
|
|
|
@@ -165,16 +223,137 @@ async function main() {
|
|
|
165
223
|
error(`Invalid --cwd: ${cwd}`);
|
|
166
224
|
}
|
|
167
225
|
|
|
226
|
+
// Resolve worktree root: in a linked worktree, .planning/ lives in the main worktree.
|
|
227
|
+
// However, in monorepo worktrees where the subdirectory itself owns .planning/,
|
|
228
|
+
// skip worktree resolution — the CWD is already the correct project root.
|
|
229
|
+
const { resolveWorktreeRoot } = require('./lib/core.cjs');
|
|
230
|
+
if (!fs.existsSync(path.join(cwd, '.planning'))) {
|
|
231
|
+
const worktreeRoot = resolveWorktreeRoot(cwd);
|
|
232
|
+
if (worktreeRoot !== cwd) {
|
|
233
|
+
cwd = worktreeRoot;
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// Optional workstream override for parallel milestone work.
|
|
238
|
+
// Priority: --ws flag > GSD_WORKSTREAM env var > session-scoped pointer > shared legacy pointer > null
|
|
239
|
+
const wsEqArg = args.find(arg => arg.startsWith('--ws='));
|
|
240
|
+
const wsIdx = args.indexOf('--ws');
|
|
241
|
+
let ws = null;
|
|
242
|
+
if (wsEqArg) {
|
|
243
|
+
ws = wsEqArg.slice('--ws='.length).trim();
|
|
244
|
+
if (!ws) error('Missing value for --ws');
|
|
245
|
+
args.splice(args.indexOf(wsEqArg), 1);
|
|
246
|
+
} else if (wsIdx !== -1) {
|
|
247
|
+
ws = args[wsIdx + 1];
|
|
248
|
+
if (!ws || ws.startsWith('--')) error('Missing value for --ws');
|
|
249
|
+
args.splice(wsIdx, 2);
|
|
250
|
+
} else if (process.env.GSD_WORKSTREAM) {
|
|
251
|
+
ws = process.env.GSD_WORKSTREAM.trim();
|
|
252
|
+
} else {
|
|
253
|
+
ws = getActiveWorkstream(cwd);
|
|
254
|
+
}
|
|
255
|
+
// Validate workstream name to prevent path traversal attacks.
|
|
256
|
+
if (ws && !/^[a-zA-Z0-9_-]+$/.test(ws)) {
|
|
257
|
+
error('Invalid workstream name: must be alphanumeric, hyphens, and underscores only');
|
|
258
|
+
}
|
|
259
|
+
// Set env var so all modules (planningDir, planningPaths) auto-resolve workstream paths
|
|
260
|
+
if (ws) {
|
|
261
|
+
process.env.GSD_WORKSTREAM = ws;
|
|
262
|
+
}
|
|
263
|
+
|
|
168
264
|
const rawIndex = args.indexOf('--raw');
|
|
169
265
|
const raw = rawIndex !== -1;
|
|
170
266
|
if (rawIndex !== -1) args.splice(rawIndex, 1);
|
|
171
267
|
|
|
268
|
+
// --pick <name>: extract a single field from JSON output (replaces jq dependency).
|
|
269
|
+
// Supports dot-notation (e.g., --pick workflow.research) and bracket notation
|
|
270
|
+
// for arrays (e.g., --pick directories[-1]).
|
|
271
|
+
const pickIdx = args.indexOf('--pick');
|
|
272
|
+
let pickField = null;
|
|
273
|
+
if (pickIdx !== -1) {
|
|
274
|
+
pickField = args[pickIdx + 1];
|
|
275
|
+
if (!pickField || pickField.startsWith('--')) error('Missing value for --pick');
|
|
276
|
+
args.splice(pickIdx, 2);
|
|
277
|
+
}
|
|
278
|
+
|
|
172
279
|
const command = args[0];
|
|
173
280
|
|
|
174
281
|
if (!command) {
|
|
175
|
-
error('Usage: gsd-tools <command> [args] [--raw] [--cwd <path>]\nCommands: state, resolve-model, find-phase, commit, verify-summary, verify, frontmatter, template, generate-slug, current-timestamp, list-todos, verify-path-exists, config-ensure-section, init');
|
|
282
|
+
error('Usage: gsd-tools <command> [args] [--raw] [--pick <field>] [--cwd <path>] [--ws <name>]\nCommands: state, resolve-model, find-phase, commit, verify-summary, verify, frontmatter, template, generate-slug, current-timestamp, list-todos, verify-path-exists, config-ensure-section, config-new-project, init, workstream, docs-init');
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
// Multi-repo guard: resolve project root for commands that read/write .planning/.
|
|
286
|
+
// Skip for pure-utility commands that don't touch .planning/ to avoid unnecessary
|
|
287
|
+
// filesystem traversal on every invocation.
|
|
288
|
+
const SKIP_ROOT_RESOLUTION = new Set([
|
|
289
|
+
'generate-slug', 'current-timestamp', 'verify-path-exists',
|
|
290
|
+
'verify-summary', 'template', 'frontmatter',
|
|
291
|
+
]);
|
|
292
|
+
if (!SKIP_ROOT_RESOLUTION.has(command)) {
|
|
293
|
+
cwd = findProjectRoot(cwd);
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
// When --pick is active, intercept stdout to extract the requested field.
|
|
297
|
+
if (pickField) {
|
|
298
|
+
const origWriteSync = fs.writeSync;
|
|
299
|
+
const chunks = [];
|
|
300
|
+
fs.writeSync = function (fd, data, ...rest) {
|
|
301
|
+
if (fd === 1) { chunks.push(String(data)); return; }
|
|
302
|
+
return origWriteSync.call(fs, fd, data, ...rest);
|
|
303
|
+
};
|
|
304
|
+
const cleanup = () => {
|
|
305
|
+
fs.writeSync = origWriteSync;
|
|
306
|
+
const captured = chunks.join('');
|
|
307
|
+
let jsonStr = captured;
|
|
308
|
+
if (jsonStr.startsWith('@file:')) {
|
|
309
|
+
jsonStr = fs.readFileSync(jsonStr.slice(6), 'utf-8');
|
|
310
|
+
}
|
|
311
|
+
try {
|
|
312
|
+
const obj = JSON.parse(jsonStr);
|
|
313
|
+
const value = extractField(obj, pickField);
|
|
314
|
+
const result = value === null || value === undefined ? '' : String(value);
|
|
315
|
+
origWriteSync.call(fs, 1, result);
|
|
316
|
+
} catch {
|
|
317
|
+
origWriteSync.call(fs, 1, captured);
|
|
318
|
+
}
|
|
319
|
+
};
|
|
320
|
+
try {
|
|
321
|
+
await runCommand(command, args, cwd, raw);
|
|
322
|
+
cleanup();
|
|
323
|
+
} catch (e) {
|
|
324
|
+
fs.writeSync = origWriteSync;
|
|
325
|
+
throw e;
|
|
326
|
+
}
|
|
327
|
+
return;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
await runCommand(command, args, cwd, raw);
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
/**
|
|
334
|
+
* Extract a field from an object using dot-notation and bracket syntax.
|
|
335
|
+
* Supports: 'field', 'parent.child', 'arr[-1]', 'arr[0]'
|
|
336
|
+
*/
|
|
337
|
+
function extractField(obj, fieldPath) {
|
|
338
|
+
const parts = fieldPath.split('.');
|
|
339
|
+
let current = obj;
|
|
340
|
+
for (const part of parts) {
|
|
341
|
+
if (current === null || current === undefined) return undefined;
|
|
342
|
+
const bracketMatch = part.match(/^(.+?)\[(-?\d+)]$/);
|
|
343
|
+
if (bracketMatch) {
|
|
344
|
+
const key = bracketMatch[1];
|
|
345
|
+
const index = parseInt(bracketMatch[2], 10);
|
|
346
|
+
current = current[key];
|
|
347
|
+
if (!Array.isArray(current)) return undefined;
|
|
348
|
+
current = index < 0 ? current[current.length + index] : current[index];
|
|
349
|
+
} else {
|
|
350
|
+
current = current[part];
|
|
351
|
+
}
|
|
176
352
|
}
|
|
353
|
+
return current;
|
|
354
|
+
}
|
|
177
355
|
|
|
356
|
+
async function runCommand(command, args, cwd, raw) {
|
|
178
357
|
switch (command) {
|
|
179
358
|
case 'state': {
|
|
180
359
|
const subcommand = args[1];
|
|
@@ -197,50 +376,37 @@ async function main() {
|
|
|
197
376
|
} else if (subcommand === 'advance-plan') {
|
|
198
377
|
state.cmdStateAdvancePlan(cwd, raw);
|
|
199
378
|
} else if (subcommand === 'record-metric') {
|
|
200
|
-
const
|
|
201
|
-
|
|
202
|
-
const durationIdx = args.indexOf('--duration');
|
|
203
|
-
const tasksIdx = args.indexOf('--tasks');
|
|
204
|
-
const filesIdx = args.indexOf('--files');
|
|
205
|
-
state.cmdStateRecordMetric(cwd, {
|
|
206
|
-
phase: phaseIdx !== -1 ? args[phaseIdx + 1] : null,
|
|
207
|
-
plan: planIdx !== -1 ? args[planIdx + 1] : null,
|
|
208
|
-
duration: durationIdx !== -1 ? args[durationIdx + 1] : null,
|
|
209
|
-
tasks: tasksIdx !== -1 ? args[tasksIdx + 1] : null,
|
|
210
|
-
files: filesIdx !== -1 ? args[filesIdx + 1] : null,
|
|
211
|
-
}, raw);
|
|
379
|
+
const { phase: p, plan, duration, tasks, files } = parseNamedArgs(args, ['phase', 'plan', 'duration', 'tasks', 'files']);
|
|
380
|
+
state.cmdStateRecordMetric(cwd, { phase: p, plan, duration, tasks, files }, raw);
|
|
212
381
|
} else if (subcommand === 'update-progress') {
|
|
213
382
|
state.cmdStateUpdateProgress(cwd, raw);
|
|
214
383
|
} else if (subcommand === 'add-decision') {
|
|
215
|
-
const
|
|
216
|
-
|
|
217
|
-
const summaryFileIdx = args.indexOf('--summary-file');
|
|
218
|
-
const rationaleIdx = args.indexOf('--rationale');
|
|
219
|
-
const rationaleFileIdx = args.indexOf('--rationale-file');
|
|
220
|
-
state.cmdStateAddDecision(cwd, {
|
|
221
|
-
phase: phaseIdx !== -1 ? args[phaseIdx + 1] : null,
|
|
222
|
-
summary: summaryIdx !== -1 ? args[summaryIdx + 1] : null,
|
|
223
|
-
summary_file: summaryFileIdx !== -1 ? args[summaryFileIdx + 1] : null,
|
|
224
|
-
rationale: rationaleIdx !== -1 ? args[rationaleIdx + 1] : '',
|
|
225
|
-
rationale_file: rationaleFileIdx !== -1 ? args[rationaleFileIdx + 1] : null,
|
|
226
|
-
}, raw);
|
|
384
|
+
const { phase: p, summary, 'summary-file': summary_file, rationale, 'rationale-file': rationale_file } = parseNamedArgs(args, ['phase', 'summary', 'summary-file', 'rationale', 'rationale-file']);
|
|
385
|
+
state.cmdStateAddDecision(cwd, { phase: p, summary, summary_file, rationale: rationale || '', rationale_file }, raw);
|
|
227
386
|
} else if (subcommand === 'add-blocker') {
|
|
228
|
-
const
|
|
229
|
-
|
|
230
|
-
state.cmdStateAddBlocker(cwd, {
|
|
231
|
-
text: textIdx !== -1 ? args[textIdx + 1] : null,
|
|
232
|
-
text_file: textFileIdx !== -1 ? args[textFileIdx + 1] : null,
|
|
233
|
-
}, raw);
|
|
387
|
+
const { text, 'text-file': text_file } = parseNamedArgs(args, ['text', 'text-file']);
|
|
388
|
+
state.cmdStateAddBlocker(cwd, { text, text_file }, raw);
|
|
234
389
|
} else if (subcommand === 'resolve-blocker') {
|
|
235
|
-
|
|
236
|
-
state.cmdStateResolveBlocker(cwd, textIdx !== -1 ? args[textIdx + 1] : null, raw);
|
|
390
|
+
state.cmdStateResolveBlocker(cwd, parseNamedArgs(args, ['text']).text, raw);
|
|
237
391
|
} else if (subcommand === 'record-session') {
|
|
238
|
-
const
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
392
|
+
const { 'stopped-at': stopped_at, 'resume-file': resume_file } = parseNamedArgs(args, ['stopped-at', 'resume-file']);
|
|
393
|
+
state.cmdStateRecordSession(cwd, { stopped_at, resume_file: resume_file || 'None' }, raw);
|
|
394
|
+
} else if (subcommand === 'begin-phase') {
|
|
395
|
+
const { phase: p, name, plans } = parseNamedArgs(args, ['phase', 'name', 'plans']);
|
|
396
|
+
state.cmdStateBeginPhase(cwd, p, name, plans !== null ? parseInt(plans, 10) : null, raw);
|
|
397
|
+
} else if (subcommand === 'signal-waiting') {
|
|
398
|
+
const { type, question, options, phase: p } = parseNamedArgs(args, ['type', 'question', 'options', 'phase']);
|
|
399
|
+
state.cmdSignalWaiting(cwd, type, question, options, p, raw);
|
|
400
|
+
} else if (subcommand === 'signal-resume') {
|
|
401
|
+
state.cmdSignalResume(cwd, raw);
|
|
402
|
+
} else if (subcommand === 'planned-phase') {
|
|
403
|
+
const { phase: p, name, plans } = parseNamedArgs(args, ['phase', 'name', 'plans']);
|
|
404
|
+
state.cmdStatePlannedPhase(cwd, p, plans !== null ? parseInt(plans, 10) : null, raw);
|
|
405
|
+
} else if (subcommand === 'validate') {
|
|
406
|
+
state.cmdStateValidate(cwd, raw);
|
|
407
|
+
} else if (subcommand === 'sync') {
|
|
408
|
+
const { verify } = parseNamedArgs(args, [], ['verify']);
|
|
409
|
+
state.cmdStateSync(cwd, { verify }, raw);
|
|
244
410
|
} else {
|
|
245
411
|
state.cmdStateLoad(cwd, raw);
|
|
246
412
|
}
|
|
@@ -259,6 +425,7 @@ async function main() {
|
|
|
259
425
|
|
|
260
426
|
case 'commit': {
|
|
261
427
|
const amend = args.includes('--amend');
|
|
428
|
+
const noVerify = args.includes('--no-verify');
|
|
262
429
|
const filesIndex = args.indexOf('--files');
|
|
263
430
|
// Collect all positional args between command name and first flag,
|
|
264
431
|
// then join them — handles both quoted ("multi word msg") and
|
|
@@ -267,7 +434,20 @@ async function main() {
|
|
|
267
434
|
const messageArgs = args.slice(1, endIndex).filter(a => !a.startsWith('--'));
|
|
268
435
|
const message = messageArgs.join(' ') || undefined;
|
|
269
436
|
const files = filesIndex !== -1 ? args.slice(filesIndex + 1).filter(a => !a.startsWith('--')) : [];
|
|
270
|
-
commands.cmdCommit(cwd, message, files, raw, amend);
|
|
437
|
+
commands.cmdCommit(cwd, message, files, raw, amend, noVerify);
|
|
438
|
+
break;
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
case 'check-commit': {
|
|
442
|
+
commands.cmdCheckCommit(cwd, raw);
|
|
443
|
+
break;
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
case 'commit-to-subrepo': {
|
|
447
|
+
const message = args[1];
|
|
448
|
+
const filesIndex = args.indexOf('--files');
|
|
449
|
+
const files = filesIndex !== -1 ? args.slice(filesIndex + 1).filter(a => !a.startsWith('--')) : [];
|
|
450
|
+
commands.cmdCommitToSubrepo(cwd, message, files, raw);
|
|
271
451
|
break;
|
|
272
452
|
}
|
|
273
453
|
|
|
@@ -285,19 +465,18 @@ async function main() {
|
|
|
285
465
|
template.cmdTemplateSelect(cwd, args[2], raw);
|
|
286
466
|
} else if (subcommand === 'fill') {
|
|
287
467
|
const templateType = args[2];
|
|
288
|
-
const
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
468
|
+
const { phase, plan, name, type, wave, fields: fieldsRaw } = parseNamedArgs(args, ['phase', 'plan', 'name', 'type', 'wave', 'fields']);
|
|
469
|
+
let fields = {};
|
|
470
|
+
if (fieldsRaw) {
|
|
471
|
+
const { safeJsonParse } = require('./lib/security.cjs');
|
|
472
|
+
const result = safeJsonParse(fieldsRaw, { label: '--fields' });
|
|
473
|
+
if (!result.ok) error(result.error);
|
|
474
|
+
fields = result.value;
|
|
475
|
+
}
|
|
294
476
|
template.cmdTemplateFill(cwd, templateType, {
|
|
295
|
-
phase
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
type: typeIdx !== -1 ? args[typeIdx + 1] : 'execute',
|
|
299
|
-
wave: waveIdx !== -1 ? args[waveIdx + 1] : '1',
|
|
300
|
-
fields: fieldsIdx !== -1 ? JSON.parse(args[fieldsIdx + 1]) : {},
|
|
477
|
+
phase, plan, name, fields,
|
|
478
|
+
type: type || 'execute',
|
|
479
|
+
wave: wave || '1',
|
|
301
480
|
}, raw);
|
|
302
481
|
} else {
|
|
303
482
|
error('Unknown template subcommand. Available: select, fill');
|
|
@@ -309,18 +488,14 @@ async function main() {
|
|
|
309
488
|
const subcommand = args[1];
|
|
310
489
|
const file = args[2];
|
|
311
490
|
if (subcommand === 'get') {
|
|
312
|
-
|
|
313
|
-
frontmatter.cmdFrontmatterGet(cwd, file, fieldIdx !== -1 ? args[fieldIdx + 1] : null, raw);
|
|
491
|
+
frontmatter.cmdFrontmatterGet(cwd, file, parseNamedArgs(args, ['field']).field, raw);
|
|
314
492
|
} else if (subcommand === 'set') {
|
|
315
|
-
const
|
|
316
|
-
|
|
317
|
-
frontmatter.cmdFrontmatterSet(cwd, file, fieldIdx !== -1 ? args[fieldIdx + 1] : null, valueIdx !== -1 ? args[valueIdx + 1] : undefined, raw);
|
|
493
|
+
const { field, value } = parseNamedArgs(args, ['field', 'value']);
|
|
494
|
+
frontmatter.cmdFrontmatterSet(cwd, file, field, value !== null ? value : undefined, raw);
|
|
318
495
|
} else if (subcommand === 'merge') {
|
|
319
|
-
|
|
320
|
-
frontmatter.cmdFrontmatterMerge(cwd, file, dataIdx !== -1 ? args[dataIdx + 1] : null, raw);
|
|
496
|
+
frontmatter.cmdFrontmatterMerge(cwd, file, parseNamedArgs(args, ['data']).data, raw);
|
|
321
497
|
} else if (subcommand === 'validate') {
|
|
322
|
-
|
|
323
|
-
frontmatter.cmdFrontmatterValidate(cwd, file, schemaIdx !== -1 ? args[schemaIdx + 1] : null, raw);
|
|
498
|
+
frontmatter.cmdFrontmatterValidate(cwd, file, parseNamedArgs(args, ['schema']).schema, raw);
|
|
324
499
|
} else {
|
|
325
500
|
error('Unknown frontmatter subcommand. Available: get, set, merge, validate');
|
|
326
501
|
}
|
|
@@ -341,8 +516,11 @@ async function main() {
|
|
|
341
516
|
verify.cmdVerifyArtifacts(cwd, args[2], raw);
|
|
342
517
|
} else if (subcommand === 'key-links') {
|
|
343
518
|
verify.cmdVerifyKeyLinks(cwd, args[2], raw);
|
|
519
|
+
} else if (subcommand === 'schema-drift') {
|
|
520
|
+
const skipFlag = args.includes('--skip');
|
|
521
|
+
verify.cmdVerifySchemaDrift(cwd, args[2], skipFlag, raw);
|
|
344
522
|
} else {
|
|
345
|
-
error('Unknown verify subcommand. Available: plan-structure, phase-completeness, references, commits, artifacts, key-links');
|
|
523
|
+
error('Unknown verify subcommand. Available: plan-structure, phase-completeness, references, commits, artifacts, key-links, schema-drift');
|
|
346
524
|
}
|
|
347
525
|
break;
|
|
348
526
|
}
|
|
@@ -377,11 +555,26 @@ async function main() {
|
|
|
377
555
|
break;
|
|
378
556
|
}
|
|
379
557
|
|
|
558
|
+
case "config-set-model-profile": {
|
|
559
|
+
config.cmdConfigSetModelProfile(cwd, args[1], raw);
|
|
560
|
+
break;
|
|
561
|
+
}
|
|
562
|
+
|
|
380
563
|
case 'config-get': {
|
|
381
564
|
config.cmdConfigGet(cwd, args[1], raw);
|
|
382
565
|
break;
|
|
383
566
|
}
|
|
384
567
|
|
|
568
|
+
case 'config-new-project': {
|
|
569
|
+
config.cmdConfigNewProject(cwd, args[1], raw);
|
|
570
|
+
break;
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
case 'agent-skills': {
|
|
574
|
+
init.cmdAgentSkills(cwd, args[1], raw);
|
|
575
|
+
break;
|
|
576
|
+
}
|
|
577
|
+
|
|
385
578
|
case 'history-digest': {
|
|
386
579
|
commands.cmdHistoryDigest(cwd, raw);
|
|
387
580
|
break;
|
|
@@ -398,8 +591,10 @@ async function main() {
|
|
|
398
591
|
includeArchived: args.includes('--include-archived'),
|
|
399
592
|
};
|
|
400
593
|
phase.cmdPhasesList(cwd, options, raw);
|
|
594
|
+
} else if (subcommand === 'clear') {
|
|
595
|
+
milestone.cmdPhasesClear(cwd, raw);
|
|
401
596
|
} else {
|
|
402
|
-
error('Unknown phases subcommand. Available: list');
|
|
597
|
+
error('Unknown phases subcommand. Available: list, clear');
|
|
403
598
|
}
|
|
404
599
|
break;
|
|
405
600
|
}
|
|
@@ -433,7 +628,18 @@ async function main() {
|
|
|
433
628
|
if (subcommand === 'next-decimal') {
|
|
434
629
|
phase.cmdPhaseNextDecimal(cwd, args[2], raw);
|
|
435
630
|
} else if (subcommand === 'add') {
|
|
436
|
-
|
|
631
|
+
const idIdx = args.indexOf('--id');
|
|
632
|
+
let customId = null;
|
|
633
|
+
const descArgs = [];
|
|
634
|
+
for (let i = 2; i < args.length; i++) {
|
|
635
|
+
if (args[i] === '--id' && i + 1 < args.length) {
|
|
636
|
+
customId = args[i + 1];
|
|
637
|
+
i++; // skip value
|
|
638
|
+
} else {
|
|
639
|
+
descArgs.push(args[i]);
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
phase.cmdPhaseAdd(cwd, descArgs.join(' '), raw, customId);
|
|
437
643
|
} else if (subcommand === 'insert') {
|
|
438
644
|
phase.cmdPhaseInsert(cwd, args[2], args.slice(3).join(' '), raw);
|
|
439
645
|
} else if (subcommand === 'remove') {
|
|
@@ -450,18 +656,8 @@ async function main() {
|
|
|
450
656
|
case 'milestone': {
|
|
451
657
|
const subcommand = args[1];
|
|
452
658
|
if (subcommand === 'complete') {
|
|
453
|
-
const
|
|
659
|
+
const milestoneName = parseMultiwordArg(args, 'name');
|
|
454
660
|
const archivePhases = args.includes('--archive-phases');
|
|
455
|
-
// Collect --name value (everything after --name until next flag or end)
|
|
456
|
-
let milestoneName = null;
|
|
457
|
-
if (nameIndex !== -1) {
|
|
458
|
-
const nameArgs = [];
|
|
459
|
-
for (let i = nameIndex + 1; i < args.length; i++) {
|
|
460
|
-
if (args[i].startsWith('--')) break;
|
|
461
|
-
nameArgs.push(args[i]);
|
|
462
|
-
}
|
|
463
|
-
milestoneName = nameArgs.join(' ') || null;
|
|
464
|
-
}
|
|
465
661
|
milestone.cmdMilestoneComplete(cwd, args[2], { name: milestoneName, archivePhases }, raw);
|
|
466
662
|
} else {
|
|
467
663
|
error('Unknown milestone subcommand. Available: complete');
|
|
@@ -476,8 +672,10 @@ async function main() {
|
|
|
476
672
|
} else if (subcommand === 'health') {
|
|
477
673
|
const repairFlag = args.includes('--repair');
|
|
478
674
|
verify.cmdValidateHealth(cwd, { repair: repairFlag }, raw);
|
|
675
|
+
} else if (subcommand === 'agents') {
|
|
676
|
+
verify.cmdValidateAgents(cwd, raw);
|
|
479
677
|
} else {
|
|
480
|
-
error('Unknown validate subcommand. Available: consistency, health');
|
|
678
|
+
error('Unknown validate subcommand. Available: consistency, health, agents');
|
|
481
679
|
}
|
|
482
680
|
break;
|
|
483
681
|
}
|
|
@@ -488,23 +686,47 @@ async function main() {
|
|
|
488
686
|
break;
|
|
489
687
|
}
|
|
490
688
|
|
|
689
|
+
case 'audit-uat': {
|
|
690
|
+
const uat = require('./lib/uat.cjs');
|
|
691
|
+
uat.cmdAuditUat(cwd, raw);
|
|
692
|
+
break;
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
case 'uat': {
|
|
696
|
+
const subcommand = args[1];
|
|
697
|
+
const uat = require('./lib/uat.cjs');
|
|
698
|
+
if (subcommand === 'render-checkpoint') {
|
|
699
|
+
const options = parseNamedArgs(args, ['file']);
|
|
700
|
+
uat.cmdRenderCheckpoint(cwd, options, raw);
|
|
701
|
+
} else {
|
|
702
|
+
error('Unknown uat subcommand. Available: render-checkpoint');
|
|
703
|
+
}
|
|
704
|
+
break;
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
case 'stats': {
|
|
708
|
+
const subcommand = args[1] || 'json';
|
|
709
|
+
commands.cmdStats(cwd, subcommand, raw);
|
|
710
|
+
break;
|
|
711
|
+
}
|
|
712
|
+
|
|
491
713
|
case 'todo': {
|
|
492
714
|
const subcommand = args[1];
|
|
493
715
|
if (subcommand === 'complete') {
|
|
494
716
|
commands.cmdTodoComplete(cwd, args[2], raw);
|
|
717
|
+
} else if (subcommand === 'match-phase') {
|
|
718
|
+
commands.cmdTodoMatchPhase(cwd, args[2], raw);
|
|
495
719
|
} else {
|
|
496
|
-
error('Unknown todo subcommand. Available: complete');
|
|
720
|
+
error('Unknown todo subcommand. Available: complete, match-phase');
|
|
497
721
|
}
|
|
498
722
|
break;
|
|
499
723
|
}
|
|
500
724
|
|
|
501
725
|
case 'scaffold': {
|
|
502
726
|
const scaffoldType = args[1];
|
|
503
|
-
const phaseIndex = args.indexOf('--phase');
|
|
504
|
-
const nameIndex = args.indexOf('--name');
|
|
505
727
|
const scaffoldOptions = {
|
|
506
|
-
phase:
|
|
507
|
-
name:
|
|
728
|
+
phase: parseNamedArgs(args, ['phase']).phase,
|
|
729
|
+
name: parseMultiwordArg(args, 'name'),
|
|
508
730
|
};
|
|
509
731
|
commands.cmdScaffold(cwd, scaffoldType, scaffoldOptions, raw);
|
|
510
732
|
break;
|
|
@@ -513,12 +735,16 @@ async function main() {
|
|
|
513
735
|
case 'init': {
|
|
514
736
|
const workflow = args[1];
|
|
515
737
|
switch (workflow) {
|
|
516
|
-
case 'execute-phase':
|
|
517
|
-
|
|
738
|
+
case 'execute-phase': {
|
|
739
|
+
const { validate: epValidate } = parseNamedArgs(args, [], ['validate']);
|
|
740
|
+
init.cmdInitExecutePhase(cwd, args[2], raw, { validate: epValidate });
|
|
518
741
|
break;
|
|
519
|
-
|
|
520
|
-
|
|
742
|
+
}
|
|
743
|
+
case 'plan-phase': {
|
|
744
|
+
const { validate: ppValidate } = parseNamedArgs(args, [], ['validate']);
|
|
745
|
+
init.cmdInitPlanPhase(cwd, args[2], raw, { validate: ppValidate });
|
|
521
746
|
break;
|
|
747
|
+
}
|
|
522
748
|
case 'new-project':
|
|
523
749
|
init.cmdInitNewProject(cwd, raw);
|
|
524
750
|
break;
|
|
@@ -549,8 +775,20 @@ async function main() {
|
|
|
549
775
|
case 'progress':
|
|
550
776
|
init.cmdInitProgress(cwd, raw);
|
|
551
777
|
break;
|
|
778
|
+
case 'manager':
|
|
779
|
+
init.cmdInitManager(cwd, raw);
|
|
780
|
+
break;
|
|
781
|
+
case 'new-workspace':
|
|
782
|
+
init.cmdInitNewWorkspace(cwd, raw);
|
|
783
|
+
break;
|
|
784
|
+
case 'list-workspaces':
|
|
785
|
+
init.cmdInitListWorkspaces(cwd, raw);
|
|
786
|
+
break;
|
|
787
|
+
case 'remove-workspace':
|
|
788
|
+
init.cmdInitRemoveWorkspace(cwd, args[2], raw);
|
|
789
|
+
break;
|
|
552
790
|
default:
|
|
553
|
-
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`);
|
|
791
|
+
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, manager, new-workspace, list-workspaces, remove-workspace`);
|
|
554
792
|
}
|
|
555
793
|
break;
|
|
556
794
|
}
|
|
@@ -584,6 +822,128 @@ async function main() {
|
|
|
584
822
|
break;
|
|
585
823
|
}
|
|
586
824
|
|
|
825
|
+
// ─── Profiling Pipeline ────────────────────────────────────────────────
|
|
826
|
+
|
|
827
|
+
case 'scan-sessions': {
|
|
828
|
+
const pathIdx = args.indexOf('--path');
|
|
829
|
+
const sessionsPath = pathIdx !== -1 ? args[pathIdx + 1] : null;
|
|
830
|
+
const verboseFlag = args.includes('--verbose');
|
|
831
|
+
const jsonFlag = args.includes('--json');
|
|
832
|
+
await profilePipeline.cmdScanSessions(sessionsPath, { verbose: verboseFlag, json: jsonFlag }, raw);
|
|
833
|
+
break;
|
|
834
|
+
}
|
|
835
|
+
|
|
836
|
+
case 'extract-messages': {
|
|
837
|
+
const sessionIdx = args.indexOf('--session');
|
|
838
|
+
const sessionId = sessionIdx !== -1 ? args[sessionIdx + 1] : null;
|
|
839
|
+
const limitIdx = args.indexOf('--limit');
|
|
840
|
+
const limit = limitIdx !== -1 ? parseInt(args[limitIdx + 1], 10) : null;
|
|
841
|
+
const pathIdx = args.indexOf('--path');
|
|
842
|
+
const sessionsPath = pathIdx !== -1 ? args[pathIdx + 1] : null;
|
|
843
|
+
const projectArg = args[1];
|
|
844
|
+
if (!projectArg || projectArg.startsWith('--')) {
|
|
845
|
+
error('Usage: gsd-tools extract-messages <project> [--session <id>] [--limit N] [--path <dir>]\nRun scan-sessions first to see available projects.');
|
|
846
|
+
}
|
|
847
|
+
await profilePipeline.cmdExtractMessages(projectArg, { sessionId, limit }, raw, sessionsPath);
|
|
848
|
+
break;
|
|
849
|
+
}
|
|
850
|
+
|
|
851
|
+
case 'profile-sample': {
|
|
852
|
+
const pathIdx = args.indexOf('--path');
|
|
853
|
+
const sessionsPath = pathIdx !== -1 ? args[pathIdx + 1] : null;
|
|
854
|
+
const limitIdx = args.indexOf('--limit');
|
|
855
|
+
const limit = limitIdx !== -1 ? parseInt(args[limitIdx + 1], 10) : 150;
|
|
856
|
+
const maxPerIdx = args.indexOf('--max-per-project');
|
|
857
|
+
const maxPerProject = maxPerIdx !== -1 ? parseInt(args[maxPerIdx + 1], 10) : null;
|
|
858
|
+
const maxCharsIdx = args.indexOf('--max-chars');
|
|
859
|
+
const maxChars = maxCharsIdx !== -1 ? parseInt(args[maxCharsIdx + 1], 10) : 500;
|
|
860
|
+
await profilePipeline.cmdProfileSample(sessionsPath, { limit, maxPerProject, maxChars }, raw);
|
|
861
|
+
break;
|
|
862
|
+
}
|
|
863
|
+
|
|
864
|
+
// ─── Profile Output ──────────────────────────────────────────────────
|
|
865
|
+
|
|
866
|
+
case 'write-profile': {
|
|
867
|
+
const inputIdx = args.indexOf('--input');
|
|
868
|
+
const inputPath = inputIdx !== -1 ? args[inputIdx + 1] : null;
|
|
869
|
+
if (!inputPath) error('--input <analysis-json-path> is required');
|
|
870
|
+
const outputIdx = args.indexOf('--output');
|
|
871
|
+
const outputPath = outputIdx !== -1 ? args[outputIdx + 1] : null;
|
|
872
|
+
profileOutput.cmdWriteProfile(cwd, { input: inputPath, output: outputPath }, raw);
|
|
873
|
+
break;
|
|
874
|
+
}
|
|
875
|
+
|
|
876
|
+
case 'profile-questionnaire': {
|
|
877
|
+
const answersIdx = args.indexOf('--answers');
|
|
878
|
+
const answers = answersIdx !== -1 ? args[answersIdx + 1] : null;
|
|
879
|
+
profileOutput.cmdProfileQuestionnaire({ answers }, raw);
|
|
880
|
+
break;
|
|
881
|
+
}
|
|
882
|
+
|
|
883
|
+
case 'generate-dev-preferences': {
|
|
884
|
+
const analysisIdx = args.indexOf('--analysis');
|
|
885
|
+
const analysisPath = analysisIdx !== -1 ? args[analysisIdx + 1] : null;
|
|
886
|
+
const outputIdx = args.indexOf('--output');
|
|
887
|
+
const outputPath = outputIdx !== -1 ? args[outputIdx + 1] : null;
|
|
888
|
+
const stackIdx = args.indexOf('--stack');
|
|
889
|
+
const stack = stackIdx !== -1 ? args[stackIdx + 1] : null;
|
|
890
|
+
profileOutput.cmdGenerateDevPreferences(cwd, { analysis: analysisPath, output: outputPath, stack }, raw);
|
|
891
|
+
break;
|
|
892
|
+
}
|
|
893
|
+
|
|
894
|
+
case 'generate-OpenCode-profile': {
|
|
895
|
+
const analysisIdx = args.indexOf('--analysis');
|
|
896
|
+
const analysisPath = analysisIdx !== -1 ? args[analysisIdx + 1] : null;
|
|
897
|
+
const outputIdx = args.indexOf('--output');
|
|
898
|
+
const outputPath = outputIdx !== -1 ? args[outputIdx + 1] : null;
|
|
899
|
+
const globalFlag = args.includes('--global');
|
|
900
|
+
profileOutput.cmdGenerateClaudeProfile(cwd, { analysis: analysisPath, output: outputPath, global: globalFlag }, raw);
|
|
901
|
+
break;
|
|
902
|
+
}
|
|
903
|
+
|
|
904
|
+
case 'generate-OpenCode-md': {
|
|
905
|
+
const outputIdx = args.indexOf('--output');
|
|
906
|
+
const outputPath = outputIdx !== -1 ? args[outputIdx + 1] : null;
|
|
907
|
+
const autoFlag = args.includes('--auto');
|
|
908
|
+
const forceFlag = args.includes('--force');
|
|
909
|
+
profileOutput.cmdGenerateClaudeMd(cwd, { output: outputPath, auto: autoFlag, force: forceFlag }, raw);
|
|
910
|
+
break;
|
|
911
|
+
}
|
|
912
|
+
|
|
913
|
+
case 'workstream': {
|
|
914
|
+
const subcommand = args[1];
|
|
915
|
+
if (subcommand === 'create') {
|
|
916
|
+
const migrateNameIdx = args.indexOf('--migrate-name');
|
|
917
|
+
const noMigrate = args.includes('--no-migrate');
|
|
918
|
+
workstream.cmdWorkstreamCreate(cwd, args[2], {
|
|
919
|
+
migrate: !noMigrate,
|
|
920
|
+
migrateName: migrateNameIdx !== -1 ? args[migrateNameIdx + 1] : null,
|
|
921
|
+
}, raw);
|
|
922
|
+
} else if (subcommand === 'list') {
|
|
923
|
+
workstream.cmdWorkstreamList(cwd, raw);
|
|
924
|
+
} else if (subcommand === 'status') {
|
|
925
|
+
workstream.cmdWorkstreamStatus(cwd, args[2], raw);
|
|
926
|
+
} else if (subcommand === 'complete') {
|
|
927
|
+
workstream.cmdWorkstreamComplete(cwd, args[2], {}, raw);
|
|
928
|
+
} else if (subcommand === 'set') {
|
|
929
|
+
workstream.cmdWorkstreamSet(cwd, args[2], raw);
|
|
930
|
+
} else if (subcommand === 'get') {
|
|
931
|
+
workstream.cmdWorkstreamGet(cwd, raw);
|
|
932
|
+
} else if (subcommand === 'progress') {
|
|
933
|
+
workstream.cmdWorkstreamProgress(cwd, raw);
|
|
934
|
+
} else {
|
|
935
|
+
error('Unknown workstream subcommand. Available: create, list, status, complete, set, get, progress');
|
|
936
|
+
}
|
|
937
|
+
break;
|
|
938
|
+
}
|
|
939
|
+
|
|
940
|
+
// ─── Documentation ────────────────────────────────────────────────────
|
|
941
|
+
|
|
942
|
+
case 'docs-init': {
|
|
943
|
+
docs.cmdDocsInit(cwd, raw);
|
|
944
|
+
break;
|
|
945
|
+
}
|
|
946
|
+
|
|
587
947
|
default:
|
|
588
948
|
error(`Unknown command: ${command}`);
|
|
589
949
|
}
|