camelmind 0.2.2 → 0.2.4

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.js CHANGED
@@ -2,9 +2,9 @@
2
2
 
3
3
  // src/index.ts
4
4
  import { Command } from "commander";
5
- import { fileURLToPath as fileURLToPath2 } from "url";
6
- import path2 from "path";
7
- import fs2 from "fs";
5
+ import { fileURLToPath as fileURLToPath3 } from "url";
6
+ import path3 from "path";
7
+ import fs3 from "fs";
8
8
 
9
9
  // src/commands/init.ts
10
10
  import path from "path";
@@ -135,11 +135,210 @@ async function init(projectName, options) {
135
135
  `);
136
136
  }
137
137
 
138
- // src/commands/version.ts
138
+ // src/commands/update.ts
139
+ import path2 from "path";
140
+ import { fileURLToPath as fileURLToPath2 } from "url";
141
+ import { execSync as execSync2 } from "child_process";
142
+ import fs2 from "fs-extra";
139
143
  import chalk2 from "chalk";
140
144
  import ora2 from "ora";
145
+ import prompts2 from "prompts";
146
+ var __dirname2 = path2.dirname(fileURLToPath2(import.meta.url));
147
+ var TEMPLATE_DIR2 = path2.join(__dirname2, "../template");
148
+ var FRAMEWORK_DIRS = ["app", "components", "lib", "public", "scripts"];
149
+ var FRAMEWORK_FILES = [
150
+ "next.config.ts",
151
+ "postcss.config.mjs",
152
+ "tsconfig.json",
153
+ "eslint.config.mjs",
154
+ "proxy.ts"
155
+ ];
156
+ var DEFAULT_IGNORED_FILES = ["app/home/page.tsx"];
157
+ async function walkFiles(dir) {
158
+ if (!await fs2.pathExists(dir)) return [];
159
+ const entries = await fs2.readdir(dir, { withFileTypes: true });
160
+ const files = [];
161
+ for (const entry of entries) {
162
+ if (entry.name === "node_modules" || entry.name === ".next" || entry.name === ".git") {
163
+ continue;
164
+ }
165
+ const fullPath = path2.join(dir, entry.name);
166
+ if (entry.isDirectory()) {
167
+ files.push(...await walkFiles(fullPath));
168
+ } else if (entry.isFile()) {
169
+ files.push(fullPath);
170
+ }
171
+ }
172
+ return files;
173
+ }
174
+ function mergePackageJson(current, template) {
175
+ return {
176
+ ...current,
177
+ scripts: {
178
+ ...template.scripts,
179
+ ...current.scripts
180
+ },
181
+ dependencies: {
182
+ ...current.dependencies,
183
+ ...template.dependencies
184
+ },
185
+ devDependencies: {
186
+ ...current.devDependencies,
187
+ ...template.devDependencies
188
+ },
189
+ overrides: {
190
+ ...current.overrides,
191
+ ...template.overrides
192
+ }
193
+ };
194
+ }
195
+ async function copyWithBackup(source, target, backupRoot, projectRoot) {
196
+ if (await fs2.pathExists(target)) {
197
+ await backupFile(target, backupRoot, projectRoot);
198
+ }
199
+ await fs2.ensureDir(path2.dirname(target));
200
+ await fs2.copy(source, target, { overwrite: true });
201
+ }
202
+ async function backupFile(file, backupRoot, projectRoot) {
203
+ const rel = path2.relative(projectRoot, file);
204
+ await fs2.ensureDir(path2.dirname(path2.join(backupRoot, rel)));
205
+ await fs2.copy(file, path2.join(backupRoot, rel), { overwrite: true });
206
+ }
207
+ async function updatePackageJson(projectRoot, backupRoot, dryRun) {
208
+ const projectPkgPath = path2.join(projectRoot, "package.json");
209
+ const templatePkgPath = path2.join(TEMPLATE_DIR2, "_package.json");
210
+ const current = await fs2.readJson(projectPkgPath);
211
+ const template = await fs2.readJson(templatePkgPath);
212
+ const merged = mergePackageJson(current, template);
213
+ if (dryRun) return;
214
+ await backupFile(projectPkgPath, backupRoot, projectRoot);
215
+ await fs2.writeJson(projectPkgPath, merged, { spaces: 2 });
216
+ await fs2.appendFile(projectPkgPath, "\n");
217
+ }
218
+ async function plannedTemplateFiles() {
219
+ const files = [];
220
+ for (const dir of FRAMEWORK_DIRS) {
221
+ const dirPath = path2.join(TEMPLATE_DIR2, dir);
222
+ const dirFiles = await walkFiles(dirPath);
223
+ files.push(...dirFiles.map((file) => path2.relative(TEMPLATE_DIR2, file)));
224
+ }
225
+ files.push(...FRAMEWORK_FILES);
226
+ return files.sort();
227
+ }
228
+ function normalizeUpdatePath(file) {
229
+ return file.replace(/\\/g, "/").replace(/^\.?\//, "");
230
+ }
231
+ function ignoredFilesFor(options) {
232
+ const ignored = /* @__PURE__ */ new Set();
233
+ if (!options.overwriteHome) {
234
+ for (const file of DEFAULT_IGNORED_FILES) ignored.add(file);
235
+ }
236
+ for (const file of options.ignoreFile ?? []) {
237
+ ignored.add(normalizeUpdatePath(file));
238
+ }
239
+ return ignored;
240
+ }
241
+ async function update(targetDir, options) {
242
+ const projectRoot = path2.resolve(process.cwd(), targetDir ?? ".");
243
+ const packageJsonPath = path2.join(projectRoot, "package.json");
244
+ const configPath = path2.join(projectRoot, "camelmind.config.ts");
245
+ if (!await fs2.pathExists(TEMPLATE_DIR2)) {
246
+ console.error(chalk2.red("Template directory not found in the installed CamelMind package."));
247
+ process.exit(1);
248
+ }
249
+ if (!await fs2.pathExists(packageJsonPath) || !await fs2.pathExists(configPath)) {
250
+ console.error(chalk2.red("Run this command from a CamelMind project root, or pass the project directory."));
251
+ process.exit(1);
252
+ }
253
+ const ignoredFiles = ignoredFilesFor(options);
254
+ const allFiles = await plannedTemplateFiles();
255
+ const files = allFiles.filter((file) => !ignoredFiles.has(file));
256
+ const skippedFiles = allFiles.filter((file) => ignoredFiles.has(file));
257
+ const backupRoot = path2.join(
258
+ projectRoot,
259
+ ".camelmind-update-backup",
260
+ (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-")
261
+ );
262
+ console.log(`
263
+ ${chalk2.hex("#D8A15B").bold("CamelMind update")}
264
+
265
+ Project: ${chalk2.cyan(projectRoot)}
266
+ Files: ${chalk2.cyan(String(files.length))} framework files + package.json
267
+ Skipped: ${chalk2.cyan(String(skippedFiles.length))} preserved files
268
+ Backup: ${chalk2.cyan(path2.relative(projectRoot, backupRoot))}
269
+ `);
270
+ if (options.dryRun) {
271
+ console.log(chalk2.bold(" Dry run \u2014 files that would be refreshed:\n"));
272
+ for (const file of files) console.log(` ${file}`);
273
+ console.log(" package.json");
274
+ if (skippedFiles.length) {
275
+ console.log(chalk2.bold("\n Preserved files:\n"));
276
+ for (const file of skippedFiles) console.log(` ${file}`);
277
+ }
278
+ console.log("");
279
+ return;
280
+ }
281
+ if (!options.yes) {
282
+ const { proceed } = await prompts2(
283
+ {
284
+ type: "confirm",
285
+ name: "proceed",
286
+ message: "Refresh CamelMind framework files and merge package updates?",
287
+ initial: true
288
+ },
289
+ { onCancel: () => process.exit(0) }
290
+ );
291
+ if (!proceed) {
292
+ console.log(chalk2.gray("\n Update cancelled.\n"));
293
+ return;
294
+ }
295
+ }
296
+ const spinner = ora2("Refreshing CamelMind framework files...").start();
297
+ try {
298
+ for (const rel of files) {
299
+ await copyWithBackup(
300
+ path2.join(TEMPLATE_DIR2, rel),
301
+ path2.join(projectRoot, rel),
302
+ backupRoot,
303
+ projectRoot
304
+ );
305
+ }
306
+ await updatePackageJson(projectRoot, backupRoot, false);
307
+ spinner.succeed("CamelMind files refreshed");
308
+ } catch (err) {
309
+ spinner.fail("Update failed");
310
+ console.error(chalk2.red(`
311
+ ${String(err)}
312
+ `));
313
+ process.exit(1);
314
+ }
315
+ if (options.install) {
316
+ const installSpinner = ora2("Installing updated dependencies...").start();
317
+ try {
318
+ execSync2("npm install", {
319
+ cwd: projectRoot,
320
+ stdio: "ignore"
321
+ });
322
+ installSpinner.succeed("Dependencies installed");
323
+ } catch {
324
+ installSpinner.warn("Dependency install failed \u2014 run npm install inside your project");
325
+ }
326
+ }
327
+ console.log(`
328
+ ${chalk2.green("Done.")} Review the changes, then run:
329
+
330
+ ${chalk2.cyan("npm run lint")}
331
+ ${chalk2.cyan("npm run build")}
332
+
333
+ Backup saved in ${chalk2.cyan(path2.relative(projectRoot, backupRoot))}
334
+ `);
335
+ }
336
+
337
+ // src/commands/version.ts
338
+ import chalk3 from "chalk";
339
+ import ora3 from "ora";
141
340
  async function checkVersion(currentVersion) {
142
- const spinner = ora2("Checking latest version...").start();
341
+ const spinner = ora3("Checking latest version...").start();
143
342
  let latestVersion;
144
343
  try {
145
344
  const res = await fetch("https://registry.npmjs.org/camelmind/latest");
@@ -150,7 +349,7 @@ async function checkVersion(currentVersion) {
150
349
  } catch {
151
350
  spinner.fail("Could not reach the npm registry");
152
351
  console.log(`
153
- Installed: ${chalk2.cyan(currentVersion)}
352
+ Installed: ${chalk3.cyan(currentVersion)}
154
353
  `);
155
354
  return;
156
355
  }
@@ -158,28 +357,29 @@ async function checkVersion(currentVersion) {
158
357
  const [latMajor, latMinor, latPatch] = latestVersion.split(".").map(Number);
159
358
  const isOutdated = latMajor > curMajor || latMajor === curMajor && latMinor > curMinor || latMajor === curMajor && latMinor === curMinor && latPatch > curPatch;
160
359
  console.log(`
161
- Installed ${chalk2.cyan(currentVersion)}
162
- Latest ${isOutdated ? chalk2.yellow(latestVersion) : chalk2.green(latestVersion)}
360
+ Installed ${chalk3.cyan(currentVersion)}
361
+ Latest ${isOutdated ? chalk3.yellow(latestVersion) : chalk3.green(latestVersion)}
163
362
  `);
164
363
  if (isOutdated) {
165
364
  console.log(
166
- ` ${chalk2.yellow("\u26A0")} A new version is available. Run:
365
+ ` ${chalk3.yellow("\u26A0")} A new version is available. To update an existing site, run:
167
366
 
168
- ${chalk2.cyan("npm install -g camelmind@latest")}
367
+ ${chalk3.cyan("npx camelmind@latest update")}
169
368
  `
170
369
  );
171
370
  } else {
172
- console.log(` ${chalk2.green("\u2713")} You're up to date.
371
+ console.log(` ${chalk3.green("\u2713")} You're up to date.
173
372
  `);
174
373
  }
175
374
  }
176
375
 
177
376
  // src/index.ts
178
- var __dirname2 = path2.dirname(fileURLToPath2(import.meta.url));
179
- var pkgPath = path2.join(__dirname2, "../package.json");
180
- var pkg = JSON.parse(fs2.readFileSync(pkgPath, "utf-8"));
377
+ var __dirname3 = path3.dirname(fileURLToPath3(import.meta.url));
378
+ var pkgPath = path3.join(__dirname3, "../package.json");
379
+ var pkg = JSON.parse(fs3.readFileSync(pkgPath, "utf-8"));
181
380
  var program = new Command();
182
381
  program.name("camelmind").description("CamelMind CLI \u2014 scaffold and manage documentation sites").version(pkg.version);
183
382
  program.command("init [project-name]").description("Create a new CamelMind documentation site").option("--no-install", "Skip installing npm dependencies").action(init);
184
383
  program.command("version").description("Show installed version and check for updates").action(() => checkVersion(pkg.version));
384
+ program.command("update [project-dir]").description("Update an existing CamelMind site to the latest platform files").option("--no-install", "Skip installing npm dependencies").option("--dry-run", "Show what would change without writing files").option("--ignore-file <path...>", "Preserve additional project files during update").option("--overwrite-home", "Overwrite app/home/page.tsx with the latest template").option("-y, --yes", "Skip the confirmation prompt").action(update);
185
385
  program.parse();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "camelmind",
3
- "version": "0.2.2",
3
+ "version": "0.2.4",
4
4
  "description": "Create and manage CamelMind documentation sites",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -25,6 +25,10 @@
25
25
  "rehype-slug": "^6.0.0",
26
26
  "remark-gfm": "^4.0.1"
27
27
  },
28
+ "overrides": {
29
+ "js-yaml": "^4.2.0",
30
+ "postcss": "^8.5.10"
31
+ },
28
32
  "devDependencies": {
29
33
  "@tailwindcss/postcss": "^4",
30
34
  "@types/js-yaml": "^4.0.9",