sim 2.1.8-preview.99.1 → 2.1.8

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 +16 -1
  2. package/dist/index.js +103 -58
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -220,11 +220,26 @@ will consume the result, and `text` for tab-separated shell output:
220
220
 
221
221
  ```bash
222
222
  sim workflows list --output json
223
- sim logs list --output json | jq -r '.[].runId'
223
+ sim logs list --output json | jq -r '.data[].runId'
224
224
  SIM_OUTPUT=yaml sim tables get <tableId>
225
225
  sim configure --set-output json
226
226
  ```
227
227
 
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
+
228
243
  JSON-valued options accept inline JSON, a file prefixed with `@`, or stdin with
229
244
  `@-`:
230
245
 
package/dist/index.js CHANGED
@@ -4763,15 +4763,21 @@ function pageProgress() {
4763
4763
  }
4764
4764
  };
4765
4765
  }
4766
- async function requestAllPages(client, path, options) {
4767
- return (await requestPages(client, path, options)).items;
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);
4768
4773
  }
4769
- async function requestPages(client, path, options) {
4774
+ async function requestAllPages(client, path, options) {
4770
4775
  const { query, pageSize, limit: requestedLimit, ...requestOptions } = options;
4771
4776
  const limit = requestedLimit ?? Number.POSITIVE_INFINITY;
4772
4777
  if (limit <= 0)
4773
- return { items: [], truncated: false };
4778
+ return [];
4774
4779
  const items = [];
4780
+ const seenCursors = new Set;
4775
4781
  const progress = pageProgress();
4776
4782
  let cursor = null;
4777
4783
  try {
@@ -4784,6 +4790,7 @@ async function requestPages(client, path, options) {
4784
4790
  cursor
4785
4791
  }
4786
4792
  });
4793
+ assertCursorAdvances(page.nextCursor, seenCursors);
4787
4794
  items.push(...page.data);
4788
4795
  cursor = page.nextCursor;
4789
4796
  if (cursor && items.length < limit)
@@ -4792,7 +4799,7 @@ async function requestPages(client, path, options) {
4792
4799
  } finally {
4793
4800
  progress.finish();
4794
4801
  }
4795
- return { items: items.slice(0, limit), truncated: cursor !== null || items.length > limit };
4802
+ return items.slice(0, limit);
4796
4803
  }
4797
4804
  function resolvePath(template, params = {}) {
4798
4805
  return template.replace(/\[([^\]]+)\]/g, (_match, key) => {
@@ -8716,6 +8723,7 @@ var V2_OPERATIONS = {
8716
8723
  pathParamDocs: { workflowId: "Unique workflow identifier." },
8717
8724
  responseMode: "json",
8718
8725
  summary: "Apply Workflow Operations",
8726
+ workspaceKeyUnsupported: true,
8719
8727
  query: {
8720
8728
  dryRun: {
8721
8729
  kind: "boolean",
@@ -8804,7 +8812,7 @@ var V2_OPERATIONS = {
8804
8812
  },
8805
8813
  folderPaths: {
8806
8814
  kind: "string",
8807
- 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."
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."
8808
8816
  }
8809
8817
  }
8810
8818
  },
@@ -9463,7 +9471,7 @@ var V2_OPERATIONS = {
9463
9471
  kind: "enum",
9464
9472
  values: ["streamable-http"],
9465
9473
  default: "streamable-http",
9466
- describe: "Transport used to communicate with the server. Applied server-side as `streamable-http` when omitted on create."
9474
+ describe: "Transport protocol. Defaults to `streamable-http` on creation."
9467
9475
  },
9468
9476
  url: {
9469
9477
  kind: "string",
@@ -9482,17 +9490,17 @@ var V2_OPERATIONS = {
9482
9490
  timeout: {
9483
9491
  kind: "integer",
9484
9492
  default: 30000,
9485
- describe: "Per-request timeout in milliseconds. Applied server-side as 30000 when omitted on create."
9493
+ describe: "Per-request timeout in milliseconds. Defaults to 30000 on creation."
9486
9494
  },
9487
9495
  retries: {
9488
9496
  kind: "integer",
9489
9497
  default: 3,
9490
- describe: "Number of retries per request. Applied server-side as 3 when omitted on create."
9498
+ describe: "Number of retries per request. Defaults to 3 on creation."
9491
9499
  },
9492
9500
  enabled: {
9493
9501
  kind: "boolean",
9494
9502
  default: true,
9495
- describe: "Whether the server tools are available to workflows. Applied server-side as true when omitted on create."
9503
+ describe: "Whether workflows can use the server's tools. Defaults to true on creation."
9496
9504
  },
9497
9505
  oauthClientId: {
9498
9506
  kind: "string",
@@ -10390,7 +10398,7 @@ var V2_OPERATIONS = {
10390
10398
  input: {
10391
10399
  kind: "object",
10392
10400
  default: {},
10393
- 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."
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."
10394
10402
  },
10395
10403
  credentialId: {
10396
10404
  kind: "string",
@@ -10425,7 +10433,7 @@ var V2_OPERATIONS = {
10425
10433
  },
10426
10434
  executionTimeoutSeconds: {
10427
10435
  kind: "integer",
10428
- 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."
10436
+ describe: "Maximum duration of an asynchronous run, in seconds, capped by the plan's execution timeout. Requires `async: true`; otherwise returns `400`."
10429
10437
  },
10430
10438
  stream: {
10431
10439
  kind: "boolean",
@@ -10434,7 +10442,7 @@ var V2_OPERATIONS = {
10434
10442
  },
10435
10443
  selectedOutputs: {
10436
10444
  kind: "array",
10437
- 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."
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."
10438
10446
  },
10439
10447
  includeThinking: {
10440
10448
  kind: "boolean",
@@ -10458,7 +10466,7 @@ var V2_OPERATIONS = {
10458
10466
  headers: {
10459
10467
  "x-run-id": {
10460
10468
  kind: "string",
10461
- 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.'
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."
10462
10470
  },
10463
10471
  "x-sim-via": {
10464
10472
  kind: "string",
@@ -10682,7 +10690,7 @@ var V2_OPERATIONS = {
10682
10690
  },
10683
10691
  folderPaths: {
10684
10692
  kind: "string",
10685
- 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."
10693
+ describe: "Comma-separated workflow folder paths, including descendants. Up to 100 paths. Unknown folder paths contribute no matches."
10686
10694
  },
10687
10695
  triggers: {
10688
10696
  kind: "string",
@@ -10704,7 +10712,7 @@ var V2_OPERATIONS = {
10704
10712
  segmentCount: {
10705
10713
  kind: "integer",
10706
10714
  default: 72,
10707
- 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."
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."
10708
10716
  }
10709
10717
  }
10710
10718
  },
@@ -11160,7 +11168,7 @@ var V2_OPERATIONS = {
11160
11168
  source: {
11161
11169
  kind: "enum",
11162
11170
  values: ["builtin", "custom"],
11163
- describe: "Restrict to shipped blocks or to this workspaces deployed custom blocks."
11171
+ describe: "Restrict to built-in blocks or this workspace's deployed custom blocks."
11164
11172
  },
11165
11173
  sortBy: {
11166
11174
  kind: "enum",
@@ -11359,7 +11367,7 @@ var V2_OPERATIONS = {
11359
11367
  },
11360
11368
  parentPath: {
11361
11369
  kind: "string",
11362
- 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."
11370
+ describe: "Restrict results to direct children of this parent path. Unknown folder paths contribute no matches."
11363
11371
  },
11364
11372
  search: {
11365
11373
  kind: "string",
@@ -11421,7 +11429,7 @@ var V2_OPERATIONS = {
11421
11429
  },
11422
11430
  folderPath: {
11423
11431
  kind: "string",
11424
- 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."
11432
+ describe: "Restrict files to this folder, including subfolders when `recursive` is true. Unknown folder paths contribute no matches."
11425
11433
  },
11426
11434
  recursive: {
11427
11435
  kind: "enum",
@@ -11439,7 +11447,7 @@ var V2_OPERATIONS = {
11439
11447
  "n",
11440
11448
  "disabled"
11441
11449
  ],
11442
- 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."
11450
+ describe: "Include subfolders in the folder filter. Defaults to true when searching and false otherwise. Ignored without a folder filter."
11443
11451
  },
11444
11452
  scope: {
11445
11453
  kind: "enum",
@@ -11490,11 +11498,11 @@ var V2_OPERATIONS = {
11490
11498
  kind: "enum",
11491
11499
  values: ["active", "archived"],
11492
11500
  default: "active",
11493
- 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."
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."
11494
11502
  },
11495
11503
  folderPath: {
11496
11504
  kind: "string",
11497
- 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."
11505
+ describe: "Restrict results to knowledge bases in this folder. Unknown folder paths contribute no matches."
11498
11506
  },
11499
11507
  search: {
11500
11508
  kind: "string",
@@ -11714,7 +11722,7 @@ var V2_OPERATIONS = {
11714
11722
  },
11715
11723
  parentPath: {
11716
11724
  kind: "string",
11717
- 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."
11725
+ describe: "Restrict results to direct children of this parent path. Unknown folder paths contribute no matches."
11718
11726
  },
11719
11727
  search: {
11720
11728
  kind: "string",
@@ -11865,7 +11873,7 @@ var V2_OPERATIONS = {
11865
11873
  },
11866
11874
  folderPaths: {
11867
11875
  kind: "string",
11868
- 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."
11876
+ describe: "Comma-separated workflow folder paths, including descendants. Up to 100 paths. Unknown folder paths contribute no matches."
11869
11877
  }
11870
11878
  }
11871
11879
  },
@@ -11924,7 +11932,7 @@ var V2_OPERATIONS = {
11924
11932
  },
11925
11933
  refresh: {
11926
11934
  kind: "boolean",
11927
- 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."
11935
+ describe: "Refresh tools using your credentials. Otherwise results may reuse another workspace member's recent discovery and omit newly added tools."
11928
11936
  }
11929
11937
  }
11930
11938
  },
@@ -12102,7 +12110,7 @@ var V2_OPERATIONS = {
12102
12110
  },
12103
12111
  parentPath: {
12104
12112
  kind: "string",
12105
- 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."
12113
+ describe: "Restrict results to direct children of this parent path. Unknown folder paths contribute no matches."
12106
12114
  },
12107
12115
  search: {
12108
12116
  kind: "string",
@@ -12166,7 +12174,7 @@ var V2_OPERATIONS = {
12166
12174
  },
12167
12175
  folderPath: {
12168
12176
  kind: "string",
12169
- 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."
12177
+ describe: "Restrict results to tables in this folder. Unknown folder paths contribute no matches."
12170
12178
  },
12171
12179
  search: {
12172
12180
  kind: "string",
@@ -12268,7 +12276,7 @@ var V2_OPERATIONS = {
12268
12276
  },
12269
12277
  parentPath: {
12270
12278
  kind: "string",
12271
- 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."
12279
+ describe: "Restrict results to direct children of this parent path. Unknown folder paths contribute no matches."
12272
12280
  },
12273
12281
  search: {
12274
12282
  kind: "string",
@@ -12403,7 +12411,7 @@ var V2_OPERATIONS = {
12403
12411
  },
12404
12412
  folderPath: {
12405
12413
  kind: "string",
12406
- 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."
12414
+ describe: "Restrict results to workflows in this folder path. Unknown folder paths contribute no matches."
12407
12415
  },
12408
12416
  deployedOnly: {
12409
12417
  kind: "boolean",
@@ -12710,6 +12718,7 @@ var V2_OPERATIONS = {
12710
12718
  pathParamDocs: { workflowId: "Unique workflow identifier." },
12711
12719
  responseMode: "json",
12712
12720
  summary: "Create or Replace Workflow Chat Deployment",
12721
+ workspaceKeyUnsupported: true,
12713
12722
  body: {
12714
12723
  identifier: {
12715
12724
  kind: "string",
@@ -12762,6 +12771,7 @@ var V2_OPERATIONS = {
12762
12771
  pathParamDocs: { workflowId: "Unique workflow identifier." },
12763
12772
  responseMode: "json",
12764
12773
  summary: "Replace Workflow State",
12774
+ workspaceKeyUnsupported: true,
12765
12775
  query: {
12766
12776
  dryRun: {
12767
12777
  kind: "boolean",
@@ -13198,6 +13208,11 @@ var V2_OPERATIONS = {
13198
13208
  },
13199
13209
  apiToken: { kind: "string", describe: "Write-only provider API token." },
13200
13210
  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
+ },
13201
13216
  signingSecret: { kind: "string", describe: "Write-only webhook signing secret." },
13202
13217
  botToken: { kind: "string", describe: "Write-only bot token." },
13203
13218
  clientId: { kind: "string", describe: "OAuth client identifier." },
@@ -13448,7 +13463,7 @@ var V2_OPERATIONS = {
13448
13463
  kind: "enum",
13449
13464
  values: ["streamable-http"],
13450
13465
  default: "streamable-http",
13451
- describe: "Transport used to communicate with the server. Applied server-side as `streamable-http` when omitted on create."
13466
+ describe: "Transport protocol. Defaults to `streamable-http` on creation."
13452
13467
  },
13453
13468
  url: {
13454
13469
  kind: "string",
@@ -13466,17 +13481,17 @@ var V2_OPERATIONS = {
13466
13481
  timeout: {
13467
13482
  kind: "integer",
13468
13483
  default: 30000,
13469
- describe: "Per-request timeout in milliseconds. Applied server-side as 30000 when omitted on create."
13484
+ describe: "Per-request timeout in milliseconds. Defaults to 30000 on creation."
13470
13485
  },
13471
13486
  retries: {
13472
13487
  kind: "integer",
13473
13488
  default: 3,
13474
- describe: "Number of retries per request. Applied server-side as 3 when omitted on create."
13489
+ describe: "Number of retries per request. Defaults to 3 on creation."
13475
13490
  },
13476
13491
  enabled: {
13477
13492
  kind: "boolean",
13478
13493
  default: true,
13479
- describe: "Whether the server tools are available to workflows. Applied server-side as true when omitted on create."
13494
+ describe: "Whether workflows can use the server's tools. Defaults to true on creation."
13480
13495
  },
13481
13496
  oauthClientId: {
13482
13497
  kind: "string",
@@ -16072,7 +16087,30 @@ function buildRequest(operation, positional, flags, workspaceId) {
16072
16087
  }
16073
16088
 
16074
16089
  // src/runtime/options.ts
16075
- var DEFAULT_LIMIT = 100;
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
+ }
16076
16114
  function describeField(flag, descriptor, name, field) {
16077
16115
  return flag.describe ?? descriptor.describe ?? `Set ${name.replaceAll("-", " ") || field}`;
16078
16116
  }
@@ -16085,15 +16123,21 @@ function withoutWireVocabulary(documented) {
16085
16123
  }
16086
16124
  var NON_PAGINATED_LIMIT_HINT = " (caps a --filter match only; omit it to act on every match, and note 0 is not accepted)";
16087
16125
  function addFieldOption(command, operation, field, descriptor, slot, paginates, capsAFilter) {
16088
- if (field === PROFILE_INJECTED_FIELD || field === "cursor")
16126
+ if (field === PROFILE_INJECTED_FIELD)
16089
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
+ }
16132
+ return;
16133
+ }
16090
16134
  const flag = flagSpecFor(operation, field);
16091
16135
  if (flag.omit)
16092
16136
  return;
16093
16137
  const name = flagNameFor(operation, field);
16094
16138
  const short = flag.short ? `-${flag.short}, ` : "";
16095
16139
  if (paginates && field === "limit" && (descriptor.kind === "number" || descriptor.kind === "integer")) {
16096
- command.option("--limit <n>", "Maximum items to return (0 for everything)", String(DEFAULT_LIMIT));
16140
+ command.option("--limit <n>", "Maximum items to return (0 for everything)", String(defaultListLimit(operation)));
16097
16141
  return;
16098
16142
  }
16099
16143
  const documented = `${describeField(flag, descriptor, name, field)}${capsAFilter && field === "limit" && (descriptor.kind === "number" || descriptor.kind === "integer") ? NON_PAGINATED_LIMIT_HINT : ""}`;
@@ -16453,11 +16497,10 @@ function unwrapResource(data) {
16453
16497
  const [, value] = entries[0];
16454
16498
  return value && typeof value === "object" && !Array.isArray(value) ? value : data;
16455
16499
  }
16456
- function renderPage(format, rows, spec, envelope, options = {}) {
16500
+ function renderPage(format, page, spec, envelope) {
16457
16501
  writePageNote(spec, envelope);
16458
16502
  writeEnvelopeTruncation(envelope);
16459
- writeCursorTruncation(rows.length, options.truncated === true);
16460
- printList(format, rows, spec.columns ? columnsFrom(spec.columns) : inferColumns(rows, spec.expand));
16503
+ printList(format, page.data, spec.columns ? columnsFrom(spec.columns) : inferColumns(page.data, spec.expand), page);
16461
16504
  }
16462
16505
  function writePageNote(spec, envelope) {
16463
16506
  if (!spec.pageNote)
@@ -16502,12 +16545,6 @@ function writeEnvelopeTruncation(envelope) {
16502
16545
  `));
16503
16546
  }
16504
16547
  }
16505
- function writeCursorTruncation(count, truncated) {
16506
- if (!truncated)
16507
- return;
16508
- process.stderr.write(source_default.dim(`showing the first ${count}; more results exist — re-run with --limit 0 for all
16509
- `));
16510
- }
16511
16548
  function renderResult(operation, format, raw, spec, options = {}, envelope) {
16512
16549
  writeEnvelopeTruncation(envelope);
16513
16550
  if (spec.document) {
@@ -16644,8 +16681,8 @@ function bulkFailureMessage(operation, payload, body) {
16644
16681
  var EXCLUSIVE_CAP_FIELDS = {
16645
16682
  deleteTableRows: { cap: "limit", ids: "rowIds" }
16646
16683
  };
16647
- function readPagedLimit(raw) {
16648
- const text = String(raw ?? DEFAULT_LIMIT).trim();
16684
+ function readPagedLimit(raw, operation) {
16685
+ const text = String(raw ?? defaultListLimit(operation)).trim();
16649
16686
  const value = text === "" ? Number.NaN : Number(text);
16650
16687
  if (!Number.isInteger(value) || value < 0) {
16651
16688
  throw new SimApiError("--limit must be a whole number of 0 or more (0 for everything)", 0);
@@ -16720,24 +16757,33 @@ async function executeOperation(operation, commandSpec, operationSpec, invocatio
16720
16757
  const omitsWorkspace = commandSpec.allWorkspaces && requestFlags.allWorkspaces === true;
16721
16758
  const needsWorkspace = (hasWorkspaceField || commandSpec.profileWorkspacePath === true) && !omitsWorkspace;
16722
16759
  const paging = cursorSlot(operationSpec);
16723
- const pagedLimit = paging ? readPagedLimit(requestFlags.limit) : 0;
16760
+ const pagedLimit = paging ? readPagedLimit(requestFlags.limit, operation) : 0;
16724
16761
  const request = buildRequest(operation, positional, requestFlags, needsWorkspace ? client.requireWorkspace() : profile.workspaceId);
16725
16762
  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
+ }
16726
16767
  const limit = pagedLimit === 0 ? Number.POSITIVE_INFINITY : pagedLimit;
16727
- const pageSize = Math.min(Number.isFinite(limit) ? limit : DEFAULT_LIMIT, DEFAULT_LIMIT);
16728
- const pageLimit = "limit" in (operationSpec[paging] ?? {}) ? { limit: pageSize } : {};
16729
16768
  const rows = [];
16769
+ const seenCursors = new Set(initialCursor ? [initialCursor] : []);
16730
16770
  const progress = pageProgress();
16731
- let cursor = null;
16771
+ let cursor = initialCursor ?? null;
16732
16772
  let envelope;
16733
16773
  try {
16734
16774
  do {
16775
+ const pageSize = Math.min(DEFAULT_PAGE_SIZE, limit - rows.length);
16776
+ const pageLimit = "limit" in (operationSpec[paging] ?? {}) ? { limit: pageSize } : {};
16735
16777
  const page = await client.request(request.path, {
16736
16778
  method: operationSpec.method,
16737
16779
  headers: request.headers,
16738
16780
  query: paging === "query" ? { ...request.query, ...pageLimit, cursor } : request.query,
16739
16781
  body: paging === "body" ? { ...request.body ?? {}, ...pageLimit, ...cursor ? { cursor } : {} } : request.body
16740
16782
  });
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);
16741
16787
  envelope = foldPageEnvelope(envelope, page);
16742
16788
  rows.push(...page.data);
16743
16789
  cursor = page.nextCursor;
@@ -16747,7 +16793,7 @@ async function executeOperation(operation, commandSpec, operationSpec, invocatio
16747
16793
  } finally {
16748
16794
  progress.finish();
16749
16795
  }
16750
- renderPage(profile.output, Number.isFinite(limit) ? rows.slice(0, limit) : rows, commandSpec, envelope, { truncated: Boolean(cursor) });
16796
+ renderPage(profile.output, { data: rows, nextCursor: cursor }, commandSpec, envelope);
16751
16797
  return;
16752
16798
  }
16753
16799
  const result = await client.request(request.path, {
@@ -18099,11 +18145,11 @@ async function listResources(client, config, workspaceId, folderPath, search, li
18099
18145
  const paginated = "cursor" in V2_OPERATIONS[config.resources].query;
18100
18146
  if (!paginated) {
18101
18147
  const page = await client.request(path, { query });
18102
- return { items: page.data.slice(0, limit), truncated: page.data.length > limit };
18148
+ return page.data.slice(0, limit);
18103
18149
  }
18104
- return requestPages(client, path, {
18150
+ return requestAllPages(client, path, {
18105
18151
  query,
18106
- pageSize: DEFAULT_LIMIT,
18152
+ pageSize: DEFAULT_PAGE_SIZE,
18107
18153
  limit
18108
18154
  });
18109
18155
  }
@@ -18133,7 +18179,7 @@ function entriesFor(config, folders, resources) {
18133
18179
  ].sort((left, right) => left.name.localeCompare(right.name) || left.kind.localeCompare(right.kind));
18134
18180
  }
18135
18181
  function attachResourceDirectoryCommands(group, config) {
18136
- 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) => {
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) => {
18137
18183
  const rawLimit = Number(options.limit);
18138
18184
  if (!Number.isSafeInteger(rawLimit) || rawLimit < 0) {
18139
18185
  throw new SimApiError("--limit must be a whole number of 0 or more (0 for everything)", 0);
@@ -18146,9 +18192,8 @@ function attachResourceDirectoryCommands(group, config) {
18146
18192
  listFolders(client, config.folders, workspaceId, folderPath, options.search),
18147
18193
  listResources(client, config, workspaceId, folderPath, options.search, limit)
18148
18194
  ]);
18149
- const entries = entriesFor(config, folders, resources.items);
18195
+ const entries = entriesFor(config, folders, resources);
18150
18196
  const shown = entries.slice(0, limit);
18151
- writeCursorTruncation(shown.length, resources.truncated || entries.length > limit);
18152
18197
  printList(profile.output, shown, COLUMNS2);
18153
18198
  });
18154
18199
  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) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sim",
3
- "version": "2.1.8-preview.99.1",
3
+ "version": "2.1.8",
4
4
  "description": "Sim CLI - talk to the Sim API from your terminal",
5
5
  "type": "module",
6
6
  "bin": {