sim 2.1.7-preview.92.1 → 2.1.8-dev.101.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 (57) hide show
  1. package/dist/auth/device-flow.d.ts +38 -0
  2. package/dist/commands/auth.d.ts +5 -0
  3. package/dist/commands/configure.d.ts +2 -0
  4. package/dist/commands/credentials.d.ts +3 -0
  5. package/dist/commands/protocol/chat.d.ts +11 -0
  6. package/dist/commands/protocol/files-get.d.ts +25 -0
  7. package/dist/commands/protocol/files-upload.d.ts +2 -0
  8. package/dist/commands/protocol/index.d.ts +3 -0
  9. package/dist/commands/protocol/knowledge-document-upload.d.ts +2 -0
  10. package/dist/commands/protocol/logs-follow.d.ts +39 -0
  11. package/dist/commands/protocol/resource-directory.d.ts +24 -0
  12. package/dist/commands/protocol/result.d.ts +2 -0
  13. package/dist/commands/protocol/tables-import.d.ts +2 -0
  14. package/dist/commands/protocol/workflow-run-follow.d.ts +56 -0
  15. package/dist/commands/protocol/workflow-run-get.d.ts +15 -0
  16. package/dist/commands/protocol/workflow-run-wait.d.ts +3 -0
  17. package/dist/commands/secrets.d.ts +3 -0
  18. package/dist/config/index.d.ts +2 -0
  19. package/dist/config/ini.d.ts +111 -0
  20. package/dist/config/paths.d.ts +21 -0
  21. package/dist/config/profile.d.ts +158 -0
  22. package/dist/context.d.ts +21 -0
  23. package/dist/contract/commands.d.ts +14 -0
  24. package/dist/contract/types.d.ts +304 -0
  25. package/dist/embed-context.d.ts +77 -0
  26. package/dist/embed-output.d.ts +15 -0
  27. package/dist/embed.d.ts +39 -0
  28. package/dist/generated/v2-api.d.ts +13498 -0
  29. package/dist/helpers.d.ts +9 -0
  30. package/dist/http/client.d.ts +166 -0
  31. package/dist/http/environment.d.ts +24 -0
  32. package/dist/index.js +768 -281
  33. package/dist/output/io.d.ts +5 -0
  34. package/dist/output/presentation.d.ts +4 -0
  35. package/dist/output/render.d.ts +60 -0
  36. package/dist/output/terminal-text.d.ts +17 -0
  37. package/dist/output/trace.d.ts +3 -0
  38. package/dist/program.d.ts +21 -0
  39. package/dist/runtime/build.d.ts +38 -0
  40. package/dist/runtime/derive.d.ts +20 -0
  41. package/dist/runtime/execute.d.ts +30 -0
  42. package/dist/runtime/naming.d.ts +25 -0
  43. package/dist/runtime/options.d.ts +7 -0
  44. package/dist/runtime/renamed.d.ts +6 -0
  45. package/dist/runtime/request.d.ts +107 -0
  46. package/dist/runtime/result.d.ts +50 -0
  47. package/dist/runtime/types.d.ts +23 -0
  48. package/dist/runtime.d.ts +5 -0
  49. package/dist/runtime.js +17708 -0
  50. package/dist/terminal/secret-input.d.ts +15 -0
  51. package/dist/terminal.d.ts +6 -0
  52. package/dist/transfer/local-file.d.ts +16 -0
  53. package/dist/transfer/streaming-upload.d.ts +16 -0
  54. package/dist/transfer/upload-session.d.ts +18 -0
  55. package/dist/update/check.d.ts +53 -0
  56. package/dist/version.d.ts +10 -0
  57. package/package.json +15 -2
package/dist/index.js CHANGED
@@ -2172,6 +2172,12 @@ var applyOptions = (object, options = {}) => {
2172
2172
  const colorLevel = stdoutColor ? stdoutColor.level : 0;
2173
2173
  object.level = options.level === undefined ? colorLevel : options.level;
2174
2174
  };
2175
+
2176
+ class Chalk {
2177
+ constructor(options) {
2178
+ return chalkFactory(options);
2179
+ }
2180
+ }
2175
2181
  var chalkFactory = (options) => {
2176
2182
  const chalk = (...strings) => strings.join(" ");
2177
2183
  applyOptions(chalk, options);
@@ -2300,6 +2306,54 @@ var chalk = createChalk();
2300
2306
  var chalkStderr = createChalk({ level: stderrColor ? stderrColor.level : 0 });
2301
2307
  var source_default = chalk;
2302
2308
 
2309
+ // src/embed-context.ts
2310
+ import { AsyncLocalStorage } from "node:async_hooks";
2311
+ function setSoftExitCode(code) {
2312
+ const ctx = embedStore.getStore();
2313
+ if (ctx)
2314
+ ctx.softExitCode = code;
2315
+ else
2316
+ process.exitCode = code;
2317
+ }
2318
+ var embedStore = new AsyncLocalStorage;
2319
+
2320
+ class EmbeddedExit extends Error {
2321
+ code;
2322
+ constructor(code) {
2323
+ super(`CLI exited with code ${code}`);
2324
+ this.code = code;
2325
+ }
2326
+ }
2327
+ function embeddedProfile() {
2328
+ const ctx = embedStore.getStore();
2329
+ if (!ctx)
2330
+ return null;
2331
+ return {
2332
+ name: "embedded",
2333
+ endpoint: ctx.identity.endpoint,
2334
+ apiKey: ctx.identity.apiKey,
2335
+ workspaceId: ctx.identity.workspaceId ?? null,
2336
+ output: "json",
2337
+ ...ctx.identity.transport ? { transport: ctx.identity.transport } : {},
2338
+ ...ctx.identity.signal ? { signal: ctx.identity.signal } : {},
2339
+ sources: { endpoint: "flag", apiKey: "flag", workspaceId: "flag", output: "flag" }
2340
+ };
2341
+ }
2342
+ function exitCli(code) {
2343
+ if (embedStore.getStore())
2344
+ throw new EmbeddedExit(code);
2345
+ return process.exit(code);
2346
+ }
2347
+
2348
+ // src/output/presentation.ts
2349
+ var plain = new Chalk({ level: 0 });
2350
+ function styles3() {
2351
+ return embedStore.getStore() ? plain : source_default;
2352
+ }
2353
+ function hasProgressTerminal() {
2354
+ return !embedStore.getStore() && Boolean(process.stderr.isTTY);
2355
+ }
2356
+
2303
2357
  // src/config/paths.ts
2304
2358
  import { homedir } from "node:os";
2305
2359
  import { join } from "node:path";
@@ -2634,6 +2688,9 @@ function refuseBlankOverrides(overrides) {
2634
2688
  }
2635
2689
  }
2636
2690
  function resolveProfile(overrides = {}) {
2691
+ const embedded = embeddedProfile();
2692
+ if (embedded)
2693
+ return embedded;
2637
2694
  refuseBlankOverrides(overrides);
2638
2695
  const named = overrides.profile || process.env.SIM_PROFILE;
2639
2696
  const name = named || DEFAULT_PROFILE;
@@ -2683,17 +2740,58 @@ function resolveProfile(overrides = {}) {
2683
2740
  }
2684
2741
  };
2685
2742
  }
2743
+ // src/output/io.ts
2744
+ import { format } from "node:util";
2745
+ function printLine(...args) {
2746
+ const context = embedStore.getStore();
2747
+ if (context)
2748
+ context.stdout.write(`${format(...args)}
2749
+ `);
2750
+ else
2751
+ console.log(...args);
2752
+ }
2753
+ function printError(...args) {
2754
+ const context = embedStore.getStore();
2755
+ if (context)
2756
+ context.stderr.write(`${format(...args)}
2757
+ `);
2758
+ else
2759
+ console.error(...args);
2760
+ }
2761
+ function writeStdout(chunk) {
2762
+ const context = embedStore.getStore();
2763
+ if (!context)
2764
+ return process.stdout.write(chunk);
2765
+ context.stdout.write(chunk);
2766
+ return true;
2767
+ }
2768
+ function writeStderr(chunk) {
2769
+ const context = embedStore.getStore();
2770
+ if (!context)
2771
+ return process.stderr.write(chunk);
2772
+ context.stderr.write(chunk);
2773
+ return true;
2774
+ }
2775
+
2686
2776
  // src/version.ts
2687
2777
  import { readFileSync as readFileSync2 } from "node:fs";
2688
2778
  function readPackageVersion() {
2689
- const metadata = JSON.parse(readFileSync2(new URL("../package.json", import.meta.url), "utf8"));
2690
- if (typeof metadata !== "object" || metadata === null || !("version" in metadata) || typeof metadata.version !== "string") {
2691
- throw new Error("CLI package metadata is missing a valid version");
2692
- }
2693
- return metadata.version;
2779
+ try {
2780
+ const metadata = JSON.parse(readFileSync2(new URL("../package.json", import.meta.url), "utf8"));
2781
+ if (typeof metadata === "object" && metadata !== null && "version" in metadata && typeof metadata.version === "string") {
2782
+ return metadata.version;
2783
+ }
2784
+ } catch {}
2785
+ return "0.0.0-embedded";
2786
+ }
2787
+ var cachedVersion = null;
2788
+ function cliVersion() {
2789
+ cachedVersion ??= readPackageVersion();
2790
+ return cachedVersion;
2791
+ }
2792
+ function userAgent() {
2793
+ return `sim-cli/${cliVersion()} node/${process.versions.node} (${process.platform}; ${process.arch})`;
2694
2794
  }
2695
- var CLI_VERSION = readPackageVersion();
2696
- var USER_AGENT = `sim-cli/${CLI_VERSION} node/${process.versions.node} (${process.platform}; ${process.arch})`;
2697
2795
 
2698
2796
  // src/http/environment.ts
2699
2797
  var reported = new Set;
@@ -2701,7 +2799,7 @@ function once(key, message) {
2701
2799
  if (reported.has(key))
2702
2800
  return;
2703
2801
  reported.add(key);
2704
- process.stderr.write(`warning: ${message}
2802
+ writeStderr(`warning: ${message}
2705
2803
  `);
2706
2804
  }
2707
2805
  var PROXY_VARIABLES = ["HTTPS_PROXY", "https_proxy", "HTTP_PROXY", "http_proxy"];
@@ -2868,7 +2966,7 @@ function debugEnabled(env = process.env) {
2868
2966
  return raw !== undefined && raw !== "" && raw !== "0" && raw.toLowerCase() !== "false";
2869
2967
  }
2870
2968
  function traceRequest(method, url, status, startedAt) {
2871
- process.stderr.write(`${source_default.dim(`[sim] ${method} ${url} → ${status} ${Math.round(performance.now() - startedAt)}ms`)}
2969
+ writeStderr(`${styles3().dim(`[sim] ${method} ${url} → ${status} ${Math.round(performance.now() - startedAt)}ms`)}
2872
2970
  `);
2873
2971
  }
2874
2972
  function withoutLeadingLabel(message, label) {
@@ -2966,17 +3064,20 @@ class SimClient {
2966
3064
  warnIfKeyOverCleartext(this.profile.endpoint, Boolean(apiKey));
2967
3065
  const timeoutMs = resolveTimeoutMs();
2968
3066
  const timeout = timeoutMs > 0 ? AbortSignal.timeout(timeoutMs) : undefined;
2969
- const signal = combineSignals(options.signal, timeout);
3067
+ const caller = combineSignals(options.signal, this.profile.signal);
3068
+ if (caller?.aborted)
3069
+ throw new SimApiError("Request cancelled.", 0);
3070
+ const signal = combineSignals(caller, timeout);
2970
3071
  const trace = debugEnabled();
2971
3072
  const startedAt = performance.now();
2972
3073
  let response;
2973
3074
  try {
2974
- response = await fetch(url, {
3075
+ response = await (this.profile.transport ?? fetch)(url, {
2975
3076
  method,
2976
3077
  headers: {
2977
3078
  ...apiKey ? { "x-api-key": apiKey } : {},
2978
3079
  accept: "application/json",
2979
- "user-agent": USER_AGENT,
3080
+ "user-agent": userAgent(),
2980
3081
  ...hasBody ? { "content-type": "application/json" } : {},
2981
3082
  ...options.headers
2982
3083
  },
@@ -2987,7 +3088,7 @@ class SimClient {
2987
3088
  } catch (cause) {
2988
3089
  if (trace)
2989
3090
  traceRequest(method, url, "failed", startedAt);
2990
- if (options.signal?.aborted) {
3091
+ if (caller?.aborted) {
2991
3092
  throw new SimApiError("Request cancelled.", 0);
2992
3093
  }
2993
3094
  if (timeout?.aborted) {
@@ -3041,14 +3142,14 @@ function pageProgress() {
3041
3142
  let reported = false;
3042
3143
  return {
3043
3144
  advance: (fetched) => {
3044
- if (!process.stderr.isTTY)
3145
+ if (!hasProgressTerminal())
3045
3146
  return;
3046
3147
  reported = true;
3047
- process.stderr.write(`\r${source_default.dim(`fetched ${fetched}…`)}\x1B[K`);
3148
+ writeStderr(`\r${styles3().dim(`fetched ${fetched}…`)}\x1B[K`);
3048
3149
  },
3049
3150
  finish: () => {
3050
3151
  if (reported)
3051
- process.stderr.write("\r\x1B[K");
3152
+ writeStderr("\r\x1B[K");
3052
3153
  }
3053
3154
  };
3054
3155
  }
@@ -6251,7 +6352,6 @@ function isWideCodePoint(codePoint) {
6251
6352
 
6252
6353
  // src/output/render.ts
6253
6354
  var EMPTY_GLYPH = "—";
6254
- var EMPTY = source_default.dim(EMPTY_GLYPH);
6255
6355
  var ESC = String.fromCharCode(27);
6256
6356
  var CONTROL_PATTERN = new RegExp([
6257
6357
  `${ESC}\\][^\\u0007${ESC}]*(?:\\u0007|${ESC}\\\\)?`,
@@ -6270,12 +6370,12 @@ function safeOneLine(value) {
6270
6370
  }
6271
6371
  function text(value) {
6272
6372
  if (value === null || value === undefined || value === "")
6273
- return EMPTY;
6373
+ return styles3().dim(EMPTY_GLYPH);
6274
6374
  return sanitize(String(value));
6275
6375
  }
6276
6376
  function timestamp2(value) {
6277
6377
  if (!value)
6278
- return EMPTY;
6378
+ return styles3().dim(EMPTY_GLYPH);
6279
6379
  const date = new Date(value);
6280
6380
  if (Number.isNaN(date.getTime()))
6281
6381
  return sanitize(String(value));
@@ -6283,12 +6383,12 @@ function timestamp2(value) {
6283
6383
  }
6284
6384
  function bool2(value) {
6285
6385
  if (value === null || value === undefined)
6286
- return EMPTY;
6287
- return value ? source_default.green("yes") : source_default.dim("no");
6386
+ return styles3().dim(EMPTY_GLYPH);
6387
+ return value ? styles3().green("yes") : styles3().dim("no");
6288
6388
  }
6289
6389
  function bytes(value) {
6290
6390
  if (value === null || value === undefined)
6291
- return EMPTY;
6391
+ return styles3().dim(EMPTY_GLYPH);
6292
6392
  const units = ["B", "KB", "MB", "GB", "TB"];
6293
6393
  let size = value;
6294
6394
  let unit = 0;
@@ -6300,7 +6400,7 @@ function bytes(value) {
6300
6400
  }
6301
6401
  function duration(ms) {
6302
6402
  if (ms === null || ms === undefined)
6303
- return EMPTY;
6403
+ return styles3().dim(EMPTY_GLYPH);
6304
6404
  if (ms < 1000)
6305
6405
  return `${Math.round(ms)}ms`;
6306
6406
  if (ms < 60000)
@@ -6331,11 +6431,11 @@ function clamp(value, width) {
6331
6431
  }
6332
6432
  function renderTable(rows, columns) {
6333
6433
  if (rows.length === 0)
6334
- return source_default.dim("No results.");
6434
+ return styles3().dim("No results.");
6335
6435
  const headers = columns.map((column) => sanitize(column.header));
6336
6436
  const cells = rows.map((row) => columns.map((column) => clamp(oneLine(column.value(row)), MAX_CELL_WIDTH)));
6337
6437
  const widths = columns.map((_column, index) => Math.max(visibleWidth(headers[index]), ...cells.map((line) => visibleWidth(line[index]))));
6338
- const header = headers.map((label, index) => source_default.dim(pad(label.toUpperCase(), widths[index]))).join(" ").trimEnd();
6438
+ const header = headers.map((label, index) => styles3().dim(pad(label.toUpperCase(), widths[index]))).join(" ").trimEnd();
6339
6439
  const body = cells.map((line) => line.map((cell, index) => pad(cell, widths[index])).join(" ").trimEnd());
6340
6440
  return [header, ...body].join(`
6341
6441
  `);
@@ -6350,36 +6450,36 @@ function renderMachine(format, raw) {
6350
6450
  function printList(format, rows, columns, raw = rows) {
6351
6451
  const machine = renderMachine(format, raw);
6352
6452
  if (machine !== null) {
6353
- console.log(machine);
6453
+ printLine(machine);
6354
6454
  return;
6355
6455
  }
6356
6456
  if (format === "text") {
6357
6457
  for (const row of rows) {
6358
- console.log(columns.map((column) => oneLine(stripAnsi(column.value(row)))).join("\t"));
6458
+ printLine(columns.map((column) => oneLine(stripAnsi(column.value(row)))).join("\t"));
6359
6459
  }
6360
6460
  return;
6361
6461
  }
6362
- console.log(renderTable(rows, columns));
6462
+ printLine(renderTable(rows, columns));
6363
6463
  }
6364
6464
  function printDocument(format, raw) {
6365
- console.log(format === "yaml" ? renderMachine("yaml", raw) : JSON.stringify(raw, null, 2));
6465
+ printLine(format === "yaml" ? renderMachine("yaml", raw) : JSON.stringify(raw, null, 2));
6366
6466
  }
6367
6467
  function printRecord(format, fields, raw) {
6368
6468
  const machine = renderMachine(format, raw);
6369
6469
  if (machine !== null) {
6370
- console.log(machine);
6470
+ printLine(machine);
6371
6471
  return;
6372
6472
  }
6373
6473
  const safeFields = fields.map(([label, value]) => [safeOneLine(label), value]);
6374
6474
  if (format === "text") {
6375
6475
  for (const [label, value] of safeFields) {
6376
- console.log(`${label} ${oneLine(stripAnsi(value))}`);
6476
+ printLine(`${label} ${oneLine(stripAnsi(value))}`);
6377
6477
  }
6378
6478
  return;
6379
6479
  }
6380
6480
  const width = Math.max(...safeFields.map(([label]) => visibleWidth(label)));
6381
6481
  for (const [label, value] of safeFields) {
6382
- console.log(`${source_default.dim(pad(`${label}:`, width + 1))} ${clamp(oneLine(value), MAX_RECORD_WIDTH)}`);
6482
+ printLine(`${styles3().dim(pad(`${label}:`, width + 1))} ${clamp(oneLine(value), MAX_RECORD_WIDTH)}`);
6383
6483
  }
6384
6484
  }
6385
6485
 
@@ -6475,7 +6575,7 @@ async function pollForKey(endpoint, auth, signal) {
6475
6575
  headers: {
6476
6576
  "content-type": "application/json",
6477
6577
  accept: "application/json",
6478
- "user-agent": USER_AGENT
6578
+ "user-agent": userAgent()
6479
6579
  },
6480
6580
  body: JSON.stringify({ request: auth.request, verifier: auth.pollSecret }),
6481
6581
  signal,
@@ -6486,7 +6586,7 @@ async function pollForKey(endpoint, auth, signal) {
6486
6586
  consecutiveTransportFailures++;
6487
6587
  if (!warnedAboutTransport && consecutiveTransportFailures >= TRANSPORT_FAILURES_BEFORE_WARNING) {
6488
6588
  warnedAboutTransport = true;
6489
- 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.
6589
+ writeStderr(`Still waiting: ${endpoint} is not answering the login poll (${cause.message}). Check the endpoint; retrying until you approve or the login times out.
6490
6590
  `);
6491
6591
  }
6492
6592
  }
@@ -6636,8 +6736,8 @@ var V2_OPERATIONS = {
6636
6736
  },
6637
6737
  outputColumns: {
6638
6738
  kind: "array",
6639
- required: true,
6640
- describe: "Columns created for producer outputs."
6739
+ default: [],
6740
+ 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."
6641
6741
  },
6642
6742
  autoRun: {
6643
6743
  kind: "boolean",
@@ -6723,7 +6823,7 @@ var V2_OPERATIONS = {
6723
6823
  summary: "Delete Files",
6724
6824
  body: {
6725
6825
  workspaceId: { kind: "string", required: true, describe: "Workspace containing the files." },
6726
- fileIds: { kind: "array", required: true, describe: "File identifiers to update." }
6826
+ fileIds: { kind: "array", required: true, describe: "File identifiers to delete." }
6727
6827
  }
6728
6828
  },
6729
6829
  bulkDeleteTables: {
@@ -6941,7 +7041,7 @@ var V2_OPERATIONS = {
6941
7041
  rowId: { kind: "string", describe: "Row whose runs should be canceled for row scope." },
6942
7042
  filter: {
6943
7043
  kind: "unknown",
6944
- describe: 'Recursive predicate tree. Each group node is exactly one non-empty `all` or `any` array whose members are further groups or `{ field, op, value }` conditions; the root must be a group, not a bare condition. At most 100 members per group, 10 levels of nesting, and 500 nodes in total. The negating operators include nulls: `ne`, `nin`, `ncontains`, `nlike`, and `nilike` match rows whose column is null or absent, so "not X" is not the complement of "X" over a nullable column. That holds for every column type, multi-select included. To exclude nulls, `all`-combine the negation with `isNotEmpty` (multi-select) or `isNotNull`. Comparison: `eq`, `ne`, `gt`, `gte`, `lt`, `lte`. Membership: `in`, `nin` (array operand). Emptiness: `isEmpty`, `isNotEmpty`, `isNull`, `isNotNull` (no operand). Substring, always case-insensitive, operand matched literally: `contains`, `ncontains`, `startsWith`, `endsWith`. Pattern: `like`/`nlike` (case-sensitive), `ilike`/`nilike` (case-insensitive). **`*` is the only wildcard** and stands for any run of characters; `%`, `_`, and backslash match themselves. Use `like: "Hi*"`, not `like: "Hi%"`. A `select` column compares by option id and restricts its operators: single-select accepts `eq`, `ne`, `in`, `nin`; multi-select accepts `contains`, `ncontains`. Option names are accepted as operands and resolved to ids.'
7044
+ describe: 'A single `{ field, op, value }` condition or a recursive `all`/`any` group; either form is normalized to a grouped predicate after validation. At most 100 members per group, 10 levels of nesting, and 500 nodes in total. The negating operators include nulls: `ne`, `nin`, `ncontains`, `nlike`, and `nilike` match rows whose column is null or absent, so "not X" is not the complement of "X" over a nullable column. That holds for every column type, multi-select included. To exclude nulls, `all`-combine the negation with `isNotEmpty` (multi-select) or `isNotNull`. Comparison: `eq`, `ne`, `gt`, `gte`, `lt`, `lte`. Membership: `in`, `nin` (array operand). Emptiness: `isEmpty`, `isNotEmpty`, `isNull`, `isNotNull` (no operand). Substring, always case-insensitive, operand matched literally: `contains`, `ncontains`, `startsWith`, `endsWith`. Pattern: `like`/`nlike` (case-sensitive), `ilike`/`nilike` (case-insensitive). **`*` is the only wildcard** and stands for any run of characters; `%`, `_`, and backslash match themselves. Use `like: "Hi*"`, not `like: "Hi%"`. A `select` column compares by option id and restricts its operators: single-select accepts `eq`, `ne`, `in`, `nin`; multi-select accepts `contains`, `ncontains`. Option names are accepted as operands and resolved to ids.'
6945
7045
  },
6946
7046
  excludeRowIds: { kind: "array", describe: "Rows excluded from an all-scope cancellation." }
6947
7047
  }
@@ -6972,6 +7072,11 @@ var V2_OPERATIONS = {
6972
7072
  conversationId: {
6973
7073
  kind: "string",
6974
7074
  describe: "Conversation to continue; a new one starts when omitted."
7075
+ },
7076
+ effort: {
7077
+ kind: "enum",
7078
+ values: ["low", "medium", "high", "xhigh", "max"],
7079
+ describe: "Model effort for this turn; defaults to the deployment default (high)."
6975
7080
  }
6976
7081
  }
6977
7082
  },
@@ -7534,7 +7639,7 @@ var V2_OPERATIONS = {
7534
7639
  description: { kind: "string", describe: "Optional credential description." },
7535
7640
  id: {
7536
7641
  kind: "string",
7537
- describe: "Required only when provider discovery requests a client-generated ID."
7642
+ 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."
7538
7643
  },
7539
7644
  credentials: {
7540
7645
  kind: "string",
@@ -7610,7 +7715,7 @@ var V2_OPERATIONS = {
7610
7715
  rowIds: { kind: "array", describe: "Explicit row subset to run." },
7611
7716
  filter: {
7612
7717
  kind: "unknown",
7613
- describe: 'Recursive predicate tree. Each group node is exactly one non-empty `all` or `any` array whose members are further groups or `{ field, op, value }` conditions; the root must be a group, not a bare condition. At most 100 members per group, 10 levels of nesting, and 500 nodes in total. The negating operators include nulls: `ne`, `nin`, `ncontains`, `nlike`, and `nilike` match rows whose column is null or absent, so "not X" is not the complement of "X" over a nullable column. That holds for every column type, multi-select included. To exclude nulls, `all`-combine the negation with `isNotEmpty` (multi-select) or `isNotNull`. Comparison: `eq`, `ne`, `gt`, `gte`, `lt`, `lte`. Membership: `in`, `nin` (array operand). Emptiness: `isEmpty`, `isNotEmpty`, `isNull`, `isNotNull` (no operand). Substring, always case-insensitive, operand matched literally: `contains`, `ncontains`, `startsWith`, `endsWith`. Pattern: `like`/`nlike` (case-sensitive), `ilike`/`nilike` (case-insensitive). **`*` is the only wildcard** and stands for any run of characters; `%`, `_`, and backslash match themselves. Use `like: "Hi*"`, not `like: "Hi%"`. A `select` column compares by option id and restricts its operators: single-select accepts `eq`, `ne`, `in`, `nin`; multi-select accepts `contains`, `ncontains`. Option names are accepted as operands and resolved to ids.'
7718
+ describe: 'A single `{ field, op, value }` condition or a recursive `all`/`any` group; either form is normalized to a grouped predicate after validation. At most 100 members per group, 10 levels of nesting, and 500 nodes in total. The negating operators include nulls: `ne`, `nin`, `ncontains`, `nlike`, and `nilike` match rows whose column is null or absent, so "not X" is not the complement of "X" over a nullable column. That holds for every column type, multi-select included. To exclude nulls, `all`-combine the negation with `isNotEmpty` (multi-select) or `isNotNull`. Comparison: `eq`, `ne`, `gt`, `gte`, `lt`, `lte`. Membership: `in`, `nin` (array operand). Emptiness: `isEmpty`, `isNotEmpty`, `isNull`, `isNotNull` (no operand). Substring, always case-insensitive, operand matched literally: `contains`, `ncontains`, `startsWith`, `endsWith`. Pattern: `like`/`nlike` (case-sensitive), `ilike`/`nilike` (case-insensitive). **`*` is the only wildcard** and stands for any run of characters; `%`, `_`, and backslash match themselves. Use `like: "Hi*"`, not `like: "Hi%"`. A `select` column compares by option id and restricts its operators: single-select accepts `eq`, `ne`, `in`, `nin`; multi-select accepts `contains`, `ncontains`. Option names are accepted as operands and resolved to ids.'
7614
7719
  },
7615
7720
  excludeRowIds: { kind: "array", describe: "Rows excluded from a select-all run scope." },
7616
7721
  limit: { kind: "object", describe: "Optional cap on eligible rows to run." }
@@ -8144,7 +8249,7 @@ var V2_OPERATIONS = {
8144
8249
  workspaceId: { kind: "string", required: true, describe: "Unique workspace identifier." },
8145
8250
  filter: {
8146
8251
  kind: "unknown",
8147
- describe: 'Recursive predicate tree. Each group node is exactly one non-empty `all` or `any` array whose members are further groups or `{ field, op, value }` conditions; the root must be a group, not a bare condition. At most 100 members per group, 10 levels of nesting, and 500 nodes in total. The negating operators include nulls: `ne`, `nin`, `ncontains`, `nlike`, and `nilike` match rows whose column is null or absent, so "not X" is not the complement of "X" over a nullable column. That holds for every column type, multi-select included. To exclude nulls, `all`-combine the negation with `isNotEmpty` (multi-select) or `isNotNull`. Comparison: `eq`, `ne`, `gt`, `gte`, `lt`, `lte`. Membership: `in`, `nin` (array operand). Emptiness: `isEmpty`, `isNotEmpty`, `isNull`, `isNotNull` (no operand). Substring, always case-insensitive, operand matched literally: `contains`, `ncontains`, `startsWith`, `endsWith`. Pattern: `like`/`nlike` (case-sensitive), `ilike`/`nilike` (case-insensitive). **`*` is the only wildcard** and stands for any run of characters; `%`, `_`, and backslash match themselves. Use `like: "Hi*"`, not `like: "Hi%"`. A `select` column compares by option id and restricts its operators: single-select accepts `eq`, `ne`, `in`, `nin`; multi-select accepts `contains`, `ncontains`. Option names are accepted as operands and resolved to ids.'
8252
+ describe: 'A single `{ field, op, value }` condition or a recursive `all`/`any` group; either form is normalized to a grouped predicate after validation. At most 100 members per group, 10 levels of nesting, and 500 nodes in total. The negating operators include nulls: `ne`, `nin`, `ncontains`, `nlike`, and `nilike` match rows whose column is null or absent, so "not X" is not the complement of "X" over a nullable column. That holds for every column type, multi-select included. To exclude nulls, `all`-combine the negation with `isNotEmpty` (multi-select) or `isNotNull`. Comparison: `eq`, `ne`, `gt`, `gte`, `lt`, `lte`. Membership: `in`, `nin` (array operand). Emptiness: `isEmpty`, `isNotEmpty`, `isNull`, `isNotNull` (no operand). Substring, always case-insensitive, operand matched literally: `contains`, `ncontains`, `startsWith`, `endsWith`. Pattern: `like`/`nlike` (case-sensitive), `ilike`/`nilike` (case-insensitive). **`*` is the only wildcard** and stands for any run of characters; `%`, `_`, and backslash match themselves. Use `like: "Hi*"`, not `like: "Hi%"`. A `select` column compares by option id and restricts its operators: single-select accepts `eq`, `ne`, `in`, `nin`; multi-select accepts `contains`, `ncontains`. Option names are accepted as operands and resolved to ids.'
8148
8253
  },
8149
8254
  limit: { kind: "integer", describe: "Maximum matching rows to delete." },
8150
8255
  rowIds: { kind: "array", describe: "Explicit row identifiers to delete." }
@@ -8393,7 +8498,7 @@ var V2_OPERATIONS = {
8393
8498
  },
8394
8499
  selectedOutputs: {
8395
8500
  kind: "array",
8396
- describe: "Block output references to include in a streamed response. Use `<blockName>.<outputPath>` for the executed workflow or `<childWorkflowId>.<blockName>.<outputPath>` for a child workflow; block names are normalized workflow reference names. Selecting a child workflow applies to every invocation of it. Requires `stream: true` — it shapes the streamed envelope only, so it is rejected on a sync request and when `async` is true. To narrow a finished run, pass `selectedOutputs` to the run resource instead."
8501
+ describe: "Block output references to include in the response. Use `<blockName>.<outputPath>` for the executed workflow or `<childWorkflowId>.<blockName>.<outputPath>` for a child workflow; block names are normalized workflow reference names, and selecting a child workflow applies to every invocation of it. On a sync request the named outputs come back in `blockOutputs`, keyed by these selector strings exactly as sent; on a stream they shape the streamed envelope. A selector whose block name or id matches no block in the workflow is rejected with `400` naming the available blocks, before the run starts. A selector whose block did not run or whose path is absent is omitted. Rejected when `async` is true — a queued run has produced nothing to select; narrow the finished run via the run resource instead."
8397
8502
  },
8398
8503
  includeThinking: {
8399
8504
  kind: "boolean",
@@ -8431,7 +8536,13 @@ var V2_OPERATIONS = {
8431
8536
  pathParams: ["workflowId"],
8432
8537
  pathParamDocs: { workflowId: "Unique workflow identifier." },
8433
8538
  responseMode: "json",
8434
- summary: "Export Workflow"
8539
+ summary: "Export Workflow",
8540
+ query: {
8541
+ includeWorkspaceBindings: {
8542
+ kind: "boolean",
8543
+ 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."
8544
+ }
8545
+ }
8435
8546
  },
8436
8547
  getAuditLog: {
8437
8548
  method: "GET",
@@ -8652,6 +8763,10 @@ var V2_OPERATIONS = {
8652
8763
  values: ["info", "error"],
8653
8764
  describe: "Severity level to include."
8654
8765
  },
8766
+ includeHandledErrors: {
8767
+ kind: "boolean",
8768
+ 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."
8769
+ },
8655
8770
  startDate: {
8656
8771
  kind: "string",
8657
8772
  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."
@@ -8663,7 +8778,26 @@ var V2_OPERATIONS = {
8663
8778
  segmentCount: {
8664
8779
  kind: "integer",
8665
8780
  default: 72,
8666
- describe: "Number of equal time buckets to divide the window into, from 1 to 500. Exactly this many buckets are always returned. 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."
8781
+ 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."
8782
+ },
8783
+ includeEmpty: {
8784
+ kind: "enum",
8785
+ values: [
8786
+ "true",
8787
+ "1",
8788
+ "yes",
8789
+ "on",
8790
+ "y",
8791
+ "enabled",
8792
+ "false",
8793
+ "0",
8794
+ "no",
8795
+ "off",
8796
+ "n",
8797
+ "disabled"
8798
+ ],
8799
+ default: false,
8800
+ 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."
8667
8801
  }
8668
8802
  }
8669
8803
  },
@@ -8721,7 +8855,7 @@ var V2_OPERATIONS = {
8721
8855
  groupId: "Workflow or enrichment group to run."
8722
8856
  },
8723
8857
  responseMode: "json",
8724
- summary: "Get Enrichment Run Detail",
8858
+ summary: "Get Row Group Run",
8725
8859
  query: {
8726
8860
  workspaceId: { kind: "string", required: true, describe: "Workspace that owns the table." }
8727
8861
  }
@@ -9121,6 +9255,10 @@ var V2_OPERATIONS = {
9121
9255
  values: ["builtin", "custom"],
9122
9256
  describe: "Restrict to shipped blocks or to this workspace’s deployed custom blocks."
9123
9257
  },
9258
+ includeSunset: {
9259
+ kind: "boolean",
9260
+ 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."
9261
+ },
9124
9262
  sortBy: {
9125
9263
  kind: "enum",
9126
9264
  values: ["id", "name", "category"],
@@ -9196,6 +9334,21 @@ var V2_OPERATIONS = {
9196
9334
  search: {
9197
9335
  kind: "string",
9198
9336
  describe: "Case-insensitive substring match against the connector name."
9337
+ },
9338
+ detail: {
9339
+ kind: "enum",
9340
+ values: ["summary", "full"],
9341
+ default: "summary",
9342
+ 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."
9343
+ },
9344
+ limit: {
9345
+ kind: "integer",
9346
+ default: 25,
9347
+ describe: "Maximum connector types to return per page. Must be a whole number from 1 to 100. Defaults to 25."
9348
+ },
9349
+ cursor: {
9350
+ kind: "string",
9351
+ 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."
9199
9352
  }
9200
9353
  }
9201
9354
  },
@@ -9797,6 +9950,10 @@ var V2_OPERATIONS = {
9797
9950
  kind: "string",
9798
9951
  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."
9799
9952
  },
9953
+ includeHandledErrors: {
9954
+ kind: "boolean",
9955
+ 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."
9956
+ },
9800
9957
  status: {
9801
9958
  kind: "string",
9802
9959
  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."
@@ -10042,7 +10199,7 @@ var V2_OPERATIONS = {
10042
10199
  pathParams: ["tableId"],
10043
10200
  pathParamDocs: { tableId: "Unique table identifier." },
10044
10201
  responseMode: "json",
10045
- summary: "List Active Run Dispatches",
10202
+ summary: "List Run Dispatches",
10046
10203
  query: {
10047
10204
  workspaceId: { kind: "string", required: true, describe: "Workspace that owns the table." }
10048
10205
  }
@@ -10454,8 +10611,8 @@ var V2_OPERATIONS = {
10454
10611
  },
10455
10612
  limit: {
10456
10613
  kind: "integer",
10457
- default: 50,
10458
- describe: "Maximum workspaces to return per page. Must be a whole number from 1 to 100. Defaults to 50."
10614
+ default: 25,
10615
+ describe: "Maximum workspaces to return per page. Must be a whole number from 1 to 100. Defaults to 25."
10459
10616
  },
10460
10617
  cursor: {
10461
10618
  kind: "string",
@@ -10567,7 +10724,9 @@ var V2_OPERATIONS = {
10567
10724
  method: "GET",
10568
10725
  path: "/api/v2/files/[fileId]/text",
10569
10726
  pathParams: ["fileId"],
10570
- pathParamDocs: { fileId: "File identifier." },
10727
+ pathParamDocs: {
10728
+ fileId: "File identifier, or the file’s VFS path: `files/<folder>/<name>`, or `uploads/<name>` for a Chat upload."
10729
+ },
10571
10730
  responseMode: "json",
10572
10731
  summary: "Read File Text",
10573
10732
  query: {
@@ -10598,7 +10757,7 @@ var V2_OPERATIONS = {
10598
10757
  destinationPath: {
10599
10758
  kind: "string",
10600
10759
  required: true,
10601
- describe: "New full path for the folder and its descendants."
10760
+ 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)."
10602
10761
  }
10603
10762
  }
10604
10763
  },
@@ -10614,7 +10773,7 @@ var V2_OPERATIONS = {
10614
10773
  destinationPath: {
10615
10774
  kind: "string",
10616
10775
  required: true,
10617
- describe: "New full path for the folder and its descendants."
10776
+ 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)."
10618
10777
  }
10619
10778
  }
10620
10779
  },
@@ -10630,7 +10789,7 @@ var V2_OPERATIONS = {
10630
10789
  destinationPath: {
10631
10790
  kind: "string",
10632
10791
  required: true,
10633
- describe: "New full path for the folder and its descendants."
10792
+ 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)."
10634
10793
  }
10635
10794
  }
10636
10795
  },
@@ -10646,7 +10805,7 @@ var V2_OPERATIONS = {
10646
10805
  destinationPath: {
10647
10806
  kind: "string",
10648
10807
  required: true,
10649
- describe: "New full path for the folder and its descendants."
10808
+ 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)."
10650
10809
  }
10651
10810
  }
10652
10811
  },
@@ -11019,7 +11178,7 @@ var V2_OPERATIONS = {
11019
11178
  q: { kind: "string", required: true, describe: "Case-insensitive cell substring to find." },
11020
11179
  predicate: {
11021
11180
  kind: "unknown",
11022
- describe: 'Recursive predicate tree. Each group node is exactly one non-empty `all` or `any` array whose members are further groups or `{ field, op, value }` conditions; the root must be a group, not a bare condition. At most 100 members per group, 10 levels of nesting, and 500 nodes in total. The negating operators include nulls: `ne`, `nin`, `ncontains`, `nlike`, and `nilike` match rows whose column is null or absent, so "not X" is not the complement of "X" over a nullable column. That holds for every column type, multi-select included. To exclude nulls, `all`-combine the negation with `isNotEmpty` (multi-select) or `isNotNull`. Comparison: `eq`, `ne`, `gt`, `gte`, `lt`, `lte`. Membership: `in`, `nin` (array operand). Emptiness: `isEmpty`, `isNotEmpty`, `isNull`, `isNotNull` (no operand). Substring, always case-insensitive, operand matched literally: `contains`, `ncontains`, `startsWith`, `endsWith`. Pattern: `like`/`nlike` (case-sensitive), `ilike`/`nilike` (case-insensitive). **`*` is the only wildcard** and stands for any run of characters; `%`, `_`, and backslash match themselves. Use `like: "Hi*"`, not `like: "Hi%"`. A `select` column compares by option id and restricts its operators: single-select accepts `eq`, `ne`, `in`, `nin`; multi-select accepts `contains`, `ncontains`. Option names are accepted as operands and resolved to ids.'
11181
+ describe: 'A single `{ field, op, value }` condition or a recursive `all`/`any` group; either form is normalized to a grouped predicate after validation. At most 100 members per group, 10 levels of nesting, and 500 nodes in total. The negating operators include nulls: `ne`, `nin`, `ncontains`, `nlike`, and `nilike` match rows whose column is null or absent, so "not X" is not the complement of "X" over a nullable column. That holds for every column type, multi-select included. To exclude nulls, `all`-combine the negation with `isNotEmpty` (multi-select) or `isNotNull`. Comparison: `eq`, `ne`, `gt`, `gte`, `lt`, `lte`. Membership: `in`, `nin` (array operand). Emptiness: `isEmpty`, `isNotEmpty`, `isNull`, `isNotNull` (no operand). Substring, always case-insensitive, operand matched literally: `contains`, `ncontains`, `startsWith`, `endsWith`. Pattern: `like`/`nlike` (case-sensitive), `ilike`/`nilike` (case-insensitive). **`*` is the only wildcard** and stands for any run of characters; `%`, `_`, and backslash match themselves. Use `like: "Hi*"`, not `like: "Hi%"`. A `select` column compares by option id and restricts its operators: single-select accepts `eq`, `ne`, `in`, `nin`; multi-select accepts `contains`, `ncontains`. Option names are accepted as operands and resolved to ids.'
11023
11182
  },
11024
11183
  sort: { kind: "array", describe: "Ordered table-row sort specification." }
11025
11184
  }
@@ -11461,7 +11620,7 @@ var V2_OPERATIONS = {
11461
11620
  filter: {
11462
11621
  kind: "unknown",
11463
11622
  required: true,
11464
- describe: 'Recursive predicate tree. Each group node is exactly one non-empty `all` or `any` array whose members are further groups or `{ field, op, value }` conditions; the root must be a group, not a bare condition. At most 100 members per group, 10 levels of nesting, and 500 nodes in total. The negating operators include nulls: `ne`, `nin`, `ncontains`, `nlike`, and `nilike` match rows whose column is null or absent, so "not X" is not the complement of "X" over a nullable column. That holds for every column type, multi-select included. To exclude nulls, `all`-combine the negation with `isNotEmpty` (multi-select) or `isNotNull`. Comparison: `eq`, `ne`, `gt`, `gte`, `lt`, `lte`. Membership: `in`, `nin` (array operand). Emptiness: `isEmpty`, `isNotEmpty`, `isNull`, `isNotNull` (no operand). Substring, always case-insensitive, operand matched literally: `contains`, `ncontains`, `startsWith`, `endsWith`. Pattern: `like`/`nlike` (case-sensitive), `ilike`/`nilike` (case-insensitive). **`*` is the only wildcard** and stands for any run of characters; `%`, `_`, and backslash match themselves. Use `like: "Hi*"`, not `like: "Hi%"`. A `select` column compares by option id and restricts its operators: single-select accepts `eq`, `ne`, `in`, `nin`; multi-select accepts `contains`, `ncontains`. Option names are accepted as operands and resolved to ids.'
11623
+ describe: 'A single `{ field, op, value }` condition or a recursive `all`/`any` group; either form is normalized to a grouped predicate after validation. At most 100 members per group, 10 levels of nesting, and 500 nodes in total. The negating operators include nulls: `ne`, `nin`, `ncontains`, `nlike`, and `nilike` match rows whose column is null or absent, so "not X" is not the complement of "X" over a nullable column. That holds for every column type, multi-select included. To exclude nulls, `all`-combine the negation with `isNotEmpty` (multi-select) or `isNotNull`. Comparison: `eq`, `ne`, `gt`, `gte`, `lt`, `lte`. Membership: `in`, `nin` (array operand). Emptiness: `isEmpty`, `isNotEmpty`, `isNull`, `isNotNull` (no operand). Substring, always case-insensitive, operand matched literally: `contains`, `ncontains`, `startsWith`, `endsWith`. Pattern: `like`/`nlike` (case-sensitive), `ilike`/`nilike` (case-insensitive). **`*` is the only wildcard** and stands for any run of characters; `%`, `_`, and backslash match themselves. Use `like: "Hi*"`, not `like: "Hi%"`. A `select` column compares by option id and restricts its operators: single-select accepts `eq`, `ne`, `in`, `nin`; multi-select accepts `contains`, `ncontains`. Option names are accepted as operands and resolved to ids.'
11465
11624
  },
11466
11625
  data: {
11467
11626
  kind: "object",
@@ -11843,10 +12002,10 @@ async function chooseWorkspace(client) {
11843
12002
  if (workspaces.length > MAX_INTERACTIVE_WORKSPACES) {
11844
12003
  throw new SimApiError(`The active API key can access more than ${MAX_INTERACTIVE_WORKSPACES} workspaces, which is too many to show interactively. Pass --workspace <id> instead.`, 0);
11845
12004
  }
11846
- console.log(`
12005
+ printLine(`
11847
12006
  Available workspaces:`);
11848
12007
  for (const [index, workspace] of workspaces.entries()) {
11849
- console.log(` ${index + 1}) ${safeOneLine(workspace.name)} (${workspace.id})`);
12008
+ printLine(` ${index + 1}) ${safeOneLine(workspace.name)} (${workspace.id})`);
11850
12009
  }
11851
12010
  const prompt = createInterface({ input: process.stdin, output: process.stderr });
11852
12011
  try {
@@ -11871,10 +12030,10 @@ function addProfileCommand() {
11871
12030
  auth_profile: authProfile,
11872
12031
  workspace: normalizeWorkspaceId(workspace.id, "the workspace response")
11873
12032
  });
11874
- console.log(source_default.green(`✓ Added profile "${safeOneLine(profileName)}" in ${configPath()}`));
11875
- console.log(` Workspace: ${safeOneLine(workspace.name)} (${workspace.id})`);
11876
- console.log(` Authentication: ${safeOneLine(authProfile)}`);
11877
- console.log(source_default.dim(` Try: sim --profile ${safeOneLine(profileName)} whoami`));
12033
+ printLine(styles3().green(`✓ Added profile "${safeOneLine(profileName)}" in ${configPath()}`));
12034
+ printLine(` Workspace: ${safeOneLine(workspace.name)} (${workspace.id})`);
12035
+ printLine(` Authentication: ${safeOneLine(authProfile)}`);
12036
+ printLine(styles3().dim(` Try: sim --profile ${safeOneLine(profileName)} whoami`));
11878
12037
  });
11879
12038
  }
11880
12039
  function loginCommand() {
@@ -11891,21 +12050,21 @@ function loginCommand() {
11891
12050
  if (readCredentialsProfile(profile.name).api_key && !options.yes) {
11892
12051
  const confirmed = await confirmProfileOverwrite(profile.name);
11893
12052
  if (!confirmed) {
11894
- console.log(source_default.dim("Login cancelled; the existing profile was not changed."));
12053
+ printLine(styles3().dim("Login cancelled; the existing profile was not changed."));
11895
12054
  return;
11896
12055
  }
11897
12056
  }
11898
12057
  const auth = createAuthRequest();
11899
12058
  const url = buildApprovalUrl(profile.endpoint, auth, scope, profile.workspaceId ?? undefined);
11900
- console.log(`Signing in to ${source_default.bold(profile.endpoint)} as profile ${source_default.bold(safeOneLine(profile.name))}`);
11901
- console.log(`
11902
- Pairing code: ${source_default.bold(auth.pairing)}`);
11903
- console.log(source_default.dim(`Confirm this code matches what the browser shows before approving.
12059
+ printLine(`Signing in to ${styles3().bold(profile.endpoint)} as profile ${styles3().bold(safeOneLine(profile.name))}`);
12060
+ printLine(`
12061
+ Pairing code: ${styles3().bold(auth.pairing)}`);
12062
+ printLine(styles3().dim(`Confirm this code matches what the browser shows before approving.
11904
12063
  `));
11905
- console.log(url);
12064
+ printLine(url);
11906
12065
  if (options.browser)
11907
12066
  openBrowser(url);
11908
- console.log(source_default.dim(`
12067
+ printLine(styles3().dim(`
11909
12068
  Waiting for approval…`));
11910
12069
  const key = await pollForKey(profile.endpoint, auth);
11911
12070
  if (key.scope !== scope) {
@@ -11918,14 +12077,14 @@ Waiting for approval…`));
11918
12077
  requireStorableKey(key.apiKey);
11919
12078
  writeConfigProfile(profile.name, settings);
11920
12079
  writeCredentialsProfile(profile.name, key.apiKey);
11921
- console.log(source_default.green(`
12080
+ printLine(styles3().green(`
11922
12081
  ✓ Logged in. Key stored in ${credentialsPath()}`));
11923
12082
  if (key.workspaceBound && key.workspaceId) {
11924
- console.log(source_default.dim(` Workspace-scoped key — it can only reach ${key.workspaceId}.`));
12083
+ printLine(styles3().dim(` Workspace-scoped key — it can only reach ${key.workspaceId}.`));
11925
12084
  } else if (key.workspaceId) {
11926
- console.log(source_default.dim(` Personal key, defaulting to ${key.workspaceId}. Override per command with --workspace.`));
12085
+ printLine(styles3().dim(` Personal key, defaulting to ${key.workspaceId}. Override per command with --workspace.`));
11927
12086
  } else {
11928
- console.log(source_default.dim(" Personal key with no default workspace. Set one with: sim configure --set-workspace <id>"));
12087
+ printLine(styles3().dim(" Personal key with no default workspace. Set one with: sim configure --set-workspace <id>"));
11929
12088
  }
11930
12089
  });
11931
12090
  }
@@ -11939,10 +12098,10 @@ function logoutCommand() {
11939
12098
  }
11940
12099
  const removed = deleteProfile(profileName);
11941
12100
  if (!removed.config && !removed.credentials) {
11942
- console.log(source_default.dim(`Nothing stored for profile "${safeOneLine(profileName)}".`));
12101
+ printLine(styles3().dim(`Nothing stored for profile "${safeOneLine(profileName)}".`));
11943
12102
  return;
11944
12103
  }
11945
- console.log(source_default.green(`✓ Removed profile "${safeOneLine(profileName)}".`));
12104
+ printLine(styles3().green(`✓ Removed profile "${safeOneLine(profileName)}".`));
11946
12105
  return;
11947
12106
  }
11948
12107
  const profile = profileFrom(command);
@@ -11951,12 +12110,12 @@ function logoutCommand() {
11951
12110
  throw new SimApiError(`Profile "${redact(profile.name)}" shares authentication with "${redact(authProfile)}". Log out of the authentication profile instead: sim logout --profile ${redact(authProfile)}`, 0);
11952
12111
  }
11953
12112
  if (!readCredentialsProfile(profile.name).api_key) {
11954
- console.log(source_default.dim(`No stored key for profile "${safeOneLine(profile.name)}".`));
12113
+ printLine(styles3().dim(`No stored key for profile "${safeOneLine(profile.name)}".`));
11955
12114
  return;
11956
12115
  }
11957
12116
  writeCredentialsProfile(profile.name, null);
11958
- console.log(source_default.green(`✓ Removed the stored key for profile "${safeOneLine(profile.name)}".`));
11959
- console.log(source_default.dim(" The key itself is still active — revoke it in Settings → API keys."));
12117
+ printLine(styles3().green(`✓ Removed the stored key for profile "${safeOneLine(profile.name)}".`));
12118
+ printLine(styles3().dim(" The key itself is still active — revoke it in Settings → Sim API keys."));
11960
12119
  });
11961
12120
  }
11962
12121
  async function readKeyType(client) {
@@ -12017,18 +12176,18 @@ function presentVerification(verification) {
12017
12176
  if (verification.status === "verified") {
12018
12177
  const { name, memberCount } = verification.workspace;
12019
12178
  const members = `${memberCount} ${memberCount === 1 ? "member" : "members"}`;
12020
- return `${source_default.green("✓")} ${safeOneLine(name)} · ${members}`;
12179
+ return `${styles3().green("✓")} ${safeOneLine(name)} · ${members}`;
12021
12180
  }
12022
12181
  const detail = safeOneLine(verification.detail);
12023
12182
  switch (verification.status) {
12024
12183
  case "rejected":
12025
- return `${source_default.red("✗")} ${detail}`;
12184
+ return `${styles3().red("✗")} ${detail}`;
12026
12185
  case "unauthenticated":
12027
- return source_default.yellow(`not logged in — ${detail}`);
12186
+ return styles3().yellow(`not logged in — ${detail}`);
12028
12187
  case "disabled":
12029
- return source_default.dim(detail);
12188
+ return styles3().dim(detail);
12030
12189
  default:
12031
- return source_default.yellow(`could not check — ${detail}`);
12190
+ return styles3().yellow(`could not check — ${detail}`);
12032
12191
  }
12033
12192
  }
12034
12193
  function whoamiCommand() {
@@ -12042,17 +12201,17 @@ function whoamiCommand() {
12042
12201
  keyType: null,
12043
12202
  detail: "not checked (--no-verify)"
12044
12203
  };
12045
- const annotate = (value, source) => source === "unset" ? source_default.dim("not set") : `${value} ${source_default.dim(`(${source})`)}`;
12204
+ const annotate = (value, source) => source === "unset" ? styles3().dim("not set") : `${value} ${styles3().dim(`(${source})`)}`;
12046
12205
  printRecord(profile.output, [
12047
12206
  ["Profile", profile.name],
12048
12207
  ["Endpoint", annotate(profile.endpoint, sources.endpoint)],
12049
12208
  [
12050
12209
  "API key",
12051
- authentication.authenticated ? annotate("configured", authentication.source) : source_default.yellow("not logged in")
12210
+ authentication.authenticated ? annotate("configured", authentication.source) : styles3().yellow("not logged in")
12052
12211
  ],
12053
12212
  [
12054
12213
  "Key type",
12055
- verification.keyType ?? source_default.dim(options.verify ? "unknown" : "not checked (--no-verify)")
12214
+ verification.keyType ?? styles3().dim(options.verify ? "unknown" : "not checked (--no-verify)")
12056
12215
  ],
12057
12216
  ["Workspace", annotate(profile.workspaceId ?? "", sources.workspaceId)],
12058
12217
  ["Output", annotate(profile.output, sources.output)],
@@ -12078,15 +12237,18 @@ function whoamiCommand() {
12078
12237
  });
12079
12238
  const exitCode = WHOAMI_EXIT_CODES[verification.status];
12080
12239
  if (exitCode !== 0)
12081
- process.exitCode = exitCode;
12240
+ setSoftExitCode(exitCode);
12082
12241
  });
12083
12242
  }
12084
12243
  var PROFILE_COLUMNS = [
12085
- { header: "", value: (row) => row.active ? source_default.green("*") : " " },
12244
+ { header: "", value: (row) => row.active ? styles3().green("*") : " " },
12086
12245
  { header: "profile", value: (row) => safeOneLine(row.name) },
12087
12246
  { header: "key", value: (row) => row.error ? text(null) : row.hasKey ? "yes" : "no" },
12088
12247
  { header: "auth", value: (row) => row.authProfile ? safeOneLine(row.authProfile) : text(null) },
12089
- { header: "error", value: (row) => row.error ? source_default.red(safeOneLine(row.error)) : text(null) }
12248
+ {
12249
+ header: "error",
12250
+ value: (row) => row.error ? styles3().red(safeOneLine(row.error)) : text(null)
12251
+ }
12090
12252
  ];
12091
12253
  function buildProfileRow(name, active) {
12092
12254
  try {
@@ -12133,7 +12295,7 @@ function profilesCommand() {
12133
12295
  const rows = listProfiles().map((name) => buildProfileRow(name, name === activeName));
12134
12296
  if (rows.length === 0) {
12135
12297
  if (output === "table")
12136
- console.log(source_default.dim("No profiles yet. Run: sim login"));
12298
+ printLine(styles3().dim("No profiles yet. Run: sim login"));
12137
12299
  else
12138
12300
  printList(output, rows, PROFILE_COLUMNS);
12139
12301
  return;
@@ -12213,21 +12375,21 @@ function configureCommand() {
12213
12375
  if (Object.keys(updates).length === 0) {
12214
12376
  const current = readConfigProfile(profile.name);
12215
12377
  if (Object.keys(current).length === 0) {
12216
- console.log(source_default.dim(`No settings stored for profile "${profile.name}".`));
12378
+ printLine(styles3().dim(`No settings stored for profile "${profile.name}".`));
12217
12379
  return;
12218
12380
  }
12219
12381
  for (const [key, value] of Object.entries(current)) {
12220
- console.log(`${source_default.dim(`${key}:`)} ${value}`);
12382
+ printLine(`${styles3().dim(`${key}:`)} ${value}`);
12221
12383
  }
12222
12384
  return;
12223
12385
  }
12224
12386
  const removalOnly = Object.values(updates).every((value) => value === null);
12225
12387
  if (removalOnly && Object.keys(readConfigProfile(profile.name)).length === 0) {
12226
- console.log(source_default.dim(`No settings stored for profile "${profile.name}".`));
12388
+ printLine(styles3().dim(`No settings stored for profile "${profile.name}".`));
12227
12389
  return;
12228
12390
  }
12229
12391
  writeConfigProfile(profile.name, updates);
12230
- console.log(source_default.green(`✓ Updated profile "${profile.name}" in ${configPath()}`));
12392
+ printLine(styles3().green(`✓ Updated profile "${profile.name}" in ${configPath()}`));
12231
12393
  });
12232
12394
  }
12233
12395
 
@@ -12451,7 +12613,7 @@ var CLI_CONTRACT = {
12451
12613
  },
12452
12614
  deleteTableView: { confirm: "This deletes the saved view and its filters." },
12453
12615
  deleteWorkflowGroup: {
12454
- confirm: "This deletes the group, every column it fed, and the values in them.",
12616
+ confirm: "This deletes the group AND its output columns with all of their row data; the workflow it pointed at is untouched.",
12455
12617
  fields: [
12456
12618
  { header: "id" },
12457
12619
  { header: "deleted", format: "bool" },
@@ -12571,7 +12733,7 @@ var CLI_CONTRACT = {
12571
12733
  },
12572
12734
  applyWorkflowOperations: {
12573
12735
  command: "workflows operations apply",
12574
- confirm: "This edits the draft graph, and a delete operation removes blocks and their edges.",
12736
+ confirm: "This edits the draft graph: the batch adds, edits, or deletes blocks and their edges as written.",
12575
12737
  flags: {
12576
12738
  operations: { json: true, describe: WORKFLOW_OPERATIONS_HELP },
12577
12739
  setBlockEnabled: { json: true, describe: WORKFLOW_SET_BLOCK_ENABLED_HELP }
@@ -13360,7 +13522,7 @@ var CLI_CONTRACT = {
13360
13522
  selectedOutputs: {
13361
13523
  name: "select-output",
13362
13524
  list: true,
13363
- describe: "Return streamed outputs as blockName.path or childWorkflowId.blockName.path; selecting a child workflow applies to every invocation, requires --follow"
13525
+ 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"
13364
13526
  },
13365
13527
  stream: { omit: true },
13366
13528
  includeThinking: { omit: true },
@@ -13384,7 +13546,7 @@ var CLI_CONTRACT = {
13384
13546
  selectedOutputs: {
13385
13547
  name: "select-output",
13386
13548
  list: true,
13387
- describe: "Include blockId or blockId.path values in JSON or YAML output; block names are not resolved on a finished run"
13549
+ 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"
13388
13550
  }
13389
13551
  },
13390
13552
  fields: [
@@ -13492,6 +13654,87 @@ function camel(flag) {
13492
13654
 
13493
13655
  // src/runtime/request.ts
13494
13656
  import { existsSync as existsSync2, readFileSync as readFileSync3, readSync } from "node:fs";
13657
+
13658
+ // src/transfer/local-file.ts
13659
+ import { constants } from "node:fs";
13660
+ import { access, stat } from "node:fs/promises";
13661
+ import { basename } from "node:path";
13662
+ function embeddedFileKey(path) {
13663
+ return path.startsWith("@") ? path.slice(1) : path;
13664
+ }
13665
+ async function embeddedFileContent(embedded, path) {
13666
+ const key = embeddedFileKey(path);
13667
+ embedded.identity.signal?.throwIfAborted();
13668
+ if (!embedded.readFile)
13669
+ throw new SimApiError("This invocation has no machine to read from", 0);
13670
+ const content = await embedded.readFile(key);
13671
+ embedded.identity.signal?.throwIfAborted();
13672
+ return typeof content === "string" ? content : new Uint8Array(content);
13673
+ }
13674
+ var CONTENT_TYPES = {
13675
+ css: "text/css",
13676
+ csv: "text/csv",
13677
+ doc: "application/msword",
13678
+ docx: "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
13679
+ gif: "image/gif",
13680
+ html: "text/html",
13681
+ htm: "text/html",
13682
+ jpeg: "image/jpeg",
13683
+ jpg: "image/jpeg",
13684
+ js: "text/javascript",
13685
+ json: "application/json",
13686
+ jsonl: "application/jsonl",
13687
+ md: "text/markdown",
13688
+ pdf: "application/pdf",
13689
+ ppt: "application/vnd.ms-powerpoint",
13690
+ pptx: "application/vnd.openxmlformats-officedocument.presentationml.presentation",
13691
+ png: "image/png",
13692
+ svg: "image/svg+xml",
13693
+ txt: "text/plain",
13694
+ webp: "image/webp",
13695
+ yaml: "application/yaml",
13696
+ yml: "application/yaml",
13697
+ xls: "application/vnd.ms-excel",
13698
+ xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
13699
+ zip: "application/zip"
13700
+ };
13701
+ function contentTypeFor(name) {
13702
+ const dot = name.lastIndexOf(".");
13703
+ const extension = dot === -1 ? "" : name.slice(dot + 1).toLowerCase();
13704
+ return CONTENT_TYPES[extension] ?? "application/octet-stream";
13705
+ }
13706
+ async function localFile(path, override) {
13707
+ const embedded = embedStore.getStore();
13708
+ if (embedded) {
13709
+ embedded.identity.signal?.throwIfAborted();
13710
+ if (!embedded.openFile)
13711
+ throw new SimApiError("This invocation has no machine to read from", 0);
13712
+ const { size } = await embedded.openFile(embeddedFileKey(path));
13713
+ embedded.identity.signal?.throwIfAborted();
13714
+ if (!Number.isSafeInteger(size) || size < 0)
13715
+ throw new SimApiError("Invalid file size", 0);
13716
+ if (size === 0)
13717
+ throw new SimApiError(`${path} is empty`, 0);
13718
+ return { name: override ?? basename(embeddedFileKey(path)), size };
13719
+ }
13720
+ let size;
13721
+ try {
13722
+ const stats = await stat(path);
13723
+ if (!stats.isFile())
13724
+ throw new SimApiError(`${path} is not a regular file`, 0);
13725
+ await access(path, constants.R_OK);
13726
+ size = stats.size;
13727
+ } catch (error) {
13728
+ if (error instanceof SimApiError)
13729
+ throw error;
13730
+ throw new SimApiError(`Cannot read ${path}: ${error.message}`, 0);
13731
+ }
13732
+ if (size === 0)
13733
+ throw new SimApiError(`${path} is empty`, 0);
13734
+ return { name: override ?? basename(path), size };
13735
+ }
13736
+
13737
+ // src/runtime/request.ts
13495
13738
  var PROFILE_INJECTED_FIELD = "workspaceId";
13496
13739
  function isProfileWorkspacePath(commandSpec, param) {
13497
13740
  return commandSpec.profileWorkspacePath === true && param === PROFILE_INJECTED_FIELD;
@@ -13573,11 +13816,21 @@ function readStdin() {
13573
13816
  function literalAtHint(error, path) {
13574
13817
  return error?.code === "ENOENT" ? `. To pass the literal value @${path}, write @@${path}` : "";
13575
13818
  }
13576
- function readArgumentSource(raw, flagName) {
13819
+ async function readArgumentSource(raw, flagName) {
13577
13820
  if (raw.startsWith("@@"))
13578
13821
  return { text: raw.slice(1), from: "" };
13579
13822
  if (!raw.startsWith("@"))
13580
13823
  return { text: raw, from: "" };
13824
+ const embedded = embedStore.getStore();
13825
+ if (embedded) {
13826
+ if (raw === "@-")
13827
+ throw new SimApiError(`--${flagName}: this invocation has no stdin; use @path or an inline value`, 0);
13828
+ const content = await embeddedFileContent(embedded, raw);
13829
+ return {
13830
+ text: typeof content === "string" ? content : new TextDecoder("utf-8", { fatal: true }).decode(content),
13831
+ from: " (read from your machine)"
13832
+ };
13833
+ }
13581
13834
  const path = raw.slice(1);
13582
13835
  if (path === "-") {
13583
13836
  if (process.stdin.isTTY) {
@@ -13599,15 +13852,18 @@ function isManifestNoise(line) {
13599
13852
  const trimmed = line.trim();
13600
13853
  return trimmed === "" || trimmed.startsWith("#");
13601
13854
  }
13602
- function readListValues(raw, flagName, manifest = false) {
13855
+ async function readListValues(raw, flagName, manifest = false) {
13603
13856
  const arguments_ = Array.isArray(raw) ? raw : [raw];
13604
- const values = arguments_.flatMap((argument) => {
13857
+ const values = [];
13858
+ for (const argument of arguments_) {
13605
13859
  if (typeof argument !== "string") {
13606
13860
  throw new SimApiError(`--${flagName} values must be strings`, 0);
13607
13861
  }
13608
- if (!argument.startsWith("@"))
13609
- return [argument];
13610
- const source = readArgumentSource(argument, flagName);
13862
+ if (!argument.startsWith("@")) {
13863
+ values.push(argument);
13864
+ continue;
13865
+ }
13866
+ const source = await readArgumentSource(argument, flagName);
13611
13867
  const lines = source.text.split(/\r?\n/);
13612
13868
  if (lines.at(-1) === "")
13613
13869
  lines.pop();
@@ -13615,14 +13871,14 @@ function readListValues(raw, flagName, manifest = false) {
13615
13871
  if (kept.length === 0) {
13616
13872
  throw new SimApiError(`--${flagName}${source.from} contains no values`, 0);
13617
13873
  }
13618
- return kept.map((line, index) => {
13874
+ values.push(...kept.map((line, index) => {
13619
13875
  const value = line.trim();
13620
13876
  if (!value) {
13621
13877
  throw new SimApiError(`--${flagName}${source.from} has an empty value on line ${index + 1}`, 0);
13622
13878
  }
13623
13879
  return value;
13624
- });
13625
- });
13880
+ }));
13881
+ }
13626
13882
  return values.map((value) => {
13627
13883
  const trimmed = value.trim();
13628
13884
  if (!trimmed)
@@ -13654,13 +13910,13 @@ var FRACTIONAL_DIGITS = /\.\d*[1-9]/;
13654
13910
  function pathHint(raw) {
13655
13911
  if (raw.startsWith("@") || /^\s*[[{"\-\d]|^\s*(true|false|null)/.test(raw))
13656
13912
  return "";
13657
- return existsSync2(raw) ? `. ${raw} is a file — pass it as @${raw}` : ". To read a file, pass @path (or @- for stdin)";
13913
+ return !embedStore.getStore() && existsSync2(raw) ? `. ${raw} is a file — pass it as @${raw}` : ". To read a file, pass @path (or @- for stdin)";
13658
13914
  }
13659
- function coerce(raw, field, flag, flagName) {
13915
+ async function coerce(raw, field, flag, flagName) {
13660
13916
  if (raw === undefined)
13661
13917
  return;
13662
13918
  if (flag.list) {
13663
- const values = readListValues(raw, flagName, flag.manifest === true).map((value) => flag.folderPath ? encodeFolderPath(value) : value);
13919
+ const values = (await readListValues(raw, flagName, flag.manifest === true)).map((value) => flag.folderPath ? encodeFolderPath(value) : value);
13664
13920
  return field.kind === "string" ? values.join(",") : values;
13665
13921
  }
13666
13922
  if (flag.rowCap)
@@ -13668,7 +13924,7 @@ function coerce(raw, field, flag, flagName) {
13668
13924
  if (takesJson(field, flag)) {
13669
13925
  if (typeof raw !== "string")
13670
13926
  return raw;
13671
- const source = readArgumentSource(raw, flagName);
13927
+ const source = await readArgumentSource(raw, flagName);
13672
13928
  try {
13673
13929
  return JSON.parse(source.text);
13674
13930
  } catch (error) {
@@ -13705,7 +13961,7 @@ function asQueryValue(value) {
13705
13961
  return JSON.stringify(value);
13706
13962
  return value;
13707
13963
  }
13708
- function buildRequest(operation, positional, flags, workspaceId) {
13964
+ async function buildRequest(operation, positional, flags, workspaceId) {
13709
13965
  const commandSpec = CLI_CONTRACT[operation] ?? {};
13710
13966
  const spec = V2_OPERATIONS[operation];
13711
13967
  let path = spec.path;
@@ -13743,7 +13999,7 @@ function buildRequest(operation, positional, flags, workspaceId) {
13743
13999
  if ((slot === "query" || NUMERIC_KINDS.has(descriptor.kind)) && typeof raw === "string" && raw.trim() === "" && !(field === "limit" && paginatedLimit)) {
13744
14000
  throw new SimApiError(`--${flagName} cannot be empty`, 0);
13745
14001
  }
13746
- const value = coerce(raw ?? undefined, descriptor, flag, flagName);
14002
+ const value = await coerce(raw ?? undefined, descriptor, flag, flagName);
13747
14003
  if (field === "limit" && !paginatedLimit && NUMERIC_KINDS.has(descriptor.kind) && typeof value === "number" && value < 1) {
13748
14004
  throw new SimApiError(`--${flagName} must be 1 or more`, 0);
13749
14005
  }
@@ -13773,7 +14029,7 @@ function buildRequest(operation, positional, flags, workspaceId) {
13773
14029
  const raw = flags[camel(variant.name)];
13774
14030
  if (typeof raw !== "string")
13775
14031
  throw new SimApiError(`--${variant.name} is required`, 0);
13776
- const parsed = coerce(raw, { kind: variant.kind }, { json: true }, variant.name);
14032
+ const parsed = await coerce(raw, { kind: variant.kind }, { json: true }, variant.name);
13777
14033
  if (variant.kind === "object" && (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) || variant.kind === "array" && !Array.isArray(parsed)) {
13778
14034
  throw new SimApiError(`--${variant.name} must be a JSON ${variant.kind}`, 0);
13779
14035
  }
@@ -13782,7 +14038,7 @@ function buildRequest(operation, positional, flags, workspaceId) {
13782
14038
  const raw = flags.body;
13783
14039
  if (typeof raw !== "string")
13784
14040
  throw new SimApiError("--body is required", 0);
13785
- const parsed = coerce(raw, { kind: "object" }, { json: true }, "body");
14041
+ const parsed = await coerce(raw, { kind: "object" }, { json: true }, "body");
13786
14042
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
13787
14043
  throw new SimApiError("--body must be a JSON object", 0);
13788
14044
  }
@@ -13907,7 +14163,7 @@ function warn(kind, from, to) {
13907
14163
  if (warned.has(key))
13908
14164
  return;
13909
14165
  warned.add(key);
13910
- process.stderr.write(`warning: ${kind} "${from}" has been renamed to "${to}". The old name still works.
14166
+ writeStderr(`warning: ${kind} "${from}" has been renamed to "${to}". The old name still works.
13911
14167
  `);
13912
14168
  }
13913
14169
  function warnRenamedCommand(from, to) {
@@ -14019,13 +14275,13 @@ function renderSpan(value, depth) {
14019
14275
  function printTraceSpans(format, traceSpans) {
14020
14276
  if (format === "json" || format === "yaml")
14021
14277
  return;
14022
- console.log("");
14023
- console.log(format === "table" ? source_default.dim("trace:") : "trace:");
14278
+ printLine("");
14279
+ printLine(format === "table" ? styles3().dim("trace:") : "trace:");
14024
14280
  if (traceSpans.length === 0) {
14025
- console.log(source_default.dim(" No trace spans."));
14281
+ printLine(styles3().dim(" No trace spans."));
14026
14282
  return;
14027
14283
  }
14028
- console.log(traceSpans.flatMap((span) => renderSpan(span, 0)).join(`
14284
+ printLine(traceSpans.flatMap((span) => renderSpan(span, 0)).join(`
14029
14285
  `));
14030
14286
  }
14031
14287
 
@@ -14190,7 +14446,7 @@ function writePageNote(spec, envelope) {
14190
14446
  const value = at(envelope, spec.pageNote.path);
14191
14447
  if (value === undefined || value === null)
14192
14448
  return;
14193
- process.stderr.write(source_default.dim(`${spec.pageNote.label}: ${String(value)}
14449
+ writeStderr(styles3().dim(`${spec.pageNote.label}: ${String(value)}
14194
14450
  `));
14195
14451
  }
14196
14452
  var TRUNCATION_FLAG = /^truncated$|^[A-Za-z0-9]+Truncated$/;
@@ -14223,14 +14479,14 @@ function clippedSubject(flag) {
14223
14479
  }
14224
14480
  function writeEnvelopeTruncation(envelope) {
14225
14481
  for (const flag of responseTruncationFlags(envelope)) {
14226
- process.stderr.write(source_default.dim(`${spellOut(flag)}: the server clipped ${clippedSubject(flag)}, so the answer is incomplete
14482
+ writeStderr(styles3().dim(`${spellOut(flag)}: the server clipped ${clippedSubject(flag)}, so the answer is incomplete
14227
14483
  `));
14228
14484
  }
14229
14485
  }
14230
14486
  function writeCursorTruncation(count, truncated) {
14231
14487
  if (!truncated)
14232
14488
  return;
14233
- process.stderr.write(source_default.dim(`showing the first ${count}; more results exist — re-run with --limit 0 for all
14489
+ writeStderr(styles3().dim(`showing the first ${count}; more results exist — re-run with --limit 0 for all
14234
14490
  `));
14235
14491
  }
14236
14492
  function renderResult(operation, format, raw, spec, options = {}, envelope) {
@@ -14239,7 +14495,7 @@ function renderResult(operation, format, raw, spec, options = {}, envelope) {
14239
14495
  printDocument(format, raw);
14240
14496
  return;
14241
14497
  }
14242
- const data = unwrapResource(raw);
14498
+ const data = format === "json" || format === "yaml" ? raw : unwrapResource(raw);
14243
14499
  if (spec.itemsPath) {
14244
14500
  const items = at(data, spec.itemsPath);
14245
14501
  if (!Array.isArray(items)) {
@@ -14358,6 +14614,22 @@ function countOf(value) {
14358
14614
  function lengthOf(value) {
14359
14615
  return Array.isArray(value) ? value.length : 0;
14360
14616
  }
14617
+ var RESULT_NOTES = {
14618
+ replaceWorkflowChatDeployment: (payload, body) => {
14619
+ const authType = payload.authType ?? body?.authType ?? "public";
14620
+ return authType === "public" ? "note: auth type is public — anyone with the link can chat; pass --auth-type password|email to restrict it." : null;
14621
+ }
14622
+ };
14623
+ function writeResultNote(operation, payload, body) {
14624
+ const note = RESULT_NOTES[operation];
14625
+ if (!note)
14626
+ return;
14627
+ const record = payload && typeof payload === "object" && !Array.isArray(payload) ? payload : {};
14628
+ const message = note(record, body);
14629
+ if (message)
14630
+ writeStderr(styles3().dim(`${message}
14631
+ `));
14632
+ }
14361
14633
  function bulkFailureMessage(operation, payload, body) {
14362
14634
  const check = BULK_OUTCOME_CHECKS[operation];
14363
14635
  if (!check)
@@ -14446,7 +14718,7 @@ async function executeOperation(operation, commandSpec, operationSpec, invocatio
14446
14718
  const needsWorkspace = (hasWorkspaceField || commandSpec.profileWorkspacePath === true) && !omitsWorkspace;
14447
14719
  const paging = cursorSlot(operationSpec);
14448
14720
  const pagedLimit = paging ? readPagedLimit(requestFlags.limit) : 0;
14449
- const request = buildRequest(operation, positional, requestFlags, needsWorkspace ? client.requireWorkspace() : profile.workspaceId);
14721
+ const request = await buildRequest(operation, positional, requestFlags, needsWorkspace ? client.requireWorkspace() : profile.workspaceId);
14450
14722
  if (paging) {
14451
14723
  const limit = pagedLimit === 0 ? Number.POSITIVE_INFINITY : pagedLimit;
14452
14724
  const pageSize = Math.min(Number.isFinite(limit) ? limit : DEFAULT_LIMIT, DEFAULT_LIMIT);
@@ -14483,6 +14755,7 @@ async function executeOperation(operation, commandSpec, operationSpec, invocatio
14483
14755
  });
14484
14756
  const payload = result?.data ?? result;
14485
14757
  renderResult(operation, profile.output, payload, commandSpec, { expandedTrace: requestFlags.trace === true }, result);
14758
+ writeResultNote(operation, payload, request.body);
14486
14759
  const failure = runFailureMessage(operation, payload) ?? bulkFailureMessage(operation, payload, request.body);
14487
14760
  if (failure)
14488
14761
  throw new SimApiError(failure, 0);
@@ -14890,8 +15163,8 @@ function serviceAccountProvider(providers, providerId) {
14890
15163
  }
14891
15164
  return provider;
14892
15165
  }
14893
- function credentialValues(provider, raw) {
14894
- const parsed = coerce(raw, { kind: "object" }, { json: true }, "credentials");
15166
+ async function credentialValues(provider, raw) {
15167
+ const parsed = await coerce(raw, { kind: "object" }, { json: true }, "credentials");
14895
15168
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
14896
15169
  throw new SimApiError("--credentials must be a JSON object", 0);
14897
15170
  }
@@ -14928,7 +15201,7 @@ async function createServiceAccount(command, providerId, options) {
14928
15201
  if (provider.requiresClientGeneratedCredentialId && !options.id) {
14929
15202
  throw new SimApiError(`--id is required for ${providerId}.`, 0);
14930
15203
  }
14931
- const credentialFields = credentialValues(provider, options.credentials);
15204
+ const credentialFields = await credentialValues(provider, options.credentials);
14932
15205
  const operation = V2_OPERATIONS.createServiceAccountCredential;
14933
15206
  const response = await client.request(operation.path, {
14934
15207
  method: operation.method,
@@ -15099,19 +15372,19 @@ Examples:
15099
15372
  const endStreamedLine = () => {
15100
15373
  if (streamed.length > 0 && !streamed.endsWith(`
15101
15374
  `)) {
15102
- process.stdout.write(`
15375
+ writeStdout(`
15103
15376
  `);
15104
15377
  streamed += `
15105
15378
  `;
15106
15379
  }
15107
15380
  };
15108
- const restorePipeHandling = streaming ? ignoreBrokenPipe(process.stdout) : undefined;
15381
+ const restorePipeHandling = streaming && !embedStore.getStore() ? ignoreBrokenPipe(process.stdout) : undefined;
15109
15382
  try {
15110
15383
  const result = await readChatStream(response, (content) => {
15111
15384
  if (!streaming)
15112
15385
  return;
15113
15386
  streamed += content;
15114
- process.stdout.write(content);
15387
+ writeStdout(content);
15115
15388
  });
15116
15389
  if (!streaming) {
15117
15390
  printProtocolResult(profile.output, result);
@@ -15119,11 +15392,11 @@ Examples:
15119
15392
  }
15120
15393
  const content = sanitize(result.content ?? "");
15121
15394
  if (content.startsWith(streamed) && content.length > streamed.length) {
15122
- process.stdout.write(content.slice(streamed.length));
15395
+ writeStdout(content.slice(streamed.length));
15123
15396
  streamed = content;
15124
15397
  }
15125
15398
  endStreamedLine();
15126
- process.stderr.write(`${source_default.dim(`conversation: ${result.conversationId}`)}
15399
+ writeStderr(`${styles3().dim(`conversation: ${result.conversationId}`)}
15127
15400
  `);
15128
15401
  } catch (error) {
15129
15402
  endStreamedLine();
@@ -15254,19 +15527,38 @@ async function saveStagedFile(body, target, force) {
15254
15527
  }
15255
15528
  }
15256
15529
  async function saveToFile(body, target, force) {
15530
+ const embedded = embedStore.getStore();
15531
+ if (embedded) {
15532
+ try {
15533
+ embedded.identity.signal?.throwIfAborted();
15534
+ if (!embedded.writeFile) {
15535
+ 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);
15536
+ }
15537
+ await embedded.writeFile(target, body, { overwrite: force });
15538
+ embedded.identity.signal?.throwIfAborted();
15539
+ } finally {
15540
+ await body.cancel().catch(() => {});
15541
+ }
15542
+ return;
15543
+ }
15257
15544
  return saveStagedFile(body, target, force);
15258
15545
  }
15259
- async function streamToStdout(body, output = process.stdout) {
15546
+ async function streamToStdout(body, output) {
15260
15547
  const reader = body.getReader();
15261
15548
  try {
15262
15549
  while (true) {
15263
15550
  const { done, value } = await reader.read();
15264
15551
  if (done)
15265
15552
  return;
15266
- if (!output.write(value))
15267
- await once2(output, "drain");
15553
+ if (output) {
15554
+ if (!output.write(value))
15555
+ await once2(output, "drain");
15556
+ } else if (!writeStdout(value)) {
15557
+ await once2(process.stdout, "drain");
15558
+ }
15268
15559
  }
15269
15560
  } finally {
15561
+ await reader.cancel().catch(() => {});
15270
15562
  reader.releaseLock();
15271
15563
  }
15272
15564
  }
@@ -15304,9 +15596,10 @@ function attachFileGet(files) {
15304
15596
  }
15305
15597
  if (options.outputFile === undefined || options.outputFile === "-") {
15306
15598
  const contentType = response.headers.get("content-type");
15307
- if (process.stdout.isTTY && !isTerminalSafeContentType(contentType)) {
15599
+ const embedded = embedStore.getStore();
15600
+ if ((embedded || process.stdout.isTTY) && !isTerminalSafeContentType(contentType)) {
15308
15601
  await response.body.cancel();
15309
- throw new SimApiError(`Refusing to write ${contentType ?? "unknown content"} to an interactive terminal. Use --output-file <path> or pipe stdout.`, 0);
15602
+ 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);
15310
15603
  }
15311
15604
  await streamToStdout(response.body);
15312
15605
  return;
@@ -15321,74 +15614,120 @@ function attachFileGet(files) {
15321
15614
  });
15322
15615
  }
15323
15616
 
15324
- // src/transfer/local-file.ts
15325
- import { constants } from "node:fs";
15326
- import { access, stat } from "node:fs/promises";
15327
- import { basename } from "node:path";
15328
- var CONTENT_TYPES = {
15329
- css: "text/css",
15330
- csv: "text/csv",
15331
- doc: "application/msword",
15332
- docx: "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
15333
- gif: "image/gif",
15334
- html: "text/html",
15335
- htm: "text/html",
15336
- jpeg: "image/jpeg",
15337
- jpg: "image/jpeg",
15338
- js: "text/javascript",
15339
- json: "application/json",
15340
- jsonl: "application/jsonl",
15341
- md: "text/markdown",
15342
- pdf: "application/pdf",
15343
- ppt: "application/vnd.ms-powerpoint",
15344
- pptx: "application/vnd.openxmlformats-officedocument.presentationml.presentation",
15345
- png: "image/png",
15346
- svg: "image/svg+xml",
15347
- txt: "text/plain",
15348
- webp: "image/webp",
15349
- yaml: "application/yaml",
15350
- yml: "application/yaml",
15351
- xls: "application/vnd.ms-excel",
15352
- xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
15353
- zip: "application/zip"
15354
- };
15355
- function contentTypeFor(name) {
15356
- const dot = name.lastIndexOf(".");
15357
- const extension = dot === -1 ? "" : name.slice(dot + 1).toLowerCase();
15358
- return CONTENT_TYPES[extension] ?? "application/octet-stream";
15359
- }
15360
- async function localFile(path, override) {
15361
- let size;
15362
- try {
15363
- const stats = await stat(path);
15364
- if (!stats.isFile())
15365
- throw new SimApiError(`${path} is not a regular file`, 0);
15366
- await access(path, constants.R_OK);
15367
- size = stats.size;
15368
- } catch (error) {
15369
- if (error instanceof SimApiError)
15370
- throw error;
15371
- throw new SimApiError(`Cannot read ${path}: ${error.message}`, 0);
15617
+ // src/transfer/upload-session.ts
15618
+ import { openAsBlob } from "node:fs";
15619
+
15620
+ // src/transfer/streaming-upload.ts
15621
+ class StreamingUpload {
15622
+ size;
15623
+ position = 0;
15624
+ pending = new Uint8Array(0);
15625
+ closed = false;
15626
+ reader;
15627
+ onAbort;
15628
+ stopped = new AbortController;
15629
+ signal;
15630
+ constructor(stream, size, signal) {
15631
+ this.size = size;
15632
+ this.signal = signal ? AbortSignal.any([signal, this.stopped.signal]) : this.stopped.signal;
15633
+ this.reader = stream.getReader();
15634
+ this.onAbort = () => {
15635
+ this.reader.cancel(this.signal.reason).catch(() => {});
15636
+ };
15637
+ this.signal.addEventListener("abort", this.onAbort, { once: true });
15638
+ if (this.signal.aborted)
15639
+ this.onAbort();
15640
+ }
15641
+ slice(start, end) {
15642
+ this.signal.throwIfAborted();
15643
+ if (this.closed || start !== this.position || end <= start || end > this.size) {
15644
+ throw new SimApiError("Upload parts must consume the snapshot in order", 0);
15645
+ }
15646
+ return new ReadableStream({
15647
+ pull: async (controller) => {
15648
+ try {
15649
+ this.signal.throwIfAborted();
15650
+ while (this.pending.byteLength === 0) {
15651
+ const next = await this.reader.read();
15652
+ this.signal.throwIfAborted();
15653
+ if (next.done)
15654
+ throw new SimApiError("Upload file ended before its declared size", 0);
15655
+ this.pending = next.value;
15656
+ }
15657
+ const length = Math.min(this.pending.byteLength, end - this.position);
15658
+ controller.enqueue(this.pending.subarray(0, length));
15659
+ this.pending = this.pending.subarray(length);
15660
+ this.position += length;
15661
+ if (this.position === end)
15662
+ controller.close();
15663
+ } catch (error) {
15664
+ controller.error(error);
15665
+ }
15666
+ },
15667
+ cancel: (reason) => this.reader.cancel(reason)
15668
+ }, { highWaterMark: 0 });
15669
+ }
15670
+ assertConsumed(end) {
15671
+ this.signal.throwIfAborted();
15672
+ if (this.position !== end) {
15673
+ throw new SimApiError("Upload was acknowledged before its complete body was consumed", 0);
15674
+ }
15675
+ }
15676
+ async verifyComplete() {
15677
+ this.assertConsumed(this.size);
15678
+ if (this.pending.byteLength > 0) {
15679
+ throw new SimApiError("Upload file exceeds its declared size", 0);
15680
+ }
15681
+ while (true) {
15682
+ const next = await this.reader.read();
15683
+ this.signal.throwIfAborted();
15684
+ if (next.done)
15685
+ return;
15686
+ if (next.value.byteLength > 0)
15687
+ throw new SimApiError("Upload file exceeds its declared size", 0);
15688
+ }
15689
+ }
15690
+ async close() {
15691
+ if (this.closed)
15692
+ return;
15693
+ this.closed = true;
15694
+ this.stopped.abort();
15695
+ this.signal.removeEventListener("abort", this.onAbort);
15696
+ try {
15697
+ await this.reader.cancel().catch(() => {});
15698
+ } finally {
15699
+ this.reader.releaseLock();
15700
+ }
15372
15701
  }
15373
- if (size === 0)
15374
- throw new SimApiError(`${path} is empty`, 0);
15375
- return { name: override ?? basename(path), size };
15376
15702
  }
15377
15703
 
15378
15704
  // src/transfer/upload-session.ts
15379
- import { openAsBlob } from "node:fs";
15380
15705
  var PART_URL_BATCH = 100;
15381
- async function uploadPut(transfer, blob) {
15382
- const response = await fetch(transfer.url, {
15706
+ async function uploadBytes(url, headers, file, start, end, label) {
15707
+ const body = file.slice(start, end);
15708
+ const options = {
15383
15709
  method: "PUT",
15384
- headers: transfer.headers,
15385
- body: blob
15386
- });
15710
+ headers,
15711
+ body,
15712
+ signal: file instanceof StreamingUpload ? file.signal : embedStore.getStore()?.identity.signal
15713
+ };
15714
+ if (file instanceof StreamingUpload) {
15715
+ const streamedHeaders = new Headers(headers);
15716
+ streamedHeaders.set("content-length", String(end - start));
15717
+ options.headers = streamedHeaders;
15718
+ options.duplex = "half";
15719
+ }
15720
+ const response = await fetch(url, options);
15387
15721
  if (!response.ok) {
15388
- throw new SimApiError(`Upload failed with status ${response.status}`, response.status);
15722
+ throw new SimApiError(`${label} failed with status ${response.status}`, response.status);
15389
15723
  }
15724
+ if (file instanceof StreamingUpload)
15725
+ file.assertConsumed(end);
15390
15726
  }
15391
- async function uploadParts(client, workspaceId, session, transfer, blob) {
15727
+ async function uploadParts(client, workspaceId, session, transfer, file) {
15728
+ if (file instanceof StreamingUpload && (!Number.isSafeInteger(transfer.partSize) || transfer.partSize <= 0)) {
15729
+ throw new SimApiError("Invalid upload part size", 0);
15730
+ }
15392
15731
  const expectedPartCount = Math.ceil(session.size / transfer.partSize);
15393
15732
  if (expectedPartCount !== transfer.partCount) {
15394
15733
  throw new Error(`Upload session expected ${transfer.partCount} parts, but file requires ${expectedPartCount}`);
@@ -15404,28 +15743,49 @@ async function uploadParts(client, workspaceId, session, transfer, blob) {
15404
15743
  headers: { "upload-token": session.uploadToken },
15405
15744
  body: { partNumbers }
15406
15745
  });
15407
- for (const part of signed.data.parts) {
15408
- const start = (part.partNumber - 1) * transfer.partSize;
15409
- const chunk = blob.slice(start, Math.min(start + transfer.partSize, session.size));
15410
- const response = await fetch(part.url, {
15411
- method: "PUT",
15412
- headers: part.headers,
15413
- body: chunk
15414
- });
15415
- if (!response.ok) {
15416
- throw new SimApiError(`Part ${part.partNumber} failed with status ${response.status}`, response.status);
15746
+ let parts = signed.data.parts;
15747
+ if (file instanceof StreamingUpload) {
15748
+ const numbers = new Set(parts.map((part) => part.partNumber));
15749
+ if (parts.length !== partNumbers.length || partNumbers.some((n) => !numbers.has(n))) {
15750
+ throw new SimApiError("Upload part URLs do not match the requested parts", 0);
15417
15751
  }
15752
+ parts = [...parts].sort((a, b) => a.partNumber - b.partNumber);
15753
+ }
15754
+ for (const part of parts) {
15755
+ const start = (part.partNumber - 1) * transfer.partSize;
15756
+ await uploadBytes(part.url, part.headers, file, start, Math.min(start + transfer.partSize, session.size), `Part ${part.partNumber}`);
15418
15757
  }
15419
15758
  }
15420
15759
  }
15421
15760
  async function finishUploadSession(client, workspaceId, session, path) {
15761
+ let snapshot;
15762
+ let streamed;
15422
15763
  try {
15423
- const blob = await openAsBlob(path);
15764
+ const embedded = embedStore.getStore();
15765
+ let file;
15766
+ if (embedded) {
15767
+ embedded.identity.signal?.throwIfAborted();
15768
+ if (!embedded.openFile)
15769
+ throw new SimApiError("This invocation has no machine to read from", 0);
15770
+ snapshot = await embedded.openFile(embeddedFileKey(path));
15771
+ if (snapshot.size !== session.size)
15772
+ throw new SimApiError("Upload snapshot size changed", 0);
15773
+ streamed = new StreamingUpload(await snapshot.stream(), snapshot.size, AbortSignal.any([
15774
+ ...embedded.identity.signal ? [embedded.identity.signal] : [],
15775
+ ...snapshot.signal ? [snapshot.signal] : []
15776
+ ]));
15777
+ file = streamed;
15778
+ } else {
15779
+ file = await openAsBlob(path);
15780
+ }
15424
15781
  if (session.transfer.method === "put") {
15425
- await uploadPut(session.transfer, blob);
15782
+ await uploadBytes(session.transfer.url, session.transfer.headers, file, 0, file instanceof Blob ? file.size : session.size, "Upload");
15426
15783
  } else {
15427
- await uploadParts(client, workspaceId, session, session.transfer, blob);
15784
+ await uploadParts(client, workspaceId, session, session.transfer, file);
15428
15785
  }
15786
+ await streamed?.verifyComplete();
15787
+ await streamed?.close();
15788
+ await snapshot?.dispose().catch(() => {});
15429
15789
  const completed = await client.request(`${session.basePath}/complete`, {
15430
15790
  method: "POST",
15431
15791
  query: { workspaceId },
@@ -15433,7 +15793,10 @@ async function finishUploadSession(client, workspaceId, session, path) {
15433
15793
  });
15434
15794
  return completed.data;
15435
15795
  } catch (error) {
15436
- await client.request(session.basePath, {
15796
+ await streamed?.close();
15797
+ const profile = embeddedProfile();
15798
+ const cleanupClient = profile ? new SimClient({ ...profile, signal: AbortSignal.timeout(5000) }) : client;
15799
+ await cleanupClient.request(session.basePath, {
15437
15800
  method: "DELETE",
15438
15801
  query: { workspaceId },
15439
15802
  headers: { "upload-token": session.uploadToken }
@@ -15441,6 +15804,9 @@ async function finishUploadSession(client, workspaceId, session, path) {
15441
15804
  return;
15442
15805
  });
15443
15806
  throw error;
15807
+ } finally {
15808
+ await streamed?.close();
15809
+ await snapshot?.dispose().catch(() => {});
15444
15810
  }
15445
15811
  }
15446
15812
 
@@ -15526,9 +15892,11 @@ function attachKnowledgeDocumentUpload(documents) {
15526
15892
  printProtocolResult(profile.output, {
15527
15893
  id: completed.document.id,
15528
15894
  knowledgeBaseId: completed.document.knowledgeBaseId,
15529
- name: completed.document.filename,
15530
- size: completed.document.fileSize,
15531
- status: completed.document.processingStatus
15895
+ filename: completed.document.filename,
15896
+ fileSize: completed.document.fileSize,
15897
+ mimeType: completed.document.mimeType,
15898
+ processingStatus: completed.document.processingStatus,
15899
+ chunkCount: completed.document.chunkCount
15532
15900
  });
15533
15901
  });
15534
15902
  }
@@ -15590,11 +15958,11 @@ function createTableWriter() {
15590
15958
  if (!widths) {
15591
15959
  widths = COLUMNS.map((column, index) => Math.min(MAX_CELL_WIDTH2, Math.max(column.floor, visibleWidth(column.header), ...lines.map((line) => visibleWidth(line[index])))));
15592
15960
  const header = widths;
15593
- console.log(source_default.dim(COLUMNS.map((column, index) => pad2(column.header.toUpperCase(), header[index])).join(" ").trimEnd()));
15961
+ printLine(styles3().dim(COLUMNS.map((column, index) => pad2(column.header.toUpperCase(), header[index])).join(" ").trimEnd()));
15594
15962
  }
15595
15963
  const locked = widths;
15596
15964
  for (const line of lines) {
15597
- console.log(line.map((cell, index) => pad2(cell, locked[index])).join(" ").trimEnd());
15965
+ printLine(line.map((cell, index) => pad2(cell, locked[index])).join(" ").trimEnd());
15598
15966
  }
15599
15967
  };
15600
15968
  }
@@ -15602,13 +15970,13 @@ function createWriter(format) {
15602
15970
  if (format === "json") {
15603
15971
  return (rows) => {
15604
15972
  for (const row of rows)
15605
- console.log(JSON.stringify(row));
15973
+ printLine(JSON.stringify(row));
15606
15974
  };
15607
15975
  }
15608
15976
  if (format === "yaml") {
15609
15977
  return (rows) => {
15610
15978
  for (const row of rows) {
15611
- console.log(`---
15979
+ printLine(`---
15612
15980
  ${dump(row, { lineWidth: 0, noRefs: true }).trimEnd()}`);
15613
15981
  }
15614
15982
  };
@@ -15625,24 +15993,24 @@ function followStatus() {
15625
15993
  let reported = false;
15626
15994
  return {
15627
15995
  note: (message) => {
15628
- if (!process.stderr.isTTY)
15996
+ if (!hasProgressTerminal())
15629
15997
  return;
15630
15998
  reported = true;
15631
- process.stderr.write(`\r${source_default.dim(message)}${ERASE_LINE}`);
15999
+ writeStderr(`\r${styles3().dim(message)}${ERASE_LINE}`);
15632
16000
  },
15633
16001
  warn: (message) => {
15634
16002
  if (reported) {
15635
16003
  reported = false;
15636
- process.stderr.write(`\r${ERASE_LINE}`);
16004
+ writeStderr(`\r${ERASE_LINE}`);
15637
16005
  }
15638
- process.stderr.write(`warning: ${message}
16006
+ writeStderr(`warning: ${message}
15639
16007
  `);
15640
16008
  },
15641
16009
  clear: () => {
15642
16010
  if (!reported)
15643
16011
  return;
15644
16012
  reported = false;
15645
- process.stderr.write(`\r${ERASE_LINE}`);
16013
+ writeStderr(`\r${ERASE_LINE}`);
15646
16014
  }
15647
16015
  };
15648
16016
  }
@@ -15935,13 +16303,13 @@ async function watchImport(client, workspaceId, job) {
15935
16303
  const next = await client.request(`/api/v2/tables/imports/${encodeURIComponent(current.id)}`, { query: { workspaceId } });
15936
16304
  current = next.data;
15937
16305
  const line = progressLine(current);
15938
- if (process.stderr.isTTY && line !== reported) {
16306
+ if (hasProgressTerminal() && line !== reported) {
15939
16307
  reported = line;
15940
- process.stderr.write(`\r${source_default.dim(line)}\x1B[K`);
16308
+ writeStderr(`\r${styles3().dim(line)}\x1B[K`);
15941
16309
  }
15942
16310
  }
15943
- if (process.stderr.isTTY && reported !== null)
15944
- process.stderr.write("\r\x1B[K");
16311
+ if (hasProgressTerminal() && reported !== null)
16312
+ writeStderr("\r\x1B[K");
15945
16313
  return current;
15946
16314
  }
15947
16315
  function validateTargetOptions(options) {
@@ -15999,8 +16367,8 @@ function attachTableImport(tables) {
15999
16367
  workspaceId,
16000
16368
  source,
16001
16369
  target,
16002
- ...options.mapping ? { mapping: jsonFlag(options.mapping, "mapping", "object") } : {},
16003
- ...options.createColumns ? { createColumns: jsonFlag(options.createColumns, "create-columns", "array") } : {},
16370
+ ...options.mapping ? { mapping: await jsonFlag(options.mapping, "mapping", "object") } : {},
16371
+ ...options.createColumns ? { createColumns: await jsonFlag(options.createColumns, "create-columns", "array") } : {},
16004
16372
  ...options.timezone ? { timezone: options.timezone } : {}
16005
16373
  }
16006
16374
  });
@@ -16045,14 +16413,11 @@ var AGENT_STREAM_PROTOCOL_HEADER = "x-sim-stream-protocol";
16045
16413
  var AGENT_STREAM_PROTOCOL_V1 = "agent-events-v1";
16046
16414
  var DONE_SENTINEL = "[DONE]";
16047
16415
  function resolveWorkflowRunSelection(flags) {
16048
- const manual = flags.manual === true;
16049
16416
  const trigger = typeof flags.trigger === "string" ? flags.trigger : undefined;
16050
16417
  const useMockPayload = flags.mockPayload === true;
16418
+ const manual = flags.manual === true || trigger !== undefined || useMockPayload;
16051
16419
  const fromBlock = typeof flags.fromBlock === "string" ? flags.fromBlock : undefined;
16052
16420
  const sourceRun = typeof flags.sourceRun === "string" ? flags.sourceRun : undefined;
16053
- if ((trigger || useMockPayload) && !manual) {
16054
- throw new SimApiError("--trigger and --mock-payload require --manual", 0);
16055
- }
16056
16421
  if (fromBlock && (trigger || useMockPayload)) {
16057
16422
  throw new SimApiError("--from-block cannot be combined with --trigger or --mock-payload", 0);
16058
16423
  }
@@ -16151,11 +16516,11 @@ class Commentary {
16151
16516
  function toolNotice(frame) {
16152
16517
  const name = safeOneLine(stringField(frame, "name") ?? "tool");
16153
16518
  if (frame.phase === "start")
16154
- return source_default.dim(`→ ${name}`);
16519
+ return styles3().dim(`→ ${name}`);
16155
16520
  const status = stringField(frame, "status");
16156
16521
  if (status && status !== "success")
16157
- return source_default.yellow(`✗ ${name} (${safeOneLine(status)})`);
16158
- return source_default.dim(`✓ ${name}`);
16522
+ return styles3().yellow(`✗ ${name} (${safeOneLine(status)})`);
16523
+ return styles3().dim(`✓ ${name}`);
16159
16524
  }
16160
16525
  async function renderRunStream(body, options) {
16161
16526
  const commentary = new Commentary(options.stderr);
@@ -16177,11 +16542,11 @@ async function renderRunStream(body, options) {
16177
16542
  }
16178
16543
  switch (frame.event) {
16179
16544
  case "chunk_reset":
16180
- commentary.line(source_default.dim("… retracted; that turn resolved to tool calls"));
16545
+ commentary.line(styles3().dim("… retracted; that turn resolved to tool calls"));
16181
16546
  break;
16182
16547
  case "thinking":
16183
16548
  if (options.includeThinking && typeof frame.data === "string") {
16184
- commentary.inline(source_default.dim(sanitize(frame.data)));
16549
+ commentary.inline(styles3().dim(sanitize(frame.data)));
16185
16550
  }
16186
16551
  break;
16187
16552
  case "tool":
@@ -16189,7 +16554,7 @@ async function renderRunStream(body, options) {
16189
16554
  commentary.line(toolNotice(frame));
16190
16555
  break;
16191
16556
  case "stream_error":
16192
- commentary.line(source_default.yellow(`warning: ${safeOneLine(stringField(frame, "error") ?? "stream read failed")}`));
16557
+ commentary.line(styles3().yellow(`warning: ${safeOneLine(stringField(frame, "error") ?? "stream read failed")}`));
16193
16558
  break;
16194
16559
  case "error":
16195
16560
  commentary.endLine();
@@ -16218,7 +16583,7 @@ async function followRun(workflowId, command) {
16218
16583
  const negotiates = includeThinking || includeToolCalls;
16219
16584
  const { client, profile } = clientFrom(command);
16220
16585
  const operation = V2_OPERATIONS.executeWorkflow;
16221
- const request = buildRequest("executeWorkflow", [workflowId], flags, profile.workspaceId);
16586
+ const request = await buildRequest("executeWorkflow", [workflowId], flags, profile.workspaceId);
16222
16587
  const response = await client.requestRaw(request.path, {
16223
16588
  method: "POST",
16224
16589
  query: request.query,
@@ -16244,7 +16609,7 @@ async function followRun(workflowId, command) {
16244
16609
  const final = await renderRunStream(response.body, {
16245
16610
  includeThinking,
16246
16611
  includeToolCalls,
16247
- stderr: process.stderr
16612
+ stderr: { write: writeStderr }
16248
16613
  });
16249
16614
  renderResult("executeWorkflow", profile.output, final, CLI_CONTRACT.executeWorkflow ?? {});
16250
16615
  if (final.success === false) {
@@ -16259,8 +16624,8 @@ function followOrDelegate(previous) {
16259
16624
  command.setOptionValue("run", selection);
16260
16625
  const flags = command.optsWithGlobals();
16261
16626
  if (flags.follow !== true) {
16262
- if (Array.isArray(flags.selectOutput) && flags.selectOutput.length > 0) {
16263
- 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);
16627
+ if (Array.isArray(flags.selectOutput) && flags.selectOutput.length > 0 && flags.async === true) {
16628
+ 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);
16264
16629
  }
16265
16630
  if (flags.includeThinking === true || flags.includeToolCalls === true) {
16266
16631
  throw new SimApiError("--include-thinking and --include-tool-calls describe a stream; add --follow", 0);
@@ -16282,7 +16647,119 @@ function attachWorkflowRunFollow(workflows) {
16282
16647
  }
16283
16648
  const held = run._actionHandler;
16284
16649
  const previous = typeof held === "function" ? held : null;
16285
- 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));
16650
+ 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));
16651
+ }
16652
+
16653
+ // src/commands/protocol/workflow-run-get.ts
16654
+ var BLOCK_ID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
16655
+ var SELECT_OUTPUT_FLAG = "select-output";
16656
+ function normalizeBlockName(name) {
16657
+ return name.toLowerCase().replace(/\s+/g, "").replace(/\./g, "");
16658
+ }
16659
+ function isRecord2(value) {
16660
+ return typeof value === "object" && value !== null && !Array.isArray(value);
16661
+ }
16662
+ async function loadWorkflowBlocks(client, workflowId) {
16663
+ const operation = V2_OPERATIONS.getWorkflowState;
16664
+ const raw = await client.request(resolvePath(operation.path, { workflowId }), {
16665
+ method: operation.method
16666
+ });
16667
+ const state = isRecord2(raw) && isRecord2(raw.data) ? raw.data : raw;
16668
+ const blocks = isRecord2(state) && isRecord2(state.blocks) ? Object.entries(state.blocks) : [];
16669
+ return blocks.map(([key, block]) => ({
16670
+ id: isRecord2(block) && typeof block.id === "string" ? block.id : key,
16671
+ name: isRecord2(block) && typeof block.name === "string" ? block.name : ""
16672
+ }));
16673
+ }
16674
+ function splitSelector(selector) {
16675
+ const dot = selector.indexOf(".");
16676
+ return dot === -1 ? { head: selector, path: "" } : { head: selector.slice(0, dot), path: selector.slice(dot) };
16677
+ }
16678
+ function isIdHeaded(selector) {
16679
+ return BLOCK_ID.test(splitSelector(selector).head);
16680
+ }
16681
+ function resolveSelection(typed, blocks, workflowId) {
16682
+ const resolved = [];
16683
+ const typedBy = new Map;
16684
+ const unresolved = [];
16685
+ for (const selector of typed) {
16686
+ const { head, path } = splitSelector(selector);
16687
+ let blockId = head;
16688
+ if (!BLOCK_ID.test(head)) {
16689
+ const wanted = normalizeBlockName(head);
16690
+ const matches = blocks.filter((block) => block.id === head || normalizeBlockName(block.name) === wanted);
16691
+ if (matches.length === 0) {
16692
+ unresolved.push(selector);
16693
+ continue;
16694
+ }
16695
+ if (matches.length > 1) {
16696
+ throw new SimApiError(`--${SELECT_OUTPUT_FLAG} ${selector} names ${matches.length} blocks (${matches.map((block) => block.id).join(", ")}); pass the block id instead`, 0);
16697
+ }
16698
+ blockId = matches[0].id;
16699
+ }
16700
+ const rewritten = `${blockId}${path}`;
16701
+ resolved.push(rewritten);
16702
+ if (!typedBy.has(rewritten))
16703
+ typedBy.set(rewritten, selector);
16704
+ }
16705
+ if (unresolved.length > 0) {
16706
+ const names = blocks.map((block) => block.name).filter((name) => name !== "");
16707
+ 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);
16708
+ }
16709
+ return { resolved, typedBy };
16710
+ }
16711
+ function keyByTyped(payload, typedBy) {
16712
+ if (!isRecord2(payload) || !isRecord2(payload.blockOutputs))
16713
+ return payload;
16714
+ const blockOutputs = {};
16715
+ for (const [key, value] of Object.entries(payload.blockOutputs)) {
16716
+ blockOutputs[typedBy.get(key) ?? key] = value;
16717
+ }
16718
+ return { ...payload, blockOutputs };
16719
+ }
16720
+ async function readRunByName(runId, typed, command) {
16721
+ const flags = command.optsWithGlobals();
16722
+ const { client, profile } = clientFrom(command);
16723
+ const operation = V2_OPERATIONS.getWorkflowRun;
16724
+ const spec = CLI_CONTRACT.getWorkflowRun ?? {};
16725
+ await buildRequest("getWorkflowRun", [runId], flags, profile.workspaceId);
16726
+ const workflowId = String(flags.workflow);
16727
+ const selection = resolveSelection(typed, await loadWorkflowBlocks(client, workflowId), workflowId);
16728
+ const request = await buildRequest("getWorkflowRun", [runId], { ...flags, selectOutput: selection.resolved }, profile.workspaceId);
16729
+ let result;
16730
+ try {
16731
+ result = await client.request(request.path, {
16732
+ method: operation.method,
16733
+ headers: request.headers,
16734
+ query: request.query,
16735
+ body: request.body
16736
+ });
16737
+ } catch (error) {
16738
+ throw retypeApiError(error, "getWorkflowRun", spec, operation);
16739
+ }
16740
+ renderResult("getWorkflowRun", profile.output, keyByTyped(result?.data ?? result, selection.typedBy), spec, {}, result);
16741
+ }
16742
+ function attachWorkflowRunGet(runs) {
16743
+ const get = runs.commands.find((command) => command.name() === "get");
16744
+ const held = get?._actionHandler;
16745
+ if (!get || typeof held !== "function") {
16746
+ throw new Error("workflows runs get must be registered before block names can be attached to it");
16747
+ }
16748
+ const previous = held;
16749
+ get.action(async (runId, _options, command) => {
16750
+ const raw = command.optsWithGlobals().selectOutput;
16751
+ if (raw === undefined) {
16752
+ await previous(command.processedArgs);
16753
+ return;
16754
+ }
16755
+ const typed = await readListValues(raw, SELECT_OUTPUT_FLAG);
16756
+ command.setOptionValue("selectOutput", typed);
16757
+ if (typed.every(isIdHeaded)) {
16758
+ await previous(command.processedArgs);
16759
+ return;
16760
+ }
16761
+ await readRunByName(runId, typed, command);
16762
+ });
16286
16763
  }
16287
16764
 
16288
16765
  // src/commands/protocol/workflow-run-wait.ts
@@ -16299,18 +16776,21 @@ var MAX_POLL_DELAY_MS = 15000;
16299
16776
  var POLL_BACKOFF_FACTOR = 2;
16300
16777
  var DEFAULT_WAIT_TIMEOUT_SECONDS = 3600;
16301
16778
  var WAIT_TIMEOUT_FLAG = "--wait-timeout <seconds>";
16302
- function isRecord2(value) {
16779
+ function isRecord3(value) {
16303
16780
  return typeof value === "object" && value !== null && !Array.isArray(value);
16304
16781
  }
16305
16782
  function optionalString(value) {
16306
16783
  return typeof value === "string" && value !== "" ? value : null;
16307
16784
  }
16785
+ function runData(raw) {
16786
+ return isRecord3(raw) && isRecord3(raw.data) ? raw.data : raw;
16787
+ }
16308
16788
  function readRun(raw) {
16309
- const run = isRecord2(raw) && isRecord2(raw.data) ? raw.data : raw;
16310
- if (!isRecord2(run) || typeof run.status !== "string") {
16789
+ const run = isRecord3(raw) && isRecord3(raw.data) ? raw.data : raw;
16790
+ if (!isRecord3(run) || typeof run.status !== "string") {
16311
16791
  throw new SimApiError("Run status response carried no status.", 0);
16312
16792
  }
16313
- const paused = isRecord2(run.paused) ? run.paused : null;
16793
+ const paused = isRecord3(run.paused) ? run.paused : null;
16314
16794
  return {
16315
16795
  status: run.status,
16316
16796
  pauseKind: paused ? optionalString(paused.pauseKind) : null,
@@ -16329,16 +16809,16 @@ function waitProgress() {
16329
16809
  let reported = false;
16330
16810
  return {
16331
16811
  advance: (status, elapsedMs) => {
16332
- if (!process.stderr.isTTY)
16812
+ if (!hasProgressTerminal())
16333
16813
  return;
16334
16814
  reported = true;
16335
- process.stderr.write(`\r${source_default.dim(`${status} — waiting ${Math.round(elapsedMs / 1000)}s…`)}\x1B[K`);
16815
+ writeStderr(`\r${styles3().dim(`${status} — waiting ${Math.round(elapsedMs / 1000)}s…`)}\x1B[K`);
16336
16816
  },
16337
16817
  finish: () => {
16338
16818
  if (!reported)
16339
16819
  return;
16340
16820
  reported = false;
16341
- process.stderr.write("\r\x1B[K");
16821
+ writeStderr("\r\x1B[K");
16342
16822
  }
16343
16823
  };
16344
16824
  }
@@ -16379,19 +16859,19 @@ function attachWorkflowRunWait(runs) {
16379
16859
  const outcome = classify(snapshot);
16380
16860
  if (outcome) {
16381
16861
  progress.finish();
16382
- renderResult("getWorkflowRun", profile.output, raw, runSpec());
16862
+ renderResult("getWorkflowRun", profile.output, runData(raw), runSpec());
16383
16863
  const message = explain(outcome, runId, options.workflow, snapshot);
16384
16864
  if (message)
16385
- console.error(source_default.red(message));
16386
- process.exitCode = WAIT_EXIT_CODES[outcome];
16865
+ printError(styles3().red(message));
16866
+ setSoftExitCode(WAIT_EXIT_CODES[outcome]);
16387
16867
  return;
16388
16868
  }
16389
16869
  const remainingMs = deadline - Date.now();
16390
16870
  if (remainingMs <= 0) {
16391
16871
  progress.finish();
16392
- renderResult("getWorkflowRun", profile.output, raw, runSpec());
16393
- 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.`));
16394
- process.exitCode = WAIT_EXIT_CODES.timeout;
16872
+ renderResult("getWorkflowRun", profile.output, runData(raw), runSpec());
16873
+ 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.`));
16874
+ setSoftExitCode(WAIT_EXIT_CODES.timeout);
16395
16875
  return;
16396
16876
  }
16397
16877
  progress.advance(snapshot.status, Date.now() - startedAt);
@@ -16447,7 +16927,9 @@ function attachProtocolCommands(program) {
16447
16927
  createFolder: "createWorkflowFolder"
16448
16928
  });
16449
16929
  attachWorkflowRunFollow(workflows);
16450
- attachWorkflowRunWait(group(workflows, "runs"));
16930
+ const runs = group(workflows, "runs");
16931
+ attachWorkflowRunGet(runs);
16932
+ attachWorkflowRunWait(runs);
16451
16933
  attachLogsFollow(group(program, "logs"));
16452
16934
  attachChat(program);
16453
16935
  }
@@ -16550,12 +17032,12 @@ var SECRET_RESULT = {
16550
17032
  { header: "description" }
16551
17033
  ]
16552
17034
  };
16553
- function readValueArgument(raw) {
17035
+ async function readValueArgument(raw) {
16554
17036
  if (raw.startsWith("@@"))
16555
17037
  return raw.slice(1);
16556
17038
  if (!raw.startsWith("@"))
16557
17039
  return raw;
16558
- return readArgumentSource(raw, "value").text;
17040
+ return (await readArgumentSource(raw, "value")).text;
16559
17041
  }
16560
17042
  function validateSecretValue(value) {
16561
17043
  if (value.length === 0)
@@ -16575,7 +17057,7 @@ function validateWorkspaceOnlyFlag(flag, value, scope) {
16575
17057
  }
16576
17058
  async function readSecretValue(options) {
16577
17059
  if (options.value !== undefined)
16578
- return validateSecretValue(readValueArgument(options.value));
17060
+ return validateSecretValue(await readValueArgument(options.value));
16579
17061
  if (options.description !== undefined || options.unredacted !== undefined)
16580
17062
  return;
16581
17063
  try {
@@ -16583,8 +17065,8 @@ async function readSecretValue(options) {
16583
17065
  } catch (error) {
16584
17066
  if (!(error instanceof SecretInputCancelledError))
16585
17067
  throw error;
16586
- console.error(source_default.red(`Error: ${error.message}`));
16587
- return process.exit(CANCELLED_EXIT_CODE);
17068
+ printError(styles3().red(`Error: ${error.message}`));
17069
+ return exitCli(CANCELLED_EXIT_CODE);
16588
17070
  }
16589
17071
  }
16590
17072
  async function setSecret(name, options, command, redactionSpellings) {
@@ -16786,7 +17268,7 @@ async function fetchDistTags(env, request) {
16786
17268
  if (!url)
16787
17269
  return null;
16788
17270
  const text = await request(url, {
16789
- headers: { accept: "application/json", "user-agent": `${PACKAGE_NAME}-cli/${CLI_VERSION}` },
17271
+ headers: { accept: "application/json", "user-agent": `${PACKAGE_NAME}-cli/${cliVersion()}` },
16790
17272
  maxResponseBytes: MAX_RESPONSE_BYTES,
16791
17273
  timeoutMs: REGISTRY_TIMEOUT_MS
16792
17274
  });
@@ -16913,7 +17395,7 @@ async function announceUpdateIfAvailable(options = {}) {
16913
17395
  return;
16914
17396
  if (isUnadvisableInstall(modulePath, env, cwd))
16915
17397
  return;
16916
- const currentVersion = options.currentVersion ?? CLI_VERSION;
17398
+ const currentVersion = options.currentVersion ?? cliVersion();
16917
17399
  const current = parseStableVersion(currentVersion);
16918
17400
  if (!current)
16919
17401
  return;
@@ -16997,52 +17479,55 @@ function addVersionOption(program) {
16997
17479
  }
16998
17480
  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.");
16999
17481
  });
17000
- program.version(CLI_VERSION, "-V, --version [none]", "output the version number (takes no value)");
17482
+ program.version(cliVersion(), "-V, --version [none]", "output the version number (takes no value)");
17001
17483
  }
17002
17484
  function buildProgram(options = {}) {
17003
- const program = new Command;
17485
+ const program = options.program ?? new Command;
17004
17486
  program.name("sim").description(PROGRAM_DESCRIPTION);
17005
17487
  if (options.version !== false)
17006
17488
  addVersionOption(program);
17007
17489
  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]));
17008
- program.addCommand(loginCommand());
17009
- program.addCommand(logoutCommand());
17010
- program.addCommand(whoamiCommand());
17011
- program.addCommand(profilesCommand());
17012
- program.addCommand(configureCommand());
17490
+ for (const command of [
17491
+ loginCommand,
17492
+ logoutCommand,
17493
+ whoamiCommand,
17494
+ profilesCommand,
17495
+ configureCommand
17496
+ ])
17497
+ program.addCommand(command());
17013
17498
  for (const command of buildGeneratedCommands()) {
17014
17499
  program.addCommand(command);
17015
17500
  }
17016
17501
  attachCredentialCommands(program);
17017
17502
  attachProtocolCommands(program);
17018
17503
  attachSecretCommands(program);
17019
- program.addHelpText("after", HELP_EPILOGUE);
17504
+ program.addHelpText("after", options.helpText ?? HELP_EPILOGUE);
17020
17505
  program.hook("preAction", () => announceUpdateIfAvailable());
17021
17506
  refuseHelpAfterUnknownCommand(program);
17022
17507
  assertNoReservedProgramFlags(program);
17023
17508
  return program;
17024
17509
  }
17025
17510
 
17026
- // src/index.ts
17027
- async function main() {
17511
+ // src/terminal.ts
17512
+ async function runTerminalCli(program = buildProgram()) {
17028
17513
  try {
17029
- await buildProgram().parseAsync(process.argv);
17514
+ await program.parseAsync(process.argv);
17030
17515
  } catch (error) {
17031
17516
  if (error instanceof ProfileConfigError) {
17032
- console.error(source_default.red(`Error: ${sanitize(error.message)}`));
17517
+ console.error(styles3().red(`Error: ${sanitize(error.message)}`));
17033
17518
  process.exit(1);
17034
17519
  }
17035
17520
  if (isRequestTimeout(error)) {
17036
- console.error(source_default.red(`Error: the request timed out. ${RAISE_TIMEOUT_HINT}`));
17521
+ console.error(styles3().red(`Error: the request timed out. ${RAISE_TIMEOUT_HINT}`));
17037
17522
  process.exit(1);
17038
17523
  }
17039
17524
  if (error instanceof SimApiError) {
17040
- console.error(source_default.red(`Error: ${sanitize(error.message)}`));
17525
+ console.error(styles3().red(`Error: ${sanitize(error.message)}`));
17041
17526
  if (error.code)
17042
- console.error(source_default.dim(` code: ${sanitize(error.code)}`));
17527
+ console.error(styles3().dim(` code: ${sanitize(error.code)}`));
17043
17528
  if (error.details !== undefined) {
17044
17529
  for (const line of formatApiErrorDetails(error.details)) {
17045
- console.error(source_default.dim(sanitize(line)));
17530
+ console.error(styles3().dim(sanitize(line)));
17046
17531
  }
17047
17532
  }
17048
17533
  process.exit(1);
@@ -17050,4 +17535,6 @@ async function main() {
17050
17535
  throw error;
17051
17536
  }
17052
17537
  }
17053
- main();
17538
+
17539
+ // src/index.ts
17540
+ runTerminalCli();