runwork 0.17.0 → 0.17.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -411,6 +411,29 @@ class ApiClient {
411
411
  const res = await this.request("/api/dev/workspaces");
412
412
  return res.data;
413
413
  }
414
+ async listWorkspaceMembers(workspaceId) {
415
+ const res = await this.request(`/api/workspaces/${workspaceId}/members`);
416
+ return res.data.members;
417
+ }
418
+ async rawApiCall(method, path, opts) {
419
+ const targetPath = opts?.query ? `${path}${path.includes("?") ? "&" : "?"}${opts.query}` : path;
420
+ const url = `${this.baseUrl}${targetPath}`;
421
+ const headers = { ...opts?.headers || {} };
422
+ if (this.apiKey) {
423
+ headers["Authorization"] = `Bearer ${this.apiKey}`;
424
+ }
425
+ let body;
426
+ if (opts?.body !== undefined) {
427
+ body = typeof opts.body === "string" ? opts.body : JSON.stringify(opts.body);
428
+ if (!Object.keys(headers).some((h) => h.toLowerCase() === "content-type")) {
429
+ headers["Content-Type"] = "application/json";
430
+ }
431
+ }
432
+ const response = await httpFetch(url, { method: method.toUpperCase(), headers, body });
433
+ const contentType = response.headers.get("content-type") || "";
434
+ const responseBody = contentType.includes("application/json") ? await response.json() : await response.text();
435
+ return { status: response.status, ok: response.ok, contentType, body: responseBody };
436
+ }
414
437
  async listApps(workspaceId) {
415
438
  const query = workspaceId ? `?workspaceId=${workspaceId}` : "";
416
439
  const res = await this.request(`/api/dev/apps${query}`);
@@ -883,20 +906,28 @@ var init_subprocess = () => {};
883
906
 
884
907
  // src/git/credentials.ts
885
908
  import { existsSync as existsSync2 } from "fs";
886
- function buildHelperValue(execPath) {
909
+ function buildHelperValue(execPath, scriptPath) {
887
910
  const normalised = execPath.replace(/\\/g, "/");
911
+ const runtimeName = normalised.split("/").pop()?.toLowerCase() ?? "";
912
+ if (SCRIPT_RUNTIMES.has(runtimeName) && scriptPath) {
913
+ const script = scriptPath.replace(/\\/g, "/");
914
+ return `!"${normalised}" "${script}" git-credential-helper`;
915
+ }
888
916
  return `!"${normalised}" git-credential-helper`;
889
917
  }
890
918
  async function configureGitCredentials(remoteUrl) {
891
919
  const origin = new URL(remoteUrl).origin;
892
- const helperValue = buildHelperValue(process.execPath);
920
+ const key = `credential.${origin}.helper`;
921
+ const helperValue = buildHelperValue(process.execPath, process.argv[1]);
893
922
  try {
894
- execFileSync("git", [
895
- "config",
896
- "--global",
897
- `credential.${origin}.helper`,
898
- helperValue
899
- ], { stdio: "pipe" });
923
+ try {
924
+ execFileSync("git", ["config", "--global", "--unset-all", key], { stdio: "pipe" });
925
+ } catch (unsetErr) {
926
+ if (unsetErr?.code === "ENOENT")
927
+ throw unsetErr;
928
+ }
929
+ execFileSync("git", ["config", "--global", "--add", key, ""], { stdio: "pipe" });
930
+ execFileSync("git", ["config", "--global", "--add", key, helperValue], { stdio: "pipe" });
900
931
  } catch (err) {
901
932
  const code = err?.code;
902
933
  if (code === "ENOENT") {
@@ -915,14 +946,37 @@ function lookupCredentialHelper(origin) {
915
946
  } catch {
916
947
  return { status: "none" };
917
948
  }
918
- const lines = helperConfig.split(/\r?\n/).map((l) => l.trim()).filter(Boolean);
919
- const escapedOrigin = origin.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
920
- const scopedRegex = new RegExp(`^credential\\.${escapedOrigin}\\.helper\\s+(.+)$`);
921
- const matchedLine = lines.find((line) => scopedRegex.test(line));
922
- if (!matchedLine) {
923
- return { status: "unscoped", otherCount: lines.length };
949
+ const keyName = `credential.${origin}.helper`;
950
+ let value = "";
951
+ let registered = false;
952
+ let hasReset = false;
953
+ let otherCount = 0;
954
+ for (const raw of helperConfig.split(/\r?\n/)) {
955
+ if (!raw.trim())
956
+ continue;
957
+ const m = raw.match(/^(\S+)(?:\s+(.*))?$/);
958
+ if (!m)
959
+ continue;
960
+ const key = m[1];
961
+ const val = (m[2] ?? "").trim();
962
+ if (key === keyName) {
963
+ if (val === "")
964
+ hasReset = true;
965
+ else if (!registered) {
966
+ registered = true;
967
+ value = val;
968
+ }
969
+ } else {
970
+ otherCount++;
971
+ }
972
+ }
973
+ if (registered) {
974
+ return { status: "registered", value, hasReset };
975
+ }
976
+ if (otherCount === 0 && !hasReset) {
977
+ return { status: "none" };
924
978
  }
925
- return { status: "registered", value: scopedRegex.exec(matchedLine)?.[1] ?? "" };
979
+ return { status: "unscoped", otherCount };
926
980
  }
927
981
  function helperBinaryStatus(value) {
928
982
  const absoluteHelperRegex = /^!"?(\/|[A-Za-z]:[\\/])/;
@@ -942,7 +996,7 @@ async function ensureGitCredentialHelper(baseUrl) {
942
996
  return;
943
997
  }
944
998
  const lookup = lookupCredentialHelper(origin);
945
- if (lookup.status === "registered" && helperBinaryStatus(lookup.value).ok) {
999
+ if (lookup.status === "registered" && helperBinaryStatus(lookup.value).ok && lookup.hasReset) {
946
1000
  return;
947
1001
  }
948
1002
  await configureGitCredentials(baseUrl);
@@ -953,7 +1007,7 @@ async function removeGitCredentials(baseUrl) {
953
1007
  execFileSync("git", [
954
1008
  "config",
955
1009
  "--global",
956
- "--unset",
1010
+ "--unset-all",
957
1011
  `credential.${origin}.helper`
958
1012
  ], { stdio: "pipe" });
959
1013
  } catch {}
@@ -996,9 +1050,11 @@ function readStdin() {
996
1050
  resolve(data);
997
1051
  });
998
1052
  }
1053
+ var SCRIPT_RUNTIMES;
999
1054
  var init_credentials = __esm(() => {
1000
1055
  init_subprocess();
1001
1056
  init_store();
1057
+ SCRIPT_RUNTIMES = new Set(["node", "node.exe", "bun", "bun.exe"]);
1002
1058
  });
1003
1059
 
1004
1060
  // src/auth/login-flow.ts
@@ -1429,8 +1485,8 @@ async function resolveWorkspace(client, nameOrId) {
1429
1485
  console.error(`Workspace "${nameOrId}" not found. Available: ${workspaces.map((w) => w.name).join(", ")}`);
1430
1486
  process.exit(1);
1431
1487
  }
1432
- async function resolveApp(client, nameOrId) {
1433
- const apps = await client.listApps();
1488
+ async function resolveApp(client, nameOrId, workspaceId) {
1489
+ const apps = await client.listApps(workspaceId);
1434
1490
  if (apps.length === 0) {
1435
1491
  console.error("No apps found.");
1436
1492
  process.exit(1);
@@ -2422,7 +2478,7 @@ var init_clone = __esm(() => {
2422
2478
  init_remote();
2423
2479
  init_repo_config();
2424
2480
  init_preflight();
2425
- cloneCommand = new Command3("clone").description("Clone a Runwork app to local development").argument("[appId]", "App ID to clone (interactive if omitted)").argument("[directory]", "Target directory").option("--app <name-or-id>", "App name or ID (skips interactive selection)").addHelpText("after", RESTRICTED_FS_HELP).action(async (rawAppId, rawDirectory, options) => {
2481
+ cloneCommand = new Command3("clone").description("Clone a Runwork app to local development").argument("[appId]", "App ID to clone (interactive if omitted)").argument("[directory]", "Target directory").option("--app <name-or-id>", "App name or ID (skips interactive selection)").option("--workspace <name-or-id>", "Workspace to look up the app in (name or ID)").addHelpText("after", RESTRICTED_FS_HELP).action(async (rawAppId, rawDirectory, options) => {
2426
2482
  requireGit("clone");
2427
2483
  const { appId, directory } = normalizeCloneArgs(rawAppId, rawDirectory, options);
2428
2484
  const creds = requireAuth();
@@ -2430,10 +2486,15 @@ var init_clone = __esm(() => {
2430
2486
  const useJson = shouldOutputJson(undefined);
2431
2487
  let app;
2432
2488
  const appRef = options?.app || appId;
2489
+ let workspaceId;
2490
+ if (options?.workspace) {
2491
+ const ws = await resolveWorkspace(client, options.workspace);
2492
+ workspaceId = ws.id;
2493
+ }
2433
2494
  if (appRef) {
2434
- app = await resolveApp(client, appRef);
2495
+ app = await resolveApp(client, appRef, workspaceId);
2435
2496
  } else {
2436
- const apps = await client.listApps();
2497
+ const apps = await client.listApps(workspaceId);
2437
2498
  if (apps.length === 0) {
2438
2499
  if (useJson) {
2439
2500
  jsonOut(buildErrorResponse("clone", "No apps found", "No apps are available to clone.", ["Create an app first with: runwork init my-app"]));
@@ -3307,13 +3368,20 @@ function resolvePollDeps(deps) {
3307
3368
  }
3308
3369
  async function pollForSession(appDir, expectedPid, expectedAppId, opts = {}) {
3309
3370
  const intervalMs = opts.intervalMs ?? 250;
3310
- const timeoutMs = opts.timeoutMs ?? 90000;
3371
+ const timeoutMs = opts.timeoutMs ?? DETACH_READY_TIMEOUT_MS;
3372
+ const heartbeatMs = opts.heartbeatMs ?? DETACH_WAITING_HEARTBEAT_MS;
3311
3373
  const d = resolvePollDeps(opts.deps);
3312
- const deadline = d.now() + timeoutMs;
3374
+ const startedAt = d.now();
3375
+ const deadline = startedAt + timeoutMs;
3376
+ let lastHeartbeatAt = startedAt;
3313
3377
  while (d.now() < deadline) {
3314
3378
  if (opts.isChildAlive && !opts.isChildAlive()) {
3315
3379
  return { result: "child-exited" };
3316
3380
  }
3381
+ if (opts.onWaiting && d.now() - lastHeartbeatAt >= heartbeatMs) {
3382
+ lastHeartbeatAt = d.now();
3383
+ opts.onWaiting(d.now() - startedAt);
3384
+ }
3317
3385
  const file = readSessionFile(appDir);
3318
3386
  if (file && file.previewUrl && file.appId === expectedAppId) {
3319
3387
  if (file.pid === expectedPid) {
@@ -3349,7 +3417,9 @@ async function runAsDetachedParent(opts) {
3349
3417
  intervalMs: opts.intervalMs,
3350
3418
  timeoutMs: opts.timeoutMs,
3351
3419
  deps: opts.pollDeps,
3352
- isChildAlive: child.isAlive
3420
+ isChildAlive: child.isAlive,
3421
+ onWaiting: opts.onWaiting,
3422
+ heartbeatMs: opts.heartbeatMs
3353
3423
  });
3354
3424
  if (outcome.result === "ready") {
3355
3425
  return { result: "started", file: outcome.file };
@@ -3366,22 +3436,27 @@ async function runAsDetachedParent(opts) {
3366
3436
  try {
3367
3437
  removeSessionFileIfOwned(opts.appDir, child.pid);
3368
3438
  } catch {}
3369
- const childLogTail = readChildStderrTail(opts.appDir);
3439
+ const childLogTail = readChildLogTail(opts.appDir);
3370
3440
  if (outcome.result === "child-exited") {
3371
3441
  return { result: "child-exited", ourPid: child.pid, childLogTail };
3372
3442
  }
3373
3443
  return { result: "timeout", ourPid: child.pid, childLogTail };
3374
3444
  }
3375
- function readChildStderrTail(appDir) {
3376
- try {
3377
- const paths = getSessionPaths(appDir);
3378
- if (!fs2.existsSync(paths.stderrLog))
3379
- return;
3380
- const raw = fs2.readFileSync(paths.stderrLog, "utf-8");
3381
- return raw.slice(-2000);
3382
- } catch {
3383
- return;
3445
+ function readChildLogTail(appDir) {
3446
+ const paths = getSessionPaths(appDir);
3447
+ const sections = [];
3448
+ for (const [label, file] of [["stderr", paths.stderrLog], ["stdout", paths.stdoutLog]]) {
3449
+ try {
3450
+ if (!fs2.existsSync(file))
3451
+ continue;
3452
+ const tail = fs2.readFileSync(file, "utf-8").slice(-2000).trim();
3453
+ if (tail)
3454
+ sections.push(`--- ${label} (tail) ---
3455
+ ${tail}`);
3456
+ } catch {}
3384
3457
  }
3458
+ return sections.length > 0 ? sections.join(`
3459
+ `) : undefined;
3385
3460
  }
3386
3461
  function defaultSpawnDetachedChild(childArgs) {
3387
3462
  const cwd = process.cwd();
@@ -3441,7 +3516,7 @@ function buildChildArgs(parentArgv) {
3441
3516
  }
3442
3517
  return [...stripInternalChildFlag(rest), INTERNAL_DETACHED_CHILD_FLAG];
3443
3518
  }
3444
- var INTERNAL_DETACHED_CHILD_FLAG = "--internal-detached-child", realPollDeps;
3519
+ var INTERNAL_DETACHED_CHILD_FLAG = "--internal-detached-child", DETACH_READY_TIMEOUT_MS = 630000, DETACH_WAITING_HEARTBEAT_MS = 15000, realPollDeps;
3445
3520
  var init_detach = __esm(() => {
3446
3521
  init_session();
3447
3522
  realPollDeps = {
@@ -3450,6 +3525,104 @@ var init_detach = __esm(() => {
3450
3525
  };
3451
3526
  });
3452
3527
 
3528
+ // src/dev/boot-await.ts
3529
+ function isPermanentStartError(err) {
3530
+ if (!(err instanceof Error))
3531
+ return false;
3532
+ const match = err.message.match(/^API error (\d{3})/);
3533
+ if (!match)
3534
+ return false;
3535
+ const status = Number.parseInt(match[1], 10);
3536
+ return status >= 400 && status < 500;
3537
+ }
3538
+ async function awaitDevSessionReady(opts) {
3539
+ const now = opts.deps?.now ?? (() => Date.now());
3540
+ const sleep = opts.deps?.sleep ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
3541
+ const timeoutMs = opts.timeoutMs ?? DEV_BOOT_TIMEOUT_MS;
3542
+ const heartbeatMs = opts.heartbeatMs ?? DEV_BOOT_HEARTBEAT_MS;
3543
+ const statusPollDelayMs = opts.statusPollDelayMs ?? DEV_BOOT_STATUS_POLL_DELAY_MS;
3544
+ const statusPollIntervalMs = opts.statusPollIntervalMs ?? DEV_BOOT_STATUS_POLL_INTERVAL_MS;
3545
+ const startedAt = now();
3546
+ const elapsed = () => now() - startedAt;
3547
+ const st = {
3548
+ startResult: null,
3549
+ startError: undefined,
3550
+ startSettled: false,
3551
+ permanentFailure: null,
3552
+ statusReady: null,
3553
+ statusInFlight: false
3554
+ };
3555
+ opts.start().then((session) => {
3556
+ st.startResult = session;
3557
+ st.startSettled = true;
3558
+ }, (err) => {
3559
+ st.startError = err;
3560
+ st.startSettled = true;
3561
+ if (isPermanentStartError(err)) {
3562
+ st.permanentFailure = err;
3563
+ } else {
3564
+ opts.onStartError?.(err);
3565
+ }
3566
+ });
3567
+ let lastStatusPollAt = -Infinity;
3568
+ let lastHeartbeatAt = startedAt;
3569
+ const readyResult = () => {
3570
+ if (st.startResult && st.startResult.previewUrl) {
3571
+ return { session: st.startResult, source: "start", elapsedMs: elapsed() };
3572
+ }
3573
+ if (st.statusReady) {
3574
+ return { session: st.statusReady, source: "status", elapsedMs: elapsed() };
3575
+ }
3576
+ return null;
3577
+ };
3578
+ while (elapsed() < timeoutMs) {
3579
+ if (st.permanentFailure)
3580
+ throw st.permanentFailure;
3581
+ const ready2 = readyResult();
3582
+ if (ready2)
3583
+ return ready2;
3584
+ const startFailedOrEmpty = st.startSettled && !(st.startResult && st.startResult.previewUrl);
3585
+ const pollingActive = elapsed() >= statusPollDelayMs || startFailedOrEmpty;
3586
+ if (pollingActive && !st.statusInFlight && now() - lastStatusPollAt >= statusPollIntervalMs) {
3587
+ st.statusInFlight = true;
3588
+ lastStatusPollAt = now();
3589
+ opts.pollStatus().then((session) => {
3590
+ st.statusInFlight = false;
3591
+ if (session.previewUrl)
3592
+ st.statusReady = session;
3593
+ }, () => {
3594
+ st.statusInFlight = false;
3595
+ });
3596
+ }
3597
+ if (now() - lastHeartbeatAt >= heartbeatMs) {
3598
+ lastHeartbeatAt = now();
3599
+ opts.onWaiting?.(elapsed());
3600
+ }
3601
+ await sleep(TICK_MS);
3602
+ }
3603
+ if (st.permanentFailure)
3604
+ throw st.permanentFailure;
3605
+ const ready = readyResult();
3606
+ if (ready)
3607
+ return ready;
3608
+ throw new DevBootTimeoutError(elapsed(), st.startError);
3609
+ }
3610
+ var DEV_BOOT_TIMEOUT_MS = 600000, DEV_BOOT_HEARTBEAT_MS = 15000, DEV_BOOT_STATUS_POLL_DELAY_MS = 45000, DEV_BOOT_STATUS_POLL_INTERVAL_MS = 1e4, DevBootTimeoutError, TICK_MS = 250;
3611
+ var init_boot_await = __esm(() => {
3612
+ DevBootTimeoutError = class DevBootTimeoutError extends Error {
3613
+ elapsedMs;
3614
+ startError;
3615
+ constructor(elapsedMs, startError) {
3616
+ const base = `Dev session did not become ready within ${Math.round(elapsedMs / 1000)}s`;
3617
+ const cause = startError instanceof Error ? ` (boot call failed: ${startError.message})` : "";
3618
+ super(`${base}${cause}`);
3619
+ this.name = "DevBootTimeoutError";
3620
+ this.elapsedMs = elapsedMs;
3621
+ this.startError = startError;
3622
+ }
3623
+ };
3624
+ });
3625
+
3453
3626
  // src/dev/stop.ts
3454
3627
  import * as fs3 from "fs";
3455
3628
  async function stopSession(appDir, expectedAppId, deps = {}) {
@@ -5652,6 +5825,13 @@ export interface JobRunRecord {
5652
5825
  completedAt?: number;
5653
5826
  result?: JobResult;
5654
5827
  error?: string;
5828
+ /**
5829
+ * Stack trace of the failure. Stored because the error MESSAGE alone made
5830
+ * the 2026-07 "Could not serialize object of type ..." production failures
5831
+ * undiagnosable: the message names the workerd serializer, not the framework
5832
+ * call site that hit it (AGENTCLI-6).
5833
+ */
5834
+ errorStack?: string;
5655
5835
  }
5656
5836
  export interface ScheduleState {
5657
5837
  name: string;
@@ -7381,7 +7561,7 @@ function createKeyboardListener() {
7381
7561
  }
7382
7562
 
7383
7563
  // src/generated/version.ts
7384
- var VERSION = "0.17.0";
7564
+ var VERSION = "0.17.1";
7385
7565
 
7386
7566
  // src/commands/dev.ts
7387
7567
  var exports_dev = {};
@@ -7515,7 +7695,64 @@ async function execDev(options) {
7515
7695
  } else {
7516
7696
  console.log(dim("Starting dev session..."));
7517
7697
  }
7518
- const session = await client.startDevSession(config.appId);
7698
+ let session;
7699
+ try {
7700
+ const boot = await awaitDevSessionReady({
7701
+ start: () => client.startDevSession(config.appId),
7702
+ pollStatus: () => client.getDevStatus(config.appId),
7703
+ onWaiting: (elapsedMs) => {
7704
+ const seconds = Math.round(elapsedMs / 1000);
7705
+ if (useJson) {
7706
+ jsonLine({
7707
+ event: "startup",
7708
+ phase: "dev_session_waiting",
7709
+ elapsedSeconds: seconds,
7710
+ timestamp: ts(),
7711
+ note: "Sandbox is booting. Cold boots can take a few minutes; keep waiting."
7712
+ });
7713
+ } else {
7714
+ console.log(dim(` Still starting the sandbox... (${seconds}s elapsed; cold boots can take a few minutes)`));
7715
+ }
7716
+ },
7717
+ onStartError: (err) => {
7718
+ const message = err instanceof Error ? err.message : String(err);
7719
+ if (useJson) {
7720
+ jsonLine({
7721
+ event: "startup",
7722
+ phase: "dev_session_retrying",
7723
+ timestamp: ts(),
7724
+ warning: `Boot call failed (${message}). The sandbox may still be booting server-side; watching status until it becomes ready.`
7725
+ });
7726
+ } else {
7727
+ console.warn(yellow(` Boot call failed (${message}); watching sandbox status in case the boot completes server-side...`));
7728
+ }
7729
+ }
7730
+ });
7731
+ session = boot.session;
7732
+ } catch (error) {
7733
+ const isTimeout = error instanceof DevBootTimeoutError;
7734
+ const message = error instanceof Error ? error.message : String(error);
7735
+ if (useJson) {
7736
+ jsonLine({
7737
+ event: "error",
7738
+ phase: "dev_session",
7739
+ timestamp: ts(),
7740
+ error: {
7741
+ message,
7742
+ diagnosis: isTimeout ? "The preview sandbox did not become ready within the boot deadline. The sandbox provider may be degraded, or the app failed to boot server-side." : "The dev session boot call failed.",
7743
+ suggestions: [
7744
+ "Re-run `runwork dev --detach --json` in about a minute; if the sandbox finished booting server-side it will be picked up quickly",
7745
+ "Run `runwork logs` to inspect sandbox logs for boot errors",
7746
+ "Run `runwork doctor` to verify auth and connectivity"
7747
+ ]
7748
+ }
7749
+ });
7750
+ } else {
7751
+ console.error(red(`Failed to start dev session: ${message}`));
7752
+ console.error(dim(" Re-run `runwork dev` in about a minute; if the sandbox finished booting server-side it will be picked up quickly."));
7753
+ }
7754
+ process.exit(1);
7755
+ }
7519
7756
  await populateSkill(cwd, client, config.appId);
7520
7757
  if (useJson)
7521
7758
  jsonLine({ event: "startup", phase: "skill_fetched", timestamp: ts() });
@@ -7804,7 +8041,21 @@ async function runDevDetachParent(opts) {
7804
8041
  const outcome = await runAsDetachedParent({
7805
8042
  appDir: cwd,
7806
8043
  expectedAppId: config.appId,
7807
- childArgs
8044
+ childArgs,
8045
+ onWaiting: (elapsedMs) => {
8046
+ const seconds = Math.round(elapsedMs / 1000);
8047
+ if (opts.json) {
8048
+ jsonLine({
8049
+ event: "waiting",
8050
+ phase: "sandbox_boot",
8051
+ elapsedSeconds: seconds,
8052
+ timestamp: ts(),
8053
+ note: "Sandbox is booting. Cold boots can take a few minutes; keep waiting for session_started."
8054
+ });
8055
+ } else {
8056
+ console.log(dim(` Still starting... (${seconds}s elapsed; cold boots can take a few minutes)`));
8057
+ }
8058
+ }
7808
8059
  });
7809
8060
  switch (outcome.result) {
7810
8061
  case "started": {
@@ -7862,9 +8113,10 @@ async function runDevDetachParent(opts) {
7862
8113
  timestamp: ts(),
7863
8114
  error: {
7864
8115
  message,
7865
- diagnosis: "The detached child process exited (typically due to missing auth, missing git, network failure, or a sync conflict) before it could publish a preview URL.",
8116
+ diagnosis: "The detached child process exited (typically due to missing auth, missing git, network failure, a sync conflict, or a sandbox boot timeout) before it could publish a preview URL.",
7866
8117
  suggestions: [
7867
- "Inspect the child stderr at .runwork/dev-stderr.log",
8118
+ "Check childLogTail below; the child logs structured errors to .runwork/dev-stdout.log (stderr carries crash traces)",
8119
+ "If the child hit a sandbox boot timeout, re-run `runwork dev --detach --json` in about a minute; a boot that completed server-side is picked up quickly",
7868
8120
  "Run `runwork doctor` to verify auth and connectivity",
7869
8121
  "Try `runwork dev` (foreground) to see the failure inline"
7870
8122
  ],
@@ -7873,7 +8125,7 @@ async function runDevDetachParent(opts) {
7873
8125
  });
7874
8126
  } else {
7875
8127
  console.error(yellow(message));
7876
- console.error(dim(" Inspect .runwork/dev-stderr.log or run `runwork dev` to see what failed."));
8128
+ console.error(dim(" Inspect .runwork/dev-stdout.log and dev-stderr.log, or run `runwork dev` to see what failed."));
7877
8129
  if (outcome.childLogTail) {
7878
8130
  console.error(dim(" Tail of child stderr:"));
7879
8131
  for (const line of outcome.childLogTail.split(`
@@ -7887,7 +8139,8 @@ async function runDevDetachParent(opts) {
7887
8139
  return;
7888
8140
  }
7889
8141
  case "timeout": {
7890
- const message = `Detached dev session did not become ready within 90s.`;
8142
+ const timeoutSeconds = Math.round(DETACH_READY_TIMEOUT_MS / 1000);
8143
+ const message = `Detached dev session did not become ready within ${timeoutSeconds}s.`;
7891
8144
  if (opts.json) {
7892
8145
  jsonLine({
7893
8146
  event: "error",
@@ -7895,9 +8148,10 @@ async function runDevDetachParent(opts) {
7895
8148
  timestamp: ts(),
7896
8149
  error: {
7897
8150
  message,
7898
- diagnosis: "The detached child process was spawned but never wrote a session file with a preview URL. The sandbox boot may have failed.",
8151
+ diagnosis: "The detached child process was spawned but never wrote a session file with a preview URL. The sandbox boot may have failed or the sandbox provider may be degraded.",
7899
8152
  suggestions: [
7900
- "Inspect the child stderr at .runwork/dev-stderr.log",
8153
+ "The sandbox may still finish booting server-side: re-run `runwork dev --detach --json` in about a minute; a completed boot is picked up quickly",
8154
+ "Inspect the child logs at .runwork/dev-stdout.log and .runwork/dev-stderr.log",
7901
8155
  "Run `runwork doctor` to verify auth and connectivity",
7902
8156
  "Try `runwork dev` (foreground) to see the failure inline"
7903
8157
  ],
@@ -7906,7 +8160,7 @@ async function runDevDetachParent(opts) {
7906
8160
  });
7907
8161
  } else {
7908
8162
  console.error(yellow(message));
7909
- console.error(dim(" Inspect .runwork/dev-stderr.log or run `runwork dev` to see what failed."));
8163
+ console.error(dim(" Inspect .runwork/dev-stdout.log and dev-stderr.log, or run `runwork dev` to see what failed."));
7910
8164
  if (outcome.childLogTail) {
7911
8165
  console.error(dim(" Tail of child stderr:"));
7912
8166
  for (const line of outcome.childLogTail.split(`
@@ -7956,6 +8210,7 @@ var init_dev = __esm(() => {
7956
8210
  init_tailer();
7957
8211
  init_session();
7958
8212
  init_detach();
8213
+ init_boot_await();
7959
8214
  init_stop();
7960
8215
  init_attach();
7961
8216
  init_types_manager();
@@ -8291,7 +8546,7 @@ var init_welcome = __esm(() => {
8291
8546
  });
8292
8547
 
8293
8548
  // src/index.ts
8294
- import { Command as Command34 } from "commander";
8549
+ import { Command as Command36 } from "commander";
8295
8550
 
8296
8551
  // src/commands/login.ts
8297
8552
  init_login_flow();
@@ -8394,8 +8649,23 @@ function getDeploySummary(cwd) {
8394
8649
  }
8395
8650
 
8396
8651
  // src/deploy/deploy-status.ts
8652
+ init_session();
8397
8653
  import { existsSync as existsSync16, mkdirSync as mkdirSync11, readFileSync as readFileSync13, writeFileSync as writeFileSync12 } from "fs";
8398
8654
  import { dirname as dirname4, join as join17 } from "path";
8655
+ function evaluateDeployStatus(status, deps = {}) {
8656
+ if (status.state !== "in-progress") {
8657
+ return { status, effectiveState: status.state };
8658
+ }
8659
+ const bootTime = deps.bootTime ?? currentBootTime;
8660
+ const pidAlive = deps.pidAlive ?? isPidAlive;
8661
+ if (typeof status.bootTime === "number" && Math.abs(bootTime() - status.bootTime) > BOOT_TIME_TOLERANCE_MS) {
8662
+ return { status, effectiveState: "stale", staleReason: "boot-time-mismatch" };
8663
+ }
8664
+ if (typeof status.pid === "number" && !pidAlive(status.pid)) {
8665
+ return { status, effectiveState: "stale", staleReason: "process-gone" };
8666
+ }
8667
+ return { status, effectiveState: "in-progress" };
8668
+ }
8399
8669
  function statusPath(cwd) {
8400
8670
  return join17(cwd, ".runwork", "deploy-status.json");
8401
8671
  }
@@ -8425,6 +8695,9 @@ function readDeployStatus(cwd) {
8425
8695
  }
8426
8696
  }
8427
8697
 
8698
+ // src/commands/deploy.ts
8699
+ init_session();
8700
+
8428
8701
  // src/deploy/detach.ts
8429
8702
  init_detach();
8430
8703
  import * as fs5 from "fs";
@@ -8536,7 +8809,7 @@ var deployCommand = new Command5("deploy").description("Deploy the current app t
8536
8809
  if (opts.detach && !isChild) {
8537
8810
  const startedAt = new Date().toISOString();
8538
8811
  const handle = spawnDetachedDeploy(buildDeployChildArgs(process.argv), cwd);
8539
- writeDeployStatus(cwd, { state: "in-progress", startedAt, pid: handle.pid });
8812
+ writeDeployStatus(cwd, { state: "in-progress", startedAt, pid: handle.pid, bootTime: currentBootTime() });
8540
8813
  if (useJson) {
8541
8814
  jsonLine({ event: "deploy_started", detached: true, pid: handle.pid, logPath: deployLogPath(cwd), startedAt, hint: "Poll `runwork deploy --status` for completion." });
8542
8815
  } else {
@@ -8639,7 +8912,7 @@ var deployCommand = new Command5("deploy").description("Deploy the current app t
8639
8912
  const deployed = deploymentUrl.length > 0;
8640
8913
  if (!deployed) {
8641
8914
  if (useJson) {
8642
- jsonOut(buildErrorResponse("deploy", "Deployment did not produce a URL", "The deploy API returned no deployment URL. The deploy may have been a no-op (no changes) or failed server-side.", ["Confirm your changes were committed and pushed (the sync step above succeeded)", "Run runwork info to check the deployed state", "Run runwork logs --production to inspect server-side errors", "Retry runwork deploy"]));
8915
+ jsonOut(buildErrorResponse("deploy", "Deployment did not produce a URL", "The deploy API returned no deployment URL. The deploy may have been a no-op (no changes) or failed server-side (e.g. a build error).", ['Run `runwork logs --events --once` and look for a "Build failed" error in recent deployment events', "If a build failed on stale sandbox files, run `runwork dev --restart --detach` to resync, then retry the deploy", "Confirm your changes were committed and pushed (the sync step above succeeded)", "Run runwork info to check the deployed state", "Retry runwork deploy"]));
8643
8916
  process.exit(1);
8644
8917
  }
8645
8918
  console.error("Deploy did not return a URL. The deploy may have been a no-op or failed server-side.");
@@ -8679,14 +8952,24 @@ var deployCommand = new Command5("deploy").description("Deploy the current app t
8679
8952
  function printDeployStatus(cwd, useJson) {
8680
8953
  const status = readDeployStatus(cwd);
8681
8954
  const summary = getDeploySummary(cwd);
8955
+ const evaluated = status ? evaluateDeployStatus(status) : null;
8956
+ const staleHint = "The deploy process died before recording an outcome. The deploy may still have completed server-side (the push precedes the deploy call). Verify with `runwork logs --production --once` or `runwork apps info`, then re-run `runwork deploy` if needed.";
8682
8957
  if (useJson) {
8683
- jsonOut({ success: true, command: "deploy", result: { status, deploy: summary } });
8958
+ jsonOut({
8959
+ success: true,
8960
+ command: "deploy",
8961
+ result: {
8962
+ status: evaluated ? { ...evaluated.status, state: evaluated.effectiveState, staleReason: evaluated.staleReason } : null,
8963
+ deploy: summary,
8964
+ hint: evaluated?.effectiveState === "stale" ? staleHint : undefined
8965
+ }
8966
+ });
8684
8967
  return;
8685
8968
  }
8686
- if (!status) {
8969
+ if (!status || !evaluated) {
8687
8970
  console.log("No deploy has been started from this machine yet.");
8688
8971
  } else {
8689
- const label = status.state === "succeeded" ? green("succeeded") : status.state === "failed" ? yellow("failed") : "in-progress";
8972
+ const label = evaluated.effectiveState === "succeeded" ? green("succeeded") : evaluated.effectiveState === "failed" ? yellow("failed") : evaluated.effectiveState === "stale" ? yellow(`stale (${evaluated.staleReason})`) : "in-progress";
8690
8973
  console.log(`Last deploy: ${label}`);
8691
8974
  console.log(dim(` started: ${status.startedAt}`));
8692
8975
  if (status.finishedAt)
@@ -8695,8 +8978,10 @@ function printDeployStatus(cwd, useJson) {
8695
8978
  console.log(dim(` url: ${status.url}`));
8696
8979
  if (status.error)
8697
8980
  console.log(yellow(` error: ${status.error}`));
8698
- if (status.state === "in-progress")
8981
+ if (evaluated.effectiveState === "in-progress")
8699
8982
  console.log(dim(` logs: ${deployLogPath(cwd)}`));
8983
+ if (evaluated.effectiveState === "stale")
8984
+ console.log(yellow(` ${staleHint}`));
8700
8985
  }
8701
8986
  if (summary.deployedShortSha) {
8702
8987
  const sync = summary.inSync === true ? green("in sync") : summary.inSync === false ? yellow("local has undeployed commits") : dim("unknown");
@@ -9280,9 +9565,14 @@ import { readFileSync as readFileSync18, existsSync as existsSync21 } from "fs";
9280
9565
  init_store();
9281
9566
  init_prompt();
9282
9567
  import { existsSync as existsSync20, readFileSync as readFileSync17 } from "fs";
9568
+ var UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
9283
9569
  async function resolveWorkspace2(client, options = {}) {
9284
9570
  if (options.workspace) {
9285
- return { workspaceId: options.workspace, workspaceName: "", source: "flag" };
9571
+ if (UUID_RE.test(options.workspace)) {
9572
+ return { workspaceId: options.workspace, workspaceName: "", source: "flag" };
9573
+ }
9574
+ const ws2 = await resolveWorkspace(client, options.workspace);
9575
+ return { workspaceId: ws2.id, workspaceName: ws2.name, source: "flag" };
9286
9576
  }
9287
9577
  if (process.env.WORKSPACE_ID) {
9288
9578
  return { workspaceId: process.env.WORKSPACE_ID, workspaceName: "", source: "flag" };
@@ -9317,6 +9607,10 @@ async function resolveWorkspace2(client, options = {}) {
9317
9607
  saveDefaultWorkspace(ws2.id, ws2.name);
9318
9608
  return { workspaceId: ws2.id, workspaceName: ws2.name, source: "prompt" };
9319
9609
  }
9610
+ if (!process.stdout.isTTY) {
9611
+ console.error(`Workspace required. Pass --workspace <name-or-id>. Available: ${workspaces.map((w) => w.name).join(", ")}`);
9612
+ process.exit(1);
9613
+ }
9320
9614
  const choices = workspaces.map((ws2) => ({ label: ws2.name, value: ws2.id }));
9321
9615
  const chosen = await promptSelect("Select a workspace:", choices);
9322
9616
  const ws = workspaces.find((w) => w.id === chosen.value);
@@ -9545,7 +9839,13 @@ async function parseCurlToRequest(curlStr) {
9545
9839
  }
9546
9840
 
9547
9841
  // src/commands/integrations.ts
9548
- var searchCommand = new Command10("search").description("Search available integrations from the platform catalog").argument("<query>", 'Search query (e.g., "google drive", "hubspot", "slack")').option("--limit <n>", "Maximum results to show", "20").option("--workspace <id>", "Workspace ID (enables team usage info)").action(async (query, opts, command) => {
9842
+ function resolveIntegrationConnection(integrations, integration) {
9843
+ const match = integrations.find((i) => (i.canonicalId || i.integrationId) === integration || i.provider === integration);
9844
+ if (!match)
9845
+ return null;
9846
+ return { connectionId: match.id || match.integrationId, match };
9847
+ }
9848
+ var searchCommand = new Command10("search").description("Search available integrations from the platform catalog").argument("<query>", 'Search query (e.g., "google drive", "hubspot", "slack")').option("--limit <n>", "Maximum results to show", "20").option("--workspace <name-or-id>", "Workspace name or ID (enables team usage info)").action(async (query, opts, command) => {
9549
9849
  const useJson = shouldOutputJson(command.optsWithGlobals().json);
9550
9850
  const credentials = requireAuth();
9551
9851
  const client = new ApiClient(credentials);
@@ -9604,7 +9904,7 @@ Usage: Add the integration ID to APP_INTEGRATION_REQUIREMENTS in worker/integrat
9604
9904
  process.exit(1);
9605
9905
  }
9606
9906
  });
9607
- var listCommand = new Command10("list").description("List connected workspace integrations").option("--workspace <id>", "Workspace ID").action(async (opts, command) => {
9907
+ var listCommand = new Command10("list").description("List connected workspace integrations").option("--workspace <name-or-id>", "Workspace name or ID").action(async (opts, command) => {
9608
9908
  const useJson = shouldOutputJson(command.optsWithGlobals().json);
9609
9909
  const credentials = requireAuth();
9610
9910
  const client = new ApiClient(credentials);
@@ -9657,7 +9957,7 @@ Used by your team (${teamOnly.length} more):
9657
9957
  process.exit(1);
9658
9958
  }
9659
9959
  });
9660
- var callCommand = new Command10("call").description("Make a proxy call to a connected integration").argument("<integration>", "Integration name (e.g., hubspot, slack)").argument("[method]", "HTTP method (GET, POST, PUT, DELETE)").argument("[path]", "API path (e.g., /crm/v3/contacts)").option("--workspace <id>", "Workspace ID").option("--body <json>", "Request body JSON").option("--header <header>", "Request header (repeatable)", (val, prev) => [...prev, val], []).option("--query <query>", "Query string (e.g., limit=10&offset=0)").option("--curl <command>", 'Parse a curl command (paste from Chrome DevTools "Copy as cURL")').option("--curl-file <file>", "Read curl command from a file").action(async (integration, method, path2, opts, command) => {
9960
+ var callCommand = new Command10("call").description("Make a proxy call to a connected integration").argument("<integration>", "Integration name (e.g., hubspot, slack)").argument("[method]", "HTTP method (GET, POST, PUT, DELETE)").argument("[path]", "API path (e.g., /crm/v3/contacts)").option("--workspace <name-or-id>", "Workspace name or ID").option("--body <json>", "Request body JSON").option("--header <header>", "Request header (repeatable)", (val, prev) => [...prev, val], []).option("--query <query>", "Query string (e.g., limit=10&offset=0)").option("--curl <command>", 'Parse a curl command (paste from Chrome DevTools "Copy as cURL")').option("--curl-file <file>", "Read curl command from a file").action(async (integration, method, path2, opts, command) => {
9661
9961
  const useJson = shouldOutputJson(command.optsWithGlobals().json);
9662
9962
  const credentials = requireAuth();
9663
9963
  const client = new ApiClient(credentials);
@@ -9711,12 +10011,12 @@ var callCommand = new Command10("call").description("Make a proxy call to a conn
9711
10011
  }
9712
10012
  try {
9713
10013
  const integrations = await client.listConnectedIntegrations(workspaceId);
9714
- const match = integrations.find((i) => (i.canonicalId || i.integrationId) === integration || i.provider === integration);
9715
- if (!match) {
10014
+ const resolved = resolveIntegrationConnection(integrations, integration);
10015
+ if (!resolved) {
9716
10016
  console.error(`Integration "${integration}" not found. Run "runwork integrations list" to see connected integrations.`);
9717
10017
  process.exit(1);
9718
10018
  }
9719
- const result = await client.callIntegrationProxy(match.integrationId, finalMethod, finalPath, { body, headers: Object.keys(headers).length > 0 ? headers : undefined, query });
10019
+ const result = await client.callIntegrationProxy(resolved.connectionId, finalMethod, finalPath, { body, headers: Object.keys(headers).length > 0 ? headers : undefined, query });
9720
10020
  if (useJson) {
9721
10021
  jsonOut(result);
9722
10022
  return;
@@ -10345,7 +10645,7 @@ function truncate(text2, max) {
10345
10645
  return first;
10346
10646
  return first.slice(0, max - 3) + "...";
10347
10647
  }
10348
- var listCommand2 = new Command13("list").description("List workspace skills (app, external, MCP-generated)").option("--workspace <id>", "Workspace ID").action(async (opts, command) => {
10648
+ var listCommand2 = new Command13("list").description("List workspace skills (app, external, MCP-generated)").option("--workspace <name-or-id>", "Workspace name or ID").action(async (opts, command) => {
10349
10649
  const useJson = shouldOutputJson(command.optsWithGlobals().json);
10350
10650
  const credentials = requireAuth();
10351
10651
  const client = new ApiClient(credentials);
@@ -10402,7 +10702,7 @@ async function readStdin2() {
10402
10702
  }
10403
10703
  return Buffer.concat(chunks).toString("utf-8");
10404
10704
  }
10405
- var pushCommand = new Command13("push").description("Upload a local skill file to workspace (upsert by name). Accepts piped content via stdin.").argument("[first]", "Skill name (if piping content) or file path (name from frontmatter)").argument("[second]", "File path (when first arg is the skill name)").option("--workspace <id>", "Workspace ID").action(async (first, second, opts, command) => {
10705
+ var pushCommand = new Command13("push").description("Upload a local skill file to workspace (upsert by name). Accepts piped content via stdin.").argument("[first]", "Skill name (if piping content) or file path (name from frontmatter)").argument("[second]", "File path (when first arg is the skill name)").option("--workspace <name-or-id>", "Workspace name or ID").action(async (first, second, opts, command) => {
10406
10706
  const useJson = shouldOutputJson(command.optsWithGlobals().json);
10407
10707
  const credentials = requireAuth();
10408
10708
  const client = new ApiClient(credentials);
@@ -10497,7 +10797,7 @@ var pushCommand = new Command13("push").description("Upload a local skill file t
10497
10797
  process.exit(1);
10498
10798
  }
10499
10799
  });
10500
- var pullCommand = new Command13("pull").alias("download").description("Download a skill from the workspace and print to stdout (or save to file)").argument("<name>", "Skill name or ID").option("--workspace <id>", "Workspace ID").option("-o, --output <file>", "Save to file instead of stdout").action(async (nameOrId, opts, command) => {
10800
+ var pullCommand = new Command13("pull").alias("download").description("Download a skill from the workspace and print to stdout (or save to file)").argument("<name>", "Skill name or ID").option("--workspace <name-or-id>", "Workspace name or ID").option("-o, --output <file>", "Save to file instead of stdout").action(async (nameOrId, opts, command) => {
10501
10801
  const useJson = shouldOutputJson(command.optsWithGlobals().json);
10502
10802
  const credentials = requireAuth();
10503
10803
  const client = new ApiClient(credentials);
@@ -10600,7 +10900,7 @@ var searchCommand2 = new Command13("search").description("Search community skill
10600
10900
  process.exit(1);
10601
10901
  }
10602
10902
  });
10603
- var installCommand = new Command13("install").description("Install a community skill from skills.sh into your workspace").argument("<identifier>", "Skill identifier: source/skill-id (e.g. vercel-labs/skills/find-skills)").option("--workspace <id>", "Workspace ID").action(async (identifier, opts, command) => {
10903
+ var installCommand = new Command13("install").description("Install a community skill from skills.sh into your workspace").argument("<identifier>", "Skill identifier: source/skill-id (e.g. vercel-labs/skills/find-skills)").option("--workspace <name-or-id>", "Workspace name or ID").action(async (identifier, opts, command) => {
10604
10904
  const useJson = shouldOutputJson(command.optsWithGlobals().json);
10605
10905
  const credentials = requireAuth();
10606
10906
  const client = new ApiClient(credentials);
@@ -13517,14 +13817,15 @@ var AGENT_REGISTRY = [
13517
13817
  method: "any",
13518
13818
  target: [
13519
13819
  { method: "path", target: { macos: "/Applications/Codex.app" } },
13520
- { method: "windows-appx", target: "OpenAI.Codex" }
13820
+ { method: "macos-bundle-id", target: "com.openai.codex" },
13821
+ { method: "windows-appx", target: ["OpenAI.Codex"] }
13521
13822
  ]
13522
13823
  },
13523
- launch: { app: { macos: "Codex", windows: "Codex" } },
13824
+ launch: { app: { macos: "Codex", windows: "Codex" }, bundleId: { macos: "com.openai.codex" } },
13524
13825
  logo: "codex",
13525
13826
  downloadUrl: "https://openai.com/codex/",
13526
13827
  skillsPaths: { global: ".codex/skills", project: ".agents/skills" },
13527
- instructionFile: { global: ".codex/instructions.md", project: "AGENTS.md" },
13828
+ instructionFile: { global: ".codex/AGENTS.md", project: "AGENTS.md" },
13528
13829
  firstClass: true,
13529
13830
  resumeCapability: {
13530
13831
  mode: "file-drop-only",
@@ -13549,7 +13850,7 @@ var AGENT_REGISTRY = [
13549
13850
  logo: "codex",
13550
13851
  downloadUrl: "https://github.com/openai/codex",
13551
13852
  skillsPaths: { global: ".codex/skills", project: ".agents/skills" },
13552
- instructionFile: { global: ".codex/instructions.md", project: "AGENTS.md" },
13853
+ instructionFile: { global: ".codex/AGENTS.md", project: "AGENTS.md" },
13553
13854
  firstClass: true,
13554
13855
  resumeCapability: {
13555
13856
  mode: "cli-resume",
@@ -13643,10 +13944,11 @@ var AGENT_REGISTRY = [
13643
13944
  method: "any",
13644
13945
  target: [
13645
13946
  { method: "path", target: { macos: "/Applications/ChatGPT.app" } },
13646
- { method: "windows-appx", target: "OpenAI.ChatGPT" }
13947
+ { method: "macos-bundle-id", target: "com.openai.chat" },
13948
+ { method: "windows-appx", target: ["OpenAI.ChatGPT"] }
13647
13949
  ]
13648
13950
  },
13649
- launch: { app: { macos: "ChatGPT", windows: "ChatGPT" }, url: "https://chatgpt.com/?prompt={prompt}" },
13951
+ launch: { app: { macos: "ChatGPT", windows: "ChatGPT" }, bundleId: { macos: "com.openai.chat" }, url: "https://chatgpt.com/?prompt={prompt}" },
13650
13952
  logo: "openai",
13651
13953
  downloadUrl: "https://chatgpt.com/download",
13652
13954
  firstClass: true,
@@ -13936,14 +14238,28 @@ function resolveToAbsolute(ps, scope) {
13936
14238
  return scope === "global" ? join26(homedir9(), resolved) : join26(process.cwd(), resolved);
13937
14239
  }
13938
14240
 
14241
+ // src/agents/detection-probes.ts
14242
+ function powershellQuote(value) {
14243
+ return `'${value.replace(/'/g, "''")}'`;
14244
+ }
14245
+ function isValidBundleId(id) {
14246
+ return /^[A-Za-z0-9][A-Za-z0-9.-]*$/.test(id);
14247
+ }
14248
+ function macosBundleIdProbeScript(id) {
14249
+ return `p=$(mdfind "kMDItemCFBundleIdentifier == '${id}'" 2>/dev/null | head -1); ` + `if [ -n "$p" ]; then exit 0; fi; ` + `for a in /Applications/*.app "$HOME"/Applications/*.app; do ` + `[ -e "$a" ] || continue; ` + `if [ "$(/usr/libexec/PlistBuddy -c 'Print :CFBundleIdentifier' "$a/Contents/Info.plist" 2>/dev/null)" = "${id}" ]; then exit 0; fi; ` + `done; exit 1`;
14250
+ }
14251
+ function appxPackageProbeScript(pkg) {
14252
+ return `$p = Get-AppxPackage -Name ${powershellQuote(pkg)} -ErrorAction SilentlyContinue; if ($null -ne $p) { exit 0 } exit 1`;
14253
+ }
14254
+ function startAppProbeScript(pattern) {
14255
+ return `$a = Get-StartApps -Name ${powershellQuote(pattern)} -ErrorAction SilentlyContinue | Select-Object -First 1; if ($null -ne $a) { exit 0 } exit 1`;
14256
+ }
14257
+
13939
14258
  // src/agents/detection.ts
13940
14259
  var execFileAsync = promisify(execFile);
13941
14260
  function isWindows() {
13942
14261
  return platform7() === "win32";
13943
14262
  }
13944
- function powershellQuote(value) {
13945
- return `'${value.replace(/'/g, "''")}'`;
13946
- }
13947
14263
  function toList(value) {
13948
14264
  return Array.isArray(value) ? value : [value];
13949
14265
  }
@@ -13963,23 +14279,30 @@ function checkPath(target) {
13963
14279
  return existsSync32(resolved);
13964
14280
  return existsSync32(join27(homedir10(), resolved));
13965
14281
  }
14282
+ async function checkMacosBundleId(target) {
14283
+ if (platform7() !== "darwin")
14284
+ return false;
14285
+ for (const id of toList(target)) {
14286
+ if (!isValidBundleId(id))
14287
+ continue;
14288
+ try {
14289
+ await execFileAsync("sh", ["-c", macosBundleIdProbeScript(id)]);
14290
+ return true;
14291
+ } catch {}
14292
+ }
14293
+ return false;
14294
+ }
13966
14295
  async function checkWindowsAppxPackage(target) {
13967
14296
  if (!isWindows())
13968
14297
  return false;
13969
- const probes = toList(target).map((pkg) => {
13970
- const script = `$p = Get-AppxPackage -Name ${powershellQuote(pkg)} -ErrorAction SilentlyContinue; if ($null -ne $p) { exit 0 } exit 1`;
13971
- return runPowerShell(script);
13972
- });
14298
+ const probes = toList(target).map((pkg) => runPowerShell(appxPackageProbeScript(pkg)));
13973
14299
  const results = await Promise.all(probes);
13974
14300
  return results.some(Boolean);
13975
14301
  }
13976
14302
  async function checkWindowsStartApp(target) {
13977
14303
  if (!isWindows())
13978
14304
  return false;
13979
- const probes = toList(target).map((pattern) => {
13980
- const script = `$a = Get-StartApps -Name ${powershellQuote(pattern)} -ErrorAction SilentlyContinue | Select-Object -First 1; if ($null -ne $a) { exit 0 } exit 1`;
13981
- return runPowerShell(script);
13982
- });
14305
+ const probes = toList(target).map((pattern) => runPowerShell(startAppProbeScript(pattern)));
13983
14306
  const results = await Promise.all(probes);
13984
14307
  return results.some(Boolean);
13985
14308
  }
@@ -13995,6 +14318,8 @@ async function runAgentDetection(detection) {
13995
14318
  return checkWindowsAppxPackage(detection.target);
13996
14319
  case "windows-start-app":
13997
14320
  return checkWindowsStartApp(detection.target);
14321
+ case "macos-bundle-id":
14322
+ return checkMacosBundleId(detection.target);
13998
14323
  case "any": {
13999
14324
  const probes = await Promise.all(detection.target.map((p) => runAgentDetection(p)));
14000
14325
  return probes.some(Boolean);
@@ -14106,6 +14431,26 @@ class CodexAdapter {
14106
14431
  }
14107
14432
  }
14108
14433
  }
14434
+ if (config.networkAllowlist?.length) {
14435
+ const features = parsed.features && typeof parsed.features === "object" ? parsed.features : undefined;
14436
+ const proxy = features?.network_proxy;
14437
+ if (proxy && proxy.enabled === true) {
14438
+ if (!proxy.domains || typeof proxy.domains !== "object")
14439
+ proxy.domains = {};
14440
+ const domains = proxy.domains;
14441
+ for (const host of config.networkAllowlist) {
14442
+ if (!(host in domains))
14443
+ domains[host] = "allow";
14444
+ }
14445
+ } else {
14446
+ if (!parsed.sandbox_workspace_write || typeof parsed.sandbox_workspace_write !== "object") {
14447
+ parsed.sandbox_workspace_write = {};
14448
+ }
14449
+ const sww = parsed.sandbox_workspace_write;
14450
+ if (sww.network_access === undefined)
14451
+ sww.network_access = true;
14452
+ }
14453
+ }
14109
14454
  mkdirSync20(join28(configPath, ".."), { recursive: true });
14110
14455
  writeFileSync21(configPath, stringify(parsed));
14111
14456
  }
@@ -15412,7 +15757,7 @@ function parseJson(content, source) {
15412
15757
  }
15413
15758
 
15414
15759
  // src/commands/entities.ts
15415
- var listCommand3 = new Command15("list").description("List entities registered in the workspace").option("--workspace <id>", "Workspace ID").option("--app <id>", "Filter by app name or ID").option("--preview", "Show preview-mode entities only").action(async (opts, command) => {
15760
+ var listCommand3 = new Command15("list").description("List entities registered in the workspace").option("--workspace <name-or-id>", "Workspace name or ID").option("--app <id>", "Filter by app name or ID").option("--preview", "Show preview-mode entities only").action(async (opts, command) => {
15416
15761
  const useJson = shouldOutputJson(command.optsWithGlobals().json);
15417
15762
  const credentials = requireAuth();
15418
15763
  const client = new ApiClient(credentials);
@@ -15447,7 +15792,7 @@ Workspace: ${workspaceName || workspaceId}
15447
15792
  process.exit(1);
15448
15793
  }
15449
15794
  });
15450
- var recordsCommand = new Command15("records").description("List records for an entity").argument("<entity>", "Entity name").option("--workspace <id>", "Workspace ID").option("--limit <n>", "Number of records to return", "20").option("--cursor <cursor>", "Pagination cursor").option("--preview", "Query preview-mode data").action(async (entity, opts, command) => {
15795
+ var recordsCommand = new Command15("records").description("List records for an entity").argument("<entity>", "Entity name").option("--workspace <name-or-id>", "Workspace name or ID").option("--limit <n>", "Number of records to return", "20").option("--cursor <cursor>", "Pagination cursor").option("--preview", "Query preview-mode data").action(async (entity, opts, command) => {
15451
15796
  const useJson = shouldOutputJson(command.optsWithGlobals().json);
15452
15797
  const credentials = requireAuth();
15453
15798
  const client = new ApiClient(credentials);
@@ -15479,7 +15824,7 @@ Next cursor: ${result.next}`);
15479
15824
  process.exit(1);
15480
15825
  }
15481
15826
  });
15482
- var getCommand = new Command15("get").description("Get a single entity record by ID").argument("<entity>", "Entity name").argument("<id>", "Record ID").option("--workspace <id>", "Workspace ID").action(async (entity, id, opts, command) => {
15827
+ var getCommand = new Command15("get").description("Get a single entity record by ID").argument("<entity>", "Entity name").argument("<id>", "Record ID").option("--workspace <name-or-id>", "Workspace name or ID").action(async (entity, id, opts, command) => {
15483
15828
  const useJson = shouldOutputJson(command.optsWithGlobals().json);
15484
15829
  const credentials = requireAuth();
15485
15830
  const client = new ApiClient(credentials);
@@ -15496,7 +15841,7 @@ var getCommand = new Command15("get").description("Get a single entity record by
15496
15841
  process.exit(1);
15497
15842
  }
15498
15843
  });
15499
- var createCommand = new Command15("create").description("Create a new entity record").argument("<entity>", "Entity name").option("--workspace <id>", "Workspace ID").option("--data <json>", "Record data as JSON string, @file.json, or pipe via stdin").option("--preview", "Create in preview-mode data store").action(async (entity, opts, command) => {
15844
+ var createCommand = new Command15("create").description("Create a new entity record").argument("<entity>", "Entity name").option("--workspace <name-or-id>", "Workspace name or ID").option("--data <json>", "Record data as JSON string, @file.json, or pipe via stdin").option("--preview", "Create in preview-mode data store").action(async (entity, opts, command) => {
15500
15845
  const useJson = shouldOutputJson(command.optsWithGlobals().json);
15501
15846
  const credentials = requireAuth();
15502
15847
  const client = new ApiClient(credentials);
@@ -15515,7 +15860,7 @@ var createCommand = new Command15("create").description("Create a new entity rec
15515
15860
  process.exit(1);
15516
15861
  }
15517
15862
  });
15518
- var updateCommand = new Command15("update").description("Update an existing entity record").argument("<entity>", "Entity name").argument("<id>", "Record ID").option("--workspace <id>", "Workspace ID").option("--data <json>", "Record data as JSON string, @file.json, or pipe via stdin").action(async (entity, id, opts, command) => {
15863
+ var updateCommand = new Command15("update").description("Update an existing entity record").argument("<entity>", "Entity name").argument("<id>", "Record ID").option("--workspace <name-or-id>", "Workspace name or ID").option("--data <json>", "Record data as JSON string, @file.json, or pipe via stdin").action(async (entity, id, opts, command) => {
15519
15864
  const useJson = shouldOutputJson(command.optsWithGlobals().json);
15520
15865
  const credentials = requireAuth();
15521
15866
  const client = new ApiClient(credentials);
@@ -15534,7 +15879,7 @@ var updateCommand = new Command15("update").description("Update an existing enti
15534
15879
  process.exit(1);
15535
15880
  }
15536
15881
  });
15537
- var deleteCommand = new Command15("delete").description("Delete an entity record").argument("<entity>", "Entity name").argument("<id>", "Record ID").option("--workspace <id>", "Workspace ID").option("--yes", "Skip confirmation prompt").action(async (entity, id, opts, command) => {
15882
+ var deleteCommand = new Command15("delete").description("Delete an entity record").argument("<entity>", "Entity name").argument("<id>", "Record ID").option("--workspace <name-or-id>", "Workspace name or ID").option("--yes", "Skip confirmation prompt").action(async (entity, id, opts, command) => {
15538
15883
  const useJson = shouldOutputJson(command.optsWithGlobals().json);
15539
15884
  const credentials = requireAuth();
15540
15885
  const client = new ApiClient(credentials);
@@ -15573,7 +15918,7 @@ function truncate2(text2, max) {
15573
15918
  return first;
15574
15919
  return first.slice(0, max - 3) + "...";
15575
15920
  }
15576
- var listCommand4 = new Command16("list").description("List workflows in a workspace").option("--workspace <id>", "Workspace ID").option("--app <name>", "Filter by app name or ID").action(async (opts, command) => {
15921
+ var listCommand4 = new Command16("list").description("List workflows in a workspace").option("--workspace <name-or-id>", "Workspace name or ID").option("--app <name>", "Filter by app name or ID").action(async (opts, command) => {
15577
15922
  const useJson = shouldOutputJson(command.optsWithGlobals().json);
15578
15923
  const credentials = requireAuth();
15579
15924
  const client = new ApiClient(credentials);
@@ -15607,7 +15952,7 @@ Workspace: ${workspaceName || workspaceId}
15607
15952
  process.exit(1);
15608
15953
  }
15609
15954
  });
15610
- var triggerCommand = new Command16("trigger").description("Trigger a workflow by name").argument("<name>", "Workflow name").option("--workspace <id>", "Workspace ID").option("--app <name>", "App name or ID (required if not in a project directory)").option("--params <json>", "JSON string of parameters to pass to the workflow").option("--instance-id <id>", "Custom instance ID for the workflow run").action(async (name, opts, command) => {
15955
+ var triggerCommand = new Command16("trigger").description("Trigger a workflow by name").argument("<name>", "Workflow name").option("--workspace <name-or-id>", "Workspace name or ID").option("--app <name>", "App name or ID (required if not in a project directory)").option("--params <json>", "JSON string of parameters to pass to the workflow").option("--instance-id <id>", "Custom instance ID for the workflow run").action(async (name, opts, command) => {
15611
15956
  const useJson = shouldOutputJson(command.optsWithGlobals().json);
15612
15957
  const credentials = requireAuth();
15613
15958
  const client = new ApiClient(credentials);
@@ -15641,7 +15986,7 @@ var triggerCommand = new Command16("trigger").description("Trigger a workflow by
15641
15986
  process.exit(1);
15642
15987
  }
15643
15988
  });
15644
- var instancesCommand = new Command16("instances").description("List workflow instances for an app").option("--workspace <id>", "Workspace ID").option("--app <name>", "App name or ID (required if not in a project directory)").option("--workflow <name>", "Filter by workflow name").option("--status <status>", "Filter by instance status").option("--limit <n>", "Maximum number of instances to return").action(async (opts, command) => {
15989
+ var instancesCommand = new Command16("instances").description("List workflow instances for an app").option("--workspace <name-or-id>", "Workspace name or ID").option("--app <name>", "App name or ID (required if not in a project directory)").option("--workflow <name>", "Filter by workflow name").option("--status <status>", "Filter by instance status").option("--limit <n>", "Maximum number of instances to return").action(async (opts, command) => {
15645
15990
  const useJson = shouldOutputJson(command.optsWithGlobals().json);
15646
15991
  const credentials = requireAuth();
15647
15992
  const client = new ApiClient(credentials);
@@ -15674,7 +16019,7 @@ var instancesCommand = new Command16("instances").description("List workflow ins
15674
16019
  process.exit(1);
15675
16020
  }
15676
16021
  });
15677
- var instanceCommand = new Command16("instance").description("Get details for a specific workflow instance").argument("<id>", "Workflow instance ID").option("--workspace <id>", "Workspace ID").option("--app <name>", "App name or ID (optional)").action(async (id, opts, command) => {
16022
+ var instanceCommand = new Command16("instance").description("Get details for a specific workflow instance").argument("<id>", "Workflow instance ID").option("--workspace <name-or-id>", "Workspace name or ID").option("--app <name>", "App name or ID (optional)").action(async (id, opts, command) => {
15678
16023
  const useJson = shouldOutputJson(command.optsWithGlobals().json);
15679
16024
  const credentials = requireAuth();
15680
16025
  const client = new ApiClient(credentials);
@@ -15702,16 +16047,64 @@ var workflowsCommand = new Command16("workflows").description("Manage workspace
15702
16047
  init_store();
15703
16048
  init_client();
15704
16049
  import { Command as Command17 } from "commander";
15705
- function truncate3(text2, max) {
15706
- if (!text2)
16050
+ // src/utils/table.ts
16051
+ function clip(value, max) {
16052
+ if (max <= 0)
15707
16053
  return "";
15708
- const first = text2.split(`
15709
- `)[0];
15710
- if (first.length <= max)
15711
- return first;
15712
- return first.slice(0, max - 3) + "...";
16054
+ if (value.length <= max)
16055
+ return value;
16056
+ if (max <= 3)
16057
+ return value.slice(0, max);
16058
+ return value.slice(0, max - 3) + "...";
16059
+ }
16060
+ function renderTable(columns, rows, indent = " ") {
16061
+ const gap = " ";
16062
+ const lastIdx = columns.length - 1;
16063
+ const data = rows.map((row) => columns.map((c, i) => {
16064
+ const raw = row[i] == null ? "" : String(row[i]);
16065
+ return c.max !== undefined ? clip(raw, c.max) : raw;
16066
+ }));
16067
+ const widths = columns.map((c, i) => {
16068
+ let w = c.header.length;
16069
+ for (const row of data)
16070
+ w = Math.max(w, row[i].length);
16071
+ return w;
16072
+ });
16073
+ const renderRow = (cells, colorize) => {
16074
+ const parts = cells.map((cell, i) => {
16075
+ const padded = i === lastIdx ? cell : cell.padEnd(widths[i]);
16076
+ const color = columns[i].color;
16077
+ return colorize && color ? color(padded) : padded;
16078
+ });
16079
+ return (indent + parts.join(gap)).replace(/\s+$/, "");
16080
+ };
16081
+ const out = [renderRow(columns.map((c) => c.header), false)];
16082
+ const total = widths.reduce((a, b) => a + b, 0) + gap.length * Math.max(0, columns.length - 1);
16083
+ out.push(indent + "-".repeat(total));
16084
+ for (const row of data)
16085
+ out.push(renderRow(row, true));
16086
+ return out.join(`
16087
+ `);
16088
+ }
16089
+
16090
+ // src/commands/schedules.ts
16091
+ function extractScheduleHistoryRecords(data) {
16092
+ if (!data || !Array.isArray(data.records))
16093
+ return [];
16094
+ return data.records;
16095
+ }
16096
+ function scheduleRowCells(s) {
16097
+ const mode = s.deploymentMode ? ` (${s.deploymentMode})` : "";
16098
+ const status = s.status ? s.status + mode : mode.trim() || "-";
16099
+ return [
16100
+ s.scheduleName || "(unnamed)",
16101
+ s.appName || s.appId || "-",
16102
+ s.schedule || "-",
16103
+ status,
16104
+ s.description || ""
16105
+ ];
15713
16106
  }
15714
- var listCommand5 = new Command17("list").description("List scheduled jobs in the workspace").option("--workspace <id>", "Workspace ID").option("--app <name|id>", "Filter by app name or ID").action(async (opts, command) => {
16107
+ var listCommand5 = new Command17("list").description("List scheduled jobs in the workspace").option("--workspace <name-or-id>", "Workspace name or ID").option("--app <name|id>", "Filter by app name or ID").action(async (opts, command) => {
15715
16108
  const useJson = shouldOutputJson(command.optsWithGlobals().json);
15716
16109
  const credentials = requireAuth();
15717
16110
  const client = new ApiClient(credentials);
@@ -15733,20 +16126,20 @@ var listCommand5 = new Command17("list").description("List scheduled jobs in the
15733
16126
  console.log(`
15734
16127
  Workspace: ${workspaceName || workspaceId}
15735
16128
  `);
15736
- console.log(" " + "Name".padEnd(24) + "App".padEnd(20) + "Schedule".padEnd(18) + "Status".padEnd(12) + "Description");
15737
- console.log(" " + "-".repeat(90));
15738
- for (const s of schedules) {
15739
- const mode = s.deploymentMode ? ` (${s.deploymentMode})` : "";
15740
- const status = s.status ? s.status + mode : mode.trim() || "-";
15741
- console.log(" " + s.name.padEnd(24) + (s.appName || s.appId).slice(0, 18).padEnd(20) + (s.schedule || "-").padEnd(18) + status.padEnd(12) + truncate3(s.description, 40));
15742
- }
16129
+ console.log(renderTable([
16130
+ { header: "Name" },
16131
+ { header: "App" },
16132
+ { header: "Schedule" },
16133
+ { header: "Status" },
16134
+ { header: "Description", max: 60 }
16135
+ ], schedules.map(scheduleRowCells)));
15743
16136
  console.log("");
15744
16137
  } catch (err) {
15745
16138
  console.error("Failed to list schedules:", err instanceof Error ? err.message : err);
15746
16139
  process.exit(1);
15747
16140
  }
15748
16141
  });
15749
- var triggerCommand2 = new Command17("trigger").description("Manually trigger a scheduled job").argument("<name>", "Schedule name").option("--workspace <id>", "Workspace ID").option("--app <name|id>", "App name or ID").option("--preview", "Trigger in preview (sandbox) mode instead of production").action(async (name, opts, command) => {
16142
+ var triggerCommand2 = new Command17("trigger").description("Manually trigger a scheduled job").argument("<name>", "Schedule name").option("--workspace <name-or-id>", "Workspace name or ID").option("--app <name|id>", "App name or ID").option("--preview", "Trigger in preview (sandbox) mode instead of production").action(async (name, opts, command) => {
15750
16143
  const useJson = shouldOutputJson(command.optsWithGlobals().json);
15751
16144
  const credentials = requireAuth();
15752
16145
  const client = new ApiClient(credentials);
@@ -15772,7 +16165,7 @@ var triggerCommand2 = new Command17("trigger").description("Manually trigger a s
15772
16165
  process.exit(1);
15773
16166
  }
15774
16167
  });
15775
- var historyCommand = new Command17("history").description("Show execution history for scheduled jobs in an app").option("--workspace <id>", "Workspace ID").option("--app <name|id>", "App name or ID (required)").action(async (opts, command) => {
16168
+ var historyCommand = new Command17("history").description("Show execution history for scheduled jobs in an app").option("--workspace <name-or-id>", "Workspace name or ID").option("--app <name|id>", "App name or ID (required)").action(async (opts, command) => {
15776
16169
  const useJson = shouldOutputJson(command.optsWithGlobals().json);
15777
16170
  const credentials = requireAuth();
15778
16171
  const client = new ApiClient(credentials);
@@ -15780,25 +16173,34 @@ var historyCommand = new Command17("history").description("Show execution histor
15780
16173
  const { appId, appName } = await resolveApp2(client, workspaceId, opts);
15781
16174
  try {
15782
16175
  const data = await client.getScheduleHistory(workspaceId, appId);
16176
+ const records = extractScheduleHistoryRecords(data);
15783
16177
  if (useJson) {
15784
- jsonOut({ history: data.history, appId, appName });
16178
+ jsonOut({ history: records, appId, appName });
15785
16179
  return;
15786
16180
  }
15787
- if (!data.history || data.history.length === 0) {
16181
+ if (records.length === 0) {
15788
16182
  console.log(`No schedule history found for app "${appName}".`);
15789
16183
  return;
15790
16184
  }
15791
16185
  console.log(`
15792
16186
  Schedule history for app: ${appName}
15793
16187
  `);
15794
- console.log(" " + "Schedule".padEnd(24) + "Executed At".padEnd(26) + "Status".padEnd(12) + "Duration");
15795
- console.log(" " + "-".repeat(72));
15796
- for (const entry of data.history) {
16188
+ const nameW = Math.max("Schedule".length, ...records.map((r) => (r.jobName || "-").length));
16189
+ console.log(" " + "Schedule".padEnd(nameW + 2) + "Started At".padEnd(26) + "Status".padEnd(12) + "Duration");
16190
+ console.log(" " + "-".repeat(nameW + 2 + 26 + 12 + 8));
16191
+ for (const entry of records) {
16192
+ const startedAt = entry.startedAt ? new Date(entry.startedAt).toISOString() : "-";
15797
16193
  const duration = entry.durationMs != null ? `${entry.durationMs}ms` : "-";
15798
- console.log(" " + entry.scheduleName.padEnd(24) + entry.executedAt.padEnd(26) + entry.status.padEnd(12) + duration);
16194
+ console.log(" " + (entry.jobName || "-").padEnd(nameW + 2) + startedAt.padEnd(26) + entry.status.padEnd(12) + duration);
15799
16195
  if (entry.error) {
15800
16196
  console.log(` Error: ${entry.error}`);
15801
16197
  }
16198
+ if (entry.errorStack) {
16199
+ for (const line of entry.errorStack.split(`
16200
+ `).slice(0, 8)) {
16201
+ console.log(` ${line.trim()}`);
16202
+ }
16203
+ }
15802
16204
  }
15803
16205
  console.log("");
15804
16206
  } catch (err) {
@@ -15806,7 +16208,7 @@ Schedule history for app: ${appName}
15806
16208
  process.exit(1);
15807
16209
  }
15808
16210
  });
15809
- var statusCommand = new Command17("status").description("Show runtime status of scheduled jobs for an app").argument("<name>", "Schedule name").option("--workspace <id>", "Workspace ID").option("--app <name|id>", "App name or ID (required)").action(async (name, opts, command) => {
16211
+ var statusCommand = new Command17("status").description("Show runtime status of scheduled jobs for an app").argument("<name>", "Schedule name").option("--workspace <name-or-id>", "Workspace name or ID").option("--app <name|id>", "App name or ID (required)").action(async (name, opts, command) => {
15810
16212
  const useJson = shouldOutputJson(command.optsWithGlobals().json);
15811
16213
  const credentials = requireAuth();
15812
16214
  const client = new ApiClient(credentials);
@@ -15828,7 +16230,7 @@ Schedule "${name}" status for app "${appName}":
15828
16230
  process.exit(1);
15829
16231
  }
15830
16232
  });
15831
- var pauseCommand = new Command17("pause").description("Pause a scheduled job").argument("<name>", "Schedule name").option("--workspace <id>", "Workspace ID").option("--app <name|id>", "App name or ID (required)").action(async (name, opts, command) => {
16233
+ var pauseCommand = new Command17("pause").description("Pause a scheduled job").argument("<name>", "Schedule name").option("--workspace <name-or-id>", "Workspace name or ID").option("--app <name|id>", "App name or ID (required)").action(async (name, opts, command) => {
15832
16234
  const useJson = shouldOutputJson(command.optsWithGlobals().json);
15833
16235
  const credentials = requireAuth();
15834
16236
  const client = new ApiClient(credentials);
@@ -15846,7 +16248,7 @@ var pauseCommand = new Command17("pause").description("Pause a scheduled job").a
15846
16248
  process.exit(1);
15847
16249
  }
15848
16250
  });
15849
- var resumeCommand = new Command17("resume").description("Resume a paused scheduled job").argument("<name>", "Schedule name").option("--workspace <id>", "Workspace ID").option("--app <name|id>", "App name or ID (required)").action(async (name, opts, command) => {
16251
+ var resumeCommand = new Command17("resume").description("Resume a paused scheduled job").argument("<name>", "Schedule name").option("--workspace <name-or-id>", "Workspace name or ID").option("--app <name|id>", "App name or ID (required)").action(async (name, opts, command) => {
15850
16252
  const useJson = shouldOutputJson(command.optsWithGlobals().json);
15851
16253
  const credentials = requireAuth();
15852
16254
  const client = new ApiClient(credentials);
@@ -15871,7 +16273,7 @@ init_store();
15871
16273
  init_client();
15872
16274
  import { Command as Command18 } from "commander";
15873
16275
  init_http();
15874
- function truncate4(text2, max) {
16276
+ function truncate3(text2, max) {
15875
16277
  if (!text2)
15876
16278
  return "";
15877
16279
  const first = text2.split(`
@@ -15880,7 +16282,7 @@ function truncate4(text2, max) {
15880
16282
  return first;
15881
16283
  return first.slice(0, max - 3) + "...";
15882
16284
  }
15883
- var listCommand6 = new Command18("list").description("List workspace public endpoints").option("--workspace <id>", "Workspace ID").option("--app <name>", "Filter by app name or ID").action(async (opts, command) => {
16285
+ var listCommand6 = new Command18("list").description("List workspace public endpoints").option("--workspace <name-or-id>", "Workspace name or ID").option("--app <name>", "Filter by app name or ID").action(async (opts, command) => {
15884
16286
  const useJson = shouldOutputJson(command.optsWithGlobals().json);
15885
16287
  const credentials = requireAuth();
15886
16288
  const client = new ApiClient(credentials);
@@ -15908,7 +16310,7 @@ Workspace: ${workspaceName || workspaceId}
15908
16310
  const path2 = e.endpointPath.padEnd(36);
15909
16311
  const app = (e.appName || e.appId).padEnd(20);
15910
16312
  const auth = (e.auth || "").padEnd(10);
15911
- const desc = truncate4(e.description, 40);
16313
+ const desc = truncate3(e.description, 40);
15912
16314
  const mode = e.deploymentMode ? ` [${e.deploymentMode}]` : "";
15913
16315
  console.log(` ${method} ${path2} ${app} ${auth} ${desc}${mode}`);
15914
16316
  }
@@ -15918,7 +16320,7 @@ Workspace: ${workspaceName || workspaceId}
15918
16320
  process.exit(1);
15919
16321
  }
15920
16322
  });
15921
- var callCommand2 = new Command18("call").description("Call a workspace endpoint directly").argument("<method>", "HTTP method (GET, POST, PUT, DELETE, etc.)").argument("<path>", "Endpoint path (e.g. /my-endpoint)").option("--workspace <id>", "Workspace ID").option("--app <name>", "App name or ID (narrows endpoint lookup)").option("--body <json>", "Request body as JSON string").option("--header <header>", 'Request header (format: "Key: Value", repeatable)', (val, prev) => [...prev, val], []).option("--query <string>", 'Query string to append to the URL (e.g. "foo=bar&baz=1")').option("--api-key <key>", "API key for Authorization: Bearer header").action(async (method, path2, opts, command) => {
16323
+ var callCommand2 = new Command18("call").description("Call a workspace endpoint directly").argument("<method>", "HTTP method (GET, POST, PUT, DELETE, etc.)").argument("<path>", "Endpoint path (e.g. /my-endpoint)").option("--workspace <name-or-id>", "Workspace name or ID").option("--app <name>", "App name or ID (narrows endpoint lookup)").option("--body <json>", "Request body as JSON string").option("--header <header>", 'Request header (format: "Key: Value", repeatable)', (val, prev) => [...prev, val], []).option("--query <string>", 'Query string to append to the URL (e.g. "foo=bar&baz=1")').option("--api-key <key>", "API key for Authorization: Bearer header").action(async (method, path2, opts, command) => {
15922
16324
  const useJson = shouldOutputJson(command.optsWithGlobals().json);
15923
16325
  const credentials = requireAuth();
15924
16326
  const client = new ApiClient(credentials);
@@ -16049,7 +16451,7 @@ function formatSize(bytes) {
16049
16451
  return `${(bytes / (1024 * 1024)).toFixed(1)}MB`;
16050
16452
  return `${(bytes / (1024 * 1024 * 1024)).toFixed(1)}GB`;
16051
16453
  }
16052
- var listCommand7 = new Command19("list").description("List file storage buckets in the workspace").option("--workspace <id>", "Workspace ID").action(async (opts, command) => {
16454
+ var listCommand7 = new Command19("list").description("List file storage buckets in the workspace").option("--workspace <name-or-id>", "Workspace name or ID").action(async (opts, command) => {
16053
16455
  const useJson = shouldOutputJson(command.optsWithGlobals().json);
16054
16456
  const credentials = requireAuth();
16055
16457
  const client = new ApiClient(credentials);
@@ -16079,7 +16481,7 @@ Workspace: ${workspaceName || workspaceId}
16079
16481
  process.exit(1);
16080
16482
  }
16081
16483
  });
16082
- var lsCommand = new Command19("ls").description("List files in a bucket").argument("<bucket>", "Bucket name").argument("[prefix]", "Key prefix to filter by").option("--workspace <id>", "Workspace ID").option("--delimiter <char>", "Delimiter for hierarchical listing", "/").action(async (bucket, prefix, opts, command) => {
16484
+ var lsCommand = new Command19("ls").description("List files in a bucket").argument("<bucket>", "Bucket name").argument("[prefix]", "Key prefix to filter by").option("--workspace <name-or-id>", "Workspace name or ID").option("--delimiter <char>", "Delimiter for hierarchical listing", "/").action(async (bucket, prefix, opts, command) => {
16083
16485
  const useJson = shouldOutputJson(command.optsWithGlobals().json);
16084
16486
  const credentials = requireAuth();
16085
16487
  const client = new ApiClient(credentials);
@@ -16116,7 +16518,7 @@ var lsCommand = new Command19("ls").description("List files in a bucket").argume
16116
16518
  process.exit(1);
16117
16519
  }
16118
16520
  });
16119
- var downloadCommand = new Command19("download").description("Download a file from a bucket").argument("<bucket>", "Bucket name").argument("<key>", "Object key to download").argument("[output]", "Local output path (defaults to basename of key)").option("--workspace <id>", "Workspace ID").action(async (bucket, key, output, opts, command) => {
16521
+ var downloadCommand = new Command19("download").description("Download a file from a bucket").argument("<bucket>", "Bucket name").argument("<key>", "Object key to download").argument("[output]", "Local output path (defaults to basename of key)").option("--workspace <name-or-id>", "Workspace name or ID").action(async (bucket, key, output, opts, command) => {
16120
16522
  const useJson = shouldOutputJson(command.optsWithGlobals().json);
16121
16523
  const credentials = requireAuth();
16122
16524
  const client = new ApiClient(credentials);
@@ -16139,7 +16541,7 @@ var downloadCommand = new Command19("download").description("Download a file fro
16139
16541
  process.exit(1);
16140
16542
  }
16141
16543
  });
16142
- var uploadCommand = new Command19("upload").description("Upload a local file to a bucket").argument("<bucket>", "Bucket name").argument("<localPath>", "Local file path to upload").argument("[key]", "Object key in bucket (defaults to basename of local path)").option("--workspace <id>", "Workspace ID").action(async (bucket, localPath, key, opts, command) => {
16544
+ var uploadCommand = new Command19("upload").description("Upload a local file to a bucket").argument("<bucket>", "Bucket name").argument("<localPath>", "Local file path to upload").argument("[key]", "Object key in bucket (defaults to basename of local path)").option("--workspace <name-or-id>", "Workspace name or ID").action(async (bucket, localPath, key, opts, command) => {
16143
16545
  const useJson = shouldOutputJson(command.optsWithGlobals().json);
16144
16546
  const credentials = requireAuth();
16145
16547
  const client = new ApiClient(credentials);
@@ -16162,7 +16564,7 @@ var uploadCommand = new Command19("upload").description("Upload a local file to
16162
16564
  process.exit(1);
16163
16565
  }
16164
16566
  });
16165
- var deleteCommand2 = new Command19("delete").description("Delete a file from a bucket").argument("<bucket>", "Bucket name").argument("<key>", "Object key to delete").option("--workspace <id>", "Workspace ID").option("--yes", "Skip confirmation prompt").action(async (bucket, key, opts, command) => {
16567
+ var deleteCommand2 = new Command19("delete").description("Delete a file from a bucket").argument("<bucket>", "Bucket name").argument("<key>", "Object key to delete").option("--workspace <name-or-id>", "Workspace name or ID").option("--yes", "Skip confirmation prompt").action(async (bucket, key, opts, command) => {
16166
16568
  const useJson = shouldOutputJson(command.optsWithGlobals().json);
16167
16569
  const credentials = requireAuth();
16168
16570
  const client = new ApiClient(credentials);
@@ -16192,7 +16594,7 @@ var filesCommand = new Command19("files").description("Manage workspace file sto
16192
16594
  init_store();
16193
16595
  init_client();
16194
16596
  import { Command as Command20 } from "commander";
16195
- var listCommand8 = new Command20("list").description("List components registered in the workspace").option("--workspace <id>", "Workspace ID").option("--app <id>", "Filter by app name or ID").action(async (opts, command) => {
16597
+ var listCommand8 = new Command20("list").description("List components registered in the workspace").option("--workspace <name-or-id>", "Workspace name or ID").option("--app <id>", "Filter by app name or ID").action(async (opts, command) => {
16196
16598
  const useJson = shouldOutputJson(command.optsWithGlobals().json);
16197
16599
  const credentials = requireAuth();
16198
16600
  const client = new ApiClient(credentials);
@@ -16231,7 +16633,7 @@ init_store();
16231
16633
  init_client();
16232
16634
  import { Command as Command21 } from "commander";
16233
16635
  init_prompt();
16234
- var listCommand9 = new Command21("list").description("List API keys for the workspace").option("--workspace <id>", "Workspace ID").action(async (opts, command) => {
16636
+ var listCommand9 = new Command21("list").description("List API keys for the workspace").option("--workspace <name-or-id>", "Workspace name or ID").action(async (opts, command) => {
16235
16637
  const useJson = shouldOutputJson(command.optsWithGlobals().json);
16236
16638
  const credentials = requireAuth();
16237
16639
  const client = new ApiClient(credentials);
@@ -16266,7 +16668,7 @@ Workspace: ${workspaceName || workspaceId}
16266
16668
  process.exit(1);
16267
16669
  }
16268
16670
  });
16269
- var createCommand2 = new Command21("create").description("Create a new API key").option("--workspace <id>", "Workspace ID").option("--name <name>", "API key name").option("--app <id>", "Restrict key to a specific app (name or ID)").option("--scopes <scopes>", "Comma-separated list of scopes").action(async (opts, command) => {
16671
+ var createCommand2 = new Command21("create").description("Create a new API key").option("--workspace <name-or-id>", "Workspace name or ID").option("--name <name>", "API key name").option("--app <id>", "Restrict key to a specific app (name or ID)").option("--scopes <scopes>", "Comma-separated list of scopes").action(async (opts, command) => {
16270
16672
  const useJson = shouldOutputJson(command.optsWithGlobals().json);
16271
16673
  const credentials = requireAuth();
16272
16674
  const client = new ApiClient(credentials);
@@ -16314,7 +16716,7 @@ var apiKeysCommand = new Command21("api-keys").description("Manage workspace API
16314
16716
  init_store();
16315
16717
  init_client();
16316
16718
  import { Command as Command22 } from "commander";
16317
- function truncate5(text2, max) {
16719
+ function truncate4(text2, max) {
16318
16720
  if (!text2)
16319
16721
  return "";
16320
16722
  const first = text2.split(`
@@ -16323,7 +16725,7 @@ function truncate5(text2, max) {
16323
16725
  return first;
16324
16726
  return first.slice(0, max - 3) + "...";
16325
16727
  }
16326
- var listCommand10 = new Command22("list").description("List agents in workspace").option("--workspace <id>", "Workspace ID").option("--app <id>", "Filter by app name or ID").action(async (opts, command) => {
16728
+ var listCommand10 = new Command22("list").description("List agents in workspace").option("--workspace <name-or-id>", "Workspace name or ID").option("--app <id>", "Filter by app name or ID").action(async (opts, command) => {
16327
16729
  const useJson = shouldOutputJson(command.optsWithGlobals().json);
16328
16730
  const credentials = requireAuth();
16329
16731
  const client = new ApiClient(credentials);
@@ -16349,8 +16751,8 @@ Workspace: ${workspaceName || workspaceId}
16349
16751
  for (const a of agents) {
16350
16752
  const name = a.agentName.padEnd(24);
16351
16753
  const type = a.type.padEnd(16);
16352
- const app = truncate5(a.appName, 18).padEnd(20);
16353
- const desc = truncate5(a.description, 40).padEnd(42);
16754
+ const app = truncate4(a.appName, 18).padEnd(20);
16755
+ const desc = truncate4(a.description, 40).padEnd(42);
16354
16756
  const integrations = (a.integrations?.join(", ") || "").padEnd(20);
16355
16757
  const entities = (a.entities?.join(", ") || "").padEnd(20);
16356
16758
  const mode = a.deploymentMode || "";
@@ -16362,7 +16764,7 @@ Workspace: ${workspaceName || workspaceId}
16362
16764
  process.exit(1);
16363
16765
  }
16364
16766
  });
16365
- var statusCommand2 = new Command22("status").description("Get status of a specific agent").argument("<name>", "Agent name").option("--workspace <id>", "Workspace ID").option("--app <id>", "App name or ID (required)").action(async (name, opts, command) => {
16767
+ var statusCommand2 = new Command22("status").description("Get status of a specific agent").argument("<name>", "Agent name").option("--workspace <name-or-id>", "Workspace name or ID").option("--app <id>", "App name or ID (required)").action(async (name, opts, command) => {
16366
16768
  const useJson = shouldOutputJson(command.optsWithGlobals().json);
16367
16769
  const credentials = requireAuth();
16368
16770
  const client = new ApiClient(credentials);
@@ -16380,7 +16782,7 @@ var statusCommand2 = new Command22("status").description("Get status of a specif
16380
16782
  process.exit(1);
16381
16783
  }
16382
16784
  });
16383
- var executionsCommand = new Command22("executions").description("List agent execution history for workspace").option("--workspace <id>", "Workspace ID").action(async (opts, command) => {
16785
+ var executionsCommand = new Command22("executions").description("List agent execution history for workspace").option("--workspace <name-or-id>", "Workspace name or ID").action(async (opts, command) => {
16384
16786
  const useJson = shouldOutputJson(command.optsWithGlobals().json);
16385
16787
  const credentials = requireAuth();
16386
16788
  const client = new ApiClient(credentials);
@@ -16399,9 +16801,9 @@ var executionsCommand = new Command22("executions").description("List agent exec
16399
16801
  console.log(" " + "-".repeat(160));
16400
16802
  for (const e of executions) {
16401
16803
  const sessionId = e.sessionId.padEnd(36);
16402
- const agent = truncate5(e.agentName, 20).padEnd(22);
16403
- const app = truncate5(e.appId, 20).padEnd(22);
16404
- const prompt = truncate5(e.prompt, 50).padEnd(52);
16804
+ const agent = truncate4(e.agentName, 20).padEnd(22);
16805
+ const app = truncate4(e.appId, 20).padEnd(22);
16806
+ const prompt = truncate4(e.prompt, 50).padEnd(52);
16405
16807
  const status = e.status.padEnd(12);
16406
16808
  const duration = e.durationMs != null ? `${e.durationMs}ms` : "";
16407
16809
  const usage = e.usage ? `${e.usage.inputTokens}/${e.usage.outputTokens}` : "";
@@ -16413,7 +16815,7 @@ var executionsCommand = new Command22("executions").description("List agent exec
16413
16815
  process.exit(1);
16414
16816
  }
16415
16817
  });
16416
- var executionCommand = new Command22("execution").description("Get execution stream for a specific session").argument("<sessionId>", "Session ID").option("--workspace <id>", "Workspace ID").action(async (sessionId, opts, command) => {
16818
+ var executionCommand = new Command22("execution").description("Get execution stream for a specific session").argument("<sessionId>", "Session ID").option("--workspace <name-or-id>", "Workspace name or ID").action(async (sessionId, opts, command) => {
16417
16819
  const useJson = shouldOutputJson(command.optsWithGlobals().json);
16418
16820
  const credentials = requireAuth();
16419
16821
  const client = new ApiClient(credentials);
@@ -16437,7 +16839,7 @@ init_store();
16437
16839
  init_client();
16438
16840
  import { Command as Command23 } from "commander";
16439
16841
  init_prompt();
16440
- var listCommand11 = new Command23("list").description("List workspace MCP servers").option("--workspace <id>", "Workspace ID").action(async (opts, command) => {
16842
+ var listCommand11 = new Command23("list").description("List workspace MCP servers").option("--workspace <name-or-id>", "Workspace name or ID").action(async (opts, command) => {
16441
16843
  const useJson = shouldOutputJson(command.optsWithGlobals().json);
16442
16844
  const credentials = requireAuth();
16443
16845
  const client = new ApiClient(credentials);
@@ -16493,7 +16895,7 @@ Workspace: ${workspaceName || workspaceId}
16493
16895
  process.exit(1);
16494
16896
  }
16495
16897
  });
16496
- var addCommand = new Command23("add").description("Add an MCP server to workspace").argument("<name>", "Server name").argument("<url>", "Server URL (Streamable HTTP or SSE endpoint)").option("--transport <type>", "Transport type: streamable-http or sse", "streamable-http").option("--workspace <id>", "Workspace ID").action(async (name, url, opts, command) => {
16898
+ var addCommand = new Command23("add").description("Add an MCP server to workspace").argument("<name>", "Server name").argument("<url>", "Server URL (Streamable HTTP or SSE endpoint)").option("--transport <type>", "Transport type: streamable-http or sse", "streamable-http").option("--workspace <name-or-id>", "Workspace name or ID").action(async (name, url, opts, command) => {
16497
16899
  const useJson = shouldOutputJson(command.optsWithGlobals().json);
16498
16900
  const credentials = requireAuth();
16499
16901
  const client = new ApiClient(credentials);
@@ -16521,7 +16923,7 @@ var addCommand = new Command23("add").description("Add an MCP server to workspac
16521
16923
  process.exit(1);
16522
16924
  }
16523
16925
  });
16524
- var removeCommand = new Command23("remove").description("Remove an MCP server from workspace").argument("<name>", "Server name").option("--yes", "Skip confirmation").option("--workspace <id>", "Workspace ID").action(async (name, opts, command) => {
16926
+ var removeCommand = new Command23("remove").description("Remove an MCP server from workspace").argument("<name>", "Server name").option("--yes", "Skip confirmation").option("--workspace <name-or-id>", "Workspace name or ID").action(async (name, opts, command) => {
16525
16927
  const useJson = shouldOutputJson(command.optsWithGlobals().json);
16526
16928
  const credentials = requireAuth();
16527
16929
  const client = new ApiClient(credentials);
@@ -16584,7 +16986,7 @@ var searchCommand3 = new Command23("search").description("Search community MCP s
16584
16986
  process.exit(1);
16585
16987
  }
16586
16988
  });
16587
- var installCommand2 = new Command23("install").description("Install a community MCP server from the MCP Registry into your workspace").argument("<query>", "Server name or search query").option("--workspace <id>", "Workspace ID").action(async (query, opts, command) => {
16989
+ var installCommand2 = new Command23("install").description("Install a community MCP server from the MCP Registry into your workspace").argument("<query>", "Server name or search query").option("--workspace <name-or-id>", "Workspace name or ID").action(async (query, opts, command) => {
16588
16990
  const useJson = shouldOutputJson(command.optsWithGlobals().json);
16589
16991
  const credentials = requireAuth();
16590
16992
  const client = new ApiClient(credentials);
@@ -18589,7 +18991,7 @@ async function resolveAndPersistWorkspace(client, opts) {
18589
18991
  }
18590
18992
  return { workspaceId, workspaceName, workspaceSlug };
18591
18993
  }
18592
- var setupCommand = new Command25("setup").description("Configure local AI agents with workspace skills and MCP servers").option("--workspace <id>", "Workspace ID").option("--agent <slug>", "Only configure a specific agent (e.g. claude-code, cursor)").option("--dry-run", "Show what would be configured without writing files").option("-y, --yes", "Skip all prompts, configure all detected agents with user scope").option("--persona <level>", "Technical-level persona for agent instructions (1=everyday, 2=curious, 3=engineer)").action(async (opts) => {
18994
+ var setupCommand = new Command25("setup").description("Configure local AI agents with workspace skills and MCP servers").option("--workspace <name-or-id>", "Workspace name or ID").option("--agent <slug>", "Only configure a specific agent (e.g. claude-code, cursor)").option("--dry-run", "Show what would be configured without writing files").option("-y, --yes", "Skip all prompts, configure all detected agents with user scope").option("--persona <level>", "Technical-level persona for agent instructions (1=everyday, 2=curious, 3=engineer)").action(async (opts) => {
18593
18995
  const credentials = requireAuth();
18594
18996
  const client = new ApiClient(credentials);
18595
18997
  const { workspaceId, workspaceName, workspaceSlug } = await resolveAndPersistWorkspace(client, opts);
@@ -18941,7 +19343,7 @@ init_store();
18941
19343
  init_client();
18942
19344
  import { Command as Command28 } from "commander";
18943
19345
  init_init();
18944
- var listCommand12 = new Command28("list").description("List apps in workspace").option("--workspace <id>", "Workspace ID").action(async (opts, command) => {
19346
+ var listCommand12 = new Command28("list").description("List apps in workspace").option("--workspace <name-or-id>", "Workspace name or ID").action(async (opts, command) => {
18945
19347
  const useJson = shouldOutputJson(command.optsWithGlobals().json);
18946
19348
  const credentials = requireAuth();
18947
19349
  const client = new ApiClient(credentials);
@@ -18974,7 +19376,7 @@ Workspace: ${workspaceName || workspaceId}
18974
19376
  var createCommand3 = new Command28("create").description("Create a new Runwork app").argument("[name]", "App name").action(async (name) => {
18975
19377
  await runCreateFlow(name);
18976
19378
  });
18977
- var infoCommand2 = new Command28("info").description("Show detailed app info, preview status, and registries").argument("[app]", "App ID, name, or slug").option("--workspace <id>", "Workspace ID").action(async (appArg, opts, command) => {
19379
+ var infoCommand2 = new Command28("info").description("Show detailed app info, preview status, and registries").argument("[app]", "App ID, name, or slug").option("--workspace <name-or-id>", "Workspace name or ID").action(async (appArg, opts, command) => {
18978
19380
  const useJson = shouldOutputJson(command.optsWithGlobals().json);
18979
19381
  const credentials = requireAuth();
18980
19382
  const client = new ApiClient(credentials);
@@ -19001,15 +19403,157 @@ var infoCommand2 = new Command28("info").description("Show detailed app info, pr
19001
19403
  });
19002
19404
  var appsCommand = new Command28("apps").description("Manage workspace apps").addCommand(listCommand12).addCommand(createCommand3).addCommand(infoCommand2);
19003
19405
 
19406
+ // src/commands/members.ts
19407
+ init_store();
19408
+ init_client();
19409
+ import { Command as Command29 } from "commander";
19410
+ function formatMemberRows(members) {
19411
+ return members.map((m) => ({
19412
+ name: m.user.displayName || m.user.email,
19413
+ email: m.user.email,
19414
+ role: m.role,
19415
+ status: m.status,
19416
+ userId: m.userId
19417
+ }));
19418
+ }
19419
+ var listCommand13 = new Command29("list").description("List members of a workspace (name, email, role)").option("--workspace <name-or-id>", "Workspace name or ID").action(async (opts, command) => {
19420
+ const useJson = shouldOutputJson(command.optsWithGlobals().json);
19421
+ const credentials = requireAuth();
19422
+ const client = new ApiClient(credentials);
19423
+ const { workspaceId, workspaceName } = await resolveWorkspace2(client, opts);
19424
+ try {
19425
+ const members = await client.listWorkspaceMembers(workspaceId);
19426
+ if (useJson) {
19427
+ jsonOut({ workspaceId, workspaceName, members });
19428
+ return;
19429
+ }
19430
+ if (members.length === 0) {
19431
+ console.log("No members found in this workspace.");
19432
+ return;
19433
+ }
19434
+ console.log(`
19435
+ Workspace: ${workspaceName || workspaceId}
19436
+ `);
19437
+ console.log(` ${"NAME".padEnd(24)} ${"EMAIL".padEnd(32)} ${"ROLE".padEnd(10)} STATUS`);
19438
+ console.log(" " + "-".repeat(76));
19439
+ for (const row of formatMemberRows(members)) {
19440
+ console.log(` ${row.name.padEnd(24)} ${row.email.padEnd(32)} ${row.role.padEnd(10)} ${row.status}`);
19441
+ }
19442
+ console.log("");
19443
+ } catch (err) {
19444
+ console.error("Failed to list members:", err instanceof Error ? err.message : err);
19445
+ process.exit(1);
19446
+ }
19447
+ });
19448
+ var membersCommand = new Command29("members").description("List workspace members").addCommand(listCommand13);
19449
+
19450
+ // src/commands/api.ts
19451
+ init_store();
19452
+ init_client();
19453
+ import { Command as Command30 } from "commander";
19454
+ import { readFileSync as readFileSync37 } from "fs";
19455
+ function normalizeApiPath(rawPath, baseUrl) {
19456
+ if (/^https?:\/\//i.test(rawPath)) {
19457
+ const target = new URL(rawPath);
19458
+ const base = new URL(baseUrl);
19459
+ if (target.origin !== base.origin) {
19460
+ throw new Error(`Refusing to call ${target.origin}: \`runwork api\` only calls the platform API at ${base.origin}.`);
19461
+ }
19462
+ return target.pathname + target.search;
19463
+ }
19464
+ return rawPath.startsWith("/") ? rawPath : `/${rawPath}`;
19465
+ }
19466
+ var apiCommand = new Command30("api").description("Make an authenticated request to the Runwork platform API (escape hatch for endpoints the CLI does not cover)").argument("<method>", "HTTP method (GET, POST, PUT, DELETE, etc.)").argument("[path]", "API path (e.g. /api/workspaces); optional with --curl").option("--body <json>", "Request body JSON (or @file.json)").option("--header <header>", 'Request header (format: "Key: Value", repeatable)', (val, prev) => [...prev, val], []).option("--query <query>", "Query string (e.g. limit=10&offset=0)").option("--curl <command>", "Parse a curl command (method, path, headers, body)").option("--curl-file <file>", "Read curl command from a file").addHelpText("after", `
19467
+ Examples:
19468
+ runwork api GET /api/workspaces
19469
+ runwork api GET /api/workspaces/<id>/members
19470
+ runwork api POST /api/workspaces/<id>/skills --body '{"name":"my-skill"}'
19471
+
19472
+ Authentication uses your stored Runwork credentials; the API key never needs
19473
+ to be read or pasted manually. Prefer a dedicated command when one exists
19474
+ (runwork apps/members/schedules/...).`).action(async (method, path2, opts, command) => {
19475
+ const useJson = shouldOutputJson(command.optsWithGlobals().json);
19476
+ const credentials = requireAuth();
19477
+ const client = new ApiClient(credentials);
19478
+ let finalMethod = method;
19479
+ let finalPath = path2;
19480
+ const headers = {};
19481
+ let body;
19482
+ const query = opts.query;
19483
+ if (opts.curl || opts.curlFile) {
19484
+ let curlStr = opts.curl;
19485
+ if (opts.curlFile) {
19486
+ try {
19487
+ curlStr = readFileSync37(opts.curlFile, "utf-8");
19488
+ } catch (err) {
19489
+ console.error(`Could not read --curl-file: ${err instanceof Error ? err.message : err}`);
19490
+ process.exit(1);
19491
+ }
19492
+ }
19493
+ const parsed = await parseCurlToRequest(curlStr);
19494
+ finalMethod = parsed.method;
19495
+ finalPath = parsed.path + (parsed.query ? `?${parsed.query}` : "");
19496
+ Object.assign(headers, parsed.headers);
19497
+ body = parsed.body;
19498
+ }
19499
+ for (const h of opts.header || []) {
19500
+ const [key, ...rest] = h.split(":");
19501
+ headers[key.trim()] = rest.join(":").trim();
19502
+ }
19503
+ if (opts.body) {
19504
+ let raw = opts.body;
19505
+ if (raw.startsWith("@")) {
19506
+ try {
19507
+ raw = readFileSync37(raw.slice(1), "utf-8");
19508
+ } catch (err) {
19509
+ console.error(`Could not read body file: ${err instanceof Error ? err.message : err}`);
19510
+ process.exit(1);
19511
+ }
19512
+ }
19513
+ try {
19514
+ body = JSON.parse(raw);
19515
+ } catch {
19516
+ console.error("Invalid JSON in --body");
19517
+ process.exit(1);
19518
+ }
19519
+ }
19520
+ if (!finalPath) {
19521
+ console.error("Usage: runwork api <method> <path>");
19522
+ console.error(' or: runwork api <method> --curl "curl ..."');
19523
+ process.exit(1);
19524
+ }
19525
+ try {
19526
+ const normalizedPath = normalizeApiPath(finalPath, credentials.baseUrl || "https://runwork.ai");
19527
+ const result = await client.rawApiCall(finalMethod, normalizedPath, {
19528
+ body,
19529
+ headers: Object.keys(headers).length > 0 ? headers : undefined,
19530
+ query
19531
+ });
19532
+ if (useJson) {
19533
+ jsonOut({ success: result.ok, status: result.status, body: result.body });
19534
+ } else if (typeof result.body === "string") {
19535
+ console.log(result.body);
19536
+ } else {
19537
+ console.log(JSON.stringify(result.body, null, 2));
19538
+ }
19539
+ if (!result.ok)
19540
+ process.exit(1);
19541
+ } catch (err) {
19542
+ console.error("API call failed:", err instanceof Error ? err.message : err);
19543
+ process.exit(1);
19544
+ }
19545
+ });
19546
+
19004
19547
  // src/commands/doctor.ts
19005
19548
  init_colors();
19006
- import { Command as Command29 } from "commander";
19549
+ import { Command as Command31 } from "commander";
19007
19550
 
19008
19551
  // src/health/checks.ts
19009
19552
  init_subprocess();
19010
19553
  init_store();
19011
19554
  init_client();
19012
- import { existsSync as existsSync44, readFileSync as readFileSync37 } from "fs";
19555
+ import { parse as parse2 } from "smol-toml";
19556
+ import { existsSync as existsSync44, readFileSync as readFileSync38 } from "fs";
19013
19557
  import { join as join40, sep as sep3 } from "path";
19014
19558
  import { homedir as homedir22, platform as osPlatform2, arch as osArch } from "os";
19015
19559
  init_http();
@@ -19045,7 +19589,7 @@ function buildContext() {
19045
19589
  const configPath = join40(process.cwd(), ".runwork.json");
19046
19590
  if (existsSync44(configPath)) {
19047
19591
  try {
19048
- config = JSON.parse(readFileSync37(configPath, "utf-8"));
19592
+ config = JSON.parse(readFileSync38(configPath, "utf-8"));
19049
19593
  } catch {}
19050
19594
  }
19051
19595
  return { credentials, client, config, cwd: process.cwd() };
@@ -19265,6 +19809,14 @@ async function checkGitCredentialHelper(ctx) {
19265
19809
  fix: "runwork doctor --fix (re-registers with the current binary path)"
19266
19810
  };
19267
19811
  }
19812
+ if (!lookup.hasReset) {
19813
+ return {
19814
+ name: "git-credential-helper",
19815
+ status: "fail",
19816
+ message: `helper registered for ${origin} but the credential-manager reset entry is missing (Windows may show a Git Credential Manager popup)`,
19817
+ fix: "runwork doctor --fix"
19818
+ };
19819
+ }
19268
19820
  return {
19269
19821
  name: "git-credential-helper",
19270
19822
  status: "pass",
@@ -19394,7 +19946,7 @@ function loadSetupState5() {
19394
19946
  for (const p of [projectPath, userPath]) {
19395
19947
  if (existsSync44(p)) {
19396
19948
  try {
19397
- return JSON.parse(readFileSync37(p, "utf-8"));
19949
+ return JSON.parse(readFileSync38(p, "utf-8"));
19398
19950
  } catch {
19399
19951
  continue;
19400
19952
  }
@@ -19402,6 +19954,95 @@ function loadSetupState5() {
19402
19954
  }
19403
19955
  return null;
19404
19956
  }
19957
+ var RUNWORK_NETWORK_DOMAINS = ["runwork.ai", "*.runwork.ai"];
19958
+ async function checkCodexNetwork() {
19959
+ const name = "codex-network";
19960
+ const state = loadSetupState5();
19961
+ if (!state || !state.configuredAgents.includes("codex")) {
19962
+ return { name, status: "skip", message: "Codex not configured for Runwork" };
19963
+ }
19964
+ const configPath = join40(homedir22(), ".codex", "config.toml");
19965
+ if (!existsSync44(configPath)) {
19966
+ return { name, status: "skip", message: "no Codex config found" };
19967
+ }
19968
+ let parsed;
19969
+ try {
19970
+ parsed = parse2(readFileSync38(configPath, "utf-8"));
19971
+ } catch {
19972
+ return { name, status: "warn", message: "could not parse ~/.codex/config.toml" };
19973
+ }
19974
+ const features = parsed.features && typeof parsed.features === "object" ? parsed.features : undefined;
19975
+ const proxy = features?.network_proxy;
19976
+ if (proxy && proxy.enabled === true) {
19977
+ const domains = proxy.domains && typeof proxy.domains === "object" ? proxy.domains : {};
19978
+ if (RUNWORK_NETWORK_DOMAINS.some((d) => domains[d] === "deny")) {
19979
+ return {
19980
+ name,
19981
+ status: "warn",
19982
+ message: "network proxy denies runwork.ai; the Runwork CLI is blocked",
19983
+ fix: 'remove the runwork.ai "deny" rule in ~/.codex/config.toml'
19984
+ };
19985
+ }
19986
+ if (RUNWORK_NETWORK_DOMAINS.every((d) => domains[d] === "allow")) {
19987
+ return { name, status: "pass", message: "proxy-allowlisted: runwork.ai permitted, other domains scoped by your proxy" };
19988
+ }
19989
+ return {
19990
+ name,
19991
+ status: "warn",
19992
+ message: "network proxy is on but runwork.ai is not allowlisted",
19993
+ fix: "runwork sync"
19994
+ };
19995
+ }
19996
+ const sww = parsed.sandbox_workspace_write && typeof parsed.sandbox_workspace_write === "object" ? parsed.sandbox_workspace_write : undefined;
19997
+ const sandboxMode = typeof parsed.sandbox_mode === "string" ? parsed.sandbox_mode : undefined;
19998
+ if (sww?.network_access === true || sandboxMode === "danger-full-access") {
19999
+ return { name, status: "pass", message: "open: outbound network enabled (all domains)" };
20000
+ }
20001
+ if (sww?.network_access === false) {
20002
+ return {
20003
+ name,
20004
+ status: "warn",
20005
+ message: "off: network explicitly disabled; the Runwork CLI cannot reach the network",
20006
+ fix: "set [sandbox_workspace_write] network_access = true, or run runwork sync"
20007
+ };
20008
+ }
20009
+ return {
20010
+ name,
20011
+ status: "warn",
20012
+ message: "off: network is disabled by default in Codex workspace-write sandbox; the Runwork CLI cannot reach the network",
20013
+ fix: "runwork sync"
20014
+ };
20015
+ }
20016
+ async function checkCodexDesktopProject() {
20017
+ const name = "codex-desktop-project";
20018
+ const state = loadSetupState5();
20019
+ const usesCodex = !!state && (state.configuredAgents.includes("codex-app") || state.configuredAgents.includes("codex"));
20020
+ if (!usesCodex) {
20021
+ return { name, status: "skip", message: "Codex not configured for Runwork" };
20022
+ }
20023
+ const statePath2 = join40(homedir22(), ".codex", ".codex-global-state.json");
20024
+ if (!existsSync44(statePath2)) {
20025
+ return { name, status: "skip", message: "Codex desktop app not detected" };
20026
+ }
20027
+ let savedRoots = [];
20028
+ try {
20029
+ const parsed = JSON.parse(readFileSync38(statePath2, "utf-8"));
20030
+ const roots = parsed["electron-saved-workspace-roots"];
20031
+ savedRoots = Array.isArray(roots) ? roots.filter((r) => typeof r === "string") : [];
20032
+ } catch {
20033
+ return { name, status: "warn", message: "could not read Codex desktop state" };
20034
+ }
20035
+ const runworkDir = join40(homedir22(), ".runwork");
20036
+ if (savedRoots.includes(runworkDir)) {
20037
+ return { name, status: "pass", message: "Runwork project added to Codex desktop sidebar" };
20038
+ }
20039
+ return {
20040
+ name,
20041
+ status: "warn",
20042
+ message: "Runwork project not added to Codex desktop sidebar",
20043
+ fix: "quit the Codex app, then run runwork sync (sync skips this while Codex is open)"
20044
+ };
20045
+ }
19405
20046
  async function checkAgentSetup() {
19406
20047
  const state = loadSetupState5();
19407
20048
  if (!state) {
@@ -19446,7 +20087,7 @@ async function checkAgentSetup() {
19446
20087
  const mcpConfigPath = getMcpConfigPath2(slug, "user");
19447
20088
  if (mcpConfigPath && existsSync44(mcpConfigPath)) {
19448
20089
  try {
19449
- const content = readFileSync37(mcpConfigPath, "utf-8");
20090
+ const content = readFileSync38(mcpConfigPath, "utf-8");
19450
20091
  const missingMcp = state.mcpServers.filter((name) => !content.includes(name));
19451
20092
  if (missingMcp.length > 0) {
19452
20093
  details.push(`${missingMcp.length} MCP server(s) missing from ${slug} config`);
@@ -19504,7 +20145,8 @@ function getMcpConfigPath2(slug, scope) {
19504
20145
  case "windsurf":
19505
20146
  return scope === "project" ? join40(process.cwd(), ".windsurf", "mcp.json") : join40(home, ".windsurf", "mcp.json");
19506
20147
  case "codex":
19507
- return scope === "user" ? join40(home, ".codex", "mcp.json") : null;
20148
+ case "codex-app":
20149
+ return scope === "user" ? join40(home, ".codex", "config.toml") : null;
19508
20150
  case "gemini":
19509
20151
  return scope === "user" ? join40(home, ".gemini", "settings.json") : null;
19510
20152
  default:
@@ -19517,6 +20159,7 @@ function getSkillsDir(slug, scope) {
19517
20159
  case "claude-code":
19518
20160
  return scope === "project" ? join40(process.cwd(), ".claude", "skills") : join40(home, ".claude", "skills");
19519
20161
  case "codex":
20162
+ case "codex-app":
19520
20163
  return scope === "project" ? join40(process.cwd(), ".codex", "skills") : join40(home, ".codex", "skills");
19521
20164
  case "gemini":
19522
20165
  return scope === "project" ? join40(process.cwd(), ".gemini", "skills") : join40(home, ".gemini", "skills");
@@ -19543,7 +20186,9 @@ var CHECK_RUNNERS = [
19543
20186
  { names: ["app-exists"], run: async (ctx) => [await checkAppExists(ctx)] },
19544
20187
  { names: ["git-remote"], run: async (ctx) => [await checkGitRemote(ctx)] },
19545
20188
  { names: ["deploy-freshness"], run: async (ctx) => [await checkDeployFreshness(ctx)] },
19546
- { names: ["agent-setup"], run: async () => [await checkAgentSetup()] }
20189
+ { names: ["agent-setup"], run: async () => [await checkAgentSetup()] },
20190
+ { names: ["codex-network"], run: async () => [await checkCodexNetwork()] },
20191
+ { names: ["codex-desktop-project"], run: async () => [await checkCodexDesktopProject()] }
19547
20192
  ];
19548
20193
  var ALL_CHECK_NAMES = CHECK_RUNNERS.flatMap((r) => r.names);
19549
20194
  async function runAllChecks(options) {
@@ -19616,7 +20261,7 @@ async function applyDoctorFixes(ctx, failingNames) {
19616
20261
  }
19617
20262
 
19618
20263
  // src/agents/runtime-detection.ts
19619
- import { existsSync as existsSync46, readFileSync as readFileSync38, statSync as statSync6, readdirSync as readdirSync13 } from "fs";
20264
+ import { existsSync as existsSync46, readFileSync as readFileSync39, statSync as statSync6, readdirSync as readdirSync13 } from "fs";
19620
20265
  import { homedir as homedir23 } from "os";
19621
20266
  import { join as join42 } from "path";
19622
20267
  var RUNWORK_SESSIONS_DIR = join42(homedir23(), ".runwork", "sessions");
@@ -19686,7 +20331,7 @@ function readHookSessionInfo(sessionId) {
19686
20331
  if (!existsSync46(path2))
19687
20332
  return null;
19688
20333
  try {
19689
- const raw = readFileSync38(path2, "utf8");
20334
+ const raw = readFileSync39(path2, "utf8");
19690
20335
  const parsed = JSON.parse(raw);
19691
20336
  return parsed;
19692
20337
  } catch {
@@ -19906,7 +20551,9 @@ var CHECK_LABELS = {
19906
20551
  "app-exists": "App exists",
19907
20552
  "git-remote": "Git remote",
19908
20553
  "deploy-freshness": "Deploy freshness",
19909
- "agent-setup": "Agent setup"
20554
+ "agent-setup": "Agent setup",
20555
+ "codex-network": "Codex network",
20556
+ "codex-desktop-project": "Codex project"
19910
20557
  };
19911
20558
  function printHumanReport(report) {
19912
20559
  console.log("");
@@ -19971,7 +20618,7 @@ function parseCheckNames(raw) {
19971
20618
  const unknown = requested.filter((n) => !known.has(n));
19972
20619
  return { only, unknown };
19973
20620
  }
19974
- var doctorCommand = new Command29("doctor").description("Check system health: auth, network, project config, agent setup").option("-v, --verbose", "Include host-agent detection results, runtime info, and allowlisted env vars (useful for AI agents debugging their own environment)").option("--check <names>", `Run only the named checks (comma-separated). Available: ${ALL_CHECK_NAMES.join(", ")}`).option("--fix", "Auto-remediate fixable failures (git credential helper, runwork remote), then re-check").action(async (opts, command) => {
20621
+ var doctorCommand = new Command31("doctor").description("Check system health: auth, network, project config, agent setup").option("-v, --verbose", "Include host-agent detection results, runtime info, and allowlisted env vars (useful for AI agents debugging their own environment)").option("--check <names>", `Run only the named checks (comma-separated). Available: ${ALL_CHECK_NAMES.join(", ")}`).option("--fix", "Auto-remediate fixable failures (git credential helper, runwork remote), then re-check").action(async (opts, command) => {
19975
20622
  const asJson = shouldOutputJson(command.optsWithGlobals().json);
19976
20623
  let only;
19977
20624
  if (opts.check) {
@@ -20022,8 +20669,8 @@ var doctorCommand = new Command29("doctor").description("Check system health: au
20022
20669
  // src/commands/share-convo.ts
20023
20670
  init_store();
20024
20671
  init_client();
20025
- import { Command as Command30 } from "commander";
20026
- import { readFileSync as readFileSync39, existsSync as existsSync47 } from "fs";
20672
+ import { Command as Command32 } from "commander";
20673
+ import { readFileSync as readFileSync40, existsSync as existsSync47 } from "fs";
20027
20674
  import { createHash as createHash4 } from "crypto";
20028
20675
  function nativeBundleFormatForAgent(slug) {
20029
20676
  if (slug === "claude-code" || slug === "claude-desktop")
@@ -20065,7 +20712,7 @@ async function runShareConvo(opts, command, isPersonalAlias = false) {
20065
20712
  const credentials = requireAuth();
20066
20713
  const client = new ApiClient(credentials);
20067
20714
  const { workspaceId } = await resolveWorkspace2(client, { workspace: opts.workspace });
20068
- const transcriptContent = readFileSync39(opts.transcriptFile, "utf8");
20715
+ const transcriptContent = readFileSync40(opts.transcriptFile, "utf8");
20069
20716
  const bundles = [
20070
20717
  {
20071
20718
  format: "transcript",
@@ -20090,7 +20737,7 @@ async function runShareConvo(opts, command, isPersonalAlias = false) {
20090
20737
  const nativeFormat = nativeBundleFormatForAgent(sourceAgent);
20091
20738
  if (nativeFormat) {
20092
20739
  try {
20093
- const content = readFileSync39(nativeFilePath, "utf8");
20740
+ const content = readFileSync40(nativeFilePath, "utf8");
20094
20741
  bundles.push({
20095
20742
  format: nativeFormat,
20096
20743
  content,
@@ -20106,7 +20753,7 @@ async function runShareConvo(opts, command, isPersonalAlias = false) {
20106
20753
  let metadata = {};
20107
20754
  if (opts.metadataFile) {
20108
20755
  try {
20109
- metadata = JSON.parse(readFileSync39(opts.metadataFile, "utf8"));
20756
+ metadata = JSON.parse(readFileSync40(opts.metadataFile, "utf8"));
20110
20757
  } catch (err) {
20111
20758
  console.error(`Error: --metadata-file is not valid JSON: ${err instanceof Error ? err.message : err}`);
20112
20759
  process.exit(1);
@@ -20161,17 +20808,17 @@ Skipped: ${result.skipped.map((s) => `${s.identifier} (${s.reason})`).join(", ")
20161
20808
  process.exit(1);
20162
20809
  }
20163
20810
  }
20164
- var shareConvoCommand = new Command30("share-convo").description("Share the current AI conversation with a teammate").option("--to <email>", "Recipient email (repeatable)", (value, prev = []) => [...prev, value], []).option("--transcript-file <path>", "Path to the LLM-emitted markdown transcript (required)").option("--native-file <path>", "Path to the native session file (optional; auto-detected from env vars otherwise)").option("--source-agent <slug>", "Override host-agent detection (e.g. claude-code, codex, claude-desktop)").option("--title <string>", "Short title for the conversation (required)").option("--note <string>", "Optional personal note to recipients").option("--ttl-days <n>", "Days until expiration (1-30, default 7)").option("--metadata-json <json>", "Inline JSON object with workMode, openQuestions, suggestedNextStep, etc.").option("--metadata-file <path>", "Path to a JSON file with the same metadata fields").option("--workspace <id>", "Workspace ID").action((opts, command) => runShareConvo(opts, command, false));
20811
+ var shareConvoCommand = new Command32("share-convo").description("Share the current AI conversation with a teammate").option("--to <email>", "Recipient email (repeatable)", (value, prev = []) => [...prev, value], []).option("--transcript-file <path>", "Path to the LLM-emitted markdown transcript (required)").option("--native-file <path>", "Path to the native session file (optional; auto-detected from env vars otherwise)").option("--source-agent <slug>", "Override host-agent detection (e.g. claude-code, codex, claude-desktop)").option("--title <string>", "Short title for the conversation (required)").option("--note <string>", "Optional personal note to recipients").option("--ttl-days <n>", "Days until expiration (1-30, default 7)").option("--metadata-json <json>", "Inline JSON object with workMode, openQuestions, suggestedNextStep, etc.").option("--metadata-file <path>", "Path to a JSON file with the same metadata fields").option("--workspace <name-or-id>", "Workspace name or ID").action((opts, command) => runShareConvo(opts, command, false));
20165
20812
 
20166
20813
  // src/commands/save-convo.ts
20167
- import { Command as Command31 } from "commander";
20168
- var saveConvoCommand = new Command31("save-convo").description("Save the current AI conversation as a personal checkpoint").option("--transcript-file <path>", "Path to the LLM-emitted markdown transcript (required)").option("--native-file <path>", "Path to the native session file (optional; auto-detected from env vars)").option("--source-agent <slug>", "Override host-agent detection").option("--title <string>", "Short title for the conversation (required)").option("--note <string>", "Optional note to your future self").option("--ttl-days <n>", "Days until expiration (1-30, default 7)").option("--metadata-json <json>", "Inline JSON object with workMode, openQuestions, etc.").option("--metadata-file <path>", "Path to a JSON file with metadata fields").option("--workspace <id>", "Workspace ID").action((opts, command) => runShareConvo({ ...opts, personal: true }, command, true));
20814
+ import { Command as Command33 } from "commander";
20815
+ var saveConvoCommand = new Command33("save-convo").description("Save the current AI conversation as a personal checkpoint").option("--transcript-file <path>", "Path to the LLM-emitted markdown transcript (required)").option("--native-file <path>", "Path to the native session file (optional; auto-detected from env vars)").option("--source-agent <slug>", "Override host-agent detection").option("--title <string>", "Short title for the conversation (required)").option("--note <string>", "Optional note to your future self").option("--ttl-days <n>", "Days until expiration (1-30, default 7)").option("--metadata-json <json>", "Inline JSON object with workMode, openQuestions, etc.").option("--metadata-file <path>", "Path to a JSON file with metadata fields").option("--workspace <name-or-id>", "Workspace name or ID").action((opts, command) => runShareConvo({ ...opts, personal: true }, command, true));
20169
20816
 
20170
20817
  // src/commands/inbox.ts
20171
20818
  init_store();
20172
20819
  init_client();
20173
- import { Command as Command32 } from "commander";
20174
- var inboxCommand = new Command32("inbox").description("List shared conversations visible to you").option("--filter <scope>", "Filter: all | received | sent | saved", "all").option("--limit <n>", "Max rows to return", "50").option("--workspace <id>", "Workspace ID").action(async (opts, command) => {
20820
+ import { Command as Command34 } from "commander";
20821
+ var inboxCommand = new Command34("inbox").description("List shared conversations visible to you").option("--filter <scope>", "Filter: all | received | sent | saved", "all").option("--limit <n>", "Max rows to return", "50").option("--workspace <name-or-id>", "Workspace name or ID").action(async (opts, command) => {
20175
20822
  const useJson = shouldOutputJson(command.optsWithGlobals().json);
20176
20823
  const scope = opts.filter === "received" || opts.filter === "sent" || opts.filter === "saved" ? opts.filter : "all";
20177
20824
  const limit = opts.limit ? parseInt(opts.limit, 10) : 50;
@@ -20211,7 +20858,7 @@ Shared conversations (${scope}, ${total}):
20211
20858
  // src/commands/resume.ts
20212
20859
  init_store();
20213
20860
  init_client();
20214
- import { Command as Command33 } from "commander";
20861
+ import { Command as Command35 } from "commander";
20215
20862
  import { writeFileSync as writeFileSync31, mkdirSync as mkdirSync28, realpathSync } from "fs";
20216
20863
  import { homedir as homedir24 } from "os";
20217
20864
  import { join as join43 } from "path";
@@ -20285,7 +20932,7 @@ function isAgentInstalled(agent) {
20285
20932
  }
20286
20933
  return false;
20287
20934
  }
20288
- var resumeCommand2 = new Command33("resume").description("Resume a shared conversation locally in your agent of choice").argument("<share-id>", "The share ID (sc_*) returned by share-convo or save-convo").option("--agent <slug>", "Override target agent (e.g. claude-code, codex)").option("--into <path>", "Override target cwd (defaults to current $PWD)").option("--dry-run", "Print the resume command instead of executing it").option("--pick", "Show interactive picker (requires TTY) - not yet implemented").option("--workspace <id>", "Workspace ID").action(async (shareId, opts, command) => {
20935
+ var resumeCommand2 = new Command35("resume").description("Resume a shared conversation locally in your agent of choice").argument("<share-id>", "The share ID (sc_*) returned by share-convo or save-convo").option("--agent <slug>", "Override target agent (e.g. claude-code, codex)").option("--into <path>", "Override target cwd (defaults to current $PWD)").option("--dry-run", "Print the resume command instead of executing it").option("--pick", "Show interactive picker (requires TTY) - not yet implemented").option("--workspace <name-or-id>", "Workspace name or ID").action(async (shareId, opts, command) => {
20289
20936
  const useJson = shouldOutputJson(command.optsWithGlobals().json);
20290
20937
  const credentials = requireAuth();
20291
20938
  const client = new ApiClient(credentials);
@@ -20510,7 +21157,7 @@ process.on("uncaughtException", (err) => {
20510
21157
  console.error(`Uncaught exception: ${formatError(err)}`);
20511
21158
  process.exit(1);
20512
21159
  });
20513
- var program = new Command34;
21160
+ var program = new Command36;
20514
21161
  program.name("runwork").description("Runwork CLI - local development for Runwork apps").version(VERSION).option("--json", "Output as JSON (auto-enabled when stdout is not a TTY)");
20515
21162
  program.addCommand(infoCommand);
20516
21163
  program.addCommand(loginCommand);
@@ -20539,6 +21186,8 @@ program.addCommand(syncCommand);
20539
21186
  program.addCommand(buildPluginCommand);
20540
21187
  program.addCommand(uninstallCommand);
20541
21188
  program.addCommand(appsCommand);
21189
+ program.addCommand(membersCommand);
21190
+ program.addCommand(apiCommand);
20542
21191
  program.addCommand(doctorCommand);
20543
21192
  program.addCommand(shareConvoCommand);
20544
21193
  program.addCommand(saveConvoCommand);