@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 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) demo app (`apps/workflow-engine`, live at [app.openwop.dev](https://app.openwop.dev)) and a lightweight client for any OpenWOP-compatible host.
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
- > **Recent sprint (`[Unreleased]`, slated for `0.3.0`):** 11 new groups + a `cron enable/disable` extension surfaced the host's governance/safety, identity, extensibility, orchestration, and observability surfaces — `approvals`, `governance`, `consent`, `toggles`, `users`, `profiles`, `auth`, `mcp`, `connections`, `workforces`, `analytics`. See [`CHANGELOG.md`](./CHANGELOG.md) for the per-group detail.
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 = "0.18.2";
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, path, options = {}) {
972
- const url = new URL(path.replace(/^\//, ""), ctx.baseUrl.endsWith("/") ? ctx.baseUrl : `${ctx.baseUrl}/`);
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 url = new URL(`/v1/runs/${encodeURIComponent(runId)}/events`, ctx.baseUrl);
1049
- const headers = { accept: "text/event-stream" };
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 = "0.18.2";
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, path, options = {}) {
973
- const url = new URL(path.replace(/^\//, ""), ctx.baseUrl.endsWith("/") ? ctx.baseUrl : `${ctx.baseUrl}/`);
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 url = new URL(`/v1/runs/${encodeURIComponent(runId)}/events`, ctx.baseUrl);
1050
- const headers = { accept: "text/event-stream" };
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;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openwop/cli",
3
- "version": "0.18.2",
3
+ "version": "1.0.1",
4
4
  "description": "OpenWOP CLI for operating the workflow-engine demo app and OpenWOP-compatible hosts.",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",