@openwop/cli 1.3.0 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -2
- package/dist/cli.js +455 -267
- package/dist/openwop.js +455 -267
- package/package.json +1 -1
package/dist/openwop.js
CHANGED
|
@@ -579,7 +579,7 @@ function errText(err) {
|
|
|
579
579
|
// package.json
|
|
580
580
|
var package_default = {
|
|
581
581
|
name: "@openwop/cli",
|
|
582
|
-
version: "1.
|
|
582
|
+
version: "1.4.0",
|
|
583
583
|
description: "OpenWOP CLI for operating the workflow-engine demo app and OpenWOP-compatible hosts.",
|
|
584
584
|
license: "Apache-2.0",
|
|
585
585
|
type: "module",
|
|
@@ -1079,7 +1079,7 @@ import { createInterface as createInterface2 } from "node:readline";
|
|
|
1079
1079
|
|
|
1080
1080
|
// src/ids.ts
|
|
1081
1081
|
function projectTenantBoundId(id) {
|
|
1082
|
-
if (id.includes("~")) return id;
|
|
1082
|
+
if (id.includes("~") && !id.includes("/")) return id;
|
|
1083
1083
|
let out = "";
|
|
1084
1084
|
for (const byte of new TextEncoder().encode(id)) {
|
|
1085
1085
|
const ch = String.fromCharCode(byte);
|
|
@@ -2632,7 +2632,19 @@ async function runInterrupts(ctx, argv) {
|
|
|
2632
2632
|
write(ctx.io.stdout, "Usage: openwop interrupts list <runId> [--json]\n");
|
|
2633
2633
|
return 2;
|
|
2634
2634
|
}
|
|
2635
|
-
|
|
2635
|
+
let res;
|
|
2636
|
+
try {
|
|
2637
|
+
res = await requestJson(ctx, `/v1/host/openwop-app/runs/${encodeURIComponent(rest[0])}/interrupts`);
|
|
2638
|
+
} catch (err) {
|
|
2639
|
+
const env = err instanceof HttpError ? errorEnvelope(err.body) : {};
|
|
2640
|
+
if (err instanceof HttpError && err.status === 404 && /^no operation at /i.test(env.message ?? "")) {
|
|
2641
|
+
throw new CliError(
|
|
2642
|
+
"interrupts: `list` reads the openwop-app host extension (GET /v1/host/openwop-app/runs/{runId}/interrupts), which this host does not serve. On any host an open interrupt appears as interrupt.requested in the run's events; answer it with `openwop interrupts respond <runId> <nodeId>`.",
|
|
2643
|
+
1
|
|
2644
|
+
);
|
|
2645
|
+
}
|
|
2646
|
+
throw err;
|
|
2647
|
+
}
|
|
2636
2648
|
if (ctx.json) {
|
|
2637
2649
|
writeJson(ctx.io.stdout, res.body);
|
|
2638
2650
|
return 0;
|
|
@@ -3599,6 +3611,24 @@ async function readDiscovery(ctx) {
|
|
|
3599
3611
|
ctx.discovery = { doc: res.body, servedVersion };
|
|
3600
3612
|
return { doc: res.body, servedVersion, major };
|
|
3601
3613
|
}
|
|
3614
|
+
async function advertisedRecord(ctx, pick) {
|
|
3615
|
+
const doc = (d) => d && typeof d === "object" ? d : {};
|
|
3616
|
+
let readAny = false;
|
|
3617
|
+
const v1 = await safeRequest(ctx, "/.well-known/openwop", { auth: false });
|
|
3618
|
+
if (v1.ok) {
|
|
3619
|
+
readAny = true;
|
|
3620
|
+
const r = pick(doc(v1.body));
|
|
3621
|
+
if (r) return r;
|
|
3622
|
+
}
|
|
3623
|
+
try {
|
|
3624
|
+
const { doc: negotiated } = await readDiscovery(ctx);
|
|
3625
|
+
readAny = true;
|
|
3626
|
+
const r = pick(doc(negotiated));
|
|
3627
|
+
if (r) return r;
|
|
3628
|
+
} catch {
|
|
3629
|
+
}
|
|
3630
|
+
return readAny ? null : void 0;
|
|
3631
|
+
}
|
|
3602
3632
|
function isV2Discovery(caps, servedVersion) {
|
|
3603
3633
|
if (typeof servedVersion === "string" && servedVersion.startsWith("2.")) return true;
|
|
3604
3634
|
if (!caps || typeof caps !== "object" || "capabilities" in caps || "supportedTransports" in caps) return false;
|
|
@@ -14860,6 +14890,153 @@ async function runOnboard(ctx, argv) {
|
|
|
14860
14890
|
return 0;
|
|
14861
14891
|
}
|
|
14862
14892
|
|
|
14893
|
+
// src/cli/login.ts
|
|
14894
|
+
import { hostname } from "node:os";
|
|
14895
|
+
var BASE10 = "/v1/host/openwop-app/cli-login";
|
|
14896
|
+
var LOGIN_HELP = `Usage:
|
|
14897
|
+
openwop login [--label <name>] [--timeout <seconds>] [--profile <name>] [--json]
|
|
14898
|
+
openwop logout [--profile <name>] [--json]
|
|
14899
|
+
|
|
14900
|
+
Sign this terminal in to an openwop-app host without copying an API key
|
|
14901
|
+
(host extension under ${BASE10}).
|
|
14902
|
+
|
|
14903
|
+
login Shows a short code. Open the host's Access \u2192 API keys page, type the
|
|
14904
|
+
code under "Sign in the OpenWOP CLI", and approve. The host then issues
|
|
14905
|
+
this CLI a key (30 days by default), saved to your config file.
|
|
14906
|
+
logout Revokes that key on the host and removes it from your config file.
|
|
14907
|
+
|
|
14908
|
+
The key is never printed. It is listed in the app as "CLI: <label>", where you can
|
|
14909
|
+
revoke it. Sign in again to renew.
|
|
14910
|
+
|
|
14911
|
+
--label <name> What to call this terminal in the app (default: this machine's hostname).
|
|
14912
|
+
--timeout <seconds> Give up waiting for approval after this long (default: the host's own limit).
|
|
14913
|
+
--profile <name> Use the named config profile.
|
|
14914
|
+
|
|
14915
|
+
Approve a code ONLY if you just ran \`openwop login\` yourself.
|
|
14916
|
+
|
|
14917
|
+
Exit codes: 0 signed in / signed out \xB7 1 denied, expired or not available on this host \xB7 2 usage.
|
|
14918
|
+
|
|
14919
|
+
Examples:
|
|
14920
|
+
export OPENWOP_BASE_URL=https://app.openwop.dev/api
|
|
14921
|
+
openwop login
|
|
14922
|
+
openwop login --label "work laptop"
|
|
14923
|
+
openwop logout
|
|
14924
|
+
`;
|
|
14925
|
+
var sleep2 = (ms2) => new Promise((r) => setTimeout(r, ms2));
|
|
14926
|
+
function approvalUrl(baseUrl, path) {
|
|
14927
|
+
const p = typeof path === "string" && path.startsWith("/") ? path : "/access?tab=api-keys";
|
|
14928
|
+
try {
|
|
14929
|
+
return `${new URL(baseUrl).origin}${p}`;
|
|
14930
|
+
} catch {
|
|
14931
|
+
return p;
|
|
14932
|
+
}
|
|
14933
|
+
}
|
|
14934
|
+
function notAvailable(ctx) {
|
|
14935
|
+
return new CliError(
|
|
14936
|
+
`${ctx.baseUrl} does not serve the CLI sign-in (${BASE10}/start is not there). Create an API key on the host and set OPENWOP_API_KEY instead.`,
|
|
14937
|
+
1
|
|
14938
|
+
);
|
|
14939
|
+
}
|
|
14940
|
+
async function runLogin(ctx, argv) {
|
|
14941
|
+
const { options } = parseOptions(argv, { bool: ["--help"], value: ["--label", "--timeout", "--profile"] });
|
|
14942
|
+
if (options.help) {
|
|
14943
|
+
write(ctx.io.stdout, LOGIN_HELP);
|
|
14944
|
+
return 0;
|
|
14945
|
+
}
|
|
14946
|
+
const timeoutS = options.timeout === void 0 ? void 0 : Number(options.timeout);
|
|
14947
|
+
if (timeoutS !== void 0 && !(Number.isFinite(timeoutS) && timeoutS > 0)) {
|
|
14948
|
+
writeLine(ctx.io.stderr, "--timeout must be a positive number of seconds.");
|
|
14949
|
+
return 2;
|
|
14950
|
+
}
|
|
14951
|
+
const label = String(options.label ?? hostname() ?? "this machine").slice(0, 60);
|
|
14952
|
+
const anon = { ...ctx, apiKey: void 0 };
|
|
14953
|
+
let started;
|
|
14954
|
+
try {
|
|
14955
|
+
started = (await requestJson(anon, `${BASE10}/start`, { method: "POST", body: { label } })).body;
|
|
14956
|
+
} catch (err) {
|
|
14957
|
+
if (err instanceof HttpError && err.status === 404) throw notAvailable(ctx);
|
|
14958
|
+
throw err;
|
|
14959
|
+
}
|
|
14960
|
+
const deviceCode = started?.deviceCode;
|
|
14961
|
+
const userCode = started?.userCode;
|
|
14962
|
+
if (typeof deviceCode !== "string" || typeof userCode !== "string") throw notAvailable(ctx);
|
|
14963
|
+
writeLine(ctx.io.stderr, "");
|
|
14964
|
+
writeLine(ctx.io.stderr, ` 1. Open ${approvalUrl(ctx.baseUrl, started.verificationPath)}`);
|
|
14965
|
+
writeLine(ctx.io.stderr, ` 2. Enter ${userCode} under "Sign in the OpenWOP CLI", and approve.`);
|
|
14966
|
+
writeLine(ctx.io.stderr, "");
|
|
14967
|
+
writeLine(ctx.io.stderr, "Waiting for approval\u2026");
|
|
14968
|
+
const hostLimitS = Number.isFinite(Number(started.expiresIn)) ? Number(started.expiresIn) : 600;
|
|
14969
|
+
const deadline = Date.now() + Math.min(timeoutS ?? hostLimitS, hostLimitS) * 1e3;
|
|
14970
|
+
let intervalS = Number.isFinite(Number(started.interval)) ? Number(started.interval) : 3;
|
|
14971
|
+
for (; ; ) {
|
|
14972
|
+
if (Date.now() >= deadline) throw new CliError("Timed out waiting for approval. Run `openwop login` again for a new code.", 1);
|
|
14973
|
+
await sleep2(Math.max(0, intervalS) * 1e3);
|
|
14974
|
+
let res;
|
|
14975
|
+
try {
|
|
14976
|
+
res = (await requestJson(anon, `${BASE10}/poll`, { method: "POST", body: { deviceCode } })).body;
|
|
14977
|
+
} catch (err) {
|
|
14978
|
+
if (err instanceof HttpError && err.status === 404) {
|
|
14979
|
+
throw new CliError("That sign-in expired or was already used. Run `openwop login` again for a new code.", 1);
|
|
14980
|
+
}
|
|
14981
|
+
throw err;
|
|
14982
|
+
}
|
|
14983
|
+
if (res?.status === "pending") {
|
|
14984
|
+
if (Number.isFinite(Number(res.interval))) intervalS = Number(res.interval);
|
|
14985
|
+
continue;
|
|
14986
|
+
}
|
|
14987
|
+
if (res?.status === "denied") throw new CliError("The sign-in was denied in the app.", 1);
|
|
14988
|
+
if (res?.status === "failed") throw new CliError(`The host could not issue a key: ${String(res.message ?? "unknown reason")}`, 1);
|
|
14989
|
+
if (res?.status === "approved" && typeof res.token === "string") {
|
|
14990
|
+
const configPath = configPathFor(options.profile, ctx.env);
|
|
14991
|
+
saveConfig(configPath, mergeConfig(readConfigSafe(configPath), { host: { baseUrl: ctx.baseUrl, apiKey: res.token } }));
|
|
14992
|
+
const key = res.key ?? {};
|
|
14993
|
+
if (ctx.json) {
|
|
14994
|
+
writeJson(ctx.io.stdout, { status: "signed-in", keyId: key.keyId ?? null, name: key.name ?? null, expiresAt: key.expiresAt ?? null, configPath });
|
|
14995
|
+
return 0;
|
|
14996
|
+
}
|
|
14997
|
+
writeLine(ctx.io.stdout, `Signed in to ${ctx.baseUrl} as \u201C${key.name ?? `CLI: ${label}`}\u201D.`);
|
|
14998
|
+
if (key.expiresAt) writeLine(ctx.io.stdout, `The key expires ${String(key.expiresAt).slice(0, 10)}; run \`openwop login\` again to renew.`);
|
|
14999
|
+
writeLine(ctx.io.stdout, `Saved to ${configPath}. Revoke it any time with \`openwop logout\` or in the app.`);
|
|
15000
|
+
return 0;
|
|
15001
|
+
}
|
|
15002
|
+
throw new CliError("The host answered the sign-in in a shape this CLI does not understand.", 1);
|
|
15003
|
+
}
|
|
15004
|
+
}
|
|
15005
|
+
async function runLogout(ctx, argv) {
|
|
15006
|
+
const { options } = parseOptions(argv, { bool: ["--help"], value: ["--profile"] });
|
|
15007
|
+
if (options.help) {
|
|
15008
|
+
write(ctx.io.stdout, LOGIN_HELP);
|
|
15009
|
+
return 0;
|
|
15010
|
+
}
|
|
15011
|
+
const configPath = configPathFor(options.profile, ctx.env);
|
|
15012
|
+
const config = readConfigSafe(configPath);
|
|
15013
|
+
const saved = config?.host?.apiKey;
|
|
15014
|
+
if (typeof saved !== "string" || saved.length === 0) {
|
|
15015
|
+
if (ctx.json) writeJson(ctx.io.stdout, { status: "not-signed-in" });
|
|
15016
|
+
else writeLine(ctx.io.stdout, "Not signed in: no key is saved in your config.");
|
|
15017
|
+
return 0;
|
|
15018
|
+
}
|
|
15019
|
+
let revoked = false;
|
|
15020
|
+
let note = "";
|
|
15021
|
+
try {
|
|
15022
|
+
await requestJson({ ...ctx, apiKey: saved }, `${BASE10}/logout`, { method: "POST", body: {} });
|
|
15023
|
+
revoked = true;
|
|
15024
|
+
} catch (err) {
|
|
15025
|
+
if (err instanceof HttpError && err.status === 401) note = "The host no longer recognised the key (already revoked or expired).";
|
|
15026
|
+
else if (err instanceof HttpError && err.status === 404) note = "This host has no sign-out route; the key was NOT revoked there \u2014 revoke it in the app.";
|
|
15027
|
+
else if (err instanceof HttpError && err.status === 400) note = "The saved key is not one a sign-in issued; it was NOT revoked on the host \u2014 revoke it in the app.";
|
|
15028
|
+
else throw err;
|
|
15029
|
+
}
|
|
15030
|
+
unsetByPath(config, "host.apiKey");
|
|
15031
|
+
saveConfig(configPath, config);
|
|
15032
|
+
if (ctx.json) {
|
|
15033
|
+
writeJson(ctx.io.stdout, { status: "signed-out", revokedOnHost: revoked, ...note ? { note } : {} });
|
|
15034
|
+
return 0;
|
|
15035
|
+
}
|
|
15036
|
+
writeLine(ctx.io.stdout, revoked ? "Signed out. The key was revoked on the host and removed from your config." : `Removed the key from your config. ${note}`);
|
|
15037
|
+
return 0;
|
|
15038
|
+
}
|
|
15039
|
+
|
|
14863
15040
|
// src/cli/providers.ts
|
|
14864
15041
|
var PROVIDERS_HELP = `Usage:
|
|
14865
15042
|
openwop providers list [--json]
|
|
@@ -18086,7 +18263,7 @@ Examples:
|
|
|
18086
18263
|
openwop profiles pin r_123
|
|
18087
18264
|
openwop profiles activity --limit 10 --status failed
|
|
18088
18265
|
`;
|
|
18089
|
-
var
|
|
18266
|
+
var BASE11 = "/v1/host/openwop-app/profiles";
|
|
18090
18267
|
async function profilesRequest(ctx, path, options, notFoundMsg) {
|
|
18091
18268
|
try {
|
|
18092
18269
|
return await requestJson(ctx, path, options);
|
|
@@ -18183,7 +18360,7 @@ async function runList2(ctx, argv) {
|
|
|
18183
18360
|
write(ctx.io.stdout, "Usage: openwop profiles list [--json]\n");
|
|
18184
18361
|
return 0;
|
|
18185
18362
|
}
|
|
18186
|
-
const res = await profilesRequest(ctx,
|
|
18363
|
+
const res = await profilesRequest(ctx, BASE11);
|
|
18187
18364
|
if (ctx.json) {
|
|
18188
18365
|
writeJson(ctx.io.stdout, res.body);
|
|
18189
18366
|
return 0;
|
|
@@ -18209,7 +18386,7 @@ async function runGet3(ctx, argv) {
|
|
|
18209
18386
|
write(ctx.io.stdout, "Usage: openwop profiles get [<userId>] [--json]\n");
|
|
18210
18387
|
return options.help ? 0 : 2;
|
|
18211
18388
|
}
|
|
18212
|
-
const path = positionals.length === 1 ? `${
|
|
18389
|
+
const path = positionals.length === 1 ? `${BASE11}/${encodeURIComponent(positionals[0])}` : `${BASE11}/me`;
|
|
18213
18390
|
const res = await profilesRequest(ctx, path, void 0, `Profile not found: ${positionals[0] ?? "me"}`);
|
|
18214
18391
|
if (ctx.json) {
|
|
18215
18392
|
writeJson(ctx.io.stdout, res.body);
|
|
@@ -18228,7 +18405,7 @@ async function runActivity(ctx, argv) {
|
|
|
18228
18405
|
if (options.limit !== void 0) qs2.set("limit", String(options.limit));
|
|
18229
18406
|
if (options.status !== void 0) qs2.set("status", String(options.status));
|
|
18230
18407
|
const q = qs2.toString();
|
|
18231
|
-
const res = await profilesRequest(ctx, `${
|
|
18408
|
+
const res = await profilesRequest(ctx, `${BASE11}/me/activity${q ? `?${q}` : ""}`);
|
|
18232
18409
|
if (ctx.json) {
|
|
18233
18410
|
writeJson(ctx.io.stdout, res.body);
|
|
18234
18411
|
return 0;
|
|
@@ -18267,7 +18444,7 @@ async function runEdit(ctx, argv) {
|
|
|
18267
18444
|
if (Array.isArray(options.interests)) body.interests = options.interests;
|
|
18268
18445
|
if (Array.isArray(options.growthInterests)) body.growthInterests = options.growthInterests;
|
|
18269
18446
|
if (options.location !== void 0 || Array.isArray(options.link)) {
|
|
18270
|
-
const current = (await profilesRequest(ctx, `${
|
|
18447
|
+
const current = (await profilesRequest(ctx, `${BASE11}/me`)).body?.contact ?? {};
|
|
18271
18448
|
const contact = { ...current };
|
|
18272
18449
|
if (options.location !== void 0) contact.location = options.location;
|
|
18273
18450
|
if (Array.isArray(options.link)) {
|
|
@@ -18294,7 +18471,7 @@ async function runEdit(ctx, argv) {
|
|
|
18294
18471
|
}
|
|
18295
18472
|
if (Object.keys(avail).length) body.availability = avail;
|
|
18296
18473
|
if (Object.keys(body).length === 0) throw new CliError("Nothing to edit \u2014 pass at least one field.", 2);
|
|
18297
|
-
const res = await profilesRequest(ctx, `${
|
|
18474
|
+
const res = await profilesRequest(ctx, `${BASE11}/me`, { method: "PATCH", body });
|
|
18298
18475
|
if (ctx.json) {
|
|
18299
18476
|
writeJson(ctx.io.stdout, res.body);
|
|
18300
18477
|
return 0;
|
|
@@ -18320,7 +18497,7 @@ async function runSkillsSet(ctx, argv) {
|
|
|
18320
18497
|
if (!Number.isFinite(prof2) || prof2 < 1 || prof2 > 5) throw new CliError(`--skill proficiency must be 1..5 (got '${e}')`, 2);
|
|
18321
18498
|
return { name, proficiency: prof2 };
|
|
18322
18499
|
});
|
|
18323
|
-
const res = await profilesRequest(ctx, `${
|
|
18500
|
+
const res = await profilesRequest(ctx, `${BASE11}/me/skills`, { method: "PUT", body: { skills } });
|
|
18324
18501
|
if (ctx.json) {
|
|
18325
18502
|
writeJson(ctx.io.stdout, res.body);
|
|
18326
18503
|
return 0;
|
|
@@ -18335,7 +18512,7 @@ async function runPortfolioAdd(ctx, argv) {
|
|
|
18335
18512
|
write(ctx.io.stdout, "Usage: openwop profiles portfolio add --token <mediaToken> [--json]\n");
|
|
18336
18513
|
return options.help ? 0 : 2;
|
|
18337
18514
|
}
|
|
18338
|
-
const res = await profilesRequest(ctx, `${
|
|
18515
|
+
const res = await profilesRequest(ctx, `${BASE11}/me/portfolio`, { method: "POST", body: { token: options.token } });
|
|
18339
18516
|
if (ctx.json) {
|
|
18340
18517
|
writeJson(ctx.io.stdout, res.body);
|
|
18341
18518
|
return 0;
|
|
@@ -18349,7 +18526,7 @@ async function runPortfolioRemove(ctx, argv) {
|
|
|
18349
18526
|
write(ctx.io.stdout, "Usage: openwop profiles portfolio remove <mediaToken> [--json]\n");
|
|
18350
18527
|
return options.help ? 0 : 2;
|
|
18351
18528
|
}
|
|
18352
|
-
const res = await profilesRequest(ctx, `${
|
|
18529
|
+
const res = await profilesRequest(ctx, `${BASE11}/me/portfolio/${encodeURIComponent(positionals[0])}`, { method: "DELETE" }, `Portfolio asset not found: ${positionals[0]}`);
|
|
18353
18530
|
if (ctx.json) {
|
|
18354
18531
|
writeJson(ctx.io.stdout, res.body);
|
|
18355
18532
|
return 0;
|
|
@@ -18364,7 +18541,7 @@ async function runPin(ctx, argv, pinned) {
|
|
|
18364
18541
|
`);
|
|
18365
18542
|
return options.help ? 0 : 2;
|
|
18366
18543
|
}
|
|
18367
|
-
const path = `${
|
|
18544
|
+
const path = `${BASE11}/me/pinned-agents/${encodeURIComponent(positionals[0])}`;
|
|
18368
18545
|
const res = await profilesRequest(ctx, path, { method: pinned ? "PUT" : "DELETE" }, `Agent not found: ${positionals[0]}`);
|
|
18369
18546
|
if (ctx.json) {
|
|
18370
18547
|
writeJson(ctx.io.stdout, res.body);
|
|
@@ -18381,7 +18558,7 @@ async function runEndorse(ctx, argv, add) {
|
|
|
18381
18558
|
return options.help ? 0 : 2;
|
|
18382
18559
|
}
|
|
18383
18560
|
const [userId, skill] = positionals;
|
|
18384
|
-
const path = `${
|
|
18561
|
+
const path = `${BASE11}/${encodeURIComponent(userId)}/skills/${encodeURIComponent(skill)}/endorse`;
|
|
18385
18562
|
const res = await profilesRequest(ctx, path, { method: add ? "POST" : "DELETE" }, `Profile or skill not found: ${userId} / ${skill}`);
|
|
18386
18563
|
if (ctx.json) {
|
|
18387
18564
|
writeJson(ctx.io.stdout, res.body);
|
|
@@ -19476,7 +19653,7 @@ Examples:
|
|
|
19476
19653
|
openwop auth saml validate --idp-url http://localhost:9100/idp --variant valid
|
|
19477
19654
|
openwop auth scim provision --op create-user --user-name jo@acme.com --email jo@acme.com
|
|
19478
19655
|
`;
|
|
19479
|
-
var
|
|
19656
|
+
var BASE12 = "/v1/host/openwop-app/auth";
|
|
19480
19657
|
var SECRET_KEY2 = /secret|token|password|private[-_]?key|client[-_]?secret|api[-_]?key|credential|bearer|assertion|certificate|cert|pem/i;
|
|
19481
19658
|
function redact2(value) {
|
|
19482
19659
|
return redactSecrets(value, { secret: SECRET_KEY2 });
|
|
@@ -19527,7 +19704,7 @@ async function runStatus(ctx, argv) {
|
|
|
19527
19704
|
const profiles = disc.ok && Array.isArray(disc.body?.capabilities?.auth?.profiles) ? disc.body.capabilities.auth.profiles : [];
|
|
19528
19705
|
const samlAdvertised = profiles.includes("openwop-auth-saml");
|
|
19529
19706
|
const scimAdvertised = profiles.includes("openwop-auth-scim");
|
|
19530
|
-
const metaReachable = samlAdvertised ? (await probeEndpoint(ctx, `${
|
|
19707
|
+
const metaReachable = samlAdvertised ? (await probeEndpoint(ctx, `${BASE12}/saml/sso/metadata`)).ok : false;
|
|
19531
19708
|
if (ctx.json) {
|
|
19532
19709
|
writeJson(ctx.io.stdout, {
|
|
19533
19710
|
authProfilesAdvertised: profiles,
|
|
@@ -19552,7 +19729,7 @@ async function runSamlMetadata(ctx, argv) {
|
|
|
19552
19729
|
write(ctx.io.stdout, "Usage: openwop auth saml metadata [--json]\n");
|
|
19553
19730
|
return 0;
|
|
19554
19731
|
}
|
|
19555
|
-
const res = await authRequest(ctx, `${
|
|
19732
|
+
const res = await authRequest(ctx, `${BASE12}/saml/sso/metadata`, { auth: false }, "SAML SSO is not configured on this host (set OPENWOP_SAML_*).");
|
|
19556
19733
|
const xml = typeof res.body?.raw === "string" ? res.body.raw : typeof res.body === "string" ? res.body : JSON.stringify(res.body);
|
|
19557
19734
|
if (ctx.json) {
|
|
19558
19735
|
writeJson(ctx.io.stdout, { metadata: xml });
|
|
@@ -19570,7 +19747,7 @@ async function runSamlLoginUrl(ctx, argv) {
|
|
|
19570
19747
|
}
|
|
19571
19748
|
const returnTo = options.returnTo ?? "/";
|
|
19572
19749
|
const base16 = ctx.baseUrl.endsWith("/") ? ctx.baseUrl : `${ctx.baseUrl}/`;
|
|
19573
|
-
const url = new URL(`${
|
|
19750
|
+
const url = new URL(`${BASE12}/saml/sso/login?returnTo=${encodeURIComponent(returnTo)}`.replace(/^\//, ""), base16);
|
|
19574
19751
|
const res = await ctx.fetchImpl(url, { method: "GET", redirect: "manual" });
|
|
19575
19752
|
if (res.status === 404) {
|
|
19576
19753
|
throw new CliError("SAML SSO is not configured on this host (set OPENWOP_SAML_*).", 1);
|
|
@@ -19595,7 +19772,7 @@ async function runSamlValidate(ctx, argv) {
|
|
|
19595
19772
|
const body = { idpUrl: options.idpUrl, variant: options.variant };
|
|
19596
19773
|
let res;
|
|
19597
19774
|
try {
|
|
19598
|
-
res = await requestJson(ctx, `${
|
|
19775
|
+
res = await requestJson(ctx, `${BASE12}/saml/validate`, { method: "POST", body });
|
|
19599
19776
|
} catch (err) {
|
|
19600
19777
|
if (err instanceof HttpError && err.status === 404) {
|
|
19601
19778
|
throw new CliError("SAML validation seam not configured on this host (set OPENWOP_TEST_SAML_IDP_URL).", 1);
|
|
@@ -19638,7 +19815,7 @@ async function runScimProvision(ctx, argv) {
|
|
|
19638
19815
|
if (options.displayName !== void 0) user.displayName = options.displayName;
|
|
19639
19816
|
const body = { op: options.op, user };
|
|
19640
19817
|
if (options.group !== void 0) body.group = options.group;
|
|
19641
|
-
const res = await authRequest(ctx, `${
|
|
19818
|
+
const res = await authRequest(ctx, `${BASE12}/scim/provision`, { method: "POST", body }, "SCIM provisioning seam not configured on this host (set OPENWOP_TEST_SCIM_URL).");
|
|
19642
19819
|
const safe = redact2(res.body ?? {});
|
|
19643
19820
|
if (ctx.json) {
|
|
19644
19821
|
writeJson(ctx.io.stdout, safe);
|
|
@@ -19662,7 +19839,7 @@ async function runBreakGlass(ctx, argv) {
|
|
|
19662
19839
|
const token = await readSecretInput(ctx, options.tokenFile !== void 0 ? { valueFile: options.tokenFile } : {}, "Break-glass token");
|
|
19663
19840
|
let res;
|
|
19664
19841
|
try {
|
|
19665
|
-
res = await requestJson(ctx, `${
|
|
19842
|
+
res = await requestJson(ctx, `${BASE12}/break-glass`, { method: "POST", body: { token } });
|
|
19666
19843
|
} catch (err) {
|
|
19667
19844
|
if (err instanceof HttpError && err.status === 404) throw new CliError("Break-glass login is not enabled on this host (OPENWOP_BREAKGLASS_ENABLED is not true).", 1);
|
|
19668
19845
|
if (err instanceof HttpError && err.status === 401) throw new CliError("Break-glass login refused (wrong, short, or already-used token, or the host is misconfigured). The attempt was audited.", 4);
|
|
@@ -19991,10 +20168,9 @@ function exitForState(state) {
|
|
|
19991
20168
|
return 1;
|
|
19992
20169
|
}
|
|
19993
20170
|
async function ensureAdvertised3(ctx) {
|
|
19994
|
-
const
|
|
19995
|
-
if (
|
|
19996
|
-
const
|
|
19997
|
-
const advertised = !!(body.capabilities?.agents?.proposals ?? body.agents?.proposals);
|
|
20171
|
+
const record = await advertisedRecord(ctx, (b) => b.capabilities?.agents?.proposals ?? b.agents?.proposals);
|
|
20172
|
+
if (record === void 0) return;
|
|
20173
|
+
const advertised = !!record;
|
|
19998
20174
|
if (!advertised) {
|
|
19999
20175
|
throw new CliError(
|
|
20000
20176
|
"proposals: this host does not advertise the reviewable-learning proposal capability (capabilities.agents.proposals is absent from /.well-known/openwop). The host is the authority \u2014 refusing to guess.",
|
|
@@ -20323,10 +20499,9 @@ function exitForState2(state) {
|
|
|
20323
20499
|
return 1;
|
|
20324
20500
|
}
|
|
20325
20501
|
async function ensureAdvertised4(ctx) {
|
|
20326
|
-
const
|
|
20327
|
-
if (
|
|
20328
|
-
const
|
|
20329
|
-
const advertised = !!(body.capabilities?.agents?.goals ?? body.agents?.goals);
|
|
20502
|
+
const record = await advertisedRecord(ctx, (b) => b.capabilities?.agents?.goals ?? b.agents?.goals);
|
|
20503
|
+
if (record === void 0) return;
|
|
20504
|
+
const advertised = !!record;
|
|
20330
20505
|
if (!advertised) {
|
|
20331
20506
|
throw new CliError(
|
|
20332
20507
|
"goals: this host does not advertise the standing-goals capability (capabilities.agents.goals is absent from /.well-known/openwop). The host is the authority \u2014 refusing to guess.",
|
|
@@ -20594,10 +20769,9 @@ function redact3(value) {
|
|
|
20594
20769
|
return redactSecrets(value, { secret: SECRET_KEY3, keep: REF_ONLY_KEY });
|
|
20595
20770
|
}
|
|
20596
20771
|
async function ensureAdvertised5(ctx) {
|
|
20597
|
-
const
|
|
20598
|
-
if (
|
|
20599
|
-
const
|
|
20600
|
-
const advertised = !!(body.capabilities?.portability ?? body.portability);
|
|
20772
|
+
const record = await advertisedRecord(ctx, (b) => b.capabilities?.portability ?? b.portability);
|
|
20773
|
+
if (record === void 0) return;
|
|
20774
|
+
const advertised = !!record;
|
|
20601
20775
|
if (!advertised) {
|
|
20602
20776
|
throw new CliError(
|
|
20603
20777
|
"portability: this host does not advertise the export/import capability (capabilities.portability is absent from /.well-known/openwop). The host is the authority \u2014 refusing to guess.",
|
|
@@ -20844,10 +21018,7 @@ function exitForState3(state) {
|
|
|
20844
21018
|
return 1;
|
|
20845
21019
|
}
|
|
20846
21020
|
async function triggerBridgeCaps(ctx) {
|
|
20847
|
-
|
|
20848
|
-
if (!wk.ok) return void 0;
|
|
20849
|
-
const body = wk.body && typeof wk.body === "object" ? wk.body : {};
|
|
20850
|
-
return body.capabilities?.triggerBridge ?? body.triggerBridge ?? null;
|
|
21021
|
+
return advertisedRecord(ctx, (b) => b.capabilities?.triggerBridge ?? b.triggerBridge);
|
|
20851
21022
|
}
|
|
20852
21023
|
async function ensureAdvertised6(ctx) {
|
|
20853
21024
|
const tb = await triggerBridgeCaps(ctx);
|
|
@@ -21107,10 +21278,7 @@ function exitForState4(state) {
|
|
|
21107
21278
|
return 1;
|
|
21108
21279
|
}
|
|
21109
21280
|
async function a2aCaps(ctx) {
|
|
21110
|
-
|
|
21111
|
-
if (!wk.ok) return void 0;
|
|
21112
|
-
const body = wk.body && typeof wk.body === "object" ? wk.body : {};
|
|
21113
|
-
return body.capabilities?.a2a ?? body.a2a ?? null;
|
|
21281
|
+
return advertisedRecord(ctx, (b) => b.capabilities?.a2a ?? b.a2a);
|
|
21114
21282
|
}
|
|
21115
21283
|
async function runStatus2(ctx, argv) {
|
|
21116
21284
|
const { options } = parseOptions(argv, { bool: ["--help"] });
|
|
@@ -21127,7 +21295,7 @@ async function runStatus2(ctx, argv) {
|
|
|
21127
21295
|
writeLine(ctx.io.stdout, "This host does not advertise A2A (capabilities.a2a absent).");
|
|
21128
21296
|
return 1;
|
|
21129
21297
|
}
|
|
21130
|
-
writeLine(ctx.io.stdout, `a2a.supported: ${a2a.supported ? "yes" : "no"}`);
|
|
21298
|
+
writeLine(ctx.io.stdout, `a2a.supported: ${a2a.supported ?? true ? "yes" : "no"}`);
|
|
21131
21299
|
if (a2a.agentCardUrl) writeLine(ctx.io.stdout, `agentCardUrl: ${a2a.agentCardUrl}`);
|
|
21132
21300
|
writeLine(ctx.io.stdout, `streaming: ${a2a.streaming ? "yes" : "no"}`);
|
|
21133
21301
|
writeLine(ctx.io.stdout, `pushNotifications: ${a2a.pushNotifications ? "yes" : "no"}`);
|
|
@@ -21316,7 +21484,7 @@ Run \`openwop docs --help\` for usage.`);
|
|
|
21316
21484
|
}
|
|
21317
21485
|
|
|
21318
21486
|
// src/cli/knowledgeSync.ts
|
|
21319
|
-
var
|
|
21487
|
+
var BASE13 = "/v1/host/openwop-app/knowledge-sync";
|
|
21320
21488
|
var KNOWLEDGE_SYNC_HELP = `Usage:
|
|
21321
21489
|
openwop knowledge-sync list --org <orgId> [--json]
|
|
21322
21490
|
openwop knowledge-sync get <sourceId> [--json]
|
|
@@ -21376,12 +21544,12 @@ async function runKnowledgeSync(ctx, argv) {
|
|
|
21376
21544
|
switch (sub) {
|
|
21377
21545
|
case "list": {
|
|
21378
21546
|
if (!options.org) return usage4(ctx, "list --org <orgId>");
|
|
21379
|
-
const res = await requestJson(ctx, withQuery(
|
|
21547
|
+
const res = await requestJson(ctx, withQuery(BASE13, { orgId: String(options.org) }));
|
|
21380
21548
|
return renderList(ctx, res.body, pickArray(res.body, "sources"), ["id", "provider", "collectionId", "cadence", "status", "lastSyncedAt"], "No sync sources.");
|
|
21381
21549
|
}
|
|
21382
21550
|
case "get": {
|
|
21383
21551
|
if (!id) return usage4(ctx, "get <sourceId>");
|
|
21384
|
-
writeJson(ctx.io.stdout, (await requestJson(ctx, `${
|
|
21552
|
+
writeJson(ctx.io.stdout, (await requestJson(ctx, `${BASE13}/${enc2(id)}`)).body);
|
|
21385
21553
|
return 0;
|
|
21386
21554
|
}
|
|
21387
21555
|
case "create": {
|
|
@@ -21397,12 +21565,12 @@ async function runKnowledgeSync(ctx, argv) {
|
|
|
21397
21565
|
if (options.cadence) body.cadence = String(options.cadence);
|
|
21398
21566
|
if (options.provider) body.provider = String(options.provider);
|
|
21399
21567
|
if (options.noMedia) body.includeMedia = false;
|
|
21400
|
-
const res = await requestJson(ctx,
|
|
21568
|
+
const res = await requestJson(ctx, BASE13, { method: "POST", body });
|
|
21401
21569
|
return renderDone(ctx, res.body, `Created sync source ${res.body?.source?.id ?? ""}.`);
|
|
21402
21570
|
}
|
|
21403
21571
|
case "browse": {
|
|
21404
21572
|
if (!options.org || !options.connection) return usage4(ctx, "browse --org <orgId> --connection <connectionId> [--folder id]");
|
|
21405
|
-
const res = await requestJson(ctx, withQuery(`${
|
|
21573
|
+
const res = await requestJson(ctx, withQuery(`${BASE13}/browse`, {
|
|
21406
21574
|
orgId: String(options.org),
|
|
21407
21575
|
connectionId: String(options.connection),
|
|
21408
21576
|
folderId: options.folder
|
|
@@ -21411,18 +21579,18 @@ async function runKnowledgeSync(ctx, argv) {
|
|
|
21411
21579
|
}
|
|
21412
21580
|
case "update": {
|
|
21413
21581
|
if (!id || !options.includeMedia && !options.noMedia) return usage4(ctx, "update <sourceId> (--include-media | --no-media)");
|
|
21414
|
-
const res = await requestJson(ctx, `${
|
|
21582
|
+
const res = await requestJson(ctx, `${BASE13}/${enc2(id)}`, { method: "PATCH", body: { includeMedia: !options.noMedia } });
|
|
21415
21583
|
return renderDone(ctx, res.body, `Updated sync source ${id} (media ${options.noMedia ? "excluded" : "included"}).`);
|
|
21416
21584
|
}
|
|
21417
21585
|
case "pause":
|
|
21418
21586
|
case "resume": {
|
|
21419
21587
|
if (!id) return usage4(ctx, `${sub} <sourceId>`);
|
|
21420
|
-
const res = await requestJson(ctx, `${
|
|
21588
|
+
const res = await requestJson(ctx, `${BASE13}/${enc2(id)}/${sub}`, { method: "POST", body: {} });
|
|
21421
21589
|
return renderDone(ctx, res.body, `${sub === "pause" ? "Paused" : "Resumed"} sync source ${id}.`);
|
|
21422
21590
|
}
|
|
21423
21591
|
case "sync": {
|
|
21424
21592
|
if (!id) return usage4(ctx, "sync <sourceId>");
|
|
21425
|
-
const res = await requestJson(ctx, `${
|
|
21593
|
+
const res = await requestJson(ctx, `${BASE13}/${enc2(id)}/sync`, { method: "POST", body: {} });
|
|
21426
21594
|
const r = res.body?.result ?? {};
|
|
21427
21595
|
const counts = Object.entries(r).filter(([, v]) => typeof v === "number").map(([k, v]) => `${k}=${v}`).join(" ");
|
|
21428
21596
|
return renderDone(ctx, res.body, `Synced source ${id}${counts ? `: ${counts}` : "."}`);
|
|
@@ -21430,7 +21598,7 @@ async function runKnowledgeSync(ctx, argv) {
|
|
|
21430
21598
|
case "delete": {
|
|
21431
21599
|
if (!id) return usage4(ctx, "delete <sourceId> [--yes]");
|
|
21432
21600
|
if (!options.yes) throw new CliError(`Refusing to delete sync source ${id} without --yes.`, 2);
|
|
21433
|
-
const res = await requestJson(ctx, `${
|
|
21601
|
+
const res = await requestJson(ctx, `${BASE13}/${enc2(id)}`, { method: "DELETE" });
|
|
21434
21602
|
return renderDone(ctx, res.body, `Deleted sync source ${id}.`);
|
|
21435
21603
|
}
|
|
21436
21604
|
default:
|
|
@@ -21442,7 +21610,7 @@ Run \`openwop knowledge-sync --help\` for usage.`);
|
|
|
21442
21610
|
// src/cli/entities.ts
|
|
21443
21611
|
import { readFileSync as readFileSync18, writeFileSync as writeFileSync14 } from "node:fs";
|
|
21444
21612
|
import { resolve as resolvePath9 } from "node:path";
|
|
21445
|
-
var
|
|
21613
|
+
var BASE14 = "/v1/host/openwop-app/entities";
|
|
21446
21614
|
var PUBLIC_BASE2 = "/v1/host/openwop-app/public-entities";
|
|
21447
21615
|
var ENTITIES_HELP = `Usage:
|
|
21448
21616
|
openwop entities locale-context [--json]
|
|
@@ -21564,7 +21732,7 @@ async function runEntities(ctx, argv) {
|
|
|
21564
21732
|
const q = (path, extra = {}) => withQuery(path, { projectId: project4, ...extra });
|
|
21565
21733
|
switch (family) {
|
|
21566
21734
|
case "locale-context": {
|
|
21567
|
-
const res = await requestJson(ctx, q(`${
|
|
21735
|
+
const res = await requestJson(ctx, q(`${BASE14}/locale-context`));
|
|
21568
21736
|
if (ctx.json) {
|
|
21569
21737
|
writeJson(ctx.io.stdout, res.body);
|
|
21570
21738
|
return 0;
|
|
@@ -21596,10 +21764,10 @@ Run \`openwop entities --help\` for usage.`);
|
|
|
21596
21764
|
}
|
|
21597
21765
|
async function types(ctx, sub, pos, o, project4, q) {
|
|
21598
21766
|
const name = pos[0];
|
|
21599
|
-
const typePath = (n) => `${
|
|
21767
|
+
const typePath = (n) => `${BASE14}/types/${enc2(n)}`;
|
|
21600
21768
|
switch (sub) {
|
|
21601
21769
|
case "list": {
|
|
21602
|
-
const res = await requestJson(ctx, q(`${
|
|
21770
|
+
const res = await requestJson(ctx, q(`${BASE14}/types`));
|
|
21603
21771
|
return renderList(
|
|
21604
21772
|
ctx,
|
|
21605
21773
|
res.body,
|
|
@@ -21623,7 +21791,7 @@ async function types(ctx, sub, pos, o, project4, q) {
|
|
|
21623
21791
|
projectId: project4
|
|
21624
21792
|
});
|
|
21625
21793
|
if (!body.name) return usage5(ctx, "types create --name <n> [--fields <json>]");
|
|
21626
|
-
const res = await requestJson(ctx, `${
|
|
21794
|
+
const res = await requestJson(ctx, `${BASE14}/types`, { method: "POST", body });
|
|
21627
21795
|
return renderDone(ctx, res.body, `Created entity type ${res.body?.name ?? body.name}.`);
|
|
21628
21796
|
}
|
|
21629
21797
|
case "update": {
|
|
@@ -21698,7 +21866,7 @@ async function types(ctx, sub, pos, o, project4, q) {
|
|
|
21698
21866
|
async function records(ctx, sub, pos, o, _project, q) {
|
|
21699
21867
|
const [type, id] = pos;
|
|
21700
21868
|
if (!type) return usage5(ctx, `${sub} <type>${sub === "list" || sub === "create" ? "" : " <entityId>"}`);
|
|
21701
|
-
const coll = `${
|
|
21869
|
+
const coll = `${BASE14}/types/${enc2(type)}/entities`;
|
|
21702
21870
|
const recordBody = () => mergeBody(ctx, o, {
|
|
21703
21871
|
values: o.values !== void 0 ? parseJsonFlag("--values", o.values) : void 0,
|
|
21704
21872
|
termIds: csv(o.termIds),
|
|
@@ -21743,7 +21911,7 @@ async function records(ctx, sub, pos, o, _project, q) {
|
|
|
21743
21911
|
async function taxonomies(ctx, sub, pos, o, project4, q) {
|
|
21744
21912
|
switch (sub) {
|
|
21745
21913
|
case "list": {
|
|
21746
|
-
const res = await requestJson(ctx, q(`${
|
|
21914
|
+
const res = await requestJson(ctx, q(`${BASE14}/taxonomies`));
|
|
21747
21915
|
return renderList(ctx, res.body, pickArray(res.body, "taxonomies"), ["name", "displayName"], "No taxonomies.");
|
|
21748
21916
|
}
|
|
21749
21917
|
case "create": {
|
|
@@ -21753,14 +21921,14 @@ async function taxonomies(ctx, sub, pos, o, project4, q) {
|
|
|
21753
21921
|
projectId: project4
|
|
21754
21922
|
});
|
|
21755
21923
|
if (!body.name) return usage5(ctx, "taxonomies create --name <n> [--display-name d]");
|
|
21756
|
-
const res = await requestJson(ctx, `${
|
|
21924
|
+
const res = await requestJson(ctx, `${BASE14}/taxonomies`, { method: "POST", body });
|
|
21757
21925
|
return renderDone(ctx, res.body, `Created taxonomy ${res.body?.name ?? body.name}.`);
|
|
21758
21926
|
}
|
|
21759
21927
|
case "delete": {
|
|
21760
21928
|
const name = pos[0];
|
|
21761
21929
|
if (!name) return usage5(ctx, "taxonomies delete <taxonomy> --yes");
|
|
21762
21930
|
confirm(o, `taxonomy ${name}`);
|
|
21763
|
-
await requestJson(ctx, q(`${
|
|
21931
|
+
await requestJson(ctx, q(`${BASE14}/taxonomies/${enc2(name)}`), { method: "DELETE" });
|
|
21764
21932
|
writeLine(ctx.io.stdout, `Deleted taxonomy ${name}.`);
|
|
21765
21933
|
return 0;
|
|
21766
21934
|
}
|
|
@@ -21771,7 +21939,7 @@ async function taxonomies(ctx, sub, pos, o, project4, q) {
|
|
|
21771
21939
|
async function terms(ctx, sub, pos, o, project4, q) {
|
|
21772
21940
|
const [tax, slug] = pos;
|
|
21773
21941
|
if (!tax) return usage5(ctx, `terms ${sub} <taxonomy>`);
|
|
21774
|
-
const coll = `${
|
|
21942
|
+
const coll = `${BASE14}/taxonomies/${enc2(tax)}/terms`;
|
|
21775
21943
|
switch (sub) {
|
|
21776
21944
|
case "list": {
|
|
21777
21945
|
const res = await requestJson(ctx, q(coll));
|
|
@@ -21823,7 +21991,7 @@ async function terms(ctx, sub, pos, o, project4, q) {
|
|
|
21823
21991
|
async function relationships(ctx, sub, pos, o, project4, q) {
|
|
21824
21992
|
switch (sub) {
|
|
21825
21993
|
case "list": {
|
|
21826
|
-
const res = await requestJson(ctx, q(`${
|
|
21994
|
+
const res = await requestJson(ctx, q(`${BASE14}/relationships`));
|
|
21827
21995
|
return renderList(ctx, res.body, pickArray(res.body, "relationships"), ["fromTypeName", "toTypeName", "cardinality", "onDelete"], "No relationships.");
|
|
21828
21996
|
}
|
|
21829
21997
|
case "create": {
|
|
@@ -21835,14 +22003,14 @@ async function relationships(ctx, sub, pos, o, project4, q) {
|
|
|
21835
22003
|
projectId: project4
|
|
21836
22004
|
});
|
|
21837
22005
|
if (!body.fromTypeName || !body.toTypeName) return usage5(ctx, "relationships create --from <type> --to <type>");
|
|
21838
|
-
const res = await requestJson(ctx, `${
|
|
22006
|
+
const res = await requestJson(ctx, `${BASE14}/relationships`, { method: "POST", body });
|
|
21839
22007
|
return renderDone(ctx, res.body, `Created relationship ${body.fromTypeName} \u2192 ${body.toTypeName}.`);
|
|
21840
22008
|
}
|
|
21841
22009
|
case "delete": {
|
|
21842
22010
|
const [from, to] = pos;
|
|
21843
22011
|
if (!from || !to) return usage5(ctx, "relationships delete <fromType> <toType> --yes");
|
|
21844
22012
|
confirm(o, `relationship ${from} \u2192 ${to}`);
|
|
21845
|
-
await requestJson(ctx, q(`${
|
|
22013
|
+
await requestJson(ctx, q(`${BASE14}/relationships/${enc2(from)}/${enc2(to)}`), { method: "DELETE" });
|
|
21846
22014
|
writeLine(ctx.io.stdout, `Deleted relationship ${from} \u2192 ${to}.`);
|
|
21847
22015
|
return 0;
|
|
21848
22016
|
}
|
|
@@ -22430,7 +22598,7 @@ Run \`openwop production --help\` for usage.`);
|
|
|
22430
22598
|
}
|
|
22431
22599
|
|
|
22432
22600
|
// src/cli/tutorials.ts
|
|
22433
|
-
var
|
|
22601
|
+
var BASE15 = "/v1/host/openwop-app/tutorials";
|
|
22434
22602
|
var TUTORIALS_HELP = `Usage:
|
|
22435
22603
|
openwop tutorials list [--json]
|
|
22436
22604
|
openwop tutorials get <slug> [--json]
|
|
@@ -22438,9 +22606,9 @@ var TUTORIALS_HELP = `Usage:
|
|
|
22438
22606
|
openwop tutorials progress set <tutorialId> --steps <id,id,...> [--json]
|
|
22439
22607
|
openwop tutorials progress clear <tutorialId> [--json]
|
|
22440
22608
|
|
|
22441
|
-
The tutorial library (GET ${
|
|
22442
|
-
\`progress\` reads YOUR saved steps (GET ${
|
|
22443
|
-
tutorial's completed steps and \`progress clear\` resets them (POST ${
|
|
22609
|
+
The tutorial library (GET ${BASE15}) and one tutorial in full (GET ${BASE15}/<slug>).
|
|
22610
|
+
\`progress\` reads YOUR saved steps (GET ${BASE15}/progress); \`progress set\` replaces a
|
|
22611
|
+
tutorial's completed steps and \`progress clear\` resets them (POST ${BASE15}/progress,
|
|
22444
22612
|
body { tutorialId, completedStepIds, mode? }). The server stamps the user \u2014 you can
|
|
22445
22613
|
only write your own progress; anonymous sessions cannot save.
|
|
22446
22614
|
|
|
@@ -22464,7 +22632,7 @@ async function runTutorials(ctx, argv) {
|
|
|
22464
22632
|
}
|
|
22465
22633
|
switch (sub) {
|
|
22466
22634
|
case "list": {
|
|
22467
|
-
const res = await requestJson(ctx,
|
|
22635
|
+
const res = await requestJson(ctx, BASE15);
|
|
22468
22636
|
const items = Array.isArray(res.body?.tutorials) ? res.body.tutorials : [];
|
|
22469
22637
|
const code2 = renderList(ctx, res.body, items, ["id", "category", "title", "source"], "No tutorials.");
|
|
22470
22638
|
if (!ctx.json && res.body?.degraded) writeLine(ctx.io.stdout, "(shipped copy \u2014 the tenant library was unreachable)");
|
|
@@ -22476,13 +22644,13 @@ async function runTutorials(ctx, argv) {
|
|
|
22476
22644
|
write(ctx.io.stderr, "Usage: openwop tutorials get <slug>\n");
|
|
22477
22645
|
return 2;
|
|
22478
22646
|
}
|
|
22479
|
-
writeJson(ctx.io.stdout, (await requestJson(ctx, `${
|
|
22647
|
+
writeJson(ctx.io.stdout, (await requestJson(ctx, `${BASE15}/${enc2(slug)}`)).body);
|
|
22480
22648
|
return 0;
|
|
22481
22649
|
}
|
|
22482
22650
|
case "progress": {
|
|
22483
22651
|
const action = positionals[0];
|
|
22484
22652
|
if (!action) {
|
|
22485
|
-
const res2 = await requestJson(ctx, `${
|
|
22653
|
+
const res2 = await requestJson(ctx, `${BASE15}/progress`);
|
|
22486
22654
|
const items = Array.isArray(res2.body?.progress) ? res2.body.progress : [];
|
|
22487
22655
|
const code2 = renderList(
|
|
22488
22656
|
ctx,
|
|
@@ -22505,7 +22673,7 @@ async function runTutorials(ctx, argv) {
|
|
|
22505
22673
|
return 2;
|
|
22506
22674
|
}
|
|
22507
22675
|
const body = action === "set" ? { tutorialId, completedStepIds: csv(options.steps) ?? [] } : { tutorialId, completedStepIds: [], mode: "clear" };
|
|
22508
|
-
const res = await requestJson(ctx, `${
|
|
22676
|
+
const res = await requestJson(ctx, `${BASE15}/progress`, { method: "POST", body });
|
|
22509
22677
|
return renderDone(ctx, res.body, action === "set" ? `Saved ${Array.isArray(res.body?.completedStepIds) ? res.body.completedStepIds.length : body.completedStepIds.length} completed step(s) for ${tutorialId}.` : `Cleared progress for ${tutorialId}.`);
|
|
22510
22678
|
}
|
|
22511
22679
|
default:
|
|
@@ -22515,16 +22683,16 @@ Run \`openwop tutorials --help\` for usage.`);
|
|
|
22515
22683
|
}
|
|
22516
22684
|
|
|
22517
22685
|
// src/cli/walkthroughs.ts
|
|
22518
|
-
var
|
|
22686
|
+
var BASE16 = "/v1/host/openwop-app/walkthroughs";
|
|
22519
22687
|
var WALKTHROUGHS_HELP = `Usage:
|
|
22520
22688
|
openwop walkthroughs progress [--json]
|
|
22521
22689
|
openwop walkthroughs progress set <walkthroughId> --status started|completed --run <runId> [--json]
|
|
22522
22690
|
openwop walkthroughs funnel <walkthroughId> [--json]
|
|
22523
22691
|
|
|
22524
|
-
\`progress\` reads your walkthrough progress (GET ${
|
|
22525
|
-
records one (POST ${
|
|
22692
|
+
\`progress\` reads your walkthrough progress (GET ${BASE16}/progress); \`progress set\`
|
|
22693
|
+
records one (POST ${BASE16}/progress, body { walkthroughId, status, runId }).
|
|
22526
22694
|
\`funnel\` shows run-status counts + where runs stalled for one walkthrough
|
|
22527
|
-
(GET ${
|
|
22695
|
+
(GET ${BASE16}/funnel?walkthroughId=\u2026) \u2014 a recent-window view over the newest runs.
|
|
22528
22696
|
|
|
22529
22697
|
Exit codes: 0 ok \xB7 2 usage / validation / feature off \xB7 4 forbidden.
|
|
22530
22698
|
|
|
@@ -22552,10 +22720,10 @@ async function runWalkthroughs(ctx, argv) {
|
|
|
22552
22720
|
write(ctx.io.stderr, "Usage: openwop walkthroughs progress set <walkthroughId> --status started|completed --run <runId>\n");
|
|
22553
22721
|
return 2;
|
|
22554
22722
|
}
|
|
22555
|
-
const res2 = await requestJson(ctx, `${
|
|
22723
|
+
const res2 = await requestJson(ctx, `${BASE16}/progress`, { method: "POST", body: { walkthroughId, status: String(options.status), runId: String(options.run) } });
|
|
22556
22724
|
return renderDone(ctx, res2.body, `Recorded ${walkthroughId} as ${String(options.status)}.`);
|
|
22557
22725
|
}
|
|
22558
|
-
const res = await requestJson(ctx, `${
|
|
22726
|
+
const res = await requestJson(ctx, `${BASE16}/progress`);
|
|
22559
22727
|
const items = Array.isArray(res.body?.progress) ? res.body.progress : [];
|
|
22560
22728
|
return renderList(ctx, res.body, items, ["walkthroughId", "status", "runId", "updatedAt"], "No walkthrough progress.");
|
|
22561
22729
|
}
|
|
@@ -22565,7 +22733,7 @@ async function runWalkthroughs(ctx, argv) {
|
|
|
22565
22733
|
write(ctx.io.stderr, "Usage: openwop walkthroughs funnel <walkthroughId>\n");
|
|
22566
22734
|
return 2;
|
|
22567
22735
|
}
|
|
22568
|
-
const res = await requestJson(ctx, withQuery(`${
|
|
22736
|
+
const res = await requestJson(ctx, withQuery(`${BASE16}/funnel`, { walkthroughId }));
|
|
22569
22737
|
if (ctx.json) {
|
|
22570
22738
|
writeJson(ctx.io.stdout, res.body);
|
|
22571
22739
|
return 0;
|
|
@@ -22586,7 +22754,7 @@ Run \`openwop walkthroughs --help\` for usage.`);
|
|
|
22586
22754
|
}
|
|
22587
22755
|
|
|
22588
22756
|
// src/cli/widgets.ts
|
|
22589
|
-
var
|
|
22757
|
+
var BASE17 = "/v1/host/openwop-app/widgets";
|
|
22590
22758
|
var WIDGETS_HELP = `Usage:
|
|
22591
22759
|
openwop widgets list [--json]
|
|
22592
22760
|
openwop widgets summary [--json]
|
|
@@ -22594,8 +22762,8 @@ var WIDGETS_HELP = `Usage:
|
|
|
22594
22762
|
openwop widgets archive <widgetId> [--json]
|
|
22595
22763
|
openwop widgets seed [--json]
|
|
22596
22764
|
|
|
22597
|
-
The reference example domain (GET/POST ${
|
|
22598
|
-
POST ${
|
|
22765
|
+
The reference example domain (GET/POST ${BASE17}, GET ${BASE17}/summary,
|
|
22766
|
+
POST ${BASE17}/<id>/archive, POST ${BASE17}/seed). Mounted only when the host sets
|
|
22599
22767
|
OPENWOP_EXAMPLE_WIDGETS_ENABLED=true. \`seed\` is idempotent (\`seeded: false\` on a
|
|
22600
22768
|
re-run). Archiving an already-archived widget is a conflict (exit 2), never a
|
|
22601
22769
|
silent success.
|
|
@@ -22621,12 +22789,12 @@ async function runWidgets(ctx, argv) {
|
|
|
22621
22789
|
try {
|
|
22622
22790
|
switch (sub) {
|
|
22623
22791
|
case "list": {
|
|
22624
|
-
const res = await requestJson(ctx,
|
|
22792
|
+
const res = await requestJson(ctx, BASE17);
|
|
22625
22793
|
const items = Array.isArray(res.body?.widgets) ? res.body.widgets : [];
|
|
22626
22794
|
return renderList(ctx, res.body, items, ["id", "name", "status"], "No widgets.");
|
|
22627
22795
|
}
|
|
22628
22796
|
case "summary": {
|
|
22629
|
-
const res = await requestJson(ctx, `${
|
|
22797
|
+
const res = await requestJson(ctx, `${BASE17}/summary`);
|
|
22630
22798
|
if (ctx.json) {
|
|
22631
22799
|
writeJson(ctx.io.stdout, res.body);
|
|
22632
22800
|
return 0;
|
|
@@ -22640,7 +22808,7 @@ async function runWidgets(ctx, argv) {
|
|
|
22640
22808
|
write(ctx.io.stderr, "widgets create needs --name.\n");
|
|
22641
22809
|
return 2;
|
|
22642
22810
|
}
|
|
22643
|
-
const res = await requestJson(ctx,
|
|
22811
|
+
const res = await requestJson(ctx, BASE17, { method: "POST", body: { name: String(options.name) } });
|
|
22644
22812
|
return renderDone(ctx, res.body, `Created widget ${res.body?.id ?? ""} (${String(options.name)}).`);
|
|
22645
22813
|
}
|
|
22646
22814
|
case "archive": {
|
|
@@ -22649,11 +22817,11 @@ async function runWidgets(ctx, argv) {
|
|
|
22649
22817
|
write(ctx.io.stderr, "Usage: openwop widgets archive <widgetId>\n");
|
|
22650
22818
|
return 2;
|
|
22651
22819
|
}
|
|
22652
|
-
const res = await requestJson(ctx, `${
|
|
22820
|
+
const res = await requestJson(ctx, `${BASE17}/${enc2(id)}/archive`, { method: "POST", body: {} });
|
|
22653
22821
|
return renderDone(ctx, res.body, `Archived widget ${id}.`);
|
|
22654
22822
|
}
|
|
22655
22823
|
case "seed": {
|
|
22656
|
-
const res = await requestJson(ctx, `${
|
|
22824
|
+
const res = await requestJson(ctx, `${BASE17}/seed`, { method: "POST", body: {} });
|
|
22657
22825
|
return renderDone(ctx, res.body, res.body?.seeded === false ? "Example widgets already seeded (no-op)." : "Seeded example widgets.");
|
|
22658
22826
|
}
|
|
22659
22827
|
default:
|
|
@@ -22673,17 +22841,17 @@ Run \`openwop widgets --help\` for usage.`);
|
|
|
22673
22841
|
}
|
|
22674
22842
|
|
|
22675
22843
|
// src/cli/uiState.ts
|
|
22676
|
-
var
|
|
22844
|
+
var BASE18 = "/v1/host/openwop-app/ui-state";
|
|
22677
22845
|
var UI_STATE_HELP = `Usage:
|
|
22678
22846
|
openwop ui-state list [--resource-type <t>] [--resource-id <id>] [--json]
|
|
22679
22847
|
openwop ui-state get <resourceType> <resourceId> <key> [--json]
|
|
22680
22848
|
openwop ui-state set <resourceType> <resourceId> <key> --value <json> [--json]
|
|
22681
22849
|
openwop ui-state delete <resourceType> <resourceId> <key>
|
|
22682
22850
|
|
|
22683
|
-
\`list\` reads your rows (GET ${
|
|
22684
|
-
key from that list. \`set\` writes one key (PUT ${
|
|
22851
|
+
\`list\` reads your rows (GET ${BASE18}?resourceType=&resourceId=); \`get\` filters one
|
|
22852
|
+
key from that list. \`set\` writes one key (PUT ${BASE18}, body { resourceType,
|
|
22685
22853
|
resourceId, key, value }); --value is parsed as JSON, falling back to a string.
|
|
22686
|
-
\`delete\` removes one key (DELETE ${
|
|
22854
|
+
\`delete\` removes one key (DELETE ${BASE18}/<type>/<id>/<key>).
|
|
22687
22855
|
|
|
22688
22856
|
Exit codes: 0 ok \xB7 2 usage / not found \xB7 4 forbidden.
|
|
22689
22857
|
|
|
@@ -22706,7 +22874,7 @@ async function runUiState(ctx, argv) {
|
|
|
22706
22874
|
const [resourceType, resourceId, key] = positionals;
|
|
22707
22875
|
switch (sub) {
|
|
22708
22876
|
case "list": {
|
|
22709
|
-
const res = await requestJson(ctx, withQuery(
|
|
22877
|
+
const res = await requestJson(ctx, withQuery(BASE18, { resourceType: options.resourceType, resourceId: options.resourceId }));
|
|
22710
22878
|
const items = Array.isArray(res.body?.items) ? res.body.items : [];
|
|
22711
22879
|
return renderList(ctx, res.body, items, ["resourceType", "resourceId", "key", "value"], "No saved UI state.");
|
|
22712
22880
|
}
|
|
@@ -22715,7 +22883,7 @@ async function runUiState(ctx, argv) {
|
|
|
22715
22883
|
write(ctx.io.stderr, "Usage: openwop ui-state get <resourceType> <resourceId> <key>\n");
|
|
22716
22884
|
return 2;
|
|
22717
22885
|
}
|
|
22718
|
-
const res = await requestJson(ctx, withQuery(
|
|
22886
|
+
const res = await requestJson(ctx, withQuery(BASE18, { resourceType, resourceId }));
|
|
22719
22887
|
const items = Array.isArray(res.body?.items) ? res.body.items : [];
|
|
22720
22888
|
const hit = items.find((i) => i?.key === key);
|
|
22721
22889
|
if (!hit) throw new CliError(`No ui-state for ${resourceType}/${resourceId}/${key}.`, 2);
|
|
@@ -22734,7 +22902,7 @@ async function runUiState(ctx, argv) {
|
|
|
22734
22902
|
} catch {
|
|
22735
22903
|
value = String(options.value);
|
|
22736
22904
|
}
|
|
22737
|
-
const res = await requestJson(ctx,
|
|
22905
|
+
const res = await requestJson(ctx, BASE18, { method: "PUT", body: { resourceType, resourceId, key, value } });
|
|
22738
22906
|
return renderDone(ctx, res.body, `Saved ${resourceType}/${resourceId}/${key}.`);
|
|
22739
22907
|
}
|
|
22740
22908
|
case "delete": {
|
|
@@ -22742,7 +22910,7 @@ async function runUiState(ctx, argv) {
|
|
|
22742
22910
|
write(ctx.io.stderr, "Usage: openwop ui-state delete <resourceType> <resourceId> <key>\n");
|
|
22743
22911
|
return 2;
|
|
22744
22912
|
}
|
|
22745
|
-
await requestJson(ctx, `${
|
|
22913
|
+
await requestJson(ctx, `${BASE18}/${enc2(resourceType)}/${enc2(resourceId)}/${enc2(key)}`, { method: "DELETE" });
|
|
22746
22914
|
writeLine(ctx.io.stdout, `Deleted ${resourceType}/${resourceId}/${key}.`);
|
|
22747
22915
|
return 0;
|
|
22748
22916
|
}
|
|
@@ -22755,8 +22923,8 @@ Run \`openwop ui-state --help\` for usage.`);
|
|
|
22755
22923
|
// src/cli/uiPlugin.ts
|
|
22756
22924
|
import { writeFileSync as writeFileSync16 } from "node:fs";
|
|
22757
22925
|
import { resolve as resolvePath11 } from "node:path";
|
|
22758
|
-
var
|
|
22759
|
-
var RPC_PRODUCT = `${
|
|
22926
|
+
var BASE19 = "/v1/host/openwop-app/ui-plugin";
|
|
22927
|
+
var RPC_PRODUCT = `${BASE19}/rpc`;
|
|
22760
22928
|
var RPC_CONFORMANCE = "/v1/host/sample/ui-plugin/rpc";
|
|
22761
22929
|
var UI_PLUGIN_HELP = `Usage:
|
|
22762
22930
|
openwop ui-plugin packs [--json]
|
|
@@ -22767,11 +22935,11 @@ var UI_PLUGIN_HELP = `Usage:
|
|
|
22767
22935
|
openwop ui-plugin rpc --body <json> | --body-file <path>
|
|
22768
22936
|
|
|
22769
22937
|
\`packs\` lists served plugins + the host's isolation mechanism + each plugin's tier
|
|
22770
|
-
(GET ${
|
|
22771
|
-
(GET ${
|
|
22772
|
-
pack's main-frame ES module (GET ${
|
|
22938
|
+
(GET ${BASE19}/packs). \`entry\` fetches a plugin's sandboxed entry bundle
|
|
22939
|
+
(GET ${BASE19}/packs/<name>/plugins/<id>/entry); \`trusted-entry\` fetches a signed
|
|
22940
|
+
pack's main-frame ES module (GET ${BASE19}/trusted/<name>/plugins/<id>/entry.mjs \u2014
|
|
22773
22941
|
404 unless the trusted-plugins toggle is on and the signature verifies).
|
|
22774
|
-
\`demo-artifact\` ensures the idempotent demo artifact (POST ${
|
|
22942
|
+
\`demo-artifact\` ensures the idempotent demo artifact (POST ${BASE19}/demo-artifact).
|
|
22775
22943
|
\`rpc\` sends one ui-plugin/1 request (POST ${RPC_PRODUCT}, body { message }); the
|
|
22776
22944
|
message is { openwop: "ui-plugin/1", type: "request", id (integer,
|
|
22777
22945
|
default 1), method, params } unless you pass a
|
|
@@ -22812,7 +22980,7 @@ async function runUiPlugin(ctx, argv) {
|
|
|
22812
22980
|
}
|
|
22813
22981
|
switch (sub) {
|
|
22814
22982
|
case "packs": {
|
|
22815
|
-
const res = await requestJson(ctx, `${
|
|
22983
|
+
const res = await requestJson(ctx, `${BASE19}/packs`);
|
|
22816
22984
|
const items = Array.isArray(res.body?.plugins) ? res.body.plugins : [];
|
|
22817
22985
|
const code2 = renderList(ctx, res.body, items, ["packName", "pluginId", "tier"], "No UI plugins served.");
|
|
22818
22986
|
if (!ctx.json && res.body?.isolation !== void 0) writeLine(ctx.io.stdout, `isolation: ${typeof res.body.isolation === "string" ? res.body.isolation : JSON.stringify(res.body.isolation)}`);
|
|
@@ -22826,7 +22994,7 @@ async function runUiPlugin(ctx, argv) {
|
|
|
22826
22994
|
`);
|
|
22827
22995
|
return 2;
|
|
22828
22996
|
}
|
|
22829
|
-
const path = sub === "entry" ? `${
|
|
22997
|
+
const path = sub === "entry" ? `${BASE19}/packs/${enc2(name)}/plugins/${enc2(pluginId)}/entry` : `${BASE19}/trusted/${enc2(name)}/plugins/${enc2(pluginId)}/entry.mjs`;
|
|
22830
22998
|
const res = await fetchRawText(ctx, path);
|
|
22831
22999
|
if (options.output) {
|
|
22832
23000
|
writeFileSync16(resolvePath11(ctx.cwd, String(options.output)), res.text);
|
|
@@ -22838,7 +23006,7 @@ async function runUiPlugin(ctx, argv) {
|
|
|
22838
23006
|
return 0;
|
|
22839
23007
|
}
|
|
22840
23008
|
case "demo-artifact": {
|
|
22841
|
-
const res = await requestJson(ctx, `${
|
|
23009
|
+
const res = await requestJson(ctx, `${BASE19}/demo-artifact`, { method: "POST", body: {} });
|
|
22842
23010
|
return renderDone(ctx, res.body, `Demo artifact ${res.body?.artifactId ?? ""} (version ${res.body?.version ?? ""}).`);
|
|
22843
23011
|
}
|
|
22844
23012
|
case "rpc": {
|
|
@@ -22868,18 +23036,18 @@ Run \`openwop ui-plugin --help\` for usage.`);
|
|
|
22868
23036
|
}
|
|
22869
23037
|
|
|
22870
23038
|
// src/cli/canvasCollab.ts
|
|
22871
|
-
var
|
|
23039
|
+
var BASE20 = "/v1/host/openwop-app/canvas-collab";
|
|
22872
23040
|
var CANVAS_COLLAB_HELP = `Usage:
|
|
22873
23041
|
openwop canvas-collab ticket <canvasId> [--json]
|
|
22874
23042
|
openwop canvas-collab claim-seed <canvasId> [--json]
|
|
22875
23043
|
openwop canvas-collab debug [--json]
|
|
22876
23044
|
|
|
22877
23045
|
\`ticket\` mints a short-lived collaboration ticket for one canvas
|
|
22878
|
-
(POST ${
|
|
23046
|
+
(POST ${BASE20}/<canvasId>/ticket) \u2014 a credential for the collaboration socket's
|
|
22879
23047
|
?ticket= parameter; it is printed once and never stored. \`claim-seed\` runs the
|
|
22880
|
-
seeder election (POST ${
|
|
23048
|
+
seeder election (POST ${BASE20}/<canvasId>/claim-seed) \u2192 { seed: true } for the one
|
|
22881
23049
|
caller that should seed a fresh room. \`debug\` lists this server instance's live
|
|
22882
|
-
rooms (GET ${
|
|
23050
|
+
rooms (GET ${BASE20}/_debug; super-admin only; lifecycle metadata, never content).
|
|
22883
23051
|
|
|
22884
23052
|
Exit codes: 0 ok \xB7 2 usage / not found (uniform) \xB7 4 forbidden (debug without super-admin).
|
|
22885
23053
|
|
|
@@ -22913,7 +23081,7 @@ async function runCanvasCollab(ctx, argv) {
|
|
|
22913
23081
|
write(ctx.io.stderr, "Usage: openwop canvas-collab ticket <canvasId>\n");
|
|
22914
23082
|
return 2;
|
|
22915
23083
|
}
|
|
22916
|
-
const res = await requestJson(ctx, `${
|
|
23084
|
+
const res = await requestJson(ctx, `${BASE20}/${enc2(id)}/ticket`, { method: "POST", body: {} });
|
|
22917
23085
|
return printTicketOnce(ctx, res.body, `canvas ${id}`);
|
|
22918
23086
|
}
|
|
22919
23087
|
case "claim-seed": {
|
|
@@ -22921,13 +23089,13 @@ async function runCanvasCollab(ctx, argv) {
|
|
|
22921
23089
|
write(ctx.io.stderr, "Usage: openwop canvas-collab claim-seed <canvasId>\n");
|
|
22922
23090
|
return 2;
|
|
22923
23091
|
}
|
|
22924
|
-
const res = await requestJson(ctx, `${
|
|
23092
|
+
const res = await requestJson(ctx, `${BASE20}/${enc2(id)}/claim-seed`, { method: "POST", body: {} });
|
|
22925
23093
|
if (ctx.json) writeJson(ctx.io.stdout, res.body);
|
|
22926
23094
|
else writeLine(ctx.io.stdout, res.body?.seed ? `You won the seed election for ${id} \u2014 seed the room.` : `Another client seeds ${id} (seed: false).`);
|
|
22927
23095
|
return 0;
|
|
22928
23096
|
}
|
|
22929
23097
|
case "debug": {
|
|
22930
|
-
const res = await requestJson(ctx, `${
|
|
23098
|
+
const res = await requestJson(ctx, `${BASE20}/_debug`);
|
|
22931
23099
|
const items = Array.isArray(res.body?.instanceRooms) ? res.body.instanceRooms : [];
|
|
22932
23100
|
return renderList(ctx, res.body, items, ["roomId", "tenantId", "clients", "openedAt"], "No live collaboration rooms on this instance.");
|
|
22933
23101
|
}
|
|
@@ -22938,14 +23106,14 @@ Run \`openwop canvas-collab --help\` for usage.`);
|
|
|
22938
23106
|
}
|
|
22939
23107
|
|
|
22940
23108
|
// src/cli/workflowCollab.ts
|
|
22941
|
-
var
|
|
23109
|
+
var BASE21 = "/v1/host/openwop-app/workflow-collab";
|
|
22942
23110
|
var WORKFLOW_COLLAB_HELP = `Usage:
|
|
22943
23111
|
openwop workflow-collab ticket <workflowId> [--json]
|
|
22944
23112
|
openwop workflow-collab claim-seed <workflowId> [--json]
|
|
22945
23113
|
|
|
22946
23114
|
\`ticket\` mints a short-lived collaboration ticket for one workflow draft
|
|
22947
|
-
(POST ${
|
|
22948
|
-
the seeder election (POST ${
|
|
23115
|
+
(POST ${BASE21}/<workflowId>/ticket) \u2014 shown once, never stored. \`claim-seed\` runs
|
|
23116
|
+
the seeder election (POST ${BASE21}/<workflowId>/claim-seed) \u2192 { seed }.
|
|
22949
23117
|
|
|
22950
23118
|
Exit codes: 0 ok \xB7 2 usage / not found / feature off \xB7 4 forbidden.
|
|
22951
23119
|
|
|
@@ -22972,11 +23140,11 @@ async function runWorkflowCollab(ctx, argv) {
|
|
|
22972
23140
|
}
|
|
22973
23141
|
switch (sub) {
|
|
22974
23142
|
case "ticket": {
|
|
22975
|
-
const res = await requestJson(ctx, `${
|
|
23143
|
+
const res = await requestJson(ctx, `${BASE21}/${enc2(id)}/ticket`, { method: "POST", body: {} });
|
|
22976
23144
|
return printTicketOnce(ctx, res.body, `workflow ${id}`);
|
|
22977
23145
|
}
|
|
22978
23146
|
case "claim-seed": {
|
|
22979
|
-
const res = await requestJson(ctx, `${
|
|
23147
|
+
const res = await requestJson(ctx, `${BASE21}/${enc2(id)}/claim-seed`, { method: "POST", body: {} });
|
|
22980
23148
|
if (ctx.json) writeJson(ctx.io.stdout, res.body);
|
|
22981
23149
|
else writeLine(ctx.io.stdout, res.body?.seed ? `You won the seed election for ${id} \u2014 seed the room.` : `Another client seeds ${id} (seed: false).`);
|
|
22982
23150
|
return 0;
|
|
@@ -23020,7 +23188,7 @@ Run \`openwop canvas-packs --help\` for usage.`);
|
|
|
23020
23188
|
}
|
|
23021
23189
|
|
|
23022
23190
|
// src/cli/present.ts
|
|
23023
|
-
var
|
|
23191
|
+
var BASE22 = "/v1/host/openwop-app/present";
|
|
23024
23192
|
var ACTIONS = ["next", "prev", "goto", "blank"];
|
|
23025
23193
|
var PRESENT_HELP = `Usage:
|
|
23026
23194
|
openwop present outline <token> [--json]
|
|
@@ -23030,11 +23198,11 @@ var PRESENT_HELP = `Usage:
|
|
|
23030
23198
|
openwop present events <token> [--max <n>] [--timeout <seconds>] [--json]
|
|
23031
23199
|
|
|
23032
23200
|
Drive a live presentation with its remote token (no API key \u2014 the token is the
|
|
23033
|
-
credential). \`outline\` reads { title, frames, current? } (GET ${
|
|
23034
|
-
\`command\` sends a navigation command (POST ${
|
|
23201
|
+
credential). \`outline\` reads { title, frames, current? } (GET ${BASE22}/<token>/outline).
|
|
23202
|
+
\`command\` sends a navigation command (POST ${BASE22}/<token>/command, body
|
|
23035
23203
|
{ action, index? }). \`state\` reports the presenter's current frame
|
|
23036
|
-
(POST ${
|
|
23037
|
-
feed (GET ${
|
|
23204
|
+
(POST ${BASE22}/<token>/state, body { current }). \`events\` follows the navigation
|
|
23205
|
+
feed (GET ${BASE22}/<token>/events, server-sent events) \u2014 one line per event, or one
|
|
23038
23206
|
JSON object per line with --json; stops after --max events or --timeout seconds.
|
|
23039
23207
|
|
|
23040
23208
|
Exit codes: 0 ok \xB7 2 usage / unknown or expired session.
|
|
@@ -23061,7 +23229,7 @@ async function runPresent(ctx, argv) {
|
|
|
23061
23229
|
`);
|
|
23062
23230
|
return 2;
|
|
23063
23231
|
}
|
|
23064
|
-
const base16 = `${
|
|
23232
|
+
const base16 = `${BASE22}/${enc2(token)}`;
|
|
23065
23233
|
switch (sub) {
|
|
23066
23234
|
case "outline": {
|
|
23067
23235
|
const res = await requestJson(ctx, `${base16}/outline`, { auth: false });
|
|
@@ -24069,8 +24237,8 @@ async function runCampaignBrief(ctx, argv) {
|
|
|
24069
24237
|
}
|
|
24070
24238
|
|
|
24071
24239
|
// src/cli/campaignConnectors.ts
|
|
24072
|
-
var
|
|
24073
|
-
var orgBase2 = (org2) => `${
|
|
24240
|
+
var BASE23 = `${APP}/campaign-connectors`;
|
|
24241
|
+
var orgBase2 = (org2) => `${BASE23}/orgs/${enc2(org2)}`;
|
|
24074
24242
|
var CAMPAIGN_CONNECTORS_HELP = `Usage:
|
|
24075
24243
|
openwop campaign-connectors platforms [--json]
|
|
24076
24244
|
openwop campaign-connectors sync --org <orgId> --platform meta|google [--json]
|
|
@@ -24119,7 +24287,7 @@ var TABLE2 = {
|
|
|
24119
24287
|
usage: "platforms [--json]",
|
|
24120
24288
|
args: 0,
|
|
24121
24289
|
run: async (ctx) => {
|
|
24122
|
-
const body = (await requestJson(ctx, `${
|
|
24290
|
+
const body = (await requestJson(ctx, `${BASE23}/platforms`)).body;
|
|
24123
24291
|
if (ctx.json) {
|
|
24124
24292
|
writeJson(ctx.io.stdout, body);
|
|
24125
24293
|
return 0;
|
|
@@ -24136,7 +24304,7 @@ var TABLE2 = {
|
|
|
24136
24304
|
requires: ["platform"],
|
|
24137
24305
|
run: async (ctx, a) => {
|
|
24138
24306
|
const req2 = assign({ ...a.body }, { orgId: orgOf(a), platform: a.options.platform });
|
|
24139
|
-
const body = (await requestJson(ctx, `${
|
|
24307
|
+
const body = (await requestJson(ctx, `${BASE23}/sync`, { method: "POST", body: req2 })).body;
|
|
24140
24308
|
return done(ctx, body, `Sync ${body?.outcome ?? "done"}${body?.imported !== void 0 ? ` (${body.imported} imported)` : ""}.`);
|
|
24141
24309
|
}
|
|
24142
24310
|
},
|
|
@@ -24149,7 +24317,7 @@ var TABLE2 = {
|
|
|
24149
24317
|
run: async (ctx, a) => {
|
|
24150
24318
|
const o = a.options;
|
|
24151
24319
|
const req2 = assign({ ...a.body }, { orgId: orgOf(a), segmentId: o.segment, adAccountId: o.adAccount, platform: o.platform, audienceName: o.audienceName });
|
|
24152
|
-
const body = (await requestJson(ctx, `${
|
|
24320
|
+
const body = (await requestJson(ctx, `${BASE23}/audience-sync`, { method: "POST", body: req2 })).body;
|
|
24153
24321
|
return done(ctx, body, `Audience sync: ${body?.outcome ?? "done"}.`);
|
|
24154
24322
|
}
|
|
24155
24323
|
},
|
|
@@ -24172,7 +24340,7 @@ var TABLE2 = {
|
|
|
24172
24340
|
writeLine(ctx.io.stderr, "openwop: missing --csv-file");
|
|
24173
24341
|
return 2;
|
|
24174
24342
|
}
|
|
24175
|
-
const body = (await requestJson(ctx, `${
|
|
24343
|
+
const body = (await requestJson(ctx, `${BASE23}/import`, { method: "POST", body: req2 })).body;
|
|
24176
24344
|
return done(ctx, body, `Imported ${body?.imported ?? 0} rows (${body?.deduped ?? 0} deduped, ${Array.isArray(body?.invalid) ? body.invalid.length : body?.invalid ?? 0} invalid).`);
|
|
24177
24345
|
}
|
|
24178
24346
|
},
|
|
@@ -24182,7 +24350,7 @@ var TABLE2 = {
|
|
|
24182
24350
|
value: ["--org", "--campaign"],
|
|
24183
24351
|
run: async (ctx, a) => listOut(
|
|
24184
24352
|
ctx,
|
|
24185
|
-
(await requestJson(ctx, `${
|
|
24353
|
+
(await requestJson(ctx, `${BASE23}/records${qs({ orgId: orgOf(a), campaignId: a.options.campaign })}`)).body,
|
|
24186
24354
|
"records",
|
|
24187
24355
|
["date", "platform", "campaignId", "impressions", "clicks", "spend", "conversions"],
|
|
24188
24356
|
"No performance records."
|
|
@@ -24192,7 +24360,7 @@ var TABLE2 = {
|
|
|
24192
24360
|
usage: "kpi --org <orgId> [--campaign <id>] [--json]",
|
|
24193
24361
|
args: 0,
|
|
24194
24362
|
value: ["--org", "--campaign"],
|
|
24195
|
-
run: async (ctx, a) => detail(ctx, (await requestJson(ctx, `${
|
|
24363
|
+
run: async (ctx, a) => detail(ctx, (await requestJson(ctx, `${BASE23}/kpi${qs({ orgId: orgOf(a), campaignId: a.options.campaign })}`)).body)
|
|
24196
24364
|
},
|
|
24197
24365
|
"sync-status": {
|
|
24198
24366
|
usage: "sync-status --org <orgId> [--json]",
|
|
@@ -24314,7 +24482,7 @@ async function runCampaignConnectors(ctx, argv) {
|
|
|
24314
24482
|
}
|
|
24315
24483
|
|
|
24316
24484
|
// src/cli/campaignIntel.ts
|
|
24317
|
-
var
|
|
24485
|
+
var BASE24 = `${APP}/campaign-intel`;
|
|
24318
24486
|
var CAMPAIGN_INTEL_HELP = `Usage:
|
|
24319
24487
|
openwop campaign-intel budget --org <orgId> [--campaign <id>] [--json]
|
|
24320
24488
|
openwop campaign-intel forecast --org <orgId> [--campaign <id>] [--json]
|
|
@@ -24353,7 +24521,7 @@ var read = (name, withCampaign) => ({
|
|
|
24353
24521
|
args: 0,
|
|
24354
24522
|
value: ["--org", ...withCampaign ? ["--campaign"] : []],
|
|
24355
24523
|
run: async (ctx, a) => {
|
|
24356
|
-
const body = (await requestJson(ctx, `${
|
|
24524
|
+
const body = (await requestJson(ctx, `${BASE24}/${name}${qs({ orgId: orgOf2(a), campaignId: withCampaign ? a.options.campaign : void 0 })}`)).body;
|
|
24357
24525
|
if (name === "anomalies") return listOut(ctx, body, "anomalies", ["date", "platform", "campaignId", "metric", "severity", "message"], "No anomalies.");
|
|
24358
24526
|
if (name === "forecast") return listOut(ctx, body, "forecasts", ["campaignId", "platform", "horizonDays", "projectedSpend", "projectedConversions"], "No forecasts (no performance records).");
|
|
24359
24527
|
return detail(ctx, body);
|
|
@@ -24388,7 +24556,7 @@ var TABLE3 = {
|
|
|
24388
24556
|
return 2;
|
|
24389
24557
|
}
|
|
24390
24558
|
}
|
|
24391
|
-
return detail(ctx, (await requestJson(ctx, `${
|
|
24559
|
+
return detail(ctx, (await requestJson(ctx, `${BASE24}/plan-budget`, { method: "POST", body: req2 })).body);
|
|
24392
24560
|
}
|
|
24393
24561
|
},
|
|
24394
24562
|
apply: {
|
|
@@ -24413,7 +24581,7 @@ var TABLE3 = {
|
|
|
24413
24581
|
dailyBudgetMinor: o.dailyBudgetMinor !== void 0 ? num(o.dailyBudgetMinor, "--daily-budget-minor") : void 0,
|
|
24414
24582
|
dryRun: dryRun ? true : void 0
|
|
24415
24583
|
});
|
|
24416
|
-
const body = (await requestJson(ctx, `${
|
|
24584
|
+
const body = (await requestJson(ctx, `${BASE24}/recommendations/apply`, { method: "POST", body: req2 })).body;
|
|
24417
24585
|
return done(ctx, body, `Budget ${dryRun ? "preview" : "update"}: ${body?.outcome ?? "done"}.`);
|
|
24418
24586
|
}
|
|
24419
24587
|
}
|
|
@@ -24473,7 +24641,7 @@ async function runCampaignJourneys(ctx, argv) {
|
|
|
24473
24641
|
}
|
|
24474
24642
|
|
|
24475
24643
|
// src/cli/cdp.ts
|
|
24476
|
-
var
|
|
24644
|
+
var BASE25 = `${APP}/cdp`;
|
|
24477
24645
|
var CDP_HELP = `Usage:
|
|
24478
24646
|
openwop cdp resolve --type <identifierType> --value <v> [--json]
|
|
24479
24647
|
openwop cdp schemas list [--json]
|
|
@@ -24520,7 +24688,7 @@ var limited = (path, key, columns, empty) => ({
|
|
|
24520
24688
|
usage: `${path === "governance-decisions" ? "governance" : path === "collected-events" ? "events" : path} [--limit <n>] [--json]`,
|
|
24521
24689
|
args: 0,
|
|
24522
24690
|
value: ["--limit"],
|
|
24523
|
-
run: async (ctx, a) => listOut(ctx, (await requestJson(ctx, `${
|
|
24691
|
+
run: async (ctx, a) => listOut(ctx, (await requestJson(ctx, `${BASE25}/${path}${qs({ limit: a.options.limit })}`)).body, key, columns, empty)
|
|
24524
24692
|
});
|
|
24525
24693
|
var TABLE5 = {
|
|
24526
24694
|
resolve: {
|
|
@@ -24528,7 +24696,7 @@ var TABLE5 = {
|
|
|
24528
24696
|
args: 0,
|
|
24529
24697
|
value: ["--type", "--value"],
|
|
24530
24698
|
requires: ["type", "value"],
|
|
24531
|
-
run: async (ctx, a) => detail(ctx, (await requestJson(ctx, `${
|
|
24699
|
+
run: async (ctx, a) => detail(ctx, (await requestJson(ctx, `${BASE25}/identity/resolve${qs({ type: a.options.type, value: a.options.value })}`)).body)
|
|
24532
24700
|
},
|
|
24533
24701
|
collect: {
|
|
24534
24702
|
usage: "collect --event-type <t> [--payload-json '{...}'] [--dedupe-key <k>] [--json]",
|
|
@@ -24543,7 +24711,7 @@ var TABLE5 = {
|
|
|
24543
24711
|
payload: o.payloadJson !== void 0 ? parseJsonFlag2(o.payloadJson, "--payload-json") : void 0,
|
|
24544
24712
|
dedupeKey: o.dedupeKey
|
|
24545
24713
|
});
|
|
24546
|
-
const body = (await requestJson(ctx, `${
|
|
24714
|
+
const body = (await requestJson(ctx, `${BASE25}/collect`, { method: "POST", body: req2 })).body;
|
|
24547
24715
|
return done(ctx, body, `Collected ${req2.eventType} event ${body?.eventId ?? body?.event?.eventId ?? ""}${body?.deduped ? " (deduplicated)" : ""}.`);
|
|
24548
24716
|
}
|
|
24549
24717
|
},
|
|
@@ -24558,7 +24726,7 @@ var TABLE5 = {
|
|
|
24558
24726
|
writeLine(ctx.io.stderr, "openwop: missing --events-json or --events-file");
|
|
24559
24727
|
return 2;
|
|
24560
24728
|
}
|
|
24561
|
-
return detail(ctx, (await requestJson(ctx, `${
|
|
24729
|
+
return detail(ctx, (await requestJson(ctx, `${BASE25}/collect/batch`, { method: "POST", body: req2 })).body);
|
|
24562
24730
|
}
|
|
24563
24731
|
},
|
|
24564
24732
|
import: {
|
|
@@ -24578,7 +24746,7 @@ var TABLE5 = {
|
|
|
24578
24746
|
writeLine(ctx.io.stderr, "openwop: missing --csv-file");
|
|
24579
24747
|
return 2;
|
|
24580
24748
|
}
|
|
24581
|
-
return detail(ctx, (await requestJson(ctx, `${
|
|
24749
|
+
return detail(ctx, (await requestJson(ctx, `${BASE25}/collect/import`, { method: "POST", body: req2 })).body);
|
|
24582
24750
|
}
|
|
24583
24751
|
},
|
|
24584
24752
|
events: limited("collected-events", "events", ["eventId", "eventType", ["at", (e) => e.at ?? e.receivedAt ?? e.createdAt], "dedupeKey"], "No collected events."),
|
|
@@ -24588,7 +24756,7 @@ var TABLE5 = {
|
|
|
24588
24756
|
usage: "audit-verify [--json]",
|
|
24589
24757
|
args: 0,
|
|
24590
24758
|
run: async (ctx) => {
|
|
24591
|
-
const body = (await requestJson(ctx, `${
|
|
24759
|
+
const body = (await requestJson(ctx, `${BASE25}/audit-chain/verify`)).body;
|
|
24592
24760
|
if (ctx.json) {
|
|
24593
24761
|
writeJson(ctx.io.stdout, body);
|
|
24594
24762
|
return body?.valid === false || body?.ok === false ? 1 : 0;
|
|
@@ -24606,7 +24774,7 @@ var SCHEMAS = {
|
|
|
24606
24774
|
args: 0,
|
|
24607
24775
|
run: async (ctx) => listOut(
|
|
24608
24776
|
ctx,
|
|
24609
|
-
(await requestJson(ctx, `${
|
|
24777
|
+
(await requestJson(ctx, `${BASE25}/event-schemas`)).body,
|
|
24610
24778
|
"schemas",
|
|
24611
24779
|
["eventType", "version", ["updatedAt", (s) => s.updatedAt ?? s.registeredAt ?? s.createdAt]],
|
|
24612
24780
|
"No event schemas registered."
|
|
@@ -24627,7 +24795,7 @@ var SCHEMAS = {
|
|
|
24627
24795
|
writeLine(ctx.io.stderr, "openwop: missing --schema-json or --schema-file");
|
|
24628
24796
|
return 2;
|
|
24629
24797
|
}
|
|
24630
|
-
const body = (await requestJson(ctx, `${
|
|
24798
|
+
const body = (await requestJson(ctx, `${BASE25}/event-schemas`, { method: "POST", body: req2 })).body;
|
|
24631
24799
|
return done(ctx, body, `Registered the ${req2.eventType} event schema${body?.version !== void 0 ? ` (version ${body.version})` : ""}.`);
|
|
24632
24800
|
}
|
|
24633
24801
|
},
|
|
@@ -24640,7 +24808,7 @@ var SCHEMAS = {
|
|
|
24640
24808
|
const req2 = assign({ ...a.body }, { payload: jsonFrom(ctx, a.options.payloadJson, a.options.payloadFile, "--payload-json", "--payload-file") });
|
|
24641
24809
|
let body;
|
|
24642
24810
|
try {
|
|
24643
|
-
body = (await requestJson(ctx, `${
|
|
24811
|
+
body = (await requestJson(ctx, `${BASE25}/event-schemas/${enc2(a.positionals[0])}/validate`, { method: "POST", body: req2 })).body;
|
|
24644
24812
|
} catch (err) {
|
|
24645
24813
|
if (!(err instanceof HttpError) || err.status !== 422) throw err;
|
|
24646
24814
|
body = err.body;
|
|
@@ -24664,7 +24832,7 @@ async function runCdp(ctx, argv) {
|
|
|
24664
24832
|
}
|
|
24665
24833
|
|
|
24666
24834
|
// src/cli/destinationSync.ts
|
|
24667
|
-
var
|
|
24835
|
+
var BASE26 = `${APP}/destination-sync/syncs`;
|
|
24668
24836
|
var DESTINATION_SYNC_HELP = `Usage:
|
|
24669
24837
|
openwop destination-sync list [--json]
|
|
24670
24838
|
openwop destination-sync get <syncId> [--json]
|
|
@@ -24698,14 +24866,14 @@ function jsonFrom2(ctx, inline, file, inlineFlag, fileFlag) {
|
|
|
24698
24866
|
if (file !== void 0) return parseJsonFlag2(readText(ctx, String(file), fileFlag), fileFlag);
|
|
24699
24867
|
return void 0;
|
|
24700
24868
|
}
|
|
24701
|
-
var item = (id) => `${
|
|
24869
|
+
var item = (id) => `${BASE26}/${enc2(id)}`;
|
|
24702
24870
|
var TABLE6 = {
|
|
24703
24871
|
list: {
|
|
24704
24872
|
usage: "list [--json]",
|
|
24705
24873
|
args: 0,
|
|
24706
24874
|
run: async (ctx) => listOut(
|
|
24707
24875
|
ctx,
|
|
24708
|
-
(await requestJson(ctx,
|
|
24876
|
+
(await requestJson(ctx, BASE26)).body,
|
|
24709
24877
|
"syncs",
|
|
24710
24878
|
[["id", (s) => s.id ?? s.syncId], "name", "destinationKind", "sourceObject", "syncMode", "cursor"],
|
|
24711
24879
|
"No destination syncs."
|
|
@@ -24733,7 +24901,7 @@ var TABLE6 = {
|
|
|
24733
24901
|
cursorField: o.cursorField,
|
|
24734
24902
|
connectionId: o.connection
|
|
24735
24903
|
});
|
|
24736
|
-
const body = (await requestJson(ctx,
|
|
24904
|
+
const body = (await requestJson(ctx, BASE26, { method: "POST", body: req2 })).body;
|
|
24737
24905
|
return done(ctx, body, `Created destination sync ${body?.id ?? body?.syncId ?? ""} (${req2.name}).`);
|
|
24738
24906
|
}
|
|
24739
24907
|
},
|
|
@@ -25563,7 +25731,7 @@ async function runPublic(ctx, argv) {
|
|
|
25563
25731
|
}
|
|
25564
25732
|
|
|
25565
25733
|
// src/cli/vault.ts
|
|
25566
|
-
var
|
|
25734
|
+
var BASE27 = "/v1/host/openwop-app/vault";
|
|
25567
25735
|
var SURFACE2 = "The secrets vault";
|
|
25568
25736
|
var VAULT_HELP = `Usage:
|
|
25569
25737
|
openwop vault list [--json]
|
|
@@ -25575,10 +25743,10 @@ The super-admin secrets vault (host extension). Every route is SUPER-ADMIN gated
|
|
|
25575
25743
|
without a super-admin principal the command fails closed with exit 4 and says how to
|
|
25576
25744
|
get one (OPENWOP_SUPERADMIN_TENANTS on the server).
|
|
25577
25745
|
|
|
25578
|
-
list GET ${
|
|
25579
|
-
set POST ${
|
|
25580
|
-
rotate POST ${
|
|
25581
|
-
delete DELETE ${
|
|
25746
|
+
list GET ${BASE27} inventory of refs (never values)
|
|
25747
|
+
set POST ${BASE27}/secrets store a new secret under a ref
|
|
25748
|
+
rotate POST ${BASE27}/secrets/:credentialRef/rotate overwrite an EXISTING secret
|
|
25749
|
+
delete DELETE ${BASE27}/secrets/:credentialRef remove (refused while the ref has live consumers unless --force)
|
|
25582
25750
|
|
|
25583
25751
|
SECRETS ARE REFS, NEVER VALUES. The value for set/rotate is read from --value-file or a
|
|
25584
25752
|
no-echo prompt (a piped line also works) \u2014 never from a command-line flag. The host's
|
|
@@ -25634,7 +25802,7 @@ async function vaultList(ctx, argv) {
|
|
|
25634
25802
|
write(ctx.io.stdout, VAULT_HELP);
|
|
25635
25803
|
return 0;
|
|
25636
25804
|
}
|
|
25637
|
-
const res = await gatedRequest(ctx,
|
|
25805
|
+
const res = await gatedRequest(ctx, BASE27, void 0, SURFACE2, "superadmin");
|
|
25638
25806
|
if (ctx.json) {
|
|
25639
25807
|
writeJson(ctx.io.stdout, res.body);
|
|
25640
25808
|
return 0;
|
|
@@ -25665,7 +25833,7 @@ async function vaultWrite(ctx, argv, verb) {
|
|
|
25665
25833
|
const scope = scopeOf(options);
|
|
25666
25834
|
const value = await readSecretInput(ctx, options, `Secret value for "${ref}"`);
|
|
25667
25835
|
const body = { value, ...scope === "host" ? { scope: "host" } : {} };
|
|
25668
|
-
const path = verb === "set" ? `${
|
|
25836
|
+
const path = verb === "set" ? `${BASE27}/secrets` : `${BASE27}/secrets/${encodeURIComponent(ref)}/rotate`;
|
|
25669
25837
|
if (verb === "set") body.credentialRef = ref;
|
|
25670
25838
|
const res = await gatedRequest(ctx, path, { method: "POST", body }, SURFACE2, "superadmin");
|
|
25671
25839
|
if (ctx.json) {
|
|
@@ -25689,7 +25857,7 @@ async function vaultDelete(ctx, argv) {
|
|
|
25689
25857
|
if (scopeOf(options) === "host") qs2.set("scope", "host");
|
|
25690
25858
|
if (options.force) qs2.set("force", "true");
|
|
25691
25859
|
const q = qs2.toString() ? `?${qs2}` : "";
|
|
25692
|
-
const res = await gatedRequest(ctx, `${
|
|
25860
|
+
const res = await gatedRequest(ctx, `${BASE27}/secrets/${encodeURIComponent(positionals[0])}${q}`, { method: "DELETE" }, SURFACE2, "superadmin");
|
|
25693
25861
|
if (ctx.json) {
|
|
25694
25862
|
writeJson(ctx.io.stdout, res.body);
|
|
25695
25863
|
return 0;
|
|
@@ -25699,27 +25867,40 @@ async function vaultDelete(ctx, argv) {
|
|
|
25699
25867
|
}
|
|
25700
25868
|
|
|
25701
25869
|
// src/cli/developerKeys.ts
|
|
25702
|
-
var
|
|
25870
|
+
var BASE28 = "/v1/host/openwop-app/developer-keys";
|
|
25703
25871
|
var SURFACE3 = "Managing developer API keys";
|
|
25704
25872
|
var DEVELOPER_KEYS_HELP = `Usage:
|
|
25705
25873
|
openwop developer-keys list [--json]
|
|
25706
25874
|
openwop developer-keys create --name <n> [--scope <s>]... [--expires-at <iso>] [--json]
|
|
25707
25875
|
openwop developer-keys revoke <keyId> --yes [--json]
|
|
25708
25876
|
|
|
25709
|
-
Developer API keys for this workspace (host extension under ${
|
|
25877
|
+
Developer API keys for this workspace (host extension under ${BASE28}). Requires an
|
|
25710
25878
|
authenticated principal (not an anonymous session); an admin or owner sees and can
|
|
25711
25879
|
revoke every key in the workspace, anyone else only their own.
|
|
25712
25880
|
|
|
25713
|
-
list GET ${
|
|
25714
|
-
create POST ${
|
|
25715
|
-
revoke DELETE ${
|
|
25881
|
+
list GET ${BASE28} keys (public fields only \u2014 never the token or its hash)
|
|
25882
|
+
create POST ${BASE28} issue a key; the token is shown ONCE
|
|
25883
|
+
revoke DELETE ${BASE28}/:keyId revoke (404 when the key is not yours / not in this workspace)
|
|
25716
25884
|
|
|
25717
25885
|
ONE-TIME SECRET: \`create\` prints the new token exactly once, on stdout, with a warning.
|
|
25718
25886
|
Store it immediately \u2014 the host keeps only a hash and cannot show it again. The CLI does
|
|
25719
25887
|
not save it anywhere.
|
|
25720
25888
|
|
|
25889
|
+
A KEY CANNOT MANAGE KEYS: openwop-app refuses \`list\`, \`create\` and \`revoke\` (403)
|
|
25890
|
+
when the CLI is itself signed in with a developer key (owk_\u2026). Create and revoke keys
|
|
25891
|
+
in the app (Access \u2192 API keys), or sign in with an operator key.
|
|
25892
|
+
|
|
25893
|
+
SCOPES ARE REQUIRED AND NARROW: openwop-app refuses a key with no --scope, and a key is
|
|
25894
|
+
limited to exactly the scopes it declares. To start a run and read it back a key needs
|
|
25895
|
+
runs:create AND runs:read; reaching the rest of the workspace (agents, memory, BYOK)
|
|
25896
|
+
needs workspace:read / workspace:write. \`--scope '*'\` is a key with your full authority.
|
|
25897
|
+
A scope the host does not know is refused by name.
|
|
25898
|
+
|
|
25899
|
+
EXPIRY: openwop-app gives a key 90 days unless --expires-at says otherwise, and refuses
|
|
25900
|
+
an expiry in the past or more than its maximum (366 days by default) away.
|
|
25901
|
+
|
|
25721
25902
|
--name <n> (create) Display name. Required.
|
|
25722
|
-
--scope <s> (create) Scope granted to the key (repeatable).
|
|
25903
|
+
--scope <s> (create) Scope granted to the key (repeatable; at least one).
|
|
25723
25904
|
--expires-at <iso> (create) Expiry timestamp.
|
|
25724
25905
|
--yes (revoke) Required confirmation.
|
|
25725
25906
|
|
|
@@ -25727,7 +25908,7 @@ Exit codes: 0 ok \xB7 2 usage / not found \xB7 4 not signed in.
|
|
|
25727
25908
|
|
|
25728
25909
|
Examples:
|
|
25729
25910
|
openwop developer-keys list
|
|
25730
|
-
openwop developer-keys create --name "CI deploy" --scope runs:
|
|
25911
|
+
openwop developer-keys create --name "CI deploy" --scope runs:create --scope runs:read
|
|
25731
25912
|
openwop developer-keys revoke dk:0123abcd --yes
|
|
25732
25913
|
`;
|
|
25733
25914
|
async function runDeveloperKeys(ctx, argv) {
|
|
@@ -25756,7 +25937,7 @@ async function keysList(ctx, argv) {
|
|
|
25756
25937
|
write(ctx.io.stdout, DEVELOPER_KEYS_HELP);
|
|
25757
25938
|
return 0;
|
|
25758
25939
|
}
|
|
25759
|
-
const res = await gatedRequest(ctx,
|
|
25940
|
+
const res = await gatedRequest(ctx, BASE28, void 0, SURFACE3, "signed-in");
|
|
25760
25941
|
if (ctx.json) {
|
|
25761
25942
|
writeJson(ctx.io.stdout, res.body);
|
|
25762
25943
|
return 0;
|
|
@@ -25785,7 +25966,7 @@ async function keysCreate(ctx, argv) {
|
|
|
25785
25966
|
const body = { name: options.name };
|
|
25786
25967
|
if (Array.isArray(options.scope) && options.scope.length) body.scopes = options.scope;
|
|
25787
25968
|
if (options.expiresAt) body.expiresAt = options.expiresAt;
|
|
25788
|
-
const res = await gatedRequest(ctx,
|
|
25969
|
+
const res = await gatedRequest(ctx, BASE28, { method: "POST", body }, SURFACE3, "signed-in");
|
|
25789
25970
|
writeLine(ctx.io.stderr, "WARNING: this token is shown ONCE. Store it now \u2014 it cannot be retrieved again.");
|
|
25790
25971
|
if (ctx.json) {
|
|
25791
25972
|
writeJson(ctx.io.stdout, res.body);
|
|
@@ -25806,7 +25987,7 @@ async function keysRevoke(ctx, argv) {
|
|
|
25806
25987
|
writeLine(ctx.io.stderr, `Refusing to revoke ${positionals[0]} without --yes.`);
|
|
25807
25988
|
return 2;
|
|
25808
25989
|
}
|
|
25809
|
-
await gatedRequest(ctx, `${
|
|
25990
|
+
await gatedRequest(ctx, `${BASE28}/${encodeURIComponent(positionals[0])}`, { method: "DELETE" }, SURFACE3, "signed-in");
|
|
25810
25991
|
if (ctx.json) {
|
|
25811
25992
|
writeJson(ctx.io.stdout, { keyId: positionals[0], revoked: true });
|
|
25812
25993
|
return 0;
|
|
@@ -25875,44 +26056,44 @@ Run \`openwop custom-domains --help\` for usage.`);
|
|
|
25875
26056
|
})), ["hostname", "status", "verifiedAt", "lastError"]));
|
|
25876
26057
|
return 0;
|
|
25877
26058
|
}
|
|
25878
|
-
const
|
|
25879
|
-
if (!
|
|
26059
|
+
const hostname2 = positionals[0];
|
|
26060
|
+
if (!hostname2) throw new CliError(`Usage: openwop custom-domains ${sub} <hostname> --org <orgId>`, 2);
|
|
25880
26061
|
if (sub === "add") {
|
|
25881
|
-
const res2 = await requestJson(ctx, base14(orgId), { method: "POST", body: { hostname } });
|
|
26062
|
+
const res2 = await requestJson(ctx, base14(orgId), { method: "POST", body: { hostname: hostname2 } });
|
|
25882
26063
|
if (ctx.json) {
|
|
25883
26064
|
writeJson(ctx.io.stdout, res2.body);
|
|
25884
26065
|
return 0;
|
|
25885
26066
|
}
|
|
25886
26067
|
const d = res2.body?.domain ?? {};
|
|
25887
|
-
writeLine(ctx.io.stdout, `Added ${d.hostname ??
|
|
25888
|
-
writeLine(ctx.io.stdout, `Publish TXT _openwop-verify.${d.hostname ??
|
|
26068
|
+
writeLine(ctx.io.stdout, `Added ${d.hostname ?? hostname2} (status ${d.status ?? "pending"}).`);
|
|
26069
|
+
writeLine(ctx.io.stdout, `Publish TXT _openwop-verify.${d.hostname ?? hostname2} = ${d.verificationToken ?? "(see --json)"} then run \`openwop custom-domains verify ${d.hostname ?? hostname2} --org ${orgId}\`.`);
|
|
25889
26070
|
return 0;
|
|
25890
26071
|
}
|
|
25891
26072
|
if (sub === "verify") {
|
|
25892
|
-
const res2 = await requestJson(ctx, `${base14(orgId)}/${encodeURIComponent(
|
|
26073
|
+
const res2 = await requestJson(ctx, `${base14(orgId)}/${encodeURIComponent(hostname2)}/verify`, { method: "POST", body: {} });
|
|
25893
26074
|
if (ctx.json) {
|
|
25894
26075
|
writeJson(ctx.io.stdout, res2.body);
|
|
25895
26076
|
return 0;
|
|
25896
26077
|
}
|
|
25897
26078
|
const d = res2.body?.domain ?? {};
|
|
25898
|
-
writeLine(ctx.io.stdout, `${d.hostname ??
|
|
26079
|
+
writeLine(ctx.io.stdout, `${d.hostname ?? hostname2}: ${d.status ?? "?"}${d.lastError ? ` \u2014 ${d.lastError}` : ""}`);
|
|
25899
26080
|
return d.status === "live" ? 0 : 3;
|
|
25900
26081
|
}
|
|
25901
26082
|
if (!options.yes) {
|
|
25902
|
-
writeLine(ctx.io.stderr, `Refusing to remove ${
|
|
26083
|
+
writeLine(ctx.io.stderr, `Refusing to remove ${hostname2} without --yes.`);
|
|
25903
26084
|
return 2;
|
|
25904
26085
|
}
|
|
25905
|
-
const res = await requestJson(ctx, `${base14(orgId)}/${encodeURIComponent(
|
|
26086
|
+
const res = await requestJson(ctx, `${base14(orgId)}/${encodeURIComponent(hostname2)}`, { method: "DELETE" });
|
|
25906
26087
|
if (ctx.json) {
|
|
25907
26088
|
writeJson(ctx.io.stdout, res.body);
|
|
25908
26089
|
return 0;
|
|
25909
26090
|
}
|
|
25910
|
-
writeLine(ctx.io.stdout, `Removed ${
|
|
26091
|
+
writeLine(ctx.io.stdout, `Removed ${hostname2}.`);
|
|
25911
26092
|
return 0;
|
|
25912
26093
|
}
|
|
25913
26094
|
|
|
25914
26095
|
// src/cli/environments.ts
|
|
25915
|
-
var
|
|
26096
|
+
var BASE29 = "/v1/host/openwop-app/environments";
|
|
25916
26097
|
var PROTECTION = ["open", "protected", "locked"];
|
|
25917
26098
|
var ENVIRONMENTS_HELP = `Usage:
|
|
25918
26099
|
openwop environments list [--drift] [--json]
|
|
@@ -25929,21 +26110,21 @@ var ENVIRONMENTS_HELP = `Usage:
|
|
|
25929
26110
|
openwop environments apply --snapshot <hash> [--json]
|
|
25930
26111
|
openwop environments promotions [--json]
|
|
25931
26112
|
|
|
25932
|
-
Config environments + promotion (host extension under ${
|
|
26113
|
+
Config environments + promotion (host extension under ${BASE29}; toggle 'environments').
|
|
25933
26114
|
Reads need workspace:read; every write needs host:members:manage in the workspace.
|
|
25934
26115
|
|
|
25935
|
-
list GET ${
|
|
25936
|
-
create POST ${
|
|
25937
|
-
ensure-chain POST ${
|
|
25938
|
-
protect PATCH ${
|
|
25939
|
-
settings GET/PATCH ${
|
|
25940
|
-
snapshots GET ${
|
|
25941
|
-
snapshot POST ${
|
|
25942
|
-
preview POST ${
|
|
25943
|
-
promote POST ${
|
|
25944
|
-
rollback POST ${
|
|
25945
|
-
apply POST ${
|
|
25946
|
-
promotions GET ${
|
|
26116
|
+
list GET ${BASE29}[?drift=1] environments, config domains, app version
|
|
26117
|
+
create POST ${BASE29} add an environment to the chain
|
|
26118
|
+
ensure-chain POST ${BASE29}/ensure-chain create the default dev \u2192 staging \u2192 prod chain
|
|
26119
|
+
protect PATCH ${BASE29}/:name/protection set open | protected | locked
|
|
26120
|
+
settings GET/PATCH ${BASE29}/settings the promotion-approval gate
|
|
26121
|
+
snapshots GET ${BASE29}/snapshots stored config snapshots
|
|
26122
|
+
snapshot POST ${BASE29}/snapshots snapshot the current live config
|
|
26123
|
+
preview POST ${BASE29}/preview diff a snapshot against an environment (no change)
|
|
26124
|
+
promote POST ${BASE29}/promote promote an env's snapshot to the next (or --to) env
|
|
26125
|
+
rollback POST ${BASE29}/rollback point an env back at a historical snapshot
|
|
26126
|
+
apply POST ${BASE29}/apply apply a snapshot to the live config
|
|
26127
|
+
promotions GET ${BASE29}/promotions the promotion ledger
|
|
25947
26128
|
|
|
25948
26129
|
Exit codes: 0 ok \xB7 3 queued for approval (202 pending_approval) \xB7 2 usage / not found /
|
|
25949
26130
|
feature off \xB7 4 permission denied.
|
|
@@ -25976,7 +26157,7 @@ async function runEnvironments(ctx, argv) {
|
|
|
25976
26157
|
};
|
|
25977
26158
|
switch (sub) {
|
|
25978
26159
|
case "list": {
|
|
25979
|
-
const res = await requestJson(ctx, `${
|
|
26160
|
+
const res = await requestJson(ctx, `${BASE29}${options.drift ? "?drift=1" : ""}`);
|
|
25980
26161
|
emit2(res.body, () => {
|
|
25981
26162
|
const envs = arrayOf(res.body, "environments");
|
|
25982
26163
|
if (envs.length === 0) {
|
|
@@ -26003,35 +26184,35 @@ async function runEnvironments(ctx, argv) {
|
|
|
26003
26184
|
body.order = n;
|
|
26004
26185
|
}
|
|
26005
26186
|
if (options.protection !== void 0) body.protection = protectionOf(options.protection);
|
|
26006
|
-
const res = await requestJson(ctx,
|
|
26187
|
+
const res = await requestJson(ctx, BASE29, { method: "POST", body });
|
|
26007
26188
|
emit2(res.body, () => writeLine(ctx.io.stdout, `Created environment ${res.body?.name ?? name} (order ${res.body?.order ?? "?"}, ${res.body?.protection ?? "?"}).`));
|
|
26008
26189
|
return 0;
|
|
26009
26190
|
}
|
|
26010
26191
|
case "ensure-chain": {
|
|
26011
|
-
const res = await requestJson(ctx, `${
|
|
26192
|
+
const res = await requestJson(ctx, `${BASE29}/ensure-chain`, { method: "POST", body: {} });
|
|
26012
26193
|
emit2(res.body, () => writeLine(ctx.io.stdout, `Chain: ${arrayOf(res.body, "environments").map((e) => e.name).join(" \u2192 ")}`));
|
|
26013
26194
|
return 0;
|
|
26014
26195
|
}
|
|
26015
26196
|
case "protect": {
|
|
26016
26197
|
const name = positionals[0];
|
|
26017
26198
|
if (!name || options.protection === void 0) throw new CliError("Usage: openwop environments protect <name> --protection open|protected|locked", 2);
|
|
26018
|
-
const res = await requestJson(ctx, `${
|
|
26199
|
+
const res = await requestJson(ctx, `${BASE29}/${encodeURIComponent(name)}/protection`, { method: "PATCH", body: { protection: protectionOf(options.protection) } });
|
|
26019
26200
|
emit2(res.body, () => writeLine(ctx.io.stdout, `${name} is now ${res.body?.protection ?? options.protection}.`));
|
|
26020
26201
|
return 0;
|
|
26021
26202
|
}
|
|
26022
26203
|
case "settings": {
|
|
26023
26204
|
if (positionals[0] === "set") {
|
|
26024
26205
|
if (options.requireApproval === void 0) throw new CliError("Usage: openwop environments settings set --require-approval true|false", 2);
|
|
26025
|
-
const res2 = await requestJson(ctx, `${
|
|
26206
|
+
const res2 = await requestJson(ctx, `${BASE29}/settings`, { method: "PATCH", body: { requireApprovalForPromotion: parseBool("--require-approval", options.requireApproval) } });
|
|
26026
26207
|
emit2(res2.body, () => writeLine(ctx.io.stdout, `requireApprovalForPromotion: ${res2.body?.requireApprovalForPromotion}`));
|
|
26027
26208
|
return 0;
|
|
26028
26209
|
}
|
|
26029
|
-
const res = await requestJson(ctx, `${
|
|
26210
|
+
const res = await requestJson(ctx, `${BASE29}/settings`);
|
|
26030
26211
|
emit2(res.body, () => writeLine(ctx.io.stdout, `requireApprovalForPromotion: ${res.body?.requireApprovalForPromotion ?? false}`));
|
|
26031
26212
|
return 0;
|
|
26032
26213
|
}
|
|
26033
26214
|
case "snapshots": {
|
|
26034
|
-
const res = await requestJson(ctx, `${
|
|
26215
|
+
const res = await requestJson(ctx, `${BASE29}/snapshots`);
|
|
26035
26216
|
emit2(res.body, () => {
|
|
26036
26217
|
const snaps = arrayOf(res.body, "snapshots");
|
|
26037
26218
|
if (snaps.length === 0) {
|
|
@@ -26051,13 +26232,13 @@ async function runEnvironments(ctx, argv) {
|
|
|
26051
26232
|
case "snapshot": {
|
|
26052
26233
|
const body = {};
|
|
26053
26234
|
if (options.sourceEnv) body.sourceEnv = options.sourceEnv;
|
|
26054
|
-
const res = await requestJson(ctx, `${
|
|
26235
|
+
const res = await requestJson(ctx, `${BASE29}/snapshots`, { method: "POST", body });
|
|
26055
26236
|
emit2(res.body, () => writeLine(ctx.io.stdout, `Snapshot ${res.body?.hash ?? "?"}${res.body?.sourceEnv ? ` (from ${res.body.sourceEnv})` : ""}.`));
|
|
26056
26237
|
return 0;
|
|
26057
26238
|
}
|
|
26058
26239
|
case "preview": {
|
|
26059
26240
|
if (!options.to || !options.snapshot) throw new CliError("Usage: openwop environments preview --to <env> --snapshot <hash>", 2);
|
|
26060
|
-
const res = await requestJson(ctx, `${
|
|
26241
|
+
const res = await requestJson(ctx, `${BASE29}/preview`, { method: "POST", body: { toEnv: options.to, snapshotHash: options.snapshot } });
|
|
26061
26242
|
writeJson(ctx.io.stdout, res.body);
|
|
26062
26243
|
return 0;
|
|
26063
26244
|
}
|
|
@@ -26065,18 +26246,18 @@ async function runEnvironments(ctx, argv) {
|
|
|
26065
26246
|
if (!options.from) throw new CliError("Usage: openwop environments promote --from <env> [--to <env>]", 2);
|
|
26066
26247
|
const body = { fromEnv: options.from };
|
|
26067
26248
|
if (options.to) body.toEnv = options.to;
|
|
26068
|
-
return movement(ctx, await requestJson(ctx, `${
|
|
26249
|
+
return movement(ctx, await requestJson(ctx, `${BASE29}/promote`, { method: "POST", body }), "Promoted");
|
|
26069
26250
|
}
|
|
26070
26251
|
case "rollback": {
|
|
26071
26252
|
if (!options.env || !options.snapshot) throw new CliError("Usage: openwop environments rollback --env <env> --snapshot <hash>", 2);
|
|
26072
|
-
return movement(ctx, await requestJson(ctx, `${
|
|
26253
|
+
return movement(ctx, await requestJson(ctx, `${BASE29}/rollback`, { method: "POST", body: { env: options.env, snapshotHash: options.snapshot } }), "Rolled back");
|
|
26073
26254
|
}
|
|
26074
26255
|
case "apply": {
|
|
26075
26256
|
if (!options.snapshot) throw new CliError("Usage: openwop environments apply --snapshot <hash>", 2);
|
|
26076
|
-
return movement(ctx, await requestJson(ctx, `${
|
|
26257
|
+
return movement(ctx, await requestJson(ctx, `${BASE29}/apply`, { method: "POST", body: { snapshotHash: options.snapshot } }), "Applied");
|
|
26077
26258
|
}
|
|
26078
26259
|
case "promotions": {
|
|
26079
|
-
const res = await requestJson(ctx, `${
|
|
26260
|
+
const res = await requestJson(ctx, `${BASE29}/promotions`);
|
|
26080
26261
|
emit2(res.body, () => {
|
|
26081
26262
|
const rows = arrayOf(res.body, "promotions");
|
|
26082
26263
|
if (rows.length === 0) {
|
|
@@ -26121,7 +26302,7 @@ function movement(ctx, res, verb) {
|
|
|
26121
26302
|
}
|
|
26122
26303
|
|
|
26123
26304
|
// src/cli/billing.ts
|
|
26124
|
-
var
|
|
26305
|
+
var BASE30 = "/v1/host/openwop-app/billing";
|
|
26125
26306
|
var BILLING_HELP = `Usage:
|
|
26126
26307
|
openwop billing subscription [--json]
|
|
26127
26308
|
openwop billing balance [--json]
|
|
@@ -26139,7 +26320,7 @@ var BILLING_HELP = `Usage:
|
|
|
26139
26320
|
openwop billing sync-seats [--json]
|
|
26140
26321
|
openwop billing import (--body <json> | --body-file <path>) [--json]
|
|
26141
26322
|
|
|
26142
|
-
Workspace billing (host extension under ${
|
|
26323
|
+
Workspace billing (host extension under ${BASE30}; toggle 'billing').
|
|
26143
26324
|
subscription GET /subscription plan tier, status, seats, period
|
|
26144
26325
|
balance GET /balance purchased token balance
|
|
26145
26326
|
entitlements GET /entitlements the plan's allowed features + limits
|
|
@@ -26186,7 +26367,7 @@ async function runBilling(ctx, argv) {
|
|
|
26186
26367
|
const superadmin = (path, body, surface) => gatedRequest(ctx, path, { method: "POST", body }, surface, "superadmin");
|
|
26187
26368
|
switch (sub) {
|
|
26188
26369
|
case "subscription": {
|
|
26189
|
-
const res = await requestJson(ctx, `${
|
|
26370
|
+
const res = await requestJson(ctx, `${BASE30}/subscription`);
|
|
26190
26371
|
emit2(res.body, () => {
|
|
26191
26372
|
const s = res.body ?? {};
|
|
26192
26373
|
writeLine(ctx.io.stdout, `plan: ${s.planTier ?? "?"} (${s.status ?? "?"})`);
|
|
@@ -26197,12 +26378,12 @@ async function runBilling(ctx, argv) {
|
|
|
26197
26378
|
return 0;
|
|
26198
26379
|
}
|
|
26199
26380
|
case "balance": {
|
|
26200
|
-
const res = await requestJson(ctx, `${
|
|
26381
|
+
const res = await requestJson(ctx, `${BASE30}/balance`);
|
|
26201
26382
|
emit2(res.body, () => writeLine(ctx.io.stdout, `tokens available: ${res.body?.totalAvailable ?? 0} (purchased total ${res.body?.purchasedTokensTotal ?? 0})`));
|
|
26202
26383
|
return 0;
|
|
26203
26384
|
}
|
|
26204
26385
|
case "entitlements": {
|
|
26205
|
-
const res = await requestJson(ctx, `${
|
|
26386
|
+
const res = await requestJson(ctx, `${BASE30}/entitlements`);
|
|
26206
26387
|
emit2(res.body, () => {
|
|
26207
26388
|
const e = res.body ?? {};
|
|
26208
26389
|
writeLine(ctx.io.stdout, `plan: ${e.plan ?? "?"}`);
|
|
@@ -26213,7 +26394,7 @@ async function runBilling(ctx, argv) {
|
|
|
26213
26394
|
return 0;
|
|
26214
26395
|
}
|
|
26215
26396
|
case "bundles": {
|
|
26216
|
-
const res = await requestJson(ctx, `${
|
|
26397
|
+
const res = await requestJson(ctx, `${BASE30}/bundles`);
|
|
26217
26398
|
emit2(res.body, () => {
|
|
26218
26399
|
const rows = arrayOf(res.body, "bundles");
|
|
26219
26400
|
if (rows.length === 0) {
|
|
@@ -26233,19 +26414,19 @@ async function runBilling(ctx, argv) {
|
|
|
26233
26414
|
const verb = positionals[0] ?? "list";
|
|
26234
26415
|
if (verb === "get") {
|
|
26235
26416
|
if (!positionals[1]) throw new CliError("Usage: openwop billing invoices get <invoiceId>", 2);
|
|
26236
|
-
const res2 = await requestJson(ctx, `${
|
|
26417
|
+
const res2 = await requestJson(ctx, `${BASE30}/invoices/${encodeURIComponent(positionals[1])}`);
|
|
26237
26418
|
emit2(res2.body, () => writeLine(ctx.io.stdout, res2.body?.markdown ?? JSON.stringify(res2.body, null, 2)));
|
|
26238
26419
|
return 0;
|
|
26239
26420
|
}
|
|
26240
26421
|
if (verb === "create") {
|
|
26241
26422
|
const amount = Number(options.amount);
|
|
26242
26423
|
if (options.amount === void 0 || !Number.isFinite(amount)) throw new CliError("Usage: openwop billing invoices create --amount <n> [--currency <c>]", 2);
|
|
26243
|
-
const res2 = await superadmin(`${
|
|
26424
|
+
const res2 = await superadmin(`${BASE30}/invoices`, { amount, ...options.currency ? { currency: options.currency } : {} }, "Generating an invoice");
|
|
26244
26425
|
emit2(res2.body, () => writeLine(ctx.io.stdout, `Created invoice ${res2.body?.invoiceId ?? "?"} (${res2.body?.amount} ${res2.body?.currency}).`));
|
|
26245
26426
|
return 0;
|
|
26246
26427
|
}
|
|
26247
26428
|
if (verb !== "list") throw new CliError(`Unknown invoices verb: ${verb}`, 2);
|
|
26248
|
-
const res = await requestJson(ctx, `${
|
|
26429
|
+
const res = await requestJson(ctx, `${BASE30}/invoices`);
|
|
26249
26430
|
emit2(res.body, () => {
|
|
26250
26431
|
const rows = arrayOf(res.body, "invoices");
|
|
26251
26432
|
if (rows.length === 0) {
|
|
@@ -26263,18 +26444,18 @@ async function runBilling(ctx, argv) {
|
|
|
26263
26444
|
}
|
|
26264
26445
|
case "checkout": {
|
|
26265
26446
|
if (!options.price) throw new CliError("Usage: openwop billing checkout --price <priceId>", 2);
|
|
26266
|
-
const res = await requestJson(ctx, `${
|
|
26447
|
+
const res = await requestJson(ctx, `${BASE30}/checkout`, { method: "POST", body: { priceId: options.price } });
|
|
26267
26448
|
emit2(res.body, () => writeLine(ctx.io.stdout, `Open to complete checkout (${res.body?.mode ?? "?"}): ${res.body?.url ?? "?"}`));
|
|
26268
26449
|
return 0;
|
|
26269
26450
|
}
|
|
26270
26451
|
case "bundle-checkout": {
|
|
26271
26452
|
if (!positionals[0]) throw new CliError("Usage: openwop billing bundle-checkout <bundleId>", 2);
|
|
26272
|
-
const res = await requestJson(ctx, `${
|
|
26453
|
+
const res = await requestJson(ctx, `${BASE30}/bundles/${encodeURIComponent(positionals[0])}/checkout`, { method: "POST", body: {} });
|
|
26273
26454
|
emit2(res.body, () => writeLine(ctx.io.stdout, `Open to complete checkout (${res.body?.mode ?? "?"}): ${res.body?.url ?? "?"}`));
|
|
26274
26455
|
return 0;
|
|
26275
26456
|
}
|
|
26276
26457
|
case "portal": {
|
|
26277
|
-
const res = await requestJson(ctx, `${
|
|
26458
|
+
const res = await requestJson(ctx, `${BASE30}/portal`, { method: "POST", body: {} });
|
|
26278
26459
|
emit2(res.body, () => writeLine(ctx.io.stdout, `Billing portal (${res.body?.mode ?? "?"}): ${res.body?.url ?? "?"}`));
|
|
26279
26460
|
return 0;
|
|
26280
26461
|
}
|
|
@@ -26287,19 +26468,19 @@ async function runBilling(ctx, argv) {
|
|
|
26287
26468
|
if (!Number.isFinite(v)) throw new CliError("--value must be a number.", 2);
|
|
26288
26469
|
body.value = v;
|
|
26289
26470
|
}
|
|
26290
|
-
const res = await superadmin(`${
|
|
26471
|
+
const res = await superadmin(`${BASE30}/coupons`, body, "Creating a billing coupon");
|
|
26291
26472
|
emit2(res.body, () => writeLine(ctx.io.stdout, `Created coupon ${res.body?.code ?? options.code} (${res.body?.type} ${res.body?.value}).`));
|
|
26292
26473
|
return 0;
|
|
26293
26474
|
}
|
|
26294
26475
|
case "sync-seats": {
|
|
26295
|
-
const res = await superadmin(`${
|
|
26476
|
+
const res = await superadmin(`${BASE30}/sync-seats`, {}, "Billing seat sync");
|
|
26296
26477
|
emit2(res.body, () => writeLine(ctx.io.stdout, `Seats synced: ${res.body?.quantity ?? "?"}.`));
|
|
26297
26478
|
return 0;
|
|
26298
26479
|
}
|
|
26299
26480
|
case "import": {
|
|
26300
26481
|
const body = readBodyOption(ctx, options);
|
|
26301
26482
|
if (!body) throw new CliError('Usage: openwop billing import (--body <json> | --body-file <path>) \u2014 {"subscriptions":[...],"balances":[...]}', 2);
|
|
26302
|
-
const res = await superadmin(`${
|
|
26483
|
+
const res = await superadmin(`${BASE30}/import`, body, "Billing import");
|
|
26303
26484
|
emit2(res.body, () => writeLine(ctx.io.stdout, `Imported ${res.body?.subscriptions ?? 0} subscription(s), ${res.body?.balances ?? 0} balance(s).`));
|
|
26304
26485
|
return 0;
|
|
26305
26486
|
}
|
|
@@ -26370,15 +26551,15 @@ Run \`openwop site-config --help\` for usage.`);
|
|
|
26370
26551
|
}
|
|
26371
26552
|
|
|
26372
26553
|
// src/cli/runtimePosture.ts
|
|
26373
|
-
var
|
|
26554
|
+
var BASE31 = "/v1/host/openwop-app/runtime-posture";
|
|
26374
26555
|
var SURFACE5 = "Runtime posture";
|
|
26375
26556
|
var RUNTIME_POSTURE_HELP = `Usage:
|
|
26376
26557
|
openwop runtime-posture [get] [--json]
|
|
26377
26558
|
openwop runtime-posture request --warm|--cold [--json]
|
|
26378
26559
|
|
|
26379
26560
|
The serving service's runtime posture (host extension, SUPER-ADMIN gated).
|
|
26380
|
-
get GET ${
|
|
26381
|
-
request POST ${
|
|
26561
|
+
get GET ${BASE31} live posture (serving revision, warm/cold, rollout)
|
|
26562
|
+
request POST ${BASE31}/change-requests ask for a warm/cold change; returns the commands to run
|
|
26382
26563
|
|
|
26383
26564
|
A change request APPLIES NOTHING: the host records it in the audit log and returns the
|
|
26384
26565
|
exact commands for an operator holding deploy rights. Without a super-admin principal
|
|
@@ -26402,7 +26583,7 @@ async function runRuntimePosture(ctx, argv) {
|
|
|
26402
26583
|
return 0;
|
|
26403
26584
|
}
|
|
26404
26585
|
if (sub === "get") {
|
|
26405
|
-
const res2 = await gatedRequest(ctx,
|
|
26586
|
+
const res2 = await gatedRequest(ctx, BASE31, void 0, SURFACE5, "superadmin");
|
|
26406
26587
|
if (ctx.json) {
|
|
26407
26588
|
writeJson(ctx.io.stdout, res2.body);
|
|
26408
26589
|
return 0;
|
|
@@ -26421,7 +26602,7 @@ async function runRuntimePosture(ctx, argv) {
|
|
|
26421
26602
|
if (sub !== "request") throw new CliError(`Unknown runtime-posture command: ${sub}
|
|
26422
26603
|
Run \`openwop runtime-posture --help\` for usage.`);
|
|
26423
26604
|
if (Boolean(options.warm) === Boolean(options.cold)) throw new CliError("Pass exactly one of --warm or --cold.", 2);
|
|
26424
|
-
const res = await gatedRequest(ctx, `${
|
|
26605
|
+
const res = await gatedRequest(ctx, `${BASE31}/change-requests`, { method: "POST", body: { warm: Boolean(options.warm) } }, SURFACE5, "superadmin");
|
|
26425
26606
|
if (ctx.json) {
|
|
26426
26607
|
writeJson(ctx.io.stdout, res.body);
|
|
26427
26608
|
return 0;
|
|
@@ -26476,16 +26657,16 @@ Run \`openwop maintenance --help\` for usage.`);
|
|
|
26476
26657
|
}
|
|
26477
26658
|
|
|
26478
26659
|
// src/cli/menuConfig.ts
|
|
26479
|
-
var
|
|
26660
|
+
var BASE32 = "/v1/host/openwop-app/menu-config";
|
|
26480
26661
|
var MENU_CONFIG_HELP = `Usage:
|
|
26481
26662
|
openwop menu-config [get] [--json]
|
|
26482
26663
|
openwop menu-config set me (--body <json> | --body-file <path>) [--json]
|
|
26483
26664
|
openwop menu-config set tenant (--body <json> | --body-file <path>) [--json]
|
|
26484
26665
|
|
|
26485
26666
|
Navigation menu layout (host extension).
|
|
26486
|
-
get GET ${
|
|
26487
|
-
set me PUT ${
|
|
26488
|
-
set tenant PUT ${
|
|
26667
|
+
get GET ${BASE32} {tenant, user} layers for the caller
|
|
26668
|
+
set me PUT ${BASE32}/me replace YOUR personal layer (signed-in user)
|
|
26669
|
+
set tenant PUT ${BASE32}/tenant [super-admin] replace the workspace default layer
|
|
26489
26670
|
|
|
26490
26671
|
The body is the menu config object ({"items": {...}, "headers": [...]}) or the full
|
|
26491
26672
|
request ({"config": {...}}). A write REPLACES that layer. \`set tenant\` reads the current
|
|
@@ -26511,7 +26692,7 @@ async function runMenuConfig(ctx, argv) {
|
|
|
26511
26692
|
return 0;
|
|
26512
26693
|
}
|
|
26513
26694
|
if (sub === "get") {
|
|
26514
|
-
const res2 = await requestJson(ctx,
|
|
26695
|
+
const res2 = await requestJson(ctx, BASE32);
|
|
26515
26696
|
writeJson(ctx.io.stdout, res2.body);
|
|
26516
26697
|
return 0;
|
|
26517
26698
|
}
|
|
@@ -26525,13 +26706,13 @@ Run \`openwop menu-config --help\` for usage.`);
|
|
|
26525
26706
|
const body = "config" in raw ? raw : { config: raw };
|
|
26526
26707
|
let res;
|
|
26527
26708
|
if (layer === "me") {
|
|
26528
|
-
res = await gatedRequest(ctx, `${
|
|
26709
|
+
res = await gatedRequest(ctx, `${BASE32}/me`, { method: "PUT", body }, "Editing your menu layout", "signed-in");
|
|
26529
26710
|
} else {
|
|
26530
|
-
const current = await requestJson(ctx,
|
|
26711
|
+
const current = await requestJson(ctx, BASE32);
|
|
26531
26712
|
const etag = current.headers.get("etag");
|
|
26532
26713
|
res = await gatedRequest(
|
|
26533
26714
|
ctx,
|
|
26534
|
-
`${
|
|
26715
|
+
`${BASE32}/tenant`,
|
|
26535
26716
|
{ method: "PUT", body, ...etag ? { headers: { "if-match": etag } } : {} },
|
|
26536
26717
|
"Editing the workspace default menu layout",
|
|
26537
26718
|
"superadmin"
|
|
@@ -26921,7 +27102,7 @@ function renderKnowledge(ctx, agentId, k) {
|
|
|
26921
27102
|
|
|
26922
27103
|
// src/cli/compatEndpoints.ts
|
|
26923
27104
|
import { readFileSync as readFileSync19 } from "node:fs";
|
|
26924
|
-
var
|
|
27105
|
+
var BASE33 = "/v1/host/openwop-app/compat-endpoints";
|
|
26925
27106
|
var COMPAT_ENDPOINTS_HELP = `Usage:
|
|
26926
27107
|
openwop compat-endpoints list --org <orgId> [--json]
|
|
26927
27108
|
openwop compat-endpoints create --org <orgId> --label <l> --base-url-endpoint <https://\u2026> [--api-key-file <path> | --api-key-env <VAR>] [--model <m>]... [--vision] [--tools] [--long-context] [--json]
|
|
@@ -26971,7 +27152,7 @@ async function runCompatEndpoints(ctx, argv) {
|
|
|
26971
27152
|
switch (sub) {
|
|
26972
27153
|
case "list": {
|
|
26973
27154
|
const org2 = requireOrg(options.org);
|
|
26974
|
-
const res = await requestJson(ctx, `${
|
|
27155
|
+
const res = await requestJson(ctx, `${BASE33}?orgId=${encodeURIComponent(org2)}`);
|
|
26975
27156
|
if (ctx.json) {
|
|
26976
27157
|
writeJson(ctx.io.stdout, res.body);
|
|
26977
27158
|
return 0;
|
|
@@ -27004,7 +27185,7 @@ async function runCompatEndpoints(ctx, argv) {
|
|
|
27004
27185
|
const apiKey = readApiKey(ctx, options);
|
|
27005
27186
|
if (apiKey) body.apiKey = apiKey;
|
|
27006
27187
|
if (Array.isArray(options.model) && options.model.length) body.models = options.model;
|
|
27007
|
-
const res = await requestJson(ctx,
|
|
27188
|
+
const res = await requestJson(ctx, BASE33, { method: "POST", body });
|
|
27008
27189
|
if (ctx.json) {
|
|
27009
27190
|
writeJson(ctx.io.stdout, res.body);
|
|
27010
27191
|
return 0;
|
|
@@ -27018,7 +27199,7 @@ async function runCompatEndpoints(ctx, argv) {
|
|
|
27018
27199
|
writeLine(ctx.io.stderr, `Refusing to delete ${positionals[0]} (and its stored key) without --yes.`);
|
|
27019
27200
|
return 2;
|
|
27020
27201
|
}
|
|
27021
|
-
await requestJson(ctx, `${
|
|
27202
|
+
await requestJson(ctx, `${BASE33}/${encodeURIComponent(positionals[0])}`, { method: "DELETE" });
|
|
27022
27203
|
writeLine(ctx.io.stdout, `Deleted compat endpoint ${positionals[0]}.`);
|
|
27023
27204
|
return 0;
|
|
27024
27205
|
}
|
|
@@ -27048,7 +27229,7 @@ function readApiKey(ctx, options) {
|
|
|
27048
27229
|
}
|
|
27049
27230
|
|
|
27050
27231
|
// src/cli/hostEvents.ts
|
|
27051
|
-
var
|
|
27232
|
+
var BASE34 = "/v1/host/openwop-app/host-events/bindings";
|
|
27052
27233
|
var HOST_EVENTS_HELP = `Usage:
|
|
27053
27234
|
openwop host-events list [--json]
|
|
27054
27235
|
openwop host-events bind --event <host.\u2026> --workflow <workflowId> [--json]
|
|
@@ -27091,7 +27272,7 @@ async function runHostEvents(ctx, argv) {
|
|
|
27091
27272
|
}
|
|
27092
27273
|
switch (sub) {
|
|
27093
27274
|
case "list": {
|
|
27094
|
-
const res = await requestJson(ctx,
|
|
27275
|
+
const res = await requestJson(ctx, BASE34);
|
|
27095
27276
|
if (ctx.json) {
|
|
27096
27277
|
writeJson(ctx.io.stdout, res.body);
|
|
27097
27278
|
return 0;
|
|
@@ -27112,7 +27293,7 @@ async function runHostEvents(ctx, argv) {
|
|
|
27112
27293
|
case "bind": {
|
|
27113
27294
|
if (!options.event || !options.workflow) throw new CliError("bind needs --event <host.\u2026> and --workflow <workflowId>.", 2);
|
|
27114
27295
|
if (!String(options.event).startsWith("host.")) throw new CliError('--event must be a host-extension event name starting with "host.".', 2);
|
|
27115
|
-
const res = await requestJson(ctx,
|
|
27296
|
+
const res = await requestJson(ctx, BASE34, { method: "POST", body: { eventType: options.event, workflowId: options.workflow } });
|
|
27116
27297
|
if (ctx.json) {
|
|
27117
27298
|
writeJson(ctx.io.stdout, res.body);
|
|
27118
27299
|
return 0;
|
|
@@ -27123,7 +27304,7 @@ async function runHostEvents(ctx, argv) {
|
|
|
27123
27304
|
case "enable":
|
|
27124
27305
|
case "disable": {
|
|
27125
27306
|
if (positionals.length !== 1) throw new CliError(`Usage: openwop host-events ${sub} <bindingId> [--json]`, 2);
|
|
27126
|
-
const res = await requestJson(ctx, `${
|
|
27307
|
+
const res = await requestJson(ctx, `${BASE34}/${encodeURIComponent(positionals[0])}`, { method: "PATCH", body: { enabled: sub === "enable" } });
|
|
27127
27308
|
if (ctx.json) {
|
|
27128
27309
|
writeJson(ctx.io.stdout, res.body);
|
|
27129
27310
|
return 0;
|
|
@@ -27137,7 +27318,7 @@ async function runHostEvents(ctx, argv) {
|
|
|
27137
27318
|
writeLine(ctx.io.stderr, `Refusing to delete binding ${positionals[0]} without --yes.`);
|
|
27138
27319
|
return 2;
|
|
27139
27320
|
}
|
|
27140
|
-
await requestJson(ctx, `${
|
|
27321
|
+
await requestJson(ctx, `${BASE34}/${encodeURIComponent(positionals[0])}`, { method: "DELETE" });
|
|
27141
27322
|
writeLine(ctx.io.stdout, `Deleted binding ${positionals[0]}.`);
|
|
27142
27323
|
return 0;
|
|
27143
27324
|
}
|
|
@@ -27336,7 +27517,7 @@ Run \`openwop openapi --help\` for usage.`);
|
|
|
27336
27517
|
}
|
|
27337
27518
|
|
|
27338
27519
|
// src/cli/assistant.ts
|
|
27339
|
-
var
|
|
27520
|
+
var BASE35 = "/v1/host/openwop-app/assistant";
|
|
27340
27521
|
var ASSISTANT_HELP = `Usage:
|
|
27341
27522
|
openwop assistant workspace [--json]
|
|
27342
27523
|
openwop assistant briefing [--json]
|
|
@@ -27399,7 +27580,7 @@ async function runAssistant(ctx, argv) {
|
|
|
27399
27580
|
return await runWorkspace2(ctx, rest);
|
|
27400
27581
|
case "briefing":
|
|
27401
27582
|
case "brief":
|
|
27402
|
-
return await simpleRead(ctx, rest, `${
|
|
27583
|
+
return await simpleRead(ctx, rest, `${BASE35}/briefing`, (b) => writeLine(ctx.io.stdout, JSON.stringify(b?.brief ?? b, null, 2)));
|
|
27403
27584
|
case "projects":
|
|
27404
27585
|
case "project":
|
|
27405
27586
|
return await runProjects2(ctx, rest);
|
|
@@ -27412,7 +27593,7 @@ async function runAssistant(ctx, argv) {
|
|
|
27412
27593
|
case "meeting":
|
|
27413
27594
|
return await runMeetings(ctx, rest);
|
|
27414
27595
|
case "stakeholders":
|
|
27415
|
-
return await simpleRead(ctx, rest, `${
|
|
27596
|
+
return await simpleRead(ctx, rest, `${BASE35}/stakeholders`, (b) => table2(ctx, b?.stakeholders, (s) => ({
|
|
27416
27597
|
stakeholderId: s.stakeholderId,
|
|
27417
27598
|
name: s.person?.name ?? s.person?.email ?? "",
|
|
27418
27599
|
importance: String(s.importance ?? ""),
|
|
@@ -27425,7 +27606,7 @@ async function runAssistant(ctx, argv) {
|
|
|
27425
27606
|
case "loop":
|
|
27426
27607
|
return await runLoops(ctx, rest);
|
|
27427
27608
|
case "health":
|
|
27428
|
-
return await simpleRead(ctx, rest, `${
|
|
27609
|
+
return await simpleRead(ctx, rest, `${BASE35}/health`, (b) => writeLine(ctx.io.stdout, JSON.stringify(b?.health ?? b, null, 2)));
|
|
27429
27610
|
default:
|
|
27430
27611
|
throw new CliError(`Unknown assistant command: ${sub}
|
|
27431
27612
|
Run \`openwop assistant --help\` for usage.`, 2);
|
|
@@ -27455,7 +27636,7 @@ async function runWorkspace2(ctx, argv) {
|
|
|
27455
27636
|
write(ctx.io.stdout, ASSISTANT_HELP);
|
|
27456
27637
|
return 0;
|
|
27457
27638
|
}
|
|
27458
|
-
const res = await requestJson(ctx, `${
|
|
27639
|
+
const res = await requestJson(ctx, `${BASE35}/workspace-conversation`, { method: "POST", body: {} });
|
|
27459
27640
|
return emit(ctx, res.body, () => {
|
|
27460
27641
|
writeLine(ctx.io.stdout, `${res.status === 201 ? "Opened" : "Resumed"} workspace conversation ${res.body?.sessionId}.`);
|
|
27461
27642
|
writeLine(ctx.io.stdout, `Talk to the assistant: openwop chat messages send ${res.body?.sessionId} --content "\u2026"`);
|
|
@@ -27481,7 +27662,7 @@ async function runProjects2(ctx, argv) {
|
|
|
27481
27662
|
const id = positionals[0];
|
|
27482
27663
|
const needId = () => {
|
|
27483
27664
|
if (!id) throw new CliError(`assistant projects ${sub} requires <projectId>.`, 2);
|
|
27484
|
-
return `${
|
|
27665
|
+
return `${BASE35}/projects/${enc(id)}`;
|
|
27485
27666
|
};
|
|
27486
27667
|
const fields = () => {
|
|
27487
27668
|
const body = {};
|
|
@@ -27494,7 +27675,7 @@ async function runProjects2(ctx, argv) {
|
|
|
27494
27675
|
};
|
|
27495
27676
|
switch (sub) {
|
|
27496
27677
|
case "list": {
|
|
27497
|
-
const res = await requestJson(ctx, `${
|
|
27678
|
+
const res = await requestJson(ctx, `${BASE35}/projects`);
|
|
27498
27679
|
return emit(ctx, res.body, () => table2(ctx, res.body?.projects, projectRow, "No assistant projects. Create one with `openwop assistant projects create --name <n>`."));
|
|
27499
27680
|
}
|
|
27500
27681
|
case "get": {
|
|
@@ -27515,7 +27696,7 @@ async function runProjects2(ctx, argv) {
|
|
|
27515
27696
|
}
|
|
27516
27697
|
case "create": {
|
|
27517
27698
|
if (!options.name) throw new CliError("assistant projects create requires --name <n>.", 2);
|
|
27518
|
-
const res = await requestJson(ctx, `${
|
|
27699
|
+
const res = await requestJson(ctx, `${BASE35}/projects`, { method: "POST", body: fields() });
|
|
27519
27700
|
return emit(ctx, res.body, () => writeLine(ctx.io.stdout, `Created project ${res.body?.projectId} (${res.body?.name ?? options.name}).`));
|
|
27520
27701
|
}
|
|
27521
27702
|
case "update": {
|
|
@@ -27562,14 +27743,14 @@ async function runCommitments(ctx, argv) {
|
|
|
27562
27743
|
const id = positionals[0];
|
|
27563
27744
|
const needId = () => {
|
|
27564
27745
|
if (!id) throw new CliError(`assistant commitments ${sub} requires <commitmentId>.`, 2);
|
|
27565
|
-
return `${
|
|
27746
|
+
return `${BASE35}/commitments/${enc(id)}`;
|
|
27566
27747
|
};
|
|
27567
27748
|
switch (sub) {
|
|
27568
27749
|
case "list": {
|
|
27569
27750
|
const q = new URLSearchParams();
|
|
27570
27751
|
if (options.status) q.set("status", options.status);
|
|
27571
27752
|
if (options.project) q.set("projectId", options.project);
|
|
27572
|
-
const res = await requestJson(ctx, `${
|
|
27753
|
+
const res = await requestJson(ctx, `${BASE35}/commitments${q.size ? `?${q}` : ""}`);
|
|
27573
27754
|
return emit(ctx, res.body, () => table2(ctx, res.body?.commitments, commitmentRow, "No commitments."));
|
|
27574
27755
|
}
|
|
27575
27756
|
case "get": {
|
|
@@ -27619,7 +27800,7 @@ async function runDecisions(ctx, argv) {
|
|
|
27619
27800
|
write(ctx.io.stdout, ASSISTANT_HELP);
|
|
27620
27801
|
return 0;
|
|
27621
27802
|
}
|
|
27622
|
-
const res = await requestJson(ctx, `${
|
|
27803
|
+
const res = await requestJson(ctx, `${BASE35}/decisions${options.project ? `?projectId=${enc(options.project)}` : ""}`);
|
|
27623
27804
|
return emit(ctx, res.body, () => table2(ctx, res.body?.decisions, (d) => ({
|
|
27624
27805
|
decisionId: d.decisionId,
|
|
27625
27806
|
decidedAt: d.decidedAt ?? "",
|
|
@@ -27636,7 +27817,7 @@ async function runMeetings(ctx, argv) {
|
|
|
27636
27817
|
return 0;
|
|
27637
27818
|
}
|
|
27638
27819
|
if (sub === "list") {
|
|
27639
|
-
const res = await requestJson(ctx, `${
|
|
27820
|
+
const res = await requestJson(ctx, `${BASE35}/meetings`);
|
|
27640
27821
|
return emit(ctx, res.body, () => table2(ctx, res.body?.meetings, (m) => ({
|
|
27641
27822
|
meetingId: m.meetingId,
|
|
27642
27823
|
startAt: m.startAt ?? "",
|
|
@@ -27646,7 +27827,7 @@ async function runMeetings(ctx, argv) {
|
|
|
27646
27827
|
}
|
|
27647
27828
|
if (sub === "get") {
|
|
27648
27829
|
if (!positionals[0]) throw new CliError("assistant meetings get requires <meetingId>.", 2);
|
|
27649
|
-
const res = await requestJson(ctx, `${
|
|
27830
|
+
const res = await requestJson(ctx, `${BASE35}/meetings/${enc(positionals[0])}`);
|
|
27650
27831
|
const m = res.body ?? {};
|
|
27651
27832
|
return emit(ctx, res.body, () => writeFields(ctx, [
|
|
27652
27833
|
["meetingId", m.meetingId],
|
|
@@ -27675,11 +27856,11 @@ async function runPending(ctx, argv) {
|
|
|
27675
27856
|
const id = positionals[0];
|
|
27676
27857
|
const needId = () => {
|
|
27677
27858
|
if (!id) throw new CliError(`assistant pending ${sub} requires <actionId>.`, 2);
|
|
27678
|
-
return `${
|
|
27859
|
+
return `${BASE35}/pending-actions/${enc(id)}`;
|
|
27679
27860
|
};
|
|
27680
27861
|
switch (sub) {
|
|
27681
27862
|
case "list": {
|
|
27682
|
-
const res = await requestJson(ctx, `${
|
|
27863
|
+
const res = await requestJson(ctx, `${BASE35}/pending-actions${options.status ? `?status=${enc(options.status)}` : ""}`);
|
|
27683
27864
|
return emit(ctx, res.body, () => table2(ctx, res.body?.pendingActions, (a) => ({
|
|
27684
27865
|
actionId: a.actionId,
|
|
27685
27866
|
kind: a.kind ?? "",
|
|
@@ -27723,7 +27904,7 @@ async function runLoops(ctx, argv) {
|
|
|
27723
27904
|
return 0;
|
|
27724
27905
|
}
|
|
27725
27906
|
if (sub === "list") {
|
|
27726
|
-
const res = await requestJson(ctx, `${
|
|
27907
|
+
const res = await requestJson(ctx, `${BASE35}/loops`);
|
|
27727
27908
|
return emit(ctx, res.body, () => table2(ctx, res.body?.loops, (l) => ({
|
|
27728
27909
|
loopId: l.loopId,
|
|
27729
27910
|
label: l.label ?? "",
|
|
@@ -27738,7 +27919,7 @@ async function runLoops(ctx, argv) {
|
|
|
27738
27919
|
if (!loopId) throw new CliError(`assistant loops ${sub} requires <loopId>.`, 2);
|
|
27739
27920
|
const body = {};
|
|
27740
27921
|
if (sub === "enable" && options.cron) body.cronExpr = options.cron;
|
|
27741
|
-
const res = await requestJson(ctx, `${
|
|
27922
|
+
const res = await requestJson(ctx, `${BASE35}/loops/${enc(loopId)}/${sub}`, { method: "POST", body });
|
|
27742
27923
|
return emit(ctx, res.body, () => writeLine(ctx.io.stdout, `Loop ${loopId}: ${res.body?.enabled ? "enabled" : "disabled"} (job ${res.body?.jobId ?? ""}).`));
|
|
27743
27924
|
}
|
|
27744
27925
|
throw new CliError(`Unknown assistant loops command: ${sub}
|
|
@@ -27746,7 +27927,7 @@ Run \`openwop assistant --help\` for usage.`, 2);
|
|
|
27746
27927
|
}
|
|
27747
27928
|
|
|
27748
27929
|
// src/cli/channels.ts
|
|
27749
|
-
var
|
|
27930
|
+
var BASE36 = "/v1/host/openwop-app/channels";
|
|
27750
27931
|
var CHANNELS_HELP = `Usage:
|
|
27751
27932
|
openwop channels list [--json]
|
|
27752
27933
|
openwop channels create --name <n> [--description d] [--private] [--member <userId>]... [--agent <agentId>]... [--json]
|
|
@@ -27845,7 +28026,7 @@ function oneId(argv, usage6, spec = {}) {
|
|
|
27845
28026
|
const { options, positionals } = parseOptions(argv, { ...spec, bool: ["--help", ...spec.bool ?? []] });
|
|
27846
28027
|
if (options.help) return { help: true, options, positionals };
|
|
27847
28028
|
if (!positionals[0]) throw new CliError(`Usage: openwop channels ${usage6}`, 2);
|
|
27848
|
-
return { help: false, options, positionals, path: `${
|
|
28029
|
+
return { help: false, options, positionals, path: `${BASE36}/${enc(positionals[0])}` };
|
|
27849
28030
|
}
|
|
27850
28031
|
function channelSummary(res) {
|
|
27851
28032
|
const c = res?.channel ?? {};
|
|
@@ -27858,7 +28039,7 @@ async function runList4(ctx, argv) {
|
|
|
27858
28039
|
write(ctx.io.stdout, CHANNELS_HELP);
|
|
27859
28040
|
return 0;
|
|
27860
28041
|
}
|
|
27861
|
-
const res = await requestJson(ctx,
|
|
28042
|
+
const res = await requestJson(ctx, BASE36);
|
|
27862
28043
|
return emit(ctx, res.body, () => {
|
|
27863
28044
|
const rows = Array.isArray(res.body?.channels) ? res.body.channels : [];
|
|
27864
28045
|
if (!rows.length) {
|
|
@@ -27891,7 +28072,7 @@ async function runCreate(ctx, argv) {
|
|
|
27891
28072
|
if (options.description) body.description = options.description;
|
|
27892
28073
|
if (Array.isArray(options.member) && options.member.length) body.memberUserIds = options.member;
|
|
27893
28074
|
if (Array.isArray(options.agent) && options.agent.length) body.agentIds = options.agent;
|
|
27894
|
-
const res = await requestJson(ctx,
|
|
28075
|
+
const res = await requestJson(ctx, BASE36, { method: "POST", body });
|
|
27895
28076
|
return emit(ctx, res.body, () => writeLine(ctx.io.stdout, `Created channel ${channelSummary(res.body)}.`));
|
|
27896
28077
|
}
|
|
27897
28078
|
async function runGet5(ctx, argv) {
|
|
@@ -28861,7 +29042,7 @@ Run \`openwop agent-author --help\` for usage.`, 2);
|
|
|
28861
29042
|
}
|
|
28862
29043
|
|
|
28863
29044
|
// src/cli/workflowAuthor.ts
|
|
28864
|
-
var
|
|
29045
|
+
var BASE37 = "/v1/host/openwop-app/workflow-author";
|
|
28865
29046
|
var WORKFLOW_AUTHOR_HELP = `Usage:
|
|
28866
29047
|
openwop workflow-author catalog [--json]
|
|
28867
29048
|
openwop workflow-author draft --intent <text> [--provider p] [--model m] [--max-attempts n]
|
|
@@ -28897,7 +29078,7 @@ async function runWorkflowAuthor(ctx, argv) {
|
|
|
28897
29078
|
return 0;
|
|
28898
29079
|
}
|
|
28899
29080
|
if (sub === "catalog") {
|
|
28900
|
-
const res = await requestJson(ctx, `${
|
|
29081
|
+
const res = await requestJson(ctx, `${BASE37}/catalog`);
|
|
28901
29082
|
return emit(ctx, res.body, () => {
|
|
28902
29083
|
const nodes = Array.isArray(res.body?.nodes) ? res.body.nodes : [];
|
|
28903
29084
|
if (!nodes.length) writeLine(ctx.io.stdout, "No authorable nodes in this workspace.");
|
|
@@ -28913,7 +29094,7 @@ async function runWorkflowAuthor(ctx, argv) {
|
|
|
28913
29094
|
if (options.model) body.model = options.model;
|
|
28914
29095
|
const maxAttempts = intFlag(options.maxAttempts, "--max-attempts");
|
|
28915
29096
|
if (maxAttempts) body.maxAttempts = maxAttempts;
|
|
28916
|
-
const res = await requestJson(ctx, `${
|
|
29097
|
+
const res = await requestJson(ctx, `${BASE37}/draft`, { method: "POST", body, headers: idempotencyHeaders(options.idempotencyKey) });
|
|
28917
29098
|
const runId = res.body?.runId;
|
|
28918
29099
|
if (!options.follow) {
|
|
28919
29100
|
return emit(ctx, res.body, () => {
|
|
@@ -28940,7 +29121,7 @@ Run \`openwop workflow-author --help\` for usage.`, 2);
|
|
|
28940
29121
|
}
|
|
28941
29122
|
|
|
28942
29123
|
// src/cli/workflowProposals.ts
|
|
28943
|
-
var
|
|
29124
|
+
var BASE38 = "/v1/host/openwop-app/workflow-proposals/admin/policies";
|
|
28944
29125
|
var WORKFLOW_PROPOSALS_HELP = `Usage:
|
|
28945
29126
|
openwop workflow-proposals policies --tenant <tenantId> [--json]
|
|
28946
29127
|
openwop workflow-proposals enable --tenant <tenantId> --agent-profile <agentProfileId> [--json]
|
|
@@ -28971,7 +29152,7 @@ async function runWorkflowProposals(ctx, argv) {
|
|
|
28971
29152
|
}
|
|
28972
29153
|
if (!options.tenant) throw new CliError("workflow-proposals requires --tenant <tenantId>.", 2);
|
|
28973
29154
|
if (sub === "policies" || sub === "list") {
|
|
28974
|
-
const res = await requestJson(ctx, `${
|
|
29155
|
+
const res = await requestJson(ctx, `${BASE38}?tenantId=${enc(options.tenant)}`);
|
|
28975
29156
|
return emit(ctx, res.body, () => {
|
|
28976
29157
|
const items = Array.isArray(res.body?.items) ? res.body.items : [];
|
|
28977
29158
|
if (!items.length) {
|
|
@@ -28983,7 +29164,7 @@ async function runWorkflowProposals(ctx, argv) {
|
|
|
28983
29164
|
}
|
|
28984
29165
|
if (sub === "enable" || sub === "disable") {
|
|
28985
29166
|
if (!options.agentProfile) throw new CliError(`workflow-proposals ${sub} requires --agent-profile <agentProfileId>.`, 2);
|
|
28986
|
-
const path = `${
|
|
29167
|
+
const path = `${BASE38}/${enc(options.tenant)}/${enc(options.agentProfile)}`;
|
|
28987
29168
|
const res = await requestJson(ctx, path, { method: sub === "enable" ? "PUT" : "DELETE" });
|
|
28988
29169
|
return emit(ctx, res.body, () => writeLine(ctx.io.stdout, sub === "enable" ? `Auto-approval enabled for ${options.agentProfile} in ${options.tenant}.` : res.body?.removed ? `Auto-approval disabled for ${options.agentProfile} in ${options.tenant}.` : `No policy was set for ${options.agentProfile} in ${options.tenant}.`));
|
|
28989
29170
|
}
|
|
@@ -29929,6 +30110,10 @@ async function runCli(argv, options = {}) {
|
|
|
29929
30110
|
return await runConformance(ctx, commandArgs);
|
|
29930
30111
|
case "onboard":
|
|
29931
30112
|
return await runOnboard(ctx, commandArgs);
|
|
30113
|
+
case "login":
|
|
30114
|
+
return await runLogin(ctx, commandArgs);
|
|
30115
|
+
case "logout":
|
|
30116
|
+
return await runLogout(ctx, commandArgs);
|
|
29932
30117
|
case "providers":
|
|
29933
30118
|
case "provider":
|
|
29934
30119
|
return await runProviders(ctx, commandArgs);
|
|
@@ -30257,6 +30442,8 @@ var HELP_MAP = {
|
|
|
30257
30442
|
packs: PACKS_HELP,
|
|
30258
30443
|
pack: PACKS_HELP,
|
|
30259
30444
|
onboard: ONBOARD_HELP,
|
|
30445
|
+
login: LOGIN_HELP,
|
|
30446
|
+
logout: LOGIN_HELP,
|
|
30260
30447
|
providers: PROVIDERS_HELP,
|
|
30261
30448
|
provider: PROVIDERS_HELP,
|
|
30262
30449
|
agents: AGENTS_HELP,
|
|
@@ -30455,6 +30642,7 @@ Exit codes:
|
|
|
30455
30642
|
|
|
30456
30643
|
Commands:
|
|
30457
30644
|
onboard Guided first-run setup (host + provider + model + BYOK key)
|
|
30645
|
+
login | logout Sign this terminal in to an openwop-app host by a code (no key to copy)
|
|
30458
30646
|
providers list List stored BYOK credential refs (never values)
|
|
30459
30647
|
providers add Store a credential ref against the configured host
|
|
30460
30648
|
providers remove Remove a credential ref
|