@sagebase/cli 0.0.1-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +1 -0
- package/dist/index.js +416 -0
- package/dist/index.js.map +1 -0
- package/package.json +49 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,416 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/index.ts
|
|
4
|
+
import { Command as Command3 } from "commander";
|
|
5
|
+
|
|
6
|
+
// src/commands/init.ts
|
|
7
|
+
import { Command } from "commander";
|
|
8
|
+
import { constants } from "fs";
|
|
9
|
+
import { access, mkdir, writeFile } from "fs/promises";
|
|
10
|
+
import { resolve as resolve2 } from "path";
|
|
11
|
+
import { z as z2 } from "zod";
|
|
12
|
+
|
|
13
|
+
// src/utils/logger.ts
|
|
14
|
+
import kleur from "kleur";
|
|
15
|
+
var logger = {
|
|
16
|
+
error(...args) {
|
|
17
|
+
console.log(kleur.red("\u2717"), ...args);
|
|
18
|
+
},
|
|
19
|
+
warn(...args) {
|
|
20
|
+
console.log(kleur.yellow("\u26A0"), ...args);
|
|
21
|
+
},
|
|
22
|
+
info(...args) {
|
|
23
|
+
console.log(kleur.cyan("\u2139"), ...args);
|
|
24
|
+
},
|
|
25
|
+
success(...args) {
|
|
26
|
+
console.log(kleur.green("\u2713"), ...args);
|
|
27
|
+
},
|
|
28
|
+
log(...args) {
|
|
29
|
+
console.log(...args);
|
|
30
|
+
},
|
|
31
|
+
break() {
|
|
32
|
+
console.log("");
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
// src/utils/spinner.ts
|
|
37
|
+
import ora from "ora";
|
|
38
|
+
function createSpinner(text) {
|
|
39
|
+
const spinner = ora({
|
|
40
|
+
text,
|
|
41
|
+
color: "cyan"
|
|
42
|
+
});
|
|
43
|
+
return {
|
|
44
|
+
start() {
|
|
45
|
+
spinner.start();
|
|
46
|
+
return this;
|
|
47
|
+
},
|
|
48
|
+
succeed(text2) {
|
|
49
|
+
spinner.succeed(text2);
|
|
50
|
+
return this;
|
|
51
|
+
},
|
|
52
|
+
fail(text2) {
|
|
53
|
+
spinner.fail(text2);
|
|
54
|
+
return this;
|
|
55
|
+
},
|
|
56
|
+
stop() {
|
|
57
|
+
spinner.stop();
|
|
58
|
+
return this;
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// src/utils/handle-error.ts
|
|
64
|
+
function handleError(error) {
|
|
65
|
+
if (error instanceof Error) {
|
|
66
|
+
logger.error(error.message);
|
|
67
|
+
} else {
|
|
68
|
+
logger.error(String(error));
|
|
69
|
+
}
|
|
70
|
+
process.exit(1);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// src/utils/get-config.ts
|
|
74
|
+
import { cosmiconfig } from "cosmiconfig";
|
|
75
|
+
import { z } from "zod";
|
|
76
|
+
var explorer = cosmiconfig("sage", {
|
|
77
|
+
searchPlaces: ["sage.json", "sage.config.json", "sage.config.ts"]
|
|
78
|
+
});
|
|
79
|
+
var sageConfigSchema = z.object({
|
|
80
|
+
$schema: z.string().optional(),
|
|
81
|
+
framework: z.enum(["nextjs", "tanstack-start"]).default("nextjs"),
|
|
82
|
+
content: z.string().default("content/docs"),
|
|
83
|
+
agent: z.object({
|
|
84
|
+
model: z.string().default("anthropic/claude-sonnet-4-6"),
|
|
85
|
+
provider: z.string().default("anthropic")
|
|
86
|
+
}).default({}),
|
|
87
|
+
ci: z.object({
|
|
88
|
+
trigger: z.string().default("pr-merge"),
|
|
89
|
+
workflow: z.string().default(".github/workflows/sage.yml")
|
|
90
|
+
}).default({})
|
|
91
|
+
});
|
|
92
|
+
async function getConfig(cwd) {
|
|
93
|
+
try {
|
|
94
|
+
const result = await explorer.search(cwd);
|
|
95
|
+
if (!result?.config) return null;
|
|
96
|
+
return sageConfigSchema.parse(result.config);
|
|
97
|
+
} catch {
|
|
98
|
+
return null;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
function getDefaultConfig() {
|
|
102
|
+
return sageConfigSchema.parse({});
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// src/utils/get-project-info.ts
|
|
106
|
+
import { existsSync } from "fs";
|
|
107
|
+
import { resolve } from "path";
|
|
108
|
+
function detectFramework(cwd) {
|
|
109
|
+
if (existsSync(resolve(cwd, "next.config.js")) || existsSync(resolve(cwd, "next.config.ts")) || existsSync(resolve(cwd, "next.config.mjs"))) {
|
|
110
|
+
return "nextjs";
|
|
111
|
+
}
|
|
112
|
+
if (existsSync(resolve(cwd, "vite.config.ts")) || existsSync(resolve(cwd, "vite.config.js"))) {
|
|
113
|
+
const hasRouter = existsSync(resolve(cwd, "app.config.ts"));
|
|
114
|
+
if (hasRouter) return "tanstack-start";
|
|
115
|
+
}
|
|
116
|
+
return null;
|
|
117
|
+
}
|
|
118
|
+
function detectContentDir(cwd) {
|
|
119
|
+
const candidates = ["content/docs", "src/content/docs"];
|
|
120
|
+
for (const dir of candidates) {
|
|
121
|
+
if (existsSync(resolve(cwd, dir))) {
|
|
122
|
+
return dir;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
return null;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// src/utils/get-monorepo-info.ts
|
|
129
|
+
import path from "path";
|
|
130
|
+
|
|
131
|
+
// src/utils/highlighter.ts
|
|
132
|
+
import kleur2 from "kleur";
|
|
133
|
+
var highlighter = {
|
|
134
|
+
error: kleur2.red,
|
|
135
|
+
warn: kleur2.yellow,
|
|
136
|
+
info: kleur2.cyan,
|
|
137
|
+
success: kleur2.green,
|
|
138
|
+
highlight: kleur2.bold,
|
|
139
|
+
dim: kleur2.dim,
|
|
140
|
+
code: kleur2.italic
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
// src/utils/get-monorepo-info.ts
|
|
144
|
+
import fg from "fast-glob";
|
|
145
|
+
import fs from "fs-extra";
|
|
146
|
+
var FRAMEWORK_CONFIG_FILES = [
|
|
147
|
+
"next.config.*",
|
|
148
|
+
"vite.config.*",
|
|
149
|
+
"astro.config.*",
|
|
150
|
+
"remix.config.*",
|
|
151
|
+
"nuxt.config.*",
|
|
152
|
+
"svelte.config.*",
|
|
153
|
+
"gatsby-config.*",
|
|
154
|
+
"angular.json"
|
|
155
|
+
];
|
|
156
|
+
async function isMonorepoRoot(cwd) {
|
|
157
|
+
if (fs.existsSync(path.resolve(cwd, "pnpm-workspace.yaml"))) {
|
|
158
|
+
return true;
|
|
159
|
+
}
|
|
160
|
+
const packageJsonPath = path.resolve(cwd, "package.json");
|
|
161
|
+
if (fs.existsSync(packageJsonPath)) {
|
|
162
|
+
try {
|
|
163
|
+
const packageJson = await fs.readJson(packageJsonPath);
|
|
164
|
+
if (packageJson.workspaces) {
|
|
165
|
+
return true;
|
|
166
|
+
}
|
|
167
|
+
} catch {
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
if (fs.existsSync(path.resolve(cwd, "lerna.json"))) {
|
|
171
|
+
return true;
|
|
172
|
+
}
|
|
173
|
+
if (fs.existsSync(path.resolve(cwd, "nx.json"))) {
|
|
174
|
+
return true;
|
|
175
|
+
}
|
|
176
|
+
return false;
|
|
177
|
+
}
|
|
178
|
+
async function getMonorepoTargets(cwd) {
|
|
179
|
+
const patterns = await getWorkspacePatterns(cwd);
|
|
180
|
+
if (!patterns.length) {
|
|
181
|
+
return [];
|
|
182
|
+
}
|
|
183
|
+
const dirs = await fg(patterns, {
|
|
184
|
+
cwd,
|
|
185
|
+
onlyDirectories: true,
|
|
186
|
+
ignore: ["**/node_modules/**"]
|
|
187
|
+
});
|
|
188
|
+
const targets = [];
|
|
189
|
+
for (const dir of dirs) {
|
|
190
|
+
const fullPath = path.resolve(cwd, dir);
|
|
191
|
+
if (!fs.existsSync(path.resolve(fullPath, "package.json"))) {
|
|
192
|
+
continue;
|
|
193
|
+
}
|
|
194
|
+
const hasSageJson = fs.existsSync(
|
|
195
|
+
path.resolve(fullPath, "sage.json")
|
|
196
|
+
);
|
|
197
|
+
const hasFrameworkConfig = FRAMEWORK_CONFIG_FILES.some((pattern) => {
|
|
198
|
+
const matches = fg.sync(pattern, {
|
|
199
|
+
cwd: fullPath,
|
|
200
|
+
dot: true
|
|
201
|
+
});
|
|
202
|
+
return matches.length > 0;
|
|
203
|
+
});
|
|
204
|
+
if (hasSageJson || hasFrameworkConfig) {
|
|
205
|
+
targets.push({
|
|
206
|
+
name: dir,
|
|
207
|
+
hasConfig: hasSageJson
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
return targets;
|
|
212
|
+
}
|
|
213
|
+
function formatMonorepoMessage(command, targets, options) {
|
|
214
|
+
const cwdFlag = options?.cwdFlag ?? "--cwd";
|
|
215
|
+
logger.break();
|
|
216
|
+
logger.log(
|
|
217
|
+
`It looks like you are running ${highlighter.info(
|
|
218
|
+
command
|
|
219
|
+
)} from a monorepo root.`
|
|
220
|
+
);
|
|
221
|
+
logger.log(
|
|
222
|
+
`To use sage in a specific workspace, use the ${highlighter.info(
|
|
223
|
+
cwdFlag
|
|
224
|
+
)} flag:`
|
|
225
|
+
);
|
|
226
|
+
logger.break();
|
|
227
|
+
for (const target of targets) {
|
|
228
|
+
logger.log(` sage ${command} ${cwdFlag} ${target.name}`);
|
|
229
|
+
}
|
|
230
|
+
logger.break();
|
|
231
|
+
}
|
|
232
|
+
async function getWorkspacePatterns(cwd) {
|
|
233
|
+
const patterns = [];
|
|
234
|
+
const pnpmWorkspacePath = path.resolve(cwd, "pnpm-workspace.yaml");
|
|
235
|
+
if (fs.existsSync(pnpmWorkspacePath)) {
|
|
236
|
+
const content = await fs.readFile(pnpmWorkspacePath, "utf8");
|
|
237
|
+
patterns.push(...parsePnpmWorkspacePackages(content));
|
|
238
|
+
}
|
|
239
|
+
const packageJsonPath = path.resolve(cwd, "package.json");
|
|
240
|
+
if (fs.existsSync(packageJsonPath)) {
|
|
241
|
+
try {
|
|
242
|
+
const packageJson = await fs.readJson(packageJsonPath);
|
|
243
|
+
const workspaces = Array.isArray(packageJson.workspaces) ? packageJson.workspaces : packageJson.workspaces?.packages;
|
|
244
|
+
if (Array.isArray(workspaces)) {
|
|
245
|
+
patterns.push(...workspaces.filter((w) => !w.startsWith("!")));
|
|
246
|
+
}
|
|
247
|
+
} catch {
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
return Array.from(new Set(patterns));
|
|
251
|
+
}
|
|
252
|
+
function parsePnpmWorkspacePackages(content) {
|
|
253
|
+
const patterns = [];
|
|
254
|
+
let inPackages = false;
|
|
255
|
+
let packagesIndent = 0;
|
|
256
|
+
for (const line of content.split("\n")) {
|
|
257
|
+
const trimmed = line.trim();
|
|
258
|
+
if (!trimmed || trimmed.startsWith("#")) {
|
|
259
|
+
continue;
|
|
260
|
+
}
|
|
261
|
+
const keyMatch = line.match(/^(\s*)([A-Za-z0-9_-]+)\s*:/);
|
|
262
|
+
if (keyMatch) {
|
|
263
|
+
packagesIndent = keyMatch[1].length;
|
|
264
|
+
inPackages = keyMatch[2] === "packages";
|
|
265
|
+
continue;
|
|
266
|
+
}
|
|
267
|
+
if (!inPackages) {
|
|
268
|
+
continue;
|
|
269
|
+
}
|
|
270
|
+
const itemMatch = line.match(/^(\s*)-\s*(.+?)\s*(?:#.*)?$/);
|
|
271
|
+
if (!itemMatch || itemMatch[1].length <= packagesIndent) {
|
|
272
|
+
continue;
|
|
273
|
+
}
|
|
274
|
+
patterns.push(itemMatch[2].trim().replace(/^["']|["']$/g, ""));
|
|
275
|
+
}
|
|
276
|
+
return patterns;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
// src/commands/init.ts
|
|
280
|
+
var initOptionsSchema = z2.object({
|
|
281
|
+
cwd: z2.string().optional(),
|
|
282
|
+
defaults: z2.boolean().optional(),
|
|
283
|
+
helpCenter: z2.boolean().optional()
|
|
284
|
+
});
|
|
285
|
+
var CONTENT_SAMPLE = `---
|
|
286
|
+
title: Welcome
|
|
287
|
+
description: Welcome to our help center
|
|
288
|
+
---
|
|
289
|
+
|
|
290
|
+
# Welcome
|
|
291
|
+
|
|
292
|
+
This help center is maintained by Sage \u2014 an AI agent that keeps your documentation accurate as you ship.
|
|
293
|
+
|
|
294
|
+
## Getting started
|
|
295
|
+
|
|
296
|
+
Replace this sample content with your own documentation.
|
|
297
|
+
`;
|
|
298
|
+
var WORKFLOW_YML = `name: Sage Documentation
|
|
299
|
+
on:
|
|
300
|
+
push:
|
|
301
|
+
branches: [main]
|
|
302
|
+
jobs:
|
|
303
|
+
sage:
|
|
304
|
+
runs-on: ubuntu-latest
|
|
305
|
+
steps:
|
|
306
|
+
- uses: actions/checkout@v4
|
|
307
|
+
with:
|
|
308
|
+
fetch-depth: 0
|
|
309
|
+
- uses: actions/setup-node@v4
|
|
310
|
+
with:
|
|
311
|
+
node-version: 20
|
|
312
|
+
- run: npx @sagebase/cli run
|
|
313
|
+
env:
|
|
314
|
+
ANTHROPIC_API_KEY: \${{ secrets.ANTHROPIC_API_KEY }}
|
|
315
|
+
`;
|
|
316
|
+
var init = new Command().name("init").alias("create").description("initialize sage in your project").argument("[dir]", "project directory").option("--cwd <cwd>", "working directory").option("--defaults", "use default configuration without prompting").option("--help-center", "add Fumadocs help center").action(async (dir, opts) => {
|
|
317
|
+
try {
|
|
318
|
+
const options = initOptionsSchema.parse(opts);
|
|
319
|
+
const cwd = resolve2(dir || options.cwd || process.cwd());
|
|
320
|
+
logger.log(options, cwd);
|
|
321
|
+
const spinner = createSpinner("Setting up Sage...").start();
|
|
322
|
+
const framework = detectFramework(cwd);
|
|
323
|
+
if (!framework) {
|
|
324
|
+
if (await isMonorepoRoot(cwd)) {
|
|
325
|
+
const targets = await getMonorepoTargets(cwd);
|
|
326
|
+
if (targets.length > 0) {
|
|
327
|
+
spinner.stop();
|
|
328
|
+
formatMonorepoMessage("init", targets);
|
|
329
|
+
process.exit(1);
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
spinner.fail(
|
|
333
|
+
"Could not detect framework. Only Next.js and TanStack Start are supported."
|
|
334
|
+
);
|
|
335
|
+
process.exit(1);
|
|
336
|
+
}
|
|
337
|
+
const existingContent = detectContentDir(cwd);
|
|
338
|
+
const contentDir = existingContent || "content/docs";
|
|
339
|
+
const config = getDefaultConfig();
|
|
340
|
+
config.framework = framework;
|
|
341
|
+
config.content = contentDir;
|
|
342
|
+
await mkdir(resolve2(cwd, "content", "docs"), { recursive: true });
|
|
343
|
+
const indexMdxPath = resolve2(cwd, contentDir, "index.mdx");
|
|
344
|
+
try {
|
|
345
|
+
await access(indexMdxPath, constants.F_OK);
|
|
346
|
+
} catch {
|
|
347
|
+
await writeFile(indexMdxPath, CONTENT_SAMPLE);
|
|
348
|
+
}
|
|
349
|
+
const workflowsDir = resolve2(cwd, ".github", "workflows");
|
|
350
|
+
await mkdir(workflowsDir, { recursive: true });
|
|
351
|
+
await writeFile(resolve2(workflowsDir, "sage.yml"), WORKFLOW_YML);
|
|
352
|
+
await writeFile(
|
|
353
|
+
resolve2(cwd, "sage.json"),
|
|
354
|
+
JSON.stringify(config, null, 2)
|
|
355
|
+
);
|
|
356
|
+
spinner.succeed("Sage initialized!");
|
|
357
|
+
logger.break();
|
|
358
|
+
logger.success("Created:");
|
|
359
|
+
logger.log(` sage.json \u2014 configuration`);
|
|
360
|
+
logger.log(` ${contentDir}/ \u2014 documentation source`);
|
|
361
|
+
logger.log(` .github/workflows/sage.yml \u2014 CI workflow`);
|
|
362
|
+
logger.break();
|
|
363
|
+
logger.info("Next steps:");
|
|
364
|
+
logger.log(" Run sage dev to preview your help center");
|
|
365
|
+
logger.log(" Edit content/docs/ to add your documentation");
|
|
366
|
+
logger.break();
|
|
367
|
+
if (!existingContent) {
|
|
368
|
+
logger.info("Created: content/docs/index.mdx \u2014 sample article");
|
|
369
|
+
}
|
|
370
|
+
} catch (error) {
|
|
371
|
+
handleError(error);
|
|
372
|
+
}
|
|
373
|
+
});
|
|
374
|
+
|
|
375
|
+
// src/commands/dev.ts
|
|
376
|
+
import { Command as Command2 } from "commander";
|
|
377
|
+
import { resolve as resolve3 } from "path";
|
|
378
|
+
import { z as z3 } from "zod";
|
|
379
|
+
var devOptionsSchema = z3.object({
|
|
380
|
+
cwd: z3.string().optional(),
|
|
381
|
+
port: z3.coerce.number().optional()
|
|
382
|
+
});
|
|
383
|
+
var dev = new Command2().name("dev").description("start the help center preview server").option("--cwd <cwd>", "working directory").option("-p, --port <port>", "port to serve on").action(async (opts) => {
|
|
384
|
+
try {
|
|
385
|
+
const options = devOptionsSchema.parse(opts);
|
|
386
|
+
const cwd = resolve3(options.cwd || process.cwd());
|
|
387
|
+
logger.log(options, cwd);
|
|
388
|
+
const config = await getConfig(cwd);
|
|
389
|
+
if (!config) {
|
|
390
|
+
logger.error("No sage.json found. Run sage init first.");
|
|
391
|
+
process.exit(1);
|
|
392
|
+
}
|
|
393
|
+
logger.info(`Content directory: ${config.content}`);
|
|
394
|
+
logger.info(`Framework: ${config.framework}`);
|
|
395
|
+
logger.break();
|
|
396
|
+
logger.info("To preview your help center, run your app's dev server:");
|
|
397
|
+
logger.info(" npm run dev");
|
|
398
|
+
logger.break();
|
|
399
|
+
logger.info("Make sure Fumadocs is configured in your app to read from:");
|
|
400
|
+
logger.info(` ${config.content}`);
|
|
401
|
+
} catch (error) {
|
|
402
|
+
handleError(error);
|
|
403
|
+
}
|
|
404
|
+
});
|
|
405
|
+
|
|
406
|
+
// src/index.ts
|
|
407
|
+
process.on("SIGINT", () => process.exit(0));
|
|
408
|
+
process.on("SIGTERM", () => process.exit(0));
|
|
409
|
+
async function main() {
|
|
410
|
+
const program = new Command3().name("sage").description("AI documentation agent for your codebase").version("0.0.1");
|
|
411
|
+
program.addCommand(init);
|
|
412
|
+
program.addCommand(dev);
|
|
413
|
+
program.parse();
|
|
414
|
+
}
|
|
415
|
+
main();
|
|
416
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/commands/init.ts","../src/utils/logger.ts","../src/utils/spinner.ts","../src/utils/handle-error.ts","../src/utils/get-config.ts","../src/utils/get-project-info.ts","../src/utils/get-monorepo-info.ts","../src/utils/highlighter.ts","../src/commands/dev.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { Command } from \"commander\"\nimport { init } from \"./commands/init.js\"\nimport { dev } from \"./commands/dev.js\"\n\nprocess.on(\"SIGINT\", () => process.exit(0))\nprocess.on(\"SIGTERM\", () => process.exit(0))\n\nasync function main() {\n const program = new Command()\n .name(\"sage\")\n .description(\"AI documentation agent for your codebase\")\n .version(\"0.0.1\")\n\n program.addCommand(init)\n program.addCommand(dev)\n\n program.parse()\n}\n\nmain()\n","import { Command } from \"commander\";\nimport { constants } from \"fs\";\nimport { access, mkdir, writeFile } from \"fs/promises\";\nimport { resolve } from \"path\";\nimport { z } from \"zod\";\nimport { logger } from \"../utils/logger.js\";\nimport { createSpinner } from \"../utils/spinner.js\";\nimport { handleError } from \"../utils/handle-error.js\";\nimport { getDefaultConfig } from \"../utils/get-config.js\";\nimport {\n detectContentDir,\n detectFramework,\n} from \"../utils/get-project-info.js\";\nimport {\n formatMonorepoMessage,\n getMonorepoTargets,\n isMonorepoRoot,\n} from \"../utils/get-monorepo-info.js\";\n\nconst initOptionsSchema = z.object({\n cwd: z.string().optional(),\n defaults: z.boolean().optional(),\n helpCenter: z.boolean().optional(),\n});\n\nconst CONTENT_SAMPLE = `---\ntitle: Welcome\ndescription: Welcome to our help center\n---\n\n# Welcome\n\nThis help center is maintained by Sage — an AI agent that keeps your documentation accurate as you ship.\n\n## Getting started\n\nReplace this sample content with your own documentation.\n`;\n\nconst WORKFLOW_YML = `name: Sage Documentation\non:\n push:\n branches: [main]\njobs:\n sage:\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v4\n with:\n fetch-depth: 0\n - uses: actions/setup-node@v4\n with:\n node-version: 20\n - run: npx @sagebase/cli run\n env:\n ANTHROPIC_API_KEY: \\${{ secrets.ANTHROPIC_API_KEY }}\n`;\n\n// TODO: we need a robust test fixture for both mono-repo, non-monorepo, next, tanstack; shadcn has all figured that out so we can just copy that approach for this; doing it manually is painstaking and always leads to some error cuz i have to do it and i'm lazy\n//\n// DO this before implementing second issue;\nexport const init = new Command()\n .name(\"init\")\n .alias(\"create\")\n .description(\"initialize sage in your project\")\n .argument(\"[dir]\", \"project directory\")\n .option(\"--cwd <cwd>\", \"working directory\")\n .option(\"--defaults\", \"use default configuration without prompting\")\n .option(\"--help-center\", \"add Fumadocs help center\")\n .action(async (dir, opts) => {\n try {\n const options = initOptionsSchema.parse(opts);\n const cwd = resolve(dir || options.cwd || process.cwd());\n\n // pnpm --filter=@sagebase/cli start:dev init ./apps/web\n // {} /Users/bishalneupane/Desktop/myprojects/sagebase/packages/cli/apps/web\n // Relative path does not work, have to pass absolute stuff; maybe fix this?? prioritize maybe the process.cwd more?? that would probably create yet another set of problems right????\n // This worked: bun sage init ~/Desktop/myprojects/sagebase/apps/web\n //\n // init didn't add any cli script into package.json how is the user supposed to run dev now\n // maybe again same npx sage dev command?? right\n //\n //\n // Would it be possible to avoid creating yet anaother config file cuz we're literally drowing in them\n logger.log(options, cwd);\n\n const spinner = createSpinner(\"Setting up Sage...\").start();\n\n const framework = detectFramework(cwd);\n if (!framework) {\n // Check if we're in a monorepo root before failing.\n if (await isMonorepoRoot(cwd)) {\n const targets = await getMonorepoTargets(cwd);\n if (targets.length > 0) {\n spinner.stop();\n formatMonorepoMessage(\"init\", targets);\n process.exit(1);\n }\n }\n spinner.fail(\n \"Could not detect framework. Only Next.js and TanStack Start are supported.\",\n );\n process.exit(1);\n }\n\n // TODO: maybe here we could use the default fuma docs cli here instead of trying to do this stuff manaully we could have more options from there; but that means we are getting joined with fuma-docs so there is a bit of trade-off there; we won't be able to control the whole setting up experience\n // how does the better-t-setup does this things well??\n //\n // Better idea is to let the user do the setup themselves directly using the fuma-docs cli and configure everything they want, and we don't deal with all that complexity ourselves and doing that will make ur repo both easy and we'll not be tied to fuma-docs as well;\n const existingContent = detectContentDir(cwd);\n const contentDir = existingContent || \"content/docs\";\n\n const config = getDefaultConfig();\n config.framework = framework;\n config.content = contentDir;\n\n await mkdir(resolve(cwd, \"content\", \"docs\"), { recursive: true });\n\n const indexMdxPath = resolve(cwd, contentDir, \"index.mdx\");\n try {\n await access(indexMdxPath, constants.F_OK);\n } catch {\n await writeFile(indexMdxPath, CONTENT_SAMPLE);\n }\n\n // TODO: here should also not do the access and write only if not exists; or is it just okay to write multiple times; here\n const workflowsDir = resolve(cwd, \".github\", \"workflows\");\n await mkdir(workflowsDir, { recursive: true });\n await writeFile(resolve(workflowsDir, \"sage.yml\"), WORKFLOW_YML);\n\n await writeFile(\n resolve(cwd, \"sage.json\"),\n JSON.stringify(config, null, 2),\n );\n\n spinner.succeed(\"Sage initialized!\");\n\n logger.break();\n logger.success(\"Created:\");\n logger.log(` sage.json — configuration`);\n logger.log(` ${contentDir}/ — documentation source`);\n logger.log(` .github/workflows/sage.yml — CI workflow`);\n logger.break();\n logger.info(\"Next steps:\");\n logger.log(\" Run sage dev to preview your help center\");\n logger.log(\" Edit content/docs/ to add your documentation\");\n logger.break();\n\n if (!existingContent) {\n logger.info(\"Created: content/docs/index.mdx — sample article\");\n }\n } catch (error) {\n handleError(error);\n }\n });\n","import kleur from \"kleur\"\n\nexport const logger = {\n error(...args: unknown[]) {\n console.log(kleur.red(\"✗\"), ...args)\n },\n warn(...args: unknown[]) {\n console.log(kleur.yellow(\"⚠\"), ...args)\n },\n info(...args: unknown[]) {\n console.log(kleur.cyan(\"ℹ\"), ...args)\n },\n success(...args: unknown[]) {\n console.log(kleur.green(\"✓\"), ...args)\n },\n log(...args: unknown[]) {\n console.log(...args)\n },\n break() {\n console.log(\"\")\n },\n}\n","import ora from \"ora\"\n\nexport function createSpinner(text: string) {\n const spinner = ora({\n text,\n color: \"cyan\",\n })\n\n return {\n start() {\n spinner.start()\n return this\n },\n succeed(text?: string) {\n spinner.succeed(text)\n return this\n },\n fail(text?: string) {\n spinner.fail(text)\n return this\n },\n stop() {\n spinner.stop()\n return this\n },\n }\n}\n","import { logger } from \"./logger.js\"\n\nexport function handleError(error: unknown) {\n if (error instanceof Error) {\n logger.error(error.message)\n } else {\n logger.error(String(error))\n }\n\n process.exit(1)\n}\n","import { cosmiconfig } from \"cosmiconfig\"\nimport { z } from \"zod\"\n\nconst explorer = cosmiconfig(\"sage\", {\n searchPlaces: [\"sage.json\", \"sage.config.json\", \"sage.config.ts\"],\n})\n\nexport const sageConfigSchema = z.object({\n $schema: z.string().optional(),\n framework: z.enum([\"nextjs\", \"tanstack-start\"]).default(\"nextjs\"),\n content: z.string().default(\"content/docs\"),\n agent: z\n .object({\n model: z.string().default(\"anthropic/claude-sonnet-4-6\"),\n provider: z.string().default(\"anthropic\"),\n })\n .default({}),\n ci: z\n .object({\n trigger: z.string().default(\"pr-merge\"),\n workflow: z.string().default(\".github/workflows/sage.yml\"),\n })\n .default({}),\n})\n\nexport type SageConfig = z.infer<typeof sageConfigSchema>\n\nexport async function getConfig(cwd?: string): Promise<SageConfig | null> {\n try {\n const result = await explorer.search(cwd)\n if (!result?.config) return null\n return sageConfigSchema.parse(result.config)\n } catch {\n return null\n }\n}\n\nexport function getDefaultConfig(): SageConfig {\n return sageConfigSchema.parse({})\n}\n","import { existsSync } from \"fs\"\nimport { resolve } from \"path\"\n\nexport type Framework = \"nextjs\" | \"tanstack-start\" | null\n\nexport function detectFramework(cwd: string): Framework {\n if (existsSync(resolve(cwd, \"next.config.js\")) || existsSync(resolve(cwd, \"next.config.ts\")) || existsSync(resolve(cwd, \"next.config.mjs\"))) {\n return \"nextjs\"\n }\n if (existsSync(resolve(cwd, \"vite.config.ts\")) || existsSync(resolve(cwd, \"vite.config.js\"))) {\n const hasRouter = existsSync(resolve(cwd, \"app.config.ts\"))\n if (hasRouter) return \"tanstack-start\"\n }\n return null\n}\n\nexport function detectContentDir(cwd: string): string | null {\n const candidates = [\"content/docs\", \"src/content/docs\"]\n for (const dir of candidates) {\n if (existsSync(resolve(cwd, dir))) {\n return dir\n }\n }\n return null\n}\n","import path from \"path\"\nimport { highlighter } from \"../utils/highlighter.js\"\nimport { logger } from \"../utils/logger.js\"\nimport fg from \"fast-glob\"\nimport fs from \"fs-extra\"\n\nconst FRAMEWORK_CONFIG_FILES = [\n \"next.config.*\",\n \"vite.config.*\",\n \"astro.config.*\",\n \"remix.config.*\",\n \"nuxt.config.*\",\n \"svelte.config.*\",\n \"gatsby-config.*\",\n \"angular.json\",\n]\n\n// Checks for workspace signals at the given directory.\nexport async function isMonorepoRoot(cwd: string) {\n // pnpm workspaces.\n if (fs.existsSync(path.resolve(cwd, \"pnpm-workspace.yaml\"))) {\n return true\n }\n\n // npm/yarn workspaces.\n const packageJsonPath = path.resolve(cwd, \"package.json\")\n if (fs.existsSync(packageJsonPath)) {\n try {\n const packageJson = await fs.readJson(packageJsonPath)\n if (packageJson.workspaces) {\n return true\n }\n } catch {\n // Ignore parse errors.\n }\n }\n\n // Lerna.\n if (fs.existsSync(path.resolve(cwd, \"lerna.json\"))) {\n return true\n }\n\n // Nx.\n if (fs.existsSync(path.resolve(cwd, \"nx.json\"))) {\n return true\n }\n\n return false\n}\n\n// Finds app directories in a monorepo that contain framework configs or sage.json.\nexport async function getMonorepoTargets(cwd: string) {\n const patterns = await getWorkspacePatterns(cwd)\n\n if (!patterns.length) {\n return []\n }\n\n // Resolve patterns to directories.\n const dirs = await fg(patterns, {\n cwd,\n onlyDirectories: true,\n ignore: [\"**/node_modules/**\"],\n })\n\n const targets: { name: string; hasConfig: boolean }[] = []\n\n for (const dir of dirs) {\n const fullPath = path.resolve(cwd, dir)\n\n // Check if it has a package.json (it's an actual workspace).\n if (!fs.existsSync(path.resolve(fullPath, \"package.json\"))) {\n continue\n }\n\n const hasSageJson = fs.existsSync(\n path.resolve(fullPath, \"sage.json\")\n )\n\n // Check for framework config files.\n const hasFrameworkConfig = FRAMEWORK_CONFIG_FILES.some((pattern) => {\n const matches = fg.sync(pattern, {\n cwd: fullPath,\n dot: true,\n })\n return matches.length > 0\n })\n\n if (hasSageJson || hasFrameworkConfig) {\n targets.push({\n name: dir,\n hasConfig: hasSageJson,\n })\n }\n }\n\n return targets\n}\n\n// Formats and logs the monorepo detection message.\nexport function formatMonorepoMessage(\n command: string,\n targets: { name: string; hasConfig: boolean }[],\n options?: {\n cwdFlag?: string\n }\n) {\n const cwdFlag = options?.cwdFlag ?? \"--cwd\"\n\n logger.break()\n logger.log(\n `It looks like you are running ${highlighter.info(\n command\n )} from a monorepo root.`\n )\n logger.log(\n `To use sage in a specific workspace, use the ${highlighter.info(\n cwdFlag\n )} flag:`\n )\n logger.break()\n\n for (const target of targets) {\n logger.log(` sage ${command} ${cwdFlag} ${target.name}`)\n }\n\n logger.break()\n}\n\nexport async function getWorkspacePatterns(cwd: string) {\n const patterns: string[] = []\n\n // Read pnpm-workspace.yaml.\n const pnpmWorkspacePath = path.resolve(cwd, \"pnpm-workspace.yaml\")\n if (fs.existsSync(pnpmWorkspacePath)) {\n const content = await fs.readFile(pnpmWorkspacePath, \"utf8\")\n patterns.push(...parsePnpmWorkspacePackages(content))\n }\n\n // Read package.json workspaces.\n const packageJsonPath = path.resolve(cwd, \"package.json\")\n if (fs.existsSync(packageJsonPath)) {\n try {\n const packageJson = await fs.readJson(packageJsonPath)\n const workspaces = Array.isArray(packageJson.workspaces)\n ? packageJson.workspaces\n : packageJson.workspaces?.packages\n if (Array.isArray(workspaces)) {\n patterns.push(...workspaces.filter((w: string) => !w.startsWith(\"!\")))\n }\n } catch {\n // Ignore parse errors.\n }\n }\n\n return Array.from(new Set(patterns))\n}\n\nexport function parsePnpmWorkspacePackages(content: string) {\n const patterns: string[] = []\n let inPackages = false\n let packagesIndent = 0\n\n for (const line of content.split(\"\\n\")) {\n const trimmed = line.trim()\n\n if (!trimmed || trimmed.startsWith(\"#\")) {\n continue\n }\n\n const keyMatch = line.match(/^(\\s*)([A-Za-z0-9_-]+)\\s*:/)\n if (keyMatch) {\n packagesIndent = keyMatch[1].length\n inPackages = keyMatch[2] === \"packages\"\n continue\n }\n\n if (!inPackages) {\n continue\n }\n\n const itemMatch = line.match(/^(\\s*)-\\s*(.+?)\\s*(?:#.*)?$/)\n if (!itemMatch || itemMatch[1].length <= packagesIndent) {\n continue\n }\n\n patterns.push(itemMatch[2].trim().replace(/^[\"']|[\"']$/g, \"\"))\n }\n\n return patterns\n}\n","import kleur from \"kleur\"\n\nexport const highlighter = {\n error: kleur.red,\n warn: kleur.yellow,\n info: kleur.cyan,\n success: kleur.green,\n highlight: kleur.bold,\n dim: kleur.dim,\n code: kleur.italic,\n}\n","import { Command } from \"commander\";\nimport { resolve } from \"path\";\nimport { z } from \"zod\";\nimport { handleError } from \"../utils/handle-error.js\";\nimport { getConfig } from \"../utils/get-config.js\";\nimport { logger } from \"../utils/logger.js\";\n\nconst devOptionsSchema = z.object({\n cwd: z.string().optional(),\n port: z.coerce.number().optional(),\n});\n\n// Right now it does not do shit apart from just informing user if config is fine, and giving instruction to setup of fumadocs properly\n//\n// Probably here see if fuma-docs is setup properly?? if not setup than give user quick command i.e fuma-docs setup script they can run; otherwise start the fuma-docs server from here;\n//\n// They can directly do that, and this is duplicate but still good to have here\nexport const dev = new Command()\n .name(\"dev\")\n .description(\"start the help center preview server\")\n .option(\"--cwd <cwd>\", \"working directory\")\n .option(\"-p, --port <port>\", \"port to serve on\")\n .action(async (opts) => {\n try {\n const options = devOptionsSchema.parse(opts);\n const cwd = resolve(options.cwd || process.cwd());\n\n logger.log(options, cwd);\n\n const config = await getConfig(cwd);\n if (!config) {\n logger.error(\"No sage.json found. Run sage init first.\");\n process.exit(1);\n }\n\n logger.info(`Content directory: ${config.content}`);\n logger.info(`Framework: ${config.framework}`);\n logger.break();\n logger.info(\"To preview your help center, run your app's dev server:\");\n logger.info(\" npm run dev\");\n logger.break();\n logger.info(\"Make sure Fumadocs is configured in your app to read from:\");\n logger.info(` ${config.content}`);\n } catch (error) {\n handleError(error);\n }\n });\n"],"mappings":"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","names":["Command","resolve","z","text","kleur","z","resolve","Command","resolve","z","z","Command","resolve","Command"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@sagebase/cli",
|
|
3
|
+
"version": "0.0.1-beta.0",
|
|
4
|
+
"license": "MIT",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"publishConfig": {
|
|
7
|
+
"access": "public"
|
|
8
|
+
},
|
|
9
|
+
"exports": {
|
|
10
|
+
".": "./dist/index.js"
|
|
11
|
+
},
|
|
12
|
+
"files": [
|
|
13
|
+
"dist/"
|
|
14
|
+
],
|
|
15
|
+
"dependencies": {
|
|
16
|
+
"commander": "^13.0.0",
|
|
17
|
+
"cosmiconfig": "^9.0.0",
|
|
18
|
+
"fast-glob": "^3.3.3",
|
|
19
|
+
"zod": "^3.24.0",
|
|
20
|
+
"prompts": "^2.4.2",
|
|
21
|
+
"kleur": "^4.1.5",
|
|
22
|
+
"ora": "^8.1.0",
|
|
23
|
+
"fs-extra": "^11.3.0"
|
|
24
|
+
},
|
|
25
|
+
"devDependencies": {
|
|
26
|
+
"@types/fs-extra": "^11.0.4",
|
|
27
|
+
"@types/node": "^22.0.0",
|
|
28
|
+
"@types/prompts": "^2.4.9",
|
|
29
|
+
"tsup": "^8.3.0",
|
|
30
|
+
"typescript": "^5.7.0",
|
|
31
|
+
"vitest": "^3.0.0",
|
|
32
|
+
"vite-tsconfig-paths": "^5.1.0"
|
|
33
|
+
},
|
|
34
|
+
"scripts": {
|
|
35
|
+
"build": "tsup",
|
|
36
|
+
"dev": "tsup --watch",
|
|
37
|
+
"start:dev": "node dist/index.js",
|
|
38
|
+
"test": "vitest run",
|
|
39
|
+
"test:watch": "vitest",
|
|
40
|
+
"lint": "tsc --noEmit",
|
|
41
|
+
"typecheck": "tsc --noEmit",
|
|
42
|
+
"pub:beta": "pnpm build && pnpm publish --no-git-checks --access public --tag beta",
|
|
43
|
+
"pub:rc": "pnpm build && pnpm publish --no-git-checks --access public --tag rc",
|
|
44
|
+
"pub:release": "pnpm build && pnpm publish --access public"
|
|
45
|
+
},
|
|
46
|
+
"bin": {
|
|
47
|
+
"cli": "./dist/index.js"
|
|
48
|
+
}
|
|
49
|
+
}
|