@oh-hai/cli 0.1.0-beta.0 → 0.2.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.
Files changed (83) hide show
  1. package/README.md +51 -8
  2. package/dist/auth/resolve-token.d.ts +2 -4
  3. package/dist/auth/resolve-token.js +4 -11
  4. package/dist/auth/resolve-token.js.map +1 -1
  5. package/dist/bindings.d.ts +65 -0
  6. package/dist/bindings.js +242 -0
  7. package/dist/bindings.js.map +1 -0
  8. package/dist/cli.js +211 -12
  9. package/dist/cli.js.map +1 -1
  10. package/dist/commands/ask.js +21 -17
  11. package/dist/commands/ask.js.map +1 -1
  12. package/dist/commands/binary-update.d.ts +61 -0
  13. package/dist/commands/binary-update.js +160 -0
  14. package/dist/commands/binary-update.js.map +1 -0
  15. package/dist/commands/context.d.ts +135 -0
  16. package/dist/commands/doctor.js +30 -3
  17. package/dist/commands/doctor.js.map +1 -1
  18. package/dist/commands/flags.d.ts +14 -2
  19. package/dist/commands/flags.js +34 -6
  20. package/dist/commands/flags.js.map +1 -1
  21. package/dist/commands/handlers.js +8 -0
  22. package/dist/commands/handlers.js.map +1 -1
  23. package/dist/commands/inbox.js +129 -33
  24. package/dist/commands/inbox.js.map +1 -1
  25. package/dist/commands/login.d.ts +13 -0
  26. package/dist/commands/login.js +35 -27
  27. package/dist/commands/login.js.map +1 -1
  28. package/dist/commands/messaging/identity.d.ts +9 -0
  29. package/dist/commands/messaging/identity.js +21 -0
  30. package/dist/commands/messaging/identity.js.map +1 -1
  31. package/dist/commands/messaging/validate.d.ts +6 -5
  32. package/dist/commands/messaging/validate.js +7 -16
  33. package/dist/commands/messaging/validate.js.map +1 -1
  34. package/dist/commands/registry.js +88 -8
  35. package/dist/commands/registry.js.map +1 -1
  36. package/dist/commands/setup.d.ts +26 -0
  37. package/dist/commands/setup.js +221 -0
  38. package/dist/commands/setup.js.map +1 -0
  39. package/dist/commands/task.js +21 -24
  40. package/dist/commands/task.js.map +1 -1
  41. package/dist/commands/teach.d.ts +13 -0
  42. package/dist/commands/teach.js +317 -0
  43. package/dist/commands/teach.js.map +1 -0
  44. package/dist/commands/update-check.d.ts +49 -0
  45. package/dist/commands/update-check.js +203 -0
  46. package/dist/commands/update-check.js.map +1 -0
  47. package/dist/commands/upgrade.d.ts +2 -0
  48. package/dist/commands/upgrade.js +178 -0
  49. package/dist/commands/upgrade.js.map +1 -0
  50. package/dist/commands/use.d.ts +2 -0
  51. package/dist/commands/use.js +99 -0
  52. package/dist/commands/use.js.map +1 -0
  53. package/dist/commands/whoami.js +113 -27
  54. package/dist/commands/whoami.js.map +1 -1
  55. package/dist/config-file.js +4 -20
  56. package/dist/config-file.js.map +1 -1
  57. package/dist/config.d.ts +15 -1
  58. package/dist/config.js +43 -4
  59. package/dist/config.js.map +1 -1
  60. package/dist/exit-codes.d.ts +6 -0
  61. package/dist/exit-codes.js +6 -0
  62. package/dist/exit-codes.js.map +1 -1
  63. package/dist/help.js +5 -1
  64. package/dist/help.js.map +1 -1
  65. package/dist/onboarding/open-url.d.ts +26 -0
  66. package/dist/onboarding/open-url.js +69 -0
  67. package/dist/onboarding/open-url.js.map +1 -0
  68. package/dist/onboarding/status.d.ts +24 -0
  69. package/dist/onboarding/status.js +53 -0
  70. package/dist/onboarding/status.js.map +1 -0
  71. package/dist/os.d.ts +16 -0
  72. package/dist/os.js +32 -0
  73. package/dist/os.js.map +1 -0
  74. package/dist/url.d.ts +8 -0
  75. package/dist/url.js +29 -0
  76. package/dist/url.js.map +1 -0
  77. package/dist/version.d.ts +11 -3
  78. package/dist/version.js +20 -3
  79. package/dist/version.js.map +1 -1
  80. package/dist/watch-lock.d.ts +85 -0
  81. package/dist/watch-lock.js +358 -0
  82. package/dist/watch-lock.js.map +1 -0
  83. package/package.json +2 -2
@@ -0,0 +1,178 @@
1
+ // `oh-hai upgrade` (docs/specs/cli.md §4 — self-update, #343, the "replaces brew upgrade" piece
2
+ // of #277). Checks the npm registry for a newer `@oh-hai/cli`, then acts by install method:
3
+ // • npm-global → run `npm i -g @oh-hai/cli@latest` (interactive human only; otherwise print it)
4
+ // • binary → guidance to re-run the installer (in-place binary re-pull lands with #344/#345)
5
+ // • dev/unknown → honest guidance (pull+rebuild, or a generic update hint)
6
+ // No fabricated success: a method that can't self-update yet PRINTS what to do, it never claims to
7
+ // have upgraded. `--check` reports availability without acting. `--json` emits the uniform envelope
8
+ // and never spawns a subprocess (machine mode must not mutate a global install).
9
+ import { CliError, buildOk, serializeEnvelope } from "../envelope.js";
10
+ import { sanitizeForTerminal } from "../terminal.js";
11
+ import { cliVersion } from "../version.js";
12
+ import { performBinaryUpdate } from "./binary-update.js";
13
+ import { flagOnStrict, parseCommandArgs } from "./flags.js";
14
+ import { PACKAGE_NAME, checkForUpdate, classifyInstall } from "./update-check.js";
15
+ /** The headline installer (the binary `curl | sh` path, #345). */
16
+ const INSTALL_SCRIPT = "curl -fsSL https://ohhai.app/install | sh";
17
+ /** The npm self-upgrade command (the live secondary channel for node users, #270). */
18
+ const NPM_UPGRADE_CMD = `npm i -g ${PACKAGE_NAME}@latest`;
19
+ /** Emit a success outcome: the uniform --json envelope, else the human line. Registry-supplied
20
+ * strings (`latest`, and any value woven into `line`) are terminal-sanitized on BOTH paths —
21
+ * JSON.stringify does not escape C1/DEL (see doctor.ts), so --json is sanitized too (§5.4). */
22
+ function emit(ctx, outcome) {
23
+ if (ctx.json) {
24
+ ctx.io.log(serializeEnvelope(buildOk("upgrade", {
25
+ current: sanitizeForTerminal(outcome.current),
26
+ latest: sanitizeForTerminal(outcome.latest),
27
+ update_available: outcome.updateAvailable,
28
+ method: outcome.method,
29
+ action: outcome.action,
30
+ })));
31
+ return;
32
+ }
33
+ ctx.io.log(sanitizeForTerminal(outcome.line));
34
+ }
35
+ /** The `binary` case of `upgrade` (#358): a `bun --compile` standalone can't `npm i -g` itself, so it
36
+ * downloads the matching release asset, verifies its SHA-256 against the release `SHA256SUMS`, and
37
+ * atomically swaps itself in place (mirroring packaging/install.sh). It self-updates ONLY when the
38
+ * download/swap seam is wired AND it's a real interactive terminal (TTY stdin + TTY stdout) — the
39
+ * SAME gate the npm-global branch uses: silently replacing the running binary under `--json`, a pipe
40
+ * (`oh-hai upgrade | tee log`), or CI is as unsafe as a silent global npm mutation (#349's
41
+ * principle). Anything else prints installer guidance without touching disk. Every
42
+ * download/checksum/execute/install failure surfaces a clear CliError — never a fabricated success,
43
+ * never an unverified binary written to disk. */
44
+ async function binaryUpgrade(ctx, base, current, latest) {
45
+ // A real terminal session: a human at the TTY (stdin) AND a TTY stdout (not `| tee log`). Absent
46
+ // isStdoutTty (hermetic callers) is treated as a TTY; production wires process.stdout.isTTY.
47
+ const interactive = (ctx.runtime.isInteractive?.() ?? false) && (ctx.runtime.isStdoutTty?.() ?? true);
48
+ // Machine mode (--json), an unwired caller, or a non-interactive/piped session → guidance, no swap.
49
+ if (ctx.json || ctx.runtime.binaryUpdateIo === undefined || !interactive) {
50
+ emit(ctx, {
51
+ ...base,
52
+ updateAvailable: true,
53
+ action: "binary-guidance",
54
+ line: `update available: v${current} → v${latest}. Re-run the installer: ${INSTALL_SCRIPT}`,
55
+ });
56
+ return;
57
+ }
58
+ ctx.io.log(sanitizeForTerminal(`Downloading ${PACKAGE_NAME} v${latest} …`));
59
+ const result = await performBinaryUpdate(ctx.runtime.binaryUpdateIo, ctx.runtime.fetchImpl, latest, ctx.config.timeoutMs);
60
+ switch (result.status) {
61
+ case "updated":
62
+ emit(ctx, { ...base, updateAvailable: true, action: "binary-updated", line: `upgraded to v${latest}. Restart oh-hai to use the new version.` });
63
+ return;
64
+ case "unsupported":
65
+ // No prebuilt binary for this host (e.g. windows-arm64) — honest guidance, not a 404 crash.
66
+ emit(ctx, {
67
+ ...base,
68
+ updateAvailable: true,
69
+ action: "binary-guidance",
70
+ line: `update available: v${current} → v${latest}. No prebuilt binary for ${result.platform}-${result.arch}; install via \`${NPM_UPGRADE_CMD}\`.`,
71
+ });
72
+ return;
73
+ case "release-pending":
74
+ // npm has v${latest} but its binary release is still building (the npm publish and the binary
75
+ // matrix fire on the same tag; the matrix is slower). Not an error in the code — just early.
76
+ throw new CliError("error", sanitizeForTerminal(`the v${latest} binary release is still publishing — try again in a few minutes, or re-run the installer: ${INSTALL_SCRIPT}`));
77
+ case "checksum-mismatch":
78
+ // A tamper/corruption signal — hard-stop loudly rather than installing unverified bytes.
79
+ throw new CliError("error", sanitizeForTerminal(`checksum verification FAILED for the v${latest} binary — refusing to install (corrupted download or tampering). Re-run to retry.`));
80
+ case "unverified-binary":
81
+ throw new CliError("error", sanitizeForTerminal(`the downloaded v${latest} binary did not run on this host — keeping the current install. Re-run the installer: ${INSTALL_SCRIPT}`));
82
+ case "download-failed":
83
+ throw new CliError(result.network ? "network" : "error", sanitizeForTerminal(`could not download the v${latest} binary — ${result.detail}. Re-run the installer: ${INSTALL_SCRIPT}`));
84
+ case "install-failed":
85
+ throw new CliError("error", sanitizeForTerminal(`could not install the v${latest} binary — ${result.detail}.`));
86
+ default: {
87
+ // Exhaustive: BinaryUpdateResult is a closed union — a new status must add a case above.
88
+ const unreachable = result;
89
+ throw new CliError("error", `unhandled binary-update result: ${String(unreachable)}`);
90
+ }
91
+ }
92
+ }
93
+ export async function upgradeCommand(ctx) {
94
+ const { values } = parseCommandArgs(ctx.argv, { check: { type: "boolean" } });
95
+ // Strict parse: `--check` is the no-mutation safety mode, so a typo'd value (`--check=treu`) must
96
+ // fail loudly rather than silently fall through to the live `npm i -g` (#349 review).
97
+ const checkOnly = flagOnStrict(values.check, "check");
98
+ const current = cliVersion();
99
+ const method = ctx.runtime.installFacts !== undefined ? classifyInstall(ctx.runtime.installFacts) : "unknown";
100
+ const result = await checkForUpdate(current, ctx.runtime.fetchImpl, ctx.config.timeoutMs);
101
+ // Registry unreachable / unparseable → a clear NETWORK exit (the user asked explicitly, so a
102
+ // failed check is an error here, unlike doctor's advisory check which just omits the line). Throw
103
+ // a CliError like every other command; cli.ts translates it once into the exit code + --json
104
+ // envelope. The message is sanitized here (cli.ts renders CliError messages raw).
105
+ if (result.error !== undefined) {
106
+ throw new CliError("network", sanitizeForTerminal(`could not check for updates — ${result.error}`));
107
+ }
108
+ const latest = result.latest ?? current;
109
+ const base = { current, latest, method };
110
+ if (!result.updateAvailable) {
111
+ emit(ctx, { ...base, updateAvailable: false, action: "up-to-date", line: `already on the latest version (v${current}).` });
112
+ return;
113
+ }
114
+ // An update exists. `--check` only reports it.
115
+ if (checkOnly) {
116
+ emit(ctx, {
117
+ ...base,
118
+ updateAvailable: true,
119
+ action: "check",
120
+ line: `update available: v${current} → v${latest} — run \`oh-hai upgrade\`.`,
121
+ });
122
+ return;
123
+ }
124
+ switch (method) {
125
+ case "npm-global": {
126
+ // A real terminal session needs BOTH a TTY stdin (a human to react) AND a TTY stdout — a piped
127
+ // stdout (`oh-hai upgrade | tee log`) has a TTY stdin but must still PRINT the command, per the
128
+ // documented pipe/machine-safety behavior (#349 review). Absent isStdoutTty (hermetic callers)
129
+ // is treated as a TTY; production wires process.stdout.isTTY.
130
+ const interactive = (ctx.runtime.isInteractive?.() ?? false) && (ctx.runtime.isStdoutTty?.() ?? true);
131
+ // Machine mode / non-interactive / piped / no runner → PRINT the command; never silently mutate
132
+ // a global install in a pipe, in CI, or under --json.
133
+ if (ctx.json || !interactive || ctx.runtime.runCommand === undefined) {
134
+ emit(ctx, {
135
+ ...base,
136
+ updateAvailable: true,
137
+ action: "print-command",
138
+ line: `update available: v${current} → v${latest}. Run: ${NPM_UPGRADE_CMD}`,
139
+ });
140
+ return;
141
+ }
142
+ ctx.io.log(sanitizeForTerminal(`Upgrading ${PACKAGE_NAME}: v${current} → v${latest} …`));
143
+ const proc = await ctx.runtime.runCommand("npm", ["i", "-g", `${PACKAGE_NAME}@latest`]);
144
+ if (proc.spawnError !== undefined || (proc.code ?? 1) !== 0) {
145
+ const detail = proc.spawnError ?? (proc.stderr.trim() !== "" ? proc.stderr.trim() : `npm exited ${proc.code}`);
146
+ throw new CliError("error", sanitizeForTerminal(`npm upgrade failed — ${detail}`));
147
+ }
148
+ emit(ctx, { ...base, updateAvailable: true, action: "npm-upgrade", line: `upgraded to v${latest}.` });
149
+ return;
150
+ }
151
+ case "binary":
152
+ await binaryUpgrade(ctx, base, current, latest);
153
+ return;
154
+ case "dev":
155
+ emit(ctx, {
156
+ ...base,
157
+ updateAvailable: true,
158
+ action: "dev-guidance",
159
+ line: `update available: v${current} → v${latest}. You're on a source checkout — pull latest and rebuild.`,
160
+ });
161
+ return;
162
+ case "unknown":
163
+ emit(ctx, {
164
+ ...base,
165
+ updateAvailable: true,
166
+ action: "unknown-guidance",
167
+ line: `update available: v${current} → v${latest}. Update via \`${NPM_UPGRADE_CMD}\`, or re-run the installer: ${INSTALL_SCRIPT}`,
168
+ });
169
+ return;
170
+ default: {
171
+ // Exhaustive: InstallMethod is a closed union — a new value must add a case above rather than
172
+ // silently fall into generic guidance.
173
+ const unreachable = method;
174
+ throw new CliError("error", `unhandled install method: ${String(unreachable)}`);
175
+ }
176
+ }
177
+ }
178
+ //# sourceMappingURL=upgrade.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"upgrade.js","sourceRoot":"","sources":["../../src/commands/upgrade.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import type { CommandContext } from "./context.js";
2
+ export declare function useCommand(ctx: CommandContext): Promise<void>;
@@ -0,0 +1,99 @@
1
+ // `oh-hai use` (docs/specs/cli.md §4, #321 — part of #307). Bind the current directory to an agent so
2
+ // sessions in that tree act as it with no `--account` juggling. Fully offline and side-effect-local:
3
+ // it only reads/writes the USER-side bindings store (`~/.config/oh-hai/bindings.json`), never a repo
4
+ // and never the network — so a binding can't be planted by a hostile checkout (credential-safety §6).
5
+ //
6
+ // oh-hai use <agent> bind cwd → <agent> for the resolved Hub origin
7
+ // oh-hai use --list list all bindings
8
+ // oh-hai use --unset remove cwd's binding for the resolved Hub origin
9
+ //
10
+ // Binding is offline and does NOT require the agent to have a stored token yet — you may `use` an
11
+ // agent then `login` as it (like `logout`, no Hub call). Resolution + the normal token lookup handle
12
+ // a not-yet-authenticated agent downstream (`whoami` then shows `token: absent`).
13
+ import { isAbsolute } from "node:path";
14
+ import { CliError, buildOk, serializeEnvelope } from "../envelope.js";
15
+ import { originOf } from "../auth/resolve-token.js";
16
+ import { bindingStoreStatus, loadBindings, setBinding, unsetBinding } from "../bindings.js";
17
+ import { sanitizeForTerminal } from "../terminal.js";
18
+ import { flagOn, parseCommandArgs } from "./flags.js";
19
+ export async function useCommand(ctx) {
20
+ // `use` takes one optional operand (the agent id) plus --list / --unset booleans.
21
+ const { values, positionals } = parseCommandArgs(ctx.argv, { list: { type: "boolean" }, unset: { type: "boolean" } }, { maxOperands: 1 });
22
+ // A blank / whitespace-only operand (`use ""`, `use " "`) is treated as ABSENT — otherwise it would
23
+ // report a successful bind while writing a dead record `asBinding` drops on read. Trim so a stray-space
24
+ // agent id is stored clean, matching the account-resolution presence semantics (config.ts).
25
+ const rawAgent = positionals[1];
26
+ const agent = rawAgent !== undefined && rawAgent.trim() !== "" ? rawAgent.trim() : undefined;
27
+ const list = flagOn(values.list);
28
+ const unset = flagOn(values.unset);
29
+ // Exactly one mode: bind (an agent operand), --list, or --unset.
30
+ const modes = (agent !== undefined ? 1 : 0) + (list ? 1 : 0) + (unset ? 1 : 0);
31
+ if (modes > 1) {
32
+ throw new CliError("usage", "choose one: `use <agent>`, `use --list`, or `use --unset`.");
33
+ }
34
+ if (modes === 0) {
35
+ throw new CliError("usage", "expected an <agent> id, or --list / --unset. Run 'oh-hai use --help'.");
36
+ }
37
+ const io = ctx.runtime.bindingsIo;
38
+ if (io === undefined) {
39
+ // Defensive: production always wires nodeBindingsIo(); this only fires if a caller omits it.
40
+ throw new CliError("error", "internal: the bindings store is unavailable.");
41
+ }
42
+ const origin = originOf(ctx.config.baseUrl);
43
+ const cwd = io.cwd;
44
+ if (list) {
45
+ const bindings = loadBindings(io);
46
+ if (ctx.json) {
47
+ ctx.io.log(serializeEnvelope(buildOk("use", { bindings })));
48
+ }
49
+ else if (bindings.length === 0) {
50
+ ctx.io.log("No directory bindings.");
51
+ }
52
+ else {
53
+ for (const b of bindings) {
54
+ // Every field here comes from the bindings FILE, so sanitize each before echoing — a hand-edited
55
+ // record could carry control chars in origin just as in path/account.
56
+ ctx.io.log(`${sanitizeForTerminal(b.path)} → ${sanitizeForTerminal(b.account)} (${sanitizeForTerminal(b.origin)})`);
57
+ }
58
+ }
59
+ return;
60
+ }
61
+ // Write-path preflight (bind + unset): fail LOUDLY rather than report a success that didn't persist.
62
+ // - a non-absolute cwd (production records "" when `process.cwd()` failed; a relative cwd would write
63
+ // a binding `resolveBinding` then ignores) has nothing meaningful to bind;
64
+ // - an "unavailable" store (no trusted config dir) would silently no-op the write;
65
+ // - an "unsupported-version" file was written by a newer CLI — overwriting it would erase its bindings.
66
+ if (!isAbsolute(cwd)) {
67
+ throw new CliError("error", "cannot bind: no absolute working directory (is the current directory gone?).");
68
+ }
69
+ const status = bindingStoreStatus(io);
70
+ if (status === "unavailable") {
71
+ throw new CliError("error", "cannot persist a binding: no writable user config directory (set $HOME or $XDG_CONFIG_HOME).");
72
+ }
73
+ if (status === "unsupported-version") {
74
+ throw new CliError("error", "refusing to modify a bindings.json written by a newer oh-hai — upgrade the CLI to change bindings.");
75
+ }
76
+ if (unset) {
77
+ const removed = unsetBinding(io, cwd, origin);
78
+ if (ctx.json) {
79
+ ctx.io.log(serializeEnvelope(buildOk("use", { path: cwd, origin, removed })));
80
+ }
81
+ else {
82
+ ctx.io.log(removed
83
+ ? `Unbound ${sanitizeForTerminal(cwd)} (${sanitizeForTerminal(origin)}).`
84
+ : `No binding for ${sanitizeForTerminal(cwd)} (${sanitizeForTerminal(origin)}).`);
85
+ }
86
+ return;
87
+ }
88
+ // Bind mode: reaching here, `agent` is defined (modes === 1 with --list/--unset both false), but the
89
+ // mode-count arithmetic doesn't narrow it for the type checker — assert the definedness we proved.
90
+ const agentId = agent;
91
+ const path = setBinding(io, cwd, origin, agentId);
92
+ if (ctx.json) {
93
+ ctx.io.log(serializeEnvelope(buildOk("use", { path, account: agentId, origin })));
94
+ }
95
+ else {
96
+ ctx.io.log(`Bound ${sanitizeForTerminal(path)} → ${sanitizeForTerminal(agentId)} (${sanitizeForTerminal(origin)}).`);
97
+ }
98
+ }
99
+ //# sourceMappingURL=use.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use.js","sourceRoot":"","sources":["../../src/commands/use.ts"],"names":[],"mappings":"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"}
@@ -2,6 +2,10 @@
2
2
  // secret (§5.4): agent id, base URL, token presence + a redacted fingerprint, and where the
3
3
  // token resolved from (`keychain` / `file` / `env`). Works fully offline. `--check` adds a
4
4
  // network probe of the Hub for token validity: exit 0 valid, 3 on 401/403, 5 unreachable (§9).
5
+ // The probe hits GET /auth/whoami, so a valid token ALSO yields the caller's Hub-attested actor. A
6
+ // `human:<id>` actor is printed as `resolver:` — the exact address an agent uses to route an ask/task
7
+ // to that human (issue #362); an agent-authed CLI validates but has no human resolver to show. An
8
+ // older Hub without that endpoint still validates via a legacy fallback probe (resolver omitted).
5
9
  import { createHash } from "node:crypto";
6
10
  import { CliError, buildOk, serializeEnvelope } from "../envelope.js";
7
11
  import { resolveIdentity } from "../auth/resolve-token.js";
@@ -18,43 +22,89 @@ export function fingerprintToken(token) {
18
22
  * set. §9 promises offline is an explicit state, never a silent hang — a Hub that accepts the
19
23
  * connection but never responds must still surface a timeout rather than block forever. */
20
24
  const DEFAULT_CHECK_TIMEOUT_MS = 10_000;
21
- /** Probe the Hub for token validity using an endpoint that exists post-#96: an authenticated
22
- * GET of a nonexistent message id. Because the Hub authenticates BEFORE looking the id up, the
23
- * ONLY response that proves the presented bearer authenticated is the expected `404` (agent
24
- * authenticated, message not found). `401`/`403` = invalid/revoked; `5xx` = the Hub errored (no
25
- * validity signal); a transport failure = unreachable/timeout. Any other status (a `2xx`/`3xx`
26
- * from a proxy that ignores `Authorization`, a wrong `--base-url`) is NOT proof of validity and
27
- * is reported as such rather than a false "valid". Side-effect-free — a GET creates nothing. */
28
- async function checkToken(ctx, token) {
29
- if (token === undefined) {
30
- throw new CliError("auth", "not authenticated — no stored token to check (run `oh-hai login`).");
31
- }
32
- const url = `${ctx.config.baseUrl}/v1/messages/oh-hai-whoami-check-nonexistent`;
25
+ /** Side-effect-free authenticated GET, with the transport-error §7 exit-code mapping shared by both
26
+ * probes (a timeout is exit 7, any other connection failure exit 5). */
27
+ async function probeGet(ctx, path, token) {
33
28
  const init = {
34
29
  method: "GET",
35
30
  headers: { Authorization: `Bearer ${token}` },
36
31
  signal: AbortSignal.timeout(ctx.config.timeoutMs ?? DEFAULT_CHECK_TIMEOUT_MS),
37
32
  };
38
- let status;
33
+ // A per-request timeout is exit 7 (§7); a DNS/connection failure is exit 5 (§9). throwTransportError
34
+ // returns `never`, so the rejected-path handler doesn't widen the resolved type.
35
+ return ctx.runtime
36
+ .fetchImpl(`${ctx.config.baseUrl}${path}`, init)
37
+ .catch((error) => throwTransportError(error, ctx.config.baseUrl));
38
+ }
39
+ /** Parse a response body as a JSON object, defensively — a status-only fake, a non-JSON body, or a
40
+ * non-object all collapse to `{}` (mirrors agents.ts readJson). */
41
+ async function readJsonBody(res) {
42
+ if (typeof res.json !== "function")
43
+ return {};
39
44
  try {
40
- status = (await ctx.runtime.fetchImpl(url, init)).status;
45
+ const parsed = await res.json();
46
+ return parsed !== null && typeof parsed === "object" && !Array.isArray(parsed)
47
+ ? parsed
48
+ : {};
41
49
  }
42
- catch (error) {
43
- // A per-request timeout is exit 7 (§7); a DNS/connection failure is exit 5 (§9).
44
- throwTransportError(error, ctx.config.baseUrl);
50
+ catch {
51
+ return {};
45
52
  }
53
+ }
54
+ /** The `actor` field of a whoami body — required to be a well-formed MA2H actor (`human:<id>` /
55
+ * `agent:<id>`, the endpoint's only shapes). A proxy `200` returning arbitrary JSON (e.g.
56
+ * `{actor:"ok"}`), or a blank/missing value, is NOT mistaken for a valid Hub identity. */
57
+ function readActor(body) {
58
+ const actor = typeof body.actor === "string" ? body.actor.trim() : "";
59
+ return /^(?:human|agent):.+/.test(actor) ? actor : undefined;
60
+ }
61
+ /** Map a "could not confirm validity" status to the §7 error the two probes share — ALWAYS throws
62
+ * (each probe handles its own "authenticated" status before delegating here). */
63
+ function classifyProbeStatus(status) {
46
64
  if (status === 401 || status === 403) {
47
65
  throw new CliError("auth", `token is invalid or revoked (Hub returned ${status}).`);
48
66
  }
49
67
  if (status >= 500) {
50
68
  throw new CliError("server", `Hub returned ${status}; token validity could not be confirmed.`);
51
69
  }
52
- if (status !== 404) {
53
- // Not the expected authenticated-and-not-found response — could be a wrong base URL or a
54
- // proxy that never reached the Hub's auth. Don't claim the token is valid.
55
- throw new CliError("error", `unexpected Hub response ${status}; could not confirm token validity (check --base-url).`);
70
+ throw new CliError("error", `unexpected Hub response ${status}; could not confirm token validity (check --base-url).`);
71
+ }
72
+ /** Legacy validity probe for a Hub that predates GET /auth/whoami: an authenticated GET of a
73
+ * nonexistent message id. The Hub authenticates BEFORE the id lookup, so the expected `404`
74
+ * (authenticated, not found) proves the bearer is valid; every other status is handled uniformly.
75
+ * Yields no resolver id. */
76
+ async function legacyCheckToken(ctx, token) {
77
+ const status = (await probeGet(ctx, "/v1/messages/oh-hai-whoami-check-nonexistent", token)).status;
78
+ if (status === 404)
79
+ return; // authenticated + not found → valid
80
+ classifyProbeStatus(status);
81
+ }
82
+ /** Probe the Hub for token validity via GET /auth/whoami (issue #362). A `200` carrying an `{ actor }`
83
+ * body BOTH proves the presented bearer authenticated AND yields the Hub-attested resolver id (a
84
+ * human's `human:<id>` or an agent's `agent:<id>`), returned for display. `401`/`403` = invalid/revoked
85
+ * (exit 3); `5xx` = the Hub errored, no validity signal (exit 6); a transport failure = unreachable/
86
+ * timeout (exit 5/7). A `404` means the endpoint is absent (an older Hub) — fall back to the legacy
87
+ * probe so `--check` stays valid there (resolver omitted). Any other response — a `2xx`/`3xx` from a
88
+ * proxy that ignored `Authorization`, or a `200` without a real `{ actor }` body — is NOT proof of
89
+ * validity and is reported as such rather than a false "valid". Side-effect-free — a GET creates nothing. */
90
+ async function checkToken(ctx, token) {
91
+ if (token === undefined) {
92
+ throw new CliError("auth", "not authenticated — no stored token to check (run `oh-hai login`).");
93
+ }
94
+ const res = await probeGet(ctx, "/auth/whoami", token);
95
+ if (res.status === 200) {
96
+ const actor = readActor(await readJsonBody(res));
97
+ if (actor !== undefined)
98
+ return actor; // authenticated → the Hub-attested resolver id
99
+ // A 200 without a real actor body isn't the Hub's whoami (likely a proxy ignoring auth).
100
+ throw new CliError("error", "unexpected Hub response (200 without an identity); could not confirm token validity (check --base-url).");
56
101
  }
57
- // 404 the bearer authenticated and the probe id doesn't exist: the token is valid.
102
+ if (res.status === 404) {
103
+ // The endpoint is absent (an older Hub) — confirm validity the legacy way; no resolver id.
104
+ await legacyCheckToken(ctx, token);
105
+ return undefined;
106
+ }
107
+ classifyProbeStatus(res.status);
58
108
  }
59
109
  export async function whoamiCommand(ctx) {
60
110
  const { values } = parseCommandArgs(ctx.argv, { check: { type: "boolean" } });
@@ -65,26 +115,62 @@ export async function whoamiCommand(ctx) {
65
115
  const resolved = await resolveIdentity(ctx.config, store);
66
116
  const account = resolved.account;
67
117
  const fingerprint = resolved.token !== undefined ? fingerprintToken(resolved.token) : undefined;
68
- // A failing --check throws before any identity is printed (the command result IS the check).
69
- if (flagOn(values.check)) {
70
- await checkToken(ctx, resolved.token);
71
- }
118
+ // Where `account` resolved (§6), so `whoami` explains the resolution key once per-project bindings
119
+ // exist (#321). resolveConfig set `accountSource` for the flag/env/binding/user-config layers; when
120
+ // it's "none" (nothing configured) yet an account still resolved, resolveIdentity DISCOVERED the sole
121
+ // stored identity. `binding_path` rides along only for the binding source (pruned otherwise).
122
+ const source = ctx.config.accountSource;
123
+ const accountSource = source === undefined || source === "none"
124
+ ? account !== undefined
125
+ ? "discovered"
126
+ : undefined
127
+ : source;
128
+ const bindingPath = source === "binding" ? ctx.config.bindingPath : undefined;
129
+ // A failing --check throws before any identity is printed (the command result IS the check). On
130
+ // success it returns the caller's Hub-attested actor (undefined against an older Hub without the
131
+ // endpoint). Only a `human:<id>` actor is a resolver an agent can address to reach a human — a
132
+ // CLI authed with an agent bearer (the common device-code flow) resolves as `agent:<id>`, which the
133
+ // submit paths reject, so it must NOT be presented as a `resolver:` the user can hand out (issue #362).
134
+ const actor = flagOn(values.check) ? await checkToken(ctx, resolved.token) : undefined;
135
+ const resolver = actor !== undefined && actor.startsWith("human:") ? actor : undefined;
72
136
  if (ctx.json) {
73
137
  const token = { present: resolved.token !== undefined, source: resolved.source };
74
138
  if (fingerprint !== undefined) {
75
139
  token.fingerprint = fingerprint;
76
140
  }
77
- ctx.io.log(serializeEnvelope(buildOk("whoami", { agent_id: account, base_url: ctx.config.baseUrl, token })));
141
+ ctx.io.log(serializeEnvelope(buildOk("whoami", {
142
+ agent_id: account,
143
+ base_url: ctx.config.baseUrl,
144
+ token,
145
+ account_source: accountSource,
146
+ binding_path: bindingPath,
147
+ resolver,
148
+ })));
78
149
  }
79
150
  else {
80
151
  // Sanitize before terminal output: a DISCOVERED account is the raw agent id the Hub chose at
81
152
  // login time, so a hostile Hub could have stored control characters in it (the raw id is kept
82
153
  // for lookup and the JSON envelope, where JSON.stringify escapes them — §5.4 / login parity).
83
154
  ctx.io.log(`agent: ${account !== undefined ? sanitizeForTerminal(account) : "(none — set --account/--agent or MA2H_AGENT_ID)"}`);
155
+ // Explain HOW the account resolved (flag / env / binding@<path> / user config / discovered).
156
+ if (accountSource !== undefined) {
157
+ const via = accountSource === "binding" && bindingPath !== undefined
158
+ ? `binding (${sanitizeForTerminal(bindingPath)})`
159
+ : accountSource === "user-config"
160
+ ? "user config"
161
+ : accountSource;
162
+ ctx.io.log(`via: ${via}`);
163
+ }
84
164
  ctx.io.log(`base url: ${ctx.config.baseUrl}`);
85
165
  ctx.io.log(resolved.token !== undefined
86
166
  ? `token: present (…${fingerprint}) [${resolved.source}]`
87
167
  : "token: absent");
168
+ // The Hub-attested human resolver id — present only after a successful --check that returned a
169
+ // `human:` actor (an agent-authed CLI has none to hand out). Sanitize: the actor is Hub-supplied,
170
+ // so a hostile Hub could smuggle control chars.
171
+ if (resolver !== undefined) {
172
+ ctx.io.log(`resolver: ${sanitizeForTerminal(resolver)}`);
173
+ }
88
174
  }
89
175
  }
90
176
  //# sourceMappingURL=whoami.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"whoami.js","sourceRoot":"","sources":["../../src/commands/whoami.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"whoami.js","sourceRoot":"","sources":["../../src/commands/whoami.ts"],"names":[],"mappings":"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"}
@@ -15,6 +15,7 @@
15
15
  import { readFileSync, statSync } from "node:fs";
16
16
  import { homedir } from "node:os";
17
17
  import { dirname, isAbsolute, join } from "node:path";
18
+ import { resolveXdgConfigHome, safeOsValue } from "./os.js";
18
19
  /**
19
20
  * Parse the minimal config dialect: flat `key = value` lines plus an optional `[oh-hai]` section.
20
21
  * Values are quoted strings (single/double), integers (optional sign + `_` separators), or booleans.
@@ -143,18 +144,11 @@ function mapProjectConfig(record) {
143
144
  }
144
145
  /** Load `~/.config/oh-hai/config.toml` ($XDG_CONFIG_HOME honored). Undefined when the file is absent. */
145
146
  export function loadUserConfig(io) {
146
- const xdg = io.xdgConfigHome?.trim();
147
- const home = io.homedir.trim();
148
147
  // The user-global config is TRUSTED (it alone may set base_url / default_account), so its directory
149
148
  // must be ABSOLUTE — a relative path would resolve against cwd and let a repo-committed file
150
- // masquerade as user-global config, bypassing per-project rejection. Prefer an absolute
151
- // $XDG_CONFIG_HOME; a relative/blank XDG is ignored in favor of the ~/.config default; if neither
152
- // yields an absolute dir (e.g. a minimal container with an empty homedir), skip the user config.
153
- const configHome = xdg !== undefined && xdg !== "" && isAbsolute(xdg)
154
- ? xdg
155
- : home !== "" && isAbsolute(home)
156
- ? join(home, ".config")
157
- : undefined;
149
+ // masquerade as user-global config, bypassing per-project rejection. `resolveXdgConfigHome` enforces
150
+ // that (shared with the bindings store); undefined no absolute config dir, so skip the user config.
151
+ const configHome = resolveXdgConfigHome(io);
158
152
  if (configHome === undefined) {
159
153
  return undefined;
160
154
  }
@@ -195,16 +189,6 @@ export function loadConfigFiles(io) {
195
189
  /** Generous ceiling on a config file's size — real configs are a few keys; anything larger is either
196
190
  * a mistake or a hostile plant, so it's skipped rather than read into memory. */
197
191
  const MAX_CONFIG_BYTES = 1024 * 1024;
198
- /** Read an OS value that can throw (notably `process.cwd()` when the working dir was removed), degrading
199
- * to "" so config loading never crashes a command that doesn't even need the value. */
200
- function safeOsValue(read) {
201
- try {
202
- return read();
203
- }
204
- catch {
205
- return "";
206
- }
207
- }
208
192
  /** Production `ConfigFileIo` backed by the real filesystem, home dir, cwd, and environment. */
209
193
  export function nodeConfigFileIo() {
210
194
  return {
@@ -1 +1 @@
1
- {"version":3,"file":"config-file.js","sourceRoot":"","sources":["../src/config-file.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"config-file.js","sourceRoot":"","sources":["../src/config-file.ts"],"names":[],"mappings":"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"}