@dunnewold-labs/mr-manager 0.4.4 → 0.4.7

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 +163 -172
  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 Command27 } from "commander";
4
+ import { Command as Command26 } from "commander";
5
5
  import { existsSync as existsSync16 } 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.4",
188
+ version: "0.4.7",
189
189
  description: "Mr. Manager - Task and project management CLI",
190
190
  bin: {
191
191
  mr: "./dist/index.mjs"
@@ -1026,6 +1026,12 @@ function slugify(title) {
1026
1026
  function shortId(id) {
1027
1027
  return id.slice(0, 8);
1028
1028
  }
1029
+ function ownerPrefix(task) {
1030
+ const name = task.user?.name;
1031
+ if (!name) return "mr";
1032
+ const first = name.split(/\s+/)[0].toLowerCase().replace(/[^a-z0-9]/g, "");
1033
+ return first || "mr";
1034
+ }
1029
1035
  function formatElapsed(ms) {
1030
1036
  const totalMinutes = Math.max(1, Math.floor(ms / 6e4));
1031
1037
  const hours = Math.floor(totalMinutes / 60);
@@ -1035,8 +1041,8 @@ function formatElapsed(ms) {
1035
1041
  }
1036
1042
  return `${totalMinutes}m`;
1037
1043
  }
1038
- function worktreePath(sid) {
1039
- return `.mr-worktrees/mr-${sid}`;
1044
+ function worktreePath(name) {
1045
+ return `.mr-worktrees/${name}`;
1040
1046
  }
1041
1047
  function worktreeNameFromPath(wtPath) {
1042
1048
  return wtPath.replace(/^\.mr-worktrees\//, "");
@@ -1227,6 +1233,33 @@ async function extractPrUrlFromUpdates(taskId) {
1227
1233
  }
1228
1234
  return null;
1229
1235
  }
1236
+ function checkPrStatus(prUrl, repoDir, vcs = "github") {
1237
+ const cmd = vcs === "gitlab" ? `glab mr view "${prUrl}" --output json 2>/dev/null` : `gh pr view "${prUrl}" --json merged,mergeable 2>/dev/null`;
1238
+ return new Promise((resolve7) => {
1239
+ exec(cmd, { cwd: repoDir }, (err, stdout) => {
1240
+ if (err || !stdout.trim()) {
1241
+ resolve7(null);
1242
+ return;
1243
+ }
1244
+ try {
1245
+ const data = JSON.parse(stdout.trim());
1246
+ if (vcs === "gitlab") {
1247
+ resolve7({
1248
+ merged: data.state === "merged",
1249
+ hasConflicts: data.has_conflicts === true
1250
+ });
1251
+ } else {
1252
+ resolve7({
1253
+ merged: data.merged === true,
1254
+ hasConflicts: data.mergeable === "CONFLICTING"
1255
+ });
1256
+ }
1257
+ } catch {
1258
+ resolve7(null);
1259
+ }
1260
+ });
1261
+ });
1262
+ }
1230
1263
  function buildPrototypeSection(protoRefs) {
1231
1264
  if (protoRefs.length === 0) return "";
1232
1265
  const sections = [
@@ -1357,8 +1390,9 @@ function buildFeaturesSection(repoDir) {
1357
1390
  function buildExecutionPrompt(task, repoDir, subtasks, vcs = "github", protoRefs = [], feedbackUpdates = [], existingResources = [], skillRefs = [], executionDir) {
1358
1391
  const sid = shortId(task.id);
1359
1392
  const slug = slugify(task.title);
1360
- const branchName = `mr/${sid}/${slug}`;
1361
- const wtPath = worktreePath(sid);
1393
+ const owner = ownerPrefix(task);
1394
+ const branchName = `${owner}/${slug}`;
1395
+ const wtPath = worktreePath(`${owner}-${slug}`);
1362
1396
  const workingDir = executionDir ?? repoDir;
1363
1397
  const prBodyPath = "/tmp/mr-pr-body.md";
1364
1398
  const notes = task.prdContent ? `
@@ -1381,7 +1415,7 @@ ${task.notes}` : "";
1381
1415
  ``
1382
1416
  ].join("\n") : "";
1383
1417
  const hasFeedback = feedbackUpdates.length > 0;
1384
- const feedbackWtPath = hasFeedback ? worktreePath(`${sid}-fb`) : wtPath;
1418
+ const feedbackWtPath = hasFeedback ? worktreePath(`${owner}-${slug}-fb`) : wtPath;
1385
1419
  const prBodyTemplate = buildPrBodyTemplate(task, pendingSubtasks, protoRefs, feedbackUpdates, existingResources, skillRefs);
1386
1420
  const prCreateCmd = vcs === "gitlab" ? `glab mr create --title "${task.title}" --description-file ${prBodyPath} --yes` : `gh pr create --title "${task.title}" --body-file ${prBodyPath}`;
1387
1421
  return [
@@ -2063,7 +2097,9 @@ var watchCommand = new Command8("watch").description(
2063
2097
  async function dispatchTask(task, repoDir) {
2064
2098
  const sid = shortId(task.id);
2065
2099
  const slug = slugify(task.title);
2066
- const branchName = `mr/${sid}/${slug}`;
2100
+ const owner = ownerPrefix(task);
2101
+ const branchName = `${owner}/${slug}`;
2102
+ const legacyBranchName = `mr/${sid}/${slug}`;
2067
2103
  const prefix = taskTag(sid);
2068
2104
  const vcs = detectVcs(repoDir)?.provider ?? "github";
2069
2105
  logDispatch(prefix, `"${paint("bold", task.title)}" ${paint("gray", repoDir)} ${paint("dim", `[${vcs}]`)}`);
@@ -2112,7 +2148,8 @@ var watchCommand = new Command8("watch").description(
2112
2148
  } catch {
2113
2149
  }
2114
2150
  const hasFeedback = feedbackUpdates.length > 0;
2115
- const desiredWorktreePath = hasFeedback ? worktreePath(`${sid}-fb`) : worktreePath(sid);
2151
+ const wtName = `${owner}-${slug}`;
2152
+ const desiredWorktreePath = hasFeedback ? worktreePath(`${wtName}-fb`) : worktreePath(wtName);
2116
2153
  let executionDir = repoDir;
2117
2154
  let cleanupWorktreePath;
2118
2155
  if (isGitRepo(repoDir)) {
@@ -2187,6 +2224,9 @@ var watchCommand = new Command8("watch").description(
2187
2224
  let prUrl = null;
2188
2225
  if (!noMrRequested) {
2189
2226
  prUrl = await findPrUrlAcrossRepos(branchName, repoDir, vcs);
2227
+ if (!prUrl) {
2228
+ prUrl = await findPrUrlAcrossRepos(legacyBranchName, repoDir, vcs);
2229
+ }
2190
2230
  if (!prUrl) {
2191
2231
  prUrl = await extractPrUrlFromUpdates(task.id);
2192
2232
  if (prUrl) {
@@ -2336,7 +2376,7 @@ var watchCommand = new Command8("watch").description(
2336
2376
  } else {
2337
2377
  prompt2 = buildPrototypePrompt(proto, repoDir);
2338
2378
  }
2339
- const child = spawnAgent(agent, repoDir, prompt2, prefix, void 0, proto.title);
2379
+ const child = spawnAgent(agent, repoDir, prompt2, prefix, void 0, void 0, proto.title);
2340
2380
  active.set(`proto-${proto.id}`, { process: child, title: proto.title, repoDir, startedAt: Date.now() });
2341
2381
  child.on("exit", async (code) => {
2342
2382
  const key = `proto-${proto.id}`;
@@ -2393,7 +2433,7 @@ var watchCommand = new Command8("watch").description(
2393
2433
  } catch {
2394
2434
  }
2395
2435
  const prompt2 = buildRepoCreationPrompt(project, workDir);
2396
- const child = spawnAgent(agent, workDir, prompt2, prefix, void 0, project.name);
2436
+ const child = spawnAgent(agent, workDir, prompt2, prefix, void 0, void 0, project.name);
2397
2437
  active.set(`repo-${project.id}`, { process: child, title: project.name, repoDir: workDir, startedAt: Date.now() });
2398
2438
  child.on("exit", async (code) => {
2399
2439
  const key = `repo-${project.id}`;
@@ -2426,7 +2466,7 @@ var watchCommand = new Command8("watch").description(
2426
2466
  }
2427
2467
  }
2428
2468
  const prompt2 = buildIdeaPrompt(idea, repoDir);
2429
- const child = spawnAgent(agent, repoDir, prompt2, prefix, void 0, idea.title);
2469
+ const child = spawnAgent(agent, repoDir, prompt2, prefix, void 0, void 0, idea.title);
2430
2470
  active.set(`idea-${idea.id}`, { process: child, title: idea.title, repoDir, startedAt: Date.now() });
2431
2471
  child.on("exit", async (code) => {
2432
2472
  const key = `idea-${idea.id}`;
@@ -2977,6 +3017,55 @@ ${divider}`);
2977
3017
  }
2978
3018
  dispatchScan(scan, prefix, key);
2979
3019
  }
3020
+ let reviewTasks = [];
3021
+ try {
3022
+ reviewTasks = await api.get("/api/tasks?status=review");
3023
+ } catch (err) {
3024
+ logError(watchTag(), `Failed to fetch review tasks: ${err.message}`);
3025
+ }
3026
+ for (const task of reviewTasks) {
3027
+ if (!task.link) continue;
3028
+ if (queued.has(task.id) || finishing.has(task.id) || active.has(task.id)) continue;
3029
+ const sid = shortId(task.id);
3030
+ const prefix = taskTag(sid);
3031
+ const prLabel = task.link.includes("gitlab") ? "MR" : "PR";
3032
+ const vcs = task.link.includes("gitlab") ? "gitlab" : "github";
3033
+ const repoDir = findDirectoryForProject(config, task.projectId, rootDir);
3034
+ if (!repoDir) continue;
3035
+ const status = await checkPrStatus(task.link, repoDir, vcs);
3036
+ if (!status) continue;
3037
+ if (status.merged) {
3038
+ logSuccess(prefix, `${prLabel} merged \u2014 auto-completing "${paint("bold", task.title)}"`);
3039
+ try {
3040
+ await api.patch(`/api/tasks/${task.id}`, {
3041
+ status: "completed",
3042
+ completedAt: (/* @__PURE__ */ new Date()).toISOString(),
3043
+ inProgressSince: null
3044
+ });
3045
+ await postTaskUpdate(task.id, `${prLabel} merged \u2014 task automatically completed`, "system");
3046
+ } catch (err) {
3047
+ logError(prefix, `Failed to auto-complete task: ${err.message}`);
3048
+ }
3049
+ continue;
3050
+ }
3051
+ if (status.hasConflicts) {
3052
+ logWarn(prefix, `${prLabel} has merge conflicts \u2014 re-dispatching agent for "${paint("bold", task.title)}"`);
3053
+ try {
3054
+ await api.patch(`/api/tasks/${task.id}`, { status: "queued" });
3055
+ await api.post(`/api/tasks/${task.id}/updates`, {
3056
+ message: `Your ${prLabel} has merge conflicts with the base branch. Please resolve the conflicts by rebasing or merging main into your branch, then push the updated branch.`,
3057
+ source: "user"
3058
+ });
3059
+ await postTaskUpdate(
3060
+ task.id,
3061
+ `${prLabel} has merge conflicts \u2014 re-dispatching agent to resolve`,
3062
+ "system"
3063
+ );
3064
+ } catch (err) {
3065
+ logError(prefix, `Failed to re-queue task for conflict resolution: ${err.message}`);
3066
+ }
3067
+ }
3068
+ }
2980
3069
  } finally {
2981
3070
  pollRunning = false;
2982
3071
  }
@@ -4167,105 +4256,8 @@ var noMrCommand = new Command22("no-mr").description("Signal that a task does no
4167
4256
  console.log(` Reason: ${description}`);
4168
4257
  });
4169
4258
 
4170
- // cli/commands/mobile.ts
4171
- import { Command as Command23 } from "commander";
4172
- function paint8(color, text) {
4173
- const colors = {
4174
- cyan: "\x1B[36m",
4175
- green: "\x1B[32m",
4176
- yellow: "\x1B[33m",
4177
- red: "\x1B[31m",
4178
- dim: "\x1B[2m",
4179
- reset: "\x1B[0m"
4180
- };
4181
- return `${colors[color] ?? ""}${text}${colors.reset}`;
4182
- }
4183
- var mobileCommand = new Command23("mobile").description(
4184
- "Start the Web-to-Mobile Conversion Wizard for the linked project"
4185
- ).argument("[project-id]", "Project ID (defaults to linked project)").option("--framework <framework>", "Framework: react-native or native").option("--url <url>", "Web app URL for analysis").action(
4186
- async (projectIdArg, opts) => {
4187
- const projectId = projectIdArg || getLinkedProjectId();
4188
- if (!projectId) {
4189
- console.error(
4190
- 'No project specified. Provide a project ID or run "mr link <project-id>" first.'
4191
- );
4192
- process.exit(1);
4193
- }
4194
- console.log(
4195
- paint8("cyan", "mobile") + paint8("dim", " \u2014 starting conversion wizard")
4196
- );
4197
- const task = await api.post("/api/tasks", {
4198
- title: "Convert to Mobile App",
4199
- projectId,
4200
- status: "in_progress"
4201
- });
4202
- console.log(` Created task: ${task.title} (${task.id})`);
4203
- console.log(" Analyzing web app...");
4204
- const analysis = await api.post("/api/wizard/mobile/analyze", {
4205
- projectId,
4206
- parentTaskId: task.id,
4207
- webAppUrl: opts.url
4208
- });
4209
- console.log(
4210
- ` Found ${analysis.analysis.screens.length} screens (${analysis.analysis.framework})`
4211
- );
4212
- if (opts.framework) {
4213
- console.log(
4214
- ` Generating architecture plan for ${opts.framework}...`
4215
- );
4216
- await api.post("/api/wizard/mobile/generate-plan", {
4217
- projectId,
4218
- parentTaskId: task.id,
4219
- framework: opts.framework,
4220
- analysisResourceId: analysis.resourceId
4221
- });
4222
- console.log(" Architecture plan created.");
4223
- }
4224
- console.log(
4225
- `
4226
- ${paint8("green", "\u2713")} Wizard initialized. Open the web UI to continue:
4227
- \u2192 Task ID: ${task.id}
4228
- \u2192 Use the "Convert to Mobile" button on the project page`
4229
- );
4230
- }
4231
- );
4232
- var statusSubcommand = new Command23("status").description("Show mobile conversion status for a task").argument("<task-id>", "Parent conversion task ID").action(async (taskId) => {
4233
- const resources = await api.get(
4234
- `/api/tasks/${taskId}/resources`
4235
- );
4236
- const wizardState = resources.find(
4237
- (r) => r.title === "Wizard State" && r.type === "plan"
4238
- );
4239
- if (!wizardState) {
4240
- console.log("No wizard state found for this task.");
4241
- return;
4242
- }
4243
- try {
4244
- const state = JSON.parse(wizardState.content);
4245
- console.log(paint8("cyan", "Mobile Conversion Status"));
4246
- console.log(` Phase: ${state.phase}`);
4247
- if (state.framework) {
4248
- console.log(` Framework: ${state.framework}`);
4249
- }
4250
- if (state.screenDesigns?.length) {
4251
- const completed = state.screenDesigns.filter(
4252
- (d) => d.status === "complete"
4253
- ).length;
4254
- console.log(
4255
- ` Screens: ${completed}/${state.screenDesigns.length} complete`
4256
- );
4257
- }
4258
- if (state.mobileRepoUrl) {
4259
- console.log(` Repo: ${state.mobileRepoUrl}`);
4260
- }
4261
- } catch {
4262
- console.log("Could not parse wizard state.");
4263
- }
4264
- });
4265
- mobileCommand.addCommand(statusSubcommand);
4266
-
4267
4259
  // cli/commands/scan.ts
4268
- import { Command as Command24 } from "commander";
4260
+ import { Command as Command23 } from "commander";
4269
4261
 
4270
4262
  // lib/scanner/index.ts
4271
4263
  import { spawn as spawn7 } from "child_process";
@@ -5014,25 +5006,25 @@ var c8 = {
5014
5006
  magenta: "\x1B[35m",
5015
5007
  gray: "\x1B[90m"
5016
5008
  };
5017
- function paint9(color, text) {
5009
+ function paint8(color, text) {
5018
5010
  return `${c8[color]}${text}${c8.reset}`;
5019
5011
  }
5020
5012
  function timestamp2() {
5021
- return paint9("gray", (/* @__PURE__ */ new Date()).toLocaleTimeString("en-US", { hour12: false }));
5013
+ return paint8("gray", (/* @__PURE__ */ new Date()).toLocaleTimeString("en-US", { hour12: false }));
5022
5014
  }
5023
5015
  function scanTag() {
5024
- return paint9("magenta", "[scan]");
5016
+ return paint8("magenta", "[scan]");
5025
5017
  }
5026
5018
  function log(msg) {
5027
5019
  console.log(`${timestamp2()} ${scanTag()} ${msg}`);
5028
5020
  }
5029
5021
  function logOk(msg) {
5030
- console.log(`${timestamp2()} ${scanTag()} ${paint9("green", "\u2713")} ${msg}`);
5022
+ console.log(`${timestamp2()} ${scanTag()} ${paint8("green", "\u2713")} ${msg}`);
5031
5023
  }
5032
5024
  function logErr(msg) {
5033
- console.error(`${timestamp2()} ${scanTag()} ${paint9("red", "\u2717")} ${msg}`);
5025
+ console.error(`${timestamp2()} ${scanTag()} ${paint8("red", "\u2717")} ${msg}`);
5034
5026
  }
5035
- var scanCommand = new Command24("scan").description("Run a product scan on the current project \u2014 analyzes codebase, crawls the app, and surfaces findings").option("--project <id>", "Project ID (defaults to linked project)").option("--report <id>", "Use an existing scan report ID (created by UI trigger)").option("--no-crawl", "Skip live crawl (codebase analysis only)").action(async (opts) => {
5027
+ var scanCommand = new Command23("scan").description("Run a product scan on the current project \u2014 analyzes codebase, crawls the app, and surfaces findings").option("--project <id>", "Project ID (defaults to linked project)").option("--report <id>", "Use an existing scan report ID (created by UI trigger)").option("--no-crawl", "Skip live crawl (codebase analysis only)").action(async (opts) => {
5036
5028
  const config = loadConfig();
5037
5029
  if (!config.apiKey) {
5038
5030
  logErr('Not authenticated. Run "mr login" first.');
@@ -5040,11 +5032,11 @@ var scanCommand = new Command24("scan").description("Run a product scan on the c
5040
5032
  }
5041
5033
  const banner = [
5042
5034
  ``,
5043
- paint9("magenta", ` \u2554\u2550\u2557\u2554\u2550\u2557\u2554\u2550\u2557\u2554\u2557\u2554`),
5044
- paint9("magenta", ` \u255A\u2550\u2557\u2551 \u2560\u2550\u2563\u2551\u2551\u2551`),
5045
- paint9("magenta", ` \u255A\u2550\u255D\u255A\u2550\u255D\u2569 \u2569\u255D\u255A\u255D`),
5046
- paint9("dim", ` \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500`),
5047
- paint9("dim", ` autonomous product scanner`),
5035
+ paint8("magenta", ` \u2554\u2550\u2557\u2554\u2550\u2557\u2554\u2550\u2557\u2554\u2557\u2554`),
5036
+ paint8("magenta", ` \u255A\u2550\u2557\u2551 \u2560\u2550\u2563\u2551\u2551\u2551`),
5037
+ paint8("magenta", ` \u255A\u2550\u255D\u255A\u2550\u255D\u2569 \u2569\u255D\u255A\u255D`),
5038
+ paint8("dim", ` \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500`),
5039
+ paint8("dim", ` autonomous product scanner`),
5048
5040
  ``
5049
5041
  ].join("\n");
5050
5042
  console.log(banner);
@@ -5060,7 +5052,7 @@ var scanCommand = new Command24("scan").description("Run a product scan on the c
5060
5052
  logErr(`Failed to fetch project ${projectId}`);
5061
5053
  process.exit(1);
5062
5054
  }
5063
- log(`Scanning project: ${paint9("cyan", project.name)}`);
5055
+ log(`Scanning project: ${paint8("cyan", project.name)}`);
5064
5056
  let projectPath = project.localPath;
5065
5057
  if (!projectPath) {
5066
5058
  for (const [dir, pid] of Object.entries(config.directories)) {
@@ -5076,7 +5068,7 @@ var scanCommand = new Command24("scan").description("Run a product scan on the c
5076
5068
  let reportId;
5077
5069
  if (opts.report) {
5078
5070
  reportId = opts.report;
5079
- log(`Using existing scan report ${paint9("yellow", reportId.slice(0, 8))}`);
5071
+ log(`Using existing scan report ${paint8("yellow", reportId.slice(0, 8))}`);
5080
5072
  } else {
5081
5073
  try {
5082
5074
  const scans = await api.get(`/api/scans?projectId=${projectId}&status=processing`);
@@ -5092,7 +5084,7 @@ var scanCommand = new Command24("scan").description("Run a product scan on the c
5092
5084
  status: "pending"
5093
5085
  });
5094
5086
  reportId = report.id;
5095
- log(`Created scan report ${paint9("yellow", reportId.slice(0, 8))}`);
5087
+ log(`Created scan report ${paint8("yellow", reportId.slice(0, 8))}`);
5096
5088
  } catch (err) {
5097
5089
  logErr(`Failed to create scan report: ${err.message}`);
5098
5090
  process.exit(1);
@@ -5105,7 +5097,7 @@ var scanCommand = new Command24("scan").description("Run a product scan on the c
5105
5097
  try {
5106
5098
  const current = await api.get(`/api/scans/${reportId}`);
5107
5099
  if (current.status === "cancelled") {
5108
- log(paint9("yellow", "Scan was cancelled \u2014 aborting."));
5100
+ log(paint8("yellow", "Scan was cancelled \u2014 aborting."));
5109
5101
  process.exit(0);
5110
5102
  }
5111
5103
  } catch {
@@ -5121,7 +5113,7 @@ var scanCommand = new Command24("scan").description("Run a product scan on the c
5121
5113
  runBrowse: runBrowseCommand2,
5122
5114
  onLog: log,
5123
5115
  onProgress: (phase, detail) => {
5124
- log(`${paint9("dim", `[${phase}]`)} ${detail}`);
5116
+ log(`${paint8("dim", `[${phase}]`)} ${detail}`);
5125
5117
  }
5126
5118
  });
5127
5119
  let wasCancelled = false;
@@ -5133,7 +5125,7 @@ var scanCommand = new Command24("scan").description("Run a product scan on the c
5133
5125
  } catch {
5134
5126
  }
5135
5127
  if (wasCancelled) {
5136
- log(paint9("yellow", "Scan was cancelled by user \u2014 discarding results."));
5128
+ log(paint8("yellow", "Scan was cancelled by user \u2014 discarding results."));
5137
5129
  process.exit(0);
5138
5130
  }
5139
5131
  await api.patch(`/api/scans/${reportId}`, {
@@ -5144,32 +5136,32 @@ var scanCommand = new Command24("scan").description("Run a product scan on the c
5144
5136
  scanDurationMs: result.scanDurationMs,
5145
5137
  routesCrawled: result.routesCrawled
5146
5138
  });
5147
- logOk(`Scan complete \u2014 ${paint9("cyan", String(result.findings.length))} findings`);
5139
+ logOk(`Scan complete \u2014 ${paint8("cyan", String(result.findings.length))} findings`);
5148
5140
  console.log("");
5149
- console.log(` ${paint9("bold", "Summary:")} ${result.summary}`);
5141
+ console.log(` ${paint8("bold", "Summary:")} ${result.summary}`);
5150
5142
  console.log("");
5151
5143
  const high = result.findings.filter((f) => f.priority === "high");
5152
5144
  const medium = result.findings.filter((f) => f.priority === "medium");
5153
5145
  const low = result.findings.filter((f) => f.priority === "low");
5154
5146
  if (high.length > 0) {
5155
- console.log(` ${paint9("bold", paint9("red", `High Priority (${high.length})`))}`);
5147
+ console.log(` ${paint8("bold", paint8("red", `High Priority (${high.length})`))}`);
5156
5148
  for (const f of high) {
5157
- console.log(` ${paint9("red", "\u25CF")} [${f.type}] ${f.title}`);
5158
- console.log(` ${paint9("dim", f.description.slice(0, 120))}`);
5149
+ console.log(` ${paint8("red", "\u25CF")} [${f.type}] ${f.title}`);
5150
+ console.log(` ${paint8("dim", f.description.slice(0, 120))}`);
5159
5151
  }
5160
5152
  console.log("");
5161
5153
  }
5162
5154
  if (medium.length > 0) {
5163
- console.log(` ${paint9("bold", paint9("yellow", `Medium Priority (${medium.length})`))}`);
5155
+ console.log(` ${paint8("bold", paint8("yellow", `Medium Priority (${medium.length})`))}`);
5164
5156
  for (const f of medium) {
5165
- console.log(` ${paint9("yellow", "\u25CF")} [${f.type}] ${f.title}`);
5157
+ console.log(` ${paint8("yellow", "\u25CF")} [${f.type}] ${f.title}`);
5166
5158
  }
5167
5159
  console.log("");
5168
5160
  }
5169
5161
  if (low.length > 0) {
5170
- console.log(` ${paint9("dim", `Low Priority (${low.length})`)} `);
5162
+ console.log(` ${paint8("dim", `Low Priority (${low.length})`)} `);
5171
5163
  for (const f of low) {
5172
- console.log(` ${paint9("dim", `\u25CB [${f.type}] ${f.title}`)}`);
5164
+ console.log(` ${paint8("dim", `\u25CB [${f.type}] ${f.title}`)}`);
5173
5165
  }
5174
5166
  console.log("");
5175
5167
  }
@@ -5187,7 +5179,7 @@ var scanCommand = new Command24("scan").description("Run a product scan on the c
5187
5179
  });
5188
5180
 
5189
5181
  // cli/commands/idea.ts
5190
- import { Command as Command25 } from "commander";
5182
+ import { Command as Command24 } from "commander";
5191
5183
  var c9 = {
5192
5184
  reset: "\x1B[0m",
5193
5185
  bold: "\x1B[1m",
@@ -5200,27 +5192,27 @@ var c9 = {
5200
5192
  gray: "\x1B[90m",
5201
5193
  magenta: "\x1B[35m"
5202
5194
  };
5203
- function paint10(color, text) {
5195
+ function paint9(color, text) {
5204
5196
  return `${c9[color]}${text}${c9.reset}`;
5205
5197
  }
5206
5198
  function statusBadge2(status) {
5207
5199
  switch (status) {
5208
5200
  case "draft":
5209
- return paint10("gray", "\u25CB draft");
5201
+ return paint9("gray", "\u25CB draft");
5210
5202
  case "generating":
5211
- return paint10("cyan", "\u27F3 generating");
5203
+ return paint9("cyan", "\u27F3 generating");
5212
5204
  case "generated":
5213
- return paint10("green", "\u2713 generated");
5205
+ return paint9("green", "\u2713 generated");
5214
5206
  case "promoted":
5215
- return paint10("magenta", "\u2191 promoted");
5207
+ return paint9("magenta", "\u2191 promoted");
5216
5208
  case "archived":
5217
- return paint10("dim", "\u2298 archived");
5209
+ return paint9("dim", "\u2298 archived");
5218
5210
  default:
5219
- return paint10("gray", status);
5211
+ return paint9("gray", status);
5220
5212
  }
5221
5213
  }
5222
- var ideaCommand = new Command25("idea").description("Manage ideas \u2014 brainstorm, generate prototypes & plans").addCommand(
5223
- new Command25("list").description("List ideas for the linked project").option("--all", "Show ideas for all projects").option("--status <status>", "Filter by status").action(async (opts) => {
5214
+ var ideaCommand = new Command24("idea").description("Manage ideas \u2014 brainstorm, generate prototypes & plans").addCommand(
5215
+ 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) => {
5224
5216
  const params = new URLSearchParams();
5225
5217
  if (!opts.all) {
5226
5218
  const projectId = getLinkedProjectId();
@@ -5231,23 +5223,23 @@ var ideaCommand = new Command25("idea").description("Manage ideas \u2014 brainst
5231
5223
  if (opts.status) params.set("status", opts.status);
5232
5224
  const ideas = await api.get(`/api/ideas?${params.toString()}`);
5233
5225
  if (ideas.length === 0) {
5234
- console.log(paint10("gray", "No ideas found."));
5226
+ console.log(paint9("gray", "No ideas found."));
5235
5227
  return;
5236
5228
  }
5237
5229
  console.log();
5238
5230
  for (const idea of ideas) {
5239
5231
  const date = new Date(idea.createdAt).toLocaleDateString();
5240
5232
  console.log(
5241
- ` ${paint10("bold", idea.title)} ${statusBadge2(idea.status)} ${paint10("gray", idea.id.slice(0, 8))} ${paint10("dim", date)}`
5233
+ ` ${paint9("bold", idea.title)} ${statusBadge2(idea.status)} ${paint9("gray", idea.id.slice(0, 8))} ${paint9("dim", date)}`
5242
5234
  );
5243
5235
  if (idea.description) {
5244
- console.log(` ${paint10("dim", idea.description.slice(0, 80) + (idea.description.length > 80 ? "\u2026" : ""))}`);
5236
+ console.log(` ${paint9("dim", idea.description.slice(0, 80) + (idea.description.length > 80 ? "\u2026" : ""))}`);
5245
5237
  }
5246
5238
  console.log();
5247
5239
  }
5248
5240
  })
5249
5241
  ).addCommand(
5250
- new Command25("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) => {
5242
+ 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) => {
5251
5243
  const projectId = opts.project ?? getLinkedProjectId() ?? null;
5252
5244
  const idea = await api.post("/api/ideas", {
5253
5245
  title,
@@ -5255,59 +5247,59 @@ var ideaCommand = new Command25("idea").description("Manage ideas \u2014 brainst
5255
5247
  projectId
5256
5248
  });
5257
5249
  console.log();
5258
- console.log(` ${paint10("green", "\u2713")} Created idea: ${paint10("bold", idea.title)}`);
5259
- console.log(` ${paint10("gray", "ID:")} ${idea.id}`);
5250
+ console.log(` ${paint9("green", "\u2713")} Created idea: ${paint9("bold", idea.title)}`);
5251
+ console.log(` ${paint9("gray", "ID:")} ${idea.id}`);
5260
5252
  if (opts.generate) {
5261
5253
  await api.post(`/api/ideas/${idea.id}/generate`);
5262
- console.log(` ${paint10("cyan", "\u27F3")} Generation will begin automatically via the watch agent.`);
5254
+ console.log(` ${paint9("cyan", "\u27F3")} Generation will begin automatically via the watch agent.`);
5263
5255
  }
5264
5256
  console.log();
5265
5257
  })
5266
5258
  ).addCommand(
5267
- new Command25("generate").description("Start generating plan & prototype for an idea").argument("<id>", "Idea ID").action(async (id) => {
5259
+ new Command24("generate").description("Start generating plan & prototype for an idea").argument("<id>", "Idea ID").action(async (id) => {
5268
5260
  const idea = await api.post(`/api/ideas/${id}/generate`);
5269
5261
  console.log();
5270
- console.log(` ${paint10("cyan", "\u27F3")} Generating: ${paint10("bold", idea.title)}`);
5271
- console.log(` ${paint10("gray", "The watch agent will pick this up shortly.")}`);
5262
+ console.log(` ${paint9("cyan", "\u27F3")} Generating: ${paint9("bold", idea.title)}`);
5263
+ console.log(` ${paint9("gray", "The watch agent will pick this up shortly.")}`);
5272
5264
  console.log();
5273
5265
  })
5274
5266
  ).addCommand(
5275
- new Command25("feedback").description("Send feedback to iterate on an idea's generated content").argument("<id>", "Idea ID").argument("<feedback>", "Feedback text").action(async (id, feedback) => {
5267
+ 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) => {
5276
5268
  const idea = await api.post(`/api/ideas/${id}/feedback`, { feedback });
5277
5269
  console.log();
5278
- console.log(` ${paint10("cyan", "\u27F3")} Feedback sent for: ${paint10("bold", idea.title)}`);
5279
- console.log(` ${paint10("gray", "The watch agent will re-generate with your feedback.")}`);
5270
+ console.log(` ${paint9("cyan", "\u27F3")} Feedback sent for: ${paint9("bold", idea.title)}`);
5271
+ console.log(` ${paint9("gray", "The watch agent will re-generate with your feedback.")}`);
5280
5272
  console.log();
5281
5273
  })
5282
5274
  ).addCommand(
5283
- new Command25("promote").description("Promote an idea to a task").argument("<id>", "Idea ID").action(async (id) => {
5275
+ new Command24("promote").description("Promote an idea to a task").argument("<id>", "Idea ID").action(async (id) => {
5284
5276
  const result = await api.post(`/api/ideas/${id}/promote`);
5285
5277
  console.log();
5286
- console.log(` ${paint10("green", "\u2713")} Promoted idea to task: ${paint10("bold", result.task.title)}`);
5287
- console.log(` ${paint10("gray", "Task ID:")} ${result.task.id}`);
5278
+ console.log(` ${paint9("green", "\u2713")} Promoted idea to task: ${paint9("bold", result.task.title)}`);
5279
+ console.log(` ${paint9("gray", "Task ID:")} ${result.task.id}`);
5288
5280
  console.log();
5289
5281
  })
5290
5282
  ).addCommand(
5291
- new Command25("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) => {
5283
+ 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) => {
5292
5284
  const body = {};
5293
5285
  if (opts.name) body.name = opts.name;
5294
5286
  const result = await api.post(`/api/ideas/${id}/spin-up`, body);
5295
5287
  console.log();
5296
- console.log(` ${paint10("green", "\u2713")} Spinning up project: ${paint10("bold", result.project.name)}`);
5297
- console.log(` ${paint10("gray", "Project ID:")} ${result.project.id}`);
5288
+ console.log(` ${paint9("green", "\u2713")} Spinning up project: ${paint9("bold", result.project.name)}`);
5289
+ console.log(` ${paint9("gray", "Project ID:")} ${result.project.id}`);
5298
5290
  if (result.tasks && result.tasks.length > 0) {
5299
- console.log(` ${paint10("green", "\u2713")} Created ${result.tasks.length} follow-up task(s):`);
5291
+ console.log(` ${paint9("green", "\u2713")} Created ${result.tasks.length} follow-up task(s):`);
5300
5292
  for (const task of result.tasks) {
5301
- console.log(` ${paint10("gray", "\u2022")} ${task.title}`);
5293
+ console.log(` ${paint9("gray", "\u2022")} ${task.title}`);
5302
5294
  }
5303
5295
  }
5304
- console.log(` ${paint10("cyan", "\u27F3")} Repo creation is queued \u2014 the watch daemon will pick it up.`);
5296
+ console.log(` ${paint9("cyan", "\u27F3")} Repo creation is queued \u2014 the watch daemon will pick it up.`);
5305
5297
  console.log();
5306
5298
  })
5307
5299
  );
5308
5300
 
5309
5301
  // cli/commands/doctor.ts
5310
- import { Command as Command26 } from "commander";
5302
+ import { Command as Command25 } from "commander";
5311
5303
  import { existsSync as existsSync15 } from "fs";
5312
5304
  import { homedir as homedir2 } from "os";
5313
5305
  import { join as join11 } from "path";
@@ -5355,7 +5347,7 @@ async function checkProjectLink() {
5355
5347
  optional: true
5356
5348
  };
5357
5349
  }
5358
- var doctorCommand = new Command26("doctor").description("Diagnose Mr. Manager CLI installation and environment").action(async () => {
5350
+ var doctorCommand = new Command25("doctor").description("Diagnose Mr. Manager CLI installation and environment").action(async () => {
5359
5351
  const banner = [
5360
5352
  ``,
5361
5353
  paint5("cyan", ` MR DOCTOR`),
@@ -5435,7 +5427,7 @@ if (isFirstRun && !shouldBypass) {
5435
5427
  console.log("");
5436
5428
  process.exit(0);
5437
5429
  }
5438
- var program = new Command27();
5430
+ var program = new Command26();
5439
5431
  program.name("mr").description("Mr. Manager - Task and project management CLI").version(CLI_VERSION);
5440
5432
  program.addCommand(initCommand);
5441
5433
  program.addCommand(authCommand);
@@ -5462,7 +5454,6 @@ program.addCommand(setPathCommand);
5462
5454
  program.addCommand(testCommand);
5463
5455
  program.addCommand(featuresCommand);
5464
5456
  program.addCommand(noMrCommand);
5465
- program.addCommand(mobileCommand);
5466
5457
  program.addCommand(scanCommand);
5467
5458
  program.addCommand(ideaCommand);
5468
5459
  program.addCommand(doctorCommand);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dunnewold-labs/mr-manager",
3
- "version": "0.4.4",
3
+ "version": "0.4.7",
4
4
  "description": "Mr. Manager - Task and project management CLI",
5
5
  "bin": {
6
6
  "mr": "./dist/index.mjs"