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
|
|
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
|
-
*
|
|
26
|
-
*
|
|
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,
|
|
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(
|
|
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.
|
|
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
|
-
//
|
|
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) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "multiclaw",
|
|
3
|
-
"version": "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.
|
|
34
|
-
"@multiclawcli/dashboard": "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
|
},
|