sim 2.1.2 → 2.1.3-preview.50.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/dist/index.js +1226 -778
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2315,8 +2315,26 @@ import { chmodSync, existsSync, mkdirSync, readFileSync, writeFileSync } from "n
|
|
|
2315
2315
|
import { dirname } from "node:path";
|
|
2316
2316
|
|
|
2317
2317
|
// src/config/ini.ts
|
|
2318
|
+
class ProfileConfigError extends Error {
|
|
2319
|
+
constructor(message) {
|
|
2320
|
+
super(message);
|
|
2321
|
+
this.name = "ProfileConfigError";
|
|
2322
|
+
}
|
|
2323
|
+
}
|
|
2318
2324
|
var SECTION_PATTERN = /^\s*\[([^\]]*)\]\s*$/;
|
|
2319
2325
|
var KV_PATTERN = /^\s*([A-Za-z0-9_.-]+)\s*=\s*(.*?)\s*$/;
|
|
2326
|
+
var FORBIDDEN_CLASS = "\\u0000-\\u001f\\u007f-\\u009f\\u2028\\u2029";
|
|
2327
|
+
var FORBIDDEN_IN_VALUE = new RegExp(`[${FORBIDDEN_CLASS}]`);
|
|
2328
|
+
var FORBIDDEN_IN_NAME = new RegExp(`[${FORBIDDEN_CLASS}[\\]]`);
|
|
2329
|
+
var WRITABLE_KEY = /^[A-Za-z0-9_.-]+$/;
|
|
2330
|
+
function assertWritable(text, what, forbidden) {
|
|
2331
|
+
if (forbidden.test(text)) {
|
|
2332
|
+
throw new ProfileConfigError(`Refusing to write ${what}: line breaks and control characters cannot be stored in the ~/.sim files, because the format has no way to escape them.`);
|
|
2333
|
+
}
|
|
2334
|
+
if (text !== text.trim()) {
|
|
2335
|
+
throw new ProfileConfigError(`Refusing to write ${what}: leading or trailing whitespace is not preserved by the ~/.sim files, so it would not read back as written.`);
|
|
2336
|
+
}
|
|
2337
|
+
}
|
|
2320
2338
|
function parseIni(text) {
|
|
2321
2339
|
const doc = { preamble: [], sections: [] };
|
|
2322
2340
|
let current = null;
|
|
@@ -2327,7 +2345,7 @@ function parseIni(text) {
|
|
|
2327
2345
|
for (const line of lines) {
|
|
2328
2346
|
const sectionMatch = SECTION_PATTERN.exec(line);
|
|
2329
2347
|
if (sectionMatch) {
|
|
2330
|
-
current = { name: sectionMatch[1].trim(), entries: [] };
|
|
2348
|
+
current = { name: sectionMatch[1].trim(), header: line, entries: [] };
|
|
2331
2349
|
doc.sections.push(current);
|
|
2332
2350
|
continue;
|
|
2333
2351
|
}
|
|
@@ -2351,7 +2369,7 @@ function serializeIni(doc) {
|
|
|
2351
2369
|
lines.pop();
|
|
2352
2370
|
if (lines.length > 0)
|
|
2353
2371
|
lines.push("");
|
|
2354
|
-
lines.push(`[${section.name}]`);
|
|
2372
|
+
lines.push(section.header ?? `[${section.name}]`);
|
|
2355
2373
|
for (const entry of section.entries) {
|
|
2356
2374
|
lines.push(entry.kind === "kv" ? `${entry.key} = ${entry.value}` : entry.text);
|
|
2357
2375
|
}
|
|
@@ -2379,9 +2397,23 @@ function listSections(doc) {
|
|
|
2379
2397
|
return doc.sections.map((s) => s.name);
|
|
2380
2398
|
}
|
|
2381
2399
|
function setSectionValues(doc, name, values) {
|
|
2400
|
+
assertWritable(name, `a section named "${name}"`, FORBIDDEN_IN_NAME);
|
|
2401
|
+
for (const [key, value] of Object.entries(values)) {
|
|
2402
|
+
if (!WRITABLE_KEY.test(key)) {
|
|
2403
|
+
throw new ProfileConfigError(`Refusing to write an unreadable setting name "${key}".`);
|
|
2404
|
+
}
|
|
2405
|
+
if (value === null)
|
|
2406
|
+
continue;
|
|
2407
|
+
if (value.trim() === "") {
|
|
2408
|
+
throw new ProfileConfigError(`Refusing to write a blank value for "${key}".`);
|
|
2409
|
+
}
|
|
2410
|
+
assertWritable(value, `a value for "${key}"`, FORBIDDEN_IN_VALUE);
|
|
2411
|
+
}
|
|
2382
2412
|
const matching = doc.sections.filter((s) => s.name === name);
|
|
2383
2413
|
let section = matching[0];
|
|
2384
2414
|
if (!section) {
|
|
2415
|
+
if (Object.values(values).every((value) => value === null))
|
|
2416
|
+
return;
|
|
2385
2417
|
section = { name, entries: [] };
|
|
2386
2418
|
doc.sections.push(section);
|
|
2387
2419
|
matching.push(section);
|
|
@@ -2413,11 +2445,21 @@ function removeSection(doc, name) {
|
|
|
2413
2445
|
var DEFAULT_PROFILE = "default";
|
|
2414
2446
|
var DEFAULT_ENDPOINT = "https://www.sim.ai";
|
|
2415
2447
|
var OUTPUT_FORMATS = ["table", "json", "yaml", "text"];
|
|
2448
|
+
var FORBIDDEN_IN_VALUE_GLOBAL = new RegExp(FORBIDDEN_IN_VALUE.source, "g");
|
|
2449
|
+
function redact(value) {
|
|
2450
|
+
return value.replace(FORBIDDEN_IN_VALUE_GLOBAL, " ");
|
|
2451
|
+
}
|
|
2416
2452
|
|
|
2417
|
-
class
|
|
2453
|
+
class ProfileOverrideError extends ProfileConfigError {
|
|
2418
2454
|
constructor(message) {
|
|
2419
2455
|
super(message);
|
|
2420
|
-
this.name = "
|
|
2456
|
+
this.name = "ProfileOverrideError";
|
|
2457
|
+
}
|
|
2458
|
+
}
|
|
2459
|
+
var PROFILE_NAME_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._-]*$/;
|
|
2460
|
+
function validateProfileName(name) {
|
|
2461
|
+
if (!PROFILE_NAME_PATTERN.test(name)) {
|
|
2462
|
+
throw new ProfileConfigError(`Invalid profile name "${redact(name)}". Use letters, numbers, dots, underscores, or hyphens, starting with a letter or number.`);
|
|
2421
2463
|
}
|
|
2422
2464
|
}
|
|
2423
2465
|
function configSectionName(profile) {
|
|
@@ -2446,24 +2488,24 @@ function resolveAuthenticationProfileName(profile) {
|
|
|
2446
2488
|
return profile;
|
|
2447
2489
|
const authProfile = config.auth_profile.trim();
|
|
2448
2490
|
if (!authProfile) {
|
|
2449
|
-
throw new ProfileConfigError(`Profile "${profile}" has an empty auth_profile.`);
|
|
2491
|
+
throw new ProfileConfigError(`Profile "${redact(profile)}" has an empty auth_profile.`);
|
|
2450
2492
|
}
|
|
2451
2493
|
if (authProfile === profile) {
|
|
2452
|
-
throw new ProfileConfigError(`Profile "${profile}" cannot use itself as auth_profile. Remove the auth_profile setting instead.`);
|
|
2494
|
+
throw new ProfileConfigError(`Profile "${redact(profile)}" cannot use itself as auth_profile. Remove the auth_profile setting instead.`);
|
|
2453
2495
|
}
|
|
2454
2496
|
if (Object.hasOwn(config, "endpoint")) {
|
|
2455
|
-
throw new ProfileConfigError(`Profile "${profile}" cannot set both auth_profile and endpoint. Set the endpoint on authentication profile "${authProfile}".`);
|
|
2497
|
+
throw new ProfileConfigError(`Profile "${redact(profile)}" cannot set both auth_profile and endpoint. Set the endpoint on authentication profile "${redact(authProfile)}".`);
|
|
2456
2498
|
}
|
|
2457
2499
|
if (readCredentialsProfile(profile).api_key) {
|
|
2458
|
-
throw new ProfileConfigError(`Profile "${profile}" cannot set both auth_profile and its own API key. Remove one of them.`);
|
|
2500
|
+
throw new ProfileConfigError(`Profile "${redact(profile)}" cannot set both auth_profile and its own API key. Remove one of them.`);
|
|
2459
2501
|
}
|
|
2460
2502
|
const authConfig = readConfigProfile(authProfile);
|
|
2461
2503
|
const credentials = readCredentialsProfile(authProfile);
|
|
2462
2504
|
if (Object.keys(authConfig).length === 0 && Object.keys(credentials).length === 0) {
|
|
2463
|
-
throw new ProfileConfigError(`Profile "${profile}" references missing auth_profile "${authProfile}".`);
|
|
2505
|
+
throw new ProfileConfigError(`Profile "${redact(profile)}" references missing auth_profile "${redact(authProfile)}".`);
|
|
2464
2506
|
}
|
|
2465
2507
|
if (Object.hasOwn(authConfig, "auth_profile")) {
|
|
2466
|
-
throw new ProfileConfigError(`Profile "${profile}" references auth_profile "${authProfile}", which also has auth_profile set. Authentication profile references cannot be chained.`);
|
|
2508
|
+
throw new ProfileConfigError(`Profile "${redact(profile)}" references auth_profile "${redact(authProfile)}", which also has auth_profile set. Authentication profile references cannot be chained.`);
|
|
2467
2509
|
}
|
|
2468
2510
|
return authProfile;
|
|
2469
2511
|
}
|
|
@@ -2473,7 +2515,7 @@ function listProfiles() {
|
|
|
2473
2515
|
if (section === DEFAULT_PROFILE)
|
|
2474
2516
|
names.add(DEFAULT_PROFILE);
|
|
2475
2517
|
else if (section.startsWith("profile "))
|
|
2476
|
-
names.add(section.slice("profile ".length)
|
|
2518
|
+
names.add(section.slice("profile ".length));
|
|
2477
2519
|
}
|
|
2478
2520
|
for (const section of listSections(readIni(credentialsPath()))) {
|
|
2479
2521
|
names.add(section);
|
|
@@ -2511,10 +2553,10 @@ function requireKnownProfile(name) {
|
|
|
2511
2553
|
if (known.includes(name))
|
|
2512
2554
|
return;
|
|
2513
2555
|
if (known.length === 0) {
|
|
2514
|
-
throw new ProfileConfigError(`Unknown profile "${name}". No profiles are configured yet. Run: sim login --profile ${name}`);
|
|
2556
|
+
throw new ProfileConfigError(`Unknown profile "${redact(name)}". No profiles are configured yet. Run: sim login --profile ${redact(name)}`);
|
|
2515
2557
|
}
|
|
2516
2558
|
const suggestion = nearestProfile(name, known);
|
|
2517
|
-
throw new ProfileConfigError(`Unknown profile "${name}".${suggestion ? ` Did you mean "${suggestion}"?` : ""} Configured profiles: ${known.join(", ")}.`);
|
|
2559
|
+
throw new ProfileConfigError(`Unknown profile "${redact(name)}".${suggestion ? ` Did you mean "${redact(suggestion)}"?` : ""} Configured profiles: ${known.map(redact).join(", ")}.`);
|
|
2518
2560
|
}
|
|
2519
2561
|
function listAuthenticationDependents(authProfile) {
|
|
2520
2562
|
return listProfiles().filter((profile) => profile !== authProfile && readConfigProfile(profile).auth_profile?.trim() === authProfile);
|
|
@@ -2541,18 +2583,31 @@ function deleteProfile(profile) {
|
|
|
2541
2583
|
return { config, credentials };
|
|
2542
2584
|
}
|
|
2543
2585
|
function normalizeEndpoint(endpoint, source) {
|
|
2544
|
-
const trimmed = endpoint.replace(/\/+$/, "");
|
|
2586
|
+
const trimmed = endpoint.trim().replace(/\/+$/, "");
|
|
2587
|
+
if (FORBIDDEN_IN_VALUE.test(trimmed)) {
|
|
2588
|
+
throw new ProfileConfigError(`Invalid endpoint "${redact(endpoint)}" from ${source}. An endpoint cannot contain line breaks or control characters.`);
|
|
2589
|
+
}
|
|
2545
2590
|
let parsed;
|
|
2546
2591
|
try {
|
|
2547
2592
|
parsed = new URL(trimmed);
|
|
2548
2593
|
} catch {
|
|
2549
|
-
throw new ProfileConfigError(`Invalid endpoint "${endpoint}" from ${source}. Use an absolute URL, e.g. ${DEFAULT_ENDPOINT} or http://localhost:3000`);
|
|
2594
|
+
throw new ProfileConfigError(`Invalid endpoint "${redact(endpoint)}" from ${source}. Use an absolute URL, e.g. ${DEFAULT_ENDPOINT} or http://localhost:3000`);
|
|
2550
2595
|
}
|
|
2551
2596
|
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
|
|
2552
2597
|
throw new ProfileConfigError(`Unsupported endpoint scheme "${parsed.protocol.replace(/:$/, "")}" from ${source}. Use http or https, e.g. ${DEFAULT_ENDPOINT}`);
|
|
2553
2598
|
}
|
|
2554
2599
|
return trimmed;
|
|
2555
2600
|
}
|
|
2601
|
+
function normalizeWorkspaceId(workspaceId, source) {
|
|
2602
|
+
const trimmed = workspaceId.trim();
|
|
2603
|
+
if (!trimmed) {
|
|
2604
|
+
throw new ProfileConfigError(`Empty workspace id from ${source}.`);
|
|
2605
|
+
}
|
|
2606
|
+
if (FORBIDDEN_IN_VALUE.test(trimmed)) {
|
|
2607
|
+
throw new ProfileConfigError(`Invalid workspace id "${redact(trimmed)}" from ${source}. A workspace id cannot contain line breaks or control characters.`);
|
|
2608
|
+
}
|
|
2609
|
+
return trimmed;
|
|
2610
|
+
}
|
|
2556
2611
|
function resolve(candidates, fallback, fallbackSource) {
|
|
2557
2612
|
for (const [source, value] of candidates) {
|
|
2558
2613
|
if (value !== null && value !== undefined && value !== "")
|
|
@@ -2560,11 +2615,28 @@ function resolve(candidates, fallback, fallbackSource) {
|
|
|
2560
2615
|
}
|
|
2561
2616
|
return { value: fallback, source: fallbackSource };
|
|
2562
2617
|
}
|
|
2618
|
+
var OVERRIDE_FLAGS = {
|
|
2619
|
+
profile: "--profile",
|
|
2620
|
+
endpoint: "--endpoint",
|
|
2621
|
+
workspaceId: "--workspace"
|
|
2622
|
+
};
|
|
2623
|
+
function refuseBlankOverrides(overrides) {
|
|
2624
|
+
for (const [key, flag] of Object.entries(OVERRIDE_FLAGS)) {
|
|
2625
|
+
const value = overrides[key];
|
|
2626
|
+
if (value !== undefined && value.trim() === "") {
|
|
2627
|
+
throw new ProfileOverrideError(`${flag} requires a value. Omit the flag to fall back to what is configured.`);
|
|
2628
|
+
}
|
|
2629
|
+
}
|
|
2630
|
+
}
|
|
2563
2631
|
function resolveProfile(overrides = {}) {
|
|
2632
|
+
refuseBlankOverrides(overrides);
|
|
2564
2633
|
const named = overrides.profile || process.env.SIM_PROFILE;
|
|
2565
2634
|
const name = named || DEFAULT_PROFILE;
|
|
2566
2635
|
if (named && !overrides.allowUnknownProfile)
|
|
2567
2636
|
requireKnownProfile(named);
|
|
2637
|
+
if (named && overrides.allowUnknownProfile && !listProfiles().includes(named)) {
|
|
2638
|
+
validateProfileName(named);
|
|
2639
|
+
}
|
|
2568
2640
|
const config = readConfigProfile(name);
|
|
2569
2641
|
const authProfile = resolveAuthenticationProfileName(name);
|
|
2570
2642
|
const authConfig = authProfile === name ? config : readConfigProfile(authProfile);
|
|
@@ -2590,7 +2662,7 @@ function resolveProfile(overrides = {}) {
|
|
|
2590
2662
|
["config", config.output]
|
|
2591
2663
|
], "table", "default");
|
|
2592
2664
|
if (!OUTPUT_FORMATS.includes(output.value)) {
|
|
2593
|
-
throw new ProfileConfigError(`Unknown output format "${output.value}" from ${output.source}. Use one of: ${OUTPUT_FORMATS.join(", ")}`);
|
|
2665
|
+
throw new ProfileConfigError(`Unknown output format "${redact(String(output.value))}" from ${output.source}. Use one of: ${OUTPUT_FORMATS.join(", ")}`);
|
|
2594
2666
|
}
|
|
2595
2667
|
return {
|
|
2596
2668
|
name,
|
|
@@ -6518,7 +6590,8 @@ var V2_OPERATIONS = {
|
|
|
6518
6590
|
version: "Numeric deployment version."
|
|
6519
6591
|
},
|
|
6520
6592
|
responseMode: "json",
|
|
6521
|
-
summary: "Activate Workflow Version"
|
|
6593
|
+
summary: "Activate Workflow Version",
|
|
6594
|
+
personalKeyOnly: true
|
|
6522
6595
|
},
|
|
6523
6596
|
addTableColumn: {
|
|
6524
6597
|
method: "POST",
|
|
@@ -6565,6 +6638,7 @@ var V2_OPERATIONS = {
|
|
|
6565
6638
|
pathParamDocs: { knowledgeBaseId: "Unique knowledge base identifier." },
|
|
6566
6639
|
responseMode: "json",
|
|
6567
6640
|
summary: "Index Workspace Files",
|
|
6641
|
+
personalKeyOnly: true,
|
|
6568
6642
|
body: {
|
|
6569
6643
|
workspaceId: {
|
|
6570
6644
|
kind: "string",
|
|
@@ -6585,6 +6659,7 @@ var V2_OPERATIONS = {
|
|
|
6585
6659
|
pathParamDocs: { workflowId: "Unique workflow identifier." },
|
|
6586
6660
|
responseMode: "json",
|
|
6587
6661
|
summary: "Apply Workflow Operations",
|
|
6662
|
+
personalKeyOnly: true,
|
|
6588
6663
|
query: {
|
|
6589
6664
|
dryRun: {
|
|
6590
6665
|
kind: "boolean",
|
|
@@ -6684,6 +6759,7 @@ var V2_OPERATIONS = {
|
|
|
6684
6759
|
pathParamDocs: { knowledgeBaseId: "Unique knowledge base identifier." },
|
|
6685
6760
|
responseMode: "json",
|
|
6686
6761
|
summary: "Bulk Save Tag Definitions",
|
|
6762
|
+
personalKeyOnly: true,
|
|
6687
6763
|
body: {
|
|
6688
6764
|
workspaceId: {
|
|
6689
6765
|
kind: "string",
|
|
@@ -6707,6 +6783,7 @@ var V2_OPERATIONS = {
|
|
|
6707
6783
|
},
|
|
6708
6784
|
responseMode: "json",
|
|
6709
6785
|
summary: "Bulk Update Chunks",
|
|
6786
|
+
personalKeyOnly: true,
|
|
6710
6787
|
body: {
|
|
6711
6788
|
workspaceId: {
|
|
6712
6789
|
kind: "string",
|
|
@@ -6722,7 +6799,7 @@ var V2_OPERATIONS = {
|
|
|
6722
6799
|
chunkIds: {
|
|
6723
6800
|
kind: "array",
|
|
6724
6801
|
required: true,
|
|
6725
|
-
describe: "Chunks to operate on, by identifier.
|
|
6802
|
+
describe: "Chunks to operate on, by identifier. An id naming no chunk in the document is reported in errors and does not fail the request."
|
|
6726
6803
|
}
|
|
6727
6804
|
}
|
|
6728
6805
|
},
|
|
@@ -6733,6 +6810,7 @@ var V2_OPERATIONS = {
|
|
|
6733
6810
|
pathParamDocs: { knowledgeBaseId: "Unique knowledge base identifier." },
|
|
6734
6811
|
responseMode: "json",
|
|
6735
6812
|
summary: "Bulk Enable or Disable Documents",
|
|
6813
|
+
personalKeyOnly: true,
|
|
6736
6814
|
body: {
|
|
6737
6815
|
workspaceId: {
|
|
6738
6816
|
kind: "string",
|
|
@@ -6957,6 +7035,7 @@ var V2_OPERATIONS = {
|
|
|
6957
7035
|
pathParams: [],
|
|
6958
7036
|
responseMode: "json",
|
|
6959
7037
|
summary: "Create Credential Connection",
|
|
7038
|
+
personalKeyOnly: true,
|
|
6960
7039
|
body: {
|
|
6961
7040
|
workspaceId: {
|
|
6962
7041
|
kind: "string",
|
|
@@ -7132,6 +7211,7 @@ var V2_OPERATIONS = {
|
|
|
7132
7211
|
},
|
|
7133
7212
|
responseMode: "json",
|
|
7134
7213
|
summary: "Create Chunk",
|
|
7214
|
+
personalKeyOnly: true,
|
|
7135
7215
|
body: {
|
|
7136
7216
|
workspaceId: {
|
|
7137
7217
|
kind: "string",
|
|
@@ -7157,6 +7237,7 @@ var V2_OPERATIONS = {
|
|
|
7157
7237
|
pathParamDocs: { knowledgeBaseId: "Unique knowledge base identifier." },
|
|
7158
7238
|
responseMode: "json",
|
|
7159
7239
|
summary: "Create Knowledge Connector",
|
|
7240
|
+
personalKeyOnly: true,
|
|
7160
7241
|
body: {
|
|
7161
7242
|
workspaceId: {
|
|
7162
7243
|
kind: "string",
|
|
@@ -7272,6 +7353,7 @@ var V2_OPERATIONS = {
|
|
|
7272
7353
|
pathParamDocs: { knowledgeBaseId: "Unique knowledge base identifier." },
|
|
7273
7354
|
responseMode: "json",
|
|
7274
7355
|
summary: "Create Tag",
|
|
7356
|
+
personalKeyOnly: true,
|
|
7275
7357
|
body: {
|
|
7276
7358
|
workspaceId: {
|
|
7277
7359
|
kind: "string",
|
|
@@ -7379,6 +7461,7 @@ var V2_OPERATIONS = {
|
|
|
7379
7461
|
pathParams: [],
|
|
7380
7462
|
responseMode: "json",
|
|
7381
7463
|
summary: "Create Service-Account Credential",
|
|
7464
|
+
personalKeyOnly: true,
|
|
7382
7465
|
body: {
|
|
7383
7466
|
workspaceId: {
|
|
7384
7467
|
kind: "string",
|
|
@@ -7417,6 +7500,7 @@ var V2_OPERATIONS = {
|
|
|
7417
7500
|
pathParams: [],
|
|
7418
7501
|
responseMode: "json",
|
|
7419
7502
|
summary: "Create Skill",
|
|
7503
|
+
personalKeyOnly: true,
|
|
7420
7504
|
body: {
|
|
7421
7505
|
workspaceId: {
|
|
7422
7506
|
kind: "string",
|
|
@@ -7632,6 +7716,7 @@ var V2_OPERATIONS = {
|
|
|
7632
7716
|
pathParams: [],
|
|
7633
7717
|
responseMode: "json",
|
|
7634
7718
|
summary: "Create Workflow MCP Server",
|
|
7719
|
+
personalKeyOnly: true,
|
|
7635
7720
|
body: {
|
|
7636
7721
|
workspaceId: {
|
|
7637
7722
|
kind: "string",
|
|
@@ -7662,6 +7747,7 @@ var V2_OPERATIONS = {
|
|
|
7662
7747
|
pathParamDocs: { credentialId: "Credential to disconnect." },
|
|
7663
7748
|
responseMode: "json",
|
|
7664
7749
|
summary: "Disconnect Credential",
|
|
7750
|
+
personalKeyOnly: true,
|
|
7665
7751
|
query: {
|
|
7666
7752
|
workspaceId: {
|
|
7667
7753
|
kind: "string",
|
|
@@ -7752,6 +7838,7 @@ var V2_OPERATIONS = {
|
|
|
7752
7838
|
},
|
|
7753
7839
|
responseMode: "json",
|
|
7754
7840
|
summary: "Delete Chunk",
|
|
7841
|
+
personalKeyOnly: true,
|
|
7755
7842
|
query: {
|
|
7756
7843
|
workspaceId: {
|
|
7757
7844
|
kind: "string",
|
|
@@ -7770,6 +7857,7 @@ var V2_OPERATIONS = {
|
|
|
7770
7857
|
},
|
|
7771
7858
|
responseMode: "json",
|
|
7772
7859
|
summary: "Delete Knowledge Connector",
|
|
7860
|
+
personalKeyOnly: true,
|
|
7773
7861
|
query: {
|
|
7774
7862
|
workspaceId: {
|
|
7775
7863
|
kind: "string",
|
|
@@ -7840,6 +7928,7 @@ var V2_OPERATIONS = {
|
|
|
7840
7928
|
},
|
|
7841
7929
|
responseMode: "json",
|
|
7842
7930
|
summary: "Delete Tag",
|
|
7931
|
+
personalKeyOnly: true,
|
|
7843
7932
|
query: {
|
|
7844
7933
|
workspaceId: {
|
|
7845
7934
|
kind: "string",
|
|
@@ -7855,6 +7944,7 @@ var V2_OPERATIONS = {
|
|
|
7855
7944
|
pathParamDocs: { knowledgeBaseId: "Unique knowledge base identifier." },
|
|
7856
7945
|
responseMode: "json",
|
|
7857
7946
|
summary: "Delete Tag Definitions",
|
|
7947
|
+
personalKeyOnly: true,
|
|
7858
7948
|
query: {
|
|
7859
7949
|
workspaceId: {
|
|
7860
7950
|
kind: "string",
|
|
@@ -7886,9 +7976,10 @@ var V2_OPERATIONS = {
|
|
|
7886
7976
|
method: "DELETE",
|
|
7887
7977
|
path: "/api/v2/secrets/[name]",
|
|
7888
7978
|
pathParams: ["name"],
|
|
7889
|
-
pathParamDocs: { name: "Secret to
|
|
7979
|
+
pathParamDocs: { name: "Secret to delete." },
|
|
7890
7980
|
responseMode: "json",
|
|
7891
7981
|
summary: "Delete Secret",
|
|
7982
|
+
personalKeyOnly: true,
|
|
7892
7983
|
query: {
|
|
7893
7984
|
workspaceId: {
|
|
7894
7985
|
kind: "string",
|
|
@@ -7912,6 +8003,7 @@ var V2_OPERATIONS = {
|
|
|
7912
8003
|
},
|
|
7913
8004
|
responseMode: "json",
|
|
7914
8005
|
summary: "Delete Skill",
|
|
8006
|
+
personalKeyOnly: true,
|
|
7915
8007
|
query: {
|
|
7916
8008
|
workspaceId: { kind: "string", required: true, describe: "Workspace that owns the skill." }
|
|
7917
8009
|
}
|
|
@@ -8022,7 +8114,8 @@ var V2_OPERATIONS = {
|
|
|
8022
8114
|
pathParams: ["workflowId"],
|
|
8023
8115
|
pathParamDocs: { workflowId: "Unique workflow identifier." },
|
|
8024
8116
|
responseMode: "json",
|
|
8025
|
-
summary: "Delete Workflow Chat Deployment"
|
|
8117
|
+
summary: "Delete Workflow Chat Deployment",
|
|
8118
|
+
personalKeyOnly: true
|
|
8026
8119
|
},
|
|
8027
8120
|
deleteWorkflowFolder: {
|
|
8028
8121
|
method: "DELETE",
|
|
@@ -8072,7 +8165,8 @@ var V2_OPERATIONS = {
|
|
|
8072
8165
|
pathParams: ["serverId"],
|
|
8073
8166
|
pathParamDocs: { serverId: "Unique workflow-MCP server identifier." },
|
|
8074
8167
|
responseMode: "json",
|
|
8075
|
-
summary: "Delete Workflow MCP Server"
|
|
8168
|
+
summary: "Delete Workflow MCP Server",
|
|
8169
|
+
personalKeyOnly: true
|
|
8076
8170
|
},
|
|
8077
8171
|
deployWorkflow: {
|
|
8078
8172
|
method: "POST",
|
|
@@ -8081,6 +8175,7 @@ var V2_OPERATIONS = {
|
|
|
8081
8175
|
pathParamDocs: { workflowId: "Unique workflow identifier." },
|
|
8082
8176
|
responseMode: "json",
|
|
8083
8177
|
summary: "Deploy Workflow",
|
|
8178
|
+
personalKeyOnly: true,
|
|
8084
8179
|
body: {
|
|
8085
8180
|
name: { kind: "string", describe: "Optional label for the deployment version." },
|
|
8086
8181
|
description: {
|
|
@@ -8096,6 +8191,7 @@ var V2_OPERATIONS = {
|
|
|
8096
8191
|
pathParamDocs: { serverId: "Unique workflow-MCP server identifier." },
|
|
8097
8192
|
responseMode: "json",
|
|
8098
8193
|
summary: "Publish Workflow As MCP Tool",
|
|
8194
|
+
personalKeyOnly: true,
|
|
8099
8195
|
body: {
|
|
8100
8196
|
workflowId: {
|
|
8101
8197
|
kind: "string",
|
|
@@ -8236,6 +8332,7 @@ var V2_OPERATIONS = {
|
|
|
8236
8332
|
pathParamDocs: { auditLogId: "Audit-log entry identifier." },
|
|
8237
8333
|
responseMode: "json",
|
|
8238
8334
|
summary: "Get Audit Log",
|
|
8335
|
+
personalKeyOnly: true,
|
|
8239
8336
|
query: {
|
|
8240
8337
|
organizationId: {
|
|
8241
8338
|
kind: "string",
|
|
@@ -8301,7 +8398,7 @@ var V2_OPERATIONS = {
|
|
|
8301
8398
|
kind: "enum",
|
|
8302
8399
|
values: ["active", "archived"],
|
|
8303
8400
|
default: "active",
|
|
8304
|
-
describe: "Which lifecycle set to read from: `active` (default) resolves live files only and returns `404` for a file a
|
|
8401
|
+
describe: "Which lifecycle set to read from: `active` (default) resolves live files only and returns `404` for a file a delete soft-deleted; `archived` also resolves soft-deleted files, so metadata stays readable before the file is restored. Authorization is identical for both."
|
|
8305
8402
|
}
|
|
8306
8403
|
}
|
|
8307
8404
|
},
|
|
@@ -8364,6 +8461,7 @@ var V2_OPERATIONS = {
|
|
|
8364
8461
|
},
|
|
8365
8462
|
responseMode: "json",
|
|
8366
8463
|
summary: "Get Chunk",
|
|
8464
|
+
personalKeyOnly: true,
|
|
8367
8465
|
query: {
|
|
8368
8466
|
workspaceId: {
|
|
8369
8467
|
kind: "string",
|
|
@@ -8382,6 +8480,7 @@ var V2_OPERATIONS = {
|
|
|
8382
8480
|
},
|
|
8383
8481
|
responseMode: "json",
|
|
8384
8482
|
summary: "Get Knowledge Connector",
|
|
8483
|
+
personalKeyOnly: true,
|
|
8385
8484
|
query: {
|
|
8386
8485
|
workspaceId: {
|
|
8387
8486
|
kind: "string",
|
|
@@ -8489,6 +8588,7 @@ var V2_OPERATIONS = {
|
|
|
8489
8588
|
pathParamDocs: { knowledgeBaseId: "Unique knowledge base identifier." },
|
|
8490
8589
|
responseMode: "json",
|
|
8491
8590
|
summary: "Get Next Tag Slot",
|
|
8591
|
+
personalKeyOnly: true,
|
|
8492
8592
|
query: {
|
|
8493
8593
|
workspaceId: {
|
|
8494
8594
|
kind: "string",
|
|
@@ -8656,7 +8756,8 @@ var V2_OPERATIONS = {
|
|
|
8656
8756
|
pathParams: ["workflowId"],
|
|
8657
8757
|
pathParamDocs: { workflowId: "Unique workflow identifier." },
|
|
8658
8758
|
responseMode: "json",
|
|
8659
|
-
summary: "Get Workflow Chat Deployment"
|
|
8759
|
+
summary: "Get Workflow Chat Deployment",
|
|
8760
|
+
personalKeyOnly: true
|
|
8660
8761
|
},
|
|
8661
8762
|
getWorkflowDeployment: {
|
|
8662
8763
|
method: "GET",
|
|
@@ -8672,7 +8773,8 @@ var V2_OPERATIONS = {
|
|
|
8672
8773
|
pathParams: ["serverId"],
|
|
8673
8774
|
pathParamDocs: { serverId: "Unique workflow-MCP server identifier." },
|
|
8674
8775
|
responseMode: "json",
|
|
8675
|
-
summary: "Get Workflow MCP Server"
|
|
8776
|
+
summary: "Get Workflow MCP Server",
|
|
8777
|
+
personalKeyOnly: true
|
|
8676
8778
|
},
|
|
8677
8779
|
getWorkflowRun: {
|
|
8678
8780
|
method: "GET",
|
|
@@ -8739,6 +8841,7 @@ var V2_OPERATIONS = {
|
|
|
8739
8841
|
},
|
|
8740
8842
|
responseMode: "json",
|
|
8741
8843
|
summary: "Grant Skill Editor",
|
|
8844
|
+
personalKeyOnly: true,
|
|
8742
8845
|
body: {
|
|
8743
8846
|
workspaceId: { kind: "string", required: true, describe: "Workspace that owns the skill." },
|
|
8744
8847
|
email: {
|
|
@@ -8779,6 +8882,7 @@ var V2_OPERATIONS = {
|
|
|
8779
8882
|
pathParams: [],
|
|
8780
8883
|
responseMode: "json",
|
|
8781
8884
|
summary: "List Audit Logs",
|
|
8885
|
+
personalKeyOnly: true,
|
|
8782
8886
|
query: {
|
|
8783
8887
|
action: { kind: "string", describe: "Filter by exact action name." },
|
|
8784
8888
|
resourceType: {
|
|
@@ -9116,7 +9220,7 @@ var V2_OPERATIONS = {
|
|
|
9116
9220
|
kind: "enum",
|
|
9117
9221
|
values: ["active", "archived"],
|
|
9118
9222
|
default: "active",
|
|
9119
|
-
describe: "Which lifecycle set to list: `active` (default) returns live folders only; `archived` returns folders a recursive
|
|
9223
|
+
describe: "Which lifecycle set to list: `active` (default) returns live folders only; `archived` returns folders a recursive delete soft-deleted, which is how a caller finds a path to hand to the folder restore. Authorization is identical for both."
|
|
9120
9224
|
}
|
|
9121
9225
|
}
|
|
9122
9226
|
},
|
|
@@ -9158,7 +9262,7 @@ var V2_OPERATIONS = {
|
|
|
9158
9262
|
kind: "enum",
|
|
9159
9263
|
values: ["active", "archived"],
|
|
9160
9264
|
default: "active",
|
|
9161
|
-
describe: "Which lifecycle set to list: `active` (default) for live files, `archived` for files a
|
|
9265
|
+
describe: "Which lifecycle set to list: `active` (default) for live files, `archived` for files a delete soft-deleted. `folderPath` resolves against active folders only, so pairing it with `scope=archived` returns an empty page when the containing folder was archived too."
|
|
9162
9266
|
},
|
|
9163
9267
|
search: {
|
|
9164
9268
|
kind: "string",
|
|
@@ -9246,6 +9350,7 @@ var V2_OPERATIONS = {
|
|
|
9246
9350
|
},
|
|
9247
9351
|
responseMode: "json",
|
|
9248
9352
|
summary: "List Chunks",
|
|
9353
|
+
personalKeyOnly: true,
|
|
9249
9354
|
query: {
|
|
9250
9355
|
workspaceId: {
|
|
9251
9356
|
kind: "string",
|
|
@@ -9295,6 +9400,7 @@ var V2_OPERATIONS = {
|
|
|
9295
9400
|
},
|
|
9296
9401
|
responseMode: "json",
|
|
9297
9402
|
summary: "List Knowledge Connector Documents",
|
|
9403
|
+
personalKeyOnly: true,
|
|
9298
9404
|
query: {
|
|
9299
9405
|
workspaceId: {
|
|
9300
9406
|
kind: "string",
|
|
@@ -9323,6 +9429,7 @@ var V2_OPERATIONS = {
|
|
|
9323
9429
|
pathParamDocs: { knowledgeBaseId: "Unique knowledge base identifier." },
|
|
9324
9430
|
responseMode: "json",
|
|
9325
9431
|
summary: "List Knowledge Connectors",
|
|
9432
|
+
personalKeyOnly: true,
|
|
9326
9433
|
query: {
|
|
9327
9434
|
workspaceId: {
|
|
9328
9435
|
kind: "string",
|
|
@@ -9466,6 +9573,7 @@ var V2_OPERATIONS = {
|
|
|
9466
9573
|
pathParamDocs: { knowledgeBaseId: "Unique knowledge base identifier." },
|
|
9467
9574
|
responseMode: "json",
|
|
9468
9575
|
summary: "List Tag Usage",
|
|
9576
|
+
personalKeyOnly: true,
|
|
9469
9577
|
query: {
|
|
9470
9578
|
workspaceId: {
|
|
9471
9579
|
kind: "string",
|
|
@@ -9557,14 +9665,14 @@ var V2_OPERATIONS = {
|
|
|
9557
9665
|
},
|
|
9558
9666
|
includeJobRuns: {
|
|
9559
9667
|
kind: "boolean",
|
|
9560
|
-
describe: 'Whether Chat and Sim-agent job runs join the sequence alongside workflow runs. Job runs report `kind: "job"`, carry no `workflow` summary, and never carry a cost ledger. They are dropped entirely — not partially matched — whenever a filter they cannot answer is set
|
|
9668
|
+
describe: 'Whether Chat and Sim-agent job runs join the sequence alongside workflow runs. Job runs report `kind: "job"`, carry no `workflow` summary, and never carry a cost ledger. They are dropped entirely — not partially matched — whenever a filter they cannot answer is set: by workflow, workflow name, folder, model, or status. A filter therefore never means two different things across the union. Accepted only when sorting by `startedAt`: job runs record cost as a document and no comparable status, so they cannot participate in the other orderings.'
|
|
9561
9669
|
},
|
|
9562
9670
|
runId: { kind: "string", describe: "Exact run identifier to match." },
|
|
9563
9671
|
sortBy: {
|
|
9564
9672
|
kind: "enum",
|
|
9565
9673
|
values: ["startedAt", "durationMs", "cost", "status"],
|
|
9566
9674
|
default: "startedAt",
|
|
9567
|
-
describe: "Field used to sort the result. `durationMs` and `cost` are null until a run settles; those runs order as though the value were below every recorded one, so they trail an ascending page and lead a descending one. Only `startedAt` can order Chat and Sim-agent job runs, so any other value is rejected
|
|
9675
|
+
describe: "Field used to sort the result. `durationMs` and `cost` are null until a run settles; those runs order as though the value were below every recorded one, so they trail an ascending page and lead a descending one. Only `startedAt` can order Chat and Sim-agent job runs, so any other value is rejected when job runs are included."
|
|
9568
9676
|
},
|
|
9569
9677
|
sortOrder: {
|
|
9570
9678
|
kind: "enum",
|
|
@@ -9624,6 +9732,7 @@ var V2_OPERATIONS = {
|
|
|
9624
9732
|
pathParamDocs: { mcpServerId: "Unique MCP server identifier." },
|
|
9625
9733
|
responseMode: "json",
|
|
9626
9734
|
summary: "List MCP Server Tools",
|
|
9735
|
+
personalKeyOnly: true,
|
|
9627
9736
|
query: {
|
|
9628
9737
|
workspaceId: {
|
|
9629
9738
|
kind: "string",
|
|
@@ -9642,6 +9751,7 @@ var V2_OPERATIONS = {
|
|
|
9642
9751
|
pathParams: [],
|
|
9643
9752
|
responseMode: "json",
|
|
9644
9753
|
summary: "List Secrets",
|
|
9754
|
+
personalKeyOnly: true,
|
|
9645
9755
|
query: {
|
|
9646
9756
|
workspaceId: {
|
|
9647
9757
|
kind: "string",
|
|
@@ -9834,7 +9944,7 @@ var V2_OPERATIONS = {
|
|
|
9834
9944
|
kind: "enum",
|
|
9835
9945
|
values: ["active", "archived"],
|
|
9836
9946
|
default: "active",
|
|
9837
|
-
describe: "Which lifecycle set to list: `active` (default) for live tables, `archived` for tables a
|
|
9947
|
+
describe: "Which lifecycle set to list: `active` (default) for live tables, `archived` for tables a delete archived and a table restore can bring back. `folderPath` resolves against active folders only, so pairing it with `scope=archived` returns an empty page when the containing folder was archived too."
|
|
9838
9948
|
},
|
|
9839
9949
|
folderPath: {
|
|
9840
9950
|
kind: "string",
|
|
@@ -9977,6 +10087,7 @@ var V2_OPERATIONS = {
|
|
|
9977
10087
|
pathParams: [],
|
|
9978
10088
|
responseMode: "json",
|
|
9979
10089
|
summary: "List Workflow MCP Servers",
|
|
10090
|
+
personalKeyOnly: true,
|
|
9980
10091
|
query: {
|
|
9981
10092
|
workspaceId: {
|
|
9982
10093
|
kind: "string",
|
|
@@ -10012,7 +10123,8 @@ var V2_OPERATIONS = {
|
|
|
10012
10123
|
pathParams: ["serverId"],
|
|
10013
10124
|
pathParamDocs: { serverId: "Unique workflow-MCP server identifier." },
|
|
10014
10125
|
responseMode: "json",
|
|
10015
|
-
summary: "List Workflow MCP Tools"
|
|
10126
|
+
summary: "List Workflow MCP Tools",
|
|
10127
|
+
personalKeyOnly: true
|
|
10016
10128
|
},
|
|
10017
10129
|
listWorkflowRuns: {
|
|
10018
10130
|
method: "GET",
|
|
@@ -10069,7 +10181,7 @@ var V2_OPERATIONS = {
|
|
|
10069
10181
|
kind: "enum",
|
|
10070
10182
|
values: ["active", "archived"],
|
|
10071
10183
|
default: "active",
|
|
10072
|
-
describe: "Which lifecycle set to list: `active` (default) for live workflows, `archived` for workflows a `DELETE` archived.
|
|
10184
|
+
describe: "Which lifecycle set to list: `active` (default) for live workflows, `archived` for workflows a `DELETE` archived. The folder filter resolves against active folders only, so pairing it with `archived` returns an empty page when the containing folder was archived too."
|
|
10073
10185
|
},
|
|
10074
10186
|
folderPath: {
|
|
10075
10187
|
kind: "string",
|
|
@@ -10372,6 +10484,7 @@ var V2_OPERATIONS = {
|
|
|
10372
10484
|
pathParamDocs: { workflowId: "Unique workflow identifier." },
|
|
10373
10485
|
responseMode: "json",
|
|
10374
10486
|
summary: "Create or Replace Workflow Chat Deployment",
|
|
10487
|
+
personalKeyOnly: true,
|
|
10375
10488
|
body: {
|
|
10376
10489
|
identifier: {
|
|
10377
10490
|
kind: "string",
|
|
@@ -10424,6 +10537,7 @@ var V2_OPERATIONS = {
|
|
|
10424
10537
|
pathParamDocs: { workflowId: "Unique workflow identifier." },
|
|
10425
10538
|
responseMode: "json",
|
|
10426
10539
|
summary: "Replace Workflow State",
|
|
10540
|
+
personalKeyOnly: true,
|
|
10427
10541
|
query: {
|
|
10428
10542
|
dryRun: {
|
|
10429
10543
|
kind: "boolean",
|
|
@@ -10477,7 +10591,7 @@ var V2_OPERATIONS = {
|
|
|
10477
10591
|
path: {
|
|
10478
10592
|
kind: "string",
|
|
10479
10593
|
required: true,
|
|
10480
|
-
describe: "Path of the archived folder to restore, as reported by
|
|
10594
|
+
describe: "Path of the archived folder to restore, as reported by an archived-scope folder list."
|
|
10481
10595
|
}
|
|
10482
10596
|
}
|
|
10483
10597
|
},
|
|
@@ -10522,7 +10636,7 @@ var V2_OPERATIONS = {
|
|
|
10522
10636
|
path: {
|
|
10523
10637
|
kind: "string",
|
|
10524
10638
|
required: true,
|
|
10525
|
-
describe: "Path the folder held when
|
|
10639
|
+
describe: "Path the folder held when a folder delete archived it."
|
|
10526
10640
|
}
|
|
10527
10641
|
}
|
|
10528
10642
|
},
|
|
@@ -10562,7 +10676,8 @@ var V2_OPERATIONS = {
|
|
|
10562
10676
|
version: "Numeric deployment version, or `active` for the currently live version."
|
|
10563
10677
|
},
|
|
10564
10678
|
responseMode: "json",
|
|
10565
|
-
summary: "Revert Workflow To Version"
|
|
10679
|
+
summary: "Revert Workflow To Version",
|
|
10680
|
+
personalKeyOnly: true
|
|
10566
10681
|
},
|
|
10567
10682
|
revokeSkillEditor: {
|
|
10568
10683
|
method: "DELETE",
|
|
@@ -10573,6 +10688,7 @@ var V2_OPERATIONS = {
|
|
|
10573
10688
|
},
|
|
10574
10689
|
responseMode: "json",
|
|
10575
10690
|
summary: "Revoke Skill Editor",
|
|
10691
|
+
personalKeyOnly: true,
|
|
10576
10692
|
query: {
|
|
10577
10693
|
workspaceId: { kind: "string", required: true, describe: "Workspace that owns the skill." },
|
|
10578
10694
|
email: {
|
|
@@ -10589,6 +10705,7 @@ var V2_OPERATIONS = {
|
|
|
10589
10705
|
pathParamDocs: { workflowId: "Unique workflow identifier." },
|
|
10590
10706
|
responseMode: "json",
|
|
10591
10707
|
summary: "Rollback Workflow",
|
|
10708
|
+
personalKeyOnly: true,
|
|
10592
10709
|
body: {
|
|
10593
10710
|
version: {
|
|
10594
10711
|
kind: "integer",
|
|
@@ -10683,9 +10800,10 @@ var V2_OPERATIONS = {
|
|
|
10683
10800
|
method: "PUT",
|
|
10684
10801
|
path: "/api/v2/secrets/[name]",
|
|
10685
10802
|
pathParams: ["name"],
|
|
10686
|
-
pathParamDocs: { name: "Secret to create
|
|
10803
|
+
pathParamDocs: { name: "Secret to create or replace." },
|
|
10687
10804
|
responseMode: "json",
|
|
10688
10805
|
summary: "Set Secret",
|
|
10806
|
+
personalKeyOnly: true,
|
|
10689
10807
|
body: {
|
|
10690
10808
|
workspaceId: {
|
|
10691
10809
|
kind: "string",
|
|
@@ -10700,8 +10818,7 @@ var V2_OPERATIONS = {
|
|
|
10700
10818
|
},
|
|
10701
10819
|
value: {
|
|
10702
10820
|
kind: "string",
|
|
10703
|
-
|
|
10704
|
-
describe: "Write-only secret value. It is never returned."
|
|
10821
|
+
describe: "Write-only secret value. It is never returned. Omit it on a workspace secret to change description or unredacted alone, leaving the stored value untouched; the secret must already exist. Always required for a personal secret, which carries no other writable field."
|
|
10705
10822
|
},
|
|
10706
10823
|
description: {
|
|
10707
10824
|
kind: "string",
|
|
@@ -10723,6 +10840,7 @@ var V2_OPERATIONS = {
|
|
|
10723
10840
|
},
|
|
10724
10841
|
responseMode: "json",
|
|
10725
10842
|
summary: "Sync Knowledge Connector",
|
|
10843
|
+
personalKeyOnly: true,
|
|
10726
10844
|
body: {
|
|
10727
10845
|
workspaceId: {
|
|
10728
10846
|
kind: "string",
|
|
@@ -10760,7 +10878,8 @@ var V2_OPERATIONS = {
|
|
|
10760
10878
|
pathParams: ["workflowId"],
|
|
10761
10879
|
pathParamDocs: { workflowId: "Unique workflow identifier." },
|
|
10762
10880
|
responseMode: "json",
|
|
10763
|
-
summary: "Undeploy Workflow"
|
|
10881
|
+
summary: "Undeploy Workflow",
|
|
10882
|
+
personalKeyOnly: true
|
|
10764
10883
|
},
|
|
10765
10884
|
undeployWorkflowMcpTool: {
|
|
10766
10885
|
method: "DELETE",
|
|
@@ -10771,7 +10890,8 @@ var V2_OPERATIONS = {
|
|
|
10771
10890
|
workflowId: "Workflow published as a tool on this server."
|
|
10772
10891
|
},
|
|
10773
10892
|
responseMode: "json",
|
|
10774
|
-
summary: "Unpublish Workflow MCP Tool"
|
|
10893
|
+
summary: "Unpublish Workflow MCP Tool",
|
|
10894
|
+
personalKeyOnly: true
|
|
10775
10895
|
},
|
|
10776
10896
|
unzipFile: {
|
|
10777
10897
|
method: "POST",
|
|
@@ -10791,6 +10911,7 @@ var V2_OPERATIONS = {
|
|
|
10791
10911
|
pathParamDocs: { credentialId: "Credential to update." },
|
|
10792
10912
|
responseMode: "json",
|
|
10793
10913
|
summary: "Update Credential",
|
|
10914
|
+
personalKeyOnly: true,
|
|
10794
10915
|
query: {
|
|
10795
10916
|
workspaceId: {
|
|
10796
10917
|
kind: "string",
|
|
@@ -10892,6 +11013,7 @@ var V2_OPERATIONS = {
|
|
|
10892
11013
|
},
|
|
10893
11014
|
responseMode: "json",
|
|
10894
11015
|
summary: "Update Chunk",
|
|
11016
|
+
personalKeyOnly: true,
|
|
10895
11017
|
body: {
|
|
10896
11018
|
workspaceId: {
|
|
10897
11019
|
kind: "string",
|
|
@@ -10918,6 +11040,7 @@ var V2_OPERATIONS = {
|
|
|
10918
11040
|
},
|
|
10919
11041
|
responseMode: "json",
|
|
10920
11042
|
summary: "Update Knowledge Connector",
|
|
11043
|
+
personalKeyOnly: true,
|
|
10921
11044
|
body: {
|
|
10922
11045
|
workspaceId: {
|
|
10923
11046
|
kind: "string",
|
|
@@ -10949,6 +11072,7 @@ var V2_OPERATIONS = {
|
|
|
10949
11072
|
},
|
|
10950
11073
|
responseMode: "json",
|
|
10951
11074
|
summary: "Update Knowledge Connector Documents",
|
|
11075
|
+
personalKeyOnly: true,
|
|
10952
11076
|
body: {
|
|
10953
11077
|
workspaceId: {
|
|
10954
11078
|
kind: "string",
|
|
@@ -10978,6 +11102,7 @@ var V2_OPERATIONS = {
|
|
|
10978
11102
|
},
|
|
10979
11103
|
responseMode: "json",
|
|
10980
11104
|
summary: "Update Document",
|
|
11105
|
+
personalKeyOnly: true,
|
|
10981
11106
|
body: {
|
|
10982
11107
|
workspaceId: {
|
|
10983
11108
|
kind: "string",
|
|
@@ -11022,6 +11147,7 @@ var V2_OPERATIONS = {
|
|
|
11022
11147
|
},
|
|
11023
11148
|
responseMode: "json",
|
|
11024
11149
|
summary: "Update Tag",
|
|
11150
|
+
personalKeyOnly: true,
|
|
11025
11151
|
body: {
|
|
11026
11152
|
workspaceId: {
|
|
11027
11153
|
kind: "string",
|
|
@@ -11126,6 +11252,7 @@ var V2_OPERATIONS = {
|
|
|
11126
11252
|
},
|
|
11127
11253
|
responseMode: "json",
|
|
11128
11254
|
summary: "Update Skill",
|
|
11255
|
+
personalKeyOnly: true,
|
|
11129
11256
|
body: {
|
|
11130
11257
|
workspaceId: { kind: "string", required: true, describe: "Workspace that owns the skill." },
|
|
11131
11258
|
name: { kind: "string", describe: "New kebab-case skill name." },
|
|
@@ -11263,6 +11390,7 @@ var V2_OPERATIONS = {
|
|
|
11263
11390
|
pathParamDocs: { serverId: "Unique workflow-MCP server identifier." },
|
|
11264
11391
|
responseMode: "json",
|
|
11265
11392
|
summary: "Update Workflow MCP Server",
|
|
11393
|
+
personalKeyOnly: true,
|
|
11266
11394
|
body: {
|
|
11267
11395
|
name: { kind: "string", describe: "Server display name, shown to connecting MCP clients." },
|
|
11268
11396
|
description: { kind: "string", describe: "New server description, or null to clear it." },
|
|
@@ -11279,6 +11407,7 @@ var V2_OPERATIONS = {
|
|
|
11279
11407
|
pathParamDocs: { workflowId: "Unique workflow identifier." },
|
|
11280
11408
|
responseMode: "json",
|
|
11281
11409
|
summary: "Update Workflow Public API Access",
|
|
11410
|
+
personalKeyOnly: true,
|
|
11282
11411
|
body: {
|
|
11283
11412
|
isPublicApi: {
|
|
11284
11413
|
kind: "boolean",
|
|
@@ -11327,6 +11456,7 @@ var V2_OPERATIONS = {
|
|
|
11327
11456
|
pathParamDocs: { fileId: "File identifier." },
|
|
11328
11457
|
responseMode: "json",
|
|
11329
11458
|
summary: "Enable or Disable File Share",
|
|
11459
|
+
personalKeyOnly: true,
|
|
11330
11460
|
body: {
|
|
11331
11461
|
workspaceId: { kind: "string", required: true, describe: "Workspace that owns the file." },
|
|
11332
11462
|
isActive: {
|
|
@@ -11361,7 +11491,7 @@ var V2_OPERATIONS = {
|
|
|
11361
11491
|
data: {
|
|
11362
11492
|
kind: "object",
|
|
11363
11493
|
required: true,
|
|
11364
|
-
describe: "Complete set of row cells keyed by column name. On the update branch this REPLACES the matched row: any column not present here is cleared, unlike
|
|
11494
|
+
describe: "Complete set of row cells keyed by column name. On the update branch this REPLACES the matched row: any column not present here is cleared, unlike a single-row update, which merges."
|
|
11365
11495
|
},
|
|
11366
11496
|
conflictTarget: { kind: "string", describe: "Unique column used to detect a conflict." }
|
|
11367
11497
|
}
|
|
@@ -11369,7 +11499,6 @@ var V2_OPERATIONS = {
|
|
|
11369
11499
|
};
|
|
11370
11500
|
|
|
11371
11501
|
// src/commands/auth.ts
|
|
11372
|
-
var PROFILE_NAME_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._-]*$/;
|
|
11373
11502
|
var MAX_INTERACTIVE_WORKSPACES = 1000;
|
|
11374
11503
|
function openBrowser(url) {
|
|
11375
11504
|
const [command, args] = process.platform === "win32" ? ["cmd", ["/c", "start", "", url]] : [process.platform === "darwin" ? "open" : "xdg-open", [url]];
|
|
@@ -11396,11 +11525,11 @@ function presentAuthentication(source) {
|
|
|
11396
11525
|
}
|
|
11397
11526
|
async function confirmProfileOverwrite(profileName) {
|
|
11398
11527
|
if (!process.stdin.isTTY) {
|
|
11399
|
-
throw new SimApiError(`Profile "${profileName}" already exists. Re-run with --yes to overwrite it.`, 0);
|
|
11528
|
+
throw new SimApiError(`Profile "${redact(profileName)}" already exists. Re-run with --yes to overwrite it.`, 0);
|
|
11400
11529
|
}
|
|
11401
11530
|
const prompt = createInterface({ input: process.stdin, output: process.stderr });
|
|
11402
11531
|
try {
|
|
11403
|
-
const answer = await prompt.question(`Profile "${profileName}" already exists. Replace its API key and login defaults? (y/N) `);
|
|
11532
|
+
const answer = await prompt.question(`Profile "${redact(profileName)}" already exists. Replace its API key and login defaults? (y/N) `);
|
|
11404
11533
|
return answer.trim().toLowerCase() === "y" || answer.trim().toLowerCase() === "yes";
|
|
11405
11534
|
} finally {
|
|
11406
11535
|
prompt.close();
|
|
@@ -11410,21 +11539,24 @@ function selectedProfileName(command) {
|
|
|
11410
11539
|
return globalsOf(command).profile || process.env.SIM_PROFILE || DEFAULT_PROFILE;
|
|
11411
11540
|
}
|
|
11412
11541
|
function validateNewProfileName(profileName) {
|
|
11413
|
-
|
|
11414
|
-
throw new SimApiError(`Invalid profile name "${profileName}". Use letters, numbers, dots, underscores, or hyphens, starting with a letter or number.`, 0);
|
|
11415
|
-
}
|
|
11542
|
+
validateProfileName(profileName);
|
|
11416
11543
|
if (listProfiles().includes(profileName)) {
|
|
11417
|
-
throw new SimApiError(`Profile "${profileName}" already exists. Remove it first with: sim logout --all --profile ${profileName}`, 0);
|
|
11544
|
+
throw new SimApiError(`Profile "${redact(profileName)}" already exists. Remove it first with: sim logout --all --profile ${redact(profileName)}`, 0);
|
|
11545
|
+
}
|
|
11546
|
+
}
|
|
11547
|
+
function requireStorableKey(apiKey) {
|
|
11548
|
+
if (typeof apiKey !== "string" || !apiKey || apiKey !== apiKey.trim() || FORBIDDEN_IN_VALUE.test(apiKey)) {
|
|
11549
|
+
throw new SimApiError("The server returned a malformed API key. Nothing was stored; check the endpoint.", 0);
|
|
11418
11550
|
}
|
|
11419
11551
|
}
|
|
11420
11552
|
function requireStoredAuthentication(profile) {
|
|
11421
11553
|
const authProfile = resolveAuthenticationProfileName(profile.name);
|
|
11422
11554
|
const storedKey = readCredentialsProfile(authProfile).api_key;
|
|
11423
11555
|
if (profile.sources.apiKey !== "credentials" || !storedKey) {
|
|
11424
|
-
throw new SimApiError(`Cannot create a shared profile from "${profile.name}": the active API key is not stored. Run: sim login --profile ${authProfile}`, 0);
|
|
11556
|
+
throw new SimApiError(`Cannot create a shared profile from "${redact(profile.name)}": the active API key is not stored. Run: sim login --profile ${redact(authProfile)}`, 0);
|
|
11425
11557
|
}
|
|
11426
11558
|
if (profile.sources.endpoint === "flag" || profile.sources.endpoint === "env") {
|
|
11427
|
-
throw new SimApiError(`Cannot create a shared profile from "${profile.name}": the active endpoint comes from ${profile.sources.endpoint}. Save it with: sim configure --profile ${authProfile} --set-endpoint ${profile.endpoint}`, 0);
|
|
11559
|
+
throw new SimApiError(`Cannot create a shared profile from "${redact(profile.name)}": the active endpoint comes from ${profile.sources.endpoint}. Save it with: sim configure --profile ${redact(authProfile)} --set-endpoint ${profile.endpoint}`, 0);
|
|
11428
11560
|
}
|
|
11429
11561
|
return authProfile;
|
|
11430
11562
|
}
|
|
@@ -11476,12 +11608,12 @@ function addProfileCommand() {
|
|
|
11476
11608
|
const workspace = workspaceId ? await getWorkspaceById(client, workspaceId) : await chooseWorkspace(client);
|
|
11477
11609
|
writeConfigProfile(profileName, {
|
|
11478
11610
|
auth_profile: authProfile,
|
|
11479
|
-
workspace: workspace.id
|
|
11611
|
+
workspace: normalizeWorkspaceId(workspace.id, "the workspace response")
|
|
11480
11612
|
});
|
|
11481
|
-
console.log(source_default.green(`✓ Added profile "${profileName}" in ${configPath()}`));
|
|
11613
|
+
console.log(source_default.green(`✓ Added profile "${safeOneLine(profileName)}" in ${configPath()}`));
|
|
11482
11614
|
console.log(` Workspace: ${safeOneLine(workspace.name)} (${workspace.id})`);
|
|
11483
|
-
console.log(` Authentication: ${authProfile}`);
|
|
11484
|
-
console.log(source_default.dim(` Try: sim --profile ${profileName} whoami`));
|
|
11615
|
+
console.log(` Authentication: ${safeOneLine(authProfile)}`);
|
|
11616
|
+
console.log(source_default.dim(` Try: sim --profile ${safeOneLine(profileName)} whoami`));
|
|
11485
11617
|
});
|
|
11486
11618
|
}
|
|
11487
11619
|
function loginCommand() {
|
|
@@ -11489,7 +11621,7 @@ function loginCommand() {
|
|
|
11489
11621
|
const profile = profileFrom(command, { allowUnknownProfile: true });
|
|
11490
11622
|
const authProfile = resolveAuthenticationProfileName(profile.name);
|
|
11491
11623
|
if (authProfile !== profile.name) {
|
|
11492
|
-
throw new SimApiError(`Profile "${profile.name}" shares authentication with "${authProfile}". Run: sim login --profile ${authProfile}`, 0);
|
|
11624
|
+
throw new SimApiError(`Profile "${redact(profile.name)}" shares authentication with "${redact(authProfile)}". Run: sim login --profile ${redact(authProfile)}`, 0);
|
|
11493
11625
|
}
|
|
11494
11626
|
if (options.scope !== "platform" && options.scope !== "copilot") {
|
|
11495
11627
|
throw new SimApiError(`Unknown scope "${options.scope}". Use platform or copilot.`, 0);
|
|
@@ -11504,7 +11636,7 @@ function loginCommand() {
|
|
|
11504
11636
|
}
|
|
11505
11637
|
const auth = createAuthRequest();
|
|
11506
11638
|
const url = buildApprovalUrl(profile.endpoint, auth, scope, profile.workspaceId ?? undefined);
|
|
11507
|
-
console.log(`Signing in to ${source_default.bold(profile.endpoint)} as profile ${source_default.bold(profile.name)}`);
|
|
11639
|
+
console.log(`Signing in to ${source_default.bold(profile.endpoint)} as profile ${source_default.bold(safeOneLine(profile.name))}`);
|
|
11508
11640
|
console.log(`
|
|
11509
11641
|
Pairing code: ${source_default.bold(auth.pairing)}`);
|
|
11510
11642
|
console.log(source_default.dim(`Confirm this code matches what the browser shows before approving.
|
|
@@ -11518,12 +11650,13 @@ Waiting for approval…`));
|
|
|
11518
11650
|
if (key.scope !== scope) {
|
|
11519
11651
|
throw new SimApiError(`Server issued a ${key.scope} key but this profile needs a ${scope} key. Update the Sim deployment, or run: sim login --scope ${key.scope}`, 0);
|
|
11520
11652
|
}
|
|
11521
|
-
writeCredentialsProfile(profile.name, key.apiKey);
|
|
11522
11653
|
const settings = {
|
|
11523
11654
|
endpoint: profile.endpoint,
|
|
11524
|
-
workspace: key.workspaceId
|
|
11655
|
+
workspace: key.workspaceId == null ? null : normalizeWorkspaceId(key.workspaceId, "the login response")
|
|
11525
11656
|
};
|
|
11657
|
+
requireStorableKey(key.apiKey);
|
|
11526
11658
|
writeConfigProfile(profile.name, settings);
|
|
11659
|
+
writeCredentialsProfile(profile.name, key.apiKey);
|
|
11527
11660
|
console.log(source_default.green(`
|
|
11528
11661
|
✓ Logged in. Key stored in ${credentialsPath()}`));
|
|
11529
11662
|
if (key.workspaceBound && key.workspaceId) {
|
|
@@ -11541,27 +11674,27 @@ function logoutCommand() {
|
|
|
11541
11674
|
const profileName = selectedProfileName(command);
|
|
11542
11675
|
const dependents = listAuthenticationDependents(profileName);
|
|
11543
11676
|
if (dependents.length > 0) {
|
|
11544
|
-
throw new SimApiError(`Cannot remove authentication profile "${profileName}" because it is used by: ${dependents.join(", ")}. Remove those profiles first.`, 0);
|
|
11677
|
+
throw new SimApiError(`Cannot remove authentication profile "${redact(profileName)}" because it is used by: ${dependents.map(redact).join(", ")}. Remove those profiles first.`, 0);
|
|
11545
11678
|
}
|
|
11546
11679
|
const removed = deleteProfile(profileName);
|
|
11547
11680
|
if (!removed.config && !removed.credentials) {
|
|
11548
|
-
console.log(source_default.dim(`Nothing stored for profile "${profileName}".`));
|
|
11681
|
+
console.log(source_default.dim(`Nothing stored for profile "${safeOneLine(profileName)}".`));
|
|
11549
11682
|
return;
|
|
11550
11683
|
}
|
|
11551
|
-
console.log(source_default.green(`✓ Removed profile "${profileName}".`));
|
|
11684
|
+
console.log(source_default.green(`✓ Removed profile "${safeOneLine(profileName)}".`));
|
|
11552
11685
|
return;
|
|
11553
11686
|
}
|
|
11554
11687
|
const profile = profileFrom(command);
|
|
11555
11688
|
const authProfile = resolveAuthenticationProfileName(profile.name);
|
|
11556
11689
|
if (authProfile !== profile.name) {
|
|
11557
|
-
throw new SimApiError(`Profile "${profile.name}" shares authentication with "${authProfile}". Log out of the authentication profile instead: sim logout --profile ${authProfile}`, 0);
|
|
11690
|
+
throw new SimApiError(`Profile "${redact(profile.name)}" shares authentication with "${redact(authProfile)}". Log out of the authentication profile instead: sim logout --profile ${redact(authProfile)}`, 0);
|
|
11558
11691
|
}
|
|
11559
11692
|
if (!readCredentialsProfile(profile.name).api_key) {
|
|
11560
|
-
console.log(source_default.dim(`No stored key for profile "${profile.name}".`));
|
|
11693
|
+
console.log(source_default.dim(`No stored key for profile "${safeOneLine(profile.name)}".`));
|
|
11561
11694
|
return;
|
|
11562
11695
|
}
|
|
11563
11696
|
writeCredentialsProfile(profile.name, null);
|
|
11564
|
-
console.log(source_default.green(`✓ Removed the stored key for profile "${profile.name}".`));
|
|
11697
|
+
console.log(source_default.green(`✓ Removed the stored key for profile "${safeOneLine(profile.name)}".`));
|
|
11565
11698
|
console.log(source_default.dim(" The key itself is still active — revoke it in Settings → API keys."));
|
|
11566
11699
|
});
|
|
11567
11700
|
}
|
|
@@ -11591,7 +11724,7 @@ async function verifyProfile(client, profile) {
|
|
|
11591
11724
|
status: "unauthenticated",
|
|
11592
11725
|
workspace: null,
|
|
11593
11726
|
keyType: null,
|
|
11594
|
-
detail: `no API key — run: sim login --profile ${profile.name}`
|
|
11727
|
+
detail: `no API key — run: sim login --profile ${safeOneLine(profile.name)}`
|
|
11595
11728
|
};
|
|
11596
11729
|
}
|
|
11597
11730
|
const keyType = await readKeyType(client);
|
|
@@ -11600,7 +11733,7 @@ async function verifyProfile(client, profile) {
|
|
|
11600
11733
|
status: "no-workspace",
|
|
11601
11734
|
workspace: null,
|
|
11602
11735
|
keyType,
|
|
11603
|
-
detail: `no workspace to check against — run: sim configure --profile ${profile.name} --set-workspace <id>`
|
|
11736
|
+
detail: `no workspace to check against — run: sim configure --profile ${safeOneLine(profile.name)} --set-workspace <id>`
|
|
11604
11737
|
};
|
|
11605
11738
|
}
|
|
11606
11739
|
const operation = V2_OPERATIONS.getWorkspace;
|
|
@@ -11687,38 +11820,83 @@ function whoamiCommand() {
|
|
|
11687
11820
|
process.exitCode = exitCode;
|
|
11688
11821
|
});
|
|
11689
11822
|
}
|
|
11823
|
+
var PROFILE_COLUMNS = [
|
|
11824
|
+
{ header: "", value: (row) => row.active ? source_default.green("*") : " " },
|
|
11825
|
+
{ header: "profile", value: (row) => safeOneLine(row.name) },
|
|
11826
|
+
{ header: "key", value: (row) => row.error ? text(null) : row.hasKey ? "yes" : "no" },
|
|
11827
|
+
{ header: "auth", value: (row) => row.authProfile ? safeOneLine(row.authProfile) : text(null) },
|
|
11828
|
+
{ header: "error", value: (row) => row.error ? source_default.red(safeOneLine(row.error)) : text(null) }
|
|
11829
|
+
];
|
|
11830
|
+
function buildProfileRow(name, active) {
|
|
11831
|
+
try {
|
|
11832
|
+
const authProfile = resolveAuthenticationProfileName(name);
|
|
11833
|
+
return {
|
|
11834
|
+
name,
|
|
11835
|
+
active,
|
|
11836
|
+
hasKey: Boolean(readCredentialsProfile(authProfile).api_key),
|
|
11837
|
+
authProfile,
|
|
11838
|
+
error: null
|
|
11839
|
+
};
|
|
11840
|
+
} catch (error) {
|
|
11841
|
+
if (!(error instanceof ProfileConfigError))
|
|
11842
|
+
throw error;
|
|
11843
|
+
return { name, active, hasKey: false, authProfile: null, error: error.message };
|
|
11844
|
+
}
|
|
11845
|
+
}
|
|
11846
|
+
function profileListingContext(command) {
|
|
11847
|
+
try {
|
|
11848
|
+
const profile = profileFrom(command);
|
|
11849
|
+
return { activeName: profile.name, output: profile.output };
|
|
11850
|
+
} catch (error) {
|
|
11851
|
+
if (!(error instanceof ProfileConfigError))
|
|
11852
|
+
throw error;
|
|
11853
|
+
if (error instanceof ProfileOverrideError)
|
|
11854
|
+
throw error;
|
|
11855
|
+
const globals = globalsOf(command);
|
|
11856
|
+
const named = globals.profile || process.env.SIM_PROFILE;
|
|
11857
|
+
if (named && named !== DEFAULT_PROFILE && !listProfiles().includes(named))
|
|
11858
|
+
throw error;
|
|
11859
|
+
const requested = globals.output ?? process.env.SIM_OUTPUT;
|
|
11860
|
+
if (requested && !OUTPUT_FORMATS.includes(requested))
|
|
11861
|
+
throw error;
|
|
11862
|
+
return {
|
|
11863
|
+
activeName: named || DEFAULT_PROFILE,
|
|
11864
|
+
output: requested ? requested : "table"
|
|
11865
|
+
};
|
|
11866
|
+
}
|
|
11867
|
+
}
|
|
11690
11868
|
function profilesCommand() {
|
|
11691
11869
|
const command = new Command("profiles").alias("profile").description("List profiles or add a workspace profile that shares a stored login");
|
|
11692
11870
|
const printProfiles = (_options, actionCommand) => {
|
|
11693
|
-
const
|
|
11694
|
-
|
|
11695
|
-
|
|
11871
|
+
const { activeName, output } = profileListingContext(actionCommand);
|
|
11872
|
+
const rows = listProfiles().map((name) => buildProfileRow(name, name === activeName));
|
|
11873
|
+
if (rows.length === 0) {
|
|
11874
|
+
if (output === "table")
|
|
11875
|
+
console.log(source_default.dim("No profiles yet. Run: sim login"));
|
|
11876
|
+
else
|
|
11877
|
+
printList(output, rows, PROFILE_COLUMNS);
|
|
11696
11878
|
return;
|
|
11697
11879
|
}
|
|
11698
|
-
|
|
11699
|
-
for (const name of profiles) {
|
|
11700
|
-
const marker = name === active ? source_default.green("*") : " ";
|
|
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
|
-
}
|
|
11710
|
-
const hasKey = Boolean(readCredentialsProfile(authProfile).api_key);
|
|
11711
|
-
const authentication = authProfile === name ? "" : source_default.dim(` (auth: ${authProfile})`);
|
|
11712
|
-
console.log(`${marker} ${name}${hasKey ? "" : source_default.dim(" (no key)")}${authentication}`);
|
|
11713
|
-
}
|
|
11880
|
+
printList(output, rows, PROFILE_COLUMNS);
|
|
11714
11881
|
};
|
|
11715
|
-
command.action(printProfiles);
|
|
11716
|
-
command.addCommand(new Command("list").description("List configured profiles").action(printProfiles));
|
|
11882
|
+
command.addCommand(new Command("list").allowExcessArguments(false).description("List configured profiles").action(printProfiles), { isDefault: true });
|
|
11717
11883
|
command.addCommand(addProfileCommand());
|
|
11884
|
+
const known = new Set(command.commands.flatMap((child) => [child.name(), ...child.aliases()]));
|
|
11885
|
+
command.hook("preSubcommand", (group) => {
|
|
11886
|
+
const first = group.args[0];
|
|
11887
|
+
if (first !== undefined && !first.startsWith("-") && !known.has(first)) {
|
|
11888
|
+
group.unknownCommand();
|
|
11889
|
+
}
|
|
11890
|
+
});
|
|
11718
11891
|
return command;
|
|
11719
11892
|
}
|
|
11720
11893
|
|
|
11721
11894
|
// src/commands/configure.ts
|
|
11895
|
+
var GLOBAL_FLAG_TWINS = [
|
|
11896
|
+
{ option: "endpoint", flag: "--endpoint", setFlag: "--set-endpoint" },
|
|
11897
|
+
{ option: "workspace", flag: "-w, --workspace", setFlag: "--set-workspace" },
|
|
11898
|
+
{ option: "output", flag: "--output", setFlag: "--set-output" }
|
|
11899
|
+
];
|
|
11722
11900
|
function requireValue(value, flag, key) {
|
|
11723
11901
|
if (value !== undefined && value.trim() === "") {
|
|
11724
11902
|
throw new SimApiError(`${flag} requires a value. To remove it, run: sim configure --unset ${key}`, 0);
|
|
@@ -11726,6 +11904,13 @@ function requireValue(value, flag, key) {
|
|
|
11726
11904
|
}
|
|
11727
11905
|
function configureCommand() {
|
|
11728
11906
|
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) => {
|
|
11907
|
+
const globals = globalsOf(command);
|
|
11908
|
+
for (const { option, flag, setFlag } of GLOBAL_FLAG_TWINS) {
|
|
11909
|
+
const value = globals[option];
|
|
11910
|
+
if (value === undefined)
|
|
11911
|
+
continue;
|
|
11912
|
+
throw new SimApiError(`${flag} applies to a single command and is not stored. To save it, run: sim configure ${setFlag} ${value}`, 0);
|
|
11913
|
+
}
|
|
11729
11914
|
const profile = profileFrom(command, { allowUnknownProfile: true });
|
|
11730
11915
|
const authProfile = resolveAuthenticationProfileName(profile.name);
|
|
11731
11916
|
const updates = {};
|
|
@@ -11738,8 +11923,9 @@ function configureCommand() {
|
|
|
11738
11923
|
}
|
|
11739
11924
|
updates.endpoint = normalizeEndpoint(options.setEndpoint, "--set-endpoint");
|
|
11740
11925
|
}
|
|
11741
|
-
if (options.setWorkspace)
|
|
11742
|
-
updates.workspace = options.setWorkspace;
|
|
11926
|
+
if (options.setWorkspace) {
|
|
11927
|
+
updates.workspace = normalizeWorkspaceId(options.setWorkspace, "--set-workspace");
|
|
11928
|
+
}
|
|
11743
11929
|
if (options.setOutput) {
|
|
11744
11930
|
if (!OUTPUT_FORMATS.includes(options.setOutput)) {
|
|
11745
11931
|
throw new SimApiError(`Unknown output format "${options.setOutput}". Use one of: ${OUTPUT_FORMATS.join(", ")}`, 0);
|
|
@@ -11748,7 +11934,7 @@ function configureCommand() {
|
|
|
11748
11934
|
}
|
|
11749
11935
|
for (const key of options.unset ?? []) {
|
|
11750
11936
|
if (!["endpoint", "workspace", "output"].includes(key)) {
|
|
11751
|
-
throw new SimApiError(`Cannot unset "${key}". Use endpoint, workspace, or output.`, 0);
|
|
11937
|
+
throw new SimApiError(`Cannot unset "${redact(key)}". Use endpoint, workspace, or output.`, 0);
|
|
11752
11938
|
}
|
|
11753
11939
|
if (key === "endpoint" && authProfile !== profile.name) {
|
|
11754
11940
|
throw new SimApiError(`Profile "${profile.name}" shares its endpoint with authentication profile "${authProfile}". Run: sim configure --profile ${authProfile} --unset endpoint`, 0);
|
|
@@ -11766,14 +11952,16 @@ function configureCommand() {
|
|
|
11766
11952
|
}
|
|
11767
11953
|
return;
|
|
11768
11954
|
}
|
|
11955
|
+
const removalOnly = Object.values(updates).every((value) => value === null);
|
|
11956
|
+
if (removalOnly && Object.keys(readConfigProfile(profile.name)).length === 0) {
|
|
11957
|
+
console.log(source_default.dim(`No settings stored for profile "${profile.name}".`));
|
|
11958
|
+
return;
|
|
11959
|
+
}
|
|
11769
11960
|
writeConfigProfile(profile.name, updates);
|
|
11770
11961
|
console.log(source_default.green(`✓ Updated profile "${profile.name}" in ${configPath()}`));
|
|
11771
11962
|
});
|
|
11772
11963
|
}
|
|
11773
11964
|
|
|
11774
|
-
// src/runtime/request.ts
|
|
11775
|
-
import { existsSync as existsSync2, readFileSync as readFileSync3, readSync } from "node:fs";
|
|
11776
|
-
|
|
11777
11965
|
// src/contract/commands.ts
|
|
11778
11966
|
var TABLE_NAME_HELP = "Identifier: letters, numbers, and underscores; cannot start with a number";
|
|
11779
11967
|
var TABLE_FILTER_HELP = 'Predicate: {"all":[{"field":"status","op":"eq","value":"active"}]}; groups use all/any. Operators: eq, ne, gt, gte, lt, lte, in, nin, contains, ncontains, startsWith, endsWith, like, ilike, nlike, nilike, isEmpty, isNotEmpty, isNull, isNotNull';
|
|
@@ -11858,7 +12046,7 @@ var CLI_CONTRACT = {
|
|
|
11858
12046
|
listBillingLogs: {
|
|
11859
12047
|
command: "billing logs",
|
|
11860
12048
|
allWorkspaces: true,
|
|
11861
|
-
describe: "List credit usage events",
|
|
12049
|
+
describe: "List credit usage events (a personal API key reports only your own events; a workspace API key reports every member's)",
|
|
11862
12050
|
flags: {
|
|
11863
12051
|
source: { describe: "Filter by usage source; sim-chat combines Copilot and workspace chat" },
|
|
11864
12052
|
period: { describe: "Billing period" },
|
|
@@ -12014,14 +12202,14 @@ var CLI_CONTRACT = {
|
|
|
12014
12202
|
}
|
|
12015
12203
|
},
|
|
12016
12204
|
columns: [
|
|
12017
|
-
{ header: "started", path: "startedAt", format: "timestamp" },
|
|
12018
|
-
{ header: "status" },
|
|
12205
|
+
{ header: "started", path: "startedAt", format: "timestamp", minWidth: 19 },
|
|
12206
|
+
{ header: "status", minWidth: 9 },
|
|
12019
12207
|
{ header: "level" },
|
|
12020
|
-
{ header: "trigger" },
|
|
12021
|
-
{ header: "workflow", path: "workflow.name" },
|
|
12208
|
+
{ header: "trigger", minWidth: 12 },
|
|
12209
|
+
{ header: "workflow", path: "workflow.name", minWidth: 24 },
|
|
12022
12210
|
{ header: "duration", path: "totalDurationMs", format: "duration" },
|
|
12023
|
-
{ header: "cost", path: "cost.total", format: "cost" },
|
|
12024
|
-
{ header: "run", path: "runId" }
|
|
12211
|
+
{ header: "cost", path: "cost.total", format: "cost", minWidth: 8 },
|
|
12212
|
+
{ header: "run", path: "runId", minWidth: 36 }
|
|
12025
12213
|
]
|
|
12026
12214
|
},
|
|
12027
12215
|
getLog: {
|
|
@@ -12769,6 +12957,23 @@ var CLI_CONTRACT = {
|
|
|
12769
12957
|
}
|
|
12770
12958
|
}
|
|
12771
12959
|
},
|
|
12960
|
+
listTableDispatches: {
|
|
12961
|
+
columns: [
|
|
12962
|
+
{ header: "id" },
|
|
12963
|
+
{ header: "status" },
|
|
12964
|
+
{ header: "mode" },
|
|
12965
|
+
{ header: "max rows", path: "limit.max" },
|
|
12966
|
+
{ header: "processed", path: "processedCount" },
|
|
12967
|
+
{ header: "manual", path: "isManualRun", format: "bool" },
|
|
12968
|
+
{ header: "requested", path: "requestedAt", format: "timestamp" },
|
|
12969
|
+
{ header: "completed", path: "completedAt", format: "timestamp" },
|
|
12970
|
+
{ header: "canceled", path: "canceledAt", format: "timestamp" },
|
|
12971
|
+
{ header: "groups", path: "scope.groupIds", format: "count" },
|
|
12972
|
+
{ header: "rows", path: "scope.rowIds", format: "count" },
|
|
12973
|
+
{ header: "filtered", path: "scope.filtered", format: "bool" },
|
|
12974
|
+
{ header: "excluded", path: "scope.excludeRowIds", format: "count" }
|
|
12975
|
+
]
|
|
12976
|
+
},
|
|
12772
12977
|
runRowEnrichment: {
|
|
12773
12978
|
command: "tables rows enrich",
|
|
12774
12979
|
describe: "Run one row’s enrichment group"
|
|
@@ -12777,8 +12982,16 @@ var CLI_CONTRACT = {
|
|
|
12777
12982
|
createTableImportPartUrls: { hidden: true },
|
|
12778
12983
|
completeTableImport: { hidden: true },
|
|
12779
12984
|
getTableImport: { flags: TRANSFER_TOKEN_OMITTED },
|
|
12780
|
-
cancelTableImport: {
|
|
12781
|
-
|
|
12985
|
+
cancelTableImport: {
|
|
12986
|
+
command: "tables imports cancel",
|
|
12987
|
+
flags: TRANSFER_TOKEN_OMITTED,
|
|
12988
|
+
describe: "Stop a running import",
|
|
12989
|
+
confirm: "This stops the import between row batches, so whatever it already wrote stays and nothing resumes it. A replace import empties the table before its first batch, so cancelling one leaves only part of the new file; an append adds its rows again if you import the file a second time."
|
|
12990
|
+
},
|
|
12991
|
+
cancelTableExport: {
|
|
12992
|
+
command: "tables exports cancel",
|
|
12993
|
+
describe: "Stop a running export"
|
|
12994
|
+
},
|
|
12782
12995
|
tableExportDownload: {
|
|
12783
12996
|
command: "tables exports download",
|
|
12784
12997
|
describe: "Get the download URL for a finished export"
|
|
@@ -12800,7 +13013,7 @@ var CLI_CONTRACT = {
|
|
|
12800
13013
|
selectedOutputs: {
|
|
12801
13014
|
name: "select-output",
|
|
12802
13015
|
list: true,
|
|
12803
|
-
describe: "Return blockName.field values (e.g. agent_1.content); missing fields are omitted"
|
|
13016
|
+
describe: "Return blockName.field values from the streamed result (e.g. agent_1.content), requires --follow; missing fields are omitted"
|
|
12804
13017
|
},
|
|
12805
13018
|
stream: { omit: true },
|
|
12806
13019
|
includeThinking: { omit: true },
|
|
@@ -12824,7 +13037,7 @@ var CLI_CONTRACT = {
|
|
|
12824
13037
|
selectedOutputs: {
|
|
12825
13038
|
name: "select-output",
|
|
12826
13039
|
list: true,
|
|
12827
|
-
describe: "Include
|
|
13040
|
+
describe: "Include blockId or blockId.path values in JSON or YAML output; block names are not resolved on a finished run"
|
|
12828
13041
|
}
|
|
12829
13042
|
},
|
|
12830
13043
|
fields: [
|
|
@@ -12931,11 +13144,20 @@ function camel(flag) {
|
|
|
12931
13144
|
}
|
|
12932
13145
|
|
|
12933
13146
|
// src/runtime/request.ts
|
|
13147
|
+
import { existsSync as existsSync2, readFileSync as readFileSync3, readSync } from "node:fs";
|
|
12934
13148
|
var PROFILE_INJECTED_FIELD = "workspaceId";
|
|
12935
13149
|
function isProfileWorkspacePath(commandSpec, param) {
|
|
12936
13150
|
return commandSpec.profileWorkspacePath === true && param === PROFILE_INJECTED_FIELD;
|
|
12937
13151
|
}
|
|
13152
|
+
function cursorSlot(operationSpec) {
|
|
13153
|
+
if (operationSpec.query && "cursor" in operationSpec.query)
|
|
13154
|
+
return "query";
|
|
13155
|
+
if (operationSpec.body && "cursor" in operationSpec.body)
|
|
13156
|
+
return "body";
|
|
13157
|
+
return null;
|
|
13158
|
+
}
|
|
12938
13159
|
var JSON_KINDS = new Set(["object", "array", "unknown"]);
|
|
13160
|
+
var NUMERIC_KINDS = new Set(["number", "integer"]);
|
|
12939
13161
|
function flagSpecFor(operation, field) {
|
|
12940
13162
|
return CLI_CONTRACT[operation]?.flags?.[field] ?? {};
|
|
12941
13163
|
}
|
|
@@ -13001,6 +13223,9 @@ function readStdin() {
|
|
|
13001
13223
|
}
|
|
13002
13224
|
return Buffer.concat(chunks).toString("utf8");
|
|
13003
13225
|
}
|
|
13226
|
+
function literalAtHint(error, path) {
|
|
13227
|
+
return error?.code === "ENOENT" ? `. To pass the literal value @${path}, write @@${path}` : "";
|
|
13228
|
+
}
|
|
13004
13229
|
function readArgumentSource(raw, flagName) {
|
|
13005
13230
|
if (raw.startsWith("@@"))
|
|
13006
13231
|
return { text: raw.slice(1), from: "" };
|
|
@@ -13020,7 +13245,7 @@ function readArgumentSource(raw, flagName) {
|
|
|
13020
13245
|
try {
|
|
13021
13246
|
return { text: readFileSync3(path, "utf8"), from: ` (read from ${path})` };
|
|
13022
13247
|
} catch (error) {
|
|
13023
|
-
throw new SimApiError(`--${flagName} cannot read ${path}: ${error.message}`, 0);
|
|
13248
|
+
throw new SimApiError(`--${flagName} cannot read ${path}: ${error.message}${literalAtHint(error, path)}`, 0);
|
|
13024
13249
|
}
|
|
13025
13250
|
}
|
|
13026
13251
|
function readListValues(raw, flagName) {
|
|
@@ -13097,7 +13322,7 @@ function coerce(raw, field, flag, flagName) {
|
|
|
13097
13322
|
throw new SimApiError(`--${flagName} must be valid JSON${source.from}: ${error.message}${pathHint(raw)}`, 0);
|
|
13098
13323
|
}
|
|
13099
13324
|
}
|
|
13100
|
-
if (
|
|
13325
|
+
if (NUMERIC_KINDS.has(field.kind)) {
|
|
13101
13326
|
const value = Number(raw);
|
|
13102
13327
|
if (Number.isNaN(value))
|
|
13103
13328
|
throw new SimApiError(`--${flagName} must be a number`, 0);
|
|
@@ -13113,6 +13338,7 @@ function coerce(raw, field, flag, flagName) {
|
|
|
13113
13338
|
return encodeFolderPath(raw);
|
|
13114
13339
|
return raw;
|
|
13115
13340
|
}
|
|
13341
|
+
var NO_WORKSPACE_FALLBACK = "No workspace set. Pass --workspace, or run: sim configure --set-workspace <id>";
|
|
13116
13342
|
function asQueryValue(value) {
|
|
13117
13343
|
if (value === null || value === undefined)
|
|
13118
13344
|
return;
|
|
@@ -13133,7 +13359,7 @@ function buildRequest(operation, positional, flags, workspaceId) {
|
|
|
13133
13359
|
const value = profileWorkspacePath ? workspaceId : pathFlag ? flags[camel(flagName)] : positional[positionalIndex++];
|
|
13134
13360
|
if (value === undefined || value === null) {
|
|
13135
13361
|
if (profileWorkspacePath) {
|
|
13136
|
-
throw new SimApiError(
|
|
13362
|
+
throw new SimApiError(NO_WORKSPACE_FALLBACK, 0);
|
|
13137
13363
|
}
|
|
13138
13364
|
throw new SimApiError(pathFlag ? `--${flagName} is required` : `Missing <${argumentName}>`, 0);
|
|
13139
13365
|
}
|
|
@@ -13145,6 +13371,7 @@ function buildRequest(operation, positional, flags, workspaceId) {
|
|
|
13145
13371
|
const query = {};
|
|
13146
13372
|
const body = {};
|
|
13147
13373
|
const headers = {};
|
|
13374
|
+
const paginatedLimit = cursorSlot(spec) !== null;
|
|
13148
13375
|
for (const slot of ["query", "body", "headers"]) {
|
|
13149
13376
|
for (const [field, descriptor] of Object.entries(spec[slot] ?? {})) {
|
|
13150
13377
|
const flag = flagSpecFor(operation, field);
|
|
@@ -13154,10 +13381,13 @@ function buildRequest(operation, positional, flags, workspaceId) {
|
|
|
13154
13381
|
const omitProfileWorkspace = commandSpec.allWorkspaces && flags.allWorkspaces === true;
|
|
13155
13382
|
const provided = field === PROFILE_INJECTED_FIELD ? omitProfileWorkspace ? undefined : workspaceId : flags[camel(flagName)];
|
|
13156
13383
|
const raw = provided ?? flag.requestDefault;
|
|
13384
|
+
if ((slot === "query" || NUMERIC_KINDS.has(descriptor.kind)) && typeof raw === "string" && raw.trim() === "" && !(field === "limit" && paginatedLimit)) {
|
|
13385
|
+
throw new SimApiError(`--${flagName} cannot be empty`, 0);
|
|
13386
|
+
}
|
|
13157
13387
|
const value = coerce(raw ?? undefined, descriptor, flag, flagName);
|
|
13158
13388
|
if (value === undefined) {
|
|
13159
13389
|
if (descriptor.required) {
|
|
13160
|
-
throw new SimApiError(field === PROFILE_INJECTED_FIELD ?
|
|
13390
|
+
throw new SimApiError(field === PROFILE_INJECTED_FIELD ? NO_WORKSPACE_FALLBACK : `--${flagName} is required`, 0);
|
|
13161
13391
|
}
|
|
13162
13392
|
continue;
|
|
13163
13393
|
}
|
|
@@ -13204,6 +13434,126 @@ function buildRequest(operation, positional, flags, workspaceId) {
|
|
|
13204
13434
|
};
|
|
13205
13435
|
}
|
|
13206
13436
|
|
|
13437
|
+
// src/runtime/options.ts
|
|
13438
|
+
var DEFAULT_LIMIT = 100;
|
|
13439
|
+
function describeField(flag, descriptor, name, field) {
|
|
13440
|
+
return flag.describe ?? descriptor.describe ?? `Set ${name.replaceAll("-", " ") || field}`;
|
|
13441
|
+
}
|
|
13442
|
+
function literalNullHint(documented, name) {
|
|
13443
|
+
return /\bnull\b/i.test(documented) ? ` (--${name} null sends the word, not JSON null)` : "";
|
|
13444
|
+
}
|
|
13445
|
+
var WIRE_VOCABULARY_SENTENCE = /\s*The listed spellings[^.]*\.\s*/g;
|
|
13446
|
+
function withoutWireVocabulary(documented) {
|
|
13447
|
+
return documented.replace(WIRE_VOCABULARY_SENTENCE, " ").trim();
|
|
13448
|
+
}
|
|
13449
|
+
var NON_PAGINATED_LIMIT_HINT = " (caps a --filter match only; omit it to act on every match, and note 0 is not accepted)";
|
|
13450
|
+
function addFieldOption(command, operation, field, descriptor, slot, paginates) {
|
|
13451
|
+
if (field === PROFILE_INJECTED_FIELD || field === "cursor")
|
|
13452
|
+
return;
|
|
13453
|
+
const flag = flagSpecFor(operation, field);
|
|
13454
|
+
if (flag.omit)
|
|
13455
|
+
return;
|
|
13456
|
+
const name = flagNameFor(operation, field);
|
|
13457
|
+
const short = flag.short ? `-${flag.short}, ` : "";
|
|
13458
|
+
if (paginates && field === "limit" && (descriptor.kind === "number" || descriptor.kind === "integer")) {
|
|
13459
|
+
command.option("--limit <n>", "Maximum items to return (0 for everything)", String(DEFAULT_LIMIT));
|
|
13460
|
+
return;
|
|
13461
|
+
}
|
|
13462
|
+
const documented = `${describeField(flag, descriptor, name, field)}${field === "limit" && (descriptor.kind === "number" || descriptor.kind === "integer") ? NON_PAGINATED_LIMIT_HINT : ""}`;
|
|
13463
|
+
if (descriptor.kind === "boolean" || flag.boolean) {
|
|
13464
|
+
const booleanDoc = withoutWireVocabulary(documented);
|
|
13465
|
+
if (descriptor.required) {
|
|
13466
|
+
command.addOption(new Option(`${short}--${name} <true|false>`, `${booleanDoc} (required)`).choices(["true", "false"]).makeOptionMandatory());
|
|
13467
|
+
return;
|
|
13468
|
+
}
|
|
13469
|
+
command.option(`${short}--${name}`, booleanDoc);
|
|
13470
|
+
if (!flag.boolean || flag.negatable) {
|
|
13471
|
+
command.option(`--no-${name}`, `Send --${name} as false`);
|
|
13472
|
+
}
|
|
13473
|
+
return;
|
|
13474
|
+
}
|
|
13475
|
+
const takesList = flag.list === true;
|
|
13476
|
+
const wantsJson = takesJson(descriptor, flag);
|
|
13477
|
+
const placeholder = takesList ? "<value...>" : flag.rowCap ? "<n>" : wantsJson ? "<json|@file>" : "<value>";
|
|
13478
|
+
const choices = flag.choices ?? descriptor.values;
|
|
13479
|
+
const literalNull = slot === "body" && !takesList && !wantsJson;
|
|
13480
|
+
const describe = `${documented}${takesList ? " (space-separated, or @path / @- with one value per line; @@value for a literal leading @)" : wantsJson ? " (JSON, or @path / @- to read a file or stdin)" : ""}${descriptor.required ? " (required)" : ""}${literalNull ? literalNullHint(documented, name) : ""}`;
|
|
13481
|
+
const renamedFrom = flag.renamedFrom ?? [];
|
|
13482
|
+
const option = new Option(`${short}--${name} ${placeholder}`, describe);
|
|
13483
|
+
if (flag.hidden)
|
|
13484
|
+
option.hideHelp();
|
|
13485
|
+
if (choices && !takesList)
|
|
13486
|
+
option.choices([...choices]);
|
|
13487
|
+
if (descriptor.default !== undefined && field !== "limit") {
|
|
13488
|
+
option.default(undefined, String(descriptor.default));
|
|
13489
|
+
}
|
|
13490
|
+
if (descriptor.required && renamedFrom.length === 0)
|
|
13491
|
+
option.makeOptionMandatory();
|
|
13492
|
+
command.addOption(option);
|
|
13493
|
+
for (const previous of renamedFrom) {
|
|
13494
|
+
const retired = new Option(`--${previous} ${placeholder}`).hideHelp();
|
|
13495
|
+
if (choices && !takesList)
|
|
13496
|
+
retired.choices([...choices]);
|
|
13497
|
+
command.addOption(retired);
|
|
13498
|
+
}
|
|
13499
|
+
}
|
|
13500
|
+
function addOperationOptions(command, operation, commandSpec, operationSpec) {
|
|
13501
|
+
for (const param of operationSpec.pathParams) {
|
|
13502
|
+
const flag = commandSpec.pathFlags?.[param];
|
|
13503
|
+
if (!flag)
|
|
13504
|
+
continue;
|
|
13505
|
+
const name = pathFlagNameFor(commandSpec, param);
|
|
13506
|
+
const short = flag.short ? `-${flag.short}, ` : "";
|
|
13507
|
+
command.addOption(new Option(`${short}--${name} <${flag.placeholder ?? "value"}>`, `${flag.describe ?? operationSpec.pathParamDocs?.[param] ?? `Set ${name.replaceAll("-", " ")}`} (required)`).makeOptionMandatory());
|
|
13508
|
+
}
|
|
13509
|
+
const paginates = cursorSlot(operationSpec) !== null;
|
|
13510
|
+
for (const slot of ["query", "body", "headers"]) {
|
|
13511
|
+
for (const [field, descriptor] of Object.entries(operationSpec[slot] ?? {})) {
|
|
13512
|
+
if (commandSpec.requestFields && !commandSpec.requestFields.includes(field))
|
|
13513
|
+
continue;
|
|
13514
|
+
if (commandSpec.positionals?.includes(field))
|
|
13515
|
+
continue;
|
|
13516
|
+
addFieldOption(command, operation, field, descriptor, slot, paginates);
|
|
13517
|
+
}
|
|
13518
|
+
}
|
|
13519
|
+
if (commandSpec.allWorkspaces) {
|
|
13520
|
+
command.option("--all-workspaces", "Do not filter to the configured workspace (personal API key required for account-wide access)");
|
|
13521
|
+
}
|
|
13522
|
+
if (commandSpec.expandedTrace) {
|
|
13523
|
+
command.option("--trace", "Show expanded trace spans with inputs, outputs, errors, timing, and cost");
|
|
13524
|
+
}
|
|
13525
|
+
if (operationSpec.opaqueBody) {
|
|
13526
|
+
if (commandSpec.bodyVariants) {
|
|
13527
|
+
for (const variant of commandSpec.bodyVariants) {
|
|
13528
|
+
command.option(`--${variant.name} <json|@file>`, `${variant.describe} (JSON, or @path / @-; choose exactly one body flag)`);
|
|
13529
|
+
}
|
|
13530
|
+
} else {
|
|
13531
|
+
command.requiredOption("--body <json|@file>", "Request body as JSON (or @path / @- to read a file or stdin) (required)");
|
|
13532
|
+
}
|
|
13533
|
+
}
|
|
13534
|
+
if (commandSpec.confirm) {
|
|
13535
|
+
const exemptedByDryRun = operationSpec.query?.dryRun !== undefined || operationSpec.body?.dryRun !== undefined;
|
|
13536
|
+
command.option("-y, --yes", exemptedByDryRun ? "Confirm this destructive operation (required unless --dry-run)" : "Confirm this destructive operation (required)");
|
|
13537
|
+
}
|
|
13538
|
+
}
|
|
13539
|
+
|
|
13540
|
+
// src/runtime/renamed.ts
|
|
13541
|
+
var warned = new Set;
|
|
13542
|
+
function warn(kind, from, to) {
|
|
13543
|
+
const key = `${kind}:${from}`;
|
|
13544
|
+
if (warned.has(key))
|
|
13545
|
+
return;
|
|
13546
|
+
warned.add(key);
|
|
13547
|
+
process.stderr.write(`warning: ${kind} "${from}" has been renamed to "${to}". The old name still works.
|
|
13548
|
+
`);
|
|
13549
|
+
}
|
|
13550
|
+
function warnRenamedCommand(from, to) {
|
|
13551
|
+
warn("command", `sim ${from}`, `sim ${to}`);
|
|
13552
|
+
}
|
|
13553
|
+
function warnRenamedFlag(from, to) {
|
|
13554
|
+
warn("flag", `--${from}`, `--${to}`);
|
|
13555
|
+
}
|
|
13556
|
+
|
|
13207
13557
|
// src/output/trace.ts
|
|
13208
13558
|
function traceSpan(value) {
|
|
13209
13559
|
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
@@ -13333,7 +13683,8 @@ function at(row, path) {
|
|
|
13333
13683
|
function decodeFolderPath(value) {
|
|
13334
13684
|
return value.split("/").map((segment) => {
|
|
13335
13685
|
try {
|
|
13336
|
-
|
|
13686
|
+
const decoded = decodeURIComponent(segment);
|
|
13687
|
+
return decoded.includes("/") ? segment : decoded;
|
|
13337
13688
|
} catch {
|
|
13338
13689
|
return segment;
|
|
13339
13690
|
}
|
|
@@ -13464,8 +13815,10 @@ function unwrapResource(data) {
|
|
|
13464
13815
|
const [, value] = entries[0];
|
|
13465
13816
|
return value && typeof value === "object" && !Array.isArray(value) ? value : data;
|
|
13466
13817
|
}
|
|
13467
|
-
function renderPage(format, rows, spec, envelope) {
|
|
13818
|
+
function renderPage(format, rows, spec, envelope, options = {}) {
|
|
13468
13819
|
writePageNote(spec, envelope);
|
|
13820
|
+
writeEnvelopeTruncation(envelope);
|
|
13821
|
+
writeCursorTruncation(rows.length, options.truncated === true);
|
|
13469
13822
|
printList(format, rows, spec.columns ? columnsFrom(spec.columns) : inferColumns(rows, spec.expand));
|
|
13470
13823
|
}
|
|
13471
13824
|
function writePageNote(spec, envelope) {
|
|
@@ -13477,7 +13830,48 @@ function writePageNote(spec, envelope) {
|
|
|
13477
13830
|
process.stderr.write(source_default.dim(`${spec.pageNote.label}: ${String(value)}
|
|
13478
13831
|
`));
|
|
13479
13832
|
}
|
|
13480
|
-
|
|
13833
|
+
var TRUNCATION_FLAG = /^truncated$|^[A-Za-z0-9]+Truncated$/;
|
|
13834
|
+
var NEGATED_TRUNCATION_FLAG = /^(?:not|un|non|never)Truncated$|(?:Not|Un|Non|Never)Truncated$/;
|
|
13835
|
+
function truncationFlags(container) {
|
|
13836
|
+
if (!container || typeof container !== "object" || Array.isArray(container))
|
|
13837
|
+
return [];
|
|
13838
|
+
return Object.entries(container).filter(([key, value]) => value === true && TRUNCATION_FLAG.test(key) && !NEGATED_TRUNCATION_FLAG.test(key)).map(([key]) => key);
|
|
13839
|
+
}
|
|
13840
|
+
function responseTruncationFlags(envelope) {
|
|
13841
|
+
return [...truncationFlags(envelope), ...truncationFlags(at(envelope, "data"))];
|
|
13842
|
+
}
|
|
13843
|
+
function foldPageEnvelope(current, page) {
|
|
13844
|
+
if (current === undefined)
|
|
13845
|
+
return page;
|
|
13846
|
+
const raised = truncationFlags(page);
|
|
13847
|
+
if (raised.length === 0 || !current || typeof current !== "object")
|
|
13848
|
+
return current;
|
|
13849
|
+
return {
|
|
13850
|
+
...current,
|
|
13851
|
+
...Object.fromEntries(raised.map((flag) => [flag, true]))
|
|
13852
|
+
};
|
|
13853
|
+
}
|
|
13854
|
+
function spellOut(flag) {
|
|
13855
|
+
return flag.replace(/([a-z])([A-Z])/g, "$1 $2").toLowerCase().trim();
|
|
13856
|
+
}
|
|
13857
|
+
function clippedSubject(flag) {
|
|
13858
|
+
const subject = flag.replace(/^truncated$|Truncated$/, "").replace(/^is(?=[A-Z]|$)/, "");
|
|
13859
|
+
return subject ? `the ${spellOut(subject)} it returned` : "this result";
|
|
13860
|
+
}
|
|
13861
|
+
function writeEnvelopeTruncation(envelope) {
|
|
13862
|
+
for (const flag of responseTruncationFlags(envelope)) {
|
|
13863
|
+
process.stderr.write(source_default.dim(`${spellOut(flag)}: the server clipped ${clippedSubject(flag)}, so the answer is incomplete
|
|
13864
|
+
`));
|
|
13865
|
+
}
|
|
13866
|
+
}
|
|
13867
|
+
function writeCursorTruncation(count, truncated) {
|
|
13868
|
+
if (!truncated)
|
|
13869
|
+
return;
|
|
13870
|
+
process.stderr.write(source_default.dim(`showing the first ${count}; more results exist — re-run with --limit 0 for all
|
|
13871
|
+
`));
|
|
13872
|
+
}
|
|
13873
|
+
function renderResult(operation, format, raw, spec, options = {}, envelope) {
|
|
13874
|
+
writeEnvelopeTruncation(envelope);
|
|
13481
13875
|
if (spec.document) {
|
|
13482
13876
|
printDocument(format, raw);
|
|
13483
13877
|
return;
|
|
@@ -13509,31 +13903,577 @@ function renderResult(operation, format, raw, spec, options = {}) {
|
|
|
13509
13903
|
}
|
|
13510
13904
|
}
|
|
13511
13905
|
|
|
13512
|
-
// src/
|
|
13513
|
-
var
|
|
13514
|
-
|
|
13515
|
-
|
|
13516
|
-
|
|
13517
|
-
]
|
|
13518
|
-
};
|
|
13519
|
-
var SERVICE_ACCOUNT_RESULT = {
|
|
13520
|
-
fields: [
|
|
13521
|
-
{ header: "id" },
|
|
13522
|
-
{ header: "name", path: "displayName" },
|
|
13523
|
-
{ header: "provider", path: "providerId" },
|
|
13524
|
-
{ header: "role" },
|
|
13525
|
-
{ header: "created", path: "createdAt", format: "timestamp" }
|
|
13526
|
-
]
|
|
13906
|
+
// src/runtime/execute.ts
|
|
13907
|
+
var RUN_OUTCOME_OPERATIONS = new Set(["executeWorkflow"]);
|
|
13908
|
+
var FAILED_RUN_STATUS_MESSAGES = {
|
|
13909
|
+
failed: "The workflow run failed.",
|
|
13910
|
+
cancelled: "The workflow run was cancelled."
|
|
13527
13911
|
};
|
|
13528
|
-
function
|
|
13529
|
-
|
|
13530
|
-
|
|
13531
|
-
|
|
13532
|
-
|
|
13533
|
-
|
|
13534
|
-
|
|
13535
|
-
|
|
13536
|
-
|
|
13912
|
+
function runFailureMessage(operation, payload) {
|
|
13913
|
+
if (!RUN_OUTCOME_OPERATIONS.has(operation))
|
|
13914
|
+
return null;
|
|
13915
|
+
if (!payload || typeof payload !== "object" || Array.isArray(payload))
|
|
13916
|
+
return null;
|
|
13917
|
+
const { status, error } = payload;
|
|
13918
|
+
if (typeof status !== "string")
|
|
13919
|
+
return null;
|
|
13920
|
+
const fallback = FAILED_RUN_STATUS_MESSAGES[status];
|
|
13921
|
+
if (!fallback)
|
|
13922
|
+
return null;
|
|
13923
|
+
const reported2 = error?.message;
|
|
13924
|
+
return safeOneLine(typeof reported2 === "string" && reported2 ? reported2 : fallback);
|
|
13925
|
+
}
|
|
13926
|
+
var BULK_OUTCOME_CHECKS = {
|
|
13927
|
+
bulkDeleteFiles: (payload, body) => {
|
|
13928
|
+
if (countOf(payload.deletedItems?.files) > 0)
|
|
13929
|
+
return null;
|
|
13930
|
+
const requested = lengthOf(body?.fileIds);
|
|
13931
|
+
if (requested === 0)
|
|
13932
|
+
return null;
|
|
13933
|
+
return `Deleted nothing: none of the ${requested} requested ${requested === 1 ? "file was" : "files were"} deleted.`;
|
|
13934
|
+
},
|
|
13935
|
+
addWorkspaceFilesToKnowledgeBase: (payload) => {
|
|
13936
|
+
if (lengthOf(payload.added) > 0)
|
|
13937
|
+
return null;
|
|
13938
|
+
const failed = lengthOf(payload.failed);
|
|
13939
|
+
if (failed === 0)
|
|
13940
|
+
return null;
|
|
13941
|
+
return `Indexed nothing: none of the ${failed} requested ${failed === 1 ? "file was" : "files were"} added.`;
|
|
13942
|
+
},
|
|
13943
|
+
bulkDeleteTables: (payload) => {
|
|
13944
|
+
const items = payload.deletedItems;
|
|
13945
|
+
const deleted = countOf(items?.tables) + countOf(items?.folders);
|
|
13946
|
+
if (deleted > 0)
|
|
13947
|
+
return null;
|
|
13948
|
+
const missed = lengthOf(payload.notFound) + lengthOf(payload.failed);
|
|
13949
|
+
if (missed === 0)
|
|
13950
|
+
return null;
|
|
13951
|
+
return `Deleted nothing: ${missed} of ${missed} ${missed === 1 ? "item was" : "items were"} not found or could not be deleted.`;
|
|
13952
|
+
},
|
|
13953
|
+
bulkUpdateKnowledgeChunks: (payload, body) => {
|
|
13954
|
+
if (countOf(payload.processed) > 0)
|
|
13955
|
+
return null;
|
|
13956
|
+
const requested = lengthOf(body?.chunkIds);
|
|
13957
|
+
if (requested === 0)
|
|
13958
|
+
return null;
|
|
13959
|
+
const reported2 = payload.errors?.[0];
|
|
13960
|
+
return typeof reported2 === "string" && reported2 ? safeOneLine(reported2) : `Updated nothing: none of the ${requested} requested ${requested === 1 ? "chunk" : "chunks"} matched.`;
|
|
13961
|
+
},
|
|
13962
|
+
moveTables: (payload) => {
|
|
13963
|
+
if (lengthOf(payload.moved) > 0)
|
|
13964
|
+
return null;
|
|
13965
|
+
const missed = lengthOf(payload.notFound) + lengthOf(payload.failed);
|
|
13966
|
+
if (missed === 0)
|
|
13967
|
+
return null;
|
|
13968
|
+
return `Moved nothing: ${missed} of ${missed} ${missed === 1 ? "item was" : "items were"} not found or could not be moved.`;
|
|
13969
|
+
},
|
|
13970
|
+
moveWorkflows: (payload) => {
|
|
13971
|
+
if (lengthOf(payload.moved) > 0)
|
|
13972
|
+
return null;
|
|
13973
|
+
const failed = lengthOf(payload.failed);
|
|
13974
|
+
if (failed === 0)
|
|
13975
|
+
return null;
|
|
13976
|
+
return `Moved nothing: ${failed} of ${failed} ${failed === 1 ? "workflow" : "workflows"} could not be moved.`;
|
|
13977
|
+
}
|
|
13978
|
+
};
|
|
13979
|
+
function countOf(value) {
|
|
13980
|
+
return typeof value === "number" && Number.isFinite(value) ? value : 0;
|
|
13981
|
+
}
|
|
13982
|
+
function lengthOf(value) {
|
|
13983
|
+
return Array.isArray(value) ? value.length : 0;
|
|
13984
|
+
}
|
|
13985
|
+
function bulkFailureMessage(operation, payload, body) {
|
|
13986
|
+
const check = BULK_OUTCOME_CHECKS[operation];
|
|
13987
|
+
if (!check)
|
|
13988
|
+
return null;
|
|
13989
|
+
if (!payload || typeof payload !== "object" || Array.isArray(payload))
|
|
13990
|
+
return null;
|
|
13991
|
+
return check(payload, body);
|
|
13992
|
+
}
|
|
13993
|
+
var EXCLUSIVE_CAP_FIELDS = {
|
|
13994
|
+
deleteTableRows: { cap: "limit", ids: "rowIds" }
|
|
13995
|
+
};
|
|
13996
|
+
function assertCapIsUsable(operation, flags) {
|
|
13997
|
+
const exclusive = EXCLUSIVE_CAP_FIELDS[operation];
|
|
13998
|
+
if (!exclusive)
|
|
13999
|
+
return;
|
|
14000
|
+
const cap = flagNameFor(operation, exclusive.cap);
|
|
14001
|
+
const ids = flagNameFor(operation, exclusive.ids);
|
|
14002
|
+
if (flags[camel(cap)] === undefined || flags[camel(ids)] === undefined)
|
|
14003
|
+
return;
|
|
14004
|
+
throw new SimApiError(`--${cap} caps a --filter match and does nothing to an explicit --${ids} list; pass one, not both`, 0);
|
|
14005
|
+
}
|
|
14006
|
+
function foldRenamedFlags(operation, commandSpec, flags) {
|
|
14007
|
+
for (const [field, flag] of Object.entries(commandSpec.flags ?? {})) {
|
|
14008
|
+
if (!flag.renamedFrom?.length)
|
|
14009
|
+
continue;
|
|
14010
|
+
const current = flagNameFor(operation, field);
|
|
14011
|
+
for (const previous of flag.renamedFrom) {
|
|
14012
|
+
const supplied = flags[camel(previous)];
|
|
14013
|
+
if (supplied === undefined)
|
|
14014
|
+
continue;
|
|
14015
|
+
if (flags[camel(current)] !== undefined) {
|
|
14016
|
+
throw new SimApiError(`--${previous} is the former name of --${current}; pass one, not both`, 0);
|
|
14017
|
+
}
|
|
14018
|
+
warnRenamedFlag(previous, current);
|
|
14019
|
+
flags[camel(current)] = supplied;
|
|
14020
|
+
}
|
|
14021
|
+
}
|
|
14022
|
+
}
|
|
14023
|
+
async function executeOperation(operation, commandSpec, operationSpec, invocation) {
|
|
14024
|
+
const host = invocation[invocation.length - 1];
|
|
14025
|
+
const inheritedFlags = host.optsWithGlobals();
|
|
14026
|
+
const flags = {
|
|
14027
|
+
...inheritedFlags.workspace === undefined ? {} : { workspace: inheritedFlags.workspace },
|
|
14028
|
+
...inheritedFlags.allWorkspaces === undefined ? {} : { allWorkspaces: inheritedFlags.allWorkspaces },
|
|
14029
|
+
...invocation[invocation.length - 2]
|
|
14030
|
+
};
|
|
14031
|
+
const pathPositionalCount = operationSpec.pathParams.filter((param) => !commandSpec.pathFlags?.[param] && !isProfileWorkspacePath(commandSpec, param)).length;
|
|
14032
|
+
const positional = invocation.slice(0, pathPositionalCount);
|
|
14033
|
+
const requestFlags = { ...flags };
|
|
14034
|
+
for (const [index, field] of (commandSpec.positionals ?? []).entries()) {
|
|
14035
|
+
requestFlags[camel(flagNameFor(operation, field))] = invocation[pathPositionalCount + index];
|
|
14036
|
+
}
|
|
14037
|
+
foldRenamedFlags(operation, commandSpec, requestFlags);
|
|
14038
|
+
assertCapIsUsable(operation, requestFlags);
|
|
14039
|
+
if (commandSpec.confirm && !requestFlags.yes && requestFlags.dryRun !== true) {
|
|
14040
|
+
throw new SimApiError(`${commandSpec.confirm} Re-run with --yes to confirm.`, 0);
|
|
14041
|
+
}
|
|
14042
|
+
if (commandSpec.allWorkspaces && requestFlags.allWorkspaces && requestFlags.workspace) {
|
|
14043
|
+
throw new SimApiError("--all-workspaces cannot be combined with --workspace", 0);
|
|
14044
|
+
}
|
|
14045
|
+
const { client, profile } = clientFrom(host);
|
|
14046
|
+
const hasWorkspaceField = Boolean(operationSpec.query && PROFILE_INJECTED_FIELD in operationSpec.query || operationSpec.body && PROFILE_INJECTED_FIELD in operationSpec.body);
|
|
14047
|
+
const omitsWorkspace = commandSpec.allWorkspaces && requestFlags.allWorkspaces === true;
|
|
14048
|
+
const needsWorkspace = (hasWorkspaceField || commandSpec.profileWorkspacePath === true) && !omitsWorkspace;
|
|
14049
|
+
const request = buildRequest(operation, positional, requestFlags, needsWorkspace ? client.requireWorkspace() : profile.workspaceId);
|
|
14050
|
+
const paging = cursorSlot(operationSpec);
|
|
14051
|
+
if (paging) {
|
|
14052
|
+
const limitText = String(requestFlags.limit ?? DEFAULT_LIMIT).trim();
|
|
14053
|
+
const rawLimit = limitText === "" ? Number.NaN : Number(limitText);
|
|
14054
|
+
if (!Number.isInteger(rawLimit) || rawLimit < 0) {
|
|
14055
|
+
throw new SimApiError("--limit must be a whole number of 0 or more (0 for everything)", 0);
|
|
14056
|
+
}
|
|
14057
|
+
const limit = rawLimit === 0 ? Number.POSITIVE_INFINITY : rawLimit;
|
|
14058
|
+
const pageSize = Math.min(Number.isFinite(limit) ? limit : DEFAULT_LIMIT, DEFAULT_LIMIT);
|
|
14059
|
+
const pageLimit = "limit" in (operationSpec[paging] ?? {}) ? { limit: pageSize } : {};
|
|
14060
|
+
const rows = [];
|
|
14061
|
+
const progress = pageProgress();
|
|
14062
|
+
let cursor = null;
|
|
14063
|
+
let envelope;
|
|
14064
|
+
try {
|
|
14065
|
+
do {
|
|
14066
|
+
const page = await client.request(request.path, {
|
|
14067
|
+
method: operationSpec.method,
|
|
14068
|
+
headers: request.headers,
|
|
14069
|
+
query: paging === "query" ? { ...request.query, ...pageLimit, cursor } : request.query,
|
|
14070
|
+
body: paging === "body" ? { ...request.body ?? {}, ...pageLimit, ...cursor ? { cursor } : {} } : request.body
|
|
14071
|
+
});
|
|
14072
|
+
envelope = foldPageEnvelope(envelope, page);
|
|
14073
|
+
rows.push(...page.data);
|
|
14074
|
+
cursor = page.nextCursor;
|
|
14075
|
+
if (cursor && rows.length < limit)
|
|
14076
|
+
progress.advance(rows.length);
|
|
14077
|
+
} while (cursor && rows.length < limit);
|
|
14078
|
+
} finally {
|
|
14079
|
+
progress.finish();
|
|
14080
|
+
}
|
|
14081
|
+
renderPage(profile.output, Number.isFinite(limit) ? rows.slice(0, limit) : rows, commandSpec, envelope, { truncated: Boolean(cursor) });
|
|
14082
|
+
return;
|
|
14083
|
+
}
|
|
14084
|
+
const result = await client.request(request.path, {
|
|
14085
|
+
method: operationSpec.method,
|
|
14086
|
+
headers: request.headers,
|
|
14087
|
+
query: request.query,
|
|
14088
|
+
body: request.body
|
|
14089
|
+
});
|
|
14090
|
+
const payload = result?.data ?? result;
|
|
14091
|
+
renderResult(operation, profile.output, payload, commandSpec, { expandedTrace: requestFlags.trace === true }, result);
|
|
14092
|
+
const failure = runFailureMessage(operation, payload) ?? bulkFailureMessage(operation, payload, request.body);
|
|
14093
|
+
if (failure)
|
|
14094
|
+
throw new SimApiError(failure, 0);
|
|
14095
|
+
}
|
|
14096
|
+
|
|
14097
|
+
// src/runtime/naming.ts
|
|
14098
|
+
var WIRE_IDENTIFIER = /^[a-z]+[A-Z]/;
|
|
14099
|
+
function spellingFor(operation, commandSpec, operationSpec, field) {
|
|
14100
|
+
if (field === PROFILE_INJECTED_FIELD)
|
|
14101
|
+
return "--workspace";
|
|
14102
|
+
if (field === "cursor")
|
|
14103
|
+
return null;
|
|
14104
|
+
if (operationSpec.pathParams.includes(field)) {
|
|
14105
|
+
return commandSpec.pathFlags?.[field] ? `--${pathFlagNameFor(commandSpec, field)}` : `<${commandSpec.pathArgumentNames?.[field] ?? field}>`;
|
|
14106
|
+
}
|
|
14107
|
+
if (commandSpec.positionals?.includes(field))
|
|
14108
|
+
return `<${flagNameFor(operation, field)}>`;
|
|
14109
|
+
if (flagSpecFor(operation, field).omit)
|
|
14110
|
+
return null;
|
|
14111
|
+
if (commandSpec.requestFields && !commandSpec.requestFields.includes(field))
|
|
14112
|
+
return null;
|
|
14113
|
+
const declared = operationSpec.query && field in operationSpec.query || operationSpec.body && field in operationSpec.body || operationSpec.headers && field in operationSpec.headers;
|
|
14114
|
+
if (!declared)
|
|
14115
|
+
return null;
|
|
14116
|
+
return `--${flagNameFor(operation, field)}`;
|
|
14117
|
+
}
|
|
14118
|
+
function typeableFields(operation, commandSpec, operationSpec) {
|
|
14119
|
+
const spellings = new Map;
|
|
14120
|
+
const fields = [
|
|
14121
|
+
...operationSpec.pathParams,
|
|
14122
|
+
...Object.keys(operationSpec.query ?? {}),
|
|
14123
|
+
...Object.keys(operationSpec.body ?? {}),
|
|
14124
|
+
...Object.keys(operationSpec.headers ?? {})
|
|
14125
|
+
];
|
|
14126
|
+
for (const field of fields) {
|
|
14127
|
+
if (spellings.has(field))
|
|
14128
|
+
continue;
|
|
14129
|
+
const spelling = spellingFor(operation, commandSpec, operationSpec, field);
|
|
14130
|
+
if (spelling)
|
|
14131
|
+
spellings.set(field, spelling);
|
|
14132
|
+
}
|
|
14133
|
+
return spellings;
|
|
14134
|
+
}
|
|
14135
|
+
function retypeMessage(message, spellings) {
|
|
14136
|
+
let retyped = message;
|
|
14137
|
+
for (const [field, spelling] of spellings) {
|
|
14138
|
+
if (!WIRE_IDENTIFIER.test(field))
|
|
14139
|
+
continue;
|
|
14140
|
+
retyped = retyped.replaceAll(new RegExp(`\\b${field}\\b`, "g"), spelling);
|
|
14141
|
+
}
|
|
14142
|
+
return retyped;
|
|
14143
|
+
}
|
|
14144
|
+
function retypeDetails(details, spellings) {
|
|
14145
|
+
if (Array.isArray(details))
|
|
14146
|
+
return details.map((issue2) => retypeDetails(issue2, spellings));
|
|
14147
|
+
if (!details || typeof details !== "object")
|
|
14148
|
+
return details;
|
|
14149
|
+
const issue = details;
|
|
14150
|
+
const retyped = { ...issue };
|
|
14151
|
+
if (Array.isArray(issue.path) && issue.path.length > 0) {
|
|
14152
|
+
const [head, ...rest] = issue.path.map(String);
|
|
14153
|
+
const spelling = spellings.get(head);
|
|
14154
|
+
if (spelling)
|
|
14155
|
+
retyped.path = [spelling, ...rest];
|
|
14156
|
+
}
|
|
14157
|
+
if (typeof issue.message === "string") {
|
|
14158
|
+
retyped.message = retypeMessage(issue.message, spellings);
|
|
14159
|
+
}
|
|
14160
|
+
if (Array.isArray(issue.errors)) {
|
|
14161
|
+
retyped.errors = retypeDetails(issue.errors, spellings);
|
|
14162
|
+
}
|
|
14163
|
+
return retyped;
|
|
14164
|
+
}
|
|
14165
|
+
function retypeApiError(error, operation, commandSpec, operationSpec) {
|
|
14166
|
+
if (!(error instanceof SimApiError) || error.status === 0)
|
|
14167
|
+
return error;
|
|
14168
|
+
const spellings = typeableFields(operation, commandSpec, operationSpec);
|
|
14169
|
+
if (spellings.size === 0)
|
|
14170
|
+
return error;
|
|
14171
|
+
return new SimApiError(retypeMessage(error.message, spellings), error.status, error.code, error.details === undefined ? undefined : retypeDetails(error.details, spellings));
|
|
14172
|
+
}
|
|
14173
|
+
|
|
14174
|
+
// src/runtime/build.ts
|
|
14175
|
+
var GROUP_ALIASES = {
|
|
14176
|
+
"audit-logs": "audit-log",
|
|
14177
|
+
credentials: "credential",
|
|
14178
|
+
"custom-tools": "custom-tool",
|
|
14179
|
+
files: "file",
|
|
14180
|
+
knowledge: "kb",
|
|
14181
|
+
logs: "log",
|
|
14182
|
+
"mcp-servers": "mcp-server",
|
|
14183
|
+
secrets: "secret",
|
|
14184
|
+
skills: "skill",
|
|
14185
|
+
tables: "table",
|
|
14186
|
+
workflows: "workflow",
|
|
14187
|
+
workspaces: "workspace"
|
|
14188
|
+
};
|
|
14189
|
+
function describeOperation(operationSpec, described) {
|
|
14190
|
+
return operationSpec.personalKeyOnly ? `${described} (personal API key required)` : described;
|
|
14191
|
+
}
|
|
14192
|
+
function argumentSyntax(command) {
|
|
14193
|
+
return command.registeredArguments.map((argument) => {
|
|
14194
|
+
const name = `${argument.name()}${argument.variadic ? "..." : ""}`;
|
|
14195
|
+
return argument.required ? `<${name}>` : `[${name}]`;
|
|
14196
|
+
}).join(" ");
|
|
14197
|
+
}
|
|
14198
|
+
function commandPath(command) {
|
|
14199
|
+
const names = [];
|
|
14200
|
+
let current = command;
|
|
14201
|
+
while (current) {
|
|
14202
|
+
names.unshift(current.name());
|
|
14203
|
+
current = current.parent;
|
|
14204
|
+
}
|
|
14205
|
+
return names.join(" ");
|
|
14206
|
+
}
|
|
14207
|
+
function addMissingArgumentExample(command) {
|
|
14208
|
+
const outputError = command.configureOutput().outputError;
|
|
14209
|
+
if (!outputError)
|
|
14210
|
+
throw new Error("Commander output formatter is not configured");
|
|
14211
|
+
command.configureOutput({
|
|
14212
|
+
outputError: (message, write) => {
|
|
14213
|
+
outputError(message, write);
|
|
14214
|
+
if (!message.startsWith("error: missing required argument "))
|
|
14215
|
+
return;
|
|
14216
|
+
const syntax = argumentSyntax(command);
|
|
14217
|
+
const example = syntax ? `${commandPath(command)} ${syntax}` : commandPath(command);
|
|
14218
|
+
write(`Example: ${example}
|
|
14219
|
+
`);
|
|
14220
|
+
}
|
|
14221
|
+
});
|
|
14222
|
+
return command;
|
|
14223
|
+
}
|
|
14224
|
+
function assertNoReservedFlags(command, operation) {
|
|
14225
|
+
for (const option of command.options) {
|
|
14226
|
+
for (const flag of [option.long, option.short]) {
|
|
14227
|
+
if (flag && RESERVED_PROGRAM_FLAGS.has(flag)) {
|
|
14228
|
+
throw new Error(`${operation} declares ${flag}, which the root program already owns; give the flag another name`);
|
|
14229
|
+
}
|
|
14230
|
+
}
|
|
14231
|
+
}
|
|
14232
|
+
}
|
|
14233
|
+
var RESERVED_FLAG_EXEMPTIONS = new Set(["profiles add"]);
|
|
14234
|
+
function assertNoReservedProgramFlags(program2) {
|
|
14235
|
+
const walk = (command, prefix) => {
|
|
14236
|
+
const path = [...prefix, command.name()];
|
|
14237
|
+
const name = path.join(" ");
|
|
14238
|
+
if (!RESERVED_FLAG_EXEMPTIONS.has(name)) {
|
|
14239
|
+
for (const option of command.options) {
|
|
14240
|
+
for (const flag of [option.long, option.short]) {
|
|
14241
|
+
if (flag && RESERVED_PROGRAM_FLAGS.has(flag)) {
|
|
14242
|
+
throw new Error(`"sim ${name}" declares ${flag}, which the root program already owns; give the flag another name`);
|
|
14243
|
+
}
|
|
14244
|
+
}
|
|
14245
|
+
}
|
|
14246
|
+
}
|
|
14247
|
+
for (const child of command.commands)
|
|
14248
|
+
walk(child, path);
|
|
14249
|
+
};
|
|
14250
|
+
for (const child of program2.commands)
|
|
14251
|
+
walk(child, []);
|
|
14252
|
+
}
|
|
14253
|
+
function refuseHelpAfterUnknownCommand(program2) {
|
|
14254
|
+
const walk = (command) => {
|
|
14255
|
+
const internals = command;
|
|
14256
|
+
const dispatchesOnly = command.commands.length > 0 && !internals._actionHandler && command.registeredArguments.length === 0;
|
|
14257
|
+
if (dispatchesOnly) {
|
|
14258
|
+
const known = new Set(["help"]);
|
|
14259
|
+
for (const child of command.commands) {
|
|
14260
|
+
known.add(child.name());
|
|
14261
|
+
for (const alias of child.aliases())
|
|
14262
|
+
known.add(alias);
|
|
14263
|
+
}
|
|
14264
|
+
command.on("beforeHelp", () => {
|
|
14265
|
+
const first = command.args[0];
|
|
14266
|
+
if (first === undefined || first.startsWith("-") || known.has(first))
|
|
14267
|
+
return;
|
|
14268
|
+
internals.unknownCommand();
|
|
14269
|
+
});
|
|
14270
|
+
}
|
|
14271
|
+
for (const child of command.commands)
|
|
14272
|
+
walk(child);
|
|
14273
|
+
};
|
|
14274
|
+
walk(program2);
|
|
14275
|
+
}
|
|
14276
|
+
function configureOperation(command, operation, spec) {
|
|
14277
|
+
const operationSpec = V2_OPERATIONS[operation];
|
|
14278
|
+
command.allowExcessArguments(false);
|
|
14279
|
+
for (const alias of spec.aliases ?? [])
|
|
14280
|
+
command.alias(alias);
|
|
14281
|
+
for (const param of Object.keys(spec.pathFlags ?? {})) {
|
|
14282
|
+
if (!operationSpec.pathParams.includes(param)) {
|
|
14283
|
+
throw new Error(`${operation}.${param} is not a path parameter`);
|
|
14284
|
+
}
|
|
14285
|
+
}
|
|
14286
|
+
for (const param of Object.keys(spec.pathArgumentNames ?? {})) {
|
|
14287
|
+
if (!operationSpec.pathParams.includes(param)) {
|
|
14288
|
+
throw new Error(`${operation}.${param} is not a path parameter`);
|
|
14289
|
+
}
|
|
14290
|
+
if (spec.pathFlags?.[param]) {
|
|
14291
|
+
throw new Error(`${operation}.${param} cannot be both a path argument and a path flag`);
|
|
14292
|
+
}
|
|
14293
|
+
}
|
|
14294
|
+
if (spec.profileWorkspacePath) {
|
|
14295
|
+
if (!operationSpec.pathParams.includes(PROFILE_INJECTED_FIELD)) {
|
|
14296
|
+
throw new Error(`${operation}.profileWorkspacePath requires a workspaceId path parameter`);
|
|
14297
|
+
}
|
|
14298
|
+
if (spec.pathFlags?.[PROFILE_INJECTED_FIELD]) {
|
|
14299
|
+
throw new Error(`${operation}.workspaceId cannot be both profile-injected and a path flag`);
|
|
14300
|
+
}
|
|
14301
|
+
}
|
|
14302
|
+
for (const param of operationSpec.pathParams) {
|
|
14303
|
+
if (spec.pathFlags?.[param] || isProfileWorkspacePath(spec, param))
|
|
14304
|
+
continue;
|
|
14305
|
+
command.argument(`<${spec.pathArgumentNames?.[param] ?? param}>`, operationSpec.pathParamDocs?.[param]);
|
|
14306
|
+
}
|
|
14307
|
+
if (spec.allWorkspaces) {
|
|
14308
|
+
const workspace = operationSpec.query?.workspaceId ?? operationSpec.body?.workspaceId;
|
|
14309
|
+
if (!workspace || workspace.required) {
|
|
14310
|
+
throw new Error(`${operation}.allWorkspaces requires an optional workspaceId field`);
|
|
14311
|
+
}
|
|
14312
|
+
}
|
|
14313
|
+
for (const field of spec.positionals ?? []) {
|
|
14314
|
+
const descriptor = operationSpec.query?.[field] ?? operationSpec.body?.[field];
|
|
14315
|
+
if (!descriptor)
|
|
14316
|
+
throw new Error(`${operation}.${field} is not a request field`);
|
|
14317
|
+
if (spec.requestFields && !spec.requestFields.includes(field)) {
|
|
14318
|
+
throw new Error(`${operation}.${field} is positional but not exposed`);
|
|
14319
|
+
}
|
|
14320
|
+
command.argument(`<${flagNameFor(operation, field)}>`, flagSpecFor(operation, field).describe ?? descriptor.describe);
|
|
14321
|
+
}
|
|
14322
|
+
if (spec.requestFields) {
|
|
14323
|
+
for (const field of spec.requestFields) {
|
|
14324
|
+
if (!operationSpec.query?.[field] && !operationSpec.body?.[field] && !operationSpec.headers?.[field]) {
|
|
14325
|
+
throw new Error(`${operation}.${field} is not a request field`);
|
|
14326
|
+
}
|
|
14327
|
+
}
|
|
14328
|
+
for (const slot of ["query", "body", "headers"]) {
|
|
14329
|
+
for (const [field, descriptor] of Object.entries(operationSpec[slot] ?? {})) {
|
|
14330
|
+
if (descriptor.required && field !== PROFILE_INJECTED_FIELD && !spec.requestFields.includes(field)) {
|
|
14331
|
+
throw new Error(`${operation}.${field} is required but not exposed`);
|
|
14332
|
+
}
|
|
14333
|
+
}
|
|
14334
|
+
}
|
|
14335
|
+
}
|
|
14336
|
+
command.description(describeOperation(operationSpec, spec.describe ?? operationSpec.summary ?? `${operationSpec.method} ${operationSpec.path}`));
|
|
14337
|
+
addOperationOptions(command, operation, spec, operationSpec);
|
|
14338
|
+
assertNoReservedFlags(command, operation);
|
|
14339
|
+
command.action((...invocation) => executeOperation(operation, spec, operationSpec, invocation).catch((error) => {
|
|
14340
|
+
throw retypeApiError(error, operation, spec, operationSpec);
|
|
14341
|
+
}));
|
|
14342
|
+
return command;
|
|
14343
|
+
}
|
|
14344
|
+
function buildLeaf(operation, spec, leafName) {
|
|
14345
|
+
return addMissingArgumentExample(configureOperation(new Command(leafName), operation, spec));
|
|
14346
|
+
}
|
|
14347
|
+
function addRenamedCommand(groups, operation, spec, from, to) {
|
|
14348
|
+
const segments = from.split(" ");
|
|
14349
|
+
const [groupName, ...rest] = segments;
|
|
14350
|
+
if (rest.length === 0)
|
|
14351
|
+
throw new Error(`${operation}.renamedFrom "${from}" must include a verb`);
|
|
14352
|
+
let parent = groupFor(groups, groupName);
|
|
14353
|
+
for (const segment of rest.slice(0, -1)) {
|
|
14354
|
+
parent = nestedGroup(parent, segment, { hidden: true });
|
|
14355
|
+
}
|
|
14356
|
+
const leaf = buildLeaf(operation, spec, rest[rest.length - 1]);
|
|
14357
|
+
leaf.hook("preAction", () => warnRenamedCommand(from, to));
|
|
14358
|
+
addSubcommand(parent, leaf, { hidden: true });
|
|
14359
|
+
}
|
|
14360
|
+
function addSubcommand(parent, child, options = {}) {
|
|
14361
|
+
const wasLeaf = parent.commands.length === 0 && parent.registeredArguments.length > 0;
|
|
14362
|
+
const usage = wasLeaf ? parent.usage() : null;
|
|
14363
|
+
parent.addCommand(child, { hidden: options.hidden });
|
|
14364
|
+
if (usage !== null)
|
|
14365
|
+
parent.usage(usage);
|
|
14366
|
+
}
|
|
14367
|
+
function groupFor(groups, name) {
|
|
14368
|
+
const existing = groups.get(name);
|
|
14369
|
+
if (existing)
|
|
14370
|
+
return existing;
|
|
14371
|
+
const group = new Command(name).description(`Manage ${name.replaceAll("-", " ")}`);
|
|
14372
|
+
const alias = GROUP_ALIASES[name];
|
|
14373
|
+
if (alias)
|
|
14374
|
+
group.alias(alias);
|
|
14375
|
+
groups.set(name, group);
|
|
14376
|
+
return group;
|
|
14377
|
+
}
|
|
14378
|
+
function resourceLabel(name) {
|
|
14379
|
+
const label = name.endsWith("s") ? name.slice(0, -1) : name;
|
|
14380
|
+
return label.replaceAll("-", " ");
|
|
14381
|
+
}
|
|
14382
|
+
function nestedGroup(parent, name, options = {}) {
|
|
14383
|
+
const existing = parent.commands.find((candidate) => candidate.name() === name);
|
|
14384
|
+
if (existing)
|
|
14385
|
+
return existing;
|
|
14386
|
+
const created = new Command(name).description(`Manage ${resourceLabel(parent.name())} ${name.replaceAll("-", " ")}`);
|
|
14387
|
+
addSubcommand(parent, created, { hidden: options.hidden });
|
|
14388
|
+
return created;
|
|
14389
|
+
}
|
|
14390
|
+
function addLeafCommand(groups, operation, spec, segments) {
|
|
14391
|
+
const [groupName, ...rest] = segments;
|
|
14392
|
+
if (rest.length === 0)
|
|
14393
|
+
throw new Error(`${operation} leaf command must include a verb`);
|
|
14394
|
+
const group = groupFor(groups, groupName);
|
|
14395
|
+
if (rest.length > 1) {
|
|
14396
|
+
let parent = group;
|
|
14397
|
+
for (const segment of rest.slice(0, -1)) {
|
|
14398
|
+
parent = nestedGroup(parent, segment);
|
|
14399
|
+
}
|
|
14400
|
+
parent.addCommand(buildLeaf(operation, spec, rest[rest.length - 1]));
|
|
14401
|
+
return;
|
|
14402
|
+
}
|
|
14403
|
+
group.addCommand(buildLeaf(operation, spec, rest[0]));
|
|
14404
|
+
}
|
|
14405
|
+
function variantCommandSpec(spec, variant) {
|
|
14406
|
+
return {
|
|
14407
|
+
...spec,
|
|
14408
|
+
command: variant.command,
|
|
14409
|
+
groupDefault: false,
|
|
14410
|
+
aliases: [],
|
|
14411
|
+
positionals: variant.positionals,
|
|
14412
|
+
requestFields: variant.requestFields,
|
|
14413
|
+
variants: [],
|
|
14414
|
+
describe: variant.describe ?? spec.describe
|
|
14415
|
+
};
|
|
14416
|
+
}
|
|
14417
|
+
function buildGeneratedCommands() {
|
|
14418
|
+
const groups = new Map;
|
|
14419
|
+
const renamed = [];
|
|
14420
|
+
for (const operation of Object.keys(V2_OPERATIONS)) {
|
|
14421
|
+
const spec = CLI_CONTRACT[operation] ?? {};
|
|
14422
|
+
const operationSpec = V2_OPERATIONS[operation];
|
|
14423
|
+
if (spec.hidden || operationSpec.responseMode !== "json")
|
|
14424
|
+
continue;
|
|
14425
|
+
const segments = spec.command ? spec.command.split(" ") : deriveCommandPath(operation);
|
|
14426
|
+
if (spec.groupDefault) {
|
|
14427
|
+
const [groupName, ...rest] = segments;
|
|
14428
|
+
const group = groupFor(groups, groupName);
|
|
14429
|
+
if (rest.length > 0)
|
|
14430
|
+
throw new Error(`${operation} groupDefault must name a command group`);
|
|
14431
|
+
const pathPositionals = operationSpec.pathParams.filter((param) => !spec.pathFlags?.[param] && !isProfileWorkspacePath(spec, param));
|
|
14432
|
+
if (pathPositionals.length > 0 || spec.positionals?.length) {
|
|
14433
|
+
throw new Error(`${operation} groupDefault cannot require positional arguments`);
|
|
14434
|
+
}
|
|
14435
|
+
configureOperation(group, operation, spec);
|
|
14436
|
+
} else {
|
|
14437
|
+
addLeafCommand(groups, operation, spec, segments);
|
|
14438
|
+
}
|
|
14439
|
+
for (const variant of spec.variants ?? []) {
|
|
14440
|
+
addLeafCommand(groups, operation, variantCommandSpec(spec, variant), variant.command.split(" "));
|
|
14441
|
+
}
|
|
14442
|
+
for (const from of spec.renamedFrom ?? []) {
|
|
14443
|
+
renamed.push({ operation, spec, from, to: segments.join(" ") });
|
|
14444
|
+
}
|
|
14445
|
+
}
|
|
14446
|
+
for (const { operation, spec, from, to } of renamed) {
|
|
14447
|
+
addRenamedCommand(groups, operation, spec, from, to);
|
|
14448
|
+
}
|
|
14449
|
+
return [...groups.values()].sort((a, b) => a.name().localeCompare(b.name()));
|
|
14450
|
+
}
|
|
14451
|
+
|
|
14452
|
+
// src/commands/credentials.ts
|
|
14453
|
+
var CONNECTION_RESULT = {
|
|
14454
|
+
fields: [
|
|
14455
|
+
{ header: "connection link", path: "authorizationUrl" },
|
|
14456
|
+
{ header: "expires", path: "expiresAt", format: "timestamp" }
|
|
14457
|
+
]
|
|
14458
|
+
};
|
|
14459
|
+
var SERVICE_ACCOUNT_RESULT = {
|
|
14460
|
+
fields: [
|
|
14461
|
+
{ header: "id" },
|
|
14462
|
+
{ header: "name", path: "displayName" },
|
|
14463
|
+
{ header: "provider", path: "providerId" },
|
|
14464
|
+
{ header: "role" },
|
|
14465
|
+
{ header: "created", path: "createdAt", format: "timestamp" }
|
|
14466
|
+
]
|
|
14467
|
+
};
|
|
14468
|
+
function serviceAccountProvider(providers, providerId) {
|
|
14469
|
+
const provider = providers.find((candidate) => candidate.type === "service_account" && candidate.providerId === providerId);
|
|
14470
|
+
if (!provider) {
|
|
14471
|
+
throw new SimApiError(`Unknown service-account provider "${providerId}".`, 0);
|
|
14472
|
+
}
|
|
14473
|
+
if (!provider.available) {
|
|
14474
|
+
throw new SimApiError(`Service-account provider "${providerId}" is not available.`, 0);
|
|
14475
|
+
}
|
|
14476
|
+
return provider;
|
|
13537
14477
|
}
|
|
13538
14478
|
function credentialValues(provider, raw) {
|
|
13539
14479
|
const parsed = coerce(raw, { kind: "object" }, { json: true }, "credentials");
|
|
@@ -13620,9 +14560,9 @@ function attachCredentialCommands(program2) {
|
|
|
13620
14560
|
if (!credentials)
|
|
13621
14561
|
throw new Error("The generated credentials command group is missing");
|
|
13622
14562
|
acceptNameOnUpdate(credentials);
|
|
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));
|
|
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 }));
|
|
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 }));
|
|
14563
|
+
credentials.command("create").argument("<providerId>", "Service-account provider to create a credential for").description(describeOperation(V2_OPERATIONS.createServiceAccountCredential, "Create a service-account credential using its discovered provider schema")).requiredOption("--name <displayName>", "Name shown for the credential in Sim (required)").requiredOption("--credentials <json|@file>", "Provider credentials as JSON (or @path / @- to read a file or stdin) (required)").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));
|
|
14564
|
+
credentials.command("connect").argument("<providerId>", "OAuth provider to connect").description(describeOperation(V2_OPERATIONS.createCredentialConnection, "Create a short-lived link for connecting an OAuth provider")).requiredOption("--name <displayName>", "Name shown for the new credential in Sim (required)").action(async (providerId, options, command) => createConnectionLink(command, { providerId, displayName: options.name }));
|
|
14565
|
+
credentials.command("reconnect").argument("<credentialId>", "Existing OAuth credential to re-authorize").description(describeOperation(V2_OPERATIONS.createCredentialConnection, "Create a short-lived link for reconnecting an OAuth credential")).action((credentialId, _options, command) => createConnectionLink(command, { credentialId }));
|
|
13626
14566
|
}
|
|
13627
14567
|
|
|
13628
14568
|
// src/commands/protocol/result.ts
|
|
@@ -13775,7 +14715,7 @@ Examples:
|
|
|
13775
14715
|
|
|
13776
14716
|
// src/commands/protocol/files-get.ts
|
|
13777
14717
|
import { once as once2 } from "node:events";
|
|
13778
|
-
import { createWriteStream } from "node:fs";
|
|
14718
|
+
import { createWriteStream, rmSync } from "node:fs";
|
|
13779
14719
|
import { link, lstat, mkdtemp, readlink, rename, rm } from "node:fs/promises";
|
|
13780
14720
|
import { dirname as dirname2, join as join2, resolve as resolve2 } from "node:path";
|
|
13781
14721
|
import { Readable } from "node:stream";
|
|
@@ -13831,37 +14771,66 @@ async function streamToFile(body, file, reportedPath = file.path) {
|
|
|
13831
14771
|
throw writeFailure(reportedPath, error);
|
|
13832
14772
|
}
|
|
13833
14773
|
}
|
|
14774
|
+
var STAGE_SIGNALS = ["SIGINT", "SIGTERM"];
|
|
14775
|
+
function reRaise(signal) {
|
|
14776
|
+
process.kill(process.pid, signal);
|
|
14777
|
+
}
|
|
14778
|
+
function removeStagingOnSignal(stagingDirectory, terminate = reRaise) {
|
|
14779
|
+
const installed = STAGE_SIGNALS.map((signal) => {
|
|
14780
|
+
const onSignal = () => {
|
|
14781
|
+
process.off(signal, onSignal);
|
|
14782
|
+
const directory = stagingDirectory();
|
|
14783
|
+
if (directory) {
|
|
14784
|
+
try {
|
|
14785
|
+
rmSync(directory, { recursive: true, force: true });
|
|
14786
|
+
} catch {}
|
|
14787
|
+
}
|
|
14788
|
+
terminate(signal);
|
|
14789
|
+
};
|
|
14790
|
+
process.on(signal, onSignal);
|
|
14791
|
+
return [signal, onSignal];
|
|
14792
|
+
});
|
|
14793
|
+
return () => {
|
|
14794
|
+
for (const [signal, onSignal] of installed)
|
|
14795
|
+
process.off(signal, onSignal);
|
|
14796
|
+
};
|
|
14797
|
+
}
|
|
13834
14798
|
async function saveStagedFile(body, target, force) {
|
|
13835
14799
|
let temporaryDirectory = null;
|
|
13836
14800
|
let failure = null;
|
|
14801
|
+
const disposeSignalCleanup = removeStagingOnSignal(() => temporaryDirectory);
|
|
13837
14802
|
try {
|
|
13838
|
-
|
|
13839
|
-
|
|
13840
|
-
|
|
13841
|
-
|
|
13842
|
-
|
|
13843
|
-
|
|
13844
|
-
|
|
13845
|
-
|
|
13846
|
-
|
|
13847
|
-
|
|
13848
|
-
|
|
14803
|
+
try {
|
|
14804
|
+
const publicationTarget = force ? await forcedPublicationTarget(target) : target;
|
|
14805
|
+
temporaryDirectory = await mkdtemp(join2(dirname2(publicationTarget), ".sim-download-"));
|
|
14806
|
+
const temporaryPath = join2(temporaryDirectory, "payload");
|
|
14807
|
+
await streamToFile(body, createWriteStream(temporaryPath, { flags: "wx" }), target);
|
|
14808
|
+
if (force) {
|
|
14809
|
+
await rename(temporaryPath, publicationTarget);
|
|
14810
|
+
} else {
|
|
14811
|
+
try {
|
|
14812
|
+
await link(temporaryPath, publicationTarget);
|
|
14813
|
+
} catch (error) {
|
|
14814
|
+
throw unsupportedAtomicPublish(target, error) ?? error;
|
|
14815
|
+
}
|
|
13849
14816
|
}
|
|
14817
|
+
} catch (error) {
|
|
14818
|
+
failure = normalizedWriteFailure(target, error);
|
|
13850
14819
|
}
|
|
13851
|
-
|
|
13852
|
-
|
|
13853
|
-
|
|
13854
|
-
|
|
13855
|
-
|
|
13856
|
-
|
|
13857
|
-
|
|
13858
|
-
|
|
13859
|
-
throw combinedCleanupFailure(failure, temporaryDirectory, cleanupError);
|
|
13860
|
-
throw new SimApiError(`Saved ${target}, but could not remove temporary directory ${temporaryDirectory}: ${cleanupError.message}`, 0);
|
|
14820
|
+
if (temporaryDirectory) {
|
|
14821
|
+
try {
|
|
14822
|
+
await rm(temporaryDirectory, { recursive: true, force: true });
|
|
14823
|
+
} catch (cleanupError) {
|
|
14824
|
+
if (failure)
|
|
14825
|
+
throw combinedCleanupFailure(failure, temporaryDirectory, cleanupError);
|
|
14826
|
+
throw new SimApiError(`Saved ${target}, but could not remove temporary directory ${temporaryDirectory}: ${cleanupError.message}`, 0);
|
|
14827
|
+
}
|
|
13861
14828
|
}
|
|
14829
|
+
if (failure)
|
|
14830
|
+
throw failure;
|
|
14831
|
+
} finally {
|
|
14832
|
+
disposeSignalCleanup();
|
|
13862
14833
|
}
|
|
13863
|
-
if (failure)
|
|
13864
|
-
throw failure;
|
|
13865
14834
|
}
|
|
13866
14835
|
async function saveToFile(body, target, force) {
|
|
13867
14836
|
return saveStagedFile(body, target, force);
|
|
@@ -14172,6 +15141,7 @@ function renderCell2(value, format) {
|
|
|
14172
15141
|
}
|
|
14173
15142
|
var COLUMNS = (CLI_CONTRACT.listLogs?.columns ?? []).map((spec) => ({
|
|
14174
15143
|
header: spec.header,
|
|
15144
|
+
floor: Math.min(MAX_CELL_WIDTH2, spec.minWidth ?? 0),
|
|
14175
15145
|
value: (row) => renderCell2(at2(row, spec.path ?? spec.header), spec.format)
|
|
14176
15146
|
}));
|
|
14177
15147
|
function oneLine2(value) {
|
|
@@ -14188,15 +15158,15 @@ function clamp2(value, width) {
|
|
|
14188
15158
|
function createTableWriter() {
|
|
14189
15159
|
let widths = null;
|
|
14190
15160
|
return (rows) => {
|
|
14191
|
-
const lines = rows.map((row) => COLUMNS.map((column) => oneLine2(column.value(row))));
|
|
15161
|
+
const lines = rows.map((row) => COLUMNS.map((column) => clamp2(oneLine2(column.value(row)), MAX_CELL_WIDTH2)));
|
|
14192
15162
|
if (!widths) {
|
|
14193
|
-
widths = COLUMNS.map((column, index) => Math.min(MAX_CELL_WIDTH2, Math.max(visibleWidth(column.header), ...lines.map((line) => visibleWidth(line[index])))));
|
|
15163
|
+
widths = COLUMNS.map((column, index) => Math.min(MAX_CELL_WIDTH2, Math.max(column.floor, visibleWidth(column.header), ...lines.map((line) => visibleWidth(line[index])))));
|
|
14194
15164
|
const header = widths;
|
|
14195
15165
|
console.log(source_default.dim(COLUMNS.map((column, index) => pad2(column.header.toUpperCase(), header[index])).join(" ").trimEnd()));
|
|
14196
15166
|
}
|
|
14197
15167
|
const locked = widths;
|
|
14198
15168
|
for (const line of lines) {
|
|
14199
|
-
console.log(line.map((cell, index) => pad2(
|
|
15169
|
+
console.log(line.map((cell, index) => pad2(cell, locked[index])).join(" ").trimEnd());
|
|
14200
15170
|
}
|
|
14201
15171
|
};
|
|
14202
15172
|
}
|
|
@@ -14341,173 +15311,72 @@ function attachLogsFollow(logs) {
|
|
|
14341
15311
|
Each run prints once, when it is first seen, so its status is the status it had
|
|
14342
15312
|
at that moment. With --output json every run is a JSON object on its own line
|
|
14343
15313
|
(JSONL) rather than a member of an array, because a follow never ends and so can
|
|
14344
|
-
never close one; --output yaml emits a --- separated document stream. Progress
|
|
14345
|
-
and retries go to stderr, leaving stdout a clean stream of rows. Ctrl-C stops the
|
|
14346
|
-
follow.
|
|
14347
|
-
|
|
14348
|
-
Examples:
|
|
14349
|
-
$ sim logs follow --level error
|
|
14350
|
-
$ sim logs follow --workflow wf_123 -n 0
|
|
14351
|
-
$ sim --output json logs follow | jq -r '.runId'
|
|
14352
|
-
`).action(async (options, command) => {
|
|
14353
|
-
const lines = nonNegativeInteger(options.lines, "--lines");
|
|
14354
|
-
const delay = intervalMs(options.interval);
|
|
14355
|
-
const { client, profile } = clientFrom(command);
|
|
14356
|
-
const path = V2_OPERATIONS.listLogs.path;
|
|
14357
|
-
const query = {
|
|
14358
|
-
workspaceId: client.requireWorkspace(),
|
|
14359
|
-
workflowIds: options.workflow?.length ? options.workflow.join(",") : undefined,
|
|
14360
|
-
folderPaths: options.folder?.length ? options.folder.map(encodeFolderPath).join(",") : undefined,
|
|
14361
|
-
triggers: options.trigger?.length ? options.trigger.join(",") : undefined,
|
|
14362
|
-
level: options.level,
|
|
14363
|
-
details: options.details,
|
|
14364
|
-
sortBy: "startedAt",
|
|
14365
|
-
sortOrder: "desc"
|
|
14366
|
-
};
|
|
14367
|
-
const write = createWriter(profile.output);
|
|
14368
|
-
const status = followStatus();
|
|
14369
|
-
const interrupt = watchForInterrupt();
|
|
14370
|
-
const state = { seen: new Map, floor: null };
|
|
14371
|
-
try {
|
|
14372
|
-
const seed = await collectUnprinted(client, path, query, state, Math.max(lines, 1), 1);
|
|
14373
|
-
remember(state, seed.rows);
|
|
14374
|
-
state.floor = seed.rows.at(-1)?.startedAt ?? null;
|
|
14375
|
-
if (seed.truncated && seed.rows.length < lines) {
|
|
14376
|
-
status.warn(`asked for ${lines} earlier runs but a page holds ${seed.rows.length}; following from there — see sim logs list for more`);
|
|
14377
|
-
}
|
|
14378
|
-
write(lines > 0 ? seed.rows.slice(0, lines).reverse() : []);
|
|
14379
|
-
let failures = 0;
|
|
14380
|
-
while (!interrupt.interrupted()) {
|
|
14381
|
-
await waitFor(failures === 0 ? delay : Math.min(delay * 2 ** failures, MAX_BACKOFF_MS), interrupt.interrupted);
|
|
14382
|
-
if (interrupt.interrupted())
|
|
14383
|
-
break;
|
|
14384
|
-
let fresh;
|
|
14385
|
-
try {
|
|
14386
|
-
fresh = await collectUnprinted(client, path, query, state, POLL_PAGE_SIZE, MAX_PAGES_PER_POLL);
|
|
14387
|
-
} catch (error) {
|
|
14388
|
-
if (!isTransient(error))
|
|
14389
|
-
throw error;
|
|
14390
|
-
failures += 1;
|
|
14391
|
-
const next = Math.min(delay * 2 ** failures, MAX_BACKOFF_MS);
|
|
14392
|
-
status.note(`poll failed (${error.message}); retrying in ${inSeconds(next)}s…`);
|
|
14393
|
-
continue;
|
|
14394
|
-
}
|
|
14395
|
-
failures = 0;
|
|
14396
|
-
status.clear();
|
|
14397
|
-
if (fresh.truncated) {
|
|
14398
|
-
status.warn(`more than ${MAX_PAGES_PER_POLL * POLL_PAGE_SIZE} runs arrived at once; older ones were skipped — see sim logs list`);
|
|
14399
|
-
}
|
|
14400
|
-
if (fresh.rows.length === 0)
|
|
14401
|
-
continue;
|
|
14402
|
-
remember(state, fresh.rows);
|
|
14403
|
-
write(fresh.rows.reverse());
|
|
14404
|
-
}
|
|
14405
|
-
} finally {
|
|
14406
|
-
status.clear();
|
|
14407
|
-
interrupt.dispose();
|
|
14408
|
-
}
|
|
14409
|
-
});
|
|
14410
|
-
}
|
|
14411
|
-
|
|
14412
|
-
// src/runtime/options.ts
|
|
14413
|
-
var DEFAULT_LIMIT = 100;
|
|
14414
|
-
function describeField(flag, descriptor, name, field) {
|
|
14415
|
-
return flag.describe ?? descriptor.describe ?? `Set ${name.replaceAll("-", " ") || field}`;
|
|
14416
|
-
}
|
|
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) {
|
|
14425
|
-
if (field === PROFILE_INJECTED_FIELD || field === "cursor")
|
|
14426
|
-
return;
|
|
14427
|
-
const flag = flagSpecFor(operation, field);
|
|
14428
|
-
if (flag.omit)
|
|
14429
|
-
return;
|
|
14430
|
-
const name = flagNameFor(operation, field);
|
|
14431
|
-
const short = flag.short ? `-${flag.short}, ` : "";
|
|
14432
|
-
if (field === "limit" && (descriptor.kind === "number" || descriptor.kind === "integer")) {
|
|
14433
|
-
command.option("--limit <n>", "Maximum items to return (0 for everything)", String(DEFAULT_LIMIT));
|
|
14434
|
-
return;
|
|
14435
|
-
}
|
|
14436
|
-
const documented = describeField(flag, descriptor, name, field);
|
|
14437
|
-
if (descriptor.kind === "boolean" || flag.boolean) {
|
|
14438
|
-
const booleanDoc = withoutWireVocabulary(documented);
|
|
14439
|
-
if (descriptor.required) {
|
|
14440
|
-
command.addOption(new Option(`${short}--${name} <true|false>`, `${booleanDoc} (required)`).choices(["true", "false"]).makeOptionMandatory());
|
|
14441
|
-
return;
|
|
14442
|
-
}
|
|
14443
|
-
command.option(`${short}--${name}`, booleanDoc);
|
|
14444
|
-
if (!flag.boolean || flag.negatable) {
|
|
14445
|
-
command.option(`--no-${name}`, `Send --${name} as false`);
|
|
14446
|
-
}
|
|
14447
|
-
return;
|
|
14448
|
-
}
|
|
14449
|
-
const takesList = flag.list === true;
|
|
14450
|
-
const wantsJson = takesJson(descriptor, flag);
|
|
14451
|
-
const placeholder = takesList ? "<value...>" : flag.rowCap ? "<n>" : wantsJson ? "<json|@file>" : "<value>";
|
|
14452
|
-
const choices = flag.choices ?? descriptor.values;
|
|
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) : ""}`;
|
|
14455
|
-
const renamedFrom = flag.renamedFrom ?? [];
|
|
14456
|
-
const option = new Option(`${short}--${name} ${placeholder}`, describe);
|
|
14457
|
-
if (flag.hidden)
|
|
14458
|
-
option.hideHelp();
|
|
14459
|
-
if (choices && !takesList)
|
|
14460
|
-
option.choices([...choices]);
|
|
14461
|
-
if (descriptor.default !== undefined && field !== "limit") {
|
|
14462
|
-
option.default(undefined, String(descriptor.default));
|
|
14463
|
-
}
|
|
14464
|
-
if (descriptor.required && renamedFrom.length === 0)
|
|
14465
|
-
option.makeOptionMandatory();
|
|
14466
|
-
command.addOption(option);
|
|
14467
|
-
for (const previous of renamedFrom) {
|
|
14468
|
-
const retired = new Option(`--${previous} ${placeholder}`).hideHelp();
|
|
14469
|
-
if (choices && !takesList)
|
|
14470
|
-
retired.choices([...choices]);
|
|
14471
|
-
command.addOption(retired);
|
|
14472
|
-
}
|
|
14473
|
-
}
|
|
14474
|
-
function addOperationOptions(command, operation, commandSpec, operationSpec) {
|
|
14475
|
-
for (const param of operationSpec.pathParams) {
|
|
14476
|
-
const flag = commandSpec.pathFlags?.[param];
|
|
14477
|
-
if (!flag)
|
|
14478
|
-
continue;
|
|
14479
|
-
const name = pathFlagNameFor(commandSpec, param);
|
|
14480
|
-
const short = flag.short ? `-${flag.short}, ` : "";
|
|
14481
|
-
command.addOption(new Option(`${short}--${name} <${flag.placeholder ?? "value"}>`, `${flag.describe ?? operationSpec.pathParamDocs?.[param] ?? `Set ${name.replaceAll("-", " ")}`} (required)`).makeOptionMandatory());
|
|
14482
|
-
}
|
|
14483
|
-
for (const slot of ["query", "body", "headers"]) {
|
|
14484
|
-
for (const [field, descriptor] of Object.entries(operationSpec[slot] ?? {})) {
|
|
14485
|
-
if (commandSpec.requestFields && !commandSpec.requestFields.includes(field))
|
|
14486
|
-
continue;
|
|
14487
|
-
if (commandSpec.positionals?.includes(field))
|
|
14488
|
-
continue;
|
|
14489
|
-
addFieldOption(command, operation, field, descriptor, slot);
|
|
14490
|
-
}
|
|
14491
|
-
}
|
|
14492
|
-
if (commandSpec.allWorkspaces) {
|
|
14493
|
-
command.option("--all-workspaces", "Do not filter to the configured workspace (personal API key required for account-wide access)");
|
|
14494
|
-
}
|
|
14495
|
-
if (commandSpec.expandedTrace) {
|
|
14496
|
-
command.option("--trace", "Show expanded trace spans with inputs, outputs, errors, timing, and cost");
|
|
14497
|
-
}
|
|
14498
|
-
if (operationSpec.opaqueBody) {
|
|
14499
|
-
if (commandSpec.bodyVariants) {
|
|
14500
|
-
for (const variant of commandSpec.bodyVariants) {
|
|
14501
|
-
command.option(`--${variant.name} <json|@file>`, `${variant.describe} (JSON, or @path / @-; choose exactly one body flag)`);
|
|
15314
|
+
never close one; --output yaml emits a --- separated document stream. Progress
|
|
15315
|
+
and retries go to stderr, leaving stdout a clean stream of rows. Ctrl-C stops the
|
|
15316
|
+
follow.
|
|
15317
|
+
|
|
15318
|
+
Examples:
|
|
15319
|
+
$ sim logs follow --level error
|
|
15320
|
+
$ sim logs follow --workflow wf_123 -n 0
|
|
15321
|
+
$ sim --output json logs follow | jq -r '.runId'
|
|
15322
|
+
`).action(async (options, command) => {
|
|
15323
|
+
const lines = nonNegativeInteger(options.lines, "--lines");
|
|
15324
|
+
const delay = intervalMs(options.interval);
|
|
15325
|
+
const { client, profile } = clientFrom(command);
|
|
15326
|
+
const path = V2_OPERATIONS.listLogs.path;
|
|
15327
|
+
const query = {
|
|
15328
|
+
workspaceId: client.requireWorkspace(),
|
|
15329
|
+
workflowIds: options.workflow?.length ? options.workflow.join(",") : undefined,
|
|
15330
|
+
folderPaths: options.folder?.length ? options.folder.map(encodeFolderPath).join(",") : undefined,
|
|
15331
|
+
triggers: options.trigger?.length ? options.trigger.join(",") : undefined,
|
|
15332
|
+
level: options.level,
|
|
15333
|
+
details: options.details,
|
|
15334
|
+
sortBy: "startedAt",
|
|
15335
|
+
sortOrder: "desc"
|
|
15336
|
+
};
|
|
15337
|
+
const write = createWriter(profile.output);
|
|
15338
|
+
const status = followStatus();
|
|
15339
|
+
const interrupt = watchForInterrupt();
|
|
15340
|
+
const state = { seen: new Map, floor: null };
|
|
15341
|
+
try {
|
|
15342
|
+
const seed = await collectUnprinted(client, path, query, state, Math.max(lines, 1), 1);
|
|
15343
|
+
remember(state, seed.rows);
|
|
15344
|
+
state.floor = seed.rows.at(-1)?.startedAt ?? null;
|
|
15345
|
+
if (seed.truncated && seed.rows.length < lines) {
|
|
15346
|
+
status.warn(`asked for ${lines} earlier runs but a page holds ${seed.rows.length}; following from there — see sim logs list for more`);
|
|
14502
15347
|
}
|
|
14503
|
-
|
|
14504
|
-
|
|
15348
|
+
write(lines > 0 ? seed.rows.slice(0, lines).reverse() : []);
|
|
15349
|
+
let failures = 0;
|
|
15350
|
+
while (!interrupt.interrupted()) {
|
|
15351
|
+
await waitFor(failures === 0 ? delay : Math.min(delay * 2 ** failures, MAX_BACKOFF_MS), interrupt.interrupted);
|
|
15352
|
+
if (interrupt.interrupted())
|
|
15353
|
+
break;
|
|
15354
|
+
let fresh;
|
|
15355
|
+
try {
|
|
15356
|
+
fresh = await collectUnprinted(client, path, query, state, POLL_PAGE_SIZE, MAX_PAGES_PER_POLL);
|
|
15357
|
+
} catch (error) {
|
|
15358
|
+
if (!isTransient(error))
|
|
15359
|
+
throw error;
|
|
15360
|
+
failures += 1;
|
|
15361
|
+
const next = Math.min(delay * 2 ** failures, MAX_BACKOFF_MS);
|
|
15362
|
+
status.note(`poll failed (${error.message}); retrying in ${inSeconds(next)}s…`);
|
|
15363
|
+
continue;
|
|
15364
|
+
}
|
|
15365
|
+
failures = 0;
|
|
15366
|
+
status.clear();
|
|
15367
|
+
if (fresh.truncated) {
|
|
15368
|
+
status.warn(`more than ${MAX_PAGES_PER_POLL * POLL_PAGE_SIZE} runs arrived at once; older ones were skipped — see sim logs list`);
|
|
15369
|
+
}
|
|
15370
|
+
if (fresh.rows.length === 0)
|
|
15371
|
+
continue;
|
|
15372
|
+
remember(state, fresh.rows);
|
|
15373
|
+
write(fresh.rows.reverse());
|
|
15374
|
+
}
|
|
15375
|
+
} finally {
|
|
15376
|
+
status.clear();
|
|
15377
|
+
interrupt.dispose();
|
|
14505
15378
|
}
|
|
14506
|
-
}
|
|
14507
|
-
if (commandSpec.confirm) {
|
|
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)");
|
|
14510
|
-
}
|
|
15379
|
+
});
|
|
14511
15380
|
}
|
|
14512
15381
|
|
|
14513
15382
|
// src/commands/protocol/resource-directory.ts
|
|
@@ -14663,13 +15532,16 @@ function validateTargetOptions(options) {
|
|
|
14663
15532
|
return intoExisting;
|
|
14664
15533
|
}
|
|
14665
15534
|
function attachTableImport(tables) {
|
|
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) => {
|
|
15535
|
+
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("-y, --yes", "Confirm this destructive operation (required with --mode replace)").option("--no-wait", "Return once the import is queued instead of watching it").action(async (path, options, command) => {
|
|
14667
15536
|
const { client, profile } = clientFrom(command);
|
|
14668
15537
|
const workspaceId = client.requireWorkspace();
|
|
14669
15538
|
if (Boolean(path) === Boolean(options.fileId)) {
|
|
14670
15539
|
throw new SimApiError("Pass exactly one of <path> or --file-id <id>", 0);
|
|
14671
15540
|
}
|
|
14672
15541
|
const intoExisting = validateTargetOptions(options);
|
|
15542
|
+
if (intoExisting && options.mode === "replace" && options.yes !== true) {
|
|
15543
|
+
throw new SimApiError("This deletes every row in the table before loading the CSV and cannot be undone. Re-run with --yes to confirm.", 0);
|
|
15544
|
+
}
|
|
14673
15545
|
const local = path ? await localFile(path) : null;
|
|
14674
15546
|
const source = local ? {
|
|
14675
15547
|
type: "upload",
|
|
@@ -14724,202 +15596,18 @@ function attachTableImport(tables) {
|
|
|
14724
15596
|
});
|
|
14725
15597
|
return;
|
|
14726
15598
|
}
|
|
14727
|
-
const finished = await watchImport(client, workspaceId, job);
|
|
14728
|
-
if (finished.status !== "completed") {
|
|
14729
|
-
throw new SimApiError(`Import ${finished.status}${finished.error ? `: ${finished.error}` : ""}`, 0);
|
|
14730
|
-
}
|
|
14731
|
-
printProtocolResult(profile.output, {
|
|
14732
|
-
id: finished.id,
|
|
14733
|
-
status: finished.status,
|
|
14734
|
-
tableId: finished.tableId,
|
|
14735
|
-
rowsProcessed: finished.rowsProcessed,
|
|
14736
|
-
...rejectionFields(finished)
|
|
14737
|
-
});
|
|
14738
|
-
});
|
|
14739
|
-
}
|
|
14740
|
-
|
|
14741
|
-
// src/runtime/renamed.ts
|
|
14742
|
-
var warned = new Set;
|
|
14743
|
-
function warn(kind, from, to) {
|
|
14744
|
-
const key = `${kind}:${from}`;
|
|
14745
|
-
if (warned.has(key))
|
|
14746
|
-
return;
|
|
14747
|
-
warned.add(key);
|
|
14748
|
-
process.stderr.write(`warning: ${kind} "${from}" has been renamed to "${to}". The old name still works.
|
|
14749
|
-
`);
|
|
14750
|
-
}
|
|
14751
|
-
function warnRenamedCommand(from, to) {
|
|
14752
|
-
warn("command", `sim ${from}`, `sim ${to}`);
|
|
14753
|
-
}
|
|
14754
|
-
function warnRenamedFlag(from, to) {
|
|
14755
|
-
warn("flag", `--${from}`, `--${to}`);
|
|
14756
|
-
}
|
|
14757
|
-
|
|
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
|
-
}
|
|
14828
|
-
function cursorSlot(operationSpec) {
|
|
14829
|
-
if (operationSpec.query && "cursor" in operationSpec.query)
|
|
14830
|
-
return "query";
|
|
14831
|
-
if (operationSpec.body && "cursor" in operationSpec.body)
|
|
14832
|
-
return "body";
|
|
14833
|
-
return null;
|
|
14834
|
-
}
|
|
14835
|
-
function foldRenamedFlags(operation, commandSpec, flags) {
|
|
14836
|
-
for (const [field, flag] of Object.entries(commandSpec.flags ?? {})) {
|
|
14837
|
-
if (!flag.renamedFrom?.length)
|
|
14838
|
-
continue;
|
|
14839
|
-
const current = flagNameFor(operation, field);
|
|
14840
|
-
for (const previous of flag.renamedFrom) {
|
|
14841
|
-
const supplied = flags[camel(previous)];
|
|
14842
|
-
if (supplied === undefined)
|
|
14843
|
-
continue;
|
|
14844
|
-
if (flags[camel(current)] !== undefined) {
|
|
14845
|
-
throw new SimApiError(`--${previous} is the former name of --${current}; pass one, not both`, 0);
|
|
14846
|
-
}
|
|
14847
|
-
warnRenamedFlag(previous, current);
|
|
14848
|
-
flags[camel(current)] = supplied;
|
|
14849
|
-
}
|
|
14850
|
-
}
|
|
14851
|
-
}
|
|
14852
|
-
async function executeOperation(operation, commandSpec, operationSpec, invocation) {
|
|
14853
|
-
const host = invocation[invocation.length - 1];
|
|
14854
|
-
const inheritedFlags = host.optsWithGlobals();
|
|
14855
|
-
const flags = {
|
|
14856
|
-
...inheritedFlags.workspace === undefined ? {} : { workspace: inheritedFlags.workspace },
|
|
14857
|
-
...inheritedFlags.allWorkspaces === undefined ? {} : { allWorkspaces: inheritedFlags.allWorkspaces },
|
|
14858
|
-
...invocation[invocation.length - 2]
|
|
14859
|
-
};
|
|
14860
|
-
const pathPositionalCount = operationSpec.pathParams.filter((param) => !commandSpec.pathFlags?.[param] && !isProfileWorkspacePath(commandSpec, param)).length;
|
|
14861
|
-
const positional = invocation.slice(0, pathPositionalCount);
|
|
14862
|
-
const requestFlags = { ...flags };
|
|
14863
|
-
for (const [index, field] of (commandSpec.positionals ?? []).entries()) {
|
|
14864
|
-
requestFlags[camel(flagNameFor(operation, field))] = invocation[pathPositionalCount + index];
|
|
14865
|
-
}
|
|
14866
|
-
foldRenamedFlags(operation, commandSpec, requestFlags);
|
|
14867
|
-
if (commandSpec.confirm && !requestFlags.yes && requestFlags.dryRun !== true) {
|
|
14868
|
-
throw new SimApiError(`${commandSpec.confirm} Re-run with --yes to confirm.`, 0);
|
|
14869
|
-
}
|
|
14870
|
-
if (commandSpec.allWorkspaces && requestFlags.allWorkspaces && requestFlags.workspace) {
|
|
14871
|
-
throw new SimApiError("--all-workspaces cannot be combined with --workspace", 0);
|
|
14872
|
-
}
|
|
14873
|
-
const { client, profile } = clientFrom(host);
|
|
14874
|
-
const hasWorkspaceField = Boolean(operationSpec.query && PROFILE_INJECTED_FIELD in operationSpec.query || operationSpec.body && PROFILE_INJECTED_FIELD in operationSpec.body);
|
|
14875
|
-
const omitsWorkspace = commandSpec.allWorkspaces && requestFlags.allWorkspaces === true;
|
|
14876
|
-
const request = buildRequest(operation, positional, requestFlags, hasWorkspaceField && !omitsWorkspace ? client.requireWorkspace() : profile.workspaceId);
|
|
14877
|
-
const paging = cursorSlot(operationSpec);
|
|
14878
|
-
if (paging) {
|
|
14879
|
-
const rawLimit = Number.parseInt(String(requestFlags.limit ?? DEFAULT_LIMIT), 10);
|
|
14880
|
-
if (Number.isNaN(rawLimit) || rawLimit < 0) {
|
|
14881
|
-
throw new SimApiError("--limit must be a non-negative number", 0);
|
|
14882
|
-
}
|
|
14883
|
-
const limit = rawLimit === 0 ? Number.POSITIVE_INFINITY : rawLimit;
|
|
14884
|
-
const pageSize = Math.min(Number.isFinite(limit) ? limit : DEFAULT_LIMIT, DEFAULT_LIMIT);
|
|
14885
|
-
const pageLimit = "limit" in (operationSpec[paging] ?? {}) ? { limit: pageSize } : {};
|
|
14886
|
-
const rows = [];
|
|
14887
|
-
const progress = pageProgress();
|
|
14888
|
-
let cursor = null;
|
|
14889
|
-
let envelope;
|
|
14890
|
-
try {
|
|
14891
|
-
do {
|
|
14892
|
-
const page = await client.request(request.path, {
|
|
14893
|
-
method: operationSpec.method,
|
|
14894
|
-
headers: request.headers,
|
|
14895
|
-
query: paging === "query" ? { ...request.query, ...pageLimit, cursor } : request.query,
|
|
14896
|
-
body: paging === "body" ? { ...request.body ?? {}, ...pageLimit, ...cursor ? { cursor } : {} } : request.body
|
|
14897
|
-
});
|
|
14898
|
-
envelope ??= page;
|
|
14899
|
-
rows.push(...page.data);
|
|
14900
|
-
cursor = page.nextCursor;
|
|
14901
|
-
if (cursor && rows.length < limit)
|
|
14902
|
-
progress.advance(rows.length);
|
|
14903
|
-
} while (cursor && rows.length < limit);
|
|
14904
|
-
} finally {
|
|
14905
|
-
progress.finish();
|
|
14906
|
-
}
|
|
14907
|
-
renderPage(profile.output, Number.isFinite(limit) ? rows.slice(0, limit) : rows, commandSpec, envelope);
|
|
14908
|
-
return;
|
|
14909
|
-
}
|
|
14910
|
-
const result = await client.request(request.path, {
|
|
14911
|
-
method: operationSpec.method,
|
|
14912
|
-
headers: request.headers,
|
|
14913
|
-
query: request.query,
|
|
14914
|
-
body: request.body
|
|
14915
|
-
});
|
|
14916
|
-
const payload = result?.data ?? result;
|
|
14917
|
-
renderResult(operation, profile.output, payload, commandSpec, {
|
|
14918
|
-
expandedTrace: requestFlags.trace === true
|
|
15599
|
+
const finished = await watchImport(client, workspaceId, job);
|
|
15600
|
+
if (finished.status !== "completed") {
|
|
15601
|
+
throw new SimApiError(`Import ${finished.status}${finished.error ? `: ${finished.error}` : ""}`, 0);
|
|
15602
|
+
}
|
|
15603
|
+
printProtocolResult(profile.output, {
|
|
15604
|
+
id: finished.id,
|
|
15605
|
+
status: finished.status,
|
|
15606
|
+
tableId: finished.tableId,
|
|
15607
|
+
rowsProcessed: finished.rowsProcessed,
|
|
15608
|
+
...rejectionFields(finished)
|
|
15609
|
+
});
|
|
14919
15610
|
});
|
|
14920
|
-
const failure = runFailureMessage(operation, payload) ?? bulkFailureMessage(operation, payload, request.body);
|
|
14921
|
-
if (failure)
|
|
14922
|
-
throw new SimApiError(failure, 0);
|
|
14923
15611
|
}
|
|
14924
15612
|
|
|
14925
15613
|
// src/commands/protocol/workflow-run-follow.ts
|
|
@@ -15141,6 +15829,9 @@ function followOrDelegate(previous) {
|
|
|
15141
15829
|
command.setOptionValue("run", selection);
|
|
15142
15830
|
const flags = command.optsWithGlobals();
|
|
15143
15831
|
if (flags.follow !== true) {
|
|
15832
|
+
if (Array.isArray(flags.selectOutput) && flags.selectOutput.length > 0) {
|
|
15833
|
+
throw new SimApiError(flags.async === true ? "--select-output shapes a streamed result, and --async returns as soon as the run is queued, so there is no stream to shape. Drop one of them, or read the finished run with: sim workflows runs get <runId> --workflow <workflowId> --select-output <blockId>[.path] — that resource matches block ids, not the block names --select-output takes here." : "--select-output shapes a streamed result; add --follow. To narrow a run that has already finished: sim workflows runs get <runId> --workflow <workflowId> --select-output <blockId>[.path] — that resource matches block ids, not the block names --select-output takes here.", 0);
|
|
15834
|
+
}
|
|
15144
15835
|
if (flags.includeThinking === true || flags.includeToolCalls === true) {
|
|
15145
15836
|
throw new SimApiError("--include-thinking and --include-tool-calls describe a stream; add --follow", 0);
|
|
15146
15837
|
}
|
|
@@ -15455,6 +16146,8 @@ function validateWorkspaceOnlyFlag(flag, value, scope) {
|
|
|
15455
16146
|
async function readSecretValue(options) {
|
|
15456
16147
|
if (options.value !== undefined)
|
|
15457
16148
|
return validateSecretValue(readValueArgument(options.value));
|
|
16149
|
+
if (options.description !== undefined || options.unredacted !== undefined)
|
|
16150
|
+
return;
|
|
15458
16151
|
try {
|
|
15459
16152
|
return validateSecretValue(await promptSecret());
|
|
15460
16153
|
} catch (error) {
|
|
@@ -15464,7 +16157,10 @@ async function readSecretValue(options) {
|
|
|
15464
16157
|
return process.exit(CANCELLED_EXIT_CODE);
|
|
15465
16158
|
}
|
|
15466
16159
|
}
|
|
15467
|
-
async function setSecret(name, options, command) {
|
|
16160
|
+
async function setSecret(name, options, command, redactionSpellings) {
|
|
16161
|
+
if (redactionSpellings.size > 1) {
|
|
16162
|
+
throw new SimApiError("Pass either --unredacted or --no-unredacted, not both: they are one setting, and commander keeps only whichever came last.", 0);
|
|
16163
|
+
}
|
|
15468
16164
|
const description = validateWorkspaceOnlyFlag("description", options.description, options.scope);
|
|
15469
16165
|
const unredacted = validateWorkspaceOnlyFlag("unredacted", options.unredacted, options.scope);
|
|
15470
16166
|
const value = await readSecretValue(options);
|
|
@@ -15475,7 +16171,7 @@ async function setSecret(name, options, command) {
|
|
|
15475
16171
|
body: {
|
|
15476
16172
|
workspaceId: client.requireWorkspace(),
|
|
15477
16173
|
scope: options.scope,
|
|
15478
|
-
value,
|
|
16174
|
+
...value === undefined ? {} : { value },
|
|
15479
16175
|
description,
|
|
15480
16176
|
...unredacted === undefined ? {} : { unredacted }
|
|
15481
16177
|
}
|
|
@@ -15486,257 +16182,8 @@ function attachSecretCommands(program2) {
|
|
|
15486
16182
|
const secrets = program2.commands.find((command) => command.name() === "secrets");
|
|
15487
16183
|
if (!secrets)
|
|
15488
16184
|
throw new Error("The generated secrets command group is missing");
|
|
15489
|
-
|
|
15490
|
-
}
|
|
15491
|
-
|
|
15492
|
-
// src/runtime/build.ts
|
|
15493
|
-
var GROUP_ALIASES = {
|
|
15494
|
-
"audit-logs": "audit-log",
|
|
15495
|
-
credentials: "credential",
|
|
15496
|
-
"custom-tools": "custom-tool",
|
|
15497
|
-
files: "file",
|
|
15498
|
-
knowledge: "kb",
|
|
15499
|
-
logs: "log",
|
|
15500
|
-
"mcp-servers": "mcp-server",
|
|
15501
|
-
secrets: "secret",
|
|
15502
|
-
skills: "skill",
|
|
15503
|
-
tables: "table",
|
|
15504
|
-
workflows: "workflow",
|
|
15505
|
-
workspaces: "workspace"
|
|
15506
|
-
};
|
|
15507
|
-
function argumentSyntax(command) {
|
|
15508
|
-
return command.registeredArguments.map((argument) => {
|
|
15509
|
-
const name = `${argument.name()}${argument.variadic ? "..." : ""}`;
|
|
15510
|
-
return argument.required ? `<${name}>` : `[${name}]`;
|
|
15511
|
-
}).join(" ");
|
|
15512
|
-
}
|
|
15513
|
-
function commandPath(command) {
|
|
15514
|
-
const names = [];
|
|
15515
|
-
let current = command;
|
|
15516
|
-
while (current) {
|
|
15517
|
-
names.unshift(current.name());
|
|
15518
|
-
current = current.parent;
|
|
15519
|
-
}
|
|
15520
|
-
return names.join(" ");
|
|
15521
|
-
}
|
|
15522
|
-
function addMissingArgumentExample(command) {
|
|
15523
|
-
const outputError = command.configureOutput().outputError;
|
|
15524
|
-
if (!outputError)
|
|
15525
|
-
throw new Error("Commander output formatter is not configured");
|
|
15526
|
-
command.configureOutput({
|
|
15527
|
-
outputError: (message, write) => {
|
|
15528
|
-
outputError(message, write);
|
|
15529
|
-
if (!message.startsWith("error: missing required argument "))
|
|
15530
|
-
return;
|
|
15531
|
-
const syntax = argumentSyntax(command);
|
|
15532
|
-
const example = syntax ? `${commandPath(command)} ${syntax}` : commandPath(command);
|
|
15533
|
-
write(`Example: ${example}
|
|
15534
|
-
`);
|
|
15535
|
-
}
|
|
15536
|
-
});
|
|
15537
|
-
return command;
|
|
15538
|
-
}
|
|
15539
|
-
function assertNoReservedFlags(command, operation) {
|
|
15540
|
-
for (const option of command.options) {
|
|
15541
|
-
for (const flag of [option.long, option.short]) {
|
|
15542
|
-
if (flag && RESERVED_PROGRAM_FLAGS.has(flag)) {
|
|
15543
|
-
throw new Error(`${operation} declares ${flag}, which the root program already owns; give the flag another name`);
|
|
15544
|
-
}
|
|
15545
|
-
}
|
|
15546
|
-
}
|
|
15547
|
-
}
|
|
15548
|
-
var RESERVED_FLAG_EXEMPTIONS = new Set(["profiles add"]);
|
|
15549
|
-
function assertNoReservedProgramFlags(program2) {
|
|
15550
|
-
const walk = (command, prefix) => {
|
|
15551
|
-
const path = [...prefix, command.name()];
|
|
15552
|
-
const name = path.join(" ");
|
|
15553
|
-
if (!RESERVED_FLAG_EXEMPTIONS.has(name)) {
|
|
15554
|
-
for (const option of command.options) {
|
|
15555
|
-
for (const flag of [option.long, option.short]) {
|
|
15556
|
-
if (flag && RESERVED_PROGRAM_FLAGS.has(flag)) {
|
|
15557
|
-
throw new Error(`"sim ${name}" declares ${flag}, which the root program already owns; give the flag another name`);
|
|
15558
|
-
}
|
|
15559
|
-
}
|
|
15560
|
-
}
|
|
15561
|
-
}
|
|
15562
|
-
for (const child of command.commands)
|
|
15563
|
-
walk(child, path);
|
|
15564
|
-
};
|
|
15565
|
-
for (const child of program2.commands)
|
|
15566
|
-
walk(child, []);
|
|
15567
|
-
}
|
|
15568
|
-
function configureOperation(command, operation, spec) {
|
|
15569
|
-
const operationSpec = V2_OPERATIONS[operation];
|
|
15570
|
-
command.allowExcessArguments(false);
|
|
15571
|
-
for (const alias of spec.aliases ?? [])
|
|
15572
|
-
command.alias(alias);
|
|
15573
|
-
for (const param of Object.keys(spec.pathFlags ?? {})) {
|
|
15574
|
-
if (!operationSpec.pathParams.includes(param)) {
|
|
15575
|
-
throw new Error(`${operation}.${param} is not a path parameter`);
|
|
15576
|
-
}
|
|
15577
|
-
}
|
|
15578
|
-
for (const param of Object.keys(spec.pathArgumentNames ?? {})) {
|
|
15579
|
-
if (!operationSpec.pathParams.includes(param)) {
|
|
15580
|
-
throw new Error(`${operation}.${param} is not a path parameter`);
|
|
15581
|
-
}
|
|
15582
|
-
if (spec.pathFlags?.[param]) {
|
|
15583
|
-
throw new Error(`${operation}.${param} cannot be both a path argument and a path flag`);
|
|
15584
|
-
}
|
|
15585
|
-
}
|
|
15586
|
-
if (spec.profileWorkspacePath) {
|
|
15587
|
-
if (!operationSpec.pathParams.includes(PROFILE_INJECTED_FIELD)) {
|
|
15588
|
-
throw new Error(`${operation}.profileWorkspacePath requires a workspaceId path parameter`);
|
|
15589
|
-
}
|
|
15590
|
-
if (spec.pathFlags?.[PROFILE_INJECTED_FIELD]) {
|
|
15591
|
-
throw new Error(`${operation}.workspaceId cannot be both profile-injected and a path flag`);
|
|
15592
|
-
}
|
|
15593
|
-
}
|
|
15594
|
-
for (const param of operationSpec.pathParams) {
|
|
15595
|
-
if (spec.pathFlags?.[param] || isProfileWorkspacePath(spec, param))
|
|
15596
|
-
continue;
|
|
15597
|
-
command.argument(`<${spec.pathArgumentNames?.[param] ?? param}>`, operationSpec.pathParamDocs?.[param]);
|
|
15598
|
-
}
|
|
15599
|
-
if (spec.allWorkspaces) {
|
|
15600
|
-
const workspace = operationSpec.query?.workspaceId ?? operationSpec.body?.workspaceId;
|
|
15601
|
-
if (!workspace || workspace.required) {
|
|
15602
|
-
throw new Error(`${operation}.allWorkspaces requires an optional workspaceId field`);
|
|
15603
|
-
}
|
|
15604
|
-
}
|
|
15605
|
-
for (const field of spec.positionals ?? []) {
|
|
15606
|
-
const descriptor = operationSpec.query?.[field] ?? operationSpec.body?.[field];
|
|
15607
|
-
if (!descriptor)
|
|
15608
|
-
throw new Error(`${operation}.${field} is not a request field`);
|
|
15609
|
-
if (spec.requestFields && !spec.requestFields.includes(field)) {
|
|
15610
|
-
throw new Error(`${operation}.${field} is positional but not exposed`);
|
|
15611
|
-
}
|
|
15612
|
-
command.argument(`<${flagNameFor(operation, field)}>`, flagSpecFor(operation, field).describe ?? descriptor.describe);
|
|
15613
|
-
}
|
|
15614
|
-
if (spec.requestFields) {
|
|
15615
|
-
for (const field of spec.requestFields) {
|
|
15616
|
-
if (!operationSpec.query?.[field] && !operationSpec.body?.[field] && !operationSpec.headers?.[field]) {
|
|
15617
|
-
throw new Error(`${operation}.${field} is not a request field`);
|
|
15618
|
-
}
|
|
15619
|
-
}
|
|
15620
|
-
for (const slot of ["query", "body", "headers"]) {
|
|
15621
|
-
for (const [field, descriptor] of Object.entries(operationSpec[slot] ?? {})) {
|
|
15622
|
-
if (descriptor.required && field !== PROFILE_INJECTED_FIELD && !spec.requestFields.includes(field)) {
|
|
15623
|
-
throw new Error(`${operation}.${field} is required but not exposed`);
|
|
15624
|
-
}
|
|
15625
|
-
}
|
|
15626
|
-
}
|
|
15627
|
-
}
|
|
15628
|
-
command.description(spec.describe ?? operationSpec.summary ?? `${operationSpec.method} ${operationSpec.path}`);
|
|
15629
|
-
addOperationOptions(command, operation, spec, operationSpec);
|
|
15630
|
-
assertNoReservedFlags(command, operation);
|
|
15631
|
-
command.action((...invocation) => executeOperation(operation, spec, operationSpec, invocation));
|
|
15632
|
-
return command;
|
|
15633
|
-
}
|
|
15634
|
-
function buildLeaf(operation, spec, leafName) {
|
|
15635
|
-
return addMissingArgumentExample(configureOperation(new Command(leafName), operation, spec));
|
|
15636
|
-
}
|
|
15637
|
-
function addRenamedCommand(groups, operation, spec, from, to) {
|
|
15638
|
-
const segments = from.split(" ");
|
|
15639
|
-
const [groupName, ...rest] = segments;
|
|
15640
|
-
if (rest.length === 0)
|
|
15641
|
-
throw new Error(`${operation}.renamedFrom "${from}" must include a verb`);
|
|
15642
|
-
let parent = groupFor(groups, groupName);
|
|
15643
|
-
for (const segment of rest.slice(0, -1)) {
|
|
15644
|
-
parent = nestedGroup(parent, segment, { hidden: true });
|
|
15645
|
-
}
|
|
15646
|
-
const leaf = buildLeaf(operation, spec, rest[rest.length - 1]);
|
|
15647
|
-
leaf.hook("preAction", () => warnRenamedCommand(from, to));
|
|
15648
|
-
addSubcommand(parent, leaf, { hidden: true });
|
|
15649
|
-
}
|
|
15650
|
-
function addSubcommand(parent, child, options = {}) {
|
|
15651
|
-
const wasLeaf = parent.commands.length === 0 && parent.registeredArguments.length > 0;
|
|
15652
|
-
const usage = wasLeaf ? parent.usage() : null;
|
|
15653
|
-
parent.addCommand(child, { hidden: options.hidden });
|
|
15654
|
-
if (usage !== null)
|
|
15655
|
-
parent.usage(usage);
|
|
15656
|
-
}
|
|
15657
|
-
function groupFor(groups, name) {
|
|
15658
|
-
const existing = groups.get(name);
|
|
15659
|
-
if (existing)
|
|
15660
|
-
return existing;
|
|
15661
|
-
const group2 = new Command(name).description(`Manage ${name.replaceAll("-", " ")}`);
|
|
15662
|
-
const alias = GROUP_ALIASES[name];
|
|
15663
|
-
if (alias)
|
|
15664
|
-
group2.alias(alias);
|
|
15665
|
-
groups.set(name, group2);
|
|
15666
|
-
return group2;
|
|
15667
|
-
}
|
|
15668
|
-
function resourceLabel(name) {
|
|
15669
|
-
const label = name.endsWith("s") ? name.slice(0, -1) : name;
|
|
15670
|
-
return label.replaceAll("-", " ");
|
|
15671
|
-
}
|
|
15672
|
-
function nestedGroup(parent, name, options = {}) {
|
|
15673
|
-
const existing = parent.commands.find((candidate) => candidate.name() === name);
|
|
15674
|
-
if (existing)
|
|
15675
|
-
return existing;
|
|
15676
|
-
const created = new Command(name).description(`Manage ${resourceLabel(parent.name())} ${name.replaceAll("-", " ")}`);
|
|
15677
|
-
addSubcommand(parent, created, { hidden: options.hidden });
|
|
15678
|
-
return created;
|
|
15679
|
-
}
|
|
15680
|
-
function addLeafCommand(groups, operation, spec, segments) {
|
|
15681
|
-
const [groupName, ...rest] = segments;
|
|
15682
|
-
if (rest.length === 0)
|
|
15683
|
-
throw new Error(`${operation} leaf command must include a verb`);
|
|
15684
|
-
const group2 = groupFor(groups, groupName);
|
|
15685
|
-
if (rest.length > 1) {
|
|
15686
|
-
let parent = group2;
|
|
15687
|
-
for (const segment of rest.slice(0, -1)) {
|
|
15688
|
-
parent = nestedGroup(parent, segment);
|
|
15689
|
-
}
|
|
15690
|
-
parent.addCommand(buildLeaf(operation, spec, rest[rest.length - 1]));
|
|
15691
|
-
return;
|
|
15692
|
-
}
|
|
15693
|
-
group2.addCommand(buildLeaf(operation, spec, rest[0]));
|
|
15694
|
-
}
|
|
15695
|
-
function variantCommandSpec(spec, variant) {
|
|
15696
|
-
return {
|
|
15697
|
-
...spec,
|
|
15698
|
-
command: variant.command,
|
|
15699
|
-
groupDefault: false,
|
|
15700
|
-
aliases: [],
|
|
15701
|
-
positionals: variant.positionals,
|
|
15702
|
-
requestFields: variant.requestFields,
|
|
15703
|
-
variants: [],
|
|
15704
|
-
describe: variant.describe ?? spec.describe
|
|
15705
|
-
};
|
|
15706
|
-
}
|
|
15707
|
-
function buildGeneratedCommands() {
|
|
15708
|
-
const groups = new Map;
|
|
15709
|
-
const renamed = [];
|
|
15710
|
-
for (const operation of Object.keys(V2_OPERATIONS)) {
|
|
15711
|
-
const spec = CLI_CONTRACT[operation] ?? {};
|
|
15712
|
-
const operationSpec = V2_OPERATIONS[operation];
|
|
15713
|
-
if (spec.hidden || operationSpec.responseMode !== "json")
|
|
15714
|
-
continue;
|
|
15715
|
-
const segments = spec.command ? spec.command.split(" ") : deriveCommandPath(operation);
|
|
15716
|
-
if (spec.groupDefault) {
|
|
15717
|
-
const [groupName, ...rest] = segments;
|
|
15718
|
-
const group2 = groupFor(groups, groupName);
|
|
15719
|
-
if (rest.length > 0)
|
|
15720
|
-
throw new Error(`${operation} groupDefault must name a command group`);
|
|
15721
|
-
const pathPositionals = operationSpec.pathParams.filter((param) => !spec.pathFlags?.[param] && !isProfileWorkspacePath(spec, param));
|
|
15722
|
-
if (pathPositionals.length > 0 || spec.positionals?.length) {
|
|
15723
|
-
throw new Error(`${operation} groupDefault cannot require positional arguments`);
|
|
15724
|
-
}
|
|
15725
|
-
configureOperation(group2, operation, spec);
|
|
15726
|
-
} else {
|
|
15727
|
-
addLeafCommand(groups, operation, spec, segments);
|
|
15728
|
-
}
|
|
15729
|
-
for (const variant of spec.variants ?? []) {
|
|
15730
|
-
addLeafCommand(groups, operation, variantCommandSpec(spec, variant), variant.command.split(" "));
|
|
15731
|
-
}
|
|
15732
|
-
for (const from of spec.renamedFrom ?? []) {
|
|
15733
|
-
renamed.push({ operation, spec, from, to: segments.join(" ") });
|
|
15734
|
-
}
|
|
15735
|
-
}
|
|
15736
|
-
for (const { operation, spec, from, to } of renamed) {
|
|
15737
|
-
addRenamedCommand(groups, operation, spec, from, to);
|
|
15738
|
-
}
|
|
15739
|
-
return [...groups.values()].sort((a, b) => a.name().localeCompare(b.name()));
|
|
16185
|
+
const redactionSpellings = new Set;
|
|
16186
|
+
secrets.command("set").argument("<name>", "Secret name, as referenced in workflows").description(describeOperation(V2_OPERATIONS.setSecret, "Create or replace a named secret")).addOption(new Option("--scope <scope>", "Secret ownership scope (required)").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").on("option:unredacted", () => redactionSpellings.add("--unredacted")).on("option:no-unredacted", () => redactionSpellings.add("--no-unredacted")).action((name, options, command) => setSecret(name, options, command, redactionSpellings));
|
|
15740
16187
|
}
|
|
15741
16188
|
|
|
15742
16189
|
// src/program.ts
|
|
@@ -15816,6 +16263,7 @@ function buildProgram(options = {}) {
|
|
|
15816
16263
|
attachProtocolCommands(program2);
|
|
15817
16264
|
attachSecretCommands(program2);
|
|
15818
16265
|
program2.addHelpText("after", HELP_EPILOGUE);
|
|
16266
|
+
refuseHelpAfterUnknownCommand(program2);
|
|
15819
16267
|
assertNoReservedProgramFlags(program2);
|
|
15820
16268
|
return program2;
|
|
15821
16269
|
}
|