@mragentix/cli 4.2.37
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/LICENSE +21 -0
- package/README.md +149 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +772 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +16 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +29 -0
- package/dist/config.js.map +1 -0
- package/dist/core/agent-session.d.ts +87 -0
- package/dist/core/agent-session.d.ts.map +1 -0
- package/dist/core/agent-session.js +498 -0
- package/dist/core/agent-session.js.map +1 -0
- package/dist/core/agents.d.ts +30 -0
- package/dist/core/agents.d.ts.map +1 -0
- package/dist/core/agents.js +91 -0
- package/dist/core/agents.js.map +1 -0
- package/dist/core/auth-storage.d.ts +35 -0
- package/dist/core/auth-storage.d.ts.map +1 -0
- package/dist/core/auth-storage.js +144 -0
- package/dist/core/auth-storage.js.map +1 -0
- package/dist/core/auto-update.d.ts +8 -0
- package/dist/core/auto-update.d.ts.map +1 -0
- package/dist/core/auto-update.js +152 -0
- package/dist/core/auto-update.js.map +1 -0
- package/dist/core/compaction/compactor.d.ts +69 -0
- package/dist/core/compaction/compactor.d.ts.map +1 -0
- package/dist/core/compaction/compactor.js +405 -0
- package/dist/core/compaction/compactor.js.map +1 -0
- package/dist/core/compaction/compactor.test.d.ts +2 -0
- package/dist/core/compaction/compactor.test.d.ts.map +1 -0
- package/dist/core/compaction/compactor.test.js +461 -0
- package/dist/core/compaction/compactor.test.js.map +1 -0
- package/dist/core/compaction/token-estimator.d.ts +10 -0
- package/dist/core/compaction/token-estimator.d.ts.map +1 -0
- package/dist/core/compaction/token-estimator.js +75 -0
- package/dist/core/compaction/token-estimator.js.map +1 -0
- package/dist/core/compaction/token-estimator.test.d.ts +2 -0
- package/dist/core/compaction/token-estimator.test.d.ts.map +1 -0
- package/dist/core/compaction/token-estimator.test.js +137 -0
- package/dist/core/compaction/token-estimator.test.js.map +1 -0
- package/dist/core/custom-commands.d.ts +13 -0
- package/dist/core/custom-commands.d.ts.map +1 -0
- package/dist/core/custom-commands.js +40 -0
- package/dist/core/custom-commands.js.map +1 -0
- package/dist/core/event-bus.d.ts +95 -0
- package/dist/core/event-bus.d.ts.map +1 -0
- package/dist/core/event-bus.js +99 -0
- package/dist/core/event-bus.js.map +1 -0
- package/dist/core/extensions/loader.d.ts +8 -0
- package/dist/core/extensions/loader.d.ts.map +1 -0
- package/dist/core/extensions/loader.js +48 -0
- package/dist/core/extensions/loader.js.map +1 -0
- package/dist/core/extensions/types.d.ts +19 -0
- package/dist/core/extensions/types.d.ts.map +1 -0
- package/dist/core/extensions/types.js +2 -0
- package/dist/core/extensions/types.js.map +1 -0
- package/dist/core/file-lock.d.ts +6 -0
- package/dist/core/file-lock.d.ts.map +1 -0
- package/dist/core/file-lock.js +76 -0
- package/dist/core/file-lock.js.map +1 -0
- package/dist/core/index.d.ts +14 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +13 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/logger.d.ts +26 -0
- package/dist/core/logger.d.ts.map +1 -0
- package/dist/core/logger.js +132 -0
- package/dist/core/logger.js.map +1 -0
- package/dist/core/mcp/client.d.ts +9 -0
- package/dist/core/mcp/client.d.ts.map +1 -0
- package/dist/core/mcp/client.js +126 -0
- package/dist/core/mcp/client.js.map +1 -0
- package/dist/core/mcp/defaults.d.ts +9 -0
- package/dist/core/mcp/defaults.d.ts.map +1 -0
- package/dist/core/mcp/defaults.js +47 -0
- package/dist/core/mcp/defaults.js.map +1 -0
- package/dist/core/mcp/index.d.ts +4 -0
- package/dist/core/mcp/index.d.ts.map +1 -0
- package/dist/core/mcp/index.js +3 -0
- package/dist/core/mcp/index.js.map +1 -0
- package/dist/core/mcp/types.d.ts +15 -0
- package/dist/core/mcp/types.d.ts.map +1 -0
- package/dist/core/mcp/types.js +2 -0
- package/dist/core/mcp/types.js.map +1 -0
- package/dist/core/model-registry.d.ts +25 -0
- package/dist/core/model-registry.d.ts.map +1 -0
- package/dist/core/model-registry.js +135 -0
- package/dist/core/model-registry.js.map +1 -0
- package/dist/core/oauth/anthropic.d.ts +4 -0
- package/dist/core/oauth/anthropic.d.ts.map +1 -0
- package/dist/core/oauth/anthropic.js +75 -0
- package/dist/core/oauth/anthropic.js.map +1 -0
- package/dist/core/oauth/openai.d.ts +4 -0
- package/dist/core/oauth/openai.d.ts.map +1 -0
- package/dist/core/oauth/openai.js +186 -0
- package/dist/core/oauth/openai.js.map +1 -0
- package/dist/core/oauth/pkce.d.ts +5 -0
- package/dist/core/oauth/pkce.d.ts.map +1 -0
- package/dist/core/oauth/pkce.js +17 -0
- package/dist/core/oauth/pkce.js.map +1 -0
- package/dist/core/oauth/types.d.ts +12 -0
- package/dist/core/oauth/types.d.ts.map +1 -0
- package/dist/core/oauth/types.js +2 -0
- package/dist/core/oauth/types.js.map +1 -0
- package/dist/core/process-manager.d.ts +30 -0
- package/dist/core/process-manager.d.ts.map +1 -0
- package/dist/core/process-manager.js +130 -0
- package/dist/core/process-manager.js.map +1 -0
- package/dist/core/prompt-commands.d.ts +14 -0
- package/dist/core/prompt-commands.d.ts.map +1 -0
- package/dist/core/prompt-commands.js +496 -0
- package/dist/core/prompt-commands.js.map +1 -0
- package/dist/core/session-manager.d.ts +112 -0
- package/dist/core/session-manager.d.ts.map +1 -0
- package/dist/core/session-manager.js +326 -0
- package/dist/core/session-manager.js.map +1 -0
- package/dist/core/settings-manager.d.ts +43 -0
- package/dist/core/settings-manager.d.ts.map +1 -0
- package/dist/core/settings-manager.js +64 -0
- package/dist/core/settings-manager.js.map +1 -0
- package/dist/core/skills.d.ts +23 -0
- package/dist/core/skills.d.ts.map +1 -0
- package/dist/core/skills.js +89 -0
- package/dist/core/skills.js.map +1 -0
- package/dist/core/slash-commands.d.ts +35 -0
- package/dist/core/slash-commands.d.ts.map +1 -0
- package/dist/core/slash-commands.js +183 -0
- package/dist/core/slash-commands.js.map +1 -0
- package/dist/core/telegram.d.ts +94 -0
- package/dist/core/telegram.d.ts.map +1 -0
- package/dist/core/telegram.js +227 -0
- package/dist/core/telegram.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +15 -0
- package/dist/index.js.map +1 -0
- package/dist/interactive.d.ts +3 -0
- package/dist/interactive.d.ts.map +1 -0
- package/dist/interactive.js +173 -0
- package/dist/interactive.js.map +1 -0
- package/dist/modes/index.d.ts +3 -0
- package/dist/modes/index.d.ts.map +1 -0
- package/dist/modes/index.js +3 -0
- package/dist/modes/index.js.map +1 -0
- package/dist/modes/json-mode.d.ts +13 -0
- package/dist/modes/json-mode.d.ts.map +1 -0
- package/dist/modes/json-mode.js +74 -0
- package/dist/modes/json-mode.js.map +1 -0
- package/dist/modes/print-mode.d.ts +12 -0
- package/dist/modes/print-mode.d.ts.map +1 -0
- package/dist/modes/print-mode.js +49 -0
- package/dist/modes/print-mode.js.map +1 -0
- package/dist/modes/rpc-mode.d.ts +28 -0
- package/dist/modes/rpc-mode.d.ts.map +1 -0
- package/dist/modes/rpc-mode.js +145 -0
- package/dist/modes/rpc-mode.js.map +1 -0
- package/dist/modes/serve-mode.d.ts +21 -0
- package/dist/modes/serve-mode.d.ts.map +1 -0
- package/dist/modes/serve-mode.js +649 -0
- package/dist/modes/serve-mode.js.map +1 -0
- package/dist/session.d.ts +16 -0
- package/dist/session.d.ts.map +1 -0
- package/dist/session.js +129 -0
- package/dist/session.js.map +1 -0
- package/dist/system-prompt.d.ts +6 -0
- package/dist/system-prompt.d.ts.map +1 -0
- package/dist/system-prompt.js +115 -0
- package/dist/system-prompt.js.map +1 -0
- package/dist/tools/bash.d.ts +13 -0
- package/dist/tools/bash.d.ts.map +1 -0
- package/dist/tools/bash.js +165 -0
- package/dist/tools/bash.js.map +1 -0
- package/dist/tools/edit-diff.d.ts +18 -0
- package/dist/tools/edit-diff.d.ts.map +1 -0
- package/dist/tools/edit-diff.js +92 -0
- package/dist/tools/edit-diff.js.map +1 -0
- package/dist/tools/edit.d.ts +11 -0
- package/dist/tools/edit.d.ts.map +1 -0
- package/dist/tools/edit.js +57 -0
- package/dist/tools/edit.js.map +1 -0
- package/dist/tools/find.d.ts +9 -0
- package/dist/tools/find.d.ts.map +1 -0
- package/dist/tools/find.js +59 -0
- package/dist/tools/find.js.map +1 -0
- package/dist/tools/grep.d.ts +13 -0
- package/dist/tools/grep.d.ts.map +1 -0
- package/dist/tools/grep.js +121 -0
- package/dist/tools/grep.js.map +1 -0
- package/dist/tools/index.d.ts +30 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +50 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/ls.d.ts +10 -0
- package/dist/tools/ls.d.ts.map +1 -0
- package/dist/tools/ls.js +56 -0
- package/dist/tools/ls.js.map +1 -0
- package/dist/tools/operations.d.ts +39 -0
- package/dist/tools/operations.d.ts.map +1 -0
- package/dist/tools/operations.js +27 -0
- package/dist/tools/operations.js.map +1 -0
- package/dist/tools/path-utils.d.ts +7 -0
- package/dist/tools/path-utils.d.ts.map +1 -0
- package/dist/tools/path-utils.js +27 -0
- package/dist/tools/path-utils.js.map +1 -0
- package/dist/tools/read.d.ts +12 -0
- package/dist/tools/read.d.ts.map +1 -0
- package/dist/tools/read.js +113 -0
- package/dist/tools/read.js.map +1 -0
- package/dist/tools/subagent.d.ts +26 -0
- package/dist/tools/subagent.d.ts.map +1 -0
- package/dist/tools/subagent.js +210 -0
- package/dist/tools/subagent.js.map +1 -0
- package/dist/tools/task-output.d.ts +10 -0
- package/dist/tools/task-output.d.ts.map +1 -0
- package/dist/tools/task-output.js +33 -0
- package/dist/tools/task-output.js.map +1 -0
- package/dist/tools/task-stop.d.ts +9 -0
- package/dist/tools/task-stop.d.ts.map +1 -0
- package/dist/tools/task-stop.js +15 -0
- package/dist/tools/task-stop.js.map +1 -0
- package/dist/tools/tasks.d.ts +16 -0
- package/dist/tools/tasks.d.ts.map +1 -0
- package/dist/tools/tasks.js +132 -0
- package/dist/tools/tasks.js.map +1 -0
- package/dist/tools/truncate.d.ts +19 -0
- package/dist/tools/truncate.d.ts.map +1 -0
- package/dist/tools/truncate.js +59 -0
- package/dist/tools/truncate.js.map +1 -0
- package/dist/tools/truncate.test.d.ts +2 -0
- package/dist/tools/truncate.test.d.ts.map +1 -0
- package/dist/tools/truncate.test.js +100 -0
- package/dist/tools/truncate.test.js.map +1 -0
- package/dist/tools/web-fetch.d.ts +9 -0
- package/dist/tools/web-fetch.d.ts.map +1 -0
- package/dist/tools/web-fetch.js +97 -0
- package/dist/tools/web-fetch.js.map +1 -0
- package/dist/tools/write.d.ts +10 -0
- package/dist/tools/write.d.ts.map +1 -0
- package/dist/tools/write.js +30 -0
- package/dist/tools/write.js.map +1 -0
- package/dist/tools/write.test.d.ts +2 -0
- package/dist/tools/write.test.d.ts.map +1 -0
- package/dist/tools/write.test.js +84 -0
- package/dist/tools/write.test.js.map +1 -0
- package/dist/types.d.ts +36 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/ui/App.d.ts +148 -0
- package/dist/ui/App.d.ts.map +1 -0
- package/dist/ui/App.js +1191 -0
- package/dist/ui/App.js.map +1 -0
- package/dist/ui/components/ActivityIndicator.d.ts +13 -0
- package/dist/ui/components/ActivityIndicator.d.ts.map +1 -0
- package/dist/ui/components/ActivityIndicator.js +313 -0
- package/dist/ui/components/ActivityIndicator.js.map +1 -0
- package/dist/ui/components/AnimationContext.d.ts +22 -0
- package/dist/ui/components/AnimationContext.d.ts.map +1 -0
- package/dist/ui/components/AnimationContext.js +35 -0
- package/dist/ui/components/AnimationContext.js.map +1 -0
- package/dist/ui/components/AssistantMessage.d.ts +9 -0
- package/dist/ui/components/AssistantMessage.d.ts.map +1 -0
- package/dist/ui/components/AssistantMessage.js +11 -0
- package/dist/ui/components/AssistantMessage.js.map +1 -0
- package/dist/ui/components/BackgroundTasksBar.d.ts +15 -0
- package/dist/ui/components/BackgroundTasksBar.d.ts.map +1 -0
- package/dist/ui/components/BackgroundTasksBar.js +74 -0
- package/dist/ui/components/BackgroundTasksBar.js.map +1 -0
- package/dist/ui/components/Banner.d.ts +11 -0
- package/dist/ui/components/Banner.d.ts.map +1 -0
- package/dist/ui/components/Banner.js +55 -0
- package/dist/ui/components/Banner.js.map +1 -0
- package/dist/ui/components/CompactionNotice.d.ts +10 -0
- package/dist/ui/components/CompactionNotice.d.ts.map +1 -0
- package/dist/ui/components/CompactionNotice.js +27 -0
- package/dist/ui/components/CompactionNotice.js.map +1 -0
- package/dist/ui/components/DiffView.d.ts +4 -0
- package/dist/ui/components/DiffView.d.ts.map +1 -0
- package/dist/ui/components/DiffView.js +20 -0
- package/dist/ui/components/DiffView.js.map +1 -0
- package/dist/ui/components/Footer.d.ts +10 -0
- package/dist/ui/components/Footer.d.ts.map +1 -0
- package/dist/ui/components/Footer.js +105 -0
- package/dist/ui/components/Footer.js.map +1 -0
- package/dist/ui/components/InputArea.d.ts +21 -0
- package/dist/ui/components/InputArea.d.ts.map +1 -0
- package/dist/ui/components/InputArea.js +465 -0
- package/dist/ui/components/InputArea.js.map +1 -0
- package/dist/ui/components/Markdown.d.ts +9 -0
- package/dist/ui/components/Markdown.d.ts.map +1 -0
- package/dist/ui/components/Markdown.js +246 -0
- package/dist/ui/components/Markdown.js.map +1 -0
- package/dist/ui/components/ModelSelector.d.ts +11 -0
- package/dist/ui/components/ModelSelector.d.ts.map +1 -0
- package/dist/ui/components/ModelSelector.js +20 -0
- package/dist/ui/components/ModelSelector.js.map +1 -0
- package/dist/ui/components/Overlay.d.ts +8 -0
- package/dist/ui/components/Overlay.d.ts.map +1 -0
- package/dist/ui/components/Overlay.js +9 -0
- package/dist/ui/components/Overlay.js.map +1 -0
- package/dist/ui/components/SelectList.d.ts +14 -0
- package/dist/ui/components/SelectList.d.ts.map +1 -0
- package/dist/ui/components/SelectList.js +46 -0
- package/dist/ui/components/SelectList.js.map +1 -0
- package/dist/ui/components/ServerToolExecution.d.ts +17 -0
- package/dist/ui/components/ServerToolExecution.d.ts.map +1 -0
- package/dist/ui/components/ServerToolExecution.js +26 -0
- package/dist/ui/components/ServerToolExecution.js.map +1 -0
- package/dist/ui/components/SessionSelector.d.ts +9 -0
- package/dist/ui/components/SessionSelector.d.ts.map +1 -0
- package/dist/ui/components/SessionSelector.js +13 -0
- package/dist/ui/components/SessionSelector.js.map +1 -0
- package/dist/ui/components/SettingsSelector.d.ts +9 -0
- package/dist/ui/components/SettingsSelector.d.ts.map +1 -0
- package/dist/ui/components/SettingsSelector.js +13 -0
- package/dist/ui/components/SettingsSelector.js.map +1 -0
- package/dist/ui/components/SlashCommandMenu.d.ts +15 -0
- package/dist/ui/components/SlashCommandMenu.d.ts.map +1 -0
- package/dist/ui/components/SlashCommandMenu.js +32 -0
- package/dist/ui/components/SlashCommandMenu.js.map +1 -0
- package/dist/ui/components/Spinner.d.ts +4 -0
- package/dist/ui/components/Spinner.d.ts.map +1 -0
- package/dist/ui/components/Spinner.js +13 -0
- package/dist/ui/components/Spinner.js.map +1 -0
- package/dist/ui/components/StreamingArea.d.ts +10 -0
- package/dist/ui/components/StreamingArea.d.ts.map +1 -0
- package/dist/ui/components/StreamingArea.js +58 -0
- package/dist/ui/components/StreamingArea.js.map +1 -0
- package/dist/ui/components/SubAgentPanel.d.ts +21 -0
- package/dist/ui/components/SubAgentPanel.d.ts.map +1 -0
- package/dist/ui/components/SubAgentPanel.js +71 -0
- package/dist/ui/components/SubAgentPanel.js.map +1 -0
- package/dist/ui/components/TaskOverlay.d.ts +10 -0
- package/dist/ui/components/TaskOverlay.d.ts.map +1 -0
- package/dist/ui/components/TaskOverlay.js +263 -0
- package/dist/ui/components/TaskOverlay.js.map +1 -0
- package/dist/ui/components/ThinkingBlock.d.ts +11 -0
- package/dist/ui/components/ThinkingBlock.d.ts.map +1 -0
- package/dist/ui/components/ThinkingBlock.js +43 -0
- package/dist/ui/components/ThinkingBlock.js.map +1 -0
- package/dist/ui/components/ThinkingIndicator.d.ts +6 -0
- package/dist/ui/components/ThinkingIndicator.d.ts.map +1 -0
- package/dist/ui/components/ThinkingIndicator.js +144 -0
- package/dist/ui/components/ThinkingIndicator.js.map +1 -0
- package/dist/ui/components/ToolExecution.d.ts +16 -0
- package/dist/ui/components/ToolExecution.d.ts.map +1 -0
- package/dist/ui/components/ToolExecution.js +490 -0
- package/dist/ui/components/ToolExecution.js.map +1 -0
- package/dist/ui/components/ToolGroupExecution.d.ts +7 -0
- package/dist/ui/components/ToolGroupExecution.d.ts.map +1 -0
- package/dist/ui/components/ToolGroupExecution.js +115 -0
- package/dist/ui/components/ToolGroupExecution.js.map +1 -0
- package/dist/ui/components/UserMessage.d.ts +7 -0
- package/dist/ui/components/UserMessage.d.ts.map +1 -0
- package/dist/ui/components/UserMessage.js +16 -0
- package/dist/ui/components/UserMessage.js.map +1 -0
- package/dist/ui/components/index.d.ts +15 -0
- package/dist/ui/components/index.d.ts.map +1 -0
- package/dist/ui/components/index.js +15 -0
- package/dist/ui/components/index.js.map +1 -0
- package/dist/ui/hooks/useAgentLoop.d.ts +69 -0
- package/dist/ui/hooks/useAgentLoop.d.ts.map +1 -0
- package/dist/ui/hooks/useAgentLoop.js +483 -0
- package/dist/ui/hooks/useAgentLoop.js.map +1 -0
- package/dist/ui/hooks/useSessionManager.d.ts +13 -0
- package/dist/ui/hooks/useSessionManager.d.ts.map +1 -0
- package/dist/ui/hooks/useSessionManager.js +43 -0
- package/dist/ui/hooks/useSessionManager.js.map +1 -0
- package/dist/ui/hooks/useSlashCommands.d.ts +7 -0
- package/dist/ui/hooks/useSlashCommands.d.ts.map +1 -0
- package/dist/ui/hooks/useSlashCommands.js +11 -0
- package/dist/ui/hooks/useSlashCommands.js.map +1 -0
- package/dist/ui/hooks/useTerminalSize.d.ts +20 -0
- package/dist/ui/hooks/useTerminalSize.d.ts.map +1 -0
- package/dist/ui/hooks/useTerminalSize.js +55 -0
- package/dist/ui/hooks/useTerminalSize.js.map +1 -0
- package/dist/ui/hooks/useTerminalTitle.d.ts +3 -0
- package/dist/ui/hooks/useTerminalTitle.d.ts.map +1 -0
- package/dist/ui/hooks/useTerminalTitle.js +41 -0
- package/dist/ui/hooks/useTerminalTitle.js.map +1 -0
- package/dist/ui/live-item-flush.d.ts +59 -0
- package/dist/ui/live-item-flush.d.ts.map +1 -0
- package/dist/ui/live-item-flush.js +135 -0
- package/dist/ui/live-item-flush.js.map +1 -0
- package/dist/ui/live-item-flush.test.d.ts +2 -0
- package/dist/ui/live-item-flush.test.d.ts.map +1 -0
- package/dist/ui/live-item-flush.test.js +307 -0
- package/dist/ui/live-item-flush.test.js.map +1 -0
- package/dist/ui/login.d.ts +3 -0
- package/dist/ui/login.d.ts.map +1 -0
- package/dist/ui/login.js +117 -0
- package/dist/ui/login.js.map +1 -0
- package/dist/ui/render.d.ts +38 -0
- package/dist/ui/render.d.ts.map +1 -0
- package/dist/ui/render.js +72 -0
- package/dist/ui/render.js.map +1 -0
- package/dist/ui/sessions.d.ts +2 -0
- package/dist/ui/sessions.d.ts.map +1 -0
- package/dist/ui/sessions.js +208 -0
- package/dist/ui/sessions.js.map +1 -0
- package/dist/ui/spinner-frames.d.ts +3 -0
- package/dist/ui/spinner-frames.d.ts.map +1 -0
- package/dist/ui/spinner-frames.js +7 -0
- package/dist/ui/spinner-frames.js.map +1 -0
- package/dist/ui/theme/dark.json +24 -0
- package/dist/ui/theme/detect-theme.d.ts +12 -0
- package/dist/ui/theme/detect-theme.d.ts.map +1 -0
- package/dist/ui/theme/detect-theme.js +152 -0
- package/dist/ui/theme/detect-theme.js.map +1 -0
- package/dist/ui/theme/light.json +24 -0
- package/dist/ui/theme/theme.d.ts +29 -0
- package/dist/ui/theme/theme.d.ts.map +1 -0
- package/dist/ui/theme/theme.js +11 -0
- package/dist/ui/theme/theme.js.map +1 -0
- package/dist/ui/utils/highlight.d.ts +8 -0
- package/dist/ui/utils/highlight.d.ts.map +1 -0
- package/dist/ui/utils/highlight.js +49 -0
- package/dist/ui/utils/highlight.js.map +1 -0
- package/dist/ui/utils/table-text.d.ts +25 -0
- package/dist/ui/utils/table-text.d.ts.map +1 -0
- package/dist/ui/utils/table-text.js +78 -0
- package/dist/ui/utils/table-text.js.map +1 -0
- package/dist/ui/utils/table-text.test.d.ts +2 -0
- package/dist/ui/utils/table-text.test.d.ts.map +1 -0
- package/dist/ui/utils/table-text.test.js +202 -0
- package/dist/ui/utils/table-text.test.js.map +1 -0
- package/dist/utils/error-handler.d.ts +5 -0
- package/dist/utils/error-handler.d.ts.map +1 -0
- package/dist/utils/error-handler.js +120 -0
- package/dist/utils/error-handler.js.map +1 -0
- package/dist/utils/format.d.ts +21 -0
- package/dist/utils/format.d.ts.map +1 -0
- package/dist/utils/format.js +120 -0
- package/dist/utils/format.js.map +1 -0
- package/dist/utils/git.d.ts +2 -0
- package/dist/utils/git.d.ts.map +1 -0
- package/dist/utils/git.js +13 -0
- package/dist/utils/git.js.map +1 -0
- package/dist/utils/image.d.ts +30 -0
- package/dist/utils/image.d.ts.map +1 -0
- package/dist/utils/image.js +231 -0
- package/dist/utils/image.js.map +1 -0
- package/dist/utils/markdown.d.ts +6 -0
- package/dist/utils/markdown.d.ts.map +1 -0
- package/dist/utils/markdown.js +25 -0
- package/dist/utils/markdown.js.map +1 -0
- package/dist/utils/process.d.ts +6 -0
- package/dist/utils/process.d.ts.map +1 -0
- package/dist/utils/process.js +19 -0
- package/dist/utils/process.js.map +1 -0
- package/dist/utils/shell.d.ts +3 -0
- package/dist/utils/shell.d.ts.map +1 -0
- package/dist/utils/shell.js +8 -0
- package/dist/utils/shell.js.map +1 -0
- package/dist/utils/sound.d.ts +2 -0
- package/dist/utils/sound.d.ts.map +1 -0
- package/dist/utils/sound.js +11 -0
- package/dist/utils/sound.js.map +1 -0
- package/package.json +56 -0
|
@@ -0,0 +1,649 @@
|
|
|
1
|
+
import fs from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { AgentSession } from "../core/agent-session.js";
|
|
4
|
+
import { TelegramBot } from "../core/telegram.js";
|
|
5
|
+
import chalk from "chalk";
|
|
6
|
+
import { formatUserError } from "../utils/error-handler.js";
|
|
7
|
+
import { log, closeLogger } from "../core/logger.js";
|
|
8
|
+
import { getAppPaths } from "../config.js";
|
|
9
|
+
import { MODELS, getContextWindow } from "../core/model-registry.js";
|
|
10
|
+
import { estimateConversationTokens } from "../core/compaction/token-estimator.js";
|
|
11
|
+
import { PROMPT_COMMANDS } from "../core/prompt-commands.js";
|
|
12
|
+
import { loadCustomCommands } from "../core/custom-commands.js";
|
|
13
|
+
function getConfigPath() {
|
|
14
|
+
return path.join(getAppPaths().agentDir, "serve.json");
|
|
15
|
+
}
|
|
16
|
+
async function loadConfig() {
|
|
17
|
+
try {
|
|
18
|
+
const content = await fs.readFile(getConfigPath(), "utf-8");
|
|
19
|
+
const raw = JSON.parse(content);
|
|
20
|
+
return { chats: raw.chats ?? {} };
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
return { chats: {} };
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
async function saveConfig(config) {
|
|
27
|
+
const configPath = getConfigPath();
|
|
28
|
+
await fs.mkdir(path.dirname(configPath), { recursive: true });
|
|
29
|
+
await fs.writeFile(configPath, JSON.stringify(config, null, 2), "utf-8");
|
|
30
|
+
}
|
|
31
|
+
// ── Project Discovery ──────────────────────────────────────
|
|
32
|
+
/**
|
|
33
|
+
* Scan ~/.mragentix/sessions/ to find all project directories that have sessions.
|
|
34
|
+
* Returns decoded absolute paths sorted alphabetically.
|
|
35
|
+
*/
|
|
36
|
+
async function discoverProjects() {
|
|
37
|
+
const sessionsDir = getAppPaths().sessionsDir;
|
|
38
|
+
try {
|
|
39
|
+
const entries = await fs.readdir(sessionsDir);
|
|
40
|
+
const projects = [];
|
|
41
|
+
for (const entry of entries) {
|
|
42
|
+
// Decode: reverse of encodeCwd (replace _ back to /)
|
|
43
|
+
// encodeCwd: replace /\\ with _, remove :, strip leading _
|
|
44
|
+
// Decoding is imperfect but works for display — we reconstruct the path
|
|
45
|
+
const decoded = "/" + entry.replace(/_/g, "/");
|
|
46
|
+
// Verify the decoded path has session files
|
|
47
|
+
const dir = path.join(sessionsDir, entry);
|
|
48
|
+
const stat = await fs.stat(dir);
|
|
49
|
+
if (stat.isDirectory()) {
|
|
50
|
+
const files = await fs.readdir(dir);
|
|
51
|
+
if (files.some((f) => f.endsWith(".jsonl"))) {
|
|
52
|
+
projects.push(decoded);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return projects.sort();
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
return [];
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Serve mode: run mragentix controlled via Telegram.
|
|
64
|
+
*
|
|
65
|
+
* - DMs to bot → default project (CWD where serve was started)
|
|
66
|
+
* - Groups → linked projects via /link <path>
|
|
67
|
+
* - Each chat gets its own AgentSession, tools, context
|
|
68
|
+
*/
|
|
69
|
+
export async function runServeMode(options) {
|
|
70
|
+
const bot = new TelegramBot({
|
|
71
|
+
botToken: options.telegram.botToken,
|
|
72
|
+
allowedUserId: options.telegram.userId,
|
|
73
|
+
});
|
|
74
|
+
const config = await loadConfig();
|
|
75
|
+
const chatStates = new Map();
|
|
76
|
+
/** Guards against concurrent session creation for the same chat. */
|
|
77
|
+
const chatCreationLocks = new Map();
|
|
78
|
+
/** Chats waiting for a number selection after /link showed the project list. */
|
|
79
|
+
const pendingLinkSelections = new Map();
|
|
80
|
+
// ── Session lifecycle ──────────────────────────────────
|
|
81
|
+
async function getOrCreateChat(chatId, cwd) {
|
|
82
|
+
const existing = chatStates.get(chatId);
|
|
83
|
+
if (existing)
|
|
84
|
+
return existing;
|
|
85
|
+
// If another call is already creating this chat, share its promise
|
|
86
|
+
const pending = chatCreationLocks.get(chatId);
|
|
87
|
+
if (pending)
|
|
88
|
+
return pending;
|
|
89
|
+
const promise = (async () => {
|
|
90
|
+
const ac = new AbortController();
|
|
91
|
+
const session = new AgentSession({
|
|
92
|
+
provider: options.provider,
|
|
93
|
+
model: options.model,
|
|
94
|
+
cwd,
|
|
95
|
+
thinkingLevel: options.thinkingLevel,
|
|
96
|
+
signal: ac.signal,
|
|
97
|
+
});
|
|
98
|
+
await session.initialize();
|
|
99
|
+
log("INFO", "serve", `Session initialized for chat ${chatId}`, { cwd });
|
|
100
|
+
const state = {
|
|
101
|
+
chatId,
|
|
102
|
+
cwd,
|
|
103
|
+
session,
|
|
104
|
+
ac,
|
|
105
|
+
textBuffer: "",
|
|
106
|
+
activeTools: new Map(),
|
|
107
|
+
isProcessing: false,
|
|
108
|
+
typingInterval: null,
|
|
109
|
+
};
|
|
110
|
+
chatStates.set(chatId, state);
|
|
111
|
+
wireSessionEvents(state);
|
|
112
|
+
return state;
|
|
113
|
+
})();
|
|
114
|
+
chatCreationLocks.set(chatId, promise);
|
|
115
|
+
try {
|
|
116
|
+
return await promise;
|
|
117
|
+
}
|
|
118
|
+
finally {
|
|
119
|
+
chatCreationLocks.delete(chatId);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
function resolveProjectPath(chatId) {
|
|
123
|
+
return config.chats[String(chatId)] ?? options.cwd;
|
|
124
|
+
}
|
|
125
|
+
// ── Per-chat typing ────────────────────────────────────
|
|
126
|
+
function startTyping(state) {
|
|
127
|
+
if (state.typingInterval)
|
|
128
|
+
return;
|
|
129
|
+
bot.sendTyping(state.chatId).catch(() => { });
|
|
130
|
+
state.typingInterval = setInterval(() => {
|
|
131
|
+
bot.sendTyping(state.chatId).catch(() => { });
|
|
132
|
+
}, 4000);
|
|
133
|
+
}
|
|
134
|
+
function stopTyping(state) {
|
|
135
|
+
if (state.typingInterval) {
|
|
136
|
+
clearInterval(state.typingInterval);
|
|
137
|
+
state.typingInterval = null;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
function flushText(state) {
|
|
141
|
+
const text = state.textBuffer.trim();
|
|
142
|
+
state.textBuffer = "";
|
|
143
|
+
if (text) {
|
|
144
|
+
return bot.send(state.chatId, text);
|
|
145
|
+
}
|
|
146
|
+
return Promise.resolve();
|
|
147
|
+
}
|
|
148
|
+
// ── Agent → Telegram bridge (per chat) ─────────────────
|
|
149
|
+
function wireSessionEvents(state) {
|
|
150
|
+
const { session, chatId } = state;
|
|
151
|
+
session.eventBus.on("text_delta", ({ text }) => {
|
|
152
|
+
state.textBuffer += text;
|
|
153
|
+
});
|
|
154
|
+
session.eventBus.on("thinking_delta", () => {
|
|
155
|
+
// Thinking not displayed in Telegram
|
|
156
|
+
});
|
|
157
|
+
session.eventBus.on("tool_call_start", ({ toolCallId, name, args }) => {
|
|
158
|
+
state.activeTools.set(toolCallId, { name, startTime: Date.now(), args });
|
|
159
|
+
});
|
|
160
|
+
session.eventBus.on("tool_call_end", ({ toolCallId, isError, durationMs }) => {
|
|
161
|
+
const tool = state.activeTools.get(toolCallId);
|
|
162
|
+
state.activeTools.delete(toolCallId);
|
|
163
|
+
if (tool) {
|
|
164
|
+
const icon = isError ? "✗" : "✓";
|
|
165
|
+
const argsStr = formatArgs(tool.args);
|
|
166
|
+
const msg = `${icon} \`${tool.name}\` ${argsStr} _${formatDuration(durationMs)}_`;
|
|
167
|
+
bot.send(chatId, msg).catch((err) => {
|
|
168
|
+
log("WARN", "telegram", `Failed to send tool message for ${tool.name}: ${err instanceof Error ? err.message : String(err)}`);
|
|
169
|
+
// Retry without markdown formatting
|
|
170
|
+
bot
|
|
171
|
+
.sendPlain(chatId, `${icon} ${tool.name} ${argsStr} ${formatDuration(durationMs)}`)
|
|
172
|
+
.catch(() => { });
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
});
|
|
176
|
+
session.eventBus.on("turn_end", () => {
|
|
177
|
+
// Flush text after each turn so each response is a separate Telegram message
|
|
178
|
+
flushText(state).catch(() => { });
|
|
179
|
+
});
|
|
180
|
+
session.eventBus.on("agent_done", ({ totalTurns, totalUsage }) => {
|
|
181
|
+
stopTyping(state);
|
|
182
|
+
state.isProcessing = false;
|
|
183
|
+
const total = totalUsage.inputTokens + totalUsage.outputTokens;
|
|
184
|
+
const tokens = total >= 1000 ? `${(total / 1000).toFixed(1)}k` : `${total}`;
|
|
185
|
+
const turns = totalTurns === 1 ? "1 turn" : `${totalTurns} turns`;
|
|
186
|
+
// Context usage percentage
|
|
187
|
+
const modelId = session.getState().model;
|
|
188
|
+
const contextWindow = getContextWindow(modelId);
|
|
189
|
+
const contextTokens = estimateConversationTokens(session.getMessages());
|
|
190
|
+
const contextPctRaw = (contextTokens / contextWindow) * 100;
|
|
191
|
+
const contextStr = contextPctRaw > 0 && contextPctRaw < 1 ? "<1" : String(Math.round(contextPctRaw));
|
|
192
|
+
state.textBuffer += `\n\n_${tokens} tokens · ${turns} · ${contextStr}% context_`;
|
|
193
|
+
flushText(state).catch(() => { });
|
|
194
|
+
});
|
|
195
|
+
session.eventBus.on("error", ({ error }) => {
|
|
196
|
+
stopTyping(state);
|
|
197
|
+
state.isProcessing = false;
|
|
198
|
+
bot.send(chatId, `✗ *Error*\n${error.message}`).catch(() => { });
|
|
199
|
+
});
|
|
200
|
+
session.eventBus.on("compaction_end", ({ originalCount, newCount }) => {
|
|
201
|
+
bot.send(chatId, `✓ *Compacted* — ${originalCount} → ${newCount} messages`).catch((err) => {
|
|
202
|
+
log("WARN", "telegram", `Failed to send compaction message: ${err instanceof Error ? err.message : String(err)}`);
|
|
203
|
+
});
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
// ── Telegram command handlers ──────────────────────────
|
|
207
|
+
const TELEGRAM_COMMANDS = new Set([
|
|
208
|
+
"help",
|
|
209
|
+
"status",
|
|
210
|
+
"cancel",
|
|
211
|
+
"link",
|
|
212
|
+
"unlink",
|
|
213
|
+
"start",
|
|
214
|
+
"new",
|
|
215
|
+
"n",
|
|
216
|
+
"m",
|
|
217
|
+
"model",
|
|
218
|
+
]);
|
|
219
|
+
/** Chats waiting for a model number selection. */
|
|
220
|
+
const pendingModelSelections = new Map();
|
|
221
|
+
async function buildHelpText(chatId) {
|
|
222
|
+
const projectPath = resolveProjectPath(chatId);
|
|
223
|
+
const linked = config.chats[String(chatId)];
|
|
224
|
+
const state = chatStates.get(chatId);
|
|
225
|
+
const currentModel = state?.session.getState().model ?? options.model;
|
|
226
|
+
const modelInfo = MODELS.find((m) => m.id === currentModel);
|
|
227
|
+
let text = `*mragentix* — remote coding agent\n\n`;
|
|
228
|
+
text += `Project: \`${path.basename(projectPath)}\`\n`;
|
|
229
|
+
text += `Model: *${modelInfo?.name ?? currentModel}*\n\n`;
|
|
230
|
+
text += `*Telegram Commands*\n`;
|
|
231
|
+
text += `/m — switch model\n`;
|
|
232
|
+
text += `/link — switch project\n`;
|
|
233
|
+
text += `/unlink — unlink from project\n`;
|
|
234
|
+
text += `/status — current state\n`;
|
|
235
|
+
text += `/cancel — abort current task\n`;
|
|
236
|
+
text += `/help — this message\n`;
|
|
237
|
+
text += `\n*Session Commands*\n`;
|
|
238
|
+
text += `/compact — compress context\n`;
|
|
239
|
+
text += `/new — fresh session\n`;
|
|
240
|
+
text += `/session — list sessions\n`;
|
|
241
|
+
text += `/branch — fork conversation\n`;
|
|
242
|
+
text += `/branches — list branches\n`;
|
|
243
|
+
text += `/clear — clear session\n`;
|
|
244
|
+
text += `/settings — show/modify settings\n`;
|
|
245
|
+
// Prompt-template commands
|
|
246
|
+
if (PROMPT_COMMANDS.length > 0) {
|
|
247
|
+
text += `\n*Agent Commands*\n`;
|
|
248
|
+
for (const cmd of PROMPT_COMMANDS) {
|
|
249
|
+
text += `/${cmd.name} — ${cmd.description}\n`;
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
// Custom commands from .mragentix/commands/
|
|
253
|
+
const customCmds = await loadCustomCommands(projectPath);
|
|
254
|
+
if (customCmds.length > 0) {
|
|
255
|
+
text += `\n*Custom Commands*\n`;
|
|
256
|
+
for (const cmd of customCmds) {
|
|
257
|
+
text += `/${cmd.name} — ${cmd.description}\n`;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
if (!linked) {
|
|
261
|
+
text += `\n_Tip: send /link to connect this chat to a specific project._`;
|
|
262
|
+
}
|
|
263
|
+
text += `\nSend any message to start coding.`;
|
|
264
|
+
return text;
|
|
265
|
+
}
|
|
266
|
+
async function linkChat(chatId, projectPath, chatTitle) {
|
|
267
|
+
config.chats[String(chatId)] = projectPath;
|
|
268
|
+
await saveConfig(config);
|
|
269
|
+
// Dispose existing session if switching projects
|
|
270
|
+
const existing = chatStates.get(chatId);
|
|
271
|
+
if (existing && existing.cwd !== projectPath) {
|
|
272
|
+
await existing.session.dispose();
|
|
273
|
+
chatStates.delete(chatId);
|
|
274
|
+
}
|
|
275
|
+
const name = chatTitle ?? path.basename(projectPath);
|
|
276
|
+
await bot.send(chatId, `Linked *${name}* → \`${projectPath}\``);
|
|
277
|
+
}
|
|
278
|
+
bot.onAddedToGroup(async (chatId, chatTitle) => {
|
|
279
|
+
const groupName = chatTitle ?? "this group";
|
|
280
|
+
await bot.send(chatId, `*mragentix* joined *${groupName}*\n\n` +
|
|
281
|
+
`Send /link to connect to a project\n` +
|
|
282
|
+
`Send /help for all commands`);
|
|
283
|
+
log("INFO", "serve", `Bot added to group ${chatId}`, { title: chatTitle ?? "unknown" });
|
|
284
|
+
});
|
|
285
|
+
bot.onRemovedFromGroup(async (chatId) => {
|
|
286
|
+
// Clean up config and session when bot is removed from a group
|
|
287
|
+
const existing = chatStates.get(chatId);
|
|
288
|
+
if (existing) {
|
|
289
|
+
stopTyping(existing);
|
|
290
|
+
await existing.session.dispose();
|
|
291
|
+
chatStates.delete(chatId);
|
|
292
|
+
}
|
|
293
|
+
if (config.chats[String(chatId)]) {
|
|
294
|
+
delete config.chats[String(chatId)];
|
|
295
|
+
await saveConfig(config);
|
|
296
|
+
}
|
|
297
|
+
log("INFO", "serve", `Bot removed from group ${chatId} — unlinked`);
|
|
298
|
+
});
|
|
299
|
+
bot.onText(async (msg) => {
|
|
300
|
+
const { text, chatId } = msg;
|
|
301
|
+
// Check for pending selections (user sent a number after /link or /m)
|
|
302
|
+
const pendingProjects = pendingLinkSelections.get(chatId);
|
|
303
|
+
if (pendingProjects) {
|
|
304
|
+
pendingLinkSelections.delete(chatId);
|
|
305
|
+
const num = parseInt(text.trim(), 10);
|
|
306
|
+
if (isNaN(num) || num < 1 || num > pendingProjects.length) {
|
|
307
|
+
await bot.send(chatId, "Invalid selection. Send /link to try again.");
|
|
308
|
+
return;
|
|
309
|
+
}
|
|
310
|
+
const selected = pendingProjects[num - 1];
|
|
311
|
+
await linkChat(chatId, selected, msg.chatTitle);
|
|
312
|
+
return;
|
|
313
|
+
}
|
|
314
|
+
const pendingModels = pendingModelSelections.get(chatId);
|
|
315
|
+
if (pendingModels) {
|
|
316
|
+
pendingModelSelections.delete(chatId);
|
|
317
|
+
const num = parseInt(text.trim(), 10);
|
|
318
|
+
if (isNaN(num) || num < 1 || num > pendingModels.length) {
|
|
319
|
+
await bot.send(chatId, "Invalid selection. Send /m to try again.");
|
|
320
|
+
return;
|
|
321
|
+
}
|
|
322
|
+
const selected = pendingModels[num - 1];
|
|
323
|
+
const projectPath = resolveProjectPath(chatId);
|
|
324
|
+
const chatState = await getOrCreateChat(chatId, projectPath);
|
|
325
|
+
await chatState.session.switchModel(selected.provider, selected.id);
|
|
326
|
+
await bot.send(chatId, `Switched to *${selected.name}*`);
|
|
327
|
+
return;
|
|
328
|
+
}
|
|
329
|
+
if (!text.startsWith("/")) {
|
|
330
|
+
await handlePrompt(chatId, text);
|
|
331
|
+
return;
|
|
332
|
+
}
|
|
333
|
+
const parts = text.trim().split(/\s+/);
|
|
334
|
+
const cmd = parts[0].slice(1).toLowerCase().replace(/@\w+$/, ""); // strip /cmd@botname
|
|
335
|
+
const args = parts.slice(1).join(" ");
|
|
336
|
+
// ── Telegram-specific commands ──
|
|
337
|
+
if (cmd === "help") {
|
|
338
|
+
await bot.send(chatId, await buildHelpText(chatId));
|
|
339
|
+
return;
|
|
340
|
+
}
|
|
341
|
+
if (cmd === "status") {
|
|
342
|
+
const projectPath = resolveProjectPath(chatId);
|
|
343
|
+
const state = chatStates.get(chatId);
|
|
344
|
+
const linked = config.chats[String(chatId)];
|
|
345
|
+
const projectName = linked ? path.basename(projectPath) : "default";
|
|
346
|
+
if (!state) {
|
|
347
|
+
await bot.send(chatId, `*${projectName}*\n\n` +
|
|
348
|
+
`Path \`${projectPath}\`\n` +
|
|
349
|
+
`Session _not started_\n\n` +
|
|
350
|
+
`_Send a message to initialize._`);
|
|
351
|
+
return;
|
|
352
|
+
}
|
|
353
|
+
const sessionState = state.session.getState();
|
|
354
|
+
const modelInfo = MODELS.find((m) => m.id === sessionState.model);
|
|
355
|
+
const contextWindow = getContextWindow(sessionState.model);
|
|
356
|
+
const contextTokens = estimateConversationTokens(state.session.getMessages());
|
|
357
|
+
const statusPctRaw = (contextTokens / contextWindow) * 100;
|
|
358
|
+
const statusContextStr = statusPctRaw > 0 && statusPctRaw < 1 ? "<1" : String(Math.round(statusPctRaw));
|
|
359
|
+
await bot.send(chatId, `*${projectName}*\n\n` +
|
|
360
|
+
`Model *${modelInfo?.name ?? sessionState.model}*\n` +
|
|
361
|
+
`Messages ${sessionState.messageCount}\n` +
|
|
362
|
+
`Context ${statusContextStr}%\n` +
|
|
363
|
+
`Status ${state.isProcessing ? "_working..._" : "_idle_"}\n\n` +
|
|
364
|
+
`\`${sessionState.cwd}\``);
|
|
365
|
+
return;
|
|
366
|
+
}
|
|
367
|
+
if (cmd === "cancel") {
|
|
368
|
+
const state = chatStates.get(chatId);
|
|
369
|
+
if (state?.isProcessing) {
|
|
370
|
+
state.ac.abort();
|
|
371
|
+
// Replace AbortController so the session's next prompt gets a fresh signal
|
|
372
|
+
const newAc = new AbortController();
|
|
373
|
+
state.ac = newAc;
|
|
374
|
+
state.session.setSignal(newAc.signal);
|
|
375
|
+
await bot.send(chatId, "Cancelled.");
|
|
376
|
+
}
|
|
377
|
+
else {
|
|
378
|
+
await bot.send(chatId, "_Nothing to cancel._");
|
|
379
|
+
}
|
|
380
|
+
return;
|
|
381
|
+
}
|
|
382
|
+
if (cmd === "link") {
|
|
383
|
+
if (args && path.isAbsolute(args.trim())) {
|
|
384
|
+
// Direct path provided — link immediately
|
|
385
|
+
const projectPath = args.trim();
|
|
386
|
+
await linkChat(chatId, projectPath, msg.chatTitle);
|
|
387
|
+
return;
|
|
388
|
+
}
|
|
389
|
+
// No path — show project picker
|
|
390
|
+
const projects = await discoverProjects();
|
|
391
|
+
if (projects.length === 0) {
|
|
392
|
+
await bot.send(chatId, "_No projects found._\n\nUse /link `<path>` to link manually.");
|
|
393
|
+
return;
|
|
394
|
+
}
|
|
395
|
+
const current = config.chats[String(chatId)];
|
|
396
|
+
const lines = projects.map((p, i) => {
|
|
397
|
+
const name = path.basename(p);
|
|
398
|
+
const active = p === current ? " _current_" : "";
|
|
399
|
+
return `*${i + 1}.* *${name}*${active}\n \`${p}\``;
|
|
400
|
+
});
|
|
401
|
+
pendingLinkSelections.set(chatId, projects);
|
|
402
|
+
await bot.send(chatId, `*Select a project*\n\n${lines.join("\n\n")}\n\nSend the number to link.`);
|
|
403
|
+
return;
|
|
404
|
+
}
|
|
405
|
+
if (cmd === "unlink") {
|
|
406
|
+
if (!config.chats[String(chatId)]) {
|
|
407
|
+
await bot.send(chatId, "_This chat isn't linked to a project._");
|
|
408
|
+
return;
|
|
409
|
+
}
|
|
410
|
+
const existing = chatStates.get(chatId);
|
|
411
|
+
if (existing) {
|
|
412
|
+
await existing.session.dispose();
|
|
413
|
+
chatStates.delete(chatId);
|
|
414
|
+
}
|
|
415
|
+
delete config.chats[String(chatId)];
|
|
416
|
+
await saveConfig(config);
|
|
417
|
+
await bot.send(chatId, `✓ *Unlinked*\n\nDefault project: \`${path.basename(options.cwd)}\``);
|
|
418
|
+
return;
|
|
419
|
+
}
|
|
420
|
+
if (cmd === "start") {
|
|
421
|
+
await bot.send(chatId, await buildHelpText(chatId));
|
|
422
|
+
return;
|
|
423
|
+
}
|
|
424
|
+
if (cmd === "new" || cmd === "n") {
|
|
425
|
+
const projectPath = resolveProjectPath(chatId);
|
|
426
|
+
const state = await getOrCreateChat(chatId, projectPath);
|
|
427
|
+
await state.session.newSession();
|
|
428
|
+
await bot.send(chatId, "── *New session* ──");
|
|
429
|
+
return;
|
|
430
|
+
}
|
|
431
|
+
if (cmd === "m" || cmd === "model") {
|
|
432
|
+
const state = chatStates.get(chatId);
|
|
433
|
+
const currentModel = state?.session.getState().model;
|
|
434
|
+
if (args) {
|
|
435
|
+
// Direct switch: /m 3 (number) or /m opus (name fragment)
|
|
436
|
+
const num = parseInt(args, 10);
|
|
437
|
+
if (!isNaN(num) && num >= 1 && num <= MODELS.length) {
|
|
438
|
+
const selected = MODELS[num - 1];
|
|
439
|
+
const projectPath = resolveProjectPath(chatId);
|
|
440
|
+
const chatState = await getOrCreateChat(chatId, projectPath);
|
|
441
|
+
await chatState.session.switchModel(selected.provider, selected.id);
|
|
442
|
+
await bot.send(chatId, `Switched to *${selected.name}*`);
|
|
443
|
+
return;
|
|
444
|
+
}
|
|
445
|
+
// Try matching by name fragment
|
|
446
|
+
const lower = args.toLowerCase();
|
|
447
|
+
const match = MODELS.find((m) => m.name.toLowerCase().includes(lower) || m.id.toLowerCase().includes(lower));
|
|
448
|
+
if (match) {
|
|
449
|
+
const projectPath = resolveProjectPath(chatId);
|
|
450
|
+
const chatState = await getOrCreateChat(chatId, projectPath);
|
|
451
|
+
await chatState.session.switchModel(match.provider, match.id);
|
|
452
|
+
await bot.send(chatId, `Switched to *${match.name}*`);
|
|
453
|
+
return;
|
|
454
|
+
}
|
|
455
|
+
await bot.send(chatId, `No model matching "${args}". Send /m to see the list.`);
|
|
456
|
+
return;
|
|
457
|
+
}
|
|
458
|
+
// No args — show numbered list grouped by provider
|
|
459
|
+
let listText = "*Models*\n";
|
|
460
|
+
let lastProvider = "";
|
|
461
|
+
const modelList = [...MODELS];
|
|
462
|
+
modelList.forEach((m, i) => {
|
|
463
|
+
if (m.provider !== lastProvider) {
|
|
464
|
+
lastProvider = m.provider;
|
|
465
|
+
const providerName = m.provider === "anthropic"
|
|
466
|
+
? "Anthropic"
|
|
467
|
+
: m.provider === "openai"
|
|
468
|
+
? "OpenAI"
|
|
469
|
+
: m.provider === "glm"
|
|
470
|
+
? "Z.AI"
|
|
471
|
+
: "Moonshot";
|
|
472
|
+
listText += `\n_${providerName}_\n`;
|
|
473
|
+
}
|
|
474
|
+
const active = m.id === currentModel ? " ←" : "";
|
|
475
|
+
listText += ` *${i + 1}.* ${m.name}${active}\n`;
|
|
476
|
+
});
|
|
477
|
+
pendingModelSelections.set(chatId, modelList);
|
|
478
|
+
listText += `\nSend number or name to switch.`;
|
|
479
|
+
await bot.send(chatId, listText);
|
|
480
|
+
return;
|
|
481
|
+
}
|
|
482
|
+
// ── Forward to mragentix slash commands ──
|
|
483
|
+
if (!TELEGRAM_COMMANDS.has(cmd)) {
|
|
484
|
+
const projectPath = resolveProjectPath(chatId);
|
|
485
|
+
const state = await getOrCreateChat(chatId, projectPath);
|
|
486
|
+
if (state.isProcessing) {
|
|
487
|
+
await bot.send(chatId, "mragentix is still processing. Wait for the current task to finish, or send /cancel to interrupt.");
|
|
488
|
+
return;
|
|
489
|
+
}
|
|
490
|
+
state.isProcessing = true;
|
|
491
|
+
startTyping(state);
|
|
492
|
+
state.textBuffer = "";
|
|
493
|
+
state.activeTools = new Map();
|
|
494
|
+
try {
|
|
495
|
+
await state.session.prompt(text.trim());
|
|
496
|
+
await flushText(state);
|
|
497
|
+
}
|
|
498
|
+
catch (err) {
|
|
499
|
+
if (err instanceof Error && err.name === "AbortError") {
|
|
500
|
+
await bot.send(chatId, "Cancelled.");
|
|
501
|
+
}
|
|
502
|
+
else {
|
|
503
|
+
await bot.send(chatId, `Command failed: ${formatUserError(err)}`);
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
finally {
|
|
507
|
+
stopTyping(state);
|
|
508
|
+
state.isProcessing = false;
|
|
509
|
+
}
|
|
510
|
+
return;
|
|
511
|
+
}
|
|
512
|
+
});
|
|
513
|
+
// ── Prompt handler ──────────────────────────────────
|
|
514
|
+
async function handlePrompt(chatId, text) {
|
|
515
|
+
const projectPath = resolveProjectPath(chatId);
|
|
516
|
+
const state = await getOrCreateChat(chatId, projectPath);
|
|
517
|
+
if (state.isProcessing) {
|
|
518
|
+
await bot.send(chatId, "mragentix is still processing. Wait for the current task to finish, or send /cancel to interrupt.");
|
|
519
|
+
return;
|
|
520
|
+
}
|
|
521
|
+
state.isProcessing = true;
|
|
522
|
+
startTyping(state);
|
|
523
|
+
state.textBuffer = "";
|
|
524
|
+
state.activeTools = new Map();
|
|
525
|
+
try {
|
|
526
|
+
await state.session.prompt(text);
|
|
527
|
+
}
|
|
528
|
+
catch (err) {
|
|
529
|
+
if (err instanceof Error && err.name === "AbortError") {
|
|
530
|
+
await bot.send(chatId, "Cancelled.");
|
|
531
|
+
}
|
|
532
|
+
else {
|
|
533
|
+
await bot.send(chatId, `Error: ${formatUserError(err)}`);
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
finally {
|
|
537
|
+
stopTyping(state);
|
|
538
|
+
state.isProcessing = false;
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
// ── Initialize and start ─────────────────────────────
|
|
542
|
+
try {
|
|
543
|
+
// Clear terminal
|
|
544
|
+
process.stdout.write("\x1b[2J\x1b[3J\x1b[H");
|
|
545
|
+
const linkedCount = Object.keys(config.chats).length;
|
|
546
|
+
const modelInfo = MODELS.find((m) => m.id === options.model);
|
|
547
|
+
const modelName = modelInfo?.name ?? options.model;
|
|
548
|
+
const home = process.env.HOME ?? "";
|
|
549
|
+
const displayPath = home && options.cwd.startsWith(home) ? "~" + options.cwd.slice(home.length) : options.cwd;
|
|
550
|
+
// GG logo with gradient (matches Banner.tsx)
|
|
551
|
+
const LOGO = [
|
|
552
|
+
" ╭●╮ ",
|
|
553
|
+
" [◉‿◉]",
|
|
554
|
+
" ╰┬╯ ",
|
|
555
|
+
];
|
|
556
|
+
const GRADIENT = [
|
|
557
|
+
"#60a5fa",
|
|
558
|
+
"#6da1f9",
|
|
559
|
+
"#7a9df7",
|
|
560
|
+
"#8799f5",
|
|
561
|
+
"#9495f3",
|
|
562
|
+
"#a18ff1",
|
|
563
|
+
"#a78bfa",
|
|
564
|
+
"#a18ff1",
|
|
565
|
+
"#9495f3",
|
|
566
|
+
"#8799f5",
|
|
567
|
+
"#7a9df7",
|
|
568
|
+
"#6da1f9",
|
|
569
|
+
];
|
|
570
|
+
function gradientText(text) {
|
|
571
|
+
let colorIdx = 0;
|
|
572
|
+
return text
|
|
573
|
+
.split("")
|
|
574
|
+
.map((ch) => {
|
|
575
|
+
if (ch === " ")
|
|
576
|
+
return ch;
|
|
577
|
+
const color = GRADIENT[colorIdx++ % GRADIENT.length];
|
|
578
|
+
return chalk.hex(color)(ch);
|
|
579
|
+
})
|
|
580
|
+
.join("");
|
|
581
|
+
}
|
|
582
|
+
const GAP = " ";
|
|
583
|
+
console.log();
|
|
584
|
+
console.log(` ${gradientText(LOGO[0])}${GAP}` +
|
|
585
|
+
chalk.hex("#60a5fa").bold("MR Agentix Coder") +
|
|
586
|
+
chalk.hex("#6b7280")(` v${options.version}`) +
|
|
587
|
+
chalk.hex("#6b7280")(" · By ") +
|
|
588
|
+
chalk.white.bold("Michael Rathgeb"));
|
|
589
|
+
console.log(` ${gradientText(LOGO[1])}${GAP}` + chalk.hex("#a78bfa")(modelName));
|
|
590
|
+
console.log(` ${gradientText(LOGO[2])}${GAP}` + chalk.hex("#6b7280")(displayPath));
|
|
591
|
+
console.log();
|
|
592
|
+
console.log(chalk.hex("#6b7280")(" Mode ") +
|
|
593
|
+
chalk.hex("#a78bfa")("Telegram") +
|
|
594
|
+
chalk.hex("#6b7280")(" · User ") +
|
|
595
|
+
chalk.white(String(options.telegram.userId)) +
|
|
596
|
+
(linkedCount > 0 ? chalk.hex("#6b7280")(` · ${linkedCount} linked chat(s)`) : ""));
|
|
597
|
+
console.log();
|
|
598
|
+
console.log(chalk.hex("#4ade80")(" Ready. ") +
|
|
599
|
+
chalk.hex("#6b7280")("Open Telegram and message your bot."));
|
|
600
|
+
console.log();
|
|
601
|
+
console.log(chalk.hex("#6b7280")(" /help ") +
|
|
602
|
+
chalk.hex("#6b7280")("all commands") +
|
|
603
|
+
chalk.hex("#6b7280")(" /link ") +
|
|
604
|
+
chalk.hex("#6b7280")("switch project") +
|
|
605
|
+
chalk.hex("#6b7280")(" /m ") +
|
|
606
|
+
chalk.hex("#6b7280")("switch model"));
|
|
607
|
+
console.log();
|
|
608
|
+
// Handle graceful shutdown
|
|
609
|
+
const shutdown = async () => {
|
|
610
|
+
console.log("\nShutting down...");
|
|
611
|
+
bot.stop();
|
|
612
|
+
for (const state of chatStates.values()) {
|
|
613
|
+
stopTyping(state);
|
|
614
|
+
await state.session.dispose();
|
|
615
|
+
}
|
|
616
|
+
closeLogger();
|
|
617
|
+
process.exit(0);
|
|
618
|
+
};
|
|
619
|
+
process.on("SIGINT", shutdown);
|
|
620
|
+
process.on("SIGTERM", shutdown);
|
|
621
|
+
await bot.start();
|
|
622
|
+
}
|
|
623
|
+
catch (err) {
|
|
624
|
+
console.error(`Failed to start: ${formatUserError(err)}`);
|
|
625
|
+
for (const state of chatStates.values()) {
|
|
626
|
+
await state.session.dispose();
|
|
627
|
+
}
|
|
628
|
+
closeLogger();
|
|
629
|
+
process.exit(1);
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
// ── Helpers ───────────────────────────────────────────────
|
|
633
|
+
function formatArgs(args) {
|
|
634
|
+
const entries = Object.entries(args);
|
|
635
|
+
if (entries.length === 0)
|
|
636
|
+
return "";
|
|
637
|
+
const [_key, value] = entries[0];
|
|
638
|
+
const str = typeof value === "string" ? value : JSON.stringify(value);
|
|
639
|
+
const truncated = str.length > 60 ? str.slice(0, 57) + "..." : str;
|
|
640
|
+
// Strip backticks to avoid breaking Telegram markdown code spans
|
|
641
|
+
const safe = truncated.replace(/`/g, "'");
|
|
642
|
+
return `\`${safe}\``;
|
|
643
|
+
}
|
|
644
|
+
function formatDuration(ms) {
|
|
645
|
+
if (ms < 1000)
|
|
646
|
+
return `${ms}ms`;
|
|
647
|
+
return `${(ms / 1000).toFixed(1)}s`;
|
|
648
|
+
}
|
|
649
|
+
//# sourceMappingURL=serve-mode.js.map
|