kentutai-app 1.1.4 → 1.1.6

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/cli/cli.js CHANGED
@@ -52,16 +52,7 @@ Options:
52
52
 
53
53
  const appDir = path.join(__dirname, "app");
54
54
  const standaloneServer = path.join(appDir, "server.js");
55
- const mainAppDir = path.resolve(__dirname, "..");
56
- const mainServerPath = path.join(mainAppDir, ".next", "standalone", "server.js");
57
-
58
55
  const useStandalone = fs.existsSync(standaloneServer);
59
- const useMainApp = !useStandalone && fs.existsSync(mainServerPath);
60
-
61
- if (!useStandalone && !useMainApp) {
62
- console.log("\n First run detected. Starting development server...\n");
63
- console.log(" For production, run: npm run build\n");
64
- }
65
56
 
66
57
  function openBrowser(url) {
67
58
  const cmd = process.platform === "darwin" ? "open"
@@ -97,31 +88,18 @@ function startServer() {
97
88
  const displayHost = host === DEFAULT_HOST ? "localhost" : host;
98
89
  const url = `http://${displayHost}:${port}/dashboard`;
99
90
 
100
- let server;
101
-
102
- if (useStandalone) {
103
- server = spawn(process.execPath, ["--max-old-space-size=4096", standaloneServer], {
104
- cwd: appDir,
105
- stdio: showLog ? "inherit" : "ignore",
106
- env: { ...process.env, PORT: String(port), HOSTNAME: host }
107
- });
108
- } else if (useMainApp) {
109
- server = spawn(process.execPath, ["--max-old-space-size=4096", mainServerPath], {
110
- cwd: path.join(mainAppDir, ".next", "standalone"),
111
- stdio: showLog ? "inherit" : "ignore",
112
- env: { ...process.env, PORT: String(port), HOSTNAME: host }
113
- });
114
- } else {
115
- const isWin = process.platform === "win32";
116
- const npmCmd = isWin ? "npm.cmd" : "npm";
117
- server = spawn(npmCmd, ["run", "dev", "--", "--port", String(port)], {
118
- cwd: mainAppDir,
119
- stdio: showLog ? "inherit" : "ignore",
120
- shell: isWin,
121
- env: { ...process.env, PORT: String(port) }
122
- });
91
+ if (!useStandalone) {
92
+ console.error("\n Error: Standalone build not found.");
93
+ console.error(" Please run 'npm run build:cli' first.\n");
94
+ process.exit(1);
123
95
  }
124
96
 
97
+ const server = spawn(process.execPath, ["--max-old-space-size=4096", standaloneServer], {
98
+ cwd: appDir,
99
+ stdio: showLog ? "inherit" : "ignore",
100
+ env: { ...process.env, PORT: String(port), HOSTNAME: host }
101
+ });
102
+
125
103
  server.on("error", (err) => {
126
104
  console.error("Failed to start server:", err.message);
127
105
  process.exit(1);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kentutai-app",
3
- "version": "1.1.4",
3
+ "version": "1.1.6",
4
4
  "description": "KentutAI web dashboard",
5
5
  "private": false,
6
6
  "bin": {
@@ -8,7 +8,12 @@
8
8
  },
9
9
  "files": [
10
10
  "bin.js",
11
- "cli/",
11
+ "cli/cli.js",
12
+ "cli/src/",
13
+ "cli/hooks/",
14
+ "cli/package.json",
15
+ "cli/README.md",
16
+ "cli/LICENSE",
12
17
  "public/",
13
18
  "README.md",
14
19
  "LICENSE",
@@ -1,265 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- const fs = require("fs");
4
- const path = require("path");
5
- const { execSync } = require("child_process");
6
-
7
- const cliDir = path.resolve(__dirname, "..");
8
- const appDir = path.resolve(cliDir, "..");
9
- const rootDir = path.resolve(appDir, "..");
10
- const cliAppDir = path.join(cliDir, "app");
11
- const buildHomeDir = path.join(cliDir, ".build-home");
12
- const buildDistDirName = ".next-cli-build";
13
- const buildDistDir = path.join(appDir, buildDistDirName);
14
-
15
- // Exclude patterns for files/folders we don't want to copy
16
- const EXCLUDE_PATTERNS = [
17
- "@img", // Sharp image processing (not needed with unoptimized images)
18
- "sharp", // Sharp core lib (not needed with unoptimized images)
19
- "detect-libc", // Sharp dependency
20
- "logs", // Runtime logs
21
- ".env", // Environment files
22
- ".env.local",
23
- ".env.*.local",
24
- "*.log", // Log files
25
- "tmp", // Temp files
26
- ".DS_Store", // macOS files
27
- ];
28
-
29
- function shouldExclude(name) {
30
- return EXCLUDE_PATTERNS.some(pattern => {
31
- if (pattern.includes("*")) {
32
- const regex = new RegExp("^" + pattern.replace(/[.+?^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*") + "$");
33
- return regex.test(name);
34
- }
35
- return name === pattern;
36
- });
37
- }
38
-
39
- function copyRecursive(src, dest) {
40
- if (!fs.existsSync(src)) {
41
- console.warn(`Warning: Source ${src} does not exist`);
42
- return;
43
- }
44
-
45
- if (!fs.existsSync(dest)) {
46
- fs.mkdirSync(dest, { recursive: true });
47
- }
48
-
49
- const entries = fs.readdirSync(src, { withFileTypes: true });
50
- for (const entry of entries) {
51
- if (shouldExclude(entry.name)) {
52
- continue;
53
- }
54
-
55
- const srcPath = path.join(src, entry.name);
56
- const destPath = path.join(dest, entry.name);
57
-
58
- // Skip broken symlinks (common in workspace setups)
59
- try {
60
- fs.accessSync(srcPath);
61
- } catch {
62
- continue;
63
- }
64
-
65
- if (entry.isDirectory()) {
66
- copyRecursive(srcPath, destPath);
67
- } else if (entry.isSymbolicLink()) {
68
- // Resolve and copy target (avoid linking outside bundle)
69
- try {
70
- const real = fs.realpathSync(srcPath);
71
- if (fs.statSync(real).isDirectory()) {
72
- copyRecursive(real, destPath);
73
- } else {
74
- fs.copyFileSync(real, destPath);
75
- }
76
- } catch {}
77
- } else {
78
- try {
79
- fs.copyFileSync(srcPath, destPath);
80
- } catch {}
81
- }
82
- }
83
- }
84
-
85
- console.log("📦 Building KentutAI CLI package with Next.js...\n");
86
-
87
- fs.mkdirSync(buildHomeDir, { recursive: true });
88
- fs.mkdirSync(path.join(buildHomeDir, "AppData", "Roaming"), { recursive: true });
89
- fs.mkdirSync(path.join(buildHomeDir, "AppData", "Local"), { recursive: true });
90
-
91
- // Step 0: Sync version from app/cli/package.json to app/package.json
92
- console.log("0️⃣ Syncing version to app/package.json...");
93
- const cliPkg = JSON.parse(fs.readFileSync(path.join(cliDir, "package.json"), "utf8"));
94
- const appPkgPath = path.join(appDir, "package.json");
95
- const appPkg = JSON.parse(fs.readFileSync(appPkgPath, "utf8"));
96
- if (appPkg.version !== cliPkg.version) {
97
- appPkg.version = cliPkg.version;
98
- fs.writeFileSync(appPkgPath, JSON.stringify(appPkg, null, 2) + "\n");
99
- console.log(`✅ Version synced: ${cliPkg.version}\n`);
100
- } else {
101
- console.log(`✅ Version already synced: ${cliPkg.version}\n`);
102
- }
103
-
104
- // Step 1: Build app with Next.js (workspace tracing root → traced node_modules in standalone).
105
- console.log("1️⃣ Building Next.js app...");
106
- try {
107
- execSync("npm run build", {
108
- stdio: "inherit",
109
- cwd: appDir,
110
- env: {
111
- ...process.env,
112
- HOME: buildHomeDir,
113
- USERPROFILE: buildHomeDir,
114
- APPDATA: path.join(buildHomeDir, "AppData", "Roaming"),
115
- LOCALAPPDATA: path.join(buildHomeDir, "AppData", "Local"),
116
- NEXT_DIST_DIR: buildDistDirName,
117
- NEXT_TRACING_ROOT_MODE: "workspace",
118
- }
119
- });
120
- console.log("✅ Next.js build completed\n");
121
- } catch (error) {
122
- console.error("❌ Next.js build failed");
123
- process.exit(1);
124
- }
125
-
126
- // Step 2: Clean old app/cli/app if exists
127
- console.log("2️⃣ Cleaning old app/cli/app...");
128
- if (fs.existsSync(cliAppDir)) {
129
- fs.rmSync(cliAppDir, { recursive: true, force: true });
130
- }
131
- console.log("✅ Cleaned\n");
132
-
133
- // Step 3: Copy Next.js standalone build to app/cli/app.
134
- // Newer Next.js standalone output writes server.js/package.json plus .next/, src/, and
135
- // node_modules/ directly under .next/standalone. Older builds may still use a nested app/.
136
- console.log("3️⃣ Copying Next.js standalone build to app/cli/app...");
137
- const standaloneRoot = path.join(appDir, ".next", "standalone");
138
- const standaloneRootResolved = path.join(buildDistDir, "standalone");
139
- const standaloneRootToUse = fs.existsSync(standaloneRootResolved) ? standaloneRootResolved : standaloneRoot;
140
- const standaloneApp = fs.existsSync(path.join(standaloneRootToUse, "server.js"))
141
- ? standaloneRootToUse
142
- : path.join(standaloneRootToUse, "app");
143
- if (!fs.existsSync(standaloneApp)) {
144
- console.error("❌ Next.js standalone build not found under .next/standalone");
145
- console.error("Expected either .next/standalone/server.js or .next/standalone/app/");
146
- process.exit(1);
147
- }
148
- copyRecursive(standaloneApp, cliAppDir);
149
-
150
- // Older nested-app layout stores traced node_modules at standalone root.
151
- const standaloneNodeModules = path.join(standaloneRootToUse, "node_modules");
152
- if (standaloneApp !== standaloneRootToUse && fs.existsSync(standaloneNodeModules)) {
153
- copyRecursive(standaloneNodeModules, path.join(cliAppDir, "node_modules"));
154
- }
155
- console.log("✅ Copied standalone build\n");
156
-
157
- // Step 3b: Ensure sql.js (pure JS fallback) bundled in app/cli/app/node_modules.
158
- // Strip better-sqlite3 (native) — it lives in ~/.kentutai/runtime to avoid
159
- // Windows EBUSY during global CLI updates. node:sqlite (Node ≥22.5) is also
160
- // available as a no-install middle tier.
161
- console.log("3️⃣ b Configuring SQLite drivers...");
162
- function ensureModuleInBundle(pkg) {
163
- const dest = path.join(cliAppDir, "node_modules", pkg);
164
- if (fs.existsSync(dest)) {
165
- console.log(`✅ ${pkg} already bundled`);
166
- return;
167
- }
168
- const candidates = [
169
- path.join(appDir, "node_modules", pkg),
170
- path.join(rootDir, "node_modules", pkg),
171
- ];
172
- const src = candidates.find((p) => fs.existsSync(p));
173
- if (!src) {
174
- console.warn(`⚠️ ${pkg} not found locally — bundle will rely on node:sqlite or runtime install`);
175
- return;
176
- }
177
- fs.mkdirSync(path.dirname(dest), { recursive: true });
178
- copyRecursive(src, dest);
179
- console.log(`✅ Bundled ${pkg}`);
180
- }
181
- ensureModuleInBundle("sql.js");
182
- const betterDir = path.join(cliAppDir, "node_modules", "better-sqlite3");
183
- if (fs.existsSync(betterDir)) {
184
- fs.rmSync(betterDir, { recursive: true, force: true });
185
- console.log("✅ Stripped better-sqlite3 (lives in ~/.kentutai/runtime)");
186
- }
187
- console.log("");
188
-
189
- // Step 4: Copy static files
190
- console.log("4️⃣ Copying static files...");
191
- const staticSrc = path.join(appDir, ".next", "static");
192
- const staticSrcResolved = path.join(buildDistDir, "static");
193
- const staticDest = path.join(cliAppDir, buildDistDirName, "static");
194
- if (fs.existsSync(staticSrcResolved) || fs.existsSync(staticSrc)) {
195
- copyRecursive(fs.existsSync(staticSrcResolved) ? staticSrcResolved : staticSrc, staticDest);
196
- console.log("✅ Copied static files\n");
197
- } else {
198
- console.log("⏭️ No static files found\n");
199
- }
200
-
201
- // Step 5: Copy public folder if exists
202
- console.log("5️⃣ Copying public folder...");
203
- const publicSrc = path.join(appDir, "public");
204
- const publicDest = path.join(cliAppDir, "public");
205
- if (fs.existsSync(publicSrc)) {
206
- copyRecursive(publicSrc, publicDest);
207
- console.log("✅ Copied public folder\n");
208
- } else {
209
- console.log("⏭️ No public folder found\n");
210
- }
211
-
212
- // Step 6: Copy vendor-chunks (required for production)
213
- console.log("6️⃣ Copying vendor-chunks...");
214
- const vendorChunksSrc = path.join(appDir, ".next", "server", "vendor-chunks");
215
- const vendorChunksSrcResolved = path.join(buildDistDir, "server", "vendor-chunks");
216
- const vendorChunksDest = path.join(cliAppDir, buildDistDirName, "server", "vendor-chunks");
217
- if (fs.existsSync(vendorChunksSrcResolved) || fs.existsSync(vendorChunksSrc)) {
218
- copyRecursive(fs.existsSync(vendorChunksSrcResolved) ? vendorChunksSrcResolved : vendorChunksSrc, vendorChunksDest);
219
- console.log("✅ Copied vendor-chunks\n");
220
- } else {
221
- console.log("⏭️ No vendor-chunks found\n");
222
- }
223
-
224
- // Step 7: Copy MITM server files (not bundled by Next.js standalone)
225
- console.log("7️⃣ Copying MITM server files...");
226
- const mitmSrc = path.join(appDir, "src", "mitm");
227
- const mitmDest = path.join(cliAppDir, "src", "mitm");
228
- if (fs.existsSync(mitmSrc)) {
229
- copyRecursive(mitmSrc, mitmDest);
230
- console.log("✅ Copied MITM files\n");
231
- } else {
232
- console.log("⏭️ No MITM files found\n");
233
- }
234
-
235
- // Step 7b: Copy standalone updater (headless Node process for install progress)
236
- console.log("7️⃣ b Copying updater files...");
237
- const updaterSrc = path.join(appDir, "src", "lib", "updater");
238
- const updaterDest = path.join(cliAppDir, "src", "lib", "updater");
239
- if (fs.existsSync(updaterSrc)) {
240
- copyRecursive(updaterSrc, updaterDest);
241
- console.log("✅ Copied updater files\n");
242
- } else {
243
- console.log("⏭️ No updater files found\n");
244
- }
245
-
246
- // Step 8: Build MITM server (config driven - see app/cli/scripts/buildMitm.js)
247
- console.log("8️⃣ Building MITM server...");
248
- try {
249
- execSync("node scripts/buildMitm.js", { stdio: "inherit", cwd: cliDir });
250
- console.log("✅ MITM server build completed\n");
251
- } catch (error) {
252
- console.error("❌ MITM build failed");
253
- process.exit(1);
254
- }
255
-
256
- console.log("✨ CLI package build completed!");
257
- console.log(`📁 Output: ${cliAppDir}`);
258
-
259
- try {
260
- const { execSync: exec } = require("child_process");
261
- const size = exec(`du -sh "${cliAppDir}"`, { encoding: "utf8" }).trim();
262
- console.log(`📊 Package size: ${size.split("\t")[0]}`);
263
- } catch (e) {
264
- // Silent fail on size check
265
- }
@@ -1,70 +0,0 @@
1
- const esbuild = require("esbuild");
2
- const fs = require("fs");
3
- const path = require("path");
4
-
5
- // ── Build config ─────────────────────────────────────────
6
- const BUILD_CONFIG = {
7
- bundle: true,
8
- minify: true,
9
- cleanPlainFiles: true,
10
- };
11
- // ─────────────────────────────────────────────────────────
12
-
13
- const cliDir = path.resolve(__dirname, "..");
14
- const appDir = path.resolve(cliDir, "..");
15
- const cliMitmDir = path.join(cliDir, "app", "src", "mitm");
16
- // Bundle everything — no externals. This keeps MITM runtime self-contained so
17
- // it can be copied to DATA_DIR/runtime/ and spawned from there (escapes
18
- // node_modules file locks that block `npm i -g kentutai@latest` on Windows).
19
- const EXTERNALS = [];
20
- const ENTRIES = ["server.js"];
21
-
22
- async function buildEntry(entry) {
23
- const mitmSrc = path.join(appDir, "src", "mitm");
24
- const output = path.join(cliMitmDir, entry);
25
-
26
- const buildPlugin = {
27
- name: "build-plugin",
28
- setup(build) {
29
- // Stub .git file scanned by esbuild
30
- build.onResolve({ filter: /\.git/ }, args => ({ path: args.path, namespace: "git-stub" }));
31
- build.onLoad({ filter: /.*/, namespace: "git-stub" }, () => ({ contents: "module.exports={}", loader: "js" }));
32
- },
33
- };
34
-
35
- const steps = [];
36
-
37
- if (BUILD_CONFIG.bundle) {
38
- await esbuild.build({
39
- entryPoints: [path.join(mitmSrc, entry)],
40
- bundle: true,
41
- minify: BUILD_CONFIG.minify,
42
- platform: "node",
43
- target: "node18",
44
- external: EXTERNALS,
45
- plugins: [buildPlugin],
46
- outfile: output,
47
- });
48
- steps.push("bundled");
49
- if (BUILD_CONFIG.minify) steps.push("minified");
50
- }
51
-
52
- console.log(`✅ ${steps.join(" + ")} → ${output}`);
53
- }
54
-
55
- async function run() {
56
- const flags = Object.entries(BUILD_CONFIG).filter(([, v]) => v).map(([k]) => k).join(", ");
57
- console.log(`⚙️ Config: ${flags}`);
58
-
59
- for (const entry of ENTRIES) await buildEntry(entry);
60
-
61
- if (BUILD_CONFIG.cleanPlainFiles) {
62
- const keep = new Set(ENTRIES);
63
- for (const name of fs.readdirSync(cliMitmDir)) {
64
- if (!keep.has(name)) fs.rmSync(path.join(cliMitmDir, name), { recursive: true, force: true });
65
- }
66
- console.log("✅ Removed plain MITM files from CLI bundle");
67
- }
68
- }
69
-
70
- run().catch((e) => { console.error(e); process.exit(1); });