create-specra 0.2.1 → 0.2.3

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 (62) hide show
  1. package/README.md +11 -14
  2. package/dist/api-client-VHQARPDT.js +15 -0
  3. package/dist/api-client-VHQARPDT.js.map +1 -0
  4. package/dist/chunk-5765WX4D.js +192 -0
  5. package/dist/chunk-5765WX4D.js.map +1 -0
  6. package/dist/{chunk-MA7QG54W.js → chunk-72RDEJR2.js} +22 -2
  7. package/dist/chunk-72RDEJR2.js.map +1 -0
  8. package/dist/chunk-SQ2MMFUZ.js +102 -0
  9. package/dist/chunk-SQ2MMFUZ.js.map +1 -0
  10. package/dist/cli.js +18 -11
  11. package/dist/cli.js.map +1 -1
  12. package/dist/{deploy-SCEMUQNS.js → deploy-V4JO2D6B.js} +74 -36
  13. package/dist/deploy-V4JO2D6B.js.map +1 -0
  14. package/dist/doctor-ICALAJ4N.js +309 -0
  15. package/dist/doctor-ICALAJ4N.js.map +1 -0
  16. package/dist/index.js +72 -105
  17. package/dist/index.js.map +1 -1
  18. package/dist/{login-NKDRQXRE.js → login-UG3WU7DY.js} +36 -15
  19. package/dist/login-UG3WU7DY.js.map +1 -0
  20. package/dist/logout-WJKHJZT6.js +24 -0
  21. package/dist/logout-WJKHJZT6.js.map +1 -0
  22. package/dist/{logs-YDAUCMAV.js → logs-BLUJPWNO.js} +26 -20
  23. package/dist/logs-BLUJPWNO.js.map +1 -0
  24. package/dist/{projects-3TAY7EDJ.js → projects-LJ57GK3D.js} +13 -6
  25. package/dist/projects-LJ57GK3D.js.map +1 -0
  26. package/package.json +3 -2
  27. package/templates/book-docs/.env.sample +1 -0
  28. package/templates/book-docs/package.json +1 -1
  29. package/templates/book-docs/src/app.css +3 -4
  30. package/templates/book-docs/src/routes/+layout.server.ts +3 -0
  31. package/templates/book-docs/src/routes/docs/[version]/[...slug]/+page.server.ts +1 -1
  32. package/templates/book-docs/svelte.config.js +6 -1
  33. package/templates/jbrains-docs/.env.sample +1 -0
  34. package/templates/jbrains-docs/package.json +1 -1
  35. package/templates/jbrains-docs/src/app.css +3 -4
  36. package/templates/jbrains-docs/src/routes/+layout.server.ts +3 -0
  37. package/templates/jbrains-docs/src/routes/docs/[version]/[...slug]/+page.server.ts +1 -1
  38. package/templates/jbrains-docs/svelte.config.js +6 -1
  39. package/templates/minimal/.env.sample +1 -0
  40. package/templates/minimal/package.json +1 -1
  41. package/templates/minimal/specra.config.json +13 -1
  42. package/templates/minimal/src/app.css +3 -4
  43. package/templates/minimal/src/hooks.server.ts +8 -0
  44. package/templates/minimal/src/routes/+error.svelte +10 -0
  45. package/templates/minimal/src/routes/+layout.server.ts +3 -0
  46. package/templates/minimal/src/routes/+page.svelte +149 -0
  47. package/templates/minimal/src/routes/docs/[version]/+page.server.ts +14 -0
  48. package/templates/minimal/src/routes/docs/[version]/[...slug]/+page.server.ts +1 -1
  49. package/templates/minimal/svelte.config.js +6 -1
  50. package/dist/chunk-3DKWECRK.js +0 -45
  51. package/dist/chunk-3DKWECRK.js.map +0 -1
  52. package/dist/chunk-MA7QG54W.js.map +0 -1
  53. package/dist/deploy-SCEMUQNS.js.map +0 -1
  54. package/dist/login-NKDRQXRE.js.map +0 -1
  55. package/dist/logout-H543QEKU.js +0 -20
  56. package/dist/logout-H543QEKU.js.map +0 -1
  57. package/dist/logs-YDAUCMAV.js.map +0 -1
  58. package/dist/projects-3TAY7EDJ.js.map +0 -1
  59. /package/templates/minimal/{public → static}/api-specs/openapi-example.json +0 -0
  60. /package/templates/minimal/{public → static}/api-specs/postman-example.json +0 -0
  61. /package/templates/minimal/{public → static}/api-specs/test-api.json +0 -0
  62. /package/templates/minimal/{public → static}/api-specs/users-api.json +0 -0
package/README.md CHANGED
@@ -108,21 +108,18 @@ The CLI creates a new SvelteKit project with Specra pre-configured:
108
108
  ```
109
109
  my-docs/
110
110
  ├── src/
111
- │ ├── app.css
112
- │ ├── app.html
113
- └── routes/
114
- ├── +layout.server.ts
115
- ├── +layout.svelte
116
- ├── +page.server.ts
117
- └── docs/
118
- └── [version]/
119
- │ └── [...slug]/
120
- │ ├── +page.server.ts
121
- │ └── +page.svelte
111
+ │ ├── routes/
112
+ ├── +layout.svelte
113
+ │ ├── +page.svelte
114
+ │ └── docs/
115
+ └── [version]/[...slug]/
116
+ ├── +page.svelte
117
+ └── +page.ts
118
+ └── app.html
122
119
  ├── docs/
123
- ├── v1.0.0/
124
- └── v2.0.0/
125
- ├── public/
120
+ └── v1.0.0/
121
+ └── index.mdx
122
+ ├── static/
126
123
  ├── specra.config.json
127
124
  ├── svelte.config.js
128
125
  ├── vite.config.ts
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ ApiError,
4
+ apiRequest,
5
+ apiUpload,
6
+ formatError
7
+ } from "./chunk-72RDEJR2.js";
8
+ import "./chunk-5765WX4D.js";
9
+ export {
10
+ ApiError,
11
+ apiRequest,
12
+ apiUpload,
13
+ formatError
14
+ };
15
+ //# sourceMappingURL=api-client-VHQARPDT.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,192 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/config.ts
4
+ import { readFileSync, writeFileSync, mkdirSync, existsSync, unlinkSync } from "fs";
5
+ import { join, resolve } from "path";
6
+ import { homedir } from "os";
7
+ var GLOBAL_CONFIG_DIR = join(homedir(), ".specra");
8
+ var GLOBAL_CONFIG_FILE = join(GLOBAL_CONFIG_DIR, "config.json");
9
+ var DEFAULT_TOKEN_ENV = "SPECRA_TOKEN";
10
+ var DEFAULT_GLOBAL_CONFIG = {
11
+ apiUrl: "https://specra-docs.com"
12
+ };
13
+ function getEnvFilePath(dir) {
14
+ return join(resolve(dir || "."), ".env");
15
+ }
16
+ function readEnvFile(dir) {
17
+ const envPath = getEnvFilePath(dir);
18
+ try {
19
+ const content = readFileSync(envPath, "utf-8");
20
+ const env = {};
21
+ for (const line of content.split("\n")) {
22
+ const trimmed = line.trim();
23
+ if (!trimmed || trimmed.startsWith("#")) continue;
24
+ const eqIdx = trimmed.indexOf("=");
25
+ if (eqIdx === -1) continue;
26
+ const key = trimmed.slice(0, eqIdx).trim();
27
+ const value = trimmed.slice(eqIdx + 1).trim().replace(/^["']|["']$/g, "");
28
+ env[key] = value;
29
+ }
30
+ return env;
31
+ } catch {
32
+ return {};
33
+ }
34
+ }
35
+ function writeEnvVar(key, value, dir) {
36
+ const envPath = getEnvFilePath(dir);
37
+ let content = "";
38
+ try {
39
+ content = readFileSync(envPath, "utf-8");
40
+ } catch {
41
+ }
42
+ const lines = content.split("\n");
43
+ let found = false;
44
+ for (let i = 0; i < lines.length; i++) {
45
+ if (lines[i].trim().startsWith(`${key}=`)) {
46
+ lines[i] = `${key}=${value}`;
47
+ found = true;
48
+ break;
49
+ }
50
+ }
51
+ if (!found) {
52
+ if (lines.length > 0 && lines[lines.length - 1] !== "") {
53
+ lines.push("");
54
+ }
55
+ lines.push(`${key}=${value}`);
56
+ }
57
+ writeFileSync(envPath, lines.join("\n") + "\n");
58
+ }
59
+ function removeEnvVar(key, dir) {
60
+ const envPath = getEnvFilePath(dir);
61
+ try {
62
+ const content = readFileSync(envPath, "utf-8");
63
+ const lines = content.split("\n").filter((line) => !line.trim().startsWith(`${key}=`));
64
+ writeFileSync(envPath, lines.join("\n"));
65
+ } catch {
66
+ }
67
+ }
68
+ function ensureGitignore(dir) {
69
+ const gitignorePath = join(resolve(dir || "."), ".gitignore");
70
+ try {
71
+ let content = "";
72
+ try {
73
+ content = readFileSync(gitignorePath, "utf-8");
74
+ } catch {
75
+ }
76
+ if (!content.split("\n").some((line) => line.trim() === ".env")) {
77
+ const newline = content && !content.endsWith("\n") ? "\n" : "";
78
+ writeFileSync(gitignorePath, content + newline + ".env\n");
79
+ }
80
+ } catch {
81
+ }
82
+ }
83
+ function getGlobalConfig() {
84
+ try {
85
+ const raw = readFileSync(GLOBAL_CONFIG_FILE, "utf-8");
86
+ return { ...DEFAULT_GLOBAL_CONFIG, ...JSON.parse(raw) };
87
+ } catch {
88
+ return DEFAULT_GLOBAL_CONFIG;
89
+ }
90
+ }
91
+ function saveGlobalConfig(config) {
92
+ mkdirSync(GLOBAL_CONFIG_DIR, { recursive: true });
93
+ const current = getGlobalConfig();
94
+ const merged = { ...current, ...config };
95
+ writeFileSync(GLOBAL_CONFIG_FILE, JSON.stringify(merged, null, 2));
96
+ }
97
+ function clearGlobalToken() {
98
+ const config = getGlobalConfig();
99
+ delete config.token;
100
+ mkdirSync(GLOBAL_CONFIG_DIR, { recursive: true });
101
+ writeFileSync(GLOBAL_CONFIG_FILE, JSON.stringify(config, null, 2));
102
+ }
103
+ function getLocalConfigPath(dir) {
104
+ return join(resolve(dir || "."), "specra.config.json");
105
+ }
106
+ function readLocalConfig(dir) {
107
+ const configPath = getLocalConfigPath(dir);
108
+ try {
109
+ return JSON.parse(readFileSync(configPath, "utf-8"));
110
+ } catch {
111
+ return null;
112
+ }
113
+ }
114
+ function getLocalToken(dir) {
115
+ const config = readLocalConfig(dir);
116
+ if (!config?.auth) return void 0;
117
+ if (config.auth.tokenEnv) {
118
+ const envName = config.auth.tokenEnv;
119
+ if (process.env[envName]) return process.env[envName];
120
+ const envVars = readEnvFile(dir);
121
+ return envVars[envName];
122
+ }
123
+ if (config.auth.source === "global") {
124
+ return getGlobalConfig().token;
125
+ }
126
+ return config.auth.token;
127
+ }
128
+ function saveLocalToken(token, dir) {
129
+ const configPath = getLocalConfigPath(dir);
130
+ if (!existsSync(configPath)) {
131
+ throw new Error(`specra.config.json not found in ${resolve(dir || ".")}. Are you in a Specra project?`);
132
+ }
133
+ writeEnvVar(DEFAULT_TOKEN_ENV, token, dir);
134
+ const config = JSON.parse(readFileSync(configPath, "utf-8"));
135
+ config.auth = { tokenEnv: DEFAULT_TOKEN_ENV };
136
+ writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n");
137
+ ensureGitignore(dir);
138
+ }
139
+ function clearLocalToken(dir) {
140
+ removeEnvVar(DEFAULT_TOKEN_ENV, dir);
141
+ const configPath = getLocalConfigPath(dir);
142
+ if (!existsSync(configPath)) return;
143
+ try {
144
+ const config = JSON.parse(readFileSync(configPath, "utf-8"));
145
+ if (config.auth) {
146
+ delete config.auth;
147
+ }
148
+ writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n");
149
+ } catch {
150
+ }
151
+ }
152
+ function getToken(dir) {
153
+ return getLocalToken(dir) || getGlobalConfig().token;
154
+ }
155
+ function getConfig() {
156
+ return getGlobalConfig();
157
+ }
158
+ function isAuthenticated(dir) {
159
+ return !!getToken(dir);
160
+ }
161
+ function saveToken(token, options) {
162
+ if (options?.global) {
163
+ saveGlobalConfig({ token });
164
+ const configPath = getLocalConfigPath(options?.dir);
165
+ if (existsSync(configPath)) {
166
+ try {
167
+ const config = JSON.parse(readFileSync(configPath, "utf-8"));
168
+ config.auth = { source: "global" };
169
+ writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n");
170
+ } catch {
171
+ }
172
+ }
173
+ } else {
174
+ saveLocalToken(token, options?.dir);
175
+ }
176
+ }
177
+ function clearToken(options) {
178
+ if (options?.global) {
179
+ clearGlobalToken();
180
+ } else {
181
+ clearLocalToken(options?.dir);
182
+ }
183
+ }
184
+
185
+ export {
186
+ getToken,
187
+ getConfig,
188
+ isAuthenticated,
189
+ saveToken,
190
+ clearToken
191
+ };
192
+ //# sourceMappingURL=chunk-5765WX4D.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/config.ts"],"sourcesContent":["import { readFileSync, writeFileSync, mkdirSync, existsSync, unlinkSync } from 'fs'\nimport { join, resolve } from 'path'\nimport { homedir } from 'os'\n\n// Global config: ~/.specra/config.json\nconst GLOBAL_CONFIG_DIR = join(homedir(), '.specra')\nconst GLOBAL_CONFIG_FILE = join(GLOBAL_CONFIG_DIR, 'config.json')\n\nconst DEFAULT_TOKEN_ENV = 'SPECRA_TOKEN'\n\ninterface GlobalConfig {\n apiUrl: string\n token?: string\n defaultProject?: string\n}\n\nconst DEFAULT_GLOBAL_CONFIG: GlobalConfig = {\n apiUrl: 'https://specra-docs.com',\n}\n\n// --------------- .env file helpers ---------------\n\nfunction getEnvFilePath(dir?: string): string {\n return join(resolve(dir || '.'), '.env')\n}\n\nfunction readEnvFile(dir?: string): Record<string, string> {\n const envPath = getEnvFilePath(dir)\n try {\n const content = readFileSync(envPath, 'utf-8')\n const env: Record<string, string> = {}\n for (const line of content.split('\\n')) {\n const trimmed = line.trim()\n if (!trimmed || trimmed.startsWith('#')) continue\n const eqIdx = trimmed.indexOf('=')\n if (eqIdx === -1) continue\n const key = trimmed.slice(0, eqIdx).trim()\n const value = trimmed.slice(eqIdx + 1).trim().replace(/^[\"']|[\"']$/g, '')\n env[key] = value\n }\n return env\n } catch {\n return {}\n }\n}\n\nfunction writeEnvVar(key: string, value: string, dir?: string) {\n const envPath = getEnvFilePath(dir)\n let content = ''\n try {\n content = readFileSync(envPath, 'utf-8')\n } catch {\n // file doesn't exist yet\n }\n\n const lines = content.split('\\n')\n let found = false\n for (let i = 0; i < lines.length; i++) {\n if (lines[i].trim().startsWith(`${key}=`)) {\n lines[i] = `${key}=${value}`\n found = true\n break\n }\n }\n\n if (!found) {\n // Ensure trailing newline before appending\n if (lines.length > 0 && lines[lines.length - 1] !== '') {\n lines.push('')\n }\n lines.push(`${key}=${value}`)\n }\n\n writeFileSync(envPath, lines.join('\\n') + '\\n')\n}\n\nfunction removeEnvVar(key: string, dir?: string) {\n const envPath = getEnvFilePath(dir)\n try {\n const content = readFileSync(envPath, 'utf-8')\n const lines = content.split('\\n').filter(line => !line.trim().startsWith(`${key}=`))\n writeFileSync(envPath, lines.join('\\n'))\n } catch {\n // file doesn't exist, nothing to remove\n }\n}\n\nfunction ensureGitignore(dir?: string) {\n const gitignorePath = join(resolve(dir || '.'), '.gitignore')\n try {\n let content = ''\n try {\n content = readFileSync(gitignorePath, 'utf-8')\n } catch {\n // no .gitignore yet\n }\n if (!content.split('\\n').some(line => line.trim() === '.env')) {\n const newline = content && !content.endsWith('\\n') ? '\\n' : ''\n writeFileSync(gitignorePath, content + newline + '.env\\n')\n }\n } catch {\n // ignore\n }\n}\n\n// --------------- Global config ---------------\n\nexport function getGlobalConfig(): GlobalConfig {\n try {\n const raw = readFileSync(GLOBAL_CONFIG_FILE, 'utf-8')\n return { ...DEFAULT_GLOBAL_CONFIG, ...JSON.parse(raw) }\n } catch {\n return DEFAULT_GLOBAL_CONFIG\n }\n}\n\nexport function saveGlobalConfig(config: Partial<GlobalConfig>) {\n mkdirSync(GLOBAL_CONFIG_DIR, { recursive: true })\n const current = getGlobalConfig()\n const merged = { ...current, ...config }\n writeFileSync(GLOBAL_CONFIG_FILE, JSON.stringify(merged, null, 2))\n}\n\nexport function clearGlobalToken() {\n const config = getGlobalConfig()\n delete config.token\n mkdirSync(GLOBAL_CONFIG_DIR, { recursive: true })\n writeFileSync(GLOBAL_CONFIG_FILE, JSON.stringify(config, null, 2))\n}\n\n// --------------- Local config (specra.config.json) ---------------\n\nfunction getLocalConfigPath(dir?: string): string {\n return join(resolve(dir || '.'), 'specra.config.json')\n}\n\nfunction readLocalConfig(dir?: string): Record<string, any> | null {\n const configPath = getLocalConfigPath(dir)\n try {\n return JSON.parse(readFileSync(configPath, 'utf-8'))\n } catch {\n return null\n }\n}\n\nexport function getLocalToken(dir?: string): string | undefined {\n const config = readLocalConfig(dir)\n if (!config?.auth) return undefined\n\n // Env var reference: auth.tokenEnv → read from process.env, then .env file\n if (config.auth.tokenEnv) {\n const envName = config.auth.tokenEnv\n if (process.env[envName]) return process.env[envName]\n const envVars = readEnvFile(dir)\n return envVars[envName]\n }\n\n // Global reference: auth.source === \"global\" → read from ~/.specra/config.json\n if (config.auth.source === 'global') {\n return getGlobalConfig().token\n }\n\n // Legacy: direct auth.token (backwards compat for existing projects)\n return config.auth.token\n}\n\nexport function saveLocalToken(token: string, dir?: string) {\n const configPath = getLocalConfigPath(dir)\n if (!existsSync(configPath)) {\n throw new Error(`specra.config.json not found in ${resolve(dir || '.')}. Are you in a Specra project?`)\n }\n\n // Save the actual token to .env\n writeEnvVar(DEFAULT_TOKEN_ENV, token, dir)\n\n // Point specra.config.json at the env var (never store raw token)\n const config = JSON.parse(readFileSync(configPath, 'utf-8'))\n config.auth = { tokenEnv: DEFAULT_TOKEN_ENV }\n writeFileSync(configPath, JSON.stringify(config, null, 2) + '\\n')\n\n // Make sure .env is gitignored\n ensureGitignore(dir)\n}\n\nexport function clearLocalToken(dir?: string) {\n // Remove token from .env\n removeEnvVar(DEFAULT_TOKEN_ENV, dir)\n\n // Clean up auth section from specra.config.json\n const configPath = getLocalConfigPath(dir)\n if (!existsSync(configPath)) return\n try {\n const config = JSON.parse(readFileSync(configPath, 'utf-8'))\n if (config.auth) {\n delete config.auth\n }\n writeFileSync(configPath, JSON.stringify(config, null, 2) + '\\n')\n } catch {\n // ignore parse errors\n }\n}\n\n// --------------- Unified accessors ---------------\n\n/** Get token: checks local specra.config.json first, then global ~/.specra/config.json */\nexport function getToken(dir?: string): string | undefined {\n return getLocalToken(dir) || getGlobalConfig().token\n}\n\n/** Get the API URL from global config */\nexport function getConfig(): GlobalConfig {\n return getGlobalConfig()\n}\n\nexport function isAuthenticated(dir?: string): boolean {\n return !!getToken(dir)\n}\n\n/** Save token to local .env (default) or global ~/.specra/config.json */\nexport function saveToken(token: string, options?: { global?: boolean; dir?: string }) {\n if (options?.global) {\n saveGlobalConfig({ token })\n // If specra.config.json exists locally, point it at global\n const configPath = getLocalConfigPath(options?.dir)\n if (existsSync(configPath)) {\n try {\n const config = JSON.parse(readFileSync(configPath, 'utf-8'))\n config.auth = { source: 'global' }\n writeFileSync(configPath, JSON.stringify(config, null, 2) + '\\n')\n } catch {\n // ignore\n }\n }\n } else {\n saveLocalToken(token, options?.dir)\n }\n}\n\n/** Clear token from local .env (default) or global config */\nexport function clearToken(options?: { global?: boolean; dir?: string }) {\n if (options?.global) {\n clearGlobalToken()\n } else {\n clearLocalToken(options?.dir)\n }\n}\n\n// Legacy exports for backwards compat\nexport function saveConfig(config: Partial<GlobalConfig>) {\n saveGlobalConfig(config)\n}\n\nexport function clearConfig() {\n if (existsSync(GLOBAL_CONFIG_FILE)) {\n unlinkSync(GLOBAL_CONFIG_FILE)\n }\n}\n"],"mappings":"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","names":[]}
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  getConfig,
4
4
  getToken
5
- } from "./chunk-3DKWECRK.js";
5
+ } from "./chunk-5765WX4D.js";
6
6
 
7
7
  // src/api-client.ts
8
8
  var ApiError = class extends Error {
@@ -12,6 +12,24 @@ var ApiError = class extends Error {
12
12
  this.name = "ApiError";
13
13
  }
14
14
  };
15
+ var STATUS_HINTS = {
16
+ 401: "Try running `specra login` to re-authenticate.",
17
+ 403: "You may not have permission for this action. Check your plan or project access.",
18
+ 502: "The server is temporarily unavailable. Try again in a moment.",
19
+ 503: "The server is temporarily unavailable. Try again in a moment."
20
+ };
21
+ function formatError(context, err) {
22
+ const prefix = context ? `${context}: ` : "";
23
+ if (err instanceof ApiError) {
24
+ const hint = STATUS_HINTS[err.status] || "";
25
+ return `${prefix}${err.message} (${err.status})${hint ? `
26
+ ${hint}` : ""}`;
27
+ }
28
+ if (err instanceof Error) {
29
+ return `${prefix}${err.message}`;
30
+ }
31
+ return `${prefix}${String(err)}`;
32
+ }
15
33
  async function apiRequest(path, options = {}) {
16
34
  const config = getConfig();
17
35
  const token = getToken();
@@ -68,7 +86,9 @@ async function apiUpload(path, body, headers = {}) {
68
86
  }
69
87
 
70
88
  export {
89
+ ApiError,
90
+ formatError,
71
91
  apiRequest,
72
92
  apiUpload
73
93
  };
74
- //# sourceMappingURL=chunk-MA7QG54W.js.map
94
+ //# sourceMappingURL=chunk-72RDEJR2.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/api-client.ts"],"sourcesContent":["import { getConfig, getToken } from './config.js'\n\nexport class ApiError extends Error {\n constructor(public status: number, message: string) {\n super(message)\n this.name = 'ApiError'\n }\n}\n\nconst STATUS_HINTS: Record<number, string> = {\n 401: 'Try running `specra login` to re-authenticate.',\n 403: 'You may not have permission for this action. Check your plan or project access.',\n 502: 'The server is temporarily unavailable. Try again in a moment.',\n 503: 'The server is temporarily unavailable. Try again in a moment.',\n}\n\n/** Format an error for CLI display (no stack traces). */\nexport function formatError(context: string, err: unknown): string {\n const prefix = context ? `${context}: ` : ''\n if (err instanceof ApiError) {\n const hint = STATUS_HINTS[err.status] || ''\n return `${prefix}${err.message} (${err.status})${hint ? `\\n ${hint}` : ''}`\n }\n if (err instanceof Error) {\n return `${prefix}${err.message}`\n }\n return `${prefix}${String(err)}`\n}\n\nexport async function apiRequest<T = unknown>(\n path: string,\n options: RequestInit = {}\n): Promise<T> {\n const config = getConfig()\n const token = getToken()\n\n if (!token) {\n throw new Error('Not authenticated. Run `specra login` first.')\n }\n\n const url = `${config.apiUrl}${path}`\n const res = await fetch(url, {\n ...options,\n headers: {\n Authorization: `Bearer ${token}`,\n ...options.headers,\n },\n })\n\n if (!res.ok) {\n let message: string\n try {\n const data = (await res.json()) as Record<string, string>\n message = data.error || res.statusText\n } catch {\n message = res.statusText\n }\n throw new ApiError(res.status, message)\n }\n\n return res.json() as Promise<T>\n}\n\nexport async function apiUpload(\n path: string,\n body: Buffer | ReadableStream,\n headers: Record<string, string> = {}\n): Promise<unknown> {\n const config = getConfig()\n const token = getToken()\n\n if (!token) {\n throw new Error('Not authenticated. Run `specra login` first.')\n }\n\n const url = `${config.apiUrl}${path}`\n const res = await fetch(url, {\n method: 'POST',\n headers: {\n Authorization: `Bearer ${token}`,\n 'Content-Type': 'application/octet-stream',\n ...headers,\n },\n body,\n })\n\n if (!res.ok) {\n let message: string\n try {\n const data = (await res.json()) as Record<string, string>\n message = data.error || res.statusText\n } catch {\n message = res.statusText\n }\n throw new ApiError(res.status, message)\n }\n\n return res.json()\n}\n"],"mappings":";;;;;;;AAEO,IAAM,WAAN,cAAuB,MAAM;AAAA,EAClC,YAAmB,QAAgB,SAAiB;AAClD,UAAM,OAAO;AADI;AAEjB,SAAK,OAAO;AAAA,EACd;AACF;AAEA,IAAM,eAAuC;AAAA,EAC3C,KAAK;AAAA,EACL,KAAK;AAAA,EACL,KAAK;AAAA,EACL,KAAK;AACP;AAGO,SAAS,YAAY,SAAiB,KAAsB;AACjE,QAAM,SAAS,UAAU,GAAG,OAAO,OAAO;AAC1C,MAAI,eAAe,UAAU;AAC3B,UAAM,OAAO,aAAa,IAAI,MAAM,KAAK;AACzC,WAAO,GAAG,MAAM,GAAG,IAAI,OAAO,KAAK,IAAI,MAAM,IAAI,OAAO;AAAA,IAAO,IAAI,KAAK,EAAE;AAAA,EAC5E;AACA,MAAI,eAAe,OAAO;AACxB,WAAO,GAAG,MAAM,GAAG,IAAI,OAAO;AAAA,EAChC;AACA,SAAO,GAAG,MAAM,GAAG,OAAO,GAAG,CAAC;AAChC;AAEA,eAAsB,WACpB,MACA,UAAuB,CAAC,GACZ;AACZ,QAAM,SAAS,UAAU;AACzB,QAAM,QAAQ,SAAS;AAEvB,MAAI,CAAC,OAAO;AACV,UAAM,IAAI,MAAM,8CAA8C;AAAA,EAChE;AAEA,QAAM,MAAM,GAAG,OAAO,MAAM,GAAG,IAAI;AACnC,QAAM,MAAM,MAAM,MAAM,KAAK;AAAA,IAC3B,GAAG;AAAA,IACH,SAAS;AAAA,MACP,eAAe,UAAU,KAAK;AAAA,MAC9B,GAAG,QAAQ;AAAA,IACb;AAAA,EACF,CAAC;AAED,MAAI,CAAC,IAAI,IAAI;AACX,QAAI;AACJ,QAAI;AACF,YAAM,OAAQ,MAAM,IAAI,KAAK;AAC7B,gBAAU,KAAK,SAAS,IAAI;AAAA,IAC9B,QAAQ;AACN,gBAAU,IAAI;AAAA,IAChB;AACA,UAAM,IAAI,SAAS,IAAI,QAAQ,OAAO;AAAA,EACxC;AAEA,SAAO,IAAI,KAAK;AAClB;AAEA,eAAsB,UACpB,MACA,MACA,UAAkC,CAAC,GACjB;AAClB,QAAM,SAAS,UAAU;AACzB,QAAM,QAAQ,SAAS;AAEvB,MAAI,CAAC,OAAO;AACV,UAAM,IAAI,MAAM,8CAA8C;AAAA,EAChE;AAEA,QAAM,MAAM,GAAG,OAAO,MAAM,GAAG,IAAI;AACnC,QAAM,MAAM,MAAM,MAAM,KAAK;AAAA,IAC3B,QAAQ;AAAA,IACR,SAAS;AAAA,MACP,eAAe,UAAU,KAAK;AAAA,MAC9B,gBAAgB;AAAA,MAChB,GAAG;AAAA,IACL;AAAA,IACA;AAAA,EACF,CAAC;AAED,MAAI,CAAC,IAAI,IAAI;AACX,QAAI;AACJ,QAAI;AACF,YAAM,OAAQ,MAAM,IAAI,KAAK;AAC7B,gBAAU,KAAK,SAAS,IAAI;AAAA,IAC9B,QAAQ;AACN,gBAAU,IAAI;AAAA,IAChB;AACA,UAAM,IAAI,SAAS,IAAI,QAAQ,OAAO;AAAA,EACxC;AAEA,SAAO,IAAI,KAAK;AAClB;","names":[]}
@@ -0,0 +1,102 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/utils.ts
4
+ import validateNpmPackageName from "validate-npm-package-name";
5
+ import { execSync } from "child_process";
6
+ import fs from "fs";
7
+ import path from "path";
8
+ function validateProjectName(name) {
9
+ const validation = validateNpmPackageName(name);
10
+ if (validation.validForNewPackages) {
11
+ return { valid: true };
12
+ }
13
+ return {
14
+ valid: false,
15
+ problems: [
16
+ ...validation.errors || [],
17
+ ...validation.warnings || []
18
+ ]
19
+ };
20
+ }
21
+ function isWriteable(directory) {
22
+ try {
23
+ fs.accessSync(directory, fs.constants.W_OK);
24
+ return true;
25
+ } catch {
26
+ return false;
27
+ }
28
+ }
29
+ function isFolderEmpty(path2) {
30
+ const files = fs.readdirSync(path2);
31
+ return files.length === 0 || files.length === 1 && files[0] === ".git";
32
+ }
33
+ function getPackageManagerCommand(packageManager) {
34
+ switch (packageManager) {
35
+ case "yarn":
36
+ return {
37
+ install: "yarn install",
38
+ run: (script) => `yarn ${script}`
39
+ };
40
+ case "pnpm":
41
+ return {
42
+ install: "pnpm install",
43
+ run: (script) => `pnpm ${script}`
44
+ };
45
+ case "npm":
46
+ default:
47
+ return {
48
+ install: "npm install",
49
+ run: (script) => `npm run ${script}`
50
+ };
51
+ }
52
+ }
53
+ function detectPackageManager(dir) {
54
+ const configPath = path.join(dir, "specra.config.json");
55
+ try {
56
+ const config = JSON.parse(fs.readFileSync(configPath, "utf-8"));
57
+ if (config.packageManager) return config.packageManager;
58
+ } catch {
59
+ }
60
+ if (fs.existsSync(path.join(dir, "pnpm-lock.yaml"))) return "pnpm";
61
+ if (fs.existsSync(path.join(dir, "yarn.lock"))) return "yarn";
62
+ return "npm";
63
+ }
64
+ function tryGitInit(root) {
65
+ try {
66
+ execSync("git --version", { stdio: "ignore" });
67
+ execSync("git init", { cwd: root, stdio: "ignore" });
68
+ execSync("git add -A", { cwd: root, stdio: "ignore" });
69
+ execSync('git commit -m "Initial commit from create-specra"', {
70
+ cwd: root,
71
+ stdio: "ignore"
72
+ });
73
+ return true;
74
+ } catch {
75
+ return false;
76
+ }
77
+ }
78
+ function copyRecursive(src, dest) {
79
+ const stat = fs.statSync(src);
80
+ if (stat.isDirectory()) {
81
+ fs.mkdirSync(dest, { recursive: true });
82
+ const entries = fs.readdirSync(src);
83
+ for (const entry of entries) {
84
+ const srcPath = path.join(src, entry);
85
+ const destPath = path.join(dest, entry);
86
+ copyRecursive(srcPath, destPath);
87
+ }
88
+ } else {
89
+ fs.copyFileSync(src, dest);
90
+ }
91
+ }
92
+
93
+ export {
94
+ validateProjectName,
95
+ isWriteable,
96
+ isFolderEmpty,
97
+ getPackageManagerCommand,
98
+ detectPackageManager,
99
+ tryGitInit,
100
+ copyRecursive
101
+ };
102
+ //# sourceMappingURL=chunk-SQ2MMFUZ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/utils.ts"],"sourcesContent":["import validateNpmPackageName from 'validate-npm-package-name'\nimport { execSync } from 'child_process'\nimport fs from 'fs'\nimport path from 'path'\n\nexport function validateProjectName(name: string) {\n const validation = validateNpmPackageName(name)\n\n if (validation.validForNewPackages) {\n return { valid: true }\n }\n\n return {\n valid: false,\n problems: [\n ...(validation.errors || []),\n ...(validation.warnings || []),\n ],\n }\n}\n\nexport function isWriteable(directory: string): boolean {\n try {\n fs.accessSync(directory, fs.constants.W_OK)\n return true\n } catch {\n return false\n }\n}\n\nexport function isFolderEmpty(path: string): boolean {\n const files = fs.readdirSync(path)\n return files.length === 0 || (files.length === 1 && files[0] === '.git')\n}\n\nexport function getPackageManagerCommand(packageManager: string): {\n install: string\n run: (script: string) => string\n} {\n switch (packageManager) {\n case 'yarn':\n return {\n install: 'yarn install',\n run: (script) => `yarn ${script}`,\n }\n case 'pnpm':\n return {\n install: 'pnpm install',\n run: (script) => `pnpm ${script}`,\n }\n case 'npm':\n default:\n return {\n install: 'npm install',\n run: (script) => `npm run ${script}`,\n }\n }\n}\n\nexport function detectPackageManager(dir: string): string {\n // 1. Check specra.config.json for explicit setting\n const configPath = path.join(dir, 'specra.config.json')\n try {\n const config = JSON.parse(fs.readFileSync(configPath, 'utf-8'))\n if (config.packageManager) return config.packageManager\n } catch {\n // ignore\n }\n\n // 2. Detect from lockfiles\n if (fs.existsSync(path.join(dir, 'pnpm-lock.yaml'))) return 'pnpm'\n if (fs.existsSync(path.join(dir, 'yarn.lock'))) return 'yarn'\n return 'npm'\n}\n\nexport function tryGitInit(root: string): boolean {\n try {\n execSync('git --version', { stdio: 'ignore' })\n execSync('git init', { cwd: root, stdio: 'ignore' })\n execSync('git add -A', { cwd: root, stdio: 'ignore' })\n execSync('git commit -m \"Initial commit from create-specra\"', {\n cwd: root,\n stdio: 'ignore',\n })\n return true\n } catch {\n return false\n }\n}\n\nexport function copyRecursive(src: string, dest: string) {\n const stat = fs.statSync(src)\n\n if (stat.isDirectory()) {\n fs.mkdirSync(dest, { recursive: true })\n const entries = fs.readdirSync(src)\n\n for (const entry of entries) {\n const srcPath = path.join(src, entry)\n const destPath = path.join(dest, entry)\n copyRecursive(srcPath, destPath)\n }\n } else {\n fs.copyFileSync(src, dest)\n }\n}\n"],"mappings":";;;AAAA,OAAO,4BAA4B;AACnC,SAAS,gBAAgB;AACzB,OAAO,QAAQ;AACf,OAAO,UAAU;AAEV,SAAS,oBAAoB,MAAc;AAChD,QAAM,aAAa,uBAAuB,IAAI;AAE9C,MAAI,WAAW,qBAAqB;AAClC,WAAO,EAAE,OAAO,KAAK;AAAA,EACvB;AAEA,SAAO;AAAA,IACL,OAAO;AAAA,IACP,UAAU;AAAA,MACR,GAAI,WAAW,UAAU,CAAC;AAAA,MAC1B,GAAI,WAAW,YAAY,CAAC;AAAA,IAC9B;AAAA,EACF;AACF;AAEO,SAAS,YAAY,WAA4B;AACtD,MAAI;AACF,OAAG,WAAW,WAAW,GAAG,UAAU,IAAI;AAC1C,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEO,SAAS,cAAcA,OAAuB;AACnD,QAAM,QAAQ,GAAG,YAAYA,KAAI;AACjC,SAAO,MAAM,WAAW,KAAM,MAAM,WAAW,KAAK,MAAM,CAAC,MAAM;AACnE;AAEO,SAAS,yBAAyB,gBAGvC;AACA,UAAQ,gBAAgB;AAAA,IACtB,KAAK;AACH,aAAO;AAAA,QACL,SAAS;AAAA,QACT,KAAK,CAAC,WAAW,QAAQ,MAAM;AAAA,MACjC;AAAA,IACF,KAAK;AACH,aAAO;AAAA,QACL,SAAS;AAAA,QACT,KAAK,CAAC,WAAW,QAAQ,MAAM;AAAA,MACjC;AAAA,IACF,KAAK;AAAA,IACL;AACE,aAAO;AAAA,QACL,SAAS;AAAA,QACT,KAAK,CAAC,WAAW,WAAW,MAAM;AAAA,MACpC;AAAA,EACJ;AACF;AAEO,SAAS,qBAAqB,KAAqB;AAExD,QAAM,aAAa,KAAK,KAAK,KAAK,oBAAoB;AACtD,MAAI;AACF,UAAM,SAAS,KAAK,MAAM,GAAG,aAAa,YAAY,OAAO,CAAC;AAC9D,QAAI,OAAO,eAAgB,QAAO,OAAO;AAAA,EAC3C,QAAQ;AAAA,EAER;AAGA,MAAI,GAAG,WAAW,KAAK,KAAK,KAAK,gBAAgB,CAAC,EAAG,QAAO;AAC5D,MAAI,GAAG,WAAW,KAAK,KAAK,KAAK,WAAW,CAAC,EAAG,QAAO;AACvD,SAAO;AACT;AAEO,SAAS,WAAW,MAAuB;AAChD,MAAI;AACF,aAAS,iBAAiB,EAAE,OAAO,SAAS,CAAC;AAC7C,aAAS,YAAY,EAAE,KAAK,MAAM,OAAO,SAAS,CAAC;AACnD,aAAS,cAAc,EAAE,KAAK,MAAM,OAAO,SAAS,CAAC;AACrD,aAAS,qDAAqD;AAAA,MAC5D,KAAK;AAAA,MACL,OAAO;AAAA,IACT,CAAC;AACD,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEO,SAAS,cAAc,KAAa,MAAc;AACvD,QAAM,OAAO,GAAG,SAAS,GAAG;AAE5B,MAAI,KAAK,YAAY,GAAG;AACtB,OAAG,UAAU,MAAM,EAAE,WAAW,KAAK,CAAC;AACtC,UAAM,UAAU,GAAG,YAAY,GAAG;AAElC,eAAW,SAAS,SAAS;AAC3B,YAAM,UAAU,KAAK,KAAK,KAAK,KAAK;AACpC,YAAM,WAAW,KAAK,KAAK,MAAM,KAAK;AACtC,oBAAc,SAAS,QAAQ;AAAA,IACjC;AAAA,EACF,OAAO;AACL,OAAG,aAAa,KAAK,IAAI;AAAA,EAC3B;AACF;","names":["path"]}
package/dist/cli.js CHANGED
@@ -3,28 +3,35 @@
3
3
  // src/cli.ts
4
4
  import { Command } from "commander";
5
5
  import pc from "picocolors";
6
+ import { createRequire } from "module";
7
+ var require2 = createRequire(import.meta.url);
8
+ var { version } = require2("../package.json");
6
9
  var program = new Command();
7
- program.name("specra").description("Specra CLI - Deploy and manage your documentation sites").version("0.1.0");
8
- program.command("login").description("Authenticate with your Specra account").action(async () => {
9
- const { login } = await import("./login-NKDRQXRE.js");
10
- await login();
10
+ program.name("specra").description("Specra CLI - Deploy and manage your documentation sites").version(version);
11
+ program.command("login").description("Authenticate with your Specra account").option("-g, --global", "Store credentials in ~/.specra/ instead of local specra.config.json").action(async (options) => {
12
+ const { login } = await import("./login-UG3WU7DY.js");
13
+ await login(options);
11
14
  });
12
- program.command("logout").description("Clear stored credentials").action(async () => {
13
- const { logout } = await import("./logout-H543QEKU.js");
14
- await logout();
15
+ program.command("logout").description("Clear stored credentials").option("-g, --global", "Clear credentials from ~/.specra/ instead of local specra.config.json").action(async (options) => {
16
+ const { logout } = await import("./logout-WJKHJZT6.js");
17
+ await logout(options);
15
18
  });
16
- program.command("deploy").description("Deploy your docs project").option("-p, --project <id>", "Project ID to deploy to").option("-d, --dir <directory>", "Docs directory to deploy", ".").action(async (options) => {
17
- const { deploy } = await import("./deploy-SCEMUQNS.js");
19
+ program.command("deploy").description("Deploy your docs project").option("-p, --project <id>", "Project ID to deploy to").option("-d, --dir <directory>", "Docs directory to deploy", ".").option("-v, --verbose", "Show detailed build output and logs").action(async (options) => {
20
+ const { deploy } = await import("./deploy-V4JO2D6B.js");
18
21
  await deploy(options);
19
22
  });
20
23
  program.command("projects").description("List your projects").action(async () => {
21
- const { projects } = await import("./projects-3TAY7EDJ.js");
24
+ const { projects } = await import("./projects-LJ57GK3D.js");
22
25
  await projects();
23
26
  });
24
27
  program.command("logs").description("View deployment logs").argument("<projectId>", "Project ID").option("--deployment <id>", "Specific deployment ID").action(async (projectId, options) => {
25
- const { logs } = await import("./logs-YDAUCMAV.js");
28
+ const { logs } = await import("./logs-BLUJPWNO.js");
26
29
  await logs(projectId, options);
27
30
  });
31
+ program.command("doctor").description("Check specra.config.json for issues").option("-d, --dir <directory>", "Project directory to check", ".").action(async (options) => {
32
+ const { doctor } = await import("./doctor-ICALAJ4N.js");
33
+ await doctor(options);
34
+ });
28
35
  program.parse();
29
36
  process.on("unhandledRejection", (err) => {
30
37
  console.error(pc.red("Error:"), err);
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/cli.ts"],"sourcesContent":["import { Command } from 'commander'\nimport pc from 'picocolors'\n\nconst program = new Command()\n\nprogram\n .name('specra')\n .description('Specra CLI - Deploy and manage your documentation sites')\n .version('0.1.0')\n\nprogram\n .command('login')\n .description('Authenticate with your Specra account')\n .action(async () => {\n const { login } = await import('./commands/login.js')\n await login()\n })\n\nprogram\n .command('logout')\n .description('Clear stored credentials')\n .action(async () => {\n const { logout } = await import('./commands/logout.js')\n await logout()\n })\n\nprogram\n .command('deploy')\n .description('Deploy your docs project')\n .option('-p, --project <id>', 'Project ID to deploy to')\n .option('-d, --dir <directory>', 'Docs directory to deploy', '.')\n .action(async (options) => {\n const { deploy } = await import('./commands/deploy.js')\n await deploy(options)\n })\n\nprogram\n .command('projects')\n .description('List your projects')\n .action(async () => {\n const { projects } = await import('./commands/projects.js')\n await projects()\n })\n\nprogram\n .command('logs')\n .description('View deployment logs')\n .argument('<projectId>', 'Project ID')\n .option('--deployment <id>', 'Specific deployment ID')\n .action(async (projectId: string, options) => {\n const { logs } = await import('./commands/logs.js')\n await logs(projectId, options)\n })\n\nprogram.parse()\n\n// Handle unhandled rejections\nprocess.on('unhandledRejection', (err) => {\n console.error(pc.red('Error:'), err)\n process.exit(1)\n})\n"],"mappings":";;;AAAA,SAAS,eAAe;AACxB,OAAO,QAAQ;AAEf,IAAM,UAAU,IAAI,QAAQ;AAE5B,QACG,KAAK,QAAQ,EACb,YAAY,yDAAyD,EACrE,QAAQ,OAAO;AAElB,QACG,QAAQ,OAAO,EACf,YAAY,uCAAuC,EACnD,OAAO,YAAY;AAClB,QAAM,EAAE,MAAM,IAAI,MAAM,OAAO,qBAAqB;AACpD,QAAM,MAAM;AACd,CAAC;AAEH,QACG,QAAQ,QAAQ,EAChB,YAAY,0BAA0B,EACtC,OAAO,YAAY;AAClB,QAAM,EAAE,OAAO,IAAI,MAAM,OAAO,sBAAsB;AACtD,QAAM,OAAO;AACf,CAAC;AAEH,QACG,QAAQ,QAAQ,EAChB,YAAY,0BAA0B,EACtC,OAAO,sBAAsB,yBAAyB,EACtD,OAAO,yBAAyB,4BAA4B,GAAG,EAC/D,OAAO,OAAO,YAAY;AACzB,QAAM,EAAE,OAAO,IAAI,MAAM,OAAO,sBAAsB;AACtD,QAAM,OAAO,OAAO;AACtB,CAAC;AAEH,QACG,QAAQ,UAAU,EAClB,YAAY,oBAAoB,EAChC,OAAO,YAAY;AAClB,QAAM,EAAE,SAAS,IAAI,MAAM,OAAO,wBAAwB;AAC1D,QAAM,SAAS;AACjB,CAAC;AAEH,QACG,QAAQ,MAAM,EACd,YAAY,sBAAsB,EAClC,SAAS,eAAe,YAAY,EACpC,OAAO,qBAAqB,wBAAwB,EACpD,OAAO,OAAO,WAAmB,YAAY;AAC5C,QAAM,EAAE,KAAK,IAAI,MAAM,OAAO,oBAAoB;AAClD,QAAM,KAAK,WAAW,OAAO;AAC/B,CAAC;AAEH,QAAQ,MAAM;AAGd,QAAQ,GAAG,sBAAsB,CAAC,QAAQ;AACxC,UAAQ,MAAM,GAAG,IAAI,QAAQ,GAAG,GAAG;AACnC,UAAQ,KAAK,CAAC;AAChB,CAAC;","names":[]}
1
+ {"version":3,"sources":["../src/cli.ts"],"sourcesContent":["import { Command } from 'commander'\nimport pc from 'picocolors'\nimport { createRequire } from 'module'\n\nconst require = createRequire(import.meta.url)\nconst { version } = require('../package.json')\n\nconst program = new Command()\n\nprogram\n .name('specra')\n .description('Specra CLI - Deploy and manage your documentation sites')\n .version(version)\n\nprogram\n .command('login')\n .description('Authenticate with your Specra account')\n .option('-g, --global', 'Store credentials in ~/.specra/ instead of local specra.config.json')\n .action(async (options) => {\n const { login } = await import('./commands/login.js')\n await login(options)\n })\n\nprogram\n .command('logout')\n .description('Clear stored credentials')\n .option('-g, --global', 'Clear credentials from ~/.specra/ instead of local specra.config.json')\n .action(async (options) => {\n const { logout } = await import('./commands/logout.js')\n await logout(options)\n })\n\nprogram\n .command('deploy')\n .description('Deploy your docs project')\n .option('-p, --project <id>', 'Project ID to deploy to')\n .option('-d, --dir <directory>', 'Docs directory to deploy', '.')\n .option('-v, --verbose', 'Show detailed build output and logs')\n .action(async (options) => {\n const { deploy } = await import('./commands/deploy.js')\n await deploy(options)\n })\n\nprogram\n .command('projects')\n .description('List your projects')\n .action(async () => {\n const { projects } = await import('./commands/projects.js')\n await projects()\n })\n\nprogram\n .command('logs')\n .description('View deployment logs')\n .argument('<projectId>', 'Project ID')\n .option('--deployment <id>', 'Specific deployment ID')\n .action(async (projectId: string, options) => {\n const { logs } = await import('./commands/logs.js')\n await logs(projectId, options)\n })\n\nprogram\n .command('doctor')\n .description('Check specra.config.json for issues')\n .option('-d, --dir <directory>', 'Project directory to check', '.')\n .action(async (options) => {\n const { doctor } = await import('./commands/doctor.js')\n await doctor(options)\n })\n\nprogram.parse()\n\n// Handle unhandled rejections\nprocess.on('unhandledRejection', (err) => {\n console.error(pc.red('Error:'), err)\n process.exit(1)\n})\n"],"mappings":";;;AAAA,SAAS,eAAe;AACxB,OAAO,QAAQ;AACf,SAAS,qBAAqB;AAE9B,IAAMA,WAAU,cAAc,YAAY,GAAG;AAC7C,IAAM,EAAE,QAAQ,IAAIA,SAAQ,iBAAiB;AAE7C,IAAM,UAAU,IAAI,QAAQ;AAE5B,QACG,KAAK,QAAQ,EACb,YAAY,yDAAyD,EACrE,QAAQ,OAAO;AAElB,QACG,QAAQ,OAAO,EACf,YAAY,uCAAuC,EACnD,OAAO,gBAAgB,qEAAqE,EAC5F,OAAO,OAAO,YAAY;AACzB,QAAM,EAAE,MAAM,IAAI,MAAM,OAAO,qBAAqB;AACpD,QAAM,MAAM,OAAO;AACrB,CAAC;AAEH,QACG,QAAQ,QAAQ,EAChB,YAAY,0BAA0B,EACtC,OAAO,gBAAgB,uEAAuE,EAC9F,OAAO,OAAO,YAAY;AACzB,QAAM,EAAE,OAAO,IAAI,MAAM,OAAO,sBAAsB;AACtD,QAAM,OAAO,OAAO;AACtB,CAAC;AAEH,QACG,QAAQ,QAAQ,EAChB,YAAY,0BAA0B,EACtC,OAAO,sBAAsB,yBAAyB,EACtD,OAAO,yBAAyB,4BAA4B,GAAG,EAC/D,OAAO,iBAAiB,qCAAqC,EAC7D,OAAO,OAAO,YAAY;AACzB,QAAM,EAAE,OAAO,IAAI,MAAM,OAAO,sBAAsB;AACtD,QAAM,OAAO,OAAO;AACtB,CAAC;AAEH,QACG,QAAQ,UAAU,EAClB,YAAY,oBAAoB,EAChC,OAAO,YAAY;AAClB,QAAM,EAAE,SAAS,IAAI,MAAM,OAAO,wBAAwB;AAC1D,QAAM,SAAS;AACjB,CAAC;AAEH,QACG,QAAQ,MAAM,EACd,YAAY,sBAAsB,EAClC,SAAS,eAAe,YAAY,EACpC,OAAO,qBAAqB,wBAAwB,EACpD,OAAO,OAAO,WAAmB,YAAY;AAC5C,QAAM,EAAE,KAAK,IAAI,MAAM,OAAO,oBAAoB;AAClD,QAAM,KAAK,WAAW,OAAO;AAC/B,CAAC;AAEH,QACG,QAAQ,QAAQ,EAChB,YAAY,qCAAqC,EACjD,OAAO,yBAAyB,8BAA8B,GAAG,EACjE,OAAO,OAAO,YAAY;AACzB,QAAM,EAAE,OAAO,IAAI,MAAM,OAAO,sBAAsB;AACtD,QAAM,OAAO,OAAO;AACtB,CAAC;AAEH,QAAQ,MAAM;AAGd,QAAQ,GAAG,sBAAsB,CAAC,QAAQ;AACxC,UAAQ,MAAM,GAAG,IAAI,QAAQ,GAAG,GAAG;AACnC,UAAQ,KAAK,CAAC;AAChB,CAAC;","names":["require"]}