sim 2.1.8-preview.103.1 → 2.1.8-preview.96.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 (3) hide show
  1. package/README.md +7 -33
  2. package/dist/index.js +137 -252
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -33,27 +33,16 @@ Sign in to the default profile:
33
33
  sim login
34
34
  ```
35
35
 
36
- With no `--method`, the CLI prefers OAuth when the server offers it and a local
37
- browser callback is possible. It selects API-key pairing for remote terminals
38
- or servers without OAuth. Use `sim login --method oauth` to require OAuth;
39
- if the server does not offer it, login fails without creating an API key.
40
-
41
- OAuth login opens Sim in your browser, asks you to approve the requested access,
36
+ The CLI opens Sim in your browser, asks you to approve the requested access,
42
37
  and receives the one-time authorization code on a loopback callback. It stores
43
38
  a short-lived OAuth login that renews automatically and can be revoked under
44
- **Settings → General → Authorized apps**. Choose a default workspace afterward with
39
+ **Settings → Authorized apps**. Choose a default workspace afterward with
45
40
  `sim configure --set-workspace <id>`.
46
41
 
47
- Use `--no-browser` with either method to print the approval URL without opening
48
- it. OAuth still needs the browser to reach the CLI's loopback callback. Over SSH
49
- or in a container without port forwarding, use
50
- `sim login --method api-key --no-browser` to approve from another device and
51
- create a permanent personal API key. `--method api-key` creates a new key;
52
- set `SIM_API_KEY` to supply an existing one.
53
-
54
- Pairing requires a server that supports `platform` API keys. Upgrade older
55
- deployments that only issue `copilot` keys before login; they are not compatible
56
- with the platform CLI. OAuth discovery does not check pairing compatibility.
42
+ Use `sim login --no-browser` to print the OAuth URL without opening it. The
43
+ browser must still be able to reach the CLI's loopback callback. Over SSH or in
44
+ a container without port forwarding, use `sim login --browserless`; that
45
+ pairing-code fallback creates a permanent personal API key instead.
57
46
 
58
47
  Check the active profile and verify that its endpoint, credential, and workspace
59
48
  work together:
@@ -220,26 +209,11 @@ will consume the result, and `text` for tab-separated shell output:
220
209
 
221
210
  ```bash
222
211
  sim workflows list --output json
223
- sim logs list --output json | jq -r '.data[].runId'
212
+ sim logs list --output json | jq -r '.[].runId'
224
213
  SIM_OUTPUT=yaml sim tables get <tableId>
225
214
  sim configure --set-output json
226
215
  ```
227
216
 
228
- Paginated lists return `{ "data": [...], "nextCursor": "..." }` in JSON and YAML.
229
- `nextCursor` is `null` when no pages remain. Resource lists and directory `ls`
230
- fetch every page by default; use `--limit N` to cap them. Table rows (including
231
- queries), logs, audit/billing events, workflow runs/versions, and knowledge
232
- documents/chunks keep a default limit of 100. Use `--limit 0` to fetch every page
233
- of those datasets, or pass the returned `nextCursor` to `--cursor` to continue
234
- with another bounded result. Keep the same resource, filters, and sort order
235
- when resuming; stop when `nextCursor` is `null`. Results accumulate in memory
236
- before printing, so large datasets need an explicit limit or filter.
237
-
238
- ```bash
239
- sim tables rows list <tableId> --limit 100 --output json
240
- sim tables rows list <tableId> --limit 100 --cursor "$nextCursor" --output json
241
- ```
242
-
243
217
  JSON-valued options accept inline JSON, a file prefixed with `@`, or stdin with
244
218
  `@-`:
245
219
 
package/dist/index.js CHANGED
@@ -4460,22 +4460,6 @@ function toApiError(url, status, contentType, raw) {
4460
4460
  function truncate(value, max) {
4461
4461
  return value.length <= max ? value : `${value.slice(0, max)}…`;
4462
4462
  }
4463
- function transportErrorMessage(error) {
4464
- const messages = [];
4465
- const seen = new Set;
4466
- let current = error;
4467
- while (current && typeof current === "object" && messages.length < 4 && !seen.has(current)) {
4468
- seen.add(current);
4469
- const candidate = current;
4470
- const message = typeof candidate.message === "string" ? truncate(candidate.message.replace(/\s+/g, " ").trim(), 300) : "";
4471
- const code = typeof candidate.code === "string" ? candidate.code : "";
4472
- const detail = `${message}${code && !message.includes(code) ? ` (${code})` : ""}`;
4473
- if (detail && messages.at(-1) !== detail)
4474
- messages.push(detail);
4475
- current = candidate.cause;
4476
- }
4477
- return messages.join(": ") || "Unknown network error";
4478
- }
4479
4463
  function namesKeyScopeRefusal(error) {
4480
4464
  if (typeof error.code === "string" && KEY_SCOPE_REFUSALS.has(error.code))
4481
4465
  return true;
@@ -4699,7 +4683,7 @@ class SimClient {
4699
4683
  if (timeout?.aborted) {
4700
4684
  throw new SimApiError(`${url} did not answer within ${timeoutMs / 1000}s. ${RAISE_TIMEOUT_HINT}`, 0);
4701
4685
  }
4702
- throw new SimApiError(`Could not reach ${this.profile.endpoint}: ${transportErrorMessage(cause)}`, 0);
4686
+ throw new SimApiError(`Could not reach ${this.profile.endpoint}: ${cause.message}`, 0);
4703
4687
  }
4704
4688
  if (trace)
4705
4689
  traceRequest(method, url, response.status, startedAt);
@@ -4763,21 +4747,15 @@ function pageProgress() {
4763
4747
  }
4764
4748
  };
4765
4749
  }
4766
- function assertCursorAdvances(cursor, seenCursors) {
4767
- if (cursor === null)
4768
- return;
4769
- if (seenCursors.has(cursor)) {
4770
- throw new SimApiError("The API returned a repeated pagination cursor; cannot continue.", 0);
4771
- }
4772
- seenCursors.add(cursor);
4773
- }
4774
4750
  async function requestAllPages(client, path, options) {
4751
+ return (await requestPages(client, path, options)).items;
4752
+ }
4753
+ async function requestPages(client, path, options) {
4775
4754
  const { query, pageSize, limit: requestedLimit, ...requestOptions } = options;
4776
4755
  const limit = requestedLimit ?? Number.POSITIVE_INFINITY;
4777
4756
  if (limit <= 0)
4778
- return [];
4757
+ return { items: [], truncated: false };
4779
4758
  const items = [];
4780
- const seenCursors = new Set;
4781
4759
  const progress = pageProgress();
4782
4760
  let cursor = null;
4783
4761
  try {
@@ -4790,7 +4768,6 @@ async function requestAllPages(client, path, options) {
4790
4768
  cursor
4791
4769
  }
4792
4770
  });
4793
- assertCursorAdvances(page.nextCursor, seenCursors);
4794
4771
  items.push(...page.data);
4795
4772
  cursor = page.nextCursor;
4796
4773
  if (cursor && items.length < limit)
@@ -4799,7 +4776,7 @@ async function requestAllPages(client, path, options) {
4799
4776
  } finally {
4800
4777
  progress.finish();
4801
4778
  }
4802
- return items.slice(0, limit);
4779
+ return { items: items.slice(0, limit), truncated: cursor !== null || items.length > limit };
4803
4780
  }
4804
4781
  function resolvePath(template, params = {}) {
4805
4782
  return template.replace(/\[([^\]]+)\]/g, (_match, key) => {
@@ -8163,12 +8140,12 @@ function createAuthRequest() {
8163
8140
  pairing: pairingCode()
8164
8141
  };
8165
8142
  }
8166
- function buildApprovalUrl(endpoint, auth, workspaceId) {
8143
+ function buildApprovalUrl(endpoint, auth, scope, workspaceId) {
8167
8144
  return buildUrl(endpoint, APPROVAL_PATH, {
8168
8145
  request: auth.request,
8169
8146
  challenge: auth.challenge,
8170
8147
  pairing: auth.pairing,
8171
- scope: "platform",
8148
+ scope,
8172
8149
  workspace: workspaceId
8173
8150
  });
8174
8151
  }
@@ -8474,7 +8451,7 @@ function listenForCallback(server, expectedState, completionUrl, signal, timeout
8474
8451
  const onAbort = () => finish({ ok: false, error: new SimApiError("Login cancelled.", 0) });
8475
8452
  const timer = setTimeout(() => finish({
8476
8453
  ok: false,
8477
- error: new SimApiError(`Timed out after ${Math.round(timeoutMs / 60000)} minutes waiting for the browser. Run sim login again, or use --method api-key if this terminal's browser cannot reach it.`, 0)
8454
+ error: new SimApiError(`Timed out after ${Math.round(timeoutMs / 60000)} minutes waiting for the browser. Run sim login again, or use --browserless if this terminal's browser cannot reach it.`, 0)
8478
8455
  }), timeoutMs);
8479
8456
  signal?.addEventListener("abort", onAbort, { once: true });
8480
8457
  server.on("request", (request, response) => {
@@ -8723,7 +8700,6 @@ var V2_OPERATIONS = {
8723
8700
  pathParamDocs: { workflowId: "Unique workflow identifier." },
8724
8701
  responseMode: "json",
8725
8702
  summary: "Apply Workflow Operations",
8726
- workspaceKeyUnsupported: true,
8727
8703
  query: {
8728
8704
  dryRun: {
8729
8705
  kind: "boolean",
@@ -8812,7 +8788,7 @@ var V2_OPERATIONS = {
8812
8788
  },
8813
8789
  folderPaths: {
8814
8790
  kind: "string",
8815
- describe: "Comma-separated folder paths whose contents are included recursively. Up to 100 paths; resolved files share the 100-file download limit. Unknown paths are rejected."
8791
+ describe: "Folder paths to include with all their descendants, comma-separated. At most 100 entries, and the files they resolve to count against the same 100-file download ceiling. A path that matches no folder is rejected rather than ignored."
8816
8792
  }
8817
8793
  }
8818
8794
  },
@@ -9471,7 +9447,7 @@ var V2_OPERATIONS = {
9471
9447
  kind: "enum",
9472
9448
  values: ["streamable-http"],
9473
9449
  default: "streamable-http",
9474
- describe: "Transport protocol. Defaults to `streamable-http` on creation."
9450
+ describe: "Transport used to communicate with the server. Applied server-side as `streamable-http` when omitted on create."
9475
9451
  },
9476
9452
  url: {
9477
9453
  kind: "string",
@@ -9490,17 +9466,17 @@ var V2_OPERATIONS = {
9490
9466
  timeout: {
9491
9467
  kind: "integer",
9492
9468
  default: 30000,
9493
- describe: "Per-request timeout in milliseconds. Defaults to 30000 on creation."
9469
+ describe: "Per-request timeout in milliseconds. Applied server-side as 30000 when omitted on create."
9494
9470
  },
9495
9471
  retries: {
9496
9472
  kind: "integer",
9497
9473
  default: 3,
9498
- describe: "Number of retries per request. Defaults to 3 on creation."
9474
+ describe: "Number of retries per request. Applied server-side as 3 when omitted on create."
9499
9475
  },
9500
9476
  enabled: {
9501
9477
  kind: "boolean",
9502
9478
  default: true,
9503
- describe: "Whether workflows can use the server's tools. Defaults to true on creation."
9479
+ describe: "Whether the server tools are available to workflows. Applied server-side as true when omitted on create."
9504
9480
  },
9505
9481
  oauthClientId: {
9506
9482
  kind: "string",
@@ -10398,7 +10374,7 @@ var V2_OPERATIONS = {
10398
10374
  input: {
10399
10375
  kind: "object",
10400
10376
  default: {},
10401
- describe: "Tool arguments keyed by published parameter IDs. For `user-only` parameters, a whole-value `{{VAR_NAME}}` reference resolves a workspace environment variable. Other values pass through unchanged."
10377
+ describe: "Arguments for the tool, keyed by the parameter ids the tool catalog publishes for it. A parameter whose visibility is `user-only` also accepts an environment-variable reference written as the whole value, `{{VAR_NAME}}`, resolved server-side against the workspace environment; any other value is sent verbatim."
10402
10378
  },
10403
10379
  credentialId: {
10404
10380
  kind: "string",
@@ -10433,7 +10409,7 @@ var V2_OPERATIONS = {
10433
10409
  },
10434
10410
  executionTimeoutSeconds: {
10435
10411
  kind: "integer",
10436
- describe: "Maximum duration of an asynchronous run, in seconds, capped by the plan's execution timeout. Requires `async: true`; otherwise returns `400`."
10412
+ describe: "Requested server-side timeout for an asynchronous run, in seconds. An upper bound, not the effective timeout: the run uses the smaller of this value and the plan's execution timeout, so requesting more than the plan allows silently yields the plan timeout. Rejected with `400` unless `async` is true."
10437
10413
  },
10438
10414
  stream: {
10439
10415
  kind: "boolean",
@@ -10442,7 +10418,7 @@ var V2_OPERATIONS = {
10442
10418
  },
10443
10419
  selectedOutputs: {
10444
10420
  kind: "array",
10445
- describe: "Output references for streaming: `<blockName>.<outputPath>` or `<childWorkflowId>.<blockName>.<outputPath>`, using normalized block names. Child references apply to every invocation. Requires `stream: true` and rejects synchronous or async requests. Use `selectedOutputs` with Get Workflow Run to narrow an existing run."
10421
+ 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."
10446
10422
  },
10447
10423
  includeThinking: {
10448
10424
  kind: "boolean",
@@ -10466,7 +10442,7 @@ var V2_OPERATIONS = {
10466
10442
  headers: {
10467
10443
  "x-run-id": {
10468
10444
  kind: "string",
10469
- describe: "Run ID for API-key or OAuth callers; ignored for anonymous requests. Reuse it after an uncertain response: a claimed ID returns `409` with `RUN_ID_CONFLICT`, without replaying results. Check Get Workflow Run, but `404` can persist while the ID remains claimed and does not establish whether execution started. Do not automatically restart with a fresh or omitted ID; either can start another run."
10445
+ describe: 'Caller-supplied run identifier, available only to API-key callers. A one-shot uniqueness claim, NOT an idempotency key: reusing a value fails with `409` and `error.details.code: "RUN_ID_CONFLICT"` rather than replaying the original result. To retry safely, send a fresh value per attempt, or omit the header and let the server allocate one.'
10470
10446
  },
10471
10447
  "x-sim-via": {
10472
10448
  kind: "string",
@@ -10690,7 +10666,7 @@ var V2_OPERATIONS = {
10690
10666
  },
10691
10667
  folderPaths: {
10692
10668
  kind: "string",
10693
- describe: "Comma-separated workflow folder paths, including descendants. Up to 100 paths. Unknown folder paths contribute no matches."
10669
+ describe: "Comma-separated workflow folder paths to include. At most 100 entries. A path covers its whole subtree. A path that names no folder narrows the result to nothing, so the response is an empty page rather than an error."
10694
10670
  },
10695
10671
  triggers: {
10696
10672
  kind: "string",
@@ -10712,7 +10688,7 @@ var V2_OPERATIONS = {
10712
10688
  segmentCount: {
10713
10689
  kind: "integer",
10714
10690
  default: 72,
10715
- describe: "Number of time buckets, up to 500. Exactly this many are returned, each at least one minute wide. Short windows extend past the requested end and include empty trailing buckets."
10691
+ 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."
10716
10692
  }
10717
10693
  }
10718
10694
  },
@@ -11168,7 +11144,7 @@ var V2_OPERATIONS = {
11168
11144
  source: {
11169
11145
  kind: "enum",
11170
11146
  values: ["builtin", "custom"],
11171
- describe: "Restrict to built-in blocks or this workspace's deployed custom blocks."
11147
+ describe: "Restrict to shipped blocks or to this workspaces deployed custom blocks."
11172
11148
  },
11173
11149
  sortBy: {
11174
11150
  kind: "enum",
@@ -11367,7 +11343,7 @@ var V2_OPERATIONS = {
11367
11343
  },
11368
11344
  parentPath: {
11369
11345
  kind: "string",
11370
- describe: "Restrict results to direct children of this parent path. Unknown folder paths contribute no matches."
11346
+ describe: "Restrict results to direct children of this parent path. A path that names no folder narrows the result to nothing, so the response is an empty page rather than an error."
11371
11347
  },
11372
11348
  search: {
11373
11349
  kind: "string",
@@ -11429,7 +11405,7 @@ var V2_OPERATIONS = {
11429
11405
  },
11430
11406
  folderPath: {
11431
11407
  kind: "string",
11432
- describe: "Restrict files to this folder, including subfolders when `recursive` is true. Unknown folder paths contribute no matches."
11408
+ describe: "Restrict results to files inside this folder — its direct children, or its whole subtree when `recursive` is true. A path that names no folder narrows the result to nothing, so the response is an empty page rather than an error."
11433
11409
  },
11434
11410
  recursive: {
11435
11411
  kind: "enum",
@@ -11447,7 +11423,7 @@ var V2_OPERATIONS = {
11447
11423
  "n",
11448
11424
  "disabled"
11449
11425
  ],
11450
- describe: "Include subfolders in the folder filter. Defaults to true when searching and false otherwise. Ignored without a folder filter."
11426
+ describe: "Whether the folder filter includes files in subfolders. Defaults to true when a search is set, false otherwise, so listing a folder shows that folder while searching one looks through everything in it. Ignored when no folder filter is set, which already spans the workspace. The listed spellings are the whole accepted vocabulary and are case-sensitive; any other value is rejected."
11451
11427
  },
11452
11428
  scope: {
11453
11429
  kind: "enum",
@@ -11498,11 +11474,11 @@ var V2_OPERATIONS = {
11498
11474
  kind: "enum",
11499
11475
  values: ["active", "archived"],
11500
11476
  default: "active",
11501
- describe: "Lifecycle scope: active or archived knowledge bases. Use Restore Knowledge Base to recover archived entries. Folder paths resolve only active folders, so filtering by an archived folder returns no matches."
11477
+ describe: "Which lifecycle set to list: `active` (default) for live knowledge bases, `archived` for knowledge bases a `DELETE` archived and `POST /knowledge/{knowledgeBaseId}/restore` can bring back. `folderPath` resolves against active folders only, so pairing it with `scope=archived` returns an empty page when the containing folder was archived too."
11502
11478
  },
11503
11479
  folderPath: {
11504
11480
  kind: "string",
11505
- describe: "Restrict results to knowledge bases in this folder. Unknown folder paths contribute no matches."
11481
+ describe: "Restrict results to knowledge bases in this folder. A path that names no folder narrows the result to nothing, so the response is an empty page rather than an error."
11506
11482
  },
11507
11483
  search: {
11508
11484
  kind: "string",
@@ -11722,7 +11698,7 @@ var V2_OPERATIONS = {
11722
11698
  },
11723
11699
  parentPath: {
11724
11700
  kind: "string",
11725
- describe: "Restrict results to direct children of this parent path. Unknown folder paths contribute no matches."
11701
+ describe: "Restrict results to direct children of this parent path. A path that names no folder narrows the result to nothing, so the response is an empty page rather than an error."
11726
11702
  },
11727
11703
  search: {
11728
11704
  kind: "string",
@@ -11873,7 +11849,7 @@ var V2_OPERATIONS = {
11873
11849
  },
11874
11850
  folderPaths: {
11875
11851
  kind: "string",
11876
- describe: "Comma-separated workflow folder paths, including descendants. Up to 100 paths. Unknown folder paths contribute no matches."
11852
+ describe: "Comma-separated workflow folder paths to include. At most 100 entries. A path covers its whole subtree, so `/prod` also selects runs in `/prod/nested`. A path that names no folder narrows the result to nothing, so the response is an empty page rather than an error."
11877
11853
  }
11878
11854
  }
11879
11855
  },
@@ -11932,7 +11908,7 @@ var V2_OPERATIONS = {
11932
11908
  },
11933
11909
  refresh: {
11934
11910
  kind: "boolean",
11935
- describe: "Refresh tools using your credentials. Otherwise results may reuse another workspace member's recent discovery and omit newly added tools."
11911
+ describe: "Bypass the short-lived per-workspace tool cache and reconnect under your own credentials. A cached result reflects whichever workspace member last ran discovery, so this is the only way to pick up a tool added since then; it costs a live round trip."
11936
11912
  }
11937
11913
  }
11938
11914
  },
@@ -12110,7 +12086,7 @@ var V2_OPERATIONS = {
12110
12086
  },
12111
12087
  parentPath: {
12112
12088
  kind: "string",
12113
- describe: "Restrict results to direct children of this parent path. Unknown folder paths contribute no matches."
12089
+ describe: "Restrict results to direct children of this parent path. A path that names no folder narrows the result to nothing, so the response is an empty page rather than an error."
12114
12090
  },
12115
12091
  search: {
12116
12092
  kind: "string",
@@ -12174,7 +12150,7 @@ var V2_OPERATIONS = {
12174
12150
  },
12175
12151
  folderPath: {
12176
12152
  kind: "string",
12177
- describe: "Restrict results to tables in this folder. Unknown folder paths contribute no matches."
12153
+ describe: "Restrict results to tables in this folder. A path that names no folder narrows the result to nothing, so the response is an empty page rather than an error."
12178
12154
  },
12179
12155
  search: {
12180
12156
  kind: "string",
@@ -12276,7 +12252,7 @@ var V2_OPERATIONS = {
12276
12252
  },
12277
12253
  parentPath: {
12278
12254
  kind: "string",
12279
- describe: "Restrict results to direct children of this parent path. Unknown folder paths contribute no matches."
12255
+ describe: "Restrict results to direct children of this parent path. A path that names no folder narrows the result to nothing, so the response is an empty page rather than an error."
12280
12256
  },
12281
12257
  search: {
12282
12258
  kind: "string",
@@ -12411,7 +12387,7 @@ var V2_OPERATIONS = {
12411
12387
  },
12412
12388
  folderPath: {
12413
12389
  kind: "string",
12414
- describe: "Restrict results to workflows in this folder path. Unknown folder paths contribute no matches."
12390
+ describe: "Restrict results to workflows in this folder path. A path that names no folder narrows the result to nothing, so the response is an empty page rather than an error."
12415
12391
  },
12416
12392
  deployedOnly: {
12417
12393
  kind: "boolean",
@@ -12718,7 +12694,6 @@ var V2_OPERATIONS = {
12718
12694
  pathParamDocs: { workflowId: "Unique workflow identifier." },
12719
12695
  responseMode: "json",
12720
12696
  summary: "Create or Replace Workflow Chat Deployment",
12721
- workspaceKeyUnsupported: true,
12722
12697
  body: {
12723
12698
  identifier: {
12724
12699
  kind: "string",
@@ -12771,7 +12746,6 @@ var V2_OPERATIONS = {
12771
12746
  pathParamDocs: { workflowId: "Unique workflow identifier." },
12772
12747
  responseMode: "json",
12773
12748
  summary: "Replace Workflow State",
12774
- workspaceKeyUnsupported: true,
12775
12749
  query: {
12776
12750
  dryRun: {
12777
12751
  kind: "boolean",
@@ -13208,11 +13182,6 @@ var V2_OPERATIONS = {
13208
13182
  },
13209
13183
  apiToken: { kind: "string", describe: "Write-only provider API token." },
13210
13184
  domain: { kind: "string", describe: "Provider account domain." },
13211
- atlassianProduct: {
13212
- kind: "enum",
13213
- values: ["jira", "confluence"],
13214
- describe: "Atlassian product to verify; defaults to Jira on create and preserves the saved product on reconnect."
13215
- },
13216
13185
  signingSecret: { kind: "string", describe: "Write-only webhook signing secret." },
13217
13186
  botToken: { kind: "string", describe: "Write-only bot token." },
13218
13187
  clientId: { kind: "string", describe: "OAuth client identifier." },
@@ -13463,7 +13432,7 @@ var V2_OPERATIONS = {
13463
13432
  kind: "enum",
13464
13433
  values: ["streamable-http"],
13465
13434
  default: "streamable-http",
13466
- describe: "Transport protocol. Defaults to `streamable-http` on creation."
13435
+ describe: "Transport used to communicate with the server. Applied server-side as `streamable-http` when omitted on create."
13467
13436
  },
13468
13437
  url: {
13469
13438
  kind: "string",
@@ -13481,17 +13450,17 @@ var V2_OPERATIONS = {
13481
13450
  timeout: {
13482
13451
  kind: "integer",
13483
13452
  default: 30000,
13484
- describe: "Per-request timeout in milliseconds. Defaults to 30000 on creation."
13453
+ describe: "Per-request timeout in milliseconds. Applied server-side as 30000 when omitted on create."
13485
13454
  },
13486
13455
  retries: {
13487
13456
  kind: "integer",
13488
13457
  default: 3,
13489
- describe: "Number of retries per request. Defaults to 3 on creation."
13458
+ describe: "Number of retries per request. Applied server-side as 3 when omitted on create."
13490
13459
  },
13491
13460
  enabled: {
13492
13461
  kind: "boolean",
13493
13462
  default: true,
13494
- describe: "Whether workflows can use the server's tools. Defaults to true on creation."
13463
+ describe: "Whether the server tools are available to workflows. Applied server-side as true when omitted on create."
13495
13464
  },
13496
13465
  oauthClientId: {
13497
13466
  kind: "string",
@@ -13975,12 +13944,12 @@ function addProfileCommand() {
13975
13944
  console.log(source_default.dim(` Try: sim --profile ${safeOneLine(profileName)} whoami`));
13976
13945
  });
13977
13946
  }
13978
- async function chooseLoginFlow(profile, options) {
13947
+ async function chooseLoginFlow(profile, options, scope) {
13979
13948
  requireSecureEndpoint(profile.endpoint);
13980
- if (options.method === "api-key")
13949
+ if (options.browserless || scope === "copilot")
13981
13950
  return "handoff";
13982
- if (options.method === undefined && isLikelyRemoteSession() && options.callbackPort === undefined) {
13983
- console.log(source_default.dim(`This looks like a remote session; using the pairing code to create a personal API key. To use OAuth, forward a port and pass --method oauth --callback-port <port>.
13951
+ if (isLikelyRemoteSession() && options.callbackPort === undefined) {
13952
+ console.log(source_default.dim(`This looks like a remote session, so the browser on this machine cannot finish an OAuth login; using the pairing code instead. Forward a port and pass --callback-port <port> to sign in through the browser anyway.
13984
13953
  `));
13985
13954
  return "handoff";
13986
13955
  }
@@ -13989,10 +13958,7 @@ async function chooseLoginFlow(profile, options) {
13989
13958
  throw new SimApiError(`Could not reach ${profile.endpoint}. Check the endpoint.`, 0);
13990
13959
  }
13991
13960
  if (status === "unavailable") {
13992
- if (options.method === "oauth") {
13993
- throw new SimApiError(`${profile.endpoint} does not offer OAuth sign-in. Enable OAuth on the server or explicitly choose sim login --method api-key.`, 0);
13994
- }
13995
- console.log(source_default.dim(`${profile.endpoint} does not offer OAuth sign-in; using the pairing code to create a personal API key.
13961
+ console.log(source_default.dim(`${profile.endpoint} does not offer OAuth sign-in; using the pairing code instead.
13996
13962
  `));
13997
13963
  return "handoff";
13998
13964
  }
@@ -14058,24 +14024,28 @@ Waiting for you to approve in the browser…`));
14058
14024
  try {
14059
14025
  await revokeToken(profile.endpoint, tokens.refreshToken);
14060
14026
  } catch (revocationError) {
14061
- console.log(source_default.yellow(`Could not revoke the uncommitted login (${safeOneLine(getErrorMessage(revocationError))}). Revoke Sim CLI in Settings → General → Authorized apps.`));
14027
+ console.log(source_default.yellow(`Could not revoke the uncommitted login (${safeOneLine(getErrorMessage(revocationError))}). Revoke Sim CLI in Settings → Authorized apps.`));
14062
14028
  }
14063
14029
  throw error;
14064
14030
  }
14065
14031
  console.log(source_default.green(`
14066
14032
  ✓ Logged in. Login stored in ${credentialsPath()}`));
14067
- console.log(source_default.dim(grantsWriteAccess(tokens.scope) ? " Renews itself; revoke it any time in Settings → General → Authorized apps, or with: sim logout" : " Read-only login — commands that change anything will be refused."));
14033
+ console.log(source_default.dim(grantsWriteAccess(tokens.scope) ? " Renews itself; revoke it any time in Settings → Authorized apps, or with: sim logout" : " Read-only login — commands that change anything will be refused."));
14068
14034
  if (!profile.workspaceId) {
14069
14035
  console.log(source_default.dim(" No default workspace. Set one with: sim configure --set-workspace <id>"));
14070
14036
  }
14071
14037
  }
14072
14038
  function loginCommand() {
14073
- return new Command("login").description("Sign in through the browser and store the login for the profile").addOption(new Option("--method <method>", "Credential to obtain: oauth requires OAuth support; api-key creates a permanent key through pairing (auto-selects when omitted)").choices(["oauth", "api-key"])).option("--no-browser", "Print the approval URL without opening it (either login method)").option("--read-only", "Ask only for permission to read, never to change anything").option("--callback-port <port>", "Pin the local port the browser returns to").option("-y, --yes", "Overwrite an existing API-key profile without prompting").action(async (options, command) => {
14039
+ return new Command("login").description("Sign in through the browser and store the login for the profile").option("--scope <scope>", 'Key space for the pairing-code handoff; only "copilot" changes anything, and it forces that flow', "platform").option("--no-browser", "Print the URL instead of opening a browser").option("--browserless", "Use the pairing-code handoff for a terminal whose browser cannot reach it (SSH, containers)").option("--read-only", "Ask only for permission to read, never to change anything").option("--callback-port <port>", "Pin the local port the browser returns to").option("-y, --yes", "Overwrite an existing API-key profile without prompting").action(async (options, command) => {
14074
14040
  const profile = profileFrom(command, { allowUnknownProfile: true });
14075
14041
  const authProfile = resolveAuthenticationProfileName(profile.name);
14076
14042
  if (authProfile !== profile.name) {
14077
14043
  throw new SimApiError(`Profile "${redact(profile.name)}" shares authentication with "${redact(authProfile)}". Run: sim login --profile ${redact(authProfile)}`, 0);
14078
14044
  }
14045
+ if (options.scope !== "platform" && options.scope !== "copilot") {
14046
+ throw new SimApiError(`Unknown scope "${options.scope}". Use platform or copilot.`, 0);
14047
+ }
14048
+ const scope = options.scope;
14079
14049
  const snapshot = readLoginProfileSnapshot(profile.name);
14080
14050
  const storedCredential = snapshot.credential;
14081
14051
  if (storedCredential?.kind === "oauth") {
@@ -14089,13 +14059,13 @@ function loginCommand() {
14089
14059
  }
14090
14060
  }
14091
14061
  const callbackPort = parseCallbackPort(options.callbackPort);
14092
- const loginFlow = await chooseLoginFlow(profile, options);
14062
+ const loginFlow = await chooseLoginFlow(profile, options, scope);
14093
14063
  if (loginFlow === "handoff") {
14094
14064
  if (options.readOnly) {
14095
- throw new SimApiError("API-key login cannot issue a read-only login. Use --method oauth, or drop --read-only.", 0);
14065
+ throw new SimApiError("The pairing-code handoff cannot issue a read-only login; it mints a full API key. Drop --read-only, or sign in through the browser.", 0);
14096
14066
  }
14097
14067
  if (callbackPort !== undefined) {
14098
- throw new SimApiError("API-key login has no local callback, so --callback-port does not apply. Use --method oauth, or drop --callback-port.", 0);
14068
+ throw new SimApiError("The pairing-code handoff has no local callback, so --callback-port does not apply. Drop it, or sign in through the browser.", 0);
14099
14069
  }
14100
14070
  }
14101
14071
  await withProfileLoginLease(profile.name, async () => {
@@ -14104,13 +14074,13 @@ function loginCommand() {
14104
14074
  await loginWithOAuth(profile, options, callbackPort, snapshot);
14105
14075
  return;
14106
14076
  }
14107
- await loginWithHandoff(profile, options, snapshot);
14077
+ await loginWithHandoff(profile, options, scope, snapshot);
14108
14078
  });
14109
14079
  });
14110
14080
  }
14111
- async function loginWithHandoff(profile, options, expected) {
14081
+ async function loginWithHandoff(profile, options, scope, expected) {
14112
14082
  const auth = createAuthRequest();
14113
- const url = buildApprovalUrl(profile.endpoint, auth, profile.workspaceId ?? undefined);
14083
+ const url = buildApprovalUrl(profile.endpoint, auth, scope, profile.workspaceId ?? undefined);
14114
14084
  console.log(`Signing in to ${source_default.bold(profile.endpoint)} as profile ${source_default.bold(safeOneLine(profile.name))}`);
14115
14085
  console.log(`
14116
14086
  Pairing code: ${source_default.bold(auth.pairing)}`);
@@ -14123,8 +14093,8 @@ Pairing code: ${source_default.bold(auth.pairing)}`);
14123
14093
  Waiting for approval…`));
14124
14094
  const key = await pollForKey(profile.endpoint, auth);
14125
14095
  try {
14126
- if (key.scope !== "platform") {
14127
- throw new SimApiError(`Server issued a ${key.scope} key, but the CLI requires a platform API key. Update the Sim deployment and try again.`, 0);
14096
+ if (key.scope !== scope) {
14097
+ throw new SimApiError(`Server issued a ${key.scope} key but this profile needs a ${scope} key. Update the Sim deployment, or run: sim login --scope ${key.scope}`, 0);
14128
14098
  }
14129
14099
  const settings = {
14130
14100
  endpoint: profile.endpoint,
@@ -14185,7 +14155,7 @@ async function revokeStoredOAuth(credential) {
14185
14155
  await revokeToken(endpoint, credential.refreshToken);
14186
14156
  console.log(source_default.dim(" Signed out of Sim; every token from this login was revoked."));
14187
14157
  } catch (error) {
14188
- console.log(source_default.yellow(` Could not revoke the login on ${displayEndpoint} (${safeOneLine(getErrorMessage(error))}). Revoke it in Settings → General → Authorized apps.`));
14158
+ console.log(source_default.yellow(` Could not revoke the login on ${displayEndpoint} (${safeOneLine(getErrorMessage(error))}). Revoke it in Settings → Authorized apps.`));
14189
14159
  }
14190
14160
  }
14191
14161
  function logoutCommand() {
@@ -16087,30 +16057,7 @@ function buildRequest(operation, positional, flags, workspaceId) {
16087
16057
  }
16088
16058
 
16089
16059
  // src/runtime/options.ts
16090
- var DEFAULT_PAGE_SIZE = 100;
16091
- var COMPLETE_LIST_OPERATIONS = new Set([
16092
- "listBlocks",
16093
- "listChatDeployments",
16094
- "listCredentials",
16095
- "listCustomTools",
16096
- "listFiles",
16097
- "listKnowledgeBases",
16098
- "listKnowledgeConnectors",
16099
- "listMcpServers",
16100
- "listSandboxes",
16101
- "listSecrets",
16102
- "listSkillEditors",
16103
- "listSkills",
16104
- "listTables",
16105
- "listTools",
16106
- "listWorkflowMcpServers",
16107
- "listWorkflows",
16108
- "listWorkspaceMembers",
16109
- "listWorkspaces"
16110
- ]);
16111
- function defaultListLimit(operation) {
16112
- return COMPLETE_LIST_OPERATIONS.has(operation) ? 0 : 100;
16113
- }
16060
+ var DEFAULT_LIMIT = 100;
16114
16061
  function describeField(flag, descriptor, name, field) {
16115
16062
  return flag.describe ?? descriptor.describe ?? `Set ${name.replaceAll("-", " ") || field}`;
16116
16063
  }
@@ -16123,21 +16070,15 @@ function withoutWireVocabulary(documented) {
16123
16070
  }
16124
16071
  var NON_PAGINATED_LIMIT_HINT = " (caps a --filter match only; omit it to act on every match, and note 0 is not accepted)";
16125
16072
  function addFieldOption(command, operation, field, descriptor, slot, paginates, capsAFilter) {
16126
- if (field === PROFILE_INJECTED_FIELD)
16127
- return;
16128
- if (field === "cursor") {
16129
- if (paginates && defaultListLimit(operation) > 0) {
16130
- command.option("--cursor <value>", "Continue from nextCursor returned by a previous result");
16131
- }
16073
+ if (field === PROFILE_INJECTED_FIELD || field === "cursor")
16132
16074
  return;
16133
- }
16134
16075
  const flag = flagSpecFor(operation, field);
16135
16076
  if (flag.omit)
16136
16077
  return;
16137
16078
  const name = flagNameFor(operation, field);
16138
16079
  const short = flag.short ? `-${flag.short}, ` : "";
16139
16080
  if (paginates && field === "limit" && (descriptor.kind === "number" || descriptor.kind === "integer")) {
16140
- command.option("--limit <n>", "Maximum items to return (0 for everything)", String(defaultListLimit(operation)));
16081
+ command.option("--limit <n>", "Maximum items to return (0 for everything)", String(DEFAULT_LIMIT));
16141
16082
  return;
16142
16083
  }
16143
16084
  const documented = `${describeField(flag, descriptor, name, field)}${capsAFilter && field === "limit" && (descriptor.kind === "number" || descriptor.kind === "integer") ? NON_PAGINATED_LIMIT_HINT : ""}`;
@@ -16497,10 +16438,11 @@ function unwrapResource(data) {
16497
16438
  const [, value] = entries[0];
16498
16439
  return value && typeof value === "object" && !Array.isArray(value) ? value : data;
16499
16440
  }
16500
- function renderPage(format, page, spec, envelope) {
16441
+ function renderPage(format, rows, spec, envelope, options = {}) {
16501
16442
  writePageNote(spec, envelope);
16502
16443
  writeEnvelopeTruncation(envelope);
16503
- printList(format, page.data, spec.columns ? columnsFrom(spec.columns) : inferColumns(page.data, spec.expand), page);
16444
+ writeCursorTruncation(rows.length, options.truncated === true);
16445
+ printList(format, rows, spec.columns ? columnsFrom(spec.columns) : inferColumns(rows, spec.expand));
16504
16446
  }
16505
16447
  function writePageNote(spec, envelope) {
16506
16448
  if (!spec.pageNote)
@@ -16545,6 +16487,12 @@ function writeEnvelopeTruncation(envelope) {
16545
16487
  `));
16546
16488
  }
16547
16489
  }
16490
+ function writeCursorTruncation(count, truncated) {
16491
+ if (!truncated)
16492
+ return;
16493
+ process.stderr.write(source_default.dim(`showing the first ${count}; more results exist — re-run with --limit 0 for all
16494
+ `));
16495
+ }
16548
16496
  function renderResult(operation, format, raw, spec, options = {}, envelope) {
16549
16497
  writeEnvelopeTruncation(envelope);
16550
16498
  if (spec.document) {
@@ -16681,8 +16629,8 @@ function bulkFailureMessage(operation, payload, body) {
16681
16629
  var EXCLUSIVE_CAP_FIELDS = {
16682
16630
  deleteTableRows: { cap: "limit", ids: "rowIds" }
16683
16631
  };
16684
- function readPagedLimit(raw, operation) {
16685
- const text = String(raw ?? defaultListLimit(operation)).trim();
16632
+ function readPagedLimit(raw) {
16633
+ const text = String(raw ?? DEFAULT_LIMIT).trim();
16686
16634
  const value = text === "" ? Number.NaN : Number(text);
16687
16635
  if (!Number.isInteger(value) || value < 0) {
16688
16636
  throw new SimApiError("--limit must be a whole number of 0 or more (0 for everything)", 0);
@@ -16757,33 +16705,24 @@ async function executeOperation(operation, commandSpec, operationSpec, invocatio
16757
16705
  const omitsWorkspace = commandSpec.allWorkspaces && requestFlags.allWorkspaces === true;
16758
16706
  const needsWorkspace = (hasWorkspaceField || commandSpec.profileWorkspacePath === true) && !omitsWorkspace;
16759
16707
  const paging = cursorSlot(operationSpec);
16760
- const pagedLimit = paging ? readPagedLimit(requestFlags.limit, operation) : 0;
16708
+ const pagedLimit = paging ? readPagedLimit(requestFlags.limit) : 0;
16761
16709
  const request = buildRequest(operation, positional, requestFlags, needsWorkspace ? client.requireWorkspace() : profile.workspaceId);
16762
16710
  if (paging) {
16763
- const initialCursor = request[paging]?.cursor;
16764
- if (initialCursor !== undefined && (typeof initialCursor !== "string" || initialCursor.trim() === "")) {
16765
- throw new SimApiError("--cursor must be a non-empty string", 0);
16766
- }
16767
16711
  const limit = pagedLimit === 0 ? Number.POSITIVE_INFINITY : pagedLimit;
16712
+ const pageSize = Math.min(Number.isFinite(limit) ? limit : DEFAULT_LIMIT, DEFAULT_LIMIT);
16713
+ const pageLimit = "limit" in (operationSpec[paging] ?? {}) ? { limit: pageSize } : {};
16768
16714
  const rows = [];
16769
- const seenCursors = new Set(initialCursor ? [initialCursor] : []);
16770
16715
  const progress = pageProgress();
16771
- let cursor = initialCursor ?? null;
16716
+ let cursor = null;
16772
16717
  let envelope;
16773
16718
  try {
16774
16719
  do {
16775
- const pageSize = Math.min(DEFAULT_PAGE_SIZE, limit - rows.length);
16776
- const pageLimit = "limit" in (operationSpec[paging] ?? {}) ? { limit: pageSize } : {};
16777
16720
  const page = await client.request(request.path, {
16778
16721
  method: operationSpec.method,
16779
16722
  headers: request.headers,
16780
16723
  query: paging === "query" ? { ...request.query, ...pageLimit, cursor } : request.query,
16781
16724
  body: paging === "body" ? { ...request.body ?? {}, ...pageLimit, ...cursor ? { cursor } : {} } : request.body
16782
16725
  });
16783
- if (page.data.length > pageSize) {
16784
- throw new SimApiError(`The API returned ${page.data.length} items for a page limit of ${pageSize}; nextCursor would skip unreturned items.`, 0);
16785
- }
16786
- assertCursorAdvances(page.nextCursor, seenCursors);
16787
16726
  envelope = foldPageEnvelope(envelope, page);
16788
16727
  rows.push(...page.data);
16789
16728
  cursor = page.nextCursor;
@@ -16793,7 +16732,7 @@ async function executeOperation(operation, commandSpec, operationSpec, invocatio
16793
16732
  } finally {
16794
16733
  progress.finish();
16795
16734
  }
16796
- renderPage(profile.output, { data: rows, nextCursor: cursor }, commandSpec, envelope);
16735
+ renderPage(profile.output, Number.isFinite(limit) ? rows.slice(0, limit) : rows, commandSpec, envelope, { truncated: Boolean(cursor) });
16797
16736
  return;
16798
16737
  }
16799
16738
  const result = await client.request(request.path, {
@@ -17301,47 +17240,6 @@ function attachCredentialCommands(program) {
17301
17240
  credentials.command("reconnect").argument("<credentialId>", "Existing OAuth credential to re-authorize").description(describeOperation(V2_OPERATIONS.createCredentialConnection, "Create a short-lived link for reconnecting an OAuth credential")).action((credentialId, _options, command) => createConnectionLink(command, { credentialId }));
17302
17241
  }
17303
17242
 
17304
- // src/http/ndjson.ts
17305
- async function* readNdjson(body, protocol) {
17306
- if (!body) {
17307
- throw new SimApiError(`${protocol} ended without a response body`, 0);
17308
- }
17309
- const reader = body.getReader();
17310
- const decoder = new TextDecoder;
17311
- let buffer = "";
17312
- const parse = (line) => {
17313
- const trimmed = line.trim();
17314
- if (!trimmed)
17315
- return;
17316
- try {
17317
- return JSON.parse(trimmed);
17318
- } catch {
17319
- throw new SimApiError(`${protocol} returned malformed data`, 0);
17320
- }
17321
- };
17322
- try {
17323
- while (true) {
17324
- const { done, value } = await reader.read();
17325
- buffer += done ? decoder.decode() : decoder.decode(value, { stream: true });
17326
- const lines = buffer.split(`
17327
- `);
17328
- buffer = done ? "" : lines.pop() ?? "";
17329
- for (const line of lines) {
17330
- const event = parse(line);
17331
- if (event !== undefined)
17332
- yield event;
17333
- }
17334
- if (done)
17335
- return;
17336
- }
17337
- } finally {
17338
- reader.cancel().catch(() => {
17339
- return;
17340
- });
17341
- reader.releaseLock();
17342
- }
17343
- }
17344
-
17345
17243
  // src/commands/protocol/result.ts
17346
17244
  function printProtocolResult(format, result) {
17347
17245
  const fields = Object.entries(result).map(([key, value]) => [key, text(value)]);
@@ -17349,28 +17247,72 @@ function printProtocolResult(format, result) {
17349
17247
  }
17350
17248
 
17351
17249
  // src/commands/protocol/chat.ts
17250
+ function parseChatStreamLine(line) {
17251
+ const trimmed = line.trim();
17252
+ if (!trimmed)
17253
+ return;
17254
+ try {
17255
+ return JSON.parse(trimmed);
17256
+ } catch {
17257
+ throw new SimApiError("Chat stream returned malformed data", 0);
17258
+ }
17259
+ }
17352
17260
  async function readChatStream(response, onChunk) {
17353
- for await (const value of readNdjson(response.body, "Chat stream")) {
17354
- if (!value || typeof value !== "object" || Array.isArray(value)) {
17355
- throw new SimApiError("Chat stream returned an unknown event", 0);
17356
- }
17357
- const event = value;
17358
- if (event.type === "heartbeat")
17359
- continue;
17261
+ if (!response.body) {
17262
+ throw new SimApiError("Chat stream ended without a response body", 0);
17263
+ }
17264
+ const reader = response.body.getReader();
17265
+ const decoder = new TextDecoder;
17266
+ let buffer = "";
17267
+ let finalResult;
17268
+ const processLine = (line) => {
17269
+ const event = parseChatStreamLine(line);
17270
+ if (!event || event.type === "heartbeat")
17271
+ return false;
17360
17272
  if (event.type === "chunk") {
17361
17273
  if (event.content)
17362
17274
  onChunk(sanitize(event.content));
17363
- continue;
17275
+ return false;
17364
17276
  }
17365
17277
  if (event.type === "error") {
17366
17278
  throw new SimApiError(event.error || "Chat request failed", 0);
17367
17279
  }
17368
17280
  if (event.type === "final") {
17369
- return event.data;
17281
+ finalResult = event.data;
17282
+ return true;
17370
17283
  }
17371
17284
  throw new SimApiError("Chat stream returned an unknown event", 0);
17285
+ };
17286
+ try {
17287
+ let ended = false;
17288
+ while (!ended) {
17289
+ const { done, value } = await reader.read();
17290
+ if (done)
17291
+ break;
17292
+ buffer += decoder.decode(value, { stream: true });
17293
+ const lines = buffer.split(`
17294
+ `);
17295
+ buffer = lines.pop() ?? "";
17296
+ for (const line of lines) {
17297
+ if (processLine(line)) {
17298
+ ended = true;
17299
+ break;
17300
+ }
17301
+ }
17302
+ }
17303
+ if (!ended) {
17304
+ buffer += decoder.decode();
17305
+ processLine(buffer);
17306
+ }
17307
+ if (!finalResult) {
17308
+ throw new SimApiError("Chat stream ended without a final result", 0);
17309
+ }
17310
+ return finalResult;
17311
+ } finally {
17312
+ reader.cancel().catch(() => {
17313
+ return;
17314
+ });
17372
17315
  }
17373
- throw new SimApiError("Chat stream ended without a final result", 0);
17374
17316
  }
17375
17317
  function ignoreBrokenPipe(stream) {
17376
17318
  const onError = (error) => {
@@ -18145,11 +18087,11 @@ async function listResources(client, config, workspaceId, folderPath, search, li
18145
18087
  const paginated = "cursor" in V2_OPERATIONS[config.resources].query;
18146
18088
  if (!paginated) {
18147
18089
  const page = await client.request(path, { query });
18148
- return page.data.slice(0, limit);
18090
+ return { items: page.data.slice(0, limit), truncated: page.data.length > limit };
18149
18091
  }
18150
- return requestAllPages(client, path, {
18092
+ return requestPages(client, path, {
18151
18093
  query,
18152
- pageSize: DEFAULT_PAGE_SIZE,
18094
+ pageSize: DEFAULT_LIMIT,
18153
18095
  limit
18154
18096
  });
18155
18097
  }
@@ -18179,7 +18121,7 @@ function entriesFor(config, folders, resources) {
18179
18121
  ].sort((left, right) => left.name.localeCompare(right.name) || left.kind.localeCompare(right.kind));
18180
18122
  }
18181
18123
  function attachResourceDirectoryCommands(group, config) {
18182
- group.command("ls").argument("[path]", "Folder path to list; defaults to the root folder").allowExcessArguments(false).description(`List ${config.kind} resources and child folders together`).option("--search <text>", "Filter folders and resources by name").addOption(new Option("--limit <n>", "Maximum combined items to return (0 for everything)").default("0")).action(async (path, options, command) => {
18124
+ group.command("ls").argument("[path]", "Folder path to list; defaults to the root folder").allowExcessArguments(false).description(`List ${config.kind} resources and child folders together`).option("--search <text>", "Filter folders and resources by name").addOption(new Option("--limit <n>", "Maximum combined items to return (0 for everything)").default(String(DEFAULT_LIMIT))).action(async (path, options, command) => {
18183
18125
  const rawLimit = Number(options.limit);
18184
18126
  if (!Number.isSafeInteger(rawLimit) || rawLimit < 0) {
18185
18127
  throw new SimApiError("--limit must be a whole number of 0 or more (0 for everything)", 0);
@@ -18192,8 +18134,9 @@ function attachResourceDirectoryCommands(group, config) {
18192
18134
  listFolders(client, config.folders, workspaceId, folderPath, options.search),
18193
18135
  listResources(client, config, workspaceId, folderPath, options.search, limit)
18194
18136
  ]);
18195
- const entries = entriesFor(config, folders, resources);
18137
+ const entries = entriesFor(config, folders, resources.items);
18196
18138
  const shown = entries.slice(0, limit);
18139
+ writeCursorTruncation(shown.length, resources.truncated || entries.length > limit);
18197
18140
  printList(profile.output, shown, COLUMNS2);
18198
18141
  });
18199
18142
  group.command("mkdir").argument("<path>", "Folder path to create; the leading / is optional").allowExcessArguments(false).description(`Create a ${config.kind} directory at a path`).action(async (path, _options, command) => {
@@ -18360,7 +18303,6 @@ function attachTableImport(tables) {
18360
18303
  // src/commands/protocol/workflow-run-follow.ts
18361
18304
  var AGENT_STREAM_PROTOCOL_HEADER = "x-sim-stream-protocol";
18362
18305
  var AGENT_STREAM_PROTOCOL_V1 = "agent-events-v1";
18363
- var WORKFLOW_RESULT_STREAM_CONTENT_TYPE = "application/x-ndjson";
18364
18306
  var DONE_SENTINEL = "[DONE]";
18365
18307
  function resolveWorkflowRunSelection(flags) {
18366
18308
  const manual = flags.manual === true;
@@ -18412,59 +18354,6 @@ function stringField(frame, key) {
18412
18354
  const value = frame[key];
18413
18355
  return typeof value === "string" ? value : null;
18414
18356
  }
18415
- async function readWorkflowResult(response) {
18416
- const contentType = (response.headers.get("content-type") ?? "").toLowerCase();
18417
- if (!contentType.includes(WORKFLOW_RESULT_STREAM_CONTENT_TYPE)) {
18418
- let envelope;
18419
- try {
18420
- envelope = await response.json();
18421
- } catch {
18422
- throw new SimApiError(`Workflow run returned malformed JSON${contentType ? ` as ${contentType}` : ""}`, response.status);
18423
- }
18424
- if (!isRecord(envelope)) {
18425
- throw new SimApiError("Workflow run returned an invalid result envelope", response.status);
18426
- }
18427
- return isRecord(envelope.data) ? envelope.data : envelope;
18428
- }
18429
- for await (const value of readNdjson(response.body, "Workflow result stream")) {
18430
- if (!isRecord(value) || typeof value.type !== "string") {
18431
- throw new SimApiError("Workflow result stream returned an unknown event", response.status);
18432
- }
18433
- if (value.type === "heartbeat")
18434
- continue;
18435
- if (value.type === "error") {
18436
- throw new SimApiError(safeOneLine(typeof value.error === "string" ? value.error : "Workflow run failed"), typeof value.status === "number" ? value.status : 0, typeof value.code === "string" ? value.code : null);
18437
- }
18438
- if (value.type === "final" && isRecord(value.data))
18439
- return value.data;
18440
- throw new SimApiError("Workflow result stream returned an unknown event", response.status);
18441
- }
18442
- throw new SimApiError("Workflow result stream ended without a final result", response.status);
18443
- }
18444
- async function runWithResultStream(workflowId, command) {
18445
- const flags = command.optsWithGlobals();
18446
- const { client, profile } = clientFrom(command);
18447
- const operation = V2_OPERATIONS.executeWorkflow;
18448
- const commandSpec = CLI_CONTRACT.executeWorkflow ?? {};
18449
- try {
18450
- const request = buildRequest("executeWorkflow", [workflowId], flags, profile.workspaceId);
18451
- const response = await client.requestRaw(request.path, {
18452
- method: operation.method,
18453
- query: request.query,
18454
- body: request.body,
18455
- headers: { ...request.headers, accept: WORKFLOW_RESULT_STREAM_CONTENT_TYPE }
18456
- });
18457
- const payload = await readWorkflowResult(response);
18458
- renderResult("executeWorkflow", profile.output, payload, commandSpec, {
18459
- expandedTrace: flags.trace === true
18460
- });
18461
- const failure = runFailureMessage("executeWorkflow", payload);
18462
- if (failure)
18463
- throw new SimApiError(failure, 0);
18464
- } catch (error) {
18465
- throw retypeApiError(error, "executeWorkflow", commandSpec, operation);
18466
- }
18467
- }
18468
18357
  async function* sseData(body) {
18469
18358
  const reader = body.getReader();
18470
18359
  const decoder = new TextDecoder;
@@ -18636,10 +18525,6 @@ function followOrDelegate(previous) {
18636
18525
  if (flags.includeThinking === true || flags.includeToolCalls === true) {
18637
18526
  throw new SimApiError("--include-thinking and --include-tool-calls describe a stream; add --follow", 0);
18638
18527
  }
18639
- if (flags.async !== true) {
18640
- await runWithResultStream(workflowId, command);
18641
- return;
18642
- }
18643
18528
  if (previous) {
18644
18529
  await previous(command.processedArgs);
18645
18530
  return;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sim",
3
- "version": "2.1.8-preview.103.1",
3
+ "version": "2.1.8-preview.96.1",
4
4
  "description": "Sim CLI - talk to the Sim API from your terminal",
5
5
  "type": "module",
6
6
  "bin": {