byterover-cli 0.2.1 → 0.3.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 +56 -56
- package/bin/dev.js +1 -1
- package/dist/commands/cipher-agent/run.d.ts +111 -0
- package/dist/commands/cipher-agent/run.js +493 -0
- package/dist/commands/cipher-agent/set-prompt.d.ts +14 -0
- package/dist/commands/cipher-agent/set-prompt.js +53 -0
- package/dist/commands/cipher-agent/show-prompt.d.ts +11 -0
- package/dist/commands/cipher-agent/show-prompt.js +48 -0
- package/dist/commands/clear.d.ts +6 -0
- package/dist/commands/clear.js +36 -15
- package/dist/commands/curate.d.ts +74 -0
- package/dist/commands/curate.js +396 -0
- package/dist/commands/foo.d.ts +12 -0
- package/dist/commands/foo.js +61 -0
- package/dist/commands/gen-rules.d.ts +3 -0
- package/dist/commands/gen-rules.js +39 -20
- package/dist/commands/init.d.ts +48 -3
- package/dist/commands/init.js +242 -70
- package/dist/commands/login.js +9 -4
- package/dist/commands/pull.d.ts +33 -0
- package/dist/commands/pull.js +115 -0
- package/dist/commands/push.d.ts +13 -13
- package/dist/commands/push.js +81 -101
- package/dist/commands/query.d.ts +63 -0
- package/dist/commands/query.js +349 -0
- package/dist/commands/space/list.d.ts +5 -2
- package/dist/commands/space/list.js +60 -56
- package/dist/commands/space/switch.d.ts +16 -0
- package/dist/commands/space/switch.js +102 -53
- package/dist/commands/status.d.ts +5 -2
- package/dist/commands/status.js +43 -33
- package/dist/commands/watch.d.ts +23 -0
- package/dist/commands/watch.js +171 -0
- package/dist/config/auth.config.js +14 -2
- package/dist/config/context-tree-domains.d.ts +12 -0
- package/dist/config/context-tree-domains.js +29 -0
- package/dist/config/environment.d.ts +6 -0
- package/dist/config/environment.js +9 -2
- package/dist/constants.d.ts +5 -0
- package/dist/constants.js +6 -0
- package/dist/core/domain/cipher/agent/agent-state-machine.d.ts +128 -0
- package/dist/core/domain/cipher/agent/agent-state-machine.js +183 -0
- package/dist/core/domain/cipher/agent/agent-state.d.ts +77 -0
- package/dist/core/domain/cipher/agent/agent-state.js +59 -0
- package/dist/core/domain/cipher/agent/index.d.ts +7 -0
- package/dist/core/domain/cipher/agent/index.js +7 -0
- package/dist/core/domain/cipher/agent-events/index.d.ts +8 -0
- package/dist/core/domain/cipher/agent-events/index.js +7 -0
- package/dist/core/domain/cipher/agent-events/types.d.ts +419 -0
- package/dist/core/domain/cipher/agent-events/types.js +42 -0
- package/dist/core/domain/cipher/blob/types.d.ts +108 -0
- package/dist/core/domain/cipher/errors/blob-error.d.ts +36 -0
- package/dist/core/domain/cipher/errors/blob-error.js +68 -0
- package/dist/core/domain/cipher/errors/file-system-error.d.ts +211 -0
- package/dist/core/domain/cipher/errors/file-system-error.js +291 -0
- package/dist/core/domain/cipher/errors/llm-error.d.ts +120 -0
- package/dist/core/domain/cipher/errors/llm-error.js +161 -0
- package/dist/core/domain/cipher/errors/memory-error.d.ts +35 -0
- package/dist/core/domain/cipher/errors/memory-error.js +62 -0
- package/dist/core/domain/cipher/errors/process-error-code.d.ts +97 -0
- package/dist/core/domain/cipher/errors/process-error-code.js +98 -0
- package/dist/core/domain/cipher/errors/process-error.d.ts +135 -0
- package/dist/core/domain/cipher/errors/process-error.js +173 -0
- package/dist/core/domain/cipher/errors/session-error.d.ts +56 -0
- package/dist/core/domain/cipher/errors/session-error.js +74 -0
- package/dist/core/domain/cipher/errors/tool-error.d.ts +57 -0
- package/dist/core/domain/cipher/errors/tool-error.js +81 -0
- package/dist/core/domain/cipher/file-system/types.d.ts +203 -0
- package/dist/core/domain/cipher/memory/types.d.ts +102 -0
- package/dist/core/domain/cipher/memory/types.js +4 -0
- package/dist/core/domain/cipher/parsed-interaction.d.ts +47 -0
- package/dist/core/domain/cipher/parsed-interaction.js +25 -0
- package/dist/core/domain/cipher/process/types.d.ts +286 -0
- package/dist/core/domain/cipher/session/types.d.ts +54 -0
- package/dist/core/domain/cipher/storage/history-types.d.ts +38 -0
- package/dist/core/domain/cipher/system-prompt/types.d.ts +131 -0
- package/dist/core/domain/cipher/todos/index.d.ts +4 -0
- package/dist/core/domain/cipher/todos/index.js +4 -0
- package/dist/core/domain/cipher/todos/types.d.ts +57 -0
- package/dist/core/domain/cipher/todos/types.js +5 -0
- package/dist/core/domain/cipher/tools/constants.d.ts +28 -0
- package/dist/core/domain/cipher/tools/constants.js +24 -0
- package/dist/core/domain/cipher/tools/tool-error.d.ts +183 -0
- package/dist/core/domain/cipher/tools/tool-error.js +246 -0
- package/dist/core/domain/cipher/tools/types.d.ts +145 -0
- package/dist/core/domain/entities/brv-config.d.ts +42 -6
- package/dist/core/domain/entities/brv-config.js +115 -17
- package/dist/core/domain/entities/cogit-push-context.d.ts +38 -0
- package/dist/core/domain/entities/cogit-push-context.js +91 -0
- package/dist/core/domain/entities/cogit-push-response.d.ts +20 -0
- package/dist/core/domain/entities/cogit-push-response.js +31 -0
- package/dist/core/domain/entities/cogit-snapshot-author.d.ts +24 -0
- package/dist/core/domain/entities/cogit-snapshot-author.js +39 -0
- package/dist/core/domain/entities/cogit-snapshot-file.d.ts +34 -0
- package/dist/core/domain/entities/cogit-snapshot-file.js +59 -0
- package/dist/core/domain/entities/cogit-snapshot.d.ts +31 -0
- package/dist/core/domain/entities/cogit-snapshot.js +58 -0
- package/dist/core/domain/entities/context-tree-index.d.ts +26 -0
- package/dist/core/domain/entities/context-tree-index.js +27 -0
- package/dist/core/domain/entities/context-tree-snapshot.d.ts +56 -0
- package/dist/core/domain/entities/context-tree-snapshot.js +83 -0
- package/dist/core/domain/entities/event.d.ts +1 -1
- package/dist/core/domain/entities/event.js +3 -1
- package/dist/core/domain/entities/parser.d.ts +567 -0
- package/dist/core/domain/entities/parser.js +10 -0
- package/dist/core/domain/entities/playbook.d.ts +2 -23
- package/dist/core/domain/entities/playbook.js +2 -70
- package/dist/core/domain/errors/brv-config-version-error.d.ts +16 -0
- package/dist/core/domain/errors/brv-config-version-error.js +21 -0
- package/dist/core/domain/knowledge/directory-manager.d.ts +80 -0
- package/dist/core/domain/knowledge/directory-manager.js +145 -0
- package/dist/core/domain/knowledge/markdown-writer.d.ts +18 -0
- package/dist/core/domain/knowledge/markdown-writer.js +18 -0
- package/dist/core/domain/knowledge/relation-parser.d.ts +90 -0
- package/dist/core/domain/knowledge/relation-parser.js +131 -0
- package/dist/core/interfaces/cipher/cipher-services.d.ts +71 -0
- package/dist/core/interfaces/cipher/cipher-services.js +1 -0
- package/dist/core/interfaces/cipher/i-blob-storage.d.ts +78 -0
- package/dist/core/interfaces/cipher/i-blob-storage.js +1 -0
- package/dist/core/interfaces/cipher/i-chat-session.d.ts +62 -0
- package/dist/core/interfaces/cipher/i-chat-session.js +1 -0
- package/dist/core/interfaces/cipher/i-cipher-agent.d.ts +88 -0
- package/dist/core/interfaces/cipher/i-cipher-agent.js +1 -0
- package/dist/core/interfaces/cipher/i-coding-agent-log-parser.d.ts +20 -0
- package/dist/core/interfaces/cipher/i-coding-agent-log-parser.js +1 -0
- package/dist/core/interfaces/cipher/i-coding-agent-log-watcher.d.ts +31 -0
- package/dist/core/interfaces/cipher/i-coding-agent-log-watcher.js +1 -0
- package/dist/core/interfaces/cipher/i-content-generator.d.ts +120 -0
- package/dist/core/interfaces/cipher/i-content-generator.js +12 -0
- package/dist/core/interfaces/cipher/i-event-emitter.d.ts +76 -0
- package/dist/core/interfaces/cipher/i-event-emitter.js +1 -0
- package/dist/core/interfaces/cipher/i-file-system.d.ts +68 -0
- package/dist/core/interfaces/cipher/i-file-system.js +1 -0
- package/dist/core/interfaces/cipher/i-history-storage.d.ts +53 -0
- package/dist/core/interfaces/cipher/i-history-storage.js +1 -0
- package/dist/core/interfaces/cipher/i-llm-provider.d.ts +14 -0
- package/dist/core/interfaces/cipher/i-llm-provider.js +1 -0
- package/dist/core/interfaces/cipher/i-llm-service.d.ts +62 -0
- package/dist/core/interfaces/cipher/i-llm-service.js +1 -0
- package/dist/core/interfaces/cipher/i-logger.d.ts +78 -0
- package/dist/core/interfaces/cipher/i-logger.js +28 -0
- package/dist/core/interfaces/cipher/i-message-formatter.d.ts +44 -0
- package/dist/core/interfaces/cipher/i-message-formatter.js +1 -0
- package/dist/core/interfaces/cipher/i-policy-engine.d.ts +102 -0
- package/dist/core/interfaces/cipher/i-policy-engine.js +9 -0
- package/dist/core/interfaces/cipher/i-process-service.d.ts +65 -0
- package/dist/core/interfaces/cipher/i-process-service.js +1 -0
- package/dist/core/interfaces/cipher/i-system-prompt-contributor.d.ts +25 -0
- package/dist/core/interfaces/cipher/i-system-prompt-contributor.js +1 -0
- package/dist/core/interfaces/cipher/i-tokenizer.d.ts +15 -0
- package/dist/core/interfaces/cipher/i-tokenizer.js +1 -0
- package/dist/core/interfaces/cipher/i-tool-provider.d.ts +64 -0
- package/dist/core/interfaces/cipher/i-tool-provider.js +1 -0
- package/dist/core/interfaces/cipher/i-tool-scheduler.d.ts +103 -0
- package/dist/core/interfaces/cipher/i-tool-scheduler.js +11 -0
- package/dist/core/interfaces/cipher/llm-types.d.ts +46 -0
- package/dist/core/interfaces/cipher/llm-types.js +5 -0
- package/dist/core/interfaces/cipher/message-types.d.ts +118 -0
- package/dist/core/interfaces/cipher/message-types.js +5 -0
- package/dist/core/interfaces/cipher/tokenizer-types.d.ts +11 -0
- package/dist/core/interfaces/cipher/tokenizer-types.js +14 -0
- package/dist/core/interfaces/i-cogit-pull-service.d.ts +24 -0
- package/dist/core/interfaces/i-cogit-pull-service.js +1 -0
- package/dist/core/interfaces/i-cogit-push-service.d.ts +27 -0
- package/dist/core/interfaces/i-cogit-push-service.js +1 -0
- package/dist/core/interfaces/i-context-file-reader.d.ts +32 -0
- package/dist/core/interfaces/i-context-file-reader.js +1 -0
- package/dist/core/interfaces/i-context-tree-service.d.ts +21 -0
- package/dist/core/interfaces/i-context-tree-service.js +1 -0
- package/dist/core/interfaces/i-context-tree-snapshot-service.d.ts +36 -0
- package/dist/core/interfaces/i-context-tree-snapshot-service.js +1 -0
- package/dist/core/interfaces/i-context-tree-writer-service.d.ts +32 -0
- package/dist/core/interfaces/i-context-tree-writer-service.js +1 -0
- package/dist/core/interfaces/i-file-watcher-service.d.ts +41 -0
- package/dist/core/interfaces/i-file-watcher-service.js +1 -0
- package/dist/core/interfaces/parser/i-clean-parser-service.d.ts +18 -0
- package/dist/core/interfaces/parser/i-clean-parser-service.js +1 -0
- package/dist/core/interfaces/parser/i-raw-parser-service.d.ts +17 -0
- package/dist/core/interfaces/parser/i-raw-parser-service.js +1 -0
- package/dist/core/interfaces/parser/i-session-normalizer.d.ts +56 -0
- package/dist/core/interfaces/parser/i-session-normalizer.js +1 -0
- package/dist/hooks/command_not_found/handle-invalid-commands.d.ts +7 -0
- package/dist/hooks/command_not_found/handle-invalid-commands.js +32 -0
- package/dist/hooks/error/clean-errors.d.ts +7 -0
- package/dist/hooks/error/clean-errors.js +50 -0
- package/dist/hooks/init/welcome.js +72 -1
- package/dist/hooks/prerun/validate-brv-config-version.d.ts +28 -0
- package/dist/hooks/prerun/validate-brv-config-version.js +43 -0
- package/dist/infra/cipher/agent-service-factory.d.ts +86 -0
- package/dist/infra/cipher/agent-service-factory.js +212 -0
- package/dist/infra/cipher/blob/blob-storage-factory.d.ts +13 -0
- package/dist/infra/cipher/blob/blob-storage-factory.js +14 -0
- package/dist/infra/cipher/blob/index.d.ts +10 -0
- package/dist/infra/cipher/blob/index.js +12 -0
- package/dist/infra/cipher/blob/migrations.d.ts +63 -0
- package/dist/infra/cipher/blob/migrations.js +148 -0
- package/dist/infra/cipher/blob/sqlite-blob-storage.d.ts +82 -0
- package/dist/infra/cipher/blob/sqlite-blob-storage.js +307 -0
- package/dist/infra/cipher/cipher-agent-state-manager.d.ts +63 -0
- package/dist/infra/cipher/cipher-agent-state-manager.js +108 -0
- package/dist/infra/cipher/cipher-agent.d.ts +182 -0
- package/dist/infra/cipher/cipher-agent.js +317 -0
- package/dist/infra/cipher/command-parser.d.ts +23 -0
- package/dist/infra/cipher/command-parser.js +85 -0
- package/dist/infra/cipher/display/todo-display.d.ts +23 -0
- package/dist/infra/cipher/display/todo-display.js +129 -0
- package/dist/infra/cipher/events/event-emitter.d.ts +137 -0
- package/dist/infra/cipher/events/event-emitter.js +158 -0
- package/dist/infra/cipher/exit-codes.d.ts +44 -0
- package/dist/infra/cipher/exit-codes.js +58 -0
- package/dist/infra/cipher/file-system/file-system-service.d.ts +105 -0
- package/dist/infra/cipher/file-system/file-system-service.js +641 -0
- package/dist/infra/cipher/file-system/gitignore-filter.d.ts +77 -0
- package/dist/infra/cipher/file-system/gitignore-filter.js +120 -0
- package/dist/infra/cipher/file-system/glob-utils.d.ts +60 -0
- package/dist/infra/cipher/file-system/glob-utils.js +120 -0
- package/dist/infra/cipher/file-system/path-validator.d.ts +69 -0
- package/dist/infra/cipher/file-system/path-validator.js +184 -0
- package/dist/infra/cipher/grpc/internal-llm-grpc-service.d.ts +149 -0
- package/dist/infra/cipher/grpc/internal-llm-grpc-service.js +364 -0
- package/dist/infra/cipher/grpc/internal-llm-grpc.proto +94 -0
- package/dist/infra/cipher/interactive-commands.d.ts +16 -0
- package/dist/infra/cipher/interactive-commands.js +198 -0
- package/dist/infra/cipher/interactive-loop.d.ts +24 -0
- package/dist/infra/cipher/interactive-loop.js +352 -0
- package/dist/infra/cipher/llm/context/async-mutex.d.ts +59 -0
- package/dist/infra/cipher/llm/context/async-mutex.js +92 -0
- package/dist/infra/cipher/llm/context/compression/index.d.ts +6 -0
- package/dist/infra/cipher/llm/context/compression/index.js +5 -0
- package/dist/infra/cipher/llm/context/compression/middle-removal.d.ts +40 -0
- package/dist/infra/cipher/llm/context/compression/middle-removal.js +76 -0
- package/dist/infra/cipher/llm/context/compression/oldest-removal.d.ts +38 -0
- package/dist/infra/cipher/llm/context/compression/oldest-removal.js +53 -0
- package/dist/infra/cipher/llm/context/compression/types.d.ts +36 -0
- package/dist/infra/cipher/llm/context/compression/types.js +1 -0
- package/dist/infra/cipher/llm/context/context-manager.d.ts +234 -0
- package/dist/infra/cipher/llm/context/context-manager.js +419 -0
- package/dist/infra/cipher/llm/context/index.d.ts +2 -0
- package/dist/infra/cipher/llm/context/index.js +2 -0
- package/dist/infra/cipher/llm/context/loop-detector.d.ts +125 -0
- package/dist/infra/cipher/llm/context/loop-detector.js +194 -0
- package/dist/infra/cipher/llm/context/utils.d.ts +17 -0
- package/dist/infra/cipher/llm/context/utils.js +89 -0
- package/dist/infra/cipher/llm/formatters/claude-formatter.d.ts +54 -0
- package/dist/infra/cipher/llm/formatters/claude-formatter.js +182 -0
- package/dist/infra/cipher/llm/formatters/gemini-formatter.d.ts +69 -0
- package/dist/infra/cipher/llm/formatters/gemini-formatter.js +253 -0
- package/dist/infra/cipher/llm/formatters/openrouter-formatter.d.ts +47 -0
- package/dist/infra/cipher/llm/formatters/openrouter-formatter.js +238 -0
- package/dist/infra/cipher/llm/generators/byterover-content-generator.d.ts +92 -0
- package/dist/infra/cipher/llm/generators/byterover-content-generator.js +211 -0
- package/dist/infra/cipher/llm/generators/index.d.ts +13 -0
- package/dist/infra/cipher/llm/generators/index.js +13 -0
- package/dist/infra/cipher/llm/generators/logging-content-generator.d.ts +104 -0
- package/dist/infra/cipher/llm/generators/logging-content-generator.js +182 -0
- package/dist/infra/cipher/llm/generators/openrouter-content-generator.d.ts +93 -0
- package/dist/infra/cipher/llm/generators/openrouter-content-generator.js +254 -0
- package/dist/infra/cipher/llm/generators/retryable-content-generator.d.ts +90 -0
- package/dist/infra/cipher/llm/generators/retryable-content-generator.js +157 -0
- package/dist/infra/cipher/llm/index.d.ts +9 -0
- package/dist/infra/cipher/llm/index.js +13 -0
- package/dist/infra/cipher/llm/internal-llm-service.d.ts +308 -0
- package/dist/infra/cipher/llm/internal-llm-service.js +724 -0
- package/dist/infra/cipher/llm/openrouter-llm-service.d.ts +183 -0
- package/dist/infra/cipher/llm/openrouter-llm-service.js +386 -0
- package/dist/infra/cipher/llm/response-validator.d.ts +89 -0
- package/dist/infra/cipher/llm/response-validator.js +157 -0
- package/dist/infra/cipher/llm/retry/index.d.ts +10 -0
- package/dist/infra/cipher/llm/retry/index.js +10 -0
- package/dist/infra/cipher/llm/retry/retry-policy.d.ts +74 -0
- package/dist/infra/cipher/llm/retry/retry-policy.js +146 -0
- package/dist/infra/cipher/llm/retry/retry-with-backoff.d.ts +113 -0
- package/dist/infra/cipher/llm/retry/retry-with-backoff.js +247 -0
- package/dist/infra/cipher/llm/thought-parser.d.ts +145 -0
- package/dist/infra/cipher/llm/thought-parser.js +190 -0
- package/dist/infra/cipher/llm/tokenizers/claude-tokenizer.d.ts +47 -0
- package/dist/infra/cipher/llm/tokenizers/claude-tokenizer.js +55 -0
- package/dist/infra/cipher/llm/tokenizers/default-tokenizer.d.ts +31 -0
- package/dist/infra/cipher/llm/tokenizers/default-tokenizer.js +38 -0
- package/dist/infra/cipher/llm/tokenizers/gemini-tokenizer.d.ts +37 -0
- package/dist/infra/cipher/llm/tokenizers/gemini-tokenizer.js +45 -0
- package/dist/infra/cipher/llm/tokenizers/openrouter-tokenizer.d.ts +29 -0
- package/dist/infra/cipher/llm/tokenizers/openrouter-tokenizer.js +37 -0
- package/dist/infra/cipher/llm/tool-output-processor.d.ts +117 -0
- package/dist/infra/cipher/llm/tool-output-processor.js +153 -0
- package/dist/infra/cipher/logger/console-logger.d.ts +42 -0
- package/dist/infra/cipher/logger/console-logger.js +63 -0
- package/dist/infra/cipher/logger/event-based-logger.d.ts +54 -0
- package/dist/infra/cipher/logger/event-based-logger.js +92 -0
- package/dist/infra/cipher/memory/index.d.ts +6 -0
- package/dist/infra/cipher/memory/index.js +7 -0
- package/dist/infra/cipher/memory/memory-manager.d.ts +136 -0
- package/dist/infra/cipher/memory/memory-manager.js +523 -0
- package/dist/infra/cipher/parsers/coding-agent-log-parser.d.ts +24 -0
- package/dist/infra/cipher/parsers/coding-agent-log-parser.js +51 -0
- package/dist/infra/cipher/process/command-validator.d.ts +59 -0
- package/dist/infra/cipher/process/command-validator.js +266 -0
- package/dist/infra/cipher/process/index.d.ts +8 -0
- package/dist/infra/cipher/process/index.js +8 -0
- package/dist/infra/cipher/process/process-service.d.ts +95 -0
- package/dist/infra/cipher/process/process-service.js +439 -0
- package/dist/infra/cipher/session/chat-session.d.ts +80 -0
- package/dist/infra/cipher/session/chat-session.js +165 -0
- package/dist/infra/cipher/session/index.d.ts +6 -0
- package/dist/infra/cipher/session/index.js +5 -0
- package/dist/infra/cipher/session/session-event-forwarder.d.ts +37 -0
- package/dist/infra/cipher/session/session-event-forwarder.js +83 -0
- package/dist/infra/cipher/session/session-manager.d.ts +109 -0
- package/dist/infra/cipher/session/session-manager.js +172 -0
- package/dist/infra/cipher/storage/blob-history-storage.d.ts +76 -0
- package/dist/infra/cipher/storage/blob-history-storage.js +178 -0
- package/dist/infra/cipher/system-prompt/simple-prompt-factory.d.ts +105 -0
- package/dist/infra/cipher/system-prompt/simple-prompt-factory.js +290 -0
- package/dist/infra/cipher/tools/core-tool-scheduler.d.ts +99 -0
- package/dist/infra/cipher/tools/core-tool-scheduler.js +161 -0
- package/dist/infra/cipher/tools/default-policy-rules.d.ts +26 -0
- package/dist/infra/cipher/tools/default-policy-rules.js +125 -0
- package/dist/infra/cipher/tools/implementations/bash-exec-tool.d.ts +12 -0
- package/dist/infra/cipher/tools/implementations/bash-exec-tool.js +93 -0
- package/dist/infra/cipher/tools/implementations/bash-output-tool.d.ts +12 -0
- package/dist/infra/cipher/tools/implementations/bash-output-tool.js +47 -0
- package/dist/infra/cipher/tools/implementations/create-knowledge-topic-tool.d.ts +11 -0
- package/dist/infra/cipher/tools/implementations/create-knowledge-topic-tool.js +142 -0
- package/dist/infra/cipher/tools/implementations/delete-memory-tool.d.ts +12 -0
- package/dist/infra/cipher/tools/implementations/delete-memory-tool.js +37 -0
- package/dist/infra/cipher/tools/implementations/detect-domains-tool.d.ts +7 -0
- package/dist/infra/cipher/tools/implementations/detect-domains-tool.js +73 -0
- package/dist/infra/cipher/tools/implementations/edit-file-tool.d.ts +13 -0
- package/dist/infra/cipher/tools/implementations/edit-file-tool.js +50 -0
- package/dist/infra/cipher/tools/implementations/edit-memory-tool.d.ts +13 -0
- package/dist/infra/cipher/tools/implementations/edit-memory-tool.js +53 -0
- package/dist/infra/cipher/tools/implementations/find-knowledge-topics-tool.d.ts +7 -0
- package/dist/infra/cipher/tools/implementations/find-knowledge-topics-tool.js +421 -0
- package/dist/infra/cipher/tools/implementations/glob-files-tool.d.ts +18 -0
- package/dist/infra/cipher/tools/implementations/glob-files-tool.js +70 -0
- package/dist/infra/cipher/tools/implementations/grep-content-tool.d.ts +12 -0
- package/dist/infra/cipher/tools/implementations/grep-content-tool.js +77 -0
- package/dist/infra/cipher/tools/implementations/kill-process-tool.d.ts +12 -0
- package/dist/infra/cipher/tools/implementations/kill-process-tool.js +55 -0
- package/dist/infra/cipher/tools/implementations/list-memories-tool.d.ts +12 -0
- package/dist/infra/cipher/tools/implementations/list-memories-tool.js +63 -0
- package/dist/infra/cipher/tools/implementations/read-file-tool.d.ts +12 -0
- package/dist/infra/cipher/tools/implementations/read-file-tool.js +54 -0
- package/dist/infra/cipher/tools/implementations/read-memory-tool.d.ts +12 -0
- package/dist/infra/cipher/tools/implementations/read-memory-tool.js +39 -0
- package/dist/infra/cipher/tools/implementations/search-history-tool.d.ts +10 -0
- package/dist/infra/cipher/tools/implementations/search-history-tool.js +36 -0
- package/dist/infra/cipher/tools/implementations/write-file-tool.d.ts +12 -0
- package/dist/infra/cipher/tools/implementations/write-file-tool.js +52 -0
- package/dist/infra/cipher/tools/implementations/write-memory-tool.d.ts +13 -0
- package/dist/infra/cipher/tools/implementations/write-memory-tool.js +52 -0
- package/dist/infra/cipher/tools/implementations/write-todos-tool.d.ts +10 -0
- package/dist/infra/cipher/tools/implementations/write-todos-tool.js +165 -0
- package/dist/infra/cipher/tools/index.d.ts +18 -0
- package/dist/infra/cipher/tools/index.js +19 -0
- package/dist/infra/cipher/tools/policy-engine.d.ts +80 -0
- package/dist/infra/cipher/tools/policy-engine.js +110 -0
- package/dist/infra/cipher/tools/tool-invocation-queue.d.ts +191 -0
- package/dist/infra/cipher/tools/tool-invocation-queue.js +254 -0
- package/dist/infra/cipher/tools/tool-invocation.d.ts +216 -0
- package/dist/infra/cipher/tools/tool-invocation.js +294 -0
- package/dist/infra/cipher/tools/tool-manager.d.ts +135 -0
- package/dist/infra/cipher/tools/tool-manager.js +209 -0
- package/dist/infra/cipher/tools/tool-markers.d.ts +48 -0
- package/dist/infra/cipher/tools/tool-markers.js +49 -0
- package/dist/infra/cipher/tools/tool-provider.d.ts +77 -0
- package/dist/infra/cipher/tools/tool-provider.js +196 -0
- package/dist/infra/cipher/tools/tool-registry.d.ts +52 -0
- package/dist/infra/cipher/tools/tool-registry.js +144 -0
- package/dist/infra/cipher/tools/utils/schema-converter.d.ts +10 -0
- package/dist/infra/cipher/tools/utils/schema-converter.js +29 -0
- package/dist/infra/cipher/validation/workspace-validator.d.ts +19 -0
- package/dist/infra/cipher/validation/workspace-validator.js +37 -0
- package/dist/infra/cipher/watcher/coding-agent-log-watcher.d.ts +14 -0
- package/dist/infra/cipher/watcher/coding-agent-log-watcher.js +55 -0
- package/dist/infra/cogit/context-tree-to-push-context-mapper.d.ts +21 -0
- package/dist/infra/cogit/context-tree-to-push-context-mapper.js +32 -0
- package/dist/infra/cogit/http-cogit-pull-service.d.ts +15 -0
- package/dist/infra/cogit/http-cogit-pull-service.js +30 -0
- package/dist/infra/cogit/http-cogit-push-service.d.ts +17 -0
- package/dist/infra/cogit/http-cogit-push-service.js +104 -0
- package/dist/infra/config/file-config-store.js +9 -3
- package/dist/infra/context-tree/file-context-file-reader.d.ts +14 -0
- package/dist/infra/context-tree/file-context-file-reader.js +46 -0
- package/dist/infra/context-tree/file-context-tree-service.d.ts +14 -0
- package/dist/infra/context-tree/file-context-tree-service.js +46 -0
- package/dist/infra/context-tree/file-context-tree-snapshot-service.d.ts +34 -0
- package/dist/infra/context-tree/file-context-tree-snapshot-service.js +117 -0
- package/dist/infra/context-tree/file-context-tree-writer-service.d.ts +22 -0
- package/dist/infra/context-tree/file-context-tree-writer-service.js +61 -0
- package/dist/infra/memory/http-memory-retrieval-service.js +2 -1
- package/dist/infra/memory/http-memory-storage-service.js +4 -3
- package/dist/infra/parsers/clean/clean-claude-service.d.ts +111 -0
- package/dist/infra/parsers/clean/clean-claude-service.js +271 -0
- package/dist/infra/parsers/clean/clean-codex-service.d.ts +231 -0
- package/dist/infra/parsers/clean/clean-codex-service.js +534 -0
- package/dist/infra/parsers/clean/clean-copilot-service.d.ts +255 -0
- package/dist/infra/parsers/clean/clean-copilot-service.js +729 -0
- package/dist/infra/parsers/clean/clean-cursor-service.d.ts +161 -0
- package/dist/infra/parsers/clean/clean-cursor-service.js +432 -0
- package/dist/infra/parsers/clean/clean-parser-service-factory.d.ts +54 -0
- package/dist/infra/parsers/clean/clean-parser-service-factory.js +80 -0
- package/dist/infra/parsers/clean/shared.d.ts +84 -0
- package/dist/infra/parsers/clean/shared.js +273 -0
- package/dist/infra/parsers/raw/raw-claude-service.d.ts +195 -0
- package/dist/infra/parsers/raw/raw-claude-service.js +548 -0
- package/dist/infra/parsers/raw/raw-codex-service.d.ts +313 -0
- package/dist/infra/parsers/raw/raw-codex-service.js +782 -0
- package/dist/infra/parsers/raw/raw-copilot-service.d.ts +196 -0
- package/dist/infra/parsers/raw/raw-copilot-service.js +558 -0
- package/dist/infra/parsers/raw/raw-cursor-service.d.ts +316 -0
- package/dist/infra/parsers/raw/raw-cursor-service.js +818 -0
- package/dist/infra/parsers/raw/raw-parser-service-factory.d.ts +54 -0
- package/dist/infra/parsers/raw/raw-parser-service-factory.js +81 -0
- package/dist/infra/space/http-space-service.js +2 -1
- package/dist/infra/team/http-team-service.js +2 -1
- package/dist/infra/user/http-user-service.js +2 -1
- package/dist/infra/watcher/file-watcher-service.d.ts +10 -0
- package/dist/infra/watcher/file-watcher-service.js +81 -0
- package/dist/infra/workspace/workspace-detector-service.d.ts +60 -0
- package/dist/infra/workspace/workspace-detector-service.js +165 -0
- package/dist/resources/prompts/curate-context-tree-curation.yml +48 -0
- package/dist/resources/prompts/modes/autonomous.yml +9 -0
- package/dist/resources/prompts/query-context-tree-retrieval.yml +49 -0
- package/dist/resources/prompts/reflection.yml +27 -0
- package/dist/resources/prompts/system-prompt.yml +82 -0
- package/dist/resources/prompts/tool-outputs.yml +30 -0
- package/dist/templates/README.md +6 -7
- package/dist/templates/sections/command-reference.md +40 -111
- package/dist/templates/sections/workflow.md +3 -30
- package/dist/utils/emoji-helpers.d.ts +38 -0
- package/dist/utils/emoji-helpers.js +42 -0
- package/dist/utils/error-handler.d.ts +51 -0
- package/dist/utils/error-handler.js +169 -0
- package/dist/utils/error-helpers.d.ts +30 -0
- package/dist/utils/error-helpers.js +47 -0
- package/dist/utils/file-helpers.d.ts +15 -0
- package/dist/utils/file-helpers.js +44 -0
- package/dist/utils/oclif-error-helpers.d.ts +40 -0
- package/dist/utils/oclif-error-helpers.js +46 -0
- package/dist/utils/tool-display-formatter.d.ts +53 -0
- package/dist/utils/tool-display-formatter.js +257 -0
- package/oclif.manifest.json +381 -141
- package/package.json +27 -6
- package/dist/commands/add.d.ts +0 -49
- package/dist/commands/add.js +0 -192
- package/dist/commands/complete.d.ts +0 -108
- package/dist/commands/complete.js +0 -340
- package/dist/commands/retrieve.d.ts +0 -26
- package/dist/commands/retrieve.js +0 -101
- package/dist/core/domain/entities/curator-output.d.ts +0 -14
- package/dist/core/domain/entities/curator-output.js +0 -23
- package/dist/core/domain/entities/delta-batch.d.ts +0 -30
- package/dist/core/domain/entities/delta-batch.js +0 -52
- package/dist/core/domain/entities/delta-operation.d.ts +0 -31
- package/dist/core/domain/entities/delta-operation.js +0 -50
- package/dist/core/domain/entities/executor-output.d.ts +0 -27
- package/dist/core/domain/entities/executor-output.js +0 -33
- package/dist/core/domain/entities/reflector-output.d.ts +0 -38
- package/dist/core/domain/entities/reflector-output.js +0 -44
- package/dist/core/interfaces/i-ace-prompt-builder.d.ts +0 -48
- package/dist/core/interfaces/i-bullet-content-store.d.ts +0 -36
- package/dist/core/interfaces/i-delta-store.d.ts +0 -15
- package/dist/core/interfaces/i-executor-output-store.d.ts +0 -14
- package/dist/core/interfaces/i-playbook-service.d.ts +0 -69
- package/dist/core/interfaces/i-playbook-store.d.ts +0 -38
- package/dist/core/interfaces/i-reflection-store.d.ts +0 -21
- package/dist/infra/ace/ace-file-utils.d.ts +0 -46
- package/dist/infra/ace/ace-file-utils.js +0 -83
- package/dist/infra/ace/ace-prompt-templates.d.ts +0 -13
- package/dist/infra/ace/ace-prompt-templates.js +0 -177
- package/dist/infra/ace/file-bullet-content-store.d.ts +0 -27
- package/dist/infra/ace/file-bullet-content-store.js +0 -89
- package/dist/infra/ace/file-delta-store.d.ts +0 -9
- package/dist/infra/ace/file-delta-store.js +0 -26
- package/dist/infra/ace/file-executor-output-store.d.ts +0 -9
- package/dist/infra/ace/file-executor-output-store.js +0 -26
- package/dist/infra/ace/file-playbook-store.d.ts +0 -29
- package/dist/infra/ace/file-playbook-store.js +0 -107
- package/dist/infra/ace/file-reflection-store.d.ts +0 -10
- package/dist/infra/ace/file-reflection-store.js +0 -55
- package/dist/infra/playbook/file-playbook-service.d.ts +0 -42
- package/dist/infra/playbook/file-playbook-service.js +0 -132
- /package/dist/core/{interfaces/i-ace-prompt-builder.js → domain/cipher/blob/types.js} +0 -0
- /package/dist/core/{interfaces/i-bullet-content-store.js → domain/cipher/file-system/types.js} +0 -0
- /package/dist/core/{interfaces/i-delta-store.js → domain/cipher/process/types.js} +0 -0
- /package/dist/core/{interfaces/i-executor-output-store.js → domain/cipher/session/types.js} +0 -0
- /package/dist/core/{interfaces/i-playbook-service.js → domain/cipher/storage/history-types.js} +0 -0
- /package/dist/core/{interfaces/i-playbook-store.js → domain/cipher/system-prompt/types.js} +0 -0
- /package/dist/core/{interfaces/i-reflection-store.js → domain/cipher/tools/types.js} +0 -0
|
@@ -0,0 +1,641 @@
|
|
|
1
|
+
import { glob } from 'glob';
|
|
2
|
+
import { spawn } from 'node:child_process';
|
|
3
|
+
import fs from 'node:fs/promises';
|
|
4
|
+
import { EOL } from 'node:os';
|
|
5
|
+
import path from 'node:path';
|
|
6
|
+
import { DirectoryNotFoundError, EditOperationError, FileNotFoundError, FileTooLargeError, GlobOperationError, InvalidExtensionError, InvalidPathError, InvalidPatternError, PathBlockedError, PathNotAllowedError, PathTraversalError, ReadOperationError, SearchOperationError, ServiceNotInitializedError, StringNotFoundError, StringNotUniqueError, WriteOperationError, } from '../../../core/domain/cipher/errors/file-system-error.js';
|
|
7
|
+
import { getErrorMessage } from '../../../utils/error-helpers.js';
|
|
8
|
+
import { createGitignoreFilter } from './gitignore-filter.js';
|
|
9
|
+
import { collectFileMetadata, escapeIfExactMatch, extractPaths, sortFilesByRecency } from './glob-utils.js';
|
|
10
|
+
import { PathValidator } from './path-validator.js';
|
|
11
|
+
/**
|
|
12
|
+
* File system service implementation.
|
|
13
|
+
* Provides secure, validated file system operations with comprehensive
|
|
14
|
+
* path validation, size limits, and allow/block list enforcement.
|
|
15
|
+
*/
|
|
16
|
+
export class FileSystemService {
|
|
17
|
+
config;
|
|
18
|
+
initialized = false;
|
|
19
|
+
pathValidator;
|
|
20
|
+
/**
|
|
21
|
+
* Creates a new file system service
|
|
22
|
+
* @param config - File system configuration (optional, uses defaults)
|
|
23
|
+
*/
|
|
24
|
+
constructor(config = {}) {
|
|
25
|
+
// Merge with defaults
|
|
26
|
+
this.config = {
|
|
27
|
+
allowedPaths: config.allowedPaths ?? ['.'],
|
|
28
|
+
blockedExtensions: config.blockedExtensions ?? ['.exe', '.dll', '.so', '.dylib'],
|
|
29
|
+
blockedPaths: config.blockedPaths ?? ['.git', 'node_modules/.bin', '.env', '.byterover'],
|
|
30
|
+
maxFileSize: config.maxFileSize ?? 10 * 1024 * 1024, // 10MB
|
|
31
|
+
workingDirectory: config.workingDirectory ?? process.cwd(),
|
|
32
|
+
};
|
|
33
|
+
this.pathValidator = new PathValidator(this.config);
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Edit a file by replacing strings.
|
|
37
|
+
*/
|
|
38
|
+
async editFile(filePath, operation, options = {}) {
|
|
39
|
+
this.ensureInitialized();
|
|
40
|
+
// Validate path
|
|
41
|
+
const validation = this.pathValidator.validate(filePath, 'read');
|
|
42
|
+
if (!validation.valid) {
|
|
43
|
+
this.throwValidationError(filePath, validation.error);
|
|
44
|
+
}
|
|
45
|
+
const { normalizedPath } = validation;
|
|
46
|
+
try {
|
|
47
|
+
// Read current content
|
|
48
|
+
const fileContent = await this.readFile(filePath, options);
|
|
49
|
+
let { content } = fileContent;
|
|
50
|
+
// Escape regex special characters for literal string matching
|
|
51
|
+
const escapedOldString = operation.oldString.replaceAll(/[$()*+.?[\u005C\]^{|}]/g, String.raw `\$&`);
|
|
52
|
+
// Count occurrences
|
|
53
|
+
const occurrences = (content.match(new RegExp(escapedOldString, 'g')) || []).length;
|
|
54
|
+
// Check if string exists
|
|
55
|
+
if (occurrences === 0) {
|
|
56
|
+
throw new StringNotFoundError(normalizedPath, operation.oldString);
|
|
57
|
+
}
|
|
58
|
+
// Check if string is unique (if replaceAll is false)
|
|
59
|
+
if (!operation.replaceAll && occurrences > 1) {
|
|
60
|
+
throw new StringNotUniqueError(normalizedPath, operation.oldString, occurrences);
|
|
61
|
+
}
|
|
62
|
+
// Perform replacement
|
|
63
|
+
content = operation.replaceAll
|
|
64
|
+
? content.replaceAll(operation.oldString, operation.newString)
|
|
65
|
+
: content.replace(operation.oldString, operation.newString);
|
|
66
|
+
// Write back
|
|
67
|
+
const writeResult = await this.writeFile(filePath, content, options);
|
|
68
|
+
return {
|
|
69
|
+
bytesWritten: writeResult.bytesWritten,
|
|
70
|
+
path: normalizedPath,
|
|
71
|
+
replacements: operation.replaceAll ? occurrences : 1,
|
|
72
|
+
success: true,
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
catch (error) {
|
|
76
|
+
// Re-throw known errors
|
|
77
|
+
if (error instanceof FileNotFoundError ||
|
|
78
|
+
error instanceof StringNotFoundError ||
|
|
79
|
+
error instanceof StringNotUniqueError ||
|
|
80
|
+
error instanceof PathNotAllowedError ||
|
|
81
|
+
error instanceof PathTraversalError ||
|
|
82
|
+
error instanceof PathBlockedError) {
|
|
83
|
+
throw error;
|
|
84
|
+
}
|
|
85
|
+
// Wrap other errors
|
|
86
|
+
throw new EditOperationError(normalizedPath, getErrorMessage(error));
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Find files matching a glob pattern.
|
|
91
|
+
*
|
|
92
|
+
* Features:
|
|
93
|
+
* - Case sensitivity control via `caseSensitive` option
|
|
94
|
+
* - Gitignore filtering via `respectGitignore` option
|
|
95
|
+
* - Smart sorting: recent files (within 24h) first, then alphabetical
|
|
96
|
+
* - Special character handling for paths with glob syntax
|
|
97
|
+
*/
|
|
98
|
+
async globFiles(pattern, options = {}) {
|
|
99
|
+
this.ensureInitialized();
|
|
100
|
+
const cwd = options.cwd ?? this.config.workingDirectory;
|
|
101
|
+
const maxResults = options.maxResults ?? 1000;
|
|
102
|
+
const includeMetadata = options.includeMetadata ?? true;
|
|
103
|
+
const caseSensitive = options.caseSensitive ?? true;
|
|
104
|
+
const respectGitignore = options.respectGitignore ?? true;
|
|
105
|
+
try {
|
|
106
|
+
// Handle special characters - escape pattern if it matches an existing file
|
|
107
|
+
const escapedPattern = await escapeIfExactMatch(pattern, cwd);
|
|
108
|
+
// Execute glob with case sensitivity option
|
|
109
|
+
const files = await glob(escapedPattern, {
|
|
110
|
+
absolute: true,
|
|
111
|
+
cwd,
|
|
112
|
+
follow: false, // Don't follow symlinks
|
|
113
|
+
nocase: !caseSensitive, // Case insensitive if caseSensitive is false
|
|
114
|
+
nodir: true, // Only files
|
|
115
|
+
});
|
|
116
|
+
// Initialize gitignore filter if requested
|
|
117
|
+
let gitignoreFilter = null;
|
|
118
|
+
if (respectGitignore) {
|
|
119
|
+
gitignoreFilter = await createGitignoreFilter(cwd);
|
|
120
|
+
}
|
|
121
|
+
// Validate paths and apply gitignore filtering
|
|
122
|
+
const validPaths = [];
|
|
123
|
+
let ignoredCount = 0;
|
|
124
|
+
for (const file of files) {
|
|
125
|
+
// Validate path
|
|
126
|
+
const validation = this.pathValidator.validate(file, 'read');
|
|
127
|
+
if (!validation.valid || !validation.normalizedPath) {
|
|
128
|
+
// Skip invalid paths
|
|
129
|
+
continue;
|
|
130
|
+
}
|
|
131
|
+
// Apply gitignore filter if enabled
|
|
132
|
+
if (gitignoreFilter) {
|
|
133
|
+
const relativePath = path.relative(cwd, validation.normalizedPath);
|
|
134
|
+
if (gitignoreFilter.isIgnored(relativePath)) {
|
|
135
|
+
ignoredCount++;
|
|
136
|
+
continue;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
validPaths.push(validation.normalizedPath);
|
|
140
|
+
}
|
|
141
|
+
const totalFound = validPaths.length;
|
|
142
|
+
// Collect metadata for all valid paths
|
|
143
|
+
const filesWithMetadata = await collectFileMetadata(validPaths, cwd);
|
|
144
|
+
// Sort files: recent files first (within 24h), then alphabetical
|
|
145
|
+
const sortedFiles = sortFilesByRecency(filesWithMetadata);
|
|
146
|
+
// Apply maxResults limit after sorting
|
|
147
|
+
const truncated = sortedFiles.length > maxResults;
|
|
148
|
+
const limitedFiles = sortedFiles.slice(0, maxResults);
|
|
149
|
+
// Convert to FileMetadata format
|
|
150
|
+
const resultFiles = includeMetadata
|
|
151
|
+
? limitedFiles.map((f) => ({
|
|
152
|
+
isDirectory: false,
|
|
153
|
+
modified: f.modifiedTime,
|
|
154
|
+
path: f.path,
|
|
155
|
+
size: f.size,
|
|
156
|
+
}))
|
|
157
|
+
: extractPaths(limitedFiles).map((p) => ({
|
|
158
|
+
isDirectory: false,
|
|
159
|
+
modified: new Date(),
|
|
160
|
+
path: p,
|
|
161
|
+
size: 0,
|
|
162
|
+
}));
|
|
163
|
+
// Build result message
|
|
164
|
+
const message = this.buildGlobMessage(resultFiles.length, totalFound, ignoredCount, truncated);
|
|
165
|
+
return {
|
|
166
|
+
files: resultFiles,
|
|
167
|
+
ignoredCount,
|
|
168
|
+
message,
|
|
169
|
+
totalFound,
|
|
170
|
+
truncated,
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
catch (error) {
|
|
174
|
+
// Check for pattern errors
|
|
175
|
+
if (getErrorMessage(error).includes('Invalid glob pattern')) {
|
|
176
|
+
throw new InvalidPatternError(pattern, getErrorMessage(error));
|
|
177
|
+
}
|
|
178
|
+
throw new GlobOperationError(pattern, getErrorMessage(error));
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Initialize the file system service.
|
|
183
|
+
*/
|
|
184
|
+
async initialize() {
|
|
185
|
+
if (this.initialized) {
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
// Verify working directory exists
|
|
189
|
+
try {
|
|
190
|
+
const stats = await fs.stat(this.config.workingDirectory);
|
|
191
|
+
if (!stats.isDirectory()) {
|
|
192
|
+
throw new DirectoryNotFoundError(this.config.workingDirectory);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
catch (error) {
|
|
196
|
+
if (error.code === 'ENOENT') {
|
|
197
|
+
throw new DirectoryNotFoundError(this.config.workingDirectory);
|
|
198
|
+
}
|
|
199
|
+
throw error;
|
|
200
|
+
}
|
|
201
|
+
this.initialized = true;
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Read the contents of a file.
|
|
205
|
+
*/
|
|
206
|
+
async readFile(filePath, options = {}) {
|
|
207
|
+
this.ensureInitialized();
|
|
208
|
+
// Validate path
|
|
209
|
+
const validation = this.pathValidator.validate(filePath, 'read');
|
|
210
|
+
if (!validation.valid) {
|
|
211
|
+
this.throwValidationError(filePath, validation.error);
|
|
212
|
+
}
|
|
213
|
+
const { normalizedPath } = validation;
|
|
214
|
+
try {
|
|
215
|
+
// Check if file exists
|
|
216
|
+
let stats;
|
|
217
|
+
try {
|
|
218
|
+
stats = await fs.stat(normalizedPath);
|
|
219
|
+
}
|
|
220
|
+
catch (error) {
|
|
221
|
+
if (error.code === 'ENOENT') {
|
|
222
|
+
throw new FileNotFoundError(normalizedPath);
|
|
223
|
+
}
|
|
224
|
+
throw error;
|
|
225
|
+
}
|
|
226
|
+
// Check file size
|
|
227
|
+
if (stats.size > this.config.maxFileSize) {
|
|
228
|
+
throw new FileTooLargeError(normalizedPath, stats.size, this.config.maxFileSize);
|
|
229
|
+
}
|
|
230
|
+
// Read file
|
|
231
|
+
const encoding = (options.encoding ?? 'utf8');
|
|
232
|
+
const content = await fs.readFile(normalizedPath, encoding);
|
|
233
|
+
// Handle pagination
|
|
234
|
+
const lines = content.split('\n');
|
|
235
|
+
let selectedLines;
|
|
236
|
+
let truncated = false;
|
|
237
|
+
// Apply offset (1-based, like text editors)
|
|
238
|
+
const { limit, offset: offset1 } = options;
|
|
239
|
+
if (offset1 !== undefined || limit !== undefined) {
|
|
240
|
+
const start = offset1 !== undefined && offset1 > 0 ? Math.max(0, offset1 - 1) : 0;
|
|
241
|
+
const end = limit === undefined ? lines.length : start + limit;
|
|
242
|
+
selectedLines = lines.slice(start, end);
|
|
243
|
+
truncated = end < lines.length;
|
|
244
|
+
}
|
|
245
|
+
else {
|
|
246
|
+
selectedLines = lines;
|
|
247
|
+
}
|
|
248
|
+
const selectedContent = selectedLines.join('\n');
|
|
249
|
+
return {
|
|
250
|
+
content: selectedContent,
|
|
251
|
+
encoding,
|
|
252
|
+
lines: selectedLines.length,
|
|
253
|
+
size: stats.size,
|
|
254
|
+
truncated,
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
catch (error) {
|
|
258
|
+
// Re-throw known errors
|
|
259
|
+
if (error instanceof FileNotFoundError ||
|
|
260
|
+
error instanceof FileTooLargeError ||
|
|
261
|
+
error instanceof PathNotAllowedError ||
|
|
262
|
+
error instanceof PathTraversalError ||
|
|
263
|
+
error instanceof PathBlockedError) {
|
|
264
|
+
throw error;
|
|
265
|
+
}
|
|
266
|
+
// Wrap other errors
|
|
267
|
+
throw new ReadOperationError(normalizedPath, getErrorMessage(error));
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
/**
|
|
271
|
+
* Search file contents for a pattern.
|
|
272
|
+
* Uses native grep commands (ripgrep, system grep) when available for better performance,
|
|
273
|
+
* falling back to JavaScript implementation when needed.
|
|
274
|
+
*/
|
|
275
|
+
async searchContent(pattern, options = {}) {
|
|
276
|
+
this.ensureInitialized();
|
|
277
|
+
const cwd = options.cwd ?? this.config.workingDirectory;
|
|
278
|
+
const maxResults = options.maxResults ?? 100;
|
|
279
|
+
const contextLines = options.contextLines ?? 0;
|
|
280
|
+
// If context lines requested, use JS fallback directly (native grep context parsing is complex)
|
|
281
|
+
if (contextLines > 0) {
|
|
282
|
+
return this.searchContentJS(pattern, options);
|
|
283
|
+
}
|
|
284
|
+
try {
|
|
285
|
+
// Try native strategies in order: ripgrep → system grep → JS fallback
|
|
286
|
+
let matches = null;
|
|
287
|
+
matches = await this.executeRipgrep(pattern, cwd, options);
|
|
288
|
+
if (matches === null) {
|
|
289
|
+
matches = await this.executeSystemGrep(pattern, cwd, options);
|
|
290
|
+
}
|
|
291
|
+
if (matches === null) {
|
|
292
|
+
return this.searchContentJS(pattern, options);
|
|
293
|
+
}
|
|
294
|
+
// Apply maxResults limit
|
|
295
|
+
const truncated = matches.length > maxResults;
|
|
296
|
+
return {
|
|
297
|
+
filesSearched: new Set(matches.map((m) => m.file)).size,
|
|
298
|
+
matches: matches.slice(0, maxResults),
|
|
299
|
+
totalMatches: matches.length,
|
|
300
|
+
truncated,
|
|
301
|
+
};
|
|
302
|
+
}
|
|
303
|
+
catch (error) {
|
|
304
|
+
// Re-throw known errors
|
|
305
|
+
if (error instanceof InvalidPatternError || error instanceof GlobOperationError) {
|
|
306
|
+
throw error;
|
|
307
|
+
}
|
|
308
|
+
throw new SearchOperationError(pattern, getErrorMessage(error));
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
/**
|
|
312
|
+
* Write content to a file.
|
|
313
|
+
*/
|
|
314
|
+
async writeFile(filePath, content, options = {}) {
|
|
315
|
+
this.ensureInitialized();
|
|
316
|
+
// Validate path
|
|
317
|
+
const validation = this.pathValidator.validate(filePath, 'write');
|
|
318
|
+
if (!validation.valid) {
|
|
319
|
+
this.throwValidationError(filePath, validation.error);
|
|
320
|
+
}
|
|
321
|
+
const { normalizedPath } = validation;
|
|
322
|
+
try {
|
|
323
|
+
// Create parent directories if requested
|
|
324
|
+
if (options.createDirs) {
|
|
325
|
+
const dirname = path.dirname(normalizedPath);
|
|
326
|
+
await fs.mkdir(dirname, { recursive: true });
|
|
327
|
+
}
|
|
328
|
+
// Write file
|
|
329
|
+
const encoding = (options.encoding ?? 'utf8');
|
|
330
|
+
await fs.writeFile(normalizedPath, content, encoding);
|
|
331
|
+
// Get file size
|
|
332
|
+
const stats = await fs.stat(normalizedPath);
|
|
333
|
+
return {
|
|
334
|
+
bytesWritten: stats.size,
|
|
335
|
+
path: normalizedPath,
|
|
336
|
+
success: true,
|
|
337
|
+
};
|
|
338
|
+
}
|
|
339
|
+
catch (error) {
|
|
340
|
+
// Re-throw known errors
|
|
341
|
+
if (error instanceof InvalidExtensionError ||
|
|
342
|
+
error instanceof PathNotAllowedError ||
|
|
343
|
+
error instanceof PathTraversalError ||
|
|
344
|
+
error instanceof PathBlockedError) {
|
|
345
|
+
throw error;
|
|
346
|
+
}
|
|
347
|
+
// Wrap other errors
|
|
348
|
+
throw new WriteOperationError(normalizedPath, getErrorMessage(error));
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
/**
|
|
352
|
+
* Builds a human-readable message for glob results.
|
|
353
|
+
*/
|
|
354
|
+
buildGlobMessage(returned, total, ignored, truncated) {
|
|
355
|
+
const parts = [];
|
|
356
|
+
if (truncated) {
|
|
357
|
+
parts.push(`Found ${total} files, showing first ${returned}`);
|
|
358
|
+
}
|
|
359
|
+
else {
|
|
360
|
+
parts.push(`Found ${returned} file${returned === 1 ? '' : 's'}`);
|
|
361
|
+
}
|
|
362
|
+
if (ignored > 0) {
|
|
363
|
+
parts.push(`(${ignored} ignored by .gitignore)`);
|
|
364
|
+
}
|
|
365
|
+
return parts.join(' ');
|
|
366
|
+
}
|
|
367
|
+
/**
|
|
368
|
+
* Collects context lines before and after a match.
|
|
369
|
+
*/
|
|
370
|
+
collectContextLines(lines, lineIndex, contextLines) {
|
|
371
|
+
const before = [];
|
|
372
|
+
const after = [];
|
|
373
|
+
if (contextLines > 0) {
|
|
374
|
+
// Lines before
|
|
375
|
+
for (let j = Math.max(0, lineIndex - contextLines); j < lineIndex; j++) {
|
|
376
|
+
before.push(lines[j]);
|
|
377
|
+
}
|
|
378
|
+
// Lines after
|
|
379
|
+
for (let j = lineIndex + 1; j < Math.min(lines.length, lineIndex + 1 + contextLines); j++) {
|
|
380
|
+
after.push(lines[j]);
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
return { after, before };
|
|
384
|
+
}
|
|
385
|
+
/**
|
|
386
|
+
* Creates a regex from a pattern string.
|
|
387
|
+
*/
|
|
388
|
+
createSearchRegex(pattern, caseInsensitive) {
|
|
389
|
+
const flags = caseInsensitive ? 'i' : '';
|
|
390
|
+
try {
|
|
391
|
+
return new RegExp(pattern, flags);
|
|
392
|
+
}
|
|
393
|
+
catch (error) {
|
|
394
|
+
throw new InvalidPatternError(pattern, getErrorMessage(error));
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
/**
|
|
398
|
+
* Ensures the service is initialized.
|
|
399
|
+
* @throws ServiceNotInitializedError if not initialized
|
|
400
|
+
*/
|
|
401
|
+
ensureInitialized() {
|
|
402
|
+
if (!this.initialized) {
|
|
403
|
+
throw new ServiceNotInitializedError();
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
/**
|
|
407
|
+
* Executes ripgrep (rg) for content search.
|
|
408
|
+
* Returns null if rg is not available or fails.
|
|
409
|
+
*/
|
|
410
|
+
async executeRipgrep(pattern, cwd, options) {
|
|
411
|
+
if (!(await this.isCommandAvailable('rg')))
|
|
412
|
+
return null;
|
|
413
|
+
const args = ['-n', '--no-heading', '--with-filename'];
|
|
414
|
+
if (options.caseInsensitive)
|
|
415
|
+
args.push('-i');
|
|
416
|
+
// Add exclusions for blocked paths
|
|
417
|
+
for (const blocked of this.config.blockedPaths) {
|
|
418
|
+
args.push('--glob', `!${blocked}`);
|
|
419
|
+
}
|
|
420
|
+
if (options.globPattern)
|
|
421
|
+
args.push('--glob', options.globPattern);
|
|
422
|
+
args.push(pattern, '.'); // Add search path to prevent reading from stdin
|
|
423
|
+
try {
|
|
424
|
+
const output = await this.spawnCommand('rg', args, cwd, options.abortSignal);
|
|
425
|
+
return this.parseGrepOutput(output, cwd);
|
|
426
|
+
}
|
|
427
|
+
catch {
|
|
428
|
+
return null;
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
/**
|
|
432
|
+
* Executes system grep for content search.
|
|
433
|
+
* Returns null if grep is not available or fails.
|
|
434
|
+
*/
|
|
435
|
+
async executeSystemGrep(pattern, cwd, options) {
|
|
436
|
+
if (!(await this.isCommandAvailable('grep')))
|
|
437
|
+
return null;
|
|
438
|
+
const args = ['-r', '-n', '-H', '-E', '-I'];
|
|
439
|
+
if (options.caseInsensitive)
|
|
440
|
+
args.push('-i');
|
|
441
|
+
// Add exclusions for blocked paths
|
|
442
|
+
for (const blocked of this.config.blockedPaths) {
|
|
443
|
+
args.push(`--exclude-dir=${blocked}`);
|
|
444
|
+
}
|
|
445
|
+
if (options.globPattern)
|
|
446
|
+
args.push(`--include=${options.globPattern}`);
|
|
447
|
+
args.push(pattern, '.');
|
|
448
|
+
try {
|
|
449
|
+
const output = await this.spawnCommand('grep', args, cwd, options.abortSignal);
|
|
450
|
+
return this.parseGrepOutput(output, cwd);
|
|
451
|
+
}
|
|
452
|
+
catch {
|
|
453
|
+
return null;
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
/**
|
|
457
|
+
* Checks if a command is available in the system's PATH.
|
|
458
|
+
*/
|
|
459
|
+
isCommandAvailable(command) {
|
|
460
|
+
return new Promise((resolve) => {
|
|
461
|
+
const checkCmd = process.platform === 'win32' ? 'where' : 'command';
|
|
462
|
+
const checkArgs = process.platform === 'win32' ? [command] : ['-v', command];
|
|
463
|
+
try {
|
|
464
|
+
const child = spawn(checkCmd, checkArgs, { shell: true, stdio: 'ignore' });
|
|
465
|
+
child.on('close', (code) => resolve(code === 0));
|
|
466
|
+
child.on('error', () => resolve(false));
|
|
467
|
+
}
|
|
468
|
+
catch {
|
|
469
|
+
resolve(false);
|
|
470
|
+
}
|
|
471
|
+
});
|
|
472
|
+
}
|
|
473
|
+
/**
|
|
474
|
+
* Parses output from grep-like commands (filepath:lineNumber:content format).
|
|
475
|
+
*/
|
|
476
|
+
parseGrepOutput(output, basePath) {
|
|
477
|
+
const results = [];
|
|
478
|
+
if (!output)
|
|
479
|
+
return results;
|
|
480
|
+
for (const line of output.split(EOL)) {
|
|
481
|
+
if (!line.trim())
|
|
482
|
+
continue;
|
|
483
|
+
// Format: filepath:lineNumber:content
|
|
484
|
+
const firstColon = line.indexOf(':');
|
|
485
|
+
if (firstColon === -1)
|
|
486
|
+
continue;
|
|
487
|
+
const secondColon = line.indexOf(':', firstColon + 1);
|
|
488
|
+
if (secondColon === -1)
|
|
489
|
+
continue;
|
|
490
|
+
const filePath = line.slice(0, firstColon);
|
|
491
|
+
const lineNumber = Number.parseInt(line.slice(firstColon + 1, secondColon), 10);
|
|
492
|
+
const content = line.slice(secondColon + 1);
|
|
493
|
+
if (!Number.isNaN(lineNumber)) {
|
|
494
|
+
results.push({
|
|
495
|
+
file: path.resolve(basePath, filePath),
|
|
496
|
+
line: content,
|
|
497
|
+
lineNumber,
|
|
498
|
+
});
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
return results;
|
|
502
|
+
}
|
|
503
|
+
/**
|
|
504
|
+
* JavaScript-based content search implementation.
|
|
505
|
+
* Used as fallback when native grep commands are unavailable or when context lines are needed.
|
|
506
|
+
*/
|
|
507
|
+
async searchContentJS(pattern, options = {}) {
|
|
508
|
+
const globPattern = options.globPattern ?? '**/*';
|
|
509
|
+
const cwd = options.cwd ?? this.config.workingDirectory;
|
|
510
|
+
const maxResults = options.maxResults ?? 100;
|
|
511
|
+
const contextLines = options.contextLines ?? 0;
|
|
512
|
+
const caseInsensitive = options.caseInsensitive ?? false;
|
|
513
|
+
try {
|
|
514
|
+
// Create regex
|
|
515
|
+
const regex = this.createSearchRegex(pattern, caseInsensitive);
|
|
516
|
+
// Find files to search
|
|
517
|
+
const globResult = await this.globFiles(globPattern, {
|
|
518
|
+
cwd,
|
|
519
|
+
includeMetadata: false,
|
|
520
|
+
maxResults: 10_000, // Search more files, but limit results
|
|
521
|
+
});
|
|
522
|
+
return await this.searchFiles(globResult.files, regex, maxResults, contextLines);
|
|
523
|
+
}
|
|
524
|
+
catch (error) {
|
|
525
|
+
// Re-throw known errors
|
|
526
|
+
if (error instanceof InvalidPatternError || error instanceof GlobOperationError) {
|
|
527
|
+
throw error;
|
|
528
|
+
}
|
|
529
|
+
throw new SearchOperationError(pattern, getErrorMessage(error));
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
/**
|
|
533
|
+
* Searches a single file for a regex pattern.
|
|
534
|
+
*/
|
|
535
|
+
async searchFile(filePath, regex, maxMatches, contextLines) {
|
|
536
|
+
const fileContent = await this.readFile(filePath);
|
|
537
|
+
const lines = fileContent.content.split('\n');
|
|
538
|
+
const matches = [];
|
|
539
|
+
let totalMatches = 0;
|
|
540
|
+
for (let i = 0; i < lines.length; i++) {
|
|
541
|
+
const line = lines[i];
|
|
542
|
+
if (regex.test(line)) {
|
|
543
|
+
totalMatches++;
|
|
544
|
+
if (matches.length >= maxMatches) {
|
|
545
|
+
break;
|
|
546
|
+
}
|
|
547
|
+
const context = this.collectContextLines(lines, i, contextLines);
|
|
548
|
+
matches.push({
|
|
549
|
+
context: contextLines > 0 ? context : undefined,
|
|
550
|
+
file: filePath,
|
|
551
|
+
line,
|
|
552
|
+
lineNumber: i + 1, // 1-based line numbers
|
|
553
|
+
});
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
return { matches, totalMatches };
|
|
557
|
+
}
|
|
558
|
+
/**
|
|
559
|
+
* Searches multiple files for a regex pattern.
|
|
560
|
+
*/
|
|
561
|
+
async searchFiles(files, regex, maxResults, contextLines) {
|
|
562
|
+
const matches = [];
|
|
563
|
+
let totalMatches = 0;
|
|
564
|
+
let filesSearched = 0;
|
|
565
|
+
for (const fileInfo of files) {
|
|
566
|
+
filesSearched++;
|
|
567
|
+
try {
|
|
568
|
+
// eslint-disable-next-line no-await-in-loop
|
|
569
|
+
const fileMatches = await this.searchFile(fileInfo.path, regex, maxResults - matches.length, contextLines);
|
|
570
|
+
totalMatches += fileMatches.totalMatches;
|
|
571
|
+
for (const match of fileMatches.matches) {
|
|
572
|
+
matches.push(match);
|
|
573
|
+
if (matches.length >= maxResults) {
|
|
574
|
+
return {
|
|
575
|
+
filesSearched,
|
|
576
|
+
matches,
|
|
577
|
+
totalMatches,
|
|
578
|
+
truncated: true,
|
|
579
|
+
};
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
catch {
|
|
584
|
+
// Skip files that can't be read
|
|
585
|
+
continue;
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
return {
|
|
589
|
+
filesSearched,
|
|
590
|
+
matches,
|
|
591
|
+
totalMatches,
|
|
592
|
+
truncated: false,
|
|
593
|
+
};
|
|
594
|
+
}
|
|
595
|
+
/**
|
|
596
|
+
* Spawns a command and returns its stdout.
|
|
597
|
+
*/
|
|
598
|
+
spawnCommand(cmd, args, cwd, signal) {
|
|
599
|
+
return new Promise((resolve, reject) => {
|
|
600
|
+
const child = spawn(cmd, args, { cwd, windowsHide: true });
|
|
601
|
+
const chunks = [];
|
|
602
|
+
if (signal) {
|
|
603
|
+
signal.addEventListener('abort', () => child.kill());
|
|
604
|
+
}
|
|
605
|
+
child.stdout.on('data', (chunk) => chunks.push(chunk));
|
|
606
|
+
child.on('error', reject);
|
|
607
|
+
child.on('close', (code) => {
|
|
608
|
+
if (code === 0 || code === 1) {
|
|
609
|
+
// 1 = no matches found (not an error)
|
|
610
|
+
resolve(Buffer.concat(chunks).toString('utf8'));
|
|
611
|
+
}
|
|
612
|
+
else {
|
|
613
|
+
reject(new Error(`Command exited with code ${code}`));
|
|
614
|
+
}
|
|
615
|
+
});
|
|
616
|
+
});
|
|
617
|
+
}
|
|
618
|
+
/**
|
|
619
|
+
* Throws the appropriate error based on validation error message.
|
|
620
|
+
*/
|
|
621
|
+
throwValidationError(path, error) {
|
|
622
|
+
if (error.includes('empty')) {
|
|
623
|
+
throw new InvalidPathError(path, error);
|
|
624
|
+
}
|
|
625
|
+
if (error.includes('traversal')) {
|
|
626
|
+
throw new PathTraversalError(path);
|
|
627
|
+
}
|
|
628
|
+
if (error.includes('not in allowed paths')) {
|
|
629
|
+
throw new PathNotAllowedError(path, this.config.allowedPaths);
|
|
630
|
+
}
|
|
631
|
+
if (error.includes('blocked')) {
|
|
632
|
+
throw new PathBlockedError(path, error);
|
|
633
|
+
}
|
|
634
|
+
if (error.includes('extension')) {
|
|
635
|
+
const ext = path.split('.').pop() ?? '';
|
|
636
|
+
throw new InvalidExtensionError(path, ext);
|
|
637
|
+
}
|
|
638
|
+
// Fallback
|
|
639
|
+
throw new InvalidPathError(path, error);
|
|
640
|
+
}
|
|
641
|
+
}
|