@dunnewold-labs/mr-manager 0.4.53 → 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 +543 -175
- 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"
|
|
@@ -1151,6 +1151,118 @@ function getAvailableAgentFallbackChain(agent, availability) {
|
|
|
1151
1151
|
return getAgentFallbackChain(agent).filter((candidate) => availability[candidate] !== false);
|
|
1152
1152
|
}
|
|
1153
1153
|
|
|
1154
|
+
// lib/permissions.ts
|
|
1155
|
+
var DEFAULT_HEADLESS_MODE = "bypass";
|
|
1156
|
+
var ENV_VAR = "MR_HEADLESS_PERMISSION_MODE";
|
|
1157
|
+
var DESTRUCTIVE_BASH_DENY = [
|
|
1158
|
+
// Privilege escalation.
|
|
1159
|
+
"Bash(sudo:*)",
|
|
1160
|
+
"Bash(su:*)",
|
|
1161
|
+
// Recursive deletes of broad / out-of-repo roots.
|
|
1162
|
+
"Bash(rm -rf /:*)",
|
|
1163
|
+
"Bash(rm -rf /*:*)",
|
|
1164
|
+
"Bash(rm -fr /:*)",
|
|
1165
|
+
"Bash(rm -rf ~:*)",
|
|
1166
|
+
"Bash(rm -rf ~/:*)",
|
|
1167
|
+
"Bash(rm -rf $HOME:*)",
|
|
1168
|
+
"Bash(rm -rf ..:*)",
|
|
1169
|
+
// Filesystem / device destruction.
|
|
1170
|
+
"Bash(mkfs:*)",
|
|
1171
|
+
"Bash(dd:*)",
|
|
1172
|
+
// Mass permission/ownership changes from root.
|
|
1173
|
+
"Bash(chmod -R 777 /:*)",
|
|
1174
|
+
"Bash(chown -R:*)",
|
|
1175
|
+
// Force-push (history rewrite / remote clobber).
|
|
1176
|
+
"Bash(git push --force:*)",
|
|
1177
|
+
"Bash(git push -f:*)",
|
|
1178
|
+
"Bash(git push origin --force:*)",
|
|
1179
|
+
"Bash(git push origin -f:*)",
|
|
1180
|
+
// Remote pipe-to-shell (curl|sh / wget|bash).
|
|
1181
|
+
"Bash(curl:* | sh)",
|
|
1182
|
+
"Bash(curl:* | bash)",
|
|
1183
|
+
"Bash(wget:* | sh)",
|
|
1184
|
+
"Bash(wget:* | bash)"
|
|
1185
|
+
];
|
|
1186
|
+
var OUT_OF_REPO_WRITE_DENY = [
|
|
1187
|
+
"Write(/etc/**)",
|
|
1188
|
+
"Edit(/etc/**)",
|
|
1189
|
+
"Write(//usr/**)",
|
|
1190
|
+
"Edit(//usr/**)",
|
|
1191
|
+
"Write(~/.ssh/**)",
|
|
1192
|
+
"Edit(~/.ssh/**)",
|
|
1193
|
+
"Write(~/.aws/**)",
|
|
1194
|
+
"Edit(~/.aws/**)"
|
|
1195
|
+
];
|
|
1196
|
+
var READ_ONLY_EXTRA_DENY = ["Edit", "Write", "MultiEdit", "NotebookEdit"];
|
|
1197
|
+
function resolveHeadlessMode(config) {
|
|
1198
|
+
const fromEnv = process.env[ENV_VAR]?.trim().toLowerCase();
|
|
1199
|
+
if (fromEnv === "auto" || fromEnv === "bypass") return fromEnv;
|
|
1200
|
+
const fromConfig = config?.headlessPermissionMode?.trim().toLowerCase();
|
|
1201
|
+
if (fromConfig === "auto" || fromConfig === "bypass") return fromConfig;
|
|
1202
|
+
if (config?.claudePermissionMode != null && config.headlessPermissionMode == null) {
|
|
1203
|
+
return "bypass";
|
|
1204
|
+
}
|
|
1205
|
+
return DEFAULT_HEADLESS_MODE;
|
|
1206
|
+
}
|
|
1207
|
+
function claudeDenyList(runKind) {
|
|
1208
|
+
const base = [...DESTRUCTIVE_BASH_DENY, ...OUT_OF_REPO_WRITE_DENY];
|
|
1209
|
+
if (runKind === "review" || runKind === "scan") {
|
|
1210
|
+
return [...base, ...READ_ONLY_EXTRA_DENY];
|
|
1211
|
+
}
|
|
1212
|
+
return base;
|
|
1213
|
+
}
|
|
1214
|
+
function resolvePermissionArgs(agent, runKind, mode) {
|
|
1215
|
+
if (runKind === "plan") {
|
|
1216
|
+
if (agent === "claude") {
|
|
1217
|
+
return { args: ["--permission-mode", "plan"], effectiveMode: "plan", mappedToBypassForLackOfSandbox: false };
|
|
1218
|
+
}
|
|
1219
|
+
return resolvePermissionArgs(agent, "execute", mode);
|
|
1220
|
+
}
|
|
1221
|
+
if (mode === "bypass") {
|
|
1222
|
+
return { args: bypassArgs(agent, runKind), effectiveMode: "bypass", mappedToBypassForLackOfSandbox: false };
|
|
1223
|
+
}
|
|
1224
|
+
switch (agent) {
|
|
1225
|
+
case "claude": {
|
|
1226
|
+
const deny = claudeDenyList(runKind);
|
|
1227
|
+
return {
|
|
1228
|
+
args: ["--permission-mode", "acceptEdits", "--disallowedTools", deny.join(",")],
|
|
1229
|
+
effectiveMode: "auto",
|
|
1230
|
+
mappedToBypassForLackOfSandbox: false
|
|
1231
|
+
};
|
|
1232
|
+
}
|
|
1233
|
+
case "codex": {
|
|
1234
|
+
return { args: ["-s", "workspace-write"], effectiveMode: "auto", mappedToBypassForLackOfSandbox: false };
|
|
1235
|
+
}
|
|
1236
|
+
case "antigravity":
|
|
1237
|
+
return { args: ["--dangerously-skip-permissions"], effectiveMode: "bypass", mappedToBypassForLackOfSandbox: true };
|
|
1238
|
+
default:
|
|
1239
|
+
return { args: bypassArgs(agent, runKind), effectiveMode: "bypass", mappedToBypassForLackOfSandbox: true };
|
|
1240
|
+
}
|
|
1241
|
+
}
|
|
1242
|
+
function bypassArgs(agent, _runKind) {
|
|
1243
|
+
switch (agent) {
|
|
1244
|
+
case "codex":
|
|
1245
|
+
return ["-s", "danger-full-access"];
|
|
1246
|
+
case "antigravity":
|
|
1247
|
+
case "claude":
|
|
1248
|
+
default:
|
|
1249
|
+
return ["--dangerously-skip-permissions"];
|
|
1250
|
+
}
|
|
1251
|
+
}
|
|
1252
|
+
function describePermissionMode(res) {
|
|
1253
|
+
if (res.mappedToBypassForLackOfSandbox) {
|
|
1254
|
+
return "bypass (no scoped sandbox for this agent \u2014 full access)";
|
|
1255
|
+
}
|
|
1256
|
+
switch (res.effectiveMode) {
|
|
1257
|
+
case "auto":
|
|
1258
|
+
return "auto (scoped: acceptEdits + destructive-command deny-list)";
|
|
1259
|
+
case "plan":
|
|
1260
|
+
return "plan (read-only)";
|
|
1261
|
+
case "bypass":
|
|
1262
|
+
return "bypass (--dangerously-skip-permissions \u2014 full access)";
|
|
1263
|
+
}
|
|
1264
|
+
}
|
|
1265
|
+
|
|
1154
1266
|
// lib/task-workflow.ts
|
|
1155
1267
|
function normalizeWhitespace(value) {
|
|
1156
1268
|
return value.replace(/\s+/g, " ").trim();
|
|
@@ -1303,6 +1415,22 @@ function tokenLogLine(jobType, identifier, prompt2, systemPrompt) {
|
|
|
1303
1415
|
return parts[0];
|
|
1304
1416
|
}
|
|
1305
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
|
+
|
|
1306
1434
|
// cli/commands/watch.ts
|
|
1307
1435
|
var FEATURES_FILE2 = ".mr-features.md";
|
|
1308
1436
|
var SYSTEM_SECTION_STATUS_UPDATES = `## Status Updates
|
|
@@ -1449,7 +1577,6 @@ var SYSTEM_SECTIONS = {
|
|
|
1449
1577
|
function composeSystemPrompt(sections) {
|
|
1450
1578
|
return sections.map((s) => SYSTEM_SECTIONS[s]).join("\n\n");
|
|
1451
1579
|
}
|
|
1452
|
-
var EXECUTION_SYSTEM_SECTIONS = ["status-updates", "screenshots", "test-plan", "mr-tests", "no-mr", "features-workflow"];
|
|
1453
1580
|
var PRD_SYSTEM_SECTIONS = ["prd-format", "prd-open-questions"];
|
|
1454
1581
|
var c = {
|
|
1455
1582
|
reset: "\x1B[0m",
|
|
@@ -2851,41 +2978,46 @@ function buildRefinementPrompt(proto, parentFiles, repoDir, options = {}) {
|
|
|
2851
2978
|
].join("\n");
|
|
2852
2979
|
}
|
|
2853
2980
|
function buildAgentArgs(agent, prompt2, mode, sessionId, name, resumeSession = false, systemPrompt, maxTurns, claudeModel) {
|
|
2981
|
+
const headlessMode = resolveHeadlessMode(loadConfig());
|
|
2982
|
+
const runKind = mode === "plan" ? "plan" : "execute";
|
|
2854
2983
|
if (agent === "codex") {
|
|
2984
|
+
const permission2 = resolvePermissionArgs("codex", runKind, headlessMode);
|
|
2855
2985
|
const args = [];
|
|
2856
2986
|
if (mode === "execute") {
|
|
2857
2987
|
args.push("-a", "never");
|
|
2858
2988
|
}
|
|
2859
2989
|
args.push("exec");
|
|
2860
2990
|
if (mode === "execute") {
|
|
2861
|
-
args.push(
|
|
2991
|
+
args.push(...permission2.args);
|
|
2862
2992
|
}
|
|
2863
2993
|
const fullPrompt = systemPrompt ? `${prompt2}
|
|
2864
2994
|
|
|
2865
2995
|
${systemPrompt}` : prompt2;
|
|
2866
2996
|
args.push(fullPrompt);
|
|
2867
|
-
return { bin: "codex", args };
|
|
2997
|
+
return { bin: "codex", args, permission: permission2 };
|
|
2868
2998
|
}
|
|
2869
2999
|
if (agent === "antigravity") {
|
|
3000
|
+
const permission2 = resolvePermissionArgs("antigravity", runKind, headlessMode);
|
|
2870
3001
|
const fullPrompt = systemPrompt ? `${prompt2}
|
|
2871
3002
|
|
|
2872
3003
|
${systemPrompt}` : prompt2;
|
|
2873
3004
|
const args = ["-p", fullPrompt];
|
|
2874
3005
|
if (mode === "execute") {
|
|
2875
|
-
args.push(
|
|
3006
|
+
args.push(...permission2.args);
|
|
2876
3007
|
}
|
|
2877
|
-
return { bin: AGENT_BINARIES.antigravity, args };
|
|
3008
|
+
return { bin: AGENT_BINARIES.antigravity, args, permission: permission2 };
|
|
2878
3009
|
}
|
|
3010
|
+
const permission = resolvePermissionArgs("claude", runKind, headlessMode);
|
|
2879
3011
|
const sessionArgs = sessionId ? resumeSession ? ["--resume", sessionId] : ["--session-id", sessionId] : [];
|
|
2880
3012
|
const nameArgs = name ? ["--name", name] : [];
|
|
2881
3013
|
const systemArgs = systemPrompt ? ["--append-system-prompt", systemPrompt] : [];
|
|
2882
3014
|
const turnsArgs = maxTurns ? ["--max-turns", String(maxTurns)] : [];
|
|
2883
3015
|
const modelArgs = claudeModel ? ["--model", claudeModel] : [];
|
|
2884
|
-
|
|
2885
|
-
|
|
2886
|
-
|
|
2887
|
-
|
|
2888
|
-
|
|
3016
|
+
return {
|
|
3017
|
+
bin: "claude",
|
|
3018
|
+
args: [...sessionArgs, ...nameArgs, ...systemArgs, ...turnsArgs, ...modelArgs, ...permission.args, "-p", prompt2],
|
|
3019
|
+
permission
|
|
3020
|
+
};
|
|
2889
3021
|
}
|
|
2890
3022
|
var AGENT_BINARIES = {
|
|
2891
3023
|
claude: "claude",
|
|
@@ -2968,7 +3100,13 @@ function askYesNo(question) {
|
|
|
2968
3100
|
function spawnAgent(agent, repoDir, prompt2, prefix, onActivity, sessionId, name, resumeSession = false, onSpawnError, systemPrompt, maxTurns, claudeModel, onOutputBytes) {
|
|
2969
3101
|
const jobLabel = name ?? "unknown";
|
|
2970
3102
|
console.log(`${timestamp()} ${prefix} ${paint("dim", tokenLogLine("agent", jobLabel, prompt2, systemPrompt))}`);
|
|
2971
|
-
const { bin, args } = buildAgentArgs(agent, prompt2, "execute", sessionId, name, resumeSession, systemPrompt, maxTurns, claudeModel);
|
|
3103
|
+
const { bin, args, permission } = buildAgentArgs(agent, prompt2, "execute", sessionId, name, resumeSession, systemPrompt, maxTurns, claudeModel);
|
|
3104
|
+
const permLine = `${timestamp()} ${prefix} ${paint("dim", `permission: ${describePermissionMode(permission)}`)}`;
|
|
3105
|
+
if (permission.mappedToBypassForLackOfSandbox) {
|
|
3106
|
+
logWarn(prefix, `permission: ${describePermissionMode(permission)}`);
|
|
3107
|
+
} else {
|
|
3108
|
+
console.log(permLine);
|
|
3109
|
+
}
|
|
2972
3110
|
const child = spawn4(bin, args, { cwd: repoDir, stdio: ["ignore", "pipe", "pipe"] });
|
|
2973
3111
|
child.on("error", (err) => {
|
|
2974
3112
|
logError(prefix, `Failed to spawn ${agent}: ${err.message}`);
|
|
@@ -3000,13 +3138,14 @@ function spawnAgent(agent, repoDir, prompt2, prefix, onActivity, sessionId, name
|
|
|
3000
3138
|
}
|
|
3001
3139
|
var watchCommand = new Command9("watch").description(
|
|
3002
3140
|
"Watch for in-progress tasks and autonomously dispatch an AI coding agent to work on them"
|
|
3003
|
-
).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) => {
|
|
3004
3142
|
const intervalMs = parseInt(opts.interval, 10) * 1e3;
|
|
3005
3143
|
const dryRun = opts.dryRun;
|
|
3006
3144
|
const planApproval = opts.planApproval;
|
|
3007
3145
|
const rootDir = opts.root ? resolve2(opts.root) : process.cwd();
|
|
3008
3146
|
const agent = opts.agent === "codex" ? "codex" : opts.agent === "antigravity" ? "antigravity" : "claude";
|
|
3009
3147
|
const scanAt = opts.scanAt;
|
|
3148
|
+
const includeTestPlan = opts.testPlan;
|
|
3010
3149
|
const taskStallTimeoutMs = getTaskStallTimeoutMs();
|
|
3011
3150
|
const hungTaskTimeoutMinutes = Math.max(5, parseInt(process.env.MR_WATCH_HUNG_TASK_TIMEOUT_MINUTES ?? "60", 10) || 60);
|
|
3012
3151
|
const hungTaskTimeoutMs = hungTaskTimeoutMinutes * 6e4;
|
|
@@ -3028,6 +3167,7 @@ var watchCommand = new Command9("watch").description(
|
|
|
3028
3167
|
...planApproval ? [paint("yellow", "plan-approval")] : [],
|
|
3029
3168
|
...dryRun ? [paint("yellow", "dry-run")] : [],
|
|
3030
3169
|
...scanAt ? [`scan-at=${paint("cyan", scanAt)}`] : [],
|
|
3170
|
+
...includeTestPlan ? [paint("yellow", "test-plan")] : [],
|
|
3031
3171
|
`hung-timeout=${paint("cyan", `${hungTaskTimeoutMinutes}m`)}`
|
|
3032
3172
|
].join(" ");
|
|
3033
3173
|
const banner = [
|
|
@@ -3262,7 +3402,7 @@ var watchCommand = new Command9("watch").description(
|
|
|
3262
3402
|
const shouldResumeClaudeSession = attemptAgent === "claude" && !!task.claudeSessionId && !resumeAlreadyRetried && (hasFeedback || pausedForNetwork?.resumeSession === true);
|
|
3263
3403
|
const sessionId = attemptAgent === "claude" ? shouldResumeClaudeSession ? task.claudeSessionId : randomUUID() : void 0;
|
|
3264
3404
|
const effectiveClaudeModel = attemptAgent === "claude" ? taskClaudeModel : void 0;
|
|
3265
|
-
const systemSections =
|
|
3405
|
+
const systemSections = getExecutionSystemSections(includeTestPlan);
|
|
3266
3406
|
const executionSystemPrompt = composeSystemPrompt(systemSections);
|
|
3267
3407
|
const child = spawnAgent(
|
|
3268
3408
|
attemptAgent,
|
|
@@ -4020,6 +4160,7 @@ var watchCommand = new Command9("watch").description(
|
|
|
4020
4160
|
function dispatchCodeReview(review, prefix, key) {
|
|
4021
4161
|
logDispatch(prefix, `Running code review on branch ${paint("cyan", review.branch)}`);
|
|
4022
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);
|
|
4023
4164
|
if (review.branchUrl) reviewArgs.push("--pr-url", review.branchUrl);
|
|
4024
4165
|
if (review.prNumber != null) reviewArgs.push("--pr-number", String(review.prNumber));
|
|
4025
4166
|
const reviewProc = spawn4(process.execPath, reviewArgs, {
|
|
@@ -4857,9 +4998,125 @@ var completeCommand = new Command12("complete").description("Mark a task as comp
|
|
|
4857
4998
|
printTaskBanner2(paint3("green", "complete \u2713"), task.title, task.id);
|
|
4858
4999
|
});
|
|
4859
5000
|
|
|
4860
|
-
// cli/commands/
|
|
5001
|
+
// cli/commands/show.ts
|
|
4861
5002
|
import { Command as Command13 } from "commander";
|
|
4862
|
-
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) => {
|
|
4863
5120
|
const subtask = await api.patch(
|
|
4864
5121
|
`/api/tasks/${taskId}/subtasks/${subtaskId}`,
|
|
4865
5122
|
{ completed: true }
|
|
@@ -4868,8 +5125,8 @@ var subtaskCompleteCommand = new Command13("subtask-complete").description("Mark
|
|
|
4868
5125
|
});
|
|
4869
5126
|
|
|
4870
5127
|
// cli/commands/subtask-add.ts
|
|
4871
|
-
import { Command as
|
|
4872
|
-
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) => {
|
|
4873
5130
|
const title = titleParts.join(" ").trim();
|
|
4874
5131
|
if (!title) {
|
|
4875
5132
|
console.error("Subtask title is required.");
|
|
@@ -4882,8 +5139,8 @@ var subtaskAddCommand = new Command14("subtask-add").description("Add a subtask
|
|
|
4882
5139
|
});
|
|
4883
5140
|
|
|
4884
5141
|
// cli/commands/prototype.ts
|
|
4885
|
-
import { Command as
|
|
4886
|
-
var
|
|
5142
|
+
import { Command as Command18 } from "commander";
|
|
5143
|
+
var c5 = {
|
|
4887
5144
|
reset: "\x1B[0m",
|
|
4888
5145
|
bold: "\x1B[1m",
|
|
4889
5146
|
dim: "\x1B[2m",
|
|
@@ -4895,7 +5152,7 @@ var c4 = {
|
|
|
4895
5152
|
gray: "\x1B[90m"
|
|
4896
5153
|
};
|
|
4897
5154
|
function paint4(color, text) {
|
|
4898
|
-
return `${
|
|
5155
|
+
return `${c5[color]}${text}${c5.reset}`;
|
|
4899
5156
|
}
|
|
4900
5157
|
function statusBadge(status) {
|
|
4901
5158
|
switch (status) {
|
|
@@ -4911,8 +5168,8 @@ function statusBadge(status) {
|
|
|
4911
5168
|
return paint4("gray", status);
|
|
4912
5169
|
}
|
|
4913
5170
|
}
|
|
4914
|
-
var prototypeCommand = new
|
|
4915
|
-
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) => {
|
|
4916
5173
|
const params = new URLSearchParams();
|
|
4917
5174
|
if (!opts.all) {
|
|
4918
5175
|
const projectId = getLinkedProjectId();
|
|
@@ -4946,7 +5203,7 @@ var prototypeCommand = new Command15("prototype").description("Manage prototypes
|
|
|
4946
5203
|
}
|
|
4947
5204
|
})
|
|
4948
5205
|
).addCommand(
|
|
4949
|
-
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) => {
|
|
4950
5207
|
const projectId = opts.project ?? getLinkedProjectId();
|
|
4951
5208
|
const variantCount = Math.max(1, Math.min(50, parseInt(opts.variants, 10) || 5));
|
|
4952
5209
|
const validTypes = ["web_app", "mobile_app", "desktop_app", "logo"];
|
|
@@ -4987,7 +5244,7 @@ var prototypeCommand = new Command15("prototype").description("Manage prototypes
|
|
|
4987
5244
|
console.log();
|
|
4988
5245
|
})
|
|
4989
5246
|
).addCommand(
|
|
4990
|
-
new
|
|
5247
|
+
new Command18("start").description("Start prototype generation (sets status to in_progress)").argument("<id>", "Prototype ID").action(async (id) => {
|
|
4991
5248
|
const prototype = await api.patch(`/api/prototypes/${id}`, {
|
|
4992
5249
|
status: "in_progress"
|
|
4993
5250
|
});
|
|
@@ -4997,7 +5254,7 @@ var prototypeCommand = new Command15("prototype").description("Manage prototypes
|
|
|
4997
5254
|
console.log();
|
|
4998
5255
|
})
|
|
4999
5256
|
).addCommand(
|
|
5000
|
-
new
|
|
5257
|
+
new Command18("retry").description("Retry a failed prototype").argument("<id>", "Prototype ID").action(async (id) => {
|
|
5001
5258
|
const prototype = await api.patch(`/api/prototypes/${id}`, {
|
|
5002
5259
|
status: "in_progress",
|
|
5003
5260
|
files: null
|
|
@@ -5009,9 +5266,9 @@ var prototypeCommand = new Command15("prototype").description("Manage prototypes
|
|
|
5009
5266
|
);
|
|
5010
5267
|
|
|
5011
5268
|
// cli/commands/setup.ts
|
|
5012
|
-
import { Command as
|
|
5269
|
+
import { Command as Command19 } from "commander";
|
|
5013
5270
|
import { exec as exec2 } from "child_process";
|
|
5014
|
-
var
|
|
5271
|
+
var c6 = {
|
|
5015
5272
|
reset: "\x1B[0m",
|
|
5016
5273
|
bold: "\x1B[1m",
|
|
5017
5274
|
dim: "\x1B[2m",
|
|
@@ -5023,7 +5280,7 @@ var c5 = {
|
|
|
5023
5280
|
gray: "\x1B[90m"
|
|
5024
5281
|
};
|
|
5025
5282
|
function paint5(color, text) {
|
|
5026
|
-
return `${
|
|
5283
|
+
return `${c6[color]}${text}${c6.reset}`;
|
|
5027
5284
|
}
|
|
5028
5285
|
function commandExists2(cmd) {
|
|
5029
5286
|
return new Promise((resolve9) => {
|
|
@@ -5267,7 +5524,7 @@ async function checkApiConnectivity() {
|
|
|
5267
5524
|
}
|
|
5268
5525
|
}
|
|
5269
5526
|
function printResults(checks) {
|
|
5270
|
-
const maxNameLen = Math.max(...checks.map((
|
|
5527
|
+
const maxNameLen = Math.max(...checks.map((c15) => c15.name.length));
|
|
5271
5528
|
let allOk = true;
|
|
5272
5529
|
for (const check of checks) {
|
|
5273
5530
|
const isOptional = check.optional ?? false;
|
|
@@ -5281,10 +5538,10 @@ function printResults(checks) {
|
|
|
5281
5538
|
}
|
|
5282
5539
|
async function autoFix(checks, agent) {
|
|
5283
5540
|
const { spawn: spawn9 } = await import("child_process");
|
|
5284
|
-
const ghInstalled = checks.find((
|
|
5285
|
-
const ghAuthed = checks.find((
|
|
5286
|
-
const mrAuthed = checks.find((
|
|
5287
|
-
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)");
|
|
5288
5545
|
if (claudeCheck && !claudeCheck.ok && agent === "claude") {
|
|
5289
5546
|
console.log(paint5("cyan", " Installing Claude Code..."));
|
|
5290
5547
|
console.log(paint5("dim", " Running: curl -fsSL https://claude.ai/install.sh | bash"));
|
|
@@ -5312,7 +5569,7 @@ async function autoFix(checks, agent) {
|
|
|
5312
5569
|
console.log("");
|
|
5313
5570
|
}
|
|
5314
5571
|
}
|
|
5315
|
-
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) => {
|
|
5316
5573
|
const agent = opts.agent === "codex" ? "codex" : opts.agent === "antigravity" ? "antigravity" : "claude";
|
|
5317
5574
|
const banner = [
|
|
5318
5575
|
``,
|
|
@@ -5347,7 +5604,7 @@ var setupCommand = new Command16("setup").description("Check that all dependenci
|
|
|
5347
5604
|
console.log("");
|
|
5348
5605
|
return;
|
|
5349
5606
|
}
|
|
5350
|
-
const fixes = checks.filter((
|
|
5607
|
+
const fixes = checks.filter((c15) => !c15.ok && c15.fix && !c15.optional);
|
|
5351
5608
|
if (fixes.length > 0) {
|
|
5352
5609
|
console.log(paint5("yellow", " To fix:"));
|
|
5353
5610
|
for (const fix of fixes) {
|
|
@@ -5362,8 +5619,8 @@ var setupCommand = new Command16("setup").description("Check that all dependenci
|
|
|
5362
5619
|
});
|
|
5363
5620
|
|
|
5364
5621
|
// cli/commands/update.ts
|
|
5365
|
-
import { Command as
|
|
5366
|
-
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) => {
|
|
5367
5624
|
if (opts.resource) {
|
|
5368
5625
|
if (!messageOrTitle || !content) {
|
|
5369
5626
|
console.error(`Usage: mr update <task-id> --resource <type> "<title>" '<content>'`);
|
|
@@ -5389,11 +5646,11 @@ var updateCommand = new Command17("update").description("Post a status update to
|
|
|
5389
5646
|
});
|
|
5390
5647
|
|
|
5391
5648
|
// cli/commands/screenshot.ts
|
|
5392
|
-
import { Command as
|
|
5649
|
+
import { Command as Command21 } from "commander";
|
|
5393
5650
|
import { readFileSync as readFileSync6, existsSync as existsSync8, unlinkSync as unlinkSync2 } from "fs";
|
|
5394
5651
|
import { join as join7 } from "path";
|
|
5395
5652
|
import { tmpdir } from "os";
|
|
5396
|
-
var screenshotCommand = new
|
|
5653
|
+
var screenshotCommand = new Command21("screenshot").description(
|
|
5397
5654
|
"Take or attach a screenshot to a task update (agents use this to show their work)"
|
|
5398
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) => {
|
|
5399
5656
|
let filePath = file;
|
|
@@ -5484,10 +5741,10 @@ var screenshotCommand = new Command18("screenshot").description(
|
|
|
5484
5741
|
});
|
|
5485
5742
|
|
|
5486
5743
|
// cli/commands/resume.ts
|
|
5487
|
-
import { Command as
|
|
5744
|
+
import { Command as Command22 } from "commander";
|
|
5488
5745
|
import { spawn as spawn5 } from "child_process";
|
|
5489
5746
|
import { resolve as resolve3 } from "path";
|
|
5490
|
-
var
|
|
5747
|
+
var c7 = {
|
|
5491
5748
|
reset: "\x1B[0m",
|
|
5492
5749
|
bold: "\x1B[1m",
|
|
5493
5750
|
dim: "\x1B[2m",
|
|
@@ -5499,9 +5756,9 @@ var c6 = {
|
|
|
5499
5756
|
gray: "\x1B[90m"
|
|
5500
5757
|
};
|
|
5501
5758
|
function paint6(color, text) {
|
|
5502
|
-
return `${
|
|
5759
|
+
return `${c7[color]}${text}${c7.reset}`;
|
|
5503
5760
|
}
|
|
5504
|
-
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) => {
|
|
5505
5762
|
const task = await api.get(`/api/tasks/${taskId}`);
|
|
5506
5763
|
if (!task.claudeSessionId) {
|
|
5507
5764
|
console.error(
|
|
@@ -5570,7 +5827,7 @@ var resumeCommand = new Command19("resume").description("Resume an interactive C
|
|
|
5570
5827
|
});
|
|
5571
5828
|
|
|
5572
5829
|
// cli/commands/browse.ts
|
|
5573
|
-
import { Command as
|
|
5830
|
+
import { Command as Command23 } from "commander";
|
|
5574
5831
|
import { execSync as execSync4, spawn as spawn6 } from "child_process";
|
|
5575
5832
|
import { existsSync as existsSync9, readFileSync as readFileSync7, writeFileSync as writeFileSync4 } from "fs";
|
|
5576
5833
|
import { createHash } from "crypto";
|
|
@@ -5685,7 +5942,7 @@ async function ensureDevServer(options = {}) {
|
|
|
5685
5942
|
}
|
|
5686
5943
|
throw new Error(`Dev server failed to start within 60s. Command: ${devCmd} in ${projectCwd}`);
|
|
5687
5944
|
}
|
|
5688
|
-
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(
|
|
5689
5946
|
"--task-id <id>",
|
|
5690
5947
|
"Attach output to a task update (for screenshot and recording-stop commands)"
|
|
5691
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(
|
|
@@ -5828,10 +6085,10 @@ var browseCommand = new Command20("browse").description("Control a headless brow
|
|
|
5828
6085
|
);
|
|
5829
6086
|
|
|
5830
6087
|
// cli/commands/set-path.ts
|
|
5831
|
-
import { Command as
|
|
6088
|
+
import { Command as Command24 } from "commander";
|
|
5832
6089
|
import { resolve as resolve5 } from "path";
|
|
5833
6090
|
import { existsSync as existsSync10 } from "fs";
|
|
5834
|
-
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) => {
|
|
5835
6092
|
const absolutePath = resolve5(pathArg);
|
|
5836
6093
|
if (!existsSync10(absolutePath)) {
|
|
5837
6094
|
console.error(`Error: Path does not exist: ${absolutePath}`);
|
|
@@ -5849,9 +6106,9 @@ var setPathCommand = new Command21("set-path").description("Set or update the lo
|
|
|
5849
6106
|
});
|
|
5850
6107
|
|
|
5851
6108
|
// cli/commands/test.ts
|
|
5852
|
-
import { Command as
|
|
6109
|
+
import { Command as Command25 } from "commander";
|
|
5853
6110
|
import { readFileSync as readFileSync8, existsSync as existsSync11 } from "fs";
|
|
5854
|
-
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) => {
|
|
5855
6112
|
const config = loadConfig();
|
|
5856
6113
|
console.log("[test] Fetching task...");
|
|
5857
6114
|
let task;
|
|
@@ -6013,11 +6270,11 @@ var testCommand = new Command22("test").description("Run automated browser test
|
|
|
6013
6270
|
});
|
|
6014
6271
|
|
|
6015
6272
|
// cli/commands/features.ts
|
|
6016
|
-
import { Command as
|
|
6273
|
+
import { Command as Command26 } from "commander";
|
|
6017
6274
|
import { readFileSync as readFileSync9, writeFileSync as writeFileSync5, existsSync as existsSync12 } from "fs";
|
|
6018
6275
|
import { resolve as resolve6, sep as sep2 } from "path";
|
|
6019
6276
|
var FEATURES_FILE3 = ".mr-features.md";
|
|
6020
|
-
var
|
|
6277
|
+
var c8 = {
|
|
6021
6278
|
reset: "\x1B[0m",
|
|
6022
6279
|
bold: "\x1B[1m",
|
|
6023
6280
|
dim: "\x1B[2m",
|
|
@@ -6028,7 +6285,7 @@ var c7 = {
|
|
|
6028
6285
|
gray: "\x1B[90m"
|
|
6029
6286
|
};
|
|
6030
6287
|
function paint7(color, text) {
|
|
6031
|
-
return `${
|
|
6288
|
+
return `${c8[color]}${text}${c8.reset}`;
|
|
6032
6289
|
}
|
|
6033
6290
|
function resolveProjectRoot2() {
|
|
6034
6291
|
const cwd = process.cwd();
|
|
@@ -6047,7 +6304,7 @@ function readFeatures2() {
|
|
|
6047
6304
|
if (!existsSync12(path)) return null;
|
|
6048
6305
|
return readFileSync9(path, "utf-8");
|
|
6049
6306
|
}
|
|
6050
|
-
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) => {
|
|
6051
6308
|
if (opts.path) {
|
|
6052
6309
|
console.log(getFeaturesPath());
|
|
6053
6310
|
return;
|
|
@@ -6075,11 +6332,11 @@ var featuresCommand = new Command23("features").description("View or update the
|
|
|
6075
6332
|
});
|
|
6076
6333
|
|
|
6077
6334
|
// cli/commands/no-mr.ts
|
|
6078
|
-
import { Command as
|
|
6335
|
+
import { Command as Command27 } from "commander";
|
|
6079
6336
|
import { writeFileSync as writeFileSync6 } from "fs";
|
|
6080
6337
|
import { resolve as resolve7 } from "path";
|
|
6081
6338
|
var NO_MR_FILE = ".mr-no-mr";
|
|
6082
|
-
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) => {
|
|
6083
6340
|
const filePath = resolve7(process.cwd(), NO_MR_FILE);
|
|
6084
6341
|
writeFileSync6(filePath, description, "utf-8");
|
|
6085
6342
|
await api.post(`/api/tasks/${taskId}/updates`, {
|
|
@@ -6091,12 +6348,12 @@ var noMrCommand = new Command24("no-mr").description("Signal that a task does no
|
|
|
6091
6348
|
});
|
|
6092
6349
|
|
|
6093
6350
|
// cli/commands/review.ts
|
|
6094
|
-
import { Command as
|
|
6351
|
+
import { Command as Command29 } from "commander";
|
|
6095
6352
|
import { execSync as execSync6 } from "child_process";
|
|
6096
6353
|
import { existsSync as existsSync14, statSync as statSync2 } from "fs";
|
|
6097
6354
|
|
|
6098
6355
|
// cli/commands/review-apply.ts
|
|
6099
|
-
import { Command as
|
|
6356
|
+
import { Command as Command28 } from "commander";
|
|
6100
6357
|
import { execSync as execSync5 } from "child_process";
|
|
6101
6358
|
import { existsSync as existsSync13 } from "fs";
|
|
6102
6359
|
|
|
@@ -6119,18 +6376,26 @@ async function resolveReviewAgentChain(preferred2 = "claude") {
|
|
|
6119
6376
|
}
|
|
6120
6377
|
return getAvailableAgentFallbackChain(preferred2, availability);
|
|
6121
6378
|
}
|
|
6122
|
-
function buildArgs(agent, prompt2) {
|
|
6379
|
+
function buildArgs(agent, prompt2, runKind) {
|
|
6380
|
+
const mode = resolveHeadlessMode(loadConfig());
|
|
6381
|
+
const permission = resolvePermissionArgs(agent, runKind, mode);
|
|
6123
6382
|
if (agent === "codex") {
|
|
6124
|
-
return ["-a", "never", "exec",
|
|
6383
|
+
return ["-a", "never", "exec", ...permission.args, prompt2];
|
|
6125
6384
|
}
|
|
6126
6385
|
if (agent === "antigravity") {
|
|
6127
|
-
return ["-p", prompt2,
|
|
6386
|
+
return ["-p", prompt2, ...permission.args];
|
|
6128
6387
|
}
|
|
6129
|
-
return ["-p",
|
|
6388
|
+
return ["-p", ...permission.args, prompt2];
|
|
6389
|
+
}
|
|
6390
|
+
function logPermission(agent, runKind) {
|
|
6391
|
+
const permission = resolvePermissionArgs(agent, runKind, resolveHeadlessMode(loadConfig()));
|
|
6392
|
+
const label = permission.mappedToBypassForLackOfSandbox ? "warning" : "info";
|
|
6393
|
+
console.error(`[review:${label}] ${agent} ${runKind} permission: ${describePermissionMode(permission)}`);
|
|
6130
6394
|
}
|
|
6131
6395
|
function runOnce(agent, prompt2, opts) {
|
|
6132
6396
|
return new Promise((resolve9) => {
|
|
6133
|
-
|
|
6397
|
+
logPermission(agent, opts.runKind);
|
|
6398
|
+
const child = spawn7(AGENT_BINARIES2[agent], buildArgs(agent, prompt2, opts.runKind), {
|
|
6134
6399
|
cwd: opts.cwd,
|
|
6135
6400
|
stdio: opts.capture ? ["ignore", "pipe", "pipe"] : ["ignore", "inherit", "inherit"]
|
|
6136
6401
|
});
|
|
@@ -6156,7 +6421,7 @@ async function runAgentCaptured(prompt2, opts) {
|
|
|
6156
6421
|
}
|
|
6157
6422
|
let lastError = "";
|
|
6158
6423
|
for (const agent of opts.chain) {
|
|
6159
|
-
const result = await runOnce(agent, prompt2, { cwd: opts.cwd, capture: true });
|
|
6424
|
+
const result = await runOnce(agent, prompt2, { cwd: opts.cwd, capture: true, runKind: "review" });
|
|
6160
6425
|
if (result.ok && result.output) {
|
|
6161
6426
|
return { output: result.output, agent };
|
|
6162
6427
|
}
|
|
@@ -6170,7 +6435,7 @@ async function runAgentInteractive(prompt2, opts) {
|
|
|
6170
6435
|
}
|
|
6171
6436
|
let lastError = "";
|
|
6172
6437
|
for (const agent of opts.chain) {
|
|
6173
|
-
const result = await runOnce(agent, prompt2, { cwd: opts.cwd, capture: false });
|
|
6438
|
+
const result = await runOnce(agent, prompt2, { cwd: opts.cwd, capture: false, runKind: "execute" });
|
|
6174
6439
|
if (result.ok) return { agent };
|
|
6175
6440
|
lastError = result.spawnError ? `${agent} could not be spawned` : `${agent} exited non-zero`;
|
|
6176
6441
|
}
|
|
@@ -6178,7 +6443,7 @@ async function runAgentInteractive(prompt2, opts) {
|
|
|
6178
6443
|
}
|
|
6179
6444
|
|
|
6180
6445
|
// cli/commands/review-apply.ts
|
|
6181
|
-
var
|
|
6446
|
+
var c9 = {
|
|
6182
6447
|
reset: "\x1B[0m",
|
|
6183
6448
|
dim: "\x1B[2m",
|
|
6184
6449
|
cyan: "\x1B[36m",
|
|
@@ -6190,7 +6455,7 @@ var c8 = {
|
|
|
6190
6455
|
magenta: "\x1B[35m"
|
|
6191
6456
|
};
|
|
6192
6457
|
function paint8(color, text) {
|
|
6193
|
-
return `${
|
|
6458
|
+
return `${c9[color]}${text}${c9.reset}`;
|
|
6194
6459
|
}
|
|
6195
6460
|
function timestamp2() {
|
|
6196
6461
|
return paint8("gray", (/* @__PURE__ */ new Date()).toLocaleTimeString("en-US", { hour12: false }));
|
|
@@ -6207,7 +6472,7 @@ function logOk(msg) {
|
|
|
6207
6472
|
function logErr(msg) {
|
|
6208
6473
|
console.error(`${timestamp2()} ${tag()} ${paint8("red", "\u2717")} ${msg}`);
|
|
6209
6474
|
}
|
|
6210
|
-
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) => {
|
|
6211
6476
|
const config = loadConfig();
|
|
6212
6477
|
if (!config.apiKey) {
|
|
6213
6478
|
logErr('Not authenticated. Run "mr login" first.');
|
|
@@ -6227,7 +6492,7 @@ var reviewApplyCommand = new Command25("apply").description("Apply review commen
|
|
|
6227
6492
|
logErr("Review has no comments or findings to act on.");
|
|
6228
6493
|
process.exit(1);
|
|
6229
6494
|
}
|
|
6230
|
-
const actionableComments = comments.filter((
|
|
6495
|
+
const actionableComments = comments.filter((c15) => !excluded.has(c15.file));
|
|
6231
6496
|
const dismissedCount = findings.filter((f) => f.status === "dismissed").length;
|
|
6232
6497
|
const actionableFindings = findings.filter(
|
|
6233
6498
|
(f) => !excluded.has(f.file) && f.status !== "dismissed"
|
|
@@ -6265,7 +6530,7 @@ var reviewApplyCommand = new Command25("apply").description("Apply review commen
|
|
|
6265
6530
|
}
|
|
6266
6531
|
const touchedFiles = Array.from(
|
|
6267
6532
|
new Set([
|
|
6268
|
-
...actionableComments.map((
|
|
6533
|
+
...actionableComments.map((c15) => c15.file),
|
|
6269
6534
|
...actionableFindings.map((f) => f.file)
|
|
6270
6535
|
].filter(Boolean))
|
|
6271
6536
|
);
|
|
@@ -6405,9 +6670,9 @@ function buildApplyPrompt(args) {
|
|
|
6405
6670
|
}
|
|
6406
6671
|
if (args.comments.length > 0) {
|
|
6407
6672
|
lines.push("USER COMMENTS:");
|
|
6408
|
-
for (const
|
|
6409
|
-
const where =
|
|
6410
|
-
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}`);
|
|
6411
6676
|
}
|
|
6412
6677
|
lines.push("");
|
|
6413
6678
|
}
|
|
@@ -6661,6 +6926,37 @@ function buildDimensionPrompt(args) {
|
|
|
6661
6926
|
lines.push(JSON_CONTRACT, "", "Here is the diff to review:", "", "```diff", args.diff, "```");
|
|
6662
6927
|
return lines.join("\n");
|
|
6663
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
|
+
}
|
|
6664
6960
|
function buildVerificationPrompt(args) {
|
|
6665
6961
|
const compact = args.findings.map((f) => ({
|
|
6666
6962
|
id: f.id,
|
|
@@ -6701,6 +6997,41 @@ function buildVerificationPrompt(args) {
|
|
|
6701
6997
|
return lines.join("\n");
|
|
6702
6998
|
}
|
|
6703
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
|
+
|
|
6704
7035
|
// lib/review/orchestrate.ts
|
|
6705
7036
|
function splitDiffByFile(diff) {
|
|
6706
7037
|
const sections = diff.split(/(?=^diff --git )/m).filter((s) => s.trim());
|
|
@@ -6721,7 +7052,10 @@ async function pool(items, limit) {
|
|
|
6721
7052
|
await Promise.all(workers);
|
|
6722
7053
|
return results;
|
|
6723
7054
|
}
|
|
6724
|
-
function buildJobs(opts) {
|
|
7055
|
+
function buildJobs(opts, fanOut) {
|
|
7056
|
+
if (!fanOut) {
|
|
7057
|
+
return [{ dimension: null, diff: opts.diff }];
|
|
7058
|
+
}
|
|
6725
7059
|
const files = splitDiffByFile(opts.diff);
|
|
6726
7060
|
const shardThreshold = opts.shardThreshold ?? 12;
|
|
6727
7061
|
if (files.length >= shardThreshold) {
|
|
@@ -6750,40 +7084,63 @@ async function orchestrateReview(opts) {
|
|
|
6750
7084
|
});
|
|
6751
7085
|
const concurrency = opts.concurrency ?? 4;
|
|
6752
7086
|
const canReadFiles = Boolean(opts.cwd);
|
|
6753
|
-
const
|
|
6754
|
-
const jobs = buildJobs(opts);
|
|
6755
|
-
|
|
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
|
+
);
|
|
6756
7099
|
const summaries = [];
|
|
6757
7100
|
const collected = [];
|
|
6758
7101
|
const jobResults = await pool(
|
|
6759
|
-
|
|
6760
|
-
const prompt2 = buildDimensionPrompt({
|
|
7102
|
+
tasks.map(({ job, agent }) => async () => {
|
|
7103
|
+
const prompt2 = job.dimension ? buildDimensionPrompt({
|
|
6761
7104
|
dimension: job.dimension,
|
|
6762
7105
|
branch: opts.branch,
|
|
6763
7106
|
baseBranch: opts.baseBranch,
|
|
6764
7107
|
diff: job.diff,
|
|
6765
7108
|
canReadFiles,
|
|
6766
7109
|
fileScope: job.fileScope
|
|
7110
|
+
}) : buildLightPrompt({
|
|
7111
|
+
branch: opts.branch,
|
|
7112
|
+
baseBranch: opts.baseBranch,
|
|
7113
|
+
diff: job.diff,
|
|
7114
|
+
canReadFiles
|
|
6767
7115
|
});
|
|
7116
|
+
const runOpts = {
|
|
7117
|
+
cwd: opts.cwd,
|
|
7118
|
+
chain: depthConfig.multiAgent ? [agent] : opts.chain
|
|
7119
|
+
};
|
|
6768
7120
|
try {
|
|
6769
|
-
const { output } = await runAgentCaptured(prompt2, runOpts);
|
|
7121
|
+
const { output, agent: usedAgent } = await runAgentCaptured(prompt2, runOpts);
|
|
6770
7122
|
const parsed = parseReviewOutput(output);
|
|
6771
|
-
return { job, parsed };
|
|
7123
|
+
return { job, parsed, agent: usedAgent };
|
|
6772
7124
|
} catch (err) {
|
|
6773
|
-
|
|
6774
|
-
|
|
7125
|
+
const label = job.dimension?.key ?? "light";
|
|
7126
|
+
log4(` ${label} subagent (${agent}) failed: ${err.message}`);
|
|
7127
|
+
return { job, parsed: { summary: "", findings: [], parseFailed: true }, agent };
|
|
6775
7128
|
}
|
|
6776
7129
|
}),
|
|
6777
7130
|
concurrency
|
|
6778
7131
|
);
|
|
6779
7132
|
const dimensionsRun = /* @__PURE__ */ new Set();
|
|
6780
|
-
|
|
6781
|
-
|
|
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}`);
|
|
6782
7137
|
for (const f of parsed.findings) {
|
|
6783
|
-
|
|
7138
|
+
agentsRun.add(agent);
|
|
7139
|
+
const fallbackType = job.dimension?.allowedTypes[0] ?? "bug";
|
|
7140
|
+
if (job.dimension) dimensionsRun.add(job.dimension.key);
|
|
6784
7141
|
collected.push({
|
|
6785
7142
|
id: f.id || "f",
|
|
6786
|
-
type: f.type ||
|
|
7143
|
+
type: f.type || fallbackType,
|
|
6787
7144
|
severity: f.severity || "medium",
|
|
6788
7145
|
title: f.title || "Untitled finding",
|
|
6789
7146
|
description: f.description || "",
|
|
@@ -6792,7 +7149,7 @@ async function orchestrateReview(opts) {
|
|
|
6792
7149
|
endLine: typeof f.endLine === "number" ? f.endLine : void 0,
|
|
6793
7150
|
suggestion: f.suggestion,
|
|
6794
7151
|
status: "new",
|
|
6795
|
-
dimension: job.dimension.
|
|
7152
|
+
dimension: job.dimension?.key ?? f.type ?? "general",
|
|
6796
7153
|
confidence: typeof f.confidence === "number" ? f.confidence : void 0
|
|
6797
7154
|
});
|
|
6798
7155
|
}
|
|
@@ -6800,13 +7157,15 @@ async function orchestrateReview(opts) {
|
|
|
6800
7157
|
const rawCount = collected.length;
|
|
6801
7158
|
let findings = mergeFindings(collected);
|
|
6802
7159
|
log4(`Merged ${rawCount} raw findings into ${findings.length} after dedup`);
|
|
6803
|
-
if (
|
|
6804
|
-
|
|
7160
|
+
if (depthConfig.verify && findings.length > 0) {
|
|
7161
|
+
const verifyOpts = { cwd: opts.cwd, chain: opts.chain };
|
|
7162
|
+
findings = await verifyFindings(findings, opts, verifyOpts, log4);
|
|
6805
7163
|
}
|
|
6806
7164
|
return {
|
|
6807
7165
|
summary: summaries.join(" "),
|
|
6808
7166
|
findings,
|
|
6809
7167
|
dimensionsRun: [...dimensionsRun],
|
|
7168
|
+
agentsRun: [...agentsRun],
|
|
6810
7169
|
rawCount
|
|
6811
7170
|
};
|
|
6812
7171
|
}
|
|
@@ -6848,7 +7207,7 @@ async function verifyFindings(findings, opts, runOpts, log4) {
|
|
|
6848
7207
|
}
|
|
6849
7208
|
|
|
6850
7209
|
// cli/commands/review.ts
|
|
6851
|
-
var
|
|
7210
|
+
var c10 = {
|
|
6852
7211
|
reset: "\x1B[0m",
|
|
6853
7212
|
bold: "\x1B[1m",
|
|
6854
7213
|
dim: "\x1B[2m",
|
|
@@ -6861,7 +7220,7 @@ var c9 = {
|
|
|
6861
7220
|
blue: "\x1B[34m"
|
|
6862
7221
|
};
|
|
6863
7222
|
function paint9(color, text) {
|
|
6864
|
-
return `${
|
|
7223
|
+
return `${c10[color]}${text}${c10.reset}`;
|
|
6865
7224
|
}
|
|
6866
7225
|
function timestamp3() {
|
|
6867
7226
|
return paint9("gray", (/* @__PURE__ */ new Date()).toLocaleTimeString("en-US", { hour12: false }));
|
|
@@ -6878,7 +7237,7 @@ function logOk2(msg) {
|
|
|
6878
7237
|
function logErr2(msg) {
|
|
6879
7238
|
console.error(`${timestamp3()} ${tag2()} ${paint9("red", "\u2717")} ${msg}`);
|
|
6880
7239
|
}
|
|
6881
|
-
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) => {
|
|
6882
7241
|
const config = loadConfig();
|
|
6883
7242
|
if (!config.apiKey) {
|
|
6884
7243
|
logErr2('Not authenticated. Run "mr login" first.');
|
|
@@ -6907,6 +7266,8 @@ var reviewCommand = new Command26("review").description("Run an automated code r
|
|
|
6907
7266
|
process.exit(1);
|
|
6908
7267
|
}
|
|
6909
7268
|
const baseBranch = opts.base || "main";
|
|
7269
|
+
const depth = normalizeReviewDepth(opts.depth);
|
|
7270
|
+
const depthConfig = getReviewDepthConfig(depth);
|
|
6910
7271
|
const prUrl = opts.prUrl;
|
|
6911
7272
|
const prNumberRaw = opts.prNumber;
|
|
6912
7273
|
const prNumber = prNumberRaw ? Number(prNumberRaw) : void 0;
|
|
@@ -7026,7 +7387,8 @@ var reviewCommand = new Command26("review").description("Run an automated code r
|
|
|
7026
7387
|
const report = await api.post("/api/reviews", {
|
|
7027
7388
|
projectId,
|
|
7028
7389
|
branch,
|
|
7029
|
-
baseBranch
|
|
7390
|
+
baseBranch,
|
|
7391
|
+
depth
|
|
7030
7392
|
});
|
|
7031
7393
|
reportId = report.id;
|
|
7032
7394
|
log2(`Created review report ${paint9("yellow", reportId.slice(0, 8))}`);
|
|
@@ -7054,6 +7416,7 @@ var reviewCommand = new Command26("review").description("Run an automated code r
|
|
|
7054
7416
|
process.exit(1);
|
|
7055
7417
|
}
|
|
7056
7418
|
log2(`Agent chain: ${paint9("cyan", chain.join(" \u2192 "))}`);
|
|
7419
|
+
log2(`Review depth: ${paint9("magenta", depthConfig.label)} ${paint9("dim", `(${depthConfig.description})`)}`);
|
|
7057
7420
|
const MAX_DIFF_CHARS = 4e5;
|
|
7058
7421
|
const diffCharsTotal = diff.length;
|
|
7059
7422
|
let reviewDiff = diff;
|
|
@@ -7064,15 +7427,15 @@ var reviewCommand = new Command26("review").description("Run an automated code r
|
|
|
7064
7427
|
log2(paint9("yellow", `Diff truncated to ${MAX_DIFF_CHARS.toLocaleString()} of ${diffCharsTotal.toLocaleString()} chars`));
|
|
7065
7428
|
}
|
|
7066
7429
|
try {
|
|
7067
|
-
log2(
|
|
7430
|
+
log2(`Running ${depthConfig.label.toLowerCase()} code review...`);
|
|
7068
7431
|
const orchestrated = await orchestrateReview({
|
|
7069
7432
|
branch,
|
|
7070
7433
|
baseBranch,
|
|
7071
7434
|
diff: reviewDiff,
|
|
7072
7435
|
chain,
|
|
7436
|
+
depth,
|
|
7073
7437
|
cwd: reviewCwd,
|
|
7074
7438
|
concurrency: 4,
|
|
7075
|
-
verify: true,
|
|
7076
7439
|
log: (m) => log2(m)
|
|
7077
7440
|
});
|
|
7078
7441
|
const result = { summary: orchestrated.summary, findings: orchestrated.findings };
|
|
@@ -7185,7 +7548,7 @@ function formatDuration(ms) {
|
|
|
7185
7548
|
}
|
|
7186
7549
|
|
|
7187
7550
|
// cli/commands/scan.ts
|
|
7188
|
-
import { Command as
|
|
7551
|
+
import { Command as Command30 } from "commander";
|
|
7189
7552
|
|
|
7190
7553
|
// lib/scanner/index.ts
|
|
7191
7554
|
import { spawn as spawn8 } from "child_process";
|
|
@@ -7651,10 +8014,10 @@ ${codebaseAnalysis.routes.map((r) => `- ${r}`).join("\n")}
|
|
|
7651
8014
|
${codebaseAnalysis.prismaModels.map((m) => `- ${m}`).join("\n")}
|
|
7652
8015
|
|
|
7653
8016
|
**Components:**
|
|
7654
|
-
${codebaseAnalysis.components.slice(0, 15).map((
|
|
8017
|
+
${codebaseAnalysis.components.slice(0, 15).map((c15) => `- ${c15}`).join("\n")}
|
|
7655
8018
|
|
|
7656
8019
|
**Recent Git Commits:**
|
|
7657
|
-
${codebaseAnalysis.recentCommits.slice(0, 8).map((
|
|
8020
|
+
${codebaseAnalysis.recentCommits.slice(0, 8).map((c15) => `- ${c15}`).join("\n")}
|
|
7658
8021
|
|
|
7659
8022
|
**Completed Tasks:**
|
|
7660
8023
|
${context.completedTasks.slice(0, 10).map((t) => `- ${t.title}`).join("\n") || "None"}
|
|
@@ -7869,7 +8232,9 @@ async function fetchScanContext(opts) {
|
|
|
7869
8232
|
}
|
|
7870
8233
|
function runClaude(prompt2) {
|
|
7871
8234
|
return new Promise((resolve9, reject) => {
|
|
7872
|
-
const
|
|
8235
|
+
const permission = resolvePermissionArgs("claude", "scan", resolveHeadlessMode(loadConfig()));
|
|
8236
|
+
console.error(`[scanner] permission: ${describePermissionMode(permission)}`);
|
|
8237
|
+
const child = spawn8("claude", ["-p", ...permission.args, prompt2], {
|
|
7873
8238
|
stdio: ["ignore", "pipe", "pipe"]
|
|
7874
8239
|
});
|
|
7875
8240
|
let output = "";
|
|
@@ -7925,7 +8290,7 @@ function parseSynthesisOutput(output) {
|
|
|
7925
8290
|
}
|
|
7926
8291
|
|
|
7927
8292
|
// cli/commands/scan.ts
|
|
7928
|
-
var
|
|
8293
|
+
var c11 = {
|
|
7929
8294
|
reset: "\x1B[0m",
|
|
7930
8295
|
bold: "\x1B[1m",
|
|
7931
8296
|
dim: "\x1B[2m",
|
|
@@ -7937,7 +8302,7 @@ var c10 = {
|
|
|
7937
8302
|
gray: "\x1B[90m"
|
|
7938
8303
|
};
|
|
7939
8304
|
function paint10(color, text) {
|
|
7940
|
-
return `${
|
|
8305
|
+
return `${c11[color]}${text}${c11.reset}`;
|
|
7941
8306
|
}
|
|
7942
8307
|
function timestamp4() {
|
|
7943
8308
|
return paint10("gray", (/* @__PURE__ */ new Date()).toLocaleTimeString("en-US", { hour12: false }));
|
|
@@ -7954,7 +8319,7 @@ function logOk3(msg) {
|
|
|
7954
8319
|
function logErr3(msg) {
|
|
7955
8320
|
console.error(`${timestamp4()} ${scanTag()} ${paint10("red", "\u2717")} ${msg}`);
|
|
7956
8321
|
}
|
|
7957
|
-
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) => {
|
|
7958
8323
|
const config = loadConfig();
|
|
7959
8324
|
if (!config.apiKey) {
|
|
7960
8325
|
logErr3('Not authenticated. Run "mr login" first.');
|
|
@@ -8119,7 +8484,7 @@ var scanCommand = new Command27("scan").description("Run a product scan on the c
|
|
|
8119
8484
|
});
|
|
8120
8485
|
|
|
8121
8486
|
// cli/commands/doctor.ts
|
|
8122
|
-
import { Command as
|
|
8487
|
+
import { Command as Command31 } from "commander";
|
|
8123
8488
|
import { existsSync as existsSync17 } from "fs";
|
|
8124
8489
|
import { homedir as homedir2 } from "os";
|
|
8125
8490
|
import { join as join11 } from "path";
|
|
@@ -8167,7 +8532,7 @@ async function checkProjectLink() {
|
|
|
8167
8532
|
optional: true
|
|
8168
8533
|
};
|
|
8169
8534
|
}
|
|
8170
|
-
var doctorCommand = new
|
|
8535
|
+
var doctorCommand = new Command31("doctor").description("Diagnose Mr. Manager CLI installation and environment").action(async () => {
|
|
8171
8536
|
const banner = [
|
|
8172
8537
|
``,
|
|
8173
8538
|
paint5("cyan", ` MR DOCTOR`),
|
|
@@ -8198,7 +8563,7 @@ var doctorCommand = new Command28("doctor").description("Diagnose Mr. Manager CL
|
|
|
8198
8563
|
console.log("");
|
|
8199
8564
|
return;
|
|
8200
8565
|
}
|
|
8201
|
-
const fixes = checks.filter((
|
|
8566
|
+
const fixes = checks.filter((c15) => !c15.ok && c15.fix && !c15.optional);
|
|
8202
8567
|
if (fixes.length > 0) {
|
|
8203
8568
|
console.log(paint5("yellow", " To fix:"));
|
|
8204
8569
|
for (const fix of fixes) {
|
|
@@ -8210,14 +8575,14 @@ var doctorCommand = new Command28("doctor").description("Diagnose Mr. Manager CL
|
|
|
8210
8575
|
});
|
|
8211
8576
|
|
|
8212
8577
|
// cli/commands/prompt-audit.ts
|
|
8213
|
-
import { Command as
|
|
8578
|
+
import { Command as Command32 } from "commander";
|
|
8214
8579
|
import { resolve as resolve8 } from "path";
|
|
8215
8580
|
import { existsSync as existsSync18, readFileSync as readFileSync12 } from "fs";
|
|
8216
8581
|
function auditLine(label, tokens) {
|
|
8217
8582
|
const bar = "\u2588".repeat(Math.min(60, Math.round(tokens / 200)));
|
|
8218
8583
|
return ` ${label.padEnd(30)} ${formatTokenCount(tokens).padStart(8)} ${bar}`;
|
|
8219
8584
|
}
|
|
8220
|
-
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) => {
|
|
8221
8586
|
const results = [];
|
|
8222
8587
|
if (opts.task) {
|
|
8223
8588
|
try {
|
|
@@ -8277,7 +8642,7 @@ ${task.notes}` : "";
|
|
|
8277
8642
|
}
|
|
8278
8643
|
}
|
|
8279
8644
|
sections.push({ name: "static-instructions (system)", tokens: estimateTokens(
|
|
8280
|
-
"status-updates + screenshots +
|
|
8645
|
+
"status-updates + screenshots + no-mr + features-workflow"
|
|
8281
8646
|
) });
|
|
8282
8647
|
const totalTokens = sections.reduce((sum, s) => sum + s.tokens, 0);
|
|
8283
8648
|
const promptTokens = sections.filter((s) => !s.name.includes("system")).reduce((sum, s) => sum + s.tokens, 0);
|
|
@@ -8426,9 +8791,9 @@ ${r.jobType} [${r.identifier}]`);
|
|
|
8426
8791
|
});
|
|
8427
8792
|
|
|
8428
8793
|
// cli/commands/skill.ts
|
|
8429
|
-
import { Command as
|
|
8430
|
-
import { createInterface as
|
|
8431
|
-
var
|
|
8794
|
+
import { Command as Command33 } from "commander";
|
|
8795
|
+
import { createInterface as createInterface4 } from "readline/promises";
|
|
8796
|
+
var c12 = {
|
|
8432
8797
|
reset: "\x1B[0m",
|
|
8433
8798
|
bold: "\x1B[1m",
|
|
8434
8799
|
dim: "\x1B[2m",
|
|
@@ -8461,7 +8826,7 @@ function formatSize(bytes) {
|
|
|
8461
8826
|
if (bytes < 1024) return `${bytes}b`;
|
|
8462
8827
|
return `${(bytes / 1024).toFixed(1)}kb`;
|
|
8463
8828
|
}
|
|
8464
|
-
var skillCommand = new
|
|
8829
|
+
var skillCommand = new Command33("skill").description("Manage skills \u2014 reusable playbooks for AI agents");
|
|
8465
8830
|
skillCommand.command("list").alias("ls").description("List all skills").option("--category <category>", "Filter by category").action(async (opts) => {
|
|
8466
8831
|
const params = new URLSearchParams();
|
|
8467
8832
|
if (opts.category) params.set("category", opts.category);
|
|
@@ -8469,17 +8834,17 @@ skillCommand.command("list").alias("ls").description("List all skills").option("
|
|
|
8469
8834
|
`/api/skills${params.toString() ? `?${params}` : ""}`
|
|
8470
8835
|
);
|
|
8471
8836
|
if (skills.length === 0) {
|
|
8472
|
-
console.log(`${
|
|
8837
|
+
console.log(`${c12.dim}No skills found.${c12.reset}`);
|
|
8473
8838
|
return;
|
|
8474
8839
|
}
|
|
8475
8840
|
for (const skill of skills) {
|
|
8476
|
-
const cat = skill.category ? ` ${
|
|
8477
|
-
const scope = skill.projectId ? ` ${
|
|
8478
|
-
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}`);
|
|
8479
8844
|
if (skill.description) {
|
|
8480
|
-
console.log(` ${
|
|
8845
|
+
console.log(` ${c12.dim}${skill.description}${c12.reset}`);
|
|
8481
8846
|
}
|
|
8482
|
-
console.log(` ${
|
|
8847
|
+
console.log(` ${c12.dim}id: ${skill.id}${c12.reset}`);
|
|
8483
8848
|
}
|
|
8484
8849
|
});
|
|
8485
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) => {
|
|
@@ -8515,7 +8880,7 @@ skillCommand.command("create").description("Create a new skill from a markdown f
|
|
|
8515
8880
|
projectId
|
|
8516
8881
|
});
|
|
8517
8882
|
console.log(
|
|
8518
|
-
`${
|
|
8883
|
+
`${c12.green}Created skill:${c12.reset} ${c12.bold}${skill.name}${c12.reset} ${c12.dim}(${skill.id})${c12.reset}`
|
|
8519
8884
|
);
|
|
8520
8885
|
});
|
|
8521
8886
|
skillCommand.command("update").description(
|
|
@@ -8576,14 +8941,14 @@ skillCommand.command("update").description(
|
|
|
8576
8941
|
const beforeContent = existing.content ?? "";
|
|
8577
8942
|
const afterContent = typeof patch.content === "string" ? patch.content : beforeContent;
|
|
8578
8943
|
const contentChanged = typeof patch.content === "string" && patch.content !== beforeContent;
|
|
8579
|
-
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}` : "";
|
|
8580
8945
|
const priorRevisions = existing.revisions?.length ?? 0;
|
|
8581
8946
|
const revisionsAfter = priorRevisions + (contentChanged ? 1 : 0);
|
|
8582
|
-
const revisionNote = contentChanged ? ` ${
|
|
8947
|
+
const revisionNote = contentChanged ? ` ${c12.dim}kept ${revisionsAfter} prior revision${revisionsAfter === 1 ? "" : "s"}${c12.reset}` : "";
|
|
8583
8948
|
console.log(
|
|
8584
|
-
`${
|
|
8949
|
+
`${c12.green}Updated skill:${c12.reset} ${c12.bold}${updated.name}${c12.reset}${sizeDiff}${revisionNote}`
|
|
8585
8950
|
);
|
|
8586
|
-
console.log(` ${
|
|
8951
|
+
console.log(` ${c12.dim}id: ${updated.id}${c12.reset}`);
|
|
8587
8952
|
});
|
|
8588
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) => {
|
|
8589
8954
|
let skill;
|
|
@@ -8594,9 +8959,9 @@ skillCommand.command("delete").alias("rm").description("Delete a skill").argumen
|
|
|
8594
8959
|
process.exit(1);
|
|
8595
8960
|
}
|
|
8596
8961
|
if (!opts.yes) {
|
|
8597
|
-
const rl =
|
|
8962
|
+
const rl = createInterface4({ input: process.stdin, output: process.stdout });
|
|
8598
8963
|
const answer = (await rl.question(
|
|
8599
|
-
`Delete skill ${
|
|
8964
|
+
`Delete skill ${c12.bold}${skill.name}${c12.reset} ${c12.dim}(${skill.id})${c12.reset}? [y/N] `
|
|
8600
8965
|
)).trim().toLowerCase();
|
|
8601
8966
|
rl.close();
|
|
8602
8967
|
if (answer !== "y" && answer !== "yes") {
|
|
@@ -8606,7 +8971,7 @@ skillCommand.command("delete").alias("rm").description("Delete a skill").argumen
|
|
|
8606
8971
|
}
|
|
8607
8972
|
await api.del(`/api/skills/${skill.id}`);
|
|
8608
8973
|
console.log(
|
|
8609
|
-
`${
|
|
8974
|
+
`${c12.yellow}Deleted skill:${c12.reset} ${c12.bold}${skill.name}${c12.reset} ${c12.dim}(${skill.id})${c12.reset}`
|
|
8610
8975
|
);
|
|
8611
8976
|
});
|
|
8612
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) => {
|
|
@@ -8620,22 +8985,22 @@ skillCommand.command("generate").alias("gen").description("Generate a new skill
|
|
|
8620
8985
|
process.exit(1);
|
|
8621
8986
|
}
|
|
8622
8987
|
}
|
|
8623
|
-
console.log(`${
|
|
8988
|
+
console.log(`${c12.dim}Generating skill...${c12.reset}`);
|
|
8624
8989
|
try {
|
|
8625
8990
|
const skill = await api.post("/api/skills/generate", {
|
|
8626
8991
|
prompt: prompt2,
|
|
8627
8992
|
projectId
|
|
8628
8993
|
});
|
|
8629
8994
|
console.log(
|
|
8630
|
-
`${
|
|
8995
|
+
`${c12.green}Generated skill:${c12.reset} ${c12.bold}${skill.name}${c12.reset}`
|
|
8631
8996
|
);
|
|
8632
8997
|
if (skill.description) {
|
|
8633
|
-
console.log(` ${
|
|
8998
|
+
console.log(` ${c12.dim}${skill.description}${c12.reset}`);
|
|
8634
8999
|
}
|
|
8635
9000
|
if (skill.category) {
|
|
8636
|
-
console.log(` ${
|
|
9001
|
+
console.log(` ${c12.dim}Category: ${skill.category}${c12.reset}`);
|
|
8637
9002
|
}
|
|
8638
|
-
console.log(` ${
|
|
9003
|
+
console.log(` ${c12.dim}id: ${skill.id}${c12.reset}`);
|
|
8639
9004
|
} catch (err) {
|
|
8640
9005
|
console.error(`Failed to generate skill: ${err.message}`);
|
|
8641
9006
|
process.exit(1);
|
|
@@ -8643,8 +9008,8 @@ skillCommand.command("generate").alias("gen").description("Generate a new skill
|
|
|
8643
9008
|
});
|
|
8644
9009
|
|
|
8645
9010
|
// cli/commands/resource.ts
|
|
8646
|
-
import { Command as
|
|
8647
|
-
var
|
|
9011
|
+
import { Command as Command34 } from "commander";
|
|
9012
|
+
var c13 = {
|
|
8648
9013
|
reset: "\x1B[0m",
|
|
8649
9014
|
bold: "\x1B[1m",
|
|
8650
9015
|
dim: "\x1B[2m",
|
|
@@ -8654,16 +9019,16 @@ var c12 = {
|
|
|
8654
9019
|
magenta: "\x1B[35m"
|
|
8655
9020
|
};
|
|
8656
9021
|
var TYPE_COLORS = {
|
|
8657
|
-
plan:
|
|
8658
|
-
research:
|
|
8659
|
-
"test-plan":
|
|
8660
|
-
note:
|
|
9022
|
+
plan: c13.cyan,
|
|
9023
|
+
research: c13.magenta,
|
|
9024
|
+
"test-plan": c13.yellow,
|
|
9025
|
+
note: c13.green
|
|
8661
9026
|
};
|
|
8662
9027
|
function typeLabel(type) {
|
|
8663
|
-
const color = TYPE_COLORS[type] ??
|
|
8664
|
-
return `${color}${type}${
|
|
9028
|
+
const color = TYPE_COLORS[type] ?? c13.dim;
|
|
9029
|
+
return `${color}${type}${c13.reset}`;
|
|
8665
9030
|
}
|
|
8666
|
-
var resourceCommand = new
|
|
9031
|
+
var resourceCommand = new Command34("resource").description("Manage resources \u2014 documents, plans, research, and notes");
|
|
8667
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) => {
|
|
8668
9033
|
const params = new URLSearchParams();
|
|
8669
9034
|
if (opts.all) {
|
|
@@ -8676,13 +9041,13 @@ resourceCommand.command("list").alias("ls").description("List resources for the
|
|
|
8676
9041
|
`/api/resources${params.toString() ? `?${params}` : ""}`
|
|
8677
9042
|
);
|
|
8678
9043
|
if (resources.length === 0) {
|
|
8679
|
-
console.log(`${
|
|
9044
|
+
console.log(`${c13.dim}No resources found.${c13.reset}`);
|
|
8680
9045
|
return;
|
|
8681
9046
|
}
|
|
8682
9047
|
for (const r of resources) {
|
|
8683
|
-
const project = r.projectName ? ` ${
|
|
8684
|
-
console.log(` ${typeLabel(r.type)} ${
|
|
8685
|
-
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}`);
|
|
8686
9051
|
}
|
|
8687
9052
|
});
|
|
8688
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) => {
|
|
@@ -8707,9 +9072,9 @@ resourceCommand.command("create").description("Create a new resource from a file
|
|
|
8707
9072
|
content: content.trim()
|
|
8708
9073
|
});
|
|
8709
9074
|
console.log(
|
|
8710
|
-
`${
|
|
9075
|
+
`${c13.green}Created resource:${c13.reset} ${c13.bold}${title}${c13.reset} ${c13.dim}(${resource.id})${c13.reset}`
|
|
8711
9076
|
);
|
|
8712
|
-
console.log(` ${
|
|
9077
|
+
console.log(` ${c13.dim}Attached to task ${opts.task}${c13.reset}`);
|
|
8713
9078
|
return;
|
|
8714
9079
|
}
|
|
8715
9080
|
let projectId;
|
|
@@ -8729,7 +9094,7 @@ resourceCommand.command("create").description("Create a new resource from a file
|
|
|
8729
9094
|
projectId
|
|
8730
9095
|
});
|
|
8731
9096
|
console.log(
|
|
8732
|
-
`${
|
|
9097
|
+
`${c13.green}Created resource:${c13.reset} ${c13.bold}${title}${c13.reset} ${c13.dim}(${result.resource.id})${c13.reset}`
|
|
8733
9098
|
);
|
|
8734
9099
|
});
|
|
8735
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) => {
|
|
@@ -8748,30 +9113,30 @@ resourceCommand.command("generate").alias("gen").description("Generate a resourc
|
|
|
8748
9113
|
process.exit(1);
|
|
8749
9114
|
}
|
|
8750
9115
|
}
|
|
8751
|
-
console.log(`${
|
|
9116
|
+
console.log(`${c13.dim}Generating ${type}...${c13.reset}`);
|
|
8752
9117
|
const result = await api.post("/api/resources", {
|
|
8753
9118
|
type,
|
|
8754
9119
|
prompt: prompt2,
|
|
8755
9120
|
projectId
|
|
8756
9121
|
});
|
|
8757
9122
|
console.log(
|
|
8758
|
-
`${
|
|
9123
|
+
`${c13.green}Queued:${c13.reset} ${c13.bold}${result.task.title}${c13.reset}`
|
|
8759
9124
|
);
|
|
8760
|
-
console.log(` ${
|
|
9125
|
+
console.log(` ${c13.dim}task: ${result.task.id}${c13.reset}`);
|
|
8761
9126
|
});
|
|
8762
9127
|
|
|
8763
9128
|
// cli/commands/tests.ts
|
|
8764
|
-
import { Command as
|
|
8765
|
-
var
|
|
9129
|
+
import { Command as Command35 } from "commander";
|
|
9130
|
+
var c14 = {
|
|
8766
9131
|
reset: "\x1B[0m",
|
|
8767
9132
|
dim: "\x1B[2m",
|
|
8768
9133
|
yellow: "\x1B[33m"
|
|
8769
9134
|
};
|
|
8770
|
-
var testsCommand = new
|
|
9135
|
+
var testsCommand = new Command35("tests").description("List MR Test scenarios for the linked project").action(async () => {
|
|
8771
9136
|
const projectId = getLinkedProjectId();
|
|
8772
9137
|
if (!projectId) {
|
|
8773
9138
|
console.error(
|
|
8774
|
-
`${
|
|
9139
|
+
`${c14.yellow}No project linked to this directory.${c14.reset} Run "mr link <project-id>" first.`
|
|
8775
9140
|
);
|
|
8776
9141
|
process.exit(1);
|
|
8777
9142
|
}
|
|
@@ -8784,13 +9149,13 @@ var testsCommand = new Command32("tests").description("List MR Test scenarios fo
|
|
|
8784
9149
|
process.exit(1);
|
|
8785
9150
|
}
|
|
8786
9151
|
if (scenarios.length === 0) {
|
|
8787
|
-
console.log(`${
|
|
9152
|
+
console.log(`${c14.dim}No test scenarios found for this project.${c14.reset}`);
|
|
8788
9153
|
return;
|
|
8789
9154
|
}
|
|
8790
9155
|
for (const scenario of scenarios) {
|
|
8791
9156
|
console.log(`### ${scenario.name}`);
|
|
8792
9157
|
if (scenario.description) {
|
|
8793
|
-
console.log(`${
|
|
9158
|
+
console.log(`${c14.dim}${scenario.description}${c14.reset}`);
|
|
8794
9159
|
console.log();
|
|
8795
9160
|
}
|
|
8796
9161
|
console.log(scenario.content);
|
|
@@ -8799,9 +9164,9 @@ var testsCommand = new Command32("tests").description("List MR Test scenarios fo
|
|
|
8799
9164
|
});
|
|
8800
9165
|
|
|
8801
9166
|
// cli/commands/walkthrough.ts
|
|
8802
|
-
import { Command as
|
|
9167
|
+
import { Command as Command36 } from "commander";
|
|
8803
9168
|
var SKILL_NAME = "Generate Walkthrough Video";
|
|
8804
|
-
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) => {
|
|
8805
9170
|
const skills = await api.get("/api/skills");
|
|
8806
9171
|
const skill = skills.find((s) => s.name === SKILL_NAME);
|
|
8807
9172
|
if (!skill) {
|
|
@@ -8834,7 +9199,7 @@ var userArgs = process.argv.slice(2);
|
|
|
8834
9199
|
var bypassCommands = /* @__PURE__ */ new Set(["login", "init", "auth", "help", "--help", "-h", "--version", "-V", "doctor", "setup"]);
|
|
8835
9200
|
var shouldBypass = userArgs.length > 0 && bypassCommands.has(userArgs[0]);
|
|
8836
9201
|
if (isFirstRun && !shouldBypass) {
|
|
8837
|
-
const
|
|
9202
|
+
const c15 = {
|
|
8838
9203
|
reset: "\x1B[0m",
|
|
8839
9204
|
bold: "\x1B[1m",
|
|
8840
9205
|
dim: "\x1B[2m",
|
|
@@ -8844,28 +9209,28 @@ if (isFirstRun && !shouldBypass) {
|
|
|
8844
9209
|
magenta: "\x1B[35m"
|
|
8845
9210
|
};
|
|
8846
9211
|
console.log("");
|
|
8847
|
-
console.log(`${
|
|
8848
|
-
console.log(`${
|
|
8849
|
-
console.log(`${
|
|
8850
|
-
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}`);
|
|
8851
9216
|
console.log("");
|
|
8852
|
-
console.log(`${
|
|
8853
|
-
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}`);
|
|
8854
9219
|
console.log("");
|
|
8855
|
-
console.log(` ${
|
|
8856
|
-
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}`);
|
|
8857
9222
|
console.log("");
|
|
8858
|
-
console.log(` ${
|
|
8859
|
-
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}`);
|
|
8860
9225
|
console.log("");
|
|
8861
|
-
console.log(` ${
|
|
8862
|
-
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}`);
|
|
8863
9228
|
console.log("");
|
|
8864
|
-
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}`);
|
|
8865
9230
|
console.log("");
|
|
8866
9231
|
process.exit(0);
|
|
8867
9232
|
}
|
|
8868
|
-
var program = new
|
|
9233
|
+
var program = new Command37();
|
|
8869
9234
|
program.name("mr").description("Mr. Manager - Task and project management CLI").version(CLI_VERSION);
|
|
8870
9235
|
program.addCommand(initCommand);
|
|
8871
9236
|
program.addCommand(authCommand);
|
|
@@ -8882,6 +9247,9 @@ program.addCommand(delegateCommand);
|
|
|
8882
9247
|
program.addCommand(undelegateCommand);
|
|
8883
9248
|
program.addCommand(createCommand);
|
|
8884
9249
|
program.addCommand(completeCommand);
|
|
9250
|
+
program.addCommand(showCommand);
|
|
9251
|
+
program.addCommand(editCommand);
|
|
9252
|
+
program.addCommand(deleteCommand);
|
|
8885
9253
|
program.addCommand(subtaskCompleteCommand);
|
|
8886
9254
|
program.addCommand(subtaskAddCommand);
|
|
8887
9255
|
program.addCommand(prototypeCommand);
|