byterover-cli 1.0.4 → 1.1.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 (172) hide show
  1. package/README.md +24 -11
  2. package/dist/commands/curate.js +1 -1
  3. package/dist/commands/hook-prompt-submit.d.ts +27 -0
  4. package/dist/commands/hook-prompt-submit.js +39 -0
  5. package/dist/commands/main.d.ts +13 -0
  6. package/dist/commands/main.js +53 -2
  7. package/dist/commands/query.js +1 -1
  8. package/dist/commands/status.js +8 -3
  9. package/dist/constants.d.ts +2 -2
  10. package/dist/constants.js +2 -2
  11. package/dist/core/domain/cipher/llm/registry.js +53 -2
  12. package/dist/core/domain/cipher/llm/types.d.ts +2 -0
  13. package/dist/core/domain/cipher/process/types.d.ts +7 -0
  14. package/dist/core/domain/cipher/session/session-metadata.d.ts +178 -0
  15. package/dist/core/domain/cipher/session/session-metadata.js +147 -0
  16. package/dist/core/domain/cipher/tools/constants.d.ts +1 -0
  17. package/dist/core/domain/cipher/tools/constants.js +1 -0
  18. package/dist/core/domain/entities/agent.d.ts +16 -0
  19. package/dist/core/domain/entities/agent.js +24 -0
  20. package/dist/core/domain/entities/connector-type.d.ts +9 -0
  21. package/dist/core/domain/entities/connector-type.js +8 -0
  22. package/dist/core/domain/entities/event.d.ts +1 -1
  23. package/dist/core/domain/entities/event.js +2 -0
  24. package/dist/core/domain/errors/task-error.d.ts +4 -0
  25. package/dist/core/domain/errors/task-error.js +7 -0
  26. package/dist/core/domain/knowledge/markdown-writer.d.ts +15 -18
  27. package/dist/core/domain/knowledge/markdown-writer.js +232 -34
  28. package/dist/core/domain/knowledge/relation-parser.d.ts +25 -39
  29. package/dist/core/domain/knowledge/relation-parser.js +39 -61
  30. package/dist/core/domain/transport/schemas.d.ts +77 -2
  31. package/dist/core/domain/transport/schemas.js +51 -2
  32. package/dist/core/interfaces/cipher/i-session-persistence.d.ts +133 -0
  33. package/dist/core/interfaces/cipher/i-session-persistence.js +7 -0
  34. package/dist/core/interfaces/cipher/message-types.d.ts +6 -0
  35. package/dist/core/interfaces/connectors/connector-types.d.ts +57 -0
  36. package/dist/core/interfaces/connectors/i-connector-manager.d.ts +72 -0
  37. package/dist/core/interfaces/connectors/i-connector.d.ts +54 -0
  38. package/dist/core/interfaces/connectors/i-connector.js +1 -0
  39. package/dist/core/interfaces/executor/i-curate-executor.d.ts +2 -2
  40. package/dist/core/interfaces/i-context-file-reader.d.ts +3 -0
  41. package/dist/core/interfaces/i-file-service.d.ts +7 -0
  42. package/dist/core/interfaces/usecase/i-connectors-use-case.d.ts +3 -0
  43. package/dist/core/interfaces/usecase/i-connectors-use-case.js +1 -0
  44. package/dist/core/interfaces/usecase/{i-clear-use-case.d.ts → i-reset-use-case.d.ts} +1 -1
  45. package/dist/core/interfaces/usecase/i-reset-use-case.js +1 -0
  46. package/dist/hooks/init/update-notifier.d.ts +1 -0
  47. package/dist/hooks/init/update-notifier.js +10 -1
  48. package/dist/infra/cipher/agent/agent-schemas.d.ts +6 -6
  49. package/dist/infra/cipher/agent/service-initializer.js +4 -4
  50. package/dist/infra/cipher/file-system/binary-utils.d.ts +7 -12
  51. package/dist/infra/cipher/file-system/binary-utils.js +46 -31
  52. package/dist/infra/cipher/file-system/context-tree-file-system-factory.js +3 -2
  53. package/dist/infra/cipher/file-system/file-system-service.js +1 -0
  54. package/dist/infra/cipher/http/internal-llm-http-service.js +3 -5
  55. package/dist/infra/cipher/interactive-loop.js +3 -1
  56. package/dist/infra/cipher/llm/context/context-manager.d.ts +2 -2
  57. package/dist/infra/cipher/llm/context/context-manager.js +63 -18
  58. package/dist/infra/cipher/llm/formatters/gemini-formatter.d.ts +13 -0
  59. package/dist/infra/cipher/llm/formatters/gemini-formatter.js +146 -15
  60. package/dist/infra/cipher/llm/generators/byterover-content-generator.js +6 -2
  61. package/dist/infra/cipher/llm/internal-llm-service.js +2 -2
  62. package/dist/infra/cipher/llm/thought-parser.d.ts +21 -0
  63. package/dist/infra/cipher/llm/thought-parser.js +27 -0
  64. package/dist/infra/cipher/llm/tool-output-processor.d.ts +10 -0
  65. package/dist/infra/cipher/llm/tool-output-processor.js +80 -7
  66. package/dist/infra/cipher/process/process-service.js +11 -3
  67. package/dist/infra/cipher/session/chat-session.d.ts +7 -2
  68. package/dist/infra/cipher/session/chat-session.js +90 -52
  69. package/dist/infra/cipher/session/session-metadata-store.d.ts +52 -0
  70. package/dist/infra/cipher/session/session-metadata-store.js +406 -0
  71. package/dist/infra/cipher/system-prompt/contributors/context-tree-structure-contributor.d.ts +6 -7
  72. package/dist/infra/cipher/system-prompt/contributors/context-tree-structure-contributor.js +57 -18
  73. package/dist/infra/cipher/tools/implementations/curate-tool.js +132 -36
  74. package/dist/infra/cipher/tools/implementations/read-file-tool.js +38 -17
  75. package/dist/infra/cipher/tools/implementations/search-knowledge-tool.d.ts +7 -0
  76. package/dist/infra/cipher/tools/implementations/search-knowledge-tool.js +303 -0
  77. package/dist/infra/cipher/tools/implementations/task-tool.js +1 -0
  78. package/dist/infra/cipher/tools/index.d.ts +1 -0
  79. package/dist/infra/cipher/tools/index.js +1 -0
  80. package/dist/infra/cipher/tools/tool-manager.js +1 -0
  81. package/dist/infra/cipher/tools/tool-registry.js +7 -0
  82. package/dist/infra/connectors/connector-manager.d.ts +32 -0
  83. package/dist/infra/connectors/connector-manager.js +156 -0
  84. package/dist/infra/connectors/hook/hook-connector-config.d.ts +52 -0
  85. package/dist/infra/connectors/hook/hook-connector-config.js +41 -0
  86. package/dist/infra/connectors/hook/hook-connector.d.ts +46 -0
  87. package/dist/infra/connectors/hook/hook-connector.js +231 -0
  88. package/dist/infra/{rule → connectors/rules}/legacy-rule-detector.d.ts +2 -2
  89. package/dist/infra/{rule → connectors/rules}/legacy-rule-detector.js +1 -1
  90. package/dist/infra/connectors/rules/rules-connector-config.d.ts +95 -0
  91. package/dist/infra/{rule/agent-rule-config.js → connectors/rules/rules-connector-config.js} +10 -10
  92. package/dist/infra/connectors/rules/rules-connector.d.ts +41 -0
  93. package/dist/infra/connectors/rules/rules-connector.js +204 -0
  94. package/dist/infra/{rule/rule-template-service.d.ts → connectors/shared/template-service.d.ts} +3 -3
  95. package/dist/infra/{rule/rule-template-service.js → connectors/shared/template-service.js} +1 -1
  96. package/dist/infra/context-tree/file-context-file-reader.js +4 -0
  97. package/dist/infra/context-tree/file-context-tree-writer-service.d.ts +5 -2
  98. package/dist/infra/context-tree/file-context-tree-writer-service.js +20 -5
  99. package/dist/infra/core/executors/curate-executor.d.ts +2 -2
  100. package/dist/infra/core/executors/curate-executor.js +7 -7
  101. package/dist/infra/core/executors/query-executor.d.ts +12 -0
  102. package/dist/infra/core/executors/query-executor.js +62 -1
  103. package/dist/infra/core/task-processor.d.ts +2 -2
  104. package/dist/infra/file/fs-file-service.d.ts +7 -0
  105. package/dist/infra/file/fs-file-service.js +15 -1
  106. package/dist/infra/process/agent-worker.d.ts +2 -2
  107. package/dist/infra/process/agent-worker.js +626 -142
  108. package/dist/infra/process/constants.d.ts +1 -1
  109. package/dist/infra/process/constants.js +1 -1
  110. package/dist/infra/process/ipc-types.d.ts +17 -4
  111. package/dist/infra/process/ipc-types.js +3 -3
  112. package/dist/infra/process/parent-heartbeat.d.ts +47 -0
  113. package/dist/infra/process/parent-heartbeat.js +118 -0
  114. package/dist/infra/process/process-manager.d.ts +89 -1
  115. package/dist/infra/process/process-manager.js +293 -9
  116. package/dist/infra/process/task-queue-manager.d.ts +13 -0
  117. package/dist/infra/process/task-queue-manager.js +19 -0
  118. package/dist/infra/process/transport-handlers.d.ts +3 -0
  119. package/dist/infra/process/transport-handlers.js +82 -5
  120. package/dist/infra/process/transport-worker.js +9 -69
  121. package/dist/infra/repl/commands/connectors-command.d.ts +8 -0
  122. package/dist/infra/repl/commands/{gen-rules-command.js → connectors-command.js} +21 -10
  123. package/dist/infra/repl/commands/index.js +8 -4
  124. package/dist/infra/repl/commands/init-command.js +11 -7
  125. package/dist/infra/repl/commands/new-command.d.ts +14 -0
  126. package/dist/infra/repl/commands/new-command.js +61 -0
  127. package/dist/infra/repl/commands/query-command.js +22 -2
  128. package/dist/infra/repl/commands/{clear-command.d.ts → reset-command.d.ts} +2 -2
  129. package/dist/infra/repl/commands/{clear-command.js → reset-command.js} +11 -11
  130. package/dist/infra/transport/socket-io-transport-client.d.ts +68 -0
  131. package/dist/infra/transport/socket-io-transport-client.js +283 -7
  132. package/dist/infra/usecase/connectors-use-case.d.ts +59 -0
  133. package/dist/infra/usecase/connectors-use-case.js +203 -0
  134. package/dist/infra/usecase/init-use-case.d.ts +8 -43
  135. package/dist/infra/usecase/init-use-case.js +29 -253
  136. package/dist/infra/usecase/logout-use-case.js +2 -2
  137. package/dist/infra/usecase/pull-use-case.js +5 -5
  138. package/dist/infra/usecase/push-use-case.js +5 -5
  139. package/dist/infra/usecase/{clear-use-case.d.ts → reset-use-case.d.ts} +5 -5
  140. package/dist/infra/usecase/{clear-use-case.js → reset-use-case.js} +7 -8
  141. package/dist/infra/usecase/space-list-use-case.js +3 -3
  142. package/dist/infra/usecase/space-switch-use-case.js +3 -3
  143. package/dist/resources/prompts/curate.yml +75 -13
  144. package/dist/resources/prompts/explore.yml +34 -0
  145. package/dist/resources/prompts/query-orchestrator.yml +112 -0
  146. package/dist/resources/prompts/system-prompt.yml +12 -2
  147. package/dist/resources/tools/curate.txt +60 -15
  148. package/dist/resources/tools/search_knowledge.txt +32 -0
  149. package/dist/templates/sections/brv-instructions.md +98 -0
  150. package/dist/tui/components/inline-prompts/inline-confirm.js +2 -2
  151. package/dist/tui/components/onboarding/onboarding-flow.js +14 -10
  152. package/dist/tui/components/onboarding/welcome-box.js +1 -1
  153. package/dist/tui/contexts/onboarding-context.d.ts +4 -0
  154. package/dist/tui/contexts/onboarding-context.js +14 -2
  155. package/dist/tui/views/command-view.js +19 -0
  156. package/dist/utils/file-validator.d.ts +1 -1
  157. package/dist/utils/file-validator.js +34 -35
  158. package/dist/utils/type-guards.d.ts +5 -0
  159. package/dist/utils/type-guards.js +7 -0
  160. package/oclif.manifest.json +32 -6
  161. package/package.json +4 -1
  162. package/dist/config/context-tree-domains.d.ts +0 -29
  163. package/dist/config/context-tree-domains.js +0 -29
  164. package/dist/core/interfaces/usecase/i-generate-rules-use-case.d.ts +0 -3
  165. package/dist/infra/repl/commands/gen-rules-command.d.ts +0 -7
  166. package/dist/infra/rule/agent-rule-config.d.ts +0 -19
  167. package/dist/infra/usecase/generate-rules-use-case.d.ts +0 -61
  168. package/dist/infra/usecase/generate-rules-use-case.js +0 -285
  169. /package/dist/core/interfaces/{usecase/i-clear-use-case.js → connectors/connector-types.js} +0 -0
  170. /package/dist/core/interfaces/{usecase/i-generate-rules-use-case.js → connectors/i-connector-manager.js} +0 -0
  171. /package/dist/infra/{rule → connectors/shared}/constants.d.ts +0 -0
  172. /package/dist/infra/{rule → connectors/shared}/constants.js +0 -0
@@ -22,6 +22,8 @@ export interface OnboardingContextValue {
22
22
  hasCurated: boolean;
23
23
  /** Whether query has been completed at least once */
24
24
  hasQueried: boolean;
25
+ /** Whether user has acknowledged init completion */
26
+ initAcknowledged: boolean;
25
27
  /** Whether the project is initialized (brvConfig exists) */
26
28
  isInitialized: boolean;
27
29
  /** Whether we're still loading the dismissed state */
@@ -30,6 +32,8 @@ export interface OnboardingContextValue {
30
32
  queryAcknowledged: boolean;
31
33
  /** Set curate acknowledged state */
32
34
  setCurateAcknowledged: (value: boolean) => void;
35
+ /** Set init acknowledged state */
36
+ setInitAcknowledged: (value: boolean) => void;
33
37
  /** Set query acknowledged state */
34
38
  setQueryAcknowledged: (value: boolean) => void;
35
39
  /** Whether onboarding should be shown */
@@ -65,6 +65,7 @@ export function OnboardingProvider({ children }) {
65
65
  }
66
66
  }, [isInitialConfigLoaded, isInitialized]);
67
67
  // Track acknowledgment for completed steps (user pressed Enter after seeing output)
68
+ const [initAcknowledged, setInitAcknowledgedState] = useState(false);
68
69
  const [curateAcknowledged, setCurateAcknowledgedState] = useState(false);
69
70
  const [queryAcknowledged, setQueryAcknowledgedState] = useState(false);
70
71
  // Track if init was completed during this onboarding session (to avoid duplicate tracking)
@@ -76,6 +77,10 @@ export function OnboardingProvider({ children }) {
76
77
  trackingService.track('onboarding:init_completed');
77
78
  }
78
79
  }, [isInitialized, trackingService]);
80
+ // Wrapper for setInitAcknowledged that also tracks
81
+ const setInitAcknowledged = useCallback((value) => {
82
+ setInitAcknowledgedState(value);
83
+ }, []);
79
84
  // Wrapper for setCurateAcknowledged that also tracks
80
85
  const setCurateAcknowledged = useCallback((value) => {
81
86
  setCurateAcknowledgedState(value);
@@ -110,10 +115,13 @@ export function OnboardingProvider({ children }) {
110
115
  return { hasCurated: curateCompleted, hasQueried: queryCompleted };
111
116
  }, [tasks]);
112
117
  // Derive current step (considering acknowledgment)
113
- // Stay on curate/query step until user acknowledges the completion
118
+ // Stay on each step until user acknowledges the completion
114
119
  const currentStep = useMemo(() => {
115
120
  if (!isInitialized)
116
121
  return 'init';
122
+ // isInitialized is true but not yet acknowledged -> stay on init
123
+ if (!initAcknowledged)
124
+ return 'init';
117
125
  if (!hasCurated)
118
126
  return 'curate';
119
127
  // hasCurated is true but not yet acknowledged -> stay on curate
@@ -125,7 +133,7 @@ export function OnboardingProvider({ children }) {
125
133
  if (!queryAcknowledged)
126
134
  return 'query';
127
135
  return 'complete';
128
- }, [isInitialized, hasCurated, hasQueried, curateAcknowledged, queryAcknowledged]);
136
+ }, [isInitialized, initAcknowledged, hasCurated, hasQueried, curateAcknowledged, queryAcknowledged]);
129
137
  // Show onboarding if:
130
138
  // 1. Project was not initialized after initial config check, AND
131
139
  // 2. User has never dismissed onboarding before (persisted)
@@ -146,10 +154,12 @@ export function OnboardingProvider({ children }) {
146
154
  currentStep,
147
155
  hasCurated,
148
156
  hasQueried,
157
+ initAcknowledged,
149
158
  isInitialized,
150
159
  isLoadingDismissed,
151
160
  queryAcknowledged,
152
161
  setCurateAcknowledged,
162
+ setInitAcknowledged,
153
163
  setQueryAcknowledged,
154
164
  shouldShowOnboarding,
155
165
  totalSteps: 3, // init, curate, query (complete is not counted)
@@ -160,9 +170,11 @@ export function OnboardingProvider({ children }) {
160
170
  hasCurated,
161
171
  hasQueried,
162
172
  hasDismissed,
173
+ initAcknowledged,
163
174
  isInitialized,
164
175
  isLoadingDismissed,
165
176
  queryAcknowledged,
177
+ setInitAcknowledged,
166
178
  shouldShowOnboarding,
167
179
  ]);
168
180
  return _jsx(OnboardingContext.Provider, { value: contextValue, children: children });
@@ -231,6 +231,7 @@ export const CommandView = ({ availableHeight }) => {
231
231
  };
232
232
  }
233
233
  }, [activePrompt?.type, appendShortcuts, removeShortcuts]);
234
+ /* eslint-disable complexity -- Command execution requires handling multiple command types and states */
234
235
  const executeCommand = useCallback(async (value) => {
235
236
  const trimmed = value.trim();
236
237
  if (!trimmed)
@@ -301,6 +302,23 @@ export const CommandView = ({ availableHeight }) => {
301
302
  setActivePrompt(null);
302
303
  const needReloadAuth = trimmed.startsWith('/login') || trimmed.startsWith('/logout');
303
304
  const needReloadBrvConfig = trimmed.startsWith('/space switch') || trimmed.startsWith('/init');
305
+ const needNewSession = trimmed.startsWith('/new');
306
+ // Handle /new command - create new session and clear messages
307
+ if (needNewSession && client) {
308
+ try {
309
+ const response = await client.request('agent:newSession', { reason: 'User requested new session' });
310
+ /* eslint-disable max-depth -- UI state handling requires this nesting level */
311
+ if (response.success) {
312
+ // Clear the messages to start fresh
313
+ setMessages([]);
314
+ clearTasks();
315
+ }
316
+ }
317
+ catch {
318
+ // Error handling - the command already showed feedback
319
+ }
320
+ /* eslint-enable max-depth */
321
+ }
304
322
  // Refresh state after commands that change auth or project state
305
323
  if (needReloadAuth || needReloadBrvConfig) {
306
324
  clearTasks();
@@ -323,6 +341,7 @@ export const CommandView = ({ availableHeight }) => {
323
341
  }
324
342
  }
325
343
  }, [clearTasks, client, exit, handleSlashCommand, reloadAuth, reloadBrvConfig]);
344
+ /* eslint-enable complexity */
326
345
  const handleSubmit = useCallback(async (value) => {
327
346
  if (mode === 'console' && !isStreaming) {
328
347
  await executeCommand(value);
@@ -3,7 +3,7 @@
3
3
  * Checks:
4
4
  * 1. File exists
5
5
  * 2. File is within project directory (where .brv exists)
6
- * 3. File is text/code file (not binary)
6
+ * 3. File is supported by read_file tool (text, images, or PDFs)
7
7
  *
8
8
  * @param filePath - The file path to validate (can be relative, absolute, or tilde)
9
9
  * @param projectRoot - The project root directory (current working directory)
@@ -1,17 +1,18 @@
1
1
  import fs from 'node:fs';
2
2
  import os from 'node:os';
3
3
  import path from 'node:path';
4
+ import { isBinaryFile, isMediaFile } from '../infra/cipher/file-system/binary-utils.js';
4
5
  /**
5
6
  * Normalize file path - handles relative, absolute, tilde, symlinks
6
7
  * Returns absolute canonical path
7
8
  * @param filePath - The file path to normalize
8
9
  * @returns Normalized absolute path
9
10
  */
10
- function normalizeFilePath(filePath) {
11
+ function normalizeFilePath(filePath, baseDir) {
11
12
  // Expand tilde to home directory
12
13
  const expanded = filePath.startsWith('~') ? filePath.replace(/^~/, os.homedir()) : filePath;
13
- // Resolve to absolute path
14
- const absolute = path.resolve(expanded);
14
+ // Resolve to absolute path using baseDir for relative paths
15
+ const absolute = path.isAbsolute(expanded) ? expanded : path.resolve(baseDir ?? process.cwd(), expanded);
15
16
  // Resolve symlinks (only if file exists)
16
17
  try {
17
18
  return fs.realpathSync(absolute);
@@ -21,44 +22,23 @@ function normalizeFilePath(filePath) {
21
22
  return absolute;
22
23
  }
23
24
  }
24
- /**
25
- * Check if file is text (no null bytes in first 8KB)
26
- * Returns false for binary files (images, PDFs, compiled binaries, etc.)
27
- * @param filePath - The file path to check
28
- * @returns true if file is text, false if binary
29
- */
30
- function isTextFile(filePath) {
31
- try {
32
- const buffer = Buffer.alloc(8192);
33
- const fd = fs.openSync(filePath, 'r');
34
- const bytesRead = fs.readSync(fd, buffer, 0, 8192, 0);
35
- fs.closeSync(fd);
36
- // Check for null bytes (indicates binary file)
37
- for (let i = 0; i < bytesRead; i++) {
38
- if (buffer[i] === 0)
39
- return false;
40
- }
41
- return true;
42
- }
43
- catch {
44
- // If we can't read the file, consider it non-text
45
- return false;
46
- }
47
- }
48
25
  /**
49
26
  * Validate file for --files flag in brv curate command
50
27
  * Checks:
51
28
  * 1. File exists
52
29
  * 2. File is within project directory (where .brv exists)
53
- * 3. File is text/code file (not binary)
30
+ * 3. File is supported by read_file tool (text, images, or PDFs)
54
31
  *
55
32
  * @param filePath - The file path to validate (can be relative, absolute, or tilde)
56
33
  * @param projectRoot - The project root directory (current working directory)
57
34
  * @returns Validation result with normalized path or error message
58
35
  */
59
36
  export function validateFileForCurate(filePath, projectRoot) {
60
- // Normalize path
61
- const normalized = normalizeFilePath(filePath);
37
+ // Normalize projectRoot first to ensure consistent behavior
38
+ // This handles cases where projectRoot might be relative
39
+ const normalizedProjectRoot = normalizeFilePath(projectRoot);
40
+ // Normalize file path using normalizedProjectRoot as base for relative paths
41
+ const normalized = normalizeFilePath(filePath, normalizedProjectRoot);
62
42
  // Check existence
63
43
  if (!fs.existsSync(normalized)) {
64
44
  return { error: `File does not exist: ${filePath}`, valid: false };
@@ -68,14 +48,33 @@ export function validateFileForCurate(filePath, projectRoot) {
68
48
  if (!stats.isFile()) {
69
49
  return { error: `Path is not a file: ${filePath}`, valid: false };
70
50
  }
71
- // Check within project (normalized paths for reliable comparison)
72
- const normalizedProjectRoot = normalizeFilePath(projectRoot);
51
+ // Check within project (both paths are already normalized)
73
52
  if (!normalized.startsWith(normalizedProjectRoot + path.sep) && normalized !== normalizedProjectRoot) {
74
53
  return { error: `File is outside project directory: ${filePath}`, valid: false };
75
54
  }
76
- // Check is text file
77
- if (!isTextFile(normalized)) {
78
- return { error: `File is not a text/code file (binary detected): ${filePath}`, valid: false };
55
+ // Read sample buffer for file type detection
56
+ let buffer;
57
+ let bytesRead;
58
+ try {
59
+ buffer = Buffer.alloc(4096);
60
+ const fd = fs.openSync(normalized, 'r');
61
+ bytesRead = fs.readSync(fd, buffer, 0, 4096, 0);
62
+ fs.closeSync(fd);
63
+ }
64
+ catch {
65
+ return { error: `Cannot read file: ${filePath}`, valid: false };
66
+ }
67
+ const sampleBuffer = buffer.subarray(0, bytesRead);
68
+ // Check file type using binary-utils (same logic as read_file tool)
69
+ // Allow media files (images/PDFs) - read_file can handle these
70
+ // For PDFs, also validate magic bytes to reject fake PDFs (e.g., binary.pdf)
71
+ if (isMediaFile(normalized, sampleBuffer)) {
72
+ return { normalizedPath: normalized, valid: true };
73
+ }
74
+ // Check if it's a binary file (using same logic as read_file tool)
75
+ if (isBinaryFile(normalized, sampleBuffer)) {
76
+ return { error: `File type not supported: ${filePath}`, valid: false };
79
77
  }
78
+ // It's a text file - supported
80
79
  return { normalizedPath: normalized, valid: true };
81
80
  }
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Type guard to check if value is a non-null object (Record).
3
+ * Useful for safely narrowing unknown values before accessing properties.
4
+ */
5
+ export declare function isRecord(value: unknown): value is Record<string, unknown>;
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Type guard to check if value is a non-null object (Record).
3
+ * Useful for safely narrowing unknown values before accessing properties.
4
+ */
5
+ export function isRecord(value) {
6
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
7
+ }
@@ -9,7 +9,7 @@
9
9
  "required": false
10
10
  }
11
11
  },
12
- "description": "Curate context to the context tree (connects to running brv instance)\n\nRequires a running brv instance. Start one with: brv start\n\nGood examples:\n- \"Auth uses JWT with 24h expiry. Tokens stored in httpOnly cookies via authMiddleware.ts\"\n- \"API rate limit is 100 req/min per user. Implemented using Redis with sliding window in rateLimiter.ts\"\nBad examples:\n- \"Authentication\" or \"JWT tokens\" (too vague, lacks context)\n- \"Rate limiting\" (no implementation details or file references)",
12
+ "description": "Curate context to the context tree (connects to running brv instance)\n\nRequires a running brv instance. Start one with: brv\n\nGood examples:\n- \"Auth uses JWT with 24h expiry. Tokens stored in httpOnly cookies via authMiddleware.ts\"\n- \"API rate limit is 100 req/min per user. Implemented using Redis with sliding window in rateLimiter.ts\"\nBad examples:\n- \"Authentication\" or \"JWT tokens\" (too vague, lacks context)\n- \"Rate limiting\" (no implementation details or file references)",
13
13
  "examples": [
14
14
  "# Curate context - queues task for background processing",
15
15
  "<%= config.bin %> <%= command.id %> \"Auth uses JWT with 24h expiry. Tokens stored in httpOnly cookies via authMiddleware.ts\"",
@@ -45,6 +45,27 @@
45
45
  "curate.js"
46
46
  ]
47
47
  },
48
+ "hook-prompt-submit": {
49
+ "aliases": [],
50
+ "args": {},
51
+ "description": "Internal: Pre-prompt hook for coding agents",
52
+ "flags": {},
53
+ "hasDynamicHelp": false,
54
+ "hidden": true,
55
+ "hiddenAliases": [],
56
+ "id": "hook-prompt-submit",
57
+ "pluginAlias": "byterover-cli",
58
+ "pluginName": "byterover-cli",
59
+ "pluginType": "core",
60
+ "strict": true,
61
+ "enableJsonFlag": false,
62
+ "isESM": true,
63
+ "relativePath": [
64
+ "dist",
65
+ "commands",
66
+ "hook-prompt-submit.js"
67
+ ]
68
+ },
48
69
  "main": {
49
70
  "aliases": [],
50
71
  "args": {},
@@ -75,7 +96,7 @@
75
96
  "required": true
76
97
  }
77
98
  },
78
- "description": "Query and retrieve information from the context tree (connects to running brv instance)\n\nRequires a running brv instance. Start one with: brv start\n\nGood:\n- \"How is user authentication implemented?\"\n- \"What are the API rate limits and where are they enforced?\"\nBad:\n- \"auth\" or \"authentication\" (too vague, not a question)\n- \"show me code\" (not specific about what information is needed)",
99
+ "description": "Query and retrieve information from the context tree (connects to running brv instance)\n\nRequires a running brv instance. Start one with: brv\n\nGood:\n- \"How is user authentication implemented?\"\n- \"What are the API rate limits and where are they enforced?\"\nBad:\n- \"auth\" or \"authentication\" (too vague, not a question)\n- \"show me code\" (not specific about what information is needed)",
79
100
  "examples": [
80
101
  "# Ask questions about patterns, decisions, or implementation details",
81
102
  "<%= config.bin %> <%= command.id %> What are the coding standards?",
@@ -109,9 +130,14 @@
109
130
  "description": "Show CLI status and project information. Display local context tree managed by ByteRover CLI",
110
131
  "examples": [
111
132
  "<%= config.bin %> <%= command.id %>",
112
- "# Check status after login:\n<%= config.bin %> login\n<%= config.bin %> <%= command.id %>",
113
- "# Verify project initialization:\n<%= config.bin %> init\n<%= config.bin %> <%= command.id %>",
114
- "<%= config.bin %> <%= command.id %>",
133
+ "# Check status after login (in REPL):",
134
+ "/login",
135
+ "/status",
136
+ "",
137
+ "# Verify project initialization (in REPL):",
138
+ "/init",
139
+ "/status",
140
+ "",
115
141
  "<%= config.bin %> <%= command.id %> /path/to/project",
116
142
  "<%= config.bin %> <%= command.id %> --format json"
117
143
  ],
@@ -198,5 +224,5 @@
198
224
  ]
199
225
  }
200
226
  },
201
- "version": "1.0.4"
227
+ "version": "1.1.0"
202
228
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "byterover-cli",
3
3
  "description": "ByteRover's CLI",
4
- "version": "1.0.4",
4
+ "version": "1.1.0",
5
5
  "author": "ByteRover",
6
6
  "bin": {
7
7
  "brv": "./bin/run.js"
@@ -32,6 +32,7 @@
32
32
  "inquirer-file-selector": "^1.0.1",
33
33
  "js-yaml": "^4.1.1",
34
34
  "keytar": "^7.9.0",
35
+ "minisearch": "^7.2.0",
35
36
  "mixpanel": "^0.18.1",
36
37
  "nanoid": "^5.1.6",
37
38
  "open": "^10.2.0",
@@ -39,6 +40,7 @@
39
40
  "react": "^19.2.1",
40
41
  "socket.io": "^4.8.1",
41
42
  "socket.io-client": "^4.8.1",
43
+ "stopword": "^3.1.5",
42
44
  "update-notifier": "^7.3.1",
43
45
  "zod": "^3.25.76",
44
46
  "zod-to-json-schema": "^3.24.6"
@@ -55,6 +57,7 @@
55
57
  "@types/node": "^20",
56
58
  "@types/react": "^19.2.7",
57
59
  "@types/sinon": "^17.0.4",
60
+ "@types/stopword": "^2.0.3",
58
61
  "chai": "^4",
59
62
  "eslint": "^9",
60
63
  "eslint-config-oclif": "^6",
@@ -1,29 +0,0 @@
1
- /**
2
- * Domain configurations for the context tree structure.
3
- * Each domain represents a specific area of knowledge in the project.
4
- *
5
- * @deprecated Domains are now created dynamically based on content semantics.
6
- * This file is kept for backward compatibility only.
7
- */
8
- export interface DomainConfig {
9
- description: string;
10
- name: string;
11
- }
12
- /**
13
- * Example domain names for reference only.
14
- * Domains are now created dynamically by the agent based on content.
15
- *
16
- * @deprecated Domains are created dynamically. These are kept as examples only.
17
- */
18
- export declare const EXAMPLE_DOMAIN_NAMES: readonly ["authentication", "api_design", "data_models", "error_handling", "ui_components", "testing_patterns", "configuration", "logging", "security", "performance"];
19
- /**
20
- * @deprecated Domains are now created dynamically based on content semantics.
21
- * The agent will create domain names that are semantically meaningful for the curated content.
22
- * This constant is kept for backward compatibility but is no longer used.
23
- */
24
- export declare const DEFAULT_CONTEXT_TREE_DOMAINS: DomainConfig[];
25
- /**
26
- * Alias for backward compatibility.
27
- * @deprecated Domains are created dynamically. This constant is no longer used.
28
- */
29
- export declare const CONTEXT_TREE_DOMAINS: DomainConfig[];
@@ -1,29 +0,0 @@
1
- /**
2
- * Example domain names for reference only.
3
- * Domains are now created dynamically by the agent based on content.
4
- *
5
- * @deprecated Domains are created dynamically. These are kept as examples only.
6
- */
7
- export const EXAMPLE_DOMAIN_NAMES = [
8
- 'authentication',
9
- 'api_design',
10
- 'data_models',
11
- 'error_handling',
12
- 'ui_components',
13
- 'testing_patterns',
14
- 'configuration',
15
- 'logging',
16
- 'security',
17
- 'performance',
18
- ];
19
- /**
20
- * @deprecated Domains are now created dynamically based on content semantics.
21
- * The agent will create domain names that are semantically meaningful for the curated content.
22
- * This constant is kept for backward compatibility but is no longer used.
23
- */
24
- export const DEFAULT_CONTEXT_TREE_DOMAINS = [];
25
- /**
26
- * Alias for backward compatibility.
27
- * @deprecated Domains are created dynamically. This constant is no longer used.
28
- */
29
- export const CONTEXT_TREE_DOMAINS = DEFAULT_CONTEXT_TREE_DOMAINS;
@@ -1,3 +0,0 @@
1
- export interface IGenerateRulesUseCase {
2
- run(): Promise<void>;
3
- }
@@ -1,7 +0,0 @@
1
- import { SlashCommand } from '../../../tui/types.js';
2
- /**
3
- * Generate rules command
4
- *
5
- * Creates and runs GenerateRulesUseCase with ReplTerminal for TUI integration.
6
- */
7
- export declare const genRulesCommand: SlashCommand;
@@ -1,19 +0,0 @@
1
- import { type Agent } from '../../core/domain/entities/agent.js';
2
- import { type WriteMode } from '../../core/interfaces/i-file-service.js';
3
- /**
4
- * Configuration for agent-specific rule files.
5
- */
6
- export type AgentRuleConfig = {
7
- /**
8
- * The file path where the agent's rules should be written.
9
- */
10
- filePath: string;
11
- /**
12
- * The write mode to use when writing the rule file.
13
- */
14
- writeMode: WriteMode;
15
- };
16
- /**
17
- * Mapping of agents to their rule file configurations.
18
- */
19
- export declare const AGENT_RULE_CONFIGS: Record<Agent, AgentRuleConfig>;
@@ -1,61 +0,0 @@
1
- import type { Agent } from '../../core/domain/entities/agent.js';
2
- import type { IFileService } from '../../core/interfaces/i-file-service.js';
3
- import type { IRuleTemplateService } from '../../core/interfaces/i-rule-template-service.js';
4
- import type { ITerminal } from '../../core/interfaces/i-terminal.js';
5
- import type { ITrackingService } from '../../core/interfaces/i-tracking-service.js';
6
- import type { IGenerateRulesUseCase } from '../../core/interfaces/usecase/i-generate-rules-use-case.js';
7
- import { LegacyRuleDetector } from '../rule/legacy-rule-detector.js';
8
- type CleanupStrategy = 'automatic' | 'manual';
9
- export declare class GenerateRulesUseCase implements IGenerateRulesUseCase {
10
- private readonly fileService;
11
- private readonly legacyRuleDetector;
12
- private readonly templateService;
13
- private readonly terminal;
14
- private readonly trackingService;
15
- constructor(fileService: IFileService, legacyRuleDetector: LegacyRuleDetector, templateService: IRuleTemplateService, terminal: ITerminal, trackingService: ITrackingService);
16
- /**
17
- * Prompts the user to select an agent.
18
- * @returns The selected agent
19
- */
20
- protected promptForAgentSelection(): Promise<Agent>;
21
- /**
22
- * Prompts the user to choose cleanup strategy for legacy rules.
23
- * @returns The chosen cleanup strategy
24
- */
25
- protected promptForCleanupStrategy(): Promise<CleanupStrategy>;
26
- /**
27
- * Prompts the user to create a new rule file.
28
- * This method is protected to allow test overrides.
29
- * @param agent The agent for which the rule file doesn't exist
30
- * @param filePath The path where the file would be created
31
- * @returns True if the user wants to create the file, false otherwise
32
- */
33
- protected promptForFileCreation(agent: Agent, filePath: string): Promise<boolean>;
34
- /**
35
- * Prompts the user to confirm overwriting an existing rule file.
36
- * This method is protected to allow test overrides.
37
- * @param agent The agent for which the rule file exists
38
- * @returns True if the user confirms overwrite, false otherwise
39
- */
40
- protected promptForOverwriteConfirmation(agent: Agent): Promise<boolean>;
41
- run(): Promise<void>;
42
- /**
43
- * Appends ByteRover rules to a file that has no ByteRover content.
44
- */
45
- private appendRulesToFile;
46
- /**
47
- * Creates a new rule file with ByteRover rules.
48
- */
49
- private createNewRuleFile;
50
- /**
51
- * Handles legacy rules cleanup with user choice of automatic or manual.
52
- */
53
- private handleLegacyRulesCleanup;
54
- private performAutomaticCleanup;
55
- private performManualCleanup;
56
- /**
57
- * Replaces existing ByteRover rules (with boundary markers) with new rules.
58
- */
59
- private replaceExistingRules;
60
- }
61
- export {};