gswd 0.1.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.
Files changed (42) hide show
  1. package/agents/gswd/architecture-drafter.md +70 -0
  2. package/agents/gswd/brainstorm-alternatives.md +60 -0
  3. package/agents/gswd/devils-advocate.md +57 -0
  4. package/agents/gswd/icp-persona.md +58 -0
  5. package/agents/gswd/integrations-checker.md +68 -0
  6. package/agents/gswd/journey-mapper.md +69 -0
  7. package/agents/gswd/market-researcher.md +54 -0
  8. package/agents/gswd/positioning.md +54 -0
  9. package/bin/gswd-tools.cjs +716 -0
  10. package/lib/audit.ts +959 -0
  11. package/lib/bootstrap.ts +617 -0
  12. package/lib/compile.ts +940 -0
  13. package/lib/config.ts +164 -0
  14. package/lib/imagine-agents.ts +154 -0
  15. package/lib/imagine-gate.ts +156 -0
  16. package/lib/imagine-input.ts +242 -0
  17. package/lib/imagine-synthesis.ts +402 -0
  18. package/lib/imagine.ts +433 -0
  19. package/lib/parse.ts +196 -0
  20. package/lib/render.ts +200 -0
  21. package/lib/specify-agents.ts +332 -0
  22. package/lib/specify-journeys.ts +410 -0
  23. package/lib/specify-nfr.ts +208 -0
  24. package/lib/specify-roles.ts +122 -0
  25. package/lib/specify.ts +773 -0
  26. package/lib/state.ts +305 -0
  27. package/package.json +26 -0
  28. package/templates/gswd/ARCHITECTURE.template.md +17 -0
  29. package/templates/gswd/AUDIT.template.md +31 -0
  30. package/templates/gswd/COMPETITION.template.md +18 -0
  31. package/templates/gswd/DECISIONS.template.md +18 -0
  32. package/templates/gswd/GTM.template.md +18 -0
  33. package/templates/gswd/ICP.template.md +18 -0
  34. package/templates/gswd/IMAGINE.template.md +24 -0
  35. package/templates/gswd/INTEGRATIONS.template.md +7 -0
  36. package/templates/gswd/JOURNEYS.template.md +7 -0
  37. package/templates/gswd/NFR.template.md +7 -0
  38. package/templates/gswd/PROJECT.template.md +21 -0
  39. package/templates/gswd/REQUIREMENTS.template.md +31 -0
  40. package/templates/gswd/ROADMAP.template.md +21 -0
  41. package/templates/gswd/SPEC.template.md +19 -0
  42. package/templates/gswd/STATE.template.md +15 -0
@@ -0,0 +1,716 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * GSWD Tools — CLI utility for GSWD workflow operations
5
+ *
6
+ * Usage: node gswd-tools.cjs <command> [args]
7
+ *
8
+ * Commands:
9
+ * init [--project-slug <slug>] Initialize STATE.json + config.json
10
+ * status Show per-stage status
11
+ * state read Read STATE.json
12
+ * state update-stage <stage> <status> Update stage status
13
+ * state checkpoint <workflow> <id> Write checkpoint
14
+ * config read Read config.json gswd section
15
+ * config merge [--overrides json] Merge gswd config
16
+ * render banner <name> Render stage banner
17
+ * render checkpoint <json> Render checkpoint box
18
+ * render next-up <json> Render Next Up block
19
+ * id-allocate <type> <agent> [size] Allocate ID range
20
+ * id-ranges [type] Get allocated ranges
21
+ * id-reset Reset ID registry
22
+ * parse ids <file> [--type X] Extract IDs from file
23
+ * parse validate-headings <file> <type> Validate headings
24
+ * commit <message> [--files f1 f2] Commit planning docs
25
+ * imagine [@idea.md] [--auto] [--skip-research] Run Imagine workflow
26
+ * specify [--auto] [--skip-agents] Run Specify workflow
27
+ * audit [--auto-fix] Run Audit workflow
28
+ * compile Run Compile workflow
29
+ * bootstrap [@idea.md] [--auto] [--resume] [--skip-research] [--policy <name>] Run full pipeline
30
+ */
31
+
32
+ 'use strict';
33
+
34
+ const fs = require('fs');
35
+ const path = require('path');
36
+ const { execSync } = require('child_process');
37
+
38
+ // ─── Module Loading ──────────────────────────────────────────────────────────
39
+
40
+ /**
41
+ * Load a lib/ TypeScript module. Tries compiled dist/ first, falls back to
42
+ * tsx require hook for development.
43
+ */
44
+ function loadModule(name) {
45
+ const distPath = path.join(__dirname, '..', 'dist', 'lib', `${name}.js`);
46
+ const srcPath = path.join(__dirname, '..', 'lib', `${name}.ts`);
47
+
48
+ // Try compiled dist/ first
49
+ try {
50
+ return require(distPath);
51
+ } catch (_e) {
52
+ // Fall through
53
+ }
54
+
55
+ // Try tsx require hook (development mode)
56
+ try {
57
+ // Register tsx if not already registered
58
+ if (!global.__tsxRegistered) {
59
+ require('tsx/cjs');
60
+ global.__tsxRegistered = true;
61
+ }
62
+ return require(srcPath);
63
+ } catch (_e) {
64
+ // Fall through
65
+ }
66
+
67
+ // Try direct require of .ts (may work with ts-node or similar)
68
+ try {
69
+ return require(srcPath);
70
+ } catch (e) {
71
+ outputError(`Failed to load module '${name}'. Run 'npm run build' or ensure tsx is installed.\n${e.message}`);
72
+ process.exit(1);
73
+ }
74
+ }
75
+
76
+ // ─── Resolve Paths ───────────────────────────────────────────────────────────
77
+
78
+ const CWD = process.cwd();
79
+ const PLANNING_DIR = path.join(CWD, '.planning');
80
+ const GSWD_DIR = path.join(PLANNING_DIR, 'gswd');
81
+ const STATE_PATH = path.join(GSWD_DIR, 'STATE.json');
82
+ const CONFIG_PATH = path.join(PLANNING_DIR, 'config.json');
83
+
84
+ // ─── Output Helpers ──────────────────────────────────────────────────────────
85
+
86
+ function outputJson(data) {
87
+ process.stdout.write(JSON.stringify(data, null, 2) + '\n');
88
+ }
89
+
90
+ function outputError(message) {
91
+ process.stdout.write(JSON.stringify({ error: true, message }) + '\n');
92
+ }
93
+
94
+ function outputText(text) {
95
+ process.stdout.write(text + '\n');
96
+ }
97
+
98
+ // ─── Argument Parsing ────────────────────────────────────────────────────────
99
+
100
+ const args = process.argv.slice(2);
101
+ const command = args[0];
102
+ const subcommand = args[1];
103
+
104
+ function getFlag(flag) {
105
+ const idx = args.indexOf(flag);
106
+ if (idx === -1) return null;
107
+ return args[idx + 1] || null;
108
+ }
109
+
110
+ function hasFlag(flag) {
111
+ return args.includes(flag);
112
+ }
113
+
114
+ // ─── Command Dispatch ────────────────────────────────────────────────────────
115
+
116
+ function printUsage() {
117
+ outputText(`GSWD Tools — CLI utility for GSWD workflow operations
118
+
119
+ Usage: node gswd-tools.cjs <command> [args]
120
+
121
+ Commands:
122
+ init [--project-slug <slug>] Initialize STATE.json + config.json
123
+ status Show per-stage status
124
+ state read Read STATE.json
125
+ state update-stage <stage> <status> Update stage status
126
+ state checkpoint <workflow> <id> Write checkpoint
127
+ config read Read config.json gswd section
128
+ config merge [--overrides json] Merge gswd config
129
+ render banner <name> Render stage banner
130
+ render checkpoint <json> Render checkpoint box
131
+ render next-up <json> Render Next Up block
132
+ id-allocate <type> <agent> [size] Allocate ID range
133
+ id-ranges [type] Get allocated ranges
134
+ id-reset Reset ID registry
135
+ parse ids <file> [--type X] Extract IDs from file
136
+ parse validate-headings <file> <type> Validate headings
137
+ commit <message> [--files f1 f2] Commit planning docs
138
+ imagine [@idea.md] [--auto] [--skip-research] Run Imagine workflow
139
+ specify [--auto] [--skip-agents] Run Specify workflow
140
+ audit [--auto-fix] Run Audit workflow
141
+ compile Run Compile workflow
142
+ bootstrap [@idea.md] [--auto] [--resume] [--skip-research] [--policy <name>] Run full pipeline`);
143
+ }
144
+
145
+ try {
146
+ switch (command) {
147
+ case 'init':
148
+ handleInit();
149
+ break;
150
+ case 'status':
151
+ handleStatus();
152
+ break;
153
+ case 'state':
154
+ handleState();
155
+ break;
156
+ case 'config':
157
+ handleConfig();
158
+ break;
159
+ case 'render':
160
+ handleRender();
161
+ break;
162
+ case 'id-allocate':
163
+ handleIdAllocate();
164
+ break;
165
+ case 'id-ranges':
166
+ handleIdRanges();
167
+ break;
168
+ case 'id-reset':
169
+ handleIdReset();
170
+ break;
171
+ case 'parse':
172
+ handleParse();
173
+ break;
174
+ case 'commit':
175
+ handleCommit();
176
+ break;
177
+ case 'imagine':
178
+ handleImagine();
179
+ break;
180
+ case 'specify':
181
+ handleSpecify();
182
+ break;
183
+ case 'audit':
184
+ handleAudit();
185
+ break;
186
+ case 'compile':
187
+ handleCompile();
188
+ break;
189
+ case 'bootstrap':
190
+ handleBootstrap();
191
+ break;
192
+ case '--help':
193
+ case '-h':
194
+ case 'help':
195
+ printUsage();
196
+ break;
197
+ default:
198
+ if (!command) {
199
+ printUsage();
200
+ process.exit(1);
201
+ }
202
+ outputError(`Unknown command: ${command}`);
203
+ printUsage();
204
+ process.exit(1);
205
+ }
206
+ } catch (err) {
207
+ outputError(err.message || String(err));
208
+ process.exit(1);
209
+ }
210
+
211
+ // ─── Command Handlers ────────────────────────────────────────────────────────
212
+
213
+ function handleInit() {
214
+ const stateModule = loadModule('state');
215
+ const configModule = loadModule('config');
216
+
217
+ const slug = getFlag('--project-slug') || path.basename(CWD).toLowerCase().replace(/[^a-z0-9-]/g, '-');
218
+
219
+ const state = stateModule.initState(GSWD_DIR, slug);
220
+ configModule.mergeGswdConfig(CONFIG_PATH);
221
+
222
+ outputJson({
223
+ initialized: true,
224
+ state_path: path.relative(CWD, STATE_PATH),
225
+ config_path: path.relative(CWD, CONFIG_PATH),
226
+ project_slug: state.project_slug,
227
+ });
228
+ }
229
+
230
+ function handleStatus() {
231
+ const stateModule = loadModule('state');
232
+ const renderModule = loadModule('render');
233
+
234
+ const state = stateModule.readState(STATE_PATH);
235
+ if (!state) {
236
+ outputError('No STATE.json found. Run "gswd-tools.cjs init" first.');
237
+ process.exit(1);
238
+ }
239
+
240
+ const banner = renderModule.renderBanner('STATUS');
241
+
242
+ const stages = ['imagine', 'specify', 'audit', 'compile'];
243
+ const stageLines = stages.map(s => {
244
+ const status = state.stage_status[s] || 'not_started';
245
+ return renderModule.renderStatusLine(
246
+ s.charAt(0).toUpperCase() + s.slice(1),
247
+ status
248
+ );
249
+ });
250
+
251
+ // Calculate progress
252
+ const doneCount = stages.filter(s => {
253
+ const st = state.stage_status[s];
254
+ return st === 'done' || st === 'pass';
255
+ }).length;
256
+ const progressBar = renderModule.renderProgressBar(doneCount, stages.length);
257
+
258
+ const output = [
259
+ banner,
260
+ '',
261
+ ...stageLines,
262
+ '',
263
+ progressBar,
264
+ '',
265
+ 'Quick Links:',
266
+ ` STATE.json: ${path.relative(CWD, STATE_PATH)}`,
267
+ ` Config: ${path.relative(CWD, CONFIG_PATH)}`,
268
+ ].join('\n');
269
+
270
+ outputText(output);
271
+ }
272
+
273
+ function handleState() {
274
+ const stateModule = loadModule('state');
275
+
276
+ switch (subcommand) {
277
+ case 'read': {
278
+ const state = stateModule.readState(STATE_PATH);
279
+ if (!state) {
280
+ outputError('No valid STATE.json found.');
281
+ process.exit(1);
282
+ }
283
+ outputJson(state);
284
+ break;
285
+ }
286
+ case 'update-stage': {
287
+ const stage = args[2];
288
+ const status = args[3];
289
+ if (!stage || !status) {
290
+ outputError('Usage: state update-stage <stage> <status>');
291
+ process.exit(1);
292
+ }
293
+ stateModule.updateStageStatus(STATE_PATH, stage, status);
294
+ outputJson({ updated: true, stage, status });
295
+ break;
296
+ }
297
+ case 'checkpoint': {
298
+ const workflow = args[2];
299
+ const checkpointId = args[3];
300
+ if (!workflow || !checkpointId) {
301
+ outputError('Usage: state checkpoint <workflow> <checkpoint_id>');
302
+ process.exit(1);
303
+ }
304
+ stateModule.writeCheckpoint(STATE_PATH, workflow, checkpointId);
305
+ outputJson({ checkpoint_written: true, workflow, checkpoint_id: checkpointId });
306
+ break;
307
+ }
308
+ default:
309
+ outputError(`Unknown state subcommand: ${subcommand}`);
310
+ process.exit(1);
311
+ }
312
+ }
313
+
314
+ function handleConfig() {
315
+ const configModule = loadModule('config');
316
+
317
+ switch (subcommand) {
318
+ case 'read': {
319
+ const config = configModule.getGswdConfig(CONFIG_PATH);
320
+ outputJson(config);
321
+ break;
322
+ }
323
+ case 'merge': {
324
+ const overridesRaw = getFlag('--overrides');
325
+ let overrides;
326
+ if (overridesRaw) {
327
+ try {
328
+ overrides = JSON.parse(overridesRaw);
329
+ } catch {
330
+ outputError('Invalid JSON for --overrides');
331
+ process.exit(1);
332
+ }
333
+ }
334
+ configModule.mergeGswdConfig(CONFIG_PATH, overrides);
335
+ outputJson({ merged: true });
336
+ break;
337
+ }
338
+ default:
339
+ outputError(`Unknown config subcommand: ${subcommand}`);
340
+ process.exit(1);
341
+ }
342
+ }
343
+
344
+ function handleRender() {
345
+ const renderModule = loadModule('render');
346
+
347
+ switch (subcommand) {
348
+ case 'banner': {
349
+ const name = args[2];
350
+ if (!name) {
351
+ outputError('Usage: render banner <name>');
352
+ process.exit(1);
353
+ }
354
+ outputText(renderModule.renderBanner(name));
355
+ break;
356
+ }
357
+ case 'checkpoint': {
358
+ const jsonStr = args[2];
359
+ if (!jsonStr) {
360
+ outputError('Usage: render checkpoint <json>');
361
+ process.exit(1);
362
+ }
363
+ try {
364
+ const data = JSON.parse(jsonStr);
365
+ outputText(renderModule.renderCheckpoint(
366
+ data.type || 'Checkpoint',
367
+ data.context || '',
368
+ data.options || [],
369
+ data.action || 'Select an option'
370
+ ));
371
+ } catch {
372
+ outputError('Invalid JSON for checkpoint render');
373
+ process.exit(1);
374
+ }
375
+ break;
376
+ }
377
+ case 'next-up': {
378
+ const jsonStr = args[2];
379
+ if (!jsonStr) {
380
+ outputError('Usage: render next-up <json>');
381
+ process.exit(1);
382
+ }
383
+ try {
384
+ const data = JSON.parse(jsonStr);
385
+ outputText(renderModule.renderNextUp(
386
+ data.files || [],
387
+ data.next_command || '',
388
+ data.also_available
389
+ ));
390
+ } catch {
391
+ outputError('Invalid JSON for next-up render');
392
+ process.exit(1);
393
+ }
394
+ break;
395
+ }
396
+ default:
397
+ outputError(`Unknown render subcommand: ${subcommand}`);
398
+ process.exit(1);
399
+ }
400
+ }
401
+
402
+ function handleIdAllocate() {
403
+ const stateModule = loadModule('state');
404
+
405
+ const idType = args[1];
406
+ const agent = args[2];
407
+ const size = args[3] ? parseInt(args[3], 10) : undefined;
408
+
409
+ if (!idType || !agent) {
410
+ outputError('Usage: id-allocate <type> <agent> [size]');
411
+ process.exit(1);
412
+ }
413
+
414
+ const range = stateModule.allocateIdRange(STATE_PATH, idType, agent, size);
415
+ outputJson({ type: idType, agent, ...range });
416
+ }
417
+
418
+ function handleIdRanges() {
419
+ const stateModule = loadModule('state');
420
+ const idType = args[1] || undefined;
421
+ const ranges = stateModule.getIdRanges(STATE_PATH, idType);
422
+ outputJson(ranges);
423
+ }
424
+
425
+ function handleIdReset() {
426
+ const stateModule = loadModule('state');
427
+ stateModule.resetIdRegistry(STATE_PATH);
428
+ outputJson({ reset: true });
429
+ }
430
+
431
+ function handleParse() {
432
+ const parseModule = loadModule('parse');
433
+
434
+ switch (subcommand) {
435
+ case 'ids': {
436
+ const filePath = args[2];
437
+ if (!filePath) {
438
+ outputError('Usage: parse ids <file> [--type X]');
439
+ process.exit(1);
440
+ }
441
+ const resolvedPath = path.resolve(CWD, filePath);
442
+ if (!fs.existsSync(resolvedPath)) {
443
+ outputError(`File not found: ${resolvedPath}`);
444
+ process.exit(1);
445
+ }
446
+ const content = fs.readFileSync(resolvedPath, 'utf-8');
447
+ const idType = getFlag('--type') || undefined;
448
+ const ids = parseModule.extractIds(content, idType);
449
+ outputJson(ids);
450
+ break;
451
+ }
452
+ case 'validate-headings': {
453
+ const filePath = args[2];
454
+ const fileType = args[3];
455
+ if (!filePath || !fileType) {
456
+ outputError('Usage: parse validate-headings <file> <type>');
457
+ process.exit(1);
458
+ }
459
+ const resolvedPath = path.resolve(CWD, filePath);
460
+ if (!fs.existsSync(resolvedPath)) {
461
+ outputError(`File not found: ${resolvedPath}`);
462
+ process.exit(1);
463
+ }
464
+ const content = fs.readFileSync(resolvedPath, 'utf-8');
465
+ const result = parseModule.validateHeadings(content, fileType);
466
+ outputJson(result);
467
+ break;
468
+ }
469
+ default:
470
+ outputError(`Unknown parse subcommand: ${subcommand}`);
471
+ process.exit(1);
472
+ }
473
+ }
474
+
475
+ function handleCommit() {
476
+ const message = args[1];
477
+ if (!message) {
478
+ outputError('Usage: commit <message> [--files f1 f2]');
479
+ process.exit(1);
480
+ }
481
+
482
+ // Collect files to commit
483
+ let files = [];
484
+ const filesIdx = args.indexOf('--files');
485
+ if (filesIdx !== -1) {
486
+ files = args.slice(filesIdx + 1);
487
+ }
488
+
489
+ try {
490
+ if (files.length > 0) {
491
+ execSync(`git add ${files.map(f => `"${f}"`).join(' ')}`, {
492
+ cwd: CWD,
493
+ stdio: 'pipe',
494
+ });
495
+ }
496
+
497
+ const result = execSync(`git commit -m "${message.replace(/"/g, '\\"')}"`, {
498
+ cwd: CWD,
499
+ stdio: 'pipe',
500
+ encoding: 'utf-8',
501
+ });
502
+
503
+ // Extract commit hash
504
+ const hashMatch = result.match(/\[[\w-]+ ([a-f0-9]+)\]/);
505
+ const hash = hashMatch ? hashMatch[1] : 'unknown';
506
+
507
+ outputJson({
508
+ committed: true,
509
+ hash,
510
+ message,
511
+ files_staged: files.length > 0 ? files : 'all staged',
512
+ });
513
+ } catch (err) {
514
+ outputError(`Commit failed: ${err.message}`);
515
+ process.exit(1);
516
+ }
517
+ }
518
+
519
+ function handleImagine() {
520
+ const imagineModule = loadModule('imagine');
521
+
522
+ const autoMode = hasFlag('--auto');
523
+ const skipResearch = hasFlag('--skip-research');
524
+
525
+ // Find idea file: look for arg starting with @ or ending with .md
526
+ let ideaFilePath = null;
527
+ for (let i = 1; i < args.length; i++) {
528
+ const arg = args[i];
529
+ if (arg.startsWith('--')) continue;
530
+ if (arg.startsWith('@')) {
531
+ ideaFilePath = path.resolve(CWD, arg.slice(1));
532
+ break;
533
+ }
534
+ if (arg.endsWith('.md')) {
535
+ ideaFilePath = path.resolve(CWD, arg);
536
+ break;
537
+ }
538
+ }
539
+
540
+ if (!ideaFilePath) {
541
+ // No idea file — start interactive 3-question intake
542
+ const readline = require('readline');
543
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
544
+
545
+ rl.question('Vision -- what does it do? ', function(vision) {
546
+ rl.question('User -- who is it for? ', function(user) {
547
+ rl.question('Why now -- what is the opportunity? ', function(whyNow) {
548
+ rl.close();
549
+
550
+ const intakeOptions = {
551
+ intakeAnswers: { vision, user, whyNow },
552
+ autoMode,
553
+ skipResearch,
554
+ planningDir: PLANNING_DIR,
555
+ configPath: CONFIG_PATH,
556
+ };
557
+
558
+ imagineModule.runImagine(intakeOptions).then(function(result) {
559
+ outputJson(result);
560
+ if (result.status === 'error' || result.status === 'gate_failed') {
561
+ process.exit(1);
562
+ }
563
+ }).catch(function(err) {
564
+ outputError(err.message || String(err));
565
+ process.exit(1);
566
+ });
567
+ });
568
+ });
569
+ });
570
+ return;
571
+ }
572
+
573
+ const options = {
574
+ ideaFilePath,
575
+ autoMode,
576
+ skipResearch,
577
+ planningDir: PLANNING_DIR,
578
+ configPath: CONFIG_PATH,
579
+ };
580
+
581
+ // runImagine is async, handle with promise
582
+ imagineModule.runImagine(options).then(function(result) {
583
+ outputJson(result);
584
+ if (result.status === 'error' || result.status === 'gate_failed') {
585
+ process.exit(1);
586
+ }
587
+ }).catch(function(err) {
588
+ outputError(err.message || String(err));
589
+ process.exit(1);
590
+ });
591
+ }
592
+
593
+ function handleSpecify() {
594
+ const specifyModule = loadModule('specify');
595
+
596
+ const autoMode = hasFlag('--auto');
597
+ const skipAgents = hasFlag('--skip-agents');
598
+
599
+ const budgetFlag = getFlag('--integration-budget');
600
+ const integrationBudget = budgetFlag ? parseInt(budgetFlag, 10) : undefined;
601
+
602
+ const options = {
603
+ auto: autoMode,
604
+ skipAgents,
605
+ integrationBudget,
606
+ planningDir: PLANNING_DIR,
607
+ configPath: CONFIG_PATH,
608
+ };
609
+
610
+ // runSpecify is async, handle with promise
611
+ specifyModule.runSpecify(options).then(function(result) {
612
+ outputJson(result);
613
+ if (result.status === 'failed') {
614
+ process.exit(1);
615
+ }
616
+ }).catch(function(err) {
617
+ outputError(err.message || String(err));
618
+ process.exit(1);
619
+ });
620
+ }
621
+
622
+ function handleBootstrap() {
623
+ const bootstrapModule = loadModule('bootstrap');
624
+
625
+ const autoMode = hasFlag('--auto');
626
+ const resume = hasFlag('--resume');
627
+ const skipResearch = hasFlag('--skip-research');
628
+ const policyFlag = getFlag('--policy');
629
+
630
+ // Find idea file: @ prefix or .md extension (same logic as handleImagine)
631
+ let ideaFilePath = null;
632
+ for (let i = 1; i < args.length; i++) {
633
+ const arg = args[i];
634
+ if (arg.startsWith('--')) continue;
635
+ if (arg.startsWith('@')) {
636
+ ideaFilePath = path.resolve(CWD, arg.slice(1));
637
+ break;
638
+ }
639
+ if (arg.endsWith('.md')) {
640
+ ideaFilePath = path.resolve(CWD, arg);
641
+ break;
642
+ }
643
+ }
644
+
645
+ const options = {
646
+ ideaFilePath,
647
+ auto: autoMode,
648
+ resume,
649
+ skipResearch,
650
+ policy: policyFlag || undefined,
651
+ planningDir: PLANNING_DIR,
652
+ configPath: CONFIG_PATH,
653
+ };
654
+
655
+ bootstrapModule.runBootstrap(options).then(function(result) {
656
+ outputJson(result);
657
+ if (result.status === 'failed' || result.status === 'interrupted') {
658
+ process.exit(1);
659
+ }
660
+ }).catch(function(err) {
661
+ outputError(err.message || String(err));
662
+ process.exit(1);
663
+ });
664
+ }
665
+
666
+ function handleAudit() {
667
+ const auditModule = loadModule('audit');
668
+
669
+ const autoFix = hasFlag('--auto-fix');
670
+
671
+ try {
672
+ const result = auditModule.runAuditWorkflow({
673
+ planningDir: PLANNING_DIR,
674
+ statePath: STATE_PATH,
675
+ autoFix,
676
+ maxCycles: 2,
677
+ });
678
+
679
+ outputJson({
680
+ passed: result.passed,
681
+ autoFixCycles: result.autoFixCycles,
682
+ reportPath: result.reportPath,
683
+ });
684
+
685
+ if (!result.passed) {
686
+ process.exit(1);
687
+ }
688
+ } catch (err) {
689
+ outputError(err.message || String(err));
690
+ process.exit(1);
691
+ }
692
+ }
693
+
694
+ function handleCompile() {
695
+ const compileModule = loadModule('compile');
696
+
697
+ try {
698
+ const result = compileModule.runCompileWorkflow({
699
+ planningDir: PLANNING_DIR,
700
+ statePath: STATE_PATH,
701
+ });
702
+
703
+ outputJson({
704
+ passed: result.passed,
705
+ filesWritten: result.filesWritten,
706
+ error: result.error,
707
+ });
708
+
709
+ if (!result.passed) {
710
+ process.exit(1);
711
+ }
712
+ } catch (err) {
713
+ outputError(err.message || String(err));
714
+ process.exit(1);
715
+ }
716
+ }