sim 2.1.1-preview.41.1 → 2.1.1-preview.43.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 +91 -22
- package/dist/index.js +752 -140
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -538,7 +538,7 @@ var require_option = __commonJS((exports) => {
|
|
|
538
538
|
// ../../node_modules/commander/lib/suggestSimilar.js
|
|
539
539
|
var require_suggestSimilar = __commonJS((exports) => {
|
|
540
540
|
var maxDistance = 3;
|
|
541
|
-
function
|
|
541
|
+
function editDistance2(a, b) {
|
|
542
542
|
if (Math.abs(a.length - b.length) > maxDistance)
|
|
543
543
|
return Math.max(a.length, b.length);
|
|
544
544
|
const d = [];
|
|
@@ -579,7 +579,7 @@ var require_suggestSimilar = __commonJS((exports) => {
|
|
|
579
579
|
candidates.forEach((candidate) => {
|
|
580
580
|
if (candidate.length <= 1)
|
|
581
581
|
return;
|
|
582
|
-
const distance =
|
|
582
|
+
const distance = editDistance2(word, candidate);
|
|
583
583
|
const length = Math.max(word.length, candidate.length);
|
|
584
584
|
const similarity = (length - distance) / length;
|
|
585
585
|
if (similarity > minSimilarity) {
|
|
@@ -2320,8 +2320,11 @@ var KV_PATTERN = /^\s*([A-Za-z0-9_.-]+)\s*=\s*(.*?)\s*$/;
|
|
|
2320
2320
|
function parseIni(text) {
|
|
2321
2321
|
const doc = { preamble: [], sections: [] };
|
|
2322
2322
|
let current = null;
|
|
2323
|
-
|
|
2324
|
-
`)
|
|
2323
|
+
const lines = text.split(`
|
|
2324
|
+
`);
|
|
2325
|
+
if (lines.length > 1 && lines[lines.length - 1] === "")
|
|
2326
|
+
lines.pop();
|
|
2327
|
+
for (const line of lines) {
|
|
2325
2328
|
const sectionMatch = SECTION_PATTERN.exec(line);
|
|
2326
2329
|
if (sectionMatch) {
|
|
2327
2330
|
current = { name: sectionMatch[1].trim(), entries: [] };
|
|
@@ -2360,13 +2363,15 @@ function serializeIni(doc) {
|
|
|
2360
2363
|
` : "";
|
|
2361
2364
|
}
|
|
2362
2365
|
function getSection(doc, name) {
|
|
2363
|
-
const
|
|
2364
|
-
if (
|
|
2366
|
+
const sections = doc.sections.filter((s) => s.name === name);
|
|
2367
|
+
if (sections.length === 0)
|
|
2365
2368
|
return null;
|
|
2366
2369
|
const values = {};
|
|
2367
|
-
for (const
|
|
2368
|
-
|
|
2369
|
-
|
|
2370
|
+
for (const section of sections) {
|
|
2371
|
+
for (const entry of section.entries) {
|
|
2372
|
+
if (entry.kind === "kv" && !Object.hasOwn(values, entry.key))
|
|
2373
|
+
values[entry.key] = entry.value;
|
|
2374
|
+
}
|
|
2370
2375
|
}
|
|
2371
2376
|
return values;
|
|
2372
2377
|
}
|
|
@@ -2374,18 +2379,21 @@ function listSections(doc) {
|
|
|
2374
2379
|
return doc.sections.map((s) => s.name);
|
|
2375
2380
|
}
|
|
2376
2381
|
function setSectionValues(doc, name, values) {
|
|
2377
|
-
|
|
2382
|
+
const matching = doc.sections.filter((s) => s.name === name);
|
|
2383
|
+
let section = matching[0];
|
|
2378
2384
|
if (!section) {
|
|
2379
2385
|
section = { name, entries: [] };
|
|
2380
2386
|
doc.sections.push(section);
|
|
2387
|
+
matching.push(section);
|
|
2381
2388
|
}
|
|
2382
2389
|
for (const [key, value] of Object.entries(values)) {
|
|
2383
|
-
const index = section.entries.findIndex((e) => e.kind === "kv" && e.key === key);
|
|
2384
2390
|
if (value === null) {
|
|
2385
|
-
|
|
2386
|
-
|
|
2391
|
+
for (const target of matching) {
|
|
2392
|
+
target.entries = target.entries.filter((e) => !(e.kind === "kv" && e.key === key));
|
|
2393
|
+
}
|
|
2387
2394
|
continue;
|
|
2388
2395
|
}
|
|
2396
|
+
const index = section.entries.findIndex((e) => e.kind === "kv" && e.key === key);
|
|
2389
2397
|
if (index === -1) {
|
|
2390
2398
|
section.entries.push({ kind: "kv", key, value });
|
|
2391
2399
|
} else {
|
|
@@ -2394,10 +2402,10 @@ function setSectionValues(doc, name, values) {
|
|
|
2394
2402
|
}
|
|
2395
2403
|
}
|
|
2396
2404
|
function removeSection(doc, name) {
|
|
2397
|
-
const
|
|
2398
|
-
if (
|
|
2405
|
+
const remaining = doc.sections.filter((s) => s.name !== name);
|
|
2406
|
+
if (remaining.length === doc.sections.length)
|
|
2399
2407
|
return false;
|
|
2400
|
-
doc.sections
|
|
2408
|
+
doc.sections = remaining;
|
|
2401
2409
|
return true;
|
|
2402
2410
|
}
|
|
2403
2411
|
|
|
@@ -2472,6 +2480,42 @@ function listProfiles() {
|
|
|
2472
2480
|
}
|
|
2473
2481
|
return [...names].sort();
|
|
2474
2482
|
}
|
|
2483
|
+
function editDistance(a, b) {
|
|
2484
|
+
let previous = Array.from({ length: b.length + 1 }, (_, index) => index);
|
|
2485
|
+
for (let i = 1;i <= a.length; i++) {
|
|
2486
|
+
const current = [i];
|
|
2487
|
+
for (let j = 1;j <= b.length; j++) {
|
|
2488
|
+
current[j] = Math.min(previous[j] + 1, current[j - 1] + 1, previous[j - 1] + (a[i - 1] === b[j - 1] ? 0 : 1));
|
|
2489
|
+
}
|
|
2490
|
+
previous = current;
|
|
2491
|
+
}
|
|
2492
|
+
return previous[b.length];
|
|
2493
|
+
}
|
|
2494
|
+
function nearestProfile(name, known) {
|
|
2495
|
+
const lowered = name.toLowerCase();
|
|
2496
|
+
let best = null;
|
|
2497
|
+
let bestDistance = Number.POSITIVE_INFINITY;
|
|
2498
|
+
for (const candidate of known) {
|
|
2499
|
+
const distance = editDistance(lowered, candidate.toLowerCase());
|
|
2500
|
+
if (distance < bestDistance) {
|
|
2501
|
+
best = candidate;
|
|
2502
|
+
bestDistance = distance;
|
|
2503
|
+
}
|
|
2504
|
+
}
|
|
2505
|
+
return bestDistance <= 2 ? best : null;
|
|
2506
|
+
}
|
|
2507
|
+
function requireKnownProfile(name) {
|
|
2508
|
+
if (name === DEFAULT_PROFILE)
|
|
2509
|
+
return;
|
|
2510
|
+
const known = listProfiles();
|
|
2511
|
+
if (known.includes(name))
|
|
2512
|
+
return;
|
|
2513
|
+
if (known.length === 0) {
|
|
2514
|
+
throw new ProfileConfigError(`Unknown profile "${name}". No profiles are configured yet. Run: sim login --profile ${name}`);
|
|
2515
|
+
}
|
|
2516
|
+
const suggestion = nearestProfile(name, known);
|
|
2517
|
+
throw new ProfileConfigError(`Unknown profile "${name}".${suggestion ? ` Did you mean "${suggestion}"?` : ""} Configured profiles: ${known.join(", ")}.`);
|
|
2518
|
+
}
|
|
2475
2519
|
function listAuthenticationDependents(authProfile) {
|
|
2476
2520
|
return listProfiles().filter((profile) => profile !== authProfile && readConfigProfile(profile).auth_profile?.trim() === authProfile);
|
|
2477
2521
|
}
|
|
@@ -2517,7 +2561,10 @@ function resolve(candidates, fallback, fallbackSource) {
|
|
|
2517
2561
|
return { value: fallback, source: fallbackSource };
|
|
2518
2562
|
}
|
|
2519
2563
|
function resolveProfile(overrides = {}) {
|
|
2520
|
-
const
|
|
2564
|
+
const named = overrides.profile || process.env.SIM_PROFILE;
|
|
2565
|
+
const name = named || DEFAULT_PROFILE;
|
|
2566
|
+
if (named && !overrides.allowUnknownProfile)
|
|
2567
|
+
requireKnownProfile(named);
|
|
2521
2568
|
const config = readConfigProfile(name);
|
|
2522
2569
|
const authProfile = resolveAuthenticationProfileName(name);
|
|
2523
2570
|
const authConfig = authProfile === name ? config : readConfigProfile(authProfile);
|
|
@@ -6284,6 +6331,7 @@ var POLL_TIMEOUT_MS = 15 * 60 * 1000;
|
|
|
6284
6331
|
var APPROVAL_PATH = "/cli/auth";
|
|
6285
6332
|
var POLL_PATH = "/api/cli/auth/poll";
|
|
6286
6333
|
var RETRYABLE_POLL_STATUSES = new Set([409, 429, 500, 502, 503, 504]);
|
|
6334
|
+
var TRANSPORT_FAILURES_BEFORE_WARNING = 3;
|
|
6287
6335
|
function token() {
|
|
6288
6336
|
return randomBytes(32).toString("base64url");
|
|
6289
6337
|
}
|
|
@@ -6328,6 +6376,8 @@ function toRedirectError(endpoint, response) {
|
|
|
6328
6376
|
}
|
|
6329
6377
|
async function pollForKey(endpoint, auth, signal) {
|
|
6330
6378
|
const deadline = Date.now() + POLL_TIMEOUT_MS;
|
|
6379
|
+
let consecutiveTransportFailures = 0;
|
|
6380
|
+
let warnedAboutTransport = false;
|
|
6331
6381
|
while (Date.now() < deadline) {
|
|
6332
6382
|
if (signal?.aborted)
|
|
6333
6383
|
throw new SimApiError("Login cancelled.", 0);
|
|
@@ -6344,10 +6394,17 @@ async function pollForKey(endpoint, auth, signal) {
|
|
|
6344
6394
|
signal,
|
|
6345
6395
|
redirect: "manual"
|
|
6346
6396
|
});
|
|
6347
|
-
} catch {
|
|
6397
|
+
} catch (cause) {
|
|
6348
6398
|
response = null;
|
|
6399
|
+
consecutiveTransportFailures++;
|
|
6400
|
+
if (!warnedAboutTransport && consecutiveTransportFailures >= TRANSPORT_FAILURES_BEFORE_WARNING) {
|
|
6401
|
+
warnedAboutTransport = true;
|
|
6402
|
+
process.stderr.write(`Still waiting: ${endpoint} is not answering the login poll (${cause.message}). Check the endpoint; retrying until you approve or the login times out.
|
|
6403
|
+
`);
|
|
6404
|
+
}
|
|
6349
6405
|
}
|
|
6350
6406
|
if (response) {
|
|
6407
|
+
consecutiveTransportFailures = 0;
|
|
6351
6408
|
if (REDIRECT_STATUSES.has(response.status))
|
|
6352
6409
|
throw toRedirectError(endpoint, response);
|
|
6353
6410
|
const raw = await response.text();
|
|
@@ -6418,6 +6475,13 @@ var V2_OPERATIONS = {
|
|
|
6418
6475
|
required: true,
|
|
6419
6476
|
describe: "Workspace that owns the upload session."
|
|
6420
6477
|
}
|
|
6478
|
+
},
|
|
6479
|
+
headers: {
|
|
6480
|
+
"upload-token": {
|
|
6481
|
+
kind: "string",
|
|
6482
|
+
required: true,
|
|
6483
|
+
describe: "Signed upload control token returned when the upload session was created."
|
|
6484
|
+
}
|
|
6421
6485
|
}
|
|
6422
6486
|
},
|
|
6423
6487
|
abortKnowledgeDocumentUpload: {
|
|
@@ -6436,6 +6500,13 @@ var V2_OPERATIONS = {
|
|
|
6436
6500
|
required: true,
|
|
6437
6501
|
describe: "Workspace that owns the knowledge base."
|
|
6438
6502
|
}
|
|
6503
|
+
},
|
|
6504
|
+
headers: {
|
|
6505
|
+
"upload-token": {
|
|
6506
|
+
kind: "string",
|
|
6507
|
+
required: true,
|
|
6508
|
+
describe: "Signed upload control token returned when the upload session was created."
|
|
6509
|
+
}
|
|
6439
6510
|
}
|
|
6440
6511
|
},
|
|
6441
6512
|
activateWorkflowVersion: {
|
|
@@ -6751,6 +6822,12 @@ var V2_OPERATIONS = {
|
|
|
6751
6822
|
required: true,
|
|
6752
6823
|
describe: "Workspace that owns the transfer resource."
|
|
6753
6824
|
}
|
|
6825
|
+
},
|
|
6826
|
+
headers: {
|
|
6827
|
+
"upload-token": {
|
|
6828
|
+
kind: "string",
|
|
6829
|
+
describe: "Signed upload control token returned when an upload-backed import was created."
|
|
6830
|
+
}
|
|
6754
6831
|
}
|
|
6755
6832
|
},
|
|
6756
6833
|
cancelTableRuns: {
|
|
@@ -6818,6 +6895,13 @@ var V2_OPERATIONS = {
|
|
|
6818
6895
|
required: true,
|
|
6819
6896
|
describe: "Workspace that owns the upload session."
|
|
6820
6897
|
}
|
|
6898
|
+
},
|
|
6899
|
+
headers: {
|
|
6900
|
+
"upload-token": {
|
|
6901
|
+
kind: "string",
|
|
6902
|
+
required: true,
|
|
6903
|
+
describe: "Signed upload control token returned when the upload session was created."
|
|
6904
|
+
}
|
|
6821
6905
|
}
|
|
6822
6906
|
},
|
|
6823
6907
|
completeKnowledgeDocumentUpload: {
|
|
@@ -6836,6 +6920,13 @@ var V2_OPERATIONS = {
|
|
|
6836
6920
|
required: true,
|
|
6837
6921
|
describe: "Workspace that owns the knowledge base."
|
|
6838
6922
|
}
|
|
6923
|
+
},
|
|
6924
|
+
headers: {
|
|
6925
|
+
"upload-token": {
|
|
6926
|
+
kind: "string",
|
|
6927
|
+
required: true,
|
|
6928
|
+
describe: "Signed upload control token returned when the upload session was created."
|
|
6929
|
+
}
|
|
6839
6930
|
}
|
|
6840
6931
|
},
|
|
6841
6932
|
completeTableImport: {
|
|
@@ -6851,6 +6942,13 @@ var V2_OPERATIONS = {
|
|
|
6851
6942
|
required: true,
|
|
6852
6943
|
describe: "Workspace that owns the transfer resource."
|
|
6853
6944
|
}
|
|
6945
|
+
},
|
|
6946
|
+
headers: {
|
|
6947
|
+
"upload-token": {
|
|
6948
|
+
kind: "string",
|
|
6949
|
+
required: true,
|
|
6950
|
+
describe: "Signed upload control token returned when the upload session was created."
|
|
6951
|
+
}
|
|
6854
6952
|
}
|
|
6855
6953
|
},
|
|
6856
6954
|
createCredentialConnection: {
|
|
@@ -6991,6 +7089,13 @@ var V2_OPERATIONS = {
|
|
|
6991
7089
|
required: true,
|
|
6992
7090
|
describe: "Multipart part numbers for which signed URLs should be created."
|
|
6993
7091
|
}
|
|
7092
|
+
},
|
|
7093
|
+
headers: {
|
|
7094
|
+
"upload-token": {
|
|
7095
|
+
kind: "string",
|
|
7096
|
+
required: true,
|
|
7097
|
+
describe: "Signed upload control token returned when the upload session was created."
|
|
7098
|
+
}
|
|
6994
7099
|
}
|
|
6995
7100
|
},
|
|
6996
7101
|
createKnowledgeBase: {
|
|
@@ -7136,6 +7241,13 @@ var V2_OPERATIONS = {
|
|
|
7136
7241
|
required: true,
|
|
7137
7242
|
describe: "Multipart part numbers for which signed URLs should be created."
|
|
7138
7243
|
}
|
|
7244
|
+
},
|
|
7245
|
+
headers: {
|
|
7246
|
+
"upload-token": {
|
|
7247
|
+
kind: "string",
|
|
7248
|
+
required: true,
|
|
7249
|
+
describe: "Signed upload control token returned when the upload session was created."
|
|
7250
|
+
}
|
|
7139
7251
|
}
|
|
7140
7252
|
},
|
|
7141
7253
|
createKnowledgeFolder: {
|
|
@@ -7441,6 +7553,13 @@ var V2_OPERATIONS = {
|
|
|
7441
7553
|
required: true,
|
|
7442
7554
|
describe: "Multipart part numbers for which signed URLs should be created."
|
|
7443
7555
|
}
|
|
7556
|
+
},
|
|
7557
|
+
headers: {
|
|
7558
|
+
"upload-token": {
|
|
7559
|
+
kind: "string",
|
|
7560
|
+
required: true,
|
|
7561
|
+
describe: "Signed upload control token returned when the upload session was created."
|
|
7562
|
+
}
|
|
7444
7563
|
}
|
|
7445
7564
|
},
|
|
7446
7565
|
createTableRows: {
|
|
@@ -7540,7 +7659,7 @@ var V2_OPERATIONS = {
|
|
|
7540
7659
|
method: "DELETE",
|
|
7541
7660
|
path: "/api/v2/credentials/[credentialId]",
|
|
7542
7661
|
pathParams: ["credentialId"],
|
|
7543
|
-
pathParamDocs: { credentialId: "Credential to
|
|
7662
|
+
pathParamDocs: { credentialId: "Credential to disconnect." },
|
|
7544
7663
|
responseMode: "json",
|
|
7545
7664
|
summary: "Disconnect Credential",
|
|
7546
7665
|
query: {
|
|
@@ -8070,7 +8189,7 @@ var V2_OPERATIONS = {
|
|
|
8070
8189
|
},
|
|
8071
8190
|
selectedOutputs: {
|
|
8072
8191
|
kind: "array",
|
|
8073
|
-
describe: "Block output references to include in a streamed response.
|
|
8192
|
+
describe: "Block output references to include in a streamed response, as `blockId`, `blockId.path`, or `BlockName.path` (resolved against the live workflow). 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."
|
|
8074
8193
|
},
|
|
8075
8194
|
includeThinking: {
|
|
8076
8195
|
kind: "boolean",
|
|
@@ -8090,6 +8209,16 @@ var V2_OPERATIONS = {
|
|
|
8090
8209
|
kind: "integer",
|
|
8091
8210
|
describe: "Maximum total bytes of file content to inline as base64, lowering but never raising the server limit of 16 MiB. Rejected when `async` is true."
|
|
8092
8211
|
}
|
|
8212
|
+
},
|
|
8213
|
+
headers: {
|
|
8214
|
+
"x-run-id": {
|
|
8215
|
+
kind: "string",
|
|
8216
|
+
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.'
|
|
8217
|
+
},
|
|
8218
|
+
"x-sim-via": {
|
|
8219
|
+
kind: "string",
|
|
8220
|
+
describe: 'Comma-separated workflow identifiers naming the workflow-to-workflow call chain that led to this request. Each hop appends its own workflow id, and Sim sets it automatically; supply it yourself only when relaying an existing chain. A chain at the maximum depth is rejected with `409` and `error.details.code: "CALL_CHAIN_DEPTH_EXCEEDED"`.'
|
|
8221
|
+
}
|
|
8093
8222
|
}
|
|
8094
8223
|
},
|
|
8095
8224
|
exportWorkflow: {
|
|
@@ -8110,8 +8239,7 @@ var V2_OPERATIONS = {
|
|
|
8110
8239
|
query: {
|
|
8111
8240
|
organizationId: {
|
|
8112
8241
|
kind: "string",
|
|
8113
|
-
|
|
8114
|
-
describe: "Organization whose audit-log entry should be returned."
|
|
8242
|
+
describe: "Organization whose audit-log entry should be returned. Defaults to the caller's own organization when omitted. A caller that belongs to no organization, or that names one it is not a member of, is refused with a 403."
|
|
8115
8243
|
}
|
|
8116
8244
|
}
|
|
8117
8245
|
},
|
|
@@ -8201,6 +8329,13 @@ var V2_OPERATIONS = {
|
|
|
8201
8329
|
required: true,
|
|
8202
8330
|
describe: "Workspace that owns the upload session."
|
|
8203
8331
|
}
|
|
8332
|
+
},
|
|
8333
|
+
headers: {
|
|
8334
|
+
"upload-token": {
|
|
8335
|
+
kind: "string",
|
|
8336
|
+
required: true,
|
|
8337
|
+
describe: "Signed upload control token returned when the upload session was created."
|
|
8338
|
+
}
|
|
8204
8339
|
}
|
|
8205
8340
|
},
|
|
8206
8341
|
getKnowledgeBase: {
|
|
@@ -8456,6 +8591,12 @@ var V2_OPERATIONS = {
|
|
|
8456
8591
|
required: true,
|
|
8457
8592
|
describe: "Workspace that owns the transfer resource."
|
|
8458
8593
|
}
|
|
8594
|
+
},
|
|
8595
|
+
headers: {
|
|
8596
|
+
"upload-token": {
|
|
8597
|
+
kind: "string",
|
|
8598
|
+
describe: "Signed upload control token returned when an upload-backed import was created."
|
|
8599
|
+
}
|
|
8459
8600
|
}
|
|
8460
8601
|
},
|
|
8461
8602
|
getTableRow: {
|
|
@@ -8550,7 +8691,7 @@ var V2_OPERATIONS = {
|
|
|
8550
8691
|
},
|
|
8551
8692
|
selectedOutputs: {
|
|
8552
8693
|
kind: "string",
|
|
8553
|
-
describe: "Comma-separated block output references to include, as `blockId` or `blockId.path`. Block *names* are not resolved here — unlike the execute request, this resource reads a recorded run and matches ids only, so a
|
|
8694
|
+
describe: "Comma-separated block output references to include, as `blockId` or `blockId.path`. Block *names* are not resolved here — unlike the execute request, this resource reads a recorded run and matches ids only, so a selector that is not headed by a block id answers `400` instead of an empty `blockOutputs`."
|
|
8554
8695
|
},
|
|
8555
8696
|
includeFileBase64: {
|
|
8556
8697
|
kind: "boolean",
|
|
@@ -8669,8 +8810,7 @@ var V2_OPERATIONS = {
|
|
|
8669
8810
|
},
|
|
8670
8811
|
organizationId: {
|
|
8671
8812
|
kind: "string",
|
|
8672
|
-
|
|
8673
|
-
describe: "Organization whose audit trail should be queried."
|
|
8813
|
+
describe: "Organization whose audit trail should be queried. Defaults to the caller's own organization when omitted. A caller that belongs to no organization, or that names one it is not a member of, is refused with a 403."
|
|
8674
8814
|
},
|
|
8675
8815
|
actorEmail: { kind: "string", describe: "Filter by actor email address." }
|
|
8676
8816
|
}
|
|
@@ -8699,7 +8839,7 @@ var V2_OPERATIONS = {
|
|
|
8699
8839
|
},
|
|
8700
8840
|
workspaceId: {
|
|
8701
8841
|
kind: "string",
|
|
8702
|
-
describe: "
|
|
8842
|
+
describe: "Narrow the ledger to usage events attributed to one workspace. It does not change whose events are reported — a personal API key always reports the usage of the person holding it, and a workspace API key always reports its own workspace's complete ledger across every member. The response `scope` field says which of the two you received. A workspace API key is pinned to its own workspace: any other id answers `404 Workspace not found`, which is also what an id that does not exist answers."
|
|
8703
8843
|
},
|
|
8704
8844
|
period: {
|
|
8705
8845
|
kind: "enum",
|
|
@@ -10648,7 +10788,7 @@ var V2_OPERATIONS = {
|
|
|
10648
10788
|
method: "PATCH",
|
|
10649
10789
|
path: "/api/v2/credentials/[credentialId]",
|
|
10650
10790
|
pathParams: ["credentialId"],
|
|
10651
|
-
pathParamDocs: { credentialId: "Credential to update
|
|
10791
|
+
pathParamDocs: { credentialId: "Credential to update." },
|
|
10652
10792
|
responseMode: "json",
|
|
10653
10793
|
summary: "Update Credential",
|
|
10654
10794
|
query: {
|
|
@@ -11346,7 +11486,7 @@ function addProfileCommand() {
|
|
|
11346
11486
|
}
|
|
11347
11487
|
function loginCommand() {
|
|
11348
11488
|
return new Command("login").description("Authorize this terminal and store an API key for the profile").option("--scope <scope>", "Key space to mint from: platform or copilot", "platform").option("--no-browser", "Print the URL instead of opening a browser").option("-y, --yes", "Overwrite an existing profile without prompting").action(async (options, command) => {
|
|
11349
|
-
const profile = profileFrom(command);
|
|
11489
|
+
const profile = profileFrom(command, { allowUnknownProfile: true });
|
|
11350
11490
|
const authProfile = resolveAuthenticationProfileName(profile.name);
|
|
11351
11491
|
if (authProfile !== profile.name) {
|
|
11352
11492
|
throw new SimApiError(`Profile "${profile.name}" shares authentication with "${authProfile}". Run: sim login --profile ${authProfile}`, 0);
|
|
@@ -11425,6 +11565,17 @@ function logoutCommand() {
|
|
|
11425
11565
|
console.log(source_default.dim(" The key itself is still active — revoke it in Settings → API keys."));
|
|
11426
11566
|
});
|
|
11427
11567
|
}
|
|
11568
|
+
async function readKeyType(client) {
|
|
11569
|
+
const operation = V2_OPERATIONS.getMeta;
|
|
11570
|
+
try {
|
|
11571
|
+
const response = await client.request(operation.path, {
|
|
11572
|
+
method: operation.method
|
|
11573
|
+
});
|
|
11574
|
+
return response.data.keyType;
|
|
11575
|
+
} catch {
|
|
11576
|
+
return null;
|
|
11577
|
+
}
|
|
11578
|
+
}
|
|
11428
11579
|
var CREDENTIAL_VERDICT_STATUSES = new Set([401, 403, 404]);
|
|
11429
11580
|
var WHOAMI_EXIT_CODES = {
|
|
11430
11581
|
verified: 0,
|
|
@@ -11439,13 +11590,16 @@ async function verifyProfile(client, profile) {
|
|
|
11439
11590
|
return {
|
|
11440
11591
|
status: "unauthenticated",
|
|
11441
11592
|
workspace: null,
|
|
11593
|
+
keyType: null,
|
|
11442
11594
|
detail: `no API key — run: sim login --profile ${profile.name}`
|
|
11443
11595
|
};
|
|
11444
11596
|
}
|
|
11597
|
+
const keyType = await readKeyType(client);
|
|
11445
11598
|
if (!profile.workspaceId) {
|
|
11446
11599
|
return {
|
|
11447
11600
|
status: "no-workspace",
|
|
11448
11601
|
workspace: null,
|
|
11602
|
+
keyType,
|
|
11449
11603
|
detail: `no workspace to check against — run: sim configure --profile ${profile.name} --set-workspace <id>`
|
|
11450
11604
|
};
|
|
11451
11605
|
}
|
|
@@ -11453,13 +11607,14 @@ async function verifyProfile(client, profile) {
|
|
|
11453
11607
|
try {
|
|
11454
11608
|
const response = await client.request(resolvePath(operation.path, { workspaceId: profile.workspaceId }), { method: operation.method });
|
|
11455
11609
|
const { id, name, memberCount } = response.data;
|
|
11456
|
-
return { status: "verified", workspace: { id, name, memberCount }, detail: null };
|
|
11610
|
+
return { status: "verified", workspace: { id, name, memberCount }, keyType, detail: null };
|
|
11457
11611
|
} catch (error) {
|
|
11458
11612
|
if (!(error instanceof SimApiError))
|
|
11459
11613
|
throw error;
|
|
11460
11614
|
return {
|
|
11461
11615
|
status: CREDENTIAL_VERDICT_STATUSES.has(error.status) ? "rejected" : "unreachable",
|
|
11462
11616
|
workspace: null,
|
|
11617
|
+
keyType,
|
|
11463
11618
|
detail: error.message
|
|
11464
11619
|
};
|
|
11465
11620
|
}
|
|
@@ -11487,7 +11642,12 @@ function whoamiCommand() {
|
|
|
11487
11642
|
const { client, profile } = clientFrom(command);
|
|
11488
11643
|
const { sources } = profile;
|
|
11489
11644
|
const authentication = presentAuthentication(sources.apiKey);
|
|
11490
|
-
const verification = options.verify ? await verifyProfile(client, profile) : {
|
|
11645
|
+
const verification = options.verify ? await verifyProfile(client, profile) : {
|
|
11646
|
+
status: "disabled",
|
|
11647
|
+
workspace: null,
|
|
11648
|
+
keyType: null,
|
|
11649
|
+
detail: "not checked (--no-verify)"
|
|
11650
|
+
};
|
|
11491
11651
|
const annotate = (value, source) => source === "unset" ? source_default.dim("not set") : `${value} ${source_default.dim(`(${source})`)}`;
|
|
11492
11652
|
printRecord(profile.output, [
|
|
11493
11653
|
["Profile", profile.name],
|
|
@@ -11496,6 +11656,10 @@ function whoamiCommand() {
|
|
|
11496
11656
|
"API key",
|
|
11497
11657
|
authentication.authenticated ? annotate("configured", authentication.source) : source_default.yellow("not logged in")
|
|
11498
11658
|
],
|
|
11659
|
+
[
|
|
11660
|
+
"Key type",
|
|
11661
|
+
verification.keyType ?? source_default.dim(options.verify ? "unknown" : "not checked (--no-verify)")
|
|
11662
|
+
],
|
|
11499
11663
|
["Workspace", annotate(profile.workspaceId ?? "", sources.workspaceId)],
|
|
11500
11664
|
["Output", annotate(profile.output, sources.output)],
|
|
11501
11665
|
["Verified", presentVerification(verification)]
|
|
@@ -11514,6 +11678,7 @@ function whoamiCommand() {
|
|
|
11514
11678
|
verification: {
|
|
11515
11679
|
status: verification.status,
|
|
11516
11680
|
workspace: verification.workspace,
|
|
11681
|
+
keyType: verification.keyType,
|
|
11517
11682
|
detail: verification.detail
|
|
11518
11683
|
}
|
|
11519
11684
|
});
|
|
@@ -11533,7 +11698,15 @@ function profilesCommand() {
|
|
|
11533
11698
|
const active = selectedProfileName(actionCommand);
|
|
11534
11699
|
for (const name of profiles) {
|
|
11535
11700
|
const marker = name === active ? source_default.green("*") : " ";
|
|
11536
|
-
|
|
11701
|
+
let authProfile;
|
|
11702
|
+
try {
|
|
11703
|
+
authProfile = resolveAuthenticationProfileName(name);
|
|
11704
|
+
} catch (error) {
|
|
11705
|
+
if (!(error instanceof ProfileConfigError))
|
|
11706
|
+
throw error;
|
|
11707
|
+
console.log(`${marker} ${name}${source_default.red(` (${safeOneLine(error.message)})`)}`);
|
|
11708
|
+
continue;
|
|
11709
|
+
}
|
|
11537
11710
|
const hasKey = Boolean(readCredentialsProfile(authProfile).api_key);
|
|
11538
11711
|
const authentication = authProfile === name ? "" : source_default.dim(` (auth: ${authProfile})`);
|
|
11539
11712
|
console.log(`${marker} ${name}${hasKey ? "" : source_default.dim(" (no key)")}${authentication}`);
|
|
@@ -11546,11 +11719,19 @@ function profilesCommand() {
|
|
|
11546
11719
|
}
|
|
11547
11720
|
|
|
11548
11721
|
// src/commands/configure.ts
|
|
11722
|
+
function requireValue(value, flag, key) {
|
|
11723
|
+
if (value !== undefined && value.trim() === "") {
|
|
11724
|
+
throw new SimApiError(`${flag} requires a value. To remove it, run: sim configure --unset ${key}`, 0);
|
|
11725
|
+
}
|
|
11726
|
+
}
|
|
11549
11727
|
function configureCommand() {
|
|
11550
11728
|
return new Command("configure").description("Set a profile's endpoint, default workspace, or output format").option("--set-endpoint <url>", "Sim deployment to talk to").option("--set-workspace <id>", "Default workspace for workspace-scoped commands").option("--set-output <format>", `Default output format (${OUTPUT_FORMATS.join(" | ")})`).option("--unset <key...>", "Remove settings (endpoint, workspace, output)").action((options, command) => {
|
|
11551
|
-
const profile = profileFrom(command);
|
|
11729
|
+
const profile = profileFrom(command, { allowUnknownProfile: true });
|
|
11552
11730
|
const authProfile = resolveAuthenticationProfileName(profile.name);
|
|
11553
11731
|
const updates = {};
|
|
11732
|
+
requireValue(options.setEndpoint, "--set-endpoint", "endpoint");
|
|
11733
|
+
requireValue(options.setWorkspace, "--set-workspace", "workspace");
|
|
11734
|
+
requireValue(options.setOutput, "--set-output", "output");
|
|
11554
11735
|
if (options.setEndpoint) {
|
|
11555
11736
|
if (authProfile !== profile.name) {
|
|
11556
11737
|
throw new SimApiError(`Profile "${profile.name}" shares its endpoint with authentication profile "${authProfile}". Run: sim configure --profile ${authProfile} --set-endpoint ${options.setEndpoint}`, 0);
|
|
@@ -11600,6 +11781,11 @@ var TABLE_READ_FILTER_HELP = 'Condition: {"field":"status","op":"eq","value":"ac
|
|
|
11600
11781
|
var TABLE_SORT_HELP = 'Ordered sort keys: [{"field":"createdAt","direction":"desc"}] (direction: asc or desc)';
|
|
11601
11782
|
var KNOWLEDGE_TAG_DEFINITIONS_HELP = 'Tag definitions: [{"tagSlot":"tag1","displayName":"category","fieldType":"text"}]';
|
|
11602
11783
|
var CUSTOM_TOOL_SCHEMA_HELP = 'OpenAI function schema: {"type":"function","function":{"name":"...","parameters":{"type":"object","properties":{}}}}';
|
|
11784
|
+
var DISPATCH_ROW_LIMIT_HELP = "Stop after this many eligible rows have run (1-1,000,000). Omit for an unbounded run";
|
|
11785
|
+
var WORKFLOW_OPERATIONS_HELP = 'Edits to apply, in a single batch, keyed by operation_type: [{"operation_type":"add","block_id":"my-fn","params":{"type":"function","name":"My Fn","inputs":{"code":"return {ok:true}"}}},{"operation_type":"edit","block_id":"<uuid>","params":{"name":"Renamed","connections":{"success":"my-fn"}}},{"operation_type":"delete","block_id":"<uuid>"}]. Also insert_into_subflow and extract_from_subflow, whose params carry {"subflowId":"<loop-id>"}';
|
|
11786
|
+
var WORKFLOW_SET_BLOCK_ENABLED_HELP = 'Blocks to enable or disable, applied after --operations: [{"block_id":"<uuid>","enabled":false}]. Disabling a loop or parallel cascades to its unlocked descendants; enabling a block whose container is disabled is declined';
|
|
11787
|
+
var WORKFLOW_VARIABLE_OPERATIONS_HELP = 'Variable changes to apply in order, keyed by operation: [{"operation":"add","name":"my_var","type":"string","value":"hello"},{"operation":"edit","name":"my_var","value":"updated"},{"operation":"delete","name":"my_var"}]';
|
|
11788
|
+
var MCP_PARAMETER_DESCRIPTIONS_HELP = 'Per-field description overrides applied to the schema generated from the deployed workflow inputs, as [{"name":"email","description":"Customer email address"}]. A name matching no input field is ignored';
|
|
11603
11789
|
var FOLDER_PATH_INPUT = {
|
|
11604
11790
|
describe: "Folder path as shown in the app; the leading / is optional",
|
|
11605
11791
|
folderPath: true
|
|
@@ -11613,6 +11799,7 @@ var FOLDER_DELETE_FLAGS = {
|
|
|
11613
11799
|
recursive: { boolean: true, describe: "Delete the folder and its descendants" }
|
|
11614
11800
|
};
|
|
11615
11801
|
var KNOWLEDGE_BASE_PATH_ARGUMENT = { knowledgeBaseId: "knowledgeBaseId" };
|
|
11802
|
+
var TRANSFER_TOKEN_OMITTED = { "upload-token": { omit: true } };
|
|
11616
11803
|
var WORKFLOW_RUN_SCOPE = {
|
|
11617
11804
|
workflowId: {
|
|
11618
11805
|
name: "workflow",
|
|
@@ -11653,7 +11840,7 @@ var CLI_CONTRACT = {
|
|
|
11653
11840
|
getBillingStatus: {
|
|
11654
11841
|
command: "billing status",
|
|
11655
11842
|
allWorkspaces: true,
|
|
11656
|
-
describe: "Show billing status and current-period credit usage",
|
|
11843
|
+
describe: "Show billing status and current-period credit usage (credits and storage require a personal API key)",
|
|
11657
11844
|
fields: [
|
|
11658
11845
|
{ header: "plan" },
|
|
11659
11846
|
{ header: "status" },
|
|
@@ -11662,7 +11849,10 @@ var CLI_CONTRACT = {
|
|
|
11662
11849
|
{ header: "period end", path: "period.end", format: "timestamp" },
|
|
11663
11850
|
{ header: "used credits", path: "credits.used" },
|
|
11664
11851
|
{ header: "limit credits", path: "credits.limit" },
|
|
11665
|
-
{ header: "remaining credits", path: "credits.remaining" }
|
|
11852
|
+
{ header: "remaining credits", path: "credits.remaining" },
|
|
11853
|
+
{ header: "used storage", path: "storage.usedBytes", format: "bytes" },
|
|
11854
|
+
{ header: "limit storage", path: "storage.limitBytes", format: "bytes" },
|
|
11855
|
+
{ header: "storage used %", path: "storage.percentUsed" }
|
|
11666
11856
|
]
|
|
11667
11857
|
},
|
|
11668
11858
|
listBillingLogs: {
|
|
@@ -11675,6 +11865,7 @@ var CLI_CONTRACT = {
|
|
|
11675
11865
|
startDate: { describe: "Custom period start (ISO 8601)" },
|
|
11676
11866
|
endDate: { describe: "Custom period end (ISO 8601)" }
|
|
11677
11867
|
},
|
|
11868
|
+
pageNote: { path: "scope", label: "scope" },
|
|
11678
11869
|
columns: [
|
|
11679
11870
|
{ header: "at", path: "createdAt", format: "timestamp" },
|
|
11680
11871
|
{ header: "workspace", path: "workspaceId" },
|
|
@@ -11719,7 +11910,7 @@ var CLI_CONTRACT = {
|
|
|
11719
11910
|
flags: {
|
|
11720
11911
|
chunkIds: { name: "chunk", list: true }
|
|
11721
11912
|
},
|
|
11722
|
-
confirm: "This
|
|
11913
|
+
confirm: "This applies --operation to every named chunk; with --operation delete it deletes them and their embeddings, which cannot be undone."
|
|
11723
11914
|
},
|
|
11724
11915
|
createKnowledgeConnector: {
|
|
11725
11916
|
pathArgumentNames: KNOWLEDGE_BASE_PATH_ARGUMENT
|
|
@@ -11751,7 +11942,8 @@ var CLI_CONTRACT = {
|
|
|
11751
11942
|
},
|
|
11752
11943
|
undeployWorkflow: {
|
|
11753
11944
|
command: "workflows undeploy",
|
|
11754
|
-
describe: "Take a workflow out of deployment"
|
|
11945
|
+
describe: "Take a workflow out of deployment",
|
|
11946
|
+
confirm: "This takes the workflow offline for every API and chat consumer, and agents calling its MCP tools lose access until it is deployed again."
|
|
11755
11947
|
},
|
|
11756
11948
|
getWorkflowDeployment: {
|
|
11757
11949
|
command: "workflows deployment status",
|
|
@@ -11759,13 +11951,17 @@ var CLI_CONTRACT = {
|
|
|
11759
11951
|
describe: "Show a workflow’s current deployment"
|
|
11760
11952
|
},
|
|
11761
11953
|
setSecret: { hidden: true },
|
|
11762
|
-
deleteTable: {
|
|
11954
|
+
deleteTable: {
|
|
11955
|
+
confirm: "This archives the table and all of its rows; restore with `tables restore`."
|
|
11956
|
+
},
|
|
11763
11957
|
deleteTableRow: { confirm: "This deletes the row." },
|
|
11764
11958
|
deleteTableColumn: {
|
|
11765
11959
|
confirm: "This deletes the column and its values in every row.",
|
|
11766
11960
|
fields: [{ header: "remaining columns", path: "columns", format: "count" }]
|
|
11767
11961
|
},
|
|
11768
|
-
deleteKnowledgeBase: {
|
|
11962
|
+
deleteKnowledgeBase: {
|
|
11963
|
+
confirm: "This archives the knowledge base and every document in it; restore with `knowledge restore`."
|
|
11964
|
+
},
|
|
11769
11965
|
deleteKnowledgeDocument: {
|
|
11770
11966
|
pathArgumentNames: KNOWLEDGE_BASE_PATH_ARGUMENT,
|
|
11771
11967
|
confirm: "This deletes the document and its embeddings."
|
|
@@ -11789,7 +11985,9 @@ var CLI_CONTRACT = {
|
|
|
11789
11985
|
deleteSecret: {
|
|
11790
11986
|
confirm: "This deletes the secret; anything using it may stop working."
|
|
11791
11987
|
},
|
|
11792
|
-
deleteWorkflow: {
|
|
11988
|
+
deleteWorkflow: {
|
|
11989
|
+
confirm: "This archives the workflow and its run history; restore with `workflows restore`."
|
|
11990
|
+
},
|
|
11793
11991
|
deleteTableView: { confirm: "This deletes the saved view and its filters." },
|
|
11794
11992
|
deleteWorkflowGroup: {
|
|
11795
11993
|
confirm: "This deletes the group, every column it fed, and the values in them.",
|
|
@@ -11854,7 +12052,17 @@ var CLI_CONTRACT = {
|
|
|
11854
12052
|
getLogStats: {
|
|
11855
12053
|
command: "logs stats",
|
|
11856
12054
|
describe: "Summarize run counts, failures, and cost over a window",
|
|
11857
|
-
flags: LOG_LIST_FILTER_FLAGS
|
|
12055
|
+
flags: LOG_LIST_FILTER_FLAGS,
|
|
12056
|
+
fields: [
|
|
12057
|
+
{ header: "runs", path: "totalRuns" },
|
|
12058
|
+
{ header: "errors", path: "totalErrors" },
|
|
12059
|
+
{ header: "avg latency", path: "avgLatency", format: "duration" },
|
|
12060
|
+
{ header: "window start", path: "timeBounds.start", format: "timestamp" },
|
|
12061
|
+
{ header: "window end", path: "timeBounds.end", format: "timestamp" },
|
|
12062
|
+
{ header: "bucket width", path: "segmentMs", format: "duration" },
|
|
12063
|
+
{ header: "workflows", format: "count" },
|
|
12064
|
+
{ header: "workflows truncated", path: "workflowsTruncated", format: "bool" }
|
|
12065
|
+
]
|
|
11858
12066
|
},
|
|
11859
12067
|
readFileText: {
|
|
11860
12068
|
command: "files read",
|
|
@@ -11866,6 +12074,29 @@ var CLI_CONTRACT = {
|
|
|
11866
12074
|
deleteWorkflowMcpServer: {
|
|
11867
12075
|
confirm: "This deletes the MCP server, and any agent calling its tools loses access."
|
|
11868
12076
|
},
|
|
12077
|
+
deployWorkflowMcpTool: {
|
|
12078
|
+
flags: {
|
|
12079
|
+
parameterDescriptions: { json: true, describe: MCP_PARAMETER_DESCRIPTIONS_HELP }
|
|
12080
|
+
}
|
|
12081
|
+
},
|
|
12082
|
+
listWorkflowMcpServers: {
|
|
12083
|
+
columns: [
|
|
12084
|
+
{ header: "id" },
|
|
12085
|
+
{ header: "name" },
|
|
12086
|
+
{ header: "tools", path: "toolCount" },
|
|
12087
|
+
{ header: "public", path: "isPublic", format: "bool" },
|
|
12088
|
+
{ header: "url", path: "mcpServerUrl" },
|
|
12089
|
+
{ header: "updated", path: "updatedAt", format: "timestamp" }
|
|
12090
|
+
]
|
|
12091
|
+
},
|
|
12092
|
+
listWorkflowMcpTools: {
|
|
12093
|
+
columns: [
|
|
12094
|
+
{ header: "tool", path: "toolName" },
|
|
12095
|
+
{ header: "workflow", path: "workflowId" },
|
|
12096
|
+
{ header: "description", path: "toolDescription" },
|
|
12097
|
+
{ header: "updated", path: "updatedAt", format: "timestamp" }
|
|
12098
|
+
]
|
|
12099
|
+
},
|
|
11869
12100
|
undeployWorkflowMcpTool: {
|
|
11870
12101
|
confirm: "This withdraws the tool, and any agent calling it loses access."
|
|
11871
12102
|
},
|
|
@@ -11879,25 +12110,43 @@ var CLI_CONTRACT = {
|
|
|
11879
12110
|
},
|
|
11880
12111
|
applyWorkflowOperations: {
|
|
11881
12112
|
command: "workflows operations apply",
|
|
11882
|
-
confirm: "This edits the draft graph, and a delete operation removes blocks and their edges."
|
|
12113
|
+
confirm: "This edits the draft graph, and a delete operation removes blocks and their edges.",
|
|
12114
|
+
flags: {
|
|
12115
|
+
operations: { json: true, describe: WORKFLOW_OPERATIONS_HELP },
|
|
12116
|
+
setBlockEnabled: { json: true, describe: WORKFLOW_SET_BLOCK_ENABLED_HELP }
|
|
12117
|
+
}
|
|
11883
12118
|
},
|
|
11884
12119
|
applyWorkflowVariables: {
|
|
11885
|
-
confirm: "This replaces the workflow’s variables and cannot be undone."
|
|
12120
|
+
confirm: "This replaces the workflow’s variables and cannot be undone.",
|
|
12121
|
+
flags: {
|
|
12122
|
+
operations: { json: true, describe: WORKFLOW_VARIABLE_OPERATIONS_HELP }
|
|
12123
|
+
}
|
|
11886
12124
|
},
|
|
11887
12125
|
revertWorkflowVersion: {
|
|
11888
12126
|
confirm: "This overwrites the draft graph with the selected version and cannot be undone."
|
|
11889
12127
|
},
|
|
12128
|
+
rollbackWorkflow: {
|
|
12129
|
+
confirm: "This changes which deployed version runs in production for every API and chat consumer."
|
|
12130
|
+
},
|
|
11890
12131
|
moveWorkflows: {
|
|
11891
12132
|
command: "workflows move",
|
|
11892
12133
|
flags: {
|
|
11893
12134
|
workflowIds: { name: "workflow", list: true },
|
|
11894
|
-
folderPath:
|
|
12135
|
+
folderPath: {
|
|
12136
|
+
...FOLDER_PATH_INPUT,
|
|
12137
|
+
name: "to",
|
|
12138
|
+
renamedFrom: ["folder"],
|
|
12139
|
+
describe: "Destination folder path; / moves the workflows to the workspace root"
|
|
12140
|
+
}
|
|
11895
12141
|
}
|
|
11896
12142
|
},
|
|
11897
12143
|
moveTables: {
|
|
11898
12144
|
command: "tables move",
|
|
11899
12145
|
flags: {
|
|
11900
|
-
folderPaths:
|
|
12146
|
+
folderPaths: {
|
|
12147
|
+
...FOLDER_PATHS_FLAG,
|
|
12148
|
+
describe: "Table folders to move, by path as shown in the app; the leading / is optional"
|
|
12149
|
+
},
|
|
11901
12150
|
targetFolderPath: TARGET_FOLDER_PATH_FLAG
|
|
11902
12151
|
}
|
|
11903
12152
|
},
|
|
@@ -12016,7 +12265,10 @@ var CLI_CONTRACT = {
|
|
|
12016
12265
|
]
|
|
12017
12266
|
},
|
|
12018
12267
|
listFiles: {
|
|
12019
|
-
flags: {
|
|
12268
|
+
flags: {
|
|
12269
|
+
folderPath: FOLDER_PATH_FLAG,
|
|
12270
|
+
recursive: { boolean: true, negatable: true }
|
|
12271
|
+
},
|
|
12020
12272
|
columns: [
|
|
12021
12273
|
{ header: "id" },
|
|
12022
12274
|
{ header: "name" },
|
|
@@ -12040,9 +12292,19 @@ var CLI_CONTRACT = {
|
|
|
12040
12292
|
]
|
|
12041
12293
|
},
|
|
12042
12294
|
getKnowledgeDocument: { pathArgumentNames: KNOWLEDGE_BASE_PATH_ARGUMENT },
|
|
12043
|
-
updateKnowledgeDocument: {
|
|
12295
|
+
updateKnowledgeDocument: {
|
|
12296
|
+
pathArgumentNames: KNOWLEDGE_BASE_PATH_ARGUMENT,
|
|
12297
|
+
flags: { retryProcessing: { boolean: true } }
|
|
12298
|
+
},
|
|
12044
12299
|
listKnowledgeTags: { pathArgumentNames: KNOWLEDGE_BASE_PATH_ARGUMENT },
|
|
12045
|
-
createKnowledgeTag: {
|
|
12300
|
+
createKnowledgeTag: {
|
|
12301
|
+
pathArgumentNames: KNOWLEDGE_BASE_PATH_ARGUMENT,
|
|
12302
|
+
flags: {
|
|
12303
|
+
fieldType: {
|
|
12304
|
+
describe: "Value type stored in the slot; it decides which slots are usable and which filter operators apply. Defaults to text, so a number, date, or boolean slot must name its type here. Slot capacity per type: text 7, number 5, date 2, boolean 3"
|
|
12305
|
+
}
|
|
12306
|
+
}
|
|
12307
|
+
},
|
|
12046
12308
|
updateKnowledgeTag: { pathArgumentNames: KNOWLEDGE_BASE_PATH_ARGUMENT },
|
|
12047
12309
|
deleteKnowledgeTag: {
|
|
12048
12310
|
pathArgumentNames: KNOWLEDGE_BASE_PATH_ARGUMENT,
|
|
@@ -12147,7 +12409,8 @@ var CLI_CONTRACT = {
|
|
|
12147
12409
|
{ header: "scope" },
|
|
12148
12410
|
{ header: "role" },
|
|
12149
12411
|
{ header: "updated", path: "updatedAt", format: "timestamp" },
|
|
12150
|
-
{ header: "description" }
|
|
12412
|
+
{ header: "description" },
|
|
12413
|
+
{ header: "unredacted", format: "bool" }
|
|
12151
12414
|
]
|
|
12152
12415
|
},
|
|
12153
12416
|
getWorkspace: {
|
|
@@ -12155,7 +12418,8 @@ var CLI_CONTRACT = {
|
|
|
12155
12418
|
fields: [
|
|
12156
12419
|
{ header: "id" },
|
|
12157
12420
|
{ header: "name" },
|
|
12158
|
-
{ header: "
|
|
12421
|
+
{ header: "color" },
|
|
12422
|
+
{ header: "logo", path: "logoUrl" },
|
|
12159
12423
|
{ header: "members", path: "memberCount" },
|
|
12160
12424
|
{ header: "created", path: "createdAt", format: "timestamp" },
|
|
12161
12425
|
{ header: "updated", path: "updatedAt", format: "timestamp" }
|
|
@@ -12178,7 +12442,7 @@ var CLI_CONTRACT = {
|
|
|
12178
12442
|
flags: {
|
|
12179
12443
|
organizationId: {
|
|
12180
12444
|
name: "organization",
|
|
12181
|
-
describe: "Organization ID (personal API key required)"
|
|
12445
|
+
describe: "Organization ID; defaults to your only organization, and is required when your account belongs to more than one (personal API key required)"
|
|
12182
12446
|
}
|
|
12183
12447
|
},
|
|
12184
12448
|
columns: [
|
|
@@ -12186,14 +12450,15 @@ var CLI_CONTRACT = {
|
|
|
12186
12450
|
{ header: "workspace", path: "workspaceId" },
|
|
12187
12451
|
{ header: "actor", path: "actorEmail" },
|
|
12188
12452
|
{ header: "action" },
|
|
12189
|
-
{ header: "resource", path: "resourceName" }
|
|
12453
|
+
{ header: "resource", path: "resourceName" },
|
|
12454
|
+
{ header: "id" }
|
|
12190
12455
|
]
|
|
12191
12456
|
},
|
|
12192
12457
|
getAuditLog: {
|
|
12193
12458
|
flags: {
|
|
12194
12459
|
organizationId: {
|
|
12195
12460
|
name: "organization",
|
|
12196
|
-
describe: "Organization ID (personal API key required)"
|
|
12461
|
+
describe: "Organization ID; defaults to your only organization, and is required when your account belongs to more than one (personal API key required)"
|
|
12197
12462
|
}
|
|
12198
12463
|
}
|
|
12199
12464
|
},
|
|
@@ -12293,6 +12558,11 @@ var CLI_CONTRACT = {
|
|
|
12293
12558
|
command: "knowledge tags cleanup",
|
|
12294
12559
|
pathArgumentNames: KNOWLEDGE_BASE_PATH_ARGUMENT,
|
|
12295
12560
|
describe: "Remove tag definitions no document still uses",
|
|
12561
|
+
flags: {
|
|
12562
|
+
unused: {
|
|
12563
|
+
describe: "Whether to remove only the tag definitions no document in the knowledge base still carries a value for. Defaults to true. Pass --no-unused to delete every definition on the knowledge base, which also clears its slot on every document and chunk and is not recoverable"
|
|
12564
|
+
}
|
|
12565
|
+
},
|
|
12296
12566
|
confirm: "This deletes every tag definition no document still uses. Their slots become free for a different field."
|
|
12297
12567
|
},
|
|
12298
12568
|
unzipFile: {
|
|
@@ -12454,7 +12724,8 @@ var CLI_CONTRACT = {
|
|
|
12454
12724
|
flags: {
|
|
12455
12725
|
excludeRowIds: { list: true },
|
|
12456
12726
|
filter: { json: true, describe: TABLE_FILTER_HELP }
|
|
12457
|
-
}
|
|
12727
|
+
},
|
|
12728
|
+
confirm: "This cancels running column jobs — the whole table with --scope all, one row with --scope row."
|
|
12458
12729
|
},
|
|
12459
12730
|
searchTableRows: {
|
|
12460
12731
|
command: "tables rows search",
|
|
@@ -12489,7 +12760,13 @@ var CLI_CONTRACT = {
|
|
|
12489
12760
|
groupIds: { list: true },
|
|
12490
12761
|
rowIds: { list: true },
|
|
12491
12762
|
excludeRowIds: { list: true },
|
|
12492
|
-
filter: { json: true, describe: TABLE_FILTER_HELP }
|
|
12763
|
+
filter: { json: true, describe: TABLE_FILTER_HELP },
|
|
12764
|
+
limit: {
|
|
12765
|
+
name: "max-rows",
|
|
12766
|
+
renamedFrom: ["limit"],
|
|
12767
|
+
rowCap: true,
|
|
12768
|
+
describe: DISPATCH_ROW_LIMIT_HELP
|
|
12769
|
+
}
|
|
12493
12770
|
}
|
|
12494
12771
|
},
|
|
12495
12772
|
runRowEnrichment: {
|
|
@@ -12499,7 +12776,8 @@ var CLI_CONTRACT = {
|
|
|
12499
12776
|
createTableImport: { hidden: true },
|
|
12500
12777
|
createTableImportPartUrls: { hidden: true },
|
|
12501
12778
|
completeTableImport: { hidden: true },
|
|
12502
|
-
|
|
12779
|
+
getTableImport: { flags: TRANSFER_TOKEN_OMITTED },
|
|
12780
|
+
cancelTableImport: { command: "tables imports cancel", flags: TRANSFER_TOKEN_OMITTED },
|
|
12503
12781
|
cancelTableExport: { command: "tables exports cancel" },
|
|
12504
12782
|
tableExportDownload: {
|
|
12505
12783
|
command: "tables exports download",
|
|
@@ -12526,7 +12804,12 @@ var CLI_CONTRACT = {
|
|
|
12526
12804
|
},
|
|
12527
12805
|
stream: { omit: true },
|
|
12528
12806
|
includeThinking: { omit: true },
|
|
12529
|
-
includeToolCalls: { omit: true }
|
|
12807
|
+
includeToolCalls: { omit: true },
|
|
12808
|
+
"x-run-id": {
|
|
12809
|
+
name: "run-id",
|
|
12810
|
+
describe: "One-shot identifier for this run; NOT an idempotency key — reusing a claimed value fails with RUN_ID_CONFLICT instead of replaying the first result, and a fresh value starts another run"
|
|
12811
|
+
},
|
|
12812
|
+
"x-sim-via": { omit: true }
|
|
12530
12813
|
}
|
|
12531
12814
|
},
|
|
12532
12815
|
getWorkflowRun: {
|
|
@@ -12614,7 +12897,8 @@ var CLI_CONTRACT = {
|
|
|
12614
12897
|
createFileUpload: { hidden: true },
|
|
12615
12898
|
createFileUploadPartUrls: { hidden: true },
|
|
12616
12899
|
completeFileUpload: { hidden: true },
|
|
12617
|
-
abortFileUpload: { hidden: true }
|
|
12900
|
+
abortFileUpload: { hidden: true },
|
|
12901
|
+
getFileUpload: { hidden: true }
|
|
12618
12902
|
};
|
|
12619
12903
|
|
|
12620
12904
|
// src/runtime/derive.ts
|
|
@@ -12655,15 +12939,44 @@ var JSON_KINDS = new Set(["object", "array", "unknown"]);
|
|
|
12655
12939
|
function flagSpecFor(operation, field) {
|
|
12656
12940
|
return CLI_CONTRACT[operation]?.flags?.[field] ?? {};
|
|
12657
12941
|
}
|
|
12942
|
+
var RESERVED_PROGRAM_FLAGS = new Set([
|
|
12943
|
+
"--version",
|
|
12944
|
+
"-V",
|
|
12945
|
+
"--help",
|
|
12946
|
+
"-h",
|
|
12947
|
+
"--profile",
|
|
12948
|
+
"-P",
|
|
12949
|
+
"--endpoint",
|
|
12950
|
+
"--workspace",
|
|
12951
|
+
"-w",
|
|
12952
|
+
"--output"
|
|
12953
|
+
]);
|
|
12954
|
+
var RESERVED_FLAG_REPLACEMENTS = {
|
|
12955
|
+
version: "to-version"
|
|
12956
|
+
};
|
|
12658
12957
|
function flagNameFor(operation, field) {
|
|
12659
|
-
|
|
12958
|
+
const declared = flagSpecFor(operation, field).name;
|
|
12959
|
+
if (declared)
|
|
12960
|
+
return declared;
|
|
12961
|
+
const derived = kebab(field);
|
|
12962
|
+
return RESERVED_FLAG_REPLACEMENTS[derived] ?? derived;
|
|
12660
12963
|
}
|
|
12661
12964
|
function pathFlagNameFor(commandSpec, param) {
|
|
12662
12965
|
return commandSpec.pathFlags?.[param]?.name ?? kebab(param);
|
|
12663
12966
|
}
|
|
12664
12967
|
function takesJson(field, flag) {
|
|
12968
|
+
if (flag.rowCap)
|
|
12969
|
+
return false;
|
|
12665
12970
|
return flag.json === true || JSON_KINDS.has(field.kind);
|
|
12666
12971
|
}
|
|
12972
|
+
var MAX_ROW_CAP = 1e6;
|
|
12973
|
+
function coerceRowCap(raw, flagName) {
|
|
12974
|
+
const value = Number(raw);
|
|
12975
|
+
if (!Number.isInteger(value) || value < 1 || value > MAX_ROW_CAP) {
|
|
12976
|
+
throw new SimApiError(`--${flagName} must be a whole number between 1 and ${MAX_ROW_CAP.toLocaleString("en-US")}`, 0);
|
|
12977
|
+
}
|
|
12978
|
+
return { type: "rows", max: value };
|
|
12979
|
+
}
|
|
12667
12980
|
function readStdin() {
|
|
12668
12981
|
const idle = new Int32Array(new SharedArrayBuffer(4));
|
|
12669
12982
|
const buffer = Buffer.alloc(64 * 1024);
|
|
@@ -12689,6 +13002,8 @@ function readStdin() {
|
|
|
12689
13002
|
return Buffer.concat(chunks).toString("utf8");
|
|
12690
13003
|
}
|
|
12691
13004
|
function readArgumentSource(raw, flagName) {
|
|
13005
|
+
if (raw.startsWith("@@"))
|
|
13006
|
+
return { text: raw.slice(1), from: "" };
|
|
12692
13007
|
if (!raw.startsWith("@"))
|
|
12693
13008
|
return { text: raw, from: "" };
|
|
12694
13009
|
const path = raw.slice(1);
|
|
@@ -12770,6 +13085,8 @@ function coerce(raw, field, flag, flagName) {
|
|
|
12770
13085
|
const values = readListValues(raw, flagName).map((value) => flag.folderPath ? encodeFolderPath(value) : value);
|
|
12771
13086
|
return field.kind === "string" ? values.join(",") : values;
|
|
12772
13087
|
}
|
|
13088
|
+
if (flag.rowCap)
|
|
13089
|
+
return coerceRowCap(raw, flagName);
|
|
12773
13090
|
if (takesJson(field, flag)) {
|
|
12774
13091
|
if (typeof raw !== "string")
|
|
12775
13092
|
return raw;
|
|
@@ -12827,7 +13144,8 @@ function buildRequest(operation, positional, flags, workspaceId) {
|
|
|
12827
13144
|
}
|
|
12828
13145
|
const query = {};
|
|
12829
13146
|
const body = {};
|
|
12830
|
-
|
|
13147
|
+
const headers = {};
|
|
13148
|
+
for (const slot of ["query", "body", "headers"]) {
|
|
12831
13149
|
for (const [field, descriptor] of Object.entries(spec[slot] ?? {})) {
|
|
12832
13150
|
const flag = flagSpecFor(operation, field);
|
|
12833
13151
|
if (flag.omit)
|
|
@@ -12845,10 +13163,13 @@ function buildRequest(operation, positional, flags, workspaceId) {
|
|
|
12845
13163
|
}
|
|
12846
13164
|
if (slot === "query")
|
|
12847
13165
|
query[field] = asQueryValue(value);
|
|
13166
|
+
else if (slot === "headers")
|
|
13167
|
+
headers[field] = String(value);
|
|
12848
13168
|
else
|
|
12849
13169
|
body[field] = value;
|
|
12850
13170
|
}
|
|
12851
13171
|
}
|
|
13172
|
+
const headerSlot = Object.keys(headers).length > 0 ? { headers } : {};
|
|
12852
13173
|
if (spec.opaqueBody) {
|
|
12853
13174
|
if (commandSpec.bodyVariants) {
|
|
12854
13175
|
const provided = commandSpec.bodyVariants.filter((variant2) => flags[camel(variant2.name)] !== undefined);
|
|
@@ -12864,7 +13185,7 @@ function buildRequest(operation, positional, flags, workspaceId) {
|
|
|
12864
13185
|
if (variant.kind === "object" && (!parsed2 || typeof parsed2 !== "object" || Array.isArray(parsed2)) || variant.kind === "array" && !Array.isArray(parsed2)) {
|
|
12865
13186
|
throw new SimApiError(`--${variant.name} must be a JSON ${variant.kind}`, 0);
|
|
12866
13187
|
}
|
|
12867
|
-
return { path, query, body: { ...body, [variant.property]: parsed2 } };
|
|
13188
|
+
return { path, query, body: { ...body, [variant.property]: parsed2 }, ...headerSlot };
|
|
12868
13189
|
}
|
|
12869
13190
|
const raw = flags.body;
|
|
12870
13191
|
if (typeof raw !== "string")
|
|
@@ -12873,12 +13194,13 @@ function buildRequest(operation, positional, flags, workspaceId) {
|
|
|
12873
13194
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
12874
13195
|
throw new SimApiError("--body must be a JSON object", 0);
|
|
12875
13196
|
}
|
|
12876
|
-
return { path, query, body: { ...body, ...parsed } };
|
|
13197
|
+
return { path, query, body: { ...body, ...parsed }, ...headerSlot };
|
|
12877
13198
|
}
|
|
12878
13199
|
return {
|
|
12879
13200
|
path,
|
|
12880
13201
|
query,
|
|
12881
|
-
body: spec.body ? body : undefined
|
|
13202
|
+
body: spec.body ? body : undefined,
|
|
13203
|
+
...headerSlot
|
|
12882
13204
|
};
|
|
12883
13205
|
}
|
|
12884
13206
|
|
|
@@ -13142,9 +13464,19 @@ function unwrapResource(data) {
|
|
|
13142
13464
|
const [, value] = entries[0];
|
|
13143
13465
|
return value && typeof value === "object" && !Array.isArray(value) ? value : data;
|
|
13144
13466
|
}
|
|
13145
|
-
function renderPage(format, rows, spec) {
|
|
13467
|
+
function renderPage(format, rows, spec, envelope) {
|
|
13468
|
+
writePageNote(spec, envelope);
|
|
13146
13469
|
printList(format, rows, spec.columns ? columnsFrom(spec.columns) : inferColumns(rows, spec.expand));
|
|
13147
13470
|
}
|
|
13471
|
+
function writePageNote(spec, envelope) {
|
|
13472
|
+
if (!spec.pageNote)
|
|
13473
|
+
return;
|
|
13474
|
+
const value = at(envelope, spec.pageNote.path);
|
|
13475
|
+
if (value === undefined || value === null)
|
|
13476
|
+
return;
|
|
13477
|
+
process.stderr.write(source_default.dim(`${spec.pageNote.label}: ${String(value)}
|
|
13478
|
+
`));
|
|
13479
|
+
}
|
|
13148
13480
|
function renderResult(operation, format, raw, spec, options = {}) {
|
|
13149
13481
|
if (spec.document) {
|
|
13150
13482
|
printDocument(format, raw);
|
|
@@ -13269,10 +13601,25 @@ async function createConnectionLink(command, body) {
|
|
|
13269
13601
|
});
|
|
13270
13602
|
renderResult("createCredentialConnection", profile.output, response.data, CONNECTION_RESULT);
|
|
13271
13603
|
}
|
|
13604
|
+
function acceptNameOnUpdate(credentials) {
|
|
13605
|
+
const update = credentials.commands.find((command) => command.name() === "update");
|
|
13606
|
+
if (!update)
|
|
13607
|
+
throw new Error("The generated credentials update command is missing");
|
|
13608
|
+
update.addOption(new Option("--name <displayName>", "Alias for --display-name")).hook("preAction", (_parent, action) => {
|
|
13609
|
+
const options = action.opts();
|
|
13610
|
+
if (options.name === undefined)
|
|
13611
|
+
return;
|
|
13612
|
+
if (options.displayName !== undefined) {
|
|
13613
|
+
throw new SimApiError("--name and --display-name are the same field; pass one, not both", 0);
|
|
13614
|
+
}
|
|
13615
|
+
options.displayName = options.name;
|
|
13616
|
+
});
|
|
13617
|
+
}
|
|
13272
13618
|
function attachCredentialCommands(program2) {
|
|
13273
13619
|
const credentials = program2.commands.find((command) => command.name() === "credentials");
|
|
13274
13620
|
if (!credentials)
|
|
13275
13621
|
throw new Error("The generated credentials command group is missing");
|
|
13622
|
+
acceptNameOnUpdate(credentials);
|
|
13276
13623
|
credentials.command("create").argument("<providerId>", "Service-account provider to create a credential for").description("Create a service-account credential using its discovered provider schema").requiredOption("--name <displayName>", "Name shown for the credential in Sim").requiredOption("--credentials <json|@file>", "Provider credentials as JSON (or @path / @- to read a file or stdin)").option("--description <description>", "Optional credential description").option("--id <credentialId>", "Client-generated credential ID when provider discovery requires it").action((providerId, options, command) => createServiceAccount(command, providerId, options));
|
|
13277
13624
|
credentials.command("connect").argument("<providerId>", "OAuth provider to connect").description("Create a short-lived link for connecting an OAuth provider").requiredOption("--name <displayName>", "Name shown for the new credential in Sim").action(async (providerId, options, command) => createConnectionLink(command, { providerId, displayName: options.name }));
|
|
13278
13625
|
credentials.command("reconnect").argument("<credentialId>", "Existing OAuth credential to re-authorize").description("Create a short-lived link for reconnecting an OAuth credential").action((credentialId, _options, command) => createConnectionLink(command, { credentialId }));
|
|
@@ -13306,23 +13653,24 @@ async function readChatStream(response, onChunk) {
|
|
|
13306
13653
|
const processLine = (line) => {
|
|
13307
13654
|
const event = parseChatStreamLine(line);
|
|
13308
13655
|
if (!event || event.type === "heartbeat")
|
|
13309
|
-
return;
|
|
13656
|
+
return false;
|
|
13310
13657
|
if (event.type === "chunk") {
|
|
13311
13658
|
if (event.content)
|
|
13312
13659
|
onChunk(sanitize(event.content));
|
|
13313
|
-
return;
|
|
13660
|
+
return false;
|
|
13314
13661
|
}
|
|
13315
13662
|
if (event.type === "error") {
|
|
13316
13663
|
throw new SimApiError(event.error || "Chat request failed", 0);
|
|
13317
13664
|
}
|
|
13318
13665
|
if (event.type === "final") {
|
|
13319
13666
|
finalResult = event.data;
|
|
13320
|
-
return;
|
|
13667
|
+
return true;
|
|
13321
13668
|
}
|
|
13322
13669
|
throw new SimApiError("Chat stream returned an unknown event", 0);
|
|
13323
13670
|
};
|
|
13324
13671
|
try {
|
|
13325
|
-
|
|
13672
|
+
let ended = false;
|
|
13673
|
+
while (!ended) {
|
|
13326
13674
|
const { done, value } = await reader.read();
|
|
13327
13675
|
if (done)
|
|
13328
13676
|
break;
|
|
@@ -13331,21 +13679,39 @@ async function readChatStream(response, onChunk) {
|
|
|
13331
13679
|
`);
|
|
13332
13680
|
buffer = lines.pop() ?? "";
|
|
13333
13681
|
for (const line of lines) {
|
|
13334
|
-
processLine(line)
|
|
13682
|
+
if (processLine(line)) {
|
|
13683
|
+
ended = true;
|
|
13684
|
+
break;
|
|
13685
|
+
}
|
|
13335
13686
|
}
|
|
13336
13687
|
}
|
|
13337
|
-
|
|
13338
|
-
|
|
13688
|
+
if (!ended) {
|
|
13689
|
+
buffer += decoder.decode();
|
|
13690
|
+
processLine(buffer);
|
|
13691
|
+
}
|
|
13339
13692
|
if (!finalResult) {
|
|
13340
13693
|
throw new SimApiError("Chat stream ended without a final result", 0);
|
|
13341
13694
|
}
|
|
13342
13695
|
return finalResult;
|
|
13343
13696
|
} finally {
|
|
13344
|
-
reader.
|
|
13697
|
+
reader.cancel().catch(() => {
|
|
13698
|
+
return;
|
|
13699
|
+
});
|
|
13345
13700
|
}
|
|
13346
13701
|
}
|
|
13702
|
+
function ignoreBrokenPipe(stream) {
|
|
13703
|
+
const onError = (error) => {
|
|
13704
|
+
if (error.code !== "EPIPE")
|
|
13705
|
+
throw error;
|
|
13706
|
+
process.exit(0);
|
|
13707
|
+
};
|
|
13708
|
+
stream.on("error", onError);
|
|
13709
|
+
return () => {
|
|
13710
|
+
stream.off("error", onError);
|
|
13711
|
+
};
|
|
13712
|
+
}
|
|
13347
13713
|
function attachChat(program2) {
|
|
13348
|
-
program2.command("chat").description("Ask Sim and print the reply").argument("<message>", "What to ask Sim").option("-c, --conversation <id>", "Continue the conversation with this ID").addHelpText("after", `
|
|
13714
|
+
program2.command("chat").description("Ask Sim and print the reply").argument("<message>", "What to ask Sim").allowExcessArguments(false).option("-c, --conversation <id>", "Continue the conversation with this ID").addHelpText("after", `
|
|
13349
13715
|
Each turn prints the reply on stdout and the conversation ID on stderr; pass
|
|
13350
13716
|
that ID back with -c to continue the same conversation. With --output json or
|
|
13351
13717
|
yaml the reply is not streamed — the finished result is printed as one
|
|
@@ -13369,28 +13735,41 @@ Examples:
|
|
|
13369
13735
|
});
|
|
13370
13736
|
const streaming = profile.output === "table" || profile.output === "text";
|
|
13371
13737
|
let streamed = "";
|
|
13372
|
-
const
|
|
13373
|
-
if (!
|
|
13374
|
-
return;
|
|
13375
|
-
streamed += content2;
|
|
13376
|
-
process.stdout.write(content2);
|
|
13377
|
-
});
|
|
13378
|
-
if (!streaming) {
|
|
13379
|
-
printProtocolResult(profile.output, result);
|
|
13380
|
-
return;
|
|
13381
|
-
}
|
|
13382
|
-
const content = sanitize(result.content ?? "");
|
|
13383
|
-
if (content.startsWith(streamed) && content.length > streamed.length) {
|
|
13384
|
-
process.stdout.write(content.slice(streamed.length));
|
|
13385
|
-
streamed = content;
|
|
13386
|
-
}
|
|
13387
|
-
if (streamed.length > 0 && !streamed.endsWith(`
|
|
13738
|
+
const endStreamedLine = () => {
|
|
13739
|
+
if (streamed.length > 0 && !streamed.endsWith(`
|
|
13388
13740
|
`)) {
|
|
13389
|
-
|
|
13741
|
+
process.stdout.write(`
|
|
13390
13742
|
`);
|
|
13391
|
-
|
|
13392
|
-
|
|
13743
|
+
streamed += `
|
|
13744
|
+
`;
|
|
13745
|
+
}
|
|
13746
|
+
};
|
|
13747
|
+
const restorePipeHandling = streaming ? ignoreBrokenPipe(process.stdout) : undefined;
|
|
13748
|
+
try {
|
|
13749
|
+
const result = await readChatStream(response, (content2) => {
|
|
13750
|
+
if (!streaming)
|
|
13751
|
+
return;
|
|
13752
|
+
streamed += content2;
|
|
13753
|
+
process.stdout.write(content2);
|
|
13754
|
+
});
|
|
13755
|
+
if (!streaming) {
|
|
13756
|
+
printProtocolResult(profile.output, result);
|
|
13757
|
+
return;
|
|
13758
|
+
}
|
|
13759
|
+
const content = sanitize(result.content ?? "");
|
|
13760
|
+
if (content.startsWith(streamed) && content.length > streamed.length) {
|
|
13761
|
+
process.stdout.write(content.slice(streamed.length));
|
|
13762
|
+
streamed = content;
|
|
13763
|
+
}
|
|
13764
|
+
endStreamedLine();
|
|
13765
|
+
process.stderr.write(`${source_default.dim(`conversation: ${result.conversationId}`)}
|
|
13393
13766
|
`);
|
|
13767
|
+
} catch (error) {
|
|
13768
|
+
endStreamedLine();
|
|
13769
|
+
throw error;
|
|
13770
|
+
} finally {
|
|
13771
|
+
restorePipeHandling?.();
|
|
13772
|
+
}
|
|
13394
13773
|
});
|
|
13395
13774
|
}
|
|
13396
13775
|
|
|
@@ -13518,7 +13897,7 @@ function isTerminalSafeContentType(contentType) {
|
|
|
13518
13897
|
].includes(mediaType);
|
|
13519
13898
|
}
|
|
13520
13899
|
function attachFileGet(files) {
|
|
13521
|
-
files.command("get").argument("<fileId>", "File whose content to read").description("Get a file’s content").option("-o, --output-file <path>", "Write content to a file instead of stdout").option("--force", "Overwrite --output-file if it already exists").action(async (fileId, options, command) => {
|
|
13900
|
+
files.command("get").argument("<fileId>", "File whose content to read").allowExcessArguments(false).description("Get a file’s content").option("-o, --output-file <path>", "Write content to a file instead of stdout").option("--force", "Overwrite --output-file if it already exists").action(async (fileId, options, command) => {
|
|
13522
13901
|
const writesToStdout = options.outputFile === undefined || options.outputFile === "-";
|
|
13523
13902
|
if (writesToStdout && options.force) {
|
|
13524
13903
|
throw new SimApiError("--force requires --output-file <path>", 0);
|
|
@@ -13553,7 +13932,8 @@ function attachFileGet(files) {
|
|
|
13553
13932
|
}
|
|
13554
13933
|
|
|
13555
13934
|
// src/transfer/local-file.ts
|
|
13556
|
-
import {
|
|
13935
|
+
import { constants } from "node:fs";
|
|
13936
|
+
import { access, stat } from "node:fs/promises";
|
|
13557
13937
|
import { basename } from "node:path";
|
|
13558
13938
|
var CONTENT_TYPES = {
|
|
13559
13939
|
css: "text/css",
|
|
@@ -13593,6 +13973,7 @@ async function localFile(path, override) {
|
|
|
13593
13973
|
const stats = await stat(path);
|
|
13594
13974
|
if (!stats.isFile())
|
|
13595
13975
|
throw new SimApiError(`${path} is not a regular file`, 0);
|
|
13976
|
+
await access(path, constants.R_OK);
|
|
13596
13977
|
size = stats.size;
|
|
13597
13978
|
} catch (error) {
|
|
13598
13979
|
if (error instanceof SimApiError)
|
|
@@ -13675,7 +14056,7 @@ async function finishUploadSession(client, workspaceId, session, path) {
|
|
|
13675
14056
|
|
|
13676
14057
|
// src/commands/protocol/files-upload.ts
|
|
13677
14058
|
function attachFileUpload(files) {
|
|
13678
|
-
files.command("upload").argument("<path>", "Local file to upload").description("Upload a file to the workspace").option("--folder <path>", "Folder path as shown in the app; defaults to the root folder").option("--name <name>", "Store it under a different name").action(async (path, options, command) => {
|
|
14059
|
+
files.command("upload").argument("<path>", "Local file to upload").allowExcessArguments(false).description("Upload a file to the workspace").option("--folder <path>", "Folder path as shown in the app; defaults to the root folder").option("--name <name>", "Store it under a different name").action(async (path, options, command) => {
|
|
13679
14060
|
const { client, profile } = clientFrom(command);
|
|
13680
14061
|
const workspaceId = client.requireWorkspace();
|
|
13681
14062
|
const { name, size } = await localFile(path, options.name);
|
|
@@ -13721,7 +14102,7 @@ function uploadMetadata(options) {
|
|
|
13721
14102
|
return metadata;
|
|
13722
14103
|
}
|
|
13723
14104
|
function attachKnowledgeDocumentUpload(documents) {
|
|
13724
|
-
documents.command("upload").argument("<knowledgeBaseId>", "Knowledge base to upload into").argument("<path>", "Local file to upload").description("Upload a document to a knowledge base").option("--name <name>", "Store it under a different name").option("--tag <value...>", "Document tags, in tag1 through tag7 order").option("--recipe <name>", "Document processing recipe").option("--lang <code>", "Document language code").action(async (knowledgeBaseId, path, options, command) => {
|
|
14105
|
+
documents.command("upload").argument("<knowledgeBaseId>", "Knowledge base to upload into").argument("<path>", "Local file to upload").allowExcessArguments(false).description("Upload a document to a knowledge base").option("--name <name>", "Store it under a different name").option("--tag <value...>", "Document tags, in tag1 through tag7 order").option("--recipe <name>", "Document processing recipe").option("--lang <code>", "Document language code").action(async (knowledgeBaseId, path, options, command) => {
|
|
13725
14106
|
const { client, profile } = clientFrom(command);
|
|
13726
14107
|
const workspaceId = client.requireWorkspace();
|
|
13727
14108
|
const { name, size } = await localFile(path, options.name);
|
|
@@ -13980,7 +14361,8 @@ Examples:
|
|
|
13980
14361
|
triggers: options.trigger?.length ? options.trigger.join(",") : undefined,
|
|
13981
14362
|
level: options.level,
|
|
13982
14363
|
details: options.details,
|
|
13983
|
-
|
|
14364
|
+
sortBy: "startedAt",
|
|
14365
|
+
sortOrder: "desc"
|
|
13984
14366
|
};
|
|
13985
14367
|
const write = createWriter(profile.output);
|
|
13986
14368
|
const status = followStatus();
|
|
@@ -14032,7 +14414,14 @@ var DEFAULT_LIMIT = 100;
|
|
|
14032
14414
|
function describeField(flag, descriptor, name, field) {
|
|
14033
14415
|
return flag.describe ?? descriptor.describe ?? `Set ${name.replaceAll("-", " ") || field}`;
|
|
14034
14416
|
}
|
|
14035
|
-
function
|
|
14417
|
+
function literalNullHint(documented, name) {
|
|
14418
|
+
return /\bnull\b/i.test(documented) ? ` (--${name} null sends the word, not JSON null)` : "";
|
|
14419
|
+
}
|
|
14420
|
+
var WIRE_VOCABULARY_SENTENCE = /\s*The listed spellings[^.]*\.\s*/g;
|
|
14421
|
+
function withoutWireVocabulary(documented) {
|
|
14422
|
+
return documented.replace(WIRE_VOCABULARY_SENTENCE, " ").trim();
|
|
14423
|
+
}
|
|
14424
|
+
function addFieldOption(command, operation, field, descriptor, slot) {
|
|
14036
14425
|
if (field === PROFILE_INJECTED_FIELD || field === "cursor")
|
|
14037
14426
|
return;
|
|
14038
14427
|
const flag = flagSpecFor(operation, field);
|
|
@@ -14046,20 +14435,23 @@ function addFieldOption(command, operation, field, descriptor) {
|
|
|
14046
14435
|
}
|
|
14047
14436
|
const documented = describeField(flag, descriptor, name, field);
|
|
14048
14437
|
if (descriptor.kind === "boolean" || flag.boolean) {
|
|
14438
|
+
const booleanDoc = withoutWireVocabulary(documented);
|
|
14049
14439
|
if (descriptor.required) {
|
|
14050
|
-
command.addOption(new Option(`${short}--${name} <true|false>`, `${
|
|
14440
|
+
command.addOption(new Option(`${short}--${name} <true|false>`, `${booleanDoc} (required)`).choices(["true", "false"]).makeOptionMandatory());
|
|
14051
14441
|
return;
|
|
14052
14442
|
}
|
|
14053
|
-
command.option(`${short}--${name}`,
|
|
14054
|
-
if (!flag.boolean)
|
|
14443
|
+
command.option(`${short}--${name}`, booleanDoc);
|
|
14444
|
+
if (!flag.boolean || flag.negatable) {
|
|
14055
14445
|
command.option(`--no-${name}`, `Send --${name} as false`);
|
|
14446
|
+
}
|
|
14056
14447
|
return;
|
|
14057
14448
|
}
|
|
14058
14449
|
const takesList = flag.list === true;
|
|
14059
14450
|
const wantsJson = takesJson(descriptor, flag);
|
|
14060
|
-
const placeholder = takesList ? "<value...>" : wantsJson ? "<json|@file>" : "<value>";
|
|
14451
|
+
const placeholder = takesList ? "<value...>" : flag.rowCap ? "<n>" : wantsJson ? "<json|@file>" : "<value>";
|
|
14061
14452
|
const choices = flag.choices ?? descriptor.values;
|
|
14062
|
-
const
|
|
14453
|
+
const literalNull = slot === "body" && !takesList && !wantsJson;
|
|
14454
|
+
const describe = `${documented}${takesList ? " (space-separated, or @path / @- with one value per line)" : wantsJson ? " (JSON, or @path / @- to read a file or stdin)" : ""}${descriptor.required ? " (required)" : ""}${literalNull ? literalNullHint(documented, name) : ""}`;
|
|
14063
14455
|
const renamedFrom = flag.renamedFrom ?? [];
|
|
14064
14456
|
const option = new Option(`${short}--${name} ${placeholder}`, describe);
|
|
14065
14457
|
if (flag.hidden)
|
|
@@ -14088,13 +14480,13 @@ function addOperationOptions(command, operation, commandSpec, operationSpec) {
|
|
|
14088
14480
|
const short = flag.short ? `-${flag.short}, ` : "";
|
|
14089
14481
|
command.addOption(new Option(`${short}--${name} <${flag.placeholder ?? "value"}>`, `${flag.describe ?? operationSpec.pathParamDocs?.[param] ?? `Set ${name.replaceAll("-", " ")}`} (required)`).makeOptionMandatory());
|
|
14090
14482
|
}
|
|
14091
|
-
for (const slot of ["query", "body"]) {
|
|
14483
|
+
for (const slot of ["query", "body", "headers"]) {
|
|
14092
14484
|
for (const [field, descriptor] of Object.entries(operationSpec[slot] ?? {})) {
|
|
14093
14485
|
if (commandSpec.requestFields && !commandSpec.requestFields.includes(field))
|
|
14094
14486
|
continue;
|
|
14095
14487
|
if (commandSpec.positionals?.includes(field))
|
|
14096
14488
|
continue;
|
|
14097
|
-
addFieldOption(command, operation, field, descriptor);
|
|
14489
|
+
addFieldOption(command, operation, field, descriptor, slot);
|
|
14098
14490
|
}
|
|
14099
14491
|
}
|
|
14100
14492
|
if (commandSpec.allWorkspaces) {
|
|
@@ -14113,7 +14505,8 @@ function addOperationOptions(command, operation, commandSpec, operationSpec) {
|
|
|
14113
14505
|
}
|
|
14114
14506
|
}
|
|
14115
14507
|
if (commandSpec.confirm) {
|
|
14116
|
-
|
|
14508
|
+
const exemptedByDryRun = operationSpec.query?.dryRun !== undefined || operationSpec.body?.dryRun !== undefined;
|
|
14509
|
+
command.option("-y, --yes", exemptedByDryRun ? "Confirm this destructive operation (required unless --dry-run)" : "Confirm this destructive operation (required)");
|
|
14117
14510
|
}
|
|
14118
14511
|
}
|
|
14119
14512
|
|
|
@@ -14212,19 +14605,43 @@ function tableNameFrom(fileName) {
|
|
|
14212
14605
|
function jsonFlag(raw, flagName, kind) {
|
|
14213
14606
|
return coerce(raw, { kind }, { json: true }, flagName);
|
|
14214
14607
|
}
|
|
14608
|
+
function rejectionFields(job) {
|
|
14609
|
+
const rows = job.rowsRejected ?? 0;
|
|
14610
|
+
const cells = job.cellsRejected ?? 0;
|
|
14611
|
+
if (rows === 0 && cells === 0)
|
|
14612
|
+
return {};
|
|
14613
|
+
const samples = (job.rejectedSamples ?? []).map((sample) => sample.line === null || sample.line === undefined ? `${sample.message} (${sample.code})` : `line ${sample.line}: ${sample.message} (${sample.code})`);
|
|
14614
|
+
return {
|
|
14615
|
+
rowsRejected: rows,
|
|
14616
|
+
cellsRejected: cells,
|
|
14617
|
+
...samples.length > 0 ? { rejectedSamples: samples } : {}
|
|
14618
|
+
};
|
|
14619
|
+
}
|
|
14620
|
+
function progressLine(job) {
|
|
14621
|
+
const rows = job.rowsRejected ?? 0;
|
|
14622
|
+
const cells = job.cellsRejected ?? 0;
|
|
14623
|
+
const parts = [];
|
|
14624
|
+
if (rows > 0)
|
|
14625
|
+
parts.push(`${rows} rows rejected`);
|
|
14626
|
+
if (cells > 0)
|
|
14627
|
+
parts.push(`${cells} cells rejected`);
|
|
14628
|
+
const suffix = parts.length > 0 ? `, ${parts.join(", ")}` : "";
|
|
14629
|
+
return `${job.status}… ${job.rowsProcessed} rows${suffix}`;
|
|
14630
|
+
}
|
|
14215
14631
|
async function watchImport(client, workspaceId, job) {
|
|
14216
14632
|
let current = job;
|
|
14217
|
-
let reported2 =
|
|
14633
|
+
let reported2 = null;
|
|
14218
14634
|
while (!IMPORT_SETTLED.has(current.status)) {
|
|
14219
14635
|
await sleep2(IMPORT_POLL_MS);
|
|
14220
14636
|
const next = await client.request(`/api/v2/tables/imports/${encodeURIComponent(current.id)}`, { query: { workspaceId } });
|
|
14221
14637
|
current = next.data;
|
|
14222
|
-
|
|
14223
|
-
|
|
14224
|
-
|
|
14638
|
+
const line = progressLine(current);
|
|
14639
|
+
if (process.stderr.isTTY && line !== reported2) {
|
|
14640
|
+
reported2 = line;
|
|
14641
|
+
process.stderr.write(`\r${source_default.dim(line)}\x1B[K`);
|
|
14225
14642
|
}
|
|
14226
14643
|
}
|
|
14227
|
-
if (process.stderr.isTTY && reported2
|
|
14644
|
+
if (process.stderr.isTTY && reported2 !== null)
|
|
14228
14645
|
process.stderr.write("\r\x1B[K");
|
|
14229
14646
|
return current;
|
|
14230
14647
|
}
|
|
@@ -14246,7 +14663,7 @@ function validateTargetOptions(options) {
|
|
|
14246
14663
|
return intoExisting;
|
|
14247
14664
|
}
|
|
14248
14665
|
function attachTableImport(tables) {
|
|
14249
|
-
tables.command("import").argument("[path]", "Local CSV file to import; omit when using --file-id").description("Import a CSV, into a new table by default").option("--name <name>", "Identifier for the new table: letters, numbers, and underscores; defaults to the sanitized file name").option("--table-id <id>", "Import into this existing table instead of creating one").addOption(new Option("--mode <append|replace>", "How to write into --table-id (default: append)").choices(["append", "replace"])).option("--folder <path>", "Folder path for the new table, as shown in the app").option("--file-id <id>", "Import a file already in the workspace instead of a local path").option("--mapping <json|@file>", "Column mapping (--table-id only)").option("--create-columns <json|@file>", "Columns to create (--table-id only)").option("--timezone <iana>", "Timezone for date parsing, e.g. America/New_York").option("--no-wait", "Return once the import is queued instead of watching it").action(async (path, options, command) => {
|
|
14666
|
+
tables.command("import").argument("[path]", "Local CSV file to import; omit when using --file-id").allowExcessArguments(false).description("Import a CSV, into a new table by default").option("--name <name>", "Identifier for the new table: letters, numbers, and underscores; defaults to the sanitized file name").option("--table-id <id>", "Import into this existing table instead of creating one").addOption(new Option("--mode <append|replace>", "How to write into --table-id (default: append)").choices(["append", "replace"])).option("--folder <path>", "Folder path for the new table, as shown in the app").option("--file-id <id>", "Import a file already in the workspace instead of a local path").option("--mapping <json|@file>", "Column mapping (--table-id only)").option("--create-columns <json|@file>", "Columns to create (--table-id only)").option("--timezone <iana>", "Timezone for date parsing, e.g. America/New_York").option("--no-wait", "Return once the import is queued instead of watching it").action(async (path, options, command) => {
|
|
14250
14667
|
const { client, profile } = clientFrom(command);
|
|
14251
14668
|
const workspaceId = client.requireWorkspace();
|
|
14252
14669
|
if (Boolean(path) === Boolean(options.fileId)) {
|
|
@@ -14302,7 +14719,8 @@ function attachTableImport(tables) {
|
|
|
14302
14719
|
id: job.id,
|
|
14303
14720
|
status: job.status,
|
|
14304
14721
|
tableId: job.tableId,
|
|
14305
|
-
rowsProcessed: job.rowsProcessed
|
|
14722
|
+
rowsProcessed: job.rowsProcessed,
|
|
14723
|
+
...rejectionFields(job)
|
|
14306
14724
|
});
|
|
14307
14725
|
return;
|
|
14308
14726
|
}
|
|
@@ -14314,7 +14732,8 @@ function attachTableImport(tables) {
|
|
|
14314
14732
|
id: finished.id,
|
|
14315
14733
|
status: finished.status,
|
|
14316
14734
|
tableId: finished.tableId,
|
|
14317
|
-
rowsProcessed: finished.rowsProcessed
|
|
14735
|
+
rowsProcessed: finished.rowsProcessed,
|
|
14736
|
+
...rejectionFields(finished)
|
|
14318
14737
|
});
|
|
14319
14738
|
});
|
|
14320
14739
|
}
|
|
@@ -14337,6 +14756,75 @@ function warnRenamedFlag(from, to) {
|
|
|
14337
14756
|
}
|
|
14338
14757
|
|
|
14339
14758
|
// src/runtime/execute.ts
|
|
14759
|
+
var RUN_OUTCOME_OPERATIONS = new Set(["executeWorkflow"]);
|
|
14760
|
+
var FAILED_RUN_STATUS_MESSAGES = {
|
|
14761
|
+
failed: "The workflow run failed.",
|
|
14762
|
+
cancelled: "The workflow run was cancelled."
|
|
14763
|
+
};
|
|
14764
|
+
function runFailureMessage(operation, payload) {
|
|
14765
|
+
if (!RUN_OUTCOME_OPERATIONS.has(operation))
|
|
14766
|
+
return null;
|
|
14767
|
+
if (!payload || typeof payload !== "object" || Array.isArray(payload))
|
|
14768
|
+
return null;
|
|
14769
|
+
const { status, error } = payload;
|
|
14770
|
+
if (typeof status !== "string")
|
|
14771
|
+
return null;
|
|
14772
|
+
const fallback = FAILED_RUN_STATUS_MESSAGES[status];
|
|
14773
|
+
if (!fallback)
|
|
14774
|
+
return null;
|
|
14775
|
+
const reported2 = error?.message;
|
|
14776
|
+
return safeOneLine(typeof reported2 === "string" && reported2 ? reported2 : fallback);
|
|
14777
|
+
}
|
|
14778
|
+
var BULK_OUTCOME_CHECKS = {
|
|
14779
|
+
bulkDeleteFiles: (payload, body) => {
|
|
14780
|
+
if (countOf(payload.deletedItems?.files) > 0)
|
|
14781
|
+
return null;
|
|
14782
|
+
const requested = lengthOf(body?.fileIds);
|
|
14783
|
+
if (requested === 0)
|
|
14784
|
+
return null;
|
|
14785
|
+
return `Deleted nothing: none of the ${requested} requested ${requested === 1 ? "file was" : "files were"} deleted.`;
|
|
14786
|
+
},
|
|
14787
|
+
bulkDeleteTables: (payload) => {
|
|
14788
|
+
const items = payload.deletedItems;
|
|
14789
|
+
const deleted = countOf(items?.tables) + countOf(items?.folders);
|
|
14790
|
+
if (deleted > 0)
|
|
14791
|
+
return null;
|
|
14792
|
+
const missed = lengthOf(payload.notFound) + lengthOf(payload.failed);
|
|
14793
|
+
if (missed === 0)
|
|
14794
|
+
return null;
|
|
14795
|
+
return `Deleted nothing: ${missed} of ${missed} ${missed === 1 ? "item was" : "items were"} not found or could not be deleted.`;
|
|
14796
|
+
},
|
|
14797
|
+
moveTables: (payload) => {
|
|
14798
|
+
if (lengthOf(payload.moved) > 0)
|
|
14799
|
+
return null;
|
|
14800
|
+
const missed = lengthOf(payload.notFound) + lengthOf(payload.failed);
|
|
14801
|
+
if (missed === 0)
|
|
14802
|
+
return null;
|
|
14803
|
+
return `Moved nothing: ${missed} of ${missed} ${missed === 1 ? "item was" : "items were"} not found or could not be moved.`;
|
|
14804
|
+
},
|
|
14805
|
+
moveWorkflows: (payload) => {
|
|
14806
|
+
if (lengthOf(payload.moved) > 0)
|
|
14807
|
+
return null;
|
|
14808
|
+
const failed = lengthOf(payload.failed);
|
|
14809
|
+
if (failed === 0)
|
|
14810
|
+
return null;
|
|
14811
|
+
return `Moved nothing: ${failed} of ${failed} ${failed === 1 ? "workflow" : "workflows"} could not be moved.`;
|
|
14812
|
+
}
|
|
14813
|
+
};
|
|
14814
|
+
function countOf(value) {
|
|
14815
|
+
return typeof value === "number" && Number.isFinite(value) ? value : 0;
|
|
14816
|
+
}
|
|
14817
|
+
function lengthOf(value) {
|
|
14818
|
+
return Array.isArray(value) ? value.length : 0;
|
|
14819
|
+
}
|
|
14820
|
+
function bulkFailureMessage(operation, payload, body) {
|
|
14821
|
+
const check = BULK_OUTCOME_CHECKS[operation];
|
|
14822
|
+
if (!check)
|
|
14823
|
+
return null;
|
|
14824
|
+
if (!payload || typeof payload !== "object" || Array.isArray(payload))
|
|
14825
|
+
return null;
|
|
14826
|
+
return check(payload, body);
|
|
14827
|
+
}
|
|
14340
14828
|
function cursorSlot(operationSpec) {
|
|
14341
14829
|
if (operationSpec.query && "cursor" in operationSpec.query)
|
|
14342
14830
|
return "query";
|
|
@@ -14398,13 +14886,16 @@ async function executeOperation(operation, commandSpec, operationSpec, invocatio
|
|
|
14398
14886
|
const rows = [];
|
|
14399
14887
|
const progress = pageProgress();
|
|
14400
14888
|
let cursor = null;
|
|
14889
|
+
let envelope;
|
|
14401
14890
|
try {
|
|
14402
14891
|
do {
|
|
14403
14892
|
const page = await client.request(request.path, {
|
|
14404
14893
|
method: operationSpec.method,
|
|
14894
|
+
headers: request.headers,
|
|
14405
14895
|
query: paging === "query" ? { ...request.query, ...pageLimit, cursor } : request.query,
|
|
14406
14896
|
body: paging === "body" ? { ...request.body ?? {}, ...pageLimit, ...cursor ? { cursor } : {} } : request.body
|
|
14407
14897
|
});
|
|
14898
|
+
envelope ??= page;
|
|
14408
14899
|
rows.push(...page.data);
|
|
14409
14900
|
cursor = page.nextCursor;
|
|
14410
14901
|
if (cursor && rows.length < limit)
|
|
@@ -14413,17 +14904,22 @@ async function executeOperation(operation, commandSpec, operationSpec, invocatio
|
|
|
14413
14904
|
} finally {
|
|
14414
14905
|
progress.finish();
|
|
14415
14906
|
}
|
|
14416
|
-
renderPage(profile.output, Number.isFinite(limit) ? rows.slice(0, limit) : rows, commandSpec);
|
|
14907
|
+
renderPage(profile.output, Number.isFinite(limit) ? rows.slice(0, limit) : rows, commandSpec, envelope);
|
|
14417
14908
|
return;
|
|
14418
14909
|
}
|
|
14419
14910
|
const result = await client.request(request.path, {
|
|
14420
14911
|
method: operationSpec.method,
|
|
14912
|
+
headers: request.headers,
|
|
14421
14913
|
query: request.query,
|
|
14422
14914
|
body: request.body
|
|
14423
14915
|
});
|
|
14424
|
-
|
|
14916
|
+
const payload = result?.data ?? result;
|
|
14917
|
+
renderResult(operation, profile.output, payload, commandSpec, {
|
|
14425
14918
|
expandedTrace: requestFlags.trace === true
|
|
14426
14919
|
});
|
|
14920
|
+
const failure = runFailureMessage(operation, payload) ?? bulkFailureMessage(operation, payload, request.body);
|
|
14921
|
+
if (failure)
|
|
14922
|
+
throw new SimApiError(failure, 0);
|
|
14427
14923
|
}
|
|
14428
14924
|
|
|
14429
14925
|
// src/commands/protocol/workflow-run-follow.ts
|
|
@@ -14746,7 +15242,7 @@ function runSpec() {
|
|
|
14746
15242
|
return CLI_CONTRACT.getWorkflowRun ?? {};
|
|
14747
15243
|
}
|
|
14748
15244
|
function attachWorkflowRunWait(runs) {
|
|
14749
|
-
runs.command("wait").argument("<runId>", V2_OPERATIONS.getWorkflowRun.pathParamDocs?.runId).description("Wait for a run to reach a terminal state, then show it").addOption(new Option("--workflow <workflowId>", "Workflow ID (required)").makeOptionMandatory()).addOption(new Option(WAIT_TIMEOUT_FLAG, `Give up after this many seconds, or 0 to wait indefinitely (default: ${DEFAULT_WAIT_TIMEOUT_SECONDS}). Bounds the whole wait; SIM_TIMEOUT_SECONDS bounds one request`)).action(async (runId, options, command) => {
|
|
15245
|
+
runs.command("wait").argument("<runId>", V2_OPERATIONS.getWorkflowRun.pathParamDocs?.runId).allowExcessArguments(false).description("Wait for a run to reach a terminal state, then show it").addOption(new Option("--workflow <workflowId>", "Workflow ID (required)").makeOptionMandatory()).addOption(new Option(WAIT_TIMEOUT_FLAG, `Give up after this many seconds, or 0 to wait indefinitely (default: ${DEFAULT_WAIT_TIMEOUT_SECONDS}). Bounds the whole wait; SIM_TIMEOUT_SECONDS bounds one request`)).action(async (runId, options, command) => {
|
|
14750
15246
|
const timeoutSeconds = options.waitTimeout === undefined ? DEFAULT_WAIT_TIMEOUT_SECONDS : parseWaitTimeout(options.waitTimeout);
|
|
14751
15247
|
const { client, profile } = clientFrom(command);
|
|
14752
15248
|
const operation = V2_OPERATIONS.getWorkflowRun;
|
|
@@ -14838,6 +15334,21 @@ function attachProtocolCommands(program2) {
|
|
|
14838
15334
|
// src/terminal/secret-input.ts
|
|
14839
15335
|
import { emitKeypressEvents } from "node:readline";
|
|
14840
15336
|
var MAX_SECRET_LENGTH = 65536;
|
|
15337
|
+
|
|
15338
|
+
class SecretInputCancelledError extends SimApiError {
|
|
15339
|
+
constructor() {
|
|
15340
|
+
super("Secret input cancelled.", 0);
|
|
15341
|
+
this.name = "SecretInputCancelledError";
|
|
15342
|
+
}
|
|
15343
|
+
}
|
|
15344
|
+
function metaCharacter(key) {
|
|
15345
|
+
if (!key.meta || !key.sequence)
|
|
15346
|
+
return "";
|
|
15347
|
+
const character = key.sequence.replace(/^\u001b+/, "");
|
|
15348
|
+
if (character.length !== 1 || character < " " || character === "")
|
|
15349
|
+
return "";
|
|
15350
|
+
return character;
|
|
15351
|
+
}
|
|
14841
15352
|
function promptSecret(input = process.stdin, output = process.stderr) {
|
|
14842
15353
|
if (!input.isTTY) {
|
|
14843
15354
|
throw new SimApiError("Interactive secret input requires a terminal. Pass --value instead.", 0);
|
|
@@ -14871,9 +15382,10 @@ function promptSecret(input = process.stdin, output = process.stderr) {
|
|
|
14871
15382
|
}
|
|
14872
15383
|
};
|
|
14873
15384
|
const fail = (message) => finish(() => reject(new SimApiError(message, 0)));
|
|
15385
|
+
const cancel = () => finish(() => reject(new SecretInputCancelledError));
|
|
14874
15386
|
function onKeypress(text2, key) {
|
|
14875
15387
|
if (key.ctrl && (key.name === "c" || key.name === "d")) {
|
|
14876
|
-
|
|
15388
|
+
cancel();
|
|
14877
15389
|
return;
|
|
14878
15390
|
}
|
|
14879
15391
|
if (key.name === "return" || key.name === "enter") {
|
|
@@ -14892,14 +15404,15 @@ function promptSecret(input = process.stdin, output = process.stderr) {
|
|
|
14892
15404
|
}
|
|
14893
15405
|
return;
|
|
14894
15406
|
}
|
|
14895
|
-
|
|
15407
|
+
const entered = text2 || metaCharacter(key);
|
|
15408
|
+
if (!entered || key.ctrl || key.name === "escape")
|
|
14896
15409
|
return;
|
|
14897
|
-
if (value.length +
|
|
15410
|
+
if (value.length + entered.length > MAX_SECRET_LENGTH) {
|
|
14898
15411
|
fail(`Secret value cannot exceed ${MAX_SECRET_LENGTH} characters.`);
|
|
14899
15412
|
return;
|
|
14900
15413
|
}
|
|
14901
|
-
value +=
|
|
14902
|
-
output.write("*".repeat(Array.from(
|
|
15414
|
+
value += entered;
|
|
15415
|
+
output.write("*".repeat(Array.from(entered).length));
|
|
14903
15416
|
}
|
|
14904
15417
|
input.on("keypress", onKeypress);
|
|
14905
15418
|
});
|
|
@@ -14907,6 +15420,7 @@ function promptSecret(input = process.stdin, output = process.stderr) {
|
|
|
14907
15420
|
|
|
14908
15421
|
// src/commands/secrets.ts
|
|
14909
15422
|
var MAX_SECRET_LENGTH2 = 65536;
|
|
15423
|
+
var CANCELLED_EXIT_CODE = 130;
|
|
14910
15424
|
var SECRET_SCOPES = ["workspace", "personal"];
|
|
14911
15425
|
var SECRET_RESULT = {
|
|
14912
15426
|
fields: [
|
|
@@ -14917,6 +15431,13 @@ var SECRET_RESULT = {
|
|
|
14917
15431
|
{ header: "description" }
|
|
14918
15432
|
]
|
|
14919
15433
|
};
|
|
15434
|
+
function readValueArgument(raw) {
|
|
15435
|
+
if (raw.startsWith("@@"))
|
|
15436
|
+
return raw.slice(1);
|
|
15437
|
+
if (!raw.startsWith("@"))
|
|
15438
|
+
return raw;
|
|
15439
|
+
return readArgumentSource(raw, "value").text;
|
|
15440
|
+
}
|
|
14920
15441
|
function validateSecretValue(value) {
|
|
14921
15442
|
if (value.length === 0)
|
|
14922
15443
|
throw new SimApiError("Secret value cannot be empty.", 0);
|
|
@@ -14925,17 +15446,30 @@ function validateSecretValue(value) {
|
|
|
14925
15446
|
}
|
|
14926
15447
|
return value;
|
|
14927
15448
|
}
|
|
14928
|
-
function
|
|
14929
|
-
if (
|
|
15449
|
+
function validateWorkspaceOnlyFlag(flag, value, scope) {
|
|
15450
|
+
if (value === undefined)
|
|
14930
15451
|
return;
|
|
14931
15452
|
if (scope === "personal") {
|
|
14932
|
-
throw new SimApiError(
|
|
15453
|
+
throw new SimApiError(`--${flag} is only supported for a workspace secret.`, 0);
|
|
15454
|
+
}
|
|
15455
|
+
return value;
|
|
15456
|
+
}
|
|
15457
|
+
async function readSecretValue(options) {
|
|
15458
|
+
if (options.value !== undefined)
|
|
15459
|
+
return validateSecretValue(readValueArgument(options.value));
|
|
15460
|
+
try {
|
|
15461
|
+
return validateSecretValue(await promptSecret());
|
|
15462
|
+
} catch (error) {
|
|
15463
|
+
if (!(error instanceof SecretInputCancelledError))
|
|
15464
|
+
throw error;
|
|
15465
|
+
console.error(source_default.red(`Error: ${error.message}`));
|
|
15466
|
+
return process.exit(CANCELLED_EXIT_CODE);
|
|
14933
15467
|
}
|
|
14934
|
-
return description;
|
|
14935
15468
|
}
|
|
14936
15469
|
async function setSecret(name, options, command) {
|
|
14937
|
-
const description =
|
|
14938
|
-
const
|
|
15470
|
+
const description = validateWorkspaceOnlyFlag("description", options.description, options.scope);
|
|
15471
|
+
const unredacted = validateWorkspaceOnlyFlag("unredacted", options.unredacted, options.scope);
|
|
15472
|
+
const value = await readSecretValue(options);
|
|
14939
15473
|
const { client, profile } = clientFrom(command);
|
|
14940
15474
|
const operation = V2_OPERATIONS.setSecret;
|
|
14941
15475
|
const response = await client.request(resolvePath(operation.path, { name }), {
|
|
@@ -14944,7 +15478,8 @@ async function setSecret(name, options, command) {
|
|
|
14944
15478
|
workspaceId: client.requireWorkspace(),
|
|
14945
15479
|
scope: options.scope,
|
|
14946
15480
|
value,
|
|
14947
|
-
description
|
|
15481
|
+
description,
|
|
15482
|
+
...unredacted === undefined ? {} : { unredacted }
|
|
14948
15483
|
}
|
|
14949
15484
|
});
|
|
14950
15485
|
renderResult("setSecret", profile.output, response.data, SECRET_RESULT);
|
|
@@ -14953,7 +15488,7 @@ function attachSecretCommands(program2) {
|
|
|
14953
15488
|
const secrets = program2.commands.find((command) => command.name() === "secrets");
|
|
14954
15489
|
if (!secrets)
|
|
14955
15490
|
throw new Error("The generated secrets command group is missing");
|
|
14956
|
-
secrets.command("set").argument("<name>", "Secret name, as referenced in workflows").description("Create or replace a named secret").addOption(new Option("--scope <scope>", "Secret ownership scope").choices([...SECRET_SCOPES]).makeOptionMandatory()).option("--value <value>", "Secret value
|
|
15491
|
+
secrets.command("set").argument("<name>", "Secret name, as referenced in workflows").description("Create or replace a named secret").addOption(new Option("--scope <scope>", "Secret ownership scope").choices([...SECRET_SCOPES]).makeOptionMandatory()).option("--value <value|@file>", "Secret value. Passing it inline exposes it to shell history and process listings; @path reads it from a file and @- from stdin, verbatim — a trailing newline is part of the value, so write the file with printf rather than echo. Prefix a literal leading @ with a second one").option("--description <description>", "What the secret is for, shown to teammates; workspace scope only. Omit to leave an existing description unchanged").option("--unredacted", `${V2_OPERATIONS.setSecret.body.unredacted.describe} Pass --no-unredacted to restore redaction`).option("--no-unredacted", "Send --unredacted as false").action((name, options, command) => setSecret(name, options, command));
|
|
14957
15492
|
}
|
|
14958
15493
|
|
|
14959
15494
|
// src/runtime/build.ts
|
|
@@ -15003,6 +15538,35 @@ function addMissingArgumentExample(command) {
|
|
|
15003
15538
|
});
|
|
15004
15539
|
return command;
|
|
15005
15540
|
}
|
|
15541
|
+
function assertNoReservedFlags(command, operation) {
|
|
15542
|
+
for (const option of command.options) {
|
|
15543
|
+
for (const flag of [option.long, option.short]) {
|
|
15544
|
+
if (flag && RESERVED_PROGRAM_FLAGS.has(flag)) {
|
|
15545
|
+
throw new Error(`${operation} declares ${flag}, which the root program already owns; give the flag another name`);
|
|
15546
|
+
}
|
|
15547
|
+
}
|
|
15548
|
+
}
|
|
15549
|
+
}
|
|
15550
|
+
var RESERVED_FLAG_EXEMPTIONS = new Set(["profiles add"]);
|
|
15551
|
+
function assertNoReservedProgramFlags(program2) {
|
|
15552
|
+
const walk = (command, prefix) => {
|
|
15553
|
+
const path = [...prefix, command.name()];
|
|
15554
|
+
const name = path.join(" ");
|
|
15555
|
+
if (!RESERVED_FLAG_EXEMPTIONS.has(name)) {
|
|
15556
|
+
for (const option of command.options) {
|
|
15557
|
+
for (const flag of [option.long, option.short]) {
|
|
15558
|
+
if (flag && RESERVED_PROGRAM_FLAGS.has(flag)) {
|
|
15559
|
+
throw new Error(`"sim ${name}" declares ${flag}, which the root program already owns; give the flag another name`);
|
|
15560
|
+
}
|
|
15561
|
+
}
|
|
15562
|
+
}
|
|
15563
|
+
}
|
|
15564
|
+
for (const child of command.commands)
|
|
15565
|
+
walk(child, path);
|
|
15566
|
+
};
|
|
15567
|
+
for (const child of program2.commands)
|
|
15568
|
+
walk(child, []);
|
|
15569
|
+
}
|
|
15006
15570
|
function configureOperation(command, operation, spec) {
|
|
15007
15571
|
const operationSpec = V2_OPERATIONS[operation];
|
|
15008
15572
|
command.allowExcessArguments(false);
|
|
@@ -15051,11 +15615,11 @@ function configureOperation(command, operation, spec) {
|
|
|
15051
15615
|
}
|
|
15052
15616
|
if (spec.requestFields) {
|
|
15053
15617
|
for (const field of spec.requestFields) {
|
|
15054
|
-
if (!operationSpec.query?.[field] && !operationSpec.body?.[field]) {
|
|
15618
|
+
if (!operationSpec.query?.[field] && !operationSpec.body?.[field] && !operationSpec.headers?.[field]) {
|
|
15055
15619
|
throw new Error(`${operation}.${field} is not a request field`);
|
|
15056
15620
|
}
|
|
15057
15621
|
}
|
|
15058
|
-
for (const slot of ["query", "body"]) {
|
|
15622
|
+
for (const slot of ["query", "body", "headers"]) {
|
|
15059
15623
|
for (const [field, descriptor] of Object.entries(operationSpec[slot] ?? {})) {
|
|
15060
15624
|
if (descriptor.required && field !== PROFILE_INJECTED_FIELD && !spec.requestFields.includes(field)) {
|
|
15061
15625
|
throw new Error(`${operation}.${field} is required but not exposed`);
|
|
@@ -15065,6 +15629,7 @@ function configureOperation(command, operation, spec) {
|
|
|
15065
15629
|
}
|
|
15066
15630
|
command.description(spec.describe ?? operationSpec.summary ?? `${operationSpec.method} ${operationSpec.path}`);
|
|
15067
15631
|
addOperationOptions(command, operation, spec, operationSpec);
|
|
15632
|
+
assertNoReservedFlags(command, operation);
|
|
15068
15633
|
command.action((...invocation) => executeOperation(operation, spec, operationSpec, invocation));
|
|
15069
15634
|
return command;
|
|
15070
15635
|
}
|
|
@@ -15082,7 +15647,14 @@ function addRenamedCommand(groups, operation, spec, from, to) {
|
|
|
15082
15647
|
}
|
|
15083
15648
|
const leaf = buildLeaf(operation, spec, rest[rest.length - 1]);
|
|
15084
15649
|
leaf.hook("preAction", () => warnRenamedCommand(from, to));
|
|
15085
|
-
parent
|
|
15650
|
+
addSubcommand(parent, leaf, { hidden: true });
|
|
15651
|
+
}
|
|
15652
|
+
function addSubcommand(parent, child, options = {}) {
|
|
15653
|
+
const wasLeaf = parent.commands.length === 0 && parent.registeredArguments.length > 0;
|
|
15654
|
+
const usage = wasLeaf ? parent.usage() : null;
|
|
15655
|
+
parent.addCommand(child, { hidden: options.hidden });
|
|
15656
|
+
if (usage !== null)
|
|
15657
|
+
parent.usage(usage);
|
|
15086
15658
|
}
|
|
15087
15659
|
function groupFor(groups, name) {
|
|
15088
15660
|
const existing = groups.get(name);
|
|
@@ -15104,7 +15676,7 @@ function nestedGroup(parent, name, options = {}) {
|
|
|
15104
15676
|
if (existing)
|
|
15105
15677
|
return existing;
|
|
15106
15678
|
const created = new Command(name).description(`Manage ${resourceLabel(parent.name())} ${name.replaceAll("-", " ")}`);
|
|
15107
|
-
parent
|
|
15679
|
+
addSubcommand(parent, created, { hidden: options.hidden });
|
|
15108
15680
|
return created;
|
|
15109
15681
|
}
|
|
15110
15682
|
function addLeafCommand(groups, operation, spec, segments) {
|
|
@@ -15176,24 +15748,63 @@ Profiles work like the AWS CLI: settings live in ~/.sim/config, keys in
|
|
|
15176
15748
|
~/.sim/credentials (0600), or under SIM_CONFIG_DIR when it is set. Select one
|
|
15177
15749
|
with -P, --profile, or SIM_PROFILE.
|
|
15178
15750
|
|
|
15751
|
+
Workflow, knowledge-base and workspace IDs are bare UUIDs. Table IDs carry a
|
|
15752
|
+
tbl_ prefix and file IDs a wf_ one, so wf_ never names a workflow.
|
|
15753
|
+
|
|
15179
15754
|
Examples:
|
|
15180
|
-
$ sim login
|
|
15181
|
-
$ sim profile add acme --workspace ws_123 Reuse that login for a workspace
|
|
15755
|
+
$ sim login Authorize the default profile
|
|
15182
15756
|
$ sim login --profile dev --endpoint http://localhost:3000
|
|
15757
|
+
$ sim profile add acme --workspace 7e2d9c14-6b83-4a55-8f01-c4d3e9a76b28
|
|
15183
15758
|
$ sim workflows list
|
|
15184
15759
|
$ sim logs list --level error --limit 20
|
|
15185
|
-
$ sim --output json
|
|
15186
|
-
$ sim
|
|
15187
|
-
$ sim knowledge search --query "refund policy" --kb
|
|
15188
|
-
$ sim workflows export
|
|
15760
|
+
$ sim configure --set-output json Save a profile output default
|
|
15761
|
+
$ sim --output json tables get tbl_9f3c1a05d4b7426e8c2f0917ab35de64
|
|
15762
|
+
$ sim knowledge search --query "refund policy" --kb 4c1b7f60-2d55-4a3e-9c18-70b6ea2f9d31
|
|
15763
|
+
$ sim workflows export 3a9e21d8-5f47-4c0b-b2ea-91d7c6034ef8 > wf.json
|
|
15189
15764
|
$ sim workflows import --workflow @wf.json
|
|
15190
15765
|
$ sim whoami --profile dev
|
|
15191
15766
|
`;
|
|
15767
|
+
var ROOT_VALUE_FLAGS = new Set([
|
|
15768
|
+
"-P",
|
|
15769
|
+
"--profile",
|
|
15770
|
+
"--endpoint",
|
|
15771
|
+
"-w",
|
|
15772
|
+
"--workspace",
|
|
15773
|
+
"--output"
|
|
15774
|
+
]);
|
|
15775
|
+
function namesASubcommandFirst(rawArgs) {
|
|
15776
|
+
const tokens = rawArgs.slice(2);
|
|
15777
|
+
for (let index = 0;index < tokens.length; index += 1) {
|
|
15778
|
+
const token2 = tokens[index];
|
|
15779
|
+
if (token2 === "--version" || token2 === "-V")
|
|
15780
|
+
return false;
|
|
15781
|
+
if (ROOT_VALUE_FLAGS.has(token2)) {
|
|
15782
|
+
index += 1;
|
|
15783
|
+
continue;
|
|
15784
|
+
}
|
|
15785
|
+
if (token2.startsWith("-"))
|
|
15786
|
+
continue;
|
|
15787
|
+
return true;
|
|
15788
|
+
}
|
|
15789
|
+
return false;
|
|
15790
|
+
}
|
|
15791
|
+
function addVersionOption(program2) {
|
|
15792
|
+
program2.on("option:version", (value) => {
|
|
15793
|
+
if (value === null || value === undefined) {
|
|
15794
|
+
const { rawArgs } = program2;
|
|
15795
|
+
if (!namesASubcommandFirst(rawArgs ?? []))
|
|
15796
|
+
return;
|
|
15797
|
+
program2.error("error: --version reports the Sim CLI version and is not a command flag. A command that acts on a deployment version reads it from --to-version.");
|
|
15798
|
+
}
|
|
15799
|
+
program2.error("error: --version reports the Sim CLI version and takes no value. A command that acts on a deployment version reads it from --to-version.");
|
|
15800
|
+
});
|
|
15801
|
+
program2.version(CLI_VERSION, "-V, --version [none]", "output the version number (takes no value)");
|
|
15802
|
+
}
|
|
15192
15803
|
function buildProgram(options = {}) {
|
|
15193
15804
|
const program2 = new Command;
|
|
15194
15805
|
program2.name("sim").description(PROGRAM_DESCRIPTION);
|
|
15195
15806
|
if (options.version !== false)
|
|
15196
|
-
program2
|
|
15807
|
+
addVersionOption(program2);
|
|
15197
15808
|
program2.option("-P, --profile <name>", "Profile to use (env: SIM_PROFILE)").option("--endpoint <url>", "Sim deployment to talk to (env: SIM_ENDPOINT)").option("-w, --workspace <id>", "Workspace to target (env: SIM_WORKSPACE)").addOption(new Option("--output <format>", "Output format for this command").choices([...OUTPUT_FORMATS]));
|
|
15198
15809
|
program2.addCommand(loginCommand());
|
|
15199
15810
|
program2.addCommand(logoutCommand());
|
|
@@ -15207,6 +15818,7 @@ function buildProgram(options = {}) {
|
|
|
15207
15818
|
attachProtocolCommands(program2);
|
|
15208
15819
|
attachSecretCommands(program2);
|
|
15209
15820
|
program2.addHelpText("after", HELP_EPILOGUE);
|
|
15821
|
+
assertNoReservedProgramFlags(program2);
|
|
15210
15822
|
return program2;
|
|
15211
15823
|
}
|
|
15212
15824
|
|