@kaddo/cli 3.68.0 → 3.69.0

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.
Files changed (3) hide show
  1. package/dist/core.js +7471 -0
  2. package/dist/index.js +133 -26
  3. package/package.json +7 -2
package/dist/index.js CHANGED
@@ -1361,8 +1361,8 @@ function loadConfig(dir) {
1361
1361
  const parsed = configSchema.safeParse(raw ?? {});
1362
1362
  if (!parsed.success) {
1363
1363
  const issues = parsed.error.issues.map((i) => {
1364
- const path8 = i.path.join(".");
1365
- return path8 ? ` - ${path8}: ${i.message}` : ` - ${i.message}`;
1364
+ const path9 = i.path.join(".");
1365
+ return path9 ? ` - ${path9}: ${i.message}` : ` - ${i.message}`;
1366
1366
  }).join("\n");
1367
1367
  throw new ConfigError(`Invalid .kaddo/config.yml:
1368
1368
  ${issues}`);
@@ -6732,10 +6732,10 @@ function analyzeGuard(touchedFiles, artifacts, silentWithoutOwnership) {
6732
6732
  import { parse as parseYaml4, stringify as stringifyYaml2 } from "yaml";
6733
6733
  var IGNORE_FILE = ".kaddo/ignores.yml";
6734
6734
  function loadIgnores(dir) {
6735
- const path8 = join(dir, IGNORE_FILE);
6736
- if (!exists(path8)) return [];
6735
+ const path9 = join(dir, IGNORE_FILE);
6736
+ if (!exists(path9)) return [];
6737
6737
  try {
6738
- const raw = readFile(path8);
6738
+ const raw = readFile(path9);
6739
6739
  const parsed = parseYaml4(raw);
6740
6740
  return Array.isArray(parsed) ? parsed : [];
6741
6741
  } catch {
@@ -6743,7 +6743,7 @@ function loadIgnores(dir) {
6743
6743
  }
6744
6744
  }
6745
6745
  function saveIgnore(dir, entry) {
6746
- const path8 = join(dir, IGNORE_FILE);
6746
+ const path9 = join(dir, IGNORE_FILE);
6747
6747
  const existing = loadIgnores(dir);
6748
6748
  const idx = existing.findIndex((e) => e.artifact_id === entry.artifact_id);
6749
6749
  if (idx >= 0) {
@@ -6751,17 +6751,17 @@ function saveIgnore(dir, entry) {
6751
6751
  } else {
6752
6752
  existing.push(entry);
6753
6753
  }
6754
- writeFile(path8, stringifyYaml2(existing));
6754
+ writeFile(path9, stringifyYaml2(existing));
6755
6755
  }
6756
6756
  function isIgnored(ignores, artifactId) {
6757
6757
  return ignores.find((e) => e.artifact_id === artifactId);
6758
6758
  }
6759
6759
  function removeIgnore(dir, artifactId) {
6760
- const path8 = join(dir, IGNORE_FILE);
6760
+ const path9 = join(dir, IGNORE_FILE);
6761
6761
  const existing = loadIgnores(dir);
6762
6762
  const filtered = existing.filter((e) => e.artifact_id !== artifactId);
6763
6763
  if (filtered.length === existing.length) return false;
6764
- writeFile(path8, stringifyYaml2(filtered));
6764
+ writeFile(path9, stringifyYaml2(filtered));
6765
6765
  return true;
6766
6766
  }
6767
6767
 
@@ -6783,11 +6783,11 @@ function moduleArtifactCoverage(dir, id) {
6783
6783
  };
6784
6784
  }
6785
6785
  function loadMappedModules(dir) {
6786
- const path8 = join(dir, DESCRIPTOR_PATH);
6787
- if (!exists(path8)) return [];
6786
+ const path9 = join(dir, DESCRIPTOR_PATH);
6787
+ if (!exists(path9)) return [];
6788
6788
  let parsed;
6789
6789
  try {
6790
- parsed = parseYaml5(readFile(path8));
6790
+ parsed = parseYaml5(readFile(path9));
6791
6791
  } catch {
6792
6792
  return [];
6793
6793
  }
@@ -7531,7 +7531,7 @@ function buildGuardHistory(dir) {
7531
7531
  const d = hotspotDir(t.code_path);
7532
7532
  hotspotMap.set(d, (hotspotMap.get(d) ?? 0) + 1);
7533
7533
  }
7534
- const hotspots = [...hotspotMap.entries()].map(([path8, warnings]) => ({ path: path8, warnings })).sort((a, b) => b.warnings - a.warnings);
7534
+ const hotspots = [...hotspotMap.entries()].map(([path9, warnings]) => ({ path: path9, warnings })).sort((a, b) => b.warnings - a.warnings);
7535
7535
  return {
7536
7536
  available: true,
7537
7537
  total_runs: sorted.length,
@@ -10102,10 +10102,10 @@ function slugify2(name) {
10102
10102
  return name.trim().toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
10103
10103
  }
10104
10104
  function readModulesDescriptor(dir) {
10105
- const path8 = join(dir, DESCRIPTOR_PATH2);
10106
- if (!exists(path8)) return { version: 1, modules: [] };
10105
+ const path9 = join(dir, DESCRIPTOR_PATH2);
10106
+ if (!exists(path9)) return { version: 1, modules: [] };
10107
10107
  try {
10108
- const parsed = parseYaml9(readFile(path8));
10108
+ const parsed = parseYaml9(readFile(path9));
10109
10109
  return { version: parsed.version ?? 1, modules: parsed.modules ?? [] };
10110
10110
  } catch {
10111
10111
  return { version: 1, modules: [] };
@@ -10485,7 +10485,7 @@ function sectionParagraph(md, title) {
10485
10485
  }
10486
10486
  return "";
10487
10487
  }
10488
- function parseCapsule(id, path8, md) {
10488
+ function parseCapsule(id, path9, md) {
10489
10489
  const { data } = matter3(md);
10490
10490
  const updatedAt = data.updated_at ? String(data.updated_at) : void 0;
10491
10491
  let ageDays = null;
@@ -10495,7 +10495,7 @@ function parseCapsule(id, path8, md) {
10495
10495
  }
10496
10496
  return {
10497
10497
  id,
10498
- path: path8,
10498
+ path: path9,
10499
10499
  system: data.system ? String(data.system) : id,
10500
10500
  owner: data.owner ? String(data.owner) : void 0,
10501
10501
  updatedAt,
@@ -10581,9 +10581,9 @@ function buildGraph(dir, config, opts = {}, now = /* @__PURE__ */ new Date()) {
10581
10581
  ];
10582
10582
  const presentLayers = [];
10583
10583
  for (const layer2 of layerDocs) {
10584
- const path8 = layer2.files.map((f) => `${KNOWLEDGE3}/${f}`).find((rel) => exists(join(dir, rel)));
10585
- if (path8) {
10586
- addNode({ id: layer2.id, type: layer2.type, label: layer2.label, path: path8 });
10584
+ const path9 = layer2.files.map((f) => `${KNOWLEDGE3}/${f}`).find((rel) => exists(join(dir, rel)));
10585
+ if (path9) {
10586
+ addNode({ id: layer2.id, type: layer2.type, label: layer2.label, path: path9 });
10587
10587
  presentLayers.push(layer2.id);
10588
10588
  }
10589
10589
  }
@@ -12119,10 +12119,10 @@ function resolveNextStep(dir, now = /* @__PURE__ */ new Date()) {
12119
12119
  const q = (rel) => analyzeKnowledgeArtifact(dir, rel);
12120
12120
  const resolveAgent = (agent) => {
12121
12121
  const file = agent.endsWith(".md") ? agent : `${agent}.md`;
12122
- const path8 = agentInstallPath(file);
12123
- const installed = isFile(join(dir, path8));
12122
+ const path9 = agentInstallPath(file);
12123
+ const installed = isFile(join(dir, path9));
12124
12124
  const group = agentGroupOf(file);
12125
- return { agentPath: path8, agentInstalled: installed, installCommand: installed ? void 0 : `kaddo add agents --group ${group}` };
12125
+ return { agentPath: path9, agentInstalled: installed, installCommand: installed ? void 0 : `kaddo add agents --group ${group}` };
12126
12126
  };
12127
12127
  const moduleRepo = isModule(config);
12128
12128
  const coreRepo = isCore(config);
@@ -18492,6 +18492,110 @@ async function runReady(id, opts = {}) {
18492
18492
  outro2(`Work Item ${wi.id} is ready.`);
18493
18493
  }
18494
18494
 
18495
+ // src/commands/admin.ts
18496
+ import path8 from "path";
18497
+ import { fileURLToPath as fileURLToPath2 } from "url";
18498
+ import net from "net";
18499
+ function isPortAvailable(port, host) {
18500
+ return new Promise((resolve) => {
18501
+ const server = net.createServer();
18502
+ server.once("error", () => resolve(false));
18503
+ server.once("listening", () => {
18504
+ server.close();
18505
+ resolve(true);
18506
+ });
18507
+ server.listen(port, host);
18508
+ });
18509
+ }
18510
+ function resolveStaticDir() {
18511
+ const __dirname = path8.dirname(fileURLToPath2(import.meta.url));
18512
+ const candidates = [
18513
+ path8.resolve(__dirname, "..", "..", "admin", "dist"),
18514
+ path8.resolve(__dirname, "..", "node_modules", "@kaddo", "admin", "dist")
18515
+ ];
18516
+ for (const c of candidates) {
18517
+ if (exists(join(c, "index.html"))) return c;
18518
+ }
18519
+ return null;
18520
+ }
18521
+ async function runAdmin(opts = {}) {
18522
+ const dir = cwd();
18523
+ const port = opts.port ?? 4173;
18524
+ const host = opts.host ?? "127.0.0.1";
18525
+ const config = loadConfig(dir);
18526
+ if (!config) {
18527
+ console.log("");
18528
+ console.log("Kaddo Admin could not start.");
18529
+ console.log("");
18530
+ console.log("No Kaddo project was detected in the current directory.");
18531
+ console.log("");
18532
+ console.log("Run:");
18533
+ console.log(" kaddo init");
18534
+ console.log("");
18535
+ console.log("or execute this command from a Kaddo project.");
18536
+ console.log("");
18537
+ process.exit(1);
18538
+ }
18539
+ const available = await isPortAvailable(port, host);
18540
+ if (!available) {
18541
+ console.log("");
18542
+ console.log(`Port ${port} is already in use.`);
18543
+ console.log("");
18544
+ console.log("Use:");
18545
+ console.log(` kaddo admin --port <port>`);
18546
+ console.log("");
18547
+ process.exit(1);
18548
+ }
18549
+ const staticDir = resolveStaticDir();
18550
+ if (!staticDir) {
18551
+ console.error("Admin frontend not built. Run `pnpm -r build` first.");
18552
+ process.exit(1);
18553
+ }
18554
+ const { createAdminServer, SQLiteAdminStorage } = await import("@kaddo/admin-server");
18555
+ const dbDir = join(dir, ".kaddo", "admin");
18556
+ ensureDir(dbDir);
18557
+ const dbPath = join(dbDir, "admin.db");
18558
+ const storage = new SQLiteAdminStorage(dbPath);
18559
+ await storage.initialize();
18560
+ const server = await createAdminServer({
18561
+ projectDir: dir,
18562
+ storage,
18563
+ staticDir,
18564
+ host,
18565
+ port
18566
+ });
18567
+ const address = await server.start();
18568
+ console.log("");
18569
+ console.log("Kaddo Admin");
18570
+ console.log("");
18571
+ console.log(`Project: ${config.project.name}`);
18572
+ console.log(`Mode: local`);
18573
+ console.log(`Address: ${address}`);
18574
+ console.log("");
18575
+ console.log(`Session: active`);
18576
+ console.log(`Storage: SQLite`);
18577
+ console.log(`Project source: Kaddo Core`);
18578
+ console.log("");
18579
+ console.log("Press Ctrl+C to stop.");
18580
+ console.log("");
18581
+ if (!opts.noOpen) {
18582
+ try {
18583
+ const { default: open } = await import("open");
18584
+ await open(address);
18585
+ } catch {
18586
+ }
18587
+ }
18588
+ const shutdown = async () => {
18589
+ console.log("");
18590
+ console.log("Shutting down...");
18591
+ await server.stop();
18592
+ console.log("Kaddo Admin stopped.");
18593
+ process.exit(0);
18594
+ };
18595
+ process.on("SIGINT", shutdown);
18596
+ process.on("SIGTERM", shutdown);
18597
+ }
18598
+
18495
18599
  // src/index.ts
18496
18600
  var require2 = createRequire(import.meta.url);
18497
18601
  var { version } = require2("../package.json");
@@ -18516,8 +18620,8 @@ var capsuleCmd = program.command("capsule").description("Export this project as
18516
18620
  capsuleCmd.command("export").description("Write a Knowledge Capsule about this project to .kaddo/exports/").option("--scope <scope>", 'Export scope: "system" includes all mapped modules').option("--module <id>", "Export a capsule for a specific mapped module").action((opts) => {
18517
18621
  runCapsuleExport(opts);
18518
18622
  });
18519
- capsuleCmd.command("add <path>").description("Register an external Knowledge Capsule as project context (.kaddo/external.yml)").action((path8) => {
18520
- runCapsuleAdd(path8);
18623
+ capsuleCmd.command("add <path>").description("Register an external Knowledge Capsule as project context (.kaddo/external.yml)").action((path9) => {
18624
+ runCapsuleAdd(path9);
18521
18625
  });
18522
18626
  var graphCmd = program.command("graph").description("Export the lightweight, file-based knowledge graph of the project");
18523
18627
  graphCmd.command("export").description("Write the knowledge graph to .kaddo/graph.json and .kaddo/graph.mmd").option("--scope <scope>", "Graph scope: active (default) or all").option("--format <format>", "Output format: json, mermaid (default: both)").action((opts) => {
@@ -18635,6 +18739,9 @@ modulesCmd.command("validate").description("Validate registered modules against
18635
18739
  program.command("add [module]").description("Install an optional Kaddo module (adr, incident, rfc, migration, legacy, agents, skills, standards, security, stack, git-strategy)").option("--all", "For `add agents` / `add skills`: install every item (not just the recommended set)").option("--group <name>", "For `add agents`: business|product|tech|delivery|utilities. For `add skills`: delivery|tech|integration").action((moduleName, opts) => {
18636
18740
  runAdd(moduleName ?? "", { all: opts.all, group: opts.group });
18637
18741
  });
18742
+ program.command("admin").description("Start Kaddo Admin \u2014 a local web interface for the project knowledge").option("--port <port>", "Server port (default: 4173)", parseInt).option("--host <host>", "Server host (default: 127.0.0.1)").option("--no-open", "Do not open the browser automatically").action(async (opts) => {
18743
+ await runAdmin({ port: opts.port, host: opts.host, noOpen: opts.open === false });
18744
+ });
18638
18745
  program.parseAsync(process.argv).catch((err) => {
18639
18746
  console.error(err);
18640
18747
  process.exit(1);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kaddo/cli",
3
- "version": "3.68.0",
3
+ "version": "3.69.0",
4
4
  "description": "Knowledge Driven Development toolkit",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -20,6 +20,10 @@
20
20
  ],
21
21
  "type": "module",
22
22
  "main": "./dist/index.js",
23
+ "exports": {
24
+ ".": "./dist/index.js",
25
+ "./core": "./dist/core.js"
26
+ },
23
27
  "bin": {
24
28
  "kaddo": "./dist/index.js"
25
29
  },
@@ -45,7 +49,8 @@
45
49
  "gray-matter": "^4.0.3",
46
50
  "minimatch": "^10.2.5",
47
51
  "yaml": "^2.4.2",
48
- "zod": "^3.23.8"
52
+ "zod": "^3.23.8",
53
+ "open": "^10.1.0"
49
54
  },
50
55
  "devDependencies": {
51
56
  "@types/node": "^20.14.0",