@getmonoceros/workbench 1.19.0 → 1.19.2

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/bin.js CHANGED
@@ -3259,8 +3259,8 @@ function removeRepoFromDoc(doc, urlOrPath) {
3259
3259
  if (!isMap2(item)) return false;
3260
3260
  const url = item.get("url");
3261
3261
  if (url === urlOrPath) return true;
3262
- const path24 = item.get("path");
3263
- const effectivePath = typeof path24 === "string" ? path24 : typeof url === "string" ? deriveRepoName(url) : void 0;
3262
+ const path25 = item.get("path");
3263
+ const effectivePath = typeof path25 === "string" ? path25 : typeof url === "string" ? deriveRepoName(url) : void 0;
3264
3264
  return effectivePath === urlOrPath;
3265
3265
  });
3266
3266
  if (idx < 0) return false;
@@ -3372,7 +3372,7 @@ async function runAddRepo(input) {
3372
3372
  "Missing repo URL. Usage: monoceros add-repo <containername> <url>."
3373
3373
  );
3374
3374
  }
3375
- const path24 = (input.path ?? deriveRepoName(url)).trim();
3375
+ const path25 = (input.path ?? deriveRepoName(url)).trim();
3376
3376
  const hasName = typeof input.gitName === "string" && input.gitName.trim().length > 0;
3377
3377
  const hasEmail = typeof input.gitEmail === "string" && input.gitEmail.trim().length > 0;
3378
3378
  if (hasName !== hasEmail) {
@@ -3409,7 +3409,7 @@ async function runAddRepo(input) {
3409
3409
  const providerToWrite = !canonical && explicitProvider ? explicitProvider : void 0;
3410
3410
  const entry2 = {
3411
3411
  url,
3412
- path: path24,
3412
+ path: path25,
3413
3413
  ...hasName && hasEmail ? {
3414
3414
  gitUser: {
3415
3415
  name: input.gitName.trim(),
@@ -6407,7 +6407,7 @@ var CLI_VERSION;
6407
6407
  var init_version = __esm({
6408
6408
  "src/version.ts"() {
6409
6409
  "use strict";
6410
- CLI_VERSION = true ? "1.19.0" : "dev";
6410
+ CLI_VERSION = true ? "1.19.2" : "dev";
6411
6411
  }
6412
6412
  });
6413
6413
 
@@ -8045,7 +8045,6 @@ exit 0
8045
8045
  const servers = [];
8046
8046
  let handledUrl = false;
8047
8047
  const onAuthUrl = (authUrl) => {
8048
- consola16.info("Opening the Claude sign-in page in your browser\u2026");
8049
8048
  openInBrowser(authUrl);
8050
8049
  const target = parseCallbackTarget(authUrl);
8051
8050
  if (!target) {
@@ -8091,9 +8090,7 @@ exit 0
8091
8090
  handledUrl = true;
8092
8091
  onAuthUrl(content.trim());
8093
8092
  }, 250);
8094
- consola16.info(
8095
- "Starting Claude login. Pick your account in Claude's menu \u2014 the browser opens for you, no copying."
8096
- );
8093
+ consola16.info("Logging in to Claude \u2014 a browser window will open for you.");
8097
8094
  const child = spawn8(
8098
8095
  process.execPath,
8099
8096
  [
@@ -8104,7 +8101,7 @@ exit 0
8104
8101
  "--mount-workspace-git-root=false",
8105
8102
  "bash",
8106
8103
  "-lc",
8107
- `export PATH="/workspaces/${name}/${RELAY_DIRNAME}:$PATH"; exec claude`
8104
+ `export PATH="/workspaces/${name}/${RELAY_DIRNAME}:$PATH"; exec claude auth login`
8108
8105
  ],
8109
8106
  {
8110
8107
  cwd: root,
@@ -9007,7 +9004,118 @@ var init_remove_service = __esm({
9007
9004
  }
9008
9005
  });
9009
9006
 
9007
+ // src/devcontainer/browser-bridge.ts
9008
+ import { spawn as spawn10 } from "child_process";
9009
+ import { existsSync as existsSync15, promises as fsp3, readFileSync as readFileSync7 } from "fs";
9010
+ import http2 from "http";
9011
+ import path23 from "path";
9012
+ function openInBrowser2(url) {
9013
+ const platform = process.platform;
9014
+ const [cmd, args] = platform === "darwin" ? ["open", [url]] : platform === "win32" ? ["cmd", ["/c", "start", "", url]] : ["xdg-open", [url]];
9015
+ try {
9016
+ const child = spawn10(cmd, args, {
9017
+ stdio: "ignore",
9018
+ detached: true
9019
+ });
9020
+ child.on("error", () => {
9021
+ });
9022
+ child.unref();
9023
+ } catch {
9024
+ }
9025
+ }
9026
+ async function startBrowserBridge(opts) {
9027
+ const relayDir = path23.join(opts.root, RELAY_DIRNAME2);
9028
+ const relayScript = path23.join(relayDir, "xdg-open");
9029
+ const urlFile = path23.join(relayDir, "url");
9030
+ await fsp3.mkdir(relayDir, { recursive: true });
9031
+ await fsp3.rm(urlFile, { force: true });
9032
+ await fsp3.writeFile(
9033
+ relayScript,
9034
+ `#!/bin/sh
9035
+ printf '%s\\n' "$1" > "$(dirname "$0")/url"
9036
+ exit 0
9037
+ `,
9038
+ { mode: 493 }
9039
+ );
9040
+ await fsp3.chmod(relayScript, 493);
9041
+ const servers = [];
9042
+ let handled = false;
9043
+ const onUrl = (url) => {
9044
+ openInBrowser2(url);
9045
+ const target = parseCallbackTarget(url);
9046
+ if (!target) return;
9047
+ const server = http2.createServer((req, res) => {
9048
+ const reqUrl = req.url ?? target.pathname;
9049
+ res.writeHead(200, { "content-type": "text/html; charset=utf-8" });
9050
+ res.end(
9051
+ '<html><body style="font-family:sans-serif;padding:3rem">You are signed in. You can close this tab and return to the terminal.</body></html>'
9052
+ );
9053
+ void opts.spawn(
9054
+ [
9055
+ "exec",
9056
+ "--workspace-folder",
9057
+ opts.root,
9058
+ "--mount-workspace-git-root=false",
9059
+ "curl",
9060
+ "-fsS",
9061
+ `http://localhost:${target.port}${reqUrl}`
9062
+ ],
9063
+ opts.root,
9064
+ { quiet: true }
9065
+ );
9066
+ });
9067
+ server.on("error", () => {
9068
+ });
9069
+ server.listen(target.port, "127.0.0.1");
9070
+ servers.push(server);
9071
+ };
9072
+ const poll = setInterval(() => {
9073
+ if (handled || !existsSync15(urlFile)) return;
9074
+ let content = "";
9075
+ try {
9076
+ content = readFileSync7(urlFile, "utf8");
9077
+ } catch {
9078
+ return;
9079
+ }
9080
+ if (!content.trim()) return;
9081
+ handled = true;
9082
+ onUrl(content.trim());
9083
+ }, 250);
9084
+ return {
9085
+ relayDirInContainer: `/workspaces/${opts.name}/${RELAY_DIRNAME2}`,
9086
+ async dispose() {
9087
+ clearInterval(poll);
9088
+ for (const s of servers) s.close();
9089
+ await fsp3.rm(relayDir, { recursive: true, force: true });
9090
+ }
9091
+ };
9092
+ }
9093
+ var RELAY_DIRNAME2;
9094
+ var init_browser_bridge = __esm({
9095
+ "src/devcontainer/browser-bridge.ts"() {
9096
+ "use strict";
9097
+ init_services();
9098
+ RELAY_DIRNAME2 = ".monoceros-bridge";
9099
+ }
9100
+ });
9101
+
9010
9102
  // src/devcontainer/run.ts
9103
+ function wrapExec(command, opts) {
9104
+ const leading = [];
9105
+ const stmts = [];
9106
+ if (opts.pathPrepend) {
9107
+ leading.push(opts.pathPrepend);
9108
+ stmts.push(`export PATH="$${leading.length}:$PATH"`);
9109
+ }
9110
+ if (opts.cwd) {
9111
+ leading.push(opts.cwd);
9112
+ stmts.push(`cd -- "$${leading.length}"`);
9113
+ }
9114
+ if (leading.length === 0) return command;
9115
+ const shift = leading.length === 1 ? "shift" : `shift ${leading.length}`;
9116
+ const script = `${stmts.join(" && ")} && ${shift} && exec "$@"`;
9117
+ return ["bash", "-lc", script, "bash", ...leading, ...command];
9118
+ }
9011
9119
  async function runInContainer(opts) {
9012
9120
  if (opts.command.length === 0) {
9013
9121
  throw new Error(
@@ -9022,29 +9130,35 @@ async function runInContainer(opts) {
9022
9130
  { quiet: true }
9023
9131
  );
9024
9132
  if (upCode !== 0) return upCode;
9025
- const innerExec = opts.cwd ? [
9026
- "bash",
9027
- "-lc",
9028
- 'cd -- "$1" && shift && exec "$@"',
9029
- "bash",
9030
- opts.cwd,
9031
- ...opts.command
9032
- ] : opts.command;
9033
- return spawnFn(
9034
- [
9035
- "exec",
9036
- "--workspace-folder",
9133
+ const bridge = opts.name && process.stdout.isTTY ? await startBrowserBridge({
9134
+ name: opts.name,
9135
+ root: opts.root,
9136
+ spawn: spawnFn
9137
+ }) : null;
9138
+ try {
9139
+ const innerExec = wrapExec(opts.command, {
9140
+ ...bridge ? { pathPrepend: bridge.relayDirInContainer } : {},
9141
+ ...opts.cwd ? { cwd: opts.cwd } : {}
9142
+ });
9143
+ return await spawnFn(
9144
+ [
9145
+ "exec",
9146
+ "--workspace-folder",
9147
+ opts.root,
9148
+ "--mount-workspace-git-root=false",
9149
+ ...innerExec
9150
+ ],
9037
9151
  opts.root,
9038
- "--mount-workspace-git-root=false",
9039
- ...innerExec
9040
- ],
9041
- opts.root,
9042
- { interactive: true }
9043
- );
9152
+ { interactive: true }
9153
+ );
9154
+ } finally {
9155
+ if (bridge) await bridge.dispose();
9156
+ }
9044
9157
  }
9045
9158
  var init_run = __esm({
9046
9159
  "src/devcontainer/run.ts"() {
9047
9160
  "use strict";
9161
+ init_browser_bridge();
9048
9162
  init_cli();
9049
9163
  init_shell();
9050
9164
  }
@@ -9088,6 +9202,7 @@ var init_run2 = __esm({
9088
9202
  try {
9089
9203
  const exitCode = await runInContainer({
9090
9204
  root: containerDir(args.name),
9205
+ name: args.name,
9091
9206
  command,
9092
9207
  ...args.in ? { cwd: args.in } : {}
9093
9208
  });
@@ -9279,11 +9394,11 @@ var init_stop = __esm({
9279
9394
  });
9280
9395
 
9281
9396
  // src/tunnel/resolve.ts
9282
- import { existsSync as existsSync15 } from "fs";
9283
- import path23 from "path";
9397
+ import { existsSync as existsSync16 } from "fs";
9398
+ import path24 from "path";
9284
9399
  async function resolveTunnelTarget(opts) {
9285
9400
  const ymlPath = containerConfigPath(opts.name, opts.monocerosHome);
9286
- if (!existsSync15(ymlPath)) {
9401
+ if (!existsSync16(ymlPath)) {
9287
9402
  throw new Error(
9288
9403
  `No yml profile for '${opts.name}' at ${ymlPath}. Run \`monoceros init ${opts.name}\` first.`
9289
9404
  );
@@ -9291,13 +9406,13 @@ async function resolveTunnelTarget(opts) {
9291
9406
  const parsed = await readConfig(ymlPath);
9292
9407
  const config = parsed.config;
9293
9408
  const containerRoot = containerDir(opts.name, opts.monocerosHome);
9294
- if (!existsSync15(containerRoot)) {
9409
+ if (!existsSync16(containerRoot)) {
9295
9410
  throw new Error(
9296
9411
  `Container '${opts.name}' is not materialised at ${containerRoot}. Run \`monoceros apply ${opts.name}\` first.`
9297
9412
  );
9298
9413
  }
9299
- const composePath = path23.join(containerRoot, ".devcontainer", "compose.yaml");
9300
- const isCompose = existsSync15(composePath);
9414
+ const composePath = path24.join(containerRoot, ".devcontainer", "compose.yaml");
9415
+ const isCompose = existsSync16(composePath);
9301
9416
  const parsedTarget = parseTargetArg(opts.target, config);
9302
9417
  const docker = opts.docker ?? defaultDockerExec;
9303
9418
  if (isCompose) {
@@ -9532,7 +9647,7 @@ var init_port_check2 = __esm({
9532
9647
  });
9533
9648
 
9534
9649
  // src/tunnel/run.ts
9535
- import { spawn as spawn10 } from "child_process";
9650
+ import { spawn as spawn11 } from "child_process";
9536
9651
  import { consola as consola34 } from "consola";
9537
9652
  function signalNumber(signal) {
9538
9653
  switch (signal) {
@@ -9622,7 +9737,7 @@ var init_run3 = __esm({
9622
9737
  init_port_check2();
9623
9738
  SOCAT_IMAGE = "alpine/socat:1.8.0.3";
9624
9739
  defaultDockerSpawn = (args) => {
9625
- const child = spawn10("docker", args, {
9740
+ const child = spawn11("docker", args, {
9626
9741
  stdio: "inherit"
9627
9742
  });
9628
9743
  const exited = new Promise((resolve, reject) => {
@@ -9716,7 +9831,7 @@ var init_tunnel = __esm({
9716
9831
  });
9717
9832
 
9718
9833
  // src/upgrade/index.ts
9719
- import { existsSync as existsSync16, promises as fs17 } from "fs";
9834
+ import { existsSync as existsSync17, promises as fs17 } from "fs";
9720
9835
  import { consola as consola36 } from "consola";
9721
9836
  async function fetchRuntimeVersions() {
9722
9837
  const tokenUrl = `https://ghcr.io/token?service=ghcr.io&scope=repository:${RUNTIME_REPO}:pull`;
@@ -9775,7 +9890,7 @@ async function runUpgrade(opts) {
9775
9890
  );
9776
9891
  }
9777
9892
  const ymlPath = containerConfigPath(opts.name, home);
9778
- if (!existsSync16(ymlPath)) {
9893
+ if (!existsSync17(ymlPath)) {
9779
9894
  throw new Error(
9780
9895
  `No such config: ${ymlPath}. Run \`monoceros init <template> ${opts.name}\` first.`
9781
9896
  );
@@ -10207,25 +10322,25 @@ function detectHelpRequest(argv, main2) {
10207
10322
  const separatorIdx = argv.indexOf("--");
10208
10323
  if (helpIdx === -1) return null;
10209
10324
  if (separatorIdx !== -1 && separatorIdx < helpIdx) return null;
10210
- const path24 = [];
10325
+ const path25 = [];
10211
10326
  const tokens = argv.slice(
10212
10327
  0,
10213
10328
  separatorIdx === -1 ? argv.length : separatorIdx
10214
10329
  );
10215
10330
  let cursor = main2;
10216
10331
  const mainName = (main2.meta ?? {}).name ?? "monoceros";
10217
- path24.push(mainName);
10332
+ path25.push(mainName);
10218
10333
  for (const tok of tokens) {
10219
10334
  if (tok.startsWith("-")) continue;
10220
10335
  const subs = cursor.subCommands ?? {};
10221
10336
  if (tok in subs) {
10222
10337
  cursor = subs[tok];
10223
- path24.push(tok);
10338
+ path25.push(tok);
10224
10339
  continue;
10225
10340
  }
10226
10341
  break;
10227
10342
  }
10228
- return { path: path24, cmd: cursor };
10343
+ return { path: path25, cmd: cursor };
10229
10344
  }
10230
10345
  async function maybeRenderHelp(argv, main2) {
10231
10346
  const hit = detectHelpRequest(argv, main2);