@dunnewold-labs/mr-manager 0.4.26 → 0.4.28
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 +45 -12
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -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.28",
|
|
189
189
|
description: "Mr. Manager - Task and project management CLI",
|
|
190
190
|
bin: {
|
|
191
191
|
mr: "./dist/index.mjs"
|
|
@@ -1354,6 +1354,18 @@ If a scenario name matches the feature you're testing (by name or keyword):
|
|
|
1354
1354
|
3. Note in your test plan summary which scenario you used.
|
|
1355
1355
|
|
|
1356
1356
|
If no matching scenario exists, infer interactions from the codebase as normal.`;
|
|
1357
|
+
var SYSTEM_SECTION_QUIET_MODE = `## Quiet Mode \u2014 CRITICAL
|
|
1358
|
+
|
|
1359
|
+
You are running in **quiet mode**. This means:
|
|
1360
|
+
|
|
1361
|
+
1. **DO NOT** write any explanatory text, conversation, commentary, or summaries outside of tool calls.
|
|
1362
|
+
2. **DO NOT** describe what you are about to do or what you just did in prose.
|
|
1363
|
+
3. **ONLY** output text when using \`mr update\` for status updates (keep these to 1 short sentence each).
|
|
1364
|
+
4. All your work must happen through tool calls (Read, Edit, Write, Bash, etc.) \u2014 not through conversational output.
|
|
1365
|
+
5. When you would normally explain your reasoning or next steps, simply proceed silently with the tool calls.
|
|
1366
|
+
6. After completing work, exit immediately without a summary.
|
|
1367
|
+
|
|
1368
|
+
This mode exists to minimize output token usage. Every word of conversational text you generate costs tokens. Tool calls and file writes are the only acceptable output.`;
|
|
1357
1369
|
var SYSTEM_SECTIONS = {
|
|
1358
1370
|
"status-updates": SYSTEM_SECTION_STATUS_UPDATES,
|
|
1359
1371
|
"screenshots": SYSTEM_SECTION_SCREENSHOTS,
|
|
@@ -1362,7 +1374,8 @@ var SYSTEM_SECTIONS = {
|
|
|
1362
1374
|
"features-workflow": SYSTEM_SECTION_FEATURES_WORKFLOW,
|
|
1363
1375
|
"prd-format": SYSTEM_SECTION_PRD_FORMAT,
|
|
1364
1376
|
"prd-open-questions": SYSTEM_SECTION_PRD_OPEN_QUESTIONS,
|
|
1365
|
-
"mr-tests": SYSTEM_SECTION_MR_TESTS
|
|
1377
|
+
"mr-tests": SYSTEM_SECTION_MR_TESTS,
|
|
1378
|
+
"quiet-mode": SYSTEM_SECTION_QUIET_MODE
|
|
1366
1379
|
};
|
|
1367
1380
|
function composeSystemPrompt(sections) {
|
|
1368
1381
|
return sections.map((s) => SYSTEM_SECTIONS[s]).join("\n\n");
|
|
@@ -2498,9 +2511,7 @@ ${systemPrompt}` : prompt2;
|
|
|
2498
2511
|
if (mode === "plan") {
|
|
2499
2512
|
return { bin: "claude", args: [...sessionArgs, ...nameArgs, ...systemArgs, ...turnsArgs, ...modelArgs, "--permission-mode", "plan", "-p", prompt2] };
|
|
2500
2513
|
}
|
|
2501
|
-
const
|
|
2502
|
-
const permissionMode = cfg.claudePermissionMode ?? "auto";
|
|
2503
|
-
const permissionArgs = permissionMode === "dangerously-skip-permissions" ? ["--dangerously-skip-permissions"] : ["--permission-mode", "auto", "--enable-auto-mode"];
|
|
2514
|
+
const permissionArgs = ["--dangerously-skip-permissions"];
|
|
2504
2515
|
return { bin: "claude", args: [...sessionArgs, ...nameArgs, ...systemArgs, ...turnsArgs, ...modelArgs, ...permissionArgs, "-p", prompt2] };
|
|
2505
2516
|
}
|
|
2506
2517
|
function commandExists(cmd) {
|
|
@@ -2573,7 +2584,7 @@ function askYesNo(question) {
|
|
|
2573
2584
|
});
|
|
2574
2585
|
});
|
|
2575
2586
|
}
|
|
2576
|
-
function spawnAgent(agent, repoDir, prompt2, prefix, onActivity, sessionId, name, resumeSession = false, onSpawnError, systemPrompt, maxTurns, claudeModel) {
|
|
2587
|
+
function spawnAgent(agent, repoDir, prompt2, prefix, onActivity, sessionId, name, resumeSession = false, onSpawnError, systemPrompt, maxTurns, claudeModel, onOutputBytes) {
|
|
2577
2588
|
const jobLabel = name ?? "unknown";
|
|
2578
2589
|
console.log(`${timestamp()} ${prefix} ${paint("dim", tokenLogLine("agent", jobLabel, prompt2, systemPrompt))}`);
|
|
2579
2590
|
const { bin, args } = buildAgentArgs(agent, prompt2, "execute", sessionId, name, resumeSession, systemPrompt, maxTurns, claudeModel);
|
|
@@ -2592,12 +2603,14 @@ function spawnAgent(agent, repoDir, prompt2, prefix, onActivity, sessionId, name
|
|
|
2592
2603
|
}
|
|
2593
2604
|
child.stdout?.on("data", (data) => {
|
|
2594
2605
|
onActivity?.();
|
|
2606
|
+
onOutputBytes?.(data.length);
|
|
2595
2607
|
for (const line of data.toString().split("\n")) {
|
|
2596
2608
|
if (line) console.log(`${timestamp()} ${prefix} ${paint("dim", line)}`);
|
|
2597
2609
|
}
|
|
2598
2610
|
});
|
|
2599
2611
|
child.stderr?.on("data", (data) => {
|
|
2600
2612
|
onActivity?.();
|
|
2613
|
+
onOutputBytes?.(data.length);
|
|
2601
2614
|
for (const line of data.toString().split("\n")) {
|
|
2602
2615
|
if (line) logError(prefix, paint("dim", line));
|
|
2603
2616
|
}
|
|
@@ -2606,13 +2619,14 @@ function spawnAgent(agent, repoDir, prompt2, prefix, onActivity, sessionId, name
|
|
|
2606
2619
|
}
|
|
2607
2620
|
var watchCommand = new Command8("watch").description(
|
|
2608
2621
|
"Watch for in-progress tasks and autonomously dispatch an AI coding agent to work on them"
|
|
2609
|
-
).option("--interval <seconds>", "Polling interval in seconds", "15").option("--dry-run", "Show what would be dispatched without spawning the agent", false).option("--plan-approval", "Show the agent's plan and ask for approval before executing", false).option("--root <dir>", "Root directory filter for linked repos (default: cwd)").option("--agent <agent>", "AI agent to use: claude, codex, or gemini", "claude").option("--scan-at <HH:MM>", "Run a product scan daily at this time (e.g., 02:00)").action(async (opts) => {
|
|
2622
|
+
).option("--interval <seconds>", "Polling interval in seconds", "15").option("--dry-run", "Show what would be dispatched without spawning the agent", false).option("--plan-approval", "Show the agent's plan and ask for approval before executing", false).option("--root <dir>", "Root directory filter for linked repos (default: cwd)").option("--agent <agent>", "AI agent to use: claude, codex, or gemini", "claude").option("--scan-at <HH:MM>", "Run a product scan daily at this time (e.g., 02:00)").option("--quiet", "Run all tasks in quiet mode (agent outputs only status updates, no conversation)", false).action(async (opts) => {
|
|
2610
2623
|
const intervalMs = parseInt(opts.interval, 10) * 1e3;
|
|
2611
2624
|
const dryRun = opts.dryRun;
|
|
2612
2625
|
const planApproval = opts.planApproval;
|
|
2613
2626
|
const rootDir = opts.root ? resolve2(opts.root) : process.cwd();
|
|
2614
2627
|
const agent = opts.agent === "codex" ? "codex" : opts.agent === "gemini" ? "gemini" : "claude";
|
|
2615
2628
|
const scanAt = opts.scanAt;
|
|
2629
|
+
const globalQuietMode = opts.quiet;
|
|
2616
2630
|
const taskStallTimeoutMs = getTaskStallTimeoutMs();
|
|
2617
2631
|
const hungTaskTimeoutMinutes = Math.max(5, parseInt(process.env.MR_WATCH_HUNG_TASK_TIMEOUT_MINUTES ?? "60", 10) || 60);
|
|
2618
2632
|
const hungTaskTimeoutMs = hungTaskTimeoutMinutes * 6e4;
|
|
@@ -2633,6 +2647,7 @@ var watchCommand = new Command8("watch").description(
|
|
|
2633
2647
|
`stall-timeout=${paint("cyan", formatTimeoutMinutes(taskStallTimeoutMs))}`,
|
|
2634
2648
|
...planApproval ? [paint("yellow", "plan-approval")] : [],
|
|
2635
2649
|
...dryRun ? [paint("yellow", "dry-run")] : [],
|
|
2650
|
+
...globalQuietMode ? [paint("yellow", "quiet")] : [],
|
|
2636
2651
|
...scanAt ? [`scan-at=${paint("cyan", scanAt)}`] : [],
|
|
2637
2652
|
`hung-timeout=${paint("cyan", `${hungTaskTimeoutMinutes}m`)}`
|
|
2638
2653
|
].join(" ");
|
|
@@ -2757,8 +2772,9 @@ var watchCommand = new Command8("watch").description(
|
|
|
2757
2772
|
const legacyBranchName = `mr/${sid}/${slug}`;
|
|
2758
2773
|
const prefix = taskTag(sid);
|
|
2759
2774
|
const vcs = detectVcs(repoDir)?.provider ?? "github";
|
|
2760
|
-
|
|
2761
|
-
|
|
2775
|
+
const taskIsQuiet = task.quietMode || globalQuietMode;
|
|
2776
|
+
logDispatch(prefix, `"${paint("bold", task.title)}" ${paint("gray", repoDir)} ${paint("dim", `[${vcs}]`)}${taskIsQuiet ? ` ${paint("yellow", "[quiet]")}` : ""}`);
|
|
2777
|
+
await postTaskUpdate(task.id, `Agent dispatched${taskIsQuiet ? " (quiet mode)" : ""} \u2014 starting work on "${task.title}"`, "system");
|
|
2762
2778
|
let subtasks = [];
|
|
2763
2779
|
try {
|
|
2764
2780
|
subtasks = await api.get(`/api/tasks/${task.id}/subtasks`);
|
|
@@ -2824,6 +2840,7 @@ var watchCommand = new Command8("watch").description(
|
|
|
2824
2840
|
);
|
|
2825
2841
|
}
|
|
2826
2842
|
const prompt2 = buildExecutionPrompt(task, repoDir, subtasks, vcs, protoRefs, feedbackUpdates, existingResources, skillRefs, executionDir, startWithoutWorktree, !startWithoutWorktree && isGitRepo(repoDir) ? branchName : void 0);
|
|
2843
|
+
const taskIsQuietForEntry = task.quietMode || globalQuietMode;
|
|
2827
2844
|
const activeEntry = {
|
|
2828
2845
|
process: void 0,
|
|
2829
2846
|
title: task.title,
|
|
@@ -2831,7 +2848,9 @@ var watchCommand = new Command8("watch").description(
|
|
|
2831
2848
|
cleanupRepoDir: cleanupWorktreePath ? repoDir : void 0,
|
|
2832
2849
|
cleanupWorktreePath,
|
|
2833
2850
|
startedAt: Date.now(),
|
|
2834
|
-
lastActivityAt: Date.now()
|
|
2851
|
+
lastActivityAt: Date.now(),
|
|
2852
|
+
outputBytes: 0,
|
|
2853
|
+
quietMode: taskIsQuietForEntry
|
|
2835
2854
|
};
|
|
2836
2855
|
const touchActivity = () => {
|
|
2837
2856
|
activeEntry.lastActivityAt = Date.now();
|
|
@@ -2860,7 +2879,12 @@ var watchCommand = new Command8("watch").description(
|
|
|
2860
2879
|
const shouldResumeClaudeSession = attemptAgent === "claude" && !!task.claudeSessionId && !resumeAlreadyRetried && (hasFeedback || pausedForNetwork?.resumeSession === true);
|
|
2861
2880
|
const sessionId = attemptAgent === "claude" ? shouldResumeClaudeSession ? task.claudeSessionId : randomUUID() : void 0;
|
|
2862
2881
|
const effectiveClaudeModel = attemptAgent === "claude" ? taskClaudeModel : void 0;
|
|
2863
|
-
const
|
|
2882
|
+
const isQuiet = task.quietMode || globalQuietMode;
|
|
2883
|
+
const systemSections = isQuiet ? ["quiet-mode", ...EXECUTION_SYSTEM_SECTIONS] : [...EXECUTION_SYSTEM_SECTIONS];
|
|
2884
|
+
const executionSystemPrompt = composeSystemPrompt(systemSections);
|
|
2885
|
+
if (isQuiet) {
|
|
2886
|
+
logInfo(prefix, `${paint("yellow", "quiet mode")} \u2014 agent will suppress conversational output`);
|
|
2887
|
+
}
|
|
2864
2888
|
const child = spawnAgent(
|
|
2865
2889
|
attemptAgent,
|
|
2866
2890
|
executionDir,
|
|
@@ -2875,7 +2899,10 @@ var watchCommand = new Command8("watch").description(
|
|
|
2875
2899
|
},
|
|
2876
2900
|
executionSystemPrompt,
|
|
2877
2901
|
void 0,
|
|
2878
|
-
effectiveClaudeModel
|
|
2902
|
+
effectiveClaudeModel,
|
|
2903
|
+
(bytes) => {
|
|
2904
|
+
activeEntry.outputBytes += bytes;
|
|
2905
|
+
}
|
|
2879
2906
|
);
|
|
2880
2907
|
activeEntry.process = child;
|
|
2881
2908
|
activeEntry.currentAgent = attemptAgent;
|
|
@@ -2930,6 +2957,12 @@ var watchCommand = new Command8("watch").description(
|
|
|
2930
2957
|
}
|
|
2931
2958
|
}
|
|
2932
2959
|
finishing.add(task.id);
|
|
2960
|
+
const elapsedMs = Date.now() - activeEntry.startedAt;
|
|
2961
|
+
const modeLabel = activeEntry.quietMode ? "quiet" : "standard";
|
|
2962
|
+
const outputTokenEstimate = Math.ceil(activeEntry.outputBytes / 4);
|
|
2963
|
+
console.log(
|
|
2964
|
+
`${timestamp()} ${prefix} ${paint("dim", `[output] mode=${modeLabel} output=~${formatTokenCount(outputTokenEstimate)} elapsed=${Math.round(elapsedMs / 1e3)}s exit=${code}`)}`
|
|
2965
|
+
);
|
|
2933
2966
|
try {
|
|
2934
2967
|
if (code === 0) {
|
|
2935
2968
|
try {
|