@openwop/cli 0.18.2 → 1.0.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 +25 -5
- package/dist/cli.js +158 -7
- package/dist/openwop.js +158 -7
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# OpenWOP CLI
|
|
2
2
|
|
|
3
|
-
The OpenWOP CLI is the local control plane for the [OpenWOP](https://github.com/openwop/openwop)
|
|
3
|
+
The OpenWOP CLI is the local control plane for the [OpenWOP](https://github.com/openwop/openwop) reference app ([`openwop/openwop-app`](https://github.com/openwop/openwop-app), live at [app.openwop.dev](https://app.openwop.dev)) and a lightweight client for any OpenWOP-compatible host.
|
|
4
4
|
|
|
5
5
|
This is the standalone home of the `@openwop/cli` package; it ships independently of the [`openwop/openwop`](https://github.com/openwop/openwop) spec corpus.
|
|
6
6
|
|
|
@@ -12,16 +12,36 @@ The CLI is a host-agnostic **control plane**: every group drives one protocol su
|
|
|
12
12
|
|---|---|
|
|
13
13
|
| **Setup & health** | `onboard` · `doctor` · `demo` · `health` · `capabilities` · `config` · `completion` · `upgrade` |
|
|
14
14
|
| **Run lifecycle** | `runs` · `chat` · `interrupts` · `workflows` · `catalog` · `media` |
|
|
15
|
-
| **Agents & orchestration** | `agents` · `roster` · `org-chart` · `kanban` · `workforces` (`fleet`) |
|
|
15
|
+
| **Agents & orchestration** | `agents` · `roster` · `org-chart` · `kanban` (`boards`) · `workforces` (`fleet`) · `agent-profile` · `agent-packs` · `agent-allowlists` · `agent-ops` · `evals` · `twin` · `reviews` |
|
|
16
16
|
| **Governance & safety** | `approvals` · `governance` (`policy`) · `consent` · `toggles` |
|
|
17
|
-
| **Identity & access** | `orgs` · `users` · `profiles` · `auth` (`sso`) |
|
|
17
|
+
| **Identity & access** | `orgs` (`org`) · `workspaces` · `users` · `profiles` · `auth` (`sso`) |
|
|
18
18
|
| **Extensibility & connections** | `packs` · `mcp` · `connections` (`conn`) · `providers` · `byok` |
|
|
19
19
|
| **Memory & workspace** | `memory` · `workspace` · `prompts` |
|
|
20
20
|
| **Automation & messaging** | `cron` · `webhooks` · `messaging` · `relay` · `notifications` · `notify` |
|
|
21
21
|
| **Observability & admin** | `analytics` (`usage`) · `account` · `admin` · `brand` · `conformance` |
|
|
22
|
-
| **Product surfaces** | `crm` · `csm` · `comments` · `sharing` · `forms` · `email` · `chat-widget` · `marketplace` · `kb` · `cms` · `documents` · `projects` |
|
|
22
|
+
| **Product surfaces** | `crm` · `csm` · `comments` · `sharing` · `forms` · `email` · `chat-widget` · `marketplace` · `kb` · `cms` · `documents` · `projects` · `strategy` · `advisors` · `campaigns-orchestration` · `notebooks` · `podcasts` · `priority-matrix` |
|
|
23
|
+
| **Protocol surfaces (RFC)** | `a2a` · `triggers` · `goals` · `proposals` · `export` / `import` |
|
|
23
24
|
|
|
24
|
-
>
|
|
25
|
+
> **`0.18.x`:** the catalog now covers the full app feature surface — the agent
|
|
26
|
+
> platform (`agent-profile`, `agent-packs`, `agent-allowlists`, `agent-ops`,
|
|
27
|
+
> `evals`, `twin`, `reviews`), workspace tenancy (`workspaces`), and the product
|
|
28
|
+
> surfaces (`strategy`, `advisors`, `campaigns-orchestration`, `notebooks`,
|
|
29
|
+
> `podcasts`, `priority-matrix`) — alongside the protocol RFC surfaces (`a2a`,
|
|
30
|
+
> `triggers`, `goals`, `proposals`, `export`/`import`). See [`CHANGELOG.md`](./CHANGELOG.md)
|
|
31
|
+
> for the per-group detail.
|
|
32
|
+
|
|
33
|
+
## Protocol version support (v2 and v1)
|
|
34
|
+
|
|
35
|
+
The CLI speaks the **OpenWOP wire directly** — no SDK dependency — and negotiates the protocol major once per invocation (`src/protocol.ts`, per `spec/v2/core/versioning.md` §1.5):
|
|
36
|
+
|
|
37
|
+
- It reads `/.well-known/openwop` and selects the **highest major it implements that the host advertises** in `protocolVersions[]` — 2 when the host lists any `2.x`, otherwise 1.
|
|
38
|
+
- Under major 2, every request for an operation named in `spec/v2/path-manifest.json` goes to the **unversioned path with `OpenWOP-Version: 2.0`** (`/v1/runs` → `/runs`). Host-proprietary routes the manifest does not name — the demo backend's `/v1/host/sample/*` — are sent exactly as written; they have no v2 home yet (`versioning.md` §5).
|
|
39
|
+
- Under major 1 nothing changes: `/v1/…` paths, header-less, the v1 default the overlap guarantees.
|
|
40
|
+
- `OPENWOP_PROTOCOL_MAJOR=1` or `=2` pins the major without probing discovery.
|
|
41
|
+
|
|
42
|
+
`openwop doctor`'s `protocol` row reports `protocolVersions`, `preferredVersion`, and the major this process selected; it fails only when the host advertises neither major the CLI implements.
|
|
43
|
+
|
|
44
|
+
The pre-1.0 `0.18.x` line was frozen v1-only; that decision was reversed with 1.0.0 (CHANGELOG). The frozen line stays on branch `cli-v1-frozen` for anyone who needs a client that never sends `OpenWOP-Version`.
|
|
25
45
|
|
|
26
46
|
## Install
|
|
27
47
|
|
package/dist/cli.js
CHANGED
|
@@ -521,8 +521,58 @@ function errText(err) {
|
|
|
521
521
|
return err instanceof Error ? err.message : String(err);
|
|
522
522
|
}
|
|
523
523
|
|
|
524
|
+
// package.json
|
|
525
|
+
var package_default = {
|
|
526
|
+
name: "@openwop/cli",
|
|
527
|
+
version: "1.0.1",
|
|
528
|
+
description: "OpenWOP CLI for operating the workflow-engine demo app and OpenWOP-compatible hosts.",
|
|
529
|
+
license: "Apache-2.0",
|
|
530
|
+
type: "module",
|
|
531
|
+
repository: {
|
|
532
|
+
type: "git",
|
|
533
|
+
url: "git+https://github.com/openwop/openwop-cli.git"
|
|
534
|
+
},
|
|
535
|
+
homepage: "https://app.openwop.dev/cli",
|
|
536
|
+
bugs: {
|
|
537
|
+
url: "https://github.com/openwop/openwop-cli/issues"
|
|
538
|
+
},
|
|
539
|
+
bin: {
|
|
540
|
+
openwop: "dist/openwop.js"
|
|
541
|
+
},
|
|
542
|
+
files: [
|
|
543
|
+
"dist",
|
|
544
|
+
"install.sh",
|
|
545
|
+
"README.md"
|
|
546
|
+
],
|
|
547
|
+
scripts: {
|
|
548
|
+
build: `rm -rf dist && esbuild src/openwop.ts src/cli.ts --bundle --platform=node --target=node20 --format=esm --outdir=dist --packages=external --banner:js="import { createRequire as _cr } from 'module'; const require = _cr(import.meta.url);"`,
|
|
549
|
+
typecheck: "tsc --noEmit",
|
|
550
|
+
test: "npm run build && node --test test/*.test.mjs"
|
|
551
|
+
},
|
|
552
|
+
devDependencies: {
|
|
553
|
+
"@types/node": "^20.14.0",
|
|
554
|
+
esbuild: "^0.25.0",
|
|
555
|
+
typescript: "^5.6.0"
|
|
556
|
+
},
|
|
557
|
+
peerDependencies: {
|
|
558
|
+
"@whiskeysockets/baileys": ">=6",
|
|
559
|
+
"discord.js": ">=14"
|
|
560
|
+
},
|
|
561
|
+
peerDependenciesMeta: {
|
|
562
|
+
"@whiskeysockets/baileys": {
|
|
563
|
+
optional: true
|
|
564
|
+
},
|
|
565
|
+
"discord.js": {
|
|
566
|
+
optional: true
|
|
567
|
+
}
|
|
568
|
+
},
|
|
569
|
+
engines: {
|
|
570
|
+
node: ">=20"
|
|
571
|
+
}
|
|
572
|
+
};
|
|
573
|
+
|
|
524
574
|
// src/constants.ts
|
|
525
|
-
var VERSION =
|
|
575
|
+
var VERSION = package_default.version;
|
|
526
576
|
var DEFAULT_BASE_URL = "http://localhost:8080";
|
|
527
577
|
var DEFAULT_REGISTRY_URL = "https://packs.openwop.dev";
|
|
528
578
|
var DEFAULT_API_KEY = "sample-token";
|
|
@@ -967,14 +1017,105 @@ function project(root, name, relativeDir) {
|
|
|
967
1017
|
// src/sse.ts
|
|
968
1018
|
import { createInterface as createInterface2 } from "node:readline";
|
|
969
1019
|
|
|
1020
|
+
// src/protocol.ts
|
|
1021
|
+
var CLI_PROTOCOL_MAJORS = [2, 1];
|
|
1022
|
+
var V2_PATH_TEMPLATES = [
|
|
1023
|
+
"/agents",
|
|
1024
|
+
"/agents/org-chart",
|
|
1025
|
+
"/agents/org-chart/{departmentId}",
|
|
1026
|
+
"/agents/roster",
|
|
1027
|
+
"/agents/roster/{rosterId}",
|
|
1028
|
+
"/agents/{agentId}",
|
|
1029
|
+
"/agents/{agentId}/deployments",
|
|
1030
|
+
"/audit/verify",
|
|
1031
|
+
"/content/pages",
|
|
1032
|
+
"/content/pages/{pageId}/sections/{sectionId}",
|
|
1033
|
+
"/content/pages/{slug}",
|
|
1034
|
+
"/content/settings",
|
|
1035
|
+
"/host/effect-seams",
|
|
1036
|
+
"/host/events",
|
|
1037
|
+
"/interrupts/{token}",
|
|
1038
|
+
"/prompts",
|
|
1039
|
+
"/prompts/{templateId}",
|
|
1040
|
+
"/prompts:render",
|
|
1041
|
+
"/runs",
|
|
1042
|
+
"/runs/{runId}",
|
|
1043
|
+
"/runs/{runId}/ancestry",
|
|
1044
|
+
"/runs/{runId}/annotations",
|
|
1045
|
+
"/runs/{runId}/artifacts/{artifactId}",
|
|
1046
|
+
"/runs/{runId}/cancel",
|
|
1047
|
+
"/runs/{runId}/compensation",
|
|
1048
|
+
"/runs/{runId}/effects",
|
|
1049
|
+
"/runs/{runId}/eval-summary",
|
|
1050
|
+
"/runs/{runId}/events",
|
|
1051
|
+
"/runs/{runId}/events/poll",
|
|
1052
|
+
"/runs/{runId}/interrupts/{nodeId}",
|
|
1053
|
+
"/runs/{runId}:diff",
|
|
1054
|
+
"/runs/{runId}:fork",
|
|
1055
|
+
"/runs/{runId}:pause",
|
|
1056
|
+
"/runs/{runId}:resume",
|
|
1057
|
+
"/runs:bulk-cancel",
|
|
1058
|
+
"/tools",
|
|
1059
|
+
"/tools/{toolId}",
|
|
1060
|
+
"/trigger-subscriptions",
|
|
1061
|
+
"/webhooks",
|
|
1062
|
+
"/webhooks/{webhookId}",
|
|
1063
|
+
"/workflows/{workflowId}"
|
|
1064
|
+
];
|
|
1065
|
+
var V2_MATCHERS = V2_PATH_TEMPLATES.map(
|
|
1066
|
+
(t) => new RegExp(`^${t.replace(/[.:]/g, "\\$&").replace(/\{[A-Za-z]+\}/g, "[^/]+")}$`)
|
|
1067
|
+
);
|
|
1068
|
+
function v2Twin(path) {
|
|
1069
|
+
const q = path.indexOf("?");
|
|
1070
|
+
const bare = q === -1 ? path : path.slice(0, q);
|
|
1071
|
+
const query = q === -1 ? "" : path.slice(q);
|
|
1072
|
+
if (!bare.startsWith("/v1/")) return null;
|
|
1073
|
+
const unversioned = bare.slice("/v1".length);
|
|
1074
|
+
return V2_MATCHERS.some((m) => m.test(unversioned)) ? `${unversioned}${query}` : null;
|
|
1075
|
+
}
|
|
1076
|
+
function selectMajor(protocolVersions) {
|
|
1077
|
+
const advertised = Array.isArray(protocolVersions) ? protocolVersions.filter((v) => typeof v === "string") : [];
|
|
1078
|
+
for (const major of CLI_PROTOCOL_MAJORS) {
|
|
1079
|
+
if (advertised.some((v) => v.startsWith(`${major}.`))) return major;
|
|
1080
|
+
}
|
|
1081
|
+
return 1;
|
|
1082
|
+
}
|
|
1083
|
+
async function negotiateMajor(ctx) {
|
|
1084
|
+
if (ctx.protocolMajor !== void 0) return ctx.protocolMajor;
|
|
1085
|
+
const pinned = ctx.env?.OPENWOP_PROTOCOL_MAJOR;
|
|
1086
|
+
if (pinned === "1" || pinned === "2") {
|
|
1087
|
+
ctx.protocolMajor = Number(pinned);
|
|
1088
|
+
return ctx.protocolMajor;
|
|
1089
|
+
}
|
|
1090
|
+
let major = 1;
|
|
1091
|
+
try {
|
|
1092
|
+
const url = new URL(".well-known/openwop", ctx.baseUrl.endsWith("/") ? ctx.baseUrl : `${ctx.baseUrl}/`);
|
|
1093
|
+
const res = await ctx.fetchImpl(url, { method: "GET", headers: { accept: "application/json" } });
|
|
1094
|
+
if (res.ok) {
|
|
1095
|
+
const doc = JSON.parse(await res.text());
|
|
1096
|
+
major = selectMajor(doc?.protocolVersions);
|
|
1097
|
+
}
|
|
1098
|
+
} catch {
|
|
1099
|
+
}
|
|
1100
|
+
ctx.protocolMajor = major;
|
|
1101
|
+
return major;
|
|
1102
|
+
}
|
|
1103
|
+
async function resolveRequest(ctx, path, headers) {
|
|
1104
|
+
const major = await negotiateMajor(ctx);
|
|
1105
|
+
if (major !== 2) return { path, headers };
|
|
1106
|
+
const twin = v2Twin(path);
|
|
1107
|
+
if (twin === null) return { path, headers };
|
|
1108
|
+
return { path: twin, headers: { ...headers, "openwop-version": "2.0" } };
|
|
1109
|
+
}
|
|
1110
|
+
|
|
970
1111
|
// src/api.ts
|
|
971
|
-
async function requestJson(ctx,
|
|
972
|
-
const
|
|
973
|
-
const headers = {
|
|
1112
|
+
async function requestJson(ctx, requestedPath, options = {}) {
|
|
1113
|
+
const { path, headers } = await resolveRequest(ctx, requestedPath, {
|
|
974
1114
|
accept: "application/json",
|
|
975
1115
|
...options.body !== void 0 ? { "content-type": "application/json" } : {},
|
|
976
1116
|
...options.headers ?? {}
|
|
977
|
-
};
|
|
1117
|
+
});
|
|
1118
|
+
const url = new URL(path.replace(/^\//, ""), ctx.baseUrl.endsWith("/") ? ctx.baseUrl : `${ctx.baseUrl}/`);
|
|
978
1119
|
if (options.auth !== false && ctx.apiKey) {
|
|
979
1120
|
headers.authorization = `Bearer ${ctx.apiKey}`;
|
|
980
1121
|
}
|
|
@@ -1045,8 +1186,8 @@ async function streamRunEvents(ctx, runId, { onEvent, useStream = true, timeoutM
|
|
|
1045
1186
|
await streamViaPoll(ctx, runId, onEvent, timeoutMs);
|
|
1046
1187
|
}
|
|
1047
1188
|
async function streamViaSse(ctx, runId, onEvent) {
|
|
1048
|
-
const
|
|
1049
|
-
const
|
|
1189
|
+
const { path, headers } = await resolveRequest(ctx, `/v1/runs/${encodeURIComponent(runId)}/events`, { accept: "text/event-stream" });
|
|
1190
|
+
const url = new URL(path.replace(/^\//, ""), ctx.baseUrl.endsWith("/") ? ctx.baseUrl : `${ctx.baseUrl}/`);
|
|
1050
1191
|
if (ctx.apiKey) headers.authorization = `Bearer ${ctx.apiKey}`;
|
|
1051
1192
|
const res = await ctx.fetchImpl(url, { method: "GET", headers });
|
|
1052
1193
|
if (!res.ok) throw new HttpError(`HTTP ${res.status}`, res.status, null);
|
|
@@ -9291,6 +9432,16 @@ async function runDoctor(ctx, argv) {
|
|
|
9291
9432
|
const health = await probeEndpoint(ctx, "/health");
|
|
9292
9433
|
if (health.ok) checks.push(ok("demo health", `${ctx.baseUrl}/health responded`));
|
|
9293
9434
|
else checks.push(warn("demo health", `demo is not reachable at ${ctx.baseUrl} (${health.message})`));
|
|
9435
|
+
const discovery = await safeRequest(ctx, "/.well-known/openwop", { auth: false });
|
|
9436
|
+
const versions = discovery?.ok ? discovery.body?.protocolVersions : void 0;
|
|
9437
|
+
if (Array.isArray(versions) && versions.length > 0) {
|
|
9438
|
+
const advertised = versions.filter((v) => typeof v === "string");
|
|
9439
|
+
const preferred = typeof discovery.body?.preferredVersion === "string" ? discovery.body.preferredVersion : "?";
|
|
9440
|
+
const selected = await negotiateMajor(ctx);
|
|
9441
|
+
const detail = `protocolVersions ${advertised.join(", ")}; preferredVersion ${preferred}; CLI speaks major ${selected}`;
|
|
9442
|
+
if (advertised.some((v) => v.startsWith(`${selected}.`))) checks.push(ok("protocol", detail));
|
|
9443
|
+
else checks.push(fail("protocol", `${detail} \u2014 host advertises neither major this CLI implements; see README \xA7"Protocol version support"`));
|
|
9444
|
+
}
|
|
9294
9445
|
const daemon = await safeRequest(ctx, "/v1/host/sample/daemon-status");
|
|
9295
9446
|
if (daemon.ok && daemon.body) {
|
|
9296
9447
|
const b = daemon.body;
|
package/dist/openwop.js
CHANGED
|
@@ -522,8 +522,58 @@ function errText(err) {
|
|
|
522
522
|
return err instanceof Error ? err.message : String(err);
|
|
523
523
|
}
|
|
524
524
|
|
|
525
|
+
// package.json
|
|
526
|
+
var package_default = {
|
|
527
|
+
name: "@openwop/cli",
|
|
528
|
+
version: "1.0.1",
|
|
529
|
+
description: "OpenWOP CLI for operating the workflow-engine demo app and OpenWOP-compatible hosts.",
|
|
530
|
+
license: "Apache-2.0",
|
|
531
|
+
type: "module",
|
|
532
|
+
repository: {
|
|
533
|
+
type: "git",
|
|
534
|
+
url: "git+https://github.com/openwop/openwop-cli.git"
|
|
535
|
+
},
|
|
536
|
+
homepage: "https://app.openwop.dev/cli",
|
|
537
|
+
bugs: {
|
|
538
|
+
url: "https://github.com/openwop/openwop-cli/issues"
|
|
539
|
+
},
|
|
540
|
+
bin: {
|
|
541
|
+
openwop: "dist/openwop.js"
|
|
542
|
+
},
|
|
543
|
+
files: [
|
|
544
|
+
"dist",
|
|
545
|
+
"install.sh",
|
|
546
|
+
"README.md"
|
|
547
|
+
],
|
|
548
|
+
scripts: {
|
|
549
|
+
build: `rm -rf dist && esbuild src/openwop.ts src/cli.ts --bundle --platform=node --target=node20 --format=esm --outdir=dist --packages=external --banner:js="import { createRequire as _cr } from 'module'; const require = _cr(import.meta.url);"`,
|
|
550
|
+
typecheck: "tsc --noEmit",
|
|
551
|
+
test: "npm run build && node --test test/*.test.mjs"
|
|
552
|
+
},
|
|
553
|
+
devDependencies: {
|
|
554
|
+
"@types/node": "^20.14.0",
|
|
555
|
+
esbuild: "^0.25.0",
|
|
556
|
+
typescript: "^5.6.0"
|
|
557
|
+
},
|
|
558
|
+
peerDependencies: {
|
|
559
|
+
"@whiskeysockets/baileys": ">=6",
|
|
560
|
+
"discord.js": ">=14"
|
|
561
|
+
},
|
|
562
|
+
peerDependenciesMeta: {
|
|
563
|
+
"@whiskeysockets/baileys": {
|
|
564
|
+
optional: true
|
|
565
|
+
},
|
|
566
|
+
"discord.js": {
|
|
567
|
+
optional: true
|
|
568
|
+
}
|
|
569
|
+
},
|
|
570
|
+
engines: {
|
|
571
|
+
node: ">=20"
|
|
572
|
+
}
|
|
573
|
+
};
|
|
574
|
+
|
|
525
575
|
// src/constants.ts
|
|
526
|
-
var VERSION =
|
|
576
|
+
var VERSION = package_default.version;
|
|
527
577
|
var DEFAULT_BASE_URL = "http://localhost:8080";
|
|
528
578
|
var DEFAULT_REGISTRY_URL = "https://packs.openwop.dev";
|
|
529
579
|
var DEFAULT_API_KEY = "sample-token";
|
|
@@ -968,14 +1018,105 @@ function project(root, name, relativeDir) {
|
|
|
968
1018
|
// src/sse.ts
|
|
969
1019
|
import { createInterface as createInterface2 } from "node:readline";
|
|
970
1020
|
|
|
1021
|
+
// src/protocol.ts
|
|
1022
|
+
var CLI_PROTOCOL_MAJORS = [2, 1];
|
|
1023
|
+
var V2_PATH_TEMPLATES = [
|
|
1024
|
+
"/agents",
|
|
1025
|
+
"/agents/org-chart",
|
|
1026
|
+
"/agents/org-chart/{departmentId}",
|
|
1027
|
+
"/agents/roster",
|
|
1028
|
+
"/agents/roster/{rosterId}",
|
|
1029
|
+
"/agents/{agentId}",
|
|
1030
|
+
"/agents/{agentId}/deployments",
|
|
1031
|
+
"/audit/verify",
|
|
1032
|
+
"/content/pages",
|
|
1033
|
+
"/content/pages/{pageId}/sections/{sectionId}",
|
|
1034
|
+
"/content/pages/{slug}",
|
|
1035
|
+
"/content/settings",
|
|
1036
|
+
"/host/effect-seams",
|
|
1037
|
+
"/host/events",
|
|
1038
|
+
"/interrupts/{token}",
|
|
1039
|
+
"/prompts",
|
|
1040
|
+
"/prompts/{templateId}",
|
|
1041
|
+
"/prompts:render",
|
|
1042
|
+
"/runs",
|
|
1043
|
+
"/runs/{runId}",
|
|
1044
|
+
"/runs/{runId}/ancestry",
|
|
1045
|
+
"/runs/{runId}/annotations",
|
|
1046
|
+
"/runs/{runId}/artifacts/{artifactId}",
|
|
1047
|
+
"/runs/{runId}/cancel",
|
|
1048
|
+
"/runs/{runId}/compensation",
|
|
1049
|
+
"/runs/{runId}/effects",
|
|
1050
|
+
"/runs/{runId}/eval-summary",
|
|
1051
|
+
"/runs/{runId}/events",
|
|
1052
|
+
"/runs/{runId}/events/poll",
|
|
1053
|
+
"/runs/{runId}/interrupts/{nodeId}",
|
|
1054
|
+
"/runs/{runId}:diff",
|
|
1055
|
+
"/runs/{runId}:fork",
|
|
1056
|
+
"/runs/{runId}:pause",
|
|
1057
|
+
"/runs/{runId}:resume",
|
|
1058
|
+
"/runs:bulk-cancel",
|
|
1059
|
+
"/tools",
|
|
1060
|
+
"/tools/{toolId}",
|
|
1061
|
+
"/trigger-subscriptions",
|
|
1062
|
+
"/webhooks",
|
|
1063
|
+
"/webhooks/{webhookId}",
|
|
1064
|
+
"/workflows/{workflowId}"
|
|
1065
|
+
];
|
|
1066
|
+
var V2_MATCHERS = V2_PATH_TEMPLATES.map(
|
|
1067
|
+
(t) => new RegExp(`^${t.replace(/[.:]/g, "\\$&").replace(/\{[A-Za-z]+\}/g, "[^/]+")}$`)
|
|
1068
|
+
);
|
|
1069
|
+
function v2Twin(path) {
|
|
1070
|
+
const q = path.indexOf("?");
|
|
1071
|
+
const bare = q === -1 ? path : path.slice(0, q);
|
|
1072
|
+
const query = q === -1 ? "" : path.slice(q);
|
|
1073
|
+
if (!bare.startsWith("/v1/")) return null;
|
|
1074
|
+
const unversioned = bare.slice("/v1".length);
|
|
1075
|
+
return V2_MATCHERS.some((m) => m.test(unversioned)) ? `${unversioned}${query}` : null;
|
|
1076
|
+
}
|
|
1077
|
+
function selectMajor(protocolVersions) {
|
|
1078
|
+
const advertised = Array.isArray(protocolVersions) ? protocolVersions.filter((v) => typeof v === "string") : [];
|
|
1079
|
+
for (const major of CLI_PROTOCOL_MAJORS) {
|
|
1080
|
+
if (advertised.some((v) => v.startsWith(`${major}.`))) return major;
|
|
1081
|
+
}
|
|
1082
|
+
return 1;
|
|
1083
|
+
}
|
|
1084
|
+
async function negotiateMajor(ctx) {
|
|
1085
|
+
if (ctx.protocolMajor !== void 0) return ctx.protocolMajor;
|
|
1086
|
+
const pinned = ctx.env?.OPENWOP_PROTOCOL_MAJOR;
|
|
1087
|
+
if (pinned === "1" || pinned === "2") {
|
|
1088
|
+
ctx.protocolMajor = Number(pinned);
|
|
1089
|
+
return ctx.protocolMajor;
|
|
1090
|
+
}
|
|
1091
|
+
let major = 1;
|
|
1092
|
+
try {
|
|
1093
|
+
const url = new URL(".well-known/openwop", ctx.baseUrl.endsWith("/") ? ctx.baseUrl : `${ctx.baseUrl}/`);
|
|
1094
|
+
const res = await ctx.fetchImpl(url, { method: "GET", headers: { accept: "application/json" } });
|
|
1095
|
+
if (res.ok) {
|
|
1096
|
+
const doc = JSON.parse(await res.text());
|
|
1097
|
+
major = selectMajor(doc?.protocolVersions);
|
|
1098
|
+
}
|
|
1099
|
+
} catch {
|
|
1100
|
+
}
|
|
1101
|
+
ctx.protocolMajor = major;
|
|
1102
|
+
return major;
|
|
1103
|
+
}
|
|
1104
|
+
async function resolveRequest(ctx, path, headers) {
|
|
1105
|
+
const major = await negotiateMajor(ctx);
|
|
1106
|
+
if (major !== 2) return { path, headers };
|
|
1107
|
+
const twin = v2Twin(path);
|
|
1108
|
+
if (twin === null) return { path, headers };
|
|
1109
|
+
return { path: twin, headers: { ...headers, "openwop-version": "2.0" } };
|
|
1110
|
+
}
|
|
1111
|
+
|
|
971
1112
|
// src/api.ts
|
|
972
|
-
async function requestJson(ctx,
|
|
973
|
-
const
|
|
974
|
-
const headers = {
|
|
1113
|
+
async function requestJson(ctx, requestedPath, options = {}) {
|
|
1114
|
+
const { path, headers } = await resolveRequest(ctx, requestedPath, {
|
|
975
1115
|
accept: "application/json",
|
|
976
1116
|
...options.body !== void 0 ? { "content-type": "application/json" } : {},
|
|
977
1117
|
...options.headers ?? {}
|
|
978
|
-
};
|
|
1118
|
+
});
|
|
1119
|
+
const url = new URL(path.replace(/^\//, ""), ctx.baseUrl.endsWith("/") ? ctx.baseUrl : `${ctx.baseUrl}/`);
|
|
979
1120
|
if (options.auth !== false && ctx.apiKey) {
|
|
980
1121
|
headers.authorization = `Bearer ${ctx.apiKey}`;
|
|
981
1122
|
}
|
|
@@ -1046,8 +1187,8 @@ async function streamRunEvents(ctx, runId, { onEvent, useStream = true, timeoutM
|
|
|
1046
1187
|
await streamViaPoll(ctx, runId, onEvent, timeoutMs);
|
|
1047
1188
|
}
|
|
1048
1189
|
async function streamViaSse(ctx, runId, onEvent) {
|
|
1049
|
-
const
|
|
1050
|
-
const
|
|
1190
|
+
const { path, headers } = await resolveRequest(ctx, `/v1/runs/${encodeURIComponent(runId)}/events`, { accept: "text/event-stream" });
|
|
1191
|
+
const url = new URL(path.replace(/^\//, ""), ctx.baseUrl.endsWith("/") ? ctx.baseUrl : `${ctx.baseUrl}/`);
|
|
1051
1192
|
if (ctx.apiKey) headers.authorization = `Bearer ${ctx.apiKey}`;
|
|
1052
1193
|
const res = await ctx.fetchImpl(url, { method: "GET", headers });
|
|
1053
1194
|
if (!res.ok) throw new HttpError(`HTTP ${res.status}`, res.status, null);
|
|
@@ -9292,6 +9433,16 @@ async function runDoctor(ctx, argv) {
|
|
|
9292
9433
|
const health = await probeEndpoint(ctx, "/health");
|
|
9293
9434
|
if (health.ok) checks.push(ok("demo health", `${ctx.baseUrl}/health responded`));
|
|
9294
9435
|
else checks.push(warn("demo health", `demo is not reachable at ${ctx.baseUrl} (${health.message})`));
|
|
9436
|
+
const discovery = await safeRequest(ctx, "/.well-known/openwop", { auth: false });
|
|
9437
|
+
const versions = discovery?.ok ? discovery.body?.protocolVersions : void 0;
|
|
9438
|
+
if (Array.isArray(versions) && versions.length > 0) {
|
|
9439
|
+
const advertised = versions.filter((v) => typeof v === "string");
|
|
9440
|
+
const preferred = typeof discovery.body?.preferredVersion === "string" ? discovery.body.preferredVersion : "?";
|
|
9441
|
+
const selected = await negotiateMajor(ctx);
|
|
9442
|
+
const detail = `protocolVersions ${advertised.join(", ")}; preferredVersion ${preferred}; CLI speaks major ${selected}`;
|
|
9443
|
+
if (advertised.some((v) => v.startsWith(`${selected}.`))) checks.push(ok("protocol", detail));
|
|
9444
|
+
else checks.push(fail("protocol", `${detail} \u2014 host advertises neither major this CLI implements; see README \xA7"Protocol version support"`));
|
|
9445
|
+
}
|
|
9295
9446
|
const daemon = await safeRequest(ctx, "/v1/host/sample/daemon-status");
|
|
9296
9447
|
if (daemon.ok && daemon.body) {
|
|
9297
9448
|
const b = daemon.body;
|