@miosa/cli 1.0.91 → 1.0.92

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/CHANGELOG.md +12 -4
  2. package/README.md +20 -57
  3. package/dist/bin/miosa.js +0 -2
  4. package/dist/bin/miosa.js.map +1 -1
  5. package/dist/client.d.ts.map +1 -1
  6. package/dist/client.js +21 -2
  7. package/dist/client.js.map +1 -1
  8. package/dist/commands/agent.js +2 -2
  9. package/dist/commands/agent.js.map +1 -1
  10. package/dist/commands/capabilities.d.ts.map +1 -1
  11. package/dist/commands/capabilities.js +59 -86
  12. package/dist/commands/capabilities.js.map +1 -1
  13. package/dist/commands/completion.d.ts.map +1 -1
  14. package/dist/commands/completion.js +1 -12
  15. package/dist/commands/completion.js.map +1 -1
  16. package/dist/commands/computers.d.ts.map +1 -1
  17. package/dist/commands/computers.js +95 -44
  18. package/dist/commands/computers.js.map +1 -1
  19. package/dist/commands/connectors.d.ts.map +1 -1
  20. package/dist/commands/connectors.js +1 -509
  21. package/dist/commands/connectors.js.map +1 -1
  22. package/dist/commands/deploy.d.ts.map +1 -1
  23. package/dist/commands/deploy.js +0 -147
  24. package/dist/commands/deploy.js.map +1 -1
  25. package/dist/commands/devices.d.ts.map +1 -1
  26. package/dist/commands/devices.js +41 -416
  27. package/dist/commands/devices.js.map +1 -1
  28. package/dist/commands/doctor.d.ts +0 -7
  29. package/dist/commands/doctor.d.ts.map +1 -1
  30. package/dist/commands/doctor.js +23 -28
  31. package/dist/commands/doctor.js.map +1 -1
  32. package/dist/commands/mcp.d.ts.map +1 -1
  33. package/dist/commands/mcp.js +8 -106
  34. package/dist/commands/mcp.js.map +1 -1
  35. package/dist/commands/sandbox.d.ts.map +1 -1
  36. package/dist/commands/sandbox.js +51 -187
  37. package/dist/commands/sandbox.js.map +1 -1
  38. package/dist/commands/workspaces.d.ts.map +1 -1
  39. package/dist/commands/workspaces.js +0 -47
  40. package/dist/commands/workspaces.js.map +1 -1
  41. package/package.json +1 -1
@@ -104,9 +104,8 @@ export function register(program) {
104
104
  console.log(JSON.stringify(data, null, 2));
105
105
  return;
106
106
  }
107
- const sb = opts.port != null
108
- ? await showSandboxWithPreview(id, opts.port, opts.probePath)
109
- : (unwrap(await client().apiGet(apiPath(`/sandboxes/${enc(id)}`))) ?? {});
107
+ const raw = unwrap(await client().apiGet(apiPath(`/sandboxes/${enc(id)}`)));
108
+ const sb = (raw ?? {});
110
109
  printBanner({ subtitle: "Sandbox" });
111
110
  const rows = [
112
111
  { label: "ID", value: chalk.bold(str(sb["id"])), icon: icon.info },
@@ -143,23 +142,6 @@ export function register(program) {
143
142
  value: chalk.cyan(str(sb["public_url"])),
144
143
  });
145
144
  }
146
- const preview = asRecord(sb["preview"]);
147
- if (preview?.["url"]) {
148
- rows.push({
149
- label: "Preview URL",
150
- value: chalk.cyan(str(preview["url"])),
151
- });
152
- rows.push({
153
- label: "URL class",
154
- value: str(preview["url_class"] ?? "temporary_preview"),
155
- });
156
- rows.push({
157
- label: "Embeddable",
158
- value: preview["stable_for_embedding"] === true
159
- ? chalk.green("yes")
160
- : chalk.yellow("temporary"),
161
- });
162
- }
163
145
  if (sb["created_at"]) {
164
146
  rows.push({
165
147
  label: "Created",
@@ -391,12 +373,14 @@ export function register(program) {
391
373
  }
392
374
  }));
393
375
  registerSandboxConnectorCommands(sandbox);
394
- // prompt — invoke an in-Sandbox AI agent CLI through the Agent Runs API.
395
- // This keeps the old CLI shape while returning a stable run response shape.
376
+ // prompt — invoke an in-Sandbox AI agent CLI (mirrors `box prompt`).
377
+ // Implemented through Agent Runs so callers get a stable run response while
378
+ // execution still happens inside the remote filesystem.
396
379
  sandbox
397
380
  .command("prompt <sandbox-id> <instruction...>")
398
- .description("Run an in-Sandbox AI agent with the given instruction")
399
- .option("--provider <name>", "AI provider: claude (default), claude-code, codex, hermes, osa, pi")
381
+ .description("Run an in-Sandbox AI agent runtime with the given instruction")
382
+ .option("--provider <name>", "Agent runtime: claude (default), claude-code, codex, pi, hermes, osa, custom")
383
+ .option("--runtime-command <command>", "Executable command for --provider custom, e.g. 'hermes-agent run'")
400
384
  .option("--model <name>", "Provider-specific model name")
401
385
  .option("--connector <uid>", "MIOSA Connect connector UID to preflight before running the agent")
402
386
  .option("--preflight", "Verify the Sandbox has the requested provider connector before exec")
@@ -411,17 +395,13 @@ export function register(program) {
411
395
  .option("--json", "Output as JSON")
412
396
  .action((id, words, opts) => runAction(async () => {
413
397
  const provider = opts.provider ?? "claude";
414
- const allowedProviders = [
415
- "claude",
416
- "claude-code",
417
- "codex",
418
- "hermes",
419
- "osa",
420
- "pi",
421
- ];
422
- if (!allowedProviders.includes(provider)) {
398
+ if (!isSupportedPromptProvider(provider)) {
399
+ const allowedProviders = supportedPromptProviders();
423
400
  throw new Error(`Unsupported provider "${provider}". Use: ${allowedProviders.join(", ")}`);
424
401
  }
402
+ if (opts.runtimeCommand && provider !== "custom") {
403
+ throw new Error("--runtime-command can only be used with --provider custom");
404
+ }
425
405
  if (opts.connector || opts.preflight) {
426
406
  await preflightSandboxConnector(id, {
427
407
  provider,
@@ -437,6 +417,8 @@ export function register(program) {
437
417
  provider,
438
418
  prompt: instruction,
439
419
  };
420
+ if (opts.runtimeCommand)
421
+ body["command"] = opts.runtimeCommand;
440
422
  if (opts.model)
441
423
  body["model"] = opts.model;
442
424
  if (opts.cwd)
@@ -686,7 +668,6 @@ export function register(program) {
686
668
  .option("--sandbox <id>", "Existing sandbox ID. Creates one when omitted")
687
669
  .option("--template <template>", "Template for new sandbox", "miosa-sandbox")
688
670
  .option("--name <name>", "Name for a new sandbox")
689
- .option("--always-on", "Create a new sandbox that keeps running instead of timing out")
690
671
  .option("--port <port>", "Preview port", parseIntegerOption)
691
672
  .option("--publish-port <port>", "Alias for --port", parseIntegerOption)
692
673
  .option("--start <command>", "Start command to run inside /workspace")
@@ -696,13 +677,6 @@ export function register(program) {
696
677
  .option("--revision <revision>", "Git revision/branch for --source git:...")
697
678
  .option("--depth <n>", "Git clone depth for --source git:...", parseIntegerOption)
698
679
  .option("--wait", "Wait until the public preview returns a good HTTP status")
699
- .option("--publish", "Publish the workspace to a durable deployment after preview succeeds")
700
- .option("--slug <slug>", "Deployment slug to use with --publish")
701
- .option("--static", "Publish as a static deployment when using --publish")
702
- .option("--deployment-type <type>", "Deployment runtime type for --publish: miosa_deploy, docker_deploy, dynamic, static")
703
- .option("--domain <domain>", "Custom domain to attach when using --publish")
704
- .option("--build-command <cmd>", "Build command to run before publish")
705
- .option("--run-command <cmd>", "Run command for durable dynamic publish")
706
680
  .option("--timeout <duration>", "Wait timeout, e.g. 180s or 3m", parseDurationSec, 180)
707
681
  .option("--probe-path <path>", "HTTP path to probe")
708
682
  .option("--json", "Output as JSON")
@@ -717,16 +691,10 @@ export function register(program) {
717
691
  console.log(` ${chalk.bold("Sandbox")} ${result.sandbox_id}`);
718
692
  console.log(` ${chalk.bold("Port")} ${result.port}`);
719
693
  console.log(` ${chalk.bold("Preview")} ${chalk.cyan(result.preview_url)}`);
720
- if (result.deployment?.url) {
721
- console.log(` ${chalk.bold("Durable")} ${chalk.cyan(result.deployment.url)}`);
722
- }
723
694
  console.log(` ${chalk.bold("Ready")} ${result.preview_ready
724
695
  ? chalk.green("yes")
725
696
  : chalk.yellow("not verified")}`);
726
697
  console.log();
727
- console.log(chalk.yellow(" This is a timed sandbox preview. Persistent keeps disk; always-on keeps the app running."));
728
- console.log(chalk.dim(` For a durable client link, publish it: miosa sandbox publish ${result.sandbox_id} --path /workspace --slug <slug> --wait`));
729
- console.log();
730
698
  }
731
699
  catch (err) {
732
700
  handleSandboxDeployError(err, opts);
@@ -751,7 +719,6 @@ export function register(program) {
751
719
  return;
752
720
  }
753
721
  console.log(result.url);
754
- printPreviewContractHint(result);
755
722
  if (!result.ready) {
756
723
  console.error(chalk.yellow(`Preview route created but not verified yet (${result.error ?? result.status ?? "pending"}).`));
757
724
  }
@@ -1829,9 +1796,6 @@ async function showSandboxWithPreview(sandboxId, port, probePath) {
1829
1796
  catch (err) {
1830
1797
  preview = {
1831
1798
  url: "",
1832
- url_class: "temporary_preview",
1833
- stable_for_embedding: false,
1834
- recommended_next_action: "create_alias_or_publish",
1835
1799
  ready: false,
1836
1800
  status: null,
1837
1801
  latency_ms: null,
@@ -1844,10 +1808,6 @@ async function showSandboxWithPreview(sandboxId, port, probePath) {
1844
1808
  preview: {
1845
1809
  url: preview?.url || null,
1846
1810
  port,
1847
- url_info: preview?.url_info ?? null,
1848
- url_class: preview?.url_class ?? "temporary_preview",
1849
- stable_for_embedding: preview?.stable_for_embedding ?? false,
1850
- recommended_next_action: preview?.recommended_next_action ?? "create_alias_or_publish",
1851
1811
  route_ready: Boolean(preview?.url),
1852
1812
  tls_ready: preview?.ready ?? false,
1853
1813
  last_status: preview?.status ?? null,
@@ -1870,28 +1830,12 @@ async function previewSandbox(sandboxId, port, opts) {
1870
1830
  : await probePublicPreview(url, opts.probePath);
1871
1831
  return {
1872
1832
  url,
1873
- url_class: stringField(exposed, "url_class") ??
1874
- stringField(exposed, "class") ??
1875
- "temporary_preview",
1876
- stable_for_embedding: booleanField(exposed, "stable_for_embedding") ?? false,
1877
- recommended_next_action: stringField(exposed, "recommended_next_action") ??
1878
- "create_alias_or_publish",
1879
- url_info: objectField(exposed, "url_info") ?? undefined,
1880
1833
  ready: edge.ok,
1881
1834
  status: edge.status,
1882
1835
  latency_ms: edge.latency_ms ?? null,
1883
1836
  error: edge.error,
1884
1837
  };
1885
1838
  }
1886
- function printPreviewContractHint(result) {
1887
- const urlClass = result.url_class ?? "temporary_preview";
1888
- if (result.stable_for_embedding === true) {
1889
- console.error(chalk.dim(`URL class: ${urlClass}, stable for embedding.`));
1890
- return;
1891
- }
1892
- console.error(chalk.yellow(`URL class: ${urlClass}, temporary preview.`));
1893
- console.error(chalk.dim(`For durable client use, next action: ${result.recommended_next_action ?? "create_alias_or_publish"}.`));
1894
- }
1895
1839
  async function waitSandboxReady(sandboxId, port, probePath, timeoutSec) {
1896
1840
  const c = client();
1897
1841
  await waitForSandboxRunning(c, sandboxId, Math.min(timeoutSec, 120));
@@ -2007,7 +1951,6 @@ async function deploySandbox(localDir, opts) {
2007
1951
  source: opts.source,
2008
1952
  revision: opts.revision,
2009
1953
  depth: opts.depth,
2010
- alwaysOn: opts.alwaysOn,
2011
1954
  });
2012
1955
  }
2013
1956
  deployStep(opts, "Waiting for sandbox");
@@ -2048,53 +1991,20 @@ async function deploySandbox(localDir, opts) {
2048
1991
  const internal = await waitForInternalHttp(c, sandboxId, resolvedPort, resolvedProbePath, Math.min(opts.timeout, 60));
2049
1992
  deployStep(opts, "Creating public preview route");
2050
1993
  const exposed = await c.apiPost(apiPath(`/sandboxes/${enc(sandboxId)}/expose`), { port: resolvedPort, title: "app preview" });
2051
- const exposeData = unwrap(exposed);
2052
- const previewUrl = extractUrl(exposeData);
1994
+ const previewUrl = extractUrl(unwrap(exposed));
2053
1995
  if (!previewUrl) {
2054
1996
  throw new UserError("Sandbox expose did not return a preview URL.");
2055
1997
  }
2056
- const previewUrlInfo = objectField(exposeData, "url_info") ?? undefined;
2057
- const previewUrlClass = stringField(exposeData, "url_class") ??
2058
- stringField(exposeData, "class") ??
2059
- "temporary_preview";
2060
- const stableForEmbedding = booleanField(exposeData, "stable_for_embedding") ?? false;
2061
- const recommendedNextAction = stringField(exposeData, "recommended_next_action") ??
2062
- "create_alias_or_publish";
2063
1998
  if (opts.wait)
2064
1999
  deployStep(opts, "Checking public preview readiness");
2065
2000
  const edge = opts.wait
2066
2001
  ? await waitForPublicPreview(previewUrl, resolvedProbePath, opts.timeout)
2067
2002
  : { ok: false, status: null };
2068
- const deployment = opts.publish
2069
- ? await publishSandbox(sandboxId, {
2070
- path: remoteWorkdir,
2071
- name: opts.name,
2072
- slug: opts.slug,
2073
- environment: "production",
2074
- buildCommand: opts.buildCommand,
2075
- runCommand: opts.runCommand,
2076
- domain: opts.domain,
2077
- deploymentType: opts.static
2078
- ? "static"
2079
- : (opts.deploymentType ?? "dynamic"),
2080
- port: resolvedPort,
2081
- wait: opts.wait,
2082
- timeout: opts.timeout,
2083
- json: opts.json,
2084
- })
2085
- : null;
2086
2003
  return {
2087
2004
  sandbox_id: sandboxId,
2088
2005
  port: resolvedPort,
2089
2006
  preview_url: previewUrl,
2090
- preview_url_info: previewUrlInfo,
2091
- preview_url_class: previewUrlClass,
2092
- stable_for_embedding: stableForEmbedding,
2093
- recommended_next_action: recommendedNextAction,
2094
2007
  preview_ready: edge.ok,
2095
- persistent: true,
2096
- always_on: Boolean(opts.alwaysOn),
2097
- deployment,
2098
2008
  internal_status: internal.status,
2099
2009
  edge_status: edge.status,
2100
2010
  latency_ms: edge.latency_ms ?? null,
@@ -2203,25 +2113,6 @@ async function publishSandbox(sandboxId, opts) {
2203
2113
  extractUrl(deployment) ??
2204
2114
  stringField(data, "url") ??
2205
2115
  null;
2206
- let urlInfo = objectField(response, "url_info") ??
2207
- objectField(deployment, "url_info") ??
2208
- objectField(data, "url_info") ??
2209
- null;
2210
- let urlClass = stringField(response, "url_class") ??
2211
- stringField(response, "class") ??
2212
- stringField(deployment, "url_class") ??
2213
- stringField(deployment, "class") ??
2214
- stringField(data, "url_class") ??
2215
- stringField(data, "class") ??
2216
- "durable_deployment";
2217
- let stableForEmbedding = booleanField(response, "stable_for_embedding") ??
2218
- booleanField(deployment, "stable_for_embedding") ??
2219
- booleanField(data, "stable_for_embedding") ??
2220
- true;
2221
- let recommendedNextAction = stringField(response, "recommended_next_action") ??
2222
- stringField(deployment, "recommended_next_action") ??
2223
- stringField(data, "recommended_next_action") ??
2224
- "attach_custom_domain";
2225
2116
  let deploymentProduct = stringField(response, "deployment_product") ??
2226
2117
  stringField(data, "deployment_product") ??
2227
2118
  stringField(deployment, "deployment_product") ??
@@ -2237,15 +2128,6 @@ async function publishSandbox(sandboxId, opts) {
2237
2128
  const waited = await waitForDeploymentReady(c, deploymentId, opts.timeout);
2238
2129
  state = stringField(waited, "state") ?? state;
2239
2130
  url = extractUrl(waited) ?? url;
2240
- urlInfo = objectField(waited, "url_info") ?? urlInfo;
2241
- urlClass =
2242
- stringField(waited, "url_class") ??
2243
- stringField(waited, "class") ??
2244
- urlClass;
2245
- stableForEmbedding =
2246
- booleanField(waited, "stable_for_embedding") ?? stableForEmbedding;
2247
- recommendedNextAction =
2248
- stringField(waited, "recommended_next_action") ?? recommendedNextAction;
2249
2131
  deploymentProduct =
2250
2132
  stringField(waited, "deployment_product") ??
2251
2133
  stringField(asRecord(waited["metadata"]), "deployment_product") ??
@@ -2257,11 +2139,6 @@ async function publishSandbox(sandboxId, opts) {
2257
2139
  response["state"] = state;
2258
2140
  if (url)
2259
2141
  response["url"] = url;
2260
- if (urlInfo)
2261
- response["url_info"] = urlInfo;
2262
- response["url_class"] = urlClass;
2263
- response["stable_for_embedding"] = stableForEmbedding;
2264
- response["recommended_next_action"] = recommendedNextAction;
2265
2142
  data["deployment"] = waited;
2266
2143
  data["promotion_pending"] = false;
2267
2144
  data["app_consistency_pending"] = false;
@@ -2283,10 +2160,6 @@ async function publishSandbox(sandboxId, opts) {
2283
2160
  release_id: releaseId,
2284
2161
  version_id: versionId,
2285
2162
  url,
2286
- url_info: urlInfo ?? undefined,
2287
- url_class: urlClass,
2288
- stable_for_embedding: stableForEmbedding,
2289
- recommended_next_action: recommendedNextAction,
2290
2163
  state,
2291
2164
  deployment_product: deploymentProduct,
2292
2165
  docker_deploy_host_id: dockerDeployHostId,
@@ -2311,7 +2184,7 @@ async function waitForDeploymentReady(c, deploymentId, timeoutSec) {
2311
2184
  await sleep(2000);
2312
2185
  }
2313
2186
  const lastState = last ? String(last["state"] ?? "unknown") : "unknown";
2314
- throw new UserError(`Deployment still building after ${timeoutSec}s — it may still finish. Re-check with \`miosa deploy show ${deploymentId}\` or \`miosa deploy logs ${deploymentId}\`.`, `Last state: ${lastState}`);
2187
+ throw new UserError(`Deployment still building after ${timeoutSec}s — it may still finish. Re-check with \`miosa sandbox show ${deploymentId}\` or \`miosa deploy logs\`.`, `Last state: ${lastState}`);
2315
2188
  }
2316
2189
  function parsePublishDatabase(value) {
2317
2190
  if (!value)
@@ -2349,12 +2222,6 @@ async function doctorSandbox(sandboxId, port, probePath) {
2349
2222
  exposeData = { error: err instanceof Error ? err.message : String(err) };
2350
2223
  }
2351
2224
  const previewUrl = extractUrl(exposeData);
2352
- const urlClass = stringField(exposeData, "url_class") ??
2353
- stringField(exposeData, "class") ??
2354
- "temporary_preview";
2355
- const stableForEmbedding = booleanField(exposeData, "stable_for_embedding") ?? false;
2356
- const recommendedNextAction = stringField(exposeData, "recommended_next_action") ??
2357
- "create_alias_or_publish";
2358
2225
  const edge = previewUrl
2359
2226
  ? await probePublicPreview(previewUrl, probePath)
2360
2227
  : { ok: false, status: null, error: "No preview URL returned" };
@@ -2372,10 +2239,6 @@ async function doctorSandbox(sandboxId, port, probePath) {
2372
2239
  edge_probe: edge,
2373
2240
  preview_ready: edge.ok,
2374
2241
  preview_url: previewUrl,
2375
- url_info: objectField(exposeData, "url_info") ?? null,
2376
- url_class: urlClass,
2377
- stable_for_embedding: stableForEmbedding,
2378
- recommended_next_action: recommendedNextAction,
2379
2242
  expose: exposeData,
2380
2243
  };
2381
2244
  }
@@ -2391,8 +2254,6 @@ function renderDoctorReport(report) {
2391
2254
  console.log(` ${chalk.bold("Preview ready")} ${report["preview_ready"] ? chalk.green("yes") : chalk.red("no")}`);
2392
2255
  if (report["preview_url"]) {
2393
2256
  console.log(` ${chalk.bold("Preview URL")} ${chalk.cyan(String(report["preview_url"]))}`);
2394
- console.log(` ${chalk.bold("URL class")} ${report["url_class"]}`);
2395
- console.log(` ${chalk.bold("Embeddable")} ${report["stable_for_embedding"] === true ? chalk.green("yes") : chalk.yellow("temporary")}`);
2396
2257
  }
2397
2258
  console.log();
2398
2259
  if (!report["preview_ready"]) {
@@ -2588,8 +2449,6 @@ async function createSandboxForDeploy(c, template, name, source) {
2588
2449
  const body = { template_id: template };
2589
2450
  if (name)
2590
2451
  body["name"] = name;
2591
- if (source?.alwaysOn)
2592
- body["always_on"] = true;
2593
2452
  if (source?.source)
2594
2453
  body["source"] = source.source;
2595
2454
  if (source?.revision)
@@ -2860,8 +2719,6 @@ function recoveryCommandForSandboxDeploy(sandboxId, opts, localDir) {
2860
2719
  parts.push("--port", String(opts.port));
2861
2720
  if (opts.publishPort != null)
2862
2721
  parts.push("--publish-port", String(opts.publishPort));
2863
- if (opts.alwaysOn)
2864
- parts.push("--always-on");
2865
2722
  if (opts.installCommand)
2866
2723
  parts.push("--install-command", shellQuote(opts.installCommand));
2867
2724
  if (opts.install === false)
@@ -3217,29 +3074,11 @@ function extractUrl(value) {
3217
3074
  return null;
3218
3075
  const row = value;
3219
3076
  for (const key of ["url", "preview_url", "public_url"]) {
3220
- if (typeof row[key] === "string" && row[key]) {
3221
- return normalizePreviewUrl(row[key]);
3222
- }
3077
+ if (typeof row[key] === "string" && row[key])
3078
+ return row[key];
3223
3079
  }
3224
3080
  return null;
3225
3081
  }
3226
- function normalizePreviewUrl(url) {
3227
- try {
3228
- const parsed = new URL(url);
3229
- parsed.hostname = parsed.hostname.replace(".sandbox.sandbox.preview.", ".sandbox.preview.");
3230
- const normalized = parsed.toString();
3231
- if (parsed.pathname === "/" &&
3232
- !parsed.search &&
3233
- !parsed.hash &&
3234
- !url.endsWith("/")) {
3235
- return normalized.replace(/\/$/, "");
3236
- }
3237
- return normalized;
3238
- }
3239
- catch {
3240
- return url.replace(".sandbox.sandbox.preview.", ".sandbox.preview.");
3241
- }
3242
- }
3243
3082
  function asRecord(value) {
3244
3083
  if (!value || typeof value !== "object" || Array.isArray(value))
3245
3084
  return null;
@@ -3249,13 +3088,6 @@ function stringField(row, key) {
3249
3088
  const value = row?.[key];
3250
3089
  return typeof value === "string" && value.length > 0 ? value : null;
3251
3090
  }
3252
- function booleanField(row, key) {
3253
- const value = row?.[key];
3254
- return typeof value === "boolean" ? value : null;
3255
- }
3256
- function objectField(row, key) {
3257
- return asRecord(row?.[key]);
3258
- }
3259
3091
  function isSandboxTarget(value) {
3260
3092
  const idx = value.indexOf(":");
3261
3093
  if (idx <= 0)
@@ -3370,6 +3202,38 @@ function commandInCwd(command, cwd) {
3370
3202
  return command;
3371
3203
  return `cd ${shellQuote(cwd)} && ${command}`;
3372
3204
  }
3205
+ function supportedPromptProviders() {
3206
+ return [
3207
+ "claude",
3208
+ "claude-code",
3209
+ "codex",
3210
+ "pi",
3211
+ "hermes",
3212
+ "osa",
3213
+ "custom",
3214
+ ];
3215
+ }
3216
+ function runtimeCommandForProvider(provider, runtimeCommand) {
3217
+ const normalized = provider.trim().toLowerCase();
3218
+ if (normalized === "custom") {
3219
+ if (!runtimeCommand?.trim()) {
3220
+ throw new Error("--provider custom requires --runtime-command, e.g. --runtime-command 'hermes-agent run'");
3221
+ }
3222
+ return runtimeCommand.trim();
3223
+ }
3224
+ const builtIns = {
3225
+ claude: "claude",
3226
+ "claude-code": "claude",
3227
+ codex: "codex",
3228
+ pi: "pi",
3229
+ hermes: "hermes",
3230
+ osa: "osa",
3231
+ };
3232
+ return builtIns[normalized] ?? null;
3233
+ }
3234
+ function isSupportedPromptProvider(provider) {
3235
+ return supportedPromptProviders().includes(provider.trim().toLowerCase());
3236
+ }
3373
3237
  function backgroundCommand(command) {
3374
3238
  if (!command.trim())
3375
3239
  return command;