runwork 0.17.0 → 0.17.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/bundled-types/core-scheduler.d.ts +7 -0
- package/dist/index.js +819 -170
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -411,6 +411,29 @@ class ApiClient {
|
|
|
411
411
|
const res = await this.request("/api/dev/workspaces");
|
|
412
412
|
return res.data;
|
|
413
413
|
}
|
|
414
|
+
async listWorkspaceMembers(workspaceId) {
|
|
415
|
+
const res = await this.request(`/api/workspaces/${workspaceId}/members`);
|
|
416
|
+
return res.data.members;
|
|
417
|
+
}
|
|
418
|
+
async rawApiCall(method, path, opts) {
|
|
419
|
+
const targetPath = opts?.query ? `${path}${path.includes("?") ? "&" : "?"}${opts.query}` : path;
|
|
420
|
+
const url = `${this.baseUrl}${targetPath}`;
|
|
421
|
+
const headers = { ...opts?.headers || {} };
|
|
422
|
+
if (this.apiKey) {
|
|
423
|
+
headers["Authorization"] = `Bearer ${this.apiKey}`;
|
|
424
|
+
}
|
|
425
|
+
let body;
|
|
426
|
+
if (opts?.body !== undefined) {
|
|
427
|
+
body = typeof opts.body === "string" ? opts.body : JSON.stringify(opts.body);
|
|
428
|
+
if (!Object.keys(headers).some((h) => h.toLowerCase() === "content-type")) {
|
|
429
|
+
headers["Content-Type"] = "application/json";
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
const response = await httpFetch(url, { method: method.toUpperCase(), headers, body });
|
|
433
|
+
const contentType = response.headers.get("content-type") || "";
|
|
434
|
+
const responseBody = contentType.includes("application/json") ? await response.json() : await response.text();
|
|
435
|
+
return { status: response.status, ok: response.ok, contentType, body: responseBody };
|
|
436
|
+
}
|
|
414
437
|
async listApps(workspaceId) {
|
|
415
438
|
const query = workspaceId ? `?workspaceId=${workspaceId}` : "";
|
|
416
439
|
const res = await this.request(`/api/dev/apps${query}`);
|
|
@@ -883,20 +906,28 @@ var init_subprocess = () => {};
|
|
|
883
906
|
|
|
884
907
|
// src/git/credentials.ts
|
|
885
908
|
import { existsSync as existsSync2 } from "fs";
|
|
886
|
-
function buildHelperValue(execPath) {
|
|
909
|
+
function buildHelperValue(execPath, scriptPath) {
|
|
887
910
|
const normalised = execPath.replace(/\\/g, "/");
|
|
911
|
+
const runtimeName = normalised.split("/").pop()?.toLowerCase() ?? "";
|
|
912
|
+
if (SCRIPT_RUNTIMES.has(runtimeName) && scriptPath) {
|
|
913
|
+
const script = scriptPath.replace(/\\/g, "/");
|
|
914
|
+
return `!"${normalised}" "${script}" git-credential-helper`;
|
|
915
|
+
}
|
|
888
916
|
return `!"${normalised}" git-credential-helper`;
|
|
889
917
|
}
|
|
890
918
|
async function configureGitCredentials(remoteUrl) {
|
|
891
919
|
const origin = new URL(remoteUrl).origin;
|
|
892
|
-
const
|
|
920
|
+
const key = `credential.${origin}.helper`;
|
|
921
|
+
const helperValue = buildHelperValue(process.execPath, process.argv[1]);
|
|
893
922
|
try {
|
|
894
|
-
|
|
895
|
-
"config",
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
923
|
+
try {
|
|
924
|
+
execFileSync("git", ["config", "--global", "--unset-all", key], { stdio: "pipe" });
|
|
925
|
+
} catch (unsetErr) {
|
|
926
|
+
if (unsetErr?.code === "ENOENT")
|
|
927
|
+
throw unsetErr;
|
|
928
|
+
}
|
|
929
|
+
execFileSync("git", ["config", "--global", "--add", key, ""], { stdio: "pipe" });
|
|
930
|
+
execFileSync("git", ["config", "--global", "--add", key, helperValue], { stdio: "pipe" });
|
|
900
931
|
} catch (err) {
|
|
901
932
|
const code = err?.code;
|
|
902
933
|
if (code === "ENOENT") {
|
|
@@ -915,14 +946,37 @@ function lookupCredentialHelper(origin) {
|
|
|
915
946
|
} catch {
|
|
916
947
|
return { status: "none" };
|
|
917
948
|
}
|
|
918
|
-
const
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
949
|
+
const keyName = `credential.${origin}.helper`;
|
|
950
|
+
let value = "";
|
|
951
|
+
let registered = false;
|
|
952
|
+
let hasReset = false;
|
|
953
|
+
let otherCount = 0;
|
|
954
|
+
for (const raw of helperConfig.split(/\r?\n/)) {
|
|
955
|
+
if (!raw.trim())
|
|
956
|
+
continue;
|
|
957
|
+
const m = raw.match(/^(\S+)(?:\s+(.*))?$/);
|
|
958
|
+
if (!m)
|
|
959
|
+
continue;
|
|
960
|
+
const key = m[1];
|
|
961
|
+
const val = (m[2] ?? "").trim();
|
|
962
|
+
if (key === keyName) {
|
|
963
|
+
if (val === "")
|
|
964
|
+
hasReset = true;
|
|
965
|
+
else if (!registered) {
|
|
966
|
+
registered = true;
|
|
967
|
+
value = val;
|
|
968
|
+
}
|
|
969
|
+
} else {
|
|
970
|
+
otherCount++;
|
|
971
|
+
}
|
|
972
|
+
}
|
|
973
|
+
if (registered) {
|
|
974
|
+
return { status: "registered", value, hasReset };
|
|
975
|
+
}
|
|
976
|
+
if (otherCount === 0 && !hasReset) {
|
|
977
|
+
return { status: "none" };
|
|
924
978
|
}
|
|
925
|
-
return { status: "
|
|
979
|
+
return { status: "unscoped", otherCount };
|
|
926
980
|
}
|
|
927
981
|
function helperBinaryStatus(value) {
|
|
928
982
|
const absoluteHelperRegex = /^!"?(\/|[A-Za-z]:[\\/])/;
|
|
@@ -942,7 +996,7 @@ async function ensureGitCredentialHelper(baseUrl) {
|
|
|
942
996
|
return;
|
|
943
997
|
}
|
|
944
998
|
const lookup = lookupCredentialHelper(origin);
|
|
945
|
-
if (lookup.status === "registered" && helperBinaryStatus(lookup.value).ok) {
|
|
999
|
+
if (lookup.status === "registered" && helperBinaryStatus(lookup.value).ok && lookup.hasReset) {
|
|
946
1000
|
return;
|
|
947
1001
|
}
|
|
948
1002
|
await configureGitCredentials(baseUrl);
|
|
@@ -953,7 +1007,7 @@ async function removeGitCredentials(baseUrl) {
|
|
|
953
1007
|
execFileSync("git", [
|
|
954
1008
|
"config",
|
|
955
1009
|
"--global",
|
|
956
|
-
"--unset",
|
|
1010
|
+
"--unset-all",
|
|
957
1011
|
`credential.${origin}.helper`
|
|
958
1012
|
], { stdio: "pipe" });
|
|
959
1013
|
} catch {}
|
|
@@ -996,9 +1050,11 @@ function readStdin() {
|
|
|
996
1050
|
resolve(data);
|
|
997
1051
|
});
|
|
998
1052
|
}
|
|
1053
|
+
var SCRIPT_RUNTIMES;
|
|
999
1054
|
var init_credentials = __esm(() => {
|
|
1000
1055
|
init_subprocess();
|
|
1001
1056
|
init_store();
|
|
1057
|
+
SCRIPT_RUNTIMES = new Set(["node", "node.exe", "bun", "bun.exe"]);
|
|
1002
1058
|
});
|
|
1003
1059
|
|
|
1004
1060
|
// src/auth/login-flow.ts
|
|
@@ -1429,8 +1485,8 @@ async function resolveWorkspace(client, nameOrId) {
|
|
|
1429
1485
|
console.error(`Workspace "${nameOrId}" not found. Available: ${workspaces.map((w) => w.name).join(", ")}`);
|
|
1430
1486
|
process.exit(1);
|
|
1431
1487
|
}
|
|
1432
|
-
async function resolveApp(client, nameOrId) {
|
|
1433
|
-
const apps = await client.listApps();
|
|
1488
|
+
async function resolveApp(client, nameOrId, workspaceId) {
|
|
1489
|
+
const apps = await client.listApps(workspaceId);
|
|
1434
1490
|
if (apps.length === 0) {
|
|
1435
1491
|
console.error("No apps found.");
|
|
1436
1492
|
process.exit(1);
|
|
@@ -2422,7 +2478,7 @@ var init_clone = __esm(() => {
|
|
|
2422
2478
|
init_remote();
|
|
2423
2479
|
init_repo_config();
|
|
2424
2480
|
init_preflight();
|
|
2425
|
-
cloneCommand = new Command3("clone").description("Clone a Runwork app to local development").argument("[appId]", "App ID to clone (interactive if omitted)").argument("[directory]", "Target directory").option("--app <name-or-id>", "App name or ID (skips interactive selection)").addHelpText("after", RESTRICTED_FS_HELP).action(async (rawAppId, rawDirectory, options) => {
|
|
2481
|
+
cloneCommand = new Command3("clone").description("Clone a Runwork app to local development").argument("[appId]", "App ID to clone (interactive if omitted)").argument("[directory]", "Target directory").option("--app <name-or-id>", "App name or ID (skips interactive selection)").option("--workspace <name-or-id>", "Workspace to look up the app in (name or ID)").addHelpText("after", RESTRICTED_FS_HELP).action(async (rawAppId, rawDirectory, options) => {
|
|
2426
2482
|
requireGit("clone");
|
|
2427
2483
|
const { appId, directory } = normalizeCloneArgs(rawAppId, rawDirectory, options);
|
|
2428
2484
|
const creds = requireAuth();
|
|
@@ -2430,10 +2486,15 @@ var init_clone = __esm(() => {
|
|
|
2430
2486
|
const useJson = shouldOutputJson(undefined);
|
|
2431
2487
|
let app;
|
|
2432
2488
|
const appRef = options?.app || appId;
|
|
2489
|
+
let workspaceId;
|
|
2490
|
+
if (options?.workspace) {
|
|
2491
|
+
const ws = await resolveWorkspace(client, options.workspace);
|
|
2492
|
+
workspaceId = ws.id;
|
|
2493
|
+
}
|
|
2433
2494
|
if (appRef) {
|
|
2434
|
-
app = await resolveApp(client, appRef);
|
|
2495
|
+
app = await resolveApp(client, appRef, workspaceId);
|
|
2435
2496
|
} else {
|
|
2436
|
-
const apps = await client.listApps();
|
|
2497
|
+
const apps = await client.listApps(workspaceId);
|
|
2437
2498
|
if (apps.length === 0) {
|
|
2438
2499
|
if (useJson) {
|
|
2439
2500
|
jsonOut(buildErrorResponse("clone", "No apps found", "No apps are available to clone.", ["Create an app first with: runwork init my-app"]));
|
|
@@ -3307,13 +3368,20 @@ function resolvePollDeps(deps) {
|
|
|
3307
3368
|
}
|
|
3308
3369
|
async function pollForSession(appDir, expectedPid, expectedAppId, opts = {}) {
|
|
3309
3370
|
const intervalMs = opts.intervalMs ?? 250;
|
|
3310
|
-
const timeoutMs = opts.timeoutMs ??
|
|
3371
|
+
const timeoutMs = opts.timeoutMs ?? DETACH_READY_TIMEOUT_MS;
|
|
3372
|
+
const heartbeatMs = opts.heartbeatMs ?? DETACH_WAITING_HEARTBEAT_MS;
|
|
3311
3373
|
const d = resolvePollDeps(opts.deps);
|
|
3312
|
-
const
|
|
3374
|
+
const startedAt = d.now();
|
|
3375
|
+
const deadline = startedAt + timeoutMs;
|
|
3376
|
+
let lastHeartbeatAt = startedAt;
|
|
3313
3377
|
while (d.now() < deadline) {
|
|
3314
3378
|
if (opts.isChildAlive && !opts.isChildAlive()) {
|
|
3315
3379
|
return { result: "child-exited" };
|
|
3316
3380
|
}
|
|
3381
|
+
if (opts.onWaiting && d.now() - lastHeartbeatAt >= heartbeatMs) {
|
|
3382
|
+
lastHeartbeatAt = d.now();
|
|
3383
|
+
opts.onWaiting(d.now() - startedAt);
|
|
3384
|
+
}
|
|
3317
3385
|
const file = readSessionFile(appDir);
|
|
3318
3386
|
if (file && file.previewUrl && file.appId === expectedAppId) {
|
|
3319
3387
|
if (file.pid === expectedPid) {
|
|
@@ -3349,7 +3417,9 @@ async function runAsDetachedParent(opts) {
|
|
|
3349
3417
|
intervalMs: opts.intervalMs,
|
|
3350
3418
|
timeoutMs: opts.timeoutMs,
|
|
3351
3419
|
deps: opts.pollDeps,
|
|
3352
|
-
isChildAlive: child.isAlive
|
|
3420
|
+
isChildAlive: child.isAlive,
|
|
3421
|
+
onWaiting: opts.onWaiting,
|
|
3422
|
+
heartbeatMs: opts.heartbeatMs
|
|
3353
3423
|
});
|
|
3354
3424
|
if (outcome.result === "ready") {
|
|
3355
3425
|
return { result: "started", file: outcome.file };
|
|
@@ -3366,22 +3436,27 @@ async function runAsDetachedParent(opts) {
|
|
|
3366
3436
|
try {
|
|
3367
3437
|
removeSessionFileIfOwned(opts.appDir, child.pid);
|
|
3368
3438
|
} catch {}
|
|
3369
|
-
const childLogTail =
|
|
3439
|
+
const childLogTail = readChildLogTail(opts.appDir);
|
|
3370
3440
|
if (outcome.result === "child-exited") {
|
|
3371
3441
|
return { result: "child-exited", ourPid: child.pid, childLogTail };
|
|
3372
3442
|
}
|
|
3373
3443
|
return { result: "timeout", ourPid: child.pid, childLogTail };
|
|
3374
3444
|
}
|
|
3375
|
-
function
|
|
3376
|
-
|
|
3377
|
-
|
|
3378
|
-
|
|
3379
|
-
|
|
3380
|
-
|
|
3381
|
-
|
|
3382
|
-
|
|
3383
|
-
|
|
3445
|
+
function readChildLogTail(appDir) {
|
|
3446
|
+
const paths = getSessionPaths(appDir);
|
|
3447
|
+
const sections = [];
|
|
3448
|
+
for (const [label, file] of [["stderr", paths.stderrLog], ["stdout", paths.stdoutLog]]) {
|
|
3449
|
+
try {
|
|
3450
|
+
if (!fs2.existsSync(file))
|
|
3451
|
+
continue;
|
|
3452
|
+
const tail = fs2.readFileSync(file, "utf-8").slice(-2000).trim();
|
|
3453
|
+
if (tail)
|
|
3454
|
+
sections.push(`--- ${label} (tail) ---
|
|
3455
|
+
${tail}`);
|
|
3456
|
+
} catch {}
|
|
3384
3457
|
}
|
|
3458
|
+
return sections.length > 0 ? sections.join(`
|
|
3459
|
+
`) : undefined;
|
|
3385
3460
|
}
|
|
3386
3461
|
function defaultSpawnDetachedChild(childArgs) {
|
|
3387
3462
|
const cwd = process.cwd();
|
|
@@ -3441,7 +3516,7 @@ function buildChildArgs(parentArgv) {
|
|
|
3441
3516
|
}
|
|
3442
3517
|
return [...stripInternalChildFlag(rest), INTERNAL_DETACHED_CHILD_FLAG];
|
|
3443
3518
|
}
|
|
3444
|
-
var INTERNAL_DETACHED_CHILD_FLAG = "--internal-detached-child", realPollDeps;
|
|
3519
|
+
var INTERNAL_DETACHED_CHILD_FLAG = "--internal-detached-child", DETACH_READY_TIMEOUT_MS = 630000, DETACH_WAITING_HEARTBEAT_MS = 15000, realPollDeps;
|
|
3445
3520
|
var init_detach = __esm(() => {
|
|
3446
3521
|
init_session();
|
|
3447
3522
|
realPollDeps = {
|
|
@@ -3450,6 +3525,104 @@ var init_detach = __esm(() => {
|
|
|
3450
3525
|
};
|
|
3451
3526
|
});
|
|
3452
3527
|
|
|
3528
|
+
// src/dev/boot-await.ts
|
|
3529
|
+
function isPermanentStartError(err) {
|
|
3530
|
+
if (!(err instanceof Error))
|
|
3531
|
+
return false;
|
|
3532
|
+
const match = err.message.match(/^API error (\d{3})/);
|
|
3533
|
+
if (!match)
|
|
3534
|
+
return false;
|
|
3535
|
+
const status = Number.parseInt(match[1], 10);
|
|
3536
|
+
return status >= 400 && status < 500;
|
|
3537
|
+
}
|
|
3538
|
+
async function awaitDevSessionReady(opts) {
|
|
3539
|
+
const now = opts.deps?.now ?? (() => Date.now());
|
|
3540
|
+
const sleep = opts.deps?.sleep ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
|
|
3541
|
+
const timeoutMs = opts.timeoutMs ?? DEV_BOOT_TIMEOUT_MS;
|
|
3542
|
+
const heartbeatMs = opts.heartbeatMs ?? DEV_BOOT_HEARTBEAT_MS;
|
|
3543
|
+
const statusPollDelayMs = opts.statusPollDelayMs ?? DEV_BOOT_STATUS_POLL_DELAY_MS;
|
|
3544
|
+
const statusPollIntervalMs = opts.statusPollIntervalMs ?? DEV_BOOT_STATUS_POLL_INTERVAL_MS;
|
|
3545
|
+
const startedAt = now();
|
|
3546
|
+
const elapsed = () => now() - startedAt;
|
|
3547
|
+
const st = {
|
|
3548
|
+
startResult: null,
|
|
3549
|
+
startError: undefined,
|
|
3550
|
+
startSettled: false,
|
|
3551
|
+
permanentFailure: null,
|
|
3552
|
+
statusReady: null,
|
|
3553
|
+
statusInFlight: false
|
|
3554
|
+
};
|
|
3555
|
+
opts.start().then((session) => {
|
|
3556
|
+
st.startResult = session;
|
|
3557
|
+
st.startSettled = true;
|
|
3558
|
+
}, (err) => {
|
|
3559
|
+
st.startError = err;
|
|
3560
|
+
st.startSettled = true;
|
|
3561
|
+
if (isPermanentStartError(err)) {
|
|
3562
|
+
st.permanentFailure = err;
|
|
3563
|
+
} else {
|
|
3564
|
+
opts.onStartError?.(err);
|
|
3565
|
+
}
|
|
3566
|
+
});
|
|
3567
|
+
let lastStatusPollAt = -Infinity;
|
|
3568
|
+
let lastHeartbeatAt = startedAt;
|
|
3569
|
+
const readyResult = () => {
|
|
3570
|
+
if (st.startResult && st.startResult.previewUrl) {
|
|
3571
|
+
return { session: st.startResult, source: "start", elapsedMs: elapsed() };
|
|
3572
|
+
}
|
|
3573
|
+
if (st.statusReady) {
|
|
3574
|
+
return { session: st.statusReady, source: "status", elapsedMs: elapsed() };
|
|
3575
|
+
}
|
|
3576
|
+
return null;
|
|
3577
|
+
};
|
|
3578
|
+
while (elapsed() < timeoutMs) {
|
|
3579
|
+
if (st.permanentFailure)
|
|
3580
|
+
throw st.permanentFailure;
|
|
3581
|
+
const ready2 = readyResult();
|
|
3582
|
+
if (ready2)
|
|
3583
|
+
return ready2;
|
|
3584
|
+
const startFailedOrEmpty = st.startSettled && !(st.startResult && st.startResult.previewUrl);
|
|
3585
|
+
const pollingActive = elapsed() >= statusPollDelayMs || startFailedOrEmpty;
|
|
3586
|
+
if (pollingActive && !st.statusInFlight && now() - lastStatusPollAt >= statusPollIntervalMs) {
|
|
3587
|
+
st.statusInFlight = true;
|
|
3588
|
+
lastStatusPollAt = now();
|
|
3589
|
+
opts.pollStatus().then((session) => {
|
|
3590
|
+
st.statusInFlight = false;
|
|
3591
|
+
if (session.previewUrl)
|
|
3592
|
+
st.statusReady = session;
|
|
3593
|
+
}, () => {
|
|
3594
|
+
st.statusInFlight = false;
|
|
3595
|
+
});
|
|
3596
|
+
}
|
|
3597
|
+
if (now() - lastHeartbeatAt >= heartbeatMs) {
|
|
3598
|
+
lastHeartbeatAt = now();
|
|
3599
|
+
opts.onWaiting?.(elapsed());
|
|
3600
|
+
}
|
|
3601
|
+
await sleep(TICK_MS);
|
|
3602
|
+
}
|
|
3603
|
+
if (st.permanentFailure)
|
|
3604
|
+
throw st.permanentFailure;
|
|
3605
|
+
const ready = readyResult();
|
|
3606
|
+
if (ready)
|
|
3607
|
+
return ready;
|
|
3608
|
+
throw new DevBootTimeoutError(elapsed(), st.startError);
|
|
3609
|
+
}
|
|
3610
|
+
var DEV_BOOT_TIMEOUT_MS = 600000, DEV_BOOT_HEARTBEAT_MS = 15000, DEV_BOOT_STATUS_POLL_DELAY_MS = 45000, DEV_BOOT_STATUS_POLL_INTERVAL_MS = 1e4, DevBootTimeoutError, TICK_MS = 250;
|
|
3611
|
+
var init_boot_await = __esm(() => {
|
|
3612
|
+
DevBootTimeoutError = class DevBootTimeoutError extends Error {
|
|
3613
|
+
elapsedMs;
|
|
3614
|
+
startError;
|
|
3615
|
+
constructor(elapsedMs, startError) {
|
|
3616
|
+
const base = `Dev session did not become ready within ${Math.round(elapsedMs / 1000)}s`;
|
|
3617
|
+
const cause = startError instanceof Error ? ` (boot call failed: ${startError.message})` : "";
|
|
3618
|
+
super(`${base}${cause}`);
|
|
3619
|
+
this.name = "DevBootTimeoutError";
|
|
3620
|
+
this.elapsedMs = elapsedMs;
|
|
3621
|
+
this.startError = startError;
|
|
3622
|
+
}
|
|
3623
|
+
};
|
|
3624
|
+
});
|
|
3625
|
+
|
|
3453
3626
|
// src/dev/stop.ts
|
|
3454
3627
|
import * as fs3 from "fs";
|
|
3455
3628
|
async function stopSession(appDir, expectedAppId, deps = {}) {
|
|
@@ -5652,6 +5825,13 @@ export interface JobRunRecord {
|
|
|
5652
5825
|
completedAt?: number;
|
|
5653
5826
|
result?: JobResult;
|
|
5654
5827
|
error?: string;
|
|
5828
|
+
/**
|
|
5829
|
+
* Stack trace of the failure. Stored because the error MESSAGE alone made
|
|
5830
|
+
* the 2026-07 "Could not serialize object of type ..." production failures
|
|
5831
|
+
* undiagnosable: the message names the workerd serializer, not the framework
|
|
5832
|
+
* call site that hit it (AGENTCLI-6).
|
|
5833
|
+
*/
|
|
5834
|
+
errorStack?: string;
|
|
5655
5835
|
}
|
|
5656
5836
|
export interface ScheduleState {
|
|
5657
5837
|
name: string;
|
|
@@ -7381,7 +7561,7 @@ function createKeyboardListener() {
|
|
|
7381
7561
|
}
|
|
7382
7562
|
|
|
7383
7563
|
// src/generated/version.ts
|
|
7384
|
-
var VERSION = "0.17.
|
|
7564
|
+
var VERSION = "0.17.1";
|
|
7385
7565
|
|
|
7386
7566
|
// src/commands/dev.ts
|
|
7387
7567
|
var exports_dev = {};
|
|
@@ -7515,7 +7695,64 @@ async function execDev(options) {
|
|
|
7515
7695
|
} else {
|
|
7516
7696
|
console.log(dim("Starting dev session..."));
|
|
7517
7697
|
}
|
|
7518
|
-
|
|
7698
|
+
let session;
|
|
7699
|
+
try {
|
|
7700
|
+
const boot = await awaitDevSessionReady({
|
|
7701
|
+
start: () => client.startDevSession(config.appId),
|
|
7702
|
+
pollStatus: () => client.getDevStatus(config.appId),
|
|
7703
|
+
onWaiting: (elapsedMs) => {
|
|
7704
|
+
const seconds = Math.round(elapsedMs / 1000);
|
|
7705
|
+
if (useJson) {
|
|
7706
|
+
jsonLine({
|
|
7707
|
+
event: "startup",
|
|
7708
|
+
phase: "dev_session_waiting",
|
|
7709
|
+
elapsedSeconds: seconds,
|
|
7710
|
+
timestamp: ts(),
|
|
7711
|
+
note: "Sandbox is booting. Cold boots can take a few minutes; keep waiting."
|
|
7712
|
+
});
|
|
7713
|
+
} else {
|
|
7714
|
+
console.log(dim(` Still starting the sandbox... (${seconds}s elapsed; cold boots can take a few minutes)`));
|
|
7715
|
+
}
|
|
7716
|
+
},
|
|
7717
|
+
onStartError: (err) => {
|
|
7718
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
7719
|
+
if (useJson) {
|
|
7720
|
+
jsonLine({
|
|
7721
|
+
event: "startup",
|
|
7722
|
+
phase: "dev_session_retrying",
|
|
7723
|
+
timestamp: ts(),
|
|
7724
|
+
warning: `Boot call failed (${message}). The sandbox may still be booting server-side; watching status until it becomes ready.`
|
|
7725
|
+
});
|
|
7726
|
+
} else {
|
|
7727
|
+
console.warn(yellow(` Boot call failed (${message}); watching sandbox status in case the boot completes server-side...`));
|
|
7728
|
+
}
|
|
7729
|
+
}
|
|
7730
|
+
});
|
|
7731
|
+
session = boot.session;
|
|
7732
|
+
} catch (error) {
|
|
7733
|
+
const isTimeout = error instanceof DevBootTimeoutError;
|
|
7734
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
7735
|
+
if (useJson) {
|
|
7736
|
+
jsonLine({
|
|
7737
|
+
event: "error",
|
|
7738
|
+
phase: "dev_session",
|
|
7739
|
+
timestamp: ts(),
|
|
7740
|
+
error: {
|
|
7741
|
+
message,
|
|
7742
|
+
diagnosis: isTimeout ? "The preview sandbox did not become ready within the boot deadline. The sandbox provider may be degraded, or the app failed to boot server-side." : "The dev session boot call failed.",
|
|
7743
|
+
suggestions: [
|
|
7744
|
+
"Re-run `runwork dev --detach --json` in about a minute; if the sandbox finished booting server-side it will be picked up quickly",
|
|
7745
|
+
"Run `runwork logs` to inspect sandbox logs for boot errors",
|
|
7746
|
+
"Run `runwork doctor` to verify auth and connectivity"
|
|
7747
|
+
]
|
|
7748
|
+
}
|
|
7749
|
+
});
|
|
7750
|
+
} else {
|
|
7751
|
+
console.error(red(`Failed to start dev session: ${message}`));
|
|
7752
|
+
console.error(dim(" Re-run `runwork dev` in about a minute; if the sandbox finished booting server-side it will be picked up quickly."));
|
|
7753
|
+
}
|
|
7754
|
+
process.exit(1);
|
|
7755
|
+
}
|
|
7519
7756
|
await populateSkill(cwd, client, config.appId);
|
|
7520
7757
|
if (useJson)
|
|
7521
7758
|
jsonLine({ event: "startup", phase: "skill_fetched", timestamp: ts() });
|
|
@@ -7804,7 +8041,21 @@ async function runDevDetachParent(opts) {
|
|
|
7804
8041
|
const outcome = await runAsDetachedParent({
|
|
7805
8042
|
appDir: cwd,
|
|
7806
8043
|
expectedAppId: config.appId,
|
|
7807
|
-
childArgs
|
|
8044
|
+
childArgs,
|
|
8045
|
+
onWaiting: (elapsedMs) => {
|
|
8046
|
+
const seconds = Math.round(elapsedMs / 1000);
|
|
8047
|
+
if (opts.json) {
|
|
8048
|
+
jsonLine({
|
|
8049
|
+
event: "waiting",
|
|
8050
|
+
phase: "sandbox_boot",
|
|
8051
|
+
elapsedSeconds: seconds,
|
|
8052
|
+
timestamp: ts(),
|
|
8053
|
+
note: "Sandbox is booting. Cold boots can take a few minutes; keep waiting for session_started."
|
|
8054
|
+
});
|
|
8055
|
+
} else {
|
|
8056
|
+
console.log(dim(` Still starting... (${seconds}s elapsed; cold boots can take a few minutes)`));
|
|
8057
|
+
}
|
|
8058
|
+
}
|
|
7808
8059
|
});
|
|
7809
8060
|
switch (outcome.result) {
|
|
7810
8061
|
case "started": {
|
|
@@ -7862,9 +8113,10 @@ async function runDevDetachParent(opts) {
|
|
|
7862
8113
|
timestamp: ts(),
|
|
7863
8114
|
error: {
|
|
7864
8115
|
message,
|
|
7865
|
-
diagnosis: "The detached child process exited (typically due to missing auth, missing git, network failure, or a
|
|
8116
|
+
diagnosis: "The detached child process exited (typically due to missing auth, missing git, network failure, a sync conflict, or a sandbox boot timeout) before it could publish a preview URL.",
|
|
7866
8117
|
suggestions: [
|
|
7867
|
-
"
|
|
8118
|
+
"Check childLogTail below; the child logs structured errors to .runwork/dev-stdout.log (stderr carries crash traces)",
|
|
8119
|
+
"If the child hit a sandbox boot timeout, re-run `runwork dev --detach --json` in about a minute; a boot that completed server-side is picked up quickly",
|
|
7868
8120
|
"Run `runwork doctor` to verify auth and connectivity",
|
|
7869
8121
|
"Try `runwork dev` (foreground) to see the failure inline"
|
|
7870
8122
|
],
|
|
@@ -7873,7 +8125,7 @@ async function runDevDetachParent(opts) {
|
|
|
7873
8125
|
});
|
|
7874
8126
|
} else {
|
|
7875
8127
|
console.error(yellow(message));
|
|
7876
|
-
console.error(dim(" Inspect .runwork/dev-stderr.log or run `runwork dev` to see what failed."));
|
|
8128
|
+
console.error(dim(" Inspect .runwork/dev-stdout.log and dev-stderr.log, or run `runwork dev` to see what failed."));
|
|
7877
8129
|
if (outcome.childLogTail) {
|
|
7878
8130
|
console.error(dim(" Tail of child stderr:"));
|
|
7879
8131
|
for (const line of outcome.childLogTail.split(`
|
|
@@ -7887,7 +8139,8 @@ async function runDevDetachParent(opts) {
|
|
|
7887
8139
|
return;
|
|
7888
8140
|
}
|
|
7889
8141
|
case "timeout": {
|
|
7890
|
-
const
|
|
8142
|
+
const timeoutSeconds = Math.round(DETACH_READY_TIMEOUT_MS / 1000);
|
|
8143
|
+
const message = `Detached dev session did not become ready within ${timeoutSeconds}s.`;
|
|
7891
8144
|
if (opts.json) {
|
|
7892
8145
|
jsonLine({
|
|
7893
8146
|
event: "error",
|
|
@@ -7895,9 +8148,10 @@ async function runDevDetachParent(opts) {
|
|
|
7895
8148
|
timestamp: ts(),
|
|
7896
8149
|
error: {
|
|
7897
8150
|
message,
|
|
7898
|
-
diagnosis: "The detached child process was spawned but never wrote a session file with a preview URL. The sandbox boot may have failed.",
|
|
8151
|
+
diagnosis: "The detached child process was spawned but never wrote a session file with a preview URL. The sandbox boot may have failed or the sandbox provider may be degraded.",
|
|
7899
8152
|
suggestions: [
|
|
7900
|
-
"
|
|
8153
|
+
"The sandbox may still finish booting server-side: re-run `runwork dev --detach --json` in about a minute; a completed boot is picked up quickly",
|
|
8154
|
+
"Inspect the child logs at .runwork/dev-stdout.log and .runwork/dev-stderr.log",
|
|
7901
8155
|
"Run `runwork doctor` to verify auth and connectivity",
|
|
7902
8156
|
"Try `runwork dev` (foreground) to see the failure inline"
|
|
7903
8157
|
],
|
|
@@ -7906,7 +8160,7 @@ async function runDevDetachParent(opts) {
|
|
|
7906
8160
|
});
|
|
7907
8161
|
} else {
|
|
7908
8162
|
console.error(yellow(message));
|
|
7909
|
-
console.error(dim(" Inspect .runwork/dev-stderr.log or run `runwork dev` to see what failed."));
|
|
8163
|
+
console.error(dim(" Inspect .runwork/dev-stdout.log and dev-stderr.log, or run `runwork dev` to see what failed."));
|
|
7910
8164
|
if (outcome.childLogTail) {
|
|
7911
8165
|
console.error(dim(" Tail of child stderr:"));
|
|
7912
8166
|
for (const line of outcome.childLogTail.split(`
|
|
@@ -7956,6 +8210,7 @@ var init_dev = __esm(() => {
|
|
|
7956
8210
|
init_tailer();
|
|
7957
8211
|
init_session();
|
|
7958
8212
|
init_detach();
|
|
8213
|
+
init_boot_await();
|
|
7959
8214
|
init_stop();
|
|
7960
8215
|
init_attach();
|
|
7961
8216
|
init_types_manager();
|
|
@@ -8291,7 +8546,7 @@ var init_welcome = __esm(() => {
|
|
|
8291
8546
|
});
|
|
8292
8547
|
|
|
8293
8548
|
// src/index.ts
|
|
8294
|
-
import { Command as
|
|
8549
|
+
import { Command as Command36 } from "commander";
|
|
8295
8550
|
|
|
8296
8551
|
// src/commands/login.ts
|
|
8297
8552
|
init_login_flow();
|
|
@@ -8394,8 +8649,23 @@ function getDeploySummary(cwd) {
|
|
|
8394
8649
|
}
|
|
8395
8650
|
|
|
8396
8651
|
// src/deploy/deploy-status.ts
|
|
8652
|
+
init_session();
|
|
8397
8653
|
import { existsSync as existsSync16, mkdirSync as mkdirSync11, readFileSync as readFileSync13, writeFileSync as writeFileSync12 } from "fs";
|
|
8398
8654
|
import { dirname as dirname4, join as join17 } from "path";
|
|
8655
|
+
function evaluateDeployStatus(status, deps = {}) {
|
|
8656
|
+
if (status.state !== "in-progress") {
|
|
8657
|
+
return { status, effectiveState: status.state };
|
|
8658
|
+
}
|
|
8659
|
+
const bootTime = deps.bootTime ?? currentBootTime;
|
|
8660
|
+
const pidAlive = deps.pidAlive ?? isPidAlive;
|
|
8661
|
+
if (typeof status.bootTime === "number" && Math.abs(bootTime() - status.bootTime) > BOOT_TIME_TOLERANCE_MS) {
|
|
8662
|
+
return { status, effectiveState: "stale", staleReason: "boot-time-mismatch" };
|
|
8663
|
+
}
|
|
8664
|
+
if (typeof status.pid === "number" && !pidAlive(status.pid)) {
|
|
8665
|
+
return { status, effectiveState: "stale", staleReason: "process-gone" };
|
|
8666
|
+
}
|
|
8667
|
+
return { status, effectiveState: "in-progress" };
|
|
8668
|
+
}
|
|
8399
8669
|
function statusPath(cwd) {
|
|
8400
8670
|
return join17(cwd, ".runwork", "deploy-status.json");
|
|
8401
8671
|
}
|
|
@@ -8425,6 +8695,9 @@ function readDeployStatus(cwd) {
|
|
|
8425
8695
|
}
|
|
8426
8696
|
}
|
|
8427
8697
|
|
|
8698
|
+
// src/commands/deploy.ts
|
|
8699
|
+
init_session();
|
|
8700
|
+
|
|
8428
8701
|
// src/deploy/detach.ts
|
|
8429
8702
|
init_detach();
|
|
8430
8703
|
import * as fs5 from "fs";
|
|
@@ -8536,7 +8809,7 @@ var deployCommand = new Command5("deploy").description("Deploy the current app t
|
|
|
8536
8809
|
if (opts.detach && !isChild) {
|
|
8537
8810
|
const startedAt = new Date().toISOString();
|
|
8538
8811
|
const handle = spawnDetachedDeploy(buildDeployChildArgs(process.argv), cwd);
|
|
8539
|
-
writeDeployStatus(cwd, { state: "in-progress", startedAt, pid: handle.pid });
|
|
8812
|
+
writeDeployStatus(cwd, { state: "in-progress", startedAt, pid: handle.pid, bootTime: currentBootTime() });
|
|
8540
8813
|
if (useJson) {
|
|
8541
8814
|
jsonLine({ event: "deploy_started", detached: true, pid: handle.pid, logPath: deployLogPath(cwd), startedAt, hint: "Poll `runwork deploy --status` for completion." });
|
|
8542
8815
|
} else {
|
|
@@ -8639,7 +8912,7 @@ var deployCommand = new Command5("deploy").description("Deploy the current app t
|
|
|
8639
8912
|
const deployed = deploymentUrl.length > 0;
|
|
8640
8913
|
if (!deployed) {
|
|
8641
8914
|
if (useJson) {
|
|
8642
|
-
jsonOut(buildErrorResponse("deploy", "Deployment did not produce a URL", "The deploy API returned no deployment URL. The deploy may have been a no-op (no changes) or failed server-side.", ["Confirm your changes were committed and pushed (the sync step above succeeded)", "Run runwork info to check the deployed state", "
|
|
8915
|
+
jsonOut(buildErrorResponse("deploy", "Deployment did not produce a URL", "The deploy API returned no deployment URL. The deploy may have been a no-op (no changes) or failed server-side (e.g. a build error).", ['Run `runwork logs --events --once` and look for a "Build failed" error in recent deployment events', "If a build failed on stale sandbox files, run `runwork dev --restart --detach` to resync, then retry the deploy", "Confirm your changes were committed and pushed (the sync step above succeeded)", "Run runwork info to check the deployed state", "Retry runwork deploy"]));
|
|
8643
8916
|
process.exit(1);
|
|
8644
8917
|
}
|
|
8645
8918
|
console.error("Deploy did not return a URL. The deploy may have been a no-op or failed server-side.");
|
|
@@ -8679,14 +8952,24 @@ var deployCommand = new Command5("deploy").description("Deploy the current app t
|
|
|
8679
8952
|
function printDeployStatus(cwd, useJson) {
|
|
8680
8953
|
const status = readDeployStatus(cwd);
|
|
8681
8954
|
const summary = getDeploySummary(cwd);
|
|
8955
|
+
const evaluated = status ? evaluateDeployStatus(status) : null;
|
|
8956
|
+
const staleHint = "The deploy process died before recording an outcome. The deploy may still have completed server-side (the push precedes the deploy call). Verify with `runwork logs --production --once` or `runwork apps info`, then re-run `runwork deploy` if needed.";
|
|
8682
8957
|
if (useJson) {
|
|
8683
|
-
jsonOut({
|
|
8958
|
+
jsonOut({
|
|
8959
|
+
success: true,
|
|
8960
|
+
command: "deploy",
|
|
8961
|
+
result: {
|
|
8962
|
+
status: evaluated ? { ...evaluated.status, state: evaluated.effectiveState, staleReason: evaluated.staleReason } : null,
|
|
8963
|
+
deploy: summary,
|
|
8964
|
+
hint: evaluated?.effectiveState === "stale" ? staleHint : undefined
|
|
8965
|
+
}
|
|
8966
|
+
});
|
|
8684
8967
|
return;
|
|
8685
8968
|
}
|
|
8686
|
-
if (!status) {
|
|
8969
|
+
if (!status || !evaluated) {
|
|
8687
8970
|
console.log("No deploy has been started from this machine yet.");
|
|
8688
8971
|
} else {
|
|
8689
|
-
const label =
|
|
8972
|
+
const label = evaluated.effectiveState === "succeeded" ? green("succeeded") : evaluated.effectiveState === "failed" ? yellow("failed") : evaluated.effectiveState === "stale" ? yellow(`stale (${evaluated.staleReason})`) : "in-progress";
|
|
8690
8973
|
console.log(`Last deploy: ${label}`);
|
|
8691
8974
|
console.log(dim(` started: ${status.startedAt}`));
|
|
8692
8975
|
if (status.finishedAt)
|
|
@@ -8695,8 +8978,10 @@ function printDeployStatus(cwd, useJson) {
|
|
|
8695
8978
|
console.log(dim(` url: ${status.url}`));
|
|
8696
8979
|
if (status.error)
|
|
8697
8980
|
console.log(yellow(` error: ${status.error}`));
|
|
8698
|
-
if (
|
|
8981
|
+
if (evaluated.effectiveState === "in-progress")
|
|
8699
8982
|
console.log(dim(` logs: ${deployLogPath(cwd)}`));
|
|
8983
|
+
if (evaluated.effectiveState === "stale")
|
|
8984
|
+
console.log(yellow(` ${staleHint}`));
|
|
8700
8985
|
}
|
|
8701
8986
|
if (summary.deployedShortSha) {
|
|
8702
8987
|
const sync = summary.inSync === true ? green("in sync") : summary.inSync === false ? yellow("local has undeployed commits") : dim("unknown");
|
|
@@ -9280,9 +9565,14 @@ import { readFileSync as readFileSync18, existsSync as existsSync21 } from "fs";
|
|
|
9280
9565
|
init_store();
|
|
9281
9566
|
init_prompt();
|
|
9282
9567
|
import { existsSync as existsSync20, readFileSync as readFileSync17 } from "fs";
|
|
9568
|
+
var UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
9283
9569
|
async function resolveWorkspace2(client, options = {}) {
|
|
9284
9570
|
if (options.workspace) {
|
|
9285
|
-
|
|
9571
|
+
if (UUID_RE.test(options.workspace)) {
|
|
9572
|
+
return { workspaceId: options.workspace, workspaceName: "", source: "flag" };
|
|
9573
|
+
}
|
|
9574
|
+
const ws2 = await resolveWorkspace(client, options.workspace);
|
|
9575
|
+
return { workspaceId: ws2.id, workspaceName: ws2.name, source: "flag" };
|
|
9286
9576
|
}
|
|
9287
9577
|
if (process.env.WORKSPACE_ID) {
|
|
9288
9578
|
return { workspaceId: process.env.WORKSPACE_ID, workspaceName: "", source: "flag" };
|
|
@@ -9317,6 +9607,10 @@ async function resolveWorkspace2(client, options = {}) {
|
|
|
9317
9607
|
saveDefaultWorkspace(ws2.id, ws2.name);
|
|
9318
9608
|
return { workspaceId: ws2.id, workspaceName: ws2.name, source: "prompt" };
|
|
9319
9609
|
}
|
|
9610
|
+
if (!process.stdout.isTTY) {
|
|
9611
|
+
console.error(`Workspace required. Pass --workspace <name-or-id>. Available: ${workspaces.map((w) => w.name).join(", ")}`);
|
|
9612
|
+
process.exit(1);
|
|
9613
|
+
}
|
|
9320
9614
|
const choices = workspaces.map((ws2) => ({ label: ws2.name, value: ws2.id }));
|
|
9321
9615
|
const chosen = await promptSelect("Select a workspace:", choices);
|
|
9322
9616
|
const ws = workspaces.find((w) => w.id === chosen.value);
|
|
@@ -9545,7 +9839,13 @@ async function parseCurlToRequest(curlStr) {
|
|
|
9545
9839
|
}
|
|
9546
9840
|
|
|
9547
9841
|
// src/commands/integrations.ts
|
|
9548
|
-
|
|
9842
|
+
function resolveIntegrationConnection(integrations, integration) {
|
|
9843
|
+
const match = integrations.find((i) => (i.canonicalId || i.integrationId) === integration || i.provider === integration);
|
|
9844
|
+
if (!match)
|
|
9845
|
+
return null;
|
|
9846
|
+
return { connectionId: match.id || match.integrationId, match };
|
|
9847
|
+
}
|
|
9848
|
+
var searchCommand = new Command10("search").description("Search available integrations from the platform catalog").argument("<query>", 'Search query (e.g., "google drive", "hubspot", "slack")').option("--limit <n>", "Maximum results to show", "20").option("--workspace <name-or-id>", "Workspace name or ID (enables team usage info)").action(async (query, opts, command) => {
|
|
9549
9849
|
const useJson = shouldOutputJson(command.optsWithGlobals().json);
|
|
9550
9850
|
const credentials = requireAuth();
|
|
9551
9851
|
const client = new ApiClient(credentials);
|
|
@@ -9604,7 +9904,7 @@ Usage: Add the integration ID to APP_INTEGRATION_REQUIREMENTS in worker/integrat
|
|
|
9604
9904
|
process.exit(1);
|
|
9605
9905
|
}
|
|
9606
9906
|
});
|
|
9607
|
-
var listCommand = new Command10("list").description("List connected workspace integrations").option("--workspace <id>", "Workspace ID").action(async (opts, command) => {
|
|
9907
|
+
var listCommand = new Command10("list").description("List connected workspace integrations").option("--workspace <name-or-id>", "Workspace name or ID").action(async (opts, command) => {
|
|
9608
9908
|
const useJson = shouldOutputJson(command.optsWithGlobals().json);
|
|
9609
9909
|
const credentials = requireAuth();
|
|
9610
9910
|
const client = new ApiClient(credentials);
|
|
@@ -9657,7 +9957,7 @@ Used by your team (${teamOnly.length} more):
|
|
|
9657
9957
|
process.exit(1);
|
|
9658
9958
|
}
|
|
9659
9959
|
});
|
|
9660
|
-
var callCommand = new Command10("call").description("Make a proxy call to a connected integration").argument("<integration>", "Integration name (e.g., hubspot, slack)").argument("[method]", "HTTP method (GET, POST, PUT, DELETE)").argument("[path]", "API path (e.g., /crm/v3/contacts)").option("--workspace <id>", "Workspace ID").option("--body <json>", "Request body JSON").option("--header <header>", "Request header (repeatable)", (val, prev) => [...prev, val], []).option("--query <query>", "Query string (e.g., limit=10&offset=0)").option("--curl <command>", 'Parse a curl command (paste from Chrome DevTools "Copy as cURL")').option("--curl-file <file>", "Read curl command from a file").action(async (integration, method, path2, opts, command) => {
|
|
9960
|
+
var callCommand = new Command10("call").description("Make a proxy call to a connected integration").argument("<integration>", "Integration name (e.g., hubspot, slack)").argument("[method]", "HTTP method (GET, POST, PUT, DELETE)").argument("[path]", "API path (e.g., /crm/v3/contacts)").option("--workspace <name-or-id>", "Workspace name or ID").option("--body <json>", "Request body JSON").option("--header <header>", "Request header (repeatable)", (val, prev) => [...prev, val], []).option("--query <query>", "Query string (e.g., limit=10&offset=0)").option("--curl <command>", 'Parse a curl command (paste from Chrome DevTools "Copy as cURL")').option("--curl-file <file>", "Read curl command from a file").action(async (integration, method, path2, opts, command) => {
|
|
9661
9961
|
const useJson = shouldOutputJson(command.optsWithGlobals().json);
|
|
9662
9962
|
const credentials = requireAuth();
|
|
9663
9963
|
const client = new ApiClient(credentials);
|
|
@@ -9711,12 +10011,12 @@ var callCommand = new Command10("call").description("Make a proxy call to a conn
|
|
|
9711
10011
|
}
|
|
9712
10012
|
try {
|
|
9713
10013
|
const integrations = await client.listConnectedIntegrations(workspaceId);
|
|
9714
|
-
const
|
|
9715
|
-
if (!
|
|
10014
|
+
const resolved = resolveIntegrationConnection(integrations, integration);
|
|
10015
|
+
if (!resolved) {
|
|
9716
10016
|
console.error(`Integration "${integration}" not found. Run "runwork integrations list" to see connected integrations.`);
|
|
9717
10017
|
process.exit(1);
|
|
9718
10018
|
}
|
|
9719
|
-
const result = await client.callIntegrationProxy(
|
|
10019
|
+
const result = await client.callIntegrationProxy(resolved.connectionId, finalMethod, finalPath, { body, headers: Object.keys(headers).length > 0 ? headers : undefined, query });
|
|
9720
10020
|
if (useJson) {
|
|
9721
10021
|
jsonOut(result);
|
|
9722
10022
|
return;
|
|
@@ -10345,7 +10645,7 @@ function truncate(text2, max) {
|
|
|
10345
10645
|
return first;
|
|
10346
10646
|
return first.slice(0, max - 3) + "...";
|
|
10347
10647
|
}
|
|
10348
|
-
var listCommand2 = new Command13("list").description("List workspace skills (app, external, MCP-generated)").option("--workspace <id>", "Workspace ID").action(async (opts, command) => {
|
|
10648
|
+
var listCommand2 = new Command13("list").description("List workspace skills (app, external, MCP-generated)").option("--workspace <name-or-id>", "Workspace name or ID").action(async (opts, command) => {
|
|
10349
10649
|
const useJson = shouldOutputJson(command.optsWithGlobals().json);
|
|
10350
10650
|
const credentials = requireAuth();
|
|
10351
10651
|
const client = new ApiClient(credentials);
|
|
@@ -10402,7 +10702,7 @@ async function readStdin2() {
|
|
|
10402
10702
|
}
|
|
10403
10703
|
return Buffer.concat(chunks).toString("utf-8");
|
|
10404
10704
|
}
|
|
10405
|
-
var pushCommand = new Command13("push").description("Upload a local skill file to workspace (upsert by name). Accepts piped content via stdin.").argument("[first]", "Skill name (if piping content) or file path (name from frontmatter)").argument("[second]", "File path (when first arg is the skill name)").option("--workspace <id>", "Workspace ID").action(async (first, second, opts, command) => {
|
|
10705
|
+
var pushCommand = new Command13("push").description("Upload a local skill file to workspace (upsert by name). Accepts piped content via stdin.").argument("[first]", "Skill name (if piping content) or file path (name from frontmatter)").argument("[second]", "File path (when first arg is the skill name)").option("--workspace <name-or-id>", "Workspace name or ID").action(async (first, second, opts, command) => {
|
|
10406
10706
|
const useJson = shouldOutputJson(command.optsWithGlobals().json);
|
|
10407
10707
|
const credentials = requireAuth();
|
|
10408
10708
|
const client = new ApiClient(credentials);
|
|
@@ -10497,7 +10797,7 @@ var pushCommand = new Command13("push").description("Upload a local skill file t
|
|
|
10497
10797
|
process.exit(1);
|
|
10498
10798
|
}
|
|
10499
10799
|
});
|
|
10500
|
-
var pullCommand = new Command13("pull").alias("download").description("Download a skill from the workspace and print to stdout (or save to file)").argument("<name>", "Skill name or ID").option("--workspace <id>", "Workspace ID").option("-o, --output <file>", "Save to file instead of stdout").action(async (nameOrId, opts, command) => {
|
|
10800
|
+
var pullCommand = new Command13("pull").alias("download").description("Download a skill from the workspace and print to stdout (or save to file)").argument("<name>", "Skill name or ID").option("--workspace <name-or-id>", "Workspace name or ID").option("-o, --output <file>", "Save to file instead of stdout").action(async (nameOrId, opts, command) => {
|
|
10501
10801
|
const useJson = shouldOutputJson(command.optsWithGlobals().json);
|
|
10502
10802
|
const credentials = requireAuth();
|
|
10503
10803
|
const client = new ApiClient(credentials);
|
|
@@ -10600,7 +10900,7 @@ var searchCommand2 = new Command13("search").description("Search community skill
|
|
|
10600
10900
|
process.exit(1);
|
|
10601
10901
|
}
|
|
10602
10902
|
});
|
|
10603
|
-
var installCommand = new Command13("install").description("Install a community skill from skills.sh into your workspace").argument("<identifier>", "Skill identifier: source/skill-id (e.g. vercel-labs/skills/find-skills)").option("--workspace <id>", "Workspace ID").action(async (identifier, opts, command) => {
|
|
10903
|
+
var installCommand = new Command13("install").description("Install a community skill from skills.sh into your workspace").argument("<identifier>", "Skill identifier: source/skill-id (e.g. vercel-labs/skills/find-skills)").option("--workspace <name-or-id>", "Workspace name or ID").action(async (identifier, opts, command) => {
|
|
10604
10904
|
const useJson = shouldOutputJson(command.optsWithGlobals().json);
|
|
10605
10905
|
const credentials = requireAuth();
|
|
10606
10906
|
const client = new ApiClient(credentials);
|
|
@@ -13517,14 +13817,15 @@ var AGENT_REGISTRY = [
|
|
|
13517
13817
|
method: "any",
|
|
13518
13818
|
target: [
|
|
13519
13819
|
{ method: "path", target: { macos: "/Applications/Codex.app" } },
|
|
13520
|
-
{ method: "
|
|
13820
|
+
{ method: "macos-bundle-id", target: "com.openai.codex" },
|
|
13821
|
+
{ method: "windows-appx", target: ["OpenAI.Codex"] }
|
|
13521
13822
|
]
|
|
13522
13823
|
},
|
|
13523
|
-
launch: { app: { macos: "Codex", windows: "Codex" } },
|
|
13824
|
+
launch: { app: { macos: "Codex", windows: "Codex" }, bundleId: { macos: "com.openai.codex" } },
|
|
13524
13825
|
logo: "codex",
|
|
13525
13826
|
downloadUrl: "https://openai.com/codex/",
|
|
13526
13827
|
skillsPaths: { global: ".codex/skills", project: ".agents/skills" },
|
|
13527
|
-
instructionFile: { global: ".codex/
|
|
13828
|
+
instructionFile: { global: ".codex/AGENTS.md", project: "AGENTS.md" },
|
|
13528
13829
|
firstClass: true,
|
|
13529
13830
|
resumeCapability: {
|
|
13530
13831
|
mode: "file-drop-only",
|
|
@@ -13549,7 +13850,7 @@ var AGENT_REGISTRY = [
|
|
|
13549
13850
|
logo: "codex",
|
|
13550
13851
|
downloadUrl: "https://github.com/openai/codex",
|
|
13551
13852
|
skillsPaths: { global: ".codex/skills", project: ".agents/skills" },
|
|
13552
|
-
instructionFile: { global: ".codex/
|
|
13853
|
+
instructionFile: { global: ".codex/AGENTS.md", project: "AGENTS.md" },
|
|
13553
13854
|
firstClass: true,
|
|
13554
13855
|
resumeCapability: {
|
|
13555
13856
|
mode: "cli-resume",
|
|
@@ -13643,10 +13944,11 @@ var AGENT_REGISTRY = [
|
|
|
13643
13944
|
method: "any",
|
|
13644
13945
|
target: [
|
|
13645
13946
|
{ method: "path", target: { macos: "/Applications/ChatGPT.app" } },
|
|
13646
|
-
{ method: "
|
|
13947
|
+
{ method: "macos-bundle-id", target: "com.openai.chat" },
|
|
13948
|
+
{ method: "windows-appx", target: ["OpenAI.ChatGPT"] }
|
|
13647
13949
|
]
|
|
13648
13950
|
},
|
|
13649
|
-
launch: { app: { macos: "ChatGPT", windows: "ChatGPT" }, url: "https://chatgpt.com/?prompt={prompt}" },
|
|
13951
|
+
launch: { app: { macos: "ChatGPT", windows: "ChatGPT" }, bundleId: { macos: "com.openai.chat" }, url: "https://chatgpt.com/?prompt={prompt}" },
|
|
13650
13952
|
logo: "openai",
|
|
13651
13953
|
downloadUrl: "https://chatgpt.com/download",
|
|
13652
13954
|
firstClass: true,
|
|
@@ -13936,14 +14238,28 @@ function resolveToAbsolute(ps, scope) {
|
|
|
13936
14238
|
return scope === "global" ? join26(homedir9(), resolved) : join26(process.cwd(), resolved);
|
|
13937
14239
|
}
|
|
13938
14240
|
|
|
14241
|
+
// src/agents/detection-probes.ts
|
|
14242
|
+
function powershellQuote(value) {
|
|
14243
|
+
return `'${value.replace(/'/g, "''")}'`;
|
|
14244
|
+
}
|
|
14245
|
+
function isValidBundleId(id) {
|
|
14246
|
+
return /^[A-Za-z0-9][A-Za-z0-9.-]*$/.test(id);
|
|
14247
|
+
}
|
|
14248
|
+
function macosBundleIdProbeScript(id) {
|
|
14249
|
+
return `p=$(mdfind "kMDItemCFBundleIdentifier == '${id}'" 2>/dev/null | head -1); ` + `if [ -n "$p" ]; then exit 0; fi; ` + `for a in /Applications/*.app "$HOME"/Applications/*.app; do ` + `[ -e "$a" ] || continue; ` + `if [ "$(/usr/libexec/PlistBuddy -c 'Print :CFBundleIdentifier' "$a/Contents/Info.plist" 2>/dev/null)" = "${id}" ]; then exit 0; fi; ` + `done; exit 1`;
|
|
14250
|
+
}
|
|
14251
|
+
function appxPackageProbeScript(pkg) {
|
|
14252
|
+
return `$p = Get-AppxPackage -Name ${powershellQuote(pkg)} -ErrorAction SilentlyContinue; if ($null -ne $p) { exit 0 } exit 1`;
|
|
14253
|
+
}
|
|
14254
|
+
function startAppProbeScript(pattern) {
|
|
14255
|
+
return `$a = Get-StartApps -Name ${powershellQuote(pattern)} -ErrorAction SilentlyContinue | Select-Object -First 1; if ($null -ne $a) { exit 0 } exit 1`;
|
|
14256
|
+
}
|
|
14257
|
+
|
|
13939
14258
|
// src/agents/detection.ts
|
|
13940
14259
|
var execFileAsync = promisify(execFile);
|
|
13941
14260
|
function isWindows() {
|
|
13942
14261
|
return platform7() === "win32";
|
|
13943
14262
|
}
|
|
13944
|
-
function powershellQuote(value) {
|
|
13945
|
-
return `'${value.replace(/'/g, "''")}'`;
|
|
13946
|
-
}
|
|
13947
14263
|
function toList(value) {
|
|
13948
14264
|
return Array.isArray(value) ? value : [value];
|
|
13949
14265
|
}
|
|
@@ -13963,23 +14279,30 @@ function checkPath(target) {
|
|
|
13963
14279
|
return existsSync32(resolved);
|
|
13964
14280
|
return existsSync32(join27(homedir10(), resolved));
|
|
13965
14281
|
}
|
|
14282
|
+
async function checkMacosBundleId(target) {
|
|
14283
|
+
if (platform7() !== "darwin")
|
|
14284
|
+
return false;
|
|
14285
|
+
for (const id of toList(target)) {
|
|
14286
|
+
if (!isValidBundleId(id))
|
|
14287
|
+
continue;
|
|
14288
|
+
try {
|
|
14289
|
+
await execFileAsync("sh", ["-c", macosBundleIdProbeScript(id)]);
|
|
14290
|
+
return true;
|
|
14291
|
+
} catch {}
|
|
14292
|
+
}
|
|
14293
|
+
return false;
|
|
14294
|
+
}
|
|
13966
14295
|
async function checkWindowsAppxPackage(target) {
|
|
13967
14296
|
if (!isWindows())
|
|
13968
14297
|
return false;
|
|
13969
|
-
const probes = toList(target).map((pkg) =>
|
|
13970
|
-
const script = `$p = Get-AppxPackage -Name ${powershellQuote(pkg)} -ErrorAction SilentlyContinue; if ($null -ne $p) { exit 0 } exit 1`;
|
|
13971
|
-
return runPowerShell(script);
|
|
13972
|
-
});
|
|
14298
|
+
const probes = toList(target).map((pkg) => runPowerShell(appxPackageProbeScript(pkg)));
|
|
13973
14299
|
const results = await Promise.all(probes);
|
|
13974
14300
|
return results.some(Boolean);
|
|
13975
14301
|
}
|
|
13976
14302
|
async function checkWindowsStartApp(target) {
|
|
13977
14303
|
if (!isWindows())
|
|
13978
14304
|
return false;
|
|
13979
|
-
const probes = toList(target).map((pattern) =>
|
|
13980
|
-
const script = `$a = Get-StartApps -Name ${powershellQuote(pattern)} -ErrorAction SilentlyContinue | Select-Object -First 1; if ($null -ne $a) { exit 0 } exit 1`;
|
|
13981
|
-
return runPowerShell(script);
|
|
13982
|
-
});
|
|
14305
|
+
const probes = toList(target).map((pattern) => runPowerShell(startAppProbeScript(pattern)));
|
|
13983
14306
|
const results = await Promise.all(probes);
|
|
13984
14307
|
return results.some(Boolean);
|
|
13985
14308
|
}
|
|
@@ -13995,6 +14318,8 @@ async function runAgentDetection(detection) {
|
|
|
13995
14318
|
return checkWindowsAppxPackage(detection.target);
|
|
13996
14319
|
case "windows-start-app":
|
|
13997
14320
|
return checkWindowsStartApp(detection.target);
|
|
14321
|
+
case "macos-bundle-id":
|
|
14322
|
+
return checkMacosBundleId(detection.target);
|
|
13998
14323
|
case "any": {
|
|
13999
14324
|
const probes = await Promise.all(detection.target.map((p) => runAgentDetection(p)));
|
|
14000
14325
|
return probes.some(Boolean);
|
|
@@ -14106,6 +14431,26 @@ class CodexAdapter {
|
|
|
14106
14431
|
}
|
|
14107
14432
|
}
|
|
14108
14433
|
}
|
|
14434
|
+
if (config.networkAllowlist?.length) {
|
|
14435
|
+
const features = parsed.features && typeof parsed.features === "object" ? parsed.features : undefined;
|
|
14436
|
+
const proxy = features?.network_proxy;
|
|
14437
|
+
if (proxy && proxy.enabled === true) {
|
|
14438
|
+
if (!proxy.domains || typeof proxy.domains !== "object")
|
|
14439
|
+
proxy.domains = {};
|
|
14440
|
+
const domains = proxy.domains;
|
|
14441
|
+
for (const host of config.networkAllowlist) {
|
|
14442
|
+
if (!(host in domains))
|
|
14443
|
+
domains[host] = "allow";
|
|
14444
|
+
}
|
|
14445
|
+
} else {
|
|
14446
|
+
if (!parsed.sandbox_workspace_write || typeof parsed.sandbox_workspace_write !== "object") {
|
|
14447
|
+
parsed.sandbox_workspace_write = {};
|
|
14448
|
+
}
|
|
14449
|
+
const sww = parsed.sandbox_workspace_write;
|
|
14450
|
+
if (sww.network_access === undefined)
|
|
14451
|
+
sww.network_access = true;
|
|
14452
|
+
}
|
|
14453
|
+
}
|
|
14109
14454
|
mkdirSync20(join28(configPath, ".."), { recursive: true });
|
|
14110
14455
|
writeFileSync21(configPath, stringify(parsed));
|
|
14111
14456
|
}
|
|
@@ -15412,7 +15757,7 @@ function parseJson(content, source) {
|
|
|
15412
15757
|
}
|
|
15413
15758
|
|
|
15414
15759
|
// src/commands/entities.ts
|
|
15415
|
-
var listCommand3 = new Command15("list").description("List entities registered in the workspace").option("--workspace <id>", "Workspace ID").option("--app <id>", "Filter by app name or ID").option("--preview", "Show preview-mode entities only").action(async (opts, command) => {
|
|
15760
|
+
var listCommand3 = new Command15("list").description("List entities registered in the workspace").option("--workspace <name-or-id>", "Workspace name or ID").option("--app <id>", "Filter by app name or ID").option("--preview", "Show preview-mode entities only").action(async (opts, command) => {
|
|
15416
15761
|
const useJson = shouldOutputJson(command.optsWithGlobals().json);
|
|
15417
15762
|
const credentials = requireAuth();
|
|
15418
15763
|
const client = new ApiClient(credentials);
|
|
@@ -15447,7 +15792,7 @@ Workspace: ${workspaceName || workspaceId}
|
|
|
15447
15792
|
process.exit(1);
|
|
15448
15793
|
}
|
|
15449
15794
|
});
|
|
15450
|
-
var recordsCommand = new Command15("records").description("List records for an entity").argument("<entity>", "Entity name").option("--workspace <id>", "Workspace ID").option("--limit <n>", "Number of records to return", "20").option("--cursor <cursor>", "Pagination cursor").option("--preview", "Query preview-mode data").action(async (entity, opts, command) => {
|
|
15795
|
+
var recordsCommand = new Command15("records").description("List records for an entity").argument("<entity>", "Entity name").option("--workspace <name-or-id>", "Workspace name or ID").option("--limit <n>", "Number of records to return", "20").option("--cursor <cursor>", "Pagination cursor").option("--preview", "Query preview-mode data").action(async (entity, opts, command) => {
|
|
15451
15796
|
const useJson = shouldOutputJson(command.optsWithGlobals().json);
|
|
15452
15797
|
const credentials = requireAuth();
|
|
15453
15798
|
const client = new ApiClient(credentials);
|
|
@@ -15479,7 +15824,7 @@ Next cursor: ${result.next}`);
|
|
|
15479
15824
|
process.exit(1);
|
|
15480
15825
|
}
|
|
15481
15826
|
});
|
|
15482
|
-
var getCommand = new Command15("get").description("Get a single entity record by ID").argument("<entity>", "Entity name").argument("<id>", "Record ID").option("--workspace <id>", "Workspace ID").action(async (entity, id, opts, command) => {
|
|
15827
|
+
var getCommand = new Command15("get").description("Get a single entity record by ID").argument("<entity>", "Entity name").argument("<id>", "Record ID").option("--workspace <name-or-id>", "Workspace name or ID").action(async (entity, id, opts, command) => {
|
|
15483
15828
|
const useJson = shouldOutputJson(command.optsWithGlobals().json);
|
|
15484
15829
|
const credentials = requireAuth();
|
|
15485
15830
|
const client = new ApiClient(credentials);
|
|
@@ -15496,7 +15841,7 @@ var getCommand = new Command15("get").description("Get a single entity record by
|
|
|
15496
15841
|
process.exit(1);
|
|
15497
15842
|
}
|
|
15498
15843
|
});
|
|
15499
|
-
var createCommand = new Command15("create").description("Create a new entity record").argument("<entity>", "Entity name").option("--workspace <id>", "Workspace ID").option("--data <json>", "Record data as JSON string, @file.json, or pipe via stdin").option("--preview", "Create in preview-mode data store").action(async (entity, opts, command) => {
|
|
15844
|
+
var createCommand = new Command15("create").description("Create a new entity record").argument("<entity>", "Entity name").option("--workspace <name-or-id>", "Workspace name or ID").option("--data <json>", "Record data as JSON string, @file.json, or pipe via stdin").option("--preview", "Create in preview-mode data store").action(async (entity, opts, command) => {
|
|
15500
15845
|
const useJson = shouldOutputJson(command.optsWithGlobals().json);
|
|
15501
15846
|
const credentials = requireAuth();
|
|
15502
15847
|
const client = new ApiClient(credentials);
|
|
@@ -15515,7 +15860,7 @@ var createCommand = new Command15("create").description("Create a new entity rec
|
|
|
15515
15860
|
process.exit(1);
|
|
15516
15861
|
}
|
|
15517
15862
|
});
|
|
15518
|
-
var updateCommand = new Command15("update").description("Update an existing entity record").argument("<entity>", "Entity name").argument("<id>", "Record ID").option("--workspace <id>", "Workspace ID").option("--data <json>", "Record data as JSON string, @file.json, or pipe via stdin").action(async (entity, id, opts, command) => {
|
|
15863
|
+
var updateCommand = new Command15("update").description("Update an existing entity record").argument("<entity>", "Entity name").argument("<id>", "Record ID").option("--workspace <name-or-id>", "Workspace name or ID").option("--data <json>", "Record data as JSON string, @file.json, or pipe via stdin").action(async (entity, id, opts, command) => {
|
|
15519
15864
|
const useJson = shouldOutputJson(command.optsWithGlobals().json);
|
|
15520
15865
|
const credentials = requireAuth();
|
|
15521
15866
|
const client = new ApiClient(credentials);
|
|
@@ -15534,7 +15879,7 @@ var updateCommand = new Command15("update").description("Update an existing enti
|
|
|
15534
15879
|
process.exit(1);
|
|
15535
15880
|
}
|
|
15536
15881
|
});
|
|
15537
|
-
var deleteCommand = new Command15("delete").description("Delete an entity record").argument("<entity>", "Entity name").argument("<id>", "Record ID").option("--workspace <id>", "Workspace ID").option("--yes", "Skip confirmation prompt").action(async (entity, id, opts, command) => {
|
|
15882
|
+
var deleteCommand = new Command15("delete").description("Delete an entity record").argument("<entity>", "Entity name").argument("<id>", "Record ID").option("--workspace <name-or-id>", "Workspace name or ID").option("--yes", "Skip confirmation prompt").action(async (entity, id, opts, command) => {
|
|
15538
15883
|
const useJson = shouldOutputJson(command.optsWithGlobals().json);
|
|
15539
15884
|
const credentials = requireAuth();
|
|
15540
15885
|
const client = new ApiClient(credentials);
|
|
@@ -15573,7 +15918,7 @@ function truncate2(text2, max) {
|
|
|
15573
15918
|
return first;
|
|
15574
15919
|
return first.slice(0, max - 3) + "...";
|
|
15575
15920
|
}
|
|
15576
|
-
var listCommand4 = new Command16("list").description("List workflows in a workspace").option("--workspace <id>", "Workspace ID").option("--app <name>", "Filter by app name or ID").action(async (opts, command) => {
|
|
15921
|
+
var listCommand4 = new Command16("list").description("List workflows in a workspace").option("--workspace <name-or-id>", "Workspace name or ID").option("--app <name>", "Filter by app name or ID").action(async (opts, command) => {
|
|
15577
15922
|
const useJson = shouldOutputJson(command.optsWithGlobals().json);
|
|
15578
15923
|
const credentials = requireAuth();
|
|
15579
15924
|
const client = new ApiClient(credentials);
|
|
@@ -15607,7 +15952,7 @@ Workspace: ${workspaceName || workspaceId}
|
|
|
15607
15952
|
process.exit(1);
|
|
15608
15953
|
}
|
|
15609
15954
|
});
|
|
15610
|
-
var triggerCommand = new Command16("trigger").description("Trigger a workflow by name").argument("<name>", "Workflow name").option("--workspace <id>", "Workspace ID").option("--app <name>", "App name or ID (required if not in a project directory)").option("--params <json>", "JSON string of parameters to pass to the workflow").option("--instance-id <id>", "Custom instance ID for the workflow run").action(async (name, opts, command) => {
|
|
15955
|
+
var triggerCommand = new Command16("trigger").description("Trigger a workflow by name").argument("<name>", "Workflow name").option("--workspace <name-or-id>", "Workspace name or ID").option("--app <name>", "App name or ID (required if not in a project directory)").option("--params <json>", "JSON string of parameters to pass to the workflow").option("--instance-id <id>", "Custom instance ID for the workflow run").action(async (name, opts, command) => {
|
|
15611
15956
|
const useJson = shouldOutputJson(command.optsWithGlobals().json);
|
|
15612
15957
|
const credentials = requireAuth();
|
|
15613
15958
|
const client = new ApiClient(credentials);
|
|
@@ -15641,7 +15986,7 @@ var triggerCommand = new Command16("trigger").description("Trigger a workflow by
|
|
|
15641
15986
|
process.exit(1);
|
|
15642
15987
|
}
|
|
15643
15988
|
});
|
|
15644
|
-
var instancesCommand = new Command16("instances").description("List workflow instances for an app").option("--workspace <id>", "Workspace ID").option("--app <name>", "App name or ID (required if not in a project directory)").option("--workflow <name>", "Filter by workflow name").option("--status <status>", "Filter by instance status").option("--limit <n>", "Maximum number of instances to return").action(async (opts, command) => {
|
|
15989
|
+
var instancesCommand = new Command16("instances").description("List workflow instances for an app").option("--workspace <name-or-id>", "Workspace name or ID").option("--app <name>", "App name or ID (required if not in a project directory)").option("--workflow <name>", "Filter by workflow name").option("--status <status>", "Filter by instance status").option("--limit <n>", "Maximum number of instances to return").action(async (opts, command) => {
|
|
15645
15990
|
const useJson = shouldOutputJson(command.optsWithGlobals().json);
|
|
15646
15991
|
const credentials = requireAuth();
|
|
15647
15992
|
const client = new ApiClient(credentials);
|
|
@@ -15674,7 +16019,7 @@ var instancesCommand = new Command16("instances").description("List workflow ins
|
|
|
15674
16019
|
process.exit(1);
|
|
15675
16020
|
}
|
|
15676
16021
|
});
|
|
15677
|
-
var instanceCommand = new Command16("instance").description("Get details for a specific workflow instance").argument("<id>", "Workflow instance ID").option("--workspace <id>", "Workspace ID").option("--app <name>", "App name or ID (optional)").action(async (id, opts, command) => {
|
|
16022
|
+
var instanceCommand = new Command16("instance").description("Get details for a specific workflow instance").argument("<id>", "Workflow instance ID").option("--workspace <name-or-id>", "Workspace name or ID").option("--app <name>", "App name or ID (optional)").action(async (id, opts, command) => {
|
|
15678
16023
|
const useJson = shouldOutputJson(command.optsWithGlobals().json);
|
|
15679
16024
|
const credentials = requireAuth();
|
|
15680
16025
|
const client = new ApiClient(credentials);
|
|
@@ -15702,16 +16047,64 @@ var workflowsCommand = new Command16("workflows").description("Manage workspace
|
|
|
15702
16047
|
init_store();
|
|
15703
16048
|
init_client();
|
|
15704
16049
|
import { Command as Command17 } from "commander";
|
|
15705
|
-
|
|
15706
|
-
|
|
16050
|
+
// src/utils/table.ts
|
|
16051
|
+
function clip(value, max) {
|
|
16052
|
+
if (max <= 0)
|
|
15707
16053
|
return "";
|
|
15708
|
-
|
|
15709
|
-
|
|
15710
|
-
if (
|
|
15711
|
-
return
|
|
15712
|
-
return
|
|
16054
|
+
if (value.length <= max)
|
|
16055
|
+
return value;
|
|
16056
|
+
if (max <= 3)
|
|
16057
|
+
return value.slice(0, max);
|
|
16058
|
+
return value.slice(0, max - 3) + "...";
|
|
16059
|
+
}
|
|
16060
|
+
function renderTable(columns, rows, indent = " ") {
|
|
16061
|
+
const gap = " ";
|
|
16062
|
+
const lastIdx = columns.length - 1;
|
|
16063
|
+
const data = rows.map((row) => columns.map((c, i) => {
|
|
16064
|
+
const raw = row[i] == null ? "" : String(row[i]);
|
|
16065
|
+
return c.max !== undefined ? clip(raw, c.max) : raw;
|
|
16066
|
+
}));
|
|
16067
|
+
const widths = columns.map((c, i) => {
|
|
16068
|
+
let w = c.header.length;
|
|
16069
|
+
for (const row of data)
|
|
16070
|
+
w = Math.max(w, row[i].length);
|
|
16071
|
+
return w;
|
|
16072
|
+
});
|
|
16073
|
+
const renderRow = (cells, colorize) => {
|
|
16074
|
+
const parts = cells.map((cell, i) => {
|
|
16075
|
+
const padded = i === lastIdx ? cell : cell.padEnd(widths[i]);
|
|
16076
|
+
const color = columns[i].color;
|
|
16077
|
+
return colorize && color ? color(padded) : padded;
|
|
16078
|
+
});
|
|
16079
|
+
return (indent + parts.join(gap)).replace(/\s+$/, "");
|
|
16080
|
+
};
|
|
16081
|
+
const out = [renderRow(columns.map((c) => c.header), false)];
|
|
16082
|
+
const total = widths.reduce((a, b) => a + b, 0) + gap.length * Math.max(0, columns.length - 1);
|
|
16083
|
+
out.push(indent + "-".repeat(total));
|
|
16084
|
+
for (const row of data)
|
|
16085
|
+
out.push(renderRow(row, true));
|
|
16086
|
+
return out.join(`
|
|
16087
|
+
`);
|
|
16088
|
+
}
|
|
16089
|
+
|
|
16090
|
+
// src/commands/schedules.ts
|
|
16091
|
+
function extractScheduleHistoryRecords(data) {
|
|
16092
|
+
if (!data || !Array.isArray(data.records))
|
|
16093
|
+
return [];
|
|
16094
|
+
return data.records;
|
|
16095
|
+
}
|
|
16096
|
+
function scheduleRowCells(s) {
|
|
16097
|
+
const mode = s.deploymentMode ? ` (${s.deploymentMode})` : "";
|
|
16098
|
+
const status = s.status ? s.status + mode : mode.trim() || "-";
|
|
16099
|
+
return [
|
|
16100
|
+
s.scheduleName || "(unnamed)",
|
|
16101
|
+
s.appName || s.appId || "-",
|
|
16102
|
+
s.schedule || "-",
|
|
16103
|
+
status,
|
|
16104
|
+
s.description || ""
|
|
16105
|
+
];
|
|
15713
16106
|
}
|
|
15714
|
-
var listCommand5 = new Command17("list").description("List scheduled jobs in the workspace").option("--workspace <id>", "Workspace ID").option("--app <name|id>", "Filter by app name or ID").action(async (opts, command) => {
|
|
16107
|
+
var listCommand5 = new Command17("list").description("List scheduled jobs in the workspace").option("--workspace <name-or-id>", "Workspace name or ID").option("--app <name|id>", "Filter by app name or ID").action(async (opts, command) => {
|
|
15715
16108
|
const useJson = shouldOutputJson(command.optsWithGlobals().json);
|
|
15716
16109
|
const credentials = requireAuth();
|
|
15717
16110
|
const client = new ApiClient(credentials);
|
|
@@ -15733,20 +16126,20 @@ var listCommand5 = new Command17("list").description("List scheduled jobs in the
|
|
|
15733
16126
|
console.log(`
|
|
15734
16127
|
Workspace: ${workspaceName || workspaceId}
|
|
15735
16128
|
`);
|
|
15736
|
-
console.log(
|
|
15737
|
-
|
|
15738
|
-
|
|
15739
|
-
|
|
15740
|
-
|
|
15741
|
-
|
|
15742
|
-
|
|
16129
|
+
console.log(renderTable([
|
|
16130
|
+
{ header: "Name" },
|
|
16131
|
+
{ header: "App" },
|
|
16132
|
+
{ header: "Schedule" },
|
|
16133
|
+
{ header: "Status" },
|
|
16134
|
+
{ header: "Description", max: 60 }
|
|
16135
|
+
], schedules.map(scheduleRowCells)));
|
|
15743
16136
|
console.log("");
|
|
15744
16137
|
} catch (err) {
|
|
15745
16138
|
console.error("Failed to list schedules:", err instanceof Error ? err.message : err);
|
|
15746
16139
|
process.exit(1);
|
|
15747
16140
|
}
|
|
15748
16141
|
});
|
|
15749
|
-
var triggerCommand2 = new Command17("trigger").description("Manually trigger a scheduled job").argument("<name>", "Schedule name").option("--workspace <id>", "Workspace ID").option("--app <name|id>", "App name or ID").option("--preview", "Trigger in preview (sandbox) mode instead of production").action(async (name, opts, command) => {
|
|
16142
|
+
var triggerCommand2 = new Command17("trigger").description("Manually trigger a scheduled job").argument("<name>", "Schedule name").option("--workspace <name-or-id>", "Workspace name or ID").option("--app <name|id>", "App name or ID").option("--preview", "Trigger in preview (sandbox) mode instead of production").action(async (name, opts, command) => {
|
|
15750
16143
|
const useJson = shouldOutputJson(command.optsWithGlobals().json);
|
|
15751
16144
|
const credentials = requireAuth();
|
|
15752
16145
|
const client = new ApiClient(credentials);
|
|
@@ -15772,7 +16165,7 @@ var triggerCommand2 = new Command17("trigger").description("Manually trigger a s
|
|
|
15772
16165
|
process.exit(1);
|
|
15773
16166
|
}
|
|
15774
16167
|
});
|
|
15775
|
-
var historyCommand = new Command17("history").description("Show execution history for scheduled jobs in an app").option("--workspace <id>", "Workspace ID").option("--app <name|id>", "App name or ID (required)").action(async (opts, command) => {
|
|
16168
|
+
var historyCommand = new Command17("history").description("Show execution history for scheduled jobs in an app").option("--workspace <name-or-id>", "Workspace name or ID").option("--app <name|id>", "App name or ID (required)").action(async (opts, command) => {
|
|
15776
16169
|
const useJson = shouldOutputJson(command.optsWithGlobals().json);
|
|
15777
16170
|
const credentials = requireAuth();
|
|
15778
16171
|
const client = new ApiClient(credentials);
|
|
@@ -15780,25 +16173,34 @@ var historyCommand = new Command17("history").description("Show execution histor
|
|
|
15780
16173
|
const { appId, appName } = await resolveApp2(client, workspaceId, opts);
|
|
15781
16174
|
try {
|
|
15782
16175
|
const data = await client.getScheduleHistory(workspaceId, appId);
|
|
16176
|
+
const records = extractScheduleHistoryRecords(data);
|
|
15783
16177
|
if (useJson) {
|
|
15784
|
-
jsonOut({ history:
|
|
16178
|
+
jsonOut({ history: records, appId, appName });
|
|
15785
16179
|
return;
|
|
15786
16180
|
}
|
|
15787
|
-
if (
|
|
16181
|
+
if (records.length === 0) {
|
|
15788
16182
|
console.log(`No schedule history found for app "${appName}".`);
|
|
15789
16183
|
return;
|
|
15790
16184
|
}
|
|
15791
16185
|
console.log(`
|
|
15792
16186
|
Schedule history for app: ${appName}
|
|
15793
16187
|
`);
|
|
15794
|
-
|
|
15795
|
-
console.log(" " + "
|
|
15796
|
-
|
|
16188
|
+
const nameW = Math.max("Schedule".length, ...records.map((r) => (r.jobName || "-").length));
|
|
16189
|
+
console.log(" " + "Schedule".padEnd(nameW + 2) + "Started At".padEnd(26) + "Status".padEnd(12) + "Duration");
|
|
16190
|
+
console.log(" " + "-".repeat(nameW + 2 + 26 + 12 + 8));
|
|
16191
|
+
for (const entry of records) {
|
|
16192
|
+
const startedAt = entry.startedAt ? new Date(entry.startedAt).toISOString() : "-";
|
|
15797
16193
|
const duration = entry.durationMs != null ? `${entry.durationMs}ms` : "-";
|
|
15798
|
-
console.log(" " + entry.
|
|
16194
|
+
console.log(" " + (entry.jobName || "-").padEnd(nameW + 2) + startedAt.padEnd(26) + entry.status.padEnd(12) + duration);
|
|
15799
16195
|
if (entry.error) {
|
|
15800
16196
|
console.log(` Error: ${entry.error}`);
|
|
15801
16197
|
}
|
|
16198
|
+
if (entry.errorStack) {
|
|
16199
|
+
for (const line of entry.errorStack.split(`
|
|
16200
|
+
`).slice(0, 8)) {
|
|
16201
|
+
console.log(` ${line.trim()}`);
|
|
16202
|
+
}
|
|
16203
|
+
}
|
|
15802
16204
|
}
|
|
15803
16205
|
console.log("");
|
|
15804
16206
|
} catch (err) {
|
|
@@ -15806,7 +16208,7 @@ Schedule history for app: ${appName}
|
|
|
15806
16208
|
process.exit(1);
|
|
15807
16209
|
}
|
|
15808
16210
|
});
|
|
15809
|
-
var statusCommand = new Command17("status").description("Show runtime status of scheduled jobs for an app").argument("<name>", "Schedule name").option("--workspace <id>", "Workspace ID").option("--app <name|id>", "App name or ID (required)").action(async (name, opts, command) => {
|
|
16211
|
+
var statusCommand = new Command17("status").description("Show runtime status of scheduled jobs for an app").argument("<name>", "Schedule name").option("--workspace <name-or-id>", "Workspace name or ID").option("--app <name|id>", "App name or ID (required)").action(async (name, opts, command) => {
|
|
15810
16212
|
const useJson = shouldOutputJson(command.optsWithGlobals().json);
|
|
15811
16213
|
const credentials = requireAuth();
|
|
15812
16214
|
const client = new ApiClient(credentials);
|
|
@@ -15828,7 +16230,7 @@ Schedule "${name}" status for app "${appName}":
|
|
|
15828
16230
|
process.exit(1);
|
|
15829
16231
|
}
|
|
15830
16232
|
});
|
|
15831
|
-
var pauseCommand = new Command17("pause").description("Pause a scheduled job").argument("<name>", "Schedule name").option("--workspace <id>", "Workspace ID").option("--app <name|id>", "App name or ID (required)").action(async (name, opts, command) => {
|
|
16233
|
+
var pauseCommand = new Command17("pause").description("Pause a scheduled job").argument("<name>", "Schedule name").option("--workspace <name-or-id>", "Workspace name or ID").option("--app <name|id>", "App name or ID (required)").action(async (name, opts, command) => {
|
|
15832
16234
|
const useJson = shouldOutputJson(command.optsWithGlobals().json);
|
|
15833
16235
|
const credentials = requireAuth();
|
|
15834
16236
|
const client = new ApiClient(credentials);
|
|
@@ -15846,7 +16248,7 @@ var pauseCommand = new Command17("pause").description("Pause a scheduled job").a
|
|
|
15846
16248
|
process.exit(1);
|
|
15847
16249
|
}
|
|
15848
16250
|
});
|
|
15849
|
-
var resumeCommand = new Command17("resume").description("Resume a paused scheduled job").argument("<name>", "Schedule name").option("--workspace <id>", "Workspace ID").option("--app <name|id>", "App name or ID (required)").action(async (name, opts, command) => {
|
|
16251
|
+
var resumeCommand = new Command17("resume").description("Resume a paused scheduled job").argument("<name>", "Schedule name").option("--workspace <name-or-id>", "Workspace name or ID").option("--app <name|id>", "App name or ID (required)").action(async (name, opts, command) => {
|
|
15850
16252
|
const useJson = shouldOutputJson(command.optsWithGlobals().json);
|
|
15851
16253
|
const credentials = requireAuth();
|
|
15852
16254
|
const client = new ApiClient(credentials);
|
|
@@ -15871,7 +16273,7 @@ init_store();
|
|
|
15871
16273
|
init_client();
|
|
15872
16274
|
import { Command as Command18 } from "commander";
|
|
15873
16275
|
init_http();
|
|
15874
|
-
function
|
|
16276
|
+
function truncate3(text2, max) {
|
|
15875
16277
|
if (!text2)
|
|
15876
16278
|
return "";
|
|
15877
16279
|
const first = text2.split(`
|
|
@@ -15880,7 +16282,7 @@ function truncate4(text2, max) {
|
|
|
15880
16282
|
return first;
|
|
15881
16283
|
return first.slice(0, max - 3) + "...";
|
|
15882
16284
|
}
|
|
15883
|
-
var listCommand6 = new Command18("list").description("List workspace public endpoints").option("--workspace <id>", "Workspace ID").option("--app <name>", "Filter by app name or ID").action(async (opts, command) => {
|
|
16285
|
+
var listCommand6 = new Command18("list").description("List workspace public endpoints").option("--workspace <name-or-id>", "Workspace name or ID").option("--app <name>", "Filter by app name or ID").action(async (opts, command) => {
|
|
15884
16286
|
const useJson = shouldOutputJson(command.optsWithGlobals().json);
|
|
15885
16287
|
const credentials = requireAuth();
|
|
15886
16288
|
const client = new ApiClient(credentials);
|
|
@@ -15908,7 +16310,7 @@ Workspace: ${workspaceName || workspaceId}
|
|
|
15908
16310
|
const path2 = e.endpointPath.padEnd(36);
|
|
15909
16311
|
const app = (e.appName || e.appId).padEnd(20);
|
|
15910
16312
|
const auth = (e.auth || "").padEnd(10);
|
|
15911
|
-
const desc =
|
|
16313
|
+
const desc = truncate3(e.description, 40);
|
|
15912
16314
|
const mode = e.deploymentMode ? ` [${e.deploymentMode}]` : "";
|
|
15913
16315
|
console.log(` ${method} ${path2} ${app} ${auth} ${desc}${mode}`);
|
|
15914
16316
|
}
|
|
@@ -15918,7 +16320,7 @@ Workspace: ${workspaceName || workspaceId}
|
|
|
15918
16320
|
process.exit(1);
|
|
15919
16321
|
}
|
|
15920
16322
|
});
|
|
15921
|
-
var callCommand2 = new Command18("call").description("Call a workspace endpoint directly").argument("<method>", "HTTP method (GET, POST, PUT, DELETE, etc.)").argument("<path>", "Endpoint path (e.g. /my-endpoint)").option("--workspace <id>", "Workspace ID").option("--app <name>", "App name or ID (narrows endpoint lookup)").option("--body <json>", "Request body as JSON string").option("--header <header>", 'Request header (format: "Key: Value", repeatable)', (val, prev) => [...prev, val], []).option("--query <string>", 'Query string to append to the URL (e.g. "foo=bar&baz=1")').option("--api-key <key>", "API key for Authorization: Bearer header").action(async (method, path2, opts, command) => {
|
|
16323
|
+
var callCommand2 = new Command18("call").description("Call a workspace endpoint directly").argument("<method>", "HTTP method (GET, POST, PUT, DELETE, etc.)").argument("<path>", "Endpoint path (e.g. /my-endpoint)").option("--workspace <name-or-id>", "Workspace name or ID").option("--app <name>", "App name or ID (narrows endpoint lookup)").option("--body <json>", "Request body as JSON string").option("--header <header>", 'Request header (format: "Key: Value", repeatable)', (val, prev) => [...prev, val], []).option("--query <string>", 'Query string to append to the URL (e.g. "foo=bar&baz=1")').option("--api-key <key>", "API key for Authorization: Bearer header").action(async (method, path2, opts, command) => {
|
|
15922
16324
|
const useJson = shouldOutputJson(command.optsWithGlobals().json);
|
|
15923
16325
|
const credentials = requireAuth();
|
|
15924
16326
|
const client = new ApiClient(credentials);
|
|
@@ -16049,7 +16451,7 @@ function formatSize(bytes) {
|
|
|
16049
16451
|
return `${(bytes / (1024 * 1024)).toFixed(1)}MB`;
|
|
16050
16452
|
return `${(bytes / (1024 * 1024 * 1024)).toFixed(1)}GB`;
|
|
16051
16453
|
}
|
|
16052
|
-
var listCommand7 = new Command19("list").description("List file storage buckets in the workspace").option("--workspace <id>", "Workspace ID").action(async (opts, command) => {
|
|
16454
|
+
var listCommand7 = new Command19("list").description("List file storage buckets in the workspace").option("--workspace <name-or-id>", "Workspace name or ID").action(async (opts, command) => {
|
|
16053
16455
|
const useJson = shouldOutputJson(command.optsWithGlobals().json);
|
|
16054
16456
|
const credentials = requireAuth();
|
|
16055
16457
|
const client = new ApiClient(credentials);
|
|
@@ -16079,7 +16481,7 @@ Workspace: ${workspaceName || workspaceId}
|
|
|
16079
16481
|
process.exit(1);
|
|
16080
16482
|
}
|
|
16081
16483
|
});
|
|
16082
|
-
var lsCommand = new Command19("ls").description("List files in a bucket").argument("<bucket>", "Bucket name").argument("[prefix]", "Key prefix to filter by").option("--workspace <id>", "Workspace ID").option("--delimiter <char>", "Delimiter for hierarchical listing", "/").action(async (bucket, prefix, opts, command) => {
|
|
16484
|
+
var lsCommand = new Command19("ls").description("List files in a bucket").argument("<bucket>", "Bucket name").argument("[prefix]", "Key prefix to filter by").option("--workspace <name-or-id>", "Workspace name or ID").option("--delimiter <char>", "Delimiter for hierarchical listing", "/").action(async (bucket, prefix, opts, command) => {
|
|
16083
16485
|
const useJson = shouldOutputJson(command.optsWithGlobals().json);
|
|
16084
16486
|
const credentials = requireAuth();
|
|
16085
16487
|
const client = new ApiClient(credentials);
|
|
@@ -16116,7 +16518,7 @@ var lsCommand = new Command19("ls").description("List files in a bucket").argume
|
|
|
16116
16518
|
process.exit(1);
|
|
16117
16519
|
}
|
|
16118
16520
|
});
|
|
16119
|
-
var downloadCommand = new Command19("download").description("Download a file from a bucket").argument("<bucket>", "Bucket name").argument("<key>", "Object key to download").argument("[output]", "Local output path (defaults to basename of key)").option("--workspace <id>", "Workspace ID").action(async (bucket, key, output, opts, command) => {
|
|
16521
|
+
var downloadCommand = new Command19("download").description("Download a file from a bucket").argument("<bucket>", "Bucket name").argument("<key>", "Object key to download").argument("[output]", "Local output path (defaults to basename of key)").option("--workspace <name-or-id>", "Workspace name or ID").action(async (bucket, key, output, opts, command) => {
|
|
16120
16522
|
const useJson = shouldOutputJson(command.optsWithGlobals().json);
|
|
16121
16523
|
const credentials = requireAuth();
|
|
16122
16524
|
const client = new ApiClient(credentials);
|
|
@@ -16139,7 +16541,7 @@ var downloadCommand = new Command19("download").description("Download a file fro
|
|
|
16139
16541
|
process.exit(1);
|
|
16140
16542
|
}
|
|
16141
16543
|
});
|
|
16142
|
-
var uploadCommand = new Command19("upload").description("Upload a local file to a bucket").argument("<bucket>", "Bucket name").argument("<localPath>", "Local file path to upload").argument("[key]", "Object key in bucket (defaults to basename of local path)").option("--workspace <id>", "Workspace ID").action(async (bucket, localPath, key, opts, command) => {
|
|
16544
|
+
var uploadCommand = new Command19("upload").description("Upload a local file to a bucket").argument("<bucket>", "Bucket name").argument("<localPath>", "Local file path to upload").argument("[key]", "Object key in bucket (defaults to basename of local path)").option("--workspace <name-or-id>", "Workspace name or ID").action(async (bucket, localPath, key, opts, command) => {
|
|
16143
16545
|
const useJson = shouldOutputJson(command.optsWithGlobals().json);
|
|
16144
16546
|
const credentials = requireAuth();
|
|
16145
16547
|
const client = new ApiClient(credentials);
|
|
@@ -16162,7 +16564,7 @@ var uploadCommand = new Command19("upload").description("Upload a local file to
|
|
|
16162
16564
|
process.exit(1);
|
|
16163
16565
|
}
|
|
16164
16566
|
});
|
|
16165
|
-
var deleteCommand2 = new Command19("delete").description("Delete a file from a bucket").argument("<bucket>", "Bucket name").argument("<key>", "Object key to delete").option("--workspace <id>", "Workspace ID").option("--yes", "Skip confirmation prompt").action(async (bucket, key, opts, command) => {
|
|
16567
|
+
var deleteCommand2 = new Command19("delete").description("Delete a file from a bucket").argument("<bucket>", "Bucket name").argument("<key>", "Object key to delete").option("--workspace <name-or-id>", "Workspace name or ID").option("--yes", "Skip confirmation prompt").action(async (bucket, key, opts, command) => {
|
|
16166
16568
|
const useJson = shouldOutputJson(command.optsWithGlobals().json);
|
|
16167
16569
|
const credentials = requireAuth();
|
|
16168
16570
|
const client = new ApiClient(credentials);
|
|
@@ -16192,7 +16594,7 @@ var filesCommand = new Command19("files").description("Manage workspace file sto
|
|
|
16192
16594
|
init_store();
|
|
16193
16595
|
init_client();
|
|
16194
16596
|
import { Command as Command20 } from "commander";
|
|
16195
|
-
var listCommand8 = new Command20("list").description("List components registered in the workspace").option("--workspace <id>", "Workspace ID").option("--app <id>", "Filter by app name or ID").action(async (opts, command) => {
|
|
16597
|
+
var listCommand8 = new Command20("list").description("List components registered in the workspace").option("--workspace <name-or-id>", "Workspace name or ID").option("--app <id>", "Filter by app name or ID").action(async (opts, command) => {
|
|
16196
16598
|
const useJson = shouldOutputJson(command.optsWithGlobals().json);
|
|
16197
16599
|
const credentials = requireAuth();
|
|
16198
16600
|
const client = new ApiClient(credentials);
|
|
@@ -16231,7 +16633,7 @@ init_store();
|
|
|
16231
16633
|
init_client();
|
|
16232
16634
|
import { Command as Command21 } from "commander";
|
|
16233
16635
|
init_prompt();
|
|
16234
|
-
var listCommand9 = new Command21("list").description("List API keys for the workspace").option("--workspace <id>", "Workspace ID").action(async (opts, command) => {
|
|
16636
|
+
var listCommand9 = new Command21("list").description("List API keys for the workspace").option("--workspace <name-or-id>", "Workspace name or ID").action(async (opts, command) => {
|
|
16235
16637
|
const useJson = shouldOutputJson(command.optsWithGlobals().json);
|
|
16236
16638
|
const credentials = requireAuth();
|
|
16237
16639
|
const client = new ApiClient(credentials);
|
|
@@ -16266,7 +16668,7 @@ Workspace: ${workspaceName || workspaceId}
|
|
|
16266
16668
|
process.exit(1);
|
|
16267
16669
|
}
|
|
16268
16670
|
});
|
|
16269
|
-
var createCommand2 = new Command21("create").description("Create a new API key").option("--workspace <id>", "Workspace ID").option("--name <name>", "API key name").option("--app <id>", "Restrict key to a specific app (name or ID)").option("--scopes <scopes>", "Comma-separated list of scopes").action(async (opts, command) => {
|
|
16671
|
+
var createCommand2 = new Command21("create").description("Create a new API key").option("--workspace <name-or-id>", "Workspace name or ID").option("--name <name>", "API key name").option("--app <id>", "Restrict key to a specific app (name or ID)").option("--scopes <scopes>", "Comma-separated list of scopes").action(async (opts, command) => {
|
|
16270
16672
|
const useJson = shouldOutputJson(command.optsWithGlobals().json);
|
|
16271
16673
|
const credentials = requireAuth();
|
|
16272
16674
|
const client = new ApiClient(credentials);
|
|
@@ -16314,7 +16716,7 @@ var apiKeysCommand = new Command21("api-keys").description("Manage workspace API
|
|
|
16314
16716
|
init_store();
|
|
16315
16717
|
init_client();
|
|
16316
16718
|
import { Command as Command22 } from "commander";
|
|
16317
|
-
function
|
|
16719
|
+
function truncate4(text2, max) {
|
|
16318
16720
|
if (!text2)
|
|
16319
16721
|
return "";
|
|
16320
16722
|
const first = text2.split(`
|
|
@@ -16323,7 +16725,7 @@ function truncate5(text2, max) {
|
|
|
16323
16725
|
return first;
|
|
16324
16726
|
return first.slice(0, max - 3) + "...";
|
|
16325
16727
|
}
|
|
16326
|
-
var listCommand10 = new Command22("list").description("List agents in workspace").option("--workspace <id>", "Workspace ID").option("--app <id>", "Filter by app name or ID").action(async (opts, command) => {
|
|
16728
|
+
var listCommand10 = new Command22("list").description("List agents in workspace").option("--workspace <name-or-id>", "Workspace name or ID").option("--app <id>", "Filter by app name or ID").action(async (opts, command) => {
|
|
16327
16729
|
const useJson = shouldOutputJson(command.optsWithGlobals().json);
|
|
16328
16730
|
const credentials = requireAuth();
|
|
16329
16731
|
const client = new ApiClient(credentials);
|
|
@@ -16349,8 +16751,8 @@ Workspace: ${workspaceName || workspaceId}
|
|
|
16349
16751
|
for (const a of agents) {
|
|
16350
16752
|
const name = a.agentName.padEnd(24);
|
|
16351
16753
|
const type = a.type.padEnd(16);
|
|
16352
|
-
const app =
|
|
16353
|
-
const desc =
|
|
16754
|
+
const app = truncate4(a.appName, 18).padEnd(20);
|
|
16755
|
+
const desc = truncate4(a.description, 40).padEnd(42);
|
|
16354
16756
|
const integrations = (a.integrations?.join(", ") || "").padEnd(20);
|
|
16355
16757
|
const entities = (a.entities?.join(", ") || "").padEnd(20);
|
|
16356
16758
|
const mode = a.deploymentMode || "";
|
|
@@ -16362,7 +16764,7 @@ Workspace: ${workspaceName || workspaceId}
|
|
|
16362
16764
|
process.exit(1);
|
|
16363
16765
|
}
|
|
16364
16766
|
});
|
|
16365
|
-
var statusCommand2 = new Command22("status").description("Get status of a specific agent").argument("<name>", "Agent name").option("--workspace <id>", "Workspace ID").option("--app <id>", "App name or ID (required)").action(async (name, opts, command) => {
|
|
16767
|
+
var statusCommand2 = new Command22("status").description("Get status of a specific agent").argument("<name>", "Agent name").option("--workspace <name-or-id>", "Workspace name or ID").option("--app <id>", "App name or ID (required)").action(async (name, opts, command) => {
|
|
16366
16768
|
const useJson = shouldOutputJson(command.optsWithGlobals().json);
|
|
16367
16769
|
const credentials = requireAuth();
|
|
16368
16770
|
const client = new ApiClient(credentials);
|
|
@@ -16380,7 +16782,7 @@ var statusCommand2 = new Command22("status").description("Get status of a specif
|
|
|
16380
16782
|
process.exit(1);
|
|
16381
16783
|
}
|
|
16382
16784
|
});
|
|
16383
|
-
var executionsCommand = new Command22("executions").description("List agent execution history for workspace").option("--workspace <id>", "Workspace ID").action(async (opts, command) => {
|
|
16785
|
+
var executionsCommand = new Command22("executions").description("List agent execution history for workspace").option("--workspace <name-or-id>", "Workspace name or ID").action(async (opts, command) => {
|
|
16384
16786
|
const useJson = shouldOutputJson(command.optsWithGlobals().json);
|
|
16385
16787
|
const credentials = requireAuth();
|
|
16386
16788
|
const client = new ApiClient(credentials);
|
|
@@ -16399,9 +16801,9 @@ var executionsCommand = new Command22("executions").description("List agent exec
|
|
|
16399
16801
|
console.log(" " + "-".repeat(160));
|
|
16400
16802
|
for (const e of executions) {
|
|
16401
16803
|
const sessionId = e.sessionId.padEnd(36);
|
|
16402
|
-
const agent =
|
|
16403
|
-
const app =
|
|
16404
|
-
const prompt =
|
|
16804
|
+
const agent = truncate4(e.agentName, 20).padEnd(22);
|
|
16805
|
+
const app = truncate4(e.appId, 20).padEnd(22);
|
|
16806
|
+
const prompt = truncate4(e.prompt, 50).padEnd(52);
|
|
16405
16807
|
const status = e.status.padEnd(12);
|
|
16406
16808
|
const duration = e.durationMs != null ? `${e.durationMs}ms` : "";
|
|
16407
16809
|
const usage = e.usage ? `${e.usage.inputTokens}/${e.usage.outputTokens}` : "";
|
|
@@ -16413,7 +16815,7 @@ var executionsCommand = new Command22("executions").description("List agent exec
|
|
|
16413
16815
|
process.exit(1);
|
|
16414
16816
|
}
|
|
16415
16817
|
});
|
|
16416
|
-
var executionCommand = new Command22("execution").description("Get execution stream for a specific session").argument("<sessionId>", "Session ID").option("--workspace <id>", "Workspace ID").action(async (sessionId, opts, command) => {
|
|
16818
|
+
var executionCommand = new Command22("execution").description("Get execution stream for a specific session").argument("<sessionId>", "Session ID").option("--workspace <name-or-id>", "Workspace name or ID").action(async (sessionId, opts, command) => {
|
|
16417
16819
|
const useJson = shouldOutputJson(command.optsWithGlobals().json);
|
|
16418
16820
|
const credentials = requireAuth();
|
|
16419
16821
|
const client = new ApiClient(credentials);
|
|
@@ -16437,7 +16839,7 @@ init_store();
|
|
|
16437
16839
|
init_client();
|
|
16438
16840
|
import { Command as Command23 } from "commander";
|
|
16439
16841
|
init_prompt();
|
|
16440
|
-
var listCommand11 = new Command23("list").description("List workspace MCP servers").option("--workspace <id>", "Workspace ID").action(async (opts, command) => {
|
|
16842
|
+
var listCommand11 = new Command23("list").description("List workspace MCP servers").option("--workspace <name-or-id>", "Workspace name or ID").action(async (opts, command) => {
|
|
16441
16843
|
const useJson = shouldOutputJson(command.optsWithGlobals().json);
|
|
16442
16844
|
const credentials = requireAuth();
|
|
16443
16845
|
const client = new ApiClient(credentials);
|
|
@@ -16493,7 +16895,7 @@ Workspace: ${workspaceName || workspaceId}
|
|
|
16493
16895
|
process.exit(1);
|
|
16494
16896
|
}
|
|
16495
16897
|
});
|
|
16496
|
-
var addCommand = new Command23("add").description("Add an MCP server to workspace").argument("<name>", "Server name").argument("<url>", "Server URL (Streamable HTTP or SSE endpoint)").option("--transport <type>", "Transport type: streamable-http or sse", "streamable-http").option("--workspace <id>", "Workspace ID").action(async (name, url, opts, command) => {
|
|
16898
|
+
var addCommand = new Command23("add").description("Add an MCP server to workspace").argument("<name>", "Server name").argument("<url>", "Server URL (Streamable HTTP or SSE endpoint)").option("--transport <type>", "Transport type: streamable-http or sse", "streamable-http").option("--workspace <name-or-id>", "Workspace name or ID").action(async (name, url, opts, command) => {
|
|
16497
16899
|
const useJson = shouldOutputJson(command.optsWithGlobals().json);
|
|
16498
16900
|
const credentials = requireAuth();
|
|
16499
16901
|
const client = new ApiClient(credentials);
|
|
@@ -16521,7 +16923,7 @@ var addCommand = new Command23("add").description("Add an MCP server to workspac
|
|
|
16521
16923
|
process.exit(1);
|
|
16522
16924
|
}
|
|
16523
16925
|
});
|
|
16524
|
-
var removeCommand = new Command23("remove").description("Remove an MCP server from workspace").argument("<name>", "Server name").option("--yes", "Skip confirmation").option("--workspace <id>", "Workspace ID").action(async (name, opts, command) => {
|
|
16926
|
+
var removeCommand = new Command23("remove").description("Remove an MCP server from workspace").argument("<name>", "Server name").option("--yes", "Skip confirmation").option("--workspace <name-or-id>", "Workspace name or ID").action(async (name, opts, command) => {
|
|
16525
16927
|
const useJson = shouldOutputJson(command.optsWithGlobals().json);
|
|
16526
16928
|
const credentials = requireAuth();
|
|
16527
16929
|
const client = new ApiClient(credentials);
|
|
@@ -16584,7 +16986,7 @@ var searchCommand3 = new Command23("search").description("Search community MCP s
|
|
|
16584
16986
|
process.exit(1);
|
|
16585
16987
|
}
|
|
16586
16988
|
});
|
|
16587
|
-
var installCommand2 = new Command23("install").description("Install a community MCP server from the MCP Registry into your workspace").argument("<query>", "Server name or search query").option("--workspace <id>", "Workspace ID").action(async (query, opts, command) => {
|
|
16989
|
+
var installCommand2 = new Command23("install").description("Install a community MCP server from the MCP Registry into your workspace").argument("<query>", "Server name or search query").option("--workspace <name-or-id>", "Workspace name or ID").action(async (query, opts, command) => {
|
|
16588
16990
|
const useJson = shouldOutputJson(command.optsWithGlobals().json);
|
|
16589
16991
|
const credentials = requireAuth();
|
|
16590
16992
|
const client = new ApiClient(credentials);
|
|
@@ -18589,7 +18991,7 @@ async function resolveAndPersistWorkspace(client, opts) {
|
|
|
18589
18991
|
}
|
|
18590
18992
|
return { workspaceId, workspaceName, workspaceSlug };
|
|
18591
18993
|
}
|
|
18592
|
-
var setupCommand = new Command25("setup").description("Configure local AI agents with workspace skills and MCP servers").option("--workspace <id>", "Workspace ID").option("--agent <slug>", "Only configure a specific agent (e.g. claude-code, cursor)").option("--dry-run", "Show what would be configured without writing files").option("-y, --yes", "Skip all prompts, configure all detected agents with user scope").option("--persona <level>", "Technical-level persona for agent instructions (1=everyday, 2=curious, 3=engineer)").action(async (opts) => {
|
|
18994
|
+
var setupCommand = new Command25("setup").description("Configure local AI agents with workspace skills and MCP servers").option("--workspace <name-or-id>", "Workspace name or ID").option("--agent <slug>", "Only configure a specific agent (e.g. claude-code, cursor)").option("--dry-run", "Show what would be configured without writing files").option("-y, --yes", "Skip all prompts, configure all detected agents with user scope").option("--persona <level>", "Technical-level persona for agent instructions (1=everyday, 2=curious, 3=engineer)").action(async (opts) => {
|
|
18593
18995
|
const credentials = requireAuth();
|
|
18594
18996
|
const client = new ApiClient(credentials);
|
|
18595
18997
|
const { workspaceId, workspaceName, workspaceSlug } = await resolveAndPersistWorkspace(client, opts);
|
|
@@ -18941,7 +19343,7 @@ init_store();
|
|
|
18941
19343
|
init_client();
|
|
18942
19344
|
import { Command as Command28 } from "commander";
|
|
18943
19345
|
init_init();
|
|
18944
|
-
var listCommand12 = new Command28("list").description("List apps in workspace").option("--workspace <id>", "Workspace ID").action(async (opts, command) => {
|
|
19346
|
+
var listCommand12 = new Command28("list").description("List apps in workspace").option("--workspace <name-or-id>", "Workspace name or ID").action(async (opts, command) => {
|
|
18945
19347
|
const useJson = shouldOutputJson(command.optsWithGlobals().json);
|
|
18946
19348
|
const credentials = requireAuth();
|
|
18947
19349
|
const client = new ApiClient(credentials);
|
|
@@ -18974,7 +19376,7 @@ Workspace: ${workspaceName || workspaceId}
|
|
|
18974
19376
|
var createCommand3 = new Command28("create").description("Create a new Runwork app").argument("[name]", "App name").action(async (name) => {
|
|
18975
19377
|
await runCreateFlow(name);
|
|
18976
19378
|
});
|
|
18977
|
-
var infoCommand2 = new Command28("info").description("Show detailed app info, preview status, and registries").argument("[app]", "App ID, name, or slug").option("--workspace <id>", "Workspace ID").action(async (appArg, opts, command) => {
|
|
19379
|
+
var infoCommand2 = new Command28("info").description("Show detailed app info, preview status, and registries").argument("[app]", "App ID, name, or slug").option("--workspace <name-or-id>", "Workspace name or ID").action(async (appArg, opts, command) => {
|
|
18978
19380
|
const useJson = shouldOutputJson(command.optsWithGlobals().json);
|
|
18979
19381
|
const credentials = requireAuth();
|
|
18980
19382
|
const client = new ApiClient(credentials);
|
|
@@ -19001,15 +19403,157 @@ var infoCommand2 = new Command28("info").description("Show detailed app info, pr
|
|
|
19001
19403
|
});
|
|
19002
19404
|
var appsCommand = new Command28("apps").description("Manage workspace apps").addCommand(listCommand12).addCommand(createCommand3).addCommand(infoCommand2);
|
|
19003
19405
|
|
|
19406
|
+
// src/commands/members.ts
|
|
19407
|
+
init_store();
|
|
19408
|
+
init_client();
|
|
19409
|
+
import { Command as Command29 } from "commander";
|
|
19410
|
+
function formatMemberRows(members) {
|
|
19411
|
+
return members.map((m) => ({
|
|
19412
|
+
name: m.user.displayName || m.user.email,
|
|
19413
|
+
email: m.user.email,
|
|
19414
|
+
role: m.role,
|
|
19415
|
+
status: m.status,
|
|
19416
|
+
userId: m.userId
|
|
19417
|
+
}));
|
|
19418
|
+
}
|
|
19419
|
+
var listCommand13 = new Command29("list").description("List members of a workspace (name, email, role)").option("--workspace <name-or-id>", "Workspace name or ID").action(async (opts, command) => {
|
|
19420
|
+
const useJson = shouldOutputJson(command.optsWithGlobals().json);
|
|
19421
|
+
const credentials = requireAuth();
|
|
19422
|
+
const client = new ApiClient(credentials);
|
|
19423
|
+
const { workspaceId, workspaceName } = await resolveWorkspace2(client, opts);
|
|
19424
|
+
try {
|
|
19425
|
+
const members = await client.listWorkspaceMembers(workspaceId);
|
|
19426
|
+
if (useJson) {
|
|
19427
|
+
jsonOut({ workspaceId, workspaceName, members });
|
|
19428
|
+
return;
|
|
19429
|
+
}
|
|
19430
|
+
if (members.length === 0) {
|
|
19431
|
+
console.log("No members found in this workspace.");
|
|
19432
|
+
return;
|
|
19433
|
+
}
|
|
19434
|
+
console.log(`
|
|
19435
|
+
Workspace: ${workspaceName || workspaceId}
|
|
19436
|
+
`);
|
|
19437
|
+
console.log(` ${"NAME".padEnd(24)} ${"EMAIL".padEnd(32)} ${"ROLE".padEnd(10)} STATUS`);
|
|
19438
|
+
console.log(" " + "-".repeat(76));
|
|
19439
|
+
for (const row of formatMemberRows(members)) {
|
|
19440
|
+
console.log(` ${row.name.padEnd(24)} ${row.email.padEnd(32)} ${row.role.padEnd(10)} ${row.status}`);
|
|
19441
|
+
}
|
|
19442
|
+
console.log("");
|
|
19443
|
+
} catch (err) {
|
|
19444
|
+
console.error("Failed to list members:", err instanceof Error ? err.message : err);
|
|
19445
|
+
process.exit(1);
|
|
19446
|
+
}
|
|
19447
|
+
});
|
|
19448
|
+
var membersCommand = new Command29("members").description("List workspace members").addCommand(listCommand13);
|
|
19449
|
+
|
|
19450
|
+
// src/commands/api.ts
|
|
19451
|
+
init_store();
|
|
19452
|
+
init_client();
|
|
19453
|
+
import { Command as Command30 } from "commander";
|
|
19454
|
+
import { readFileSync as readFileSync37 } from "fs";
|
|
19455
|
+
function normalizeApiPath(rawPath, baseUrl) {
|
|
19456
|
+
if (/^https?:\/\//i.test(rawPath)) {
|
|
19457
|
+
const target = new URL(rawPath);
|
|
19458
|
+
const base = new URL(baseUrl);
|
|
19459
|
+
if (target.origin !== base.origin) {
|
|
19460
|
+
throw new Error(`Refusing to call ${target.origin}: \`runwork api\` only calls the platform API at ${base.origin}.`);
|
|
19461
|
+
}
|
|
19462
|
+
return target.pathname + target.search;
|
|
19463
|
+
}
|
|
19464
|
+
return rawPath.startsWith("/") ? rawPath : `/${rawPath}`;
|
|
19465
|
+
}
|
|
19466
|
+
var apiCommand = new Command30("api").description("Make an authenticated request to the Runwork platform API (escape hatch for endpoints the CLI does not cover)").argument("<method>", "HTTP method (GET, POST, PUT, DELETE, etc.)").argument("[path]", "API path (e.g. /api/workspaces); optional with --curl").option("--body <json>", "Request body JSON (or @file.json)").option("--header <header>", 'Request header (format: "Key: Value", repeatable)', (val, prev) => [...prev, val], []).option("--query <query>", "Query string (e.g. limit=10&offset=0)").option("--curl <command>", "Parse a curl command (method, path, headers, body)").option("--curl-file <file>", "Read curl command from a file").addHelpText("after", `
|
|
19467
|
+
Examples:
|
|
19468
|
+
runwork api GET /api/workspaces
|
|
19469
|
+
runwork api GET /api/workspaces/<id>/members
|
|
19470
|
+
runwork api POST /api/workspaces/<id>/skills --body '{"name":"my-skill"}'
|
|
19471
|
+
|
|
19472
|
+
Authentication uses your stored Runwork credentials; the API key never needs
|
|
19473
|
+
to be read or pasted manually. Prefer a dedicated command when one exists
|
|
19474
|
+
(runwork apps/members/schedules/...).`).action(async (method, path2, opts, command) => {
|
|
19475
|
+
const useJson = shouldOutputJson(command.optsWithGlobals().json);
|
|
19476
|
+
const credentials = requireAuth();
|
|
19477
|
+
const client = new ApiClient(credentials);
|
|
19478
|
+
let finalMethod = method;
|
|
19479
|
+
let finalPath = path2;
|
|
19480
|
+
const headers = {};
|
|
19481
|
+
let body;
|
|
19482
|
+
const query = opts.query;
|
|
19483
|
+
if (opts.curl || opts.curlFile) {
|
|
19484
|
+
let curlStr = opts.curl;
|
|
19485
|
+
if (opts.curlFile) {
|
|
19486
|
+
try {
|
|
19487
|
+
curlStr = readFileSync37(opts.curlFile, "utf-8");
|
|
19488
|
+
} catch (err) {
|
|
19489
|
+
console.error(`Could not read --curl-file: ${err instanceof Error ? err.message : err}`);
|
|
19490
|
+
process.exit(1);
|
|
19491
|
+
}
|
|
19492
|
+
}
|
|
19493
|
+
const parsed = await parseCurlToRequest(curlStr);
|
|
19494
|
+
finalMethod = parsed.method;
|
|
19495
|
+
finalPath = parsed.path + (parsed.query ? `?${parsed.query}` : "");
|
|
19496
|
+
Object.assign(headers, parsed.headers);
|
|
19497
|
+
body = parsed.body;
|
|
19498
|
+
}
|
|
19499
|
+
for (const h of opts.header || []) {
|
|
19500
|
+
const [key, ...rest] = h.split(":");
|
|
19501
|
+
headers[key.trim()] = rest.join(":").trim();
|
|
19502
|
+
}
|
|
19503
|
+
if (opts.body) {
|
|
19504
|
+
let raw = opts.body;
|
|
19505
|
+
if (raw.startsWith("@")) {
|
|
19506
|
+
try {
|
|
19507
|
+
raw = readFileSync37(raw.slice(1), "utf-8");
|
|
19508
|
+
} catch (err) {
|
|
19509
|
+
console.error(`Could not read body file: ${err instanceof Error ? err.message : err}`);
|
|
19510
|
+
process.exit(1);
|
|
19511
|
+
}
|
|
19512
|
+
}
|
|
19513
|
+
try {
|
|
19514
|
+
body = JSON.parse(raw);
|
|
19515
|
+
} catch {
|
|
19516
|
+
console.error("Invalid JSON in --body");
|
|
19517
|
+
process.exit(1);
|
|
19518
|
+
}
|
|
19519
|
+
}
|
|
19520
|
+
if (!finalPath) {
|
|
19521
|
+
console.error("Usage: runwork api <method> <path>");
|
|
19522
|
+
console.error(' or: runwork api <method> --curl "curl ..."');
|
|
19523
|
+
process.exit(1);
|
|
19524
|
+
}
|
|
19525
|
+
try {
|
|
19526
|
+
const normalizedPath = normalizeApiPath(finalPath, credentials.baseUrl || "https://runwork.ai");
|
|
19527
|
+
const result = await client.rawApiCall(finalMethod, normalizedPath, {
|
|
19528
|
+
body,
|
|
19529
|
+
headers: Object.keys(headers).length > 0 ? headers : undefined,
|
|
19530
|
+
query
|
|
19531
|
+
});
|
|
19532
|
+
if (useJson) {
|
|
19533
|
+
jsonOut({ success: result.ok, status: result.status, body: result.body });
|
|
19534
|
+
} else if (typeof result.body === "string") {
|
|
19535
|
+
console.log(result.body);
|
|
19536
|
+
} else {
|
|
19537
|
+
console.log(JSON.stringify(result.body, null, 2));
|
|
19538
|
+
}
|
|
19539
|
+
if (!result.ok)
|
|
19540
|
+
process.exit(1);
|
|
19541
|
+
} catch (err) {
|
|
19542
|
+
console.error("API call failed:", err instanceof Error ? err.message : err);
|
|
19543
|
+
process.exit(1);
|
|
19544
|
+
}
|
|
19545
|
+
});
|
|
19546
|
+
|
|
19004
19547
|
// src/commands/doctor.ts
|
|
19005
19548
|
init_colors();
|
|
19006
|
-
import { Command as
|
|
19549
|
+
import { Command as Command31 } from "commander";
|
|
19007
19550
|
|
|
19008
19551
|
// src/health/checks.ts
|
|
19009
19552
|
init_subprocess();
|
|
19010
19553
|
init_store();
|
|
19011
19554
|
init_client();
|
|
19012
|
-
import {
|
|
19555
|
+
import { parse as parse2 } from "smol-toml";
|
|
19556
|
+
import { existsSync as existsSync44, readFileSync as readFileSync38 } from "fs";
|
|
19013
19557
|
import { join as join40, sep as sep3 } from "path";
|
|
19014
19558
|
import { homedir as homedir22, platform as osPlatform2, arch as osArch } from "os";
|
|
19015
19559
|
init_http();
|
|
@@ -19045,7 +19589,7 @@ function buildContext() {
|
|
|
19045
19589
|
const configPath = join40(process.cwd(), ".runwork.json");
|
|
19046
19590
|
if (existsSync44(configPath)) {
|
|
19047
19591
|
try {
|
|
19048
|
-
config = JSON.parse(
|
|
19592
|
+
config = JSON.parse(readFileSync38(configPath, "utf-8"));
|
|
19049
19593
|
} catch {}
|
|
19050
19594
|
}
|
|
19051
19595
|
return { credentials, client, config, cwd: process.cwd() };
|
|
@@ -19265,6 +19809,14 @@ async function checkGitCredentialHelper(ctx) {
|
|
|
19265
19809
|
fix: "runwork doctor --fix (re-registers with the current binary path)"
|
|
19266
19810
|
};
|
|
19267
19811
|
}
|
|
19812
|
+
if (!lookup.hasReset) {
|
|
19813
|
+
return {
|
|
19814
|
+
name: "git-credential-helper",
|
|
19815
|
+
status: "fail",
|
|
19816
|
+
message: `helper registered for ${origin} but the credential-manager reset entry is missing (Windows may show a Git Credential Manager popup)`,
|
|
19817
|
+
fix: "runwork doctor --fix"
|
|
19818
|
+
};
|
|
19819
|
+
}
|
|
19268
19820
|
return {
|
|
19269
19821
|
name: "git-credential-helper",
|
|
19270
19822
|
status: "pass",
|
|
@@ -19394,7 +19946,7 @@ function loadSetupState5() {
|
|
|
19394
19946
|
for (const p of [projectPath, userPath]) {
|
|
19395
19947
|
if (existsSync44(p)) {
|
|
19396
19948
|
try {
|
|
19397
|
-
return JSON.parse(
|
|
19949
|
+
return JSON.parse(readFileSync38(p, "utf-8"));
|
|
19398
19950
|
} catch {
|
|
19399
19951
|
continue;
|
|
19400
19952
|
}
|
|
@@ -19402,6 +19954,95 @@ function loadSetupState5() {
|
|
|
19402
19954
|
}
|
|
19403
19955
|
return null;
|
|
19404
19956
|
}
|
|
19957
|
+
var RUNWORK_NETWORK_DOMAINS = ["runwork.ai", "*.runwork.ai"];
|
|
19958
|
+
async function checkCodexNetwork() {
|
|
19959
|
+
const name = "codex-network";
|
|
19960
|
+
const state = loadSetupState5();
|
|
19961
|
+
if (!state || !state.configuredAgents.includes("codex")) {
|
|
19962
|
+
return { name, status: "skip", message: "Codex not configured for Runwork" };
|
|
19963
|
+
}
|
|
19964
|
+
const configPath = join40(homedir22(), ".codex", "config.toml");
|
|
19965
|
+
if (!existsSync44(configPath)) {
|
|
19966
|
+
return { name, status: "skip", message: "no Codex config found" };
|
|
19967
|
+
}
|
|
19968
|
+
let parsed;
|
|
19969
|
+
try {
|
|
19970
|
+
parsed = parse2(readFileSync38(configPath, "utf-8"));
|
|
19971
|
+
} catch {
|
|
19972
|
+
return { name, status: "warn", message: "could not parse ~/.codex/config.toml" };
|
|
19973
|
+
}
|
|
19974
|
+
const features = parsed.features && typeof parsed.features === "object" ? parsed.features : undefined;
|
|
19975
|
+
const proxy = features?.network_proxy;
|
|
19976
|
+
if (proxy && proxy.enabled === true) {
|
|
19977
|
+
const domains = proxy.domains && typeof proxy.domains === "object" ? proxy.domains : {};
|
|
19978
|
+
if (RUNWORK_NETWORK_DOMAINS.some((d) => domains[d] === "deny")) {
|
|
19979
|
+
return {
|
|
19980
|
+
name,
|
|
19981
|
+
status: "warn",
|
|
19982
|
+
message: "network proxy denies runwork.ai; the Runwork CLI is blocked",
|
|
19983
|
+
fix: 'remove the runwork.ai "deny" rule in ~/.codex/config.toml'
|
|
19984
|
+
};
|
|
19985
|
+
}
|
|
19986
|
+
if (RUNWORK_NETWORK_DOMAINS.every((d) => domains[d] === "allow")) {
|
|
19987
|
+
return { name, status: "pass", message: "proxy-allowlisted: runwork.ai permitted, other domains scoped by your proxy" };
|
|
19988
|
+
}
|
|
19989
|
+
return {
|
|
19990
|
+
name,
|
|
19991
|
+
status: "warn",
|
|
19992
|
+
message: "network proxy is on but runwork.ai is not allowlisted",
|
|
19993
|
+
fix: "runwork sync"
|
|
19994
|
+
};
|
|
19995
|
+
}
|
|
19996
|
+
const sww = parsed.sandbox_workspace_write && typeof parsed.sandbox_workspace_write === "object" ? parsed.sandbox_workspace_write : undefined;
|
|
19997
|
+
const sandboxMode = typeof parsed.sandbox_mode === "string" ? parsed.sandbox_mode : undefined;
|
|
19998
|
+
if (sww?.network_access === true || sandboxMode === "danger-full-access") {
|
|
19999
|
+
return { name, status: "pass", message: "open: outbound network enabled (all domains)" };
|
|
20000
|
+
}
|
|
20001
|
+
if (sww?.network_access === false) {
|
|
20002
|
+
return {
|
|
20003
|
+
name,
|
|
20004
|
+
status: "warn",
|
|
20005
|
+
message: "off: network explicitly disabled; the Runwork CLI cannot reach the network",
|
|
20006
|
+
fix: "set [sandbox_workspace_write] network_access = true, or run runwork sync"
|
|
20007
|
+
};
|
|
20008
|
+
}
|
|
20009
|
+
return {
|
|
20010
|
+
name,
|
|
20011
|
+
status: "warn",
|
|
20012
|
+
message: "off: network is disabled by default in Codex workspace-write sandbox; the Runwork CLI cannot reach the network",
|
|
20013
|
+
fix: "runwork sync"
|
|
20014
|
+
};
|
|
20015
|
+
}
|
|
20016
|
+
async function checkCodexDesktopProject() {
|
|
20017
|
+
const name = "codex-desktop-project";
|
|
20018
|
+
const state = loadSetupState5();
|
|
20019
|
+
const usesCodex = !!state && (state.configuredAgents.includes("codex-app") || state.configuredAgents.includes("codex"));
|
|
20020
|
+
if (!usesCodex) {
|
|
20021
|
+
return { name, status: "skip", message: "Codex not configured for Runwork" };
|
|
20022
|
+
}
|
|
20023
|
+
const statePath2 = join40(homedir22(), ".codex", ".codex-global-state.json");
|
|
20024
|
+
if (!existsSync44(statePath2)) {
|
|
20025
|
+
return { name, status: "skip", message: "Codex desktop app not detected" };
|
|
20026
|
+
}
|
|
20027
|
+
let savedRoots = [];
|
|
20028
|
+
try {
|
|
20029
|
+
const parsed = JSON.parse(readFileSync38(statePath2, "utf-8"));
|
|
20030
|
+
const roots = parsed["electron-saved-workspace-roots"];
|
|
20031
|
+
savedRoots = Array.isArray(roots) ? roots.filter((r) => typeof r === "string") : [];
|
|
20032
|
+
} catch {
|
|
20033
|
+
return { name, status: "warn", message: "could not read Codex desktop state" };
|
|
20034
|
+
}
|
|
20035
|
+
const runworkDir = join40(homedir22(), ".runwork");
|
|
20036
|
+
if (savedRoots.includes(runworkDir)) {
|
|
20037
|
+
return { name, status: "pass", message: "Runwork project added to Codex desktop sidebar" };
|
|
20038
|
+
}
|
|
20039
|
+
return {
|
|
20040
|
+
name,
|
|
20041
|
+
status: "warn",
|
|
20042
|
+
message: "Runwork project not added to Codex desktop sidebar",
|
|
20043
|
+
fix: "quit the Codex app, then run runwork sync (sync skips this while Codex is open)"
|
|
20044
|
+
};
|
|
20045
|
+
}
|
|
19405
20046
|
async function checkAgentSetup() {
|
|
19406
20047
|
const state = loadSetupState5();
|
|
19407
20048
|
if (!state) {
|
|
@@ -19446,7 +20087,7 @@ async function checkAgentSetup() {
|
|
|
19446
20087
|
const mcpConfigPath = getMcpConfigPath2(slug, "user");
|
|
19447
20088
|
if (mcpConfigPath && existsSync44(mcpConfigPath)) {
|
|
19448
20089
|
try {
|
|
19449
|
-
const content =
|
|
20090
|
+
const content = readFileSync38(mcpConfigPath, "utf-8");
|
|
19450
20091
|
const missingMcp = state.mcpServers.filter((name) => !content.includes(name));
|
|
19451
20092
|
if (missingMcp.length > 0) {
|
|
19452
20093
|
details.push(`${missingMcp.length} MCP server(s) missing from ${slug} config`);
|
|
@@ -19504,7 +20145,8 @@ function getMcpConfigPath2(slug, scope) {
|
|
|
19504
20145
|
case "windsurf":
|
|
19505
20146
|
return scope === "project" ? join40(process.cwd(), ".windsurf", "mcp.json") : join40(home, ".windsurf", "mcp.json");
|
|
19506
20147
|
case "codex":
|
|
19507
|
-
|
|
20148
|
+
case "codex-app":
|
|
20149
|
+
return scope === "user" ? join40(home, ".codex", "config.toml") : null;
|
|
19508
20150
|
case "gemini":
|
|
19509
20151
|
return scope === "user" ? join40(home, ".gemini", "settings.json") : null;
|
|
19510
20152
|
default:
|
|
@@ -19517,6 +20159,7 @@ function getSkillsDir(slug, scope) {
|
|
|
19517
20159
|
case "claude-code":
|
|
19518
20160
|
return scope === "project" ? join40(process.cwd(), ".claude", "skills") : join40(home, ".claude", "skills");
|
|
19519
20161
|
case "codex":
|
|
20162
|
+
case "codex-app":
|
|
19520
20163
|
return scope === "project" ? join40(process.cwd(), ".codex", "skills") : join40(home, ".codex", "skills");
|
|
19521
20164
|
case "gemini":
|
|
19522
20165
|
return scope === "project" ? join40(process.cwd(), ".gemini", "skills") : join40(home, ".gemini", "skills");
|
|
@@ -19543,7 +20186,9 @@ var CHECK_RUNNERS = [
|
|
|
19543
20186
|
{ names: ["app-exists"], run: async (ctx) => [await checkAppExists(ctx)] },
|
|
19544
20187
|
{ names: ["git-remote"], run: async (ctx) => [await checkGitRemote(ctx)] },
|
|
19545
20188
|
{ names: ["deploy-freshness"], run: async (ctx) => [await checkDeployFreshness(ctx)] },
|
|
19546
|
-
{ names: ["agent-setup"], run: async () => [await checkAgentSetup()] }
|
|
20189
|
+
{ names: ["agent-setup"], run: async () => [await checkAgentSetup()] },
|
|
20190
|
+
{ names: ["codex-network"], run: async () => [await checkCodexNetwork()] },
|
|
20191
|
+
{ names: ["codex-desktop-project"], run: async () => [await checkCodexDesktopProject()] }
|
|
19547
20192
|
];
|
|
19548
20193
|
var ALL_CHECK_NAMES = CHECK_RUNNERS.flatMap((r) => r.names);
|
|
19549
20194
|
async function runAllChecks(options) {
|
|
@@ -19616,7 +20261,7 @@ async function applyDoctorFixes(ctx, failingNames) {
|
|
|
19616
20261
|
}
|
|
19617
20262
|
|
|
19618
20263
|
// src/agents/runtime-detection.ts
|
|
19619
|
-
import { existsSync as existsSync46, readFileSync as
|
|
20264
|
+
import { existsSync as existsSync46, readFileSync as readFileSync39, statSync as statSync6, readdirSync as readdirSync13 } from "fs";
|
|
19620
20265
|
import { homedir as homedir23 } from "os";
|
|
19621
20266
|
import { join as join42 } from "path";
|
|
19622
20267
|
var RUNWORK_SESSIONS_DIR = join42(homedir23(), ".runwork", "sessions");
|
|
@@ -19686,7 +20331,7 @@ function readHookSessionInfo(sessionId) {
|
|
|
19686
20331
|
if (!existsSync46(path2))
|
|
19687
20332
|
return null;
|
|
19688
20333
|
try {
|
|
19689
|
-
const raw =
|
|
20334
|
+
const raw = readFileSync39(path2, "utf8");
|
|
19690
20335
|
const parsed = JSON.parse(raw);
|
|
19691
20336
|
return parsed;
|
|
19692
20337
|
} catch {
|
|
@@ -19906,7 +20551,9 @@ var CHECK_LABELS = {
|
|
|
19906
20551
|
"app-exists": "App exists",
|
|
19907
20552
|
"git-remote": "Git remote",
|
|
19908
20553
|
"deploy-freshness": "Deploy freshness",
|
|
19909
|
-
"agent-setup": "Agent setup"
|
|
20554
|
+
"agent-setup": "Agent setup",
|
|
20555
|
+
"codex-network": "Codex network",
|
|
20556
|
+
"codex-desktop-project": "Codex project"
|
|
19910
20557
|
};
|
|
19911
20558
|
function printHumanReport(report) {
|
|
19912
20559
|
console.log("");
|
|
@@ -19971,7 +20618,7 @@ function parseCheckNames(raw) {
|
|
|
19971
20618
|
const unknown = requested.filter((n) => !known.has(n));
|
|
19972
20619
|
return { only, unknown };
|
|
19973
20620
|
}
|
|
19974
|
-
var doctorCommand = new
|
|
20621
|
+
var doctorCommand = new Command31("doctor").description("Check system health: auth, network, project config, agent setup").option("-v, --verbose", "Include host-agent detection results, runtime info, and allowlisted env vars (useful for AI agents debugging their own environment)").option("--check <names>", `Run only the named checks (comma-separated). Available: ${ALL_CHECK_NAMES.join(", ")}`).option("--fix", "Auto-remediate fixable failures (git credential helper, runwork remote), then re-check").action(async (opts, command) => {
|
|
19975
20622
|
const asJson = shouldOutputJson(command.optsWithGlobals().json);
|
|
19976
20623
|
let only;
|
|
19977
20624
|
if (opts.check) {
|
|
@@ -20022,8 +20669,8 @@ var doctorCommand = new Command29("doctor").description("Check system health: au
|
|
|
20022
20669
|
// src/commands/share-convo.ts
|
|
20023
20670
|
init_store();
|
|
20024
20671
|
init_client();
|
|
20025
|
-
import { Command as
|
|
20026
|
-
import { readFileSync as
|
|
20672
|
+
import { Command as Command32 } from "commander";
|
|
20673
|
+
import { readFileSync as readFileSync40, existsSync as existsSync47 } from "fs";
|
|
20027
20674
|
import { createHash as createHash4 } from "crypto";
|
|
20028
20675
|
function nativeBundleFormatForAgent(slug) {
|
|
20029
20676
|
if (slug === "claude-code" || slug === "claude-desktop")
|
|
@@ -20065,7 +20712,7 @@ async function runShareConvo(opts, command, isPersonalAlias = false) {
|
|
|
20065
20712
|
const credentials = requireAuth();
|
|
20066
20713
|
const client = new ApiClient(credentials);
|
|
20067
20714
|
const { workspaceId } = await resolveWorkspace2(client, { workspace: opts.workspace });
|
|
20068
|
-
const transcriptContent =
|
|
20715
|
+
const transcriptContent = readFileSync40(opts.transcriptFile, "utf8");
|
|
20069
20716
|
const bundles = [
|
|
20070
20717
|
{
|
|
20071
20718
|
format: "transcript",
|
|
@@ -20090,7 +20737,7 @@ async function runShareConvo(opts, command, isPersonalAlias = false) {
|
|
|
20090
20737
|
const nativeFormat = nativeBundleFormatForAgent(sourceAgent);
|
|
20091
20738
|
if (nativeFormat) {
|
|
20092
20739
|
try {
|
|
20093
|
-
const content =
|
|
20740
|
+
const content = readFileSync40(nativeFilePath, "utf8");
|
|
20094
20741
|
bundles.push({
|
|
20095
20742
|
format: nativeFormat,
|
|
20096
20743
|
content,
|
|
@@ -20106,7 +20753,7 @@ async function runShareConvo(opts, command, isPersonalAlias = false) {
|
|
|
20106
20753
|
let metadata = {};
|
|
20107
20754
|
if (opts.metadataFile) {
|
|
20108
20755
|
try {
|
|
20109
|
-
metadata = JSON.parse(
|
|
20756
|
+
metadata = JSON.parse(readFileSync40(opts.metadataFile, "utf8"));
|
|
20110
20757
|
} catch (err) {
|
|
20111
20758
|
console.error(`Error: --metadata-file is not valid JSON: ${err instanceof Error ? err.message : err}`);
|
|
20112
20759
|
process.exit(1);
|
|
@@ -20161,17 +20808,17 @@ Skipped: ${result.skipped.map((s) => `${s.identifier} (${s.reason})`).join(", ")
|
|
|
20161
20808
|
process.exit(1);
|
|
20162
20809
|
}
|
|
20163
20810
|
}
|
|
20164
|
-
var shareConvoCommand = new
|
|
20811
|
+
var shareConvoCommand = new Command32("share-convo").description("Share the current AI conversation with a teammate").option("--to <email>", "Recipient email (repeatable)", (value, prev = []) => [...prev, value], []).option("--transcript-file <path>", "Path to the LLM-emitted markdown transcript (required)").option("--native-file <path>", "Path to the native session file (optional; auto-detected from env vars otherwise)").option("--source-agent <slug>", "Override host-agent detection (e.g. claude-code, codex, claude-desktop)").option("--title <string>", "Short title for the conversation (required)").option("--note <string>", "Optional personal note to recipients").option("--ttl-days <n>", "Days until expiration (1-30, default 7)").option("--metadata-json <json>", "Inline JSON object with workMode, openQuestions, suggestedNextStep, etc.").option("--metadata-file <path>", "Path to a JSON file with the same metadata fields").option("--workspace <name-or-id>", "Workspace name or ID").action((opts, command) => runShareConvo(opts, command, false));
|
|
20165
20812
|
|
|
20166
20813
|
// src/commands/save-convo.ts
|
|
20167
|
-
import { Command as
|
|
20168
|
-
var saveConvoCommand = new
|
|
20814
|
+
import { Command as Command33 } from "commander";
|
|
20815
|
+
var saveConvoCommand = new Command33("save-convo").description("Save the current AI conversation as a personal checkpoint").option("--transcript-file <path>", "Path to the LLM-emitted markdown transcript (required)").option("--native-file <path>", "Path to the native session file (optional; auto-detected from env vars)").option("--source-agent <slug>", "Override host-agent detection").option("--title <string>", "Short title for the conversation (required)").option("--note <string>", "Optional note to your future self").option("--ttl-days <n>", "Days until expiration (1-30, default 7)").option("--metadata-json <json>", "Inline JSON object with workMode, openQuestions, etc.").option("--metadata-file <path>", "Path to a JSON file with metadata fields").option("--workspace <name-or-id>", "Workspace name or ID").action((opts, command) => runShareConvo({ ...opts, personal: true }, command, true));
|
|
20169
20816
|
|
|
20170
20817
|
// src/commands/inbox.ts
|
|
20171
20818
|
init_store();
|
|
20172
20819
|
init_client();
|
|
20173
|
-
import { Command as
|
|
20174
|
-
var inboxCommand = new
|
|
20820
|
+
import { Command as Command34 } from "commander";
|
|
20821
|
+
var inboxCommand = new Command34("inbox").description("List shared conversations visible to you").option("--filter <scope>", "Filter: all | received | sent | saved", "all").option("--limit <n>", "Max rows to return", "50").option("--workspace <name-or-id>", "Workspace name or ID").action(async (opts, command) => {
|
|
20175
20822
|
const useJson = shouldOutputJson(command.optsWithGlobals().json);
|
|
20176
20823
|
const scope = opts.filter === "received" || opts.filter === "sent" || opts.filter === "saved" ? opts.filter : "all";
|
|
20177
20824
|
const limit = opts.limit ? parseInt(opts.limit, 10) : 50;
|
|
@@ -20211,7 +20858,7 @@ Shared conversations (${scope}, ${total}):
|
|
|
20211
20858
|
// src/commands/resume.ts
|
|
20212
20859
|
init_store();
|
|
20213
20860
|
init_client();
|
|
20214
|
-
import { Command as
|
|
20861
|
+
import { Command as Command35 } from "commander";
|
|
20215
20862
|
import { writeFileSync as writeFileSync31, mkdirSync as mkdirSync28, realpathSync } from "fs";
|
|
20216
20863
|
import { homedir as homedir24 } from "os";
|
|
20217
20864
|
import { join as join43 } from "path";
|
|
@@ -20285,7 +20932,7 @@ function isAgentInstalled(agent) {
|
|
|
20285
20932
|
}
|
|
20286
20933
|
return false;
|
|
20287
20934
|
}
|
|
20288
|
-
var resumeCommand2 = new
|
|
20935
|
+
var resumeCommand2 = new Command35("resume").description("Resume a shared conversation locally in your agent of choice").argument("<share-id>", "The share ID (sc_*) returned by share-convo or save-convo").option("--agent <slug>", "Override target agent (e.g. claude-code, codex)").option("--into <path>", "Override target cwd (defaults to current $PWD)").option("--dry-run", "Print the resume command instead of executing it").option("--pick", "Show interactive picker (requires TTY) - not yet implemented").option("--workspace <name-or-id>", "Workspace name or ID").action(async (shareId, opts, command) => {
|
|
20289
20936
|
const useJson = shouldOutputJson(command.optsWithGlobals().json);
|
|
20290
20937
|
const credentials = requireAuth();
|
|
20291
20938
|
const client = new ApiClient(credentials);
|
|
@@ -20510,7 +21157,7 @@ process.on("uncaughtException", (err) => {
|
|
|
20510
21157
|
console.error(`Uncaught exception: ${formatError(err)}`);
|
|
20511
21158
|
process.exit(1);
|
|
20512
21159
|
});
|
|
20513
|
-
var program = new
|
|
21160
|
+
var program = new Command36;
|
|
20514
21161
|
program.name("runwork").description("Runwork CLI - local development for Runwork apps").version(VERSION).option("--json", "Output as JSON (auto-enabled when stdout is not a TTY)");
|
|
20515
21162
|
program.addCommand(infoCommand);
|
|
20516
21163
|
program.addCommand(loginCommand);
|
|
@@ -20539,6 +21186,8 @@ program.addCommand(syncCommand);
|
|
|
20539
21186
|
program.addCommand(buildPluginCommand);
|
|
20540
21187
|
program.addCommand(uninstallCommand);
|
|
20541
21188
|
program.addCommand(appsCommand);
|
|
21189
|
+
program.addCommand(membersCommand);
|
|
21190
|
+
program.addCommand(apiCommand);
|
|
20542
21191
|
program.addCommand(doctorCommand);
|
|
20543
21192
|
program.addCommand(shareConvoCommand);
|
|
20544
21193
|
program.addCommand(saveConvoCommand);
|