profclaw 0.0.1-beta.2 → 2.0.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/CHANGELOG.md +21 -38
- package/CONTRIBUTING.md +3 -5
- package/README.md +128 -63
- package/dist/chat/execution/tools/index.d.ts +1 -1
- package/dist/chat/execution/tools/index.js +41 -2
- package/dist/chat/providers/slack/index.d.ts +2 -2
- package/dist/cli/commands/models.js +39 -26
- package/dist/cli/commands/onboard.js +64 -79
- package/dist/cli/commands/setup.js +293 -90
- package/dist/cli/index.js +0 -6
- package/dist/cli/providers.d.ts +15 -0
- package/dist/cli/providers.js +41 -0
- package/dist/core/deployment.js +2 -0
- package/dist/providers/ai-sdk.js +26 -6
- package/dist/routes/channels.d.ts +12 -0
- package/dist/routes/channels.js +166 -0
- package/dist/server/route-loader.js +1 -0
- package/dist/server.js +115 -109
- package/package.json +1 -1
- package/skills/git-workflow/SKILL.md +3 -3
- package/ui/dist/assets/{ActivityView-DIPQSJ_d.js → ActivityView-BeshZXmE.js} +1 -1
- package/ui/dist/assets/{AgentList-CqyaYrcq.js → AgentList-QVHeldPi.js} +1 -1
- package/ui/dist/assets/{AnalyticsDashboard-C-mjuGHT.js → AnalyticsDashboard-C9R97dXE.js} +1 -1
- package/ui/dist/assets/{AreaChart-CfYWmbtr.js → AreaChart-B73gaiVQ.js} +1 -1
- package/ui/dist/assets/{CartesianChart-BaQ3It0c.js → CartesianChart-CXYL2R-A.js} +1 -1
- package/ui/dist/assets/{ChatView-DxxQy6pl.js → ChatView-qjZErlrp.js} +1 -1
- package/ui/dist/assets/{CostsDashboard-CDBBcGkg.js → CostsDashboard-O4DCLy1i.js} +1 -1
- package/ui/dist/assets/{EstimateSelect-CDjf5qKl.js → EstimateSelect-1hQf4Osk.js} +1 -1
- package/ui/dist/assets/{FloatingChatbot-CZHjvJIe.js → FloatingChatbot-BZBzrJxd.js} +1 -1
- package/ui/dist/assets/{InviteCodeManagement-DTm-IPTm.js → InviteCodeManagement-LEoGqYeA.js} +1 -1
- package/ui/dist/assets/{ProjectDetail-DlYUcOss.js → ProjectDetail--gPfvATB.js} +1 -1
- package/ui/dist/assets/{ProjectIcon-BMRpnM04.js → ProjectIcon-Chd_ofsw.js} +1 -1
- package/ui/dist/assets/{ProjectList-D85TN0i0.js → ProjectList-BvUfVB6c.js} +1 -1
- package/ui/dist/assets/{Settings-CgPqzUvj.js → Settings-1kaf7VHE.js} +1 -1
- package/ui/dist/assets/{StatusIndicator-yig0uZEA.js → StatusIndicator-pRfkNcdV.js} +1 -1
- package/ui/dist/assets/{SummaryDetail-CwLAfHgJ.js → SummaryDetail-DV3AmONk.js} +1 -1
- package/ui/dist/assets/{SummaryList-BvS5Idnu.js → SummaryList-B6kXiTxL.js} +1 -1
- package/ui/dist/assets/{TaskDetail-zarC1fOt.js → TaskDetail-CV6CzbOS.js} +1 -1
- package/ui/dist/assets/{TaskList-CyJq3ANE.js → TaskList-DL7brQKd.js} +1 -1
- package/ui/dist/assets/{TicketBoard-BlWr3-iH.js → TicketBoard-CrkkFj7C.js} +1 -1
- package/ui/dist/assets/{TicketDetail-DmqWKj2W.js → TicketDetail-hnnYclpD.js} +1 -1
- package/ui/dist/assets/{TicketList-Scj4pMWa.js → TicketList-CsDAyQCL.js} +1 -1
- package/ui/dist/assets/{UserManagement-BH7uG7dw.js → UserManagement-BGFQyTSr.js} +1 -1
- package/ui/dist/assets/{ViewSwitcher-3HzZUdWn.js → ViewSwitcher-CnL0OqA8.js} +1 -1
- package/ui/dist/assets/{alert-dialog-DWPb2IfQ.js → alert-dialog-SKM6Gjz4.js} +1 -1
- package/ui/dist/assets/{archive-CGck7gxR.js → archive-BsLa7brF.js} +1 -1
- package/ui/dist/assets/{badge-DEmc3Z_l.js → badge-CVHH1a-v.js} +1 -1
- package/ui/dist/assets/{brain-CfFdLVqb.js → brain-6o_RHVpe.js} +1 -1
- package/ui/dist/assets/{bug-DqSGPUUE.js → bug-CmZI7jqM.js} +1 -1
- package/ui/dist/assets/{calendar-BuZ4zbPW.js → calendar-Bf0t2B82.js} +1 -1
- package/ui/dist/assets/{chevron-up-DcJ4LL_N.js → chevron-up-CoUsOvZj.js} +1 -1
- package/ui/dist/assets/{circle-x-C78PNZjF.js → circle-x-Dgw11LgT.js} +1 -1
- package/ui/dist/assets/{constants-DhDjZe4P.js → constants-Q5Zivl-a.js} +1 -1
- package/ui/dist/assets/{cpu-Ck6AoG8c.js → cpu-DiPMQICV.js} +1 -1
- package/ui/dist/assets/{database-CA2w8Lvt.js → database-BwTfupDi.js} +1 -1
- package/ui/dist/assets/{dialog-BOdGWhgE.js → dialog-BUqN9Psj.js} +1 -1
- package/ui/dist/assets/{ellipsis-FhHKRbfl.js → ellipsis-UJx4Xnf6.js} +1 -1
- package/ui/dist/assets/{ellipsis-vertical-CO0UqE4-.js → ellipsis-vertical-DoULYEKn.js} +1 -1
- package/ui/dist/assets/{file-code-ChnhYYj1.js → file-code-B2UrJLwi.js} +1 -1
- package/ui/dist/assets/{folder-open-CHwA1-ve.js → folder-open-BJi577JH.js} +1 -1
- package/ui/dist/assets/{funnel-ByEjRFNB.js → funnel-PkaD_HSR.js} +1 -1
- package/ui/dist/assets/{git-branch-GTOPQgU4.js → git-branch-C_K30am0.js} +1 -1
- package/ui/dist/assets/{git-commit-horizontal-F5M84Kut.js → git-commit-horizontal-IT6ecxWQ.js} +1 -1
- package/ui/dist/assets/{globe-CQWfr7hT.js → globe-f-jjCa_g.js} +1 -1
- package/ui/dist/assets/{hash-nKC9gtLg.js → hash-DNEv8Elo.js} +1 -1
- package/ui/dist/assets/{history-DfFSA9xJ.js → history-BQSBo_1Q.js} +1 -1
- package/ui/dist/assets/{index-DHGvP9mp.js → index-BUmnwPQr.js} +1 -1
- package/ui/dist/assets/{index-Z4-RtZcs.js → index-BfF5G4Cw.js} +1 -1
- package/ui/dist/assets/{index-DeI8lKRR.js → index-C8N375c2.js} +1 -1
- package/ui/dist/assets/index-CuxnqVVz.css +1 -0
- package/ui/dist/assets/{index-Ca3vk7Gq.js → index-CzMM3QOk.js} +1 -1
- package/ui/dist/assets/{index--JkIxVXb.js → index-lJlNPFVJ.js} +3 -3
- package/ui/dist/assets/{index-a4Fxq0Hb.js → index-nS3EErDg.js} +1 -1
- package/ui/dist/assets/{layers-DFeLExSa.js → layers-jFqVrWMD.js} +1 -1
- package/ui/dist/assets/{layout-dashboard-WmgjMhWF.js → layout-dashboard-CcKt1hXw.js} +1 -1
- package/ui/dist/assets/{lightbulb-Bo8hEr7B.js → lightbulb-Jhp7FvbU.js} +1 -1
- package/ui/dist/assets/{link-2-YqrpQXBH.js → link-2-DdO7ostF.js} +1 -1
- package/ui/dist/assets/{markdown-renderer-Croje6Xe.js → markdown-renderer-n1ToC4XQ.js} +1 -1
- package/ui/dist/assets/{message-square-CD0H5hot.js → message-square-CBgH65X7.js} +1 -1
- package/ui/dist/assets/{pencil-DpFnj5dn.js → pencil-CYXCEPQh.js} +1 -1
- package/ui/dist/assets/{play-DVgea_jT.js → play-d1ONaH0-.js} +1 -1
- package/ui/dist/assets/{popover-JXecfWG5.js → popover-CrmZgoWu.js} +1 -1
- package/ui/dist/assets/{progress-C1ghf1Fu.js → progress-uv4SPkL5.js} +1 -1
- package/ui/dist/assets/{rocket-BFxPYGx9.js → rocket-DhvUetsk.js} +1 -1
- package/ui/dist/assets/{select-MADP8m6Q.js → select-CeQ8AHGy.js} +1 -1
- package/ui/dist/assets/{send-eYnW_7n-.js → send-P0r5D7td.js} +1 -1
- package/ui/dist/assets/{server-CPMaysH8.js → server-CVHTZB72.js} +1 -1
- package/ui/dist/assets/{settings-2-scXUOuE_.js → settings-2-ocj5uHGx.js} +1 -1
- package/ui/dist/assets/{sheet-r6NSOxi-.js → sheet-DuQExSho.js} +1 -1
- package/ui/dist/assets/{shield-check-PEr7nmVw.js → shield-check-DfVdE34l.js} +1 -1
- package/ui/dist/assets/{shield-off-CLtXio62.js → shield-off-8l0J6R-8.js} +1 -1
- package/ui/dist/assets/{skeleton-C9oEzNlU.js → skeleton-TFiFJ3nB.js} +1 -1
- package/ui/dist/assets/{smartphone-DusFfY0U.js → smartphone-77_g3SQn.js} +1 -1
- package/ui/dist/assets/{square-e1yxB2eR.js → square-Ckzsr3Rn.js} +1 -1
- package/ui/dist/assets/{switch-tNs0n-kz.js → switch-CAePkd6k.js} +1 -1
- package/ui/dist/assets/{table-CXxtLicg.js → table-ZjAZ7hkt.js} +1 -1
- package/ui/dist/assets/{tag-tAwMmQ9G.js → tag-C35mgoEv.js} +1 -1
- package/ui/dist/assets/{textarea-BjiEeIWh.js → textarea-DsVPnSgR.js} +1 -1
- package/ui/dist/assets/{timer-Vel1N3RP.js → timer-DHJBS2w1.js} +1 -1
- package/ui/dist/assets/{tooltip-ZMwtfr1J.js → tooltip-BYmQ331W.js} +1 -1
- package/ui/dist/assets/{trash-2-eM-CNwsZ.js → trash-2-keO5tKPE.js} +1 -1
- package/ui/dist/assets/{trending-up-BGafmjRo.js → trending-up-BBv8KbrY.js} +1 -1
- package/ui/dist/assets/{wand-sparkles-DPvcd9Pi.js → wand-sparkles-BusQ52ZK.js} +1 -1
- package/ui/dist/assets/{wrench-B8s3zYVV.js → wrench-02YaOSiK.js} +1 -1
- package/ui/dist/index.html +2 -2
- package/dist/chat/auto-reply.d.ts +0 -90
- package/dist/chat/auto-reply.js +0 -272
- package/dist/chat/execution/pty.d.ts +0 -92
- package/dist/chat/execution/pty.js +0 -285
- package/dist/chat/execution/tools/glinr-ops.d.ts +0 -202
- package/dist/chat/execution/tools/glinr-ops.js +0 -694
- package/dist/cli/commands/browser.d.ts +0 -3
- package/dist/cli/commands/browser.js +0 -138
- package/dist/cli/commands/canvas.d.ts +0 -3
- package/dist/cli/commands/canvas.js +0 -155
- package/dist/cli/commands/nodes.d.ts +0 -3
- package/dist/cli/commands/nodes.js +0 -193
- package/dist/diagnostics/exporters.d.ts +0 -21
- package/dist/diagnostics/exporters.js +0 -138
- package/dist/diagnostics/index.d.ts +0 -10
- package/dist/diagnostics/index.js +0 -9
- package/dist/diagnostics/middleware.d.ts +0 -12
- package/dist/diagnostics/middleware.js +0 -58
- package/dist/diagnostics/tracer.d.ts +0 -133
- package/dist/diagnostics/tracer.js +0 -257
- package/dist/discovery/index.d.ts +0 -8
- package/dist/discovery/index.js +0 -7
- package/dist/discovery/mdns.d.ts +0 -40
- package/dist/discovery/mdns.js +0 -249
- package/dist/plugins/registry.d.ts +0 -122
- package/dist/plugins/registry.js +0 -352
- package/dist/plugins/sandbox.d.ts +0 -77
- package/dist/plugins/sandbox.js +0 -287
- package/dist/plugins/search/brave.d.ts +0 -9
- package/dist/plugins/search/brave.js +0 -157
- package/dist/plugins/search/duckduckgo.d.ts +0 -9
- package/dist/plugins/search/duckduckgo.js +0 -171
- package/dist/plugins/search/index.d.ts +0 -13
- package/dist/plugins/search/index.js +0 -23
- package/dist/plugins/search/searxng.d.ts +0 -9
- package/dist/plugins/search/searxng.js +0 -170
- package/dist/plugins/search/serper.d.ts +0 -9
- package/dist/plugins/search/serper.js +0 -135
- package/dist/plugins/search/tavily.d.ts +0 -9
- package/dist/plugins/search/tavily.js +0 -146
- package/dist/providers/adapters/anthropic.d.ts +0 -26
- package/dist/providers/adapters/anthropic.js +0 -306
- package/dist/providers/adapters/base.d.ts +0 -53
- package/dist/providers/adapters/base.js +0 -99
- package/dist/providers/adapters/ollama.d.ts +0 -30
- package/dist/providers/adapters/ollama.js +0 -292
- package/dist/utils/ai-cache.d.ts +0 -72
- package/dist/utils/ai-cache.js +0 -204
- package/dist/utils/file-lock.d.ts +0 -85
- package/dist/utils/file-lock.js +0 -204
- package/ui/dist/assets/index-WclMPci1.css +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,49 +1,32 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
## [2.0.0](https://github.com/profclaw/profclaw/releases/tag/v2.0.0) (2026-03-14)
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
* `GLINR_REQUIRE_REDIS` renamed to `PROFCLAW_REQUIRE_REDIS`
|
|
9
|
-
* `glinr.mjs` renamed to `profclaw.mjs`
|
|
10
|
-
* All `glinr-*` skill names renamed to `profclaw-*`
|
|
7
|
+
Initial public beta release.
|
|
11
8
|
|
|
12
9
|
### Features
|
|
13
10
|
|
|
14
|
-
* **
|
|
15
|
-
* **
|
|
16
|
-
* **
|
|
17
|
-
* **
|
|
18
|
-
* **
|
|
19
|
-
* **
|
|
20
|
-
* **
|
|
21
|
-
* **Plugin SDK
|
|
22
|
-
* **
|
|
23
|
-
* **
|
|
24
|
-
* **
|
|
25
|
-
* **
|
|
26
|
-
* **Pico Docker Image**: Minimal image without Chromium (`Dockerfile.pico`)
|
|
11
|
+
* **35 AI providers** - Anthropic, OpenAI, Google, Groq, Ollama, DeepSeek, Bedrock, and more
|
|
12
|
+
* **22 chat channels** - Slack, Discord, Telegram, WhatsApp, iMessage, Matrix, Teams, and 15 more
|
|
13
|
+
* **72 built-in tools** - file ops, git, browser automation, cron, web search, canvas, voice
|
|
14
|
+
* **50 skills** - coding agent, GitHub issues, Notion, Obsidian, image gen, and more
|
|
15
|
+
* **3 deployment modes** - pico (~140MB), mini (~145MB), pro (full features)
|
|
16
|
+
* **MCP server** - native Model Context Protocol support (stdio + SSE)
|
|
17
|
+
* **Voice I/O** - STT (Whisper) + TTS (ElevenLabs/OpenAI/system) + Talk Mode
|
|
18
|
+
* **Plugin SDK** - build and share third-party plugins via npm
|
|
19
|
+
* **Mode-aware routing** - API endpoints, tools, and capabilities gated by deployment mode
|
|
20
|
+
* **In-memory queue** - BullMQ-compatible task queue without Redis for pico/mini modes
|
|
21
|
+
* **Cost tracking** - per-token budget management with alerts at 50/80/100%
|
|
22
|
+
* **Project management** - tickets, Kanban, sprints, burndown charts, GitHub/Jira/Linear sync
|
|
27
23
|
|
|
28
|
-
### Chat Channels
|
|
24
|
+
### Chat Channels
|
|
29
25
|
|
|
30
|
-
|
|
31
|
-
* WebChat, Matrix, Google Chat, Microsoft Teams (new)
|
|
26
|
+
Slack, Discord, Telegram, WhatsApp, WebChat, Matrix, Google Chat, Microsoft Teams, iMessage, Signal, IRC, LINE, Mattermost, DingTalk, WeCom, Feishu/Lark, QQ, Nostr, Twitch, Zalo, Nextcloud Talk, Synology Chat
|
|
32
27
|
|
|
33
|
-
###
|
|
28
|
+
### Integrations
|
|
34
29
|
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
|
|
38
|
-
## [1.0.0](https://github.com/profclaw/profclaw/releases/tag/v1.0.0) (2026-03-10)
|
|
39
|
-
|
|
40
|
-
### Features
|
|
41
|
-
|
|
42
|
-
* Initial release as GLINR Task Manager v1.0.0
|
|
43
|
-
* AI agent task orchestration with 51+ built-in tools
|
|
44
|
-
* 15+ AI provider support (Anthropic, OpenAI, Google, Azure, Ollama, etc.)
|
|
45
|
-
* 4 chat channels (Slack, Discord, Telegram, WhatsApp)
|
|
46
|
-
* GitHub, Jira, Linear integrations
|
|
47
|
-
* MCP server for Model Context Protocol
|
|
48
|
-
* Redis-backed BullMQ task queue
|
|
49
|
-
* React 19 dashboard UI
|
|
30
|
+
* GitHub (webhooks, OAuth, issue sync, PR automation)
|
|
31
|
+
* Jira (webhooks, OAuth, issue sync, transitions)
|
|
32
|
+
* Linear (webhooks, OAuth, issue sync)
|
package/CONTRIBUTING.md
CHANGED
|
@@ -50,7 +50,7 @@ Open a discussion or issue describing:
|
|
|
50
50
|
|
|
51
51
|
1. Fork the repo and create a branch from `main`
|
|
52
52
|
2. Follow the naming convention: `feat/description`, `fix/description`, `refactor/description`
|
|
53
|
-
3. Write code following existing patterns (see `
|
|
53
|
+
3. Write code following existing patterns (see `AGENTS.md` for conventions)
|
|
54
54
|
4. Add tests for new features
|
|
55
55
|
5. Ensure `pnpm build && pnpm test && pnpm lint` pass
|
|
56
56
|
6. Submit a pull request
|
|
@@ -61,8 +61,6 @@ We use conventional commits:
|
|
|
61
61
|
|
|
62
62
|
```
|
|
63
63
|
<type>: <description>
|
|
64
|
-
|
|
65
|
-
Co-Authored-By: Your Name <your@email.com>
|
|
66
64
|
```
|
|
67
65
|
|
|
68
66
|
Types: `feat`, `fix`, `perf`, `refactor`, `docs`, `test`
|
|
@@ -75,7 +73,7 @@ Types: `feat`, `fix`, `perf`, `refactor`, `docs`, `test`
|
|
|
75
73
|
- Tailwind v4 for UI styling (no inline styles)
|
|
76
74
|
- Lucide icons only
|
|
77
75
|
- Zod validation at system boundaries
|
|
78
|
-
- See `
|
|
76
|
+
- See `AGENTS.md` for full conventions
|
|
79
77
|
|
|
80
78
|
## Architecture
|
|
81
79
|
|
|
@@ -86,7 +84,7 @@ src/
|
|
|
86
84
|
core/ - Deployment modes, feature flags
|
|
87
85
|
integrations/ - GitHub, Jira, Linear webhooks
|
|
88
86
|
queue/ - BullMQ + in-memory task queue
|
|
89
|
-
providers/ - AI SDK providers (
|
|
87
|
+
providers/ - AI SDK providers (35+)
|
|
90
88
|
skills/ - Skill loader and registry
|
|
91
89
|
types/ - Shared TypeScript types
|
|
92
90
|
|
package/README.md
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
<p align="center">
|
|
2
|
-
<
|
|
3
|
-
|
|
2
|
+
<img src="ui/public/brand/profclaw-appicon.svg" alt="profClaw" width="120" height="120">
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
<h1 align="center">profClaw</h1>
|
|
6
|
+
|
|
7
|
+
<p align="center">
|
|
8
|
+
<b>Smart, lightweight AI agent engine.</b><br>
|
|
9
|
+
Run locally on anything from a Raspberry Pi to a production VPS.
|
|
4
10
|
</p>
|
|
5
11
|
|
|
6
12
|
<p align="center">
|
|
@@ -18,9 +24,37 @@
|
|
|
18
24
|
|
|
19
25
|
---
|
|
20
26
|
|
|
21
|
-
|
|
27
|
+
## Table of Contents
|
|
28
|
+
|
|
29
|
+
- [Why profClaw](#why-profclaw)
|
|
30
|
+
- [Features](#features)
|
|
31
|
+
- [Installation](#installation)
|
|
32
|
+
- [Deployment Modes](#deployment-modes)
|
|
33
|
+
- [Where It Runs](#where-it-runs)
|
|
34
|
+
- [Configuration](#configuration)
|
|
35
|
+
- [AI Providers](#ai-providers)
|
|
36
|
+
- [Chat Channels](#chat-channels)
|
|
37
|
+
- [Integrations](#integrations)
|
|
38
|
+
- [Architecture](#architecture)
|
|
39
|
+
- [Development](#development)
|
|
40
|
+
- [License](#license)
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## Why profClaw
|
|
45
|
+
|
|
46
|
+
Most AI coding tools are either cloud-only (Cursor, Devin) or single-purpose CLIs (Aider, SWE-Agent). profClaw is different:
|
|
22
47
|
|
|
23
|
-
|
|
48
|
+
- **Local-first** - runs on your machine, your data stays local
|
|
49
|
+
- **Multi-agent orchestration** - routes tasks to the right agent (Claude, GPT, Ollama) based on capability scoring, not just round-robin
|
|
50
|
+
- **Real task queue** - BullMQ with dead letter queue, retry with backoff, priority scheduling
|
|
51
|
+
- **Built-in project management** - tickets, Kanban, sprints, burndown charts, bi-directional sync with GitHub/Jira/Linear
|
|
52
|
+
- **22 chat channels** - talk to your AI through Slack, Discord, Telegram, WhatsApp, Teams, or 17 others
|
|
53
|
+
- **Cost tracking** - per-token budget management with alerts at 50/80/100%
|
|
54
|
+
- **72 built-in tools** - file ops, git, browser automation, cron, web search, canvas, voice
|
|
55
|
+
- **Mode-aware** - scales from a Raspberry Pi (pico) to a full team server (pro)
|
|
56
|
+
|
|
57
|
+
No other open-source tool combines task orchestration, project management, and cost tracking in one self-hosted package.
|
|
24
58
|
|
|
25
59
|
## Features
|
|
26
60
|
|
|
@@ -33,30 +67,24 @@ Runs on your machine. Your data stays local. No cloud required.
|
|
|
33
67
|
| **MCP server** | Native Model Context Protocol - connect to any MCP-compatible client |
|
|
34
68
|
| **Voice I/O** | STT (Whisper) + TTS (ElevenLabs/OpenAI/system) + Talk Mode |
|
|
35
69
|
| **Plugin SDK** | Build and share third-party plugins via npm or ClawHub |
|
|
36
|
-
| **3 deployment modes** | Pico (~140MB), Mini (~
|
|
70
|
+
| **3 deployment modes** | Pico (~140MB), Mini (~145MB), Pro (full features) |
|
|
37
71
|
|
|
38
|
-
##
|
|
72
|
+
## Installation
|
|
39
73
|
|
|
40
|
-
|
|
74
|
+
### npm (recommended)
|
|
41
75
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
| **mini** | + Dashboard, basic cron, 1-2 channels | ~180MB | Personal dev server, VPS |
|
|
46
|
-
| **pro** | + All channels, Redis queues, plugins, sandbox | ~200MB | Teams, production |
|
|
47
|
-
|
|
48
|
-
Set via `PROFCLAW_MODE=pico|mini|pro` environment variable.
|
|
76
|
+
```bash
|
|
77
|
+
npx profclaw onboard
|
|
78
|
+
```
|
|
49
79
|
|
|
50
|
-
|
|
80
|
+
This runs the zero-to-running wizard: picks your AI provider, sets up config, and starts the server.
|
|
51
81
|
|
|
52
|
-
|
|
82
|
+
Or install globally:
|
|
53
83
|
|
|
54
84
|
```bash
|
|
55
|
-
npx profclaw onboard # Zero-to-running wizard
|
|
56
|
-
# or
|
|
57
85
|
npm install -g profclaw@latest
|
|
58
|
-
profclaw setup
|
|
59
|
-
profclaw serve
|
|
86
|
+
profclaw setup
|
|
87
|
+
profclaw serve
|
|
60
88
|
```
|
|
61
89
|
|
|
62
90
|
### Docker
|
|
@@ -74,11 +102,11 @@ docker run -d \
|
|
|
74
102
|
```bash
|
|
75
103
|
git clone https://github.com/profclaw/profclaw.git
|
|
76
104
|
cd profclaw
|
|
77
|
-
cp .env.example .env
|
|
105
|
+
cp .env.example .env
|
|
78
106
|
docker compose up -d
|
|
79
107
|
```
|
|
80
108
|
|
|
81
|
-
|
|
109
|
+
Want free local AI? Add Ollama:
|
|
82
110
|
|
|
83
111
|
```bash
|
|
84
112
|
docker compose --profile ai up -d
|
|
@@ -90,6 +118,32 @@ docker compose --profile ai up -d
|
|
|
90
118
|
curl -fsSL https://raw.githubusercontent.com/profclaw/profclaw/main/install.sh | bash
|
|
91
119
|
```
|
|
92
120
|
|
|
121
|
+
## Deployment Modes
|
|
122
|
+
|
|
123
|
+
profClaw scales from a Raspberry Pi to a full production server:
|
|
124
|
+
|
|
125
|
+
| Mode | What you get | RAM | Best for |
|
|
126
|
+
|------|-------------|-----|----------|
|
|
127
|
+
| **pico** | Agent + tools + 1 chat channel + cron. No UI. | ~140MB | Raspberry Pi, $5 VPS, home server |
|
|
128
|
+
| **mini** | + Dashboard, integrations, 3 channels | ~145MB | Personal dev server, small VPS |
|
|
129
|
+
| **pro** | + All channels, Redis queues, plugins, browser tools | ~120-200MB | Teams, production |
|
|
130
|
+
|
|
131
|
+
Set via `PROFCLAW_MODE=pico|mini|pro` environment variable.
|
|
132
|
+
|
|
133
|
+
## Where It Runs
|
|
134
|
+
|
|
135
|
+
| Hardware | RAM | Recommended mode |
|
|
136
|
+
|----------|-----|-----------------|
|
|
137
|
+
| Raspberry Pi Zero 2W | 512MB | pico |
|
|
138
|
+
| Raspberry Pi 3/4/5 | 1-8GB | mini or pro |
|
|
139
|
+
| Orange Pi / Rock Pi | 1-4GB | mini or pro |
|
|
140
|
+
| $5/mo VPS (Hetzner, OVH) | 512MB-1GB | pico or mini |
|
|
141
|
+
| Old laptop / home PC | 4-16GB | pro |
|
|
142
|
+
| Docker (alongside other services) | 512MB+ | any mode |
|
|
143
|
+
| Old Android phone (Termux) | 1-2GB | pico |
|
|
144
|
+
|
|
145
|
+
profClaw requires Node.js 22+. For bare-metal embedded devices (ESP32, Arduino), see [MimiClaw](https://github.com/mimiclaw) (C) or [PicoClaw](https://github.com/picoclaw) (Go).
|
|
146
|
+
|
|
93
147
|
## Configuration
|
|
94
148
|
|
|
95
149
|
The setup wizard (`profclaw setup`) handles everything interactively. Or set environment variables:
|
|
@@ -101,8 +155,8 @@ OPENAI_API_KEY=sk-xxx
|
|
|
101
155
|
OLLAMA_BASE_URL=http://localhost:11434
|
|
102
156
|
|
|
103
157
|
# Deployment
|
|
104
|
-
PROFCLAW_MODE=mini
|
|
105
|
-
PORT=3000
|
|
158
|
+
PROFCLAW_MODE=mini
|
|
159
|
+
PORT=3000
|
|
106
160
|
|
|
107
161
|
# Optional
|
|
108
162
|
REDIS_URL=redis://localhost:6379 # Required for pro mode
|
|
@@ -110,26 +164,6 @@ REDIS_URL=redis://localhost:6379 # Required for pro mode
|
|
|
110
164
|
|
|
111
165
|
See [`.env.example`](.env.example) for all options.
|
|
112
166
|
|
|
113
|
-
## Architecture
|
|
114
|
-
|
|
115
|
-
```
|
|
116
|
-
src/
|
|
117
|
-
adapters/ AI agent adapters (tool calling, streaming)
|
|
118
|
-
chat/ Chat engine + execution pipeline
|
|
119
|
-
providers/ Slack, Discord, Telegram, WhatsApp, WebChat, ...
|
|
120
|
-
execution/ Tool executor, sandbox, agentic loop
|
|
121
|
-
core/ Deployment modes, feature flags
|
|
122
|
-
integrations/ GitHub, Jira, Linear webhooks
|
|
123
|
-
queue/ BullMQ (pro) + in-memory (pico/mini) task queue
|
|
124
|
-
providers/ 35 AI SDK providers
|
|
125
|
-
skills/ Skill loader and registry
|
|
126
|
-
mcp/ MCP server (stdio + SSE)
|
|
127
|
-
types/ Shared TypeScript types
|
|
128
|
-
|
|
129
|
-
ui/src/ React 19 + Vite dashboard (mini/pro only)
|
|
130
|
-
skills/ Built-in skill definitions
|
|
131
|
-
```
|
|
132
|
-
|
|
133
167
|
## AI Providers
|
|
134
168
|
|
|
135
169
|
35 providers with 90+ model aliases:
|
|
@@ -145,15 +179,38 @@ skills/ Built-in skill definitions
|
|
|
145
179
|
| DeepSeek | V3, R1 | No |
|
|
146
180
|
| Azure OpenAI | GPT-4o | No |
|
|
147
181
|
| xAI | Grok | No |
|
|
148
|
-
|
|
|
149
|
-
| Moonshot | Kimi | No |
|
|
150
|
-
| Qwen API | Qwen 2.5 | No |
|
|
182
|
+
| OpenRouter | Any model | No |
|
|
151
183
|
| Together | Open models | No |
|
|
152
184
|
| Fireworks | Open models | No |
|
|
153
185
|
| Mistral | Mistral Large, Codestral | No |
|
|
154
|
-
|
|
|
155
|
-
|
|
156
|
-
|
|
186
|
+
| ... and 22 more | HuggingFace, NVIDIA NIM, Cerebras, Replicate, Zhipu, Moonshot, Qwen, etc. | |
|
|
187
|
+
|
|
188
|
+
## Chat Channels
|
|
189
|
+
|
|
190
|
+
| Channel | Protocol |
|
|
191
|
+
|---------|----------|
|
|
192
|
+
| Slack | Bolt SDK |
|
|
193
|
+
| Discord | HTTP Interactions |
|
|
194
|
+
| Telegram | Bot API |
|
|
195
|
+
| WhatsApp | Cloud API |
|
|
196
|
+
| WebChat | SSE (browser-based) |
|
|
197
|
+
| Matrix | Client-Server API |
|
|
198
|
+
| Google Chat | Webhook + API |
|
|
199
|
+
| Microsoft Teams | Bot Framework |
|
|
200
|
+
| iMessage | BlueBubbles |
|
|
201
|
+
| Signal | signald bridge |
|
|
202
|
+
| IRC | TLS, RFC 1459 |
|
|
203
|
+
| LINE | Messaging API |
|
|
204
|
+
| Mattermost | REST API v4 |
|
|
205
|
+
| DingTalk | OpenAPI + webhook |
|
|
206
|
+
| WeCom | WeChat Work API |
|
|
207
|
+
| Feishu/Lark | Open Platform |
|
|
208
|
+
| QQ | Bot API |
|
|
209
|
+
| Nostr | Relay protocol |
|
|
210
|
+
| Twitch | Helix API + IRC |
|
|
211
|
+
| Zalo | OA API v3 |
|
|
212
|
+
| Nextcloud Talk | OCS API |
|
|
213
|
+
| Synology Chat | Webhook |
|
|
157
214
|
|
|
158
215
|
## Integrations
|
|
159
216
|
|
|
@@ -162,14 +219,26 @@ skills/ Built-in skill definitions
|
|
|
162
219
|
| **GitHub** | Webhooks, OAuth, issue sync, PR automation |
|
|
163
220
|
| **Jira** | Webhooks, OAuth, issue sync, transitions |
|
|
164
221
|
| **Linear** | Webhooks, OAuth, issue sync |
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
222
|
+
|
|
223
|
+
## Architecture
|
|
224
|
+
|
|
225
|
+
```
|
|
226
|
+
src/
|
|
227
|
+
adapters/ AI agent adapters (tool calling, streaming)
|
|
228
|
+
chat/ Chat engine + execution pipeline
|
|
229
|
+
providers/ Slack, Discord, Telegram, WhatsApp, WebChat, ...
|
|
230
|
+
execution/ Tool executor, sandbox, agentic loop
|
|
231
|
+
core/ Deployment modes, feature flags
|
|
232
|
+
integrations/ GitHub, Jira, Linear webhooks
|
|
233
|
+
queue/ BullMQ (pro) + in-memory (pico/mini) task queue
|
|
234
|
+
providers/ 35 AI SDK providers
|
|
235
|
+
skills/ Skill loader and registry
|
|
236
|
+
mcp/ MCP server (stdio + SSE)
|
|
237
|
+
types/ Shared TypeScript types
|
|
238
|
+
|
|
239
|
+
ui/src/ React 19 + Vite dashboard (mini/pro only)
|
|
240
|
+
skills/ Built-in skill definitions
|
|
241
|
+
```
|
|
173
242
|
|
|
174
243
|
## Development
|
|
175
244
|
|
|
@@ -187,10 +256,6 @@ See [CONTRIBUTING.md](CONTRIBUTING.md) for full guidelines.
|
|
|
187
256
|
|
|
188
257
|
See [SECURITY.md](SECURITY.md) for our security policy and how to report vulnerabilities.
|
|
189
258
|
|
|
190
|
-
## Docs & Website
|
|
191
|
-
|
|
192
|
-
Documentation and marketing site live in a separate repo: [`profclaw-site`](https://github.com/profclaw/profclaw-site)
|
|
193
|
-
|
|
194
259
|
## License
|
|
195
260
|
|
|
196
|
-
[AGPL-3.0](LICENSE)
|
|
261
|
+
[AGPL-3.0](LICENSE)
|
|
@@ -58,7 +58,7 @@ export type { SessionsSendParams, SessionsSendResult } from './sessions-send.js'
|
|
|
58
58
|
export type { BrowserNavigateResult, BrowserSnapshotResult, BrowserClickResult, BrowserTypeResult, BrowserSearchResult, BrowserScreenshotResult, BrowserPagesResult, BrowserCloseResult, } from './browser.js';
|
|
59
59
|
export declare const builtinTools: ToolDefinition[];
|
|
60
60
|
/**
|
|
61
|
-
* Register all built-in tools (with tier assignments)
|
|
61
|
+
* Register all built-in tools (with tier assignments and mode gating)
|
|
62
62
|
*/
|
|
63
63
|
export declare function registerBuiltinTools(): void;
|
|
64
64
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* Export all built-in tools and registration function.
|
|
5
5
|
*/
|
|
6
6
|
import { getToolRegistry } from '../registry.js';
|
|
7
|
+
import { hasCapability } from '../../../core/deployment.js';
|
|
7
8
|
// Core tools
|
|
8
9
|
import { execTool } from './exec.js';
|
|
9
10
|
import { webFetchTool } from './web-fetch.js';
|
|
@@ -233,12 +234,50 @@ const rawBuiltinTools = [
|
|
|
233
234
|
];
|
|
234
235
|
// Apply tier assignments to all tools
|
|
235
236
|
export const builtinTools = applyTiers(rawBuiltinTools);
|
|
237
|
+
/** Tool names that require specific deployment mode capabilities */
|
|
238
|
+
const BROWSER_TOOL_NAMES = new Set([
|
|
239
|
+
'browser_navigate', 'browser_snapshot', 'browser_click', 'browser_type',
|
|
240
|
+
'browser_search', 'browser_screenshot', 'browser_pages', 'browser_close',
|
|
241
|
+
]);
|
|
242
|
+
const CRON_TOOL_NAMES = new Set([
|
|
243
|
+
'cron_create', 'cron_list', 'cron_trigger', 'cron_pause',
|
|
244
|
+
'cron_archive', 'cron_delete', 'cron_history',
|
|
245
|
+
]);
|
|
246
|
+
const CHANNEL_TOOL_NAMES = new Set([
|
|
247
|
+
'discord_actions', 'slack_actions', 'telegram_actions',
|
|
248
|
+
]);
|
|
249
|
+
const INTEGRATION_TOOL_NAMES = new Set([
|
|
250
|
+
'create_ticket', 'list_tickets', 'update_ticket', 'get_ticket',
|
|
251
|
+
'create_project', 'list_projects',
|
|
252
|
+
]);
|
|
236
253
|
/**
|
|
237
|
-
* Register all built-in tools (with tier assignments)
|
|
254
|
+
* Register all built-in tools (with tier assignments and mode gating)
|
|
238
255
|
*/
|
|
239
256
|
export function registerBuiltinTools() {
|
|
240
257
|
const registry = getToolRegistry();
|
|
241
|
-
|
|
258
|
+
const modeFilteredTools = builtinTools.filter((tool) => {
|
|
259
|
+
// Browser tools: pro only (browser_tools capability)
|
|
260
|
+
if (BROWSER_TOOL_NAMES.has(tool.name))
|
|
261
|
+
return hasCapability('browser_tools');
|
|
262
|
+
// Cron tools: mini+ (cron capability)
|
|
263
|
+
if (CRON_TOOL_NAMES.has(tool.name))
|
|
264
|
+
return hasCapability('cron');
|
|
265
|
+
// Channel action tools: mini+ (chat_channels capability)
|
|
266
|
+
if (CHANNEL_TOOL_NAMES.has(tool.name))
|
|
267
|
+
return hasCapability('chat_channels');
|
|
268
|
+
// Integration tools: mini+ (integrations capability)
|
|
269
|
+
if (INTEGRATION_TOOL_NAMES.has(tool.name))
|
|
270
|
+
return hasCapability('integrations');
|
|
271
|
+
// Screen capture: pro only (sandbox_full capability)
|
|
272
|
+
if (tool.name === 'screen_capture')
|
|
273
|
+
return hasCapability('sandbox_full');
|
|
274
|
+
// Canvas render: pro only (browser_tools - needs headless browser)
|
|
275
|
+
if (tool.name === 'canvas_render')
|
|
276
|
+
return hasCapability('browser_tools');
|
|
277
|
+
// Everything else: always available
|
|
278
|
+
return true;
|
|
279
|
+
});
|
|
280
|
+
for (const tool of modeFilteredTools) {
|
|
242
281
|
registry.register(tool);
|
|
243
282
|
}
|
|
244
283
|
}
|
|
@@ -29,9 +29,9 @@ declare const SlackAccountConfigSchema: z.ZodObject<{
|
|
|
29
29
|
teamId?: string | undefined;
|
|
30
30
|
teamName?: string | undefined;
|
|
31
31
|
botToken?: string | undefined;
|
|
32
|
-
webhookUrl?: string | undefined;
|
|
33
32
|
appToken?: string | undefined;
|
|
34
33
|
signingSecret?: string | undefined;
|
|
34
|
+
webhookUrl?: string | undefined;
|
|
35
35
|
}, {
|
|
36
36
|
id: string;
|
|
37
37
|
provider: "slack";
|
|
@@ -42,9 +42,9 @@ declare const SlackAccountConfigSchema: z.ZodObject<{
|
|
|
42
42
|
teamId?: string | undefined;
|
|
43
43
|
teamName?: string | undefined;
|
|
44
44
|
botToken?: string | undefined;
|
|
45
|
-
webhookUrl?: string | undefined;
|
|
46
45
|
appToken?: string | undefined;
|
|
47
46
|
signingSecret?: string | undefined;
|
|
47
|
+
webhookUrl?: string | undefined;
|
|
48
48
|
}>;
|
|
49
49
|
export declare const slackProvider: ChatProvider<SlackAccountConfig>;
|
|
50
50
|
export { SlackAccountConfigSchema };
|
|
@@ -16,6 +16,13 @@ function formatCostPair(input, output) {
|
|
|
16
16
|
return chalk.dim('-');
|
|
17
17
|
return `$${input.toFixed(2)}/$${output.toFixed(2)}`;
|
|
18
18
|
}
|
|
19
|
+
/**
|
|
20
|
+
* Extract the provider type from a model ID (e.g. "anthropic/claude-3" -> "anthropic")
|
|
21
|
+
*/
|
|
22
|
+
function extractProvider(modelId) {
|
|
23
|
+
const slash = modelId.indexOf('/');
|
|
24
|
+
return slash > 0 ? modelId.slice(0, slash) : undefined;
|
|
25
|
+
}
|
|
19
26
|
export function modelsCommands() {
|
|
20
27
|
const cmd = new Command('models')
|
|
21
28
|
.description('Manage AI model configuration');
|
|
@@ -29,13 +36,13 @@ export function modelsCommands() {
|
|
|
29
36
|
const spin = spinner('Fetching models...').start();
|
|
30
37
|
try {
|
|
31
38
|
const params = options.provider ? `?provider=${encodeURIComponent(options.provider)}` : '';
|
|
32
|
-
const result = await api.get(`/api/
|
|
39
|
+
const result = await api.get(`/api/chat/models${params}`);
|
|
33
40
|
spin.stop();
|
|
34
41
|
if (!result.ok) {
|
|
35
42
|
error(result.error || 'Failed to fetch models');
|
|
36
43
|
process.exit(1);
|
|
37
44
|
}
|
|
38
|
-
const { models
|
|
45
|
+
const { models } = result.data;
|
|
39
46
|
if (options.json) {
|
|
40
47
|
console.log(JSON.stringify(result.data, null, 2));
|
|
41
48
|
return;
|
|
@@ -44,21 +51,17 @@ export function modelsCommands() {
|
|
|
44
51
|
info('No models available.');
|
|
45
52
|
return;
|
|
46
53
|
}
|
|
47
|
-
const table = createTable(['Model', 'Provider', 'Context', 'Cost (in/out)'
|
|
54
|
+
const table = createTable(['Model', 'Provider', 'Context', 'Cost (in/out)']);
|
|
48
55
|
for (const m of models) {
|
|
49
|
-
const isDefault = m.id === defaultModel || m.isDefault;
|
|
50
56
|
table.push([
|
|
51
|
-
|
|
57
|
+
truncate(m.id, 40),
|
|
52
58
|
m.provider,
|
|
53
59
|
formatContext(m.contextWindow),
|
|
54
60
|
formatCostPair(m.costPer1MInput, m.costPer1MOutput),
|
|
55
|
-
isDefault ? chalk.yellow('yes') : chalk.dim('no'),
|
|
56
61
|
]);
|
|
57
62
|
}
|
|
58
63
|
console.log(table.toString());
|
|
59
64
|
console.log(chalk.dim(`\n${models.length} model${models.length !== 1 ? 's' : ''}`));
|
|
60
|
-
if (defaultModel)
|
|
61
|
-
console.log(chalk.dim(`Default: ${defaultModel}`));
|
|
62
65
|
}
|
|
63
66
|
catch (err) {
|
|
64
67
|
spin.stop();
|
|
@@ -73,13 +76,17 @@ export function modelsCommands() {
|
|
|
73
76
|
.action(async (model, options) => {
|
|
74
77
|
const spin = spinner(`Fetching info for ${model}...`).start();
|
|
75
78
|
try {
|
|
76
|
-
const result = await api.get(
|
|
79
|
+
const result = await api.get('/api/chat/models');
|
|
77
80
|
spin.stop();
|
|
78
81
|
if (!result.ok) {
|
|
79
|
-
error(result.error ||
|
|
82
|
+
error(result.error || 'Failed to fetch models');
|
|
83
|
+
process.exit(1);
|
|
84
|
+
}
|
|
85
|
+
const m = result.data.models.find((entry) => entry.id === model || entry.id.endsWith(`/${model}`));
|
|
86
|
+
if (!m) {
|
|
87
|
+
error(`Model ${model} not found`);
|
|
80
88
|
process.exit(1);
|
|
81
89
|
}
|
|
82
|
-
const m = result.data;
|
|
83
90
|
if (options.json) {
|
|
84
91
|
console.log(JSON.stringify(m, null, 2));
|
|
85
92
|
return;
|
|
@@ -102,12 +109,18 @@ export function modelsCommands() {
|
|
|
102
109
|
});
|
|
103
110
|
cmd
|
|
104
111
|
.command('set-default <model>')
|
|
105
|
-
.description('Set the default model')
|
|
112
|
+
.description('Set the default model for a provider')
|
|
106
113
|
.option('--json', 'Output as JSON')
|
|
107
114
|
.action(async (model, options) => {
|
|
115
|
+
const provider = extractProvider(model);
|
|
116
|
+
if (!provider) {
|
|
117
|
+
error('Model must include provider prefix (e.g. anthropic/claude-sonnet-4-20250514)');
|
|
118
|
+
process.exit(1);
|
|
119
|
+
}
|
|
108
120
|
const spin = spinner(`Setting default model to ${model}...`).start();
|
|
109
121
|
try {
|
|
110
|
-
const
|
|
122
|
+
const modelName = model.slice(provider.length + 1);
|
|
123
|
+
const result = await api.post(`/api/chat/providers/${encodeURIComponent(provider)}/configure`, { defaultModel: modelName });
|
|
111
124
|
spin.stop();
|
|
112
125
|
if (!result.ok) {
|
|
113
126
|
error(result.error || 'Failed to set default model');
|
|
@@ -132,7 +145,7 @@ export function modelsCommands() {
|
|
|
132
145
|
.action(async (options) => {
|
|
133
146
|
const spin = spinner('Fetching aliases...').start();
|
|
134
147
|
try {
|
|
135
|
-
const result = await api.get('/api/
|
|
148
|
+
const result = await api.get('/api/chat/models');
|
|
136
149
|
spin.stop();
|
|
137
150
|
if (!result.ok) {
|
|
138
151
|
error(result.error || 'Failed to fetch aliases');
|
|
@@ -143,14 +156,13 @@ export function modelsCommands() {
|
|
|
143
156
|
console.log(JSON.stringify(aliases, null, 2));
|
|
144
157
|
return;
|
|
145
158
|
}
|
|
146
|
-
|
|
147
|
-
if (entries.length === 0) {
|
|
159
|
+
if (!aliases || aliases.length === 0) {
|
|
148
160
|
info('No model aliases configured.');
|
|
149
161
|
return;
|
|
150
162
|
}
|
|
151
|
-
const table = createTable(['Alias', '
|
|
152
|
-
for (const
|
|
153
|
-
table.push([chalk.cyan(alias),
|
|
163
|
+
const table = createTable(['Alias', 'Provider', 'Model']);
|
|
164
|
+
for (const entry of aliases) {
|
|
165
|
+
table.push([chalk.cyan(entry.alias), entry.provider, entry.model]);
|
|
154
166
|
}
|
|
155
167
|
console.log(table.toString());
|
|
156
168
|
}
|
|
@@ -162,15 +174,16 @@ export function modelsCommands() {
|
|
|
162
174
|
});
|
|
163
175
|
cmd
|
|
164
176
|
.command('test <model>')
|
|
165
|
-
.description('Test a model
|
|
177
|
+
.description('Test a model provider health check')
|
|
166
178
|
.option('--json', 'Output as JSON')
|
|
167
179
|
.action(async (model, options) => {
|
|
168
|
-
const
|
|
180
|
+
const provider = extractProvider(model) ?? model;
|
|
181
|
+
const spin = spinner(`Testing ${provider}...`).start();
|
|
169
182
|
try {
|
|
170
|
-
const result = await api.post(`/api/providers
|
|
183
|
+
const result = await api.post(`/api/chat/providers/${encodeURIComponent(provider)}/health`);
|
|
171
184
|
spin.stop();
|
|
172
185
|
if (!result.ok) {
|
|
173
|
-
error(result.error || `Failed to test ${
|
|
186
|
+
error(result.error || `Failed to test ${provider}`);
|
|
174
187
|
process.exit(1);
|
|
175
188
|
}
|
|
176
189
|
const data = result.data;
|
|
@@ -178,12 +191,12 @@ export function modelsCommands() {
|
|
|
178
191
|
console.log(JSON.stringify(data, null, 2));
|
|
179
192
|
return;
|
|
180
193
|
}
|
|
181
|
-
if (data.
|
|
194
|
+
if (data.healthy) {
|
|
182
195
|
const latency = data.latencyMs != null ? chalk.dim(` (${data.latencyMs}ms)`) : '';
|
|
183
|
-
success(`${chalk.cyan(
|
|
196
|
+
success(`${chalk.cyan(provider)} is healthy${latency}`);
|
|
184
197
|
}
|
|
185
198
|
else {
|
|
186
|
-
error(`${chalk.cyan(
|
|
199
|
+
error(`${chalk.cyan(provider)} health check failed: ${data.message || 'Unknown error'}`);
|
|
187
200
|
}
|
|
188
201
|
}
|
|
189
202
|
catch (err) {
|