sim 2.1.8-preview.102.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.
- package/README.md +7 -33
- package/dist/index.js +137 -247
- 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
|
-
|
|
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 →
|
|
39
|
+
**Settings → Authorized apps**. Choose a default workspace afterward with
|
|
45
40
|
`sim configure --set-workspace <id>`.
|
|
46
41
|
|
|
47
|
-
Use
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
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 '.
|
|
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}: ${
|
|
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
|
|
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 --
|
|
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: "
|
|
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
|
|
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.
|
|
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.
|
|
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
|
|
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: "
|
|
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: "
|
|
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: "
|
|
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:
|
|
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
|
|
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,
|
|
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
|
|
11147
|
+
describe: "Restrict to shipped blocks or to this workspace’s 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.
|
|
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
|
|
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: "
|
|
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: "
|
|
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.
|
|
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.
|
|
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
|
|
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: "
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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",
|
|
@@ -13458,7 +13432,7 @@ var V2_OPERATIONS = {
|
|
|
13458
13432
|
kind: "enum",
|
|
13459
13433
|
values: ["streamable-http"],
|
|
13460
13434
|
default: "streamable-http",
|
|
13461
|
-
describe: "Transport
|
|
13435
|
+
describe: "Transport used to communicate with the server. Applied server-side as `streamable-http` when omitted on create."
|
|
13462
13436
|
},
|
|
13463
13437
|
url: {
|
|
13464
13438
|
kind: "string",
|
|
@@ -13476,17 +13450,17 @@ var V2_OPERATIONS = {
|
|
|
13476
13450
|
timeout: {
|
|
13477
13451
|
kind: "integer",
|
|
13478
13452
|
default: 30000,
|
|
13479
|
-
describe: "Per-request timeout in milliseconds.
|
|
13453
|
+
describe: "Per-request timeout in milliseconds. Applied server-side as 30000 when omitted on create."
|
|
13480
13454
|
},
|
|
13481
13455
|
retries: {
|
|
13482
13456
|
kind: "integer",
|
|
13483
13457
|
default: 3,
|
|
13484
|
-
describe: "Number of retries per request.
|
|
13458
|
+
describe: "Number of retries per request. Applied server-side as 3 when omitted on create."
|
|
13485
13459
|
},
|
|
13486
13460
|
enabled: {
|
|
13487
13461
|
kind: "boolean",
|
|
13488
13462
|
default: true,
|
|
13489
|
-
describe: "Whether
|
|
13463
|
+
describe: "Whether the server tools are available to workflows. Applied server-side as true when omitted on create."
|
|
13490
13464
|
},
|
|
13491
13465
|
oauthClientId: {
|
|
13492
13466
|
kind: "string",
|
|
@@ -13970,12 +13944,12 @@ function addProfileCommand() {
|
|
|
13970
13944
|
console.log(source_default.dim(` Try: sim --profile ${safeOneLine(profileName)} whoami`));
|
|
13971
13945
|
});
|
|
13972
13946
|
}
|
|
13973
|
-
async function chooseLoginFlow(profile, options) {
|
|
13947
|
+
async function chooseLoginFlow(profile, options, scope) {
|
|
13974
13948
|
requireSecureEndpoint(profile.endpoint);
|
|
13975
|
-
if (options.
|
|
13949
|
+
if (options.browserless || scope === "copilot")
|
|
13976
13950
|
return "handoff";
|
|
13977
|
-
if (
|
|
13978
|
-
console.log(source_default.dim(`This looks like a remote session
|
|
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.
|
|
13979
13953
|
`));
|
|
13980
13954
|
return "handoff";
|
|
13981
13955
|
}
|
|
@@ -13984,10 +13958,7 @@ async function chooseLoginFlow(profile, options) {
|
|
|
13984
13958
|
throw new SimApiError(`Could not reach ${profile.endpoint}. Check the endpoint.`, 0);
|
|
13985
13959
|
}
|
|
13986
13960
|
if (status === "unavailable") {
|
|
13987
|
-
|
|
13988
|
-
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);
|
|
13989
|
-
}
|
|
13990
|
-
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.
|
|
13991
13962
|
`));
|
|
13992
13963
|
return "handoff";
|
|
13993
13964
|
}
|
|
@@ -14053,24 +14024,28 @@ Waiting for you to approve in the browser…`));
|
|
|
14053
14024
|
try {
|
|
14054
14025
|
await revokeToken(profile.endpoint, tokens.refreshToken);
|
|
14055
14026
|
} catch (revocationError) {
|
|
14056
|
-
console.log(source_default.yellow(`Could not revoke the uncommitted login (${safeOneLine(getErrorMessage(revocationError))}). Revoke Sim CLI in Settings →
|
|
14027
|
+
console.log(source_default.yellow(`Could not revoke the uncommitted login (${safeOneLine(getErrorMessage(revocationError))}). Revoke Sim CLI in Settings → Authorized apps.`));
|
|
14057
14028
|
}
|
|
14058
14029
|
throw error;
|
|
14059
14030
|
}
|
|
14060
14031
|
console.log(source_default.green(`
|
|
14061
14032
|
✓ Logged in. Login stored in ${credentialsPath()}`));
|
|
14062
|
-
console.log(source_default.dim(grantsWriteAccess(tokens.scope) ? " Renews itself; revoke it any time in Settings →
|
|
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."));
|
|
14063
14034
|
if (!profile.workspaceId) {
|
|
14064
14035
|
console.log(source_default.dim(" No default workspace. Set one with: sim configure --set-workspace <id>"));
|
|
14065
14036
|
}
|
|
14066
14037
|
}
|
|
14067
14038
|
function loginCommand() {
|
|
14068
|
-
return new Command("login").description("Sign in through the browser and store the login for the profile").
|
|
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) => {
|
|
14069
14040
|
const profile = profileFrom(command, { allowUnknownProfile: true });
|
|
14070
14041
|
const authProfile = resolveAuthenticationProfileName(profile.name);
|
|
14071
14042
|
if (authProfile !== profile.name) {
|
|
14072
14043
|
throw new SimApiError(`Profile "${redact(profile.name)}" shares authentication with "${redact(authProfile)}". Run: sim login --profile ${redact(authProfile)}`, 0);
|
|
14073
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;
|
|
14074
14049
|
const snapshot = readLoginProfileSnapshot(profile.name);
|
|
14075
14050
|
const storedCredential = snapshot.credential;
|
|
14076
14051
|
if (storedCredential?.kind === "oauth") {
|
|
@@ -14084,13 +14059,13 @@ function loginCommand() {
|
|
|
14084
14059
|
}
|
|
14085
14060
|
}
|
|
14086
14061
|
const callbackPort = parseCallbackPort(options.callbackPort);
|
|
14087
|
-
const loginFlow = await chooseLoginFlow(profile, options);
|
|
14062
|
+
const loginFlow = await chooseLoginFlow(profile, options, scope);
|
|
14088
14063
|
if (loginFlow === "handoff") {
|
|
14089
14064
|
if (options.readOnly) {
|
|
14090
|
-
throw new SimApiError("
|
|
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);
|
|
14091
14066
|
}
|
|
14092
14067
|
if (callbackPort !== undefined) {
|
|
14093
|
-
throw new SimApiError("
|
|
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);
|
|
14094
14069
|
}
|
|
14095
14070
|
}
|
|
14096
14071
|
await withProfileLoginLease(profile.name, async () => {
|
|
@@ -14099,13 +14074,13 @@ function loginCommand() {
|
|
|
14099
14074
|
await loginWithOAuth(profile, options, callbackPort, snapshot);
|
|
14100
14075
|
return;
|
|
14101
14076
|
}
|
|
14102
|
-
await loginWithHandoff(profile, options, snapshot);
|
|
14077
|
+
await loginWithHandoff(profile, options, scope, snapshot);
|
|
14103
14078
|
});
|
|
14104
14079
|
});
|
|
14105
14080
|
}
|
|
14106
|
-
async function loginWithHandoff(profile, options, expected) {
|
|
14081
|
+
async function loginWithHandoff(profile, options, scope, expected) {
|
|
14107
14082
|
const auth = createAuthRequest();
|
|
14108
|
-
const url = buildApprovalUrl(profile.endpoint, auth, profile.workspaceId ?? undefined);
|
|
14083
|
+
const url = buildApprovalUrl(profile.endpoint, auth, scope, profile.workspaceId ?? undefined);
|
|
14109
14084
|
console.log(`Signing in to ${source_default.bold(profile.endpoint)} as profile ${source_default.bold(safeOneLine(profile.name))}`);
|
|
14110
14085
|
console.log(`
|
|
14111
14086
|
Pairing code: ${source_default.bold(auth.pairing)}`);
|
|
@@ -14118,8 +14093,8 @@ Pairing code: ${source_default.bold(auth.pairing)}`);
|
|
|
14118
14093
|
Waiting for approval…`));
|
|
14119
14094
|
const key = await pollForKey(profile.endpoint, auth);
|
|
14120
14095
|
try {
|
|
14121
|
-
if (key.scope !==
|
|
14122
|
-
throw new SimApiError(`Server issued a ${key.scope} key
|
|
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);
|
|
14123
14098
|
}
|
|
14124
14099
|
const settings = {
|
|
14125
14100
|
endpoint: profile.endpoint,
|
|
@@ -14180,7 +14155,7 @@ async function revokeStoredOAuth(credential) {
|
|
|
14180
14155
|
await revokeToken(endpoint, credential.refreshToken);
|
|
14181
14156
|
console.log(source_default.dim(" Signed out of Sim; every token from this login was revoked."));
|
|
14182
14157
|
} catch (error) {
|
|
14183
|
-
console.log(source_default.yellow(` Could not revoke the login on ${displayEndpoint} (${safeOneLine(getErrorMessage(error))}). Revoke it in Settings →
|
|
14158
|
+
console.log(source_default.yellow(` Could not revoke the login on ${displayEndpoint} (${safeOneLine(getErrorMessage(error))}). Revoke it in Settings → Authorized apps.`));
|
|
14184
14159
|
}
|
|
14185
14160
|
}
|
|
14186
14161
|
function logoutCommand() {
|
|
@@ -16082,30 +16057,7 @@ function buildRequest(operation, positional, flags, workspaceId) {
|
|
|
16082
16057
|
}
|
|
16083
16058
|
|
|
16084
16059
|
// src/runtime/options.ts
|
|
16085
|
-
var
|
|
16086
|
-
var COMPLETE_LIST_OPERATIONS = new Set([
|
|
16087
|
-
"listBlocks",
|
|
16088
|
-
"listChatDeployments",
|
|
16089
|
-
"listCredentials",
|
|
16090
|
-
"listCustomTools",
|
|
16091
|
-
"listFiles",
|
|
16092
|
-
"listKnowledgeBases",
|
|
16093
|
-
"listKnowledgeConnectors",
|
|
16094
|
-
"listMcpServers",
|
|
16095
|
-
"listSandboxes",
|
|
16096
|
-
"listSecrets",
|
|
16097
|
-
"listSkillEditors",
|
|
16098
|
-
"listSkills",
|
|
16099
|
-
"listTables",
|
|
16100
|
-
"listTools",
|
|
16101
|
-
"listWorkflowMcpServers",
|
|
16102
|
-
"listWorkflows",
|
|
16103
|
-
"listWorkspaceMembers",
|
|
16104
|
-
"listWorkspaces"
|
|
16105
|
-
]);
|
|
16106
|
-
function defaultListLimit(operation) {
|
|
16107
|
-
return COMPLETE_LIST_OPERATIONS.has(operation) ? 0 : 100;
|
|
16108
|
-
}
|
|
16060
|
+
var DEFAULT_LIMIT = 100;
|
|
16109
16061
|
function describeField(flag, descriptor, name, field) {
|
|
16110
16062
|
return flag.describe ?? descriptor.describe ?? `Set ${name.replaceAll("-", " ") || field}`;
|
|
16111
16063
|
}
|
|
@@ -16118,21 +16070,15 @@ function withoutWireVocabulary(documented) {
|
|
|
16118
16070
|
}
|
|
16119
16071
|
var NON_PAGINATED_LIMIT_HINT = " (caps a --filter match only; omit it to act on every match, and note 0 is not accepted)";
|
|
16120
16072
|
function addFieldOption(command, operation, field, descriptor, slot, paginates, capsAFilter) {
|
|
16121
|
-
if (field === PROFILE_INJECTED_FIELD)
|
|
16122
|
-
return;
|
|
16123
|
-
if (field === "cursor") {
|
|
16124
|
-
if (paginates && defaultListLimit(operation) > 0) {
|
|
16125
|
-
command.option("--cursor <value>", "Continue from nextCursor returned by a previous result");
|
|
16126
|
-
}
|
|
16073
|
+
if (field === PROFILE_INJECTED_FIELD || field === "cursor")
|
|
16127
16074
|
return;
|
|
16128
|
-
}
|
|
16129
16075
|
const flag = flagSpecFor(operation, field);
|
|
16130
16076
|
if (flag.omit)
|
|
16131
16077
|
return;
|
|
16132
16078
|
const name = flagNameFor(operation, field);
|
|
16133
16079
|
const short = flag.short ? `-${flag.short}, ` : "";
|
|
16134
16080
|
if (paginates && field === "limit" && (descriptor.kind === "number" || descriptor.kind === "integer")) {
|
|
16135
|
-
command.option("--limit <n>", "Maximum items to return (0 for everything)", String(
|
|
16081
|
+
command.option("--limit <n>", "Maximum items to return (0 for everything)", String(DEFAULT_LIMIT));
|
|
16136
16082
|
return;
|
|
16137
16083
|
}
|
|
16138
16084
|
const documented = `${describeField(flag, descriptor, name, field)}${capsAFilter && field === "limit" && (descriptor.kind === "number" || descriptor.kind === "integer") ? NON_PAGINATED_LIMIT_HINT : ""}`;
|
|
@@ -16492,10 +16438,11 @@ function unwrapResource(data) {
|
|
|
16492
16438
|
const [, value] = entries[0];
|
|
16493
16439
|
return value && typeof value === "object" && !Array.isArray(value) ? value : data;
|
|
16494
16440
|
}
|
|
16495
|
-
function renderPage(format,
|
|
16441
|
+
function renderPage(format, rows, spec, envelope, options = {}) {
|
|
16496
16442
|
writePageNote(spec, envelope);
|
|
16497
16443
|
writeEnvelopeTruncation(envelope);
|
|
16498
|
-
|
|
16444
|
+
writeCursorTruncation(rows.length, options.truncated === true);
|
|
16445
|
+
printList(format, rows, spec.columns ? columnsFrom(spec.columns) : inferColumns(rows, spec.expand));
|
|
16499
16446
|
}
|
|
16500
16447
|
function writePageNote(spec, envelope) {
|
|
16501
16448
|
if (!spec.pageNote)
|
|
@@ -16540,6 +16487,12 @@ function writeEnvelopeTruncation(envelope) {
|
|
|
16540
16487
|
`));
|
|
16541
16488
|
}
|
|
16542
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
|
+
}
|
|
16543
16496
|
function renderResult(operation, format, raw, spec, options = {}, envelope) {
|
|
16544
16497
|
writeEnvelopeTruncation(envelope);
|
|
16545
16498
|
if (spec.document) {
|
|
@@ -16676,8 +16629,8 @@ function bulkFailureMessage(operation, payload, body) {
|
|
|
16676
16629
|
var EXCLUSIVE_CAP_FIELDS = {
|
|
16677
16630
|
deleteTableRows: { cap: "limit", ids: "rowIds" }
|
|
16678
16631
|
};
|
|
16679
|
-
function readPagedLimit(raw
|
|
16680
|
-
const text = String(raw ??
|
|
16632
|
+
function readPagedLimit(raw) {
|
|
16633
|
+
const text = String(raw ?? DEFAULT_LIMIT).trim();
|
|
16681
16634
|
const value = text === "" ? Number.NaN : Number(text);
|
|
16682
16635
|
if (!Number.isInteger(value) || value < 0) {
|
|
16683
16636
|
throw new SimApiError("--limit must be a whole number of 0 or more (0 for everything)", 0);
|
|
@@ -16752,33 +16705,24 @@ async function executeOperation(operation, commandSpec, operationSpec, invocatio
|
|
|
16752
16705
|
const omitsWorkspace = commandSpec.allWorkspaces && requestFlags.allWorkspaces === true;
|
|
16753
16706
|
const needsWorkspace = (hasWorkspaceField || commandSpec.profileWorkspacePath === true) && !omitsWorkspace;
|
|
16754
16707
|
const paging = cursorSlot(operationSpec);
|
|
16755
|
-
const pagedLimit = paging ? readPagedLimit(requestFlags.limit
|
|
16708
|
+
const pagedLimit = paging ? readPagedLimit(requestFlags.limit) : 0;
|
|
16756
16709
|
const request = buildRequest(operation, positional, requestFlags, needsWorkspace ? client.requireWorkspace() : profile.workspaceId);
|
|
16757
16710
|
if (paging) {
|
|
16758
|
-
const initialCursor = request[paging]?.cursor;
|
|
16759
|
-
if (initialCursor !== undefined && (typeof initialCursor !== "string" || initialCursor.trim() === "")) {
|
|
16760
|
-
throw new SimApiError("--cursor must be a non-empty string", 0);
|
|
16761
|
-
}
|
|
16762
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 } : {};
|
|
16763
16714
|
const rows = [];
|
|
16764
|
-
const seenCursors = new Set(initialCursor ? [initialCursor] : []);
|
|
16765
16715
|
const progress = pageProgress();
|
|
16766
|
-
let cursor =
|
|
16716
|
+
let cursor = null;
|
|
16767
16717
|
let envelope;
|
|
16768
16718
|
try {
|
|
16769
16719
|
do {
|
|
16770
|
-
const pageSize = Math.min(DEFAULT_PAGE_SIZE, limit - rows.length);
|
|
16771
|
-
const pageLimit = "limit" in (operationSpec[paging] ?? {}) ? { limit: pageSize } : {};
|
|
16772
16720
|
const page = await client.request(request.path, {
|
|
16773
16721
|
method: operationSpec.method,
|
|
16774
16722
|
headers: request.headers,
|
|
16775
16723
|
query: paging === "query" ? { ...request.query, ...pageLimit, cursor } : request.query,
|
|
16776
16724
|
body: paging === "body" ? { ...request.body ?? {}, ...pageLimit, ...cursor ? { cursor } : {} } : request.body
|
|
16777
16725
|
});
|
|
16778
|
-
if (page.data.length > pageSize) {
|
|
16779
|
-
throw new SimApiError(`The API returned ${page.data.length} items for a page limit of ${pageSize}; nextCursor would skip unreturned items.`, 0);
|
|
16780
|
-
}
|
|
16781
|
-
assertCursorAdvances(page.nextCursor, seenCursors);
|
|
16782
16726
|
envelope = foldPageEnvelope(envelope, page);
|
|
16783
16727
|
rows.push(...page.data);
|
|
16784
16728
|
cursor = page.nextCursor;
|
|
@@ -16788,7 +16732,7 @@ async function executeOperation(operation, commandSpec, operationSpec, invocatio
|
|
|
16788
16732
|
} finally {
|
|
16789
16733
|
progress.finish();
|
|
16790
16734
|
}
|
|
16791
|
-
renderPage(profile.output,
|
|
16735
|
+
renderPage(profile.output, Number.isFinite(limit) ? rows.slice(0, limit) : rows, commandSpec, envelope, { truncated: Boolean(cursor) });
|
|
16792
16736
|
return;
|
|
16793
16737
|
}
|
|
16794
16738
|
const result = await client.request(request.path, {
|
|
@@ -17296,47 +17240,6 @@ function attachCredentialCommands(program) {
|
|
|
17296
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 }));
|
|
17297
17241
|
}
|
|
17298
17242
|
|
|
17299
|
-
// src/http/ndjson.ts
|
|
17300
|
-
async function* readNdjson(body, protocol) {
|
|
17301
|
-
if (!body) {
|
|
17302
|
-
throw new SimApiError(`${protocol} ended without a response body`, 0);
|
|
17303
|
-
}
|
|
17304
|
-
const reader = body.getReader();
|
|
17305
|
-
const decoder = new TextDecoder;
|
|
17306
|
-
let buffer = "";
|
|
17307
|
-
const parse = (line) => {
|
|
17308
|
-
const trimmed = line.trim();
|
|
17309
|
-
if (!trimmed)
|
|
17310
|
-
return;
|
|
17311
|
-
try {
|
|
17312
|
-
return JSON.parse(trimmed);
|
|
17313
|
-
} catch {
|
|
17314
|
-
throw new SimApiError(`${protocol} returned malformed data`, 0);
|
|
17315
|
-
}
|
|
17316
|
-
};
|
|
17317
|
-
try {
|
|
17318
|
-
while (true) {
|
|
17319
|
-
const { done, value } = await reader.read();
|
|
17320
|
-
buffer += done ? decoder.decode() : decoder.decode(value, { stream: true });
|
|
17321
|
-
const lines = buffer.split(`
|
|
17322
|
-
`);
|
|
17323
|
-
buffer = done ? "" : lines.pop() ?? "";
|
|
17324
|
-
for (const line of lines) {
|
|
17325
|
-
const event = parse(line);
|
|
17326
|
-
if (event !== undefined)
|
|
17327
|
-
yield event;
|
|
17328
|
-
}
|
|
17329
|
-
if (done)
|
|
17330
|
-
return;
|
|
17331
|
-
}
|
|
17332
|
-
} finally {
|
|
17333
|
-
reader.cancel().catch(() => {
|
|
17334
|
-
return;
|
|
17335
|
-
});
|
|
17336
|
-
reader.releaseLock();
|
|
17337
|
-
}
|
|
17338
|
-
}
|
|
17339
|
-
|
|
17340
17243
|
// src/commands/protocol/result.ts
|
|
17341
17244
|
function printProtocolResult(format, result) {
|
|
17342
17245
|
const fields = Object.entries(result).map(([key, value]) => [key, text(value)]);
|
|
@@ -17344,28 +17247,72 @@ function printProtocolResult(format, result) {
|
|
|
17344
17247
|
}
|
|
17345
17248
|
|
|
17346
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
|
+
}
|
|
17347
17260
|
async function readChatStream(response, onChunk) {
|
|
17348
|
-
|
|
17349
|
-
|
|
17350
|
-
|
|
17351
|
-
|
|
17352
|
-
|
|
17353
|
-
|
|
17354
|
-
|
|
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;
|
|
17355
17272
|
if (event.type === "chunk") {
|
|
17356
17273
|
if (event.content)
|
|
17357
17274
|
onChunk(sanitize(event.content));
|
|
17358
|
-
|
|
17275
|
+
return false;
|
|
17359
17276
|
}
|
|
17360
17277
|
if (event.type === "error") {
|
|
17361
17278
|
throw new SimApiError(event.error || "Chat request failed", 0);
|
|
17362
17279
|
}
|
|
17363
17280
|
if (event.type === "final") {
|
|
17364
|
-
|
|
17281
|
+
finalResult = event.data;
|
|
17282
|
+
return true;
|
|
17365
17283
|
}
|
|
17366
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
|
+
});
|
|
17367
17315
|
}
|
|
17368
|
-
throw new SimApiError("Chat stream ended without a final result", 0);
|
|
17369
17316
|
}
|
|
17370
17317
|
function ignoreBrokenPipe(stream) {
|
|
17371
17318
|
const onError = (error) => {
|
|
@@ -18140,11 +18087,11 @@ async function listResources(client, config, workspaceId, folderPath, search, li
|
|
|
18140
18087
|
const paginated = "cursor" in V2_OPERATIONS[config.resources].query;
|
|
18141
18088
|
if (!paginated) {
|
|
18142
18089
|
const page = await client.request(path, { query });
|
|
18143
|
-
return page.data.slice(0, limit);
|
|
18090
|
+
return { items: page.data.slice(0, limit), truncated: page.data.length > limit };
|
|
18144
18091
|
}
|
|
18145
|
-
return
|
|
18092
|
+
return requestPages(client, path, {
|
|
18146
18093
|
query,
|
|
18147
|
-
pageSize:
|
|
18094
|
+
pageSize: DEFAULT_LIMIT,
|
|
18148
18095
|
limit
|
|
18149
18096
|
});
|
|
18150
18097
|
}
|
|
@@ -18174,7 +18121,7 @@ function entriesFor(config, folders, resources) {
|
|
|
18174
18121
|
].sort((left, right) => left.name.localeCompare(right.name) || left.kind.localeCompare(right.kind));
|
|
18175
18122
|
}
|
|
18176
18123
|
function attachResourceDirectoryCommands(group, config) {
|
|
18177
|
-
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(
|
|
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) => {
|
|
18178
18125
|
const rawLimit = Number(options.limit);
|
|
18179
18126
|
if (!Number.isSafeInteger(rawLimit) || rawLimit < 0) {
|
|
18180
18127
|
throw new SimApiError("--limit must be a whole number of 0 or more (0 for everything)", 0);
|
|
@@ -18187,8 +18134,9 @@ function attachResourceDirectoryCommands(group, config) {
|
|
|
18187
18134
|
listFolders(client, config.folders, workspaceId, folderPath, options.search),
|
|
18188
18135
|
listResources(client, config, workspaceId, folderPath, options.search, limit)
|
|
18189
18136
|
]);
|
|
18190
|
-
const entries = entriesFor(config, folders, resources);
|
|
18137
|
+
const entries = entriesFor(config, folders, resources.items);
|
|
18191
18138
|
const shown = entries.slice(0, limit);
|
|
18139
|
+
writeCursorTruncation(shown.length, resources.truncated || entries.length > limit);
|
|
18192
18140
|
printList(profile.output, shown, COLUMNS2);
|
|
18193
18141
|
});
|
|
18194
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) => {
|
|
@@ -18355,7 +18303,6 @@ function attachTableImport(tables) {
|
|
|
18355
18303
|
// src/commands/protocol/workflow-run-follow.ts
|
|
18356
18304
|
var AGENT_STREAM_PROTOCOL_HEADER = "x-sim-stream-protocol";
|
|
18357
18305
|
var AGENT_STREAM_PROTOCOL_V1 = "agent-events-v1";
|
|
18358
|
-
var WORKFLOW_RESULT_STREAM_CONTENT_TYPE = "application/x-ndjson";
|
|
18359
18306
|
var DONE_SENTINEL = "[DONE]";
|
|
18360
18307
|
function resolveWorkflowRunSelection(flags) {
|
|
18361
18308
|
const manual = flags.manual === true;
|
|
@@ -18407,59 +18354,6 @@ function stringField(frame, key) {
|
|
|
18407
18354
|
const value = frame[key];
|
|
18408
18355
|
return typeof value === "string" ? value : null;
|
|
18409
18356
|
}
|
|
18410
|
-
async function readWorkflowResult(response) {
|
|
18411
|
-
const contentType = (response.headers.get("content-type") ?? "").toLowerCase();
|
|
18412
|
-
if (!contentType.includes(WORKFLOW_RESULT_STREAM_CONTENT_TYPE)) {
|
|
18413
|
-
let envelope;
|
|
18414
|
-
try {
|
|
18415
|
-
envelope = await response.json();
|
|
18416
|
-
} catch {
|
|
18417
|
-
throw new SimApiError(`Workflow run returned malformed JSON${contentType ? ` as ${contentType}` : ""}`, response.status);
|
|
18418
|
-
}
|
|
18419
|
-
if (!isRecord(envelope)) {
|
|
18420
|
-
throw new SimApiError("Workflow run returned an invalid result envelope", response.status);
|
|
18421
|
-
}
|
|
18422
|
-
return isRecord(envelope.data) ? envelope.data : envelope;
|
|
18423
|
-
}
|
|
18424
|
-
for await (const value of readNdjson(response.body, "Workflow result stream")) {
|
|
18425
|
-
if (!isRecord(value) || typeof value.type !== "string") {
|
|
18426
|
-
throw new SimApiError("Workflow result stream returned an unknown event", response.status);
|
|
18427
|
-
}
|
|
18428
|
-
if (value.type === "heartbeat")
|
|
18429
|
-
continue;
|
|
18430
|
-
if (value.type === "error") {
|
|
18431
|
-
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);
|
|
18432
|
-
}
|
|
18433
|
-
if (value.type === "final" && isRecord(value.data))
|
|
18434
|
-
return value.data;
|
|
18435
|
-
throw new SimApiError("Workflow result stream returned an unknown event", response.status);
|
|
18436
|
-
}
|
|
18437
|
-
throw new SimApiError("Workflow result stream ended without a final result", response.status);
|
|
18438
|
-
}
|
|
18439
|
-
async function runWithResultStream(workflowId, command) {
|
|
18440
|
-
const flags = command.optsWithGlobals();
|
|
18441
|
-
const { client, profile } = clientFrom(command);
|
|
18442
|
-
const operation = V2_OPERATIONS.executeWorkflow;
|
|
18443
|
-
const commandSpec = CLI_CONTRACT.executeWorkflow ?? {};
|
|
18444
|
-
try {
|
|
18445
|
-
const request = buildRequest("executeWorkflow", [workflowId], flags, profile.workspaceId);
|
|
18446
|
-
const response = await client.requestRaw(request.path, {
|
|
18447
|
-
method: operation.method,
|
|
18448
|
-
query: request.query,
|
|
18449
|
-
body: request.body,
|
|
18450
|
-
headers: { ...request.headers, accept: WORKFLOW_RESULT_STREAM_CONTENT_TYPE }
|
|
18451
|
-
});
|
|
18452
|
-
const payload = await readWorkflowResult(response);
|
|
18453
|
-
renderResult("executeWorkflow", profile.output, payload, commandSpec, {
|
|
18454
|
-
expandedTrace: flags.trace === true
|
|
18455
|
-
});
|
|
18456
|
-
const failure = runFailureMessage("executeWorkflow", payload);
|
|
18457
|
-
if (failure)
|
|
18458
|
-
throw new SimApiError(failure, 0);
|
|
18459
|
-
} catch (error) {
|
|
18460
|
-
throw retypeApiError(error, "executeWorkflow", commandSpec, operation);
|
|
18461
|
-
}
|
|
18462
|
-
}
|
|
18463
18357
|
async function* sseData(body) {
|
|
18464
18358
|
const reader = body.getReader();
|
|
18465
18359
|
const decoder = new TextDecoder;
|
|
@@ -18631,10 +18525,6 @@ function followOrDelegate(previous) {
|
|
|
18631
18525
|
if (flags.includeThinking === true || flags.includeToolCalls === true) {
|
|
18632
18526
|
throw new SimApiError("--include-thinking and --include-tool-calls describe a stream; add --follow", 0);
|
|
18633
18527
|
}
|
|
18634
|
-
if (flags.async !== true) {
|
|
18635
|
-
await runWithResultStream(workflowId, command);
|
|
18636
|
-
return;
|
|
18637
|
-
}
|
|
18638
18528
|
if (previous) {
|
|
18639
18529
|
await previous(command.processedArgs);
|
|
18640
18530
|
return;
|