@openwop/cli 1.3.0 → 1.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -2
- package/dist/cli.js +467 -271
- package/dist/openwop.js +467 -271
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -578,7 +578,7 @@ function errText(err) {
|
|
|
578
578
|
// package.json
|
|
579
579
|
var package_default = {
|
|
580
580
|
name: "@openwop/cli",
|
|
581
|
-
version: "1.
|
|
581
|
+
version: "1.4.1",
|
|
582
582
|
description: "OpenWOP CLI for operating the workflow-engine demo app and OpenWOP-compatible hosts.",
|
|
583
583
|
license: "Apache-2.0",
|
|
584
584
|
type: "module",
|
|
@@ -1078,7 +1078,7 @@ import { createInterface as createInterface2 } from "node:readline";
|
|
|
1078
1078
|
|
|
1079
1079
|
// src/ids.ts
|
|
1080
1080
|
function projectTenantBoundId(id) {
|
|
1081
|
-
if (id.includes("~")) return id;
|
|
1081
|
+
if (id.includes("~") && !id.includes("/")) return id;
|
|
1082
1082
|
let out = "";
|
|
1083
1083
|
for (const byte of new TextEncoder().encode(id)) {
|
|
1084
1084
|
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;
|
|
@@ -4496,7 +4526,7 @@ async function runCatalogPacks(ctx, argv = []) {
|
|
|
4496
4526
|
write(ctx.io.stdout, CATALOG_HELP);
|
|
4497
4527
|
return 0;
|
|
4498
4528
|
}
|
|
4499
|
-
const res = await
|
|
4529
|
+
const res = await catalogRead(ctx, "", { auth: false });
|
|
4500
4530
|
if (ctx.json) {
|
|
4501
4531
|
writeJson(ctx.io.stdout, res.body);
|
|
4502
4532
|
return 0;
|
|
@@ -4505,6 +4535,14 @@ async function runCatalogPacks(ctx, argv = []) {
|
|
|
4505
4535
|
writeLine(ctx.io.stdout, formatTable(rows, ["name", "nodes"]));
|
|
4506
4536
|
return 0;
|
|
4507
4537
|
}
|
|
4538
|
+
async function catalogRead(ctx, rest, options = {}) {
|
|
4539
|
+
try {
|
|
4540
|
+
return await requestJson(ctx, `/v1/host/openwop-app/packs${rest}`, options);
|
|
4541
|
+
} catch (err) {
|
|
4542
|
+
if (err instanceof HttpError && err.status === 404) return requestJson(ctx, `/v1/packs${rest}`, options);
|
|
4543
|
+
throw err;
|
|
4544
|
+
}
|
|
4545
|
+
}
|
|
4508
4546
|
async function runCatalogPacksVerb(ctx, verb, argv) {
|
|
4509
4547
|
const { options, positionals } = parseOptions(argv, { bool: ["--help"], value: ["--out"] });
|
|
4510
4548
|
if (options.help) {
|
|
@@ -4513,7 +4551,7 @@ async function runCatalogPacksVerb(ctx, verb, argv) {
|
|
|
4513
4551
|
}
|
|
4514
4552
|
if (verb === "search") {
|
|
4515
4553
|
const q = positionals[0] ?? "";
|
|
4516
|
-
const res2 = await
|
|
4554
|
+
const res2 = await catalogRead(ctx, `/-/search${q ? `?q=${encodeURIComponent(q)}` : ""}`);
|
|
4517
4555
|
if (ctx.json) {
|
|
4518
4556
|
writeJson(ctx.io.stdout, res2.body);
|
|
4519
4557
|
return 0;
|
|
@@ -4529,7 +4567,7 @@ async function runCatalogPacksVerb(ctx, verb, argv) {
|
|
|
4529
4567
|
}
|
|
4530
4568
|
if (verb === "get") {
|
|
4531
4569
|
if (positionals.length !== 1) throw new CliError("Usage: openwop catalog packs get <packName> [--json]", 2);
|
|
4532
|
-
const res2 = await
|
|
4570
|
+
const res2 = await catalogRead(ctx, `/${encodeURIComponent(positionals[0])}`);
|
|
4533
4571
|
if (ctx.json) {
|
|
4534
4572
|
writeJson(ctx.io.stdout, res2.body);
|
|
4535
4573
|
return 0;
|
|
@@ -4540,7 +4578,7 @@ async function runCatalogPacksVerb(ctx, verb, argv) {
|
|
|
4540
4578
|
for (const n of nodes) writeLine(ctx.io.stdout, ` ${n}`);
|
|
4541
4579
|
return 0;
|
|
4542
4580
|
}
|
|
4543
|
-
const res = await
|
|
4581
|
+
const res = await catalogRead(ctx, "/export");
|
|
4544
4582
|
if (options.out) {
|
|
4545
4583
|
writeFileSync4(String(options.out), `${JSON.stringify(res.body, null, 2)}
|
|
4546
4584
|
`);
|
|
@@ -14860,6 +14898,153 @@ async function runOnboard(ctx, argv) {
|
|
|
14860
14898
|
return 0;
|
|
14861
14899
|
}
|
|
14862
14900
|
|
|
14901
|
+
// src/cli/login.ts
|
|
14902
|
+
import { hostname } from "node:os";
|
|
14903
|
+
var BASE10 = "/v1/host/openwop-app/cli-login";
|
|
14904
|
+
var LOGIN_HELP = `Usage:
|
|
14905
|
+
openwop login [--label <name>] [--timeout <seconds>] [--profile <name>] [--json]
|
|
14906
|
+
openwop logout [--profile <name>] [--json]
|
|
14907
|
+
|
|
14908
|
+
Sign this terminal in to an openwop-app host without copying an API key
|
|
14909
|
+
(host extension under ${BASE10}).
|
|
14910
|
+
|
|
14911
|
+
login Shows a short code. Open the host's Access \u2192 API keys page, type the
|
|
14912
|
+
code under "Sign in the OpenWOP CLI", and approve. The host then issues
|
|
14913
|
+
this CLI a key (30 days by default), saved to your config file.
|
|
14914
|
+
logout Revokes that key on the host and removes it from your config file.
|
|
14915
|
+
|
|
14916
|
+
The key is never printed. It is listed in the app as "CLI: <label>", where you can
|
|
14917
|
+
revoke it. Sign in again to renew.
|
|
14918
|
+
|
|
14919
|
+
--label <name> What to call this terminal in the app (default: this machine's hostname).
|
|
14920
|
+
--timeout <seconds> Give up waiting for approval after this long (default: the host's own limit).
|
|
14921
|
+
--profile <name> Use the named config profile.
|
|
14922
|
+
|
|
14923
|
+
Approve a code ONLY if you just ran \`openwop login\` yourself.
|
|
14924
|
+
|
|
14925
|
+
Exit codes: 0 signed in / signed out \xB7 1 denied, expired or not available on this host \xB7 2 usage.
|
|
14926
|
+
|
|
14927
|
+
Examples:
|
|
14928
|
+
export OPENWOP_BASE_URL=https://app.openwop.dev/api
|
|
14929
|
+
openwop login
|
|
14930
|
+
openwop login --label "work laptop"
|
|
14931
|
+
openwop logout
|
|
14932
|
+
`;
|
|
14933
|
+
var sleep2 = (ms2) => new Promise((r) => setTimeout(r, ms2));
|
|
14934
|
+
function approvalUrl(baseUrl, path) {
|
|
14935
|
+
const p = typeof path === "string" && path.startsWith("/") ? path : "/access?tab=api-keys";
|
|
14936
|
+
try {
|
|
14937
|
+
return `${new URL(baseUrl).origin}${p}`;
|
|
14938
|
+
} catch {
|
|
14939
|
+
return p;
|
|
14940
|
+
}
|
|
14941
|
+
}
|
|
14942
|
+
function notAvailable(ctx) {
|
|
14943
|
+
return new CliError(
|
|
14944
|
+
`${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.`,
|
|
14945
|
+
1
|
|
14946
|
+
);
|
|
14947
|
+
}
|
|
14948
|
+
async function runLogin(ctx, argv) {
|
|
14949
|
+
const { options } = parseOptions(argv, { bool: ["--help"], value: ["--label", "--timeout", "--profile"] });
|
|
14950
|
+
if (options.help) {
|
|
14951
|
+
write(ctx.io.stdout, LOGIN_HELP);
|
|
14952
|
+
return 0;
|
|
14953
|
+
}
|
|
14954
|
+
const timeoutS = options.timeout === void 0 ? void 0 : Number(options.timeout);
|
|
14955
|
+
if (timeoutS !== void 0 && !(Number.isFinite(timeoutS) && timeoutS > 0)) {
|
|
14956
|
+
writeLine(ctx.io.stderr, "--timeout must be a positive number of seconds.");
|
|
14957
|
+
return 2;
|
|
14958
|
+
}
|
|
14959
|
+
const label = String(options.label ?? hostname() ?? "this machine").slice(0, 60);
|
|
14960
|
+
const anon = { ...ctx, apiKey: void 0 };
|
|
14961
|
+
let started;
|
|
14962
|
+
try {
|
|
14963
|
+
started = (await requestJson(anon, `${BASE10}/start`, { method: "POST", body: { label } })).body;
|
|
14964
|
+
} catch (err) {
|
|
14965
|
+
if (err instanceof HttpError && err.status === 404) throw notAvailable(ctx);
|
|
14966
|
+
throw err;
|
|
14967
|
+
}
|
|
14968
|
+
const deviceCode = started?.deviceCode;
|
|
14969
|
+
const userCode = started?.userCode;
|
|
14970
|
+
if (typeof deviceCode !== "string" || typeof userCode !== "string") throw notAvailable(ctx);
|
|
14971
|
+
writeLine(ctx.io.stderr, "");
|
|
14972
|
+
writeLine(ctx.io.stderr, ` 1. Open ${approvalUrl(ctx.baseUrl, started.verificationPath)}`);
|
|
14973
|
+
writeLine(ctx.io.stderr, ` 2. Enter ${userCode} under "Sign in the OpenWOP CLI", and approve.`);
|
|
14974
|
+
writeLine(ctx.io.stderr, "");
|
|
14975
|
+
writeLine(ctx.io.stderr, "Waiting for approval\u2026");
|
|
14976
|
+
const hostLimitS = Number.isFinite(Number(started.expiresIn)) ? Number(started.expiresIn) : 600;
|
|
14977
|
+
const deadline = Date.now() + Math.min(timeoutS ?? hostLimitS, hostLimitS) * 1e3;
|
|
14978
|
+
let intervalS = Number.isFinite(Number(started.interval)) ? Number(started.interval) : 3;
|
|
14979
|
+
for (; ; ) {
|
|
14980
|
+
if (Date.now() >= deadline) throw new CliError("Timed out waiting for approval. Run `openwop login` again for a new code.", 1);
|
|
14981
|
+
await sleep2(Math.max(0, intervalS) * 1e3);
|
|
14982
|
+
let res;
|
|
14983
|
+
try {
|
|
14984
|
+
res = (await requestJson(anon, `${BASE10}/poll`, { method: "POST", body: { deviceCode } })).body;
|
|
14985
|
+
} catch (err) {
|
|
14986
|
+
if (err instanceof HttpError && err.status === 404) {
|
|
14987
|
+
throw new CliError("That sign-in expired or was already used. Run `openwop login` again for a new code.", 1);
|
|
14988
|
+
}
|
|
14989
|
+
throw err;
|
|
14990
|
+
}
|
|
14991
|
+
if (res?.status === "pending") {
|
|
14992
|
+
if (Number.isFinite(Number(res.interval))) intervalS = Number(res.interval);
|
|
14993
|
+
continue;
|
|
14994
|
+
}
|
|
14995
|
+
if (res?.status === "denied") throw new CliError("The sign-in was denied in the app.", 1);
|
|
14996
|
+
if (res?.status === "failed") throw new CliError(`The host could not issue a key: ${String(res.message ?? "unknown reason")}`, 1);
|
|
14997
|
+
if (res?.status === "approved" && typeof res.token === "string") {
|
|
14998
|
+
const configPath = configPathFor(options.profile, ctx.env);
|
|
14999
|
+
saveConfig(configPath, mergeConfig(readConfigSafe(configPath), { host: { baseUrl: ctx.baseUrl, apiKey: res.token } }));
|
|
15000
|
+
const key = res.key ?? {};
|
|
15001
|
+
if (ctx.json) {
|
|
15002
|
+
writeJson(ctx.io.stdout, { status: "signed-in", keyId: key.keyId ?? null, name: key.name ?? null, expiresAt: key.expiresAt ?? null, configPath });
|
|
15003
|
+
return 0;
|
|
15004
|
+
}
|
|
15005
|
+
writeLine(ctx.io.stdout, `Signed in to ${ctx.baseUrl} as \u201C${key.name ?? `CLI: ${label}`}\u201D.`);
|
|
15006
|
+
if (key.expiresAt) writeLine(ctx.io.stdout, `The key expires ${String(key.expiresAt).slice(0, 10)}; run \`openwop login\` again to renew.`);
|
|
15007
|
+
writeLine(ctx.io.stdout, `Saved to ${configPath}. Revoke it any time with \`openwop logout\` or in the app.`);
|
|
15008
|
+
return 0;
|
|
15009
|
+
}
|
|
15010
|
+
throw new CliError("The host answered the sign-in in a shape this CLI does not understand.", 1);
|
|
15011
|
+
}
|
|
15012
|
+
}
|
|
15013
|
+
async function runLogout(ctx, argv) {
|
|
15014
|
+
const { options } = parseOptions(argv, { bool: ["--help"], value: ["--profile"] });
|
|
15015
|
+
if (options.help) {
|
|
15016
|
+
write(ctx.io.stdout, LOGIN_HELP);
|
|
15017
|
+
return 0;
|
|
15018
|
+
}
|
|
15019
|
+
const configPath = configPathFor(options.profile, ctx.env);
|
|
15020
|
+
const config = readConfigSafe(configPath);
|
|
15021
|
+
const saved = config?.host?.apiKey;
|
|
15022
|
+
if (typeof saved !== "string" || saved.length === 0) {
|
|
15023
|
+
if (ctx.json) writeJson(ctx.io.stdout, { status: "not-signed-in" });
|
|
15024
|
+
else writeLine(ctx.io.stdout, "Not signed in: no key is saved in your config.");
|
|
15025
|
+
return 0;
|
|
15026
|
+
}
|
|
15027
|
+
let revoked = false;
|
|
15028
|
+
let note = "";
|
|
15029
|
+
try {
|
|
15030
|
+
await requestJson({ ...ctx, apiKey: saved }, `${BASE10}/logout`, { method: "POST", body: {} });
|
|
15031
|
+
revoked = true;
|
|
15032
|
+
} catch (err) {
|
|
15033
|
+
if (err instanceof HttpError && err.status === 401) note = "The host no longer recognised the key (already revoked or expired).";
|
|
15034
|
+
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.";
|
|
15035
|
+
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.";
|
|
15036
|
+
else throw err;
|
|
15037
|
+
}
|
|
15038
|
+
unsetByPath(config, "host.apiKey");
|
|
15039
|
+
saveConfig(configPath, config);
|
|
15040
|
+
if (ctx.json) {
|
|
15041
|
+
writeJson(ctx.io.stdout, { status: "signed-out", revokedOnHost: revoked, ...note ? { note } : {} });
|
|
15042
|
+
return 0;
|
|
15043
|
+
}
|
|
15044
|
+
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}`);
|
|
15045
|
+
return 0;
|
|
15046
|
+
}
|
|
15047
|
+
|
|
14863
15048
|
// src/cli/providers.ts
|
|
14864
15049
|
var PROVIDERS_HELP = `Usage:
|
|
14865
15050
|
openwop providers list [--json]
|
|
@@ -18086,7 +18271,7 @@ Examples:
|
|
|
18086
18271
|
openwop profiles pin r_123
|
|
18087
18272
|
openwop profiles activity --limit 10 --status failed
|
|
18088
18273
|
`;
|
|
18089
|
-
var
|
|
18274
|
+
var BASE11 = "/v1/host/openwop-app/profiles";
|
|
18090
18275
|
async function profilesRequest(ctx, path, options, notFoundMsg) {
|
|
18091
18276
|
try {
|
|
18092
18277
|
return await requestJson(ctx, path, options);
|
|
@@ -18183,7 +18368,7 @@ async function runList2(ctx, argv) {
|
|
|
18183
18368
|
write(ctx.io.stdout, "Usage: openwop profiles list [--json]\n");
|
|
18184
18369
|
return 0;
|
|
18185
18370
|
}
|
|
18186
|
-
const res = await profilesRequest(ctx,
|
|
18371
|
+
const res = await profilesRequest(ctx, BASE11);
|
|
18187
18372
|
if (ctx.json) {
|
|
18188
18373
|
writeJson(ctx.io.stdout, res.body);
|
|
18189
18374
|
return 0;
|
|
@@ -18209,7 +18394,7 @@ async function runGet3(ctx, argv) {
|
|
|
18209
18394
|
write(ctx.io.stdout, "Usage: openwop profiles get [<userId>] [--json]\n");
|
|
18210
18395
|
return options.help ? 0 : 2;
|
|
18211
18396
|
}
|
|
18212
|
-
const path = positionals.length === 1 ? `${
|
|
18397
|
+
const path = positionals.length === 1 ? `${BASE11}/${encodeURIComponent(positionals[0])}` : `${BASE11}/me`;
|
|
18213
18398
|
const res = await profilesRequest(ctx, path, void 0, `Profile not found: ${positionals[0] ?? "me"}`);
|
|
18214
18399
|
if (ctx.json) {
|
|
18215
18400
|
writeJson(ctx.io.stdout, res.body);
|
|
@@ -18228,7 +18413,7 @@ async function runActivity(ctx, argv) {
|
|
|
18228
18413
|
if (options.limit !== void 0) qs2.set("limit", String(options.limit));
|
|
18229
18414
|
if (options.status !== void 0) qs2.set("status", String(options.status));
|
|
18230
18415
|
const q = qs2.toString();
|
|
18231
|
-
const res = await profilesRequest(ctx, `${
|
|
18416
|
+
const res = await profilesRequest(ctx, `${BASE11}/me/activity${q ? `?${q}` : ""}`);
|
|
18232
18417
|
if (ctx.json) {
|
|
18233
18418
|
writeJson(ctx.io.stdout, res.body);
|
|
18234
18419
|
return 0;
|
|
@@ -18267,7 +18452,7 @@ async function runEdit(ctx, argv) {
|
|
|
18267
18452
|
if (Array.isArray(options.interests)) body.interests = options.interests;
|
|
18268
18453
|
if (Array.isArray(options.growthInterests)) body.growthInterests = options.growthInterests;
|
|
18269
18454
|
if (options.location !== void 0 || Array.isArray(options.link)) {
|
|
18270
|
-
const current = (await profilesRequest(ctx, `${
|
|
18455
|
+
const current = (await profilesRequest(ctx, `${BASE11}/me`)).body?.contact ?? {};
|
|
18271
18456
|
const contact = { ...current };
|
|
18272
18457
|
if (options.location !== void 0) contact.location = options.location;
|
|
18273
18458
|
if (Array.isArray(options.link)) {
|
|
@@ -18294,7 +18479,7 @@ async function runEdit(ctx, argv) {
|
|
|
18294
18479
|
}
|
|
18295
18480
|
if (Object.keys(avail).length) body.availability = avail;
|
|
18296
18481
|
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, `${
|
|
18482
|
+
const res = await profilesRequest(ctx, `${BASE11}/me`, { method: "PATCH", body });
|
|
18298
18483
|
if (ctx.json) {
|
|
18299
18484
|
writeJson(ctx.io.stdout, res.body);
|
|
18300
18485
|
return 0;
|
|
@@ -18320,7 +18505,7 @@ async function runSkillsSet(ctx, argv) {
|
|
|
18320
18505
|
if (!Number.isFinite(prof2) || prof2 < 1 || prof2 > 5) throw new CliError(`--skill proficiency must be 1..5 (got '${e}')`, 2);
|
|
18321
18506
|
return { name, proficiency: prof2 };
|
|
18322
18507
|
});
|
|
18323
|
-
const res = await profilesRequest(ctx, `${
|
|
18508
|
+
const res = await profilesRequest(ctx, `${BASE11}/me/skills`, { method: "PUT", body: { skills } });
|
|
18324
18509
|
if (ctx.json) {
|
|
18325
18510
|
writeJson(ctx.io.stdout, res.body);
|
|
18326
18511
|
return 0;
|
|
@@ -18335,7 +18520,7 @@ async function runPortfolioAdd(ctx, argv) {
|
|
|
18335
18520
|
write(ctx.io.stdout, "Usage: openwop profiles portfolio add --token <mediaToken> [--json]\n");
|
|
18336
18521
|
return options.help ? 0 : 2;
|
|
18337
18522
|
}
|
|
18338
|
-
const res = await profilesRequest(ctx, `${
|
|
18523
|
+
const res = await profilesRequest(ctx, `${BASE11}/me/portfolio`, { method: "POST", body: { token: options.token } });
|
|
18339
18524
|
if (ctx.json) {
|
|
18340
18525
|
writeJson(ctx.io.stdout, res.body);
|
|
18341
18526
|
return 0;
|
|
@@ -18349,7 +18534,7 @@ async function runPortfolioRemove(ctx, argv) {
|
|
|
18349
18534
|
write(ctx.io.stdout, "Usage: openwop profiles portfolio remove <mediaToken> [--json]\n");
|
|
18350
18535
|
return options.help ? 0 : 2;
|
|
18351
18536
|
}
|
|
18352
|
-
const res = await profilesRequest(ctx, `${
|
|
18537
|
+
const res = await profilesRequest(ctx, `${BASE11}/me/portfolio/${encodeURIComponent(positionals[0])}`, { method: "DELETE" }, `Portfolio asset not found: ${positionals[0]}`);
|
|
18353
18538
|
if (ctx.json) {
|
|
18354
18539
|
writeJson(ctx.io.stdout, res.body);
|
|
18355
18540
|
return 0;
|
|
@@ -18364,7 +18549,7 @@ async function runPin(ctx, argv, pinned) {
|
|
|
18364
18549
|
`);
|
|
18365
18550
|
return options.help ? 0 : 2;
|
|
18366
18551
|
}
|
|
18367
|
-
const path = `${
|
|
18552
|
+
const path = `${BASE11}/me/pinned-agents/${encodeURIComponent(positionals[0])}`;
|
|
18368
18553
|
const res = await profilesRequest(ctx, path, { method: pinned ? "PUT" : "DELETE" }, `Agent not found: ${positionals[0]}`);
|
|
18369
18554
|
if (ctx.json) {
|
|
18370
18555
|
writeJson(ctx.io.stdout, res.body);
|
|
@@ -18381,7 +18566,7 @@ async function runEndorse(ctx, argv, add) {
|
|
|
18381
18566
|
return options.help ? 0 : 2;
|
|
18382
18567
|
}
|
|
18383
18568
|
const [userId, skill] = positionals;
|
|
18384
|
-
const path = `${
|
|
18569
|
+
const path = `${BASE11}/${encodeURIComponent(userId)}/skills/${encodeURIComponent(skill)}/endorse`;
|
|
18385
18570
|
const res = await profilesRequest(ctx, path, { method: add ? "POST" : "DELETE" }, `Profile or skill not found: ${userId} / ${skill}`);
|
|
18386
18571
|
if (ctx.json) {
|
|
18387
18572
|
writeJson(ctx.io.stdout, res.body);
|
|
@@ -19476,7 +19661,7 @@ Examples:
|
|
|
19476
19661
|
openwop auth saml validate --idp-url http://localhost:9100/idp --variant valid
|
|
19477
19662
|
openwop auth scim provision --op create-user --user-name jo@acme.com --email jo@acme.com
|
|
19478
19663
|
`;
|
|
19479
|
-
var
|
|
19664
|
+
var BASE12 = "/v1/host/openwop-app/auth";
|
|
19480
19665
|
var SECRET_KEY2 = /secret|token|password|private[-_]?key|client[-_]?secret|api[-_]?key|credential|bearer|assertion|certificate|cert|pem/i;
|
|
19481
19666
|
function redact2(value) {
|
|
19482
19667
|
return redactSecrets(value, { secret: SECRET_KEY2 });
|
|
@@ -19527,7 +19712,7 @@ async function runStatus(ctx, argv) {
|
|
|
19527
19712
|
const profiles = disc.ok && Array.isArray(disc.body?.capabilities?.auth?.profiles) ? disc.body.capabilities.auth.profiles : [];
|
|
19528
19713
|
const samlAdvertised = profiles.includes("openwop-auth-saml");
|
|
19529
19714
|
const scimAdvertised = profiles.includes("openwop-auth-scim");
|
|
19530
|
-
const metaReachable = samlAdvertised ? (await probeEndpoint(ctx, `${
|
|
19715
|
+
const metaReachable = samlAdvertised ? (await probeEndpoint(ctx, `${BASE12}/saml/sso/metadata`)).ok : false;
|
|
19531
19716
|
if (ctx.json) {
|
|
19532
19717
|
writeJson(ctx.io.stdout, {
|
|
19533
19718
|
authProfilesAdvertised: profiles,
|
|
@@ -19552,7 +19737,7 @@ async function runSamlMetadata(ctx, argv) {
|
|
|
19552
19737
|
write(ctx.io.stdout, "Usage: openwop auth saml metadata [--json]\n");
|
|
19553
19738
|
return 0;
|
|
19554
19739
|
}
|
|
19555
|
-
const res = await authRequest(ctx, `${
|
|
19740
|
+
const res = await authRequest(ctx, `${BASE12}/saml/sso/metadata`, { auth: false }, "SAML SSO is not configured on this host (set OPENWOP_SAML_*).");
|
|
19556
19741
|
const xml = typeof res.body?.raw === "string" ? res.body.raw : typeof res.body === "string" ? res.body : JSON.stringify(res.body);
|
|
19557
19742
|
if (ctx.json) {
|
|
19558
19743
|
writeJson(ctx.io.stdout, { metadata: xml });
|
|
@@ -19570,7 +19755,7 @@ async function runSamlLoginUrl(ctx, argv) {
|
|
|
19570
19755
|
}
|
|
19571
19756
|
const returnTo = options.returnTo ?? "/";
|
|
19572
19757
|
const base16 = ctx.baseUrl.endsWith("/") ? ctx.baseUrl : `${ctx.baseUrl}/`;
|
|
19573
|
-
const url = new URL(`${
|
|
19758
|
+
const url = new URL(`${BASE12}/saml/sso/login?returnTo=${encodeURIComponent(returnTo)}`.replace(/^\//, ""), base16);
|
|
19574
19759
|
const res = await ctx.fetchImpl(url, { method: "GET", redirect: "manual" });
|
|
19575
19760
|
if (res.status === 404) {
|
|
19576
19761
|
throw new CliError("SAML SSO is not configured on this host (set OPENWOP_SAML_*).", 1);
|
|
@@ -19595,7 +19780,7 @@ async function runSamlValidate(ctx, argv) {
|
|
|
19595
19780
|
const body = { idpUrl: options.idpUrl, variant: options.variant };
|
|
19596
19781
|
let res;
|
|
19597
19782
|
try {
|
|
19598
|
-
res = await requestJson(ctx, `${
|
|
19783
|
+
res = await requestJson(ctx, `${BASE12}/saml/validate`, { method: "POST", body });
|
|
19599
19784
|
} catch (err) {
|
|
19600
19785
|
if (err instanceof HttpError && err.status === 404) {
|
|
19601
19786
|
throw new CliError("SAML validation seam not configured on this host (set OPENWOP_TEST_SAML_IDP_URL).", 1);
|
|
@@ -19638,7 +19823,7 @@ async function runScimProvision(ctx, argv) {
|
|
|
19638
19823
|
if (options.displayName !== void 0) user.displayName = options.displayName;
|
|
19639
19824
|
const body = { op: options.op, user };
|
|
19640
19825
|
if (options.group !== void 0) body.group = options.group;
|
|
19641
|
-
const res = await authRequest(ctx, `${
|
|
19826
|
+
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
19827
|
const safe = redact2(res.body ?? {});
|
|
19643
19828
|
if (ctx.json) {
|
|
19644
19829
|
writeJson(ctx.io.stdout, safe);
|
|
@@ -19662,7 +19847,7 @@ async function runBreakGlass(ctx, argv) {
|
|
|
19662
19847
|
const token = await readSecretInput(ctx, options.tokenFile !== void 0 ? { valueFile: options.tokenFile } : {}, "Break-glass token");
|
|
19663
19848
|
let res;
|
|
19664
19849
|
try {
|
|
19665
|
-
res = await requestJson(ctx, `${
|
|
19850
|
+
res = await requestJson(ctx, `${BASE12}/break-glass`, { method: "POST", body: { token } });
|
|
19666
19851
|
} catch (err) {
|
|
19667
19852
|
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
19853
|
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 +20176,9 @@ function exitForState(state) {
|
|
|
19991
20176
|
return 1;
|
|
19992
20177
|
}
|
|
19993
20178
|
async function ensureAdvertised3(ctx) {
|
|
19994
|
-
const
|
|
19995
|
-
if (
|
|
19996
|
-
const
|
|
19997
|
-
const advertised = !!(body.capabilities?.agents?.proposals ?? body.agents?.proposals);
|
|
20179
|
+
const record = await advertisedRecord(ctx, (b) => b.capabilities?.agents?.proposals ?? b.agents?.proposals);
|
|
20180
|
+
if (record === void 0) return;
|
|
20181
|
+
const advertised = !!record;
|
|
19998
20182
|
if (!advertised) {
|
|
19999
20183
|
throw new CliError(
|
|
20000
20184
|
"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 +20507,9 @@ function exitForState2(state) {
|
|
|
20323
20507
|
return 1;
|
|
20324
20508
|
}
|
|
20325
20509
|
async function ensureAdvertised4(ctx) {
|
|
20326
|
-
const
|
|
20327
|
-
if (
|
|
20328
|
-
const
|
|
20329
|
-
const advertised = !!(body.capabilities?.agents?.goals ?? body.agents?.goals);
|
|
20510
|
+
const record = await advertisedRecord(ctx, (b) => b.capabilities?.agents?.goals ?? b.agents?.goals);
|
|
20511
|
+
if (record === void 0) return;
|
|
20512
|
+
const advertised = !!record;
|
|
20330
20513
|
if (!advertised) {
|
|
20331
20514
|
throw new CliError(
|
|
20332
20515
|
"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 +20777,9 @@ function redact3(value) {
|
|
|
20594
20777
|
return redactSecrets(value, { secret: SECRET_KEY3, keep: REF_ONLY_KEY });
|
|
20595
20778
|
}
|
|
20596
20779
|
async function ensureAdvertised5(ctx) {
|
|
20597
|
-
const
|
|
20598
|
-
if (
|
|
20599
|
-
const
|
|
20600
|
-
const advertised = !!(body.capabilities?.portability ?? body.portability);
|
|
20780
|
+
const record = await advertisedRecord(ctx, (b) => b.capabilities?.portability ?? b.portability);
|
|
20781
|
+
if (record === void 0) return;
|
|
20782
|
+
const advertised = !!record;
|
|
20601
20783
|
if (!advertised) {
|
|
20602
20784
|
throw new CliError(
|
|
20603
20785
|
"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 +21026,7 @@ function exitForState3(state) {
|
|
|
20844
21026
|
return 1;
|
|
20845
21027
|
}
|
|
20846
21028
|
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;
|
|
21029
|
+
return advertisedRecord(ctx, (b) => b.capabilities?.triggerBridge ?? b.triggerBridge);
|
|
20851
21030
|
}
|
|
20852
21031
|
async function ensureAdvertised6(ctx) {
|
|
20853
21032
|
const tb = await triggerBridgeCaps(ctx);
|
|
@@ -21107,10 +21286,7 @@ function exitForState4(state) {
|
|
|
21107
21286
|
return 1;
|
|
21108
21287
|
}
|
|
21109
21288
|
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;
|
|
21289
|
+
return advertisedRecord(ctx, (b) => b.capabilities?.a2a ?? b.a2a);
|
|
21114
21290
|
}
|
|
21115
21291
|
async function runStatus2(ctx, argv) {
|
|
21116
21292
|
const { options } = parseOptions(argv, { bool: ["--help"] });
|
|
@@ -21127,7 +21303,7 @@ async function runStatus2(ctx, argv) {
|
|
|
21127
21303
|
writeLine(ctx.io.stdout, "This host does not advertise A2A (capabilities.a2a absent).");
|
|
21128
21304
|
return 1;
|
|
21129
21305
|
}
|
|
21130
|
-
writeLine(ctx.io.stdout, `a2a.supported: ${a2a.supported ? "yes" : "no"}`);
|
|
21306
|
+
writeLine(ctx.io.stdout, `a2a.supported: ${a2a.supported ?? true ? "yes" : "no"}`);
|
|
21131
21307
|
if (a2a.agentCardUrl) writeLine(ctx.io.stdout, `agentCardUrl: ${a2a.agentCardUrl}`);
|
|
21132
21308
|
writeLine(ctx.io.stdout, `streaming: ${a2a.streaming ? "yes" : "no"}`);
|
|
21133
21309
|
writeLine(ctx.io.stdout, `pushNotifications: ${a2a.pushNotifications ? "yes" : "no"}`);
|
|
@@ -21316,7 +21492,7 @@ Run \`openwop docs --help\` for usage.`);
|
|
|
21316
21492
|
}
|
|
21317
21493
|
|
|
21318
21494
|
// src/cli/knowledgeSync.ts
|
|
21319
|
-
var
|
|
21495
|
+
var BASE13 = "/v1/host/openwop-app/knowledge-sync";
|
|
21320
21496
|
var KNOWLEDGE_SYNC_HELP = `Usage:
|
|
21321
21497
|
openwop knowledge-sync list --org <orgId> [--json]
|
|
21322
21498
|
openwop knowledge-sync get <sourceId> [--json]
|
|
@@ -21376,12 +21552,12 @@ async function runKnowledgeSync(ctx, argv) {
|
|
|
21376
21552
|
switch (sub) {
|
|
21377
21553
|
case "list": {
|
|
21378
21554
|
if (!options.org) return usage4(ctx, "list --org <orgId>");
|
|
21379
|
-
const res = await requestJson(ctx, withQuery(
|
|
21555
|
+
const res = await requestJson(ctx, withQuery(BASE13, { orgId: String(options.org) }));
|
|
21380
21556
|
return renderList(ctx, res.body, pickArray(res.body, "sources"), ["id", "provider", "collectionId", "cadence", "status", "lastSyncedAt"], "No sync sources.");
|
|
21381
21557
|
}
|
|
21382
21558
|
case "get": {
|
|
21383
21559
|
if (!id) return usage4(ctx, "get <sourceId>");
|
|
21384
|
-
writeJson(ctx.io.stdout, (await requestJson(ctx, `${
|
|
21560
|
+
writeJson(ctx.io.stdout, (await requestJson(ctx, `${BASE13}/${enc2(id)}`)).body);
|
|
21385
21561
|
return 0;
|
|
21386
21562
|
}
|
|
21387
21563
|
case "create": {
|
|
@@ -21397,12 +21573,12 @@ async function runKnowledgeSync(ctx, argv) {
|
|
|
21397
21573
|
if (options.cadence) body.cadence = String(options.cadence);
|
|
21398
21574
|
if (options.provider) body.provider = String(options.provider);
|
|
21399
21575
|
if (options.noMedia) body.includeMedia = false;
|
|
21400
|
-
const res = await requestJson(ctx,
|
|
21576
|
+
const res = await requestJson(ctx, BASE13, { method: "POST", body });
|
|
21401
21577
|
return renderDone(ctx, res.body, `Created sync source ${res.body?.source?.id ?? ""}.`);
|
|
21402
21578
|
}
|
|
21403
21579
|
case "browse": {
|
|
21404
21580
|
if (!options.org || !options.connection) return usage4(ctx, "browse --org <orgId> --connection <connectionId> [--folder id]");
|
|
21405
|
-
const res = await requestJson(ctx, withQuery(`${
|
|
21581
|
+
const res = await requestJson(ctx, withQuery(`${BASE13}/browse`, {
|
|
21406
21582
|
orgId: String(options.org),
|
|
21407
21583
|
connectionId: String(options.connection),
|
|
21408
21584
|
folderId: options.folder
|
|
@@ -21411,18 +21587,18 @@ async function runKnowledgeSync(ctx, argv) {
|
|
|
21411
21587
|
}
|
|
21412
21588
|
case "update": {
|
|
21413
21589
|
if (!id || !options.includeMedia && !options.noMedia) return usage4(ctx, "update <sourceId> (--include-media | --no-media)");
|
|
21414
|
-
const res = await requestJson(ctx, `${
|
|
21590
|
+
const res = await requestJson(ctx, `${BASE13}/${enc2(id)}`, { method: "PATCH", body: { includeMedia: !options.noMedia } });
|
|
21415
21591
|
return renderDone(ctx, res.body, `Updated sync source ${id} (media ${options.noMedia ? "excluded" : "included"}).`);
|
|
21416
21592
|
}
|
|
21417
21593
|
case "pause":
|
|
21418
21594
|
case "resume": {
|
|
21419
21595
|
if (!id) return usage4(ctx, `${sub} <sourceId>`);
|
|
21420
|
-
const res = await requestJson(ctx, `${
|
|
21596
|
+
const res = await requestJson(ctx, `${BASE13}/${enc2(id)}/${sub}`, { method: "POST", body: {} });
|
|
21421
21597
|
return renderDone(ctx, res.body, `${sub === "pause" ? "Paused" : "Resumed"} sync source ${id}.`);
|
|
21422
21598
|
}
|
|
21423
21599
|
case "sync": {
|
|
21424
21600
|
if (!id) return usage4(ctx, "sync <sourceId>");
|
|
21425
|
-
const res = await requestJson(ctx, `${
|
|
21601
|
+
const res = await requestJson(ctx, `${BASE13}/${enc2(id)}/sync`, { method: "POST", body: {} });
|
|
21426
21602
|
const r = res.body?.result ?? {};
|
|
21427
21603
|
const counts = Object.entries(r).filter(([, v]) => typeof v === "number").map(([k, v]) => `${k}=${v}`).join(" ");
|
|
21428
21604
|
return renderDone(ctx, res.body, `Synced source ${id}${counts ? `: ${counts}` : "."}`);
|
|
@@ -21430,7 +21606,7 @@ async function runKnowledgeSync(ctx, argv) {
|
|
|
21430
21606
|
case "delete": {
|
|
21431
21607
|
if (!id) return usage4(ctx, "delete <sourceId> [--yes]");
|
|
21432
21608
|
if (!options.yes) throw new CliError(`Refusing to delete sync source ${id} without --yes.`, 2);
|
|
21433
|
-
const res = await requestJson(ctx, `${
|
|
21609
|
+
const res = await requestJson(ctx, `${BASE13}/${enc2(id)}`, { method: "DELETE" });
|
|
21434
21610
|
return renderDone(ctx, res.body, `Deleted sync source ${id}.`);
|
|
21435
21611
|
}
|
|
21436
21612
|
default:
|
|
@@ -21442,7 +21618,7 @@ Run \`openwop knowledge-sync --help\` for usage.`);
|
|
|
21442
21618
|
// src/cli/entities.ts
|
|
21443
21619
|
import { readFileSync as readFileSync18, writeFileSync as writeFileSync14 } from "node:fs";
|
|
21444
21620
|
import { resolve as resolvePath9 } from "node:path";
|
|
21445
|
-
var
|
|
21621
|
+
var BASE14 = "/v1/host/openwop-app/entities";
|
|
21446
21622
|
var PUBLIC_BASE2 = "/v1/host/openwop-app/public-entities";
|
|
21447
21623
|
var ENTITIES_HELP = `Usage:
|
|
21448
21624
|
openwop entities locale-context [--json]
|
|
@@ -21564,7 +21740,7 @@ async function runEntities(ctx, argv) {
|
|
|
21564
21740
|
const q = (path, extra = {}) => withQuery(path, { projectId: project4, ...extra });
|
|
21565
21741
|
switch (family) {
|
|
21566
21742
|
case "locale-context": {
|
|
21567
|
-
const res = await requestJson(ctx, q(`${
|
|
21743
|
+
const res = await requestJson(ctx, q(`${BASE14}/locale-context`));
|
|
21568
21744
|
if (ctx.json) {
|
|
21569
21745
|
writeJson(ctx.io.stdout, res.body);
|
|
21570
21746
|
return 0;
|
|
@@ -21596,10 +21772,10 @@ Run \`openwop entities --help\` for usage.`);
|
|
|
21596
21772
|
}
|
|
21597
21773
|
async function types(ctx, sub, pos, o, project4, q) {
|
|
21598
21774
|
const name = pos[0];
|
|
21599
|
-
const typePath = (n) => `${
|
|
21775
|
+
const typePath = (n) => `${BASE14}/types/${enc2(n)}`;
|
|
21600
21776
|
switch (sub) {
|
|
21601
21777
|
case "list": {
|
|
21602
|
-
const res = await requestJson(ctx, q(`${
|
|
21778
|
+
const res = await requestJson(ctx, q(`${BASE14}/types`));
|
|
21603
21779
|
return renderList(
|
|
21604
21780
|
ctx,
|
|
21605
21781
|
res.body,
|
|
@@ -21623,7 +21799,7 @@ async function types(ctx, sub, pos, o, project4, q) {
|
|
|
21623
21799
|
projectId: project4
|
|
21624
21800
|
});
|
|
21625
21801
|
if (!body.name) return usage5(ctx, "types create --name <n> [--fields <json>]");
|
|
21626
|
-
const res = await requestJson(ctx, `${
|
|
21802
|
+
const res = await requestJson(ctx, `${BASE14}/types`, { method: "POST", body });
|
|
21627
21803
|
return renderDone(ctx, res.body, `Created entity type ${res.body?.name ?? body.name}.`);
|
|
21628
21804
|
}
|
|
21629
21805
|
case "update": {
|
|
@@ -21698,7 +21874,7 @@ async function types(ctx, sub, pos, o, project4, q) {
|
|
|
21698
21874
|
async function records(ctx, sub, pos, o, _project, q) {
|
|
21699
21875
|
const [type, id] = pos;
|
|
21700
21876
|
if (!type) return usage5(ctx, `${sub} <type>${sub === "list" || sub === "create" ? "" : " <entityId>"}`);
|
|
21701
|
-
const coll = `${
|
|
21877
|
+
const coll = `${BASE14}/types/${enc2(type)}/entities`;
|
|
21702
21878
|
const recordBody = () => mergeBody(ctx, o, {
|
|
21703
21879
|
values: o.values !== void 0 ? parseJsonFlag("--values", o.values) : void 0,
|
|
21704
21880
|
termIds: csv(o.termIds),
|
|
@@ -21743,7 +21919,7 @@ async function records(ctx, sub, pos, o, _project, q) {
|
|
|
21743
21919
|
async function taxonomies(ctx, sub, pos, o, project4, q) {
|
|
21744
21920
|
switch (sub) {
|
|
21745
21921
|
case "list": {
|
|
21746
|
-
const res = await requestJson(ctx, q(`${
|
|
21922
|
+
const res = await requestJson(ctx, q(`${BASE14}/taxonomies`));
|
|
21747
21923
|
return renderList(ctx, res.body, pickArray(res.body, "taxonomies"), ["name", "displayName"], "No taxonomies.");
|
|
21748
21924
|
}
|
|
21749
21925
|
case "create": {
|
|
@@ -21753,14 +21929,14 @@ async function taxonomies(ctx, sub, pos, o, project4, q) {
|
|
|
21753
21929
|
projectId: project4
|
|
21754
21930
|
});
|
|
21755
21931
|
if (!body.name) return usage5(ctx, "taxonomies create --name <n> [--display-name d]");
|
|
21756
|
-
const res = await requestJson(ctx, `${
|
|
21932
|
+
const res = await requestJson(ctx, `${BASE14}/taxonomies`, { method: "POST", body });
|
|
21757
21933
|
return renderDone(ctx, res.body, `Created taxonomy ${res.body?.name ?? body.name}.`);
|
|
21758
21934
|
}
|
|
21759
21935
|
case "delete": {
|
|
21760
21936
|
const name = pos[0];
|
|
21761
21937
|
if (!name) return usage5(ctx, "taxonomies delete <taxonomy> --yes");
|
|
21762
21938
|
confirm(o, `taxonomy ${name}`);
|
|
21763
|
-
await requestJson(ctx, q(`${
|
|
21939
|
+
await requestJson(ctx, q(`${BASE14}/taxonomies/${enc2(name)}`), { method: "DELETE" });
|
|
21764
21940
|
writeLine(ctx.io.stdout, `Deleted taxonomy ${name}.`);
|
|
21765
21941
|
return 0;
|
|
21766
21942
|
}
|
|
@@ -21771,7 +21947,7 @@ async function taxonomies(ctx, sub, pos, o, project4, q) {
|
|
|
21771
21947
|
async function terms(ctx, sub, pos, o, project4, q) {
|
|
21772
21948
|
const [tax, slug] = pos;
|
|
21773
21949
|
if (!tax) return usage5(ctx, `terms ${sub} <taxonomy>`);
|
|
21774
|
-
const coll = `${
|
|
21950
|
+
const coll = `${BASE14}/taxonomies/${enc2(tax)}/terms`;
|
|
21775
21951
|
switch (sub) {
|
|
21776
21952
|
case "list": {
|
|
21777
21953
|
const res = await requestJson(ctx, q(coll));
|
|
@@ -21823,7 +21999,7 @@ async function terms(ctx, sub, pos, o, project4, q) {
|
|
|
21823
21999
|
async function relationships(ctx, sub, pos, o, project4, q) {
|
|
21824
22000
|
switch (sub) {
|
|
21825
22001
|
case "list": {
|
|
21826
|
-
const res = await requestJson(ctx, q(`${
|
|
22002
|
+
const res = await requestJson(ctx, q(`${BASE14}/relationships`));
|
|
21827
22003
|
return renderList(ctx, res.body, pickArray(res.body, "relationships"), ["fromTypeName", "toTypeName", "cardinality", "onDelete"], "No relationships.");
|
|
21828
22004
|
}
|
|
21829
22005
|
case "create": {
|
|
@@ -21835,14 +22011,14 @@ async function relationships(ctx, sub, pos, o, project4, q) {
|
|
|
21835
22011
|
projectId: project4
|
|
21836
22012
|
});
|
|
21837
22013
|
if (!body.fromTypeName || !body.toTypeName) return usage5(ctx, "relationships create --from <type> --to <type>");
|
|
21838
|
-
const res = await requestJson(ctx, `${
|
|
22014
|
+
const res = await requestJson(ctx, `${BASE14}/relationships`, { method: "POST", body });
|
|
21839
22015
|
return renderDone(ctx, res.body, `Created relationship ${body.fromTypeName} \u2192 ${body.toTypeName}.`);
|
|
21840
22016
|
}
|
|
21841
22017
|
case "delete": {
|
|
21842
22018
|
const [from, to] = pos;
|
|
21843
22019
|
if (!from || !to) return usage5(ctx, "relationships delete <fromType> <toType> --yes");
|
|
21844
22020
|
confirm(o, `relationship ${from} \u2192 ${to}`);
|
|
21845
|
-
await requestJson(ctx, q(`${
|
|
22021
|
+
await requestJson(ctx, q(`${BASE14}/relationships/${enc2(from)}/${enc2(to)}`), { method: "DELETE" });
|
|
21846
22022
|
writeLine(ctx.io.stdout, `Deleted relationship ${from} \u2192 ${to}.`);
|
|
21847
22023
|
return 0;
|
|
21848
22024
|
}
|
|
@@ -22430,7 +22606,7 @@ Run \`openwop production --help\` for usage.`);
|
|
|
22430
22606
|
}
|
|
22431
22607
|
|
|
22432
22608
|
// src/cli/tutorials.ts
|
|
22433
|
-
var
|
|
22609
|
+
var BASE15 = "/v1/host/openwop-app/tutorials";
|
|
22434
22610
|
var TUTORIALS_HELP = `Usage:
|
|
22435
22611
|
openwop tutorials list [--json]
|
|
22436
22612
|
openwop tutorials get <slug> [--json]
|
|
@@ -22438,9 +22614,9 @@ var TUTORIALS_HELP = `Usage:
|
|
|
22438
22614
|
openwop tutorials progress set <tutorialId> --steps <id,id,...> [--json]
|
|
22439
22615
|
openwop tutorials progress clear <tutorialId> [--json]
|
|
22440
22616
|
|
|
22441
|
-
The tutorial library (GET ${
|
|
22442
|
-
\`progress\` reads YOUR saved steps (GET ${
|
|
22443
|
-
tutorial's completed steps and \`progress clear\` resets them (POST ${
|
|
22617
|
+
The tutorial library (GET ${BASE15}) and one tutorial in full (GET ${BASE15}/<slug>).
|
|
22618
|
+
\`progress\` reads YOUR saved steps (GET ${BASE15}/progress); \`progress set\` replaces a
|
|
22619
|
+
tutorial's completed steps and \`progress clear\` resets them (POST ${BASE15}/progress,
|
|
22444
22620
|
body { tutorialId, completedStepIds, mode? }). The server stamps the user \u2014 you can
|
|
22445
22621
|
only write your own progress; anonymous sessions cannot save.
|
|
22446
22622
|
|
|
@@ -22464,7 +22640,7 @@ async function runTutorials(ctx, argv) {
|
|
|
22464
22640
|
}
|
|
22465
22641
|
switch (sub) {
|
|
22466
22642
|
case "list": {
|
|
22467
|
-
const res = await requestJson(ctx,
|
|
22643
|
+
const res = await requestJson(ctx, BASE15);
|
|
22468
22644
|
const items = Array.isArray(res.body?.tutorials) ? res.body.tutorials : [];
|
|
22469
22645
|
const code = renderList(ctx, res.body, items, ["id", "category", "title", "source"], "No tutorials.");
|
|
22470
22646
|
if (!ctx.json && res.body?.degraded) writeLine(ctx.io.stdout, "(shipped copy \u2014 the tenant library was unreachable)");
|
|
@@ -22476,13 +22652,13 @@ async function runTutorials(ctx, argv) {
|
|
|
22476
22652
|
write(ctx.io.stderr, "Usage: openwop tutorials get <slug>\n");
|
|
22477
22653
|
return 2;
|
|
22478
22654
|
}
|
|
22479
|
-
writeJson(ctx.io.stdout, (await requestJson(ctx, `${
|
|
22655
|
+
writeJson(ctx.io.stdout, (await requestJson(ctx, `${BASE15}/${enc2(slug)}`)).body);
|
|
22480
22656
|
return 0;
|
|
22481
22657
|
}
|
|
22482
22658
|
case "progress": {
|
|
22483
22659
|
const action = positionals[0];
|
|
22484
22660
|
if (!action) {
|
|
22485
|
-
const res2 = await requestJson(ctx, `${
|
|
22661
|
+
const res2 = await requestJson(ctx, `${BASE15}/progress`);
|
|
22486
22662
|
const items = Array.isArray(res2.body?.progress) ? res2.body.progress : [];
|
|
22487
22663
|
const code = renderList(
|
|
22488
22664
|
ctx,
|
|
@@ -22505,7 +22681,7 @@ async function runTutorials(ctx, argv) {
|
|
|
22505
22681
|
return 2;
|
|
22506
22682
|
}
|
|
22507
22683
|
const body = action === "set" ? { tutorialId, completedStepIds: csv(options.steps) ?? [] } : { tutorialId, completedStepIds: [], mode: "clear" };
|
|
22508
|
-
const res = await requestJson(ctx, `${
|
|
22684
|
+
const res = await requestJson(ctx, `${BASE15}/progress`, { method: "POST", body });
|
|
22509
22685
|
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
22686
|
}
|
|
22511
22687
|
default:
|
|
@@ -22515,16 +22691,16 @@ Run \`openwop tutorials --help\` for usage.`);
|
|
|
22515
22691
|
}
|
|
22516
22692
|
|
|
22517
22693
|
// src/cli/walkthroughs.ts
|
|
22518
|
-
var
|
|
22694
|
+
var BASE16 = "/v1/host/openwop-app/walkthroughs";
|
|
22519
22695
|
var WALKTHROUGHS_HELP = `Usage:
|
|
22520
22696
|
openwop walkthroughs progress [--json]
|
|
22521
22697
|
openwop walkthroughs progress set <walkthroughId> --status started|completed --run <runId> [--json]
|
|
22522
22698
|
openwop walkthroughs funnel <walkthroughId> [--json]
|
|
22523
22699
|
|
|
22524
|
-
\`progress\` reads your walkthrough progress (GET ${
|
|
22525
|
-
records one (POST ${
|
|
22700
|
+
\`progress\` reads your walkthrough progress (GET ${BASE16}/progress); \`progress set\`
|
|
22701
|
+
records one (POST ${BASE16}/progress, body { walkthroughId, status, runId }).
|
|
22526
22702
|
\`funnel\` shows run-status counts + where runs stalled for one walkthrough
|
|
22527
|
-
(GET ${
|
|
22703
|
+
(GET ${BASE16}/funnel?walkthroughId=\u2026) \u2014 a recent-window view over the newest runs.
|
|
22528
22704
|
|
|
22529
22705
|
Exit codes: 0 ok \xB7 2 usage / validation / feature off \xB7 4 forbidden.
|
|
22530
22706
|
|
|
@@ -22552,10 +22728,10 @@ async function runWalkthroughs(ctx, argv) {
|
|
|
22552
22728
|
write(ctx.io.stderr, "Usage: openwop walkthroughs progress set <walkthroughId> --status started|completed --run <runId>\n");
|
|
22553
22729
|
return 2;
|
|
22554
22730
|
}
|
|
22555
|
-
const res2 = await requestJson(ctx, `${
|
|
22731
|
+
const res2 = await requestJson(ctx, `${BASE16}/progress`, { method: "POST", body: { walkthroughId, status: String(options.status), runId: String(options.run) } });
|
|
22556
22732
|
return renderDone(ctx, res2.body, `Recorded ${walkthroughId} as ${String(options.status)}.`);
|
|
22557
22733
|
}
|
|
22558
|
-
const res = await requestJson(ctx, `${
|
|
22734
|
+
const res = await requestJson(ctx, `${BASE16}/progress`);
|
|
22559
22735
|
const items = Array.isArray(res.body?.progress) ? res.body.progress : [];
|
|
22560
22736
|
return renderList(ctx, res.body, items, ["walkthroughId", "status", "runId", "updatedAt"], "No walkthrough progress.");
|
|
22561
22737
|
}
|
|
@@ -22565,7 +22741,7 @@ async function runWalkthroughs(ctx, argv) {
|
|
|
22565
22741
|
write(ctx.io.stderr, "Usage: openwop walkthroughs funnel <walkthroughId>\n");
|
|
22566
22742
|
return 2;
|
|
22567
22743
|
}
|
|
22568
|
-
const res = await requestJson(ctx, withQuery(`${
|
|
22744
|
+
const res = await requestJson(ctx, withQuery(`${BASE16}/funnel`, { walkthroughId }));
|
|
22569
22745
|
if (ctx.json) {
|
|
22570
22746
|
writeJson(ctx.io.stdout, res.body);
|
|
22571
22747
|
return 0;
|
|
@@ -22586,7 +22762,7 @@ Run \`openwop walkthroughs --help\` for usage.`);
|
|
|
22586
22762
|
}
|
|
22587
22763
|
|
|
22588
22764
|
// src/cli/widgets.ts
|
|
22589
|
-
var
|
|
22765
|
+
var BASE17 = "/v1/host/openwop-app/widgets";
|
|
22590
22766
|
var WIDGETS_HELP = `Usage:
|
|
22591
22767
|
openwop widgets list [--json]
|
|
22592
22768
|
openwop widgets summary [--json]
|
|
@@ -22594,8 +22770,8 @@ var WIDGETS_HELP = `Usage:
|
|
|
22594
22770
|
openwop widgets archive <widgetId> [--json]
|
|
22595
22771
|
openwop widgets seed [--json]
|
|
22596
22772
|
|
|
22597
|
-
The reference example domain (GET/POST ${
|
|
22598
|
-
POST ${
|
|
22773
|
+
The reference example domain (GET/POST ${BASE17}, GET ${BASE17}/summary,
|
|
22774
|
+
POST ${BASE17}/<id>/archive, POST ${BASE17}/seed). Mounted only when the host sets
|
|
22599
22775
|
OPENWOP_EXAMPLE_WIDGETS_ENABLED=true. \`seed\` is idempotent (\`seeded: false\` on a
|
|
22600
22776
|
re-run). Archiving an already-archived widget is a conflict (exit 2), never a
|
|
22601
22777
|
silent success.
|
|
@@ -22621,12 +22797,12 @@ async function runWidgets(ctx, argv) {
|
|
|
22621
22797
|
try {
|
|
22622
22798
|
switch (sub) {
|
|
22623
22799
|
case "list": {
|
|
22624
|
-
const res = await requestJson(ctx,
|
|
22800
|
+
const res = await requestJson(ctx, BASE17);
|
|
22625
22801
|
const items = Array.isArray(res.body?.widgets) ? res.body.widgets : [];
|
|
22626
22802
|
return renderList(ctx, res.body, items, ["id", "name", "status"], "No widgets.");
|
|
22627
22803
|
}
|
|
22628
22804
|
case "summary": {
|
|
22629
|
-
const res = await requestJson(ctx, `${
|
|
22805
|
+
const res = await requestJson(ctx, `${BASE17}/summary`);
|
|
22630
22806
|
if (ctx.json) {
|
|
22631
22807
|
writeJson(ctx.io.stdout, res.body);
|
|
22632
22808
|
return 0;
|
|
@@ -22640,7 +22816,7 @@ async function runWidgets(ctx, argv) {
|
|
|
22640
22816
|
write(ctx.io.stderr, "widgets create needs --name.\n");
|
|
22641
22817
|
return 2;
|
|
22642
22818
|
}
|
|
22643
|
-
const res = await requestJson(ctx,
|
|
22819
|
+
const res = await requestJson(ctx, BASE17, { method: "POST", body: { name: String(options.name) } });
|
|
22644
22820
|
return renderDone(ctx, res.body, `Created widget ${res.body?.id ?? ""} (${String(options.name)}).`);
|
|
22645
22821
|
}
|
|
22646
22822
|
case "archive": {
|
|
@@ -22649,11 +22825,11 @@ async function runWidgets(ctx, argv) {
|
|
|
22649
22825
|
write(ctx.io.stderr, "Usage: openwop widgets archive <widgetId>\n");
|
|
22650
22826
|
return 2;
|
|
22651
22827
|
}
|
|
22652
|
-
const res = await requestJson(ctx, `${
|
|
22828
|
+
const res = await requestJson(ctx, `${BASE17}/${enc2(id)}/archive`, { method: "POST", body: {} });
|
|
22653
22829
|
return renderDone(ctx, res.body, `Archived widget ${id}.`);
|
|
22654
22830
|
}
|
|
22655
22831
|
case "seed": {
|
|
22656
|
-
const res = await requestJson(ctx, `${
|
|
22832
|
+
const res = await requestJson(ctx, `${BASE17}/seed`, { method: "POST", body: {} });
|
|
22657
22833
|
return renderDone(ctx, res.body, res.body?.seeded === false ? "Example widgets already seeded (no-op)." : "Seeded example widgets.");
|
|
22658
22834
|
}
|
|
22659
22835
|
default:
|
|
@@ -22673,17 +22849,17 @@ Run \`openwop widgets --help\` for usage.`);
|
|
|
22673
22849
|
}
|
|
22674
22850
|
|
|
22675
22851
|
// src/cli/uiState.ts
|
|
22676
|
-
var
|
|
22852
|
+
var BASE18 = "/v1/host/openwop-app/ui-state";
|
|
22677
22853
|
var UI_STATE_HELP = `Usage:
|
|
22678
22854
|
openwop ui-state list [--resource-type <t>] [--resource-id <id>] [--json]
|
|
22679
22855
|
openwop ui-state get <resourceType> <resourceId> <key> [--json]
|
|
22680
22856
|
openwop ui-state set <resourceType> <resourceId> <key> --value <json> [--json]
|
|
22681
22857
|
openwop ui-state delete <resourceType> <resourceId> <key>
|
|
22682
22858
|
|
|
22683
|
-
\`list\` reads your rows (GET ${
|
|
22684
|
-
key from that list. \`set\` writes one key (PUT ${
|
|
22859
|
+
\`list\` reads your rows (GET ${BASE18}?resourceType=&resourceId=); \`get\` filters one
|
|
22860
|
+
key from that list. \`set\` writes one key (PUT ${BASE18}, body { resourceType,
|
|
22685
22861
|
resourceId, key, value }); --value is parsed as JSON, falling back to a string.
|
|
22686
|
-
\`delete\` removes one key (DELETE ${
|
|
22862
|
+
\`delete\` removes one key (DELETE ${BASE18}/<type>/<id>/<key>).
|
|
22687
22863
|
|
|
22688
22864
|
Exit codes: 0 ok \xB7 2 usage / not found \xB7 4 forbidden.
|
|
22689
22865
|
|
|
@@ -22706,7 +22882,7 @@ async function runUiState(ctx, argv) {
|
|
|
22706
22882
|
const [resourceType, resourceId, key] = positionals;
|
|
22707
22883
|
switch (sub) {
|
|
22708
22884
|
case "list": {
|
|
22709
|
-
const res = await requestJson(ctx, withQuery(
|
|
22885
|
+
const res = await requestJson(ctx, withQuery(BASE18, { resourceType: options.resourceType, resourceId: options.resourceId }));
|
|
22710
22886
|
const items = Array.isArray(res.body?.items) ? res.body.items : [];
|
|
22711
22887
|
return renderList(ctx, res.body, items, ["resourceType", "resourceId", "key", "value"], "No saved UI state.");
|
|
22712
22888
|
}
|
|
@@ -22715,7 +22891,7 @@ async function runUiState(ctx, argv) {
|
|
|
22715
22891
|
write(ctx.io.stderr, "Usage: openwop ui-state get <resourceType> <resourceId> <key>\n");
|
|
22716
22892
|
return 2;
|
|
22717
22893
|
}
|
|
22718
|
-
const res = await requestJson(ctx, withQuery(
|
|
22894
|
+
const res = await requestJson(ctx, withQuery(BASE18, { resourceType, resourceId }));
|
|
22719
22895
|
const items = Array.isArray(res.body?.items) ? res.body.items : [];
|
|
22720
22896
|
const hit = items.find((i) => i?.key === key);
|
|
22721
22897
|
if (!hit) throw new CliError(`No ui-state for ${resourceType}/${resourceId}/${key}.`, 2);
|
|
@@ -22734,7 +22910,7 @@ async function runUiState(ctx, argv) {
|
|
|
22734
22910
|
} catch {
|
|
22735
22911
|
value = String(options.value);
|
|
22736
22912
|
}
|
|
22737
|
-
const res = await requestJson(ctx,
|
|
22913
|
+
const res = await requestJson(ctx, BASE18, { method: "PUT", body: { resourceType, resourceId, key, value } });
|
|
22738
22914
|
return renderDone(ctx, res.body, `Saved ${resourceType}/${resourceId}/${key}.`);
|
|
22739
22915
|
}
|
|
22740
22916
|
case "delete": {
|
|
@@ -22742,7 +22918,7 @@ async function runUiState(ctx, argv) {
|
|
|
22742
22918
|
write(ctx.io.stderr, "Usage: openwop ui-state delete <resourceType> <resourceId> <key>\n");
|
|
22743
22919
|
return 2;
|
|
22744
22920
|
}
|
|
22745
|
-
await requestJson(ctx, `${
|
|
22921
|
+
await requestJson(ctx, `${BASE18}/${enc2(resourceType)}/${enc2(resourceId)}/${enc2(key)}`, { method: "DELETE" });
|
|
22746
22922
|
writeLine(ctx.io.stdout, `Deleted ${resourceType}/${resourceId}/${key}.`);
|
|
22747
22923
|
return 0;
|
|
22748
22924
|
}
|
|
@@ -22755,8 +22931,8 @@ Run \`openwop ui-state --help\` for usage.`);
|
|
|
22755
22931
|
// src/cli/uiPlugin.ts
|
|
22756
22932
|
import { writeFileSync as writeFileSync16 } from "node:fs";
|
|
22757
22933
|
import { resolve as resolvePath11 } from "node:path";
|
|
22758
|
-
var
|
|
22759
|
-
var RPC_PRODUCT = `${
|
|
22934
|
+
var BASE19 = "/v1/host/openwop-app/ui-plugin";
|
|
22935
|
+
var RPC_PRODUCT = `${BASE19}/rpc`;
|
|
22760
22936
|
var RPC_CONFORMANCE = "/v1/host/sample/ui-plugin/rpc";
|
|
22761
22937
|
var UI_PLUGIN_HELP = `Usage:
|
|
22762
22938
|
openwop ui-plugin packs [--json]
|
|
@@ -22767,11 +22943,11 @@ var UI_PLUGIN_HELP = `Usage:
|
|
|
22767
22943
|
openwop ui-plugin rpc --body <json> | --body-file <path>
|
|
22768
22944
|
|
|
22769
22945
|
\`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 ${
|
|
22946
|
+
(GET ${BASE19}/packs). \`entry\` fetches a plugin's sandboxed entry bundle
|
|
22947
|
+
(GET ${BASE19}/packs/<name>/plugins/<id>/entry); \`trusted-entry\` fetches a signed
|
|
22948
|
+
pack's main-frame ES module (GET ${BASE19}/trusted/<name>/plugins/<id>/entry.mjs \u2014
|
|
22773
22949
|
404 unless the trusted-plugins toggle is on and the signature verifies).
|
|
22774
|
-
\`demo-artifact\` ensures the idempotent demo artifact (POST ${
|
|
22950
|
+
\`demo-artifact\` ensures the idempotent demo artifact (POST ${BASE19}/demo-artifact).
|
|
22775
22951
|
\`rpc\` sends one ui-plugin/1 request (POST ${RPC_PRODUCT}, body { message }); the
|
|
22776
22952
|
message is { openwop: "ui-plugin/1", type: "request", id (integer,
|
|
22777
22953
|
default 1), method, params } unless you pass a
|
|
@@ -22812,7 +22988,7 @@ async function runUiPlugin(ctx, argv) {
|
|
|
22812
22988
|
}
|
|
22813
22989
|
switch (sub) {
|
|
22814
22990
|
case "packs": {
|
|
22815
|
-
const res = await requestJson(ctx, `${
|
|
22991
|
+
const res = await requestJson(ctx, `${BASE19}/packs`);
|
|
22816
22992
|
const items = Array.isArray(res.body?.plugins) ? res.body.plugins : [];
|
|
22817
22993
|
const code = renderList(ctx, res.body, items, ["packName", "pluginId", "tier"], "No UI plugins served.");
|
|
22818
22994
|
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 +23002,7 @@ async function runUiPlugin(ctx, argv) {
|
|
|
22826
23002
|
`);
|
|
22827
23003
|
return 2;
|
|
22828
23004
|
}
|
|
22829
|
-
const path = sub === "entry" ? `${
|
|
23005
|
+
const path = sub === "entry" ? `${BASE19}/packs/${enc2(name)}/plugins/${enc2(pluginId)}/entry` : `${BASE19}/trusted/${enc2(name)}/plugins/${enc2(pluginId)}/entry.mjs`;
|
|
22830
23006
|
const res = await fetchRawText(ctx, path);
|
|
22831
23007
|
if (options.output) {
|
|
22832
23008
|
writeFileSync16(resolvePath11(ctx.cwd, String(options.output)), res.text);
|
|
@@ -22838,7 +23014,7 @@ async function runUiPlugin(ctx, argv) {
|
|
|
22838
23014
|
return 0;
|
|
22839
23015
|
}
|
|
22840
23016
|
case "demo-artifact": {
|
|
22841
|
-
const res = await requestJson(ctx, `${
|
|
23017
|
+
const res = await requestJson(ctx, `${BASE19}/demo-artifact`, { method: "POST", body: {} });
|
|
22842
23018
|
return renderDone(ctx, res.body, `Demo artifact ${res.body?.artifactId ?? ""} (version ${res.body?.version ?? ""}).`);
|
|
22843
23019
|
}
|
|
22844
23020
|
case "rpc": {
|
|
@@ -22868,18 +23044,18 @@ Run \`openwop ui-plugin --help\` for usage.`);
|
|
|
22868
23044
|
}
|
|
22869
23045
|
|
|
22870
23046
|
// src/cli/canvasCollab.ts
|
|
22871
|
-
var
|
|
23047
|
+
var BASE20 = "/v1/host/openwop-app/canvas-collab";
|
|
22872
23048
|
var CANVAS_COLLAB_HELP = `Usage:
|
|
22873
23049
|
openwop canvas-collab ticket <canvasId> [--json]
|
|
22874
23050
|
openwop canvas-collab claim-seed <canvasId> [--json]
|
|
22875
23051
|
openwop canvas-collab debug [--json]
|
|
22876
23052
|
|
|
22877
23053
|
\`ticket\` mints a short-lived collaboration ticket for one canvas
|
|
22878
|
-
(POST ${
|
|
23054
|
+
(POST ${BASE20}/<canvasId>/ticket) \u2014 a credential for the collaboration socket's
|
|
22879
23055
|
?ticket= parameter; it is printed once and never stored. \`claim-seed\` runs the
|
|
22880
|
-
seeder election (POST ${
|
|
23056
|
+
seeder election (POST ${BASE20}/<canvasId>/claim-seed) \u2192 { seed: true } for the one
|
|
22881
23057
|
caller that should seed a fresh room. \`debug\` lists this server instance's live
|
|
22882
|
-
rooms (GET ${
|
|
23058
|
+
rooms (GET ${BASE20}/_debug; super-admin only; lifecycle metadata, never content).
|
|
22883
23059
|
|
|
22884
23060
|
Exit codes: 0 ok \xB7 2 usage / not found (uniform) \xB7 4 forbidden (debug without super-admin).
|
|
22885
23061
|
|
|
@@ -22913,7 +23089,7 @@ async function runCanvasCollab(ctx, argv) {
|
|
|
22913
23089
|
write(ctx.io.stderr, "Usage: openwop canvas-collab ticket <canvasId>\n");
|
|
22914
23090
|
return 2;
|
|
22915
23091
|
}
|
|
22916
|
-
const res = await requestJson(ctx, `${
|
|
23092
|
+
const res = await requestJson(ctx, `${BASE20}/${enc2(id)}/ticket`, { method: "POST", body: {} });
|
|
22917
23093
|
return printTicketOnce(ctx, res.body, `canvas ${id}`);
|
|
22918
23094
|
}
|
|
22919
23095
|
case "claim-seed": {
|
|
@@ -22921,13 +23097,13 @@ async function runCanvasCollab(ctx, argv) {
|
|
|
22921
23097
|
write(ctx.io.stderr, "Usage: openwop canvas-collab claim-seed <canvasId>\n");
|
|
22922
23098
|
return 2;
|
|
22923
23099
|
}
|
|
22924
|
-
const res = await requestJson(ctx, `${
|
|
23100
|
+
const res = await requestJson(ctx, `${BASE20}/${enc2(id)}/claim-seed`, { method: "POST", body: {} });
|
|
22925
23101
|
if (ctx.json) writeJson(ctx.io.stdout, res.body);
|
|
22926
23102
|
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
23103
|
return 0;
|
|
22928
23104
|
}
|
|
22929
23105
|
case "debug": {
|
|
22930
|
-
const res = await requestJson(ctx, `${
|
|
23106
|
+
const res = await requestJson(ctx, `${BASE20}/_debug`);
|
|
22931
23107
|
const items = Array.isArray(res.body?.instanceRooms) ? res.body.instanceRooms : [];
|
|
22932
23108
|
return renderList(ctx, res.body, items, ["roomId", "tenantId", "clients", "openedAt"], "No live collaboration rooms on this instance.");
|
|
22933
23109
|
}
|
|
@@ -22938,14 +23114,14 @@ Run \`openwop canvas-collab --help\` for usage.`);
|
|
|
22938
23114
|
}
|
|
22939
23115
|
|
|
22940
23116
|
// src/cli/workflowCollab.ts
|
|
22941
|
-
var
|
|
23117
|
+
var BASE21 = "/v1/host/openwop-app/workflow-collab";
|
|
22942
23118
|
var WORKFLOW_COLLAB_HELP = `Usage:
|
|
22943
23119
|
openwop workflow-collab ticket <workflowId> [--json]
|
|
22944
23120
|
openwop workflow-collab claim-seed <workflowId> [--json]
|
|
22945
23121
|
|
|
22946
23122
|
\`ticket\` mints a short-lived collaboration ticket for one workflow draft
|
|
22947
|
-
(POST ${
|
|
22948
|
-
the seeder election (POST ${
|
|
23123
|
+
(POST ${BASE21}/<workflowId>/ticket) \u2014 shown once, never stored. \`claim-seed\` runs
|
|
23124
|
+
the seeder election (POST ${BASE21}/<workflowId>/claim-seed) \u2192 { seed }.
|
|
22949
23125
|
|
|
22950
23126
|
Exit codes: 0 ok \xB7 2 usage / not found / feature off \xB7 4 forbidden.
|
|
22951
23127
|
|
|
@@ -22972,11 +23148,11 @@ async function runWorkflowCollab(ctx, argv) {
|
|
|
22972
23148
|
}
|
|
22973
23149
|
switch (sub) {
|
|
22974
23150
|
case "ticket": {
|
|
22975
|
-
const res = await requestJson(ctx, `${
|
|
23151
|
+
const res = await requestJson(ctx, `${BASE21}/${enc2(id)}/ticket`, { method: "POST", body: {} });
|
|
22976
23152
|
return printTicketOnce(ctx, res.body, `workflow ${id}`);
|
|
22977
23153
|
}
|
|
22978
23154
|
case "claim-seed": {
|
|
22979
|
-
const res = await requestJson(ctx, `${
|
|
23155
|
+
const res = await requestJson(ctx, `${BASE21}/${enc2(id)}/claim-seed`, { method: "POST", body: {} });
|
|
22980
23156
|
if (ctx.json) writeJson(ctx.io.stdout, res.body);
|
|
22981
23157
|
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
23158
|
return 0;
|
|
@@ -23020,7 +23196,7 @@ Run \`openwop canvas-packs --help\` for usage.`);
|
|
|
23020
23196
|
}
|
|
23021
23197
|
|
|
23022
23198
|
// src/cli/present.ts
|
|
23023
|
-
var
|
|
23199
|
+
var BASE22 = "/v1/host/openwop-app/present";
|
|
23024
23200
|
var ACTIONS = ["next", "prev", "goto", "blank"];
|
|
23025
23201
|
var PRESENT_HELP = `Usage:
|
|
23026
23202
|
openwop present outline <token> [--json]
|
|
@@ -23030,11 +23206,11 @@ var PRESENT_HELP = `Usage:
|
|
|
23030
23206
|
openwop present events <token> [--max <n>] [--timeout <seconds>] [--json]
|
|
23031
23207
|
|
|
23032
23208
|
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 ${
|
|
23209
|
+
credential). \`outline\` reads { title, frames, current? } (GET ${BASE22}/<token>/outline).
|
|
23210
|
+
\`command\` sends a navigation command (POST ${BASE22}/<token>/command, body
|
|
23035
23211
|
{ action, index? }). \`state\` reports the presenter's current frame
|
|
23036
|
-
(POST ${
|
|
23037
|
-
feed (GET ${
|
|
23212
|
+
(POST ${BASE22}/<token>/state, body { current }). \`events\` follows the navigation
|
|
23213
|
+
feed (GET ${BASE22}/<token>/events, server-sent events) \u2014 one line per event, or one
|
|
23038
23214
|
JSON object per line with --json; stops after --max events or --timeout seconds.
|
|
23039
23215
|
|
|
23040
23216
|
Exit codes: 0 ok \xB7 2 usage / unknown or expired session.
|
|
@@ -23061,7 +23237,7 @@ async function runPresent(ctx, argv) {
|
|
|
23061
23237
|
`);
|
|
23062
23238
|
return 2;
|
|
23063
23239
|
}
|
|
23064
|
-
const base16 = `${
|
|
23240
|
+
const base16 = `${BASE22}/${enc2(token)}`;
|
|
23065
23241
|
switch (sub) {
|
|
23066
23242
|
case "outline": {
|
|
23067
23243
|
const res = await requestJson(ctx, `${base16}/outline`, { auth: false });
|
|
@@ -24069,8 +24245,8 @@ async function runCampaignBrief(ctx, argv) {
|
|
|
24069
24245
|
}
|
|
24070
24246
|
|
|
24071
24247
|
// src/cli/campaignConnectors.ts
|
|
24072
|
-
var
|
|
24073
|
-
var orgBase2 = (org2) => `${
|
|
24248
|
+
var BASE23 = `${APP}/campaign-connectors`;
|
|
24249
|
+
var orgBase2 = (org2) => `${BASE23}/orgs/${enc2(org2)}`;
|
|
24074
24250
|
var CAMPAIGN_CONNECTORS_HELP = `Usage:
|
|
24075
24251
|
openwop campaign-connectors platforms [--json]
|
|
24076
24252
|
openwop campaign-connectors sync --org <orgId> --platform meta|google [--json]
|
|
@@ -24119,7 +24295,7 @@ var TABLE2 = {
|
|
|
24119
24295
|
usage: "platforms [--json]",
|
|
24120
24296
|
args: 0,
|
|
24121
24297
|
run: async (ctx) => {
|
|
24122
|
-
const body = (await requestJson(ctx, `${
|
|
24298
|
+
const body = (await requestJson(ctx, `${BASE23}/platforms`)).body;
|
|
24123
24299
|
if (ctx.json) {
|
|
24124
24300
|
writeJson(ctx.io.stdout, body);
|
|
24125
24301
|
return 0;
|
|
@@ -24136,7 +24312,7 @@ var TABLE2 = {
|
|
|
24136
24312
|
requires: ["platform"],
|
|
24137
24313
|
run: async (ctx, a) => {
|
|
24138
24314
|
const req2 = assign({ ...a.body }, { orgId: orgOf(a), platform: a.options.platform });
|
|
24139
|
-
const body = (await requestJson(ctx, `${
|
|
24315
|
+
const body = (await requestJson(ctx, `${BASE23}/sync`, { method: "POST", body: req2 })).body;
|
|
24140
24316
|
return done(ctx, body, `Sync ${body?.outcome ?? "done"}${body?.imported !== void 0 ? ` (${body.imported} imported)` : ""}.`);
|
|
24141
24317
|
}
|
|
24142
24318
|
},
|
|
@@ -24149,7 +24325,7 @@ var TABLE2 = {
|
|
|
24149
24325
|
run: async (ctx, a) => {
|
|
24150
24326
|
const o = a.options;
|
|
24151
24327
|
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, `${
|
|
24328
|
+
const body = (await requestJson(ctx, `${BASE23}/audience-sync`, { method: "POST", body: req2 })).body;
|
|
24153
24329
|
return done(ctx, body, `Audience sync: ${body?.outcome ?? "done"}.`);
|
|
24154
24330
|
}
|
|
24155
24331
|
},
|
|
@@ -24172,7 +24348,7 @@ var TABLE2 = {
|
|
|
24172
24348
|
writeLine(ctx.io.stderr, "openwop: missing --csv-file");
|
|
24173
24349
|
return 2;
|
|
24174
24350
|
}
|
|
24175
|
-
const body = (await requestJson(ctx, `${
|
|
24351
|
+
const body = (await requestJson(ctx, `${BASE23}/import`, { method: "POST", body: req2 })).body;
|
|
24176
24352
|
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
24353
|
}
|
|
24178
24354
|
},
|
|
@@ -24182,7 +24358,7 @@ var TABLE2 = {
|
|
|
24182
24358
|
value: ["--org", "--campaign"],
|
|
24183
24359
|
run: async (ctx, a) => listOut(
|
|
24184
24360
|
ctx,
|
|
24185
|
-
(await requestJson(ctx, `${
|
|
24361
|
+
(await requestJson(ctx, `${BASE23}/records${qs({ orgId: orgOf(a), campaignId: a.options.campaign })}`)).body,
|
|
24186
24362
|
"records",
|
|
24187
24363
|
["date", "platform", "campaignId", "impressions", "clicks", "spend", "conversions"],
|
|
24188
24364
|
"No performance records."
|
|
@@ -24192,7 +24368,7 @@ var TABLE2 = {
|
|
|
24192
24368
|
usage: "kpi --org <orgId> [--campaign <id>] [--json]",
|
|
24193
24369
|
args: 0,
|
|
24194
24370
|
value: ["--org", "--campaign"],
|
|
24195
|
-
run: async (ctx, a) => detail(ctx, (await requestJson(ctx, `${
|
|
24371
|
+
run: async (ctx, a) => detail(ctx, (await requestJson(ctx, `${BASE23}/kpi${qs({ orgId: orgOf(a), campaignId: a.options.campaign })}`)).body)
|
|
24196
24372
|
},
|
|
24197
24373
|
"sync-status": {
|
|
24198
24374
|
usage: "sync-status --org <orgId> [--json]",
|
|
@@ -24314,7 +24490,7 @@ async function runCampaignConnectors(ctx, argv) {
|
|
|
24314
24490
|
}
|
|
24315
24491
|
|
|
24316
24492
|
// src/cli/campaignIntel.ts
|
|
24317
|
-
var
|
|
24493
|
+
var BASE24 = `${APP}/campaign-intel`;
|
|
24318
24494
|
var CAMPAIGN_INTEL_HELP = `Usage:
|
|
24319
24495
|
openwop campaign-intel budget --org <orgId> [--campaign <id>] [--json]
|
|
24320
24496
|
openwop campaign-intel forecast --org <orgId> [--campaign <id>] [--json]
|
|
@@ -24353,7 +24529,7 @@ var read = (name, withCampaign) => ({
|
|
|
24353
24529
|
args: 0,
|
|
24354
24530
|
value: ["--org", ...withCampaign ? ["--campaign"] : []],
|
|
24355
24531
|
run: async (ctx, a) => {
|
|
24356
|
-
const body = (await requestJson(ctx, `${
|
|
24532
|
+
const body = (await requestJson(ctx, `${BASE24}/${name}${qs({ orgId: orgOf2(a), campaignId: withCampaign ? a.options.campaign : void 0 })}`)).body;
|
|
24357
24533
|
if (name === "anomalies") return listOut(ctx, body, "anomalies", ["date", "platform", "campaignId", "metric", "severity", "message"], "No anomalies.");
|
|
24358
24534
|
if (name === "forecast") return listOut(ctx, body, "forecasts", ["campaignId", "platform", "horizonDays", "projectedSpend", "projectedConversions"], "No forecasts (no performance records).");
|
|
24359
24535
|
return detail(ctx, body);
|
|
@@ -24388,7 +24564,7 @@ var TABLE3 = {
|
|
|
24388
24564
|
return 2;
|
|
24389
24565
|
}
|
|
24390
24566
|
}
|
|
24391
|
-
return detail(ctx, (await requestJson(ctx, `${
|
|
24567
|
+
return detail(ctx, (await requestJson(ctx, `${BASE24}/plan-budget`, { method: "POST", body: req2 })).body);
|
|
24392
24568
|
}
|
|
24393
24569
|
},
|
|
24394
24570
|
apply: {
|
|
@@ -24413,7 +24589,7 @@ var TABLE3 = {
|
|
|
24413
24589
|
dailyBudgetMinor: o.dailyBudgetMinor !== void 0 ? num(o.dailyBudgetMinor, "--daily-budget-minor") : void 0,
|
|
24414
24590
|
dryRun: dryRun ? true : void 0
|
|
24415
24591
|
});
|
|
24416
|
-
const body = (await requestJson(ctx, `${
|
|
24592
|
+
const body = (await requestJson(ctx, `${BASE24}/recommendations/apply`, { method: "POST", body: req2 })).body;
|
|
24417
24593
|
return done(ctx, body, `Budget ${dryRun ? "preview" : "update"}: ${body?.outcome ?? "done"}.`);
|
|
24418
24594
|
}
|
|
24419
24595
|
}
|
|
@@ -24473,7 +24649,7 @@ async function runCampaignJourneys(ctx, argv) {
|
|
|
24473
24649
|
}
|
|
24474
24650
|
|
|
24475
24651
|
// src/cli/cdp.ts
|
|
24476
|
-
var
|
|
24652
|
+
var BASE25 = `${APP}/cdp`;
|
|
24477
24653
|
var CDP_HELP = `Usage:
|
|
24478
24654
|
openwop cdp resolve --type <identifierType> --value <v> [--json]
|
|
24479
24655
|
openwop cdp schemas list [--json]
|
|
@@ -24520,7 +24696,7 @@ var limited = (path, key, columns, empty) => ({
|
|
|
24520
24696
|
usage: `${path === "governance-decisions" ? "governance" : path === "collected-events" ? "events" : path} [--limit <n>] [--json]`,
|
|
24521
24697
|
args: 0,
|
|
24522
24698
|
value: ["--limit"],
|
|
24523
|
-
run: async (ctx, a) => listOut(ctx, (await requestJson(ctx, `${
|
|
24699
|
+
run: async (ctx, a) => listOut(ctx, (await requestJson(ctx, `${BASE25}/${path}${qs({ limit: a.options.limit })}`)).body, key, columns, empty)
|
|
24524
24700
|
});
|
|
24525
24701
|
var TABLE5 = {
|
|
24526
24702
|
resolve: {
|
|
@@ -24528,7 +24704,7 @@ var TABLE5 = {
|
|
|
24528
24704
|
args: 0,
|
|
24529
24705
|
value: ["--type", "--value"],
|
|
24530
24706
|
requires: ["type", "value"],
|
|
24531
|
-
run: async (ctx, a) => detail(ctx, (await requestJson(ctx, `${
|
|
24707
|
+
run: async (ctx, a) => detail(ctx, (await requestJson(ctx, `${BASE25}/identity/resolve${qs({ type: a.options.type, value: a.options.value })}`)).body)
|
|
24532
24708
|
},
|
|
24533
24709
|
collect: {
|
|
24534
24710
|
usage: "collect --event-type <t> [--payload-json '{...}'] [--dedupe-key <k>] [--json]",
|
|
@@ -24543,7 +24719,7 @@ var TABLE5 = {
|
|
|
24543
24719
|
payload: o.payloadJson !== void 0 ? parseJsonFlag2(o.payloadJson, "--payload-json") : void 0,
|
|
24544
24720
|
dedupeKey: o.dedupeKey
|
|
24545
24721
|
});
|
|
24546
|
-
const body = (await requestJson(ctx, `${
|
|
24722
|
+
const body = (await requestJson(ctx, `${BASE25}/collect`, { method: "POST", body: req2 })).body;
|
|
24547
24723
|
return done(ctx, body, `Collected ${req2.eventType} event ${body?.eventId ?? body?.event?.eventId ?? ""}${body?.deduped ? " (deduplicated)" : ""}.`);
|
|
24548
24724
|
}
|
|
24549
24725
|
},
|
|
@@ -24558,7 +24734,7 @@ var TABLE5 = {
|
|
|
24558
24734
|
writeLine(ctx.io.stderr, "openwop: missing --events-json or --events-file");
|
|
24559
24735
|
return 2;
|
|
24560
24736
|
}
|
|
24561
|
-
return detail(ctx, (await requestJson(ctx, `${
|
|
24737
|
+
return detail(ctx, (await requestJson(ctx, `${BASE25}/collect/batch`, { method: "POST", body: req2 })).body);
|
|
24562
24738
|
}
|
|
24563
24739
|
},
|
|
24564
24740
|
import: {
|
|
@@ -24578,7 +24754,7 @@ var TABLE5 = {
|
|
|
24578
24754
|
writeLine(ctx.io.stderr, "openwop: missing --csv-file");
|
|
24579
24755
|
return 2;
|
|
24580
24756
|
}
|
|
24581
|
-
return detail(ctx, (await requestJson(ctx, `${
|
|
24757
|
+
return detail(ctx, (await requestJson(ctx, `${BASE25}/collect/import`, { method: "POST", body: req2 })).body);
|
|
24582
24758
|
}
|
|
24583
24759
|
},
|
|
24584
24760
|
events: limited("collected-events", "events", ["eventId", "eventType", ["at", (e) => e.at ?? e.receivedAt ?? e.createdAt], "dedupeKey"], "No collected events."),
|
|
@@ -24588,7 +24764,7 @@ var TABLE5 = {
|
|
|
24588
24764
|
usage: "audit-verify [--json]",
|
|
24589
24765
|
args: 0,
|
|
24590
24766
|
run: async (ctx) => {
|
|
24591
|
-
const body = (await requestJson(ctx, `${
|
|
24767
|
+
const body = (await requestJson(ctx, `${BASE25}/audit-chain/verify`)).body;
|
|
24592
24768
|
if (ctx.json) {
|
|
24593
24769
|
writeJson(ctx.io.stdout, body);
|
|
24594
24770
|
return body?.valid === false || body?.ok === false ? 1 : 0;
|
|
@@ -24606,7 +24782,7 @@ var SCHEMAS = {
|
|
|
24606
24782
|
args: 0,
|
|
24607
24783
|
run: async (ctx) => listOut(
|
|
24608
24784
|
ctx,
|
|
24609
|
-
(await requestJson(ctx, `${
|
|
24785
|
+
(await requestJson(ctx, `${BASE25}/event-schemas`)).body,
|
|
24610
24786
|
"schemas",
|
|
24611
24787
|
["eventType", "version", ["updatedAt", (s) => s.updatedAt ?? s.registeredAt ?? s.createdAt]],
|
|
24612
24788
|
"No event schemas registered."
|
|
@@ -24627,7 +24803,7 @@ var SCHEMAS = {
|
|
|
24627
24803
|
writeLine(ctx.io.stderr, "openwop: missing --schema-json or --schema-file");
|
|
24628
24804
|
return 2;
|
|
24629
24805
|
}
|
|
24630
|
-
const body = (await requestJson(ctx, `${
|
|
24806
|
+
const body = (await requestJson(ctx, `${BASE25}/event-schemas`, { method: "POST", body: req2 })).body;
|
|
24631
24807
|
return done(ctx, body, `Registered the ${req2.eventType} event schema${body?.version !== void 0 ? ` (version ${body.version})` : ""}.`);
|
|
24632
24808
|
}
|
|
24633
24809
|
},
|
|
@@ -24640,7 +24816,7 @@ var SCHEMAS = {
|
|
|
24640
24816
|
const req2 = assign({ ...a.body }, { payload: jsonFrom(ctx, a.options.payloadJson, a.options.payloadFile, "--payload-json", "--payload-file") });
|
|
24641
24817
|
let body;
|
|
24642
24818
|
try {
|
|
24643
|
-
body = (await requestJson(ctx, `${
|
|
24819
|
+
body = (await requestJson(ctx, `${BASE25}/event-schemas/${enc2(a.positionals[0])}/validate`, { method: "POST", body: req2 })).body;
|
|
24644
24820
|
} catch (err) {
|
|
24645
24821
|
if (!(err instanceof HttpError) || err.status !== 422) throw err;
|
|
24646
24822
|
body = err.body;
|
|
@@ -24664,7 +24840,7 @@ async function runCdp(ctx, argv) {
|
|
|
24664
24840
|
}
|
|
24665
24841
|
|
|
24666
24842
|
// src/cli/destinationSync.ts
|
|
24667
|
-
var
|
|
24843
|
+
var BASE26 = `${APP}/destination-sync/syncs`;
|
|
24668
24844
|
var DESTINATION_SYNC_HELP = `Usage:
|
|
24669
24845
|
openwop destination-sync list [--json]
|
|
24670
24846
|
openwop destination-sync get <syncId> [--json]
|
|
@@ -24698,14 +24874,14 @@ function jsonFrom2(ctx, inline, file, inlineFlag, fileFlag) {
|
|
|
24698
24874
|
if (file !== void 0) return parseJsonFlag2(readText(ctx, String(file), fileFlag), fileFlag);
|
|
24699
24875
|
return void 0;
|
|
24700
24876
|
}
|
|
24701
|
-
var item = (id) => `${
|
|
24877
|
+
var item = (id) => `${BASE26}/${enc2(id)}`;
|
|
24702
24878
|
var TABLE6 = {
|
|
24703
24879
|
list: {
|
|
24704
24880
|
usage: "list [--json]",
|
|
24705
24881
|
args: 0,
|
|
24706
24882
|
run: async (ctx) => listOut(
|
|
24707
24883
|
ctx,
|
|
24708
|
-
(await requestJson(ctx,
|
|
24884
|
+
(await requestJson(ctx, BASE26)).body,
|
|
24709
24885
|
"syncs",
|
|
24710
24886
|
[["id", (s) => s.id ?? s.syncId], "name", "destinationKind", "sourceObject", "syncMode", "cursor"],
|
|
24711
24887
|
"No destination syncs."
|
|
@@ -24733,7 +24909,7 @@ var TABLE6 = {
|
|
|
24733
24909
|
cursorField: o.cursorField,
|
|
24734
24910
|
connectionId: o.connection
|
|
24735
24911
|
});
|
|
24736
|
-
const body = (await requestJson(ctx,
|
|
24912
|
+
const body = (await requestJson(ctx, BASE26, { method: "POST", body: req2 })).body;
|
|
24737
24913
|
return done(ctx, body, `Created destination sync ${body?.id ?? body?.syncId ?? ""} (${req2.name}).`);
|
|
24738
24914
|
}
|
|
24739
24915
|
},
|
|
@@ -25563,7 +25739,7 @@ async function runPublic(ctx, argv) {
|
|
|
25563
25739
|
}
|
|
25564
25740
|
|
|
25565
25741
|
// src/cli/vault.ts
|
|
25566
|
-
var
|
|
25742
|
+
var BASE27 = "/v1/host/openwop-app/vault";
|
|
25567
25743
|
var SURFACE2 = "The secrets vault";
|
|
25568
25744
|
var VAULT_HELP = `Usage:
|
|
25569
25745
|
openwop vault list [--json]
|
|
@@ -25575,10 +25751,10 @@ The super-admin secrets vault (host extension). Every route is SUPER-ADMIN gated
|
|
|
25575
25751
|
without a super-admin principal the command fails closed with exit 4 and says how to
|
|
25576
25752
|
get one (OPENWOP_SUPERADMIN_TENANTS on the server).
|
|
25577
25753
|
|
|
25578
|
-
list GET ${
|
|
25579
|
-
set POST ${
|
|
25580
|
-
rotate POST ${
|
|
25581
|
-
delete DELETE ${
|
|
25754
|
+
list GET ${BASE27} inventory of refs (never values)
|
|
25755
|
+
set POST ${BASE27}/secrets store a new secret under a ref
|
|
25756
|
+
rotate POST ${BASE27}/secrets/:credentialRef/rotate overwrite an EXISTING secret
|
|
25757
|
+
delete DELETE ${BASE27}/secrets/:credentialRef remove (refused while the ref has live consumers unless --force)
|
|
25582
25758
|
|
|
25583
25759
|
SECRETS ARE REFS, NEVER VALUES. The value for set/rotate is read from --value-file or a
|
|
25584
25760
|
no-echo prompt (a piped line also works) \u2014 never from a command-line flag. The host's
|
|
@@ -25634,7 +25810,7 @@ async function vaultList(ctx, argv) {
|
|
|
25634
25810
|
write(ctx.io.stdout, VAULT_HELP);
|
|
25635
25811
|
return 0;
|
|
25636
25812
|
}
|
|
25637
|
-
const res = await gatedRequest(ctx,
|
|
25813
|
+
const res = await gatedRequest(ctx, BASE27, void 0, SURFACE2, "superadmin");
|
|
25638
25814
|
if (ctx.json) {
|
|
25639
25815
|
writeJson(ctx.io.stdout, res.body);
|
|
25640
25816
|
return 0;
|
|
@@ -25665,7 +25841,7 @@ async function vaultWrite(ctx, argv, verb) {
|
|
|
25665
25841
|
const scope = scopeOf(options);
|
|
25666
25842
|
const value = await readSecretInput(ctx, options, `Secret value for "${ref}"`);
|
|
25667
25843
|
const body = { value, ...scope === "host" ? { scope: "host" } : {} };
|
|
25668
|
-
const path = verb === "set" ? `${
|
|
25844
|
+
const path = verb === "set" ? `${BASE27}/secrets` : `${BASE27}/secrets/${encodeURIComponent(ref)}/rotate`;
|
|
25669
25845
|
if (verb === "set") body.credentialRef = ref;
|
|
25670
25846
|
const res = await gatedRequest(ctx, path, { method: "POST", body }, SURFACE2, "superadmin");
|
|
25671
25847
|
if (ctx.json) {
|
|
@@ -25689,7 +25865,7 @@ async function vaultDelete(ctx, argv) {
|
|
|
25689
25865
|
if (scopeOf(options) === "host") qs2.set("scope", "host");
|
|
25690
25866
|
if (options.force) qs2.set("force", "true");
|
|
25691
25867
|
const q = qs2.toString() ? `?${qs2}` : "";
|
|
25692
|
-
const res = await gatedRequest(ctx, `${
|
|
25868
|
+
const res = await gatedRequest(ctx, `${BASE27}/secrets/${encodeURIComponent(positionals[0])}${q}`, { method: "DELETE" }, SURFACE2, "superadmin");
|
|
25693
25869
|
if (ctx.json) {
|
|
25694
25870
|
writeJson(ctx.io.stdout, res.body);
|
|
25695
25871
|
return 0;
|
|
@@ -25699,27 +25875,40 @@ async function vaultDelete(ctx, argv) {
|
|
|
25699
25875
|
}
|
|
25700
25876
|
|
|
25701
25877
|
// src/cli/developerKeys.ts
|
|
25702
|
-
var
|
|
25878
|
+
var BASE28 = "/v1/host/openwop-app/developer-keys";
|
|
25703
25879
|
var SURFACE3 = "Managing developer API keys";
|
|
25704
25880
|
var DEVELOPER_KEYS_HELP = `Usage:
|
|
25705
25881
|
openwop developer-keys list [--json]
|
|
25706
25882
|
openwop developer-keys create --name <n> [--scope <s>]... [--expires-at <iso>] [--json]
|
|
25707
25883
|
openwop developer-keys revoke <keyId> --yes [--json]
|
|
25708
25884
|
|
|
25709
|
-
Developer API keys for this workspace (host extension under ${
|
|
25885
|
+
Developer API keys for this workspace (host extension under ${BASE28}). Requires an
|
|
25710
25886
|
authenticated principal (not an anonymous session); an admin or owner sees and can
|
|
25711
25887
|
revoke every key in the workspace, anyone else only their own.
|
|
25712
25888
|
|
|
25713
|
-
list GET ${
|
|
25714
|
-
create POST ${
|
|
25715
|
-
revoke DELETE ${
|
|
25889
|
+
list GET ${BASE28} keys (public fields only \u2014 never the token or its hash)
|
|
25890
|
+
create POST ${BASE28} issue a key; the token is shown ONCE
|
|
25891
|
+
revoke DELETE ${BASE28}/:keyId revoke (404 when the key is not yours / not in this workspace)
|
|
25716
25892
|
|
|
25717
25893
|
ONE-TIME SECRET: \`create\` prints the new token exactly once, on stdout, with a warning.
|
|
25718
25894
|
Store it immediately \u2014 the host keeps only a hash and cannot show it again. The CLI does
|
|
25719
25895
|
not save it anywhere.
|
|
25720
25896
|
|
|
25897
|
+
A KEY CANNOT MANAGE KEYS: openwop-app refuses \`list\`, \`create\` and \`revoke\` (403)
|
|
25898
|
+
when the CLI is itself signed in with a developer key (owk_\u2026). Create and revoke keys
|
|
25899
|
+
in the app (Access \u2192 API keys), or sign in with an operator key.
|
|
25900
|
+
|
|
25901
|
+
SCOPES ARE REQUIRED AND NARROW: openwop-app refuses a key with no --scope, and a key is
|
|
25902
|
+
limited to exactly the scopes it declares. To start a run and read it back a key needs
|
|
25903
|
+
runs:create AND runs:read; reaching the rest of the workspace (agents, memory, BYOK)
|
|
25904
|
+
needs workspace:read / workspace:write. \`--scope '*'\` is a key with your full authority.
|
|
25905
|
+
A scope the host does not know is refused by name.
|
|
25906
|
+
|
|
25907
|
+
EXPIRY: openwop-app gives a key 90 days unless --expires-at says otherwise, and refuses
|
|
25908
|
+
an expiry in the past or more than its maximum (366 days by default) away.
|
|
25909
|
+
|
|
25721
25910
|
--name <n> (create) Display name. Required.
|
|
25722
|
-
--scope <s> (create) Scope granted to the key (repeatable).
|
|
25911
|
+
--scope <s> (create) Scope granted to the key (repeatable; at least one).
|
|
25723
25912
|
--expires-at <iso> (create) Expiry timestamp.
|
|
25724
25913
|
--yes (revoke) Required confirmation.
|
|
25725
25914
|
|
|
@@ -25727,7 +25916,7 @@ Exit codes: 0 ok \xB7 2 usage / not found \xB7 4 not signed in.
|
|
|
25727
25916
|
|
|
25728
25917
|
Examples:
|
|
25729
25918
|
openwop developer-keys list
|
|
25730
|
-
openwop developer-keys create --name "CI deploy" --scope runs:
|
|
25919
|
+
openwop developer-keys create --name "CI deploy" --scope runs:create --scope runs:read
|
|
25731
25920
|
openwop developer-keys revoke dk:0123abcd --yes
|
|
25732
25921
|
`;
|
|
25733
25922
|
async function runDeveloperKeys(ctx, argv) {
|
|
@@ -25756,7 +25945,7 @@ async function keysList(ctx, argv) {
|
|
|
25756
25945
|
write(ctx.io.stdout, DEVELOPER_KEYS_HELP);
|
|
25757
25946
|
return 0;
|
|
25758
25947
|
}
|
|
25759
|
-
const res = await gatedRequest(ctx,
|
|
25948
|
+
const res = await gatedRequest(ctx, BASE28, void 0, SURFACE3, "signed-in");
|
|
25760
25949
|
if (ctx.json) {
|
|
25761
25950
|
writeJson(ctx.io.stdout, res.body);
|
|
25762
25951
|
return 0;
|
|
@@ -25785,7 +25974,7 @@ async function keysCreate(ctx, argv) {
|
|
|
25785
25974
|
const body = { name: options.name };
|
|
25786
25975
|
if (Array.isArray(options.scope) && options.scope.length) body.scopes = options.scope;
|
|
25787
25976
|
if (options.expiresAt) body.expiresAt = options.expiresAt;
|
|
25788
|
-
const res = await gatedRequest(ctx,
|
|
25977
|
+
const res = await gatedRequest(ctx, BASE28, { method: "POST", body }, SURFACE3, "signed-in");
|
|
25789
25978
|
writeLine(ctx.io.stderr, "WARNING: this token is shown ONCE. Store it now \u2014 it cannot be retrieved again.");
|
|
25790
25979
|
if (ctx.json) {
|
|
25791
25980
|
writeJson(ctx.io.stdout, res.body);
|
|
@@ -25806,7 +25995,7 @@ async function keysRevoke(ctx, argv) {
|
|
|
25806
25995
|
writeLine(ctx.io.stderr, `Refusing to revoke ${positionals[0]} without --yes.`);
|
|
25807
25996
|
return 2;
|
|
25808
25997
|
}
|
|
25809
|
-
await gatedRequest(ctx, `${
|
|
25998
|
+
await gatedRequest(ctx, `${BASE28}/${encodeURIComponent(positionals[0])}`, { method: "DELETE" }, SURFACE3, "signed-in");
|
|
25810
25999
|
if (ctx.json) {
|
|
25811
26000
|
writeJson(ctx.io.stdout, { keyId: positionals[0], revoked: true });
|
|
25812
26001
|
return 0;
|
|
@@ -25875,44 +26064,44 @@ Run \`openwop custom-domains --help\` for usage.`);
|
|
|
25875
26064
|
})), ["hostname", "status", "verifiedAt", "lastError"]));
|
|
25876
26065
|
return 0;
|
|
25877
26066
|
}
|
|
25878
|
-
const
|
|
25879
|
-
if (!
|
|
26067
|
+
const hostname2 = positionals[0];
|
|
26068
|
+
if (!hostname2) throw new CliError(`Usage: openwop custom-domains ${sub} <hostname> --org <orgId>`, 2);
|
|
25880
26069
|
if (sub === "add") {
|
|
25881
|
-
const res2 = await requestJson(ctx, base14(orgId), { method: "POST", body: { hostname } });
|
|
26070
|
+
const res2 = await requestJson(ctx, base14(orgId), { method: "POST", body: { hostname: hostname2 } });
|
|
25882
26071
|
if (ctx.json) {
|
|
25883
26072
|
writeJson(ctx.io.stdout, res2.body);
|
|
25884
26073
|
return 0;
|
|
25885
26074
|
}
|
|
25886
26075
|
const d = res2.body?.domain ?? {};
|
|
25887
|
-
writeLine(ctx.io.stdout, `Added ${d.hostname ??
|
|
25888
|
-
writeLine(ctx.io.stdout, `Publish TXT _openwop-verify.${d.hostname ??
|
|
26076
|
+
writeLine(ctx.io.stdout, `Added ${d.hostname ?? hostname2} (status ${d.status ?? "pending"}).`);
|
|
26077
|
+
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
26078
|
return 0;
|
|
25890
26079
|
}
|
|
25891
26080
|
if (sub === "verify") {
|
|
25892
|
-
const res2 = await requestJson(ctx, `${base14(orgId)}/${encodeURIComponent(
|
|
26081
|
+
const res2 = await requestJson(ctx, `${base14(orgId)}/${encodeURIComponent(hostname2)}/verify`, { method: "POST", body: {} });
|
|
25893
26082
|
if (ctx.json) {
|
|
25894
26083
|
writeJson(ctx.io.stdout, res2.body);
|
|
25895
26084
|
return 0;
|
|
25896
26085
|
}
|
|
25897
26086
|
const d = res2.body?.domain ?? {};
|
|
25898
|
-
writeLine(ctx.io.stdout, `${d.hostname ??
|
|
26087
|
+
writeLine(ctx.io.stdout, `${d.hostname ?? hostname2}: ${d.status ?? "?"}${d.lastError ? ` \u2014 ${d.lastError}` : ""}`);
|
|
25899
26088
|
return d.status === "live" ? 0 : 3;
|
|
25900
26089
|
}
|
|
25901
26090
|
if (!options.yes) {
|
|
25902
|
-
writeLine(ctx.io.stderr, `Refusing to remove ${
|
|
26091
|
+
writeLine(ctx.io.stderr, `Refusing to remove ${hostname2} without --yes.`);
|
|
25903
26092
|
return 2;
|
|
25904
26093
|
}
|
|
25905
|
-
const res = await requestJson(ctx, `${base14(orgId)}/${encodeURIComponent(
|
|
26094
|
+
const res = await requestJson(ctx, `${base14(orgId)}/${encodeURIComponent(hostname2)}`, { method: "DELETE" });
|
|
25906
26095
|
if (ctx.json) {
|
|
25907
26096
|
writeJson(ctx.io.stdout, res.body);
|
|
25908
26097
|
return 0;
|
|
25909
26098
|
}
|
|
25910
|
-
writeLine(ctx.io.stdout, `Removed ${
|
|
26099
|
+
writeLine(ctx.io.stdout, `Removed ${hostname2}.`);
|
|
25911
26100
|
return 0;
|
|
25912
26101
|
}
|
|
25913
26102
|
|
|
25914
26103
|
// src/cli/environments.ts
|
|
25915
|
-
var
|
|
26104
|
+
var BASE29 = "/v1/host/openwop-app/environments";
|
|
25916
26105
|
var PROTECTION = ["open", "protected", "locked"];
|
|
25917
26106
|
var ENVIRONMENTS_HELP = `Usage:
|
|
25918
26107
|
openwop environments list [--drift] [--json]
|
|
@@ -25929,21 +26118,21 @@ var ENVIRONMENTS_HELP = `Usage:
|
|
|
25929
26118
|
openwop environments apply --snapshot <hash> [--json]
|
|
25930
26119
|
openwop environments promotions [--json]
|
|
25931
26120
|
|
|
25932
|
-
Config environments + promotion (host extension under ${
|
|
26121
|
+
Config environments + promotion (host extension under ${BASE29}; toggle 'environments').
|
|
25933
26122
|
Reads need workspace:read; every write needs host:members:manage in the workspace.
|
|
25934
26123
|
|
|
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 ${
|
|
26124
|
+
list GET ${BASE29}[?drift=1] environments, config domains, app version
|
|
26125
|
+
create POST ${BASE29} add an environment to the chain
|
|
26126
|
+
ensure-chain POST ${BASE29}/ensure-chain create the default dev \u2192 staging \u2192 prod chain
|
|
26127
|
+
protect PATCH ${BASE29}/:name/protection set open | protected | locked
|
|
26128
|
+
settings GET/PATCH ${BASE29}/settings the promotion-approval gate
|
|
26129
|
+
snapshots GET ${BASE29}/snapshots stored config snapshots
|
|
26130
|
+
snapshot POST ${BASE29}/snapshots snapshot the current live config
|
|
26131
|
+
preview POST ${BASE29}/preview diff a snapshot against an environment (no change)
|
|
26132
|
+
promote POST ${BASE29}/promote promote an env's snapshot to the next (or --to) env
|
|
26133
|
+
rollback POST ${BASE29}/rollback point an env back at a historical snapshot
|
|
26134
|
+
apply POST ${BASE29}/apply apply a snapshot to the live config
|
|
26135
|
+
promotions GET ${BASE29}/promotions the promotion ledger
|
|
25947
26136
|
|
|
25948
26137
|
Exit codes: 0 ok \xB7 3 queued for approval (202 pending_approval) \xB7 2 usage / not found /
|
|
25949
26138
|
feature off \xB7 4 permission denied.
|
|
@@ -25976,7 +26165,7 @@ async function runEnvironments(ctx, argv) {
|
|
|
25976
26165
|
};
|
|
25977
26166
|
switch (sub) {
|
|
25978
26167
|
case "list": {
|
|
25979
|
-
const res = await requestJson(ctx, `${
|
|
26168
|
+
const res = await requestJson(ctx, `${BASE29}${options.drift ? "?drift=1" : ""}`);
|
|
25980
26169
|
emit2(res.body, () => {
|
|
25981
26170
|
const envs = arrayOf(res.body, "environments");
|
|
25982
26171
|
if (envs.length === 0) {
|
|
@@ -26003,35 +26192,35 @@ async function runEnvironments(ctx, argv) {
|
|
|
26003
26192
|
body.order = n;
|
|
26004
26193
|
}
|
|
26005
26194
|
if (options.protection !== void 0) body.protection = protectionOf(options.protection);
|
|
26006
|
-
const res = await requestJson(ctx,
|
|
26195
|
+
const res = await requestJson(ctx, BASE29, { method: "POST", body });
|
|
26007
26196
|
emit2(res.body, () => writeLine(ctx.io.stdout, `Created environment ${res.body?.name ?? name} (order ${res.body?.order ?? "?"}, ${res.body?.protection ?? "?"}).`));
|
|
26008
26197
|
return 0;
|
|
26009
26198
|
}
|
|
26010
26199
|
case "ensure-chain": {
|
|
26011
|
-
const res = await requestJson(ctx, `${
|
|
26200
|
+
const res = await requestJson(ctx, `${BASE29}/ensure-chain`, { method: "POST", body: {} });
|
|
26012
26201
|
emit2(res.body, () => writeLine(ctx.io.stdout, `Chain: ${arrayOf(res.body, "environments").map((e) => e.name).join(" \u2192 ")}`));
|
|
26013
26202
|
return 0;
|
|
26014
26203
|
}
|
|
26015
26204
|
case "protect": {
|
|
26016
26205
|
const name = positionals[0];
|
|
26017
26206
|
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, `${
|
|
26207
|
+
const res = await requestJson(ctx, `${BASE29}/${encodeURIComponent(name)}/protection`, { method: "PATCH", body: { protection: protectionOf(options.protection) } });
|
|
26019
26208
|
emit2(res.body, () => writeLine(ctx.io.stdout, `${name} is now ${res.body?.protection ?? options.protection}.`));
|
|
26020
26209
|
return 0;
|
|
26021
26210
|
}
|
|
26022
26211
|
case "settings": {
|
|
26023
26212
|
if (positionals[0] === "set") {
|
|
26024
26213
|
if (options.requireApproval === void 0) throw new CliError("Usage: openwop environments settings set --require-approval true|false", 2);
|
|
26025
|
-
const res2 = await requestJson(ctx, `${
|
|
26214
|
+
const res2 = await requestJson(ctx, `${BASE29}/settings`, { method: "PATCH", body: { requireApprovalForPromotion: parseBool("--require-approval", options.requireApproval) } });
|
|
26026
26215
|
emit2(res2.body, () => writeLine(ctx.io.stdout, `requireApprovalForPromotion: ${res2.body?.requireApprovalForPromotion}`));
|
|
26027
26216
|
return 0;
|
|
26028
26217
|
}
|
|
26029
|
-
const res = await requestJson(ctx, `${
|
|
26218
|
+
const res = await requestJson(ctx, `${BASE29}/settings`);
|
|
26030
26219
|
emit2(res.body, () => writeLine(ctx.io.stdout, `requireApprovalForPromotion: ${res.body?.requireApprovalForPromotion ?? false}`));
|
|
26031
26220
|
return 0;
|
|
26032
26221
|
}
|
|
26033
26222
|
case "snapshots": {
|
|
26034
|
-
const res = await requestJson(ctx, `${
|
|
26223
|
+
const res = await requestJson(ctx, `${BASE29}/snapshots`);
|
|
26035
26224
|
emit2(res.body, () => {
|
|
26036
26225
|
const snaps = arrayOf(res.body, "snapshots");
|
|
26037
26226
|
if (snaps.length === 0) {
|
|
@@ -26051,13 +26240,13 @@ async function runEnvironments(ctx, argv) {
|
|
|
26051
26240
|
case "snapshot": {
|
|
26052
26241
|
const body = {};
|
|
26053
26242
|
if (options.sourceEnv) body.sourceEnv = options.sourceEnv;
|
|
26054
|
-
const res = await requestJson(ctx, `${
|
|
26243
|
+
const res = await requestJson(ctx, `${BASE29}/snapshots`, { method: "POST", body });
|
|
26055
26244
|
emit2(res.body, () => writeLine(ctx.io.stdout, `Snapshot ${res.body?.hash ?? "?"}${res.body?.sourceEnv ? ` (from ${res.body.sourceEnv})` : ""}.`));
|
|
26056
26245
|
return 0;
|
|
26057
26246
|
}
|
|
26058
26247
|
case "preview": {
|
|
26059
26248
|
if (!options.to || !options.snapshot) throw new CliError("Usage: openwop environments preview --to <env> --snapshot <hash>", 2);
|
|
26060
|
-
const res = await requestJson(ctx, `${
|
|
26249
|
+
const res = await requestJson(ctx, `${BASE29}/preview`, { method: "POST", body: { toEnv: options.to, snapshotHash: options.snapshot } });
|
|
26061
26250
|
writeJson(ctx.io.stdout, res.body);
|
|
26062
26251
|
return 0;
|
|
26063
26252
|
}
|
|
@@ -26065,18 +26254,18 @@ async function runEnvironments(ctx, argv) {
|
|
|
26065
26254
|
if (!options.from) throw new CliError("Usage: openwop environments promote --from <env> [--to <env>]", 2);
|
|
26066
26255
|
const body = { fromEnv: options.from };
|
|
26067
26256
|
if (options.to) body.toEnv = options.to;
|
|
26068
|
-
return movement(ctx, await requestJson(ctx, `${
|
|
26257
|
+
return movement(ctx, await requestJson(ctx, `${BASE29}/promote`, { method: "POST", body }), "Promoted");
|
|
26069
26258
|
}
|
|
26070
26259
|
case "rollback": {
|
|
26071
26260
|
if (!options.env || !options.snapshot) throw new CliError("Usage: openwop environments rollback --env <env> --snapshot <hash>", 2);
|
|
26072
|
-
return movement(ctx, await requestJson(ctx, `${
|
|
26261
|
+
return movement(ctx, await requestJson(ctx, `${BASE29}/rollback`, { method: "POST", body: { env: options.env, snapshotHash: options.snapshot } }), "Rolled back");
|
|
26073
26262
|
}
|
|
26074
26263
|
case "apply": {
|
|
26075
26264
|
if (!options.snapshot) throw new CliError("Usage: openwop environments apply --snapshot <hash>", 2);
|
|
26076
|
-
return movement(ctx, await requestJson(ctx, `${
|
|
26265
|
+
return movement(ctx, await requestJson(ctx, `${BASE29}/apply`, { method: "POST", body: { snapshotHash: options.snapshot } }), "Applied");
|
|
26077
26266
|
}
|
|
26078
26267
|
case "promotions": {
|
|
26079
|
-
const res = await requestJson(ctx, `${
|
|
26268
|
+
const res = await requestJson(ctx, `${BASE29}/promotions`);
|
|
26080
26269
|
emit2(res.body, () => {
|
|
26081
26270
|
const rows = arrayOf(res.body, "promotions");
|
|
26082
26271
|
if (rows.length === 0) {
|
|
@@ -26121,7 +26310,7 @@ function movement(ctx, res, verb) {
|
|
|
26121
26310
|
}
|
|
26122
26311
|
|
|
26123
26312
|
// src/cli/billing.ts
|
|
26124
|
-
var
|
|
26313
|
+
var BASE30 = "/v1/host/openwop-app/billing";
|
|
26125
26314
|
var BILLING_HELP = `Usage:
|
|
26126
26315
|
openwop billing subscription [--json]
|
|
26127
26316
|
openwop billing balance [--json]
|
|
@@ -26139,7 +26328,7 @@ var BILLING_HELP = `Usage:
|
|
|
26139
26328
|
openwop billing sync-seats [--json]
|
|
26140
26329
|
openwop billing import (--body <json> | --body-file <path>) [--json]
|
|
26141
26330
|
|
|
26142
|
-
Workspace billing (host extension under ${
|
|
26331
|
+
Workspace billing (host extension under ${BASE30}; toggle 'billing').
|
|
26143
26332
|
subscription GET /subscription plan tier, status, seats, period
|
|
26144
26333
|
balance GET /balance purchased token balance
|
|
26145
26334
|
entitlements GET /entitlements the plan's allowed features + limits
|
|
@@ -26186,7 +26375,7 @@ async function runBilling(ctx, argv) {
|
|
|
26186
26375
|
const superadmin = (path, body, surface) => gatedRequest(ctx, path, { method: "POST", body }, surface, "superadmin");
|
|
26187
26376
|
switch (sub) {
|
|
26188
26377
|
case "subscription": {
|
|
26189
|
-
const res = await requestJson(ctx, `${
|
|
26378
|
+
const res = await requestJson(ctx, `${BASE30}/subscription`);
|
|
26190
26379
|
emit2(res.body, () => {
|
|
26191
26380
|
const s = res.body ?? {};
|
|
26192
26381
|
writeLine(ctx.io.stdout, `plan: ${s.planTier ?? "?"} (${s.status ?? "?"})`);
|
|
@@ -26197,12 +26386,12 @@ async function runBilling(ctx, argv) {
|
|
|
26197
26386
|
return 0;
|
|
26198
26387
|
}
|
|
26199
26388
|
case "balance": {
|
|
26200
|
-
const res = await requestJson(ctx, `${
|
|
26389
|
+
const res = await requestJson(ctx, `${BASE30}/balance`);
|
|
26201
26390
|
emit2(res.body, () => writeLine(ctx.io.stdout, `tokens available: ${res.body?.totalAvailable ?? 0} (purchased total ${res.body?.purchasedTokensTotal ?? 0})`));
|
|
26202
26391
|
return 0;
|
|
26203
26392
|
}
|
|
26204
26393
|
case "entitlements": {
|
|
26205
|
-
const res = await requestJson(ctx, `${
|
|
26394
|
+
const res = await requestJson(ctx, `${BASE30}/entitlements`);
|
|
26206
26395
|
emit2(res.body, () => {
|
|
26207
26396
|
const e = res.body ?? {};
|
|
26208
26397
|
writeLine(ctx.io.stdout, `plan: ${e.plan ?? "?"}`);
|
|
@@ -26213,7 +26402,7 @@ async function runBilling(ctx, argv) {
|
|
|
26213
26402
|
return 0;
|
|
26214
26403
|
}
|
|
26215
26404
|
case "bundles": {
|
|
26216
|
-
const res = await requestJson(ctx, `${
|
|
26405
|
+
const res = await requestJson(ctx, `${BASE30}/bundles`);
|
|
26217
26406
|
emit2(res.body, () => {
|
|
26218
26407
|
const rows = arrayOf(res.body, "bundles");
|
|
26219
26408
|
if (rows.length === 0) {
|
|
@@ -26233,19 +26422,19 @@ async function runBilling(ctx, argv) {
|
|
|
26233
26422
|
const verb = positionals[0] ?? "list";
|
|
26234
26423
|
if (verb === "get") {
|
|
26235
26424
|
if (!positionals[1]) throw new CliError("Usage: openwop billing invoices get <invoiceId>", 2);
|
|
26236
|
-
const res2 = await requestJson(ctx, `${
|
|
26425
|
+
const res2 = await requestJson(ctx, `${BASE30}/invoices/${encodeURIComponent(positionals[1])}`);
|
|
26237
26426
|
emit2(res2.body, () => writeLine(ctx.io.stdout, res2.body?.markdown ?? JSON.stringify(res2.body, null, 2)));
|
|
26238
26427
|
return 0;
|
|
26239
26428
|
}
|
|
26240
26429
|
if (verb === "create") {
|
|
26241
26430
|
const amount = Number(options.amount);
|
|
26242
26431
|
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(`${
|
|
26432
|
+
const res2 = await superadmin(`${BASE30}/invoices`, { amount, ...options.currency ? { currency: options.currency } : {} }, "Generating an invoice");
|
|
26244
26433
|
emit2(res2.body, () => writeLine(ctx.io.stdout, `Created invoice ${res2.body?.invoiceId ?? "?"} (${res2.body?.amount} ${res2.body?.currency}).`));
|
|
26245
26434
|
return 0;
|
|
26246
26435
|
}
|
|
26247
26436
|
if (verb !== "list") throw new CliError(`Unknown invoices verb: ${verb}`, 2);
|
|
26248
|
-
const res = await requestJson(ctx, `${
|
|
26437
|
+
const res = await requestJson(ctx, `${BASE30}/invoices`);
|
|
26249
26438
|
emit2(res.body, () => {
|
|
26250
26439
|
const rows = arrayOf(res.body, "invoices");
|
|
26251
26440
|
if (rows.length === 0) {
|
|
@@ -26263,18 +26452,18 @@ async function runBilling(ctx, argv) {
|
|
|
26263
26452
|
}
|
|
26264
26453
|
case "checkout": {
|
|
26265
26454
|
if (!options.price) throw new CliError("Usage: openwop billing checkout --price <priceId>", 2);
|
|
26266
|
-
const res = await requestJson(ctx, `${
|
|
26455
|
+
const res = await requestJson(ctx, `${BASE30}/checkout`, { method: "POST", body: { priceId: options.price } });
|
|
26267
26456
|
emit2(res.body, () => writeLine(ctx.io.stdout, `Open to complete checkout (${res.body?.mode ?? "?"}): ${res.body?.url ?? "?"}`));
|
|
26268
26457
|
return 0;
|
|
26269
26458
|
}
|
|
26270
26459
|
case "bundle-checkout": {
|
|
26271
26460
|
if (!positionals[0]) throw new CliError("Usage: openwop billing bundle-checkout <bundleId>", 2);
|
|
26272
|
-
const res = await requestJson(ctx, `${
|
|
26461
|
+
const res = await requestJson(ctx, `${BASE30}/bundles/${encodeURIComponent(positionals[0])}/checkout`, { method: "POST", body: {} });
|
|
26273
26462
|
emit2(res.body, () => writeLine(ctx.io.stdout, `Open to complete checkout (${res.body?.mode ?? "?"}): ${res.body?.url ?? "?"}`));
|
|
26274
26463
|
return 0;
|
|
26275
26464
|
}
|
|
26276
26465
|
case "portal": {
|
|
26277
|
-
const res = await requestJson(ctx, `${
|
|
26466
|
+
const res = await requestJson(ctx, `${BASE30}/portal`, { method: "POST", body: {} });
|
|
26278
26467
|
emit2(res.body, () => writeLine(ctx.io.stdout, `Billing portal (${res.body?.mode ?? "?"}): ${res.body?.url ?? "?"}`));
|
|
26279
26468
|
return 0;
|
|
26280
26469
|
}
|
|
@@ -26287,19 +26476,19 @@ async function runBilling(ctx, argv) {
|
|
|
26287
26476
|
if (!Number.isFinite(v)) throw new CliError("--value must be a number.", 2);
|
|
26288
26477
|
body.value = v;
|
|
26289
26478
|
}
|
|
26290
|
-
const res = await superadmin(`${
|
|
26479
|
+
const res = await superadmin(`${BASE30}/coupons`, body, "Creating a billing coupon");
|
|
26291
26480
|
emit2(res.body, () => writeLine(ctx.io.stdout, `Created coupon ${res.body?.code ?? options.code} (${res.body?.type} ${res.body?.value}).`));
|
|
26292
26481
|
return 0;
|
|
26293
26482
|
}
|
|
26294
26483
|
case "sync-seats": {
|
|
26295
|
-
const res = await superadmin(`${
|
|
26484
|
+
const res = await superadmin(`${BASE30}/sync-seats`, {}, "Billing seat sync");
|
|
26296
26485
|
emit2(res.body, () => writeLine(ctx.io.stdout, `Seats synced: ${res.body?.quantity ?? "?"}.`));
|
|
26297
26486
|
return 0;
|
|
26298
26487
|
}
|
|
26299
26488
|
case "import": {
|
|
26300
26489
|
const body = readBodyOption(ctx, options);
|
|
26301
26490
|
if (!body) throw new CliError('Usage: openwop billing import (--body <json> | --body-file <path>) \u2014 {"subscriptions":[...],"balances":[...]}', 2);
|
|
26302
|
-
const res = await superadmin(`${
|
|
26491
|
+
const res = await superadmin(`${BASE30}/import`, body, "Billing import");
|
|
26303
26492
|
emit2(res.body, () => writeLine(ctx.io.stdout, `Imported ${res.body?.subscriptions ?? 0} subscription(s), ${res.body?.balances ?? 0} balance(s).`));
|
|
26304
26493
|
return 0;
|
|
26305
26494
|
}
|
|
@@ -26370,15 +26559,15 @@ Run \`openwop site-config --help\` for usage.`);
|
|
|
26370
26559
|
}
|
|
26371
26560
|
|
|
26372
26561
|
// src/cli/runtimePosture.ts
|
|
26373
|
-
var
|
|
26562
|
+
var BASE31 = "/v1/host/openwop-app/runtime-posture";
|
|
26374
26563
|
var SURFACE5 = "Runtime posture";
|
|
26375
26564
|
var RUNTIME_POSTURE_HELP = `Usage:
|
|
26376
26565
|
openwop runtime-posture [get] [--json]
|
|
26377
26566
|
openwop runtime-posture request --warm|--cold [--json]
|
|
26378
26567
|
|
|
26379
26568
|
The serving service's runtime posture (host extension, SUPER-ADMIN gated).
|
|
26380
|
-
get GET ${
|
|
26381
|
-
request POST ${
|
|
26569
|
+
get GET ${BASE31} live posture (serving revision, warm/cold, rollout)
|
|
26570
|
+
request POST ${BASE31}/change-requests ask for a warm/cold change; returns the commands to run
|
|
26382
26571
|
|
|
26383
26572
|
A change request APPLIES NOTHING: the host records it in the audit log and returns the
|
|
26384
26573
|
exact commands for an operator holding deploy rights. Without a super-admin principal
|
|
@@ -26402,7 +26591,7 @@ async function runRuntimePosture(ctx, argv) {
|
|
|
26402
26591
|
return 0;
|
|
26403
26592
|
}
|
|
26404
26593
|
if (sub === "get") {
|
|
26405
|
-
const res2 = await gatedRequest(ctx,
|
|
26594
|
+
const res2 = await gatedRequest(ctx, BASE31, void 0, SURFACE5, "superadmin");
|
|
26406
26595
|
if (ctx.json) {
|
|
26407
26596
|
writeJson(ctx.io.stdout, res2.body);
|
|
26408
26597
|
return 0;
|
|
@@ -26421,7 +26610,7 @@ async function runRuntimePosture(ctx, argv) {
|
|
|
26421
26610
|
if (sub !== "request") throw new CliError(`Unknown runtime-posture command: ${sub}
|
|
26422
26611
|
Run \`openwop runtime-posture --help\` for usage.`);
|
|
26423
26612
|
if (Boolean(options.warm) === Boolean(options.cold)) throw new CliError("Pass exactly one of --warm or --cold.", 2);
|
|
26424
|
-
const res = await gatedRequest(ctx, `${
|
|
26613
|
+
const res = await gatedRequest(ctx, `${BASE31}/change-requests`, { method: "POST", body: { warm: Boolean(options.warm) } }, SURFACE5, "superadmin");
|
|
26425
26614
|
if (ctx.json) {
|
|
26426
26615
|
writeJson(ctx.io.stdout, res.body);
|
|
26427
26616
|
return 0;
|
|
@@ -26476,16 +26665,16 @@ Run \`openwop maintenance --help\` for usage.`);
|
|
|
26476
26665
|
}
|
|
26477
26666
|
|
|
26478
26667
|
// src/cli/menuConfig.ts
|
|
26479
|
-
var
|
|
26668
|
+
var BASE32 = "/v1/host/openwop-app/menu-config";
|
|
26480
26669
|
var MENU_CONFIG_HELP = `Usage:
|
|
26481
26670
|
openwop menu-config [get] [--json]
|
|
26482
26671
|
openwop menu-config set me (--body <json> | --body-file <path>) [--json]
|
|
26483
26672
|
openwop menu-config set tenant (--body <json> | --body-file <path>) [--json]
|
|
26484
26673
|
|
|
26485
26674
|
Navigation menu layout (host extension).
|
|
26486
|
-
get GET ${
|
|
26487
|
-
set me PUT ${
|
|
26488
|
-
set tenant PUT ${
|
|
26675
|
+
get GET ${BASE32} {tenant, user} layers for the caller
|
|
26676
|
+
set me PUT ${BASE32}/me replace YOUR personal layer (signed-in user)
|
|
26677
|
+
set tenant PUT ${BASE32}/tenant [super-admin] replace the workspace default layer
|
|
26489
26678
|
|
|
26490
26679
|
The body is the menu config object ({"items": {...}, "headers": [...]}) or the full
|
|
26491
26680
|
request ({"config": {...}}). A write REPLACES that layer. \`set tenant\` reads the current
|
|
@@ -26511,7 +26700,7 @@ async function runMenuConfig(ctx, argv) {
|
|
|
26511
26700
|
return 0;
|
|
26512
26701
|
}
|
|
26513
26702
|
if (sub === "get") {
|
|
26514
|
-
const res2 = await requestJson(ctx,
|
|
26703
|
+
const res2 = await requestJson(ctx, BASE32);
|
|
26515
26704
|
writeJson(ctx.io.stdout, res2.body);
|
|
26516
26705
|
return 0;
|
|
26517
26706
|
}
|
|
@@ -26525,13 +26714,13 @@ Run \`openwop menu-config --help\` for usage.`);
|
|
|
26525
26714
|
const body = "config" in raw ? raw : { config: raw };
|
|
26526
26715
|
let res;
|
|
26527
26716
|
if (layer === "me") {
|
|
26528
|
-
res = await gatedRequest(ctx, `${
|
|
26717
|
+
res = await gatedRequest(ctx, `${BASE32}/me`, { method: "PUT", body }, "Editing your menu layout", "signed-in");
|
|
26529
26718
|
} else {
|
|
26530
|
-
const current = await requestJson(ctx,
|
|
26719
|
+
const current = await requestJson(ctx, BASE32);
|
|
26531
26720
|
const etag = current.headers.get("etag");
|
|
26532
26721
|
res = await gatedRequest(
|
|
26533
26722
|
ctx,
|
|
26534
|
-
`${
|
|
26723
|
+
`${BASE32}/tenant`,
|
|
26535
26724
|
{ method: "PUT", body, ...etag ? { headers: { "if-match": etag } } : {} },
|
|
26536
26725
|
"Editing the workspace default menu layout",
|
|
26537
26726
|
"superadmin"
|
|
@@ -26921,7 +27110,7 @@ function renderKnowledge(ctx, agentId, k) {
|
|
|
26921
27110
|
|
|
26922
27111
|
// src/cli/compatEndpoints.ts
|
|
26923
27112
|
import { readFileSync as readFileSync19 } from "node:fs";
|
|
26924
|
-
var
|
|
27113
|
+
var BASE33 = "/v1/host/openwop-app/compat-endpoints";
|
|
26925
27114
|
var COMPAT_ENDPOINTS_HELP = `Usage:
|
|
26926
27115
|
openwop compat-endpoints list --org <orgId> [--json]
|
|
26927
27116
|
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 +27160,7 @@ async function runCompatEndpoints(ctx, argv) {
|
|
|
26971
27160
|
switch (sub) {
|
|
26972
27161
|
case "list": {
|
|
26973
27162
|
const org2 = requireOrg(options.org);
|
|
26974
|
-
const res = await requestJson(ctx, `${
|
|
27163
|
+
const res = await requestJson(ctx, `${BASE33}?orgId=${encodeURIComponent(org2)}`);
|
|
26975
27164
|
if (ctx.json) {
|
|
26976
27165
|
writeJson(ctx.io.stdout, res.body);
|
|
26977
27166
|
return 0;
|
|
@@ -27004,7 +27193,7 @@ async function runCompatEndpoints(ctx, argv) {
|
|
|
27004
27193
|
const apiKey = readApiKey(ctx, options);
|
|
27005
27194
|
if (apiKey) body.apiKey = apiKey;
|
|
27006
27195
|
if (Array.isArray(options.model) && options.model.length) body.models = options.model;
|
|
27007
|
-
const res = await requestJson(ctx,
|
|
27196
|
+
const res = await requestJson(ctx, BASE33, { method: "POST", body });
|
|
27008
27197
|
if (ctx.json) {
|
|
27009
27198
|
writeJson(ctx.io.stdout, res.body);
|
|
27010
27199
|
return 0;
|
|
@@ -27018,7 +27207,7 @@ async function runCompatEndpoints(ctx, argv) {
|
|
|
27018
27207
|
writeLine(ctx.io.stderr, `Refusing to delete ${positionals[0]} (and its stored key) without --yes.`);
|
|
27019
27208
|
return 2;
|
|
27020
27209
|
}
|
|
27021
|
-
await requestJson(ctx, `${
|
|
27210
|
+
await requestJson(ctx, `${BASE33}/${encodeURIComponent(positionals[0])}`, { method: "DELETE" });
|
|
27022
27211
|
writeLine(ctx.io.stdout, `Deleted compat endpoint ${positionals[0]}.`);
|
|
27023
27212
|
return 0;
|
|
27024
27213
|
}
|
|
@@ -27048,7 +27237,7 @@ function readApiKey(ctx, options) {
|
|
|
27048
27237
|
}
|
|
27049
27238
|
|
|
27050
27239
|
// src/cli/hostEvents.ts
|
|
27051
|
-
var
|
|
27240
|
+
var BASE34 = "/v1/host/openwop-app/host-events/bindings";
|
|
27052
27241
|
var HOST_EVENTS_HELP = `Usage:
|
|
27053
27242
|
openwop host-events list [--json]
|
|
27054
27243
|
openwop host-events bind --event <host.\u2026> --workflow <workflowId> [--json]
|
|
@@ -27091,7 +27280,7 @@ async function runHostEvents(ctx, argv) {
|
|
|
27091
27280
|
}
|
|
27092
27281
|
switch (sub) {
|
|
27093
27282
|
case "list": {
|
|
27094
|
-
const res = await requestJson(ctx,
|
|
27283
|
+
const res = await requestJson(ctx, BASE34);
|
|
27095
27284
|
if (ctx.json) {
|
|
27096
27285
|
writeJson(ctx.io.stdout, res.body);
|
|
27097
27286
|
return 0;
|
|
@@ -27112,7 +27301,7 @@ async function runHostEvents(ctx, argv) {
|
|
|
27112
27301
|
case "bind": {
|
|
27113
27302
|
if (!options.event || !options.workflow) throw new CliError("bind needs --event <host.\u2026> and --workflow <workflowId>.", 2);
|
|
27114
27303
|
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,
|
|
27304
|
+
const res = await requestJson(ctx, BASE34, { method: "POST", body: { eventType: options.event, workflowId: options.workflow } });
|
|
27116
27305
|
if (ctx.json) {
|
|
27117
27306
|
writeJson(ctx.io.stdout, res.body);
|
|
27118
27307
|
return 0;
|
|
@@ -27123,7 +27312,7 @@ async function runHostEvents(ctx, argv) {
|
|
|
27123
27312
|
case "enable":
|
|
27124
27313
|
case "disable": {
|
|
27125
27314
|
if (positionals.length !== 1) throw new CliError(`Usage: openwop host-events ${sub} <bindingId> [--json]`, 2);
|
|
27126
|
-
const res = await requestJson(ctx, `${
|
|
27315
|
+
const res = await requestJson(ctx, `${BASE34}/${encodeURIComponent(positionals[0])}`, { method: "PATCH", body: { enabled: sub === "enable" } });
|
|
27127
27316
|
if (ctx.json) {
|
|
27128
27317
|
writeJson(ctx.io.stdout, res.body);
|
|
27129
27318
|
return 0;
|
|
@@ -27137,7 +27326,7 @@ async function runHostEvents(ctx, argv) {
|
|
|
27137
27326
|
writeLine(ctx.io.stderr, `Refusing to delete binding ${positionals[0]} without --yes.`);
|
|
27138
27327
|
return 2;
|
|
27139
27328
|
}
|
|
27140
|
-
await requestJson(ctx, `${
|
|
27329
|
+
await requestJson(ctx, `${BASE34}/${encodeURIComponent(positionals[0])}`, { method: "DELETE" });
|
|
27141
27330
|
writeLine(ctx.io.stdout, `Deleted binding ${positionals[0]}.`);
|
|
27142
27331
|
return 0;
|
|
27143
27332
|
}
|
|
@@ -27336,7 +27525,7 @@ Run \`openwop openapi --help\` for usage.`);
|
|
|
27336
27525
|
}
|
|
27337
27526
|
|
|
27338
27527
|
// src/cli/assistant.ts
|
|
27339
|
-
var
|
|
27528
|
+
var BASE35 = "/v1/host/openwop-app/assistant";
|
|
27340
27529
|
var ASSISTANT_HELP = `Usage:
|
|
27341
27530
|
openwop assistant workspace [--json]
|
|
27342
27531
|
openwop assistant briefing [--json]
|
|
@@ -27399,7 +27588,7 @@ async function runAssistant(ctx, argv) {
|
|
|
27399
27588
|
return await runWorkspace2(ctx, rest);
|
|
27400
27589
|
case "briefing":
|
|
27401
27590
|
case "brief":
|
|
27402
|
-
return await simpleRead(ctx, rest, `${
|
|
27591
|
+
return await simpleRead(ctx, rest, `${BASE35}/briefing`, (b) => writeLine(ctx.io.stdout, JSON.stringify(b?.brief ?? b, null, 2)));
|
|
27403
27592
|
case "projects":
|
|
27404
27593
|
case "project":
|
|
27405
27594
|
return await runProjects2(ctx, rest);
|
|
@@ -27412,7 +27601,7 @@ async function runAssistant(ctx, argv) {
|
|
|
27412
27601
|
case "meeting":
|
|
27413
27602
|
return await runMeetings(ctx, rest);
|
|
27414
27603
|
case "stakeholders":
|
|
27415
|
-
return await simpleRead(ctx, rest, `${
|
|
27604
|
+
return await simpleRead(ctx, rest, `${BASE35}/stakeholders`, (b) => table2(ctx, b?.stakeholders, (s) => ({
|
|
27416
27605
|
stakeholderId: s.stakeholderId,
|
|
27417
27606
|
name: s.person?.name ?? s.person?.email ?? "",
|
|
27418
27607
|
importance: String(s.importance ?? ""),
|
|
@@ -27425,7 +27614,7 @@ async function runAssistant(ctx, argv) {
|
|
|
27425
27614
|
case "loop":
|
|
27426
27615
|
return await runLoops(ctx, rest);
|
|
27427
27616
|
case "health":
|
|
27428
|
-
return await simpleRead(ctx, rest, `${
|
|
27617
|
+
return await simpleRead(ctx, rest, `${BASE35}/health`, (b) => writeLine(ctx.io.stdout, JSON.stringify(b?.health ?? b, null, 2)));
|
|
27429
27618
|
default:
|
|
27430
27619
|
throw new CliError(`Unknown assistant command: ${sub}
|
|
27431
27620
|
Run \`openwop assistant --help\` for usage.`, 2);
|
|
@@ -27455,7 +27644,7 @@ async function runWorkspace2(ctx, argv) {
|
|
|
27455
27644
|
write(ctx.io.stdout, ASSISTANT_HELP);
|
|
27456
27645
|
return 0;
|
|
27457
27646
|
}
|
|
27458
|
-
const res = await requestJson(ctx, `${
|
|
27647
|
+
const res = await requestJson(ctx, `${BASE35}/workspace-conversation`, { method: "POST", body: {} });
|
|
27459
27648
|
return emit(ctx, res.body, () => {
|
|
27460
27649
|
writeLine(ctx.io.stdout, `${res.status === 201 ? "Opened" : "Resumed"} workspace conversation ${res.body?.sessionId}.`);
|
|
27461
27650
|
writeLine(ctx.io.stdout, `Talk to the assistant: openwop chat messages send ${res.body?.sessionId} --content "\u2026"`);
|
|
@@ -27481,7 +27670,7 @@ async function runProjects2(ctx, argv) {
|
|
|
27481
27670
|
const id = positionals[0];
|
|
27482
27671
|
const needId = () => {
|
|
27483
27672
|
if (!id) throw new CliError(`assistant projects ${sub} requires <projectId>.`, 2);
|
|
27484
|
-
return `${
|
|
27673
|
+
return `${BASE35}/projects/${enc(id)}`;
|
|
27485
27674
|
};
|
|
27486
27675
|
const fields = () => {
|
|
27487
27676
|
const body = {};
|
|
@@ -27494,7 +27683,7 @@ async function runProjects2(ctx, argv) {
|
|
|
27494
27683
|
};
|
|
27495
27684
|
switch (sub) {
|
|
27496
27685
|
case "list": {
|
|
27497
|
-
const res = await requestJson(ctx, `${
|
|
27686
|
+
const res = await requestJson(ctx, `${BASE35}/projects`);
|
|
27498
27687
|
return emit(ctx, res.body, () => table2(ctx, res.body?.projects, projectRow, "No assistant projects. Create one with `openwop assistant projects create --name <n>`."));
|
|
27499
27688
|
}
|
|
27500
27689
|
case "get": {
|
|
@@ -27515,7 +27704,7 @@ async function runProjects2(ctx, argv) {
|
|
|
27515
27704
|
}
|
|
27516
27705
|
case "create": {
|
|
27517
27706
|
if (!options.name) throw new CliError("assistant projects create requires --name <n>.", 2);
|
|
27518
|
-
const res = await requestJson(ctx, `${
|
|
27707
|
+
const res = await requestJson(ctx, `${BASE35}/projects`, { method: "POST", body: fields() });
|
|
27519
27708
|
return emit(ctx, res.body, () => writeLine(ctx.io.stdout, `Created project ${res.body?.projectId} (${res.body?.name ?? options.name}).`));
|
|
27520
27709
|
}
|
|
27521
27710
|
case "update": {
|
|
@@ -27562,14 +27751,14 @@ async function runCommitments(ctx, argv) {
|
|
|
27562
27751
|
const id = positionals[0];
|
|
27563
27752
|
const needId = () => {
|
|
27564
27753
|
if (!id) throw new CliError(`assistant commitments ${sub} requires <commitmentId>.`, 2);
|
|
27565
|
-
return `${
|
|
27754
|
+
return `${BASE35}/commitments/${enc(id)}`;
|
|
27566
27755
|
};
|
|
27567
27756
|
switch (sub) {
|
|
27568
27757
|
case "list": {
|
|
27569
27758
|
const q = new URLSearchParams();
|
|
27570
27759
|
if (options.status) q.set("status", options.status);
|
|
27571
27760
|
if (options.project) q.set("projectId", options.project);
|
|
27572
|
-
const res = await requestJson(ctx, `${
|
|
27761
|
+
const res = await requestJson(ctx, `${BASE35}/commitments${q.size ? `?${q}` : ""}`);
|
|
27573
27762
|
return emit(ctx, res.body, () => table2(ctx, res.body?.commitments, commitmentRow, "No commitments."));
|
|
27574
27763
|
}
|
|
27575
27764
|
case "get": {
|
|
@@ -27619,7 +27808,7 @@ async function runDecisions(ctx, argv) {
|
|
|
27619
27808
|
write(ctx.io.stdout, ASSISTANT_HELP);
|
|
27620
27809
|
return 0;
|
|
27621
27810
|
}
|
|
27622
|
-
const res = await requestJson(ctx, `${
|
|
27811
|
+
const res = await requestJson(ctx, `${BASE35}/decisions${options.project ? `?projectId=${enc(options.project)}` : ""}`);
|
|
27623
27812
|
return emit(ctx, res.body, () => table2(ctx, res.body?.decisions, (d) => ({
|
|
27624
27813
|
decisionId: d.decisionId,
|
|
27625
27814
|
decidedAt: d.decidedAt ?? "",
|
|
@@ -27636,7 +27825,7 @@ async function runMeetings(ctx, argv) {
|
|
|
27636
27825
|
return 0;
|
|
27637
27826
|
}
|
|
27638
27827
|
if (sub === "list") {
|
|
27639
|
-
const res = await requestJson(ctx, `${
|
|
27828
|
+
const res = await requestJson(ctx, `${BASE35}/meetings`);
|
|
27640
27829
|
return emit(ctx, res.body, () => table2(ctx, res.body?.meetings, (m) => ({
|
|
27641
27830
|
meetingId: m.meetingId,
|
|
27642
27831
|
startAt: m.startAt ?? "",
|
|
@@ -27646,7 +27835,7 @@ async function runMeetings(ctx, argv) {
|
|
|
27646
27835
|
}
|
|
27647
27836
|
if (sub === "get") {
|
|
27648
27837
|
if (!positionals[0]) throw new CliError("assistant meetings get requires <meetingId>.", 2);
|
|
27649
|
-
const res = await requestJson(ctx, `${
|
|
27838
|
+
const res = await requestJson(ctx, `${BASE35}/meetings/${enc(positionals[0])}`);
|
|
27650
27839
|
const m = res.body ?? {};
|
|
27651
27840
|
return emit(ctx, res.body, () => writeFields(ctx, [
|
|
27652
27841
|
["meetingId", m.meetingId],
|
|
@@ -27675,11 +27864,11 @@ async function runPending(ctx, argv) {
|
|
|
27675
27864
|
const id = positionals[0];
|
|
27676
27865
|
const needId = () => {
|
|
27677
27866
|
if (!id) throw new CliError(`assistant pending ${sub} requires <actionId>.`, 2);
|
|
27678
|
-
return `${
|
|
27867
|
+
return `${BASE35}/pending-actions/${enc(id)}`;
|
|
27679
27868
|
};
|
|
27680
27869
|
switch (sub) {
|
|
27681
27870
|
case "list": {
|
|
27682
|
-
const res = await requestJson(ctx, `${
|
|
27871
|
+
const res = await requestJson(ctx, `${BASE35}/pending-actions${options.status ? `?status=${enc(options.status)}` : ""}`);
|
|
27683
27872
|
return emit(ctx, res.body, () => table2(ctx, res.body?.pendingActions, (a) => ({
|
|
27684
27873
|
actionId: a.actionId,
|
|
27685
27874
|
kind: a.kind ?? "",
|
|
@@ -27723,7 +27912,7 @@ async function runLoops(ctx, argv) {
|
|
|
27723
27912
|
return 0;
|
|
27724
27913
|
}
|
|
27725
27914
|
if (sub === "list") {
|
|
27726
|
-
const res = await requestJson(ctx, `${
|
|
27915
|
+
const res = await requestJson(ctx, `${BASE35}/loops`);
|
|
27727
27916
|
return emit(ctx, res.body, () => table2(ctx, res.body?.loops, (l) => ({
|
|
27728
27917
|
loopId: l.loopId,
|
|
27729
27918
|
label: l.label ?? "",
|
|
@@ -27738,7 +27927,7 @@ async function runLoops(ctx, argv) {
|
|
|
27738
27927
|
if (!loopId) throw new CliError(`assistant loops ${sub} requires <loopId>.`, 2);
|
|
27739
27928
|
const body = {};
|
|
27740
27929
|
if (sub === "enable" && options.cron) body.cronExpr = options.cron;
|
|
27741
|
-
const res = await requestJson(ctx, `${
|
|
27930
|
+
const res = await requestJson(ctx, `${BASE35}/loops/${enc(loopId)}/${sub}`, { method: "POST", body });
|
|
27742
27931
|
return emit(ctx, res.body, () => writeLine(ctx.io.stdout, `Loop ${loopId}: ${res.body?.enabled ? "enabled" : "disabled"} (job ${res.body?.jobId ?? ""}).`));
|
|
27743
27932
|
}
|
|
27744
27933
|
throw new CliError(`Unknown assistant loops command: ${sub}
|
|
@@ -27746,7 +27935,7 @@ Run \`openwop assistant --help\` for usage.`, 2);
|
|
|
27746
27935
|
}
|
|
27747
27936
|
|
|
27748
27937
|
// src/cli/channels.ts
|
|
27749
|
-
var
|
|
27938
|
+
var BASE36 = "/v1/host/openwop-app/channels";
|
|
27750
27939
|
var CHANNELS_HELP = `Usage:
|
|
27751
27940
|
openwop channels list [--json]
|
|
27752
27941
|
openwop channels create --name <n> [--description d] [--private] [--member <userId>]... [--agent <agentId>]... [--json]
|
|
@@ -27845,7 +28034,7 @@ function oneId(argv, usage6, spec = {}) {
|
|
|
27845
28034
|
const { options, positionals } = parseOptions(argv, { ...spec, bool: ["--help", ...spec.bool ?? []] });
|
|
27846
28035
|
if (options.help) return { help: true, options, positionals };
|
|
27847
28036
|
if (!positionals[0]) throw new CliError(`Usage: openwop channels ${usage6}`, 2);
|
|
27848
|
-
return { help: false, options, positionals, path: `${
|
|
28037
|
+
return { help: false, options, positionals, path: `${BASE36}/${enc(positionals[0])}` };
|
|
27849
28038
|
}
|
|
27850
28039
|
function channelSummary(res) {
|
|
27851
28040
|
const c = res?.channel ?? {};
|
|
@@ -27858,7 +28047,7 @@ async function runList4(ctx, argv) {
|
|
|
27858
28047
|
write(ctx.io.stdout, CHANNELS_HELP);
|
|
27859
28048
|
return 0;
|
|
27860
28049
|
}
|
|
27861
|
-
const res = await requestJson(ctx,
|
|
28050
|
+
const res = await requestJson(ctx, BASE36);
|
|
27862
28051
|
return emit(ctx, res.body, () => {
|
|
27863
28052
|
const rows = Array.isArray(res.body?.channels) ? res.body.channels : [];
|
|
27864
28053
|
if (!rows.length) {
|
|
@@ -27891,7 +28080,7 @@ async function runCreate(ctx, argv) {
|
|
|
27891
28080
|
if (options.description) body.description = options.description;
|
|
27892
28081
|
if (Array.isArray(options.member) && options.member.length) body.memberUserIds = options.member;
|
|
27893
28082
|
if (Array.isArray(options.agent) && options.agent.length) body.agentIds = options.agent;
|
|
27894
|
-
const res = await requestJson(ctx,
|
|
28083
|
+
const res = await requestJson(ctx, BASE36, { method: "POST", body });
|
|
27895
28084
|
return emit(ctx, res.body, () => writeLine(ctx.io.stdout, `Created channel ${channelSummary(res.body)}.`));
|
|
27896
28085
|
}
|
|
27897
28086
|
async function runGet5(ctx, argv) {
|
|
@@ -28861,7 +29050,7 @@ Run \`openwop agent-author --help\` for usage.`, 2);
|
|
|
28861
29050
|
}
|
|
28862
29051
|
|
|
28863
29052
|
// src/cli/workflowAuthor.ts
|
|
28864
|
-
var
|
|
29053
|
+
var BASE37 = "/v1/host/openwop-app/workflow-author";
|
|
28865
29054
|
var WORKFLOW_AUTHOR_HELP = `Usage:
|
|
28866
29055
|
openwop workflow-author catalog [--json]
|
|
28867
29056
|
openwop workflow-author draft --intent <text> [--provider p] [--model m] [--max-attempts n]
|
|
@@ -28897,7 +29086,7 @@ async function runWorkflowAuthor(ctx, argv) {
|
|
|
28897
29086
|
return 0;
|
|
28898
29087
|
}
|
|
28899
29088
|
if (sub === "catalog") {
|
|
28900
|
-
const res = await requestJson(ctx, `${
|
|
29089
|
+
const res = await requestJson(ctx, `${BASE37}/catalog`);
|
|
28901
29090
|
return emit(ctx, res.body, () => {
|
|
28902
29091
|
const nodes = Array.isArray(res.body?.nodes) ? res.body.nodes : [];
|
|
28903
29092
|
if (!nodes.length) writeLine(ctx.io.stdout, "No authorable nodes in this workspace.");
|
|
@@ -28913,7 +29102,7 @@ async function runWorkflowAuthor(ctx, argv) {
|
|
|
28913
29102
|
if (options.model) body.model = options.model;
|
|
28914
29103
|
const maxAttempts = intFlag(options.maxAttempts, "--max-attempts");
|
|
28915
29104
|
if (maxAttempts) body.maxAttempts = maxAttempts;
|
|
28916
|
-
const res = await requestJson(ctx, `${
|
|
29105
|
+
const res = await requestJson(ctx, `${BASE37}/draft`, { method: "POST", body, headers: idempotencyHeaders(options.idempotencyKey) });
|
|
28917
29106
|
const runId = res.body?.runId;
|
|
28918
29107
|
if (!options.follow) {
|
|
28919
29108
|
return emit(ctx, res.body, () => {
|
|
@@ -28940,7 +29129,7 @@ Run \`openwop workflow-author --help\` for usage.`, 2);
|
|
|
28940
29129
|
}
|
|
28941
29130
|
|
|
28942
29131
|
// src/cli/workflowProposals.ts
|
|
28943
|
-
var
|
|
29132
|
+
var BASE38 = "/v1/host/openwop-app/workflow-proposals/admin/policies";
|
|
28944
29133
|
var WORKFLOW_PROPOSALS_HELP = `Usage:
|
|
28945
29134
|
openwop workflow-proposals policies --tenant <tenantId> [--json]
|
|
28946
29135
|
openwop workflow-proposals enable --tenant <tenantId> --agent-profile <agentProfileId> [--json]
|
|
@@ -28971,7 +29160,7 @@ async function runWorkflowProposals(ctx, argv) {
|
|
|
28971
29160
|
}
|
|
28972
29161
|
if (!options.tenant) throw new CliError("workflow-proposals requires --tenant <tenantId>.", 2);
|
|
28973
29162
|
if (sub === "policies" || sub === "list") {
|
|
28974
|
-
const res = await requestJson(ctx, `${
|
|
29163
|
+
const res = await requestJson(ctx, `${BASE38}?tenantId=${enc(options.tenant)}`);
|
|
28975
29164
|
return emit(ctx, res.body, () => {
|
|
28976
29165
|
const items = Array.isArray(res.body?.items) ? res.body.items : [];
|
|
28977
29166
|
if (!items.length) {
|
|
@@ -28983,7 +29172,7 @@ async function runWorkflowProposals(ctx, argv) {
|
|
|
28983
29172
|
}
|
|
28984
29173
|
if (sub === "enable" || sub === "disable") {
|
|
28985
29174
|
if (!options.agentProfile) throw new CliError(`workflow-proposals ${sub} requires --agent-profile <agentProfileId>.`, 2);
|
|
28986
|
-
const path = `${
|
|
29175
|
+
const path = `${BASE38}/${enc(options.tenant)}/${enc(options.agentProfile)}`;
|
|
28987
29176
|
const res = await requestJson(ctx, path, { method: sub === "enable" ? "PUT" : "DELETE" });
|
|
28988
29177
|
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
29178
|
}
|
|
@@ -29929,6 +30118,10 @@ async function runCli(argv, options = {}) {
|
|
|
29929
30118
|
return await runConformance(ctx, commandArgs);
|
|
29930
30119
|
case "onboard":
|
|
29931
30120
|
return await runOnboard(ctx, commandArgs);
|
|
30121
|
+
case "login":
|
|
30122
|
+
return await runLogin(ctx, commandArgs);
|
|
30123
|
+
case "logout":
|
|
30124
|
+
return await runLogout(ctx, commandArgs);
|
|
29932
30125
|
case "providers":
|
|
29933
30126
|
case "provider":
|
|
29934
30127
|
return await runProviders(ctx, commandArgs);
|
|
@@ -30257,6 +30450,8 @@ var HELP_MAP = {
|
|
|
30257
30450
|
packs: PACKS_HELP,
|
|
30258
30451
|
pack: PACKS_HELP,
|
|
30259
30452
|
onboard: ONBOARD_HELP,
|
|
30453
|
+
login: LOGIN_HELP,
|
|
30454
|
+
logout: LOGIN_HELP,
|
|
30260
30455
|
providers: PROVIDERS_HELP,
|
|
30261
30456
|
provider: PROVIDERS_HELP,
|
|
30262
30457
|
agents: AGENTS_HELP,
|
|
@@ -30455,6 +30650,7 @@ Exit codes:
|
|
|
30455
30650
|
|
|
30456
30651
|
Commands:
|
|
30457
30652
|
onboard Guided first-run setup (host + provider + model + BYOK key)
|
|
30653
|
+
login | logout Sign this terminal in to an openwop-app host by a code (no key to copy)
|
|
30458
30654
|
providers list List stored BYOK credential refs (never values)
|
|
30459
30655
|
providers add Store a credential ref against the configured host
|
|
30460
30656
|
providers remove Remove a credential ref
|