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.
- package/README.md +9 -0
- package/dist/src/app.module.js +2 -0
- package/dist/src/app.module.js.map +1 -1
- package/dist/src/cli/cli.d.ts +3 -3
- package/dist/src/cli/cli.js +118 -1
- package/dist/src/cli/cli.js.map +1 -1
- package/dist/src/cli/cli.types.d.ts +14 -0
- package/dist/src/cli/init/init.constants.js +0 -1
- package/dist/src/cli/init/init.constants.js.map +1 -1
- package/dist/src/cli/plugin/install.command.d.ts +10 -0
- package/dist/src/cli/plugin/install.command.js +31 -0
- package/dist/src/cli/plugin/install.command.js.map +1 -0
- package/dist/src/cli/plugin/plugins.command.d.ts +9 -0
- package/dist/src/cli/plugin/plugins.command.js +51 -0
- package/dist/src/cli/plugin/plugins.command.js.map +1 -0
- package/dist/src/cli/plugin/search.command.d.ts +9 -0
- package/dist/src/cli/plugin/search.command.js +53 -0
- package/dist/src/cli/plugin/search.command.js.map +1 -0
- package/dist/src/cli/plugin/uninstall.command.d.ts +12 -0
- package/dist/src/cli/plugin/uninstall.command.js +79 -0
- package/dist/src/cli/plugin/uninstall.command.js.map +1 -0
- package/dist/src/cli/plugin/update.command.d.ts +11 -0
- package/dist/src/cli/plugin/update.command.js +103 -0
- package/dist/src/cli/plugin/update.command.js.map +1 -0
- package/dist/src/cli/run-tui.js +16 -0
- package/dist/src/cli/run-tui.js.map +1 -1
- package/dist/src/context/briefing-loader.service.d.ts +27 -0
- package/dist/src/context/briefing-loader.service.js +124 -0
- package/dist/src/context/briefing-loader.service.js.map +1 -0
- package/dist/src/context/briefing.service.d.ts +27 -0
- package/dist/src/context/briefing.service.js +181 -0
- package/dist/src/context/briefing.service.js.map +1 -0
- package/dist/src/context/briefing.types.d.ts +13 -0
- package/dist/src/context/briefing.types.js +6 -0
- package/dist/src/context/briefing.types.js.map +1 -0
- package/dist/src/context/context.module.js +16 -2
- package/dist/src/context/context.module.js.map +1 -1
- package/dist/src/context/index.d.ts +2 -0
- package/dist/src/context/index.js +2 -0
- package/dist/src/context/index.js.map +1 -1
- package/dist/src/main.js +0 -17
- package/dist/src/main.js.map +1 -1
- package/dist/src/mcp/handlers/briefing.handler.d.ts +12 -0
- package/dist/src/mcp/handlers/briefing.handler.js +71 -0
- package/dist/src/mcp/handlers/briefing.handler.js.map +1 -0
- package/dist/src/mcp/handlers/index.d.ts +4 -0
- package/dist/src/mcp/handlers/index.js +9 -1
- package/dist/src/mcp/handlers/index.js.map +1 -1
- package/dist/src/mcp/handlers/quality-report.handler.d.ts +12 -0
- package/dist/src/mcp/handlers/quality-report.handler.js +75 -0
- package/dist/src/mcp/handlers/quality-report.handler.js.map +1 -0
- package/dist/src/mcp/handlers/resume.handler.d.ts +12 -0
- package/dist/src/mcp/handlers/resume.handler.js +63 -0
- package/dist/src/mcp/handlers/resume.handler.js.map +1 -0
- package/dist/src/mcp/handlers/rule-impact.handler.d.ts +23 -0
- package/dist/src/mcp/handlers/rule-impact.handler.js +241 -0
- package/dist/src/mcp/handlers/rule-impact.handler.js.map +1 -0
- package/dist/src/mcp/handlers/skill.handler.js +2 -2
- package/dist/src/mcp/handlers/skill.handler.js.map +1 -1
- package/dist/src/mcp/mcp.module.js +6 -0
- package/dist/src/mcp/mcp.module.js.map +1 -1
- package/dist/src/plugin/plugin-installer.service.d.ts +41 -0
- package/dist/src/plugin/plugin-installer.service.js +183 -0
- package/dist/src/plugin/plugin-installer.service.js.map +1 -0
- package/dist/src/plugin/plugin-manifest.schema.d.ts +21 -0
- package/dist/src/plugin/plugin-manifest.schema.js +45 -0
- package/dist/src/plugin/plugin-manifest.schema.js.map +1 -0
- package/dist/src/plugin/plugin.module.d.ts +2 -0
- package/dist/src/plugin/plugin.module.js +17 -0
- package/dist/src/plugin/plugin.module.js.map +1 -0
- package/dist/src/plugin/plugin.types.d.ts +7 -0
- package/dist/src/plugin/plugin.types.js +3 -0
- package/dist/src/plugin/plugin.types.js.map +1 -0
- package/dist/src/plugin/registry-client.d.ts +24 -0
- package/dist/src/plugin/registry-client.js +45 -0
- package/dist/src/plugin/registry-client.js.map +1 -0
- package/dist/src/rules/rule-event-collector.d.ts +7 -0
- package/dist/src/rules/rule-event-collector.js +38 -0
- package/dist/src/rules/rule-event-collector.js.map +1 -0
- package/dist/src/rules/rule-event.types.d.ts +9 -0
- package/dist/src/rules/rule-event.types.js +10 -0
- package/dist/src/rules/rule-event.types.js.map +1 -0
- package/dist/src/rules/rule-stats-writer.d.ts +23 -0
- package/dist/src/rules/rule-stats-writer.js +138 -0
- package/dist/src/rules/rule-stats-writer.js.map +1 -0
- package/dist/src/rules/rules.module.js +4 -2
- package/dist/src/rules/rules.module.js.map +1 -1
- package/dist/src/rules/rules.service.d.ts +2 -1
- package/dist/src/rules/rules.service.js.map +1 -1
- package/dist/src/rules/skill.schema.d.ts +5 -0
- package/dist/src/rules/skill.schema.js +6 -0
- package/dist/src/rules/skill.schema.js.map +1 -1
- package/dist/src/shared/rules-core.d.ts +2 -1
- package/dist/src/shared/rules-core.js +1 -0
- package/dist/src/shared/rules-core.js.map +1 -1
- package/dist/src/shared/version.d.ts +1 -1
- package/dist/src/shared/version.js +1 -1
- package/dist/src/ship/file-specialist-mapper.d.ts +9 -0
- package/dist/src/ship/file-specialist-mapper.js +56 -0
- package/dist/src/ship/file-specialist-mapper.js.map +1 -0
- package/dist/src/ship/quality-report.service.d.ts +6 -0
- package/dist/src/ship/quality-report.service.js +56 -0
- package/dist/src/ship/quality-report.service.js.map +1 -0
- package/dist/src/ship/quality-report.types.d.ts +20 -0
- package/dist/src/ship/quality-report.types.js +3 -0
- package/dist/src/ship/quality-report.types.js.map +1 -0
- package/dist/src/ship/ship.module.d.ts +2 -0
- package/dist/src/ship/ship.module.js +21 -0
- package/dist/src/ship/ship.module.js.map +1 -0
- package/dist/src/skill/skill-recommendation.service.d.ts +9 -2
- package/dist/src/skill/skill-recommendation.service.js +94 -16
- package/dist/src/skill/skill-recommendation.service.js.map +1 -1
- package/dist/src/skill/skill.module.js +2 -0
- package/dist/src/skill/skill.module.js.map +1 -1
- package/dist/src/tui/__perf__/memory-stability.spec.js +6 -6
- package/dist/src/tui/__perf__/memory-stability.spec.js.map +1 -1
- package/dist/src/tui/__perf__/rendering-performance.spec.js +5 -8
- package/dist/src/tui/__perf__/rendering-performance.spec.js.map +1 -1
- package/dist/src/tui/dashboard-app.spec.js +15 -15
- package/dist/src/tui/dashboard-app.spec.js.map +1 -1
- package/dist/src/tui/eventbus-ui.integration.spec.js +45 -45
- package/dist/src/tui/eventbus-ui.integration.spec.js.map +1 -1
- package/dist/src/tui/events/hud-file-bridge.d.ts +21 -0
- package/dist/src/tui/events/hud-file-bridge.js +112 -0
- package/dist/src/tui/events/hud-file-bridge.js.map +1 -0
- package/dist/src/tui/events/index.d.ts +1 -0
- package/dist/src/tui/events/index.js +3 -1
- package/dist/src/tui/events/index.js.map +1 -1
- package/dist/src/tui/testing/tui-test-utils.d.ts +2 -0
- package/dist/src/tui/testing/tui-test-utils.js +25 -0
- package/dist/src/tui/testing/tui-test-utils.js.map +1 -0
- package/dist/src/tui/transport-tui.integration.spec.js +8 -8
- package/dist/src/tui/transport-tui.integration.spec.js.map +1 -1
- package/dist/src/tui-bundle.mjs +226 -61
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +2 -2
package/dist/src/tui-bundle.mjs
CHANGED
|
@@ -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,
|
|
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
|
-
|
|
606
|
+
path10 = root;
|
|
606
607
|
} else {
|
|
607
|
-
|
|
608
|
+
path10 = root ? root.concat(branchName) : [branchName];
|
|
608
609
|
}
|
|
609
610
|
isArrayPath = asArray || typeof branchName === "symbol";
|
|
610
|
-
hasListeners && events.push(isArrayPath ?
|
|
611
|
+
hasListeners && events.push(isArrayPath ? path10 : path10.join(this.delimiter));
|
|
611
612
|
if (typeof branch === "object") {
|
|
612
|
-
collectTreeEvents.call(this, branch, events,
|
|
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(
|
|
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(
|
|
2378
|
-
path2.resolve(
|
|
2379
|
-
path2.resolve(
|
|
2380
|
-
path2.resolve(
|
|
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
|
|
2383
|
-
if (
|
|
2389
|
+
const existsSync8 = options?.existsSync;
|
|
2390
|
+
if (existsSync8) {
|
|
2384
2391
|
for (const candidate of candidates) {
|
|
2385
|
-
if (
|
|
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
|
|
2404
|
+
const readFile4 = getReadFile(deps);
|
|
2398
2405
|
try {
|
|
2399
|
-
return await
|
|
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
|
|
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
|
|
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
|
|
2494
|
+
const readFile4 = getReadFile(deps);
|
|
2487
2495
|
try {
|
|
2488
|
-
const content = await
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
|
2906
|
-
import { existsSync as
|
|
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
|
|
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 (
|
|
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 (
|
|
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 (
|
|
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
|
|
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 (!
|
|
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
|
|
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 (!
|
|
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 (
|
|
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
|
-
|
|
4094
|
+
Injectable9()
|
|
3934
4095
|
], ConfigService);
|
|
3935
4096
|
|
|
3936
4097
|
// src/config/config-diff.service.ts
|
|
3937
|
-
import { Injectable as
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
5602
|
+
path10.push({ x, y: from.y, char: "\u2500" });
|
|
5438
5603
|
}
|
|
5439
|
-
|
|
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
|
-
|
|
5608
|
+
path10.push({ x: from.x, y, char: "\u2502" });
|
|
5444
5609
|
}
|
|
5445
|
-
|
|
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
|
-
|
|
5615
|
+
path10.push({ x, y: from.y, char: "\u2500" });
|
|
5451
5616
|
}
|
|
5452
5617
|
}
|
|
5453
5618
|
const dirY = to.y > from.y ? 1 : -1;
|
|
5454
|
-
|
|
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
|
-
|
|
5625
|
+
path10.push({ x: midX, y, char: "\u2502" });
|
|
5461
5626
|
}
|
|
5462
5627
|
const dirX2 = to.x > midX ? 1 : to.x < midX ? -1 : 0;
|
|
5463
|
-
|
|
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
|
-
|
|
5635
|
+
path10.push({ x, y: to.y, char: "\u2500" });
|
|
5471
5636
|
}
|
|
5472
5637
|
}
|
|
5473
5638
|
if (to.x !== midX) {
|
|
5474
|
-
|
|
5639
|
+
path10.push({ x: to.x, y: to.y, char: dirX2 >= 0 ? "\u25B8" : "\u25C2" });
|
|
5475
5640
|
} else {
|
|
5476
|
-
|
|
5641
|
+
path10[path10.length - 1].char = dirY > 0 ? "\u25BE" : "\u25B4";
|
|
5477
5642
|
}
|
|
5478
5643
|
}
|
|
5479
|
-
return
|
|
5644
|
+
return path10;
|
|
5480
5645
|
}
|
|
5481
|
-
function computeLabelPosition(
|
|
5482
|
-
const hSegments =
|
|
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
|
|
5918
|
+
const path10 = computeEdgePath(fromPoint, toPoint);
|
|
5754
5919
|
const edgeDimmed = inactiveIds.has(edge.from) && inactiveIds.has(edge.to);
|
|
5755
|
-
for (const seg of
|
|
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(
|
|
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
|
|
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:
|
|
7140
|
+
projectName: path9.basename(sessionState.projectRoot),
|
|
6976
7141
|
globalState: sessionState.dashboardState.globalState,
|
|
6977
7142
|
isActive: pid === activeSessionPid
|
|
6978
7143
|
});
|