krexel 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.
package/dist/init.d.ts ADDED
@@ -0,0 +1,103 @@
1
+ /**
2
+ * init.ts — `krexel init`
3
+ *
4
+ * One-command installer for the Krexel MCP server. Orchestrates:
5
+ * 1. Prerequisite check (Node version, OS detection)
6
+ * 2. MCP server binary resolution (npm global OR monorepo dev path)
7
+ * 3. Master-key mint + persist to ~/.zshrc (and ~/.bashrc if present)
8
+ * 4. Patch every AI client's config (skip silently when absent)
9
+ * 5. Run the OAuth login flow via `runLogin()`
10
+ * 6. Print an animated "you're set up" checklist
11
+ *
12
+ * Hard rule: a single bad client config must NOT abort the run. Each
13
+ * patcher is wrapped in try/catch; failures are surfaced via `warn()`
14
+ * and the next one is attempted.
15
+ */
16
+ import { type ClientSpec } from "./paths.js";
17
+ import { type MasterKeyResult, type PatchResult } from "./config-patchers.js";
18
+ /** Options the orchestrator respects (matches the CLI flags). */
19
+ export interface InitOptions {
20
+ /** Don't write to disk — print the diffs and exit. */
21
+ dryRun?: boolean;
22
+ /** Skip the OAuth login step (for CI / scripted installs). */
23
+ skipLogin?: boolean;
24
+ /** Reuse a known master key instead of minting a fresh one. */
25
+ masterKey?: string;
26
+ /** Override the resolved MCP server binary command. */
27
+ binaryCommand?: string;
28
+ /** Override the resolved MCP server binary args. */
29
+ binaryArgs?: string[];
30
+ /** Override the API URL injected into the entry env. */
31
+ apiUrl?: string;
32
+ /** For tests: skip the actual `runLogin` (still mints the master key). */
33
+ loginRunner?: () => Promise<void>;
34
+ }
35
+ /** Where the MCP server lives on disk. */
36
+ export interface BinaryResolution {
37
+ command: string;
38
+ args: string[];
39
+ /** True if we found the dev binary in the monorepo. */
40
+ fromDev: boolean;
41
+ }
42
+ /**
43
+ * Detect the Node version on PATH and assert >= 20. Throws with a
44
+ * clean message if too old.
45
+ */
46
+ export declare function assertNodeVersion(): {
47
+ major: number;
48
+ raw: string;
49
+ };
50
+ /**
51
+ * Find the MCP server binary. Resolution order:
52
+ * 1. Caller override (init option).
53
+ * 2. Dev mode: if `~/krexel/mcp-server/dist/index.js` exists AND we're
54
+ * inside the monorepo, return that path with a node shebang.
55
+ * 3. Production: assume `krexel-mcp` is on $PATH (npm install -g).
56
+ *
57
+ * If we can't satisfy either, throw with a clear install hint.
58
+ */
59
+ export declare function resolveMcpBinary(opts?: InitOptions): Promise<BinaryResolution>;
60
+ /**
61
+ * Mint a fresh 64-hex-char master key, persist it to the user's shell rc,
62
+ * and return the persisted value + which files were touched.
63
+ *
64
+ * Set on both ~/.zshrc AND ~/.bashrc (when one or both exist) so users
65
+ * who switch shells between login sessions don't lose the key.
66
+ */
67
+ export declare function initMasterKey(opts?: InitOptions): Promise<MasterKeyResult>;
68
+ /**
69
+ * Patch every client config on disk. Returns one PatchResult per client
70
+ * in the same order as `resolveAll()`. Failures become `{ ok: false }`
71
+ * entries — the caller decides how to render them.
72
+ */
73
+ export interface PatchRow {
74
+ spec: ClientSpec;
75
+ ok: boolean;
76
+ result?: PatchResult;
77
+ error?: string;
78
+ }
79
+ export declare function patchAllClients(binary: BinaryResolution, env: Record<string, string>, opts?: InitOptions): Promise<PatchRow[]>;
80
+ /**
81
+ * Render the "you're set up" checklist. Public so tests can assert shape.
82
+ */
83
+ export type ChecklistItem = {
84
+ kind: "ok";
85
+ text: string;
86
+ } | {
87
+ kind: "warn";
88
+ text: string;
89
+ };
90
+ export declare function renderChecklist(args: {
91
+ version: string;
92
+ masterKey: MasterKeyResult;
93
+ rows: PatchRow[];
94
+ oauthDone: boolean;
95
+ apiUrl: string;
96
+ }): ChecklistItem[];
97
+ /**
98
+ * The main entry point wired into the CLI.
99
+ *
100
+ * Each phase's failure is non-fatal when possible. Truly fatal errors
101
+ * (no MCP server, no Node 20+) raise via `error()` and exit.
102
+ */
103
+ export declare function runInit(opts?: InitOptions): Promise<void>;
package/dist/init.js ADDED
@@ -0,0 +1,312 @@
1
+ /**
2
+ * init.ts — `krexel init`
3
+ *
4
+ * One-command installer for the Krexel MCP server. Orchestrates:
5
+ * 1. Prerequisite check (Node version, OS detection)
6
+ * 2. MCP server binary resolution (npm global OR monorepo dev path)
7
+ * 3. Master-key mint + persist to ~/.zshrc (and ~/.bashrc if present)
8
+ * 4. Patch every AI client's config (skip silently when absent)
9
+ * 5. Run the OAuth login flow via `runLogin()`
10
+ * 6. Print an animated "you're set up" checklist
11
+ *
12
+ * Hard rule: a single bad client config must NOT abort the run. Each
13
+ * patcher is wrapped in try/catch; failures are surfaced via `warn()`
14
+ * and the next one is attempted.
15
+ */
16
+ import { randomBytes } from "node:crypto";
17
+ import { existsSync, readFileSync } from "node:fs";
18
+ import * as os from "node:os";
19
+ import * as path from "node:path";
20
+ import { runLogin } from "./login.js";
21
+ import { dim, error, isJsonMode, success, warn } from "./output.js";
22
+ import { resolveAll, effectiveHome, effectivePlatform, } from "./paths.js";
23
+ import { patchJsonConfig, patchTomlConfig, persistMasterKeyToRc, maskSecret, } from "./config-patchers.js";
24
+ /**
25
+ * Detect the Node version on PATH and assert >= 20. Throws with a
26
+ * clean message if too old.
27
+ */
28
+ export function assertNodeVersion() {
29
+ // process.version is "vX.Y.Z" — strip the leading v.
30
+ const raw = process.version.replace(/^v/, "");
31
+ const majorStr = raw.split(".")[0] ?? "0";
32
+ const major = Number.parseInt(majorStr, 10);
33
+ if (!Number.isFinite(major) || major < 20) {
34
+ error(`Krexel init requires Node 20 or newer. You have Node ${raw}. ` +
35
+ `Install a newer Node from https://nodejs.org/ or via nvm, then re-run \`krexel init\`.`);
36
+ }
37
+ return { major, raw };
38
+ }
39
+ /**
40
+ * Find the MCP server binary. Resolution order:
41
+ * 1. Caller override (init option).
42
+ * 2. Dev mode: if `~/krexel/mcp-server/dist/index.js` exists AND we're
43
+ * inside the monorepo, return that path with a node shebang.
44
+ * 3. Production: assume `krexel-mcp` is on $PATH (npm install -g).
45
+ *
46
+ * If we can't satisfy either, throw with a clear install hint.
47
+ */
48
+ export async function resolveMcpBinary(opts = {}) {
49
+ if (opts.binaryCommand) {
50
+ return {
51
+ command: opts.binaryCommand,
52
+ args: opts.binaryArgs ?? [],
53
+ fromDev: false,
54
+ };
55
+ }
56
+ // Dev path: monorepo checkout. Check BOTH the (possibly-overridden) home
57
+ // and the real os.homedir() — sandboxed smoke tests override KREXEL_HOME
58
+ // but still want to find the actual built binary.
59
+ const effHome = effectiveHome();
60
+ const realHome = os.homedir();
61
+ const devCandidates = [
62
+ path.join(effHome, "krexel", "mcp-server", "dist", "index.js"),
63
+ path.join(realHome, "krexel", "mcp-server", "dist", "index.js"),
64
+ // Allow override via env for unusual layouts.
65
+ process.env.KREXEL_MCP_DEV_PATH,
66
+ ].filter((p) => typeof p === "string");
67
+ for (const candidate of devCandidates) {
68
+ if (existsSync(candidate)) {
69
+ return { command: process.execPath, args: [candidate], fromDev: true };
70
+ }
71
+ }
72
+ // Production: look for `krexel-mcp` on PATH.
73
+ if (binaryOnPath("krexel-mcp")) {
74
+ return { command: "krexel-mcp", args: [], fromDev: false };
75
+ }
76
+ error("Could not find the Krexel MCP server binary. Either:\n" +
77
+ " • Run `npm install -g krexel-mcp` to fetch it from npm, OR\n" +
78
+ " • Build the dev version: `cd ~/krexel/mcp-server && npm run build`");
79
+ }
80
+ /** Best-effort PATH check. */
81
+ function binaryOnPath(name) {
82
+ const pathEnv = process.env.PATH ?? "";
83
+ const sep = process.platform === "win32" ? ";" : ":";
84
+ for (const dir of pathEnv.split(sep)) {
85
+ if (!dir)
86
+ continue;
87
+ const candidate = path.join(dir, name + (process.platform === "win32" ? ".cmd" : ""));
88
+ if (existsSync(candidate))
89
+ return true;
90
+ }
91
+ return false;
92
+ }
93
+ /**
94
+ * Mint a fresh 64-hex-char master key, persist it to the user's shell rc,
95
+ * and return the persisted value + which files were touched.
96
+ *
97
+ * Set on both ~/.zshrc AND ~/.bashrc (when one or both exist) so users
98
+ * who switch shells between login sessions don't lose the key.
99
+ */
100
+ export async function initMasterKey(opts = {}) {
101
+ const platform = effectivePlatform();
102
+ const home = effectiveHome();
103
+ const wantedValue = opts.masterKey ?? randomBytes(32).toString("hex");
104
+ // Decide which files to touch. zshrc is mandatory if it exists or we're
105
+ // on darwin. bashrc is best-effort on linux.
106
+ const files = [];
107
+ let minted = false;
108
+ // The resolved key — may be the freshly minted value OR a pre-existing
109
+ // one pulled from one of the rc files. We surface whichever was actually
110
+ // on disk last.
111
+ let resolved = wantedValue;
112
+ const zshrc = path.join(home, ".zshrc");
113
+ const bashrc = path.join(home, ".bashrc");
114
+ if (existsSync(zshrc) || platform === "darwin") {
115
+ const res = await persistMasterKeyToRc(zshrc, wantedValue);
116
+ files.push(zshrc);
117
+ if (res.written)
118
+ minted = true;
119
+ resolved = res.value;
120
+ }
121
+ if (existsSync(bashrc) && platform !== "darwin") {
122
+ const res = await persistMasterKeyToRc(bashrc, wantedValue);
123
+ files.push(bashrc);
124
+ if (res.written)
125
+ minted = true;
126
+ // If bashrc has a different key than zshrc, prefer the FIRST file's
127
+ // value — we trust the order zshrc → bashrc.
128
+ if (resolved === wantedValue) {
129
+ resolved = res.value;
130
+ }
131
+ }
132
+ return { value: resolved, files, minted };
133
+ }
134
+ export async function patchAllClients(binary, env, opts = {}) {
135
+ const all = resolveAll();
136
+ const home = effectiveHome();
137
+ const rows = [];
138
+ for (const spec of all) {
139
+ if (!spec.configPath)
140
+ continue;
141
+ const present = existsSync(spec.configPath);
142
+ if (!present) {
143
+ // Skip silently — spec.label gets rendered with "(absent)" note.
144
+ rows.push({ spec: { ...spec, present: false }, ok: true });
145
+ continue;
146
+ }
147
+ rows.push({ spec: { ...spec, present: true }, ok: true });
148
+ }
149
+ // Now actually patch. We loop again so "skipped because absent" rows
150
+ // sit alongside "patched" rows in stable order.
151
+ for (let i = 0; i < rows.length; i++) {
152
+ const row = rows[i];
153
+ if (!row || !row.spec.present || !row.spec.configPath)
154
+ continue;
155
+ const input = {
156
+ filePath: row.spec.configPath,
157
+ binaryCommand: binary.command,
158
+ binaryArgs: binary.args,
159
+ env,
160
+ dryRun: Boolean(opts.dryRun),
161
+ };
162
+ try {
163
+ const result = row.spec.id === "codex"
164
+ ? await patchTomlConfig(input)
165
+ : await patchJsonConfig(input, row.spec.id);
166
+ rows[i] = { ...row, ok: true, result };
167
+ }
168
+ catch (err) {
169
+ rows[i] = {
170
+ ...row,
171
+ ok: false,
172
+ error: err instanceof Error ? err.message : String(err),
173
+ };
174
+ }
175
+ }
176
+ return rows;
177
+ }
178
+ export function renderChecklist(args) {
179
+ const items = [];
180
+ items.push({ kind: "ok", text: `Krexel v${args.version} installed` });
181
+ if (args.masterKey.files.length > 0) {
182
+ const targets = args.masterKey.files
183
+ .map((f) => path.basename(f))
184
+ .join(", ");
185
+ items.push({
186
+ kind: "ok",
187
+ text: `Master key (${maskSecret(args.masterKey.value)}) saved to ${targets}`,
188
+ });
189
+ }
190
+ else {
191
+ items.push({
192
+ kind: "ok",
193
+ text: `Master key (${maskSecret(args.masterKey.value)}) ready in env`,
194
+ });
195
+ }
196
+ for (const row of args.rows) {
197
+ if (!row.spec.present)
198
+ continue; // skip silently
199
+ if (!row.ok) {
200
+ items.push({ kind: "warn", text: `${row.spec.label}: ${row.error ?? "unknown error"}` });
201
+ continue;
202
+ }
203
+ if (!row.result) {
204
+ items.push({ kind: "warn", text: `${row.spec.label}: no result` });
205
+ continue;
206
+ }
207
+ if (!row.result.changed) {
208
+ items.push({ kind: "ok", text: `${row.spec.label}: already configured` });
209
+ }
210
+ else {
211
+ items.push({ kind: "ok", text: `Patched: ${row.spec.label}` });
212
+ }
213
+ }
214
+ if (args.oauthDone) {
215
+ items.push({ kind: "ok", text: "Cloudflare OAuth complete" });
216
+ }
217
+ return items;
218
+ }
219
+ /**
220
+ * The main entry point wired into the CLI.
221
+ *
222
+ * Each phase's failure is non-fatal when possible. Truly fatal errors
223
+ * (no MCP server, no Node 20+) raise via `error()` and exit.
224
+ */
225
+ export async function runInit(opts = {}) {
226
+ assertNodeVersion();
227
+ const platform = effectivePlatform();
228
+ const home = effectiveHome();
229
+ const version = readVersion();
230
+ const apiUrl = opts.apiUrl ?? process.env.KREXEL_API_URL ?? "http://localhost:8787";
231
+ if (!isJsonMode()) {
232
+ dim(`OS: ${platform}`);
233
+ dim(`Home: ${home}`);
234
+ }
235
+ // 1. Resolve the MCP binary.
236
+ const binary = await resolveMcpBinary(opts);
237
+ // 2. Mint / load the master key.
238
+ const master = await initMasterKey(opts);
239
+ const env = {
240
+ KREXEL_API_URL: apiUrl,
241
+ KREXEL_MASTER_KEY: master.value,
242
+ };
243
+ if (!isJsonMode()) {
244
+ dim(`Binary: ${binary.command} ${binary.args.join(" ")}`);
245
+ dim(`Master key: ${maskSecret(master.value)}${master.minted ? " (newly minted)" : " (reused)"}`);
246
+ }
247
+ // 3. Patch every client config.
248
+ const rows = await patchAllClients(binary, env, opts);
249
+ // 4. Run OAuth unless caller said skip / dry-run.
250
+ let oauthDone = false;
251
+ const shouldLogin = !opts.skipLogin && !opts.dryRun;
252
+ if (shouldLogin) {
253
+ try {
254
+ const runner = opts.loginRunner ?? (() => runLogin({ provider: "cloudflare" }));
255
+ await runner();
256
+ oauthDone = true;
257
+ }
258
+ catch (err) {
259
+ // Non-fatal — we still print a successful-looking checklist so the
260
+ // user's MCP server is wired; they can run `krexel login` later.
261
+ warn(`OAuth did not complete: ${err instanceof Error ? err.message : String(err)}. ` +
262
+ `Run \`krexel login\` to retry.`);
263
+ }
264
+ }
265
+ else if (opts.dryRun) {
266
+ if (!isJsonMode())
267
+ dim("Dry run — skipping OAuth.");
268
+ }
269
+ else {
270
+ if (!isJsonMode())
271
+ dim("Skipping OAuth (--skip-login).");
272
+ }
273
+ // 5. Final checklist.
274
+ const items = renderChecklist({
275
+ version,
276
+ masterKey: master,
277
+ rows,
278
+ oauthDone,
279
+ apiUrl,
280
+ });
281
+ for (const item of items) {
282
+ if (item.kind === "ok")
283
+ success(item.text);
284
+ else
285
+ warn(item.text);
286
+ }
287
+ // 6. Handoff — what to do next.
288
+ if (!isJsonMode()) {
289
+ dim("");
290
+ dim("Restart Claude Desktop, then ask:");
291
+ dim(" \"ship my site to example.com\"");
292
+ dim("");
293
+ dim(`Dashboard: https://app.krexel.com`);
294
+ dim(`Advanced: npx krexel help`);
295
+ }
296
+ }
297
+ /**
298
+ * Read the CLI version straight from cli/package.json so we never drift
299
+ * from `npm view krexel`.
300
+ */
301
+ function readVersion() {
302
+ try {
303
+ const here = path.dirname(new URL(import.meta.url).pathname);
304
+ const pkgPath = path.resolve(here, "..", "package.json");
305
+ const json = JSON.parse(readFileSync(pkgPath, "utf8"));
306
+ return json.version ?? "0.0.0";
307
+ }
308
+ catch {
309
+ return "0.0.0";
310
+ }
311
+ }
312
+ //# sourceMappingURL=init.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.js","sourceRoot":"","sources":["../src/init.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ /**
2
+ * login.ts — `krexel login [--provider=cloudflare|vercel|netlify]`
3
+ *
4
+ * Phase 1 only wires Cloudflare. Vercel and Netlify throw a clean Phase 2
5
+ * error rather than silently no-oping.
6
+ *
7
+ * The flow:
8
+ * 1. Mint a one-shot API key locally with nanoid.
9
+ * 2. Open the browser to `${KREXEL_API_URL}/api/v1/auth/cloudflare/start?token=<key>`.
10
+ * 3. Poll the orchestrator's callback endpoint until it reports success,
11
+ * showing an ora spinner. The orchestrator exchanges its own cookie
12
+ * with us via the same key.
13
+ */
14
+ /**
15
+ * Run `krexel login`. Throws (via `error`) on unrecoverable problems;
16
+ * happy-path returns when the browser has been opened and the orchestrator
17
+ * has confirmed the callback.
18
+ *
19
+ * @param options.provider one of `cloudflare` (only real in Phase 1) | `vercel` | `netlify`
20
+ * @param options.apiKey optional — reused session token from previous login.
21
+ * If omitted, generate a fresh one-shot API key.
22
+ */
23
+ export declare function runLogin(opts: {
24
+ provider?: string;
25
+ apiKey?: string;
26
+ pollIntervalMs?: number;
27
+ timeoutMs?: number;
28
+ opener?: (url: string) => Promise<void>;
29
+ }): Promise<void>;
package/dist/login.js ADDED
@@ -0,0 +1,106 @@
1
+ /**
2
+ * login.ts — `krexel login [--provider=cloudflare|vercel|netlify]`
3
+ *
4
+ * Phase 1 only wires Cloudflare. Vercel and Netlify throw a clean Phase 2
5
+ * error rather than silently no-oping.
6
+ *
7
+ * The flow:
8
+ * 1. Mint a one-shot API key locally with nanoid.
9
+ * 2. Open the browser to `${KREXEL_API_URL}/api/v1/auth/cloudflare/start?token=<key>`.
10
+ * 3. Poll the orchestrator's callback endpoint until it reports success,
11
+ * showing an ora spinner. The orchestrator exchanges its own cookie
12
+ * with us via the same key.
13
+ */
14
+ import open from "open";
15
+ import { nanoid } from "nanoid";
16
+ import { request } from "undici";
17
+ import { z } from "zod";
18
+ import { withSpinner, error, dim, success, isJsonMode } from "./output.js";
19
+ const PROVIDERS = ["cloudflare", "vercel", "netlify"];
20
+ // Phase-1 environment variable matching the worker's @krexel/api-client convention.
21
+ const DEFAULT_API_URL = "http://localhost:8787";
22
+ function apiUrl() {
23
+ return process.env.KREXEL_API_URL ?? DEFAULT_API_URL;
24
+ }
25
+ /**
26
+ * Run `krexel login`. Throws (via `error`) on unrecoverable problems;
27
+ * happy-path returns when the browser has been opened and the orchestrator
28
+ * has confirmed the callback.
29
+ *
30
+ * @param options.provider one of `cloudflare` (only real in Phase 1) | `vercel` | `netlify`
31
+ * @param options.apiKey optional — reused session token from previous login.
32
+ * If omitted, generate a fresh one-shot API key.
33
+ */
34
+ export async function runLogin(opts) {
35
+ const provider = (opts.provider ?? "cloudflare");
36
+ if (!PROVIDERS.includes(provider)) {
37
+ error(`Unknown provider "${provider}". Expected one of: ${PROVIDERS.join(", ")}`);
38
+ }
39
+ if (provider !== "cloudflare") {
40
+ error(`Provider "${provider}" support lands in Phase 2. ` +
41
+ `Today only --provider=cloudflare is wired (Cloudflare for SaaS pipeline).`);
42
+ }
43
+ const apiKey = opts.apiKey ?? `krx_live_${nanoid(32)}`;
44
+ const baseUrl = apiUrl();
45
+ const startUrl = `${baseUrl}/api/v1/auth/cloudflare/start?token=${encodeURIComponent(apiKey)}`;
46
+ const statusUrl = `${baseUrl}/api/v1/auth/status?token=${encodeURIComponent(apiKey)}`;
47
+ if (!isJsonMode()) {
48
+ dim(`API: ${baseUrl}`);
49
+ dim(`Provider: ${provider}`);
50
+ }
51
+ // Open the browser (or fallback opener for tests / headless boxes).
52
+ try {
53
+ if (opts.opener) {
54
+ await opts.opener(startUrl);
55
+ }
56
+ else {
57
+ await open(startUrl, { wait: false });
58
+ }
59
+ }
60
+ catch (err) {
61
+ // Don't abort — the user can open the URL by hand.
62
+ dim(`Could not auto-open browser: ${err instanceof Error ? err.message : String(err)}. ` +
63
+ `Open this URL manually:\n ${startUrl}`);
64
+ }
65
+ const pollIntervalMs = opts.pollIntervalMs ?? 2_000;
66
+ const timeoutMs = opts.timeoutMs ?? 5 * 60_000; // 5 minutes
67
+ await withSpinner(`Waiting for ${provider} callback…`, async () => {
68
+ await pollUntilConnected(statusUrl, pollIntervalMs, timeoutMs);
69
+ });
70
+ success(`Logged in to ${provider}.`);
71
+ if (!isJsonMode()) {
72
+ dim(`Save this token if you want to skip the browser step next time:`);
73
+ dim(` ${apiKey}`);
74
+ }
75
+ }
76
+ const StatusSchema = z.object({
77
+ connected: z.boolean(),
78
+ account_email: z.string().optional(),
79
+ note: z.string().optional(),
80
+ });
81
+ async function pollUntilConnected(statusUrl, intervalMs, timeoutMs) {
82
+ const deadline = Date.now() + timeoutMs;
83
+ for (;;) {
84
+ if (Date.now() > deadline) {
85
+ error("Login timed out after 5 minutes. Re-run `krexel login` to retry.");
86
+ }
87
+ try {
88
+ const res = await request(statusUrl, { method: "GET" });
89
+ if (res.statusCode === 200) {
90
+ const body = (await res.body.json());
91
+ const parsed = StatusSchema.safeParse(body);
92
+ if (parsed.success && parsed.data.connected) {
93
+ if (parsed.data.account_email && !isJsonMode()) {
94
+ dim(`Account: ${parsed.data.account_email}`);
95
+ }
96
+ return;
97
+ }
98
+ }
99
+ }
100
+ catch {
101
+ // transient network blip — keep polling
102
+ }
103
+ await new Promise((r) => setTimeout(r, intervalMs));
104
+ }
105
+ }
106
+ //# sourceMappingURL=login.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"login.js","sourceRoot":"","sources":["../src/login.ts"],"names":[],"mappings":"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"}
package/dist/logs.d.ts ADDED
@@ -0,0 +1,10 @@
1
+ /**
2
+ * logs.ts — `krexel logs <deploy_id>`
3
+ *
4
+ * Asks the MCP server for the (currently mocked, Phase 2 will stream real)
5
+ * build logs and prints them monospace. In `--json` mode we emit the raw MCP
6
+ * payload for piping to `jq`.
7
+ */
8
+ export declare function runLogs(opts: {
9
+ deployId: string;
10
+ }): Promise<void>;
package/dist/logs.js ADDED
@@ -0,0 +1,26 @@
1
+ /**
2
+ * logs.ts — `krexel logs <deploy_id>`
3
+ *
4
+ * Asks the MCP server for the (currently mocked, Phase 2 will stream real)
5
+ * build logs and prints them monospace. In `--json` mode we emit the raw MCP
6
+ * payload for piping to `jq`.
7
+ */
8
+ import { withSpinner, error, monospace, isJsonMode } from "./output.js";
9
+ import { getClient } from "./mcp-client.js";
10
+ export async function runLogs(opts) {
11
+ const deployId = (opts.deployId ?? "").trim();
12
+ if (!deployId)
13
+ error("deploy_id is required (e.g. `krexel logs dep_abc123_xyz`).");
14
+ if (!deployId.startsWith("dep_")) {
15
+ error(`Invalid deploy_id format — must start with "dep_". Got: ${deployId}`);
16
+ }
17
+ const client = getClient();
18
+ const result = await withSpinner(`Fetching logs for ${deployId}…`, () => client.callTool("get_logs", { deploy_id: deployId }), { enabled: true });
19
+ if (isJsonMode()) {
20
+ // eslint-disable-next-line no-console
21
+ console.log(JSON.stringify(result, null, 2));
22
+ return;
23
+ }
24
+ monospace(result.logs);
25
+ }
26
+ //# sourceMappingURL=logs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logs.js","sourceRoot":"","sources":["../src/logs.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,WAAW,EAAE,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACxE,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAE5C,MAAM,CAAC,KAAK,UAAU,OAAO,CAAC,IAA0B;IACtD,MAAM,QAAQ,GAAG,CAAC,IAAI,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IAC9C,IAAI,CAAC,QAAQ;QAAE,KAAK,CAAC,4DAA4D,CAAC,CAAC;IACnF,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;QACjC,KAAK,CAAC,2DAA2D,QAAQ,EAAE,CAAC,CAAC;IAC/E,CAAC;IAED,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;IAC3B,MAAM,MAAM,GAAG,MAAM,WAAW,CAC9B,qBAAqB,QAAQ,GAAG,EAChC,GAAG,EAAE,CACH,MAAM,CAAC,QAAQ,CAMZ,UAAU,EAAE,EAAE,SAAS,EAAE,QAAQ,EAAE,CAAC,EACzC,EAAE,OAAO,EAAE,IAAI,EAAE,CAClB,CAAC;IAEF,IAAI,UAAU,EAAE,EAAE,CAAC;QACjB,sCAAsC;QACtC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;QAC7C,OAAO;IACT,CAAC;IAED,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;AACzB,CAAC"}