@ebowwa/coder 0.7.63 → 0.7.64
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 +32 -52192
- 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 +159 -52768
- 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/index.d.ts +480 -0
- package/dist/native/index.d.ts.map +1 -0
- package/dist/native/index.js +1625 -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/package.json +4 -2
- package/packages/src/core/__tests__/permissions.test.ts +1091 -0
- package/packages/src/core/agent-loop/__tests__/compaction.test.ts +280 -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 +88 -0
- package/packages/src/core/agent-loop/formatters.ts +50 -0
- package/packages/src/core/agent-loop/index.ts +135 -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 +222 -0
- package/packages/src/core/agent-loop/types.ts +148 -0
- package/packages/src/core/agent-loop.ts +18 -0
- package/packages/src/core/api-client-impl.ts +619 -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 +590 -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-loader.ts +324 -0
- package/packages/src/core/context-compaction.ts +578 -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 +430 -0
- package/packages/src/core/normalizers/todo +4 -0
- package/packages/src/core/permissions.ts +431 -0
- package/packages/src/core/retry.ts +170 -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 +1877 -0
- package/packages/src/index.ts +120 -0
- package/packages/src/interfaces/mcp/client.ts +389 -0
- package/packages/src/interfaces/ui/Screenshot 2026-03-02 at 9.23.10/342/200/257PM.png +0 -0
- package/packages/src/interfaces/ui/Screenshot 2026-03-03 at 10.55.11/342/200/257AM.png +0 -0
- package/packages/src/interfaces/ui/index.ts +161 -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/cli/index.ts +228 -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 +71 -0
- package/packages/src/interfaces/ui/terminal/shared/loading-state.ts +322 -0
- package/packages/src/interfaces/ui/terminal/shared/query.ts +146 -0
- package/packages/src/interfaces/ui/terminal/shared/setup.ts +295 -0
- package/packages/src/interfaces/ui/terminal/shared/status-line.ts +358 -0
- package/packages/src/interfaces/ui/terminal/shared/system-prompt.ts +146 -0
- package/packages/src/interfaces/ui/terminal/tui/HelpPanel.tsx +262 -0
- package/packages/src/interfaces/ui/terminal/tui/InputContext.tsx +232 -0
- package/packages/src/interfaces/ui/terminal/tui/InputField.tsx +62 -0
- package/packages/src/interfaces/ui/terminal/tui/InteractiveTUI.tsx +537 -0
- package/packages/src/interfaces/ui/terminal/tui/MessageArea.tsx +107 -0
- package/packages/src/interfaces/ui/terminal/tui/MessageStore.tsx +240 -0
- package/packages/src/interfaces/ui/terminal/tui/StatusBar.tsx +54 -0
- package/packages/src/interfaces/ui/terminal/tui/commands.ts +438 -0
- package/packages/src/interfaces/ui/terminal/tui/components/InteractiveElements.tsx +584 -0
- package/packages/src/interfaces/ui/terminal/tui/components/MultilineInput.tsx +614 -0
- package/packages/src/interfaces/ui/terminal/tui/components/PaneManager.tsx +333 -0
- package/packages/src/interfaces/ui/terminal/tui/components/Sidebar.tsx +604 -0
- package/packages/src/interfaces/ui/terminal/tui/components/index.ts +118 -0
- package/packages/src/interfaces/ui/terminal/tui/console.ts +49 -0
- package/packages/src/interfaces/ui/terminal/tui/index.ts +90 -0
- package/packages/src/interfaces/ui/terminal/tui/run.tsx +42 -0
- package/packages/src/interfaces/ui/terminal/tui/spinner.ts +69 -0
- package/packages/src/interfaces/ui/terminal/tui/tui-app.tsx +390 -0
- package/packages/src/interfaces/ui/terminal/tui/tui-footer.ts +422 -0
- package/packages/src/interfaces/ui/terminal/tui/types.ts +186 -0
- package/packages/src/interfaces/ui/terminal/tui/useInputHandler.ts +104 -0
- package/packages/src/interfaces/ui/terminal/tui/useNativeInput.ts +239 -0
- package/packages/src/lmdb.db +0 -0
- package/packages/src/lmdb.db-lock +0 -0
- package/packages/src/native/index.ts +2345 -0
- package/packages/src/teammates/index.ts +982 -0
- package/packages/src/types/index.ts +722 -0
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Image Processing Module
|
|
3
|
+
*/
|
|
4
|
+
import type { MediaType, ImageBlock } from "../types/index.js";
|
|
5
|
+
/**
|
|
6
|
+
* Supported image extensions
|
|
7
|
+
*/
|
|
8
|
+
export declare const IMAGE_EXTENSIONS: Set<string>;
|
|
9
|
+
/**
|
|
10
|
+
* Binary file exclusions (CI8 set in binary)
|
|
11
|
+
* These are NOT processed as images - treated as binary
|
|
12
|
+
*/
|
|
13
|
+
export declare const BINARY_EXCLUSIONS: Set<string>;
|
|
14
|
+
/**
|
|
15
|
+
* Size limits (from binary)
|
|
16
|
+
*/
|
|
17
|
+
export declare const MAX_IMAGE_TOKENS = 25000;
|
|
18
|
+
export declare const MAX_FILE_SIZE = 5242880;
|
|
19
|
+
export declare const MAX_DIMENSION = 3932160;
|
|
20
|
+
/**
|
|
21
|
+
* Resize fallback settings (from binary)
|
|
22
|
+
*/
|
|
23
|
+
export declare const FALLBACK_MAX_DIMENSION = 400;
|
|
24
|
+
export declare const FALLBACK_JPEG_QUALITY = 20;
|
|
25
|
+
/**
|
|
26
|
+
* Detect MIME type from file magic bytes (ObT function in binary)
|
|
27
|
+
* Not just extension-based - inspects file header
|
|
28
|
+
*/
|
|
29
|
+
export declare function detectMimeType(bytes: Buffer): MediaType | null;
|
|
30
|
+
export interface ImageFileResult {
|
|
31
|
+
type: "image";
|
|
32
|
+
base64: string;
|
|
33
|
+
mediaType: MediaType;
|
|
34
|
+
originalSize: number;
|
|
35
|
+
dimensions?: {
|
|
36
|
+
originalWidth?: number;
|
|
37
|
+
originalHeight?: number;
|
|
38
|
+
displayWidth?: number;
|
|
39
|
+
displayHeight?: number;
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Read and process an image file (bwA function in binary)
|
|
44
|
+
*
|
|
45
|
+
* Flow:
|
|
46
|
+
* 1. Read file as bytes
|
|
47
|
+
* 2. Detect MIME type from magic bytes
|
|
48
|
+
* 3. Process with sharp library
|
|
49
|
+
* 4. Check token limit and resize if needed
|
|
50
|
+
* 5. Return base64-encoded result
|
|
51
|
+
*/
|
|
52
|
+
export declare function readImageFile(filePath: string, maxTokens?: number, signal?: AbortSignal): Promise<ImageFileResult>;
|
|
53
|
+
/**
|
|
54
|
+
* Check if a file extension is a supported image
|
|
55
|
+
*/
|
|
56
|
+
export declare function isImageExtension(extension: string): boolean;
|
|
57
|
+
/**
|
|
58
|
+
* Check if a file extension should be treated as binary (not image)
|
|
59
|
+
*/
|
|
60
|
+
export declare function isBinaryExclusion(extension: string): boolean;
|
|
61
|
+
/**
|
|
62
|
+
* Convert ImageFileResult to API ImageBlock format
|
|
63
|
+
*/
|
|
64
|
+
export declare function toImageBlock(result: ImageFileResult): ImageBlock;
|
|
65
|
+
/**
|
|
66
|
+
* Format image result for tool output
|
|
67
|
+
*/
|
|
68
|
+
export declare function formatImageResult(result: ImageFileResult): string;
|
|
69
|
+
//# sourceMappingURL=image.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"image.d.ts","sourceRoot":"","sources":["../../packages/src/core/image.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAM/D;;GAEG;AACH,eAAO,MAAM,gBAAgB,aAAiD,CAAC;AAE/E;;;GAGG;AACH,eAAO,MAAM,iBAAiB,aAsB5B,CAAC;AAEH;;GAEG;AACH,eAAO,MAAM,gBAAgB,QAAQ,CAAC;AACtC,eAAO,MAAM,aAAa,UAAU,CAAC;AACrC,eAAO,MAAM,aAAa,UAAU,CAAC;AAErC;;GAEG;AACH,eAAO,MAAM,sBAAsB,MAAM,CAAC;AAC1C,eAAO,MAAM,qBAAqB,KAAK,CAAC;AAoBxC;;;GAGG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CA0B9D;AAMD,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,OAAO,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,SAAS,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE;QACX,aAAa,CAAC,EAAE,MAAM,CAAC;QACvB,cAAc,CAAC,EAAE,MAAM,CAAC;QACxB,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,aAAa,CAAC,EAAE,MAAM,CAAC;KACxB,CAAC;CACH;AAED;;;;;;;;;GASG;AACH,wBAAsB,aAAa,CACjC,QAAQ,EAAE,MAAM,EAChB,SAAS,GAAE,MAAyB,EACpC,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,eAAe,CAAC,CAmI1B;AAwCD;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAG3D;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAG5D;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,eAAe,GAAG,UAAU,CAShE;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,eAAe,GAAG,MAAM,CAOjE"}
|
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Image Processing Module
|
|
3
|
+
*/
|
|
4
|
+
import sharp from "sharp";
|
|
5
|
+
// ============================================
|
|
6
|
+
// CONSTANTS
|
|
7
|
+
// ============================================
|
|
8
|
+
/**
|
|
9
|
+
* Supported image extensions
|
|
10
|
+
*/
|
|
11
|
+
export const IMAGE_EXTENSIONS = new Set(["png", "jpg", "jpeg", "gif", "webp"]);
|
|
12
|
+
/**
|
|
13
|
+
* Binary file exclusions (CI8 set in binary)
|
|
14
|
+
* These are NOT processed as images - treated as binary
|
|
15
|
+
*/
|
|
16
|
+
export const BINARY_EXCLUSIONS = new Set([
|
|
17
|
+
// Audio/Video
|
|
18
|
+
"mp3", "wav", "flac", "ogg", "aac", "m4a", "wma", "aiff", "opus",
|
|
19
|
+
"mp4", "avi", "mov", "wmv", "flv", "mkv", "webm", "m4v", "mpeg", "mpg",
|
|
20
|
+
// Archives
|
|
21
|
+
"zip", "rar", "tar", "gz", "bz2", "7z", "xz", "z", "tgz", "iso",
|
|
22
|
+
// Executables
|
|
23
|
+
"exe", "dll", "so", "dylib", "app", "msi", "deb", "rpm", "bin",
|
|
24
|
+
// Databases
|
|
25
|
+
"dat", "db", "sqlite", "sqlite3", "mdb", "idx",
|
|
26
|
+
// Documents
|
|
27
|
+
"doc", "docx", "xls", "xlsx", "ppt", "pptx", "odt", "ods", "odp",
|
|
28
|
+
// Fonts
|
|
29
|
+
"ttf", "otf", "woff", "woff2", "eot",
|
|
30
|
+
// Design files
|
|
31
|
+
"psd", "ai", "eps", "sketch", "fig", "xd",
|
|
32
|
+
// 3D
|
|
33
|
+
"blend", "obj", "3ds", "max",
|
|
34
|
+
// Compiled code
|
|
35
|
+
"class", "jar", "war", "pyc", "pyo", "rlib",
|
|
36
|
+
// Other
|
|
37
|
+
"swf", "fla"
|
|
38
|
+
]);
|
|
39
|
+
/**
|
|
40
|
+
* Size limits (from binary)
|
|
41
|
+
*/
|
|
42
|
+
export const MAX_IMAGE_TOKENS = 25000; // muA() default
|
|
43
|
+
export const MAX_FILE_SIZE = 5242880; // 5MB a2T
|
|
44
|
+
export const MAX_DIMENSION = 3932160; // MP total pixels
|
|
45
|
+
/**
|
|
46
|
+
* Resize fallback settings (from binary)
|
|
47
|
+
*/
|
|
48
|
+
export const FALLBACK_MAX_DIMENSION = 400;
|
|
49
|
+
export const FALLBACK_JPEG_QUALITY = 20;
|
|
50
|
+
// ============================================
|
|
51
|
+
// MIME TYPE DETECTION (ObT function in binary)
|
|
52
|
+
// ============================================
|
|
53
|
+
/**
|
|
54
|
+
* Magic byte signatures for image formats
|
|
55
|
+
*/
|
|
56
|
+
const MAGIC_SIGNATURES = [
|
|
57
|
+
// PNG: 89 50 4E 47
|
|
58
|
+
{ signature: [0x89, 0x50, 0x4E, 0x47], mimeType: "image/png" },
|
|
59
|
+
// JPEG: FF D8 FF
|
|
60
|
+
{ signature: [0xFF, 0xD8, 0xFF], mimeType: "image/jpeg" },
|
|
61
|
+
// GIF: 47 49 46 38
|
|
62
|
+
{ signature: [0x47, 0x49, 0x46, 0x38], mimeType: "image/gif" },
|
|
63
|
+
// WEBP: 52 49 46 46 ... 57 45 42 50 (at offset 8)
|
|
64
|
+
{ signature: [0x52, 0x49, 0x46, 0x46], mimeType: "image/webp" },
|
|
65
|
+
];
|
|
66
|
+
/**
|
|
67
|
+
* Detect MIME type from file magic bytes (ObT function in binary)
|
|
68
|
+
* Not just extension-based - inspects file header
|
|
69
|
+
*/
|
|
70
|
+
export function detectMimeType(bytes) {
|
|
71
|
+
if (bytes.length < 4)
|
|
72
|
+
return null;
|
|
73
|
+
for (const { signature, mimeType } of MAGIC_SIGNATURES) {
|
|
74
|
+
let matches = true;
|
|
75
|
+
for (let i = 0; i < signature.length; i++) {
|
|
76
|
+
if (bytes[i] !== signature[i]) {
|
|
77
|
+
matches = false;
|
|
78
|
+
break;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
if (matches) {
|
|
82
|
+
// Special case for WEBP - verify RIFF...WEBP pattern
|
|
83
|
+
if (mimeType === "image/webp") {
|
|
84
|
+
if (bytes.length >= 12 &&
|
|
85
|
+
bytes[8] === 0x57 && bytes[9] === 0x45 &&
|
|
86
|
+
bytes[10] === 0x42 && bytes[11] === 0x50) {
|
|
87
|
+
return "image/webp";
|
|
88
|
+
}
|
|
89
|
+
continue;
|
|
90
|
+
}
|
|
91
|
+
return mimeType;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return null;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Read and process an image file (bwA function in binary)
|
|
98
|
+
*
|
|
99
|
+
* Flow:
|
|
100
|
+
* 1. Read file as bytes
|
|
101
|
+
* 2. Detect MIME type from magic bytes
|
|
102
|
+
* 3. Process with sharp library
|
|
103
|
+
* 4. Check token limit and resize if needed
|
|
104
|
+
* 5. Return base64-encoded result
|
|
105
|
+
*/
|
|
106
|
+
export async function readImageFile(filePath, maxTokens = MAX_IMAGE_TOKENS, signal) {
|
|
107
|
+
// 1. Read file as bytes
|
|
108
|
+
const file = Bun.file(filePath);
|
|
109
|
+
const bytes = Buffer.from(await file.arrayBuffer());
|
|
110
|
+
if (bytes.length === 0) {
|
|
111
|
+
throw new Error(`Image file is empty: ${filePath}`);
|
|
112
|
+
}
|
|
113
|
+
// Check file size limit
|
|
114
|
+
if (bytes.length > MAX_FILE_SIZE) {
|
|
115
|
+
throw new Error(`Image file too large: ${filePath} (${(bytes.length / 1024 / 1024).toFixed(2)}MB > 5MB limit)`);
|
|
116
|
+
}
|
|
117
|
+
// 2. Detect MIME type from magic bytes (ObT function)
|
|
118
|
+
const detectedMimeType = detectMimeType(bytes);
|
|
119
|
+
if (!detectedMimeType) {
|
|
120
|
+
throw new Error(`Unsupported image format: ${filePath}`);
|
|
121
|
+
}
|
|
122
|
+
// 3. Process with sharp library
|
|
123
|
+
let image = sharp(bytes);
|
|
124
|
+
const metadata = await image.metadata();
|
|
125
|
+
const dimensions = {
|
|
126
|
+
originalWidth: metadata.width,
|
|
127
|
+
originalHeight: metadata.height,
|
|
128
|
+
};
|
|
129
|
+
// Check dimension limits
|
|
130
|
+
const totalPixels = (metadata.width || 0) * (metadata.height || 0);
|
|
131
|
+
if (totalPixels > MAX_DIMENSION) {
|
|
132
|
+
// Need to resize
|
|
133
|
+
const scale = Math.sqrt(MAX_DIMENSION / totalPixels);
|
|
134
|
+
const newWidth = Math.round((metadata.width || 1) * scale);
|
|
135
|
+
const newHeight = Math.round((metadata.height || 1) * scale);
|
|
136
|
+
image = sharp(bytes).resize(newWidth, newHeight, {
|
|
137
|
+
fit: "inside",
|
|
138
|
+
withoutEnlargement: true,
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
// 4. Get processed buffer
|
|
142
|
+
let outputFormat = metadata.format || "jpeg";
|
|
143
|
+
let outputBuffer;
|
|
144
|
+
// Determine output format based on input
|
|
145
|
+
if (outputFormat === "png") {
|
|
146
|
+
outputBuffer = await image.png().toBuffer();
|
|
147
|
+
}
|
|
148
|
+
else if (outputFormat === "webp") {
|
|
149
|
+
outputBuffer = await image.webp().toBuffer();
|
|
150
|
+
}
|
|
151
|
+
else if (outputFormat === "gif") {
|
|
152
|
+
outputBuffer = await image.gif().toBuffer();
|
|
153
|
+
}
|
|
154
|
+
else {
|
|
155
|
+
// Default to JPEG for everything else
|
|
156
|
+
outputBuffer = await image.jpeg({ quality: 85 }).toBuffer();
|
|
157
|
+
outputFormat = "jpeg";
|
|
158
|
+
}
|
|
159
|
+
// 5. Check token limit and resize if needed
|
|
160
|
+
const base64 = outputBuffer.toString("base64");
|
|
161
|
+
const estimatedTokens = Math.ceil(base64.length * 0.125);
|
|
162
|
+
if (estimatedTokens > maxTokens) {
|
|
163
|
+
// Resize to fit within token limit
|
|
164
|
+
try {
|
|
165
|
+
const resizedBuffer = await resizeForTokenLimit(bytes, maxTokens);
|
|
166
|
+
const resizedBase64 = resizedBuffer.toString("base64");
|
|
167
|
+
// Get final dimensions
|
|
168
|
+
const finalMeta = await sharp(resizedBuffer).metadata();
|
|
169
|
+
return {
|
|
170
|
+
type: "image",
|
|
171
|
+
base64: resizedBase64,
|
|
172
|
+
mediaType: "image/jpeg", // Resized images are always JPEG
|
|
173
|
+
originalSize: bytes.length,
|
|
174
|
+
dimensions: {
|
|
175
|
+
originalWidth: metadata.width,
|
|
176
|
+
originalHeight: metadata.height,
|
|
177
|
+
displayWidth: finalMeta.width,
|
|
178
|
+
displayHeight: finalMeta.height,
|
|
179
|
+
},
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
catch (resizeErr) {
|
|
183
|
+
// Final fallback: aggressive resize with sharp
|
|
184
|
+
const smallImage = await sharp(bytes)
|
|
185
|
+
.resize(FALLBACK_MAX_DIMENSION, FALLBACK_MAX_DIMENSION, {
|
|
186
|
+
fit: "inside",
|
|
187
|
+
withoutEnlargement: true,
|
|
188
|
+
})
|
|
189
|
+
.jpeg({ quality: FALLBACK_JPEG_QUALITY })
|
|
190
|
+
.toBuffer();
|
|
191
|
+
const finalMeta = await sharp(smallImage).metadata();
|
|
192
|
+
return {
|
|
193
|
+
type: "image",
|
|
194
|
+
base64: smallImage.toString("base64"),
|
|
195
|
+
mediaType: "image/jpeg",
|
|
196
|
+
originalSize: bytes.length,
|
|
197
|
+
dimensions: {
|
|
198
|
+
originalWidth: metadata.width,
|
|
199
|
+
originalHeight: metadata.height,
|
|
200
|
+
displayWidth: finalMeta.width,
|
|
201
|
+
displayHeight: finalMeta.height,
|
|
202
|
+
},
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
// Map format to MediaType
|
|
207
|
+
const mediaType = outputFormat === "jpeg" ? "image/jpeg" :
|
|
208
|
+
outputFormat === "png" ? "image/png" :
|
|
209
|
+
outputFormat === "gif" ? "image/gif" :
|
|
210
|
+
outputFormat === "webp" ? "image/webp" :
|
|
211
|
+
"image/jpeg";
|
|
212
|
+
return {
|
|
213
|
+
type: "image",
|
|
214
|
+
base64,
|
|
215
|
+
mediaType,
|
|
216
|
+
originalSize: bytes.length,
|
|
217
|
+
dimensions: {
|
|
218
|
+
originalWidth: metadata.width,
|
|
219
|
+
originalHeight: metadata.height,
|
|
220
|
+
displayWidth: metadata.width,
|
|
221
|
+
displayHeight: metadata.height,
|
|
222
|
+
},
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* Resize image to fit within token limit
|
|
227
|
+
*/
|
|
228
|
+
async function resizeForTokenLimit(bytes, maxTokens) {
|
|
229
|
+
// Target ~80% of max tokens for safety margin
|
|
230
|
+
const targetBase64Length = Math.floor((maxTokens * 0.8) / 0.125);
|
|
231
|
+
const targetBufferSize = Math.floor(targetBase64Length * 0.75); // base64 is ~4/3 of binary
|
|
232
|
+
const image = sharp(bytes);
|
|
233
|
+
const metadata = await image.metadata();
|
|
234
|
+
// Calculate scale factor needed
|
|
235
|
+
const currentSize = bytes.length;
|
|
236
|
+
if (currentSize <= targetBufferSize) {
|
|
237
|
+
return bytes;
|
|
238
|
+
}
|
|
239
|
+
const scaleFactor = Math.sqrt(targetBufferSize / currentSize);
|
|
240
|
+
const newWidth = Math.round((metadata.width || 1) * scaleFactor);
|
|
241
|
+
const newHeight = Math.round((metadata.height || 1) * scaleFactor);
|
|
242
|
+
// Resize and convert to JPEG
|
|
243
|
+
return sharp(bytes)
|
|
244
|
+
.resize(newWidth, newHeight, {
|
|
245
|
+
fit: "inside",
|
|
246
|
+
withoutEnlargement: true,
|
|
247
|
+
})
|
|
248
|
+
.jpeg({ quality: 70 })
|
|
249
|
+
.toBuffer();
|
|
250
|
+
}
|
|
251
|
+
// ============================================
|
|
252
|
+
// HELPER FUNCTIONS
|
|
253
|
+
// ============================================
|
|
254
|
+
/**
|
|
255
|
+
* Check if a file extension is a supported image
|
|
256
|
+
*/
|
|
257
|
+
export function isImageExtension(extension) {
|
|
258
|
+
const ext = extension.toLowerCase().replace(/^\./, "");
|
|
259
|
+
return IMAGE_EXTENSIONS.has(ext);
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
262
|
+
* Check if a file extension should be treated as binary (not image)
|
|
263
|
+
*/
|
|
264
|
+
export function isBinaryExclusion(extension) {
|
|
265
|
+
const ext = extension.toLowerCase().replace(/^\./, "");
|
|
266
|
+
return BINARY_EXCLUSIONS.has(ext);
|
|
267
|
+
}
|
|
268
|
+
/**
|
|
269
|
+
* Convert ImageFileResult to API ImageBlock format
|
|
270
|
+
*/
|
|
271
|
+
export function toImageBlock(result) {
|
|
272
|
+
return {
|
|
273
|
+
type: "image",
|
|
274
|
+
source: {
|
|
275
|
+
type: "base64",
|
|
276
|
+
data: result.base64,
|
|
277
|
+
media_type: result.mediaType,
|
|
278
|
+
},
|
|
279
|
+
};
|
|
280
|
+
}
|
|
281
|
+
/**
|
|
282
|
+
* Format image result for tool output
|
|
283
|
+
*/
|
|
284
|
+
export function formatImageResult(result) {
|
|
285
|
+
const dims = result.dimensions;
|
|
286
|
+
const dimStr = dims?.originalWidth && dims?.originalHeight
|
|
287
|
+
? ` (${dims.originalWidth}x${dims.originalHeight}${dims.displayWidth !== dims.originalWidth ? ` → ${dims.displayWidth}x${dims.displayHeight}` : ''})`
|
|
288
|
+
: '';
|
|
289
|
+
return `[Image: ${result.mediaType}${dimStr}, ${(result.originalSize / 1024).toFixed(1)}KB original]`;
|
|
290
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"image.test.d.ts","sourceRoot":"","sources":["../../packages/src/core/image.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import { test, expect, describe } from "bun:test";
|
|
2
|
+
import { IMAGE_EXTENSIONS, BINARY_EXCLUSIONS, detectMimeType, isImageExtension, isBinaryExclusion, readImageFile, toImageBlock, formatImageResult, } from "./image.js";
|
|
3
|
+
describe("Image Extensions", () => {
|
|
4
|
+
test("IMAGE_EXTENSIONS contains supported formats", () => {
|
|
5
|
+
expect(IMAGE_EXTENSIONS.has("png")).toBe(true);
|
|
6
|
+
expect(IMAGE_EXTENSIONS.has("jpg")).toBe(true);
|
|
7
|
+
expect(IMAGE_EXTENSIONS.has("jpeg")).toBe(true);
|
|
8
|
+
expect(IMAGE_EXTENSIONS.has("gif")).toBe(true);
|
|
9
|
+
expect(IMAGE_EXTENSIONS.has("webp")).toBe(true);
|
|
10
|
+
});
|
|
11
|
+
test("IMAGE_EXTENSIONS does not contain unsupported formats", () => {
|
|
12
|
+
expect(IMAGE_EXTENSIONS.has("bmp")).toBe(false);
|
|
13
|
+
expect(IMAGE_EXTENSIONS.has("svg")).toBe(false);
|
|
14
|
+
expect(IMAGE_EXTENSIONS.has("pdf")).toBe(false);
|
|
15
|
+
});
|
|
16
|
+
});
|
|
17
|
+
describe("Binary Exclusions", () => {
|
|
18
|
+
test("BINARY_EXCLUSIONS contains common binary formats", () => {
|
|
19
|
+
expect(BINARY_EXCLUSIONS.has("exe")).toBe(true);
|
|
20
|
+
expect(BINARY_EXCLUSIONS.has("zip")).toBe(true);
|
|
21
|
+
expect(BINARY_EXCLUSIONS.has("mp4")).toBe(true);
|
|
22
|
+
expect(BINARY_EXCLUSIONS.has("doc")).toBe(true);
|
|
23
|
+
});
|
|
24
|
+
test("PDF is NOT in binary exclusions (handled separately)", () => {
|
|
25
|
+
// PDF files can be read with page limits, not in exclusions
|
|
26
|
+
expect(BINARY_EXCLUSIONS.has("pdf")).toBe(false);
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
describe("isImageExtension", () => {
|
|
30
|
+
test("returns true for image extensions", () => {
|
|
31
|
+
expect(isImageExtension("png")).toBe(true);
|
|
32
|
+
expect(isImageExtension("jpg")).toBe(true);
|
|
33
|
+
expect(isImageExtension(".jpeg")).toBe(true);
|
|
34
|
+
expect(isImageExtension("GIF")).toBe(true);
|
|
35
|
+
});
|
|
36
|
+
test("returns false for non-image extensions", () => {
|
|
37
|
+
expect(isImageExtension("txt")).toBe(false);
|
|
38
|
+
expect(isImageExtension("pdf")).toBe(false);
|
|
39
|
+
expect(isImageExtension("exe")).toBe(false);
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
describe("isBinaryExclusion", () => {
|
|
43
|
+
test("returns true for binary exclusions", () => {
|
|
44
|
+
expect(isBinaryExclusion("exe")).toBe(true);
|
|
45
|
+
expect(isBinaryExclusion("zip")).toBe(true);
|
|
46
|
+
expect(isBinaryExclusion("mp4")).toBe(true);
|
|
47
|
+
});
|
|
48
|
+
test("returns false for text files", () => {
|
|
49
|
+
expect(isBinaryExclusion("txt")).toBe(false);
|
|
50
|
+
expect(isBinaryExclusion("md")).toBe(false);
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
describe("detectMimeType", () => {
|
|
54
|
+
test("detects PNG magic bytes", () => {
|
|
55
|
+
// PNG magic bytes: 89 50 4E 47
|
|
56
|
+
const pngHeader = Buffer.from([0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A]);
|
|
57
|
+
expect(detectMimeType(pngHeader)).toBe("image/png");
|
|
58
|
+
});
|
|
59
|
+
test("detects JPEG magic bytes", () => {
|
|
60
|
+
// JPEG magic bytes: FF D8 FF
|
|
61
|
+
const jpegHeader = Buffer.from([0xFF, 0xD8, 0xFF, 0xE0, 0x00, 0x10]);
|
|
62
|
+
expect(detectMimeType(jpegHeader)).toBe("image/jpeg");
|
|
63
|
+
});
|
|
64
|
+
test("detects GIF magic bytes", () => {
|
|
65
|
+
// GIF magic bytes: 47 49 46 38
|
|
66
|
+
const gifHeader = Buffer.from([0x47, 0x49, 0x46, 0x38, 0x39, 0x61]);
|
|
67
|
+
expect(detectMimeType(gifHeader)).toBe("image/gif");
|
|
68
|
+
});
|
|
69
|
+
test("detects WEBP magic bytes", () => {
|
|
70
|
+
// WEBP: RIFF....WEBP
|
|
71
|
+
const webpHeader = Buffer.from([
|
|
72
|
+
0x52, 0x49, 0x46, 0x46, // RIFF
|
|
73
|
+
0x00, 0x00, 0x00, 0x00, // size
|
|
74
|
+
0x57, 0x45, 0x42, 0x50, // WEBP
|
|
75
|
+
]);
|
|
76
|
+
expect(detectMimeType(webpHeader)).toBe("image/webp");
|
|
77
|
+
});
|
|
78
|
+
test("returns null for unknown data", () => {
|
|
79
|
+
const unknownData = Buffer.from([0x00, 0x01, 0x02, 0x03]);
|
|
80
|
+
expect(detectMimeType(unknownData)).toBe(null);
|
|
81
|
+
});
|
|
82
|
+
test("returns null for empty buffer", () => {
|
|
83
|
+
expect(detectMimeType(Buffer.alloc(0))).toBe(null);
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
describe("toImageBlock", () => {
|
|
87
|
+
test("converts ImageFileResult to ImageBlock", () => {
|
|
88
|
+
const result = {
|
|
89
|
+
type: "image",
|
|
90
|
+
base64: "dGVzdCBkYXRh", // "test data" in base64
|
|
91
|
+
mediaType: "image/png",
|
|
92
|
+
originalSize: 1000,
|
|
93
|
+
dimensions: {
|
|
94
|
+
originalWidth: 100,
|
|
95
|
+
originalHeight: 100,
|
|
96
|
+
displayWidth: 100,
|
|
97
|
+
displayHeight: 100,
|
|
98
|
+
},
|
|
99
|
+
};
|
|
100
|
+
const block = toImageBlock(result);
|
|
101
|
+
expect(block.type).toBe("image");
|
|
102
|
+
expect(block.source.type).toBe("base64");
|
|
103
|
+
expect(block.source.data).toBe("dGVzdCBkYXRh");
|
|
104
|
+
expect(block.source.media_type).toBe("image/png");
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
describe("formatImageResult", () => {
|
|
108
|
+
test("formats image result with dimensions", () => {
|
|
109
|
+
const result = {
|
|
110
|
+
type: "image",
|
|
111
|
+
base64: "dGVzdA==",
|
|
112
|
+
mediaType: "image/png",
|
|
113
|
+
originalSize: 1024,
|
|
114
|
+
dimensions: {
|
|
115
|
+
originalWidth: 100,
|
|
116
|
+
originalHeight: 200,
|
|
117
|
+
displayWidth: 100,
|
|
118
|
+
displayHeight: 200,
|
|
119
|
+
},
|
|
120
|
+
};
|
|
121
|
+
const formatted = formatImageResult(result);
|
|
122
|
+
expect(formatted).toContain("image/png");
|
|
123
|
+
expect(formatted).toContain("100x200");
|
|
124
|
+
expect(formatted).toContain("1.0KB");
|
|
125
|
+
});
|
|
126
|
+
test("formats image result without dimensions", () => {
|
|
127
|
+
const result = {
|
|
128
|
+
type: "image",
|
|
129
|
+
base64: "dGVzdA==",
|
|
130
|
+
mediaType: "image/jpeg",
|
|
131
|
+
originalSize: 2048,
|
|
132
|
+
dimensions: {},
|
|
133
|
+
};
|
|
134
|
+
const formatted = formatImageResult(result);
|
|
135
|
+
expect(formatted).toContain("image/jpeg");
|
|
136
|
+
expect(formatted).toContain("2.0KB");
|
|
137
|
+
});
|
|
138
|
+
});
|
|
139
|
+
describe("readImageFile", () => {
|
|
140
|
+
test("throws error for non-existent file", async () => {
|
|
141
|
+
try {
|
|
142
|
+
await readImageFile("/non/existent/file.png");
|
|
143
|
+
expect(true).toBe(false); // Should not reach here
|
|
144
|
+
}
|
|
145
|
+
catch (error) {
|
|
146
|
+
expect(error).toBeDefined();
|
|
147
|
+
}
|
|
148
|
+
});
|
|
149
|
+
});
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Model Configuration - Single Source of Truth
|
|
3
|
+
* Consolidates all model-related constants, types, and utilities
|
|
4
|
+
*/
|
|
5
|
+
export interface ModelDefinition {
|
|
6
|
+
/** Model ID (e.g., "claude-opus-4-6") */
|
|
7
|
+
id: string;
|
|
8
|
+
/** Short display name (e.g., "Opus 4.6") */
|
|
9
|
+
name: string;
|
|
10
|
+
/** Full display name (e.g., "Claude Opus 4.6") - for /models command */
|
|
11
|
+
fullName: string;
|
|
12
|
+
/** Context window in tokens */
|
|
13
|
+
contextWindow: number;
|
|
14
|
+
/** Maximum output tokens (optional, defaults to contextWindow/4) */
|
|
15
|
+
maxOutput?: number;
|
|
16
|
+
/** Pricing per 1M tokens in USD */
|
|
17
|
+
pricing: {
|
|
18
|
+
input: number;
|
|
19
|
+
output: number;
|
|
20
|
+
cacheWrite: number;
|
|
21
|
+
cacheRead: number;
|
|
22
|
+
};
|
|
23
|
+
/** Whether model supports extended thinking */
|
|
24
|
+
supportsThinking: boolean;
|
|
25
|
+
/** Model provider */
|
|
26
|
+
provider: "anthropic" | "zhipu" | "openai" | "other";
|
|
27
|
+
/** Whether model supports vision/images */
|
|
28
|
+
supportsVision: boolean;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* All available models with complete configuration
|
|
32
|
+
*/
|
|
33
|
+
export declare const MODELS: Record<string, ModelDefinition>;
|
|
34
|
+
/** Models available for interactive use (shown in /models command) */
|
|
35
|
+
export declare const AVAILABLE_MODELS: readonly [ModelDefinition, ModelDefinition, ModelDefinition, ModelDefinition];
|
|
36
|
+
/** Model aliases for subagent tasks */
|
|
37
|
+
export declare const MODEL_ALIASES: {
|
|
38
|
+
readonly haiku: "claude-haiku-4-5";
|
|
39
|
+
readonly sonnet: "claude-sonnet-4-6";
|
|
40
|
+
readonly opus: "claude-opus-4-6";
|
|
41
|
+
readonly fast: "glm-4.5-air";
|
|
42
|
+
readonly default: "claude-sonnet-4-6";
|
|
43
|
+
};
|
|
44
|
+
/** Default model for interactive use */
|
|
45
|
+
export declare const DEFAULT_MODEL = "claude-sonnet-4-6";
|
|
46
|
+
/** Default model for summarization (fast/cheap) */
|
|
47
|
+
export declare const SUMMARIZATION_MODEL: string;
|
|
48
|
+
/** Default context window if model not found */
|
|
49
|
+
export declare const DEFAULT_CONTEXT_WINDOW = 200000;
|
|
50
|
+
/** Default max output tokens if not specified */
|
|
51
|
+
export declare const DEFAULT_MAX_OUTPUT = 4096;
|
|
52
|
+
/**
|
|
53
|
+
* Get model definition by ID
|
|
54
|
+
*/
|
|
55
|
+
export declare function getModel(modelId: string): ModelDefinition | undefined;
|
|
56
|
+
/**
|
|
57
|
+
* Get model or throw if not found
|
|
58
|
+
*/
|
|
59
|
+
export declare function requireModel(modelId: string): ModelDefinition;
|
|
60
|
+
/**
|
|
61
|
+
* Get context window for a model
|
|
62
|
+
* Falls back to fuzzy matching and then default
|
|
63
|
+
*/
|
|
64
|
+
export declare function getContextWindow(modelId: string): number;
|
|
65
|
+
/**
|
|
66
|
+
* Get max output tokens for a model
|
|
67
|
+
*/
|
|
68
|
+
export declare function getMaxOutput(modelId: string): number;
|
|
69
|
+
/**
|
|
70
|
+
* Get display name for a model
|
|
71
|
+
*/
|
|
72
|
+
export declare function getModelDisplayName(modelId: string): string;
|
|
73
|
+
/**
|
|
74
|
+
* Check if model supports extended thinking
|
|
75
|
+
*/
|
|
76
|
+
export declare function supportsExtendedThinking(modelId: string): boolean;
|
|
77
|
+
/**
|
|
78
|
+
* Check if model supports vision
|
|
79
|
+
*/
|
|
80
|
+
export declare function supportsVision(modelId: string): boolean;
|
|
81
|
+
/**
|
|
82
|
+
* Get pricing for a model
|
|
83
|
+
*/
|
|
84
|
+
export declare function getModelPricing(modelId: string): {
|
|
85
|
+
input: number;
|
|
86
|
+
output: number;
|
|
87
|
+
cacheWrite: number;
|
|
88
|
+
cacheRead: number;
|
|
89
|
+
};
|
|
90
|
+
/**
|
|
91
|
+
* Calculate cost for API usage
|
|
92
|
+
*/
|
|
93
|
+
export declare function calculateCost(modelId: string, usage: {
|
|
94
|
+
input_tokens: number;
|
|
95
|
+
output_tokens: number;
|
|
96
|
+
cache_creation_input_tokens?: number;
|
|
97
|
+
cache_read_input_tokens?: number;
|
|
98
|
+
}): {
|
|
99
|
+
costUSD: number;
|
|
100
|
+
estimatedSavingsUSD: number;
|
|
101
|
+
};
|
|
102
|
+
/**
|
|
103
|
+
* Format cost for display
|
|
104
|
+
*/
|
|
105
|
+
export declare function formatCost(costUSD: number): string;
|
|
106
|
+
/**
|
|
107
|
+
* Resolve model alias to model ID
|
|
108
|
+
*/
|
|
109
|
+
export declare function resolveModelAlias(alias: string): string;
|
|
110
|
+
/** Claude model type (for TypeScript type checking) */
|
|
111
|
+
export type ClaudeModel = "claude-opus-4-6" | "claude-sonnet-4-6" | "claude-haiku-4-5" | "claude-haiku-4-5-20251001" | "claude-opus-4-5" | "claude-sonnet-4-5" | "claude-3-5-sonnet" | "claude-3-5-haiku" | "claude-3-opus" | "claude-3-sonnet" | "claude-3-haiku" | "glm-5" | "glm-4.5-air" | string;
|
|
112
|
+
/** @deprecated Use getModelPricing() instead */
|
|
113
|
+
export declare const MODEL_PRICING: Record<string, {
|
|
114
|
+
input: number;
|
|
115
|
+
output: number;
|
|
116
|
+
cache_write: number;
|
|
117
|
+
cache_read: number;
|
|
118
|
+
}>;
|
|
119
|
+
/** @deprecated Use getContextWindow() instead */
|
|
120
|
+
export declare const MODEL_CONTEXT_WINDOWS: Record<string, number>;
|
|
121
|
+
/** @deprecated Use getModelDisplayName() instead */
|
|
122
|
+
export declare const MODEL_DISPLAY_NAMES: Record<string, string>;
|
|
123
|
+
//# sourceMappingURL=models.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"models.d.ts","sourceRoot":"","sources":["../../packages/src/core/models.ts"],"names":[],"mappings":"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"}
|