@codespar/cli 0.2.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 (49) hide show
  1. package/README.md +116 -0
  2. package/dist/api.js +62 -0
  3. package/dist/api.js.map +1 -0
  4. package/dist/commands/connect.js +71 -0
  5. package/dist/commands/connect.js.map +1 -0
  6. package/dist/commands/execute.js +62 -0
  7. package/dist/commands/execute.js.map +1 -0
  8. package/dist/commands/init.js +130 -0
  9. package/dist/commands/init.js.map +1 -0
  10. package/dist/commands/login.js +55 -0
  11. package/dist/commands/login.js.map +1 -0
  12. package/dist/commands/logs.js +74 -0
  13. package/dist/commands/logs.js.map +1 -0
  14. package/dist/commands/servers.js +48 -0
  15. package/dist/commands/servers.js.map +1 -0
  16. package/dist/commands/sessions.js +62 -0
  17. package/dist/commands/sessions.js.map +1 -0
  18. package/dist/commands/tools.js +43 -0
  19. package/dist/commands/tools.js.map +1 -0
  20. package/dist/config.js +57 -0
  21. package/dist/config.js.map +1 -0
  22. package/dist/index.js +210 -0
  23. package/dist/index.js.map +1 -0
  24. package/dist/output.js +54 -0
  25. package/dist/output.js.map +1 -0
  26. package/package.json +55 -0
  27. package/templates/ecommerce-checkout/.env.example +2 -0
  28. package/templates/ecommerce-checkout/README.md +22 -0
  29. package/templates/ecommerce-checkout/package.json +24 -0
  30. package/templates/ecommerce-checkout/src/index.ts +73 -0
  31. package/templates/ecommerce-checkout/tsconfig.json +15 -0
  32. package/templates/multi-tenant/.env.example +2 -0
  33. package/templates/multi-tenant/README.md +31 -0
  34. package/templates/multi-tenant/app/api/commerce/[tenantId]/route.ts +55 -0
  35. package/templates/multi-tenant/lib/commerce.ts +24 -0
  36. package/templates/multi-tenant/package.json +26 -0
  37. package/templates/multi-tenant/tsconfig.json +21 -0
  38. package/templates/pix-agent/.env.example +2 -0
  39. package/templates/pix-agent/README.md +22 -0
  40. package/templates/pix-agent/package.json +24 -0
  41. package/templates/pix-agent/src/index.ts +66 -0
  42. package/templates/pix-agent/tsconfig.json +15 -0
  43. package/templates/streaming-chat/.env.example +2 -0
  44. package/templates/streaming-chat/README.md +23 -0
  45. package/templates/streaming-chat/app/api/chat/route.ts +29 -0
  46. package/templates/streaming-chat/app/layout.tsx +12 -0
  47. package/templates/streaming-chat/app/page.tsx +66 -0
  48. package/templates/streaming-chat/package.json +29 -0
  49. package/templates/streaming-chat/tsconfig.json +21 -0
package/README.md ADDED
@@ -0,0 +1,116 @@
1
+ # @codespar/cli
2
+
3
+ Command-line interface for [CodeSpar](https://codespar.dev) — authenticate, inspect servers, execute tools, and manage sessions from your terminal.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npm install -g @codespar/cli
9
+ ```
10
+
11
+ Verify:
12
+
13
+ ```bash
14
+ codespar --version
15
+ ```
16
+
17
+ ## Quick start
18
+
19
+ ```bash
20
+ # One-time: authenticate with your API key
21
+ codespar login
22
+
23
+ # Inspect the catalog
24
+ codespar servers list
25
+ codespar servers show stripe
26
+ codespar tools list --server asaas
27
+ codespar tools show codespar_pay
28
+
29
+ # Run a one-shot tool call
30
+ codespar execute codespar_pay \
31
+ --server asaas \
32
+ --input '{"method":"pix","amount":15000,"currency":"BRL"}'
33
+
34
+ # Manage sessions
35
+ codespar sessions list
36
+ codespar sessions show ses_abc123 --logs
37
+ codespar sessions close ses_abc123
38
+ ```
39
+
40
+ ## Commands
41
+
42
+ | Command | What it does |
43
+ |---------|--------------|
44
+ | `login` | Save your API key to `~/.codespar/config.json` |
45
+ | `logout` | Clear the stored API key |
46
+ | `whoami` | Show authenticated user, org, project, and key scopes |
47
+ | `servers list` | List the server catalog (filter by `--category`, `--region`) |
48
+ | `servers show <id>` | Show a server's details and tools |
49
+ | `tools list` | List tools (filter by `--server`) |
50
+ | `tools show <name>` | Show a tool's full input/output schema |
51
+ | `execute <tool>` | Run a single tool call in a throwaway session |
52
+ | `sessions list` | List recent sessions (filter by `--status`, `--limit`) |
53
+ | `sessions show <id>` | Show session details (add `--logs` for tool calls) |
54
+ | `sessions close <id>` | Close an active session |
55
+ | `connect list` | List active Connect Links per user |
56
+ | `connect start <server>` | Start an OAuth Connect Link flow (add `--open` to launch it) |
57
+ | `connect revoke <server>` | Revoke a connection |
58
+ | `logs tail` | Stream tool-call logs in real time (filter by `--server`, `--status`, `--tool`) |
59
+ | `init <name>` | Scaffold a new commerce agent from a template |
60
+
61
+ ### Templates available via `init`
62
+
63
+ | Slug | Stack | What you get |
64
+ |------|-------|--------------|
65
+ | `pix-agent` | Node + OpenAI | Minimal Pix charge + WhatsApp notify loop |
66
+ | `ecommerce-checkout` | Node + Claude | Full Complete Loop: checkout → invoice → ship → notify |
67
+ | `streaming-chat` | Next.js + Vercel AI | Token-by-token streaming commerce chat |
68
+ | `multi-tenant` | Next.js + OpenAI | One API key, N tenants, per-tenant billing |
69
+
70
+ Every command supports:
71
+
72
+ - `--json` — machine-readable JSON output (pipe into `jq`)
73
+ - `--api-key <key>` — override the stored key
74
+ - `--base-url <url>` — point at a custom API (staging, self-hosted)
75
+
76
+ ## Configuration
77
+
78
+ Resolution order (first match wins):
79
+
80
+ 1. Command-line flags (`--api-key`, `--base-url`)
81
+ 2. Environment variables (`CODESPAR_API_KEY`, `CODESPAR_BASE_URL`)
82
+ 3. Config file at `~/.codespar/config.json` (chmod 600)
83
+
84
+ ## Scripting
85
+
86
+ Output is valid JSON on stdout and human messages on stderr, so you can pipe cleanly:
87
+
88
+ ```bash
89
+ # IDs of all servers that handle Pix
90
+ codespar servers list --json \
91
+ | jq -r '.[] | select(.capabilities | contains(["pix"])) | .id'
92
+
93
+ # p95 latency of the last 100 stripe calls in a session
94
+ codespar sessions show ses_abc123 --logs --json \
95
+ | jq '[.logs[] | select(.server == "stripe") | .duration_ms] | sort | .[95]'
96
+ ```
97
+
98
+ Use `--json` explicitly when piping — the CLI defaults to tables in a TTY.
99
+
100
+ ## Development
101
+
102
+ This package lives in the `codespar-core` monorepo.
103
+
104
+ ```bash
105
+ # From repo root
106
+ npm install
107
+ npm run build --workspace @codespar/cli
108
+ npm run typecheck --workspace @codespar/cli
109
+
110
+ # Run the local build directly
111
+ node packages/cli/dist/index.js --help
112
+ ```
113
+
114
+ ## License
115
+
116
+ MIT © CodeSpar
package/dist/api.js ADDED
@@ -0,0 +1,62 @@
1
+ import { CliError } from "./config.js";
2
+ /**
3
+ * Thin fetch wrapper around the CodeSpar REST API. The SDK doesn't expose
4
+ * every endpoint the CLI needs (catalog listings, session bookkeeping),
5
+ * so we hit the HTTP surface directly with the user's API key.
6
+ */
7
+ export class ApiClient {
8
+ config;
9
+ constructor(config) {
10
+ this.config = config;
11
+ }
12
+ async get(path, query) {
13
+ return this.request("GET", path, undefined, query);
14
+ }
15
+ async post(path, body) {
16
+ return this.request("POST", path, body);
17
+ }
18
+ async delete(path) {
19
+ return this.request("DELETE", path);
20
+ }
21
+ async request(method, path, body, query) {
22
+ const url = new URL(path.startsWith("/") ? path : `/${path}`, this.config.baseUrl);
23
+ if (query) {
24
+ for (const [k, v] of Object.entries(query)) {
25
+ if (v !== undefined)
26
+ url.searchParams.set(k, v);
27
+ }
28
+ }
29
+ let res;
30
+ try {
31
+ res = await fetch(url, {
32
+ method,
33
+ headers: {
34
+ Authorization: `Bearer ${this.config.apiKey}`,
35
+ "Content-Type": "application/json",
36
+ "User-Agent": "codespar-cli/0.1.0",
37
+ },
38
+ body: body !== undefined ? JSON.stringify(body) : undefined,
39
+ });
40
+ }
41
+ catch (err) {
42
+ throw new CliError(`Network error calling ${method} ${url.pathname}: ${err.message}`);
43
+ }
44
+ if (!res.ok) {
45
+ let detail = "";
46
+ try {
47
+ const errBody = (await res.json());
48
+ detail = errBody.message ?? errBody.error ?? "";
49
+ }
50
+ catch {
51
+ detail = await res.text().catch(() => "");
52
+ }
53
+ const prefix = `${method} ${url.pathname} → ${res.status}`;
54
+ throw new CliError(detail ? `${prefix}: ${detail}` : prefix);
55
+ }
56
+ // 204 No Content
57
+ if (res.status === 204)
58
+ return undefined;
59
+ return (await res.json());
60
+ }
61
+ }
62
+ //# sourceMappingURL=api.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api.js","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,71 @@
1
+ import { exec } from "node:child_process";
2
+ import { promisify } from "node:util";
3
+ import { CliError } from "../config.js";
4
+ import { info, json, success, table } from "../output.js";
5
+ const execAsync = promisify(exec);
6
+ export async function listConnectionsCommand(client, opts) {
7
+ const data = await client.get("/v1/connections", {
8
+ user: opts.user,
9
+ status: opts.status,
10
+ });
11
+ if (opts.json) {
12
+ json(data.data);
13
+ return;
14
+ }
15
+ table(["SERVER", "USER", "STATUS", "CONNECTED", "EXPIRES"], data.data.map((c) => [
16
+ c.server,
17
+ c.user_id ?? "-",
18
+ c.status,
19
+ c.connected_at ? new Date(c.connected_at).toISOString().slice(0, 10) : "-",
20
+ c.expires_at ? new Date(c.expires_at).toISOString().slice(0, 10) : "-",
21
+ ]));
22
+ }
23
+ /**
24
+ * Start a Connect Link flow for a server. Prints the authorization URL so
25
+ * the user can click or share it; optionally opens it in the default browser.
26
+ * This is the CLI equivalent of `session.authorize(serverId)`.
27
+ */
28
+ export async function startConnectCommand(client, server, opts) {
29
+ if (!server)
30
+ throw new CliError("Server id is required. Example: `codespar connect start stripe`");
31
+ const userId = opts.user ?? "cli-user";
32
+ const res = await client.post("/v1/connections", { server, user_id: userId });
33
+ if (opts.json) {
34
+ json(res);
35
+ return;
36
+ }
37
+ info(`Connect ${server} for user ${userId}:`);
38
+ process.stdout.write(`\n ${res.connect_url}\n\n`);
39
+ if (res.expires_at) {
40
+ info(`Link expires ${new Date(res.expires_at).toLocaleString()}`);
41
+ }
42
+ if (opts.open) {
43
+ await openInBrowser(res.connect_url).catch(() => {
44
+ // Silent fail — user can copy/paste from stdout.
45
+ });
46
+ }
47
+ else {
48
+ info("Tip: pass --open to launch the link in your browser automatically.");
49
+ }
50
+ }
51
+ export async function revokeConnectCommand(client, server, opts) {
52
+ if (!server)
53
+ throw new CliError("Server id is required. Example: `codespar connect revoke stripe`");
54
+ const userId = opts.user ?? "cli-user";
55
+ await client.delete(`/v1/connections/${encodeURIComponent(server)}?user=${encodeURIComponent(userId)}`);
56
+ success(`Revoked ${server} for user ${userId}.`);
57
+ }
58
+ /**
59
+ * Opens a URL in the system's default browser. Uses `open` on macOS,
60
+ * `xdg-open` on Linux, `start` on Windows. Intentionally minimal — we
61
+ * don't bring in `open`/`openurl` npm packages just for this.
62
+ */
63
+ async function openInBrowser(url) {
64
+ const cmd = process.platform === "darwin"
65
+ ? `open ${JSON.stringify(url)}`
66
+ : process.platform === "win32"
67
+ ? `start "" ${JSON.stringify(url)}`
68
+ : `xdg-open ${JSON.stringify(url)}`;
69
+ await execAsync(cmd);
70
+ }
71
+ //# sourceMappingURL=connect.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"connect.js","sourceRoot":"","sources":["../../src/commands/connect.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,62 @@
1
+ import { readFile } from "node:fs/promises";
2
+ import { CodeSpar } from "@codespar/sdk";
3
+ import { CliError } from "../config.js";
4
+ import { json, success } from "../output.js";
5
+ /**
6
+ * One-shot tool execution. Opens a session, calls execute(), closes.
7
+ * For multi-step flows or long sessions, use the SDK directly.
8
+ */
9
+ export async function executeCommand(toolName, opts) {
10
+ if (!toolName)
11
+ throw new CliError("Tool name is required. Example: `codespar execute codespar_pay --input '{...}'`");
12
+ if (!opts.server)
13
+ throw new CliError("--server is required (e.g. --server asaas)");
14
+ const input = await resolveInput(opts);
15
+ const userId = opts.user ?? "cli-user";
16
+ const cs = new CodeSpar({ apiKey: opts.apiKey, baseUrl: opts.baseUrl });
17
+ const session = await cs.create(userId, { servers: [opts.server] });
18
+ try {
19
+ const result = await session.execute(toolName, input);
20
+ if (opts.json) {
21
+ json(result);
22
+ return;
23
+ }
24
+ if (result.success) {
25
+ success(`${toolName} succeeded in ${result.duration ?? "?"}ms`);
26
+ }
27
+ else {
28
+ process.stderr.write(`Tool call failed: ${result.error ?? "unknown error"}\n`);
29
+ }
30
+ process.stdout.write(JSON.stringify(result, null, 2) + "\n");
31
+ }
32
+ finally {
33
+ await session.close();
34
+ }
35
+ }
36
+ async function resolveInput(opts) {
37
+ if (opts.input && opts.inputFile) {
38
+ throw new CliError("Pass either --input or --input-file, not both.");
39
+ }
40
+ if (opts.inputFile) {
41
+ const raw = await readFile(opts.inputFile, "utf-8");
42
+ return parseJson(raw, opts.inputFile);
43
+ }
44
+ if (opts.input)
45
+ return parseJson(opts.input, "--input");
46
+ return {};
47
+ }
48
+ function parseJson(raw, source) {
49
+ try {
50
+ const parsed = JSON.parse(raw);
51
+ if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
52
+ throw new CliError(`${source} must be a JSON object.`);
53
+ }
54
+ return parsed;
55
+ }
56
+ catch (err) {
57
+ if (err instanceof CliError)
58
+ throw err;
59
+ throw new CliError(`${source} is not valid JSON: ${err.message}`);
60
+ }
61
+ }
62
+ //# sourceMappingURL=execute.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"execute.js","sourceRoot":"","sources":["../../src/commands/execute.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AACxC,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAY7C;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,QAAgB,EAAE,IAAoB;IACzE,IAAI,CAAC,QAAQ;QAAE,MAAM,IAAI,QAAQ,CAAC,iFAAiF,CAAC,CAAC;IACrH,IAAI,CAAC,IAAI,CAAC,MAAM;QAAE,MAAM,IAAI,QAAQ,CAAC,4CAA4C,CAAC,CAAC;IAEnF,MAAM,KAAK,GAAG,MAAM,YAAY,CAAC,IAAI,CAAC,CAAC;IACvC,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,IAAI,UAAU,CAAC;IAEvC,MAAM,EAAE,GAAG,IAAI,QAAQ,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC;IACxE,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,MAAM,CAAC,MAAM,EAAE,EAAE,OAAO,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IAEpE,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,OAAO,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;QAEtD,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;YACd,IAAI,CAAC,MAAM,CAAC,CAAC;YACb,OAAO;QACT,CAAC;QAED,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;YACnB,OAAO,CAAC,GAAG,QAAQ,iBAAiB,MAAM,CAAC,QAAQ,IAAI,GAAG,IAAI,CAAC,CAAC;QAClE,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,qBAAqB,MAAM,CAAC,KAAK,IAAI,eAAe,IAAI,CAAC,CAAC;QACjF,CAAC;QACD,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;IAC/D,CAAC;YAAS,CAAC;QACT,MAAM,OAAO,CAAC,KAAK,EAAE,CAAC;IACxB,CAAC;AACH,CAAC;AAED,KAAK,UAAU,YAAY,CAAC,IAAoB;IAC9C,IAAI,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;QACjC,MAAM,IAAI,QAAQ,CAAC,gDAAgD,CAAC,CAAC;IACvE,CAAC;IACD,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;QACnB,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;QACpD,OAAO,SAAS,CAAC,GAAG,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC;IACxC,CAAC;IACD,IAAI,IAAI,CAAC,KAAK;QAAE,OAAO,SAAS,CAAC,IAAI,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC;IACxD,OAAO,EAAE,CAAC;AACZ,CAAC;AAED,SAAS,SAAS,CAAC,GAAW,EAAE,MAAc;IAC5C,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAY,CAAC;QAC1C,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,KAAK,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;YAC3E,MAAM,IAAI,QAAQ,CAAC,GAAG,MAAM,yBAAyB,CAAC,CAAC;QACzD,CAAC;QACD,OAAO,MAAiC,CAAC;IAC3C,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,GAAG,YAAY,QAAQ;YAAE,MAAM,GAAG,CAAC;QACvC,MAAM,IAAI,QAAQ,CAAC,GAAG,MAAM,uBAAwB,GAAa,CAAC,OAAO,EAAE,CAAC,CAAC;IAC/E,CAAC;AACH,CAAC"}
@@ -0,0 +1,130 @@
1
+ import { createInterface } from "node:readline/promises";
2
+ import { stdin, stdout } from "node:process";
3
+ import { mkdir, readdir, readFile, stat, writeFile } from "node:fs/promises";
4
+ import { dirname, join, resolve } from "node:path";
5
+ import { fileURLToPath } from "node:url";
6
+ import { CliError } from "../config.js";
7
+ import { c, info, success } from "../output.js";
8
+ const TEMPLATES = [
9
+ {
10
+ slug: "pix-agent",
11
+ label: "Pix Payment Agent",
12
+ description: "Minimal Pix charge + WhatsApp notification via OpenAI",
13
+ framework: "OpenAI",
14
+ },
15
+ {
16
+ slug: "ecommerce-checkout",
17
+ label: "E-Commerce Checkout",
18
+ description: "Full Complete Loop: checkout → invoice → ship → notify (Claude)",
19
+ framework: "Claude",
20
+ },
21
+ {
22
+ slug: "streaming-chat",
23
+ label: "Streaming Chat",
24
+ description: "Next.js 15 + Vercel AI SDK with token-by-token streaming",
25
+ framework: "Next.js + Vercel AI",
26
+ },
27
+ {
28
+ slug: "multi-tenant",
29
+ label: "Multi-Tenant Agent",
30
+ description: "SaaS pattern — one API key, N tenants, per-tenant billing",
31
+ framework: "Next.js + OpenAI",
32
+ },
33
+ ];
34
+ export async function initCommand(name, opts) {
35
+ if (!name)
36
+ throw new CliError("Project name is required. Example: `codespar init my-agent`");
37
+ if (!/^[a-z0-9][a-z0-9-_]*$/i.test(name)) {
38
+ throw new CliError("Project name must start with a letter/number and contain only letters, digits, dashes, and underscores.");
39
+ }
40
+ const target = resolve(process.cwd(), name);
41
+ // Refuse to clobber an existing non-empty directory.
42
+ try {
43
+ const existing = await readdir(target);
44
+ if (existing.length > 0) {
45
+ throw new CliError(`Directory ${name}/ already exists and is not empty. Choose a different name or delete it first.`);
46
+ }
47
+ }
48
+ catch (err) {
49
+ if (err.code !== "ENOENT")
50
+ throw err;
51
+ }
52
+ const template = await pickTemplate(opts);
53
+ info(`Creating ${c.bold(name)} using the ${c.bold(template.label)} template...`);
54
+ const templatesRoot = resolveTemplatesDir();
55
+ const source = join(templatesRoot, template.slug);
56
+ await copyTemplate(source, target, { name });
57
+ process.stdout.write("\n");
58
+ success(`Created ${name}/`);
59
+ process.stdout.write([
60
+ "",
61
+ "Next steps:",
62
+ ` cd ${name}`,
63
+ " cp .env.example .env # then fill in your keys",
64
+ " npm install",
65
+ " npm run dev",
66
+ "",
67
+ ].join("\n"));
68
+ }
69
+ async function pickTemplate(opts) {
70
+ if (opts.template) {
71
+ const t = TEMPLATES.find((x) => x.slug === opts.template);
72
+ if (!t) {
73
+ throw new CliError(`Unknown template "${opts.template}". Available: ${TEMPLATES.map((x) => x.slug).join(", ")}`);
74
+ }
75
+ return t;
76
+ }
77
+ if (opts.yes)
78
+ return TEMPLATES[0];
79
+ // Interactive pick
80
+ process.stdout.write(c.bold("Choose a template:\n\n"));
81
+ TEMPLATES.forEach((t, i) => {
82
+ process.stdout.write(` ${c.blue(`${i + 1}.`)} ${c.bold(t.label)} ${c.dim(`(${t.framework})`)}\n`);
83
+ process.stdout.write(` ${c.dim(t.description)}\n\n`);
84
+ });
85
+ const rl = createInterface({ input: stdin, output: stdout });
86
+ try {
87
+ const answer = (await rl.question(`Pick a number [1-${TEMPLATES.length}] (default 1): `)).trim();
88
+ const index = answer === "" ? 0 : Number.parseInt(answer, 10) - 1;
89
+ if (Number.isNaN(index) || index < 0 || index >= TEMPLATES.length) {
90
+ throw new CliError(`Invalid choice: ${answer}`);
91
+ }
92
+ return TEMPLATES[index];
93
+ }
94
+ finally {
95
+ rl.close();
96
+ }
97
+ }
98
+ function resolveTemplatesDir() {
99
+ // When running from dist/, __dirname is packages/cli/dist/commands.
100
+ // Templates live at packages/cli/templates, so go up two levels.
101
+ const here = dirname(fileURLToPath(import.meta.url));
102
+ return resolve(here, "..", "..", "templates");
103
+ }
104
+ async function copyTemplate(source, target, vars) {
105
+ const stats = await stat(source).catch(() => null);
106
+ if (!stats)
107
+ throw new CliError(`Template not found at ${source}. Is the package installation corrupted?`);
108
+ await mkdir(target, { recursive: true });
109
+ const entries = await readdir(source, { withFileTypes: true });
110
+ for (const entry of entries) {
111
+ const srcPath = join(source, entry.name);
112
+ // Substitute placeholders in file names too (rare but cheap)
113
+ const outName = substituteAll(entry.name, vars);
114
+ const dstPath = join(target, outName);
115
+ if (entry.isDirectory()) {
116
+ await copyTemplate(srcPath, dstPath, vars);
117
+ continue;
118
+ }
119
+ // Binary detection is heuristic — read as utf-8 and substitute if
120
+ // it decodes cleanly. Good enough for templates which are all text.
121
+ const buf = await readFile(srcPath);
122
+ const text = buf.toString("utf-8");
123
+ const rendered = substituteAll(text, vars);
124
+ await writeFile(dstPath, rendered, "utf-8");
125
+ }
126
+ }
127
+ function substituteAll(source, vars) {
128
+ return source.replace(/\{\{(\w+)\}\}/g, (match, key) => vars[key] ?? match);
129
+ }
130
+ //# sourceMappingURL=init.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,55 @@
1
+ import { createInterface } from "node:readline/promises";
2
+ import { stdin as input, stdout as output } from "node:process";
3
+ import { saveConfig, CliError } from "../config.js";
4
+ import { ApiClient } from "../api.js";
5
+ import { success, info } from "../output.js";
6
+ /**
7
+ * Store an API key on disk. If `--api-key` is passed we use it directly;
8
+ * otherwise we prompt the user interactively. After saving we call
9
+ * /v1/whoami to validate that the key actually works — fail-fast is
10
+ * friendlier than saving a bad key and failing on the next command.
11
+ */
12
+ export async function loginCommand(opts) {
13
+ let apiKey = opts.apiKey;
14
+ if (!apiKey) {
15
+ info("Get your API key at https://codespar.dev/dashboard/settings?tab=api-keys");
16
+ const rl = createInterface({ input, output });
17
+ try {
18
+ apiKey = (await rl.question("API key: ")).trim();
19
+ }
20
+ finally {
21
+ rl.close();
22
+ }
23
+ }
24
+ if (!apiKey)
25
+ throw new CliError("API key is required.");
26
+ if (!apiKey.startsWith("csk_")) {
27
+ throw new CliError("That doesn't look like a CodeSpar key — they start with `csk_live_` or `csk_test_`.");
28
+ }
29
+ const baseUrl = opts.baseUrl ?? process.env.CODESPAR_BASE_URL ?? "https://api.codespar.dev";
30
+ // Validate before saving so we don't persist a typo.
31
+ const client = new ApiClient({ apiKey, baseUrl });
32
+ const me = await client.get("/v1/whoami");
33
+ await saveConfig({ apiKey, baseUrl });
34
+ success(`Logged in as ${me.user?.email ?? me.user?.id ?? "unknown user"}`);
35
+ if (me.organization?.name) {
36
+ info(`Organization: ${me.organization.name}`);
37
+ }
38
+ }
39
+ export async function whoamiCommand(client, asJson) {
40
+ const me = await client.get("/v1/whoami");
41
+ if (asJson) {
42
+ const { json } = await import("../output.js");
43
+ json(me);
44
+ return;
45
+ }
46
+ const { kv } = await import("../output.js");
47
+ kv([
48
+ ["User", me.user?.email ?? me.user?.id ?? "(unknown)"],
49
+ ["Organization", me.organization?.name ?? "(none)"],
50
+ ["Project", me.project?.name ?? me.project?.id ?? "(none)"],
51
+ ["Key env", me.key?.environment ?? "(unknown)"],
52
+ ["Scopes", me.key?.scopes?.join(", ") ?? "(all)"],
53
+ ]);
54
+ }
55
+ //# sourceMappingURL=login.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"login.js","sourceRoot":"","sources":["../../src/commands/login.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,74 @@
1
+ import { CliError } from "../config.js";
2
+ import { c, json } from "../output.js";
3
+ /**
4
+ * Stream execution logs live from /v1/logs/stream (SSE).
5
+ * Falls through on Ctrl-C — we don't need a clean shutdown, the server
6
+ * will close the connection when stdin closes.
7
+ */
8
+ export async function tailLogsCommand(config, opts) {
9
+ const url = new URL("/v1/logs/stream", config.baseUrl);
10
+ if (opts.server)
11
+ url.searchParams.set("server", opts.server);
12
+ if (opts.status)
13
+ url.searchParams.set("status", opts.status);
14
+ if (opts.tool)
15
+ url.searchParams.set("tool", opts.tool);
16
+ if (opts.limit)
17
+ url.searchParams.set("limit", opts.limit);
18
+ let res;
19
+ try {
20
+ res = await fetch(url, {
21
+ headers: {
22
+ Authorization: `Bearer ${config.apiKey}`,
23
+ Accept: "text/event-stream",
24
+ },
25
+ });
26
+ }
27
+ catch (err) {
28
+ throw new CliError(`Failed to connect: ${err.message}`);
29
+ }
30
+ if (!res.ok || !res.body) {
31
+ throw new CliError(`Log stream returned ${res.status}. Check your API key.`);
32
+ }
33
+ process.stderr.write(c.dim("Tailing logs — press Ctrl-C to stop\n\n"));
34
+ const reader = res.body.getReader();
35
+ const decoder = new TextDecoder();
36
+ let buffer = "";
37
+ while (true) {
38
+ const { done, value } = await reader.read();
39
+ if (done)
40
+ break;
41
+ buffer += decoder.decode(value, { stream: true });
42
+ // SSE frames are separated by a blank line (\n\n).
43
+ const frames = buffer.split("\n\n");
44
+ buffer = frames.pop() ?? "";
45
+ for (const frame of frames) {
46
+ const dataLines = frame
47
+ .split("\n")
48
+ .filter((l) => l.startsWith("data: "))
49
+ .map((l) => l.slice(6));
50
+ if (dataLines.length === 0)
51
+ continue;
52
+ try {
53
+ const entry = JSON.parse(dataLines.join("\n"));
54
+ printEntry(entry, opts.json ?? false);
55
+ }
56
+ catch {
57
+ // Ignore malformed frames (keep-alives, comments)
58
+ }
59
+ }
60
+ }
61
+ }
62
+ function printEntry(entry, asJson) {
63
+ if (asJson) {
64
+ json(entry);
65
+ return;
66
+ }
67
+ const time = entry.called_at ? new Date(entry.called_at).toISOString().slice(11, 19) : "--:--:--";
68
+ const statusColor = entry.status === "success" ? c.green : entry.status === "error" ? c.red : c.yellow;
69
+ const statusLabel = statusColor(entry.status.toUpperCase().padEnd(7));
70
+ const durationStr = entry.duration_ms !== undefined ? `${entry.duration_ms}ms` : "";
71
+ const suffix = entry.error ? ` ${c.red(entry.error)}` : "";
72
+ process.stdout.write(`${c.gray(time)} ${statusLabel} ${entry.tool.padEnd(24)} ${c.dim(entry.server.padEnd(16))} ${c.dim(durationStr)}${suffix}\n`);
73
+ }
74
+ //# sourceMappingURL=logs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logs.js","sourceRoot":"","sources":["../../src/commands/logs.ts"],"names":[],"mappings":"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"}