profclaw 2.0.0 → 2.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +14 -2
- package/CHANGELOG.md +37 -0
- package/CONTRIBUTING.md +20 -0
- package/Dockerfile +39 -23
- package/README.md +174 -40
- 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/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.d.ts +35 -1
- package/dist/agents/executor.js +573 -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/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/result-store.d.ts +37 -0
- package/dist/agents/result-store.js +104 -0
- package/dist/agents/session-diff.d.ts +43 -0
- package/dist/agents/session-diff.js +258 -0
- package/dist/agents/tool-loader.d.ts +65 -0
- package/dist/agents/tool-loader.js +273 -0
- package/dist/agents/transcript.d.ts +96 -0
- package/dist/agents/transcript.js +267 -0
- package/dist/agents/worktree-manager.d.ts +80 -0
- package/dist/agents/worktree-manager.js +203 -0
- package/dist/auth/middleware.js +14 -0
- package/dist/chat/agentic-executor.d.ts +7 -0
- package/dist/chat/agentic-executor.js +253 -30
- 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/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/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/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 +116 -61
- 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/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 +19 -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/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 +78 -19
- package/dist/providers/core/models.js +67 -1
- package/dist/providers/core/types.d.ts +3 -0
- package/dist/providers/index.d.ts +1 -0
- package/dist/providers/index.js +1 -0
- package/dist/providers/smart-router.d.ts +118 -0
- package/dist/providers/smart-router.js +685 -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 +259 -14
- 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 +310 -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
|
@@ -0,0 +1,381 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI Init Command
|
|
3
|
+
*
|
|
4
|
+
* Scans the current project directory and generates a `.profclaw/context.md`
|
|
5
|
+
* file describing the tech stack, structure, build/test commands, and conventions.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* profclaw init # interactive (asks before overwriting)
|
|
9
|
+
* profclaw init --force # overwrite without prompting
|
|
10
|
+
*/
|
|
11
|
+
import { Command } from 'commander';
|
|
12
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
13
|
+
import fs from 'node:fs/promises';
|
|
14
|
+
import path from 'node:path';
|
|
15
|
+
import { execSync } from 'node:child_process';
|
|
16
|
+
import { confirm } from '@inquirer/prompts';
|
|
17
|
+
import { success, error, info, spinner } from '../utils/output.js';
|
|
18
|
+
// ── Manifest readers ──────────────────────────────────────────────────────────
|
|
19
|
+
function readJson(filePath) {
|
|
20
|
+
try {
|
|
21
|
+
return JSON.parse(readFileSync(filePath, 'utf-8'));
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
function readText(filePath) {
|
|
28
|
+
try {
|
|
29
|
+
return readFileSync(filePath, 'utf-8');
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
function fileExists(filePath) {
|
|
36
|
+
return existsSync(filePath);
|
|
37
|
+
}
|
|
38
|
+
// ── Detectors ─────────────────────────────────────────────────────────────────
|
|
39
|
+
function detectLanguage(cwd) {
|
|
40
|
+
if (fileExists(path.join(cwd, 'Cargo.toml')))
|
|
41
|
+
return 'Rust';
|
|
42
|
+
if (fileExists(path.join(cwd, 'go.mod')))
|
|
43
|
+
return 'Go';
|
|
44
|
+
if (fileExists(path.join(cwd, 'pyproject.toml')) || fileExists(path.join(cwd, 'setup.py')))
|
|
45
|
+
return 'Python';
|
|
46
|
+
if (fileExists(path.join(cwd, 'tsconfig.json')))
|
|
47
|
+
return 'TypeScript';
|
|
48
|
+
if (fileExists(path.join(cwd, 'package.json')))
|
|
49
|
+
return 'JavaScript';
|
|
50
|
+
if (fileExists(path.join(cwd, 'pom.xml')) || fileExists(path.join(cwd, 'build.gradle')))
|
|
51
|
+
return 'Java';
|
|
52
|
+
if (fileExists(path.join(cwd, 'mix.exs')))
|
|
53
|
+
return 'Elixir';
|
|
54
|
+
if (fileExists(path.join(cwd, 'Gemfile')))
|
|
55
|
+
return 'Ruby';
|
|
56
|
+
return 'Unknown';
|
|
57
|
+
}
|
|
58
|
+
function detectPackageManager(cwd) {
|
|
59
|
+
if (fileExists(path.join(cwd, 'pnpm-lock.yaml')))
|
|
60
|
+
return 'pnpm';
|
|
61
|
+
if (fileExists(path.join(cwd, 'yarn.lock')))
|
|
62
|
+
return 'yarn';
|
|
63
|
+
if (fileExists(path.join(cwd, 'bun.lockb')))
|
|
64
|
+
return 'bun';
|
|
65
|
+
if (fileExists(path.join(cwd, 'package-lock.json')))
|
|
66
|
+
return 'npm';
|
|
67
|
+
return 'npm';
|
|
68
|
+
}
|
|
69
|
+
function detectFramework(cwd, pkg) {
|
|
70
|
+
const deps = {
|
|
71
|
+
...(pkg?.dependencies ?? {}),
|
|
72
|
+
...(pkg?.devDependencies ?? {}),
|
|
73
|
+
};
|
|
74
|
+
const hasDep = (name) => name in deps;
|
|
75
|
+
if (hasDep('next'))
|
|
76
|
+
return 'Next.js';
|
|
77
|
+
if (hasDep('nuxt'))
|
|
78
|
+
return 'Nuxt';
|
|
79
|
+
if (hasDep('astro'))
|
|
80
|
+
return 'Astro';
|
|
81
|
+
if (hasDep('remix'))
|
|
82
|
+
return 'Remix';
|
|
83
|
+
if (hasDep('@sveltejs/kit'))
|
|
84
|
+
return 'SvelteKit';
|
|
85
|
+
if (hasDep('svelte'))
|
|
86
|
+
return 'Svelte';
|
|
87
|
+
if (hasDep('react'))
|
|
88
|
+
return 'React';
|
|
89
|
+
if (hasDep('vue'))
|
|
90
|
+
return 'Vue';
|
|
91
|
+
if (hasDep('express'))
|
|
92
|
+
return 'Express';
|
|
93
|
+
if (hasDep('fastify'))
|
|
94
|
+
return 'Fastify';
|
|
95
|
+
if (hasDep('hono'))
|
|
96
|
+
return 'Hono';
|
|
97
|
+
if (hasDep('@nestjs/core'))
|
|
98
|
+
return 'NestJS';
|
|
99
|
+
if (hasDep('commander'))
|
|
100
|
+
return 'CLI (commander)';
|
|
101
|
+
if (hasDep('ink'))
|
|
102
|
+
return 'CLI (ink/TUI)';
|
|
103
|
+
if (fileExists(path.join(cwd, 'pyproject.toml'))) {
|
|
104
|
+
const content = readText(path.join(cwd, 'pyproject.toml')) ?? '';
|
|
105
|
+
if (content.includes('fastapi'))
|
|
106
|
+
return 'FastAPI';
|
|
107
|
+
if (content.includes('flask'))
|
|
108
|
+
return 'Flask';
|
|
109
|
+
if (content.includes('django'))
|
|
110
|
+
return 'Django';
|
|
111
|
+
}
|
|
112
|
+
if (fileExists(path.join(cwd, 'Cargo.toml'))) {
|
|
113
|
+
const content = readText(path.join(cwd, 'Cargo.toml')) ?? '';
|
|
114
|
+
if (content.includes('axum'))
|
|
115
|
+
return 'Axum';
|
|
116
|
+
if (content.includes('actix-web'))
|
|
117
|
+
return 'Actix-web';
|
|
118
|
+
if (content.includes('rocket'))
|
|
119
|
+
return 'Rocket';
|
|
120
|
+
}
|
|
121
|
+
if (fileExists(path.join(cwd, 'go.mod'))) {
|
|
122
|
+
const content = readText(path.join(cwd, 'go.mod')) ?? '';
|
|
123
|
+
if (content.includes('gin-gonic'))
|
|
124
|
+
return 'Gin';
|
|
125
|
+
if (content.includes('echo'))
|
|
126
|
+
return 'Echo';
|
|
127
|
+
if (content.includes('fiber'))
|
|
128
|
+
return 'Fiber';
|
|
129
|
+
}
|
|
130
|
+
return 'None detected';
|
|
131
|
+
}
|
|
132
|
+
function detectBuildAndTestCommands(cwd, pkg, pm, language) {
|
|
133
|
+
const scripts = pkg?.scripts ?? {};
|
|
134
|
+
const run = (script) => `${pm} run ${script}`;
|
|
135
|
+
const build = scripts['build'] ? run('build') :
|
|
136
|
+
language === 'Rust' ? 'cargo build --release' :
|
|
137
|
+
language === 'Go' ? 'go build ./...' :
|
|
138
|
+
language === 'Python' ? (fileExists(path.join(cwd, 'pyproject.toml')) ? 'python -m build' : 'python setup.py build') :
|
|
139
|
+
scripts['compile'] ? run('compile') :
|
|
140
|
+
'N/A';
|
|
141
|
+
const test = scripts['test'] ? run('test') :
|
|
142
|
+
language === 'Rust' ? 'cargo test' :
|
|
143
|
+
language === 'Go' ? 'go test ./...' :
|
|
144
|
+
language === 'Python' ? 'pytest' :
|
|
145
|
+
scripts['check'] ? run('check') :
|
|
146
|
+
'N/A';
|
|
147
|
+
const dev = scripts['dev'] ? run('dev') :
|
|
148
|
+
scripts['start'] ? run('start') :
|
|
149
|
+
scripts['serve'] ? run('serve') :
|
|
150
|
+
'N/A';
|
|
151
|
+
return { build, test, dev };
|
|
152
|
+
}
|
|
153
|
+
function detectKeyDirs(cwd) {
|
|
154
|
+
const candidates = [
|
|
155
|
+
{ name: 'src', purpose: 'Source code' },
|
|
156
|
+
{ name: 'app', purpose: 'Application code' },
|
|
157
|
+
{ name: 'lib', purpose: 'Library / shared utilities' },
|
|
158
|
+
{ name: 'packages', purpose: 'Monorepo packages' },
|
|
159
|
+
{ name: 'apps', purpose: 'Monorepo applications' },
|
|
160
|
+
{ name: 'tests', purpose: 'Test files' },
|
|
161
|
+
{ name: 'test', purpose: 'Test files' },
|
|
162
|
+
{ name: '__tests__', purpose: 'Jest test files' },
|
|
163
|
+
{ name: 'docs', purpose: 'Documentation' },
|
|
164
|
+
{ name: 'scripts', purpose: 'Build / utility scripts' },
|
|
165
|
+
{ name: 'public', purpose: 'Static assets' },
|
|
166
|
+
{ name: 'assets', purpose: 'Static assets' },
|
|
167
|
+
{ name: 'api', purpose: 'API layer' },
|
|
168
|
+
{ name: 'components', purpose: 'UI components' },
|
|
169
|
+
{ name: 'pages', purpose: 'Page components / routes' },
|
|
170
|
+
{ name: 'hooks', purpose: 'React hooks' },
|
|
171
|
+
{ name: 'services', purpose: 'Service / business logic layer' },
|
|
172
|
+
{ name: 'utils', purpose: 'Utility functions' },
|
|
173
|
+
{ name: 'config', purpose: 'Configuration files' },
|
|
174
|
+
{ name: 'migrations', purpose: 'Database migrations' },
|
|
175
|
+
{ name: 'prisma', purpose: 'Prisma schema and migrations' },
|
|
176
|
+
{ name: 'drizzle', purpose: 'Drizzle ORM schema' },
|
|
177
|
+
{ name: '.github', purpose: 'GitHub Actions / workflows' },
|
|
178
|
+
{ name: 'docker', purpose: 'Docker configuration' },
|
|
179
|
+
{ name: 'infra', purpose: 'Infrastructure / IaC' },
|
|
180
|
+
{ name: 'k8s', purpose: 'Kubernetes manifests' },
|
|
181
|
+
];
|
|
182
|
+
return candidates
|
|
183
|
+
.filter(c => fileExists(path.join(cwd, c.name)))
|
|
184
|
+
.map(c => ({ path: c.name, purpose: c.purpose }));
|
|
185
|
+
}
|
|
186
|
+
function detectConventions(cwd, pkg) {
|
|
187
|
+
const conventions = [];
|
|
188
|
+
// Linting
|
|
189
|
+
if (fileExists(path.join(cwd, '.eslintrc.js')) ||
|
|
190
|
+
fileExists(path.join(cwd, '.eslintrc.json')) ||
|
|
191
|
+
fileExists(path.join(cwd, 'eslint.config.js')) ||
|
|
192
|
+
fileExists(path.join(cwd, 'eslint.config.ts'))) {
|
|
193
|
+
conventions.push('ESLint for linting');
|
|
194
|
+
}
|
|
195
|
+
if (fileExists(path.join(cwd, '.prettierrc')) ||
|
|
196
|
+
fileExists(path.join(cwd, '.prettierrc.json')) ||
|
|
197
|
+
fileExists(path.join(cwd, 'prettier.config.js')) ||
|
|
198
|
+
fileExists(path.join(cwd, 'prettier.config.ts'))) {
|
|
199
|
+
conventions.push('Prettier for formatting');
|
|
200
|
+
}
|
|
201
|
+
if (fileExists(path.join(cwd, 'biome.json')) || fileExists(path.join(cwd, 'biome.jsonc'))) {
|
|
202
|
+
conventions.push('Biome for linting and formatting');
|
|
203
|
+
}
|
|
204
|
+
// Editor config
|
|
205
|
+
if (fileExists(path.join(cwd, '.editorconfig'))) {
|
|
206
|
+
const content = readText(path.join(cwd, '.editorconfig')) ?? '';
|
|
207
|
+
const indentMatch = content.match(/indent_style\s*=\s*(\w+)/);
|
|
208
|
+
const sizeMatch = content.match(/indent_size\s*=\s*(\d+)/);
|
|
209
|
+
if (indentMatch && sizeMatch) {
|
|
210
|
+
conventions.push(`${indentMatch[1] === 'tab' ? 'Tabs' : `${sizeMatch[1]}-space`} indentation (from .editorconfig)`);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
// TypeScript strictness
|
|
214
|
+
if (fileExists(path.join(cwd, 'tsconfig.json'))) {
|
|
215
|
+
const tsconfig = readJson(path.join(cwd, 'tsconfig.json'));
|
|
216
|
+
const co = tsconfig?.compilerOptions;
|
|
217
|
+
if (co?.strict === true)
|
|
218
|
+
conventions.push('TypeScript strict mode enabled');
|
|
219
|
+
if (co?.noUncheckedIndexedAccess === true)
|
|
220
|
+
conventions.push('noUncheckedIndexedAccess enforced');
|
|
221
|
+
}
|
|
222
|
+
// Git hooks
|
|
223
|
+
if (fileExists(path.join(cwd, '.husky')))
|
|
224
|
+
conventions.push('Husky git hooks');
|
|
225
|
+
// Commit conventions
|
|
226
|
+
if (fileExists(path.join(cwd, 'commitlint.config.js')) ||
|
|
227
|
+
fileExists(path.join(cwd, 'commitlint.config.ts'))) {
|
|
228
|
+
conventions.push('commitlint for conventional commits');
|
|
229
|
+
}
|
|
230
|
+
const scripts = pkg?.scripts ?? {};
|
|
231
|
+
if (scripts['lint'])
|
|
232
|
+
conventions.push(`Lint command: \`${scripts['lint']}\``);
|
|
233
|
+
if (scripts['format'])
|
|
234
|
+
conventions.push(`Format command: \`${scripts['format']}\``);
|
|
235
|
+
if (scripts['typecheck'] || scripts['type-check']) {
|
|
236
|
+
conventions.push(`Type-check command: \`${scripts['typecheck'] ?? scripts['type-check']}\``);
|
|
237
|
+
}
|
|
238
|
+
return conventions;
|
|
239
|
+
}
|
|
240
|
+
function detectRecentActivity(cwd) {
|
|
241
|
+
try {
|
|
242
|
+
const log = execSync('git log --oneline --no-merges -10', { cwd, encoding: 'utf-8', timeout: 5000, stdio: ['pipe', 'pipe', 'pipe'] }).trim();
|
|
243
|
+
if (!log)
|
|
244
|
+
return 'No git history found.';
|
|
245
|
+
return log;
|
|
246
|
+
}
|
|
247
|
+
catch {
|
|
248
|
+
return 'No git repository or git unavailable.';
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
function extractDescription(cwd, pkg) {
|
|
252
|
+
if (pkg?.description && typeof pkg.description === 'string' && pkg.description.trim()) {
|
|
253
|
+
return pkg.description.trim();
|
|
254
|
+
}
|
|
255
|
+
const readme = readText(path.join(cwd, 'README.md')) ?? readText(path.join(cwd, 'readme.md'));
|
|
256
|
+
if (readme) {
|
|
257
|
+
// Take the first non-heading paragraph (strip markdown headings)
|
|
258
|
+
const lines = readme.split('\n');
|
|
259
|
+
for (const line of lines) {
|
|
260
|
+
const trimmed = line.trim();
|
|
261
|
+
if (trimmed && !trimmed.startsWith('#') && !trimmed.startsWith('!') && trimmed.length > 20) {
|
|
262
|
+
return trimmed.replace(/[*_`]/g, '').slice(0, 200);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
return 'No description found. Add one in README.md or package.json.';
|
|
267
|
+
}
|
|
268
|
+
// ── Main scan function ────────────────────────────────────────────────────────
|
|
269
|
+
async function scanProject(cwd) {
|
|
270
|
+
const pkg = readJson(path.join(cwd, 'package.json'));
|
|
271
|
+
const language = detectLanguage(cwd);
|
|
272
|
+
const pm = detectPackageManager(cwd);
|
|
273
|
+
const framework = detectFramework(cwd, pkg);
|
|
274
|
+
const { build, test, dev } = detectBuildAndTestCommands(cwd, pkg, pm, language);
|
|
275
|
+
const keyDirs = detectKeyDirs(cwd);
|
|
276
|
+
const conventions = detectConventions(cwd, pkg);
|
|
277
|
+
const recentActivity = detectRecentActivity(cwd);
|
|
278
|
+
const description = extractDescription(cwd, pkg);
|
|
279
|
+
const name = pkg?.name ?? path.basename(cwd);
|
|
280
|
+
return {
|
|
281
|
+
name,
|
|
282
|
+
description,
|
|
283
|
+
language,
|
|
284
|
+
framework,
|
|
285
|
+
buildCommand: build,
|
|
286
|
+
testCommand: test,
|
|
287
|
+
devCommand: dev,
|
|
288
|
+
keyDirs,
|
|
289
|
+
conventions,
|
|
290
|
+
recentActivity,
|
|
291
|
+
packageManager: pm,
|
|
292
|
+
};
|
|
293
|
+
}
|
|
294
|
+
// ── Context file generator ────────────────────────────────────────────────────
|
|
295
|
+
function generateContextMarkdown(info) {
|
|
296
|
+
const now = new Date().toISOString().slice(0, 10);
|
|
297
|
+
const structureLines = info.keyDirs.length > 0
|
|
298
|
+
? info.keyDirs.map(d => `- \`${d.path}/\` — ${d.purpose}`).join('\n')
|
|
299
|
+
: '- No key directories detected automatically.';
|
|
300
|
+
const conventionLines = info.conventions.length > 0
|
|
301
|
+
? info.conventions.map(c => `- ${c}`).join('\n')
|
|
302
|
+
: '- No convention files detected.';
|
|
303
|
+
return `# Project Context
|
|
304
|
+
> Auto-generated by \`profclaw init\` on ${now}. Edit freely — this file is yours.
|
|
305
|
+
|
|
306
|
+
## Overview
|
|
307
|
+
|
|
308
|
+
${info.description}
|
|
309
|
+
|
|
310
|
+
**Project name:** \`${info.name}\`
|
|
311
|
+
|
|
312
|
+
## Tech Stack
|
|
313
|
+
|
|
314
|
+
- **Language:** ${info.language}
|
|
315
|
+
- **Framework:** ${info.framework}
|
|
316
|
+
- **Package manager:** ${info.packageManager}
|
|
317
|
+
- **Build:** \`${info.buildCommand}\`
|
|
318
|
+
- **Test:** \`${info.testCommand}\`
|
|
319
|
+
- **Dev server:** \`${info.devCommand}\`
|
|
320
|
+
|
|
321
|
+
## Structure
|
|
322
|
+
|
|
323
|
+
${structureLines}
|
|
324
|
+
|
|
325
|
+
## Conventions
|
|
326
|
+
|
|
327
|
+
${conventionLines}
|
|
328
|
+
|
|
329
|
+
## Recent Activity
|
|
330
|
+
|
|
331
|
+
\`\`\`
|
|
332
|
+
${info.recentActivity}
|
|
333
|
+
\`\`\`
|
|
334
|
+
`;
|
|
335
|
+
}
|
|
336
|
+
// ── Command ───────────────────────────────────────────────────────────────────
|
|
337
|
+
export function initCommand() {
|
|
338
|
+
const cmd = new Command('init')
|
|
339
|
+
.description('Scan the project and generate .profclaw/context.md')
|
|
340
|
+
.option('-f, --force', 'Overwrite existing context.md without prompting')
|
|
341
|
+
.option('--dir <path>', 'Project directory to scan (default: cwd)')
|
|
342
|
+
.action(async (options) => {
|
|
343
|
+
const cwd = options.dir ? path.resolve(options.dir) : process.cwd();
|
|
344
|
+
const outputDir = path.join(cwd, '.profclaw');
|
|
345
|
+
const outputPath = path.join(outputDir, 'context.md');
|
|
346
|
+
// Check for existing file
|
|
347
|
+
if (fileExists(outputPath) && !options.force) {
|
|
348
|
+
const overwrite = await confirm({
|
|
349
|
+
message: '.profclaw/context.md already exists. Overwrite?',
|
|
350
|
+
default: false,
|
|
351
|
+
});
|
|
352
|
+
if (!overwrite) {
|
|
353
|
+
info('Aborted. Use --force to overwrite without prompting.');
|
|
354
|
+
return;
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
const spin = spinner('Scanning project...').start();
|
|
358
|
+
try {
|
|
359
|
+
const projectInfo = await scanProject(cwd);
|
|
360
|
+
spin.stop();
|
|
361
|
+
const markdown = generateContextMarkdown(projectInfo);
|
|
362
|
+
await fs.mkdir(outputDir, { recursive: true });
|
|
363
|
+
await fs.writeFile(outputPath, markdown, 'utf-8');
|
|
364
|
+
success(`Context written to .profclaw/context.md`);
|
|
365
|
+
console.log('');
|
|
366
|
+
console.log(` Project : ${projectInfo.name}`);
|
|
367
|
+
console.log(` Language: ${projectInfo.language}`);
|
|
368
|
+
console.log(` Framework: ${projectInfo.framework}`);
|
|
369
|
+
console.log(` Dirs scanned: ${projectInfo.keyDirs.length}`);
|
|
370
|
+
console.log('');
|
|
371
|
+
info('Edit .profclaw/context.md to add your own notes and conventions.');
|
|
372
|
+
}
|
|
373
|
+
catch (err) {
|
|
374
|
+
spin.stop();
|
|
375
|
+
error(err instanceof Error ? err.message : 'Init failed');
|
|
376
|
+
process.exit(1);
|
|
377
|
+
}
|
|
378
|
+
});
|
|
379
|
+
return cmd;
|
|
380
|
+
}
|
|
381
|
+
//# sourceMappingURL=init.js.map
|
|
@@ -11,12 +11,40 @@
|
|
|
11
11
|
import { Command } from 'commander';
|
|
12
12
|
import chalk from 'chalk';
|
|
13
13
|
import figlet from 'figlet';
|
|
14
|
-
import { select, search, input, Separator } from '@inquirer/prompts';
|
|
14
|
+
import { select, search, input, confirm, Separator } from '@inquirer/prompts';
|
|
15
15
|
import { existsSync, writeFileSync, readFileSync } from 'node:fs';
|
|
16
16
|
import { join } from 'node:path';
|
|
17
17
|
import { execSync } from 'node:child_process';
|
|
18
18
|
import { success, error, info, warn, spinner } from '../utils/output.js';
|
|
19
19
|
import { PROVIDER_CATALOG, PROVIDER_ENV_KEYS } from '../providers.js';
|
|
20
|
+
/** Returns true if an env var name should have its value masked. */
|
|
21
|
+
function isSensitiveKey(key) {
|
|
22
|
+
return key.includes('KEY') || key.includes('TOKEN') || key.includes('SECRET');
|
|
23
|
+
}
|
|
24
|
+
/** Mask an API key for display — shows first 8 chars and last 4, dots in between. */
|
|
25
|
+
function maskApiKey(key) {
|
|
26
|
+
if (key.length <= 12)
|
|
27
|
+
return key.slice(0, 4) + '•'.repeat(key.length - 4);
|
|
28
|
+
return key.slice(0, 8) + '•'.repeat(8) + key.slice(-4);
|
|
29
|
+
}
|
|
30
|
+
/** Format a generated env file for display with sensitive values masked. */
|
|
31
|
+
function formatEnvPreview(content) {
|
|
32
|
+
return content.split('\n')
|
|
33
|
+
.map(line => {
|
|
34
|
+
if (line.startsWith('#') || line.trim() === '')
|
|
35
|
+
return chalk.dim(` ${line}`);
|
|
36
|
+
const eqIndex = line.indexOf('=');
|
|
37
|
+
if (eqIndex === -1)
|
|
38
|
+
return chalk.dim(` ${line}`);
|
|
39
|
+
const key = line.slice(0, eqIndex);
|
|
40
|
+
const value = line.slice(eqIndex + 1);
|
|
41
|
+
if (isSensitiveKey(key)) {
|
|
42
|
+
return ` ${chalk.cyan(key)}=${chalk.yellow(maskApiKey(value))}`;
|
|
43
|
+
}
|
|
44
|
+
return ` ${chalk.cyan(key)}=${chalk.white(value)}`;
|
|
45
|
+
})
|
|
46
|
+
.join('\n');
|
|
47
|
+
}
|
|
20
48
|
/** Render a step header with progress bar. */
|
|
21
49
|
function stepHeader(step, total, title) {
|
|
22
50
|
const barLen = 20;
|
|
@@ -148,6 +176,89 @@ function generateEnvFile(opts) {
|
|
|
148
176
|
}
|
|
149
177
|
return lines.join('\n');
|
|
150
178
|
}
|
|
179
|
+
const KEY_FORMAT_PREFIXES = {
|
|
180
|
+
anthropic: 'sk-ant-',
|
|
181
|
+
openai: 'sk-',
|
|
182
|
+
groq: 'gsk_',
|
|
183
|
+
};
|
|
184
|
+
async function validateProviderKey(providerKey, apiKey) {
|
|
185
|
+
// Fast-fail: format check for known prefix patterns
|
|
186
|
+
const expectedPrefix = KEY_FORMAT_PREFIXES[providerKey];
|
|
187
|
+
if (expectedPrefix && !apiKey.startsWith(expectedPrefix)) {
|
|
188
|
+
return {
|
|
189
|
+
valid: false,
|
|
190
|
+
error: `Key should start with "${expectedPrefix}"`,
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
// Ollama uses a local URL, no key validation needed
|
|
194
|
+
if (providerKey === 'ollama') {
|
|
195
|
+
return { valid: true };
|
|
196
|
+
}
|
|
197
|
+
// Lightweight API call to verify the key works
|
|
198
|
+
try {
|
|
199
|
+
let response;
|
|
200
|
+
if (providerKey === 'anthropic') {
|
|
201
|
+
response = await fetch('https://api.anthropic.com/v1/messages', {
|
|
202
|
+
method: 'POST',
|
|
203
|
+
signal: AbortSignal.timeout(5000),
|
|
204
|
+
headers: {
|
|
205
|
+
'x-api-key': apiKey,
|
|
206
|
+
'anthropic-version': '2023-06-01',
|
|
207
|
+
'content-type': 'application/json',
|
|
208
|
+
},
|
|
209
|
+
body: JSON.stringify({
|
|
210
|
+
model: 'claude-3-haiku-20240307',
|
|
211
|
+
max_tokens: 1,
|
|
212
|
+
messages: [{ role: 'user', content: 'hi' }],
|
|
213
|
+
}),
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
else if (providerKey === 'openai') {
|
|
217
|
+
response = await fetch('https://api.openai.com/v1/models', {
|
|
218
|
+
signal: AbortSignal.timeout(5000),
|
|
219
|
+
headers: { Authorization: `Bearer ${apiKey}` },
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
else if (providerKey === 'google') {
|
|
223
|
+
response = await fetch(`https://generativelanguage.googleapis.com/v1beta/models?key=${encodeURIComponent(apiKey)}`, { signal: AbortSignal.timeout(5000) });
|
|
224
|
+
}
|
|
225
|
+
else if (providerKey === 'groq') {
|
|
226
|
+
response = await fetch('https://api.groq.com/openai/v1/models', {
|
|
227
|
+
signal: AbortSignal.timeout(5000),
|
|
228
|
+
headers: { Authorization: `Bearer ${apiKey}` },
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
else {
|
|
232
|
+
// Provider not supported for live validation — skip
|
|
233
|
+
return { valid: true };
|
|
234
|
+
}
|
|
235
|
+
if (response.ok) {
|
|
236
|
+
return { valid: true };
|
|
237
|
+
}
|
|
238
|
+
// Parse error message from response body when possible
|
|
239
|
+
let detail;
|
|
240
|
+
try {
|
|
241
|
+
const body = (await response.json());
|
|
242
|
+
detail = body?.error?.message ?? (typeof body?.message === 'string' ? body.message : undefined);
|
|
243
|
+
}
|
|
244
|
+
catch {
|
|
245
|
+
// ignore parse failure
|
|
246
|
+
}
|
|
247
|
+
return {
|
|
248
|
+
valid: false,
|
|
249
|
+
error: detail ?? `HTTP ${response.status}`,
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
catch (err) {
|
|
253
|
+
if (err instanceof Error && err.name === 'TimeoutError') {
|
|
254
|
+
return { valid: false, error: 'Request timed out (5s)' };
|
|
255
|
+
}
|
|
256
|
+
return {
|
|
257
|
+
valid: false,
|
|
258
|
+
error: err instanceof Error ? err.message : 'Network error',
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
}
|
|
151
262
|
// Interactive Onboarding
|
|
152
263
|
async function runInteractive() {
|
|
153
264
|
const banner = figlet.textSync('profClaw', { font: 'Standard' });
|
|
@@ -364,28 +475,56 @@ async function runInteractive() {
|
|
|
364
475
|
success(`${chosen.name} already configured from ${chosen.envVar}`);
|
|
365
476
|
}
|
|
366
477
|
else {
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
478
|
+
let configured = false;
|
|
479
|
+
while (!configured) {
|
|
480
|
+
let keyInput;
|
|
481
|
+
try {
|
|
482
|
+
keyInput = await input({
|
|
483
|
+
message: chosen.envVar,
|
|
484
|
+
theme: { prefix: ' ' },
|
|
485
|
+
});
|
|
486
|
+
}
|
|
487
|
+
catch {
|
|
488
|
+
warn('Input cancelled, skipping provider.');
|
|
489
|
+
break;
|
|
490
|
+
}
|
|
491
|
+
if (!keyInput) {
|
|
492
|
+
warn('No key provided, skipping.');
|
|
493
|
+
break;
|
|
494
|
+
}
|
|
495
|
+
const verifySpin = spinner('Verifying API key...');
|
|
496
|
+
verifySpin.start();
|
|
497
|
+
const validation = await validateProviderKey(chosen.key, keyInput);
|
|
498
|
+
verifySpin.stop();
|
|
499
|
+
if (validation.valid) {
|
|
373
500
|
if (chosen.key === 'anthropic')
|
|
374
501
|
anthropicKey = keyInput;
|
|
375
502
|
else if (chosen.key === 'openai')
|
|
376
503
|
openaiKey = keyInput;
|
|
377
|
-
else
|
|
504
|
+
else
|
|
378
505
|
process.env[chosen.envVar] = keyInput;
|
|
379
|
-
}
|
|
380
506
|
success(`${chosen.name} configured.`);
|
|
507
|
+
configured = true;
|
|
381
508
|
}
|
|
382
509
|
else {
|
|
383
|
-
|
|
510
|
+
error(`Invalid key: ${validation.error ?? 'verification failed'}`);
|
|
511
|
+
let retry = false;
|
|
512
|
+
try {
|
|
513
|
+
retry = await confirm({
|
|
514
|
+
message: 'Re-enter the key?',
|
|
515
|
+
default: true,
|
|
516
|
+
theme: { prefix: ' ' },
|
|
517
|
+
});
|
|
518
|
+
}
|
|
519
|
+
catch {
|
|
520
|
+
// cancelled
|
|
521
|
+
}
|
|
522
|
+
if (!retry) {
|
|
523
|
+
warn(`Skipping ${chosen.name}.`);
|
|
524
|
+
break;
|
|
525
|
+
}
|
|
384
526
|
}
|
|
385
527
|
}
|
|
386
|
-
catch {
|
|
387
|
-
warn('Input cancelled, skipping provider.');
|
|
388
|
-
}
|
|
389
528
|
}
|
|
390
529
|
}
|
|
391
530
|
else {
|
|
@@ -411,13 +550,30 @@ async function runInteractive() {
|
|
|
411
550
|
ollamaUrl,
|
|
412
551
|
extraEnvVars,
|
|
413
552
|
});
|
|
553
|
+
console.log(chalk.bold.white('\n Configuration Preview:\n'));
|
|
554
|
+
console.log(formatEnvPreview(envContent));
|
|
555
|
+
console.log('');
|
|
556
|
+
let writeConfirmed = true;
|
|
414
557
|
try {
|
|
415
|
-
|
|
416
|
-
|
|
558
|
+
writeConfirmed = await confirm({
|
|
559
|
+
message: 'Write this configuration to .env?',
|
|
560
|
+
default: true,
|
|
561
|
+
theme: { prefix: ' ' },
|
|
562
|
+
});
|
|
417
563
|
}
|
|
418
|
-
catch
|
|
419
|
-
|
|
420
|
-
|
|
564
|
+
catch { /* Ctrl+C — keep default true */ }
|
|
565
|
+
if (!writeConfirmed) {
|
|
566
|
+
warn('Skipped .env write. You can create it manually.');
|
|
567
|
+
}
|
|
568
|
+
else {
|
|
569
|
+
try {
|
|
570
|
+
writeFileSync(envPath, envContent, { mode: 0o600 });
|
|
571
|
+
success('.env file created.');
|
|
572
|
+
}
|
|
573
|
+
catch (err) {
|
|
574
|
+
error(`Failed to write .env: ${err instanceof Error ? err.message : 'unknown'}`);
|
|
575
|
+
info('Create .env manually with the values above.');
|
|
576
|
+
}
|
|
421
577
|
}
|
|
422
578
|
}
|
|
423
579
|
else {
|
|
@@ -437,21 +593,44 @@ async function runInteractive() {
|
|
|
437
593
|
keysToWrite['OPENAI_API_KEY'] = openaiKey;
|
|
438
594
|
if (ollamaUrl)
|
|
439
595
|
keysToWrite['OLLAMA_BASE_URL'] = ollamaUrl;
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
}
|
|
596
|
+
// Show preview of what will change
|
|
597
|
+
const allUpdates = { PROFCLAW_MODE: mode, ...keysToWrite };
|
|
598
|
+
console.log(chalk.bold.white('\n Changes to existing .env:\n'));
|
|
599
|
+
for (const [key, value] of Object.entries(allUpdates)) {
|
|
600
|
+
const masked = isSensitiveKey(key) ? maskApiKey(value) : value;
|
|
601
|
+
const action = content.includes(`${key}=`) ? chalk.yellow('update') : chalk.green('add');
|
|
602
|
+
console.log(` [${action}] ${chalk.cyan(key)}=${chalk.white(masked)}`);
|
|
603
|
+
}
|
|
604
|
+
console.log('');
|
|
605
|
+
let writeConfirmed = true;
|
|
606
|
+
try {
|
|
607
|
+
writeConfirmed = await confirm({
|
|
608
|
+
message: 'Apply these changes to .env?',
|
|
609
|
+
default: true,
|
|
610
|
+
theme: { prefix: ' ' },
|
|
611
|
+
});
|
|
447
612
|
}
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
success(`PROFCLAW_MODE=${mode} + ${keyCount} provider key(s) saved to .env`);
|
|
613
|
+
catch { /* Ctrl+C — keep default true */ }
|
|
614
|
+
if (!writeConfirmed) {
|
|
615
|
+
warn('Skipped .env update. You can edit it manually.');
|
|
452
616
|
}
|
|
453
617
|
else {
|
|
454
|
-
|
|
618
|
+
for (const [key, value] of Object.entries(keysToWrite)) {
|
|
619
|
+
if (content.includes(`${key}=`)) {
|
|
620
|
+
content = content.replace(new RegExp(`${key}=.*`), `${key}=${value}`);
|
|
621
|
+
}
|
|
622
|
+
else {
|
|
623
|
+
content += `${key}=${value}\n`;
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
writeFileSync(envPath, content);
|
|
627
|
+
const keyCount = Object.keys(keysToWrite).length;
|
|
628
|
+
if (keyCount > 0) {
|
|
629
|
+
success(`PROFCLAW_MODE=${mode} + ${keyCount} provider key(s) saved to .env`);
|
|
630
|
+
}
|
|
631
|
+
else {
|
|
632
|
+
success(`PROFCLAW_MODE=${mode} set in .env`);
|
|
633
|
+
}
|
|
455
634
|
}
|
|
456
635
|
}
|
|
457
636
|
// Steps 5-6: Delegate to setup wizard for admin account + registration
|
|
@@ -523,6 +702,7 @@ export function onboardCommand() {
|
|
|
523
702
|
else {
|
|
524
703
|
await runInteractive();
|
|
525
704
|
}
|
|
705
|
+
process.exit(0);
|
|
526
706
|
}
|
|
527
707
|
catch (err) {
|
|
528
708
|
error(err instanceof Error ? err.message : 'Onboarding failed');
|