palmier 0.6.0 → 0.6.2
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/.github/workflows/publish.yml +15 -2
- package/CLAUDE.md +2 -2
- package/DISCLAIMER.md +36 -0
- package/README.md +76 -87
- package/dist/agents/agent-instructions.md +1 -1
- package/dist/agents/agent.d.ts +2 -0
- package/dist/agents/agent.js +21 -0
- package/dist/agents/aider.d.ts +9 -0
- package/dist/agents/aider.js +32 -0
- package/dist/agents/cursor.d.ts +9 -0
- package/dist/agents/cursor.js +35 -0
- package/dist/agents/deepagents.d.ts +9 -0
- package/dist/agents/deepagents.js +35 -0
- package/dist/agents/droid.d.ts +9 -0
- package/dist/agents/droid.js +32 -0
- package/dist/agents/goose.d.ts +9 -0
- package/dist/agents/goose.js +32 -0
- package/dist/agents/opencode.d.ts +9 -0
- package/dist/agents/opencode.js +35 -0
- package/dist/agents/openhands.d.ts +9 -0
- package/dist/agents/openhands.js +35 -0
- package/dist/commands/pair.d.ts +1 -1
- package/dist/commands/pair.js +1 -1
- package/dist/commands/run.js +2 -2
- package/dist/pwa/apple-touch-icon.png +0 -0
- package/dist/pwa/assets/index-ByhOhTz1.js +118 -0
- package/dist/pwa/assets/index-_AmC1Rkn.css +1 -0
- package/dist/pwa/assets/plus-jakarta-sans-latin-ext-wght-normal-DmpS2jIq.woff2 +0 -0
- package/dist/pwa/assets/plus-jakarta-sans-latin-wght-normal-eXO_dkmS.woff2 +0 -0
- package/dist/pwa/assets/plus-jakarta-sans-vietnamese-wght-normal-qRpaaN48.woff2 +0 -0
- package/dist/pwa/favicon.ico +0 -0
- package/dist/pwa/index.html +17 -0
- package/dist/pwa/manifest.webmanifest +1 -0
- package/dist/pwa/pwa-192x192.png +0 -0
- package/dist/pwa/pwa-512x512.png +0 -0
- package/dist/pwa/registerSW.js +1 -0
- package/dist/pwa/service-worker.js +2 -0
- package/dist/rpc-handler.d.ts +4 -0
- package/dist/rpc-handler.js +5 -4
- package/dist/transports/http-transport.js +29 -41
- package/package.json +2 -2
- package/palmier-server/.github/workflows/ci.yml +21 -0
- package/palmier-server/.github/workflows/deploy.yml +38 -0
- package/palmier-server/CLAUDE.md +13 -0
- package/palmier-server/PRODUCTION.md +355 -0
- package/palmier-server/README.md +187 -0
- package/palmier-server/nats.conf +15 -0
- package/palmier-server/package.json +8 -0
- package/palmier-server/pnpm-lock.yaml +6597 -0
- package/palmier-server/pnpm-workspace.yaml +3 -0
- package/palmier-server/pwa/index.html +16 -0
- package/palmier-server/pwa/logo/logo-prompt.md +28 -0
- package/palmier-server/pwa/logo/logo_20260330.png +0 -0
- package/palmier-server/pwa/package.json +30 -0
- package/palmier-server/pwa/public/apple-touch-icon.png +0 -0
- package/palmier-server/pwa/public/favicon.ico +0 -0
- package/palmier-server/pwa/public/pwa-192x192.png +0 -0
- package/palmier-server/pwa/public/pwa-512x512.png +0 -0
- package/palmier-server/pwa/src/App.css +2387 -0
- package/palmier-server/pwa/src/App.tsx +21 -0
- package/palmier-server/pwa/src/agentLabels.ts +11 -0
- package/palmier-server/pwa/src/api.ts +61 -0
- package/palmier-server/pwa/src/components/HostMenu.tsx +289 -0
- package/palmier-server/pwa/src/components/PlanDialog.tsx +41 -0
- package/palmier-server/pwa/src/components/RunDetailView.tsx +293 -0
- package/palmier-server/pwa/src/components/RunsView.tsx +254 -0
- package/palmier-server/pwa/src/components/TabBar.tsx +31 -0
- package/palmier-server/pwa/src/components/TaskCard.tsx +213 -0
- package/palmier-server/pwa/src/components/TaskForm.tsx +580 -0
- package/palmier-server/pwa/src/components/TaskListView.tsx +415 -0
- package/palmier-server/pwa/src/constants.ts +2 -0
- package/palmier-server/pwa/src/contexts/HostConnectionContext.tsx +313 -0
- package/palmier-server/pwa/src/contexts/HostStoreContext.tsx +135 -0
- package/palmier-server/pwa/src/formatTime.ts +10 -0
- package/palmier-server/pwa/src/hooks/useBackClose.ts +75 -0
- package/palmier-server/pwa/src/hooks/useMediaQuery.ts +17 -0
- package/palmier-server/pwa/src/hooks/usePushSubscription.ts +75 -0
- package/palmier-server/pwa/src/main.tsx +14 -0
- package/palmier-server/pwa/src/pages/Dashboard.tsx +223 -0
- package/palmier-server/pwa/src/pages/PairHost.tsx +178 -0
- package/palmier-server/pwa/src/service-worker.ts +139 -0
- package/palmier-server/pwa/src/types.ts +79 -0
- package/palmier-server/pwa/src/vite-env.d.ts +11 -0
- package/palmier-server/pwa/tsconfig.json +21 -0
- package/palmier-server/pwa/tsconfig.node.json +19 -0
- package/palmier-server/pwa/vite.config.ts +47 -0
- package/palmier-server/server/.env.example +16 -0
- package/palmier-server/server/package.json +33 -0
- package/palmier-server/server/src/db.ts +34 -0
- package/palmier-server/server/src/index.ts +219 -0
- package/palmier-server/server/src/nats.ts +25 -0
- package/palmier-server/server/src/push.ts +68 -0
- package/palmier-server/server/src/routes/hosts.ts +45 -0
- package/palmier-server/server/src/routes/push.ts +100 -0
- package/palmier-server/server/tsconfig.json +20 -0
- package/palmier-server/spec.md +415 -0
- package/src/agents/agent-instructions.md +1 -1
- package/src/agents/agent.ts +23 -0
- package/src/agents/aider.ts +37 -0
- package/src/agents/cursor.ts +38 -0
- package/src/agents/deepagents.ts +38 -0
- package/src/agents/droid.ts +37 -0
- package/src/agents/goose.ts +35 -0
- package/src/agents/opencode.ts +38 -0
- package/src/agents/openhands.ts +38 -0
- package/src/commands/pair.ts +1 -1
- package/src/commands/run.ts +2 -2
- package/src/rpc-handler.ts +5 -4
- package/src/transports/http-transport.ts +31 -43
- package/test/result-state.test.ts +110 -0
|
@@ -12,13 +12,26 @@ jobs:
|
|
|
12
12
|
id-token: write
|
|
13
13
|
steps:
|
|
14
14
|
- uses: actions/checkout@v6
|
|
15
|
+
- uses: actions/checkout@v6
|
|
16
|
+
with:
|
|
17
|
+
repository: caihongxu/palmier-server
|
|
18
|
+
token: ${{ secrets.SERVER_REPO_TOKEN }}
|
|
19
|
+
path: palmier-server
|
|
15
20
|
- uses: actions/setup-node@v6
|
|
16
21
|
with:
|
|
17
22
|
node-version: 24
|
|
18
23
|
cache: npm
|
|
19
24
|
registry-url: https://registry.npmjs.org
|
|
20
|
-
- run: npm ci
|
|
21
|
-
-
|
|
25
|
+
- run: npm ci --ignore-scripts
|
|
26
|
+
- uses: pnpm/action-setup@v4
|
|
27
|
+
with:
|
|
28
|
+
version: latest
|
|
29
|
+
- name: Build PWA
|
|
30
|
+
run: cd palmier-server && pnpm install --frozen-lockfile && cd pwa && pnpm build
|
|
31
|
+
- name: Build host
|
|
32
|
+
run: npm run build
|
|
33
|
+
env:
|
|
34
|
+
PALMIER_PWA_DIST: palmier-server/pwa/dist
|
|
22
35
|
- run: npm publish --provenance --access public
|
|
23
36
|
env:
|
|
24
37
|
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
package/CLAUDE.md
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
## Getting Started
|
|
4
4
|
|
|
5
|
-
Always read `README.md` first before starting any task.
|
|
5
|
+
Always read `README.md` first before starting any task.
|
|
6
6
|
|
|
7
7
|
## Documentation
|
|
8
8
|
|
|
9
|
-
When making architectural changes, update `README.md`
|
|
9
|
+
When making architectural changes, update `README.md` to reflect the new state.
|
package/DISCLAIMER.md
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# Disclaimer
|
|
2
|
+
|
|
3
|
+
**USE AT YOUR OWN RISK.** Palmier is provided on an "AS IS" and "AS AVAILABLE" basis, without warranties of any kind, either express or implied.
|
|
4
|
+
|
|
5
|
+
## AI Agent Execution
|
|
6
|
+
|
|
7
|
+
Palmier spawns third-party AI agent CLIs (such as Claude Code, Gemini CLI, Codex CLI, GitHub Copilot, and others) that can:
|
|
8
|
+
|
|
9
|
+
- **Read, create, modify, and delete files** on your machine
|
|
10
|
+
- **Execute arbitrary shell commands** with your user permissions
|
|
11
|
+
- **Make network requests** and interact with external services
|
|
12
|
+
|
|
13
|
+
AI agents may produce unexpected, incorrect, or harmful outputs. **You are solely responsible for reviewing and approving all actions taken by AI agents on your system.** The authors of Palmier have no control over the behavior of third-party AI agents and accept no liability for their actions.
|
|
14
|
+
|
|
15
|
+
## Unattended and Scheduled Execution
|
|
16
|
+
|
|
17
|
+
Tasks can be configured to run on schedules (cron) or in response to events without active supervision. You should:
|
|
18
|
+
|
|
19
|
+
- Use the **confirmation** feature for sensitive tasks
|
|
20
|
+
- Restrict **permissions** granted to agents to the minimum necessary
|
|
21
|
+
- Regularly review **task history and results**
|
|
22
|
+
- Maintain **backups** of any important data in directories where agents operate
|
|
23
|
+
|
|
24
|
+
## Third-Party Services
|
|
25
|
+
|
|
26
|
+
Task prompts and execution data may be transmitted to third-party AI service providers (Anthropic, Google, OpenAI, etc.) according to their respective terms and privacy policies. Palmier does not install and has no control over how these services process your data.
|
|
27
|
+
|
|
28
|
+
When using server mode, communication between your device and the host is relayed through the Palmier server. See the [Privacy Policy](https://www.palmier.me/privacy) for details on what data is collected.
|
|
29
|
+
|
|
30
|
+
## Limitation of Liability
|
|
31
|
+
|
|
32
|
+
To the maximum extent permitted by applicable law, the authors and contributors of Palmier shall not be liable for any direct, indirect, incidental, special, consequential, or exemplary damages arising from the use of this software, including but not limited to damages for loss of data, loss of profits, business interruption, or any other commercial damages or losses.
|
|
33
|
+
|
|
34
|
+
## No Professional Advice
|
|
35
|
+
|
|
36
|
+
Palmier is a developer tool, not a substitute for professional advice. Do not rely on AI-generated outputs for critical decisions without independent verification.
|
package/README.md
CHANGED
|
@@ -6,72 +6,87 @@
|
|
|
6
6
|
|
|
7
7
|
**Website:** [palmier.me](https://www.palmier.me) | **App:** [app.palmier.me](https://app.palmier.me)
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
You have AI agents on your machine. But you have to sit at your desk to use them. Palmier lets you dispatch, schedule, and monitor them from any device, anywhere.
|
|
10
10
|
|
|
11
|
+
It runs on your machine as a background daemon and connects to a mobile-friendly PWA, so you can create tasks, approve permissions, and check results without being at your computer.
|
|
11
12
|
> **Important:** By using Palmier, you agree to the [Terms of Service](https://www.palmier.me/terms) and [Privacy Policy](https://www.palmier.me/privacy). See the [Disclaimer](#disclaimer) section below.
|
|
12
13
|
|
|
13
|
-
##
|
|
14
|
+
## Quick Start
|
|
14
15
|
|
|
15
|
-
|
|
16
|
+
1. Install a supported agent CLI — [Claude Code](https://docs.anthropic.com/en/docs/claude-code), [Gemini CLI](https://github.com/google-gemini/gemini-cli), [Codex CLI](https://github.com/openai/codex), [GitHub Copilot](https://github.com/github/gh-copilot), [OpenClaw](https://openclaw.ai/), or [others](https://www.palmier.me/agents).
|
|
17
|
+
2. Install Palmier:
|
|
18
|
+
```bash
|
|
19
|
+
npm install -g palmier
|
|
20
|
+
```
|
|
21
|
+
3. Run the setup wizard from your Palmier root directory (e.g., `~/palmier`):
|
|
22
|
+
```bash
|
|
23
|
+
palmier init
|
|
24
|
+
```
|
|
25
|
+
This detects your agents, configures access, installs the background daemon, and starts pairing.
|
|
26
|
+
4. Open `http://localhost:<port>` to access the app locally — no pairing needed.
|
|
27
|
+
5. To access from other devices, enter the pairing code shown after init into the [PWA](https://app.palmier.me).
|
|
16
28
|
|
|
17
|
-
|
|
18
|
-
|------|-----------|-----|---------|----------|
|
|
19
|
-
| **Local** | HTTP (localhost) | `http://localhost:<port>` | Not required | Full access from the host machine, no internet needed |
|
|
20
|
-
| **LAN** | HTTP (direct) | `http://<host-ip>:<port>` | Required | Access from other devices on the local network |
|
|
21
|
-
| **Server** | Cloud relay (NATS) | `https://app.palmier.me` | Required | Push notifications, remote access from anywhere |
|
|
29
|
+
### Prerequisites
|
|
22
30
|
|
|
23
|
-
|
|
31
|
+
- **Node.js 24+**
|
|
32
|
+
- **Linux with systemd** or **Windows 10/11** (macOS coming soon)
|
|
33
|
+
- At least one supported agent CLI
|
|
24
34
|
|
|
25
|
-
|
|
35
|
+
## How It Works
|
|
26
36
|
|
|
27
|
-
|
|
37
|
+
Palmier runs as a background daemon (systemd on Linux, Task Scheduler on Windows). It invokes your agent CLIs directly, schedules tasks via native OS timers, and exposes an API that the PWA connects to — either directly over HTTP or remotely through a relay server.
|
|
28
38
|
|
|
29
|
-
|
|
39
|
+
```
|
|
40
|
+
┌──────────────┐ HTTP ┌──────────────────┐
|
|
41
|
+
│ │◄──────────────────────│ │
|
|
42
|
+
│ Host Daemon │ │ PWA (Browser) │
|
|
43
|
+
│ │◄──────┐ │ │
|
|
44
|
+
└──────┬───────┘ │ └──────────────────┘
|
|
45
|
+
│ │ │
|
|
46
|
+
▼ │ NATS (TLS) │ NATS (TLS)
|
|
47
|
+
┌──────────────┐ │ ┌────────┴─────────┐
|
|
48
|
+
│ Agent CLIs │ └───────────────│ Relay Server │
|
|
49
|
+
│ (Claude, │ │ (passthrough, │
|
|
50
|
+
│ Gemini, │ │ push notify) │
|
|
51
|
+
│ Codex ...) │ └──────────────────┘
|
|
52
|
+
└──────────────┘
|
|
53
|
+
Local / LAN: direct HTTP
|
|
54
|
+
Server mode: via relay server
|
|
55
|
+
```
|
|
30
56
|
|
|
31
|
-
|
|
32
|
-
- An agent CLI tool for task execution (e.g., Claude Code, Gemini CLI, OpenAI Codex, GitHub Copilot)
|
|
33
|
-
- **Linux with systemd** or **Windows 10/11**
|
|
57
|
+
## Access Modes
|
|
34
58
|
|
|
35
|
-
|
|
59
|
+
Local always works. Enable LAN and/or Server mode during `palmier init`.
|
|
36
60
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
61
|
+
| Mode | Transport | URL | Pairing | Features |
|
|
62
|
+
|------|-----------|-----|---------|----------|
|
|
63
|
+
| **Local** | HTTP (localhost) | `http://localhost:<port>` | Not required | Full access from the host machine, no internet needed |
|
|
64
|
+
| **LAN** | HTTP (direct) | `http://<host-ip>:<port>` | Required | Access from other devices on the local network |
|
|
65
|
+
| **Server** | Cloud relay (NATS) | [https://app.palmier.me](https://app.palmier.me) | Required | Push notifications, remote access from anywhere |
|
|
40
66
|
|
|
41
|
-
|
|
67
|
+
**LAN mode** binds the daemon to `0.0.0.0` so the PWA is accessible from other devices on your network. Devices must pair with a pairing code.
|
|
42
68
|
|
|
43
|
-
|
|
69
|
+
**Server mode** relays communication through the Palmier cloud server (via [NATS](https://nats.io)). All features including push notifications are available. Server mode and LAN mode can be active at the same time.
|
|
44
70
|
|
|
45
|
-
|
|
46
|
-
|---|---|
|
|
47
|
-
| `palmier init` | Interactive setup wizard |
|
|
48
|
-
| `palmier pair` | Generate an OTP code to pair a new device |
|
|
49
|
-
| `palmier clients list` | List active client tokens |
|
|
50
|
-
| `palmier clients revoke <token>` | Revoke a specific client token |
|
|
51
|
-
| `palmier clients revoke-all` | Revoke all client tokens |
|
|
52
|
-
| `palmier info` | Show host connection info (address, mode) |
|
|
53
|
-
| `palmier serve` | Run the persistent RPC handler (default command) |
|
|
54
|
-
| `palmier restart` | Restart the palmier serve daemon |
|
|
55
|
-
| `palmier run <task-id>` | Execute a specific task |
|
|
56
|
-
| `palmier uninstall` | Stop daemon and remove all scheduled tasks |
|
|
71
|
+
## Security & Privacy
|
|
57
72
|
|
|
58
|
-
|
|
73
|
+
**Local mode** — all traffic stays on `127.0.0.1`. No data leaves your machine.
|
|
59
74
|
|
|
60
|
-
|
|
75
|
+
**LAN mode** — traffic stays on your local network. Devices must pair with a one-time pairing code before they can access the host. Unpaired requests are rejected.
|
|
61
76
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
77
|
+
**Server mode** — communication between your device and host is relayed through the Palmier cloud server over TLS-encrypted NATS connections. The server acts as a passthrough relay only — it does not store, log, or inspect any user data, task content, or agent output. The only data the server persists is a host registration ID used for message routing and Web Push subscription info for delivering notifications. See the [Privacy Policy](https://www.palmier.me/privacy) for full details.
|
|
78
|
+
|
|
79
|
+
In all modes, client tokens are generated and validated entirely on your host. The Palmier server never sees or stores them.
|
|
80
|
+
|
|
81
|
+
## Setup Details
|
|
67
82
|
|
|
68
|
-
### Pairing
|
|
83
|
+
### Pairing Devices
|
|
69
84
|
|
|
70
85
|
Local access (`http://localhost:<port>`) works immediately — no pairing needed.
|
|
71
86
|
|
|
72
|
-
For LAN or server mode, run `palmier pair` on the host to generate
|
|
87
|
+
For LAN or server mode, run `palmier pair` on the host to generate a pairing code. Enter it in the PWA — either at `http://<host-ip>:<port>` (LAN mode) or [https://app.palmier.me](https://app.palmier.me) (server mode).
|
|
73
88
|
|
|
74
|
-
### Managing
|
|
89
|
+
### Managing Clients
|
|
75
90
|
|
|
76
91
|
```bash
|
|
77
92
|
# List all paired devices
|
|
@@ -84,8 +99,10 @@ palmier clients revoke <token>
|
|
|
84
99
|
palmier clients revoke-all
|
|
85
100
|
```
|
|
86
101
|
|
|
87
|
-
The `init`
|
|
88
|
-
|
|
102
|
+
### The `init` Command
|
|
103
|
+
|
|
104
|
+
The wizard:
|
|
105
|
+
- Detects installed agent CLIs and caches the result
|
|
89
106
|
- Configures access modes (HTTP port, LAN access)
|
|
90
107
|
- Shows a summary (including any existing scheduled tasks to recover) and asks for confirmation
|
|
91
108
|
- Registers with the Palmier server, saves configuration to `~/.config/palmier/host.json`
|
|
@@ -126,15 +143,20 @@ Get-Process -Name node -ErrorAction SilentlyContinue | Where-Object { $_.Command
|
|
|
126
143
|
palmier restart
|
|
127
144
|
```
|
|
128
145
|
|
|
129
|
-
##
|
|
146
|
+
## CLI Reference
|
|
130
147
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
148
|
+
| Command | Description |
|
|
149
|
+
|---|---|
|
|
150
|
+
| `palmier init` | Interactive setup wizard |
|
|
151
|
+
| `palmier pair` | Generate a pairing code to pair a new device |
|
|
152
|
+
| `palmier clients list` | List active client tokens |
|
|
153
|
+
| `palmier clients revoke <token>` | Revoke a specific client token |
|
|
154
|
+
| `palmier clients revoke-all` | Revoke all client tokens |
|
|
155
|
+
| `palmier info` | Show host connection info (address, mode) |
|
|
156
|
+
| `palmier serve` | Run the persistent RPC handler (default command) |
|
|
157
|
+
| `palmier restart` | Restart the palmier serve daemon |
|
|
158
|
+
| `palmier run <task-id>` | Execute a specific task |
|
|
159
|
+
| `palmier uninstall` | Stop daemon and remove all scheduled tasks |
|
|
138
160
|
|
|
139
161
|
## Uninstalling
|
|
140
162
|
|
|
@@ -170,40 +192,7 @@ To fully remove Palmier from a machine:
|
|
|
170
192
|
|
|
171
193
|
## Disclaimer
|
|
172
194
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
### AI Agent Execution
|
|
176
|
-
|
|
177
|
-
Palmier spawns third-party AI agent CLIs (such as Claude Code, Gemini CLI, and Codex CLI) that can:
|
|
178
|
-
|
|
179
|
-
- **Read, create, modify, and delete files** on your machine
|
|
180
|
-
- **Execute arbitrary shell commands** with your user permissions
|
|
181
|
-
- **Make network requests** and interact with external services
|
|
182
|
-
|
|
183
|
-
AI agents may produce unexpected, incorrect, or harmful outputs. **You are solely responsible for reviewing and approving all actions taken by AI agents on your system.** The authors of Palmier have no control over the behavior of third-party AI agents and accept no liability for their actions.
|
|
184
|
-
|
|
185
|
-
### Unattended and Scheduled Execution
|
|
186
|
-
|
|
187
|
-
Tasks can be configured to run on schedules (cron) or in response to events without active supervision. You should:
|
|
188
|
-
|
|
189
|
-
- Use the **confirmation** feature for sensitive tasks
|
|
190
|
-
- Restrict **permissions** granted to agents to the minimum necessary
|
|
191
|
-
- Regularly review **task history and results**
|
|
192
|
-
- Maintain **backups** of any important data in directories where agents operate
|
|
193
|
-
|
|
194
|
-
### Third-Party Services
|
|
195
|
-
|
|
196
|
-
Task prompts and execution data may be transmitted to third-party AI service providers (Anthropic, Google, OpenAI, etc.) according to their respective terms and privacy policies. Palmier does not control how these services process your data.
|
|
197
|
-
|
|
198
|
-
When using server mode, communication between your device and the host is relayed through the Palmier server. See the [Privacy Policy](https://www.palmier.me/privacy) for details on what data is collected.
|
|
199
|
-
|
|
200
|
-
### Limitation of Liability
|
|
201
|
-
|
|
202
|
-
To the maximum extent permitted by applicable law, the authors and contributors of Palmier shall not be liable for any direct, indirect, incidental, special, consequential, or exemplary damages arising from the use of this software, including but not limited to damages for loss of data, loss of profits, business interruption, or any other commercial damages or losses.
|
|
203
|
-
|
|
204
|
-
### No Professional Advice
|
|
205
|
-
|
|
206
|
-
Palmier is a developer tool, not a substitute for professional advice. Do not rely on AI-generated outputs for critical decisions without independent verification.
|
|
195
|
+
Palmier spawns AI agents that can read, write, and execute on your machine. [Read the full disclaimer](DISCLAIMER.md) before use.
|
|
207
196
|
|
|
208
197
|
## License
|
|
209
198
|
|
|
@@ -28,7 +28,7 @@ The request blocks until the user responds. Response: `{"values":["answer1","ans
|
|
|
28
28
|
|
|
29
29
|
**Sending push notifications** — To notify the user, POST to `/notify` with:
|
|
30
30
|
```json
|
|
31
|
-
{"title":"...","body":"..."}
|
|
31
|
+
{"taskId":"{{TASK_ID}}","title":"...","body":"..."}
|
|
32
32
|
```
|
|
33
33
|
|
|
34
34
|
---
|
package/dist/agents/agent.d.ts
CHANGED
|
@@ -4,6 +4,8 @@ export interface CommandLine {
|
|
|
4
4
|
args: string[];
|
|
5
5
|
/** If provided, the string is written to the process's stdin and then the pipe is closed. */
|
|
6
6
|
stdin?: string;
|
|
7
|
+
/** Additional environment variables to set for the spawned process. */
|
|
8
|
+
env?: Record<string, string>;
|
|
7
9
|
}
|
|
8
10
|
/**
|
|
9
11
|
* Interface that each agent tool must implement.
|
package/dist/agents/agent.js
CHANGED
|
@@ -1,10 +1,17 @@
|
|
|
1
1
|
import { ClaudeAgent } from "./claude.js";
|
|
2
2
|
import { GeminiAgent } from "./gemini.js";
|
|
3
3
|
import { CodexAgent } from "./codex.js";
|
|
4
|
+
import { DroidAgent } from "./droid.js";
|
|
4
5
|
import { OpenClawAgent } from "./openclaw.js";
|
|
5
6
|
import { CopilotAgent } from "./copilot.js";
|
|
6
7
|
import { QwenAgent } from "./qwen.js";
|
|
7
8
|
import { KimiAgent } from "./kimi.js";
|
|
9
|
+
import { GooseAgent } from "./goose.js";
|
|
10
|
+
import { OpenCodeAgent } from "./opencode.js";
|
|
11
|
+
import { DeepAgents } from "./deepagents.js";
|
|
12
|
+
import { Aider } from "./aider.js";
|
|
13
|
+
import { OpenHands } from "./openhands.js";
|
|
14
|
+
import { Cursor } from "./cursor.js";
|
|
8
15
|
const agentRegistry = {
|
|
9
16
|
claude: new ClaudeAgent(),
|
|
10
17
|
gemini: new GeminiAgent(),
|
|
@@ -13,15 +20,29 @@ const agentRegistry = {
|
|
|
13
20
|
copilot: new CopilotAgent(),
|
|
14
21
|
qwen: new QwenAgent(),
|
|
15
22
|
kimi: new KimiAgent(),
|
|
23
|
+
droid: new DroidAgent(),
|
|
24
|
+
goose: new GooseAgent(),
|
|
25
|
+
opencode: new OpenCodeAgent(),
|
|
26
|
+
deepagents: new DeepAgents(),
|
|
27
|
+
aider: new Aider(),
|
|
28
|
+
openhands: new OpenHands(),
|
|
29
|
+
cursor: new Cursor(),
|
|
16
30
|
};
|
|
17
31
|
const agentLabels = {
|
|
18
32
|
claude: "Claude Code",
|
|
19
33
|
gemini: "Gemini CLI",
|
|
20
34
|
codex: "Codex CLI",
|
|
35
|
+
droid: "Droid CLI",
|
|
21
36
|
openclaw: "OpenClaw",
|
|
22
37
|
copilot: "Copilot CLI",
|
|
23
38
|
qwen: "Qwen Code",
|
|
24
39
|
kimi: "Kimi Code",
|
|
40
|
+
goose: "Goose CLI",
|
|
41
|
+
opencode: "OpenCode",
|
|
42
|
+
deepagents: "Deep Agents CLI",
|
|
43
|
+
aider: "Aider",
|
|
44
|
+
openhands: "OpenHands",
|
|
45
|
+
cursor: "Cursor CLI",
|
|
25
46
|
};
|
|
26
47
|
export async function detectAgents() {
|
|
27
48
|
const detected = [];
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { ParsedTask, RequiredPermission } from "../types.js";
|
|
2
|
+
import type { AgentTool, CommandLine } from "./agent.js";
|
|
3
|
+
export declare class Aider implements AgentTool {
|
|
4
|
+
supportsPermissions: boolean;
|
|
5
|
+
getPlanGenerationCommandLine(prompt: string): CommandLine;
|
|
6
|
+
getTaskRunCommandLine(task: ParsedTask, followupPrompt?: string, extraPermissions?: RequiredPermission[] | "yolo"): CommandLine;
|
|
7
|
+
init(): Promise<boolean>;
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=aider.d.ts.map
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { execSync } from "child_process";
|
|
2
|
+
import { getAgentInstructions } from "./shared-prompt.js";
|
|
3
|
+
import { SHELL } from "../platform/index.js";
|
|
4
|
+
export class Aider {
|
|
5
|
+
supportsPermissions = false;
|
|
6
|
+
getPlanGenerationCommandLine(prompt) {
|
|
7
|
+
return {
|
|
8
|
+
command: "aider",
|
|
9
|
+
args: ["--message", prompt],
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
getTaskRunCommandLine(task, followupPrompt, extraPermissions) {
|
|
13
|
+
const yolo = extraPermissions === "yolo";
|
|
14
|
+
const prompt = followupPrompt ?? (getAgentInstructions(task.frontmatter.id, yolo || !this.supportsPermissions) + "\n\n" + (task.body || task.frontmatter.user_prompt));
|
|
15
|
+
const args = [];
|
|
16
|
+
if (yolo) {
|
|
17
|
+
args.push("--yes-always");
|
|
18
|
+
}
|
|
19
|
+
args.push("--message", prompt);
|
|
20
|
+
return { command: "aider", args };
|
|
21
|
+
}
|
|
22
|
+
async init() {
|
|
23
|
+
try {
|
|
24
|
+
execSync("aider --version", { stdio: "ignore", shell: SHELL });
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
return true;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=aider.js.map
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { ParsedTask, RequiredPermission } from "../types.js";
|
|
2
|
+
import type { AgentTool, CommandLine } from "./agent.js";
|
|
3
|
+
export declare class Cursor implements AgentTool {
|
|
4
|
+
supportsPermissions: boolean;
|
|
5
|
+
getPlanGenerationCommandLine(prompt: string): CommandLine;
|
|
6
|
+
getTaskRunCommandLine(task: ParsedTask, followupPrompt?: string, extraPermissions?: RequiredPermission[] | "yolo"): CommandLine;
|
|
7
|
+
init(): Promise<boolean>;
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=cursor.d.ts.map
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { execSync } from "child_process";
|
|
2
|
+
import { getAgentInstructions } from "./shared-prompt.js";
|
|
3
|
+
import { SHELL } from "../platform/index.js";
|
|
4
|
+
export class Cursor {
|
|
5
|
+
supportsPermissions = false;
|
|
6
|
+
getPlanGenerationCommandLine(prompt) {
|
|
7
|
+
return {
|
|
8
|
+
command: "cursor",
|
|
9
|
+
args: ["-p", prompt],
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
getTaskRunCommandLine(task, followupPrompt, extraPermissions) {
|
|
13
|
+
const yolo = extraPermissions === "yolo";
|
|
14
|
+
const prompt = followupPrompt ?? (getAgentInstructions(task.frontmatter.id, yolo || !this.supportsPermissions) + "\n\n" + (task.body || task.frontmatter.user_prompt));
|
|
15
|
+
const args = [];
|
|
16
|
+
if (yolo) {
|
|
17
|
+
args.push("--force");
|
|
18
|
+
}
|
|
19
|
+
if (followupPrompt) {
|
|
20
|
+
args.push("--continue");
|
|
21
|
+
} // continue mode for followups
|
|
22
|
+
args.push("-p", prompt);
|
|
23
|
+
return { command: "cursor", args };
|
|
24
|
+
}
|
|
25
|
+
async init() {
|
|
26
|
+
try {
|
|
27
|
+
execSync("cursor --version", { stdio: "ignore", shell: SHELL });
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
return true;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=cursor.js.map
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { ParsedTask, RequiredPermission } from "../types.js";
|
|
2
|
+
import type { AgentTool, CommandLine } from "./agent.js";
|
|
3
|
+
export declare class DeepAgents implements AgentTool {
|
|
4
|
+
supportsPermissions: boolean;
|
|
5
|
+
getPlanGenerationCommandLine(prompt: string): CommandLine;
|
|
6
|
+
getTaskRunCommandLine(task: ParsedTask, followupPrompt?: string, extraPermissions?: RequiredPermission[] | "yolo"): CommandLine;
|
|
7
|
+
init(): Promise<boolean>;
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=deepagents.d.ts.map
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { execSync } from "child_process";
|
|
2
|
+
import { getAgentInstructions } from "./shared-prompt.js";
|
|
3
|
+
import { SHELL } from "../platform/index.js";
|
|
4
|
+
export class DeepAgents {
|
|
5
|
+
supportsPermissions = false;
|
|
6
|
+
getPlanGenerationCommandLine(prompt) {
|
|
7
|
+
return {
|
|
8
|
+
command: "deepagents",
|
|
9
|
+
args: ["--non-interactive", prompt],
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
getTaskRunCommandLine(task, followupPrompt, extraPermissions) {
|
|
13
|
+
const yolo = extraPermissions === "yolo";
|
|
14
|
+
const prompt = followupPrompt ?? (getAgentInstructions(task.frontmatter.id, yolo || !this.supportsPermissions) + "\n\n" + (task.body || task.frontmatter.user_prompt));
|
|
15
|
+
const args = [];
|
|
16
|
+
if (yolo) {
|
|
17
|
+
args.push("--auto-approve");
|
|
18
|
+
}
|
|
19
|
+
if (followupPrompt) {
|
|
20
|
+
args.push("--resume");
|
|
21
|
+
} // continue mode for followups
|
|
22
|
+
args.push("--non-interactive", prompt);
|
|
23
|
+
return { command: "deepagents", args };
|
|
24
|
+
}
|
|
25
|
+
async init() {
|
|
26
|
+
try {
|
|
27
|
+
execSync("deepagents --version", { stdio: "ignore", shell: SHELL });
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
return true;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=deepagents.js.map
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { ParsedTask, RequiredPermission } from "../types.js";
|
|
2
|
+
import type { AgentTool, CommandLine } from "./agent.js";
|
|
3
|
+
export declare class DroidAgent implements AgentTool {
|
|
4
|
+
supportsPermissions: boolean;
|
|
5
|
+
getPlanGenerationCommandLine(prompt: string): CommandLine;
|
|
6
|
+
getTaskRunCommandLine(task: ParsedTask, followupPrompt?: string, extraPermissions?: RequiredPermission[] | "yolo"): CommandLine;
|
|
7
|
+
init(): Promise<boolean>;
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=droid.d.ts.map
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { execSync } from "child_process";
|
|
2
|
+
import { getAgentInstructions } from "./shared-prompt.js";
|
|
3
|
+
import { SHELL } from "../platform/index.js";
|
|
4
|
+
export class DroidAgent {
|
|
5
|
+
supportsPermissions = false;
|
|
6
|
+
getPlanGenerationCommandLine(prompt) {
|
|
7
|
+
return {
|
|
8
|
+
command: "droid",
|
|
9
|
+
args: ["exec", prompt],
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
getTaskRunCommandLine(task, followupPrompt, extraPermissions) {
|
|
13
|
+
const yolo = extraPermissions === "yolo";
|
|
14
|
+
const prompt = followupPrompt ?? (getAgentInstructions(task.frontmatter.id, yolo || !this.supportsPermissions) + "\n\n" + (task.body || task.frontmatter.user_prompt));
|
|
15
|
+
const args = ["exec", "--session-id", task.frontmatter.id];
|
|
16
|
+
if (yolo) {
|
|
17
|
+
args.push("--skip-permissions-unsafe");
|
|
18
|
+
}
|
|
19
|
+
args.push(prompt);
|
|
20
|
+
return { command: "droid", args };
|
|
21
|
+
}
|
|
22
|
+
async init() {
|
|
23
|
+
try {
|
|
24
|
+
execSync("droid --version", { stdio: "ignore", shell: SHELL });
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
return true;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=droid.js.map
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { ParsedTask, RequiredPermission } from "../types.js";
|
|
2
|
+
import type { AgentTool, CommandLine } from "./agent.js";
|
|
3
|
+
export declare class GooseAgent implements AgentTool {
|
|
4
|
+
supportsPermissions: boolean;
|
|
5
|
+
getPlanGenerationCommandLine(prompt: string): CommandLine;
|
|
6
|
+
getTaskRunCommandLine(task: ParsedTask, followupPrompt?: string, extraPermissions?: RequiredPermission[] | "yolo"): CommandLine;
|
|
7
|
+
init(): Promise<boolean>;
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=goose.d.ts.map
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { execSync } from "child_process";
|
|
2
|
+
import { getAgentInstructions } from "./shared-prompt.js";
|
|
3
|
+
import { SHELL } from "../platform/index.js";
|
|
4
|
+
export class GooseAgent {
|
|
5
|
+
supportsPermissions = false;
|
|
6
|
+
getPlanGenerationCommandLine(prompt) {
|
|
7
|
+
return {
|
|
8
|
+
command: "goose",
|
|
9
|
+
args: ["run", "--text", prompt],
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
getTaskRunCommandLine(task, followupPrompt, extraPermissions) {
|
|
13
|
+
const yolo = extraPermissions === "yolo";
|
|
14
|
+
const prompt = followupPrompt ?? (getAgentInstructions(task.frontmatter.id, yolo || !this.supportsPermissions) + "\n\n" + (task.body || task.frontmatter.user_prompt));
|
|
15
|
+
const args = ["run"];
|
|
16
|
+
if (followupPrompt) {
|
|
17
|
+
args.push("--resume");
|
|
18
|
+
} // continue mode for followups
|
|
19
|
+
args.push("--text", prompt);
|
|
20
|
+
return { command: "goose", args, ...(yolo ? { env: { GOOSE_MODE: "auto" } } : {}) };
|
|
21
|
+
}
|
|
22
|
+
async init() {
|
|
23
|
+
try {
|
|
24
|
+
execSync("goose --version", { stdio: "ignore", shell: SHELL });
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
return true;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=goose.js.map
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { ParsedTask, RequiredPermission } from "../types.js";
|
|
2
|
+
import type { AgentTool, CommandLine } from "./agent.js";
|
|
3
|
+
export declare class OpenCodeAgent implements AgentTool {
|
|
4
|
+
supportsPermissions: boolean;
|
|
5
|
+
getPlanGenerationCommandLine(prompt: string): CommandLine;
|
|
6
|
+
getTaskRunCommandLine(task: ParsedTask, followupPrompt?: string, extraPermissions?: RequiredPermission[] | "yolo"): CommandLine;
|
|
7
|
+
init(): Promise<boolean>;
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=opencode.d.ts.map
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { execSync } from "child_process";
|
|
2
|
+
import { getAgentInstructions } from "./shared-prompt.js";
|
|
3
|
+
import { SHELL } from "../platform/index.js";
|
|
4
|
+
export class OpenCodeAgent {
|
|
5
|
+
supportsPermissions = false;
|
|
6
|
+
getPlanGenerationCommandLine(prompt) {
|
|
7
|
+
return {
|
|
8
|
+
command: "opencode",
|
|
9
|
+
args: ["run", prompt],
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
getTaskRunCommandLine(task, followupPrompt, extraPermissions) {
|
|
13
|
+
const yolo = extraPermissions === "yolo";
|
|
14
|
+
const prompt = followupPrompt ?? (getAgentInstructions(task.frontmatter.id, yolo || !this.supportsPermissions) + "\n\n" + (task.body || task.frontmatter.user_prompt));
|
|
15
|
+
const args = ["run"];
|
|
16
|
+
if (yolo) {
|
|
17
|
+
args.push("--dangerously-skip-permissions");
|
|
18
|
+
}
|
|
19
|
+
if (followupPrompt) {
|
|
20
|
+
args.push("--continue");
|
|
21
|
+
} // continue mode for followups
|
|
22
|
+
args.push(prompt);
|
|
23
|
+
return { command: "opencode", args };
|
|
24
|
+
}
|
|
25
|
+
async init() {
|
|
26
|
+
try {
|
|
27
|
+
execSync("opencode --version", { stdio: "ignore", shell: SHELL });
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
return true;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=opencode.js.map
|