multiclaw 0.5.0 → 0.6.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.
- package/dist/commands/run.d.ts +1 -0
- package/dist/commands/tui.test.d.ts +1 -0
- package/dist/commands/upgrade.d.ts +29 -0
- package/dist/index.js +138 -26
- package/package.json +5 -5
package/dist/commands/run.d.ts
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1 +1,30 @@
|
|
|
1
|
+
/** Which package manager owns the copy of multiclaw that is currently running. */
|
|
2
|
+
export type Installer = "npm" | "pnpm" | "bun" | "yarn" | "unknown";
|
|
3
|
+
/** Walk up from `start` to the package.json that declares this package. */
|
|
4
|
+
export declare function findPackageRoot(start: string): string | undefined;
|
|
5
|
+
/** Read the installed version straight from disk (no module cache to go stale). */
|
|
6
|
+
export declare function readInstalledVersion(pkgRoot: string): string | undefined;
|
|
7
|
+
/**
|
|
8
|
+
* Identify the installer from the on-disk location of the running package.
|
|
9
|
+
*
|
|
10
|
+
* This is the whole point of the command: `npm install -g` writes to npm's
|
|
11
|
+
* prefix, which is not necessarily where the binary on PATH came from. A user
|
|
12
|
+
* with a pnpm global install used to get a silent no-op upgrade — npm installed
|
|
13
|
+
* a fresh copy somewhere else while `multiclaw --version` kept reporting the
|
|
14
|
+
* pnpm one. Upgrading must therefore target the manager that owns this copy.
|
|
15
|
+
*/
|
|
16
|
+
export declare function detectInstaller(pkgRoot: string): Installer;
|
|
17
|
+
type Exec = (command: string, mode: "capture" | "inherit") => string;
|
|
18
|
+
export interface UpgradeContext {
|
|
19
|
+
pkgRoot: string;
|
|
20
|
+
currentVersion: string;
|
|
21
|
+
installer: Installer;
|
|
22
|
+
/** Re-read after installing: the on-disk copy is what `--version` reports. */
|
|
23
|
+
readVersion: (pkgRoot: string) => string | undefined;
|
|
24
|
+
exec: Exec;
|
|
25
|
+
}
|
|
26
|
+
/** Resolve the running install. `undefined` means it is not an installed copy. */
|
|
27
|
+
export declare function createUpgradeContext(): UpgradeContext | undefined;
|
|
28
|
+
export declare function runUpgrade(ctx: UpgradeContext): Promise<void>;
|
|
1
29
|
export declare function upgradeCommand(): Promise<void>;
|
|
30
|
+
export {};
|
package/dist/index.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/index.ts
|
|
4
|
-
import { readFileSync as
|
|
5
|
-
import { dirname as
|
|
6
|
-
import { fileURLToPath } from "url";
|
|
4
|
+
import { readFileSync as readFileSync3 } from "fs";
|
|
5
|
+
import { dirname as dirname4, join as join5 } from "path";
|
|
6
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
7
7
|
import { Command } from "commander";
|
|
8
8
|
|
|
9
9
|
// src/commands/doctor.ts
|
|
@@ -611,7 +611,7 @@ ${C.bold}${C.purple}${edge[0]}${line}${edge[3]}`);
|
|
|
611
611
|
break;
|
|
612
612
|
}
|
|
613
613
|
case "orchestration:complete": {
|
|
614
|
-
const { success, totalDuration, agentResults, reply } = e.payload;
|
|
614
|
+
const { success, totalDuration, agentResults, reply, acceptance } = e.payload;
|
|
615
615
|
if (reply) {
|
|
616
616
|
const mark = reply.mode === "ask" ? "?" : S.ok;
|
|
617
617
|
console.log(`
|
|
@@ -619,11 +619,22 @@ ${C.cyan}${mark} ${reply.message}${C.reset}`);
|
|
|
619
619
|
}
|
|
620
620
|
const line = (isFancy ? "\u2550" : "=").repeat(50);
|
|
621
621
|
const edge = isFancy ? ["\u2554", "\u2551", "\u255A", "\u2557", "\u255D"] : ["+", "|", "+", "+", "+"];
|
|
622
|
-
const title = reply ? reply.mode === "ask" ? `${S.warn} Needs your input` : `${S.ok} Answered` : e.payload.cancelled ? `${S.skip} Cancelled` : success ? `${S.ok} All done` : `${S.warn} Done (with failures)`;
|
|
622
|
+
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)`;
|
|
623
623
|
console.log(`
|
|
624
624
|
${C.bold}${C.purple}${edge[0]}${line}${edge[3]}`);
|
|
625
625
|
console.log(`${edge[1]} ${title.padEnd(48)}${edge[1]}`);
|
|
626
626
|
console.log(`${edge[2]}${line}${edge[4]}${C.reset}`);
|
|
627
|
+
if (acceptance) {
|
|
628
|
+
console.log(
|
|
629
|
+
` Reviewer: ${acceptance.reviewer} Repair rounds: ${acceptance.repairRounds}`
|
|
630
|
+
);
|
|
631
|
+
if (acceptance.reason) console.log(` ${acceptance.reason}`);
|
|
632
|
+
const review = acceptance.reviews[acceptance.reviews.length - 1];
|
|
633
|
+
if (review) {
|
|
634
|
+
console.log(` ${review.summary}`);
|
|
635
|
+
for (const issue of review.issues) console.log(` ${S.bullet} ${issue}`);
|
|
636
|
+
}
|
|
637
|
+
}
|
|
627
638
|
const nameWidth = Math.max(8, ...agentResults.map((r) => r.agentName.length));
|
|
628
639
|
const totalStr = `${(totalDuration / 1e3).toFixed(1)}s`;
|
|
629
640
|
const cost = e.payload.totalCostUsd;
|
|
@@ -716,12 +727,12 @@ var FileLogWriter = class {
|
|
|
716
727
|
this.streams.clear();
|
|
717
728
|
return Promise.all(
|
|
718
729
|
streams.map(
|
|
719
|
-
(s) => new Promise((
|
|
730
|
+
(s) => new Promise((resolve5) => {
|
|
720
731
|
if (s.destroyed || s.writableEnded) {
|
|
721
|
-
|
|
732
|
+
resolve5();
|
|
722
733
|
return;
|
|
723
734
|
}
|
|
724
|
-
s.end(() =>
|
|
735
|
+
s.end(() => resolve5());
|
|
725
736
|
})
|
|
726
737
|
)
|
|
727
738
|
).then(() => void 0);
|
|
@@ -769,12 +780,13 @@ function readReport(runDir) {
|
|
|
769
780
|
}
|
|
770
781
|
}
|
|
771
782
|
function resumeOptionsFromReport(report, requirementOverride) {
|
|
772
|
-
const
|
|
783
|
+
const latest = new Map(report.agentResults.map((result) => [result.agentId, result]));
|
|
784
|
+
const agents2 = [...latest.keys()].filter((id) => id !== report.acceptance?.reviewer);
|
|
773
785
|
if (agents2.length === 0) {
|
|
774
786
|
throw new Error("The previous run has no agent results \u2014 nothing to resume");
|
|
775
787
|
}
|
|
776
788
|
const sessions = {};
|
|
777
|
-
for (const result of
|
|
789
|
+
for (const result of latest.values()) {
|
|
778
790
|
if (result.sessionId) sessions[result.agentId] = result.sessionId;
|
|
779
791
|
}
|
|
780
792
|
const requirement = requirementOverride ?? report.requirement;
|
|
@@ -796,7 +808,7 @@ function resumeOptionsFromReport(report, requirementOverride) {
|
|
|
796
808
|
var EXIT_CANCELLED = 130;
|
|
797
809
|
async function runCommand(requirementArg, options) {
|
|
798
810
|
const config = await loadConfig(options.config, requirementArg);
|
|
799
|
-
if (options.noLeader) {
|
|
811
|
+
if (options.leader === false || options.noLeader) {
|
|
800
812
|
config.useLeader = false;
|
|
801
813
|
}
|
|
802
814
|
const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-").slice(0, 19);
|
|
@@ -912,47 +924,147 @@ async function tuiCommand(options) {
|
|
|
912
924
|
await startTui({
|
|
913
925
|
config,
|
|
914
926
|
onTurnStart: (eventBus, logDir) => {
|
|
915
|
-
new FileLogWriter(logDir)
|
|
927
|
+
const writer = new FileLogWriter(logDir);
|
|
928
|
+
const detach = writer.attach(eventBus);
|
|
929
|
+
return async () => {
|
|
930
|
+
try {
|
|
931
|
+
await writer.drain();
|
|
932
|
+
} finally {
|
|
933
|
+
detach();
|
|
934
|
+
}
|
|
935
|
+
};
|
|
916
936
|
}
|
|
917
937
|
});
|
|
918
938
|
}
|
|
919
939
|
|
|
920
940
|
// src/commands/upgrade.ts
|
|
921
941
|
import { execSync } from "child_process";
|
|
922
|
-
import {
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
942
|
+
import { existsSync as existsSync5, readFileSync as readFileSync2 } from "fs";
|
|
943
|
+
import { dirname as dirname3, join as join4, resolve as resolve4 } from "path";
|
|
944
|
+
import { fileURLToPath } from "url";
|
|
945
|
+
var PACKAGE_NAME = "multiclaw";
|
|
946
|
+
var RED2 = "\x1B[31m";
|
|
947
|
+
var GREEN2 = "\x1B[32m";
|
|
948
|
+
var RESET2 = "\x1B[0m";
|
|
949
|
+
function readManifest(dir) {
|
|
950
|
+
const manifest = join4(dir, "package.json");
|
|
951
|
+
if (!existsSync5(manifest)) return void 0;
|
|
952
|
+
try {
|
|
953
|
+
return JSON.parse(readFileSync2(manifest, "utf8"));
|
|
954
|
+
} catch {
|
|
955
|
+
return void 0;
|
|
956
|
+
}
|
|
957
|
+
}
|
|
958
|
+
function findPackageRoot(start) {
|
|
959
|
+
let dir = resolve4(start);
|
|
960
|
+
for (; ; ) {
|
|
961
|
+
if (readManifest(dir)?.name === PACKAGE_NAME) return dir;
|
|
962
|
+
const parent = dirname3(dir);
|
|
963
|
+
if (parent === dir) return void 0;
|
|
964
|
+
dir = parent;
|
|
965
|
+
}
|
|
966
|
+
}
|
|
967
|
+
function readInstalledVersion(pkgRoot) {
|
|
968
|
+
return readManifest(pkgRoot)?.version;
|
|
969
|
+
}
|
|
970
|
+
function detectInstaller(pkgRoot) {
|
|
971
|
+
const path6 = pkgRoot.replaceAll("\\", "/");
|
|
972
|
+
if (path6.includes("/pnpm/global/") || path6.includes("/.pnpm/")) return "pnpm";
|
|
973
|
+
if (path6.includes("/install/global/") || path6.includes("/.bun/")) return "bun";
|
|
974
|
+
if (path6.includes("/yarn/global/")) return "yarn";
|
|
975
|
+
if (path6.includes("/node_modules/")) return "npm";
|
|
976
|
+
return "unknown";
|
|
977
|
+
}
|
|
978
|
+
var COMMANDS = {
|
|
979
|
+
npm: { latest: "npm show multiclaw version", install: "npm install -g multiclaw@latest" },
|
|
980
|
+
pnpm: { latest: "pnpm view multiclaw version", install: "pnpm add -g multiclaw@latest" },
|
|
981
|
+
bun: void 0,
|
|
982
|
+
yarn: void 0,
|
|
983
|
+
unknown: void 0
|
|
984
|
+
};
|
|
985
|
+
var MANUAL = {
|
|
986
|
+
npm: "npm install -g multiclaw@latest",
|
|
987
|
+
pnpm: "pnpm add -g multiclaw@latest",
|
|
988
|
+
bun: "bun add -g multiclaw@latest",
|
|
989
|
+
yarn: "yarn global add multiclaw@latest",
|
|
990
|
+
unknown: "npm install -g multiclaw@latest"
|
|
991
|
+
};
|
|
992
|
+
function createUpgradeContext() {
|
|
993
|
+
const pkgRoot = findPackageRoot(dirname3(fileURLToPath(import.meta.url)));
|
|
994
|
+
if (!pkgRoot) return void 0;
|
|
995
|
+
const currentVersion = readInstalledVersion(pkgRoot);
|
|
996
|
+
if (!currentVersion) return void 0;
|
|
997
|
+
return {
|
|
998
|
+
pkgRoot,
|
|
999
|
+
currentVersion,
|
|
1000
|
+
installer: detectInstaller(pkgRoot),
|
|
1001
|
+
readVersion: readInstalledVersion,
|
|
1002
|
+
exec: (command, mode) => {
|
|
1003
|
+
if (mode === "inherit") {
|
|
1004
|
+
execSync(command, { stdio: "inherit" });
|
|
1005
|
+
return "";
|
|
1006
|
+
}
|
|
1007
|
+
return execSync(command, { encoding: "utf8" });
|
|
1008
|
+
}
|
|
1009
|
+
};
|
|
1010
|
+
}
|
|
1011
|
+
async function runUpgrade(ctx) {
|
|
1012
|
+
const { pkgRoot, currentVersion, installer, exec, readVersion } = ctx;
|
|
1013
|
+
console.log(`Current version: v${currentVersion} (${installer} install)`);
|
|
1014
|
+
const commands = COMMANDS[installer];
|
|
1015
|
+
if (!commands) {
|
|
1016
|
+
const reason = installer === "unknown" ? `this copy is not a global install (${pkgRoot})` : `the ${installer} install at ${pkgRoot} cannot be upgraded automatically`;
|
|
1017
|
+
console.error(`${RED2}Error: ${reason}. Run it manually: ${MANUAL[installer]}${RESET2}`);
|
|
1018
|
+
process.exit(1);
|
|
1019
|
+
return;
|
|
1020
|
+
}
|
|
927
1021
|
console.log("Checking for updates...");
|
|
928
1022
|
let latestVersion;
|
|
929
1023
|
try {
|
|
930
|
-
latestVersion =
|
|
1024
|
+
latestVersion = exec(commands.latest, "capture").trim();
|
|
931
1025
|
} catch {
|
|
932
|
-
console.error(
|
|
1026
|
+
console.error(`${RED2}Error: Failed to fetch latest version from npm registry${RESET2}`);
|
|
933
1027
|
process.exit(1);
|
|
934
1028
|
return;
|
|
935
1029
|
}
|
|
936
1030
|
if (latestVersion === currentVersion) {
|
|
937
|
-
console.log(
|
|
1031
|
+
console.log(`${GREEN2}\u2713${RESET2} Already on the latest version (v${currentVersion})`);
|
|
938
1032
|
return;
|
|
939
1033
|
}
|
|
940
1034
|
console.log(`Upgrading multiclaw v${currentVersion} \u2192 v${latestVersion}...`);
|
|
941
1035
|
try {
|
|
942
|
-
|
|
943
|
-
console.log(`\x1B[32m\u2713\x1B[0m Successfully upgraded to v${latestVersion}`);
|
|
1036
|
+
exec(commands.install, "inherit");
|
|
944
1037
|
} catch {
|
|
1038
|
+
console.error(`${RED2}Error: Upgrade failed. Try running manually: ${commands.install}${RESET2}`);
|
|
1039
|
+
process.exit(1);
|
|
1040
|
+
return;
|
|
1041
|
+
}
|
|
1042
|
+
const installedVersion = readVersion(pkgRoot);
|
|
1043
|
+
if (installedVersion !== latestVersion) {
|
|
945
1044
|
console.error(
|
|
946
|
-
|
|
1045
|
+
`${RED2}Error: ${commands.install} finished, but ${pkgRoot} still reports v${installedVersion ?? "unknown"}. Check for a second multiclaw install, then retry.${RESET2}`
|
|
947
1046
|
);
|
|
948
1047
|
process.exit(1);
|
|
1048
|
+
return;
|
|
1049
|
+
}
|
|
1050
|
+
console.log(`${GREEN2}\u2713${RESET2} Successfully upgraded to v${latestVersion} (${pkgRoot})`);
|
|
1051
|
+
}
|
|
1052
|
+
async function upgradeCommand() {
|
|
1053
|
+
const ctx = createUpgradeContext();
|
|
1054
|
+
if (!ctx) {
|
|
1055
|
+
console.error(
|
|
1056
|
+
`${RED2}Error: could not locate the multiclaw package this process is running from.${RESET2}`
|
|
1057
|
+
);
|
|
1058
|
+
process.exit(1);
|
|
1059
|
+
return;
|
|
949
1060
|
}
|
|
1061
|
+
await runUpgrade(ctx);
|
|
950
1062
|
}
|
|
951
1063
|
|
|
952
1064
|
// src/index.ts
|
|
953
|
-
var __filename2 =
|
|
954
|
-
var __dirname2 =
|
|
955
|
-
var pkg = JSON.parse(
|
|
1065
|
+
var __filename2 = fileURLToPath2(import.meta.url);
|
|
1066
|
+
var __dirname2 = dirname4(__filename2);
|
|
1067
|
+
var pkg = JSON.parse(readFileSync3(join5(__dirname2, "../package.json"), "utf-8"));
|
|
956
1068
|
var program = new Command();
|
|
957
1069
|
program.name("multiclaw").description("Multi-agent orchestration CLI").version(pkg.version, "-v, --version", "Display version number").action((options) => tuiCommand(options));
|
|
958
1070
|
program.command("init").description("Scaffold a config file (interactive)").action(() => initCommand());
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "multiclaw",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"bin": {
|
|
6
6
|
"multiclaw": "dist/index.js"
|
|
@@ -27,11 +27,11 @@
|
|
|
27
27
|
"url": "https://github.com/shipengqi/multiclaw/issues"
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@agentclientprotocol/claude-agent-acp": "^0.
|
|
30
|
+
"@agentclientprotocol/claude-agent-acp": "^0.95.0",
|
|
31
31
|
"@agentclientprotocol/codex-acp": "^2.2.2",
|
|
32
|
-
"@inquirer/prompts": "^8.7.
|
|
33
|
-
"@multiclawcli/core": "0.
|
|
34
|
-
"@multiclawcli/dashboard": "0.
|
|
32
|
+
"@inquirer/prompts": "^8.7.4",
|
|
33
|
+
"@multiclawcli/core": "0.6.0",
|
|
34
|
+
"@multiclawcli/dashboard": "0.6.0",
|
|
35
35
|
"commander": "^15.0.0",
|
|
36
36
|
"jiti": "^2.7.0"
|
|
37
37
|
},
|