@chat-js/cli 0.6.0 → 0.6.1

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
@@ -3844,7 +3844,7 @@ var {
3844
3844
  // package.json
3845
3845
  var package_default = {
3846
3846
  name: "@chat-js/cli",
3847
- version: "0.6.0",
3847
+ version: "0.6.1",
3848
3848
  description: "CLI for creating and extending ChatJS apps",
3849
3849
  license: "Apache-2.0",
3850
3850
  repository: {
@@ -3883,9 +3883,10 @@ var package_default = {
3883
3883
  },
3884
3884
  scripts: {
3885
3885
  start: "bun src/index.ts",
3886
- build: "bun build ./src/index.ts --target=node --format=esm --outfile ./dist/index.js",
3886
+ build: "bun run template:sync && bun build ./src/index.ts --target=node --format=esm --outfile ./dist/index.js",
3887
+ "test:unit": "bun run template:sync && bun test src",
3887
3888
  "template:sync": "bun ../../scripts/sync-template.ts",
3888
- prepublishOnly: "bun run template:sync && bun run build && node ./dist/index.js --help >/dev/null"
3889
+ prepublishOnly: "bun run build && node ./dist/index.js --help >/dev/null"
3889
3890
  },
3890
3891
  type: "module",
3891
3892
  devDependencies: {
@@ -19748,9 +19749,134 @@ async function promptInstall(packageManager, skipPrompt) {
19748
19749
  // src/helpers/scaffold.ts
19749
19750
  import { existsSync } from "node:fs";
19750
19751
  import { cp, readFile, rm, writeFile } from "node:fs/promises";
19751
- import { dirname, join, resolve } from "node:path";
19752
+ import { dirname, join, relative, resolve, sep } from "node:path";
19752
19753
  import { fileURLToPath } from "node:url";
19753
19754
 
19755
+ // src/helpers/package-manifest.ts
19756
+ var ESBUILD_VERSION = "^0.28.0";
19757
+ var BETTER_AUTH_PACKAGES = [
19758
+ "@better-auth/core",
19759
+ "@better-auth/electron",
19760
+ "better-auth"
19761
+ ];
19762
+ function toExactVersion(range) {
19763
+ return range.replace(/^[~^]/, "");
19764
+ }
19765
+ function resolveBetterAuthVersion(packageJson) {
19766
+ for (const dependencyGroup of [
19767
+ packageJson.dependencies,
19768
+ packageJson.devDependencies
19769
+ ]) {
19770
+ if (!dependencyGroup) {
19771
+ continue;
19772
+ }
19773
+ for (const packageName of BETTER_AUTH_PACKAGES) {
19774
+ const version2 = dependencyGroup[packageName];
19775
+ if (version2) {
19776
+ return toExactVersion(version2);
19777
+ }
19778
+ }
19779
+ }
19780
+ return null;
19781
+ }
19782
+ function pinBetterAuthVersions(dependencyGroup, version2) {
19783
+ if (!dependencyGroup) {
19784
+ return;
19785
+ }
19786
+ for (const packageName of BETTER_AUTH_PACKAGES) {
19787
+ if (dependencyGroup[packageName]) {
19788
+ dependencyGroup[packageName] = version2;
19789
+ }
19790
+ }
19791
+ }
19792
+ function normalizeChatAppScripts(scripts) {
19793
+ const defaultBranchName = "$" + "{1:-dev-local}";
19794
+ scripts.prebuild = "tsx scripts/check-env.ts";
19795
+ scripts.dev = "tsx scripts/check-env.ts && bash scripts/with-db.sh next dev";
19796
+ scripts["dev:inspect"] = "tsx scripts/check-env.ts && bash scripts/with-db.sh next dev --inspect";
19797
+ scripts.prod = "tsx scripts/check-env.ts && tsx lib/db/migrate.ts && next build && next start";
19798
+ scripts.lint = "ultracite check";
19799
+ scripts.format = "ultracite fix";
19800
+ scripts["check-env"] = "tsx scripts/check-env.ts";
19801
+ scripts["db:migrate"] = "export VERCEL_ENV=production && bash scripts/with-db.sh tsx lib/db/migrate.ts";
19802
+ scripts["db:backfill-parts"] = "tsx lib/db/backfill-parts.ts";
19803
+ scripts["db:branch:start"] = `bash -c 'N=${defaultBranchName}; bash scripts/db-branch-create.sh "$N" && bash scripts/db-branch-use.sh "$N"' --`;
19804
+ scripts["db:branch:stop"] = `bash -c 'N=${defaultBranchName}; bash scripts/db-branch-use.sh main && bash scripts/db-branch-delete.sh "$N"' --`;
19805
+ scripts["db:branch:list"] = "npx neonctl branches list";
19806
+ scripts["skiller:apply"] = "npx skiller@latest apply";
19807
+ scripts.test = "export PLAYWRIGHT=True && playwright test --workers=4 && vitest run";
19808
+ scripts["test:e2e"] = "export PLAYWRIGHT=True && playwright test --workers=4";
19809
+ scripts["ai:devtools"] = "npx @ai-sdk/devtools";
19810
+ scripts["fetch:models"] = "tsx scripts/fetch-models.ts && ultracite fix";
19811
+ }
19812
+ function normalizeElectronScripts(scripts) {
19813
+ const prebuild = "tsx scripts/write-branding.ts && tsx scripts/generate-icons.ts";
19814
+ const build = "esbuild src/main.ts --bundle --platform=node --format=cjs --outfile=dist/main.js --external:electron --external:electron-updater --alias:@=.. && esbuild src/preload.ts --bundle --platform=browser --format=cjs --outfile=dist/preload.js --external:electron --alias:@=..";
19815
+ scripts.forge = "node ./scripts/run-forge.cjs";
19816
+ scripts["generate-icons"] = "tsx scripts/generate-icons.ts";
19817
+ scripts.prebuild = prebuild;
19818
+ scripts.build = build;
19819
+ scripts.start = "node ./scripts/run-forge.cjs start";
19820
+ scripts.dev = "node ./scripts/run-forge.cjs start";
19821
+ scripts.package = "node ./scripts/run-forge.cjs package";
19822
+ scripts.make = "node ./scripts/run-forge.cjs make";
19823
+ scripts["make:mac"] = "node ./scripts/run-forge.cjs make --platform=darwin --arch=universal";
19824
+ scripts["make:win"] = "node ./scripts/run-forge.cjs make --platform=win32 --arch=x64";
19825
+ scripts["make:linux"] = "node ./scripts/run-forge.cjs make --platform=linux --arch=x64";
19826
+ scripts.publish = "node ./scripts/run-forge.cjs publish";
19827
+ scripts["electron:build"] = build;
19828
+ scripts["electron:dev"] = scripts.dev;
19829
+ scripts["electron:make"] = scripts.make;
19830
+ scripts["electron:publish"] = scripts.publish;
19831
+ delete scripts["dist:mac"];
19832
+ delete scripts["dist:win"];
19833
+ delete scripts["dist:linux"];
19834
+ delete scripts["publish:mac"];
19835
+ delete scripts["publish:win"];
19836
+ }
19837
+ function normalizeElectronDevDependencies(devDependencies, tsxVersion) {
19838
+ if (!devDependencies) {
19839
+ return;
19840
+ }
19841
+ devDependencies.esbuild = ESBUILD_VERSION;
19842
+ if (tsxVersion) {
19843
+ devDependencies.tsx = tsxVersion;
19844
+ }
19845
+ }
19846
+ function normalizeScaffoldedPackageJson(packageJson, options) {
19847
+ const betterAuthVersion = resolveBetterAuthVersion(packageJson);
19848
+ if (betterAuthVersion) {
19849
+ pinBetterAuthVersions(packageJson.dependencies, betterAuthVersion);
19850
+ pinBetterAuthVersions(packageJson.devDependencies, betterAuthVersion);
19851
+ packageJson.overrides = {
19852
+ ...packageJson.overrides ?? {},
19853
+ "@better-auth/core": betterAuthVersion
19854
+ };
19855
+ }
19856
+ switch (options?.template) {
19857
+ case "chat-app":
19858
+ if (packageJson.scripts) {
19859
+ normalizeChatAppScripts(packageJson.scripts);
19860
+ }
19861
+ break;
19862
+ case "electron":
19863
+ if (packageJson.scripts) {
19864
+ normalizeElectronScripts(packageJson.scripts);
19865
+ }
19866
+ normalizeElectronDevDependencies(packageJson.devDependencies, options?.tsxVersion);
19867
+ break;
19868
+ default:
19869
+ break;
19870
+ }
19871
+ if (options?.persistPackageManager !== false) {
19872
+ const packageManager = options?.packageManager ?? "bun";
19873
+ if (packageManager !== "bun") {
19874
+ delete packageJson.packageManager;
19875
+ }
19876
+ }
19877
+ return packageJson;
19878
+ }
19879
+
19754
19880
  // src/utils/run-command.ts
19755
19881
  import { spawn as spawn2 } from "node:child_process";
19756
19882
  async function runCommand(command, args, cwd) {
@@ -19772,26 +19898,273 @@ ${stderr.join("")}`.trim()));
19772
19898
  }
19773
19899
 
19774
19900
  // src/helpers/scaffold.ts
19775
- function findTemplateDir(name) {
19901
+ var CHAT_APP_EXCLUDED_SEGMENTS = new Set([
19902
+ "node_modules",
19903
+ ".next",
19904
+ ".turbo",
19905
+ "playwright",
19906
+ "playwright-report",
19907
+ "test-results",
19908
+ "blob-report",
19909
+ "dist",
19910
+ "build"
19911
+ ]);
19912
+ var CHAT_APP_EXCLUDED_FILES = new Set([
19913
+ ".env.local",
19914
+ ".DS_Store",
19915
+ "bun.lock",
19916
+ "bun.lockb"
19917
+ ]);
19918
+ var ELECTRON_EXCLUDED_SEGMENTS = new Set([
19919
+ "node_modules",
19920
+ ".turbo",
19921
+ "build",
19922
+ "dist",
19923
+ "release"
19924
+ ]);
19925
+ var ELECTRON_EXCLUDED_FILES = new Set([
19926
+ ".DS_Store",
19927
+ "bun.lock",
19928
+ "bun.lockb",
19929
+ "branding.json"
19930
+ ]);
19931
+ function getCliPackageRoot() {
19776
19932
  const __dir = dirname(fileURLToPath(import.meta.url));
19777
- for (const relative of [`../templates/${name}`, `../../templates/${name}`]) {
19778
- const candidate = resolve(__dir, relative);
19779
- if (existsSync(candidate))
19933
+ for (const relative2 of ["..", "../.."]) {
19934
+ const candidate = resolve(__dir, relative2);
19935
+ if (existsSync(join(candidate, "package.json"))) {
19780
19936
  return candidate;
19937
+ }
19938
+ }
19939
+ throw new Error("Could not locate the @chat-js/cli package root.");
19940
+ }
19941
+ function getRepoRoot() {
19942
+ return resolve(getCliPackageRoot(), "../..");
19943
+ }
19944
+ function findTemplateDir(name) {
19945
+ const cliRoot = getCliPackageRoot();
19946
+ const candidate = join(cliRoot, "templates", name);
19947
+ return existsSync(candidate) ? candidate : null;
19948
+ }
19949
+ function shouldCopyChatAppFilePath(sourceDir, filePath) {
19950
+ const relativePath = relative(sourceDir, filePath);
19951
+ const segments = relativePath.split(sep);
19952
+ if (segments.some((segment) => CHAT_APP_EXCLUDED_SEGMENTS.has(segment))) {
19953
+ return false;
19781
19954
  }
19782
- throw new Error(`Template "${name}" not found. Run \`bun template:sync\` to generate templates.`);
19955
+ const fileName = segments.at(-1);
19956
+ return !(fileName && CHAT_APP_EXCLUDED_FILES.has(fileName));
19957
+ }
19958
+ function shouldCopyElectronFilePath(sourceDir, filePath) {
19959
+ const relativePath = relative(sourceDir, filePath);
19960
+ const segments = relativePath.split(sep);
19961
+ if (segments.some((segment) => ELECTRON_EXCLUDED_SEGMENTS.has(segment))) {
19962
+ return false;
19963
+ }
19964
+ const fileName = segments.at(-1);
19965
+ return !(fileName && ELECTRON_EXCLUDED_FILES.has(fileName));
19966
+ }
19967
+ function runScript(packageManager, script) {
19968
+ return `${packageManager} run ${script}`;
19969
+ }
19970
+ function execCommand(packageManager) {
19971
+ switch (packageManager) {
19972
+ case "bun":
19973
+ return "bunx";
19974
+ case "pnpm":
19975
+ return "pnpm dlx";
19976
+ case "yarn":
19977
+ return "yarn dlx";
19978
+ case "npm":
19979
+ return "npx";
19980
+ }
19981
+ }
19982
+ async function replaceInFile(filePath, replacements) {
19983
+ if (!existsSync(filePath)) {
19984
+ return;
19985
+ }
19986
+ let content = await readFile(filePath, "utf8");
19987
+ for (const [search, replacement] of replacements) {
19988
+ content = content.replaceAll(search, replacement);
19989
+ }
19990
+ await writeFile(filePath, content);
19991
+ }
19992
+ async function applyChatTemplateSourceTransforms(destination) {
19993
+ await Promise.all(["components/github-link.tsx", "components/docs-link.tsx"].map((file2) => rm(join(destination, file2), { force: true })));
19994
+ const headerPath = join(destination, "components", "header-actions.tsx");
19995
+ await replaceInFile(headerPath, [
19996
+ [`import { DocsLink } from "@/components/docs-link";
19997
+ `, ""],
19998
+ [`import { GitHubLink } from "@/components/github-link";
19999
+ `, ""],
20000
+ ["<DocsLink />", ""],
20001
+ ["<GitHubLink />", ""]
20002
+ ]);
20003
+ const globalsCssPath = join(destination, "app", "globals.css");
20004
+ await replaceInFile(globalsCssPath, [
20005
+ [
20006
+ `@source "../node_modules/streamdown/dist/*.js";
20007
+ @source "../../../node_modules/streamdown/dist/*.js";`,
20008
+ '@source "../node_modules/streamdown/dist/*.js";'
20009
+ ]
20010
+ ]);
20011
+ const repoPackageJsonPath = join(getRepoRoot(), "package.json");
20012
+ const rootPackageJson = JSON.parse(await readFile(repoPackageJsonPath, "utf8"));
20013
+ const packageJsonPath = join(destination, "package.json");
20014
+ const packageJson = JSON.parse(await readFile(packageJsonPath, "utf8"));
20015
+ packageJson.packageManager = rootPackageJson.packageManager;
20016
+ await writeFile(packageJsonPath, `${JSON.stringify(packageJson, null, 2)}
20017
+ `);
19783
20018
  }
19784
- async function scaffoldFromTemplate(destination) {
20019
+ async function applyElectronTemplateSourceTransforms(destination) {
20020
+ const tsconfigPath = join(destination, "tsconfig.json");
20021
+ await replaceInFile(tsconfigPath, [['"../chat/*"', '"../*"']]);
20022
+ const packageJsonPath = join(destination, "package.json");
20023
+ await replaceInFile(packageJsonPath, [
20024
+ ['"name": "@chatjs/electron"', '"name": "__PROJECT_NAME__-electron"'],
20025
+ [
20026
+ '"url": "https://github.com/FranciscoMoretti/chat-js.git"',
20027
+ '"url": "https://github.com/__GITHUB_OWNER__/__GITHUB_REPO__.git"'
20028
+ ]
20029
+ ]);
20030
+ }
20031
+ async function copyChatTemplateFromRepoSource(destination) {
20032
+ const sourceDir = join(getRepoRoot(), "apps", "chat");
20033
+ await cp(sourceDir, destination, {
20034
+ recursive: true,
20035
+ filter: (filePath) => shouldCopyChatAppFilePath(sourceDir, filePath)
20036
+ });
20037
+ await applyChatTemplateSourceTransforms(destination);
20038
+ }
20039
+ async function copyElectronTemplateFromRepoSource(destination) {
20040
+ const sourceDir = join(getRepoRoot(), "apps", "electron");
20041
+ await cp(sourceDir, destination, {
20042
+ recursive: true,
20043
+ filter: (filePath) => shouldCopyElectronFilePath(sourceDir, filePath)
20044
+ });
20045
+ await applyElectronTemplateSourceTransforms(destination);
20046
+ }
20047
+ async function normalizeChatAppFiles(destination, packageManager) {
20048
+ await replaceInFile(join(destination, "playwright.config.ts"), [
20049
+ ['command: "bun dev"', `command: "${runScript(packageManager, "dev")}"`]
20050
+ ]);
20051
+ await replaceInFile(join(destination, "scripts", "check-env.ts"), [
20052
+ [
20053
+ " * Run via `bun run check-env` or automatically in prebuild.",
20054
+ ` * Run via \`${runScript(packageManager, "check-env")}\` or automatically in prebuild.`
20055
+ ],
20056
+ [
20057
+ "bun fetch:models",
20058
+ runScript(packageManager, "fetch:models")
20059
+ ]
20060
+ ]);
20061
+ await replaceInFile(join(destination, "lib", "ai", "gateways", "fallback-models.ts"), [
20062
+ [
20063
+ "bun fetch:models",
20064
+ runScript(packageManager, "fetch:models")
20065
+ ]
20066
+ ]);
20067
+ await replaceInFile(join(destination, "scripts", "with-db.sh"), [
20068
+ ["bunx neonctl", `${execCommand(packageManager)} neonctl`],
20069
+ ["filter out bun's package resolution output", `filter out ${execCommand(packageManager)} resolution output`],
20070
+ [
20071
+ "Run: bun db:branch:use main (to switch back to main)",
20072
+ "Run: bash scripts/db-branch-use.sh main (to switch back to main)"
20073
+ ]
20074
+ ]);
20075
+ await replaceInFile(join(destination, "scripts", "db-branch-create.sh"), [
20076
+ ["bunx neonctl", `${execCommand(packageManager)} neonctl`],
20077
+ [
20078
+ 'echo "To use it: bun db:branch:use $BRANCH_NAME"',
20079
+ 'echo "To use it: bash scripts/db-branch-use.sh $BRANCH_NAME"'
20080
+ ]
20081
+ ]);
20082
+ await replaceInFile(join(destination, "scripts", "db-branch-use.sh"), [
20083
+ ["bunx neonctl", `${execCommand(packageManager)} neonctl`],
20084
+ ['echo "Usage: bun db:branch:use <branch-name>"', 'echo "Usage: bash scripts/db-branch-use.sh <branch-name>"'],
20085
+ [
20086
+ 'echo " bun db:branch:use main (switch to production)"',
20087
+ 'echo " bash scripts/db-branch-use.sh main (switch to production)"'
20088
+ ],
20089
+ ['echo "Available branches: bun db:branch:list"', `echo "Available branches: ${execCommand(packageManager)} neonctl branches list"`],
20090
+ ['echo "Create branch: bun db:branch:create"', 'echo "Create branch: bash scripts/db-branch-create.sh"']
20091
+ ]);
20092
+ await replaceInFile(join(destination, "scripts", "db-branch-delete.sh"), [
20093
+ ["bunx neonctl", `${execCommand(packageManager)} neonctl`]
20094
+ ]);
20095
+ await replaceInFile(join(destination, "scripts", "worktree-setup.sh"), [
20096
+ ["bun i", `${packageManager} install`]
20097
+ ]);
20098
+ const vercelJsonPath = join(destination, "vercel.json");
20099
+ const vercelJson = JSON.parse(await readFile(vercelJsonPath, "utf8"));
20100
+ vercelJson.installCommand = `${packageManager} install`;
20101
+ vercelJson.buildCommand = runScript(packageManager, "build");
20102
+ await writeFile(vercelJsonPath, `${JSON.stringify(vercelJson, null, 2)}
20103
+ `);
20104
+ }
20105
+ async function normalizeElectronFiles(destination, packageManager) {
20106
+ const scriptPlaceholder = "$" + "{script}";
20107
+ await replaceInFile(join(destination, "forge.config.ts"), [
20108
+ ["Run \\`bun run prebuild\\`", "Run \\`" + runScript(packageManager, "prebuild") + "\\`"],
20109
+ ["function runBunScript", "function runPackageManagerScript"],
20110
+ ['spawnSync("bun", ["run", script], {', `spawnSync("${packageManager}", ["run", script], {`],
20111
+ [`bun run ${scriptPlaceholder} failed`, `${packageManager} run ${scriptPlaceholder} failed`],
20112
+ [' runBunScript("prebuild");', ' runPackageManagerScript("prebuild");'],
20113
+ [
20114
+ ' runBunScript("build", { NODE_ENV: "development" });',
20115
+ ' runPackageManagerScript("build", { NODE_ENV: "development" });'
20116
+ ],
20117
+ [
20118
+ ' runBunScript("build", { NODE_ENV: "production" });',
20119
+ ' runPackageManagerScript("build", { NODE_ENV: "production" });'
20120
+ ]
20121
+ ]);
20122
+ await replaceInFile(join(destination, "README.md"), [
20123
+ ["bun install", `${packageManager} install`],
20124
+ ["bun run dev", runScript(packageManager, "dev")],
20125
+ ["bun run generate-icons", runScript(packageManager, "generate-icons")],
20126
+ ["bun run make:mac", runScript(packageManager, "make:mac")],
20127
+ ["bun run make:win", runScript(packageManager, "make:win")],
20128
+ ["bun run make:linux", runScript(packageManager, "make:linux")]
20129
+ ]);
20130
+ }
20131
+ async function scaffoldFromTemplate(destination, options) {
20132
+ const packageManager = options?.packageManager ?? "bun";
19785
20133
  const templateDir = findTemplateDir("chat-app");
19786
- await cp(templateDir, destination, { recursive: true });
20134
+ if (templateDir) {
20135
+ await cp(templateDir, destination, { recursive: true });
20136
+ } else {
20137
+ await copyChatTemplateFromRepoSource(destination);
20138
+ }
20139
+ const packageJsonPath = join(destination, "package.json");
20140
+ const packageJson = normalizeScaffoldedPackageJson(JSON.parse(await readFile(packageJsonPath, "utf8")), {
20141
+ packageManager,
20142
+ template: "chat-app"
20143
+ });
20144
+ await writeFile(packageJsonPath, `${JSON.stringify(packageJson, null, 2)}
20145
+ `);
20146
+ await normalizeChatAppFiles(destination, packageManager);
19787
20147
  }
19788
20148
  async function scaffoldElectron(projectDir, opts) {
19789
- const templateDir = findTemplateDir("electron");
20149
+ const packageManager = opts.packageManager ?? "bun";
20150
+ const rootPackageJsonPath = join(projectDir, "package.json");
20151
+ const rootPackageJson = JSON.parse(await readFile(rootPackageJsonPath, "utf8"));
19790
20152
  const destination = join(projectDir, "electron");
19791
- await cp(templateDir, destination, { recursive: true });
20153
+ const templateDir = findTemplateDir("electron");
20154
+ if (templateDir) {
20155
+ await cp(templateDir, destination, { recursive: true });
20156
+ } else {
20157
+ await copyElectronTemplateFromRepoSource(destination);
20158
+ }
19792
20159
  const packageJsonPath = join(destination, "package.json");
19793
- const packageJson = (await readFile(packageJsonPath, "utf8")).replace("__PROJECT_NAME__-electron", `${opts.projectName}-electron`).replace("__GITHUB_OWNER__", "your-github-username").replace("__GITHUB_REPO__", opts.projectName);
19794
- await writeFile(packageJsonPath, packageJson);
20160
+ const packageJson = normalizeScaffoldedPackageJson(JSON.parse((await readFile(packageJsonPath, "utf8")).replace("__PROJECT_NAME__-electron", `${opts.projectName}-electron`).replace("__GITHUB_OWNER__", "your-github-username").replace("__GITHUB_REPO__", opts.projectName)), {
20161
+ packageManager,
20162
+ template: "electron",
20163
+ tsxVersion: rootPackageJson.devDependencies?.tsx
20164
+ });
20165
+ await writeFile(packageJsonPath, `${JSON.stringify(packageJson, null, 2)}
20166
+ `);
20167
+ await normalizeElectronFiles(destination, packageManager);
19795
20168
  }
19796
20169
  async function scaffoldFromGit(url2, destination) {
19797
20170
  await runCommand("git", ["clone", "--depth", "1", url2, destination], process.cwd());
@@ -21197,15 +21570,16 @@ var createOptionsSchema = exports_external.object({
21197
21570
  yes: exports_external.boolean(),
21198
21571
  install: exports_external.boolean(),
21199
21572
  electron: exports_external.boolean().optional(),
21200
- fromGit: exports_external.string().optional()
21573
+ fromGit: exports_external.string().optional(),
21574
+ packageManager: exports_external.enum(["bun", "npm", "pnpm", "yarn"]).optional()
21201
21575
  });
21202
- var create = new Command().name("create").description("scaffold a new ChatJS chat application").argument("[directory]", "target directory for the project").option("-y, --yes", "skip prompts and use defaults", false).option("--no-install", "skip dependency installation").option("--electron", "include the Electron desktop app").option("--no-electron", "do not include the Electron desktop app").option("--from-git <url>", "clone from a git repository instead of the built-in scaffold").action(async (directory, opts) => {
21576
+ var create = new Command().name("create").description("scaffold a new ChatJS chat application").argument("[directory]", "target directory for the project").option("-y, --yes", "skip prompts and use defaults", false).option("--no-install", "skip dependency installation").option("--electron", "include the Electron desktop app").option("--no-electron", "do not include the Electron desktop app").option("--package-manager <manager>", "package manager for install + next steps (bun, npm, pnpm, yarn)").option("--from-git <url>", "clone from a git repository instead of the built-in scaffold").action(async (directory, opts) => {
21203
21577
  try {
21204
21578
  const options = createOptionsSchema.parse({
21205
21579
  target: directory,
21206
21580
  ...opts
21207
21581
  });
21208
- const packageManager = inferPackageManager();
21582
+ const packageManager = options.packageManager ?? inferPackageManager();
21209
21583
  if (!options.yes) {
21210
21584
  mt("Create ChatJS App");
21211
21585
  }
@@ -21225,11 +21599,12 @@ var create = new Command().name("create").description("scaffold a new ChatJS cha
21225
21599
  if (options.fromGit) {
21226
21600
  await scaffoldFromGit(options.fromGit, targetDir);
21227
21601
  } else {
21228
- await scaffoldFromTemplate(targetDir);
21602
+ await scaffoldFromTemplate(targetDir, { packageManager });
21229
21603
  }
21230
21604
  if (withElectron) {
21231
21605
  await scaffoldElectron(targetDir, {
21232
- projectName
21606
+ projectName,
21607
+ packageManager
21233
21608
  });
21234
21609
  }
21235
21610
  scaffoldSpinner.succeed("Project scaffolded.");
@@ -21287,7 +21662,7 @@ var create = new Command().name("create").description("scaffold a new ChatJS cha
21287
21662
  if (withElectron) {
21288
21663
  logger.break();
21289
21664
  logger.info("Electron desktop app:");
21290
- logger.log(` Run the web app first, then: ${highlighter.info(`cd electron && bun install && bun run dev`)}`);
21665
+ logger.log(` Run the web app first, then: ${highlighter.info(`cd electron && ${packageManager} install && ${packageManager} run dev`)}`);
21291
21666
  }
21292
21667
  logger.break();
21293
21668
  printEnvChecklist(envEntries);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@chat-js/cli",
3
- "version": "0.6.0",
3
+ "version": "0.6.1",
4
4
  "description": "CLI for creating and extending ChatJS apps",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -39,9 +39,10 @@
39
39
  },
40
40
  "scripts": {
41
41
  "start": "bun src/index.ts",
42
- "build": "bun build ./src/index.ts --target=node --format=esm --outfile ./dist/index.js",
42
+ "build": "bun run template:sync && bun build ./src/index.ts --target=node --format=esm --outfile ./dist/index.js",
43
+ "test:unit": "bun run template:sync && bun test src",
43
44
  "template:sync": "bun ../../scripts/sync-template.ts",
44
- "prepublishOnly": "bun run template:sync && bun run build && node ./dist/index.js --help >/dev/null"
45
+ "prepublishOnly": "bun run build && node ./dist/index.js --help >/dev/null"
45
46
  },
46
47
  "type": "module",
47
48
  "devDependencies": {
@@ -184,5 +184,6 @@
184
184
  "ultracite": "7.4.3",
185
185
  "vite-tsconfig-paths": "^6.1.1",
186
186
  "vitest": "^4.0.0"
187
- }
187
+ },
188
+ "packageManager": "bun@1.3.1"
188
189
  }
@@ -1,4 +1,4 @@
1
- import { existsSync, readFileSync, rmSync } from "node:fs";
1
+ import { existsSync, readFileSync } from "node:fs";
2
2
  import { join } from "node:path";
3
3
  import { spawnSync } from "node:child_process";
4
4
  import type { ForgeConfig } from "@electron-forge/shared-types";
@@ -61,10 +61,6 @@ function ensurePrebuild(): void {
61
61
  prebuildComplete = true;
62
62
  }
63
63
 
64
- function removeLocalNodeModules(): void {
65
- rmSync(join(appRoot, "node_modules"), { recursive: true, force: true });
66
- }
67
-
68
64
  function createForgeConfig(): ForgeConfig {
69
65
  const branding = loadBranding();
70
66
  const { appName, appPrefix, orgName, orgEmail } = branding;
@@ -146,7 +142,6 @@ function createForgeConfig(): ForgeConfig {
146
142
  },
147
143
  prePackage: async () => {
148
144
  runBunScript("build", { NODE_ENV: "production" });
149
- removeLocalNodeModules();
150
145
  },
151
146
  },
152
147
  };