@fulldivevr/workcord-cli 1.6.0 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @fulldivevr/workcord-cli
2
2
 
3
- TypeScript CLI for talking to WorkCord agents through persistent Hermes tenant
3
+ TypeScript CLI for talking to WorkCord agents through persistent Autoworker Hub tenant
4
4
  chat and using the WorkCord API. **One invocation = one user action.** Designed
5
5
  for automated agents such as Claude Code: ask the user's Assistant for the
6
6
  outcome you need, let that tenant manage its own instructions, skills, and
@@ -149,7 +149,7 @@ workcord [--as <userId>] <namespace> <command> [flags]
149
149
  ### Agent-first customization
150
150
 
151
151
  To change agent behavior, create or update a skill, or maintain a flavor, talk
152
- to the owning agent through Hermes tenant chat. Do not edit prompts or tenant
152
+ to the owning agent through Hub tenant chat. Do not edit prompts or tenant
153
153
  files directly. With no `--agent`, the user's non-deletable Assistant is the
154
154
  target and becomes the default owner of anything it creates:
155
155
 
@@ -164,7 +164,7 @@ Use the returned `chatId` for follow-up, verification, or rollback:
164
164
  workcord agent chat send --chat "$CHAT_ID" --message "Verify the change, list the versions you created, and explain how to roll it back."
165
165
  ```
166
166
 
167
- Both commands wait up to two minutes by default and return the durable Hermes
167
+ Both commands wait up to two minutes by default and return the durable Hub
168
168
  message document. Use `--async` for a queued response, then continue with its
169
169
  `messageId`:
170
170
 
@@ -184,8 +184,8 @@ workcord agent chat new --agent "$AGENT_ID" --message "Create and maintain a fin
184
184
 
185
185
  The Assistant or selected agent works within its tenant's Hub permissions. It
186
186
  can safely validate changes and report what it activated. `agent chat` uses
187
- Hermes' native durable `hub_chat` transport; it is not raw A2A wire traffic.
188
- A2A remains available for external agent peers. Direct `hermes` commands are
187
+ the Hub's native durable `hub_chat` transport; it is not raw A2A wire traffic.
188
+ A2A remains available for external agent peers. Direct `hub` commands are
189
189
  advanced diagnostics and recovery tools, not the normal customization workflow.
190
190
 
191
191
  - `workcord --help` lists namespaces.
@@ -321,22 +321,25 @@ workcord --as $U dm send-text --to $OTHER --text "hey"
321
321
  # → composite: opens (or finds) the DM room, sends the message, returns both
322
322
  ```
323
323
 
324
- ## Advanced Hermes diagnostics and recovery (`hermes` namespace)
324
+ ## Advanced Hub diagnostics and recovery (`hub` namespace)
325
325
 
326
- WorkCord provisions a **Hermes Hub tenant** for each room-agent, Hermes custom
326
+ WorkCord provisions an **Autoworker Hub tenant** for each room-agent, custom
327
327
  agent, and room-scoped marketplace flavor install. That tenant is where the
328
328
  agent actually runs: its chats, runs, files, skills, flavor pin, A2A peers and
329
329
  eval runs all live on the Hub, not in WorkCord. Normal changes should be
330
- requested with `workcord agent chat`; the `hermes` namespace exists for direct
330
+ requested with `workcord agent chat`; the `hub` namespace exists for direct
331
331
  inspection, diagnostics, and recovery.
332
332
 
333
333
  This is the one namespace that talks to a **second origin**. Every other command
334
- goes to the WorkCord API; `hermes` uses the WorkCord API only to reveal the
334
+ goes to the WorkCord API; `hub` uses the WorkCord API only to reveal the
335
335
  tenant key, then calls the Hub's `/v1/tenant-api/*` routes with it.
336
336
 
337
+ `workcord hub ...` is a hidden alias of `workcord hub ...`, kept for one
338
+ release. New scripts should use `hub`.
339
+
337
340
  ### Target selection
338
341
 
339
- Every `hermes` command takes exactly one of:
342
+ Every `hub` command takes exactly one of:
340
343
 
341
344
  | Flag | Meaning |
342
345
  | --- | --- |
@@ -355,11 +358,16 @@ and is **never** accepted as a flag:
355
358
 
356
359
  | Env var | Meaning |
357
360
  | --- | --- |
358
- | `WORKCORD_HERMES_KEY` | tenant key, used verbatim; requires `WORKCORD_HERMES_HUB_URL` |
359
- | `WORKCORD_HERMES_HUB_URL` | Hub origin (bare origin, no path); requires `WORKCORD_HERMES_KEY` |
360
- | `WORKCORD_HERMES_TENANT_ID` | tenant id for the tenant-scoped routes, alongside the two above |
361
+ | `WORKCORD_HUB_KEY` | tenant key, used verbatim; requires `WORKCORD_HUB_URL` |
362
+ | `WORKCORD_HUB_URL` | Hub origin (bare origin, no path); requires `WORKCORD_HUB_KEY` |
363
+ | `WORKCORD_HUB_TENANT_ID` | tenant id for the tenant-scoped routes, alongside the two above |
364
+ | `WORKCORD_HUB_MANAGED` | `1` enables managed mode (see below) |
365
+
366
+ The older `WORKCORD_HERMES_KEY`, `WORKCORD_HERMES_HUB_URL`,
367
+ `WORKCORD_HERMES_TENANT_ID` and `WORKCORD_HERMES_MANAGED` names still work and
368
+ take precedence when both are set.
361
369
 
362
- Setting only one of `WORKCORD_HERMES_KEY` / `WORKCORD_HERMES_HUB_URL` is an
370
+ Setting only one of `WORKCORD_HUB_KEY` / `WORKCORD_HUB_URL` is an
363
371
  error — the CLI will not half-guess a hub.
364
372
 
365
373
  With none of them set, the CLI calls
@@ -376,34 +384,56 @@ under `hermes`, alongside the saved login. The file is written `0600` inside a
376
384
  | `--refresh` | ignore the cached entry, re-reveal, rewrite the cache |
377
385
  | `--no-cache` | neither read nor write the cache for this invocation |
378
386
 
379
- Env credentials always win over the cache. `hermes key` prints the resolved
387
+ Env credentials always win over the cache. `hub key` prints the resolved
380
388
  credentials on stdout — that is its whole job; no other command emits key
381
389
  material.
382
390
 
391
+ ### Managed mode
392
+
393
+ A personal Shadow tenant runs this CLI with a WorkCord token that WorkCord
394
+ resolves to the owner user. It must use the same `hub` commands, but with a
395
+ per-call reveal and nothing on disk. Managed mode is enabled by
396
+ `WORKCORD_HUB_MANAGED=1` (or `WORKCORD_HERMES_MANAGED=1`), or per invocation
397
+ with `--managed`. In managed mode the CLI:
398
+
399
+ - always reveals the key through `POST /api/v1/agents/{id}/hermes-cli-key/reveal`,
400
+ - never reads or writes `~/.workcord/config.json` for hub credentials,
401
+ - ignores `WORKCORD_HUB_KEY` / `WORKCORD_HERMES_KEY`,
402
+ - rejects `--as` with an error,
403
+ - never prints the key (`hub key` prints only `tenantId` and `hubBaseUrl`).
404
+
405
+ ```bash
406
+ export WORKCORD_TOKEN=... # the owner user's token
407
+ export WORKCORD_HUB_MANAGED=1
408
+ workcord hub flavor set --agent $AGENT --flavor-version 1.4.0
409
+ workcord hub flavor subscribe --agent $AGENT --policy stable
410
+ workcord hub agent restart --agent $AGENT
411
+ ```
412
+
383
413
  ### Commands
384
414
 
385
415
  | Group | What |
386
416
  | --- | --- |
387
- | `hermes key` / `whoami` / `runtime` | reveal credentials, show the tenant, show its runtime |
388
- | `hermes agent status\|start\|stop\|restart\|card` | tenant agent lifecycle |
389
- | `hermes chat list\|create\|get\|messages\|send\|message\|stream\|stop\|approve` | chats and chat messages (`stream` is SSE) |
390
- | `hermes run create\|get\|stream\|stop\|approve` | runs |
391
- | `hermes files ls\|cat\|download` | tenant-visible files |
392
- | `hermes share groups\|ls\|read\|stat\|grep\|find\|write\|mkdir\|move\|rm` | share-group filesystem |
393
- | `hermes skills list\|enable\|disable\|files\|cat` | skills installed on this tenant |
394
- | `hermes flavor current\|catalog\|get\|set\|subscribe\|checkout\|publish\|rollout` | flavor marketplace and this tenant's pin |
395
- | `hermes skill catalog\|get\|checkout\|publish` | skill marketplace |
396
- | `hermes eval suites\|run\|list\|get\|cancel` | flavor eval suites and runs |
397
- | `hermes peers list\|get\|call\|find` | A2A peers |
398
- | `hermes conversations list\|get\|messages` | A2A conversations |
399
- | `hermes sessions list`, `hermes artifacts` | agent sessions and artifacts |
417
+ | `hub key` / `whoami` / `runtime` | reveal credentials, show the tenant, show its runtime |
418
+ | `hub agent status\|start\|stop\|restart\|card` | tenant agent lifecycle |
419
+ | `hub chat list\|create\|get\|messages\|send\|message\|stream\|stop\|approve` | chats and chat messages (`stream` is SSE) |
420
+ | `hub run create\|get\|stream\|stop\|approve` | runs |
421
+ | `hub files ls\|cat\|download` | tenant-visible files |
422
+ | `hub share groups\|ls\|read\|stat\|grep\|find\|write\|mkdir\|move\|rm` | share-group filesystem |
423
+ | `hub skills list\|enable\|disable\|files\|cat` | skills installed on this tenant |
424
+ | `hub flavor current\|catalog\|get\|set\|subscribe\|checkout\|publish\|rollout` | flavor marketplace and this tenant's pin |
425
+ | `hub skill catalog\|get\|checkout\|publish` | skill marketplace |
426
+ | `hub eval suites\|run\|list\|get\|cancel` | flavor eval suites and runs |
427
+ | `hub peers list\|get\|call\|find` | A2A peers |
428
+ | `hub conversations list\|get\|messages` | A2A conversations |
429
+ | `hub sessions list`, `hub artifacts` | agent sessions and artifacts |
400
430
 
401
431
  ```bash
402
- workcord hermes whoami --room-agent $RA
403
- workcord hermes whoami --marketplace-install $MARKETPLACE_INSTALL
404
- workcord hermes chat send --room-agent $RA --chat $CHAT --text "status?"
405
- workcord hermes flavor current --agent $AGENT
406
- workcord hermes peers find --agent $AGENT --query "translation" --limit 5
432
+ workcord hub whoami --room-agent $RA
433
+ workcord hub whoami --marketplace-install $MARKETPLACE_INSTALL
434
+ workcord hub chat send --room-agent $RA --chat $CHAT --text "status?"
435
+ workcord hub flavor current --agent $AGENT
436
+ workcord hub peers find --agent $AGENT --query "translation" --limit 5
407
437
  ```
408
438
 
409
439
  Version flags are named `--flavor-version` and `--skill-version`, not
@@ -413,7 +443,7 @@ anywhere in argv, prints the CLI version and exits before the subcommand runs.
413
443
  ### Direct flavor and skill recovery
414
444
 
415
445
  For normal work, ask the Assistant or another owned agent to create, update,
416
- validate, or activate its own flavor and skills. Hermes Hub supports
446
+ validate, or activate its own flavor and skills. Autoworker Hub supports
417
447
  tenant-owned skill and flavor namespaces; ownership defaults to whichever agent
418
448
  tenant performs the creation.
419
449
 
@@ -424,9 +454,9 @@ the selected tenant and can only mutate namespaces that tenant owns.
424
454
  The CLI does **not** pack or untar archives. The authoring loop is:
425
455
 
426
456
  ```bash
427
- workcord hermes flavor checkout --agent $AGENT --flavor-version 1.4.0 --out flavor.tgz
428
- # unpack, edit, and repack with hermes-hub's own tooling
429
- workcord hermes flavor publish --agent $AGENT --archive flavor.tgz
457
+ workcord hub flavor checkout --agent $AGENT --flavor-version 1.4.0 --out flavor.tgz
458
+ # unpack, edit, and repack with the Hub's own tooling
459
+ workcord hub flavor publish --agent $AGENT --archive flavor.tgz
430
460
  ```
431
461
 
432
462
  `--archive` must already be a gzipped package built beforehand; anything over
@@ -467,10 +497,10 @@ without running `regen` if you don't need the latest server changes.
467
497
  src/
468
498
  ├── cli.ts commander entry, global --as flag
469
499
  ├── auth.ts auth resolution: WORKCORD_TOKEN vs minted --as JWT,
470
- │ plus Hermes Hub key resolution
500
+ │ plus Autoworker Hub key resolution
471
501
  ├── http.ts shared fetch primitives (retry, errors, query)
472
502
  ├── client.ts WorkCord fetch wrapper (JSON + multipart)
473
- ├── hermes-client.ts Hermes Hub fetch wrapper (JSON, upload, SSE, binary)
503
+ ├── hermes-client.ts Autoworker Hub fetch wrapper (JSON, upload, SSE, binary)
474
504
  ├── hermes-guards.ts rollout/ownership/archive guards, version compare
475
505
  ├── commands/ hand-written semantic commands
476
506
  └── generated/ auto-generated from openapi.json
package/dist/auth.js CHANGED
@@ -28,7 +28,22 @@ export function resolveAuth(asUserId, env = process.env, config = {}) {
28
28
  }
29
29
  throw new Error("No credentials. Run `workcord auth login --email <address> --save`, or set WORKCORD_TOKEN. For privileged impersonation, set WORKCORD_JWT_SECRET and pass --as <userId>.");
30
30
  }
31
- async function revealHermesKey(agentRef, asUserId) {
31
+ export function resolveMachineCredential(env = process.env, file) {
32
+ const envKey = env.WORKCORD_MACHINE_KEY?.trim();
33
+ if (envKey)
34
+ return { key: envKey, machineId: undefined, baseUrl: file?.baseUrl || undefined, source: "env" };
35
+ if (file?.key)
36
+ return { key: file.key, machineId: file.machineId, baseUrl: file.baseUrl || undefined, source: "file" };
37
+ throw new Error("No machine key. Run `workcord machine pair` (or `workcord machine enroll`) first, or set WORKCORD_MACHINE_KEY.");
38
+ }
39
+ function envFlag(value) {
40
+ const v = value?.trim().toLowerCase();
41
+ return v === "1" || v === "true" || v === "yes";
42
+ }
43
+ export function isManagedHubMode(env = process.env) {
44
+ return envFlag(env.WORKCORD_HERMES_MANAGED) || envFlag(env.WORKCORD_HUB_MANAGED);
45
+ }
46
+ export async function revealHermesKey(agentRef, asUserId) {
32
47
  const { call } = await import("./client.js");
33
48
  const res = (await call({
34
49
  method: "POST",
@@ -36,25 +51,34 @@ async function revealHermesKey(agentRef, asUserId) {
36
51
  asUserId,
37
52
  }));
38
53
  if (!res?.key) {
39
- throw new Error(`Reveal for ${agentRef} returned no Hermes key`);
54
+ throw new Error(`Reveal for ${agentRef} returned no hub tenant key`);
40
55
  }
41
56
  if (!res.hubBaseUrl) {
42
- throw new Error(`Reveal for ${agentRef} returned no hubBaseUrl. Set WORKCORD_HERMES_HUB_URL (with WORKCORD_HERMES_KEY) to target the hub explicitly.`);
57
+ throw new Error(`Reveal for ${agentRef} returned no hubBaseUrl. Set WORKCORD_HUB_URL (with WORKCORD_HUB_KEY) to target the hub explicitly.`);
43
58
  }
44
59
  return { key: res.key, tenantId: res.tenantId ?? "", hubBaseUrl: res.hubBaseUrl };
45
60
  }
46
61
  export async function resolveHermesKey(agentRef, opts = {}) {
47
62
  const env = opts.env ?? process.env;
48
- const envKey = env.WORKCORD_HERMES_KEY?.trim() || undefined;
49
- const envHub = env.WORKCORD_HERMES_HUB_URL?.trim() || undefined;
63
+ const managed = opts.managed ?? isManagedHubMode(env);
64
+ if (managed) {
65
+ if (opts.asUserId) {
66
+ throw new Error("--as is not allowed in managed hub mode (WORKCORD_HUB_MANAGED): the hub key is always revealed for the token's own user.");
67
+ }
68
+ const revealed = await (opts.reveal ?? revealHermesKey)(agentRef);
69
+ return { ...revealed, source: "reveal" };
70
+ }
71
+ const envKey = env.WORKCORD_HERMES_KEY?.trim() || env.WORKCORD_HUB_KEY?.trim() || undefined;
72
+ const envHub = env.WORKCORD_HERMES_HUB_URL?.trim() || env.WORKCORD_HUB_URL?.trim() || undefined;
73
+ const envTenant = env.WORKCORD_HERMES_TENANT_ID?.trim() || env.WORKCORD_HUB_TENANT_ID?.trim() || "";
50
74
  if (envKey) {
51
75
  if (!envHub) {
52
- throw new Error("WORKCORD_HERMES_KEY is set but WORKCORD_HERMES_HUB_URL is not. Set both, or unset the key to reveal it from WorkCord.");
76
+ throw new Error("WORKCORD_HUB_KEY (WORKCORD_HERMES_KEY) is set but WORKCORD_HUB_URL (WORKCORD_HERMES_HUB_URL) is not. Set both, or unset the key to reveal it from WorkCord.");
53
77
  }
54
- return { key: envKey, tenantId: env.WORKCORD_HERMES_TENANT_ID?.trim() || "", hubBaseUrl: envHub, source: "env" };
78
+ return { key: envKey, tenantId: envTenant, hubBaseUrl: envHub, source: "env" };
55
79
  }
56
80
  if (envHub && !envKey) {
57
- throw new Error("WORKCORD_HERMES_HUB_URL is set but WORKCORD_HERMES_KEY is not. Set both, or unset the hub URL to reveal both from WorkCord.");
81
+ throw new Error("WORKCORD_HUB_URL (WORKCORD_HERMES_HUB_URL) is set but WORKCORD_HUB_KEY (WORKCORD_HERMES_KEY) is not. Set both, or unset the hub URL to reveal both from WorkCord.");
58
82
  }
59
83
  const useCache = opts.cache !== false;
60
84
  const config = opts.config ?? (await readConfig());
package/dist/cli.js CHANGED
@@ -12,17 +12,18 @@ import { registerRoomAgents } from "./commands/room-agents.js";
12
12
  import { registerCustomAgents } from "./commands/custom-agents.js";
13
13
  import { registerChallenges } from "./commands/challenges.js";
14
14
  import { registerHealth } from "./commands/health.js";
15
- import { registerHermes } from "./commands/hermes.js";
15
+ import { registerHub } from "./commands/hub.js";
16
16
  import { registerAgent } from "./commands/agent.js";
17
17
  import { registerAgentSkills } from "./commands/agent-skills.js";
18
18
  import { registerReflections } from "./commands/reflections.js";
19
+ import { registerMachine } from "./commands/machine.js";
19
20
  import { registerAll as registerGenerated } from "./generated/index.js";
20
21
  const program = new Command();
21
22
  const require = createRequire(import.meta.url);
22
23
  const { version } = require("../package.json");
23
24
  program
24
25
  .name("workcord")
25
- .description("Talk to WorkCord agents through Hermes tenant chat, with advanced API diagnostics.")
26
+ .description("Talk to WorkCord agents through Autoworker Hub tenant chat, with advanced API diagnostics.")
26
27
  .version(version)
27
28
  .option("--as <userId>", "user to act as")
28
29
  .option("--base-url <url>", "API base URL (overrides WORKCORD_API_URL and saved configuration)");
@@ -42,7 +43,8 @@ registerAgentSkills(program);
42
43
  registerReflections(program);
43
44
  registerChallenges(program); // adds regenerate-cards (not in the OpenAPI spec)
44
45
  registerHealth(program);
45
- registerHermes(program);
46
+ registerHub(program);
47
+ registerMachine(program);
46
48
  registerGenerated(program);
47
49
  program.parseAsync().catch((err) => {
48
50
  const out = { error: err.message ?? String(err) };