profclaw 2.0.0 → 2.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +14 -2
- package/CHANGELOG.md +52 -0
- package/CONTRIBUTING.md +20 -0
- package/Dockerfile +39 -23
- package/README.md +178 -41
- package/config/pricing.yml +26 -2
- package/dist/agents/agent-summary.d.ts +44 -0
- package/dist/agents/agent-summary.js +176 -0
- package/dist/agents/auto-memory.d.ts +59 -0
- package/dist/agents/auto-memory.js +310 -0
- package/dist/agents/checkpoint-manager.d.ts +76 -0
- package/dist/agents/checkpoint-manager.js +156 -0
- package/dist/agents/circuit-breaker.d.ts +54 -0
- package/dist/agents/circuit-breaker.js +153 -0
- package/dist/agents/command-sandbox.d.ts +93 -0
- package/dist/agents/command-sandbox.js +235 -0
- package/dist/agents/context-compactor.d.ts +70 -0
- package/dist/agents/context-compactor.js +361 -0
- package/dist/agents/conversation-branch.d.ts +55 -0
- package/dist/agents/conversation-branch.js +115 -0
- package/dist/agents/error-recovery.d.ts +44 -0
- package/dist/agents/error-recovery.js +197 -0
- package/dist/agents/events.d.ts +76 -0
- package/dist/agents/events.js +8 -0
- package/dist/agents/executor-runner.d.ts +135 -0
- package/dist/agents/executor-runner.js +303 -0
- package/dist/agents/executor.d.ts +37 -1
- package/dist/agents/executor.js +606 -124
- package/dist/agents/file-snapshots.d.ts +72 -0
- package/dist/agents/file-snapshots.js +182 -0
- package/dist/agents/index.d.ts +2 -0
- package/dist/agents/orchestrator.d.ts +183 -0
- package/dist/agents/orchestrator.js +495 -0
- package/dist/agents/output-truncator.d.ts +59 -0
- package/dist/agents/output-truncator.js +128 -0
- package/dist/agents/permissions.d.ts +63 -0
- package/dist/agents/permissions.js +138 -0
- package/dist/agents/plan-mode.d.ts +71 -0
- package/dist/agents/plan-mode.js +186 -0
- package/dist/agents/prompt-suggestions.d.ts +33 -0
- package/dist/agents/prompt-suggestions.js +208 -0
- package/dist/agents/rate-limit-monitor.d.ts +56 -0
- package/dist/agents/rate-limit-monitor.js +224 -0
- package/dist/agents/receipt/receipt-cli.d.ts +43 -0
- package/dist/agents/receipt/receipt-cli.js +82 -0
- package/dist/agents/receipt/receipt-types.d.ts +136 -0
- package/dist/agents/receipt/receipt-types.js +19 -0
- package/dist/agents/receipt/receipt-verify.d.ts +19 -0
- package/dist/agents/receipt/receipt-verify.js +176 -0
- package/dist/agents/receipt/receipt-view.d.ts +29 -0
- package/dist/agents/receipt/receipt-view.js +227 -0
- package/dist/agents/receipt/receipt-writer.d.ts +47 -0
- package/dist/agents/receipt/receipt-writer.js +186 -0
- package/dist/agents/result-store.d.ts +43 -0
- package/dist/agents/result-store.js +145 -0
- package/dist/agents/session-diff.d.ts +49 -0
- package/dist/agents/session-diff.js +249 -0
- package/dist/agents/tool-loader.d.ts +65 -0
- package/dist/agents/tool-loader.js +273 -0
- package/dist/agents/tool-selector.d.ts +123 -0
- package/dist/agents/tool-selector.js +321 -0
- package/dist/agents/transcript.d.ts +96 -0
- package/dist/agents/transcript.js +267 -0
- package/dist/agents/verified-run-git.d.ts +49 -0
- package/dist/agents/verified-run-git.js +82 -0
- package/dist/agents/verified-run.d.ts +149 -0
- package/dist/agents/verified-run.js +402 -0
- package/dist/agents/verifier.d.ts +64 -0
- package/dist/agents/verifier.js +186 -0
- package/dist/agents/worktree-manager.d.ts +80 -0
- package/dist/agents/worktree-manager.js +203 -0
- package/dist/agents/worktree-tools.d.ts +47 -0
- package/dist/agents/worktree-tools.js +246 -0
- package/dist/auth/middleware.js +14 -0
- package/dist/chat/agentic-executor.d.ts +7 -0
- package/dist/chat/agentic-executor.js +263 -32
- package/dist/chat/conversations.d.ts +2 -0
- package/dist/chat/conversations.js +8 -0
- package/dist/chat/execution/executor.d.ts +8 -0
- package/dist/chat/execution/executor.js +157 -103
- package/dist/chat/execution/index.js +5 -1
- package/dist/chat/execution/sandbox.d.ts +8 -0
- package/dist/chat/execution/sandbox.js +25 -1
- package/dist/chat/execution/tool-router.js +40 -14
- package/dist/chat/execution/tools/canvas.d.ts +2 -2
- package/dist/chat/execution/tools/code-tools.d.ts +66 -0
- package/dist/chat/execution/tools/code-tools.js +353 -0
- package/dist/chat/execution/tools/complete-task.d.ts +2 -2
- package/dist/chat/execution/tools/cron-tool.d.ts +26 -10
- package/dist/chat/execution/tools/cron-tool.js +48 -3
- package/dist/chat/execution/tools/decompose-task.d.ts +58 -0
- package/dist/chat/execution/tools/decompose-task.js +166 -0
- package/dist/chat/execution/tools/exec.d.ts +5 -2
- package/dist/chat/execution/tools/exec.js +294 -155
- package/dist/chat/execution/tools/feed-tools.d.ts +77 -0
- package/dist/chat/execution/tools/feed-tools.js +142 -0
- package/dist/chat/execution/tools/file-ops.d.ts +1 -1
- package/dist/chat/execution/tools/github.d.ts +2 -2
- package/dist/chat/execution/tools/index.d.ts +14 -2
- package/dist/chat/execution/tools/index.js +86 -12
- package/dist/chat/execution/tools/integrations.d.ts +8 -8
- package/dist/chat/execution/tools/multi-patch.d.ts +53 -0
- package/dist/chat/execution/tools/multi-patch.js +373 -0
- package/dist/chat/execution/tools/openai-image-gen.d.ts +2 -2
- package/dist/chat/execution/tools/plan-tools.d.ts +80 -0
- package/dist/chat/execution/tools/plan-tools.js +134 -0
- package/dist/chat/execution/tools/profclaw-ops.d.ts +6 -6
- package/dist/chat/execution/tools/repl-tool.d.ts +46 -0
- package/dist/chat/execution/tools/repl-tool.js +207 -0
- package/dist/chat/execution/tools/sessions-send.d.ts +2 -2
- package/dist/chat/execution/tools/slack-actions.d.ts +2 -2
- package/dist/chat/execution/tools/system.d.ts +4 -4
- package/dist/chat/execution/tools/todo-tool.d.ts +72 -0
- package/dist/chat/execution/tools/todo-tool.js +152 -0
- package/dist/chat/execution/tools/tool-search.d.ts +50 -0
- package/dist/chat/execution/tools/tool-search.js +155 -0
- package/dist/chat/execution/tools/tts-speak.d.ts +2 -2
- package/dist/chat/execution/types.d.ts +21 -14
- package/dist/chat/execution/workflows/executor.d.ts +11 -0
- package/dist/chat/execution/workflows/executor.js +99 -1
- package/dist/chat/execution/workflows/types.d.ts +35 -2
- package/dist/chat/format/index.d.ts +1 -0
- package/dist/chat/format/index.js +1 -0
- package/dist/chat/format/markdown-convert.d.ts +23 -0
- package/dist/chat/format/markdown-convert.js +149 -0
- package/dist/chat/index.d.ts +1 -1
- package/dist/chat/index.js +1 -1
- package/dist/chat/message-handler.js +58 -6
- package/dist/chat/meta-tool-handlers.d.ts +18 -0
- package/dist/chat/meta-tool-handlers.js +51 -0
- package/dist/chat/proactive/index.d.ts +62 -0
- package/dist/chat/proactive/index.js +147 -0
- package/dist/chat/prompt-adapter.js +2 -0
- package/dist/chat/providers/irc/index.d.ts +2 -2
- package/dist/chat/providers/telegram/index.d.ts +2 -0
- package/dist/chat/providers/telegram/index.js +21 -2
- package/dist/chat/system-prompts.d.ts +3 -3
- package/dist/chat/system-prompts.js +121 -61
- package/dist/chat/tool-handler.d.ts +2 -0
- package/dist/chat/tool-handler.js +47 -3
- package/dist/chat/tools.d.ts +6 -6
- package/dist/cli/commands/auth.js +64 -1
- package/dist/cli/commands/chat.js +1327 -138
- package/dist/cli/commands/doctor.js +222 -16
- package/dist/cli/commands/history.d.ts +3 -0
- package/dist/cli/commands/history.js +138 -0
- package/dist/cli/commands/import.d.ts +44 -0
- package/dist/cli/commands/import.js +526 -0
- package/dist/cli/commands/init.d.ts +13 -0
- package/dist/cli/commands/init.js +381 -0
- package/dist/cli/commands/onboard.js +210 -30
- package/dist/cli/commands/plan.d.ts +13 -0
- package/dist/cli/commands/plan.js +184 -0
- package/dist/cli/commands/receipt.d.ts +7 -0
- package/dist/cli/commands/receipt.js +90 -0
- package/dist/cli/commands/run.d.ts +28 -0
- package/dist/cli/commands/run.js +204 -0
- package/dist/cli/commands/serve.d.ts +7 -0
- package/dist/cli/commands/serve.js +77 -18
- package/dist/cli/commands/setup.js +84 -3
- package/dist/cli/commands/status.js +54 -0
- package/dist/cli/commands/tools.js +13 -13
- package/dist/cli/commands/tui.js +26 -1
- package/dist/cli/index.js +23 -0
- package/dist/cli/ink/App.d.ts +13 -0
- package/dist/cli/ink/App.js +6 -0
- package/dist/cli/ink/ChatApp.d.ts +60 -0
- package/dist/cli/ink/ChatApp.js +325 -0
- package/dist/cli/ink/DashboardApp.d.ts +3 -0
- package/dist/cli/ink/DashboardApp.js +143 -0
- package/dist/cli/ink/components/AgentStatus.d.ts +17 -0
- package/dist/cli/ink/components/AgentStatus.js +33 -0
- package/dist/cli/ink/components/ChannelList.d.ts +17 -0
- package/dist/cli/ink/components/ChannelList.js +33 -0
- package/dist/cli/ink/components/ConnectionStatus.d.ts +19 -0
- package/dist/cli/ink/components/ConnectionStatus.js +50 -0
- package/dist/cli/ink/components/CostBar.d.ts +19 -0
- package/dist/cli/ink/components/CostBar.js +35 -0
- package/dist/cli/ink/components/HookStatus.d.ts +15 -0
- package/dist/cli/ink/components/HookStatus.js +7 -0
- package/dist/cli/ink/components/PermissionPrompt.d.ts +21 -0
- package/dist/cli/ink/components/PermissionPrompt.js +51 -0
- package/dist/cli/ink/components/PlanView.d.ts +23 -0
- package/dist/cli/ink/components/PlanView.js +26 -0
- package/dist/cli/ink/components/ProviderList.d.ts +16 -0
- package/dist/cli/ink/components/ProviderList.js +16 -0
- package/dist/cli/ink/components/SessionHeader.d.ts +15 -0
- package/dist/cli/ink/components/SessionHeader.js +15 -0
- package/dist/cli/ink/components/StreamingMessage.d.ts +20 -0
- package/dist/cli/ink/components/StreamingMessage.js +27 -0
- package/dist/cli/ink/components/SuggestionBar.d.ts +15 -0
- package/dist/cli/ink/components/SuggestionBar.js +28 -0
- package/dist/cli/ink/components/SystemHealth.d.ts +20 -0
- package/dist/cli/ink/components/SystemHealth.js +39 -0
- package/dist/cli/ink/components/TaskList.d.ts +17 -0
- package/dist/cli/ink/components/TaskList.js +59 -0
- package/dist/cli/ink/components/ToolCall.d.ts +17 -0
- package/dist/cli/ink/components/ToolCall.js +43 -0
- package/dist/cli/ink/index.d.ts +23 -0
- package/dist/cli/ink/index.js +15 -0
- package/dist/cli/ink/keybindings.d.ts +35 -0
- package/dist/cli/ink/keybindings.js +105 -0
- package/dist/cli/ink/markdown-renderer.d.ts +47 -0
- package/dist/cli/ink/markdown-renderer.js +380 -0
- package/dist/cli/ink/output-styles.d.ts +39 -0
- package/dist/cli/ink/output-styles.js +119 -0
- package/dist/cli/interactive/auto-serve.d.ts +38 -0
- package/dist/cli/interactive/auto-serve.js +209 -0
- package/dist/cli/interactive/index.d.ts +25 -0
- package/dist/cli/interactive/index.js +23 -0
- package/dist/cli/interactive/picker.d.ts +28 -0
- package/dist/cli/interactive/picker.js +153 -0
- package/dist/cli/interactive/renderer.d.ts +26 -0
- package/dist/cli/interactive/renderer.js +555 -0
- package/dist/cli/interactive/repl.d.ts +14 -0
- package/dist/cli/interactive/repl.js +1516 -0
- package/dist/cli/interactive/stream-client.d.ts +59 -0
- package/dist/cli/interactive/stream-client.js +506 -0
- package/dist/cli/interactive/types.d.ts +121 -0
- package/dist/cli/interactive/types.js +10 -0
- package/dist/cli/utils/api.d.ts +9 -0
- package/dist/cli/utils/api.js +58 -2
- package/dist/costs/token-tracker.d.ts +10 -1
- package/dist/costs/token-tracker.js +37 -5
- package/dist/cron/natural-language.d.ts +54 -0
- package/dist/cron/natural-language.js +569 -0
- package/dist/cron/scheduler.d.ts +34 -4
- package/dist/cron/scheduler.js +141 -9
- package/dist/cron/templates.d.ts +1 -1
- package/dist/cron/templates.js +219 -0
- package/dist/feeds/feed-engine.d.ts +149 -0
- package/dist/feeds/feed-engine.js +600 -0
- package/dist/feeds/index.d.ts +9 -0
- package/dist/feeds/index.js +8 -0
- package/dist/gateway/router.js +6 -1
- package/dist/hooks/built-in/audit-log.d.ts +11 -0
- package/dist/hooks/built-in/audit-log.js +84 -0
- package/dist/hooks/built-in/cost-warning.d.ts +10 -0
- package/dist/hooks/built-in/cost-warning.js +59 -0
- package/dist/hooks/built-in/dangerous-tool.d.ts +32 -0
- package/dist/hooks/built-in/dangerous-tool.js +80 -0
- package/dist/hooks/built-in/index.d.ts +14 -0
- package/dist/hooks/built-in/index.js +20 -0
- package/dist/hooks/index.d.ts +3 -0
- package/dist/hooks/index.js +6 -0
- package/dist/hooks/loader.d.ts +17 -0
- package/dist/hooks/loader.js +142 -0
- package/dist/hooks/registry.d.ts +62 -0
- package/dist/hooks/registry.js +127 -0
- package/dist/integrations/web-search.js +6 -3
- package/dist/memory/index.d.ts +1 -0
- package/dist/memory/index.js +2 -0
- package/dist/memory/memory-service.js +14 -13
- package/dist/memory/observational.d.ts +62 -0
- package/dist/memory/observational.js +396 -0
- package/dist/middleware/content-filter.d.ts +22 -0
- package/dist/middleware/content-filter.js +69 -0
- package/dist/middleware/request-validator.d.ts +159 -0
- package/dist/middleware/request-validator.js +93 -0
- package/dist/plugins/sdk.d.ts +22 -0
- package/dist/plugins/sdk.js +17 -1
- package/dist/projects/types.d.ts +10 -10
- package/dist/providers/ai-sdk.d.ts +11 -0
- package/dist/providers/ai-sdk.js +111 -56
- package/dist/providers/core/models.js +114 -6
- package/dist/providers/core/types.d.ts +7 -0
- package/dist/providers/index.d.ts +1 -0
- package/dist/providers/index.js +1 -0
- package/dist/providers/prompt-cache.d.ts +68 -0
- package/dist/providers/prompt-cache.js +165 -0
- package/dist/providers/smart-router.d.ts +118 -0
- package/dist/providers/smart-router.js +693 -0
- package/dist/providers/types.d.ts +16 -16
- package/dist/routes/agents.js +50 -0
- package/dist/routes/auth.js +8 -1
- package/dist/routes/chat.js +280 -18
- package/dist/routes/costs.js +32 -0
- package/dist/routes/cron.js +80 -5
- package/dist/routes/feeds.d.ts +10 -0
- package/dist/routes/feeds.js +168 -0
- package/dist/routes/mcp.js +21 -0
- package/dist/routes/memory.js +130 -0
- package/dist/routes/skills.js +129 -0
- package/dist/routes/teams.d.ts +9 -0
- package/dist/routes/teams.js +210 -0
- package/dist/routes/tools.js +14 -0
- package/dist/routes/users.js +2 -0
- package/dist/server/route-loader.js +3 -1
- package/dist/server/stream-bridge.d.ts +19 -0
- package/dist/server/stream-bridge.js +38 -0
- package/dist/server.js +313 -36
- package/dist/skills/marketplace.d.ts +87 -0
- package/dist/skills/marketplace.js +268 -0
- package/dist/storage/index.d.ts +14 -0
- package/dist/storage/index.js +64 -3
- package/dist/storage/schema.d.ts +4 -4
- package/dist/storage/schema.js +1 -1
- package/dist/teams/index.d.ts +110 -0
- package/dist/teams/index.js +365 -0
- package/dist/tickets/types.d.ts +39 -39
- package/dist/types/summary.d.ts +5 -5
- package/dist/utils/auto-update.d.ts +23 -0
- package/dist/utils/auto-update.js +157 -0
- package/dist/utils/offline-detect.d.ts +55 -0
- package/dist/utils/offline-detect.js +121 -0
- package/dist/utils/pid-file.d.ts +36 -0
- package/dist/utils/pid-file.js +125 -0
- package/dist/utils/prevent-sleep.d.ts +27 -0
- package/dist/utils/prevent-sleep.js +95 -0
- package/dist/utils/sanitizer.d.ts +57 -0
- package/dist/utils/sanitizer.js +174 -0
- package/docker-compose.yml +13 -137
- package/package.json +31 -6
- package/skills/deploy-cloudflare/SKILL.md +62 -0
- package/skills/deploy-vercel/SKILL.md +67 -0
- package/skills/docker-deploy/SKILL.md +158 -0
- package/skills/full-stack-builder/SKILL.md +92 -0
- package/skills/humanizer/SKILL.md +488 -0
- package/skills/profclaw-assistant/SKILL.md +85 -56
- package/ui/dist/assets/ActivityView-Da6HQ8ws.js +1 -0
- package/ui/dist/assets/AgentList-H58R0kX3.js +1 -0
- package/ui/dist/assets/AnalyticsDashboard-B28AeRsc.js +1 -0
- package/ui/dist/assets/AreaChart-DwLzeAQ8.js +1 -0
- package/ui/dist/assets/CartesianChart-piKQsTAR.js +36 -0
- package/ui/dist/assets/ChatView-Dbj8rxU5.js +10 -0
- package/ui/dist/assets/CostsDashboard-C6F5df0F.js +1 -0
- package/ui/dist/assets/EstimateSelect-wga0rUKX.js +1 -0
- package/ui/dist/assets/FeedDashboard-Ef6FEzEf.js +1 -0
- package/ui/dist/assets/FloatingChatbot-0yhkUeCq.js +2 -0
- package/ui/dist/assets/InviteCodeManagement-tUXfx4Bc.js +2 -0
- package/ui/dist/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
- package/ui/dist/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
- package/ui/dist/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
- package/ui/dist/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
- package/ui/dist/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
- package/ui/dist/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
- package/ui/dist/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
- package/ui/dist/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
- package/ui/dist/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
- package/ui/dist/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
- package/ui/dist/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
- package/ui/dist/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
- package/ui/dist/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
- package/ui/dist/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
- package/ui/dist/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
- package/ui/dist/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
- package/ui/dist/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
- package/ui/dist/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
- package/ui/dist/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
- package/ui/dist/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
- package/ui/dist/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
- package/ui/dist/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
- package/ui/dist/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
- package/ui/dist/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
- package/ui/dist/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
- package/ui/dist/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
- package/ui/dist/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
- package/ui/dist/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
- package/ui/dist/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
- package/ui/dist/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
- package/ui/dist/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
- package/ui/dist/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
- package/ui/dist/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
- package/ui/dist/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
- package/ui/dist/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
- package/ui/dist/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
- package/ui/dist/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
- package/ui/dist/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
- package/ui/dist/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
- package/ui/dist/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
- package/ui/dist/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
- package/ui/dist/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
- package/ui/dist/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
- package/ui/dist/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
- package/ui/dist/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
- package/ui/dist/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
- package/ui/dist/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
- package/ui/dist/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
- package/ui/dist/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
- package/ui/dist/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
- package/ui/dist/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
- package/ui/dist/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
- package/ui/dist/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
- package/ui/dist/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
- package/ui/dist/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
- package/ui/dist/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
- package/ui/dist/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
- package/ui/dist/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
- package/ui/dist/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
- package/ui/dist/assets/MarketplacePage-DGrLtolR.js +1 -0
- package/ui/dist/assets/{ProjectDetail--gPfvATB.js → ProjectDetail-BgWvA6UP.js} +2 -2
- package/ui/dist/assets/ProjectIcon-TDuliqwg.js +1 -0
- package/ui/dist/assets/ProjectList-DXgM4187.js +1 -0
- package/ui/dist/assets/{Settings-1kaf7VHE.js → Settings-xA8Zhi3p.js} +3 -3
- package/ui/dist/assets/StatusIndicator-B8vfFAxg.js +1 -0
- package/ui/dist/assets/{SummaryDetail-DV3AmONk.js → SummaryDetail-eedRfTtF.js} +2 -2
- package/ui/dist/assets/SummaryList-CLNX2P84.js +1 -0
- package/ui/dist/assets/TaskDetail-BtWclNiR.js +1 -0
- package/ui/dist/assets/TaskList-JjODAgSc.js +1 -0
- package/ui/dist/assets/TeamsPage-CBK5iAyx.js +1 -0
- package/ui/dist/assets/TicketBoard-C9aJNNYp.js +1 -0
- package/ui/dist/assets/TicketDetail-CV5JmL31.js +1 -0
- package/ui/dist/assets/TicketList-68V4lzUz.js +1 -0
- package/ui/dist/assets/UserManagement-DKTb6UpE.js +2 -0
- package/ui/dist/assets/ViewSwitcher-BvdQht2Y.js +1 -0
- package/ui/dist/assets/alert-dialog-O6qBOv_f.js +1 -0
- package/ui/dist/assets/{archive-BsLa7brF.js → archive-CX7UvZpf.js} +1 -1
- package/ui/dist/assets/badge-BbfnwDJP.js +1 -0
- package/ui/dist/assets/{bug-CmZI7jqM.js → bug-3WX0394-.js} +1 -1
- package/ui/dist/assets/{calendar-Bf0t2B82.js → calendar-buq77TaS.js} +1 -1
- package/ui/dist/assets/{chevron-up-CoUsOvZj.js → chevron-up-4ymsBJRo.js} +1 -1
- package/ui/dist/assets/{circle-x-Dgw11LgT.js → circle-x-ByXtwR6Y.js} +1 -1
- package/ui/dist/assets/constants-CVdDh7p0.js +1 -0
- package/ui/dist/assets/{cpu-DiPMQICV.js → cpu-CiuoCeDY.js} +1 -1
- package/ui/dist/assets/{database-BwTfupDi.js → database-BWXSBg5a.js} +1 -1
- package/ui/dist/assets/dialog-lDg4NvMV.js +1 -0
- package/ui/dist/assets/dollar-sign-Dmijd6DP.js +1 -0
- package/ui/dist/assets/{ellipsis-UJx4Xnf6.js → ellipsis-vT-5SVIp.js} +1 -1
- package/ui/dist/assets/{ellipsis-vertical-DoULYEKn.js → ellipsis-vertical-B4tAX_bL.js} +1 -1
- package/ui/dist/assets/feature-markdown-DBo5Q7uq.js +289 -0
- package/ui/dist/assets/{file-code-B2UrJLwi.js → file-code-ChOWdKXf.js} +1 -1
- package/ui/dist/assets/{folder-open-BJi577JH.js → folder-open-CkOUbIiP.js} +1 -1
- package/ui/dist/assets/{funnel-PkaD_HSR.js → funnel-uZkoSPP-.js} +1 -1
- package/ui/dist/assets/{git-branch-C_K30am0.js → git-branch-CwvUxj7C.js} +1 -1
- package/ui/dist/assets/{git-commit-horizontal-IT6ecxWQ.js → git-commit-horizontal-lxPzCvhD.js} +1 -1
- package/ui/dist/assets/{globe-f-jjCa_g.js → globe-D_WpJdsj.js} +1 -1
- package/ui/dist/assets/{hash-DNEv8Elo.js → hash-CA0hJ7vh.js} +1 -1
- package/ui/dist/assets/{history-BQSBo_1Q.js → history-CEWMLELs.js} +1 -1
- package/ui/dist/assets/inbox-ehtOptTV.js +1 -0
- package/ui/dist/assets/{index-nS3EErDg.js → index-C1rhbml4.js} +3 -3
- package/ui/dist/assets/index-CR8gfCHv.js +1 -0
- package/ui/dist/assets/index-DVXMpWai.js +1 -0
- package/ui/dist/assets/index-DaDJMM2v.js +1 -0
- package/ui/dist/assets/index-Djdq_0xu.js +1 -0
- package/ui/dist/assets/index-M46Gcb8K.css +1 -0
- package/ui/dist/assets/index-sEBN7w8J.js +109 -0
- package/ui/dist/assets/layers-C6Mhf8Nk.js +1 -0
- package/ui/dist/assets/{layout-dashboard-CcKt1hXw.js → layout-dashboard-BRUM0kpT.js} +1 -1
- package/ui/dist/assets/{lightbulb-Jhp7FvbU.js → lightbulb-CN2q1O5l.js} +1 -1
- package/ui/dist/assets/{link-2-DdO7ostF.js → link-2-CC4E28yJ.js} +1 -1
- package/ui/dist/assets/markdown-renderer-C6ENbB0u.js +10 -0
- package/ui/dist/assets/markdown-renderer-CfVKi3_s.css +1 -0
- package/ui/dist/assets/{message-square-CBgH65X7.js → message-square-Bbb241am.js} +1 -1
- package/ui/dist/assets/package-CwT3IzFx.js +1 -0
- package/ui/dist/assets/{pencil-CYXCEPQh.js → pencil-CDmiHzoj.js} +1 -1
- package/ui/dist/assets/{play-d1ONaH0-.js → play-tjy5jMQX.js} +1 -1
- package/ui/dist/assets/popover-CFHZf3pE.js +1 -0
- package/ui/dist/assets/progress-BboUHuLf.js +1 -0
- package/ui/dist/assets/{rocket-DhvUetsk.js → rocket--8ZHgdXJ.js} +1 -1
- package/ui/dist/assets/select-n108rXny.js +1 -0
- package/ui/dist/assets/{send-P0r5D7td.js → send-Cu7MR2Qh.js} +1 -1
- package/ui/dist/assets/server-DmodxZp-.js +1 -0
- package/ui/dist/assets/{settings-2-ocj5uHGx.js → settings-2-CkRNqkxj.js} +1 -1
- package/ui/dist/assets/sheet-7aUJkyzU.js +1 -0
- package/ui/dist/assets/{shield-check-DfVdE34l.js → shield-check-ViI3nMKE.js} +1 -1
- package/ui/dist/assets/{shield-off-8l0J6R-8.js → shield-off-DN3tagkn.js} +1 -1
- package/ui/dist/assets/skeleton-C0E1Nfro.js +1 -0
- package/ui/dist/assets/{smartphone-77_g3SQn.js → smartphone-5FghiXpA.js} +1 -1
- package/ui/dist/assets/{square-Ckzsr3Rn.js → square-DiNSx8K7.js} +1 -1
- package/ui/dist/assets/star-DhdFVidS.js +1 -0
- package/ui/dist/assets/switch-CIgVbZqQ.js +1 -0
- package/ui/dist/assets/table-BC56FVMV.js +1 -0
- package/ui/dist/assets/{tag-C35mgoEv.js → tag-CH_vQliw.js} +1 -1
- package/ui/dist/assets/textarea-CxDiKFXZ.js +1 -0
- package/ui/dist/assets/{timer-DHJBS2w1.js → timer-CdGVTb60.js} +1 -1
- package/ui/dist/assets/tooltip-BuW9A5UO.js +1 -0
- package/ui/dist/assets/{trash-2-keO5tKPE.js → trash-2-CucZJL0N.js} +1 -1
- package/ui/dist/assets/trending-down-BCezC1z2.js +1 -0
- package/ui/dist/assets/{trending-up-BBv8KbrY.js → trending-up-C5OYX2k2.js} +1 -1
- package/ui/dist/assets/vendor-query-C0p7b53x.js +4 -0
- package/ui/dist/assets/vendor-react-Mc5_kfYG.js +12 -0
- package/ui/dist/assets/vendor-ui-CXPAUBFv.js +51 -0
- package/ui/dist/assets/{wand-sparkles-BusQ52ZK.js → wand-sparkles-BaH6pJnc.js} +1 -1
- package/ui/dist/assets/{wrench-02YaOSiK.js → wrench-CjxjP6ok.js} +1 -1
- package/ui/dist/index.html +5 -2
- package/ui/dist/assets/ActivityView-BeshZXmE.js +0 -1
- package/ui/dist/assets/AgentList-QVHeldPi.js +0 -1
- package/ui/dist/assets/AnalyticsDashboard-C9R97dXE.js +0 -1
- package/ui/dist/assets/AreaChart-B73gaiVQ.js +0 -1
- package/ui/dist/assets/CartesianChart-CXYL2R-A.js +0 -36
- package/ui/dist/assets/ChatView-qjZErlrp.js +0 -10
- package/ui/dist/assets/CostsDashboard-O4DCLy1i.js +0 -1
- package/ui/dist/assets/EstimateSelect-1hQf4Osk.js +0 -1
- package/ui/dist/assets/FloatingChatbot-BZBzrJxd.js +0 -2
- package/ui/dist/assets/InviteCodeManagement-LEoGqYeA.js +0 -2
- package/ui/dist/assets/ProjectIcon-Chd_ofsw.js +0 -1
- package/ui/dist/assets/ProjectList-BvUfVB6c.js +0 -4
- package/ui/dist/assets/StatusIndicator-pRfkNcdV.js +0 -1
- package/ui/dist/assets/SummaryList-B6kXiTxL.js +0 -1
- package/ui/dist/assets/TaskDetail-CV6CzbOS.js +0 -1
- package/ui/dist/assets/TaskList-DL7brQKd.js +0 -1
- package/ui/dist/assets/TicketBoard-CrkkFj7C.js +0 -1
- package/ui/dist/assets/TicketDetail-hnnYclpD.js +0 -1
- package/ui/dist/assets/TicketList-CsDAyQCL.js +0 -1
- package/ui/dist/assets/UserManagement-BGFQyTSr.js +0 -2
- package/ui/dist/assets/ViewSwitcher-CnL0OqA8.js +0 -1
- package/ui/dist/assets/alert-dialog-SKM6Gjz4.js +0 -7
- package/ui/dist/assets/badge-CVHH1a-v.js +0 -1
- package/ui/dist/assets/brain-6o_RHVpe.js +0 -1
- package/ui/dist/assets/constants-Q5Zivl-a.js +0 -1
- package/ui/dist/assets/dialog-BUqN9Psj.js +0 -1
- package/ui/dist/assets/index-BUmnwPQr.js +0 -1
- package/ui/dist/assets/index-BfF5G4Cw.js +0 -1
- package/ui/dist/assets/index-C8N375c2.js +0 -1
- package/ui/dist/assets/index-CuxnqVVz.css +0 -1
- package/ui/dist/assets/index-CzMM3QOk.js +0 -1
- package/ui/dist/assets/index-lJlNPFVJ.js +0 -67
- package/ui/dist/assets/layers-jFqVrWMD.js +0 -1
- package/ui/dist/assets/markdown-renderer-n1ToC4XQ.js +0 -36
- package/ui/dist/assets/popover-CrmZgoWu.js +0 -1
- package/ui/dist/assets/progress-uv4SPkL5.js +0 -1
- package/ui/dist/assets/select-CeQ8AHGy.js +0 -1
- package/ui/dist/assets/server-CVHTZB72.js +0 -1
- package/ui/dist/assets/sheet-DuQExSho.js +0 -1
- package/ui/dist/assets/skeleton-TFiFJ3nB.js +0 -1
- package/ui/dist/assets/switch-CAePkd6k.js +0 -1
- package/ui/dist/assets/table-ZjAZ7hkt.js +0 -1
- package/ui/dist/assets/textarea-DsVPnSgR.js +0 -1
- package/ui/dist/assets/tooltip-BYmQ331W.js +0 -1
package/dist/server.js
CHANGED
|
@@ -6,6 +6,7 @@ import { createServer } from 'net';
|
|
|
6
6
|
// Core imports - keep static only for truly essential boot utilities
|
|
7
7
|
import { loadConfig } from './utils/config-loader.js';
|
|
8
8
|
import { createContextualLogger } from './utils/logger.js';
|
|
9
|
+
import { writePidFile, removePidFile } from './utils/pid-file.js';
|
|
9
10
|
const appLog = createContextualLogger('Server');
|
|
10
11
|
import { validateEnvironment, getConfiguredIntegrations, getConfiguredAIProviders } from './utils/env-validator.js';
|
|
11
12
|
import { initApiTokensTable, tokenAuthMiddleware } from './auth/api-tokens.js';
|
|
@@ -14,7 +15,14 @@ import { rateLimit } from './middleware/rate-limit.js';
|
|
|
14
15
|
import { CreateTaskSchema } from './types/task.js';
|
|
15
16
|
import { getMode, getModeLabel, hasCapability, getCapabilities } from './core/deployment.js';
|
|
16
17
|
import { getRouteDefinitionsForMode, registerRouteModules } from './server/route-loader.js';
|
|
18
|
+
import { validateBody, GatewayExecuteSchema } from './middleware/request-validator.js';
|
|
17
19
|
const VERSION = '2.0.0';
|
|
20
|
+
// Module-level startup state flags
|
|
21
|
+
let degradedMode = false;
|
|
22
|
+
let inMemoryStorageReminderInterval = null;
|
|
23
|
+
// Runtime tracking state
|
|
24
|
+
let runningPort = 0;
|
|
25
|
+
let lastErrorMessage;
|
|
18
26
|
let cachedSettings = null;
|
|
19
27
|
function getAppSettings() {
|
|
20
28
|
if (!cachedSettings) {
|
|
@@ -87,6 +95,13 @@ app.use('*', cors({
|
|
|
87
95
|
// Authentication middleware — applied to all /api/* routes
|
|
88
96
|
// Skips public routes (auth, setup, webhooks, messaging channels)
|
|
89
97
|
app.use('/api/*', authMiddleware());
|
|
98
|
+
// WS-1.4: In-memory storage warning header — set on every response when storage is ephemeral
|
|
99
|
+
app.use('*', async (c, next) => {
|
|
100
|
+
await next();
|
|
101
|
+
if (degradedMode) {
|
|
102
|
+
c.res.headers.set('X-ProfClaw-Storage', 'ephemeral');
|
|
103
|
+
}
|
|
104
|
+
});
|
|
90
105
|
// HTTP rate limiting (sliding window, per-IP)
|
|
91
106
|
const apiRateLimiter = rateLimit({
|
|
92
107
|
maxRequests: parseInt(process.env['API_RATE_LIMIT'] ?? '100', 10),
|
|
@@ -100,22 +115,199 @@ app.use('/api/*', apiRateLimiter);
|
|
|
100
115
|
app.use('/auth/*', authRateLimiter);
|
|
101
116
|
// === Core Routes ===
|
|
102
117
|
// Health check
|
|
118
|
+
const serverStartTime = Date.now();
|
|
119
|
+
async function checkDatabaseHealth() {
|
|
120
|
+
const start = Date.now();
|
|
121
|
+
try {
|
|
122
|
+
const { getDb } = await import('./storage/index.js');
|
|
123
|
+
const db = getDb();
|
|
124
|
+
if (!db)
|
|
125
|
+
return { status: 'error', message: 'Database not initialised' };
|
|
126
|
+
// Simple liveness query
|
|
127
|
+
await db.run('SELECT 1');
|
|
128
|
+
return { status: 'ok', latencyMs: Date.now() - start };
|
|
129
|
+
}
|
|
130
|
+
catch (err) {
|
|
131
|
+
return {
|
|
132
|
+
status: 'error',
|
|
133
|
+
latencyMs: Date.now() - start,
|
|
134
|
+
message: err instanceof Error ? err.message : 'Database check failed',
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
async function checkQueueHealth() {
|
|
139
|
+
try {
|
|
140
|
+
const { getQueueType } = await import('./queue/index.js');
|
|
141
|
+
const queueType = getQueueType();
|
|
142
|
+
if (!queueType)
|
|
143
|
+
return { status: 'warning', message: 'Queue not initialised' };
|
|
144
|
+
if (queueType === 'redis') {
|
|
145
|
+
// Test Redis reachability with a fresh connection
|
|
146
|
+
const redisUrl = process.env.REDIS_URL || 'redis://localhost:6379';
|
|
147
|
+
const start = Date.now();
|
|
148
|
+
try {
|
|
149
|
+
const IORedis = (await import('ioredis')).default;
|
|
150
|
+
const probe = new IORedis(redisUrl, { lazyConnect: true, connectTimeout: 2000, maxRetriesPerRequest: 0 });
|
|
151
|
+
await probe.connect();
|
|
152
|
+
await probe.ping();
|
|
153
|
+
await probe.disconnect();
|
|
154
|
+
return { status: 'ok', type: 'redis', latencyMs: Date.now() - start };
|
|
155
|
+
}
|
|
156
|
+
catch {
|
|
157
|
+
return { status: 'error', type: 'redis', latencyMs: Date.now() - start, message: 'Redis unreachable' };
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
return { status: 'ok', type: queueType };
|
|
161
|
+
}
|
|
162
|
+
catch {
|
|
163
|
+
return { status: 'ok', type: 'in-memory' };
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
async function checkOllamaHealth() {
|
|
167
|
+
const ollamaUrl = process.env.OLLAMA_BASE_URL || 'http://localhost:11434';
|
|
168
|
+
const start = Date.now();
|
|
169
|
+
try {
|
|
170
|
+
const res = await fetch(`${ollamaUrl}/api/tags`, {
|
|
171
|
+
signal: AbortSignal.timeout(3000),
|
|
172
|
+
});
|
|
173
|
+
if (!res.ok)
|
|
174
|
+
return { status: 'error', latencyMs: Date.now() - start, message: `HTTP ${res.status}` };
|
|
175
|
+
const data = await res.json();
|
|
176
|
+
const modelCount = Array.isArray(data.models) ? data.models.length : 0;
|
|
177
|
+
return { status: 'ok', latencyMs: Date.now() - start, models: modelCount };
|
|
178
|
+
}
|
|
179
|
+
catch {
|
|
180
|
+
// Ollama is optional — not reachable means degraded, not unhealthy
|
|
181
|
+
return { status: 'warning', latencyMs: Date.now() - start, message: 'Ollama not reachable' };
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
async function checkDiskHealth() {
|
|
185
|
+
try {
|
|
186
|
+
const { statfs } = await import('node:fs/promises');
|
|
187
|
+
const stats = await statfs(process.cwd());
|
|
188
|
+
const freeBytes = stats.bfree * stats.bsize;
|
|
189
|
+
const freeGb = freeBytes / (1024 ** 3);
|
|
190
|
+
const WARN_THRESHOLD_BYTES = 100 * 1024 * 1024; // 100 MB
|
|
191
|
+
const status = freeBytes < WARN_THRESHOLD_BYTES ? 'warning' : 'ok';
|
|
192
|
+
return {
|
|
193
|
+
status,
|
|
194
|
+
freeGb: Math.round(freeGb * 100) / 100,
|
|
195
|
+
...(status === 'warning' && { message: 'Low disk space (< 100 MB free)' }),
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
catch {
|
|
199
|
+
return { status: 'warning', message: 'Disk check unavailable' };
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
function checkMemoryHealth() {
|
|
203
|
+
const WARN_THRESHOLD = 90;
|
|
204
|
+
const mode = getMode();
|
|
205
|
+
const mem = process.memoryUsage();
|
|
206
|
+
const rssMb = Math.round(mem.rss / 1024 / 1024);
|
|
207
|
+
// Mode-specific RSS caps (absolute memory usage is more actionable than heap ratio)
|
|
208
|
+
const RSS_CAP_MB = { pico: 128, mini: 256, pro: 512 };
|
|
209
|
+
const capMb = RSS_CAP_MB[mode] ?? 512;
|
|
210
|
+
// Use RSS vs mode cap — heap ratio is misleading at small heap sizes
|
|
211
|
+
const usedPercent = Math.round((rssMb / capMb) * 100);
|
|
212
|
+
const status = usedPercent > WARN_THRESHOLD ? 'warning' : 'ok';
|
|
213
|
+
return {
|
|
214
|
+
status,
|
|
215
|
+
usedPercent,
|
|
216
|
+
...(status === 'warning' && { message: `RSS ${rssMb}MB exceeds ${WARN_THRESHOLD}% of ${capMb}MB cap (${mode} mode)` }),
|
|
217
|
+
};
|
|
218
|
+
}
|
|
103
219
|
app.get('/health', async (c) => {
|
|
104
|
-
const
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
220
|
+
const [database, queue, ollama, disk] = await Promise.all([
|
|
221
|
+
checkDatabaseHealth(),
|
|
222
|
+
checkQueueHealth(),
|
|
223
|
+
checkOllamaHealth(),
|
|
224
|
+
checkDiskHealth(),
|
|
225
|
+
]);
|
|
226
|
+
const memory = checkMemoryHealth();
|
|
227
|
+
const services = { database, queue, ollama, disk, memory };
|
|
228
|
+
const statuses = Object.values(services).map((s) => s.status);
|
|
229
|
+
const overallStatus = statuses.some((s) => s === 'error')
|
|
230
|
+
? 'unhealthy'
|
|
231
|
+
: statuses.some((s) => s === 'warning')
|
|
232
|
+
? 'degraded'
|
|
233
|
+
: 'ok';
|
|
234
|
+
// Gather queue depth
|
|
235
|
+
let queueDepth = { pending: 0, running: 0, total: 0 };
|
|
236
|
+
try {
|
|
237
|
+
const { getTasks } = await import('./queue/index.js');
|
|
238
|
+
const pending = getTasks({ status: 'pending' }).length + getTasks({ status: 'queued' }).length;
|
|
239
|
+
const running = getTasks({ status: 'in_progress' }).length;
|
|
240
|
+
queueDepth = { pending, running, total: pending + running };
|
|
241
|
+
}
|
|
242
|
+
catch {
|
|
243
|
+
// Queue not yet initialised — use zeroes
|
|
244
|
+
}
|
|
245
|
+
// Gather active agent sessions
|
|
246
|
+
let activeSessions = 0;
|
|
247
|
+
try {
|
|
248
|
+
const { getAgentRegistry } = await import('./adapters/registry.js');
|
|
249
|
+
activeSessions = getAgentRegistry().getActiveAdapters().length;
|
|
250
|
+
}
|
|
251
|
+
catch {
|
|
252
|
+
// Registry not yet initialised
|
|
253
|
+
}
|
|
254
|
+
const memUsage = process.memoryUsage();
|
|
255
|
+
const { loadavg: osLoadavg } = await import('node:os');
|
|
256
|
+
const body = {
|
|
257
|
+
status: overallStatus,
|
|
258
|
+
services,
|
|
110
259
|
version: VERSION,
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
260
|
+
uptime: Math.floor((Date.now() - serverStartTime) / 1000),
|
|
261
|
+
sseClients: sseConnections.size,
|
|
262
|
+
activeSessions,
|
|
263
|
+
queueDepth,
|
|
264
|
+
process: {
|
|
265
|
+
pid: process.pid,
|
|
266
|
+
port: runningPort,
|
|
267
|
+
memoryMb: Math.round(memUsage.rss / 1024 / 1024),
|
|
268
|
+
cpuLoadAvg: process.platform !== 'win32' ? osLoadavg() : [0, 0, 0],
|
|
269
|
+
},
|
|
270
|
+
...(lastErrorMessage !== undefined && { lastError: lastErrorMessage }),
|
|
271
|
+
};
|
|
272
|
+
const httpStatus = overallStatus === 'unhealthy' ? 503 : 200;
|
|
273
|
+
return c.json(body, httpStatus);
|
|
116
274
|
});
|
|
117
275
|
// API info (mode-aware)
|
|
118
|
-
app.get('/', (c) => {
|
|
276
|
+
app.get('/', async (c) => {
|
|
277
|
+
// WS-1.3: First-run setup redirect — send to /setup when no admin users exist
|
|
278
|
+
try {
|
|
279
|
+
const [{ getDb }, { users }, { eq }] = await Promise.all([
|
|
280
|
+
import('./storage/index.js'),
|
|
281
|
+
import('./storage/schema.js'),
|
|
282
|
+
import('drizzle-orm'),
|
|
283
|
+
]);
|
|
284
|
+
const db = getDb();
|
|
285
|
+
if (db) {
|
|
286
|
+
const adminCount = await db
|
|
287
|
+
.select({ id: users.id })
|
|
288
|
+
.from(users)
|
|
289
|
+
.where(eq(users.role, 'admin'))
|
|
290
|
+
.limit(1);
|
|
291
|
+
if (adminCount.length === 0) {
|
|
292
|
+
return c.redirect('/setup', 302);
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
catch {
|
|
297
|
+
// DB may not be ready; fall through to normal response
|
|
298
|
+
}
|
|
299
|
+
// If UI is built and web_ui capability is enabled, serve the dashboard
|
|
300
|
+
if (hasCapability('web_ui')) {
|
|
301
|
+
const { existsSync } = await import('node:fs');
|
|
302
|
+
const { join } = await import('node:path');
|
|
303
|
+
const { readFile } = await import('node:fs/promises');
|
|
304
|
+
const indexPath = join(process.cwd(), 'ui', 'dist', 'index.html');
|
|
305
|
+
if (existsSync(indexPath)) {
|
|
306
|
+
const html = await readFile(indexPath, 'utf-8');
|
|
307
|
+
return c.html(html);
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
// Fallback: API info JSON
|
|
119
311
|
const mode = getMode();
|
|
120
312
|
const routes = getRouteDefinitionsForMode(mode);
|
|
121
313
|
const routeIds = new Set(routes.map((r) => r.id));
|
|
@@ -156,8 +348,13 @@ app.get('/', (c) => {
|
|
|
156
348
|
sessions: 'GET /api/hook/sessions',
|
|
157
349
|
};
|
|
158
350
|
}
|
|
159
|
-
if (routeIds.has('tools'))
|
|
160
|
-
endpoints.tools =
|
|
351
|
+
if (routeIds.has('tools')) {
|
|
352
|
+
endpoints.tools = {
|
|
353
|
+
list: 'GET /api/tools',
|
|
354
|
+
execute: 'POST /api/tools/execute',
|
|
355
|
+
security: 'GET /api/tools/security',
|
|
356
|
+
};
|
|
357
|
+
}
|
|
161
358
|
if (routeIds.has('settings')) {
|
|
162
359
|
endpoints.settings = {
|
|
163
360
|
get: 'GET /api/settings',
|
|
@@ -173,10 +370,23 @@ app.get('/', (c) => {
|
|
|
173
370
|
endpoints.memory = 'GET /api/memory';
|
|
174
371
|
if (routeIds.has('skills'))
|
|
175
372
|
endpoints.skills = 'GET /api/skills';
|
|
176
|
-
if (routeIds.has('mcp'))
|
|
177
|
-
endpoints.mcp =
|
|
373
|
+
if (routeIds.has('mcp')) {
|
|
374
|
+
endpoints.mcp = {
|
|
375
|
+
status: 'GET /api/mcp',
|
|
376
|
+
tools: 'GET /api/mcp/tools',
|
|
377
|
+
};
|
|
378
|
+
}
|
|
178
379
|
if (routeIds.has('tunnels'))
|
|
179
380
|
endpoints.tunnels = 'GET /api/tunnels';
|
|
381
|
+
if (routeIds.has('teams')) {
|
|
382
|
+
endpoints.teams = {
|
|
383
|
+
list: 'GET /api/teams?userId=<id>',
|
|
384
|
+
create: 'POST /api/teams',
|
|
385
|
+
members: 'GET /api/teams/:id/members',
|
|
386
|
+
usage: 'GET /api/teams/:id/usage',
|
|
387
|
+
invites: 'POST /api/teams/:id/invites',
|
|
388
|
+
};
|
|
389
|
+
}
|
|
180
390
|
// Web UI data routes
|
|
181
391
|
if (routeIds.has('dlq'))
|
|
182
392
|
endpoints.deadLetterQueue = 'GET /api/dlq';
|
|
@@ -401,9 +611,10 @@ app.get('/api/events', (c) => {
|
|
|
401
611
|
});
|
|
402
612
|
});
|
|
403
613
|
// === Protected Gateway Endpoint ===
|
|
404
|
-
app.post('/api/gateway/execute-secure', tokenAuthMiddleware(['gateway:execute']), async (c) => {
|
|
614
|
+
app.post('/api/gateway/execute-secure', tokenAuthMiddleware(['gateway:execute']), validateBody(GatewayExecuteSchema), async (c) => {
|
|
405
615
|
try {
|
|
406
|
-
|
|
616
|
+
// validateBody middleware stores the parsed result; cast via raw context map
|
|
617
|
+
const body = c.get('validatedBody');
|
|
407
618
|
const { getGateway } = await import('./gateway/index.js');
|
|
408
619
|
const gateway = getGateway();
|
|
409
620
|
const request = {
|
|
@@ -442,6 +653,7 @@ app.post('/api/plugins/:id/toggle', async (c) => {
|
|
|
442
653
|
return c.redirect(`/api/settings/plugins/${id}/toggle`, 307);
|
|
443
654
|
});
|
|
444
655
|
// === Server Startup ===
|
|
656
|
+
const MAX_PORT_ATTEMPTS = 3;
|
|
445
657
|
function checkPortAvailable(port) {
|
|
446
658
|
return new Promise((resolve) => {
|
|
447
659
|
const server = createServer();
|
|
@@ -455,6 +667,16 @@ function checkPortAvailable(port) {
|
|
|
455
667
|
server.listen(port, '127.0.0.1');
|
|
456
668
|
});
|
|
457
669
|
}
|
|
670
|
+
async function resolvePort(startPort) {
|
|
671
|
+
for (let offset = 0; offset < MAX_PORT_ATTEMPTS; offset++) {
|
|
672
|
+
const candidate = startPort + offset;
|
|
673
|
+
const available = await checkPortAvailable(candidate);
|
|
674
|
+
if (available) {
|
|
675
|
+
return candidate;
|
|
676
|
+
}
|
|
677
|
+
}
|
|
678
|
+
return null;
|
|
679
|
+
}
|
|
458
680
|
async function main() {
|
|
459
681
|
// Only start IF we are the main module actually being executed
|
|
460
682
|
const isMain = process.argv[1]?.endsWith('server.ts') || process.argv[1]?.endsWith('server.js');
|
|
@@ -463,15 +685,18 @@ async function main() {
|
|
|
463
685
|
}
|
|
464
686
|
const mode = getMode();
|
|
465
687
|
const appSettings = getAppSettings();
|
|
466
|
-
const
|
|
688
|
+
const configuredPort = getPort();
|
|
467
689
|
const ENABLE_CRON = isCronEnabled();
|
|
468
690
|
appLog.info('profClaw starting', { version: VERSION, mode: getModeLabel() });
|
|
469
|
-
//
|
|
470
|
-
const
|
|
471
|
-
if (
|
|
472
|
-
appLog.error(`
|
|
691
|
+
// Bind-or-retry: find an available port
|
|
692
|
+
const PORT = await resolvePort(configuredPort);
|
|
693
|
+
if (PORT === null) {
|
|
694
|
+
appLog.error(`All ports ${configuredPort}–${configuredPort + MAX_PORT_ATTEMPTS - 1} are in use`, new Error(`EADDRINUSE: ports ${configuredPort}-${configuredPort + MAX_PORT_ATTEMPTS - 1}`));
|
|
473
695
|
process.exit(1);
|
|
474
696
|
}
|
|
697
|
+
if (PORT !== configuredPort) {
|
|
698
|
+
appLog.warn(`Port ${configuredPort} in use, started on port ${PORT}`);
|
|
699
|
+
}
|
|
475
700
|
// Validate environment variables (fail fast if critical vars missing)
|
|
476
701
|
const envResult = validateEnvironment({
|
|
477
702
|
exitOnError: process.env.NODE_ENV === 'production',
|
|
@@ -551,6 +776,15 @@ async function main() {
|
|
|
551
776
|
appLog.error('Failed to initialize task queue', error instanceof Error ? error : new Error(String(error)));
|
|
552
777
|
appLog.warn('Tasks will not be processed');
|
|
553
778
|
}
|
|
779
|
+
// Register SSE broadcaster for agent summary updates
|
|
780
|
+
try {
|
|
781
|
+
const { getAgentSummaryTracker } = await import('./agents/agent-summary.js');
|
|
782
|
+
getAgentSummaryTracker().registerSSEBroadcaster(broadcastEvent);
|
|
783
|
+
appLog.info('Agent summary SSE broadcaster registered');
|
|
784
|
+
}
|
|
785
|
+
catch (error) {
|
|
786
|
+
appLog.error('Failed to register agent summary broadcaster', error instanceof Error ? error : new Error(String(error)));
|
|
787
|
+
}
|
|
554
788
|
// Initialize sync engine (pro mode or if explicitly configured)
|
|
555
789
|
if (hasCapability('sync_engine')) {
|
|
556
790
|
try {
|
|
@@ -567,12 +801,13 @@ async function main() {
|
|
|
567
801
|
appLog.warn('Sync engine initialization failed', { error: error instanceof Error ? error.message : String(error) });
|
|
568
802
|
}
|
|
569
803
|
}
|
|
570
|
-
// Initialize cost tracking (
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
}
|
|
804
|
+
// Initialize cost tracking (all modes — lightweight, needed for /api/costs)
|
|
805
|
+
const { initTokenTracker } = await import('./costs/token-tracker.js');
|
|
806
|
+
initTokenTracker();
|
|
807
|
+
appLog.info('Token tracker initialized');
|
|
808
|
+
// Sweep stale tool-result temp dirs left by crashed runs (fire-and-forget)
|
|
809
|
+
const { ResultStore } = await import('./agents/result-store.js');
|
|
810
|
+
void ResultStore.sweepStale();
|
|
576
811
|
// Initialize agents from config
|
|
577
812
|
const { getAgentRegistry } = await import('./adapters/registry.js');
|
|
578
813
|
const registry = getAgentRegistry();
|
|
@@ -611,11 +846,13 @@ async function main() {
|
|
|
611
846
|
}
|
|
612
847
|
}
|
|
613
848
|
}
|
|
614
|
-
// Auto-discover agents if enabled
|
|
615
|
-
|
|
849
|
+
// Auto-discover agents if enabled
|
|
850
|
+
// Pico mode: only auto-discover Ollama (cheap fetch, essential for pico users)
|
|
851
|
+
// Mini/Pro: full auto-discovery (Claude Code CLI check, etc.)
|
|
852
|
+
const autoDiscover = mode === 'pico' ? true : (process.env.AUTO_DISCOVER_AGENTS !== undefined
|
|
616
853
|
? process.env.AUTO_DISCOVER_AGENTS === 'true'
|
|
617
854
|
: (appSettings.agents?.autoDiscover ?? false));
|
|
618
|
-
if (autoDiscover && !registry.getActiveAdapters().some(a => a.type === 'claude-code')) {
|
|
855
|
+
if (autoDiscover && mode !== 'pico' && !registry.getActiveAdapters().some(a => a.type === 'claude-code')) {
|
|
619
856
|
try {
|
|
620
857
|
const { execSync } = await import('child_process');
|
|
621
858
|
execSync('which claude', { stdio: 'ignore' });
|
|
@@ -661,6 +898,32 @@ async function main() {
|
|
|
661
898
|
// Ollama not running
|
|
662
899
|
}
|
|
663
900
|
}
|
|
901
|
+
// WS-1.2: Provider validation — warn (or exit in strict mode) when no AI adapters are configured
|
|
902
|
+
if (registry.getActiveAdapters().length === 0) {
|
|
903
|
+
appLog.warn('No AI providers configured. Run `profclaw setup` or set ANTHROPIC_API_KEY / OPENAI_API_KEY');
|
|
904
|
+
if (process.env.PROFCLAW_STRICT_MODE === 'true') {
|
|
905
|
+
appLog.error('Strict mode enabled: refusing to start without an AI provider');
|
|
906
|
+
process.exit(1);
|
|
907
|
+
}
|
|
908
|
+
degradedMode = true;
|
|
909
|
+
}
|
|
910
|
+
// WS-1.4: In-memory storage — warn on startup and remind every 60 seconds
|
|
911
|
+
{
|
|
912
|
+
const { isStorageInMemory } = await import('./storage/index.js');
|
|
913
|
+
if (isStorageInMemory()) {
|
|
914
|
+
degradedMode = true;
|
|
915
|
+
appLog.warn('╔══════════════════════════════════════════════════════════╗');
|
|
916
|
+
appLog.warn('║ WARNING: Running with in-memory storage (ephemeral) ║');
|
|
917
|
+
appLog.warn('║ All data will be lost when the server restarts. ║');
|
|
918
|
+
appLog.warn('║ Set STORAGE_TIER=local or DATABASE_URL to persist data. ║');
|
|
919
|
+
appLog.warn('╚══════════════════════════════════════════════════════════╝');
|
|
920
|
+
inMemoryStorageReminderInterval = setInterval(() => {
|
|
921
|
+
appLog.warn('Reminder: server is running with ephemeral in-memory storage — data will not survive a restart');
|
|
922
|
+
}, 60_000);
|
|
923
|
+
// Allow Node to exit cleanly without waiting for this interval
|
|
924
|
+
inMemoryStorageReminderInterval.unref();
|
|
925
|
+
}
|
|
926
|
+
}
|
|
664
927
|
// Start cron jobs (if mode supports it and enabled)
|
|
665
928
|
if (ENABLE_CRON && hasCapability('cron')) {
|
|
666
929
|
const { startAllCronJobs } = await import('./cron/index.js');
|
|
@@ -720,6 +983,10 @@ async function main() {
|
|
|
720
983
|
fetch: app.fetch,
|
|
721
984
|
port: PORT,
|
|
722
985
|
});
|
|
986
|
+
// Record runtime port for health endpoint
|
|
987
|
+
runningPort = PORT;
|
|
988
|
+
// Record PID so the CLI can detect/kill existing instances
|
|
989
|
+
writePidFile(PORT);
|
|
723
990
|
appLog.info(`profClaw ready on http://localhost:${PORT}`, { port: PORT, mode: getModeLabel() });
|
|
724
991
|
if (ENABLE_CRON) {
|
|
725
992
|
const heartbeatMs = parseInt(process.env.POLL_INTERVAL_HEARTBEAT || '30000', 10);
|
|
@@ -790,7 +1057,12 @@ async function gracefulShutdown(signal) {
|
|
|
790
1057
|
sseConnections.clear();
|
|
791
1058
|
clearInterval(sseCleanupInterval);
|
|
792
1059
|
appLog.info('SSE connections closed');
|
|
793
|
-
// 2. Stop
|
|
1060
|
+
// 2. Stop in-memory storage reminder interval
|
|
1061
|
+
if (inMemoryStorageReminderInterval !== null) {
|
|
1062
|
+
clearInterval(inMemoryStorageReminderInterval);
|
|
1063
|
+
inMemoryStorageReminderInterval = null;
|
|
1064
|
+
}
|
|
1065
|
+
// 3. Stop cron jobs
|
|
794
1066
|
try {
|
|
795
1067
|
const { stopAllCronJobs } = await import('./cron/index.js');
|
|
796
1068
|
stopAllCronJobs();
|
|
@@ -799,7 +1071,7 @@ async function gracefulShutdown(signal) {
|
|
|
799
1071
|
catch {
|
|
800
1072
|
// Cron may not be initialized
|
|
801
1073
|
}
|
|
802
|
-
//
|
|
1074
|
+
// 4. Drain task queue
|
|
803
1075
|
try {
|
|
804
1076
|
const { closeQueue } = await import('./queue/index.js');
|
|
805
1077
|
await closeQueue();
|
|
@@ -808,7 +1080,7 @@ async function gracefulShutdown(signal) {
|
|
|
808
1080
|
catch {
|
|
809
1081
|
// Queue may not be initialized
|
|
810
1082
|
}
|
|
811
|
-
//
|
|
1083
|
+
// 5. Destroy HTTP rate limiters
|
|
812
1084
|
try {
|
|
813
1085
|
apiRateLimiter.destroy();
|
|
814
1086
|
authRateLimiter.destroy();
|
|
@@ -817,6 +1089,8 @@ async function gracefulShutdown(signal) {
|
|
|
817
1089
|
catch {
|
|
818
1090
|
// Rate limiters may not be initialized
|
|
819
1091
|
}
|
|
1092
|
+
// Remove PID file so new instances know the slot is free
|
|
1093
|
+
removePidFile();
|
|
820
1094
|
appLog.info('Clean exit');
|
|
821
1095
|
clearTimeout(forceExitTimer);
|
|
822
1096
|
process.exit(0);
|
|
@@ -825,12 +1099,15 @@ process.on('SIGINT', () => { gracefulShutdown('SIGINT'); });
|
|
|
825
1099
|
process.on('SIGTERM', () => { gracefulShutdown('SIGTERM'); });
|
|
826
1100
|
// Catch unhandled errors to log before crashing
|
|
827
1101
|
process.on('uncaughtException', (err) => {
|
|
1102
|
+
lastErrorMessage = err.message;
|
|
828
1103
|
appLog.error('Uncaught exception', err);
|
|
829
1104
|
// Let the process crash (daemon/serve will restart it)
|
|
830
1105
|
process.exit(1);
|
|
831
1106
|
});
|
|
832
1107
|
process.on('unhandledRejection', (reason) => {
|
|
833
|
-
|
|
1108
|
+
const errMsg = reason instanceof Error ? reason.message : String(reason);
|
|
1109
|
+
lastErrorMessage = errMsg;
|
|
1110
|
+
appLog.error('Unhandled rejection', reason instanceof Error ? reason : new Error(errMsg));
|
|
834
1111
|
// Don't exit for unhandled rejections - log and continue
|
|
835
1112
|
// This prevents a single failed promise from taking down the server
|
|
836
1113
|
});
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Skill Marketplace Client
|
|
3
|
+
*
|
|
4
|
+
* Enables discovering, installing, and updating skills from remote registries.
|
|
5
|
+
* Supports the profClaw skill registry (future) and GitHub-hosted skills.
|
|
6
|
+
*
|
|
7
|
+
* Skills are installed to ~/.profclaw/skills/<name>/SKILL.md
|
|
8
|
+
*/
|
|
9
|
+
export interface MarketplaceSkill {
|
|
10
|
+
name: string;
|
|
11
|
+
description: string;
|
|
12
|
+
version: string;
|
|
13
|
+
author: string;
|
|
14
|
+
category: string;
|
|
15
|
+
tags: string[];
|
|
16
|
+
/** Number of installs */
|
|
17
|
+
installs: number;
|
|
18
|
+
/** Average rating 0-5 */
|
|
19
|
+
rating: number;
|
|
20
|
+
/** Source URL (GitHub raw content, registry API, etc.) */
|
|
21
|
+
sourceUrl: string;
|
|
22
|
+
/** When the skill was last updated */
|
|
23
|
+
updatedAt: string;
|
|
24
|
+
/** Whether this skill is already installed locally */
|
|
25
|
+
installed?: boolean;
|
|
26
|
+
/** Local version if installed */
|
|
27
|
+
installedVersion?: string;
|
|
28
|
+
}
|
|
29
|
+
export interface MarketplaceSearchParams {
|
|
30
|
+
query?: string;
|
|
31
|
+
category?: string;
|
|
32
|
+
tag?: string;
|
|
33
|
+
sortBy?: 'installs' | 'rating' | 'updated' | 'name';
|
|
34
|
+
limit?: number;
|
|
35
|
+
offset?: number;
|
|
36
|
+
}
|
|
37
|
+
export interface MarketplaceRegistry {
|
|
38
|
+
name: string;
|
|
39
|
+
url: string;
|
|
40
|
+
enabled: boolean;
|
|
41
|
+
}
|
|
42
|
+
export interface InstallResult {
|
|
43
|
+
success: boolean;
|
|
44
|
+
skillName: string;
|
|
45
|
+
version?: string;
|
|
46
|
+
installPath?: string;
|
|
47
|
+
error?: string;
|
|
48
|
+
}
|
|
49
|
+
export declare class MarketplaceClient {
|
|
50
|
+
private registries;
|
|
51
|
+
constructor(registries?: MarketplaceRegistry[]);
|
|
52
|
+
/**
|
|
53
|
+
* Search for skills across all enabled registries.
|
|
54
|
+
*/
|
|
55
|
+
search(params?: MarketplaceSearchParams): Promise<MarketplaceSkill[]>;
|
|
56
|
+
/**
|
|
57
|
+
* Install a skill from a registry or direct URL.
|
|
58
|
+
*/
|
|
59
|
+
install(source: string): Promise<InstallResult>;
|
|
60
|
+
/**
|
|
61
|
+
* Uninstall a managed skill.
|
|
62
|
+
*/
|
|
63
|
+
uninstall(skillName: string): Promise<boolean>;
|
|
64
|
+
/**
|
|
65
|
+
* Check for updates to installed managed skills.
|
|
66
|
+
*/
|
|
67
|
+
checkUpdates(): Promise<Array<{
|
|
68
|
+
name: string;
|
|
69
|
+
currentVersion: string;
|
|
70
|
+
latestVersion: string;
|
|
71
|
+
}>>;
|
|
72
|
+
/**
|
|
73
|
+
* Add a custom registry.
|
|
74
|
+
*/
|
|
75
|
+
addRegistry(registry: MarketplaceRegistry): void;
|
|
76
|
+
/**
|
|
77
|
+
* List configured registries.
|
|
78
|
+
*/
|
|
79
|
+
listRegistries(): MarketplaceRegistry[];
|
|
80
|
+
private searchRegistry;
|
|
81
|
+
private fetchSkillFromUrl;
|
|
82
|
+
private fetchSkillFromGitHub;
|
|
83
|
+
private fetchSkillFromRegistry;
|
|
84
|
+
private getLatestVersion;
|
|
85
|
+
}
|
|
86
|
+
export declare function getMarketplace(): MarketplaceClient;
|
|
87
|
+
//# sourceMappingURL=marketplace.d.ts.map
|