@dunnewold-labs/mr-manager 0.4.28 → 0.4.29

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.mjs +126 -507
  2. package/package.json +1 -1
package/dist/index.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // cli/index.ts
4
- import { Command as Command29 } from "commander";
4
+ import { Command as Command28 } from "commander";
5
5
  import { existsSync as existsSync17 } from "fs";
6
6
  import { homedir as homedir3 } from "os";
7
7
  import { join as join12 } from "path";
@@ -185,7 +185,7 @@ import { fileURLToPath } from "url";
185
185
  // cli/package.json
186
186
  var package_default = {
187
187
  name: "@dunnewold-labs/mr-manager",
188
- version: "0.4.28",
188
+ version: "0.4.29",
189
189
  description: "Mr. Manager - Task and project management CLI",
190
190
  bin: {
191
191
  mr: "./dist/index.mjs"
@@ -1162,6 +1162,19 @@ function taskLikelyDoesNotNeedCodeChanges(task) {
1162
1162
  return NON_CODE_TASK_KEYWORDS.some((keyword) => haystack.includes(keyword)) || NON_CODE_TASK_PATTERNS.some((pattern) => pattern.test(haystack));
1163
1163
  }
1164
1164
 
1165
+ // lib/task-branch.ts
1166
+ function isPrOrMrUrl(input) {
1167
+ try {
1168
+ const url = new URL(input.trim());
1169
+ const path = url.pathname;
1170
+ if (url.hostname.includes("github") && /\/pull\/\d+/.test(path)) return true;
1171
+ if (url.hostname.includes("gitlab") && /\/merge_requests\/\d+/.test(path)) return true;
1172
+ } catch {
1173
+ return false;
1174
+ }
1175
+ return false;
1176
+ }
1177
+
1165
1178
  // cli/browse-runner.ts
1166
1179
  import { execSync as execSync3, spawn as spawn3 } from "child_process";
1167
1180
  import { existsSync as existsSync6 } from "fs";
@@ -1482,6 +1495,15 @@ function taskBranchName(task) {
1482
1495
  }
1483
1496
  return `${ownerPrefix(task)}/${slugify(task.title)}`;
1484
1497
  }
1498
+ function resolveBranchFromPrUrl(prUrl, repoDir, vcs) {
1499
+ const cmd = vcs === "gitlab" ? `glab mr view "${prUrl}" --output json 2>/dev/null | jq -r '.source_branch // empty'` : `gh pr view "${prUrl}" --json headRefName -q .headRefName 2>/dev/null`;
1500
+ return new Promise((resolve9) => {
1501
+ exec(cmd, { cwd: repoDir }, (err, stdout) => {
1502
+ const branch = stdout?.trim();
1503
+ resolve9(branch || null);
1504
+ });
1505
+ });
1506
+ }
1485
1507
  function formatElapsed(ms) {
1486
1508
  const totalMinutes = Math.max(1, Math.floor(ms / 6e4));
1487
1509
  const hours = Math.floor(totalMinutes / 60);
@@ -2119,9 +2141,6 @@ function protoTag(sid) {
2119
2141
  function repoTag(sid) {
2120
2142
  return paint("cyan", `[repo:${sid}]`);
2121
2143
  }
2122
- function ideaTag(sid) {
2123
- return paint("magenta", `[idea:${sid}]`);
2124
- }
2125
2144
  function buildRepoCreationPrompt(project, rootDir, vcs = "github") {
2126
2145
  const apiBase = process.env.MR_API_BASE ?? "http://localhost:3000";
2127
2146
  const apiKey = process.env.MR_API_KEY ?? "";
@@ -2400,83 +2419,6 @@ function buildRefinementPrompt(proto, parentFiles, repoDir) {
2400
2419
  `- Do NOT exit until ALL ${proto.variantCount} files have been written and verified.`
2401
2420
  ].join("\n");
2402
2421
  }
2403
- function buildIdeaPrompt(idea, repoDir) {
2404
- const feedbackSection = idea.feedback ? [
2405
- `## Previous Feedback`,
2406
- ``,
2407
- `The user provided this feedback on a previous generation:`,
2408
- `${idea.feedback}`,
2409
- ``,
2410
- `Please incorporate this feedback into your new generation.`,
2411
- ``
2412
- ] : [];
2413
- const existingPlanSection = idea.plan && idea.feedback ? [
2414
- `## Previous Plan`,
2415
- ``,
2416
- `Here is the plan from the previous iteration:`,
2417
- `\`\`\`markdown`,
2418
- idea.plan,
2419
- `\`\`\``,
2420
- ``
2421
- ] : [];
2422
- return [
2423
- `You are a product strategist and UI designer. Your job is to take a rough idea and generate two outputs:`,
2424
- `1. An implementation plan (saved as \`idea-plan.md\`)`,
2425
- `2. A visual prototype (saved as \`idea-prototype.html\`)`,
2426
- ``,
2427
- `Working directory: ${repoDir}`,
2428
- ``,
2429
- `## Idea`,
2430
- `Title: ${idea.title}`,
2431
- `ID: ${idea.id}`,
2432
- ...idea.description ? [``, `Description: ${idea.description}`] : [],
2433
- ``,
2434
- ...feedbackSection,
2435
- ...existingPlanSection,
2436
- `## Instructions`,
2437
- ``,
2438
- `### Step 1: Generate the Plan`,
2439
- ``,
2440
- `Write a comprehensive implementation plan to \`${repoDir}/idea-plan.md\` covering:`,
2441
- `- **Problem statement**: What problem does this idea solve?`,
2442
- `- **Proposed solution**: High-level approach`,
2443
- `- **Key features**: Bulleted list of features/capabilities`,
2444
- `- **Technical approach**: How it could be built (components, data model, integrations)`,
2445
- `- **Implementation phases**: Phased rollout plan with milestones`,
2446
- `- **Open questions**: Things that need clarification`,
2447
- ``,
2448
- `### Step 2: Generate Follow-up Tasks`,
2449
- ``,
2450
- `Write a JSON file to \`${repoDir}/idea-tasks.json\` containing an array of follow-up tasks that will need to be done after the project repo is created. These are setup and implementation tasks the user will need to complete. Examples: "Add environment variables (.env)", "Set up CI/CD pipeline", "Configure database", "Add authentication", etc.`,
2451
- ``,
2452
- `Format: a JSON array of objects with "title" (short task name) and optional "notes" (additional context):`,
2453
- `\`\`\`json`,
2454
- `[`,
2455
- ` { "title": "Add environment variables (.env)", "notes": "Create .env file with required API keys and database URL" },`,
2456
- ` { "title": "Set up CI/CD pipeline" }`,
2457
- `]`,
2458
- `\`\`\``,
2459
- ``,
2460
- `Generate 3-8 tasks that are specific to this idea. Focus on actionable setup and implementation steps.`,
2461
- ``,
2462
- `### Step 3: Generate the Prototype`,
2463
- ``,
2464
- `Write a self-contained HTML prototype to \`${repoDir}/idea-prototype.html\` that visually demonstrates the idea.`,
2465
- `- Must be completely self-contained (inline CSS/JS, Tailwind CDN is acceptable)`,
2466
- `- Should be interactive where possible (click handlers, animations, sample data)`,
2467
- `- Should look polished and professional \u2014 this will be shown to stakeholders`,
2468
- `- Include realistic sample data that demonstrates the feature`,
2469
- ``,
2470
- `### Step 4: Verify`,
2471
- ``,
2472
- `List the files in ${repoDir} and confirm \`idea-plan.md\`, \`idea-tasks.json\`, and \`idea-prototype.html\` all exist.`,
2473
- ``,
2474
- `IMPORTANT RULES:`,
2475
- `- Write EXACTLY three files: idea-plan.md, idea-tasks.json, and idea-prototype.html`,
2476
- `- Do NOT upload or POST the files anywhere \u2014 the watch handler will upload them automatically`,
2477
- `- Do NOT exit until both files have been written and verified`
2478
- ].join("\n");
2479
- }
2480
2422
  function buildAgentArgs(agent, prompt2, mode, sessionId, name, resumeSession = false, systemPrompt, maxTurns, claudeModel) {
2481
2423
  if (agent === "codex") {
2482
2424
  const args = [];
@@ -2619,14 +2561,13 @@ function spawnAgent(agent, repoDir, prompt2, prefix, onActivity, sessionId, name
2619
2561
  }
2620
2562
  var watchCommand = new Command8("watch").description(
2621
2563
  "Watch for in-progress tasks and autonomously dispatch an AI coding agent to work on them"
2622
- ).option("--interval <seconds>", "Polling interval in seconds", "15").option("--dry-run", "Show what would be dispatched without spawning the agent", false).option("--plan-approval", "Show the agent's plan and ask for approval before executing", false).option("--root <dir>", "Root directory filter for linked repos (default: cwd)").option("--agent <agent>", "AI agent to use: claude, codex, or gemini", "claude").option("--scan-at <HH:MM>", "Run a product scan daily at this time (e.g., 02:00)").option("--quiet", "Run all tasks in quiet mode (agent outputs only status updates, no conversation)", false).action(async (opts) => {
2564
+ ).option("--interval <seconds>", "Polling interval in seconds", "15").option("--dry-run", "Show what would be dispatched without spawning the agent", false).option("--plan-approval", "Show the agent's plan and ask for approval before executing", false).option("--root <dir>", "Root directory filter for linked repos (default: cwd)").option("--agent <agent>", "AI agent to use: claude, codex, or gemini", "claude").option("--scan-at <HH:MM>", "Run a product scan daily at this time (e.g., 02:00)").action(async (opts) => {
2623
2565
  const intervalMs = parseInt(opts.interval, 10) * 1e3;
2624
2566
  const dryRun = opts.dryRun;
2625
2567
  const planApproval = opts.planApproval;
2626
2568
  const rootDir = opts.root ? resolve2(opts.root) : process.cwd();
2627
2569
  const agent = opts.agent === "codex" ? "codex" : opts.agent === "gemini" ? "gemini" : "claude";
2628
2570
  const scanAt = opts.scanAt;
2629
- const globalQuietMode = opts.quiet;
2630
2571
  const taskStallTimeoutMs = getTaskStallTimeoutMs();
2631
2572
  const hungTaskTimeoutMinutes = Math.max(5, parseInt(process.env.MR_WATCH_HUNG_TASK_TIMEOUT_MINUTES ?? "60", 10) || 60);
2632
2573
  const hungTaskTimeoutMs = hungTaskTimeoutMinutes * 6e4;
@@ -2647,7 +2588,6 @@ var watchCommand = new Command8("watch").description(
2647
2588
  `stall-timeout=${paint("cyan", formatTimeoutMinutes(taskStallTimeoutMs))}`,
2648
2589
  ...planApproval ? [paint("yellow", "plan-approval")] : [],
2649
2590
  ...dryRun ? [paint("yellow", "dry-run")] : [],
2650
- ...globalQuietMode ? [paint("yellow", "quiet")] : [],
2651
2591
  ...scanAt ? [`scan-at=${paint("cyan", scanAt)}`] : [],
2652
2592
  `hung-timeout=${paint("cyan", `${hungTaskTimeoutMinutes}m`)}`
2653
2593
  ].join(" ");
@@ -2721,7 +2661,7 @@ var watchCommand = new Command8("watch").description(
2721
2661
  logWarn(watchTag(), `Network unavailable \u2014 pausing active tasks until connectivity returns (${reason})`);
2722
2662
  }
2723
2663
  for (const taskId of active.keys()) {
2724
- const nonTaskPrefixes = ["proto-", "repo-", "scan-", "idea-", "test-"];
2664
+ const nonTaskPrefixes = ["proto-", "repo-", "scan-", "test-"];
2725
2665
  if (nonTaskPrefixes.some((prefix) => taskId.startsWith(prefix))) continue;
2726
2666
  pauseTaskForNetwork(taskId, reason);
2727
2667
  }
@@ -2768,13 +2708,19 @@ var watchCommand = new Command8("watch").description(
2768
2708
  const sid = shortId(task.id);
2769
2709
  const slug = slugify(task.title);
2770
2710
  const owner = ownerPrefix(task);
2771
- const branchName = taskBranchName(task);
2711
+ let branchName = taskBranchName(task);
2772
2712
  const legacyBranchName = `mr/${sid}/${slug}`;
2773
2713
  const prefix = taskTag(sid);
2774
2714
  const vcs = detectVcs(repoDir)?.provider ?? "github";
2775
- const taskIsQuiet = task.quietMode || globalQuietMode;
2776
- logDispatch(prefix, `"${paint("bold", task.title)}" ${paint("gray", repoDir)} ${paint("dim", `[${vcs}]`)}${taskIsQuiet ? ` ${paint("yellow", "[quiet]")}` : ""}`);
2777
- await postTaskUpdate(task.id, `Agent dispatched${taskIsQuiet ? " (quiet mode)" : ""} \u2014 starting work on "${task.title}"`, "system");
2715
+ if (!task.attachedBranch?.trim() && task.attachedBranchLink && isPrOrMrUrl(task.attachedBranchLink)) {
2716
+ const resolved = await resolveBranchFromPrUrl(task.attachedBranchLink, repoDir, vcs);
2717
+ if (resolved) {
2718
+ branchName = resolved;
2719
+ logInfo(prefix, `Resolved branch ${paint("cyan", resolved)} from attached ${vcs === "gitlab" ? "MR" : "PR"}`);
2720
+ }
2721
+ }
2722
+ logDispatch(prefix, `"${paint("bold", task.title)}" ${paint("gray", repoDir)} ${paint("dim", `[${vcs}]`)}`);
2723
+ await postTaskUpdate(task.id, `Agent dispatched \u2014 starting work on "${task.title}"`, "system");
2778
2724
  let subtasks = [];
2779
2725
  try {
2780
2726
  subtasks = await api.get(`/api/tasks/${task.id}/subtasks`);
@@ -2840,7 +2786,6 @@ var watchCommand = new Command8("watch").description(
2840
2786
  );
2841
2787
  }
2842
2788
  const prompt2 = buildExecutionPrompt(task, repoDir, subtasks, vcs, protoRefs, feedbackUpdates, existingResources, skillRefs, executionDir, startWithoutWorktree, !startWithoutWorktree && isGitRepo(repoDir) ? branchName : void 0);
2843
- const taskIsQuietForEntry = task.quietMode || globalQuietMode;
2844
2789
  const activeEntry = {
2845
2790
  process: void 0,
2846
2791
  title: task.title,
@@ -2849,8 +2794,7 @@ var watchCommand = new Command8("watch").description(
2849
2794
  cleanupWorktreePath,
2850
2795
  startedAt: Date.now(),
2851
2796
  lastActivityAt: Date.now(),
2852
- outputBytes: 0,
2853
- quietMode: taskIsQuietForEntry
2797
+ outputBytes: 0
2854
2798
  };
2855
2799
  const touchActivity = () => {
2856
2800
  activeEntry.lastActivityAt = Date.now();
@@ -2879,12 +2823,8 @@ var watchCommand = new Command8("watch").description(
2879
2823
  const shouldResumeClaudeSession = attemptAgent === "claude" && !!task.claudeSessionId && !resumeAlreadyRetried && (hasFeedback || pausedForNetwork?.resumeSession === true);
2880
2824
  const sessionId = attemptAgent === "claude" ? shouldResumeClaudeSession ? task.claudeSessionId : randomUUID() : void 0;
2881
2825
  const effectiveClaudeModel = attemptAgent === "claude" ? taskClaudeModel : void 0;
2882
- const isQuiet = task.quietMode || globalQuietMode;
2883
- const systemSections = isQuiet ? ["quiet-mode", ...EXECUTION_SYSTEM_SECTIONS] : [...EXECUTION_SYSTEM_SECTIONS];
2826
+ const systemSections = ["quiet-mode", ...EXECUTION_SYSTEM_SECTIONS];
2884
2827
  const executionSystemPrompt = composeSystemPrompt(systemSections);
2885
- if (isQuiet) {
2886
- logInfo(prefix, `${paint("yellow", "quiet mode")} \u2014 agent will suppress conversational output`);
2887
- }
2888
2828
  const child = spawnAgent(
2889
2829
  attemptAgent,
2890
2830
  executionDir,
@@ -2932,36 +2872,47 @@ var watchCommand = new Command8("watch").description(
2932
2872
  logWarn(prefix, `${attemptAgent} paused after network loss (${failureDetail})`);
2933
2873
  return;
2934
2874
  }
2935
- if (shouldResumeClaudeSession && !resumeAlreadyRetried) {
2936
- resumeAlreadyRetried = true;
2937
- logWarn(prefix, `Claude session resume failed (${failureDetail}) \u2014 retrying with fresh session`);
2938
- await postTaskUpdate(
2939
- task.id,
2940
- `Claude session resume failed \u2014 retrying with fresh session`,
2941
- "system"
2942
- );
2943
- await launchAttempt("claude");
2944
- return;
2875
+ try {
2876
+ const currentTask = await api.get(`/api/tasks/${task.id}`);
2877
+ if (currentTask.status === "completed" || currentTask.status === "review" || currentTask.status === "error") {
2878
+ logWarn(prefix, `Task already in "${currentTask.status}" state after agent exit \u2014 skipping retry`);
2879
+ activeEntry.terminatedForError = true;
2880
+ }
2881
+ } catch {
2882
+ logWarn(prefix, `Could not verify task status \u2014 skipping retry to avoid stale re-dispatch`);
2883
+ activeEntry.terminatedForError = true;
2945
2884
  }
2946
- const nextAgent = attemptOrder[attemptIndex + 1];
2947
- if (nextAgent) {
2948
- logWarn(prefix, `${attemptAgent} failed (${failureDetail}) \u2014 retrying with ${nextAgent}`);
2949
- await postTaskUpdate(
2950
- task.id,
2951
- `${attemptAgent} failed (${failureDetail}) \u2014 retrying with ${nextAgent}`,
2952
- "system"
2953
- );
2954
- attemptIndex += 1;
2955
- await launchAttempt(nextAgent);
2956
- return;
2885
+ if (!activeEntry.terminatedForError) {
2886
+ if (shouldResumeClaudeSession && !resumeAlreadyRetried) {
2887
+ resumeAlreadyRetried = true;
2888
+ logWarn(prefix, `Claude session resume failed (${failureDetail}) \u2014 retrying with fresh session`);
2889
+ await postTaskUpdate(
2890
+ task.id,
2891
+ `Claude session resume failed \u2014 retrying with fresh session`,
2892
+ "system"
2893
+ );
2894
+ await launchAttempt("claude");
2895
+ return;
2896
+ }
2897
+ const nextAgent = attemptOrder[attemptIndex + 1];
2898
+ if (nextAgent) {
2899
+ logWarn(prefix, `${attemptAgent} failed (${failureDetail}) \u2014 retrying with ${nextAgent}`);
2900
+ await postTaskUpdate(
2901
+ task.id,
2902
+ `${attemptAgent} failed (${failureDetail}) \u2014 retrying with ${nextAgent}`,
2903
+ "system"
2904
+ );
2905
+ attemptIndex += 1;
2906
+ await launchAttempt(nextAgent);
2907
+ return;
2908
+ }
2957
2909
  }
2958
2910
  }
2959
2911
  finishing.add(task.id);
2960
2912
  const elapsedMs = Date.now() - activeEntry.startedAt;
2961
- const modeLabel = activeEntry.quietMode ? "quiet" : "standard";
2962
2913
  const outputTokenEstimate = Math.ceil(activeEntry.outputBytes / 4);
2963
2914
  console.log(
2964
- `${timestamp()} ${prefix} ${paint("dim", `[output] mode=${modeLabel} output=~${formatTokenCount(outputTokenEstimate)} elapsed=${Math.round(elapsedMs / 1e3)}s exit=${code}`)}`
2915
+ `${timestamp()} ${prefix} ${paint("dim", `[output] output=~${formatTokenCount(outputTokenEstimate)} elapsed=${Math.round(elapsedMs / 1e3)}s exit=${code}`)}`
2965
2916
  );
2966
2917
  try {
2967
2918
  if (code === 0) {
@@ -3301,7 +3252,7 @@ var watchCommand = new Command8("watch").description(
3301
3252
  active.delete(key);
3302
3253
  }
3303
3254
  const failedAttempt = code !== 0 || spawnFailureReason !== null;
3304
- if (failedAttempt) {
3255
+ if (failedAttempt && !activeEntry.terminatedForError) {
3305
3256
  const nextAgent = attemptOrder[attemptIndex + 1];
3306
3257
  if (nextAgent) {
3307
3258
  const failureDetail = spawnFailureReason ?? `exit code ${code}`;
@@ -3411,7 +3362,7 @@ var watchCommand = new Command8("watch").description(
3411
3362
  active.delete(key);
3412
3363
  }
3413
3364
  const failedAttempt = code !== 0 || spawnFailureReason !== null;
3414
- if (failedAttempt) {
3365
+ if (failedAttempt && !activeEntry.terminatedForError) {
3415
3366
  const nextAgent = attemptOrder[attemptIndex + 1];
3416
3367
  if (nextAgent) {
3417
3368
  const failureDetail = spawnFailureReason ?? `exit code ${code}`;
@@ -3448,158 +3399,6 @@ var watchCommand = new Command8("watch").description(
3448
3399
  };
3449
3400
  await launchAttempt(attemptOrder[attemptIndex]);
3450
3401
  }
3451
- async function dispatchIdeaJob(idea, repoDir) {
3452
- const sid = shortId(idea.id);
3453
- const prefix = ideaTag(sid);
3454
- logDispatch(prefix, `"${paint("bold", idea.title)}"${idea.feedback ? paint("cyan", " (iteration)") : ""} ${paint("gray", repoDir)}`);
3455
- for (const f of ["idea-plan.md", "idea-tasks.json", "idea-prototype.html"]) {
3456
- try {
3457
- unlinkSync(resolve2(repoDir, f));
3458
- } catch {
3459
- }
3460
- }
3461
- const prompt2 = buildIdeaPrompt(idea, repoDir);
3462
- const key = `idea-${idea.id}`;
3463
- const attemptOrder = await resolveAgentChain(agent);
3464
- if (attemptOrder.length === 0) {
3465
- logError(prefix, `No available agents found for fallback chain starting at ${agent}`);
3466
- queued.delete(key);
3467
- try {
3468
- await api.patch(`/api/ideas/${idea.id}`, { status: "draft" });
3469
- } catch {
3470
- }
3471
- return;
3472
- }
3473
- const activeEntry = {
3474
- process: void 0,
3475
- title: idea.title,
3476
- repoDir,
3477
- startedAt: Date.now(),
3478
- lastActivityAt: Date.now()
3479
- };
3480
- let attemptIndex = 0;
3481
- const launchAttempt = async (attemptAgent) => {
3482
- let spawnFailureReason = null;
3483
- const child = spawnAgent(
3484
- attemptAgent,
3485
- repoDir,
3486
- prompt2,
3487
- prefix,
3488
- void 0,
3489
- void 0,
3490
- idea.title,
3491
- false,
3492
- (err) => {
3493
- spawnFailureReason = err.message;
3494
- }
3495
- );
3496
- activeEntry.process = child;
3497
- activeEntry.currentAgent = attemptAgent;
3498
- active.set(key, activeEntry);
3499
- child.on("exit", async (code) => {
3500
- if (active.get(key)?.process === child) {
3501
- active.delete(key);
3502
- }
3503
- const failedAttempt = code !== 0 || spawnFailureReason !== null;
3504
- if (failedAttempt) {
3505
- const nextAgent = attemptOrder[attemptIndex + 1];
3506
- if (nextAgent) {
3507
- const failureDetail = spawnFailureReason ?? `exit code ${code}`;
3508
- logWarn(prefix, `${attemptAgent} failed (${failureDetail}) \u2014 retrying idea generation with ${nextAgent}`);
3509
- attemptIndex += 1;
3510
- await launchAttempt(nextAgent);
3511
- return;
3512
- }
3513
- }
3514
- finishing.add(key);
3515
- try {
3516
- if (code === 0) {
3517
- try {
3518
- let plan;
3519
- let protoHtml;
3520
- let followUpTasks;
3521
- const planPath = resolve2(repoDir, "idea-plan.md");
3522
- const tasksPath = resolve2(repoDir, "idea-tasks.json");
3523
- const protoPath = resolve2(repoDir, "idea-prototype.html");
3524
- try {
3525
- plan = readFileSync5(planPath, "utf-8");
3526
- } catch {
3527
- }
3528
- try {
3529
- protoHtml = readFileSync5(protoPath, "utf-8");
3530
- } catch {
3531
- }
3532
- try {
3533
- const tasksRaw = readFileSync5(tasksPath, "utf-8");
3534
- const parsed = JSON.parse(tasksRaw);
3535
- if (Array.isArray(parsed)) {
3536
- followUpTasks = parsed.filter((t) => t && typeof t === "object" && "title" in t);
3537
- }
3538
- } catch {
3539
- }
3540
- if (!plan && !protoHtml) {
3541
- logError(prefix, `No output files found in ${repoDir}`);
3542
- await api.patch(`/api/ideas/${idea.id}`, { status: "draft" });
3543
- return;
3544
- }
3545
- const updateData = { status: "generated" };
3546
- if (plan) updateData.plan = plan;
3547
- if (followUpTasks) updateData.followUpTasks = followUpTasks;
3548
- if (protoHtml) {
3549
- try {
3550
- const proto = await api.post("/api/prototypes", {
3551
- title: `${idea.title} \u2014 Idea Prototype`,
3552
- prompt: idea.description || idea.title,
3553
- variantCount: 1,
3554
- projectId: idea.projectId ?? null
3555
- });
3556
- await api.patch(`/api/prototypes/${proto.id}`, {
3557
- status: "completed",
3558
- files: [{ name: "idea-prototype.html", content: protoHtml }]
3559
- });
3560
- updateData.generatedPrototypeId = proto.id;
3561
- logSuccess(prefix, `Prototype created: ${paint("gray", proto.id.slice(0, 8))}`);
3562
- } catch (err) {
3563
- logError(prefix, `Failed to create prototype: ${err.message}`);
3564
- }
3565
- }
3566
- await api.patch(`/api/ideas/${idea.id}`, updateData);
3567
- logSuccess(prefix, `"${paint("bold", idea.title)}" generation complete`);
3568
- try {
3569
- unlinkSync(planPath);
3570
- } catch {
3571
- }
3572
- try {
3573
- unlinkSync(tasksPath);
3574
- } catch {
3575
- }
3576
- try {
3577
- unlinkSync(protoPath);
3578
- } catch {
3579
- }
3580
- } catch (err) {
3581
- logError(prefix, `Failed to upload idea output: ${err.message}`);
3582
- try {
3583
- await api.patch(`/api/ideas/${idea.id}`, { status: "draft" });
3584
- } catch {
3585
- }
3586
- }
3587
- } else {
3588
- const failureDetail = spawnFailureReason ?? `exit code ${code}`;
3589
- logError(prefix, `"${paint("bold", idea.title)}" generation failed via ${attemptAgent} (${failureDetail})`);
3590
- try {
3591
- await api.patch(`/api/ideas/${idea.id}`, { status: "draft" });
3592
- } catch {
3593
- }
3594
- }
3595
- } finally {
3596
- queued.delete(key);
3597
- finishing.delete(key);
3598
- }
3599
- });
3600
- };
3601
- await launchAttempt(attemptOrder[attemptIndex]);
3602
- }
3603
3402
  function dispatchScan(scan, prefix, key) {
3604
3403
  logDispatch(prefix, `Running scan for project ${paint("cyan", scan.projectId.slice(0, 8))}`);
3605
3404
  const scanProc = spawn4(process.execPath, [process.argv[1], "scan", "--project", scan.projectId, "--report", scan.id], {
@@ -3736,6 +3535,7 @@ ${divider}`);
3736
3535
  const running = active.get(task.id);
3737
3536
  if (running) {
3738
3537
  logWarn(prefix, `Task exceeded hang timeout after ${formatElapsed(Date.now() - running.startedAt)}, terminating agent\u2026`);
3538
+ running.terminatedForError = true;
3739
3539
  running.process.kill("SIGTERM");
3740
3540
  active.delete(task.id);
3741
3541
  }
@@ -3792,7 +3592,7 @@ ${divider}`);
3792
3592
  queued.delete(taskId);
3793
3593
  }
3794
3594
  }
3795
- const nonTaskPrefixes = ["proto-", "repo-", "scan-", "idea-", "test-"];
3595
+ const nonTaskPrefixes = ["proto-", "repo-", "scan-", "test-"];
3796
3596
  for (const taskId of failed.keys()) {
3797
3597
  if (nonTaskPrefixes.some((p) => taskId.startsWith(p))) continue;
3798
3598
  if (!activeTaskIds.has(taskId)) failed.delete(taskId);
@@ -3861,6 +3661,7 @@ ${divider}`);
3861
3661
  for (const [key, entry] of active) {
3862
3662
  if (key.startsWith("proto-") && !inProgressProtoKeys.has(key)) {
3863
3663
  logWarn(watchTag(), `Prototype ${paint("yellow", key)} no longer in_progress, terminating\u2026`);
3664
+ entry.terminatedForError = true;
3864
3665
  entry.process.kill("SIGTERM");
3865
3666
  active.delete(key);
3866
3667
  queued.delete(key);
@@ -4074,59 +3875,6 @@ ${divider}`);
4074
3875
  }
4075
3876
  dispatchRepoCreation(project, rootDir);
4076
3877
  }
4077
- let generatingIdeas = [];
4078
- try {
4079
- generatingIdeas = await api.get("/api/ideas?status=generating");
4080
- } catch (err) {
4081
- logError(watchTag(), `Failed to fetch generating ideas: ${err.message}`);
4082
- }
4083
- const inProgressIdeaKeys = new Set(generatingIdeas.map((i) => `idea-${i.id}`));
4084
- for (const [key, entry] of active) {
4085
- if (key.startsWith("idea-") && !inProgressIdeaKeys.has(key)) {
4086
- logWarn(watchTag(), `Idea ${paint("yellow", key)} no longer generating, terminating\u2026`);
4087
- entry.process.kill("SIGTERM");
4088
- active.delete(key);
4089
- queued.delete(key);
4090
- }
4091
- }
4092
- for (const key of failed.keys()) {
4093
- if (key.startsWith("idea-") && !inProgressIdeaKeys.has(key)) failed.delete(key);
4094
- }
4095
- for (const key of queued) {
4096
- if (key.startsWith("idea-") && !inProgressIdeaKeys.has(key) && !finishing.has(key)) queued.delete(key);
4097
- }
4098
- const activeIdeaCount = [...active.keys()].filter((k) => k.startsWith("idea-")).length;
4099
- let ideaSlots = Math.max(0, 1 - activeIdeaCount);
4100
- for (const idea of generatingIdeas) {
4101
- if (ideaSlots <= 0) break;
4102
- const key = `idea-${idea.id}`;
4103
- if (queued.has(key)) continue;
4104
- if (finishing.has(key)) continue;
4105
- if (failed.has(key)) continue;
4106
- const sid = shortId(idea.id);
4107
- const prefix = ideaTag(sid);
4108
- let repoDir;
4109
- if (idea.projectId) {
4110
- const dir = findDirectoryForProject(config, idea.projectId, rootDir);
4111
- if (!dir) {
4112
- logWarn(prefix, `"${idea.title}": no linked directory found \u2014 skipping`);
4113
- continue;
4114
- }
4115
- repoDir = dir;
4116
- } else {
4117
- repoDir = rootDir;
4118
- }
4119
- queued.add(key);
4120
- ideaSlots--;
4121
- if (dryRun) {
4122
- logInfo(
4123
- watchTag(),
4124
- `${paint("yellow", "[dry-run]")} would dispatch idea "${paint("bold", idea.title)}" in ${paint("cyan", repoDir)}`
4125
- );
4126
- continue;
4127
- }
4128
- dispatchIdeaJob(idea, repoDir);
4129
- }
4130
3878
  let pendingScans = [];
4131
3879
  try {
4132
3880
  pendingScans = await api.get("/api/scans?status=pending&limit=5");
@@ -4751,7 +4499,7 @@ async function checkApiConnectivity() {
4751
4499
  }
4752
4500
  }
4753
4501
  function printResults(checks) {
4754
- const maxNameLen = Math.max(...checks.map((c12) => c12.name.length));
4502
+ const maxNameLen = Math.max(...checks.map((c11) => c11.name.length));
4755
4503
  let allOk = true;
4756
4504
  for (const check of checks) {
4757
4505
  const isOptional = check.optional ?? false;
@@ -4765,10 +4513,10 @@ function printResults(checks) {
4765
4513
  }
4766
4514
  async function autoFix(checks, agent) {
4767
4515
  const { spawn: spawn8 } = await import("child_process");
4768
- const ghInstalled = checks.find((c12) => c12.name === "GitHub CLI (gh)").ok;
4769
- const ghAuthed = checks.find((c12) => c12.name === "GitHub CLI auth").ok;
4770
- const mrAuthed = checks.find((c12) => c12.name === "Mr. Manager CLI auth").ok;
4771
- const claudeCheck = checks.find((c12) => c12.name === "Claude Code (claude)");
4516
+ const ghInstalled = checks.find((c11) => c11.name === "GitHub CLI (gh)").ok;
4517
+ const ghAuthed = checks.find((c11) => c11.name === "GitHub CLI auth").ok;
4518
+ const mrAuthed = checks.find((c11) => c11.name === "Mr. Manager CLI auth").ok;
4519
+ const claudeCheck = checks.find((c11) => c11.name === "Claude Code (claude)");
4772
4520
  if (claudeCheck && !claudeCheck.ok && agent === "claude") {
4773
4521
  console.log(paint5("cyan", " Installing Claude Code..."));
4774
4522
  console.log(paint5("dim", " Running: curl -fsSL https://claude.ai/install.sh | bash"));
@@ -4831,7 +4579,7 @@ var setupCommand = new Command14("setup").description("Check that all dependenci
4831
4579
  console.log("");
4832
4580
  return;
4833
4581
  }
4834
- const fixes = checks.filter((c12) => !c12.ok && c12.fix && !c12.optional);
4582
+ const fixes = checks.filter((c11) => !c11.ok && c11.fix && !c11.optional);
4835
4583
  if (fixes.length > 0) {
4836
4584
  console.log(paint5("yellow", " To fix:"));
4837
4585
  for (const fix of fixes) {
@@ -6024,10 +5772,10 @@ ${codebaseAnalysis.routes.map((r) => `- ${r}`).join("\n")}
6024
5772
  ${codebaseAnalysis.prismaModels.map((m) => `- ${m}`).join("\n")}
6025
5773
 
6026
5774
  **Components:**
6027
- ${codebaseAnalysis.components.slice(0, 15).map((c12) => `- ${c12}`).join("\n")}
5775
+ ${codebaseAnalysis.components.slice(0, 15).map((c11) => `- ${c11}`).join("\n")}
6028
5776
 
6029
5777
  **Recent Git Commits:**
6030
- ${codebaseAnalysis.recentCommits.slice(0, 8).map((c12) => `- ${c12}`).join("\n")}
5778
+ ${codebaseAnalysis.recentCommits.slice(0, 8).map((c11) => `- ${c11}`).join("\n")}
6031
5779
 
6032
5780
  **Completed Tasks:**
6033
5781
  ${context.completedTasks.slice(0, 10).map((t) => `- ${t.title}`).join("\n") || "None"}
@@ -6474,128 +6222,8 @@ var scanCommand = new Command23("scan").description("Run a product scan on the c
6474
6222
  }
6475
6223
  });
6476
6224
 
6477
- // cli/commands/idea.ts
6478
- import { Command as Command24 } from "commander";
6479
- var c9 = {
6480
- reset: "\x1B[0m",
6481
- bold: "\x1B[1m",
6482
- dim: "\x1B[2m",
6483
- cyan: "\x1B[36m",
6484
- green: "\x1B[32m",
6485
- yellow: "\x1B[33m",
6486
- red: "\x1B[31m",
6487
- blue: "\x1B[34m",
6488
- gray: "\x1B[90m",
6489
- magenta: "\x1B[35m"
6490
- };
6491
- function paint9(color, text) {
6492
- return `${c9[color]}${text}${c9.reset}`;
6493
- }
6494
- function statusBadge2(status) {
6495
- switch (status) {
6496
- case "draft":
6497
- return paint9("gray", "\u25CB draft");
6498
- case "generating":
6499
- return paint9("cyan", "\u27F3 generating");
6500
- case "generated":
6501
- return paint9("green", "\u2713 generated");
6502
- case "promoted":
6503
- return paint9("magenta", "\u2191 promoted");
6504
- case "archived":
6505
- return paint9("dim", "\u2298 archived");
6506
- default:
6507
- return paint9("gray", status);
6508
- }
6509
- }
6510
- var ideaCommand = new Command24("idea").description("Manage ideas \u2014 brainstorm, generate prototypes & plans").addCommand(
6511
- new Command24("list").description("List ideas for the linked project").option("--all", "Show ideas for all projects").option("--status <status>", "Filter by status").action(async (opts) => {
6512
- const params = new URLSearchParams();
6513
- if (!opts.all) {
6514
- const projectId = getLinkedProjectId();
6515
- if (projectId) {
6516
- params.set("projectId", projectId);
6517
- }
6518
- }
6519
- if (opts.status) params.set("status", opts.status);
6520
- const ideas = await api.get(`/api/ideas?${params.toString()}`);
6521
- if (ideas.length === 0) {
6522
- console.log(paint9("gray", "No ideas found."));
6523
- return;
6524
- }
6525
- console.log();
6526
- for (const idea of ideas) {
6527
- const date = new Date(idea.createdAt).toLocaleDateString();
6528
- console.log(
6529
- ` ${paint9("bold", idea.title)} ${statusBadge2(idea.status)} ${paint9("gray", idea.id.slice(0, 8))} ${paint9("dim", date)}`
6530
- );
6531
- if (idea.description) {
6532
- console.log(` ${paint9("dim", idea.description.slice(0, 80) + (idea.description.length > 80 ? "\u2026" : ""))}`);
6533
- }
6534
- console.log();
6535
- }
6536
- })
6537
- ).addCommand(
6538
- new Command24("create").description("Create a new idea").argument("<title>", "Title of the idea").option("--description <desc>", "Description of the idea").option("--project <projectId>", "Project ID (defaults to linked project)").option("--generate", "Immediately start generating plan & prototype").action(async (title, opts) => {
6539
- const projectId = opts.project ?? getLinkedProjectId() ?? null;
6540
- const idea = await api.post("/api/ideas", {
6541
- title,
6542
- description: opts.description,
6543
- projectId
6544
- });
6545
- console.log();
6546
- console.log(` ${paint9("green", "\u2713")} Created idea: ${paint9("bold", idea.title)}`);
6547
- console.log(` ${paint9("gray", "ID:")} ${idea.id}`);
6548
- if (opts.generate) {
6549
- await api.post(`/api/ideas/${idea.id}/generate`);
6550
- console.log(` ${paint9("cyan", "\u27F3")} Generation will begin automatically via the watch agent.`);
6551
- }
6552
- console.log();
6553
- })
6554
- ).addCommand(
6555
- new Command24("generate").description("Start generating plan & prototype for an idea").argument("<id>", "Idea ID").action(async (id) => {
6556
- const idea = await api.post(`/api/ideas/${id}/generate`);
6557
- console.log();
6558
- console.log(` ${paint9("cyan", "\u27F3")} Generating: ${paint9("bold", idea.title)}`);
6559
- console.log(` ${paint9("gray", "The watch agent will pick this up shortly.")}`);
6560
- console.log();
6561
- })
6562
- ).addCommand(
6563
- new Command24("feedback").description("Send feedback to iterate on an idea's generated content").argument("<id>", "Idea ID").argument("<feedback>", "Feedback text").action(async (id, feedback) => {
6564
- const idea = await api.post(`/api/ideas/${id}/feedback`, { feedback });
6565
- console.log();
6566
- console.log(` ${paint9("cyan", "\u27F3")} Feedback sent for: ${paint9("bold", idea.title)}`);
6567
- console.log(` ${paint9("gray", "The watch agent will re-generate with your feedback.")}`);
6568
- console.log();
6569
- })
6570
- ).addCommand(
6571
- new Command24("promote").description("Promote an idea to a task").argument("<id>", "Idea ID").action(async (id) => {
6572
- const result = await api.post(`/api/ideas/${id}/promote`);
6573
- console.log();
6574
- console.log(` ${paint9("green", "\u2713")} Promoted idea to task: ${paint9("bold", result.task.title)}`);
6575
- console.log(` ${paint9("gray", "Task ID:")} ${result.task.id}`);
6576
- console.log();
6577
- })
6578
- ).addCommand(
6579
- new Command24("spin-up").description("Spin up a new project with a GitHub repo from an idea").argument("<id>", "Idea ID").option("--name <name>", "Custom project name (defaults to idea title)").action(async (id, opts) => {
6580
- const body = {};
6581
- if (opts.name) body.name = opts.name;
6582
- const result = await api.post(`/api/ideas/${id}/spin-up`, body);
6583
- console.log();
6584
- console.log(` ${paint9("green", "\u2713")} Spinning up project: ${paint9("bold", result.project.name)}`);
6585
- console.log(` ${paint9("gray", "Project ID:")} ${result.project.id}`);
6586
- if (result.tasks && result.tasks.length > 0) {
6587
- console.log(` ${paint9("green", "\u2713")} Created ${result.tasks.length} follow-up task(s):`);
6588
- for (const task of result.tasks) {
6589
- console.log(` ${paint9("gray", "\u2022")} ${task.title}`);
6590
- }
6591
- }
6592
- console.log(` ${paint9("cyan", "\u27F3")} Repo creation is queued \u2014 the watch daemon will pick it up.`);
6593
- console.log();
6594
- })
6595
- );
6596
-
6597
6225
  // cli/commands/doctor.ts
6598
- import { Command as Command25 } from "commander";
6226
+ import { Command as Command24 } from "commander";
6599
6227
  import { existsSync as existsSync15 } from "fs";
6600
6228
  import { homedir as homedir2 } from "os";
6601
6229
  import { join as join11 } from "path";
@@ -6643,7 +6271,7 @@ async function checkProjectLink() {
6643
6271
  optional: true
6644
6272
  };
6645
6273
  }
6646
- var doctorCommand = new Command25("doctor").description("Diagnose Mr. Manager CLI installation and environment").action(async () => {
6274
+ var doctorCommand = new Command24("doctor").description("Diagnose Mr. Manager CLI installation and environment").action(async () => {
6647
6275
  const banner = [
6648
6276
  ``,
6649
6277
  paint5("cyan", ` MR DOCTOR`),
@@ -6674,7 +6302,7 @@ var doctorCommand = new Command25("doctor").description("Diagnose Mr. Manager CL
6674
6302
  console.log("");
6675
6303
  return;
6676
6304
  }
6677
- const fixes = checks.filter((c12) => !c12.ok && c12.fix && !c12.optional);
6305
+ const fixes = checks.filter((c11) => !c11.ok && c11.fix && !c11.optional);
6678
6306
  if (fixes.length > 0) {
6679
6307
  console.log(paint5("yellow", " To fix:"));
6680
6308
  for (const fix of fixes) {
@@ -6686,14 +6314,14 @@ var doctorCommand = new Command25("doctor").description("Diagnose Mr. Manager CL
6686
6314
  });
6687
6315
 
6688
6316
  // cli/commands/prompt-audit.ts
6689
- import { Command as Command26 } from "commander";
6317
+ import { Command as Command25 } from "commander";
6690
6318
  import { resolve as resolve8 } from "path";
6691
6319
  import { existsSync as existsSync16, readFileSync as readFileSync12 } from "fs";
6692
6320
  function auditLine(label, tokens) {
6693
6321
  const bar = "\u2588".repeat(Math.min(60, Math.round(tokens / 200)));
6694
6322
  return ` ${label.padEnd(30)} ${formatTokenCount(tokens).padStart(8)} ${bar}`;
6695
6323
  }
6696
- var promptAuditCommand = new Command26("prompt-audit").description("Dry-run prompt construction and report estimated token counts by job type").option("--task <id>", "Audit prompts for a specific task ID").option("--all", "Audit all supported job types with representative data", false).option("--json", "Output as JSON instead of plain text", false).action(async (opts) => {
6324
+ var promptAuditCommand = new Command25("prompt-audit").description("Dry-run prompt construction and report estimated token counts by job type").option("--task <id>", "Audit prompts for a specific task ID").option("--all", "Audit all supported job types with representative data", false).option("--json", "Output as JSON instead of plain text", false).action(async (opts) => {
6697
6325
  const results = [];
6698
6326
  if (opts.task) {
6699
6327
  try {
@@ -6853,14 +6481,6 @@ ${task.notes}` : "";
6853
6481
  { name: "instructions", tokens: 500 }
6854
6482
  ]
6855
6483
  },
6856
- {
6857
- jobType: "idea",
6858
- description: "Idea generation prompt",
6859
- sections: [
6860
- { name: "core-prompt", tokens: 500 },
6861
- { name: "idea-desc", tokens: 200 }
6862
- ]
6863
- },
6864
6484
  {
6865
6485
  jobType: "repo-creation",
6866
6486
  description: "Repository creation prompt",
@@ -6906,8 +6526,8 @@ ${r.jobType} [${r.identifier}]`);
6906
6526
  });
6907
6527
 
6908
6528
  // cli/commands/skill.ts
6909
- import { Command as Command27 } from "commander";
6910
- var c10 = {
6529
+ import { Command as Command26 } from "commander";
6530
+ var c9 = {
6911
6531
  reset: "\x1B[0m",
6912
6532
  bold: "\x1B[1m",
6913
6533
  dim: "\x1B[2m",
@@ -6915,7 +6535,7 @@ var c10 = {
6915
6535
  green: "\x1B[32m",
6916
6536
  yellow: "\x1B[33m"
6917
6537
  };
6918
- var skillCommand = new Command27("skill").description("Manage skills \u2014 reusable playbooks for AI agents");
6538
+ var skillCommand = new Command26("skill").description("Manage skills \u2014 reusable playbooks for AI agents");
6919
6539
  skillCommand.command("list").alias("ls").description("List all skills").option("--category <category>", "Filter by category").action(async (opts) => {
6920
6540
  const params = new URLSearchParams();
6921
6541
  if (opts.category) params.set("category", opts.category);
@@ -6923,17 +6543,17 @@ skillCommand.command("list").alias("ls").description("List all skills").option("
6923
6543
  `/api/skills${params.toString() ? `?${params}` : ""}`
6924
6544
  );
6925
6545
  if (skills.length === 0) {
6926
- console.log(`${c10.dim}No skills found.${c10.reset}`);
6546
+ console.log(`${c9.dim}No skills found.${c9.reset}`);
6927
6547
  return;
6928
6548
  }
6929
6549
  for (const skill of skills) {
6930
- const cat = skill.category ? ` ${c10.dim}[${skill.category}]${c10.reset}` : "";
6931
- const scope = skill.projectId ? ` ${c10.dim}(project)${c10.reset}` : ` ${c10.dim}(global)${c10.reset}`;
6932
- console.log(` ${c10.cyan}${skill.name}${c10.reset}${cat}${scope}`);
6550
+ const cat = skill.category ? ` ${c9.dim}[${skill.category}]${c9.reset}` : "";
6551
+ const scope = skill.projectId ? ` ${c9.dim}(project)${c9.reset}` : ` ${c9.dim}(global)${c9.reset}`;
6552
+ console.log(` ${c9.cyan}${skill.name}${c9.reset}${cat}${scope}`);
6933
6553
  if (skill.description) {
6934
- console.log(` ${c10.dim}${skill.description}${c10.reset}`);
6554
+ console.log(` ${c9.dim}${skill.description}${c9.reset}`);
6935
6555
  }
6936
- console.log(` ${c10.dim}id: ${skill.id}${c10.reset}`);
6556
+ console.log(` ${c9.dim}id: ${skill.id}${c9.reset}`);
6937
6557
  }
6938
6558
  });
6939
6559
  skillCommand.command("create").description("Create a new skill from a markdown file or inline content").argument("<name>", "Skill name").option("-d, --description <desc>", "Short description").option("-c, --category <cat>", "Category (e.g. Deployment, Testing)").option("-f, --file <path>", "Read content from a markdown file").option("--content <text>", "Inline markdown content").option("-p, --project", "Scope to the linked project").action(async (name, opts) => {
@@ -6969,7 +6589,7 @@ skillCommand.command("create").description("Create a new skill from a markdown f
6969
6589
  projectId
6970
6590
  });
6971
6591
  console.log(
6972
- `${c10.green}Created skill:${c10.reset} ${c10.bold}${skill.name}${c10.reset} ${c10.dim}(${skill.id})${c10.reset}`
6592
+ `${c9.green}Created skill:${c9.reset} ${c9.bold}${skill.name}${c9.reset} ${c9.dim}(${skill.id})${c9.reset}`
6973
6593
  );
6974
6594
  });
6975
6595
  skillCommand.command("generate").alias("gen").description("Generate a new skill using AI from a text prompt").argument("<prompt>", "Describe the skill to generate").option("-p, --project", "Scope to the linked project").action(async (prompt2, opts) => {
@@ -6983,22 +6603,22 @@ skillCommand.command("generate").alias("gen").description("Generate a new skill
6983
6603
  process.exit(1);
6984
6604
  }
6985
6605
  }
6986
- console.log(`${c10.dim}Generating skill...${c10.reset}`);
6606
+ console.log(`${c9.dim}Generating skill...${c9.reset}`);
6987
6607
  try {
6988
6608
  const skill = await api.post("/api/skills/generate", {
6989
6609
  prompt: prompt2,
6990
6610
  projectId
6991
6611
  });
6992
6612
  console.log(
6993
- `${c10.green}Generated skill:${c10.reset} ${c10.bold}${skill.name}${c10.reset}`
6613
+ `${c9.green}Generated skill:${c9.reset} ${c9.bold}${skill.name}${c9.reset}`
6994
6614
  );
6995
6615
  if (skill.description) {
6996
- console.log(` ${c10.dim}${skill.description}${c10.reset}`);
6616
+ console.log(` ${c9.dim}${skill.description}${c9.reset}`);
6997
6617
  }
6998
6618
  if (skill.category) {
6999
- console.log(` ${c10.dim}Category: ${skill.category}${c10.reset}`);
6619
+ console.log(` ${c9.dim}Category: ${skill.category}${c9.reset}`);
7000
6620
  }
7001
- console.log(` ${c10.dim}id: ${skill.id}${c10.reset}`);
6621
+ console.log(` ${c9.dim}id: ${skill.id}${c9.reset}`);
7002
6622
  } catch (err) {
7003
6623
  console.error(`Failed to generate skill: ${err.message}`);
7004
6624
  process.exit(1);
@@ -7006,17 +6626,17 @@ skillCommand.command("generate").alias("gen").description("Generate a new skill
7006
6626
  });
7007
6627
 
7008
6628
  // cli/commands/tests.ts
7009
- import { Command as Command28 } from "commander";
7010
- var c11 = {
6629
+ import { Command as Command27 } from "commander";
6630
+ var c10 = {
7011
6631
  reset: "\x1B[0m",
7012
6632
  dim: "\x1B[2m",
7013
6633
  yellow: "\x1B[33m"
7014
6634
  };
7015
- var testsCommand = new Command28("tests").description("List MR Test scenarios for the linked project").action(async () => {
6635
+ var testsCommand = new Command27("tests").description("List MR Test scenarios for the linked project").action(async () => {
7016
6636
  const projectId = getLinkedProjectId();
7017
6637
  if (!projectId) {
7018
6638
  console.error(
7019
- `${c11.yellow}No project linked to this directory.${c11.reset} Run "mr link <project-id>" first.`
6639
+ `${c10.yellow}No project linked to this directory.${c10.reset} Run "mr link <project-id>" first.`
7020
6640
  );
7021
6641
  process.exit(1);
7022
6642
  }
@@ -7029,13 +6649,13 @@ var testsCommand = new Command28("tests").description("List MR Test scenarios fo
7029
6649
  process.exit(1);
7030
6650
  }
7031
6651
  if (scenarios.length === 0) {
7032
- console.log(`${c11.dim}No test scenarios found for this project.${c11.reset}`);
6652
+ console.log(`${c10.dim}No test scenarios found for this project.${c10.reset}`);
7033
6653
  return;
7034
6654
  }
7035
6655
  for (const scenario of scenarios) {
7036
6656
  console.log(`### ${scenario.name}`);
7037
6657
  if (scenario.description) {
7038
- console.log(`${c11.dim}${scenario.description}${c11.reset}`);
6658
+ console.log(`${c10.dim}${scenario.description}${c10.reset}`);
7039
6659
  console.log();
7040
6660
  }
7041
6661
  console.log(scenario.content);
@@ -7050,7 +6670,7 @@ var userArgs = process.argv.slice(2);
7050
6670
  var bypassCommands = /* @__PURE__ */ new Set(["login", "init", "auth", "help", "--help", "-h", "--version", "-V", "doctor", "setup"]);
7051
6671
  var shouldBypass = userArgs.length > 0 && bypassCommands.has(userArgs[0]);
7052
6672
  if (isFirstRun && !shouldBypass) {
7053
- const c12 = {
6673
+ const c11 = {
7054
6674
  reset: "\x1B[0m",
7055
6675
  bold: "\x1B[1m",
7056
6676
  dim: "\x1B[2m",
@@ -7060,28 +6680,28 @@ if (isFirstRun && !shouldBypass) {
7060
6680
  magenta: "\x1B[35m"
7061
6681
  };
7062
6682
  console.log("");
7063
- console.log(`${c12.cyan} \u2554\u2566\u2557\u2566\u2550\u2557 \u2554\u2566\u2557\u2554\u2550\u2557\u2554\u2557\u2554\u2554\u2550\u2557\u2554\u2550\u2557\u2554\u2550\u2557\u2566\u2550\u2557${c12.reset}`);
7064
- console.log(`${c12.magenta} \u2551\u2551\u2551\u2560\u2566\u255D \u2551\u2551\u2551\u2560\u2550\u2563\u2551\u2551\u2551\u2560\u2550\u2563\u2551 \u2566\u2551\u2563 \u2560\u2566\u255D${c12.reset}`);
7065
- console.log(`${c12.cyan} \u2569 \u2569\u2569\u255A\u2550 \u2569 \u2569\u2569 \u2569\u255D\u255A\u255D\u2569 \u2569\u255A\u2550\u255D\u255A\u2550\u255D\u2569\u255A\u2550${c12.reset}`);
7066
- console.log(`${c12.dim} \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500${c12.reset}`);
6683
+ console.log(`${c11.cyan} \u2554\u2566\u2557\u2566\u2550\u2557 \u2554\u2566\u2557\u2554\u2550\u2557\u2554\u2557\u2554\u2554\u2550\u2557\u2554\u2550\u2557\u2554\u2550\u2557\u2566\u2550\u2557${c11.reset}`);
6684
+ console.log(`${c11.magenta} \u2551\u2551\u2551\u2560\u2566\u255D \u2551\u2551\u2551\u2560\u2550\u2563\u2551\u2551\u2551\u2560\u2550\u2563\u2551 \u2566\u2551\u2563 \u2560\u2566\u255D${c11.reset}`);
6685
+ console.log(`${c11.cyan} \u2569 \u2569\u2569\u255A\u2550 \u2569 \u2569\u2569 \u2569\u255D\u255A\u255D\u2569 \u2569\u255A\u2550\u255D\u255A\u2550\u255D\u2569\u255A\u2550${c11.reset}`);
6686
+ console.log(`${c11.dim} \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500${c11.reset}`);
7067
6687
  console.log("");
7068
- console.log(`${c12.bold} Welcome to Mr. Manager!${c12.reset}`);
7069
- console.log(`${c12.dim} Let's get you set up in a few quick steps.${c12.reset}`);
6688
+ console.log(`${c11.bold} Welcome to Mr. Manager!${c11.reset}`);
6689
+ console.log(`${c11.dim} Let's get you set up in a few quick steps.${c11.reset}`);
7070
6690
  console.log("");
7071
- console.log(` ${c12.yellow}Step 1:${c12.reset} Authenticate via Google OAuth`);
7072
- console.log(` ${c12.dim}Run:${c12.reset} ${c12.cyan}mr login${c12.reset}`);
6691
+ console.log(` ${c11.yellow}Step 1:${c11.reset} Authenticate via Google OAuth`);
6692
+ console.log(` ${c11.dim}Run:${c11.reset} ${c11.cyan}mr login${c11.reset}`);
7073
6693
  console.log("");
7074
- console.log(` ${c12.yellow}Step 2:${c12.reset} Verify your environment`);
7075
- console.log(` ${c12.dim}Run:${c12.reset} ${c12.cyan}mr setup${c12.reset}`);
6694
+ console.log(` ${c11.yellow}Step 2:${c11.reset} Verify your environment`);
6695
+ console.log(` ${c11.dim}Run:${c11.reset} ${c11.cyan}mr setup${c11.reset}`);
7076
6696
  console.log("");
7077
- console.log(` ${c12.yellow}Step 3:${c12.reset} Link a repo and start watching`);
7078
- console.log(` ${c12.dim}Run:${c12.reset} ${c12.cyan}mr link${c12.reset} ${c12.dim}&&${c12.reset} ${c12.cyan}mr watch${c12.reset}`);
6697
+ console.log(` ${c11.yellow}Step 3:${c11.reset} Link a repo and start watching`);
6698
+ console.log(` ${c11.dim}Run:${c11.reset} ${c11.cyan}mr link${c11.reset} ${c11.dim}&&${c11.reset} ${c11.cyan}mr watch${c11.reset}`);
7079
6699
  console.log("");
7080
- console.log(`${c12.dim} Or run ${c12.reset}${c12.cyan}mr login${c12.reset}${c12.dim} to get started now.${c12.reset}`);
6700
+ console.log(`${c11.dim} Or run ${c11.reset}${c11.cyan}mr login${c11.reset}${c11.dim} to get started now.${c11.reset}`);
7081
6701
  console.log("");
7082
6702
  process.exit(0);
7083
6703
  }
7084
- var program = new Command29();
6704
+ var program = new Command28();
7085
6705
  program.name("mr").description("Mr. Manager - Task and project management CLI").version(CLI_VERSION);
7086
6706
  program.addCommand(initCommand);
7087
6707
  program.addCommand(authCommand);
@@ -7109,7 +6729,6 @@ program.addCommand(testCommand);
7109
6729
  program.addCommand(featuresCommand);
7110
6730
  program.addCommand(noMrCommand);
7111
6731
  program.addCommand(scanCommand);
7112
- program.addCommand(ideaCommand);
7113
6732
  program.addCommand(doctorCommand);
7114
6733
  program.addCommand(promptAuditCommand);
7115
6734
  program.addCommand(skillCommand);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dunnewold-labs/mr-manager",
3
- "version": "0.4.28",
3
+ "version": "0.4.29",
4
4
  "description": "Mr. Manager - Task and project management CLI",
5
5
  "bin": {
6
6
  "mr": "./dist/index.mjs"