@boxcompute/cli 0.2.0 → 0.2.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.
package/dist/cli.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  #!/usr/bin/env node
2
+ import { spawn } from "node:child_process";
2
3
  import { type Connection } from "./config.js";
3
4
  import { detectHarnesses, installSkill, readSkill, removeSkill, syncManagedSkills } from "./skill.js";
4
5
  type Io = {
@@ -22,6 +23,18 @@ export type CliDependencies = {
22
23
  readSkill?: typeof readSkill;
23
24
  syncManagedSkills?: typeof syncManagedSkills;
24
25
  };
26
+ type BrowserRuntime = {
27
+ env?: NodeJS.ProcessEnv;
28
+ kernelRelease?: string;
29
+ spawn?: typeof spawn;
30
+ system?: NodeJS.Platform;
31
+ };
32
+ export declare function browserLaunch(url: string, runtime?: Pick<BrowserRuntime, "env" | "kernelRelease" | "system">): {
33
+ command: string;
34
+ args: string[];
35
+ detached: boolean;
36
+ };
37
+ export declare function openBrowser(url: string, runtime?: BrowserRuntime): void;
25
38
  export declare function runCli(argv: string[], supplied?: CliDependencies): Promise<number>;
26
39
  export declare function formatCliError(error: unknown): string;
27
40
  export {};
package/dist/cli.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import { spawn } from "node:child_process";
3
3
  import { readFileSync, realpathSync } from "node:fs";
4
- import { hostname, platform } from "node:os";
4
+ import { hostname, platform, release } from "node:os";
5
5
  import { fileURLToPath } from "node:url";
6
6
  import { BoxComputeClient, BoxComputeHttpError, publicRequest, } from "./client.js";
7
7
  import { clearConnection, loadConnection, loadSavedUrl, saveConnection, } from "./config.js";
@@ -105,13 +105,33 @@ Supported harnesses:
105
105
  class UsageError extends Error {
106
106
  constructor(message) { super(message); this.name = "UsageError"; }
107
107
  }
108
- function browser(url) {
109
- const system = platform();
110
- const command = system === "darwin" ? "open" : system === "win32" ? "cmd" : "xdg-open";
111
- const args = system === "win32" ? ["/c", "start", "", url] : [url];
112
- const child = spawn(command, args, { detached: true, stdio: "ignore" });
113
- child.on("error", () => undefined);
114
- child.unref();
108
+ export function browserLaunch(url, runtime = {}) {
109
+ const system = runtime.system ?? platform();
110
+ const env = runtime.env ?? process.env;
111
+ const kernelRelease = runtime.kernelRelease ?? release();
112
+ const isWsl = system === "linux" && Boolean(env.WSL_DISTRO_NAME || env.WSL_INTEROP || /microsoft/i.test(kernelRelease));
113
+ if (isWsl)
114
+ return { command: "explorer.exe", args: [url], detached: false };
115
+ if (system === "darwin")
116
+ return { command: "open", args: [url], detached: true };
117
+ if (system === "win32")
118
+ return { command: "cmd", args: ["/c", "start", "", url], detached: true };
119
+ return { command: "xdg-open", args: [url], detached: true };
120
+ }
121
+ export function openBrowser(url, runtime = {}) {
122
+ const launch = browserLaunch(url, runtime);
123
+ try {
124
+ const child = (runtime.spawn ?? spawn)(launch.command, launch.args, {
125
+ detached: launch.detached,
126
+ stdio: "ignore",
127
+ });
128
+ child.on("error", () => undefined);
129
+ child.unref();
130
+ }
131
+ catch {
132
+ // The approval URL is always printed before this best-effort launch. Keep
133
+ // polling so headless shells and restricted WSL interop can authenticate.
134
+ }
115
135
  }
116
136
  const delay = (milliseconds) => new Promise((resolve) => setTimeout(resolve, milliseconds));
117
137
  const write = (stream, value) => { stream.write(value); };
@@ -251,7 +271,7 @@ export async function runCli(argv, supplied = {}) {
251
271
  const fetchImpl = supplied.fetch ?? fetch;
252
272
  const now = supplied.now ?? Date.now;
253
273
  const sleep = supplied.sleep ?? delay;
254
- const openBrowser = supplied.openBrowser ?? browser;
274
+ const openBrowserImpl = supplied.openBrowser ?? openBrowser;
255
275
  const load = supplied.loadConnection ?? loadConnection;
256
276
  const savedUrl = supplied.loadSavedUrl ?? loadSavedUrl;
257
277
  const save = supplied.saveConnection ?? saveConnection;
@@ -323,7 +343,7 @@ export async function runCli(argv, supplied = {}) {
323
343
  emit(io, json, { authenticated: false }, "BoxCompute CLI credential revoked and removed.\n");
324
344
  return 0;
325
345
  }
326
- return authenticate(args, { env, io, json, fetch: fetchImpl, now, sleep, openBrowser, loadSavedUrl: savedUrl, saveConnection: save });
346
+ return authenticate(args, { env, io, json, fetch: fetchImpl, now, sleep, openBrowser: openBrowserImpl, loadSavedUrl: savedUrl, saveConnection: save });
327
347
  }
328
348
  if (command === "skill") {
329
349
  let action = args.shift();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@boxcompute/cli",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "description": "Connect local AI agents to BoxCompute sandboxes",
5
5
  "keywords": [
6
6
  "boxcompute",