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.
@@ -1,5 +1,6 @@
1
1
  export interface RunOptions {
2
2
  config?: string;
3
+ leader?: boolean;
3
4
  noLeader?: boolean;
4
5
  /**
5
6
  * `true` for a bare `--resume` (latest run), or a path to a specific run.
@@ -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 readFileSync2 } from "fs";
5
- import { dirname as dirname3, join as join4 } from "path";
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((resolve4) => {
730
+ (s) => new Promise((resolve5) => {
720
731
  if (s.destroyed || s.writableEnded) {
721
- resolve4();
732
+ resolve5();
722
733
  return;
723
734
  }
724
- s.end(() => resolve4());
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 agents2 = [...new Set(report.agentResults.map((result) => result.agentId))];
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 report.agentResults) {
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).attach(eventBus);
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 { createRequire as createRequire2 } from "module";
923
- var require2 = createRequire2(import.meta.url);
924
- async function upgradeCommand() {
925
- const { version: currentVersion } = require2("../package.json");
926
- console.log(`Current version: v${currentVersion}`);
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 = execSync("npm show multiclaw version", { encoding: "utf8" }).trim();
1024
+ latestVersion = exec(commands.latest, "capture").trim();
931
1025
  } catch {
932
- console.error("\x1B[31mError: Failed to fetch latest version from npm registry\x1B[0m");
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(`\x1B[32m\u2713\x1B[0m Already on the latest version (v${currentVersion})`);
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
- execSync("npm install -g multiclaw@latest", { stdio: "inherit" });
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
- "\x1B[31mError: Upgrade failed. Try running manually: npm install -g multiclaw@latest\x1B[0m"
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 = fileURLToPath(import.meta.url);
954
- var __dirname2 = dirname3(__filename2);
955
- var pkg = JSON.parse(readFileSync2(join4(__dirname2, "../package.json"), "utf-8"));
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.5.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.93.0",
30
+ "@agentclientprotocol/claude-agent-acp": "^0.95.0",
31
31
  "@agentclientprotocol/codex-acp": "^2.2.2",
32
- "@inquirer/prompts": "^8.7.3",
33
- "@multiclawcli/core": "0.5.0",
34
- "@multiclawcli/dashboard": "0.5.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
  },