sim 2.1.17 → 2.1.18-dev.129.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.
Files changed (75) hide show
  1. package/dist/auth/device-flow.d.ts +39 -0
  2. package/dist/auth/oauth-flow.d.ts +119 -0
  3. package/dist/auth/refresh.d.ts +16 -0
  4. package/dist/commands/auth.d.ts +5 -0
  5. package/dist/commands/configure.d.ts +2 -0
  6. package/dist/commands/credentials.d.ts +3 -0
  7. package/dist/commands/protocol/chat.d.ts +11 -0
  8. package/dist/commands/protocol/files-get.d.ts +25 -0
  9. package/dist/commands/protocol/files-upload.d.ts +2 -0
  10. package/dist/commands/protocol/index.d.ts +3 -0
  11. package/dist/commands/protocol/knowledge-document-upload.d.ts +2 -0
  12. package/dist/commands/protocol/knowledge-export.d.ts +14 -0
  13. package/dist/commands/protocol/logs-follow.d.ts +39 -0
  14. package/dist/commands/protocol/resource-directory.d.ts +24 -0
  15. package/dist/commands/protocol/result.d.ts +2 -0
  16. package/dist/commands/protocol/tables-import.d.ts +2 -0
  17. package/dist/commands/protocol/workflow-run-follow.d.ts +56 -0
  18. package/dist/commands/protocol/workflow-run-get.d.ts +15 -0
  19. package/dist/commands/protocol/workflow-run-wait.d.ts +3 -0
  20. package/dist/commands/protocol/workspace-operation-wait.d.ts +14 -0
  21. package/dist/commands/secrets.d.ts +3 -0
  22. package/dist/commands/telemetry.d.ts +2 -0
  23. package/dist/commands/update.d.ts +2 -0
  24. package/dist/config/index.d.ts +2 -0
  25. package/dist/config/ini.d.ts +111 -0
  26. package/dist/config/json-file.d.ts +18 -0
  27. package/dist/config/paths.d.ts +29 -0
  28. package/dist/config/profile.d.ts +210 -0
  29. package/dist/context.d.ts +21 -0
  30. package/dist/contract/commands.d.ts +14 -0
  31. package/dist/contract/types.d.ts +306 -0
  32. package/dist/embed-context.d.ts +77 -0
  33. package/dist/embed-output.d.ts +15 -0
  34. package/dist/embed.d.ts +39 -0
  35. package/dist/environment.d.ts +22 -0
  36. package/dist/generated/v2-api.d.ts +15057 -0
  37. package/dist/helpers.d.ts +9 -0
  38. package/dist/http/client.d.ts +173 -0
  39. package/dist/http/environment.d.ts +24 -0
  40. package/dist/http/ndjson.d.ts +5 -0
  41. package/dist/index.js +809 -327
  42. package/dist/output/io.d.ts +5 -0
  43. package/dist/output/presentation.d.ts +4 -0
  44. package/dist/output/render.d.ts +60 -0
  45. package/dist/output/terminal-text.d.ts +17 -0
  46. package/dist/output/trace.d.ts +3 -0
  47. package/dist/output/truncation.d.ts +3 -0
  48. package/dist/program.d.ts +21 -0
  49. package/dist/runtime/build.d.ts +38 -0
  50. package/dist/runtime/derive.d.ts +20 -0
  51. package/dist/runtime/execute.d.ts +32 -0
  52. package/dist/runtime/naming.d.ts +25 -0
  53. package/dist/runtime/options.d.ts +9 -0
  54. package/dist/runtime/renamed.d.ts +6 -0
  55. package/dist/runtime/request.d.ts +110 -0
  56. package/dist/runtime/result.d.ts +41 -0
  57. package/dist/runtime/types.d.ts +23 -0
  58. package/dist/runtime.d.ts +5 -0
  59. package/dist/runtime.js +21854 -0
  60. package/dist/telemetry/client-info.d.ts +20 -0
  61. package/dist/telemetry/coding-agent.d.ts +31 -0
  62. package/dist/telemetry/index.d.ts +4 -0
  63. package/dist/telemetry/invocation.d.ts +98 -0
  64. package/dist/telemetry/policy.d.ts +38 -0
  65. package/dist/telemetry/state.d.ts +47 -0
  66. package/dist/telemetry/transport.d.ts +47 -0
  67. package/dist/terminal/secret-input.d.ts +15 -0
  68. package/dist/terminal.d.ts +7 -0
  69. package/dist/transfer/local-file.d.ts +16 -0
  70. package/dist/transfer/streaming-upload.d.ts +16 -0
  71. package/dist/transfer/upload-session.d.ts +18 -0
  72. package/dist/update/check.d.ts +53 -0
  73. package/dist/update/install.d.ts +20 -0
  74. package/dist/version.d.ts +10 -0
  75. package/package.json +12 -2
package/dist/index.js CHANGED
@@ -3692,6 +3692,12 @@ var applyOptions = (object, options = {}) => {
3692
3692
  const colorLevel = stdoutColor ? stdoutColor.level : 0;
3693
3693
  object.level = options.level === undefined ? colorLevel : options.level;
3694
3694
  };
3695
+
3696
+ class Chalk {
3697
+ constructor(options) {
3698
+ return chalkFactory(options);
3699
+ }
3700
+ }
3695
3701
  var chalkFactory = (options) => {
3696
3702
  const chalk = (...strings) => strings.join(" ");
3697
3703
  applyOptions(chalk, options);
@@ -3820,6 +3826,56 @@ var chalk = createChalk();
3820
3826
  var chalkStderr = createChalk({ level: stderrColor ? stderrColor.level : 0 });
3821
3827
  var source_default = chalk;
3822
3828
 
3829
+ // src/embed-context.ts
3830
+ import { AsyncLocalStorage } from "node:async_hooks";
3831
+ function setSoftExitCode(code) {
3832
+ const ctx = embedStore.getStore();
3833
+ if (ctx)
3834
+ ctx.softExitCode = code;
3835
+ else
3836
+ process.exitCode = code;
3837
+ }
3838
+ var embedStore = new AsyncLocalStorage;
3839
+
3840
+ class EmbeddedExit extends Error {
3841
+ code;
3842
+ constructor(code) {
3843
+ super(`CLI exited with code ${code}`);
3844
+ this.code = code;
3845
+ }
3846
+ }
3847
+ function embeddedProfile() {
3848
+ const ctx = embedStore.getStore();
3849
+ if (!ctx)
3850
+ return null;
3851
+ return {
3852
+ name: "embedded",
3853
+ authProfile: "embedded",
3854
+ oauth: null,
3855
+ endpoint: ctx.identity.endpoint,
3856
+ apiKey: ctx.identity.apiKey,
3857
+ workspaceId: ctx.identity.workspaceId ?? null,
3858
+ output: "json",
3859
+ ...ctx.identity.transport ? { transport: ctx.identity.transport } : {},
3860
+ ...ctx.identity.signal ? { signal: ctx.identity.signal } : {},
3861
+ sources: { endpoint: "flag", credential: "flag", workspaceId: "flag", output: "flag" }
3862
+ };
3863
+ }
3864
+ function exitCli(code) {
3865
+ if (embedStore.getStore())
3866
+ throw new EmbeddedExit(code);
3867
+ return process.exit(code);
3868
+ }
3869
+
3870
+ // src/output/presentation.ts
3871
+ var plain = new Chalk({ level: 0 });
3872
+ function styles3() {
3873
+ return embedStore.getStore() ? plain : source_default;
3874
+ }
3875
+ function hasProgressTerminal() {
3876
+ return !embedStore.getStore() && Boolean(process.stderr.isTTY);
3877
+ }
3878
+
3823
3879
  // node_modules/js-yaml/dist/js-yaml.mjs
3824
3880
  function getDefaultExportFromCjs(x) {
3825
3881
  return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, "default") ? x["default"] : x;
@@ -6962,15 +7018,6 @@ function getErrorMessage(value, fallback) {
6962
7018
  return fallback ?? String(value);
6963
7019
  }
6964
7020
 
6965
- // ../utils/src/object.ts
6966
- function omit(obj, keys) {
6967
- const result = { ...obj };
6968
- for (const key of keys) {
6969
- delete result[key];
6970
- }
6971
- return result;
6972
- }
6973
-
6974
7021
  // src/update/install.ts
6975
7022
  var import_proper_lockfile = __toESM(require_proper_lockfile(), 1);
6976
7023
 
@@ -7103,14 +7150,22 @@ function childProcessEnv(strip, extra = {}) {
7103
7150
  // src/version.ts
7104
7151
  import { readFileSync } from "node:fs";
7105
7152
  function readPackageVersion() {
7106
- const metadata = JSON.parse(readFileSync(new URL("../package.json", import.meta.url), "utf8"));
7107
- if (typeof metadata !== "object" || metadata === null || !("version" in metadata) || typeof metadata.version !== "string") {
7108
- throw new Error("CLI package metadata is missing a valid version");
7109
- }
7110
- return metadata.version;
7153
+ try {
7154
+ const metadata = JSON.parse(readFileSync(new URL("../package.json", import.meta.url), "utf8"));
7155
+ if (typeof metadata === "object" && metadata !== null && "version" in metadata && typeof metadata.version === "string") {
7156
+ return metadata.version;
7157
+ }
7158
+ } catch {}
7159
+ return "0.0.0-embedded";
7160
+ }
7161
+ var cachedVersion = null;
7162
+ function cliVersion() {
7163
+ cachedVersion ??= readPackageVersion();
7164
+ return cachedVersion;
7165
+ }
7166
+ function userAgent() {
7167
+ return `sim-cli/${cliVersion()} node/${process.versions.node} (${process.platform}; ${process.arch})`;
7111
7168
  }
7112
- var CLI_VERSION = readPackageVersion();
7113
- var USER_AGENT = `sim-cli/${CLI_VERSION} node/${process.versions.node} (${process.platform}; ${process.arch})`;
7114
7169
 
7115
7170
  // src/update/check.ts
7116
7171
  var CHECK_INTERVAL_MS = 24 * 60 * 60 * 1000;
@@ -7243,7 +7298,7 @@ async function fetchDistTags(env, request) {
7243
7298
  if (!url)
7244
7299
  return null;
7245
7300
  const text = await request(url, {
7246
- headers: { accept: "application/json", "user-agent": `${PACKAGE_NAME}-cli/${CLI_VERSION}` },
7301
+ headers: { accept: "application/json", "user-agent": `${PACKAGE_NAME}-cli/${cliVersion()}` },
7247
7302
  maxResponseBytes: MAX_RESPONSE_BYTES,
7248
7303
  timeoutMs: REGISTRY_TIMEOUT_MS
7249
7304
  });
@@ -7315,7 +7370,7 @@ async function announceUpdateIfAvailable(options = {}) {
7315
7370
  return;
7316
7371
  if (isUnadvisableInstall(modulePath, env, cwd))
7317
7372
  return;
7318
- const currentVersion = options.currentVersion ?? CLI_VERSION;
7373
+ const currentVersion = options.currentVersion ?? cliVersion();
7319
7374
  const current = parseStableVersion(currentVersion);
7320
7375
  if (!current)
7321
7376
  return;
@@ -7438,7 +7493,7 @@ function parseRegistryVersion(output, manager) {
7438
7493
  }
7439
7494
  async function installUpdate(options = {}) {
7440
7495
  const modulePath = resolveInstallationPath(options.modulePath ?? fileURLToPath2(import.meta.url));
7441
- const env = omit(options.env ?? process.env, ["SIM_API_KEY"]);
7496
+ const env = { ...options.env ?? process.env, SIM_API_KEY: undefined };
7442
7497
  const normalized = modulePath.replaceAll("\\", "/").toLowerCase();
7443
7498
  if (env.npm_command === "exec" || normalized.includes("/_npx/") || normalized.includes("/bunx-") || !normalized.endsWith("/node_modules/sim/dist/index.js")) {
7444
7499
  throw new CliUpdateError("sim update requires a global installation. Update project dependencies with their package manager, or use sim@latest with your package runner.");
@@ -7449,7 +7504,7 @@ async function installUpdate(options = {}) {
7449
7504
  }
7450
7505
  const packageManager = manager;
7451
7506
  const run = options.run ?? runPackageManager;
7452
- const currentVersion = options.currentVersion ?? CLI_VERSION;
7507
+ const currentVersion = options.currentVersion ?? cliVersion();
7453
7508
  const current = parseReleaseVersion(currentVersion);
7454
7509
  const target = current.channel;
7455
7510
  const write = options.write ?? ((message) => void process.stderr.write(message));
@@ -7516,7 +7571,7 @@ async function installUpdate(options = {}) {
7516
7571
  }
7517
7572
  // src/config/profile.ts
7518
7573
  var import_proper_lockfile2 = __toESM(require_proper_lockfile(), 1);
7519
- import { AsyncLocalStorage } from "node:async_hooks";
7574
+ import { AsyncLocalStorage as AsyncLocalStorage2 } from "node:async_hooks";
7520
7575
  import { createHash } from "node:crypto";
7521
7576
  import {
7522
7577
  chmodSync,
@@ -7850,7 +7905,7 @@ function readStoredCredential(profile) {
7850
7905
  var CREDENTIALS_LOCK_STALE_MS = 30000;
7851
7906
  var CREDENTIALS_LOCK_WAIT_MS = 20000;
7852
7907
  var CREDENTIALS_LOCK_POLL_MS = 50;
7853
- var heldLock = new AsyncLocalStorage;
7908
+ var heldLock = new AsyncLocalStorage2;
7854
7909
  async function withProfileLoginLease(profile, work) {
7855
7910
  const digest = createHash("sha256").update(profile, "utf8").digest("hex");
7856
7911
  const path = `${credentialsPath()}.login-${digest}`;
@@ -7964,6 +8019,9 @@ function refuseBlankOverrides(overrides) {
7964
8019
  }
7965
8020
  }
7966
8021
  function resolveProfile(overrides = {}) {
8022
+ const embedded = embeddedProfile();
8023
+ if (embedded)
8024
+ return embedded;
7967
8025
  refuseBlankOverrides(overrides);
7968
8026
  const named = overrides.profile || process.env.SIM_PROFILE;
7969
8027
  const name = named || DEFAULT_PROFILE;
@@ -8021,6 +8079,39 @@ function resolveProfile(overrides = {}) {
8021
8079
  }
8022
8080
  };
8023
8081
  }
8082
+ // src/output/io.ts
8083
+ import { format } from "node:util";
8084
+ function printLine(...args) {
8085
+ const context = embedStore.getStore();
8086
+ if (context)
8087
+ context.stdout.write(`${format(...args)}
8088
+ `);
8089
+ else
8090
+ console.log(...args);
8091
+ }
8092
+ function printError(...args) {
8093
+ const context = embedStore.getStore();
8094
+ if (context)
8095
+ context.stderr.write(`${format(...args)}
8096
+ `);
8097
+ else
8098
+ console.error(...args);
8099
+ }
8100
+ function writeStdout(chunk) {
8101
+ const context = embedStore.getStore();
8102
+ if (!context)
8103
+ return process.stdout.write(chunk);
8104
+ context.stdout.write(chunk);
8105
+ return true;
8106
+ }
8107
+ function writeStderr(chunk) {
8108
+ const context = embedStore.getStore();
8109
+ if (!context)
8110
+ return process.stderr.write(chunk);
8111
+ context.stderr.write(chunk);
8112
+ return true;
8113
+ }
8114
+
8024
8115
  // ../utils/src/client-info.ts
8025
8116
  var CLIENT_INFO_HEADER = "x-sim-client-info";
8026
8117
  var SIM_SURFACES = ["web", "desktop", "cli", "sdk-js", "sdk-python"];
@@ -8192,12 +8283,12 @@ function clientInfoHeader(env = process.env) {
8192
8283
  return cached;
8193
8284
  }
8194
8285
  function identityHeaders() {
8195
- return { "user-agent": USER_AGENT, [CLIENT_INFO_HEADER]: clientInfoHeader() };
8286
+ return { "user-agent": userAgent(), [CLIENT_INFO_HEADER]: clientInfoHeader() };
8196
8287
  }
8197
8288
  function buildClientInfoHeader(env) {
8198
8289
  return formatClientInfo({
8199
8290
  surface: "cli",
8200
- version: CLI_VERSION,
8291
+ version: cliVersion(),
8201
8292
  runtime: { name: "node", version: process.versions.node },
8202
8293
  os: process.platform,
8203
8294
  arch: process.arch,
@@ -8214,7 +8305,7 @@ function once(key, message) {
8214
8305
  if (reported.has(key))
8215
8306
  return;
8216
8307
  reported.add(key);
8217
- process.stderr.write(`warning: ${message}
8308
+ writeStderr(`warning: ${message}
8218
8309
  `);
8219
8310
  }
8220
8311
  var PROXY_VARIABLES = ["HTTPS_PROXY", "https_proxy", "HTTP_PROXY", "http_proxy"];
@@ -8406,7 +8497,7 @@ function debugEnabled(env = process.env) {
8406
8497
  return raw !== undefined && raw !== "" && raw !== "0" && raw.toLowerCase() !== "false";
8407
8498
  }
8408
8499
  function traceRequest(method, url, status, startedAt) {
8409
- process.stderr.write(`${source_default.dim(`[sim] ${method} ${url} → ${status} ${Math.round(performance.now() - startedAt)}ms`)}
8500
+ writeStderr(`${styles3().dim(`[sim] ${method} ${url} → ${status} ${Math.round(performance.now() - startedAt)}ms`)}
8410
8501
  `);
8411
8502
  }
8412
8503
  function withoutLeadingLabel(message, label) {
@@ -8534,12 +8625,15 @@ class SimClient {
8534
8625
  warnIfCredentialOverCleartext(this.profile.endpoint, Boolean(credential));
8535
8626
  const timeoutMs = resolveTimeoutMs();
8536
8627
  const timeout = timeoutMs > 0 ? AbortSignal.timeout(timeoutMs) : undefined;
8537
- const signal = combineSignals(options.signal, timeout);
8628
+ const caller = combineSignals(options.signal, this.profile.signal);
8629
+ if (caller?.aborted)
8630
+ throw new SimApiError("Request cancelled.", 0);
8631
+ const signal = combineSignals(caller, timeout);
8538
8632
  const trace = debugEnabled();
8539
8633
  const startedAt = performance.now();
8540
8634
  let response;
8541
8635
  try {
8542
- response = await fetch(url, {
8636
+ response = await (this.profile.transport ?? fetch)(url, {
8543
8637
  method,
8544
8638
  headers: {
8545
8639
  ...credential?.kind === "api_key" ? { "x-api-key": credential.apiKey } : {},
@@ -8556,7 +8650,7 @@ class SimClient {
8556
8650
  } catch (cause) {
8557
8651
  if (trace)
8558
8652
  traceRequest(method, url, "failed", startedAt);
8559
- if (options.signal?.aborted) {
8653
+ if (caller?.aborted) {
8560
8654
  throw new SimApiError("Request cancelled.", 0);
8561
8655
  }
8562
8656
  if (timeout?.aborted) {
@@ -8615,14 +8709,14 @@ function pageProgress() {
8615
8709
  let reported = false;
8616
8710
  return {
8617
8711
  advance: (fetched) => {
8618
- if (!process.stderr.isTTY)
8712
+ if (!hasProgressTerminal())
8619
8713
  return;
8620
8714
  reported = true;
8621
- process.stderr.write(`\r${source_default.dim(`fetched ${fetched}…`)}\x1B[K`);
8715
+ writeStderr(`\r${styles3().dim(`fetched ${fetched}…`)}\x1B[K`);
8622
8716
  },
8623
8717
  finish: () => {
8624
8718
  if (reported)
8625
- process.stderr.write("\r\x1B[K");
8719
+ writeStderr("\r\x1B[K");
8626
8720
  }
8627
8721
  };
8628
8722
  }
@@ -9046,7 +9140,6 @@ function isWideCodePoint(codePoint) {
9046
9140
 
9047
9141
  // src/output/render.ts
9048
9142
  var EMPTY_GLYPH = "—";
9049
- var EMPTY = source_default.dim(EMPTY_GLYPH);
9050
9143
  var ESC = String.fromCharCode(27);
9051
9144
  var CONTROL_PATTERN = new RegExp([
9052
9145
  `${ESC}\\][^\\u0007${ESC}]*(?:\\u0007|${ESC}\\\\)?`,
@@ -9065,12 +9158,12 @@ function safeOneLine(value) {
9065
9158
  }
9066
9159
  function text(value) {
9067
9160
  if (value === null || value === undefined || value === "")
9068
- return EMPTY;
9161
+ return styles3().dim(EMPTY_GLYPH);
9069
9162
  return sanitize(String(value));
9070
9163
  }
9071
9164
  function timestamp2(value) {
9072
9165
  if (!value)
9073
- return EMPTY;
9166
+ return styles3().dim(EMPTY_GLYPH);
9074
9167
  const date = new Date(value);
9075
9168
  if (Number.isNaN(date.getTime()))
9076
9169
  return sanitize(String(value));
@@ -9078,12 +9171,12 @@ function timestamp2(value) {
9078
9171
  }
9079
9172
  function bool2(value) {
9080
9173
  if (value === null || value === undefined)
9081
- return EMPTY;
9082
- return value ? source_default.green("yes") : source_default.dim("no");
9174
+ return styles3().dim(EMPTY_GLYPH);
9175
+ return value ? styles3().green("yes") : styles3().dim("no");
9083
9176
  }
9084
9177
  function bytes(value) {
9085
9178
  if (value === null || value === undefined)
9086
- return EMPTY;
9179
+ return styles3().dim(EMPTY_GLYPH);
9087
9180
  const units = ["B", "KB", "MB", "GB", "TB"];
9088
9181
  let size = value;
9089
9182
  let unit = 0;
@@ -9095,7 +9188,7 @@ function bytes(value) {
9095
9188
  }
9096
9189
  function duration(ms) {
9097
9190
  if (ms === null || ms === undefined)
9098
- return EMPTY;
9191
+ return styles3().dim(EMPTY_GLYPH);
9099
9192
  if (ms < 1000)
9100
9193
  return `${Math.round(ms)}ms`;
9101
9194
  if (ms < 60000)
@@ -9126,11 +9219,11 @@ function clamp(value, width) {
9126
9219
  }
9127
9220
  function renderTable(rows, columns) {
9128
9221
  if (rows.length === 0)
9129
- return source_default.dim("No results.");
9222
+ return styles3().dim("No results.");
9130
9223
  const headers = columns.map((column) => sanitize(column.header));
9131
9224
  const cells = rows.map((row) => columns.map((column) => clamp(oneLine(column.value(row)), MAX_CELL_WIDTH)));
9132
9225
  const widths = columns.map((_column, index) => Math.max(visibleWidth(headers[index]), ...cells.map((line) => visibleWidth(line[index]))));
9133
- const header = headers.map((label, index) => source_default.dim(pad(label.toUpperCase(), widths[index]))).join(" ").trimEnd();
9226
+ const header = headers.map((label, index) => styles3().dim(pad(label.toUpperCase(), widths[index]))).join(" ").trimEnd();
9134
9227
  const body = cells.map((line) => line.map((cell, index) => pad(cell, widths[index])).join(" ").trimEnd());
9135
9228
  return [header, ...body].join(`
9136
9229
  `);
@@ -9145,36 +9238,36 @@ function renderMachine(format, raw) {
9145
9238
  function printList(format, rows, columns, raw = rows) {
9146
9239
  const machine = renderMachine(format, raw);
9147
9240
  if (machine !== null) {
9148
- console.log(machine);
9241
+ printLine(machine);
9149
9242
  return;
9150
9243
  }
9151
9244
  if (format === "text") {
9152
9245
  for (const row of rows) {
9153
- console.log(columns.map((column) => oneLine(stripAnsi(column.value(row)))).join("\t"));
9246
+ printLine(columns.map((column) => oneLine(stripAnsi(column.value(row)))).join("\t"));
9154
9247
  }
9155
9248
  return;
9156
9249
  }
9157
- console.log(renderTable(rows, columns));
9250
+ printLine(renderTable(rows, columns));
9158
9251
  }
9159
9252
  function printDocument(format, raw) {
9160
- console.log(format === "yaml" ? renderMachine("yaml", raw) : JSON.stringify(raw, null, 2));
9253
+ printLine(format === "yaml" ? renderMachine("yaml", raw) : JSON.stringify(raw, null, 2));
9161
9254
  }
9162
9255
  function printRecord(format, fields, raw) {
9163
9256
  const machine = renderMachine(format, raw);
9164
9257
  if (machine !== null) {
9165
- console.log(machine);
9258
+ printLine(machine);
9166
9259
  return;
9167
9260
  }
9168
9261
  const safeFields = fields.map(([label, value]) => [safeOneLine(label), value]);
9169
9262
  if (format === "text") {
9170
9263
  for (const [label, value] of safeFields) {
9171
- console.log(`${label} ${oneLine(stripAnsi(value))}`);
9264
+ printLine(`${label} ${oneLine(stripAnsi(value))}`);
9172
9265
  }
9173
9266
  return;
9174
9267
  }
9175
9268
  const width = Math.max(...safeFields.map(([label]) => visibleWidth(label)));
9176
9269
  for (const [label, value] of safeFields) {
9177
- console.log(`${source_default.dim(pad(`${label}:`, width + 1))} ${clamp(oneLine(value), MAX_RECORD_WIDTH)}`);
9270
+ printLine(`${styles3().dim(pad(`${label}:`, width + 1))} ${clamp(oneLine(value), MAX_RECORD_WIDTH)}`);
9178
9271
  }
9179
9272
  }
9180
9273
 
@@ -9289,7 +9382,7 @@ async function pollForKey(endpoint, auth, signal) {
9289
9382
  consecutiveTransportFailures++;
9290
9383
  if (!warnedAboutTransport && consecutiveTransportFailures >= TRANSPORT_FAILURES_BEFORE_WARNING) {
9291
9384
  warnedAboutTransport = true;
9292
- process.stderr.write(`Still waiting: ${endpoint} is not answering the login poll (${cause.message}). Check the endpoint; retrying until you approve or the login times out.
9385
+ writeStderr(`Still waiting: ${endpoint} is not answering the login poll (${cause.message}). Check the endpoint; retrying until you approve or the login times out.
9293
9386
  `);
9294
9387
  }
9295
9388
  }
@@ -9420,8 +9513,8 @@ var V2_OPERATIONS = {
9420
9513
  },
9421
9514
  outputColumns: {
9422
9515
  kind: "array",
9423
- required: true,
9424
- describe: "Columns created for producer outputs."
9516
+ default: [],
9517
+ describe: "Columns to create for producer outputs. An entry naming a column the table already has attaches that column to the group instead of creating it (its `type` must match), and an output whose column already exists may omit its entry entirely — so `[]` attaches existing columns only."
9425
9518
  },
9426
9519
  autoRun: {
9427
9520
  kind: "boolean",
@@ -9462,7 +9555,7 @@ var V2_OPERATIONS = {
9462
9555
  query: {
9463
9556
  dryRun: {
9464
9557
  kind: "boolean",
9465
- describe: "Validate and lint without persisting. The response is identical to the committed write of the same body, so a caller can inspect `lint` and then re-send the request for real. Nothing is written, no audit entry is recorded, and collaborators are not notified."
9558
+ describe: "Validate and lint without writing, auditing, or notifying collaborators. Returns the same validation, preparation warnings, lint findings, and ID-ownership conflicts (`409`) as a committed write. `needsRedeployment` describes the pre-write state. For semantic operations, `mintedBlockIds` is empty; `previewBlockIds` contains provisional IDs with a warning, since committing mints new IDs."
9466
9559
  }
9467
9560
  },
9468
9561
  body: {
@@ -9507,7 +9600,7 @@ var V2_OPERATIONS = {
9507
9600
  summary: "Delete Files",
9508
9601
  body: {
9509
9602
  workspaceId: { kind: "string", required: true, describe: "Workspace containing the files." },
9510
- fileIds: { kind: "array", required: true, describe: "File identifiers to update." }
9603
+ fileIds: { kind: "array", required: true, describe: "File identifiers to delete." }
9511
9604
  }
9512
9605
  },
9513
9606
  bulkDeleteTables: {
@@ -9725,7 +9818,7 @@ var V2_OPERATIONS = {
9725
9818
  rowId: { kind: "string", describe: "Row whose runs should be canceled for row scope." },
9726
9819
  filter: {
9727
9820
  kind: "unknown",
9728
- describe: "Recursive non-empty `all`/`any` groups containing groups or conditions; the root cannot be a condition. Limits: 100 members per group, 10 levels, and 500 nodes. The negating operators include nulls and absent cells, multi-select included; combine with `isNotNull` or `isNotEmpty` to exclude them. Pattern operators use `*` as the only wildcard; `%`, `_`, and backslash are literal. Select operators: single-select uses `eq`/`ne`/`in`/`nin`; multi-select uses `contains`/`ncontains`; option names resolve to IDs. Full operand rules are documented on `op`."
9821
+ describe: "One condition or a recursive `all`/`any` group, normalized to a grouped predicate. Limits: 100 members per group, 10 levels, and 500 nodes. The negating operators include nulls and absent cells, multi-select included; combine with `isNotNull` or `isNotEmpty` to exclude them. Pattern operators use `*` as the only wildcard; `%`, `_`, and backslash are literal. Select operators: single-select uses `eq`/`ne`/`in`/`nin`; multi-select uses `contains`/`ncontains`; option names resolve to IDs. Full operand rules are documented on `op`."
9729
9822
  },
9730
9823
  excludeRowIds: { kind: "array", describe: "Rows excluded from an all-scope cancellation." }
9731
9824
  }
@@ -9756,6 +9849,11 @@ var V2_OPERATIONS = {
9756
9849
  conversationId: {
9757
9850
  kind: "string",
9758
9851
  describe: "Conversation to continue; a new one starts when omitted."
9852
+ },
9853
+ effort: {
9854
+ kind: "enum",
9855
+ values: ["low", "medium", "high", "xhigh", "max"],
9856
+ describe: "Model effort for this turn; defaults to the deployment default (high)."
9759
9857
  }
9760
9858
  }
9761
9859
  },
@@ -10318,7 +10416,7 @@ var V2_OPERATIONS = {
10318
10416
  description: { kind: "string", describe: "Optional credential description." },
10319
10417
  id: {
10320
10418
  kind: "string",
10321
- describe: "Required only when provider discovery requests a client-generated ID."
10419
+ describe: "Optional client-generated credential ID. The server mints one when it is omitted, so no provider requires it. A `slack-custom-bot` credential may supply one so its Slack Request URL, which embeds the ID, can be configured before the credential exists; every other provider ignores it."
10322
10420
  },
10323
10421
  credentials: {
10324
10422
  kind: "string",
@@ -10394,7 +10492,7 @@ var V2_OPERATIONS = {
10394
10492
  rowIds: { kind: "array", describe: "Explicit row subset to run." },
10395
10493
  filter: {
10396
10494
  kind: "unknown",
10397
- describe: "Recursive non-empty `all`/`any` groups containing groups or conditions; the root cannot be a condition. Limits: 100 members per group, 10 levels, and 500 nodes. The negating operators include nulls and absent cells, multi-select included; combine with `isNotNull` or `isNotEmpty` to exclude them. Pattern operators use `*` as the only wildcard; `%`, `_`, and backslash are literal. Select operators: single-select uses `eq`/`ne`/`in`/`nin`; multi-select uses `contains`/`ncontains`; option names resolve to IDs. Full operand rules are documented on `op`."
10495
+ describe: "One condition or a recursive `all`/`any` group, normalized to a grouped predicate. Limits: 100 members per group, 10 levels, and 500 nodes. The negating operators include nulls and absent cells, multi-select included; combine with `isNotNull` or `isNotEmpty` to exclude them. Pattern operators use `*` as the only wildcard; `%`, `_`, and backslash are literal. Select operators: single-select uses `eq`/`ne`/`in`/`nin`; multi-select uses `contains`/`ncontains`; option names resolve to IDs. Full operand rules are documented on `op`."
10398
10496
  },
10399
10497
  excludeRowIds: { kind: "array", describe: "Rows excluded from a select-all run scope." },
10400
10498
  limit: { kind: "object", describe: "Optional cap on eligible rows to run." }
@@ -10928,7 +11026,7 @@ var V2_OPERATIONS = {
10928
11026
  workspaceId: { kind: "string", required: true, describe: "Unique workspace identifier." },
10929
11027
  filter: {
10930
11028
  kind: "unknown",
10931
- describe: "Recursive non-empty `all`/`any` groups containing groups or conditions; the root cannot be a condition. Limits: 100 members per group, 10 levels, and 500 nodes. The negating operators include nulls and absent cells, multi-select included; combine with `isNotNull` or `isNotEmpty` to exclude them. Pattern operators use `*` as the only wildcard; `%`, `_`, and backslash are literal. Select operators: single-select uses `eq`/`ne`/`in`/`nin`; multi-select uses `contains`/`ncontains`; option names resolve to IDs. Full operand rules are documented on `op`."
11029
+ describe: "One condition or a recursive `all`/`any` group, normalized to a grouped predicate. Limits: 100 members per group, 10 levels, and 500 nodes. The negating operators include nulls and absent cells, multi-select included; combine with `isNotNull` or `isNotEmpty` to exclude them. Pattern operators use `*` as the only wildcard; `%`, `_`, and backslash are literal. Select operators: single-select uses `eq`/`ne`/`in`/`nin`; multi-select uses `contains`/`ncontains`; option names resolve to IDs. Full operand rules are documented on `op`."
10932
11030
  },
10933
11031
  limit: { kind: "integer", describe: "Maximum matching rows to delete." },
10934
11032
  rowIds: { kind: "array", describe: "Explicit row identifiers to delete." }
@@ -11177,7 +11275,7 @@ var V2_OPERATIONS = {
11177
11275
  },
11178
11276
  selectedOutputs: {
11179
11277
  kind: "array",
11180
- describe: "Output references for streaming: `<blockName>.<outputPath>` or `<childWorkflowId>.<blockName>.<outputPath>`, using normalized block names. Child references apply to every invocation. Requires `stream: true` and rejects synchronous or async requests. Use `selectedOutputs` with Get Workflow Run to narrow an existing run."
11278
+ describe: "Select `<blockName>.<outputPath>` or `<childWorkflowId>.<blockName>.<outputPath>` using normalized block reference names. Child selectors cover every invocation. Synchronous results use selector strings verbatim as `blockOutputs` keys; streaming selections shape the envelope. Unknown block names or IDs return `400` with available blocks before execution. Unexecuted blocks and absent paths are omitted. Incompatible with `async`; select outputs from the finished run resource instead."
11181
11279
  },
11182
11280
  includeThinking: {
11183
11281
  kind: "boolean",
@@ -11239,6 +11337,10 @@ var V2_OPERATIONS = {
11239
11337
  includeReferences: {
11240
11338
  kind: "boolean",
11241
11339
  describe: "Include non-secret resource identifiers and source field occurrences for mapped imports."
11340
+ },
11341
+ includeWorkspaceBindings: {
11342
+ kind: "boolean",
11343
+ describe: "Whether to keep workspace-scoped bindings — table, knowledge base, document, folder, channel, and other resource selectors — in the exported state. Defaults to false, the sharing-safe export in which those ids are cleared because they resolve nowhere else. Send true for a same-workspace round trip so the re-imported workflow can run without re-selecting them. Credentials, passwords, and table sub-block values are cleared either way."
11242
11344
  }
11243
11345
  }
11244
11346
  },
@@ -11487,6 +11589,10 @@ var V2_OPERATIONS = {
11487
11589
  values: ["info", "error"],
11488
11590
  describe: "Severity level to include."
11489
11591
  },
11592
+ includeHandledErrors: {
11593
+ kind: "boolean",
11594
+ describe: "Whether runs with a handled block error are counted as `handledErrorRuns`, and whether `level=error` also selects them. Off by default: counting them scans each run’s stored trace."
11595
+ },
11490
11596
  startDate: {
11491
11597
  kind: "string",
11492
11598
  describe: "Only include runs started at or after this UTC ISO 8601 timestamp, e.g. `2026-08-06T00:00:00Z`. A date without a time, or a timestamp carrying a UTC offset instead of `Z`, is rejected, as is year `0000`, which names no storable instant."
@@ -11498,7 +11604,26 @@ var V2_OPERATIONS = {
11498
11604
  segmentCount: {
11499
11605
  kind: "integer",
11500
11606
  default: 72,
11501
- describe: "Number of time buckets, up to 500. Exactly this many are returned, each at least one minute wide. Short windows extend past the requested end and include empty trailing buckets."
11607
+ describe: "Number of equal time buckets to divide the window into, from 1 to 500. It is the ceiling on how many buckets a series carries: with `includeEmpty=true` exactly this many are returned, otherwise only the buckets holding at least one run. Buckets are never narrower than one minute, so on a short window the series extends past the end of the window rather than being compressed, and the trailing buckets are empty."
11608
+ },
11609
+ includeEmpty: {
11610
+ kind: "enum",
11611
+ values: [
11612
+ "true",
11613
+ "1",
11614
+ "yes",
11615
+ "on",
11616
+ "y",
11617
+ "enabled",
11618
+ "false",
11619
+ "0",
11620
+ "no",
11621
+ "off",
11622
+ "n",
11623
+ "disabled"
11624
+ ],
11625
+ default: false,
11626
+ describe: "Whether buckets with no runs are included in every series. Off by default, so each series carries only the buckets that hold at least one run; set it to publish exactly `segmentCount` buckets per series, empty ones included. The listed spellings are the whole accepted vocabulary and are case-sensitive; any other value is rejected."
11502
11627
  }
11503
11628
  }
11504
11629
  },
@@ -11556,7 +11681,7 @@ var V2_OPERATIONS = {
11556
11681
  groupId: "Workflow or enrichment group to run."
11557
11682
  },
11558
11683
  responseMode: "json",
11559
- summary: "Get Enrichment Run Detail",
11684
+ summary: "Get Row Group Run",
11560
11685
  query: {
11561
11686
  workspaceId: { kind: "string", required: true, describe: "Workspace that owns the table." }
11562
11687
  }
@@ -12166,7 +12291,11 @@ var V2_OPERATIONS = {
12166
12291
  source: {
12167
12292
  kind: "enum",
12168
12293
  values: ["builtin", "custom"],
12169
- describe: "Restrict to built-in blocks or this workspace's deployed custom blocks."
12294
+ describe: "Restrict to shipped blocks or to this workspaces deployed custom blocks."
12295
+ },
12296
+ includeSunset: {
12297
+ kind: "boolean",
12298
+ describe: "Include `legacy` and `deprecated` blocks. Off by default: a sunset block keeps executing where it is already placed, but it is not offered for new authoring. Each returned entry carries `sunset.replacedBy`, the block to build with instead."
12170
12299
  },
12171
12300
  sortBy: {
12172
12301
  kind: "enum",
@@ -12243,6 +12372,21 @@ var V2_OPERATIONS = {
12243
12372
  search: {
12244
12373
  kind: "string",
12245
12374
  describe: "Case-insensitive substring match against the connector name."
12375
+ },
12376
+ detail: {
12377
+ kind: "enum",
12378
+ values: ["summary", "full"],
12379
+ default: "summary",
12380
+ describe: "Projection of each item. `summary` (the default) carries the identifier, name, description, and auth mode; `full` adds the version, the complete auth settings, the `sourceConfig` field schema, incremental-sync support, and tag definitions."
12381
+ },
12382
+ limit: {
12383
+ kind: "integer",
12384
+ default: 25,
12385
+ describe: "Maximum connector types to return per page. Must be a whole number from 1 to 100. Defaults to 25."
12386
+ },
12387
+ cursor: {
12388
+ kind: "string",
12389
+ describe: "Opaque cursor from the previous page. Send it back with the same sort and filters; only `limit` may change. Change anything else and pagination must restart without a cursor."
12246
12390
  }
12247
12391
  }
12248
12392
  },
@@ -12844,6 +12988,10 @@ var V2_OPERATIONS = {
12844
12988
  kind: "string",
12845
12989
  describe: "Opaque cursor from the previous page. Send it back with the same sort and filters; only `limit` may change. Change anything else and pagination must restart without a cursor."
12846
12990
  },
12991
+ includeHandledErrors: {
12992
+ kind: "boolean",
12993
+ describe: "Whether `level=error` also selects runs that finished at `info` after a block error was recovered by an error path. Off by default: such a run succeeded, so it is an error only to a caller auditing error handling. Every row reports `hasHandledErrors` whether or not this is set. Job runs carry no block trace, so the flag never widens that branch."
12994
+ },
12847
12995
  status: {
12848
12996
  kind: "string",
12849
12997
  describe: "Comma-separated execution statuses to include, from `pending` | `running` | `paused` | `redacting` | `completed` | `failed` | `cancelled`. An empty entry is rejected. ANDed with `level`, which reports severity rather than lifecycle."
@@ -13218,7 +13366,7 @@ var V2_OPERATIONS = {
13218
13366
  pathParams: ["tableId"],
13219
13367
  pathParamDocs: { tableId: "Unique table identifier." },
13220
13368
  responseMode: "json",
13221
- summary: "List Active Run Dispatches",
13369
+ summary: "List Run Dispatches",
13222
13370
  query: {
13223
13371
  workspaceId: { kind: "string", required: true, describe: "Workspace that owns the table." }
13224
13372
  }
@@ -13731,8 +13879,8 @@ var V2_OPERATIONS = {
13731
13879
  },
13732
13880
  limit: {
13733
13881
  kind: "integer",
13734
- default: 50,
13735
- describe: "Maximum workspaces to return per page. Must be a whole number from 1 to 100. Defaults to 50."
13882
+ default: 25,
13883
+ describe: "Maximum workspaces to return per page. Must be a whole number from 1 to 100. Defaults to 25."
13736
13884
  },
13737
13885
  cursor: {
13738
13886
  kind: "string",
@@ -14071,7 +14219,9 @@ var V2_OPERATIONS = {
14071
14219
  method: "GET",
14072
14220
  path: "/api/v2/files/[fileId]/text",
14073
14221
  pathParams: ["fileId"],
14074
- pathParamDocs: { fileId: "File identifier." },
14222
+ pathParamDocs: {
14223
+ fileId: "File identifier, or the file’s VFS path: `files/<folder>/<name>`, or `uploads/<name>` for a Chat upload."
14224
+ },
14075
14225
  responseMode: "json",
14076
14226
  summary: "Read File Text",
14077
14227
  query: {
@@ -14102,7 +14252,7 @@ var V2_OPERATIONS = {
14102
14252
  destinationPath: {
14103
14253
  kind: "string",
14104
14254
  required: true,
14105
- describe: "New full path for the folder and its descendants."
14255
+ describe: "Where the folder lands, with `mv` semantics. A path naming an existing folder receives the source as a child under its current name; `/` moves it to the workspace root under its current name; any other path becomes the folder’s new full path (a rename, a relocation, or both)."
14106
14256
  }
14107
14257
  }
14108
14258
  },
@@ -14118,7 +14268,7 @@ var V2_OPERATIONS = {
14118
14268
  destinationPath: {
14119
14269
  kind: "string",
14120
14270
  required: true,
14121
- describe: "New full path for the folder and its descendants."
14271
+ describe: "Where the folder lands, with `mv` semantics. A path naming an existing folder receives the source as a child under its current name; `/` moves it to the workspace root under its current name; any other path becomes the folder’s new full path (a rename, a relocation, or both)."
14122
14272
  }
14123
14273
  }
14124
14274
  },
@@ -14134,7 +14284,7 @@ var V2_OPERATIONS = {
14134
14284
  destinationPath: {
14135
14285
  kind: "string",
14136
14286
  required: true,
14137
- describe: "New full path for the folder and its descendants."
14287
+ describe: "Where the folder lands, with `mv` semantics. A path naming an existing folder receives the source as a child under its current name; `/` moves it to the workspace root under its current name; any other path becomes the folder’s new full path (a rename, a relocation, or both)."
14138
14288
  }
14139
14289
  }
14140
14290
  },
@@ -14150,7 +14300,7 @@ var V2_OPERATIONS = {
14150
14300
  destinationPath: {
14151
14301
  kind: "string",
14152
14302
  required: true,
14153
- describe: "New full path for the folder and its descendants."
14303
+ describe: "Where the folder lands, with `mv` semantics. A path naming an existing folder receives the source as a child under its current name; `/` moves it to the workspace root under its current name; any other path becomes the folder’s new full path (a rename, a relocation, or both)."
14154
14304
  }
14155
14305
  }
14156
14306
  },
@@ -14230,7 +14380,7 @@ var V2_OPERATIONS = {
14230
14380
  query: {
14231
14381
  dryRun: {
14232
14382
  kind: "boolean",
14233
- describe: "Validate and lint without persisting. The response is identical to the committed write of the same body, so a caller can inspect `lint` and then re-send the request for real. Nothing is written, no audit entry is recorded, and collaborators are not notified."
14383
+ describe: "Validate and lint without writing, auditing, or notifying collaborators. Returns the same validation, preparation warnings, lint findings, and ID-ownership conflicts (`409`) as a committed write. `needsRedeployment` describes the pre-write state. For semantic operations, `mintedBlockIds` is empty; `previewBlockIds` contains provisional IDs with a warning, since committing mints new IDs."
14234
14384
  }
14235
14385
  },
14236
14386
  body: {
@@ -14539,7 +14689,7 @@ var V2_OPERATIONS = {
14539
14689
  q: { kind: "string", required: true, describe: "Case-insensitive cell substring to find." },
14540
14690
  predicate: {
14541
14691
  kind: "unknown",
14542
- describe: "Recursive non-empty `all`/`any` groups containing groups or conditions; the root cannot be a condition. Limits: 100 members per group, 10 levels, and 500 nodes. The negating operators include nulls and absent cells, multi-select included; combine with `isNotNull` or `isNotEmpty` to exclude them. Pattern operators use `*` as the only wildcard; `%`, `_`, and backslash are literal. Select operators: single-select uses `eq`/`ne`/`in`/`nin`; multi-select uses `contains`/`ncontains`; option names resolve to IDs. Full operand rules are documented on `op`."
14692
+ describe: "One condition or a recursive `all`/`any` group, normalized to a grouped predicate. Limits: 100 members per group, 10 levels, and 500 nodes. The negating operators include nulls and absent cells, multi-select included; combine with `isNotNull` or `isNotEmpty` to exclude them. Pattern operators use `*` as the only wildcard; `%`, `_`, and backslash are literal. Select operators: single-select uses `eq`/`ne`/`in`/`nin`; multi-select uses `contains`/`ncontains`; option names resolve to IDs. Full operand rules are documented on `op`."
14543
14693
  },
14544
14694
  sort: { kind: "array", describe: "Ordered table-row sort specification." }
14545
14695
  }
@@ -15002,7 +15152,7 @@ var V2_OPERATIONS = {
15002
15152
  filter: {
15003
15153
  kind: "unknown",
15004
15154
  required: true,
15005
- describe: "Recursive non-empty `all`/`any` groups containing groups or conditions; the root cannot be a condition. Limits: 100 members per group, 10 levels, and 500 nodes. The negating operators include nulls and absent cells, multi-select included; combine with `isNotNull` or `isNotEmpty` to exclude them. Pattern operators use `*` as the only wildcard; `%`, `_`, and backslash are literal. Select operators: single-select uses `eq`/`ne`/`in`/`nin`; multi-select uses `contains`/`ncontains`; option names resolve to IDs. Full operand rules are documented on `op`."
15155
+ describe: "One condition or a recursive `all`/`any` group, normalized to a grouped predicate. Limits: 100 members per group, 10 levels, and 500 nodes. The negating operators include nulls and absent cells, multi-select included; combine with `isNotNull` or `isNotEmpty` to exclude them. Pattern operators use `*` as the only wildcard; `%`, `_`, and backslash are literal. Select operators: single-select uses `eq`/`ne`/`in`/`nin`; multi-select uses `contains`/`ncontains`; option names resolve to IDs. Full operand rules are documented on `op`."
15006
15156
  },
15007
15157
  data: {
15008
15158
  kind: "object",
@@ -15466,10 +15616,10 @@ async function chooseWorkspace(client) {
15466
15616
  if (workspaces.length > MAX_INTERACTIVE_WORKSPACES) {
15467
15617
  throw new SimApiError(`The active credential can access more than ${MAX_INTERACTIVE_WORKSPACES} workspaces, which is too many to show interactively. Pass --workspace <id> instead.`, 0);
15468
15618
  }
15469
- console.log(`
15619
+ printLine(`
15470
15620
  Available workspaces:`);
15471
15621
  for (const [index, workspace] of workspaces.entries()) {
15472
- console.log(` ${index + 1}) ${safeOneLine(workspace.name)} (${workspace.id})`);
15622
+ printLine(` ${index + 1}) ${safeOneLine(workspace.name)} (${workspace.id})`);
15473
15623
  }
15474
15624
  const prompt = createInterface({ input: process.stdin, output: process.stderr });
15475
15625
  try {
@@ -15504,10 +15654,10 @@ function addProfileCommand() {
15504
15654
  workspace: normalizedWorkspaceId
15505
15655
  });
15506
15656
  });
15507
- console.log(source_default.green(`✓ Added profile "${safeOneLine(profileName)}" in ${configPath()}`));
15508
- console.log(` Workspace: ${safeOneLine(workspace.name)} (${workspace.id})`);
15509
- console.log(` Authentication: ${safeOneLine(authProfile)}`);
15510
- console.log(source_default.dim(` Try: sim --profile ${safeOneLine(profileName)} whoami`));
15657
+ printLine(styles3().green(`✓ Added profile "${safeOneLine(profileName)}" in ${configPath()}`));
15658
+ printLine(` Workspace: ${safeOneLine(workspace.name)} (${workspace.id})`);
15659
+ printLine(` Authentication: ${safeOneLine(authProfile)}`);
15660
+ printLine(styles3().dim(` Try: sim --profile ${safeOneLine(profileName)} whoami`));
15511
15661
  });
15512
15662
  }
15513
15663
  async function chooseLoginFlow(profile, options) {
@@ -15515,7 +15665,7 @@ async function chooseLoginFlow(profile, options) {
15515
15665
  if (options.method === "api-key")
15516
15666
  return "handoff";
15517
15667
  if (options.method === undefined && isLikelyRemoteSession() && options.callbackPort === undefined) {
15518
- console.log(source_default.dim(`This looks like a remote session; using the pairing code to create a personal API key. To use OAuth, forward a port and pass --method oauth --callback-port <port>.
15668
+ printLine(styles3().dim(`This looks like a remote session; using the pairing code to create a personal API key. To use OAuth, forward a port and pass --method oauth --callback-port <port>.
15519
15669
  `));
15520
15670
  return "handoff";
15521
15671
  }
@@ -15527,7 +15677,7 @@ async function chooseLoginFlow(profile, options) {
15527
15677
  if (options.method === "oauth") {
15528
15678
  throw new SimApiError(`${profile.endpoint} does not offer OAuth sign-in. Enable OAuth on the server or explicitly choose sim login --method api-key.`, 0);
15529
15679
  }
15530
- console.log(source_default.dim(`${profile.endpoint} does not offer OAuth sign-in; using the pairing code to create a personal API key.
15680
+ printLine(styles3().dim(`${profile.endpoint} does not offer OAuth sign-in; using the pairing code to create a personal API key.
15531
15681
  `));
15532
15682
  return "handoff";
15533
15683
  }
@@ -15543,16 +15693,16 @@ function parseCallbackPort(value) {
15543
15693
  return port;
15544
15694
  }
15545
15695
  async function loginWithOAuth(profile, options, callbackPort, expected) {
15546
- console.log(`Signing in to ${source_default.bold(profile.endpoint)} as profile ${source_default.bold(safeOneLine(profile.name))}`);
15696
+ printLine(`Signing in to ${styles3().bold(profile.endpoint)} as profile ${styles3().bold(safeOneLine(profile.name))}`);
15547
15697
  const tokens = await loginWithBrowser(profile.endpoint, {
15548
15698
  scopes: options.readOnly ? OAUTH_SCOPES_READ_ONLY : OAUTH_SCOPES_FULL,
15549
15699
  callbackPort,
15550
15700
  onAuthorizeUrl: (url) => {
15551
- console.log(`
15701
+ printLine(`
15552
15702
  ${url}`);
15553
15703
  if (options.browser)
15554
15704
  openBrowser(url);
15555
- console.log(source_default.dim(`
15705
+ printLine(styles3().dim(`
15556
15706
  Waiting for you to approve in the browser…`));
15557
15707
  }
15558
15708
  });
@@ -15584,7 +15734,7 @@ Waiting for you to approve in the browser…`));
15584
15734
  try {
15585
15735
  writeCredentialsProfile(profile.name, null);
15586
15736
  } catch {}
15587
- console.log(source_default.yellow(`Could not restore the previous profile safely (${safeOneLine(getErrorMessage(rollbackError))}). Its local login was cleared to avoid using it against the wrong endpoint. The new server login will still be revoked.`));
15737
+ printLine(styles3().yellow(`Could not restore the previous profile safely (${safeOneLine(getErrorMessage(rollbackError))}). Its local login was cleared to avoid using it against the wrong endpoint. The new server login will still be revoked.`));
15588
15738
  }
15589
15739
  throw error;
15590
15740
  }
@@ -15593,15 +15743,15 @@ Waiting for you to approve in the browser…`));
15593
15743
  try {
15594
15744
  await revokeToken(profile.endpoint, tokens.refreshToken);
15595
15745
  } catch (revocationError) {
15596
- console.log(source_default.yellow(`Could not revoke the uncommitted login (${safeOneLine(getErrorMessage(revocationError))}). Revoke Sim CLI in Settings → General → Authorized apps.`));
15746
+ printLine(styles3().yellow(`Could not revoke the uncommitted login (${safeOneLine(getErrorMessage(revocationError))}). Revoke Sim CLI in Settings → General → Authorized apps.`));
15597
15747
  }
15598
15748
  throw error;
15599
15749
  }
15600
- console.log(source_default.green(`
15750
+ printLine(styles3().green(`
15601
15751
  ✓ Logged in. Login stored in ${credentialsPath()}`));
15602
- console.log(source_default.dim(grantsWriteAccess(tokens.scope) ? " Renews itself; revoke it any time in Settings → General → Authorized apps, or with: sim logout" : " Read-only login — commands that change anything will be refused."));
15752
+ printLine(styles3().dim(grantsWriteAccess(tokens.scope) ? " Renews itself; revoke it any time in Settings → General → Authorized apps, or with: sim logout" : " Read-only login — commands that change anything will be refused."));
15603
15753
  if (!profile.workspaceId) {
15604
- console.log(source_default.dim(" No default workspace. Set one with: sim configure --set-workspace <id>"));
15754
+ printLine(styles3().dim(" No default workspace. Set one with: sim configure --set-workspace <id>"));
15605
15755
  }
15606
15756
  }
15607
15757
  function loginCommand() {
@@ -15619,7 +15769,7 @@ function loginCommand() {
15619
15769
  if (storedCredential && !options.yes) {
15620
15770
  const confirmed = await confirmProfileOverwrite(profile.name);
15621
15771
  if (!confirmed) {
15622
- console.log(source_default.dim("Login cancelled; the existing profile was not changed."));
15772
+ printLine(styles3().dim("Login cancelled; the existing profile was not changed."));
15623
15773
  return;
15624
15774
  }
15625
15775
  }
@@ -15646,15 +15796,15 @@ function loginCommand() {
15646
15796
  async function loginWithHandoff(profile, options, expected) {
15647
15797
  const auth = createAuthRequest();
15648
15798
  const url = buildApprovalUrl(profile.endpoint, auth, profile.workspaceId ?? undefined);
15649
- console.log(`Signing in to ${source_default.bold(profile.endpoint)} as profile ${source_default.bold(safeOneLine(profile.name))}`);
15650
- console.log(`
15651
- Pairing code: ${source_default.bold(auth.pairing)}`);
15652
- console.log(source_default.dim(`Confirm this code matches what the browser shows before approving.
15799
+ printLine(`Signing in to ${styles3().bold(profile.endpoint)} as profile ${styles3().bold(safeOneLine(profile.name))}`);
15800
+ printLine(`
15801
+ Pairing code: ${styles3().bold(auth.pairing)}`);
15802
+ printLine(styles3().dim(`Confirm this code matches what the browser shows before approving.
15653
15803
  `));
15654
- console.log(url);
15804
+ printLine(url);
15655
15805
  if (options.browser)
15656
15806
  openBrowser(url);
15657
- console.log(source_default.dim(`
15807
+ printLine(styles3().dim(`
15658
15808
  Waiting for approval…`));
15659
15809
  const key = await pollForKey(profile.endpoint, auth);
15660
15810
  try {
@@ -15683,24 +15833,24 @@ Waiting for approval…`));
15683
15833
  try {
15684
15834
  writeCredentialsProfile(profile.name, null);
15685
15835
  } catch {}
15686
- console.log(source_default.yellow(`Could not restore the previous profile safely (${safeOneLine(getErrorMessage(rollbackError))}). Its local login was cleared to avoid using it against the wrong endpoint.`));
15836
+ printLine(styles3().yellow(`Could not restore the previous profile safely (${safeOneLine(getErrorMessage(rollbackError))}). Its local login was cleared to avoid using it against the wrong endpoint.`));
15687
15837
  }
15688
15838
  throw error;
15689
15839
  }
15690
15840
  });
15691
15841
  } catch (error) {
15692
15842
  const keyId = typeof key.id === "string" && key.id ? safeOneLine(key.id) : "unknown";
15693
- console.log(source_default.yellow(`API key ${keyId} was created but could not be stored safely. Revoke it in Settings → API keys.`));
15843
+ printLine(styles3().yellow(`API key ${keyId} was created but could not be stored safely. Revoke it in Settings → API keys.`));
15694
15844
  throw error;
15695
15845
  }
15696
- console.log(source_default.green(`
15846
+ printLine(styles3().green(`
15697
15847
  ✓ Logged in. Key stored in ${credentialsPath()}`));
15698
15848
  if (key.workspaceBound && key.workspaceId) {
15699
- console.log(source_default.dim(` Workspace-scoped key — it can only reach ${key.workspaceId}.`));
15849
+ printLine(styles3().dim(` Workspace-scoped key — it can only reach ${key.workspaceId}.`));
15700
15850
  } else if (key.workspaceId) {
15701
- console.log(source_default.dim(` Personal key, defaulting to ${key.workspaceId}. Override per command with --workspace.`));
15851
+ printLine(styles3().dim(` Personal key, defaulting to ${key.workspaceId}. Override per command with --workspace.`));
15702
15852
  } else {
15703
- console.log(source_default.dim(" Personal key with no default workspace. Set one with: sim configure --set-workspace <id>"));
15853
+ printLine(styles3().dim(" Personal key with no default workspace. Set one with: sim configure --set-workspace <id>"));
15704
15854
  }
15705
15855
  }
15706
15856
  async function revokeStoredOAuth(credential) {
@@ -15718,9 +15868,9 @@ async function revokeStoredOAuth(credential) {
15718
15868
  const endpoint = issuer.toString().replace(/\/$/, "");
15719
15869
  displayEndpoint = safeOneLine(endpoint);
15720
15870
  await revokeToken(endpoint, credential.refreshToken);
15721
- console.log(source_default.dim(" Signed out of Sim; every token from this login was revoked."));
15871
+ printLine(styles3().dim(" Signed out of Sim; every token from this login was revoked."));
15722
15872
  } catch (error) {
15723
- console.log(source_default.yellow(` Could not revoke the login on ${displayEndpoint} (${safeOneLine(getErrorMessage(error))}). Revoke it in Settings → General → Authorized apps.`));
15873
+ printLine(styles3().yellow(` Could not revoke the login on ${displayEndpoint} (${safeOneLine(getErrorMessage(error))}). Revoke it in Settings → General → Authorized apps.`));
15724
15874
  }
15725
15875
  }
15726
15876
  function logoutCommand() {
@@ -15739,12 +15889,12 @@ function logoutCommand() {
15739
15889
  return { removed: deleteProfile(profileName), credential };
15740
15890
  });
15741
15891
  if (!removed.config && !removed.credentials) {
15742
- console.log(source_default.dim(`Nothing stored for profile "${safeOneLine(profileName)}".`));
15892
+ printLine(styles3().dim(`Nothing stored for profile "${safeOneLine(profileName)}".`));
15743
15893
  return;
15744
15894
  }
15745
- console.log(source_default.green(`✓ Removed profile "${safeOneLine(profileName)}".`));
15895
+ printLine(styles3().green(`✓ Removed profile "${safeOneLine(profileName)}".`));
15746
15896
  if (credential?.kind === "api_key") {
15747
- console.log(source_default.dim(" The key itself is still active — revoke it in Settings → API keys."));
15897
+ printLine(styles3().dim(" The key itself is still active — revoke it in Settings → API keys."));
15748
15898
  }
15749
15899
  return;
15750
15900
  }
@@ -15764,12 +15914,12 @@ function logoutCommand() {
15764
15914
  return credential;
15765
15915
  });
15766
15916
  if (!credential) {
15767
- console.log(source_default.dim(`No stored login for profile "${safeOneLine(profileName)}".`));
15917
+ printLine(styles3().dim(`No stored login for profile "${safeOneLine(profileName)}".`));
15768
15918
  return;
15769
15919
  }
15770
- console.log(source_default.green(`✓ Removed the stored login for profile "${safeOneLine(profileName)}".`));
15920
+ printLine(styles3().green(`✓ Removed the stored login for profile "${safeOneLine(profileName)}".`));
15771
15921
  if (credential.kind === "api_key") {
15772
- console.log(source_default.dim(" The key itself is still active — revoke it in Settings → API keys."));
15922
+ printLine(styles3().dim(" The key itself is still active — revoke it in Settings → API keys."));
15773
15923
  }
15774
15924
  });
15775
15925
  }
@@ -15831,18 +15981,18 @@ function presentVerification(verification) {
15831
15981
  if (verification.status === "verified") {
15832
15982
  const { name, memberCount } = verification.workspace;
15833
15983
  const members = `${memberCount} ${memberCount === 1 ? "member" : "members"}`;
15834
- return `${source_default.green("✓")} ${safeOneLine(name)} · ${members}`;
15984
+ return `${styles3().green("✓")} ${safeOneLine(name)} · ${members}`;
15835
15985
  }
15836
15986
  const detail = safeOneLine(verification.detail);
15837
15987
  switch (verification.status) {
15838
15988
  case "rejected":
15839
- return `${source_default.red("✗")} ${detail}`;
15989
+ return `${styles3().red("✗")} ${detail}`;
15840
15990
  case "unauthenticated":
15841
- return source_default.yellow(`not logged in — ${detail}`);
15991
+ return styles3().yellow(`not logged in — ${detail}`);
15842
15992
  case "disabled":
15843
- return source_default.dim(detail);
15993
+ return styles3().dim(detail);
15844
15994
  default:
15845
- return source_default.yellow(`could not check — ${detail}`);
15995
+ return styles3().yellow(`could not check — ${detail}`);
15846
15996
  }
15847
15997
  }
15848
15998
  function whoamiCommand() {
@@ -15856,17 +16006,17 @@ function whoamiCommand() {
15856
16006
  keyType: null,
15857
16007
  detail: "not checked (--no-verify)"
15858
16008
  };
15859
- const annotate = (value, source) => source === "unset" ? source_default.dim("not set") : `${value} ${source_default.dim(`(${source})`)}`;
16009
+ const annotate = (value, source) => source === "unset" ? styles3().dim("not set") : `${value} ${styles3().dim(`(${source})`)}`;
15860
16010
  printRecord(profile.output, [
15861
16011
  ["Profile", profile.name],
15862
16012
  ["Endpoint", annotate(profile.endpoint, sources.endpoint)],
15863
16013
  [
15864
16014
  "Login",
15865
- authentication.authenticated ? annotate(profile.oauth ? "OAuth" : "API key", authentication.source) : source_default.yellow("not logged in")
16015
+ authentication.authenticated ? annotate(profile.oauth ? "OAuth" : "API key", authentication.source) : styles3().yellow("not logged in")
15866
16016
  ],
15867
16017
  [
15868
16018
  "Key type",
15869
- verification.keyType ?? source_default.dim(options.verify ? "unknown" : "not checked (--no-verify)")
16019
+ verification.keyType ?? styles3().dim(options.verify ? "unknown" : "not checked (--no-verify)")
15870
16020
  ],
15871
16021
  ["Workspace", annotate(profile.workspaceId ?? "", sources.workspaceId)],
15872
16022
  ["Output", annotate(profile.output, sources.output)],
@@ -15892,15 +16042,15 @@ function whoamiCommand() {
15892
16042
  });
15893
16043
  const exitCode = WHOAMI_EXIT_CODES[verification.status];
15894
16044
  if (exitCode !== 0)
15895
- process.exitCode = exitCode;
16045
+ setSoftExitCode(exitCode);
15896
16046
  });
15897
16047
  }
15898
16048
  var PROFILE_COLUMNS = [
15899
- { header: "", value: (row) => row.active ? source_default.green("*") : " " },
16049
+ { header: "", value: (row) => row.active ? styles3().green("*") : " " },
15900
16050
  { header: "profile", value: (row) => safeOneLine(row.name) },
15901
16051
  { header: "key", value: (row) => row.error ? text(null) : row.hasKey ? "yes" : "no" },
15902
16052
  { header: "auth", value: (row) => row.authProfile ? safeOneLine(row.authProfile) : text(null) },
15903
- { header: "error", value: (row) => row.error ? source_default.red(safeOneLine(row.error)) : text(null) }
16053
+ { header: "error", value: (row) => row.error ? styles3().red(safeOneLine(row.error)) : text(null) }
15904
16054
  ];
15905
16055
  function buildProfileRow(name, active) {
15906
16056
  try {
@@ -15947,7 +16097,7 @@ function profilesCommand() {
15947
16097
  const rows = listProfiles().map((name) => buildProfileRow(name, name === activeName));
15948
16098
  if (rows.length === 0) {
15949
16099
  if (output === "table")
15950
- console.log(source_default.dim("No profiles yet. Run: sim login"));
16100
+ printLine(styles3().dim("No profiles yet. Run: sim login"));
15951
16101
  else
15952
16102
  printList(output, rows, PROFILE_COLUMNS);
15953
16103
  return;
@@ -16020,11 +16170,11 @@ function configureCommand() {
16020
16170
  if (Object.keys(updates).length === 0) {
16021
16171
  const current = readConfigProfile(profile.name);
16022
16172
  if (Object.keys(current).length === 0) {
16023
- console.log(source_default.dim(`No settings stored for profile "${profile.name}".`));
16173
+ printLine(styles3().dim(`No settings stored for profile "${profile.name}".`));
16024
16174
  return;
16025
16175
  }
16026
16176
  for (const [key, value] of Object.entries(current)) {
16027
- console.log(`${source_default.dim(`${key}:`)} ${value}`);
16177
+ printLine(`${styles3().dim(`${key}:`)} ${value}`);
16028
16178
  }
16029
16179
  return;
16030
16180
  }
@@ -16049,10 +16199,10 @@ function configureCommand() {
16049
16199
  return true;
16050
16200
  });
16051
16201
  if (!changed) {
16052
- console.log(source_default.dim(`No settings stored for profile "${profile.name}".`));
16202
+ printLine(styles3().dim(`No settings stored for profile "${profile.name}".`));
16053
16203
  return;
16054
16204
  }
16055
- console.log(source_default.green(`✓ Updated profile "${profile.name}" in ${configPath()}`));
16205
+ printLine(styles3().green(`✓ Updated profile "${profile.name}" in ${configPath()}`));
16056
16206
  });
16057
16207
  }
16058
16208
 
@@ -16276,7 +16426,7 @@ var CLI_CONTRACT = {
16276
16426
  },
16277
16427
  deleteTableView: { confirm: "This deletes the saved view and its filters." },
16278
16428
  deleteWorkflowGroup: {
16279
- confirm: "This deletes the group, every column it fed, and the values in them.",
16429
+ confirm: "This deletes the group AND its output columns with all of their row data; the workflow it pointed at is untouched.",
16280
16430
  fields: [
16281
16431
  { header: "id" },
16282
16432
  { header: "deleted", format: "bool" },
@@ -16396,7 +16546,7 @@ var CLI_CONTRACT = {
16396
16546
  },
16397
16547
  applyWorkflowOperations: {
16398
16548
  command: "workflows operations apply",
16399
- confirm: "This edits the draft graph, and a delete operation removes blocks and their edges.",
16549
+ confirm: "This edits the draft graph: the batch adds, edits, or deletes blocks and their edges as written.",
16400
16550
  flags: {
16401
16551
  operations: { json: true, describe: WORKFLOW_OPERATIONS_HELP },
16402
16552
  setBlockEnabled: { json: true, describe: WORKFLOW_SET_BLOCK_ENABLED_HELP }
@@ -17248,7 +17398,7 @@ var CLI_CONTRACT = {
17248
17398
  selectedOutputs: {
17249
17399
  name: "select-output",
17250
17400
  list: true,
17251
- describe: "Return streamed outputs as blockName.path or childWorkflowId.blockName.path; selecting a child workflow applies to every invocation, requires --follow"
17401
+ describe: "Return blockName.path values (e.g. agent_1.content), or childWorkflowId.blockName.path for a child workflow (applies to every invocation) — in blockOutputs on a sync run, or from the streamed result with --follow; missing paths are omitted. Not available with --async"
17252
17402
  },
17253
17403
  stream: { omit: true },
17254
17404
  includeThinking: { omit: true },
@@ -17272,7 +17422,7 @@ var CLI_CONTRACT = {
17272
17422
  selectedOutputs: {
17273
17423
  name: "select-output",
17274
17424
  list: true,
17275
- describe: "Include blockId or blockId.path values in JSON or YAML output; block names are not resolved on a finished run"
17425
+ describe: "Include blockName.path or blockId.path values (e.g. agent_1.content) in JSON or YAML output; names resolve against the workflow’s current blocks, and missing paths are omitted"
17276
17426
  }
17277
17427
  },
17278
17428
  fields: [
@@ -17378,6 +17528,22 @@ function camel(flag) {
17378
17528
  return flag.replace(/-([a-z])/g, (_match, character) => character.toUpperCase());
17379
17529
  }
17380
17530
 
17531
+ // src/output/truncation.ts
17532
+ var TRUNCATION_FLAG = /^truncated$|^[A-Za-z0-9]+Truncated$/;
17533
+ var NEGATED_TRUNCATION_FLAG = /^(?:not|un|non|never)Truncated$|(?:Not|Un|Non|Never)Truncated$/;
17534
+ function isTruncationField(key) {
17535
+ return TRUNCATION_FLAG.test(key) && !NEGATED_TRUNCATION_FLAG.test(key);
17536
+ }
17537
+ function truncationMetadata(container) {
17538
+ if (!container || typeof container !== "object" || Array.isArray(container))
17539
+ return {};
17540
+ const metadata = {};
17541
+ for (const [key, value] of Object.entries(container))
17542
+ if (typeof value === "boolean" && isTruncationField(key))
17543
+ metadata[key] = value;
17544
+ return metadata;
17545
+ }
17546
+
17381
17547
  // src/output/trace.ts
17382
17548
  function traceSpan(value) {
17383
17549
  if (!value || typeof value !== "object" || Array.isArray(value)) {
@@ -17480,13 +17646,13 @@ function renderSpan(value, depth) {
17480
17646
  function printTraceSpans(format, traceSpans) {
17481
17647
  if (format === "json" || format === "yaml")
17482
17648
  return;
17483
- console.log("");
17484
- console.log(format === "table" ? source_default.dim("trace:") : "trace:");
17649
+ printLine("");
17650
+ printLine(format === "table" ? styles3().dim("trace:") : "trace:");
17485
17651
  if (traceSpans.length === 0) {
17486
- console.log(source_default.dim(" No trace spans."));
17652
+ printLine(styles3().dim(" No trace spans."));
17487
17653
  return;
17488
17654
  }
17489
- console.log(traceSpans.flatMap((span) => renderSpan(span, 0)).join(`
17655
+ printLine(traceSpans.flatMap((span) => renderSpan(span, 0)).join(`
17490
17656
  `));
17491
17657
  }
17492
17658
 
@@ -17650,20 +17816,9 @@ function writePageNote(spec, envelope) {
17650
17816
  const value = at(envelope, spec.pageNote.path);
17651
17817
  if (value === undefined || value === null)
17652
17818
  return;
17653
- process.stderr.write(source_default.dim(`${spec.pageNote.label}: ${String(value)}
17819
+ writeStderr(styles3().dim(`${spec.pageNote.label}: ${String(value)}
17654
17820
  `));
17655
17821
  }
17656
- var TRUNCATION_FLAG = /^truncated$|^[A-Za-z0-9]+Truncated$/;
17657
- var NEGATED_TRUNCATION_FLAG = /^(?:not|un|non|never)Truncated$|(?:Not|Un|Non|Never)Truncated$/;
17658
- function truncationMetadata(container) {
17659
- if (!container || typeof container !== "object" || Array.isArray(container))
17660
- return {};
17661
- const metadata = {};
17662
- for (const [key, value] of Object.entries(container))
17663
- if (typeof value === "boolean" && TRUNCATION_FLAG.test(key) && !NEGATED_TRUNCATION_FLAG.test(key))
17664
- metadata[key] = value;
17665
- return metadata;
17666
- }
17667
17822
  function truncationFlags(container) {
17668
17823
  return Object.entries(truncationMetadata(container)).filter(([, value]) => value).map(([key]) => key);
17669
17824
  }
@@ -17689,7 +17844,7 @@ function clippedSubject(flag) {
17689
17844
  }
17690
17845
  function writeEnvelopeTruncation(envelope) {
17691
17846
  for (const flag of responseTruncationFlags(envelope)) {
17692
- process.stderr.write(source_default.dim(`${spellOut(flag)}: the server clipped ${clippedSubject(flag)}, so the answer is incomplete
17847
+ writeStderr(styles3().dim(`${spellOut(flag)}: the server clipped ${clippedSubject(flag)}, so the answer is incomplete
17693
17848
  `));
17694
17849
  }
17695
17850
  }
@@ -17699,7 +17854,7 @@ function renderResult(operation, format, raw, spec, options = {}, envelope) {
17699
17854
  printDocument(format, raw);
17700
17855
  return;
17701
17856
  }
17702
- const data = unwrapResource(raw);
17857
+ const data = format === "json" || format === "yaml" ? raw : unwrapResource(raw);
17703
17858
  if (spec.itemsPath) {
17704
17859
  const items = at(data, spec.itemsPath);
17705
17860
  if (!Array.isArray(items)) {
@@ -17821,6 +17976,87 @@ function attachWorkspaceOperationWait(operations) {
17821
17976
 
17822
17977
  // src/runtime/request.ts
17823
17978
  import { closeSync as closeSync2, existsSync as existsSync2, fstatSync as fstatSync2, openSync as openSync2, readSync as readSync2 } from "node:fs";
17979
+
17980
+ // src/transfer/local-file.ts
17981
+ import { constants as constants2 } from "node:fs";
17982
+ import { access, stat } from "node:fs/promises";
17983
+ import { basename } from "node:path";
17984
+ function embeddedFileKey(path) {
17985
+ return path.startsWith("@") ? path.slice(1) : path;
17986
+ }
17987
+ async function embeddedFileContent(embedded, path) {
17988
+ const key = embeddedFileKey(path);
17989
+ embedded.identity.signal?.throwIfAborted();
17990
+ if (!embedded.readFile)
17991
+ throw new SimApiError("This invocation has no machine to read from", 0);
17992
+ const content = await embedded.readFile(key);
17993
+ embedded.identity.signal?.throwIfAborted();
17994
+ return typeof content === "string" ? content : new Uint8Array(content);
17995
+ }
17996
+ var CONTENT_TYPES = {
17997
+ css: "text/css",
17998
+ csv: "text/csv",
17999
+ doc: "application/msword",
18000
+ docx: "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
18001
+ gif: "image/gif",
18002
+ html: "text/html",
18003
+ htm: "text/html",
18004
+ jpeg: "image/jpeg",
18005
+ jpg: "image/jpeg",
18006
+ js: "text/javascript",
18007
+ json: "application/json",
18008
+ jsonl: "application/jsonl",
18009
+ md: "text/markdown",
18010
+ pdf: "application/pdf",
18011
+ ppt: "application/vnd.ms-powerpoint",
18012
+ pptx: "application/vnd.openxmlformats-officedocument.presentationml.presentation",
18013
+ png: "image/png",
18014
+ svg: "image/svg+xml",
18015
+ txt: "text/plain",
18016
+ webp: "image/webp",
18017
+ yaml: "application/yaml",
18018
+ yml: "application/yaml",
18019
+ xls: "application/vnd.ms-excel",
18020
+ xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
18021
+ zip: "application/zip"
18022
+ };
18023
+ function contentTypeFor(name) {
18024
+ const dot = name.lastIndexOf(".");
18025
+ const extension = dot === -1 ? "" : name.slice(dot + 1).toLowerCase();
18026
+ return CONTENT_TYPES[extension] ?? "application/octet-stream";
18027
+ }
18028
+ async function localFile(path, override) {
18029
+ const embedded = embedStore.getStore();
18030
+ if (embedded) {
18031
+ embedded.identity.signal?.throwIfAborted();
18032
+ if (!embedded.openFile)
18033
+ throw new SimApiError("This invocation has no machine to read from", 0);
18034
+ const { size } = await embedded.openFile(embeddedFileKey(path));
18035
+ embedded.identity.signal?.throwIfAborted();
18036
+ if (!Number.isSafeInteger(size) || size < 0)
18037
+ throw new SimApiError("Invalid file size", 0);
18038
+ if (size === 0)
18039
+ throw new SimApiError(`${path} is empty`, 0);
18040
+ return { name: override ?? basename(embeddedFileKey(path)), size };
18041
+ }
18042
+ let size;
18043
+ try {
18044
+ const stats = await stat(path);
18045
+ if (!stats.isFile())
18046
+ throw new SimApiError(`${path} is not a regular file`, 0);
18047
+ await access(path, constants2.R_OK);
18048
+ size = stats.size;
18049
+ } catch (error) {
18050
+ if (error instanceof SimApiError)
18051
+ throw error;
18052
+ throw new SimApiError(`Cannot read ${path}: ${error.message}`, 0);
18053
+ }
18054
+ if (size === 0)
18055
+ throw new SimApiError(`${path} is empty`, 0);
18056
+ return { name: override ?? basename(path), size };
18057
+ }
18058
+
18059
+ // src/runtime/request.ts
17824
18060
  var PROFILE_INJECTED_FIELD = "workspaceId";
17825
18061
  function isProfileWorkspacePath(commandSpec, param) {
17826
18062
  return commandSpec.profileWorkspacePath === true && param === PROFILE_INJECTED_FIELD;
@@ -17907,13 +18143,25 @@ function readArgumentDescriptor(descriptor) {
17907
18143
  function literalAtHint(error, path) {
17908
18144
  return error?.code === "ENOENT" ? `. To pass the literal value @${path}, write @@${path}` : "";
17909
18145
  }
17910
- function readArgumentSource(raw, flagName) {
18146
+ async function readArgumentSource(raw, flagName) {
17911
18147
  if (Buffer.byteLength(raw, "utf8") > MAX_JSON_ARGUMENT_BYTES)
17912
18148
  throw new SimApiError(`--${flagName} exceeds the 10 MiB JSON input limit`, 0);
17913
18149
  if (raw.startsWith("@@"))
17914
18150
  return { text: raw.slice(1), from: "" };
17915
18151
  if (!raw.startsWith("@"))
17916
18152
  return { text: raw, from: "" };
18153
+ const embedded = embedStore.getStore();
18154
+ if (embedded) {
18155
+ if (raw === "@-")
18156
+ throw new SimApiError(`--${flagName}: this invocation has no stdin; use @path or an inline value`, 0);
18157
+ const content = await embeddedFileContent(embedded, raw);
18158
+ if (Buffer.byteLength(content) > MAX_JSON_ARGUMENT_BYTES)
18159
+ throw new SimApiError(`--${flagName} exceeds the 10 MiB JSON input limit`, 0);
18160
+ return {
18161
+ text: typeof content === "string" ? content : new TextDecoder("utf-8", { fatal: true }).decode(content),
18162
+ from: " (read from your machine)"
18163
+ };
18164
+ }
17917
18165
  const path = raw.slice(1);
17918
18166
  if (path === "-") {
17919
18167
  if (process.stdin.isTTY) {
@@ -17942,15 +18190,18 @@ function isManifestNoise(line) {
17942
18190
  const trimmed = line.trim();
17943
18191
  return trimmed === "" || trimmed.startsWith("#");
17944
18192
  }
17945
- function readListValues(raw, flagName, manifest = false) {
18193
+ async function readListValues(raw, flagName, manifest = false) {
17946
18194
  const arguments_ = Array.isArray(raw) ? raw : [raw];
17947
- const values = arguments_.flatMap((argument) => {
18195
+ const values = [];
18196
+ for (const argument of arguments_) {
17948
18197
  if (typeof argument !== "string") {
17949
18198
  throw new SimApiError(`--${flagName} values must be strings`, 0);
17950
18199
  }
17951
- if (!argument.startsWith("@"))
17952
- return [argument];
17953
- const source = readArgumentSource(argument, flagName);
18200
+ if (!argument.startsWith("@")) {
18201
+ values.push(argument);
18202
+ continue;
18203
+ }
18204
+ const source = await readArgumentSource(argument, flagName);
17954
18205
  const lines = source.text.split(/\r?\n/);
17955
18206
  if (lines.at(-1) === "")
17956
18207
  lines.pop();
@@ -17958,14 +18209,14 @@ function readListValues(raw, flagName, manifest = false) {
17958
18209
  if (kept.length === 0) {
17959
18210
  throw new SimApiError(`--${flagName}${source.from} contains no values`, 0);
17960
18211
  }
17961
- return kept.map((line, index) => {
18212
+ values.push(...kept.map((line, index) => {
17962
18213
  const value = line.trim();
17963
18214
  if (!value) {
17964
18215
  throw new SimApiError(`--${flagName}${source.from} has an empty value on line ${index + 1}`, 0);
17965
18216
  }
17966
18217
  return value;
17967
- });
17968
- });
18218
+ }));
18219
+ }
17969
18220
  return values.map((value) => {
17970
18221
  const trimmed = value.trim();
17971
18222
  if (!trimmed)
@@ -17997,13 +18248,13 @@ var FRACTIONAL_DIGITS = /\.\d*[1-9]/;
17997
18248
  function pathHint(raw) {
17998
18249
  if (raw.startsWith("@") || /^\s*[[{"\-\d]|^\s*(true|false|null)/.test(raw))
17999
18250
  return "";
18000
- return existsSync2(raw) ? `. ${raw} is a file — pass it as @${raw}` : ". To read a file, pass @path (or @- for stdin)";
18251
+ return !embedStore.getStore() && existsSync2(raw) ? `. ${raw} is a file — pass it as @${raw}` : ". To read a file, pass @path (or @- for stdin)";
18001
18252
  }
18002
- function coerce(raw, field, flag, flagName) {
18253
+ async function coerce(raw, field, flag, flagName) {
18003
18254
  if (raw === undefined)
18004
18255
  return;
18005
18256
  if (flag.list) {
18006
- const values = readListValues(raw, flagName, flag.manifest === true).map((value) => flag.folderPath ? encodeFolderPath(value) : value);
18257
+ const values = (await readListValues(raw, flagName, flag.manifest === true)).map((value) => flag.folderPath ? encodeFolderPath(value) : value);
18007
18258
  return field.kind === "string" ? values.join(",") : values;
18008
18259
  }
18009
18260
  if (flag.rowCap)
@@ -18011,7 +18262,7 @@ function coerce(raw, field, flag, flagName) {
18011
18262
  if (takesJson(field, flag)) {
18012
18263
  if (typeof raw !== "string")
18013
18264
  return raw;
18014
- const source = readArgumentSource(raw, flagName);
18265
+ const source = await readArgumentSource(raw, flagName);
18015
18266
  try {
18016
18267
  return JSON.parse(source.text);
18017
18268
  } catch (error) {
@@ -18053,7 +18304,7 @@ function boundedRequest(request) {
18053
18304
  throw new SimApiError("Aggregate JSON request body exceeds 10 MiB", 0);
18054
18305
  return request;
18055
18306
  }
18056
- function buildRequest(operation, positional, flags, workspaceId) {
18307
+ async function buildRequest(operation, positional, flags, workspaceId) {
18057
18308
  const commandSpec = CLI_CONTRACT[operation] ?? {};
18058
18309
  const spec = V2_OPERATIONS[operation];
18059
18310
  let path = spec.path;
@@ -18091,7 +18342,7 @@ function buildRequest(operation, positional, flags, workspaceId) {
18091
18342
  if ((slot === "query" || NUMERIC_KINDS.has(descriptor.kind)) && typeof raw === "string" && raw.trim() === "" && !(field === "limit" && paginatedLimit)) {
18092
18343
  throw new SimApiError(`--${flagName} cannot be empty`, 0);
18093
18344
  }
18094
- const value = coerce(raw ?? undefined, descriptor, flag, flagName);
18345
+ const value = await coerce(raw ?? undefined, descriptor, flag, flagName);
18095
18346
  if (field === "limit" && !paginatedLimit && NUMERIC_KINDS.has(descriptor.kind) && typeof value === "number" && value < 1) {
18096
18347
  throw new SimApiError(`--${flagName} must be 1 or more`, 0);
18097
18348
  }
@@ -18121,7 +18372,7 @@ function buildRequest(operation, positional, flags, workspaceId) {
18121
18372
  const raw = flags[camel(variant.name)];
18122
18373
  if (typeof raw !== "string")
18123
18374
  throw new SimApiError(`--${variant.name} is required`, 0);
18124
- const parsed = coerce(raw, { kind: variant.kind }, { json: true }, variant.name);
18375
+ const parsed = await coerce(raw, { kind: variant.kind }, { json: true }, variant.name);
18125
18376
  if (variant.kind === "object" && (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) || variant.kind === "array" && !Array.isArray(parsed)) {
18126
18377
  throw new SimApiError(`--${variant.name} must be a JSON ${variant.kind}`, 0);
18127
18378
  }
@@ -18135,7 +18386,7 @@ function buildRequest(operation, positional, flags, workspaceId) {
18135
18386
  const raw = flags.body;
18136
18387
  if (typeof raw !== "string")
18137
18388
  throw new SimApiError("--body is required", 0);
18138
- const parsed = coerce(raw, { kind: "object" }, { json: true }, "body");
18389
+ const parsed = await coerce(raw, { kind: "object" }, { json: true }, "body");
18139
18390
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
18140
18391
  throw new SimApiError("--body must be a JSON object", 0);
18141
18392
  }
@@ -18298,7 +18549,7 @@ function warn(kind, from, to) {
18298
18549
  if (warned.has(key))
18299
18550
  return;
18300
18551
  warned.add(key);
18301
- process.stderr.write(`warning: ${kind} "${from}" has been renamed to "${to}". The old name still works.
18552
+ writeStderr(`warning: ${kind} "${from}" has been renamed to "${to}". The old name still works.
18302
18553
  `);
18303
18554
  }
18304
18555
  function warnRenamedCommand(from, to) {
@@ -18406,6 +18657,22 @@ function countOf(value) {
18406
18657
  function lengthOf(value) {
18407
18658
  return Array.isArray(value) ? value.length : 0;
18408
18659
  }
18660
+ var RESULT_NOTES = {
18661
+ replaceWorkflowChatDeployment: (payload, body) => {
18662
+ const authType = payload.authType ?? body?.authType ?? "public";
18663
+ return authType === "public" ? "note: auth type is public — anyone with the link can chat; pass --auth-type password|email to restrict it." : null;
18664
+ }
18665
+ };
18666
+ function writeResultNote(operation, payload, body) {
18667
+ const note = RESULT_NOTES[operation];
18668
+ if (!note)
18669
+ return;
18670
+ const record = payload && typeof payload === "object" && !Array.isArray(payload) ? payload : {};
18671
+ const message = note(record, body);
18672
+ if (message)
18673
+ writeStderr(styles3().dim(`${message}
18674
+ `));
18675
+ }
18409
18676
  function bulkFailureMessage(operation, payload, body) {
18410
18677
  const check = BULK_OUTCOME_CHECKS[operation];
18411
18678
  if (!check)
@@ -18495,7 +18762,7 @@ async function executeOperation(operation, commandSpec, operationSpec, invocatio
18495
18762
  const paging = cursorSlot(operationSpec);
18496
18763
  const pagedLimit = paging ? readPagedLimit(requestFlags.limit, operation) : 0;
18497
18764
  const requestWorkspaceId = needsWorkspace ? client.requireWorkspace() : profile.workspaceId;
18498
- const request = buildRequest(operation, positional, requestFlags, requestWorkspaceId);
18765
+ const request = await buildRequest(operation, positional, requestFlags, requestWorkspaceId);
18499
18766
  if (commandSpec.workspaceOperation) {
18500
18767
  if (!WORKSPACE_OPERATION_KINDS[operation])
18501
18768
  throw new SimApiError("This command has no workspace operation identity configured", 0);
@@ -18585,6 +18852,7 @@ async function executeOperation(operation, commandSpec, operationSpec, invocatio
18585
18852
  return;
18586
18853
  }
18587
18854
  renderResult(operation, profile.output, payload, commandSpec, { expandedTrace: requestFlags.trace === true }, result);
18855
+ writeResultNote(operation, payload, request.body);
18588
18856
  const failure = runFailureMessage(operation, payload) ?? bulkFailureMessage(operation, payload, request.body);
18589
18857
  if (failure)
18590
18858
  throw new SimApiError(failure, 0);
@@ -18992,8 +19260,8 @@ function serviceAccountProvider(providers, providerId) {
18992
19260
  }
18993
19261
  return provider;
18994
19262
  }
18995
- function credentialValues(provider, raw) {
18996
- const parsed = coerce(raw, { kind: "object" }, { json: true }, "credentials");
19263
+ async function credentialValues(provider, raw) {
19264
+ const parsed = await coerce(raw, { kind: "object" }, { json: true }, "credentials");
18997
19265
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
18998
19266
  throw new SimApiError("--credentials must be a JSON object", 0);
18999
19267
  }
@@ -19030,7 +19298,7 @@ async function createServiceAccount(command, providerId, options) {
19030
19298
  if (provider.requiresClientGeneratedCredentialId && !options.id) {
19031
19299
  throw new SimApiError(`--id is required for ${providerId}.`, 0);
19032
19300
  }
19033
- const credentialFields = credentialValues(provider, options.credentials);
19301
+ const credentialFields = await credentialValues(provider, options.credentials);
19034
19302
  const operation = V2_OPERATIONS.createServiceAccountCredential;
19035
19303
  const response = await client.request(operation.path, {
19036
19304
  method: operation.method,
@@ -19198,19 +19466,19 @@ Examples:
19198
19466
  const endStreamedLine = () => {
19199
19467
  if (streamed.length > 0 && !streamed.endsWith(`
19200
19468
  `)) {
19201
- process.stdout.write(`
19469
+ writeStdout(`
19202
19470
  `);
19203
19471
  streamed += `
19204
19472
  `;
19205
19473
  }
19206
19474
  };
19207
- const restorePipeHandling = streaming ? ignoreBrokenPipe(process.stdout) : undefined;
19475
+ const restorePipeHandling = streaming && !embedStore.getStore() ? ignoreBrokenPipe(process.stdout) : undefined;
19208
19476
  try {
19209
19477
  const result = await readChatStream(response, (content) => {
19210
19478
  if (!streaming)
19211
19479
  return;
19212
19480
  streamed += content;
19213
- process.stdout.write(content);
19481
+ writeStdout(content);
19214
19482
  });
19215
19483
  if (!streaming) {
19216
19484
  printProtocolResult(profile.output, result);
@@ -19218,11 +19486,11 @@ Examples:
19218
19486
  }
19219
19487
  const content = sanitize(result.content ?? "");
19220
19488
  if (content.startsWith(streamed) && content.length > streamed.length) {
19221
- process.stdout.write(content.slice(streamed.length));
19489
+ writeStdout(content.slice(streamed.length));
19222
19490
  streamed = content;
19223
19491
  }
19224
19492
  endStreamedLine();
19225
- process.stderr.write(`${source_default.dim(`conversation: ${result.conversationId}`)}
19493
+ writeStderr(`${styles3().dim(`conversation: ${result.conversationId}`)}
19226
19494
  `);
19227
19495
  } catch (error) {
19228
19496
  endStreamedLine();
@@ -19353,19 +19621,38 @@ async function saveStagedFile(body, target, force) {
19353
19621
  }
19354
19622
  }
19355
19623
  async function saveToFile(body, target, force) {
19624
+ const embedded = embedStore.getStore();
19625
+ if (embedded) {
19626
+ try {
19627
+ embedded.identity.signal?.throwIfAborted();
19628
+ if (!embedded.writeFile) {
19629
+ throw new SimApiError(`--output-file cannot save ${target} here: this surface has no machine to write to. Read the file instead, or use a client with filesystem access to download it.`, 0);
19630
+ }
19631
+ await embedded.writeFile(target, body, { overwrite: force });
19632
+ embedded.identity.signal?.throwIfAborted();
19633
+ } finally {
19634
+ await body.cancel().catch(() => {});
19635
+ }
19636
+ return;
19637
+ }
19356
19638
  return saveStagedFile(body, target, force);
19357
19639
  }
19358
- async function streamToStdout(body, output = process.stdout) {
19640
+ async function streamToStdout(body, output) {
19359
19641
  const reader = body.getReader();
19360
19642
  try {
19361
19643
  while (true) {
19362
19644
  const { done, value } = await reader.read();
19363
19645
  if (done)
19364
19646
  return;
19365
- if (!output.write(value))
19366
- await once2(output, "drain");
19647
+ if (output) {
19648
+ if (!output.write(value))
19649
+ await once2(output, "drain");
19650
+ } else if (!writeStdout(value)) {
19651
+ await once2(process.stdout, "drain");
19652
+ }
19367
19653
  }
19368
19654
  } finally {
19655
+ await reader.cancel().catch(() => {});
19369
19656
  reader.releaseLock();
19370
19657
  }
19371
19658
  }
@@ -19403,9 +19690,10 @@ function attachFileGet(files) {
19403
19690
  }
19404
19691
  if (options.outputFile === undefined || options.outputFile === "-") {
19405
19692
  const contentType = response.headers.get("content-type");
19406
- if (process.stdout.isTTY && !isTerminalSafeContentType(contentType)) {
19693
+ const embedded = embedStore.getStore();
19694
+ if ((embedded || process.stdout.isTTY) && !isTerminalSafeContentType(contentType)) {
19407
19695
  await response.body.cancel();
19408
- throw new SimApiError(`Refusing to write ${contentType ?? "unknown content"} to an interactive terminal. Use --output-file <path> or pipe stdout.`, 0);
19696
+ throw new SimApiError(embedded ? `Refusing to put ${contentType ?? "unknown content"} in a text result. Use --output-file <path>.` : `Refusing to write ${contentType ?? "unknown content"} to an interactive terminal. Use --output-file <path> or pipe stdout.`, 0);
19409
19697
  }
19410
19698
  await streamToStdout(response.body);
19411
19699
  return;
@@ -19420,74 +19708,120 @@ function attachFileGet(files) {
19420
19708
  });
19421
19709
  }
19422
19710
 
19423
- // src/transfer/local-file.ts
19424
- import { constants as constants2 } from "node:fs";
19425
- import { access, stat } from "node:fs/promises";
19426
- import { basename } from "node:path";
19427
- var CONTENT_TYPES = {
19428
- css: "text/css",
19429
- csv: "text/csv",
19430
- doc: "application/msword",
19431
- docx: "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
19432
- gif: "image/gif",
19433
- html: "text/html",
19434
- htm: "text/html",
19435
- jpeg: "image/jpeg",
19436
- jpg: "image/jpeg",
19437
- js: "text/javascript",
19438
- json: "application/json",
19439
- jsonl: "application/jsonl",
19440
- md: "text/markdown",
19441
- pdf: "application/pdf",
19442
- ppt: "application/vnd.ms-powerpoint",
19443
- pptx: "application/vnd.openxmlformats-officedocument.presentationml.presentation",
19444
- png: "image/png",
19445
- svg: "image/svg+xml",
19446
- txt: "text/plain",
19447
- webp: "image/webp",
19448
- yaml: "application/yaml",
19449
- yml: "application/yaml",
19450
- xls: "application/vnd.ms-excel",
19451
- xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
19452
- zip: "application/zip"
19453
- };
19454
- function contentTypeFor(name) {
19455
- const dot = name.lastIndexOf(".");
19456
- const extension = dot === -1 ? "" : name.slice(dot + 1).toLowerCase();
19457
- return CONTENT_TYPES[extension] ?? "application/octet-stream";
19458
- }
19459
- async function localFile(path, override) {
19460
- let size;
19461
- try {
19462
- const stats = await stat(path);
19463
- if (!stats.isFile())
19464
- throw new SimApiError(`${path} is not a regular file`, 0);
19465
- await access(path, constants2.R_OK);
19466
- size = stats.size;
19467
- } catch (error) {
19468
- if (error instanceof SimApiError)
19469
- throw error;
19470
- throw new SimApiError(`Cannot read ${path}: ${error.message}`, 0);
19711
+ // src/transfer/upload-session.ts
19712
+ import { openAsBlob } from "node:fs";
19713
+
19714
+ // src/transfer/streaming-upload.ts
19715
+ class StreamingUpload {
19716
+ size;
19717
+ position = 0;
19718
+ pending = new Uint8Array(0);
19719
+ closed = false;
19720
+ reader;
19721
+ onAbort;
19722
+ stopped = new AbortController;
19723
+ signal;
19724
+ constructor(stream, size, signal) {
19725
+ this.size = size;
19726
+ this.signal = signal ? AbortSignal.any([signal, this.stopped.signal]) : this.stopped.signal;
19727
+ this.reader = stream.getReader();
19728
+ this.onAbort = () => {
19729
+ this.reader.cancel(this.signal.reason).catch(() => {});
19730
+ };
19731
+ this.signal.addEventListener("abort", this.onAbort, { once: true });
19732
+ if (this.signal.aborted)
19733
+ this.onAbort();
19734
+ }
19735
+ slice(start, end) {
19736
+ this.signal.throwIfAborted();
19737
+ if (this.closed || start !== this.position || end <= start || end > this.size) {
19738
+ throw new SimApiError("Upload parts must consume the snapshot in order", 0);
19739
+ }
19740
+ return new ReadableStream({
19741
+ pull: async (controller) => {
19742
+ try {
19743
+ this.signal.throwIfAborted();
19744
+ while (this.pending.byteLength === 0) {
19745
+ const next = await this.reader.read();
19746
+ this.signal.throwIfAborted();
19747
+ if (next.done)
19748
+ throw new SimApiError("Upload file ended before its declared size", 0);
19749
+ this.pending = next.value;
19750
+ }
19751
+ const length = Math.min(this.pending.byteLength, end - this.position);
19752
+ controller.enqueue(this.pending.subarray(0, length));
19753
+ this.pending = this.pending.subarray(length);
19754
+ this.position += length;
19755
+ if (this.position === end)
19756
+ controller.close();
19757
+ } catch (error) {
19758
+ controller.error(error);
19759
+ }
19760
+ },
19761
+ cancel: (reason) => this.reader.cancel(reason)
19762
+ }, { highWaterMark: 0 });
19763
+ }
19764
+ assertConsumed(end) {
19765
+ this.signal.throwIfAborted();
19766
+ if (this.position !== end) {
19767
+ throw new SimApiError("Upload was acknowledged before its complete body was consumed", 0);
19768
+ }
19769
+ }
19770
+ async verifyComplete() {
19771
+ this.assertConsumed(this.size);
19772
+ if (this.pending.byteLength > 0) {
19773
+ throw new SimApiError("Upload file exceeds its declared size", 0);
19774
+ }
19775
+ while (true) {
19776
+ const next = await this.reader.read();
19777
+ this.signal.throwIfAborted();
19778
+ if (next.done)
19779
+ return;
19780
+ if (next.value.byteLength > 0)
19781
+ throw new SimApiError("Upload file exceeds its declared size", 0);
19782
+ }
19783
+ }
19784
+ async close() {
19785
+ if (this.closed)
19786
+ return;
19787
+ this.closed = true;
19788
+ this.stopped.abort();
19789
+ this.signal.removeEventListener("abort", this.onAbort);
19790
+ try {
19791
+ await this.reader.cancel().catch(() => {});
19792
+ } finally {
19793
+ this.reader.releaseLock();
19794
+ }
19471
19795
  }
19472
- if (size === 0)
19473
- throw new SimApiError(`${path} is empty`, 0);
19474
- return { name: override ?? basename(path), size };
19475
19796
  }
19476
19797
 
19477
19798
  // src/transfer/upload-session.ts
19478
- import { openAsBlob } from "node:fs";
19479
19799
  var PART_URL_BATCH = 100;
19480
- async function uploadPut(transfer, blob) {
19481
- const response = await fetch(transfer.url, {
19800
+ async function uploadBytes(url, headers, file, start, end, label) {
19801
+ const body = file.slice(start, end);
19802
+ const options = {
19482
19803
  method: "PUT",
19483
- headers: transfer.headers,
19484
- body: blob
19485
- });
19804
+ headers,
19805
+ body,
19806
+ signal: file instanceof StreamingUpload ? file.signal : embedStore.getStore()?.identity.signal
19807
+ };
19808
+ if (file instanceof StreamingUpload) {
19809
+ const streamedHeaders = new Headers(headers);
19810
+ streamedHeaders.set("content-length", String(end - start));
19811
+ options.headers = streamedHeaders;
19812
+ options.duplex = "half";
19813
+ }
19814
+ const response = await fetch(url, options);
19486
19815
  if (!response.ok) {
19487
- throw new SimApiError(`Upload failed with status ${response.status}`, response.status);
19816
+ throw new SimApiError(`${label} failed with status ${response.status}`, response.status);
19488
19817
  }
19818
+ if (file instanceof StreamingUpload)
19819
+ file.assertConsumed(end);
19489
19820
  }
19490
- async function uploadParts(client, workspaceId, session, transfer, blob) {
19821
+ async function uploadParts(client, workspaceId, session, transfer, file) {
19822
+ if (file instanceof StreamingUpload && (!Number.isSafeInteger(transfer.partSize) || transfer.partSize <= 0)) {
19823
+ throw new SimApiError("Invalid upload part size", 0);
19824
+ }
19491
19825
  const expectedPartCount = Math.ceil(session.size / transfer.partSize);
19492
19826
  if (expectedPartCount !== transfer.partCount) {
19493
19827
  throw new Error(`Upload session expected ${transfer.partCount} parts, but file requires ${expectedPartCount}`);
@@ -19503,28 +19837,49 @@ async function uploadParts(client, workspaceId, session, transfer, blob) {
19503
19837
  headers: { "upload-token": session.uploadToken },
19504
19838
  body: { partNumbers }
19505
19839
  });
19506
- for (const part of signed.data.parts) {
19507
- const start = (part.partNumber - 1) * transfer.partSize;
19508
- const chunk = blob.slice(start, Math.min(start + transfer.partSize, session.size));
19509
- const response = await fetch(part.url, {
19510
- method: "PUT",
19511
- headers: part.headers,
19512
- body: chunk
19513
- });
19514
- if (!response.ok) {
19515
- throw new SimApiError(`Part ${part.partNumber} failed with status ${response.status}`, response.status);
19840
+ let parts = signed.data.parts;
19841
+ if (file instanceof StreamingUpload) {
19842
+ const numbers = new Set(parts.map((part) => part.partNumber));
19843
+ if (parts.length !== partNumbers.length || partNumbers.some((n) => !numbers.has(n))) {
19844
+ throw new SimApiError("Upload part URLs do not match the requested parts", 0);
19516
19845
  }
19846
+ parts = [...parts].sort((a, b) => a.partNumber - b.partNumber);
19847
+ }
19848
+ for (const part of parts) {
19849
+ const start = (part.partNumber - 1) * transfer.partSize;
19850
+ await uploadBytes(part.url, part.headers, file, start, Math.min(start + transfer.partSize, session.size), `Part ${part.partNumber}`);
19517
19851
  }
19518
19852
  }
19519
19853
  }
19520
19854
  async function finishUploadSession(client, workspaceId, session, path) {
19855
+ let snapshot;
19856
+ let streamed;
19521
19857
  try {
19522
- const blob = await openAsBlob(path);
19858
+ const embedded = embedStore.getStore();
19859
+ let file;
19860
+ if (embedded) {
19861
+ embedded.identity.signal?.throwIfAborted();
19862
+ if (!embedded.openFile)
19863
+ throw new SimApiError("This invocation has no machine to read from", 0);
19864
+ snapshot = await embedded.openFile(embeddedFileKey(path));
19865
+ if (snapshot.size !== session.size)
19866
+ throw new SimApiError("Upload snapshot size changed", 0);
19867
+ streamed = new StreamingUpload(await snapshot.stream(), snapshot.size, AbortSignal.any([
19868
+ ...embedded.identity.signal ? [embedded.identity.signal] : [],
19869
+ ...snapshot.signal ? [snapshot.signal] : []
19870
+ ]));
19871
+ file = streamed;
19872
+ } else {
19873
+ file = await openAsBlob(path);
19874
+ }
19523
19875
  if (session.transfer.method === "put") {
19524
- await uploadPut(session.transfer, blob);
19876
+ await uploadBytes(session.transfer.url, session.transfer.headers, file, 0, file instanceof Blob ? file.size : session.size, "Upload");
19525
19877
  } else {
19526
- await uploadParts(client, workspaceId, session, session.transfer, blob);
19878
+ await uploadParts(client, workspaceId, session, session.transfer, file);
19527
19879
  }
19880
+ await streamed?.verifyComplete();
19881
+ await streamed?.close();
19882
+ await snapshot?.dispose().catch(() => {});
19528
19883
  const completed = await client.request(`${session.basePath}/complete`, {
19529
19884
  method: "POST",
19530
19885
  query: { workspaceId },
@@ -19532,7 +19887,10 @@ async function finishUploadSession(client, workspaceId, session, path) {
19532
19887
  });
19533
19888
  return completed.data;
19534
19889
  } catch (error) {
19535
- await client.request(session.basePath, {
19890
+ await streamed?.close();
19891
+ const profile = embeddedProfile();
19892
+ const cleanupClient = profile ? new SimClient({ ...profile, signal: AbortSignal.timeout(5000) }) : client;
19893
+ await cleanupClient.request(session.basePath, {
19536
19894
  method: "DELETE",
19537
19895
  query: { workspaceId },
19538
19896
  headers: { "upload-token": session.uploadToken }
@@ -19540,6 +19898,9 @@ async function finishUploadSession(client, workspaceId, session, path) {
19540
19898
  return;
19541
19899
  });
19542
19900
  throw error;
19901
+ } finally {
19902
+ await streamed?.close();
19903
+ await snapshot?.dispose().catch(() => {});
19543
19904
  }
19544
19905
  }
19545
19906
 
@@ -19625,9 +19986,11 @@ function attachKnowledgeDocumentUpload(documents) {
19625
19986
  printProtocolResult(profile.output, {
19626
19987
  id: completed.document.id,
19627
19988
  knowledgeBaseId: completed.document.knowledgeBaseId,
19628
- name: completed.document.filename,
19629
- size: completed.document.fileSize,
19630
- status: completed.document.processingStatus
19989
+ filename: completed.document.filename,
19990
+ fileSize: completed.document.fileSize,
19991
+ mimeType: completed.document.mimeType,
19992
+ processingStatus: completed.document.processingStatus,
19993
+ chunkCount: completed.document.chunkCount
19631
19994
  });
19632
19995
  });
19633
19996
  }
@@ -19743,11 +20106,11 @@ function createTableWriter() {
19743
20106
  if (!widths) {
19744
20107
  widths = COLUMNS.map((column, index) => Math.min(MAX_CELL_WIDTH2, Math.max(column.floor, visibleWidth(column.header), ...lines.map((line) => visibleWidth(line[index])))));
19745
20108
  const header = widths;
19746
- console.log(source_default.dim(COLUMNS.map((column, index) => pad2(column.header.toUpperCase(), header[index])).join(" ").trimEnd()));
20109
+ printLine(styles3().dim(COLUMNS.map((column, index) => pad2(column.header.toUpperCase(), header[index])).join(" ").trimEnd()));
19747
20110
  }
19748
20111
  const locked = widths;
19749
20112
  for (const line of lines) {
19750
- console.log(line.map((cell, index) => pad2(cell, locked[index])).join(" ").trimEnd());
20113
+ printLine(line.map((cell, index) => pad2(cell, locked[index])).join(" ").trimEnd());
19751
20114
  }
19752
20115
  };
19753
20116
  }
@@ -19755,13 +20118,13 @@ function createWriter(format) {
19755
20118
  if (format === "json") {
19756
20119
  return (rows) => {
19757
20120
  for (const row of rows)
19758
- console.log(JSON.stringify(row));
20121
+ printLine(JSON.stringify(row));
19759
20122
  };
19760
20123
  }
19761
20124
  if (format === "yaml") {
19762
20125
  return (rows) => {
19763
20126
  for (const row of rows) {
19764
- console.log(`---
20127
+ printLine(`---
19765
20128
  ${dump(row, { lineWidth: 0, noRefs: true }).trimEnd()}`);
19766
20129
  }
19767
20130
  };
@@ -19778,24 +20141,24 @@ function followStatus() {
19778
20141
  let reported = false;
19779
20142
  return {
19780
20143
  note: (message) => {
19781
- if (!process.stderr.isTTY)
20144
+ if (!hasProgressTerminal())
19782
20145
  return;
19783
20146
  reported = true;
19784
- process.stderr.write(`\r${source_default.dim(message)}${ERASE_LINE}`);
20147
+ writeStderr(`\r${styles3().dim(message)}${ERASE_LINE}`);
19785
20148
  },
19786
20149
  warn: (message) => {
19787
20150
  if (reported) {
19788
20151
  reported = false;
19789
- process.stderr.write(`\r${ERASE_LINE}`);
20152
+ writeStderr(`\r${ERASE_LINE}`);
19790
20153
  }
19791
- process.stderr.write(`warning: ${message}
20154
+ writeStderr(`warning: ${message}
19792
20155
  `);
19793
20156
  },
19794
20157
  clear: () => {
19795
20158
  if (!reported)
19796
20159
  return;
19797
20160
  reported = false;
19798
- process.stderr.write(`\r${ERASE_LINE}`);
20161
+ writeStderr(`\r${ERASE_LINE}`);
19799
20162
  }
19800
20163
  };
19801
20164
  }
@@ -20087,13 +20450,13 @@ async function watchImport(client, workspaceId, job) {
20087
20450
  const next = await client.request(`/api/v2/tables/imports/${encodeURIComponent(current.id)}`, { query: { workspaceId } });
20088
20451
  current = next.data;
20089
20452
  const line = progressLine(current);
20090
- if (process.stderr.isTTY && line !== reported) {
20453
+ if (hasProgressTerminal() && line !== reported) {
20091
20454
  reported = line;
20092
- process.stderr.write(`\r${source_default.dim(line)}\x1B[K`);
20455
+ writeStderr(`\r${styles3().dim(line)}\x1B[K`);
20093
20456
  }
20094
20457
  }
20095
- if (process.stderr.isTTY && reported !== null)
20096
- process.stderr.write("\r\x1B[K");
20458
+ if (hasProgressTerminal() && reported !== null)
20459
+ writeStderr("\r\x1B[K");
20097
20460
  return current;
20098
20461
  }
20099
20462
  function validateTargetOptions(options) {
@@ -20151,8 +20514,8 @@ function attachTableImport(tables) {
20151
20514
  workspaceId,
20152
20515
  source,
20153
20516
  target,
20154
- ...options.mapping ? { mapping: jsonFlag(options.mapping, "mapping", "object") } : {},
20155
- ...options.createColumns ? { createColumns: jsonFlag(options.createColumns, "create-columns", "array") } : {},
20517
+ ...options.mapping ? { mapping: await jsonFlag(options.mapping, "mapping", "object") } : {},
20518
+ ...options.createColumns ? { createColumns: await jsonFlag(options.createColumns, "create-columns", "array") } : {},
20156
20519
  ...options.timezone ? { timezone: options.timezone } : {}
20157
20520
  }
20158
20521
  });
@@ -20198,14 +20561,11 @@ var AGENT_STREAM_PROTOCOL_V1 = "agent-events-v1";
20198
20561
  var WORKFLOW_RESULT_STREAM_CONTENT_TYPE = "application/x-ndjson";
20199
20562
  var DONE_SENTINEL = "[DONE]";
20200
20563
  function resolveWorkflowRunSelection(flags) {
20201
- const manual = flags.manual === true;
20202
20564
  const trigger = typeof flags.trigger === "string" ? flags.trigger : undefined;
20203
20565
  const useMockPayload = flags.mockPayload === true;
20566
+ const manual = flags.manual === true || trigger !== undefined || useMockPayload;
20204
20567
  const fromBlock = typeof flags.fromBlock === "string" ? flags.fromBlock : undefined;
20205
20568
  const sourceRun = typeof flags.sourceRun === "string" ? flags.sourceRun : undefined;
20206
- if ((trigger || useMockPayload) && !manual) {
20207
- throw new SimApiError("--trigger and --mock-payload require --manual", 0);
20208
- }
20209
20569
  if (fromBlock && (trigger || useMockPayload)) {
20210
20570
  throw new SimApiError("--from-block cannot be combined with --trigger or --mock-payload", 0);
20211
20571
  }
@@ -20282,7 +20642,7 @@ async function runWithResultStream(workflowId, command) {
20282
20642
  const operation = V2_OPERATIONS.executeWorkflow;
20283
20643
  const commandSpec = CLI_CONTRACT.executeWorkflow ?? {};
20284
20644
  try {
20285
- const request = buildRequest("executeWorkflow", [workflowId], flags, profile.workspaceId);
20645
+ const request = await buildRequest("executeWorkflow", [workflowId], flags, profile.workspaceId);
20286
20646
  const response = await client.requestRaw(request.path, {
20287
20647
  method: operation.method,
20288
20648
  query: request.query,
@@ -20357,11 +20717,11 @@ class Commentary {
20357
20717
  function toolNotice(frame) {
20358
20718
  const name = safeOneLine(stringField(frame, "name") ?? "tool");
20359
20719
  if (frame.phase === "start")
20360
- return source_default.dim(`→ ${name}`);
20720
+ return styles3().dim(`→ ${name}`);
20361
20721
  const status = stringField(frame, "status");
20362
20722
  if (status && status !== "success")
20363
- return source_default.yellow(`✗ ${name} (${safeOneLine(status)})`);
20364
- return source_default.dim(`✓ ${name}`);
20723
+ return styles3().yellow(`✗ ${name} (${safeOneLine(status)})`);
20724
+ return styles3().dim(`✓ ${name}`);
20365
20725
  }
20366
20726
  async function renderRunStream(body, options) {
20367
20727
  const commentary = new Commentary(options.stderr);
@@ -20383,11 +20743,11 @@ async function renderRunStream(body, options) {
20383
20743
  }
20384
20744
  switch (frame.event) {
20385
20745
  case "chunk_reset":
20386
- commentary.line(source_default.dim("… retracted; that turn resolved to tool calls"));
20746
+ commentary.line(styles3().dim("… retracted; that turn resolved to tool calls"));
20387
20747
  break;
20388
20748
  case "thinking":
20389
20749
  if (options.includeThinking && typeof frame.data === "string") {
20390
- commentary.inline(source_default.dim(sanitize(frame.data)));
20750
+ commentary.inline(styles3().dim(sanitize(frame.data)));
20391
20751
  }
20392
20752
  break;
20393
20753
  case "tool":
@@ -20395,7 +20755,7 @@ async function renderRunStream(body, options) {
20395
20755
  commentary.line(toolNotice(frame));
20396
20756
  break;
20397
20757
  case "stream_error":
20398
- commentary.line(source_default.yellow(`warning: ${safeOneLine(stringField(frame, "error") ?? "stream read failed")}`));
20758
+ commentary.line(styles3().yellow(`warning: ${safeOneLine(stringField(frame, "error") ?? "stream read failed")}`));
20399
20759
  break;
20400
20760
  case "error":
20401
20761
  commentary.endLine();
@@ -20424,7 +20784,7 @@ async function followRun(workflowId, command) {
20424
20784
  const negotiates = includeThinking || includeToolCalls;
20425
20785
  const { client, profile } = clientFrom(command);
20426
20786
  const operation = V2_OPERATIONS.executeWorkflow;
20427
- const request = buildRequest("executeWorkflow", [workflowId], flags, profile.workspaceId);
20787
+ const request = await buildRequest("executeWorkflow", [workflowId], flags, profile.workspaceId);
20428
20788
  const response = await client.requestRaw(request.path, {
20429
20789
  method: "POST",
20430
20790
  query: request.query,
@@ -20450,7 +20810,7 @@ async function followRun(workflowId, command) {
20450
20810
  const final = await renderRunStream(response.body, {
20451
20811
  includeThinking,
20452
20812
  includeToolCalls,
20453
- stderr: process.stderr
20813
+ stderr: { write: writeStderr }
20454
20814
  });
20455
20815
  renderResult("executeWorkflow", profile.output, final, CLI_CONTRACT.executeWorkflow ?? {});
20456
20816
  if (final.success === false) {
@@ -20465,8 +20825,8 @@ function followOrDelegate(previous) {
20465
20825
  command.setOptionValue("run", selection);
20466
20826
  const flags = command.optsWithGlobals();
20467
20827
  if (flags.follow !== true) {
20468
- if (Array.isArray(flags.selectOutput) && flags.selectOutput.length > 0) {
20469
- throw new SimApiError(flags.async === true ? "--select-output shapes a streamed result, and --async returns as soon as the run is queued, so there is no stream to shape. Drop one of them, or read the finished run with: sim workflows runs get <runId> --workflow <workflowId> --select-output <blockId>[.path] — that resource matches block ids, not the block names --select-output takes here." : "--select-output shapes a streamed result; add --follow. To narrow a run that has already finished: sim workflows runs get <runId> --workflow <workflowId> --select-output <blockId>[.path] — that resource matches block ids, not the block names --select-output takes here.", 0);
20828
+ if (Array.isArray(flags.selectOutput) && flags.selectOutput.length > 0 && flags.async === true) {
20829
+ throw new SimApiError("--select-output names outputs of a completed run, and --async returns as soon as the run is queued. Drop one of them, or read the finished run with: sim workflows runs get <runId> --workflow <workflowId> --select-output <blockName|blockId>[.path] — that resource takes the same selectors --select-output takes here.", 0);
20470
20830
  }
20471
20831
  if (flags.includeThinking === true || flags.includeToolCalls === true) {
20472
20832
  throw new SimApiError("--include-thinking and --include-tool-calls describe a stream; add --follow", 0);
@@ -20492,7 +20852,119 @@ function attachWorkflowRunFollow(workflows) {
20492
20852
  }
20493
20853
  const held = run._actionHandler;
20494
20854
  const previous = typeof held === "function" ? held : null;
20495
- run.option("--manual", "Run the current saved workflow state instead of the active deployment").option("--trigger <blockId>", "Enter a manual run through this runnable trigger (requires --manual)").option("--mock-payload", "Use the selected trigger's server-derived mock payload (requires --manual)").option("--from-block <blockId>", "Run manually from this saved workflow block").option("--source-run <runId>", "Prior run whose persisted state supplies upstream outputs (requires --from-block)").option("--follow", "Stream the run as it happens; progress on stderr, result on stdout. The stream reports only success and output, so the result omits the run id and timings a non-streaming run returns").option("--include-thinking", "Show model reasoning while following (requires --follow)").option("--include-tool-calls", "Show tool calls while following (requires --follow)").action(followOrDelegate(previous));
20855
+ run.option("--manual", "Run the current saved workflow state instead of the active deployment").option("--trigger <blockId>", "Enter the run through this runnable trigger; runs the current saved workflow state (implies --manual)").option("--mock-payload", "Use the selected trigger's server-derived mock payload; runs the current saved workflow state (implies --manual)").option("--from-block <blockId>", "Run manually from this saved workflow block").option("--source-run <runId>", "Prior run whose persisted state supplies upstream outputs (requires --from-block)").option("--follow", "Stream the run as it happens; progress on stderr, result on stdout. The stream reports only success and output, so the result omits the run id and timings a non-streaming run returns").option("--include-thinking", "Show model reasoning while following (requires --follow)").option("--include-tool-calls", "Show tool calls while following (requires --follow)").action(followOrDelegate(previous));
20856
+ }
20857
+
20858
+ // src/commands/protocol/workflow-run-get.ts
20859
+ var BLOCK_ID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
20860
+ var SELECT_OUTPUT_FLAG = "select-output";
20861
+ function normalizeBlockName(name) {
20862
+ return name.toLowerCase().replace(/\s+/g, "").replace(/\./g, "");
20863
+ }
20864
+ function isRecord2(value) {
20865
+ return typeof value === "object" && value !== null && !Array.isArray(value);
20866
+ }
20867
+ async function loadWorkflowBlocks(client, workflowId) {
20868
+ const operation = V2_OPERATIONS.getWorkflowState;
20869
+ const raw = await client.request(resolvePath(operation.path, { workflowId }), {
20870
+ method: operation.method
20871
+ });
20872
+ const state = isRecord2(raw) && isRecord2(raw.data) ? raw.data : raw;
20873
+ const blocks = isRecord2(state) && isRecord2(state.blocks) ? Object.entries(state.blocks) : [];
20874
+ return blocks.map(([key, block]) => ({
20875
+ id: isRecord2(block) && typeof block.id === "string" ? block.id : key,
20876
+ name: isRecord2(block) && typeof block.name === "string" ? block.name : ""
20877
+ }));
20878
+ }
20879
+ function splitSelector(selector) {
20880
+ const dot = selector.indexOf(".");
20881
+ return dot === -1 ? { head: selector, path: "" } : { head: selector.slice(0, dot), path: selector.slice(dot) };
20882
+ }
20883
+ function isIdHeaded(selector) {
20884
+ return BLOCK_ID.test(splitSelector(selector).head);
20885
+ }
20886
+ function resolveSelection(typed, blocks, workflowId) {
20887
+ const resolved = [];
20888
+ const typedBy = new Map;
20889
+ const unresolved = [];
20890
+ for (const selector of typed) {
20891
+ const { head, path } = splitSelector(selector);
20892
+ let blockId = head;
20893
+ if (!BLOCK_ID.test(head)) {
20894
+ const wanted = normalizeBlockName(head);
20895
+ const matches = blocks.filter((block) => block.id === head || normalizeBlockName(block.name) === wanted);
20896
+ if (matches.length === 0) {
20897
+ unresolved.push(selector);
20898
+ continue;
20899
+ }
20900
+ if (matches.length > 1) {
20901
+ throw new SimApiError(`--${SELECT_OUTPUT_FLAG} ${selector} names ${matches.length} blocks (${matches.map((block) => block.id).join(", ")}); pass the block id instead`, 0);
20902
+ }
20903
+ blockId = matches[0].id;
20904
+ }
20905
+ const rewritten = `${blockId}${path}`;
20906
+ resolved.push(rewritten);
20907
+ if (!typedBy.has(rewritten))
20908
+ typedBy.set(rewritten, selector);
20909
+ }
20910
+ if (unresolved.length > 0) {
20911
+ const names = blocks.map((block) => block.name).filter((name) => name !== "");
20912
+ throw new SimApiError(`--${SELECT_OUTPUT_FLAG} did not resolve to any block on this run: ${unresolved.join(", ")}. Pass a block id or its name — "blockId", "blockId.path", "blockName" or "blockName.path"; names match ignoring case, spaces and dots. Blocks on workflow ${workflowId}: ${names.length > 0 ? names.join(", ") : "none"}.`, 0);
20913
+ }
20914
+ return { resolved, typedBy };
20915
+ }
20916
+ function keyByTyped(payload, typedBy) {
20917
+ if (!isRecord2(payload) || !isRecord2(payload.blockOutputs))
20918
+ return payload;
20919
+ const blockOutputs = {};
20920
+ for (const [key, value] of Object.entries(payload.blockOutputs)) {
20921
+ blockOutputs[typedBy.get(key) ?? key] = value;
20922
+ }
20923
+ return { ...payload, blockOutputs };
20924
+ }
20925
+ async function readRunByName(runId, typed, command) {
20926
+ const flags = command.optsWithGlobals();
20927
+ const { client, profile } = clientFrom(command);
20928
+ const operation = V2_OPERATIONS.getWorkflowRun;
20929
+ const spec = CLI_CONTRACT.getWorkflowRun ?? {};
20930
+ await buildRequest("getWorkflowRun", [runId], flags, profile.workspaceId);
20931
+ const workflowId = String(flags.workflow);
20932
+ const selection = resolveSelection(typed, await loadWorkflowBlocks(client, workflowId), workflowId);
20933
+ const request = await buildRequest("getWorkflowRun", [runId], { ...flags, selectOutput: selection.resolved }, profile.workspaceId);
20934
+ let result;
20935
+ try {
20936
+ result = await client.request(request.path, {
20937
+ method: operation.method,
20938
+ headers: request.headers,
20939
+ query: request.query,
20940
+ body: request.body
20941
+ });
20942
+ } catch (error) {
20943
+ throw retypeApiError(error, "getWorkflowRun", spec, operation);
20944
+ }
20945
+ renderResult("getWorkflowRun", profile.output, keyByTyped(result?.data ?? result, selection.typedBy), spec, {}, result);
20946
+ }
20947
+ function attachWorkflowRunGet(runs) {
20948
+ const get = runs.commands.find((command) => command.name() === "get");
20949
+ const held = get?._actionHandler;
20950
+ if (!get || typeof held !== "function") {
20951
+ throw new Error("workflows runs get must be registered before block names can be attached to it");
20952
+ }
20953
+ const previous = held;
20954
+ get.action(async (runId, _options, command) => {
20955
+ const raw = command.optsWithGlobals().selectOutput;
20956
+ if (raw === undefined) {
20957
+ await previous(command.processedArgs);
20958
+ return;
20959
+ }
20960
+ const typed = await readListValues(raw, SELECT_OUTPUT_FLAG);
20961
+ command.setOptionValue("selectOutput", typed);
20962
+ if (typed.every(isIdHeaded)) {
20963
+ await previous(command.processedArgs);
20964
+ return;
20965
+ }
20966
+ await readRunByName(runId, typed, command);
20967
+ });
20496
20968
  }
20497
20969
 
20498
20970
  // src/commands/protocol/workflow-run-wait.ts
@@ -20509,18 +20981,21 @@ var MAX_POLL_DELAY_MS = 15000;
20509
20981
  var POLL_BACKOFF_FACTOR = 2;
20510
20982
  var DEFAULT_WAIT_TIMEOUT_SECONDS = 3600;
20511
20983
  var WAIT_TIMEOUT_FLAG = "--wait-timeout <seconds>";
20512
- function isRecord2(value) {
20984
+ function isRecord3(value) {
20513
20985
  return typeof value === "object" && value !== null && !Array.isArray(value);
20514
20986
  }
20515
20987
  function optionalString(value) {
20516
20988
  return typeof value === "string" && value !== "" ? value : null;
20517
20989
  }
20990
+ function runData(raw) {
20991
+ return isRecord3(raw) && isRecord3(raw.data) ? raw.data : raw;
20992
+ }
20518
20993
  function readRun(raw) {
20519
- const run = isRecord2(raw) && isRecord2(raw.data) ? raw.data : raw;
20520
- if (!isRecord2(run) || typeof run.status !== "string") {
20994
+ const run = isRecord3(raw) && isRecord3(raw.data) ? raw.data : raw;
20995
+ if (!isRecord3(run) || typeof run.status !== "string") {
20521
20996
  throw new SimApiError("Run status response carried no status.", 0);
20522
20997
  }
20523
- const paused = isRecord2(run.paused) ? run.paused : null;
20998
+ const paused = isRecord3(run.paused) ? run.paused : null;
20524
20999
  return {
20525
21000
  status: run.status,
20526
21001
  pauseKind: paused ? optionalString(paused.pauseKind) : null,
@@ -20539,16 +21014,16 @@ function waitProgress() {
20539
21014
  let reported = false;
20540
21015
  return {
20541
21016
  advance: (status, elapsedMs) => {
20542
- if (!process.stderr.isTTY)
21017
+ if (!hasProgressTerminal())
20543
21018
  return;
20544
21019
  reported = true;
20545
- process.stderr.write(`\r${source_default.dim(`${status} — waiting ${Math.round(elapsedMs / 1000)}s…`)}\x1B[K`);
21020
+ writeStderr(`\r${styles3().dim(`${status} — waiting ${Math.round(elapsedMs / 1000)}s…`)}\x1B[K`);
20546
21021
  },
20547
21022
  finish: () => {
20548
21023
  if (!reported)
20549
21024
  return;
20550
21025
  reported = false;
20551
- process.stderr.write("\r\x1B[K");
21026
+ writeStderr("\r\x1B[K");
20552
21027
  }
20553
21028
  };
20554
21029
  }
@@ -20589,19 +21064,19 @@ function attachWorkflowRunWait(runs) {
20589
21064
  const outcome = classify(snapshot);
20590
21065
  if (outcome) {
20591
21066
  progress.finish();
20592
- renderResult("getWorkflowRun", profile.output, raw, runSpec());
21067
+ renderResult("getWorkflowRun", profile.output, runData(raw), runSpec());
20593
21068
  const message = explain(outcome, runId, options.workflow, snapshot);
20594
21069
  if (message)
20595
- console.error(source_default.red(message));
20596
- process.exitCode = WAIT_EXIT_CODES[outcome];
21070
+ printError(styles3().red(message));
21071
+ setSoftExitCode(WAIT_EXIT_CODES[outcome]);
20597
21072
  return;
20598
21073
  }
20599
21074
  const remainingMs = deadline - Date.now();
20600
21075
  if (remainingMs <= 0) {
20601
21076
  progress.finish();
20602
- renderResult("getWorkflowRun", profile.output, raw, runSpec());
20603
- console.error(source_default.red(`Timed out after ${timeoutSeconds}s waiting for run ${runId} (status: ${snapshot.status}${snapshot.resumeAt ? `, resuming at ${snapshot.resumeAt}` : ""}). Raise ${WAIT_TIMEOUT_FLAG}, or set it to 0 to wait indefinitely.`));
20604
- process.exitCode = WAIT_EXIT_CODES.timeout;
21077
+ renderResult("getWorkflowRun", profile.output, runData(raw), runSpec());
21078
+ printError(styles3().red(`Timed out after ${timeoutSeconds}s waiting for run ${runId} (status: ${snapshot.status}${snapshot.resumeAt ? `, resuming at ${snapshot.resumeAt}` : ""}). Raise ${WAIT_TIMEOUT_FLAG}, or set it to 0 to wait indefinitely.`));
21079
+ setSoftExitCode(WAIT_EXIT_CODES.timeout);
20605
21080
  return;
20606
21081
  }
20607
21082
  progress.advance(snapshot.status, Date.now() - startedAt);
@@ -20658,7 +21133,9 @@ function attachProtocolCommands(program) {
20658
21133
  createFolder: "createWorkflowFolder"
20659
21134
  });
20660
21135
  attachWorkflowRunFollow(workflows);
20661
- attachWorkflowRunWait(group(workflows, "runs"));
21136
+ const runs = group(workflows, "runs");
21137
+ attachWorkflowRunGet(runs);
21138
+ attachWorkflowRunWait(runs);
20662
21139
  attachWorkspaceOperationWait(group(group(program, "workspaces"), "operations"));
20663
21140
  attachLogsFollow(group(program, "logs"));
20664
21141
  attachChat(program);
@@ -20762,12 +21239,12 @@ var SECRET_RESULT = {
20762
21239
  { header: "description" }
20763
21240
  ]
20764
21241
  };
20765
- function readValueArgument(raw) {
21242
+ async function readValueArgument(raw) {
20766
21243
  if (raw.startsWith("@@"))
20767
21244
  return raw.slice(1);
20768
21245
  if (!raw.startsWith("@"))
20769
21246
  return raw;
20770
- return readArgumentSource(raw, "value").text;
21247
+ return (await readArgumentSource(raw, "value")).text;
20771
21248
  }
20772
21249
  function validateSecretValue(value) {
20773
21250
  if (value.length === 0)
@@ -20787,7 +21264,7 @@ function validateWorkspaceOnlyFlag(flag, value, scope) {
20787
21264
  }
20788
21265
  async function readSecretValue(options) {
20789
21266
  if (options.value !== undefined)
20790
- return validateSecretValue(readValueArgument(options.value));
21267
+ return validateSecretValue(await readValueArgument(options.value));
20791
21268
  if (options.description !== undefined || options.unredacted !== undefined)
20792
21269
  return;
20793
21270
  try {
@@ -20795,8 +21272,8 @@ async function readSecretValue(options) {
20795
21272
  } catch (error) {
20796
21273
  if (!(error instanceof SecretInputCancelledError))
20797
21274
  throw error;
20798
- console.error(source_default.red(`Error: ${error.message}`));
20799
- return process.exit(CANCELLED_EXIT_CODE);
21275
+ printError(styles3().red(`Error: ${error.message}`));
21276
+ return exitCli(CANCELLED_EXIT_CODE);
20800
21277
  }
20801
21278
  }
20802
21279
  async function setSecret(name, options, command, redactionSpellings) {
@@ -20968,7 +21445,7 @@ function createCommandTelemetry(options = {}) {
20968
21445
  writeTelemetryState({ ...state, session });
20969
21446
  const properties = {
20970
21447
  $lib: LIBRARY_NAME,
20971
- $lib_version: CLI_VERSION,
21448
+ $lib_version: cliVersion(),
20972
21449
  $process_person_profile: false,
20973
21450
  $session_id: session.id,
20974
21451
  session_sequence: session.sequence,
@@ -20979,7 +21456,7 @@ function createCommandTelemetry(options = {}) {
20979
21456
  exit_code: outcome.exitCode,
20980
21457
  duration_ms: Math.round(elapsed()),
20981
21458
  ...failureProperties(outcome.error),
20982
- cli_version: CLI_VERSION,
21459
+ cli_version: cliVersion(),
20983
21460
  node_version: process.versions.node,
20984
21461
  os: process.platform,
20985
21462
  arch: process.arch,
@@ -21118,19 +21595,22 @@ function addVersionOption(program) {
21118
21595
  }
21119
21596
  program.error("error: --version reports the Sim CLI version and takes no value. A command that acts on a deployment version reads it from --to-version.");
21120
21597
  });
21121
- program.version(CLI_VERSION, "-V, --version [none]", "output the version number (takes no value)");
21598
+ program.version(cliVersion(), "-V, --version [none]", "output the version number (takes no value)");
21122
21599
  }
21123
21600
  function buildProgram(options = {}) {
21124
- const program = new Command;
21601
+ const program = options.program ?? new Command;
21125
21602
  program.name("sim").description(PROGRAM_DESCRIPTION);
21126
21603
  if (options.version !== false)
21127
21604
  addVersionOption(program);
21128
21605
  program.option("-P, --profile <name>", "Profile to use (env: SIM_PROFILE)").option("--endpoint <url>", "Sim deployment to talk to (env: SIM_ENDPOINT)").option("-w, --workspace <id>", "Workspace to target (env: SIM_WORKSPACE)").addOption(new Option("--output <format>", "Output format for this command").choices([...OUTPUT_FORMATS]));
21129
- program.addCommand(loginCommand());
21130
- program.addCommand(logoutCommand());
21131
- program.addCommand(whoamiCommand());
21132
- program.addCommand(profilesCommand());
21133
- program.addCommand(configureCommand());
21606
+ for (const command of [
21607
+ loginCommand,
21608
+ logoutCommand,
21609
+ whoamiCommand,
21610
+ profilesCommand,
21611
+ configureCommand
21612
+ ])
21613
+ program.addCommand(command());
21134
21614
  const update = updateCommand();
21135
21615
  program.addCommand(update);
21136
21616
  program.addCommand(telemetryCommand());
@@ -21140,7 +21620,7 @@ function buildProgram(options = {}) {
21140
21620
  attachCredentialCommands(program);
21141
21621
  attachProtocolCommands(program);
21142
21622
  attachSecretCommands(program);
21143
- program.addHelpText("after", HELP_EPILOGUE);
21623
+ program.addHelpText("after", options.helpText ?? HELP_EPILOGUE);
21144
21624
  program.hook("preAction", async (_program, command) => {
21145
21625
  if (command === update)
21146
21626
  return;
@@ -21151,14 +21631,14 @@ function buildProgram(options = {}) {
21151
21631
  return program;
21152
21632
  }
21153
21633
 
21154
- // src/index.ts
21634
+ // src/terminal.ts
21155
21635
  function explainFailure(error, program) {
21156
21636
  if (error instanceof ProfileConfigError || error instanceof CliUpdateError) {
21157
- console.error(source_default.red(`Error: ${sanitize(error.message)}`));
21637
+ console.error(styles3().red(`Error: ${sanitize(error.message)}`));
21158
21638
  return 1;
21159
21639
  }
21160
21640
  if (isRequestTimeout(error)) {
21161
- console.error(source_default.red(`Error: the request timed out. ${RAISE_TIMEOUT_HINT}`));
21641
+ console.error(styles3().red(`Error: the request timed out. ${RAISE_TIMEOUT_HINT}`));
21162
21642
  return 1;
21163
21643
  }
21164
21644
  if (error instanceof SimApiError) {
@@ -21178,30 +21658,32 @@ function explainFailure(error, program) {
21178
21658
  ` : dump(payload));
21179
21659
  return error.exitCode;
21180
21660
  }
21181
- console.error(source_default.red(`Error: ${sanitize(error.message)}`));
21661
+ console.error(styles3().red(`Error: ${sanitize(error.message)}`));
21182
21662
  if (error.code)
21183
- console.error(source_default.dim(` code: ${sanitize(error.code)}`));
21663
+ console.error(styles3().dim(` code: ${sanitize(error.code)}`));
21184
21664
  if (error.details !== undefined) {
21185
21665
  for (const line of formatApiErrorDetails(error.details)) {
21186
- console.error(source_default.dim(sanitize(line)));
21666
+ console.error(styles3().dim(sanitize(line)));
21187
21667
  }
21188
21668
  }
21189
21669
  return error.exitCode;
21190
21670
  }
21191
21671
  return null;
21192
21672
  }
21193
- async function main() {
21194
- const telemetry = createCommandTelemetry();
21195
- const program = buildProgram();
21196
- telemetry.observe(program);
21673
+ async function runTerminalCli(suppliedProgram) {
21674
+ const telemetry = suppliedProgram ? undefined : createCommandTelemetry();
21675
+ const program = suppliedProgram ?? buildProgram();
21676
+ telemetry?.observe(program);
21197
21677
  try {
21198
21678
  await program.parseAsync(process.argv);
21199
21679
  } catch (error) {
21200
21680
  const exitCode = explainFailure(error, program);
21201
- telemetry.complete({ exitCode: exitCode ?? 1, error });
21681
+ telemetry?.complete({ exitCode: exitCode ?? 1, error });
21202
21682
  if (exitCode === null)
21203
21683
  throw error;
21204
21684
  process.exit(exitCode);
21205
21685
  }
21206
21686
  }
21207
- main();
21687
+
21688
+ // src/index.ts
21689
+ runTerminalCli();