@ebowwa/coder 0.7.63 → 0.7.65
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/dist/core/__tests__/permissions.test.d.ts +12 -0
- package/dist/core/__tests__/permissions.test.d.ts.map +1 -0
- package/dist/core/__tests__/permissions.test.js +851 -0
- package/dist/core/agent-loop/__tests__/compaction.test.d.ts +5 -0
- package/dist/core/agent-loop/__tests__/compaction.test.d.ts.map +1 -0
- package/dist/core/agent-loop/__tests__/compaction.test.js +209 -0
- package/dist/core/agent-loop/__tests__/formatters.test.d.ts +5 -0
- package/dist/core/agent-loop/__tests__/formatters.test.d.ts.map +1 -0
- package/dist/core/agent-loop/__tests__/formatters.test.js +195 -0
- package/dist/core/agent-loop/__tests__/index.test.d.ts +5 -0
- package/dist/core/agent-loop/__tests__/index.test.d.ts.map +1 -0
- package/dist/core/agent-loop/__tests__/index.test.js +121 -0
- package/dist/core/agent-loop/__tests__/loop-state.test.d.ts +5 -0
- package/dist/core/agent-loop/__tests__/loop-state.test.d.ts.map +1 -0
- package/dist/core/agent-loop/__tests__/loop-state.test.js +340 -0
- package/dist/core/agent-loop/__tests__/message-builder.test.d.ts +5 -0
- package/dist/core/agent-loop/__tests__/message-builder.test.d.ts.map +1 -0
- package/dist/core/agent-loop/__tests__/message-builder.test.js +178 -0
- package/dist/core/agent-loop/__tests__/tool-executor.test.d.ts +5 -0
- package/dist/core/agent-loop/__tests__/tool-executor.test.d.ts.map +1 -0
- package/dist/core/agent-loop/__tests__/tool-executor.test.js +331 -0
- package/dist/core/agent-loop/compaction.d.ts +39 -0
- package/dist/core/agent-loop/compaction.d.ts.map +1 -0
- package/dist/core/agent-loop/compaction.js +51 -0
- package/dist/core/agent-loop/formatters.d.ts +21 -0
- package/dist/core/agent-loop/formatters.d.ts.map +1 -0
- package/dist/core/agent-loop/formatters.js +42 -0
- package/dist/core/agent-loop/index.d.ts +25 -0
- package/dist/core/agent-loop/index.d.ts.map +1 -0
- package/dist/core/agent-loop/index.js +83 -0
- package/dist/core/agent-loop/loop-state.d.ts +74 -0
- package/dist/core/agent-loop/loop-state.d.ts.map +1 -0
- package/dist/core/agent-loop/loop-state.js +147 -0
- package/dist/core/agent-loop/message-builder.d.ts +13 -0
- package/dist/core/agent-loop/message-builder.d.ts.map +1 -0
- package/dist/core/agent-loop/message-builder.js +49 -0
- package/dist/core/agent-loop/tool-executor.d.ts +23 -0
- package/dist/core/agent-loop/tool-executor.d.ts.map +1 -0
- package/dist/core/agent-loop/tool-executor.js +152 -0
- package/dist/core/agent-loop/turn-executor.d.ts +57 -0
- package/dist/core/agent-loop/turn-executor.d.ts.map +1 -0
- package/dist/core/agent-loop/turn-executor.js +124 -0
- package/dist/core/agent-loop/types.d.ts +141 -0
- package/dist/core/agent-loop/types.d.ts.map +1 -0
- package/dist/core/agent-loop/types.js +4 -0
- package/dist/core/agent-loop.d.ts +17 -0
- package/dist/core/agent-loop.d.ts.map +1 -0
- package/dist/core/agent-loop.js +16 -0
- package/dist/core/api-client-impl.d.ts +62 -0
- package/dist/core/api-client-impl.d.ts.map +1 -0
- package/dist/core/api-client-impl.js +479 -0
- package/dist/core/api-client.d.ts +6 -0
- package/dist/core/api-client.d.ts.map +1 -0
- package/dist/core/api-client.js +5 -0
- package/dist/core/checkpoints.d.ts +128 -0
- package/dist/core/checkpoints.d.ts.map +1 -0
- package/dist/core/checkpoints.js +438 -0
- package/dist/core/claude-md.d.ts +71 -0
- package/dist/core/claude-md.d.ts.map +1 -0
- package/dist/core/claude-md.js +198 -0
- package/dist/core/cognitive-security/hooks.d.ts +138 -0
- package/dist/core/cognitive-security/hooks.d.ts.map +1 -0
- package/dist/core/cognitive-security/hooks.js +389 -0
- package/dist/core/cognitive-security/index.d.ts +751 -0
- package/dist/core/cognitive-security/index.d.ts.map +1 -0
- package/dist/core/cognitive-security/index.js +1123 -0
- package/dist/core/cognitive-security/middleware.d.ts +136 -0
- package/dist/core/cognitive-security/middleware.d.ts.map +1 -0
- package/dist/core/cognitive-security/middleware.js +376 -0
- package/dist/core/config-loader.d.ts +127 -0
- package/dist/core/config-loader.d.ts.map +1 -0
- package/dist/core/config-loader.js +219 -0
- package/dist/core/context-compaction.d.ts +87 -0
- package/dist/core/context-compaction.d.ts.map +1 -0
- package/dist/core/context-compaction.js +428 -0
- package/dist/core/git-status.d.ts +25 -0
- package/dist/core/git-status.d.ts.map +1 -0
- package/dist/core/git-status.js +204 -0
- package/dist/core/image.d.ts +69 -0
- package/dist/core/image.d.ts.map +1 -0
- package/dist/core/image.js +290 -0
- package/dist/core/image.test.d.ts +2 -0
- package/dist/core/image.test.d.ts.map +1 -0
- package/dist/core/image.test.js +149 -0
- package/dist/core/models.d.ts +123 -0
- package/dist/core/models.d.ts.map +1 -0
- package/dist/core/models.js +325 -0
- package/dist/core/permissions.d.ts +81 -0
- package/dist/core/permissions.d.ts.map +1 -0
- package/dist/core/permissions.js +327 -0
- package/dist/core/retry.d.ts +25 -0
- package/dist/core/retry.d.ts.map +1 -0
- package/dist/core/retry.js +121 -0
- package/dist/core/session-store.d.ts +9 -0
- package/dist/core/session-store.d.ts.map +1 -0
- package/dist/core/session-store.js +10 -0
- package/dist/core/sessions/export.d.ts +47 -0
- package/dist/core/sessions/export.d.ts.map +1 -0
- package/dist/core/sessions/export.js +256 -0
- package/dist/core/sessions/index.d.ts +132 -0
- package/dist/core/sessions/index.d.ts.map +1 -0
- package/dist/core/sessions/index.js +442 -0
- package/dist/core/sessions/metadata.d.ts +77 -0
- package/dist/core/sessions/metadata.d.ts.map +1 -0
- package/dist/core/sessions/metadata.js +233 -0
- package/dist/core/sessions/persistence.d.ts +72 -0
- package/dist/core/sessions/persistence.d.ts.map +1 -0
- package/dist/core/sessions/persistence.js +201 -0
- package/dist/core/sessions/types.d.ts +110 -0
- package/dist/core/sessions/types.d.ts.map +1 -0
- package/dist/core/sessions/types.js +4 -0
- package/dist/core/stream-highlighter.d.ts +18 -0
- package/dist/core/stream-highlighter.d.ts.map +1 -0
- package/dist/core/stream-highlighter.js +916 -0
- package/dist/core/system-reminders.d.ts +89 -0
- package/dist/core/system-reminders.d.ts.map +1 -0
- package/dist/core/system-reminders.js +285 -0
- package/dist/ecosystem/hooks/__tests__/index.test.d.ts +5 -0
- package/dist/ecosystem/hooks/__tests__/index.test.d.ts.map +1 -0
- package/dist/ecosystem/hooks/__tests__/index.test.js +458 -0
- package/dist/ecosystem/hooks/index.d.ts +59 -0
- package/dist/ecosystem/hooks/index.d.ts.map +1 -0
- package/dist/ecosystem/hooks/index.js +294 -0
- package/dist/ecosystem/hooks/prompt-evaluator.d.ts +32 -0
- package/dist/ecosystem/hooks/prompt-evaluator.d.ts.map +1 -0
- package/dist/ecosystem/hooks/prompt-evaluator.js +229 -0
- package/dist/ecosystem/skills/index.d.ts +55 -0
- package/dist/ecosystem/skills/index.d.ts.map +1 -0
- package/dist/ecosystem/skills/index.js +258 -0
- package/dist/ecosystem/tools/__tests__/index.test.d.ts +7 -0
- package/dist/ecosystem/tools/__tests__/index.test.d.ts.map +1 -0
- package/dist/ecosystem/tools/__tests__/index.test.js +856 -0
- package/dist/ecosystem/tools/index.d.ts +24 -0
- package/dist/ecosystem/tools/index.d.ts.map +1 -0
- package/dist/ecosystem/tools/index.js +1709 -0
- package/dist/index.d.ts +24 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +33688 -49712
- package/dist/interfaces/mcp/client.d.ts +40 -0
- package/dist/interfaces/mcp/client.d.ts.map +1 -0
- package/dist/interfaces/mcp/client.js +309 -0
- package/dist/interfaces/ui/index.d.ts +36 -0
- package/dist/interfaces/ui/index.d.ts.map +1 -0
- package/dist/interfaces/ui/index.js +61 -0
- package/dist/interfaces/ui/spinner.d.ts +140 -0
- package/dist/interfaces/ui/spinner.d.ts.map +1 -0
- package/dist/interfaces/ui/spinner.js +342 -0
- package/dist/interfaces/ui/terminal/cli/index.d.ts +12 -0
- package/dist/interfaces/ui/terminal/cli/index.d.ts.map +1 -0
- package/dist/interfaces/ui/terminal/cli/index.js +32012 -50526
- package/dist/interfaces/ui/terminal/native/README.md +53 -0
- package/dist/interfaces/ui/terminal/native/claude_code_native.darwin-x64.node +0 -0
- package/dist/interfaces/ui/terminal/native/claude_code_native.dylib +0 -0
- package/dist/interfaces/ui/terminal/native/index.d.ts +0 -0
- package/dist/interfaces/ui/terminal/native/index.darwin-arm64.node +0 -0
- package/dist/interfaces/ui/terminal/native/index.js +43 -0
- package/dist/interfaces/ui/terminal/native/index.node +0 -0
- package/dist/interfaces/ui/terminal/native/package.json +34 -0
- package/dist/interfaces/ui/terminal/shared/args.d.ts +39 -0
- package/dist/interfaces/ui/terminal/shared/args.d.ts.map +1 -0
- package/dist/interfaces/ui/terminal/shared/args.js +176 -0
- package/dist/interfaces/ui/terminal/shared/index.d.ts +11 -0
- package/dist/interfaces/ui/terminal/shared/index.d.ts.map +1 -0
- package/dist/interfaces/ui/terminal/shared/index.js +16 -0
- package/dist/interfaces/ui/terminal/shared/loading-state.d.ts +124 -0
- package/dist/interfaces/ui/terminal/shared/loading-state.d.ts.map +1 -0
- package/dist/interfaces/ui/terminal/shared/loading-state.js +246 -0
- package/dist/interfaces/ui/terminal/shared/query.d.ts +22 -0
- package/dist/interfaces/ui/terminal/shared/query.d.ts.map +1 -0
- package/dist/interfaces/ui/terminal/shared/query.js +100 -0
- package/dist/interfaces/ui/terminal/shared/setup.d.ts +33 -0
- package/dist/interfaces/ui/terminal/shared/setup.d.ts.map +1 -0
- package/dist/interfaces/ui/terminal/shared/setup.js +226 -0
- package/dist/interfaces/ui/terminal/shared/status-line.d.ts +117 -0
- package/dist/interfaces/ui/terminal/shared/status-line.d.ts.map +1 -0
- package/dist/interfaces/ui/terminal/shared/status-line.js +267 -0
- package/dist/interfaces/ui/terminal/shared/system-prompt.d.ts +38 -0
- package/dist/interfaces/ui/terminal/shared/system-prompt.d.ts.map +1 -0
- package/dist/interfaces/ui/terminal/shared/system-prompt.js +102 -0
- package/dist/interfaces/ui/terminal/tui/HelpPanel.d.ts +39 -0
- package/dist/interfaces/ui/terminal/tui/HelpPanel.d.ts.map +1 -0
- package/dist/interfaces/ui/terminal/tui/HelpPanel.js +215 -0
- package/dist/interfaces/ui/terminal/tui/InputContext.d.ts +91 -0
- package/dist/interfaces/ui/terminal/tui/InputContext.d.ts.map +1 -0
- package/dist/interfaces/ui/terminal/tui/InputContext.js +154 -0
- package/dist/interfaces/ui/terminal/tui/InputField.d.ts +18 -0
- package/dist/interfaces/ui/terminal/tui/InputField.d.ts.map +1 -0
- package/dist/interfaces/ui/terminal/tui/InputField.js +41 -0
- package/dist/interfaces/ui/terminal/tui/InteractiveTUI.d.ts +16 -0
- package/dist/interfaces/ui/terminal/tui/InteractiveTUI.d.ts.map +1 -0
- package/dist/interfaces/ui/terminal/tui/InteractiveTUI.js +451 -0
- package/dist/interfaces/ui/terminal/tui/MessageArea.d.ts +10 -0
- package/dist/interfaces/ui/terminal/tui/MessageArea.d.ts.map +1 -0
- package/dist/interfaces/ui/terminal/tui/MessageArea.js +91 -0
- package/dist/interfaces/ui/terminal/tui/MessageStore.d.ts +48 -0
- package/dist/interfaces/ui/terminal/tui/MessageStore.d.ts.map +1 -0
- package/dist/interfaces/ui/terminal/tui/MessageStore.js +151 -0
- package/dist/interfaces/ui/terminal/tui/StatusBar.d.ts +9 -0
- package/dist/interfaces/ui/terminal/tui/StatusBar.d.ts.map +1 -0
- package/dist/interfaces/ui/terminal/tui/StatusBar.js +36 -0
- package/dist/interfaces/ui/terminal/tui/commands.d.ts +21 -0
- package/dist/interfaces/ui/terminal/tui/commands.d.ts.map +1 -0
- package/dist/interfaces/ui/terminal/tui/commands.js +359 -0
- package/dist/interfaces/ui/terminal/tui/components/InteractiveElements.d.ts +115 -0
- package/dist/interfaces/ui/terminal/tui/components/InteractiveElements.d.ts.map +1 -0
- package/dist/interfaces/ui/terminal/tui/components/InteractiveElements.js +306 -0
- package/dist/interfaces/ui/terminal/tui/components/MultilineInput.d.ts +92 -0
- package/dist/interfaces/ui/terminal/tui/components/MultilineInput.d.ts.map +1 -0
- package/dist/interfaces/ui/terminal/tui/components/MultilineInput.js +399 -0
- package/dist/interfaces/ui/terminal/tui/components/PaneManager.d.ts +59 -0
- package/dist/interfaces/ui/terminal/tui/components/PaneManager.d.ts.map +1 -0
- package/dist/interfaces/ui/terminal/tui/components/PaneManager.js +139 -0
- package/dist/interfaces/ui/terminal/tui/components/Sidebar.d.ts +68 -0
- package/dist/interfaces/ui/terminal/tui/components/Sidebar.d.ts.map +1 -0
- package/dist/interfaces/ui/terminal/tui/components/Sidebar.js +340 -0
- package/dist/interfaces/ui/terminal/tui/components/index.d.ts +23 -0
- package/dist/interfaces/ui/terminal/tui/components/index.d.ts.map +1 -0
- package/dist/interfaces/ui/terminal/tui/components/index.js +51 -0
- package/dist/interfaces/ui/terminal/tui/console.d.ts +20 -0
- package/dist/interfaces/ui/terminal/tui/console.d.ts.map +1 -0
- package/dist/interfaces/ui/terminal/tui/console.js +46 -0
- package/dist/interfaces/ui/terminal/tui/index.d.ts +20 -0
- package/dist/interfaces/ui/terminal/tui/index.d.ts.map +1 -0
- package/dist/interfaces/ui/terminal/tui/index.js +28 -0
- package/dist/interfaces/ui/terminal/tui/run.d.ts +13 -0
- package/dist/interfaces/ui/terminal/tui/run.d.ts.map +1 -0
- package/dist/interfaces/ui/terminal/tui/run.js +31 -0
- package/dist/interfaces/ui/terminal/tui/spinner.d.ts +44 -0
- package/dist/interfaces/ui/terminal/tui/spinner.d.ts.map +1 -0
- package/dist/interfaces/ui/terminal/tui/spinner.js +59 -0
- package/dist/interfaces/ui/terminal/tui/tui-app.d.ts +39 -0
- package/dist/interfaces/ui/terminal/tui/tui-app.d.ts.map +1 -0
- package/dist/interfaces/ui/terminal/tui/tui-app.js +198 -0
- package/dist/interfaces/ui/terminal/tui/tui-footer.d.ts +167 -0
- package/dist/interfaces/ui/terminal/tui/tui-footer.d.ts.map +1 -0
- package/dist/interfaces/ui/terminal/tui/tui-footer.js +330 -0
- package/dist/interfaces/ui/terminal/tui/types.d.ts +165 -0
- package/dist/interfaces/ui/terminal/tui/types.d.ts.map +1 -0
- package/dist/interfaces/ui/terminal/tui/types.js +5 -0
- package/dist/interfaces/ui/terminal/tui/useInputHandler.d.ts +23 -0
- package/dist/interfaces/ui/terminal/tui/useInputHandler.d.ts.map +1 -0
- package/dist/interfaces/ui/terminal/tui/useInputHandler.js +72 -0
- package/dist/interfaces/ui/terminal/tui/useNativeInput.d.ts +90 -0
- package/dist/interfaces/ui/terminal/tui/useNativeInput.d.ts.map +1 -0
- package/dist/interfaces/ui/terminal/tui/useNativeInput.js +188 -0
- package/dist/native/README.md +53 -0
- package/dist/native/claude_code_native.darwin-x64.node +0 -0
- package/dist/native/claude_code_native.dylib +0 -0
- package/dist/native/index.d.ts +0 -0
- package/dist/native/index.d.ts.map +1 -0
- package/dist/native/index.darwin-arm64.node +0 -0
- package/dist/native/index.js +43 -0
- package/dist/native/index.node +0 -0
- package/dist/native/package.json +34 -0
- package/dist/teammates/index.d.ts +161 -0
- package/dist/teammates/index.d.ts.map +1 -0
- package/dist/teammates/index.js +827 -0
- package/dist/types/index.d.ts +482 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +52 -0
- package/native/index.darwin-arm64.node +0 -0
- package/native/index.js +33 -19
- package/package.json +6 -3
- package/packages/src/core/__tests__/permissions.test.ts +1091 -0
- package/packages/src/core/agent-loop/__tests__/compaction.test.ts +283 -0
- package/packages/src/core/agent-loop/__tests__/formatters.test.ts +234 -0
- package/packages/src/core/agent-loop/__tests__/index.test.ts +162 -0
- package/packages/src/core/agent-loop/__tests__/loop-state.test.ts +413 -0
- package/packages/src/core/agent-loop/__tests__/message-builder.test.ts +229 -0
- package/packages/src/core/agent-loop/__tests__/tool-executor.test.ts +457 -0
- package/packages/src/core/agent-loop/compaction.ts +92 -0
- package/packages/src/core/agent-loop/formatters.ts +50 -0
- package/packages/src/core/agent-loop/index.ts +137 -0
- package/packages/src/core/agent-loop/loop-state.ts +187 -0
- package/packages/src/core/agent-loop/message-builder.ts +62 -0
- package/packages/src/core/agent-loop/tool-executor.ts +211 -0
- package/packages/src/core/agent-loop/turn-executor.ts +226 -0
- package/packages/src/core/agent-loop/types.ts +152 -0
- package/packages/src/core/agent-loop.ts +18 -0
- package/packages/src/core/api-client-impl.ts +729 -0
- package/packages/src/core/api-client.ts +6 -0
- package/packages/src/core/checkpoints.ts +606 -0
- package/packages/src/core/claude-md.ts +272 -0
- package/packages/src/core/cognitive-security/hooks.ts +591 -0
- package/packages/src/core/cognitive-security/index.ts +2041 -0
- package/packages/src/core/cognitive-security/middleware.ts +536 -0
- package/packages/src/core/config/todo +7 -0
- package/packages/src/core/config-loader.ts +324 -0
- package/packages/src/core/context/__tests__/integration.test.ts +334 -0
- package/packages/src/core/context/compaction.ts +170 -0
- package/packages/src/core/context/constants.ts +58 -0
- package/packages/src/core/context/extraction.ts +85 -0
- package/packages/src/core/context/index.ts +66 -0
- package/packages/src/core/context/summarization.ts +251 -0
- package/packages/src/core/context/token-estimation.ts +98 -0
- package/packages/src/core/context/types.ts +59 -0
- package/packages/src/core/git-status.ts +262 -0
- package/packages/src/core/image.test.ts +180 -0
- package/packages/src/core/image.ts +350 -0
- package/packages/src/core/lmdb.db +0 -0
- package/packages/src/core/lmdb.db-lock +0 -0
- package/packages/src/core/models.ts +507 -0
- package/packages/src/core/normalizers/todo +8 -0
- package/packages/src/core/permissions.ts +431 -0
- package/packages/src/core/providers/README.md +230 -0
- package/packages/src/core/providers/__tests__/providers.test.ts +135 -0
- package/packages/src/core/providers/index.ts +419 -0
- package/packages/src/core/providers/types.ts +132 -0
- package/packages/src/core/retry.ts +180 -0
- package/packages/src/core/session-store.ts +36 -0
- package/packages/src/core/sessions/export.ts +329 -0
- package/packages/src/core/sessions/index.ts +587 -0
- package/packages/src/core/sessions/metadata.ts +309 -0
- package/packages/src/core/sessions/persistence.ts +244 -0
- package/packages/src/core/sessions/types.ts +169 -0
- package/packages/src/core/stream-highlighter.ts +1123 -0
- package/packages/src/core/system-reminders.ts +402 -0
- package/packages/src/core/todo +8 -0
- package/packages/src/ecosystem/hooks/__tests__/index.test.ts +561 -0
- package/packages/src/ecosystem/hooks/index.ts +341 -0
- package/packages/src/ecosystem/hooks/prompt-evaluator.ts +300 -0
- package/packages/src/ecosystem/skills/index.ts +295 -0
- package/packages/src/ecosystem/tools/__tests__/index.test.ts +1335 -0
- package/packages/src/ecosystem/tools/index.ts +2051 -0
- package/packages/src/index.ts +141 -0
- package/packages/src/interfaces/mcp/client.ts +389 -0
- package/packages/src/interfaces/ui/index.ts +158 -0
- package/packages/src/interfaces/ui/lmdb.db +0 -0
- package/packages/src/interfaces/ui/lmdb.db-lock +0 -0
- package/packages/src/interfaces/ui/spinner.ts +451 -0
- package/packages/src/interfaces/ui/terminal/bridge/index.ts +370 -0
- package/packages/src/interfaces/ui/terminal/bridge/ipc.ts +829 -0
- package/packages/src/interfaces/ui/terminal/bridge/screen-export.ts +968 -0
- package/packages/src/interfaces/ui/terminal/bridge/types.ts +226 -0
- package/packages/src/interfaces/ui/terminal/bridge/useBridge.ts +210 -0
- package/packages/src/interfaces/ui/terminal/cli/bootstrap.ts +132 -0
- package/packages/src/interfaces/ui/terminal/cli/index.ts +415 -0
- package/packages/src/interfaces/ui/terminal/cli/interactive/index.ts +110 -0
- package/packages/src/interfaces/ui/terminal/cli/interactive/input-handler.ts +393 -0
- package/packages/src/interfaces/ui/terminal/cli/interactive/interactive-runner.ts +820 -0
- package/packages/src/interfaces/ui/terminal/cli/interactive/message-store.ts +299 -0
- package/packages/src/interfaces/ui/terminal/cli/interactive/types.ts +274 -0
- package/packages/src/interfaces/ui/terminal/lmdb.db +0 -0
- package/packages/src/interfaces/ui/terminal/lmdb.db-lock +0 -0
- package/packages/src/interfaces/ui/terminal/shared/args.ts +222 -0
- package/packages/src/interfaces/ui/terminal/shared/index.ts +84 -0
- package/packages/src/interfaces/ui/terminal/shared/loading-state.ts +322 -0
- package/packages/src/interfaces/ui/terminal/shared/query.ts +152 -0
- package/packages/src/interfaces/ui/terminal/shared/setup.ts +299 -0
- package/packages/src/interfaces/ui/terminal/shared/spinner-frames.ts +73 -0
- package/packages/src/interfaces/ui/terminal/shared/status-line.ts +366 -0
- package/packages/src/interfaces/ui/terminal/shared/system-prompt.ts +146 -0
- package/packages/src/lmdb.db +0 -0
- package/packages/src/lmdb.db-lock +0 -0
- package/packages/src/native/index.ts +2722 -0
- package/packages/src/native/tui_v2_types.ts +39 -0
- package/packages/src/teammates/coordination.test.ts +279 -0
- package/packages/src/teammates/coordination.ts +646 -0
- package/packages/src/teammates/index.ts +1052 -0
- package/packages/src/teammates/integration.test.ts +272 -0
- package/packages/src/teammates/runner.test.ts +235 -0
- package/packages/src/teammates/runner.ts +750 -0
- package/packages/src/teammates/schemas.ts +673 -0
- package/packages/src/types/index.ts +723 -0
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Token Estimation - Estimate token counts for messages
|
|
3
|
+
*
|
|
4
|
+
* Uses native Rust module for accurate, code-aware token counting.
|
|
5
|
+
* Falls back to heuristic (~4 chars/token) if native unavailable.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type { Message, ContentBlock } from "../../types/index.js";
|
|
9
|
+
import { CHARS_PER_TOKEN } from "./constants.js";
|
|
10
|
+
|
|
11
|
+
// Lazy-load native module to avoid circular dependencies
|
|
12
|
+
let _native: { count_tokens?: (text: string) => number } | null = null;
|
|
13
|
+
let _nativeLoadAttempted = false;
|
|
14
|
+
|
|
15
|
+
function getNative(): { count_tokens?: (text: string) => number } | null {
|
|
16
|
+
if (_nativeLoadAttempted) return _native;
|
|
17
|
+
_nativeLoadAttempted = true;
|
|
18
|
+
|
|
19
|
+
try {
|
|
20
|
+
// Dynamic import to avoid bundling issues
|
|
21
|
+
const nativePath = require.resolve("../../../native/index.js");
|
|
22
|
+
_native = require(nativePath).getNative?.() ?? null;
|
|
23
|
+
} catch {
|
|
24
|
+
// Native module not available, use fallback
|
|
25
|
+
_native = null;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return _native;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Estimate the number of tokens in a text string.
|
|
33
|
+
* Uses native code-aware tokenizer if available, falls back to heuristic.
|
|
34
|
+
*/
|
|
35
|
+
export function estimateTokens(text: string): number {
|
|
36
|
+
if (!text || text.length === 0) return 0;
|
|
37
|
+
|
|
38
|
+
// Try native module first (more accurate, code-aware)
|
|
39
|
+
const native = getNative();
|
|
40
|
+
if (native?.count_tokens) {
|
|
41
|
+
return native.count_tokens(text);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Fallback: simple heuristic
|
|
45
|
+
return Math.ceil(text.length / CHARS_PER_TOKEN);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Estimate tokens for a single content block
|
|
50
|
+
*/
|
|
51
|
+
export function estimateBlockTokens(block: ContentBlock): number {
|
|
52
|
+
switch (block.type) {
|
|
53
|
+
case "text":
|
|
54
|
+
return estimateTokens(block.text);
|
|
55
|
+
case "image":
|
|
56
|
+
// Images are roughly 85-110 tokens for standard sizes
|
|
57
|
+
// Use 100 as an average estimate
|
|
58
|
+
return 100;
|
|
59
|
+
case "tool_use":
|
|
60
|
+
// Tool use: name + JSON input
|
|
61
|
+
const toolInput = JSON.stringify(block.input);
|
|
62
|
+
return estimateTokens(block.name) + estimateTokens(toolInput) + 10; // overhead
|
|
63
|
+
case "tool_result":
|
|
64
|
+
// Tool result: content + metadata
|
|
65
|
+
if (typeof block.content === "string") {
|
|
66
|
+
return estimateTokens(block.content) + 10;
|
|
67
|
+
}
|
|
68
|
+
return block.content.reduce((sum, b) => sum + estimateBlockTokens(b), 0) + 10;
|
|
69
|
+
case "thinking":
|
|
70
|
+
return estimateTokens(block.thinking);
|
|
71
|
+
default:
|
|
72
|
+
return 0;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Estimate the total number of tokens in a message
|
|
78
|
+
*/
|
|
79
|
+
export function estimateMessageTokens(message: Message): number {
|
|
80
|
+
// Role overhead (~4 tokens)
|
|
81
|
+
const roleOverhead = 4;
|
|
82
|
+
|
|
83
|
+
// Sum all content blocks
|
|
84
|
+
const contentTokens = message.content.reduce(
|
|
85
|
+
(sum, block) => sum + estimateBlockTokens(block),
|
|
86
|
+
0
|
|
87
|
+
);
|
|
88
|
+
|
|
89
|
+
return roleOverhead + contentTokens;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Get total estimated tokens across all messages
|
|
94
|
+
*/
|
|
95
|
+
export function estimateMessagesTokens(messages: Message[]): number {
|
|
96
|
+
if (!messages || messages.length === 0) return 0;
|
|
97
|
+
return messages.reduce((sum, msg) => sum + estimateMessageTokens(msg), 0);
|
|
98
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Context Types - Type definitions for context compaction
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import type { ContentBlock, Message } from "../../types/index.js";
|
|
6
|
+
|
|
7
|
+
/** Options for LLM-based summarization */
|
|
8
|
+
export interface LLMSummarizationOptions {
|
|
9
|
+
/** API key for the LLM */
|
|
10
|
+
apiKey?: string;
|
|
11
|
+
/** Model to use for summarization (default: haiku) */
|
|
12
|
+
model?: string;
|
|
13
|
+
/** Base URL for API (for non-Anthropic providers) */
|
|
14
|
+
baseUrl?: string;
|
|
15
|
+
/** Timeout in ms (default: 30000) */
|
|
16
|
+
timeout?: number;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/** Options for message compaction */
|
|
20
|
+
export interface CompactionOptions {
|
|
21
|
+
/** Number of initial messages to keep unchanged */
|
|
22
|
+
keepFirst?: number;
|
|
23
|
+
/** Number of recent messages to keep unchanged */
|
|
24
|
+
keepLast?: number;
|
|
25
|
+
/** Whether to preserve tool_use/tool_result pairs */
|
|
26
|
+
preserveToolPairs?: boolean;
|
|
27
|
+
/** Use LLM for summarization (default: true if API key available) */
|
|
28
|
+
useLLMSummarization?: boolean;
|
|
29
|
+
/** API key for LLM summarization (falls back to env) */
|
|
30
|
+
apiKey?: string;
|
|
31
|
+
/** Base URL for API (for non-Anthropic providers like Z.AI) */
|
|
32
|
+
baseUrl?: string;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** Result of a compaction operation */
|
|
36
|
+
export interface CompactionResult {
|
|
37
|
+
/** The compacted messages */
|
|
38
|
+
messages: Message[];
|
|
39
|
+
/** Number of messages removed */
|
|
40
|
+
messagesRemoved: number;
|
|
41
|
+
/** Estimated tokens before compaction */
|
|
42
|
+
tokensBefore: number;
|
|
43
|
+
/** Estimated tokens after compaction */
|
|
44
|
+
tokensAfter: number;
|
|
45
|
+
/** Whether compaction actually occurred */
|
|
46
|
+
didCompact: boolean;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** Statistics from compaction */
|
|
50
|
+
export interface CompactionStats {
|
|
51
|
+
reductionPercent: number;
|
|
52
|
+
tokensSaved: number;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/** Tool use/result pair for preservation */
|
|
56
|
+
export interface ToolPair {
|
|
57
|
+
use: { type: "tool_use"; id: string; name: string; input: unknown };
|
|
58
|
+
result?: { type: "tool_result"; tool_use_id: string; content: string | ContentBlock[]; is_error?: boolean };
|
|
59
|
+
}
|
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Git Status - Retrieve repository status information
|
|
3
|
+
* Uses Bun subprocess to run git commands
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { GitStatus } from "../types/index.js";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Run a git command and return its output
|
|
10
|
+
*/
|
|
11
|
+
async function runGitCommand(
|
|
12
|
+
args: string[],
|
|
13
|
+
cwd: string
|
|
14
|
+
): Promise<{ stdout: string; stderr: string; exitCode: number }> {
|
|
15
|
+
const proc = Bun.spawn(["git", ...args], {
|
|
16
|
+
cwd,
|
|
17
|
+
stdout: "pipe",
|
|
18
|
+
stderr: "pipe",
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
const stdout = await new Response(proc.stdout).text();
|
|
22
|
+
const stderr = await new Response(proc.stderr).text();
|
|
23
|
+
const exitCode = await proc.exited;
|
|
24
|
+
|
|
25
|
+
return { stdout: stdout.trim(), stderr: stderr.trim(), exitCode };
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Check if the directory is a git repository
|
|
30
|
+
*/
|
|
31
|
+
async function isGitRepository(workingDirectory: string): Promise<boolean> {
|
|
32
|
+
const { exitCode } = await runGitCommand(
|
|
33
|
+
["rev-parse", "--git-dir"],
|
|
34
|
+
workingDirectory
|
|
35
|
+
);
|
|
36
|
+
return exitCode === 0;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Get the current branch name
|
|
41
|
+
*/
|
|
42
|
+
async function getBranch(workingDirectory: string): Promise<string> {
|
|
43
|
+
const { stdout, exitCode } = await runGitCommand(
|
|
44
|
+
["rev-parse", "--abbrev-ref", "HEAD"],
|
|
45
|
+
workingDirectory
|
|
46
|
+
);
|
|
47
|
+
|
|
48
|
+
if (exitCode !== 0) {
|
|
49
|
+
return "HEAD";
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return stdout || "HEAD";
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Get ahead/behind counts compared to upstream
|
|
57
|
+
*/
|
|
58
|
+
async function getAheadBehind(
|
|
59
|
+
workingDirectory: string
|
|
60
|
+
): Promise<{ ahead: number; behind: number }> {
|
|
61
|
+
const { stdout, exitCode } = await runGitCommand(
|
|
62
|
+
["rev-list", "--left-right", "--count", "@{upstream}...HEAD"],
|
|
63
|
+
workingDirectory
|
|
64
|
+
);
|
|
65
|
+
|
|
66
|
+
if (exitCode !== 0 || !stdout) {
|
|
67
|
+
return { ahead: 0, behind: 0 };
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const parts = stdout.split(/\s+/);
|
|
71
|
+
if (parts.length >= 2 && parts[0] !== undefined && parts[1] !== undefined) {
|
|
72
|
+
return {
|
|
73
|
+
ahead: parseInt(parts[0], 10) || 0,
|
|
74
|
+
behind: parseInt(parts[1], 10) || 0,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return { ahead: 0, behind: 0 };
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Parse git status porcelain output
|
|
83
|
+
* Format: XY PATH where X is staged status, Y is unstaged status
|
|
84
|
+
*
|
|
85
|
+
* Status codes:
|
|
86
|
+
* - ' ' (space): unmodified
|
|
87
|
+
* - 'M': modified
|
|
88
|
+
* - 'A': added (staged)
|
|
89
|
+
* - 'D': deleted
|
|
90
|
+
* - 'R': renamed
|
|
91
|
+
* - 'C': copied
|
|
92
|
+
* - 'U': unmerged (conflict)
|
|
93
|
+
* - '?': untracked
|
|
94
|
+
* - '!': ignored
|
|
95
|
+
*/
|
|
96
|
+
async function getFileStatus(
|
|
97
|
+
workingDirectory: string
|
|
98
|
+
): Promise<{
|
|
99
|
+
staged: string[];
|
|
100
|
+
unstaged: string[];
|
|
101
|
+
untracked: string[];
|
|
102
|
+
conflicted: string[];
|
|
103
|
+
}> {
|
|
104
|
+
const { stdout, exitCode } = await runGitCommand(
|
|
105
|
+
["status", "--porcelain"],
|
|
106
|
+
workingDirectory
|
|
107
|
+
);
|
|
108
|
+
|
|
109
|
+
if (exitCode !== 0 || !stdout) {
|
|
110
|
+
return {
|
|
111
|
+
staged: [],
|
|
112
|
+
unstaged: [],
|
|
113
|
+
untracked: [],
|
|
114
|
+
conflicted: [],
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const staged: string[] = [];
|
|
119
|
+
const unstaged: string[] = [];
|
|
120
|
+
const untracked: string[] = [];
|
|
121
|
+
const conflicted: string[] = [];
|
|
122
|
+
|
|
123
|
+
const lines = stdout.split("\n");
|
|
124
|
+
|
|
125
|
+
for (const line of lines) {
|
|
126
|
+
if (!line) continue;
|
|
127
|
+
|
|
128
|
+
// Porcelain format: XY PATH or XY ORIG_PATH -> PATH
|
|
129
|
+
const x = line[0]; // Staged status
|
|
130
|
+
const y = line[1]; // Unstaged status
|
|
131
|
+
let path = line.substring(3);
|
|
132
|
+
|
|
133
|
+
// Handle renamed files (format: "R old -> new")
|
|
134
|
+
if (path.includes(" -> ")) {
|
|
135
|
+
const splitPath = path.split(" -> ");
|
|
136
|
+
path = splitPath[1] ?? splitPath[0] ?? path;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// Check for conflicts (U or both A/A, D/D, etc.)
|
|
140
|
+
const isConflicted =
|
|
141
|
+
x === "U" ||
|
|
142
|
+
y === "U" ||
|
|
143
|
+
(x === "A" && y === "A") ||
|
|
144
|
+
(x === "D" && y === "D") ||
|
|
145
|
+
x === "A" && y === "U" ||
|
|
146
|
+
x === "U" && y === "A" ||
|
|
147
|
+
x === "D" && y === "U" ||
|
|
148
|
+
x === "U" && y === "D";
|
|
149
|
+
|
|
150
|
+
if (isConflicted) {
|
|
151
|
+
conflicted.push(path);
|
|
152
|
+
continue;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// Untracked files
|
|
156
|
+
if (x === "?" && y === "?") {
|
|
157
|
+
untracked.push(path);
|
|
158
|
+
continue;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// Staged changes (X is not space or ?)
|
|
162
|
+
if (x !== " " && x !== "?" && x !== "!") {
|
|
163
|
+
staged.push(path);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// Unstaged changes (Y is not space or ?)
|
|
167
|
+
if (y !== " " && y !== "?" && y !== "!") {
|
|
168
|
+
// Don't double-add if already in staged
|
|
169
|
+
if (!staged.includes(path)) {
|
|
170
|
+
unstaged.push(path);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
return { staged, unstaged, untracked, conflicted };
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Get comprehensive git status for a working directory
|
|
180
|
+
*
|
|
181
|
+
* @param workingDirectory - The directory to check git status for
|
|
182
|
+
* @returns GitStatus object if in a git repository, null otherwise
|
|
183
|
+
*/
|
|
184
|
+
export async function getGitStatus(
|
|
185
|
+
workingDirectory: string
|
|
186
|
+
): Promise<GitStatus | null> {
|
|
187
|
+
try {
|
|
188
|
+
// First check if this is a git repository
|
|
189
|
+
const isRepo = await isGitRepository(workingDirectory);
|
|
190
|
+
if (!isRepo) {
|
|
191
|
+
return null;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// Run all status queries in parallel for better performance
|
|
195
|
+
const [branch, aheadBehind, fileStatus] = await Promise.all([
|
|
196
|
+
getBranch(workingDirectory),
|
|
197
|
+
getAheadBehind(workingDirectory),
|
|
198
|
+
getFileStatus(workingDirectory),
|
|
199
|
+
]);
|
|
200
|
+
|
|
201
|
+
return {
|
|
202
|
+
branch,
|
|
203
|
+
ahead: aheadBehind.ahead,
|
|
204
|
+
behind: aheadBehind.behind,
|
|
205
|
+
staged: fileStatus.staged,
|
|
206
|
+
unstaged: fileStatus.unstaged,
|
|
207
|
+
untracked: fileStatus.untracked,
|
|
208
|
+
conflicted: fileStatus.conflicted,
|
|
209
|
+
};
|
|
210
|
+
} catch (error) {
|
|
211
|
+
// Log error for debugging but return null gracefully
|
|
212
|
+
console.error("Error getting git status:", error);
|
|
213
|
+
return null;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Check if there are any uncommitted changes
|
|
219
|
+
*/
|
|
220
|
+
export function hasUncommittedChanges(status: GitStatus): boolean {
|
|
221
|
+
return (
|
|
222
|
+
status.staged.length > 0 ||
|
|
223
|
+
status.unstaged.length > 0 ||
|
|
224
|
+
status.untracked.length > 0 ||
|
|
225
|
+
status.conflicted.length > 0
|
|
226
|
+
);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* Check if the repository is clean (no changes and synced with upstream)
|
|
231
|
+
*/
|
|
232
|
+
export function isRepositoryClean(status: GitStatus): boolean {
|
|
233
|
+
return !hasUncommittedChanges(status) && status.ahead === 0 && status.behind === 0;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* Get a human-readable summary of the git status
|
|
238
|
+
*/
|
|
239
|
+
export function getGitStatusSummary(status: GitStatus): string {
|
|
240
|
+
const parts: string[] = [];
|
|
241
|
+
|
|
242
|
+
parts.push(`branch: ${status.branch}`);
|
|
243
|
+
|
|
244
|
+
if (status.ahead > 0 || status.behind > 0) {
|
|
245
|
+
const sync: string[] = [];
|
|
246
|
+
if (status.ahead > 0) sync.push(`ahead ${status.ahead}`);
|
|
247
|
+
if (status.behind > 0) sync.push(`behind ${status.behind}`);
|
|
248
|
+
parts.push(`(${sync.join(", ")})`);
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
const changes: string[] = [];
|
|
252
|
+
if (status.staged.length > 0) changes.push(`${status.staged.length} staged`);
|
|
253
|
+
if (status.unstaged.length > 0) changes.push(`${status.unstaged.length} unstaged`);
|
|
254
|
+
if (status.untracked.length > 0) changes.push(`${status.untracked.length} untracked`);
|
|
255
|
+
if (status.conflicted.length > 0) changes.push(`${status.conflicted.length} conflicted`);
|
|
256
|
+
|
|
257
|
+
if (changes.length > 0) {
|
|
258
|
+
parts.push(`[${changes.join(", ")}]`);
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
return parts.join(" ");
|
|
262
|
+
}
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
import { test, expect, describe } from "bun:test";
|
|
2
|
+
import {
|
|
3
|
+
IMAGE_EXTENSIONS,
|
|
4
|
+
BINARY_EXCLUSIONS,
|
|
5
|
+
detectMimeType,
|
|
6
|
+
isImageExtension,
|
|
7
|
+
isBinaryExclusion,
|
|
8
|
+
readImageFile,
|
|
9
|
+
toImageBlock,
|
|
10
|
+
formatImageResult,
|
|
11
|
+
} from "./image.js";
|
|
12
|
+
import type { MediaType } from "../types/index.js";
|
|
13
|
+
|
|
14
|
+
describe("Image Extensions", () => {
|
|
15
|
+
test("IMAGE_EXTENSIONS contains supported formats", () => {
|
|
16
|
+
expect(IMAGE_EXTENSIONS.has("png")).toBe(true);
|
|
17
|
+
expect(IMAGE_EXTENSIONS.has("jpg")).toBe(true);
|
|
18
|
+
expect(IMAGE_EXTENSIONS.has("jpeg")).toBe(true);
|
|
19
|
+
expect(IMAGE_EXTENSIONS.has("gif")).toBe(true);
|
|
20
|
+
expect(IMAGE_EXTENSIONS.has("webp")).toBe(true);
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
test("IMAGE_EXTENSIONS does not contain unsupported formats", () => {
|
|
24
|
+
expect(IMAGE_EXTENSIONS.has("bmp")).toBe(false);
|
|
25
|
+
expect(IMAGE_EXTENSIONS.has("svg")).toBe(false);
|
|
26
|
+
expect(IMAGE_EXTENSIONS.has("pdf")).toBe(false);
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
describe("Binary Exclusions", () => {
|
|
31
|
+
test("BINARY_EXCLUSIONS contains common binary formats", () => {
|
|
32
|
+
expect(BINARY_EXCLUSIONS.has("exe")).toBe(true);
|
|
33
|
+
expect(BINARY_EXCLUSIONS.has("zip")).toBe(true);
|
|
34
|
+
expect(BINARY_EXCLUSIONS.has("mp4")).toBe(true);
|
|
35
|
+
expect(BINARY_EXCLUSIONS.has("doc")).toBe(true);
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
test("PDF is NOT in binary exclusions (handled separately)", () => {
|
|
39
|
+
// PDF files can be read with page limits, not in exclusions
|
|
40
|
+
expect(BINARY_EXCLUSIONS.has("pdf")).toBe(false);
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
describe("isImageExtension", () => {
|
|
45
|
+
test("returns true for image extensions", () => {
|
|
46
|
+
expect(isImageExtension("png")).toBe(true);
|
|
47
|
+
expect(isImageExtension("jpg")).toBe(true);
|
|
48
|
+
expect(isImageExtension(".jpeg")).toBe(true);
|
|
49
|
+
expect(isImageExtension("GIF")).toBe(true);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
test("returns false for non-image extensions", () => {
|
|
53
|
+
expect(isImageExtension("txt")).toBe(false);
|
|
54
|
+
expect(isImageExtension("pdf")).toBe(false);
|
|
55
|
+
expect(isImageExtension("exe")).toBe(false);
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
describe("isBinaryExclusion", () => {
|
|
60
|
+
test("returns true for binary exclusions", () => {
|
|
61
|
+
expect(isBinaryExclusion("exe")).toBe(true);
|
|
62
|
+
expect(isBinaryExclusion("zip")).toBe(true);
|
|
63
|
+
expect(isBinaryExclusion("mp4")).toBe(true);
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
test("returns false for text files", () => {
|
|
67
|
+
expect(isBinaryExclusion("txt")).toBe(false);
|
|
68
|
+
expect(isBinaryExclusion("md")).toBe(false);
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
describe("detectMimeType", () => {
|
|
73
|
+
test("detects PNG magic bytes", () => {
|
|
74
|
+
// PNG magic bytes: 89 50 4E 47
|
|
75
|
+
const pngHeader = Buffer.from([0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A]);
|
|
76
|
+
expect(detectMimeType(pngHeader)).toBe("image/png");
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
test("detects JPEG magic bytes", () => {
|
|
80
|
+
// JPEG magic bytes: FF D8 FF
|
|
81
|
+
const jpegHeader = Buffer.from([0xFF, 0xD8, 0xFF, 0xE0, 0x00, 0x10]);
|
|
82
|
+
expect(detectMimeType(jpegHeader)).toBe("image/jpeg");
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
test("detects GIF magic bytes", () => {
|
|
86
|
+
// GIF magic bytes: 47 49 46 38
|
|
87
|
+
const gifHeader = Buffer.from([0x47, 0x49, 0x46, 0x38, 0x39, 0x61]);
|
|
88
|
+
expect(detectMimeType(gifHeader)).toBe("image/gif");
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
test("detects WEBP magic bytes", () => {
|
|
92
|
+
// WEBP: RIFF....WEBP
|
|
93
|
+
const webpHeader = Buffer.from([
|
|
94
|
+
0x52, 0x49, 0x46, 0x46, // RIFF
|
|
95
|
+
0x00, 0x00, 0x00, 0x00, // size
|
|
96
|
+
0x57, 0x45, 0x42, 0x50, // WEBP
|
|
97
|
+
]);
|
|
98
|
+
expect(detectMimeType(webpHeader)).toBe("image/webp");
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
test("returns null for unknown data", () => {
|
|
102
|
+
const unknownData = Buffer.from([0x00, 0x01, 0x02, 0x03]);
|
|
103
|
+
expect(detectMimeType(unknownData)).toBe(null);
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
test("returns null for empty buffer", () => {
|
|
107
|
+
expect(detectMimeType(Buffer.alloc(0))).toBe(null);
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
describe("toImageBlock", () => {
|
|
112
|
+
test("converts ImageFileResult to ImageBlock", () => {
|
|
113
|
+
const result = {
|
|
114
|
+
type: "image" as const,
|
|
115
|
+
base64: "dGVzdCBkYXRh", // "test data" in base64
|
|
116
|
+
mediaType: "image/png" as MediaType,
|
|
117
|
+
originalSize: 1000,
|
|
118
|
+
dimensions: {
|
|
119
|
+
originalWidth: 100,
|
|
120
|
+
originalHeight: 100,
|
|
121
|
+
displayWidth: 100,
|
|
122
|
+
displayHeight: 100,
|
|
123
|
+
},
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
const block = toImageBlock(result);
|
|
127
|
+
|
|
128
|
+
expect(block.type).toBe("image");
|
|
129
|
+
expect(block.source.type).toBe("base64");
|
|
130
|
+
expect(block.source.data).toBe("dGVzdCBkYXRh");
|
|
131
|
+
expect(block.source.media_type).toBe("image/png");
|
|
132
|
+
});
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
describe("formatImageResult", () => {
|
|
136
|
+
test("formats image result with dimensions", () => {
|
|
137
|
+
const result = {
|
|
138
|
+
type: "image" as const,
|
|
139
|
+
base64: "dGVzdA==",
|
|
140
|
+
mediaType: "image/png" as MediaType,
|
|
141
|
+
originalSize: 1024,
|
|
142
|
+
dimensions: {
|
|
143
|
+
originalWidth: 100,
|
|
144
|
+
originalHeight: 200,
|
|
145
|
+
displayWidth: 100,
|
|
146
|
+
displayHeight: 200,
|
|
147
|
+
},
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
const formatted = formatImageResult(result);
|
|
151
|
+
expect(formatted).toContain("image/png");
|
|
152
|
+
expect(formatted).toContain("100x200");
|
|
153
|
+
expect(formatted).toContain("1.0KB");
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
test("formats image result without dimensions", () => {
|
|
157
|
+
const result = {
|
|
158
|
+
type: "image" as const,
|
|
159
|
+
base64: "dGVzdA==",
|
|
160
|
+
mediaType: "image/jpeg" as MediaType,
|
|
161
|
+
originalSize: 2048,
|
|
162
|
+
dimensions: {},
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
const formatted = formatImageResult(result);
|
|
166
|
+
expect(formatted).toContain("image/jpeg");
|
|
167
|
+
expect(formatted).toContain("2.0KB");
|
|
168
|
+
});
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
describe("readImageFile", () => {
|
|
172
|
+
test("throws error for non-existent file", async () => {
|
|
173
|
+
try {
|
|
174
|
+
await readImageFile("/non/existent/file.png");
|
|
175
|
+
expect(true).toBe(false); // Should not reach here
|
|
176
|
+
} catch (error) {
|
|
177
|
+
expect(error).toBeDefined();
|
|
178
|
+
}
|
|
179
|
+
});
|
|
180
|
+
});
|