@dunnewold-labs/mr-manager 0.4.55 → 0.4.56
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/index.mjs +392 -157
- 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
|
|
4
|
+
import { Command as Command37 } from "commander";
|
|
5
5
|
import { existsSync as existsSync19 } 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.
|
|
188
|
+
version: "0.4.56",
|
|
189
189
|
description: "Mr. Manager - Task and project management CLI",
|
|
190
190
|
bin: {
|
|
191
191
|
mr: "./dist/index.mjs"
|
|
@@ -1415,6 +1415,22 @@ function tokenLogLine(jobType, identifier, prompt2, systemPrompt) {
|
|
|
1415
1415
|
return parts[0];
|
|
1416
1416
|
}
|
|
1417
1417
|
|
|
1418
|
+
// cli/watch-options.ts
|
|
1419
|
+
var EXECUTION_SYSTEM_SECTIONS = [
|
|
1420
|
+
"status-updates",
|
|
1421
|
+
"screenshots",
|
|
1422
|
+
"no-mr",
|
|
1423
|
+
"features-workflow"
|
|
1424
|
+
];
|
|
1425
|
+
var TEST_PLAN_SYSTEM_SECTIONS = ["test-plan", "mr-tests"];
|
|
1426
|
+
function getExecutionSystemSections(includeTestPlan) {
|
|
1427
|
+
return [
|
|
1428
|
+
"quiet-mode",
|
|
1429
|
+
...EXECUTION_SYSTEM_SECTIONS,
|
|
1430
|
+
...includeTestPlan ? TEST_PLAN_SYSTEM_SECTIONS : []
|
|
1431
|
+
];
|
|
1432
|
+
}
|
|
1433
|
+
|
|
1418
1434
|
// cli/commands/watch.ts
|
|
1419
1435
|
var FEATURES_FILE2 = ".mr-features.md";
|
|
1420
1436
|
var SYSTEM_SECTION_STATUS_UPDATES = `## Status Updates
|
|
@@ -1561,7 +1577,6 @@ var SYSTEM_SECTIONS = {
|
|
|
1561
1577
|
function composeSystemPrompt(sections) {
|
|
1562
1578
|
return sections.map((s) => SYSTEM_SECTIONS[s]).join("\n\n");
|
|
1563
1579
|
}
|
|
1564
|
-
var EXECUTION_SYSTEM_SECTIONS = ["status-updates", "screenshots", "test-plan", "mr-tests", "no-mr", "features-workflow"];
|
|
1565
1580
|
var PRD_SYSTEM_SECTIONS = ["prd-format", "prd-open-questions"];
|
|
1566
1581
|
var c = {
|
|
1567
1582
|
reset: "\x1B[0m",
|
|
@@ -3123,13 +3138,14 @@ function spawnAgent(agent, repoDir, prompt2, prefix, onActivity, sessionId, name
|
|
|
3123
3138
|
}
|
|
3124
3139
|
var watchCommand = new Command9("watch").description(
|
|
3125
3140
|
"Watch for in-progress tasks and autonomously dispatch an AI coding agent to work on them"
|
|
3126
|
-
).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 antigravity", "claude").option("--scan-at <HH:MM>", "Run a product scan daily at this time (e.g., 02:00)").action(async (opts) => {
|
|
3141
|
+
).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 antigravity", "claude").option("--scan-at <HH:MM>", "Run a product scan daily at this time (e.g., 02:00)").option("--test-plan", "Ask build agents to create a structured browser test plan", false).action(async (opts) => {
|
|
3127
3142
|
const intervalMs = parseInt(opts.interval, 10) * 1e3;
|
|
3128
3143
|
const dryRun = opts.dryRun;
|
|
3129
3144
|
const planApproval = opts.planApproval;
|
|
3130
3145
|
const rootDir = opts.root ? resolve2(opts.root) : process.cwd();
|
|
3131
3146
|
const agent = opts.agent === "codex" ? "codex" : opts.agent === "antigravity" ? "antigravity" : "claude";
|
|
3132
3147
|
const scanAt = opts.scanAt;
|
|
3148
|
+
const includeTestPlan = opts.testPlan;
|
|
3133
3149
|
const taskStallTimeoutMs = getTaskStallTimeoutMs();
|
|
3134
3150
|
const hungTaskTimeoutMinutes = Math.max(5, parseInt(process.env.MR_WATCH_HUNG_TASK_TIMEOUT_MINUTES ?? "60", 10) || 60);
|
|
3135
3151
|
const hungTaskTimeoutMs = hungTaskTimeoutMinutes * 6e4;
|
|
@@ -3151,6 +3167,7 @@ var watchCommand = new Command9("watch").description(
|
|
|
3151
3167
|
...planApproval ? [paint("yellow", "plan-approval")] : [],
|
|
3152
3168
|
...dryRun ? [paint("yellow", "dry-run")] : [],
|
|
3153
3169
|
...scanAt ? [`scan-at=${paint("cyan", scanAt)}`] : [],
|
|
3170
|
+
...includeTestPlan ? [paint("yellow", "test-plan")] : [],
|
|
3154
3171
|
`hung-timeout=${paint("cyan", `${hungTaskTimeoutMinutes}m`)}`
|
|
3155
3172
|
].join(" ");
|
|
3156
3173
|
const banner = [
|
|
@@ -3385,7 +3402,7 @@ var watchCommand = new Command9("watch").description(
|
|
|
3385
3402
|
const shouldResumeClaudeSession = attemptAgent === "claude" && !!task.claudeSessionId && !resumeAlreadyRetried && (hasFeedback || pausedForNetwork?.resumeSession === true);
|
|
3386
3403
|
const sessionId = attemptAgent === "claude" ? shouldResumeClaudeSession ? task.claudeSessionId : randomUUID() : void 0;
|
|
3387
3404
|
const effectiveClaudeModel = attemptAgent === "claude" ? taskClaudeModel : void 0;
|
|
3388
|
-
const systemSections =
|
|
3405
|
+
const systemSections = getExecutionSystemSections(includeTestPlan);
|
|
3389
3406
|
const executionSystemPrompt = composeSystemPrompt(systemSections);
|
|
3390
3407
|
const child = spawnAgent(
|
|
3391
3408
|
attemptAgent,
|
|
@@ -4143,6 +4160,7 @@ var watchCommand = new Command9("watch").description(
|
|
|
4143
4160
|
function dispatchCodeReview(review, prefix, key) {
|
|
4144
4161
|
logDispatch(prefix, `Running code review on branch ${paint("cyan", review.branch)}`);
|
|
4145
4162
|
const reviewArgs = [process.argv[1], "review", "--project", review.projectId, "--report", review.id, "--branch", review.branch, "--base", review.baseBranch];
|
|
4163
|
+
if (review.depth) reviewArgs.push("--depth", review.depth);
|
|
4146
4164
|
if (review.branchUrl) reviewArgs.push("--pr-url", review.branchUrl);
|
|
4147
4165
|
if (review.prNumber != null) reviewArgs.push("--pr-number", String(review.prNumber));
|
|
4148
4166
|
const reviewProc = spawn4(process.execPath, reviewArgs, {
|
|
@@ -4980,9 +4998,125 @@ var completeCommand = new Command12("complete").description("Mark a task as comp
|
|
|
4980
4998
|
printTaskBanner2(paint3("green", "complete \u2713"), task.title, task.id);
|
|
4981
4999
|
});
|
|
4982
5000
|
|
|
4983
|
-
// cli/commands/
|
|
5001
|
+
// cli/commands/show.ts
|
|
4984
5002
|
import { Command as Command13 } from "commander";
|
|
4985
|
-
var
|
|
5003
|
+
var showCommand = new Command13("show").description("Show a single task").argument("<task-id>", "Task ID to show").option("--json", "Output raw JSON").option(
|
|
5004
|
+
"--include <fields>",
|
|
5005
|
+
"Comma-separated relations to include (e.g. project,resources)"
|
|
5006
|
+
).action(async (taskId, opts) => {
|
|
5007
|
+
let path = `/api/tasks/${taskId}`;
|
|
5008
|
+
if (opts.include) {
|
|
5009
|
+
path += `?include=${encodeURIComponent(opts.include)}`;
|
|
5010
|
+
}
|
|
5011
|
+
const task = await api.get(path);
|
|
5012
|
+
if (opts.json) {
|
|
5013
|
+
console.log(JSON.stringify(task, null, 2));
|
|
5014
|
+
return;
|
|
5015
|
+
}
|
|
5016
|
+
const c15 = {
|
|
5017
|
+
reset: "\x1B[0m",
|
|
5018
|
+
bold: "\x1B[1m",
|
|
5019
|
+
dim: "\x1B[2m",
|
|
5020
|
+
cyan: "\x1B[36m"
|
|
5021
|
+
};
|
|
5022
|
+
const row = (label, value) => {
|
|
5023
|
+
if (value == null || value === "") return;
|
|
5024
|
+
console.log(`${c15.dim}${label.padEnd(14)}${c15.reset}${value}`);
|
|
5025
|
+
};
|
|
5026
|
+
console.log(`${c15.bold}${c15.cyan}${task.title}${c15.reset} ${c15.dim}(${task.id})${c15.reset}`);
|
|
5027
|
+
row("Status", task.status);
|
|
5028
|
+
row("Mode", task.mode);
|
|
5029
|
+
row("Project", task.projectId);
|
|
5030
|
+
row("Due", task.dueDate);
|
|
5031
|
+
row("Jira", task.jiraTicketKey);
|
|
5032
|
+
row("Branch", task.attachedBranch);
|
|
5033
|
+
row("Link", task.link ?? task.attachedBranchLink);
|
|
5034
|
+
row("Auto-merge", task.autoMergeEnabled ? "enabled" : void 0);
|
|
5035
|
+
row("Created", task.createdAt);
|
|
5036
|
+
row("Completed", task.completedAt);
|
|
5037
|
+
if (task.notes) {
|
|
5038
|
+
console.log(`${c15.dim}Notes${c15.reset}`);
|
|
5039
|
+
console.log(task.notes);
|
|
5040
|
+
}
|
|
5041
|
+
});
|
|
5042
|
+
|
|
5043
|
+
// cli/commands/edit.ts
|
|
5044
|
+
import { Command as Command14 } from "commander";
|
|
5045
|
+
var VALID_STATUSES = [
|
|
5046
|
+
"todo",
|
|
5047
|
+
"in_progress",
|
|
5048
|
+
"queued",
|
|
5049
|
+
"delegated",
|
|
5050
|
+
"review",
|
|
5051
|
+
"completed",
|
|
5052
|
+
"error"
|
|
5053
|
+
];
|
|
5054
|
+
var VALID_MODES = ["development", "planning", "testing"];
|
|
5055
|
+
var editCommand = new Command14("edit").description("Update fields on an existing task").argument("<task-id>", "Task ID to update").option("--title <title>", "New task title").option("--notes <notes>", "New task notes").option("--status <status>", `New status (${VALID_STATUSES.join(", ")})`).option("--mode <mode>", `New mode (${VALID_MODES.join(", ")})`).option("--due-date <date>", "Due date (ISO string), or 'none' to clear").option("--link <url>", "Task link, or 'none' to clear").option("--jira <key>", "Jira ticket key, or 'none' to clear").option("--branch <input>", "Attached branch name or PR/MR URL, or 'none' to clear").option("--auto-merge <bool>", "Enable/disable auto-merge (true/false)").action(async (taskId, opts) => {
|
|
5056
|
+
const body = {};
|
|
5057
|
+
if (opts.title != null) body.title = opts.title;
|
|
5058
|
+
if (opts.notes != null) body.notes = opts.notes;
|
|
5059
|
+
if (opts.status != null) {
|
|
5060
|
+
if (!VALID_STATUSES.includes(opts.status)) {
|
|
5061
|
+
console.error(`Invalid status. Must be one of: ${VALID_STATUSES.join(", ")}`);
|
|
5062
|
+
process.exit(1);
|
|
5063
|
+
}
|
|
5064
|
+
body.status = opts.status;
|
|
5065
|
+
}
|
|
5066
|
+
if (opts.mode != null) {
|
|
5067
|
+
if (!VALID_MODES.includes(opts.mode)) {
|
|
5068
|
+
console.error(`Invalid mode. Must be one of: ${VALID_MODES.join(", ")}`);
|
|
5069
|
+
process.exit(1);
|
|
5070
|
+
}
|
|
5071
|
+
body.mode = opts.mode;
|
|
5072
|
+
}
|
|
5073
|
+
const clearable = (v) => v.toLowerCase() === "none" ? null : v;
|
|
5074
|
+
if (opts.dueDate != null) body.dueDate = clearable(opts.dueDate);
|
|
5075
|
+
if (opts.link != null) body.link = clearable(opts.link);
|
|
5076
|
+
if (opts.jira != null) body.jiraTicketKey = clearable(opts.jira);
|
|
5077
|
+
if (opts.branch != null) body.attachedBranchInput = clearable(opts.branch) ?? "";
|
|
5078
|
+
if (opts.autoMerge != null) body.autoMergeEnabled = opts.autoMerge === "true";
|
|
5079
|
+
if (Object.keys(body).length === 0) {
|
|
5080
|
+
console.error("No fields to update. Pass at least one option (e.g. --title, --status).");
|
|
5081
|
+
process.exit(1);
|
|
5082
|
+
}
|
|
5083
|
+
const task = await api.patch(`/api/tasks/${taskId}`, body);
|
|
5084
|
+
console.log(`\u2713 Updated: ${task.title} (${task.id})`);
|
|
5085
|
+
});
|
|
5086
|
+
|
|
5087
|
+
// cli/commands/delete.ts
|
|
5088
|
+
import { Command as Command15 } from "commander";
|
|
5089
|
+
import { createInterface as createInterface3 } from "readline/promises";
|
|
5090
|
+
var c4 = {
|
|
5091
|
+
reset: "\x1B[0m",
|
|
5092
|
+
bold: "\x1B[1m",
|
|
5093
|
+
dim: "\x1B[2m"
|
|
5094
|
+
};
|
|
5095
|
+
var deleteCommand = new Command15("delete").description("Delete a task").argument("<task-id>", "Task ID to delete").option("-y, --yes", "Skip the confirmation prompt").action(async (taskId, opts) => {
|
|
5096
|
+
let title = taskId;
|
|
5097
|
+
try {
|
|
5098
|
+
const task = await api.get(`/api/tasks/${taskId}`);
|
|
5099
|
+
if (task?.title) title = task.title;
|
|
5100
|
+
} catch {
|
|
5101
|
+
}
|
|
5102
|
+
if (!opts.yes) {
|
|
5103
|
+
const rl = createInterface3({ input: process.stdin, output: process.stdout });
|
|
5104
|
+
const answer = (await rl.question(
|
|
5105
|
+
`Delete task ${c4.bold}${title}${c4.reset} ${c4.dim}(${taskId})${c4.reset}? [y/N] `
|
|
5106
|
+
)).trim().toLowerCase();
|
|
5107
|
+
rl.close();
|
|
5108
|
+
if (answer !== "y" && answer !== "yes") {
|
|
5109
|
+
console.log("Aborted.");
|
|
5110
|
+
return;
|
|
5111
|
+
}
|
|
5112
|
+
}
|
|
5113
|
+
await api.del(`/api/tasks/${taskId}`);
|
|
5114
|
+
console.log(`\u2713 Deleted task ${title} (${taskId})`);
|
|
5115
|
+
});
|
|
5116
|
+
|
|
5117
|
+
// cli/commands/subtask-complete.ts
|
|
5118
|
+
import { Command as Command16 } from "commander";
|
|
5119
|
+
var subtaskCompleteCommand = new Command16("subtask-complete").description("Mark a subtask as completed").argument("<task-id>", "Parent task ID").argument("<subtask-id>", "Subtask ID to complete").action(async (taskId, subtaskId) => {
|
|
4986
5120
|
const subtask = await api.patch(
|
|
4987
5121
|
`/api/tasks/${taskId}/subtasks/${subtaskId}`,
|
|
4988
5122
|
{ completed: true }
|
|
@@ -4991,8 +5125,8 @@ var subtaskCompleteCommand = new Command13("subtask-complete").description("Mark
|
|
|
4991
5125
|
});
|
|
4992
5126
|
|
|
4993
5127
|
// cli/commands/subtask-add.ts
|
|
4994
|
-
import { Command as
|
|
4995
|
-
var subtaskAddCommand = new
|
|
5128
|
+
import { Command as Command17 } from "commander";
|
|
5129
|
+
var subtaskAddCommand = new Command17("subtask-add").description("Add a subtask to a task (used by the agent to plan work as it starts)").argument("<task-id>", "Parent task ID").argument("<title...>", "Subtask title").action(async (taskId, titleParts) => {
|
|
4996
5130
|
const title = titleParts.join(" ").trim();
|
|
4997
5131
|
if (!title) {
|
|
4998
5132
|
console.error("Subtask title is required.");
|
|
@@ -5005,8 +5139,8 @@ var subtaskAddCommand = new Command14("subtask-add").description("Add a subtask
|
|
|
5005
5139
|
});
|
|
5006
5140
|
|
|
5007
5141
|
// cli/commands/prototype.ts
|
|
5008
|
-
import { Command as
|
|
5009
|
-
var
|
|
5142
|
+
import { Command as Command18 } from "commander";
|
|
5143
|
+
var c5 = {
|
|
5010
5144
|
reset: "\x1B[0m",
|
|
5011
5145
|
bold: "\x1B[1m",
|
|
5012
5146
|
dim: "\x1B[2m",
|
|
@@ -5018,7 +5152,7 @@ var c4 = {
|
|
|
5018
5152
|
gray: "\x1B[90m"
|
|
5019
5153
|
};
|
|
5020
5154
|
function paint4(color, text) {
|
|
5021
|
-
return `${
|
|
5155
|
+
return `${c5[color]}${text}${c5.reset}`;
|
|
5022
5156
|
}
|
|
5023
5157
|
function statusBadge(status) {
|
|
5024
5158
|
switch (status) {
|
|
@@ -5034,8 +5168,8 @@ function statusBadge(status) {
|
|
|
5034
5168
|
return paint4("gray", status);
|
|
5035
5169
|
}
|
|
5036
5170
|
}
|
|
5037
|
-
var prototypeCommand = new
|
|
5038
|
-
new
|
|
5171
|
+
var prototypeCommand = new Command18("prototype").description("Manage prototypes").addCommand(
|
|
5172
|
+
new Command18("list").description("List prototypes for the linked project").option("--all", "Show prototypes for all projects").action(async (opts) => {
|
|
5039
5173
|
const params = new URLSearchParams();
|
|
5040
5174
|
if (!opts.all) {
|
|
5041
5175
|
const projectId = getLinkedProjectId();
|
|
@@ -5069,7 +5203,7 @@ var prototypeCommand = new Command15("prototype").description("Manage prototypes
|
|
|
5069
5203
|
}
|
|
5070
5204
|
})
|
|
5071
5205
|
).addCommand(
|
|
5072
|
-
new
|
|
5206
|
+
new Command18("create").description("Create a new prototype").argument("<title>", "Title of the prototype").requiredOption("--prompt <prompt>", "Design description / prompt").option("--project <projectId>", "Project ID (defaults to linked project, when available)").option("--variants <count>", "Number of variants to generate (1-50)", "5").option("--type <type>", "Prototype type: web_app, mobile_app, desktop_app, logo (default: web_app)", "web_app").option("--fidelity <fidelity>", "Fidelity level: low, high (default: high)", "high").action(async (title, opts) => {
|
|
5073
5207
|
const projectId = opts.project ?? getLinkedProjectId();
|
|
5074
5208
|
const variantCount = Math.max(1, Math.min(50, parseInt(opts.variants, 10) || 5));
|
|
5075
5209
|
const validTypes = ["web_app", "mobile_app", "desktop_app", "logo"];
|
|
@@ -5110,7 +5244,7 @@ var prototypeCommand = new Command15("prototype").description("Manage prototypes
|
|
|
5110
5244
|
console.log();
|
|
5111
5245
|
})
|
|
5112
5246
|
).addCommand(
|
|
5113
|
-
new
|
|
5247
|
+
new Command18("start").description("Start prototype generation (sets status to in_progress)").argument("<id>", "Prototype ID").action(async (id) => {
|
|
5114
5248
|
const prototype = await api.patch(`/api/prototypes/${id}`, {
|
|
5115
5249
|
status: "in_progress"
|
|
5116
5250
|
});
|
|
@@ -5120,7 +5254,7 @@ var prototypeCommand = new Command15("prototype").description("Manage prototypes
|
|
|
5120
5254
|
console.log();
|
|
5121
5255
|
})
|
|
5122
5256
|
).addCommand(
|
|
5123
|
-
new
|
|
5257
|
+
new Command18("retry").description("Retry a failed prototype").argument("<id>", "Prototype ID").action(async (id) => {
|
|
5124
5258
|
const prototype = await api.patch(`/api/prototypes/${id}`, {
|
|
5125
5259
|
status: "in_progress",
|
|
5126
5260
|
files: null
|
|
@@ -5132,9 +5266,9 @@ var prototypeCommand = new Command15("prototype").description("Manage prototypes
|
|
|
5132
5266
|
);
|
|
5133
5267
|
|
|
5134
5268
|
// cli/commands/setup.ts
|
|
5135
|
-
import { Command as
|
|
5269
|
+
import { Command as Command19 } from "commander";
|
|
5136
5270
|
import { exec as exec2 } from "child_process";
|
|
5137
|
-
var
|
|
5271
|
+
var c6 = {
|
|
5138
5272
|
reset: "\x1B[0m",
|
|
5139
5273
|
bold: "\x1B[1m",
|
|
5140
5274
|
dim: "\x1B[2m",
|
|
@@ -5146,7 +5280,7 @@ var c5 = {
|
|
|
5146
5280
|
gray: "\x1B[90m"
|
|
5147
5281
|
};
|
|
5148
5282
|
function paint5(color, text) {
|
|
5149
|
-
return `${
|
|
5283
|
+
return `${c6[color]}${text}${c6.reset}`;
|
|
5150
5284
|
}
|
|
5151
5285
|
function commandExists2(cmd) {
|
|
5152
5286
|
return new Promise((resolve9) => {
|
|
@@ -5390,7 +5524,7 @@ async function checkApiConnectivity() {
|
|
|
5390
5524
|
}
|
|
5391
5525
|
}
|
|
5392
5526
|
function printResults(checks) {
|
|
5393
|
-
const maxNameLen = Math.max(...checks.map((
|
|
5527
|
+
const maxNameLen = Math.max(...checks.map((c15) => c15.name.length));
|
|
5394
5528
|
let allOk = true;
|
|
5395
5529
|
for (const check of checks) {
|
|
5396
5530
|
const isOptional = check.optional ?? false;
|
|
@@ -5404,10 +5538,10 @@ function printResults(checks) {
|
|
|
5404
5538
|
}
|
|
5405
5539
|
async function autoFix(checks, agent) {
|
|
5406
5540
|
const { spawn: spawn9 } = await import("child_process");
|
|
5407
|
-
const ghInstalled = checks.find((
|
|
5408
|
-
const ghAuthed = checks.find((
|
|
5409
|
-
const mrAuthed = checks.find((
|
|
5410
|
-
const claudeCheck = checks.find((
|
|
5541
|
+
const ghInstalled = checks.find((c15) => c15.name === "GitHub CLI (gh)").ok;
|
|
5542
|
+
const ghAuthed = checks.find((c15) => c15.name === "GitHub CLI auth").ok;
|
|
5543
|
+
const mrAuthed = checks.find((c15) => c15.name === "Mr. Manager CLI auth").ok;
|
|
5544
|
+
const claudeCheck = checks.find((c15) => c15.name === "Claude Code (claude)");
|
|
5411
5545
|
if (claudeCheck && !claudeCheck.ok && agent === "claude") {
|
|
5412
5546
|
console.log(paint5("cyan", " Installing Claude Code..."));
|
|
5413
5547
|
console.log(paint5("dim", " Running: curl -fsSL https://claude.ai/install.sh | bash"));
|
|
@@ -5435,7 +5569,7 @@ async function autoFix(checks, agent) {
|
|
|
5435
5569
|
console.log("");
|
|
5436
5570
|
}
|
|
5437
5571
|
}
|
|
5438
|
-
var setupCommand = new
|
|
5572
|
+
var setupCommand = new Command19("setup").description("Check that all dependencies for mr watch are installed and configured").option("--fix", "Attempt to auto-fix issues where possible", false).option("--agent <agent>", "AI agent to check: claude, codex, or antigravity (default: claude)", "claude").action(async (opts) => {
|
|
5439
5573
|
const agent = opts.agent === "codex" ? "codex" : opts.agent === "antigravity" ? "antigravity" : "claude";
|
|
5440
5574
|
const banner = [
|
|
5441
5575
|
``,
|
|
@@ -5470,7 +5604,7 @@ var setupCommand = new Command16("setup").description("Check that all dependenci
|
|
|
5470
5604
|
console.log("");
|
|
5471
5605
|
return;
|
|
5472
5606
|
}
|
|
5473
|
-
const fixes = checks.filter((
|
|
5607
|
+
const fixes = checks.filter((c15) => !c15.ok && c15.fix && !c15.optional);
|
|
5474
5608
|
if (fixes.length > 0) {
|
|
5475
5609
|
console.log(paint5("yellow", " To fix:"));
|
|
5476
5610
|
for (const fix of fixes) {
|
|
@@ -5485,8 +5619,8 @@ var setupCommand = new Command16("setup").description("Check that all dependenci
|
|
|
5485
5619
|
});
|
|
5486
5620
|
|
|
5487
5621
|
// cli/commands/update.ts
|
|
5488
|
-
import { Command as
|
|
5489
|
-
var updateCommand = new
|
|
5622
|
+
import { Command as Command20 } from "commander";
|
|
5623
|
+
var updateCommand = new Command20("update").description("Post a status update to a task, or attach a resource").argument("<task-id>", "Task ID").argument("[message-or-title]", "Status update message, or resource title when using --resource").argument("[content]", "Resource content (only used with --resource)").option("--source <source>", "Update source: agent, system, or user", "agent").option("--resource <type>", "Create a task resource (e.g. test-plan, note, plan, research)").action(async (taskId, messageOrTitle, content, opts) => {
|
|
5490
5624
|
if (opts.resource) {
|
|
5491
5625
|
if (!messageOrTitle || !content) {
|
|
5492
5626
|
console.error(`Usage: mr update <task-id> --resource <type> "<title>" '<content>'`);
|
|
@@ -5512,11 +5646,11 @@ var updateCommand = new Command17("update").description("Post a status update to
|
|
|
5512
5646
|
});
|
|
5513
5647
|
|
|
5514
5648
|
// cli/commands/screenshot.ts
|
|
5515
|
-
import { Command as
|
|
5649
|
+
import { Command as Command21 } from "commander";
|
|
5516
5650
|
import { readFileSync as readFileSync6, existsSync as existsSync8, unlinkSync as unlinkSync2 } from "fs";
|
|
5517
5651
|
import { join as join7 } from "path";
|
|
5518
5652
|
import { tmpdir } from "os";
|
|
5519
|
-
var screenshotCommand = new
|
|
5653
|
+
var screenshotCommand = new Command21("screenshot").description(
|
|
5520
5654
|
"Take or attach a screenshot to a task update (agents use this to show their work)"
|
|
5521
5655
|
).argument("<task-id>", "Task ID").argument("[file]", "Path to an image file (if omitted, uses headless browser to screenshot the app)").option("-m, --message <message>", "Optional message to include with the screenshot").option("-u, --url <url>", "Custom URL to screenshot (defaults to the task's project page)").action(async (taskId, file, opts) => {
|
|
5522
5656
|
let filePath = file;
|
|
@@ -5607,10 +5741,10 @@ var screenshotCommand = new Command18("screenshot").description(
|
|
|
5607
5741
|
});
|
|
5608
5742
|
|
|
5609
5743
|
// cli/commands/resume.ts
|
|
5610
|
-
import { Command as
|
|
5744
|
+
import { Command as Command22 } from "commander";
|
|
5611
5745
|
import { spawn as spawn5 } from "child_process";
|
|
5612
5746
|
import { resolve as resolve3 } from "path";
|
|
5613
|
-
var
|
|
5747
|
+
var c7 = {
|
|
5614
5748
|
reset: "\x1B[0m",
|
|
5615
5749
|
bold: "\x1B[1m",
|
|
5616
5750
|
dim: "\x1B[2m",
|
|
@@ -5622,9 +5756,9 @@ var c6 = {
|
|
|
5622
5756
|
gray: "\x1B[90m"
|
|
5623
5757
|
};
|
|
5624
5758
|
function paint6(color, text) {
|
|
5625
|
-
return `${
|
|
5759
|
+
return `${c7[color]}${text}${c7.reset}`;
|
|
5626
5760
|
}
|
|
5627
|
-
var resumeCommand = new
|
|
5761
|
+
var resumeCommand = new Command22("resume").description("Resume an interactive Claude session for a task (non-headless)").argument("<task-id>", "Task ID whose Claude session to resume").option("--dir <directory>", "Override the working directory for the session").action(async (taskId, opts) => {
|
|
5628
5762
|
const task = await api.get(`/api/tasks/${taskId}`);
|
|
5629
5763
|
if (!task.claudeSessionId) {
|
|
5630
5764
|
console.error(
|
|
@@ -5693,7 +5827,7 @@ var resumeCommand = new Command19("resume").description("Resume an interactive C
|
|
|
5693
5827
|
});
|
|
5694
5828
|
|
|
5695
5829
|
// cli/commands/browse.ts
|
|
5696
|
-
import { Command as
|
|
5830
|
+
import { Command as Command23 } from "commander";
|
|
5697
5831
|
import { execSync as execSync4, spawn as spawn6 } from "child_process";
|
|
5698
5832
|
import { existsSync as existsSync9, readFileSync as readFileSync7, writeFileSync as writeFileSync4 } from "fs";
|
|
5699
5833
|
import { createHash } from "crypto";
|
|
@@ -5808,7 +5942,7 @@ async function ensureDevServer(options = {}) {
|
|
|
5808
5942
|
}
|
|
5809
5943
|
throw new Error(`Dev server failed to start within 60s. Command: ${devCmd} in ${projectCwd}`);
|
|
5810
5944
|
}
|
|
5811
|
-
var browseCommand = new
|
|
5945
|
+
var browseCommand = new Command23("browse").description("Control a headless browser for QA and testing").argument("[command]", "Browse command (goto, click, fill, screenshot, etc.)").argument("[args...]", "Command arguments").option(
|
|
5812
5946
|
"--task-id <id>",
|
|
5813
5947
|
"Attach output to a task update (for screenshot and recording-stop commands)"
|
|
5814
5948
|
).option("--dev", "Auto-start local dev server before browsing").option("--dev-cwd <path>", "Working directory for the dev server (defaults to mr-manager root)").option("--dev-cmd <command>", "Dev server command to run (auto-detected from package.json if omitted)").option("--dev-port-flag <flag>", "CLI flag name used to set port (e.g. --port). Omit to use PORT env var.").allowUnknownOption(true).action(
|
|
@@ -5951,10 +6085,10 @@ var browseCommand = new Command20("browse").description("Control a headless brow
|
|
|
5951
6085
|
);
|
|
5952
6086
|
|
|
5953
6087
|
// cli/commands/set-path.ts
|
|
5954
|
-
import { Command as
|
|
6088
|
+
import { Command as Command24 } from "commander";
|
|
5955
6089
|
import { resolve as resolve5 } from "path";
|
|
5956
6090
|
import { existsSync as existsSync10 } from "fs";
|
|
5957
|
-
var setPathCommand = new
|
|
6091
|
+
var setPathCommand = new Command24("set-path").description("Set or update the local repo path for a project").argument("<project-id>", "Project ID").argument("<path>", "Absolute or relative path to the local repo").action(async (projectId, pathArg) => {
|
|
5958
6092
|
const absolutePath = resolve5(pathArg);
|
|
5959
6093
|
if (!existsSync10(absolutePath)) {
|
|
5960
6094
|
console.error(`Error: Path does not exist: ${absolutePath}`);
|
|
@@ -5972,9 +6106,9 @@ var setPathCommand = new Command21("set-path").description("Set or update the lo
|
|
|
5972
6106
|
});
|
|
5973
6107
|
|
|
5974
6108
|
// cli/commands/test.ts
|
|
5975
|
-
import { Command as
|
|
6109
|
+
import { Command as Command25 } from "commander";
|
|
5976
6110
|
import { readFileSync as readFileSync8, existsSync as existsSync11 } from "fs";
|
|
5977
|
-
var testCommand = new
|
|
6111
|
+
var testCommand = new Command25("test").description("Run automated browser test for a task's MR/PR").argument("<task-id>", "Task ID to test").option("--plan <file>", "Path to a custom test plan JSON file").option("--no-recording", "Disable proof recording for this run").action(async (taskId, opts) => {
|
|
5978
6112
|
const config = loadConfig();
|
|
5979
6113
|
console.log("[test] Fetching task...");
|
|
5980
6114
|
let task;
|
|
@@ -6136,11 +6270,11 @@ var testCommand = new Command22("test").description("Run automated browser test
|
|
|
6136
6270
|
});
|
|
6137
6271
|
|
|
6138
6272
|
// cli/commands/features.ts
|
|
6139
|
-
import { Command as
|
|
6273
|
+
import { Command as Command26 } from "commander";
|
|
6140
6274
|
import { readFileSync as readFileSync9, writeFileSync as writeFileSync5, existsSync as existsSync12 } from "fs";
|
|
6141
6275
|
import { resolve as resolve6, sep as sep2 } from "path";
|
|
6142
6276
|
var FEATURES_FILE3 = ".mr-features.md";
|
|
6143
|
-
var
|
|
6277
|
+
var c8 = {
|
|
6144
6278
|
reset: "\x1B[0m",
|
|
6145
6279
|
bold: "\x1B[1m",
|
|
6146
6280
|
dim: "\x1B[2m",
|
|
@@ -6151,7 +6285,7 @@ var c7 = {
|
|
|
6151
6285
|
gray: "\x1B[90m"
|
|
6152
6286
|
};
|
|
6153
6287
|
function paint7(color, text) {
|
|
6154
|
-
return `${
|
|
6288
|
+
return `${c8[color]}${text}${c8.reset}`;
|
|
6155
6289
|
}
|
|
6156
6290
|
function resolveProjectRoot2() {
|
|
6157
6291
|
const cwd = process.cwd();
|
|
@@ -6170,7 +6304,7 @@ function readFeatures2() {
|
|
|
6170
6304
|
if (!existsSync12(path)) return null;
|
|
6171
6305
|
return readFileSync9(path, "utf-8");
|
|
6172
6306
|
}
|
|
6173
|
-
var featuresCommand = new
|
|
6307
|
+
var featuresCommand = new Command26("features").description("View or update the project features & goals document (.mr-features.md)").option("--update <content>", "Replace the features document with the given content").option("--file <path>", "Read content from a file and use it to update the features document").option("--path", "Print the path to the features file").action(async (opts) => {
|
|
6174
6308
|
if (opts.path) {
|
|
6175
6309
|
console.log(getFeaturesPath());
|
|
6176
6310
|
return;
|
|
@@ -6198,11 +6332,11 @@ var featuresCommand = new Command23("features").description("View or update the
|
|
|
6198
6332
|
});
|
|
6199
6333
|
|
|
6200
6334
|
// cli/commands/no-mr.ts
|
|
6201
|
-
import { Command as
|
|
6335
|
+
import { Command as Command27 } from "commander";
|
|
6202
6336
|
import { writeFileSync as writeFileSync6 } from "fs";
|
|
6203
6337
|
import { resolve as resolve7 } from "path";
|
|
6204
6338
|
var NO_MR_FILE = ".mr-no-mr";
|
|
6205
|
-
var noMrCommand = new
|
|
6339
|
+
var noMrCommand = new Command27("no-mr").description("Signal that a task does not require a merge/pull request and describe what was done instead").argument("<task-id>", "Task ID").argument("<description>", "Description of what was done instead of creating an MR/PR").action(async (taskId, description) => {
|
|
6206
6340
|
const filePath = resolve7(process.cwd(), NO_MR_FILE);
|
|
6207
6341
|
writeFileSync6(filePath, description, "utf-8");
|
|
6208
6342
|
await api.post(`/api/tasks/${taskId}/updates`, {
|
|
@@ -6214,12 +6348,12 @@ var noMrCommand = new Command24("no-mr").description("Signal that a task does no
|
|
|
6214
6348
|
});
|
|
6215
6349
|
|
|
6216
6350
|
// cli/commands/review.ts
|
|
6217
|
-
import { Command as
|
|
6351
|
+
import { Command as Command29 } from "commander";
|
|
6218
6352
|
import { execSync as execSync6 } from "child_process";
|
|
6219
6353
|
import { existsSync as existsSync14, statSync as statSync2 } from "fs";
|
|
6220
6354
|
|
|
6221
6355
|
// cli/commands/review-apply.ts
|
|
6222
|
-
import { Command as
|
|
6356
|
+
import { Command as Command28 } from "commander";
|
|
6223
6357
|
import { execSync as execSync5 } from "child_process";
|
|
6224
6358
|
import { existsSync as existsSync13 } from "fs";
|
|
6225
6359
|
|
|
@@ -6309,7 +6443,7 @@ async function runAgentInteractive(prompt2, opts) {
|
|
|
6309
6443
|
}
|
|
6310
6444
|
|
|
6311
6445
|
// cli/commands/review-apply.ts
|
|
6312
|
-
var
|
|
6446
|
+
var c9 = {
|
|
6313
6447
|
reset: "\x1B[0m",
|
|
6314
6448
|
dim: "\x1B[2m",
|
|
6315
6449
|
cyan: "\x1B[36m",
|
|
@@ -6321,7 +6455,7 @@ var c8 = {
|
|
|
6321
6455
|
magenta: "\x1B[35m"
|
|
6322
6456
|
};
|
|
6323
6457
|
function paint8(color, text) {
|
|
6324
|
-
return `${
|
|
6458
|
+
return `${c9[color]}${text}${c9.reset}`;
|
|
6325
6459
|
}
|
|
6326
6460
|
function timestamp2() {
|
|
6327
6461
|
return paint8("gray", (/* @__PURE__ */ new Date()).toLocaleTimeString("en-US", { hour12: false }));
|
|
@@ -6338,7 +6472,7 @@ function logOk(msg) {
|
|
|
6338
6472
|
function logErr(msg) {
|
|
6339
6473
|
console.error(`${timestamp2()} ${tag()} ${paint8("red", "\u2717")} ${msg}`);
|
|
6340
6474
|
}
|
|
6341
|
-
var reviewApplyCommand = new
|
|
6475
|
+
var reviewApplyCommand = new Command28("apply").description("Apply review comments and findings using the Claude agent").argument("<id>", "Code review ID (the one shown in the Reviews UI)").option("--no-push", "Skip pushing the fix commit to the remote").option("--no-commit", "Apply changes but don't commit (for dry-run review)").option("--in-place", "Apply edits directly in the linked checkout instead of an isolated worktree (legacy, unsafe)").action(async (id, opts) => {
|
|
6342
6476
|
const config = loadConfig();
|
|
6343
6477
|
if (!config.apiKey) {
|
|
6344
6478
|
logErr('Not authenticated. Run "mr login" first.');
|
|
@@ -6358,7 +6492,7 @@ var reviewApplyCommand = new Command25("apply").description("Apply review commen
|
|
|
6358
6492
|
logErr("Review has no comments or findings to act on.");
|
|
6359
6493
|
process.exit(1);
|
|
6360
6494
|
}
|
|
6361
|
-
const actionableComments = comments.filter((
|
|
6495
|
+
const actionableComments = comments.filter((c15) => !excluded.has(c15.file));
|
|
6362
6496
|
const dismissedCount = findings.filter((f) => f.status === "dismissed").length;
|
|
6363
6497
|
const actionableFindings = findings.filter(
|
|
6364
6498
|
(f) => !excluded.has(f.file) && f.status !== "dismissed"
|
|
@@ -6396,7 +6530,7 @@ var reviewApplyCommand = new Command25("apply").description("Apply review commen
|
|
|
6396
6530
|
}
|
|
6397
6531
|
const touchedFiles = Array.from(
|
|
6398
6532
|
new Set([
|
|
6399
|
-
...actionableComments.map((
|
|
6533
|
+
...actionableComments.map((c15) => c15.file),
|
|
6400
6534
|
...actionableFindings.map((f) => f.file)
|
|
6401
6535
|
].filter(Boolean))
|
|
6402
6536
|
);
|
|
@@ -6536,9 +6670,9 @@ function buildApplyPrompt(args) {
|
|
|
6536
6670
|
}
|
|
6537
6671
|
if (args.comments.length > 0) {
|
|
6538
6672
|
lines.push("USER COMMENTS:");
|
|
6539
|
-
for (const
|
|
6540
|
-
const where =
|
|
6541
|
-
lines.push(`- [${where}] ${
|
|
6673
|
+
for (const c15 of args.comments) {
|
|
6674
|
+
const where = c15.line ? `${c15.file}:${c15.line}` : c15.file;
|
|
6675
|
+
lines.push(`- [${where}] ${c15.body}`);
|
|
6542
6676
|
}
|
|
6543
6677
|
lines.push("");
|
|
6544
6678
|
}
|
|
@@ -6792,6 +6926,37 @@ function buildDimensionPrompt(args) {
|
|
|
6792
6926
|
lines.push(JSON_CONTRACT, "", "Here is the diff to review:", "", "```diff", args.diff, "```");
|
|
6793
6927
|
return lines.join("\n");
|
|
6794
6928
|
}
|
|
6929
|
+
function buildLightPrompt(args) {
|
|
6930
|
+
const allowedTypes = [
|
|
6931
|
+
...new Set(REVIEW_DIMENSIONS.flatMap((d) => d.allowedTypes))
|
|
6932
|
+
];
|
|
6933
|
+
const lines = [];
|
|
6934
|
+
lines.push(
|
|
6935
|
+
`You are a senior code reviewer doing a quick but careful pass.`,
|
|
6936
|
+
`Review the git diff for branch "${args.branch}" compared to "${args.baseBranch}".`,
|
|
6937
|
+
"",
|
|
6938
|
+
"Cover all of these concerns in a single pass and report the issues that matter most:",
|
|
6939
|
+
"- Security (injection, auth gaps, leaked secrets, unsafe input handling)",
|
|
6940
|
+
"- Correctness (logic bugs, null/undefined, broken contracts, bad async)",
|
|
6941
|
+
"- Performance (N+1 queries, hot-loop work, missing memoization)",
|
|
6942
|
+
"- Style & maintainability (naming, dead code, duplication) \u2014 keep these low severity",
|
|
6943
|
+
"",
|
|
6944
|
+
"Prioritize real, high-impact problems over nitpicks. This is a fast pass, so favor",
|
|
6945
|
+
"the issues you are confident about over exhaustive coverage.",
|
|
6946
|
+
"",
|
|
6947
|
+
`Emit findings whose "type" is one of: ${allowedTypes.join(", ")}.`,
|
|
6948
|
+
""
|
|
6949
|
+
);
|
|
6950
|
+
if (args.canReadFiles) {
|
|
6951
|
+
lines.push(
|
|
6952
|
+
"You are running inside a checkout of this repository and MAY open changed files",
|
|
6953
|
+
"and their neighbors to confirm a finding before reporting it.",
|
|
6954
|
+
""
|
|
6955
|
+
);
|
|
6956
|
+
}
|
|
6957
|
+
lines.push(JSON_CONTRACT, "", "Here is the diff to review:", "", "```diff", args.diff, "```");
|
|
6958
|
+
return lines.join("\n");
|
|
6959
|
+
}
|
|
6795
6960
|
function buildVerificationPrompt(args) {
|
|
6796
6961
|
const compact = args.findings.map((f) => ({
|
|
6797
6962
|
id: f.id,
|
|
@@ -6832,6 +6997,41 @@ function buildVerificationPrompt(args) {
|
|
|
6832
6997
|
return lines.join("\n");
|
|
6833
6998
|
}
|
|
6834
6999
|
|
|
7000
|
+
// lib/review/depth.ts
|
|
7001
|
+
var REVIEW_DEPTHS = {
|
|
7002
|
+
light: {
|
|
7003
|
+
key: "light",
|
|
7004
|
+
label: "Light",
|
|
7005
|
+
description: "One agent, quick single pass",
|
|
7006
|
+
fanOut: false,
|
|
7007
|
+
verify: false,
|
|
7008
|
+
multiAgent: false
|
|
7009
|
+
},
|
|
7010
|
+
regular: {
|
|
7011
|
+
key: "regular",
|
|
7012
|
+
label: "Regular",
|
|
7013
|
+
description: "Team review across security, correctness, performance & style",
|
|
7014
|
+
fanOut: true,
|
|
7015
|
+
verify: true,
|
|
7016
|
+
multiAgent: false
|
|
7017
|
+
},
|
|
7018
|
+
deep: {
|
|
7019
|
+
key: "deep",
|
|
7020
|
+
label: "Deep",
|
|
7021
|
+
description: "Multiple agents (claude, codex, gemini) for deep analysis",
|
|
7022
|
+
fanOut: true,
|
|
7023
|
+
verify: true,
|
|
7024
|
+
multiAgent: true
|
|
7025
|
+
}
|
|
7026
|
+
};
|
|
7027
|
+
var DEFAULT_REVIEW_DEPTH = "regular";
|
|
7028
|
+
function normalizeReviewDepth(value) {
|
|
7029
|
+
return value === "light" || value === "regular" || value === "deep" ? value : DEFAULT_REVIEW_DEPTH;
|
|
7030
|
+
}
|
|
7031
|
+
function getReviewDepthConfig(value) {
|
|
7032
|
+
return REVIEW_DEPTHS[normalizeReviewDepth(value)];
|
|
7033
|
+
}
|
|
7034
|
+
|
|
6835
7035
|
// lib/review/orchestrate.ts
|
|
6836
7036
|
function splitDiffByFile(diff) {
|
|
6837
7037
|
const sections = diff.split(/(?=^diff --git )/m).filter((s) => s.trim());
|
|
@@ -6852,7 +7052,10 @@ async function pool(items, limit) {
|
|
|
6852
7052
|
await Promise.all(workers);
|
|
6853
7053
|
return results;
|
|
6854
7054
|
}
|
|
6855
|
-
function buildJobs(opts) {
|
|
7055
|
+
function buildJobs(opts, fanOut) {
|
|
7056
|
+
if (!fanOut) {
|
|
7057
|
+
return [{ dimension: null, diff: opts.diff }];
|
|
7058
|
+
}
|
|
6856
7059
|
const files = splitDiffByFile(opts.diff);
|
|
6857
7060
|
const shardThreshold = opts.shardThreshold ?? 12;
|
|
6858
7061
|
if (files.length >= shardThreshold) {
|
|
@@ -6881,40 +7084,63 @@ async function orchestrateReview(opts) {
|
|
|
6881
7084
|
});
|
|
6882
7085
|
const concurrency = opts.concurrency ?? 4;
|
|
6883
7086
|
const canReadFiles = Boolean(opts.cwd);
|
|
6884
|
-
const
|
|
6885
|
-
const jobs = buildJobs(opts);
|
|
6886
|
-
|
|
7087
|
+
const depthConfig = getReviewDepthConfig(opts.depth);
|
|
7088
|
+
const jobs = buildJobs(opts, depthConfig.fanOut);
|
|
7089
|
+
const reviewers = depthConfig.multiAgent ? opts.chain : [opts.chain[0]];
|
|
7090
|
+
if (depthConfig.multiAgent) {
|
|
7091
|
+
log4(`Deep review across ${reviewers.length} agent(s): ${reviewers.join(", ")}`);
|
|
7092
|
+
}
|
|
7093
|
+
log4(
|
|
7094
|
+
depthConfig.fanOut ? `Fanning out ${jobs.length} review subagent(s) across ${REVIEW_DIMENSIONS.length} dimensions \xD7 ${reviewers.length} agent(s)` : `Running a light single-pass review with ${reviewers[0]}`
|
|
7095
|
+
);
|
|
7096
|
+
const tasks = jobs.flatMap(
|
|
7097
|
+
(job) => reviewers.map((agent) => ({ job, agent }))
|
|
7098
|
+
);
|
|
6887
7099
|
const summaries = [];
|
|
6888
7100
|
const collected = [];
|
|
6889
7101
|
const jobResults = await pool(
|
|
6890
|
-
|
|
6891
|
-
const prompt2 = buildDimensionPrompt({
|
|
7102
|
+
tasks.map(({ job, agent }) => async () => {
|
|
7103
|
+
const prompt2 = job.dimension ? buildDimensionPrompt({
|
|
6892
7104
|
dimension: job.dimension,
|
|
6893
7105
|
branch: opts.branch,
|
|
6894
7106
|
baseBranch: opts.baseBranch,
|
|
6895
7107
|
diff: job.diff,
|
|
6896
7108
|
canReadFiles,
|
|
6897
7109
|
fileScope: job.fileScope
|
|
7110
|
+
}) : buildLightPrompt({
|
|
7111
|
+
branch: opts.branch,
|
|
7112
|
+
baseBranch: opts.baseBranch,
|
|
7113
|
+
diff: job.diff,
|
|
7114
|
+
canReadFiles
|
|
6898
7115
|
});
|
|
7116
|
+
const runOpts = {
|
|
7117
|
+
cwd: opts.cwd,
|
|
7118
|
+
chain: depthConfig.multiAgent ? [agent] : opts.chain
|
|
7119
|
+
};
|
|
6899
7120
|
try {
|
|
6900
|
-
const { output } = await runAgentCaptured(prompt2, runOpts);
|
|
7121
|
+
const { output, agent: usedAgent } = await runAgentCaptured(prompt2, runOpts);
|
|
6901
7122
|
const parsed = parseReviewOutput(output);
|
|
6902
|
-
return { job, parsed };
|
|
7123
|
+
return { job, parsed, agent: usedAgent };
|
|
6903
7124
|
} catch (err) {
|
|
6904
|
-
|
|
6905
|
-
|
|
7125
|
+
const label = job.dimension?.key ?? "light";
|
|
7126
|
+
log4(` ${label} subagent (${agent}) failed: ${err.message}`);
|
|
7127
|
+
return { job, parsed: { summary: "", findings: [], parseFailed: true }, agent };
|
|
6906
7128
|
}
|
|
6907
7129
|
}),
|
|
6908
7130
|
concurrency
|
|
6909
7131
|
);
|
|
6910
7132
|
const dimensionsRun = /* @__PURE__ */ new Set();
|
|
6911
|
-
|
|
6912
|
-
|
|
7133
|
+
const agentsRun = /* @__PURE__ */ new Set();
|
|
7134
|
+
for (const { job, parsed, agent } of jobResults) {
|
|
7135
|
+
const label = job.dimension?.title ?? "Review";
|
|
7136
|
+
if (parsed.summary) summaries.push(`${label}: ${parsed.summary}`);
|
|
6913
7137
|
for (const f of parsed.findings) {
|
|
6914
|
-
|
|
7138
|
+
agentsRun.add(agent);
|
|
7139
|
+
const fallbackType = job.dimension?.allowedTypes[0] ?? "bug";
|
|
7140
|
+
if (job.dimension) dimensionsRun.add(job.dimension.key);
|
|
6915
7141
|
collected.push({
|
|
6916
7142
|
id: f.id || "f",
|
|
6917
|
-
type: f.type ||
|
|
7143
|
+
type: f.type || fallbackType,
|
|
6918
7144
|
severity: f.severity || "medium",
|
|
6919
7145
|
title: f.title || "Untitled finding",
|
|
6920
7146
|
description: f.description || "",
|
|
@@ -6923,7 +7149,7 @@ async function orchestrateReview(opts) {
|
|
|
6923
7149
|
endLine: typeof f.endLine === "number" ? f.endLine : void 0,
|
|
6924
7150
|
suggestion: f.suggestion,
|
|
6925
7151
|
status: "new",
|
|
6926
|
-
dimension: job.dimension.
|
|
7152
|
+
dimension: job.dimension?.key ?? f.type ?? "general",
|
|
6927
7153
|
confidence: typeof f.confidence === "number" ? f.confidence : void 0
|
|
6928
7154
|
});
|
|
6929
7155
|
}
|
|
@@ -6931,13 +7157,15 @@ async function orchestrateReview(opts) {
|
|
|
6931
7157
|
const rawCount = collected.length;
|
|
6932
7158
|
let findings = mergeFindings(collected);
|
|
6933
7159
|
log4(`Merged ${rawCount} raw findings into ${findings.length} after dedup`);
|
|
6934
|
-
if (
|
|
6935
|
-
|
|
7160
|
+
if (depthConfig.verify && findings.length > 0) {
|
|
7161
|
+
const verifyOpts = { cwd: opts.cwd, chain: opts.chain };
|
|
7162
|
+
findings = await verifyFindings(findings, opts, verifyOpts, log4);
|
|
6936
7163
|
}
|
|
6937
7164
|
return {
|
|
6938
7165
|
summary: summaries.join(" "),
|
|
6939
7166
|
findings,
|
|
6940
7167
|
dimensionsRun: [...dimensionsRun],
|
|
7168
|
+
agentsRun: [...agentsRun],
|
|
6941
7169
|
rawCount
|
|
6942
7170
|
};
|
|
6943
7171
|
}
|
|
@@ -6979,7 +7207,7 @@ async function verifyFindings(findings, opts, runOpts, log4) {
|
|
|
6979
7207
|
}
|
|
6980
7208
|
|
|
6981
7209
|
// cli/commands/review.ts
|
|
6982
|
-
var
|
|
7210
|
+
var c10 = {
|
|
6983
7211
|
reset: "\x1B[0m",
|
|
6984
7212
|
bold: "\x1B[1m",
|
|
6985
7213
|
dim: "\x1B[2m",
|
|
@@ -6992,7 +7220,7 @@ var c9 = {
|
|
|
6992
7220
|
blue: "\x1B[34m"
|
|
6993
7221
|
};
|
|
6994
7222
|
function paint9(color, text) {
|
|
6995
|
-
return `${
|
|
7223
|
+
return `${c10[color]}${text}${c10.reset}`;
|
|
6996
7224
|
}
|
|
6997
7225
|
function timestamp3() {
|
|
6998
7226
|
return paint9("gray", (/* @__PURE__ */ new Date()).toLocaleTimeString("en-US", { hour12: false }));
|
|
@@ -7009,7 +7237,7 @@ function logOk2(msg) {
|
|
|
7009
7237
|
function logErr2(msg) {
|
|
7010
7238
|
console.error(`${timestamp3()} ${tag2()} ${paint9("red", "\u2717")} ${msg}`);
|
|
7011
7239
|
}
|
|
7012
|
-
var reviewCommand = new
|
|
7240
|
+
var reviewCommand = new Command29("review").description("Run an automated code review on a branch").option("--project <id>", "Project ID (defaults to linked project)").option("--report <id>", "Use an existing review report ID (created by UI trigger)").option("--branch <name>", "Branch to review (defaults to current branch)").option("--base <name>", "Base branch to diff against (defaults to main)").option("--depth <level>", "Review depth: light | regular | deep", "regular").option("--pr-url <url>", "Pull/merge request URL; when set, diff is fetched via gh/glab and no local checkout is needed").option("--pr-number <n>", "Pull/merge request number (used with --pr-url)").addCommand(reviewApplyCommand).action(async (opts) => {
|
|
7013
7241
|
const config = loadConfig();
|
|
7014
7242
|
if (!config.apiKey) {
|
|
7015
7243
|
logErr2('Not authenticated. Run "mr login" first.');
|
|
@@ -7038,6 +7266,8 @@ var reviewCommand = new Command26("review").description("Run an automated code r
|
|
|
7038
7266
|
process.exit(1);
|
|
7039
7267
|
}
|
|
7040
7268
|
const baseBranch = opts.base || "main";
|
|
7269
|
+
const depth = normalizeReviewDepth(opts.depth);
|
|
7270
|
+
const depthConfig = getReviewDepthConfig(depth);
|
|
7041
7271
|
const prUrl = opts.prUrl;
|
|
7042
7272
|
const prNumberRaw = opts.prNumber;
|
|
7043
7273
|
const prNumber = prNumberRaw ? Number(prNumberRaw) : void 0;
|
|
@@ -7157,7 +7387,8 @@ var reviewCommand = new Command26("review").description("Run an automated code r
|
|
|
7157
7387
|
const report = await api.post("/api/reviews", {
|
|
7158
7388
|
projectId,
|
|
7159
7389
|
branch,
|
|
7160
|
-
baseBranch
|
|
7390
|
+
baseBranch,
|
|
7391
|
+
depth
|
|
7161
7392
|
});
|
|
7162
7393
|
reportId = report.id;
|
|
7163
7394
|
log2(`Created review report ${paint9("yellow", reportId.slice(0, 8))}`);
|
|
@@ -7185,6 +7416,7 @@ var reviewCommand = new Command26("review").description("Run an automated code r
|
|
|
7185
7416
|
process.exit(1);
|
|
7186
7417
|
}
|
|
7187
7418
|
log2(`Agent chain: ${paint9("cyan", chain.join(" \u2192 "))}`);
|
|
7419
|
+
log2(`Review depth: ${paint9("magenta", depthConfig.label)} ${paint9("dim", `(${depthConfig.description})`)}`);
|
|
7188
7420
|
const MAX_DIFF_CHARS = 4e5;
|
|
7189
7421
|
const diffCharsTotal = diff.length;
|
|
7190
7422
|
let reviewDiff = diff;
|
|
@@ -7195,15 +7427,15 @@ var reviewCommand = new Command26("review").description("Run an automated code r
|
|
|
7195
7427
|
log2(paint9("yellow", `Diff truncated to ${MAX_DIFF_CHARS.toLocaleString()} of ${diffCharsTotal.toLocaleString()} chars`));
|
|
7196
7428
|
}
|
|
7197
7429
|
try {
|
|
7198
|
-
log2(
|
|
7430
|
+
log2(`Running ${depthConfig.label.toLowerCase()} code review...`);
|
|
7199
7431
|
const orchestrated = await orchestrateReview({
|
|
7200
7432
|
branch,
|
|
7201
7433
|
baseBranch,
|
|
7202
7434
|
diff: reviewDiff,
|
|
7203
7435
|
chain,
|
|
7436
|
+
depth,
|
|
7204
7437
|
cwd: reviewCwd,
|
|
7205
7438
|
concurrency: 4,
|
|
7206
|
-
verify: true,
|
|
7207
7439
|
log: (m) => log2(m)
|
|
7208
7440
|
});
|
|
7209
7441
|
const result = { summary: orchestrated.summary, findings: orchestrated.findings };
|
|
@@ -7316,7 +7548,7 @@ function formatDuration(ms) {
|
|
|
7316
7548
|
}
|
|
7317
7549
|
|
|
7318
7550
|
// cli/commands/scan.ts
|
|
7319
|
-
import { Command as
|
|
7551
|
+
import { Command as Command30 } from "commander";
|
|
7320
7552
|
|
|
7321
7553
|
// lib/scanner/index.ts
|
|
7322
7554
|
import { spawn as spawn8 } from "child_process";
|
|
@@ -7782,10 +8014,10 @@ ${codebaseAnalysis.routes.map((r) => `- ${r}`).join("\n")}
|
|
|
7782
8014
|
${codebaseAnalysis.prismaModels.map((m) => `- ${m}`).join("\n")}
|
|
7783
8015
|
|
|
7784
8016
|
**Components:**
|
|
7785
|
-
${codebaseAnalysis.components.slice(0, 15).map((
|
|
8017
|
+
${codebaseAnalysis.components.slice(0, 15).map((c15) => `- ${c15}`).join("\n")}
|
|
7786
8018
|
|
|
7787
8019
|
**Recent Git Commits:**
|
|
7788
|
-
${codebaseAnalysis.recentCommits.slice(0, 8).map((
|
|
8020
|
+
${codebaseAnalysis.recentCommits.slice(0, 8).map((c15) => `- ${c15}`).join("\n")}
|
|
7789
8021
|
|
|
7790
8022
|
**Completed Tasks:**
|
|
7791
8023
|
${context.completedTasks.slice(0, 10).map((t) => `- ${t.title}`).join("\n") || "None"}
|
|
@@ -8058,7 +8290,7 @@ function parseSynthesisOutput(output) {
|
|
|
8058
8290
|
}
|
|
8059
8291
|
|
|
8060
8292
|
// cli/commands/scan.ts
|
|
8061
|
-
var
|
|
8293
|
+
var c11 = {
|
|
8062
8294
|
reset: "\x1B[0m",
|
|
8063
8295
|
bold: "\x1B[1m",
|
|
8064
8296
|
dim: "\x1B[2m",
|
|
@@ -8070,7 +8302,7 @@ var c10 = {
|
|
|
8070
8302
|
gray: "\x1B[90m"
|
|
8071
8303
|
};
|
|
8072
8304
|
function paint10(color, text) {
|
|
8073
|
-
return `${
|
|
8305
|
+
return `${c11[color]}${text}${c11.reset}`;
|
|
8074
8306
|
}
|
|
8075
8307
|
function timestamp4() {
|
|
8076
8308
|
return paint10("gray", (/* @__PURE__ */ new Date()).toLocaleTimeString("en-US", { hour12: false }));
|
|
@@ -8087,7 +8319,7 @@ function logOk3(msg) {
|
|
|
8087
8319
|
function logErr3(msg) {
|
|
8088
8320
|
console.error(`${timestamp4()} ${scanTag()} ${paint10("red", "\u2717")} ${msg}`);
|
|
8089
8321
|
}
|
|
8090
|
-
var scanCommand = new
|
|
8322
|
+
var scanCommand = new Command30("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("--prompt <prompt>", "Custom scan direction/prompt to focus the scan on").option("--no-crawl", "Skip live crawl (codebase analysis only)").action(async (opts) => {
|
|
8091
8323
|
const config = loadConfig();
|
|
8092
8324
|
if (!config.apiKey) {
|
|
8093
8325
|
logErr3('Not authenticated. Run "mr login" first.');
|
|
@@ -8252,7 +8484,7 @@ var scanCommand = new Command27("scan").description("Run a product scan on the c
|
|
|
8252
8484
|
});
|
|
8253
8485
|
|
|
8254
8486
|
// cli/commands/doctor.ts
|
|
8255
|
-
import { Command as
|
|
8487
|
+
import { Command as Command31 } from "commander";
|
|
8256
8488
|
import { existsSync as existsSync17 } from "fs";
|
|
8257
8489
|
import { homedir as homedir2 } from "os";
|
|
8258
8490
|
import { join as join11 } from "path";
|
|
@@ -8300,7 +8532,7 @@ async function checkProjectLink() {
|
|
|
8300
8532
|
optional: true
|
|
8301
8533
|
};
|
|
8302
8534
|
}
|
|
8303
|
-
var doctorCommand = new
|
|
8535
|
+
var doctorCommand = new Command31("doctor").description("Diagnose Mr. Manager CLI installation and environment").action(async () => {
|
|
8304
8536
|
const banner = [
|
|
8305
8537
|
``,
|
|
8306
8538
|
paint5("cyan", ` MR DOCTOR`),
|
|
@@ -8331,7 +8563,7 @@ var doctorCommand = new Command28("doctor").description("Diagnose Mr. Manager CL
|
|
|
8331
8563
|
console.log("");
|
|
8332
8564
|
return;
|
|
8333
8565
|
}
|
|
8334
|
-
const fixes = checks.filter((
|
|
8566
|
+
const fixes = checks.filter((c15) => !c15.ok && c15.fix && !c15.optional);
|
|
8335
8567
|
if (fixes.length > 0) {
|
|
8336
8568
|
console.log(paint5("yellow", " To fix:"));
|
|
8337
8569
|
for (const fix of fixes) {
|
|
@@ -8343,14 +8575,14 @@ var doctorCommand = new Command28("doctor").description("Diagnose Mr. Manager CL
|
|
|
8343
8575
|
});
|
|
8344
8576
|
|
|
8345
8577
|
// cli/commands/prompt-audit.ts
|
|
8346
|
-
import { Command as
|
|
8578
|
+
import { Command as Command32 } from "commander";
|
|
8347
8579
|
import { resolve as resolve8 } from "path";
|
|
8348
8580
|
import { existsSync as existsSync18, readFileSync as readFileSync12 } from "fs";
|
|
8349
8581
|
function auditLine(label, tokens) {
|
|
8350
8582
|
const bar = "\u2588".repeat(Math.min(60, Math.round(tokens / 200)));
|
|
8351
8583
|
return ` ${label.padEnd(30)} ${formatTokenCount(tokens).padStart(8)} ${bar}`;
|
|
8352
8584
|
}
|
|
8353
|
-
var promptAuditCommand = new
|
|
8585
|
+
var promptAuditCommand = new Command32("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) => {
|
|
8354
8586
|
const results = [];
|
|
8355
8587
|
if (opts.task) {
|
|
8356
8588
|
try {
|
|
@@ -8410,7 +8642,7 @@ ${task.notes}` : "";
|
|
|
8410
8642
|
}
|
|
8411
8643
|
}
|
|
8412
8644
|
sections.push({ name: "static-instructions (system)", tokens: estimateTokens(
|
|
8413
|
-
"status-updates + screenshots +
|
|
8645
|
+
"status-updates + screenshots + no-mr + features-workflow"
|
|
8414
8646
|
) });
|
|
8415
8647
|
const totalTokens = sections.reduce((sum, s) => sum + s.tokens, 0);
|
|
8416
8648
|
const promptTokens = sections.filter((s) => !s.name.includes("system")).reduce((sum, s) => sum + s.tokens, 0);
|
|
@@ -8559,9 +8791,9 @@ ${r.jobType} [${r.identifier}]`);
|
|
|
8559
8791
|
});
|
|
8560
8792
|
|
|
8561
8793
|
// cli/commands/skill.ts
|
|
8562
|
-
import { Command as
|
|
8563
|
-
import { createInterface as
|
|
8564
|
-
var
|
|
8794
|
+
import { Command as Command33 } from "commander";
|
|
8795
|
+
import { createInterface as createInterface4 } from "readline/promises";
|
|
8796
|
+
var c12 = {
|
|
8565
8797
|
reset: "\x1B[0m",
|
|
8566
8798
|
bold: "\x1B[1m",
|
|
8567
8799
|
dim: "\x1B[2m",
|
|
@@ -8594,7 +8826,7 @@ function formatSize(bytes) {
|
|
|
8594
8826
|
if (bytes < 1024) return `${bytes}b`;
|
|
8595
8827
|
return `${(bytes / 1024).toFixed(1)}kb`;
|
|
8596
8828
|
}
|
|
8597
|
-
var skillCommand = new
|
|
8829
|
+
var skillCommand = new Command33("skill").description("Manage skills \u2014 reusable playbooks for AI agents");
|
|
8598
8830
|
skillCommand.command("list").alias("ls").description("List all skills").option("--category <category>", "Filter by category").action(async (opts) => {
|
|
8599
8831
|
const params = new URLSearchParams();
|
|
8600
8832
|
if (opts.category) params.set("category", opts.category);
|
|
@@ -8602,17 +8834,17 @@ skillCommand.command("list").alias("ls").description("List all skills").option("
|
|
|
8602
8834
|
`/api/skills${params.toString() ? `?${params}` : ""}`
|
|
8603
8835
|
);
|
|
8604
8836
|
if (skills.length === 0) {
|
|
8605
|
-
console.log(`${
|
|
8837
|
+
console.log(`${c12.dim}No skills found.${c12.reset}`);
|
|
8606
8838
|
return;
|
|
8607
8839
|
}
|
|
8608
8840
|
for (const skill of skills) {
|
|
8609
|
-
const cat = skill.category ? ` ${
|
|
8610
|
-
const scope = skill.projectId ? ` ${
|
|
8611
|
-
console.log(` ${
|
|
8841
|
+
const cat = skill.category ? ` ${c12.dim}[${skill.category}]${c12.reset}` : "";
|
|
8842
|
+
const scope = skill.projectId ? ` ${c12.dim}(project)${c12.reset}` : ` ${c12.dim}(global)${c12.reset}`;
|
|
8843
|
+
console.log(` ${c12.cyan}${skill.name}${c12.reset}${cat}${scope}`);
|
|
8612
8844
|
if (skill.description) {
|
|
8613
|
-
console.log(` ${
|
|
8845
|
+
console.log(` ${c12.dim}${skill.description}${c12.reset}`);
|
|
8614
8846
|
}
|
|
8615
|
-
console.log(` ${
|
|
8847
|
+
console.log(` ${c12.dim}id: ${skill.id}${c12.reset}`);
|
|
8616
8848
|
}
|
|
8617
8849
|
});
|
|
8618
8850
|
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) => {
|
|
@@ -8648,7 +8880,7 @@ skillCommand.command("create").description("Create a new skill from a markdown f
|
|
|
8648
8880
|
projectId
|
|
8649
8881
|
});
|
|
8650
8882
|
console.log(
|
|
8651
|
-
`${
|
|
8883
|
+
`${c12.green}Created skill:${c12.reset} ${c12.bold}${skill.name}${c12.reset} ${c12.dim}(${skill.id})${c12.reset}`
|
|
8652
8884
|
);
|
|
8653
8885
|
});
|
|
8654
8886
|
skillCommand.command("update").description(
|
|
@@ -8709,14 +8941,14 @@ skillCommand.command("update").description(
|
|
|
8709
8941
|
const beforeContent = existing.content ?? "";
|
|
8710
8942
|
const afterContent = typeof patch.content === "string" ? patch.content : beforeContent;
|
|
8711
8943
|
const contentChanged = typeof patch.content === "string" && patch.content !== beforeContent;
|
|
8712
|
-
const sizeDiff = typeof patch.content === "string" ? ` ${
|
|
8944
|
+
const sizeDiff = typeof patch.content === "string" ? ` ${c12.dim}(${formatSize(Buffer.byteLength(beforeContent, "utf-8"))} -> ${formatSize(Buffer.byteLength(afterContent, "utf-8"))})${c12.reset}` : "";
|
|
8713
8945
|
const priorRevisions = existing.revisions?.length ?? 0;
|
|
8714
8946
|
const revisionsAfter = priorRevisions + (contentChanged ? 1 : 0);
|
|
8715
|
-
const revisionNote = contentChanged ? ` ${
|
|
8947
|
+
const revisionNote = contentChanged ? ` ${c12.dim}kept ${revisionsAfter} prior revision${revisionsAfter === 1 ? "" : "s"}${c12.reset}` : "";
|
|
8716
8948
|
console.log(
|
|
8717
|
-
`${
|
|
8949
|
+
`${c12.green}Updated skill:${c12.reset} ${c12.bold}${updated.name}${c12.reset}${sizeDiff}${revisionNote}`
|
|
8718
8950
|
);
|
|
8719
|
-
console.log(` ${
|
|
8951
|
+
console.log(` ${c12.dim}id: ${updated.id}${c12.reset}`);
|
|
8720
8952
|
});
|
|
8721
8953
|
skillCommand.command("delete").alias("rm").description("Delete a skill").argument("<idOrName>", "Skill id or name").option("--yes", "Skip confirmation prompt").action(async (idOrName, opts) => {
|
|
8722
8954
|
let skill;
|
|
@@ -8727,9 +8959,9 @@ skillCommand.command("delete").alias("rm").description("Delete a skill").argumen
|
|
|
8727
8959
|
process.exit(1);
|
|
8728
8960
|
}
|
|
8729
8961
|
if (!opts.yes) {
|
|
8730
|
-
const rl =
|
|
8962
|
+
const rl = createInterface4({ input: process.stdin, output: process.stdout });
|
|
8731
8963
|
const answer = (await rl.question(
|
|
8732
|
-
`Delete skill ${
|
|
8964
|
+
`Delete skill ${c12.bold}${skill.name}${c12.reset} ${c12.dim}(${skill.id})${c12.reset}? [y/N] `
|
|
8733
8965
|
)).trim().toLowerCase();
|
|
8734
8966
|
rl.close();
|
|
8735
8967
|
if (answer !== "y" && answer !== "yes") {
|
|
@@ -8739,7 +8971,7 @@ skillCommand.command("delete").alias("rm").description("Delete a skill").argumen
|
|
|
8739
8971
|
}
|
|
8740
8972
|
await api.del(`/api/skills/${skill.id}`);
|
|
8741
8973
|
console.log(
|
|
8742
|
-
`${
|
|
8974
|
+
`${c12.yellow}Deleted skill:${c12.reset} ${c12.bold}${skill.name}${c12.reset} ${c12.dim}(${skill.id})${c12.reset}`
|
|
8743
8975
|
);
|
|
8744
8976
|
});
|
|
8745
8977
|
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) => {
|
|
@@ -8753,22 +8985,22 @@ skillCommand.command("generate").alias("gen").description("Generate a new skill
|
|
|
8753
8985
|
process.exit(1);
|
|
8754
8986
|
}
|
|
8755
8987
|
}
|
|
8756
|
-
console.log(`${
|
|
8988
|
+
console.log(`${c12.dim}Generating skill...${c12.reset}`);
|
|
8757
8989
|
try {
|
|
8758
8990
|
const skill = await api.post("/api/skills/generate", {
|
|
8759
8991
|
prompt: prompt2,
|
|
8760
8992
|
projectId
|
|
8761
8993
|
});
|
|
8762
8994
|
console.log(
|
|
8763
|
-
`${
|
|
8995
|
+
`${c12.green}Generated skill:${c12.reset} ${c12.bold}${skill.name}${c12.reset}`
|
|
8764
8996
|
);
|
|
8765
8997
|
if (skill.description) {
|
|
8766
|
-
console.log(` ${
|
|
8998
|
+
console.log(` ${c12.dim}${skill.description}${c12.reset}`);
|
|
8767
8999
|
}
|
|
8768
9000
|
if (skill.category) {
|
|
8769
|
-
console.log(` ${
|
|
9001
|
+
console.log(` ${c12.dim}Category: ${skill.category}${c12.reset}`);
|
|
8770
9002
|
}
|
|
8771
|
-
console.log(` ${
|
|
9003
|
+
console.log(` ${c12.dim}id: ${skill.id}${c12.reset}`);
|
|
8772
9004
|
} catch (err) {
|
|
8773
9005
|
console.error(`Failed to generate skill: ${err.message}`);
|
|
8774
9006
|
process.exit(1);
|
|
@@ -8776,8 +9008,8 @@ skillCommand.command("generate").alias("gen").description("Generate a new skill
|
|
|
8776
9008
|
});
|
|
8777
9009
|
|
|
8778
9010
|
// cli/commands/resource.ts
|
|
8779
|
-
import { Command as
|
|
8780
|
-
var
|
|
9011
|
+
import { Command as Command34 } from "commander";
|
|
9012
|
+
var c13 = {
|
|
8781
9013
|
reset: "\x1B[0m",
|
|
8782
9014
|
bold: "\x1B[1m",
|
|
8783
9015
|
dim: "\x1B[2m",
|
|
@@ -8787,16 +9019,16 @@ var c12 = {
|
|
|
8787
9019
|
magenta: "\x1B[35m"
|
|
8788
9020
|
};
|
|
8789
9021
|
var TYPE_COLORS = {
|
|
8790
|
-
plan:
|
|
8791
|
-
research:
|
|
8792
|
-
"test-plan":
|
|
8793
|
-
note:
|
|
9022
|
+
plan: c13.cyan,
|
|
9023
|
+
research: c13.magenta,
|
|
9024
|
+
"test-plan": c13.yellow,
|
|
9025
|
+
note: c13.green
|
|
8794
9026
|
};
|
|
8795
9027
|
function typeLabel(type) {
|
|
8796
|
-
const color = TYPE_COLORS[type] ??
|
|
8797
|
-
return `${color}${type}${
|
|
9028
|
+
const color = TYPE_COLORS[type] ?? c13.dim;
|
|
9029
|
+
return `${color}${type}${c13.reset}`;
|
|
8798
9030
|
}
|
|
8799
|
-
var resourceCommand = new
|
|
9031
|
+
var resourceCommand = new Command34("resource").description("Manage resources \u2014 documents, plans, research, and notes");
|
|
8800
9032
|
resourceCommand.command("list").alias("ls").description("List resources for the linked project (or all)").option("--all", "List all resources across projects").action(async (opts) => {
|
|
8801
9033
|
const params = new URLSearchParams();
|
|
8802
9034
|
if (opts.all) {
|
|
@@ -8809,13 +9041,13 @@ resourceCommand.command("list").alias("ls").description("List resources for the
|
|
|
8809
9041
|
`/api/resources${params.toString() ? `?${params}` : ""}`
|
|
8810
9042
|
);
|
|
8811
9043
|
if (resources.length === 0) {
|
|
8812
|
-
console.log(`${
|
|
9044
|
+
console.log(`${c13.dim}No resources found.${c13.reset}`);
|
|
8813
9045
|
return;
|
|
8814
9046
|
}
|
|
8815
9047
|
for (const r of resources) {
|
|
8816
|
-
const project = r.projectName ? ` ${
|
|
8817
|
-
console.log(` ${typeLabel(r.type)} ${
|
|
8818
|
-
console.log(` ${
|
|
9048
|
+
const project = r.projectName ? ` ${c13.dim}[${r.projectName}]${c13.reset}` : "";
|
|
9049
|
+
console.log(` ${typeLabel(r.type)} ${c13.bold}${r.title}${c13.reset}${project}`);
|
|
9050
|
+
console.log(` ${c13.dim}id: ${r.id}${c13.reset}`);
|
|
8819
9051
|
}
|
|
8820
9052
|
});
|
|
8821
9053
|
resourceCommand.command("create").description("Create a new resource from a file or inline content").argument("<title>", "Resource title").option("-t, --type <type>", "Resource type (note, plan, research, test-plan)", "note").option("-f, --file <path>", "Read content from a file").option("--content <text>", "Inline content").option("--task <taskId>", "Attach to an existing task instead of creating a standalone resource").option("-p, --project", "Scope to the linked project").action(async (title, opts) => {
|
|
@@ -8840,9 +9072,9 @@ resourceCommand.command("create").description("Create a new resource from a file
|
|
|
8840
9072
|
content: content.trim()
|
|
8841
9073
|
});
|
|
8842
9074
|
console.log(
|
|
8843
|
-
`${
|
|
9075
|
+
`${c13.green}Created resource:${c13.reset} ${c13.bold}${title}${c13.reset} ${c13.dim}(${resource.id})${c13.reset}`
|
|
8844
9076
|
);
|
|
8845
|
-
console.log(` ${
|
|
9077
|
+
console.log(` ${c13.dim}Attached to task ${opts.task}${c13.reset}`);
|
|
8846
9078
|
return;
|
|
8847
9079
|
}
|
|
8848
9080
|
let projectId;
|
|
@@ -8862,7 +9094,7 @@ resourceCommand.command("create").description("Create a new resource from a file
|
|
|
8862
9094
|
projectId
|
|
8863
9095
|
});
|
|
8864
9096
|
console.log(
|
|
8865
|
-
`${
|
|
9097
|
+
`${c13.green}Created resource:${c13.reset} ${c13.bold}${title}${c13.reset} ${c13.dim}(${result.resource.id})${c13.reset}`
|
|
8866
9098
|
);
|
|
8867
9099
|
});
|
|
8868
9100
|
resourceCommand.command("generate").alias("gen").description("Generate a resource using AI from a text prompt").argument("<prompt>", "Describe the resource to generate").option("-t, --type <type>", "Resource type (plan or research)", "research").option("-p, --project", "Scope to the linked project").action(async (prompt2, opts) => {
|
|
@@ -8881,30 +9113,30 @@ resourceCommand.command("generate").alias("gen").description("Generate a resourc
|
|
|
8881
9113
|
process.exit(1);
|
|
8882
9114
|
}
|
|
8883
9115
|
}
|
|
8884
|
-
console.log(`${
|
|
9116
|
+
console.log(`${c13.dim}Generating ${type}...${c13.reset}`);
|
|
8885
9117
|
const result = await api.post("/api/resources", {
|
|
8886
9118
|
type,
|
|
8887
9119
|
prompt: prompt2,
|
|
8888
9120
|
projectId
|
|
8889
9121
|
});
|
|
8890
9122
|
console.log(
|
|
8891
|
-
`${
|
|
9123
|
+
`${c13.green}Queued:${c13.reset} ${c13.bold}${result.task.title}${c13.reset}`
|
|
8892
9124
|
);
|
|
8893
|
-
console.log(` ${
|
|
9125
|
+
console.log(` ${c13.dim}task: ${result.task.id}${c13.reset}`);
|
|
8894
9126
|
});
|
|
8895
9127
|
|
|
8896
9128
|
// cli/commands/tests.ts
|
|
8897
|
-
import { Command as
|
|
8898
|
-
var
|
|
9129
|
+
import { Command as Command35 } from "commander";
|
|
9130
|
+
var c14 = {
|
|
8899
9131
|
reset: "\x1B[0m",
|
|
8900
9132
|
dim: "\x1B[2m",
|
|
8901
9133
|
yellow: "\x1B[33m"
|
|
8902
9134
|
};
|
|
8903
|
-
var testsCommand = new
|
|
9135
|
+
var testsCommand = new Command35("tests").description("List MR Test scenarios for the linked project").action(async () => {
|
|
8904
9136
|
const projectId = getLinkedProjectId();
|
|
8905
9137
|
if (!projectId) {
|
|
8906
9138
|
console.error(
|
|
8907
|
-
`${
|
|
9139
|
+
`${c14.yellow}No project linked to this directory.${c14.reset} Run "mr link <project-id>" first.`
|
|
8908
9140
|
);
|
|
8909
9141
|
process.exit(1);
|
|
8910
9142
|
}
|
|
@@ -8917,13 +9149,13 @@ var testsCommand = new Command32("tests").description("List MR Test scenarios fo
|
|
|
8917
9149
|
process.exit(1);
|
|
8918
9150
|
}
|
|
8919
9151
|
if (scenarios.length === 0) {
|
|
8920
|
-
console.log(`${
|
|
9152
|
+
console.log(`${c14.dim}No test scenarios found for this project.${c14.reset}`);
|
|
8921
9153
|
return;
|
|
8922
9154
|
}
|
|
8923
9155
|
for (const scenario of scenarios) {
|
|
8924
9156
|
console.log(`### ${scenario.name}`);
|
|
8925
9157
|
if (scenario.description) {
|
|
8926
|
-
console.log(`${
|
|
9158
|
+
console.log(`${c14.dim}${scenario.description}${c14.reset}`);
|
|
8927
9159
|
console.log();
|
|
8928
9160
|
}
|
|
8929
9161
|
console.log(scenario.content);
|
|
@@ -8932,9 +9164,9 @@ var testsCommand = new Command32("tests").description("List MR Test scenarios fo
|
|
|
8932
9164
|
});
|
|
8933
9165
|
|
|
8934
9166
|
// cli/commands/walkthrough.ts
|
|
8935
|
-
import { Command as
|
|
9167
|
+
import { Command as Command36 } from "commander";
|
|
8936
9168
|
var SKILL_NAME = "Generate Walkthrough Video";
|
|
8937
|
-
var walkthroughCommand = new
|
|
9169
|
+
var walkthroughCommand = new Command36("walkthrough").description("Attach the Generate Walkthrough Video skill to a task and queue it").argument("<task-id>", "Task ID to generate a walkthrough for").option("--prod", "Allow recording against production (requires explicit confirmation)").action(async (taskId, opts) => {
|
|
8938
9170
|
const skills = await api.get("/api/skills");
|
|
8939
9171
|
const skill = skills.find((s) => s.name === SKILL_NAME);
|
|
8940
9172
|
if (!skill) {
|
|
@@ -8967,7 +9199,7 @@ var userArgs = process.argv.slice(2);
|
|
|
8967
9199
|
var bypassCommands = /* @__PURE__ */ new Set(["login", "init", "auth", "help", "--help", "-h", "--version", "-V", "doctor", "setup"]);
|
|
8968
9200
|
var shouldBypass = userArgs.length > 0 && bypassCommands.has(userArgs[0]);
|
|
8969
9201
|
if (isFirstRun && !shouldBypass) {
|
|
8970
|
-
const
|
|
9202
|
+
const c15 = {
|
|
8971
9203
|
reset: "\x1B[0m",
|
|
8972
9204
|
bold: "\x1B[1m",
|
|
8973
9205
|
dim: "\x1B[2m",
|
|
@@ -8977,28 +9209,28 @@ if (isFirstRun && !shouldBypass) {
|
|
|
8977
9209
|
magenta: "\x1B[35m"
|
|
8978
9210
|
};
|
|
8979
9211
|
console.log("");
|
|
8980
|
-
console.log(`${
|
|
8981
|
-
console.log(`${
|
|
8982
|
-
console.log(`${
|
|
8983
|
-
console.log(`${
|
|
9212
|
+
console.log(`${c15.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${c15.reset}`);
|
|
9213
|
+
console.log(`${c15.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${c15.reset}`);
|
|
9214
|
+
console.log(`${c15.cyan} \u2569 \u2569\u2569\u255A\u2550 \u2569 \u2569\u2569 \u2569\u255D\u255A\u255D\u2569 \u2569\u255A\u2550\u255D\u255A\u2550\u255D\u2569\u255A\u2550${c15.reset}`);
|
|
9215
|
+
console.log(`${c15.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${c15.reset}`);
|
|
8984
9216
|
console.log("");
|
|
8985
|
-
console.log(`${
|
|
8986
|
-
console.log(`${
|
|
9217
|
+
console.log(`${c15.bold} Welcome to Mr. Manager!${c15.reset}`);
|
|
9218
|
+
console.log(`${c15.dim} Let's get you set up in a few quick steps.${c15.reset}`);
|
|
8987
9219
|
console.log("");
|
|
8988
|
-
console.log(` ${
|
|
8989
|
-
console.log(` ${
|
|
9220
|
+
console.log(` ${c15.yellow}Step 1:${c15.reset} Authenticate via Google OAuth`);
|
|
9221
|
+
console.log(` ${c15.dim}Run:${c15.reset} ${c15.cyan}mr login${c15.reset}`);
|
|
8990
9222
|
console.log("");
|
|
8991
|
-
console.log(` ${
|
|
8992
|
-
console.log(` ${
|
|
9223
|
+
console.log(` ${c15.yellow}Step 2:${c15.reset} Verify your environment`);
|
|
9224
|
+
console.log(` ${c15.dim}Run:${c15.reset} ${c15.cyan}mr setup${c15.reset}`);
|
|
8993
9225
|
console.log("");
|
|
8994
|
-
console.log(` ${
|
|
8995
|
-
console.log(` ${
|
|
9226
|
+
console.log(` ${c15.yellow}Step 3:${c15.reset} Link a repo and start watching`);
|
|
9227
|
+
console.log(` ${c15.dim}Run:${c15.reset} ${c15.cyan}mr link${c15.reset} ${c15.dim}&&${c15.reset} ${c15.cyan}mr watch${c15.reset}`);
|
|
8996
9228
|
console.log("");
|
|
8997
|
-
console.log(`${
|
|
9229
|
+
console.log(`${c15.dim} Or run ${c15.reset}${c15.cyan}mr login${c15.reset}${c15.dim} to get started now.${c15.reset}`);
|
|
8998
9230
|
console.log("");
|
|
8999
9231
|
process.exit(0);
|
|
9000
9232
|
}
|
|
9001
|
-
var program = new
|
|
9233
|
+
var program = new Command37();
|
|
9002
9234
|
program.name("mr").description("Mr. Manager - Task and project management CLI").version(CLI_VERSION);
|
|
9003
9235
|
program.addCommand(initCommand);
|
|
9004
9236
|
program.addCommand(authCommand);
|
|
@@ -9015,6 +9247,9 @@ program.addCommand(delegateCommand);
|
|
|
9015
9247
|
program.addCommand(undelegateCommand);
|
|
9016
9248
|
program.addCommand(createCommand);
|
|
9017
9249
|
program.addCommand(completeCommand);
|
|
9250
|
+
program.addCommand(showCommand);
|
|
9251
|
+
program.addCommand(editCommand);
|
|
9252
|
+
program.addCommand(deleteCommand);
|
|
9018
9253
|
program.addCommand(subtaskCompleteCommand);
|
|
9019
9254
|
program.addCommand(subtaskAddCommand);
|
|
9020
9255
|
program.addCommand(prototypeCommand);
|