@ora-ai/cli 0.1.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.
Files changed (147) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +102 -0
  3. package/dist/auth-commands.d.ts +39 -0
  4. package/dist/auth-commands.d.ts.map +1 -0
  5. package/dist/auth-commands.js +116 -0
  6. package/dist/auth-commands.js.map +1 -0
  7. package/dist/core/auth.d.ts +41 -0
  8. package/dist/core/auth.d.ts.map +1 -0
  9. package/dist/core/auth.js +110 -0
  10. package/dist/core/auth.js.map +1 -0
  11. package/dist/core/config.d.ts +26 -0
  12. package/dist/core/config.d.ts.map +1 -0
  13. package/dist/core/config.js +51 -0
  14. package/dist/core/config.js.map +1 -0
  15. package/dist/core/http.d.ts +46 -0
  16. package/dist/core/http.d.ts.map +1 -0
  17. package/dist/core/http.js +82 -0
  18. package/dist/core/http.js.map +1 -0
  19. package/dist/core/login.d.ts +14 -0
  20. package/dist/core/login.d.ts.map +1 -0
  21. package/dist/core/login.js +70 -0
  22. package/dist/core/login.js.map +1 -0
  23. package/dist/core/output.d.ts +18 -0
  24. package/dist/core/output.d.ts.map +1 -0
  25. package/dist/core/output.js +94 -0
  26. package/dist/core/output.js.map +1 -0
  27. package/dist/core/run-operation.d.ts +57 -0
  28. package/dist/core/run-operation.d.ts.map +1 -0
  29. package/dist/core/run-operation.js +119 -0
  30. package/dist/core/run-operation.js.map +1 -0
  31. package/dist/core/sse.d.ts +13 -0
  32. package/dist/core/sse.d.ts.map +1 -0
  33. package/dist/core/sse.js +63 -0
  34. package/dist/core/sse.js.map +1 -0
  35. package/dist/generated/operations.d.ts +47 -0
  36. package/dist/generated/operations.d.ts.map +1 -0
  37. package/dist/generated/operations.js +2050 -0
  38. package/dist/generated/operations.js.map +1 -0
  39. package/dist/generated/types.d.ts +1039 -0
  40. package/dist/generated/types.d.ts.map +1 -0
  41. package/dist/generated/types.js +5 -0
  42. package/dist/generated/types.js.map +1 -0
  43. package/dist/index.d.ts +7 -0
  44. package/dist/index.d.ts.map +1 -0
  45. package/dist/index.js +17 -0
  46. package/dist/index.js.map +1 -0
  47. package/dist/interactive/derive-prompts.d.ts +44 -0
  48. package/dist/interactive/derive-prompts.d.ts.map +1 -0
  49. package/dist/interactive/derive-prompts.js +58 -0
  50. package/dist/interactive/derive-prompts.js.map +1 -0
  51. package/dist/interactive/inquirer-prompter.d.ts +11 -0
  52. package/dist/interactive/inquirer-prompter.d.ts.map +1 -0
  53. package/dist/interactive/inquirer-prompter.js +64 -0
  54. package/dist/interactive/inquirer-prompter.js.map +1 -0
  55. package/dist/interactive/menu.d.ts +25 -0
  56. package/dist/interactive/menu.d.ts.map +1 -0
  57. package/dist/interactive/menu.js +57 -0
  58. package/dist/interactive/menu.js.map +1 -0
  59. package/dist/interactive/prompter.d.ts +25 -0
  60. package/dist/interactive/prompter.d.ts.map +1 -0
  61. package/dist/interactive/prompter.js +14 -0
  62. package/dist/interactive/prompter.js.map +1 -0
  63. package/dist/interactive/session.d.ts +19 -0
  64. package/dist/interactive/session.d.ts.map +1 -0
  65. package/dist/interactive/session.js +204 -0
  66. package/dist/interactive/session.js.map +1 -0
  67. package/dist/program.d.ts +81 -0
  68. package/dist/program.d.ts.map +1 -0
  69. package/dist/program.js +178 -0
  70. package/dist/program.js.map +1 -0
  71. package/dist/render/ansi.d.ts +13 -0
  72. package/dist/render/ansi.d.ts.map +1 -0
  73. package/dist/render/ansi.js +34 -0
  74. package/dist/render/ansi.js.map +1 -0
  75. package/dist/render/banner.d.ts +7 -0
  76. package/dist/render/banner.d.ts.map +1 -0
  77. package/dist/render/banner.js +18 -0
  78. package/dist/render/banner.js.map +1 -0
  79. package/dist/render/glyphs.d.ts +39 -0
  80. package/dist/render/glyphs.d.ts.map +1 -0
  81. package/dist/render/glyphs.js +83 -0
  82. package/dist/render/glyphs.js.map +1 -0
  83. package/dist/render/index.d.ts +13 -0
  84. package/dist/render/index.d.ts.map +1 -0
  85. package/dist/render/index.js +24 -0
  86. package/dist/render/index.js.map +1 -0
  87. package/dist/render/insight-lines.d.ts +8 -0
  88. package/dist/render/insight-lines.d.ts.map +1 -0
  89. package/dist/render/insight-lines.js +62 -0
  90. package/dist/render/insight-lines.js.map +1 -0
  91. package/dist/render/insight.d.ts +9 -0
  92. package/dist/render/insight.d.ts.map +1 -0
  93. package/dist/render/insight.js +68 -0
  94. package/dist/render/insight.js.map +1 -0
  95. package/dist/render/journey-graph.d.ts +73 -0
  96. package/dist/render/journey-graph.d.ts.map +1 -0
  97. package/dist/render/journey-graph.js +250 -0
  98. package/dist/render/journey-graph.js.map +1 -0
  99. package/dist/render/journey.d.ts +14 -0
  100. package/dist/render/journey.d.ts.map +1 -0
  101. package/dist/render/journey.js +67 -0
  102. package/dist/render/journey.js.map +1 -0
  103. package/dist/render/live-panel.d.ts +34 -0
  104. package/dist/render/live-panel.d.ts.map +1 -0
  105. package/dist/render/live-panel.js +84 -0
  106. package/dist/render/live-panel.js.map +1 -0
  107. package/dist/render/mode.d.ts +19 -0
  108. package/dist/render/mode.d.ts.map +1 -0
  109. package/dist/render/mode.js +23 -0
  110. package/dist/render/mode.js.map +1 -0
  111. package/dist/render/registry.d.ts +17 -0
  112. package/dist/render/registry.d.ts.map +1 -0
  113. package/dist/render/registry.js +34 -0
  114. package/dist/render/registry.js.map +1 -0
  115. package/dist/render/run-list.d.ts +11 -0
  116. package/dist/render/run-list.d.ts.map +1 -0
  117. package/dist/render/run-list.js +53 -0
  118. package/dist/render/run-list.js.map +1 -0
  119. package/dist/render/spinner.d.ts +14 -0
  120. package/dist/render/spinner.d.ts.map +1 -0
  121. package/dist/render/spinner.js +37 -0
  122. package/dist/render/spinner.js.map +1 -0
  123. package/dist/render/table.d.ts +20 -0
  124. package/dist/render/table.d.ts.map +1 -0
  125. package/dist/render/table.js +29 -0
  126. package/dist/render/table.js.map +1 -0
  127. package/dist/render/trajectory.d.ts +19 -0
  128. package/dist/render/trajectory.d.ts.map +1 -0
  129. package/dist/render/trajectory.js +75 -0
  130. package/dist/render/trajectory.js.map +1 -0
  131. package/dist/render/tunnel.d.ts +10 -0
  132. package/dist/render/tunnel.d.ts.map +1 -0
  133. package/dist/render/tunnel.js +108 -0
  134. package/dist/render/tunnel.js.map +1 -0
  135. package/dist/render/usage.d.ts +29 -0
  136. package/dist/render/usage.d.ts.map +1 -0
  137. package/dist/render/usage.js +83 -0
  138. package/dist/render/usage.js.map +1 -0
  139. package/dist/tunnel-command.d.ts +15 -0
  140. package/dist/tunnel-command.d.ts.map +1 -0
  141. package/dist/tunnel-command.js +267 -0
  142. package/dist/tunnel-command.js.map +1 -0
  143. package/dist/watch.d.ts +53 -0
  144. package/dist/watch.d.ts.map +1 -0
  145. package/dist/watch.js +305 -0
  146. package/dist/watch.js.map +1 -0
  147. package/package.json +36 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 ora (ora-ai)
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,102 @@
1
+ # ora — the ora CLI
2
+
3
+ Drive the [ora](https://agentfront.sh) public API from your terminal. Every
4
+ command is generated from ora's public OpenAPI document, so the CLI always
5
+ matches the API: `https://api.agentfront.sh/openapi.json`.
6
+
7
+ ## Install
8
+
9
+ npm install -g @ora-ai/cli
10
+ ora --help
11
+
12
+ (`npx @ora-ai/cli` also works. Note: bare `npx ora` fetches an unrelated npm
13
+ spinner library — always use the scoped package name with npx.)
14
+
15
+ ## Interactive
16
+
17
+ Just run `ora` — browse every command, get prompted for arguments, and see
18
+ the equivalent scriptable command before it runs.
19
+
20
+ ora
21
+
22
+ This only opens in a real terminal (both stdin and stdout attached to a tty).
23
+ Piped or scripted (`ora | less`, `ora > out.txt`, inside CI), bare `ora`
24
+ prints `--help` instead — nothing changes for existing scripts.
25
+
26
+ ## Authenticate
27
+
28
+ Mint an api key in the ora dashboard (Settings → API keys), then:
29
+
30
+ ora login # paste the key (masked), or:
31
+ ora login --api-key ora_sk_...
32
+ ora whoami
33
+
34
+ In CI, skip login and export `ORA_API_KEY` (prefer short-expiry keys). The
35
+ key is stored at `~/.config/ora/config.json` (0600) and exchanged for a
36
+ short-lived token on every call — the key itself never travels beyond the
37
+ token exchange.
38
+
39
+ ## Use
40
+
41
+ Every command's `--help` ends with a ready-to-run example (including a request
42
+ body where one is needed) — the fastest way to learn a command is to ask it:
43
+
44
+ ora --help # all command groups
45
+ ora experiment runs --help # everything you can do with runs
46
+ ora experiment runs create --help # flags + an example run.json
47
+
48
+ ### Runs — launch and follow agent executions
49
+
50
+ ora experiment runs list --page-size 20
51
+
52
+ cat > run.json <<'EOF'
53
+ { "intent": "check pricing for acme.com", "harness": "eve", "model": "claude-sonnet-5" }
54
+ EOF
55
+ ora experiment runs create --file run.json # returns {runId, streamUrl, status}
56
+ ora experiment runs create --file run.json --watch # same, then streams live events until done
57
+ ora experiment runs stream <run-id> # attach to a run already in flight
58
+ ora experiment runs feed # org-wide live feed of run status changes
59
+
60
+ After a run completes, read its artifacts:
61
+
62
+ ora experiment runs insight <run-id> # the analyzed outcome
63
+ ora experiment runs trajectory <run-id> # step-by-step trace
64
+ ora experiment runs raw-trace <run-id> # the full raw event log
65
+
66
+ ### Intents — AEO measurement (studio)
67
+
68
+ ora intents list
69
+ cat > intent.json <<'EOF'
70
+ { "title": "Best AEO platform for B2B SaaS", "layer": "discovery" }
71
+ EOF
72
+ ora intents create --file intent.json
73
+ ora intents measurements-status # are the daily measurements running?
74
+ ora intents measurements-pause-all # stop the scans
75
+ ora intents measurements-resume-all # restart them
76
+
77
+ ### Sessions — long-lived agent environments
78
+
79
+ ora sessions catalog # harnesses + models you can launch
80
+ ora sessions list
81
+ ora sessions hibernate <id>
82
+ ora sessions wake <id>
83
+
84
+ ### Scripting
85
+
86
+ `--json` prints the raw API response; with `--watch` it becomes NDJSON (the
87
+ create response first, then one line per event). Exit codes: 0 ok, 1 API/auth
88
+ error, 2 usage error.
89
+
90
+ id=$(ora experiment runs create --file run.json --json | jq -r .runId)
91
+ ora experiment runs stream "$id" --json | jq -c 'select(.event == "step")'
92
+
93
+ ora experiment runs list --json | jq '.results[] | {id, harness, status}'
94
+
95
+ In CI, export `ORA_API_KEY` instead of logging in. Point at another
96
+ environment with `ORA_API_URL` or `--api-url`.
97
+
98
+ ## Errors that explain themselves
99
+
100
+ - **402** — a plan limit was hit; the message names the dimension and where to upgrade.
101
+ - **403 INSUFFICIENT_SCOPE** — the key lacks a scope; the message names it. Mint
102
+ a key with that scope and `ora login` again.
@@ -0,0 +1,39 @@
1
+ /**
2
+ * The three handwritten auth commands: login / logout / whoami — plus
3
+ * performLogin/performWhoami, the cores shared verbatim with the interactive
4
+ * session (interactive/session.ts imports both).
5
+ *
6
+ * ResolvedDeps is imported type-only from program.ts — no runtime edge back
7
+ * to program.ts (program.ts imports these attach* functions by value; see
8
+ * that file's session-cycle doc comment for the same pattern).
9
+ */
10
+ import type { Command } from "commander";
11
+ import type { ResolvedDeps } from "./program.js";
12
+ /**
13
+ * The login core: validate the `ora_sk_` prefix → store → verify by
14
+ * exchanging for a token → roll back the stored key on verification failure.
15
+ * Shared verbatim by the scripted `login` action and (Task 4) the
16
+ * interactive session — prints exactly the lines the action always printed
17
+ * and returns whether login succeeded.
18
+ */
19
+ export declare function performLogin(deps: ResolvedDeps, opts: {
20
+ apiKey?: string;
21
+ apiUrl?: string;
22
+ }): Promise<boolean>;
23
+ /**
24
+ * The whoami core: verify the configured key and print its identity. THE one
25
+ * implementation — shared verbatim by the scripted `whoami` action and the
26
+ * interactive session's whoami menu entry (interactive/session.ts) so the two
27
+ * doors never drift apart. Returns whether it succeeded and never throws;
28
+ * mirrors runOperation's own caller contract (sets process.exitCode on
29
+ * failure, leaves it alone on success) so both callers reset exit-code state
30
+ * the same way.
31
+ */
32
+ export declare function performWhoami(deps: ResolvedDeps, opts: {
33
+ json?: boolean;
34
+ apiUrlFlag?: string;
35
+ }): Promise<boolean>;
36
+ export declare function attachLogin(program: Command, deps: ResolvedDeps): void;
37
+ export declare function attachLogout(program: Command, deps: ResolvedDeps): void;
38
+ export declare function attachWhoami(program: Command, deps: ResolvedDeps): void;
39
+ //# sourceMappingURL=auth-commands.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth-commands.d.ts","sourceRoot":"","sources":["../src/auth-commands.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAQzC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAEjD;;;;;;GAMG;AACH,wBAAsB,YAAY,CAAC,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CA0BnH;AAED;;;;;;;;GAQG;AACH,wBAAsB,aAAa,CAAC,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE;IAAE,IAAI,CAAC,EAAE,OAAO,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAwBvH;AAED,wBAAgB,WAAW,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,YAAY,GAAG,IAAI,CAWtE;AAED,wBAAgB,YAAY,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,YAAY,GAAG,IAAI,CASvE;AAED,wBAAgB,YAAY,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,YAAY,GAAG,IAAI,CAUvE"}
@@ -0,0 +1,116 @@
1
+ /**
2
+ * The three handwritten auth commands: login / logout / whoami — plus
3
+ * performLogin/performWhoami, the cores shared verbatim with the interactive
4
+ * session (interactive/session.ts imports both).
5
+ *
6
+ * ResolvedDeps is imported type-only from program.ts — no runtime edge back
7
+ * to program.ts (program.ts imports these attach* functions by value; see
8
+ * that file's session-cycle doc comment for the same pattern).
9
+ */
10
+ import { decodeClaims } from "./core/auth.js";
11
+ import { clearCredentials, readConfig, resolveApiUrl, writeConfig } from "./core/config.js";
12
+ import { promptForKey } from "./core/login.js";
13
+ import { renderError } from "./core/output.js";
14
+ import { credentials } from "./core/run-operation.js";
15
+ import { SPEC } from "./generated/operations.js";
16
+ /**
17
+ * The login core: validate the `ora_sk_` prefix → store → verify by
18
+ * exchanging for a token → roll back the stored key on verification failure.
19
+ * Shared verbatim by the scripted `login` action and (Task 4) the
20
+ * interactive session — prints exactly the lines the action always printed
21
+ * and returns whether login succeeded.
22
+ */
23
+ export async function performLogin(deps, opts) {
24
+ const key = opts.apiKey ?? "";
25
+ if (!key.startsWith("ora_sk_")) {
26
+ deps.errOut(renderError(new Error('That does not look like an ora api key (expected an "ora_sk_" prefix).')));
27
+ process.exitCode = 1;
28
+ return false;
29
+ }
30
+ const previous = readConfig(deps.dir);
31
+ const apiUrl = resolveApiUrl(previous, opts.apiUrl, SPEC.server, deps.env);
32
+ // Announce the target BEFORE verifying: a key minted on one environment
33
+ // failing against another must be self-diagnosing, never a mystery.
34
+ deps.out(`Verifying against ${apiUrl}`);
35
+ writeConfig({ ...previous, apiKey: key, ...(opts.apiUrl ? { apiUrl } : {}) }, deps.dir);
36
+ try {
37
+ const token = await deps.makeAuth({ apiUrl, apiKey: key }).forceRefresh();
38
+ const claims = decodeClaims(token);
39
+ deps.out(`Logged in. org=${String(claims.org ?? claims.organizationId ?? "?")} subject=${String(claims.sub ?? "?")}`);
40
+ return true;
41
+ }
42
+ catch (err) {
43
+ writeConfig(previous, deps.dir); // verification failed — roll back
44
+ deps.errOut(renderError(err));
45
+ process.exitCode = 1;
46
+ return false;
47
+ }
48
+ }
49
+ /**
50
+ * The whoami core: verify the configured key and print its identity. THE one
51
+ * implementation — shared verbatim by the scripted `whoami` action and the
52
+ * interactive session's whoami menu entry (interactive/session.ts) so the two
53
+ * doors never drift apart. Returns whether it succeeded and never throws;
54
+ * mirrors runOperation's own caller contract (sets process.exitCode on
55
+ * failure, leaves it alone on success) so both callers reset exit-code state
56
+ * the same way.
57
+ */
58
+ export async function performWhoami(deps, opts) {
59
+ const creds = credentials(deps, opts.apiUrlFlag);
60
+ if (!creds)
61
+ return false;
62
+ try {
63
+ const token = await deps.makeAuth(creds).forceRefresh();
64
+ const claims = decodeClaims(token);
65
+ if (opts.json) {
66
+ deps.out(JSON.stringify(claims, null, 2));
67
+ return true;
68
+ }
69
+ deps.out([
70
+ `org: ${String(claims.org ?? claims.organizationId ?? "?")}`,
71
+ `subject: ${String(claims.sub ?? "?")}`,
72
+ ...(Array.isArray(claims.scopes) ? [`scopes: ${claims.scopes.join(", ")}`] : []),
73
+ `api: ${creds.apiUrl}`,
74
+ ].join("\n"));
75
+ return true;
76
+ }
77
+ catch (err) {
78
+ deps.errOut(renderError(err));
79
+ process.exitCode = 1;
80
+ return false;
81
+ }
82
+ }
83
+ export function attachLogin(program, deps) {
84
+ program
85
+ .command("login")
86
+ .description("Store an api key for ora (paste, --api-key, or ORA_API_KEY)")
87
+ .option("--api-key <key>", "the ora_sk_… api key")
88
+ .option("--api-url <url>", "override the API base URL")
89
+ .addHelpText("after", "\nExamples:\n ora login --api-key ora_sk_…\n ORA_API_KEY=ora_sk_… ora login # non-interactive (CI)\n ora login --api-url http://api.localhost:8081 # dev cluster")
90
+ .action(async (opts) => {
91
+ const key = opts.apiKey ?? deps.env.ORA_API_KEY ?? (await promptForKey());
92
+ await performLogin(deps, { apiKey: key, apiUrl: opts.apiUrl });
93
+ });
94
+ }
95
+ export function attachLogout(program, deps) {
96
+ program
97
+ .command("logout")
98
+ .description("Delete the stored api key and cached token")
99
+ .addHelpText("after", "\nExamples:\n ora logout")
100
+ .action(() => {
101
+ clearCredentials(deps.dir);
102
+ deps.out("Logged out — credentials removed.");
103
+ });
104
+ }
105
+ export function attachWhoami(program, deps) {
106
+ program
107
+ .command("whoami")
108
+ .description("Verify the configured key against the API and print its identity")
109
+ .option("--json", "print the raw token claims")
110
+ .option("--api-url <url>", "override the API base URL")
111
+ .addHelpText("after", "\nExamples:\n ora whoami\n ora whoami --json")
112
+ .action(async (opts) => {
113
+ await performWhoami(deps, { json: opts.json, apiUrlFlag: opts.apiUrl });
114
+ });
115
+ }
116
+ //# sourceMappingURL=auth-commands.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth-commands.js","sourceRoot":"","sources":["../src/auth-commands.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Api-key → short-lived token exchange.
3
+ *
4
+ * The credential travels ONLY as "Authorization: Bearer <ora_sk_…>" to
5
+ * POST /auth/token (the doc's own rule: never in the request body). The
6
+ * response {token, expiresIn} is cached on disk (0600) and reused until a 30s
7
+ * skew before expiry, so a token can't die between "checked" and "used".
8
+ *
9
+ * The cache is keyed to (apiUrl, sha256(key)) — pointing the CLI at staging or
10
+ * switching keys can never replay a token minted elsewhere. Cache write
11
+ * failures are swallowed: a cache is an optimization, not a requirement.
12
+ */
13
+ export declare class AuthError extends Error {
14
+ readonly status: number;
15
+ readonly code: string;
16
+ constructor(message: string, status: number, code: string);
17
+ }
18
+ export interface ApiKeyAuthDeps {
19
+ apiUrl: string;
20
+ apiKey: string;
21
+ dir?: string;
22
+ fetchFn?: typeof fetch;
23
+ now?: () => number;
24
+ }
25
+ export declare class ApiKeyAuth {
26
+ private readonly apiUrl;
27
+ private readonly apiKey;
28
+ private readonly dir;
29
+ private readonly fetchFn;
30
+ private readonly now;
31
+ constructor(deps: ApiKeyAuthDeps);
32
+ getToken(): Promise<string>;
33
+ forceRefresh(): Promise<string>;
34
+ clearCache(): void;
35
+ private cachePath;
36
+ private keyDigest;
37
+ private readCache;
38
+ }
39
+ /** JWT payload claims, {} on anything unparseable. Display only — never trust. */
40
+ export declare function decodeClaims(token: string): Record<string, unknown>;
41
+ //# sourceMappingURL=auth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/core/auth.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAWH,qBAAa,SAAU,SAAQ,KAAK;IAGhC,QAAQ,CAAC,MAAM,EAAE,MAAM;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM;gBAFrB,OAAO,EAAE,MAAM,EACN,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM;CAKxB;AASD,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,OAAO,KAAK,CAAC;IACvB,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CACpB;AAED,qBAAa,UAAU;IACrB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAS;IAC7B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAe;IACvC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAe;gBAEvB,IAAI,EAAE,cAAc;IAQ1B,QAAQ,IAAI,OAAO,CAAC,MAAM,CAAC;IAM3B,YAAY,IAAI,OAAO,CAAC,MAAM,CAAC;IAqCrC,UAAU,IAAI,IAAI;IAIlB,OAAO,CAAC,SAAS;IAIjB,OAAO,CAAC,SAAS;IAIjB,OAAO,CAAC,SAAS;CAUlB;AAED,kFAAkF;AAClF,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAQnE"}
@@ -0,0 +1,110 @@
1
+ /**
2
+ * Api-key → short-lived token exchange.
3
+ *
4
+ * The credential travels ONLY as "Authorization: Bearer <ora_sk_…>" to
5
+ * POST /auth/token (the doc's own rule: never in the request body). The
6
+ * response {token, expiresIn} is cached on disk (0600) and reused until a 30s
7
+ * skew before expiry, so a token can't die between "checked" and "used".
8
+ *
9
+ * The cache is keyed to (apiUrl, sha256(key)) — pointing the CLI at staging or
10
+ * switching keys can never replay a token minted elsewhere. Cache write
11
+ * failures are swallowed: a cache is an optimization, not a requirement.
12
+ */
13
+ import { createHash } from "node:crypto";
14
+ import { chmodSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
15
+ import { join } from "node:path";
16
+ import { configDir } from "./config.js";
17
+ const EXPIRY_SKEW_MS = 30_000;
18
+ const DEFAULT_EXPIRES_IN_S = 900;
19
+ export class AuthError extends Error {
20
+ status;
21
+ code;
22
+ constructor(message, status, code) {
23
+ super(message);
24
+ this.status = status;
25
+ this.code = code;
26
+ this.name = "AuthError";
27
+ }
28
+ }
29
+ export class ApiKeyAuth {
30
+ apiUrl;
31
+ apiKey;
32
+ dir;
33
+ fetchFn;
34
+ now;
35
+ constructor(deps) {
36
+ this.apiUrl = deps.apiUrl;
37
+ this.apiKey = deps.apiKey;
38
+ this.dir = deps.dir ?? configDir();
39
+ this.fetchFn = deps.fetchFn ?? fetch;
40
+ this.now = deps.now ?? Date.now;
41
+ }
42
+ async getToken() {
43
+ const cached = this.readCache();
44
+ if (cached && cached.expiresAt - EXPIRY_SKEW_MS > this.now())
45
+ return cached.token;
46
+ return this.forceRefresh();
47
+ }
48
+ async forceRefresh() {
49
+ const res = await this.fetchFn(`${this.apiUrl}/auth/token`, {
50
+ method: "POST",
51
+ headers: { authorization: `Bearer ${this.apiKey}`, "content-type": "application/json" },
52
+ body: "{}",
53
+ });
54
+ const body = (await res.json().catch(() => ({})));
55
+ if (!res.ok || typeof body.token !== "string") {
56
+ throw new AuthError(body.error ?? `token exchange failed (HTTP ${res.status})`, res.status, body.code ?? "EXCHANGE_FAILED");
57
+ }
58
+ const record = {
59
+ apiUrl: this.apiUrl,
60
+ keyDigest: this.keyDigest(),
61
+ token: body.token,
62
+ expiresAt: this.now() + (body.expiresIn ?? DEFAULT_EXPIRES_IN_S) * 1000,
63
+ };
64
+ try {
65
+ mkdirSync(this.dir, { recursive: true, mode: 0o700 });
66
+ chmodSync(this.dir, 0o700);
67
+ writeFileSync(this.cachePath(), `${JSON.stringify(record, null, 2)}\n`, { mode: 0o600 });
68
+ chmodSync(this.cachePath(), 0o600);
69
+ }
70
+ catch {
71
+ // Unwritable cache just means we exchange again next invocation.
72
+ }
73
+ return body.token;
74
+ }
75
+ clearCache() {
76
+ rmSync(this.cachePath(), { force: true });
77
+ }
78
+ cachePath() {
79
+ return join(this.dir, "token.json");
80
+ }
81
+ keyDigest() {
82
+ return createHash("sha256").update(this.apiKey).digest("hex").slice(0, 16);
83
+ }
84
+ readCache() {
85
+ try {
86
+ const parsed = JSON.parse(readFileSync(this.cachePath(), "utf8"));
87
+ if (parsed.apiUrl !== this.apiUrl || parsed.keyDigest !== this.keyDigest())
88
+ return null;
89
+ if (typeof parsed.token !== "string" || typeof parsed.expiresAt !== "number")
90
+ return null;
91
+ return parsed;
92
+ }
93
+ catch {
94
+ return null;
95
+ }
96
+ }
97
+ }
98
+ /** JWT payload claims, {} on anything unparseable. Display only — never trust. */
99
+ export function decodeClaims(token) {
100
+ const payload = token.split(".")[1];
101
+ if (!payload)
102
+ return {};
103
+ try {
104
+ return JSON.parse(Buffer.from(payload, "base64url").toString("utf8"));
105
+ }
106
+ catch {
107
+ return {};
108
+ }
109
+ }
110
+ //# sourceMappingURL=auth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/core/auth.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AACpF,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAExC,MAAM,cAAc,GAAG,MAAM,CAAC;AAC9B,MAAM,oBAAoB,GAAG,GAAG,CAAC;AAEjC,MAAM,OAAO,SAAU,SAAQ,KAAK;IAGvB;IACA;IAHX,YACE,OAAe,EACN,MAAc,EACd,IAAY;QAErB,KAAK,CAAC,OAAO,CAAC,CAAC;QAHN,WAAM,GAAN,MAAM,CAAQ;QACd,SAAI,GAAJ,IAAI,CAAQ;QAGrB,IAAI,CAAC,IAAI,GAAG,WAAW,CAAC;IAC1B,CAAC;CACF;AAiBD,MAAM,OAAO,UAAU;IACJ,MAAM,CAAS;IACf,MAAM,CAAS;IACf,GAAG,CAAS;IACZ,OAAO,CAAe;IACtB,GAAG,CAAe;IAEnC,YAAY,IAAoB;QAC9B,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;QAC1B,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;QAC1B,IAAI,CAAC,GAAG,GAAG,IAAI,CAAC,GAAG,IAAI,SAAS,EAAE,CAAC;QACnC,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,IAAI,KAAK,CAAC;QACrC,IAAI,CAAC,GAAG,GAAG,IAAI,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC;IAClC,CAAC;IAED,KAAK,CAAC,QAAQ;QACZ,MAAM,MAAM,GAAG,IAAI,CAAC,SAAS,EAAE,CAAC;QAChC,IAAI,MAAM,IAAI,MAAM,CAAC,SAAS,GAAG,cAAc,GAAG,IAAI,CAAC,GAAG,EAAE;YAAE,OAAO,MAAM,CAAC,KAAK,CAAC;QAClF,OAAO,IAAI,CAAC,YAAY,EAAE,CAAC;IAC7B,CAAC;IAED,KAAK,CAAC,YAAY;QAChB,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC,MAAM,aAAa,EAAE;YAC1D,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,EAAE,aAAa,EAAE,UAAU,IAAI,CAAC,MAAM,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;YACvF,IAAI,EAAE,IAAI;SACX,CAAC,CAAC;QACH,MAAM,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAK/C,CAAC;QACF,IAAI,CAAC,GAAG,CAAC,EAAE,IAAI,OAAO,IAAI,CAAC,KAAK,KAAK,QAAQ,EAAE,CAAC;YAC9C,MAAM,IAAI,SAAS,CACjB,IAAI,CAAC,KAAK,IAAI,+BAA+B,GAAG,CAAC,MAAM,GAAG,EAC1D,GAAG,CAAC,MAAM,EACV,IAAI,CAAC,IAAI,IAAI,iBAAiB,CAC/B,CAAC;QACJ,CAAC;QAED,MAAM,MAAM,GAAgB;YAC1B,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,SAAS,EAAE,IAAI,CAAC,SAAS,EAAE;YAC3B,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC,IAAI,CAAC,SAAS,IAAI,oBAAoB,CAAC,GAAG,IAAI;SACxE,CAAC;QACF,IAAI,CAAC;YACH,SAAS,CAAC,IAAI,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;YACtD,SAAS,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;YAC3B,aAAa,CAAC,IAAI,CAAC,SAAS,EAAE,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;YACzF,SAAS,CAAC,IAAI,CAAC,SAAS,EAAE,EAAE,KAAK,CAAC,CAAC;QACrC,CAAC;QAAC,MAAM,CAAC;YACP,iEAAiE;QACnE,CAAC;QACD,OAAO,IAAI,CAAC,KAAK,CAAC;IACpB,CAAC;IAED,UAAU;QACR,MAAM,CAAC,IAAI,CAAC,SAAS,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IAC5C,CAAC;IAEO,SAAS;QACf,OAAO,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,YAAY,CAAC,CAAC;IACtC,CAAC;IAEO,SAAS;QACf,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAC7E,CAAC;IAEO,SAAS;QACf,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,SAAS,EAAE,EAAE,MAAM,CAAC,CAAyB,CAAC;YAC1F,IAAI,MAAM,CAAC,MAAM,KAAK,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,SAAS,KAAK,IAAI,CAAC,SAAS,EAAE;gBAAE,OAAO,IAAI,CAAC;YACxF,IAAI,OAAO,MAAM,CAAC,KAAK,KAAK,QAAQ,IAAI,OAAO,MAAM,CAAC,SAAS,KAAK,QAAQ;gBAAE,OAAO,IAAI,CAAC;YAC1F,OAAO,MAAqB,CAAC;QAC/B,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;CACF;AAED,kFAAkF;AAClF,MAAM,UAAU,YAAY,CAAC,KAAa;IACxC,MAAM,OAAO,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IACpC,IAAI,CAAC,OAAO;QAAE,OAAO,EAAE,CAAC;IACxB,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAA4B,CAAC;IACnG,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Credential + endpoint configuration.
3
+ *
4
+ * ~/.config/ora (XDG-respecting) holds config.json (api key, api url) and
5
+ * token.json (the cached short-lived token, owned by auth.ts). Both are 0600 in
6
+ * a 0700 dir — the key is a secret. Every read degrades to "not configured"
7
+ * rather than throwing: a corrupt file must never brick the CLI.
8
+ *
9
+ * Permissions are re-asserted on every write, not just on creation. This hardens
10
+ * pre-existing insecure files (e.g. restored from dotfiles with loose modes).
11
+ *
12
+ * Precedence (why: CI overrides laptops, flags override everything):
13
+ * api key : ORA_API_KEY env > config.json
14
+ * api url : --api-url flag > ORA_API_URL env > config.json > the spec's server
15
+ */
16
+ export interface OraConfig {
17
+ apiKey?: string;
18
+ apiUrl?: string;
19
+ }
20
+ export declare function configDir(env?: NodeJS.ProcessEnv): string;
21
+ export declare function readConfig(dir?: string): OraConfig;
22
+ export declare function writeConfig(cfg: OraConfig, dir?: string): void;
23
+ export declare function clearCredentials(dir?: string): void;
24
+ export declare function resolveApiKey(cfg: OraConfig, env?: NodeJS.ProcessEnv): string | undefined;
25
+ export declare function resolveApiUrl(cfg: OraConfig, flagValue: string | undefined, embeddedDefault: string, env?: NodeJS.ProcessEnv): string;
26
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/core/config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAMH,MAAM,WAAW,SAAS;IACxB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,wBAAgB,SAAS,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,MAAM,CAGtE;AAED,wBAAgB,UAAU,CAAC,GAAG,GAAE,MAAoB,GAAG,SAAS,CAU/D;AAED,wBAAgB,WAAW,CAAC,GAAG,EAAE,SAAS,EAAE,GAAG,GAAE,MAAoB,GAAG,IAAI,CAK3E;AAED,wBAAgB,gBAAgB,CAAC,GAAG,GAAE,MAAoB,GAAG,IAAI,CAGhE;AAED,wBAAgB,aAAa,CAAC,GAAG,EAAE,SAAS,EAAE,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,MAAM,GAAG,SAAS,CAEtG;AAED,wBAAgB,aAAa,CAC3B,GAAG,EAAE,SAAS,EACd,SAAS,EAAE,MAAM,GAAG,SAAS,EAC7B,eAAe,EAAE,MAAM,EACvB,GAAG,GAAE,MAAM,CAAC,UAAwB,GACnC,MAAM,CAER"}
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Credential + endpoint configuration.
3
+ *
4
+ * ~/.config/ora (XDG-respecting) holds config.json (api key, api url) and
5
+ * token.json (the cached short-lived token, owned by auth.ts). Both are 0600 in
6
+ * a 0700 dir — the key is a secret. Every read degrades to "not configured"
7
+ * rather than throwing: a corrupt file must never brick the CLI.
8
+ *
9
+ * Permissions are re-asserted on every write, not just on creation. This hardens
10
+ * pre-existing insecure files (e.g. restored from dotfiles with loose modes).
11
+ *
12
+ * Precedence (why: CI overrides laptops, flags override everything):
13
+ * api key : ORA_API_KEY env > config.json
14
+ * api url : --api-url flag > ORA_API_URL env > config.json > the spec's server
15
+ */
16
+ import { chmodSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
17
+ import { homedir } from "node:os";
18
+ import { join } from "node:path";
19
+ export function configDir(env = process.env) {
20
+ const base = env.XDG_CONFIG_HOME || join(homedir(), ".config");
21
+ return join(base, "ora");
22
+ }
23
+ export function readConfig(dir = configDir()) {
24
+ try {
25
+ const parsed = JSON.parse(readFileSync(join(dir, "config.json"), "utf8"));
26
+ return {
27
+ ...(typeof parsed.apiKey === "string" ? { apiKey: parsed.apiKey } : {}),
28
+ ...(typeof parsed.apiUrl === "string" ? { apiUrl: parsed.apiUrl } : {}),
29
+ };
30
+ }
31
+ catch {
32
+ return {};
33
+ }
34
+ }
35
+ export function writeConfig(cfg, dir = configDir()) {
36
+ mkdirSync(dir, { recursive: true, mode: 0o700 });
37
+ chmodSync(dir, 0o700);
38
+ writeFileSync(join(dir, "config.json"), `${JSON.stringify(cfg, null, 2)}\n`, { mode: 0o600 });
39
+ chmodSync(join(dir, "config.json"), 0o600);
40
+ }
41
+ export function clearCredentials(dir = configDir()) {
42
+ rmSync(join(dir, "config.json"), { force: true });
43
+ rmSync(join(dir, "token.json"), { force: true });
44
+ }
45
+ export function resolveApiKey(cfg, env = process.env) {
46
+ return env.ORA_API_KEY || cfg.apiKey;
47
+ }
48
+ export function resolveApiUrl(cfg, flagValue, embeddedDefault, env = process.env) {
49
+ return (flagValue || env.ORA_API_URL || cfg.apiUrl || embeddedDefault).replace(/\/+$/, "");
50
+ }
51
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/core/config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AACpF,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAOjC,MAAM,UAAU,SAAS,CAAC,MAAyB,OAAO,CAAC,GAAG;IAC5D,MAAM,IAAI,GAAG,GAAG,CAAC,eAAe,IAAI,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,CAAC,CAAC;IAC/D,OAAO,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;AAC3B,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,MAAc,SAAS,EAAE;IAClD,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,GAAG,EAAE,aAAa,CAAC,EAAE,MAAM,CAAC,CAA4B,CAAC;QACrG,OAAO;YACL,GAAG,CAAC,OAAO,MAAM,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACvE,GAAG,CAAC,OAAO,MAAM,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SACxE,CAAC;IACJ,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,GAAc,EAAE,MAAc,SAAS,EAAE;IACnE,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IACjD,SAAS,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IACtB,aAAa,CAAC,IAAI,CAAC,GAAG,EAAE,aAAa,CAAC,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IAC9F,SAAS,CAAC,IAAI,CAAC,GAAG,EAAE,aAAa,CAAC,EAAE,KAAK,CAAC,CAAC;AAC7C,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,MAAc,SAAS,EAAE;IACxD,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,aAAa,CAAC,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IAClD,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,YAAY,CAAC,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;AACnD,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,GAAc,EAAE,MAAyB,OAAO,CAAC,GAAG;IAChF,OAAO,GAAG,CAAC,WAAW,IAAI,GAAG,CAAC,MAAM,CAAC;AACvC,CAAC;AAED,MAAM,UAAU,aAAa,CAC3B,GAAc,EACd,SAA6B,EAC7B,eAAuB,EACvB,MAAyB,OAAO,CAAC,GAAG;IAEpC,OAAO,CAAC,SAAS,IAAI,GAAG,CAAC,WAAW,IAAI,GAAG,CAAC,MAAM,IAAI,eAAe,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;AAC7F,CAAC"}
@@ -0,0 +1,46 @@
1
+ /**
2
+ * The one HTTP door for every generated command.
3
+ *
4
+ * Auth policy mirrors the platform's createServiceClient: on a 401 the token
5
+ * is force-re-exchanged and the request retried EXACTLY once. 5xx is never
6
+ * retried — a POST /runs may have been admitted and billed; at-most-once is
7
+ * the CLI's promise for mutations.
8
+ *
9
+ * Non-ok responses map to ApiError carrying the platform envelope
10
+ * {error, code, details?} so output.ts can tell the 402/403 stories.
11
+ */
12
+ export declare class ApiError extends Error {
13
+ readonly status: number;
14
+ readonly code: string;
15
+ readonly details?: Record<string, unknown> | undefined;
16
+ constructor(message: string, status: number, code: string, details?: Record<string, unknown> | undefined);
17
+ }
18
+ export interface CallOptions {
19
+ method: string;
20
+ path: string;
21
+ query?: Record<string, string | number | boolean | undefined>;
22
+ body?: unknown;
23
+ }
24
+ /** The narrow auth port — both members required so a fake-retry can't hide. */
25
+ export interface TokenSource {
26
+ getToken(): Promise<string>;
27
+ forceRefresh(): Promise<string>;
28
+ }
29
+ export interface HttpClientDeps {
30
+ apiUrl: string;
31
+ auth: TokenSource;
32
+ fetchFn?: typeof fetch;
33
+ }
34
+ export declare class HttpClient {
35
+ private readonly apiUrl;
36
+ private readonly auth;
37
+ private readonly fetchFn;
38
+ constructor(deps: HttpClientDeps);
39
+ /** JSON operations: parsed body (null when empty), ApiError on non-ok. */
40
+ call(opts: CallOptions): Promise<unknown>;
41
+ /** Stream operations: the raw ok Response, for core/sse.ts to consume. */
42
+ open(opts: CallOptions): Promise<Response>;
43
+ private url;
44
+ private send;
45
+ }
46
+ //# sourceMappingURL=http.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../../src/core/http.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,qBAAa,QAAS,SAAQ,KAAK;IAG/B,QAAQ,CAAC,MAAM,EAAE,MAAM;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM;IACrB,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;gBAH1C,OAAO,EAAE,MAAM,EACN,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,YAAA;CAK7C;AAED,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,SAAS,CAAC,CAAC;IAC9D,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED,+EAA+E;AAC/E,MAAM,WAAW,WAAW;IAC1B,QAAQ,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;IAC5B,YAAY,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;CACjC;AAED,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,WAAW,CAAC;IAClB,OAAO,CAAC,EAAE,OAAO,KAAK,CAAC;CACxB;AAED,qBAAa,UAAU;IACrB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAc;IACnC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAe;gBAE3B,IAAI,EAAE,cAAc;IAMhC,0EAA0E;IACpE,IAAI,CAAC,IAAI,EAAE,WAAW,GAAG,OAAO,CAAC,OAAO,CAAC;IAW/C,0EAA0E;IACpE,IAAI,CAAC,IAAI,EAAE,WAAW,GAAG,OAAO,CAAC,QAAQ,CAAC;IAIhD,OAAO,CAAC,GAAG;YAQG,IAAI;CAmBnB"}