replicas-cli 0.2.369 → 0.2.371

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.
Files changed (2) hide show
  1. package/dist/index.mjs +446 -227
  2. package/package.json +1 -1
package/dist/index.mjs CHANGED
@@ -7335,7 +7335,7 @@ var require_dist = __commonJS({
7335
7335
  // src/index.ts
7336
7336
  import "dotenv/config";
7337
7337
  import { Command, InvalidArgumentError } from "commander";
7338
- import chalk24 from "chalk";
7338
+ import chalk25 from "chalk";
7339
7339
 
7340
7340
  // src/commands/login.ts
7341
7341
  import http from "http";
@@ -9212,24 +9212,18 @@ When you run services on ports \u2014 such as a web app, API server, or database
9212
9212
 
9213
9213
  ## Running Services for Preview
9214
9214
 
9215
- Services must run as detached background processes so they survive after your command session ends. Do not leave them attached to a foreground terminal.
9215
+ Always start services with \`replicas service start\` (see \`REPLICAS.md\`, "Long-running services"). It daemonizes the process so it survives your turn ending and workspace sleep/wake \u2014 a service left attached to your shell or backgrounded with \`&\`/\`nohup\` dies when the workspace sleeps, leaving the preview broken for the user.
9216
9216
 
9217
- Some potential methods:
9218
9217
  \`\`\`bash
9219
- # Start a detached service with logging
9220
- setsid -f bash -lc 'cd /path/to/app && exec yarn dev >> /tmp/app.log 2>&1'
9221
-
9222
- # For daemons like Docker
9223
- nohup dockerd > /tmp/dockerd.log 2>&1 &
9218
+ replicas service start web "yarn dev" --cwd /path/to/app
9224
9219
  \`\`\`
9225
9220
 
9226
9221
  After starting a service:
9227
- 1. Verify the process is running: \`pgrep -af 'yarn dev'\`
9228
- 2. Check logs for readiness: \`tail -f /tmp/app.log\`
9229
- 3. Confirm it's actually serving: \`curl -s http://localhost:3000\` (or appropriate health check)
9230
- 4. Only create the preview after the service is healthy
9222
+ 1. Check logs for readiness: \`replicas service logs web\`
9223
+ 2. Confirm it's actually serving: \`curl -s http://localhost:3000\` (or appropriate health check)
9224
+ 3. Only create the preview after the service is healthy
9231
9225
 
9232
- If a prior detached process exists on the same port, stop it before restarting.
9226
+ \`replicas service start\` on the same name restarts the service, so you never need to hunt down stale processes on the port.
9233
9227
 
9234
9228
  ## Creating Previews
9235
9229
 
@@ -9302,7 +9296,8 @@ Use this when:
9302
9296
  - The user asks you to create, edit, run, or delete an automation
9303
9297
  - The user asks you to manage environments, environment variables, or environment files
9304
9298
  - The user asks "what envs / repos / automations do I have?"
9305
- - The user asks you to scaffold a \`replicas.json\` / \`replicas.yaml\` in a repo`;
9299
+ - The user asks you to scaffold a \`replicas.json\` / \`replicas.yaml\` in a repo
9300
+ - You need to run a long-lived service (dev server, daemon) \u2014 always use \`replicas service start\` so it survives workspace sleep/wake`;
9306
9301
  var REFERENCE10 = `# Replicas (in-workspace CLI)
9307
9302
 
9308
9303
  This guide covers how to take action *with* Replicas itself from inside a Replicas workspace \u2014 managing automations, environments (and their variables/files), repos, previews, and the user's \`replicas.json\` config \u2014 using the pre-installed \`replicas\` CLI.
@@ -9338,6 +9333,7 @@ In agent mode the CLI hides commands that don't make sense for in-workspace agen
9338
9333
  | \`replicas environment ...\` | Manage environments, env vars, env files |
9339
9334
  | \`replicas automation ...\` | Manage automations (cron + GitHub/GitLab event triggers) |
9340
9335
  | \`replicas preview ...\` | Register / list preview URLs (covered in \`PREVIEWS.md\`) |
9336
+ | \`replicas service ...\` | Run long-lived services detached so they survive workspace sleep/wake (see below) |
9341
9337
  | \`replicas media ...\` | Upload screenshots, videos, audio (covered in \`MEDIA.md\`) |
9342
9338
  | \`replicas slack thread ...\` | Attach or switch Slack thread routing (covered in \`SLACK.md\`) |
9343
9339
 
@@ -9479,6 +9475,24 @@ replicas automation edit <id> \\
9479
9475
 
9480
9476
  \`replicas automation edit <id>\` with no flags drops into interactive mode.
9481
9477
 
9478
+ ## Long-running services
9479
+
9480
+ **Always use \`replicas service start\` to run anything that should keep running after your current command or turn ends** \u2014 dev servers, backend APIs, databases, daemons, watchers. Never leave them attached to your shell, and never rely on plain \`&\`, \`nohup\`, or your own backgrounding: processes started inside your session are torn down when your turn ends and the workspace goes to sleep, so the user finds them dead after waking the workspace. \`replicas service start\` daemonizes the process into its own session, which survives workspace sleep/wake.
9481
+
9482
+ \`\`\`bash
9483
+ replicas service start <name> "<command>" # start (or restart) a named service
9484
+ replicas service start web "bun run dev" --cwd ~/workspaces/app
9485
+ replicas service list # names, pids, running/stopped
9486
+ replicas service logs <name> [-n 100] # tail the service log
9487
+ replicas service stop <name> # stop the whole process group
9488
+ \`\`\`
9489
+
9490
+ Notes:
9491
+ - Quote the command if it contains shell operators: \`replicas service start web "cd app && bun dev"\`.
9492
+ - \`start\` on an existing name restarts it (the old process group is stopped first). It fails fast and prints the log tail if the service dies within the first second.
9493
+ - Logs stream to \`~/.replicas/services/<name>.log\`.
9494
+ - After starting, verify the service is actually healthy (check \`logs\`, then \`curl\` its port) before telling the user it's up or creating a preview for it.
9495
+
9482
9496
  ## Repositories
9483
9497
 
9484
9498
  Read-only listing of repos connected to the org. Use when the user asks "what repos can I use?", or to validate a \`--repository\` value before passing it to \`environment create\` / \`automation create\`:
@@ -9736,7 +9750,7 @@ var HOOK_EXEC_MAX_BUFFER_BYTES = 10 * 1024 * 1024;
9736
9750
  var REPLICAS_CONFIG_FILENAMES = ["replicas.json", "replicas.yaml", "replicas.yml"];
9737
9751
 
9738
9752
  // ../shared/src/cli-version.ts
9739
- var CLI_VERSION = "0.2.369";
9753
+ var CLI_VERSION = "0.2.371";
9740
9754
 
9741
9755
  // ../shared/src/version.ts
9742
9756
  function compareVersions(v1, v2) {
@@ -12095,7 +12109,7 @@ function generateState() {
12095
12109
  }
12096
12110
  async function loginCommand() {
12097
12111
  const state = generateState();
12098
- return new Promise((resolve2, reject) => {
12112
+ return new Promise((resolve3, reject) => {
12099
12113
  let authTimeout;
12100
12114
  let hasHandledCallback = false;
12101
12115
  let lastRedirectUrl = null;
@@ -12232,7 +12246,7 @@ async function loginCommand() {
12232
12246
  setImmediate(() => {
12233
12247
  server.closeAllConnections?.();
12234
12248
  server.close();
12235
- resolve2();
12249
+ resolve3();
12236
12250
  });
12237
12251
  } catch (error2) {
12238
12252
  const errorUrl = `${WEB_APP_URL}/cli-login/error?message=${encodeURIComponent("Failed to verify authentication.")}`;
@@ -12335,13 +12349,13 @@ import chalk5 from "chalk";
12335
12349
  import { spawn } from "child_process";
12336
12350
  var SSH_OPTIONS = ["-o", "StrictHostKeyChecking=no", "-o", "UserKnownHostsFile=/dev/null"];
12337
12351
  async function connectSSH(token, host, proxyCommand) {
12338
- return new Promise((resolve2, reject) => {
12352
+ return new Promise((resolve3, reject) => {
12339
12353
  const sshArgs = proxyCommand ? [...SSH_OPTIONS, "-o", `ProxyCommand=${proxyCommand}`, `${token}@${host}`] : [...SSH_OPTIONS, `${token}@${host}`];
12340
12354
  const ssh = spawn("ssh", sshArgs, {
12341
12355
  stdio: "inherit"
12342
12356
  });
12343
12357
  ssh.on("close", () => {
12344
- resolve2();
12358
+ resolve3();
12345
12359
  });
12346
12360
  ssh.on("error", reject);
12347
12361
  });
@@ -12852,7 +12866,7 @@ async function exchangeCodeForTokens(code, codeVerifier) {
12852
12866
  };
12853
12867
  }
12854
12868
  function startCallbackServer(expectedState, codeVerifier) {
12855
- return new Promise((resolve2, reject) => {
12869
+ return new Promise((resolve3, reject) => {
12856
12870
  const server = http2.createServer(async (req, res) => {
12857
12871
  try {
12858
12872
  if (!req.url) {
@@ -12895,7 +12909,7 @@ function startCallbackServer(expectedState, codeVerifier) {
12895
12909
  res.writeHead(302, { "Location": `${WEB_APP_URL2}/codex/oauth/success` });
12896
12910
  res.end();
12897
12911
  server.close();
12898
- resolve2(tokens);
12912
+ resolve3(tokens);
12899
12913
  } catch (tokenError) {
12900
12914
  const errorMessage = encodeURIComponent(tokenError instanceof Error ? tokenError.message : "Unknown error");
12901
12915
  res.writeHead(302, { "Location": `${WEB_APP_URL2}/codex/oauth/error?message=${errorMessage}` });
@@ -12929,7 +12943,7 @@ async function runCodexOAuthFlow() {
12929
12943
  const state = generateState2();
12930
12944
  const authUrl = buildAuthorizationUrl(pkce.codeChallenge, state);
12931
12945
  const tokensPromise = startCallbackServer(state, pkce.codeVerifier);
12932
- await new Promise((resolve2) => setTimeout(resolve2, 500));
12946
+ await new Promise((resolve3) => setTimeout(resolve3, 500));
12933
12947
  console.log("If the browser does not open automatically, visit:");
12934
12948
  console.log(authUrl);
12935
12949
  console.log();
@@ -13048,10 +13062,10 @@ async function promptForAuthorizationCode(instruction) {
13048
13062
  input: process.stdin,
13049
13063
  output: process.stdout
13050
13064
  });
13051
- return new Promise((resolve2) => {
13065
+ return new Promise((resolve3) => {
13052
13066
  rl.question(instruction, (answer) => {
13053
13067
  rl.close();
13054
- resolve2(answer.trim());
13068
+ resolve3(answer.trim());
13055
13069
  });
13056
13070
  });
13057
13071
  }
@@ -14889,6 +14903,169 @@ async function slackThreadSwitchCommand(workspace, options) {
14889
14903
  });
14890
14904
  }
14891
14905
 
14906
+ // src/commands/service.ts
14907
+ import chalk21 from "chalk";
14908
+ import { spawn as spawn3 } from "child_process";
14909
+ import { closeSync, mkdirSync, openSync, readdirSync, readFileSync, rmSync, writeFileSync } from "fs";
14910
+ import { homedir } from "os";
14911
+ import { join, resolve } from "path";
14912
+ var SERVICES_DIR = join(homedir(), ".replicas", "services");
14913
+ var NAME_PATTERN = /^[a-zA-Z0-9][a-zA-Z0-9._-]*$/;
14914
+ function isValidServiceName(name) {
14915
+ return NAME_PATTERN.test(name);
14916
+ }
14917
+ function tailLines(content, lines) {
14918
+ const all = content.split("\n");
14919
+ if (all.length > 0 && all[all.length - 1] === "") all.pop();
14920
+ return all.slice(-lines).join("\n").trim();
14921
+ }
14922
+ function statePath(name) {
14923
+ return join(SERVICES_DIR, `${name}.json`);
14924
+ }
14925
+ function isServiceState(value) {
14926
+ if (typeof value !== "object" || value === null) return false;
14927
+ const record = value;
14928
+ return typeof record.name === "string" && typeof record.command === "string" && typeof record.cwd === "string" && typeof record.pid === "number" && typeof record.logFile === "string" && typeof record.startedAt === "string";
14929
+ }
14930
+ function readState(name) {
14931
+ let parsed;
14932
+ try {
14933
+ parsed = JSON.parse(readFileSync(statePath(name), "utf-8"));
14934
+ } catch {
14935
+ return null;
14936
+ }
14937
+ return isServiceState(parsed) ? parsed : null;
14938
+ }
14939
+ function isRunning(pid) {
14940
+ try {
14941
+ process.kill(-pid, 0);
14942
+ return true;
14943
+ } catch {
14944
+ return false;
14945
+ }
14946
+ }
14947
+ function sleep(ms) {
14948
+ return new Promise((r) => setTimeout(r, ms));
14949
+ }
14950
+ async function killServiceGroup(pid) {
14951
+ try {
14952
+ process.kill(-pid, "SIGTERM");
14953
+ } catch {
14954
+ return;
14955
+ }
14956
+ for (let i = 0; i < 20; i++) {
14957
+ if (!isRunning(pid)) return;
14958
+ await sleep(250);
14959
+ }
14960
+ try {
14961
+ process.kill(-pid, "SIGKILL");
14962
+ } catch {
14963
+ }
14964
+ }
14965
+ function tailLog(logFile, lines) {
14966
+ try {
14967
+ return tailLines(readFileSync(logFile, "utf-8"), lines);
14968
+ } catch {
14969
+ return "";
14970
+ }
14971
+ }
14972
+ async function serviceStartCommand(name, commandParts, options) {
14973
+ if (!isValidServiceName(name)) {
14974
+ throw new Error('Service name must start with a letter or digit and contain only letters, digits, ".", "_", or "-"');
14975
+ }
14976
+ const command = commandParts.join(" ").trim();
14977
+ if (!command) {
14978
+ throw new Error('Provide the command to run, e.g.: replicas service start web "bun run dev"');
14979
+ }
14980
+ const existing = readState(name);
14981
+ if (existing && isRunning(existing.pid)) {
14982
+ console.log(`Stopping existing "${name}" (pid ${existing.pid}) before restart`);
14983
+ await killServiceGroup(existing.pid);
14984
+ }
14985
+ mkdirSync(SERVICES_DIR, { recursive: true });
14986
+ const cwd = resolve(options.cwd ?? process.cwd());
14987
+ const logFile = join(SERVICES_DIR, `${name}.log`);
14988
+ const logFd = openSync(logFile, "a");
14989
+ writeFileSync(logFd, `
14990
+ === [replicas service] "${name}" started ${(/* @__PURE__ */ new Date()).toISOString()} in ${cwd}: ${command} ===
14991
+ `);
14992
+ const child = spawn3("bash", ["-lc", command], {
14993
+ cwd,
14994
+ detached: true,
14995
+ stdio: ["ignore", logFd, logFd],
14996
+ env: process.env
14997
+ });
14998
+ closeSync(logFd);
14999
+ if (child.pid === void 0) {
15000
+ throw new Error("Failed to spawn service process");
15001
+ }
15002
+ child.unref();
15003
+ const state = {
15004
+ name,
15005
+ command,
15006
+ cwd,
15007
+ pid: child.pid,
15008
+ logFile,
15009
+ startedAt: (/* @__PURE__ */ new Date()).toISOString()
15010
+ };
15011
+ writeFileSync(statePath(name), JSON.stringify(state, null, 2));
15012
+ await sleep(1e3);
15013
+ if (!isRunning(child.pid)) {
15014
+ const logs = tailLog(logFile, 20);
15015
+ rmSync(statePath(name), { force: true });
15016
+ throw new Error(`Service "${name}" exited immediately.${logs ? `
15017
+
15018
+ Last log output:
15019
+ ${logs}` : ""}`);
15020
+ }
15021
+ console.log(`Started "${name}" (pid ${child.pid})`);
15022
+ console.log(`Logs: ${logFile}`);
15023
+ }
15024
+ async function serviceStopCommand(name) {
15025
+ const state = readState(name);
15026
+ if (!state) {
15027
+ throw new Error(`Unknown service "${name}". Run: replicas service list`);
15028
+ }
15029
+ if (isRunning(state.pid)) {
15030
+ await killServiceGroup(state.pid);
15031
+ console.log(`Stopped "${name}" (pid ${state.pid})`);
15032
+ } else {
15033
+ console.log(`Service "${name}" was not running`);
15034
+ }
15035
+ rmSync(statePath(name), { force: true });
15036
+ }
15037
+ async function serviceListCommand() {
15038
+ let entries;
15039
+ try {
15040
+ entries = readdirSync(SERVICES_DIR).filter((f) => f.endsWith(".json"));
15041
+ } catch {
15042
+ entries = [];
15043
+ }
15044
+ const states = entries.map((f) => readState(f.slice(0, -".json".length))).filter((s) => s !== null);
15045
+ if (states.length === 0) {
15046
+ console.log('No services registered. Start one with: replicas service start <name> "<command>"');
15047
+ return;
15048
+ }
15049
+ for (const state of states) {
15050
+ const status = isRunning(state.pid) ? chalk21.green("running") : chalk21.red("stopped");
15051
+ console.log(`${state.name} ${status} pid ${state.pid} started ${state.startedAt}`);
15052
+ console.log(` command: ${state.command} (cwd: ${state.cwd})`);
15053
+ console.log(` logs: ${state.logFile}`);
15054
+ }
15055
+ }
15056
+ async function serviceLogsCommand(name, options) {
15057
+ const state = readState(name);
15058
+ if (!state) {
15059
+ throw new Error(`Unknown service "${name}". Run: replicas service list`);
15060
+ }
15061
+ const lines = options.lines ? Number(options.lines) : 50;
15062
+ if (!Number.isInteger(lines) || lines < 1) {
15063
+ throw new Error("--lines must be a positive integer");
15064
+ }
15065
+ const logs = tailLog(state.logFile, lines);
15066
+ console.log(logs || "(no log output yet)");
15067
+ }
15068
+
14892
15069
  // src/commands/learnings.ts
14893
15070
  function printBlocks(learnings) {
14894
15071
  for (const learning of learnings) {
@@ -14960,16 +15137,16 @@ async function learningsDeleteCommand(id) {
14960
15137
  }
14961
15138
 
14962
15139
  // src/commands/computer/index.ts
14963
- import { spawn as spawn4, spawnSync as spawnSync3 } from "child_process";
15140
+ import { spawn as spawn5, spawnSync as spawnSync3 } from "child_process";
14964
15141
  import { createHash as createHash2 } from "crypto";
14965
- import { closeSync, copyFileSync as copyFileSync2, existsSync as existsSync3, mkdirSync as mkdirSync3, openSync, readFileSync as readFileSync3, readSync, rmSync as rmSync3, writeFileSync as writeFileSync3 } from "fs";
15142
+ import { closeSync as closeSync2, copyFileSync as copyFileSync2, existsSync as existsSync3, mkdirSync as mkdirSync4, openSync as openSync2, readFileSync as readFileSync4, readSync, rmSync as rmSync4, writeFileSync as writeFileSync4 } from "fs";
14966
15143
  import { dirname as dirname3 } from "path";
14967
- import chalk21 from "chalk";
15144
+ import chalk22 from "chalk";
14968
15145
 
14969
15146
  // src/commands/computer/desktop.ts
14970
15147
  import { spawnSync } from "child_process";
14971
- import { existsSync, mkdirSync, readFileSync } from "fs";
14972
- import { dirname, isAbsolute, resolve } from "path";
15148
+ import { existsSync, mkdirSync as mkdirSync2, readFileSync as readFileSync2 } from "fs";
15149
+ import { dirname, isAbsolute, resolve as resolve2 } from "path";
14973
15150
  var STATE_DIR = process.env.REPLICAS_DESKTOP_STATE_DIR || "/tmp/replicas-computer";
14974
15151
  var DEFAULT_DISPLAY = process.env.REPLICAS_DESKTOP_DISPLAY || ":99";
14975
15152
  var NOVNC_PORT = process.env.REPLICAS_DESKTOP_NOVNC_PORT ? parseInt(process.env.REPLICAS_DESKTOP_NOVNC_PORT, 10) : DESKTOP_NOVNC_PORT;
@@ -15004,7 +15181,7 @@ function desktopStackHealthy() {
15004
15181
  const pids = {};
15005
15182
  for (const name of ["openbox", "tint2", "x11vnc", "novnc"]) {
15006
15183
  try {
15007
- const pid = Number.parseInt(readFileSync(`${STATE_DIR}/${name}.pid`, "utf8").trim(), 10);
15184
+ const pid = Number.parseInt(readFileSync2(`${STATE_DIR}/${name}.pid`, "utf8").trim(), 10);
15008
15185
  if (!Number.isFinite(pid)) return false;
15009
15186
  process.kill(pid, 0);
15010
15187
  pids[name] = pid;
@@ -15047,7 +15224,7 @@ function runDisplayCmd(bin, args) {
15047
15224
  return r.stdout?.toString() ?? "";
15048
15225
  }
15049
15226
  function runDesktopInputCmd(args) {
15050
- mkdirSync(dirname(INPUT_LOCK_FILE), { recursive: true });
15227
+ mkdirSync2(dirname(INPUT_LOCK_FILE), { recursive: true });
15051
15228
  return runDisplayCmd("flock", [
15052
15229
  "--exclusive",
15053
15230
  "--wait",
@@ -15106,7 +15283,7 @@ function parseScreenCoord(value, label, size) {
15106
15283
  return n;
15107
15284
  }
15108
15285
  function resolvePath(p) {
15109
- return isAbsolute(p) ? p : resolve(process.cwd(), p);
15286
+ return isAbsolute(p) ? p : resolve2(process.cwd(), p);
15110
15287
  }
15111
15288
  function configuredDesktopDimensions() {
15112
15289
  const width = parseInt(process.env.REPLICAS_DESKTOP_WIDTH || String(DESKTOP_VIEWER_WIDTH), 10);
@@ -15118,16 +15295,16 @@ function configuredDesktopDimensions() {
15118
15295
  function clamp(n, min, max) {
15119
15296
  return Math.min(max, Math.max(min, n));
15120
15297
  }
15121
- var sleep = (ms) => new Promise((resolve2) => setTimeout(resolve2, ms));
15298
+ var sleep2 = (ms) => new Promise((resolve3) => setTimeout(resolve3, ms));
15122
15299
 
15123
15300
  // src/commands/computer/recording.ts
15124
- import { spawn as spawn3 } from "child_process";
15125
- import { appendFileSync, existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync as readFileSync2, rmSync as rmSync2, statSync, writeFileSync as writeFileSync2 } from "fs";
15301
+ import { spawn as spawn4 } from "child_process";
15302
+ import { appendFileSync, existsSync as existsSync2, mkdirSync as mkdirSync3, readFileSync as readFileSync3, rmSync as rmSync3, statSync, writeFileSync as writeFileSync3 } from "fs";
15126
15303
  import { dirname as dirname2 } from "path";
15127
15304
 
15128
15305
  // src/commands/computer/recording/render.ts
15129
15306
  import { spawnSync as spawnSync2 } from "child_process";
15130
- import { copyFileSync, rmSync, writeFileSync } from "fs";
15307
+ import { copyFileSync, rmSync as rmSync2, writeFileSync as writeFileSync2 } from "fs";
15131
15308
 
15132
15309
  // src/commands/computer/recording/config.ts
15133
15310
  var cameraMotion = {
@@ -15532,7 +15709,7 @@ function renderRecording(rawPath, target, actions, fps, size) {
15532
15709
  }
15533
15710
  const stamp = `${process.pid}-${Date.now()}`;
15534
15711
  const cursor = cursorAssets(stamp);
15535
- writeFileSync(cursor.path, cursorSvg(cursor.size));
15712
+ writeFileSync2(cursor.path, cursorSvg(cursor.size));
15536
15713
  const spans = renderedSegmentSpans(segments);
15537
15714
  const renderedDuration = spans.length ? spans[spans.length - 1].outputEnd : duration;
15538
15715
  const renderedActions = actionsOnRenderedTimeline(actions, spans);
@@ -15555,7 +15732,7 @@ function renderRecording(rawPath, target, actions, fps, size) {
15555
15732
  const concatInputs = segments.map((_, index) => `[v${index}]`).join("");
15556
15733
  const filter = `${screenSplitFilter};${filters.join(";")};${concatInputs}concat=n=${segments.length}:v=1:a=0[screen];${cursorFilter}`;
15557
15734
  const filterPath = `/tmp/replicas-recording-filter-${stamp}.ffgraph`;
15558
- writeFileSync(filterPath, filter);
15735
+ writeFileSync2(filterPath, filter);
15559
15736
  try {
15560
15737
  const r = spawnSync2("ffmpeg", [
15561
15738
  "-y",
@@ -15590,8 +15767,8 @@ function renderRecording(rawPath, target, actions, fps, size) {
15590
15767
  fail(`recording post-processing failed: ${r.error?.message || r.stderr?.toString().trim() || `exit ${r.status}`}`);
15591
15768
  }
15592
15769
  } finally {
15593
- rmSync(filterPath, { force: true });
15594
- rmSync(cursor.path, { force: true });
15770
+ rmSync2(filterPath, { force: true });
15771
+ rmSync2(cursor.path, { force: true });
15595
15772
  }
15596
15773
  }
15597
15774
 
@@ -15613,11 +15790,11 @@ var RECORD_STATE_FILES = [
15613
15790
  RECORD_ACTIONS_FILE
15614
15791
  ];
15615
15792
  function clearRecordingState() {
15616
- for (const file of RECORD_STATE_FILES) rmSync2(file, { force: true });
15793
+ for (const file of RECORD_STATE_FILES) rmSync3(file, { force: true });
15617
15794
  }
15618
15795
  function recordingStartedAt() {
15619
15796
  if (!existsSync2(RECORD_STARTED_AT_FILE)) return null;
15620
- const startedAt = Number.parseInt(readFileSync2(RECORD_STARTED_AT_FILE, "utf8").trim(), 10);
15797
+ const startedAt = Number.parseInt(readFileSync3(RECORD_STARTED_AT_FILE, "utf8").trim(), 10);
15621
15798
  return Number.isFinite(startedAt) ? startedAt : null;
15622
15799
  }
15623
15800
  function logRecordingAction(action) {
@@ -15630,7 +15807,7 @@ function logRecordingAction(action) {
15630
15807
  function readRecordingDimensions() {
15631
15808
  if (!existsSync2(RECORD_DIMENSIONS_FILE)) return configuredDesktopDimensions();
15632
15809
  try {
15633
- const dimensions = JSON.parse(readFileSync2(RECORD_DIMENSIONS_FILE, "utf8"));
15810
+ const dimensions = JSON.parse(readFileSync3(RECORD_DIMENSIONS_FILE, "utf8"));
15634
15811
  const width = dimensions?.width;
15635
15812
  const height = dimensions?.height;
15636
15813
  if (typeof width === "number" && Number.isFinite(width) && width > 0 && typeof height === "number" && Number.isFinite(height) && height > 0) {
@@ -15648,7 +15825,7 @@ function isOptionalNumber(value) {
15648
15825
  }
15649
15826
  function readRecordingActions() {
15650
15827
  if (!existsSync2(RECORD_ACTIONS_FILE)) return [];
15651
- return readFileSync2(RECORD_ACTIONS_FILE, "utf8").split("\n").filter(Boolean).flatMap((line) => {
15828
+ return readFileSync3(RECORD_ACTIONS_FILE, "utf8").split("\n").filter(Boolean).flatMap((line) => {
15652
15829
  try {
15653
15830
  const value = JSON.parse(line);
15654
15831
  if (typeof value !== "object" || value === null) return [];
@@ -15670,7 +15847,7 @@ function readRecordingActions() {
15670
15847
  async function computerRecordStartCommand(path6, options) {
15671
15848
  ensureServicesRunning();
15672
15849
  if (existsSync2(RECORD_PID_FILE)) {
15673
- const pid = parseInt(readFileSync2(RECORD_PID_FILE, "utf8").trim(), 10);
15850
+ const pid = parseInt(readFileSync3(RECORD_PID_FILE, "utf8").trim(), 10);
15674
15851
  if (Number.isFinite(pid)) {
15675
15852
  let alive2 = false;
15676
15853
  try {
@@ -15682,13 +15859,13 @@ async function computerRecordStartCommand(path6, options) {
15682
15859
  }
15683
15860
  }
15684
15861
  const target = resolvePath(path6);
15685
- mkdirSync2(dirname2(target), { recursive: true });
15862
+ mkdirSync3(dirname2(target), { recursive: true });
15686
15863
  const fps = options.fps ? parseCoord(options.fps, "--fps") : 60;
15687
15864
  const { width, height } = configuredDesktopDimensions();
15688
- mkdirSync2(STATE_DIR, { recursive: true });
15865
+ mkdirSync3(STATE_DIR, { recursive: true });
15689
15866
  const rawTarget = `${target}.raw-${Date.now()}.mp4`;
15690
- rmSync2(RECORD_ACTIONS_FILE, { force: true });
15691
- const child = spawn3("ffmpeg", [
15867
+ rmSync3(RECORD_ACTIONS_FILE, { force: true });
15868
+ const child = spawn4("ffmpeg", [
15692
15869
  "-y",
15693
15870
  "-hide_banner",
15694
15871
  "-loglevel",
@@ -15719,12 +15896,12 @@ async function computerRecordStartCommand(path6, options) {
15719
15896
  ], { detached: true, stdio: "ignore" });
15720
15897
  child.unref();
15721
15898
  if (!child.pid) fail("failed to launch ffmpeg");
15722
- writeFileSync2(RECORD_PID_FILE, String(child.pid));
15723
- writeFileSync2(RECORD_PATH_FILE, target);
15724
- writeFileSync2(RECORD_RAW_PATH_FILE, rawTarget);
15725
- writeFileSync2(RECORD_STARTED_AT_FILE, String(Date.now()));
15726
- writeFileSync2(RECORD_FPS_FILE, String(fps));
15727
- writeFileSync2(RECORD_DIMENSIONS_FILE, JSON.stringify({ width, height }));
15899
+ writeFileSync3(RECORD_PID_FILE, String(child.pid));
15900
+ writeFileSync3(RECORD_PATH_FILE, target);
15901
+ writeFileSync3(RECORD_RAW_PATH_FILE, rawTarget);
15902
+ writeFileSync3(RECORD_STARTED_AT_FILE, String(Date.now()));
15903
+ writeFileSync3(RECORD_FPS_FILE, String(fps));
15904
+ writeFileSync3(RECORD_DIMENSIONS_FILE, JSON.stringify({ width, height }));
15728
15905
  const startedAt = Date.now();
15729
15906
  while (Date.now() - startedAt < 5e3) {
15730
15907
  try {
@@ -15736,7 +15913,7 @@ async function computerRecordStartCommand(path6, options) {
15736
15913
  } catch {
15737
15914
  break;
15738
15915
  }
15739
- await sleep(100);
15916
+ await sleep2(100);
15740
15917
  }
15741
15918
  let alive = false;
15742
15919
  try {
@@ -15746,13 +15923,13 @@ async function computerRecordStartCommand(path6, options) {
15746
15923
  }
15747
15924
  if (alive) fail("ffmpeg is running but did not produce recording output within 5 seconds; run `replicas computer record stop` to finalize or retry");
15748
15925
  clearRecordingState();
15749
- rmSync2(rawTarget, { force: true });
15926
+ rmSync3(rawTarget, { force: true });
15750
15927
  fail("ffmpeg exited before screen recording became ready");
15751
15928
  }
15752
15929
  async function computerRecordStopCommand() {
15753
15930
  if (!existsSync2(RECORD_PID_FILE) && !existsSync2(RECORD_PATH_FILE)) fail("no recording in progress");
15754
15931
  if (existsSync2(RECORD_PID_FILE)) {
15755
- const pid = parseInt(readFileSync2(RECORD_PID_FILE, "utf8").trim(), 10);
15932
+ const pid = parseInt(readFileSync3(RECORD_PID_FILE, "utf8").trim(), 10);
15756
15933
  if (!Number.isFinite(pid)) fail("invalid recording pidfile");
15757
15934
  try {
15758
15935
  process.kill(pid, "SIGINT");
@@ -15766,19 +15943,19 @@ async function computerRecordStopCommand() {
15766
15943
  alive = false;
15767
15944
  break;
15768
15945
  }
15769
- await sleep(200);
15946
+ await sleep2(200);
15770
15947
  }
15771
15948
  if (alive) fail(`ffmpeg did not finalize recording within 30 seconds (pid ${pid})`);
15772
15949
  }
15773
15950
  if (existsSync2(RECORD_PATH_FILE)) {
15774
- const target = readFileSync2(RECORD_PATH_FILE, "utf8").trim();
15775
- const rawPath = existsSync2(RECORD_RAW_PATH_FILE) ? readFileSync2(RECORD_RAW_PATH_FILE, "utf8").trim() : target;
15776
- const fps = existsSync2(RECORD_FPS_FILE) ? parseInt(readFileSync2(RECORD_FPS_FILE, "utf8").trim(), 10) : 60;
15951
+ const target = readFileSync3(RECORD_PATH_FILE, "utf8").trim();
15952
+ const rawPath = existsSync2(RECORD_RAW_PATH_FILE) ? readFileSync3(RECORD_RAW_PATH_FILE, "utf8").trim() : target;
15953
+ const fps = existsSync2(RECORD_FPS_FILE) ? parseInt(readFileSync3(RECORD_FPS_FILE, "utf8").trim(), 10) : 60;
15777
15954
  const size = readRecordingDimensions();
15778
15955
  const actions = readRecordingActions();
15779
15956
  if (rawPath !== target) {
15780
15957
  renderRecording(rawPath, target, actions, Number.isFinite(fps) ? fps : 60, size);
15781
- rmSync2(rawPath, { force: true });
15958
+ rmSync3(rawPath, { force: true });
15782
15959
  }
15783
15960
  console.log(target);
15784
15961
  }
@@ -15809,7 +15986,7 @@ async function waitForDesktopViewerUrl(timeoutMs) {
15809
15986
  while (Date.now() < deadline) {
15810
15987
  const url = await lookupDesktopViewerUrl();
15811
15988
  if (url) return url;
15812
- await new Promise((resolve2) => setTimeout(resolve2, INFO_WAIT_INTERVAL_MS));
15989
+ await new Promise((resolve3) => setTimeout(resolve3, INFO_WAIT_INTERVAL_MS));
15813
15990
  }
15814
15991
  return await lookupDesktopViewerUrl();
15815
15992
  }
@@ -15821,7 +15998,7 @@ async function computerInfoCommand() {
15821
15998
  );
15822
15999
  }
15823
16000
  console.log(viewerUrl);
15824
- console.error(chalk21.dim(`Share this URL with the user to let them watch the desktop live.`));
16001
+ console.error(chalk22.dim(`Share this URL with the user to let them watch the desktop live.`));
15825
16002
  }
15826
16003
  async function computerStatusCommand() {
15827
16004
  ensureServicesRunning();
@@ -15831,18 +16008,18 @@ async function computerStatusCommand() {
15831
16008
  const r = spawnSync3("pgrep", ["-af", p], { stdio: "pipe" });
15832
16009
  const running = r.status === 0 && !!r.stdout?.toString().trim();
15833
16010
  const suffix = p === "x11vnc" && bridge ? bridgeStatus(bridge.x11vnc, true) : p === "websockify" && bridge ? bridgeStatus(bridge.websockify, false, true) : "";
15834
- console.log(` ${running ? chalk21.green("\u25CF") : chalk21.red("\u25CB")} ${p}${suffix}`);
16011
+ console.log(` ${running ? chalk22.green("\u25CF") : chalk22.red("\u25CB")} ${p}${suffix}`);
15835
16012
  }
15836
16013
  const viewerUrl = await lookupDesktopViewerUrl();
15837
16014
  if (viewerUrl) {
15838
- console.log(` ${chalk21.cyan("preview")}: ${viewerUrl}`);
16015
+ console.log(` ${chalk22.cyan("preview")}: ${viewerUrl}`);
15839
16016
  } else {
15840
- console.log(` ${chalk21.dim("preview: not yet registered (engine registers it at startup)")}`);
16017
+ console.log(` ${chalk22.dim("preview: not yet registered (engine registers it at startup)")}`);
15841
16018
  }
15842
16019
  }
15843
16020
  var PNG_SIGNATURE = Buffer.from([137, 80, 78, 71, 13, 10, 26, 10]);
15844
16021
  function readPngDimensions(filePath) {
15845
- const fd = openSync(filePath, "r");
16022
+ const fd = openSync2(filePath, "r");
15846
16023
  try {
15847
16024
  const buf = Buffer.alloc(24);
15848
16025
  const bytesRead = readSync(fd, buf, 0, 24, 0);
@@ -15851,7 +16028,7 @@ function readPngDimensions(filePath) {
15851
16028
  }
15852
16029
  return { width: buf.readUInt32BE(16), height: buf.readUInt32BE(20) };
15853
16030
  } finally {
15854
- closeSync(fd);
16031
+ closeSync2(fd);
15855
16032
  }
15856
16033
  }
15857
16034
  function brandSvgPath() {
@@ -15865,7 +16042,7 @@ function loadBrandSvg(canvasW, canvasH) {
15865
16042
  `Brand wallpaper SVG missing at ${path6}. The workspace image is out of date \u2014 \`desktop/brand-wallpaper.svg\` must be installed at $REPLICAS_DESKTOP_TEMPLATES.`
15866
16043
  );
15867
16044
  }
15868
- return readFileSync3(path6, "utf8").replace(/(<svg[^>]*\s)width="\d+"/, `$1width="${canvasW}"`).replace(/(<svg[^>]*\s)height="\d+"/, `$1height="${canvasH}"`);
16045
+ return readFileSync4(path6, "utf8").replace(/(<svg[^>]*\s)width="\d+"/, `$1width="${canvasW}"`).replace(/(<svg[^>]*\s)height="\d+"/, `$1height="${canvasH}"`);
15869
16046
  }
15870
16047
  var BRAND_PAD_FRACTION = 0.06;
15871
16048
  var SCREENSHOT_CORNER_FRACTION = 0.022;
@@ -15900,7 +16077,7 @@ ${labels.join("\n")}
15900
16077
  </svg>`;
15901
16078
  }
15902
16079
  function overlayGrid(rawPath, target, width, height, gridSize, gridPath) {
15903
- writeFileSync3(gridPath, buildGridSvg(width, height, gridSize));
16080
+ writeFileSync4(gridPath, buildGridSvg(width, height, gridSize));
15904
16081
  const r = spawnSync3(
15905
16082
  "ffmpeg",
15906
16083
  [
@@ -15928,7 +16105,7 @@ function overlayGrid(rawPath, target, width, height, gridSize, gridPath) {
15928
16105
  }
15929
16106
  async function computerScreenshotCommand(path6, options = {}) {
15930
16107
  const target = resolvePath(path6);
15931
- mkdirSync3(dirname3(target), { recursive: true });
16108
+ mkdirSync4(dirname3(target), { recursive: true });
15932
16109
  const stamp = `${process.pid}-${Date.now()}`;
15933
16110
  const rawPath = `/tmp/replicas-screenshot-${stamp}.raw.png`;
15934
16111
  const svgPath = `/tmp/replicas-screenshot-${stamp}.brand.svg`;
@@ -15960,12 +16137,12 @@ async function computerScreenshotCommand(path6, options = {}) {
15960
16137
  const shadowMargin = shadowSigma * 3;
15961
16138
  const shadowW = width + shadowMargin * 2;
15962
16139
  const shadowH = height + shadowMargin * 2;
15963
- writeFileSync3(svgPath, loadBrandSvg(canvasW, canvasH));
15964
- writeFileSync3(
16140
+ writeFileSync4(svgPath, loadBrandSvg(canvasW, canvasH));
16141
+ writeFileSync4(
15965
16142
  maskPath,
15966
16143
  SCREENSHOT_MASK_TEMPLATE.replace(/__W__/g, String(width)).replace(/__H__/g, String(height)).replace(/__R__/g, String(cornerR))
15967
16144
  );
15968
- writeFileSync3(
16145
+ writeFileSync4(
15969
16146
  shadowPath,
15970
16147
  SHADOW_MASK_TEMPLATE.replace(/__SW__/g, String(shadowW)).replace(/__SH__/g, String(shadowH)).replace(/__M__/g, String(shadowMargin)).replace(/__W__/g, String(width)).replace(/__H__/g, String(height)).replace(/__R__/g, String(cornerR))
15971
16148
  );
@@ -15998,16 +16175,16 @@ async function computerScreenshotCommand(path6, options = {}) {
15998
16175
  fail(`ffmpeg branding failed: ${r.stderr?.toString().trim() || `exit ${r.status}`}`);
15999
16176
  }
16000
16177
  } finally {
16001
- rmSync3(rawPath, { force: true });
16002
- rmSync3(svgPath, { force: true });
16003
- rmSync3(maskPath, { force: true });
16004
- rmSync3(shadowPath, { force: true });
16005
- rmSync3(gridPath, { force: true });
16178
+ rmSync4(rawPath, { force: true });
16179
+ rmSync4(svgPath, { force: true });
16180
+ rmSync4(maskPath, { force: true });
16181
+ rmSync4(shadowPath, { force: true });
16182
+ rmSync4(gridPath, { force: true });
16006
16183
  }
16007
16184
  console.log(target);
16008
16185
  }
16009
16186
  function hashFile(path6) {
16010
- return createHash2("sha256").update(readFileSync3(path6)).digest("hex");
16187
+ return createHash2("sha256").update(readFileSync4(path6)).digest("hex");
16011
16188
  }
16012
16189
  async function captureStableRawScreenshot(target, options) {
16013
16190
  const start = Date.now();
@@ -16038,11 +16215,11 @@ async function captureStableRawScreenshot(target, options) {
16038
16215
  if (frames > 1 && now - lastChangeAt >= options.stableMs) {
16039
16216
  return { width, height, stable: true, elapsedMs: now - start, frames, changes };
16040
16217
  }
16041
- await sleep(options.pollMs);
16218
+ await sleep2(options.pollMs);
16042
16219
  }
16043
16220
  return { width, height, stable: false, elapsedMs: Date.now() - start, frames, changes };
16044
16221
  } finally {
16045
- rmSync3(framePath, { force: true });
16222
+ rmSync4(framePath, { force: true });
16046
16223
  }
16047
16224
  }
16048
16225
  function getActiveWindowTitle() {
@@ -16058,7 +16235,7 @@ function recordingMousePosition() {
16058
16235
  }
16059
16236
  async function computerObserveCommand(path6, options = {}) {
16060
16237
  const target = resolvePath(path6);
16061
- mkdirSync3(dirname3(target), { recursive: true });
16238
+ mkdirSync4(dirname3(target), { recursive: true });
16062
16239
  const timeoutMs = options.timeout ? parseCoord(options.timeout, "--timeout") : 3e3;
16063
16240
  const stableMs = options.stableMs ? parseCoord(options.stableMs, "--stable-ms") : 600;
16064
16241
  const pollMs = options.pollMs ? parseCoord(options.pollMs, "--poll-ms") : 200;
@@ -16092,8 +16269,8 @@ async function computerObserveCommand(path6, options = {}) {
16092
16269
  gridSize
16093
16270
  }, null, 2));
16094
16271
  } finally {
16095
- rmSync3(rawPath, { force: true });
16096
- rmSync3(gridPath, { force: true });
16272
+ rmSync4(rawPath, { force: true });
16273
+ rmSync4(gridPath, { force: true });
16097
16274
  }
16098
16275
  }
16099
16276
  async function fetchChromeJson(path6) {
@@ -16154,7 +16331,7 @@ async function sendChromeSessionCommand(session, method, params) {
16154
16331
  return chromeResult(await session.send({ method, params }), method);
16155
16332
  }
16156
16333
  async function withChromeSession(webSocketDebuggerUrl, callback) {
16157
- return await new Promise((resolve2, reject) => {
16334
+ return await new Promise((resolve3, reject) => {
16158
16335
  const ws = new WebSocket(webSocketDebuggerUrl);
16159
16336
  const pending = /* @__PURE__ */ new Map();
16160
16337
  let nextId = 1;
@@ -16176,7 +16353,7 @@ async function withChromeSession(webSocketDebuggerUrl, callback) {
16176
16353
  for (const request of pending.values()) clearTimeout(request.timeout);
16177
16354
  pending.clear();
16178
16355
  ws.close();
16179
- resolve2(value);
16356
+ resolve3(value);
16180
16357
  };
16181
16358
  const session = {
16182
16359
  send: ({ method, params }) => new Promise((resolveCommand, rejectCommand) => {
@@ -16293,7 +16470,7 @@ function browserStateProperties(node) {
16293
16470
  function readBrowserStateCache(path6) {
16294
16471
  let value;
16295
16472
  try {
16296
- value = JSON.parse(readFileSync3(path6, "utf8"));
16473
+ value = JSON.parse(readFileSync4(path6, "utf8"));
16297
16474
  } catch {
16298
16475
  return null;
16299
16476
  }
@@ -16773,7 +16950,7 @@ async function waitForBrowserStability(page, options) {
16773
16950
  }
16774
16951
  } catch {
16775
16952
  }
16776
- await sleep(options.pollMs);
16953
+ await sleep2(options.pollMs);
16777
16954
  }
16778
16955
  return { stable: false, elapsedMs: Date.now() - startedAt, samples, changes, state };
16779
16956
  }
@@ -16819,7 +16996,7 @@ async function computerBrowserStateCommand(path6, options = {}) {
16819
16996
  const page = await selectChromePage(options);
16820
16997
  const stability = await waitForBrowserStability(page, { timeoutMs, stableMs, pollMs });
16821
16998
  const target = resolvePath(path6);
16822
- mkdirSync3(dirname3(target), { recursive: true });
16999
+ mkdirSync4(dirname3(target), { recursive: true });
16823
17000
  const [{ snapshot, entries }, screenshotResult] = await Promise.all([
16824
17001
  captureBrowserSnapshot(page, { textLimit, elementLimit }),
16825
17002
  sendChromeCommand(page.webSocketDebuggerUrl, "Page.captureScreenshot", {
@@ -16830,7 +17007,7 @@ async function computerBrowserStateCommand(path6, options = {}) {
16830
17007
  ]);
16831
17008
  const data = screenshotResult.data;
16832
17009
  if (typeof data !== "string") fail("Chrome did not return screenshot data");
16833
- writeFileSync3(target, Buffer.from(data, "base64"));
17010
+ writeFileSync4(target, Buffer.from(data, "base64"));
16834
17011
  const screenshot = readPngDimensions(target);
16835
17012
  const targetId = page.id ?? "unknown";
16836
17013
  const cachePath = browserStateCachePath(targetId);
@@ -16846,8 +17023,8 @@ async function computerBrowserStateCommand(path6, options = {}) {
16846
17023
  changes = { added: diff.added, changed: diff.changed, removed: diff.removed };
16847
17024
  }
16848
17025
  }
16849
- mkdirSync3(STATE_DIR, { recursive: true });
16850
- writeFileSync3(cachePath, JSON.stringify({ url: snapshot.url, documentId: snapshot.documentId, entries }));
17026
+ mkdirSync4(STATE_DIR, { recursive: true });
17027
+ writeFileSync4(cachePath, JSON.stringify({ url: snapshot.url, documentId: snapshot.documentId, entries }));
16851
17028
  const stableState = isRecord(stability.state) ? stability.state : {};
16852
17029
  const state = {
16853
17030
  title: snapshot.title,
@@ -17408,7 +17585,7 @@ async function computerBrowserWaitCommand(query, options = {}) {
17408
17585
  console.log(JSON.stringify({ ok: true, elapsedMs: Date.now() - start, attempts, result: lastResult }, null, 2));
17409
17586
  return;
17410
17587
  }
17411
- await sleep(pollMs);
17588
+ await sleep2(pollMs);
17412
17589
  }
17413
17590
  console.log(JSON.stringify({ ok: false, elapsedMs: Date.now() - start, attempts, result: lastResult }, null, 2));
17414
17591
  process.exitCode = 1;
@@ -17634,7 +17811,7 @@ async function computerBrowserBatchCommand(actionsJson, options = {}) {
17634
17811
  attempts++;
17635
17812
  result = await evaluateChromeSession(session, expression);
17636
17813
  if (isRecord(result) && result.matched === true) break;
17637
- await sleep(action.pollMs);
17814
+ await sleep2(action.pollMs);
17638
17815
  }
17639
17816
  if (!isRecord(result) || result.matched !== true) fail(`Batch wait ${index} timed out after ${Date.now() - actionStartedAt}ms`);
17640
17817
  completed.push({ index, action: action.action, attempts, elapsedMs: Date.now() - actionStartedAt });
@@ -17780,7 +17957,7 @@ async function computerLaunchCommand(app, args) {
17780
17957
  } catch {
17781
17958
  }
17782
17959
  }
17783
- const child = spawn4(bin, fullArgs, {
17960
+ const child = spawn5(bin, fullArgs, {
17784
17961
  env: withDisplay(),
17785
17962
  detached: true,
17786
17963
  stdio: "ignore"
@@ -17812,7 +17989,7 @@ async function computerLaunchCommand(app, args) {
17812
17989
  } catch {
17813
17990
  fail(`Chrome exited before its desktop control channel became ready.`);
17814
17991
  }
17815
- await sleep(100);
17992
+ await sleep2(100);
17816
17993
  }
17817
17994
  if (!readyPage?.webSocketDebuggerUrl) fail(`Chrome launched but its requested page was not controllable after 15 seconds.`);
17818
17995
  await sendChromeCommand(readyPage.webSocketDebuggerUrl, "Page.bringToFront", {});
@@ -17823,7 +18000,7 @@ async function computerLaunchCommand(app, args) {
17823
18000
  }
17824
18001
 
17825
18002
  // src/commands/interactive.ts
17826
- import chalk22 from "chalk";
18003
+ import chalk23 from "chalk";
17827
18004
 
17828
18005
  // src/interactive/index.tsx
17829
18006
  import { createCliRenderer } from "@opentui/core";
@@ -17897,7 +18074,7 @@ function useReconnectingSseStream(options) {
17897
18074
  while (!cancelled) {
17898
18075
  const stop = await connect();
17899
18076
  if (cancelled || stop) break;
17900
- await new Promise((resolve2) => setTimeout(resolve2, reconnectDelayMs));
18077
+ await new Promise((resolve3) => setTimeout(resolve3, reconnectDelayMs));
17901
18078
  }
17902
18079
  };
17903
18080
  run().catch(() => setConnected(false));
@@ -21004,13 +21181,13 @@ async function interactiveCommand() {
21004
21181
  'No organization selected. Please run "replicas org switch" to select an organization.'
21005
21182
  );
21006
21183
  }
21007
- console.log(chalk22.gray("Starting interactive mode..."));
21184
+ console.log(chalk23.gray("Starting interactive mode..."));
21008
21185
  await launchInteractive();
21009
21186
  }
21010
21187
 
21011
21188
  // src/commands/environment.ts
21012
21189
  import fs5 from "fs";
21013
- import chalk23 from "chalk";
21190
+ import chalk24 from "chalk";
21014
21191
  import prompts5 from "prompts";
21015
21192
  var UUID_RE = /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/;
21016
21193
  function maskValue(value) {
@@ -21023,38 +21200,38 @@ async function resolveEnvironmentId(input) {
21023
21200
  const response = await orgAuthenticatedFetch("/v1/environments");
21024
21201
  const resolved = resolveByNameOrId(input, response.environments);
21025
21202
  if (!resolved) {
21026
- console.log(chalk23.red(`Environment not found: ${input}`));
21203
+ console.log(chalk24.red(`Environment not found: ${input}`));
21027
21204
  const available = response.environments.map((e) => e.name).join(", ");
21028
- console.log(chalk23.gray(`Available: ${available || "(none)"}`));
21205
+ console.log(chalk24.gray(`Available: ${available || "(none)"}`));
21029
21206
  process.exit(1);
21030
21207
  }
21031
21208
  return resolved.id;
21032
21209
  }
21033
21210
  function printEnvironment(env) {
21034
- console.log(chalk23.white(` ${env.name}${env.is_global ? chalk23.gray(" (global)") : ""}`));
21035
- console.log(chalk23.gray(` ID: ${env.id}`));
21211
+ console.log(chalk24.white(` ${env.name}${env.is_global ? chalk24.gray(" (global)") : ""}`));
21212
+ console.log(chalk24.gray(` ID: ${env.id}`));
21036
21213
  if (env.description) {
21037
- console.log(chalk23.gray(` Description: ${env.description}`));
21214
+ console.log(chalk24.gray(` Description: ${env.description}`));
21038
21215
  }
21039
21216
  if (env.repository_id) {
21040
- console.log(chalk23.gray(` Repository: ${env.repository_id}`));
21217
+ console.log(chalk24.gray(` Repository: ${env.repository_id}`));
21041
21218
  } else if (env.repository_set_id) {
21042
- console.log(chalk23.gray(` Repository Set: ${env.repository_set_id}`));
21219
+ console.log(chalk24.gray(` Repository Set: ${env.repository_set_id}`));
21043
21220
  }
21044
21221
  if (env.variable_count !== void 0) {
21045
- console.log(chalk23.gray(` Variables: ${env.variable_count}, Files: ${env.file_count ?? 0}, Skills: ${env.skill_count ?? 0}, MCPs: ${env.mcp_count ?? 0}`));
21222
+ console.log(chalk24.gray(` Variables: ${env.variable_count}, Files: ${env.file_count ?? 0}, Skills: ${env.skill_count ?? 0}, MCPs: ${env.mcp_count ?? 0}`));
21046
21223
  }
21047
- console.log(chalk23.gray(` Updated: ${formatDate2(env.updated_at)}`));
21224
+ console.log(chalk24.gray(` Updated: ${formatDate2(env.updated_at)}`));
21048
21225
  console.log();
21049
21226
  }
21050
21227
  async function environmentListCommand() {
21051
21228
  ensureOrgApiAuthenticated();
21052
21229
  const response = await orgAuthenticatedFetch("/v1/environments");
21053
21230
  if (response.environments.length === 0) {
21054
- console.log(chalk23.yellow("\nNo environments found.\n"));
21231
+ console.log(chalk24.yellow("\nNo environments found.\n"));
21055
21232
  return;
21056
21233
  }
21057
- console.log(chalk23.green(`
21234
+ console.log(chalk24.green(`
21058
21235
  Environments (${response.environments.length}):
21059
21236
  `));
21060
21237
  for (const env of response.environments) {
@@ -21065,7 +21242,7 @@ async function environmentGetCommand(idOrName) {
21065
21242
  ensureOrgApiAuthenticated();
21066
21243
  const id = await resolveEnvironmentId(idOrName);
21067
21244
  const response = await orgAuthenticatedFetch(`/v1/environments/${id}`);
21068
- console.log(chalk23.green(`
21245
+ console.log(chalk24.green(`
21069
21246
  Environment: ${response.environment.name}
21070
21247
  `));
21071
21248
  printEnvironment(response.environment);
@@ -21081,7 +21258,7 @@ async function environmentCreateCommand(name, options) {
21081
21258
  validate: (v) => v.trim() ? true : "Name is required"
21082
21259
  });
21083
21260
  if (!r.name) {
21084
- console.log(chalk23.yellow("\nCancelled."));
21261
+ console.log(chalk24.yellow("\nCancelled."));
21085
21262
  return;
21086
21263
  }
21087
21264
  envName = r.name;
@@ -21094,8 +21271,8 @@ async function environmentCreateCommand(name, options) {
21094
21271
  const repos2 = await orgAuthenticatedFetch("/v1/repositories");
21095
21272
  const repo = repos2.repositories.find((r) => r.name === options.repository);
21096
21273
  if (!repo) {
21097
- console.log(chalk23.red(`Repository not found: ${options.repository}`));
21098
- console.log(chalk23.gray(`Available: ${repos2.repositories.map((r) => r.name).join(", ")}`));
21274
+ console.log(chalk24.red(`Repository not found: ${options.repository}`));
21275
+ console.log(chalk24.gray(`Available: ${repos2.repositories.map((r) => r.name).join(", ")}`));
21099
21276
  process.exit(1);
21100
21277
  }
21101
21278
  repositoryId = repo.id;
@@ -21125,9 +21302,9 @@ async function environmentCreateCommand(name, options) {
21125
21302
  method: "POST",
21126
21303
  body
21127
21304
  });
21128
- console.log(chalk23.green(`
21305
+ console.log(chalk24.green(`
21129
21306
  Created environment: ${response.environment.name}`));
21130
- console.log(chalk23.gray(` ID: ${response.environment.id}
21307
+ console.log(chalk24.gray(` ID: ${response.environment.id}
21131
21308
  `));
21132
21309
  }
21133
21310
  async function environmentEditCommand(idOrName, options) {
@@ -21146,21 +21323,21 @@ async function environmentEditCommand(idOrName, options) {
21146
21323
  const repos2 = await orgAuthenticatedFetch("/v1/repositories");
21147
21324
  const repo = repos2.repositories.find((r) => r.name === options.repository);
21148
21325
  if (!repo) {
21149
- console.log(chalk23.red(`Repository not found: ${options.repository}`));
21326
+ console.log(chalk24.red(`Repository not found: ${options.repository}`));
21150
21327
  process.exit(1);
21151
21328
  }
21152
21329
  body.repository_id = repo.id;
21153
21330
  }
21154
21331
  }
21155
21332
  if (Object.keys(body).length === 0) {
21156
- console.log(chalk23.yellow("\nNo changes specified. Pass --name, --description, --repository, or --system-prompt."));
21333
+ console.log(chalk24.yellow("\nNo changes specified. Pass --name, --description, --repository, or --system-prompt."));
21157
21334
  return;
21158
21335
  }
21159
21336
  const response = await orgAuthenticatedFetch(`/v1/environments/${id}`, {
21160
21337
  method: "PATCH",
21161
21338
  body
21162
21339
  });
21163
- console.log(chalk23.green(`
21340
+ console.log(chalk24.green(`
21164
21341
  Updated environment: ${response.environment.name}
21165
21342
  `));
21166
21343
  }
@@ -21175,20 +21352,20 @@ async function environmentDeleteCommand(idOrName, options) {
21175
21352
  initial: false
21176
21353
  });
21177
21354
  if (!r.confirm) {
21178
- console.log(chalk23.yellow("\nCancelled."));
21355
+ console.log(chalk24.yellow("\nCancelled."));
21179
21356
  return;
21180
21357
  }
21181
21358
  }
21182
21359
  await orgAuthenticatedFetch(`/v1/environments/${id}`, { method: "DELETE" });
21183
- console.log(chalk23.green(`
21360
+ console.log(chalk24.green(`
21184
21361
  Deleted environment ${idOrName}.
21185
21362
  `));
21186
21363
  }
21187
21364
  function printVariable(v, reveal) {
21188
- console.log(chalk23.white(` ${v.key}`));
21189
- console.log(chalk23.gray(` ID: ${v.id}`));
21190
- console.log(chalk23.gray(` Value: ${reveal ? v.value : maskValue(v.value)}`));
21191
- console.log(chalk23.gray(` Updated: ${formatDate2(v.updated_at)}`));
21365
+ console.log(chalk24.white(` ${v.key}`));
21366
+ console.log(chalk24.gray(` ID: ${v.id}`));
21367
+ console.log(chalk24.gray(` Value: ${reveal ? v.value : maskValue(v.value)}`));
21368
+ console.log(chalk24.gray(` Updated: ${formatDate2(v.updated_at)}`));
21192
21369
  console.log();
21193
21370
  }
21194
21371
  async function envVarsListCommand(envIdOrName, options) {
@@ -21198,14 +21375,14 @@ async function envVarsListCommand(envIdOrName, options) {
21198
21375
  `/v1/environments/${id}/variables`
21199
21376
  );
21200
21377
  if (response.environment_variables.length === 0) {
21201
- console.log(chalk23.yellow("\nNo variables.\n"));
21378
+ console.log(chalk24.yellow("\nNo variables.\n"));
21202
21379
  return;
21203
21380
  }
21204
- console.log(chalk23.green(`
21381
+ console.log(chalk24.green(`
21205
21382
  Variables (${response.environment_variables.length}):
21206
21383
  `));
21207
21384
  if (!options.reveal) {
21208
- console.log(chalk23.gray(" Values are masked. Pass --reveal to show full values.\n"));
21385
+ console.log(chalk24.gray(" Values are masked. Pass --reveal to show full values.\n"));
21209
21386
  }
21210
21387
  for (const v of response.environment_variables) printVariable(v, !!options.reveal);
21211
21388
  }
@@ -21222,7 +21399,7 @@ async function envVarsSetCommand(envIdOrName, key, value) {
21222
21399
  `/v1/environments/${id}/variables/${match.id}`,
21223
21400
  { method: "PATCH", body: body2 }
21224
21401
  );
21225
- console.log(chalk23.green(`
21402
+ console.log(chalk24.green(`
21226
21403
  Updated variable ${response2.environment_variable.key}.
21227
21404
  `));
21228
21405
  return;
@@ -21236,7 +21413,7 @@ Updated variable ${response2.environment_variable.key}.
21236
21413
  `/v1/environments/${id}/variables`,
21237
21414
  { method: "POST", body }
21238
21415
  );
21239
- console.log(chalk23.green(`
21416
+ console.log(chalk24.green(`
21240
21417
  Created variable ${response.environment_variable.key}.
21241
21418
  `));
21242
21419
  }
@@ -21250,7 +21427,7 @@ async function envVarsDeleteCommand(envIdOrName, keyOrId, options) {
21250
21427
  );
21251
21428
  const match = existing.environment_variables.find((v) => v.key === keyOrId);
21252
21429
  if (!match) {
21253
- console.log(chalk23.red(`Variable not found: ${keyOrId}`));
21430
+ console.log(chalk24.red(`Variable not found: ${keyOrId}`));
21254
21431
  process.exit(1);
21255
21432
  }
21256
21433
  variableId = match.id;
@@ -21263,23 +21440,23 @@ async function envVarsDeleteCommand(envIdOrName, keyOrId, options) {
21263
21440
  initial: false
21264
21441
  });
21265
21442
  if (!r.confirm) {
21266
- console.log(chalk23.yellow("\nCancelled."));
21443
+ console.log(chalk24.yellow("\nCancelled."));
21267
21444
  return;
21268
21445
  }
21269
21446
  }
21270
21447
  await orgAuthenticatedFetch(`/v1/environments/${id}/variables/${variableId}`, {
21271
21448
  method: "DELETE"
21272
21449
  });
21273
- console.log(chalk23.green(`
21450
+ console.log(chalk24.green(`
21274
21451
  Deleted variable ${keyOrId}.
21275
21452
  `));
21276
21453
  }
21277
21454
  function printFile(f) {
21278
- console.log(chalk23.white(` ${f.path}`));
21279
- console.log(chalk23.gray(` ID: ${f.id}`));
21280
- console.log(chalk23.gray(` Name: ${f.name}`));
21281
- console.log(chalk23.gray(` Size: ${f.content.length} bytes`));
21282
- console.log(chalk23.gray(` Updated: ${formatDate2(f.updated_at)}`));
21455
+ console.log(chalk24.white(` ${f.path}`));
21456
+ console.log(chalk24.gray(` ID: ${f.id}`));
21457
+ console.log(chalk24.gray(` Name: ${f.name}`));
21458
+ console.log(chalk24.gray(` Size: ${f.content.length} bytes`));
21459
+ console.log(chalk24.gray(` Updated: ${formatDate2(f.updated_at)}`));
21283
21460
  console.log();
21284
21461
  }
21285
21462
  async function envFilesListCommand(envIdOrName) {
@@ -21289,10 +21466,10 @@ async function envFilesListCommand(envIdOrName) {
21289
21466
  `/v1/environments/${id}/files`
21290
21467
  );
21291
21468
  if (response.environment_files.length === 0) {
21292
- console.log(chalk23.yellow("\nNo files.\n"));
21469
+ console.log(chalk24.yellow("\nNo files.\n"));
21293
21470
  return;
21294
21471
  }
21295
- console.log(chalk23.green(`
21472
+ console.log(chalk24.green(`
21296
21473
  Files (${response.environment_files.length}):
21297
21474
  `));
21298
21475
  for (const f of response.environment_files) printFile(f);
@@ -21323,7 +21500,7 @@ async function envFilesSetCommand(envIdOrName, destinationPath, options) {
21323
21500
  `/v1/environments/${id}/files/${match.id}`,
21324
21501
  { method: "PATCH", body: body2 }
21325
21502
  );
21326
- console.log(chalk23.green(`
21503
+ console.log(chalk24.green(`
21327
21504
  Updated file ${response2.environment_file.path}.
21328
21505
  `));
21329
21506
  return;
@@ -21338,7 +21515,7 @@ Updated file ${response2.environment_file.path}.
21338
21515
  `/v1/environments/${id}/files`,
21339
21516
  { method: "POST", body }
21340
21517
  );
21341
- console.log(chalk23.green(`
21518
+ console.log(chalk24.green(`
21342
21519
  Created file ${response.environment_file.path}.
21343
21520
  `));
21344
21521
  }
@@ -21352,7 +21529,7 @@ async function envFilesDeleteCommand(envIdOrName, pathOrId, options) {
21352
21529
  );
21353
21530
  const match = existing.environment_files.find((f) => f.path === pathOrId);
21354
21531
  if (!match) {
21355
- console.log(chalk23.red(`File not found: ${pathOrId}`));
21532
+ console.log(chalk24.red(`File not found: ${pathOrId}`));
21356
21533
  process.exit(1);
21357
21534
  }
21358
21535
  fileId = match.id;
@@ -21365,14 +21542,14 @@ async function envFilesDeleteCommand(envIdOrName, pathOrId, options) {
21365
21542
  initial: false
21366
21543
  });
21367
21544
  if (!r.confirm) {
21368
- console.log(chalk23.yellow("\nCancelled."));
21545
+ console.log(chalk24.yellow("\nCancelled."));
21369
21546
  return;
21370
21547
  }
21371
21548
  }
21372
21549
  await orgAuthenticatedFetch(`/v1/environments/${id}/files/${fileId}`, {
21373
21550
  method: "DELETE"
21374
21551
  });
21375
- console.log(chalk23.green(`
21552
+ console.log(chalk24.green(`
21376
21553
  Deleted file ${pathOrId}.
21377
21554
  `));
21378
21555
  }
@@ -21383,15 +21560,15 @@ async function envStartHookGetCommand(envIdOrName) {
21383
21560
  `/v1/environments/${id}/start-hooks`
21384
21561
  );
21385
21562
  if (!response.start_hook) {
21386
- console.log(chalk23.yellow("\nNo start hook configured.\n"));
21563
+ console.log(chalk24.yellow("\nNo start hook configured.\n"));
21387
21564
  return;
21388
21565
  }
21389
21566
  const hook = response.start_hook;
21390
- console.log(chalk23.green(`
21567
+ console.log(chalk24.green(`
21391
21568
  Start hook (v${hook.version}, ${hook.is_active ? "active" : "inactive"}):
21392
21569
  `));
21393
- console.log(chalk23.gray(` ID: ${hook.id}`));
21394
- console.log(chalk23.gray(` Created: ${formatDate2(hook.created_at)}
21570
+ console.log(chalk24.gray(` ID: ${hook.id}`));
21571
+ console.log(chalk24.gray(` Created: ${formatDate2(hook.created_at)}
21395
21572
  `));
21396
21573
  console.log(hook.content);
21397
21574
  console.log();
@@ -21406,10 +21583,10 @@ async function envStartHookSaveCommand(envIdOrName, options) {
21406
21583
  { method: "POST", body }
21407
21584
  );
21408
21585
  if (!response.start_hook) {
21409
- console.log(chalk23.green("\nCleared start hook.\n"));
21586
+ console.log(chalk24.green("\nCleared start hook.\n"));
21410
21587
  return;
21411
21588
  }
21412
- console.log(chalk23.green(`
21589
+ console.log(chalk24.green(`
21413
21590
  Saved start hook v${response.start_hook.version}.
21414
21591
  `));
21415
21592
  }
@@ -21426,7 +21603,7 @@ async function envStartHookTestCommand(envIdOrName, options) {
21426
21603
  body: { content },
21427
21604
  onEvent: (event) => {
21428
21605
  if (event.type === "progress" && event.message) {
21429
- console.log(chalk23.gray(event.message));
21606
+ console.log(chalk24.gray(event.message));
21430
21607
  } else if (event.type === "output" && event.output) {
21431
21608
  process.stdout.write(event.output);
21432
21609
  } else if (event.type === "complete") {
@@ -21439,21 +21616,21 @@ async function envStartHookTestCommand(envIdOrName, options) {
21439
21616
  }
21440
21617
  );
21441
21618
  if (errorMessage) {
21442
- console.log(chalk23.red(`
21619
+ console.log(chalk24.red(`
21443
21620
  ${errorMessage}
21444
21621
  `));
21445
21622
  process.exit(1);
21446
21623
  }
21447
21624
  if (timedOut) {
21448
- console.log(chalk23.yellow("\nStart hook timed out.\n"));
21625
+ console.log(chalk24.yellow("\nStart hook timed out.\n"));
21449
21626
  process.exit(1);
21450
21627
  }
21451
21628
  if (exitCode === 0) {
21452
- console.log(chalk23.green(`
21629
+ console.log(chalk24.green(`
21453
21630
  Start hook passed (exit code ${exitCode}).
21454
21631
  `));
21455
21632
  } else {
21456
- console.log(chalk23.red(`
21633
+ console.log(chalk24.red(`
21457
21634
  Start hook failed (exit code ${exitCode ?? "unknown"}).
21458
21635
  `));
21459
21636
  process.exit(1);
@@ -21466,24 +21643,24 @@ async function envStartHookRepositoryHooksCommand(envIdOrName) {
21466
21643
  `/v1/environments/${id}/start-hooks/repository-hooks`
21467
21644
  );
21468
21645
  if (response.repositories.length === 0) {
21469
- console.log(chalk23.yellow("\nNo repositories bound to this environment.\n"));
21646
+ console.log(chalk24.yellow("\nNo repositories bound to this environment.\n"));
21470
21647
  return;
21471
21648
  }
21472
- console.log(chalk23.green(`
21649
+ console.log(chalk24.green(`
21473
21650
  Repository start hooks (${response.repositories.length}):
21474
21651
  `));
21475
21652
  for (const repo of response.repositories) {
21476
- console.log(chalk23.white(` ${repo.repository_name} @${repo.default_branch}`));
21653
+ console.log(chalk24.white(` ${repo.repository_name} @${repo.default_branch}`));
21477
21654
  if (repo.error) {
21478
- console.log(chalk23.red(` Error: ${repo.error}`));
21655
+ console.log(chalk24.red(` Error: ${repo.error}`));
21479
21656
  } else if (repo.start_hook) {
21480
- console.log(chalk23.gray(` Source: ${repo.filename ?? "(unknown)"}`));
21481
- console.log(chalk23.gray(` Commands (${repo.start_hook.commands.length}):`));
21657
+ console.log(chalk24.gray(` Source: ${repo.filename ?? "(unknown)"}`));
21658
+ console.log(chalk24.gray(` Commands (${repo.start_hook.commands.length}):`));
21482
21659
  for (const cmd of repo.start_hook.commands) {
21483
- console.log(chalk23.gray(` ${cmd}`));
21660
+ console.log(chalk24.gray(` ${cmd}`));
21484
21661
  }
21485
21662
  } else {
21486
- console.log(chalk23.gray(` No startHook defined.`));
21663
+ console.log(chalk24.gray(` No startHook defined.`));
21487
21664
  }
21488
21665
  console.log();
21489
21666
  }
@@ -21505,7 +21682,7 @@ function registerSlackCommands(parent) {
21505
21682
  await slackThreadAttachCommand(options);
21506
21683
  } catch (error) {
21507
21684
  if (error instanceof Error) {
21508
- console.error(chalk24.red(`
21685
+ console.error(chalk25.red(`
21509
21686
  \u2717 ${error.message}
21510
21687
  `));
21511
21688
  }
@@ -21517,7 +21694,7 @@ function registerSlackCommands(parent) {
21517
21694
  await slackThreadSwitchCommand(workspace, options);
21518
21695
  } catch (error) {
21519
21696
  if (error instanceof Error) {
21520
- console.error(chalk24.red(`
21697
+ console.error(chalk25.red(`
21521
21698
  \u2717 ${error.message}
21522
21699
  `));
21523
21700
  }
@@ -21531,7 +21708,7 @@ program.command("login").description("Authenticate with your Replicas account").
21531
21708
  await loginCommand();
21532
21709
  } catch (error) {
21533
21710
  if (error instanceof Error) {
21534
- console.error(chalk24.red(`
21711
+ console.error(chalk25.red(`
21535
21712
  \u2717 ${error.message}
21536
21713
  `));
21537
21714
  }
@@ -21543,7 +21720,7 @@ program.command("init").description("Create a replicas.json or replicas.yaml con
21543
21720
  initCommand(options);
21544
21721
  } catch (error) {
21545
21722
  if (error instanceof Error) {
21546
- console.error(chalk24.red(`
21723
+ console.error(chalk25.red(`
21547
21724
  \u2717 ${error.message}
21548
21725
  `));
21549
21726
  }
@@ -21555,7 +21732,7 @@ program.command("logout").description("Clear stored credentials").action(() => {
21555
21732
  logoutCommand();
21556
21733
  } catch (error) {
21557
21734
  if (error instanceof Error) {
21558
- console.error(chalk24.red(`
21735
+ console.error(chalk25.red(`
21559
21736
  \u2717 ${error.message}
21560
21737
  `));
21561
21738
  }
@@ -21567,7 +21744,7 @@ program.command("whoami").description("Display current authenticated user").acti
21567
21744
  await whoamiCommand();
21568
21745
  } catch (error) {
21569
21746
  if (error instanceof Error) {
21570
- console.error(chalk24.red(`
21747
+ console.error(chalk25.red(`
21571
21748
  \u2717 ${error.message}
21572
21749
  `));
21573
21750
  }
@@ -21579,7 +21756,7 @@ program.command("codex-auth").description("Authenticate Replicas with your Codex
21579
21756
  await codexAuthCommand(options);
21580
21757
  } catch (error) {
21581
21758
  if (error instanceof Error) {
21582
- console.error(chalk24.red(`
21759
+ console.error(chalk25.red(`
21583
21760
  \u2717 ${error.message}
21584
21761
  `));
21585
21762
  }
@@ -21591,7 +21768,7 @@ program.command("claude-auth").description("Authenticate Replicas with your Clau
21591
21768
  await claudeAuthCommand(options);
21592
21769
  } catch (error) {
21593
21770
  if (error instanceof Error) {
21594
- console.error(chalk24.red(`
21771
+ console.error(chalk25.red(`
21595
21772
  \u2717 ${error.message}
21596
21773
  `));
21597
21774
  }
@@ -21604,7 +21781,7 @@ org.command("switch").description("Switch to a different organization").action(a
21604
21781
  await orgSwitchCommand();
21605
21782
  } catch (error) {
21606
21783
  if (error instanceof Error) {
21607
- console.error(chalk24.red(`
21784
+ console.error(chalk25.red(`
21608
21785
  \u2717 ${error.message}
21609
21786
  `));
21610
21787
  }
@@ -21616,7 +21793,7 @@ org.action(async () => {
21616
21793
  await orgCommand();
21617
21794
  } catch (error) {
21618
21795
  if (error instanceof Error) {
21619
- console.error(chalk24.red(`
21796
+ console.error(chalk25.red(`
21620
21797
  \u2717 ${error.message}
21621
21798
  `));
21622
21799
  }
@@ -21628,7 +21805,7 @@ program.command("connect <workspace-name>").description("Connect to a workspace
21628
21805
  await connectCommand(workspaceName);
21629
21806
  } catch (error) {
21630
21807
  if (error instanceof Error) {
21631
- console.error(chalk24.red(`
21808
+ console.error(chalk25.red(`
21632
21809
  \u2717 ${error.message}
21633
21810
  `));
21634
21811
  }
@@ -21640,7 +21817,7 @@ program.command("code <workspace-name>").description("Open a workspace in VSCode
21640
21817
  await codeCommand(workspaceName);
21641
21818
  } catch (error) {
21642
21819
  if (error instanceof Error) {
21643
- console.error(chalk24.red(`
21820
+ console.error(chalk25.red(`
21644
21821
  \u2717 ${error.message}
21645
21822
  `));
21646
21823
  }
@@ -21653,7 +21830,7 @@ config.command("get <key>").description("Get a configuration value").action(asyn
21653
21830
  await configGetCommand(key);
21654
21831
  } catch (error) {
21655
21832
  if (error instanceof Error) {
21656
- console.error(chalk24.red(`
21833
+ console.error(chalk25.red(`
21657
21834
  \u2717 ${error.message}
21658
21835
  `));
21659
21836
  }
@@ -21665,7 +21842,7 @@ config.command("set <key> <value>").description("Set a configuration value").act
21665
21842
  await configSetCommand(key, value);
21666
21843
  } catch (error) {
21667
21844
  if (error instanceof Error) {
21668
- console.error(chalk24.red(`
21845
+ console.error(chalk25.red(`
21669
21846
  \u2717 ${error.message}
21670
21847
  `));
21671
21848
  }
@@ -21677,7 +21854,7 @@ config.command("list").description("List all configuration values").action(async
21677
21854
  await configListCommand();
21678
21855
  } catch (error) {
21679
21856
  if (error instanceof Error) {
21680
- console.error(chalk24.red(`
21857
+ console.error(chalk25.red(`
21681
21858
  \u2717 ${error.message}
21682
21859
  `));
21683
21860
  }
@@ -21689,7 +21866,7 @@ program.command("list").description("List all replicas").option("-p, --page <pag
21689
21866
  await replicaListCommand(options);
21690
21867
  } catch (error) {
21691
21868
  if (error instanceof Error) {
21692
- console.error(chalk24.red(`
21869
+ console.error(chalk25.red(`
21693
21870
  \u2717 ${error.message}
21694
21871
  `));
21695
21872
  }
@@ -21701,7 +21878,7 @@ program.command("get <id>").description("Get replica details by ID").action(asyn
21701
21878
  await replicaGetCommand(id);
21702
21879
  } catch (error) {
21703
21880
  if (error instanceof Error) {
21704
- console.error(chalk24.red(`
21881
+ console.error(chalk25.red(`
21705
21882
  \u2717 ${error.message}
21706
21883
  `));
21707
21884
  }
@@ -21713,7 +21890,7 @@ program.command("create [name]").description("Create a new replica").option("-m,
21713
21890
  await replicaCreateCommand(name, options);
21714
21891
  } catch (error) {
21715
21892
  if (error instanceof Error) {
21716
- console.error(chalk24.red(`
21893
+ console.error(chalk25.red(`
21717
21894
  \u2717 ${error.message}
21718
21895
  `));
21719
21896
  }
@@ -21725,7 +21902,7 @@ program.command("send <id>").description("Send a message to a replica").option("
21725
21902
  await replicaSendCommand(id, options);
21726
21903
  } catch (error) {
21727
21904
  if (error instanceof Error) {
21728
- console.error(chalk24.red(`
21905
+ console.error(chalk25.red(`
21729
21906
  \u2717 ${error.message}
21730
21907
  `));
21731
21908
  }
@@ -21737,7 +21914,7 @@ program.command("delete <id>").description("Delete a replica").option("-f, --for
21737
21914
  await replicaDeleteCommand(id, options);
21738
21915
  } catch (error) {
21739
21916
  if (error instanceof Error) {
21740
- console.error(chalk24.red(`
21917
+ console.error(chalk25.red(`
21741
21918
  \u2717 ${error.message}
21742
21919
  `));
21743
21920
  }
@@ -21749,7 +21926,7 @@ program.command("read <id>").description("Read conversation history of a replica
21749
21926
  await replicaReadCommand(id, options);
21750
21927
  } catch (error) {
21751
21928
  if (error instanceof Error) {
21752
- console.error(chalk24.red(`
21929
+ console.error(chalk25.red(`
21753
21930
  \u2717 ${error.message}
21754
21931
  `));
21755
21932
  }
@@ -21762,7 +21939,7 @@ automation.command("list").description("List all automations").option("-p, --pag
21762
21939
  await automationListCommand(options);
21763
21940
  } catch (error) {
21764
21941
  if (error instanceof Error) {
21765
- console.error(chalk24.red(`
21942
+ console.error(chalk25.red(`
21766
21943
  \u2717 ${error.message}
21767
21944
  `));
21768
21945
  }
@@ -21774,7 +21951,7 @@ automation.command("get <id>").description("Get automation details by ID").actio
21774
21951
  await automationGetCommand(id);
21775
21952
  } catch (error) {
21776
21953
  if (error instanceof Error) {
21777
- console.error(chalk24.red(`
21954
+ console.error(chalk25.red(`
21778
21955
  \u2717 ${error.message}
21779
21956
  `));
21780
21957
  }
@@ -21789,7 +21966,7 @@ automation.command("create [name]").description("Create a new automation").optio
21789
21966
  });
21790
21967
  } catch (error) {
21791
21968
  if (error instanceof Error) {
21792
- console.error(chalk24.red(`
21969
+ console.error(chalk25.red(`
21793
21970
  \u2717 ${error.message}
21794
21971
  `));
21795
21972
  }
@@ -21801,7 +21978,7 @@ automation.command("edit <id>").description("Edit an existing automation").optio
21801
21978
  await automationEditCommand(id, options);
21802
21979
  } catch (error) {
21803
21980
  if (error instanceof Error) {
21804
- console.error(chalk24.red(`
21981
+ console.error(chalk25.red(`
21805
21982
  \u2717 ${error.message}
21806
21983
  `));
21807
21984
  }
@@ -21813,7 +21990,7 @@ automation.command("run <id>").description("Manually trigger an automation (cron
21813
21990
  await automationRunCommand(id);
21814
21991
  } catch (error) {
21815
21992
  if (error instanceof Error) {
21816
- console.error(chalk24.red(`
21993
+ console.error(chalk25.red(`
21817
21994
  \u2717 ${error.message}
21818
21995
  `));
21819
21996
  }
@@ -21825,7 +22002,7 @@ automation.command("delete <id>").description("Delete an automation").option("-f
21825
22002
  await automationDeleteCommand(id, options);
21826
22003
  } catch (error) {
21827
22004
  if (error instanceof Error) {
21828
- console.error(chalk24.red(`
22005
+ console.error(chalk25.red(`
21829
22006
  \u2717 ${error.message}
21830
22007
  `));
21831
22008
  }
@@ -21837,7 +22014,7 @@ automation.action(async () => {
21837
22014
  await automationListCommand({});
21838
22015
  } catch (error) {
21839
22016
  if (error instanceof Error) {
21840
- console.error(chalk24.red(`
22017
+ console.error(chalk25.red(`
21841
22018
  \u2717 ${error.message}
21842
22019
  `));
21843
22020
  }
@@ -21850,7 +22027,7 @@ repos.command("list").description("List all repositories").action(async () => {
21850
22027
  await repositoriesListCommand();
21851
22028
  } catch (error) {
21852
22029
  if (error instanceof Error) {
21853
- console.error(chalk24.red(`
22030
+ console.error(chalk25.red(`
21854
22031
  \u2717 ${error.message}
21855
22032
  `));
21856
22033
  }
@@ -21862,7 +22039,7 @@ repos.action(async () => {
21862
22039
  await repositoriesListCommand();
21863
22040
  } catch (error) {
21864
22041
  if (error instanceof Error) {
21865
- console.error(chalk24.red(`
22042
+ console.error(chalk25.red(`
21866
22043
  \u2717 ${error.message}
21867
22044
  `));
21868
22045
  }
@@ -21875,7 +22052,7 @@ environment.command("list").description("List all environments").action(async ()
21875
22052
  await environmentListCommand();
21876
22053
  } catch (error) {
21877
22054
  if (error instanceof Error) {
21878
- console.error(chalk24.red(`
22055
+ console.error(chalk25.red(`
21879
22056
  \u2717 ${error.message}
21880
22057
  `));
21881
22058
  }
@@ -21887,7 +22064,7 @@ environment.command("get <id-or-name>").description('Get an environment by ID or
21887
22064
  await environmentGetCommand(idOrName);
21888
22065
  } catch (error) {
21889
22066
  if (error instanceof Error) {
21890
- console.error(chalk24.red(`
22067
+ console.error(chalk25.red(`
21891
22068
  \u2717 ${error.message}
21892
22069
  `));
21893
22070
  }
@@ -21899,7 +22076,7 @@ environment.command("create [name]").description("Create a new environment").opt
21899
22076
  await environmentCreateCommand(name, options);
21900
22077
  } catch (error) {
21901
22078
  if (error instanceof Error) {
21902
- console.error(chalk24.red(`
22079
+ console.error(chalk25.red(`
21903
22080
  \u2717 ${error.message}
21904
22081
  `));
21905
22082
  }
@@ -21911,7 +22088,7 @@ environment.command("edit <id-or-name>").description("Edit an environment").opti
21911
22088
  await environmentEditCommand(idOrName, options);
21912
22089
  } catch (error) {
21913
22090
  if (error instanceof Error) {
21914
- console.error(chalk24.red(`
22091
+ console.error(chalk25.red(`
21915
22092
  \u2717 ${error.message}
21916
22093
  `));
21917
22094
  }
@@ -21923,7 +22100,7 @@ environment.command("delete <id-or-name>").description("Delete an environment").
21923
22100
  await environmentDeleteCommand(idOrName, options);
21924
22101
  } catch (error) {
21925
22102
  if (error instanceof Error) {
21926
- console.error(chalk24.red(`
22103
+ console.error(chalk25.red(`
21927
22104
  \u2717 ${error.message}
21928
22105
  `));
21929
22106
  }
@@ -21936,7 +22113,7 @@ envVars.command("list <env>").description("List variables in an environment (val
21936
22113
  await envVarsListCommand(env, options);
21937
22114
  } catch (error) {
21938
22115
  if (error instanceof Error) {
21939
- console.error(chalk24.red(`
22116
+ console.error(chalk25.red(`
21940
22117
  \u2717 ${error.message}
21941
22118
  `));
21942
22119
  }
@@ -21948,7 +22125,7 @@ envVars.command("set <env> <key> <value>").description("Create or update a varia
21948
22125
  await envVarsSetCommand(env, key, value);
21949
22126
  } catch (error) {
21950
22127
  if (error instanceof Error) {
21951
- console.error(chalk24.red(`
22128
+ console.error(chalk25.red(`
21952
22129
  \u2717 ${error.message}
21953
22130
  `));
21954
22131
  }
@@ -21960,7 +22137,7 @@ envVars.command("delete <env> <key-or-id>").description("Delete a variable by ke
21960
22137
  await envVarsDeleteCommand(env, keyOrId, options);
21961
22138
  } catch (error) {
21962
22139
  if (error instanceof Error) {
21963
- console.error(chalk24.red(`
22140
+ console.error(chalk25.red(`
21964
22141
  \u2717 ${error.message}
21965
22142
  `));
21966
22143
  }
@@ -21973,7 +22150,7 @@ envFiles.command("list <env>").description("List files in an environment").actio
21973
22150
  await envFilesListCommand(env);
21974
22151
  } catch (error) {
21975
22152
  if (error instanceof Error) {
21976
- console.error(chalk24.red(`
22153
+ console.error(chalk25.red(`
21977
22154
  \u2717 ${error.message}
21978
22155
  `));
21979
22156
  }
@@ -21985,7 +22162,7 @@ envFiles.command("set <env> <destination-path>").description("Create or update a
21985
22162
  await envFilesSetCommand(env, destinationPath, options);
21986
22163
  } catch (error) {
21987
22164
  if (error instanceof Error) {
21988
- console.error(chalk24.red(`
22165
+ console.error(chalk25.red(`
21989
22166
  \u2717 ${error.message}
21990
22167
  `));
21991
22168
  }
@@ -21997,7 +22174,7 @@ envFiles.command("delete <env> <path-or-id>").description("Delete a file by dest
21997
22174
  await envFilesDeleteCommand(env, pathOrId, options);
21998
22175
  } catch (error) {
21999
22176
  if (error instanceof Error) {
22000
- console.error(chalk24.red(`
22177
+ console.error(chalk25.red(`
22001
22178
  \u2717 ${error.message}
22002
22179
  `));
22003
22180
  }
@@ -22010,7 +22187,7 @@ envStartHooks.command("get <env>").description("Show the active start hook for a
22010
22187
  await envStartHookGetCommand(env);
22011
22188
  } catch (error) {
22012
22189
  if (error instanceof Error) {
22013
- console.error(chalk24.red(`
22190
+ console.error(chalk25.red(`
22014
22191
  \u2717 ${error.message}
22015
22192
  `));
22016
22193
  }
@@ -22022,7 +22199,7 @@ envStartHooks.command("save <env>").description("Save and activate a start hook
22022
22199
  await envStartHookSaveCommand(env, options);
22023
22200
  } catch (error) {
22024
22201
  if (error instanceof Error) {
22025
- console.error(chalk24.red(`
22202
+ console.error(chalk25.red(`
22026
22203
  \u2717 ${error.message}
22027
22204
  `));
22028
22205
  }
@@ -22034,7 +22211,7 @@ envStartHooks.command("test <env>").description("Run a start hook in an isolated
22034
22211
  await envStartHookTestCommand(env, options);
22035
22212
  } catch (error) {
22036
22213
  if (error instanceof Error) {
22037
- console.error(chalk24.red(`
22214
+ console.error(chalk25.red(`
22038
22215
  \u2717 ${error.message}
22039
22216
  `));
22040
22217
  }
@@ -22046,7 +22223,7 @@ envStartHooks.command("repository-hooks <env>").description("List per-repo start
22046
22223
  await envStartHookRepositoryHooksCommand(env);
22047
22224
  } catch (error) {
22048
22225
  if (error instanceof Error) {
22049
- console.error(chalk24.red(`
22226
+ console.error(chalk25.red(`
22050
22227
  \u2717 ${error.message}
22051
22228
  `));
22052
22229
  }
@@ -22058,7 +22235,7 @@ environment.action(async () => {
22058
22235
  await environmentListCommand();
22059
22236
  } catch (error) {
22060
22237
  if (error instanceof Error) {
22061
- console.error(chalk24.red(`
22238
+ console.error(chalk25.red(`
22062
22239
  \u2717 ${error.message}
22063
22240
  `));
22064
22241
  }
@@ -22070,7 +22247,7 @@ program.command("interact").alias("i").description("Launch the interactive termi
22070
22247
  await interactiveCommand();
22071
22248
  } catch (error) {
22072
22249
  if (error instanceof Error) {
22073
- console.error(chalk24.red(`
22250
+ console.error(chalk25.red(`
22074
22251
  \u2717 ${error.message}
22075
22252
  `));
22076
22253
  }
@@ -22121,7 +22298,7 @@ if (isAgentMode()) {
22121
22298
  await previewAddCommand(workspaceId, options);
22122
22299
  } catch (error) {
22123
22300
  if (error instanceof Error) {
22124
- console.error(chalk24.red(`
22301
+ console.error(chalk25.red(`
22125
22302
  \u2717 ${error.message}
22126
22303
  `));
22127
22304
  }
@@ -22133,7 +22310,7 @@ if (isAgentMode()) {
22133
22310
  await previewListCommand(workspaceId);
22134
22311
  } catch (error) {
22135
22312
  if (error instanceof Error) {
22136
- console.error(chalk24.red(`
22313
+ console.error(chalk25.red(`
22137
22314
  \u2717 ${error.message}
22138
22315
  `));
22139
22316
  }
@@ -22145,7 +22322,7 @@ if (isAgentMode()) {
22145
22322
  await previewRemoveCommand(workspaceId, options);
22146
22323
  } catch (error) {
22147
22324
  if (error instanceof Error) {
22148
- console.error(chalk24.red(`
22325
+ console.error(chalk25.red(`
22149
22326
  \u2717 ${error.message}
22150
22327
  `));
22151
22328
  }
@@ -22154,13 +22331,54 @@ if (isAgentMode()) {
22154
22331
  });
22155
22332
  }
22156
22333
  if (isAgentMode()) {
22334
+ const service = program.command("service").description("Run long-lived services (dev servers, daemons) detached from the agent session so they survive workspace sleep/wake");
22335
+ service.command("start <name> [command...]").description('Start (or restart) a named service as a detached daemon. Quote shell operators: replicas service start web "cd app && bun dev"').option("-d, --cwd <dir>", "Working directory for the service (defaults to the current directory)").action(async (name, commandParts, options) => {
22336
+ try {
22337
+ await serviceStartCommand(name, commandParts, options);
22338
+ } catch (error) {
22339
+ if (error instanceof Error) {
22340
+ console.error(`Error: ${error.message}`);
22341
+ }
22342
+ process.exit(1);
22343
+ }
22344
+ });
22345
+ service.command("stop <name>").description("Stop a service and its whole process group").action(async (name) => {
22346
+ try {
22347
+ await serviceStopCommand(name);
22348
+ } catch (error) {
22349
+ if (error instanceof Error) {
22350
+ console.error(`Error: ${error.message}`);
22351
+ }
22352
+ process.exit(1);
22353
+ }
22354
+ });
22355
+ service.command("list").description("List registered services and whether they are running").action(async () => {
22356
+ try {
22357
+ await serviceListCommand();
22358
+ } catch (error) {
22359
+ if (error instanceof Error) {
22360
+ console.error(`Error: ${error.message}`);
22361
+ }
22362
+ process.exit(1);
22363
+ }
22364
+ });
22365
+ service.command("logs <name>").description("Print the last lines of a service log").option("-n, --lines <n>", "Number of lines to print (default 50)").action(async (name, options) => {
22366
+ try {
22367
+ await serviceLogsCommand(name, options);
22368
+ } catch (error) {
22369
+ if (error instanceof Error) {
22370
+ console.error(`Error: ${error.message}`);
22371
+ }
22372
+ process.exit(1);
22373
+ }
22374
+ });
22157
22375
  const media = program.command("media").description("Share workspace media (screenshots, videos, audio) inline in chat");
22158
22376
  media.command("upload <files...>").description("Upload one or more screenshot, video, or audio files. Multiple files are uploaded concurrently. Prints a markdown embed per file for the assistant reply.").option("-k, --kind <kind>", "Media kind: image, video, or audio (inferred from extension if omitted)").option("-s, --session-id <id>", "Session ID to associate the asset with").option("--share", "Create an opt-in public forge embed URL for each asset").action(async (files, options) => {
22159
22377
  try {
22160
22378
  await mediaUploadCommand(files, options);
22161
22379
  } catch (error) {
22162
22380
  if (error instanceof Error) {
22163
- console.error(chalk24.red(`
22381
+ console.error(chalk25.red(`
22164
22382
  \u2717 ${error.message}
22165
22383
  `));
22166
22384
  }
@@ -22171,7 +22389,7 @@ if (isAgentMode()) {
22171
22389
  try {
22172
22390
  await mediaShareCommand(mediaId);
22173
22391
  } catch (error) {
22174
- if (error instanceof Error) console.error(chalk24.red(`
22392
+ if (error instanceof Error) console.error(chalk25.red(`
22175
22393
  \u2717 ${error.message}
22176
22394
  `));
22177
22395
  process.exit(1);
@@ -22181,7 +22399,7 @@ if (isAgentMode()) {
22181
22399
  try {
22182
22400
  await mediaRevokeCommand(mediaId);
22183
22401
  } catch (error) {
22184
- if (error instanceof Error) console.error(chalk24.red(`
22402
+ if (error instanceof Error) console.error(chalk25.red(`
22185
22403
  \u2717 ${error.message}
22186
22404
  `));
22187
22405
  process.exit(1);
@@ -22192,7 +22410,7 @@ if (isAgentMode()) {
22192
22410
  await mediaListCommand(options);
22193
22411
  } catch (error) {
22194
22412
  if (error instanceof Error) {
22195
- console.error(chalk24.red(`
22413
+ console.error(chalk25.red(`
22196
22414
  \u2717 ${error.message}
22197
22415
  `));
22198
22416
  }
@@ -22205,7 +22423,7 @@ if (isAgentMode()) {
22205
22423
  await learningsReadCommand(options);
22206
22424
  } catch (error) {
22207
22425
  if (error instanceof Error) {
22208
- console.error(chalk24.red(`
22426
+ console.error(chalk25.red(`
22209
22427
  \u2717 ${error.message}
22210
22428
  `));
22211
22429
  }
@@ -22217,7 +22435,7 @@ if (isAgentMode()) {
22217
22435
  await learningsAddCommand(options);
22218
22436
  } catch (error) {
22219
22437
  if (error instanceof Error) {
22220
- console.error(chalk24.red(`
22438
+ console.error(chalk25.red(`
22221
22439
  \u2717 ${error.message}
22222
22440
  `));
22223
22441
  }
@@ -22229,7 +22447,7 @@ if (isAgentMode()) {
22229
22447
  await learningsUpdateCommand(id, options);
22230
22448
  } catch (error) {
22231
22449
  if (error instanceof Error) {
22232
- console.error(chalk24.red(`
22450
+ console.error(chalk25.red(`
22233
22451
  \u2717 ${error.message}
22234
22452
  `));
22235
22453
  }
@@ -22241,7 +22459,7 @@ if (isAgentMode()) {
22241
22459
  await learningsDeleteCommand(id);
22242
22460
  } catch (error) {
22243
22461
  if (error instanceof Error) {
22244
- console.error(chalk24.red(`
22462
+ console.error(chalk25.red(`
22245
22463
  \u2717 ${error.message}
22246
22464
  `));
22247
22465
  }
@@ -22254,7 +22472,7 @@ if (isAgentMode()) {
22254
22472
  await fn(...args);
22255
22473
  } catch (error) {
22256
22474
  if (error instanceof Error) {
22257
- console.error(chalk24.red(`
22475
+ console.error(chalk25.red(`
22258
22476
  \u2717 ${error.message}
22259
22477
  `));
22260
22478
  }
@@ -22295,6 +22513,7 @@ if (isAgentMode()) {
22295
22513
  "list",
22296
22514
  "connect",
22297
22515
  "preview",
22516
+ "service",
22298
22517
  "media",
22299
22518
  "slack",
22300
22519
  "computer",