multiclaw 0.13.0 → 0.14.0

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.
@@ -1,4 +1,4 @@
1
- import type { OrchestratorResult } from "@multiclawcli/core";
1
+ import { type OrchestratorResult } from "@multiclawcli/core";
2
2
  /** A previous run's report, as much of it as resume needs. */
3
3
  export interface ResumeTarget {
4
4
  runDir: string;
@@ -22,14 +22,13 @@ export declare function readReport(runDir: string): OrchestratorResult;
22
22
  /**
23
23
  * Turn a report (plus an optional requirement override) into run config.
24
24
  *
25
- * The requirement is the one thing a report cannot always supply — an older
26
- * report predates the field — so an explicit override wins, and its absence on
27
- * both sides is an error rather than a silently empty run.
25
+ * An explicit requirement override wins. Missing requirements fail rather than
26
+ * silently starting an empty run.
28
27
  */
29
28
  export declare function resumeOptionsFromReport(report: OrchestratorResult, requirementOverride?: string): {
30
29
  requirement: string;
31
30
  resume: {
32
31
  agents: string[];
33
- sessions?: Record<string, string>;
32
+ sessions?: Record<string, import("@multiclawcli/core").SessionRecord>;
34
33
  };
35
34
  };
package/dist/index.js CHANGED
@@ -662,6 +662,9 @@ async function assertRuntimesAvailable(config) {
662
662
  }
663
663
 
664
664
  // src/reporters/ConsoleReporter.ts
665
+ import {
666
+ describeSession
667
+ } from "@multiclawcli/core";
665
668
  var isFancy = !process.env.NO_COLOR && process.env.TERM !== "dumb" && process.stdout.isTTY === true;
666
669
  var S = isFancy ? { ok: "\u2713", fail: "\u2717", run: "\u203A", retry: "\u21BB", skip: "\u2298", warn: "\u26A0", bullet: "\xB7" } : { ok: "+", fail: "x", run: ">", retry: "~", skip: "-", warn: "!", bullet: "*" };
667
670
  var C = isFancy ? {
@@ -685,6 +688,7 @@ var C = isFancy ? {
685
688
  };
686
689
  function markFor(status) {
687
690
  if (status === "success") return { icon: S.ok, color: C.green };
691
+ if (status === "handed_back") return { icon: S.retry, color: C.yellow };
688
692
  if (status === "cancelled") return { icon: S.skip, color: C.yellow };
689
693
  return { icon: S.fail, color: C.red };
690
694
  }
@@ -694,6 +698,13 @@ var ConsoleReporter = class {
694
698
  }
695
699
  handle(e) {
696
700
  switch (e.type) {
701
+ case "agent:session": {
702
+ if (e.payload.action === "state_changed") break;
703
+ console.log(
704
+ e.payload.record.agentId + ": " + e.payload.action.replaceAll("_", " ") + (e.payload.requestedSessionId ? " target=" + e.payload.requestedSessionId : "") + " \u2014 " + describeSession(e.payload.record) + (e.payload.reason ? " \u2014 " + e.payload.reason : "")
705
+ );
706
+ break;
707
+ }
697
708
  case "orchestration:start": {
698
709
  const line = (isFancy ? "\u2550" : "=").repeat(50);
699
710
  const edge = isFancy ? ["\u2554", "\u2551", "\u255A", "\u2557", "\u255D"] : ["+", "|", "+", "+", "+"];
@@ -711,6 +722,23 @@ ${C.bold}${C.purple}${edge[0]}${line}${edge[3]}`);
711
722
  }
712
723
  break;
713
724
  }
725
+ case "orchestration:route": {
726
+ const route = JSON.stringify(e.payload.routing);
727
+ if (route === this.lastRoute) break;
728
+ this.lastRoute = route;
729
+ console.log(
730
+ "Route: " + e.payload.routing.mode + " work=" + (e.payload.routing.workId ?? "unknown") + (e.payload.routing.reroutes ? " (rerouting once)" : "")
731
+ );
732
+ break;
733
+ }
734
+ case "orchestration:routing-error": {
735
+ console.log("Routing incomplete: " + e.payload.message);
736
+ break;
737
+ }
738
+ case "agent:handed-back": {
739
+ console.log(e.payload.agentName + " handed back: " + e.payload.handoffReason);
740
+ break;
741
+ }
714
742
  case "orchestration:stages": {
715
743
  console.log(
716
744
  `${C.dim}${S.bullet} Plan applied \u2014 ${e.payload.stages.length} stages${C.reset}`
@@ -767,7 +795,7 @@ ${C.cyan}${mark} ${reply.message}${C.reset}`);
767
795
  }
768
796
  const line = (isFancy ? "\u2550" : "=").repeat(50);
769
797
  const edge = isFancy ? ["\u2554", "\u2551", "\u255A", "\u2557", "\u255D"] : ["+", "|", "+", "+", "+"];
770
- const title = reply ? reply.mode === "ask" ? `${S.warn} Needs your input` : `${S.ok} Answered` : acceptance ? acceptance.status === "approved" ? `${S.ok} Approved` : acceptance.status === "changes_required" ? `${S.warn} Changes required` : acceptance.status === "cancelled" ? `${S.skip} Acceptance cancelled` : `${S.fail} Acceptance failed` : e.payload.cancelled ? `${S.skip} Cancelled` : success ? `${S.ok} All done` : `${S.warn} Done (with failures)`;
798
+ const title = e.payload.routing?.error ? `${S.warn} Work incomplete` : reply ? reply.mode === "ask" ? `${S.warn} Needs your input` : `${S.ok} Answered` : acceptance ? acceptance.status === "approved" ? `${S.ok} Approved` : acceptance.status === "changes_required" ? `${S.warn} Changes required` : acceptance.status === "cancelled" ? `${S.skip} Acceptance cancelled` : `${S.fail} Acceptance failed` : e.payload.cancelled ? `${S.skip} Cancelled` : success ? `${S.ok} All done` : `${S.warn} Done (with failures)`;
771
799
  console.log(`
772
800
  ${C.bold}${C.purple}${edge[0]}${line}${edge[3]}`);
773
801
  console.log(`${edge[1]} ${title.padEnd(48)}${edge[1]}`);
@@ -788,6 +816,7 @@ ${C.bold}${C.purple}${edge[0]}${line}${edge[3]}`);
788
816
  const cost = e.payload.totalCostUsd;
789
817
  const costStr = cost === void 0 ? "" : ` $${cost.toFixed(2)}`;
790
818
  console.log(` ~ ${"Total".padEnd(nameWidth)} ${totalStr.padStart(7)}${costStr}`);
819
+ if (e.payload.routing?.reroutes) console.log(" Execution attempts (audit):");
791
820
  for (const r of agentResults) {
792
821
  const { icon, color: color2 } = markFor(r.status);
793
822
  const dur = `${(r.duration / 1e3).toFixed(1)}s`;
@@ -795,6 +824,12 @@ ${C.bold}${C.purple}${edge[0]}${line}${edge[3]}`);
795
824
  ` ${color2}${icon}${C.reset} ${r.agentName.padEnd(nameWidth)} ${dur.padStart(7)}`
796
825
  );
797
826
  }
827
+ if (e.payload.routing?.reroutes) {
828
+ console.log(" Effective results:");
829
+ for (const result of e.payload.effectiveAgentResults ?? [])
830
+ console.log(" " + result.agentId + ": " + result.status);
831
+ }
832
+ if (e.payload.routing?.error) console.log(" " + e.payload.routing.error);
798
833
  if (e.payload.deliverables && e.payload.deliverables.length > 0) {
799
834
  console.log(`
800
835
  Deliverables:`);
@@ -893,6 +928,7 @@ function errorMessage(err) {
893
928
  // src/commands/resume.ts
894
929
  import * as fs5 from "fs";
895
930
  import * as path5 from "path";
931
+ import { isSessionRecord } from "@multiclawcli/core";
896
932
  function resolveRunDir(runsRoot, target) {
897
933
  if (typeof target !== "string" || target === "latest") {
898
934
  return latestRunDir(runsRoot);
@@ -928,14 +964,18 @@ function readReport(runDir) {
928
964
  }
929
965
  }
930
966
  function resumeOptionsFromReport(report, requirementOverride) {
931
- const latest = new Map(report.agentResults.map((result) => [result.agentId, result]));
967
+ const latest = new Map(
968
+ (report.effectiveAgentResults ?? report.agentResults).map((result) => [result.agentId, result])
969
+ );
932
970
  const agents2 = [...latest.keys()].filter((id) => id !== report.acceptance?.reviewer);
933
971
  if (agents2.length === 0) {
934
972
  throw new Error("The previous run has no agent results \u2014 nothing to resume");
935
973
  }
936
974
  const sessions2 = {};
937
975
  for (const result of latest.values()) {
938
- if (result.sessionId) sessions2[result.agentId] = result.sessionId;
976
+ if (result.session !== void 0 && !isSessionRecord(result.session))
977
+ throw new Error("Invalid Session metadata for " + result.agentId);
978
+ if (result.session?.sessionId) sessions2[result.agentId] = result.session;
939
979
  }
940
980
  const requirement = requirementOverride ?? report.requirement;
941
981
  if (requirement === void 0) {
@@ -945,8 +985,7 @@ function resumeOptionsFromReport(report, requirementOverride) {
945
985
  requirement,
946
986
  resume: {
947
987
  agents: agents2,
948
- // Absent, not `{}`: core reads a missing `sessions` as "start every agent
949
- // fresh", which is exactly the single-agent retry of a failed agent.
988
+ // No established Session means the fixed retry starts a fresh executor.
950
989
  ...Object.keys(sessions2).length > 0 ? { sessions: sessions2 } : {}
951
990
  }
952
991
  };
@@ -967,6 +1006,7 @@ async function runCommand(requirementArg, options) {
967
1006
  const { requirement, resume } = resumeOptionsFromReport(report, requirementArg);
968
1007
  config.workDir = runDir;
969
1008
  config.resume = resume;
1009
+ config.latestWork = report.work;
970
1010
  config.context = { ...config.context, requirement };
971
1011
  config.logDir = path6.join(runDir, `logs-resume-${stamp}`);
972
1012
  const plan = describeResumePlan({
@@ -1017,6 +1057,8 @@ async function runCommand(requirementArg, options) {
1017
1057
  }
1018
1058
  function printDryRun(preview, workDir) {
1019
1059
  console.log("Dry run \u2014 no pipeline agents will execute.");
1060
+ if (preview.routing)
1061
+ console.log("Route: " + preview.routing.mode + " work=" + preview.routing.workId);
1020
1062
  console.log(`Project: ${preview.name}`);
1021
1063
  console.log(`Work dir: ${workDir}`);
1022
1064
  if (preview.requirement) console.log(`Requirement: ${preview.requirement}`);
@@ -1024,6 +1066,10 @@ function printDryRun(preview, workDir) {
1024
1066
  console.log(`${preview.reply.mode === "ask" ? "Question" : "Reply"}: ${preview.reply.message}`);
1025
1067
  return;
1026
1068
  }
1069
+ for (const session of preview.sessions ?? [])
1070
+ console.log(
1071
+ "Session intent: " + session.agentId + " " + session.action + " \u2014 " + session.reason
1072
+ );
1027
1073
  console.log(`Agents: ${preview.totalAgents}`);
1028
1074
  if (preview.selectionReason) console.log(`Why: ${preview.selectionReason}`);
1029
1075
  for (const stage of preview.stages) {
@@ -1,5 +1,6 @@
1
- import type { EventBus } from "@multiclawcli/core";
1
+ import { type EventBus } from "@multiclawcli/core";
2
2
  export declare class ConsoleReporter {
3
+ private lastRoute?;
3
4
  attach(eventBus: EventBus): () => void;
4
5
  private handle;
5
6
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "multiclaw",
3
- "version": "0.13.0",
3
+ "version": "0.14.0",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "multiclaw": "dist/index.js"
@@ -30,8 +30,8 @@
30
30
  "@agentclientprotocol/claude-agent-acp": "^0.95.0",
31
31
  "@agentclientprotocol/codex-acp": "^2.2.2",
32
32
  "@inquirer/prompts": "^8.7.4",
33
- "@multiclawcli/core": "0.13.0",
34
- "@multiclawcli/dashboard": "0.13.0",
33
+ "@multiclawcli/core": "0.14.0",
34
+ "@multiclawcli/dashboard": "0.14.0",
35
35
  "commander": "^15.0.0",
36
36
  "jiti": "^2.7.0"
37
37
  },