muonroi-cli 1.7.0 → 1.7.1

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,2 +1,2 @@
1
- export declare const PACKAGE_VERSION = "1.7.0";
1
+ export declare const PACKAGE_VERSION = "1.7.1";
2
2
  export declare const PACKAGE_DESCRIPTION = "BYOK AI coding agent with multi-model council debate, role-based routing, and auto-compact.";
@@ -1,5 +1,5 @@
1
1
  // AUTO-GENERATED by scripts/sync-version.cjs. DO NOT EDIT BY HAND.
2
2
  // Sourced from package.json at build time so it survives bun --compile bundling.
3
- export const PACKAGE_VERSION = "1.7.0";
3
+ export const PACKAGE_VERSION = "1.7.1";
4
4
  export const PACKAGE_DESCRIPTION = "BYOK AI coding agent with multi-model council debate, role-based routing, and auto-compact.";
5
5
  //# sourceMappingURL=version.js.map
@@ -51,6 +51,35 @@ export declare function saveScriptInstallMetadata(metadata: ScriptInstallMetadat
51
51
  export declare function getScriptInstallContext(homeDir?: string): ScriptInstallContext | null;
52
52
  export declare function fetchLatestReleaseVersion(): Promise<string | null>;
53
53
  export declare function parseChecksumsFile(contents: string): Map<string, string>;
54
+ /**
55
+ * How this muonroi-cli was installed. Drives which update path the built-in
56
+ * `/update` flow takes:
57
+ * - "script" → install.sh-managed; runScriptManagedUpdate replaces the binary.
58
+ * - "bun-global" → `bun add -g muonroi-cli`; update via bun.
59
+ * - "npm-global" → `npm install -g muonroi-cli`; update via npm.
60
+ * - "compiled" → standalone single-file binary; re-download / rebuild.
61
+ * - "dev-link" → linked/source build run from a git checkout (bun link,
62
+ * symlinked global bin, or `bun run src/index.ts`); rebuild dist.
63
+ * - "unknown" → can't tell; fall back to generic guidance.
64
+ */
65
+ export type InstallMethod = "script" | "bun-global" | "npm-global" | "compiled" | "dev-link" | "unknown";
66
+ /**
67
+ * Detect how the running muonroi-cli was installed by inspecting the location
68
+ * of this module on disk plus the runtime. Pure path inspection — no I/O beyond
69
+ * the install.json check, so it is safe to call on the hot path.
70
+ */
71
+ export declare function detectInstallMethod(homeDir?: string): InstallMethod;
72
+ /** Package-manager command that updates muonroi-cli for the given method, or null. */
73
+ export declare function getUpdateCommandForMethod(method: InstallMethod): string | null;
74
+ /**
75
+ * Top-level update entry point. Routes to the script-managed updater for
76
+ * install.sh installs, and returns the correct package-manager command for
77
+ * bun/npm global installs (rather than the misleading "reinstall via install.sh"
78
+ * dead-end). We do NOT auto-spawn the package manager: on Windows overwriting the
79
+ * files of the live process is unreliable, so we hand the user an exact command
80
+ * to run from a fresh terminal.
81
+ */
82
+ export declare function runManagedUpdate(currentVersion: string): Promise<ScriptUpdateRunResult>;
54
83
  export declare function runScriptManagedUpdate(currentVersion: string): Promise<ScriptUpdateRunResult>;
55
84
  export declare function buildScriptUninstallPlan(options?: ScriptUninstallOptions, homeDir?: string): ScriptUninstallPlan | null;
56
85
  export declare function runScriptManagedUninstall(options?: ScriptUninstallOptions): Promise<ScriptUpdateRunResult>;
@@ -6,6 +6,7 @@ import path from "path";
6
6
  import readline from "readline";
7
7
  import semverGt from "semver/functions/gt.js";
8
8
  import semverValid from "semver/functions/valid.js";
9
+ import { fileURLToPath } from "url";
9
10
  export const GITHUB_REPO = "muonroi/muonroi-cli";
10
11
  export const RELEASES_API = `https://api.github.com/repos/${GITHUB_REPO}/releases`;
11
12
  export const SCRIPT_INSTALL_METHOD = "script";
@@ -99,6 +100,111 @@ export function parseChecksumsFile(contents) {
99
100
  }
100
101
  return result;
101
102
  }
103
+ /** Absolute filesystem path of THIS module, normalized to forward slashes. */
104
+ function runningModulePath() {
105
+ try {
106
+ return fileURLToPath(import.meta.url).replace(/\\/g, "/");
107
+ }
108
+ catch {
109
+ return (process.argv[1] ?? "").replace(/\\/g, "/");
110
+ }
111
+ }
112
+ /** Walk up from `startDir` looking for a `.git` entry; return the repo root or null. */
113
+ function findGitRoot(startDir) {
114
+ let dir = startDir;
115
+ for (let i = 0; i < 30 && dir; i++) {
116
+ if (fs.existsSync(path.join(dir, ".git")))
117
+ return dir;
118
+ const parent = path.dirname(dir);
119
+ if (parent === dir)
120
+ break;
121
+ dir = parent;
122
+ }
123
+ return null;
124
+ }
125
+ /**
126
+ * Detect how the running muonroi-cli was installed by inspecting the location
127
+ * of this module on disk plus the runtime. Pure path inspection — no I/O beyond
128
+ * the install.json check, so it is safe to call on the hot path.
129
+ */
130
+ export function detectInstallMethod(homeDir = os.homedir()) {
131
+ if (loadScriptInstallMetadata(homeDir))
132
+ return "script";
133
+ const modPath = runningModulePath();
134
+ const importUrl = (import.meta.url || "").replace(/\\/g, "/");
135
+ // Bun single-file compiled executable embeds modules under a virtual root
136
+ // (e.g. "/$bunfs/" or "/~BUN/"), so the module path is not a real fs path.
137
+ if (importUrl.includes("/$bunfs/") || importUrl.includes("/~BUN/") || modPath.includes("/$bunfs/")) {
138
+ return "compiled";
139
+ }
140
+ // Bun's global install root: ~/.bun/install/global/node_modules/muonroi-cli/...
141
+ if (modPath.includes("/.bun/install/global/"))
142
+ return "bun-global";
143
+ if (/\/node_modules\/muonroi-cli\//.test(modPath)) {
144
+ return modPath.includes("/.bun/") ? "bun-global" : "npm-global";
145
+ }
146
+ // Not under node_modules and not launched by node/bun → standalone binary.
147
+ const exeBase = ((process.execPath || "").replace(/\\/g, "/").split("/").pop() ?? "").toLowerCase();
148
+ if (!modPath.includes("/node_modules/") && !/^(node|bun)(\.exe)?$/.test(exeBase)) {
149
+ return "compiled";
150
+ }
151
+ // Linked/source build run from a git checkout (e.g. `bun link`, a symlinked
152
+ // global bin pointing at the repo, or `bun run src/index.ts`). The "update"
153
+ // here is a rebuild, not a package-manager swap.
154
+ if (modPath && !modPath.includes("/node_modules/") && findGitRoot(path.dirname(modPath))) {
155
+ return "dev-link";
156
+ }
157
+ return "unknown";
158
+ }
159
+ /** Package-manager command that updates muonroi-cli for the given method, or null. */
160
+ export function getUpdateCommandForMethod(method) {
161
+ switch (method) {
162
+ case "bun-global":
163
+ return "bun add -g muonroi-cli@latest";
164
+ case "npm-global":
165
+ return "npm install -g muonroi-cli@latest";
166
+ default:
167
+ return null;
168
+ }
169
+ }
170
+ /**
171
+ * Top-level update entry point. Routes to the script-managed updater for
172
+ * install.sh installs, and returns the correct package-manager command for
173
+ * bun/npm global installs (rather than the misleading "reinstall via install.sh"
174
+ * dead-end). We do NOT auto-spawn the package manager: on Windows overwriting the
175
+ * files of the live process is unreliable, so we hand the user an exact command
176
+ * to run from a fresh terminal.
177
+ */
178
+ export async function runManagedUpdate(currentVersion) {
179
+ const method = detectInstallMethod();
180
+ if (method === "script")
181
+ return runScriptManagedUpdate(currentVersion);
182
+ const cmd = getUpdateCommandForMethod(method);
183
+ if (cmd) {
184
+ const pm = method === "bun-global" ? "bun" : "npm";
185
+ return {
186
+ success: true,
187
+ output: `Installed via ${pm} (global package). To update, run this in a fresh terminal:\n\n ${cmd}\n\nThen restart muonroi-cli.`,
188
+ };
189
+ }
190
+ if (method === "compiled") {
191
+ const target = getReleaseTargetForPlatform();
192
+ const asset = target?.assetName ?? "the release asset for your platform";
193
+ return {
194
+ success: true,
195
+ output: `Standalone binary install. Download the latest ${asset} from https://github.com/${GITHUB_REPO}/releases/latest and replace the current binary, or rebuild from source.`,
196
+ };
197
+ }
198
+ if (method === "dev-link") {
199
+ const root = findGitRoot(path.dirname(runningModulePath()));
200
+ const target = root ?? "the muonroi-cli checkout";
201
+ return {
202
+ success: true,
203
+ output: `Running a linked/source build from ${target}. To update, rebuild it:\n\n git -C "${target}" pull && bun install && bun run build\n\nThen restart muonroi-cli. (If you also use the compiled muonroi-cli-dev binary, rebuild that separately.)`,
204
+ };
205
+ }
206
+ return notScriptManaged("update");
207
+ }
102
208
  export async function runScriptManagedUpdate(currentVersion) {
103
209
  const context = getScriptInstallContext();
104
210
  if (!context)
@@ -1,6 +1,6 @@
1
1
  import semverGt from "semver/functions/gt.js";
2
2
  import semverValid from "semver/functions/valid.js";
3
- import { fetchLatestReleaseVersion, runScriptManagedUpdate } from "./install-manager.js";
3
+ import { fetchLatestReleaseVersion, runManagedUpdate } from "./install-manager.js";
4
4
  export async function checkForUpdate(currentVersion) {
5
5
  try {
6
6
  const latestVersion = await fetchLatestReleaseVersion();
@@ -17,6 +17,6 @@ export async function checkForUpdate(currentVersion) {
17
17
  }
18
18
  }
19
19
  export function runUpdate(currentVersion) {
20
- return runScriptManagedUpdate(currentVersion);
20
+ return runManagedUpdate(currentVersion);
21
21
  }
22
22
  //# sourceMappingURL=update-checker.js.map
@@ -95,12 +95,12 @@ describe("checkForUpdate", () => {
95
95
  });
96
96
  });
97
97
  describe("runUpdate", () => {
98
- it("returns success when the script-managed updater succeeds", async () => {
98
+ it("returns success when the managed updater succeeds", async () => {
99
99
  vi.doMock("./install-manager", async () => {
100
100
  const actual = await vi.importActual("./install-manager");
101
101
  return {
102
102
  ...actual,
103
- runScriptManagedUpdate: vi.fn().mockResolvedValue({ success: true, output: "Updated to Grok 2.0.0." }),
103
+ runManagedUpdate: vi.fn().mockResolvedValue({ success: true, output: "Updated to muonroi-cli 2.0.0." }),
104
104
  };
105
105
  });
106
106
  const { runUpdate } = await importModule();
@@ -108,12 +108,12 @@ describe("runUpdate", () => {
108
108
  expect(result.success).toBe(true);
109
109
  expect(result.output).toContain("Updated");
110
110
  });
111
- it("returns failure when the script-managed updater fails", async () => {
111
+ it("returns failure when the managed updater fails", async () => {
112
112
  vi.doMock("./install-manager", async () => {
113
113
  const actual = await vi.importActual("./install-manager");
114
114
  return {
115
115
  ...actual,
116
- runScriptManagedUpdate: vi.fn().mockResolvedValue({ success: false, output: "permission denied" }),
116
+ runManagedUpdate: vi.fn().mockResolvedValue({ success: false, output: "permission denied" }),
117
117
  };
118
118
  });
119
119
  const { runUpdate } = await importModule();
@@ -122,4 +122,17 @@ describe("runUpdate", () => {
122
122
  expect(result.output).toContain("permission denied");
123
123
  });
124
124
  });
125
+ describe("getUpdateCommandForMethod", () => {
126
+ it("maps bun/npm global installs to the right update command", async () => {
127
+ const { getUpdateCommandForMethod } = await import("./install-manager.js");
128
+ expect(getUpdateCommandForMethod("bun-global")).toBe("bun add -g muonroi-cli@latest");
129
+ expect(getUpdateCommandForMethod("npm-global")).toBe("npm install -g muonroi-cli@latest");
130
+ });
131
+ it("returns null for methods without a package-manager command", async () => {
132
+ const { getUpdateCommandForMethod } = await import("./install-manager.js");
133
+ expect(getUpdateCommandForMethod("script")).toBeNull();
134
+ expect(getUpdateCommandForMethod("compiled")).toBeNull();
135
+ expect(getUpdateCommandForMethod("unknown")).toBeNull();
136
+ });
137
+ });
125
138
  //# sourceMappingURL=update-checker.test.js.map
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "workspaces": [
4
4
  "packages/*"
5
5
  ],
6
- "version": "1.7.0",
6
+ "version": "1.7.1",
7
7
  "description": "BYOK AI coding agent with multi-model council debate, role-based routing, and auto-compact.",
8
8
  "repository": {
9
9
  "type": "git",