kenzoboard 0.1.1 → 0.1.2
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 +134 -275
- package/dist/mcp.js +16018 -0
- package/dist/web/assets/index-BwQljj46.js +5 -0
- package/dist/web/assets/index-D8L4OSbt.css +1 -0
- package/dist/web/favicon.svg +4 -0
- package/dist/web/index.html +14 -0
- package/package.json +19 -8
package/dist/index.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
#!/usr/bin/env
|
|
2
|
-
// @bun
|
|
1
|
+
#!/usr/bin/env node
|
|
3
2
|
import { createRequire } from "node:module";
|
|
4
3
|
var __create = Object.create;
|
|
5
4
|
var __getProtoOf = Object.getPrototypeOf;
|
|
@@ -29,146 +28,65 @@ var __export = (target, all) => {
|
|
|
29
28
|
var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
|
|
30
29
|
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
31
30
|
|
|
32
|
-
// ../shared/dist/adapters/sqlite-adapter.js
|
|
33
|
-
var exports_sqlite_adapter = {};
|
|
34
|
-
__export(exports_sqlite_adapter, {
|
|
35
|
-
createSqliteAdapter: () => createSqliteAdapter
|
|
36
|
-
});
|
|
37
|
-
import { Database } from "bun:sqlite";
|
|
38
|
-
import { existsSync as existsSync2, mkdirSync as mkdirSync2 } from "fs";
|
|
39
|
-
import { dirname as dirname2 } from "path";
|
|
40
|
-
function createSqliteAdapter(filePath) {
|
|
41
|
-
const dir = dirname2(filePath);
|
|
42
|
-
if (!existsSync2(dir)) {
|
|
43
|
-
mkdirSync2(dir, { recursive: true });
|
|
44
|
-
}
|
|
45
|
-
const db2 = new Database(filePath, { create: true });
|
|
46
|
-
db2.exec("PRAGMA journal_mode = WAL");
|
|
47
|
-
db2.exec("CREATE TABLE IF NOT EXISTS store (id INTEGER PRIMARY KEY CHECK (id = 1), data TEXT NOT NULL)");
|
|
48
|
-
const selectStmt = db2.prepare("SELECT data FROM store WHERE id = 1");
|
|
49
|
-
const insertStmt = db2.prepare("INSERT INTO store (id, data) VALUES (1, ?)");
|
|
50
|
-
const updateStmt = db2.prepare("UPDATE store SET data = ? WHERE id = 1");
|
|
51
|
-
let _data = { ...defaultData2 };
|
|
52
|
-
const readFromDb = () => {
|
|
53
|
-
const row = selectStmt.get();
|
|
54
|
-
if (row?.data) {
|
|
55
|
-
try {
|
|
56
|
-
return JSON.parse(row.data);
|
|
57
|
-
} catch {
|
|
58
|
-
return { ...defaultData2 };
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
return { ...defaultData2 };
|
|
62
|
-
};
|
|
63
|
-
return {
|
|
64
|
-
get data() {
|
|
65
|
-
return _data;
|
|
66
|
-
},
|
|
67
|
-
read() {
|
|
68
|
-
_data = readFromDb();
|
|
69
|
-
if (!selectStmt.get()) {
|
|
70
|
-
insertStmt.run(JSON.stringify(_data));
|
|
71
|
-
}
|
|
72
|
-
},
|
|
73
|
-
write() {
|
|
74
|
-
db2.transaction(() => {
|
|
75
|
-
const current = readFromDb();
|
|
76
|
-
const merged = {
|
|
77
|
-
projects: mergeById(current.projects, _data.projects),
|
|
78
|
-
epics: mergeById(current.epics, _data.epics),
|
|
79
|
-
tasks: mergeById(current.tasks, _data.tasks),
|
|
80
|
-
blobs: mergeById(current.blobs || [], _data.blobs || [])
|
|
81
|
-
};
|
|
82
|
-
const serialized = JSON.stringify(merged);
|
|
83
|
-
const row = selectStmt.get();
|
|
84
|
-
if (row) {
|
|
85
|
-
updateStmt.run(serialized);
|
|
86
|
-
} else {
|
|
87
|
-
insertStmt.run(serialized);
|
|
88
|
-
}
|
|
89
|
-
_data = merged;
|
|
90
|
-
})();
|
|
91
|
-
}
|
|
92
|
-
};
|
|
93
|
-
}
|
|
94
|
-
function mergeById(current, updated) {
|
|
95
|
-
const result = new Map;
|
|
96
|
-
for (const item of current) {
|
|
97
|
-
result.set(item.id, item);
|
|
98
|
-
}
|
|
99
|
-
for (const item of updated) {
|
|
100
|
-
result.set(item.id, item);
|
|
101
|
-
}
|
|
102
|
-
return Array.from(result.values());
|
|
103
|
-
}
|
|
104
|
-
var defaultData2;
|
|
105
|
-
var init_sqlite_adapter = __esm(() => {
|
|
106
|
-
defaultData2 = {
|
|
107
|
-
projects: [],
|
|
108
|
-
epics: [],
|
|
109
|
-
tasks: []
|
|
110
|
-
};
|
|
111
|
-
});
|
|
112
|
-
|
|
113
31
|
// ../shared/dist/blob-storage.js
|
|
114
32
|
var exports_blob_storage = {};
|
|
115
33
|
__export(exports_blob_storage, {
|
|
116
|
-
setBlobStorage: () =>
|
|
34
|
+
setBlobStorage: () => setBlobStorage,
|
|
117
35
|
getBlobStorage: () => getBlobStorage,
|
|
118
|
-
createFilesystemBlobStorage: () =>
|
|
36
|
+
createFilesystemBlobStorage: () => createFilesystemBlobStorage
|
|
119
37
|
});
|
|
120
|
-
import { existsSync as
|
|
121
|
-
import { join
|
|
122
|
-
import { createHash
|
|
123
|
-
function
|
|
38
|
+
import { existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync2, unlinkSync } from "fs";
|
|
39
|
+
import { join } from "path";
|
|
40
|
+
import { createHash } from "crypto";
|
|
41
|
+
function blobPath(blobsDir, hash) {
|
|
124
42
|
const prefix = hash.slice(0, 2);
|
|
125
|
-
return
|
|
43
|
+
return join(blobsDir, prefix, hash);
|
|
126
44
|
}
|
|
127
|
-
function
|
|
128
|
-
|
|
45
|
+
function createFilesystemBlobStorage(blobsDir) {
|
|
46
|
+
mkdirSync2(blobsDir, { recursive: true });
|
|
129
47
|
return {
|
|
130
48
|
write(content) {
|
|
131
|
-
const hash =
|
|
49
|
+
const hash = createHash("sha256").update(content).digest("hex");
|
|
132
50
|
const size = content.length;
|
|
133
|
-
const filePath =
|
|
134
|
-
if (!
|
|
135
|
-
const prefixDir =
|
|
136
|
-
|
|
137
|
-
|
|
51
|
+
const filePath = blobPath(blobsDir, hash);
|
|
52
|
+
if (!existsSync2(filePath)) {
|
|
53
|
+
const prefixDir = join(blobsDir, hash.slice(0, 2));
|
|
54
|
+
mkdirSync2(prefixDir, { recursive: true });
|
|
55
|
+
writeFileSync2(filePath, content);
|
|
138
56
|
}
|
|
139
57
|
return { hash, size };
|
|
140
58
|
},
|
|
141
59
|
read(hash) {
|
|
142
|
-
const filePath =
|
|
143
|
-
if (!
|
|
60
|
+
const filePath = blobPath(blobsDir, hash);
|
|
61
|
+
if (!existsSync2(filePath))
|
|
144
62
|
return null;
|
|
145
|
-
return
|
|
63
|
+
return readFileSync2(filePath);
|
|
146
64
|
},
|
|
147
65
|
exists(hash) {
|
|
148
|
-
return
|
|
66
|
+
return existsSync2(blobPath(blobsDir, hash));
|
|
149
67
|
},
|
|
150
68
|
remove(hash) {
|
|
151
|
-
const filePath =
|
|
152
|
-
if (!
|
|
69
|
+
const filePath = blobPath(blobsDir, hash);
|
|
70
|
+
if (!existsSync2(filePath))
|
|
153
71
|
return false;
|
|
154
|
-
|
|
72
|
+
unlinkSync(filePath);
|
|
155
73
|
return true;
|
|
156
74
|
}
|
|
157
75
|
};
|
|
158
76
|
}
|
|
159
|
-
function
|
|
160
|
-
|
|
77
|
+
function setBlobStorage(bs) {
|
|
78
|
+
blobStorage = bs;
|
|
161
79
|
}
|
|
162
80
|
function getBlobStorage() {
|
|
163
|
-
return
|
|
81
|
+
return blobStorage;
|
|
164
82
|
}
|
|
165
|
-
var
|
|
83
|
+
var blobStorage = null;
|
|
166
84
|
var init_blob_storage = () => {};
|
|
167
85
|
|
|
168
86
|
// src/index.ts
|
|
169
|
-
import { resolve as resolve4, dirname as
|
|
87
|
+
import { resolve as resolve4, dirname as dirname4, basename as basename2 } from "path";
|
|
170
88
|
import { execSync } from "child_process";
|
|
171
|
-
import { existsSync as
|
|
89
|
+
import { existsSync as existsSync7, readFileSync as readFileSync6, writeFileSync as writeFileSync5, mkdirSync as mkdirSync3, appendFileSync, cpSync, realpathSync } from "fs";
|
|
172
90
|
import { fileURLToPath as fileURLToPath2, pathToFileURL } from "url";
|
|
173
91
|
import { createInterface } from "readline";
|
|
174
92
|
|
|
@@ -680,11 +598,14 @@ function createJsonAdapter(filePath) {
|
|
|
680
598
|
|
|
681
599
|
// ../shared/dist/adapters/index.js
|
|
682
600
|
var _createSqliteAdapter;
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
601
|
+
if ("Bun" in globalThis) {
|
|
602
|
+
try {
|
|
603
|
+
const runtimeImport = new Function("specifier", "return import(specifier)");
|
|
604
|
+
const mod = await runtimeImport("./sqlite-adapter.js");
|
|
605
|
+
_createSqliteAdapter = mod.createSqliteAdapter;
|
|
606
|
+
} catch {}
|
|
607
|
+
}
|
|
608
|
+
function createSqliteAdapter(filePath) {
|
|
688
609
|
if (!_createSqliteAdapter) {
|
|
689
610
|
throw new Error("SQLite adapter requires Bun runtime");
|
|
690
611
|
}
|
|
@@ -692,59 +613,17 @@ function createSqliteAdapter2(filePath) {
|
|
|
692
613
|
}
|
|
693
614
|
function createAdapter(filePath) {
|
|
694
615
|
if (filePath.endsWith(".sqlite") || filePath.endsWith(".db")) {
|
|
695
|
-
return
|
|
616
|
+
return createSqliteAdapter(filePath);
|
|
696
617
|
}
|
|
697
618
|
return createJsonAdapter(filePath);
|
|
698
619
|
}
|
|
699
620
|
|
|
700
|
-
//
|
|
701
|
-
|
|
702
|
-
import { join } from "path";
|
|
703
|
-
import { createHash } from "crypto";
|
|
704
|
-
function blobPath(blobsDir, hash) {
|
|
705
|
-
const prefix = hash.slice(0, 2);
|
|
706
|
-
return join(blobsDir, prefix, hash);
|
|
707
|
-
}
|
|
708
|
-
function createFilesystemBlobStorage(blobsDir) {
|
|
709
|
-
mkdirSync3(blobsDir, { recursive: true });
|
|
710
|
-
return {
|
|
711
|
-
write(content) {
|
|
712
|
-
const hash = createHash("sha256").update(content).digest("hex");
|
|
713
|
-
const size = content.length;
|
|
714
|
-
const filePath = blobPath(blobsDir, hash);
|
|
715
|
-
if (!existsSync3(filePath)) {
|
|
716
|
-
const prefixDir = join(blobsDir, hash.slice(0, 2));
|
|
717
|
-
mkdirSync3(prefixDir, { recursive: true });
|
|
718
|
-
writeFileSync2(filePath, content);
|
|
719
|
-
}
|
|
720
|
-
return { hash, size };
|
|
721
|
-
},
|
|
722
|
-
read(hash) {
|
|
723
|
-
const filePath = blobPath(blobsDir, hash);
|
|
724
|
-
if (!existsSync3(filePath))
|
|
725
|
-
return null;
|
|
726
|
-
return readFileSync2(filePath);
|
|
727
|
-
},
|
|
728
|
-
exists(hash) {
|
|
729
|
-
return existsSync3(blobPath(blobsDir, hash));
|
|
730
|
-
},
|
|
731
|
-
remove(hash) {
|
|
732
|
-
const filePath = blobPath(blobsDir, hash);
|
|
733
|
-
if (!existsSync3(filePath))
|
|
734
|
-
return false;
|
|
735
|
-
unlinkSync(filePath);
|
|
736
|
-
return true;
|
|
737
|
-
}
|
|
738
|
-
};
|
|
739
|
-
}
|
|
740
|
-
var blobStorage = null;
|
|
741
|
-
function setBlobStorage(bs) {
|
|
742
|
-
blobStorage = bs;
|
|
743
|
-
}
|
|
621
|
+
// src/index.ts
|
|
622
|
+
init_blob_storage();
|
|
744
623
|
|
|
745
624
|
// ../shared/dist/config.js
|
|
746
|
-
import { resolve, dirname as
|
|
747
|
-
import { existsSync as
|
|
625
|
+
import { resolve, dirname as dirname2 } from "path";
|
|
626
|
+
import { existsSync as existsSync3, readFileSync as readFileSync3, writeFileSync as writeFileSync3, chmodSync } from "fs";
|
|
748
627
|
function expandEnv(value) {
|
|
749
628
|
if (!value?.startsWith("$"))
|
|
750
629
|
return value;
|
|
@@ -755,20 +634,20 @@ function findFluxDir() {
|
|
|
755
634
|
return process.env.FLUX_DIR;
|
|
756
635
|
}
|
|
757
636
|
let dir = process.cwd();
|
|
758
|
-
while (
|
|
637
|
+
while (dirname2(dir) !== dir) {
|
|
759
638
|
const fluxDir = resolve(dir, ".flux");
|
|
760
|
-
if (
|
|
639
|
+
if (existsSync3(fluxDir)) {
|
|
761
640
|
return fluxDir;
|
|
762
641
|
}
|
|
763
|
-
dir =
|
|
642
|
+
dir = dirname2(dir);
|
|
764
643
|
}
|
|
765
644
|
const homeDir = process.env.HOME || process.env.USERPROFILE || "";
|
|
766
645
|
return resolve(homeDir, ".flux");
|
|
767
646
|
}
|
|
768
647
|
function loadEnvLocal(fluxDir) {
|
|
769
|
-
const repoRoot =
|
|
648
|
+
const repoRoot = dirname2(fluxDir);
|
|
770
649
|
const envPath = resolve(repoRoot, ".env.local");
|
|
771
|
-
if (
|
|
650
|
+
if (existsSync3(envPath)) {
|
|
772
651
|
const content = readFileSync3(envPath, "utf-8");
|
|
773
652
|
for (const line of content.split(`
|
|
774
653
|
`)) {
|
|
@@ -788,7 +667,7 @@ function loadEnvLocal(fluxDir) {
|
|
|
788
667
|
}
|
|
789
668
|
function readConfigRaw(fluxDir) {
|
|
790
669
|
const configPath = resolve(fluxDir, "config.json");
|
|
791
|
-
if (
|
|
670
|
+
if (existsSync3(configPath)) {
|
|
792
671
|
try {
|
|
793
672
|
return JSON.parse(readFileSync3(configPath, "utf-8"));
|
|
794
673
|
} catch {
|
|
@@ -2302,8 +2181,8 @@ var _baseMimes = {
|
|
|
2302
2181
|
var baseMimes = _baseMimes;
|
|
2303
2182
|
|
|
2304
2183
|
// ../../node_modules/.bun/@hono+node-server@1.19.8+fd698e00a3b2abce/node_modules/@hono/node-server/dist/serve-static.mjs
|
|
2305
|
-
import { createReadStream, statSync, existsSync as
|
|
2306
|
-
import { join as
|
|
2184
|
+
import { createReadStream, statSync, existsSync as existsSync4 } from "fs";
|
|
2185
|
+
import { join as join2 } from "path";
|
|
2307
2186
|
import { versions } from "process";
|
|
2308
2187
|
import { Readable as Readable2 } from "stream";
|
|
2309
2188
|
var COMPRESSIBLE_CONTENT_TYPE_REGEX = /^\s*(?:text\/[^;\s]+|application\/(?:javascript|json|xml|xml-dtd|ecmascript|dart|postscript|rtf|tar|toml|vnd\.dart|vnd\.ms-fontobject|vnd\.ms-opentype|wasm|x-httpd-php|x-javascript|x-ns-proxy-autoconfig|x-sh|x-tar|x-virtualbox-hdd|x-virtualbox-ova|x-virtualbox-ovf|x-virtualbox-vbox|x-virtualbox-vdi|x-virtualbox-vhd|x-virtualbox-vmdk|x-www-form-urlencoded)|font\/(?:otf|ttf)|image\/(?:bmp|vnd\.adobe\.photoshop|vnd\.microsoft\.icon|vnd\.ms-dds|x-icon|x-ms-bmp)|message\/rfc822|model\/gltf-binary|x-shader\/x-fragment|x-shader\/x-vertex|[^;\s]+?\+(?:json|text|xml|yaml))(?:[;\s]|$)/i;
|
|
@@ -2350,7 +2229,7 @@ var getStats = (path) => {
|
|
|
2350
2229
|
var serveStatic = (options = { root: "" }) => {
|
|
2351
2230
|
const root = options.root || "";
|
|
2352
2231
|
const optionPath = options.path;
|
|
2353
|
-
if (root !== "" && !
|
|
2232
|
+
if (root !== "" && !existsSync4(root)) {
|
|
2354
2233
|
console.error(`serveStatic: root path '${root}' is not found, are you sure it's correct?`);
|
|
2355
2234
|
}
|
|
2356
2235
|
return async (c, next) => {
|
|
@@ -2371,11 +2250,11 @@ var serveStatic = (options = { root: "" }) => {
|
|
|
2371
2250
|
return next();
|
|
2372
2251
|
}
|
|
2373
2252
|
}
|
|
2374
|
-
let path =
|
|
2253
|
+
let path = join2(root, !optionPath && options.rewriteRequestPath ? options.rewriteRequestPath(filename, c) : filename);
|
|
2375
2254
|
let stats = getStats(path);
|
|
2376
2255
|
if (stats && stats.isDirectory()) {
|
|
2377
2256
|
const indexFile = options.index ?? "index.html";
|
|
2378
|
-
path =
|
|
2257
|
+
path = join2(path, indexFile);
|
|
2379
2258
|
stats = getStats(path);
|
|
2380
2259
|
}
|
|
2381
2260
|
if (!stats) {
|
|
@@ -4033,32 +3912,12 @@ var cors = (options) => {
|
|
|
4033
3912
|
};
|
|
4034
3913
|
|
|
4035
3914
|
// src/commands/serve.ts
|
|
4036
|
-
import { join as
|
|
3915
|
+
import { join as join3, dirname as dirname3, resolve as resolve2, sep } from "path";
|
|
4037
3916
|
import { fileURLToPath } from "url";
|
|
4038
|
-
import { existsSync as
|
|
3917
|
+
import { existsSync as existsSync5, readFileSync as readFileSync4, statSync as statSync2 } from "fs";
|
|
4039
3918
|
import { spawn } from "child_process";
|
|
4040
|
-
|
|
4041
|
-
|
|
4042
|
-
var _createSqliteAdapter2;
|
|
4043
|
-
try {
|
|
4044
|
-
const mod = await Promise.resolve().then(() => (init_sqlite_adapter(), exports_sqlite_adapter));
|
|
4045
|
-
_createSqliteAdapter2 = mod.createSqliteAdapter;
|
|
4046
|
-
} catch {}
|
|
4047
|
-
function createSqliteAdapter3(filePath) {
|
|
4048
|
-
if (!_createSqliteAdapter2) {
|
|
4049
|
-
throw new Error("SQLite adapter requires Bun runtime");
|
|
4050
|
-
}
|
|
4051
|
-
return _createSqliteAdapter2(filePath);
|
|
4052
|
-
}
|
|
4053
|
-
function createAdapter2(filePath) {
|
|
4054
|
-
if (filePath.endsWith(".sqlite") || filePath.endsWith(".db")) {
|
|
4055
|
-
return createSqliteAdapter3(filePath);
|
|
4056
|
-
}
|
|
4057
|
-
return createJsonAdapter(filePath);
|
|
4058
|
-
}
|
|
4059
|
-
|
|
4060
|
-
// src/commands/serve.ts
|
|
4061
|
-
var __dirname2 = dirname4(fileURLToPath(import.meta.url));
|
|
3919
|
+
import { createServer } from "net";
|
|
3920
|
+
var __dirname2 = dirname3(fileURLToPath(import.meta.url));
|
|
4062
3921
|
function openBrowser(url) {
|
|
4063
3922
|
const command = process.platform === "darwin" ? "open" : process.platform === "win32" ? "cmd" : "xdg-open";
|
|
4064
3923
|
const args = process.platform === "win32" ? ["/c", "start", "", url] : [url];
|
|
@@ -4177,8 +4036,7 @@ function createApp() {
|
|
|
4177
4036
|
}
|
|
4178
4037
|
function isPortAvailable(port) {
|
|
4179
4038
|
return new Promise((resolve3) => {
|
|
4180
|
-
const
|
|
4181
|
-
const server = net.createServer();
|
|
4039
|
+
const server = createServer();
|
|
4182
4040
|
server.once("error", () => resolve3(false));
|
|
4183
4041
|
server.once("listening", () => {
|
|
4184
4042
|
server.close();
|
|
@@ -4212,25 +4070,27 @@ async function serveCommand(args, flags, options = {}) {
|
|
|
4212
4070
|
console.error(e.message);
|
|
4213
4071
|
process.exit(1);
|
|
4214
4072
|
}
|
|
4215
|
-
const adapter =
|
|
4073
|
+
const adapter = createAdapter(dataFile);
|
|
4216
4074
|
setStorageAdapter(adapter);
|
|
4217
4075
|
initStore();
|
|
4218
4076
|
const app = createApp();
|
|
4219
4077
|
const webDistPaths = [
|
|
4220
|
-
|
|
4221
|
-
|
|
4222
|
-
|
|
4078
|
+
join3(__dirname2, "web"),
|
|
4079
|
+
join3(__dirname2, "../web"),
|
|
4080
|
+
join3(__dirname2, "../../../web/dist"),
|
|
4081
|
+
join3(__dirname2, "../../web/dist"),
|
|
4082
|
+
join3(process.cwd(), "packages/web/dist")
|
|
4223
4083
|
];
|
|
4224
4084
|
let webDistPath = null;
|
|
4225
4085
|
for (const p of webDistPaths) {
|
|
4226
|
-
if (
|
|
4086
|
+
if (existsSync5(join3(p, "index.html"))) {
|
|
4227
4087
|
webDistPath = p;
|
|
4228
4088
|
break;
|
|
4229
4089
|
}
|
|
4230
4090
|
}
|
|
4231
4091
|
app.all("/api/*", (c) => c.json({ error: "Not found" }, 404));
|
|
4232
4092
|
if (webDistPath) {
|
|
4233
|
-
const indexHtml =
|
|
4093
|
+
const indexHtml = readFileSync4(join3(webDistPath, "index.html"), "utf-8");
|
|
4234
4094
|
const staticHandler = serveStatic({ root: webDistPath });
|
|
4235
4095
|
const staticExtensions = /\.(js|css|png|jpg|jpeg|gif|svg|ico|woff2?|ttf|eot|map|json|webp|webm|mp4|mp3|pdf)$/i;
|
|
4236
4096
|
app.use("/*", async (c, next) => {
|
|
@@ -4239,11 +4099,11 @@ async function serveCommand(args, flags, options = {}) {
|
|
|
4239
4099
|
return next();
|
|
4240
4100
|
}
|
|
4241
4101
|
if (staticExtensions.test(path)) {
|
|
4242
|
-
const filePath =
|
|
4102
|
+
const filePath = join3(webDistPath, path);
|
|
4243
4103
|
if (!filePath.startsWith(webDistPath + sep)) {
|
|
4244
4104
|
return c.notFound();
|
|
4245
4105
|
}
|
|
4246
|
-
if (
|
|
4106
|
+
if (existsSync5(filePath) && statSync2(filePath).isFile()) {
|
|
4247
4107
|
return staticHandler(c, next);
|
|
4248
4108
|
}
|
|
4249
4109
|
return c.notFound();
|
|
@@ -4494,11 +4354,11 @@ ${c.red}✗${c.reset} Auth timed out. Try again.`);
|
|
|
4494
4354
|
}
|
|
4495
4355
|
|
|
4496
4356
|
// src/commands/blob.ts
|
|
4497
|
-
import { readFileSync as
|
|
4357
|
+
import { readFileSync as readFileSync5, writeFileSync as writeFileSync4, existsSync as existsSync6 } from "fs";
|
|
4498
4358
|
import { basename, resolve as resolve3, extname } from "path";
|
|
4499
4359
|
function guessMimeType(filename) {
|
|
4500
4360
|
const ext = extname(filename).toLowerCase();
|
|
4501
|
-
const
|
|
4361
|
+
const types2 = {
|
|
4502
4362
|
".png": "image/png",
|
|
4503
4363
|
".jpg": "image/jpeg",
|
|
4504
4364
|
".jpeg": "image/jpeg",
|
|
@@ -4528,7 +4388,7 @@ function guessMimeType(filename) {
|
|
|
4528
4388
|
".xls": "application/vnd.ms-excel",
|
|
4529
4389
|
".xlsx": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
|
|
4530
4390
|
};
|
|
4531
|
-
return
|
|
4391
|
+
return types2[ext] || "application/octet-stream";
|
|
4532
4392
|
}
|
|
4533
4393
|
async function blobCommand(subcommand, args, flags, json) {
|
|
4534
4394
|
switch (subcommand) {
|
|
@@ -4539,11 +4399,11 @@ async function blobCommand(subcommand, args, flags, json) {
|
|
|
4539
4399
|
console.error("Usage: kenzoboard blob attach <task-id> <file-path>");
|
|
4540
4400
|
process.exit(1);
|
|
4541
4401
|
}
|
|
4542
|
-
if (!
|
|
4402
|
+
if (!existsSync6(filePath)) {
|
|
4543
4403
|
console.error(`File not found: ${filePath}`);
|
|
4544
4404
|
process.exit(1);
|
|
4545
4405
|
}
|
|
4546
|
-
const content =
|
|
4406
|
+
const content = readFileSync5(filePath);
|
|
4547
4407
|
const filename = basename(filePath);
|
|
4548
4408
|
const mime_type = guessMimeType(filename);
|
|
4549
4409
|
const blob = await uploadBlob(Buffer.from(content), filename, mime_type, taskId);
|
|
@@ -4568,7 +4428,7 @@ async function blobCommand(subcommand, args, flags, json) {
|
|
|
4568
4428
|
process.exit(1);
|
|
4569
4429
|
}
|
|
4570
4430
|
const destPath = outputPath || resolve3(process.cwd(), result.blob.filename);
|
|
4571
|
-
|
|
4431
|
+
writeFileSync4(destPath, result.content);
|
|
4572
4432
|
if (json) {
|
|
4573
4433
|
output({ path: destPath, ...result.blob }, true);
|
|
4574
4434
|
} else {
|
|
@@ -4626,6 +4486,7 @@ function formatSize(bytes) {
|
|
|
4626
4486
|
return `${(bytes / 1024).toFixed(1)}KB`;
|
|
4627
4487
|
return `${(bytes / (1024 * 1024)).toFixed(1)}MB`;
|
|
4628
4488
|
}
|
|
4489
|
+
|
|
4629
4490
|
// src/index.ts
|
|
4630
4491
|
var c2 = {
|
|
4631
4492
|
reset: "\x1B[0m",
|
|
@@ -4649,7 +4510,7 @@ function prompt(question) {
|
|
|
4649
4510
|
function isInteractive() {
|
|
4650
4511
|
return process.stdin.isTTY === true;
|
|
4651
4512
|
}
|
|
4652
|
-
var __dirname3 =
|
|
4513
|
+
var __dirname3 = dirname4(fileURLToPath2(import.meta.url));
|
|
4653
4514
|
function publicCommandName() {
|
|
4654
4515
|
const invoked = basename2(process.argv[1] || "");
|
|
4655
4516
|
return invoked === "flux" ? "flux" : "kenzoboard";
|
|
@@ -4666,22 +4527,11 @@ function isCliEntrypoint() {
|
|
|
4666
4527
|
function defaultServePort() {
|
|
4667
4528
|
return publicCommandName() === "flux" ? 3589 : 3000;
|
|
4668
4529
|
}
|
|
4669
|
-
function findExistingFluxDirFromCwd() {
|
|
4670
|
-
let dir = process.cwd();
|
|
4671
|
-
while (dirname5(dir) !== dir) {
|
|
4672
|
-
const fluxDir = resolve4(dir, ".flux");
|
|
4673
|
-
if (existsSync9(fluxDir)) {
|
|
4674
|
-
return fluxDir;
|
|
4675
|
-
}
|
|
4676
|
-
dir = dirname5(dir);
|
|
4677
|
-
}
|
|
4678
|
-
return null;
|
|
4679
|
-
}
|
|
4680
4530
|
function ensureFluxIgnored() {
|
|
4681
4531
|
const gitRoot = findGitRoot();
|
|
4682
4532
|
const gitignorePath = gitRoot ? resolve4(gitRoot, ".gitignore") : resolve4(process.cwd(), ".gitignore");
|
|
4683
4533
|
const gitignoreEntry = ".flux/";
|
|
4684
|
-
let gitignoreContent =
|
|
4534
|
+
let gitignoreContent = existsSync7(gitignorePath) ? readFileSync6(gitignorePath, "utf-8") : "";
|
|
4685
4535
|
if (!gitignoreContent.split(`
|
|
4686
4536
|
`).some((line) => line.trim() === gitignoreEntry)) {
|
|
4687
4537
|
const newline = gitignoreContent.length > 0 && !gitignoreContent.endsWith(`
|
|
@@ -4693,22 +4543,22 @@ function ensureFluxIgnored() {
|
|
|
4693
4543
|
}
|
|
4694
4544
|
}
|
|
4695
4545
|
async function ensureKenzoWorkspace() {
|
|
4696
|
-
const fluxDir =
|
|
4546
|
+
const fluxDir = process.env.FLUX_DIR || resolve4(process.cwd(), ".flux");
|
|
4697
4547
|
const configPath = resolve4(fluxDir, "config.json");
|
|
4698
4548
|
const jsonPath = resolve4(fluxDir, "data.json");
|
|
4699
4549
|
const sqlitePath = resolve4(fluxDir, "data.sqlite");
|
|
4700
|
-
if (!
|
|
4701
|
-
|
|
4550
|
+
if (!existsSync7(fluxDir)) {
|
|
4551
|
+
mkdirSync3(fluxDir, { recursive: true });
|
|
4702
4552
|
writeConfig(fluxDir, {});
|
|
4703
|
-
|
|
4553
|
+
writeFileSync5(jsonPath, JSON.stringify({ projects: [], epics: [], tasks: [] }, null, 2));
|
|
4704
4554
|
ensureFluxIgnored();
|
|
4705
4555
|
console.log(`Created local Kenzo workspace at ${fluxDir}`);
|
|
4706
|
-
} else if (!
|
|
4556
|
+
} else if (!existsSync7(configPath)) {
|
|
4707
4557
|
writeConfig(fluxDir, {});
|
|
4708
4558
|
}
|
|
4709
4559
|
const config = readConfigRaw(fluxDir);
|
|
4710
|
-
if (!config.server && !
|
|
4711
|
-
|
|
4560
|
+
if (!config.server && !existsSync7(jsonPath) && !existsSync7(sqlitePath)) {
|
|
4561
|
+
writeFileSync5(jsonPath, JSON.stringify({ projects: [], epics: [], tasks: [] }, null, 2));
|
|
4712
4562
|
}
|
|
4713
4563
|
const storage = initStorage();
|
|
4714
4564
|
const projects = await getProjects2();
|
|
@@ -4735,22 +4585,31 @@ async function ensureKenzoWorkspace() {
|
|
|
4735
4585
|
return { projectId, projectName };
|
|
4736
4586
|
}
|
|
4737
4587
|
function printMcpSetup(command = publicCommandName()) {
|
|
4588
|
+
const npxMcpCommand = "npx -y --package kenzoboard kenzoboard-mcp";
|
|
4589
|
+
const installedMcpCommand = "kenzoboard-mcp";
|
|
4738
4590
|
const dockerCommand = 'docker run -i --rm -v "$(pwd)/.flux:/app/packages/data" -e FLUX_DATA=/app/packages/data/flux.sqlite flux-mcp bun packages/mcp/dist/index.js';
|
|
4739
4591
|
const localMcpPath = resolve4(process.cwd(), "packages/mcp/dist/index.js");
|
|
4740
4592
|
console.log(`${c2.bold}Agent setup${c2.reset} ${c2.dim}(MCP resources remain flux:// for compatibility)${c2.reset}
|
|
4741
4593
|
`);
|
|
4742
|
-
|
|
4743
|
-
|
|
4594
|
+
console.log(`${c2.bold}Codex:${c2.reset}`);
|
|
4595
|
+
if (existsSync7(localMcpPath)) {
|
|
4744
4596
|
console.log(` codex mcp add flux -- bun ${localMcpPath}`);
|
|
4745
|
-
|
|
4597
|
+
} else {
|
|
4598
|
+
console.log(` codex mcp add flux -- ${npxMcpCommand}`);
|
|
4599
|
+
}
|
|
4600
|
+
console.log(`${c2.bold}Claude Code:${c2.reset}`);
|
|
4601
|
+
if (existsSync7(localMcpPath)) {
|
|
4746
4602
|
console.log(` claude mcp add flux -- bun ${localMcpPath}`);
|
|
4747
4603
|
} else {
|
|
4748
|
-
console.log(
|
|
4749
|
-
console.log(` codex mcp add flux -- ${dockerCommand}`);
|
|
4750
|
-
console.log(`${c2.bold}Claude Code:${c2.reset}`);
|
|
4751
|
-
console.log(` claude mcp add flux -- ${dockerCommand}`);
|
|
4604
|
+
console.log(` claude mcp add flux -- ${npxMcpCommand}`);
|
|
4752
4605
|
}
|
|
4753
4606
|
console.log("");
|
|
4607
|
+
console.log(`${c2.bold}Global install:${c2.reset}`);
|
|
4608
|
+
console.log(` ${installedMcpCommand}`);
|
|
4609
|
+
console.log("");
|
|
4610
|
+
console.log(`${c2.bold}Advanced Docker:${c2.reset}`);
|
|
4611
|
+
console.log(` ${dockerCommand}`);
|
|
4612
|
+
console.log("");
|
|
4754
4613
|
console.log(`Run ${c2.cyan}${command} ready${c2.reset} to see agent-ready work.`);
|
|
4755
4614
|
}
|
|
4756
4615
|
async function launchKenzoApp() {
|
|
@@ -4788,7 +4647,7 @@ function updateAgentInstructions() {
|
|
|
4788
4647
|
let targetFile = null;
|
|
4789
4648
|
for (const name of candidates) {
|
|
4790
4649
|
const path = resolve4(cwd, name);
|
|
4791
|
-
if (
|
|
4650
|
+
if (existsSync7(path)) {
|
|
4792
4651
|
targetFile = path;
|
|
4793
4652
|
break;
|
|
4794
4653
|
}
|
|
@@ -4796,7 +4655,7 @@ function updateAgentInstructions() {
|
|
|
4796
4655
|
if (!targetFile) {
|
|
4797
4656
|
targetFile = resolve4(cwd, "AGENTS.md");
|
|
4798
4657
|
}
|
|
4799
|
-
let content =
|
|
4658
|
+
let content = existsSync7(targetFile) ? readFileSync6(targetFile, "utf-8") : "";
|
|
4800
4659
|
const startMarker = "<!-- FLUX:START -->";
|
|
4801
4660
|
const endMarker = "<!-- FLUX:END -->";
|
|
4802
4661
|
const startIdx = content.indexOf(startMarker);
|
|
@@ -4809,7 +4668,7 @@ function updateAgentInstructions() {
|
|
|
4809
4668
|
` + FLUX_INSTRUCTIONS + `
|
|
4810
4669
|
`;
|
|
4811
4670
|
}
|
|
4812
|
-
|
|
4671
|
+
writeFileSync5(targetFile, content.trimStart());
|
|
4813
4672
|
return targetFile;
|
|
4814
4673
|
}
|
|
4815
4674
|
function findGitRoot() {
|
|
@@ -4821,7 +4680,7 @@ function findGitRoot() {
|
|
|
4821
4680
|
}
|
|
4822
4681
|
function ensureWorktree(gitRoot) {
|
|
4823
4682
|
const worktreePath = resolve4(gitRoot, ".git", "flux-worktree");
|
|
4824
|
-
if (
|
|
4683
|
+
if (existsSync7(worktreePath)) {
|
|
4825
4684
|
return worktreePath;
|
|
4826
4685
|
}
|
|
4827
4686
|
const branchExists = ["flux-data", "origin/flux-data"].some((ref) => {
|
|
@@ -4875,7 +4734,7 @@ async function doctorCommand(flags) {
|
|
|
4875
4734
|
`);
|
|
4876
4735
|
return;
|
|
4877
4736
|
}
|
|
4878
|
-
const fluxDirExists =
|
|
4737
|
+
const fluxDirExists = existsSync7(fluxDir);
|
|
4879
4738
|
if (!fluxDirExists) {
|
|
4880
4739
|
console.log(`${c2.yellow}!${c2.reset} .flux directory not found at ${fluxDir}`);
|
|
4881
4740
|
console.log(` Run ${c2.cyan}${publicCommandName()} init${c2.reset} to initialize
|
|
@@ -4884,7 +4743,7 @@ async function doctorCommand(flags) {
|
|
|
4884
4743
|
}
|
|
4885
4744
|
console.log(`${c2.green}OK${c2.reset} .flux directory: ${fluxDir}`);
|
|
4886
4745
|
const configPath = resolve4(fluxDir, "config.json");
|
|
4887
|
-
const configExists =
|
|
4746
|
+
const configExists = existsSync7(configPath);
|
|
4888
4747
|
if (configExists) {
|
|
4889
4748
|
const config2 = readConfig(fluxDir);
|
|
4890
4749
|
const mode = config2.server ? "server" : "local";
|
|
@@ -4896,8 +4755,8 @@ async function doctorCommand(flags) {
|
|
|
4896
4755
|
}
|
|
4897
4756
|
const jsonPath = resolve4(fluxDir, "data.json");
|
|
4898
4757
|
const sqlitePath = resolve4(fluxDir, "data.sqlite");
|
|
4899
|
-
const jsonExists =
|
|
4900
|
-
const sqliteExists =
|
|
4758
|
+
const jsonExists = existsSync7(jsonPath);
|
|
4759
|
+
const sqliteExists = existsSync7(sqlitePath);
|
|
4901
4760
|
const countRecords = (path) => {
|
|
4902
4761
|
try {
|
|
4903
4762
|
const adapter = createAdapter(path);
|
|
@@ -4968,8 +4827,8 @@ ${c2.cyan}Merging ${otherFile} into ${configuredFile}...${c2.reset}`);
|
|
|
4968
4827
|
console.log(`
|
|
4969
4828
|
${c2.dim}data.json is empty (likely created by old MCP/Server bug)${c2.reset}`);
|
|
4970
4829
|
if (fix) {
|
|
4971
|
-
const { unlinkSync:
|
|
4972
|
-
|
|
4830
|
+
const { unlinkSync: unlinkSync2 } = await import("fs");
|
|
4831
|
+
unlinkSync2(jsonPath);
|
|
4973
4832
|
console.log(`${c2.green}OK${c2.reset} Removed empty data.json`);
|
|
4974
4833
|
fixed++;
|
|
4975
4834
|
} else {
|
|
@@ -4980,8 +4839,8 @@ ${c2.dim}data.json is empty (likely created by old MCP/Server bug)${c2.reset}`);
|
|
|
4980
4839
|
console.log(`
|
|
4981
4840
|
${c2.dim}data.sqlite is empty${c2.reset}`);
|
|
4982
4841
|
if (fix) {
|
|
4983
|
-
const { unlinkSync:
|
|
4984
|
-
|
|
4842
|
+
const { unlinkSync: unlinkSync2 } = await import("fs");
|
|
4843
|
+
unlinkSync2(sqlitePath);
|
|
4985
4844
|
console.log(`${c2.green}OK${c2.reset} Removed empty data.sqlite`);
|
|
4986
4845
|
fixed++;
|
|
4987
4846
|
} else {
|
|
@@ -5073,14 +4932,14 @@ async function main() {
|
|
|
5073
4932
|
const dataFileName = useSqlite ? "data.sqlite" : "data.json";
|
|
5074
4933
|
const dataPath = resolve4(fluxDir, dataFileName);
|
|
5075
4934
|
const configPath = resolve4(fluxDir, "config.json");
|
|
5076
|
-
const isNew = !
|
|
5077
|
-
|
|
4935
|
+
const isNew = !existsSync7(resolve4(fluxDir, "data.json")) && !existsSync7(resolve4(fluxDir, "data.sqlite"));
|
|
4936
|
+
mkdirSync3(fluxDir, { recursive: true });
|
|
5078
4937
|
let serverUrl2 = parsed.flags.server;
|
|
5079
4938
|
let apiKey2 = parsed.flags["api-key"];
|
|
5080
4939
|
const useGit = parsed.flags.git === true;
|
|
5081
|
-
if (
|
|
4940
|
+
if (existsSync7(configPath)) {
|
|
5082
4941
|
try {
|
|
5083
|
-
const existing = JSON.parse(
|
|
4942
|
+
const existing = JSON.parse(readFileSync6(configPath, "utf-8"));
|
|
5084
4943
|
const warnings = [];
|
|
5085
4944
|
if (existing.server && (useGit || parsed.flags.sqlite)) {
|
|
5086
4945
|
warnings.push(`Repo uses server mode (${existing.server}), you're setting up git mode`);
|
|
@@ -5150,7 +5009,7 @@ Overwrite existing config? [y/N]: `);
|
|
|
5150
5009
|
const gitRoot = findGitRoot();
|
|
5151
5010
|
const gitignorePath = gitRoot ? resolve4(gitRoot, ".gitignore") : resolve4(process.cwd(), ".gitignore");
|
|
5152
5011
|
const gitignoreEntry = ".flux/";
|
|
5153
|
-
let gitignoreContent =
|
|
5012
|
+
let gitignoreContent = existsSync7(gitignorePath) ? readFileSync6(gitignorePath, "utf-8") : "";
|
|
5154
5013
|
if (!gitignoreContent.split(`
|
|
5155
5014
|
`).some((line) => line.trim() === gitignoreEntry)) {
|
|
5156
5015
|
const newline = gitignoreContent.length > 0 && !gitignoreContent.endsWith(`
|
|
@@ -5160,13 +5019,13 @@ Overwrite existing config? [y/N]: `);
|
|
|
5160
5019
|
`);
|
|
5161
5020
|
console.log(`Added .flux/ to ${gitRoot ? gitignorePath : ".gitignore"}`);
|
|
5162
5021
|
}
|
|
5163
|
-
if (!serverUrl2 && !
|
|
5022
|
+
if (!serverUrl2 && !existsSync7(dataPath)) {
|
|
5164
5023
|
if (useSqlite) {
|
|
5165
5024
|
const adapter = createAdapter(dataPath);
|
|
5166
5025
|
setStorageAdapter(adapter);
|
|
5167
5026
|
initStore();
|
|
5168
5027
|
} else {
|
|
5169
|
-
|
|
5028
|
+
writeFileSync5(dataPath, JSON.stringify({ projects: [], epics: [], tasks: [] }, null, 2));
|
|
5170
5029
|
}
|
|
5171
5030
|
}
|
|
5172
5031
|
if (isNew) {
|
|
@@ -5268,15 +5127,15 @@ Select a project:`);
|
|
|
5268
5127
|
const localBlobs = resolve4(fluxDir, "blobs");
|
|
5269
5128
|
execSync("git fetch origin flux-data", { stdio: "pipe", cwd: worktree });
|
|
5270
5129
|
execSync("git reset --hard origin/flux-data", { stdio: "pipe", cwd: worktree });
|
|
5271
|
-
if (
|
|
5272
|
-
|
|
5273
|
-
|
|
5130
|
+
if (existsSync7(worktreeData)) {
|
|
5131
|
+
mkdirSync3(fluxDir, { recursive: true });
|
|
5132
|
+
writeFileSync5(dataPath, readFileSync6(worktreeData, "utf-8"));
|
|
5274
5133
|
console.log("Pulled latest tasks from flux-data branch");
|
|
5275
5134
|
} else {
|
|
5276
5135
|
console.log("No .flux/data.json in flux-data branch yet");
|
|
5277
5136
|
}
|
|
5278
|
-
if (
|
|
5279
|
-
|
|
5137
|
+
if (existsSync7(worktreeBlobs)) {
|
|
5138
|
+
mkdirSync3(localBlobs, { recursive: true });
|
|
5280
5139
|
cpSync(worktreeBlobs, localBlobs, { recursive: true });
|
|
5281
5140
|
console.log("Pulled blobs from flux-data branch");
|
|
5282
5141
|
}
|
|
@@ -5286,7 +5145,7 @@ Select a project:`);
|
|
|
5286
5145
|
}
|
|
5287
5146
|
} else {
|
|
5288
5147
|
const msg = parsed.subcommand || "update tasks";
|
|
5289
|
-
if (!
|
|
5148
|
+
if (!existsSync7(dataPath)) {
|
|
5290
5149
|
console.error(`No .flux/data.json found. Run: ${publicCommandName()} init`);
|
|
5291
5150
|
process.exit(1);
|
|
5292
5151
|
}
|
|
@@ -5296,14 +5155,14 @@ Select a project:`);
|
|
|
5296
5155
|
const worktreeData = resolve4(worktreeFlux, "data.json");
|
|
5297
5156
|
const localBlobs = resolve4(fluxDir, "blobs");
|
|
5298
5157
|
const worktreeBlobs = resolve4(worktreeFlux, "blobs");
|
|
5299
|
-
|
|
5300
|
-
|
|
5301
|
-
if (
|
|
5302
|
-
|
|
5158
|
+
mkdirSync3(worktreeFlux, { recursive: true });
|
|
5159
|
+
writeFileSync5(worktreeData, readFileSync6(dataPath, "utf-8"));
|
|
5160
|
+
if (existsSync7(localBlobs)) {
|
|
5161
|
+
mkdirSync3(worktreeBlobs, { recursive: true });
|
|
5303
5162
|
cpSync(localBlobs, worktreeBlobs, { recursive: true });
|
|
5304
5163
|
}
|
|
5305
5164
|
execSync("git add .flux/data.json", { stdio: "pipe", cwd: worktree });
|
|
5306
|
-
if (
|
|
5165
|
+
if (existsSync7(worktreeBlobs)) {
|
|
5307
5166
|
execSync("git add .flux/blobs", { stdio: "pipe", cwd: worktree });
|
|
5308
5167
|
}
|
|
5309
5168
|
try {
|
|
@@ -5338,7 +5197,7 @@ Select a project:`);
|
|
|
5338
5197
|
if (parsed.command === "prime") {
|
|
5339
5198
|
const fluxDir = findFluxDir();
|
|
5340
5199
|
const configPath = resolve4(fluxDir, "config.json");
|
|
5341
|
-
if (!
|
|
5200
|
+
if (!existsSync7(configPath)) {
|
|
5342
5201
|
return;
|
|
5343
5202
|
}
|
|
5344
5203
|
try {
|
|
@@ -5382,7 +5241,7 @@ Select a project:`);
|
|
|
5382
5241
|
const output2 = JSON.stringify(data, null, 2);
|
|
5383
5242
|
const outFile = parsed.flags.o || parsed.flags.output;
|
|
5384
5243
|
if (outFile) {
|
|
5385
|
-
|
|
5244
|
+
writeFileSync5(outFile, output2);
|
|
5386
5245
|
console.log(`Exported to ${outFile}`);
|
|
5387
5246
|
} else {
|
|
5388
5247
|
console.log(output2);
|
|
@@ -5403,11 +5262,11 @@ Select a project:`);
|
|
|
5403
5262
|
}
|
|
5404
5263
|
content = Buffer.concat(chunks).toString("utf-8");
|
|
5405
5264
|
} else {
|
|
5406
|
-
if (!
|
|
5265
|
+
if (!existsSync7(file)) {
|
|
5407
5266
|
console.error(`File not found: ${file}`);
|
|
5408
5267
|
process.exit(1);
|
|
5409
5268
|
}
|
|
5410
|
-
content =
|
|
5269
|
+
content = readFileSync6(file, "utf-8");
|
|
5411
5270
|
}
|
|
5412
5271
|
const data = JSON.parse(content);
|
|
5413
5272
|
const merge = parsed.flags.merge === true;
|