@dunnewold-labs/mr-manager 0.4.30 → 0.4.32
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 +123 -493
- 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 Command28 } from "commander";
|
|
5
5
|
import { existsSync as existsSync17 } from "fs";
|
|
6
6
|
import { homedir as homedir3 } from "os";
|
|
7
7
|
import { join as join12 } from "path";
|
|
@@ -185,7 +185,7 @@ import { fileURLToPath } from "url";
|
|
|
185
185
|
// cli/package.json
|
|
186
186
|
var package_default = {
|
|
187
187
|
name: "@dunnewold-labs/mr-manager",
|
|
188
|
-
version: "0.4.
|
|
188
|
+
version: "0.4.32",
|
|
189
189
|
description: "Mr. Manager - Task and project management CLI",
|
|
190
190
|
bin: {
|
|
191
191
|
mr: "./dist/index.mjs"
|
|
@@ -1162,6 +1162,19 @@ function taskLikelyDoesNotNeedCodeChanges(task) {
|
|
|
1162
1162
|
return NON_CODE_TASK_KEYWORDS.some((keyword) => haystack.includes(keyword)) || NON_CODE_TASK_PATTERNS.some((pattern) => pattern.test(haystack));
|
|
1163
1163
|
}
|
|
1164
1164
|
|
|
1165
|
+
// lib/task-branch.ts
|
|
1166
|
+
function isPrOrMrUrl(input) {
|
|
1167
|
+
try {
|
|
1168
|
+
const url = new URL(input.trim());
|
|
1169
|
+
const path = url.pathname;
|
|
1170
|
+
if (url.hostname.includes("github") && /\/pull\/\d+/.test(path)) return true;
|
|
1171
|
+
if (url.hostname.includes("gitlab") && /\/merge_requests\/\d+/.test(path)) return true;
|
|
1172
|
+
} catch {
|
|
1173
|
+
return false;
|
|
1174
|
+
}
|
|
1175
|
+
return false;
|
|
1176
|
+
}
|
|
1177
|
+
|
|
1165
1178
|
// cli/browse-runner.ts
|
|
1166
1179
|
import { execSync as execSync3, spawn as spawn3 } from "child_process";
|
|
1167
1180
|
import { existsSync as existsSync6 } from "fs";
|
|
@@ -1477,11 +1490,21 @@ function ownerPrefix(task) {
|
|
|
1477
1490
|
return first || "mr";
|
|
1478
1491
|
}
|
|
1479
1492
|
function taskBranchName(task) {
|
|
1480
|
-
|
|
1481
|
-
|
|
1493
|
+
const branch = task.attachedBranch?.trim();
|
|
1494
|
+
if (branch && !isPrOrMrUrl(branch)) {
|
|
1495
|
+
return branch;
|
|
1482
1496
|
}
|
|
1483
1497
|
return `${ownerPrefix(task)}/${slugify(task.title)}`;
|
|
1484
1498
|
}
|
|
1499
|
+
function resolveBranchFromPrUrl(prUrl, repoDir, vcs) {
|
|
1500
|
+
const cmd = vcs === "gitlab" ? `glab mr view "${prUrl}" --output json 2>/dev/null | jq -r '.source_branch // empty'` : `gh pr view "${prUrl}" --json headRefName -q .headRefName 2>/dev/null`;
|
|
1501
|
+
return new Promise((resolve9) => {
|
|
1502
|
+
exec(cmd, { cwd: repoDir }, (err, stdout) => {
|
|
1503
|
+
const branch = stdout?.trim();
|
|
1504
|
+
resolve9(branch || null);
|
|
1505
|
+
});
|
|
1506
|
+
});
|
|
1507
|
+
}
|
|
1485
1508
|
function formatElapsed(ms) {
|
|
1486
1509
|
const totalMinutes = Math.max(1, Math.floor(ms / 6e4));
|
|
1487
1510
|
const hours = Math.floor(totalMinutes / 60);
|
|
@@ -2119,9 +2142,6 @@ function protoTag(sid) {
|
|
|
2119
2142
|
function repoTag(sid) {
|
|
2120
2143
|
return paint("cyan", `[repo:${sid}]`);
|
|
2121
2144
|
}
|
|
2122
|
-
function ideaTag(sid) {
|
|
2123
|
-
return paint("magenta", `[idea:${sid}]`);
|
|
2124
|
-
}
|
|
2125
2145
|
function buildRepoCreationPrompt(project, rootDir, vcs = "github") {
|
|
2126
2146
|
const apiBase = process.env.MR_API_BASE ?? "http://localhost:3000";
|
|
2127
2147
|
const apiKey = process.env.MR_API_KEY ?? "";
|
|
@@ -2400,83 +2420,6 @@ function buildRefinementPrompt(proto, parentFiles, repoDir) {
|
|
|
2400
2420
|
`- Do NOT exit until ALL ${proto.variantCount} files have been written and verified.`
|
|
2401
2421
|
].join("\n");
|
|
2402
2422
|
}
|
|
2403
|
-
function buildIdeaPrompt(idea, repoDir) {
|
|
2404
|
-
const feedbackSection = idea.feedback ? [
|
|
2405
|
-
`## Previous Feedback`,
|
|
2406
|
-
``,
|
|
2407
|
-
`The user provided this feedback on a previous generation:`,
|
|
2408
|
-
`${idea.feedback}`,
|
|
2409
|
-
``,
|
|
2410
|
-
`Please incorporate this feedback into your new generation.`,
|
|
2411
|
-
``
|
|
2412
|
-
] : [];
|
|
2413
|
-
const existingPlanSection = idea.plan && idea.feedback ? [
|
|
2414
|
-
`## Previous Plan`,
|
|
2415
|
-
``,
|
|
2416
|
-
`Here is the plan from the previous iteration:`,
|
|
2417
|
-
`\`\`\`markdown`,
|
|
2418
|
-
idea.plan,
|
|
2419
|
-
`\`\`\``,
|
|
2420
|
-
``
|
|
2421
|
-
] : [];
|
|
2422
|
-
return [
|
|
2423
|
-
`You are a product strategist and UI designer. Your job is to take a rough idea and generate two outputs:`,
|
|
2424
|
-
`1. An implementation plan (saved as \`idea-plan.md\`)`,
|
|
2425
|
-
`2. A visual prototype (saved as \`idea-prototype.html\`)`,
|
|
2426
|
-
``,
|
|
2427
|
-
`Working directory: ${repoDir}`,
|
|
2428
|
-
``,
|
|
2429
|
-
`## Idea`,
|
|
2430
|
-
`Title: ${idea.title}`,
|
|
2431
|
-
`ID: ${idea.id}`,
|
|
2432
|
-
...idea.description ? [``, `Description: ${idea.description}`] : [],
|
|
2433
|
-
``,
|
|
2434
|
-
...feedbackSection,
|
|
2435
|
-
...existingPlanSection,
|
|
2436
|
-
`## Instructions`,
|
|
2437
|
-
``,
|
|
2438
|
-
`### Step 1: Generate the Plan`,
|
|
2439
|
-
``,
|
|
2440
|
-
`Write a comprehensive implementation plan to \`${repoDir}/idea-plan.md\` covering:`,
|
|
2441
|
-
`- **Problem statement**: What problem does this idea solve?`,
|
|
2442
|
-
`- **Proposed solution**: High-level approach`,
|
|
2443
|
-
`- **Key features**: Bulleted list of features/capabilities`,
|
|
2444
|
-
`- **Technical approach**: How it could be built (components, data model, integrations)`,
|
|
2445
|
-
`- **Implementation phases**: Phased rollout plan with milestones`,
|
|
2446
|
-
`- **Open questions**: Things that need clarification`,
|
|
2447
|
-
``,
|
|
2448
|
-
`### Step 2: Generate Follow-up Tasks`,
|
|
2449
|
-
``,
|
|
2450
|
-
`Write a JSON file to \`${repoDir}/idea-tasks.json\` containing an array of follow-up tasks that will need to be done after the project repo is created. These are setup and implementation tasks the user will need to complete. Examples: "Add environment variables (.env)", "Set up CI/CD pipeline", "Configure database", "Add authentication", etc.`,
|
|
2451
|
-
``,
|
|
2452
|
-
`Format: a JSON array of objects with "title" (short task name) and optional "notes" (additional context):`,
|
|
2453
|
-
`\`\`\`json`,
|
|
2454
|
-
`[`,
|
|
2455
|
-
` { "title": "Add environment variables (.env)", "notes": "Create .env file with required API keys and database URL" },`,
|
|
2456
|
-
` { "title": "Set up CI/CD pipeline" }`,
|
|
2457
|
-
`]`,
|
|
2458
|
-
`\`\`\``,
|
|
2459
|
-
``,
|
|
2460
|
-
`Generate 3-8 tasks that are specific to this idea. Focus on actionable setup and implementation steps.`,
|
|
2461
|
-
``,
|
|
2462
|
-
`### Step 3: Generate the Prototype`,
|
|
2463
|
-
``,
|
|
2464
|
-
`Write a self-contained HTML prototype to \`${repoDir}/idea-prototype.html\` that visually demonstrates the idea.`,
|
|
2465
|
-
`- Must be completely self-contained (inline CSS/JS, Tailwind CDN is acceptable)`,
|
|
2466
|
-
`- Should be interactive where possible (click handlers, animations, sample data)`,
|
|
2467
|
-
`- Should look polished and professional \u2014 this will be shown to stakeholders`,
|
|
2468
|
-
`- Include realistic sample data that demonstrates the feature`,
|
|
2469
|
-
``,
|
|
2470
|
-
`### Step 4: Verify`,
|
|
2471
|
-
``,
|
|
2472
|
-
`List the files in ${repoDir} and confirm \`idea-plan.md\`, \`idea-tasks.json\`, and \`idea-prototype.html\` all exist.`,
|
|
2473
|
-
``,
|
|
2474
|
-
`IMPORTANT RULES:`,
|
|
2475
|
-
`- Write EXACTLY three files: idea-plan.md, idea-tasks.json, and idea-prototype.html`,
|
|
2476
|
-
`- Do NOT upload or POST the files anywhere \u2014 the watch handler will upload them automatically`,
|
|
2477
|
-
`- Do NOT exit until both files have been written and verified`
|
|
2478
|
-
].join("\n");
|
|
2479
|
-
}
|
|
2480
2423
|
function buildAgentArgs(agent, prompt2, mode, sessionId, name, resumeSession = false, systemPrompt, maxTurns, claudeModel) {
|
|
2481
2424
|
if (agent === "codex") {
|
|
2482
2425
|
const args = [];
|
|
@@ -2719,7 +2662,7 @@ var watchCommand = new Command8("watch").description(
|
|
|
2719
2662
|
logWarn(watchTag(), `Network unavailable \u2014 pausing active tasks until connectivity returns (${reason})`);
|
|
2720
2663
|
}
|
|
2721
2664
|
for (const taskId of active.keys()) {
|
|
2722
|
-
const nonTaskPrefixes = ["proto-", "repo-", "scan-", "
|
|
2665
|
+
const nonTaskPrefixes = ["proto-", "repo-", "scan-", "test-"];
|
|
2723
2666
|
if (nonTaskPrefixes.some((prefix) => taskId.startsWith(prefix))) continue;
|
|
2724
2667
|
pauseTaskForNetwork(taskId, reason);
|
|
2725
2668
|
}
|
|
@@ -2766,10 +2709,17 @@ var watchCommand = new Command8("watch").description(
|
|
|
2766
2709
|
const sid = shortId(task.id);
|
|
2767
2710
|
const slug = slugify(task.title);
|
|
2768
2711
|
const owner = ownerPrefix(task);
|
|
2769
|
-
|
|
2712
|
+
let branchName = taskBranchName(task);
|
|
2770
2713
|
const legacyBranchName = `mr/${sid}/${slug}`;
|
|
2771
2714
|
const prefix = taskTag(sid);
|
|
2772
2715
|
const vcs = detectVcs(repoDir)?.provider ?? "github";
|
|
2716
|
+
if (!task.attachedBranch?.trim() && task.attachedBranchLink && isPrOrMrUrl(task.attachedBranchLink)) {
|
|
2717
|
+
const resolved = await resolveBranchFromPrUrl(task.attachedBranchLink, repoDir, vcs);
|
|
2718
|
+
if (resolved) {
|
|
2719
|
+
branchName = resolved;
|
|
2720
|
+
logInfo(prefix, `Resolved branch ${paint("cyan", resolved)} from attached ${vcs === "gitlab" ? "MR" : "PR"}`);
|
|
2721
|
+
}
|
|
2722
|
+
}
|
|
2773
2723
|
logDispatch(prefix, `"${paint("bold", task.title)}" ${paint("gray", repoDir)} ${paint("dim", `[${vcs}]`)}`);
|
|
2774
2724
|
await postTaskUpdate(task.id, `Agent dispatched \u2014 starting work on "${task.title}"`, "system");
|
|
2775
2725
|
let subtasks = [];
|
|
@@ -2923,28 +2873,40 @@ var watchCommand = new Command8("watch").description(
|
|
|
2923
2873
|
logWarn(prefix, `${attemptAgent} paused after network loss (${failureDetail})`);
|
|
2924
2874
|
return;
|
|
2925
2875
|
}
|
|
2926
|
-
|
|
2927
|
-
|
|
2928
|
-
|
|
2929
|
-
|
|
2930
|
-
|
|
2931
|
-
|
|
2932
|
-
|
|
2933
|
-
);
|
|
2934
|
-
|
|
2935
|
-
return;
|
|
2876
|
+
try {
|
|
2877
|
+
const currentTask = await api.get(`/api/tasks/${task.id}`);
|
|
2878
|
+
if (currentTask.status === "completed" || currentTask.status === "review" || currentTask.status === "error") {
|
|
2879
|
+
logWarn(prefix, `Task already in "${currentTask.status}" state after agent exit \u2014 skipping retry`);
|
|
2880
|
+
activeEntry.terminatedForError = true;
|
|
2881
|
+
}
|
|
2882
|
+
} catch {
|
|
2883
|
+
logWarn(prefix, `Could not verify task status \u2014 skipping retry to avoid stale re-dispatch`);
|
|
2884
|
+
activeEntry.terminatedForError = true;
|
|
2936
2885
|
}
|
|
2937
|
-
|
|
2938
|
-
|
|
2939
|
-
|
|
2940
|
-
|
|
2941
|
-
|
|
2942
|
-
|
|
2943
|
-
|
|
2944
|
-
|
|
2945
|
-
|
|
2946
|
-
|
|
2947
|
-
|
|
2886
|
+
if (!activeEntry.terminatedForError) {
|
|
2887
|
+
if (shouldResumeClaudeSession && !resumeAlreadyRetried) {
|
|
2888
|
+
resumeAlreadyRetried = true;
|
|
2889
|
+
logWarn(prefix, `Claude session resume failed (${failureDetail}) \u2014 retrying with fresh session`);
|
|
2890
|
+
await postTaskUpdate(
|
|
2891
|
+
task.id,
|
|
2892
|
+
`Claude session resume failed \u2014 retrying with fresh session`,
|
|
2893
|
+
"system"
|
|
2894
|
+
);
|
|
2895
|
+
await launchAttempt("claude");
|
|
2896
|
+
return;
|
|
2897
|
+
}
|
|
2898
|
+
const nextAgent = attemptOrder[attemptIndex + 1];
|
|
2899
|
+
if (nextAgent) {
|
|
2900
|
+
logWarn(prefix, `${attemptAgent} failed (${failureDetail}) \u2014 retrying with ${nextAgent}`);
|
|
2901
|
+
await postTaskUpdate(
|
|
2902
|
+
task.id,
|
|
2903
|
+
`${attemptAgent} failed (${failureDetail}) \u2014 retrying with ${nextAgent}`,
|
|
2904
|
+
"system"
|
|
2905
|
+
);
|
|
2906
|
+
attemptIndex += 1;
|
|
2907
|
+
await launchAttempt(nextAgent);
|
|
2908
|
+
return;
|
|
2909
|
+
}
|
|
2948
2910
|
}
|
|
2949
2911
|
}
|
|
2950
2912
|
finishing.add(task.id);
|
|
@@ -3291,7 +3253,7 @@ var watchCommand = new Command8("watch").description(
|
|
|
3291
3253
|
active.delete(key);
|
|
3292
3254
|
}
|
|
3293
3255
|
const failedAttempt = code !== 0 || spawnFailureReason !== null;
|
|
3294
|
-
if (failedAttempt) {
|
|
3256
|
+
if (failedAttempt && !activeEntry.terminatedForError) {
|
|
3295
3257
|
const nextAgent = attemptOrder[attemptIndex + 1];
|
|
3296
3258
|
if (nextAgent) {
|
|
3297
3259
|
const failureDetail = spawnFailureReason ?? `exit code ${code}`;
|
|
@@ -3401,7 +3363,7 @@ var watchCommand = new Command8("watch").description(
|
|
|
3401
3363
|
active.delete(key);
|
|
3402
3364
|
}
|
|
3403
3365
|
const failedAttempt = code !== 0 || spawnFailureReason !== null;
|
|
3404
|
-
if (failedAttempt) {
|
|
3366
|
+
if (failedAttempt && !activeEntry.terminatedForError) {
|
|
3405
3367
|
const nextAgent = attemptOrder[attemptIndex + 1];
|
|
3406
3368
|
if (nextAgent) {
|
|
3407
3369
|
const failureDetail = spawnFailureReason ?? `exit code ${code}`;
|
|
@@ -3438,158 +3400,6 @@ var watchCommand = new Command8("watch").description(
|
|
|
3438
3400
|
};
|
|
3439
3401
|
await launchAttempt(attemptOrder[attemptIndex]);
|
|
3440
3402
|
}
|
|
3441
|
-
async function dispatchIdeaJob(idea, repoDir) {
|
|
3442
|
-
const sid = shortId(idea.id);
|
|
3443
|
-
const prefix = ideaTag(sid);
|
|
3444
|
-
logDispatch(prefix, `"${paint("bold", idea.title)}"${idea.feedback ? paint("cyan", " (iteration)") : ""} ${paint("gray", repoDir)}`);
|
|
3445
|
-
for (const f of ["idea-plan.md", "idea-tasks.json", "idea-prototype.html"]) {
|
|
3446
|
-
try {
|
|
3447
|
-
unlinkSync(resolve2(repoDir, f));
|
|
3448
|
-
} catch {
|
|
3449
|
-
}
|
|
3450
|
-
}
|
|
3451
|
-
const prompt2 = buildIdeaPrompt(idea, repoDir);
|
|
3452
|
-
const key = `idea-${idea.id}`;
|
|
3453
|
-
const attemptOrder = await resolveAgentChain(agent);
|
|
3454
|
-
if (attemptOrder.length === 0) {
|
|
3455
|
-
logError(prefix, `No available agents found for fallback chain starting at ${agent}`);
|
|
3456
|
-
queued.delete(key);
|
|
3457
|
-
try {
|
|
3458
|
-
await api.patch(`/api/ideas/${idea.id}`, { status: "draft" });
|
|
3459
|
-
} catch {
|
|
3460
|
-
}
|
|
3461
|
-
return;
|
|
3462
|
-
}
|
|
3463
|
-
const activeEntry = {
|
|
3464
|
-
process: void 0,
|
|
3465
|
-
title: idea.title,
|
|
3466
|
-
repoDir,
|
|
3467
|
-
startedAt: Date.now(),
|
|
3468
|
-
lastActivityAt: Date.now()
|
|
3469
|
-
};
|
|
3470
|
-
let attemptIndex = 0;
|
|
3471
|
-
const launchAttempt = async (attemptAgent) => {
|
|
3472
|
-
let spawnFailureReason = null;
|
|
3473
|
-
const child = spawnAgent(
|
|
3474
|
-
attemptAgent,
|
|
3475
|
-
repoDir,
|
|
3476
|
-
prompt2,
|
|
3477
|
-
prefix,
|
|
3478
|
-
void 0,
|
|
3479
|
-
void 0,
|
|
3480
|
-
idea.title,
|
|
3481
|
-
false,
|
|
3482
|
-
(err) => {
|
|
3483
|
-
spawnFailureReason = err.message;
|
|
3484
|
-
}
|
|
3485
|
-
);
|
|
3486
|
-
activeEntry.process = child;
|
|
3487
|
-
activeEntry.currentAgent = attemptAgent;
|
|
3488
|
-
active.set(key, activeEntry);
|
|
3489
|
-
child.on("exit", async (code) => {
|
|
3490
|
-
if (active.get(key)?.process === child) {
|
|
3491
|
-
active.delete(key);
|
|
3492
|
-
}
|
|
3493
|
-
const failedAttempt = code !== 0 || spawnFailureReason !== null;
|
|
3494
|
-
if (failedAttempt) {
|
|
3495
|
-
const nextAgent = attemptOrder[attemptIndex + 1];
|
|
3496
|
-
if (nextAgent) {
|
|
3497
|
-
const failureDetail = spawnFailureReason ?? `exit code ${code}`;
|
|
3498
|
-
logWarn(prefix, `${attemptAgent} failed (${failureDetail}) \u2014 retrying idea generation with ${nextAgent}`);
|
|
3499
|
-
attemptIndex += 1;
|
|
3500
|
-
await launchAttempt(nextAgent);
|
|
3501
|
-
return;
|
|
3502
|
-
}
|
|
3503
|
-
}
|
|
3504
|
-
finishing.add(key);
|
|
3505
|
-
try {
|
|
3506
|
-
if (code === 0) {
|
|
3507
|
-
try {
|
|
3508
|
-
let plan;
|
|
3509
|
-
let protoHtml;
|
|
3510
|
-
let followUpTasks;
|
|
3511
|
-
const planPath = resolve2(repoDir, "idea-plan.md");
|
|
3512
|
-
const tasksPath = resolve2(repoDir, "idea-tasks.json");
|
|
3513
|
-
const protoPath = resolve2(repoDir, "idea-prototype.html");
|
|
3514
|
-
try {
|
|
3515
|
-
plan = readFileSync5(planPath, "utf-8");
|
|
3516
|
-
} catch {
|
|
3517
|
-
}
|
|
3518
|
-
try {
|
|
3519
|
-
protoHtml = readFileSync5(protoPath, "utf-8");
|
|
3520
|
-
} catch {
|
|
3521
|
-
}
|
|
3522
|
-
try {
|
|
3523
|
-
const tasksRaw = readFileSync5(tasksPath, "utf-8");
|
|
3524
|
-
const parsed = JSON.parse(tasksRaw);
|
|
3525
|
-
if (Array.isArray(parsed)) {
|
|
3526
|
-
followUpTasks = parsed.filter((t) => t && typeof t === "object" && "title" in t);
|
|
3527
|
-
}
|
|
3528
|
-
} catch {
|
|
3529
|
-
}
|
|
3530
|
-
if (!plan && !protoHtml) {
|
|
3531
|
-
logError(prefix, `No output files found in ${repoDir}`);
|
|
3532
|
-
await api.patch(`/api/ideas/${idea.id}`, { status: "draft" });
|
|
3533
|
-
return;
|
|
3534
|
-
}
|
|
3535
|
-
const updateData = { status: "generated" };
|
|
3536
|
-
if (plan) updateData.plan = plan;
|
|
3537
|
-
if (followUpTasks) updateData.followUpTasks = followUpTasks;
|
|
3538
|
-
if (protoHtml) {
|
|
3539
|
-
try {
|
|
3540
|
-
const proto = await api.post("/api/prototypes", {
|
|
3541
|
-
title: `${idea.title} \u2014 Idea Prototype`,
|
|
3542
|
-
prompt: idea.description || idea.title,
|
|
3543
|
-
variantCount: 1,
|
|
3544
|
-
projectId: idea.projectId ?? null
|
|
3545
|
-
});
|
|
3546
|
-
await api.patch(`/api/prototypes/${proto.id}`, {
|
|
3547
|
-
status: "completed",
|
|
3548
|
-
files: [{ name: "idea-prototype.html", content: protoHtml }]
|
|
3549
|
-
});
|
|
3550
|
-
updateData.generatedPrototypeId = proto.id;
|
|
3551
|
-
logSuccess(prefix, `Prototype created: ${paint("gray", proto.id.slice(0, 8))}`);
|
|
3552
|
-
} catch (err) {
|
|
3553
|
-
logError(prefix, `Failed to create prototype: ${err.message}`);
|
|
3554
|
-
}
|
|
3555
|
-
}
|
|
3556
|
-
await api.patch(`/api/ideas/${idea.id}`, updateData);
|
|
3557
|
-
logSuccess(prefix, `"${paint("bold", idea.title)}" generation complete`);
|
|
3558
|
-
try {
|
|
3559
|
-
unlinkSync(planPath);
|
|
3560
|
-
} catch {
|
|
3561
|
-
}
|
|
3562
|
-
try {
|
|
3563
|
-
unlinkSync(tasksPath);
|
|
3564
|
-
} catch {
|
|
3565
|
-
}
|
|
3566
|
-
try {
|
|
3567
|
-
unlinkSync(protoPath);
|
|
3568
|
-
} catch {
|
|
3569
|
-
}
|
|
3570
|
-
} catch (err) {
|
|
3571
|
-
logError(prefix, `Failed to upload idea output: ${err.message}`);
|
|
3572
|
-
try {
|
|
3573
|
-
await api.patch(`/api/ideas/${idea.id}`, { status: "draft" });
|
|
3574
|
-
} catch {
|
|
3575
|
-
}
|
|
3576
|
-
}
|
|
3577
|
-
} else {
|
|
3578
|
-
const failureDetail = spawnFailureReason ?? `exit code ${code}`;
|
|
3579
|
-
logError(prefix, `"${paint("bold", idea.title)}" generation failed via ${attemptAgent} (${failureDetail})`);
|
|
3580
|
-
try {
|
|
3581
|
-
await api.patch(`/api/ideas/${idea.id}`, { status: "draft" });
|
|
3582
|
-
} catch {
|
|
3583
|
-
}
|
|
3584
|
-
}
|
|
3585
|
-
} finally {
|
|
3586
|
-
queued.delete(key);
|
|
3587
|
-
finishing.delete(key);
|
|
3588
|
-
}
|
|
3589
|
-
});
|
|
3590
|
-
};
|
|
3591
|
-
await launchAttempt(attemptOrder[attemptIndex]);
|
|
3592
|
-
}
|
|
3593
3403
|
function dispatchScan(scan, prefix, key) {
|
|
3594
3404
|
logDispatch(prefix, `Running scan for project ${paint("cyan", scan.projectId.slice(0, 8))}`);
|
|
3595
3405
|
const scanProc = spawn4(process.execPath, [process.argv[1], "scan", "--project", scan.projectId, "--report", scan.id], {
|
|
@@ -3726,6 +3536,7 @@ ${divider}`);
|
|
|
3726
3536
|
const running = active.get(task.id);
|
|
3727
3537
|
if (running) {
|
|
3728
3538
|
logWarn(prefix, `Task exceeded hang timeout after ${formatElapsed(Date.now() - running.startedAt)}, terminating agent\u2026`);
|
|
3539
|
+
running.terminatedForError = true;
|
|
3729
3540
|
running.process.kill("SIGTERM");
|
|
3730
3541
|
active.delete(task.id);
|
|
3731
3542
|
}
|
|
@@ -3782,7 +3593,7 @@ ${divider}`);
|
|
|
3782
3593
|
queued.delete(taskId);
|
|
3783
3594
|
}
|
|
3784
3595
|
}
|
|
3785
|
-
const nonTaskPrefixes = ["proto-", "repo-", "scan-", "
|
|
3596
|
+
const nonTaskPrefixes = ["proto-", "repo-", "scan-", "test-"];
|
|
3786
3597
|
for (const taskId of failed.keys()) {
|
|
3787
3598
|
if (nonTaskPrefixes.some((p) => taskId.startsWith(p))) continue;
|
|
3788
3599
|
if (!activeTaskIds.has(taskId)) failed.delete(taskId);
|
|
@@ -3851,6 +3662,7 @@ ${divider}`);
|
|
|
3851
3662
|
for (const [key, entry] of active) {
|
|
3852
3663
|
if (key.startsWith("proto-") && !inProgressProtoKeys.has(key)) {
|
|
3853
3664
|
logWarn(watchTag(), `Prototype ${paint("yellow", key)} no longer in_progress, terminating\u2026`);
|
|
3665
|
+
entry.terminatedForError = true;
|
|
3854
3666
|
entry.process.kill("SIGTERM");
|
|
3855
3667
|
active.delete(key);
|
|
3856
3668
|
queued.delete(key);
|
|
@@ -4064,59 +3876,6 @@ ${divider}`);
|
|
|
4064
3876
|
}
|
|
4065
3877
|
dispatchRepoCreation(project, rootDir);
|
|
4066
3878
|
}
|
|
4067
|
-
let generatingIdeas = [];
|
|
4068
|
-
try {
|
|
4069
|
-
generatingIdeas = await api.get("/api/ideas?status=generating");
|
|
4070
|
-
} catch (err) {
|
|
4071
|
-
logError(watchTag(), `Failed to fetch generating ideas: ${err.message}`);
|
|
4072
|
-
}
|
|
4073
|
-
const inProgressIdeaKeys = new Set(generatingIdeas.map((i) => `idea-${i.id}`));
|
|
4074
|
-
for (const [key, entry] of active) {
|
|
4075
|
-
if (key.startsWith("idea-") && !inProgressIdeaKeys.has(key)) {
|
|
4076
|
-
logWarn(watchTag(), `Idea ${paint("yellow", key)} no longer generating, terminating\u2026`);
|
|
4077
|
-
entry.process.kill("SIGTERM");
|
|
4078
|
-
active.delete(key);
|
|
4079
|
-
queued.delete(key);
|
|
4080
|
-
}
|
|
4081
|
-
}
|
|
4082
|
-
for (const key of failed.keys()) {
|
|
4083
|
-
if (key.startsWith("idea-") && !inProgressIdeaKeys.has(key)) failed.delete(key);
|
|
4084
|
-
}
|
|
4085
|
-
for (const key of queued) {
|
|
4086
|
-
if (key.startsWith("idea-") && !inProgressIdeaKeys.has(key) && !finishing.has(key)) queued.delete(key);
|
|
4087
|
-
}
|
|
4088
|
-
const activeIdeaCount = [...active.keys()].filter((k) => k.startsWith("idea-")).length;
|
|
4089
|
-
let ideaSlots = Math.max(0, 1 - activeIdeaCount);
|
|
4090
|
-
for (const idea of generatingIdeas) {
|
|
4091
|
-
if (ideaSlots <= 0) break;
|
|
4092
|
-
const key = `idea-${idea.id}`;
|
|
4093
|
-
if (queued.has(key)) continue;
|
|
4094
|
-
if (finishing.has(key)) continue;
|
|
4095
|
-
if (failed.has(key)) continue;
|
|
4096
|
-
const sid = shortId(idea.id);
|
|
4097
|
-
const prefix = ideaTag(sid);
|
|
4098
|
-
let repoDir;
|
|
4099
|
-
if (idea.projectId) {
|
|
4100
|
-
const dir = findDirectoryForProject(config, idea.projectId, rootDir);
|
|
4101
|
-
if (!dir) {
|
|
4102
|
-
logWarn(prefix, `"${idea.title}": no linked directory found \u2014 skipping`);
|
|
4103
|
-
continue;
|
|
4104
|
-
}
|
|
4105
|
-
repoDir = dir;
|
|
4106
|
-
} else {
|
|
4107
|
-
repoDir = rootDir;
|
|
4108
|
-
}
|
|
4109
|
-
queued.add(key);
|
|
4110
|
-
ideaSlots--;
|
|
4111
|
-
if (dryRun) {
|
|
4112
|
-
logInfo(
|
|
4113
|
-
watchTag(),
|
|
4114
|
-
`${paint("yellow", "[dry-run]")} would dispatch idea "${paint("bold", idea.title)}" in ${paint("cyan", repoDir)}`
|
|
4115
|
-
);
|
|
4116
|
-
continue;
|
|
4117
|
-
}
|
|
4118
|
-
dispatchIdeaJob(idea, repoDir);
|
|
4119
|
-
}
|
|
4120
3879
|
let pendingScans = [];
|
|
4121
3880
|
try {
|
|
4122
3881
|
pendingScans = await api.get("/api/scans?status=pending&limit=5");
|
|
@@ -4741,7 +4500,7 @@ async function checkApiConnectivity() {
|
|
|
4741
4500
|
}
|
|
4742
4501
|
}
|
|
4743
4502
|
function printResults(checks) {
|
|
4744
|
-
const maxNameLen = Math.max(...checks.map((
|
|
4503
|
+
const maxNameLen = Math.max(...checks.map((c11) => c11.name.length));
|
|
4745
4504
|
let allOk = true;
|
|
4746
4505
|
for (const check of checks) {
|
|
4747
4506
|
const isOptional = check.optional ?? false;
|
|
@@ -4755,10 +4514,10 @@ function printResults(checks) {
|
|
|
4755
4514
|
}
|
|
4756
4515
|
async function autoFix(checks, agent) {
|
|
4757
4516
|
const { spawn: spawn8 } = await import("child_process");
|
|
4758
|
-
const ghInstalled = checks.find((
|
|
4759
|
-
const ghAuthed = checks.find((
|
|
4760
|
-
const mrAuthed = checks.find((
|
|
4761
|
-
const claudeCheck = checks.find((
|
|
4517
|
+
const ghInstalled = checks.find((c11) => c11.name === "GitHub CLI (gh)").ok;
|
|
4518
|
+
const ghAuthed = checks.find((c11) => c11.name === "GitHub CLI auth").ok;
|
|
4519
|
+
const mrAuthed = checks.find((c11) => c11.name === "Mr. Manager CLI auth").ok;
|
|
4520
|
+
const claudeCheck = checks.find((c11) => c11.name === "Claude Code (claude)");
|
|
4762
4521
|
if (claudeCheck && !claudeCheck.ok && agent === "claude") {
|
|
4763
4522
|
console.log(paint5("cyan", " Installing Claude Code..."));
|
|
4764
4523
|
console.log(paint5("dim", " Running: curl -fsSL https://claude.ai/install.sh | bash"));
|
|
@@ -4821,7 +4580,7 @@ var setupCommand = new Command14("setup").description("Check that all dependenci
|
|
|
4821
4580
|
console.log("");
|
|
4822
4581
|
return;
|
|
4823
4582
|
}
|
|
4824
|
-
const fixes = checks.filter((
|
|
4583
|
+
const fixes = checks.filter((c11) => !c11.ok && c11.fix && !c11.optional);
|
|
4825
4584
|
if (fixes.length > 0) {
|
|
4826
4585
|
console.log(paint5("yellow", " To fix:"));
|
|
4827
4586
|
for (const fix of fixes) {
|
|
@@ -6014,10 +5773,10 @@ ${codebaseAnalysis.routes.map((r) => `- ${r}`).join("\n")}
|
|
|
6014
5773
|
${codebaseAnalysis.prismaModels.map((m) => `- ${m}`).join("\n")}
|
|
6015
5774
|
|
|
6016
5775
|
**Components:**
|
|
6017
|
-
${codebaseAnalysis.components.slice(0, 15).map((
|
|
5776
|
+
${codebaseAnalysis.components.slice(0, 15).map((c11) => `- ${c11}`).join("\n")}
|
|
6018
5777
|
|
|
6019
5778
|
**Recent Git Commits:**
|
|
6020
|
-
${codebaseAnalysis.recentCommits.slice(0, 8).map((
|
|
5779
|
+
${codebaseAnalysis.recentCommits.slice(0, 8).map((c11) => `- ${c11}`).join("\n")}
|
|
6021
5780
|
|
|
6022
5781
|
**Completed Tasks:**
|
|
6023
5782
|
${context.completedTasks.slice(0, 10).map((t) => `- ${t.title}`).join("\n") || "None"}
|
|
@@ -6464,128 +6223,8 @@ var scanCommand = new Command23("scan").description("Run a product scan on the c
|
|
|
6464
6223
|
}
|
|
6465
6224
|
});
|
|
6466
6225
|
|
|
6467
|
-
// cli/commands/idea.ts
|
|
6468
|
-
import { Command as Command24 } from "commander";
|
|
6469
|
-
var c9 = {
|
|
6470
|
-
reset: "\x1B[0m",
|
|
6471
|
-
bold: "\x1B[1m",
|
|
6472
|
-
dim: "\x1B[2m",
|
|
6473
|
-
cyan: "\x1B[36m",
|
|
6474
|
-
green: "\x1B[32m",
|
|
6475
|
-
yellow: "\x1B[33m",
|
|
6476
|
-
red: "\x1B[31m",
|
|
6477
|
-
blue: "\x1B[34m",
|
|
6478
|
-
gray: "\x1B[90m",
|
|
6479
|
-
magenta: "\x1B[35m"
|
|
6480
|
-
};
|
|
6481
|
-
function paint9(color, text) {
|
|
6482
|
-
return `${c9[color]}${text}${c9.reset}`;
|
|
6483
|
-
}
|
|
6484
|
-
function statusBadge2(status) {
|
|
6485
|
-
switch (status) {
|
|
6486
|
-
case "draft":
|
|
6487
|
-
return paint9("gray", "\u25CB draft");
|
|
6488
|
-
case "generating":
|
|
6489
|
-
return paint9("cyan", "\u27F3 generating");
|
|
6490
|
-
case "generated":
|
|
6491
|
-
return paint9("green", "\u2713 generated");
|
|
6492
|
-
case "promoted":
|
|
6493
|
-
return paint9("magenta", "\u2191 promoted");
|
|
6494
|
-
case "archived":
|
|
6495
|
-
return paint9("dim", "\u2298 archived");
|
|
6496
|
-
default:
|
|
6497
|
-
return paint9("gray", status);
|
|
6498
|
-
}
|
|
6499
|
-
}
|
|
6500
|
-
var ideaCommand = new Command24("idea").description("Manage ideas \u2014 brainstorm, generate prototypes & plans").addCommand(
|
|
6501
|
-
new Command24("list").description("List ideas for the linked project").option("--all", "Show ideas for all projects").option("--status <status>", "Filter by status").action(async (opts) => {
|
|
6502
|
-
const params = new URLSearchParams();
|
|
6503
|
-
if (!opts.all) {
|
|
6504
|
-
const projectId = getLinkedProjectId();
|
|
6505
|
-
if (projectId) {
|
|
6506
|
-
params.set("projectId", projectId);
|
|
6507
|
-
}
|
|
6508
|
-
}
|
|
6509
|
-
if (opts.status) params.set("status", opts.status);
|
|
6510
|
-
const ideas = await api.get(`/api/ideas?${params.toString()}`);
|
|
6511
|
-
if (ideas.length === 0) {
|
|
6512
|
-
console.log(paint9("gray", "No ideas found."));
|
|
6513
|
-
return;
|
|
6514
|
-
}
|
|
6515
|
-
console.log();
|
|
6516
|
-
for (const idea of ideas) {
|
|
6517
|
-
const date = new Date(idea.createdAt).toLocaleDateString();
|
|
6518
|
-
console.log(
|
|
6519
|
-
` ${paint9("bold", idea.title)} ${statusBadge2(idea.status)} ${paint9("gray", idea.id.slice(0, 8))} ${paint9("dim", date)}`
|
|
6520
|
-
);
|
|
6521
|
-
if (idea.description) {
|
|
6522
|
-
console.log(` ${paint9("dim", idea.description.slice(0, 80) + (idea.description.length > 80 ? "\u2026" : ""))}`);
|
|
6523
|
-
}
|
|
6524
|
-
console.log();
|
|
6525
|
-
}
|
|
6526
|
-
})
|
|
6527
|
-
).addCommand(
|
|
6528
|
-
new Command24("create").description("Create a new idea").argument("<title>", "Title of the idea").option("--description <desc>", "Description of the idea").option("--project <projectId>", "Project ID (defaults to linked project)").option("--generate", "Immediately start generating plan & prototype").action(async (title, opts) => {
|
|
6529
|
-
const projectId = opts.project ?? getLinkedProjectId() ?? null;
|
|
6530
|
-
const idea = await api.post("/api/ideas", {
|
|
6531
|
-
title,
|
|
6532
|
-
description: opts.description,
|
|
6533
|
-
projectId
|
|
6534
|
-
});
|
|
6535
|
-
console.log();
|
|
6536
|
-
console.log(` ${paint9("green", "\u2713")} Created idea: ${paint9("bold", idea.title)}`);
|
|
6537
|
-
console.log(` ${paint9("gray", "ID:")} ${idea.id}`);
|
|
6538
|
-
if (opts.generate) {
|
|
6539
|
-
await api.post(`/api/ideas/${idea.id}/generate`);
|
|
6540
|
-
console.log(` ${paint9("cyan", "\u27F3")} Generation will begin automatically via the watch agent.`);
|
|
6541
|
-
}
|
|
6542
|
-
console.log();
|
|
6543
|
-
})
|
|
6544
|
-
).addCommand(
|
|
6545
|
-
new Command24("generate").description("Start generating plan & prototype for an idea").argument("<id>", "Idea ID").action(async (id) => {
|
|
6546
|
-
const idea = await api.post(`/api/ideas/${id}/generate`);
|
|
6547
|
-
console.log();
|
|
6548
|
-
console.log(` ${paint9("cyan", "\u27F3")} Generating: ${paint9("bold", idea.title)}`);
|
|
6549
|
-
console.log(` ${paint9("gray", "The watch agent will pick this up shortly.")}`);
|
|
6550
|
-
console.log();
|
|
6551
|
-
})
|
|
6552
|
-
).addCommand(
|
|
6553
|
-
new Command24("feedback").description("Send feedback to iterate on an idea's generated content").argument("<id>", "Idea ID").argument("<feedback>", "Feedback text").action(async (id, feedback) => {
|
|
6554
|
-
const idea = await api.post(`/api/ideas/${id}/feedback`, { feedback });
|
|
6555
|
-
console.log();
|
|
6556
|
-
console.log(` ${paint9("cyan", "\u27F3")} Feedback sent for: ${paint9("bold", idea.title)}`);
|
|
6557
|
-
console.log(` ${paint9("gray", "The watch agent will re-generate with your feedback.")}`);
|
|
6558
|
-
console.log();
|
|
6559
|
-
})
|
|
6560
|
-
).addCommand(
|
|
6561
|
-
new Command24("promote").description("Promote an idea to a task").argument("<id>", "Idea ID").action(async (id) => {
|
|
6562
|
-
const result = await api.post(`/api/ideas/${id}/promote`);
|
|
6563
|
-
console.log();
|
|
6564
|
-
console.log(` ${paint9("green", "\u2713")} Promoted idea to task: ${paint9("bold", result.task.title)}`);
|
|
6565
|
-
console.log(` ${paint9("gray", "Task ID:")} ${result.task.id}`);
|
|
6566
|
-
console.log();
|
|
6567
|
-
})
|
|
6568
|
-
).addCommand(
|
|
6569
|
-
new Command24("spin-up").description("Spin up a new project with a GitHub repo from an idea").argument("<id>", "Idea ID").option("--name <name>", "Custom project name (defaults to idea title)").action(async (id, opts) => {
|
|
6570
|
-
const body = {};
|
|
6571
|
-
if (opts.name) body.name = opts.name;
|
|
6572
|
-
const result = await api.post(`/api/ideas/${id}/spin-up`, body);
|
|
6573
|
-
console.log();
|
|
6574
|
-
console.log(` ${paint9("green", "\u2713")} Spinning up project: ${paint9("bold", result.project.name)}`);
|
|
6575
|
-
console.log(` ${paint9("gray", "Project ID:")} ${result.project.id}`);
|
|
6576
|
-
if (result.tasks && result.tasks.length > 0) {
|
|
6577
|
-
console.log(` ${paint9("green", "\u2713")} Created ${result.tasks.length} follow-up task(s):`);
|
|
6578
|
-
for (const task of result.tasks) {
|
|
6579
|
-
console.log(` ${paint9("gray", "\u2022")} ${task.title}`);
|
|
6580
|
-
}
|
|
6581
|
-
}
|
|
6582
|
-
console.log(` ${paint9("cyan", "\u27F3")} Repo creation is queued \u2014 the watch daemon will pick it up.`);
|
|
6583
|
-
console.log();
|
|
6584
|
-
})
|
|
6585
|
-
);
|
|
6586
|
-
|
|
6587
6226
|
// cli/commands/doctor.ts
|
|
6588
|
-
import { Command as
|
|
6227
|
+
import { Command as Command24 } from "commander";
|
|
6589
6228
|
import { existsSync as existsSync15 } from "fs";
|
|
6590
6229
|
import { homedir as homedir2 } from "os";
|
|
6591
6230
|
import { join as join11 } from "path";
|
|
@@ -6633,7 +6272,7 @@ async function checkProjectLink() {
|
|
|
6633
6272
|
optional: true
|
|
6634
6273
|
};
|
|
6635
6274
|
}
|
|
6636
|
-
var doctorCommand = new
|
|
6275
|
+
var doctorCommand = new Command24("doctor").description("Diagnose Mr. Manager CLI installation and environment").action(async () => {
|
|
6637
6276
|
const banner = [
|
|
6638
6277
|
``,
|
|
6639
6278
|
paint5("cyan", ` MR DOCTOR`),
|
|
@@ -6664,7 +6303,7 @@ var doctorCommand = new Command25("doctor").description("Diagnose Mr. Manager CL
|
|
|
6664
6303
|
console.log("");
|
|
6665
6304
|
return;
|
|
6666
6305
|
}
|
|
6667
|
-
const fixes = checks.filter((
|
|
6306
|
+
const fixes = checks.filter((c11) => !c11.ok && c11.fix && !c11.optional);
|
|
6668
6307
|
if (fixes.length > 0) {
|
|
6669
6308
|
console.log(paint5("yellow", " To fix:"));
|
|
6670
6309
|
for (const fix of fixes) {
|
|
@@ -6676,14 +6315,14 @@ var doctorCommand = new Command25("doctor").description("Diagnose Mr. Manager CL
|
|
|
6676
6315
|
});
|
|
6677
6316
|
|
|
6678
6317
|
// cli/commands/prompt-audit.ts
|
|
6679
|
-
import { Command as
|
|
6318
|
+
import { Command as Command25 } from "commander";
|
|
6680
6319
|
import { resolve as resolve8 } from "path";
|
|
6681
6320
|
import { existsSync as existsSync16, readFileSync as readFileSync12 } from "fs";
|
|
6682
6321
|
function auditLine(label, tokens) {
|
|
6683
6322
|
const bar = "\u2588".repeat(Math.min(60, Math.round(tokens / 200)));
|
|
6684
6323
|
return ` ${label.padEnd(30)} ${formatTokenCount(tokens).padStart(8)} ${bar}`;
|
|
6685
6324
|
}
|
|
6686
|
-
var promptAuditCommand = new
|
|
6325
|
+
var promptAuditCommand = new Command25("prompt-audit").description("Dry-run prompt construction and report estimated token counts by job type").option("--task <id>", "Audit prompts for a specific task ID").option("--all", "Audit all supported job types with representative data", false).option("--json", "Output as JSON instead of plain text", false).action(async (opts) => {
|
|
6687
6326
|
const results = [];
|
|
6688
6327
|
if (opts.task) {
|
|
6689
6328
|
try {
|
|
@@ -6843,14 +6482,6 @@ ${task.notes}` : "";
|
|
|
6843
6482
|
{ name: "instructions", tokens: 500 }
|
|
6844
6483
|
]
|
|
6845
6484
|
},
|
|
6846
|
-
{
|
|
6847
|
-
jobType: "idea",
|
|
6848
|
-
description: "Idea generation prompt",
|
|
6849
|
-
sections: [
|
|
6850
|
-
{ name: "core-prompt", tokens: 500 },
|
|
6851
|
-
{ name: "idea-desc", tokens: 200 }
|
|
6852
|
-
]
|
|
6853
|
-
},
|
|
6854
6485
|
{
|
|
6855
6486
|
jobType: "repo-creation",
|
|
6856
6487
|
description: "Repository creation prompt",
|
|
@@ -6896,8 +6527,8 @@ ${r.jobType} [${r.identifier}]`);
|
|
|
6896
6527
|
});
|
|
6897
6528
|
|
|
6898
6529
|
// cli/commands/skill.ts
|
|
6899
|
-
import { Command as
|
|
6900
|
-
var
|
|
6530
|
+
import { Command as Command26 } from "commander";
|
|
6531
|
+
var c9 = {
|
|
6901
6532
|
reset: "\x1B[0m",
|
|
6902
6533
|
bold: "\x1B[1m",
|
|
6903
6534
|
dim: "\x1B[2m",
|
|
@@ -6905,7 +6536,7 @@ var c10 = {
|
|
|
6905
6536
|
green: "\x1B[32m",
|
|
6906
6537
|
yellow: "\x1B[33m"
|
|
6907
6538
|
};
|
|
6908
|
-
var skillCommand = new
|
|
6539
|
+
var skillCommand = new Command26("skill").description("Manage skills \u2014 reusable playbooks for AI agents");
|
|
6909
6540
|
skillCommand.command("list").alias("ls").description("List all skills").option("--category <category>", "Filter by category").action(async (opts) => {
|
|
6910
6541
|
const params = new URLSearchParams();
|
|
6911
6542
|
if (opts.category) params.set("category", opts.category);
|
|
@@ -6913,17 +6544,17 @@ skillCommand.command("list").alias("ls").description("List all skills").option("
|
|
|
6913
6544
|
`/api/skills${params.toString() ? `?${params}` : ""}`
|
|
6914
6545
|
);
|
|
6915
6546
|
if (skills.length === 0) {
|
|
6916
|
-
console.log(`${
|
|
6547
|
+
console.log(`${c9.dim}No skills found.${c9.reset}`);
|
|
6917
6548
|
return;
|
|
6918
6549
|
}
|
|
6919
6550
|
for (const skill of skills) {
|
|
6920
|
-
const cat = skill.category ? ` ${
|
|
6921
|
-
const scope = skill.projectId ? ` ${
|
|
6922
|
-
console.log(` ${
|
|
6551
|
+
const cat = skill.category ? ` ${c9.dim}[${skill.category}]${c9.reset}` : "";
|
|
6552
|
+
const scope = skill.projectId ? ` ${c9.dim}(project)${c9.reset}` : ` ${c9.dim}(global)${c9.reset}`;
|
|
6553
|
+
console.log(` ${c9.cyan}${skill.name}${c9.reset}${cat}${scope}`);
|
|
6923
6554
|
if (skill.description) {
|
|
6924
|
-
console.log(` ${
|
|
6555
|
+
console.log(` ${c9.dim}${skill.description}${c9.reset}`);
|
|
6925
6556
|
}
|
|
6926
|
-
console.log(` ${
|
|
6557
|
+
console.log(` ${c9.dim}id: ${skill.id}${c9.reset}`);
|
|
6927
6558
|
}
|
|
6928
6559
|
});
|
|
6929
6560
|
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) => {
|
|
@@ -6959,7 +6590,7 @@ skillCommand.command("create").description("Create a new skill from a markdown f
|
|
|
6959
6590
|
projectId
|
|
6960
6591
|
});
|
|
6961
6592
|
console.log(
|
|
6962
|
-
`${
|
|
6593
|
+
`${c9.green}Created skill:${c9.reset} ${c9.bold}${skill.name}${c9.reset} ${c9.dim}(${skill.id})${c9.reset}`
|
|
6963
6594
|
);
|
|
6964
6595
|
});
|
|
6965
6596
|
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) => {
|
|
@@ -6973,22 +6604,22 @@ skillCommand.command("generate").alias("gen").description("Generate a new skill
|
|
|
6973
6604
|
process.exit(1);
|
|
6974
6605
|
}
|
|
6975
6606
|
}
|
|
6976
|
-
console.log(`${
|
|
6607
|
+
console.log(`${c9.dim}Generating skill...${c9.reset}`);
|
|
6977
6608
|
try {
|
|
6978
6609
|
const skill = await api.post("/api/skills/generate", {
|
|
6979
6610
|
prompt: prompt2,
|
|
6980
6611
|
projectId
|
|
6981
6612
|
});
|
|
6982
6613
|
console.log(
|
|
6983
|
-
`${
|
|
6614
|
+
`${c9.green}Generated skill:${c9.reset} ${c9.bold}${skill.name}${c9.reset}`
|
|
6984
6615
|
);
|
|
6985
6616
|
if (skill.description) {
|
|
6986
|
-
console.log(` ${
|
|
6617
|
+
console.log(` ${c9.dim}${skill.description}${c9.reset}`);
|
|
6987
6618
|
}
|
|
6988
6619
|
if (skill.category) {
|
|
6989
|
-
console.log(` ${
|
|
6620
|
+
console.log(` ${c9.dim}Category: ${skill.category}${c9.reset}`);
|
|
6990
6621
|
}
|
|
6991
|
-
console.log(` ${
|
|
6622
|
+
console.log(` ${c9.dim}id: ${skill.id}${c9.reset}`);
|
|
6992
6623
|
} catch (err) {
|
|
6993
6624
|
console.error(`Failed to generate skill: ${err.message}`);
|
|
6994
6625
|
process.exit(1);
|
|
@@ -6996,17 +6627,17 @@ skillCommand.command("generate").alias("gen").description("Generate a new skill
|
|
|
6996
6627
|
});
|
|
6997
6628
|
|
|
6998
6629
|
// cli/commands/tests.ts
|
|
6999
|
-
import { Command as
|
|
7000
|
-
var
|
|
6630
|
+
import { Command as Command27 } from "commander";
|
|
6631
|
+
var c10 = {
|
|
7001
6632
|
reset: "\x1B[0m",
|
|
7002
6633
|
dim: "\x1B[2m",
|
|
7003
6634
|
yellow: "\x1B[33m"
|
|
7004
6635
|
};
|
|
7005
|
-
var testsCommand = new
|
|
6636
|
+
var testsCommand = new Command27("tests").description("List MR Test scenarios for the linked project").action(async () => {
|
|
7006
6637
|
const projectId = getLinkedProjectId();
|
|
7007
6638
|
if (!projectId) {
|
|
7008
6639
|
console.error(
|
|
7009
|
-
`${
|
|
6640
|
+
`${c10.yellow}No project linked to this directory.${c10.reset} Run "mr link <project-id>" first.`
|
|
7010
6641
|
);
|
|
7011
6642
|
process.exit(1);
|
|
7012
6643
|
}
|
|
@@ -7019,13 +6650,13 @@ var testsCommand = new Command28("tests").description("List MR Test scenarios fo
|
|
|
7019
6650
|
process.exit(1);
|
|
7020
6651
|
}
|
|
7021
6652
|
if (scenarios.length === 0) {
|
|
7022
|
-
console.log(`${
|
|
6653
|
+
console.log(`${c10.dim}No test scenarios found for this project.${c10.reset}`);
|
|
7023
6654
|
return;
|
|
7024
6655
|
}
|
|
7025
6656
|
for (const scenario of scenarios) {
|
|
7026
6657
|
console.log(`### ${scenario.name}`);
|
|
7027
6658
|
if (scenario.description) {
|
|
7028
|
-
console.log(`${
|
|
6659
|
+
console.log(`${c10.dim}${scenario.description}${c10.reset}`);
|
|
7029
6660
|
console.log();
|
|
7030
6661
|
}
|
|
7031
6662
|
console.log(scenario.content);
|
|
@@ -7040,7 +6671,7 @@ var userArgs = process.argv.slice(2);
|
|
|
7040
6671
|
var bypassCommands = /* @__PURE__ */ new Set(["login", "init", "auth", "help", "--help", "-h", "--version", "-V", "doctor", "setup"]);
|
|
7041
6672
|
var shouldBypass = userArgs.length > 0 && bypassCommands.has(userArgs[0]);
|
|
7042
6673
|
if (isFirstRun && !shouldBypass) {
|
|
7043
|
-
const
|
|
6674
|
+
const c11 = {
|
|
7044
6675
|
reset: "\x1B[0m",
|
|
7045
6676
|
bold: "\x1B[1m",
|
|
7046
6677
|
dim: "\x1B[2m",
|
|
@@ -7050,28 +6681,28 @@ if (isFirstRun && !shouldBypass) {
|
|
|
7050
6681
|
magenta: "\x1B[35m"
|
|
7051
6682
|
};
|
|
7052
6683
|
console.log("");
|
|
7053
|
-
console.log(`${
|
|
7054
|
-
console.log(`${
|
|
7055
|
-
console.log(`${
|
|
7056
|
-
console.log(`${
|
|
6684
|
+
console.log(`${c11.cyan} \u2554\u2566\u2557\u2566\u2550\u2557 \u2554\u2566\u2557\u2554\u2550\u2557\u2554\u2557\u2554\u2554\u2550\u2557\u2554\u2550\u2557\u2554\u2550\u2557\u2566\u2550\u2557${c11.reset}`);
|
|
6685
|
+
console.log(`${c11.magenta} \u2551\u2551\u2551\u2560\u2566\u255D \u2551\u2551\u2551\u2560\u2550\u2563\u2551\u2551\u2551\u2560\u2550\u2563\u2551 \u2566\u2551\u2563 \u2560\u2566\u255D${c11.reset}`);
|
|
6686
|
+
console.log(`${c11.cyan} \u2569 \u2569\u2569\u255A\u2550 \u2569 \u2569\u2569 \u2569\u255D\u255A\u255D\u2569 \u2569\u255A\u2550\u255D\u255A\u2550\u255D\u2569\u255A\u2550${c11.reset}`);
|
|
6687
|
+
console.log(`${c11.dim} \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500${c11.reset}`);
|
|
7057
6688
|
console.log("");
|
|
7058
|
-
console.log(`${
|
|
7059
|
-
console.log(`${
|
|
6689
|
+
console.log(`${c11.bold} Welcome to Mr. Manager!${c11.reset}`);
|
|
6690
|
+
console.log(`${c11.dim} Let's get you set up in a few quick steps.${c11.reset}`);
|
|
7060
6691
|
console.log("");
|
|
7061
|
-
console.log(` ${
|
|
7062
|
-
console.log(` ${
|
|
6692
|
+
console.log(` ${c11.yellow}Step 1:${c11.reset} Authenticate via Google OAuth`);
|
|
6693
|
+
console.log(` ${c11.dim}Run:${c11.reset} ${c11.cyan}mr login${c11.reset}`);
|
|
7063
6694
|
console.log("");
|
|
7064
|
-
console.log(` ${
|
|
7065
|
-
console.log(` ${
|
|
6695
|
+
console.log(` ${c11.yellow}Step 2:${c11.reset} Verify your environment`);
|
|
6696
|
+
console.log(` ${c11.dim}Run:${c11.reset} ${c11.cyan}mr setup${c11.reset}`);
|
|
7066
6697
|
console.log("");
|
|
7067
|
-
console.log(` ${
|
|
7068
|
-
console.log(` ${
|
|
6698
|
+
console.log(` ${c11.yellow}Step 3:${c11.reset} Link a repo and start watching`);
|
|
6699
|
+
console.log(` ${c11.dim}Run:${c11.reset} ${c11.cyan}mr link${c11.reset} ${c11.dim}&&${c11.reset} ${c11.cyan}mr watch${c11.reset}`);
|
|
7069
6700
|
console.log("");
|
|
7070
|
-
console.log(`${
|
|
6701
|
+
console.log(`${c11.dim} Or run ${c11.reset}${c11.cyan}mr login${c11.reset}${c11.dim} to get started now.${c11.reset}`);
|
|
7071
6702
|
console.log("");
|
|
7072
6703
|
process.exit(0);
|
|
7073
6704
|
}
|
|
7074
|
-
var program = new
|
|
6705
|
+
var program = new Command28();
|
|
7075
6706
|
program.name("mr").description("Mr. Manager - Task and project management CLI").version(CLI_VERSION);
|
|
7076
6707
|
program.addCommand(initCommand);
|
|
7077
6708
|
program.addCommand(authCommand);
|
|
@@ -7099,7 +6730,6 @@ program.addCommand(testCommand);
|
|
|
7099
6730
|
program.addCommand(featuresCommand);
|
|
7100
6731
|
program.addCommand(noMrCommand);
|
|
7101
6732
|
program.addCommand(scanCommand);
|
|
7102
|
-
program.addCommand(ideaCommand);
|
|
7103
6733
|
program.addCommand(doctorCommand);
|
|
7104
6734
|
program.addCommand(promptAuditCommand);
|
|
7105
6735
|
program.addCommand(skillCommand);
|