@dunnewold-labs/mr-manager 0.4.27 → 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.
Files changed (2) hide show
  1. package/dist/index.mjs +44 -9
  2. 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.27",
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");
@@ -2571,7 +2584,7 @@ function askYesNo(question) {
2571
2584
  });
2572
2585
  });
2573
2586
  }
2574
- 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) {
2575
2588
  const jobLabel = name ?? "unknown";
2576
2589
  console.log(`${timestamp()} ${prefix} ${paint("dim", tokenLogLine("agent", jobLabel, prompt2, systemPrompt))}`);
2577
2590
  const { bin, args } = buildAgentArgs(agent, prompt2, "execute", sessionId, name, resumeSession, systemPrompt, maxTurns, claudeModel);
@@ -2590,12 +2603,14 @@ function spawnAgent(agent, repoDir, prompt2, prefix, onActivity, sessionId, name
2590
2603
  }
2591
2604
  child.stdout?.on("data", (data) => {
2592
2605
  onActivity?.();
2606
+ onOutputBytes?.(data.length);
2593
2607
  for (const line of data.toString().split("\n")) {
2594
2608
  if (line) console.log(`${timestamp()} ${prefix} ${paint("dim", line)}`);
2595
2609
  }
2596
2610
  });
2597
2611
  child.stderr?.on("data", (data) => {
2598
2612
  onActivity?.();
2613
+ onOutputBytes?.(data.length);
2599
2614
  for (const line of data.toString().split("\n")) {
2600
2615
  if (line) logError(prefix, paint("dim", line));
2601
2616
  }
@@ -2604,13 +2619,14 @@ function spawnAgent(agent, repoDir, prompt2, prefix, onActivity, sessionId, name
2604
2619
  }
2605
2620
  var watchCommand = new Command8("watch").description(
2606
2621
  "Watch for in-progress tasks and autonomously dispatch an AI coding agent to work on them"
2607
- ).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) => {
2608
2623
  const intervalMs = parseInt(opts.interval, 10) * 1e3;
2609
2624
  const dryRun = opts.dryRun;
2610
2625
  const planApproval = opts.planApproval;
2611
2626
  const rootDir = opts.root ? resolve2(opts.root) : process.cwd();
2612
2627
  const agent = opts.agent === "codex" ? "codex" : opts.agent === "gemini" ? "gemini" : "claude";
2613
2628
  const scanAt = opts.scanAt;
2629
+ const globalQuietMode = opts.quiet;
2614
2630
  const taskStallTimeoutMs = getTaskStallTimeoutMs();
2615
2631
  const hungTaskTimeoutMinutes = Math.max(5, parseInt(process.env.MR_WATCH_HUNG_TASK_TIMEOUT_MINUTES ?? "60", 10) || 60);
2616
2632
  const hungTaskTimeoutMs = hungTaskTimeoutMinutes * 6e4;
@@ -2631,6 +2647,7 @@ var watchCommand = new Command8("watch").description(
2631
2647
  `stall-timeout=${paint("cyan", formatTimeoutMinutes(taskStallTimeoutMs))}`,
2632
2648
  ...planApproval ? [paint("yellow", "plan-approval")] : [],
2633
2649
  ...dryRun ? [paint("yellow", "dry-run")] : [],
2650
+ ...globalQuietMode ? [paint("yellow", "quiet")] : [],
2634
2651
  ...scanAt ? [`scan-at=${paint("cyan", scanAt)}`] : [],
2635
2652
  `hung-timeout=${paint("cyan", `${hungTaskTimeoutMinutes}m`)}`
2636
2653
  ].join(" ");
@@ -2755,8 +2772,9 @@ var watchCommand = new Command8("watch").description(
2755
2772
  const legacyBranchName = `mr/${sid}/${slug}`;
2756
2773
  const prefix = taskTag(sid);
2757
2774
  const vcs = detectVcs(repoDir)?.provider ?? "github";
2758
- logDispatch(prefix, `"${paint("bold", task.title)}" ${paint("gray", repoDir)} ${paint("dim", `[${vcs}]`)}`);
2759
- await postTaskUpdate(task.id, `Agent dispatched \u2014 starting work on "${task.title}"`, "system");
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");
2760
2778
  let subtasks = [];
2761
2779
  try {
2762
2780
  subtasks = await api.get(`/api/tasks/${task.id}/subtasks`);
@@ -2822,6 +2840,7 @@ var watchCommand = new Command8("watch").description(
2822
2840
  );
2823
2841
  }
2824
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;
2825
2844
  const activeEntry = {
2826
2845
  process: void 0,
2827
2846
  title: task.title,
@@ -2829,7 +2848,9 @@ var watchCommand = new Command8("watch").description(
2829
2848
  cleanupRepoDir: cleanupWorktreePath ? repoDir : void 0,
2830
2849
  cleanupWorktreePath,
2831
2850
  startedAt: Date.now(),
2832
- lastActivityAt: Date.now()
2851
+ lastActivityAt: Date.now(),
2852
+ outputBytes: 0,
2853
+ quietMode: taskIsQuietForEntry
2833
2854
  };
2834
2855
  const touchActivity = () => {
2835
2856
  activeEntry.lastActivityAt = Date.now();
@@ -2858,7 +2879,12 @@ var watchCommand = new Command8("watch").description(
2858
2879
  const shouldResumeClaudeSession = attemptAgent === "claude" && !!task.claudeSessionId && !resumeAlreadyRetried && (hasFeedback || pausedForNetwork?.resumeSession === true);
2859
2880
  const sessionId = attemptAgent === "claude" ? shouldResumeClaudeSession ? task.claudeSessionId : randomUUID() : void 0;
2860
2881
  const effectiveClaudeModel = attemptAgent === "claude" ? taskClaudeModel : void 0;
2861
- const executionSystemPrompt = composeSystemPrompt(EXECUTION_SYSTEM_SECTIONS);
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
+ }
2862
2888
  const child = spawnAgent(
2863
2889
  attemptAgent,
2864
2890
  executionDir,
@@ -2873,7 +2899,10 @@ var watchCommand = new Command8("watch").description(
2873
2899
  },
2874
2900
  executionSystemPrompt,
2875
2901
  void 0,
2876
- effectiveClaudeModel
2902
+ effectiveClaudeModel,
2903
+ (bytes) => {
2904
+ activeEntry.outputBytes += bytes;
2905
+ }
2877
2906
  );
2878
2907
  activeEntry.process = child;
2879
2908
  activeEntry.currentAgent = attemptAgent;
@@ -2928,6 +2957,12 @@ var watchCommand = new Command8("watch").description(
2928
2957
  }
2929
2958
  }
2930
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
+ );
2931
2966
  try {
2932
2967
  if (code === 0) {
2933
2968
  try {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dunnewold-labs/mr-manager",
3
- "version": "0.4.27",
3
+ "version": "0.4.28",
4
4
  "description": "Mr. Manager - Task and project management CLI",
5
5
  "bin": {
6
6
  "mr": "./dist/index.mjs"