@devflow-tools/cli 0.15.0 → 0.16.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 (95) hide show
  1. package/dist/commands/benchmark-cmd.d.ts +17 -4
  2. package/dist/commands/benchmark-cmd.d.ts.map +1 -1
  3. package/dist/commands/benchmark-cmd.js +71 -14
  4. package/dist/commands/benchmark-cmd.js.map +1 -1
  5. package/dist/commands/connect.d.ts +0 -1
  6. package/dist/commands/connect.d.ts.map +1 -1
  7. package/dist/commands/connect.js +4 -10
  8. package/dist/commands/connect.js.map +1 -1
  9. package/dist/commands/context.d.ts +2 -2
  10. package/dist/commands/context.d.ts.map +1 -1
  11. package/dist/commands/context.js +5 -3
  12. package/dist/commands/context.js.map +1 -1
  13. package/dist/commands/db.d.ts +25 -0
  14. package/dist/commands/db.d.ts.map +1 -0
  15. package/dist/commands/db.js +258 -0
  16. package/dist/commands/db.js.map +1 -0
  17. package/dist/commands/docs.d.ts +20 -0
  18. package/dist/commands/docs.d.ts.map +1 -0
  19. package/dist/commands/docs.js +37 -0
  20. package/dist/commands/docs.js.map +1 -0
  21. package/dist/commands/doctor.d.ts +59 -1
  22. package/dist/commands/doctor.d.ts.map +1 -1
  23. package/dist/commands/doctor.js +3912 -50
  24. package/dist/commands/doctor.js.map +1 -1
  25. package/dist/commands/index-cmd.d.ts +1 -0
  26. package/dist/commands/index-cmd.d.ts.map +1 -1
  27. package/dist/commands/index-cmd.js +7 -0
  28. package/dist/commands/index-cmd.js.map +1 -1
  29. package/dist/commands/init.d.ts.map +1 -1
  30. package/dist/commands/init.js +3 -6
  31. package/dist/commands/init.js.map +1 -1
  32. package/dist/commands/knowledge.d.ts +2 -1
  33. package/dist/commands/knowledge.d.ts.map +1 -1
  34. package/dist/commands/knowledge.js +11 -8
  35. package/dist/commands/knowledge.js.map +1 -1
  36. package/dist/commands/memory.d.ts +17 -1
  37. package/dist/commands/memory.d.ts.map +1 -1
  38. package/dist/commands/memory.js +22 -3
  39. package/dist/commands/memory.js.map +1 -1
  40. package/dist/commands/plugin-loader.d.ts +1 -1
  41. package/dist/commands/plugin-loader.d.ts.map +1 -1
  42. package/dist/commands/plugin-loader.js +1 -1
  43. package/dist/commands/plugin-loader.js.map +1 -1
  44. package/dist/commands/plugin-memory-hints.d.ts +23 -0
  45. package/dist/commands/plugin-memory-hints.d.ts.map +1 -0
  46. package/dist/commands/plugin-memory-hints.js +58 -0
  47. package/dist/commands/plugin-memory-hints.js.map +1 -0
  48. package/dist/commands/reset.d.ts +32 -0
  49. package/dist/commands/reset.d.ts.map +1 -0
  50. package/dist/commands/reset.js +316 -0
  51. package/dist/commands/reset.js.map +1 -0
  52. package/dist/commands/session.d.ts.map +1 -1
  53. package/dist/commands/session.js +2 -1
  54. package/dist/commands/session.js.map +1 -1
  55. package/dist/commands/status.d.ts.map +1 -1
  56. package/dist/commands/status.js +33 -6
  57. package/dist/commands/status.js.map +1 -1
  58. package/dist/index.js +225 -96
  59. package/dist/index.js.map +1 -1
  60. package/dist/lib/plugin-setup.d.ts.map +1 -1
  61. package/dist/lib/plugin-setup.js +37 -2
  62. package/dist/lib/plugin-setup.js.map +1 -1
  63. package/dist/plugin-files/.claude-plugin/plugin.json +1 -1
  64. package/dist/plugin-files/dist/command-registry.json +34 -36
  65. package/dist/plugin-files/dist/hooks/enforcer-summary.js +6 -0
  66. package/dist/plugin-files/dist/hooks/hook-client.js +6 -0
  67. package/dist/plugin-files/dist/hooks/hook-daemon.js +14 -0
  68. package/dist/plugin-files/dist/hooks/post-tool-use-failure.js +2 -0
  69. package/dist/plugin-files/dist/hooks/post-tool-use.js +3 -0
  70. package/dist/plugin-files/dist/hooks/pre-compact.js +3 -0
  71. package/dist/plugin-files/dist/hooks/pre-tool-use.js +2 -0
  72. package/dist/plugin-files/dist/hooks/server-bootstrap.js +109 -0
  73. package/dist/plugin-files/dist/hooks/session-end.js +2 -0
  74. package/dist/plugin-files/dist/hooks/stop.js +2 -0
  75. package/dist/plugin-files/dist/hooks/user-prompt-submit.js +2 -0
  76. package/dist/plugin-files/dist/skills/devflow:graphql/SKILL.md +2 -4
  77. package/dist/plugin-files/dist/skills/devflow:nest/SKILL.md +4 -4
  78. package/dist/plugin-files/dist/skills/devflow:nextjs/SKILL.md +4 -4
  79. package/dist/plugin-files/dist/skills/devflow:react/SKILL.md +6 -8
  80. package/dist/plugin-files/dist/skills/devflow:tailwind/SKILL.md +4 -2
  81. package/dist/plugin-files/dist/skills/devflow:vue/SKILL.md +2 -4
  82. package/dist/plugin-files/hooks/post-tool-use +2 -2
  83. package/dist/plugin-files/hooks/post-tool-use-failure +2 -2
  84. package/dist/plugin-files/hooks/pre-compact +2 -2
  85. package/dist/plugin-files/hooks/pre-tool-use +4 -4
  86. package/dist/plugin-files/hooks/session-end +2 -2
  87. package/dist/plugin-files/hooks/session-start +160 -77
  88. package/dist/plugin-files/hooks/stop +2 -8
  89. package/dist/plugin-files/hooks/user-prompt-submit +2 -2
  90. package/dist/plugin-files/package.json +13 -2
  91. package/package.json +27 -27
  92. package/dist/commands/dashboard.d.ts +0 -3
  93. package/dist/commands/dashboard.d.ts.map +0 -1
  94. package/dist/commands/dashboard.js +0 -10
  95. package/dist/commands/dashboard.js.map +0 -1
package/dist/index.js CHANGED
@@ -4,31 +4,6 @@ import chalk from "chalk";
4
4
  import fs from "fs";
5
5
  import path from "path";
6
6
  import { detectMode } from "./mode.js";
7
- import { initProject } from "./commands/init.js";
8
- import { guidePluginInstallation, installPluginsFromList } from "./commands/plugin-guide.js";
9
- import { connectAgent, getAvailableAgents } from "./commands/connect.js";
10
- import { getIndexStatus } from "./commands/index-cmd.js";
11
- import { getGraph } from "./commands/graph.js";
12
- import { getContext, getTaskContext } from "./commands/context.js";
13
- import { listWorkflows, runWorkflow, getWorkflowStatus, getWorkflowRuns, } from "./commands/workflow.js";
14
- import { showMemory, setMemory, reviewCandidates } from "./commands/memory.js";
15
- import { searchKnowledge } from "./commands/knowledge.js";
16
- import { listSkills, searchSkills, installSkill, uninstallSkill } from "./commands/skill.js";
17
- import { runDoctor, runDoctorAudit, runDoctorAuditFix, runDoctorViolations, runDoctorReceipts } from "./commands/doctor.js";
18
- import { generateToken } from "./commands/session.js";
19
- import { runBenchmark } from "./commands/benchmark-cmd.js";
20
- import { runReview } from "./commands/review.js";
21
- import { startServer, stopServer, serverStatus } from "./commands/server.js";
22
- import { startAll } from "./commands/start.js";
23
- import { stopAll } from "./commands/stop.js";
24
- import { showStatus } from "./commands/status.js";
25
- import { setupCommand } from "./commands/setup.js";
26
- import { pluginListCommand } from "./commands/plugin/list.js";
27
- import { pluginSearchCommand } from "./commands/plugin/search.js";
28
- import { pluginInstallCommand } from "./commands/plugin/install.js";
29
- import { pluginUninstallCommand } from "./commands/plugin/uninstall.js";
30
- import { dashboardCommand } from "./commands/dashboard.js";
31
- import { KnowledgeEngine } from "@devflow-tools/knowledge-engine";
32
7
  import { createRequire } from "module";
33
8
  const require = createRequire(import.meta.url);
34
9
  // Read version from package.json at runtime
@@ -61,6 +36,7 @@ program
61
36
  .option("--report", "Output onboarding markdown report to stdout")
62
37
  .option("--json", "Output onboarding pack as JSON to stdout")
63
38
  .option("--plugins <names>", "Comma-separated list of plugins to install (non-interactive)")
39
+ .option("--with-plugin <names>", "Interactively review optional memory hints from installed plugins")
64
40
  .option("--no-plugins", "Skip plugin installation guide")
65
41
  .action(async (opts) => {
66
42
  const root = process.cwd();
@@ -78,12 +54,12 @@ program
78
54
  }
79
55
  const mode = detectMode(root);
80
56
  console.error(chalk.blue(`DevFlow init — mode: ${mode}`));
57
+ const { initProject, renderInitReport } = await import("./commands/init.js");
81
58
  const result = await initProject(root, { force: opts.force });
82
59
  if (opts.json && result.onboardingPack) {
83
60
  console.log(JSON.stringify(result.onboardingPack, null, 2));
84
61
  }
85
62
  else if (opts.report && result.onboardingPack) {
86
- const { renderInitReport } = await import("./commands/init.js");
87
63
  console.log(renderInitReport(result.onboardingPack));
88
64
  }
89
65
  else {
@@ -116,27 +92,66 @@ program
116
92
  if (result.pluginDeployed && result.pluginEnabled && result.mcpConfigured) {
117
93
  console.log(chalk.green("\nDevFlow is ready! Run `claude` to start."));
118
94
  }
95
+ if (typeof opts.withPlugin === "string") {
96
+ const { reviewPluginMemoryHints } = await import("./commands/plugin-memory-hints.js");
97
+ const hints = await reviewPluginMemoryHints(root, opts.withPlugin);
98
+ console.log(chalk.dim(`Plugin memory hints: ${hints.selected}/${hints.available} selected`));
99
+ }
119
100
  // ── Plugin installation guide ──
120
101
  if (typeof opts.plugins === "string") {
121
102
  // Non-interactive: --plugins <names>
103
+ const { installPluginsFromList } = await import("./commands/plugin-guide.js");
122
104
  await installPluginsFromList(opts.plugins);
123
105
  }
124
106
  else if (opts.plugins !== false) {
125
107
  // Interactive: no --plugins flag and not --no-plugins
108
+ const { guidePluginInstallation } = await import("./commands/plugin-guide.js");
126
109
  await guidePluginInstallation(root);
127
110
  }
128
111
  }
129
112
  });
113
+ // --- reset ---
114
+ program
115
+ .command("reset")
116
+ .description("Reset generated DevFlow project data")
117
+ .requiredOption("--scope <scope>", "memory | knowledge | codegraph | all")
118
+ .option("--backup-to <dir>", "Back up selected data before resetting")
119
+ .option("--force", "Reset without creating a backup")
120
+ .option("--project <path>", "Project directory", process.cwd())
121
+ .action(async (opts) => {
122
+ const { executeResetCommand } = await import("./commands/reset.js");
123
+ const succeeded = executeResetCommand(opts, {}, {
124
+ log: (message) => console.log(message),
125
+ error: (message) => console.error(chalk.red(message)),
126
+ });
127
+ if (!succeeded)
128
+ process.exitCode = 1;
129
+ });
130
+ // --- db ---
131
+ const dbCmd = program
132
+ .command("db")
133
+ .description("Manage DevFlow databases");
134
+ dbCmd
135
+ .command("consolidate")
136
+ .description("Merge legacy project databases into the global database")
137
+ .option("--project <path>", "Project directory", process.cwd())
138
+ .option("--dry-run", "Report rows and conflicts without writing")
139
+ .action(async (opts) => {
140
+ const { consolidateDatabases, formatConsolidateResult } = await import("./commands/db.js");
141
+ const result = consolidateDatabases(opts);
142
+ for (const line of formatConsolidateResult(result))
143
+ console.log(line);
144
+ });
130
145
  // --- connect ---
131
146
  program
132
147
  .command("connect [agent]")
133
- .description("Configure MCP connection for AI coding agents")
148
+ .description("Configure the Claude Code MCP connection")
134
149
  .option("--command <cmd>", "MCP server command", "devflow-mcp")
135
- .option("--sse <url>", "SSE server URL (instead of stdio)")
136
150
  .action(async (agent, opts) => {
137
151
  const root = process.cwd();
138
152
  const mode = detectMode(root);
139
153
  console.log(chalk.blue(`DevFlow connect — mode: ${mode}`));
154
+ const { connectAgent, getAvailableAgents } = await import("./commands/connect.js");
140
155
  if (agent) {
141
156
  const available = getAvailableAgents();
142
157
  if (!available.includes(agent)) {
@@ -149,7 +164,6 @@ program
149
164
  const results = await connectAgent({
150
165
  agent: agent,
151
166
  command: opts.command,
152
- sseUrl: opts.sse,
153
167
  });
154
168
  for (const r of results) {
155
169
  console.log(chalk.green(`✓ ${r}`));
@@ -164,9 +178,13 @@ program
164
178
  program
165
179
  .command("index")
166
180
  .description("Show index status")
181
+ .option("--backfill-vectors", "Reconcile the index and wait for symbol vectors")
167
182
  .option("--watch", "Start file watcher for hot updates (stub)")
168
183
  .action(async (opts) => {
169
- const status = await getIndexStatus(program.opts().local);
184
+ const { getIndexStatus, refreshIndex } = await import("./commands/index-cmd.js");
185
+ const status = opts.backfillVectors
186
+ ? await refreshIndex(program.opts().local)
187
+ : await getIndexStatus(program.opts().local);
170
188
  console.log(chalk.blue("Index Status"));
171
189
  console.log(` Files: ${status.totalFiles}`);
172
190
  console.log(` Symbols: ${status.totalSymbols}`);
@@ -181,6 +199,7 @@ program
181
199
  .description("Show dependency graph")
182
200
  .option("--depth <n>", "Expansion depth", "2")
183
201
  .action(async (target, opts) => {
202
+ const { getGraph } = await import("./commands/graph.js");
184
203
  const graph = await getGraph({ target, depth: parseInt(opts.depth, 10), skipServer: program.opts().local });
185
204
  console.log(chalk.blue("Dependency Graph"));
186
205
  console.log(` Nodes: ${graph.nodes.length}`);
@@ -196,6 +215,7 @@ program
196
215
  .option("--why", "Show reasoning for file selection")
197
216
  .action(async (query, opts) => {
198
217
  if (opts.task) {
218
+ const { getTaskContext } = await import("./commands/context.js");
199
219
  const result = await getTaskContext({
200
220
  query,
201
221
  mode: opts.mode,
@@ -211,6 +231,7 @@ program
211
231
  }, null, 2));
212
232
  }
213
233
  else {
234
+ const { getContext } = await import("./commands/context.js");
214
235
  const result = await getContext({
215
236
  query,
216
237
  mode: opts.mode,
@@ -231,6 +252,7 @@ workflowCmd
231
252
  .command("list")
232
253
  .description("List available workflows")
233
254
  .action(async () => {
255
+ const { listWorkflows } = await import("./commands/workflow.js");
234
256
  const workflows = await listWorkflows(program.opts().local);
235
257
  if (workflows.length === 0) {
236
258
  console.log(chalk.dim("No workflows registered."));
@@ -244,6 +266,7 @@ workflowCmd
244
266
  .command("run <type> [input]")
245
267
  .description("Run a workflow")
246
268
  .action(async (type, input) => {
269
+ const { runWorkflow } = await import("./commands/workflow.js");
247
270
  const result = await runWorkflow(type, { input: input ?? "" }, program.opts().local);
248
271
  console.log(`Run: ${result.runId}`);
249
272
  console.log(`Status: ${result.status}`);
@@ -253,6 +276,7 @@ workflowCmd
253
276
  .command("status")
254
277
  .description("Show running workflows")
255
278
  .action(async () => {
279
+ const { getWorkflowStatus } = await import("./commands/workflow.js");
256
280
  const runs = await getWorkflowStatus(program.opts().local);
257
281
  console.log(`${runs.length} run(s)`);
258
282
  for (const r of runs) {
@@ -263,6 +287,7 @@ workflowCmd
263
287
  .command("runs")
264
288
  .description("Show workflow history")
265
289
  .action(async () => {
290
+ const { getWorkflowRuns } = await import("./commands/workflow.js");
266
291
  const runs = await getWorkflowRuns(program.opts().local);
267
292
  if (runs.length === 0) {
268
293
  console.log(chalk.dim("No runs yet."));
@@ -280,14 +305,40 @@ const memoryCmd = program
280
305
  memoryCmd
281
306
  .command("show")
282
307
  .description("Show current project memory")
283
- .action(async () => {
284
- const mem = await showMemory(program.opts().local);
308
+ .option("--source <source>", "Filter memories by source")
309
+ .action(async (options) => {
310
+ const { showMemory } = await import("./commands/memory.js");
311
+ const mem = await showMemory(program.opts().local, options.source);
285
312
  console.log(JSON.stringify(mem, null, 2));
286
313
  });
314
+ memoryCmd.command("list").description("List project memories")
315
+ .option("--source <source>", "Filter memories by source")
316
+ .action(async (options) => {
317
+ const { showMemory } = await import("./commands/memory.js");
318
+ console.log(JSON.stringify(await showMemory(program.opts().local, options.source), null, 2));
319
+ });
320
+ memoryCmd
321
+ .command("query [query]")
322
+ .description("Retrieve ranked project memory with a token budget")
323
+ .option("--purpose <purpose>", "Retrieval purpose", "task_context")
324
+ .option("--budget-tokens <count>", "Maximum response tokens", "2000")
325
+ .option("--scope <scope>", "Memory scope to include (repeatable)", (value, previous) => [...previous, value], [])
326
+ .action(async (query, options) => {
327
+ const { queryMemory } = await import("./commands/memory.js");
328
+ const result = await queryMemory({
329
+ query,
330
+ purpose: options.purpose,
331
+ budgetTokens: Number.parseInt(options.budgetTokens, 10),
332
+ scopes: options.scope.length > 0 ? options.scope : undefined,
333
+ skipServer: program.opts().local,
334
+ });
335
+ console.log(JSON.stringify(result, null, 2));
336
+ });
287
337
  memoryCmd
288
338
  .command("set <key> <value>")
289
339
  .description("Set a memory key")
290
340
  .action(async (key, value) => {
341
+ const { setMemory } = await import("./commands/memory.js");
291
342
  await setMemory(key, value, program.opts().local);
292
343
  console.log(chalk.green(`Memory set: ${key} = ${value}`));
293
344
  });
@@ -295,28 +346,54 @@ memoryCmd
295
346
  .command("review")
296
347
  .description("Review memory candidates")
297
348
  .action(async () => {
349
+ const { reviewCandidates } = await import("./commands/memory.js");
298
350
  const candidates = await reviewCandidates(program.opts().local);
299
351
  console.log(JSON.stringify(candidates, null, 2));
300
352
  });
353
+ memoryCmd
354
+ .command("backfill-obs-vectors")
355
+ .description("Backfill missing observation vectors")
356
+ .option("--batch-size <count>", "Embedding batch size", "32")
357
+ .action(async (options) => {
358
+ const { backfillObservationVectors } = await import("./commands/memory.js");
359
+ const result = await backfillObservationVectors({
360
+ batchSize: Number.parseInt(options.batchSize, 10),
361
+ onProgress: ({ processed, remaining }) => {
362
+ console.log(` vectors: ${processed} processed, ${remaining} remaining`);
363
+ },
364
+ });
365
+ console.log(chalk.green(`Observation vectors ready: ${result.processed} added, ${result.remaining} remaining`));
366
+ });
301
367
  // --- knowledge ---
302
368
  const knowledgeCmd = program
303
369
  .command("knowledge <query>")
304
370
  .description("Search knowledge base")
305
371
  .action(async (query) => {
306
- const results = await searchKnowledge(query, undefined, program.opts().local);
372
+ const { queryKnowledge } = await import("./commands/knowledge.js");
373
+ const result = await queryKnowledge(query, undefined, undefined, program.opts().local);
374
+ const results = result.results;
307
375
  console.log(chalk.blue(`Knowledge: "${query}"`));
308
376
  console.log(` Results: ${results.length}`);
309
377
  for (const r of results.slice(0, 5)) {
310
378
  console.log(` — ${r.title}`);
311
379
  }
312
380
  });
313
- // docs sync
314
- program
315
- .command("docs sync [plugin-name]")
381
+ const docsCmd = program
382
+ .command("docs")
383
+ .description("Documentation index management");
384
+ docsCmd
385
+ .command("sync [plugin-name]")
316
386
  .description("Sync documentation for plugins")
317
387
  .action(async (pluginName) => {
318
388
  console.log(chalk.blue(`◉ Syncing docs${pluginName ? ` for ${pluginName} plugin` : ""}`));
319
- const engine = new KnowledgeEngine({ projectRoot: process.cwd() });
389
+ const [{ KnowledgeEngine }, { EmbeddingProvider }] = await Promise.all([
390
+ import("@devflow-tools/knowledge-engine"),
391
+ import("@devflow-tools/memory-engine"),
392
+ ]);
393
+ const engine = new KnowledgeEngine({
394
+ projectRoot: process.cwd(),
395
+ embedder: new EmbeddingProvider(),
396
+ });
320
397
  if (pluginName) {
321
398
  const results = await engine.syncDocs(pluginName);
322
399
  for (const r of results) {
@@ -345,6 +422,43 @@ program
345
422
  console.log(chalk.green("\n All docs synced."));
346
423
  }
347
424
  });
425
+ docsCmd
426
+ .command("backfill-vectors")
427
+ .description("Backfill missing knowledge chunk vectors")
428
+ .option("--source <name>", "Only backfill one knowledge source")
429
+ .option("--batch-size <count>", "Embedding batch size", "32")
430
+ .action(async (options) => {
431
+ const { backfillKnowledgeVectors } = await import("./commands/docs.js");
432
+ const result = await backfillKnowledgeVectors({
433
+ source: options.source,
434
+ batchSize: Number.parseInt(options.batchSize, 10),
435
+ onProgress: ({ processed, remaining }) => {
436
+ console.log(` vectors: ${processed} processed, ${remaining} remaining`);
437
+ },
438
+ });
439
+ console.log(chalk.green(`Knowledge vectors ready: ${result.processed} added, ${result.remaining} remaining`));
440
+ });
441
+ docsCmd
442
+ .command("resync [plugin-name]")
443
+ .description("Rebuild documentation chunks before vector backfill")
444
+ .requiredOption("--with-headings", "Use heading-aware 500-3000 character chunks")
445
+ .action(async (pluginName, options) => {
446
+ const { resyncKnowledgeDocs } = await import("./commands/docs.js");
447
+ console.log(chalk.blue(`Resyncing docs${pluginName ? ` for ${pluginName}` : ""} with headings`));
448
+ const results = await resyncKnowledgeDocs({
449
+ source: pluginName,
450
+ withHeadings: options.withHeadings,
451
+ });
452
+ for (const result of results) {
453
+ if (result.added > 0) {
454
+ console.log(` ${chalk.green("✓")} ${result.source} → ${result.added} chunks`);
455
+ }
456
+ else {
457
+ console.log(` ${chalk.red("✗")} ${result.source} — ${result.errors.join(", ") || "no content"}`);
458
+ }
459
+ }
460
+ console.log(chalk.green("Docs resynced. Run `devflow docs backfill-vectors` to rebuild vectors."));
461
+ });
348
462
  // --- skill ---
349
463
  const skillCmd = program
350
464
  .command("skill")
@@ -353,6 +467,7 @@ skillCmd
353
467
  .command("list")
354
468
  .description("List installed skills")
355
469
  .action(async () => {
470
+ const { listSkills } = await import("./commands/skill.js");
356
471
  const skills = await listSkills(program.opts().local);
357
472
  if (skills.length === 0) {
358
473
  console.log(chalk.dim("No skills installed. Use 'devflow skill search' to find plugins."));
@@ -366,6 +481,7 @@ skillCmd
366
481
  .command("search <query>")
367
482
  .description("Search available plugins")
368
483
  .action(async (query) => {
484
+ const { searchSkills } = await import("./commands/skill.js");
369
485
  const results = await searchSkills(query, program.opts().local);
370
486
  console.log(chalk.blue(`Search: "${query}"`));
371
487
  if (results.length === 0) {
@@ -381,6 +497,7 @@ skillCmd
381
497
  .description("Install a plugin/skill")
382
498
  .action(async (name) => {
383
499
  try {
500
+ const { installSkill } = await import("./commands/skill.js");
384
501
  const result = await installSkill(name, process.cwd(), program.opts().local);
385
502
  console.log(chalk.green(`✓ Installed @devflow-tools/plugin-${result.name}@${result.version}`));
386
503
  if (result.templates.length > 0) {
@@ -397,6 +514,7 @@ skillCmd
397
514
  .description("Uninstall a plugin/skill")
398
515
  .action(async (name) => {
399
516
  try {
517
+ const { uninstallSkill } = await import("./commands/skill.js");
400
518
  await uninstallSkill(name, process.cwd(), program.opts().local);
401
519
  console.log(chalk.green(`✓ Uninstalled ${name}`));
402
520
  }
@@ -410,12 +528,15 @@ program
410
528
  .command("doctor")
411
529
  .description("Run project health check")
412
530
  .option("--json", "Output as JSON")
531
+ .option("--strict", "Exit with status 1 when any health section has warnings or errors")
532
+ .option("--project <path>", "Project directory", process.cwd())
413
533
  .option("--audit", "Verify audit chain integrity")
414
534
  .option("--audit-fix", "Rebuild audit chain signatures")
415
535
  .option("--violations", "Show violation records")
416
536
  .option("--last <period>", "Filter violations by time (e.g. 7d, 24h)")
417
537
  .option("--receipts", "Show current session receipt status")
418
538
  .action(async (opts) => {
539
+ const { runDoctorCommand, runDoctorAudit, runDoctorAuditFix, runDoctorViolations, runDoctorReceipts, } = await import("./commands/doctor.js");
419
540
  if (opts.audit) {
420
541
  const report = await runDoctorAudit();
421
542
  console.log(opts.json ? JSON.stringify(report) : `Audit chain: ${report.valid ? "VALID" : `BROKEN at seq ${report.brokenAt}`} (${report.entryCount} entries)`);
@@ -444,49 +565,12 @@ program
444
565
  }
445
566
  return;
446
567
  }
447
- // Default: full health report
448
- const report = await runDoctor();
449
- if (opts.json) {
450
- console.log(JSON.stringify(report));
451
- return;
452
- }
453
- console.log(chalk.blue(`DevFlow Doctor v${pkgVersion}\n`));
454
- console.log(chalk.bold("◉ Index Status"));
455
- console.log(` Files ${report.index.totalFiles.toLocaleString()}`);
456
- console.log(` Symbols ${report.index.totalSymbols.toLocaleString()}`);
457
- console.log(` Graph (${report.graph.edges.toLocaleString()} edges)`);
458
- console.log(` Status ${report.index.indexing ? "indexing" : "idle"}`);
459
- console.log();
460
- console.log(chalk.bold("◉ Memory"));
461
- console.log(` Project ${report.memory.projectReady ? "ready" : "not set"}`);
462
- console.log(` Preferences ${report.memory.userPrefs} set`);
463
- console.log();
464
- console.log(chalk.bold("◉ Knowledge"));
465
- console.log(` Sources ${report.knowledge.sources}`);
466
- console.log();
467
- console.log(chalk.bold("◉ Server"));
468
- if (report.server.running) {
469
- console.log(` ${chalk.green("✔")} Running on http://localhost:13337`);
470
- }
471
- else {
472
- console.log(` ${chalk.yellow("○")} Not running — run \`devflow server start\` for telemetry`);
473
- }
474
- console.log();
475
- console.log(chalk.bold("◉ Plugins"));
476
- if (report.plugins.installed === 0) {
477
- console.log(` ${chalk.dim("No plugins installed")}`);
478
- }
479
- else {
480
- for (const name of report.plugins.names) {
481
- console.log(` ${name}`);
482
- }
483
- }
484
- console.log();
485
- console.log(chalk.bold("◉ Workflows"));
486
- console.log(` Registered ${report.workflows.registered}`);
487
- console.log();
488
- const scoreColor = report.readyScore >= 70 ? chalk.green : report.readyScore >= 40 ? chalk.yellow : chalk.red;
489
- console.log(`AI Ready: ${scoreColor(report.readyScore + "%")}`);
568
+ const exitCode = await runDoctorCommand({
569
+ project: opts.project,
570
+ json: opts.json,
571
+ strict: opts.strict,
572
+ });
573
+ process.exitCode = exitCode;
490
574
  });
491
575
  // --- session ---
492
576
  program
@@ -494,21 +578,43 @@ program
494
578
  .description("Generate a session token for MCP Gateway authentication")
495
579
  .option("--expires <seconds>", "Token TTL in seconds", "3600")
496
580
  .action(async (opts) => {
581
+ const { generateToken } = await import("./commands/session.js");
497
582
  const result = await generateToken(process.cwd(), parseInt(opts.expires, 10));
498
583
  console.log(JSON.stringify(result, null, 2));
499
584
  });
500
585
  // --- benchmark ---
501
- program
502
- .command("benchmark [target]")
503
- .description("Run benchmark on engines")
504
- .option("--iterations <n>", "Number of iterations", "5")
505
- .option("--output <format>", "json | text", "text")
506
- .action(async (target, opts) => {
507
- const output = await runBenchmark(target ?? "all", {
508
- iterations: parseInt(opts.iterations, 10),
586
+ const benchmarkCmd = program
587
+ .command("benchmark")
588
+ .description("Run and inspect reproducible A/B benchmarks");
589
+ benchmarkCmd
590
+ .command("run")
591
+ .description("Run a benchmark suite and persist the report")
592
+ .option("--suite <id>", "Benchmark suite", "default")
593
+ .option("--project <root>", "Initialized project root", process.cwd())
594
+ .option("--rounds <n>", "Rounds per task", "1")
595
+ .option("--output <format>", "text | json", "text")
596
+ .action(async (opts) => {
597
+ const { runBenchmarkCommand } = await import("./commands/benchmark-cmd.js");
598
+ console.log(await runBenchmarkCommand({
599
+ projectRoot: opts.project,
600
+ suite: opts.suite,
601
+ rounds: parseInt(opts.rounds, 10),
509
602
  output: opts.output,
510
- });
511
- console.log(output);
603
+ }));
604
+ });
605
+ benchmarkCmd
606
+ .command("report")
607
+ .description("Render a persisted benchmark report")
608
+ .option("--run-id <id>", "Specific report; defaults to latest")
609
+ .option("--baseline <id>", "Prior report used for regression comparison")
610
+ .option("--output <format>", "text | json | markdown", "text")
611
+ .action(async (opts) => {
612
+ const { reportBenchmarkCommand } = await import("./commands/benchmark-cmd.js");
613
+ console.log(await reportBenchmarkCommand({
614
+ runId: opts.runId,
615
+ baselineRunId: opts.baseline,
616
+ output: opts.output,
617
+ }));
512
618
  });
513
619
  // --- review ---
514
620
  program
@@ -516,6 +622,7 @@ program
516
622
  .description("Review a PR or current branch diff")
517
623
  .option("--agent <agent>", "AI agent to use", "claude")
518
624
  .action(async (prUrl, opts) => {
625
+ const { runReview } = await import("./commands/review.js");
519
626
  const output = await runReview({ prUrl, agent: opts.agent });
520
627
  console.log(output);
521
628
  });
@@ -529,6 +636,7 @@ serverCmd
529
636
  .option("--port <n>", "Port number", "13337")
530
637
  .action(async (opts) => {
531
638
  console.log(chalk.blue("Starting DevFlow server..."));
639
+ const { startServer } = await import("./commands/server.js");
532
640
  const result = await startServer({ port: parseInt(opts.port, 10) });
533
641
  console.log(chalk.green(`Server started (pid: ${result.pid}) on port ${opts.port}`));
534
642
  });
@@ -536,6 +644,7 @@ serverCmd
536
644
  .command("stop")
537
645
  .description("Stop the DevFlow REST server")
538
646
  .action(async () => {
647
+ const { stopServer } = await import("./commands/server.js");
539
648
  const ok = await stopServer();
540
649
  if (ok)
541
650
  console.log(chalk.green("Server stopped"));
@@ -546,6 +655,7 @@ serverCmd
546
655
  .command("status")
547
656
  .description("Show server status")
548
657
  .action(async () => {
658
+ const { serverStatus } = await import("./commands/server.js");
549
659
  const status = await serverStatus();
550
660
  if (status.running)
551
661
  console.log(chalk.green(`Running (pid: ${status.pid})`));
@@ -553,7 +663,14 @@ serverCmd
553
663
  console.log(chalk.yellow("Not running"));
554
664
  });
555
665
  // --- dashboard ---
556
- program.addCommand(dashboardCommand);
666
+ program
667
+ .command("dashboard")
668
+ .description("Open DevFlow Dashboard")
669
+ .action(() => {
670
+ console.log(chalk.blue("The Dashboard is served by the DevFlow server."));
671
+ console.log(chalk.dim("Run: devflow start"));
672
+ console.log(chalk.dim("Then open: http://localhost:13337"));
673
+ });
557
674
  // --- start ---
558
675
  program
559
676
  .command("start")
@@ -561,6 +678,7 @@ program
561
678
  .option("--port <n>", "Server port", "13337")
562
679
  .option("-d, --background", "Run in background (detached)")
563
680
  .action(async (opts) => {
681
+ const { startAll } = await import("./commands/start.js");
564
682
  await startAll({
565
683
  port: parseInt(opts.port, 10),
566
684
  background: !!opts.background,
@@ -571,6 +689,7 @@ program
571
689
  .command("stop")
572
690
  .description("Stop DevFlow server")
573
691
  .action(async () => {
692
+ const { stopAll } = await import("./commands/stop.js");
574
693
  await stopAll();
575
694
  });
576
695
  // --- status ---
@@ -578,6 +697,7 @@ program
578
697
  .command("status")
579
698
  .description("Show DevFlow services status")
580
699
  .action(async () => {
700
+ const { showStatus } = await import("./commands/status.js");
581
701
  await showStatus();
582
702
  });
583
703
  // --- setup ---
@@ -588,6 +708,7 @@ program
588
708
  .option("--skip-mcp", "Skip MCP configuration")
589
709
  .option("--skip-plugin", "Skip plugin registration")
590
710
  .action(async (opts) => {
711
+ const { setupCommand } = await import("./commands/setup.js");
591
712
  await setupCommand({
592
713
  agent: opts.agent,
593
714
  skipMcp: !!opts.skipMcp,
@@ -598,9 +719,17 @@ program
598
719
  const pluginCmd = program
599
720
  .command("plugin")
600
721
  .description("Manage DevFlow plugins");
601
- pluginCmd.addCommand(pluginListCommand);
602
- pluginCmd.addCommand(pluginSearchCommand);
603
- pluginCmd.addCommand(pluginInstallCommand);
604
- pluginCmd.addCommand(pluginUninstallCommand);
605
- program.parse();
722
+ if (process.argv.includes("plugin")) {
723
+ const [{ pluginListCommand }, { pluginSearchCommand }, { pluginInstallCommand }, { pluginUninstallCommand },] = await Promise.all([
724
+ import("./commands/plugin/list.js"),
725
+ import("./commands/plugin/search.js"),
726
+ import("./commands/plugin/install.js"),
727
+ import("./commands/plugin/uninstall.js"),
728
+ ]);
729
+ pluginCmd.addCommand(pluginListCommand);
730
+ pluginCmd.addCommand(pluginSearchCommand);
731
+ pluginCmd.addCommand(pluginInstallCommand);
732
+ pluginCmd.addCommand(pluginUninstallCommand);
733
+ }
734
+ await program.parseAsync();
606
735
  //# sourceMappingURL=index.js.map