@vextlabs/theron-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 (111) hide show
  1. package/LICENSE +15 -0
  2. package/LICENSE.txt +190 -0
  3. package/README.md +98 -0
  4. package/bin/theron +22 -0
  5. package/bin/theron.js +25 -0
  6. package/dist/api.d.ts +111 -0
  7. package/dist/api.js +328 -0
  8. package/dist/api.js.map +1 -0
  9. package/dist/auth.d.ts +15 -0
  10. package/dist/auth.js +92 -0
  11. package/dist/auth.js.map +1 -0
  12. package/dist/banner.d.ts +29 -0
  13. package/dist/banner.js +191 -0
  14. package/dist/banner.js.map +1 -0
  15. package/dist/cap_config.d.ts +28 -0
  16. package/dist/cap_config.js +83 -0
  17. package/dist/cap_config.js.map +1 -0
  18. package/dist/config.d.ts +18 -0
  19. package/dist/config.js +65 -0
  20. package/dist/config.js.map +1 -0
  21. package/dist/connections.d.ts +3 -0
  22. package/dist/connections.js +105 -0
  23. package/dist/connections.js.map +1 -0
  24. package/dist/import_claude.d.ts +3 -0
  25. package/dist/import_claude.js +268 -0
  26. package/dist/import_claude.js.map +1 -0
  27. package/dist/index.d.ts +1 -0
  28. package/dist/index.js +237 -0
  29. package/dist/index.js.map +1 -0
  30. package/dist/onboard.d.ts +3 -0
  31. package/dist/onboard.js +234 -0
  32. package/dist/onboard.js.map +1 -0
  33. package/dist/profile_match.d.ts +15 -0
  34. package/dist/profile_match.js +107 -0
  35. package/dist/profile_match.js.map +1 -0
  36. package/dist/profiles/index.d.ts +20 -0
  37. package/dist/profiles/index.js +56 -0
  38. package/dist/profiles/index.js.map +1 -0
  39. package/dist/profiles/seeds.d.ts +4 -0
  40. package/dist/profiles/seeds.js +500 -0
  41. package/dist/profiles/seeds.js.map +1 -0
  42. package/dist/profiles/types.d.ts +35 -0
  43. package/dist/profiles/types.js +18 -0
  44. package/dist/profiles/types.js.map +1 -0
  45. package/dist/render.d.ts +18 -0
  46. package/dist/render.js +82 -0
  47. package/dist/render.js.map +1 -0
  48. package/dist/repl.d.ts +13 -0
  49. package/dist/repl.js +821 -0
  50. package/dist/repl.js.map +1 -0
  51. package/dist/streaming.d.ts +28 -0
  52. package/dist/streaming.js +118 -0
  53. package/dist/streaming.js.map +1 -0
  54. package/dist/tools/bash.d.ts +8 -0
  55. package/dist/tools/bash.js +57 -0
  56. package/dist/tools/bash.js.map +1 -0
  57. package/dist/tools/edit.d.ts +9 -0
  58. package/dist/tools/edit.js +42 -0
  59. package/dist/tools/edit.js.map +1 -0
  60. package/dist/tools/glob.d.ts +7 -0
  61. package/dist/tools/glob.js +40 -0
  62. package/dist/tools/glob.js.map +1 -0
  63. package/dist/tools/grep.d.ts +9 -0
  64. package/dist/tools/grep.js +73 -0
  65. package/dist/tools/grep.js.map +1 -0
  66. package/dist/tools/index.d.ts +31 -0
  67. package/dist/tools/index.js +180 -0
  68. package/dist/tools/index.js.map +1 -0
  69. package/dist/tools/ls.d.ts +6 -0
  70. package/dist/tools/ls.js +25 -0
  71. package/dist/tools/ls.js.map +1 -0
  72. package/dist/tools/read.d.ts +8 -0
  73. package/dist/tools/read.js +43 -0
  74. package/dist/tools/read.js.map +1 -0
  75. package/dist/tools/stoa.d.ts +34 -0
  76. package/dist/tools/stoa.js +103 -0
  77. package/dist/tools/stoa.js.map +1 -0
  78. package/dist/tools/write.d.ts +7 -0
  79. package/dist/tools/write.js +15 -0
  80. package/dist/tools/write.js.map +1 -0
  81. package/dist/verifiers/ai_ism_check.d.ts +2 -0
  82. package/dist/verifiers/ai_ism_check.js +48 -0
  83. package/dist/verifiers/ai_ism_check.js.map +1 -0
  84. package/dist/verifiers/arithmetic_recheck.d.ts +2 -0
  85. package/dist/verifiers/arithmetic_recheck.js +74 -0
  86. package/dist/verifiers/arithmetic_recheck.js.map +1 -0
  87. package/dist/verifiers/citation_presence.d.ts +2 -0
  88. package/dist/verifiers/citation_presence.js +42 -0
  89. package/dist/verifiers/citation_presence.js.map +1 -0
  90. package/dist/verifiers/em_dash_check.d.ts +2 -0
  91. package/dist/verifiers/em_dash_check.js +23 -0
  92. package/dist/verifiers/em_dash_check.js.map +1 -0
  93. package/dist/verifiers/index.d.ts +16 -0
  94. package/dist/verifiers/index.js +123 -0
  95. package/dist/verifiers/index.js.map +1 -0
  96. package/dist/verifiers/lint.d.ts +2 -0
  97. package/dist/verifiers/lint.js +90 -0
  98. package/dist/verifiers/lint.js.map +1 -0
  99. package/dist/verifiers/style_lint.d.ts +2 -0
  100. package/dist/verifiers/style_lint.js +115 -0
  101. package/dist/verifiers/style_lint.js.map +1 -0
  102. package/dist/verifiers/test_smoke.d.ts +2 -0
  103. package/dist/verifiers/test_smoke.js +94 -0
  104. package/dist/verifiers/test_smoke.js.map +1 -0
  105. package/dist/verifiers/typecheck.d.ts +2 -0
  106. package/dist/verifiers/typecheck.js +98 -0
  107. package/dist/verifiers/typecheck.js.map +1 -0
  108. package/dist/verifiers/types.d.ts +33 -0
  109. package/dist/verifiers/types.js +23 -0
  110. package/dist/verifiers/types.js.map +1 -0
  111. package/package.json +60 -0
package/dist/api.js ADDED
@@ -0,0 +1,328 @@
1
+ // API client — talks to /api/cli/chat (the new tool-loop-aware endpoint
2
+ // we'll add to marketing/api/). Uses streaming JSON-NDJSON so we can
3
+ // emit text deltas as they arrive AND surface tool_call frames cleanly.
4
+ //
5
+ // Wire format (one JSON object per line):
6
+ // { "type": "text_delta", "delta": "..." }
7
+ // { "type": "tool_call", "id": "tc_...", "name": "Read", "args": {...} }
8
+ // { "type": "turn_end", "stop_reason": "tool_use" | "end_turn" | "max_tokens" }
9
+ // { "type": "error", "message": "..." }
10
+ //
11
+ // We chose NDJSON over OpenAI's SSE delta shape because it's easier to
12
+ // stream to a local CLI (no event:/data: parsing) and lets us send
13
+ // typed tool_calls in a single coherent frame.
14
+ /** POSTs /api/theron/plan. Returns null on any failure so the REPL
15
+ * never blocks on the classifier — chat starts streaming regardless. */
16
+ export async function fetchInteractionPlan(opts) {
17
+ const url = opts.apiUrl.replace(/\/$/, "") + "/api/theron/plan";
18
+ try {
19
+ const r = await fetch(url, {
20
+ method: "POST",
21
+ signal: opts.signal,
22
+ headers: { "content-type": "application/json" },
23
+ body: JSON.stringify({
24
+ prompt: opts.prompt,
25
+ history: opts.history,
26
+ surface: "cli",
27
+ }),
28
+ });
29
+ if (!r.ok)
30
+ return null;
31
+ const data = (await r.json());
32
+ if (!data || typeof data.intent !== "string")
33
+ return null;
34
+ return data;
35
+ }
36
+ catch {
37
+ return null;
38
+ }
39
+ }
40
+ // Failure-mode constants. Tuned for: fetch timeout > model thinking
41
+ // time (so we don't kill long reasoning); retry budget > transient
42
+ // 429s but not so aggressive we hammer rate limits.
43
+ const FETCH_CONNECT_TIMEOUT_MS = 30_000; // connect / first byte
44
+ const FETCH_TOTAL_TIMEOUT_MS = 300_000; // 5 min total stream
45
+ const RETRY_STATUSES = new Set([408, 429, 500, 502, 503, 504]);
46
+ const MAX_RETRIES = 3;
47
+ /** Sleep ms with abort support. */
48
+ function sleep(ms, signal) {
49
+ return new Promise((resolve, reject) => {
50
+ if (signal?.aborted)
51
+ return reject(new Error("aborted"));
52
+ const t = setTimeout(resolve, ms);
53
+ signal?.addEventListener("abort", () => { clearTimeout(t); reject(new Error("aborted")); });
54
+ });
55
+ }
56
+ /** POSTs /api/cli/chat and parses NDJSON deltas. Returns when the
57
+ * stream closes (normally on turn_end).
58
+ *
59
+ * Hardened (2026-05-10):
60
+ * - Retries automatically on 429 / 5xx with exponential backoff
61
+ * (1s → 2s → 4s, max 3 retries). Surfaces "rate limited, retrying
62
+ * in Ns…" via onError so the user sees what's happening.
63
+ * - 30s connect timeout + 5min total stream timeout. After timeout
64
+ * we surface a friendly error rather than hanging.
65
+ * - Network errors (ECONNRESET, fetch failures) get a single
66
+ * reconnect attempt before bailing.
67
+ * - Ignored partial NDJSON frames at stream-end (some upstreams
68
+ * flush a half-line on close; previously this logged a noisy
69
+ * "skipped malformed NDJSON" warning every turn). */
70
+ /** Thrown by getJson on a non-2xx response. Carries the HTTP status so
71
+ * callers can branch (e.g. 401 -> prompt re-auth). */
72
+ export class ApiError extends Error {
73
+ status;
74
+ body;
75
+ constructor(status, message, body) {
76
+ super(message);
77
+ this.name = "ApiError";
78
+ this.status = status;
79
+ this.body = body;
80
+ }
81
+ }
82
+ /** Minimal GET helper for non-streaming JSON endpoints (version probe,
83
+ * workspace list/get). Mirrors streamChat's apiUrl + Bearer convention. */
84
+ export async function getJson(path, opts) {
85
+ const base = opts.apiUrl.replace(/\/$/, "");
86
+ const url = base + (path.startsWith("/") ? path : `/${path}`);
87
+ const headers = { accept: "application/json" };
88
+ if (opts.apiKey)
89
+ headers.authorization = `Bearer ${opts.apiKey}`;
90
+ for (let attempt = 0; attempt < 2; attempt++) {
91
+ try {
92
+ const r = await fetch(url, { method: "GET", headers });
93
+ const ct = r.headers.get("content-type") || "";
94
+ const body = ct.includes("application/json")
95
+ ? await r.json().catch(() => null)
96
+ : await r.text().catch(() => null);
97
+ if (!r.ok) {
98
+ // Retry once on transient 5xx; 4xx is terminal.
99
+ if (r.status >= 500 && attempt === 0) {
100
+ opts.onRetry?.(`server ${r.status}, retrying…`);
101
+ continue;
102
+ }
103
+ const msg = body && typeof body === "object" && "error" in body && typeof body.error === "string"
104
+ ? body.error
105
+ : `HTTP ${r.status}`;
106
+ throw new ApiError(r.status, msg, body);
107
+ }
108
+ return body;
109
+ }
110
+ catch (err) {
111
+ if (err instanceof ApiError)
112
+ throw err;
113
+ if (attempt === 0) {
114
+ opts.onRetry?.(`network error, retrying…`);
115
+ continue;
116
+ }
117
+ throw err;
118
+ }
119
+ }
120
+ throw new ApiError(0, "request failed after retry");
121
+ }
122
+ export async function streamChat(req, h) {
123
+ const url = req.apiUrl.replace(/\/$/, "") + "/api/cli/chat";
124
+ let attempt = 0;
125
+ while (attempt <= MAX_RETRIES) {
126
+ attempt += 1;
127
+ // Per-attempt abort — chains through caller's signal + a connect
128
+ // timeout. Clears after first byte; total-stream timeout caps the
129
+ // whole thing.
130
+ const ctl = new AbortController();
131
+ const onCallerAbort = () => ctl.abort();
132
+ req.signal?.addEventListener("abort", onCallerAbort);
133
+ const connectTimer = setTimeout(() => ctl.abort(), FETCH_CONNECT_TIMEOUT_MS);
134
+ const totalTimer = setTimeout(() => ctl.abort(), FETCH_TOTAL_TIMEOUT_MS);
135
+ let r;
136
+ try {
137
+ r = await fetch(url, {
138
+ method: "POST",
139
+ headers: {
140
+ "content-type": "application/json",
141
+ ...(req.apiKey ? { authorization: `Bearer ${req.apiKey}` } : {}),
142
+ accept: "application/x-ndjson",
143
+ },
144
+ body: JSON.stringify({
145
+ messages: req.messages,
146
+ tools: req.tools,
147
+ surface: "cli",
148
+ profile: req.profile,
149
+ }),
150
+ signal: ctl.signal,
151
+ });
152
+ clearTimeout(connectTimer);
153
+ }
154
+ catch (err) {
155
+ clearTimeout(connectTimer);
156
+ clearTimeout(totalTimer);
157
+ req.signal?.removeEventListener("abort", onCallerAbort);
158
+ const aborted = req.signal?.aborted ?? false;
159
+ if (aborted) {
160
+ h.onError("canceled");
161
+ return;
162
+ }
163
+ if (attempt <= MAX_RETRIES) {
164
+ const wait = 1000 * Math.pow(2, attempt - 1);
165
+ h.onError(`network error (${err instanceof Error ? err.message : String(err)}) — retrying in ${wait / 1000}s…`);
166
+ try {
167
+ await sleep(wait, req.signal);
168
+ }
169
+ catch {
170
+ return;
171
+ }
172
+ continue;
173
+ }
174
+ h.onError(`network error after ${MAX_RETRIES} retries: ${err instanceof Error ? err.message : String(err)}`);
175
+ return;
176
+ }
177
+ if (!r.ok || !r.body) {
178
+ let detail = "";
179
+ try {
180
+ detail = (await r.text()).slice(0, 500);
181
+ }
182
+ catch { /* ignore */ }
183
+ clearTimeout(totalTimer);
184
+ req.signal?.removeEventListener("abort", onCallerAbort);
185
+ // Retry on transient statuses with exponential backoff.
186
+ if (RETRY_STATUSES.has(r.status) && attempt <= MAX_RETRIES) {
187
+ const wait = 1000 * Math.pow(2, attempt - 1);
188
+ const reason = r.status === 429 ? "rate limited" : `HTTP ${r.status}`;
189
+ h.onError(`${reason} — retrying in ${wait / 1000}s…`);
190
+ try {
191
+ await sleep(wait, req.signal);
192
+ }
193
+ catch {
194
+ return;
195
+ }
196
+ continue;
197
+ }
198
+ // Friendlier 401 / 403 messaging — auth issue, not infra.
199
+ if (r.status === 401 || r.status === 403) {
200
+ h.onError(`HTTP ${r.status}: not authorized. Run \`theron login\` or check your API key.`);
201
+ }
202
+ else {
203
+ h.onError(`HTTP ${r.status}: ${detail || "no response body"}`);
204
+ }
205
+ return;
206
+ }
207
+ // Stream consumed successfully — read NDJSON line-by-line.
208
+ const reader = r.body.getReader();
209
+ const decoder = new TextDecoder();
210
+ let buf = "";
211
+ try {
212
+ while (true) {
213
+ const { done, value } = await reader.read();
214
+ if (done) {
215
+ // Surface any trailing JSON line (some servers don't flush
216
+ // a final newline). Tolerate parse failure quietly here —
217
+ // the previous noisy warning fired every turn on partial
218
+ // chunks.
219
+ const tail = buf.trim();
220
+ if (tail) {
221
+ try {
222
+ const frame = JSON.parse(tail);
223
+ dispatchFrame(frame, h);
224
+ }
225
+ catch { /* end-of-stream partial — ignore */ }
226
+ }
227
+ break;
228
+ }
229
+ buf += decoder.decode(value, { stream: true });
230
+ let idx;
231
+ while ((idx = buf.indexOf("\n")) >= 0) {
232
+ const line = buf.slice(0, idx).trim();
233
+ buf = buf.slice(idx + 1);
234
+ if (!line)
235
+ continue;
236
+ try {
237
+ dispatchFrame(JSON.parse(line), h);
238
+ }
239
+ catch {
240
+ // Mid-stream malformed line — skip silently. Server can
241
+ // hiccup; we'd rather lose one frame than spam stderr.
242
+ }
243
+ }
244
+ }
245
+ }
246
+ catch (err) {
247
+ // Stream interrupted. Most common cause: timeout fired on a
248
+ // genuinely-long generation. Surface the cause + don't retry —
249
+ // the model already produced partial output, retrying would
250
+ // duplicate it.
251
+ const aborted = req.signal?.aborted ?? false;
252
+ if (aborted) {
253
+ h.onError("canceled");
254
+ }
255
+ else {
256
+ h.onError(`stream interrupted: ${err instanceof Error ? err.message : String(err)}`);
257
+ }
258
+ }
259
+ finally {
260
+ clearTimeout(totalTimer);
261
+ req.signal?.removeEventListener("abort", onCallerAbort);
262
+ }
263
+ return;
264
+ }
265
+ }
266
+ /** Apply one parsed NDJSON frame to the handler set. */
267
+ /** Normalize tool-call args. The current substrate (DeepSeek-V3.2 via
268
+ * OpenRouter) intermittently emits arguments as a JSON *string* (single
269
+ * or double-encoded) and leaks special tokens like
270
+ * `<|tool_call_argument_begin|>` into the payload. Left unhandled, every
271
+ * tool sees `undefined` for its required args and the agent loop stalls.
272
+ * This coerces any shape into a plain object so Read/Glob/Grep/Edit work. */
273
+ export function normalizeToolArgs(raw) {
274
+ if (raw && typeof raw === "object" && !Array.isArray(raw)) {
275
+ return raw;
276
+ }
277
+ if (typeof raw === "string") {
278
+ // Strip model special tokens (<|...|>) and any `functions.Name:1` prefix.
279
+ let s = raw.replace(/<\|[^|]*\|>/g, "").replace(/^\s*functions\.[A-Za-z_]+:\d+\s*/g, "").trim();
280
+ // Unwrap up to two layers of JSON encoding.
281
+ for (let i = 0; i < 2; i++) {
282
+ try {
283
+ const parsed = JSON.parse(s);
284
+ if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
285
+ return parsed;
286
+ }
287
+ if (typeof parsed === "string") {
288
+ s = parsed;
289
+ continue;
290
+ }
291
+ }
292
+ catch {
293
+ break;
294
+ }
295
+ }
296
+ // Last resort: pull the first {...} block out of contaminated text.
297
+ const m = s.match(/\{[\s\S]*\}/);
298
+ if (m) {
299
+ try {
300
+ const obj = JSON.parse(m[0]);
301
+ if (obj && typeof obj === "object" && !Array.isArray(obj)) {
302
+ return obj;
303
+ }
304
+ }
305
+ catch { /* give up */ }
306
+ }
307
+ }
308
+ return {};
309
+ }
310
+ /** Strip a leaked `functions.` prefix / `:N` suffix off a tool name. */
311
+ function normalizeToolName(name) {
312
+ const s = typeof name === "string" ? name : "";
313
+ return s.replace(/<\|[^|]*\|>/g, "").replace(/^functions\./, "").replace(/:\d+$/, "").trim();
314
+ }
315
+ function dispatchFrame(frame, h) {
316
+ const f = frame;
317
+ if (f && typeof f === "object" && "type" in f) {
318
+ if (f.type === "text_delta")
319
+ h.onTextDelta(f.delta);
320
+ else if (f.type === "tool_call")
321
+ h.onToolCall({ id: f.id, name: normalizeToolName(f.name), args: normalizeToolArgs(f.args) });
322
+ else if (f.type === "turn_end")
323
+ h.onTurnEnd(f.stop_reason);
324
+ else if (f.type === "error")
325
+ h.onError(f.message);
326
+ }
327
+ }
328
+ //# sourceMappingURL=api.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api.js","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"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"}
package/dist/auth.d.ts ADDED
@@ -0,0 +1,15 @@
1
+ export interface Credentials {
2
+ api_key?: string;
3
+ /** Override the API base URL — defaults to https://theron.tryvext.com */
4
+ api_url?: string;
5
+ /** Last-known username for greeting. */
6
+ email?: string;
7
+ }
8
+ export declare function loadCredentials(): Promise<Credentials>;
9
+ export declare function saveCredentials(creds: Credentials): Promise<void>;
10
+ /** Path to the credentials file — exposed so other commands can clear
11
+ * it consistently (REPL `/logout`, etc.) without rebuilding the path. */
12
+ export declare function credentialsPath(): string;
13
+ /** Interactive `theron login` flow. */
14
+ export declare function loginCommand(): Promise<number>;
15
+ export declare function logoutCommand(): Promise<number>;
package/dist/auth.js ADDED
@@ -0,0 +1,92 @@
1
+ // Auth — stores the user's API key in ~/.theron/credentials so the
2
+ // CLI doesn't need it on the command line every invocation.
3
+ //
4
+ // Resolution order (collapsed by loadCredentials, then --api-key beats
5
+ // it inside index.ts):
6
+ // 1. --api-key CLI flag (handled by main, not here)
7
+ // 2. THERON_API_KEY env var
8
+ // 3. ~/.theron/credentials JSON
9
+ // Run `theron login` to set option 3 interactively.
10
+ //
11
+ // Storage is a flat 0600 file with 0700 dir, which gates against
12
+ // other-user reads on a multi-user box. macOS Keychain / Windows
13
+ // Credential Manager / freedesktop Secret Service are on the roadmap;
14
+ // see OPEN_QUESTIONS in the audit.
15
+ import { promises as fs } from "node:fs";
16
+ import os from "node:os";
17
+ import path from "node:path";
18
+ import readline from "node:readline";
19
+ const CRED_DIR = path.join(os.homedir(), ".theron");
20
+ const CRED_FILE = path.join(CRED_DIR, "credentials");
21
+ export async function loadCredentials() {
22
+ // Env wins over file.
23
+ const envKey = process.env.THERON_API_KEY;
24
+ const envUrl = process.env.THERON_API_URL;
25
+ let fileCreds = {};
26
+ try {
27
+ const raw = await fs.readFile(CRED_FILE, "utf-8");
28
+ fileCreds = JSON.parse(raw);
29
+ }
30
+ catch { /* file not present — that's fine */ }
31
+ return {
32
+ api_key: envKey ?? fileCreds.api_key,
33
+ api_url: envUrl ?? fileCreds.api_url ?? "https://theron.tryvext.com",
34
+ email: fileCreds.email,
35
+ };
36
+ }
37
+ export async function saveCredentials(creds) {
38
+ // 0700 dir + 0600 file: only the owner can read or write the key.
39
+ // chmod() runs after writeFile in case the file already existed
40
+ // with looser perms (writeFile honors `mode` only on create).
41
+ await fs.mkdir(CRED_DIR, { recursive: true, mode: 0o700 });
42
+ await fs.writeFile(CRED_FILE, JSON.stringify(creds, null, 2), { mode: 0o600 });
43
+ try {
44
+ await fs.chmod(CRED_FILE, 0o600);
45
+ }
46
+ catch { /* best effort */ }
47
+ try {
48
+ await fs.chmod(CRED_DIR, 0o700);
49
+ }
50
+ catch { /* best effort */ }
51
+ }
52
+ /** Path to the credentials file — exposed so other commands can clear
53
+ * it consistently (REPL `/logout`, etc.) without rebuilding the path. */
54
+ export function credentialsPath() {
55
+ return CRED_FILE;
56
+ }
57
+ /** Interactive `theron login` flow. */
58
+ export async function loginCommand() {
59
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
60
+ const ask = (q) => new Promise((resolve) => rl.question(q, resolve));
61
+ console.log("\nTheron — Vext Labs CLI login\n");
62
+ console.log("Get your API key at https://theron.tryvext.com/settings/api-keys\n");
63
+ const apiKey = (await ask("API key: ")).trim();
64
+ const apiUrl = (await ask("API URL [https://theron.tryvext.com]: ")).trim() || undefined;
65
+ const email = (await ask("Email (for greeting, optional): ")).trim() || undefined;
66
+ rl.close();
67
+ if (!apiKey) {
68
+ console.error("No API key entered. Aborting.");
69
+ return 1;
70
+ }
71
+ await saveCredentials({ api_key: apiKey, api_url: apiUrl, email });
72
+ console.log(`\nSaved to ${CRED_FILE} (mode 0600)`);
73
+ return 0;
74
+ }
75
+ export async function logoutCommand() {
76
+ try {
77
+ await fs.unlink(CRED_FILE);
78
+ console.log(`Removed ${CRED_FILE}`);
79
+ }
80
+ catch (err) {
81
+ const code = err.code;
82
+ if (code === "ENOENT") {
83
+ console.log("Not logged in.");
84
+ }
85
+ else {
86
+ console.error(`Failed to remove credentials: ${err instanceof Error ? err.message : String(err)}`);
87
+ return 1;
88
+ }
89
+ }
90
+ return 0;
91
+ }
92
+ //# sourceMappingURL=auth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.js","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ /** Render the THERON banner as a string of ANSI-colored block letters. */
2
+ export declare function bannerTheron(): string;
3
+ /** Tiny rounded-box drawing — same shape as Claude Code's "Welcome to
4
+ * Claude Code research preview!" pill. Single-line content, amber
5
+ * border, leading * marker. */
6
+ export declare function welcomePill(text: string): string;
7
+ export interface IntroNote {
8
+ title: string;
9
+ body: string[];
10
+ }
11
+ export declare function renderNotes(notes: IntroNote[]): string;
12
+ export declare function sampleSuggestion(): string;
13
+ export interface StatusLine {
14
+ cwd: string;
15
+ apiUrl: string;
16
+ loggedIn: boolean;
17
+ yolo: boolean;
18
+ model?: string;
19
+ /** Active profile label (e.g. "Code", "Legal"). Surfaces what
20
+ * domain mode the REPL is in so the user always sees the active
21
+ * voice + verifier set. */
22
+ profileLabel?: string;
23
+ }
24
+ export declare function renderStatus(s: StatusLine): string;
25
+ export declare const SLASH_COMMANDS: Array<{
26
+ trigger: string;
27
+ desc: string;
28
+ }>;
29
+ export declare function renderSlashHelp(): string;