byterover-cli 0.3.4 → 0.4.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 +119 -63
- package/bin/dev.js +8 -1
- package/bin/run.js +7 -0
- package/dist/commands/cipher-agent/run.d.ts +30 -0
- package/dist/commands/cipher-agent/run.js +123 -61
- package/dist/commands/cipher-agent/set-prompt.d.ts +2 -0
- package/dist/commands/cipher-agent/set-prompt.js +13 -8
- package/dist/commands/cipher-agent/show-prompt.d.ts +2 -0
- package/dist/commands/cipher-agent/show-prompt.js +17 -12
- package/dist/commands/curate.d.ts +3 -60
- package/dist/commands/curate.js +45 -341
- package/dist/commands/foo.d.ts +4 -2
- package/dist/commands/foo.js +21 -16
- package/dist/commands/main.d.ts +9 -0
- package/dist/commands/main.js +34 -0
- package/dist/commands/query.d.ts +2 -48
- package/dist/commands/query.js +19 -287
- package/dist/commands/status.d.ts +2 -13
- package/dist/commands/status.js +12 -91
- package/dist/commands/watch.d.ts +2 -0
- package/dist/commands/watch.js +23 -19
- package/dist/config/environment.d.ts +1 -1
- package/dist/config/environment.js +2 -2
- package/dist/constants.d.ts +4 -5
- package/dist/constants.js +5 -5
- package/dist/core/domain/cipher/errors/storage-error.d.ts +89 -0
- package/dist/core/domain/cipher/errors/storage-error.js +130 -0
- package/dist/core/domain/cipher/queue/types.d.ts +71 -0
- package/dist/core/domain/cipher/queue/types.js +9 -0
- package/dist/core/domain/cipher/storage/message-storage-types.d.ts +218 -0
- package/dist/core/domain/cipher/storage/message-storage-types.js +18 -0
- package/dist/core/domain/cipher/tools/constants.d.ts +1 -0
- package/dist/core/domain/cipher/tools/constants.js +1 -0
- package/dist/core/domain/entities/event.d.ts +1 -1
- package/dist/core/domain/entities/event.js +5 -0
- package/dist/core/domain/entities/global-config.d.ts +36 -0
- package/dist/core/domain/entities/global-config.js +66 -0
- package/dist/core/domain/knowledge/directory-manager.d.ts +10 -0
- package/dist/core/domain/knowledge/directory-manager.js +18 -0
- package/dist/core/domain/knowledge/markdown-writer.d.ts +9 -0
- package/dist/core/domain/knowledge/markdown-writer.js +51 -1
- package/dist/core/interfaces/cipher/i-agent-storage.d.ts +152 -0
- package/dist/core/interfaces/cipher/i-agent-storage.js +1 -0
- package/dist/core/interfaces/cipher/i-cipher-agent.d.ts +2 -0
- package/dist/core/interfaces/cipher/i-key-storage.d.ts +91 -0
- package/dist/core/interfaces/cipher/i-key-storage.js +1 -0
- package/dist/core/interfaces/i-global-config-store.d.ts +34 -0
- package/dist/core/interfaces/i-global-config-store.js +1 -0
- package/dist/core/interfaces/i-onboarding-preference-store.d.ts +20 -0
- package/dist/core/interfaces/i-onboarding-preference-store.js +1 -0
- package/dist/core/interfaces/i-terminal.d.ts +146 -0
- package/dist/core/interfaces/i-terminal.js +1 -0
- package/dist/core/interfaces/i-workspace-detector-service.d.ts +8 -0
- package/dist/core/interfaces/i-workspace-detector-service.js +1 -0
- package/dist/core/interfaces/usecase/i-clear-use-case.d.ts +6 -0
- package/dist/core/interfaces/usecase/i-clear-use-case.js +1 -0
- package/dist/core/interfaces/usecase/i-curate-use-case.d.ts +10 -0
- package/dist/core/interfaces/usecase/i-curate-use-case.js +1 -0
- package/dist/core/interfaces/usecase/i-generate-rules-use-case.d.ts +3 -0
- package/dist/core/interfaces/usecase/i-generate-rules-use-case.js +1 -0
- package/dist/core/interfaces/usecase/i-init-use-case.d.ts +5 -0
- package/dist/core/interfaces/usecase/i-init-use-case.js +1 -0
- package/dist/core/interfaces/usecase/i-login-use-case.d.ts +3 -0
- package/dist/core/interfaces/usecase/i-login-use-case.js +1 -0
- package/dist/core/interfaces/usecase/i-logout-use-case.d.ts +5 -0
- package/dist/core/interfaces/usecase/i-logout-use-case.js +1 -0
- package/dist/core/interfaces/usecase/i-pull-use-case.d.ts +5 -0
- package/dist/core/interfaces/usecase/i-pull-use-case.js +1 -0
- package/dist/core/interfaces/usecase/i-push-use-case.d.ts +6 -0
- package/dist/core/interfaces/usecase/i-push-use-case.js +1 -0
- package/dist/core/interfaces/usecase/i-query-use-case.d.ts +9 -0
- package/dist/core/interfaces/usecase/i-query-use-case.js +1 -0
- package/dist/core/interfaces/usecase/i-space-list-use-case.d.ts +3 -0
- package/dist/core/interfaces/usecase/i-space-list-use-case.js +1 -0
- package/dist/core/interfaces/usecase/i-space-switch-use-case.d.ts +3 -0
- package/dist/core/interfaces/usecase/i-space-switch-use-case.js +1 -0
- package/dist/core/interfaces/usecase/i-status-use-case.d.ts +5 -0
- package/dist/core/interfaces/usecase/i-status-use-case.js +1 -0
- package/dist/hooks/init/update-notifier.js +1 -5
- package/dist/hooks/init/welcome.js +1 -2
- package/dist/infra/cipher/agent-service-factory.d.ts +13 -6
- package/dist/infra/cipher/agent-service-factory.js +40 -16
- package/dist/infra/cipher/cipher-agent.js +4 -4
- package/dist/infra/cipher/consumer/consumer-lock.d.ts +20 -0
- package/dist/infra/cipher/consumer/consumer-lock.js +40 -0
- package/dist/infra/cipher/consumer/consumer-service.d.ts +99 -0
- package/dist/infra/cipher/consumer/consumer-service.js +165 -0
- package/dist/infra/cipher/consumer/execution-consumer.d.ts +121 -0
- package/dist/infra/cipher/consumer/execution-consumer.js +523 -0
- package/dist/infra/cipher/consumer/index.d.ts +33 -0
- package/dist/infra/cipher/consumer/index.js +33 -0
- package/dist/infra/cipher/consumer/queue-polling-service.d.ts +120 -0
- package/dist/infra/cipher/consumer/queue-polling-service.js +248 -0
- package/dist/infra/cipher/http/internal-llm-http-service.d.ts +94 -0
- package/dist/infra/cipher/http/internal-llm-http-service.js +118 -0
- package/dist/infra/cipher/llm/context/compaction/compaction-service.d.ts +106 -0
- package/dist/infra/cipher/llm/context/compaction/compaction-service.js +132 -0
- package/dist/infra/cipher/llm/context/compaction/index.d.ts +9 -0
- package/dist/infra/cipher/llm/context/compaction/index.js +9 -0
- package/dist/infra/cipher/llm/context/context-manager.d.ts +46 -2
- package/dist/infra/cipher/llm/context/context-manager.js +68 -4
- package/dist/infra/cipher/llm/context/rw-lock.d.ts +72 -0
- package/dist/infra/cipher/llm/context/rw-lock.js +145 -0
- package/dist/infra/cipher/llm/generators/byterover-content-generator.d.ts +7 -7
- package/dist/infra/cipher/llm/generators/byterover-content-generator.js +8 -8
- package/dist/infra/cipher/llm/internal-llm-service.js +2 -0
- package/dist/infra/cipher/session/session-manager.d.ts +4 -4
- package/dist/infra/cipher/session/session-manager.js +5 -5
- package/dist/infra/cipher/storage/agent-storage.d.ts +246 -0
- package/dist/infra/cipher/storage/agent-storage.js +956 -0
- package/dist/infra/cipher/storage/dual-format-history-storage.d.ts +77 -0
- package/dist/infra/cipher/storage/dual-format-history-storage.js +149 -0
- package/dist/infra/cipher/storage/granular-history-storage.d.ts +65 -0
- package/dist/infra/cipher/storage/granular-history-storage.js +118 -0
- package/dist/infra/cipher/storage/message-storage-service.d.ts +108 -0
- package/dist/infra/cipher/storage/message-storage-service.js +529 -0
- package/dist/infra/cipher/storage/process-utils.d.ts +16 -0
- package/dist/infra/cipher/storage/process-utils.js +43 -0
- package/dist/infra/cipher/storage/sqlite-key-storage.d.ts +105 -0
- package/dist/infra/cipher/storage/sqlite-key-storage.js +404 -0
- package/dist/infra/cipher/system-prompt/simple-prompt-factory.d.ts +1 -0
- package/dist/infra/cipher/system-prompt/simple-prompt-factory.js +7 -0
- package/dist/infra/cipher/tools/default-policy-rules.js +1 -1
- package/dist/infra/cipher/tools/implementations/curate-tool.d.ts +10 -0
- package/dist/infra/cipher/tools/implementations/curate-tool.js +371 -0
- package/dist/infra/cipher/tools/implementations/find-knowledge-topics-tool.js +11 -8
- package/dist/infra/cipher/tools/tool-manager.d.ts +8 -2
- package/dist/infra/cipher/tools/tool-manager.js +29 -2
- package/dist/infra/cipher/tools/tool-registry.js +7 -0
- package/dist/infra/http/authenticated-http-client.d.ts +21 -0
- package/dist/infra/http/authenticated-http-client.js +38 -0
- package/dist/infra/repl/commands/arg-parser.d.ts +97 -0
- package/dist/infra/repl/commands/arg-parser.js +129 -0
- package/dist/infra/repl/commands/clear-command.d.ts +5 -0
- package/dist/infra/repl/commands/clear-command.js +61 -0
- package/dist/infra/repl/commands/curate-command.d.ts +9 -0
- package/dist/infra/repl/commands/curate-command.js +88 -0
- package/dist/infra/repl/commands/gen-rules-command.d.ts +7 -0
- package/dist/infra/repl/commands/gen-rules-command.js +38 -0
- package/dist/infra/repl/commands/index.d.ts +8 -0
- package/dist/infra/repl/commands/index.js +36 -0
- package/dist/infra/repl/commands/init-command.d.ts +7 -0
- package/dist/infra/repl/commands/init-command.js +83 -0
- package/dist/infra/repl/commands/login-command.d.ts +7 -0
- package/dist/infra/repl/commands/login-command.js +50 -0
- package/dist/infra/repl/commands/logout-command.d.ts +5 -0
- package/dist/infra/repl/commands/logout-command.js +48 -0
- package/dist/infra/repl/commands/pull-command.d.ts +5 -0
- package/dist/infra/repl/commands/pull-command.js +61 -0
- package/dist/infra/repl/commands/push-command.d.ts +5 -0
- package/dist/infra/repl/commands/push-command.js +66 -0
- package/dist/infra/repl/commands/query-command.d.ts +5 -0
- package/dist/infra/repl/commands/query-command.js +66 -0
- package/dist/infra/repl/commands/space/index.d.ts +5 -0
- package/dist/infra/repl/commands/space/index.js +14 -0
- package/dist/infra/repl/commands/space/list-command.d.ts +5 -0
- package/dist/infra/repl/commands/space/list-command.js +70 -0
- package/dist/infra/repl/commands/space/switch-command.d.ts +5 -0
- package/dist/infra/repl/commands/space/switch-command.js +37 -0
- package/dist/infra/repl/commands/status-command.d.ts +5 -0
- package/dist/infra/repl/commands/status-command.js +39 -0
- package/dist/infra/repl/repl-startup.d.ts +18 -0
- package/dist/infra/repl/repl-startup.js +26 -0
- package/dist/infra/storage/file-global-config-store.d.ts +22 -0
- package/dist/infra/storage/file-global-config-store.js +65 -0
- package/dist/infra/storage/file-onboarding-preference-store.d.ts +10 -0
- package/dist/infra/storage/file-onboarding-preference-store.js +46 -0
- package/dist/infra/terminal/oclif-terminal.d.ts +19 -0
- package/dist/infra/terminal/oclif-terminal.js +60 -0
- package/dist/infra/terminal/repl-terminal.d.ts +31 -0
- package/dist/infra/terminal/repl-terminal.js +116 -0
- package/dist/infra/tracking/mixpanel-tracking-service.d.ts +11 -1
- package/dist/infra/tracking/mixpanel-tracking-service.js +18 -13
- package/dist/infra/usecase/clear-use-case.d.ts +20 -0
- package/dist/infra/usecase/clear-use-case.js +58 -0
- package/dist/infra/usecase/curate-use-case.d.ts +66 -0
- package/dist/infra/usecase/curate-use-case.js +283 -0
- package/dist/{commands/gen-rules.d.ts → infra/usecase/generate-rules-use-case.d.ts} +14 -20
- package/dist/{commands/gen-rules.js → infra/usecase/generate-rules-use-case.js} +59 -78
- package/dist/infra/usecase/init-use-case.d.ts +139 -0
- package/dist/{commands/init.js → infra/usecase/init-use-case.js} +184 -230
- package/dist/infra/usecase/login-use-case.d.ts +28 -0
- package/dist/infra/usecase/login-use-case.js +88 -0
- package/dist/infra/usecase/logout-use-case.d.ts +22 -0
- package/dist/infra/usecase/logout-use-case.js +51 -0
- package/dist/infra/usecase/pull-use-case.d.ts +35 -0
- package/dist/infra/usecase/pull-use-case.js +89 -0
- package/dist/infra/usecase/push-use-case.d.ts +37 -0
- package/dist/infra/usecase/push-use-case.js +124 -0
- package/dist/infra/usecase/query-use-case.d.ts +78 -0
- package/dist/infra/usecase/query-use-case.js +401 -0
- package/dist/infra/usecase/space-list-use-case.d.ts +27 -0
- package/dist/infra/usecase/space-list-use-case.js +64 -0
- package/dist/infra/usecase/space-switch-use-case.d.ts +36 -0
- package/dist/infra/usecase/space-switch-use-case.js +140 -0
- package/dist/infra/usecase/status-use-case.d.ts +27 -0
- package/dist/infra/usecase/status-use-case.js +97 -0
- package/dist/infra/workspace/workspace-detector-service.d.ts +3 -6
- package/dist/resources/prompts/curate-context-tree-curation.yml +23 -11
- package/dist/resources/prompts/query-context-tree-retrieval.yml +3 -4
- package/dist/resources/prompts/system-prompt.yml +1 -1
- package/dist/resources/prompts/tool-outputs.yml +4 -3
- package/dist/templates/sections/command-reference.md +12 -0
- package/dist/templates/sections/workflow.md +10 -1
- package/dist/tui/app.d.ts +9 -0
- package/dist/tui/app.js +26 -0
- package/dist/tui/components/enter-prompt.d.ts +13 -0
- package/dist/tui/components/enter-prompt.js +15 -0
- package/dist/tui/components/execution/execution-changes.d.ts +14 -0
- package/dist/tui/components/execution/execution-changes.js +15 -0
- package/dist/tui/components/execution/execution-content.d.ts +25 -0
- package/dist/tui/components/execution/execution-content.js +67 -0
- package/dist/tui/components/execution/execution-input.d.ts +12 -0
- package/dist/tui/components/execution/execution-input.js +16 -0
- package/dist/tui/components/execution/execution-progress.d.ts +21 -0
- package/dist/tui/components/execution/execution-progress.js +21 -0
- package/dist/tui/components/execution/execution-status.d.ts +13 -0
- package/dist/tui/components/execution/execution-status.js +19 -0
- package/dist/tui/components/execution/index.d.ts +11 -0
- package/dist/tui/components/execution/index.js +11 -0
- package/dist/tui/components/execution/log-item.d.ts +17 -0
- package/dist/tui/components/execution/log-item.js +25 -0
- package/dist/tui/components/footer.d.ts +5 -0
- package/dist/tui/components/footer.js +12 -0
- package/dist/tui/components/header.d.ts +18 -0
- package/dist/tui/components/header.js +18 -0
- package/dist/tui/components/index.d.ts +17 -0
- package/dist/tui/components/index.js +14 -0
- package/dist/tui/components/inline-prompts/index.d.ts +15 -0
- package/dist/tui/components/inline-prompts/index.js +10 -0
- package/dist/tui/components/inline-prompts/inline-confirm.d.ts +17 -0
- package/dist/tui/components/inline-prompts/inline-confirm.js +32 -0
- package/dist/tui/components/inline-prompts/inline-file-selector.d.ts +43 -0
- package/dist/tui/components/inline-prompts/inline-file-selector.js +185 -0
- package/dist/tui/components/inline-prompts/inline-input.d.ts +19 -0
- package/dist/tui/components/inline-prompts/inline-input.js +32 -0
- package/dist/tui/components/inline-prompts/inline-search.d.ts +20 -0
- package/dist/tui/components/inline-prompts/inline-search.js +50 -0
- package/dist/tui/components/inline-prompts/inline-select.d.ts +20 -0
- package/dist/tui/components/inline-prompts/inline-select.js +34 -0
- package/dist/tui/components/logo.d.ts +43 -0
- package/dist/tui/components/logo.js +103 -0
- package/dist/tui/components/message-item.d.ts +12 -0
- package/dist/tui/components/message-item.js +12 -0
- package/dist/tui/components/onboarding/copyable-prompt.d.ts +15 -0
- package/dist/tui/components/onboarding/copyable-prompt.js +65 -0
- package/dist/tui/components/onboarding/index.d.ts +7 -0
- package/dist/tui/components/onboarding/index.js +6 -0
- package/dist/tui/components/onboarding/onboarding-flow.d.ts +13 -0
- package/dist/tui/components/onboarding/onboarding-flow.js +304 -0
- package/dist/tui/components/onboarding/onboarding-step.d.ts +23 -0
- package/dist/tui/components/onboarding/onboarding-step.js +12 -0
- package/dist/tui/components/output-log.d.ts +14 -0
- package/dist/tui/components/output-log.js +13 -0
- package/dist/tui/components/scrollable-list.d.ts +30 -0
- package/dist/tui/components/scrollable-list.js +121 -0
- package/dist/tui/components/suggestions.d.ts +16 -0
- package/dist/tui/components/suggestions.js +162 -0
- package/dist/tui/components/tab-bar.d.ts +10 -0
- package/dist/tui/components/tab-bar.js +12 -0
- package/dist/tui/constants.d.ts +11 -0
- package/dist/tui/constants.js +13 -0
- package/dist/tui/contexts/auth-context.d.ts +30 -0
- package/dist/tui/contexts/auth-context.js +153 -0
- package/dist/tui/contexts/consumer.d.ts +31 -0
- package/dist/tui/contexts/consumer.js +56 -0
- package/dist/tui/contexts/index.d.ts +6 -0
- package/dist/tui/contexts/index.js +6 -0
- package/dist/tui/contexts/onboarding-context.d.ts +43 -0
- package/dist/tui/contexts/onboarding-context.js +181 -0
- package/dist/tui/contexts/services-context.d.ts +29 -0
- package/dist/tui/contexts/services-context.js +20 -0
- package/dist/tui/contexts/use-commands.d.ts +29 -0
- package/dist/tui/contexts/use-commands.js +53 -0
- package/dist/tui/contexts/use-mode.d.ts +43 -0
- package/dist/tui/contexts/use-mode.js +76 -0
- package/dist/tui/contexts/use-theme.d.ts +53 -0
- package/dist/tui/contexts/use-theme.js +60 -0
- package/dist/tui/hooks/index.d.ts +17 -0
- package/dist/tui/hooks/index.js +14 -0
- package/dist/tui/hooks/use-activity-logs.d.ts +26 -0
- package/dist/tui/hooks/use-activity-logs.js +90 -0
- package/dist/tui/hooks/use-consumer.d.ts +12 -0
- package/dist/tui/hooks/use-consumer.js +50 -0
- package/dist/tui/hooks/use-onboarding.d.ts +7 -0
- package/dist/tui/hooks/use-onboarding.js +6 -0
- package/dist/tui/hooks/use-queue-polling.d.ts +31 -0
- package/dist/tui/hooks/use-queue-polling.js +90 -0
- package/dist/tui/hooks/use-slash-command-processor.d.ts +16 -0
- package/dist/tui/hooks/use-slash-command-processor.js +132 -0
- package/dist/tui/hooks/use-slash-completion.d.ts +30 -0
- package/dist/tui/hooks/use-slash-completion.js +230 -0
- package/dist/tui/hooks/use-tab-navigation.d.ts +10 -0
- package/dist/tui/hooks/use-tab-navigation.js +35 -0
- package/dist/tui/hooks/use-visible-window.d.ts +22 -0
- package/dist/tui/hooks/use-visible-window.js +37 -0
- package/dist/tui/index.d.ts +1 -0
- package/dist/tui/index.js +1 -0
- package/dist/tui/providers/app-providers.d.ts +25 -0
- package/dist/tui/providers/app-providers.js +9 -0
- package/dist/tui/types/commands.d.ts +252 -0
- package/dist/tui/types/commands.js +16 -0
- package/dist/tui/types/dialogs.d.ts +37 -0
- package/dist/tui/types/dialogs.js +4 -0
- package/dist/tui/types/index.d.ts +11 -0
- package/dist/tui/types/index.js +7 -0
- package/dist/tui/types/messages.d.ts +55 -0
- package/dist/tui/types/messages.js +4 -0
- package/dist/tui/types/prompts.d.ts +100 -0
- package/dist/tui/types/prompts.js +4 -0
- package/dist/tui/types/ui.d.ts +14 -0
- package/dist/tui/types/ui.js +4 -0
- package/dist/tui/types.d.ts +1 -0
- package/dist/tui/types.js +1 -0
- package/dist/tui/views/command-view.d.ts +12 -0
- package/dist/tui/views/command-view.js +451 -0
- package/dist/tui/views/index.d.ts +6 -0
- package/dist/tui/views/index.js +6 -0
- package/dist/tui/views/login-view.d.ts +10 -0
- package/dist/tui/views/login-view.js +30 -0
- package/dist/tui/views/logs-view.d.ts +11 -0
- package/dist/tui/views/logs-view.js +73 -0
- package/dist/utils/file-validator.d.ts +16 -0
- package/dist/utils/file-validator.js +81 -0
- package/dist/utils/global-config-path.d.ts +15 -0
- package/dist/utils/global-config-path.js +38 -0
- package/oclif.manifest.json +29 -315
- package/package.json +11 -4
- package/dist/commands/clear.d.ts +0 -19
- package/dist/commands/clear.js +0 -78
- package/dist/commands/init.d.ts +0 -130
- package/dist/commands/login.d.ts +0 -22
- package/dist/commands/login.js +0 -108
- package/dist/commands/logout.d.ts +0 -16
- package/dist/commands/logout.js +0 -61
- package/dist/commands/pull.d.ts +0 -33
- package/dist/commands/pull.js +0 -115
- package/dist/commands/push.d.ts +0 -35
- package/dist/commands/push.js +0 -160
- package/dist/commands/space/list.d.ts +0 -25
- package/dist/commands/space/list.js +0 -114
- package/dist/commands/space/switch.d.ts +0 -36
- package/dist/commands/space/switch.js +0 -160
- package/dist/infra/cipher/grpc/internal-llm-grpc-service.d.ts +0 -149
- package/dist/infra/cipher/grpc/internal-llm-grpc-service.js +0 -364
- package/dist/infra/cipher/grpc/internal-llm-grpc.proto +0 -94
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import open from 'open';
|
|
5
|
+
import { CONTEXT_TREE_DOMAINS } from '../../config/context-tree-domains.js';
|
|
6
|
+
import { BRV_DIR, CONTEXT_FILE, CONTEXT_TREE_DIR } from '../../constants.js';
|
|
7
|
+
import { validateFileForCurate } from '../../utils/file-validator.js';
|
|
8
|
+
import { getAgentStorage } from '../cipher/storage/agent-storage.js';
|
|
9
|
+
import { WorkspaceNotInitializedError } from '../cipher/validation/workspace-validator.js';
|
|
10
|
+
// Full path to context tree
|
|
11
|
+
const CONTEXT_TREE_PATH = path.join(BRV_DIR, CONTEXT_TREE_DIR);
|
|
12
|
+
export class CurateUseCase {
|
|
13
|
+
projectConfigStore;
|
|
14
|
+
terminal;
|
|
15
|
+
tokenStore;
|
|
16
|
+
trackingService;
|
|
17
|
+
constructor(options) {
|
|
18
|
+
this.projectConfigStore = options.projectConfigStore;
|
|
19
|
+
this.terminal = options.terminal;
|
|
20
|
+
this.tokenStore = options.tokenStore;
|
|
21
|
+
this.trackingService = options.trackingService;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Create topic folder with context.md file
|
|
25
|
+
* @param targetPath - The parent path where the topic folder will be created
|
|
26
|
+
* @param topicName - The name of the topic folder to create
|
|
27
|
+
* @returns The path to the created context.md file
|
|
28
|
+
*/
|
|
29
|
+
createTopicWithContextFile(targetPath, topicName) {
|
|
30
|
+
const topicPath = path.join(targetPath, topicName);
|
|
31
|
+
const contextFilePath = path.join(topicPath, CONTEXT_FILE);
|
|
32
|
+
// Create the topic directory
|
|
33
|
+
fs.mkdirSync(topicPath, { recursive: true });
|
|
34
|
+
// Create the context.md file with initial content
|
|
35
|
+
const initialContent = `# ${topicName}\n\n<!-- Add your context here -->\n`;
|
|
36
|
+
fs.writeFileSync(contextFilePath, initialContent, 'utf8');
|
|
37
|
+
return contextFilePath;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Generate a unique session ID for the autonomous agent.
|
|
41
|
+
* Uses crypto.randomUUID() for guaranteed uniqueness (122 bits of entropy).
|
|
42
|
+
*/
|
|
43
|
+
generateSessionId() {
|
|
44
|
+
return randomUUID();
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Navigate through the context tree using file selector
|
|
48
|
+
* Returns the selected path relative to context-tree root
|
|
49
|
+
*/
|
|
50
|
+
async navigateContextTree() {
|
|
51
|
+
const contextTreePath = path.resolve(process.cwd(), CONTEXT_TREE_PATH);
|
|
52
|
+
// Ensure context tree directory exists
|
|
53
|
+
if (!fs.existsSync(contextTreePath)) {
|
|
54
|
+
fs.mkdirSync(contextTreePath, { recursive: true });
|
|
55
|
+
}
|
|
56
|
+
// Ensure predefined domains exist as directories
|
|
57
|
+
for (const domain of CONTEXT_TREE_DOMAINS) {
|
|
58
|
+
const domainPath = path.join(contextTreePath, domain.name);
|
|
59
|
+
if (!fs.existsSync(domainPath)) {
|
|
60
|
+
fs.mkdirSync(domainPath, { recursive: true });
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
while (true) {
|
|
64
|
+
try {
|
|
65
|
+
// eslint-disable-next-line no-await-in-loop
|
|
66
|
+
const selectedItem = await this.terminal.fileSelector({
|
|
67
|
+
allowCancel: true,
|
|
68
|
+
basePath: contextTreePath,
|
|
69
|
+
filter: (item) => item.isDirectory,
|
|
70
|
+
message: 'Target context location:',
|
|
71
|
+
pageSize: 15,
|
|
72
|
+
theme: {
|
|
73
|
+
labels: {
|
|
74
|
+
messages: {
|
|
75
|
+
cancel: 'Selection cancelled.',
|
|
76
|
+
empty: 'No sub-folders. Press Enter to add content here.',
|
|
77
|
+
},
|
|
78
|
+
},
|
|
79
|
+
},
|
|
80
|
+
type: 'directory',
|
|
81
|
+
});
|
|
82
|
+
// User cancelled
|
|
83
|
+
if (!selectedItem) {
|
|
84
|
+
return null;
|
|
85
|
+
}
|
|
86
|
+
// Restrict navigation to stay within the context tree
|
|
87
|
+
const normalizedItemPath = path.resolve(selectedItem.path);
|
|
88
|
+
const isValid = normalizedItemPath.startsWith(contextTreePath);
|
|
89
|
+
if (isValid) {
|
|
90
|
+
// Valid selection - proceed
|
|
91
|
+
return selectedItem.path;
|
|
92
|
+
}
|
|
93
|
+
// Invalid selection - retry
|
|
94
|
+
this.terminal.log('Invalid selection. Please choose a valid location within the context tree.');
|
|
95
|
+
}
|
|
96
|
+
catch {
|
|
97
|
+
// Error occurred
|
|
98
|
+
return null;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Open a file in the default editor
|
|
104
|
+
* @param filePath - The path to the file to open
|
|
105
|
+
*/
|
|
106
|
+
async openFile(filePath) {
|
|
107
|
+
await open(filePath);
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Prompt user to enter topic name with validation
|
|
111
|
+
* @param targetPath - The path where the topic folder will be created
|
|
112
|
+
* @returns The topic name or null if cancelled
|
|
113
|
+
*/
|
|
114
|
+
async promptForTopicName(targetPath) {
|
|
115
|
+
try {
|
|
116
|
+
const topicName = await this.terminal.input({
|
|
117
|
+
message: 'New topic name:',
|
|
118
|
+
validate: (value) => this.validateTopicName(value, targetPath),
|
|
119
|
+
});
|
|
120
|
+
return topicName.trim();
|
|
121
|
+
}
|
|
122
|
+
catch {
|
|
123
|
+
return null;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
async run(options) {
|
|
127
|
+
// Determine mode: autonomous if context is provided
|
|
128
|
+
return options.context ? this.runAutonomous(options.context, options) : this.runInteractive();
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Handle workspace not initialized error
|
|
132
|
+
*/
|
|
133
|
+
handleWorkspaceError(_error) {
|
|
134
|
+
const message = 'Project not initialized. Please run "brv init" to select your team and workspace.';
|
|
135
|
+
this.terminal.log(message);
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Process file paths from --files flag
|
|
139
|
+
* @param filePaths - Array of file paths (relative or absolute)
|
|
140
|
+
* @returns Formatted instructions for the agent to read the specified files, or undefined if validation fails
|
|
141
|
+
*/
|
|
142
|
+
processFileReferences(filePaths) {
|
|
143
|
+
const MAX_FILES = 5;
|
|
144
|
+
if (!filePaths || filePaths.length === 0) {
|
|
145
|
+
return '';
|
|
146
|
+
}
|
|
147
|
+
// Validate max files and truncate if needed
|
|
148
|
+
if (filePaths.length > MAX_FILES) {
|
|
149
|
+
const ignored = filePaths.slice(MAX_FILES);
|
|
150
|
+
this.terminal.log(`\n⚠️ Only the first ${MAX_FILES} files will be processed. Ignoring: ${ignored.join(', ')}\n`);
|
|
151
|
+
filePaths = filePaths.slice(0, MAX_FILES);
|
|
152
|
+
}
|
|
153
|
+
// Get project root (current directory with .brv)
|
|
154
|
+
const projectRoot = process.cwd();
|
|
155
|
+
// Validate each file and collect errors
|
|
156
|
+
const validPaths = [];
|
|
157
|
+
const errors = [];
|
|
158
|
+
for (const filePath of filePaths) {
|
|
159
|
+
const result = validateFileForCurate(filePath, projectRoot);
|
|
160
|
+
if (result.valid && result.normalizedPath) {
|
|
161
|
+
validPaths.push(result.normalizedPath);
|
|
162
|
+
}
|
|
163
|
+
else {
|
|
164
|
+
errors.push(` ✗ ${result.error}`);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
// If there are any validation errors, show them and return undefined
|
|
168
|
+
if (errors.length > 0) {
|
|
169
|
+
this.terminal.log('\n❌ File validation failed:\n');
|
|
170
|
+
this.terminal.log(errors.join('\n'));
|
|
171
|
+
this.terminal.log('');
|
|
172
|
+
this.terminal.log('Invalid files provided. Please fix the errors above and try again.');
|
|
173
|
+
return undefined;
|
|
174
|
+
}
|
|
175
|
+
// Format instructions for the agent
|
|
176
|
+
const instructions = [
|
|
177
|
+
'\n## IMPORTANT: Critical Files to Read (--files flag)',
|
|
178
|
+
'',
|
|
179
|
+
'The user has explicitly specified these files as critical context that MUST be read before creating knowledge topics:',
|
|
180
|
+
'',
|
|
181
|
+
...validPaths.map((p) => `- ${p}`),
|
|
182
|
+
'',
|
|
183
|
+
'**MANDATORY INSTRUCTIONS:**',
|
|
184
|
+
'- You MUST use the `read_file` tool to read ALL of these files IN PARALLEL (in a single iteration) before proceeding to create knowledge topics',
|
|
185
|
+
'- These files contain essential context that will help you create comprehensive and accurate knowledge topics',
|
|
186
|
+
'- Read them in parallel to maximize efficiency - they do not depend on each other',
|
|
187
|
+
'- After reading all files, proceed with the normal workflow: detect domains, find existing knowledge, and create/update topics',
|
|
188
|
+
'',
|
|
189
|
+
];
|
|
190
|
+
return instructions.join('\n');
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Run in autonomous mode - push to queue for background processing
|
|
194
|
+
*/
|
|
195
|
+
async runAutonomous(content, options) {
|
|
196
|
+
try {
|
|
197
|
+
// Get authentication token
|
|
198
|
+
const token = await this.tokenStore.load();
|
|
199
|
+
if (!token) {
|
|
200
|
+
this.terminal.log('Authentication required. Please run "brv login" first.');
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
// Load project config
|
|
204
|
+
const brvConfig = await this.projectConfigStore.read();
|
|
205
|
+
// Validate workspace is initialized
|
|
206
|
+
if (!brvConfig) {
|
|
207
|
+
throw new WorkspaceNotInitializedError('Project not initialized. Please run "brv init" to select your team and workspace.', '.brv');
|
|
208
|
+
}
|
|
209
|
+
// Process file references if provided (validates and creates instructions)
|
|
210
|
+
const fileReferenceInstructions = this.processFileReferences(options.files ?? []);
|
|
211
|
+
if (fileReferenceInstructions === undefined) {
|
|
212
|
+
// Validation failed, error already displayed
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
// Initialize storage and create execution (auto-detects .brv/blobs)
|
|
216
|
+
const storage = await getAgentStorage();
|
|
217
|
+
// Create execution with status='queued'
|
|
218
|
+
storage.createExecution('curate', JSON.stringify({
|
|
219
|
+
content,
|
|
220
|
+
fileReferenceInstructions,
|
|
221
|
+
flags: { apiKey: options.apiKey, model: options.model, verbose: options.verbose },
|
|
222
|
+
}));
|
|
223
|
+
// Simple output for agents - just confirm saved
|
|
224
|
+
this.terminal.log('✓ Context queued for processing.');
|
|
225
|
+
// Track the event
|
|
226
|
+
await this.trackingService.track('mem:curate');
|
|
227
|
+
}
|
|
228
|
+
catch (error) {
|
|
229
|
+
if (error instanceof WorkspaceNotInitializedError) {
|
|
230
|
+
this.handleWorkspaceError(error);
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
233
|
+
// Display error
|
|
234
|
+
this.terminal.error(error instanceof Error ? error.message : 'Runtime error occurred');
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
/**
|
|
238
|
+
* Run in interactive mode with manual prompts
|
|
239
|
+
*/
|
|
240
|
+
async runInteractive() {
|
|
241
|
+
try {
|
|
242
|
+
// Navigate to target location in context tree
|
|
243
|
+
const targetPath = await this.navigateContextTree();
|
|
244
|
+
if (!targetPath) {
|
|
245
|
+
this.terminal.log('\nOperation cancelled.');
|
|
246
|
+
return;
|
|
247
|
+
}
|
|
248
|
+
// Prompt for topic name with validation
|
|
249
|
+
const topicName = await this.promptForTopicName(targetPath);
|
|
250
|
+
if (!topicName) {
|
|
251
|
+
this.terminal.log('\nOperation cancelled.');
|
|
252
|
+
return;
|
|
253
|
+
}
|
|
254
|
+
// Create the topic folder with context.md
|
|
255
|
+
const contextFilePath = this.createTopicWithContextFile(targetPath, topicName);
|
|
256
|
+
this.terminal.log(`\nCreated: ${path.relative(process.cwd(), contextFilePath)}`);
|
|
257
|
+
// Track the event
|
|
258
|
+
this.trackingService.track('mem:curate');
|
|
259
|
+
// Auto-open context.md in default editor
|
|
260
|
+
this.terminal.log('Opening context.md for editing...');
|
|
261
|
+
await this.openFile(contextFilePath);
|
|
262
|
+
}
|
|
263
|
+
catch (error) {
|
|
264
|
+
this.terminal.error(error instanceof Error ? error.message : 'Unexpected error occurred');
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
validateTopicName(value, targetPath) {
|
|
268
|
+
const trimmed = value.trim();
|
|
269
|
+
if (!trimmed) {
|
|
270
|
+
return 'Topic name cannot be empty';
|
|
271
|
+
}
|
|
272
|
+
// Only allow letters, numbers, and hyphens
|
|
273
|
+
if (!/^[a-zA-Z0-9-]+$/.test(trimmed)) {
|
|
274
|
+
return 'Topic name can only contain letters (a-z, A-Z), numbers (0-9), and hyphens (-)';
|
|
275
|
+
}
|
|
276
|
+
// Check if folder already exists
|
|
277
|
+
const topicPath = path.join(targetPath, trimmed);
|
|
278
|
+
if (fs.existsSync(topicPath)) {
|
|
279
|
+
return `Topic "${trimmed}" already exists at this location`;
|
|
280
|
+
}
|
|
281
|
+
return true;
|
|
282
|
+
}
|
|
283
|
+
}
|
|
@@ -1,31 +1,25 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import type {
|
|
3
|
-
import type {
|
|
4
|
-
import type {
|
|
5
|
-
import type { ITrackingService } from '
|
|
6
|
-
import {
|
|
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';
|
|
7
8
|
type CleanupStrategy = 'automatic' | 'manual';
|
|
8
|
-
export
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
fileService: IFileService;
|
|
16
|
-
legacyRuleDetector: LegacyRuleDetector;
|
|
17
|
-
templateService: IRuleTemplateService;
|
|
18
|
-
trackingService: ITrackingService;
|
|
19
|
-
};
|
|
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);
|
|
20
16
|
/**
|
|
21
17
|
* Prompts the user to select an agent.
|
|
22
|
-
* This method is protected to allow test overrides.
|
|
23
18
|
* @returns The selected agent
|
|
24
19
|
*/
|
|
25
20
|
protected promptForAgentSelection(): Promise<Agent>;
|
|
26
21
|
/**
|
|
27
22
|
* Prompts the user to choose cleanup strategy for legacy rules.
|
|
28
|
-
* This method is protected to allow test overrides.
|
|
29
23
|
* @returns The chosen cleanup strategy
|
|
30
24
|
*/
|
|
31
25
|
protected promptForCleanupStrategy(): Promise<CleanupStrategy>;
|
|
@@ -1,14 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { FsFileService } from '../infra/file/fs-file-service.js';
|
|
5
|
-
import { AGENT_RULE_CONFIGS } from '../infra/rule/agent-rule-config.js';
|
|
6
|
-
import { BRV_RULE_MARKERS, BRV_RULE_TAG } from '../infra/rule/constants.js';
|
|
7
|
-
import { LegacyRuleDetector } from '../infra/rule/legacy-rule-detector.js';
|
|
8
|
-
import { RuleTemplateService } from '../infra/rule/rule-template-service.js';
|
|
9
|
-
import { KeychainTokenStore } from '../infra/storage/keychain-token-store.js';
|
|
10
|
-
import { FsTemplateLoader } from '../infra/template/fs-template-loader.js';
|
|
11
|
-
import { MixpanelTrackingService } from '../infra/tracking/mixpanel-tracking-service.js';
|
|
1
|
+
import { AGENT_VALUES } from '../../core/domain/entities/agent.js';
|
|
2
|
+
import { AGENT_RULE_CONFIGS } from '../rule/agent-rule-config.js';
|
|
3
|
+
import { BRV_RULE_MARKERS, BRV_RULE_TAG } from '../rule/constants.js';
|
|
12
4
|
/**
|
|
13
5
|
* Array of all agents with name and value properties.
|
|
14
6
|
* Useful for UI components like select dropdowns.
|
|
@@ -17,50 +9,41 @@ const AGENTS = AGENT_VALUES.map((agent) => ({
|
|
|
17
9
|
name: agent,
|
|
18
10
|
value: agent,
|
|
19
11
|
}));
|
|
20
|
-
export
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
return {
|
|
34
|
-
fileService,
|
|
35
|
-
legacyRuleDetector: new LegacyRuleDetector(),
|
|
36
|
-
templateService,
|
|
37
|
-
trackingService: new MixpanelTrackingService(new KeychainTokenStore()),
|
|
38
|
-
};
|
|
12
|
+
export class GenerateRulesUseCase {
|
|
13
|
+
fileService;
|
|
14
|
+
legacyRuleDetector;
|
|
15
|
+
templateService;
|
|
16
|
+
terminal;
|
|
17
|
+
trackingService;
|
|
18
|
+
// eslint-disable-next-line max-params
|
|
19
|
+
constructor(fileService, legacyRuleDetector, templateService, terminal, trackingService) {
|
|
20
|
+
this.fileService = fileService;
|
|
21
|
+
this.legacyRuleDetector = legacyRuleDetector;
|
|
22
|
+
this.templateService = templateService;
|
|
23
|
+
this.terminal = terminal;
|
|
24
|
+
this.trackingService = trackingService;
|
|
39
25
|
}
|
|
40
26
|
/**
|
|
41
27
|
* Prompts the user to select an agent.
|
|
42
|
-
* This method is protected to allow test overrides.
|
|
43
28
|
* @returns The selected agent
|
|
44
29
|
*/
|
|
45
30
|
async promptForAgentSelection() {
|
|
46
|
-
|
|
31
|
+
return this.terminal.search({
|
|
47
32
|
message: 'Which agent you are using (type to search):',
|
|
48
|
-
|
|
33
|
+
source(input) {
|
|
49
34
|
if (!input)
|
|
50
35
|
return AGENTS;
|
|
51
36
|
return AGENTS.filter((agent) => agent.name.toLowerCase().includes(input.toLowerCase()) ||
|
|
52
37
|
agent.value.toLowerCase().includes(input.toLowerCase()));
|
|
53
38
|
},
|
|
54
39
|
});
|
|
55
|
-
return answer;
|
|
56
40
|
}
|
|
57
41
|
/**
|
|
58
42
|
* Prompts the user to choose cleanup strategy for legacy rules.
|
|
59
|
-
* This method is protected to allow test overrides.
|
|
60
43
|
* @returns The chosen cleanup strategy
|
|
61
44
|
*/
|
|
62
45
|
async promptForCleanupStrategy() {
|
|
63
|
-
return select({
|
|
46
|
+
return this.terminal.select({
|
|
64
47
|
choices: [
|
|
65
48
|
{
|
|
66
49
|
description: 'New rules will be added with boundary markers. You manually remove old sections at your convenience.',
|
|
@@ -84,7 +67,7 @@ export default class GenRules extends Command {
|
|
|
84
67
|
* @returns True if the user wants to create the file, false otherwise
|
|
85
68
|
*/
|
|
86
69
|
async promptForFileCreation(agent, filePath) {
|
|
87
|
-
return confirm({
|
|
70
|
+
return this.terminal.confirm({
|
|
88
71
|
default: true,
|
|
89
72
|
message: `Rule file '${filePath}' doesn't exist. Create it with ByteRover rules?`,
|
|
90
73
|
});
|
|
@@ -96,36 +79,35 @@ export default class GenRules extends Command {
|
|
|
96
79
|
* @returns True if the user confirms overwrite, false otherwise
|
|
97
80
|
*/
|
|
98
81
|
async promptForOverwriteConfirmation(agent) {
|
|
99
|
-
return confirm({
|
|
82
|
+
return this.terminal.confirm({
|
|
100
83
|
default: true,
|
|
101
84
|
message: `Rule file already exists for ${agent}. Overwrite?`,
|
|
102
85
|
});
|
|
103
86
|
}
|
|
104
87
|
async run() {
|
|
105
|
-
|
|
106
|
-
await trackingService.track('rule:generate');
|
|
88
|
+
await this.trackingService.track('rule:generate');
|
|
107
89
|
const selectedAgent = await this.promptForAgentSelection();
|
|
108
90
|
const { filePath, writeMode } = AGENT_RULE_CONFIGS[selectedAgent];
|
|
109
|
-
this.log(`Generating rules for: ${selectedAgent}`);
|
|
91
|
+
this.terminal.log(`Generating rules for: ${selectedAgent}`);
|
|
110
92
|
// STEP 1: Check if file exists
|
|
111
|
-
const fileExists = await fileService.exists(filePath);
|
|
93
|
+
const fileExists = await this.fileService.exists(filePath);
|
|
112
94
|
if (!fileExists) {
|
|
113
95
|
// Scenario A: File doesn't exist
|
|
114
96
|
const shouldCreate = await this.promptForFileCreation(selectedAgent, filePath);
|
|
115
97
|
if (!shouldCreate) {
|
|
116
|
-
this.log(`Skipped rule file creation for ${selectedAgent}`);
|
|
98
|
+
this.terminal.log(`Skipped rule file creation for ${selectedAgent}`);
|
|
117
99
|
return;
|
|
118
100
|
}
|
|
119
101
|
await this.createNewRuleFile({
|
|
120
102
|
agent: selectedAgent,
|
|
121
103
|
filePath,
|
|
122
|
-
fileService,
|
|
123
|
-
templateService,
|
|
104
|
+
fileService: this.fileService,
|
|
105
|
+
templateService: this.templateService,
|
|
124
106
|
});
|
|
125
107
|
return;
|
|
126
108
|
}
|
|
127
109
|
// STEP 2: File exists - read content
|
|
128
|
-
const content = await fileService.read(filePath);
|
|
110
|
+
const content = await this.fileService.read(filePath);
|
|
129
111
|
// STEP 3: Check for LEGACY rules (priority: clean these up first)
|
|
130
112
|
const hasFooterTag = content.includes(`${BRV_RULE_TAG} ${selectedAgent}`);
|
|
131
113
|
const hasBoundaryMarkers = content.includes(BRV_RULE_MARKERS.START) && content.includes(BRV_RULE_MARKERS.END);
|
|
@@ -136,9 +118,9 @@ export default class GenRules extends Command {
|
|
|
136
118
|
agent: selectedAgent,
|
|
137
119
|
content,
|
|
138
120
|
filePath,
|
|
139
|
-
fileService,
|
|
140
|
-
legacyRuleDetector,
|
|
141
|
-
templateService,
|
|
121
|
+
fileService: this.fileService,
|
|
122
|
+
legacyRuleDetector: this.legacyRuleDetector,
|
|
123
|
+
templateService: this.templateService,
|
|
142
124
|
});
|
|
143
125
|
return;
|
|
144
126
|
}
|
|
@@ -147,15 +129,15 @@ export default class GenRules extends Command {
|
|
|
147
129
|
// Scenario C: New rules exist - prompt for overwrite
|
|
148
130
|
const shouldOverwrite = await this.promptForOverwriteConfirmation(selectedAgent);
|
|
149
131
|
if (!shouldOverwrite) {
|
|
150
|
-
this.log(`Skipped rule file update for ${selectedAgent}`);
|
|
132
|
+
this.terminal.log(`Skipped rule file update for ${selectedAgent}`);
|
|
151
133
|
return;
|
|
152
134
|
}
|
|
153
135
|
await this.replaceExistingRules({
|
|
154
136
|
agent: selectedAgent,
|
|
155
137
|
content,
|
|
156
138
|
filePath,
|
|
157
|
-
fileService,
|
|
158
|
-
templateService,
|
|
139
|
+
fileService: this.fileService,
|
|
140
|
+
templateService: this.templateService,
|
|
159
141
|
writeMode,
|
|
160
142
|
});
|
|
161
143
|
return;
|
|
@@ -164,8 +146,8 @@ export default class GenRules extends Command {
|
|
|
164
146
|
await this.appendRulesToFile({
|
|
165
147
|
agent: selectedAgent,
|
|
166
148
|
filePath,
|
|
167
|
-
fileService,
|
|
168
|
-
templateService,
|
|
149
|
+
fileService: this.fileService,
|
|
150
|
+
templateService: this.templateService,
|
|
169
151
|
writeMode,
|
|
170
152
|
});
|
|
171
153
|
}
|
|
@@ -178,7 +160,7 @@ export default class GenRules extends Command {
|
|
|
178
160
|
// For dedicated ByteRover files, overwrite; for shared instruction files, append
|
|
179
161
|
const mode = writeMode === 'overwrite' ? 'overwrite' : 'append';
|
|
180
162
|
await fileService.write(ruleContent, filePath, mode);
|
|
181
|
-
this.log(`✅ Successfully added rule file for ${agent}`);
|
|
163
|
+
this.terminal.log(`✅ Successfully added rule file for ${agent}`);
|
|
182
164
|
}
|
|
183
165
|
/**
|
|
184
166
|
* Creates a new rule file with ByteRover rules.
|
|
@@ -187,7 +169,7 @@ export default class GenRules extends Command {
|
|
|
187
169
|
const { agent, filePath, fileService, templateService } = params;
|
|
188
170
|
const ruleContent = await templateService.generateRuleContent(agent);
|
|
189
171
|
await fileService.write(ruleContent, filePath, 'overwrite');
|
|
190
|
-
this.log(`✅ Successfully created rule file for ${agent} at ${filePath}`);
|
|
172
|
+
this.terminal.log(`✅ Successfully created rule file for ${agent} at ${filePath}`);
|
|
191
173
|
}
|
|
192
174
|
/**
|
|
193
175
|
* Handles legacy rules cleanup with user choice of automatic or manual.
|
|
@@ -196,22 +178,21 @@ export default class GenRules extends Command {
|
|
|
196
178
|
const { agent, content, filePath, fileService, legacyRuleDetector, templateService } = params;
|
|
197
179
|
const detectionResult = legacyRuleDetector.detectLegacyRules(content, agent);
|
|
198
180
|
const { reliableMatches, uncertainMatches } = detectionResult;
|
|
199
|
-
this.log(`\n⚠️ Detected ${reliableMatches.length + uncertainMatches.length} old ByteRover rule section(s) in ${filePath}:\n`);
|
|
181
|
+
this.terminal.log(`\n⚠️ Detected ${reliableMatches.length + uncertainMatches.length} old ByteRover rule section(s) in ${filePath}:\n`);
|
|
200
182
|
if (reliableMatches.length > 0) {
|
|
201
|
-
this.log('Reliable matches:');
|
|
183
|
+
this.terminal.log('Reliable matches:');
|
|
202
184
|
for (const [index, match] of reliableMatches.entries()) {
|
|
203
|
-
this.log(` Section ${index + 1}: lines ${match.startLine}-${match.endLine}`);
|
|
185
|
+
this.terminal.log(` Section ${index + 1}: lines ${match.startLine}-${match.endLine}`);
|
|
204
186
|
}
|
|
205
|
-
this.log();
|
|
187
|
+
this.terminal.log('');
|
|
206
188
|
}
|
|
207
189
|
if (uncertainMatches.length > 0) {
|
|
208
|
-
this.log(' ⚠️ Uncertain matches (cannot determine start):');
|
|
190
|
+
this.terminal.log(' ⚠️ Uncertain matches (cannot determine start):');
|
|
209
191
|
for (const match of uncertainMatches) {
|
|
210
|
-
this.log(` Footer found at line ${match.footerLine}`);
|
|
211
|
-
this.log(` Reason: ${match.reason}`);
|
|
192
|
+
this.terminal.log(` Footer found at line ${match.footerLine}`);
|
|
193
|
+
this.terminal.log(` Reason: ${match.reason}`);
|
|
212
194
|
}
|
|
213
|
-
this.log();
|
|
214
|
-
this.log('⚠️ Due to uncertain matches, only manual cleanup is available.\n');
|
|
195
|
+
this.terminal.log('\n⚠️ Due to uncertain matches, only manual cleanup is available.\n');
|
|
215
196
|
await this.performManualCleanup({
|
|
216
197
|
agent,
|
|
217
198
|
filePath,
|
|
@@ -243,7 +224,7 @@ export default class GenRules extends Command {
|
|
|
243
224
|
async performAutomaticCleanup(params) {
|
|
244
225
|
const { agent, filePath, fileService, reliableMatches, templateService } = params;
|
|
245
226
|
const backupPath = await fileService.createBackup(filePath);
|
|
246
|
-
this.log(`📦 Backup created: ${backupPath}`);
|
|
227
|
+
this.terminal.log(`📦 Backup created: ${backupPath}`);
|
|
247
228
|
let content = await fileService.read(filePath);
|
|
248
229
|
// Remove all reliable matches (in reverse order to preserve line numbers)
|
|
249
230
|
const sortedMatches = [...reliableMatches].sort((a, b) => b.startLine - a.startLine);
|
|
@@ -255,25 +236,25 @@ export default class GenRules extends Command {
|
|
|
255
236
|
// Append new rules
|
|
256
237
|
const ruleContent = await templateService.generateRuleContent(agent);
|
|
257
238
|
await fileService.write(ruleContent, filePath, 'append');
|
|
258
|
-
this.log(`✅ Removed ${reliableMatches.length} old ByteRover section(s)`);
|
|
259
|
-
this.log(`✅ Added new rules with boundary markers`);
|
|
260
|
-
this.log(`\nYou can safely delete the backup file once verified.`);
|
|
239
|
+
this.terminal.log(`✅ Removed ${reliableMatches.length} old ByteRover section(s)`);
|
|
240
|
+
this.terminal.log(`✅ Added new rules with boundary markers`);
|
|
241
|
+
this.terminal.log(`\nYou can safely delete the backup file once verified.`);
|
|
261
242
|
}
|
|
262
243
|
async performManualCleanup(params) {
|
|
263
244
|
const { agent, filePath, fileService, reliableMatches, templateService, uncertainMatches } = params;
|
|
264
245
|
const ruleContent = await templateService.generateRuleContent(agent);
|
|
265
246
|
await fileService.write(ruleContent, filePath, 'append');
|
|
266
|
-
this.log(`✅ New ByteRover rules added with boundary markers\n`);
|
|
267
|
-
this.log('Please manually remove old sections:');
|
|
247
|
+
this.terminal.log(`✅ New ByteRover rules added with boundary markers\n`);
|
|
248
|
+
this.terminal.log('Please manually remove old sections:');
|
|
268
249
|
for (const [index, match] of reliableMatches.entries()) {
|
|
269
|
-
this.log(` - Section ${index + 1}: lines ${match.startLine}-${match.endLine} in ${filePath}`);
|
|
250
|
+
this.terminal.log(` - Section ${index + 1}: lines ${match.startLine}-${match.endLine} in ${filePath}`);
|
|
270
251
|
}
|
|
271
252
|
for (const match of uncertainMatches) {
|
|
272
|
-
this.log(` - Section ending at line ${match.footerLine} in ${filePath}`);
|
|
253
|
+
this.terminal.log(` - Section ending at line ${match.footerLine} in ${filePath}`);
|
|
273
254
|
}
|
|
274
|
-
this.log('\nKeep only the section between:');
|
|
275
|
-
this.log(' <!-- BEGIN BYTEROVER RULES -->');
|
|
276
|
-
this.log(' <!-- END BYTEROVER RULES -->');
|
|
255
|
+
this.terminal.log('\nKeep only the section between:');
|
|
256
|
+
this.terminal.log(' <!-- BEGIN BYTEROVER RULES -->');
|
|
257
|
+
this.terminal.log(' <!-- END BYTEROVER RULES -->');
|
|
277
258
|
}
|
|
278
259
|
/**
|
|
279
260
|
* Replaces existing ByteRover rules (with boundary markers) with new rules.
|
|
@@ -292,13 +273,13 @@ export default class GenRules extends Command {
|
|
|
292
273
|
const startIndex = content.indexOf(startMarker);
|
|
293
274
|
const endIndex = content.indexOf(endMarker, startIndex);
|
|
294
275
|
if (startIndex === -1 || endIndex === -1) {
|
|
295
|
-
this.error('Could not find boundary markers in the file');
|
|
276
|
+
this.terminal.error('Could not find boundary markers in the file');
|
|
296
277
|
}
|
|
297
278
|
const before = content.slice(0, startIndex);
|
|
298
279
|
const after = content.slice(endIndex + endMarker.length);
|
|
299
280
|
const newContent = before + ruleContent + after;
|
|
300
281
|
await fileService.write(newContent, filePath, 'overwrite');
|
|
301
282
|
}
|
|
302
|
-
this.log(`✅ Successfully updated rule file for ${agent}`);
|
|
283
|
+
this.terminal.log(`✅ Successfully updated rule file for ${agent}`);
|
|
303
284
|
}
|
|
304
285
|
}
|