sim 2.1.2 → 2.1.3-preview.51.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 +1301 -788
- 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,
|
|
@@ -2794,6 +2866,10 @@ function traceRequest(method, url, status, startedAt) {
|
|
|
2794
2866
|
process.stderr.write(`${source_default.dim(`[sim] ${method} ${url} → ${status} ${Math.round(performance.now() - startedAt)}ms`)}
|
|
2795
2867
|
`);
|
|
2796
2868
|
}
|
|
2869
|
+
function withoutLeadingLabel(message, label) {
|
|
2870
|
+
const prefix = `${label}: `;
|
|
2871
|
+
return message.startsWith(prefix) ? message.slice(prefix.length) : message;
|
|
2872
|
+
}
|
|
2797
2873
|
function formatApiErrorDetails(details) {
|
|
2798
2874
|
const issues = [];
|
|
2799
2875
|
const seen = new Set;
|
|
@@ -2831,7 +2907,10 @@ function formatApiErrorDetails(details) {
|
|
|
2831
2907
|
const visible = kept.slice(0, 8);
|
|
2832
2908
|
const lines = [
|
|
2833
2909
|
" details:",
|
|
2834
|
-
...visible.map((issue) =>
|
|
2910
|
+
...visible.map((issue) => {
|
|
2911
|
+
const label = issue.path.length > 0 ? issue.path.join(".") : "request";
|
|
2912
|
+
return ` ${label}: ${withoutLeadingLabel(issue.message, label)}`;
|
|
2913
|
+
})
|
|
2835
2914
|
];
|
|
2836
2915
|
if (kept.length > visible.length)
|
|
2837
2916
|
lines.push(` … ${kept.length - visible.length} more issues`);
|
|
@@ -2969,10 +3048,13 @@ function pageProgress() {
|
|
|
2969
3048
|
};
|
|
2970
3049
|
}
|
|
2971
3050
|
async function requestAllPages(client, path, options) {
|
|
3051
|
+
return (await requestPages(client, path, options)).items;
|
|
3052
|
+
}
|
|
3053
|
+
async function requestPages(client, path, options) {
|
|
2972
3054
|
const { query, pageSize, limit: requestedLimit, ...requestOptions } = options;
|
|
2973
3055
|
const limit = requestedLimit ?? Number.POSITIVE_INFINITY;
|
|
2974
3056
|
if (limit <= 0)
|
|
2975
|
-
return [];
|
|
3057
|
+
return { items: [], truncated: false };
|
|
2976
3058
|
const items = [];
|
|
2977
3059
|
const progress = pageProgress();
|
|
2978
3060
|
let cursor = null;
|
|
@@ -2994,7 +3076,7 @@ async function requestAllPages(client, path, options) {
|
|
|
2994
3076
|
} finally {
|
|
2995
3077
|
progress.finish();
|
|
2996
3078
|
}
|
|
2997
|
-
return items.slice(0, limit);
|
|
3079
|
+
return { items: items.slice(0, limit), truncated: cursor !== null || items.length > limit };
|
|
2998
3080
|
}
|
|
2999
3081
|
function resolvePath(template, params = {}) {
|
|
3000
3082
|
return template.replace(/\[([^\]]+)\]/g, (_match, key) => {
|
|
@@ -6518,7 +6600,8 @@ var V2_OPERATIONS = {
|
|
|
6518
6600
|
version: "Numeric deployment version."
|
|
6519
6601
|
},
|
|
6520
6602
|
responseMode: "json",
|
|
6521
|
-
summary: "Activate Workflow Version"
|
|
6603
|
+
summary: "Activate Workflow Version",
|
|
6604
|
+
personalKeyOnly: true
|
|
6522
6605
|
},
|
|
6523
6606
|
addTableColumn: {
|
|
6524
6607
|
method: "POST",
|
|
@@ -6565,6 +6648,7 @@ var V2_OPERATIONS = {
|
|
|
6565
6648
|
pathParamDocs: { knowledgeBaseId: "Unique knowledge base identifier." },
|
|
6566
6649
|
responseMode: "json",
|
|
6567
6650
|
summary: "Index Workspace Files",
|
|
6651
|
+
personalKeyOnly: true,
|
|
6568
6652
|
body: {
|
|
6569
6653
|
workspaceId: {
|
|
6570
6654
|
kind: "string",
|
|
@@ -6585,6 +6669,7 @@ var V2_OPERATIONS = {
|
|
|
6585
6669
|
pathParamDocs: { workflowId: "Unique workflow identifier." },
|
|
6586
6670
|
responseMode: "json",
|
|
6587
6671
|
summary: "Apply Workflow Operations",
|
|
6672
|
+
personalKeyOnly: true,
|
|
6588
6673
|
query: {
|
|
6589
6674
|
dryRun: {
|
|
6590
6675
|
kind: "boolean",
|
|
@@ -6684,6 +6769,7 @@ var V2_OPERATIONS = {
|
|
|
6684
6769
|
pathParamDocs: { knowledgeBaseId: "Unique knowledge base identifier." },
|
|
6685
6770
|
responseMode: "json",
|
|
6686
6771
|
summary: "Bulk Save Tag Definitions",
|
|
6772
|
+
personalKeyOnly: true,
|
|
6687
6773
|
body: {
|
|
6688
6774
|
workspaceId: {
|
|
6689
6775
|
kind: "string",
|
|
@@ -6707,6 +6793,7 @@ var V2_OPERATIONS = {
|
|
|
6707
6793
|
},
|
|
6708
6794
|
responseMode: "json",
|
|
6709
6795
|
summary: "Bulk Update Chunks",
|
|
6796
|
+
personalKeyOnly: true,
|
|
6710
6797
|
body: {
|
|
6711
6798
|
workspaceId: {
|
|
6712
6799
|
kind: "string",
|
|
@@ -6722,7 +6809,7 @@ var V2_OPERATIONS = {
|
|
|
6722
6809
|
chunkIds: {
|
|
6723
6810
|
kind: "array",
|
|
6724
6811
|
required: true,
|
|
6725
|
-
describe: "Chunks to operate on, by identifier.
|
|
6812
|
+
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
6813
|
}
|
|
6727
6814
|
}
|
|
6728
6815
|
},
|
|
@@ -6733,6 +6820,7 @@ var V2_OPERATIONS = {
|
|
|
6733
6820
|
pathParamDocs: { knowledgeBaseId: "Unique knowledge base identifier." },
|
|
6734
6821
|
responseMode: "json",
|
|
6735
6822
|
summary: "Bulk Enable or Disable Documents",
|
|
6823
|
+
personalKeyOnly: true,
|
|
6736
6824
|
body: {
|
|
6737
6825
|
workspaceId: {
|
|
6738
6826
|
kind: "string",
|
|
@@ -6957,6 +7045,7 @@ var V2_OPERATIONS = {
|
|
|
6957
7045
|
pathParams: [],
|
|
6958
7046
|
responseMode: "json",
|
|
6959
7047
|
summary: "Create Credential Connection",
|
|
7048
|
+
personalKeyOnly: true,
|
|
6960
7049
|
body: {
|
|
6961
7050
|
workspaceId: {
|
|
6962
7051
|
kind: "string",
|
|
@@ -7132,6 +7221,7 @@ var V2_OPERATIONS = {
|
|
|
7132
7221
|
},
|
|
7133
7222
|
responseMode: "json",
|
|
7134
7223
|
summary: "Create Chunk",
|
|
7224
|
+
personalKeyOnly: true,
|
|
7135
7225
|
body: {
|
|
7136
7226
|
workspaceId: {
|
|
7137
7227
|
kind: "string",
|
|
@@ -7157,6 +7247,7 @@ var V2_OPERATIONS = {
|
|
|
7157
7247
|
pathParamDocs: { knowledgeBaseId: "Unique knowledge base identifier." },
|
|
7158
7248
|
responseMode: "json",
|
|
7159
7249
|
summary: "Create Knowledge Connector",
|
|
7250
|
+
personalKeyOnly: true,
|
|
7160
7251
|
body: {
|
|
7161
7252
|
workspaceId: {
|
|
7162
7253
|
kind: "string",
|
|
@@ -7272,6 +7363,7 @@ var V2_OPERATIONS = {
|
|
|
7272
7363
|
pathParamDocs: { knowledgeBaseId: "Unique knowledge base identifier." },
|
|
7273
7364
|
responseMode: "json",
|
|
7274
7365
|
summary: "Create Tag",
|
|
7366
|
+
personalKeyOnly: true,
|
|
7275
7367
|
body: {
|
|
7276
7368
|
workspaceId: {
|
|
7277
7369
|
kind: "string",
|
|
@@ -7379,6 +7471,7 @@ var V2_OPERATIONS = {
|
|
|
7379
7471
|
pathParams: [],
|
|
7380
7472
|
responseMode: "json",
|
|
7381
7473
|
summary: "Create Service-Account Credential",
|
|
7474
|
+
personalKeyOnly: true,
|
|
7382
7475
|
body: {
|
|
7383
7476
|
workspaceId: {
|
|
7384
7477
|
kind: "string",
|
|
@@ -7417,6 +7510,7 @@ var V2_OPERATIONS = {
|
|
|
7417
7510
|
pathParams: [],
|
|
7418
7511
|
responseMode: "json",
|
|
7419
7512
|
summary: "Create Skill",
|
|
7513
|
+
personalKeyOnly: true,
|
|
7420
7514
|
body: {
|
|
7421
7515
|
workspaceId: {
|
|
7422
7516
|
kind: "string",
|
|
@@ -7632,6 +7726,7 @@ var V2_OPERATIONS = {
|
|
|
7632
7726
|
pathParams: [],
|
|
7633
7727
|
responseMode: "json",
|
|
7634
7728
|
summary: "Create Workflow MCP Server",
|
|
7729
|
+
personalKeyOnly: true,
|
|
7635
7730
|
body: {
|
|
7636
7731
|
workspaceId: {
|
|
7637
7732
|
kind: "string",
|
|
@@ -7662,6 +7757,7 @@ var V2_OPERATIONS = {
|
|
|
7662
7757
|
pathParamDocs: { credentialId: "Credential to disconnect." },
|
|
7663
7758
|
responseMode: "json",
|
|
7664
7759
|
summary: "Disconnect Credential",
|
|
7760
|
+
personalKeyOnly: true,
|
|
7665
7761
|
query: {
|
|
7666
7762
|
workspaceId: {
|
|
7667
7763
|
kind: "string",
|
|
@@ -7752,6 +7848,7 @@ var V2_OPERATIONS = {
|
|
|
7752
7848
|
},
|
|
7753
7849
|
responseMode: "json",
|
|
7754
7850
|
summary: "Delete Chunk",
|
|
7851
|
+
personalKeyOnly: true,
|
|
7755
7852
|
query: {
|
|
7756
7853
|
workspaceId: {
|
|
7757
7854
|
kind: "string",
|
|
@@ -7770,6 +7867,7 @@ var V2_OPERATIONS = {
|
|
|
7770
7867
|
},
|
|
7771
7868
|
responseMode: "json",
|
|
7772
7869
|
summary: "Delete Knowledge Connector",
|
|
7870
|
+
personalKeyOnly: true,
|
|
7773
7871
|
query: {
|
|
7774
7872
|
workspaceId: {
|
|
7775
7873
|
kind: "string",
|
|
@@ -7840,6 +7938,7 @@ var V2_OPERATIONS = {
|
|
|
7840
7938
|
},
|
|
7841
7939
|
responseMode: "json",
|
|
7842
7940
|
summary: "Delete Tag",
|
|
7941
|
+
personalKeyOnly: true,
|
|
7843
7942
|
query: {
|
|
7844
7943
|
workspaceId: {
|
|
7845
7944
|
kind: "string",
|
|
@@ -7855,6 +7954,7 @@ var V2_OPERATIONS = {
|
|
|
7855
7954
|
pathParamDocs: { knowledgeBaseId: "Unique knowledge base identifier." },
|
|
7856
7955
|
responseMode: "json",
|
|
7857
7956
|
summary: "Delete Tag Definitions",
|
|
7957
|
+
personalKeyOnly: true,
|
|
7858
7958
|
query: {
|
|
7859
7959
|
workspaceId: {
|
|
7860
7960
|
kind: "string",
|
|
@@ -7886,9 +7986,10 @@ var V2_OPERATIONS = {
|
|
|
7886
7986
|
method: "DELETE",
|
|
7887
7987
|
path: "/api/v2/secrets/[name]",
|
|
7888
7988
|
pathParams: ["name"],
|
|
7889
|
-
pathParamDocs: { name: "Secret to
|
|
7989
|
+
pathParamDocs: { name: "Secret to delete." },
|
|
7890
7990
|
responseMode: "json",
|
|
7891
7991
|
summary: "Delete Secret",
|
|
7992
|
+
personalKeyOnly: true,
|
|
7892
7993
|
query: {
|
|
7893
7994
|
workspaceId: {
|
|
7894
7995
|
kind: "string",
|
|
@@ -7912,6 +8013,7 @@ var V2_OPERATIONS = {
|
|
|
7912
8013
|
},
|
|
7913
8014
|
responseMode: "json",
|
|
7914
8015
|
summary: "Delete Skill",
|
|
8016
|
+
personalKeyOnly: true,
|
|
7915
8017
|
query: {
|
|
7916
8018
|
workspaceId: { kind: "string", required: true, describe: "Workspace that owns the skill." }
|
|
7917
8019
|
}
|
|
@@ -8022,7 +8124,8 @@ var V2_OPERATIONS = {
|
|
|
8022
8124
|
pathParams: ["workflowId"],
|
|
8023
8125
|
pathParamDocs: { workflowId: "Unique workflow identifier." },
|
|
8024
8126
|
responseMode: "json",
|
|
8025
|
-
summary: "Delete Workflow Chat Deployment"
|
|
8127
|
+
summary: "Delete Workflow Chat Deployment",
|
|
8128
|
+
personalKeyOnly: true
|
|
8026
8129
|
},
|
|
8027
8130
|
deleteWorkflowFolder: {
|
|
8028
8131
|
method: "DELETE",
|
|
@@ -8072,7 +8175,8 @@ var V2_OPERATIONS = {
|
|
|
8072
8175
|
pathParams: ["serverId"],
|
|
8073
8176
|
pathParamDocs: { serverId: "Unique workflow-MCP server identifier." },
|
|
8074
8177
|
responseMode: "json",
|
|
8075
|
-
summary: "Delete Workflow MCP Server"
|
|
8178
|
+
summary: "Delete Workflow MCP Server",
|
|
8179
|
+
personalKeyOnly: true
|
|
8076
8180
|
},
|
|
8077
8181
|
deployWorkflow: {
|
|
8078
8182
|
method: "POST",
|
|
@@ -8081,6 +8185,7 @@ var V2_OPERATIONS = {
|
|
|
8081
8185
|
pathParamDocs: { workflowId: "Unique workflow identifier." },
|
|
8082
8186
|
responseMode: "json",
|
|
8083
8187
|
summary: "Deploy Workflow",
|
|
8188
|
+
personalKeyOnly: true,
|
|
8084
8189
|
body: {
|
|
8085
8190
|
name: { kind: "string", describe: "Optional label for the deployment version." },
|
|
8086
8191
|
description: {
|
|
@@ -8096,6 +8201,7 @@ var V2_OPERATIONS = {
|
|
|
8096
8201
|
pathParamDocs: { serverId: "Unique workflow-MCP server identifier." },
|
|
8097
8202
|
responseMode: "json",
|
|
8098
8203
|
summary: "Publish Workflow As MCP Tool",
|
|
8204
|
+
personalKeyOnly: true,
|
|
8099
8205
|
body: {
|
|
8100
8206
|
workflowId: {
|
|
8101
8207
|
kind: "string",
|
|
@@ -8236,6 +8342,7 @@ var V2_OPERATIONS = {
|
|
|
8236
8342
|
pathParamDocs: { auditLogId: "Audit-log entry identifier." },
|
|
8237
8343
|
responseMode: "json",
|
|
8238
8344
|
summary: "Get Audit Log",
|
|
8345
|
+
personalKeyOnly: true,
|
|
8239
8346
|
query: {
|
|
8240
8347
|
organizationId: {
|
|
8241
8348
|
kind: "string",
|
|
@@ -8301,7 +8408,7 @@ var V2_OPERATIONS = {
|
|
|
8301
8408
|
kind: "enum",
|
|
8302
8409
|
values: ["active", "archived"],
|
|
8303
8410
|
default: "active",
|
|
8304
|
-
describe: "Which lifecycle set to read from: `active` (default) resolves live files only and returns `404` for a file a
|
|
8411
|
+
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
8412
|
}
|
|
8306
8413
|
}
|
|
8307
8414
|
},
|
|
@@ -8364,6 +8471,7 @@ var V2_OPERATIONS = {
|
|
|
8364
8471
|
},
|
|
8365
8472
|
responseMode: "json",
|
|
8366
8473
|
summary: "Get Chunk",
|
|
8474
|
+
personalKeyOnly: true,
|
|
8367
8475
|
query: {
|
|
8368
8476
|
workspaceId: {
|
|
8369
8477
|
kind: "string",
|
|
@@ -8382,6 +8490,7 @@ var V2_OPERATIONS = {
|
|
|
8382
8490
|
},
|
|
8383
8491
|
responseMode: "json",
|
|
8384
8492
|
summary: "Get Knowledge Connector",
|
|
8493
|
+
personalKeyOnly: true,
|
|
8385
8494
|
query: {
|
|
8386
8495
|
workspaceId: {
|
|
8387
8496
|
kind: "string",
|
|
@@ -8489,6 +8598,7 @@ var V2_OPERATIONS = {
|
|
|
8489
8598
|
pathParamDocs: { knowledgeBaseId: "Unique knowledge base identifier." },
|
|
8490
8599
|
responseMode: "json",
|
|
8491
8600
|
summary: "Get Next Tag Slot",
|
|
8601
|
+
personalKeyOnly: true,
|
|
8492
8602
|
query: {
|
|
8493
8603
|
workspaceId: {
|
|
8494
8604
|
kind: "string",
|
|
@@ -8656,7 +8766,8 @@ var V2_OPERATIONS = {
|
|
|
8656
8766
|
pathParams: ["workflowId"],
|
|
8657
8767
|
pathParamDocs: { workflowId: "Unique workflow identifier." },
|
|
8658
8768
|
responseMode: "json",
|
|
8659
|
-
summary: "Get Workflow Chat Deployment"
|
|
8769
|
+
summary: "Get Workflow Chat Deployment",
|
|
8770
|
+
personalKeyOnly: true
|
|
8660
8771
|
},
|
|
8661
8772
|
getWorkflowDeployment: {
|
|
8662
8773
|
method: "GET",
|
|
@@ -8672,7 +8783,8 @@ var V2_OPERATIONS = {
|
|
|
8672
8783
|
pathParams: ["serverId"],
|
|
8673
8784
|
pathParamDocs: { serverId: "Unique workflow-MCP server identifier." },
|
|
8674
8785
|
responseMode: "json",
|
|
8675
|
-
summary: "Get Workflow MCP Server"
|
|
8786
|
+
summary: "Get Workflow MCP Server",
|
|
8787
|
+
personalKeyOnly: true
|
|
8676
8788
|
},
|
|
8677
8789
|
getWorkflowRun: {
|
|
8678
8790
|
method: "GET",
|
|
@@ -8739,6 +8851,7 @@ var V2_OPERATIONS = {
|
|
|
8739
8851
|
},
|
|
8740
8852
|
responseMode: "json",
|
|
8741
8853
|
summary: "Grant Skill Editor",
|
|
8854
|
+
personalKeyOnly: true,
|
|
8742
8855
|
body: {
|
|
8743
8856
|
workspaceId: { kind: "string", required: true, describe: "Workspace that owns the skill." },
|
|
8744
8857
|
email: {
|
|
@@ -8779,6 +8892,7 @@ var V2_OPERATIONS = {
|
|
|
8779
8892
|
pathParams: [],
|
|
8780
8893
|
responseMode: "json",
|
|
8781
8894
|
summary: "List Audit Logs",
|
|
8895
|
+
personalKeyOnly: true,
|
|
8782
8896
|
query: {
|
|
8783
8897
|
action: { kind: "string", describe: "Filter by exact action name." },
|
|
8784
8898
|
resourceType: {
|
|
@@ -9116,7 +9230,7 @@ var V2_OPERATIONS = {
|
|
|
9116
9230
|
kind: "enum",
|
|
9117
9231
|
values: ["active", "archived"],
|
|
9118
9232
|
default: "active",
|
|
9119
|
-
describe: "Which lifecycle set to list: `active` (default) returns live folders only; `archived` returns folders a recursive
|
|
9233
|
+
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
9234
|
}
|
|
9121
9235
|
}
|
|
9122
9236
|
},
|
|
@@ -9158,7 +9272,7 @@ var V2_OPERATIONS = {
|
|
|
9158
9272
|
kind: "enum",
|
|
9159
9273
|
values: ["active", "archived"],
|
|
9160
9274
|
default: "active",
|
|
9161
|
-
describe: "Which lifecycle set to list: `active` (default) for live files, `archived` for files a
|
|
9275
|
+
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
9276
|
},
|
|
9163
9277
|
search: {
|
|
9164
9278
|
kind: "string",
|
|
@@ -9246,6 +9360,7 @@ var V2_OPERATIONS = {
|
|
|
9246
9360
|
},
|
|
9247
9361
|
responseMode: "json",
|
|
9248
9362
|
summary: "List Chunks",
|
|
9363
|
+
personalKeyOnly: true,
|
|
9249
9364
|
query: {
|
|
9250
9365
|
workspaceId: {
|
|
9251
9366
|
kind: "string",
|
|
@@ -9295,6 +9410,7 @@ var V2_OPERATIONS = {
|
|
|
9295
9410
|
},
|
|
9296
9411
|
responseMode: "json",
|
|
9297
9412
|
summary: "List Knowledge Connector Documents",
|
|
9413
|
+
personalKeyOnly: true,
|
|
9298
9414
|
query: {
|
|
9299
9415
|
workspaceId: {
|
|
9300
9416
|
kind: "string",
|
|
@@ -9323,6 +9439,7 @@ var V2_OPERATIONS = {
|
|
|
9323
9439
|
pathParamDocs: { knowledgeBaseId: "Unique knowledge base identifier." },
|
|
9324
9440
|
responseMode: "json",
|
|
9325
9441
|
summary: "List Knowledge Connectors",
|
|
9442
|
+
personalKeyOnly: true,
|
|
9326
9443
|
query: {
|
|
9327
9444
|
workspaceId: {
|
|
9328
9445
|
kind: "string",
|
|
@@ -9466,6 +9583,7 @@ var V2_OPERATIONS = {
|
|
|
9466
9583
|
pathParamDocs: { knowledgeBaseId: "Unique knowledge base identifier." },
|
|
9467
9584
|
responseMode: "json",
|
|
9468
9585
|
summary: "List Tag Usage",
|
|
9586
|
+
personalKeyOnly: true,
|
|
9469
9587
|
query: {
|
|
9470
9588
|
workspaceId: {
|
|
9471
9589
|
kind: "string",
|
|
@@ -9557,14 +9675,14 @@ var V2_OPERATIONS = {
|
|
|
9557
9675
|
},
|
|
9558
9676
|
includeJobRuns: {
|
|
9559
9677
|
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
|
|
9678
|
+
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
9679
|
},
|
|
9562
9680
|
runId: { kind: "string", describe: "Exact run identifier to match." },
|
|
9563
9681
|
sortBy: {
|
|
9564
9682
|
kind: "enum",
|
|
9565
9683
|
values: ["startedAt", "durationMs", "cost", "status"],
|
|
9566
9684
|
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
|
|
9685
|
+
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
9686
|
},
|
|
9569
9687
|
sortOrder: {
|
|
9570
9688
|
kind: "enum",
|
|
@@ -9624,6 +9742,7 @@ var V2_OPERATIONS = {
|
|
|
9624
9742
|
pathParamDocs: { mcpServerId: "Unique MCP server identifier." },
|
|
9625
9743
|
responseMode: "json",
|
|
9626
9744
|
summary: "List MCP Server Tools",
|
|
9745
|
+
personalKeyOnly: true,
|
|
9627
9746
|
query: {
|
|
9628
9747
|
workspaceId: {
|
|
9629
9748
|
kind: "string",
|
|
@@ -9642,6 +9761,7 @@ var V2_OPERATIONS = {
|
|
|
9642
9761
|
pathParams: [],
|
|
9643
9762
|
responseMode: "json",
|
|
9644
9763
|
summary: "List Secrets",
|
|
9764
|
+
personalKeyOnly: true,
|
|
9645
9765
|
query: {
|
|
9646
9766
|
workspaceId: {
|
|
9647
9767
|
kind: "string",
|
|
@@ -9834,7 +9954,7 @@ var V2_OPERATIONS = {
|
|
|
9834
9954
|
kind: "enum",
|
|
9835
9955
|
values: ["active", "archived"],
|
|
9836
9956
|
default: "active",
|
|
9837
|
-
describe: "Which lifecycle set to list: `active` (default) for live tables, `archived` for tables a
|
|
9957
|
+
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
9958
|
},
|
|
9839
9959
|
folderPath: {
|
|
9840
9960
|
kind: "string",
|
|
@@ -9977,6 +10097,7 @@ var V2_OPERATIONS = {
|
|
|
9977
10097
|
pathParams: [],
|
|
9978
10098
|
responseMode: "json",
|
|
9979
10099
|
summary: "List Workflow MCP Servers",
|
|
10100
|
+
personalKeyOnly: true,
|
|
9980
10101
|
query: {
|
|
9981
10102
|
workspaceId: {
|
|
9982
10103
|
kind: "string",
|
|
@@ -10012,7 +10133,8 @@ var V2_OPERATIONS = {
|
|
|
10012
10133
|
pathParams: ["serverId"],
|
|
10013
10134
|
pathParamDocs: { serverId: "Unique workflow-MCP server identifier." },
|
|
10014
10135
|
responseMode: "json",
|
|
10015
|
-
summary: "List Workflow MCP Tools"
|
|
10136
|
+
summary: "List Workflow MCP Tools",
|
|
10137
|
+
personalKeyOnly: true
|
|
10016
10138
|
},
|
|
10017
10139
|
listWorkflowRuns: {
|
|
10018
10140
|
method: "GET",
|
|
@@ -10069,7 +10191,7 @@ var V2_OPERATIONS = {
|
|
|
10069
10191
|
kind: "enum",
|
|
10070
10192
|
values: ["active", "archived"],
|
|
10071
10193
|
default: "active",
|
|
10072
|
-
describe: "Which lifecycle set to list: `active` (default) for live workflows, `archived` for workflows a `DELETE` archived.
|
|
10194
|
+
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
10195
|
},
|
|
10074
10196
|
folderPath: {
|
|
10075
10197
|
kind: "string",
|
|
@@ -10372,6 +10494,7 @@ var V2_OPERATIONS = {
|
|
|
10372
10494
|
pathParamDocs: { workflowId: "Unique workflow identifier." },
|
|
10373
10495
|
responseMode: "json",
|
|
10374
10496
|
summary: "Create or Replace Workflow Chat Deployment",
|
|
10497
|
+
personalKeyOnly: true,
|
|
10375
10498
|
body: {
|
|
10376
10499
|
identifier: {
|
|
10377
10500
|
kind: "string",
|
|
@@ -10424,6 +10547,7 @@ var V2_OPERATIONS = {
|
|
|
10424
10547
|
pathParamDocs: { workflowId: "Unique workflow identifier." },
|
|
10425
10548
|
responseMode: "json",
|
|
10426
10549
|
summary: "Replace Workflow State",
|
|
10550
|
+
personalKeyOnly: true,
|
|
10427
10551
|
query: {
|
|
10428
10552
|
dryRun: {
|
|
10429
10553
|
kind: "boolean",
|
|
@@ -10477,7 +10601,7 @@ var V2_OPERATIONS = {
|
|
|
10477
10601
|
path: {
|
|
10478
10602
|
kind: "string",
|
|
10479
10603
|
required: true,
|
|
10480
|
-
describe: "Path of the archived folder to restore, as reported by
|
|
10604
|
+
describe: "Path of the archived folder to restore, as reported by an archived-scope folder list."
|
|
10481
10605
|
}
|
|
10482
10606
|
}
|
|
10483
10607
|
},
|
|
@@ -10522,7 +10646,7 @@ var V2_OPERATIONS = {
|
|
|
10522
10646
|
path: {
|
|
10523
10647
|
kind: "string",
|
|
10524
10648
|
required: true,
|
|
10525
|
-
describe: "Path the folder held when
|
|
10649
|
+
describe: "Path the folder held when a folder delete archived it."
|
|
10526
10650
|
}
|
|
10527
10651
|
}
|
|
10528
10652
|
},
|
|
@@ -10562,7 +10686,8 @@ var V2_OPERATIONS = {
|
|
|
10562
10686
|
version: "Numeric deployment version, or `active` for the currently live version."
|
|
10563
10687
|
},
|
|
10564
10688
|
responseMode: "json",
|
|
10565
|
-
summary: "Revert Workflow To Version"
|
|
10689
|
+
summary: "Revert Workflow To Version",
|
|
10690
|
+
personalKeyOnly: true
|
|
10566
10691
|
},
|
|
10567
10692
|
revokeSkillEditor: {
|
|
10568
10693
|
method: "DELETE",
|
|
@@ -10573,6 +10698,7 @@ var V2_OPERATIONS = {
|
|
|
10573
10698
|
},
|
|
10574
10699
|
responseMode: "json",
|
|
10575
10700
|
summary: "Revoke Skill Editor",
|
|
10701
|
+
personalKeyOnly: true,
|
|
10576
10702
|
query: {
|
|
10577
10703
|
workspaceId: { kind: "string", required: true, describe: "Workspace that owns the skill." },
|
|
10578
10704
|
email: {
|
|
@@ -10589,6 +10715,7 @@ var V2_OPERATIONS = {
|
|
|
10589
10715
|
pathParamDocs: { workflowId: "Unique workflow identifier." },
|
|
10590
10716
|
responseMode: "json",
|
|
10591
10717
|
summary: "Rollback Workflow",
|
|
10718
|
+
personalKeyOnly: true,
|
|
10592
10719
|
body: {
|
|
10593
10720
|
version: {
|
|
10594
10721
|
kind: "integer",
|
|
@@ -10683,9 +10810,10 @@ var V2_OPERATIONS = {
|
|
|
10683
10810
|
method: "PUT",
|
|
10684
10811
|
path: "/api/v2/secrets/[name]",
|
|
10685
10812
|
pathParams: ["name"],
|
|
10686
|
-
pathParamDocs: { name: "Secret to create
|
|
10813
|
+
pathParamDocs: { name: "Secret to create or replace." },
|
|
10687
10814
|
responseMode: "json",
|
|
10688
10815
|
summary: "Set Secret",
|
|
10816
|
+
personalKeyOnly: true,
|
|
10689
10817
|
body: {
|
|
10690
10818
|
workspaceId: {
|
|
10691
10819
|
kind: "string",
|
|
@@ -10700,8 +10828,7 @@ var V2_OPERATIONS = {
|
|
|
10700
10828
|
},
|
|
10701
10829
|
value: {
|
|
10702
10830
|
kind: "string",
|
|
10703
|
-
|
|
10704
|
-
describe: "Write-only secret value. It is never returned."
|
|
10831
|
+
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
10832
|
},
|
|
10706
10833
|
description: {
|
|
10707
10834
|
kind: "string",
|
|
@@ -10723,6 +10850,7 @@ var V2_OPERATIONS = {
|
|
|
10723
10850
|
},
|
|
10724
10851
|
responseMode: "json",
|
|
10725
10852
|
summary: "Sync Knowledge Connector",
|
|
10853
|
+
personalKeyOnly: true,
|
|
10726
10854
|
body: {
|
|
10727
10855
|
workspaceId: {
|
|
10728
10856
|
kind: "string",
|
|
@@ -10760,7 +10888,8 @@ var V2_OPERATIONS = {
|
|
|
10760
10888
|
pathParams: ["workflowId"],
|
|
10761
10889
|
pathParamDocs: { workflowId: "Unique workflow identifier." },
|
|
10762
10890
|
responseMode: "json",
|
|
10763
|
-
summary: "Undeploy Workflow"
|
|
10891
|
+
summary: "Undeploy Workflow",
|
|
10892
|
+
personalKeyOnly: true
|
|
10764
10893
|
},
|
|
10765
10894
|
undeployWorkflowMcpTool: {
|
|
10766
10895
|
method: "DELETE",
|
|
@@ -10771,7 +10900,8 @@ var V2_OPERATIONS = {
|
|
|
10771
10900
|
workflowId: "Workflow published as a tool on this server."
|
|
10772
10901
|
},
|
|
10773
10902
|
responseMode: "json",
|
|
10774
|
-
summary: "Unpublish Workflow MCP Tool"
|
|
10903
|
+
summary: "Unpublish Workflow MCP Tool",
|
|
10904
|
+
personalKeyOnly: true
|
|
10775
10905
|
},
|
|
10776
10906
|
unzipFile: {
|
|
10777
10907
|
method: "POST",
|
|
@@ -10791,6 +10921,7 @@ var V2_OPERATIONS = {
|
|
|
10791
10921
|
pathParamDocs: { credentialId: "Credential to update." },
|
|
10792
10922
|
responseMode: "json",
|
|
10793
10923
|
summary: "Update Credential",
|
|
10924
|
+
personalKeyOnly: true,
|
|
10794
10925
|
query: {
|
|
10795
10926
|
workspaceId: {
|
|
10796
10927
|
kind: "string",
|
|
@@ -10892,6 +11023,7 @@ var V2_OPERATIONS = {
|
|
|
10892
11023
|
},
|
|
10893
11024
|
responseMode: "json",
|
|
10894
11025
|
summary: "Update Chunk",
|
|
11026
|
+
personalKeyOnly: true,
|
|
10895
11027
|
body: {
|
|
10896
11028
|
workspaceId: {
|
|
10897
11029
|
kind: "string",
|
|
@@ -10918,6 +11050,7 @@ var V2_OPERATIONS = {
|
|
|
10918
11050
|
},
|
|
10919
11051
|
responseMode: "json",
|
|
10920
11052
|
summary: "Update Knowledge Connector",
|
|
11053
|
+
personalKeyOnly: true,
|
|
10921
11054
|
body: {
|
|
10922
11055
|
workspaceId: {
|
|
10923
11056
|
kind: "string",
|
|
@@ -10949,6 +11082,7 @@ var V2_OPERATIONS = {
|
|
|
10949
11082
|
},
|
|
10950
11083
|
responseMode: "json",
|
|
10951
11084
|
summary: "Update Knowledge Connector Documents",
|
|
11085
|
+
personalKeyOnly: true,
|
|
10952
11086
|
body: {
|
|
10953
11087
|
workspaceId: {
|
|
10954
11088
|
kind: "string",
|
|
@@ -10978,6 +11112,7 @@ var V2_OPERATIONS = {
|
|
|
10978
11112
|
},
|
|
10979
11113
|
responseMode: "json",
|
|
10980
11114
|
summary: "Update Document",
|
|
11115
|
+
personalKeyOnly: true,
|
|
10981
11116
|
body: {
|
|
10982
11117
|
workspaceId: {
|
|
10983
11118
|
kind: "string",
|
|
@@ -11022,6 +11157,7 @@ var V2_OPERATIONS = {
|
|
|
11022
11157
|
},
|
|
11023
11158
|
responseMode: "json",
|
|
11024
11159
|
summary: "Update Tag",
|
|
11160
|
+
personalKeyOnly: true,
|
|
11025
11161
|
body: {
|
|
11026
11162
|
workspaceId: {
|
|
11027
11163
|
kind: "string",
|
|
@@ -11126,6 +11262,7 @@ var V2_OPERATIONS = {
|
|
|
11126
11262
|
},
|
|
11127
11263
|
responseMode: "json",
|
|
11128
11264
|
summary: "Update Skill",
|
|
11265
|
+
personalKeyOnly: true,
|
|
11129
11266
|
body: {
|
|
11130
11267
|
workspaceId: { kind: "string", required: true, describe: "Workspace that owns the skill." },
|
|
11131
11268
|
name: { kind: "string", describe: "New kebab-case skill name." },
|
|
@@ -11263,6 +11400,7 @@ var V2_OPERATIONS = {
|
|
|
11263
11400
|
pathParamDocs: { serverId: "Unique workflow-MCP server identifier." },
|
|
11264
11401
|
responseMode: "json",
|
|
11265
11402
|
summary: "Update Workflow MCP Server",
|
|
11403
|
+
personalKeyOnly: true,
|
|
11266
11404
|
body: {
|
|
11267
11405
|
name: { kind: "string", describe: "Server display name, shown to connecting MCP clients." },
|
|
11268
11406
|
description: { kind: "string", describe: "New server description, or null to clear it." },
|
|
@@ -11279,6 +11417,7 @@ var V2_OPERATIONS = {
|
|
|
11279
11417
|
pathParamDocs: { workflowId: "Unique workflow identifier." },
|
|
11280
11418
|
responseMode: "json",
|
|
11281
11419
|
summary: "Update Workflow Public API Access",
|
|
11420
|
+
personalKeyOnly: true,
|
|
11282
11421
|
body: {
|
|
11283
11422
|
isPublicApi: {
|
|
11284
11423
|
kind: "boolean",
|
|
@@ -11327,6 +11466,7 @@ var V2_OPERATIONS = {
|
|
|
11327
11466
|
pathParamDocs: { fileId: "File identifier." },
|
|
11328
11467
|
responseMode: "json",
|
|
11329
11468
|
summary: "Enable or Disable File Share",
|
|
11469
|
+
personalKeyOnly: true,
|
|
11330
11470
|
body: {
|
|
11331
11471
|
workspaceId: { kind: "string", required: true, describe: "Workspace that owns the file." },
|
|
11332
11472
|
isActive: {
|
|
@@ -11361,7 +11501,7 @@ var V2_OPERATIONS = {
|
|
|
11361
11501
|
data: {
|
|
11362
11502
|
kind: "object",
|
|
11363
11503
|
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
|
|
11504
|
+
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
11505
|
},
|
|
11366
11506
|
conflictTarget: { kind: "string", describe: "Unique column used to detect a conflict." }
|
|
11367
11507
|
}
|
|
@@ -11369,7 +11509,6 @@ var V2_OPERATIONS = {
|
|
|
11369
11509
|
};
|
|
11370
11510
|
|
|
11371
11511
|
// src/commands/auth.ts
|
|
11372
|
-
var PROFILE_NAME_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._-]*$/;
|
|
11373
11512
|
var MAX_INTERACTIVE_WORKSPACES = 1000;
|
|
11374
11513
|
function openBrowser(url) {
|
|
11375
11514
|
const [command, args] = process.platform === "win32" ? ["cmd", ["/c", "start", "", url]] : [process.platform === "darwin" ? "open" : "xdg-open", [url]];
|
|
@@ -11396,11 +11535,11 @@ function presentAuthentication(source) {
|
|
|
11396
11535
|
}
|
|
11397
11536
|
async function confirmProfileOverwrite(profileName) {
|
|
11398
11537
|
if (!process.stdin.isTTY) {
|
|
11399
|
-
throw new SimApiError(`Profile "${profileName}" already exists. Re-run with --yes to overwrite it.`, 0);
|
|
11538
|
+
throw new SimApiError(`Profile "${redact(profileName)}" already exists. Re-run with --yes to overwrite it.`, 0);
|
|
11400
11539
|
}
|
|
11401
11540
|
const prompt = createInterface({ input: process.stdin, output: process.stderr });
|
|
11402
11541
|
try {
|
|
11403
|
-
const answer = await prompt.question(`Profile "${profileName}" already exists. Replace its API key and login defaults? (y/N) `);
|
|
11542
|
+
const answer = await prompt.question(`Profile "${redact(profileName)}" already exists. Replace its API key and login defaults? (y/N) `);
|
|
11404
11543
|
return answer.trim().toLowerCase() === "y" || answer.trim().toLowerCase() === "yes";
|
|
11405
11544
|
} finally {
|
|
11406
11545
|
prompt.close();
|
|
@@ -11410,21 +11549,24 @@ function selectedProfileName(command) {
|
|
|
11410
11549
|
return globalsOf(command).profile || process.env.SIM_PROFILE || DEFAULT_PROFILE;
|
|
11411
11550
|
}
|
|
11412
11551
|
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
|
-
}
|
|
11552
|
+
validateProfileName(profileName);
|
|
11416
11553
|
if (listProfiles().includes(profileName)) {
|
|
11417
|
-
throw new SimApiError(`Profile "${profileName}" already exists. Remove it first with: sim logout --all --profile ${profileName}`, 0);
|
|
11554
|
+
throw new SimApiError(`Profile "${redact(profileName)}" already exists. Remove it first with: sim logout --all --profile ${redact(profileName)}`, 0);
|
|
11555
|
+
}
|
|
11556
|
+
}
|
|
11557
|
+
function requireStorableKey(apiKey) {
|
|
11558
|
+
if (typeof apiKey !== "string" || !apiKey || apiKey !== apiKey.trim() || FORBIDDEN_IN_VALUE.test(apiKey)) {
|
|
11559
|
+
throw new SimApiError("The server returned a malformed API key. Nothing was stored; check the endpoint.", 0);
|
|
11418
11560
|
}
|
|
11419
11561
|
}
|
|
11420
11562
|
function requireStoredAuthentication(profile) {
|
|
11421
11563
|
const authProfile = resolveAuthenticationProfileName(profile.name);
|
|
11422
11564
|
const storedKey = readCredentialsProfile(authProfile).api_key;
|
|
11423
11565
|
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);
|
|
11566
|
+
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
11567
|
}
|
|
11426
11568
|
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);
|
|
11569
|
+
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
11570
|
}
|
|
11429
11571
|
return authProfile;
|
|
11430
11572
|
}
|
|
@@ -11476,12 +11618,12 @@ function addProfileCommand() {
|
|
|
11476
11618
|
const workspace = workspaceId ? await getWorkspaceById(client, workspaceId) : await chooseWorkspace(client);
|
|
11477
11619
|
writeConfigProfile(profileName, {
|
|
11478
11620
|
auth_profile: authProfile,
|
|
11479
|
-
workspace: workspace.id
|
|
11621
|
+
workspace: normalizeWorkspaceId(workspace.id, "the workspace response")
|
|
11480
11622
|
});
|
|
11481
|
-
console.log(source_default.green(`✓ Added profile "${profileName}" in ${configPath()}`));
|
|
11623
|
+
console.log(source_default.green(`✓ Added profile "${safeOneLine(profileName)}" in ${configPath()}`));
|
|
11482
11624
|
console.log(` Workspace: ${safeOneLine(workspace.name)} (${workspace.id})`);
|
|
11483
|
-
console.log(` Authentication: ${authProfile}`);
|
|
11484
|
-
console.log(source_default.dim(` Try: sim --profile ${profileName} whoami`));
|
|
11625
|
+
console.log(` Authentication: ${safeOneLine(authProfile)}`);
|
|
11626
|
+
console.log(source_default.dim(` Try: sim --profile ${safeOneLine(profileName)} whoami`));
|
|
11485
11627
|
});
|
|
11486
11628
|
}
|
|
11487
11629
|
function loginCommand() {
|
|
@@ -11489,7 +11631,7 @@ function loginCommand() {
|
|
|
11489
11631
|
const profile = profileFrom(command, { allowUnknownProfile: true });
|
|
11490
11632
|
const authProfile = resolveAuthenticationProfileName(profile.name);
|
|
11491
11633
|
if (authProfile !== profile.name) {
|
|
11492
|
-
throw new SimApiError(`Profile "${profile.name}" shares authentication with "${authProfile}". Run: sim login --profile ${authProfile}`, 0);
|
|
11634
|
+
throw new SimApiError(`Profile "${redact(profile.name)}" shares authentication with "${redact(authProfile)}". Run: sim login --profile ${redact(authProfile)}`, 0);
|
|
11493
11635
|
}
|
|
11494
11636
|
if (options.scope !== "platform" && options.scope !== "copilot") {
|
|
11495
11637
|
throw new SimApiError(`Unknown scope "${options.scope}". Use platform or copilot.`, 0);
|
|
@@ -11504,7 +11646,7 @@ function loginCommand() {
|
|
|
11504
11646
|
}
|
|
11505
11647
|
const auth = createAuthRequest();
|
|
11506
11648
|
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)}`);
|
|
11649
|
+
console.log(`Signing in to ${source_default.bold(profile.endpoint)} as profile ${source_default.bold(safeOneLine(profile.name))}`);
|
|
11508
11650
|
console.log(`
|
|
11509
11651
|
Pairing code: ${source_default.bold(auth.pairing)}`);
|
|
11510
11652
|
console.log(source_default.dim(`Confirm this code matches what the browser shows before approving.
|
|
@@ -11518,12 +11660,13 @@ Waiting for approval…`));
|
|
|
11518
11660
|
if (key.scope !== scope) {
|
|
11519
11661
|
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
11662
|
}
|
|
11521
|
-
writeCredentialsProfile(profile.name, key.apiKey);
|
|
11522
11663
|
const settings = {
|
|
11523
11664
|
endpoint: profile.endpoint,
|
|
11524
|
-
workspace: key.workspaceId
|
|
11665
|
+
workspace: key.workspaceId == null ? null : normalizeWorkspaceId(key.workspaceId, "the login response")
|
|
11525
11666
|
};
|
|
11667
|
+
requireStorableKey(key.apiKey);
|
|
11526
11668
|
writeConfigProfile(profile.name, settings);
|
|
11669
|
+
writeCredentialsProfile(profile.name, key.apiKey);
|
|
11527
11670
|
console.log(source_default.green(`
|
|
11528
11671
|
✓ Logged in. Key stored in ${credentialsPath()}`));
|
|
11529
11672
|
if (key.workspaceBound && key.workspaceId) {
|
|
@@ -11541,27 +11684,27 @@ function logoutCommand() {
|
|
|
11541
11684
|
const profileName = selectedProfileName(command);
|
|
11542
11685
|
const dependents = listAuthenticationDependents(profileName);
|
|
11543
11686
|
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);
|
|
11687
|
+
throw new SimApiError(`Cannot remove authentication profile "${redact(profileName)}" because it is used by: ${dependents.map(redact).join(", ")}. Remove those profiles first.`, 0);
|
|
11545
11688
|
}
|
|
11546
11689
|
const removed = deleteProfile(profileName);
|
|
11547
11690
|
if (!removed.config && !removed.credentials) {
|
|
11548
|
-
console.log(source_default.dim(`Nothing stored for profile "${profileName}".`));
|
|
11691
|
+
console.log(source_default.dim(`Nothing stored for profile "${safeOneLine(profileName)}".`));
|
|
11549
11692
|
return;
|
|
11550
11693
|
}
|
|
11551
|
-
console.log(source_default.green(`✓ Removed profile "${profileName}".`));
|
|
11694
|
+
console.log(source_default.green(`✓ Removed profile "${safeOneLine(profileName)}".`));
|
|
11552
11695
|
return;
|
|
11553
11696
|
}
|
|
11554
11697
|
const profile = profileFrom(command);
|
|
11555
11698
|
const authProfile = resolveAuthenticationProfileName(profile.name);
|
|
11556
11699
|
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);
|
|
11700
|
+
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
11701
|
}
|
|
11559
11702
|
if (!readCredentialsProfile(profile.name).api_key) {
|
|
11560
|
-
console.log(source_default.dim(`No stored key for profile "${profile.name}".`));
|
|
11703
|
+
console.log(source_default.dim(`No stored key for profile "${safeOneLine(profile.name)}".`));
|
|
11561
11704
|
return;
|
|
11562
11705
|
}
|
|
11563
11706
|
writeCredentialsProfile(profile.name, null);
|
|
11564
|
-
console.log(source_default.green(`✓ Removed the stored key for profile "${profile.name}".`));
|
|
11707
|
+
console.log(source_default.green(`✓ Removed the stored key for profile "${safeOneLine(profile.name)}".`));
|
|
11565
11708
|
console.log(source_default.dim(" The key itself is still active — revoke it in Settings → API keys."));
|
|
11566
11709
|
});
|
|
11567
11710
|
}
|
|
@@ -11591,7 +11734,7 @@ async function verifyProfile(client, profile) {
|
|
|
11591
11734
|
status: "unauthenticated",
|
|
11592
11735
|
workspace: null,
|
|
11593
11736
|
keyType: null,
|
|
11594
|
-
detail: `no API key — run: sim login --profile ${profile.name}`
|
|
11737
|
+
detail: `no API key — run: sim login --profile ${safeOneLine(profile.name)}`
|
|
11595
11738
|
};
|
|
11596
11739
|
}
|
|
11597
11740
|
const keyType = await readKeyType(client);
|
|
@@ -11600,7 +11743,7 @@ async function verifyProfile(client, profile) {
|
|
|
11600
11743
|
status: "no-workspace",
|
|
11601
11744
|
workspace: null,
|
|
11602
11745
|
keyType,
|
|
11603
|
-
detail: `no workspace to check against — run: sim configure --profile ${profile.name} --set-workspace <id>`
|
|
11746
|
+
detail: `no workspace to check against — run: sim configure --profile ${safeOneLine(profile.name)} --set-workspace <id>`
|
|
11604
11747
|
};
|
|
11605
11748
|
}
|
|
11606
11749
|
const operation = V2_OPERATIONS.getWorkspace;
|
|
@@ -11687,38 +11830,83 @@ function whoamiCommand() {
|
|
|
11687
11830
|
process.exitCode = exitCode;
|
|
11688
11831
|
});
|
|
11689
11832
|
}
|
|
11833
|
+
var PROFILE_COLUMNS = [
|
|
11834
|
+
{ header: "", value: (row) => row.active ? source_default.green("*") : " " },
|
|
11835
|
+
{ header: "profile", value: (row) => safeOneLine(row.name) },
|
|
11836
|
+
{ header: "key", value: (row) => row.error ? text(null) : row.hasKey ? "yes" : "no" },
|
|
11837
|
+
{ header: "auth", value: (row) => row.authProfile ? safeOneLine(row.authProfile) : text(null) },
|
|
11838
|
+
{ header: "error", value: (row) => row.error ? source_default.red(safeOneLine(row.error)) : text(null) }
|
|
11839
|
+
];
|
|
11840
|
+
function buildProfileRow(name, active) {
|
|
11841
|
+
try {
|
|
11842
|
+
const authProfile = resolveAuthenticationProfileName(name);
|
|
11843
|
+
return {
|
|
11844
|
+
name,
|
|
11845
|
+
active,
|
|
11846
|
+
hasKey: Boolean(readCredentialsProfile(authProfile).api_key),
|
|
11847
|
+
authProfile,
|
|
11848
|
+
error: null
|
|
11849
|
+
};
|
|
11850
|
+
} catch (error) {
|
|
11851
|
+
if (!(error instanceof ProfileConfigError))
|
|
11852
|
+
throw error;
|
|
11853
|
+
return { name, active, hasKey: false, authProfile: null, error: error.message };
|
|
11854
|
+
}
|
|
11855
|
+
}
|
|
11856
|
+
function profileListingContext(command) {
|
|
11857
|
+
try {
|
|
11858
|
+
const profile = profileFrom(command);
|
|
11859
|
+
return { activeName: profile.name, output: profile.output };
|
|
11860
|
+
} catch (error) {
|
|
11861
|
+
if (!(error instanceof ProfileConfigError))
|
|
11862
|
+
throw error;
|
|
11863
|
+
if (error instanceof ProfileOverrideError)
|
|
11864
|
+
throw error;
|
|
11865
|
+
const globals = globalsOf(command);
|
|
11866
|
+
const named = globals.profile || process.env.SIM_PROFILE;
|
|
11867
|
+
if (named && named !== DEFAULT_PROFILE && !listProfiles().includes(named))
|
|
11868
|
+
throw error;
|
|
11869
|
+
const requested = globals.output ?? process.env.SIM_OUTPUT;
|
|
11870
|
+
if (requested && !OUTPUT_FORMATS.includes(requested))
|
|
11871
|
+
throw error;
|
|
11872
|
+
return {
|
|
11873
|
+
activeName: named || DEFAULT_PROFILE,
|
|
11874
|
+
output: requested ? requested : "table"
|
|
11875
|
+
};
|
|
11876
|
+
}
|
|
11877
|
+
}
|
|
11690
11878
|
function profilesCommand() {
|
|
11691
11879
|
const command = new Command("profiles").alias("profile").description("List profiles or add a workspace profile that shares a stored login");
|
|
11692
11880
|
const printProfiles = (_options, actionCommand) => {
|
|
11693
|
-
const
|
|
11694
|
-
|
|
11695
|
-
|
|
11881
|
+
const { activeName, output } = profileListingContext(actionCommand);
|
|
11882
|
+
const rows = listProfiles().map((name) => buildProfileRow(name, name === activeName));
|
|
11883
|
+
if (rows.length === 0) {
|
|
11884
|
+
if (output === "table")
|
|
11885
|
+
console.log(source_default.dim("No profiles yet. Run: sim login"));
|
|
11886
|
+
else
|
|
11887
|
+
printList(output, rows, PROFILE_COLUMNS);
|
|
11696
11888
|
return;
|
|
11697
11889
|
}
|
|
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
|
-
}
|
|
11890
|
+
printList(output, rows, PROFILE_COLUMNS);
|
|
11714
11891
|
};
|
|
11715
|
-
command.action(printProfiles);
|
|
11716
|
-
command.addCommand(new Command("list").description("List configured profiles").action(printProfiles));
|
|
11892
|
+
command.addCommand(new Command("list").allowExcessArguments(false).description("List configured profiles").action(printProfiles), { isDefault: true });
|
|
11717
11893
|
command.addCommand(addProfileCommand());
|
|
11894
|
+
const known = new Set(command.commands.flatMap((child) => [child.name(), ...child.aliases()]));
|
|
11895
|
+
command.hook("preSubcommand", (group) => {
|
|
11896
|
+
const first = group.args[0];
|
|
11897
|
+
if (first !== undefined && !first.startsWith("-") && !known.has(first)) {
|
|
11898
|
+
group.unknownCommand();
|
|
11899
|
+
}
|
|
11900
|
+
});
|
|
11718
11901
|
return command;
|
|
11719
11902
|
}
|
|
11720
11903
|
|
|
11721
11904
|
// src/commands/configure.ts
|
|
11905
|
+
var GLOBAL_FLAG_TWINS = [
|
|
11906
|
+
{ option: "endpoint", flag: "--endpoint", setFlag: "--set-endpoint" },
|
|
11907
|
+
{ option: "workspace", flag: "-w, --workspace", setFlag: "--set-workspace" },
|
|
11908
|
+
{ option: "output", flag: "--output", setFlag: "--set-output" }
|
|
11909
|
+
];
|
|
11722
11910
|
function requireValue(value, flag, key) {
|
|
11723
11911
|
if (value !== undefined && value.trim() === "") {
|
|
11724
11912
|
throw new SimApiError(`${flag} requires a value. To remove it, run: sim configure --unset ${key}`, 0);
|
|
@@ -11726,6 +11914,13 @@ function requireValue(value, flag, key) {
|
|
|
11726
11914
|
}
|
|
11727
11915
|
function configureCommand() {
|
|
11728
11916
|
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) => {
|
|
11917
|
+
const globals = globalsOf(command);
|
|
11918
|
+
for (const { option, flag, setFlag } of GLOBAL_FLAG_TWINS) {
|
|
11919
|
+
const value = globals[option];
|
|
11920
|
+
if (value === undefined)
|
|
11921
|
+
continue;
|
|
11922
|
+
throw new SimApiError(`${flag} applies to a single command and is not stored. To save it, run: sim configure ${setFlag} ${redact(value)}`, 0);
|
|
11923
|
+
}
|
|
11729
11924
|
const profile = profileFrom(command, { allowUnknownProfile: true });
|
|
11730
11925
|
const authProfile = resolveAuthenticationProfileName(profile.name);
|
|
11731
11926
|
const updates = {};
|
|
@@ -11738,8 +11933,9 @@ function configureCommand() {
|
|
|
11738
11933
|
}
|
|
11739
11934
|
updates.endpoint = normalizeEndpoint(options.setEndpoint, "--set-endpoint");
|
|
11740
11935
|
}
|
|
11741
|
-
if (options.setWorkspace)
|
|
11742
|
-
updates.workspace = options.setWorkspace;
|
|
11936
|
+
if (options.setWorkspace) {
|
|
11937
|
+
updates.workspace = normalizeWorkspaceId(options.setWorkspace, "--set-workspace");
|
|
11938
|
+
}
|
|
11743
11939
|
if (options.setOutput) {
|
|
11744
11940
|
if (!OUTPUT_FORMATS.includes(options.setOutput)) {
|
|
11745
11941
|
throw new SimApiError(`Unknown output format "${options.setOutput}". Use one of: ${OUTPUT_FORMATS.join(", ")}`, 0);
|
|
@@ -11748,7 +11944,7 @@ function configureCommand() {
|
|
|
11748
11944
|
}
|
|
11749
11945
|
for (const key of options.unset ?? []) {
|
|
11750
11946
|
if (!["endpoint", "workspace", "output"].includes(key)) {
|
|
11751
|
-
throw new SimApiError(`Cannot unset "${key}". Use endpoint, workspace, or output.`, 0);
|
|
11947
|
+
throw new SimApiError(`Cannot unset "${redact(key)}". Use endpoint, workspace, or output.`, 0);
|
|
11752
11948
|
}
|
|
11753
11949
|
if (key === "endpoint" && authProfile !== profile.name) {
|
|
11754
11950
|
throw new SimApiError(`Profile "${profile.name}" shares its endpoint with authentication profile "${authProfile}". Run: sim configure --profile ${authProfile} --unset endpoint`, 0);
|
|
@@ -11766,14 +11962,16 @@ function configureCommand() {
|
|
|
11766
11962
|
}
|
|
11767
11963
|
return;
|
|
11768
11964
|
}
|
|
11965
|
+
const removalOnly = Object.values(updates).every((value) => value === null);
|
|
11966
|
+
if (removalOnly && Object.keys(readConfigProfile(profile.name)).length === 0) {
|
|
11967
|
+
console.log(source_default.dim(`No settings stored for profile "${profile.name}".`));
|
|
11968
|
+
return;
|
|
11969
|
+
}
|
|
11769
11970
|
writeConfigProfile(profile.name, updates);
|
|
11770
11971
|
console.log(source_default.green(`✓ Updated profile "${profile.name}" in ${configPath()}`));
|
|
11771
11972
|
});
|
|
11772
11973
|
}
|
|
11773
11974
|
|
|
11774
|
-
// src/runtime/request.ts
|
|
11775
|
-
import { existsSync as existsSync2, readFileSync as readFileSync3, readSync } from "node:fs";
|
|
11776
|
-
|
|
11777
11975
|
// src/contract/commands.ts
|
|
11778
11976
|
var TABLE_NAME_HELP = "Identifier: letters, numbers, and underscores; cannot start with a number";
|
|
11779
11977
|
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';
|
|
@@ -11782,7 +11980,7 @@ var TABLE_SORT_HELP = 'Ordered sort keys: [{"field":"createdAt","direction":"des
|
|
|
11782
11980
|
var KNOWLEDGE_TAG_DEFINITIONS_HELP = 'Tag definitions: [{"tagSlot":"tag1","displayName":"category","fieldType":"text"}]';
|
|
11783
11981
|
var CUSTOM_TOOL_SCHEMA_HELP = 'OpenAI function schema: {"type":"function","function":{"name":"...","parameters":{"type":"object","properties":{}}}}';
|
|
11784
11982
|
var DISPATCH_ROW_LIMIT_HELP = "Stop after this many eligible rows have run (1-1,000,000). Omit for an unbounded run";
|
|
11785
|
-
var WORKFLOW_OPERATIONS_HELP = 'Edits to apply, in a single batch, keyed by operation_type: [{"operation_type":"add","block_id":"my-fn","params":{"type":"function","name":"My Fn","inputs":{"code":"return {ok:true}"}}},{"operation_type":"edit","block_id":"<uuid>","params":{"name":"Renamed","connections":{"success":"my-fn"}}},{"operation_type":"delete","block_id":"<uuid>"}]. Also
|
|
11983
|
+
var WORKFLOW_OPERATIONS_HELP = 'Edits to apply, in a single batch, keyed by operation_type: [{"operation_type":"add","block_id":"my-fn","params":{"type":"function","name":"My Fn","inputs":{"code":"return {ok:true}"}}},{"operation_type":"edit","block_id":"<uuid>","params":{"name":"Renamed","connections":{"success":"my-fn"}}},{"operation_type":"delete","block_id":"<uuid>"}]. Also extract_from_subflow, whose params carry {"subflowId":"<loop-id>"}, and insert_into_subflow, which creates a block and so takes an add’s params plus that subflowId';
|
|
11786
11984
|
var WORKFLOW_SET_BLOCK_ENABLED_HELP = 'Blocks to enable or disable, applied after --operations: [{"block_id":"<uuid>","enabled":false}]. Disabling a loop or parallel cascades to its unlocked descendants; enabling a block whose container is disabled is declined';
|
|
11787
11985
|
var WORKFLOW_VARIABLE_OPERATIONS_HELP = 'Variable changes to apply in order, keyed by operation: [{"operation":"add","name":"my_var","type":"string","value":"hello"},{"operation":"edit","name":"my_var","value":"updated"},{"operation":"delete","name":"my_var"}]';
|
|
11788
11986
|
var MCP_PARAMETER_DESCRIPTIONS_HELP = 'Per-field description overrides applied to the schema generated from the deployed workflow inputs, as [{"name":"email","description":"Customer email address"}]. A name matching no input field is ignored';
|
|
@@ -11858,7 +12056,7 @@ var CLI_CONTRACT = {
|
|
|
11858
12056
|
listBillingLogs: {
|
|
11859
12057
|
command: "billing logs",
|
|
11860
12058
|
allWorkspaces: true,
|
|
11861
|
-
describe: "List credit usage events",
|
|
12059
|
+
describe: "List credit usage events (a personal API key reports only your own events; a workspace API key reports every member's in aggregate, unattributed)",
|
|
11862
12060
|
flags: {
|
|
11863
12061
|
source: { describe: "Filter by usage source; sim-chat combines Copilot and workspace chat" },
|
|
11864
12062
|
period: { describe: "Billing period" },
|
|
@@ -12014,14 +12212,14 @@ var CLI_CONTRACT = {
|
|
|
12014
12212
|
}
|
|
12015
12213
|
},
|
|
12016
12214
|
columns: [
|
|
12017
|
-
{ header: "started", path: "startedAt", format: "timestamp" },
|
|
12018
|
-
{ header: "status" },
|
|
12215
|
+
{ header: "started", path: "startedAt", format: "timestamp", minWidth: 19 },
|
|
12216
|
+
{ header: "status", minWidth: 9 },
|
|
12019
12217
|
{ header: "level" },
|
|
12020
|
-
{ header: "trigger" },
|
|
12021
|
-
{ header: "workflow", path: "workflow.name" },
|
|
12218
|
+
{ header: "trigger", minWidth: 12 },
|
|
12219
|
+
{ header: "workflow", path: "workflow.name", minWidth: 24 },
|
|
12022
12220
|
{ header: "duration", path: "totalDurationMs", format: "duration" },
|
|
12023
|
-
{ header: "cost", path: "cost.total", format: "cost" },
|
|
12024
|
-
{ header: "run", path: "runId" }
|
|
12221
|
+
{ header: "cost", path: "cost.total", format: "cost", minWidth: 8 },
|
|
12222
|
+
{ header: "run", path: "runId", minWidth: 36 }
|
|
12025
12223
|
]
|
|
12026
12224
|
},
|
|
12027
12225
|
getLog: {
|
|
@@ -12051,7 +12249,7 @@ var CLI_CONTRACT = {
|
|
|
12051
12249
|
},
|
|
12052
12250
|
getLogStats: {
|
|
12053
12251
|
command: "logs stats",
|
|
12054
|
-
describe: "Summarize run counts, failures
|
|
12252
|
+
describe: "Summarize run counts, failures and latency over a window",
|
|
12055
12253
|
flags: LOG_LIST_FILTER_FLAGS,
|
|
12056
12254
|
fields: [
|
|
12057
12255
|
{ header: "runs", path: "totalRuns" },
|
|
@@ -12379,7 +12577,7 @@ var CLI_CONTRACT = {
|
|
|
12379
12577
|
listCustomTools: {
|
|
12380
12578
|
columns: [
|
|
12381
12579
|
{ header: "id" },
|
|
12382
|
-
{ header: "
|
|
12580
|
+
{ header: "title", path: "title" },
|
|
12383
12581
|
{ header: "description", path: "schema.function.description" },
|
|
12384
12582
|
{ header: "updated", path: "updatedAt", format: "timestamp" }
|
|
12385
12583
|
]
|
|
@@ -12611,6 +12809,7 @@ var CLI_CONTRACT = {
|
|
|
12611
12809
|
]
|
|
12612
12810
|
},
|
|
12613
12811
|
listFileFolders: {
|
|
12812
|
+
describe: "List folders",
|
|
12614
12813
|
aliases: ["ls"],
|
|
12615
12814
|
flags: {
|
|
12616
12815
|
parentPath: { ...FOLDER_PATH_INPUT, name: "parent", describe: "Direct parent folder path" }
|
|
@@ -12618,6 +12817,7 @@ var CLI_CONTRACT = {
|
|
|
12618
12817
|
columns: FOLDER_LIST_COLUMNS
|
|
12619
12818
|
},
|
|
12620
12819
|
listKnowledgeFolders: {
|
|
12820
|
+
describe: "List knowledge folders",
|
|
12621
12821
|
aliases: ["ls"],
|
|
12622
12822
|
flags: {
|
|
12623
12823
|
parentPath: { ...FOLDER_PATH_INPUT, name: "parent", describe: "Direct parent folder path" }
|
|
@@ -12625,6 +12825,7 @@ var CLI_CONTRACT = {
|
|
|
12625
12825
|
columns: FOLDER_LIST_COLUMNS
|
|
12626
12826
|
},
|
|
12627
12827
|
listTableFolders: {
|
|
12828
|
+
describe: "List table folders",
|
|
12628
12829
|
aliases: ["ls"],
|
|
12629
12830
|
flags: {
|
|
12630
12831
|
parentPath: { ...FOLDER_PATH_INPUT, name: "parent", describe: "Direct parent folder path" }
|
|
@@ -12632,6 +12833,7 @@ var CLI_CONTRACT = {
|
|
|
12632
12833
|
columns: FOLDER_LIST_COLUMNS
|
|
12633
12834
|
},
|
|
12634
12835
|
listWorkflowFolders: {
|
|
12836
|
+
describe: "List workflow folders",
|
|
12635
12837
|
aliases: ["ls"],
|
|
12636
12838
|
flags: {
|
|
12637
12839
|
parentPath: { ...FOLDER_PATH_INPUT, name: "parent", describe: "Direct parent folder path" }
|
|
@@ -12769,6 +12971,23 @@ var CLI_CONTRACT = {
|
|
|
12769
12971
|
}
|
|
12770
12972
|
}
|
|
12771
12973
|
},
|
|
12974
|
+
listTableDispatches: {
|
|
12975
|
+
columns: [
|
|
12976
|
+
{ header: "id" },
|
|
12977
|
+
{ header: "status" },
|
|
12978
|
+
{ header: "mode" },
|
|
12979
|
+
{ header: "max rows", path: "limit.max" },
|
|
12980
|
+
{ header: "processed", path: "processedCount" },
|
|
12981
|
+
{ header: "manual", path: "isManualRun", format: "bool" },
|
|
12982
|
+
{ header: "requested", path: "requestedAt", format: "timestamp" },
|
|
12983
|
+
{ header: "completed", path: "completedAt", format: "timestamp" },
|
|
12984
|
+
{ header: "canceled", path: "canceledAt", format: "timestamp" },
|
|
12985
|
+
{ header: "groups", path: "scope.groupIds", format: "count" },
|
|
12986
|
+
{ header: "rows", path: "scope.rowIds", format: "count" },
|
|
12987
|
+
{ header: "filtered", path: "scope.filtered", format: "bool" },
|
|
12988
|
+
{ header: "excluded", path: "scope.excludeRowIds", format: "count" }
|
|
12989
|
+
]
|
|
12990
|
+
},
|
|
12772
12991
|
runRowEnrichment: {
|
|
12773
12992
|
command: "tables rows enrich",
|
|
12774
12993
|
describe: "Run one row’s enrichment group"
|
|
@@ -12777,8 +12996,16 @@ var CLI_CONTRACT = {
|
|
|
12777
12996
|
createTableImportPartUrls: { hidden: true },
|
|
12778
12997
|
completeTableImport: { hidden: true },
|
|
12779
12998
|
getTableImport: { flags: TRANSFER_TOKEN_OMITTED },
|
|
12780
|
-
cancelTableImport: {
|
|
12781
|
-
|
|
12999
|
+
cancelTableImport: {
|
|
13000
|
+
command: "tables imports cancel",
|
|
13001
|
+
flags: TRANSFER_TOKEN_OMITTED,
|
|
13002
|
+
describe: "Stop a running import",
|
|
13003
|
+
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."
|
|
13004
|
+
},
|
|
13005
|
+
cancelTableExport: {
|
|
13006
|
+
command: "tables exports cancel",
|
|
13007
|
+
describe: "Stop a running export"
|
|
13008
|
+
},
|
|
12782
13009
|
tableExportDownload: {
|
|
12783
13010
|
command: "tables exports download",
|
|
12784
13011
|
describe: "Get the download URL for a finished export"
|
|
@@ -12800,7 +13027,7 @@ var CLI_CONTRACT = {
|
|
|
12800
13027
|
selectedOutputs: {
|
|
12801
13028
|
name: "select-output",
|
|
12802
13029
|
list: true,
|
|
12803
|
-
describe: "Return blockName.field values (e.g. agent_1.content); missing fields are omitted"
|
|
13030
|
+
describe: "Return blockName.field values from the streamed result (e.g. agent_1.content), requires --follow; missing fields are omitted"
|
|
12804
13031
|
},
|
|
12805
13032
|
stream: { omit: true },
|
|
12806
13033
|
includeThinking: { omit: true },
|
|
@@ -12824,7 +13051,7 @@ var CLI_CONTRACT = {
|
|
|
12824
13051
|
selectedOutputs: {
|
|
12825
13052
|
name: "select-output",
|
|
12826
13053
|
list: true,
|
|
12827
|
-
describe: "Include
|
|
13054
|
+
describe: "Include blockId or blockId.path values in JSON or YAML output; block names are not resolved on a finished run"
|
|
12828
13055
|
}
|
|
12829
13056
|
},
|
|
12830
13057
|
fields: [
|
|
@@ -12931,11 +13158,20 @@ function camel(flag) {
|
|
|
12931
13158
|
}
|
|
12932
13159
|
|
|
12933
13160
|
// src/runtime/request.ts
|
|
13161
|
+
import { existsSync as existsSync2, readFileSync as readFileSync3, readSync } from "node:fs";
|
|
12934
13162
|
var PROFILE_INJECTED_FIELD = "workspaceId";
|
|
12935
13163
|
function isProfileWorkspacePath(commandSpec, param) {
|
|
12936
13164
|
return commandSpec.profileWorkspacePath === true && param === PROFILE_INJECTED_FIELD;
|
|
12937
13165
|
}
|
|
13166
|
+
function cursorSlot(operationSpec) {
|
|
13167
|
+
if (operationSpec.query && "cursor" in operationSpec.query)
|
|
13168
|
+
return "query";
|
|
13169
|
+
if (operationSpec.body && "cursor" in operationSpec.body)
|
|
13170
|
+
return "body";
|
|
13171
|
+
return null;
|
|
13172
|
+
}
|
|
12938
13173
|
var JSON_KINDS = new Set(["object", "array", "unknown"]);
|
|
13174
|
+
var NUMERIC_KINDS = new Set(["number", "integer"]);
|
|
12939
13175
|
function flagSpecFor(operation, field) {
|
|
12940
13176
|
return CLI_CONTRACT[operation]?.flags?.[field] ?? {};
|
|
12941
13177
|
}
|
|
@@ -13001,6 +13237,9 @@ function readStdin() {
|
|
|
13001
13237
|
}
|
|
13002
13238
|
return Buffer.concat(chunks).toString("utf8");
|
|
13003
13239
|
}
|
|
13240
|
+
function literalAtHint(error, path) {
|
|
13241
|
+
return error?.code === "ENOENT" ? `. To pass the literal value @${path}, write @@${path}` : "";
|
|
13242
|
+
}
|
|
13004
13243
|
function readArgumentSource(raw, flagName) {
|
|
13005
13244
|
if (raw.startsWith("@@"))
|
|
13006
13245
|
return { text: raw.slice(1), from: "" };
|
|
@@ -13020,7 +13259,7 @@ function readArgumentSource(raw, flagName) {
|
|
|
13020
13259
|
try {
|
|
13021
13260
|
return { text: readFileSync3(path, "utf8"), from: ` (read from ${path})` };
|
|
13022
13261
|
} catch (error) {
|
|
13023
|
-
throw new SimApiError(`--${flagName} cannot read ${path}: ${error.message}`, 0);
|
|
13262
|
+
throw new SimApiError(`--${flagName} cannot read ${path}: ${error.message}${literalAtHint(error, path)}`, 0);
|
|
13024
13263
|
}
|
|
13025
13264
|
}
|
|
13026
13265
|
function readListValues(raw, flagName) {
|
|
@@ -13073,6 +13312,7 @@ function encodeFolderPath(value) {
|
|
|
13073
13312
|
}
|
|
13074
13313
|
}).join("/");
|
|
13075
13314
|
}
|
|
13315
|
+
var FRACTIONAL_DIGITS = /\.\d*[1-9]/;
|
|
13076
13316
|
function pathHint(raw) {
|
|
13077
13317
|
if (raw.startsWith("@") || /^\s*[[{"\-\d]|^\s*(true|false|null)/.test(raw))
|
|
13078
13318
|
return "";
|
|
@@ -13097,10 +13337,16 @@ function coerce(raw, field, flag, flagName) {
|
|
|
13097
13337
|
throw new SimApiError(`--${flagName} must be valid JSON${source.from}: ${error.message}${pathHint(raw)}`, 0);
|
|
13098
13338
|
}
|
|
13099
13339
|
}
|
|
13100
|
-
if (
|
|
13340
|
+
if (NUMERIC_KINDS.has(field.kind)) {
|
|
13101
13341
|
const value = Number(raw);
|
|
13102
13342
|
if (Number.isNaN(value))
|
|
13103
13343
|
throw new SimApiError(`--${flagName} must be a number`, 0);
|
|
13344
|
+
if (field.kind === "integer" && (!Number.isInteger(value) || FRACTIONAL_DIGITS.test(String(raw)))) {
|
|
13345
|
+
throw new SimApiError(`--${flagName} must be a whole number`, 0);
|
|
13346
|
+
}
|
|
13347
|
+
if (field.kind === "integer" && !Number.isSafeInteger(value)) {
|
|
13348
|
+
throw new SimApiError(`--${flagName} is outside the whole-number range the API accepts (±${Number.MAX_SAFE_INTEGER})`, 0);
|
|
13349
|
+
}
|
|
13104
13350
|
return value;
|
|
13105
13351
|
}
|
|
13106
13352
|
if (field.kind === "boolean" || flag.boolean)
|
|
@@ -13113,6 +13359,7 @@ function coerce(raw, field, flag, flagName) {
|
|
|
13113
13359
|
return encodeFolderPath(raw);
|
|
13114
13360
|
return raw;
|
|
13115
13361
|
}
|
|
13362
|
+
var NO_WORKSPACE_FALLBACK = "No workspace set. Pass --workspace, or run: sim configure --set-workspace <id>";
|
|
13116
13363
|
function asQueryValue(value) {
|
|
13117
13364
|
if (value === null || value === undefined)
|
|
13118
13365
|
return;
|
|
@@ -13133,7 +13380,7 @@ function buildRequest(operation, positional, flags, workspaceId) {
|
|
|
13133
13380
|
const value = profileWorkspacePath ? workspaceId : pathFlag ? flags[camel(flagName)] : positional[positionalIndex++];
|
|
13134
13381
|
if (value === undefined || value === null) {
|
|
13135
13382
|
if (profileWorkspacePath) {
|
|
13136
|
-
throw new SimApiError(
|
|
13383
|
+
throw new SimApiError(NO_WORKSPACE_FALLBACK, 0);
|
|
13137
13384
|
}
|
|
13138
13385
|
throw new SimApiError(pathFlag ? `--${flagName} is required` : `Missing <${argumentName}>`, 0);
|
|
13139
13386
|
}
|
|
@@ -13145,6 +13392,7 @@ function buildRequest(operation, positional, flags, workspaceId) {
|
|
|
13145
13392
|
const query = {};
|
|
13146
13393
|
const body = {};
|
|
13147
13394
|
const headers = {};
|
|
13395
|
+
const paginatedLimit = cursorSlot(spec) !== null;
|
|
13148
13396
|
for (const slot of ["query", "body", "headers"]) {
|
|
13149
13397
|
for (const [field, descriptor] of Object.entries(spec[slot] ?? {})) {
|
|
13150
13398
|
const flag = flagSpecFor(operation, field);
|
|
@@ -13154,10 +13402,16 @@ function buildRequest(operation, positional, flags, workspaceId) {
|
|
|
13154
13402
|
const omitProfileWorkspace = commandSpec.allWorkspaces && flags.allWorkspaces === true;
|
|
13155
13403
|
const provided = field === PROFILE_INJECTED_FIELD ? omitProfileWorkspace ? undefined : workspaceId : flags[camel(flagName)];
|
|
13156
13404
|
const raw = provided ?? flag.requestDefault;
|
|
13405
|
+
if ((slot === "query" || NUMERIC_KINDS.has(descriptor.kind)) && typeof raw === "string" && raw.trim() === "" && !(field === "limit" && paginatedLimit)) {
|
|
13406
|
+
throw new SimApiError(`--${flagName} cannot be empty`, 0);
|
|
13407
|
+
}
|
|
13157
13408
|
const value = coerce(raw ?? undefined, descriptor, flag, flagName);
|
|
13409
|
+
if (field === "limit" && !paginatedLimit && NUMERIC_KINDS.has(descriptor.kind) && typeof value === "number" && value < 1) {
|
|
13410
|
+
throw new SimApiError(`--${flagName} must be 1 or more`, 0);
|
|
13411
|
+
}
|
|
13158
13412
|
if (value === undefined) {
|
|
13159
13413
|
if (descriptor.required) {
|
|
13160
|
-
throw new SimApiError(field === PROFILE_INJECTED_FIELD ?
|
|
13414
|
+
throw new SimApiError(field === PROFILE_INJECTED_FIELD ? NO_WORKSPACE_FALLBACK : `--${flagName} is required`, 0);
|
|
13161
13415
|
}
|
|
13162
13416
|
continue;
|
|
13163
13417
|
}
|
|
@@ -13204,6 +13458,126 @@ function buildRequest(operation, positional, flags, workspaceId) {
|
|
|
13204
13458
|
};
|
|
13205
13459
|
}
|
|
13206
13460
|
|
|
13461
|
+
// src/runtime/options.ts
|
|
13462
|
+
var DEFAULT_LIMIT = 100;
|
|
13463
|
+
function describeField(flag, descriptor, name, field) {
|
|
13464
|
+
return flag.describe ?? descriptor.describe ?? `Set ${name.replaceAll("-", " ") || field}`;
|
|
13465
|
+
}
|
|
13466
|
+
function literalNullHint(documented, name) {
|
|
13467
|
+
return /\bnull\b/i.test(documented) ? ` (--${name} null sends the word, not JSON null)` : "";
|
|
13468
|
+
}
|
|
13469
|
+
var WIRE_VOCABULARY_SENTENCE = /\s*The listed spellings[^.]*\.\s*/g;
|
|
13470
|
+
function withoutWireVocabulary(documented) {
|
|
13471
|
+
return documented.replace(WIRE_VOCABULARY_SENTENCE, " ").trim();
|
|
13472
|
+
}
|
|
13473
|
+
var NON_PAGINATED_LIMIT_HINT = " (caps a --filter match only; omit it to act on every match, and note 0 is not accepted)";
|
|
13474
|
+
function addFieldOption(command, operation, field, descriptor, slot, paginates) {
|
|
13475
|
+
if (field === PROFILE_INJECTED_FIELD || field === "cursor")
|
|
13476
|
+
return;
|
|
13477
|
+
const flag = flagSpecFor(operation, field);
|
|
13478
|
+
if (flag.omit)
|
|
13479
|
+
return;
|
|
13480
|
+
const name = flagNameFor(operation, field);
|
|
13481
|
+
const short = flag.short ? `-${flag.short}, ` : "";
|
|
13482
|
+
if (paginates && field === "limit" && (descriptor.kind === "number" || descriptor.kind === "integer")) {
|
|
13483
|
+
command.option("--limit <n>", "Maximum items to return (0 for everything)", String(DEFAULT_LIMIT));
|
|
13484
|
+
return;
|
|
13485
|
+
}
|
|
13486
|
+
const documented = `${describeField(flag, descriptor, name, field)}${field === "limit" && (descriptor.kind === "number" || descriptor.kind === "integer") ? NON_PAGINATED_LIMIT_HINT : ""}`;
|
|
13487
|
+
if (descriptor.kind === "boolean" || flag.boolean) {
|
|
13488
|
+
const booleanDoc = withoutWireVocabulary(documented);
|
|
13489
|
+
if (descriptor.required) {
|
|
13490
|
+
command.addOption(new Option(`${short}--${name} <true|false>`, `${booleanDoc} (required)`).choices(["true", "false"]).makeOptionMandatory());
|
|
13491
|
+
return;
|
|
13492
|
+
}
|
|
13493
|
+
command.option(`${short}--${name}`, booleanDoc);
|
|
13494
|
+
if (!flag.boolean || flag.negatable) {
|
|
13495
|
+
command.option(`--no-${name}`, `Send --${name} as false`);
|
|
13496
|
+
}
|
|
13497
|
+
return;
|
|
13498
|
+
}
|
|
13499
|
+
const takesList = flag.list === true;
|
|
13500
|
+
const wantsJson = takesJson(descriptor, flag);
|
|
13501
|
+
const placeholder = takesList ? "<value...>" : flag.rowCap ? "<n>" : wantsJson ? "<json|@file>" : "<value>";
|
|
13502
|
+
const choices = flag.choices ?? descriptor.values;
|
|
13503
|
+
const literalNull = slot === "body" && !takesList && !wantsJson;
|
|
13504
|
+
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) : ""}`;
|
|
13505
|
+
const renamedFrom = flag.renamedFrom ?? [];
|
|
13506
|
+
const option = new Option(`${short}--${name} ${placeholder}`, describe);
|
|
13507
|
+
if (flag.hidden)
|
|
13508
|
+
option.hideHelp();
|
|
13509
|
+
if (choices && !takesList)
|
|
13510
|
+
option.choices([...choices]);
|
|
13511
|
+
if (descriptor.default !== undefined && field !== "limit") {
|
|
13512
|
+
option.default(undefined, String(descriptor.default));
|
|
13513
|
+
}
|
|
13514
|
+
if (descriptor.required && renamedFrom.length === 0)
|
|
13515
|
+
option.makeOptionMandatory();
|
|
13516
|
+
command.addOption(option);
|
|
13517
|
+
for (const previous of renamedFrom) {
|
|
13518
|
+
const retired = new Option(`--${previous} ${placeholder}`).hideHelp();
|
|
13519
|
+
if (choices && !takesList)
|
|
13520
|
+
retired.choices([...choices]);
|
|
13521
|
+
command.addOption(retired);
|
|
13522
|
+
}
|
|
13523
|
+
}
|
|
13524
|
+
function addOperationOptions(command, operation, commandSpec, operationSpec) {
|
|
13525
|
+
for (const param of operationSpec.pathParams) {
|
|
13526
|
+
const flag = commandSpec.pathFlags?.[param];
|
|
13527
|
+
if (!flag)
|
|
13528
|
+
continue;
|
|
13529
|
+
const name = pathFlagNameFor(commandSpec, param);
|
|
13530
|
+
const short = flag.short ? `-${flag.short}, ` : "";
|
|
13531
|
+
command.addOption(new Option(`${short}--${name} <${flag.placeholder ?? "value"}>`, `${flag.describe ?? operationSpec.pathParamDocs?.[param] ?? `Set ${name.replaceAll("-", " ")}`} (required)`).makeOptionMandatory());
|
|
13532
|
+
}
|
|
13533
|
+
const paginates = cursorSlot(operationSpec) !== null;
|
|
13534
|
+
for (const slot of ["query", "body", "headers"]) {
|
|
13535
|
+
for (const [field, descriptor] of Object.entries(operationSpec[slot] ?? {})) {
|
|
13536
|
+
if (commandSpec.requestFields && !commandSpec.requestFields.includes(field))
|
|
13537
|
+
continue;
|
|
13538
|
+
if (commandSpec.positionals?.includes(field))
|
|
13539
|
+
continue;
|
|
13540
|
+
addFieldOption(command, operation, field, descriptor, slot, paginates);
|
|
13541
|
+
}
|
|
13542
|
+
}
|
|
13543
|
+
if (commandSpec.allWorkspaces) {
|
|
13544
|
+
command.option("--all-workspaces", "Do not filter to the configured workspace (personal API key required for account-wide access)");
|
|
13545
|
+
}
|
|
13546
|
+
if (commandSpec.expandedTrace) {
|
|
13547
|
+
command.option("--trace", "Show expanded trace spans with inputs, outputs, errors, timing, and cost");
|
|
13548
|
+
}
|
|
13549
|
+
if (operationSpec.opaqueBody) {
|
|
13550
|
+
if (commandSpec.bodyVariants) {
|
|
13551
|
+
for (const variant of commandSpec.bodyVariants) {
|
|
13552
|
+
command.option(`--${variant.name} <json|@file>`, `${variant.describe} (JSON, or @path / @-; choose exactly one body flag)`);
|
|
13553
|
+
}
|
|
13554
|
+
} else {
|
|
13555
|
+
command.requiredOption("--body <json|@file>", "Request body as JSON (or @path / @- to read a file or stdin) (required)");
|
|
13556
|
+
}
|
|
13557
|
+
}
|
|
13558
|
+
if (commandSpec.confirm) {
|
|
13559
|
+
const exemptedByDryRun = operationSpec.query?.dryRun !== undefined || operationSpec.body?.dryRun !== undefined;
|
|
13560
|
+
command.option("-y, --yes", exemptedByDryRun ? "Confirm this operation (required unless --dry-run)" : "Confirm this operation (required)");
|
|
13561
|
+
}
|
|
13562
|
+
}
|
|
13563
|
+
|
|
13564
|
+
// src/runtime/renamed.ts
|
|
13565
|
+
var warned = new Set;
|
|
13566
|
+
function warn(kind, from, to) {
|
|
13567
|
+
const key = `${kind}:${from}`;
|
|
13568
|
+
if (warned.has(key))
|
|
13569
|
+
return;
|
|
13570
|
+
warned.add(key);
|
|
13571
|
+
process.stderr.write(`warning: ${kind} "${from}" has been renamed to "${to}". The old name still works.
|
|
13572
|
+
`);
|
|
13573
|
+
}
|
|
13574
|
+
function warnRenamedCommand(from, to) {
|
|
13575
|
+
warn("command", `sim ${from}`, `sim ${to}`);
|
|
13576
|
+
}
|
|
13577
|
+
function warnRenamedFlag(from, to) {
|
|
13578
|
+
warn("flag", `--${from}`, `--${to}`);
|
|
13579
|
+
}
|
|
13580
|
+
|
|
13207
13581
|
// src/output/trace.ts
|
|
13208
13582
|
function traceSpan(value) {
|
|
13209
13583
|
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
@@ -13333,7 +13707,8 @@ function at(row, path) {
|
|
|
13333
13707
|
function decodeFolderPath(value) {
|
|
13334
13708
|
return value.split("/").map((segment) => {
|
|
13335
13709
|
try {
|
|
13336
|
-
|
|
13710
|
+
const decoded = decodeURIComponent(segment);
|
|
13711
|
+
return decoded.includes("/") ? segment : decoded;
|
|
13337
13712
|
} catch {
|
|
13338
13713
|
return segment;
|
|
13339
13714
|
}
|
|
@@ -13464,8 +13839,10 @@ function unwrapResource(data) {
|
|
|
13464
13839
|
const [, value] = entries[0];
|
|
13465
13840
|
return value && typeof value === "object" && !Array.isArray(value) ? value : data;
|
|
13466
13841
|
}
|
|
13467
|
-
function renderPage(format, rows, spec, envelope) {
|
|
13842
|
+
function renderPage(format, rows, spec, envelope, options = {}) {
|
|
13468
13843
|
writePageNote(spec, envelope);
|
|
13844
|
+
writeEnvelopeTruncation(envelope);
|
|
13845
|
+
writeCursorTruncation(rows.length, options.truncated === true);
|
|
13469
13846
|
printList(format, rows, spec.columns ? columnsFrom(spec.columns) : inferColumns(rows, spec.expand));
|
|
13470
13847
|
}
|
|
13471
13848
|
function writePageNote(spec, envelope) {
|
|
@@ -13477,7 +13854,48 @@ function writePageNote(spec, envelope) {
|
|
|
13477
13854
|
process.stderr.write(source_default.dim(`${spec.pageNote.label}: ${String(value)}
|
|
13478
13855
|
`));
|
|
13479
13856
|
}
|
|
13480
|
-
|
|
13857
|
+
var TRUNCATION_FLAG = /^truncated$|^[A-Za-z0-9]+Truncated$/;
|
|
13858
|
+
var NEGATED_TRUNCATION_FLAG = /^(?:not|un|non|never)Truncated$|(?:Not|Un|Non|Never)Truncated$/;
|
|
13859
|
+
function truncationFlags(container) {
|
|
13860
|
+
if (!container || typeof container !== "object" || Array.isArray(container))
|
|
13861
|
+
return [];
|
|
13862
|
+
return Object.entries(container).filter(([key, value]) => value === true && TRUNCATION_FLAG.test(key) && !NEGATED_TRUNCATION_FLAG.test(key)).map(([key]) => key);
|
|
13863
|
+
}
|
|
13864
|
+
function responseTruncationFlags(envelope) {
|
|
13865
|
+
return [...truncationFlags(envelope), ...truncationFlags(at(envelope, "data"))];
|
|
13866
|
+
}
|
|
13867
|
+
function foldPageEnvelope(current, page) {
|
|
13868
|
+
if (current === undefined)
|
|
13869
|
+
return page;
|
|
13870
|
+
const raised = truncationFlags(page);
|
|
13871
|
+
if (raised.length === 0 || !current || typeof current !== "object")
|
|
13872
|
+
return current;
|
|
13873
|
+
return {
|
|
13874
|
+
...current,
|
|
13875
|
+
...Object.fromEntries(raised.map((flag) => [flag, true]))
|
|
13876
|
+
};
|
|
13877
|
+
}
|
|
13878
|
+
function spellOut(flag) {
|
|
13879
|
+
return flag.replace(/([a-z])([A-Z])/g, "$1 $2").toLowerCase().trim();
|
|
13880
|
+
}
|
|
13881
|
+
function clippedSubject(flag) {
|
|
13882
|
+
const subject = flag.replace(/^truncated$|Truncated$/, "").replace(/^is(?=[A-Z]|$)/, "");
|
|
13883
|
+
return subject ? `the ${spellOut(subject)} it returned` : "this result";
|
|
13884
|
+
}
|
|
13885
|
+
function writeEnvelopeTruncation(envelope) {
|
|
13886
|
+
for (const flag of responseTruncationFlags(envelope)) {
|
|
13887
|
+
process.stderr.write(source_default.dim(`${spellOut(flag)}: the server clipped ${clippedSubject(flag)}, so the answer is incomplete
|
|
13888
|
+
`));
|
|
13889
|
+
}
|
|
13890
|
+
}
|
|
13891
|
+
function writeCursorTruncation(count, truncated) {
|
|
13892
|
+
if (!truncated)
|
|
13893
|
+
return;
|
|
13894
|
+
process.stderr.write(source_default.dim(`showing the first ${count}; more results exist — re-run with --limit 0 for all
|
|
13895
|
+
`));
|
|
13896
|
+
}
|
|
13897
|
+
function renderResult(operation, format, raw, spec, options = {}, envelope) {
|
|
13898
|
+
writeEnvelopeTruncation(envelope);
|
|
13481
13899
|
if (spec.document) {
|
|
13482
13900
|
printDocument(format, raw);
|
|
13483
13901
|
return;
|
|
@@ -13509,26 +13927,598 @@ function renderResult(operation, format, raw, spec, options = {}) {
|
|
|
13509
13927
|
}
|
|
13510
13928
|
}
|
|
13511
13929
|
|
|
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
|
-
]
|
|
13930
|
+
// src/runtime/execute.ts
|
|
13931
|
+
var RUN_OUTCOME_OPERATIONS = new Set(["executeWorkflow"]);
|
|
13932
|
+
var FAILED_RUN_STATUS_MESSAGES = {
|
|
13933
|
+
failed: "The workflow run failed.",
|
|
13934
|
+
cancelled: "The workflow run was cancelled."
|
|
13527
13935
|
};
|
|
13528
|
-
function
|
|
13529
|
-
|
|
13530
|
-
|
|
13531
|
-
|
|
13936
|
+
function runFailureMessage(operation, payload) {
|
|
13937
|
+
if (!RUN_OUTCOME_OPERATIONS.has(operation))
|
|
13938
|
+
return null;
|
|
13939
|
+
if (!payload || typeof payload !== "object" || Array.isArray(payload))
|
|
13940
|
+
return null;
|
|
13941
|
+
const { status, error } = payload;
|
|
13942
|
+
if (typeof status !== "string")
|
|
13943
|
+
return null;
|
|
13944
|
+
const fallback = FAILED_RUN_STATUS_MESSAGES[status];
|
|
13945
|
+
if (!fallback)
|
|
13946
|
+
return null;
|
|
13947
|
+
const reported2 = error?.message;
|
|
13948
|
+
return safeOneLine(typeof reported2 === "string" && reported2 ? reported2 : fallback);
|
|
13949
|
+
}
|
|
13950
|
+
var BULK_OUTCOME_CHECKS = {
|
|
13951
|
+
bulkDeleteFiles: (payload, body) => {
|
|
13952
|
+
if (countOf(payload.deletedItems?.files) > 0)
|
|
13953
|
+
return null;
|
|
13954
|
+
const requested = lengthOf(body?.fileIds);
|
|
13955
|
+
if (requested === 0)
|
|
13956
|
+
return null;
|
|
13957
|
+
return `Deleted nothing: none of the ${requested} requested ${requested === 1 ? "file was" : "files were"} deleted.`;
|
|
13958
|
+
},
|
|
13959
|
+
addWorkspaceFilesToKnowledgeBase: (payload) => {
|
|
13960
|
+
if (lengthOf(payload.added) > 0)
|
|
13961
|
+
return null;
|
|
13962
|
+
const failed = lengthOf(payload.failed);
|
|
13963
|
+
if (failed === 0)
|
|
13964
|
+
return null;
|
|
13965
|
+
return `Indexed nothing: none of the ${failed} requested ${failed === 1 ? "file was" : "files were"} added.`;
|
|
13966
|
+
},
|
|
13967
|
+
bulkDeleteTables: (payload) => {
|
|
13968
|
+
const items = payload.deletedItems;
|
|
13969
|
+
const deleted = countOf(items?.tables) + countOf(items?.folders);
|
|
13970
|
+
if (deleted > 0)
|
|
13971
|
+
return null;
|
|
13972
|
+
const missed = lengthOf(payload.notFound) + lengthOf(payload.failed);
|
|
13973
|
+
if (missed === 0)
|
|
13974
|
+
return null;
|
|
13975
|
+
return `Deleted nothing: ${missed} of ${missed} ${missed === 1 ? "item was" : "items were"} not found or could not be deleted.`;
|
|
13976
|
+
},
|
|
13977
|
+
bulkUpdateKnowledgeChunks: (payload, body) => {
|
|
13978
|
+
if (countOf(payload.processed) > 0)
|
|
13979
|
+
return null;
|
|
13980
|
+
const requested = lengthOf(body?.chunkIds);
|
|
13981
|
+
if (requested === 0)
|
|
13982
|
+
return null;
|
|
13983
|
+
const reported2 = payload.errors?.[0];
|
|
13984
|
+
return typeof reported2 === "string" && reported2 ? safeOneLine(reported2) : `Updated nothing: none of the ${requested} requested ${requested === 1 ? "chunk" : "chunks"} matched.`;
|
|
13985
|
+
},
|
|
13986
|
+
moveTables: (payload) => {
|
|
13987
|
+
if (lengthOf(payload.moved) > 0)
|
|
13988
|
+
return null;
|
|
13989
|
+
const missed = lengthOf(payload.notFound) + lengthOf(payload.failed);
|
|
13990
|
+
if (missed === 0)
|
|
13991
|
+
return null;
|
|
13992
|
+
return `Moved nothing: ${missed} of ${missed} ${missed === 1 ? "item was" : "items were"} not found or could not be moved.`;
|
|
13993
|
+
},
|
|
13994
|
+
moveWorkflows: (payload) => {
|
|
13995
|
+
if (lengthOf(payload.moved) > 0)
|
|
13996
|
+
return null;
|
|
13997
|
+
const failed = lengthOf(payload.failed);
|
|
13998
|
+
if (failed === 0)
|
|
13999
|
+
return null;
|
|
14000
|
+
return `Moved nothing: ${failed} of ${failed} ${failed === 1 ? "workflow" : "workflows"} could not be moved.`;
|
|
14001
|
+
}
|
|
14002
|
+
};
|
|
14003
|
+
function countOf(value) {
|
|
14004
|
+
return typeof value === "number" && Number.isFinite(value) ? value : 0;
|
|
14005
|
+
}
|
|
14006
|
+
function lengthOf(value) {
|
|
14007
|
+
return Array.isArray(value) ? value.length : 0;
|
|
14008
|
+
}
|
|
14009
|
+
function bulkFailureMessage(operation, payload, body) {
|
|
14010
|
+
const check = BULK_OUTCOME_CHECKS[operation];
|
|
14011
|
+
if (!check)
|
|
14012
|
+
return null;
|
|
14013
|
+
if (!payload || typeof payload !== "object" || Array.isArray(payload))
|
|
14014
|
+
return null;
|
|
14015
|
+
return check(payload, body);
|
|
14016
|
+
}
|
|
14017
|
+
var EXCLUSIVE_CAP_FIELDS = {
|
|
14018
|
+
deleteTableRows: { cap: "limit", ids: "rowIds" }
|
|
14019
|
+
};
|
|
14020
|
+
function readPagedLimit(raw) {
|
|
14021
|
+
const text2 = String(raw ?? DEFAULT_LIMIT).trim();
|
|
14022
|
+
const value = text2 === "" ? Number.NaN : Number(text2);
|
|
14023
|
+
if (!Number.isInteger(value) || value < 0) {
|
|
14024
|
+
throw new SimApiError("--limit must be a whole number of 0 or more (0 for everything)", 0);
|
|
14025
|
+
}
|
|
14026
|
+
return value;
|
|
14027
|
+
}
|
|
14028
|
+
function assertCapIsUsable(operation, flags) {
|
|
14029
|
+
const exclusive = EXCLUSIVE_CAP_FIELDS[operation];
|
|
14030
|
+
if (!exclusive)
|
|
14031
|
+
return;
|
|
14032
|
+
const cap = flagNameFor(operation, exclusive.cap);
|
|
14033
|
+
const ids = flagNameFor(operation, exclusive.ids);
|
|
14034
|
+
if (flags[camel(cap)] === undefined || flags[camel(ids)] === undefined)
|
|
14035
|
+
return;
|
|
14036
|
+
throw new SimApiError(`--${cap} caps a --filter match and does nothing to an explicit --${ids} list; pass one, not both`, 0);
|
|
14037
|
+
}
|
|
14038
|
+
var REQUIRED_SELECTORS = {
|
|
14039
|
+
deleteTableRows: { fields: ["filter", "rowIds"], noun: "rows to delete" }
|
|
14040
|
+
};
|
|
14041
|
+
function assertSelectorIsUsable(operation, flags) {
|
|
14042
|
+
const selector = REQUIRED_SELECTORS[operation];
|
|
14043
|
+
if (!selector)
|
|
14044
|
+
return;
|
|
14045
|
+
const [first, second] = selector.fields.map((field) => flagNameFor(operation, field));
|
|
14046
|
+
const given = [first, second].filter((name) => flags[camel(name)] !== undefined);
|
|
14047
|
+
if (given.length === 1)
|
|
14048
|
+
return;
|
|
14049
|
+
throw new SimApiError(given.length === 0 ? `--${first} or --${second} is required to choose the ${selector.noun}` : `--${first} and --${second} choose the ${selector.noun} two different ways; pass one, not both`, 0);
|
|
14050
|
+
}
|
|
14051
|
+
function foldRenamedFlags(operation, commandSpec, flags) {
|
|
14052
|
+
for (const [field, flag] of Object.entries(commandSpec.flags ?? {})) {
|
|
14053
|
+
if (!flag.renamedFrom?.length)
|
|
14054
|
+
continue;
|
|
14055
|
+
const current = flagNameFor(operation, field);
|
|
14056
|
+
for (const previous of flag.renamedFrom) {
|
|
14057
|
+
const supplied = flags[camel(previous)];
|
|
14058
|
+
if (supplied === undefined)
|
|
14059
|
+
continue;
|
|
14060
|
+
if (flags[camel(current)] !== undefined) {
|
|
14061
|
+
throw new SimApiError(`--${previous} is the former name of --${current}; pass one, not both`, 0);
|
|
14062
|
+
}
|
|
14063
|
+
warnRenamedFlag(previous, current);
|
|
14064
|
+
flags[camel(current)] = supplied;
|
|
14065
|
+
}
|
|
14066
|
+
}
|
|
14067
|
+
}
|
|
14068
|
+
async function executeOperation(operation, commandSpec, operationSpec, invocation) {
|
|
14069
|
+
const host = invocation[invocation.length - 1];
|
|
14070
|
+
const inheritedFlags = host.optsWithGlobals();
|
|
14071
|
+
const flags = {
|
|
14072
|
+
...inheritedFlags.workspace === undefined ? {} : { workspace: inheritedFlags.workspace },
|
|
14073
|
+
...inheritedFlags.allWorkspaces === undefined ? {} : { allWorkspaces: inheritedFlags.allWorkspaces },
|
|
14074
|
+
...invocation[invocation.length - 2]
|
|
14075
|
+
};
|
|
14076
|
+
const pathPositionalCount = operationSpec.pathParams.filter((param) => !commandSpec.pathFlags?.[param] && !isProfileWorkspacePath(commandSpec, param)).length;
|
|
14077
|
+
const positional = invocation.slice(0, pathPositionalCount);
|
|
14078
|
+
const requestFlags = { ...flags };
|
|
14079
|
+
for (const [index, field] of (commandSpec.positionals ?? []).entries()) {
|
|
14080
|
+
requestFlags[camel(flagNameFor(operation, field))] = invocation[pathPositionalCount + index];
|
|
14081
|
+
}
|
|
14082
|
+
foldRenamedFlags(operation, commandSpec, requestFlags);
|
|
14083
|
+
assertCapIsUsable(operation, requestFlags);
|
|
14084
|
+
assertSelectorIsUsable(operation, requestFlags);
|
|
14085
|
+
if (commandSpec.confirm && !requestFlags.yes && requestFlags.dryRun !== true) {
|
|
14086
|
+
throw new SimApiError(`${commandSpec.confirm} Re-run with --yes to confirm.`, 0);
|
|
14087
|
+
}
|
|
14088
|
+
if (commandSpec.allWorkspaces && requestFlags.allWorkspaces && requestFlags.workspace) {
|
|
14089
|
+
throw new SimApiError("--all-workspaces cannot be combined with --workspace", 0);
|
|
14090
|
+
}
|
|
14091
|
+
const { client, profile } = clientFrom(host);
|
|
14092
|
+
const hasWorkspaceField = Boolean(operationSpec.query && PROFILE_INJECTED_FIELD in operationSpec.query || operationSpec.body && PROFILE_INJECTED_FIELD in operationSpec.body);
|
|
14093
|
+
const omitsWorkspace = commandSpec.allWorkspaces && requestFlags.allWorkspaces === true;
|
|
14094
|
+
const needsWorkspace = (hasWorkspaceField || commandSpec.profileWorkspacePath === true) && !omitsWorkspace;
|
|
14095
|
+
const paging = cursorSlot(operationSpec);
|
|
14096
|
+
const pagedLimit = paging ? readPagedLimit(requestFlags.limit) : 0;
|
|
14097
|
+
const request = buildRequest(operation, positional, requestFlags, needsWorkspace ? client.requireWorkspace() : profile.workspaceId);
|
|
14098
|
+
if (paging) {
|
|
14099
|
+
const limit = pagedLimit === 0 ? Number.POSITIVE_INFINITY : pagedLimit;
|
|
14100
|
+
const pageSize = Math.min(Number.isFinite(limit) ? limit : DEFAULT_LIMIT, DEFAULT_LIMIT);
|
|
14101
|
+
const pageLimit = "limit" in (operationSpec[paging] ?? {}) ? { limit: pageSize } : {};
|
|
14102
|
+
const rows = [];
|
|
14103
|
+
const progress = pageProgress();
|
|
14104
|
+
let cursor = null;
|
|
14105
|
+
let envelope;
|
|
14106
|
+
try {
|
|
14107
|
+
do {
|
|
14108
|
+
const page = await client.request(request.path, {
|
|
14109
|
+
method: operationSpec.method,
|
|
14110
|
+
headers: request.headers,
|
|
14111
|
+
query: paging === "query" ? { ...request.query, ...pageLimit, cursor } : request.query,
|
|
14112
|
+
body: paging === "body" ? { ...request.body ?? {}, ...pageLimit, ...cursor ? { cursor } : {} } : request.body
|
|
14113
|
+
});
|
|
14114
|
+
envelope = foldPageEnvelope(envelope, page);
|
|
14115
|
+
rows.push(...page.data);
|
|
14116
|
+
cursor = page.nextCursor;
|
|
14117
|
+
if (cursor && rows.length < limit)
|
|
14118
|
+
progress.advance(rows.length);
|
|
14119
|
+
} while (cursor && rows.length < limit);
|
|
14120
|
+
} finally {
|
|
14121
|
+
progress.finish();
|
|
14122
|
+
}
|
|
14123
|
+
renderPage(profile.output, Number.isFinite(limit) ? rows.slice(0, limit) : rows, commandSpec, envelope, { truncated: Boolean(cursor) });
|
|
14124
|
+
return;
|
|
14125
|
+
}
|
|
14126
|
+
const result = await client.request(request.path, {
|
|
14127
|
+
method: operationSpec.method,
|
|
14128
|
+
headers: request.headers,
|
|
14129
|
+
query: request.query,
|
|
14130
|
+
body: request.body
|
|
14131
|
+
});
|
|
14132
|
+
const payload = result?.data ?? result;
|
|
14133
|
+
renderResult(operation, profile.output, payload, commandSpec, { expandedTrace: requestFlags.trace === true }, result);
|
|
14134
|
+
const failure = runFailureMessage(operation, payload) ?? bulkFailureMessage(operation, payload, request.body);
|
|
14135
|
+
if (failure)
|
|
14136
|
+
throw new SimApiError(failure, 0);
|
|
14137
|
+
}
|
|
14138
|
+
|
|
14139
|
+
// src/runtime/naming.ts
|
|
14140
|
+
var WIRE_IDENTIFIER = /^[a-z]+[A-Z]/;
|
|
14141
|
+
function spellingFor(operation, commandSpec, operationSpec, field) {
|
|
14142
|
+
if (field === PROFILE_INJECTED_FIELD)
|
|
14143
|
+
return "--workspace";
|
|
14144
|
+
if (field === "cursor")
|
|
14145
|
+
return null;
|
|
14146
|
+
if (operationSpec.pathParams.includes(field)) {
|
|
14147
|
+
return commandSpec.pathFlags?.[field] ? `--${pathFlagNameFor(commandSpec, field)}` : `<${commandSpec.pathArgumentNames?.[field] ?? field}>`;
|
|
14148
|
+
}
|
|
14149
|
+
if (commandSpec.positionals?.includes(field))
|
|
14150
|
+
return `<${flagNameFor(operation, field)}>`;
|
|
14151
|
+
if (flagSpecFor(operation, field).omit)
|
|
14152
|
+
return null;
|
|
14153
|
+
if (commandSpec.requestFields && !commandSpec.requestFields.includes(field))
|
|
14154
|
+
return null;
|
|
14155
|
+
const declared = operationSpec.query && field in operationSpec.query || operationSpec.body && field in operationSpec.body || operationSpec.headers && field in operationSpec.headers;
|
|
14156
|
+
if (!declared)
|
|
14157
|
+
return null;
|
|
14158
|
+
return `--${flagNameFor(operation, field)}`;
|
|
14159
|
+
}
|
|
14160
|
+
function typeableFields(operation, commandSpec, operationSpec) {
|
|
14161
|
+
const spellings = new Map;
|
|
14162
|
+
const fields = [
|
|
14163
|
+
...operationSpec.pathParams,
|
|
14164
|
+
...Object.keys(operationSpec.query ?? {}),
|
|
14165
|
+
...Object.keys(operationSpec.body ?? {}),
|
|
14166
|
+
...Object.keys(operationSpec.headers ?? {})
|
|
14167
|
+
];
|
|
14168
|
+
for (const field of fields) {
|
|
14169
|
+
if (spellings.has(field))
|
|
14170
|
+
continue;
|
|
14171
|
+
const spelling = spellingFor(operation, commandSpec, operationSpec, field);
|
|
14172
|
+
if (spelling)
|
|
14173
|
+
spellings.set(field, spelling);
|
|
14174
|
+
}
|
|
14175
|
+
return spellings;
|
|
14176
|
+
}
|
|
14177
|
+
function retypeMessage(message, spellings) {
|
|
14178
|
+
let retyped = message;
|
|
14179
|
+
for (const [field, spelling] of spellings) {
|
|
14180
|
+
if (!WIRE_IDENTIFIER.test(field))
|
|
14181
|
+
continue;
|
|
14182
|
+
retyped = retyped.replaceAll(new RegExp(`\\b${field}\\b`, "g"), spelling);
|
|
14183
|
+
}
|
|
14184
|
+
if (retyped === message)
|
|
14185
|
+
return message;
|
|
14186
|
+
for (const field of spellings.keys()) {
|
|
14187
|
+
if (WIRE_IDENTIFIER.test(field))
|
|
14188
|
+
continue;
|
|
14189
|
+
if (new RegExp(`\\b${field}\\b`).test(message))
|
|
14190
|
+
return message;
|
|
14191
|
+
}
|
|
14192
|
+
return retyped;
|
|
14193
|
+
}
|
|
14194
|
+
function retypeDetails(details, spellings) {
|
|
14195
|
+
if (Array.isArray(details))
|
|
14196
|
+
return details.map((issue2) => retypeDetails(issue2, spellings));
|
|
14197
|
+
if (!details || typeof details !== "object")
|
|
14198
|
+
return details;
|
|
14199
|
+
const issue = details;
|
|
14200
|
+
const retyped = { ...issue };
|
|
14201
|
+
if (Array.isArray(issue.path) && issue.path.length > 0) {
|
|
14202
|
+
const [head, ...rest] = issue.path.map(String);
|
|
14203
|
+
const spelling = spellings.get(head);
|
|
14204
|
+
if (spelling)
|
|
14205
|
+
retyped.path = [spelling, ...rest];
|
|
14206
|
+
}
|
|
14207
|
+
if (typeof issue.message === "string") {
|
|
14208
|
+
retyped.message = retypeMessage(issue.message, spellings);
|
|
14209
|
+
}
|
|
14210
|
+
if (Array.isArray(issue.errors)) {
|
|
14211
|
+
retyped.errors = retypeDetails(issue.errors, spellings);
|
|
14212
|
+
}
|
|
14213
|
+
return retyped;
|
|
14214
|
+
}
|
|
14215
|
+
function retypeApiError(error, operation, commandSpec, operationSpec) {
|
|
14216
|
+
if (!(error instanceof SimApiError) || error.status === 0)
|
|
14217
|
+
return error;
|
|
14218
|
+
const spellings = typeableFields(operation, commandSpec, operationSpec);
|
|
14219
|
+
if (spellings.size === 0)
|
|
14220
|
+
return error;
|
|
14221
|
+
return new SimApiError(retypeMessage(error.message, spellings), error.status, error.code, error.details === undefined ? undefined : retypeDetails(error.details, spellings));
|
|
14222
|
+
}
|
|
14223
|
+
|
|
14224
|
+
// src/runtime/build.ts
|
|
14225
|
+
var GROUP_ALIASES = {
|
|
14226
|
+
"audit-logs": "audit-log",
|
|
14227
|
+
credentials: "credential",
|
|
14228
|
+
"custom-tools": "custom-tool",
|
|
14229
|
+
files: "file",
|
|
14230
|
+
knowledge: "kb",
|
|
14231
|
+
logs: "log",
|
|
14232
|
+
"mcp-servers": "mcp-server",
|
|
14233
|
+
secrets: "secret",
|
|
14234
|
+
skills: "skill",
|
|
14235
|
+
tables: "table",
|
|
14236
|
+
workflows: "workflow",
|
|
14237
|
+
workspaces: "workspace"
|
|
14238
|
+
};
|
|
14239
|
+
function describeOperation(operationSpec, described) {
|
|
14240
|
+
return operationSpec.personalKeyOnly ? `${described} (personal API key required)` : described;
|
|
14241
|
+
}
|
|
14242
|
+
function argumentSyntax(command) {
|
|
14243
|
+
return command.registeredArguments.map((argument) => {
|
|
14244
|
+
const name = `${argument.name()}${argument.variadic ? "..." : ""}`;
|
|
14245
|
+
return argument.required ? `<${name}>` : `[${name}]`;
|
|
14246
|
+
}).join(" ");
|
|
14247
|
+
}
|
|
14248
|
+
function commandPath(command) {
|
|
14249
|
+
const names = [];
|
|
14250
|
+
let current = command;
|
|
14251
|
+
while (current) {
|
|
14252
|
+
names.unshift(current.name());
|
|
14253
|
+
current = current.parent;
|
|
14254
|
+
}
|
|
14255
|
+
return names.join(" ");
|
|
14256
|
+
}
|
|
14257
|
+
function addMissingArgumentExample(command) {
|
|
14258
|
+
const outputError = command.configureOutput().outputError;
|
|
14259
|
+
if (!outputError)
|
|
14260
|
+
throw new Error("Commander output formatter is not configured");
|
|
14261
|
+
command.configureOutput({
|
|
14262
|
+
outputError: (message, write) => {
|
|
14263
|
+
outputError(message, write);
|
|
14264
|
+
if (!message.startsWith("error: missing required argument "))
|
|
14265
|
+
return;
|
|
14266
|
+
const syntax = argumentSyntax(command);
|
|
14267
|
+
const example = syntax ? `${commandPath(command)} ${syntax}` : commandPath(command);
|
|
14268
|
+
write(`Example: ${example}
|
|
14269
|
+
`);
|
|
14270
|
+
}
|
|
14271
|
+
});
|
|
14272
|
+
return command;
|
|
14273
|
+
}
|
|
14274
|
+
function assertNoReservedFlags(command, operation) {
|
|
14275
|
+
for (const option of command.options) {
|
|
14276
|
+
for (const flag of [option.long, option.short]) {
|
|
14277
|
+
if (flag && RESERVED_PROGRAM_FLAGS.has(flag)) {
|
|
14278
|
+
throw new Error(`${operation} declares ${flag}, which the root program already owns; give the flag another name`);
|
|
14279
|
+
}
|
|
14280
|
+
}
|
|
14281
|
+
}
|
|
14282
|
+
}
|
|
14283
|
+
var RESERVED_FLAG_EXEMPTIONS = new Set(["profiles add"]);
|
|
14284
|
+
function assertNoReservedProgramFlags(program2) {
|
|
14285
|
+
const walk = (command, prefix) => {
|
|
14286
|
+
const path = [...prefix, command.name()];
|
|
14287
|
+
const name = path.join(" ");
|
|
14288
|
+
if (!RESERVED_FLAG_EXEMPTIONS.has(name)) {
|
|
14289
|
+
for (const option of command.options) {
|
|
14290
|
+
for (const flag of [option.long, option.short]) {
|
|
14291
|
+
if (flag && RESERVED_PROGRAM_FLAGS.has(flag)) {
|
|
14292
|
+
throw new Error(`"sim ${name}" declares ${flag}, which the root program already owns; give the flag another name`);
|
|
14293
|
+
}
|
|
14294
|
+
}
|
|
14295
|
+
}
|
|
14296
|
+
}
|
|
14297
|
+
for (const child of command.commands)
|
|
14298
|
+
walk(child, path);
|
|
14299
|
+
};
|
|
14300
|
+
for (const child of program2.commands)
|
|
14301
|
+
walk(child, []);
|
|
14302
|
+
}
|
|
14303
|
+
function refuseHelpAfterUnknownCommand(program2) {
|
|
14304
|
+
const walk = (command) => {
|
|
14305
|
+
const internals = command;
|
|
14306
|
+
const dispatchesOnly = command.commands.length > 0 && !internals._actionHandler && command.registeredArguments.length === 0;
|
|
14307
|
+
if (dispatchesOnly) {
|
|
14308
|
+
const known = new Set(["help"]);
|
|
14309
|
+
for (const child of command.commands) {
|
|
14310
|
+
known.add(child.name());
|
|
14311
|
+
for (const alias of child.aliases())
|
|
14312
|
+
known.add(alias);
|
|
14313
|
+
}
|
|
14314
|
+
command.on("beforeHelp", () => {
|
|
14315
|
+
const first = command.args[0];
|
|
14316
|
+
if (first === undefined || first.startsWith("-") || known.has(first))
|
|
14317
|
+
return;
|
|
14318
|
+
internals.unknownCommand();
|
|
14319
|
+
});
|
|
14320
|
+
}
|
|
14321
|
+
for (const child of command.commands)
|
|
14322
|
+
walk(child);
|
|
14323
|
+
};
|
|
14324
|
+
walk(program2);
|
|
14325
|
+
}
|
|
14326
|
+
function configureOperation(command, operation, spec) {
|
|
14327
|
+
const operationSpec = V2_OPERATIONS[operation];
|
|
14328
|
+
command.allowExcessArguments(false);
|
|
14329
|
+
for (const alias of spec.aliases ?? [])
|
|
14330
|
+
command.alias(alias);
|
|
14331
|
+
for (const param of Object.keys(spec.pathFlags ?? {})) {
|
|
14332
|
+
if (!operationSpec.pathParams.includes(param)) {
|
|
14333
|
+
throw new Error(`${operation}.${param} is not a path parameter`);
|
|
14334
|
+
}
|
|
14335
|
+
}
|
|
14336
|
+
for (const param of Object.keys(spec.pathArgumentNames ?? {})) {
|
|
14337
|
+
if (!operationSpec.pathParams.includes(param)) {
|
|
14338
|
+
throw new Error(`${operation}.${param} is not a path parameter`);
|
|
14339
|
+
}
|
|
14340
|
+
if (spec.pathFlags?.[param]) {
|
|
14341
|
+
throw new Error(`${operation}.${param} cannot be both a path argument and a path flag`);
|
|
14342
|
+
}
|
|
14343
|
+
}
|
|
14344
|
+
if (spec.profileWorkspacePath) {
|
|
14345
|
+
if (!operationSpec.pathParams.includes(PROFILE_INJECTED_FIELD)) {
|
|
14346
|
+
throw new Error(`${operation}.profileWorkspacePath requires a workspaceId path parameter`);
|
|
14347
|
+
}
|
|
14348
|
+
if (spec.pathFlags?.[PROFILE_INJECTED_FIELD]) {
|
|
14349
|
+
throw new Error(`${operation}.workspaceId cannot be both profile-injected and a path flag`);
|
|
14350
|
+
}
|
|
14351
|
+
}
|
|
14352
|
+
for (const param of operationSpec.pathParams) {
|
|
14353
|
+
if (spec.pathFlags?.[param] || isProfileWorkspacePath(spec, param))
|
|
14354
|
+
continue;
|
|
14355
|
+
command.argument(`<${spec.pathArgumentNames?.[param] ?? param}>`, operationSpec.pathParamDocs?.[param]);
|
|
14356
|
+
}
|
|
14357
|
+
if (spec.allWorkspaces) {
|
|
14358
|
+
const workspace = operationSpec.query?.workspaceId ?? operationSpec.body?.workspaceId;
|
|
14359
|
+
if (!workspace || workspace.required) {
|
|
14360
|
+
throw new Error(`${operation}.allWorkspaces requires an optional workspaceId field`);
|
|
14361
|
+
}
|
|
14362
|
+
}
|
|
14363
|
+
for (const field of spec.positionals ?? []) {
|
|
14364
|
+
const descriptor = operationSpec.query?.[field] ?? operationSpec.body?.[field];
|
|
14365
|
+
if (!descriptor)
|
|
14366
|
+
throw new Error(`${operation}.${field} is not a request field`);
|
|
14367
|
+
if (spec.requestFields && !spec.requestFields.includes(field)) {
|
|
14368
|
+
throw new Error(`${operation}.${field} is positional but not exposed`);
|
|
14369
|
+
}
|
|
14370
|
+
command.argument(`<${flagNameFor(operation, field)}>`, flagSpecFor(operation, field).describe ?? descriptor.describe);
|
|
14371
|
+
}
|
|
14372
|
+
if (spec.requestFields) {
|
|
14373
|
+
for (const field of spec.requestFields) {
|
|
14374
|
+
if (!operationSpec.query?.[field] && !operationSpec.body?.[field] && !operationSpec.headers?.[field]) {
|
|
14375
|
+
throw new Error(`${operation}.${field} is not a request field`);
|
|
14376
|
+
}
|
|
14377
|
+
}
|
|
14378
|
+
for (const slot of ["query", "body", "headers"]) {
|
|
14379
|
+
for (const [field, descriptor] of Object.entries(operationSpec[slot] ?? {})) {
|
|
14380
|
+
if (descriptor.required && field !== PROFILE_INJECTED_FIELD && !spec.requestFields.includes(field)) {
|
|
14381
|
+
throw new Error(`${operation}.${field} is required but not exposed`);
|
|
14382
|
+
}
|
|
14383
|
+
}
|
|
14384
|
+
}
|
|
14385
|
+
}
|
|
14386
|
+
command.description(describeOperation(operationSpec, spec.describe ?? operationSpec.summary ?? `${operationSpec.method} ${operationSpec.path}`));
|
|
14387
|
+
addOperationOptions(command, operation, spec, operationSpec);
|
|
14388
|
+
assertNoReservedFlags(command, operation);
|
|
14389
|
+
command.action((...invocation) => executeOperation(operation, spec, operationSpec, invocation).catch((error) => {
|
|
14390
|
+
throw retypeApiError(error, operation, spec, operationSpec);
|
|
14391
|
+
}));
|
|
14392
|
+
return command;
|
|
14393
|
+
}
|
|
14394
|
+
function buildLeaf(operation, spec, leafName) {
|
|
14395
|
+
return addMissingArgumentExample(configureOperation(new Command(leafName), operation, spec));
|
|
14396
|
+
}
|
|
14397
|
+
function addRenamedCommand(groups, operation, spec, from, to) {
|
|
14398
|
+
const segments = from.split(" ");
|
|
14399
|
+
const [groupName, ...rest] = segments;
|
|
14400
|
+
if (rest.length === 0)
|
|
14401
|
+
throw new Error(`${operation}.renamedFrom "${from}" must include a verb`);
|
|
14402
|
+
let parent = groupFor(groups, groupName);
|
|
14403
|
+
for (const segment of rest.slice(0, -1)) {
|
|
14404
|
+
parent = nestedGroup(parent, segment, { hidden: true });
|
|
14405
|
+
}
|
|
14406
|
+
const leaf = buildLeaf(operation, spec, rest[rest.length - 1]);
|
|
14407
|
+
leaf.hook("preAction", () => warnRenamedCommand(from, to));
|
|
14408
|
+
addSubcommand(parent, leaf, { hidden: true });
|
|
14409
|
+
}
|
|
14410
|
+
function addSubcommand(parent, child, options = {}) {
|
|
14411
|
+
const wasLeaf = parent.commands.length === 0 && parent.registeredArguments.length > 0;
|
|
14412
|
+
const usage = wasLeaf ? parent.usage() : null;
|
|
14413
|
+
parent.addCommand(child, { hidden: options.hidden });
|
|
14414
|
+
if (usage !== null)
|
|
14415
|
+
parent.usage(usage);
|
|
14416
|
+
}
|
|
14417
|
+
function groupFor(groups, name) {
|
|
14418
|
+
const existing = groups.get(name);
|
|
14419
|
+
if (existing)
|
|
14420
|
+
return existing;
|
|
14421
|
+
const group = new Command(name).description(`Manage ${name.replaceAll("-", " ")}`);
|
|
14422
|
+
const alias = GROUP_ALIASES[name];
|
|
14423
|
+
if (alias)
|
|
14424
|
+
group.alias(alias);
|
|
14425
|
+
groups.set(name, group);
|
|
14426
|
+
return group;
|
|
14427
|
+
}
|
|
14428
|
+
function resourceLabel(name) {
|
|
14429
|
+
const label = name.endsWith("s") ? name.slice(0, -1) : name;
|
|
14430
|
+
return label.replaceAll("-", " ");
|
|
14431
|
+
}
|
|
14432
|
+
function nestedGroup(parent, name, options = {}) {
|
|
14433
|
+
const existing = parent.commands.find((candidate) => candidate.name() === name);
|
|
14434
|
+
if (existing)
|
|
14435
|
+
return existing;
|
|
14436
|
+
const created = new Command(name).description(`Manage ${resourceLabel(parent.name())} ${name.replaceAll("-", " ")}`);
|
|
14437
|
+
addSubcommand(parent, created, { hidden: options.hidden });
|
|
14438
|
+
return created;
|
|
14439
|
+
}
|
|
14440
|
+
function addLeafCommand(groups, operation, spec, segments) {
|
|
14441
|
+
const [groupName, ...rest] = segments;
|
|
14442
|
+
if (rest.length === 0)
|
|
14443
|
+
throw new Error(`${operation} leaf command must include a verb`);
|
|
14444
|
+
const group = groupFor(groups, groupName);
|
|
14445
|
+
if (rest.length > 1) {
|
|
14446
|
+
let parent = group;
|
|
14447
|
+
for (const segment of rest.slice(0, -1)) {
|
|
14448
|
+
parent = nestedGroup(parent, segment);
|
|
14449
|
+
}
|
|
14450
|
+
parent.addCommand(buildLeaf(operation, spec, rest[rest.length - 1]));
|
|
14451
|
+
return;
|
|
14452
|
+
}
|
|
14453
|
+
group.addCommand(buildLeaf(operation, spec, rest[0]));
|
|
14454
|
+
}
|
|
14455
|
+
function variantCommandSpec(spec, variant) {
|
|
14456
|
+
return {
|
|
14457
|
+
...spec,
|
|
14458
|
+
command: variant.command,
|
|
14459
|
+
groupDefault: false,
|
|
14460
|
+
aliases: [],
|
|
14461
|
+
positionals: variant.positionals,
|
|
14462
|
+
requestFields: variant.requestFields,
|
|
14463
|
+
variants: [],
|
|
14464
|
+
describe: variant.describe ?? spec.describe
|
|
14465
|
+
};
|
|
14466
|
+
}
|
|
14467
|
+
function buildGeneratedCommands() {
|
|
14468
|
+
const groups = new Map;
|
|
14469
|
+
const renamed = [];
|
|
14470
|
+
for (const operation of Object.keys(V2_OPERATIONS)) {
|
|
14471
|
+
const spec = CLI_CONTRACT[operation] ?? {};
|
|
14472
|
+
const operationSpec = V2_OPERATIONS[operation];
|
|
14473
|
+
if (spec.hidden || operationSpec.responseMode !== "json")
|
|
14474
|
+
continue;
|
|
14475
|
+
const segments = spec.command ? spec.command.split(" ") : deriveCommandPath(operation);
|
|
14476
|
+
if (spec.groupDefault) {
|
|
14477
|
+
const [groupName, ...rest] = segments;
|
|
14478
|
+
const group = groupFor(groups, groupName);
|
|
14479
|
+
if (rest.length > 0)
|
|
14480
|
+
throw new Error(`${operation} groupDefault must name a command group`);
|
|
14481
|
+
const pathPositionals = operationSpec.pathParams.filter((param) => !spec.pathFlags?.[param] && !isProfileWorkspacePath(spec, param));
|
|
14482
|
+
if (pathPositionals.length > 0 || spec.positionals?.length) {
|
|
14483
|
+
throw new Error(`${operation} groupDefault cannot require positional arguments`);
|
|
14484
|
+
}
|
|
14485
|
+
configureOperation(group, operation, spec);
|
|
14486
|
+
} else {
|
|
14487
|
+
addLeafCommand(groups, operation, spec, segments);
|
|
14488
|
+
}
|
|
14489
|
+
for (const variant of spec.variants ?? []) {
|
|
14490
|
+
addLeafCommand(groups, operation, variantCommandSpec(spec, variant), variant.command.split(" "));
|
|
14491
|
+
}
|
|
14492
|
+
for (const from of spec.renamedFrom ?? []) {
|
|
14493
|
+
renamed.push({ operation, spec, from, to: segments.join(" ") });
|
|
14494
|
+
}
|
|
14495
|
+
}
|
|
14496
|
+
for (const { operation, spec, from, to } of renamed) {
|
|
14497
|
+
addRenamedCommand(groups, operation, spec, from, to);
|
|
14498
|
+
}
|
|
14499
|
+
return [...groups.values()].sort((a, b) => a.name().localeCompare(b.name()));
|
|
14500
|
+
}
|
|
14501
|
+
|
|
14502
|
+
// src/commands/credentials.ts
|
|
14503
|
+
var CONNECTION_RESULT = {
|
|
14504
|
+
fields: [
|
|
14505
|
+
{ header: "connection link", path: "authorizationUrl" },
|
|
14506
|
+
{ header: "expires", path: "expiresAt", format: "timestamp" }
|
|
14507
|
+
]
|
|
14508
|
+
};
|
|
14509
|
+
var SERVICE_ACCOUNT_RESULT = {
|
|
14510
|
+
fields: [
|
|
14511
|
+
{ header: "id" },
|
|
14512
|
+
{ header: "name", path: "displayName" },
|
|
14513
|
+
{ header: "provider", path: "providerId" },
|
|
14514
|
+
{ header: "role" },
|
|
14515
|
+
{ header: "created", path: "createdAt", format: "timestamp" }
|
|
14516
|
+
]
|
|
14517
|
+
};
|
|
14518
|
+
function serviceAccountProvider(providers, providerId) {
|
|
14519
|
+
const provider = providers.find((candidate) => candidate.type === "service_account" && candidate.providerId === providerId);
|
|
14520
|
+
if (!provider) {
|
|
14521
|
+
throw new SimApiError(`Unknown service-account provider "${providerId}".`, 0);
|
|
13532
14522
|
}
|
|
13533
14523
|
if (!provider.available) {
|
|
13534
14524
|
throw new SimApiError(`Service-account provider "${providerId}" is not available.`, 0);
|
|
@@ -13620,9 +14610,9 @@ function attachCredentialCommands(program2) {
|
|
|
13620
14610
|
if (!credentials)
|
|
13621
14611
|
throw new Error("The generated credentials command group is missing");
|
|
13622
14612
|
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 }));
|
|
14613
|
+
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));
|
|
14614
|
+
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 }));
|
|
14615
|
+
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
14616
|
}
|
|
13627
14617
|
|
|
13628
14618
|
// src/commands/protocol/result.ts
|
|
@@ -13722,6 +14712,12 @@ Examples:
|
|
|
13722
14712
|
$ sim chat -c 3f2a… "Which of those run on a schedule?"
|
|
13723
14713
|
$ sim --output json chat "Summarize yesterday's failed runs" | jq -r '.content'
|
|
13724
14714
|
`).action(async (message, options, command) => {
|
|
14715
|
+
if (message.trim() === "") {
|
|
14716
|
+
throw new SimApiError("<message> cannot be empty", 0);
|
|
14717
|
+
}
|
|
14718
|
+
if (options.conversation !== undefined && options.conversation.trim() === "") {
|
|
14719
|
+
throw new SimApiError("-c/--conversation cannot be empty — pass the conversation id printed on stderr after each turn", 0);
|
|
14720
|
+
}
|
|
13725
14721
|
const { client, profile } = clientFrom(command);
|
|
13726
14722
|
const workspaceId = client.requireWorkspace();
|
|
13727
14723
|
const response = await client.requestRaw(V2_OPERATIONS.chat.path, {
|
|
@@ -13775,7 +14771,7 @@ Examples:
|
|
|
13775
14771
|
|
|
13776
14772
|
// src/commands/protocol/files-get.ts
|
|
13777
14773
|
import { once as once2 } from "node:events";
|
|
13778
|
-
import { createWriteStream } from "node:fs";
|
|
14774
|
+
import { createWriteStream, rmSync } from "node:fs";
|
|
13779
14775
|
import { link, lstat, mkdtemp, readlink, rename, rm } from "node:fs/promises";
|
|
13780
14776
|
import { dirname as dirname2, join as join2, resolve as resolve2 } from "node:path";
|
|
13781
14777
|
import { Readable } from "node:stream";
|
|
@@ -13831,37 +14827,66 @@ async function streamToFile(body, file, reportedPath = file.path) {
|
|
|
13831
14827
|
throw writeFailure(reportedPath, error);
|
|
13832
14828
|
}
|
|
13833
14829
|
}
|
|
14830
|
+
var STAGE_SIGNALS = ["SIGINT", "SIGTERM"];
|
|
14831
|
+
function reRaise(signal) {
|
|
14832
|
+
process.kill(process.pid, signal);
|
|
14833
|
+
}
|
|
14834
|
+
function removeStagingOnSignal(stagingDirectory, terminate = reRaise) {
|
|
14835
|
+
const installed = STAGE_SIGNALS.map((signal) => {
|
|
14836
|
+
const onSignal = () => {
|
|
14837
|
+
process.off(signal, onSignal);
|
|
14838
|
+
const directory = stagingDirectory();
|
|
14839
|
+
if (directory) {
|
|
14840
|
+
try {
|
|
14841
|
+
rmSync(directory, { recursive: true, force: true });
|
|
14842
|
+
} catch {}
|
|
14843
|
+
}
|
|
14844
|
+
terminate(signal);
|
|
14845
|
+
};
|
|
14846
|
+
process.on(signal, onSignal);
|
|
14847
|
+
return [signal, onSignal];
|
|
14848
|
+
});
|
|
14849
|
+
return () => {
|
|
14850
|
+
for (const [signal, onSignal] of installed)
|
|
14851
|
+
process.off(signal, onSignal);
|
|
14852
|
+
};
|
|
14853
|
+
}
|
|
13834
14854
|
async function saveStagedFile(body, target, force) {
|
|
13835
14855
|
let temporaryDirectory = null;
|
|
13836
14856
|
let failure = null;
|
|
14857
|
+
const disposeSignalCleanup = removeStagingOnSignal(() => temporaryDirectory);
|
|
13837
14858
|
try {
|
|
13838
|
-
|
|
13839
|
-
|
|
13840
|
-
|
|
13841
|
-
|
|
13842
|
-
|
|
13843
|
-
|
|
13844
|
-
|
|
13845
|
-
|
|
13846
|
-
|
|
13847
|
-
|
|
13848
|
-
|
|
14859
|
+
try {
|
|
14860
|
+
const publicationTarget = force ? await forcedPublicationTarget(target) : target;
|
|
14861
|
+
temporaryDirectory = await mkdtemp(join2(dirname2(publicationTarget), ".sim-download-"));
|
|
14862
|
+
const temporaryPath = join2(temporaryDirectory, "payload");
|
|
14863
|
+
await streamToFile(body, createWriteStream(temporaryPath, { flags: "wx" }), target);
|
|
14864
|
+
if (force) {
|
|
14865
|
+
await rename(temporaryPath, publicationTarget);
|
|
14866
|
+
} else {
|
|
14867
|
+
try {
|
|
14868
|
+
await link(temporaryPath, publicationTarget);
|
|
14869
|
+
} catch (error) {
|
|
14870
|
+
throw unsupportedAtomicPublish(target, error) ?? error;
|
|
14871
|
+
}
|
|
13849
14872
|
}
|
|
14873
|
+
} catch (error) {
|
|
14874
|
+
failure = normalizedWriteFailure(target, error);
|
|
13850
14875
|
}
|
|
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);
|
|
14876
|
+
if (temporaryDirectory) {
|
|
14877
|
+
try {
|
|
14878
|
+
await rm(temporaryDirectory, { recursive: true, force: true });
|
|
14879
|
+
} catch (cleanupError) {
|
|
14880
|
+
if (failure)
|
|
14881
|
+
throw combinedCleanupFailure(failure, temporaryDirectory, cleanupError);
|
|
14882
|
+
throw new SimApiError(`Saved ${target}, but could not remove temporary directory ${temporaryDirectory}: ${cleanupError.message}`, 0);
|
|
14883
|
+
}
|
|
13861
14884
|
}
|
|
14885
|
+
if (failure)
|
|
14886
|
+
throw failure;
|
|
14887
|
+
} finally {
|
|
14888
|
+
disposeSignalCleanup();
|
|
13862
14889
|
}
|
|
13863
|
-
if (failure)
|
|
13864
|
-
throw failure;
|
|
13865
14890
|
}
|
|
13866
14891
|
async function saveToFile(body, target, force) {
|
|
13867
14892
|
return saveStagedFile(body, target, force);
|
|
@@ -14101,8 +15126,15 @@ function uploadMetadata(options) {
|
|
|
14101
15126
|
}
|
|
14102
15127
|
return metadata;
|
|
14103
15128
|
}
|
|
15129
|
+
var UPLOAD_RECIPES = [
|
|
15130
|
+
"default",
|
|
15131
|
+
"plain",
|
|
15132
|
+
"markdown",
|
|
15133
|
+
"code"
|
|
15134
|
+
];
|
|
15135
|
+
var LANGUAGE_TAG_HELP = "Document language tag: hyphen-separated letter and digit subtags, for example en or en-US";
|
|
14104
15136
|
function attachKnowledgeDocumentUpload(documents) {
|
|
14105
|
-
documents.command("upload").argument("<knowledgeBaseId>", "Knowledge base to upload into").argument("<path>", "Local file to upload").allowExcessArguments(false).description("Upload a document to a knowledge base").option("--name <name>", "Store it under a different name").option("--tag <value...>", "Document tags, in tag1 through tag7 order").
|
|
15137
|
+
documents.command("upload").argument("<knowledgeBaseId>", "Knowledge base to upload into").argument("<path>", "Local file to upload").allowExcessArguments(false).description("Upload a document to a knowledge base").option("--name <name>", "Store it under a different name").option("--tag <value...>", "Document tags, in tag1 through tag7 order").addOption(new Option("--recipe <name>", "Document processing recipe").choices(UPLOAD_RECIPES)).option("--lang <code>", LANGUAGE_TAG_HELP).action(async (knowledgeBaseId, path, options, command) => {
|
|
14106
15138
|
const { client, profile } = clientFrom(command);
|
|
14107
15139
|
const workspaceId = client.requireWorkspace();
|
|
14108
15140
|
const { name, size } = await localFile(path, options.name);
|
|
@@ -14172,6 +15204,7 @@ function renderCell2(value, format) {
|
|
|
14172
15204
|
}
|
|
14173
15205
|
var COLUMNS = (CLI_CONTRACT.listLogs?.columns ?? []).map((spec) => ({
|
|
14174
15206
|
header: spec.header,
|
|
15207
|
+
floor: Math.min(MAX_CELL_WIDTH2, spec.minWidth ?? 0),
|
|
14175
15208
|
value: (row) => renderCell2(at2(row, spec.path ?? spec.header), spec.format)
|
|
14176
15209
|
}));
|
|
14177
15210
|
function oneLine2(value) {
|
|
@@ -14188,15 +15221,15 @@ function clamp2(value, width) {
|
|
|
14188
15221
|
function createTableWriter() {
|
|
14189
15222
|
let widths = null;
|
|
14190
15223
|
return (rows) => {
|
|
14191
|
-
const lines = rows.map((row) => COLUMNS.map((column) => oneLine2(column.value(row))));
|
|
15224
|
+
const lines = rows.map((row) => COLUMNS.map((column) => clamp2(oneLine2(column.value(row)), MAX_CELL_WIDTH2)));
|
|
14192
15225
|
if (!widths) {
|
|
14193
|
-
widths = COLUMNS.map((column, index) => Math.min(MAX_CELL_WIDTH2, Math.max(visibleWidth(column.header), ...lines.map((line) => visibleWidth(line[index])))));
|
|
15226
|
+
widths = COLUMNS.map((column, index) => Math.min(MAX_CELL_WIDTH2, Math.max(column.floor, visibleWidth(column.header), ...lines.map((line) => visibleWidth(line[index])))));
|
|
14194
15227
|
const header = widths;
|
|
14195
15228
|
console.log(source_default.dim(COLUMNS.map((column, index) => pad2(column.header.toUpperCase(), header[index])).join(" ").trimEnd()));
|
|
14196
15229
|
}
|
|
14197
15230
|
const locked = widths;
|
|
14198
15231
|
for (const line of lines) {
|
|
14199
|
-
console.log(line.map((cell, index) => pad2(
|
|
15232
|
+
console.log(line.map((cell, index) => pad2(cell, locked[index])).join(" ").trimEnd());
|
|
14200
15233
|
}
|
|
14201
15234
|
};
|
|
14202
15235
|
}
|
|
@@ -14320,7 +15353,7 @@ function isTransient(error) {
|
|
|
14320
15353
|
function nonNegativeInteger(raw, flag) {
|
|
14321
15354
|
const value = Number(raw);
|
|
14322
15355
|
if (!Number.isSafeInteger(value) || value < 0) {
|
|
14323
|
-
throw new SimApiError(`${flag} must be a
|
|
15356
|
+
throw new SimApiError(`${flag} must be a whole number of 0 or more`, 0);
|
|
14324
15357
|
}
|
|
14325
15358
|
return value;
|
|
14326
15359
|
}
|
|
@@ -14339,175 +15372,74 @@ function attachLogsFollow(logs) {
|
|
|
14339
15372
|
...V2_OPERATIONS.listLogs.query.level.values
|
|
14340
15373
|
])).addOption(new Option("--details <level>", "Response detail level; full names each run’s workflow").choices([...V2_OPERATIONS.listLogs.query.details.values]).default("full")).option("-n, --lines <count>", "Recent runs to print before watching", String(DEFAULT_BACKLOG)).option("--interval <seconds>", "Seconds between polls", String(DEFAULT_INTERVAL_SECONDS)).addHelpText("after", `
|
|
14341
15374
|
Each run prints once, when it is first seen, so its status is the status it had
|
|
14342
|
-
at that moment. With --output json every run is a JSON object on its own line
|
|
14343
|
-
(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
|
|
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)`);
|
|
15375
|
+
at that moment. With --output json every run is a JSON object on its own line
|
|
15376
|
+
(JSONL) rather than a member of an array, because a follow never ends and so can
|
|
15377
|
+
never close one; --output yaml emits a --- separated document stream. Progress
|
|
15378
|
+
and retries go to stderr, leaving stdout a clean stream of rows. Ctrl-C stops the
|
|
15379
|
+
follow.
|
|
15380
|
+
|
|
15381
|
+
Examples:
|
|
15382
|
+
$ sim logs follow --level error
|
|
15383
|
+
$ sim logs follow --workflow 00000000-0000-4000-8000-000000000000 -n 0
|
|
15384
|
+
$ sim --output json logs follow | jq -r '.runId'
|
|
15385
|
+
`).action(async (options, command) => {
|
|
15386
|
+
const lines = nonNegativeInteger(options.lines, "--lines");
|
|
15387
|
+
const delay = intervalMs(options.interval);
|
|
15388
|
+
const { client, profile } = clientFrom(command);
|
|
15389
|
+
const path = V2_OPERATIONS.listLogs.path;
|
|
15390
|
+
const query = {
|
|
15391
|
+
workspaceId: client.requireWorkspace(),
|
|
15392
|
+
workflowIds: options.workflow?.length ? options.workflow.join(",") : undefined,
|
|
15393
|
+
folderPaths: options.folder?.length ? options.folder.map(encodeFolderPath).join(",") : undefined,
|
|
15394
|
+
triggers: options.trigger?.length ? options.trigger.join(",") : undefined,
|
|
15395
|
+
level: options.level,
|
|
15396
|
+
details: options.details,
|
|
15397
|
+
sortBy: "startedAt",
|
|
15398
|
+
sortOrder: "desc"
|
|
15399
|
+
};
|
|
15400
|
+
const write = createWriter(profile.output);
|
|
15401
|
+
const status = followStatus();
|
|
15402
|
+
const interrupt = watchForInterrupt();
|
|
15403
|
+
const state = { seen: new Map, floor: null };
|
|
15404
|
+
try {
|
|
15405
|
+
const seed = await collectUnprinted(client, path, query, state, Math.max(lines, 1), 1);
|
|
15406
|
+
remember(state, seed.rows);
|
|
15407
|
+
state.floor = seed.rows.at(-1)?.startedAt ?? null;
|
|
15408
|
+
if (seed.truncated && seed.rows.length < lines) {
|
|
15409
|
+
status.warn(`asked for ${lines} earlier runs but a page holds ${seed.rows.length}; following from there — see sim logs list for more`);
|
|
14502
15410
|
}
|
|
14503
|
-
|
|
14504
|
-
|
|
15411
|
+
write(lines > 0 ? seed.rows.slice(0, lines).reverse() : []);
|
|
15412
|
+
let failures = 0;
|
|
15413
|
+
while (!interrupt.interrupted()) {
|
|
15414
|
+
await waitFor(failures === 0 ? delay : Math.min(delay * 2 ** failures, MAX_BACKOFF_MS), interrupt.interrupted);
|
|
15415
|
+
if (interrupt.interrupted())
|
|
15416
|
+
break;
|
|
15417
|
+
let fresh;
|
|
15418
|
+
try {
|
|
15419
|
+
fresh = await collectUnprinted(client, path, query, state, POLL_PAGE_SIZE, MAX_PAGES_PER_POLL);
|
|
15420
|
+
} catch (error) {
|
|
15421
|
+
if (!isTransient(error))
|
|
15422
|
+
throw error;
|
|
15423
|
+
failures += 1;
|
|
15424
|
+
const next = Math.min(delay * 2 ** failures, MAX_BACKOFF_MS);
|
|
15425
|
+
status.note(`poll failed (${error.message}); retrying in ${inSeconds(next)}s…`);
|
|
15426
|
+
continue;
|
|
15427
|
+
}
|
|
15428
|
+
failures = 0;
|
|
15429
|
+
status.clear();
|
|
15430
|
+
if (fresh.truncated) {
|
|
15431
|
+
status.warn(`more than ${MAX_PAGES_PER_POLL * POLL_PAGE_SIZE} runs arrived at once; older ones were skipped — see sim logs list`);
|
|
15432
|
+
}
|
|
15433
|
+
if (fresh.rows.length === 0)
|
|
15434
|
+
continue;
|
|
15435
|
+
remember(state, fresh.rows);
|
|
15436
|
+
write(fresh.rows.reverse());
|
|
15437
|
+
}
|
|
15438
|
+
} finally {
|
|
15439
|
+
status.clear();
|
|
15440
|
+
interrupt.dispose();
|
|
14505
15441
|
}
|
|
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
|
-
}
|
|
15442
|
+
});
|
|
14511
15443
|
}
|
|
14512
15444
|
|
|
14513
15445
|
// src/commands/protocol/resource-directory.ts
|
|
@@ -14530,9 +15462,9 @@ async function listResources(client, config, workspaceId, folderPath, search, li
|
|
|
14530
15462
|
const paginated = "cursor" in V2_OPERATIONS[config.resources].query;
|
|
14531
15463
|
if (!paginated) {
|
|
14532
15464
|
const page = await client.request(path, { query });
|
|
14533
|
-
return page.data.slice(0, limit);
|
|
15465
|
+
return { items: page.data.slice(0, limit), truncated: page.data.length > limit };
|
|
14534
15466
|
}
|
|
14535
|
-
return
|
|
15467
|
+
return requestPages(client, path, {
|
|
14536
15468
|
query,
|
|
14537
15469
|
pageSize: DEFAULT_LIMIT,
|
|
14538
15470
|
limit
|
|
@@ -14567,7 +15499,7 @@ function attachResourceDirectoryCommands(group, config) {
|
|
|
14567
15499
|
group.command("ls").argument("[path]", "Folder path to list; defaults to the root folder").allowExcessArguments(false).description(`List ${config.kind} resources and child folders together`).option("--search <text>", "Filter folders and resources by name").addOption(new Option("--limit <n>", "Maximum combined items to return (0 for everything)").default(String(DEFAULT_LIMIT))).action(async (path, options, command) => {
|
|
14568
15500
|
const rawLimit = Number(options.limit);
|
|
14569
15501
|
if (!Number.isSafeInteger(rawLimit) || rawLimit < 0) {
|
|
14570
|
-
throw new SimApiError("--limit must be a
|
|
15502
|
+
throw new SimApiError("--limit must be a whole number of 0 or more (0 for everything)", 0);
|
|
14571
15503
|
}
|
|
14572
15504
|
const limit = rawLimit === 0 ? Number.POSITIVE_INFINITY : rawLimit;
|
|
14573
15505
|
const folderPath = encodeFolderPath(path ?? "/");
|
|
@@ -14577,8 +15509,10 @@ function attachResourceDirectoryCommands(group, config) {
|
|
|
14577
15509
|
listFolders(client, config.folders, workspaceId, folderPath, options.search),
|
|
14578
15510
|
listResources(client, config, workspaceId, folderPath, options.search, limit)
|
|
14579
15511
|
]);
|
|
14580
|
-
const entries = entriesFor(config, folders, resources);
|
|
14581
|
-
|
|
15512
|
+
const entries = entriesFor(config, folders, resources.items);
|
|
15513
|
+
const shown = entries.slice(0, limit);
|
|
15514
|
+
writeCursorTruncation(shown.length, resources.truncated || entries.length > limit);
|
|
15515
|
+
printList(profile.output, shown, COLUMNS2);
|
|
14582
15516
|
});
|
|
14583
15517
|
group.command("mkdir").argument("<path>", "Folder path to create; the leading / is optional").allowExcessArguments(false).description(`Create a ${config.kind} directory at a path`).action(async (path, _options, command) => {
|
|
14584
15518
|
const { client, profile } = clientFrom(command);
|
|
@@ -14663,13 +15597,16 @@ function validateTargetOptions(options) {
|
|
|
14663
15597
|
return intoExisting;
|
|
14664
15598
|
}
|
|
14665
15599
|
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) => {
|
|
15600
|
+
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
15601
|
const { client, profile } = clientFrom(command);
|
|
14668
15602
|
const workspaceId = client.requireWorkspace();
|
|
14669
15603
|
if (Boolean(path) === Boolean(options.fileId)) {
|
|
14670
15604
|
throw new SimApiError("Pass exactly one of <path> or --file-id <id>", 0);
|
|
14671
15605
|
}
|
|
14672
15606
|
const intoExisting = validateTargetOptions(options);
|
|
15607
|
+
if (intoExisting && options.mode === "replace" && options.yes !== true) {
|
|
15608
|
+
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);
|
|
15609
|
+
}
|
|
14673
15610
|
const local = path ? await localFile(path) : null;
|
|
14674
15611
|
const source = local ? {
|
|
14675
15612
|
type: "upload",
|
|
@@ -14724,202 +15661,18 @@ function attachTableImport(tables) {
|
|
|
14724
15661
|
});
|
|
14725
15662
|
return;
|
|
14726
15663
|
}
|
|
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
|
|
15664
|
+
const finished = await watchImport(client, workspaceId, job);
|
|
15665
|
+
if (finished.status !== "completed") {
|
|
15666
|
+
throw new SimApiError(`Import ${finished.status}${finished.error ? `: ${finished.error}` : ""}`, 0);
|
|
15667
|
+
}
|
|
15668
|
+
printProtocolResult(profile.output, {
|
|
15669
|
+
id: finished.id,
|
|
15670
|
+
status: finished.status,
|
|
15671
|
+
tableId: finished.tableId,
|
|
15672
|
+
rowsProcessed: finished.rowsProcessed,
|
|
15673
|
+
...rejectionFields(finished)
|
|
15674
|
+
});
|
|
14919
15675
|
});
|
|
14920
|
-
const failure = runFailureMessage(operation, payload) ?? bulkFailureMessage(operation, payload, request.body);
|
|
14921
|
-
if (failure)
|
|
14922
|
-
throw new SimApiError(failure, 0);
|
|
14923
15676
|
}
|
|
14924
15677
|
|
|
14925
15678
|
// src/commands/protocol/workflow-run-follow.ts
|
|
@@ -15141,6 +15894,9 @@ function followOrDelegate(previous) {
|
|
|
15141
15894
|
command.setOptionValue("run", selection);
|
|
15142
15895
|
const flags = command.optsWithGlobals();
|
|
15143
15896
|
if (flags.follow !== true) {
|
|
15897
|
+
if (Array.isArray(flags.selectOutput) && flags.selectOutput.length > 0) {
|
|
15898
|
+
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);
|
|
15899
|
+
}
|
|
15144
15900
|
if (flags.includeThinking === true || flags.includeToolCalls === true) {
|
|
15145
15901
|
throw new SimApiError("--include-thinking and --include-tool-calls describe a stream; add --follow", 0);
|
|
15146
15902
|
}
|
|
@@ -15455,6 +16211,8 @@ function validateWorkspaceOnlyFlag(flag, value, scope) {
|
|
|
15455
16211
|
async function readSecretValue(options) {
|
|
15456
16212
|
if (options.value !== undefined)
|
|
15457
16213
|
return validateSecretValue(readValueArgument(options.value));
|
|
16214
|
+
if (options.description !== undefined || options.unredacted !== undefined)
|
|
16215
|
+
return;
|
|
15458
16216
|
try {
|
|
15459
16217
|
return validateSecretValue(await promptSecret());
|
|
15460
16218
|
} catch (error) {
|
|
@@ -15464,7 +16222,10 @@ async function readSecretValue(options) {
|
|
|
15464
16222
|
return process.exit(CANCELLED_EXIT_CODE);
|
|
15465
16223
|
}
|
|
15466
16224
|
}
|
|
15467
|
-
async function setSecret(name, options, command) {
|
|
16225
|
+
async function setSecret(name, options, command, redactionSpellings) {
|
|
16226
|
+
if (redactionSpellings.size > 1) {
|
|
16227
|
+
throw new SimApiError("Pass either --unredacted or --no-unredacted, not both: they are one setting, and commander keeps only whichever came last.", 0);
|
|
16228
|
+
}
|
|
15468
16229
|
const description = validateWorkspaceOnlyFlag("description", options.description, options.scope);
|
|
15469
16230
|
const unredacted = validateWorkspaceOnlyFlag("unredacted", options.unredacted, options.scope);
|
|
15470
16231
|
const value = await readSecretValue(options);
|
|
@@ -15475,7 +16236,7 @@ async function setSecret(name, options, command) {
|
|
|
15475
16236
|
body: {
|
|
15476
16237
|
workspaceId: client.requireWorkspace(),
|
|
15477
16238
|
scope: options.scope,
|
|
15478
|
-
value,
|
|
16239
|
+
...value === undefined ? {} : { value },
|
|
15479
16240
|
description,
|
|
15480
16241
|
...unredacted === undefined ? {} : { unredacted }
|
|
15481
16242
|
}
|
|
@@ -15486,257 +16247,8 @@ function attachSecretCommands(program2) {
|
|
|
15486
16247
|
const secrets = program2.commands.find((command) => command.name() === "secrets");
|
|
15487
16248
|
if (!secrets)
|
|
15488
16249
|
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()));
|
|
16250
|
+
const redactionSpellings = new Set;
|
|
16251
|
+
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
16252
|
}
|
|
15741
16253
|
|
|
15742
16254
|
// src/program.ts
|
|
@@ -15816,6 +16328,7 @@ function buildProgram(options = {}) {
|
|
|
15816
16328
|
attachProtocolCommands(program2);
|
|
15817
16329
|
attachSecretCommands(program2);
|
|
15818
16330
|
program2.addHelpText("after", HELP_EPILOGUE);
|
|
16331
|
+
refuseHelpAfterUnknownCommand(program2);
|
|
15819
16332
|
assertNoReservedProgramFlags(program2);
|
|
15820
16333
|
return program2;
|
|
15821
16334
|
}
|