byterover-cli 1.0.5 → 1.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 (204) hide show
  1. package/README.md +19 -13
  2. package/dist/commands/hook-prompt-submit.d.ts +27 -0
  3. package/dist/commands/hook-prompt-submit.js +39 -0
  4. package/dist/commands/mcp.d.ts +13 -0
  5. package/dist/commands/mcp.js +61 -0
  6. package/dist/commands/status.js +8 -3
  7. package/dist/constants.d.ts +1 -1
  8. package/dist/constants.js +1 -1
  9. package/dist/core/domain/cipher/agent-events/types.d.ts +44 -1
  10. package/dist/core/domain/cipher/tools/constants.d.ts +1 -0
  11. package/dist/core/domain/cipher/tools/constants.js +1 -0
  12. package/dist/core/domain/entities/agent.d.ts +16 -0
  13. package/dist/core/domain/entities/agent.js +78 -0
  14. package/dist/core/domain/entities/connector-type.d.ts +10 -0
  15. package/dist/core/domain/entities/connector-type.js +9 -0
  16. package/dist/core/domain/entities/event.d.ts +1 -1
  17. package/dist/core/domain/entities/event.js +2 -0
  18. package/dist/core/domain/errors/task-error.d.ts +4 -0
  19. package/dist/core/domain/errors/task-error.js +7 -0
  20. package/dist/core/domain/transport/schemas.d.ts +40 -0
  21. package/dist/core/domain/transport/schemas.js +28 -0
  22. package/dist/core/interfaces/connectors/connector-types.d.ts +70 -0
  23. package/dist/core/interfaces/connectors/i-connector-manager.d.ts +72 -0
  24. package/dist/core/interfaces/connectors/i-connector-manager.js +1 -0
  25. package/dist/core/interfaces/connectors/i-connector.d.ts +54 -0
  26. package/dist/core/interfaces/connectors/i-connector.js +1 -0
  27. package/dist/core/interfaces/i-file-service.d.ts +7 -0
  28. package/dist/core/interfaces/i-mcp-config-writer.d.ts +40 -0
  29. package/dist/core/interfaces/i-mcp-config-writer.js +1 -0
  30. package/dist/core/interfaces/i-rule-template-service.d.ts +4 -2
  31. package/dist/core/interfaces/transport/i-transport-client.d.ts +7 -0
  32. package/dist/core/interfaces/usecase/i-connectors-use-case.d.ts +3 -0
  33. package/dist/core/interfaces/usecase/i-connectors-use-case.js +1 -0
  34. package/dist/hooks/init/update-notifier.d.ts +1 -0
  35. package/dist/hooks/init/update-notifier.js +10 -1
  36. package/dist/infra/cipher/agent/cipher-agent.d.ts +8 -0
  37. package/dist/infra/cipher/agent/cipher-agent.js +16 -0
  38. package/dist/infra/cipher/file-system/binary-utils.d.ts +7 -12
  39. package/dist/infra/cipher/file-system/binary-utils.js +46 -31
  40. package/dist/infra/cipher/llm/context/context-manager.d.ts +10 -2
  41. package/dist/infra/cipher/llm/context/context-manager.js +39 -2
  42. package/dist/infra/cipher/llm/formatters/gemini-formatter.js +48 -9
  43. package/dist/infra/cipher/llm/internal-llm-service.d.ts +4 -0
  44. package/dist/infra/cipher/llm/internal-llm-service.js +40 -12
  45. package/dist/infra/cipher/session/chat-session.d.ts +3 -0
  46. package/dist/infra/cipher/session/chat-session.js +7 -1
  47. package/dist/infra/cipher/system-prompt/contributors/context-tree-structure-contributor.d.ts +6 -7
  48. package/dist/infra/cipher/system-prompt/contributors/context-tree-structure-contributor.js +57 -18
  49. package/dist/infra/cipher/tools/implementations/curate-tool.d.ts +1 -8
  50. package/dist/infra/cipher/tools/implementations/curate-tool.js +380 -24
  51. package/dist/infra/cipher/tools/implementations/read-file-tool.js +38 -17
  52. package/dist/infra/cipher/tools/implementations/search-knowledge-tool.d.ts +7 -0
  53. package/dist/infra/cipher/tools/implementations/search-knowledge-tool.js +303 -0
  54. package/dist/infra/cipher/tools/index.d.ts +1 -0
  55. package/dist/infra/cipher/tools/index.js +1 -0
  56. package/dist/infra/cipher/tools/tool-manager.js +1 -0
  57. package/dist/infra/cipher/tools/tool-registry.js +7 -0
  58. package/dist/infra/connectors/connector-manager.d.ts +32 -0
  59. package/dist/infra/connectors/connector-manager.js +158 -0
  60. package/dist/infra/connectors/hook/hook-connector-config.d.ts +52 -0
  61. package/dist/infra/connectors/hook/hook-connector-config.js +41 -0
  62. package/dist/infra/connectors/hook/hook-connector.d.ts +46 -0
  63. package/dist/infra/connectors/hook/hook-connector.js +231 -0
  64. package/dist/infra/connectors/mcp/index.d.ts +4 -0
  65. package/dist/infra/connectors/mcp/index.js +4 -0
  66. package/dist/infra/connectors/mcp/json-mcp-config-writer.d.ts +26 -0
  67. package/dist/infra/connectors/mcp/json-mcp-config-writer.js +71 -0
  68. package/dist/infra/connectors/mcp/mcp-connector-config.d.ts +229 -0
  69. package/dist/infra/connectors/mcp/mcp-connector-config.js +173 -0
  70. package/dist/infra/connectors/mcp/mcp-connector.d.ts +80 -0
  71. package/dist/infra/connectors/mcp/mcp-connector.js +324 -0
  72. package/dist/infra/connectors/mcp/toml-mcp-config-writer.d.ts +45 -0
  73. package/dist/infra/connectors/mcp/toml-mcp-config-writer.js +134 -0
  74. package/dist/infra/{rule → connectors/rules}/legacy-rule-detector.d.ts +2 -2
  75. package/dist/infra/{rule → connectors/rules}/legacy-rule-detector.js +1 -1
  76. package/dist/infra/connectors/rules/rules-connector-config.d.ts +95 -0
  77. package/dist/infra/{rule/agent-rule-config.js → connectors/rules/rules-connector-config.js} +10 -10
  78. package/dist/infra/connectors/rules/rules-connector.d.ts +34 -0
  79. package/dist/infra/connectors/rules/rules-connector.js +139 -0
  80. package/dist/infra/connectors/shared/rule-file-manager.d.ts +72 -0
  81. package/dist/infra/connectors/shared/rule-file-manager.js +119 -0
  82. package/dist/infra/connectors/shared/template-service.d.ts +27 -0
  83. package/dist/infra/connectors/shared/template-service.js +125 -0
  84. package/dist/infra/context-tree/file-context-tree-writer-service.d.ts +5 -2
  85. package/dist/infra/context-tree/file-context-tree-writer-service.js +20 -5
  86. package/dist/infra/core/executors/curate-executor.d.ts +2 -2
  87. package/dist/infra/core/executors/curate-executor.js +7 -7
  88. package/dist/infra/core/executors/query-executor.d.ts +12 -0
  89. package/dist/infra/core/executors/query-executor.js +62 -1
  90. package/dist/infra/file/fs-file-service.d.ts +7 -0
  91. package/dist/infra/file/fs-file-service.js +15 -1
  92. package/dist/infra/mcp/index.d.ts +2 -0
  93. package/dist/infra/mcp/index.js +2 -0
  94. package/dist/infra/mcp/mcp-server.d.ts +58 -0
  95. package/dist/infra/mcp/mcp-server.js +178 -0
  96. package/dist/infra/mcp/tools/brv-curate-tool.d.ts +23 -0
  97. package/dist/infra/mcp/tools/brv-curate-tool.js +68 -0
  98. package/dist/infra/mcp/tools/brv-query-tool.d.ts +17 -0
  99. package/dist/infra/mcp/tools/brv-query-tool.js +68 -0
  100. package/dist/infra/mcp/tools/index.d.ts +3 -0
  101. package/dist/infra/mcp/tools/index.js +3 -0
  102. package/dist/infra/mcp/tools/task-result-waiter.d.ts +30 -0
  103. package/dist/infra/mcp/tools/task-result-waiter.js +56 -0
  104. package/dist/infra/process/agent-worker.d.ts +2 -2
  105. package/dist/infra/process/agent-worker.js +663 -142
  106. package/dist/infra/process/constants.d.ts +1 -1
  107. package/dist/infra/process/constants.js +1 -1
  108. package/dist/infra/process/ipc-types.d.ts +17 -4
  109. package/dist/infra/process/ipc-types.js +3 -3
  110. package/dist/infra/process/parent-heartbeat.d.ts +47 -0
  111. package/dist/infra/process/parent-heartbeat.js +118 -0
  112. package/dist/infra/process/process-manager.d.ts +79 -0
  113. package/dist/infra/process/process-manager.js +277 -3
  114. package/dist/infra/process/task-queue-manager.d.ts +13 -0
  115. package/dist/infra/process/task-queue-manager.js +19 -0
  116. package/dist/infra/process/transport-handlers.d.ts +3 -0
  117. package/dist/infra/process/transport-handlers.js +51 -5
  118. package/dist/infra/process/transport-worker.js +9 -69
  119. package/dist/infra/repl/commands/connectors-command.d.ts +8 -0
  120. package/dist/infra/repl/commands/{gen-rules-command.js → connectors-command.js} +21 -10
  121. package/dist/infra/repl/commands/curate-command.js +2 -2
  122. package/dist/infra/repl/commands/index.js +3 -2
  123. package/dist/infra/repl/commands/init-command.js +11 -7
  124. package/dist/infra/repl/commands/query-command.js +22 -2
  125. package/dist/infra/repl/commands/reset-command.js +1 -1
  126. package/dist/infra/transport/socket-io-transport-client.d.ts +75 -0
  127. package/dist/infra/transport/socket-io-transport-client.js +308 -7
  128. package/dist/infra/transport/socket-io-transport-server.js +4 -0
  129. package/dist/infra/usecase/connectors-use-case.d.ts +63 -0
  130. package/dist/infra/usecase/connectors-use-case.js +222 -0
  131. package/dist/infra/usecase/init-use-case.d.ts +8 -43
  132. package/dist/infra/usecase/init-use-case.js +27 -252
  133. package/dist/infra/usecase/logout-use-case.js +1 -1
  134. package/dist/infra/usecase/pull-use-case.js +5 -5
  135. package/dist/infra/usecase/push-use-case.js +4 -4
  136. package/dist/infra/usecase/reset-use-case.js +3 -4
  137. package/dist/infra/usecase/space-list-use-case.js +3 -3
  138. package/dist/infra/usecase/space-switch-use-case.js +3 -3
  139. package/dist/infra/usecase/status-use-case.d.ts +10 -0
  140. package/dist/infra/usecase/status-use-case.js +53 -0
  141. package/dist/resources/prompts/curate.yml +114 -4
  142. package/dist/resources/prompts/explore.yml +34 -0
  143. package/dist/resources/prompts/query-orchestrator.yml +112 -0
  144. package/dist/resources/prompts/system-prompt.yml +12 -2
  145. package/dist/resources/tools/search_knowledge.txt +32 -0
  146. package/dist/templates/mcp-base.md +1 -0
  147. package/dist/templates/sections/brv-instructions.md +98 -0
  148. package/dist/templates/sections/mcp-workflow.md +13 -0
  149. package/dist/tui/app.js +4 -1
  150. package/dist/tui/components/command-details.js +1 -1
  151. package/dist/tui/components/execution/execution-changes.d.ts +2 -0
  152. package/dist/tui/components/execution/execution-changes.js +5 -1
  153. package/dist/tui/components/execution/execution-content.d.ts +2 -0
  154. package/dist/tui/components/execution/execution-content.js +8 -18
  155. package/dist/tui/components/execution/execution-input.d.ts +2 -0
  156. package/dist/tui/components/execution/execution-input.js +6 -4
  157. package/dist/tui/components/execution/execution-progress.d.ts +2 -0
  158. package/dist/tui/components/execution/execution-progress.js +6 -2
  159. package/dist/tui/components/execution/expanded-log-view.d.ts +20 -0
  160. package/dist/tui/components/execution/expanded-log-view.js +75 -0
  161. package/dist/tui/components/execution/expanded-message-view.d.ts +24 -0
  162. package/dist/tui/components/execution/expanded-message-view.js +68 -0
  163. package/dist/tui/components/execution/index.d.ts +2 -0
  164. package/dist/tui/components/execution/index.js +2 -0
  165. package/dist/tui/components/execution/log-item.d.ts +4 -0
  166. package/dist/tui/components/execution/log-item.js +2 -2
  167. package/dist/tui/components/footer.js +1 -1
  168. package/dist/tui/components/index.d.ts +2 -1
  169. package/dist/tui/components/index.js +2 -1
  170. package/dist/tui/components/init.js +2 -9
  171. package/dist/tui/components/logo.js +4 -3
  172. package/dist/tui/components/markdown.d.ts +13 -0
  173. package/dist/tui/components/markdown.js +88 -0
  174. package/dist/tui/components/message-item.js +1 -1
  175. package/dist/tui/components/onboarding/onboarding-flow.js +14 -11
  176. package/dist/tui/components/onboarding/welcome-box.js +1 -1
  177. package/dist/tui/components/suggestions.js +3 -3
  178. package/dist/tui/contexts/mode-context.js +6 -2
  179. package/dist/tui/contexts/onboarding-context.d.ts +4 -0
  180. package/dist/tui/contexts/onboarding-context.js +14 -2
  181. package/dist/tui/hooks/index.d.ts +1 -0
  182. package/dist/tui/hooks/index.js +1 -0
  183. package/dist/tui/hooks/use-is-latest-version.d.ts +6 -0
  184. package/dist/tui/hooks/use-is-latest-version.js +22 -0
  185. package/dist/tui/views/command-view.d.ts +1 -1
  186. package/dist/tui/views/command-view.js +87 -98
  187. package/dist/tui/views/logs-view.d.ts +8 -0
  188. package/dist/tui/views/logs-view.js +55 -27
  189. package/dist/utils/file-validator.d.ts +1 -1
  190. package/dist/utils/file-validator.js +25 -28
  191. package/dist/utils/type-guards.d.ts +5 -0
  192. package/dist/utils/type-guards.js +7 -0
  193. package/oclif.manifest.json +55 -4
  194. package/package.json +12 -1
  195. package/dist/core/interfaces/usecase/i-generate-rules-use-case.d.ts +0 -3
  196. package/dist/infra/repl/commands/gen-rules-command.d.ts +0 -7
  197. package/dist/infra/rule/agent-rule-config.d.ts +0 -19
  198. package/dist/infra/rule/rule-template-service.d.ts +0 -18
  199. package/dist/infra/rule/rule-template-service.js +0 -88
  200. package/dist/infra/usecase/generate-rules-use-case.d.ts +0 -61
  201. package/dist/infra/usecase/generate-rules-use-case.js +0 -285
  202. /package/dist/core/interfaces/{usecase/i-generate-rules-use-case.js → connectors/connector-types.js} +0 -0
  203. /package/dist/infra/{rule → connectors/shared}/constants.d.ts +0 -0
  204. /package/dist/infra/{rule → connectors/shared}/constants.js +0 -0
@@ -0,0 +1,134 @@
1
+ /**
2
+ * Boundary markers for managed ByteRover MCP sections in TOML files.
3
+ */
4
+ export const BRV_MCP_TOML_MARKERS = {
5
+ END: '# END BYTEROVER MCP',
6
+ START: '# BEGIN BYTEROVER MCP',
7
+ };
8
+ /**
9
+ * Convert a JavaScript object to TOML format for MCP server config.
10
+ * Only handles simple key-value pairs and arrays (no nested objects).
11
+ */
12
+ function toTomlSection(sectionName, config) {
13
+ const lines = [`[${sectionName}]`];
14
+ for (const [key, value] of Object.entries(config)) {
15
+ if (value === undefined || value === null) {
16
+ continue;
17
+ }
18
+ if (typeof value === 'string') {
19
+ lines.push(`${key} = "${value}"`);
20
+ }
21
+ else if (typeof value === 'number' || typeof value === 'boolean') {
22
+ lines.push(`${key} = ${value}`);
23
+ }
24
+ else if (Array.isArray(value)) {
25
+ const arrayStr = value.map((v) => (typeof v === 'string' ? `"${v}"` : String(v))).join(', ');
26
+ lines.push(`${key} = [${arrayStr}]`);
27
+ }
28
+ // Skip nested objects for simplicity
29
+ }
30
+ return lines.join('\n');
31
+ }
32
+ /**
33
+ * MCP config writer for TOML format files.
34
+ * Uses marker-based insertion/replacement similar to rules connector.
35
+ */
36
+ export class TomlMcpConfigWriter {
37
+ fileService;
38
+ serverName;
39
+ constructor(options) {
40
+ this.fileService = options.fileService;
41
+ this.serverName = options.serverName;
42
+ }
43
+ async exists(filePath) {
44
+ const fileExists = await this.fileService.exists(filePath);
45
+ if (!fileExists) {
46
+ return { fileExists: false, serverExists: false };
47
+ }
48
+ try {
49
+ const content = await this.fileService.read(filePath);
50
+ const hasMarkers = content.includes(BRV_MCP_TOML_MARKERS.START) && content.includes(BRV_MCP_TOML_MARKERS.END);
51
+ return {
52
+ fileExists: true,
53
+ serverExists: hasMarkers,
54
+ };
55
+ }
56
+ catch {
57
+ return { fileExists: true, serverExists: false };
58
+ }
59
+ }
60
+ async remove(filePath) {
61
+ const fileExists = await this.fileService.exists(filePath);
62
+ if (!fileExists) {
63
+ return false;
64
+ }
65
+ const content = await this.fileService.read(filePath);
66
+ const hasMarkers = content.includes(BRV_MCP_TOML_MARKERS.START) && content.includes(BRV_MCP_TOML_MARKERS.END);
67
+ if (!hasMarkers) {
68
+ return false;
69
+ }
70
+ const newContent = this.removeMarkerSection(content);
71
+ // eslint-disable-next-line unicorn/prefer-ternary
72
+ if (newContent.trim() === '') {
73
+ await this.fileService.delete(filePath);
74
+ }
75
+ else {
76
+ await this.fileService.write(newContent, filePath, 'overwrite');
77
+ }
78
+ return true;
79
+ }
80
+ async write(filePath, serverConfig) {
81
+ const fileExists = await this.fileService.exists(filePath);
82
+ const mcpSection = this.buildMcpSection(serverConfig);
83
+ if (!fileExists) {
84
+ await this.fileService.write(mcpSection, filePath, 'overwrite');
85
+ return;
86
+ }
87
+ const content = await this.fileService.read(filePath);
88
+ const hasMarkers = content.includes(BRV_MCP_TOML_MARKERS.START) && content.includes(BRV_MCP_TOML_MARKERS.END);
89
+ if (hasMarkers) {
90
+ // Replace existing section
91
+ const newContent = this.replaceMarkerSection(content, mcpSection);
92
+ await this.fileService.write(newContent, filePath, 'overwrite');
93
+ }
94
+ else {
95
+ // Append to file
96
+ const newContent = content.trimEnd() + '\n\n' + mcpSection;
97
+ await this.fileService.write(newContent, filePath, 'overwrite');
98
+ }
99
+ }
100
+ /**
101
+ * Build the MCP section with markers.
102
+ */
103
+ buildMcpSection(serverConfig) {
104
+ const tomlContent = toTomlSection(`mcp_servers.${this.serverName}`, serverConfig);
105
+ return `${BRV_MCP_TOML_MARKERS.START}\n${tomlContent}\n${BRV_MCP_TOML_MARKERS.END}`;
106
+ }
107
+ /**
108
+ * Remove the section between markers (inclusive).
109
+ */
110
+ removeMarkerSection(content) {
111
+ const startIndex = content.indexOf(BRV_MCP_TOML_MARKERS.START);
112
+ const endIndex = content.indexOf(BRV_MCP_TOML_MARKERS.END);
113
+ if (startIndex === -1 || endIndex === -1) {
114
+ return content;
115
+ }
116
+ const before = content.slice(0, startIndex);
117
+ const after = content.slice(endIndex + BRV_MCP_TOML_MARKERS.END.length);
118
+ // Clean up extra newlines
119
+ return (before + after).replaceAll(/\n{3,}/g, '\n\n').trim();
120
+ }
121
+ /**
122
+ * Replace the section between markers with new content.
123
+ */
124
+ replaceMarkerSection(content, newSection) {
125
+ const startIndex = content.indexOf(BRV_MCP_TOML_MARKERS.START);
126
+ const endIndex = content.indexOf(BRV_MCP_TOML_MARKERS.END);
127
+ if (startIndex === -1 || endIndex === -1) {
128
+ return content;
129
+ }
130
+ const before = content.slice(0, startIndex);
131
+ const after = content.slice(endIndex + BRV_MCP_TOML_MARKERS.END.length);
132
+ return before + newSection + after;
133
+ }
134
+ }
@@ -1,5 +1,5 @@
1
- import type { Agent } from '../../core/domain/entities/agent.js';
2
- import type { ILegacyRuleDetector, LegacyRuleDetectionResult } from '../../core/interfaces/i-legacy-rule-detector.js';
1
+ import type { Agent } from '../../../core/domain/entities/agent.js';
2
+ import type { ILegacyRuleDetector, LegacyRuleDetectionResult } from '../../../core/interfaces/i-legacy-rule-detector.js';
3
3
  export declare class LegacyRuleDetector implements ILegacyRuleDetector {
4
4
  private static readonly SECTION_SEPARATOR_PATTERN;
5
5
  private static readonly WORKFLOW_HEADER_PATTERN;
@@ -1,4 +1,4 @@
1
- import { BRV_RULE_TAG } from './constants.js';
1
+ import { BRV_RULE_TAG } from '../shared/constants.js';
2
2
  export class LegacyRuleDetector {
3
3
  static SECTION_SEPARATOR_PATTERN = /^---\s*$/;
4
4
  static WORKFLOW_HEADER_PATTERN = /^#\sWorkflow Instruction$/;
@@ -0,0 +1,95 @@
1
+ import type { WriteMode } from '../../../core/interfaces/i-file-service.js';
2
+ /**
3
+ * Configuration for agent-specific rule files.
4
+ */
5
+ export type RulesConnectorConfig = {
6
+ /**
7
+ * The file path where the agent's rules should be written.
8
+ */
9
+ filePath: string;
10
+ /**
11
+ * The write mode to use when writing the rule file.
12
+ */
13
+ writeMode: WriteMode;
14
+ };
15
+ /**
16
+ * Mapping of agents to their rule file configurations.
17
+ */
18
+ export declare const RULES_CONNECTOR_CONFIGS: {
19
+ readonly Amp: {
20
+ readonly filePath: "AGENTS.md";
21
+ readonly writeMode: "append";
22
+ };
23
+ readonly 'Augment Code': {
24
+ readonly filePath: ".augment/rules/agent-context.md";
25
+ readonly writeMode: "overwrite";
26
+ };
27
+ readonly 'Claude Code': {
28
+ readonly filePath: "CLAUDE.md";
29
+ readonly writeMode: "append";
30
+ };
31
+ readonly Cline: {
32
+ readonly filePath: ".clinerules/agent-context.md";
33
+ readonly writeMode: "overwrite";
34
+ };
35
+ readonly Codex: {
36
+ readonly filePath: "AGENTS.md";
37
+ readonly writeMode: "append";
38
+ };
39
+ readonly Cursor: {
40
+ readonly filePath: ".cursor/rules/agent-context.mdc";
41
+ readonly writeMode: "overwrite";
42
+ };
43
+ readonly 'Gemini CLI': {
44
+ readonly filePath: "GEMINI.md";
45
+ readonly writeMode: "append";
46
+ };
47
+ readonly 'Github Copilot': {
48
+ readonly filePath: ".github/copilot-instructions.md";
49
+ readonly writeMode: "append";
50
+ };
51
+ readonly Junie: {
52
+ readonly filePath: ".junie/guidelines.md";
53
+ readonly writeMode: "append";
54
+ };
55
+ readonly 'Kilo Code': {
56
+ readonly filePath: ".kilocode/rules/agent-context.md";
57
+ readonly writeMode: "overwrite";
58
+ };
59
+ readonly Kiro: {
60
+ readonly filePath: ".kiro/steering/agent-context.md";
61
+ readonly writeMode: "overwrite";
62
+ };
63
+ readonly Qoder: {
64
+ readonly filePath: ".qoder/rules/agent-context.md";
65
+ readonly writeMode: "overwrite";
66
+ };
67
+ readonly 'Qwen Code': {
68
+ readonly filePath: "QWEN.md";
69
+ readonly writeMode: "append";
70
+ };
71
+ readonly 'Roo Code': {
72
+ readonly filePath: ".roo/rules/agent-context.md";
73
+ readonly writeMode: "overwrite";
74
+ };
75
+ readonly 'Trae.ai': {
76
+ readonly filePath: "project_rules.md";
77
+ readonly writeMode: "append";
78
+ };
79
+ readonly Warp: {
80
+ readonly filePath: "WARP.md";
81
+ readonly writeMode: "append";
82
+ };
83
+ readonly Windsurf: {
84
+ readonly filePath: ".windsurf/rules/agent-context.md";
85
+ readonly writeMode: "overwrite";
86
+ };
87
+ readonly Zed: {
88
+ readonly filePath: "agent-context.rules";
89
+ readonly writeMode: "overwrite";
90
+ };
91
+ };
92
+ /**
93
+ * Type for agents that have rules connector configurations.
94
+ */
95
+ export type RulesSupportedAgent = keyof typeof RULES_CONNECTOR_CONFIGS;
@@ -1,13 +1,13 @@
1
1
  /**
2
2
  * Mapping of agents to their rule file configurations.
3
3
  */
4
- export const AGENT_RULE_CONFIGS = {
4
+ export const RULES_CONNECTOR_CONFIGS = {
5
5
  Amp: {
6
6
  filePath: 'AGENTS.md',
7
7
  writeMode: 'append',
8
8
  },
9
9
  'Augment Code': {
10
- filePath: '.augment/rules/agent-context-engineering.md',
10
+ filePath: '.augment/rules/agent-context.md',
11
11
  writeMode: 'overwrite',
12
12
  },
13
13
  'Claude Code': {
@@ -15,7 +15,7 @@ export const AGENT_RULE_CONFIGS = {
15
15
  writeMode: 'append',
16
16
  },
17
17
  Cline: {
18
- filePath: '.clinerules/agent-context-engineering.md',
18
+ filePath: '.clinerules/agent-context.md',
19
19
  writeMode: 'overwrite',
20
20
  },
21
21
  Codex: {
@@ -23,7 +23,7 @@ export const AGENT_RULE_CONFIGS = {
23
23
  writeMode: 'append',
24
24
  },
25
25
  Cursor: {
26
- filePath: '.cursor/rules/agent-context-engineering.mdc',
26
+ filePath: '.cursor/rules/agent-context.mdc',
27
27
  writeMode: 'overwrite',
28
28
  },
29
29
  'Gemini CLI': {
@@ -39,15 +39,15 @@ export const AGENT_RULE_CONFIGS = {
39
39
  writeMode: 'append',
40
40
  },
41
41
  'Kilo Code': {
42
- filePath: '.kilocode/rules/agent-context-engineering.md',
42
+ filePath: '.kilocode/rules/agent-context.md',
43
43
  writeMode: 'overwrite',
44
44
  },
45
45
  Kiro: {
46
- filePath: '.kiro/steering/agent-context-engineering.md',
46
+ filePath: '.kiro/steering/agent-context.md',
47
47
  writeMode: 'overwrite',
48
48
  },
49
49
  Qoder: {
50
- filePath: '.qoder/rules/agent-context-engineering.md',
50
+ filePath: '.qoder/rules/agent-context.md',
51
51
  writeMode: 'overwrite',
52
52
  },
53
53
  'Qwen Code': {
@@ -55,7 +55,7 @@ export const AGENT_RULE_CONFIGS = {
55
55
  writeMode: 'append',
56
56
  },
57
57
  'Roo Code': {
58
- filePath: '.roo/rules/agent-context-engineering.md',
58
+ filePath: '.roo/rules/agent-context.md',
59
59
  writeMode: 'overwrite',
60
60
  },
61
61
  'Trae.ai': {
@@ -67,11 +67,11 @@ export const AGENT_RULE_CONFIGS = {
67
67
  writeMode: 'append',
68
68
  },
69
69
  Windsurf: {
70
- filePath: '.windsurf/rules/agent-context-engineering.md',
70
+ filePath: '.windsurf/rules/agent-context.md',
71
71
  writeMode: 'overwrite',
72
72
  },
73
73
  Zed: {
74
- filePath: 'agent-context-engineering.rules',
74
+ filePath: 'agent-context.rules',
75
75
  writeMode: 'overwrite',
76
76
  },
77
77
  };
@@ -0,0 +1,34 @@
1
+ import type { Agent } from '../../../core/domain/entities/agent.js';
2
+ import type { ConnectorType } from '../../../core/domain/entities/connector-type.js';
3
+ import type { ConnectorInstallResult, ConnectorStatus, ConnectorUninstallResult } from '../../../core/interfaces/connectors/connector-types.js';
4
+ import type { IConnector } from '../../../core/interfaces/connectors/i-connector.js';
5
+ import type { IFileService } from '../../../core/interfaces/i-file-service.js';
6
+ import type { IRuleTemplateService } from '../../../core/interfaces/i-rule-template-service.js';
7
+ /**
8
+ * Options for constructing RulesConnector.
9
+ */
10
+ type RulesConnectorOptions = {
11
+ fileService: IFileService;
12
+ projectRoot: string;
13
+ templateService: IRuleTemplateService;
14
+ };
15
+ /**
16
+ * Connector that integrates BRV with coding agents via rule files.
17
+ * Manages the installation, uninstallation, and status of rule files.
18
+ */
19
+ export declare class RulesConnector implements IConnector {
20
+ readonly type: ConnectorType;
21
+ private readonly fileService;
22
+ private readonly projectRoot;
23
+ private readonly ruleFileManager;
24
+ private readonly supportedAgents;
25
+ private readonly templateService;
26
+ constructor(options: RulesConnectorOptions);
27
+ getConfigPath(agent: Agent): string;
28
+ getSupportedAgents(): Agent[];
29
+ install(agent: Agent): Promise<ConnectorInstallResult>;
30
+ isSupported(agent: Agent): boolean;
31
+ status(agent: Agent): Promise<ConnectorStatus>;
32
+ uninstall(agent: Agent): Promise<ConnectorUninstallResult>;
33
+ }
34
+ export {};
@@ -0,0 +1,139 @@
1
+ import path from 'node:path';
2
+ import { AGENT_CONNECTOR_CONFIG } from '../../../core/domain/entities/agent.js';
3
+ import { RuleFileManager } from '../shared/rule-file-manager.js';
4
+ import { RULES_CONNECTOR_CONFIGS } from './rules-connector-config.js';
5
+ /**
6
+ * Connector that integrates BRV with coding agents via rule files.
7
+ * Manages the installation, uninstallation, and status of rule files.
8
+ */
9
+ export class RulesConnector {
10
+ type = 'rules';
11
+ fileService;
12
+ projectRoot;
13
+ ruleFileManager;
14
+ supportedAgents;
15
+ templateService;
16
+ constructor(options) {
17
+ this.fileService = options.fileService;
18
+ this.projectRoot = options.projectRoot;
19
+ this.templateService = options.templateService;
20
+ this.ruleFileManager = new RuleFileManager({
21
+ fileService: options.fileService,
22
+ projectRoot: options.projectRoot,
23
+ });
24
+ this.supportedAgents = Object.entries(AGENT_CONNECTOR_CONFIG)
25
+ .filter(([_, config]) => config.supported.includes(this.type))
26
+ .map(([agent]) => agent);
27
+ }
28
+ getConfigPath(agent) {
29
+ return RULES_CONNECTOR_CONFIGS[agent].filePath;
30
+ }
31
+ getSupportedAgents() {
32
+ return this.supportedAgents;
33
+ }
34
+ async install(agent) {
35
+ const config = RULES_CONNECTOR_CONFIGS[agent];
36
+ try {
37
+ const ruleContent = await this.templateService.generateRuleContent(agent, this.type);
38
+ // Write the rule content to the file
39
+ await this.ruleFileManager.install(config.filePath, config.writeMode, ruleContent);
40
+ return {
41
+ alreadyInstalled: false,
42
+ configPath: config.filePath,
43
+ message: `Rules connector installed for ${agent} (created ${config.filePath})`,
44
+ success: true,
45
+ };
46
+ }
47
+ catch (error) {
48
+ return {
49
+ alreadyInstalled: false,
50
+ configPath: config.filePath,
51
+ message: `Failed to install rules connector for ${agent}: ${error instanceof Error ? error.message : String(error)}`,
52
+ success: false,
53
+ };
54
+ }
55
+ }
56
+ isSupported(agent) {
57
+ return AGENT_CONNECTOR_CONFIG[agent].supported.includes(this.type);
58
+ }
59
+ async status(agent) {
60
+ const config = RULES_CONNECTOR_CONFIGS[agent];
61
+ const fullPath = path.join(this.projectRoot, config.filePath);
62
+ try {
63
+ const { fileExists, hasMarkers } = await this.ruleFileManager.status(config.filePath);
64
+ if (!fileExists) {
65
+ return {
66
+ configExists: false,
67
+ configPath: config.filePath,
68
+ installed: false,
69
+ };
70
+ }
71
+ const content = await this.fileService.read(fullPath);
72
+ const hasMcpTools = content.includes('brv-query') || content.includes('brv-curate');
73
+ // For overwrite files, any BRV content means installed
74
+ // For append files, need both markers and agent tag
75
+ const installed = hasMarkers && !hasMcpTools;
76
+ return {
77
+ configExists: true,
78
+ configPath: config.filePath,
79
+ installed,
80
+ };
81
+ }
82
+ catch (error) {
83
+ return {
84
+ configExists: true,
85
+ configPath: config.filePath,
86
+ error: error instanceof Error ? error.message : String(error),
87
+ installed: false,
88
+ };
89
+ }
90
+ }
91
+ async uninstall(agent) {
92
+ const config = RULES_CONNECTOR_CONFIGS[agent];
93
+ try {
94
+ const { fileExists, hasLegacyTag, hasMarkers } = await this.ruleFileManager.status(config.filePath);
95
+ if (!fileExists) {
96
+ return {
97
+ configPath: config.filePath,
98
+ message: `Rule file does not exist: ${config.filePath}`,
99
+ success: true,
100
+ wasInstalled: false,
101
+ };
102
+ }
103
+ if (!hasMarkers) {
104
+ if (!hasLegacyTag) {
105
+ return {
106
+ configPath: config.filePath,
107
+ message: `Rules connector is not installed for ${agent}`,
108
+ success: true,
109
+ wasInstalled: false,
110
+ };
111
+ }
112
+ // Legacy format detected - cannot safely uninstall
113
+ return {
114
+ configPath: config.filePath,
115
+ message: `Legacy rules detected for ${agent}. Please manually remove the old rules section.`,
116
+ success: false,
117
+ wasInstalled: true,
118
+ };
119
+ }
120
+ const result = await this.ruleFileManager.uninstall(config.filePath, config.writeMode);
121
+ return {
122
+ configPath: config.filePath,
123
+ message: result.wasInstalled
124
+ ? `Rules connector uninstalled for ${agent}`
125
+ : `Rules connector is not installed for ${agent}`,
126
+ success: true,
127
+ wasInstalled: result.wasInstalled,
128
+ };
129
+ }
130
+ catch (error) {
131
+ return {
132
+ configPath: config.filePath,
133
+ message: `Failed to uninstall rules connector for ${agent}: ${error instanceof Error ? error.message : String(error)}`,
134
+ success: false,
135
+ wasInstalled: true,
136
+ };
137
+ }
138
+ }
139
+ }
@@ -0,0 +1,72 @@
1
+ import type { IFileService, WriteMode } from '../../../core/interfaces/i-file-service.js';
2
+ /**
3
+ * Result of a rule file installation operation.
4
+ */
5
+ export type RuleFileInstallResult = {
6
+ /** Whether the content was newly installed (false if replaced existing) */
7
+ isNew: boolean;
8
+ /** Whether the operation succeeded */
9
+ success: boolean;
10
+ };
11
+ /**
12
+ * Result of a rule file uninstallation operation.
13
+ */
14
+ export type RuleFileUninstallResult = {
15
+ /** Whether the operation succeeded */
16
+ success: boolean;
17
+ /** Whether there was content to remove */
18
+ wasInstalled: boolean;
19
+ };
20
+ /**
21
+ * Result of a rule file status check.
22
+ */
23
+ export type RuleFileStatusResult = {
24
+ /** Whether the file exists */
25
+ fileExists: boolean;
26
+ /** Whether the file contains legacy BRV tag (without markers) */
27
+ hasLegacyTag: boolean;
28
+ /** Whether the file contains BRV markers */
29
+ hasMarkers: boolean;
30
+ };
31
+ /**
32
+ * Manages rule file operations including installation, uninstallation,
33
+ * and marker section manipulation.
34
+ *
35
+ * This class centralizes the logic for working with rule files that use
36
+ * BRV markers to delimit managed content sections.
37
+ */
38
+ export declare class RuleFileManager {
39
+ private readonly fileService;
40
+ private readonly projectRoot;
41
+ constructor(options: {
42
+ fileService: IFileService;
43
+ projectRoot: string;
44
+ });
45
+ /**
46
+ * Install rule content into a file.
47
+ *
48
+ * @param filePath - Relative path to the rule file
49
+ * @param writeMode - How to write the content ('overwrite' or 'append')
50
+ * @param ruleContent - The rule content to write (should include markers)
51
+ */
52
+ install(filePath: string, writeMode: WriteMode, ruleContent: string): Promise<RuleFileInstallResult>;
53
+ /**
54
+ * Removes the section between BRV markers (inclusive).
55
+ */
56
+ removeMarkerSection(content: string): string;
57
+ /**
58
+ * Replaces the section between BRV markers with new content.
59
+ */
60
+ replaceMarkerSection(content: string, newRuleContent: string): string;
61
+ /**
62
+ * Check the status of rule content in a file.
63
+ */
64
+ status(filePath: string): Promise<RuleFileStatusResult>;
65
+ /**
66
+ * Uninstall rule content from a file.
67
+ *
68
+ * @param filePath - Relative path to the rule file
69
+ * @param writeMode - How the content was written ('overwrite' or 'append')
70
+ */
71
+ uninstall(filePath: string, writeMode: WriteMode): Promise<RuleFileUninstallResult>;
72
+ }
@@ -0,0 +1,119 @@
1
+ import path from 'node:path';
2
+ import { BRV_RULE_MARKERS, BRV_RULE_TAG } from './constants.js';
3
+ /**
4
+ * Manages rule file operations including installation, uninstallation,
5
+ * and marker section manipulation.
6
+ *
7
+ * This class centralizes the logic for working with rule files that use
8
+ * BRV markers to delimit managed content sections.
9
+ */
10
+ export class RuleFileManager {
11
+ fileService;
12
+ projectRoot;
13
+ constructor(options) {
14
+ this.fileService = options.fileService;
15
+ this.projectRoot = options.projectRoot;
16
+ }
17
+ /**
18
+ * Install rule content into a file.
19
+ *
20
+ * @param filePath - Relative path to the rule file
21
+ * @param writeMode - How to write the content ('overwrite' or 'append')
22
+ * @param ruleContent - The rule content to write (should include markers)
23
+ */
24
+ async install(filePath, writeMode, ruleContent) {
25
+ const fullPath = path.join(this.projectRoot, filePath);
26
+ const exists = await this.fileService.exists(fullPath);
27
+ if (exists) {
28
+ const content = await this.fileService.read(fullPath);
29
+ const hasMarkers = content.includes(BRV_RULE_MARKERS.START) && content.includes(BRV_RULE_MARKERS.END);
30
+ if (writeMode === 'overwrite') {
31
+ await this.fileService.write(ruleContent, fullPath, 'overwrite');
32
+ }
33
+ else if (hasMarkers) {
34
+ // Replace existing markers section
35
+ const newContent = this.replaceMarkerSection(content, ruleContent);
36
+ await this.fileService.write(newContent, fullPath, 'overwrite');
37
+ }
38
+ else {
39
+ // Append to file
40
+ await this.fileService.write(ruleContent, fullPath, 'append');
41
+ }
42
+ return { isNew: !hasMarkers, success: true };
43
+ }
44
+ // File doesn't exist - create it
45
+ await this.fileService.write(ruleContent, fullPath, 'overwrite');
46
+ return { isNew: true, success: true };
47
+ }
48
+ /**
49
+ * Removes the section between BRV markers (inclusive).
50
+ */
51
+ removeMarkerSection(content) {
52
+ const startIndex = content.indexOf(BRV_RULE_MARKERS.START);
53
+ const endIndex = content.indexOf(BRV_RULE_MARKERS.END);
54
+ if (startIndex === -1 || endIndex === -1) {
55
+ return content;
56
+ }
57
+ const before = content.slice(0, startIndex);
58
+ const after = content.slice(endIndex + BRV_RULE_MARKERS.END.length);
59
+ // Clean up extra newlines
60
+ return (before + after).replaceAll(/\n{3,}/g, '\n\n').trim();
61
+ }
62
+ /**
63
+ * Replaces the section between BRV markers with new content.
64
+ */
65
+ replaceMarkerSection(content, newRuleContent) {
66
+ const startIndex = content.indexOf(BRV_RULE_MARKERS.START);
67
+ const endIndex = content.indexOf(BRV_RULE_MARKERS.END);
68
+ if (startIndex === -1 || endIndex === -1) {
69
+ return content;
70
+ }
71
+ const before = content.slice(0, startIndex);
72
+ const after = content.slice(endIndex + BRV_RULE_MARKERS.END.length);
73
+ return before + newRuleContent + after;
74
+ }
75
+ /**
76
+ * Check the status of rule content in a file.
77
+ */
78
+ async status(filePath) {
79
+ const fullPath = path.join(this.projectRoot, filePath);
80
+ const fileExists = await this.fileService.exists(fullPath);
81
+ if (!fileExists) {
82
+ return { fileExists: false, hasLegacyTag: false, hasMarkers: false };
83
+ }
84
+ const content = await this.fileService.read(fullPath);
85
+ const hasMarkers = content.includes(BRV_RULE_MARKERS.START) && content.includes(BRV_RULE_MARKERS.END);
86
+ const hasLegacyTag = content.includes(BRV_RULE_TAG);
87
+ return { fileExists: true, hasLegacyTag, hasMarkers };
88
+ }
89
+ /**
90
+ * Uninstall rule content from a file.
91
+ *
92
+ * @param filePath - Relative path to the rule file
93
+ * @param writeMode - How the content was written ('overwrite' or 'append')
94
+ */
95
+ async uninstall(filePath, writeMode) {
96
+ const fullPath = path.join(this.projectRoot, filePath);
97
+ const exists = await this.fileService.exists(fullPath);
98
+ if (!exists) {
99
+ return { success: true, wasInstalled: false };
100
+ }
101
+ const content = await this.fileService.read(fullPath);
102
+ const hasMarkers = content.includes(BRV_RULE_MARKERS.START) && content.includes(BRV_RULE_MARKERS.END);
103
+ if (!hasMarkers) {
104
+ return { success: true, wasInstalled: false };
105
+ }
106
+ if (writeMode === 'overwrite') {
107
+ // For dedicated files, delete the entire file
108
+ await this.fileService.delete(fullPath);
109
+ }
110
+ else {
111
+ // For shared files, remove only the BRV section
112
+ const newContent = this.removeMarkerSection(content);
113
+ await (newContent.trim() === ''
114
+ ? this.fileService.delete(fullPath)
115
+ : this.fileService.write(newContent, fullPath, 'overwrite'));
116
+ }
117
+ return { success: true, wasInstalled: true };
118
+ }
119
+ }