@dunnewold-labs/mr-manager 0.4.18 → 0.4.20

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 +72 -4
  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.18",
188
+ version: "0.4.20",
189
189
  description: "Mr. Manager - Task and project management CLI",
190
190
  bin: {
191
191
  mr: "./dist/index.mjs"
@@ -2729,11 +2729,12 @@ var watchCommand = new Command8("watch").description(
2729
2729
  return;
2730
2730
  }
2731
2731
  let attemptIndex = 0;
2732
+ let resumeAlreadyRetried = false;
2732
2733
  const launchAttempt = async (attemptAgent) => {
2733
2734
  let spawnFailureReason = null;
2734
2735
  const pausedForNetwork = networkPaused.get(task.id);
2735
- const shouldResumeClaudeSession = attemptAgent === "claude" && !!task.claudeSessionId && (hasFeedback || pausedForNetwork?.resumeSession === true);
2736
- const sessionId = attemptAgent === "claude" ? task.claudeSessionId ?? randomUUID() : void 0;
2736
+ const shouldResumeClaudeSession = attemptAgent === "claude" && !!task.claudeSessionId && !resumeAlreadyRetried && (hasFeedback || pausedForNetwork?.resumeSession === true);
2737
+ const sessionId = attemptAgent === "claude" ? shouldResumeClaudeSession ? task.claudeSessionId : randomUUID() : void 0;
2737
2738
  const executionSystemPrompt = composeSystemPrompt(EXECUTION_SYSTEM_SECTIONS);
2738
2739
  const child = spawnAgent(
2739
2740
  attemptAgent,
@@ -2777,6 +2778,17 @@ var watchCommand = new Command8("watch").description(
2777
2778
  logWarn(prefix, `${attemptAgent} paused after network loss (${failureDetail})`);
2778
2779
  return;
2779
2780
  }
2781
+ if (shouldResumeClaudeSession && !resumeAlreadyRetried) {
2782
+ resumeAlreadyRetried = true;
2783
+ logWarn(prefix, `Claude session resume failed (${failureDetail}) \u2014 retrying with fresh session`);
2784
+ await postTaskUpdate(
2785
+ task.id,
2786
+ `Claude session resume failed \u2014 retrying with fresh session`,
2787
+ "system"
2788
+ );
2789
+ await launchAttempt("claude");
2790
+ return;
2791
+ }
2780
2792
  const nextAgent = attemptOrder[attemptIndex + 1];
2781
2793
  if (nextAgent) {
2782
2794
  logWarn(prefix, `${attemptAgent} failed (${failureDetail}) \u2014 retrying with ${nextAgent}`);
@@ -4909,7 +4921,7 @@ async function ensureDevServer() {
4909
4921
  }
4910
4922
  var browseCommand = new Command18("browse").description("Control a headless browser for QA and testing").argument("[command]", "Browse command (goto, click, fill, screenshot, etc.)").argument("[args...]", "Command arguments").option(
4911
4923
  "--task-id <id>",
4912
- "Attach screenshot to a task update (only for screenshot command)"
4924
+ "Attach output to a task update (for screenshot and recording-stop commands)"
4913
4925
  ).option("--dev", "Auto-start local dev server before browsing").allowUnknownOption(true).action(
4914
4926
  async (command, args, opts) => {
4915
4927
  if (!command) {
@@ -4948,6 +4960,62 @@ var browseCommand = new Command18("browse").description("Control a headless brow
4948
4960
  if (exitCode !== 0) {
4949
4961
  process.exit(exitCode);
4950
4962
  }
4963
+ if (command === "recording-stop" && opts.taskId) {
4964
+ const recordingPath = stdout.match(/Recording saved: (.+)/)?.[1]?.trim();
4965
+ if (!recordingPath || !existsSync9(recordingPath)) {
4966
+ console.error("[browse] Could not find recording file");
4967
+ process.exit(1);
4968
+ }
4969
+ try {
4970
+ const config = loadConfig();
4971
+ const videoBuffer = readFileSync7(recordingPath);
4972
+ const fileName = recordingPath.split("/").pop() || "browse-recording.webm";
4973
+ const isMp4 = fileName.endsWith(".mp4");
4974
+ const formData = new FormData();
4975
+ const blob = new Blob([videoBuffer], {
4976
+ type: isMp4 ? "video/mp4" : "video/webm"
4977
+ });
4978
+ formData.append("file", blob, fileName);
4979
+ formData.append("prefix", "browse-recordings");
4980
+ const uploadRes = await fetch(`${config.apiUrl}/api/upload`, {
4981
+ method: "POST",
4982
+ headers: { Authorization: `Bearer ${config.apiKey}` },
4983
+ body: formData
4984
+ });
4985
+ if (!uploadRes.ok) {
4986
+ const errText = await uploadRes.text();
4987
+ console.error(
4988
+ `[browse] Upload failed: ${uploadRes.status} ${errText}`
4989
+ );
4990
+ process.exit(1);
4991
+ }
4992
+ const uploadData = await uploadRes.json();
4993
+ await api.post(`/api/tasks/${opts.taskId}/updates`, {
4994
+ message: "Browser recording",
4995
+ source: "agent",
4996
+ media: [
4997
+ {
4998
+ kind: "recording",
4999
+ url: uploadData.url,
5000
+ mimeType: isMp4 ? "video/mp4" : "video/webm",
5001
+ label: "Browse recording",
5002
+ captureContext: "browse-recording",
5003
+ uploadState: "uploaded",
5004
+ isCanonical: true
5005
+ }
5006
+ ]
5007
+ });
5008
+ console.log(
5009
+ `[browse] Recording uploaded and attached to task ${opts.taskId}`
5010
+ );
5011
+ } catch (err) {
5012
+ console.error(
5013
+ `[browse] Failed to attach recording: ${err.message}`
5014
+ );
5015
+ process.exit(1);
5016
+ }
5017
+ return;
5018
+ }
4951
5019
  if (command === "screenshot" && opts.taskId) {
4952
5020
  const screenshotPath = stdout.match(/Screenshot saved: (.+)/)?.[1];
4953
5021
  if (!screenshotPath || !existsSync9(screenshotPath)) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dunnewold-labs/mr-manager",
3
- "version": "0.4.18",
3
+ "version": "0.4.20",
4
4
  "description": "Mr. Manager - Task and project management CLI",
5
5
  "bin": {
6
6
  "mr": "./dist/index.mjs"