codingbuddy 5.1.2 → 5.2.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 (136) hide show
  1. package/README.md +9 -0
  2. package/dist/src/app.module.js +2 -0
  3. package/dist/src/app.module.js.map +1 -1
  4. package/dist/src/cli/cli.d.ts +3 -3
  5. package/dist/src/cli/cli.js +118 -1
  6. package/dist/src/cli/cli.js.map +1 -1
  7. package/dist/src/cli/cli.types.d.ts +14 -0
  8. package/dist/src/cli/init/init.constants.js +0 -1
  9. package/dist/src/cli/init/init.constants.js.map +1 -1
  10. package/dist/src/cli/plugin/install.command.d.ts +10 -0
  11. package/dist/src/cli/plugin/install.command.js +31 -0
  12. package/dist/src/cli/plugin/install.command.js.map +1 -0
  13. package/dist/src/cli/plugin/plugins.command.d.ts +9 -0
  14. package/dist/src/cli/plugin/plugins.command.js +51 -0
  15. package/dist/src/cli/plugin/plugins.command.js.map +1 -0
  16. package/dist/src/cli/plugin/search.command.d.ts +9 -0
  17. package/dist/src/cli/plugin/search.command.js +53 -0
  18. package/dist/src/cli/plugin/search.command.js.map +1 -0
  19. package/dist/src/cli/plugin/uninstall.command.d.ts +12 -0
  20. package/dist/src/cli/plugin/uninstall.command.js +79 -0
  21. package/dist/src/cli/plugin/uninstall.command.js.map +1 -0
  22. package/dist/src/cli/plugin/update.command.d.ts +11 -0
  23. package/dist/src/cli/plugin/update.command.js +103 -0
  24. package/dist/src/cli/plugin/update.command.js.map +1 -0
  25. package/dist/src/cli/run-tui.js +16 -0
  26. package/dist/src/cli/run-tui.js.map +1 -1
  27. package/dist/src/context/briefing-loader.service.d.ts +27 -0
  28. package/dist/src/context/briefing-loader.service.js +124 -0
  29. package/dist/src/context/briefing-loader.service.js.map +1 -0
  30. package/dist/src/context/briefing.service.d.ts +27 -0
  31. package/dist/src/context/briefing.service.js +181 -0
  32. package/dist/src/context/briefing.service.js.map +1 -0
  33. package/dist/src/context/briefing.types.d.ts +13 -0
  34. package/dist/src/context/briefing.types.js +6 -0
  35. package/dist/src/context/briefing.types.js.map +1 -0
  36. package/dist/src/context/context.module.js +16 -2
  37. package/dist/src/context/context.module.js.map +1 -1
  38. package/dist/src/context/index.d.ts +2 -0
  39. package/dist/src/context/index.js +2 -0
  40. package/dist/src/context/index.js.map +1 -1
  41. package/dist/src/main.js +0 -17
  42. package/dist/src/main.js.map +1 -1
  43. package/dist/src/mcp/handlers/briefing.handler.d.ts +12 -0
  44. package/dist/src/mcp/handlers/briefing.handler.js +71 -0
  45. package/dist/src/mcp/handlers/briefing.handler.js.map +1 -0
  46. package/dist/src/mcp/handlers/index.d.ts +4 -0
  47. package/dist/src/mcp/handlers/index.js +9 -1
  48. package/dist/src/mcp/handlers/index.js.map +1 -1
  49. package/dist/src/mcp/handlers/quality-report.handler.d.ts +12 -0
  50. package/dist/src/mcp/handlers/quality-report.handler.js +75 -0
  51. package/dist/src/mcp/handlers/quality-report.handler.js.map +1 -0
  52. package/dist/src/mcp/handlers/resume.handler.d.ts +12 -0
  53. package/dist/src/mcp/handlers/resume.handler.js +63 -0
  54. package/dist/src/mcp/handlers/resume.handler.js.map +1 -0
  55. package/dist/src/mcp/handlers/rule-impact.handler.d.ts +23 -0
  56. package/dist/src/mcp/handlers/rule-impact.handler.js +241 -0
  57. package/dist/src/mcp/handlers/rule-impact.handler.js.map +1 -0
  58. package/dist/src/mcp/handlers/skill.handler.js +2 -2
  59. package/dist/src/mcp/handlers/skill.handler.js.map +1 -1
  60. package/dist/src/mcp/mcp.module.js +6 -0
  61. package/dist/src/mcp/mcp.module.js.map +1 -1
  62. package/dist/src/plugin/plugin-installer.service.d.ts +41 -0
  63. package/dist/src/plugin/plugin-installer.service.js +183 -0
  64. package/dist/src/plugin/plugin-installer.service.js.map +1 -0
  65. package/dist/src/plugin/plugin-manifest.schema.d.ts +21 -0
  66. package/dist/src/plugin/plugin-manifest.schema.js +45 -0
  67. package/dist/src/plugin/plugin-manifest.schema.js.map +1 -0
  68. package/dist/src/plugin/plugin.module.d.ts +2 -0
  69. package/dist/src/plugin/plugin.module.js +17 -0
  70. package/dist/src/plugin/plugin.module.js.map +1 -0
  71. package/dist/src/plugin/plugin.types.d.ts +7 -0
  72. package/dist/src/plugin/plugin.types.js +3 -0
  73. package/dist/src/plugin/plugin.types.js.map +1 -0
  74. package/dist/src/plugin/registry-client.d.ts +24 -0
  75. package/dist/src/plugin/registry-client.js +45 -0
  76. package/dist/src/plugin/registry-client.js.map +1 -0
  77. package/dist/src/rules/rule-event-collector.d.ts +7 -0
  78. package/dist/src/rules/rule-event-collector.js +38 -0
  79. package/dist/src/rules/rule-event-collector.js.map +1 -0
  80. package/dist/src/rules/rule-event.types.d.ts +9 -0
  81. package/dist/src/rules/rule-event.types.js +10 -0
  82. package/dist/src/rules/rule-event.types.js.map +1 -0
  83. package/dist/src/rules/rule-stats-writer.d.ts +23 -0
  84. package/dist/src/rules/rule-stats-writer.js +138 -0
  85. package/dist/src/rules/rule-stats-writer.js.map +1 -0
  86. package/dist/src/rules/rules.module.js +4 -2
  87. package/dist/src/rules/rules.module.js.map +1 -1
  88. package/dist/src/rules/rules.service.d.ts +2 -1
  89. package/dist/src/rules/rules.service.js.map +1 -1
  90. package/dist/src/rules/skill.schema.d.ts +5 -0
  91. package/dist/src/rules/skill.schema.js +6 -0
  92. package/dist/src/rules/skill.schema.js.map +1 -1
  93. package/dist/src/shared/rules-core.d.ts +2 -1
  94. package/dist/src/shared/rules-core.js +1 -0
  95. package/dist/src/shared/rules-core.js.map +1 -1
  96. package/dist/src/shared/version.d.ts +1 -1
  97. package/dist/src/shared/version.js +1 -1
  98. package/dist/src/ship/file-specialist-mapper.d.ts +9 -0
  99. package/dist/src/ship/file-specialist-mapper.js +56 -0
  100. package/dist/src/ship/file-specialist-mapper.js.map +1 -0
  101. package/dist/src/ship/quality-report.service.d.ts +6 -0
  102. package/dist/src/ship/quality-report.service.js +56 -0
  103. package/dist/src/ship/quality-report.service.js.map +1 -0
  104. package/dist/src/ship/quality-report.types.d.ts +20 -0
  105. package/dist/src/ship/quality-report.types.js +3 -0
  106. package/dist/src/ship/quality-report.types.js.map +1 -0
  107. package/dist/src/ship/ship.module.d.ts +2 -0
  108. package/dist/src/ship/ship.module.js +21 -0
  109. package/dist/src/ship/ship.module.js.map +1 -0
  110. package/dist/src/skill/skill-recommendation.service.d.ts +9 -2
  111. package/dist/src/skill/skill-recommendation.service.js +94 -16
  112. package/dist/src/skill/skill-recommendation.service.js.map +1 -1
  113. package/dist/src/skill/skill.module.js +2 -0
  114. package/dist/src/skill/skill.module.js.map +1 -1
  115. package/dist/src/tui/__perf__/memory-stability.spec.js +6 -6
  116. package/dist/src/tui/__perf__/memory-stability.spec.js.map +1 -1
  117. package/dist/src/tui/__perf__/rendering-performance.spec.js +5 -8
  118. package/dist/src/tui/__perf__/rendering-performance.spec.js.map +1 -1
  119. package/dist/src/tui/dashboard-app.spec.js +15 -15
  120. package/dist/src/tui/dashboard-app.spec.js.map +1 -1
  121. package/dist/src/tui/eventbus-ui.integration.spec.js +45 -45
  122. package/dist/src/tui/eventbus-ui.integration.spec.js.map +1 -1
  123. package/dist/src/tui/events/hud-file-bridge.d.ts +21 -0
  124. package/dist/src/tui/events/hud-file-bridge.js +112 -0
  125. package/dist/src/tui/events/hud-file-bridge.js.map +1 -0
  126. package/dist/src/tui/events/index.d.ts +1 -0
  127. package/dist/src/tui/events/index.js +3 -1
  128. package/dist/src/tui/events/index.js.map +1 -1
  129. package/dist/src/tui/testing/tui-test-utils.d.ts +2 -0
  130. package/dist/src/tui/testing/tui-test-utils.js +25 -0
  131. package/dist/src/tui/testing/tui-test-utils.js.map +1 -0
  132. package/dist/src/tui/transport-tui.integration.spec.js +8 -8
  133. package/dist/src/tui/transport-tui.integration.spec.js.map +1 -1
  134. package/dist/src/tui-bundle.mjs +226 -61
  135. package/dist/tsconfig.build.tsbuildinfo +1 -1
  136. package/package.json +2 -2
@@ -38,6 +38,7 @@ var __decorateClass = (decorators, target, key, kind) => {
38
38
  if (kind && result) __defProp(target, key, result);
39
39
  return result;
40
40
  };
41
+ var __decorateParam = (index, decorator) => (target, key) => decorator(target, key, index);
41
42
 
42
43
  // node_modules/eventemitter2/lib/eventemitter2.js
43
44
  var require_eventemitter2 = __commonJS({
@@ -595,21 +596,21 @@ var require_eventemitter2 = __commonJS({
595
596
  function collectTreeEvents(tree, events, root, asArray) {
596
597
  var branches = ownKeys(tree);
597
598
  var i = branches.length;
598
- var branch, branchName, path9;
599
+ var branch, branchName, path10;
599
600
  var hasListeners = tree["_listeners"];
600
601
  var isArrayPath;
601
602
  while (i-- > 0) {
602
603
  branchName = branches[i];
603
604
  branch = tree[branchName];
604
605
  if (branchName === "_listeners") {
605
- path9 = root;
606
+ path10 = root;
606
607
  } else {
607
- path9 = root ? root.concat(branchName) : [branchName];
608
+ path10 = root ? root.concat(branchName) : [branchName];
608
609
  }
609
610
  isArrayPath = asArray || typeof branchName === "symbol";
610
- hasListeners && events.push(isArrayPath ? path9 : path9.join(this.delimiter));
611
+ hasListeners && events.push(isArrayPath ? path10 : path10.join(this.delimiter));
611
612
  if (typeof branch === "object") {
612
- collectTreeEvents.call(this, branch, events, path9, isArrayPath);
613
+ collectTreeEvents.call(this, branch, events, path10, isArrayPath);
613
614
  }
614
615
  }
615
616
  return events;
@@ -2302,9 +2303,14 @@ var SkillSchemaError = class extends Error {
2302
2303
  this.name = "SkillSchemaError";
2303
2304
  }
2304
2305
  };
2306
+ var SkillFrontmatterTriggerSchema = z2.object({
2307
+ pattern: z2.string().min(1),
2308
+ confidence: z2.enum(["high", "medium", "low"])
2309
+ });
2305
2310
  var SkillFrontmatterSchema = z2.object({
2306
2311
  name: z2.string().min(1).regex(/^[a-z0-9-]+$/, "Skill name must be lowercase alphanumeric with hyphens only"),
2307
- description: z2.string().min(1).max(500)
2312
+ description: z2.string().min(1).max(500),
2313
+ triggers: z2.array(SkillFrontmatterTriggerSchema).optional()
2308
2314
  });
2309
2315
  var FRONTMATTER_REGEX = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?([\s\S]*)$/;
2310
2316
  function parseFrontmatter(content) {
@@ -2343,7 +2349,8 @@ function parseSkill(content, filePath) {
2343
2349
  name: result.data.name,
2344
2350
  description: result.data.description,
2345
2351
  content: body,
2346
- path: filePath
2352
+ path: filePath,
2353
+ triggers: result.data.triggers
2347
2354
  };
2348
2355
  }
2349
2356
 
@@ -2366,7 +2373,7 @@ function getReadFile(deps) {
2366
2373
  function getReaddir(deps) {
2367
2374
  return deps?.readdir ?? defaultReaddir;
2368
2375
  }
2369
- function resolveRulesDir(dirname2, options) {
2376
+ function resolveRulesDir(dirname4, options) {
2370
2377
  if (options?.envRulesDir) {
2371
2378
  return options.envRulesDir;
2372
2379
  }
@@ -2374,15 +2381,15 @@ function resolveRulesDir(dirname2, options) {
2374
2381
  return options.packageRulesPath;
2375
2382
  }
2376
2383
  const candidates = [
2377
- path2.resolve(dirname2, "../../../../packages/rules/.ai-rules"),
2378
- path2.resolve(dirname2, "../../../packages/rules/.ai-rules"),
2379
- path2.resolve(dirname2, "../../../../.ai-rules"),
2380
- path2.resolve(dirname2, "../../../.ai-rules")
2384
+ path2.resolve(dirname4, "../../../../packages/rules/.ai-rules"),
2385
+ path2.resolve(dirname4, "../../../packages/rules/.ai-rules"),
2386
+ path2.resolve(dirname4, "../../../../.ai-rules"),
2387
+ path2.resolve(dirname4, "../../../.ai-rules")
2381
2388
  ];
2382
- const existsSync6 = options?.existsSync;
2383
- if (existsSync6) {
2389
+ const existsSync8 = options?.existsSync;
2390
+ if (existsSync8) {
2384
2391
  for (const candidate of candidates) {
2385
- if (existsSync6(candidate)) {
2392
+ if (existsSync8(candidate)) {
2386
2393
  return candidate;
2387
2394
  }
2388
2395
  }
@@ -2394,9 +2401,9 @@ async function readRuleContent(rulesDir, relativePath, deps) {
2394
2401
  throw new Error("Access denied: Invalid path");
2395
2402
  }
2396
2403
  const fullPath = path2.join(rulesDir, relativePath);
2397
- const readFile3 = getReadFile(deps);
2404
+ const readFile4 = getReadFile(deps);
2398
2405
  try {
2399
- return await readFile3(fullPath, "utf-8");
2406
+ return await readFile4(fullPath, "utf-8");
2400
2407
  } catch {
2401
2408
  throw new Error(`Failed to read rule file: ${relativePath}`);
2402
2409
  }
@@ -2450,7 +2457,7 @@ async function searchInRuleFiles(rulesDir, query, files, deps) {
2450
2457
  async function listSkillSummaries(rulesDir, deps) {
2451
2458
  const skillsDir = path2.join(rulesDir, "skills");
2452
2459
  const readdir2 = getReaddir(deps);
2453
- const readFile3 = getReadFile(deps);
2460
+ const readFile4 = getReadFile(deps);
2454
2461
  const summaries = [];
2455
2462
  try {
2456
2463
  const entries = await readdir2(skillsDir, {
@@ -2460,11 +2467,12 @@ async function listSkillSummaries(rulesDir, deps) {
2460
2467
  if (entry.isDirectory()) {
2461
2468
  const skillPath = path2.join(skillsDir, entry.name, "SKILL.md");
2462
2469
  try {
2463
- const content = await readFile3(skillPath, "utf-8");
2470
+ const content = await readFile4(skillPath, "utf-8");
2464
2471
  const skill = parseSkill(content, `skills/${entry.name}/SKILL.md`);
2465
2472
  summaries.push({
2466
2473
  name: skill.name,
2467
- description: skill.description
2474
+ description: skill.description,
2475
+ triggers: skill.triggers
2468
2476
  });
2469
2477
  } catch {
2470
2478
  }
@@ -2483,9 +2491,9 @@ async function loadSkill(rulesDir, name, deps) {
2483
2491
  throw new Error("Access denied: Invalid path");
2484
2492
  }
2485
2493
  const fullPath = path2.join(rulesDir, skillPath);
2486
- const readFile3 = getReadFile(deps);
2494
+ const readFile4 = getReadFile(deps);
2487
2495
  try {
2488
- const content = await readFile3(fullPath, "utf-8");
2496
+ const content = await readFile4(fullPath, "utf-8");
2489
2497
  return parseSkill(content, skillPath);
2490
2498
  } catch (error) {
2491
2499
  if (error instanceof SkillSchemaError) {
@@ -2629,7 +2637,7 @@ var RulesService = class {
2629
2637
  // ============================================================================
2630
2638
  /**
2631
2639
  * List all available skills from the skills directory
2632
- * @returns Array of skill summaries with name and description
2640
+ * @returns Array of skill summaries with name, description, and optional triggers
2633
2641
  */
2634
2642
  async listSkillsFromDir() {
2635
2643
  try {
@@ -2761,11 +2769,164 @@ RuleInsightsService = __decorateClass([
2761
2769
  Injectable5()
2762
2770
  ], RuleInsightsService);
2763
2771
 
2772
+ // src/rules/rule-event-collector.ts
2773
+ import { Injectable as Injectable6 } from "@nestjs/common";
2774
+
2775
+ // src/rules/rule-event.types.ts
2776
+ var RULE_EVENT_TYPES = [
2777
+ "mode_activated",
2778
+ "checklist_generated",
2779
+ "specialist_dispatched",
2780
+ "violation_caught"
2781
+ ];
2782
+
2783
+ // src/rules/rule-event-collector.ts
2784
+ var RuleEventCollector = class {
2785
+ constructor() {
2786
+ this.events = [];
2787
+ }
2788
+ record(event) {
2789
+ if (!RULE_EVENT_TYPES.includes(event.type)) {
2790
+ throw new Error(`Invalid rule event type: ${event.type}`);
2791
+ }
2792
+ this.events.push({
2793
+ ...event,
2794
+ timestamp: event.timestamp ?? (/* @__PURE__ */ new Date()).toISOString()
2795
+ });
2796
+ }
2797
+ getEvents() {
2798
+ return [...this.events];
2799
+ }
2800
+ flush() {
2801
+ const flushed = [...this.events];
2802
+ this.events = [];
2803
+ return flushed;
2804
+ }
2805
+ };
2806
+ RuleEventCollector = __decorateClass([
2807
+ Injectable6()
2808
+ ], RuleEventCollector);
2809
+
2810
+ // src/rules/rule-stats-writer.ts
2811
+ import { Injectable as Injectable7, Inject, Optional } from "@nestjs/common";
2812
+ import { readFile, writeFile, rename, mkdir } from "fs/promises";
2813
+ import { existsSync as existsSync2 } from "fs";
2814
+ import { dirname, join as join2 } from "path";
2815
+ var STATS_FILE_PATH = /* @__PURE__ */ Symbol("STATS_FILE_PATH");
2816
+ var DEFAULT_STATS_RELATIVE_PATH = "docs/codingbuddy/rule-stats.json";
2817
+ function createEmptyStats() {
2818
+ return {
2819
+ lastUpdated: (/* @__PURE__ */ new Date()).toISOString(),
2820
+ rules: {},
2821
+ domains: {}
2822
+ };
2823
+ }
2824
+ function aggregateEvents(events) {
2825
+ const stats = createEmptyStats();
2826
+ for (const event of events) {
2827
+ switch (event.type) {
2828
+ case "mode_activated": {
2829
+ if (!event.rule) break;
2830
+ if (!stats.rules[event.rule]) {
2831
+ stats.rules[event.rule] = { applied: 0, sessions: 0 };
2832
+ }
2833
+ stats.rules[event.rule].applied += 1;
2834
+ stats.rules[event.rule].sessions += 1;
2835
+ break;
2836
+ }
2837
+ case "checklist_generated":
2838
+ case "specialist_dispatched": {
2839
+ if (!event.domain) break;
2840
+ if (!stats.domains[event.domain]) {
2841
+ stats.domains[event.domain] = { checks: 0, issues_prevented: 0 };
2842
+ }
2843
+ stats.domains[event.domain].checks += 1;
2844
+ break;
2845
+ }
2846
+ case "violation_caught": {
2847
+ if (!event.domain) break;
2848
+ if (!stats.domains[event.domain]) {
2849
+ stats.domains[event.domain] = { checks: 0, issues_prevented: 0 };
2850
+ }
2851
+ stats.domains[event.domain].issues_prevented += 1;
2852
+ break;
2853
+ }
2854
+ }
2855
+ }
2856
+ return stats;
2857
+ }
2858
+ function mergeStats(existing, incoming) {
2859
+ const merged = {
2860
+ lastUpdated: (/* @__PURE__ */ new Date()).toISOString(),
2861
+ rules: { ...existing.rules },
2862
+ domains: { ...existing.domains }
2863
+ };
2864
+ for (const [name, entry] of Object.entries(incoming.rules)) {
2865
+ if (merged.rules[name]) {
2866
+ merged.rules[name] = {
2867
+ applied: merged.rules[name].applied + entry.applied,
2868
+ sessions: merged.rules[name].sessions + entry.sessions
2869
+ };
2870
+ } else {
2871
+ merged.rules[name] = { ...entry };
2872
+ }
2873
+ }
2874
+ for (const [name, entry] of Object.entries(incoming.domains)) {
2875
+ if (merged.domains[name]) {
2876
+ merged.domains[name] = {
2877
+ checks: merged.domains[name].checks + entry.checks,
2878
+ issues_prevented: merged.domains[name].issues_prevented + entry.issues_prevented
2879
+ };
2880
+ } else {
2881
+ merged.domains[name] = { ...entry };
2882
+ }
2883
+ }
2884
+ return merged;
2885
+ }
2886
+ var RuleStatsWriter = class {
2887
+ constructor(collector, statsPath) {
2888
+ this.collector = collector;
2889
+ this.statsPath = statsPath ?? join2(process.cwd(), DEFAULT_STATS_RELATIVE_PATH);
2890
+ }
2891
+ async flush() {
2892
+ const events = this.collector.flush();
2893
+ if (events.length === 0) {
2894
+ return;
2895
+ }
2896
+ const incoming = aggregateEvents(events);
2897
+ const existing = await this.readExistingStats();
2898
+ const merged = existing ? mergeStats(existing, incoming) : incoming;
2899
+ await this.atomicWrite(merged);
2900
+ }
2901
+ async readExistingStats() {
2902
+ try {
2903
+ const raw = await readFile(this.statsPath, "utf-8");
2904
+ return JSON.parse(raw);
2905
+ } catch {
2906
+ return null;
2907
+ }
2908
+ }
2909
+ async atomicWrite(stats) {
2910
+ const dir = dirname(this.statsPath);
2911
+ if (!existsSync2(dir)) {
2912
+ await mkdir(dir, { recursive: true });
2913
+ }
2914
+ const tmpPath = this.statsPath + ".tmp";
2915
+ await writeFile(tmpPath, JSON.stringify(stats, null, 2), "utf-8");
2916
+ await rename(tmpPath, this.statsPath);
2917
+ }
2918
+ };
2919
+ RuleStatsWriter = __decorateClass([
2920
+ Injectable7(),
2921
+ __decorateParam(1, Optional()),
2922
+ __decorateParam(1, Inject(STATS_FILE_PATH))
2923
+ ], RuleStatsWriter);
2924
+
2764
2925
  // src/custom/custom.module.ts
2765
2926
  import { Module } from "@nestjs/common";
2766
2927
 
2767
2928
  // src/custom/custom.service.ts
2768
- import { Injectable as Injectable6, Logger as Logger5 } from "@nestjs/common";
2929
+ import { Injectable as Injectable8, Logger as Logger5 } from "@nestjs/common";
2769
2930
  import * as fs from "fs/promises";
2770
2931
  import * as path3 from "path";
2771
2932
 
@@ -2885,7 +3046,7 @@ var CustomService = class {
2885
3046
  }
2886
3047
  };
2887
3048
  CustomService = __decorateClass([
2888
- Injectable6()
3049
+ Injectable8()
2889
3050
  ], CustomService);
2890
3051
 
2891
3052
  // src/custom/custom.module.ts
@@ -2902,14 +3063,14 @@ CustomModule = __decorateClass([
2902
3063
  import { Module as Module2 } from "@nestjs/common";
2903
3064
 
2904
3065
  // src/config/config.service.ts
2905
- import { Injectable as Injectable7, Logger as Logger6 } from "@nestjs/common";
2906
- import { existsSync as existsSync5, statSync } from "fs";
3066
+ import { Injectable as Injectable9, Logger as Logger6 } from "@nestjs/common";
3067
+ import { existsSync as existsSync6, statSync } from "fs";
2907
3068
  import { stat, realpath } from "fs/promises";
2908
3069
  import * as path7 from "path";
2909
3070
 
2910
3071
  // src/config/config.loader.ts
2911
3072
  import * as fs2 from "fs/promises";
2912
- import { existsSync as existsSync2 } from "fs";
3073
+ import { existsSync as existsSync3 } from "fs";
2913
3074
  import * as path4 from "path";
2914
3075
 
2915
3076
  // src/config/config.schema.ts
@@ -3128,7 +3289,7 @@ var ConfigLoadError = class extends Error {
3128
3289
  function findConfigFile(projectRoot) {
3129
3290
  for (const fileName of CONFIG_FILE_NAMES) {
3130
3291
  const filePath = path4.join(projectRoot, fileName);
3131
- if (existsSync2(filePath)) {
3292
+ if (existsSync3(filePath)) {
3132
3293
  return filePath;
3133
3294
  }
3134
3295
  }
@@ -3138,7 +3299,7 @@ function findDeprecatedConfigFiles(projectRoot) {
3138
3299
  const found = [];
3139
3300
  for (const fileName of DEPRECATED_CONFIG_FILE_NAMES) {
3140
3301
  const filePath = path4.join(projectRoot, fileName);
3141
- if (existsSync2(filePath)) {
3302
+ if (existsSync3(filePath)) {
3142
3303
  found.push(filePath);
3143
3304
  }
3144
3305
  }
@@ -3195,7 +3356,7 @@ function findProjectRoot(startDir) {
3195
3356
  return currentDir;
3196
3357
  }
3197
3358
  const packageJsonPath = path4.join(currentDir, "package.json");
3198
- if (existsSync2(packageJsonPath) && firstPackageJsonDir === null) {
3359
+ if (existsSync3(packageJsonPath) && firstPackageJsonDir === null) {
3199
3360
  firstPackageJsonDir = currentDir;
3200
3361
  }
3201
3362
  const parentDir = path4.dirname(currentDir);
@@ -3271,7 +3432,7 @@ async function loadConfig(projectRoot) {
3271
3432
  }
3272
3433
 
3273
3434
  // src/config/ignore.parser.ts
3274
- import { existsSync as existsSync3 } from "fs";
3435
+ import { existsSync as existsSync4 } from "fs";
3275
3436
  import * as path5 from "path";
3276
3437
 
3277
3438
  // src/shared/file.utils.ts
@@ -3457,7 +3618,7 @@ function parseIgnoreContent(content) {
3457
3618
  }
3458
3619
  async function loadIgnoreFile(projectRoot) {
3459
3620
  const ignorePath = path5.join(projectRoot, IGNORE_FILE_NAME);
3460
- if (!existsSync3(ignorePath)) {
3621
+ if (!existsSync4(ignorePath)) {
3461
3622
  return {
3462
3623
  patterns: [],
3463
3624
  source: null
@@ -3547,7 +3708,7 @@ function getDefaultIgnorePatterns() {
3547
3708
  }
3548
3709
 
3549
3710
  // src/config/context.loader.ts
3550
- import { existsSync as existsSync4 } from "fs";
3711
+ import { existsSync as existsSync5 } from "fs";
3551
3712
  import * as path6 from "path";
3552
3713
  var CONTEXT_DIR_NAME = ".codingbuddy";
3553
3714
  var KNOWN_SUBDIRS = {
@@ -3614,7 +3775,7 @@ async function loadContextFile(contextDir, relativePath) {
3614
3775
  }
3615
3776
  async function loadContextFiles(projectRoot) {
3616
3777
  const contextDir = path6.join(projectRoot, CONTEXT_DIR_NAME);
3617
- if (!existsSync4(contextDir)) {
3778
+ if (!existsSync5(contextDir)) {
3618
3779
  return {
3619
3780
  files: [],
3620
3781
  source: null,
@@ -3707,7 +3868,7 @@ var ConfigService = class {
3707
3868
  const envRoot = process.env.CODINGBUDDY_PROJECT_ROOT;
3708
3869
  if (envRoot) {
3709
3870
  const normalizedPath = path7.resolve(envRoot);
3710
- if (existsSync5(normalizedPath)) {
3871
+ if (existsSync6(normalizedPath)) {
3711
3872
  try {
3712
3873
  const stat2 = statSync(normalizedPath);
3713
3874
  if (stat2.isDirectory()) {
@@ -3930,11 +4091,11 @@ var ConfigService = class {
3930
4091
  }
3931
4092
  };
3932
4093
  ConfigService = __decorateClass([
3933
- Injectable7()
4094
+ Injectable9()
3934
4095
  ], ConfigService);
3935
4096
 
3936
4097
  // src/config/config-diff.service.ts
3937
- import { Injectable as Injectable8 } from "@nestjs/common";
4098
+ import { Injectable as Injectable10 } from "@nestjs/common";
3938
4099
  var ConfigDiffService = class {
3939
4100
  /**
3940
4101
  * Compare project analysis with current config
@@ -4106,7 +4267,7 @@ var ConfigDiffService = class {
4106
4267
  }
4107
4268
  };
4108
4269
  ConfigDiffService = __decorateClass([
4109
- Injectable8()
4270
+ Injectable10()
4110
4271
  ], ConfigDiffService);
4111
4272
 
4112
4273
  // src/config/config.module.ts
@@ -4125,8 +4286,8 @@ var RulesModule = class {
4125
4286
  RulesModule = __decorateClass([
4126
4287
  Module3({
4127
4288
  imports: [CustomModule, CodingBuddyConfigModule],
4128
- providers: [RulesService, RuleInsightsService],
4129
- exports: [RulesService, RuleInsightsService]
4289
+ providers: [RulesService, RuleInsightsService, RuleEventCollector, RuleStatsWriter],
4290
+ exports: [RulesService, RuleInsightsService, RuleEventCollector, RuleStatsWriter]
4130
4291
  })
4131
4292
  ], RulesModule);
4132
4293
 
@@ -4141,6 +4302,10 @@ TuiEventsModule = __decorateClass([
4141
4302
  })
4142
4303
  ], TuiEventsModule);
4143
4304
 
4305
+ // src/tui/events/hud-file-bridge.ts
4306
+ import * as fs4 from "node:fs";
4307
+ import * as path8 from "node:path";
4308
+
4144
4309
  // src/tui/hooks/use-focus-agent.ts
4145
4310
  function selectFocusedAgent(agents, currentFocusId) {
4146
4311
  if (agents.size === 0) return null;
@@ -5429,57 +5594,57 @@ var ColorBuffer = class {
5429
5594
 
5430
5595
  // src/tui/utils/edge-router.ts
5431
5596
  function computeEdgePath(from, to) {
5432
- const path9 = [];
5597
+ const path10 = [];
5433
5598
  const midX = Math.floor((from.x + to.x) / 2);
5434
5599
  if (from.y === to.y) {
5435
5600
  const dir = to.x > from.x ? 1 : -1;
5436
5601
  for (let x = from.x; x !== to.x; x += dir) {
5437
- path9.push({ x, y: from.y, char: "\u2500" });
5602
+ path10.push({ x, y: from.y, char: "\u2500" });
5438
5603
  }
5439
- path9.push({ x: to.x, y: to.y, char: dir > 0 ? "\u25B8" : "\u25C2" });
5604
+ path10.push({ x: to.x, y: to.y, char: dir > 0 ? "\u25B8" : "\u25C2" });
5440
5605
  } else if (from.x === to.x) {
5441
5606
  const dir = to.y > from.y ? 1 : -1;
5442
5607
  for (let y = from.y; y !== to.y; y += dir) {
5443
- path9.push({ x: from.x, y, char: "\u2502" });
5608
+ path10.push({ x: from.x, y, char: "\u2502" });
5444
5609
  }
5445
- path9.push({ x: to.x, y: to.y, char: dir > 0 ? "\u25BE" : "\u25B4" });
5610
+ path10.push({ x: to.x, y: to.y, char: dir > 0 ? "\u25BE" : "\u25B4" });
5446
5611
  } else {
5447
5612
  const dirX = midX > from.x ? 1 : midX < from.x ? -1 : 0;
5448
5613
  if (dirX !== 0) {
5449
5614
  for (let x = from.x; x !== midX; x += dirX) {
5450
- path9.push({ x, y: from.y, char: "\u2500" });
5615
+ path10.push({ x, y: from.y, char: "\u2500" });
5451
5616
  }
5452
5617
  }
5453
5618
  const dirY = to.y > from.y ? 1 : -1;
5454
- path9.push({
5619
+ path10.push({
5455
5620
  x: midX,
5456
5621
  y: from.y,
5457
5622
  char: dirX >= 0 ? dirY > 0 ? "\u256E" : "\u256F" : dirY > 0 ? "\u256D" : "\u2570"
5458
5623
  });
5459
5624
  for (let y = from.y + dirY; y !== to.y; y += dirY) {
5460
- path9.push({ x: midX, y, char: "\u2502" });
5625
+ path10.push({ x: midX, y, char: "\u2502" });
5461
5626
  }
5462
5627
  const dirX2 = to.x > midX ? 1 : to.x < midX ? -1 : 0;
5463
- path9.push({
5628
+ path10.push({
5464
5629
  x: midX,
5465
5630
  y: to.y,
5466
5631
  char: dirY > 0 ? dirX2 >= 0 ? "\u2570" : "\u256F" : dirX2 >= 0 ? "\u256D" : "\u256E"
5467
5632
  });
5468
5633
  if (dirX2 !== 0) {
5469
5634
  for (let x = midX + dirX2; x !== to.x; x += dirX2) {
5470
- path9.push({ x, y: to.y, char: "\u2500" });
5635
+ path10.push({ x, y: to.y, char: "\u2500" });
5471
5636
  }
5472
5637
  }
5473
5638
  if (to.x !== midX) {
5474
- path9.push({ x: to.x, y: to.y, char: dirX2 >= 0 ? "\u25B8" : "\u25C2" });
5639
+ path10.push({ x: to.x, y: to.y, char: dirX2 >= 0 ? "\u25B8" : "\u25C2" });
5475
5640
  } else {
5476
- path9[path9.length - 1].char = dirY > 0 ? "\u25BE" : "\u25B4";
5641
+ path10[path10.length - 1].char = dirY > 0 ? "\u25BE" : "\u25B4";
5477
5642
  }
5478
5643
  }
5479
- return path9;
5644
+ return path10;
5480
5645
  }
5481
- function computeLabelPosition(path9, label) {
5482
- const hSegments = path9.filter((p) => p.char === "\u2500");
5646
+ function computeLabelPosition(path10, label) {
5647
+ const hSegments = path10.filter((p) => p.char === "\u2500");
5483
5648
  if (hSegments.length < label.length + 2) return null;
5484
5649
  const startIdx = Math.floor((hSegments.length - label.length) / 2);
5485
5650
  return { x: hSegments[startIdx].x, y: hSegments[startIdx].y };
@@ -5750,14 +5915,14 @@ function renderFlowMap(agents, edges, width, height, activeStage = null) {
5750
5915
  x: toPos.x - 1,
5751
5916
  y: toPos.y + Math.floor(toPos.height / 2)
5752
5917
  };
5753
- const path9 = computeEdgePath(fromPoint, toPoint);
5918
+ const path10 = computeEdgePath(fromPoint, toPoint);
5754
5919
  const edgeDimmed = inactiveIds.has(edge.from) && inactiveIds.has(edge.to);
5755
- for (const seg of path9) {
5920
+ for (const seg of path10) {
5756
5921
  const isArrow = seg.char === "\u25B8" || seg.char === "\u25C2" || seg.char === "\u25BE" || seg.char === "\u25B4";
5757
5922
  const segStyle = edgeDimmed ? DIMMED_STYLE : isArrow ? EDGE_STYLES.arrow : EDGE_STYLES.path;
5758
5923
  buf.setChar(seg.x, seg.y, seg.char, segStyle);
5759
5924
  }
5760
- const labelPos = computeLabelPosition(path9, edge.label);
5925
+ const labelPos = computeLabelPosition(path10, edge.label);
5761
5926
  if (labelPos) {
5762
5927
  buf.writeText(
5763
5928
  labelPos.x,
@@ -6747,7 +6912,7 @@ function DashboardApp({
6747
6912
  // src/tui/multi-session-app.tsx
6748
6913
  import React15, { useMemo as useMemo8, useCallback as useCallback2 } from "react";
6749
6914
  import { Box as Box15, useInput } from "ink";
6750
- import * as path8 from "path";
6915
+ import * as path9 from "path";
6751
6916
 
6752
6917
  // src/tui/hooks/use-multi-session-state.ts
6753
6918
  import { useState as useState3, useCallback, useEffect as useEffect4, useRef } from "react";
@@ -6972,7 +7137,7 @@ function MultiSessionApp({ manager }) {
6972
7137
  result.push({
6973
7138
  pid,
6974
7139
  index,
6975
- projectName: path8.basename(sessionState.projectRoot),
7140
+ projectName: path9.basename(sessionState.projectRoot),
6976
7141
  globalState: sessionState.dashboardState.globalState,
6977
7142
  isActive: pid === activeSessionPid
6978
7143
  });