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 CHANGED
@@ -1,5 +1,4 @@
1
- #!/usr/bin/env bun
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: () => setBlobStorage2,
34
+ setBlobStorage: () => setBlobStorage,
117
35
  getBlobStorage: () => getBlobStorage,
118
- createFilesystemBlobStorage: () => createFilesystemBlobStorage2
36
+ createFilesystemBlobStorage: () => createFilesystemBlobStorage
119
37
  });
120
- import { existsSync as existsSync5, mkdirSync as mkdirSync4, readFileSync as readFileSync4, writeFileSync as writeFileSync4, unlinkSync as unlinkSync2 } from "fs";
121
- import { join as join2 } from "path";
122
- import { createHash as createHash2 } from "crypto";
123
- function blobPath2(blobsDir, hash) {
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 join2(blobsDir, prefix, hash);
43
+ return join(blobsDir, prefix, hash);
126
44
  }
127
- function createFilesystemBlobStorage2(blobsDir) {
128
- mkdirSync4(blobsDir, { recursive: true });
45
+ function createFilesystemBlobStorage(blobsDir) {
46
+ mkdirSync2(blobsDir, { recursive: true });
129
47
  return {
130
48
  write(content) {
131
- const hash = createHash2("sha256").update(content).digest("hex");
49
+ const hash = createHash("sha256").update(content).digest("hex");
132
50
  const size = content.length;
133
- const filePath = blobPath2(blobsDir, hash);
134
- if (!existsSync5(filePath)) {
135
- const prefixDir = join2(blobsDir, hash.slice(0, 2));
136
- mkdirSync4(prefixDir, { recursive: true });
137
- writeFileSync4(filePath, content);
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 = blobPath2(blobsDir, hash);
143
- if (!existsSync5(filePath))
60
+ const filePath = blobPath(blobsDir, hash);
61
+ if (!existsSync2(filePath))
144
62
  return null;
145
- return readFileSync4(filePath);
63
+ return readFileSync2(filePath);
146
64
  },
147
65
  exists(hash) {
148
- return existsSync5(blobPath2(blobsDir, hash));
66
+ return existsSync2(blobPath(blobsDir, hash));
149
67
  },
150
68
  remove(hash) {
151
- const filePath = blobPath2(blobsDir, hash);
152
- if (!existsSync5(filePath))
69
+ const filePath = blobPath(blobsDir, hash);
70
+ if (!existsSync2(filePath))
153
71
  return false;
154
- unlinkSync2(filePath);
72
+ unlinkSync(filePath);
155
73
  return true;
156
74
  }
157
75
  };
158
76
  }
159
- function setBlobStorage2(bs) {
160
- blobStorage2 = bs;
77
+ function setBlobStorage(bs) {
78
+ blobStorage = bs;
161
79
  }
162
80
  function getBlobStorage() {
163
- return blobStorage2;
81
+ return blobStorage;
164
82
  }
165
- var blobStorage2 = null;
83
+ var blobStorage = null;
166
84
  var init_blob_storage = () => {};
167
85
 
168
86
  // src/index.ts
169
- import { resolve as resolve4, dirname as dirname5, basename as basename2 } from "path";
87
+ import { resolve as resolve4, dirname as dirname4, basename as basename2 } from "path";
170
88
  import { execSync } from "child_process";
171
- import { existsSync as existsSync9, readFileSync as readFileSync7, writeFileSync as writeFileSync6, mkdirSync as mkdirSync5, appendFileSync, cpSync, realpathSync } from "fs";
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
- try {
684
- const mod = await Promise.resolve().then(() => (init_sqlite_adapter(), exports_sqlite_adapter));
685
- _createSqliteAdapter = mod.createSqliteAdapter;
686
- } catch {}
687
- function createSqliteAdapter2(filePath) {
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 createSqliteAdapter2(filePath);
616
+ return createSqliteAdapter(filePath);
696
617
  }
697
618
  return createJsonAdapter(filePath);
698
619
  }
699
620
 
700
- // ../shared/dist/blob-storage.js
701
- import { existsSync as existsSync3, mkdirSync as mkdirSync3, readFileSync as readFileSync2, writeFileSync as writeFileSync2, unlinkSync } from "fs";
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 dirname3 } from "path";
747
- import { existsSync as existsSync4, readFileSync as readFileSync3, writeFileSync as writeFileSync3, chmodSync } from "fs";
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 (dirname3(dir) !== dir) {
637
+ while (dirname2(dir) !== dir) {
759
638
  const fluxDir = resolve(dir, ".flux");
760
- if (existsSync4(fluxDir)) {
639
+ if (existsSync3(fluxDir)) {
761
640
  return fluxDir;
762
641
  }
763
- dir = dirname3(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 = dirname3(fluxDir);
648
+ const repoRoot = dirname2(fluxDir);
770
649
  const envPath = resolve(repoRoot, ".env.local");
771
- if (existsSync4(envPath)) {
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 (existsSync4(configPath)) {
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 existsSync6 } from "fs";
2306
- import { join as join3 } from "path";
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 !== "" && !existsSync6(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 = join3(root, !optionPath && options.rewriteRequestPath ? options.rewriteRequestPath(filename, c) : filename);
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 = join3(path, indexFile);
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 join4, dirname as dirname4, resolve as resolve2, sep } from "path";
3915
+ import { join as join3, dirname as dirname3, resolve as resolve2, sep } from "path";
4037
3916
  import { fileURLToPath } from "url";
4038
- import { existsSync as existsSync7, readFileSync as readFileSync5, statSync as statSync2 } from "fs";
3917
+ import { existsSync as existsSync5, readFileSync as readFileSync4, statSync as statSync2 } from "fs";
4039
3918
  import { spawn } from "child_process";
4040
-
4041
- // ../shared/dist/adapters/index.js
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 net = __require("net");
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 = createAdapter2(dataFile);
4073
+ const adapter = createAdapter(dataFile);
4216
4074
  setStorageAdapter(adapter);
4217
4075
  initStore();
4218
4076
  const app = createApp();
4219
4077
  const webDistPaths = [
4220
- join4(__dirname2, "../../../web/dist"),
4221
- join4(__dirname2, "../../web/dist"),
4222
- join4(process.cwd(), "packages/web/dist")
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 (existsSync7(join4(p, "index.html"))) {
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 = readFileSync5(join4(webDistPath, "index.html"), "utf-8");
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 = join4(webDistPath, path);
4102
+ const filePath = join3(webDistPath, path);
4243
4103
  if (!filePath.startsWith(webDistPath + sep)) {
4244
4104
  return c.notFound();
4245
4105
  }
4246
- if (existsSync7(filePath) && statSync2(filePath).isFile()) {
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 readFileSync6, writeFileSync as writeFileSync5, existsSync as existsSync8 } from "fs";
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 types3 = {
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 types3[ext] || "application/octet-stream";
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 (!existsSync8(filePath)) {
4402
+ if (!existsSync6(filePath)) {
4543
4403
  console.error(`File not found: ${filePath}`);
4544
4404
  process.exit(1);
4545
4405
  }
4546
- const content = readFileSync6(filePath);
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
- writeFileSync5(destPath, result.content);
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 = dirname5(fileURLToPath2(import.meta.url));
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 = existsSync9(gitignorePath) ? readFileSync7(gitignorePath, "utf-8") : "";
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 = findExistingFluxDirFromCwd() || resolve4(process.cwd(), ".flux");
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 (!existsSync9(fluxDir)) {
4701
- mkdirSync5(fluxDir, { recursive: true });
4550
+ if (!existsSync7(fluxDir)) {
4551
+ mkdirSync3(fluxDir, { recursive: true });
4702
4552
  writeConfig(fluxDir, {});
4703
- writeFileSync6(jsonPath, JSON.stringify({ projects: [], epics: [], tasks: [] }, null, 2));
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 (!existsSync9(configPath)) {
4556
+ } else if (!existsSync7(configPath)) {
4707
4557
  writeConfig(fluxDir, {});
4708
4558
  }
4709
4559
  const config = readConfigRaw(fluxDir);
4710
- if (!config.server && !existsSync9(jsonPath) && !existsSync9(sqlitePath)) {
4711
- writeFileSync6(jsonPath, JSON.stringify({ projects: [], epics: [], tasks: [] }, null, 2));
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
- if (existsSync9(localMcpPath)) {
4743
- console.log(`${c2.bold}Codex:${c2.reset}`);
4594
+ console.log(`${c2.bold}Codex:${c2.reset}`);
4595
+ if (existsSync7(localMcpPath)) {
4744
4596
  console.log(` codex mcp add flux -- bun ${localMcpPath}`);
4745
- console.log(`${c2.bold}Claude Code:${c2.reset}`);
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(`${c2.bold}Codex:${c2.reset}`);
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 (existsSync9(path)) {
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 = existsSync9(targetFile) ? readFileSync7(targetFile, "utf-8") : "";
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
- writeFileSync6(targetFile, content.trimStart());
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 (existsSync9(worktreePath)) {
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 = existsSync9(fluxDir);
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 = existsSync9(configPath);
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 = existsSync9(jsonPath);
4900
- const sqliteExists = existsSync9(sqlitePath);
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: unlinkSync3 } = await import("fs");
4972
- unlinkSync3(jsonPath);
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: unlinkSync3 } = await import("fs");
4984
- unlinkSync3(sqlitePath);
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 = !existsSync9(resolve4(fluxDir, "data.json")) && !existsSync9(resolve4(fluxDir, "data.sqlite"));
5077
- mkdirSync5(fluxDir, { recursive: true });
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 (existsSync9(configPath)) {
4940
+ if (existsSync7(configPath)) {
5082
4941
  try {
5083
- const existing = JSON.parse(readFileSync7(configPath, "utf-8"));
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 = existsSync9(gitignorePath) ? readFileSync7(gitignorePath, "utf-8") : "";
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 && !existsSync9(dataPath)) {
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
- writeFileSync6(dataPath, JSON.stringify({ projects: [], epics: [], tasks: [] }, null, 2));
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 (existsSync9(worktreeData)) {
5272
- mkdirSync5(fluxDir, { recursive: true });
5273
- writeFileSync6(dataPath, readFileSync7(worktreeData, "utf-8"));
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 (existsSync9(worktreeBlobs)) {
5279
- mkdirSync5(localBlobs, { recursive: true });
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 (!existsSync9(dataPath)) {
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
- mkdirSync5(worktreeFlux, { recursive: true });
5300
- writeFileSync6(worktreeData, readFileSync7(dataPath, "utf-8"));
5301
- if (existsSync9(localBlobs)) {
5302
- mkdirSync5(worktreeBlobs, { recursive: true });
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 (existsSync9(worktreeBlobs)) {
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 (!existsSync9(configPath)) {
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
- writeFileSync6(outFile, output2);
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 (!existsSync9(file)) {
5265
+ if (!existsSync7(file)) {
5407
5266
  console.error(`File not found: ${file}`);
5408
5267
  process.exit(1);
5409
5268
  }
5410
- content = readFileSync7(file, "utf-8");
5269
+ content = readFileSync6(file, "utf-8");
5411
5270
  }
5412
5271
  const data = JSON.parse(content);
5413
5272
  const merge = parsed.flags.merge === true;