chiefwiggum 1.3.51 → 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.
- package/dist/cli.cjs +745 -508
- package/package.json +1 -1
package/dist/cli.cjs
CHANGED
|
@@ -392,8 +392,88 @@ async function runClaude(options) {
|
|
|
392
392
|
});
|
|
393
393
|
});
|
|
394
394
|
}
|
|
395
|
-
function
|
|
396
|
-
|
|
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.
|
|
397
477
|
|
|
398
478
|
## Before Starting
|
|
399
479
|
Read these ROOT-LEVEL files only (ignore subdirectories for project context):
|
|
@@ -421,51 +501,214 @@ IMPORTANT: Only use the root-level files above for project context. Do not read
|
|
|
421
501
|
## When Done
|
|
422
502
|
Output: RALPH_COMPLETE
|
|
423
503
|
If no tasks remain: RALPH_ALL_DONE`;
|
|
424
|
-
}
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
5. Close the issue: gh issue close <number> --comment "Completed"
|
|
444
|
-
6. Update project board status to "Done"
|
|
445
|
-
7. Commit: git commit -m "type(scope): description (closes #<number>)"
|
|
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
|
+
});
|
|
446
523
|
|
|
447
|
-
|
|
448
|
-
|
|
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
|
+
}
|
|
572
|
+
}
|
|
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
|
+
});
|
|
449
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 ? `
|
|
647
|
+
## Project Board Status Updates (REQUIRED)
|
|
648
|
+
|
|
649
|
+
Pre-computed values for this project:
|
|
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}
|
|
656
|
+
|
|
657
|
+
### Step 1: Get Item ID for the Issue
|
|
658
|
+
Run this to get the ITEM_ID (replace ISSUE_NUMBER with the actual issue number):
|
|
450
659
|
\`\`\`bash
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
PROJECT_ID=$(gh repo view --json projectsV2 -q '.projectsV2.Nodes[0].id')
|
|
455
|
-
|
|
456
|
-
# Get the issue's item ID in the project
|
|
457
|
-
ITEM_ID=$(gh project item-list $PROJECT_NUM --owner $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')
|
|
661
|
+
echo "Item ID: $ITEM_ID"
|
|
662
|
+
\`\`\`
|
|
458
663
|
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
664
|
+
### Step 2: Mark In Progress (do this FIRST, before any code changes)
|
|
665
|
+
\`\`\`bash
|
|
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}
|
|
667
|
+
\`\`\`
|
|
462
668
|
|
|
463
|
-
|
|
464
|
-
|
|
669
|
+
### Step 3: Mark Done (do this AFTER closing the issue)
|
|
670
|
+
\`\`\`bash
|
|
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}
|
|
465
672
|
\`\`\`
|
|
466
673
|
|
|
467
|
-
|
|
674
|
+
**You MUST update the board status at each step. Do not skip this.**
|
|
675
|
+
` : `
|
|
676
|
+
## Project Board Status Updates
|
|
677
|
+
No project board is linked or Status field not found. Skip board status updates.
|
|
678
|
+
`;
|
|
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.
|
|
468
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}
|
|
691
|
+
## Before Starting (REQUIRED - Read these first)
|
|
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`}
|
|
694
|
+
|
|
695
|
+
IMPORTANT: Only use root-level files for project context. Do not read subdirectory README files.
|
|
696
|
+
|
|
697
|
+
## Pick an 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.`}
|
|
702
|
+
|
|
703
|
+
## Workflow
|
|
704
|
+
1. Read the issue: gh issue view <number>
|
|
705
|
+
2. **Mark issue as "In Progress" on project board** (see commands below)
|
|
706
|
+
3. Implement the code following existing patterns
|
|
707
|
+
4. Test your changes work correctly
|
|
708
|
+
5. Close the issue: gh issue close <number> --comment "Completed: <brief summary>"
|
|
709
|
+
6. **Mark issue as "Done" on project board**
|
|
710
|
+
7. Commit: git add -A && git commit -m "type(scope): description (closes #<number>)"
|
|
711
|
+
${boardInstructions}
|
|
469
712
|
## Rules
|
|
470
713
|
- ONE issue per iteration
|
|
471
714
|
- Follow existing code patterns
|
|
@@ -476,286 +719,281 @@ If any step fails (no project linked, field not found), skip and continue.
|
|
|
476
719
|
## When Done
|
|
477
720
|
Output: RALPH_COMPLETE
|
|
478
721
|
If no issues remain: RALPH_ALL_DONE`;
|
|
479
|
-
}
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
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;
|
|
496
742
|
}
|
|
497
743
|
}
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
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
|
+
};
|
|
510
891
|
}
|
|
511
|
-
|
|
892
|
+
});
|
|
893
|
+
|
|
894
|
+
// src/lib/tracker/index.ts
|
|
895
|
+
function createTracker() {
|
|
896
|
+
const type = getProjectTracker();
|
|
897
|
+
return type === "github" ? new GitHubTracker() : new TodoTracker();
|
|
512
898
|
}
|
|
513
|
-
var
|
|
514
|
-
|
|
515
|
-
"src/lib/claude.ts"() {
|
|
899
|
+
var init_tracker = __esm({
|
|
900
|
+
"src/lib/tracker/index.ts"() {
|
|
516
901
|
"use strict";
|
|
517
902
|
init_cjs_shims();
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
903
|
+
init_new();
|
|
904
|
+
init_todo();
|
|
905
|
+
init_github();
|
|
906
|
+
init_github_board();
|
|
907
|
+
init_todo();
|
|
908
|
+
init_github();
|
|
523
909
|
}
|
|
524
910
|
});
|
|
525
911
|
|
|
526
912
|
// src/commands/loop.ts
|
|
527
|
-
function
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
const
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
}
|
|
536
|
-
}
|
|
537
|
-
return count;
|
|
538
|
-
}
|
|
539
|
-
function hasUncheckedTasks() {
|
|
540
|
-
if (!(0, import_node_fs2.existsSync)(config.todoFile)) return false;
|
|
541
|
-
const content = (0, import_node_fs2.readFileSync)(config.todoFile, "utf-8");
|
|
542
|
-
return /^\s*-\s*\[\s\]/m.test(content);
|
|
543
|
-
}
|
|
544
|
-
function countOpenIssues() {
|
|
545
|
-
try {
|
|
546
|
-
const output = (0, import_node_child_process5.execSync)(
|
|
547
|
-
"gh issue list --state open --json number --jq 'length'",
|
|
548
|
-
{ encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"], timeout: 3e4 }
|
|
549
|
-
);
|
|
550
|
-
return parseInt(output.trim(), 10) || 0;
|
|
551
|
-
} catch {
|
|
552
|
-
return 0;
|
|
553
|
-
}
|
|
554
|
-
}
|
|
555
|
-
function hasOpenIssues() {
|
|
556
|
-
try {
|
|
557
|
-
const output = (0, import_node_child_process5.execSync)(
|
|
558
|
-
"gh issue list --state open --limit 1 --json number --jq 'length'",
|
|
559
|
-
{ encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"], timeout: 3e4 }
|
|
560
|
-
);
|
|
561
|
-
return parseInt(output.trim(), 10) > 0;
|
|
562
|
-
} catch {
|
|
563
|
-
return false;
|
|
564
|
-
}
|
|
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;
|
|
565
921
|
}
|
|
566
|
-
function
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
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
|
+
}
|
|
575
935
|
}
|
|
936
|
+
return null;
|
|
576
937
|
}
|
|
577
938
|
function getCurrentCommit() {
|
|
578
939
|
try {
|
|
579
|
-
return (0,
|
|
940
|
+
return (0, import_node_child_process7.execSync)("git rev-parse HEAD", { encoding: "utf-8" }).trim();
|
|
580
941
|
} catch {
|
|
581
942
|
return "none";
|
|
582
943
|
}
|
|
583
944
|
}
|
|
584
|
-
function getLinkedProjectNumber() {
|
|
585
|
-
try {
|
|
586
|
-
const output = (0, import_node_child_process5.execSync)(
|
|
587
|
-
"gh repo view --json projectsV2 -q '.projectsV2.Nodes[0].number'",
|
|
588
|
-
{ encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"], timeout: 3e4 }
|
|
589
|
-
);
|
|
590
|
-
const num = output.trim();
|
|
591
|
-
return num && num !== "null" ? num : null;
|
|
592
|
-
} catch {
|
|
593
|
-
return null;
|
|
594
|
-
}
|
|
595
|
-
}
|
|
596
|
-
async function ensureProjectLinked() {
|
|
597
|
-
if (getLinkedProjectNumber()) {
|
|
598
|
-
return;
|
|
599
|
-
}
|
|
600
|
-
const configuredProject = getGithubProject();
|
|
601
|
-
console.log();
|
|
602
|
-
console.log(import_picocolors6.default.yellow("\u26A0 No project board is linked to this repo."));
|
|
603
|
-
console.log(import_picocolors6.default.dim(" This is required for automatic status updates."));
|
|
604
|
-
console.log();
|
|
605
|
-
let repoName = "";
|
|
606
|
-
let owner = "";
|
|
607
|
-
try {
|
|
608
|
-
repoName = (0, import_node_child_process5.execSync)("gh repo view --json nameWithOwner -q .nameWithOwner", {
|
|
609
|
-
encoding: "utf-8",
|
|
610
|
-
stdio: ["pipe", "pipe", "pipe"]
|
|
611
|
-
}).trim();
|
|
612
|
-
owner = repoName.split("/")[0];
|
|
613
|
-
} catch {
|
|
614
|
-
console.log(import_picocolors6.default.red("Could not detect GitHub repo."));
|
|
615
|
-
console.log(import_picocolors6.default.dim("Continuing without project board integration..."));
|
|
616
|
-
return;
|
|
617
|
-
}
|
|
618
|
-
let existingProjects = [];
|
|
619
|
-
try {
|
|
620
|
-
const projectsOutput = (0, import_node_child_process5.execSync)(`gh project list --owner ${owner} --format json`, {
|
|
621
|
-
encoding: "utf-8",
|
|
622
|
-
stdio: ["pipe", "pipe", "pipe"]
|
|
623
|
-
});
|
|
624
|
-
const projects = JSON.parse(projectsOutput);
|
|
625
|
-
existingProjects = projects.projects?.map((p2) => ({
|
|
626
|
-
title: p2.title,
|
|
627
|
-
number: p2.number
|
|
628
|
-
})) || [];
|
|
629
|
-
} catch {
|
|
630
|
-
}
|
|
631
|
-
const options = [
|
|
632
|
-
...existingProjects.map((p2) => ({
|
|
633
|
-
value: String(p2.number),
|
|
634
|
-
label: p2.title,
|
|
635
|
-
hint: configuredProject === p2.title ? "configured" : void 0
|
|
636
|
-
})),
|
|
637
|
-
{ value: "__new__", label: "Create new board..." },
|
|
638
|
-
{ value: "__skip__", label: "Skip (automation will be limited)" }
|
|
639
|
-
];
|
|
640
|
-
const selected = await select2({
|
|
641
|
-
message: "Link a project board to this repo?",
|
|
642
|
-
options
|
|
643
|
-
});
|
|
644
|
-
if (selected === "__skip__") {
|
|
645
|
-
console.log(import_picocolors6.default.dim("Continuing without project board integration..."));
|
|
646
|
-
return;
|
|
647
|
-
}
|
|
648
|
-
if (selected === "__new__") {
|
|
649
|
-
const existingNames = new Set(existingProjects.map((p2) => p2.title.toLowerCase()));
|
|
650
|
-
const projectName = await text2({
|
|
651
|
-
message: "Board name",
|
|
652
|
-
placeholder: "e.g., My Project Kanban",
|
|
653
|
-
validate: (value) => {
|
|
654
|
-
if (!value || !value.trim()) {
|
|
655
|
-
return "Board name is required";
|
|
656
|
-
}
|
|
657
|
-
if (existingNames.has(value.trim().toLowerCase())) {
|
|
658
|
-
return `A board named "${value.trim()}" already exists. Choose a different name.`;
|
|
659
|
-
}
|
|
660
|
-
return void 0;
|
|
661
|
-
}
|
|
662
|
-
});
|
|
663
|
-
console.log(import_picocolors6.default.cyan(`Creating board "${projectName}"...`));
|
|
664
|
-
try {
|
|
665
|
-
const createOutput = (0, import_node_child_process5.execSync)(
|
|
666
|
-
`gh project create --owner ${owner} --title "${projectName}"`,
|
|
667
|
-
{ encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }
|
|
668
|
-
);
|
|
669
|
-
const projectNumberMatch = createOutput.match(/projects\/(\d+)/);
|
|
670
|
-
const projectNumber = projectNumberMatch ? projectNumberMatch[1] : null;
|
|
671
|
-
if (projectNumber) {
|
|
672
|
-
(0, import_node_child_process5.execSync)(`gh project link ${projectNumber} --owner ${owner} --repo ${repoName}`, {
|
|
673
|
-
stdio: ["pipe", "pipe", "pipe"]
|
|
674
|
-
});
|
|
675
|
-
console.log(import_picocolors6.default.green(`\u2713 Board "${projectName}" created and linked`));
|
|
676
|
-
}
|
|
677
|
-
} catch (err) {
|
|
678
|
-
console.log(import_picocolors6.default.yellow("Could not create board. Continuing without project integration..."));
|
|
679
|
-
}
|
|
680
|
-
} else {
|
|
681
|
-
const projectNumber = selected;
|
|
682
|
-
const projectTitle = existingProjects.find((p2) => String(p2.number) === projectNumber)?.title || projectNumber;
|
|
683
|
-
try {
|
|
684
|
-
(0, import_node_child_process5.execSync)(`gh project link ${projectNumber} --owner ${owner} --repo ${repoName}`, {
|
|
685
|
-
stdio: ["pipe", "pipe", "pipe"]
|
|
686
|
-
});
|
|
687
|
-
console.log(import_picocolors6.default.green(`\u2713 Linked "${projectTitle}" to ${repoName}`));
|
|
688
|
-
} catch {
|
|
689
|
-
console.log(import_picocolors6.default.yellow("Could not link project. It may already be linked."));
|
|
690
|
-
}
|
|
691
|
-
}
|
|
692
|
-
console.log();
|
|
693
|
-
}
|
|
694
945
|
function pushToOrigin() {
|
|
695
946
|
try {
|
|
696
|
-
(0,
|
|
947
|
+
(0, import_node_child_process7.execSync)("git push origin HEAD", { stdio: "pipe" });
|
|
697
948
|
console.log("Pushed to origin");
|
|
698
949
|
} catch {
|
|
699
950
|
}
|
|
700
951
|
}
|
|
701
952
|
async function cmdLoop() {
|
|
702
|
-
const tracker =
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
let hasRemainingTasks;
|
|
709
|
-
let trackerLabel;
|
|
710
|
-
let completedCount = 0;
|
|
711
|
-
if (isGitHub) {
|
|
712
|
-
maxIterations = countOpenIssues();
|
|
713
|
-
completedCount = countClosedIssues();
|
|
714
|
-
hasRemainingTasks = hasOpenIssues;
|
|
715
|
-
trackerLabel = "Issues";
|
|
716
|
-
if (maxIterations === 0) {
|
|
717
|
-
console.log(import_picocolors6.default.green("No open GitHub Issues. All done!"));
|
|
718
|
-
process.exit(0);
|
|
719
|
-
}
|
|
720
|
-
} else {
|
|
721
|
-
if (!(0, import_node_fs2.existsSync)(config.todoFile)) {
|
|
722
|
-
console.log(import_picocolors6.default.red(`Missing ${config.todoFile}`));
|
|
723
|
-
process.exit(1);
|
|
724
|
-
}
|
|
725
|
-
maxIterations = countUncheckedTasks();
|
|
726
|
-
hasRemainingTasks = hasUncheckedTasks;
|
|
727
|
-
trackerLabel = "Tasks";
|
|
728
|
-
if (maxIterations === 0) {
|
|
729
|
-
console.log(import_picocolors6.default.green(`No unchecked tasks in ${config.todoFile}. All done!`));
|
|
730
|
-
process.exit(0);
|
|
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));
|
|
731
959
|
}
|
|
960
|
+
process.exit(1);
|
|
961
|
+
}
|
|
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);
|
|
732
970
|
}
|
|
733
971
|
console.log();
|
|
734
|
-
console.log(
|
|
735
|
-
console.log(
|
|
736
|
-
if (
|
|
737
|
-
|
|
738
|
-
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)`));
|
|
739
976
|
} else {
|
|
740
|
-
console.log(
|
|
977
|
+
console.log(import_picocolors7.default.green(` ${stats.label} remaining: ${stats.remaining}`));
|
|
741
978
|
}
|
|
742
|
-
console.log(
|
|
743
|
-
console.log(
|
|
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"));
|
|
744
981
|
let consecutiveFailures = 0;
|
|
745
982
|
let noCommitCycles = 0;
|
|
746
983
|
let lastCommit = getCurrentCommit();
|
|
747
|
-
for (let i = 1; i <=
|
|
984
|
+
for (let i = 1; i <= stats.remaining; i++) {
|
|
748
985
|
console.log();
|
|
749
|
-
console.log(
|
|
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`));
|
|
750
987
|
cleanupStaleProcesses();
|
|
751
988
|
const startTime = Date.now();
|
|
752
|
-
const
|
|
989
|
+
const prompt = tracker.getTaskPrompt(planContent);
|
|
990
|
+
const result = await runTaskIteration(i, prompt);
|
|
753
991
|
const duration = Math.round((Date.now() - startTime) / 1e3);
|
|
754
992
|
console.log();
|
|
755
993
|
console.log(`Completed in ${duration}s (exit: ${result.success ? 0 : 1})`);
|
|
756
994
|
if (!result.success) {
|
|
757
995
|
consecutiveFailures++;
|
|
758
|
-
console.log(
|
|
996
|
+
console.log(import_picocolors7.default.red(`Failure ${consecutiveFailures}/${config.maxConsecutiveFailures}`));
|
|
759
997
|
await sleep(3e4);
|
|
760
998
|
} else {
|
|
761
999
|
consecutiveFailures = 0;
|
|
@@ -764,48 +1002,47 @@ async function cmdLoop() {
|
|
|
764
1002
|
if (currentCommit === lastCommit) {
|
|
765
1003
|
if (result.success) {
|
|
766
1004
|
noCommitCycles++;
|
|
767
|
-
console.log(
|
|
1005
|
+
console.log(import_picocolors7.default.yellow(`No commit (${noCommitCycles}/${config.maxNoCommitCycles})`));
|
|
768
1006
|
}
|
|
769
1007
|
} else {
|
|
770
1008
|
noCommitCycles = 0;
|
|
771
1009
|
lastCommit = currentCommit;
|
|
772
|
-
console.log(
|
|
1010
|
+
console.log(import_picocolors7.default.green(`New commit: ${currentCommit.substring(0, 7)}`));
|
|
773
1011
|
pushToOrigin();
|
|
774
1012
|
}
|
|
775
1013
|
if (consecutiveFailures >= config.maxConsecutiveFailures) {
|
|
776
|
-
console.log(
|
|
1014
|
+
console.log(import_picocolors7.default.red(`Stopping: ${config.maxConsecutiveFailures} consecutive failures`));
|
|
777
1015
|
process.exit(1);
|
|
778
1016
|
}
|
|
779
1017
|
if (noCommitCycles >= config.maxNoCommitCycles) {
|
|
780
|
-
console.log(
|
|
1018
|
+
console.log(import_picocolors7.default.red(`Stopping: No commits for ${config.maxNoCommitCycles} cycles`));
|
|
781
1019
|
process.exit(1);
|
|
782
1020
|
}
|
|
783
|
-
if (!hasRemainingTasks()) {
|
|
1021
|
+
if (!tracker.hasRemainingTasks()) {
|
|
784
1022
|
console.log();
|
|
785
|
-
console.log(
|
|
786
|
-
console.log(
|
|
787
|
-
console.log(
|
|
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"));
|
|
788
1026
|
pushToOrigin();
|
|
789
1027
|
process.exit(0);
|
|
790
1028
|
}
|
|
791
1029
|
await sleep(config.cooldownSeconds * 1e3);
|
|
792
1030
|
}
|
|
793
|
-
console.log(
|
|
1031
|
+
console.log(import_picocolors7.default.yellow(`Reached max iterations (${stats.remaining})`));
|
|
794
1032
|
pushToOrigin();
|
|
795
1033
|
}
|
|
796
|
-
var
|
|
1034
|
+
var import_node_fs3, import_node_child_process7, import_picocolors7;
|
|
797
1035
|
var init_loop = __esm({
|
|
798
1036
|
"src/commands/loop.ts"() {
|
|
799
1037
|
"use strict";
|
|
800
1038
|
init_cjs_shims();
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
1039
|
+
import_node_fs3 = require("fs");
|
|
1040
|
+
import_node_child_process7 = require("child_process");
|
|
1041
|
+
import_picocolors7 = __toESM(require("picocolors"), 1);
|
|
804
1042
|
init_config();
|
|
805
1043
|
init_claude();
|
|
806
1044
|
init_process();
|
|
807
|
-
|
|
808
|
-
init_prompts();
|
|
1045
|
+
init_tracker();
|
|
809
1046
|
}
|
|
810
1047
|
});
|
|
811
1048
|
|
|
@@ -820,28 +1057,28 @@ function stripTrailingCommas(json) {
|
|
|
820
1057
|
return json.replace(/,(\s*[}\]])/g, "$1");
|
|
821
1058
|
}
|
|
822
1059
|
function getConfig() {
|
|
823
|
-
if (!(0,
|
|
1060
|
+
if (!(0, import_node_fs4.existsSync)(CONFIG_FILE)) {
|
|
824
1061
|
return { projectTracker: "todo" };
|
|
825
1062
|
}
|
|
826
|
-
const raw = (0,
|
|
1063
|
+
const raw = (0, import_node_fs4.readFileSync)(CONFIG_FILE, "utf-8");
|
|
827
1064
|
try {
|
|
828
1065
|
return JSON.parse(raw);
|
|
829
1066
|
} catch {
|
|
830
1067
|
try {
|
|
831
1068
|
const fixed = stripTrailingCommas(raw);
|
|
832
1069
|
const config2 = JSON.parse(fixed);
|
|
833
|
-
console.log(
|
|
1070
|
+
console.log(import_picocolors8.default.yellow("Note: Fixed trailing comma in config file."));
|
|
834
1071
|
saveConfig(config2);
|
|
835
1072
|
return config2;
|
|
836
1073
|
} catch {
|
|
837
|
-
console.log(
|
|
1074
|
+
console.log(import_picocolors8.default.yellow("Warning: Could not parse config file. Using defaults."));
|
|
838
1075
|
return { projectTracker: "todo" };
|
|
839
1076
|
}
|
|
840
1077
|
}
|
|
841
1078
|
}
|
|
842
1079
|
function saveConfig(config2) {
|
|
843
|
-
(0,
|
|
844
|
-
(0,
|
|
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");
|
|
845
1082
|
}
|
|
846
1083
|
function getProjectTracker() {
|
|
847
1084
|
return getConfig().projectTracker || "todo";
|
|
@@ -850,13 +1087,13 @@ function getGithubProject() {
|
|
|
850
1087
|
return getConfig().githubProject;
|
|
851
1088
|
}
|
|
852
1089
|
function countTodoTasks() {
|
|
853
|
-
if (!(0,
|
|
854
|
-
const content = (0,
|
|
1090
|
+
if (!(0, import_node_fs4.existsSync)(config.todoFile)) return 0;
|
|
1091
|
+
const content = (0, import_node_fs4.readFileSync)(config.todoFile, "utf-8");
|
|
855
1092
|
return (content.match(/^\s*-\s*\[\s\]/gm) || []).length;
|
|
856
1093
|
}
|
|
857
1094
|
function countOpenGitHubIssues() {
|
|
858
1095
|
try {
|
|
859
|
-
const output = (0,
|
|
1096
|
+
const output = (0, import_node_child_process8.execSync)(
|
|
860
1097
|
"gh issue list --state open --json number --jq 'length'",
|
|
861
1098
|
{ encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"], timeout: 3e4 }
|
|
862
1099
|
);
|
|
@@ -884,7 +1121,7 @@ function parsePRDFrontmatter(content) {
|
|
|
884
1121
|
function findMarkdownFiles(dir, basePath = "") {
|
|
885
1122
|
const results = [];
|
|
886
1123
|
try {
|
|
887
|
-
const entries = (0,
|
|
1124
|
+
const entries = (0, import_node_fs4.readdirSync)(dir, { withFileTypes: true });
|
|
888
1125
|
for (const entry of entries) {
|
|
889
1126
|
const relativePath = basePath ? `${basePath}/${entry.name}` : entry.name;
|
|
890
1127
|
if (entry.isDirectory()) {
|
|
@@ -900,14 +1137,14 @@ function findMarkdownFiles(dir, basePath = "") {
|
|
|
900
1137
|
return results;
|
|
901
1138
|
}
|
|
902
1139
|
async function cmdNew(planFile) {
|
|
903
|
-
console.log(
|
|
1140
|
+
console.log(import_picocolors8.default.bold("Project Setup"));
|
|
904
1141
|
console.log();
|
|
905
|
-
console.log(`Working directory: ${
|
|
1142
|
+
console.log(`Working directory: ${import_picocolors8.default.cyan(process.cwd())}`);
|
|
906
1143
|
await setupProjectConfig();
|
|
907
1144
|
await setupTemplates();
|
|
908
1145
|
if (planFile) {
|
|
909
|
-
if (!(0,
|
|
910
|
-
console.log(
|
|
1146
|
+
if (!(0, import_node_fs4.existsSync)(planFile)) {
|
|
1147
|
+
console.log(import_picocolors8.default.red(`Plan file not found: ${planFile}`));
|
|
911
1148
|
process.exit(1);
|
|
912
1149
|
}
|
|
913
1150
|
await checkExistingFiles();
|
|
@@ -927,8 +1164,8 @@ async function cmdNew(planFile) {
|
|
|
927
1164
|
case "plan": {
|
|
928
1165
|
const mdFiles = findMarkdownFiles(process.cwd());
|
|
929
1166
|
if (mdFiles.length === 0) {
|
|
930
|
-
console.log(
|
|
931
|
-
console.log(
|
|
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"));
|
|
932
1169
|
process.exit(1);
|
|
933
1170
|
}
|
|
934
1171
|
console.log();
|
|
@@ -939,7 +1176,7 @@ async function cmdNew(planFile) {
|
|
|
939
1176
|
maxVisible: 15
|
|
940
1177
|
});
|
|
941
1178
|
if (!planPath) {
|
|
942
|
-
console.log(
|
|
1179
|
+
console.log(import_picocolors8.default.yellow("No plan selected."));
|
|
943
1180
|
process.exit(0);
|
|
944
1181
|
}
|
|
945
1182
|
await checkExistingFiles();
|
|
@@ -951,8 +1188,8 @@ async function cmdNew(planFile) {
|
|
|
951
1188
|
await interactiveDescribe();
|
|
952
1189
|
break;
|
|
953
1190
|
case "existing":
|
|
954
|
-
if (!(0,
|
|
955
|
-
console.log(
|
|
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."));
|
|
956
1193
|
process.exit(1);
|
|
957
1194
|
}
|
|
958
1195
|
break;
|
|
@@ -981,23 +1218,23 @@ async function cmdNew(planFile) {
|
|
|
981
1218
|
break;
|
|
982
1219
|
case "review":
|
|
983
1220
|
console.log();
|
|
984
|
-
console.log(
|
|
985
|
-
console.log(` ${
|
|
1221
|
+
console.log(import_picocolors8.default.green("Setup complete!") + " Review your files, then run:");
|
|
1222
|
+
console.log(` ${import_picocolors8.default.cyan("chiefwiggum loop")}`);
|
|
986
1223
|
break;
|
|
987
1224
|
case "exit":
|
|
988
|
-
console.log(
|
|
1225
|
+
console.log(import_picocolors8.default.yellow("Exiting."));
|
|
989
1226
|
break;
|
|
990
1227
|
}
|
|
991
1228
|
}
|
|
992
1229
|
async function checkExistingFiles() {
|
|
993
1230
|
const existingFiles = [];
|
|
994
|
-
if ((0,
|
|
995
|
-
if ((0,
|
|
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}/`);
|
|
996
1233
|
if (existingFiles.length === 0) {
|
|
997
1234
|
return true;
|
|
998
1235
|
}
|
|
999
1236
|
console.log();
|
|
1000
|
-
console.log(
|
|
1237
|
+
console.log(import_picocolors8.default.yellow("Existing files found:"));
|
|
1001
1238
|
for (const f of existingFiles) {
|
|
1002
1239
|
console.log(` - ${f}`);
|
|
1003
1240
|
}
|
|
@@ -1007,39 +1244,39 @@ async function checkExistingFiles() {
|
|
|
1007
1244
|
initialValue: false
|
|
1008
1245
|
});
|
|
1009
1246
|
if (!shouldOverwrite) {
|
|
1010
|
-
console.log(
|
|
1247
|
+
console.log(import_picocolors8.default.yellow("Aborted."));
|
|
1011
1248
|
process.exit(0);
|
|
1012
1249
|
}
|
|
1013
1250
|
return true;
|
|
1014
1251
|
}
|
|
1015
1252
|
async function setupTemplates() {
|
|
1016
|
-
if ((0,
|
|
1253
|
+
if ((0, import_node_fs4.existsSync)(LOCAL_TEMPLATES_DIR)) {
|
|
1017
1254
|
return;
|
|
1018
1255
|
}
|
|
1019
|
-
if (!(0,
|
|
1020
|
-
console.log(
|
|
1256
|
+
if (!(0, import_node_fs4.existsSync)(BUNDLED_TEMPLATES_DIR)) {
|
|
1257
|
+
console.log(import_picocolors8.default.red("Bundled templates not found. Please reinstall chiefwiggum."));
|
|
1021
1258
|
process.exit(1);
|
|
1022
1259
|
}
|
|
1023
|
-
console.log(
|
|
1024
|
-
(0,
|
|
1025
|
-
(0,
|
|
1026
|
-
console.log(
|
|
1027
|
-
console.log(
|
|
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."));
|
|
1028
1265
|
console.log();
|
|
1029
1266
|
}
|
|
1030
1267
|
function checkGitHubCLI() {
|
|
1031
1268
|
try {
|
|
1032
|
-
(0,
|
|
1269
|
+
(0, import_node_child_process8.execSync)("which gh", { stdio: ["pipe", "pipe", "pipe"] });
|
|
1033
1270
|
} catch {
|
|
1034
1271
|
return { ok: false, reason: "not_installed" };
|
|
1035
1272
|
}
|
|
1036
1273
|
try {
|
|
1037
|
-
(0,
|
|
1274
|
+
(0, import_node_child_process8.execSync)("gh auth status", { stdio: ["pipe", "pipe", "pipe"] });
|
|
1038
1275
|
} catch {
|
|
1039
1276
|
return { ok: false, reason: "not_authenticated" };
|
|
1040
1277
|
}
|
|
1041
1278
|
try {
|
|
1042
|
-
const repo = (0,
|
|
1279
|
+
const repo = (0, import_node_child_process8.execSync)("gh repo view --json nameWithOwner -q .nameWithOwner", {
|
|
1043
1280
|
encoding: "utf-8",
|
|
1044
1281
|
stdio: ["pipe", "pipe", "pipe"]
|
|
1045
1282
|
}).trim();
|
|
@@ -1050,7 +1287,7 @@ function checkGitHubCLI() {
|
|
|
1050
1287
|
}
|
|
1051
1288
|
async function setupProjectConfig() {
|
|
1052
1289
|
const existingConfig = getConfig();
|
|
1053
|
-
if ((0,
|
|
1290
|
+
if ((0, import_node_fs4.existsSync)(CONFIG_FILE)) {
|
|
1054
1291
|
if (existingConfig.projectTracker === "github" && !existingConfig.githubProject) {
|
|
1055
1292
|
const ghCheck = checkGitHubCLI();
|
|
1056
1293
|
if (ghCheck.ok) {
|
|
@@ -1058,7 +1295,7 @@ async function setupProjectConfig() {
|
|
|
1058
1295
|
const config3 = { ...existingConfig, githubProject: projectName };
|
|
1059
1296
|
saveConfig(config3);
|
|
1060
1297
|
if (projectName) {
|
|
1061
|
-
console.log(
|
|
1298
|
+
console.log(import_picocolors8.default.green(`\u2713 Project board saved: ${projectName}`));
|
|
1062
1299
|
}
|
|
1063
1300
|
}
|
|
1064
1301
|
}
|
|
@@ -1077,25 +1314,25 @@ async function setupProjectConfig() {
|
|
|
1077
1314
|
if (!ghCheck.ok) {
|
|
1078
1315
|
console.log();
|
|
1079
1316
|
if (ghCheck.reason === "not_installed") {
|
|
1080
|
-
console.log(
|
|
1317
|
+
console.log(import_picocolors8.default.yellow("GitHub CLI (gh) is not installed."));
|
|
1081
1318
|
console.log();
|
|
1082
1319
|
console.log("To use GitHub Issues, install it first:");
|
|
1083
|
-
console.log(
|
|
1084
|
-
console.log(
|
|
1085
|
-
console.log(
|
|
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"));
|
|
1086
1323
|
} else if (ghCheck.reason === "not_authenticated") {
|
|
1087
|
-
console.log(
|
|
1324
|
+
console.log(import_picocolors8.default.yellow("GitHub CLI is not authenticated."));
|
|
1088
1325
|
console.log();
|
|
1089
1326
|
console.log("Run this command to log in:");
|
|
1090
|
-
console.log(
|
|
1327
|
+
console.log(import_picocolors8.default.cyan(" gh auth login"));
|
|
1091
1328
|
} else if (ghCheck.reason === "not_github_repo") {
|
|
1092
|
-
console.log(
|
|
1329
|
+
console.log(import_picocolors8.default.yellow("Not in a GitHub repository."));
|
|
1093
1330
|
console.log();
|
|
1094
1331
|
console.log("Run chiefwiggum from inside a project directory:");
|
|
1095
|
-
console.log(
|
|
1332
|
+
console.log(import_picocolors8.default.cyan(" cd your-project && chiefwiggum new"));
|
|
1096
1333
|
console.log();
|
|
1097
1334
|
console.log("Or create a new repo here:");
|
|
1098
|
-
console.log(
|
|
1335
|
+
console.log(import_picocolors8.default.cyan(" gh repo create"));
|
|
1099
1336
|
}
|
|
1100
1337
|
console.log();
|
|
1101
1338
|
let exitHint = "Then run chiefwiggum new again";
|
|
@@ -1120,10 +1357,10 @@ async function setupProjectConfig() {
|
|
|
1120
1357
|
if (fallback === "exit") {
|
|
1121
1358
|
console.log();
|
|
1122
1359
|
if (exitCommand) {
|
|
1123
|
-
console.log(
|
|
1360
|
+
console.log(import_picocolors8.default.cyan(` ${exitCommand}`));
|
|
1124
1361
|
console.log();
|
|
1125
1362
|
}
|
|
1126
|
-
console.log(
|
|
1363
|
+
console.log(import_picocolors8.default.dim("Then run 'chiefwiggum new' again."));
|
|
1127
1364
|
process.exit(0);
|
|
1128
1365
|
}
|
|
1129
1366
|
config2.projectTracker = "todo";
|
|
@@ -1133,11 +1370,11 @@ async function setupProjectConfig() {
|
|
|
1133
1370
|
}
|
|
1134
1371
|
}
|
|
1135
1372
|
saveConfig(config2);
|
|
1136
|
-
console.log(
|
|
1373
|
+
console.log(import_picocolors8.default.green(`\u2713 Config saved to ${CONFIG_FILE}`));
|
|
1137
1374
|
if (config2.projectTracker === "github") {
|
|
1138
|
-
console.log(
|
|
1375
|
+
console.log(import_picocolors8.default.dim(" Tasks will be created as GitHub Issues."));
|
|
1139
1376
|
if (config2.githubProject) {
|
|
1140
|
-
console.log(
|
|
1377
|
+
console.log(import_picocolors8.default.dim(` Issues will be added to board: ${config2.githubProject}`));
|
|
1141
1378
|
}
|
|
1142
1379
|
}
|
|
1143
1380
|
console.log();
|
|
@@ -1146,18 +1383,18 @@ async function selectOrCreateProjectBoard(knownRepo) {
|
|
|
1146
1383
|
let repoName = knownRepo || "";
|
|
1147
1384
|
if (!repoName) {
|
|
1148
1385
|
try {
|
|
1149
|
-
repoName = (0,
|
|
1386
|
+
repoName = (0, import_node_child_process8.execSync)("gh repo view --json nameWithOwner -q .nameWithOwner", {
|
|
1150
1387
|
encoding: "utf-8",
|
|
1151
1388
|
stdio: ["pipe", "pipe", "pipe"]
|
|
1152
1389
|
}).trim();
|
|
1153
1390
|
} catch {
|
|
1154
|
-
console.log(
|
|
1391
|
+
console.log(import_picocolors8.default.yellow("Could not detect GitHub repo. Skipping project board setup."));
|
|
1155
1392
|
return null;
|
|
1156
1393
|
}
|
|
1157
1394
|
}
|
|
1158
1395
|
let existingProjects = [];
|
|
1159
1396
|
try {
|
|
1160
|
-
const projectsOutput = (0,
|
|
1397
|
+
const projectsOutput = (0, import_node_child_process8.execSync)(`gh project list --owner ${repoName.split("/")[0]} --format json`, {
|
|
1161
1398
|
encoding: "utf-8",
|
|
1162
1399
|
stdio: ["pipe", "pipe", "pipe"]
|
|
1163
1400
|
});
|
|
@@ -1166,8 +1403,8 @@ async function selectOrCreateProjectBoard(knownRepo) {
|
|
|
1166
1403
|
} catch {
|
|
1167
1404
|
}
|
|
1168
1405
|
console.log();
|
|
1169
|
-
console.log(
|
|
1170
|
-
console.log(
|
|
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}`));
|
|
1171
1408
|
console.log();
|
|
1172
1409
|
const projectOptions = [
|
|
1173
1410
|
...existingProjects.map((name) => ({ value: name, label: name })),
|
|
@@ -1183,44 +1420,44 @@ async function selectOrCreateProjectBoard(knownRepo) {
|
|
|
1183
1420
|
message: "Board name",
|
|
1184
1421
|
placeholder: "e.g., SVG Icon Generator v2"
|
|
1185
1422
|
});
|
|
1186
|
-
console.log(
|
|
1423
|
+
console.log(import_picocolors8.default.cyan(`Creating board "${projectName}"...`));
|
|
1187
1424
|
try {
|
|
1188
|
-
const createOutput = (0,
|
|
1425
|
+
const createOutput = (0, import_node_child_process8.execSync)(
|
|
1189
1426
|
`gh project create --owner ${repoName.split("/")[0]} --title "${projectName}"`,
|
|
1190
1427
|
{ encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }
|
|
1191
1428
|
);
|
|
1192
1429
|
const projectNumberMatch = createOutput.match(/projects\/(\d+)/);
|
|
1193
1430
|
const projectNumber = projectNumberMatch ? projectNumberMatch[1] : null;
|
|
1194
|
-
console.log(
|
|
1431
|
+
console.log(import_picocolors8.default.green(`\u2713 Board "${projectName}" created`));
|
|
1195
1432
|
if (projectNumber) {
|
|
1196
1433
|
try {
|
|
1197
|
-
(0,
|
|
1434
|
+
(0, import_node_child_process8.execSync)(`gh project link ${projectNumber} --owner ${repoName.split("/")[0]} --repo ${repoName}`, {
|
|
1198
1435
|
stdio: ["pipe", "pipe", "pipe"]
|
|
1199
1436
|
});
|
|
1200
|
-
console.log(
|
|
1437
|
+
console.log(import_picocolors8.default.green(`\u2713 Linked to ${repoName}`));
|
|
1201
1438
|
} catch {
|
|
1202
|
-
console.log(
|
|
1439
|
+
console.log(import_picocolors8.default.dim(` Note: Board created at org level. Link manually from repo's Projects tab.`));
|
|
1203
1440
|
}
|
|
1204
1441
|
}
|
|
1205
1442
|
return projectName;
|
|
1206
1443
|
} catch {
|
|
1207
|
-
console.log(
|
|
1444
|
+
console.log(import_picocolors8.default.yellow("Could not create board. Issues will be created without one."));
|
|
1208
1445
|
return null;
|
|
1209
1446
|
}
|
|
1210
1447
|
} else if (selectedProject !== "__none__") {
|
|
1211
1448
|
try {
|
|
1212
|
-
const projectsOutput = (0,
|
|
1449
|
+
const projectsOutput = (0, import_node_child_process8.execSync)(
|
|
1213
1450
|
`gh project list --owner ${repoName.split("/")[0]} --format json`,
|
|
1214
1451
|
{ encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }
|
|
1215
1452
|
);
|
|
1216
1453
|
const projects = JSON.parse(projectsOutput);
|
|
1217
1454
|
const project = projects.projects?.find((p2) => p2.title === selectedProject);
|
|
1218
1455
|
if (project?.number) {
|
|
1219
|
-
(0,
|
|
1456
|
+
(0, import_node_child_process8.execSync)(
|
|
1220
1457
|
`gh project link ${project.number} --owner ${repoName.split("/")[0]} --repo ${repoName}`,
|
|
1221
1458
|
{ stdio: ["pipe", "pipe", "pipe"] }
|
|
1222
1459
|
);
|
|
1223
|
-
console.log(
|
|
1460
|
+
console.log(import_picocolors8.default.green(`\u2713 Linked "${selectedProject}" to ${repoName}`));
|
|
1224
1461
|
}
|
|
1225
1462
|
} catch {
|
|
1226
1463
|
}
|
|
@@ -1230,7 +1467,7 @@ async function selectOrCreateProjectBoard(knownRepo) {
|
|
|
1230
1467
|
}
|
|
1231
1468
|
async function interactiveDescribe() {
|
|
1232
1469
|
console.log();
|
|
1233
|
-
console.log(
|
|
1470
|
+
console.log(import_picocolors8.default.bold("Tell me about your project"));
|
|
1234
1471
|
console.log();
|
|
1235
1472
|
const projectName = await text2({
|
|
1236
1473
|
message: "Project name"
|
|
@@ -1271,36 +1508,36 @@ ${techStack}
|
|
|
1271
1508
|
## Key Features
|
|
1272
1509
|
${features}
|
|
1273
1510
|
`;
|
|
1274
|
-
(0,
|
|
1511
|
+
(0, import_node_fs4.mkdirSync)("plans", { recursive: true });
|
|
1275
1512
|
const planPath = "plans/plan.md";
|
|
1276
|
-
(0,
|
|
1513
|
+
(0, import_node_fs4.writeFileSync)(planPath, planContent);
|
|
1277
1514
|
console.log();
|
|
1278
|
-
console.log(
|
|
1515
|
+
console.log(import_picocolors8.default.green(`Plan saved to ${planPath}`));
|
|
1279
1516
|
await generateFromPlan(planPath);
|
|
1280
1517
|
}
|
|
1281
1518
|
async function generateFromPlan(planFile) {
|
|
1282
|
-
const planContent = (0,
|
|
1519
|
+
const planContent = (0, import_node_fs4.readFileSync)(planFile, "utf-8");
|
|
1283
1520
|
const specsDir = config.specsDir;
|
|
1284
1521
|
const todoFile = config.todoFile;
|
|
1285
1522
|
const prdPath = `${specsDir}/prd.md`;
|
|
1286
1523
|
const techPath = `${specsDir}/technical.md`;
|
|
1287
1524
|
console.log();
|
|
1288
|
-
console.log(
|
|
1289
|
-
console.log(
|
|
1290
|
-
console.log(
|
|
1291
|
-
if (!(0,
|
|
1292
|
-
console.log(
|
|
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}`));
|
|
1293
1530
|
console.log();
|
|
1294
1531
|
console.log("Run 'chiefwiggum new' to set up templates first.");
|
|
1295
1532
|
process.exit(1);
|
|
1296
1533
|
}
|
|
1297
|
-
(0,
|
|
1298
|
-
const prdTemplate = (0,
|
|
1299
|
-
const techTemplate = (0,
|
|
1300
|
-
const todoTemplate = (0,
|
|
1301
|
-
const claudeTemplate = (0,
|
|
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");
|
|
1302
1539
|
console.log();
|
|
1303
|
-
console.log(
|
|
1540
|
+
console.log(import_picocolors8.default.yellow(`[1/4] Generating ${prdPath}...`));
|
|
1304
1541
|
const planFilename = planFile.split("/").pop() || planFile;
|
|
1305
1542
|
const prdPrompt = `You are filling in a PRD template based on a project plan.
|
|
1306
1543
|
|
|
@@ -1331,10 +1568,10 @@ For User Stories section:
|
|
|
1331
1568
|
Write the completed PRD directly to ${prdPath}.
|
|
1332
1569
|
Do NOT ask questions \u2014 infer everything from the plan.`;
|
|
1333
1570
|
await runClaude({ prompt: prdPrompt });
|
|
1334
|
-
console.log(
|
|
1571
|
+
console.log(import_picocolors8.default.green(` \u2713 ${prdPath}`));
|
|
1335
1572
|
console.log();
|
|
1336
|
-
console.log(
|
|
1337
|
-
const prdGenerated = (0,
|
|
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") : "";
|
|
1338
1575
|
const techPrompt = `You are filling in a Technical Specification template based on a PRD.
|
|
1339
1576
|
|
|
1340
1577
|
Here is the PRD:
|
|
@@ -1352,13 +1589,13 @@ Replace all placeholder text in [brackets] with real content.
|
|
|
1352
1589
|
Write the completed spec directly to ${techPath}.
|
|
1353
1590
|
Do NOT ask questions \u2014 infer everything from the PRD.`;
|
|
1354
1591
|
await runClaude({ prompt: techPrompt });
|
|
1355
|
-
console.log(
|
|
1592
|
+
console.log(import_picocolors8.default.green(` \u2713 ${techPath}`));
|
|
1356
1593
|
console.log();
|
|
1357
|
-
if ((0,
|
|
1358
|
-
console.log(
|
|
1594
|
+
if ((0, import_node_fs4.existsSync)("CLAUDE.md")) {
|
|
1595
|
+
console.log(import_picocolors8.default.yellow("[3/4] Skipping CLAUDE.md (already exists)"));
|
|
1359
1596
|
} else {
|
|
1360
|
-
console.log(
|
|
1361
|
-
const techGenerated2 = (0,
|
|
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") : "";
|
|
1362
1599
|
const claudePrompt = `You are filling in a CLAUDE.md template for a project.
|
|
1363
1600
|
|
|
1364
1601
|
Here is the PRD:
|
|
@@ -1381,28 +1618,28 @@ Replace all placeholder text in [brackets] with real content.
|
|
|
1381
1618
|
Keep it concise - this is a quick reference for AI agents.
|
|
1382
1619
|
Write directly to CLAUDE.md.`;
|
|
1383
1620
|
await runClaude({ prompt: claudePrompt });
|
|
1384
|
-
console.log(
|
|
1621
|
+
console.log(import_picocolors8.default.green(" \u2713 CLAUDE.md"));
|
|
1385
1622
|
}
|
|
1386
1623
|
const tracker = getProjectTracker();
|
|
1387
|
-
const techGenerated = (0,
|
|
1624
|
+
const techGenerated = (0, import_node_fs4.existsSync)(techPath) ? (0, import_node_fs4.readFileSync)(techPath, "utf-8") : "";
|
|
1388
1625
|
if (tracker === "github") {
|
|
1389
1626
|
console.log();
|
|
1390
1627
|
let repoName = "";
|
|
1391
1628
|
try {
|
|
1392
|
-
repoName = (0,
|
|
1629
|
+
repoName = (0, import_node_child_process8.execSync)("gh repo view --json nameWithOwner -q .nameWithOwner", {
|
|
1393
1630
|
encoding: "utf-8",
|
|
1394
1631
|
stdio: ["pipe", "pipe", "pipe"]
|
|
1395
1632
|
}).trim();
|
|
1396
1633
|
} catch {
|
|
1397
|
-
console.log(
|
|
1634
|
+
console.log(import_picocolors8.default.red("Could not detect GitHub repo. Make sure you're in a git repo with a GitHub remote."));
|
|
1398
1635
|
process.exit(1);
|
|
1399
1636
|
}
|
|
1400
1637
|
const projectName = getGithubProject();
|
|
1401
|
-
console.log(
|
|
1638
|
+
console.log(import_picocolors8.default.yellow("[4/4] Creating GitHub Issues..."));
|
|
1402
1639
|
if (projectName) {
|
|
1403
|
-
console.log(
|
|
1640
|
+
console.log(import_picocolors8.default.dim(` Issues will be added to board: ${projectName}`));
|
|
1404
1641
|
}
|
|
1405
|
-
console.log(
|
|
1642
|
+
console.log(import_picocolors8.default.dim(" Planning issues..."));
|
|
1406
1643
|
const issuesPrompt = `You are planning GitHub Issues based on specs.
|
|
1407
1644
|
|
|
1408
1645
|
Here is the PRD:
|
|
@@ -1440,7 +1677,7 @@ Output ONLY valid JSON, no other text:
|
|
|
1440
1677
|
} catch {
|
|
1441
1678
|
}
|
|
1442
1679
|
if (issues.length === 0) {
|
|
1443
|
-
console.log(
|
|
1680
|
+
console.log(import_picocolors8.default.dim(" Generating issues directly..."));
|
|
1444
1681
|
const fallbackPrompt = `Create GitHub Issues using gh CLI for this project.
|
|
1445
1682
|
PRD: ${prdGenerated.slice(0, 2e3)}
|
|
1446
1683
|
Tech: ${techGenerated.slice(0, 2e3)}
|
|
@@ -1453,17 +1690,17 @@ Create 5-15 issues.${projectName ? ` Add each to project "${projectName}".` : ""
|
|
|
1453
1690
|
const total = issues.length;
|
|
1454
1691
|
const owner = repoName.split("/")[0];
|
|
1455
1692
|
try {
|
|
1456
|
-
(0,
|
|
1693
|
+
(0, import_node_child_process8.execSync)(
|
|
1457
1694
|
`gh label create chiefwiggum --description "Created by Chief Wiggum CLI" --color "FFA500" 2>/dev/null || true`,
|
|
1458
1695
|
{ stdio: ["pipe", "pipe", "pipe"] }
|
|
1459
1696
|
);
|
|
1460
|
-
(0,
|
|
1697
|
+
(0, import_node_child_process8.execSync)(
|
|
1461
1698
|
`gh label create epic --description "Parent tracking issue" --color "6366F1" 2>/dev/null || true`,
|
|
1462
1699
|
{ stdio: ["pipe", "pipe", "pipe"] }
|
|
1463
1700
|
);
|
|
1464
1701
|
} catch {
|
|
1465
1702
|
}
|
|
1466
|
-
console.log(
|
|
1703
|
+
console.log(import_picocolors8.default.dim(" Creating epic from PRD..."));
|
|
1467
1704
|
const prdFrontmatter = parsePRDFrontmatter(prdGenerated);
|
|
1468
1705
|
let epicTitle;
|
|
1469
1706
|
if (prdFrontmatter?.project) {
|
|
@@ -1483,7 +1720,7 @@ _Creating issues..._
|
|
|
1483
1720
|
let epicNumber = null;
|
|
1484
1721
|
let epicUrl = null;
|
|
1485
1722
|
try {
|
|
1486
|
-
const result2 = (0,
|
|
1723
|
+
const result2 = (0, import_node_child_process8.spawnSync)("gh", [
|
|
1487
1724
|
"issue",
|
|
1488
1725
|
"create",
|
|
1489
1726
|
"--title",
|
|
@@ -1503,23 +1740,23 @@ _Creating issues..._
|
|
|
1503
1740
|
const epicNumMatch = epicUrl.match(/\/issues\/(\d+)$/);
|
|
1504
1741
|
epicNumber = epicNumMatch ? parseInt(epicNumMatch[1], 10) : null;
|
|
1505
1742
|
if (epicNumber) {
|
|
1506
|
-
console.log(
|
|
1743
|
+
console.log(import_picocolors8.default.green(` \u2713 Created epic #${epicNumber}`));
|
|
1507
1744
|
}
|
|
1508
1745
|
} catch (err) {
|
|
1509
|
-
console.log(
|
|
1746
|
+
console.log(import_picocolors8.default.yellow(" Could not create epic issue. Continuing without parent tracking..."));
|
|
1510
1747
|
const errMsg = err instanceof Error ? err.message : String(err);
|
|
1511
1748
|
if (errMsg) {
|
|
1512
|
-
console.log(
|
|
1749
|
+
console.log(import_picocolors8.default.dim(` ${errMsg.slice(0, 100)}`));
|
|
1513
1750
|
}
|
|
1514
1751
|
}
|
|
1515
|
-
console.log(
|
|
1752
|
+
console.log(import_picocolors8.default.dim(` Creating ${total} child issues...`));
|
|
1516
1753
|
let projectNumber = null;
|
|
1517
1754
|
let projectId = null;
|
|
1518
1755
|
let statusFieldId = null;
|
|
1519
1756
|
let todoOptionId = null;
|
|
1520
1757
|
if (projectName) {
|
|
1521
1758
|
try {
|
|
1522
|
-
const projectsOutput = (0,
|
|
1759
|
+
const projectsOutput = (0, import_node_child_process8.execSync)(
|
|
1523
1760
|
`gh project list --owner ${owner} --format json`,
|
|
1524
1761
|
{ encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }
|
|
1525
1762
|
);
|
|
@@ -1528,14 +1765,14 @@ _Creating issues..._
|
|
|
1528
1765
|
projectNumber = project?.number?.toString() || null;
|
|
1529
1766
|
if (projectNumber) {
|
|
1530
1767
|
try {
|
|
1531
|
-
(0,
|
|
1768
|
+
(0, import_node_child_process8.execSync)(
|
|
1532
1769
|
`gh project link ${projectNumber} --owner ${owner} --repo ${repoName}`,
|
|
1533
1770
|
{ stdio: ["pipe", "pipe", "pipe"] }
|
|
1534
1771
|
);
|
|
1535
1772
|
} catch {
|
|
1536
1773
|
}
|
|
1537
1774
|
try {
|
|
1538
|
-
const repoProjectsOutput = (0,
|
|
1775
|
+
const repoProjectsOutput = (0, import_node_child_process8.execSync)(
|
|
1539
1776
|
`gh repo view --json projectsV2 -q '.projectsV2.Nodes[] | select(.number == ${projectNumber}) | .id'`,
|
|
1540
1777
|
{ encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }
|
|
1541
1778
|
);
|
|
@@ -1544,7 +1781,7 @@ _Creating issues..._
|
|
|
1544
1781
|
}
|
|
1545
1782
|
if (projectId) {
|
|
1546
1783
|
try {
|
|
1547
|
-
const fieldsOutput = (0,
|
|
1784
|
+
const fieldsOutput = (0, import_node_child_process8.execSync)(
|
|
1548
1785
|
`gh project field-list ${projectNumber} --owner ${owner} --format json`,
|
|
1549
1786
|
{ encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }
|
|
1550
1787
|
);
|
|
@@ -1564,7 +1801,7 @@ _Creating issues..._
|
|
|
1564
1801
|
}
|
|
1565
1802
|
if (epicUrl && projectNumber) {
|
|
1566
1803
|
try {
|
|
1567
|
-
(0,
|
|
1804
|
+
(0, import_node_child_process8.execSync)(
|
|
1568
1805
|
`gh project item-add ${projectNumber} --owner ${owner} --url "${epicUrl}"`,
|
|
1569
1806
|
{ stdio: ["pipe", "pipe", "pipe"] }
|
|
1570
1807
|
);
|
|
@@ -1573,7 +1810,7 @@ _Creating issues..._
|
|
|
1573
1810
|
}
|
|
1574
1811
|
let availableLabels = /* @__PURE__ */ new Set();
|
|
1575
1812
|
try {
|
|
1576
|
-
const labelsOutput = (0,
|
|
1813
|
+
const labelsOutput = (0, import_node_child_process8.execSync)("gh label list --json name --jq '.[].name'", {
|
|
1577
1814
|
encoding: "utf-8",
|
|
1578
1815
|
stdio: ["pipe", "pipe", "pipe"]
|
|
1579
1816
|
});
|
|
@@ -1593,12 +1830,12 @@ _Creating issues..._
|
|
|
1593
1830
|
const barWidth = 20;
|
|
1594
1831
|
const filled = Math.round(progress / 100 * barWidth);
|
|
1595
1832
|
const empty = barWidth - filled;
|
|
1596
|
-
const bar =
|
|
1833
|
+
const bar = import_picocolors8.default.green("\u2588".repeat(filled)) + import_picocolors8.default.dim("\u2591".repeat(empty));
|
|
1597
1834
|
process.stdout.write(`\r ${bar} ${progress}% (${i + 1}/${total}) Creating: ${issue.title.slice(0, 40)}...`);
|
|
1598
1835
|
} else {
|
|
1599
1836
|
const milestone = Math.floor(progress / 25) * 25;
|
|
1600
1837
|
if (milestone > 0 && !loggedMilestones.has(milestone) && milestone < 100) {
|
|
1601
|
-
console.log(
|
|
1838
|
+
console.log(import_picocolors8.default.dim(` ${milestone}% complete (${i + 1}/${total})...`));
|
|
1602
1839
|
loggedMilestones.add(milestone);
|
|
1603
1840
|
}
|
|
1604
1841
|
}
|
|
@@ -1613,7 +1850,7 @@ _Creating issues..._
|
|
|
1613
1850
|
|
|
1614
1851
|
${issue.body}`;
|
|
1615
1852
|
}
|
|
1616
|
-
const createResult = (0,
|
|
1853
|
+
const createResult = (0, import_node_child_process8.spawnSync)("gh", [
|
|
1617
1854
|
"issue",
|
|
1618
1855
|
"create",
|
|
1619
1856
|
"--title",
|
|
@@ -1636,7 +1873,7 @@ ${issue.body}`;
|
|
|
1636
1873
|
}
|
|
1637
1874
|
if (projectNumber && issueUrl) {
|
|
1638
1875
|
try {
|
|
1639
|
-
const addOutput = (0,
|
|
1876
|
+
const addOutput = (0, import_node_child_process8.execSync)(
|
|
1640
1877
|
`gh project item-add ${projectNumber} --owner ${owner} --url "${issueUrl}" --format json`,
|
|
1641
1878
|
{ encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }
|
|
1642
1879
|
);
|
|
@@ -1645,7 +1882,7 @@ ${issue.body}`;
|
|
|
1645
1882
|
const addResult = JSON.parse(addOutput);
|
|
1646
1883
|
const itemId = addResult.id;
|
|
1647
1884
|
if (itemId) {
|
|
1648
|
-
(0,
|
|
1885
|
+
(0, import_node_child_process8.execSync)(
|
|
1649
1886
|
`gh project item-edit --project-id ${projectId} --id ${itemId} --field-id ${statusFieldId} --single-select-option-id ${todoOptionId}`,
|
|
1650
1887
|
{ stdio: ["pipe", "pipe", "pipe"] }
|
|
1651
1888
|
);
|
|
@@ -1666,22 +1903,22 @@ ${issue.body}`;
|
|
|
1666
1903
|
if (supportsInPlace) {
|
|
1667
1904
|
process.stdout.write("\r" + " ".repeat(80) + "\r");
|
|
1668
1905
|
}
|
|
1669
|
-
console.log(
|
|
1906
|
+
console.log(import_picocolors8.default.green(` \u2713 Created ${created} GitHub Issues`));
|
|
1670
1907
|
if (failed > 0) {
|
|
1671
|
-
console.log(
|
|
1908
|
+
console.log(import_picocolors8.default.yellow(` \u26A0 ${failed} issues failed to create:`));
|
|
1672
1909
|
for (const f of failedIssues) {
|
|
1673
|
-
console.log(
|
|
1910
|
+
console.log(import_picocolors8.default.dim(` - ${f.title.slice(0, 50)}`));
|
|
1674
1911
|
const errMatch = f.error.match(/stderr: "([^"]+)"/);
|
|
1675
1912
|
if (errMatch) {
|
|
1676
|
-
console.log(
|
|
1913
|
+
console.log(import_picocolors8.default.dim(` ${errMatch[1]}`));
|
|
1677
1914
|
}
|
|
1678
1915
|
}
|
|
1679
1916
|
}
|
|
1680
1917
|
if (projectName && projectNumber) {
|
|
1681
1918
|
if (todoOptionId) {
|
|
1682
|
-
console.log(
|
|
1919
|
+
console.log(import_picocolors8.default.green(` \u2713 Added to board "${projectName}" (Todo column)`));
|
|
1683
1920
|
} else {
|
|
1684
|
-
console.log(
|
|
1921
|
+
console.log(import_picocolors8.default.green(` \u2713 Added to board "${projectName}"`));
|
|
1685
1922
|
}
|
|
1686
1923
|
}
|
|
1687
1924
|
if (epicNumber && createdIssueNumbers.length > 0) {
|
|
@@ -1694,7 +1931,7 @@ ${issue.body}`;
|
|
|
1694
1931
|
|
|
1695
1932
|
${tasklist}`;
|
|
1696
1933
|
try {
|
|
1697
|
-
const editResult = (0,
|
|
1934
|
+
const editResult = (0, import_node_child_process8.spawnSync)("gh", [
|
|
1698
1935
|
"issue",
|
|
1699
1936
|
"edit",
|
|
1700
1937
|
String(epicNumber),
|
|
@@ -1705,26 +1942,26 @@ ${tasklist}`;
|
|
|
1705
1942
|
stdio: ["pipe", "pipe", "pipe"]
|
|
1706
1943
|
});
|
|
1707
1944
|
if (editResult.status === 0) {
|
|
1708
|
-
console.log(
|
|
1945
|
+
console.log(import_picocolors8.default.green(` \u2713 Updated epic #${epicNumber} with tasklist`));
|
|
1709
1946
|
} else {
|
|
1710
1947
|
throw new Error(editResult.stderr || "Failed");
|
|
1711
1948
|
}
|
|
1712
1949
|
} catch {
|
|
1713
|
-
console.log(
|
|
1950
|
+
console.log(import_picocolors8.default.yellow(` Could not update epic with tasklist`));
|
|
1714
1951
|
}
|
|
1715
1952
|
}
|
|
1716
1953
|
} else {
|
|
1717
|
-
console.log(
|
|
1954
|
+
console.log(import_picocolors8.default.green(" \u2713 GitHub Issues created"));
|
|
1718
1955
|
if (projectName) {
|
|
1719
|
-
console.log(
|
|
1956
|
+
console.log(import_picocolors8.default.green(` \u2713 Added to board "${projectName}"`));
|
|
1720
1957
|
}
|
|
1721
1958
|
}
|
|
1722
1959
|
} else {
|
|
1723
1960
|
console.log();
|
|
1724
|
-
console.log(
|
|
1961
|
+
console.log(import_picocolors8.default.yellow(`[4/4] Generating ${todoFile}...`));
|
|
1725
1962
|
const todoDir = (0, import_node_path2.dirname)(todoFile);
|
|
1726
1963
|
if (todoDir !== ".") {
|
|
1727
|
-
(0,
|
|
1964
|
+
(0, import_node_fs4.mkdirSync)(todoDir, { recursive: true });
|
|
1728
1965
|
}
|
|
1729
1966
|
const todoPrompt = `You are filling in a TODO template based on specs.
|
|
1730
1967
|
|
|
@@ -1749,13 +1986,13 @@ Keep tasks granular (1-2 hours max each).
|
|
|
1749
1986
|
End each phase with: - [ ] Phase N review
|
|
1750
1987
|
Write directly to ${todoFile}.`;
|
|
1751
1988
|
await runClaude({ prompt: todoPrompt });
|
|
1752
|
-
console.log(
|
|
1989
|
+
console.log(import_picocolors8.default.green(` \u2713 ${todoFile}`));
|
|
1753
1990
|
}
|
|
1754
1991
|
console.log();
|
|
1755
|
-
console.log(
|
|
1992
|
+
console.log(import_picocolors8.default.green("Specs generated:"));
|
|
1756
1993
|
console.log(` - ${prdPath}`);
|
|
1757
1994
|
console.log(` - ${techPath}`);
|
|
1758
|
-
if (!(0,
|
|
1995
|
+
if (!(0, import_node_fs4.existsSync)("CLAUDE.md")) {
|
|
1759
1996
|
console.log(" - CLAUDE.md");
|
|
1760
1997
|
}
|
|
1761
1998
|
if (tracker === "github") {
|
|
@@ -1764,25 +2001,25 @@ Write directly to ${todoFile}.`;
|
|
|
1764
2001
|
console.log(` - ${todoFile}`);
|
|
1765
2002
|
}
|
|
1766
2003
|
try {
|
|
1767
|
-
(0,
|
|
2004
|
+
(0, import_node_child_process8.execSync)("git rev-parse --git-dir", { stdio: "pipe" });
|
|
1768
2005
|
const filesToAdd = tracker === "github" ? `${specsDir}/ CLAUDE.md` : `${specsDir}/ ${todoFile} CLAUDE.md`;
|
|
1769
|
-
(0,
|
|
1770
|
-
(0,
|
|
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', {
|
|
1771
2008
|
stdio: "pipe"
|
|
1772
2009
|
});
|
|
1773
2010
|
} catch {
|
|
1774
2011
|
}
|
|
1775
2012
|
}
|
|
1776
|
-
var
|
|
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;
|
|
1777
2014
|
var init_new = __esm({
|
|
1778
2015
|
"src/commands/new.ts"() {
|
|
1779
2016
|
"use strict";
|
|
1780
2017
|
init_cjs_shims();
|
|
1781
|
-
|
|
1782
|
-
|
|
2018
|
+
import_node_fs4 = require("fs");
|
|
2019
|
+
import_node_child_process8 = require("child_process");
|
|
1783
2020
|
import_node_path2 = require("path");
|
|
1784
2021
|
import_node_url = require("url");
|
|
1785
|
-
|
|
2022
|
+
import_picocolors8 = __toESM(require("picocolors"), 1);
|
|
1786
2023
|
init_config();
|
|
1787
2024
|
init_prompts();
|
|
1788
2025
|
init_claude();
|
|
@@ -1807,8 +2044,8 @@ var init_new = __esm({
|
|
|
1807
2044
|
// src/cli.ts
|
|
1808
2045
|
init_cjs_shims();
|
|
1809
2046
|
var import_commander = require("commander");
|
|
1810
|
-
var
|
|
1811
|
-
var
|
|
2047
|
+
var import_picocolors11 = __toESM(require("picocolors"), 1);
|
|
2048
|
+
var import_node_fs7 = require("fs");
|
|
1812
2049
|
var import_node_path3 = require("path");
|
|
1813
2050
|
var import_node_url2 = require("url");
|
|
1814
2051
|
|
|
@@ -1943,9 +2180,9 @@ init_loop();
|
|
|
1943
2180
|
|
|
1944
2181
|
// src/commands/clean.ts
|
|
1945
2182
|
init_cjs_shims();
|
|
1946
|
-
var
|
|
1947
|
-
var
|
|
1948
|
-
var
|
|
2183
|
+
var import_node_fs5 = require("fs");
|
|
2184
|
+
var import_node_child_process9 = require("child_process");
|
|
2185
|
+
var import_picocolors9 = __toESM(require("picocolors"), 1);
|
|
1949
2186
|
init_prompts();
|
|
1950
2187
|
init_new();
|
|
1951
2188
|
async function removeIssues(numbers, action) {
|
|
@@ -1954,14 +2191,14 @@ async function removeIssues(numbers, action) {
|
|
|
1954
2191
|
for (const num of numbers) {
|
|
1955
2192
|
try {
|
|
1956
2193
|
if (action === "delete") {
|
|
1957
|
-
(0,
|
|
2194
|
+
(0, import_node_child_process9.execSync)(`gh issue delete ${num} --yes`, { stdio: ["pipe", "pipe", "pipe"] });
|
|
1958
2195
|
} else {
|
|
1959
|
-
(0,
|
|
2196
|
+
(0, import_node_child_process9.execSync)(`gh issue close ${num}`, { stdio: ["pipe", "pipe", "pipe"] });
|
|
1960
2197
|
}
|
|
1961
|
-
console.log(
|
|
2198
|
+
console.log(import_picocolors9.default.green(`\u2713 #${num} ${action === "delete" ? "deleted" : "closed"}`));
|
|
1962
2199
|
success++;
|
|
1963
2200
|
} catch {
|
|
1964
|
-
console.log(
|
|
2201
|
+
console.log(import_picocolors9.default.red(`\u2717 #${num} failed`));
|
|
1965
2202
|
failed++;
|
|
1966
2203
|
}
|
|
1967
2204
|
}
|
|
@@ -1971,17 +2208,17 @@ async function removeIssues(numbers, action) {
|
|
|
1971
2208
|
async function cleanGitHubIssues() {
|
|
1972
2209
|
let issues = [];
|
|
1973
2210
|
try {
|
|
1974
|
-
const output = (0,
|
|
2211
|
+
const output = (0, import_node_child_process9.execSync)(
|
|
1975
2212
|
`gh issue list --label chiefwiggum --state open --json number,title,createdAt,labels --limit 100`,
|
|
1976
2213
|
{ encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }
|
|
1977
2214
|
);
|
|
1978
2215
|
issues = JSON.parse(output);
|
|
1979
2216
|
} catch {
|
|
1980
|
-
console.log(
|
|
2217
|
+
console.log(import_picocolors9.default.yellow("Could not fetch GitHub issues."));
|
|
1981
2218
|
return;
|
|
1982
2219
|
}
|
|
1983
2220
|
if (issues.length === 0) {
|
|
1984
|
-
console.log(
|
|
2221
|
+
console.log(import_picocolors9.default.dim("No open issues with 'chiefwiggum' label found."));
|
|
1985
2222
|
return;
|
|
1986
2223
|
}
|
|
1987
2224
|
const isEpic = (i) => i.labels.some((l) => l.name === "epic");
|
|
@@ -1990,15 +2227,15 @@ async function cleanGitHubIssues() {
|
|
|
1990
2227
|
console.log();
|
|
1991
2228
|
console.log(`Found ${issues.length} issues with 'chiefwiggum' label:`);
|
|
1992
2229
|
if (epics.length > 0) {
|
|
1993
|
-
console.log(
|
|
2230
|
+
console.log(import_picocolors9.default.dim(" Epics:"));
|
|
1994
2231
|
for (const issue of epics) {
|
|
1995
|
-
console.log(` ${
|
|
2232
|
+
console.log(` ${import_picocolors9.default.magenta(`#${issue.number}`)} ${import_picocolors9.default.bold("\u{1F4CB}")} ${issue.title}`);
|
|
1996
2233
|
}
|
|
1997
2234
|
}
|
|
1998
2235
|
if (childIssues.length > 0) {
|
|
1999
|
-
console.log(
|
|
2236
|
+
console.log(import_picocolors9.default.dim(" Tasks:"));
|
|
2000
2237
|
for (const issue of childIssues) {
|
|
2001
|
-
console.log(` ${
|
|
2238
|
+
console.log(` ${import_picocolors9.default.cyan(`#${issue.number}`)} - ${issue.title}`);
|
|
2002
2239
|
}
|
|
2003
2240
|
}
|
|
2004
2241
|
console.log();
|
|
@@ -2024,7 +2261,7 @@ async function cleanGitHubIssues() {
|
|
|
2024
2261
|
}))
|
|
2025
2262
|
});
|
|
2026
2263
|
if (selected.length === 0) {
|
|
2027
|
-
console.log(
|
|
2264
|
+
console.log(import_picocolors9.default.yellow("No issues selected."));
|
|
2028
2265
|
return;
|
|
2029
2266
|
}
|
|
2030
2267
|
const pickAction = await select2({
|
|
@@ -2048,7 +2285,7 @@ async function cleanGitHubIssues() {
|
|
|
2048
2285
|
}
|
|
2049
2286
|
}
|
|
2050
2287
|
async function cmdClean() {
|
|
2051
|
-
console.log(
|
|
2288
|
+
console.log(import_picocolors9.default.bold("Clean Project"));
|
|
2052
2289
|
console.log();
|
|
2053
2290
|
const tracker = getProjectTracker();
|
|
2054
2291
|
if (tracker === "github") {
|
|
@@ -2062,16 +2299,16 @@ async function cmdClean() {
|
|
|
2062
2299
|
console.log();
|
|
2063
2300
|
}
|
|
2064
2301
|
const filesToRemove = [];
|
|
2065
|
-
if ((0,
|
|
2066
|
-
if ((0,
|
|
2067
|
-
if ((0,
|
|
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");
|
|
2068
2305
|
if (filesToRemove.length === 0) {
|
|
2069
|
-
console.log(
|
|
2306
|
+
console.log(import_picocolors9.default.dim("No chiefwiggum files found to clean."));
|
|
2070
2307
|
return;
|
|
2071
2308
|
}
|
|
2072
2309
|
console.log("Files to remove:");
|
|
2073
2310
|
for (const f of filesToRemove) {
|
|
2074
|
-
console.log(` ${
|
|
2311
|
+
console.log(` ${import_picocolors9.default.red(f)}`);
|
|
2075
2312
|
}
|
|
2076
2313
|
console.log();
|
|
2077
2314
|
const shouldClean = await confirm2({
|
|
@@ -2079,65 +2316,65 @@ async function cmdClean() {
|
|
|
2079
2316
|
initialValue: false
|
|
2080
2317
|
});
|
|
2081
2318
|
if (!shouldClean) {
|
|
2082
|
-
console.log(
|
|
2319
|
+
console.log(import_picocolors9.default.yellow("Aborted."));
|
|
2083
2320
|
return;
|
|
2084
2321
|
}
|
|
2085
2322
|
for (const f of filesToRemove) {
|
|
2086
2323
|
const path = f.replace(/\/$/, "");
|
|
2087
|
-
(0,
|
|
2088
|
-
console.log(
|
|
2324
|
+
(0, import_node_fs5.rmSync)(path, { recursive: true, force: true });
|
|
2325
|
+
console.log(import_picocolors9.default.red(`\u2717 Removed ${f}`));
|
|
2089
2326
|
}
|
|
2090
2327
|
console.log();
|
|
2091
|
-
console.log(
|
|
2328
|
+
console.log(import_picocolors9.default.green("Clean complete."));
|
|
2092
2329
|
}
|
|
2093
2330
|
|
|
2094
2331
|
// src/commands/config.ts
|
|
2095
2332
|
init_cjs_shims();
|
|
2096
|
-
var
|
|
2097
|
-
var
|
|
2098
|
-
var
|
|
2333
|
+
var import_node_fs6 = require("fs");
|
|
2334
|
+
var import_node_child_process10 = require("child_process");
|
|
2335
|
+
var import_picocolors10 = __toESM(require("picocolors"), 1);
|
|
2099
2336
|
init_prompts();
|
|
2100
2337
|
var CONFIG_FILE2 = ".chiefwiggum/CLAUDE.md";
|
|
2101
2338
|
function stripTrailingCommas2(json) {
|
|
2102
2339
|
return json.replace(/,(\s*[}\]])/g, "$1");
|
|
2103
2340
|
}
|
|
2104
2341
|
function getConfig2() {
|
|
2105
|
-
if (!(0,
|
|
2342
|
+
if (!(0, import_node_fs6.existsSync)(CONFIG_FILE2)) {
|
|
2106
2343
|
return { projectTracker: "todo" };
|
|
2107
2344
|
}
|
|
2108
|
-
const raw = (0,
|
|
2345
|
+
const raw = (0, import_node_fs6.readFileSync)(CONFIG_FILE2, "utf-8");
|
|
2109
2346
|
try {
|
|
2110
2347
|
return JSON.parse(raw);
|
|
2111
2348
|
} catch {
|
|
2112
2349
|
try {
|
|
2113
2350
|
const fixed = stripTrailingCommas2(raw);
|
|
2114
2351
|
const config2 = JSON.parse(fixed);
|
|
2115
|
-
console.log(
|
|
2352
|
+
console.log(import_picocolors10.default.yellow("Note: Fixed trailing comma in config file."));
|
|
2116
2353
|
saveConfig2(config2);
|
|
2117
2354
|
return config2;
|
|
2118
2355
|
} catch {
|
|
2119
|
-
console.log(
|
|
2356
|
+
console.log(import_picocolors10.default.yellow("Warning: Could not parse config file. Using defaults."));
|
|
2120
2357
|
return { projectTracker: "todo" };
|
|
2121
2358
|
}
|
|
2122
2359
|
}
|
|
2123
2360
|
}
|
|
2124
2361
|
function saveConfig2(config2) {
|
|
2125
|
-
(0,
|
|
2126
|
-
(0,
|
|
2362
|
+
(0, import_node_fs6.mkdirSync)(".chiefwiggum", { recursive: true });
|
|
2363
|
+
(0, import_node_fs6.writeFileSync)(CONFIG_FILE2, JSON.stringify(config2, null, 2) + "\n");
|
|
2127
2364
|
}
|
|
2128
2365
|
function checkGitHubCLI2() {
|
|
2129
2366
|
try {
|
|
2130
|
-
(0,
|
|
2367
|
+
(0, import_node_child_process10.execSync)("which gh", { stdio: ["pipe", "pipe", "pipe"] });
|
|
2131
2368
|
} catch {
|
|
2132
2369
|
return { ok: false, reason: "not_installed" };
|
|
2133
2370
|
}
|
|
2134
2371
|
try {
|
|
2135
|
-
(0,
|
|
2372
|
+
(0, import_node_child_process10.execSync)("gh auth status", { stdio: ["pipe", "pipe", "pipe"] });
|
|
2136
2373
|
} catch {
|
|
2137
2374
|
return { ok: false, reason: "not_authenticated" };
|
|
2138
2375
|
}
|
|
2139
2376
|
try {
|
|
2140
|
-
const repo = (0,
|
|
2377
|
+
const repo = (0, import_node_child_process10.execSync)("gh repo view --json nameWithOwner -q .nameWithOwner", {
|
|
2141
2378
|
encoding: "utf-8",
|
|
2142
2379
|
stdio: ["pipe", "pipe", "pipe"]
|
|
2143
2380
|
}).trim();
|
|
@@ -2147,12 +2384,12 @@ function checkGitHubCLI2() {
|
|
|
2147
2384
|
}
|
|
2148
2385
|
}
|
|
2149
2386
|
async function cmdConfig() {
|
|
2150
|
-
console.log(
|
|
2387
|
+
console.log(import_picocolors10.default.bold("Configuration"));
|
|
2151
2388
|
console.log();
|
|
2152
2389
|
const config2 = getConfig2();
|
|
2153
|
-
console.log(`Current tracker: ${
|
|
2390
|
+
console.log(`Current tracker: ${import_picocolors10.default.cyan(config2.projectTracker)}`);
|
|
2154
2391
|
if (config2.projectTracker === "github") {
|
|
2155
|
-
console.log(`GitHub Project Board: ${
|
|
2392
|
+
console.log(`GitHub Project Board: ${import_picocolors10.default.cyan(config2.githubProject || "(none)")}`);
|
|
2156
2393
|
}
|
|
2157
2394
|
console.log();
|
|
2158
2395
|
const newTracker = await select2({
|
|
@@ -2169,24 +2406,24 @@ async function cmdConfig() {
|
|
|
2169
2406
|
if (!ghCheck.ok) {
|
|
2170
2407
|
console.log();
|
|
2171
2408
|
if (ghCheck.reason === "not_installed") {
|
|
2172
|
-
console.log(
|
|
2409
|
+
console.log(import_picocolors10.default.yellow("GitHub CLI (gh) is not installed."));
|
|
2173
2410
|
console.log();
|
|
2174
2411
|
console.log("To use GitHub Issues, install it first:");
|
|
2175
|
-
console.log(
|
|
2176
|
-
console.log(
|
|
2177
|
-
console.log(
|
|
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"));
|
|
2178
2415
|
} else if (ghCheck.reason === "not_authenticated") {
|
|
2179
|
-
console.log(
|
|
2416
|
+
console.log(import_picocolors10.default.yellow("GitHub CLI is not authenticated."));
|
|
2180
2417
|
console.log();
|
|
2181
2418
|
console.log("Run this command to log in:");
|
|
2182
|
-
console.log(
|
|
2419
|
+
console.log(import_picocolors10.default.cyan(" gh auth login"));
|
|
2183
2420
|
} else if (ghCheck.reason === "not_github_repo") {
|
|
2184
|
-
console.log(
|
|
2421
|
+
console.log(import_picocolors10.default.yellow("This doesn't appear to be a GitHub repository."));
|
|
2185
2422
|
console.log();
|
|
2186
2423
|
console.log("Make sure you're in a git repo with a GitHub remote.");
|
|
2187
2424
|
}
|
|
2188
2425
|
console.log();
|
|
2189
|
-
console.log(
|
|
2426
|
+
console.log(import_picocolors10.default.dim("Cannot switch to GitHub Issues. Keeping current tracker."));
|
|
2190
2427
|
return;
|
|
2191
2428
|
}
|
|
2192
2429
|
config2.projectTracker = "github";
|
|
@@ -2213,32 +2450,32 @@ async function cmdConfig() {
|
|
|
2213
2450
|
if (changed) {
|
|
2214
2451
|
saveConfig2(config2);
|
|
2215
2452
|
console.log();
|
|
2216
|
-
console.log(
|
|
2217
|
-
console.log(
|
|
2453
|
+
console.log(import_picocolors10.default.green(`\u2713 Config updated`));
|
|
2454
|
+
console.log(import_picocolors10.default.dim(` Tracker: ${config2.projectTracker}`));
|
|
2218
2455
|
if (config2.projectTracker === "github" && config2.githubProject) {
|
|
2219
|
-
console.log(
|
|
2456
|
+
console.log(import_picocolors10.default.dim(` Project board: ${config2.githubProject}`));
|
|
2220
2457
|
}
|
|
2221
2458
|
} else {
|
|
2222
2459
|
console.log();
|
|
2223
|
-
console.log(
|
|
2460
|
+
console.log(import_picocolors10.default.dim("No changes made."));
|
|
2224
2461
|
}
|
|
2225
2462
|
}
|
|
2226
2463
|
async function selectOrCreateProjectBoard2(knownRepo) {
|
|
2227
2464
|
let repoName = knownRepo || "";
|
|
2228
2465
|
if (!repoName) {
|
|
2229
2466
|
try {
|
|
2230
|
-
repoName = (0,
|
|
2467
|
+
repoName = (0, import_node_child_process10.execSync)("gh repo view --json nameWithOwner -q .nameWithOwner", {
|
|
2231
2468
|
encoding: "utf-8",
|
|
2232
2469
|
stdio: ["pipe", "pipe", "pipe"]
|
|
2233
2470
|
}).trim();
|
|
2234
2471
|
} catch {
|
|
2235
|
-
console.log(
|
|
2472
|
+
console.log(import_picocolors10.default.yellow("Could not detect GitHub repo. Skipping project board setup."));
|
|
2236
2473
|
return null;
|
|
2237
2474
|
}
|
|
2238
2475
|
}
|
|
2239
2476
|
let existingProjects = [];
|
|
2240
2477
|
try {
|
|
2241
|
-
const projectsOutput = (0,
|
|
2478
|
+
const projectsOutput = (0, import_node_child_process10.execSync)(`gh project list --owner ${repoName.split("/")[0]} --format json`, {
|
|
2242
2479
|
encoding: "utf-8",
|
|
2243
2480
|
stdio: ["pipe", "pipe", "pipe"]
|
|
2244
2481
|
});
|
|
@@ -2247,8 +2484,8 @@ async function selectOrCreateProjectBoard2(knownRepo) {
|
|
|
2247
2484
|
} catch {
|
|
2248
2485
|
}
|
|
2249
2486
|
console.log();
|
|
2250
|
-
console.log(
|
|
2251
|
-
console.log(
|
|
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}`));
|
|
2252
2489
|
console.log();
|
|
2253
2490
|
const projectOptions = [
|
|
2254
2491
|
...existingProjects.map((name) => ({ value: name, label: name })),
|
|
@@ -2264,44 +2501,44 @@ async function selectOrCreateProjectBoard2(knownRepo) {
|
|
|
2264
2501
|
message: "Board name",
|
|
2265
2502
|
placeholder: "e.g., SVG Icon Generator v2"
|
|
2266
2503
|
});
|
|
2267
|
-
console.log(
|
|
2504
|
+
console.log(import_picocolors10.default.cyan(`Creating board "${projectName}"...`));
|
|
2268
2505
|
try {
|
|
2269
|
-
const createOutput = (0,
|
|
2506
|
+
const createOutput = (0, import_node_child_process10.execSync)(
|
|
2270
2507
|
`gh project create --owner ${repoName.split("/")[0]} --title "${projectName}"`,
|
|
2271
2508
|
{ encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }
|
|
2272
2509
|
);
|
|
2273
2510
|
const projectNumberMatch = createOutput.match(/projects\/(\d+)/);
|
|
2274
2511
|
const projectNumber = projectNumberMatch ? projectNumberMatch[1] : null;
|
|
2275
|
-
console.log(
|
|
2512
|
+
console.log(import_picocolors10.default.green(`\u2713 Board "${projectName}" created`));
|
|
2276
2513
|
if (projectNumber) {
|
|
2277
2514
|
try {
|
|
2278
|
-
(0,
|
|
2515
|
+
(0, import_node_child_process10.execSync)(`gh project link ${projectNumber} --owner ${repoName.split("/")[0]} --repo ${repoName}`, {
|
|
2279
2516
|
stdio: ["pipe", "pipe", "pipe"]
|
|
2280
2517
|
});
|
|
2281
|
-
console.log(
|
|
2518
|
+
console.log(import_picocolors10.default.green(`\u2713 Linked to ${repoName}`));
|
|
2282
2519
|
} catch {
|
|
2283
|
-
console.log(
|
|
2520
|
+
console.log(import_picocolors10.default.dim(` Note: Board created at org level. Link manually from repo's Projects tab.`));
|
|
2284
2521
|
}
|
|
2285
2522
|
}
|
|
2286
2523
|
return projectName;
|
|
2287
2524
|
} catch {
|
|
2288
|
-
console.log(
|
|
2525
|
+
console.log(import_picocolors10.default.yellow("Could not create board."));
|
|
2289
2526
|
return null;
|
|
2290
2527
|
}
|
|
2291
2528
|
} else if (selectedProject !== "__none__") {
|
|
2292
2529
|
try {
|
|
2293
|
-
const projectsOutput = (0,
|
|
2530
|
+
const projectsOutput = (0, import_node_child_process10.execSync)(
|
|
2294
2531
|
`gh project list --owner ${repoName.split("/")[0]} --format json`,
|
|
2295
2532
|
{ encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }
|
|
2296
2533
|
);
|
|
2297
2534
|
const projects = JSON.parse(projectsOutput);
|
|
2298
2535
|
const project = projects.projects?.find((p2) => p2.title === selectedProject);
|
|
2299
2536
|
if (project?.number) {
|
|
2300
|
-
(0,
|
|
2537
|
+
(0, import_node_child_process10.execSync)(
|
|
2301
2538
|
`gh project link ${project.number} --owner ${repoName.split("/")[0]} --repo ${repoName}`,
|
|
2302
2539
|
{ stdio: ["pipe", "pipe", "pipe"] }
|
|
2303
2540
|
);
|
|
2304
|
-
console.log(
|
|
2541
|
+
console.log(import_picocolors10.default.green(`\u2713 Linked "${selectedProject}" to ${repoName}`));
|
|
2305
2542
|
}
|
|
2306
2543
|
} catch {
|
|
2307
2544
|
}
|
|
@@ -2315,7 +2552,7 @@ var __dirname2 = (0, import_node_path3.dirname)((0, import_node_url2.fileURLToPa
|
|
|
2315
2552
|
function getVersion() {
|
|
2316
2553
|
try {
|
|
2317
2554
|
const pkgPath = (0, import_node_path3.join)(__dirname2, "..", "package.json");
|
|
2318
|
-
const pkg = JSON.parse((0,
|
|
2555
|
+
const pkg = JSON.parse((0, import_node_fs7.readFileSync)(pkgPath, "utf-8"));
|
|
2319
2556
|
return pkg.version || "dev";
|
|
2320
2557
|
} catch {
|
|
2321
2558
|
return "dev";
|
|
@@ -2348,19 +2585,19 @@ async function main() {
|
|
|
2348
2585
|
});
|
|
2349
2586
|
program.action(async () => {
|
|
2350
2587
|
await showBanner(version);
|
|
2351
|
-
const { existsSync:
|
|
2588
|
+
const { existsSync: existsSync7 } = await import("fs");
|
|
2352
2589
|
const { getProjectTracker: getProjectTracker2 } = await Promise.resolve().then(() => (init_new(), new_exports));
|
|
2353
2590
|
const tracker = getProjectTracker2();
|
|
2354
|
-
if (tracker === "github" ||
|
|
2591
|
+
if (tracker === "github" || existsSync7("TODO.md") || existsSync7(".chiefwiggum/CLAUDE.md")) {
|
|
2355
2592
|
await cmdLoop();
|
|
2356
2593
|
} else {
|
|
2357
|
-
console.log(
|
|
2594
|
+
console.log(import_picocolors11.default.yellow("No project configured. Run 'chiefwiggum new' to get started."));
|
|
2358
2595
|
process.exit(1);
|
|
2359
2596
|
}
|
|
2360
2597
|
});
|
|
2361
2598
|
await program.parseAsync();
|
|
2362
2599
|
}
|
|
2363
2600
|
main().catch((err) => {
|
|
2364
|
-
console.error(
|
|
2601
|
+
console.error(import_picocolors11.default.red("Error:"), err.message);
|
|
2365
2602
|
process.exit(1);
|
|
2366
2603
|
});
|