chiefwiggum 1.3.52 → 1.3.55

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 (2) hide show
  1. package/dist/cli.cjs +712 -549
  2. package/package.json +1 -1
package/dist/cli.cjs CHANGED
@@ -300,54 +300,6 @@ var init_config = __esm({
300
300
  });
301
301
 
302
302
  // src/lib/claude.ts
303
- function getProjectBoardContext() {
304
- try {
305
- const owner = (0, import_node_child_process4.execSync)("gh repo view --json owner -q .owner.login", {
306
- encoding: "utf-8",
307
- stdio: ["pipe", "pipe", "pipe"],
308
- timeout: 3e4
309
- }).trim();
310
- const projectNumber = (0, import_node_child_process4.execSync)(
311
- "gh repo view --json projectsV2 -q '.projectsV2.Nodes[0].number'",
312
- { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"], timeout: 3e4 }
313
- ).trim();
314
- if (!projectNumber || projectNumber === "null") return null;
315
- const projectId = (0, import_node_child_process4.execSync)(
316
- "gh repo view --json projectsV2 -q '.projectsV2.Nodes[0].id'",
317
- { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"], timeout: 3e4 }
318
- ).trim();
319
- const fieldsOutput = (0, import_node_child_process4.execSync)(
320
- `gh project field-list ${projectNumber} --owner ${owner} --format json`,
321
- { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"], timeout: 3e4 }
322
- );
323
- const fields = JSON.parse(fieldsOutput);
324
- const statusField = fields.fields?.find((f) => f.name === "Status");
325
- if (!statusField) return null;
326
- const findOption = (names) => {
327
- for (const name of names) {
328
- const option = statusField.options?.find(
329
- (o) => o.name.toLowerCase() === name.toLowerCase()
330
- );
331
- if (option) return option;
332
- }
333
- return null;
334
- };
335
- const todoOption = findOption(["Todo", "To Do", "To do", "Backlog"]);
336
- const inProgressOption = findOption(["In Progress", "In progress", "Doing", "Active"]);
337
- const doneOption = findOption(["Done", "Completed", "Closed", "Finished"]);
338
- return {
339
- owner,
340
- projectNumber,
341
- projectId,
342
- statusFieldId: statusField.id,
343
- todoOptionId: todoOption?.id || "",
344
- inProgressOptionId: inProgressOption?.id || "",
345
- doneOptionId: doneOption?.id || ""
346
- };
347
- } catch {
348
- return null;
349
- }
350
- }
351
303
  async function runClaude(options) {
352
304
  const { prompt, streaming = false, onOutput } = options;
353
305
  const timeoutMs = options.timeoutMs || config.iterationTimeoutMinutes * 60 * 1e3;
@@ -440,8 +392,88 @@ async function runClaude(options) {
440
392
  });
441
393
  });
442
394
  }
443
- function getTodoTaskPrompt() {
444
- return `You are an autonomous coding agent. Complete ONE task from TODO.md.
395
+ async function runTaskIteration(iteration, prompt) {
396
+ let lastResult = {
397
+ success: false,
398
+ output: "",
399
+ error: "No attempts made"
400
+ };
401
+ for (let attempt = 1; attempt <= config.maxClaudeAttempts; attempt++) {
402
+ console.log(import_picocolors5.default.yellow(`Attempt ${attempt}/${config.maxClaudeAttempts}`));
403
+ const result = await runClaude({
404
+ prompt,
405
+ streaming: true,
406
+ onOutput: (line) => {
407
+ process.stdout.write(line);
408
+ if (!line.endsWith("\n")) {
409
+ process.stdout.write("\n");
410
+ }
411
+ }
412
+ });
413
+ lastResult = result;
414
+ if (result.success) {
415
+ return result;
416
+ }
417
+ const isTransient = result.output.includes("No messages returned") || result.output.includes("ECONNRESET") || result.output.includes("ETIMEDOUT") || result.error?.includes("ECONNRESET") || result.error?.includes("ETIMEDOUT");
418
+ if (isTransient && attempt < config.maxClaudeAttempts) {
419
+ console.log(import_picocolors5.default.yellow("Transient error, retrying..."));
420
+ await sleep(attempt * 5e3);
421
+ continue;
422
+ }
423
+ break;
424
+ }
425
+ return lastResult;
426
+ }
427
+ var import_node_child_process4, import_node_readline, import_picocolors5;
428
+ var init_claude = __esm({
429
+ "src/lib/claude.ts"() {
430
+ "use strict";
431
+ init_cjs_shims();
432
+ import_node_child_process4 = require("child_process");
433
+ import_node_readline = require("readline");
434
+ import_picocolors5 = __toESM(require("picocolors"), 1);
435
+ init_config();
436
+ init_process();
437
+ }
438
+ });
439
+
440
+ // src/lib/tracker/todo.ts
441
+ var import_node_fs2, TodoTracker;
442
+ var init_todo = __esm({
443
+ "src/lib/tracker/todo.ts"() {
444
+ "use strict";
445
+ init_cjs_shims();
446
+ import_node_fs2 = require("fs");
447
+ init_config();
448
+ TodoTracker = class {
449
+ type = "todo";
450
+ displayName = "TODO.md";
451
+ /**
452
+ * Validate that the TODO.md file exists
453
+ * @throws Error if file is missing
454
+ */
455
+ async initialize() {
456
+ if (!(0, import_node_fs2.existsSync)(config.todoFile)) {
457
+ throw new Error(`Missing ${config.todoFile}`);
458
+ }
459
+ }
460
+ getStats() {
461
+ const remaining = this.countUncheckedTasks();
462
+ return {
463
+ remaining,
464
+ completed: 0,
465
+ // TODO.md doesn't track completed separately
466
+ total: remaining,
467
+ label: "Tasks"
468
+ };
469
+ }
470
+ hasRemainingTasks() {
471
+ if (!(0, import_node_fs2.existsSync)(config.todoFile)) return false;
472
+ const content = (0, import_node_fs2.readFileSync)(config.todoFile, "utf-8");
473
+ return /^\s*-\s*\[\s\]/m.test(content);
474
+ }
475
+ getTaskPrompt() {
476
+ return `You are an autonomous coding agent. Complete ONE task from TODO.md.
445
477
 
446
478
  ## Before Starting
447
479
  Read these ROOT-LEVEL files only (ignore subdirectories for project context):
@@ -469,34 +501,174 @@ IMPORTANT: Only use the root-level files above for project context. Do not read
469
501
  ## When Done
470
502
  Output: RALPH_COMPLETE
471
503
  If no tasks remain: RALPH_ALL_DONE`;
504
+ }
505
+ getContext() {
506
+ return {};
507
+ }
508
+ countUncheckedTasks() {
509
+ if (!(0, import_node_fs2.existsSync)(config.todoFile)) return 0;
510
+ const content = (0, import_node_fs2.readFileSync)(config.todoFile, "utf-8");
511
+ const lines = content.split("\n");
512
+ let count = 0;
513
+ for (const line of lines) {
514
+ if (/^\s*-\s*\[\s\]/.test(line)) {
515
+ count++;
516
+ }
517
+ }
518
+ return count;
519
+ }
520
+ };
521
+ }
522
+ });
523
+
524
+ // src/lib/tracker/github-board.ts
525
+ function getProjectBoardContext() {
526
+ try {
527
+ const owner = (0, import_node_child_process5.execSync)("gh repo view --json owner -q .owner.login", {
528
+ encoding: "utf-8",
529
+ stdio: ["pipe", "pipe", "pipe"],
530
+ timeout: 3e4
531
+ }).trim();
532
+ const projectNumber = (0, import_node_child_process5.execSync)(
533
+ "gh repo view --json projectsV2 -q '.projectsV2.Nodes[0].number'",
534
+ { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"], timeout: 3e4 }
535
+ ).trim();
536
+ if (!projectNumber || projectNumber === "null") return null;
537
+ const projectId = (0, import_node_child_process5.execSync)(
538
+ "gh repo view --json projectsV2 -q '.projectsV2.Nodes[0].id'",
539
+ { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"], timeout: 3e4 }
540
+ ).trim();
541
+ const fieldsOutput = (0, import_node_child_process5.execSync)(
542
+ `gh project field-list ${projectNumber} --owner ${owner} --format json`,
543
+ { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"], timeout: 3e4 }
544
+ );
545
+ const fields = JSON.parse(fieldsOutput);
546
+ const statusField = fields.fields?.find((f) => f.name === "Status");
547
+ if (!statusField) return null;
548
+ const findOption = (names) => {
549
+ for (const name of names) {
550
+ const option = statusField.options?.find(
551
+ (o) => o.name.toLowerCase() === name.toLowerCase()
552
+ );
553
+ if (option) return option;
554
+ }
555
+ return null;
556
+ };
557
+ const todoOption = findOption(["Todo", "To Do", "To do", "Backlog"]);
558
+ const inProgressOption = findOption(["In Progress", "In progress", "Doing", "Active"]);
559
+ const doneOption = findOption(["Done", "Completed", "Closed", "Finished"]);
560
+ return {
561
+ owner,
562
+ projectNumber,
563
+ projectId,
564
+ statusFieldId: statusField.id,
565
+ todoOptionId: todoOption?.id || "",
566
+ inProgressOptionId: inProgressOption?.id || "",
567
+ doneOptionId: doneOption?.id || ""
568
+ };
569
+ } catch {
570
+ return null;
571
+ }
472
572
  }
473
- function getGitHubTaskPrompt(boardContext) {
474
- const boardInstructions = boardContext && boardContext.inProgressOptionId && boardContext.doneOptionId ? `
573
+ var import_node_child_process5;
574
+ var init_github_board = __esm({
575
+ "src/lib/tracker/github-board.ts"() {
576
+ "use strict";
577
+ init_cjs_shims();
578
+ import_node_child_process5 = require("child_process");
579
+ }
580
+ });
581
+
582
+ // src/lib/tracker/github.ts
583
+ var import_node_child_process6, import_picocolors6, GitHubTracker;
584
+ var init_github = __esm({
585
+ "src/lib/tracker/github.ts"() {
586
+ "use strict";
587
+ init_cjs_shims();
588
+ import_node_child_process6 = require("child_process");
589
+ import_picocolors6 = __toESM(require("picocolors"), 1);
590
+ init_github_board();
591
+ init_new();
592
+ init_prompts();
593
+ GitHubTracker = class {
594
+ type = "github";
595
+ displayName = "GitHub Issues";
596
+ boardContext = null;
597
+ todoIssueNumbers = [];
598
+ /**
599
+ * Initialize the GitHub tracker
600
+ * - Ensures a project board is linked
601
+ * - Fetches board context (IDs for status updates)
602
+ * - Fetches issues in "Todo" column
603
+ */
604
+ async initialize() {
605
+ await this.ensureProjectLinked();
606
+ console.log(import_picocolors6.default.dim("Fetching project board context..."));
607
+ this.boardContext = getProjectBoardContext();
608
+ if (this.boardContext) {
609
+ console.log(import_picocolors6.default.green(`\u2713 Board context loaded (Project #${this.boardContext.projectNumber})`));
610
+ if (!this.boardContext.inProgressOptionId || !this.boardContext.doneOptionId) {
611
+ console.log(import_picocolors6.default.yellow(" \u26A0 Missing status options - status updates may not work"));
612
+ }
613
+ this.todoIssueNumbers = this.fetchTodoIssueNumbers();
614
+ if (this.todoIssueNumbers.length > 0) {
615
+ console.log(import_picocolors6.default.green(`\u2713 Found ${this.todoIssueNumbers.length} issue(s) in Todo column`));
616
+ } else {
617
+ console.log(import_picocolors6.default.yellow("\u26A0 No issues found in Todo column - will fall back to open issues"));
618
+ }
619
+ } else {
620
+ console.log(import_picocolors6.default.yellow("\u26A0 Could not fetch project board context."));
621
+ console.log(import_picocolors6.default.dim(" Status updates will not work. Continuing anyway..."));
622
+ }
623
+ }
624
+ getStats() {
625
+ const remaining = this.countOpenIssues();
626
+ const completed = this.countClosedIssues();
627
+ return {
628
+ remaining,
629
+ completed,
630
+ total: remaining + completed,
631
+ label: "Issues"
632
+ };
633
+ }
634
+ hasRemainingTasks() {
635
+ try {
636
+ const output = (0, import_node_child_process6.execSync)(
637
+ "gh issue list --state open --limit 1 --json number --jq 'length'",
638
+ { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"], timeout: 3e4 }
639
+ );
640
+ return parseInt(output.trim(), 10) > 0;
641
+ } catch {
642
+ return false;
643
+ }
644
+ }
645
+ getTaskPrompt(planContent) {
646
+ const boardInstructions = this.boardContext && this.boardContext.inProgressOptionId && this.boardContext.doneOptionId ? `
475
647
  ## Project Board Status Updates (REQUIRED)
476
648
 
477
649
  Pre-computed values for this project:
478
- - Owner: ${boardContext.owner}
479
- - Project Number: ${boardContext.projectNumber}
480
- - Project ID: ${boardContext.projectId}
481
- - Status Field ID: ${boardContext.statusFieldId}
482
- - In Progress Option ID: ${boardContext.inProgressOptionId}
483
- - Done Option ID: ${boardContext.doneOptionId}
650
+ - Owner: ${this.boardContext.owner}
651
+ - Project Number: ${this.boardContext.projectNumber}
652
+ - Project ID: ${this.boardContext.projectId}
653
+ - Status Field ID: ${this.boardContext.statusFieldId}
654
+ - In Progress Option ID: ${this.boardContext.inProgressOptionId}
655
+ - Done Option ID: ${this.boardContext.doneOptionId}
484
656
 
485
657
  ### Step 1: Get Item ID for the Issue
486
658
  Run this to get the ITEM_ID (replace ISSUE_NUMBER with the actual issue number):
487
659
  \`\`\`bash
488
- ITEM_ID=$(gh project item-list ${boardContext.projectNumber} --owner ${boardContext.owner} --format json | jq -r '.items[] | select(.content.number == ISSUE_NUMBER) | .id')
660
+ ITEM_ID=$(gh project item-list ${this.boardContext.projectNumber} --owner ${this.boardContext.owner} --format json | jq -r '.items[] | select(.content.number == ISSUE_NUMBER) | .id')
489
661
  echo "Item ID: $ITEM_ID"
490
662
  \`\`\`
491
663
 
492
664
  ### Step 2: Mark In Progress (do this FIRST, before any code changes)
493
665
  \`\`\`bash
494
- gh project item-edit --project-id ${boardContext.projectId} --id $ITEM_ID --field-id ${boardContext.statusFieldId} --single-select-option-id ${boardContext.inProgressOptionId}
666
+ gh project item-edit --project-id ${this.boardContext.projectId} --id $ITEM_ID --field-id ${this.boardContext.statusFieldId} --single-select-option-id ${this.boardContext.inProgressOptionId}
495
667
  \`\`\`
496
668
 
497
669
  ### Step 3: Mark Done (do this AFTER closing the issue)
498
670
  \`\`\`bash
499
- gh project item-edit --project-id ${boardContext.projectId} --id $ITEM_ID --field-id ${boardContext.statusFieldId} --single-select-option-id ${boardContext.doneOptionId}
671
+ gh project item-edit --project-id ${this.boardContext.projectId} --id $ITEM_ID --field-id ${this.boardContext.statusFieldId} --single-select-option-id ${this.boardContext.doneOptionId}
500
672
  \`\`\`
501
673
 
502
674
  **You MUST update the board status at each step. Do not skip this.**
@@ -504,18 +676,29 @@ gh project item-edit --project-id ${boardContext.projectId} --id $ITEM_ID --fiel
504
676
  ## Project Board Status Updates
505
677
  No project board is linked or Status field not found. Skip board status updates.
506
678
  `;
507
- return `You are an autonomous coding agent. Complete ONE GitHub Issue.
679
+ const planSection = planContent ? `
680
+ ## Project Plan (for context)
681
+ The following plan describes the overall project. Use this to understand priorities and pick the most impactful issue.
682
+ GitHub Issues are the source of truth for what needs to be done - the plan provides context.
508
683
 
684
+ <plan>
685
+ ${planContent}
686
+ </plan>
687
+ ` : "";
688
+ const todoIssueNumbers = this.todoIssueNumbers;
689
+ return `You are an autonomous coding agent. Complete ONE GitHub Issue.
690
+ ${planSection}
509
691
  ## Before Starting (REQUIRED - Read these first)
510
- 1. Read specs/prd.md to understand what we're building
511
- 2. Read CLAUDE.md for coding conventions
512
- 3. List open issues: gh issue list --state open --json number,title
692
+ 1. Read CLAUDE.md for coding conventions
693
+ ${todoIssueNumbers && todoIssueNumbers.length > 0 ? `2. Issues in "Todo" column (pick from these): ${todoIssueNumbers.join(", ")}` : `2. List open issues: gh issue list --state open --json number,title,labels`}
513
694
 
514
695
  IMPORTANT: Only use root-level files for project context. Do not read subdirectory README files.
515
696
 
516
697
  ## Pick an Issue
517
- Choose the issue that best aligns with the PRD priorities.
518
- If unsure, pick the lowest numbered open issue.
698
+ ${todoIssueNumbers && todoIssueNumbers.length > 0 ? `Pick one issue from the Todo list above: ${todoIssueNumbers.join(", ")}
699
+ These are the issues explicitly ready to work on (in "Todo" status on the project board).` : `Use the plan context above (if provided) to choose the most impactful issue.
700
+ Consider: dependencies between issues, priority labels, and logical order.
701
+ If unsure, pick the lowest numbered open issue.`}
519
702
 
520
703
  ## Workflow
521
704
  1. Read the issue: gh issue view <number>
@@ -536,300 +719,281 @@ ${boardInstructions}
536
719
  ## When Done
537
720
  Output: RALPH_COMPLETE
538
721
  If no issues remain: RALPH_ALL_DONE`;
539
- }
540
- async function runTaskIteration(iteration, useGitHub = false, boardContext) {
541
- const taskPrompt = useGitHub ? getGitHubTaskPrompt(boardContext || null) : getTodoTaskPrompt();
542
- let lastResult = {
543
- success: false,
544
- output: "",
545
- error: "No attempts made"
546
- };
547
- for (let attempt = 1; attempt <= config.maxClaudeAttempts; attempt++) {
548
- console.log(import_picocolors5.default.yellow(`Attempt ${attempt}/${config.maxClaudeAttempts}`));
549
- const result = await runClaude({
550
- prompt: taskPrompt,
551
- streaming: true,
552
- onOutput: (line) => {
553
- process.stdout.write(line);
554
- if (!line.endsWith("\n")) {
555
- process.stdout.write("\n");
722
+ }
723
+ getContext() {
724
+ return {
725
+ boardContext: this.boardContext,
726
+ todoIssueNumbers: this.todoIssueNumbers
727
+ };
728
+ }
729
+ getTodoTaskIds() {
730
+ return this.todoIssueNumbers;
731
+ }
732
+ // =========== Private Methods ===========
733
+ countOpenIssues() {
734
+ try {
735
+ const output = (0, import_node_child_process6.execSync)(
736
+ "gh issue list --state open --json number --jq 'length'",
737
+ { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"], timeout: 3e4 }
738
+ );
739
+ return parseInt(output.trim(), 10) || 0;
740
+ } catch {
741
+ return 0;
556
742
  }
557
743
  }
558
- });
559
- lastResult = result;
560
- if (result.success) {
561
- return result;
562
- }
563
- const isTransient = result.output.includes("No messages returned") || result.output.includes("ECONNRESET") || result.output.includes("ETIMEDOUT") || result.error?.includes("ECONNRESET") || result.error?.includes("ETIMEDOUT");
564
- if (isTransient && attempt < config.maxClaudeAttempts) {
565
- console.log(import_picocolors5.default.yellow("Transient error, retrying..."));
566
- await sleep(attempt * 5e3);
567
- continue;
568
- }
569
- break;
744
+ countClosedIssues() {
745
+ try {
746
+ const output = (0, import_node_child_process6.execSync)(
747
+ "gh issue list --state closed --json number --jq 'length'",
748
+ { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"], timeout: 3e4 }
749
+ );
750
+ return parseInt(output.trim(), 10) || 0;
751
+ } catch {
752
+ return 0;
753
+ }
754
+ }
755
+ /**
756
+ * Get issue numbers that are in "Todo" status on the project board
757
+ */
758
+ fetchTodoIssueNumbers() {
759
+ if (!this.boardContext?.todoOptionId) return [];
760
+ try {
761
+ const output = (0, import_node_child_process6.execSync)(
762
+ `gh project item-list ${this.boardContext.projectNumber} --owner ${this.boardContext.owner} --format json`,
763
+ { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"], timeout: 3e4 }
764
+ );
765
+ const data = JSON.parse(output);
766
+ return data.items?.filter(
767
+ (item) => item.status?.optionId === this.boardContext?.todoOptionId
768
+ )?.map((item) => item.content?.number)?.filter((n) => typeof n === "number") || [];
769
+ } catch {
770
+ return [];
771
+ }
772
+ }
773
+ /**
774
+ * Check if a GitHub project is linked to the current repo
775
+ */
776
+ getLinkedProjectNumber() {
777
+ try {
778
+ const output = (0, import_node_child_process6.execSync)(
779
+ "gh repo view --json projectsV2 -q '.projectsV2.Nodes[0].number'",
780
+ { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"], timeout: 3e4 }
781
+ );
782
+ const num = output.trim();
783
+ return num && num !== "null" ? num : null;
784
+ } catch {
785
+ return null;
786
+ }
787
+ }
788
+ /**
789
+ * Ensure a project board is linked when using GitHub tracker
790
+ * If not linked, offer to link one or create a new one
791
+ */
792
+ async ensureProjectLinked() {
793
+ if (this.getLinkedProjectNumber()) {
794
+ return;
795
+ }
796
+ const configuredProject = getGithubProject();
797
+ console.log();
798
+ console.log(import_picocolors6.default.yellow("\u26A0 No project board is linked to this repo."));
799
+ console.log(import_picocolors6.default.dim(" This is required for automatic status updates."));
800
+ console.log();
801
+ let repoName = "";
802
+ let owner = "";
803
+ try {
804
+ repoName = (0, import_node_child_process6.execSync)("gh repo view --json nameWithOwner -q .nameWithOwner", {
805
+ encoding: "utf-8",
806
+ stdio: ["pipe", "pipe", "pipe"]
807
+ }).trim();
808
+ owner = repoName.split("/")[0] ?? "";
809
+ } catch {
810
+ console.log(import_picocolors6.default.red("Could not detect GitHub repo."));
811
+ console.log(import_picocolors6.default.dim("Continuing without project board integration..."));
812
+ return;
813
+ }
814
+ let existingProjects = [];
815
+ try {
816
+ const projectsOutput = (0, import_node_child_process6.execSync)(`gh project list --owner ${owner} --format json`, {
817
+ encoding: "utf-8",
818
+ stdio: ["pipe", "pipe", "pipe"]
819
+ });
820
+ const projects = JSON.parse(projectsOutput);
821
+ existingProjects = projects.projects?.map((p2) => ({
822
+ title: p2.title,
823
+ number: p2.number
824
+ })) || [];
825
+ } catch {
826
+ }
827
+ const options = [
828
+ ...existingProjects.map((p2) => ({
829
+ value: String(p2.number),
830
+ label: p2.title,
831
+ hint: configuredProject === p2.title ? "configured" : void 0
832
+ })),
833
+ { value: "__new__", label: "Create new board..." },
834
+ { value: "__skip__", label: "Skip (automation will be limited)" }
835
+ ];
836
+ const selected = await select2({
837
+ message: "Link a project board to this repo?",
838
+ options
839
+ });
840
+ if (selected === "__skip__") {
841
+ console.log(import_picocolors6.default.dim("Continuing without project board integration..."));
842
+ return;
843
+ }
844
+ if (selected === "__new__") {
845
+ const existingNames = new Set(existingProjects.map((p2) => p2.title.toLowerCase()));
846
+ const projectName = await text2({
847
+ message: "Board name",
848
+ placeholder: "e.g., My Project Kanban",
849
+ validate: (value) => {
850
+ if (!value || !value.trim()) {
851
+ return "Board name is required";
852
+ }
853
+ if (existingNames.has(value.trim().toLowerCase())) {
854
+ return `A board named "${value.trim()}" already exists. Choose a different name.`;
855
+ }
856
+ return void 0;
857
+ }
858
+ });
859
+ console.log(import_picocolors6.default.cyan(`Creating board "${projectName}"...`));
860
+ try {
861
+ const createOutput = (0, import_node_child_process6.execSync)(
862
+ `gh project create --owner ${owner} --title "${projectName}"`,
863
+ { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }
864
+ );
865
+ const projectNumberMatch = createOutput.match(/projects\/(\d+)/);
866
+ const projectNumber = projectNumberMatch ? projectNumberMatch[1] : null;
867
+ if (projectNumber) {
868
+ (0, import_node_child_process6.execSync)(`gh project link ${projectNumber} --owner ${owner} --repo ${repoName}`, {
869
+ stdio: ["pipe", "pipe", "pipe"]
870
+ });
871
+ console.log(import_picocolors6.default.green(`\u2713 Board "${projectName}" created and linked`));
872
+ }
873
+ } catch {
874
+ console.log(import_picocolors6.default.yellow("Could not create board. Continuing without project integration..."));
875
+ }
876
+ } else {
877
+ const projectNumber = selected;
878
+ const projectTitle = existingProjects.find((p2) => String(p2.number) === projectNumber)?.title || projectNumber;
879
+ try {
880
+ (0, import_node_child_process6.execSync)(`gh project link ${projectNumber} --owner ${owner} --repo ${repoName}`, {
881
+ stdio: ["pipe", "pipe", "pipe"]
882
+ });
883
+ console.log(import_picocolors6.default.green(`\u2713 Linked "${projectTitle}" to ${repoName}`));
884
+ } catch {
885
+ console.log(import_picocolors6.default.yellow("Could not link project. It may already be linked."));
886
+ }
887
+ }
888
+ console.log();
889
+ }
890
+ };
570
891
  }
571
- return lastResult;
892
+ });
893
+
894
+ // src/lib/tracker/index.ts
895
+ function createTracker() {
896
+ const type = getProjectTracker();
897
+ return type === "github" ? new GitHubTracker() : new TodoTracker();
572
898
  }
573
- var import_node_child_process4, import_node_readline, import_picocolors5;
574
- var init_claude = __esm({
575
- "src/lib/claude.ts"() {
899
+ var init_tracker = __esm({
900
+ "src/lib/tracker/index.ts"() {
576
901
  "use strict";
577
902
  init_cjs_shims();
578
- import_node_child_process4 = require("child_process");
579
- import_node_readline = require("readline");
580
- import_picocolors5 = __toESM(require("picocolors"), 1);
581
- init_config();
582
- init_process();
903
+ init_new();
904
+ init_todo();
905
+ init_github();
906
+ init_github_board();
907
+ init_todo();
908
+ init_github();
583
909
  }
584
910
  });
585
911
 
586
912
  // src/commands/loop.ts
587
- function countUncheckedTasks() {
588
- if (!(0, import_node_fs2.existsSync)(config.todoFile)) return 0;
589
- const content = (0, import_node_fs2.readFileSync)(config.todoFile, "utf-8");
590
- const lines = content.split("\n");
591
- let count = 0;
592
- for (const line of lines) {
593
- if (/^\s*-\s*\[\s\]/.test(line)) {
594
- count++;
595
- }
596
- }
597
- return count;
598
- }
599
- function hasUncheckedTasks() {
600
- if (!(0, import_node_fs2.existsSync)(config.todoFile)) return false;
601
- const content = (0, import_node_fs2.readFileSync)(config.todoFile, "utf-8");
602
- return /^\s*-\s*\[\s\]/m.test(content);
603
- }
604
- function countOpenIssues() {
605
- try {
606
- const output = (0, import_node_child_process5.execSync)(
607
- "gh issue list --state open --json number --jq 'length'",
608
- { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"], timeout: 3e4 }
609
- );
610
- return parseInt(output.trim(), 10) || 0;
611
- } catch {
612
- return 0;
613
- }
614
- }
615
- function hasOpenIssues() {
616
- try {
617
- const output = (0, import_node_child_process5.execSync)(
618
- "gh issue list --state open --limit 1 --json number --jq 'length'",
619
- { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"], timeout: 3e4 }
620
- );
621
- return parseInt(output.trim(), 10) > 0;
622
- } catch {
623
- return false;
624
- }
913
+ function getPlanPathFromPRD() {
914
+ const prdPath = "specs/prd.md";
915
+ if (!(0, import_node_fs3.existsSync)(prdPath)) return null;
916
+ const content = (0, import_node_fs3.readFileSync)(prdPath, "utf-8");
917
+ const frontmatterMatch = content.match(/^---\n([\s\S]*?)\n---/);
918
+ if (!frontmatterMatch) return null;
919
+ const sourcePlanMatch = frontmatterMatch[1].match(/^source_plan:\s*"?([^"\n]+)"?/m);
920
+ return sourcePlanMatch ? sourcePlanMatch[1].trim() : null;
625
921
  }
626
- function countClosedIssues() {
627
- try {
628
- const output = (0, import_node_child_process5.execSync)(
629
- "gh issue list --state closed --json number --jq 'length'",
630
- { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"], timeout: 3e4 }
631
- );
632
- return parseInt(output.trim(), 10) || 0;
633
- } catch {
634
- return 0;
922
+ function loadPlanContent() {
923
+ const planFilename = getPlanPathFromPRD();
924
+ if (!planFilename) return null;
925
+ const locations = [
926
+ `docs/plans/${planFilename}`,
927
+ planFilename
928
+ // Might be a full path
929
+ ];
930
+ for (const path of locations) {
931
+ if ((0, import_node_fs3.existsSync)(path)) {
932
+ console.log(import_picocolors7.default.dim(`Loading plan context from ${path}...`));
933
+ return (0, import_node_fs3.readFileSync)(path, "utf-8");
934
+ }
635
935
  }
936
+ return null;
636
937
  }
637
938
  function getCurrentCommit() {
638
939
  try {
639
- return (0, import_node_child_process5.execSync)("git rev-parse HEAD", { encoding: "utf-8" }).trim();
940
+ return (0, import_node_child_process7.execSync)("git rev-parse HEAD", { encoding: "utf-8" }).trim();
640
941
  } catch {
641
942
  return "none";
642
943
  }
643
944
  }
644
- function getLinkedProjectNumber() {
645
- try {
646
- const output = (0, import_node_child_process5.execSync)(
647
- "gh repo view --json projectsV2 -q '.projectsV2.Nodes[0].number'",
648
- { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"], timeout: 3e4 }
649
- );
650
- const num = output.trim();
651
- return num && num !== "null" ? num : null;
652
- } catch {
653
- return null;
654
- }
655
- }
656
- async function ensureProjectLinked() {
657
- if (getLinkedProjectNumber()) {
658
- return;
659
- }
660
- const configuredProject = getGithubProject();
661
- console.log();
662
- console.log(import_picocolors6.default.yellow("\u26A0 No project board is linked to this repo."));
663
- console.log(import_picocolors6.default.dim(" This is required for automatic status updates."));
664
- console.log();
665
- let repoName = "";
666
- let owner = "";
667
- try {
668
- repoName = (0, import_node_child_process5.execSync)("gh repo view --json nameWithOwner -q .nameWithOwner", {
669
- encoding: "utf-8",
670
- stdio: ["pipe", "pipe", "pipe"]
671
- }).trim();
672
- owner = repoName.split("/")[0];
673
- } catch {
674
- console.log(import_picocolors6.default.red("Could not detect GitHub repo."));
675
- console.log(import_picocolors6.default.dim("Continuing without project board integration..."));
676
- return;
677
- }
678
- let existingProjects = [];
679
- try {
680
- const projectsOutput = (0, import_node_child_process5.execSync)(`gh project list --owner ${owner} --format json`, {
681
- encoding: "utf-8",
682
- stdio: ["pipe", "pipe", "pipe"]
683
- });
684
- const projects = JSON.parse(projectsOutput);
685
- existingProjects = projects.projects?.map((p2) => ({
686
- title: p2.title,
687
- number: p2.number
688
- })) || [];
689
- } catch {
690
- }
691
- const options = [
692
- ...existingProjects.map((p2) => ({
693
- value: String(p2.number),
694
- label: p2.title,
695
- hint: configuredProject === p2.title ? "configured" : void 0
696
- })),
697
- { value: "__new__", label: "Create new board..." },
698
- { value: "__skip__", label: "Skip (automation will be limited)" }
699
- ];
700
- const selected = await select2({
701
- message: "Link a project board to this repo?",
702
- options
703
- });
704
- if (selected === "__skip__") {
705
- console.log(import_picocolors6.default.dim("Continuing without project board integration..."));
706
- return;
707
- }
708
- if (selected === "__new__") {
709
- const existingNames = new Set(existingProjects.map((p2) => p2.title.toLowerCase()));
710
- const projectName = await text2({
711
- message: "Board name",
712
- placeholder: "e.g., My Project Kanban",
713
- validate: (value) => {
714
- if (!value || !value.trim()) {
715
- return "Board name is required";
716
- }
717
- if (existingNames.has(value.trim().toLowerCase())) {
718
- return `A board named "${value.trim()}" already exists. Choose a different name.`;
719
- }
720
- return void 0;
721
- }
722
- });
723
- console.log(import_picocolors6.default.cyan(`Creating board "${projectName}"...`));
724
- try {
725
- const createOutput = (0, import_node_child_process5.execSync)(
726
- `gh project create --owner ${owner} --title "${projectName}"`,
727
- { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }
728
- );
729
- const projectNumberMatch = createOutput.match(/projects\/(\d+)/);
730
- const projectNumber = projectNumberMatch ? projectNumberMatch[1] : null;
731
- if (projectNumber) {
732
- (0, import_node_child_process5.execSync)(`gh project link ${projectNumber} --owner ${owner} --repo ${repoName}`, {
733
- stdio: ["pipe", "pipe", "pipe"]
734
- });
735
- console.log(import_picocolors6.default.green(`\u2713 Board "${projectName}" created and linked`));
736
- }
737
- } catch (err) {
738
- console.log(import_picocolors6.default.yellow("Could not create board. Continuing without project integration..."));
739
- }
740
- } else {
741
- const projectNumber = selected;
742
- const projectTitle = existingProjects.find((p2) => String(p2.number) === projectNumber)?.title || projectNumber;
743
- try {
744
- (0, import_node_child_process5.execSync)(`gh project link ${projectNumber} --owner ${owner} --repo ${repoName}`, {
745
- stdio: ["pipe", "pipe", "pipe"]
746
- });
747
- console.log(import_picocolors6.default.green(`\u2713 Linked "${projectTitle}" to ${repoName}`));
748
- } catch {
749
- console.log(import_picocolors6.default.yellow("Could not link project. It may already be linked."));
750
- }
751
- }
752
- console.log();
753
- }
754
945
  function pushToOrigin() {
755
946
  try {
756
- (0, import_node_child_process5.execSync)("git push origin HEAD", { stdio: "pipe" });
947
+ (0, import_node_child_process7.execSync)("git push origin HEAD", { stdio: "pipe" });
757
948
  console.log("Pushed to origin");
758
949
  } catch {
759
950
  }
760
951
  }
761
952
  async function cmdLoop() {
762
- const tracker = getProjectTracker();
763
- const isGitHub = tracker === "github";
764
- if (isGitHub) {
765
- await ensureProjectLinked();
766
- }
767
- let boardContext = null;
768
- if (isGitHub) {
769
- console.log(import_picocolors6.default.dim("Fetching project board context..."));
770
- boardContext = getProjectBoardContext();
771
- if (boardContext) {
772
- console.log(import_picocolors6.default.green(`\u2713 Board context loaded (Project #${boardContext.projectNumber})`));
773
- if (!boardContext.inProgressOptionId || !boardContext.doneOptionId) {
774
- console.log(import_picocolors6.default.yellow(" \u26A0 Missing status options - status updates may not work"));
775
- }
776
- } else {
777
- console.log(import_picocolors6.default.yellow("\u26A0 Could not fetch project board context."));
778
- console.log(import_picocolors6.default.dim(" Status updates will not work. Continuing anyway..."));
953
+ const tracker = createTracker();
954
+ try {
955
+ await tracker.initialize();
956
+ } catch (error) {
957
+ if (error instanceof Error) {
958
+ console.log(import_picocolors7.default.red(error.message));
779
959
  }
960
+ process.exit(1);
780
961
  }
781
- let maxIterations;
782
- let hasRemainingTasks;
783
- let trackerLabel;
784
- let completedCount = 0;
785
- if (isGitHub) {
786
- maxIterations = countOpenIssues();
787
- completedCount = countClosedIssues();
788
- hasRemainingTasks = hasOpenIssues;
789
- trackerLabel = "Issues";
790
- if (maxIterations === 0) {
791
- console.log(import_picocolors6.default.green("No open GitHub Issues. All done!"));
792
- process.exit(0);
793
- }
794
- } else {
795
- if (!(0, import_node_fs2.existsSync)(config.todoFile)) {
796
- console.log(import_picocolors6.default.red(`Missing ${config.todoFile}`));
797
- process.exit(1);
798
- }
799
- maxIterations = countUncheckedTasks();
800
- hasRemainingTasks = hasUncheckedTasks;
801
- trackerLabel = "Tasks";
802
- if (maxIterations === 0) {
803
- console.log(import_picocolors6.default.green(`No unchecked tasks in ${config.todoFile}. All done!`));
804
- process.exit(0);
805
- }
962
+ const planContent = tracker.type === "github" ? loadPlanContent() : null;
963
+ if (planContent) {
964
+ console.log(import_picocolors7.default.green("\u2713 Plan context loaded"));
965
+ }
966
+ const stats = tracker.getStats();
967
+ if (stats.remaining === 0) {
968
+ console.log(import_picocolors7.default.green(`No ${stats.label.toLowerCase()} remaining. All done!`));
969
+ process.exit(0);
806
970
  }
807
971
  console.log();
808
- console.log(import_picocolors6.default.green("\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550"));
809
- console.log(import_picocolors6.default.green(" Starting Build Loop"));
810
- if (isGitHub && completedCount > 0) {
811
- const total = maxIterations + completedCount;
812
- console.log(import_picocolors6.default.green(` ${trackerLabel}: ${maxIterations} remaining, ${completedCount} done (${total} total)`));
972
+ console.log(import_picocolors7.default.green("\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550"));
973
+ console.log(import_picocolors7.default.green(" Starting Build Loop"));
974
+ if (stats.completed > 0) {
975
+ console.log(import_picocolors7.default.green(` ${stats.label}: ${stats.remaining} remaining, ${stats.completed} done (${stats.total} total)`));
813
976
  } else {
814
- console.log(import_picocolors6.default.green(` ${trackerLabel} remaining: ${maxIterations}`));
977
+ console.log(import_picocolors7.default.green(` ${stats.label} remaining: ${stats.remaining}`));
815
978
  }
816
- console.log(import_picocolors6.default.green(` Timeout: ${config.iterationTimeoutMinutes}m per task`));
817
- console.log(import_picocolors6.default.green("\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550"));
979
+ console.log(import_picocolors7.default.green(` Timeout: ${config.iterationTimeoutMinutes}m per task`));
980
+ console.log(import_picocolors7.default.green("\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550"));
818
981
  let consecutiveFailures = 0;
819
982
  let noCommitCycles = 0;
820
983
  let lastCommit = getCurrentCommit();
821
- for (let i = 1; i <= maxIterations; i++) {
984
+ for (let i = 1; i <= stats.remaining; i++) {
822
985
  console.log();
823
- console.log(import_picocolors6.default.yellow(`\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 Task ${i} of ${maxIterations} \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550`));
986
+ console.log(import_picocolors7.default.yellow(`\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 Task ${i} of ${stats.remaining} \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550`));
824
987
  cleanupStaleProcesses();
825
988
  const startTime = Date.now();
826
- const result = await runTaskIteration(i, isGitHub, boardContext);
989
+ const prompt = tracker.getTaskPrompt(planContent);
990
+ const result = await runTaskIteration(i, prompt);
827
991
  const duration = Math.round((Date.now() - startTime) / 1e3);
828
992
  console.log();
829
993
  console.log(`Completed in ${duration}s (exit: ${result.success ? 0 : 1})`);
830
994
  if (!result.success) {
831
995
  consecutiveFailures++;
832
- console.log(import_picocolors6.default.red(`Failure ${consecutiveFailures}/${config.maxConsecutiveFailures}`));
996
+ console.log(import_picocolors7.default.red(`Failure ${consecutiveFailures}/${config.maxConsecutiveFailures}`));
833
997
  await sleep(3e4);
834
998
  } else {
835
999
  consecutiveFailures = 0;
@@ -838,48 +1002,47 @@ async function cmdLoop() {
838
1002
  if (currentCommit === lastCommit) {
839
1003
  if (result.success) {
840
1004
  noCommitCycles++;
841
- console.log(import_picocolors6.default.yellow(`No commit (${noCommitCycles}/${config.maxNoCommitCycles})`));
1005
+ console.log(import_picocolors7.default.yellow(`No commit (${noCommitCycles}/${config.maxNoCommitCycles})`));
842
1006
  }
843
1007
  } else {
844
1008
  noCommitCycles = 0;
845
1009
  lastCommit = currentCommit;
846
- console.log(import_picocolors6.default.green(`New commit: ${currentCommit.substring(0, 7)}`));
1010
+ console.log(import_picocolors7.default.green(`New commit: ${currentCommit.substring(0, 7)}`));
847
1011
  pushToOrigin();
848
1012
  }
849
1013
  if (consecutiveFailures >= config.maxConsecutiveFailures) {
850
- console.log(import_picocolors6.default.red(`Stopping: ${config.maxConsecutiveFailures} consecutive failures`));
1014
+ console.log(import_picocolors7.default.red(`Stopping: ${config.maxConsecutiveFailures} consecutive failures`));
851
1015
  process.exit(1);
852
1016
  }
853
1017
  if (noCommitCycles >= config.maxNoCommitCycles) {
854
- console.log(import_picocolors6.default.red(`Stopping: No commits for ${config.maxNoCommitCycles} cycles`));
1018
+ console.log(import_picocolors7.default.red(`Stopping: No commits for ${config.maxNoCommitCycles} cycles`));
855
1019
  process.exit(1);
856
1020
  }
857
- if (!hasRemainingTasks()) {
1021
+ if (!tracker.hasRemainingTasks()) {
858
1022
  console.log();
859
- console.log(import_picocolors6.default.green("\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550"));
860
- console.log(import_picocolors6.default.green(` All ${trackerLabel.toLowerCase()} completed!`));
861
- console.log(import_picocolors6.default.green("\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550"));
1023
+ console.log(import_picocolors7.default.green("\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550"));
1024
+ console.log(import_picocolors7.default.green(` All ${stats.label.toLowerCase()} completed!`));
1025
+ console.log(import_picocolors7.default.green("\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550"));
862
1026
  pushToOrigin();
863
1027
  process.exit(0);
864
1028
  }
865
1029
  await sleep(config.cooldownSeconds * 1e3);
866
1030
  }
867
- console.log(import_picocolors6.default.yellow(`Reached max iterations (${maxIterations})`));
1031
+ console.log(import_picocolors7.default.yellow(`Reached max iterations (${stats.remaining})`));
868
1032
  pushToOrigin();
869
1033
  }
870
- var import_node_fs2, import_node_child_process5, import_picocolors6;
1034
+ var import_node_fs3, import_node_child_process7, import_picocolors7;
871
1035
  var init_loop = __esm({
872
1036
  "src/commands/loop.ts"() {
873
1037
  "use strict";
874
1038
  init_cjs_shims();
875
- import_node_fs2 = require("fs");
876
- import_node_child_process5 = require("child_process");
877
- import_picocolors6 = __toESM(require("picocolors"), 1);
1039
+ import_node_fs3 = require("fs");
1040
+ import_node_child_process7 = require("child_process");
1041
+ import_picocolors7 = __toESM(require("picocolors"), 1);
878
1042
  init_config();
879
1043
  init_claude();
880
1044
  init_process();
881
- init_new();
882
- init_prompts();
1045
+ init_tracker();
883
1046
  }
884
1047
  });
885
1048
 
@@ -894,28 +1057,28 @@ function stripTrailingCommas(json) {
894
1057
  return json.replace(/,(\s*[}\]])/g, "$1");
895
1058
  }
896
1059
  function getConfig() {
897
- if (!(0, import_node_fs3.existsSync)(CONFIG_FILE)) {
1060
+ if (!(0, import_node_fs4.existsSync)(CONFIG_FILE)) {
898
1061
  return { projectTracker: "todo" };
899
1062
  }
900
- const raw = (0, import_node_fs3.readFileSync)(CONFIG_FILE, "utf-8");
1063
+ const raw = (0, import_node_fs4.readFileSync)(CONFIG_FILE, "utf-8");
901
1064
  try {
902
1065
  return JSON.parse(raw);
903
1066
  } catch {
904
1067
  try {
905
1068
  const fixed = stripTrailingCommas(raw);
906
1069
  const config2 = JSON.parse(fixed);
907
- console.log(import_picocolors7.default.yellow("Note: Fixed trailing comma in config file."));
1070
+ console.log(import_picocolors8.default.yellow("Note: Fixed trailing comma in config file."));
908
1071
  saveConfig(config2);
909
1072
  return config2;
910
1073
  } catch {
911
- console.log(import_picocolors7.default.yellow("Warning: Could not parse config file. Using defaults."));
1074
+ console.log(import_picocolors8.default.yellow("Warning: Could not parse config file. Using defaults."));
912
1075
  return { projectTracker: "todo" };
913
1076
  }
914
1077
  }
915
1078
  }
916
1079
  function saveConfig(config2) {
917
- (0, import_node_fs3.mkdirSync)((0, import_node_path2.dirname)(CONFIG_FILE), { recursive: true });
918
- (0, import_node_fs3.writeFileSync)(CONFIG_FILE, JSON.stringify(config2, null, 2) + "\n");
1080
+ (0, import_node_fs4.mkdirSync)((0, import_node_path2.dirname)(CONFIG_FILE), { recursive: true });
1081
+ (0, import_node_fs4.writeFileSync)(CONFIG_FILE, JSON.stringify(config2, null, 2) + "\n");
919
1082
  }
920
1083
  function getProjectTracker() {
921
1084
  return getConfig().projectTracker || "todo";
@@ -924,13 +1087,13 @@ function getGithubProject() {
924
1087
  return getConfig().githubProject;
925
1088
  }
926
1089
  function countTodoTasks() {
927
- if (!(0, import_node_fs3.existsSync)(config.todoFile)) return 0;
928
- const content = (0, import_node_fs3.readFileSync)(config.todoFile, "utf-8");
1090
+ if (!(0, import_node_fs4.existsSync)(config.todoFile)) return 0;
1091
+ const content = (0, import_node_fs4.readFileSync)(config.todoFile, "utf-8");
929
1092
  return (content.match(/^\s*-\s*\[\s\]/gm) || []).length;
930
1093
  }
931
1094
  function countOpenGitHubIssues() {
932
1095
  try {
933
- const output = (0, import_node_child_process6.execSync)(
1096
+ const output = (0, import_node_child_process8.execSync)(
934
1097
  "gh issue list --state open --json number --jq 'length'",
935
1098
  { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"], timeout: 3e4 }
936
1099
  );
@@ -958,7 +1121,7 @@ function parsePRDFrontmatter(content) {
958
1121
  function findMarkdownFiles(dir, basePath = "") {
959
1122
  const results = [];
960
1123
  try {
961
- const entries = (0, import_node_fs3.readdirSync)(dir, { withFileTypes: true });
1124
+ const entries = (0, import_node_fs4.readdirSync)(dir, { withFileTypes: true });
962
1125
  for (const entry of entries) {
963
1126
  const relativePath = basePath ? `${basePath}/${entry.name}` : entry.name;
964
1127
  if (entry.isDirectory()) {
@@ -974,14 +1137,14 @@ function findMarkdownFiles(dir, basePath = "") {
974
1137
  return results;
975
1138
  }
976
1139
  async function cmdNew(planFile) {
977
- console.log(import_picocolors7.default.bold("Project Setup"));
1140
+ console.log(import_picocolors8.default.bold("Project Setup"));
978
1141
  console.log();
979
- console.log(`Working directory: ${import_picocolors7.default.cyan(process.cwd())}`);
1142
+ console.log(`Working directory: ${import_picocolors8.default.cyan(process.cwd())}`);
980
1143
  await setupProjectConfig();
981
1144
  await setupTemplates();
982
1145
  if (planFile) {
983
- if (!(0, import_node_fs3.existsSync)(planFile)) {
984
- console.log(import_picocolors7.default.red(`Plan file not found: ${planFile}`));
1146
+ if (!(0, import_node_fs4.existsSync)(planFile)) {
1147
+ console.log(import_picocolors8.default.red(`Plan file not found: ${planFile}`));
985
1148
  process.exit(1);
986
1149
  }
987
1150
  await checkExistingFiles();
@@ -1001,8 +1164,8 @@ async function cmdNew(planFile) {
1001
1164
  case "plan": {
1002
1165
  const mdFiles = findMarkdownFiles(process.cwd());
1003
1166
  if (mdFiles.length === 0) {
1004
- console.log(import_picocolors7.default.yellow("No markdown files found in project."));
1005
- console.log(import_picocolors7.default.dim("Create a plan file first, e.g., plans/plan.md"));
1167
+ console.log(import_picocolors8.default.yellow("No markdown files found in project."));
1168
+ console.log(import_picocolors8.default.dim("Create a plan file first, e.g., plans/plan.md"));
1006
1169
  process.exit(1);
1007
1170
  }
1008
1171
  console.log();
@@ -1013,7 +1176,7 @@ async function cmdNew(planFile) {
1013
1176
  maxVisible: 15
1014
1177
  });
1015
1178
  if (!planPath) {
1016
- console.log(import_picocolors7.default.yellow("No plan selected."));
1179
+ console.log(import_picocolors8.default.yellow("No plan selected."));
1017
1180
  process.exit(0);
1018
1181
  }
1019
1182
  await checkExistingFiles();
@@ -1025,8 +1188,8 @@ async function cmdNew(planFile) {
1025
1188
  await interactiveDescribe();
1026
1189
  break;
1027
1190
  case "existing":
1028
- if (!(0, import_node_fs3.existsSync)(config.todoFile)) {
1029
- console.log(import_picocolors7.default.red("No TODO.md found. Run 'chiefwiggum new' to set up first."));
1191
+ if (!(0, import_node_fs4.existsSync)(config.todoFile)) {
1192
+ console.log(import_picocolors8.default.red("No TODO.md found. Run 'chiefwiggum new' to set up first."));
1030
1193
  process.exit(1);
1031
1194
  }
1032
1195
  break;
@@ -1055,23 +1218,23 @@ async function cmdNew(planFile) {
1055
1218
  break;
1056
1219
  case "review":
1057
1220
  console.log();
1058
- console.log(import_picocolors7.default.green("Setup complete!") + " Review your files, then run:");
1059
- console.log(` ${import_picocolors7.default.cyan("chiefwiggum loop")}`);
1221
+ console.log(import_picocolors8.default.green("Setup complete!") + " Review your files, then run:");
1222
+ console.log(` ${import_picocolors8.default.cyan("chiefwiggum loop")}`);
1060
1223
  break;
1061
1224
  case "exit":
1062
- console.log(import_picocolors7.default.yellow("Exiting."));
1225
+ console.log(import_picocolors8.default.yellow("Exiting."));
1063
1226
  break;
1064
1227
  }
1065
1228
  }
1066
1229
  async function checkExistingFiles() {
1067
1230
  const existingFiles = [];
1068
- if ((0, import_node_fs3.existsSync)(config.todoFile)) existingFiles.push(config.todoFile);
1069
- if ((0, import_node_fs3.existsSync)(config.specsDir)) existingFiles.push(`${config.specsDir}/`);
1231
+ if ((0, import_node_fs4.existsSync)(config.todoFile)) existingFiles.push(config.todoFile);
1232
+ if ((0, import_node_fs4.existsSync)(config.specsDir)) existingFiles.push(`${config.specsDir}/`);
1070
1233
  if (existingFiles.length === 0) {
1071
1234
  return true;
1072
1235
  }
1073
1236
  console.log();
1074
- console.log(import_picocolors7.default.yellow("Existing files found:"));
1237
+ console.log(import_picocolors8.default.yellow("Existing files found:"));
1075
1238
  for (const f of existingFiles) {
1076
1239
  console.log(` - ${f}`);
1077
1240
  }
@@ -1081,39 +1244,39 @@ async function checkExistingFiles() {
1081
1244
  initialValue: false
1082
1245
  });
1083
1246
  if (!shouldOverwrite) {
1084
- console.log(import_picocolors7.default.yellow("Aborted."));
1247
+ console.log(import_picocolors8.default.yellow("Aborted."));
1085
1248
  process.exit(0);
1086
1249
  }
1087
1250
  return true;
1088
1251
  }
1089
1252
  async function setupTemplates() {
1090
- if ((0, import_node_fs3.existsSync)(LOCAL_TEMPLATES_DIR)) {
1253
+ if ((0, import_node_fs4.existsSync)(LOCAL_TEMPLATES_DIR)) {
1091
1254
  return;
1092
1255
  }
1093
- if (!(0, import_node_fs3.existsSync)(BUNDLED_TEMPLATES_DIR)) {
1094
- console.log(import_picocolors7.default.red("Bundled templates not found. Please reinstall chiefwiggum."));
1256
+ if (!(0, import_node_fs4.existsSync)(BUNDLED_TEMPLATES_DIR)) {
1257
+ console.log(import_picocolors8.default.red("Bundled templates not found. Please reinstall chiefwiggum."));
1095
1258
  process.exit(1);
1096
1259
  }
1097
- console.log(import_picocolors7.default.cyan(`Setting up templates in ${LOCAL_TEMPLATES_DIR}...`));
1098
- (0, import_node_fs3.mkdirSync)(LOCAL_TEMPLATES_DIR, { recursive: true });
1099
- (0, import_node_fs3.cpSync)(BUNDLED_TEMPLATES_DIR, LOCAL_TEMPLATES_DIR, { recursive: true });
1100
- console.log(import_picocolors7.default.green(`\u2713 Templates copied to ${LOCAL_TEMPLATES_DIR}`));
1101
- console.log(import_picocolors7.default.dim(" You can customize these templates to change how specs are generated."));
1260
+ console.log(import_picocolors8.default.cyan(`Setting up templates in ${LOCAL_TEMPLATES_DIR}...`));
1261
+ (0, import_node_fs4.mkdirSync)(LOCAL_TEMPLATES_DIR, { recursive: true });
1262
+ (0, import_node_fs4.cpSync)(BUNDLED_TEMPLATES_DIR, LOCAL_TEMPLATES_DIR, { recursive: true });
1263
+ console.log(import_picocolors8.default.green(`\u2713 Templates copied to ${LOCAL_TEMPLATES_DIR}`));
1264
+ console.log(import_picocolors8.default.dim(" You can customize these templates to change how specs are generated."));
1102
1265
  console.log();
1103
1266
  }
1104
1267
  function checkGitHubCLI() {
1105
1268
  try {
1106
- (0, import_node_child_process6.execSync)("which gh", { stdio: ["pipe", "pipe", "pipe"] });
1269
+ (0, import_node_child_process8.execSync)("which gh", { stdio: ["pipe", "pipe", "pipe"] });
1107
1270
  } catch {
1108
1271
  return { ok: false, reason: "not_installed" };
1109
1272
  }
1110
1273
  try {
1111
- (0, import_node_child_process6.execSync)("gh auth status", { stdio: ["pipe", "pipe", "pipe"] });
1274
+ (0, import_node_child_process8.execSync)("gh auth status", { stdio: ["pipe", "pipe", "pipe"] });
1112
1275
  } catch {
1113
1276
  return { ok: false, reason: "not_authenticated" };
1114
1277
  }
1115
1278
  try {
1116
- const repo = (0, import_node_child_process6.execSync)("gh repo view --json nameWithOwner -q .nameWithOwner", {
1279
+ const repo = (0, import_node_child_process8.execSync)("gh repo view --json nameWithOwner -q .nameWithOwner", {
1117
1280
  encoding: "utf-8",
1118
1281
  stdio: ["pipe", "pipe", "pipe"]
1119
1282
  }).trim();
@@ -1124,7 +1287,7 @@ function checkGitHubCLI() {
1124
1287
  }
1125
1288
  async function setupProjectConfig() {
1126
1289
  const existingConfig = getConfig();
1127
- if ((0, import_node_fs3.existsSync)(CONFIG_FILE)) {
1290
+ if ((0, import_node_fs4.existsSync)(CONFIG_FILE)) {
1128
1291
  if (existingConfig.projectTracker === "github" && !existingConfig.githubProject) {
1129
1292
  const ghCheck = checkGitHubCLI();
1130
1293
  if (ghCheck.ok) {
@@ -1132,7 +1295,7 @@ async function setupProjectConfig() {
1132
1295
  const config3 = { ...existingConfig, githubProject: projectName };
1133
1296
  saveConfig(config3);
1134
1297
  if (projectName) {
1135
- console.log(import_picocolors7.default.green(`\u2713 Project board saved: ${projectName}`));
1298
+ console.log(import_picocolors8.default.green(`\u2713 Project board saved: ${projectName}`));
1136
1299
  }
1137
1300
  }
1138
1301
  }
@@ -1151,25 +1314,25 @@ async function setupProjectConfig() {
1151
1314
  if (!ghCheck.ok) {
1152
1315
  console.log();
1153
1316
  if (ghCheck.reason === "not_installed") {
1154
- console.log(import_picocolors7.default.yellow("GitHub CLI (gh) is not installed."));
1317
+ console.log(import_picocolors8.default.yellow("GitHub CLI (gh) is not installed."));
1155
1318
  console.log();
1156
1319
  console.log("To use GitHub Issues, install it first:");
1157
- console.log(import_picocolors7.default.cyan(" brew install gh # macOS"));
1158
- console.log(import_picocolors7.default.cyan(" sudo apt install gh # Ubuntu/Debian"));
1159
- console.log(import_picocolors7.default.dim(" https://cli.github.com for other platforms"));
1320
+ console.log(import_picocolors8.default.cyan(" brew install gh # macOS"));
1321
+ console.log(import_picocolors8.default.cyan(" sudo apt install gh # Ubuntu/Debian"));
1322
+ console.log(import_picocolors8.default.dim(" https://cli.github.com for other platforms"));
1160
1323
  } else if (ghCheck.reason === "not_authenticated") {
1161
- console.log(import_picocolors7.default.yellow("GitHub CLI is not authenticated."));
1324
+ console.log(import_picocolors8.default.yellow("GitHub CLI is not authenticated."));
1162
1325
  console.log();
1163
1326
  console.log("Run this command to log in:");
1164
- console.log(import_picocolors7.default.cyan(" gh auth login"));
1327
+ console.log(import_picocolors8.default.cyan(" gh auth login"));
1165
1328
  } else if (ghCheck.reason === "not_github_repo") {
1166
- console.log(import_picocolors7.default.yellow("Not in a GitHub repository."));
1329
+ console.log(import_picocolors8.default.yellow("Not in a GitHub repository."));
1167
1330
  console.log();
1168
1331
  console.log("Run chiefwiggum from inside a project directory:");
1169
- console.log(import_picocolors7.default.cyan(" cd your-project && chiefwiggum new"));
1332
+ console.log(import_picocolors8.default.cyan(" cd your-project && chiefwiggum new"));
1170
1333
  console.log();
1171
1334
  console.log("Or create a new repo here:");
1172
- console.log(import_picocolors7.default.cyan(" gh repo create"));
1335
+ console.log(import_picocolors8.default.cyan(" gh repo create"));
1173
1336
  }
1174
1337
  console.log();
1175
1338
  let exitHint = "Then run chiefwiggum new again";
@@ -1194,10 +1357,10 @@ async function setupProjectConfig() {
1194
1357
  if (fallback === "exit") {
1195
1358
  console.log();
1196
1359
  if (exitCommand) {
1197
- console.log(import_picocolors7.default.cyan(` ${exitCommand}`));
1360
+ console.log(import_picocolors8.default.cyan(` ${exitCommand}`));
1198
1361
  console.log();
1199
1362
  }
1200
- console.log(import_picocolors7.default.dim("Then run 'chiefwiggum new' again."));
1363
+ console.log(import_picocolors8.default.dim("Then run 'chiefwiggum new' again."));
1201
1364
  process.exit(0);
1202
1365
  }
1203
1366
  config2.projectTracker = "todo";
@@ -1207,11 +1370,11 @@ async function setupProjectConfig() {
1207
1370
  }
1208
1371
  }
1209
1372
  saveConfig(config2);
1210
- console.log(import_picocolors7.default.green(`\u2713 Config saved to ${CONFIG_FILE}`));
1373
+ console.log(import_picocolors8.default.green(`\u2713 Config saved to ${CONFIG_FILE}`));
1211
1374
  if (config2.projectTracker === "github") {
1212
- console.log(import_picocolors7.default.dim(" Tasks will be created as GitHub Issues."));
1375
+ console.log(import_picocolors8.default.dim(" Tasks will be created as GitHub Issues."));
1213
1376
  if (config2.githubProject) {
1214
- console.log(import_picocolors7.default.dim(` Issues will be added to board: ${config2.githubProject}`));
1377
+ console.log(import_picocolors8.default.dim(` Issues will be added to board: ${config2.githubProject}`));
1215
1378
  }
1216
1379
  }
1217
1380
  console.log();
@@ -1220,18 +1383,18 @@ async function selectOrCreateProjectBoard(knownRepo) {
1220
1383
  let repoName = knownRepo || "";
1221
1384
  if (!repoName) {
1222
1385
  try {
1223
- repoName = (0, import_node_child_process6.execSync)("gh repo view --json nameWithOwner -q .nameWithOwner", {
1386
+ repoName = (0, import_node_child_process8.execSync)("gh repo view --json nameWithOwner -q .nameWithOwner", {
1224
1387
  encoding: "utf-8",
1225
1388
  stdio: ["pipe", "pipe", "pipe"]
1226
1389
  }).trim();
1227
1390
  } catch {
1228
- console.log(import_picocolors7.default.yellow("Could not detect GitHub repo. Skipping project board setup."));
1391
+ console.log(import_picocolors8.default.yellow("Could not detect GitHub repo. Skipping project board setup."));
1229
1392
  return null;
1230
1393
  }
1231
1394
  }
1232
1395
  let existingProjects = [];
1233
1396
  try {
1234
- const projectsOutput = (0, import_node_child_process6.execSync)(`gh project list --owner ${repoName.split("/")[0]} --format json`, {
1397
+ const projectsOutput = (0, import_node_child_process8.execSync)(`gh project list --owner ${repoName.split("/")[0]} --format json`, {
1235
1398
  encoding: "utf-8",
1236
1399
  stdio: ["pipe", "pipe", "pipe"]
1237
1400
  });
@@ -1240,8 +1403,8 @@ async function selectOrCreateProjectBoard(knownRepo) {
1240
1403
  } catch {
1241
1404
  }
1242
1405
  console.log();
1243
- console.log(import_picocolors7.default.bold(`GitHub Project Board`));
1244
- console.log(import_picocolors7.default.dim(`Organize issues in a Kanban-style board for ${repoName}`));
1406
+ console.log(import_picocolors8.default.bold(`GitHub Project Board`));
1407
+ console.log(import_picocolors8.default.dim(`Organize issues in a Kanban-style board for ${repoName}`));
1245
1408
  console.log();
1246
1409
  const projectOptions = [
1247
1410
  ...existingProjects.map((name) => ({ value: name, label: name })),
@@ -1257,44 +1420,44 @@ async function selectOrCreateProjectBoard(knownRepo) {
1257
1420
  message: "Board name",
1258
1421
  placeholder: "e.g., SVG Icon Generator v2"
1259
1422
  });
1260
- console.log(import_picocolors7.default.cyan(`Creating board "${projectName}"...`));
1423
+ console.log(import_picocolors8.default.cyan(`Creating board "${projectName}"...`));
1261
1424
  try {
1262
- const createOutput = (0, import_node_child_process6.execSync)(
1425
+ const createOutput = (0, import_node_child_process8.execSync)(
1263
1426
  `gh project create --owner ${repoName.split("/")[0]} --title "${projectName}"`,
1264
1427
  { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }
1265
1428
  );
1266
1429
  const projectNumberMatch = createOutput.match(/projects\/(\d+)/);
1267
1430
  const projectNumber = projectNumberMatch ? projectNumberMatch[1] : null;
1268
- console.log(import_picocolors7.default.green(`\u2713 Board "${projectName}" created`));
1431
+ console.log(import_picocolors8.default.green(`\u2713 Board "${projectName}" created`));
1269
1432
  if (projectNumber) {
1270
1433
  try {
1271
- (0, import_node_child_process6.execSync)(`gh project link ${projectNumber} --owner ${repoName.split("/")[0]} --repo ${repoName}`, {
1434
+ (0, import_node_child_process8.execSync)(`gh project link ${projectNumber} --owner ${repoName.split("/")[0]} --repo ${repoName}`, {
1272
1435
  stdio: ["pipe", "pipe", "pipe"]
1273
1436
  });
1274
- console.log(import_picocolors7.default.green(`\u2713 Linked to ${repoName}`));
1437
+ console.log(import_picocolors8.default.green(`\u2713 Linked to ${repoName}`));
1275
1438
  } catch {
1276
- console.log(import_picocolors7.default.dim(` Note: Board created at org level. Link manually from repo's Projects tab.`));
1439
+ console.log(import_picocolors8.default.dim(` Note: Board created at org level. Link manually from repo's Projects tab.`));
1277
1440
  }
1278
1441
  }
1279
1442
  return projectName;
1280
1443
  } catch {
1281
- console.log(import_picocolors7.default.yellow("Could not create board. Issues will be created without one."));
1444
+ console.log(import_picocolors8.default.yellow("Could not create board. Issues will be created without one."));
1282
1445
  return null;
1283
1446
  }
1284
1447
  } else if (selectedProject !== "__none__") {
1285
1448
  try {
1286
- const projectsOutput = (0, import_node_child_process6.execSync)(
1449
+ const projectsOutput = (0, import_node_child_process8.execSync)(
1287
1450
  `gh project list --owner ${repoName.split("/")[0]} --format json`,
1288
1451
  { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }
1289
1452
  );
1290
1453
  const projects = JSON.parse(projectsOutput);
1291
1454
  const project = projects.projects?.find((p2) => p2.title === selectedProject);
1292
1455
  if (project?.number) {
1293
- (0, import_node_child_process6.execSync)(
1456
+ (0, import_node_child_process8.execSync)(
1294
1457
  `gh project link ${project.number} --owner ${repoName.split("/")[0]} --repo ${repoName}`,
1295
1458
  { stdio: ["pipe", "pipe", "pipe"] }
1296
1459
  );
1297
- console.log(import_picocolors7.default.green(`\u2713 Linked "${selectedProject}" to ${repoName}`));
1460
+ console.log(import_picocolors8.default.green(`\u2713 Linked "${selectedProject}" to ${repoName}`));
1298
1461
  }
1299
1462
  } catch {
1300
1463
  }
@@ -1304,7 +1467,7 @@ async function selectOrCreateProjectBoard(knownRepo) {
1304
1467
  }
1305
1468
  async function interactiveDescribe() {
1306
1469
  console.log();
1307
- console.log(import_picocolors7.default.bold("Tell me about your project"));
1470
+ console.log(import_picocolors8.default.bold("Tell me about your project"));
1308
1471
  console.log();
1309
1472
  const projectName = await text2({
1310
1473
  message: "Project name"
@@ -1345,36 +1508,36 @@ ${techStack}
1345
1508
  ## Key Features
1346
1509
  ${features}
1347
1510
  `;
1348
- (0, import_node_fs3.mkdirSync)("plans", { recursive: true });
1511
+ (0, import_node_fs4.mkdirSync)("plans", { recursive: true });
1349
1512
  const planPath = "plans/plan.md";
1350
- (0, import_node_fs3.writeFileSync)(planPath, planContent);
1513
+ (0, import_node_fs4.writeFileSync)(planPath, planContent);
1351
1514
  console.log();
1352
- console.log(import_picocolors7.default.green(`Plan saved to ${planPath}`));
1515
+ console.log(import_picocolors8.default.green(`Plan saved to ${planPath}`));
1353
1516
  await generateFromPlan(planPath);
1354
1517
  }
1355
1518
  async function generateFromPlan(planFile) {
1356
- const planContent = (0, import_node_fs3.readFileSync)(planFile, "utf-8");
1519
+ const planContent = (0, import_node_fs4.readFileSync)(planFile, "utf-8");
1357
1520
  const specsDir = config.specsDir;
1358
1521
  const todoFile = config.todoFile;
1359
1522
  const prdPath = `${specsDir}/prd.md`;
1360
1523
  const techPath = `${specsDir}/technical.md`;
1361
1524
  console.log();
1362
- console.log(import_picocolors7.default.green("\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550"));
1363
- console.log(import_picocolors7.default.green(` Generating specs from: ${planFile}`));
1364
- console.log(import_picocolors7.default.green("\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550"));
1365
- if (!(0, import_node_fs3.existsSync)(LOCAL_TEMPLATES_DIR)) {
1366
- console.log(import_picocolors7.default.red(`Templates not found at: ${LOCAL_TEMPLATES_DIR}`));
1525
+ console.log(import_picocolors8.default.green("\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550"));
1526
+ console.log(import_picocolors8.default.green(` Generating specs from: ${planFile}`));
1527
+ console.log(import_picocolors8.default.green("\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550"));
1528
+ if (!(0, import_node_fs4.existsSync)(LOCAL_TEMPLATES_DIR)) {
1529
+ console.log(import_picocolors8.default.red(`Templates not found at: ${LOCAL_TEMPLATES_DIR}`));
1367
1530
  console.log();
1368
1531
  console.log("Run 'chiefwiggum new' to set up templates first.");
1369
1532
  process.exit(1);
1370
1533
  }
1371
- (0, import_node_fs3.mkdirSync)(specsDir, { recursive: true });
1372
- const prdTemplate = (0, import_node_fs3.readFileSync)(`${LOCAL_TEMPLATES_DIR}/prd-template.md`, "utf-8");
1373
- const techTemplate = (0, import_node_fs3.readFileSync)(`${LOCAL_TEMPLATES_DIR}/technical-template.md`, "utf-8");
1374
- const todoTemplate = (0, import_node_fs3.readFileSync)(`${LOCAL_TEMPLATES_DIR}/TODO-template.md`, "utf-8");
1375
- const claudeTemplate = (0, import_node_fs3.readFileSync)(`${LOCAL_TEMPLATES_DIR}/CLAUDE-template.md`, "utf-8");
1534
+ (0, import_node_fs4.mkdirSync)(specsDir, { recursive: true });
1535
+ const prdTemplate = (0, import_node_fs4.readFileSync)(`${LOCAL_TEMPLATES_DIR}/prd-template.md`, "utf-8");
1536
+ const techTemplate = (0, import_node_fs4.readFileSync)(`${LOCAL_TEMPLATES_DIR}/technical-template.md`, "utf-8");
1537
+ const todoTemplate = (0, import_node_fs4.readFileSync)(`${LOCAL_TEMPLATES_DIR}/TODO-template.md`, "utf-8");
1538
+ const claudeTemplate = (0, import_node_fs4.readFileSync)(`${LOCAL_TEMPLATES_DIR}/CLAUDE-template.md`, "utf-8");
1376
1539
  console.log();
1377
- console.log(import_picocolors7.default.yellow(`[1/4] Generating ${prdPath}...`));
1540
+ console.log(import_picocolors8.default.yellow(`[1/4] Generating ${prdPath}...`));
1378
1541
  const planFilename = planFile.split("/").pop() || planFile;
1379
1542
  const prdPrompt = `You are filling in a PRD template based on a project plan.
1380
1543
 
@@ -1405,10 +1568,10 @@ For User Stories section:
1405
1568
  Write the completed PRD directly to ${prdPath}.
1406
1569
  Do NOT ask questions \u2014 infer everything from the plan.`;
1407
1570
  await runClaude({ prompt: prdPrompt });
1408
- console.log(import_picocolors7.default.green(` \u2713 ${prdPath}`));
1571
+ console.log(import_picocolors8.default.green(` \u2713 ${prdPath}`));
1409
1572
  console.log();
1410
- console.log(import_picocolors7.default.yellow(`[2/4] Generating ${techPath}...`));
1411
- const prdGenerated = (0, import_node_fs3.existsSync)(prdPath) ? (0, import_node_fs3.readFileSync)(prdPath, "utf-8") : "";
1573
+ console.log(import_picocolors8.default.yellow(`[2/4] Generating ${techPath}...`));
1574
+ const prdGenerated = (0, import_node_fs4.existsSync)(prdPath) ? (0, import_node_fs4.readFileSync)(prdPath, "utf-8") : "";
1412
1575
  const techPrompt = `You are filling in a Technical Specification template based on a PRD.
1413
1576
 
1414
1577
  Here is the PRD:
@@ -1426,13 +1589,13 @@ Replace all placeholder text in [brackets] with real content.
1426
1589
  Write the completed spec directly to ${techPath}.
1427
1590
  Do NOT ask questions \u2014 infer everything from the PRD.`;
1428
1591
  await runClaude({ prompt: techPrompt });
1429
- console.log(import_picocolors7.default.green(` \u2713 ${techPath}`));
1592
+ console.log(import_picocolors8.default.green(` \u2713 ${techPath}`));
1430
1593
  console.log();
1431
- if ((0, import_node_fs3.existsSync)("CLAUDE.md")) {
1432
- console.log(import_picocolors7.default.yellow("[3/4] Skipping CLAUDE.md (already exists)"));
1594
+ if ((0, import_node_fs4.existsSync)("CLAUDE.md")) {
1595
+ console.log(import_picocolors8.default.yellow("[3/4] Skipping CLAUDE.md (already exists)"));
1433
1596
  } else {
1434
- console.log(import_picocolors7.default.yellow("[3/4] Generating CLAUDE.md..."));
1435
- const techGenerated2 = (0, import_node_fs3.existsSync)(techPath) ? (0, import_node_fs3.readFileSync)(techPath, "utf-8") : "";
1597
+ console.log(import_picocolors8.default.yellow("[3/4] Generating CLAUDE.md..."));
1598
+ const techGenerated2 = (0, import_node_fs4.existsSync)(techPath) ? (0, import_node_fs4.readFileSync)(techPath, "utf-8") : "";
1436
1599
  const claudePrompt = `You are filling in a CLAUDE.md template for a project.
1437
1600
 
1438
1601
  Here is the PRD:
@@ -1455,28 +1618,28 @@ Replace all placeholder text in [brackets] with real content.
1455
1618
  Keep it concise - this is a quick reference for AI agents.
1456
1619
  Write directly to CLAUDE.md.`;
1457
1620
  await runClaude({ prompt: claudePrompt });
1458
- console.log(import_picocolors7.default.green(" \u2713 CLAUDE.md"));
1621
+ console.log(import_picocolors8.default.green(" \u2713 CLAUDE.md"));
1459
1622
  }
1460
1623
  const tracker = getProjectTracker();
1461
- const techGenerated = (0, import_node_fs3.existsSync)(techPath) ? (0, import_node_fs3.readFileSync)(techPath, "utf-8") : "";
1624
+ const techGenerated = (0, import_node_fs4.existsSync)(techPath) ? (0, import_node_fs4.readFileSync)(techPath, "utf-8") : "";
1462
1625
  if (tracker === "github") {
1463
1626
  console.log();
1464
1627
  let repoName = "";
1465
1628
  try {
1466
- repoName = (0, import_node_child_process6.execSync)("gh repo view --json nameWithOwner -q .nameWithOwner", {
1629
+ repoName = (0, import_node_child_process8.execSync)("gh repo view --json nameWithOwner -q .nameWithOwner", {
1467
1630
  encoding: "utf-8",
1468
1631
  stdio: ["pipe", "pipe", "pipe"]
1469
1632
  }).trim();
1470
1633
  } catch {
1471
- console.log(import_picocolors7.default.red("Could not detect GitHub repo. Make sure you're in a git repo with a GitHub remote."));
1634
+ console.log(import_picocolors8.default.red("Could not detect GitHub repo. Make sure you're in a git repo with a GitHub remote."));
1472
1635
  process.exit(1);
1473
1636
  }
1474
1637
  const projectName = getGithubProject();
1475
- console.log(import_picocolors7.default.yellow("[4/4] Creating GitHub Issues..."));
1638
+ console.log(import_picocolors8.default.yellow("[4/4] Creating GitHub Issues..."));
1476
1639
  if (projectName) {
1477
- console.log(import_picocolors7.default.dim(` Issues will be added to board: ${projectName}`));
1640
+ console.log(import_picocolors8.default.dim(` Issues will be added to board: ${projectName}`));
1478
1641
  }
1479
- console.log(import_picocolors7.default.dim(" Planning issues..."));
1642
+ console.log(import_picocolors8.default.dim(" Planning issues..."));
1480
1643
  const issuesPrompt = `You are planning GitHub Issues based on specs.
1481
1644
 
1482
1645
  Here is the PRD:
@@ -1514,7 +1677,7 @@ Output ONLY valid JSON, no other text:
1514
1677
  } catch {
1515
1678
  }
1516
1679
  if (issues.length === 0) {
1517
- console.log(import_picocolors7.default.dim(" Generating issues directly..."));
1680
+ console.log(import_picocolors8.default.dim(" Generating issues directly..."));
1518
1681
  const fallbackPrompt = `Create GitHub Issues using gh CLI for this project.
1519
1682
  PRD: ${prdGenerated.slice(0, 2e3)}
1520
1683
  Tech: ${techGenerated.slice(0, 2e3)}
@@ -1527,17 +1690,17 @@ Create 5-15 issues.${projectName ? ` Add each to project "${projectName}".` : ""
1527
1690
  const total = issues.length;
1528
1691
  const owner = repoName.split("/")[0];
1529
1692
  try {
1530
- (0, import_node_child_process6.execSync)(
1693
+ (0, import_node_child_process8.execSync)(
1531
1694
  `gh label create chiefwiggum --description "Created by Chief Wiggum CLI" --color "FFA500" 2>/dev/null || true`,
1532
1695
  { stdio: ["pipe", "pipe", "pipe"] }
1533
1696
  );
1534
- (0, import_node_child_process6.execSync)(
1697
+ (0, import_node_child_process8.execSync)(
1535
1698
  `gh label create epic --description "Parent tracking issue" --color "6366F1" 2>/dev/null || true`,
1536
1699
  { stdio: ["pipe", "pipe", "pipe"] }
1537
1700
  );
1538
1701
  } catch {
1539
1702
  }
1540
- console.log(import_picocolors7.default.dim(" Creating epic from PRD..."));
1703
+ console.log(import_picocolors8.default.dim(" Creating epic from PRD..."));
1541
1704
  const prdFrontmatter = parsePRDFrontmatter(prdGenerated);
1542
1705
  let epicTitle;
1543
1706
  if (prdFrontmatter?.project) {
@@ -1557,7 +1720,7 @@ _Creating issues..._
1557
1720
  let epicNumber = null;
1558
1721
  let epicUrl = null;
1559
1722
  try {
1560
- const result2 = (0, import_node_child_process6.spawnSync)("gh", [
1723
+ const result2 = (0, import_node_child_process8.spawnSync)("gh", [
1561
1724
  "issue",
1562
1725
  "create",
1563
1726
  "--title",
@@ -1577,23 +1740,23 @@ _Creating issues..._
1577
1740
  const epicNumMatch = epicUrl.match(/\/issues\/(\d+)$/);
1578
1741
  epicNumber = epicNumMatch ? parseInt(epicNumMatch[1], 10) : null;
1579
1742
  if (epicNumber) {
1580
- console.log(import_picocolors7.default.green(` \u2713 Created epic #${epicNumber}`));
1743
+ console.log(import_picocolors8.default.green(` \u2713 Created epic #${epicNumber}`));
1581
1744
  }
1582
1745
  } catch (err) {
1583
- console.log(import_picocolors7.default.yellow(" Could not create epic issue. Continuing without parent tracking..."));
1746
+ console.log(import_picocolors8.default.yellow(" Could not create epic issue. Continuing without parent tracking..."));
1584
1747
  const errMsg = err instanceof Error ? err.message : String(err);
1585
1748
  if (errMsg) {
1586
- console.log(import_picocolors7.default.dim(` ${errMsg.slice(0, 100)}`));
1749
+ console.log(import_picocolors8.default.dim(` ${errMsg.slice(0, 100)}`));
1587
1750
  }
1588
1751
  }
1589
- console.log(import_picocolors7.default.dim(` Creating ${total} child issues...`));
1752
+ console.log(import_picocolors8.default.dim(` Creating ${total} child issues...`));
1590
1753
  let projectNumber = null;
1591
1754
  let projectId = null;
1592
1755
  let statusFieldId = null;
1593
1756
  let todoOptionId = null;
1594
1757
  if (projectName) {
1595
1758
  try {
1596
- const projectsOutput = (0, import_node_child_process6.execSync)(
1759
+ const projectsOutput = (0, import_node_child_process8.execSync)(
1597
1760
  `gh project list --owner ${owner} --format json`,
1598
1761
  { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }
1599
1762
  );
@@ -1602,14 +1765,14 @@ _Creating issues..._
1602
1765
  projectNumber = project?.number?.toString() || null;
1603
1766
  if (projectNumber) {
1604
1767
  try {
1605
- (0, import_node_child_process6.execSync)(
1768
+ (0, import_node_child_process8.execSync)(
1606
1769
  `gh project link ${projectNumber} --owner ${owner} --repo ${repoName}`,
1607
1770
  { stdio: ["pipe", "pipe", "pipe"] }
1608
1771
  );
1609
1772
  } catch {
1610
1773
  }
1611
1774
  try {
1612
- const repoProjectsOutput = (0, import_node_child_process6.execSync)(
1775
+ const repoProjectsOutput = (0, import_node_child_process8.execSync)(
1613
1776
  `gh repo view --json projectsV2 -q '.projectsV2.Nodes[] | select(.number == ${projectNumber}) | .id'`,
1614
1777
  { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }
1615
1778
  );
@@ -1618,7 +1781,7 @@ _Creating issues..._
1618
1781
  }
1619
1782
  if (projectId) {
1620
1783
  try {
1621
- const fieldsOutput = (0, import_node_child_process6.execSync)(
1784
+ const fieldsOutput = (0, import_node_child_process8.execSync)(
1622
1785
  `gh project field-list ${projectNumber} --owner ${owner} --format json`,
1623
1786
  { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }
1624
1787
  );
@@ -1638,7 +1801,7 @@ _Creating issues..._
1638
1801
  }
1639
1802
  if (epicUrl && projectNumber) {
1640
1803
  try {
1641
- (0, import_node_child_process6.execSync)(
1804
+ (0, import_node_child_process8.execSync)(
1642
1805
  `gh project item-add ${projectNumber} --owner ${owner} --url "${epicUrl}"`,
1643
1806
  { stdio: ["pipe", "pipe", "pipe"] }
1644
1807
  );
@@ -1647,7 +1810,7 @@ _Creating issues..._
1647
1810
  }
1648
1811
  let availableLabels = /* @__PURE__ */ new Set();
1649
1812
  try {
1650
- const labelsOutput = (0, import_node_child_process6.execSync)("gh label list --json name --jq '.[].name'", {
1813
+ const labelsOutput = (0, import_node_child_process8.execSync)("gh label list --json name --jq '.[].name'", {
1651
1814
  encoding: "utf-8",
1652
1815
  stdio: ["pipe", "pipe", "pipe"]
1653
1816
  });
@@ -1667,12 +1830,12 @@ _Creating issues..._
1667
1830
  const barWidth = 20;
1668
1831
  const filled = Math.round(progress / 100 * barWidth);
1669
1832
  const empty = barWidth - filled;
1670
- const bar = import_picocolors7.default.green("\u2588".repeat(filled)) + import_picocolors7.default.dim("\u2591".repeat(empty));
1833
+ const bar = import_picocolors8.default.green("\u2588".repeat(filled)) + import_picocolors8.default.dim("\u2591".repeat(empty));
1671
1834
  process.stdout.write(`\r ${bar} ${progress}% (${i + 1}/${total}) Creating: ${issue.title.slice(0, 40)}...`);
1672
1835
  } else {
1673
1836
  const milestone = Math.floor(progress / 25) * 25;
1674
1837
  if (milestone > 0 && !loggedMilestones.has(milestone) && milestone < 100) {
1675
- console.log(import_picocolors7.default.dim(` ${milestone}% complete (${i + 1}/${total})...`));
1838
+ console.log(import_picocolors8.default.dim(` ${milestone}% complete (${i + 1}/${total})...`));
1676
1839
  loggedMilestones.add(milestone);
1677
1840
  }
1678
1841
  }
@@ -1687,7 +1850,7 @@ _Creating issues..._
1687
1850
 
1688
1851
  ${issue.body}`;
1689
1852
  }
1690
- const createResult = (0, import_node_child_process6.spawnSync)("gh", [
1853
+ const createResult = (0, import_node_child_process8.spawnSync)("gh", [
1691
1854
  "issue",
1692
1855
  "create",
1693
1856
  "--title",
@@ -1710,7 +1873,7 @@ ${issue.body}`;
1710
1873
  }
1711
1874
  if (projectNumber && issueUrl) {
1712
1875
  try {
1713
- const addOutput = (0, import_node_child_process6.execSync)(
1876
+ const addOutput = (0, import_node_child_process8.execSync)(
1714
1877
  `gh project item-add ${projectNumber} --owner ${owner} --url "${issueUrl}" --format json`,
1715
1878
  { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }
1716
1879
  );
@@ -1719,7 +1882,7 @@ ${issue.body}`;
1719
1882
  const addResult = JSON.parse(addOutput);
1720
1883
  const itemId = addResult.id;
1721
1884
  if (itemId) {
1722
- (0, import_node_child_process6.execSync)(
1885
+ (0, import_node_child_process8.execSync)(
1723
1886
  `gh project item-edit --project-id ${projectId} --id ${itemId} --field-id ${statusFieldId} --single-select-option-id ${todoOptionId}`,
1724
1887
  { stdio: ["pipe", "pipe", "pipe"] }
1725
1888
  );
@@ -1740,22 +1903,22 @@ ${issue.body}`;
1740
1903
  if (supportsInPlace) {
1741
1904
  process.stdout.write("\r" + " ".repeat(80) + "\r");
1742
1905
  }
1743
- console.log(import_picocolors7.default.green(` \u2713 Created ${created} GitHub Issues`));
1906
+ console.log(import_picocolors8.default.green(` \u2713 Created ${created} GitHub Issues`));
1744
1907
  if (failed > 0) {
1745
- console.log(import_picocolors7.default.yellow(` \u26A0 ${failed} issues failed to create:`));
1908
+ console.log(import_picocolors8.default.yellow(` \u26A0 ${failed} issues failed to create:`));
1746
1909
  for (const f of failedIssues) {
1747
- console.log(import_picocolors7.default.dim(` - ${f.title.slice(0, 50)}`));
1910
+ console.log(import_picocolors8.default.dim(` - ${f.title.slice(0, 50)}`));
1748
1911
  const errMatch = f.error.match(/stderr: "([^"]+)"/);
1749
1912
  if (errMatch) {
1750
- console.log(import_picocolors7.default.dim(` ${errMatch[1]}`));
1913
+ console.log(import_picocolors8.default.dim(` ${errMatch[1]}`));
1751
1914
  }
1752
1915
  }
1753
1916
  }
1754
1917
  if (projectName && projectNumber) {
1755
1918
  if (todoOptionId) {
1756
- console.log(import_picocolors7.default.green(` \u2713 Added to board "${projectName}" (Todo column)`));
1919
+ console.log(import_picocolors8.default.green(` \u2713 Added to board "${projectName}" (Todo column)`));
1757
1920
  } else {
1758
- console.log(import_picocolors7.default.green(` \u2713 Added to board "${projectName}"`));
1921
+ console.log(import_picocolors8.default.green(` \u2713 Added to board "${projectName}"`));
1759
1922
  }
1760
1923
  }
1761
1924
  if (epicNumber && createdIssueNumbers.length > 0) {
@@ -1768,7 +1931,7 @@ ${issue.body}`;
1768
1931
 
1769
1932
  ${tasklist}`;
1770
1933
  try {
1771
- const editResult = (0, import_node_child_process6.spawnSync)("gh", [
1934
+ const editResult = (0, import_node_child_process8.spawnSync)("gh", [
1772
1935
  "issue",
1773
1936
  "edit",
1774
1937
  String(epicNumber),
@@ -1779,26 +1942,26 @@ ${tasklist}`;
1779
1942
  stdio: ["pipe", "pipe", "pipe"]
1780
1943
  });
1781
1944
  if (editResult.status === 0) {
1782
- console.log(import_picocolors7.default.green(` \u2713 Updated epic #${epicNumber} with tasklist`));
1945
+ console.log(import_picocolors8.default.green(` \u2713 Updated epic #${epicNumber} with tasklist`));
1783
1946
  } else {
1784
1947
  throw new Error(editResult.stderr || "Failed");
1785
1948
  }
1786
1949
  } catch {
1787
- console.log(import_picocolors7.default.yellow(` Could not update epic with tasklist`));
1950
+ console.log(import_picocolors8.default.yellow(` Could not update epic with tasklist`));
1788
1951
  }
1789
1952
  }
1790
1953
  } else {
1791
- console.log(import_picocolors7.default.green(" \u2713 GitHub Issues created"));
1954
+ console.log(import_picocolors8.default.green(" \u2713 GitHub Issues created"));
1792
1955
  if (projectName) {
1793
- console.log(import_picocolors7.default.green(` \u2713 Added to board "${projectName}"`));
1956
+ console.log(import_picocolors8.default.green(` \u2713 Added to board "${projectName}"`));
1794
1957
  }
1795
1958
  }
1796
1959
  } else {
1797
1960
  console.log();
1798
- console.log(import_picocolors7.default.yellow(`[4/4] Generating ${todoFile}...`));
1961
+ console.log(import_picocolors8.default.yellow(`[4/4] Generating ${todoFile}...`));
1799
1962
  const todoDir = (0, import_node_path2.dirname)(todoFile);
1800
1963
  if (todoDir !== ".") {
1801
- (0, import_node_fs3.mkdirSync)(todoDir, { recursive: true });
1964
+ (0, import_node_fs4.mkdirSync)(todoDir, { recursive: true });
1802
1965
  }
1803
1966
  const todoPrompt = `You are filling in a TODO template based on specs.
1804
1967
 
@@ -1823,13 +1986,13 @@ Keep tasks granular (1-2 hours max each).
1823
1986
  End each phase with: - [ ] Phase N review
1824
1987
  Write directly to ${todoFile}.`;
1825
1988
  await runClaude({ prompt: todoPrompt });
1826
- console.log(import_picocolors7.default.green(` \u2713 ${todoFile}`));
1989
+ console.log(import_picocolors8.default.green(` \u2713 ${todoFile}`));
1827
1990
  }
1828
1991
  console.log();
1829
- console.log(import_picocolors7.default.green("Specs generated:"));
1992
+ console.log(import_picocolors8.default.green("Specs generated:"));
1830
1993
  console.log(` - ${prdPath}`);
1831
1994
  console.log(` - ${techPath}`);
1832
- if (!(0, import_node_fs3.existsSync)("CLAUDE.md")) {
1995
+ if (!(0, import_node_fs4.existsSync)("CLAUDE.md")) {
1833
1996
  console.log(" - CLAUDE.md");
1834
1997
  }
1835
1998
  if (tracker === "github") {
@@ -1838,25 +2001,25 @@ Write directly to ${todoFile}.`;
1838
2001
  console.log(` - ${todoFile}`);
1839
2002
  }
1840
2003
  try {
1841
- (0, import_node_child_process6.execSync)("git rev-parse --git-dir", { stdio: "pipe" });
2004
+ (0, import_node_child_process8.execSync)("git rev-parse --git-dir", { stdio: "pipe" });
1842
2005
  const filesToAdd = tracker === "github" ? `${specsDir}/ CLAUDE.md` : `${specsDir}/ ${todoFile} CLAUDE.md`;
1843
- (0, import_node_child_process6.execSync)(`git add ${filesToAdd} 2>/dev/null || true`, { stdio: "pipe" });
1844
- (0, import_node_child_process6.execSync)('git commit -m "chore: generate specs from plan" 2>/dev/null || true', {
2006
+ (0, import_node_child_process8.execSync)(`git add ${filesToAdd} 2>/dev/null || true`, { stdio: "pipe" });
2007
+ (0, import_node_child_process8.execSync)('git commit -m "chore: generate specs from plan" 2>/dev/null || true', {
1845
2008
  stdio: "pipe"
1846
2009
  });
1847
2010
  } catch {
1848
2011
  }
1849
2012
  }
1850
- var import_node_fs3, import_node_child_process6, import_node_path2, import_node_url, import_picocolors7, __dirname, LOCAL_TEMPLATES_DIR, CONFIG_FILE, BUNDLED_TEMPLATES_DIR, SKIP_DIRS;
2013
+ var import_node_fs4, import_node_child_process8, import_node_path2, import_node_url, import_picocolors8, __dirname, LOCAL_TEMPLATES_DIR, CONFIG_FILE, BUNDLED_TEMPLATES_DIR, SKIP_DIRS;
1851
2014
  var init_new = __esm({
1852
2015
  "src/commands/new.ts"() {
1853
2016
  "use strict";
1854
2017
  init_cjs_shims();
1855
- import_node_fs3 = require("fs");
1856
- import_node_child_process6 = require("child_process");
2018
+ import_node_fs4 = require("fs");
2019
+ import_node_child_process8 = require("child_process");
1857
2020
  import_node_path2 = require("path");
1858
2021
  import_node_url = require("url");
1859
- import_picocolors7 = __toESM(require("picocolors"), 1);
2022
+ import_picocolors8 = __toESM(require("picocolors"), 1);
1860
2023
  init_config();
1861
2024
  init_prompts();
1862
2025
  init_claude();
@@ -1881,8 +2044,8 @@ var init_new = __esm({
1881
2044
  // src/cli.ts
1882
2045
  init_cjs_shims();
1883
2046
  var import_commander = require("commander");
1884
- var import_picocolors10 = __toESM(require("picocolors"), 1);
1885
- var import_node_fs6 = require("fs");
2047
+ var import_picocolors11 = __toESM(require("picocolors"), 1);
2048
+ var import_node_fs7 = require("fs");
1886
2049
  var import_node_path3 = require("path");
1887
2050
  var import_node_url2 = require("url");
1888
2051
 
@@ -2017,9 +2180,9 @@ init_loop();
2017
2180
 
2018
2181
  // src/commands/clean.ts
2019
2182
  init_cjs_shims();
2020
- var import_node_fs4 = require("fs");
2021
- var import_node_child_process7 = require("child_process");
2022
- var import_picocolors8 = __toESM(require("picocolors"), 1);
2183
+ var import_node_fs5 = require("fs");
2184
+ var import_node_child_process9 = require("child_process");
2185
+ var import_picocolors9 = __toESM(require("picocolors"), 1);
2023
2186
  init_prompts();
2024
2187
  init_new();
2025
2188
  async function removeIssues(numbers, action) {
@@ -2028,14 +2191,14 @@ async function removeIssues(numbers, action) {
2028
2191
  for (const num of numbers) {
2029
2192
  try {
2030
2193
  if (action === "delete") {
2031
- (0, import_node_child_process7.execSync)(`gh issue delete ${num} --yes`, { stdio: ["pipe", "pipe", "pipe"] });
2194
+ (0, import_node_child_process9.execSync)(`gh issue delete ${num} --yes`, { stdio: ["pipe", "pipe", "pipe"] });
2032
2195
  } else {
2033
- (0, import_node_child_process7.execSync)(`gh issue close ${num}`, { stdio: ["pipe", "pipe", "pipe"] });
2196
+ (0, import_node_child_process9.execSync)(`gh issue close ${num}`, { stdio: ["pipe", "pipe", "pipe"] });
2034
2197
  }
2035
- console.log(import_picocolors8.default.green(`\u2713 #${num} ${action === "delete" ? "deleted" : "closed"}`));
2198
+ console.log(import_picocolors9.default.green(`\u2713 #${num} ${action === "delete" ? "deleted" : "closed"}`));
2036
2199
  success++;
2037
2200
  } catch {
2038
- console.log(import_picocolors8.default.red(`\u2717 #${num} failed`));
2201
+ console.log(import_picocolors9.default.red(`\u2717 #${num} failed`));
2039
2202
  failed++;
2040
2203
  }
2041
2204
  }
@@ -2045,17 +2208,17 @@ async function removeIssues(numbers, action) {
2045
2208
  async function cleanGitHubIssues() {
2046
2209
  let issues = [];
2047
2210
  try {
2048
- const output = (0, import_node_child_process7.execSync)(
2211
+ const output = (0, import_node_child_process9.execSync)(
2049
2212
  `gh issue list --label chiefwiggum --state open --json number,title,createdAt,labels --limit 100`,
2050
2213
  { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }
2051
2214
  );
2052
2215
  issues = JSON.parse(output);
2053
2216
  } catch {
2054
- console.log(import_picocolors8.default.yellow("Could not fetch GitHub issues."));
2217
+ console.log(import_picocolors9.default.yellow("Could not fetch GitHub issues."));
2055
2218
  return;
2056
2219
  }
2057
2220
  if (issues.length === 0) {
2058
- console.log(import_picocolors8.default.dim("No open issues with 'chiefwiggum' label found."));
2221
+ console.log(import_picocolors9.default.dim("No open issues with 'chiefwiggum' label found."));
2059
2222
  return;
2060
2223
  }
2061
2224
  const isEpic = (i) => i.labels.some((l) => l.name === "epic");
@@ -2064,15 +2227,15 @@ async function cleanGitHubIssues() {
2064
2227
  console.log();
2065
2228
  console.log(`Found ${issues.length} issues with 'chiefwiggum' label:`);
2066
2229
  if (epics.length > 0) {
2067
- console.log(import_picocolors8.default.dim(" Epics:"));
2230
+ console.log(import_picocolors9.default.dim(" Epics:"));
2068
2231
  for (const issue of epics) {
2069
- console.log(` ${import_picocolors8.default.magenta(`#${issue.number}`)} ${import_picocolors8.default.bold("\u{1F4CB}")} ${issue.title}`);
2232
+ console.log(` ${import_picocolors9.default.magenta(`#${issue.number}`)} ${import_picocolors9.default.bold("\u{1F4CB}")} ${issue.title}`);
2070
2233
  }
2071
2234
  }
2072
2235
  if (childIssues.length > 0) {
2073
- console.log(import_picocolors8.default.dim(" Tasks:"));
2236
+ console.log(import_picocolors9.default.dim(" Tasks:"));
2074
2237
  for (const issue of childIssues) {
2075
- console.log(` ${import_picocolors8.default.cyan(`#${issue.number}`)} - ${issue.title}`);
2238
+ console.log(` ${import_picocolors9.default.cyan(`#${issue.number}`)} - ${issue.title}`);
2076
2239
  }
2077
2240
  }
2078
2241
  console.log();
@@ -2098,7 +2261,7 @@ async function cleanGitHubIssues() {
2098
2261
  }))
2099
2262
  });
2100
2263
  if (selected.length === 0) {
2101
- console.log(import_picocolors8.default.yellow("No issues selected."));
2264
+ console.log(import_picocolors9.default.yellow("No issues selected."));
2102
2265
  return;
2103
2266
  }
2104
2267
  const pickAction = await select2({
@@ -2122,7 +2285,7 @@ async function cleanGitHubIssues() {
2122
2285
  }
2123
2286
  }
2124
2287
  async function cmdClean() {
2125
- console.log(import_picocolors8.default.bold("Clean Project"));
2288
+ console.log(import_picocolors9.default.bold("Clean Project"));
2126
2289
  console.log();
2127
2290
  const tracker = getProjectTracker();
2128
2291
  if (tracker === "github") {
@@ -2136,16 +2299,16 @@ async function cmdClean() {
2136
2299
  console.log();
2137
2300
  }
2138
2301
  const filesToRemove = [];
2139
- if ((0, import_node_fs4.existsSync)(".chiefwiggum")) filesToRemove.push(".chiefwiggum/");
2140
- if ((0, import_node_fs4.existsSync)("specs")) filesToRemove.push("specs/");
2141
- if ((0, import_node_fs4.existsSync)("TODO.md")) filesToRemove.push("TODO.md");
2302
+ if ((0, import_node_fs5.existsSync)(".chiefwiggum")) filesToRemove.push(".chiefwiggum/");
2303
+ if ((0, import_node_fs5.existsSync)("specs")) filesToRemove.push("specs/");
2304
+ if ((0, import_node_fs5.existsSync)("TODO.md")) filesToRemove.push("TODO.md");
2142
2305
  if (filesToRemove.length === 0) {
2143
- console.log(import_picocolors8.default.dim("No chiefwiggum files found to clean."));
2306
+ console.log(import_picocolors9.default.dim("No chiefwiggum files found to clean."));
2144
2307
  return;
2145
2308
  }
2146
2309
  console.log("Files to remove:");
2147
2310
  for (const f of filesToRemove) {
2148
- console.log(` ${import_picocolors8.default.red(f)}`);
2311
+ console.log(` ${import_picocolors9.default.red(f)}`);
2149
2312
  }
2150
2313
  console.log();
2151
2314
  const shouldClean = await confirm2({
@@ -2153,65 +2316,65 @@ async function cmdClean() {
2153
2316
  initialValue: false
2154
2317
  });
2155
2318
  if (!shouldClean) {
2156
- console.log(import_picocolors8.default.yellow("Aborted."));
2319
+ console.log(import_picocolors9.default.yellow("Aborted."));
2157
2320
  return;
2158
2321
  }
2159
2322
  for (const f of filesToRemove) {
2160
2323
  const path = f.replace(/\/$/, "");
2161
- (0, import_node_fs4.rmSync)(path, { recursive: true, force: true });
2162
- console.log(import_picocolors8.default.red(`\u2717 Removed ${f}`));
2324
+ (0, import_node_fs5.rmSync)(path, { recursive: true, force: true });
2325
+ console.log(import_picocolors9.default.red(`\u2717 Removed ${f}`));
2163
2326
  }
2164
2327
  console.log();
2165
- console.log(import_picocolors8.default.green("Clean complete."));
2328
+ console.log(import_picocolors9.default.green("Clean complete."));
2166
2329
  }
2167
2330
 
2168
2331
  // src/commands/config.ts
2169
2332
  init_cjs_shims();
2170
- var import_node_fs5 = require("fs");
2171
- var import_node_child_process8 = require("child_process");
2172
- var import_picocolors9 = __toESM(require("picocolors"), 1);
2333
+ var import_node_fs6 = require("fs");
2334
+ var import_node_child_process10 = require("child_process");
2335
+ var import_picocolors10 = __toESM(require("picocolors"), 1);
2173
2336
  init_prompts();
2174
2337
  var CONFIG_FILE2 = ".chiefwiggum/CLAUDE.md";
2175
2338
  function stripTrailingCommas2(json) {
2176
2339
  return json.replace(/,(\s*[}\]])/g, "$1");
2177
2340
  }
2178
2341
  function getConfig2() {
2179
- if (!(0, import_node_fs5.existsSync)(CONFIG_FILE2)) {
2342
+ if (!(0, import_node_fs6.existsSync)(CONFIG_FILE2)) {
2180
2343
  return { projectTracker: "todo" };
2181
2344
  }
2182
- const raw = (0, import_node_fs5.readFileSync)(CONFIG_FILE2, "utf-8");
2345
+ const raw = (0, import_node_fs6.readFileSync)(CONFIG_FILE2, "utf-8");
2183
2346
  try {
2184
2347
  return JSON.parse(raw);
2185
2348
  } catch {
2186
2349
  try {
2187
2350
  const fixed = stripTrailingCommas2(raw);
2188
2351
  const config2 = JSON.parse(fixed);
2189
- console.log(import_picocolors9.default.yellow("Note: Fixed trailing comma in config file."));
2352
+ console.log(import_picocolors10.default.yellow("Note: Fixed trailing comma in config file."));
2190
2353
  saveConfig2(config2);
2191
2354
  return config2;
2192
2355
  } catch {
2193
- console.log(import_picocolors9.default.yellow("Warning: Could not parse config file. Using defaults."));
2356
+ console.log(import_picocolors10.default.yellow("Warning: Could not parse config file. Using defaults."));
2194
2357
  return { projectTracker: "todo" };
2195
2358
  }
2196
2359
  }
2197
2360
  }
2198
2361
  function saveConfig2(config2) {
2199
- (0, import_node_fs5.mkdirSync)(".chiefwiggum", { recursive: true });
2200
- (0, import_node_fs5.writeFileSync)(CONFIG_FILE2, JSON.stringify(config2, null, 2) + "\n");
2362
+ (0, import_node_fs6.mkdirSync)(".chiefwiggum", { recursive: true });
2363
+ (0, import_node_fs6.writeFileSync)(CONFIG_FILE2, JSON.stringify(config2, null, 2) + "\n");
2201
2364
  }
2202
2365
  function checkGitHubCLI2() {
2203
2366
  try {
2204
- (0, import_node_child_process8.execSync)("which gh", { stdio: ["pipe", "pipe", "pipe"] });
2367
+ (0, import_node_child_process10.execSync)("which gh", { stdio: ["pipe", "pipe", "pipe"] });
2205
2368
  } catch {
2206
2369
  return { ok: false, reason: "not_installed" };
2207
2370
  }
2208
2371
  try {
2209
- (0, import_node_child_process8.execSync)("gh auth status", { stdio: ["pipe", "pipe", "pipe"] });
2372
+ (0, import_node_child_process10.execSync)("gh auth status", { stdio: ["pipe", "pipe", "pipe"] });
2210
2373
  } catch {
2211
2374
  return { ok: false, reason: "not_authenticated" };
2212
2375
  }
2213
2376
  try {
2214
- const repo = (0, import_node_child_process8.execSync)("gh repo view --json nameWithOwner -q .nameWithOwner", {
2377
+ const repo = (0, import_node_child_process10.execSync)("gh repo view --json nameWithOwner -q .nameWithOwner", {
2215
2378
  encoding: "utf-8",
2216
2379
  stdio: ["pipe", "pipe", "pipe"]
2217
2380
  }).trim();
@@ -2221,12 +2384,12 @@ function checkGitHubCLI2() {
2221
2384
  }
2222
2385
  }
2223
2386
  async function cmdConfig() {
2224
- console.log(import_picocolors9.default.bold("Configuration"));
2387
+ console.log(import_picocolors10.default.bold("Configuration"));
2225
2388
  console.log();
2226
2389
  const config2 = getConfig2();
2227
- console.log(`Current tracker: ${import_picocolors9.default.cyan(config2.projectTracker)}`);
2390
+ console.log(`Current tracker: ${import_picocolors10.default.cyan(config2.projectTracker)}`);
2228
2391
  if (config2.projectTracker === "github") {
2229
- console.log(`GitHub Project Board: ${import_picocolors9.default.cyan(config2.githubProject || "(none)")}`);
2392
+ console.log(`GitHub Project Board: ${import_picocolors10.default.cyan(config2.githubProject || "(none)")}`);
2230
2393
  }
2231
2394
  console.log();
2232
2395
  const newTracker = await select2({
@@ -2243,24 +2406,24 @@ async function cmdConfig() {
2243
2406
  if (!ghCheck.ok) {
2244
2407
  console.log();
2245
2408
  if (ghCheck.reason === "not_installed") {
2246
- console.log(import_picocolors9.default.yellow("GitHub CLI (gh) is not installed."));
2409
+ console.log(import_picocolors10.default.yellow("GitHub CLI (gh) is not installed."));
2247
2410
  console.log();
2248
2411
  console.log("To use GitHub Issues, install it first:");
2249
- console.log(import_picocolors9.default.cyan(" brew install gh # macOS"));
2250
- console.log(import_picocolors9.default.cyan(" sudo apt install gh # Ubuntu/Debian"));
2251
- console.log(import_picocolors9.default.dim(" https://cli.github.com for other platforms"));
2412
+ console.log(import_picocolors10.default.cyan(" brew install gh # macOS"));
2413
+ console.log(import_picocolors10.default.cyan(" sudo apt install gh # Ubuntu/Debian"));
2414
+ console.log(import_picocolors10.default.dim(" https://cli.github.com for other platforms"));
2252
2415
  } else if (ghCheck.reason === "not_authenticated") {
2253
- console.log(import_picocolors9.default.yellow("GitHub CLI is not authenticated."));
2416
+ console.log(import_picocolors10.default.yellow("GitHub CLI is not authenticated."));
2254
2417
  console.log();
2255
2418
  console.log("Run this command to log in:");
2256
- console.log(import_picocolors9.default.cyan(" gh auth login"));
2419
+ console.log(import_picocolors10.default.cyan(" gh auth login"));
2257
2420
  } else if (ghCheck.reason === "not_github_repo") {
2258
- console.log(import_picocolors9.default.yellow("This doesn't appear to be a GitHub repository."));
2421
+ console.log(import_picocolors10.default.yellow("This doesn't appear to be a GitHub repository."));
2259
2422
  console.log();
2260
2423
  console.log("Make sure you're in a git repo with a GitHub remote.");
2261
2424
  }
2262
2425
  console.log();
2263
- console.log(import_picocolors9.default.dim("Cannot switch to GitHub Issues. Keeping current tracker."));
2426
+ console.log(import_picocolors10.default.dim("Cannot switch to GitHub Issues. Keeping current tracker."));
2264
2427
  return;
2265
2428
  }
2266
2429
  config2.projectTracker = "github";
@@ -2287,32 +2450,32 @@ async function cmdConfig() {
2287
2450
  if (changed) {
2288
2451
  saveConfig2(config2);
2289
2452
  console.log();
2290
- console.log(import_picocolors9.default.green(`\u2713 Config updated`));
2291
- console.log(import_picocolors9.default.dim(` Tracker: ${config2.projectTracker}`));
2453
+ console.log(import_picocolors10.default.green(`\u2713 Config updated`));
2454
+ console.log(import_picocolors10.default.dim(` Tracker: ${config2.projectTracker}`));
2292
2455
  if (config2.projectTracker === "github" && config2.githubProject) {
2293
- console.log(import_picocolors9.default.dim(` Project board: ${config2.githubProject}`));
2456
+ console.log(import_picocolors10.default.dim(` Project board: ${config2.githubProject}`));
2294
2457
  }
2295
2458
  } else {
2296
2459
  console.log();
2297
- console.log(import_picocolors9.default.dim("No changes made."));
2460
+ console.log(import_picocolors10.default.dim("No changes made."));
2298
2461
  }
2299
2462
  }
2300
2463
  async function selectOrCreateProjectBoard2(knownRepo) {
2301
2464
  let repoName = knownRepo || "";
2302
2465
  if (!repoName) {
2303
2466
  try {
2304
- repoName = (0, import_node_child_process8.execSync)("gh repo view --json nameWithOwner -q .nameWithOwner", {
2467
+ repoName = (0, import_node_child_process10.execSync)("gh repo view --json nameWithOwner -q .nameWithOwner", {
2305
2468
  encoding: "utf-8",
2306
2469
  stdio: ["pipe", "pipe", "pipe"]
2307
2470
  }).trim();
2308
2471
  } catch {
2309
- console.log(import_picocolors9.default.yellow("Could not detect GitHub repo. Skipping project board setup."));
2472
+ console.log(import_picocolors10.default.yellow("Could not detect GitHub repo. Skipping project board setup."));
2310
2473
  return null;
2311
2474
  }
2312
2475
  }
2313
2476
  let existingProjects = [];
2314
2477
  try {
2315
- const projectsOutput = (0, import_node_child_process8.execSync)(`gh project list --owner ${repoName.split("/")[0]} --format json`, {
2478
+ const projectsOutput = (0, import_node_child_process10.execSync)(`gh project list --owner ${repoName.split("/")[0]} --format json`, {
2316
2479
  encoding: "utf-8",
2317
2480
  stdio: ["pipe", "pipe", "pipe"]
2318
2481
  });
@@ -2321,8 +2484,8 @@ async function selectOrCreateProjectBoard2(knownRepo) {
2321
2484
  } catch {
2322
2485
  }
2323
2486
  console.log();
2324
- console.log(import_picocolors9.default.bold(`GitHub Project Board`));
2325
- console.log(import_picocolors9.default.dim(`Organize issues in a Kanban-style board for ${repoName}`));
2487
+ console.log(import_picocolors10.default.bold(`GitHub Project Board`));
2488
+ console.log(import_picocolors10.default.dim(`Organize issues in a Kanban-style board for ${repoName}`));
2326
2489
  console.log();
2327
2490
  const projectOptions = [
2328
2491
  ...existingProjects.map((name) => ({ value: name, label: name })),
@@ -2338,44 +2501,44 @@ async function selectOrCreateProjectBoard2(knownRepo) {
2338
2501
  message: "Board name",
2339
2502
  placeholder: "e.g., SVG Icon Generator v2"
2340
2503
  });
2341
- console.log(import_picocolors9.default.cyan(`Creating board "${projectName}"...`));
2504
+ console.log(import_picocolors10.default.cyan(`Creating board "${projectName}"...`));
2342
2505
  try {
2343
- const createOutput = (0, import_node_child_process8.execSync)(
2506
+ const createOutput = (0, import_node_child_process10.execSync)(
2344
2507
  `gh project create --owner ${repoName.split("/")[0]} --title "${projectName}"`,
2345
2508
  { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }
2346
2509
  );
2347
2510
  const projectNumberMatch = createOutput.match(/projects\/(\d+)/);
2348
2511
  const projectNumber = projectNumberMatch ? projectNumberMatch[1] : null;
2349
- console.log(import_picocolors9.default.green(`\u2713 Board "${projectName}" created`));
2512
+ console.log(import_picocolors10.default.green(`\u2713 Board "${projectName}" created`));
2350
2513
  if (projectNumber) {
2351
2514
  try {
2352
- (0, import_node_child_process8.execSync)(`gh project link ${projectNumber} --owner ${repoName.split("/")[0]} --repo ${repoName}`, {
2515
+ (0, import_node_child_process10.execSync)(`gh project link ${projectNumber} --owner ${repoName.split("/")[0]} --repo ${repoName}`, {
2353
2516
  stdio: ["pipe", "pipe", "pipe"]
2354
2517
  });
2355
- console.log(import_picocolors9.default.green(`\u2713 Linked to ${repoName}`));
2518
+ console.log(import_picocolors10.default.green(`\u2713 Linked to ${repoName}`));
2356
2519
  } catch {
2357
- console.log(import_picocolors9.default.dim(` Note: Board created at org level. Link manually from repo's Projects tab.`));
2520
+ console.log(import_picocolors10.default.dim(` Note: Board created at org level. Link manually from repo's Projects tab.`));
2358
2521
  }
2359
2522
  }
2360
2523
  return projectName;
2361
2524
  } catch {
2362
- console.log(import_picocolors9.default.yellow("Could not create board."));
2525
+ console.log(import_picocolors10.default.yellow("Could not create board."));
2363
2526
  return null;
2364
2527
  }
2365
2528
  } else if (selectedProject !== "__none__") {
2366
2529
  try {
2367
- const projectsOutput = (0, import_node_child_process8.execSync)(
2530
+ const projectsOutput = (0, import_node_child_process10.execSync)(
2368
2531
  `gh project list --owner ${repoName.split("/")[0]} --format json`,
2369
2532
  { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }
2370
2533
  );
2371
2534
  const projects = JSON.parse(projectsOutput);
2372
2535
  const project = projects.projects?.find((p2) => p2.title === selectedProject);
2373
2536
  if (project?.number) {
2374
- (0, import_node_child_process8.execSync)(
2537
+ (0, import_node_child_process10.execSync)(
2375
2538
  `gh project link ${project.number} --owner ${repoName.split("/")[0]} --repo ${repoName}`,
2376
2539
  { stdio: ["pipe", "pipe", "pipe"] }
2377
2540
  );
2378
- console.log(import_picocolors9.default.green(`\u2713 Linked "${selectedProject}" to ${repoName}`));
2541
+ console.log(import_picocolors10.default.green(`\u2713 Linked "${selectedProject}" to ${repoName}`));
2379
2542
  }
2380
2543
  } catch {
2381
2544
  }
@@ -2389,7 +2552,7 @@ var __dirname2 = (0, import_node_path3.dirname)((0, import_node_url2.fileURLToPa
2389
2552
  function getVersion() {
2390
2553
  try {
2391
2554
  const pkgPath = (0, import_node_path3.join)(__dirname2, "..", "package.json");
2392
- const pkg = JSON.parse((0, import_node_fs6.readFileSync)(pkgPath, "utf-8"));
2555
+ const pkg = JSON.parse((0, import_node_fs7.readFileSync)(pkgPath, "utf-8"));
2393
2556
  return pkg.version || "dev";
2394
2557
  } catch {
2395
2558
  return "dev";
@@ -2422,19 +2585,19 @@ async function main() {
2422
2585
  });
2423
2586
  program.action(async () => {
2424
2587
  await showBanner(version);
2425
- const { existsSync: existsSync6 } = await import("fs");
2588
+ const { existsSync: existsSync7 } = await import("fs");
2426
2589
  const { getProjectTracker: getProjectTracker2 } = await Promise.resolve().then(() => (init_new(), new_exports));
2427
2590
  const tracker = getProjectTracker2();
2428
- if (tracker === "github" || existsSync6("TODO.md") || existsSync6(".chiefwiggum/CLAUDE.md")) {
2591
+ if (tracker === "github" || existsSync7("TODO.md") || existsSync7(".chiefwiggum/CLAUDE.md")) {
2429
2592
  await cmdLoop();
2430
2593
  } else {
2431
- console.log(import_picocolors10.default.yellow("No project configured. Run 'chiefwiggum new' to get started."));
2594
+ console.log(import_picocolors11.default.yellow("No project configured. Run 'chiefwiggum new' to get started."));
2432
2595
  process.exit(1);
2433
2596
  }
2434
2597
  });
2435
2598
  await program.parseAsync();
2436
2599
  }
2437
2600
  main().catch((err) => {
2438
- console.error(import_picocolors10.default.red("Error:"), err.message);
2601
+ console.error(import_picocolors11.default.red("Error:"), err.message);
2439
2602
  process.exit(1);
2440
2603
  });