create-specra 0.1.7 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (136) hide show
  1. package/LICENSE.MD +16 -4
  2. package/README.md +53 -17
  3. package/dist/chunk-3DKWECRK.js +45 -0
  4. package/dist/chunk-3DKWECRK.js.map +1 -0
  5. package/dist/chunk-MA7QG54W.js +74 -0
  6. package/dist/chunk-MA7QG54W.js.map +1 -0
  7. package/dist/cli.d.ts +2 -0
  8. package/dist/cli.js +33 -0
  9. package/dist/cli.js.map +1 -0
  10. package/dist/deploy-SCEMUQNS.js +141 -0
  11. package/dist/deploy-SCEMUQNS.js.map +1 -0
  12. package/dist/index.js +11 -11
  13. package/dist/index.js.map +1 -1
  14. package/dist/login-NKDRQXRE.js +71 -0
  15. package/dist/login-NKDRQXRE.js.map +1 -0
  16. package/dist/logout-H543QEKU.js +20 -0
  17. package/dist/logout-H543QEKU.js.map +1 -0
  18. package/dist/logs-YDAUCMAV.js +71 -0
  19. package/dist/logs-YDAUCMAV.js.map +1 -0
  20. package/dist/projects-3TAY7EDJ.js +42 -0
  21. package/dist/projects-3TAY7EDJ.js.map +1 -0
  22. package/package.json +7 -3
  23. package/templates/book-docs/docs/v1.0.0/concepts.mdx +89 -0
  24. package/templates/book-docs/docs/v1.0.0/content/_category_.json +7 -0
  25. package/templates/book-docs/docs/v1.0.0/content/formatting.mdx +128 -0
  26. package/templates/book-docs/docs/v1.0.0/content/reusable-content.mdx +116 -0
  27. package/templates/book-docs/docs/v1.0.0/content/structure.mdx +92 -0
  28. package/templates/book-docs/docs/v1.0.0/customization/_category_.json +7 -0
  29. package/templates/book-docs/docs/v1.0.0/customization/branding.mdx +115 -0
  30. package/templates/book-docs/docs/v1.0.0/customization/themes.mdx +81 -0
  31. package/templates/book-docs/docs/v1.0.0/introduction.mdx +38 -0
  32. package/templates/book-docs/docs/v1.0.0/quickstart.mdx +112 -0
  33. package/templates/book-docs/docs/v2.0.0/concepts.mdx +89 -0
  34. package/templates/book-docs/docs/v2.0.0/content/_category_.json +7 -0
  35. package/templates/book-docs/docs/v2.0.0/content/formatting.mdx +128 -0
  36. package/templates/book-docs/docs/v2.0.0/content/reusable-content.mdx +116 -0
  37. package/templates/book-docs/docs/v2.0.0/content/structure.mdx +92 -0
  38. package/templates/book-docs/docs/v2.0.0/customization/_category_.json +7 -0
  39. package/templates/book-docs/docs/v2.0.0/customization/branding.mdx +115 -0
  40. package/templates/book-docs/docs/v2.0.0/customization/themes.mdx +81 -0
  41. package/templates/book-docs/docs/v2.0.0/introduction.mdx +39 -0
  42. package/templates/book-docs/docs/v2.0.0/quickstart.mdx +112 -0
  43. package/templates/book-docs/gitignore +7 -0
  44. package/templates/book-docs/package.json +28 -0
  45. package/templates/book-docs/postcss.config.mjs +8 -0
  46. package/templates/book-docs/public/api-specs/openapi-example.json +259 -0
  47. package/templates/book-docs/public/api-specs/postman-example.json +205 -0
  48. package/templates/book-docs/public/api-specs/test-api.json +256 -0
  49. package/templates/book-docs/public/api-specs/users-api.json +264 -0
  50. package/templates/book-docs/specra.config.json +77 -0
  51. package/templates/book-docs/src/app.css +2 -0
  52. package/templates/book-docs/src/app.html +12 -0
  53. package/templates/book-docs/src/routes/+layout.server.ts +11 -0
  54. package/templates/book-docs/src/routes/+layout.svelte +21 -0
  55. package/templates/book-docs/src/routes/+page.server.ts +9 -0
  56. package/templates/book-docs/src/routes/docs/[version]/[...slug]/+page.server.ts +119 -0
  57. package/templates/book-docs/src/routes/docs/[version]/[...slug]/+page.svelte +129 -0
  58. package/templates/book-docs/svelte.config.js +8 -0
  59. package/templates/book-docs/tsconfig.json +12 -0
  60. package/templates/book-docs/vite.config.ts +6 -0
  61. package/templates/jbrains-docs/docs/v1.0.0/advanced/_category_.json +8 -0
  62. package/templates/jbrains-docs/docs/v1.0.0/advanced/async.mdx +95 -0
  63. package/templates/jbrains-docs/docs/v1.0.0/advanced/generics.mdx +126 -0
  64. package/templates/jbrains-docs/docs/v1.0.0/basics/_category_.json +8 -0
  65. package/templates/jbrains-docs/docs/v1.0.0/basics/control-flow.mdx +106 -0
  66. package/templates/jbrains-docs/docs/v1.0.0/basics/syntax.mdx +129 -0
  67. package/templates/jbrains-docs/docs/v1.0.0/basics/types.mdx +135 -0
  68. package/templates/jbrains-docs/docs/v1.0.0/getting-started.mdx +111 -0
  69. package/templates/jbrains-docs/docs/v1.0.0/home.mdx +37 -0
  70. package/templates/jbrains-docs/docs/v1.0.0/tools/_category_.json +8 -0
  71. package/templates/jbrains-docs/docs/v1.0.0/tools/build-tools.mdx +165 -0
  72. package/templates/jbrains-docs/docs/v1.0.0/tools/testing.mdx +112 -0
  73. package/templates/jbrains-docs/docs/v2.0.0/advanced/_category_.json +8 -0
  74. package/templates/jbrains-docs/docs/v2.0.0/advanced/async.mdx +95 -0
  75. package/templates/jbrains-docs/docs/v2.0.0/advanced/generics.mdx +126 -0
  76. package/templates/jbrains-docs/docs/v2.0.0/basics/_category_.json +8 -0
  77. package/templates/jbrains-docs/docs/v2.0.0/basics/control-flow.mdx +106 -0
  78. package/templates/jbrains-docs/docs/v2.0.0/basics/syntax.mdx +129 -0
  79. package/templates/jbrains-docs/docs/v2.0.0/basics/types.mdx +135 -0
  80. package/templates/jbrains-docs/docs/v2.0.0/getting-started.mdx +111 -0
  81. package/templates/jbrains-docs/docs/v2.0.0/home.mdx +37 -0
  82. package/templates/jbrains-docs/docs/v2.0.0/tools/_category_.json +8 -0
  83. package/templates/jbrains-docs/docs/v2.0.0/tools/build-tools.mdx +165 -0
  84. package/templates/jbrains-docs/docs/v2.0.0/tools/testing.mdx +112 -0
  85. package/templates/jbrains-docs/gitignore +7 -0
  86. package/templates/jbrains-docs/package.json +28 -0
  87. package/templates/jbrains-docs/postcss.config.mjs +8 -0
  88. package/templates/jbrains-docs/public/api-specs/openapi-example.json +259 -0
  89. package/templates/jbrains-docs/public/api-specs/postman-example.json +205 -0
  90. package/templates/jbrains-docs/public/api-specs/test-api.json +256 -0
  91. package/templates/jbrains-docs/public/api-specs/users-api.json +264 -0
  92. package/templates/jbrains-docs/specra.config.json +80 -0
  93. package/templates/jbrains-docs/src/app.css +2 -0
  94. package/templates/jbrains-docs/src/app.html +12 -0
  95. package/templates/jbrains-docs/src/routes/+layout.server.ts +11 -0
  96. package/templates/jbrains-docs/src/routes/+layout.svelte +21 -0
  97. package/templates/jbrains-docs/src/routes/+page.server.ts +9 -0
  98. package/templates/jbrains-docs/src/routes/docs/[version]/[...slug]/+page.server.ts +119 -0
  99. package/templates/jbrains-docs/src/routes/docs/[version]/[...slug]/+page.svelte +129 -0
  100. package/templates/jbrains-docs/svelte.config.js +8 -0
  101. package/templates/jbrains-docs/tsconfig.json +12 -0
  102. package/templates/jbrains-docs/vite.config.ts +6 -0
  103. package/templates/minimal/docs/v1.0.0/about.mdx +3 -3
  104. package/templates/minimal/docs/v2.0.0/about.mdx +3 -3
  105. package/templates/minimal/gitignore +7 -0
  106. package/templates/minimal/package.json +18 -24
  107. package/templates/minimal/specra.config.json +12 -63
  108. package/templates/minimal/src/app.css +2 -0
  109. package/templates/minimal/src/app.html +12 -0
  110. package/templates/minimal/src/routes/+layout.server.ts +11 -0
  111. package/templates/minimal/src/routes/+layout.svelte +21 -0
  112. package/templates/minimal/src/routes/+page.server.ts +9 -0
  113. package/templates/minimal/src/routes/docs/[version]/[...slug]/+page.server.ts +119 -0
  114. package/templates/minimal/src/routes/docs/[version]/[...slug]/+page.svelte +129 -0
  115. package/templates/minimal/svelte.config.js +8 -0
  116. package/templates/minimal/tsconfig.json +7 -36
  117. package/templates/minimal/vite.config.ts +6 -0
  118. package/templates/minimal/README.md +0 -132
  119. package/templates/minimal/app/api/mdx-watch/route.ts +0 -6
  120. package/templates/minimal/app/api/search/route.ts +0 -75
  121. package/templates/minimal/app/docs/[version]/[...slug]/loading.tsx +0 -7
  122. package/templates/minimal/app/docs/[version]/[...slug]/page.tsx +0 -205
  123. package/templates/minimal/app/docs/[version]/[...slug]/page.tsx.bak +0 -203
  124. package/templates/minimal/app/docs/[version]/not-found.tsx +0 -10
  125. package/templates/minimal/app/docs/[version]/page.tsx +0 -27
  126. package/templates/minimal/app/globals.css +0 -9
  127. package/templates/minimal/app/layout.tsx +0 -62
  128. package/templates/minimal/app/not-found.tsx +0 -10
  129. package/templates/minimal/app/page.tsx +0 -179
  130. package/templates/minimal/next.config.mjs +0 -1
  131. package/templates/minimal/package-lock.json +0 -7881
  132. package/templates/minimal/proxy_.ts +0 -22
  133. package/templates/minimal/scripts/generate-redirects.mjs +0 -128
  134. package/templates/minimal/scripts/generate-static-redirects.mjs +0 -115
  135. package/templates/minimal/scripts/index-search.ts +0 -182
  136. package/templates/minimal/scripts/test-search.ts +0 -83
@@ -0,0 +1,71 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ apiRequest
4
+ } from "./chunk-MA7QG54W.js";
5
+ import {
6
+ getConfig,
7
+ saveConfig
8
+ } from "./chunk-3DKWECRK.js";
9
+
10
+ // src/commands/login.ts
11
+ import pc from "picocolors";
12
+ import open from "open";
13
+ import { createServer } from "http";
14
+ import { randomBytes } from "crypto";
15
+ async function login() {
16
+ console.log(pc.bold("Specra Login"));
17
+ console.log();
18
+ const state = randomBytes(16).toString("hex");
19
+ const port = 9876;
20
+ const { apiUrl } = getConfig();
21
+ return new Promise((resolve) => {
22
+ const server = createServer(async (req, res) => {
23
+ const url = new URL(req.url, `http://localhost:${port}`);
24
+ const token = url.searchParams.get("token");
25
+ const returnedState = url.searchParams.get("state");
26
+ if (token || returnedState) {
27
+ if (returnedState !== state) {
28
+ res.writeHead(400, { "Content-Type": "text/html" });
29
+ res.end("<html><body><h1>State mismatch. Please try again.</h1></body></html>");
30
+ server.close();
31
+ resolve();
32
+ return;
33
+ }
34
+ if (token) {
35
+ saveConfig({ token });
36
+ try {
37
+ const user = await apiRequest("/api/auth/verify");
38
+ console.log(pc.green(`Authenticated as ${user.email}`));
39
+ } catch {
40
+ console.log(pc.green("Token saved."));
41
+ }
42
+ res.writeHead(200, { "Content-Type": "text/html" });
43
+ res.end(
44
+ "<html><body><h1>Authenticated!</h1><p>You can close this window and return to the terminal.</p></body></html>"
45
+ );
46
+ } else {
47
+ res.writeHead(400, { "Content-Type": "text/html" });
48
+ res.end("<html><body><h1>Authentication failed.</h1></body></html>");
49
+ }
50
+ server.close();
51
+ resolve();
52
+ }
53
+ });
54
+ server.listen(port, () => {
55
+ const loginUrl = `${apiUrl}/auth/cli?port=${port}&state=${state}`;
56
+ console.log(`Opening browser to authenticate...`);
57
+ console.log(pc.dim(`If the browser doesn't open, visit: ${loginUrl}`));
58
+ console.log();
59
+ open(loginUrl);
60
+ });
61
+ setTimeout(() => {
62
+ console.log(pc.yellow("Login timed out."));
63
+ server.close();
64
+ resolve();
65
+ }, 3e5);
66
+ });
67
+ }
68
+ export {
69
+ login
70
+ };
71
+ //# sourceMappingURL=login-NKDRQXRE.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 { getConfig, saveConfig } from '../config.js'\nimport { apiRequest } from '../api-client.js'\nimport { randomBytes } from 'crypto'\n\nexport async function login() {\n console.log(pc.bold('Specra Login'))\n console.log()\n\n const state = randomBytes(16).toString('hex')\n const port = 9876\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 return\n }\n\n if (token) {\n saveConfig({ token })\n\n // Verify the token works\n try {\n const user = await apiRequest<{ email: string }>('/api/auth/verify')\n console.log(pc.green(`Authenticated as ${user.email}`))\n } catch {\n console.log(pc.green('Token saved.'))\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 }\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 }, 300000)\n })\n}\n"],"mappings":";;;;;;;;;;AAAA,OAAO,QAAQ;AACf,OAAO,UAAU;AACjB,SAAS,oBAAoB;AAG7B,SAAS,mBAAmB;AAE5B,eAAsB,QAAQ;AAC5B,UAAQ,IAAI,GAAG,KAAK,cAAc,CAAC;AACnC,UAAQ,IAAI;AAEZ,QAAM,QAAQ,YAAY,EAAE,EAAE,SAAS,KAAK;AAC5C,QAAM,OAAO;AACb,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;AACb,kBAAQ;AACR;AAAA,QACF;AAEA,YAAI,OAAO;AACT,qBAAW,EAAE,MAAM,CAAC;AAGpB,cAAI;AACF,kBAAM,OAAO,MAAM,WAA8B,kBAAkB;AACnE,oBAAQ,IAAI,GAAG,MAAM,oBAAoB,KAAK,KAAK,EAAE,CAAC;AAAA,UACxD,QAAQ;AACN,oBAAQ,IAAI,GAAG,MAAM,cAAc,CAAC;AAAA,UACtC;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;AACb,gBAAQ;AAAA,MACV;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;AACb,cAAQ;AAAA,IACV,GAAG,GAAM;AAAA,EACX,CAAC;AACH;","names":[]}
@@ -0,0 +1,20 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ clearConfig,
4
+ isAuthenticated
5
+ } from "./chunk-3DKWECRK.js";
6
+
7
+ // src/commands/logout.ts
8
+ import pc from "picocolors";
9
+ async function logout() {
10
+ if (!isAuthenticated()) {
11
+ console.log(pc.yellow("Not currently logged in."));
12
+ return;
13
+ }
14
+ clearConfig();
15
+ console.log(pc.green("Logged out successfully."));
16
+ }
17
+ export {
18
+ logout
19
+ };
20
+ //# sourceMappingURL=logout-H543QEKU.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/commands/logout.ts"],"sourcesContent":["import pc from 'picocolors'\nimport { clearConfig, isAuthenticated } from '../config.js'\n\nexport async function logout() {\n if (!isAuthenticated()) {\n console.log(pc.yellow('Not currently logged in.'))\n return\n }\n\n clearConfig()\n console.log(pc.green('Logged out successfully.'))\n}\n"],"mappings":";;;;;;;AAAA,OAAO,QAAQ;AAGf,eAAsB,SAAS;AAC7B,MAAI,CAAC,gBAAgB,GAAG;AACtB,YAAQ,IAAI,GAAG,OAAO,0BAA0B,CAAC;AACjD;AAAA,EACF;AAEA,cAAY;AACZ,UAAQ,IAAI,GAAG,MAAM,0BAA0B,CAAC;AAClD;","names":[]}
@@ -0,0 +1,71 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ apiRequest
4
+ } from "./chunk-MA7QG54W.js";
5
+ import {
6
+ isAuthenticated
7
+ } from "./chunk-3DKWECRK.js";
8
+
9
+ // src/commands/logs.ts
10
+ import pc from "picocolors";
11
+ async function logs(projectId, options) {
12
+ if (!isAuthenticated()) {
13
+ console.error(pc.red("Not authenticated. Run `specra login` first."));
14
+ process.exit(1);
15
+ }
16
+ if (options.deployment) {
17
+ const deploy = await apiRequest(
18
+ `/api/projects/${projectId}/deployments/${options.deployment}`
19
+ );
20
+ printDeployment(deploy);
21
+ } else {
22
+ const data = await apiRequest(
23
+ `/api/projects/${projectId}/deployments?limit=1`
24
+ );
25
+ if (data.deployments.length === 0) {
26
+ console.log(pc.yellow("No deployments found."));
27
+ return;
28
+ }
29
+ const deploy = await apiRequest(
30
+ `/api/projects/${projectId}/deployments/${data.deployments[0].id}`
31
+ );
32
+ printDeployment(deploy);
33
+ }
34
+ }
35
+ function printDeployment(deploy) {
36
+ console.log(pc.bold(`Deployment ${deploy.id.slice(0, 8)}`));
37
+ console.log(` Status: ${colorStatus(deploy.status)}`);
38
+ console.log(` Trigger: ${deploy.trigger.toLowerCase()}`);
39
+ console.log(` Created: ${new Date(deploy.createdAt).toLocaleString()}`);
40
+ console.log();
41
+ if (deploy.buildLogs) {
42
+ console.log(pc.bold("Build Logs:"));
43
+ console.log(pc.dim("\u2500".repeat(60)));
44
+ console.log(deploy.buildLogs);
45
+ console.log(pc.dim("\u2500".repeat(60)));
46
+ }
47
+ if (deploy.containerLogs) {
48
+ console.log();
49
+ console.log(pc.bold("Container Logs:"));
50
+ console.log(pc.dim("\u2500".repeat(60)));
51
+ console.log(deploy.containerLogs);
52
+ console.log(pc.dim("\u2500".repeat(60)));
53
+ }
54
+ }
55
+ function colorStatus(status) {
56
+ switch (status) {
57
+ case "RUNNING":
58
+ return pc.green(status.toLowerCase());
59
+ case "FAILED":
60
+ return pc.red(status.toLowerCase());
61
+ case "BUILDING":
62
+ case "DEPLOYING":
63
+ return pc.yellow(status.toLowerCase());
64
+ default:
65
+ return pc.dim(status.toLowerCase());
66
+ }
67
+ }
68
+ export {
69
+ logs
70
+ };
71
+ //# sourceMappingURL=logs-YDAUCMAV.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/commands/logs.ts"],"sourcesContent":["import pc from 'picocolors'\nimport { apiRequest } 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 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}\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,QAAQ,YAAY;AAEtB,UAAM,SAAS,MAAM;AAAA,MACnB,iBAAiB,SAAS,gBAAgB,QAAQ,UAAU;AAAA,IAC9D;AAEA,oBAAgB,MAAM;AAAA,EACxB,OAAO;AAEL,UAAM,OAAO,MAAM;AAAA,MACjB,iBAAiB,SAAS;AAAA,IAC5B;AAEA,QAAI,KAAK,YAAY,WAAW,GAAG;AACjC,cAAQ,IAAI,GAAG,OAAO,uBAAuB,CAAC;AAC9C;AAAA,IACF;AAGA,UAAM,SAAS,MAAM;AAAA,MACnB,iBAAiB,SAAS,gBAAgB,KAAK,YAAY,CAAC,EAAE,EAAE;AAAA,IAClE;AAEA,oBAAgB,MAAM;AAAA,EACxB;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":[]}
@@ -0,0 +1,42 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ apiRequest
4
+ } from "./chunk-MA7QG54W.js";
5
+ import {
6
+ isAuthenticated
7
+ } from "./chunk-3DKWECRK.js";
8
+
9
+ // src/commands/projects.ts
10
+ import pc from "picocolors";
11
+ async function projects() {
12
+ if (!isAuthenticated()) {
13
+ console.error(pc.red("Not authenticated. Run `specra login` first."));
14
+ process.exit(1);
15
+ }
16
+ const list = await apiRequest("/api/projects");
17
+ if (list.length === 0) {
18
+ console.log(pc.yellow("No projects found."));
19
+ console.log(
20
+ `Create one at ${pc.dim("https://specra.dev/dashboard/projects/new")}`
21
+ );
22
+ return;
23
+ }
24
+ console.log(pc.bold(`Projects (${list.length}):`));
25
+ console.log();
26
+ for (const p of list) {
27
+ const status = p.deployments[0]?.status || "NOT_DEPLOYED";
28
+ const statusColor = status === "RUNNING" ? pc.green : status === "FAILED" ? pc.red : pc.dim;
29
+ console.log(
30
+ ` ${pc.bold(p.name)} ${pc.dim(`(${p.id.slice(0, 8)})`)} ${statusColor(status.toLowerCase())}`
31
+ );
32
+ console.log(` ${pc.dim(`${p.subdomain}.docs.specra.dev`)}`);
33
+ if (p.customDomain) {
34
+ console.log(` ${pc.dim(p.customDomain)}`);
35
+ }
36
+ console.log();
37
+ }
38
+ }
39
+ export {
40
+ projects
41
+ };
42
+ //# sourceMappingURL=projects-3TAY7EDJ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/commands/projects.ts"],"sourcesContent":["import pc from 'picocolors'\nimport { apiRequest } 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 const list = await apiRequest<Project[]>('/api/projects')\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.dev/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,QAAM,OAAO,MAAM,WAAsB,eAAe;AAExD,MAAI,KAAK,WAAW,GAAG;AACrB,YAAQ,IAAI,GAAG,OAAO,oBAAoB,CAAC;AAC3C,YAAQ;AAAA,MACN,iBAAiB,GAAG,IAAI,2CAA2C,CAAC;AAAA,IACtE;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,WACX,GAAG,MACH,GAAG;AAET,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,10 +1,11 @@
1
1
  {
2
2
  "name": "create-specra",
3
- "version": "0.1.7",
3
+ "version": "0.2.0",
4
4
  "description": "CLI tool to scaffold a new Specra documentation site with Next.js",
5
5
  "type": "module",
6
6
  "bin": {
7
- "create-specra": "./dist/index.js"
7
+ "create-specra": "./dist/index.js",
8
+ "specra": "./dist/cli.js"
8
9
  },
9
10
  "files": [
10
11
  "dist",
@@ -29,11 +30,14 @@
29
30
  "type": "git",
30
31
  "url": "https://github.com/dalmasonto/specra-cli"
31
32
  },
32
- "license": "MIT",
33
+ "license": "SEE LICENSE IN LICENSE.MD",
33
34
  "dependencies": {
34
35
  "commander": "^12.1.0",
36
+ "open": "^11.0.0",
37
+ "ora": "^9.3.0",
35
38
  "picocolors": "^1.1.1",
36
39
  "prompts": "^2.4.2",
40
+ "tar": "^7.5.7",
37
41
  "validate-npm-package-name": "^6.0.0"
38
42
  },
39
43
  "devDependencies": {
@@ -0,0 +1,89 @@
1
+ ---
2
+ title: Core Concepts
3
+ description: Understand the key ideas behind the documentation platform
4
+ sidebar_position: 3
5
+ icon: lightbulb
6
+ ---
7
+
8
+ Before diving into content creation, it helps to understand a few core concepts that shape how the platform works.
9
+
10
+ ## MDX
11
+
12
+ MDX is Markdown with components. You write standard Markdown and can embed rich, interactive components directly in your content.
13
+
14
+ ```mdx
15
+ # Regular Markdown
16
+
17
+ This is a paragraph with **bold** and *italic* text.
18
+
19
+ <Callout type="tip">
20
+ And this is an interactive component inside Markdown!
21
+ </Callout>
22
+ ```
23
+
24
+ <Callout type="info">
25
+ All documentation files use the `.mdx` extension, not `.md`.
26
+ </Callout>
27
+
28
+ ## Frontmatter
29
+
30
+ Every page starts with frontmatter — a YAML block at the top of the file that defines metadata:
31
+
32
+ ```mdx
33
+ ---
34
+ title: Page Title
35
+ description: A short description for SEO
36
+ sidebar_position: 1
37
+ icon: book
38
+ ---
39
+ ```
40
+
41
+ | Field | Required | Description |
42
+ |-------|----------|-------------|
43
+ | `title` | Yes | Page title shown in sidebar and browser tab |
44
+ | `description` | Recommended | Short description for search engines |
45
+ | `sidebar_position` | No | Controls order in sidebar (lower number = higher up) |
46
+ | `icon` | No | Lucide icon name for the sidebar |
47
+ | `tags` | No | Array of tags for categorization |
48
+
49
+ ## Versioning
50
+
51
+ Documentation is organized by version. Each version lives in its own folder:
52
+
53
+ ```txt
54
+ docs/
55
+ ├── v1.0.0/ # Stable release
56
+ ├── v2.0.0/ # Next major release
57
+ └── next/ # Development docs
58
+ ```
59
+
60
+ Users can switch between versions using the version selector in the header.
61
+
62
+ ## Sidebar Navigation
63
+
64
+ The sidebar is automatically generated from your folder structure. You control the order and appearance using:
65
+
66
+ - **`sidebar_position`** in frontmatter — sets page order
67
+ - **`_category_.json`** in folders — configures section labels and behavior
68
+
69
+ ```json
70
+ {
71
+ "label": "Getting Started",
72
+ "position": 1,
73
+ "collapsible": true,
74
+ "collapsed": false
75
+ }
76
+ ```
77
+
78
+ ## Components
79
+
80
+ The platform includes a library of built-in components that you can use without any imports:
81
+
82
+ <CardGrid cols={3}>
83
+ <Card icon="message-square" title="Callouts" description="Highlight important info" />
84
+ <Card icon="layers" title="Tabs" description="Tabbed content panels" />
85
+ <Card icon="list" title="Steps" description="Step-by-step guides" />
86
+ <Card icon="grid" title="Cards" description="Feature cards with icons" />
87
+ <Card icon="code" title="Code Blocks" description="Syntax-highlighted code" />
88
+ <Card icon="chevrons-up-down" title="Accordion" description="Collapsible sections" />
89
+ </CardGrid>
@@ -0,0 +1,7 @@
1
+ {
2
+ "label": "Content",
3
+ "position": 4,
4
+ "collapsible": true,
5
+ "collapsed": false,
6
+ "icon": "file-text"
7
+ }
@@ -0,0 +1,128 @@
1
+ ---
2
+ title: Formatting
3
+ description: Format your content with Markdown and components
4
+ sidebar_position: 1
5
+ ---
6
+
7
+ This guide covers the formatting options available for your documentation pages.
8
+
9
+ ## Text Formatting
10
+
11
+ Standard Markdown formatting is fully supported:
12
+
13
+ | Syntax | Output |
14
+ |--------|--------|
15
+ | `**bold**` | **bold** |
16
+ | `*italic*` | *italic* |
17
+ | `` `code` `` | `code` |
18
+ | `~~strikethrough~~` | ~~strikethrough~~ |
19
+
20
+ ## Headings
21
+
22
+ Use headings to structure your content. The table of contents on the right is generated from your headings.
23
+
24
+ ```markdown
25
+ ## Second Level
26
+ ### Third Level
27
+ #### Fourth Level
28
+ ```
29
+
30
+ <Callout type="tip">
31
+ Start with `##` (H2) in your content. The page title from frontmatter is rendered as H1 automatically.
32
+ </Callout>
33
+
34
+ ## Lists
35
+
36
+ ### Unordered Lists
37
+
38
+ ```markdown
39
+ - First item
40
+ - Second item
41
+ - Nested item
42
+ - Another nested item
43
+ - Third item
44
+ ```
45
+
46
+ - First item
47
+ - Second item
48
+ - Nested item
49
+ - Another nested item
50
+ - Third item
51
+
52
+ ### Ordered Lists
53
+
54
+ 1. First step
55
+ 2. Second step
56
+ 3. Third step
57
+
58
+ ## Code Blocks
59
+
60
+ Use fenced code blocks with a language identifier for syntax highlighting:
61
+
62
+ ```typescript
63
+ interface Config {
64
+ title: string;
65
+ theme: 'light' | 'dark' | 'system';
66
+ version: string;
67
+ }
68
+
69
+ function loadConfig(path: string): Config {
70
+ const raw = readFileSync(path, 'utf-8');
71
+ return JSON.parse(raw);
72
+ }
73
+ ```
74
+
75
+ ## Tables
76
+
77
+ ```markdown
78
+ | Feature | Status |
79
+ |---------|--------|
80
+ | Dark Mode | Supported |
81
+ | Search | Supported |
82
+ | i18n | Coming Soon |
83
+ ```
84
+
85
+ | Feature | Status |
86
+ |---------|--------|
87
+ | Dark Mode | Supported |
88
+ | Search | Supported |
89
+ | i18n | Coming Soon |
90
+
91
+ ## Callouts
92
+
93
+ Use callouts to draw attention to important information:
94
+
95
+ <Callout type="info">
96
+ Informational callouts provide additional context.
97
+ </Callout>
98
+
99
+ <Callout type="warning">
100
+ Warning callouts alert readers to potential issues.
101
+ </Callout>
102
+
103
+ <Callout type="tip">
104
+ Tip callouts suggest best practices or shortcuts.
105
+ </Callout>
106
+
107
+ ## Tabs
108
+
109
+ Use tabs to show alternative content side by side:
110
+
111
+ <Tabs defaultValue="JavaScript">
112
+ <Tab label="JavaScript">
113
+ ```javascript
114
+ console.log("Hello, world!");
115
+ ```
116
+ </Tab>
117
+ <Tab label="Python">
118
+ ```python
119
+ print("Hello, world!")
120
+ ```
121
+ </Tab>
122
+ </Tabs>
123
+
124
+ ## Links
125
+
126
+ - **Internal links**: `[Getting Started](/docs/v1.0.0/quickstart)`
127
+ - **External links**: `[GitHub](https://github.com)`
128
+ - **Anchor links**: `[See below](#callouts)`
@@ -0,0 +1,116 @@
1
+ ---
2
+ title: Reusable Content
3
+ description: Create reusable content blocks for consistent documentation
4
+ sidebar_position: 3
5
+ ---
6
+
7
+ Reusable content helps you maintain consistency across your documentation by defining content once and using it in multiple places.
8
+
9
+ ## Components as Reusable Blocks
10
+
11
+ The built-in component library provides reusable patterns for common documentation needs.
12
+
13
+ ### Card Grids
14
+
15
+ Use card grids to create consistent navigation sections across pages:
16
+
17
+ <CardGrid cols={3}>
18
+ <Card icon="zap" title="Fast" description="Optimized for speed" />
19
+ <Card icon="shield" title="Secure" description="Built with security in mind" />
20
+ <Card icon="code" title="Developer First" description="Great developer experience" />
21
+ </CardGrid>
22
+
23
+ ### Step-by-Step Patterns
24
+
25
+ Use the Steps component for consistent instructional content:
26
+
27
+ <Steps>
28
+ <Step title="Define the Content">
29
+ Write your content in MDX format with clear, concise language.
30
+ </Step>
31
+
32
+ <Step title="Add Components">
33
+ Enhance your content with interactive components like callouts, tabs, and cards.
34
+ </Step>
35
+
36
+ <Step title="Review and Publish">
37
+ Preview your changes locally, then commit and deploy.
38
+ </Step>
39
+ </Steps>
40
+
41
+ ## Consistent Callout Patterns
42
+
43
+ Use standardized callout types across your docs for a consistent reading experience:
44
+
45
+ <Callout type="info">
46
+ **Info callouts** provide supplementary context that helps readers understand a topic better.
47
+ </Callout>
48
+
49
+ <Callout type="warning">
50
+ **Warning callouts** alert readers about potential pitfalls or breaking changes.
51
+ </Callout>
52
+
53
+ <Callout type="tip">
54
+ **Tip callouts** share best practices and shortcuts that improve the reader's workflow.
55
+ </Callout>
56
+
57
+ ## Tabbed Content Patterns
58
+
59
+ Use tabs to provide content variations. Common patterns include:
60
+
61
+ ### Installation Instructions
62
+
63
+ <Tabs defaultValue="npm">
64
+ <Tab label="npm">
65
+ ```bash
66
+ npm install my-package
67
+ ```
68
+ </Tab>
69
+ <Tab label="yarn">
70
+ ```bash
71
+ yarn add my-package
72
+ ```
73
+ </Tab>
74
+ <Tab label="pnpm">
75
+ ```bash
76
+ pnpm add my-package
77
+ ```
78
+ </Tab>
79
+ </Tabs>
80
+
81
+ ### Language Examples
82
+
83
+ <Tabs defaultValue="TypeScript">
84
+ <Tab label="TypeScript">
85
+ ```typescript
86
+ const greeting: string = "Hello, world!";
87
+ console.log(greeting);
88
+ ```
89
+ </Tab>
90
+ <Tab label="Python">
91
+ ```python
92
+ greeting = "Hello, world!"
93
+ print(greeting)
94
+ ```
95
+ </Tab>
96
+ <Tab label="Go">
97
+ ```go
98
+ package main
99
+
100
+ import "fmt"
101
+
102
+ func main() {
103
+ fmt.Println("Hello, world!")
104
+ }
105
+ ```
106
+ </Tab>
107
+ </Tabs>
108
+
109
+ ## Best Practices
110
+
111
+ | Practice | Description |
112
+ |----------|-------------|
113
+ | **Use consistent types** | Always use the same callout type for the same kind of information |
114
+ | **Keep cards brief** | Card descriptions should be one short sentence |
115
+ | **Limit tab count** | Use 2-4 tabs per group for readability |
116
+ | **Name tabs clearly** | Tab labels should be short and descriptive |