sim 2.1.7-preview.92.1 → 2.1.8-dev.101.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/auth/device-flow.d.ts +38 -0
- package/dist/commands/auth.d.ts +5 -0
- package/dist/commands/configure.d.ts +2 -0
- package/dist/commands/credentials.d.ts +3 -0
- package/dist/commands/protocol/chat.d.ts +11 -0
- package/dist/commands/protocol/files-get.d.ts +25 -0
- package/dist/commands/protocol/files-upload.d.ts +2 -0
- package/dist/commands/protocol/index.d.ts +3 -0
- package/dist/commands/protocol/knowledge-document-upload.d.ts +2 -0
- package/dist/commands/protocol/logs-follow.d.ts +39 -0
- package/dist/commands/protocol/resource-directory.d.ts +24 -0
- package/dist/commands/protocol/result.d.ts +2 -0
- package/dist/commands/protocol/tables-import.d.ts +2 -0
- package/dist/commands/protocol/workflow-run-follow.d.ts +56 -0
- package/dist/commands/protocol/workflow-run-get.d.ts +15 -0
- package/dist/commands/protocol/workflow-run-wait.d.ts +3 -0
- package/dist/commands/secrets.d.ts +3 -0
- package/dist/config/index.d.ts +2 -0
- package/dist/config/ini.d.ts +111 -0
- package/dist/config/paths.d.ts +21 -0
- package/dist/config/profile.d.ts +158 -0
- package/dist/context.d.ts +21 -0
- package/dist/contract/commands.d.ts +14 -0
- package/dist/contract/types.d.ts +304 -0
- package/dist/embed-context.d.ts +77 -0
- package/dist/embed-output.d.ts +15 -0
- package/dist/embed.d.ts +39 -0
- package/dist/generated/v2-api.d.ts +13498 -0
- package/dist/helpers.d.ts +9 -0
- package/dist/http/client.d.ts +166 -0
- package/dist/http/environment.d.ts +24 -0
- package/dist/index.js +768 -281
- package/dist/output/io.d.ts +5 -0
- package/dist/output/presentation.d.ts +4 -0
- package/dist/output/render.d.ts +60 -0
- package/dist/output/terminal-text.d.ts +17 -0
- package/dist/output/trace.d.ts +3 -0
- package/dist/program.d.ts +21 -0
- package/dist/runtime/build.d.ts +38 -0
- package/dist/runtime/derive.d.ts +20 -0
- package/dist/runtime/execute.d.ts +30 -0
- package/dist/runtime/naming.d.ts +25 -0
- package/dist/runtime/options.d.ts +7 -0
- package/dist/runtime/renamed.d.ts +6 -0
- package/dist/runtime/request.d.ts +107 -0
- package/dist/runtime/result.d.ts +50 -0
- package/dist/runtime/types.d.ts +23 -0
- package/dist/runtime.d.ts +5 -0
- package/dist/runtime.js +17708 -0
- package/dist/terminal/secret-input.d.ts +15 -0
- package/dist/terminal.d.ts +6 -0
- package/dist/transfer/local-file.d.ts +16 -0
- package/dist/transfer/streaming-upload.d.ts +16 -0
- package/dist/transfer/upload-session.d.ts +18 -0
- package/dist/update/check.d.ts +53 -0
- package/dist/version.d.ts +10 -0
- package/package.json +15 -2
package/dist/index.js
CHANGED
|
@@ -2172,6 +2172,12 @@ var applyOptions = (object, options = {}) => {
|
|
|
2172
2172
|
const colorLevel = stdoutColor ? stdoutColor.level : 0;
|
|
2173
2173
|
object.level = options.level === undefined ? colorLevel : options.level;
|
|
2174
2174
|
};
|
|
2175
|
+
|
|
2176
|
+
class Chalk {
|
|
2177
|
+
constructor(options) {
|
|
2178
|
+
return chalkFactory(options);
|
|
2179
|
+
}
|
|
2180
|
+
}
|
|
2175
2181
|
var chalkFactory = (options) => {
|
|
2176
2182
|
const chalk = (...strings) => strings.join(" ");
|
|
2177
2183
|
applyOptions(chalk, options);
|
|
@@ -2300,6 +2306,54 @@ var chalk = createChalk();
|
|
|
2300
2306
|
var chalkStderr = createChalk({ level: stderrColor ? stderrColor.level : 0 });
|
|
2301
2307
|
var source_default = chalk;
|
|
2302
2308
|
|
|
2309
|
+
// src/embed-context.ts
|
|
2310
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
2311
|
+
function setSoftExitCode(code) {
|
|
2312
|
+
const ctx = embedStore.getStore();
|
|
2313
|
+
if (ctx)
|
|
2314
|
+
ctx.softExitCode = code;
|
|
2315
|
+
else
|
|
2316
|
+
process.exitCode = code;
|
|
2317
|
+
}
|
|
2318
|
+
var embedStore = new AsyncLocalStorage;
|
|
2319
|
+
|
|
2320
|
+
class EmbeddedExit extends Error {
|
|
2321
|
+
code;
|
|
2322
|
+
constructor(code) {
|
|
2323
|
+
super(`CLI exited with code ${code}`);
|
|
2324
|
+
this.code = code;
|
|
2325
|
+
}
|
|
2326
|
+
}
|
|
2327
|
+
function embeddedProfile() {
|
|
2328
|
+
const ctx = embedStore.getStore();
|
|
2329
|
+
if (!ctx)
|
|
2330
|
+
return null;
|
|
2331
|
+
return {
|
|
2332
|
+
name: "embedded",
|
|
2333
|
+
endpoint: ctx.identity.endpoint,
|
|
2334
|
+
apiKey: ctx.identity.apiKey,
|
|
2335
|
+
workspaceId: ctx.identity.workspaceId ?? null,
|
|
2336
|
+
output: "json",
|
|
2337
|
+
...ctx.identity.transport ? { transport: ctx.identity.transport } : {},
|
|
2338
|
+
...ctx.identity.signal ? { signal: ctx.identity.signal } : {},
|
|
2339
|
+
sources: { endpoint: "flag", apiKey: "flag", workspaceId: "flag", output: "flag" }
|
|
2340
|
+
};
|
|
2341
|
+
}
|
|
2342
|
+
function exitCli(code) {
|
|
2343
|
+
if (embedStore.getStore())
|
|
2344
|
+
throw new EmbeddedExit(code);
|
|
2345
|
+
return process.exit(code);
|
|
2346
|
+
}
|
|
2347
|
+
|
|
2348
|
+
// src/output/presentation.ts
|
|
2349
|
+
var plain = new Chalk({ level: 0 });
|
|
2350
|
+
function styles3() {
|
|
2351
|
+
return embedStore.getStore() ? plain : source_default;
|
|
2352
|
+
}
|
|
2353
|
+
function hasProgressTerminal() {
|
|
2354
|
+
return !embedStore.getStore() && Boolean(process.stderr.isTTY);
|
|
2355
|
+
}
|
|
2356
|
+
|
|
2303
2357
|
// src/config/paths.ts
|
|
2304
2358
|
import { homedir } from "node:os";
|
|
2305
2359
|
import { join } from "node:path";
|
|
@@ -2634,6 +2688,9 @@ function refuseBlankOverrides(overrides) {
|
|
|
2634
2688
|
}
|
|
2635
2689
|
}
|
|
2636
2690
|
function resolveProfile(overrides = {}) {
|
|
2691
|
+
const embedded = embeddedProfile();
|
|
2692
|
+
if (embedded)
|
|
2693
|
+
return embedded;
|
|
2637
2694
|
refuseBlankOverrides(overrides);
|
|
2638
2695
|
const named = overrides.profile || process.env.SIM_PROFILE;
|
|
2639
2696
|
const name = named || DEFAULT_PROFILE;
|
|
@@ -2683,17 +2740,58 @@ function resolveProfile(overrides = {}) {
|
|
|
2683
2740
|
}
|
|
2684
2741
|
};
|
|
2685
2742
|
}
|
|
2743
|
+
// src/output/io.ts
|
|
2744
|
+
import { format } from "node:util";
|
|
2745
|
+
function printLine(...args) {
|
|
2746
|
+
const context = embedStore.getStore();
|
|
2747
|
+
if (context)
|
|
2748
|
+
context.stdout.write(`${format(...args)}
|
|
2749
|
+
`);
|
|
2750
|
+
else
|
|
2751
|
+
console.log(...args);
|
|
2752
|
+
}
|
|
2753
|
+
function printError(...args) {
|
|
2754
|
+
const context = embedStore.getStore();
|
|
2755
|
+
if (context)
|
|
2756
|
+
context.stderr.write(`${format(...args)}
|
|
2757
|
+
`);
|
|
2758
|
+
else
|
|
2759
|
+
console.error(...args);
|
|
2760
|
+
}
|
|
2761
|
+
function writeStdout(chunk) {
|
|
2762
|
+
const context = embedStore.getStore();
|
|
2763
|
+
if (!context)
|
|
2764
|
+
return process.stdout.write(chunk);
|
|
2765
|
+
context.stdout.write(chunk);
|
|
2766
|
+
return true;
|
|
2767
|
+
}
|
|
2768
|
+
function writeStderr(chunk) {
|
|
2769
|
+
const context = embedStore.getStore();
|
|
2770
|
+
if (!context)
|
|
2771
|
+
return process.stderr.write(chunk);
|
|
2772
|
+
context.stderr.write(chunk);
|
|
2773
|
+
return true;
|
|
2774
|
+
}
|
|
2775
|
+
|
|
2686
2776
|
// src/version.ts
|
|
2687
2777
|
import { readFileSync as readFileSync2 } from "node:fs";
|
|
2688
2778
|
function readPackageVersion() {
|
|
2689
|
-
|
|
2690
|
-
|
|
2691
|
-
|
|
2692
|
-
|
|
2693
|
-
|
|
2779
|
+
try {
|
|
2780
|
+
const metadata = JSON.parse(readFileSync2(new URL("../package.json", import.meta.url), "utf8"));
|
|
2781
|
+
if (typeof metadata === "object" && metadata !== null && "version" in metadata && typeof metadata.version === "string") {
|
|
2782
|
+
return metadata.version;
|
|
2783
|
+
}
|
|
2784
|
+
} catch {}
|
|
2785
|
+
return "0.0.0-embedded";
|
|
2786
|
+
}
|
|
2787
|
+
var cachedVersion = null;
|
|
2788
|
+
function cliVersion() {
|
|
2789
|
+
cachedVersion ??= readPackageVersion();
|
|
2790
|
+
return cachedVersion;
|
|
2791
|
+
}
|
|
2792
|
+
function userAgent() {
|
|
2793
|
+
return `sim-cli/${cliVersion()} node/${process.versions.node} (${process.platform}; ${process.arch})`;
|
|
2694
2794
|
}
|
|
2695
|
-
var CLI_VERSION = readPackageVersion();
|
|
2696
|
-
var USER_AGENT = `sim-cli/${CLI_VERSION} node/${process.versions.node} (${process.platform}; ${process.arch})`;
|
|
2697
2795
|
|
|
2698
2796
|
// src/http/environment.ts
|
|
2699
2797
|
var reported = new Set;
|
|
@@ -2701,7 +2799,7 @@ function once(key, message) {
|
|
|
2701
2799
|
if (reported.has(key))
|
|
2702
2800
|
return;
|
|
2703
2801
|
reported.add(key);
|
|
2704
|
-
|
|
2802
|
+
writeStderr(`warning: ${message}
|
|
2705
2803
|
`);
|
|
2706
2804
|
}
|
|
2707
2805
|
var PROXY_VARIABLES = ["HTTPS_PROXY", "https_proxy", "HTTP_PROXY", "http_proxy"];
|
|
@@ -2868,7 +2966,7 @@ function debugEnabled(env = process.env) {
|
|
|
2868
2966
|
return raw !== undefined && raw !== "" && raw !== "0" && raw.toLowerCase() !== "false";
|
|
2869
2967
|
}
|
|
2870
2968
|
function traceRequest(method, url, status, startedAt) {
|
|
2871
|
-
|
|
2969
|
+
writeStderr(`${styles3().dim(`[sim] ${method} ${url} → ${status} ${Math.round(performance.now() - startedAt)}ms`)}
|
|
2872
2970
|
`);
|
|
2873
2971
|
}
|
|
2874
2972
|
function withoutLeadingLabel(message, label) {
|
|
@@ -2966,17 +3064,20 @@ class SimClient {
|
|
|
2966
3064
|
warnIfKeyOverCleartext(this.profile.endpoint, Boolean(apiKey));
|
|
2967
3065
|
const timeoutMs = resolveTimeoutMs();
|
|
2968
3066
|
const timeout = timeoutMs > 0 ? AbortSignal.timeout(timeoutMs) : undefined;
|
|
2969
|
-
const
|
|
3067
|
+
const caller = combineSignals(options.signal, this.profile.signal);
|
|
3068
|
+
if (caller?.aborted)
|
|
3069
|
+
throw new SimApiError("Request cancelled.", 0);
|
|
3070
|
+
const signal = combineSignals(caller, timeout);
|
|
2970
3071
|
const trace = debugEnabled();
|
|
2971
3072
|
const startedAt = performance.now();
|
|
2972
3073
|
let response;
|
|
2973
3074
|
try {
|
|
2974
|
-
response = await fetch(url, {
|
|
3075
|
+
response = await (this.profile.transport ?? fetch)(url, {
|
|
2975
3076
|
method,
|
|
2976
3077
|
headers: {
|
|
2977
3078
|
...apiKey ? { "x-api-key": apiKey } : {},
|
|
2978
3079
|
accept: "application/json",
|
|
2979
|
-
"user-agent":
|
|
3080
|
+
"user-agent": userAgent(),
|
|
2980
3081
|
...hasBody ? { "content-type": "application/json" } : {},
|
|
2981
3082
|
...options.headers
|
|
2982
3083
|
},
|
|
@@ -2987,7 +3088,7 @@ class SimClient {
|
|
|
2987
3088
|
} catch (cause) {
|
|
2988
3089
|
if (trace)
|
|
2989
3090
|
traceRequest(method, url, "failed", startedAt);
|
|
2990
|
-
if (
|
|
3091
|
+
if (caller?.aborted) {
|
|
2991
3092
|
throw new SimApiError("Request cancelled.", 0);
|
|
2992
3093
|
}
|
|
2993
3094
|
if (timeout?.aborted) {
|
|
@@ -3041,14 +3142,14 @@ function pageProgress() {
|
|
|
3041
3142
|
let reported = false;
|
|
3042
3143
|
return {
|
|
3043
3144
|
advance: (fetched) => {
|
|
3044
|
-
if (!
|
|
3145
|
+
if (!hasProgressTerminal())
|
|
3045
3146
|
return;
|
|
3046
3147
|
reported = true;
|
|
3047
|
-
|
|
3148
|
+
writeStderr(`\r${styles3().dim(`fetched ${fetched}…`)}\x1B[K`);
|
|
3048
3149
|
},
|
|
3049
3150
|
finish: () => {
|
|
3050
3151
|
if (reported)
|
|
3051
|
-
|
|
3152
|
+
writeStderr("\r\x1B[K");
|
|
3052
3153
|
}
|
|
3053
3154
|
};
|
|
3054
3155
|
}
|
|
@@ -6251,7 +6352,6 @@ function isWideCodePoint(codePoint) {
|
|
|
6251
6352
|
|
|
6252
6353
|
// src/output/render.ts
|
|
6253
6354
|
var EMPTY_GLYPH = "—";
|
|
6254
|
-
var EMPTY = source_default.dim(EMPTY_GLYPH);
|
|
6255
6355
|
var ESC = String.fromCharCode(27);
|
|
6256
6356
|
var CONTROL_PATTERN = new RegExp([
|
|
6257
6357
|
`${ESC}\\][^\\u0007${ESC}]*(?:\\u0007|${ESC}\\\\)?`,
|
|
@@ -6270,12 +6370,12 @@ function safeOneLine(value) {
|
|
|
6270
6370
|
}
|
|
6271
6371
|
function text(value) {
|
|
6272
6372
|
if (value === null || value === undefined || value === "")
|
|
6273
|
-
return
|
|
6373
|
+
return styles3().dim(EMPTY_GLYPH);
|
|
6274
6374
|
return sanitize(String(value));
|
|
6275
6375
|
}
|
|
6276
6376
|
function timestamp2(value) {
|
|
6277
6377
|
if (!value)
|
|
6278
|
-
return
|
|
6378
|
+
return styles3().dim(EMPTY_GLYPH);
|
|
6279
6379
|
const date = new Date(value);
|
|
6280
6380
|
if (Number.isNaN(date.getTime()))
|
|
6281
6381
|
return sanitize(String(value));
|
|
@@ -6283,12 +6383,12 @@ function timestamp2(value) {
|
|
|
6283
6383
|
}
|
|
6284
6384
|
function bool2(value) {
|
|
6285
6385
|
if (value === null || value === undefined)
|
|
6286
|
-
return
|
|
6287
|
-
return value ?
|
|
6386
|
+
return styles3().dim(EMPTY_GLYPH);
|
|
6387
|
+
return value ? styles3().green("yes") : styles3().dim("no");
|
|
6288
6388
|
}
|
|
6289
6389
|
function bytes(value) {
|
|
6290
6390
|
if (value === null || value === undefined)
|
|
6291
|
-
return
|
|
6391
|
+
return styles3().dim(EMPTY_GLYPH);
|
|
6292
6392
|
const units = ["B", "KB", "MB", "GB", "TB"];
|
|
6293
6393
|
let size = value;
|
|
6294
6394
|
let unit = 0;
|
|
@@ -6300,7 +6400,7 @@ function bytes(value) {
|
|
|
6300
6400
|
}
|
|
6301
6401
|
function duration(ms) {
|
|
6302
6402
|
if (ms === null || ms === undefined)
|
|
6303
|
-
return
|
|
6403
|
+
return styles3().dim(EMPTY_GLYPH);
|
|
6304
6404
|
if (ms < 1000)
|
|
6305
6405
|
return `${Math.round(ms)}ms`;
|
|
6306
6406
|
if (ms < 60000)
|
|
@@ -6331,11 +6431,11 @@ function clamp(value, width) {
|
|
|
6331
6431
|
}
|
|
6332
6432
|
function renderTable(rows, columns) {
|
|
6333
6433
|
if (rows.length === 0)
|
|
6334
|
-
return
|
|
6434
|
+
return styles3().dim("No results.");
|
|
6335
6435
|
const headers = columns.map((column) => sanitize(column.header));
|
|
6336
6436
|
const cells = rows.map((row) => columns.map((column) => clamp(oneLine(column.value(row)), MAX_CELL_WIDTH)));
|
|
6337
6437
|
const widths = columns.map((_column, index) => Math.max(visibleWidth(headers[index]), ...cells.map((line) => visibleWidth(line[index]))));
|
|
6338
|
-
const header = headers.map((label, index) =>
|
|
6438
|
+
const header = headers.map((label, index) => styles3().dim(pad(label.toUpperCase(), widths[index]))).join(" ").trimEnd();
|
|
6339
6439
|
const body = cells.map((line) => line.map((cell, index) => pad(cell, widths[index])).join(" ").trimEnd());
|
|
6340
6440
|
return [header, ...body].join(`
|
|
6341
6441
|
`);
|
|
@@ -6350,36 +6450,36 @@ function renderMachine(format, raw) {
|
|
|
6350
6450
|
function printList(format, rows, columns, raw = rows) {
|
|
6351
6451
|
const machine = renderMachine(format, raw);
|
|
6352
6452
|
if (machine !== null) {
|
|
6353
|
-
|
|
6453
|
+
printLine(machine);
|
|
6354
6454
|
return;
|
|
6355
6455
|
}
|
|
6356
6456
|
if (format === "text") {
|
|
6357
6457
|
for (const row of rows) {
|
|
6358
|
-
|
|
6458
|
+
printLine(columns.map((column) => oneLine(stripAnsi(column.value(row)))).join("\t"));
|
|
6359
6459
|
}
|
|
6360
6460
|
return;
|
|
6361
6461
|
}
|
|
6362
|
-
|
|
6462
|
+
printLine(renderTable(rows, columns));
|
|
6363
6463
|
}
|
|
6364
6464
|
function printDocument(format, raw) {
|
|
6365
|
-
|
|
6465
|
+
printLine(format === "yaml" ? renderMachine("yaml", raw) : JSON.stringify(raw, null, 2));
|
|
6366
6466
|
}
|
|
6367
6467
|
function printRecord(format, fields, raw) {
|
|
6368
6468
|
const machine = renderMachine(format, raw);
|
|
6369
6469
|
if (machine !== null) {
|
|
6370
|
-
|
|
6470
|
+
printLine(machine);
|
|
6371
6471
|
return;
|
|
6372
6472
|
}
|
|
6373
6473
|
const safeFields = fields.map(([label, value]) => [safeOneLine(label), value]);
|
|
6374
6474
|
if (format === "text") {
|
|
6375
6475
|
for (const [label, value] of safeFields) {
|
|
6376
|
-
|
|
6476
|
+
printLine(`${label} ${oneLine(stripAnsi(value))}`);
|
|
6377
6477
|
}
|
|
6378
6478
|
return;
|
|
6379
6479
|
}
|
|
6380
6480
|
const width = Math.max(...safeFields.map(([label]) => visibleWidth(label)));
|
|
6381
6481
|
for (const [label, value] of safeFields) {
|
|
6382
|
-
|
|
6482
|
+
printLine(`${styles3().dim(pad(`${label}:`, width + 1))} ${clamp(oneLine(value), MAX_RECORD_WIDTH)}`);
|
|
6383
6483
|
}
|
|
6384
6484
|
}
|
|
6385
6485
|
|
|
@@ -6475,7 +6575,7 @@ async function pollForKey(endpoint, auth, signal) {
|
|
|
6475
6575
|
headers: {
|
|
6476
6576
|
"content-type": "application/json",
|
|
6477
6577
|
accept: "application/json",
|
|
6478
|
-
"user-agent":
|
|
6578
|
+
"user-agent": userAgent()
|
|
6479
6579
|
},
|
|
6480
6580
|
body: JSON.stringify({ request: auth.request, verifier: auth.pollSecret }),
|
|
6481
6581
|
signal,
|
|
@@ -6486,7 +6586,7 @@ async function pollForKey(endpoint, auth, signal) {
|
|
|
6486
6586
|
consecutiveTransportFailures++;
|
|
6487
6587
|
if (!warnedAboutTransport && consecutiveTransportFailures >= TRANSPORT_FAILURES_BEFORE_WARNING) {
|
|
6488
6588
|
warnedAboutTransport = true;
|
|
6489
|
-
|
|
6589
|
+
writeStderr(`Still waiting: ${endpoint} is not answering the login poll (${cause.message}). Check the endpoint; retrying until you approve or the login times out.
|
|
6490
6590
|
`);
|
|
6491
6591
|
}
|
|
6492
6592
|
}
|
|
@@ -6636,8 +6736,8 @@ var V2_OPERATIONS = {
|
|
|
6636
6736
|
},
|
|
6637
6737
|
outputColumns: {
|
|
6638
6738
|
kind: "array",
|
|
6639
|
-
|
|
6640
|
-
describe: "Columns
|
|
6739
|
+
default: [],
|
|
6740
|
+
describe: "Columns to create for producer outputs. An entry naming a column the table already has attaches that column to the group instead of creating it (its `type` must match), and an output whose column already exists may omit its entry entirely — so `[]` attaches existing columns only."
|
|
6641
6741
|
},
|
|
6642
6742
|
autoRun: {
|
|
6643
6743
|
kind: "boolean",
|
|
@@ -6723,7 +6823,7 @@ var V2_OPERATIONS = {
|
|
|
6723
6823
|
summary: "Delete Files",
|
|
6724
6824
|
body: {
|
|
6725
6825
|
workspaceId: { kind: "string", required: true, describe: "Workspace containing the files." },
|
|
6726
|
-
fileIds: { kind: "array", required: true, describe: "File identifiers to
|
|
6826
|
+
fileIds: { kind: "array", required: true, describe: "File identifiers to delete." }
|
|
6727
6827
|
}
|
|
6728
6828
|
},
|
|
6729
6829
|
bulkDeleteTables: {
|
|
@@ -6941,7 +7041,7 @@ var V2_OPERATIONS = {
|
|
|
6941
7041
|
rowId: { kind: "string", describe: "Row whose runs should be canceled for row scope." },
|
|
6942
7042
|
filter: {
|
|
6943
7043
|
kind: "unknown",
|
|
6944
|
-
describe: '
|
|
7044
|
+
describe: 'A single `{ field, op, value }` condition or a recursive `all`/`any` group; either form is normalized to a grouped predicate after validation. At most 100 members per group, 10 levels of nesting, and 500 nodes in total. The negating operators include nulls: `ne`, `nin`, `ncontains`, `nlike`, and `nilike` match rows whose column is null or absent, so "not X" is not the complement of "X" over a nullable column. That holds for every column type, multi-select included. To exclude nulls, `all`-combine the negation with `isNotEmpty` (multi-select) or `isNotNull`. Comparison: `eq`, `ne`, `gt`, `gte`, `lt`, `lte`. Membership: `in`, `nin` (array operand). Emptiness: `isEmpty`, `isNotEmpty`, `isNull`, `isNotNull` (no operand). Substring, always case-insensitive, operand matched literally: `contains`, `ncontains`, `startsWith`, `endsWith`. Pattern: `like`/`nlike` (case-sensitive), `ilike`/`nilike` (case-insensitive). **`*` is the only wildcard** and stands for any run of characters; `%`, `_`, and backslash match themselves. Use `like: "Hi*"`, not `like: "Hi%"`. A `select` column compares by option id and restricts its operators: single-select accepts `eq`, `ne`, `in`, `nin`; multi-select accepts `contains`, `ncontains`. Option names are accepted as operands and resolved to ids.'
|
|
6945
7045
|
},
|
|
6946
7046
|
excludeRowIds: { kind: "array", describe: "Rows excluded from an all-scope cancellation." }
|
|
6947
7047
|
}
|
|
@@ -6972,6 +7072,11 @@ var V2_OPERATIONS = {
|
|
|
6972
7072
|
conversationId: {
|
|
6973
7073
|
kind: "string",
|
|
6974
7074
|
describe: "Conversation to continue; a new one starts when omitted."
|
|
7075
|
+
},
|
|
7076
|
+
effort: {
|
|
7077
|
+
kind: "enum",
|
|
7078
|
+
values: ["low", "medium", "high", "xhigh", "max"],
|
|
7079
|
+
describe: "Model effort for this turn; defaults to the deployment default (high)."
|
|
6975
7080
|
}
|
|
6976
7081
|
}
|
|
6977
7082
|
},
|
|
@@ -7534,7 +7639,7 @@ var V2_OPERATIONS = {
|
|
|
7534
7639
|
description: { kind: "string", describe: "Optional credential description." },
|
|
7535
7640
|
id: {
|
|
7536
7641
|
kind: "string",
|
|
7537
|
-
describe: "
|
|
7642
|
+
describe: "Optional client-generated credential ID. The server mints one when it is omitted, so no provider requires it. A `slack-custom-bot` credential may supply one so its Slack Request URL, which embeds the ID, can be configured before the credential exists; every other provider ignores it."
|
|
7538
7643
|
},
|
|
7539
7644
|
credentials: {
|
|
7540
7645
|
kind: "string",
|
|
@@ -7610,7 +7715,7 @@ var V2_OPERATIONS = {
|
|
|
7610
7715
|
rowIds: { kind: "array", describe: "Explicit row subset to run." },
|
|
7611
7716
|
filter: {
|
|
7612
7717
|
kind: "unknown",
|
|
7613
|
-
describe: '
|
|
7718
|
+
describe: 'A single `{ field, op, value }` condition or a recursive `all`/`any` group; either form is normalized to a grouped predicate after validation. At most 100 members per group, 10 levels of nesting, and 500 nodes in total. The negating operators include nulls: `ne`, `nin`, `ncontains`, `nlike`, and `nilike` match rows whose column is null or absent, so "not X" is not the complement of "X" over a nullable column. That holds for every column type, multi-select included. To exclude nulls, `all`-combine the negation with `isNotEmpty` (multi-select) or `isNotNull`. Comparison: `eq`, `ne`, `gt`, `gte`, `lt`, `lte`. Membership: `in`, `nin` (array operand). Emptiness: `isEmpty`, `isNotEmpty`, `isNull`, `isNotNull` (no operand). Substring, always case-insensitive, operand matched literally: `contains`, `ncontains`, `startsWith`, `endsWith`. Pattern: `like`/`nlike` (case-sensitive), `ilike`/`nilike` (case-insensitive). **`*` is the only wildcard** and stands for any run of characters; `%`, `_`, and backslash match themselves. Use `like: "Hi*"`, not `like: "Hi%"`. A `select` column compares by option id and restricts its operators: single-select accepts `eq`, `ne`, `in`, `nin`; multi-select accepts `contains`, `ncontains`. Option names are accepted as operands and resolved to ids.'
|
|
7614
7719
|
},
|
|
7615
7720
|
excludeRowIds: { kind: "array", describe: "Rows excluded from a select-all run scope." },
|
|
7616
7721
|
limit: { kind: "object", describe: "Optional cap on eligible rows to run." }
|
|
@@ -8144,7 +8249,7 @@ var V2_OPERATIONS = {
|
|
|
8144
8249
|
workspaceId: { kind: "string", required: true, describe: "Unique workspace identifier." },
|
|
8145
8250
|
filter: {
|
|
8146
8251
|
kind: "unknown",
|
|
8147
|
-
describe: '
|
|
8252
|
+
describe: 'A single `{ field, op, value }` condition or a recursive `all`/`any` group; either form is normalized to a grouped predicate after validation. At most 100 members per group, 10 levels of nesting, and 500 nodes in total. The negating operators include nulls: `ne`, `nin`, `ncontains`, `nlike`, and `nilike` match rows whose column is null or absent, so "not X" is not the complement of "X" over a nullable column. That holds for every column type, multi-select included. To exclude nulls, `all`-combine the negation with `isNotEmpty` (multi-select) or `isNotNull`. Comparison: `eq`, `ne`, `gt`, `gte`, `lt`, `lte`. Membership: `in`, `nin` (array operand). Emptiness: `isEmpty`, `isNotEmpty`, `isNull`, `isNotNull` (no operand). Substring, always case-insensitive, operand matched literally: `contains`, `ncontains`, `startsWith`, `endsWith`. Pattern: `like`/`nlike` (case-sensitive), `ilike`/`nilike` (case-insensitive). **`*` is the only wildcard** and stands for any run of characters; `%`, `_`, and backslash match themselves. Use `like: "Hi*"`, not `like: "Hi%"`. A `select` column compares by option id and restricts its operators: single-select accepts `eq`, `ne`, `in`, `nin`; multi-select accepts `contains`, `ncontains`. Option names are accepted as operands and resolved to ids.'
|
|
8148
8253
|
},
|
|
8149
8254
|
limit: { kind: "integer", describe: "Maximum matching rows to delete." },
|
|
8150
8255
|
rowIds: { kind: "array", describe: "Explicit row identifiers to delete." }
|
|
@@ -8393,7 +8498,7 @@ var V2_OPERATIONS = {
|
|
|
8393
8498
|
},
|
|
8394
8499
|
selectedOutputs: {
|
|
8395
8500
|
kind: "array",
|
|
8396
|
-
describe: "Block output references to include in
|
|
8501
|
+
describe: "Block output references to include in the response. Use `<blockName>.<outputPath>` for the executed workflow or `<childWorkflowId>.<blockName>.<outputPath>` for a child workflow; block names are normalized workflow reference names, and selecting a child workflow applies to every invocation of it. On a sync request the named outputs come back in `blockOutputs`, keyed by these selector strings exactly as sent; on a stream they shape the streamed envelope. A selector whose block name or id matches no block in the workflow is rejected with `400` naming the available blocks, before the run starts. A selector whose block did not run or whose path is absent is omitted. Rejected when `async` is true — a queued run has produced nothing to select; narrow the finished run via the run resource instead."
|
|
8397
8502
|
},
|
|
8398
8503
|
includeThinking: {
|
|
8399
8504
|
kind: "boolean",
|
|
@@ -8431,7 +8536,13 @@ var V2_OPERATIONS = {
|
|
|
8431
8536
|
pathParams: ["workflowId"],
|
|
8432
8537
|
pathParamDocs: { workflowId: "Unique workflow identifier." },
|
|
8433
8538
|
responseMode: "json",
|
|
8434
|
-
summary: "Export Workflow"
|
|
8539
|
+
summary: "Export Workflow",
|
|
8540
|
+
query: {
|
|
8541
|
+
includeWorkspaceBindings: {
|
|
8542
|
+
kind: "boolean",
|
|
8543
|
+
describe: "Whether to keep workspace-scoped bindings — table, knowledge base, document, folder, channel, and other resource selectors — in the exported state. Defaults to false, the sharing-safe export in which those ids are cleared because they resolve nowhere else. Send true for a same-workspace round trip so the re-imported workflow can run without re-selecting them. Credentials, passwords, and table sub-block values are cleared either way."
|
|
8544
|
+
}
|
|
8545
|
+
}
|
|
8435
8546
|
},
|
|
8436
8547
|
getAuditLog: {
|
|
8437
8548
|
method: "GET",
|
|
@@ -8652,6 +8763,10 @@ var V2_OPERATIONS = {
|
|
|
8652
8763
|
values: ["info", "error"],
|
|
8653
8764
|
describe: "Severity level to include."
|
|
8654
8765
|
},
|
|
8766
|
+
includeHandledErrors: {
|
|
8767
|
+
kind: "boolean",
|
|
8768
|
+
describe: "Whether runs with a handled block error are counted as `handledErrorRuns`, and whether `level=error` also selects them. Off by default: counting them scans each run’s stored trace."
|
|
8769
|
+
},
|
|
8655
8770
|
startDate: {
|
|
8656
8771
|
kind: "string",
|
|
8657
8772
|
describe: "Only include runs started at or after this UTC ISO 8601 timestamp, e.g. `2026-08-06T00:00:00Z`. A date without a time, or a timestamp carrying a UTC offset instead of `Z`, is rejected, as is year `0000`, which names no storable instant."
|
|
@@ -8663,7 +8778,26 @@ var V2_OPERATIONS = {
|
|
|
8663
8778
|
segmentCount: {
|
|
8664
8779
|
kind: "integer",
|
|
8665
8780
|
default: 72,
|
|
8666
|
-
describe: "Number of equal time buckets to divide the window into, from 1 to 500.
|
|
8781
|
+
describe: "Number of equal time buckets to divide the window into, from 1 to 500. It is the ceiling on how many buckets a series carries: with `includeEmpty=true` exactly this many are returned, otherwise only the buckets holding at least one run. Buckets are never narrower than one minute, so on a short window the series extends past the end of the window rather than being compressed, and the trailing buckets are empty."
|
|
8782
|
+
},
|
|
8783
|
+
includeEmpty: {
|
|
8784
|
+
kind: "enum",
|
|
8785
|
+
values: [
|
|
8786
|
+
"true",
|
|
8787
|
+
"1",
|
|
8788
|
+
"yes",
|
|
8789
|
+
"on",
|
|
8790
|
+
"y",
|
|
8791
|
+
"enabled",
|
|
8792
|
+
"false",
|
|
8793
|
+
"0",
|
|
8794
|
+
"no",
|
|
8795
|
+
"off",
|
|
8796
|
+
"n",
|
|
8797
|
+
"disabled"
|
|
8798
|
+
],
|
|
8799
|
+
default: false,
|
|
8800
|
+
describe: "Whether buckets with no runs are included in every series. Off by default, so each series carries only the buckets that hold at least one run; set it to publish exactly `segmentCount` buckets per series, empty ones included. The listed spellings are the whole accepted vocabulary and are case-sensitive; any other value is rejected."
|
|
8667
8801
|
}
|
|
8668
8802
|
}
|
|
8669
8803
|
},
|
|
@@ -8721,7 +8855,7 @@ var V2_OPERATIONS = {
|
|
|
8721
8855
|
groupId: "Workflow or enrichment group to run."
|
|
8722
8856
|
},
|
|
8723
8857
|
responseMode: "json",
|
|
8724
|
-
summary: "Get
|
|
8858
|
+
summary: "Get Row Group Run",
|
|
8725
8859
|
query: {
|
|
8726
8860
|
workspaceId: { kind: "string", required: true, describe: "Workspace that owns the table." }
|
|
8727
8861
|
}
|
|
@@ -9121,6 +9255,10 @@ var V2_OPERATIONS = {
|
|
|
9121
9255
|
values: ["builtin", "custom"],
|
|
9122
9256
|
describe: "Restrict to shipped blocks or to this workspace’s deployed custom blocks."
|
|
9123
9257
|
},
|
|
9258
|
+
includeSunset: {
|
|
9259
|
+
kind: "boolean",
|
|
9260
|
+
describe: "Include `legacy` and `deprecated` blocks. Off by default: a sunset block keeps executing where it is already placed, but it is not offered for new authoring. Each returned entry carries `sunset.replacedBy`, the block to build with instead."
|
|
9261
|
+
},
|
|
9124
9262
|
sortBy: {
|
|
9125
9263
|
kind: "enum",
|
|
9126
9264
|
values: ["id", "name", "category"],
|
|
@@ -9196,6 +9334,21 @@ var V2_OPERATIONS = {
|
|
|
9196
9334
|
search: {
|
|
9197
9335
|
kind: "string",
|
|
9198
9336
|
describe: "Case-insensitive substring match against the connector name."
|
|
9337
|
+
},
|
|
9338
|
+
detail: {
|
|
9339
|
+
kind: "enum",
|
|
9340
|
+
values: ["summary", "full"],
|
|
9341
|
+
default: "summary",
|
|
9342
|
+
describe: "Projection of each item. `summary` (the default) carries the identifier, name, description, and auth mode; `full` adds the version, the complete auth settings, the `sourceConfig` field schema, incremental-sync support, and tag definitions."
|
|
9343
|
+
},
|
|
9344
|
+
limit: {
|
|
9345
|
+
kind: "integer",
|
|
9346
|
+
default: 25,
|
|
9347
|
+
describe: "Maximum connector types to return per page. Must be a whole number from 1 to 100. Defaults to 25."
|
|
9348
|
+
},
|
|
9349
|
+
cursor: {
|
|
9350
|
+
kind: "string",
|
|
9351
|
+
describe: "Opaque cursor from the previous page. Send it back with the same sort and filters; only `limit` may change. Change anything else and pagination must restart without a cursor."
|
|
9199
9352
|
}
|
|
9200
9353
|
}
|
|
9201
9354
|
},
|
|
@@ -9797,6 +9950,10 @@ var V2_OPERATIONS = {
|
|
|
9797
9950
|
kind: "string",
|
|
9798
9951
|
describe: "Opaque cursor from the previous page. Send it back with the same sort and filters; only `limit` may change. Change anything else and pagination must restart without a cursor."
|
|
9799
9952
|
},
|
|
9953
|
+
includeHandledErrors: {
|
|
9954
|
+
kind: "boolean",
|
|
9955
|
+
describe: "Whether `level=error` also selects runs that finished at `info` after a block error was recovered by an error path. Off by default: such a run succeeded, so it is an error only to a caller auditing error handling. Every row reports `hasHandledErrors` whether or not this is set. Job runs carry no block trace, so the flag never widens that branch."
|
|
9956
|
+
},
|
|
9800
9957
|
status: {
|
|
9801
9958
|
kind: "string",
|
|
9802
9959
|
describe: "Comma-separated execution statuses to include, from `pending` | `running` | `paused` | `redacting` | `completed` | `failed` | `cancelled`. An empty entry is rejected. ANDed with `level`, which reports severity rather than lifecycle."
|
|
@@ -10042,7 +10199,7 @@ var V2_OPERATIONS = {
|
|
|
10042
10199
|
pathParams: ["tableId"],
|
|
10043
10200
|
pathParamDocs: { tableId: "Unique table identifier." },
|
|
10044
10201
|
responseMode: "json",
|
|
10045
|
-
summary: "List
|
|
10202
|
+
summary: "List Run Dispatches",
|
|
10046
10203
|
query: {
|
|
10047
10204
|
workspaceId: { kind: "string", required: true, describe: "Workspace that owns the table." }
|
|
10048
10205
|
}
|
|
@@ -10454,8 +10611,8 @@ var V2_OPERATIONS = {
|
|
|
10454
10611
|
},
|
|
10455
10612
|
limit: {
|
|
10456
10613
|
kind: "integer",
|
|
10457
|
-
default:
|
|
10458
|
-
describe: "Maximum workspaces to return per page. Must be a whole number from 1 to 100. Defaults to
|
|
10614
|
+
default: 25,
|
|
10615
|
+
describe: "Maximum workspaces to return per page. Must be a whole number from 1 to 100. Defaults to 25."
|
|
10459
10616
|
},
|
|
10460
10617
|
cursor: {
|
|
10461
10618
|
kind: "string",
|
|
@@ -10567,7 +10724,9 @@ var V2_OPERATIONS = {
|
|
|
10567
10724
|
method: "GET",
|
|
10568
10725
|
path: "/api/v2/files/[fileId]/text",
|
|
10569
10726
|
pathParams: ["fileId"],
|
|
10570
|
-
pathParamDocs: {
|
|
10727
|
+
pathParamDocs: {
|
|
10728
|
+
fileId: "File identifier, or the file’s VFS path: `files/<folder>/<name>`, or `uploads/<name>` for a Chat upload."
|
|
10729
|
+
},
|
|
10571
10730
|
responseMode: "json",
|
|
10572
10731
|
summary: "Read File Text",
|
|
10573
10732
|
query: {
|
|
@@ -10598,7 +10757,7 @@ var V2_OPERATIONS = {
|
|
|
10598
10757
|
destinationPath: {
|
|
10599
10758
|
kind: "string",
|
|
10600
10759
|
required: true,
|
|
10601
|
-
describe: "
|
|
10760
|
+
describe: "Where the folder lands, with `mv` semantics. A path naming an existing folder receives the source as a child under its current name; `/` moves it to the workspace root under its current name; any other path becomes the folder’s new full path (a rename, a relocation, or both)."
|
|
10602
10761
|
}
|
|
10603
10762
|
}
|
|
10604
10763
|
},
|
|
@@ -10614,7 +10773,7 @@ var V2_OPERATIONS = {
|
|
|
10614
10773
|
destinationPath: {
|
|
10615
10774
|
kind: "string",
|
|
10616
10775
|
required: true,
|
|
10617
|
-
describe: "
|
|
10776
|
+
describe: "Where the folder lands, with `mv` semantics. A path naming an existing folder receives the source as a child under its current name; `/` moves it to the workspace root under its current name; any other path becomes the folder’s new full path (a rename, a relocation, or both)."
|
|
10618
10777
|
}
|
|
10619
10778
|
}
|
|
10620
10779
|
},
|
|
@@ -10630,7 +10789,7 @@ var V2_OPERATIONS = {
|
|
|
10630
10789
|
destinationPath: {
|
|
10631
10790
|
kind: "string",
|
|
10632
10791
|
required: true,
|
|
10633
|
-
describe: "
|
|
10792
|
+
describe: "Where the folder lands, with `mv` semantics. A path naming an existing folder receives the source as a child under its current name; `/` moves it to the workspace root under its current name; any other path becomes the folder’s new full path (a rename, a relocation, or both)."
|
|
10634
10793
|
}
|
|
10635
10794
|
}
|
|
10636
10795
|
},
|
|
@@ -10646,7 +10805,7 @@ var V2_OPERATIONS = {
|
|
|
10646
10805
|
destinationPath: {
|
|
10647
10806
|
kind: "string",
|
|
10648
10807
|
required: true,
|
|
10649
|
-
describe: "
|
|
10808
|
+
describe: "Where the folder lands, with `mv` semantics. A path naming an existing folder receives the source as a child under its current name; `/` moves it to the workspace root under its current name; any other path becomes the folder’s new full path (a rename, a relocation, or both)."
|
|
10650
10809
|
}
|
|
10651
10810
|
}
|
|
10652
10811
|
},
|
|
@@ -11019,7 +11178,7 @@ var V2_OPERATIONS = {
|
|
|
11019
11178
|
q: { kind: "string", required: true, describe: "Case-insensitive cell substring to find." },
|
|
11020
11179
|
predicate: {
|
|
11021
11180
|
kind: "unknown",
|
|
11022
|
-
describe: '
|
|
11181
|
+
describe: 'A single `{ field, op, value }` condition or a recursive `all`/`any` group; either form is normalized to a grouped predicate after validation. At most 100 members per group, 10 levels of nesting, and 500 nodes in total. The negating operators include nulls: `ne`, `nin`, `ncontains`, `nlike`, and `nilike` match rows whose column is null or absent, so "not X" is not the complement of "X" over a nullable column. That holds for every column type, multi-select included. To exclude nulls, `all`-combine the negation with `isNotEmpty` (multi-select) or `isNotNull`. Comparison: `eq`, `ne`, `gt`, `gte`, `lt`, `lte`. Membership: `in`, `nin` (array operand). Emptiness: `isEmpty`, `isNotEmpty`, `isNull`, `isNotNull` (no operand). Substring, always case-insensitive, operand matched literally: `contains`, `ncontains`, `startsWith`, `endsWith`. Pattern: `like`/`nlike` (case-sensitive), `ilike`/`nilike` (case-insensitive). **`*` is the only wildcard** and stands for any run of characters; `%`, `_`, and backslash match themselves. Use `like: "Hi*"`, not `like: "Hi%"`. A `select` column compares by option id and restricts its operators: single-select accepts `eq`, `ne`, `in`, `nin`; multi-select accepts `contains`, `ncontains`. Option names are accepted as operands and resolved to ids.'
|
|
11023
11182
|
},
|
|
11024
11183
|
sort: { kind: "array", describe: "Ordered table-row sort specification." }
|
|
11025
11184
|
}
|
|
@@ -11461,7 +11620,7 @@ var V2_OPERATIONS = {
|
|
|
11461
11620
|
filter: {
|
|
11462
11621
|
kind: "unknown",
|
|
11463
11622
|
required: true,
|
|
11464
|
-
describe: '
|
|
11623
|
+
describe: 'A single `{ field, op, value }` condition or a recursive `all`/`any` group; either form is normalized to a grouped predicate after validation. At most 100 members per group, 10 levels of nesting, and 500 nodes in total. The negating operators include nulls: `ne`, `nin`, `ncontains`, `nlike`, and `nilike` match rows whose column is null or absent, so "not X" is not the complement of "X" over a nullable column. That holds for every column type, multi-select included. To exclude nulls, `all`-combine the negation with `isNotEmpty` (multi-select) or `isNotNull`. Comparison: `eq`, `ne`, `gt`, `gte`, `lt`, `lte`. Membership: `in`, `nin` (array operand). Emptiness: `isEmpty`, `isNotEmpty`, `isNull`, `isNotNull` (no operand). Substring, always case-insensitive, operand matched literally: `contains`, `ncontains`, `startsWith`, `endsWith`. Pattern: `like`/`nlike` (case-sensitive), `ilike`/`nilike` (case-insensitive). **`*` is the only wildcard** and stands for any run of characters; `%`, `_`, and backslash match themselves. Use `like: "Hi*"`, not `like: "Hi%"`. A `select` column compares by option id and restricts its operators: single-select accepts `eq`, `ne`, `in`, `nin`; multi-select accepts `contains`, `ncontains`. Option names are accepted as operands and resolved to ids.'
|
|
11465
11624
|
},
|
|
11466
11625
|
data: {
|
|
11467
11626
|
kind: "object",
|
|
@@ -11843,10 +12002,10 @@ async function chooseWorkspace(client) {
|
|
|
11843
12002
|
if (workspaces.length > MAX_INTERACTIVE_WORKSPACES) {
|
|
11844
12003
|
throw new SimApiError(`The active API key can access more than ${MAX_INTERACTIVE_WORKSPACES} workspaces, which is too many to show interactively. Pass --workspace <id> instead.`, 0);
|
|
11845
12004
|
}
|
|
11846
|
-
|
|
12005
|
+
printLine(`
|
|
11847
12006
|
Available workspaces:`);
|
|
11848
12007
|
for (const [index, workspace] of workspaces.entries()) {
|
|
11849
|
-
|
|
12008
|
+
printLine(` ${index + 1}) ${safeOneLine(workspace.name)} (${workspace.id})`);
|
|
11850
12009
|
}
|
|
11851
12010
|
const prompt = createInterface({ input: process.stdin, output: process.stderr });
|
|
11852
12011
|
try {
|
|
@@ -11871,10 +12030,10 @@ function addProfileCommand() {
|
|
|
11871
12030
|
auth_profile: authProfile,
|
|
11872
12031
|
workspace: normalizeWorkspaceId(workspace.id, "the workspace response")
|
|
11873
12032
|
});
|
|
11874
|
-
|
|
11875
|
-
|
|
11876
|
-
|
|
11877
|
-
|
|
12033
|
+
printLine(styles3().green(`✓ Added profile "${safeOneLine(profileName)}" in ${configPath()}`));
|
|
12034
|
+
printLine(` Workspace: ${safeOneLine(workspace.name)} (${workspace.id})`);
|
|
12035
|
+
printLine(` Authentication: ${safeOneLine(authProfile)}`);
|
|
12036
|
+
printLine(styles3().dim(` Try: sim --profile ${safeOneLine(profileName)} whoami`));
|
|
11878
12037
|
});
|
|
11879
12038
|
}
|
|
11880
12039
|
function loginCommand() {
|
|
@@ -11891,21 +12050,21 @@ function loginCommand() {
|
|
|
11891
12050
|
if (readCredentialsProfile(profile.name).api_key && !options.yes) {
|
|
11892
12051
|
const confirmed = await confirmProfileOverwrite(profile.name);
|
|
11893
12052
|
if (!confirmed) {
|
|
11894
|
-
|
|
12053
|
+
printLine(styles3().dim("Login cancelled; the existing profile was not changed."));
|
|
11895
12054
|
return;
|
|
11896
12055
|
}
|
|
11897
12056
|
}
|
|
11898
12057
|
const auth = createAuthRequest();
|
|
11899
12058
|
const url = buildApprovalUrl(profile.endpoint, auth, scope, profile.workspaceId ?? undefined);
|
|
11900
|
-
|
|
11901
|
-
|
|
11902
|
-
Pairing code: ${
|
|
11903
|
-
|
|
12059
|
+
printLine(`Signing in to ${styles3().bold(profile.endpoint)} as profile ${styles3().bold(safeOneLine(profile.name))}`);
|
|
12060
|
+
printLine(`
|
|
12061
|
+
Pairing code: ${styles3().bold(auth.pairing)}`);
|
|
12062
|
+
printLine(styles3().dim(`Confirm this code matches what the browser shows before approving.
|
|
11904
12063
|
`));
|
|
11905
|
-
|
|
12064
|
+
printLine(url);
|
|
11906
12065
|
if (options.browser)
|
|
11907
12066
|
openBrowser(url);
|
|
11908
|
-
|
|
12067
|
+
printLine(styles3().dim(`
|
|
11909
12068
|
Waiting for approval…`));
|
|
11910
12069
|
const key = await pollForKey(profile.endpoint, auth);
|
|
11911
12070
|
if (key.scope !== scope) {
|
|
@@ -11918,14 +12077,14 @@ Waiting for approval…`));
|
|
|
11918
12077
|
requireStorableKey(key.apiKey);
|
|
11919
12078
|
writeConfigProfile(profile.name, settings);
|
|
11920
12079
|
writeCredentialsProfile(profile.name, key.apiKey);
|
|
11921
|
-
|
|
12080
|
+
printLine(styles3().green(`
|
|
11922
12081
|
✓ Logged in. Key stored in ${credentialsPath()}`));
|
|
11923
12082
|
if (key.workspaceBound && key.workspaceId) {
|
|
11924
|
-
|
|
12083
|
+
printLine(styles3().dim(` Workspace-scoped key — it can only reach ${key.workspaceId}.`));
|
|
11925
12084
|
} else if (key.workspaceId) {
|
|
11926
|
-
|
|
12085
|
+
printLine(styles3().dim(` Personal key, defaulting to ${key.workspaceId}. Override per command with --workspace.`));
|
|
11927
12086
|
} else {
|
|
11928
|
-
|
|
12087
|
+
printLine(styles3().dim(" Personal key with no default workspace. Set one with: sim configure --set-workspace <id>"));
|
|
11929
12088
|
}
|
|
11930
12089
|
});
|
|
11931
12090
|
}
|
|
@@ -11939,10 +12098,10 @@ function logoutCommand() {
|
|
|
11939
12098
|
}
|
|
11940
12099
|
const removed = deleteProfile(profileName);
|
|
11941
12100
|
if (!removed.config && !removed.credentials) {
|
|
11942
|
-
|
|
12101
|
+
printLine(styles3().dim(`Nothing stored for profile "${safeOneLine(profileName)}".`));
|
|
11943
12102
|
return;
|
|
11944
12103
|
}
|
|
11945
|
-
|
|
12104
|
+
printLine(styles3().green(`✓ Removed profile "${safeOneLine(profileName)}".`));
|
|
11946
12105
|
return;
|
|
11947
12106
|
}
|
|
11948
12107
|
const profile = profileFrom(command);
|
|
@@ -11951,12 +12110,12 @@ function logoutCommand() {
|
|
|
11951
12110
|
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);
|
|
11952
12111
|
}
|
|
11953
12112
|
if (!readCredentialsProfile(profile.name).api_key) {
|
|
11954
|
-
|
|
12113
|
+
printLine(styles3().dim(`No stored key for profile "${safeOneLine(profile.name)}".`));
|
|
11955
12114
|
return;
|
|
11956
12115
|
}
|
|
11957
12116
|
writeCredentialsProfile(profile.name, null);
|
|
11958
|
-
|
|
11959
|
-
|
|
12117
|
+
printLine(styles3().green(`✓ Removed the stored key for profile "${safeOneLine(profile.name)}".`));
|
|
12118
|
+
printLine(styles3().dim(" The key itself is still active — revoke it in Settings → Sim API keys."));
|
|
11960
12119
|
});
|
|
11961
12120
|
}
|
|
11962
12121
|
async function readKeyType(client) {
|
|
@@ -12017,18 +12176,18 @@ function presentVerification(verification) {
|
|
|
12017
12176
|
if (verification.status === "verified") {
|
|
12018
12177
|
const { name, memberCount } = verification.workspace;
|
|
12019
12178
|
const members = `${memberCount} ${memberCount === 1 ? "member" : "members"}`;
|
|
12020
|
-
return `${
|
|
12179
|
+
return `${styles3().green("✓")} ${safeOneLine(name)} · ${members}`;
|
|
12021
12180
|
}
|
|
12022
12181
|
const detail = safeOneLine(verification.detail);
|
|
12023
12182
|
switch (verification.status) {
|
|
12024
12183
|
case "rejected":
|
|
12025
|
-
return `${
|
|
12184
|
+
return `${styles3().red("✗")} ${detail}`;
|
|
12026
12185
|
case "unauthenticated":
|
|
12027
|
-
return
|
|
12186
|
+
return styles3().yellow(`not logged in — ${detail}`);
|
|
12028
12187
|
case "disabled":
|
|
12029
|
-
return
|
|
12188
|
+
return styles3().dim(detail);
|
|
12030
12189
|
default:
|
|
12031
|
-
return
|
|
12190
|
+
return styles3().yellow(`could not check — ${detail}`);
|
|
12032
12191
|
}
|
|
12033
12192
|
}
|
|
12034
12193
|
function whoamiCommand() {
|
|
@@ -12042,17 +12201,17 @@ function whoamiCommand() {
|
|
|
12042
12201
|
keyType: null,
|
|
12043
12202
|
detail: "not checked (--no-verify)"
|
|
12044
12203
|
};
|
|
12045
|
-
const annotate = (value, source) => source === "unset" ?
|
|
12204
|
+
const annotate = (value, source) => source === "unset" ? styles3().dim("not set") : `${value} ${styles3().dim(`(${source})`)}`;
|
|
12046
12205
|
printRecord(profile.output, [
|
|
12047
12206
|
["Profile", profile.name],
|
|
12048
12207
|
["Endpoint", annotate(profile.endpoint, sources.endpoint)],
|
|
12049
12208
|
[
|
|
12050
12209
|
"API key",
|
|
12051
|
-
authentication.authenticated ? annotate("configured", authentication.source) :
|
|
12210
|
+
authentication.authenticated ? annotate("configured", authentication.source) : styles3().yellow("not logged in")
|
|
12052
12211
|
],
|
|
12053
12212
|
[
|
|
12054
12213
|
"Key type",
|
|
12055
|
-
verification.keyType ??
|
|
12214
|
+
verification.keyType ?? styles3().dim(options.verify ? "unknown" : "not checked (--no-verify)")
|
|
12056
12215
|
],
|
|
12057
12216
|
["Workspace", annotate(profile.workspaceId ?? "", sources.workspaceId)],
|
|
12058
12217
|
["Output", annotate(profile.output, sources.output)],
|
|
@@ -12078,15 +12237,18 @@ function whoamiCommand() {
|
|
|
12078
12237
|
});
|
|
12079
12238
|
const exitCode = WHOAMI_EXIT_CODES[verification.status];
|
|
12080
12239
|
if (exitCode !== 0)
|
|
12081
|
-
|
|
12240
|
+
setSoftExitCode(exitCode);
|
|
12082
12241
|
});
|
|
12083
12242
|
}
|
|
12084
12243
|
var PROFILE_COLUMNS = [
|
|
12085
|
-
{ header: "", value: (row) => row.active ?
|
|
12244
|
+
{ header: "", value: (row) => row.active ? styles3().green("*") : " " },
|
|
12086
12245
|
{ header: "profile", value: (row) => safeOneLine(row.name) },
|
|
12087
12246
|
{ header: "key", value: (row) => row.error ? text(null) : row.hasKey ? "yes" : "no" },
|
|
12088
12247
|
{ header: "auth", value: (row) => row.authProfile ? safeOneLine(row.authProfile) : text(null) },
|
|
12089
|
-
{
|
|
12248
|
+
{
|
|
12249
|
+
header: "error",
|
|
12250
|
+
value: (row) => row.error ? styles3().red(safeOneLine(row.error)) : text(null)
|
|
12251
|
+
}
|
|
12090
12252
|
];
|
|
12091
12253
|
function buildProfileRow(name, active) {
|
|
12092
12254
|
try {
|
|
@@ -12133,7 +12295,7 @@ function profilesCommand() {
|
|
|
12133
12295
|
const rows = listProfiles().map((name) => buildProfileRow(name, name === activeName));
|
|
12134
12296
|
if (rows.length === 0) {
|
|
12135
12297
|
if (output === "table")
|
|
12136
|
-
|
|
12298
|
+
printLine(styles3().dim("No profiles yet. Run: sim login"));
|
|
12137
12299
|
else
|
|
12138
12300
|
printList(output, rows, PROFILE_COLUMNS);
|
|
12139
12301
|
return;
|
|
@@ -12213,21 +12375,21 @@ function configureCommand() {
|
|
|
12213
12375
|
if (Object.keys(updates).length === 0) {
|
|
12214
12376
|
const current = readConfigProfile(profile.name);
|
|
12215
12377
|
if (Object.keys(current).length === 0) {
|
|
12216
|
-
|
|
12378
|
+
printLine(styles3().dim(`No settings stored for profile "${profile.name}".`));
|
|
12217
12379
|
return;
|
|
12218
12380
|
}
|
|
12219
12381
|
for (const [key, value] of Object.entries(current)) {
|
|
12220
|
-
|
|
12382
|
+
printLine(`${styles3().dim(`${key}:`)} ${value}`);
|
|
12221
12383
|
}
|
|
12222
12384
|
return;
|
|
12223
12385
|
}
|
|
12224
12386
|
const removalOnly = Object.values(updates).every((value) => value === null);
|
|
12225
12387
|
if (removalOnly && Object.keys(readConfigProfile(profile.name)).length === 0) {
|
|
12226
|
-
|
|
12388
|
+
printLine(styles3().dim(`No settings stored for profile "${profile.name}".`));
|
|
12227
12389
|
return;
|
|
12228
12390
|
}
|
|
12229
12391
|
writeConfigProfile(profile.name, updates);
|
|
12230
|
-
|
|
12392
|
+
printLine(styles3().green(`✓ Updated profile "${profile.name}" in ${configPath()}`));
|
|
12231
12393
|
});
|
|
12232
12394
|
}
|
|
12233
12395
|
|
|
@@ -12451,7 +12613,7 @@ var CLI_CONTRACT = {
|
|
|
12451
12613
|
},
|
|
12452
12614
|
deleteTableView: { confirm: "This deletes the saved view and its filters." },
|
|
12453
12615
|
deleteWorkflowGroup: {
|
|
12454
|
-
confirm: "This deletes the group
|
|
12616
|
+
confirm: "This deletes the group AND its output columns with all of their row data; the workflow it pointed at is untouched.",
|
|
12455
12617
|
fields: [
|
|
12456
12618
|
{ header: "id" },
|
|
12457
12619
|
{ header: "deleted", format: "bool" },
|
|
@@ -12571,7 +12733,7 @@ var CLI_CONTRACT = {
|
|
|
12571
12733
|
},
|
|
12572
12734
|
applyWorkflowOperations: {
|
|
12573
12735
|
command: "workflows operations apply",
|
|
12574
|
-
confirm: "This edits the draft graph
|
|
12736
|
+
confirm: "This edits the draft graph: the batch adds, edits, or deletes blocks and their edges as written.",
|
|
12575
12737
|
flags: {
|
|
12576
12738
|
operations: { json: true, describe: WORKFLOW_OPERATIONS_HELP },
|
|
12577
12739
|
setBlockEnabled: { json: true, describe: WORKFLOW_SET_BLOCK_ENABLED_HELP }
|
|
@@ -13360,7 +13522,7 @@ var CLI_CONTRACT = {
|
|
|
13360
13522
|
selectedOutputs: {
|
|
13361
13523
|
name: "select-output",
|
|
13362
13524
|
list: true,
|
|
13363
|
-
describe: "Return
|
|
13525
|
+
describe: "Return blockName.path values (e.g. agent_1.content), or childWorkflowId.blockName.path for a child workflow (applies to every invocation) — in blockOutputs on a sync run, or from the streamed result with --follow; missing paths are omitted. Not available with --async"
|
|
13364
13526
|
},
|
|
13365
13527
|
stream: { omit: true },
|
|
13366
13528
|
includeThinking: { omit: true },
|
|
@@ -13384,7 +13546,7 @@ var CLI_CONTRACT = {
|
|
|
13384
13546
|
selectedOutputs: {
|
|
13385
13547
|
name: "select-output",
|
|
13386
13548
|
list: true,
|
|
13387
|
-
describe: "Include
|
|
13549
|
+
describe: "Include blockName.path or blockId.path values (e.g. agent_1.content) in JSON or YAML output; names resolve against the workflow’s current blocks, and missing paths are omitted"
|
|
13388
13550
|
}
|
|
13389
13551
|
},
|
|
13390
13552
|
fields: [
|
|
@@ -13492,6 +13654,87 @@ function camel(flag) {
|
|
|
13492
13654
|
|
|
13493
13655
|
// src/runtime/request.ts
|
|
13494
13656
|
import { existsSync as existsSync2, readFileSync as readFileSync3, readSync } from "node:fs";
|
|
13657
|
+
|
|
13658
|
+
// src/transfer/local-file.ts
|
|
13659
|
+
import { constants } from "node:fs";
|
|
13660
|
+
import { access, stat } from "node:fs/promises";
|
|
13661
|
+
import { basename } from "node:path";
|
|
13662
|
+
function embeddedFileKey(path) {
|
|
13663
|
+
return path.startsWith("@") ? path.slice(1) : path;
|
|
13664
|
+
}
|
|
13665
|
+
async function embeddedFileContent(embedded, path) {
|
|
13666
|
+
const key = embeddedFileKey(path);
|
|
13667
|
+
embedded.identity.signal?.throwIfAborted();
|
|
13668
|
+
if (!embedded.readFile)
|
|
13669
|
+
throw new SimApiError("This invocation has no machine to read from", 0);
|
|
13670
|
+
const content = await embedded.readFile(key);
|
|
13671
|
+
embedded.identity.signal?.throwIfAborted();
|
|
13672
|
+
return typeof content === "string" ? content : new Uint8Array(content);
|
|
13673
|
+
}
|
|
13674
|
+
var CONTENT_TYPES = {
|
|
13675
|
+
css: "text/css",
|
|
13676
|
+
csv: "text/csv",
|
|
13677
|
+
doc: "application/msword",
|
|
13678
|
+
docx: "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
|
13679
|
+
gif: "image/gif",
|
|
13680
|
+
html: "text/html",
|
|
13681
|
+
htm: "text/html",
|
|
13682
|
+
jpeg: "image/jpeg",
|
|
13683
|
+
jpg: "image/jpeg",
|
|
13684
|
+
js: "text/javascript",
|
|
13685
|
+
json: "application/json",
|
|
13686
|
+
jsonl: "application/jsonl",
|
|
13687
|
+
md: "text/markdown",
|
|
13688
|
+
pdf: "application/pdf",
|
|
13689
|
+
ppt: "application/vnd.ms-powerpoint",
|
|
13690
|
+
pptx: "application/vnd.openxmlformats-officedocument.presentationml.presentation",
|
|
13691
|
+
png: "image/png",
|
|
13692
|
+
svg: "image/svg+xml",
|
|
13693
|
+
txt: "text/plain",
|
|
13694
|
+
webp: "image/webp",
|
|
13695
|
+
yaml: "application/yaml",
|
|
13696
|
+
yml: "application/yaml",
|
|
13697
|
+
xls: "application/vnd.ms-excel",
|
|
13698
|
+
xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
|
13699
|
+
zip: "application/zip"
|
|
13700
|
+
};
|
|
13701
|
+
function contentTypeFor(name) {
|
|
13702
|
+
const dot = name.lastIndexOf(".");
|
|
13703
|
+
const extension = dot === -1 ? "" : name.slice(dot + 1).toLowerCase();
|
|
13704
|
+
return CONTENT_TYPES[extension] ?? "application/octet-stream";
|
|
13705
|
+
}
|
|
13706
|
+
async function localFile(path, override) {
|
|
13707
|
+
const embedded = embedStore.getStore();
|
|
13708
|
+
if (embedded) {
|
|
13709
|
+
embedded.identity.signal?.throwIfAborted();
|
|
13710
|
+
if (!embedded.openFile)
|
|
13711
|
+
throw new SimApiError("This invocation has no machine to read from", 0);
|
|
13712
|
+
const { size } = await embedded.openFile(embeddedFileKey(path));
|
|
13713
|
+
embedded.identity.signal?.throwIfAborted();
|
|
13714
|
+
if (!Number.isSafeInteger(size) || size < 0)
|
|
13715
|
+
throw new SimApiError("Invalid file size", 0);
|
|
13716
|
+
if (size === 0)
|
|
13717
|
+
throw new SimApiError(`${path} is empty`, 0);
|
|
13718
|
+
return { name: override ?? basename(embeddedFileKey(path)), size };
|
|
13719
|
+
}
|
|
13720
|
+
let size;
|
|
13721
|
+
try {
|
|
13722
|
+
const stats = await stat(path);
|
|
13723
|
+
if (!stats.isFile())
|
|
13724
|
+
throw new SimApiError(`${path} is not a regular file`, 0);
|
|
13725
|
+
await access(path, constants.R_OK);
|
|
13726
|
+
size = stats.size;
|
|
13727
|
+
} catch (error) {
|
|
13728
|
+
if (error instanceof SimApiError)
|
|
13729
|
+
throw error;
|
|
13730
|
+
throw new SimApiError(`Cannot read ${path}: ${error.message}`, 0);
|
|
13731
|
+
}
|
|
13732
|
+
if (size === 0)
|
|
13733
|
+
throw new SimApiError(`${path} is empty`, 0);
|
|
13734
|
+
return { name: override ?? basename(path), size };
|
|
13735
|
+
}
|
|
13736
|
+
|
|
13737
|
+
// src/runtime/request.ts
|
|
13495
13738
|
var PROFILE_INJECTED_FIELD = "workspaceId";
|
|
13496
13739
|
function isProfileWorkspacePath(commandSpec, param) {
|
|
13497
13740
|
return commandSpec.profileWorkspacePath === true && param === PROFILE_INJECTED_FIELD;
|
|
@@ -13573,11 +13816,21 @@ function readStdin() {
|
|
|
13573
13816
|
function literalAtHint(error, path) {
|
|
13574
13817
|
return error?.code === "ENOENT" ? `. To pass the literal value @${path}, write @@${path}` : "";
|
|
13575
13818
|
}
|
|
13576
|
-
function readArgumentSource(raw, flagName) {
|
|
13819
|
+
async function readArgumentSource(raw, flagName) {
|
|
13577
13820
|
if (raw.startsWith("@@"))
|
|
13578
13821
|
return { text: raw.slice(1), from: "" };
|
|
13579
13822
|
if (!raw.startsWith("@"))
|
|
13580
13823
|
return { text: raw, from: "" };
|
|
13824
|
+
const embedded = embedStore.getStore();
|
|
13825
|
+
if (embedded) {
|
|
13826
|
+
if (raw === "@-")
|
|
13827
|
+
throw new SimApiError(`--${flagName}: this invocation has no stdin; use @path or an inline value`, 0);
|
|
13828
|
+
const content = await embeddedFileContent(embedded, raw);
|
|
13829
|
+
return {
|
|
13830
|
+
text: typeof content === "string" ? content : new TextDecoder("utf-8", { fatal: true }).decode(content),
|
|
13831
|
+
from: " (read from your machine)"
|
|
13832
|
+
};
|
|
13833
|
+
}
|
|
13581
13834
|
const path = raw.slice(1);
|
|
13582
13835
|
if (path === "-") {
|
|
13583
13836
|
if (process.stdin.isTTY) {
|
|
@@ -13599,15 +13852,18 @@ function isManifestNoise(line) {
|
|
|
13599
13852
|
const trimmed = line.trim();
|
|
13600
13853
|
return trimmed === "" || trimmed.startsWith("#");
|
|
13601
13854
|
}
|
|
13602
|
-
function readListValues(raw, flagName, manifest = false) {
|
|
13855
|
+
async function readListValues(raw, flagName, manifest = false) {
|
|
13603
13856
|
const arguments_ = Array.isArray(raw) ? raw : [raw];
|
|
13604
|
-
const values =
|
|
13857
|
+
const values = [];
|
|
13858
|
+
for (const argument of arguments_) {
|
|
13605
13859
|
if (typeof argument !== "string") {
|
|
13606
13860
|
throw new SimApiError(`--${flagName} values must be strings`, 0);
|
|
13607
13861
|
}
|
|
13608
|
-
if (!argument.startsWith("@"))
|
|
13609
|
-
|
|
13610
|
-
|
|
13862
|
+
if (!argument.startsWith("@")) {
|
|
13863
|
+
values.push(argument);
|
|
13864
|
+
continue;
|
|
13865
|
+
}
|
|
13866
|
+
const source = await readArgumentSource(argument, flagName);
|
|
13611
13867
|
const lines = source.text.split(/\r?\n/);
|
|
13612
13868
|
if (lines.at(-1) === "")
|
|
13613
13869
|
lines.pop();
|
|
@@ -13615,14 +13871,14 @@ function readListValues(raw, flagName, manifest = false) {
|
|
|
13615
13871
|
if (kept.length === 0) {
|
|
13616
13872
|
throw new SimApiError(`--${flagName}${source.from} contains no values`, 0);
|
|
13617
13873
|
}
|
|
13618
|
-
|
|
13874
|
+
values.push(...kept.map((line, index) => {
|
|
13619
13875
|
const value = line.trim();
|
|
13620
13876
|
if (!value) {
|
|
13621
13877
|
throw new SimApiError(`--${flagName}${source.from} has an empty value on line ${index + 1}`, 0);
|
|
13622
13878
|
}
|
|
13623
13879
|
return value;
|
|
13624
|
-
});
|
|
13625
|
-
}
|
|
13880
|
+
}));
|
|
13881
|
+
}
|
|
13626
13882
|
return values.map((value) => {
|
|
13627
13883
|
const trimmed = value.trim();
|
|
13628
13884
|
if (!trimmed)
|
|
@@ -13654,13 +13910,13 @@ var FRACTIONAL_DIGITS = /\.\d*[1-9]/;
|
|
|
13654
13910
|
function pathHint(raw) {
|
|
13655
13911
|
if (raw.startsWith("@") || /^\s*[[{"\-\d]|^\s*(true|false|null)/.test(raw))
|
|
13656
13912
|
return "";
|
|
13657
|
-
return existsSync2(raw) ? `. ${raw} is a file — pass it as @${raw}` : ". To read a file, pass @path (or @- for stdin)";
|
|
13913
|
+
return !embedStore.getStore() && existsSync2(raw) ? `. ${raw} is a file — pass it as @${raw}` : ". To read a file, pass @path (or @- for stdin)";
|
|
13658
13914
|
}
|
|
13659
|
-
function coerce(raw, field, flag, flagName) {
|
|
13915
|
+
async function coerce(raw, field, flag, flagName) {
|
|
13660
13916
|
if (raw === undefined)
|
|
13661
13917
|
return;
|
|
13662
13918
|
if (flag.list) {
|
|
13663
|
-
const values = readListValues(raw, flagName, flag.manifest === true).map((value) => flag.folderPath ? encodeFolderPath(value) : value);
|
|
13919
|
+
const values = (await readListValues(raw, flagName, flag.manifest === true)).map((value) => flag.folderPath ? encodeFolderPath(value) : value);
|
|
13664
13920
|
return field.kind === "string" ? values.join(",") : values;
|
|
13665
13921
|
}
|
|
13666
13922
|
if (flag.rowCap)
|
|
@@ -13668,7 +13924,7 @@ function coerce(raw, field, flag, flagName) {
|
|
|
13668
13924
|
if (takesJson(field, flag)) {
|
|
13669
13925
|
if (typeof raw !== "string")
|
|
13670
13926
|
return raw;
|
|
13671
|
-
const source = readArgumentSource(raw, flagName);
|
|
13927
|
+
const source = await readArgumentSource(raw, flagName);
|
|
13672
13928
|
try {
|
|
13673
13929
|
return JSON.parse(source.text);
|
|
13674
13930
|
} catch (error) {
|
|
@@ -13705,7 +13961,7 @@ function asQueryValue(value) {
|
|
|
13705
13961
|
return JSON.stringify(value);
|
|
13706
13962
|
return value;
|
|
13707
13963
|
}
|
|
13708
|
-
function buildRequest(operation, positional, flags, workspaceId) {
|
|
13964
|
+
async function buildRequest(operation, positional, flags, workspaceId) {
|
|
13709
13965
|
const commandSpec = CLI_CONTRACT[operation] ?? {};
|
|
13710
13966
|
const spec = V2_OPERATIONS[operation];
|
|
13711
13967
|
let path = spec.path;
|
|
@@ -13743,7 +13999,7 @@ function buildRequest(operation, positional, flags, workspaceId) {
|
|
|
13743
13999
|
if ((slot === "query" || NUMERIC_KINDS.has(descriptor.kind)) && typeof raw === "string" && raw.trim() === "" && !(field === "limit" && paginatedLimit)) {
|
|
13744
14000
|
throw new SimApiError(`--${flagName} cannot be empty`, 0);
|
|
13745
14001
|
}
|
|
13746
|
-
const value = coerce(raw ?? undefined, descriptor, flag, flagName);
|
|
14002
|
+
const value = await coerce(raw ?? undefined, descriptor, flag, flagName);
|
|
13747
14003
|
if (field === "limit" && !paginatedLimit && NUMERIC_KINDS.has(descriptor.kind) && typeof value === "number" && value < 1) {
|
|
13748
14004
|
throw new SimApiError(`--${flagName} must be 1 or more`, 0);
|
|
13749
14005
|
}
|
|
@@ -13773,7 +14029,7 @@ function buildRequest(operation, positional, flags, workspaceId) {
|
|
|
13773
14029
|
const raw = flags[camel(variant.name)];
|
|
13774
14030
|
if (typeof raw !== "string")
|
|
13775
14031
|
throw new SimApiError(`--${variant.name} is required`, 0);
|
|
13776
|
-
const parsed = coerce(raw, { kind: variant.kind }, { json: true }, variant.name);
|
|
14032
|
+
const parsed = await coerce(raw, { kind: variant.kind }, { json: true }, variant.name);
|
|
13777
14033
|
if (variant.kind === "object" && (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) || variant.kind === "array" && !Array.isArray(parsed)) {
|
|
13778
14034
|
throw new SimApiError(`--${variant.name} must be a JSON ${variant.kind}`, 0);
|
|
13779
14035
|
}
|
|
@@ -13782,7 +14038,7 @@ function buildRequest(operation, positional, flags, workspaceId) {
|
|
|
13782
14038
|
const raw = flags.body;
|
|
13783
14039
|
if (typeof raw !== "string")
|
|
13784
14040
|
throw new SimApiError("--body is required", 0);
|
|
13785
|
-
const parsed = coerce(raw, { kind: "object" }, { json: true }, "body");
|
|
14041
|
+
const parsed = await coerce(raw, { kind: "object" }, { json: true }, "body");
|
|
13786
14042
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
13787
14043
|
throw new SimApiError("--body must be a JSON object", 0);
|
|
13788
14044
|
}
|
|
@@ -13907,7 +14163,7 @@ function warn(kind, from, to) {
|
|
|
13907
14163
|
if (warned.has(key))
|
|
13908
14164
|
return;
|
|
13909
14165
|
warned.add(key);
|
|
13910
|
-
|
|
14166
|
+
writeStderr(`warning: ${kind} "${from}" has been renamed to "${to}". The old name still works.
|
|
13911
14167
|
`);
|
|
13912
14168
|
}
|
|
13913
14169
|
function warnRenamedCommand(from, to) {
|
|
@@ -14019,13 +14275,13 @@ function renderSpan(value, depth) {
|
|
|
14019
14275
|
function printTraceSpans(format, traceSpans) {
|
|
14020
14276
|
if (format === "json" || format === "yaml")
|
|
14021
14277
|
return;
|
|
14022
|
-
|
|
14023
|
-
|
|
14278
|
+
printLine("");
|
|
14279
|
+
printLine(format === "table" ? styles3().dim("trace:") : "trace:");
|
|
14024
14280
|
if (traceSpans.length === 0) {
|
|
14025
|
-
|
|
14281
|
+
printLine(styles3().dim(" No trace spans."));
|
|
14026
14282
|
return;
|
|
14027
14283
|
}
|
|
14028
|
-
|
|
14284
|
+
printLine(traceSpans.flatMap((span) => renderSpan(span, 0)).join(`
|
|
14029
14285
|
`));
|
|
14030
14286
|
}
|
|
14031
14287
|
|
|
@@ -14190,7 +14446,7 @@ function writePageNote(spec, envelope) {
|
|
|
14190
14446
|
const value = at(envelope, spec.pageNote.path);
|
|
14191
14447
|
if (value === undefined || value === null)
|
|
14192
14448
|
return;
|
|
14193
|
-
|
|
14449
|
+
writeStderr(styles3().dim(`${spec.pageNote.label}: ${String(value)}
|
|
14194
14450
|
`));
|
|
14195
14451
|
}
|
|
14196
14452
|
var TRUNCATION_FLAG = /^truncated$|^[A-Za-z0-9]+Truncated$/;
|
|
@@ -14223,14 +14479,14 @@ function clippedSubject(flag) {
|
|
|
14223
14479
|
}
|
|
14224
14480
|
function writeEnvelopeTruncation(envelope) {
|
|
14225
14481
|
for (const flag of responseTruncationFlags(envelope)) {
|
|
14226
|
-
|
|
14482
|
+
writeStderr(styles3().dim(`${spellOut(flag)}: the server clipped ${clippedSubject(flag)}, so the answer is incomplete
|
|
14227
14483
|
`));
|
|
14228
14484
|
}
|
|
14229
14485
|
}
|
|
14230
14486
|
function writeCursorTruncation(count, truncated) {
|
|
14231
14487
|
if (!truncated)
|
|
14232
14488
|
return;
|
|
14233
|
-
|
|
14489
|
+
writeStderr(styles3().dim(`showing the first ${count}; more results exist — re-run with --limit 0 for all
|
|
14234
14490
|
`));
|
|
14235
14491
|
}
|
|
14236
14492
|
function renderResult(operation, format, raw, spec, options = {}, envelope) {
|
|
@@ -14239,7 +14495,7 @@ function renderResult(operation, format, raw, spec, options = {}, envelope) {
|
|
|
14239
14495
|
printDocument(format, raw);
|
|
14240
14496
|
return;
|
|
14241
14497
|
}
|
|
14242
|
-
const data = unwrapResource(raw);
|
|
14498
|
+
const data = format === "json" || format === "yaml" ? raw : unwrapResource(raw);
|
|
14243
14499
|
if (spec.itemsPath) {
|
|
14244
14500
|
const items = at(data, spec.itemsPath);
|
|
14245
14501
|
if (!Array.isArray(items)) {
|
|
@@ -14358,6 +14614,22 @@ function countOf(value) {
|
|
|
14358
14614
|
function lengthOf(value) {
|
|
14359
14615
|
return Array.isArray(value) ? value.length : 0;
|
|
14360
14616
|
}
|
|
14617
|
+
var RESULT_NOTES = {
|
|
14618
|
+
replaceWorkflowChatDeployment: (payload, body) => {
|
|
14619
|
+
const authType = payload.authType ?? body?.authType ?? "public";
|
|
14620
|
+
return authType === "public" ? "note: auth type is public — anyone with the link can chat; pass --auth-type password|email to restrict it." : null;
|
|
14621
|
+
}
|
|
14622
|
+
};
|
|
14623
|
+
function writeResultNote(operation, payload, body) {
|
|
14624
|
+
const note = RESULT_NOTES[operation];
|
|
14625
|
+
if (!note)
|
|
14626
|
+
return;
|
|
14627
|
+
const record = payload && typeof payload === "object" && !Array.isArray(payload) ? payload : {};
|
|
14628
|
+
const message = note(record, body);
|
|
14629
|
+
if (message)
|
|
14630
|
+
writeStderr(styles3().dim(`${message}
|
|
14631
|
+
`));
|
|
14632
|
+
}
|
|
14361
14633
|
function bulkFailureMessage(operation, payload, body) {
|
|
14362
14634
|
const check = BULK_OUTCOME_CHECKS[operation];
|
|
14363
14635
|
if (!check)
|
|
@@ -14446,7 +14718,7 @@ async function executeOperation(operation, commandSpec, operationSpec, invocatio
|
|
|
14446
14718
|
const needsWorkspace = (hasWorkspaceField || commandSpec.profileWorkspacePath === true) && !omitsWorkspace;
|
|
14447
14719
|
const paging = cursorSlot(operationSpec);
|
|
14448
14720
|
const pagedLimit = paging ? readPagedLimit(requestFlags.limit) : 0;
|
|
14449
|
-
const request = buildRequest(operation, positional, requestFlags, needsWorkspace ? client.requireWorkspace() : profile.workspaceId);
|
|
14721
|
+
const request = await buildRequest(operation, positional, requestFlags, needsWorkspace ? client.requireWorkspace() : profile.workspaceId);
|
|
14450
14722
|
if (paging) {
|
|
14451
14723
|
const limit = pagedLimit === 0 ? Number.POSITIVE_INFINITY : pagedLimit;
|
|
14452
14724
|
const pageSize = Math.min(Number.isFinite(limit) ? limit : DEFAULT_LIMIT, DEFAULT_LIMIT);
|
|
@@ -14483,6 +14755,7 @@ async function executeOperation(operation, commandSpec, operationSpec, invocatio
|
|
|
14483
14755
|
});
|
|
14484
14756
|
const payload = result?.data ?? result;
|
|
14485
14757
|
renderResult(operation, profile.output, payload, commandSpec, { expandedTrace: requestFlags.trace === true }, result);
|
|
14758
|
+
writeResultNote(operation, payload, request.body);
|
|
14486
14759
|
const failure = runFailureMessage(operation, payload) ?? bulkFailureMessage(operation, payload, request.body);
|
|
14487
14760
|
if (failure)
|
|
14488
14761
|
throw new SimApiError(failure, 0);
|
|
@@ -14890,8 +15163,8 @@ function serviceAccountProvider(providers, providerId) {
|
|
|
14890
15163
|
}
|
|
14891
15164
|
return provider;
|
|
14892
15165
|
}
|
|
14893
|
-
function credentialValues(provider, raw) {
|
|
14894
|
-
const parsed = coerce(raw, { kind: "object" }, { json: true }, "credentials");
|
|
15166
|
+
async function credentialValues(provider, raw) {
|
|
15167
|
+
const parsed = await coerce(raw, { kind: "object" }, { json: true }, "credentials");
|
|
14895
15168
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
14896
15169
|
throw new SimApiError("--credentials must be a JSON object", 0);
|
|
14897
15170
|
}
|
|
@@ -14928,7 +15201,7 @@ async function createServiceAccount(command, providerId, options) {
|
|
|
14928
15201
|
if (provider.requiresClientGeneratedCredentialId && !options.id) {
|
|
14929
15202
|
throw new SimApiError(`--id is required for ${providerId}.`, 0);
|
|
14930
15203
|
}
|
|
14931
|
-
const credentialFields = credentialValues(provider, options.credentials);
|
|
15204
|
+
const credentialFields = await credentialValues(provider, options.credentials);
|
|
14932
15205
|
const operation = V2_OPERATIONS.createServiceAccountCredential;
|
|
14933
15206
|
const response = await client.request(operation.path, {
|
|
14934
15207
|
method: operation.method,
|
|
@@ -15099,19 +15372,19 @@ Examples:
|
|
|
15099
15372
|
const endStreamedLine = () => {
|
|
15100
15373
|
if (streamed.length > 0 && !streamed.endsWith(`
|
|
15101
15374
|
`)) {
|
|
15102
|
-
|
|
15375
|
+
writeStdout(`
|
|
15103
15376
|
`);
|
|
15104
15377
|
streamed += `
|
|
15105
15378
|
`;
|
|
15106
15379
|
}
|
|
15107
15380
|
};
|
|
15108
|
-
const restorePipeHandling = streaming ? ignoreBrokenPipe(process.stdout) : undefined;
|
|
15381
|
+
const restorePipeHandling = streaming && !embedStore.getStore() ? ignoreBrokenPipe(process.stdout) : undefined;
|
|
15109
15382
|
try {
|
|
15110
15383
|
const result = await readChatStream(response, (content) => {
|
|
15111
15384
|
if (!streaming)
|
|
15112
15385
|
return;
|
|
15113
15386
|
streamed += content;
|
|
15114
|
-
|
|
15387
|
+
writeStdout(content);
|
|
15115
15388
|
});
|
|
15116
15389
|
if (!streaming) {
|
|
15117
15390
|
printProtocolResult(profile.output, result);
|
|
@@ -15119,11 +15392,11 @@ Examples:
|
|
|
15119
15392
|
}
|
|
15120
15393
|
const content = sanitize(result.content ?? "");
|
|
15121
15394
|
if (content.startsWith(streamed) && content.length > streamed.length) {
|
|
15122
|
-
|
|
15395
|
+
writeStdout(content.slice(streamed.length));
|
|
15123
15396
|
streamed = content;
|
|
15124
15397
|
}
|
|
15125
15398
|
endStreamedLine();
|
|
15126
|
-
|
|
15399
|
+
writeStderr(`${styles3().dim(`conversation: ${result.conversationId}`)}
|
|
15127
15400
|
`);
|
|
15128
15401
|
} catch (error) {
|
|
15129
15402
|
endStreamedLine();
|
|
@@ -15254,19 +15527,38 @@ async function saveStagedFile(body, target, force) {
|
|
|
15254
15527
|
}
|
|
15255
15528
|
}
|
|
15256
15529
|
async function saveToFile(body, target, force) {
|
|
15530
|
+
const embedded = embedStore.getStore();
|
|
15531
|
+
if (embedded) {
|
|
15532
|
+
try {
|
|
15533
|
+
embedded.identity.signal?.throwIfAborted();
|
|
15534
|
+
if (!embedded.writeFile) {
|
|
15535
|
+
throw new SimApiError(`--output-file cannot save ${target} here: this surface has no machine to write to. Read the file instead, or use a client with filesystem access to download it.`, 0);
|
|
15536
|
+
}
|
|
15537
|
+
await embedded.writeFile(target, body, { overwrite: force });
|
|
15538
|
+
embedded.identity.signal?.throwIfAborted();
|
|
15539
|
+
} finally {
|
|
15540
|
+
await body.cancel().catch(() => {});
|
|
15541
|
+
}
|
|
15542
|
+
return;
|
|
15543
|
+
}
|
|
15257
15544
|
return saveStagedFile(body, target, force);
|
|
15258
15545
|
}
|
|
15259
|
-
async function streamToStdout(body, output
|
|
15546
|
+
async function streamToStdout(body, output) {
|
|
15260
15547
|
const reader = body.getReader();
|
|
15261
15548
|
try {
|
|
15262
15549
|
while (true) {
|
|
15263
15550
|
const { done, value } = await reader.read();
|
|
15264
15551
|
if (done)
|
|
15265
15552
|
return;
|
|
15266
|
-
if (
|
|
15267
|
-
|
|
15553
|
+
if (output) {
|
|
15554
|
+
if (!output.write(value))
|
|
15555
|
+
await once2(output, "drain");
|
|
15556
|
+
} else if (!writeStdout(value)) {
|
|
15557
|
+
await once2(process.stdout, "drain");
|
|
15558
|
+
}
|
|
15268
15559
|
}
|
|
15269
15560
|
} finally {
|
|
15561
|
+
await reader.cancel().catch(() => {});
|
|
15270
15562
|
reader.releaseLock();
|
|
15271
15563
|
}
|
|
15272
15564
|
}
|
|
@@ -15304,9 +15596,10 @@ function attachFileGet(files) {
|
|
|
15304
15596
|
}
|
|
15305
15597
|
if (options.outputFile === undefined || options.outputFile === "-") {
|
|
15306
15598
|
const contentType = response.headers.get("content-type");
|
|
15307
|
-
|
|
15599
|
+
const embedded = embedStore.getStore();
|
|
15600
|
+
if ((embedded || process.stdout.isTTY) && !isTerminalSafeContentType(contentType)) {
|
|
15308
15601
|
await response.body.cancel();
|
|
15309
|
-
throw new SimApiError(`Refusing to write ${contentType ?? "unknown content"} to an interactive terminal. Use --output-file <path> or pipe stdout.`, 0);
|
|
15602
|
+
throw new SimApiError(embedded ? `Refusing to put ${contentType ?? "unknown content"} in a text result. Use --output-file <path>.` : `Refusing to write ${contentType ?? "unknown content"} to an interactive terminal. Use --output-file <path> or pipe stdout.`, 0);
|
|
15310
15603
|
}
|
|
15311
15604
|
await streamToStdout(response.body);
|
|
15312
15605
|
return;
|
|
@@ -15321,74 +15614,120 @@ function attachFileGet(files) {
|
|
|
15321
15614
|
});
|
|
15322
15615
|
}
|
|
15323
15616
|
|
|
15324
|
-
// src/transfer/
|
|
15325
|
-
import {
|
|
15326
|
-
|
|
15327
|
-
|
|
15328
|
-
|
|
15329
|
-
|
|
15330
|
-
|
|
15331
|
-
|
|
15332
|
-
|
|
15333
|
-
|
|
15334
|
-
|
|
15335
|
-
|
|
15336
|
-
|
|
15337
|
-
|
|
15338
|
-
|
|
15339
|
-
|
|
15340
|
-
|
|
15341
|
-
|
|
15342
|
-
|
|
15343
|
-
|
|
15344
|
-
|
|
15345
|
-
|
|
15346
|
-
|
|
15347
|
-
|
|
15348
|
-
|
|
15349
|
-
|
|
15350
|
-
|
|
15351
|
-
|
|
15352
|
-
|
|
15353
|
-
|
|
15354
|
-
|
|
15355
|
-
|
|
15356
|
-
|
|
15357
|
-
|
|
15358
|
-
|
|
15359
|
-
|
|
15360
|
-
|
|
15361
|
-
|
|
15362
|
-
|
|
15363
|
-
|
|
15364
|
-
|
|
15365
|
-
|
|
15366
|
-
|
|
15367
|
-
|
|
15368
|
-
|
|
15369
|
-
|
|
15370
|
-
|
|
15371
|
-
|
|
15617
|
+
// src/transfer/upload-session.ts
|
|
15618
|
+
import { openAsBlob } from "node:fs";
|
|
15619
|
+
|
|
15620
|
+
// src/transfer/streaming-upload.ts
|
|
15621
|
+
class StreamingUpload {
|
|
15622
|
+
size;
|
|
15623
|
+
position = 0;
|
|
15624
|
+
pending = new Uint8Array(0);
|
|
15625
|
+
closed = false;
|
|
15626
|
+
reader;
|
|
15627
|
+
onAbort;
|
|
15628
|
+
stopped = new AbortController;
|
|
15629
|
+
signal;
|
|
15630
|
+
constructor(stream, size, signal) {
|
|
15631
|
+
this.size = size;
|
|
15632
|
+
this.signal = signal ? AbortSignal.any([signal, this.stopped.signal]) : this.stopped.signal;
|
|
15633
|
+
this.reader = stream.getReader();
|
|
15634
|
+
this.onAbort = () => {
|
|
15635
|
+
this.reader.cancel(this.signal.reason).catch(() => {});
|
|
15636
|
+
};
|
|
15637
|
+
this.signal.addEventListener("abort", this.onAbort, { once: true });
|
|
15638
|
+
if (this.signal.aborted)
|
|
15639
|
+
this.onAbort();
|
|
15640
|
+
}
|
|
15641
|
+
slice(start, end) {
|
|
15642
|
+
this.signal.throwIfAborted();
|
|
15643
|
+
if (this.closed || start !== this.position || end <= start || end > this.size) {
|
|
15644
|
+
throw new SimApiError("Upload parts must consume the snapshot in order", 0);
|
|
15645
|
+
}
|
|
15646
|
+
return new ReadableStream({
|
|
15647
|
+
pull: async (controller) => {
|
|
15648
|
+
try {
|
|
15649
|
+
this.signal.throwIfAborted();
|
|
15650
|
+
while (this.pending.byteLength === 0) {
|
|
15651
|
+
const next = await this.reader.read();
|
|
15652
|
+
this.signal.throwIfAborted();
|
|
15653
|
+
if (next.done)
|
|
15654
|
+
throw new SimApiError("Upload file ended before its declared size", 0);
|
|
15655
|
+
this.pending = next.value;
|
|
15656
|
+
}
|
|
15657
|
+
const length = Math.min(this.pending.byteLength, end - this.position);
|
|
15658
|
+
controller.enqueue(this.pending.subarray(0, length));
|
|
15659
|
+
this.pending = this.pending.subarray(length);
|
|
15660
|
+
this.position += length;
|
|
15661
|
+
if (this.position === end)
|
|
15662
|
+
controller.close();
|
|
15663
|
+
} catch (error) {
|
|
15664
|
+
controller.error(error);
|
|
15665
|
+
}
|
|
15666
|
+
},
|
|
15667
|
+
cancel: (reason) => this.reader.cancel(reason)
|
|
15668
|
+
}, { highWaterMark: 0 });
|
|
15669
|
+
}
|
|
15670
|
+
assertConsumed(end) {
|
|
15671
|
+
this.signal.throwIfAborted();
|
|
15672
|
+
if (this.position !== end) {
|
|
15673
|
+
throw new SimApiError("Upload was acknowledged before its complete body was consumed", 0);
|
|
15674
|
+
}
|
|
15675
|
+
}
|
|
15676
|
+
async verifyComplete() {
|
|
15677
|
+
this.assertConsumed(this.size);
|
|
15678
|
+
if (this.pending.byteLength > 0) {
|
|
15679
|
+
throw new SimApiError("Upload file exceeds its declared size", 0);
|
|
15680
|
+
}
|
|
15681
|
+
while (true) {
|
|
15682
|
+
const next = await this.reader.read();
|
|
15683
|
+
this.signal.throwIfAborted();
|
|
15684
|
+
if (next.done)
|
|
15685
|
+
return;
|
|
15686
|
+
if (next.value.byteLength > 0)
|
|
15687
|
+
throw new SimApiError("Upload file exceeds its declared size", 0);
|
|
15688
|
+
}
|
|
15689
|
+
}
|
|
15690
|
+
async close() {
|
|
15691
|
+
if (this.closed)
|
|
15692
|
+
return;
|
|
15693
|
+
this.closed = true;
|
|
15694
|
+
this.stopped.abort();
|
|
15695
|
+
this.signal.removeEventListener("abort", this.onAbort);
|
|
15696
|
+
try {
|
|
15697
|
+
await this.reader.cancel().catch(() => {});
|
|
15698
|
+
} finally {
|
|
15699
|
+
this.reader.releaseLock();
|
|
15700
|
+
}
|
|
15372
15701
|
}
|
|
15373
|
-
if (size === 0)
|
|
15374
|
-
throw new SimApiError(`${path} is empty`, 0);
|
|
15375
|
-
return { name: override ?? basename(path), size };
|
|
15376
15702
|
}
|
|
15377
15703
|
|
|
15378
15704
|
// src/transfer/upload-session.ts
|
|
15379
|
-
import { openAsBlob } from "node:fs";
|
|
15380
15705
|
var PART_URL_BATCH = 100;
|
|
15381
|
-
async function
|
|
15382
|
-
const
|
|
15706
|
+
async function uploadBytes(url, headers, file, start, end, label) {
|
|
15707
|
+
const body = file.slice(start, end);
|
|
15708
|
+
const options = {
|
|
15383
15709
|
method: "PUT",
|
|
15384
|
-
headers
|
|
15385
|
-
body
|
|
15386
|
-
|
|
15710
|
+
headers,
|
|
15711
|
+
body,
|
|
15712
|
+
signal: file instanceof StreamingUpload ? file.signal : embedStore.getStore()?.identity.signal
|
|
15713
|
+
};
|
|
15714
|
+
if (file instanceof StreamingUpload) {
|
|
15715
|
+
const streamedHeaders = new Headers(headers);
|
|
15716
|
+
streamedHeaders.set("content-length", String(end - start));
|
|
15717
|
+
options.headers = streamedHeaders;
|
|
15718
|
+
options.duplex = "half";
|
|
15719
|
+
}
|
|
15720
|
+
const response = await fetch(url, options);
|
|
15387
15721
|
if (!response.ok) {
|
|
15388
|
-
throw new SimApiError(
|
|
15722
|
+
throw new SimApiError(`${label} failed with status ${response.status}`, response.status);
|
|
15389
15723
|
}
|
|
15724
|
+
if (file instanceof StreamingUpload)
|
|
15725
|
+
file.assertConsumed(end);
|
|
15390
15726
|
}
|
|
15391
|
-
async function uploadParts(client, workspaceId, session, transfer,
|
|
15727
|
+
async function uploadParts(client, workspaceId, session, transfer, file) {
|
|
15728
|
+
if (file instanceof StreamingUpload && (!Number.isSafeInteger(transfer.partSize) || transfer.partSize <= 0)) {
|
|
15729
|
+
throw new SimApiError("Invalid upload part size", 0);
|
|
15730
|
+
}
|
|
15392
15731
|
const expectedPartCount = Math.ceil(session.size / transfer.partSize);
|
|
15393
15732
|
if (expectedPartCount !== transfer.partCount) {
|
|
15394
15733
|
throw new Error(`Upload session expected ${transfer.partCount} parts, but file requires ${expectedPartCount}`);
|
|
@@ -15404,28 +15743,49 @@ async function uploadParts(client, workspaceId, session, transfer, blob) {
|
|
|
15404
15743
|
headers: { "upload-token": session.uploadToken },
|
|
15405
15744
|
body: { partNumbers }
|
|
15406
15745
|
});
|
|
15407
|
-
|
|
15408
|
-
|
|
15409
|
-
const
|
|
15410
|
-
|
|
15411
|
-
|
|
15412
|
-
headers: part.headers,
|
|
15413
|
-
body: chunk
|
|
15414
|
-
});
|
|
15415
|
-
if (!response.ok) {
|
|
15416
|
-
throw new SimApiError(`Part ${part.partNumber} failed with status ${response.status}`, response.status);
|
|
15746
|
+
let parts = signed.data.parts;
|
|
15747
|
+
if (file instanceof StreamingUpload) {
|
|
15748
|
+
const numbers = new Set(parts.map((part) => part.partNumber));
|
|
15749
|
+
if (parts.length !== partNumbers.length || partNumbers.some((n) => !numbers.has(n))) {
|
|
15750
|
+
throw new SimApiError("Upload part URLs do not match the requested parts", 0);
|
|
15417
15751
|
}
|
|
15752
|
+
parts = [...parts].sort((a, b) => a.partNumber - b.partNumber);
|
|
15753
|
+
}
|
|
15754
|
+
for (const part of parts) {
|
|
15755
|
+
const start = (part.partNumber - 1) * transfer.partSize;
|
|
15756
|
+
await uploadBytes(part.url, part.headers, file, start, Math.min(start + transfer.partSize, session.size), `Part ${part.partNumber}`);
|
|
15418
15757
|
}
|
|
15419
15758
|
}
|
|
15420
15759
|
}
|
|
15421
15760
|
async function finishUploadSession(client, workspaceId, session, path) {
|
|
15761
|
+
let snapshot;
|
|
15762
|
+
let streamed;
|
|
15422
15763
|
try {
|
|
15423
|
-
const
|
|
15764
|
+
const embedded = embedStore.getStore();
|
|
15765
|
+
let file;
|
|
15766
|
+
if (embedded) {
|
|
15767
|
+
embedded.identity.signal?.throwIfAborted();
|
|
15768
|
+
if (!embedded.openFile)
|
|
15769
|
+
throw new SimApiError("This invocation has no machine to read from", 0);
|
|
15770
|
+
snapshot = await embedded.openFile(embeddedFileKey(path));
|
|
15771
|
+
if (snapshot.size !== session.size)
|
|
15772
|
+
throw new SimApiError("Upload snapshot size changed", 0);
|
|
15773
|
+
streamed = new StreamingUpload(await snapshot.stream(), snapshot.size, AbortSignal.any([
|
|
15774
|
+
...embedded.identity.signal ? [embedded.identity.signal] : [],
|
|
15775
|
+
...snapshot.signal ? [snapshot.signal] : []
|
|
15776
|
+
]));
|
|
15777
|
+
file = streamed;
|
|
15778
|
+
} else {
|
|
15779
|
+
file = await openAsBlob(path);
|
|
15780
|
+
}
|
|
15424
15781
|
if (session.transfer.method === "put") {
|
|
15425
|
-
await
|
|
15782
|
+
await uploadBytes(session.transfer.url, session.transfer.headers, file, 0, file instanceof Blob ? file.size : session.size, "Upload");
|
|
15426
15783
|
} else {
|
|
15427
|
-
await uploadParts(client, workspaceId, session, session.transfer,
|
|
15784
|
+
await uploadParts(client, workspaceId, session, session.transfer, file);
|
|
15428
15785
|
}
|
|
15786
|
+
await streamed?.verifyComplete();
|
|
15787
|
+
await streamed?.close();
|
|
15788
|
+
await snapshot?.dispose().catch(() => {});
|
|
15429
15789
|
const completed = await client.request(`${session.basePath}/complete`, {
|
|
15430
15790
|
method: "POST",
|
|
15431
15791
|
query: { workspaceId },
|
|
@@ -15433,7 +15793,10 @@ async function finishUploadSession(client, workspaceId, session, path) {
|
|
|
15433
15793
|
});
|
|
15434
15794
|
return completed.data;
|
|
15435
15795
|
} catch (error) {
|
|
15436
|
-
await
|
|
15796
|
+
await streamed?.close();
|
|
15797
|
+
const profile = embeddedProfile();
|
|
15798
|
+
const cleanupClient = profile ? new SimClient({ ...profile, signal: AbortSignal.timeout(5000) }) : client;
|
|
15799
|
+
await cleanupClient.request(session.basePath, {
|
|
15437
15800
|
method: "DELETE",
|
|
15438
15801
|
query: { workspaceId },
|
|
15439
15802
|
headers: { "upload-token": session.uploadToken }
|
|
@@ -15441,6 +15804,9 @@ async function finishUploadSession(client, workspaceId, session, path) {
|
|
|
15441
15804
|
return;
|
|
15442
15805
|
});
|
|
15443
15806
|
throw error;
|
|
15807
|
+
} finally {
|
|
15808
|
+
await streamed?.close();
|
|
15809
|
+
await snapshot?.dispose().catch(() => {});
|
|
15444
15810
|
}
|
|
15445
15811
|
}
|
|
15446
15812
|
|
|
@@ -15526,9 +15892,11 @@ function attachKnowledgeDocumentUpload(documents) {
|
|
|
15526
15892
|
printProtocolResult(profile.output, {
|
|
15527
15893
|
id: completed.document.id,
|
|
15528
15894
|
knowledgeBaseId: completed.document.knowledgeBaseId,
|
|
15529
|
-
|
|
15530
|
-
|
|
15531
|
-
|
|
15895
|
+
filename: completed.document.filename,
|
|
15896
|
+
fileSize: completed.document.fileSize,
|
|
15897
|
+
mimeType: completed.document.mimeType,
|
|
15898
|
+
processingStatus: completed.document.processingStatus,
|
|
15899
|
+
chunkCount: completed.document.chunkCount
|
|
15532
15900
|
});
|
|
15533
15901
|
});
|
|
15534
15902
|
}
|
|
@@ -15590,11 +15958,11 @@ function createTableWriter() {
|
|
|
15590
15958
|
if (!widths) {
|
|
15591
15959
|
widths = COLUMNS.map((column, index) => Math.min(MAX_CELL_WIDTH2, Math.max(column.floor, visibleWidth(column.header), ...lines.map((line) => visibleWidth(line[index])))));
|
|
15592
15960
|
const header = widths;
|
|
15593
|
-
|
|
15961
|
+
printLine(styles3().dim(COLUMNS.map((column, index) => pad2(column.header.toUpperCase(), header[index])).join(" ").trimEnd()));
|
|
15594
15962
|
}
|
|
15595
15963
|
const locked = widths;
|
|
15596
15964
|
for (const line of lines) {
|
|
15597
|
-
|
|
15965
|
+
printLine(line.map((cell, index) => pad2(cell, locked[index])).join(" ").trimEnd());
|
|
15598
15966
|
}
|
|
15599
15967
|
};
|
|
15600
15968
|
}
|
|
@@ -15602,13 +15970,13 @@ function createWriter(format) {
|
|
|
15602
15970
|
if (format === "json") {
|
|
15603
15971
|
return (rows) => {
|
|
15604
15972
|
for (const row of rows)
|
|
15605
|
-
|
|
15973
|
+
printLine(JSON.stringify(row));
|
|
15606
15974
|
};
|
|
15607
15975
|
}
|
|
15608
15976
|
if (format === "yaml") {
|
|
15609
15977
|
return (rows) => {
|
|
15610
15978
|
for (const row of rows) {
|
|
15611
|
-
|
|
15979
|
+
printLine(`---
|
|
15612
15980
|
${dump(row, { lineWidth: 0, noRefs: true }).trimEnd()}`);
|
|
15613
15981
|
}
|
|
15614
15982
|
};
|
|
@@ -15625,24 +15993,24 @@ function followStatus() {
|
|
|
15625
15993
|
let reported = false;
|
|
15626
15994
|
return {
|
|
15627
15995
|
note: (message) => {
|
|
15628
|
-
if (!
|
|
15996
|
+
if (!hasProgressTerminal())
|
|
15629
15997
|
return;
|
|
15630
15998
|
reported = true;
|
|
15631
|
-
|
|
15999
|
+
writeStderr(`\r${styles3().dim(message)}${ERASE_LINE}`);
|
|
15632
16000
|
},
|
|
15633
16001
|
warn: (message) => {
|
|
15634
16002
|
if (reported) {
|
|
15635
16003
|
reported = false;
|
|
15636
|
-
|
|
16004
|
+
writeStderr(`\r${ERASE_LINE}`);
|
|
15637
16005
|
}
|
|
15638
|
-
|
|
16006
|
+
writeStderr(`warning: ${message}
|
|
15639
16007
|
`);
|
|
15640
16008
|
},
|
|
15641
16009
|
clear: () => {
|
|
15642
16010
|
if (!reported)
|
|
15643
16011
|
return;
|
|
15644
16012
|
reported = false;
|
|
15645
|
-
|
|
16013
|
+
writeStderr(`\r${ERASE_LINE}`);
|
|
15646
16014
|
}
|
|
15647
16015
|
};
|
|
15648
16016
|
}
|
|
@@ -15935,13 +16303,13 @@ async function watchImport(client, workspaceId, job) {
|
|
|
15935
16303
|
const next = await client.request(`/api/v2/tables/imports/${encodeURIComponent(current.id)}`, { query: { workspaceId } });
|
|
15936
16304
|
current = next.data;
|
|
15937
16305
|
const line = progressLine(current);
|
|
15938
|
-
if (
|
|
16306
|
+
if (hasProgressTerminal() && line !== reported) {
|
|
15939
16307
|
reported = line;
|
|
15940
|
-
|
|
16308
|
+
writeStderr(`\r${styles3().dim(line)}\x1B[K`);
|
|
15941
16309
|
}
|
|
15942
16310
|
}
|
|
15943
|
-
if (
|
|
15944
|
-
|
|
16311
|
+
if (hasProgressTerminal() && reported !== null)
|
|
16312
|
+
writeStderr("\r\x1B[K");
|
|
15945
16313
|
return current;
|
|
15946
16314
|
}
|
|
15947
16315
|
function validateTargetOptions(options) {
|
|
@@ -15999,8 +16367,8 @@ function attachTableImport(tables) {
|
|
|
15999
16367
|
workspaceId,
|
|
16000
16368
|
source,
|
|
16001
16369
|
target,
|
|
16002
|
-
...options.mapping ? { mapping: jsonFlag(options.mapping, "mapping", "object") } : {},
|
|
16003
|
-
...options.createColumns ? { createColumns: jsonFlag(options.createColumns, "create-columns", "array") } : {},
|
|
16370
|
+
...options.mapping ? { mapping: await jsonFlag(options.mapping, "mapping", "object") } : {},
|
|
16371
|
+
...options.createColumns ? { createColumns: await jsonFlag(options.createColumns, "create-columns", "array") } : {},
|
|
16004
16372
|
...options.timezone ? { timezone: options.timezone } : {}
|
|
16005
16373
|
}
|
|
16006
16374
|
});
|
|
@@ -16045,14 +16413,11 @@ var AGENT_STREAM_PROTOCOL_HEADER = "x-sim-stream-protocol";
|
|
|
16045
16413
|
var AGENT_STREAM_PROTOCOL_V1 = "agent-events-v1";
|
|
16046
16414
|
var DONE_SENTINEL = "[DONE]";
|
|
16047
16415
|
function resolveWorkflowRunSelection(flags) {
|
|
16048
|
-
const manual = flags.manual === true;
|
|
16049
16416
|
const trigger = typeof flags.trigger === "string" ? flags.trigger : undefined;
|
|
16050
16417
|
const useMockPayload = flags.mockPayload === true;
|
|
16418
|
+
const manual = flags.manual === true || trigger !== undefined || useMockPayload;
|
|
16051
16419
|
const fromBlock = typeof flags.fromBlock === "string" ? flags.fromBlock : undefined;
|
|
16052
16420
|
const sourceRun = typeof flags.sourceRun === "string" ? flags.sourceRun : undefined;
|
|
16053
|
-
if ((trigger || useMockPayload) && !manual) {
|
|
16054
|
-
throw new SimApiError("--trigger and --mock-payload require --manual", 0);
|
|
16055
|
-
}
|
|
16056
16421
|
if (fromBlock && (trigger || useMockPayload)) {
|
|
16057
16422
|
throw new SimApiError("--from-block cannot be combined with --trigger or --mock-payload", 0);
|
|
16058
16423
|
}
|
|
@@ -16151,11 +16516,11 @@ class Commentary {
|
|
|
16151
16516
|
function toolNotice(frame) {
|
|
16152
16517
|
const name = safeOneLine(stringField(frame, "name") ?? "tool");
|
|
16153
16518
|
if (frame.phase === "start")
|
|
16154
|
-
return
|
|
16519
|
+
return styles3().dim(`→ ${name}`);
|
|
16155
16520
|
const status = stringField(frame, "status");
|
|
16156
16521
|
if (status && status !== "success")
|
|
16157
|
-
return
|
|
16158
|
-
return
|
|
16522
|
+
return styles3().yellow(`✗ ${name} (${safeOneLine(status)})`);
|
|
16523
|
+
return styles3().dim(`✓ ${name}`);
|
|
16159
16524
|
}
|
|
16160
16525
|
async function renderRunStream(body, options) {
|
|
16161
16526
|
const commentary = new Commentary(options.stderr);
|
|
@@ -16177,11 +16542,11 @@ async function renderRunStream(body, options) {
|
|
|
16177
16542
|
}
|
|
16178
16543
|
switch (frame.event) {
|
|
16179
16544
|
case "chunk_reset":
|
|
16180
|
-
commentary.line(
|
|
16545
|
+
commentary.line(styles3().dim("… retracted; that turn resolved to tool calls"));
|
|
16181
16546
|
break;
|
|
16182
16547
|
case "thinking":
|
|
16183
16548
|
if (options.includeThinking && typeof frame.data === "string") {
|
|
16184
|
-
commentary.inline(
|
|
16549
|
+
commentary.inline(styles3().dim(sanitize(frame.data)));
|
|
16185
16550
|
}
|
|
16186
16551
|
break;
|
|
16187
16552
|
case "tool":
|
|
@@ -16189,7 +16554,7 @@ async function renderRunStream(body, options) {
|
|
|
16189
16554
|
commentary.line(toolNotice(frame));
|
|
16190
16555
|
break;
|
|
16191
16556
|
case "stream_error":
|
|
16192
|
-
commentary.line(
|
|
16557
|
+
commentary.line(styles3().yellow(`warning: ${safeOneLine(stringField(frame, "error") ?? "stream read failed")}`));
|
|
16193
16558
|
break;
|
|
16194
16559
|
case "error":
|
|
16195
16560
|
commentary.endLine();
|
|
@@ -16218,7 +16583,7 @@ async function followRun(workflowId, command) {
|
|
|
16218
16583
|
const negotiates = includeThinking || includeToolCalls;
|
|
16219
16584
|
const { client, profile } = clientFrom(command);
|
|
16220
16585
|
const operation = V2_OPERATIONS.executeWorkflow;
|
|
16221
|
-
const request = buildRequest("executeWorkflow", [workflowId], flags, profile.workspaceId);
|
|
16586
|
+
const request = await buildRequest("executeWorkflow", [workflowId], flags, profile.workspaceId);
|
|
16222
16587
|
const response = await client.requestRaw(request.path, {
|
|
16223
16588
|
method: "POST",
|
|
16224
16589
|
query: request.query,
|
|
@@ -16244,7 +16609,7 @@ async function followRun(workflowId, command) {
|
|
|
16244
16609
|
const final = await renderRunStream(response.body, {
|
|
16245
16610
|
includeThinking,
|
|
16246
16611
|
includeToolCalls,
|
|
16247
|
-
stderr:
|
|
16612
|
+
stderr: { write: writeStderr }
|
|
16248
16613
|
});
|
|
16249
16614
|
renderResult("executeWorkflow", profile.output, final, CLI_CONTRACT.executeWorkflow ?? {});
|
|
16250
16615
|
if (final.success === false) {
|
|
@@ -16259,8 +16624,8 @@ function followOrDelegate(previous) {
|
|
|
16259
16624
|
command.setOptionValue("run", selection);
|
|
16260
16625
|
const flags = command.optsWithGlobals();
|
|
16261
16626
|
if (flags.follow !== true) {
|
|
16262
|
-
if (Array.isArray(flags.selectOutput) && flags.selectOutput.length > 0) {
|
|
16263
|
-
throw new SimApiError(
|
|
16627
|
+
if (Array.isArray(flags.selectOutput) && flags.selectOutput.length > 0 && flags.async === true) {
|
|
16628
|
+
throw new SimApiError("--select-output names outputs of a completed run, and --async returns as soon as the run is queued. Drop one of them, or read the finished run with: sim workflows runs get <runId> --workflow <workflowId> --select-output <blockName|blockId>[.path] — that resource takes the same selectors --select-output takes here.", 0);
|
|
16264
16629
|
}
|
|
16265
16630
|
if (flags.includeThinking === true || flags.includeToolCalls === true) {
|
|
16266
16631
|
throw new SimApiError("--include-thinking and --include-tool-calls describe a stream; add --follow", 0);
|
|
@@ -16282,7 +16647,119 @@ function attachWorkflowRunFollow(workflows) {
|
|
|
16282
16647
|
}
|
|
16283
16648
|
const held = run._actionHandler;
|
|
16284
16649
|
const previous = typeof held === "function" ? held : null;
|
|
16285
|
-
run.option("--manual", "Run the current saved workflow state instead of the active deployment").option("--trigger <blockId>", "Enter
|
|
16650
|
+
run.option("--manual", "Run the current saved workflow state instead of the active deployment").option("--trigger <blockId>", "Enter the run through this runnable trigger; runs the current saved workflow state (implies --manual)").option("--mock-payload", "Use the selected trigger's server-derived mock payload; runs the current saved workflow state (implies --manual)").option("--from-block <blockId>", "Run manually from this saved workflow block").option("--source-run <runId>", "Prior run whose persisted state supplies upstream outputs (requires --from-block)").option("--follow", "Stream the run as it happens; progress on stderr, result on stdout. The stream reports only success and output, so the result omits the run id and timings a non-streaming run returns").option("--include-thinking", "Show model reasoning while following (requires --follow)").option("--include-tool-calls", "Show tool calls while following (requires --follow)").action(followOrDelegate(previous));
|
|
16651
|
+
}
|
|
16652
|
+
|
|
16653
|
+
// src/commands/protocol/workflow-run-get.ts
|
|
16654
|
+
var BLOCK_ID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
16655
|
+
var SELECT_OUTPUT_FLAG = "select-output";
|
|
16656
|
+
function normalizeBlockName(name) {
|
|
16657
|
+
return name.toLowerCase().replace(/\s+/g, "").replace(/\./g, "");
|
|
16658
|
+
}
|
|
16659
|
+
function isRecord2(value) {
|
|
16660
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
16661
|
+
}
|
|
16662
|
+
async function loadWorkflowBlocks(client, workflowId) {
|
|
16663
|
+
const operation = V2_OPERATIONS.getWorkflowState;
|
|
16664
|
+
const raw = await client.request(resolvePath(operation.path, { workflowId }), {
|
|
16665
|
+
method: operation.method
|
|
16666
|
+
});
|
|
16667
|
+
const state = isRecord2(raw) && isRecord2(raw.data) ? raw.data : raw;
|
|
16668
|
+
const blocks = isRecord2(state) && isRecord2(state.blocks) ? Object.entries(state.blocks) : [];
|
|
16669
|
+
return blocks.map(([key, block]) => ({
|
|
16670
|
+
id: isRecord2(block) && typeof block.id === "string" ? block.id : key,
|
|
16671
|
+
name: isRecord2(block) && typeof block.name === "string" ? block.name : ""
|
|
16672
|
+
}));
|
|
16673
|
+
}
|
|
16674
|
+
function splitSelector(selector) {
|
|
16675
|
+
const dot = selector.indexOf(".");
|
|
16676
|
+
return dot === -1 ? { head: selector, path: "" } : { head: selector.slice(0, dot), path: selector.slice(dot) };
|
|
16677
|
+
}
|
|
16678
|
+
function isIdHeaded(selector) {
|
|
16679
|
+
return BLOCK_ID.test(splitSelector(selector).head);
|
|
16680
|
+
}
|
|
16681
|
+
function resolveSelection(typed, blocks, workflowId) {
|
|
16682
|
+
const resolved = [];
|
|
16683
|
+
const typedBy = new Map;
|
|
16684
|
+
const unresolved = [];
|
|
16685
|
+
for (const selector of typed) {
|
|
16686
|
+
const { head, path } = splitSelector(selector);
|
|
16687
|
+
let blockId = head;
|
|
16688
|
+
if (!BLOCK_ID.test(head)) {
|
|
16689
|
+
const wanted = normalizeBlockName(head);
|
|
16690
|
+
const matches = blocks.filter((block) => block.id === head || normalizeBlockName(block.name) === wanted);
|
|
16691
|
+
if (matches.length === 0) {
|
|
16692
|
+
unresolved.push(selector);
|
|
16693
|
+
continue;
|
|
16694
|
+
}
|
|
16695
|
+
if (matches.length > 1) {
|
|
16696
|
+
throw new SimApiError(`--${SELECT_OUTPUT_FLAG} ${selector} names ${matches.length} blocks (${matches.map((block) => block.id).join(", ")}); pass the block id instead`, 0);
|
|
16697
|
+
}
|
|
16698
|
+
blockId = matches[0].id;
|
|
16699
|
+
}
|
|
16700
|
+
const rewritten = `${blockId}${path}`;
|
|
16701
|
+
resolved.push(rewritten);
|
|
16702
|
+
if (!typedBy.has(rewritten))
|
|
16703
|
+
typedBy.set(rewritten, selector);
|
|
16704
|
+
}
|
|
16705
|
+
if (unresolved.length > 0) {
|
|
16706
|
+
const names = blocks.map((block) => block.name).filter((name) => name !== "");
|
|
16707
|
+
throw new SimApiError(`--${SELECT_OUTPUT_FLAG} did not resolve to any block on this run: ${unresolved.join(", ")}. Pass a block id or its name — "blockId", "blockId.path", "blockName" or "blockName.path"; names match ignoring case, spaces and dots. Blocks on workflow ${workflowId}: ${names.length > 0 ? names.join(", ") : "none"}.`, 0);
|
|
16708
|
+
}
|
|
16709
|
+
return { resolved, typedBy };
|
|
16710
|
+
}
|
|
16711
|
+
function keyByTyped(payload, typedBy) {
|
|
16712
|
+
if (!isRecord2(payload) || !isRecord2(payload.blockOutputs))
|
|
16713
|
+
return payload;
|
|
16714
|
+
const blockOutputs = {};
|
|
16715
|
+
for (const [key, value] of Object.entries(payload.blockOutputs)) {
|
|
16716
|
+
blockOutputs[typedBy.get(key) ?? key] = value;
|
|
16717
|
+
}
|
|
16718
|
+
return { ...payload, blockOutputs };
|
|
16719
|
+
}
|
|
16720
|
+
async function readRunByName(runId, typed, command) {
|
|
16721
|
+
const flags = command.optsWithGlobals();
|
|
16722
|
+
const { client, profile } = clientFrom(command);
|
|
16723
|
+
const operation = V2_OPERATIONS.getWorkflowRun;
|
|
16724
|
+
const spec = CLI_CONTRACT.getWorkflowRun ?? {};
|
|
16725
|
+
await buildRequest("getWorkflowRun", [runId], flags, profile.workspaceId);
|
|
16726
|
+
const workflowId = String(flags.workflow);
|
|
16727
|
+
const selection = resolveSelection(typed, await loadWorkflowBlocks(client, workflowId), workflowId);
|
|
16728
|
+
const request = await buildRequest("getWorkflowRun", [runId], { ...flags, selectOutput: selection.resolved }, profile.workspaceId);
|
|
16729
|
+
let result;
|
|
16730
|
+
try {
|
|
16731
|
+
result = await client.request(request.path, {
|
|
16732
|
+
method: operation.method,
|
|
16733
|
+
headers: request.headers,
|
|
16734
|
+
query: request.query,
|
|
16735
|
+
body: request.body
|
|
16736
|
+
});
|
|
16737
|
+
} catch (error) {
|
|
16738
|
+
throw retypeApiError(error, "getWorkflowRun", spec, operation);
|
|
16739
|
+
}
|
|
16740
|
+
renderResult("getWorkflowRun", profile.output, keyByTyped(result?.data ?? result, selection.typedBy), spec, {}, result);
|
|
16741
|
+
}
|
|
16742
|
+
function attachWorkflowRunGet(runs) {
|
|
16743
|
+
const get = runs.commands.find((command) => command.name() === "get");
|
|
16744
|
+
const held = get?._actionHandler;
|
|
16745
|
+
if (!get || typeof held !== "function") {
|
|
16746
|
+
throw new Error("workflows runs get must be registered before block names can be attached to it");
|
|
16747
|
+
}
|
|
16748
|
+
const previous = held;
|
|
16749
|
+
get.action(async (runId, _options, command) => {
|
|
16750
|
+
const raw = command.optsWithGlobals().selectOutput;
|
|
16751
|
+
if (raw === undefined) {
|
|
16752
|
+
await previous(command.processedArgs);
|
|
16753
|
+
return;
|
|
16754
|
+
}
|
|
16755
|
+
const typed = await readListValues(raw, SELECT_OUTPUT_FLAG);
|
|
16756
|
+
command.setOptionValue("selectOutput", typed);
|
|
16757
|
+
if (typed.every(isIdHeaded)) {
|
|
16758
|
+
await previous(command.processedArgs);
|
|
16759
|
+
return;
|
|
16760
|
+
}
|
|
16761
|
+
await readRunByName(runId, typed, command);
|
|
16762
|
+
});
|
|
16286
16763
|
}
|
|
16287
16764
|
|
|
16288
16765
|
// src/commands/protocol/workflow-run-wait.ts
|
|
@@ -16299,18 +16776,21 @@ var MAX_POLL_DELAY_MS = 15000;
|
|
|
16299
16776
|
var POLL_BACKOFF_FACTOR = 2;
|
|
16300
16777
|
var DEFAULT_WAIT_TIMEOUT_SECONDS = 3600;
|
|
16301
16778
|
var WAIT_TIMEOUT_FLAG = "--wait-timeout <seconds>";
|
|
16302
|
-
function
|
|
16779
|
+
function isRecord3(value) {
|
|
16303
16780
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
16304
16781
|
}
|
|
16305
16782
|
function optionalString(value) {
|
|
16306
16783
|
return typeof value === "string" && value !== "" ? value : null;
|
|
16307
16784
|
}
|
|
16785
|
+
function runData(raw) {
|
|
16786
|
+
return isRecord3(raw) && isRecord3(raw.data) ? raw.data : raw;
|
|
16787
|
+
}
|
|
16308
16788
|
function readRun(raw) {
|
|
16309
|
-
const run =
|
|
16310
|
-
if (!
|
|
16789
|
+
const run = isRecord3(raw) && isRecord3(raw.data) ? raw.data : raw;
|
|
16790
|
+
if (!isRecord3(run) || typeof run.status !== "string") {
|
|
16311
16791
|
throw new SimApiError("Run status response carried no status.", 0);
|
|
16312
16792
|
}
|
|
16313
|
-
const paused =
|
|
16793
|
+
const paused = isRecord3(run.paused) ? run.paused : null;
|
|
16314
16794
|
return {
|
|
16315
16795
|
status: run.status,
|
|
16316
16796
|
pauseKind: paused ? optionalString(paused.pauseKind) : null,
|
|
@@ -16329,16 +16809,16 @@ function waitProgress() {
|
|
|
16329
16809
|
let reported = false;
|
|
16330
16810
|
return {
|
|
16331
16811
|
advance: (status, elapsedMs) => {
|
|
16332
|
-
if (!
|
|
16812
|
+
if (!hasProgressTerminal())
|
|
16333
16813
|
return;
|
|
16334
16814
|
reported = true;
|
|
16335
|
-
|
|
16815
|
+
writeStderr(`\r${styles3().dim(`${status} — waiting ${Math.round(elapsedMs / 1000)}s…`)}\x1B[K`);
|
|
16336
16816
|
},
|
|
16337
16817
|
finish: () => {
|
|
16338
16818
|
if (!reported)
|
|
16339
16819
|
return;
|
|
16340
16820
|
reported = false;
|
|
16341
|
-
|
|
16821
|
+
writeStderr("\r\x1B[K");
|
|
16342
16822
|
}
|
|
16343
16823
|
};
|
|
16344
16824
|
}
|
|
@@ -16379,19 +16859,19 @@ function attachWorkflowRunWait(runs) {
|
|
|
16379
16859
|
const outcome = classify(snapshot);
|
|
16380
16860
|
if (outcome) {
|
|
16381
16861
|
progress.finish();
|
|
16382
|
-
renderResult("getWorkflowRun", profile.output, raw, runSpec());
|
|
16862
|
+
renderResult("getWorkflowRun", profile.output, runData(raw), runSpec());
|
|
16383
16863
|
const message = explain(outcome, runId, options.workflow, snapshot);
|
|
16384
16864
|
if (message)
|
|
16385
|
-
|
|
16386
|
-
|
|
16865
|
+
printError(styles3().red(message));
|
|
16866
|
+
setSoftExitCode(WAIT_EXIT_CODES[outcome]);
|
|
16387
16867
|
return;
|
|
16388
16868
|
}
|
|
16389
16869
|
const remainingMs = deadline - Date.now();
|
|
16390
16870
|
if (remainingMs <= 0) {
|
|
16391
16871
|
progress.finish();
|
|
16392
|
-
renderResult("getWorkflowRun", profile.output, raw, runSpec());
|
|
16393
|
-
|
|
16394
|
-
|
|
16872
|
+
renderResult("getWorkflowRun", profile.output, runData(raw), runSpec());
|
|
16873
|
+
printError(styles3().red(`Timed out after ${timeoutSeconds}s waiting for run ${runId} (status: ${snapshot.status}${snapshot.resumeAt ? `, resuming at ${snapshot.resumeAt}` : ""}). Raise ${WAIT_TIMEOUT_FLAG}, or set it to 0 to wait indefinitely.`));
|
|
16874
|
+
setSoftExitCode(WAIT_EXIT_CODES.timeout);
|
|
16395
16875
|
return;
|
|
16396
16876
|
}
|
|
16397
16877
|
progress.advance(snapshot.status, Date.now() - startedAt);
|
|
@@ -16447,7 +16927,9 @@ function attachProtocolCommands(program) {
|
|
|
16447
16927
|
createFolder: "createWorkflowFolder"
|
|
16448
16928
|
});
|
|
16449
16929
|
attachWorkflowRunFollow(workflows);
|
|
16450
|
-
|
|
16930
|
+
const runs = group(workflows, "runs");
|
|
16931
|
+
attachWorkflowRunGet(runs);
|
|
16932
|
+
attachWorkflowRunWait(runs);
|
|
16451
16933
|
attachLogsFollow(group(program, "logs"));
|
|
16452
16934
|
attachChat(program);
|
|
16453
16935
|
}
|
|
@@ -16550,12 +17032,12 @@ var SECRET_RESULT = {
|
|
|
16550
17032
|
{ header: "description" }
|
|
16551
17033
|
]
|
|
16552
17034
|
};
|
|
16553
|
-
function readValueArgument(raw) {
|
|
17035
|
+
async function readValueArgument(raw) {
|
|
16554
17036
|
if (raw.startsWith("@@"))
|
|
16555
17037
|
return raw.slice(1);
|
|
16556
17038
|
if (!raw.startsWith("@"))
|
|
16557
17039
|
return raw;
|
|
16558
|
-
return readArgumentSource(raw, "value").text;
|
|
17040
|
+
return (await readArgumentSource(raw, "value")).text;
|
|
16559
17041
|
}
|
|
16560
17042
|
function validateSecretValue(value) {
|
|
16561
17043
|
if (value.length === 0)
|
|
@@ -16575,7 +17057,7 @@ function validateWorkspaceOnlyFlag(flag, value, scope) {
|
|
|
16575
17057
|
}
|
|
16576
17058
|
async function readSecretValue(options) {
|
|
16577
17059
|
if (options.value !== undefined)
|
|
16578
|
-
return validateSecretValue(readValueArgument(options.value));
|
|
17060
|
+
return validateSecretValue(await readValueArgument(options.value));
|
|
16579
17061
|
if (options.description !== undefined || options.unredacted !== undefined)
|
|
16580
17062
|
return;
|
|
16581
17063
|
try {
|
|
@@ -16583,8 +17065,8 @@ async function readSecretValue(options) {
|
|
|
16583
17065
|
} catch (error) {
|
|
16584
17066
|
if (!(error instanceof SecretInputCancelledError))
|
|
16585
17067
|
throw error;
|
|
16586
|
-
|
|
16587
|
-
return
|
|
17068
|
+
printError(styles3().red(`Error: ${error.message}`));
|
|
17069
|
+
return exitCli(CANCELLED_EXIT_CODE);
|
|
16588
17070
|
}
|
|
16589
17071
|
}
|
|
16590
17072
|
async function setSecret(name, options, command, redactionSpellings) {
|
|
@@ -16786,7 +17268,7 @@ async function fetchDistTags(env, request) {
|
|
|
16786
17268
|
if (!url)
|
|
16787
17269
|
return null;
|
|
16788
17270
|
const text = await request(url, {
|
|
16789
|
-
headers: { accept: "application/json", "user-agent": `${PACKAGE_NAME}-cli/${
|
|
17271
|
+
headers: { accept: "application/json", "user-agent": `${PACKAGE_NAME}-cli/${cliVersion()}` },
|
|
16790
17272
|
maxResponseBytes: MAX_RESPONSE_BYTES,
|
|
16791
17273
|
timeoutMs: REGISTRY_TIMEOUT_MS
|
|
16792
17274
|
});
|
|
@@ -16913,7 +17395,7 @@ async function announceUpdateIfAvailable(options = {}) {
|
|
|
16913
17395
|
return;
|
|
16914
17396
|
if (isUnadvisableInstall(modulePath, env, cwd))
|
|
16915
17397
|
return;
|
|
16916
|
-
const currentVersion = options.currentVersion ??
|
|
17398
|
+
const currentVersion = options.currentVersion ?? cliVersion();
|
|
16917
17399
|
const current = parseStableVersion(currentVersion);
|
|
16918
17400
|
if (!current)
|
|
16919
17401
|
return;
|
|
@@ -16997,52 +17479,55 @@ function addVersionOption(program) {
|
|
|
16997
17479
|
}
|
|
16998
17480
|
program.error("error: --version reports the Sim CLI version and takes no value. A command that acts on a deployment version reads it from --to-version.");
|
|
16999
17481
|
});
|
|
17000
|
-
program.version(
|
|
17482
|
+
program.version(cliVersion(), "-V, --version [none]", "output the version number (takes no value)");
|
|
17001
17483
|
}
|
|
17002
17484
|
function buildProgram(options = {}) {
|
|
17003
|
-
const program = new Command;
|
|
17485
|
+
const program = options.program ?? new Command;
|
|
17004
17486
|
program.name("sim").description(PROGRAM_DESCRIPTION);
|
|
17005
17487
|
if (options.version !== false)
|
|
17006
17488
|
addVersionOption(program);
|
|
17007
17489
|
program.option("-P, --profile <name>", "Profile to use (env: SIM_PROFILE)").option("--endpoint <url>", "Sim deployment to talk to (env: SIM_ENDPOINT)").option("-w, --workspace <id>", "Workspace to target (env: SIM_WORKSPACE)").addOption(new Option("--output <format>", "Output format for this command").choices([...OUTPUT_FORMATS]));
|
|
17008
|
-
|
|
17009
|
-
|
|
17010
|
-
|
|
17011
|
-
|
|
17012
|
-
|
|
17490
|
+
for (const command of [
|
|
17491
|
+
loginCommand,
|
|
17492
|
+
logoutCommand,
|
|
17493
|
+
whoamiCommand,
|
|
17494
|
+
profilesCommand,
|
|
17495
|
+
configureCommand
|
|
17496
|
+
])
|
|
17497
|
+
program.addCommand(command());
|
|
17013
17498
|
for (const command of buildGeneratedCommands()) {
|
|
17014
17499
|
program.addCommand(command);
|
|
17015
17500
|
}
|
|
17016
17501
|
attachCredentialCommands(program);
|
|
17017
17502
|
attachProtocolCommands(program);
|
|
17018
17503
|
attachSecretCommands(program);
|
|
17019
|
-
program.addHelpText("after", HELP_EPILOGUE);
|
|
17504
|
+
program.addHelpText("after", options.helpText ?? HELP_EPILOGUE);
|
|
17020
17505
|
program.hook("preAction", () => announceUpdateIfAvailable());
|
|
17021
17506
|
refuseHelpAfterUnknownCommand(program);
|
|
17022
17507
|
assertNoReservedProgramFlags(program);
|
|
17023
17508
|
return program;
|
|
17024
17509
|
}
|
|
17025
17510
|
|
|
17026
|
-
// src/
|
|
17027
|
-
async function
|
|
17511
|
+
// src/terminal.ts
|
|
17512
|
+
async function runTerminalCli(program = buildProgram()) {
|
|
17028
17513
|
try {
|
|
17029
|
-
await
|
|
17514
|
+
await program.parseAsync(process.argv);
|
|
17030
17515
|
} catch (error) {
|
|
17031
17516
|
if (error instanceof ProfileConfigError) {
|
|
17032
|
-
console.error(
|
|
17517
|
+
console.error(styles3().red(`Error: ${sanitize(error.message)}`));
|
|
17033
17518
|
process.exit(1);
|
|
17034
17519
|
}
|
|
17035
17520
|
if (isRequestTimeout(error)) {
|
|
17036
|
-
console.error(
|
|
17521
|
+
console.error(styles3().red(`Error: the request timed out. ${RAISE_TIMEOUT_HINT}`));
|
|
17037
17522
|
process.exit(1);
|
|
17038
17523
|
}
|
|
17039
17524
|
if (error instanceof SimApiError) {
|
|
17040
|
-
console.error(
|
|
17525
|
+
console.error(styles3().red(`Error: ${sanitize(error.message)}`));
|
|
17041
17526
|
if (error.code)
|
|
17042
|
-
console.error(
|
|
17527
|
+
console.error(styles3().dim(` code: ${sanitize(error.code)}`));
|
|
17043
17528
|
if (error.details !== undefined) {
|
|
17044
17529
|
for (const line of formatApiErrorDetails(error.details)) {
|
|
17045
|
-
console.error(
|
|
17530
|
+
console.error(styles3().dim(sanitize(line)));
|
|
17046
17531
|
}
|
|
17047
17532
|
}
|
|
17048
17533
|
process.exit(1);
|
|
@@ -17050,4 +17535,6 @@ async function main() {
|
|
|
17050
17535
|
throw error;
|
|
17051
17536
|
}
|
|
17052
17537
|
}
|
|
17053
|
-
|
|
17538
|
+
|
|
17539
|
+
// src/index.ts
|
|
17540
|
+
runTerminalCli();
|