@action-llama/action-llama 0.1.5 → 0.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/README.md +76 -68
- package/dist/agents/container-entry.js +79 -18
- package/dist/agents/container-entry.js.map +1 -1
- package/dist/agents/container-runner.d.ts +2 -1
- package/dist/agents/container-runner.d.ts.map +1 -1
- package/dist/agents/container-runner.js +48 -18
- package/dist/agents/container-runner.js.map +1 -1
- package/dist/agents/prompt.d.ts.map +1 -1
- package/dist/agents/prompt.js +18 -7
- package/dist/agents/prompt.js.map +1 -1
- package/dist/agents/runner.d.ts.map +1 -1
- package/dist/agents/runner.js +40 -6
- package/dist/agents/runner.js.map +1 -1
- package/dist/cli/commands/{agent/add.d.ts → console.d.ts} +1 -2
- package/dist/cli/commands/console.d.ts.map +1 -0
- package/dist/cli/commands/console.js +173 -0
- package/dist/cli/commands/console.js.map +1 -0
- package/dist/cli/commands/new.d.ts.map +1 -1
- package/dist/cli/commands/new.js +27 -52
- package/dist/cli/commands/new.js.map +1 -1
- package/dist/cli/commands/setup.d.ts +4 -0
- package/dist/cli/commands/setup.d.ts.map +1 -0
- package/dist/cli/commands/setup.js +50 -0
- package/dist/cli/commands/setup.js.map +1 -0
- package/dist/cli/commands/start.d.ts.map +1 -1
- package/dist/cli/commands/start.js +3 -0
- package/dist/cli/commands/start.js.map +1 -1
- package/dist/cli/commands/status.d.ts.map +1 -1
- package/dist/cli/commands/status.js +1 -37
- package/dist/cli/commands/status.js.map +1 -1
- package/dist/cli/main.js +14 -9
- package/dist/cli/main.js.map +1 -1
- package/dist/credentials/builtins/anthropic-key.d.ts +4 -0
- package/dist/credentials/builtins/anthropic-key.d.ts.map +1 -0
- package/dist/credentials/builtins/anthropic-key.js +68 -0
- package/dist/credentials/builtins/anthropic-key.js.map +1 -0
- package/dist/credentials/builtins/github-token.d.ts +4 -0
- package/dist/credentials/builtins/github-token.d.ts.map +1 -0
- package/dist/credentials/builtins/github-token.js +18 -0
- package/dist/credentials/builtins/github-token.js.map +1 -0
- package/dist/credentials/builtins/github-webhook-secret.d.ts +4 -0
- package/dist/credentials/builtins/github-webhook-secret.d.ts.map +1 -0
- package/dist/credentials/builtins/github-webhook-secret.js +11 -0
- package/dist/credentials/builtins/github-webhook-secret.js.map +1 -0
- package/dist/credentials/builtins/id-rsa.d.ts +4 -0
- package/dist/credentials/builtins/id-rsa.d.ts.map +1 -0
- package/dist/credentials/builtins/id-rsa.js +95 -0
- package/dist/credentials/builtins/id-rsa.js.map +1 -0
- package/dist/credentials/builtins/index.d.ts +3 -0
- package/dist/credentials/builtins/index.d.ts.map +1 -0
- package/dist/credentials/builtins/index.js +15 -0
- package/dist/credentials/builtins/index.js.map +1 -0
- package/dist/credentials/builtins/sentry-client-secret.d.ts +4 -0
- package/dist/credentials/builtins/sentry-client-secret.d.ts.map +1 -0
- package/dist/credentials/builtins/sentry-client-secret.js +11 -0
- package/dist/credentials/builtins/sentry-client-secret.js.map +1 -0
- package/dist/credentials/builtins/sentry-token.d.ts +4 -0
- package/dist/credentials/builtins/sentry-token.d.ts.map +1 -0
- package/dist/credentials/builtins/sentry-token.js +71 -0
- package/dist/credentials/builtins/sentry-token.js.map +1 -0
- package/dist/credentials/prompter.d.ts +14 -0
- package/dist/credentials/prompter.d.ts.map +1 -0
- package/dist/credentials/prompter.js +55 -0
- package/dist/credentials/prompter.js.map +1 -0
- package/dist/credentials/registry.d.ts +16 -0
- package/dist/credentials/registry.d.ts.map +1 -0
- package/dist/credentials/registry.js +25 -0
- package/dist/credentials/registry.js.map +1 -0
- package/dist/credentials/schema.d.ts +22 -0
- package/dist/credentials/schema.d.ts.map +1 -0
- package/dist/credentials/schema.js +5 -0
- package/dist/credentials/schema.js.map +1 -0
- package/dist/docker/container.js +1 -1
- package/dist/docker/container.js.map +1 -1
- package/dist/docker/image.d.ts +8 -0
- package/dist/docker/image.d.ts.map +1 -1
- package/dist/docker/image.js +26 -2
- package/dist/docker/image.js.map +1 -1
- package/dist/scheduler/index.d.ts.map +1 -1
- package/dist/scheduler/index.js +44 -13
- package/dist/scheduler/index.js.map +1 -1
- package/dist/setup/prompts.d.ts +1 -43
- package/dist/setup/prompts.d.ts.map +1 -1
- package/dist/setup/prompts.js +40 -609
- package/dist/setup/prompts.js.map +1 -1
- package/dist/setup/scaffold.d.ts +3 -4
- package/dist/setup/scaffold.d.ts.map +1 -1
- package/dist/setup/scaffold.js +347 -32
- package/dist/setup/scaffold.js.map +1 -1
- package/dist/shared/config.d.ts +1 -2
- package/dist/shared/config.d.ts.map +1 -1
- package/dist/shared/config.js +16 -6
- package/dist/shared/config.js.map +1 -1
- package/dist/shared/credentials.d.ts +37 -3
- package/dist/shared/credentials.d.ts.map +1 -1
- package/dist/shared/credentials.js +68 -11
- package/dist/shared/credentials.js.map +1 -1
- package/dist/shared/git.js +1 -1
- package/dist/shared/git.js.map +1 -1
- package/dist/shared/paths.d.ts +0 -1
- package/dist/shared/paths.d.ts.map +1 -1
- package/dist/shared/paths.js +0 -3
- package/dist/shared/paths.js.map +1 -1
- package/dist/tui/App.d.ts.map +1 -1
- package/dist/tui/App.js +11 -5
- package/dist/tui/App.js.map +1 -1
- package/dist/tui/status-tracker.d.ts +5 -3
- package/dist/tui/status-tracker.d.ts.map +1 -1
- package/dist/tui/status-tracker.js +14 -2
- package/dist/tui/status-tracker.js.map +1 -1
- package/dist/webhooks/definitions/github.d.ts +3 -0
- package/dist/webhooks/definitions/github.d.ts.map +1 -0
- package/dist/webhooks/definitions/github.js +38 -0
- package/dist/webhooks/definitions/github.js.map +1 -0
- package/dist/webhooks/definitions/registry.d.ts +4 -0
- package/dist/webhooks/definitions/registry.d.ts.map +1 -0
- package/dist/webhooks/definitions/registry.js +14 -0
- package/dist/webhooks/definitions/registry.js.map +1 -0
- package/dist/webhooks/definitions/schema.d.ts +19 -0
- package/dist/webhooks/definitions/schema.d.ts.map +1 -0
- package/dist/webhooks/definitions/schema.js +2 -0
- package/dist/webhooks/definitions/schema.js.map +1 -0
- package/dist/webhooks/definitions/sentry.d.ts +3 -0
- package/dist/webhooks/definitions/sentry.d.ts.map +1 -0
- package/dist/webhooks/definitions/sentry.js +22 -0
- package/dist/webhooks/definitions/sentry.js.map +1 -0
- package/dist/webhooks/providers/sentry.d.ts +9 -0
- package/dist/webhooks/providers/sentry.d.ts.map +1 -0
- package/dist/webhooks/providers/sentry.js +108 -0
- package/dist/webhooks/providers/sentry.js.map +1 -0
- package/dist/webhooks/registry.js +2 -2
- package/dist/webhooks/registry.js.map +1 -1
- package/dist/webhooks/types.d.ts +5 -1
- package/dist/webhooks/types.d.ts.map +1 -1
- package/docker/Dockerfile +1 -11
- package/package.json +6 -5
- package/dist/agents/definitions/dev/AGENTS.md +0 -44
- package/dist/agents/definitions/dev/config-definition.json +0 -39
- package/dist/agents/definitions/devops/AGENTS.md +0 -33
- package/dist/agents/definitions/devops/config-definition.json +0 -37
- package/dist/agents/definitions/loader.d.ts +0 -18
- package/dist/agents/definitions/loader.d.ts.map +0 -1
- package/dist/agents/definitions/loader.js +0 -59
- package/dist/agents/definitions/loader.js.map +0 -1
- package/dist/agents/definitions/reviewer/AGENTS.md +0 -37
- package/dist/agents/definitions/reviewer/config-definition.json +0 -24
- package/dist/agents/definitions/schema.d.ts +0 -38
- package/dist/agents/definitions/schema.d.ts.map +0 -1
- package/dist/agents/definitions/schema.js +0 -97
- package/dist/agents/definitions/schema.js.map +0 -1
- package/dist/cli/commands/agent/add.d.ts.map +0 -1
- package/dist/cli/commands/agent/add.js +0 -86
- package/dist/cli/commands/agent/add.js.map +0 -1
package/README.md
CHANGED
|
@@ -9,7 +9,7 @@ Run agents like scripts: triggered by cron or webhooks.
|
|
|
9
9
|
Dev Experience:
|
|
10
10
|
|
|
11
11
|
1. Either a webhook or cron wakes up the agent
|
|
12
|
-
2. The agent runs according the instructions in
|
|
12
|
+
2. The agent runs according to the instructions in PLAYBOOK.md you define
|
|
13
13
|
3. The agent shuts down
|
|
14
14
|
|
|
15
15
|
Key features:
|
|
@@ -33,85 +33,79 @@ Built on [pi.dev](https://github.com/badlogic/pi-mono) as the agent harness.
|
|
|
33
33
|
|
|
34
34
|
## How to get started
|
|
35
35
|
|
|
36
|
+
### 1. Create a project
|
|
37
|
+
|
|
36
38
|
```bash
|
|
37
39
|
npx @action-llama/action-llama@latest new my-project
|
|
40
|
+
cd my-project
|
|
38
41
|
```
|
|
39
42
|
|
|
40
|
-
|
|
43
|
+
This scaffolds the project and sets up your Anthropic credential and default model.
|
|
44
|
+
|
|
45
|
+
### 2. Create and manage agents
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
npx al console
|
|
49
|
+
```
|
|
41
50
|
|
|
42
|
-
|
|
51
|
+
The console is a TUI powered by [Pi](https://github.com/badlogic/pi-mono) that helps you create and manage agents. If no agents exist yet, it will offer to create one for you.
|
|
43
52
|
|
|
44
|
-
|
|
53
|
+
You can also create agents manually — see the [creating agents guide](docs/creating-agents.md).
|
|
45
54
|
|
|
46
|
-
|
|
55
|
+
Or, if you're using your own coding agent just make sure it reads the AGENTS.md in your project root. It contains everything needed to create agents (including a complete example playbook).
|
|
47
56
|
|
|
48
|
-
|
|
49
|
-
- **Repos** — which GitHub repos to monitor (fetched from your token)
|
|
50
|
-
- **Trigger label** — the issue label that activates the agent (default: `agent`)
|
|
51
|
-
- **Assignee** — only trigger on issues assigned to this user (default: your GitHub username)
|
|
52
|
-
- **Webhooks** — say **no** for now (requires setting up a GitHub webhook endpoint)
|
|
53
|
-
- **Schedule** — say **yes**, and accept the default `*/5 * * * *` (poll every 5 minutes)
|
|
57
|
+
### 3. Run
|
|
54
58
|
|
|
55
|
-
Once
|
|
59
|
+
Once your agents are ready, run the gateway!
|
|
56
60
|
|
|
57
61
|
```bash
|
|
58
|
-
|
|
59
|
-
npx al start # if using local install
|
|
62
|
+
npx al start
|
|
60
63
|
```
|
|
61
64
|
|
|
62
|
-
|
|
65
|
+
If any credentials are missing, it will prompt you for them. Credentials are stored in `~/.action-llama-credentials/` (shared across projects, not committed to git). See [credentials docs](docs/credentials.md) for details.
|
|
63
66
|
|
|
64
|
-
|
|
67
|
+
If you want to set up credentials without starting the gateway:
|
|
65
68
|
|
|
66
|
-
|
|
69
|
+
```bash
|
|
70
|
+
npx al setup
|
|
71
|
+
```
|
|
67
72
|
|
|
68
|
-
|
|
73
|
+
### Project structure
|
|
69
74
|
|
|
70
75
|
```
|
|
71
76
|
my-project/
|
|
72
77
|
package.json # Includes @action-llama/action-llama as a dependency
|
|
78
|
+
AGENTS.md # Project overview, credential/webhook reference, example playbook
|
|
73
79
|
config.json # Global config: docker, gateway, webhooks (no secrets)
|
|
74
80
|
dev/ # One directory per agent
|
|
75
|
-
config.
|
|
76
|
-
|
|
81
|
+
agent-config.toml # Agent config: credentials, repos, model, schedule, webhooks, params
|
|
82
|
+
PLAYBOOK.md # Agent instructions (system prompt) — edit to customize behavior
|
|
83
|
+
Dockerfile # (optional) Custom Docker image for this agent
|
|
77
84
|
```
|
|
78
85
|
|
|
79
|
-
Credentials are stored separately in `~/.action-llama-credentials/` (shared across projects, not committed to git).
|
|
80
|
-
|
|
81
86
|
## CLI commands
|
|
82
87
|
|
|
83
88
|
If you installed globally (`npm install -g @action-llama/action-llama`), you can use `al` directly. Otherwise, prefix commands with `npx` (e.g., `npx al start`).
|
|
84
89
|
|
|
85
90
|
| Command | Description |
|
|
86
91
|
|---------|-------------|
|
|
87
|
-
| `al new <name>` |
|
|
92
|
+
| `al new <name>` | Scaffold a new project (sets up Anthropic credential and model defaults) |
|
|
93
|
+
| `al console` | TUI for creating and managing agents |
|
|
94
|
+
| `al setup` | Scan agents and prompt for any missing credentials |
|
|
88
95
|
| `al start` | Start the scheduler — runs agents on their cron schedule and/or webhook triggers |
|
|
89
96
|
| `al status` | Show the current status of all agents |
|
|
90
97
|
| `al logs <agent>` | View log entries for an agent |
|
|
91
|
-
|
|
98
|
+
|
|
99
|
+
See [CLI command reference](docs/commands.md) for all options and flags.
|
|
92
100
|
|
|
93
101
|
### Common options
|
|
94
102
|
|
|
95
103
|
- `-p, --project <dir>` — specify the project directory (defaults to `.`)
|
|
96
104
|
|
|
97
|
-
### `al logs` options
|
|
98
|
-
|
|
99
|
-
- `-n, --lines <N>` — number of log entries to show (default: 50)
|
|
100
|
-
- `-f, --follow` — tail mode, watch for new log entries
|
|
101
|
-
- `-d, --date <YYYY-MM-DD>` — view a specific date's log file
|
|
102
|
-
|
|
103
105
|
### `al start` options
|
|
104
106
|
|
|
105
107
|
- `--dangerous-no-docker` — disable Docker container isolation and run agents directly on the host
|
|
106
108
|
|
|
107
|
-
## Built-in Agents
|
|
108
|
-
|
|
109
|
-
| Agent | Trigger | Action |
|
|
110
|
-
|-------|---------|--------|
|
|
111
|
-
| **Developer** | Webhook: issue labeled; or poll for labeled issues | Checks out a worktree, implements the fix/feature, runs tests, opens a PR |
|
|
112
|
-
| **PR Reviewer** | Webhook: PR opened/updated; or poll for open PRs | Reviews code for correctness, style, security; approves+merges or requests changes |
|
|
113
|
-
| **DevOps** | Poll for CI failures/Sentry errors | Creates Github issues describing problem and potential fix |
|
|
114
|
-
|
|
115
109
|
## Configuration
|
|
116
110
|
|
|
117
111
|
### Global config (`config.json`)
|
|
@@ -120,45 +114,32 @@ If you installed globally (`npm install -g @action-llama/action-llama`), you can
|
|
|
120
114
|
{
|
|
121
115
|
"docker": { "enabled": false },
|
|
122
116
|
"gateway": { "port": 8080 },
|
|
123
|
-
"webhooks": { "
|
|
117
|
+
"webhooks": { "secretCredentials": { "github": "github_webhook_secret:default" } }
|
|
124
118
|
}
|
|
125
119
|
```
|
|
126
120
|
|
|
127
121
|
| Key | Default | Description |
|
|
128
122
|
|-----|---------|-------------|
|
|
129
123
|
| `docker.enabled` | `false` | Run agents in isolated Docker containers |
|
|
130
|
-
| `docker.image` | `"al-agent:latest"` | Docker image for containers |
|
|
124
|
+
| `docker.image` | `"al-agent:latest"` | Base Docker image for containers |
|
|
131
125
|
| `docker.memory` | `"4g"` | Memory limit per container |
|
|
132
126
|
| `docker.cpus` | `2` | CPU limit per container |
|
|
133
127
|
| `docker.timeout` | `3600` | Max container runtime (seconds) |
|
|
134
128
|
| `gateway.port` | `8080` | Gateway server listen port |
|
|
135
129
|
|
|
136
|
-
### Agent config (`<agent>/config.
|
|
130
|
+
### Agent config (`<agent>/agent-config.toml`)
|
|
137
131
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
"repos": ["acme/frontend"],
|
|
144
|
-
"schedule": "*/5 * * * *",
|
|
145
|
-
"webhooks": {
|
|
146
|
-
"filters": [{
|
|
147
|
-
"source": "github",
|
|
148
|
-
"events": ["issues"],
|
|
149
|
-
"actions": ["labeled"],
|
|
150
|
-
"labels": ["agent"],
|
|
151
|
-
"assignee": "bot-user"
|
|
152
|
-
}]
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
```
|
|
132
|
+
See the [agent-config.toml reference](docs/agent-config-reference.md) for all fields. Each agent carries its own model config, so you can run different models per agent (e.g., Opus for dev, Haiku for devops).
|
|
133
|
+
|
|
134
|
+
### Credentials
|
|
135
|
+
|
|
136
|
+
Credentials are stored in `~/.action-llama-credentials/<type>/<instance>/<field>` and referenced in agent configs as `"type:instance"` (e.g. `"github_token:default"`). Run `al setup` to configure them interactively.
|
|
156
137
|
|
|
157
|
-
|
|
138
|
+
See [credentials docs](docs/credentials.md) for the full reference including built-in credential types, named instances, and manual setup.
|
|
158
139
|
|
|
159
140
|
### Webhooks
|
|
160
141
|
|
|
161
|
-
To use webhooks instead of polling,
|
|
142
|
+
To use webhooks instead of polling, add webhook filters to your `agent-config.toml` and add a webhook in your GitHub repo settings:
|
|
162
143
|
|
|
163
144
|
- **Payload URL**: `http://<your-host>:8080/webhooks/github`
|
|
164
145
|
- **Content type**: `application/json`
|
|
@@ -166,6 +147,8 @@ To use webhooks instead of polling, enable them during `al new` and add a webhoo
|
|
|
166
147
|
|
|
167
148
|
Payloads are validated with HMAC-SHA256 (`x-hub-signature-256`). Webhook filters in `webhooks.filters` support matching on `source`, `repos`, `events`, `actions`, `labels`, `assignee`, `author`, and `branches` (AND logic; omitted fields are not checked).
|
|
168
149
|
|
|
150
|
+
See [webhooks docs](docs/webhooks.md) for filter fields, Sentry webhooks, and setup details.
|
|
151
|
+
|
|
169
152
|
#### Local development with ngrok
|
|
170
153
|
|
|
171
154
|
If you're developing locally and need GitHub to reach your machine, use [ngrok](https://ngrok.com) to create a public tunnel:
|
|
@@ -192,7 +175,32 @@ ngrok http 8080 --url=your-name.ngrok-free.app
|
|
|
192
175
|
|
|
193
176
|
### Docker mode
|
|
194
177
|
|
|
195
|
-
Set `"docker": { "enabled": true }` in `config.json`. Agents run in isolated containers with credentials mounted read-only
|
|
178
|
+
Set `"docker": { "enabled": true }` in `config.json`. Agents run in isolated containers with credentials mounted read-only, a read-only root FS, dropped capabilities, non-root user, and PID/memory/CPU limits.
|
|
179
|
+
|
|
180
|
+
The base image is built automatically on first run from `docker/Dockerfile`. Agents can extend it by adding a `Dockerfile` to their directory:
|
|
181
|
+
|
|
182
|
+
```dockerfile
|
|
183
|
+
FROM al-agent:latest
|
|
184
|
+
USER root
|
|
185
|
+
RUN apt-get update && apt-get install -y --no-install-recommends gh && rm -rf /var/lib/apt/lists/*
|
|
186
|
+
USER node
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
See [Docker docs](docs/docker.md) for the full reference including base image contents, custom Dockerfiles, standalone images, and the container filesystem layout.
|
|
190
|
+
|
|
191
|
+
## Documentation
|
|
192
|
+
|
|
193
|
+
| Doc | Description |
|
|
194
|
+
|-----|-------------|
|
|
195
|
+
| [Creating Agents](docs/creating-agents.md) | Step-by-step guide to creating a new agent |
|
|
196
|
+
| [agent-config.toml Reference](docs/agent-config-reference.md) | All config fields with examples |
|
|
197
|
+
| [Credentials](docs/credentials.md) | Credential types, storage layout, named instances |
|
|
198
|
+
| [Webhooks](docs/webhooks.md) | Webhook setup, filter fields, Sentry integration |
|
|
199
|
+
| [Docker](docs/docker.md) | Container isolation, custom Dockerfiles, filesystem layout |
|
|
200
|
+
| [CLI Commands](docs/commands.md) | All CLI commands with options and flags |
|
|
201
|
+
| [Example: Dev Agent](docs/examples/dev-agent.md) | Developer agent that implements GitHub issues |
|
|
202
|
+
| [Example: Reviewer Agent](docs/examples/reviewer-agent.md) | PR review agent |
|
|
203
|
+
| [Example: DevOps Agent](docs/examples/devops-agent.md) | CI/CD and Sentry monitoring agent |
|
|
196
204
|
|
|
197
205
|
## Developing
|
|
198
206
|
|
|
@@ -216,7 +224,7 @@ npm test
|
|
|
216
224
|
|
|
217
225
|
`al start` runs a single Node.js process (the **scheduler**) that:
|
|
218
226
|
|
|
219
|
-
1. Discovers agents in the project directory (each subdirectory with
|
|
227
|
+
1. Discovers agents in the project directory (each subdirectory with an `agent-config.toml`)
|
|
220
228
|
2. Starts a **gateway** HTTP server if webhooks or Docker mode are enabled (health check, webhook receiver, shutdown kill switch)
|
|
221
229
|
3. Creates a **runner** per agent — either `AgentRunner` (host mode) or `ContainerAgentRunner` (Docker mode)
|
|
222
230
|
4. Wires up **cron jobs** and/or **webhook bindings** to trigger each runner
|
|
@@ -226,10 +234,10 @@ npm test
|
|
|
226
234
|
|
|
227
235
|
```
|
|
228
236
|
src/
|
|
229
|
-
cli/ # Command definitions (new, start, status, logs
|
|
230
|
-
setup/ #
|
|
237
|
+
cli/ # Command definitions (new, setup, start, status, logs)
|
|
238
|
+
setup/ # Project scaffolding
|
|
231
239
|
scheduler/ # Scheduler: discovers agents, starts gateway, wires cron + webhooks
|
|
232
|
-
agents/ # Agent runners (host + Docker), prompt builder
|
|
240
|
+
agents/ # Agent runners (host + Docker), prompt builder
|
|
233
241
|
gateway/ # HTTP server: router, health, shutdown, webhook routes
|
|
234
242
|
docker/ # Container lifecycle (launch, wait, logs, remove), image + network
|
|
235
243
|
webhooks/ # Webhook registry, provider interface, GitHub provider
|
|
@@ -239,7 +247,7 @@ src/
|
|
|
239
247
|
|
|
240
248
|
### Extension points
|
|
241
249
|
|
|
242
|
-
- **New agent
|
|
250
|
+
- **New agent** — create a directory with an `agent-config.toml` and `PLAYBOOK.md` in your project. See [creating agents](docs/creating-agents.md).
|
|
243
251
|
- **New webhook provider** — implement the `WebhookProvider` interface in `src/webhooks/providers/` and register it in `src/scheduler/index.ts`. The registry handles routing by `source` field.
|
|
244
252
|
- **Custom runner** — subclass or replace `AgentRunner` in `src/agents/runner.ts` to change how agent sessions are created (different model providers, tool sets, etc.).
|
|
245
253
|
- **Gateway routes** — add routes in `src/gateway/routes/` and register them in `src/gateway/index.ts`.
|
|
@@ -247,7 +255,7 @@ src/
|
|
|
247
255
|
### Tests
|
|
248
256
|
|
|
249
257
|
```bash
|
|
250
|
-
npm test # run all
|
|
258
|
+
npm test # run all 185 tests
|
|
251
259
|
npm run test:watch # watch mode
|
|
252
260
|
npm run test:coverage # V8 coverage report
|
|
253
261
|
```
|
|
@@ -1,16 +1,28 @@
|
|
|
1
|
-
import { readFileSync, existsSync } from "fs";
|
|
1
|
+
import { readFileSync, existsSync, mkdirSync, writeFileSync, readdirSync } from "fs";
|
|
2
|
+
import { resolve } from "path";
|
|
2
3
|
import { getModel } from "@mariozechner/pi-ai";
|
|
3
4
|
import { AuthStorage, createAgentSession, DefaultResourceLoader, SessionManager, SettingsManager, createCodingTools, } from "@mariozechner/pi-coding-agent";
|
|
5
|
+
import { parseCredentialRef } from "../shared/credentials.js";
|
|
4
6
|
// Structured log line — written to stdout, parsed by ContainerAgentRunner on the host
|
|
5
7
|
function emitLog(level, msg, data) {
|
|
6
8
|
console.log(JSON.stringify({ _log: true, level, msg, ...data, ts: Date.now() }));
|
|
7
9
|
}
|
|
8
|
-
function
|
|
9
|
-
const path = `/credentials/${
|
|
10
|
+
function readCredentialField(type, instance, field) {
|
|
11
|
+
const path = `/credentials/${type}/${instance}/${field}`;
|
|
10
12
|
if (!existsSync(path))
|
|
11
13
|
return undefined;
|
|
12
14
|
return readFileSync(path, "utf-8").trim();
|
|
13
15
|
}
|
|
16
|
+
function readCredentialFields(type, instance) {
|
|
17
|
+
const dir = `/credentials/${type}/${instance}`;
|
|
18
|
+
const result = {};
|
|
19
|
+
if (!existsSync(dir))
|
|
20
|
+
return result;
|
|
21
|
+
for (const file of readdirSync(dir)) {
|
|
22
|
+
result[file] = readFileSync(resolve(dir, file), "utf-8").trim();
|
|
23
|
+
}
|
|
24
|
+
return result;
|
|
25
|
+
}
|
|
14
26
|
async function main() {
|
|
15
27
|
// Switch CWD to /workspace so child processes (git, bash, etc.) default to it.
|
|
16
28
|
// Node must resolve from /app (WORKDIR at build time), so we chdir after startup.
|
|
@@ -30,29 +42,78 @@ async function main() {
|
|
|
30
42
|
const modelId = agentConfig.model.model;
|
|
31
43
|
const modelThinking = agentConfig.model.thinkingLevel;
|
|
32
44
|
emitLog("info", "container starting", { agentName: agentConfig.name, modelId, gatewayUrl });
|
|
33
|
-
// Read Anthropic API key from credentials volume
|
|
34
|
-
const anthropicKey =
|
|
35
|
-
if (!anthropicKey) {
|
|
36
|
-
emitLog("error", "missing
|
|
45
|
+
// Read Anthropic API key from credentials volume (not needed for pi_auth)
|
|
46
|
+
const anthropicKey = readCredentialField("anthropic_key", "default", "token");
|
|
47
|
+
if (!anthropicKey && agentConfig.model.authType !== "pi_auth") {
|
|
48
|
+
emitLog("error", "missing anthropic_key credential. Run 'al setup' to configure it.");
|
|
37
49
|
process.exit(1);
|
|
38
50
|
}
|
|
39
|
-
//
|
|
40
|
-
const
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
51
|
+
// Generic credential → env var injection from credential definitions
|
|
52
|
+
const { builtinCredentials } = await import("../credentials/builtins/index.js");
|
|
53
|
+
for (const credRef of agentConfig.credentials) {
|
|
54
|
+
const { type, instance } = parseCredentialRef(credRef);
|
|
55
|
+
const def = builtinCredentials[type];
|
|
56
|
+
if (!def?.envVars)
|
|
57
|
+
continue;
|
|
58
|
+
const fields = readCredentialFields(type, instance);
|
|
59
|
+
for (const [fieldName, envVar] of Object.entries(def.envVars)) {
|
|
60
|
+
if (fields[fieldName]) {
|
|
61
|
+
process.env[envVar] = fields[fieldName];
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
// Special case: github_token also sets GH_TOKEN alias
|
|
65
|
+
if (type === "github_token" && fields.token) {
|
|
66
|
+
process.env.GH_TOKEN = fields.token;
|
|
67
|
+
}
|
|
44
68
|
}
|
|
45
|
-
|
|
46
|
-
if (
|
|
47
|
-
process.env.
|
|
69
|
+
// Configure git credential helper so HTTPS clones can use GITHUB_TOKEN
|
|
70
|
+
if (process.env.GITHUB_TOKEN) {
|
|
71
|
+
process.env.GIT_ASKPASS = "/bin/echo";
|
|
72
|
+
process.env.GIT_TERMINAL_PROMPT = "0";
|
|
73
|
+
const { execSync } = await import("child_process");
|
|
74
|
+
try {
|
|
75
|
+
execSync('git config --global credential.helper "!f() { echo username=x-access-token; echo password=$GITHUB_TOKEN; }; f"', { stdio: "ignore" });
|
|
76
|
+
emitLog("info", "git HTTPS credential helper configured");
|
|
77
|
+
}
|
|
78
|
+
catch (err) {
|
|
79
|
+
emitLog("warn", "failed to configure git credential helper", { error: err.message });
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
// Set up SSH key for git push/clone if git_ssh credential is available
|
|
83
|
+
// Find the git_ssh instance from credentials
|
|
84
|
+
const gitSshRef = agentConfig.credentials.find((ref) => parseCredentialRef(ref).type === "git_ssh");
|
|
85
|
+
if (gitSshRef) {
|
|
86
|
+
const { instance } = parseCredentialRef(gitSshRef);
|
|
87
|
+
const sshKey = readCredentialField("git_ssh", instance, "id_rsa");
|
|
88
|
+
if (sshKey) {
|
|
89
|
+
const sshDir = "/home/node/.ssh";
|
|
90
|
+
mkdirSync(sshDir, { recursive: true, mode: 0o700 });
|
|
91
|
+
const keyPath = `${sshDir}/id_rsa`;
|
|
92
|
+
writeFileSync(keyPath, sshKey + "\n", { mode: 0o600 });
|
|
93
|
+
process.env.GIT_SSH_COMMAND = `ssh -i "${keyPath}" -o StrictHostKeyChecking=accept-new -o IdentitiesOnly=yes`;
|
|
94
|
+
emitLog("info", "SSH key configured for git");
|
|
95
|
+
}
|
|
96
|
+
// Set git author identity
|
|
97
|
+
const gitName = readCredentialField("git_ssh", instance, "username");
|
|
98
|
+
if (gitName) {
|
|
99
|
+
process.env.GIT_AUTHOR_NAME = gitName;
|
|
100
|
+
process.env.GIT_COMMITTER_NAME = gitName;
|
|
101
|
+
}
|
|
102
|
+
const gitEmail = readCredentialField("git_ssh", instance, "email");
|
|
103
|
+
if (gitEmail) {
|
|
104
|
+
process.env.GIT_AUTHOR_EMAIL = gitEmail;
|
|
105
|
+
process.env.GIT_COMMITTER_EMAIL = gitEmail;
|
|
106
|
+
}
|
|
48
107
|
}
|
|
49
108
|
const cwd = "/workspace";
|
|
50
109
|
const model = getModel("anthropic", modelId);
|
|
51
110
|
const authStorage = AuthStorage.create();
|
|
52
|
-
|
|
53
|
-
|
|
111
|
+
if (anthropicKey) {
|
|
112
|
+
authStorage.setRuntimeApiKey("anthropic", anthropicKey);
|
|
113
|
+
}
|
|
114
|
+
// PLAYBOOK.md content is passed via the serialized config from the host
|
|
54
115
|
const agentsContent = agentsMd || `# ${agentConfig.name} Agent\n\nCustom agent.\n`;
|
|
55
|
-
const agentsFile = "/tmp/
|
|
116
|
+
const agentsFile = "/tmp/PLAYBOOK.md";
|
|
56
117
|
const resourceLoader = new DefaultResourceLoader({
|
|
57
118
|
noExtensions: true,
|
|
58
119
|
agentsFilesOverride: () => ({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"container-entry.js","sourceRoot":"","sources":["../../src/agents/container-entry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"container-entry.js","sourceRoot":"","sources":["../../src/agents/container-entry.ts"],"names":[],"mappings":"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"}
|
|
@@ -9,8 +9,9 @@ export declare class ContainerAgentRunner {
|
|
|
9
9
|
private registerContainer;
|
|
10
10
|
private gatewayUrl;
|
|
11
11
|
private projectPath;
|
|
12
|
+
private image;
|
|
12
13
|
private statusTracker?;
|
|
13
|
-
constructor(globalConfig: GlobalConfig, agentConfig: AgentConfig, logger: Logger, registerContainer: (secret: string, containerName: string) => void, gatewayUrl: string, projectPath: string, statusTracker?: StatusTracker);
|
|
14
|
+
constructor(globalConfig: GlobalConfig, agentConfig: AgentConfig, logger: Logger, registerContainer: (secret: string, containerName: string) => void, gatewayUrl: string, projectPath: string, image: string, statusTracker?: StatusTracker);
|
|
14
15
|
get isRunning(): boolean;
|
|
15
16
|
private forwardLogLine;
|
|
16
17
|
private streamContainerLogs;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"container-runner.d.ts","sourceRoot":"","sources":["../../src/agents/container-runner.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AACrE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"container-runner.d.ts","sourceRoot":"","sources":["../../src/agents/container-runner.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AACrE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAOlD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAE9D,qBAAa,oBAAoB;IAC/B,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,YAAY,CAAe;IACnC,OAAO,CAAC,WAAW,CAAc;IACjC,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,iBAAiB,CAAkD;IAC3E,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,aAAa,CAAC,CAAgB;gBAGpC,YAAY,EAAE,YAAY,EAC1B,WAAW,EAAE,WAAW,EACxB,MAAM,EAAE,MAAM,EACd,iBAAiB,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,KAAK,IAAI,EAClE,UAAU,EAAE,MAAM,EAClB,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,MAAM,EACb,aAAa,CAAC,EAAE,aAAa;IAY/B,IAAI,SAAS,IAAI,OAAO,CAEvB;IAED,OAAO,CAAC,cAAc;IAqDtB,OAAO,CAAC,mBAAmB;IAkC3B,OAAO,CAAC,gBAAgB;IA6BlB,GAAG,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CA0GzC"}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { spawn } from "child_process";
|
|
2
|
-
import { mkdtempSync,
|
|
2
|
+
import { mkdtempSync, copyFileSync, rmSync, mkdirSync, readdirSync, existsSync } from "fs";
|
|
3
3
|
import { join, resolve } from "path";
|
|
4
4
|
import { tmpdir } from "os";
|
|
5
5
|
import { randomUUID } from "crypto";
|
|
6
6
|
import { readFileSync } from "fs";
|
|
7
7
|
import { CREDENTIALS_DIR } from "../shared/paths.js";
|
|
8
|
+
import { parseCredentialRef } from "../shared/credentials.js";
|
|
8
9
|
import { launchContainer, removeContainer, } from "../docker/container.js";
|
|
9
10
|
export class ContainerAgentRunner {
|
|
10
11
|
_running = false;
|
|
@@ -14,14 +15,16 @@ export class ContainerAgentRunner {
|
|
|
14
15
|
registerContainer;
|
|
15
16
|
gatewayUrl;
|
|
16
17
|
projectPath;
|
|
18
|
+
image;
|
|
17
19
|
statusTracker;
|
|
18
|
-
constructor(globalConfig, agentConfig, logger, registerContainer, gatewayUrl, projectPath, statusTracker) {
|
|
20
|
+
constructor(globalConfig, agentConfig, logger, registerContainer, gatewayUrl, projectPath, image, statusTracker) {
|
|
19
21
|
this.globalConfig = globalConfig;
|
|
20
22
|
this.agentConfig = agentConfig;
|
|
21
23
|
this.logger = logger;
|
|
22
24
|
this.registerContainer = registerContainer;
|
|
23
25
|
this.gatewayUrl = gatewayUrl;
|
|
24
26
|
this.projectPath = projectPath;
|
|
27
|
+
this.image = image;
|
|
25
28
|
this.statusTracker = statusTracker;
|
|
26
29
|
}
|
|
27
30
|
get isRunning() {
|
|
@@ -49,7 +52,20 @@ export class ContainerAgentRunner {
|
|
|
49
52
|
}
|
|
50
53
|
// Forward info-level log events to status tracker
|
|
51
54
|
if (level !== "debug") {
|
|
52
|
-
this.statusTracker?.addLogLine(this.agentConfig.name, msg);
|
|
55
|
+
this.statusTracker?.addLogLine(this.agentConfig.name, level === "error" ? `ERROR: ${msg}` : msg);
|
|
56
|
+
}
|
|
57
|
+
// Surface tool errors to status tracker for TUI display
|
|
58
|
+
if (level === "error" && msg === "tool error" && data.result) {
|
|
59
|
+
let errorMsg = String(data.result);
|
|
60
|
+
try {
|
|
61
|
+
const parsed = JSON.parse(data.result);
|
|
62
|
+
if (parsed?.content?.[0]?.text) {
|
|
63
|
+
errorMsg = parsed.content[0].text;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
catch { /* use raw string */ }
|
|
67
|
+
const cmdPrefix = data.cmd ? `$ ${String(data.cmd).slice(0, 80)} — ` : "";
|
|
68
|
+
this.statusTracker?.setAgentError(this.agentConfig.name, `${cmdPrefix}${errorMsg.slice(0, 200)}`);
|
|
53
69
|
}
|
|
54
70
|
return;
|
|
55
71
|
}
|
|
@@ -130,32 +146,44 @@ export class ContainerAgentRunner {
|
|
|
130
146
|
this.statusTracker?.setAgentState(this.agentConfig.name, "running");
|
|
131
147
|
this.logger.info(`Starting ${this.agentConfig.name} container run`);
|
|
132
148
|
const runStartTime = Date.now();
|
|
149
|
+
let runError;
|
|
133
150
|
const shutdownSecret = randomUUID();
|
|
134
151
|
const stagingDir = mkdtempSync(join(tmpdir(), "al-creds-"));
|
|
135
152
|
let containerName;
|
|
136
153
|
let logStream;
|
|
137
154
|
try {
|
|
138
|
-
const image = this.globalConfig.docker?.image || "al-agent:latest";
|
|
139
155
|
const timeout = this.globalConfig.docker?.timeout || 3600;
|
|
140
|
-
//
|
|
141
|
-
//
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
156
|
+
// Copy credentials into staging dir with directory-based layout
|
|
157
|
+
// Layout: stagingDir/<type>/<instance>/<field>
|
|
158
|
+
// Always include anthropic_key — the container entry reads it directly
|
|
159
|
+
const credRefs = new Set(this.agentConfig.credentials);
|
|
160
|
+
if (this.agentConfig.model.authType !== "pi_auth") {
|
|
161
|
+
credRefs.add("anthropic_key:default");
|
|
162
|
+
}
|
|
163
|
+
for (const credRef of credRefs) {
|
|
164
|
+
const { type, instance } = parseCredentialRef(credRef);
|
|
165
|
+
const srcDir = resolve(CREDENTIALS_DIR, type, instance);
|
|
166
|
+
const dstDir = join(stagingDir, type, instance);
|
|
167
|
+
if (!existsSync(srcDir)) {
|
|
168
|
+
this.logger.warn({ cred: credRef }, "credential directory not found");
|
|
169
|
+
continue;
|
|
148
170
|
}
|
|
149
|
-
|
|
150
|
-
|
|
171
|
+
mkdirSync(dstDir, { recursive: true });
|
|
172
|
+
for (const file of readdirSync(srcDir)) {
|
|
173
|
+
try {
|
|
174
|
+
copyFileSync(resolve(srcDir, file), join(dstDir, file));
|
|
175
|
+
}
|
|
176
|
+
catch (err) {
|
|
177
|
+
this.logger.warn({ cred: credRef, file, err: err.message }, "failed to copy credential file");
|
|
178
|
+
}
|
|
151
179
|
}
|
|
152
180
|
}
|
|
153
|
-
// Read
|
|
154
|
-
const agentsMdPath = resolve(this.projectPath, this.agentConfig.name, "
|
|
181
|
+
// Read PLAYBOOK.md from disk and include it in the serialized config
|
|
182
|
+
const agentsMdPath = resolve(this.projectPath, this.agentConfig.name, "PLAYBOOK.md");
|
|
155
183
|
const agentsMd = readFileSync(agentsMdPath, "utf-8");
|
|
156
184
|
const configWithMd = { ...this.agentConfig, _agentsMd: agentsMd };
|
|
157
185
|
containerName = launchContainer({
|
|
158
|
-
image,
|
|
186
|
+
image: this.image,
|
|
159
187
|
agentName: this.agentConfig.name,
|
|
160
188
|
agentConfig: JSON.stringify(configWithMd),
|
|
161
189
|
shutdownSecret,
|
|
@@ -180,6 +208,7 @@ export class ContainerAgentRunner {
|
|
|
180
208
|
logStream = undefined;
|
|
181
209
|
if (exitCode !== 0) {
|
|
182
210
|
this.logger.error({ exitCode, elapsed: `${elapsed}s` }, "container exited with error");
|
|
211
|
+
runError = `Container exited with code ${exitCode}`;
|
|
183
212
|
}
|
|
184
213
|
else {
|
|
185
214
|
this.logger.info({ exitCode, elapsed: `${elapsed}s` }, "container finished");
|
|
@@ -187,6 +216,7 @@ export class ContainerAgentRunner {
|
|
|
187
216
|
}
|
|
188
217
|
catch (err) {
|
|
189
218
|
this.logger.error({ err }, `${this.agentConfig.name} container run failed`);
|
|
219
|
+
runError = String(err?.message || err).slice(0, 200);
|
|
190
220
|
}
|
|
191
221
|
finally {
|
|
192
222
|
if (logStream)
|
|
@@ -200,7 +230,7 @@ export class ContainerAgentRunner {
|
|
|
200
230
|
removeContainer(containerName);
|
|
201
231
|
}
|
|
202
232
|
const elapsed = Date.now() - runStartTime;
|
|
203
|
-
this.statusTracker?.completeRun(this.agentConfig.name, elapsed);
|
|
233
|
+
this.statusTracker?.completeRun(this.agentConfig.name, elapsed, runError);
|
|
204
234
|
this._running = false;
|
|
205
235
|
}
|
|
206
236
|
}
|