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.
- package/README.md +11 -14
- package/dist/api-client-VHQARPDT.js +15 -0
- package/dist/api-client-VHQARPDT.js.map +1 -0
- package/dist/chunk-5765WX4D.js +192 -0
- package/dist/chunk-5765WX4D.js.map +1 -0
- package/dist/{chunk-MA7QG54W.js → chunk-72RDEJR2.js} +22 -2
- package/dist/chunk-72RDEJR2.js.map +1 -0
- package/dist/chunk-SQ2MMFUZ.js +102 -0
- package/dist/chunk-SQ2MMFUZ.js.map +1 -0
- package/dist/cli.js +18 -11
- package/dist/cli.js.map +1 -1
- package/dist/{deploy-SCEMUQNS.js → deploy-V4JO2D6B.js} +74 -36
- package/dist/deploy-V4JO2D6B.js.map +1 -0
- package/dist/doctor-ICALAJ4N.js +309 -0
- package/dist/doctor-ICALAJ4N.js.map +1 -0
- package/dist/index.js +72 -105
- package/dist/index.js.map +1 -1
- package/dist/{login-NKDRQXRE.js → login-UG3WU7DY.js} +36 -15
- package/dist/login-UG3WU7DY.js.map +1 -0
- package/dist/logout-WJKHJZT6.js +24 -0
- package/dist/logout-WJKHJZT6.js.map +1 -0
- package/dist/{logs-YDAUCMAV.js → logs-BLUJPWNO.js} +26 -20
- package/dist/logs-BLUJPWNO.js.map +1 -0
- package/dist/{projects-3TAY7EDJ.js → projects-LJ57GK3D.js} +13 -6
- package/dist/projects-LJ57GK3D.js.map +1 -0
- package/package.json +3 -2
- package/templates/book-docs/.env.sample +1 -0
- package/templates/book-docs/package.json +1 -1
- package/templates/book-docs/src/app.css +3 -4
- package/templates/book-docs/src/routes/+layout.server.ts +3 -0
- package/templates/book-docs/src/routes/docs/[version]/[...slug]/+page.server.ts +1 -1
- package/templates/book-docs/svelte.config.js +6 -1
- package/templates/jbrains-docs/.env.sample +1 -0
- package/templates/jbrains-docs/package.json +1 -1
- package/templates/jbrains-docs/src/app.css +3 -4
- package/templates/jbrains-docs/src/routes/+layout.server.ts +3 -0
- package/templates/jbrains-docs/src/routes/docs/[version]/[...slug]/+page.server.ts +1 -1
- package/templates/jbrains-docs/svelte.config.js +6 -1
- package/templates/minimal/.env.sample +1 -0
- package/templates/minimal/package.json +1 -1
- package/templates/minimal/specra.config.json +13 -1
- package/templates/minimal/src/app.css +3 -4
- package/templates/minimal/src/hooks.server.ts +8 -0
- package/templates/minimal/src/routes/+error.svelte +10 -0
- package/templates/minimal/src/routes/+layout.server.ts +3 -0
- package/templates/minimal/src/routes/+page.svelte +149 -0
- package/templates/minimal/src/routes/docs/[version]/+page.server.ts +14 -0
- package/templates/minimal/src/routes/docs/[version]/[...slug]/+page.server.ts +1 -1
- package/templates/minimal/svelte.config.js +6 -1
- package/dist/chunk-3DKWECRK.js +0 -45
- package/dist/chunk-3DKWECRK.js.map +0 -1
- package/dist/chunk-MA7QG54W.js.map +0 -1
- package/dist/deploy-SCEMUQNS.js.map +0 -1
- package/dist/login-NKDRQXRE.js.map +0 -1
- package/dist/logout-H543QEKU.js +0 -20
- package/dist/logout-H543QEKU.js.map +0 -1
- package/dist/logs-YDAUCMAV.js.map +0 -1
- package/dist/projects-3TAY7EDJ.js.map +0 -1
- /package/templates/minimal/{public → static}/api-specs/openapi-example.json +0 -0
- /package/templates/minimal/{public → static}/api-specs/postman-example.json +0 -0
- /package/templates/minimal/{public → static}/api-specs/test-api.json +0 -0
- /package/templates/minimal/{public → static}/api-specs/users-api.json +0 -0
package/dist/index.js
CHANGED
|
@@ -1,105 +1,33 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
copyRecursive,
|
|
4
|
+
getPackageManagerCommand,
|
|
5
|
+
isFolderEmpty,
|
|
6
|
+
isWriteable,
|
|
7
|
+
tryGitInit,
|
|
8
|
+
validateProjectName
|
|
9
|
+
} from "./chunk-SQ2MMFUZ.js";
|
|
2
10
|
|
|
3
11
|
// src/index.ts
|
|
4
12
|
import { Command } from "commander";
|
|
5
13
|
import prompts from "prompts";
|
|
6
|
-
|
|
7
|
-
// src/create-project.ts
|
|
8
|
-
import fs2 from "fs";
|
|
9
14
|
import path2 from "path";
|
|
10
|
-
import { fileURLToPath } from "url";
|
|
11
|
-
import { execSync as execSync2 } from "child_process";
|
|
12
|
-
import pc from "picocolors";
|
|
13
15
|
|
|
14
|
-
// src/
|
|
15
|
-
import validateNpmPackageName from "validate-npm-package-name";
|
|
16
|
-
import { execSync } from "child_process";
|
|
16
|
+
// src/create-project.ts
|
|
17
17
|
import fs from "fs";
|
|
18
18
|
import path from "path";
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
return { valid: true };
|
|
23
|
-
}
|
|
24
|
-
return {
|
|
25
|
-
valid: false,
|
|
26
|
-
problems: [
|
|
27
|
-
...validation.errors || [],
|
|
28
|
-
...validation.warnings || []
|
|
29
|
-
]
|
|
30
|
-
};
|
|
31
|
-
}
|
|
32
|
-
function isWriteable(directory) {
|
|
33
|
-
try {
|
|
34
|
-
fs.accessSync(directory, fs.constants.W_OK);
|
|
35
|
-
return true;
|
|
36
|
-
} catch {
|
|
37
|
-
return false;
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
function isFolderEmpty(path3) {
|
|
41
|
-
const files = fs.readdirSync(path3);
|
|
42
|
-
return files.length === 0 || files.length === 1 && files[0] === ".git";
|
|
43
|
-
}
|
|
44
|
-
function getPackageManagerCommand(packageManager) {
|
|
45
|
-
switch (packageManager) {
|
|
46
|
-
case "yarn":
|
|
47
|
-
return {
|
|
48
|
-
install: "yarn install",
|
|
49
|
-
run: (script) => `yarn ${script}`
|
|
50
|
-
};
|
|
51
|
-
case "pnpm":
|
|
52
|
-
return {
|
|
53
|
-
install: "pnpm install",
|
|
54
|
-
run: (script) => `pnpm ${script}`
|
|
55
|
-
};
|
|
56
|
-
case "npm":
|
|
57
|
-
default:
|
|
58
|
-
return {
|
|
59
|
-
install: "npm install",
|
|
60
|
-
run: (script) => `npm run ${script}`
|
|
61
|
-
};
|
|
62
|
-
}
|
|
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
|
-
// src/create-project.ts
|
|
19
|
+
import { fileURLToPath } from "url";
|
|
20
|
+
import { execSync } from "child_process";
|
|
21
|
+
import pc from "picocolors";
|
|
94
22
|
async function createProject({
|
|
95
23
|
projectName,
|
|
96
24
|
template,
|
|
97
25
|
packageManager,
|
|
98
26
|
skipInstall
|
|
99
27
|
}) {
|
|
100
|
-
const root =
|
|
101
|
-
const appName =
|
|
102
|
-
if (
|
|
28
|
+
const root = path.resolve(projectName);
|
|
29
|
+
const appName = path.basename(root);
|
|
30
|
+
if (fs.existsSync(root)) {
|
|
103
31
|
if (!isWriteable(root)) {
|
|
104
32
|
console.error(
|
|
105
33
|
pc.red(`The directory ${pc.cyan(projectName)} is not writable.`)
|
|
@@ -117,34 +45,40 @@ async function createProject({
|
|
|
117
45
|
process.exit(1);
|
|
118
46
|
}
|
|
119
47
|
} else {
|
|
120
|
-
|
|
48
|
+
fs.mkdirSync(root, { recursive: true });
|
|
121
49
|
}
|
|
122
|
-
console.log(`Creating a new Specra documentation site in ${pc.cyan(root)}`);
|
|
50
|
+
console.log(`Creating a new Specra documentation site (SvelteKit) in ${pc.cyan(root)}`);
|
|
123
51
|
console.log();
|
|
124
52
|
const __filename2 = fileURLToPath(import.meta.url);
|
|
125
|
-
const __dirname2 =
|
|
126
|
-
const templateDir =
|
|
127
|
-
if (!
|
|
53
|
+
const __dirname2 = path.dirname(__filename2);
|
|
54
|
+
const templateDir = path.join(__dirname2, "..", "templates", template);
|
|
55
|
+
if (!fs.existsSync(templateDir)) {
|
|
128
56
|
console.error(pc.red(`Template ${pc.cyan(template)} not found.`));
|
|
129
57
|
process.exit(1);
|
|
130
58
|
}
|
|
131
59
|
console.log(`Using template: ${pc.cyan(template)}`);
|
|
132
60
|
console.log();
|
|
133
61
|
copyRecursive(templateDir, root);
|
|
134
|
-
const packageJsonPath =
|
|
135
|
-
const packageJson = JSON.parse(
|
|
62
|
+
const packageJsonPath = path.join(root, "package.json");
|
|
63
|
+
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf8"));
|
|
136
64
|
packageJson.name = appName;
|
|
137
|
-
|
|
138
|
-
const
|
|
139
|
-
if (
|
|
140
|
-
|
|
65
|
+
fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2) + "\n");
|
|
66
|
+
const specraConfigPath = path.join(root, "specra.config.json");
|
|
67
|
+
if (fs.existsSync(specraConfigPath)) {
|
|
68
|
+
const specraConfig = JSON.parse(fs.readFileSync(specraConfigPath, "utf8"));
|
|
69
|
+
specraConfig.packageManager = packageManager;
|
|
70
|
+
fs.writeFileSync(specraConfigPath, JSON.stringify(specraConfig, null, 2) + "\n");
|
|
71
|
+
}
|
|
72
|
+
const gitignorePath = path.join(root, "gitignore");
|
|
73
|
+
if (fs.existsSync(gitignorePath)) {
|
|
74
|
+
fs.renameSync(gitignorePath, path.join(root, ".gitignore"));
|
|
141
75
|
}
|
|
142
76
|
if (!skipInstall) {
|
|
143
77
|
console.log("Installing dependencies...");
|
|
144
78
|
console.log();
|
|
145
79
|
const command2 = getPackageManagerCommand(packageManager);
|
|
146
80
|
try {
|
|
147
|
-
|
|
81
|
+
execSync(command2.install, { cwd: root, stdio: "inherit" });
|
|
148
82
|
} catch (error) {
|
|
149
83
|
console.error(pc.red("Failed to install dependencies."));
|
|
150
84
|
process.exit(1);
|
|
@@ -166,8 +100,8 @@ async function createProject({
|
|
|
166
100
|
console.log(pc.cyan(` ${command.run("build")}`));
|
|
167
101
|
console.log(" Builds the app for production.");
|
|
168
102
|
console.log();
|
|
169
|
-
console.log(pc.cyan(` ${command.run("
|
|
170
|
-
console.log("
|
|
103
|
+
console.log(pc.cyan(` ${command.run("preview")}`));
|
|
104
|
+
console.log(" Previews the built app locally.");
|
|
171
105
|
console.log();
|
|
172
106
|
console.log("We suggest that you begin by typing:");
|
|
173
107
|
console.log();
|
|
@@ -178,8 +112,12 @@ async function createProject({
|
|
|
178
112
|
|
|
179
113
|
// src/index.ts
|
|
180
114
|
import pc2 from "picocolors";
|
|
115
|
+
import { createRequire } from "module";
|
|
116
|
+
var require2 = createRequire(import.meta.url);
|
|
117
|
+
var { version } = require2("../package.json");
|
|
181
118
|
var program = new Command();
|
|
182
|
-
program.name("create-specra").description("
|
|
119
|
+
program.name("create-specra").description("Specra CLI - Create, deploy, and manage your documentation sites").version(version);
|
|
120
|
+
var initCmd = program.command("init [project-directory]", { isDefault: true }).description("Create a new Specra documentation site").option("--template <template>", "Template to use (minimal)").option("--use-npm", "Use npm as the package manager").option("--use-pnpm", "Use pnpm as the package manager").option("--use-yarn", "Use yarn as the package manager").option("--skip-install", "Skip package installation").action(async (projectDirectory, options) => {
|
|
183
121
|
console.log();
|
|
184
122
|
console.log(pc2.bold(pc2.cyan("Create Specra Documentation Site")));
|
|
185
123
|
console.log();
|
|
@@ -205,12 +143,13 @@ program.name("create-specra").description("Create a new Specra documentation sit
|
|
|
205
143
|
}
|
|
206
144
|
projectName = response.projectName;
|
|
207
145
|
}
|
|
208
|
-
const
|
|
146
|
+
const projectBaseName = path2.basename(path2.resolve(projectName));
|
|
147
|
+
const validation = validateProjectName(projectBaseName);
|
|
209
148
|
if (!validation.valid) {
|
|
210
149
|
console.error(
|
|
211
150
|
pc2.red(
|
|
212
151
|
`Cannot create a project named ${pc2.cyan(
|
|
213
|
-
`"${
|
|
152
|
+
`"${projectBaseName}"`
|
|
214
153
|
)} because of npm naming restrictions:
|
|
215
154
|
`
|
|
216
155
|
)
|
|
@@ -275,7 +214,7 @@ program.name("create-specra").description("Create a new Specra documentation sit
|
|
|
275
214
|
try {
|
|
276
215
|
await createProject({
|
|
277
216
|
projectName,
|
|
278
|
-
template: template || "
|
|
217
|
+
template: template || "minimal",
|
|
279
218
|
packageManager: packageManager || "npm",
|
|
280
219
|
skipInstall: options.skipInstall
|
|
281
220
|
});
|
|
@@ -285,5 +224,33 @@ program.name("create-specra").description("Create a new Specra documentation sit
|
|
|
285
224
|
process.exit(1);
|
|
286
225
|
}
|
|
287
226
|
});
|
|
227
|
+
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) => {
|
|
228
|
+
const { login } = await import("./login-UG3WU7DY.js");
|
|
229
|
+
await login(options);
|
|
230
|
+
});
|
|
231
|
+
program.command("logout").description("Clear stored credentials").option("-g, --global", "Clear credentials from ~/.specra/ instead of local specra.config.json").action(async (options) => {
|
|
232
|
+
const { logout } = await import("./logout-WJKHJZT6.js");
|
|
233
|
+
await logout(options);
|
|
234
|
+
});
|
|
235
|
+
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) => {
|
|
236
|
+
const { deploy } = await import("./deploy-V4JO2D6B.js");
|
|
237
|
+
await deploy(options);
|
|
238
|
+
});
|
|
239
|
+
program.command("projects").description("List your projects").action(async () => {
|
|
240
|
+
const { projects } = await import("./projects-LJ57GK3D.js");
|
|
241
|
+
await projects();
|
|
242
|
+
});
|
|
243
|
+
program.command("logs").description("View deployment logs").argument("<projectId>", "Project ID").option("--deployment <id>", "Specific deployment ID").action(async (projectId, options) => {
|
|
244
|
+
const { logs } = await import("./logs-BLUJPWNO.js");
|
|
245
|
+
await logs(projectId, options);
|
|
246
|
+
});
|
|
247
|
+
program.command("doctor").description("Check specra.config.json for issues").option("-d, --dir <directory>", "Project directory to check", ".").action(async (options) => {
|
|
248
|
+
const { doctor } = await import("./doctor-ICALAJ4N.js");
|
|
249
|
+
await doctor(options);
|
|
250
|
+
});
|
|
288
251
|
program.parse();
|
|
252
|
+
process.on("unhandledRejection", (err) => {
|
|
253
|
+
console.error(pc2.red("Error:"), err);
|
|
254
|
+
process.exit(1);
|
|
255
|
+
});
|
|
289
256
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/create-project.ts","../src/utils.ts"],"sourcesContent":["import { Command } from 'commander'\nimport prompts from 'prompts'\nimport { createProject } from './create-project.js'\nimport { validateProjectName } from './utils.js'\nimport pc from 'picocolors'\n\nconst program = new Command()\n\nprogram\n .name('create-specra')\n .description('Create a new Specra documentation site')\n .argument('[project-directory]', 'Directory to create the project in')\n .option('--template <template>', 'Template to use (minimal, book-docs, jbrains-docs)')\n .option('--use-npm', 'Use npm as the package manager')\n .option('--use-pnpm', 'Use pnpm as the package manager')\n .option('--use-yarn', 'Use yarn as the package manager')\n .option('--skip-install', 'Skip package installation')\n .action(async (projectDirectory: string | undefined, options) => {\n console.log()\n console.log(pc.bold(pc.cyan('Create Specra Documentation Site')))\n console.log()\n\n let projectName = projectDirectory\n\n // Prompt for project name if not provided\n if (!projectName) {\n const response = await prompts({\n type: 'text',\n name: 'projectName',\n message: 'What is your project named?',\n initial: 'my-docs',\n validate: (name) => {\n const validation = validateProjectName(name)\n if (validation.valid) {\n return true\n }\n return validation.problems![0]\n },\n })\n\n if (!response.projectName) {\n console.log()\n console.log('Aborting.')\n process.exit(1)\n }\n\n projectName = response.projectName\n }\n\n // Validate project name\n const validation = validateProjectName(projectName!)\n if (!validation.valid) {\n console.error(\n pc.red(\n `Cannot create a project named ${pc.cyan(\n `\"${projectName}\"`\n )} because of npm naming restrictions:\\n`\n )\n )\n validation.problems!.forEach((p) =>\n console.error(` ${pc.red('•')} ${p}`)\n )\n process.exit(1)\n }\n\n // Prompt for template if not provided\n let template = options.template\n\n if (!template) {\n const response = await prompts({\n type: 'select',\n name: 'template',\n message: 'Which template would you like to use?',\n choices: [\n {\n title: 'Minimal',\n value: 'minimal',\n description: 'Minimal setup to get started quickly',\n },\n {\n title: 'Book Docs',\n value: 'book-docs',\n description: 'Knowledge base style with dark theme and categorized sidebar',\n },\n {\n title: 'JBrains Docs',\n value: 'jbrains-docs',\n description: 'Reference docs style with light theme and tab groups',\n },\n ],\n initial: 0,\n })\n\n if (!response.template) {\n console.log()\n console.log('Aborting.')\n process.exit(1)\n }\n\n template = response.template\n }\n\n // Detect or prompt for package manager\n let packageManager = options.useNpm\n ? 'npm'\n : options.usePnpm\n ? 'pnpm'\n : options.useYarn\n ? 'yarn'\n : undefined\n\n if (!packageManager && !options.skipInstall) {\n const response = await prompts({\n type: 'select',\n name: 'packageManager',\n message: 'Which package manager do you want to use?',\n choices: [\n { title: 'npm', value: 'npm' },\n { title: 'yarn', value: 'yarn' },\n { title: 'pnpm', value: 'pnpm' },\n ],\n initial: 0,\n })\n\n if (!response.packageManager) {\n console.log()\n console.log('Aborting.')\n process.exit(1)\n }\n\n packageManager = response.packageManager\n }\n\n // Create the project\n try {\n await createProject({\n projectName: projectName!,\n template: template || 'default',\n packageManager: packageManager || 'npm',\n skipInstall: options.skipInstall,\n })\n } catch (error) {\n console.error(pc.red('\\nError creating project:'))\n console.error(error)\n process.exit(1)\n }\n })\n\nprogram.parse()\n","import fs from 'fs'\nimport path from 'path'\nimport { fileURLToPath } from 'url'\nimport { execSync } from 'child_process'\nimport pc from 'picocolors'\nimport {\n isWriteable,\n isFolderEmpty,\n getPackageManagerCommand,\n tryGitInit,\n copyRecursive,\n} from './utils.js'\n\ninterface CreateProjectOptions {\n projectName: string\n template: string\n packageManager: string\n skipInstall: boolean\n}\n\nexport async function createProject({\n projectName,\n template,\n packageManager,\n skipInstall,\n}: CreateProjectOptions) {\n const root = path.resolve(projectName)\n const appName = path.basename(root)\n\n // Check if directory exists\n if (fs.existsSync(root)) {\n if (!isWriteable(root)) {\n console.error(\n pc.red(`The directory ${pc.cyan(projectName)} is not writable.`)\n )\n process.exit(1)\n }\n\n if (!isFolderEmpty(root)) {\n console.error(\n pc.red(\n `The directory ${pc.cyan(\n projectName\n )} contains files that could conflict. Please use a new directory.`\n )\n )\n process.exit(1)\n }\n } else {\n fs.mkdirSync(root, { recursive: true })\n }\n\n console.log(`Creating a new Specra documentation site in ${pc.cyan(root)}`)\n console.log()\n\n // Create project structure based on template\n const __filename = fileURLToPath(import.meta.url)\n const __dirname = path.dirname(__filename)\n const templateDir = path.join(__dirname, '..', 'templates', template)\n\n if (!fs.existsSync(templateDir)) {\n console.error(pc.red(`Template ${pc.cyan(template)} not found.`))\n process.exit(1)\n }\n\n console.log(`Using template: ${pc.cyan(template)}`)\n console.log()\n\n // Copy template files\n copyRecursive(templateDir, root)\n\n // Update package.json with project name\n const packageJsonPath = path.join(root, 'package.json')\n const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'))\n packageJson.name = appName\n fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2) + '\\n')\n\n // Rename gitignore\n const gitignorePath = path.join(root, 'gitignore')\n if (fs.existsSync(gitignorePath)) {\n fs.renameSync(gitignorePath, path.join(root, '.gitignore'))\n }\n\n // Install dependencies\n if (!skipInstall) {\n console.log('Installing dependencies...')\n console.log()\n\n const command = getPackageManagerCommand(packageManager)\n\n try {\n execSync(command.install, { cwd: root, stdio: 'inherit' })\n } catch (error) {\n console.error(pc.red('Failed to install dependencies.'))\n process.exit(1)\n }\n\n console.log()\n }\n\n // Initialize git\n if (tryGitInit(root)) {\n console.log('Initialized a git repository.')\n console.log()\n }\n\n // Success message\n console.log(pc.green('Success!') + ` Created ${appName} at ${root}`)\n console.log()\n console.log('Inside that directory, you can run several commands:')\n console.log()\n\n const command = getPackageManagerCommand(packageManager)\n\n console.log(pc.cyan(` ${command.run('dev')}`))\n console.log(' Starts the development server.')\n console.log()\n console.log(pc.cyan(` ${command.run('build')}`))\n console.log(' Builds the app for production.')\n console.log()\n console.log(pc.cyan(` ${command.run('start')}`))\n console.log(' Runs the built app in production mode.')\n console.log()\n console.log('We suggest that you begin by typing:')\n console.log()\n console.log(pc.cyan(' cd'), projectName)\n console.log(` ${pc.cyan(command.run('dev'))}`)\n console.log()\n}\n","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 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":"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","names":["fs","path","execSync","path","path","fs","__filename","__dirname","command","execSync","pc","validation"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/create-project.ts"],"sourcesContent":["import { Command } from 'commander'\nimport prompts from 'prompts'\nimport path from 'path'\nimport { createProject } from './create-project.js'\nimport { validateProjectName } from './utils.js'\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('create-specra')\n .description('Specra CLI - Create, deploy, and manage your documentation sites')\n .version(version)\n\n// init command - create a new project (default when no subcommand given)\nconst initCmd = program\n .command('init [project-directory]', { isDefault: true })\n .description('Create a new Specra documentation site')\n .option('--template <template>', 'Template to use (minimal)')\n .option('--use-npm', 'Use npm as the package manager')\n .option('--use-pnpm', 'Use pnpm as the package manager')\n .option('--use-yarn', 'Use yarn as the package manager')\n .option('--skip-install', 'Skip package installation')\n .action(async (projectDirectory: string | undefined, options) => {\n console.log()\n console.log(pc.bold(pc.cyan('Create Specra Documentation Site')))\n console.log()\n\n let projectName = projectDirectory\n\n // Prompt for project name if not provided\n if (!projectName) {\n const response = await prompts({\n type: 'text',\n name: 'projectName',\n message: 'What is your project named?',\n initial: 'my-docs',\n validate: (name) => {\n const validation = validateProjectName(name)\n if (validation.valid) {\n return true\n }\n return validation.problems![0]\n },\n })\n\n if (!response.projectName) {\n console.log()\n console.log('Aborting.')\n process.exit(1)\n }\n\n projectName = response.projectName\n }\n\n // Validate the basename as a package name (allow full paths like /tmp/my-docs)\n const projectBaseName = path.basename(path.resolve(projectName!))\n const validation = validateProjectName(projectBaseName)\n if (!validation.valid) {\n console.error(\n pc.red(\n `Cannot create a project named ${pc.cyan(\n `\"${projectBaseName}\"`\n )} because of npm naming restrictions:\\n`\n )\n )\n validation.problems!.forEach((p) =>\n console.error(` ${pc.red('•')} ${p}`)\n )\n process.exit(1)\n }\n\n // Prompt for template if not provided\n let template = options.template\n\n if (!template) {\n const response = await prompts({\n type: 'select',\n name: 'template',\n message: 'Which template would you like to use?',\n choices: [\n {\n title: 'Minimal',\n value: 'minimal',\n description: 'Minimal setup to get started quickly',\n },\n {\n title: 'Book Docs',\n value: 'book-docs',\n description: 'Knowledge base style with dark theme and categorized sidebar',\n },\n {\n title: 'JBrains Docs',\n value: 'jbrains-docs',\n description: 'Reference docs style with light theme and tab groups',\n },\n ],\n initial: 0,\n })\n\n if (!response.template) {\n console.log()\n console.log('Aborting.')\n process.exit(1)\n }\n\n template = response.template\n }\n\n // Detect or prompt for package manager\n let packageManager = options.useNpm\n ? 'npm'\n : options.usePnpm\n ? 'pnpm'\n : options.useYarn\n ? 'yarn'\n : undefined\n\n if (!packageManager && !options.skipInstall) {\n const response = await prompts({\n type: 'select',\n name: 'packageManager',\n message: 'Which package manager do you want to use?',\n choices: [\n { title: 'npm', value: 'npm' },\n { title: 'yarn', value: 'yarn' },\n { title: 'pnpm', value: 'pnpm' },\n ],\n initial: 0,\n })\n\n if (!response.packageManager) {\n console.log()\n console.log('Aborting.')\n process.exit(1)\n }\n\n packageManager = response.packageManager\n }\n\n // Create the project\n try {\n await createProject({\n projectName: projectName!,\n template: template || 'minimal',\n packageManager: packageManager || 'npm',\n skipInstall: options.skipInstall,\n })\n } catch (error) {\n console.error(pc.red('\\nError creating project:'))\n console.error(error)\n process.exit(1)\n }\n })\n\n// login\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\n// logout\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\n// deploy\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\n// projects\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\n// logs\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\n// doctor\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","import fs from 'fs'\nimport path from 'path'\nimport { fileURLToPath } from 'url'\nimport { execSync } from 'child_process'\nimport pc from 'picocolors'\nimport {\n isWriteable,\n isFolderEmpty,\n getPackageManagerCommand,\n tryGitInit,\n copyRecursive,\n} from './utils.js'\n\ninterface CreateProjectOptions {\n projectName: string\n template: string\n packageManager: string\n skipInstall: boolean\n}\n\nexport async function createProject({\n projectName,\n template,\n packageManager,\n skipInstall,\n}: CreateProjectOptions) {\n const root = path.resolve(projectName)\n const appName = path.basename(root)\n\n // Check if directory exists\n if (fs.existsSync(root)) {\n if (!isWriteable(root)) {\n console.error(\n pc.red(`The directory ${pc.cyan(projectName)} is not writable.`)\n )\n process.exit(1)\n }\n\n if (!isFolderEmpty(root)) {\n console.error(\n pc.red(\n `The directory ${pc.cyan(\n projectName\n )} contains files that could conflict. Please use a new directory.`\n )\n )\n process.exit(1)\n }\n } else {\n fs.mkdirSync(root, { recursive: true })\n }\n\n console.log(`Creating a new Specra documentation site (SvelteKit) in ${pc.cyan(root)}`)\n console.log()\n\n // Create project structure based on template\n const __filename = fileURLToPath(import.meta.url)\n const __dirname = path.dirname(__filename)\n const templateDir = path.join(__dirname, '..', 'templates', template)\n\n if (!fs.existsSync(templateDir)) {\n console.error(pc.red(`Template ${pc.cyan(template)} not found.`))\n process.exit(1)\n }\n\n console.log(`Using template: ${pc.cyan(template)}`)\n console.log()\n\n // Copy template files\n copyRecursive(templateDir, root)\n\n // Update package.json with project name\n const packageJsonPath = path.join(root, 'package.json')\n const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'))\n packageJson.name = appName\n fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2) + '\\n')\n\n // Save package manager choice to specra.config.json\n const specraConfigPath = path.join(root, 'specra.config.json')\n if (fs.existsSync(specraConfigPath)) {\n const specraConfig = JSON.parse(fs.readFileSync(specraConfigPath, 'utf8'))\n specraConfig.packageManager = packageManager\n fs.writeFileSync(specraConfigPath, JSON.stringify(specraConfig, null, 2) + '\\n')\n }\n\n // Rename gitignore\n const gitignorePath = path.join(root, 'gitignore')\n if (fs.existsSync(gitignorePath)) {\n fs.renameSync(gitignorePath, path.join(root, '.gitignore'))\n }\n\n // Install dependencies\n if (!skipInstall) {\n console.log('Installing dependencies...')\n console.log()\n\n const command = getPackageManagerCommand(packageManager)\n\n try {\n execSync(command.install, { cwd: root, stdio: 'inherit' })\n } catch (error) {\n console.error(pc.red('Failed to install dependencies.'))\n process.exit(1)\n }\n\n console.log()\n }\n\n // Initialize git\n if (tryGitInit(root)) {\n console.log('Initialized a git repository.')\n console.log()\n }\n\n // Success message\n console.log(pc.green('Success!') + ` Created ${appName} at ${root}`)\n console.log()\n console.log('Inside that directory, you can run several commands:')\n console.log()\n\n const command = getPackageManagerCommand(packageManager)\n\n console.log(pc.cyan(` ${command.run('dev')}`))\n console.log(' Starts the development server.')\n console.log()\n console.log(pc.cyan(` ${command.run('build')}`))\n console.log(' Builds the app for production.')\n console.log()\n console.log(pc.cyan(` ${command.run('preview')}`))\n console.log(' Previews the built app locally.')\n console.log()\n console.log('We suggest that you begin by typing:')\n console.log()\n console.log(pc.cyan(' cd'), projectName)\n console.log(` ${pc.cyan(command.run('dev'))}`)\n console.log()\n}\n"],"mappings":"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","names":["path","__filename","__dirname","command","pc","require","validation","path"]}
|
|
@@ -1,20 +1,23 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
apiRequest
|
|
4
|
-
} from "./chunk-MA7QG54W.js";
|
|
5
2
|
import {
|
|
6
3
|
getConfig,
|
|
7
|
-
|
|
8
|
-
} from "./chunk-
|
|
4
|
+
saveToken
|
|
5
|
+
} from "./chunk-5765WX4D.js";
|
|
9
6
|
|
|
10
7
|
// src/commands/login.ts
|
|
11
8
|
import pc from "picocolors";
|
|
12
9
|
import open from "open";
|
|
13
10
|
import { createServer } from "http";
|
|
14
11
|
import { randomBytes } from "crypto";
|
|
15
|
-
async function login() {
|
|
12
|
+
async function login(options = {}) {
|
|
16
13
|
console.log(pc.bold("Specra Login"));
|
|
17
14
|
console.log();
|
|
15
|
+
if (options.global) {
|
|
16
|
+
console.log(pc.dim("Storing credentials globally in ~/.specra/config.json"));
|
|
17
|
+
} else {
|
|
18
|
+
console.log(pc.dim("Storing credentials in local .env (referenced by specra.config.json)"));
|
|
19
|
+
}
|
|
20
|
+
console.log();
|
|
18
21
|
const state = randomBytes(16).toString("hex");
|
|
19
22
|
const port = 9876;
|
|
20
23
|
const { apiUrl } = getConfig();
|
|
@@ -27,17 +30,31 @@ async function login() {
|
|
|
27
30
|
if (returnedState !== state) {
|
|
28
31
|
res.writeHead(400, { "Content-Type": "text/html" });
|
|
29
32
|
res.end("<html><body><h1>State mismatch. Please try again.</h1></body></html>");
|
|
30
|
-
server.close()
|
|
31
|
-
|
|
33
|
+
server.close(() => {
|
|
34
|
+
resolve();
|
|
35
|
+
process.exit(1);
|
|
36
|
+
});
|
|
32
37
|
return;
|
|
33
38
|
}
|
|
34
39
|
if (token) {
|
|
35
|
-
saveConfig({ token });
|
|
36
40
|
try {
|
|
41
|
+
saveToken(token, { global: options.global });
|
|
42
|
+
console.log(pc.green("Token saved."));
|
|
43
|
+
} catch (err) {
|
|
44
|
+
if (!options.global) {
|
|
45
|
+
console.log(pc.yellow(`Could not save to local config: ${err instanceof Error ? err.message : err}`));
|
|
46
|
+
console.log(pc.yellow("Falling back to global ~/.specra/ config"));
|
|
47
|
+
saveToken(token, { global: true });
|
|
48
|
+
console.log(pc.green("Token saved globally."));
|
|
49
|
+
} else {
|
|
50
|
+
throw err;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
try {
|
|
54
|
+
const { apiRequest } = await import("./api-client-VHQARPDT.js");
|
|
37
55
|
const user = await apiRequest("/api/auth/verify");
|
|
38
56
|
console.log(pc.green(`Authenticated as ${user.email}`));
|
|
39
57
|
} catch {
|
|
40
|
-
console.log(pc.green("Token saved."));
|
|
41
58
|
}
|
|
42
59
|
res.writeHead(200, { "Content-Type": "text/html" });
|
|
43
60
|
res.end(
|
|
@@ -47,8 +64,10 @@ async function login() {
|
|
|
47
64
|
res.writeHead(400, { "Content-Type": "text/html" });
|
|
48
65
|
res.end("<html><body><h1>Authentication failed.</h1></body></html>");
|
|
49
66
|
}
|
|
50
|
-
server.close()
|
|
51
|
-
|
|
67
|
+
server.close(() => {
|
|
68
|
+
resolve();
|
|
69
|
+
process.exit(0);
|
|
70
|
+
});
|
|
52
71
|
}
|
|
53
72
|
});
|
|
54
73
|
server.listen(port, () => {
|
|
@@ -60,12 +79,14 @@ async function login() {
|
|
|
60
79
|
});
|
|
61
80
|
setTimeout(() => {
|
|
62
81
|
console.log(pc.yellow("Login timed out."));
|
|
63
|
-
server.close()
|
|
64
|
-
|
|
82
|
+
server.close(() => {
|
|
83
|
+
resolve();
|
|
84
|
+
process.exit(1);
|
|
85
|
+
});
|
|
65
86
|
}, 3e5);
|
|
66
87
|
});
|
|
67
88
|
}
|
|
68
89
|
export {
|
|
69
90
|
login
|
|
70
91
|
};
|
|
71
|
-
//# sourceMappingURL=login-
|
|
92
|
+
//# sourceMappingURL=login-UG3WU7DY.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/commands/login.ts"],"sourcesContent":["import pc from 'picocolors'\nimport open from 'open'\nimport { createServer } from 'http'\nimport { saveToken, getGlobalConfig } from '../config.js'\nimport { getConfig, saveConfig } from '../config.js'\nimport { apiRequest } from '../api-client.js'\nimport { randomBytes } from 'crypto'\n\ninterface LoginOptions {\n global?: boolean\n}\n\nexport async function login(options: LoginOptions = {}) {\n console.log(pc.bold('Specra Login'))\n console.log()\n\n if (options.global) {\n console.log(pc.dim('Storing credentials globally in ~/.specra/config.json'))\n } else {\n console.log(pc.dim('Storing credentials in local .env (referenced by specra.config.json)'))\n }\n console.log()\n\n const state = randomBytes(16).toString('hex')\n const port = 9876\n // const apiUrl = getGlobalConfig().apiUrl\n const { apiUrl } = getConfig()\n\n return new Promise<void>((resolve) => {\n const server = createServer(async (req, res) => {\n const url = new URL(req.url!, `http://localhost:${port}`)\n\n // Backend redirects to root path with token as query param\n const token = url.searchParams.get('token')\n const returnedState = url.searchParams.get('state')\n\n if (token || returnedState) {\n if (returnedState !== state) {\n res.writeHead(400, { 'Content-Type': 'text/html' })\n res.end('<html><body><h1>State mismatch. Please try again.</h1></body></html>')\n server.close(() => {\n resolve()\n process.exit(1)\n })\n return\n }\n\n if (token) {\n try {\n saveToken(token, { global: options.global })\n console.log(pc.green('Token saved.'))\n } catch (err) {\n if (!options.global) {\n console.log(pc.yellow(`Could not save to local config: ${err instanceof Error ? err.message : err}`))\n console.log(pc.yellow('Falling back to global ~/.specra/ config'))\n saveToken(token, { global: true })\n console.log(pc.green('Token saved globally.'))\n } else {\n throw err\n }\n }\n\n // Verify the token works\n try {\n const { apiRequest } = await import('../api-client.js')\n const user = await apiRequest<{ email: string }>('/api/auth/verify')\n console.log(pc.green(`Authenticated as ${user.email}`))\n } catch {\n // verification is optional\n }\n\n res.writeHead(200, { 'Content-Type': 'text/html' })\n res.end(\n '<html><body><h1>Authenticated!</h1><p>You can close this window and return to the terminal.</p></body></html>'\n )\n } else {\n res.writeHead(400, { 'Content-Type': 'text/html' })\n res.end('<html><body><h1>Authentication failed.</h1></body></html>')\n }\n\n server.close(() => {\n resolve()\n process.exit(0)\n })\n }\n })\n\n server.listen(port, () => {\n const loginUrl = `${apiUrl}/auth/cli?port=${port}&state=${state}`\n console.log(`Opening browser to authenticate...`)\n console.log(pc.dim(`If the browser doesn't open, visit: ${loginUrl}`))\n console.log()\n open(loginUrl)\n })\n\n // Timeout after 5 minutes\n setTimeout(() => {\n console.log(pc.yellow('Login timed out.'))\n server.close(() => {\n resolve()\n process.exit(1)\n })\n }, 300000)\n })\n}\n"],"mappings":";;;;;;;AAAA,OAAO,QAAQ;AACf,OAAO,UAAU;AACjB,SAAS,oBAAoB;AAI7B,SAAS,mBAAmB;AAM5B,eAAsB,MAAM,UAAwB,CAAC,GAAG;AACtD,UAAQ,IAAI,GAAG,KAAK,cAAc,CAAC;AACnC,UAAQ,IAAI;AAEZ,MAAI,QAAQ,QAAQ;AAClB,YAAQ,IAAI,GAAG,IAAI,uDAAuD,CAAC;AAAA,EAC7E,OAAO;AACL,YAAQ,IAAI,GAAG,IAAI,sEAAsE,CAAC;AAAA,EAC5F;AACA,UAAQ,IAAI;AAEZ,QAAM,QAAQ,YAAY,EAAE,EAAE,SAAS,KAAK;AAC5C,QAAM,OAAO;AAEb,QAAM,EAAE,OAAO,IAAI,UAAU;AAE7B,SAAO,IAAI,QAAc,CAAC,YAAY;AACpC,UAAM,SAAS,aAAa,OAAO,KAAK,QAAQ;AAC9C,YAAM,MAAM,IAAI,IAAI,IAAI,KAAM,oBAAoB,IAAI,EAAE;AAGxD,YAAM,QAAQ,IAAI,aAAa,IAAI,OAAO;AAC1C,YAAM,gBAAgB,IAAI,aAAa,IAAI,OAAO;AAElD,UAAI,SAAS,eAAe;AAC1B,YAAI,kBAAkB,OAAO;AAC3B,cAAI,UAAU,KAAK,EAAE,gBAAgB,YAAY,CAAC;AAClD,cAAI,IAAI,sEAAsE;AAC9E,iBAAO,MAAM,MAAM;AACjB,oBAAQ;AACR,oBAAQ,KAAK,CAAC;AAAA,UAChB,CAAC;AACD;AAAA,QACF;AAEA,YAAI,OAAO;AACT,cAAI;AACF,sBAAU,OAAO,EAAE,QAAQ,QAAQ,OAAO,CAAC;AAC3C,oBAAQ,IAAI,GAAG,MAAM,cAAc,CAAC;AAAA,UACtC,SAAS,KAAK;AACZ,gBAAI,CAAC,QAAQ,QAAQ;AACnB,sBAAQ,IAAI,GAAG,OAAO,mCAAmC,eAAe,QAAQ,IAAI,UAAU,GAAG,EAAE,CAAC;AACpG,sBAAQ,IAAI,GAAG,OAAO,0CAA0C,CAAC;AACjE,wBAAU,OAAO,EAAE,QAAQ,KAAK,CAAC;AACjC,sBAAQ,IAAI,GAAG,MAAM,uBAAuB,CAAC;AAAA,YAC/C,OAAO;AACL,oBAAM;AAAA,YACR;AAAA,UACF;AAGA,cAAI;AACF,kBAAM,EAAE,WAAW,IAAI,MAAM,OAAO,0BAAkB;AACtD,kBAAM,OAAO,MAAM,WAA8B,kBAAkB;AACnE,oBAAQ,IAAI,GAAG,MAAM,oBAAoB,KAAK,KAAK,EAAE,CAAC;AAAA,UACxD,QAAQ;AAAA,UAER;AAEA,cAAI,UAAU,KAAK,EAAE,gBAAgB,YAAY,CAAC;AAClD,cAAI;AAAA,YACF;AAAA,UACF;AAAA,QACF,OAAO;AACL,cAAI,UAAU,KAAK,EAAE,gBAAgB,YAAY,CAAC;AAClD,cAAI,IAAI,2DAA2D;AAAA,QACrE;AAEA,eAAO,MAAM,MAAM;AACjB,kBAAQ;AACR,kBAAQ,KAAK,CAAC;AAAA,QAChB,CAAC;AAAA,MACH;AAAA,IACF,CAAC;AAED,WAAO,OAAO,MAAM,MAAM;AACxB,YAAM,WAAW,GAAG,MAAM,kBAAkB,IAAI,UAAU,KAAK;AAC/D,cAAQ,IAAI,oCAAoC;AAChD,cAAQ,IAAI,GAAG,IAAI,uCAAuC,QAAQ,EAAE,CAAC;AACrE,cAAQ,IAAI;AACZ,WAAK,QAAQ;AAAA,IACf,CAAC;AAGD,eAAW,MAAM;AACf,cAAQ,IAAI,GAAG,OAAO,kBAAkB,CAAC;AACzC,aAAO,MAAM,MAAM;AACjB,gBAAQ;AACR,gBAAQ,KAAK,CAAC;AAAA,MAChB,CAAC;AAAA,IACH,GAAG,GAAM;AAAA,EACX,CAAC;AACH;","names":[]}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
clearToken,
|
|
4
|
+
isAuthenticated
|
|
5
|
+
} from "./chunk-5765WX4D.js";
|
|
6
|
+
|
|
7
|
+
// src/commands/logout.ts
|
|
8
|
+
import pc from "picocolors";
|
|
9
|
+
async function logout(options = {}) {
|
|
10
|
+
if (!isAuthenticated()) {
|
|
11
|
+
console.log(pc.yellow("Not currently logged in."));
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
clearToken({ global: options.global });
|
|
15
|
+
if (options.global) {
|
|
16
|
+
console.log(pc.green("Logged out globally (cleared ~/.specra/ credentials)."));
|
|
17
|
+
} else {
|
|
18
|
+
console.log(pc.green("Logged out (cleared local project credentials)."));
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
export {
|
|
22
|
+
logout
|
|
23
|
+
};
|
|
24
|
+
//# sourceMappingURL=logout-WJKHJZT6.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/commands/logout.ts"],"sourcesContent":["import pc from 'picocolors'\nimport { clearToken, isAuthenticated } from '../config.js'\n\ninterface LogoutOptions {\n global?: boolean\n}\n\nexport async function logout(options: LogoutOptions = {}) {\n if (!isAuthenticated()) {\n console.log(pc.yellow('Not currently logged in.'))\n return\n }\n\n clearToken({ global: options.global })\n\n if (options.global) {\n console.log(pc.green('Logged out globally (cleared ~/.specra/ credentials).'))\n } else {\n console.log(pc.green('Logged out (cleared local project credentials).'))\n }\n}\n"],"mappings":";;;;;;;AAAA,OAAO,QAAQ;AAOf,eAAsB,OAAO,UAAyB,CAAC,GAAG;AACxD,MAAI,CAAC,gBAAgB,GAAG;AACtB,YAAQ,IAAI,GAAG,OAAO,0BAA0B,CAAC;AACjD;AAAA,EACF;AAEA,aAAW,EAAE,QAAQ,QAAQ,OAAO,CAAC;AAErC,MAAI,QAAQ,QAAQ;AAClB,YAAQ,IAAI,GAAG,MAAM,uDAAuD,CAAC;AAAA,EAC/E,OAAO;AACL,YAAQ,IAAI,GAAG,MAAM,iDAAiD,CAAC;AAAA,EACzE;AACF;","names":[]}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
|
-
apiRequest
|
|
4
|
-
|
|
3
|
+
apiRequest,
|
|
4
|
+
formatError
|
|
5
|
+
} from "./chunk-72RDEJR2.js";
|
|
5
6
|
import {
|
|
6
7
|
isAuthenticated
|
|
7
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-5765WX4D.js";
|
|
8
9
|
|
|
9
10
|
// src/commands/logs.ts
|
|
10
11
|
import pc from "picocolors";
|
|
@@ -13,23 +14,28 @@ async function logs(projectId, options) {
|
|
|
13
14
|
console.error(pc.red("Not authenticated. Run `specra login` first."));
|
|
14
15
|
process.exit(1);
|
|
15
16
|
}
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
17
|
+
try {
|
|
18
|
+
if (options.deployment) {
|
|
19
|
+
const deploy = await apiRequest(
|
|
20
|
+
`/api/projects/${projectId}/deployments/${options.deployment}`
|
|
21
|
+
);
|
|
22
|
+
printDeployment(deploy);
|
|
23
|
+
} else {
|
|
24
|
+
const data = await apiRequest(
|
|
25
|
+
`/api/projects/${projectId}/deployments?limit=1`
|
|
26
|
+
);
|
|
27
|
+
if (data.deployments.length === 0) {
|
|
28
|
+
console.log(pc.yellow("No deployments found."));
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
const deploy = await apiRequest(
|
|
32
|
+
`/api/projects/${projectId}/deployments/${data.deployments[0].id}`
|
|
33
|
+
);
|
|
34
|
+
printDeployment(deploy);
|
|
28
35
|
}
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
);
|
|
32
|
-
printDeployment(deploy);
|
|
36
|
+
} catch (err) {
|
|
37
|
+
console.error(pc.red(formatError("Failed to fetch logs", err)));
|
|
38
|
+
process.exit(1);
|
|
33
39
|
}
|
|
34
40
|
}
|
|
35
41
|
function printDeployment(deploy) {
|
|
@@ -68,4 +74,4 @@ function colorStatus(status) {
|
|
|
68
74
|
export {
|
|
69
75
|
logs
|
|
70
76
|
};
|
|
71
|
-
//# sourceMappingURL=logs-
|
|
77
|
+
//# sourceMappingURL=logs-BLUJPWNO.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/commands/logs.ts"],"sourcesContent":["import pc from 'picocolors'\nimport { apiRequest, formatError } from '../api-client.js'\nimport { isAuthenticated } from '../config.js'\n\ninterface Deployment {\n id: string\n status: string\n buildLogs: string | null\n containerLogs?: string\n trigger: string\n createdAt: string\n}\n\ninterface DeploymentList {\n deployments: Deployment[]\n}\n\nexport async function logs(\n projectId: string,\n options: { deployment?: string }\n) {\n if (!isAuthenticated()) {\n console.error(pc.red('Not authenticated. Run `specra login` first.'))\n process.exit(1)\n }\n\n try {\n if (options.deployment) {\n // Get specific deployment\n const deploy = await apiRequest<Deployment>(\n `/api/projects/${projectId}/deployments/${options.deployment}`\n )\n\n printDeployment(deploy)\n } else {\n // Get latest deployment\n const data = await apiRequest<DeploymentList>(\n `/api/projects/${projectId}/deployments?limit=1`\n )\n\n if (data.deployments.length === 0) {\n console.log(pc.yellow('No deployments found.'))\n return\n }\n\n // Fetch full details with logs\n const deploy = await apiRequest<Deployment>(\n `/api/projects/${projectId}/deployments/${data.deployments[0].id}`\n )\n\n printDeployment(deploy)\n }\n } catch (err) {\n console.error(pc.red(formatError('Failed to fetch logs', err)))\n process.exit(1)\n }\n}\n\nfunction printDeployment(deploy: Deployment) {\n console.log(pc.bold(`Deployment ${deploy.id.slice(0, 8)}`))\n console.log(` Status: ${colorStatus(deploy.status)}`)\n console.log(` Trigger: ${deploy.trigger.toLowerCase()}`)\n console.log(` Created: ${new Date(deploy.createdAt).toLocaleString()}`)\n console.log()\n\n if (deploy.buildLogs) {\n console.log(pc.bold('Build Logs:'))\n console.log(pc.dim('─'.repeat(60)))\n console.log(deploy.buildLogs)\n console.log(pc.dim('─'.repeat(60)))\n }\n\n if (deploy.containerLogs) {\n console.log()\n console.log(pc.bold('Container Logs:'))\n console.log(pc.dim('─'.repeat(60)))\n console.log(deploy.containerLogs)\n console.log(pc.dim('─'.repeat(60)))\n }\n}\n\nfunction colorStatus(status: string) {\n switch (status) {\n case 'RUNNING':\n return pc.green(status.toLowerCase())\n case 'FAILED':\n return pc.red(status.toLowerCase())\n case 'BUILDING':\n case 'DEPLOYING':\n return pc.yellow(status.toLowerCase())\n default:\n return pc.dim(status.toLowerCase())\n }\n}\n"],"mappings":";;;;;;;;;;AAAA,OAAO,QAAQ;AAiBf,eAAsB,KACpB,WACA,SACA;AACA,MAAI,CAAC,gBAAgB,GAAG;AACtB,YAAQ,MAAM,GAAG,IAAI,8CAA8C,CAAC;AACpE,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,MAAI;AACF,QAAI,QAAQ,YAAY;AAEtB,YAAM,SAAS,MAAM;AAAA,QACnB,iBAAiB,SAAS,gBAAgB,QAAQ,UAAU;AAAA,MAC9D;AAEA,sBAAgB,MAAM;AAAA,IACxB,OAAO;AAEL,YAAM,OAAO,MAAM;AAAA,QACjB,iBAAiB,SAAS;AAAA,MAC5B;AAEA,UAAI,KAAK,YAAY,WAAW,GAAG;AACjC,gBAAQ,IAAI,GAAG,OAAO,uBAAuB,CAAC;AAC9C;AAAA,MACF;AAGA,YAAM,SAAS,MAAM;AAAA,QACnB,iBAAiB,SAAS,gBAAgB,KAAK,YAAY,CAAC,EAAE,EAAE;AAAA,MAClE;AAEA,sBAAgB,MAAM;AAAA,IACxB;AAAA,EACF,SAAS,KAAK;AACZ,YAAQ,MAAM,GAAG,IAAI,YAAY,wBAAwB,GAAG,CAAC,CAAC;AAC9D,YAAQ,KAAK,CAAC;AAAA,EAChB;AACF;AAEA,SAAS,gBAAgB,QAAoB;AAC3C,UAAQ,IAAI,GAAG,KAAK,cAAc,OAAO,GAAG,MAAM,GAAG,CAAC,CAAC,EAAE,CAAC;AAC1D,UAAQ,IAAI,cAAc,YAAY,OAAO,MAAM,CAAC,EAAE;AACtD,UAAQ,IAAI,cAAc,OAAO,QAAQ,YAAY,CAAC,EAAE;AACxD,UAAQ,IAAI,cAAc,IAAI,KAAK,OAAO,SAAS,EAAE,eAAe,CAAC,EAAE;AACvE,UAAQ,IAAI;AAEZ,MAAI,OAAO,WAAW;AACpB,YAAQ,IAAI,GAAG,KAAK,aAAa,CAAC;AAClC,YAAQ,IAAI,GAAG,IAAI,SAAI,OAAO,EAAE,CAAC,CAAC;AAClC,YAAQ,IAAI,OAAO,SAAS;AAC5B,YAAQ,IAAI,GAAG,IAAI,SAAI,OAAO,EAAE,CAAC,CAAC;AAAA,EACpC;AAEA,MAAI,OAAO,eAAe;AACxB,YAAQ,IAAI;AACZ,YAAQ,IAAI,GAAG,KAAK,iBAAiB,CAAC;AACtC,YAAQ,IAAI,GAAG,IAAI,SAAI,OAAO,EAAE,CAAC,CAAC;AAClC,YAAQ,IAAI,OAAO,aAAa;AAChC,YAAQ,IAAI,GAAG,IAAI,SAAI,OAAO,EAAE,CAAC,CAAC;AAAA,EACpC;AACF;AAEA,SAAS,YAAY,QAAgB;AACnC,UAAQ,QAAQ;AAAA,IACd,KAAK;AACH,aAAO,GAAG,MAAM,OAAO,YAAY,CAAC;AAAA,IACtC,KAAK;AACH,aAAO,GAAG,IAAI,OAAO,YAAY,CAAC;AAAA,IACpC,KAAK;AAAA,IACL,KAAK;AACH,aAAO,GAAG,OAAO,OAAO,YAAY,CAAC;AAAA,IACvC;AACE,aAAO,GAAG,IAAI,OAAO,YAAY,CAAC;AAAA,EACtC;AACF;","names":[]}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
|
-
apiRequest
|
|
4
|
-
|
|
3
|
+
apiRequest,
|
|
4
|
+
formatError
|
|
5
|
+
} from "./chunk-72RDEJR2.js";
|
|
5
6
|
import {
|
|
6
7
|
isAuthenticated
|
|
7
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-5765WX4D.js";
|
|
8
9
|
|
|
9
10
|
// src/commands/projects.ts
|
|
10
11
|
import pc from "picocolors";
|
|
@@ -13,11 +14,17 @@ async function projects() {
|
|
|
13
14
|
console.error(pc.red("Not authenticated. Run `specra login` first."));
|
|
14
15
|
process.exit(1);
|
|
15
16
|
}
|
|
16
|
-
|
|
17
|
+
let list;
|
|
18
|
+
try {
|
|
19
|
+
list = await apiRequest("/api/projects");
|
|
20
|
+
} catch (err) {
|
|
21
|
+
console.error(pc.red(formatError("Failed to fetch projects", err)));
|
|
22
|
+
process.exit(1);
|
|
23
|
+
}
|
|
17
24
|
if (list.length === 0) {
|
|
18
25
|
console.log(pc.yellow("No projects found."));
|
|
19
26
|
console.log(
|
|
20
|
-
`Create one at ${pc.dim("https://specra.
|
|
27
|
+
`Create one at ${pc.dim("https://specra-docs.com/dashboard/projects/new")}`
|
|
21
28
|
);
|
|
22
29
|
return;
|
|
23
30
|
}
|
|
@@ -39,4 +46,4 @@ async function projects() {
|
|
|
39
46
|
export {
|
|
40
47
|
projects
|
|
41
48
|
};
|
|
42
|
-
//# sourceMappingURL=projects-
|
|
49
|
+
//# sourceMappingURL=projects-LJ57GK3D.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/commands/projects.ts"],"sourcesContent":["import pc from 'picocolors'\nimport { apiRequest, formatError } from '../api-client.js'\nimport { isAuthenticated } from '../config.js'\n\ninterface Project {\n id: string\n name: string\n subdomain: string\n customDomain: string | null\n deployments: Array<{ status: string }>\n}\n\nexport async function projects() {\n if (!isAuthenticated()) {\n console.error(pc.red('Not authenticated. Run `specra login` first.'))\n process.exit(1)\n }\n\n let list: Project[]\n try {\n list = await apiRequest<Project[]>('/api/projects')\n } catch (err) {\n console.error(pc.red(formatError('Failed to fetch projects', err)))\n process.exit(1)\n }\n\n if (list.length === 0) {\n console.log(pc.yellow('No projects found.'))\n console.log(\n `Create one at ${pc.dim('https://specra-docs.com/dashboard/projects/new')}`\n )\n return\n }\n\n console.log(pc.bold(`Projects (${list.length}):`))\n console.log()\n\n for (const p of list) {\n const status = p.deployments[0]?.status || 'NOT_DEPLOYED'\n const statusColor =\n status === 'RUNNING'\n ? pc.green\n : status === 'FAILED'\n ? pc.red\n : pc.dim\n\n console.log(\n ` ${pc.bold(p.name)} ${pc.dim(`(${p.id.slice(0, 8)})`)} ${statusColor(status.toLowerCase())}`\n )\n console.log(` ${pc.dim(`${p.subdomain}.docs.specra.dev`)}`)\n if (p.customDomain) {\n console.log(` ${pc.dim(p.customDomain)}`)\n }\n console.log()\n }\n}\n"],"mappings":";;;;;;;;;;AAAA,OAAO,QAAQ;AAYf,eAAsB,WAAW;AAC/B,MAAI,CAAC,gBAAgB,GAAG;AACtB,YAAQ,MAAM,GAAG,IAAI,8CAA8C,CAAC;AACpE,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,MAAI;AACJ,MAAI;AACF,WAAO,MAAM,WAAsB,eAAe;AAAA,EACpD,SAAS,KAAK;AACZ,YAAQ,MAAM,GAAG,IAAI,YAAY,4BAA4B,GAAG,CAAC,CAAC;AAClE,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,MAAI,KAAK,WAAW,GAAG;AACrB,YAAQ,IAAI,GAAG,OAAO,oBAAoB,CAAC;AAC3C,YAAQ;AAAA,MACN,iBAAiB,GAAG,IAAI,gDAAgD,CAAC;AAAA,IAC3E;AACA;AAAA,EACF;AAEA,UAAQ,IAAI,GAAG,KAAK,aAAa,KAAK,MAAM,IAAI,CAAC;AACjD,UAAQ,IAAI;AAEZ,aAAW,KAAK,MAAM;AACpB,UAAM,SAAS,EAAE,YAAY,CAAC,GAAG,UAAU;AAC3C,UAAM,cACJ,WAAW,YACP,GAAG,QACH,WAAW,WACT,GAAG,MACH,GAAG;AAEX,YAAQ;AAAA,MACN,KAAK,GAAG,KAAK,EAAE,IAAI,CAAC,IAAI,GAAG,IAAI,IAAI,EAAE,GAAG,MAAM,GAAG,CAAC,CAAC,GAAG,CAAC,KAAK,YAAY,OAAO,YAAY,CAAC,CAAC;AAAA,IAC/F;AACA,YAAQ,IAAI,OAAO,GAAG,IAAI,GAAG,EAAE,SAAS,kBAAkB,CAAC,EAAE;AAC7D,QAAI,EAAE,cAAc;AAClB,cAAQ,IAAI,OAAO,GAAG,IAAI,EAAE,YAAY,CAAC,EAAE;AAAA,IAC7C;AACA,YAAQ,IAAI;AAAA,EACd;AACF;","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-specra",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.3",
|
|
4
4
|
"description": "CLI tool to scaffold a new Specra documentation site with Next.js",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -19,7 +19,8 @@
|
|
|
19
19
|
"keywords": [
|
|
20
20
|
"documentation",
|
|
21
21
|
"docs",
|
|
22
|
-
"
|
|
22
|
+
"sveltekit",
|
|
23
|
+
"svelte",
|
|
23
24
|
"mdx",
|
|
24
25
|
"specra",
|
|
25
26
|
"create-app",
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
SPECTRA_TOKEN=sk_xxx...
|