@neotx/cli 0.1.0-alpha.2 → 0.1.0-alpha.4
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 +381 -0
- package/dist/{agents-Y6LREFXP.js → agents-PH3P7G7E.js} +2 -2
- package/dist/{chunk-CP54H7WA.js → chunk-3ZP3BQXB.js} +6 -11
- package/dist/chunk-3ZP3BQXB.js.map +1 -0
- package/dist/{chunk-TNJOG54I.js → chunk-F622JUDY.js} +6 -2
- package/dist/{chunk-TNJOG54I.js.map → chunk-F622JUDY.js.map} +1 -1
- package/dist/{cost-DNGKT4UC.js → cost-OQGFNBBG.js} +3 -8
- package/dist/cost-OQGFNBBG.js.map +1 -0
- package/dist/daemon/supervisor-worker.js +7 -1
- package/dist/daemon/supervisor-worker.js.map +1 -1
- package/dist/daemon/worker.js +25 -0
- package/dist/daemon/worker.js.map +1 -1
- package/dist/doctor-ZBO73UID.js +337 -0
- package/dist/doctor-ZBO73UID.js.map +1 -0
- package/dist/index.js +12 -9
- package/dist/index.js.map +1 -1
- package/dist/{init-YNSPTCA3.js → init-UYS6KS5U.js} +4 -20
- package/dist/init-UYS6KS5U.js.map +1 -0
- package/dist/log-PTHLI7ZN.js +141 -0
- package/dist/log-PTHLI7ZN.js.map +1 -0
- package/dist/{mcp-GH6CCW7A.js → mcp-XHZND5A4.js} +6 -1
- package/dist/mcp-XHZND5A4.js.map +1 -0
- package/dist/memory-6R22DFS7.js +292 -0
- package/dist/memory-6R22DFS7.js.map +1 -0
- package/dist/{run-KIU2ZE72.js → run-GJLDWPUE.js} +32 -9
- package/dist/run-GJLDWPUE.js.map +1 -0
- package/dist/{runs-CHA2JM5K.js → runs-LOYOWU55.js} +9 -10
- package/dist/runs-LOYOWU55.js.map +1 -0
- package/dist/{supervise-KIB2EYY4.js → supervise-LVCGVYA4.js} +33 -28
- package/dist/supervise-LVCGVYA4.js.map +1 -0
- package/dist/{tui-QS3RPHKH.js → tui-6USVDV75.js} +100 -33
- package/dist/tui-6USVDV75.js.map +1 -0
- package/dist/version-XVOAMGDD.js +26 -0
- package/dist/version-XVOAMGDD.js.map +1 -0
- package/package.json +22 -4
- package/dist/chunk-CP54H7WA.js.map +0 -1
- package/dist/cost-DNGKT4UC.js.map +0 -1
- package/dist/doctor-GC4NH7H6.js +0 -173
- package/dist/doctor-GC4NH7H6.js.map +0 -1
- package/dist/init-YNSPTCA3.js.map +0 -1
- package/dist/mcp-GH6CCW7A.js.map +0 -1
- package/dist/run-KIU2ZE72.js.map +0 -1
- package/dist/runs-CHA2JM5K.js.map +0 -1
- package/dist/supervise-KIB2EYY4.js.map +0 -1
- package/dist/tui-QS3RPHKH.js.map +0 -1
- /package/dist/{agents-Y6LREFXP.js.map → agents-PH3P7G7E.js.map} +0 -0
package/README.md
ADDED
|
@@ -0,0 +1,381 @@
|
|
|
1
|
+
# @neotx/cli
|
|
2
|
+
|
|
3
|
+
The `neo` command-line interface for orchestrating autonomous developer agents. This thin wrapper over `@neotx/core` provides a user-friendly CLI for dispatching agents, monitoring runs, managing costs, and running the supervisor daemon.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install -g neotx
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Or with the scoped package name:
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npm install -g @neotx/cli
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Requires Node.js 22 or later.
|
|
18
|
+
|
|
19
|
+
## Quick Start
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
# Initialize a repository for neo
|
|
23
|
+
neo init
|
|
24
|
+
|
|
25
|
+
# Check your environment
|
|
26
|
+
neo doctor
|
|
27
|
+
|
|
28
|
+
# Run an agent
|
|
29
|
+
neo run developer --prompt "Add input validation to the login form"
|
|
30
|
+
|
|
31
|
+
# Watch a detached run
|
|
32
|
+
neo logs -f --run <run-id>
|
|
33
|
+
|
|
34
|
+
# Start the supervisor daemon
|
|
35
|
+
neo supervise
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Commands
|
|
39
|
+
|
|
40
|
+
### `neo init`
|
|
41
|
+
|
|
42
|
+
Initialize a `.neo/` project directory and register the repo in your global config.
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
neo init
|
|
46
|
+
neo init --force # Re-register even if already initialized
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Creates:
|
|
50
|
+
- `.neo/agents/` directory for project-local agent definitions
|
|
51
|
+
- Registers the repo in global config
|
|
52
|
+
- Registers the repo in `~/.neo/config.yml`
|
|
53
|
+
|
|
54
|
+
### `neo run <agent>`
|
|
55
|
+
|
|
56
|
+
Dispatch an agent to execute a task in an isolated clone.
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
neo run developer --prompt "Implement user authentication"
|
|
60
|
+
neo run architect --prompt "Design the caching layer" --repo /path/to/repo
|
|
61
|
+
neo run reviewer-quality --prompt "Review the auth changes" --priority high
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
**Arguments:**
|
|
65
|
+
- `<agent>` - Agent name (e.g., `developer`, `architect`, `reviewer-quality`)
|
|
66
|
+
|
|
67
|
+
**Options:**
|
|
68
|
+
| Flag | Description |
|
|
69
|
+
|------|-------------|
|
|
70
|
+
| `--prompt` | Task description for the agent (required) |
|
|
71
|
+
| `--repo` | Target repository path (default: `.`) |
|
|
72
|
+
| `--priority` | Priority level: `critical`, `high`, `medium`, `low` |
|
|
73
|
+
| `--meta` | Metadata as JSON string |
|
|
74
|
+
| `--output json` | Output as JSON |
|
|
75
|
+
| `-d, --detach` | Run in background (default: `true`) |
|
|
76
|
+
| `-s, --sync` | Run in foreground (blocking) |
|
|
77
|
+
|
|
78
|
+
By default, runs are **detached** — the command returns immediately with a run ID while the agent works in the background. Use `--sync` to run in the foreground.
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
# Detached (default) - returns immediately
|
|
82
|
+
neo run developer --prompt "Fix the login bug"
|
|
83
|
+
# Output: Detached run started: abc123...
|
|
84
|
+
# Logs: neo logs -f abc123
|
|
85
|
+
|
|
86
|
+
# Foreground - blocks until complete
|
|
87
|
+
neo run developer --prompt "Fix the login bug" --sync
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### `neo runs [run-id]`
|
|
91
|
+
|
|
92
|
+
List runs or show details of a specific run.
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
neo runs # List recent runs
|
|
96
|
+
neo runs abc123 # Show details for run abc123 (prefix match works)
|
|
97
|
+
neo runs --all # Show runs from all repos
|
|
98
|
+
neo runs --repo my-project # Filter by repo
|
|
99
|
+
neo runs --last 10 # Show only the last 10 runs
|
|
100
|
+
neo runs --status running # Filter by status
|
|
101
|
+
neo runs --output json # Output as JSON
|
|
102
|
+
neo runs --short # Compact output (useful for scripts)
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
**Options:**
|
|
106
|
+
| Flag | Description |
|
|
107
|
+
|------|-------------|
|
|
108
|
+
| `--all` | Show runs from all repos |
|
|
109
|
+
| `--repo` | Filter by repo name or path |
|
|
110
|
+
| `--last` | Show only the last N runs |
|
|
111
|
+
| `--status` | Filter: `completed`, `failed`, `running` |
|
|
112
|
+
| `--short` | Compact output |
|
|
113
|
+
| `--output json` | Output as JSON |
|
|
114
|
+
|
|
115
|
+
### `neo logs`
|
|
116
|
+
|
|
117
|
+
Show event logs from journals (session starts, completions, failures, costs).
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
neo logs # Show last 20 events
|
|
121
|
+
neo logs --last 50 # Show last 50 events
|
|
122
|
+
neo logs --type session:complete # Filter by event type
|
|
123
|
+
neo logs --run abc123 # Filter by run ID (prefix match)
|
|
124
|
+
neo logs -f --run abc123 # Follow a detached run's log in real time
|
|
125
|
+
neo logs --output json # Output as JSON
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
**Options:**
|
|
129
|
+
| Flag | Description |
|
|
130
|
+
|------|-------------|
|
|
131
|
+
| `--last` | Number of events to show (default: 20) |
|
|
132
|
+
| `--type` | Filter: `session:start`, `session:complete`, `session:fail`, `cost:update`, `budget:alert` |
|
|
133
|
+
| `--run` | Filter by run ID (prefix match) |
|
|
134
|
+
| `-f, --follow` | Follow a detached run log in real time (requires `--run`) |
|
|
135
|
+
| `--short` | Compact output |
|
|
136
|
+
| `--output json` | Output as JSON |
|
|
137
|
+
|
|
138
|
+
### `neo log <type> <message>`
|
|
139
|
+
|
|
140
|
+
Log a structured progress report to the supervisor activity log.
|
|
141
|
+
|
|
142
|
+
```bash
|
|
143
|
+
neo log decision "Chose JWT over sessions for auth"
|
|
144
|
+
neo log action "Created migration for users table"
|
|
145
|
+
neo log blocker "Tests failing due to missing env var"
|
|
146
|
+
neo log progress "Completed 3 of 5 endpoints"
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
**Arguments:**
|
|
150
|
+
- `<type>` - Report type: `decision`, `action`, `blocker`, `progress`
|
|
151
|
+
- `<message>` - Message to log
|
|
152
|
+
|
|
153
|
+
**Options:**
|
|
154
|
+
| Flag | Description |
|
|
155
|
+
|------|-------------|
|
|
156
|
+
| `--name` | Supervisor instance name (default: `supervisor`) |
|
|
157
|
+
|
|
158
|
+
### `neo cost`
|
|
159
|
+
|
|
160
|
+
Show cost breakdown from journals (today, by agent, by run).
|
|
161
|
+
|
|
162
|
+
```bash
|
|
163
|
+
neo cost # Show costs for current repo
|
|
164
|
+
neo cost --all # Show costs from all repos
|
|
165
|
+
neo cost --repo my-app # Filter by repo
|
|
166
|
+
neo cost --short # Compact output
|
|
167
|
+
neo cost --output json # Output as JSON
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
**Options:**
|
|
171
|
+
| Flag | Description |
|
|
172
|
+
|------|-------------|
|
|
173
|
+
| `--all` | Show costs from all repos |
|
|
174
|
+
| `--repo` | Filter by repo name or path |
|
|
175
|
+
| `--short` | Compact output |
|
|
176
|
+
| `--output json` | Output as JSON |
|
|
177
|
+
|
|
178
|
+
### `neo agents`
|
|
179
|
+
|
|
180
|
+
List available agents (built-in and custom from `.neo/agents/`).
|
|
181
|
+
|
|
182
|
+
```bash
|
|
183
|
+
neo agents # List all agents
|
|
184
|
+
neo agents --output json
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
Shows agent name, model, sandbox mode, and source (built-in or custom).
|
|
188
|
+
|
|
189
|
+
### `neo repos [action] [target]`
|
|
190
|
+
|
|
191
|
+
Manage registered repositories.
|
|
192
|
+
|
|
193
|
+
```bash
|
|
194
|
+
neo repos # List registered repos
|
|
195
|
+
neo repos add /path/to/repo # Add a repo
|
|
196
|
+
neo repos add . --name my-project # Add with custom name
|
|
197
|
+
neo repos add . --branch develop # Add with specific default branch
|
|
198
|
+
neo repos remove my-project # Remove by name or path
|
|
199
|
+
neo repos --output json # Output as JSON
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
**Actions:**
|
|
203
|
+
- `add` - Register a repository
|
|
204
|
+
- `remove` - Unregister a repository
|
|
205
|
+
- (omit) - List all registered repos
|
|
206
|
+
|
|
207
|
+
**Options for `add`:**
|
|
208
|
+
| Flag | Description |
|
|
209
|
+
|------|-------------|
|
|
210
|
+
| `--name` | Custom name for the repo |
|
|
211
|
+
| `--branch` | Default branch (auto-detected if omitted) |
|
|
212
|
+
|
|
213
|
+
### `neo supervise`
|
|
214
|
+
|
|
215
|
+
Manage the autonomous supervisor daemon.
|
|
216
|
+
|
|
217
|
+
```bash
|
|
218
|
+
neo supervise # Start daemon + open TUI (default)
|
|
219
|
+
neo supervise -d # Start daemon headless (no TUI)
|
|
220
|
+
neo supervise --status # Show supervisor status
|
|
221
|
+
neo supervise --kill # Stop the running supervisor
|
|
222
|
+
neo supervise --message "Focus on the auth module" # Send a message
|
|
223
|
+
neo supervise --name prod # Use a named instance
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
**Options:**
|
|
227
|
+
| Flag | Description |
|
|
228
|
+
|------|-------------|
|
|
229
|
+
| `--name` | Supervisor instance name (default: `supervisor`) |
|
|
230
|
+
| `-d, --detach` | Start daemon without opening the TUI |
|
|
231
|
+
| `--status` | Show supervisor status |
|
|
232
|
+
| `--kill` | Stop the running supervisor |
|
|
233
|
+
| `--attach` | Open the TUI (same as default, explicit flag) |
|
|
234
|
+
| `--message` | Send a message to the supervisor inbox |
|
|
235
|
+
|
|
236
|
+
By default, `neo supervise` starts the daemon (if not running) and opens the TUI. If the daemon is already running, it opens the TUI directly. Use `-d` for headless mode.
|
|
237
|
+
|
|
238
|
+
#### Supervisor TUI
|
|
239
|
+
|
|
240
|
+
The TUI provides a live dashboard for monitoring the supervisor:
|
|
241
|
+
|
|
242
|
+
- **Header**: PID, port, heartbeat count, uptime, live status
|
|
243
|
+
- **Budget panel**: Real-time cost tracking with progress bar and sparkline
|
|
244
|
+
- **Activity feed**: Live stream of supervisor actions, decisions, and events
|
|
245
|
+
- **Input**: Send messages to the supervisor
|
|
246
|
+
|
|
247
|
+
**Controls:**
|
|
248
|
+
- `Enter` - Send message
|
|
249
|
+
- `Esc` - Quit TUI (daemon keeps running)
|
|
250
|
+
|
|
251
|
+
### `neo mcp <action>`
|
|
252
|
+
|
|
253
|
+
Manage MCP (Model Context Protocol) server integrations.
|
|
254
|
+
|
|
255
|
+
```bash
|
|
256
|
+
neo mcp list # List configured MCP servers
|
|
257
|
+
neo mcp add linear # Add using a preset
|
|
258
|
+
neo mcp add github # Add GitHub integration
|
|
259
|
+
neo mcp add custom --type stdio --command "node" --serverArgs "server.js"
|
|
260
|
+
neo mcp add api --type http --url "https://api.example.com/mcp"
|
|
261
|
+
neo mcp remove linear # Remove an MCP server
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
**Available presets:**
|
|
265
|
+
- `linear` - Linear issue tracking (requires `LINEAR_API_KEY`)
|
|
266
|
+
- `notion` - Notion workspace (requires `NOTION_TOKEN`)
|
|
267
|
+
- `github` - GitHub repositories (requires `GITHUB_TOKEN`)
|
|
268
|
+
- `jira` - Jira projects (requires `JIRA_API_TOKEN`, `JIRA_URL`)
|
|
269
|
+
- `slack` - Slack workspace (requires `SLACK_BOT_TOKEN`)
|
|
270
|
+
|
|
271
|
+
**Custom server options:**
|
|
272
|
+
| Flag | Description |
|
|
273
|
+
|------|-------------|
|
|
274
|
+
| `--type` | Server type: `stdio` or `http` |
|
|
275
|
+
| `--command` | Command for stdio servers |
|
|
276
|
+
| `--serverArgs` | Comma-separated args for stdio servers |
|
|
277
|
+
| `--url` | URL for http servers |
|
|
278
|
+
|
|
279
|
+
### `neo doctor`
|
|
280
|
+
|
|
281
|
+
Check environment prerequisites and configuration.
|
|
282
|
+
|
|
283
|
+
```bash
|
|
284
|
+
neo doctor
|
|
285
|
+
neo doctor --output json
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
Checks:
|
|
289
|
+
- Node.js version (requires >= 22)
|
|
290
|
+
- Git version (requires >= 2.20)
|
|
291
|
+
- Global config validity
|
|
292
|
+
- Repo registration status
|
|
293
|
+
- Claude CLI installation
|
|
294
|
+
- Agent definitions
|
|
295
|
+
- Journal directory permissions
|
|
296
|
+
|
|
297
|
+
## Detached Runs
|
|
298
|
+
|
|
299
|
+
By default, `neo run` executes agents in **detached mode**:
|
|
300
|
+
|
|
301
|
+
```bash
|
|
302
|
+
neo run developer --prompt "Add tests for the API"
|
|
303
|
+
# ✓ Detached run started: eeb76521-e806-46cd-8451-87490cfe7281
|
|
304
|
+
# PID: 12345
|
|
305
|
+
# Logs: neo logs -f eeb76521
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
The agent runs in a background process while you continue working. To monitor:
|
|
309
|
+
|
|
310
|
+
```bash
|
|
311
|
+
# Follow logs in real time
|
|
312
|
+
neo logs -f --run eeb76521
|
|
313
|
+
|
|
314
|
+
# Check run status
|
|
315
|
+
neo runs eeb76521
|
|
316
|
+
|
|
317
|
+
# List all running
|
|
318
|
+
neo runs --status running
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
For blocking execution, use `--sync`:
|
|
322
|
+
|
|
323
|
+
```bash
|
|
324
|
+
neo run developer --prompt "Quick fix" --sync
|
|
325
|
+
# Blocks until complete, shows progress inline
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
## JSON Output
|
|
329
|
+
|
|
330
|
+
All commands support `--output json` for scripting and automation:
|
|
331
|
+
|
|
332
|
+
```bash
|
|
333
|
+
neo runs --output json | jq '.[] | select(.status == "failed")'
|
|
334
|
+
neo cost --output json | jq '.today.total'
|
|
335
|
+
neo agents --output json | jq '.[].name'
|
|
336
|
+
neo doctor --output json | jq '.checks[] | select(.status == "fail")'
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
## Global Configuration
|
|
340
|
+
|
|
341
|
+
Neo stores global configuration in `~/.neo/config.yml`:
|
|
342
|
+
|
|
343
|
+
```yaml
|
|
344
|
+
budget:
|
|
345
|
+
dailyCapUsd: 50
|
|
346
|
+
|
|
347
|
+
repos:
|
|
348
|
+
- path: /Users/you/projects/my-app
|
|
349
|
+
defaultBranch: main
|
|
350
|
+
|
|
351
|
+
supervisor:
|
|
352
|
+
port: 7420
|
|
353
|
+
idleIntervalMs: 60000
|
|
354
|
+
idleSkipMax: 5
|
|
355
|
+
|
|
356
|
+
mcpServers:
|
|
357
|
+
linear:
|
|
358
|
+
type: stdio
|
|
359
|
+
command: npx
|
|
360
|
+
args: ["-y", "@anthropic/linear-mcp-server"]
|
|
361
|
+
env:
|
|
362
|
+
LINEAR_API_KEY: "${LINEAR_API_KEY}"
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
Run `neo init` or `neo repos add` to register repositories. The config is auto-created with defaults if missing.
|
|
366
|
+
|
|
367
|
+
## Project-Local Agents
|
|
368
|
+
|
|
369
|
+
Define custom agents in `.neo/agents/` within your repository:
|
|
370
|
+
|
|
371
|
+
```
|
|
372
|
+
.neo/
|
|
373
|
+
agents/
|
|
374
|
+
my-custom-agent.yml
|
|
375
|
+
```
|
|
376
|
+
|
|
377
|
+
These are loaded alongside built-in agents and can be used with `neo run my-custom-agent`.
|
|
378
|
+
|
|
379
|
+
## License
|
|
380
|
+
|
|
381
|
+
MIT
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
resolveAgentsDir
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-F622JUDY.js";
|
|
4
4
|
import {
|
|
5
5
|
printError,
|
|
6
6
|
printJson,
|
|
@@ -55,4 +55,4 @@ var agents_default = defineCommand({
|
|
|
55
55
|
export {
|
|
56
56
|
agents_default as default
|
|
57
57
|
};
|
|
58
|
-
//# sourceMappingURL=agents-
|
|
58
|
+
//# sourceMappingURL=agents-PH3P7G7E.js.map
|
|
@@ -4,23 +4,18 @@ import { readdir, readFile } from "fs/promises";
|
|
|
4
4
|
import path from "path";
|
|
5
5
|
import { getRunsDir, listReposFromGlobalConfig, toRepoSlug } from "@neotx/core";
|
|
6
6
|
async function resolveRepoFilter(args) {
|
|
7
|
-
if (args.all) return { mode: "all" };
|
|
8
7
|
if (args.repo) {
|
|
9
8
|
const repo = args.repo;
|
|
10
|
-
const
|
|
11
|
-
const
|
|
9
|
+
const repos = await listReposFromGlobalConfig();
|
|
10
|
+
const match = repos.find(
|
|
12
11
|
(r) => toRepoSlug(r) === repo || path.resolve(r.path) === path.resolve(repo)
|
|
13
12
|
);
|
|
14
|
-
if (
|
|
15
|
-
return { mode: "named", repoSlug: toRepoSlug(
|
|
13
|
+
if (match) {
|
|
14
|
+
return { mode: "named", repoSlug: toRepoSlug(match), repoPath: match.path };
|
|
16
15
|
}
|
|
17
16
|
return { mode: "named", repoSlug: toRepoSlug({ path: repo }), repoPath: repo };
|
|
18
17
|
}
|
|
19
|
-
|
|
20
|
-
const repos = await listReposFromGlobalConfig();
|
|
21
|
-
const match = repos.find((r) => path.resolve(r.path) === cwd);
|
|
22
|
-
const slug = match ? toRepoSlug(match) : toRepoSlug({ path: cwd });
|
|
23
|
-
return { mode: "cwd", repoSlug: slug, repoPath: cwd };
|
|
18
|
+
return { mode: "all" };
|
|
24
19
|
}
|
|
25
20
|
async function loadRunsFiltered(filter) {
|
|
26
21
|
const runsDir = getRunsDir();
|
|
@@ -82,4 +77,4 @@ export {
|
|
|
82
77
|
resolveRepoFilter,
|
|
83
78
|
loadRunsFiltered
|
|
84
79
|
};
|
|
85
|
-
//# sourceMappingURL=chunk-
|
|
80
|
+
//# sourceMappingURL=chunk-3ZP3BQXB.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/repo-filter.ts"],"sourcesContent":["import { existsSync } from \"node:fs\";\nimport { readdir, readFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport type { PersistedRun } from \"@neotx/core\";\nimport { getRunsDir, listReposFromGlobalConfig, toRepoSlug } from \"@neotx/core\";\n\nexport interface RepoFilter {\n mode: \"all\" | \"named\";\n repoSlug?: string;\n repoPath?: string;\n}\n\n/**\n * Resolve which repos to query based on --repo flag.\n * Default: show all repos (global view).\n */\nexport async function resolveRepoFilter(args: { repo?: string | undefined }): Promise<RepoFilter> {\n if (args.repo) {\n const repo = args.repo;\n // Could be a name/slug or a path\n const repos = await listReposFromGlobalConfig();\n const match = repos.find(\n (r) => toRepoSlug(r) === repo || path.resolve(r.path) === path.resolve(repo),\n );\n if (match) {\n return { mode: \"named\", repoSlug: toRepoSlug(match), repoPath: match.path };\n }\n // Treat as path, derive slug\n return { mode: \"named\", repoSlug: toRepoSlug({ path: repo }), repoPath: repo };\n }\n\n // Default: show all runs globally\n // Users can filter by repo explicitly with --repo\n return { mode: \"all\" };\n}\n\n/**\n * Load persisted runs, filtered by RepoFilter.\n */\nexport async function loadRunsFiltered(filter: RepoFilter): Promise<PersistedRun[]> {\n const runsDir = getRunsDir();\n if (!existsSync(runsDir)) return [];\n\n const runs: PersistedRun[] = [];\n\n if (filter.mode === \"all\") {\n // Scan all slug subdirs + legacy flat files\n const entries = await readdir(runsDir, { withFileTypes: true });\n for (const entry of entries) {\n if (entry.isDirectory()) {\n await loadRunsFromDir(path.join(runsDir, entry.name), runs);\n } else if (entry.name.endsWith(\".json\")) {\n await loadRunFile(path.join(runsDir, entry.name), runs);\n }\n }\n } else {\n // Specific slug dir\n const slugDir = path.join(runsDir, filter.repoSlug ?? \"unknown\");\n await loadRunsFromDir(slugDir, runs);\n // Also check legacy flat files matching this repo\n await loadLegacyRuns(runsDir, filter.repoPath, runs);\n }\n\n runs.sort((a, b) => b.updatedAt.localeCompare(a.updatedAt));\n return runs;\n}\n\nasync function loadRunsFromDir(dir: string, runs: PersistedRun[]): Promise<void> {\n if (!existsSync(dir)) return;\n const files = await readdir(dir);\n for (const file of files) {\n if (!file.endsWith(\".json\")) continue;\n await loadRunFile(path.join(dir, file), runs);\n }\n}\n\nasync function loadRunFile(filePath: string, runs: PersistedRun[]): Promise<void> {\n try {\n const content = await readFile(filePath, \"utf-8\");\n runs.push(JSON.parse(content) as PersistedRun);\n } catch {\n // Skip corrupt files\n }\n}\n\nasync function loadLegacyRuns(\n runsDir: string,\n repoPath: string | undefined,\n runs: PersistedRun[],\n): Promise<void> {\n if (!repoPath) return;\n const resolvedRepo = path.resolve(repoPath);\n\n try {\n const entries = await readdir(runsDir, { withFileTypes: true });\n for (const entry of entries) {\n if (!entry.isFile() || !entry.name.endsWith(\".json\")) continue;\n const filePath = path.join(runsDir, entry.name);\n const content = await readFile(filePath, \"utf-8\");\n const run = JSON.parse(content) as PersistedRun;\n if (path.resolve(run.repo) === resolvedRepo) {\n // Avoid duplicates\n if (!runs.some((r) => r.runId === run.runId)) {\n runs.push(run);\n }\n }\n }\n } catch {\n // Non-critical\n }\n}\n"],"mappings":";AAAA,SAAS,kBAAkB;AAC3B,SAAS,SAAS,gBAAgB;AAClC,OAAO,UAAU;AAEjB,SAAS,YAAY,2BAA2B,kBAAkB;AAYlE,eAAsB,kBAAkB,MAA0D;AAChG,MAAI,KAAK,MAAM;AACb,UAAM,OAAO,KAAK;AAElB,UAAM,QAAQ,MAAM,0BAA0B;AAC9C,UAAM,QAAQ,MAAM;AAAA,MAClB,CAAC,MAAM,WAAW,CAAC,MAAM,QAAQ,KAAK,QAAQ,EAAE,IAAI,MAAM,KAAK,QAAQ,IAAI;AAAA,IAC7E;AACA,QAAI,OAAO;AACT,aAAO,EAAE,MAAM,SAAS,UAAU,WAAW,KAAK,GAAG,UAAU,MAAM,KAAK;AAAA,IAC5E;AAEA,WAAO,EAAE,MAAM,SAAS,UAAU,WAAW,EAAE,MAAM,KAAK,CAAC,GAAG,UAAU,KAAK;AAAA,EAC/E;AAIA,SAAO,EAAE,MAAM,MAAM;AACvB;AAKA,eAAsB,iBAAiB,QAA6C;AAClF,QAAM,UAAU,WAAW;AAC3B,MAAI,CAAC,WAAW,OAAO,EAAG,QAAO,CAAC;AAElC,QAAM,OAAuB,CAAC;AAE9B,MAAI,OAAO,SAAS,OAAO;AAEzB,UAAM,UAAU,MAAM,QAAQ,SAAS,EAAE,eAAe,KAAK,CAAC;AAC9D,eAAW,SAAS,SAAS;AAC3B,UAAI,MAAM,YAAY,GAAG;AACvB,cAAM,gBAAgB,KAAK,KAAK,SAAS,MAAM,IAAI,GAAG,IAAI;AAAA,MAC5D,WAAW,MAAM,KAAK,SAAS,OAAO,GAAG;AACvC,cAAM,YAAY,KAAK,KAAK,SAAS,MAAM,IAAI,GAAG,IAAI;AAAA,MACxD;AAAA,IACF;AAAA,EACF,OAAO;AAEL,UAAM,UAAU,KAAK,KAAK,SAAS,OAAO,YAAY,SAAS;AAC/D,UAAM,gBAAgB,SAAS,IAAI;AAEnC,UAAM,eAAe,SAAS,OAAO,UAAU,IAAI;AAAA,EACrD;AAEA,OAAK,KAAK,CAAC,GAAG,MAAM,EAAE,UAAU,cAAc,EAAE,SAAS,CAAC;AAC1D,SAAO;AACT;AAEA,eAAe,gBAAgB,KAAa,MAAqC;AAC/E,MAAI,CAAC,WAAW,GAAG,EAAG;AACtB,QAAM,QAAQ,MAAM,QAAQ,GAAG;AAC/B,aAAW,QAAQ,OAAO;AACxB,QAAI,CAAC,KAAK,SAAS,OAAO,EAAG;AAC7B,UAAM,YAAY,KAAK,KAAK,KAAK,IAAI,GAAG,IAAI;AAAA,EAC9C;AACF;AAEA,eAAe,YAAY,UAAkB,MAAqC;AAChF,MAAI;AACF,UAAM,UAAU,MAAM,SAAS,UAAU,OAAO;AAChD,SAAK,KAAK,KAAK,MAAM,OAAO,CAAiB;AAAA,EAC/C,QAAQ;AAAA,EAER;AACF;AAEA,eAAe,eACb,SACA,UACA,MACe;AACf,MAAI,CAAC,SAAU;AACf,QAAM,eAAe,KAAK,QAAQ,QAAQ;AAE1C,MAAI;AACF,UAAM,UAAU,MAAM,QAAQ,SAAS,EAAE,eAAe,KAAK,CAAC;AAC9D,eAAW,SAAS,SAAS;AAC3B,UAAI,CAAC,MAAM,OAAO,KAAK,CAAC,MAAM,KAAK,SAAS,OAAO,EAAG;AACtD,YAAM,WAAW,KAAK,KAAK,SAAS,MAAM,IAAI;AAC9C,YAAM,UAAU,MAAM,SAAS,UAAU,OAAO;AAChD,YAAM,MAAM,KAAK,MAAM,OAAO;AAC9B,UAAI,KAAK,QAAQ,IAAI,IAAI,MAAM,cAAc;AAE3C,YAAI,CAAC,KAAK,KAAK,CAAC,MAAM,EAAE,UAAU,IAAI,KAAK,GAAG;AAC5C,eAAK,KAAK,GAAG;AAAA,QACf;AAAA,MACF;AAAA,IACF;AAAA,EACF,QAAQ;AAAA,EAER;AACF;","names":[]}
|
|
@@ -9,8 +9,12 @@ function resolvePackageDir(pkg) {
|
|
|
9
9
|
function resolveAgentsDir() {
|
|
10
10
|
return path.join(resolvePackageDir("@neotx/agents"), "agents");
|
|
11
11
|
}
|
|
12
|
+
function resolveAgentsPackageDir() {
|
|
13
|
+
return resolvePackageDir("@neotx/agents");
|
|
14
|
+
}
|
|
12
15
|
|
|
13
16
|
export {
|
|
14
|
-
resolveAgentsDir
|
|
17
|
+
resolveAgentsDir,
|
|
18
|
+
resolveAgentsPackageDir
|
|
15
19
|
};
|
|
16
|
-
//# sourceMappingURL=chunk-
|
|
20
|
+
//# sourceMappingURL=chunk-F622JUDY.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/resolve.ts"],"sourcesContent":["import { createRequire } from \"node:module\";\nimport path from \"node:path\";\n\nconst require = createRequire(import.meta.url);\n\nfunction resolvePackageDir(pkg: string): string {\n const pkgPath = require.resolve(`${pkg}/package.json`);\n return path.dirname(pkgPath);\n}\n\nexport function resolveAgentsDir(): string {\n return path.join(resolvePackageDir(\"@neotx/agents\"), \"agents\");\n}\n"],"mappings":";AAAA,SAAS,qBAAqB;AAC9B,OAAO,UAAU;AAEjB,IAAMA,WAAU,cAAc,YAAY,GAAG;AAE7C,SAAS,kBAAkB,KAAqB;AAC9C,QAAM,UAAUA,SAAQ,QAAQ,GAAG,GAAG,eAAe;AACrD,SAAO,KAAK,QAAQ,OAAO;AAC7B;AAEO,SAAS,mBAA2B;AACzC,SAAO,KAAK,KAAK,kBAAkB,eAAe,GAAG,QAAQ;AAC/D;","names":["require"]}
|
|
1
|
+
{"version":3,"sources":["../src/resolve.ts"],"sourcesContent":["import { createRequire } from \"node:module\";\nimport path from \"node:path\";\n\nconst require = createRequire(import.meta.url);\n\nfunction resolvePackageDir(pkg: string): string {\n const pkgPath = require.resolve(`${pkg}/package.json`);\n return path.dirname(pkgPath);\n}\n\nexport function resolveAgentsDir(): string {\n return path.join(resolvePackageDir(\"@neotx/agents\"), \"agents\");\n}\n\nexport function resolveAgentsPackageDir(): string {\n return resolvePackageDir(\"@neotx/agents\");\n}\n"],"mappings":";AAAA,SAAS,qBAAqB;AAC9B,OAAO,UAAU;AAEjB,IAAMA,WAAU,cAAc,YAAY,GAAG;AAE7C,SAAS,kBAAkB,KAAqB;AAC9C,QAAM,UAAUA,SAAQ,QAAQ,GAAG,GAAG,eAAe;AACrD,SAAO,KAAK,QAAQ,OAAO;AAC7B;AAEO,SAAS,mBAA2B;AACzC,SAAO,KAAK,KAAK,kBAAkB,eAAe,GAAG,QAAQ;AAC/D;AAEO,SAAS,0BAAkC;AAChD,SAAO,kBAAkB,eAAe;AAC1C;","names":["require"]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
resolveRepoFilter
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-3ZP3BQXB.js";
|
|
4
4
|
import {
|
|
5
5
|
printError,
|
|
6
6
|
printJson,
|
|
@@ -38,11 +38,6 @@ var cost_default = defineCommand({
|
|
|
38
38
|
description: "Show cost breakdown from journals (today, by agent, by run)"
|
|
39
39
|
},
|
|
40
40
|
args: {
|
|
41
|
-
all: {
|
|
42
|
-
type: "boolean",
|
|
43
|
-
description: "Show costs from all repos",
|
|
44
|
-
default: false
|
|
45
|
-
},
|
|
46
41
|
repo: {
|
|
47
42
|
type: "string",
|
|
48
43
|
description: "Filter by repo name or path"
|
|
@@ -66,7 +61,7 @@ var cost_default = defineCommand({
|
|
|
66
61
|
process.exitCode = 1;
|
|
67
62
|
return;
|
|
68
63
|
}
|
|
69
|
-
const filter = await resolveRepoFilter({
|
|
64
|
+
const filter = await resolveRepoFilter({ repo: args.repo });
|
|
70
65
|
if (filter.mode !== "all") {
|
|
71
66
|
const slug = filter.repoSlug;
|
|
72
67
|
entries = entries.filter((e) => {
|
|
@@ -131,4 +126,4 @@ var cost_default = defineCommand({
|
|
|
131
126
|
export {
|
|
132
127
|
cost_default as default
|
|
133
128
|
};
|
|
134
|
-
//# sourceMappingURL=cost-
|
|
129
|
+
//# sourceMappingURL=cost-OQGFNBBG.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/commands/cost.ts"],"sourcesContent":["import { existsSync } from \"node:fs\";\nimport { readdir, readFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport type { CostEntry } from \"@neotx/core\";\nimport { getJournalsDir, toRepoSlug } from \"@neotx/core\";\nimport { defineCommand } from \"citty\";\nimport { printError, printJson, printTable } from \"../output.js\";\nimport { resolveRepoFilter } from \"../repo-filter.js\";\n\nasync function readCostEntries(journalDir: string): Promise<CostEntry[]> {\n if (!existsSync(journalDir)) return [];\n const files = await readdir(journalDir);\n const costFiles = files\n .filter((f) => f.startsWith(\"cost-\"))\n .sort()\n .reverse();\n const entries: CostEntry[] = [];\n\n for (const file of costFiles) {\n const content = await readFile(path.join(journalDir, file), \"utf-8\");\n for (const line of content.trim().split(\"\\n\")) {\n if (!line.trim()) continue;\n entries.push(JSON.parse(line) as CostEntry);\n }\n }\n\n return entries;\n}\n\nfunction isToday(timestamp: string): boolean {\n const d = new Date(timestamp);\n const now = new Date();\n return (\n d.getUTCFullYear() === now.getUTCFullYear() &&\n d.getUTCMonth() === now.getUTCMonth() &&\n d.getUTCDate() === now.getUTCDate()\n );\n}\n\nexport default defineCommand({\n meta: {\n name: \"cost\",\n description: \"Show cost breakdown from journals (today, by agent, by run)\",\n },\n args: {\n repo: {\n type: \"string\",\n description: \"Filter by repo name or path\",\n },\n short: {\n type: \"boolean\",\n description: \"Compact output for supervisor agents (saves tokens)\",\n default: false,\n },\n output: {\n type: \"string\",\n description: \"Output format: json\",\n },\n },\n async run({ args }) {\n const jsonOutput = args.output === \"json\";\n const journalDir = getJournalsDir();\n let entries = await readCostEntries(journalDir);\n\n if (entries.length === 0) {\n printError(\"No cost data found.\");\n process.exitCode = 1;\n return;\n }\n\n // Filter by repo if specified\n const filter = await resolveRepoFilter({ repo: args.repo });\n if (filter.mode !== \"all\") {\n const slug = filter.repoSlug;\n entries = entries.filter((e) => {\n if (!e.repo) return false;\n return toRepoSlug({ path: e.repo }) === slug;\n });\n }\n\n const todayEntries = entries.filter((e) => isToday(e.timestamp));\n const todayTotal = todayEntries.reduce((sum, e) => sum + e.costUsd, 0);\n const allTimeTotal = entries.reduce((sum, e) => sum + e.costUsd, 0);\n\n // Breakdown by agent (today)\n const byAgent = new Map<string, { cost: number; runs: number }>();\n for (const e of todayEntries) {\n const prev = byAgent.get(e.agent) ?? { cost: 0, runs: 0 };\n byAgent.set(e.agent, { cost: prev.cost + e.costUsd, runs: prev.runs + 1 });\n }\n\n // Breakdown by repo (today, only in --all mode)\n const byRepo = new Map<string, { cost: number; runs: number }>();\n if (filter.mode === \"all\") {\n for (const e of todayEntries) {\n const repo = e.repo ?? \"unknown\";\n const prev = byRepo.get(repo) ?? { cost: 0, runs: 0 };\n byRepo.set(repo, { cost: prev.cost + e.costUsd, runs: prev.runs + 1 });\n }\n }\n\n if (jsonOutput) {\n printJson({\n today: {\n total: todayTotal,\n sessions: todayEntries.length,\n byAgent: Object.fromEntries(byAgent),\n ...(byRepo.size > 0 ? { byRepo: Object.fromEntries(byRepo) } : {}),\n },\n allTime: {\n total: allTimeTotal,\n sessions: entries.length,\n },\n });\n return;\n }\n\n if (args.short) {\n const agents = [...byAgent.entries()]\n .map(([name, data]) => `${name}=$${data.cost.toFixed(4)}`)\n .join(\" \");\n console.log(`today=$${todayTotal.toFixed(4)} sessions=${todayEntries.length} ${agents}`);\n return;\n }\n\n console.log(`Today: $${todayTotal.toFixed(4)} (${todayEntries.length} sessions)`);\n console.log(`All time: $${allTimeTotal.toFixed(4)} (${entries.length} sessions)`);\n\n if (byAgent.size > 0) {\n console.log(\"\");\n printTable(\n [\"AGENT\", \"COST TODAY\", \"SESSIONS\"],\n [...byAgent.entries()]\n .sort((a, b) => b[1].cost - a[1].cost)\n .map(([name, data]) => [name, `$${data.cost.toFixed(4)}`, String(data.runs)]),\n );\n }\n\n if (byRepo.size > 0) {\n console.log(\"\");\n printTable(\n [\"REPO\", \"COST TODAY\", \"SESSIONS\"],\n [...byRepo.entries()]\n .sort((a, b) => b[1].cost - a[1].cost)\n .map(([repo, data]) => [repo, `$${data.cost.toFixed(4)}`, String(data.runs)]),\n );\n }\n },\n});\n"],"mappings":"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","names":[]}
|
|
@@ -1,6 +1,11 @@
|
|
|
1
|
+
import {
|
|
2
|
+
resolveAgentsPackageDir
|
|
3
|
+
} from "../chunk-F622JUDY.js";
|
|
4
|
+
|
|
1
5
|
// src/daemon/supervisor-worker.ts
|
|
2
6
|
import { createWriteStream } from "fs";
|
|
3
7
|
import { mkdir } from "fs/promises";
|
|
8
|
+
import path from "path";
|
|
4
9
|
import { getSupervisorDir, loadGlobalConfig, SupervisorDaemon } from "@neotx/core";
|
|
5
10
|
async function main() {
|
|
6
11
|
const name = process.argv[2];
|
|
@@ -16,7 +21,8 @@ async function main() {
|
|
|
16
21
|
process.stderr.write = logStream.write.bind(logStream);
|
|
17
22
|
try {
|
|
18
23
|
const config = await loadGlobalConfig();
|
|
19
|
-
const
|
|
24
|
+
const defaultInstructionsPath = path.join(resolveAgentsPackageDir(), "SUPERVISOR.md");
|
|
25
|
+
const daemon = new SupervisorDaemon({ name, config, defaultInstructionsPath });
|
|
20
26
|
await daemon.start();
|
|
21
27
|
} catch (error) {
|
|
22
28
|
const msg = error instanceof Error ? error.message : String(error);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/daemon/supervisor-worker.ts"],"sourcesContent":["/**\n * Detached worker process for the supervisor daemon.\n *\n * Launched via child_process.fork() from the supervise command.\n * Runs the SupervisorDaemon which starts the heartbeat loop,\n * webhook server, and event queue.\n *\n * Usage: node supervisor-worker.js <name>\n */\n\nimport { createWriteStream } from \"node:fs\";\nimport { mkdir } from \"node:fs/promises\";\nimport { getSupervisorDir, loadGlobalConfig, SupervisorDaemon } from \"@neotx/core\";\n\nasync function main(): Promise<void> {\n const name = process.argv[2];\n if (!name) {\n process.stderr.write(\"Usage: supervisor-worker.js <name>\\n\");\n process.exit(1);\n }\n\n // Redirect stdout/stderr to a log file\n const dir = getSupervisorDir(name);\n await mkdir(dir, { recursive: true });\n const logPath = `${dir}/daemon.log`;\n const logStream = createWriteStream(logPath, { flags: \"a\" });\n process.stdout.write = logStream.write.bind(logStream);\n process.stderr.write = logStream.write.bind(logStream);\n\n try {\n const config = await loadGlobalConfig();\n const daemon = new SupervisorDaemon({ name, config });\n await daemon.start();\n } catch (error) {\n const msg = error instanceof Error ? error.message : String(error);\n console.error(`[supervisor-worker] Fatal: ${msg}`);\n process.exit(1);\n }\n}\n\nmain();\n"],"mappings":"
|
|
1
|
+
{"version":3,"sources":["../../src/daemon/supervisor-worker.ts"],"sourcesContent":["/**\n * Detached worker process for the supervisor daemon.\n *\n * Launched via child_process.fork() from the supervise command.\n * Runs the SupervisorDaemon which starts the heartbeat loop,\n * webhook server, and event queue.\n *\n * Usage: node supervisor-worker.js <name>\n */\n\nimport { createWriteStream } from \"node:fs\";\nimport { mkdir } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { getSupervisorDir, loadGlobalConfig, SupervisorDaemon } from \"@neotx/core\";\nimport { resolveAgentsPackageDir } from \"../resolve.js\";\n\nasync function main(): Promise<void> {\n const name = process.argv[2];\n if (!name) {\n process.stderr.write(\"Usage: supervisor-worker.js <name>\\n\");\n process.exit(1);\n }\n\n // Redirect stdout/stderr to a log file\n const dir = getSupervisorDir(name);\n await mkdir(dir, { recursive: true });\n const logPath = `${dir}/daemon.log`;\n const logStream = createWriteStream(logPath, { flags: \"a\" });\n process.stdout.write = logStream.write.bind(logStream);\n process.stderr.write = logStream.write.bind(logStream);\n\n try {\n const config = await loadGlobalConfig();\n const defaultInstructionsPath = path.join(resolveAgentsPackageDir(), \"SUPERVISOR.md\");\n const daemon = new SupervisorDaemon({ name, config, defaultInstructionsPath });\n await daemon.start();\n } catch (error) {\n const msg = error instanceof Error ? error.message : String(error);\n console.error(`[supervisor-worker] Fatal: ${msg}`);\n process.exit(1);\n }\n}\n\nmain();\n"],"mappings":";;;;;AAUA,SAAS,yBAAyB;AAClC,SAAS,aAAa;AACtB,OAAO,UAAU;AACjB,SAAS,kBAAkB,kBAAkB,wBAAwB;AAGrE,eAAe,OAAsB;AACnC,QAAM,OAAO,QAAQ,KAAK,CAAC;AAC3B,MAAI,CAAC,MAAM;AACT,YAAQ,OAAO,MAAM,sCAAsC;AAC3D,YAAQ,KAAK,CAAC;AAAA,EAChB;AAGA,QAAM,MAAM,iBAAiB,IAAI;AACjC,QAAM,MAAM,KAAK,EAAE,WAAW,KAAK,CAAC;AACpC,QAAM,UAAU,GAAG,GAAG;AACtB,QAAM,YAAY,kBAAkB,SAAS,EAAE,OAAO,IAAI,CAAC;AAC3D,UAAQ,OAAO,QAAQ,UAAU,MAAM,KAAK,SAAS;AACrD,UAAQ,OAAO,QAAQ,UAAU,MAAM,KAAK,SAAS;AAErD,MAAI;AACF,UAAM,SAAS,MAAM,iBAAiB;AACtC,UAAM,0BAA0B,KAAK,KAAK,wBAAwB,GAAG,eAAe;AACpF,UAAM,SAAS,IAAI,iBAAiB,EAAE,MAAM,QAAQ,wBAAwB,CAAC;AAC7E,UAAM,OAAO,MAAM;AAAA,EACrB,SAAS,OAAO;AACd,UAAM,MAAM,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AACjE,YAAQ,MAAM,8BAA8B,GAAG,EAAE;AACjD,YAAQ,KAAK,CAAC;AAAA,EAChB;AACF;AAEA,KAAK;","names":[]}
|
package/dist/daemon/worker.js
CHANGED
|
@@ -19,8 +19,29 @@ async function main() {
|
|
|
19
19
|
const logPath = getRunLogPath(repoSlug, runId);
|
|
20
20
|
await mkdir(path.dirname(logPath), { recursive: true });
|
|
21
21
|
const logStream = createWriteStream(logPath, { flags: "a" });
|
|
22
|
+
function writeLog(msg) {
|
|
23
|
+
logStream.write(`${(/* @__PURE__ */ new Date()).toISOString()} ${msg}
|
|
24
|
+
`);
|
|
25
|
+
}
|
|
22
26
|
process.stdout.write = logStream.write.bind(logStream);
|
|
23
27
|
process.stderr.write = logStream.write.bind(logStream);
|
|
28
|
+
process.on("uncaughtException", (err) => {
|
|
29
|
+
writeLog(`[worker] UNCAUGHT EXCEPTION: ${err.message}
|
|
30
|
+
${err.stack}`);
|
|
31
|
+
logStream.end();
|
|
32
|
+
process.exit(1);
|
|
33
|
+
});
|
|
34
|
+
process.on("unhandledRejection", (reason) => {
|
|
35
|
+
writeLog(`[worker] UNHANDLED REJECTION: ${String(reason)}`);
|
|
36
|
+
});
|
|
37
|
+
for (const sig of ["SIGTERM", "SIGINT", "SIGHUP"]) {
|
|
38
|
+
process.on(sig, () => {
|
|
39
|
+
writeLog(`[worker] Received ${sig}, exiting`);
|
|
40
|
+
logStream.end();
|
|
41
|
+
process.exit(1);
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
writeLog(`[worker] Starting run ${runId} (PID ${process.pid})`);
|
|
24
45
|
const dispatchPath = getRunDispatchPath(repoSlug, runId);
|
|
25
46
|
const runPath = path.join(getRepoRunsDir(repoSlug), `${runId}.json`);
|
|
26
47
|
try {
|
|
@@ -28,6 +49,7 @@ async function main() {
|
|
|
28
49
|
const request = JSON.parse(raw);
|
|
29
50
|
await unlink(dispatchPath).catch(() => {
|
|
30
51
|
});
|
|
52
|
+
writeLog(`[worker] Dispatch loaded: agent=${request.agentName} repo=${request.repo}`);
|
|
31
53
|
const config = await loadGlobalConfig();
|
|
32
54
|
const agentRegistry = new AgentRegistry(
|
|
33
55
|
request.bundledAgentsDir,
|
|
@@ -53,13 +75,16 @@ async function main() {
|
|
|
53
75
|
process.exit(1);
|
|
54
76
|
}, config.sessions.maxDurationMs + 6e4);
|
|
55
77
|
safetyTimeout.unref();
|
|
78
|
+
writeLog("[worker] Starting orchestrator...");
|
|
56
79
|
await orchestrator.start();
|
|
57
80
|
await updatePersistedRun(runPath, { status: "running", pid: process.pid });
|
|
81
|
+
writeLog("[worker] Dispatching...");
|
|
58
82
|
const result = await orchestrator.dispatch({
|
|
59
83
|
runId,
|
|
60
84
|
workflow: `_run_${request.agentName}`,
|
|
61
85
|
repo: request.repo,
|
|
62
86
|
prompt: request.prompt,
|
|
87
|
+
...request.branch ? { branch: request.branch } : {},
|
|
63
88
|
priority: request.priority ?? "medium",
|
|
64
89
|
metadata: request.metadata
|
|
65
90
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/daemon/worker.ts"],"sourcesContent":["/**\n * Detached worker process for `neo run -d`.\n *\n * Launched via child_process.fork() from the run command.\n * Reads dispatch parameters from a .dispatch.json file, runs the orchestrator,\n * and persists results. Stdout/stderr are redirected to a log file.\n *\n * Usage: node worker.js <runId> <repoSlug>\n */\n\nimport { createWriteStream, existsSync } from \"node:fs\";\nimport { mkdir, readFile, unlink, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport type { PersistedRun } from \"@neotx/core\";\nimport {\n AgentRegistry,\n getRepoRunsDir,\n getRunDispatchPath,\n getRunLogPath,\n loadGlobalConfig,\n Orchestrator,\n} from \"@neotx/core\";\n\ninterface DispatchRequest {\n agentName: string;\n repo: string;\n prompt: string;\n priority?: \"critical\" | \"high\" | \"medium\" | \"low\";\n metadata?: Record<string, unknown>;\n bundledAgentsDir: string;\n customAgentsDir?: string;\n}\n\nasync function main(): Promise<void> {\n const [runId, repoSlug] = process.argv.slice(2);\n if (!runId || !repoSlug) {\n process.stderr.write(\"Usage: worker.js <runId> <repoSlug>\\n\");\n process.exit(1);\n }\n\n // Redirect stdout/stderr to log file\n const logPath = getRunLogPath(repoSlug, runId);\n await mkdir(path.dirname(logPath), { recursive: true });\n const logStream = createWriteStream(logPath, { flags: \"a\" });\n process.stdout.write = logStream.write.bind(logStream);\n process.stderr.write = logStream.write.bind(logStream);\n\n const dispatchPath = getRunDispatchPath(repoSlug, runId);\n const runPath = path.join(getRepoRunsDir(repoSlug), `${runId}.json`);\n\n try {\n // Read dispatch request\n const raw = await readFile(dispatchPath, \"utf-8\");\n const request = JSON.parse(raw) as DispatchRequest;\n\n // Clean up dispatch file\n await unlink(dispatchPath).catch(() => {});\n\n // Load config and agents\n const config = await loadGlobalConfig();\n const agentRegistry = new AgentRegistry(\n request.bundledAgentsDir,\n request.customAgentsDir && existsSync(request.customAgentsDir)\n ? request.customAgentsDir\n : undefined,\n );\n await agentRegistry.load();\n\n const agent = agentRegistry.get(request.agentName);\n if (!agent) {\n throw new Error(`Agent \"${request.agentName}\" not found`);\n }\n\n // Create orchestrator\n const orchestrator = new Orchestrator(config);\n orchestrator.registerAgent(agent);\n orchestrator.registerWorkflow({\n name: `_run_${request.agentName}`,\n description: `Detached dispatch to ${request.agentName}`,\n steps: {\n run: { agent: request.agentName },\n },\n });\n\n // Update persisted run with PID\n await updatePersistedRun(runPath, { pid: process.pid });\n\n // Safety timeout — ensure the process eventually exits\n const safetyTimeout = setTimeout(() => {\n console.error(\"[worker] Safety timeout reached, forcing exit\");\n process.exit(1);\n }, config.sessions.maxDurationMs + 60_000);\n safetyTimeout.unref();\n\n await orchestrator.start();\n\n // Re-assert running status — orchestrator.start() calls recoverOrphanedRuns()\n // which marks any \"running\" persisted runs as \"failed\"\n await updatePersistedRun(runPath, { status: \"running\", pid: process.pid });\n\n const result = await orchestrator.dispatch({\n runId,\n workflow: `_run_${request.agentName}`,\n repo: request.repo,\n prompt: request.prompt,\n priority: request.priority ?? \"medium\",\n metadata: request.metadata,\n });\n\n await orchestrator.shutdown();\n\n console.log(`[worker] Run ${runId} completed: ${result.status}`);\n console.log(`[worker] Cost: $${result.costUsd.toFixed(4)}`);\n if (result.branch) {\n console.log(`[worker] Branch: ${result.branch}`);\n }\n } catch (error) {\n const errorMsg = error instanceof Error ? error.message : String(error);\n console.error(`[worker] Run ${runId} failed: ${errorMsg}`);\n\n // Update persisted run to failed status\n await updatePersistedRun(runPath, {\n status: \"failed\",\n updatedAt: new Date().toISOString(),\n }).catch(() => {});\n } finally {\n logStream.end();\n process.exit(0);\n }\n}\n\nasync function updatePersistedRun(runPath: string, updates: Partial<PersistedRun>): Promise<void> {\n try {\n const raw = await readFile(runPath, \"utf-8\");\n const run = JSON.parse(raw) as PersistedRun;\n Object.assign(run, updates);\n await writeFile(runPath, JSON.stringify(run, null, 2), \"utf-8\");\n } catch {\n // Non-critical\n }\n}\n\nmain();\n"],"mappings":";AAUA,SAAS,mBAAmB,kBAAkB;AAC9C,SAAS,OAAO,UAAU,QAAQ,iBAAiB;AACnD,OAAO,UAAU;AAEjB;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;
|
|
1
|
+
{"version":3,"sources":["../../src/daemon/worker.ts"],"sourcesContent":["/**\n * Detached worker process for `neo run -d`.\n *\n * Launched via child_process.fork() from the run command.\n * Reads dispatch parameters from a .dispatch.json file, runs the orchestrator,\n * and persists results. Stdout/stderr are redirected to a log file.\n *\n * Usage: node worker.js <runId> <repoSlug>\n */\n\nimport { createWriteStream, existsSync } from \"node:fs\";\nimport { mkdir, readFile, unlink, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport type { PersistedRun } from \"@neotx/core\";\nimport {\n AgentRegistry,\n getRepoRunsDir,\n getRunDispatchPath,\n getRunLogPath,\n loadGlobalConfig,\n Orchestrator,\n} from \"@neotx/core\";\n\ninterface DispatchRequest {\n agentName: string;\n repo: string;\n prompt: string;\n branch?: string;\n priority?: \"critical\" | \"high\" | \"medium\" | \"low\";\n metadata?: Record<string, unknown>;\n bundledAgentsDir: string;\n customAgentsDir?: string;\n}\n\nasync function main(): Promise<void> {\n const [runId, repoSlug] = process.argv.slice(2);\n if (!runId || !repoSlug) {\n process.stderr.write(\"Usage: worker.js <runId> <repoSlug>\\n\");\n process.exit(1);\n }\n\n // Redirect stdout/stderr to log file\n const logPath = getRunLogPath(repoSlug, runId);\n await mkdir(path.dirname(logPath), { recursive: true });\n const logStream = createWriteStream(logPath, { flags: \"a\" });\n\n function writeLog(msg: string): void {\n logStream.write(`${new Date().toISOString()} ${msg}\\n`);\n }\n\n process.stdout.write = logStream.write.bind(logStream);\n process.stderr.write = logStream.write.bind(logStream);\n\n // Catch crashes and signals so we always leave a trace\n process.on(\"uncaughtException\", (err) => {\n writeLog(`[worker] UNCAUGHT EXCEPTION: ${err.message}\\n${err.stack}`);\n logStream.end();\n process.exit(1);\n });\n process.on(\"unhandledRejection\", (reason) => {\n writeLog(`[worker] UNHANDLED REJECTION: ${String(reason)}`);\n });\n for (const sig of [\"SIGTERM\", \"SIGINT\", \"SIGHUP\"] as const) {\n process.on(sig, () => {\n writeLog(`[worker] Received ${sig}, exiting`);\n logStream.end();\n process.exit(1);\n });\n }\n\n writeLog(`[worker] Starting run ${runId} (PID ${process.pid})`);\n\n const dispatchPath = getRunDispatchPath(repoSlug, runId);\n const runPath = path.join(getRepoRunsDir(repoSlug), `${runId}.json`);\n\n try {\n // Read dispatch request\n const raw = await readFile(dispatchPath, \"utf-8\");\n const request = JSON.parse(raw) as DispatchRequest;\n\n // Clean up dispatch file\n await unlink(dispatchPath).catch(() => {});\n writeLog(`[worker] Dispatch loaded: agent=${request.agentName} repo=${request.repo}`);\n\n // Load config and agents\n const config = await loadGlobalConfig();\n const agentRegistry = new AgentRegistry(\n request.bundledAgentsDir,\n request.customAgentsDir && existsSync(request.customAgentsDir)\n ? request.customAgentsDir\n : undefined,\n );\n await agentRegistry.load();\n\n const agent = agentRegistry.get(request.agentName);\n if (!agent) {\n throw new Error(`Agent \"${request.agentName}\" not found`);\n }\n\n // Create orchestrator\n const orchestrator = new Orchestrator(config);\n orchestrator.registerAgent(agent);\n orchestrator.registerWorkflow({\n name: `_run_${request.agentName}`,\n description: `Detached dispatch to ${request.agentName}`,\n steps: {\n run: { agent: request.agentName },\n },\n });\n\n // Update persisted run with PID\n await updatePersistedRun(runPath, { pid: process.pid });\n\n // Safety timeout — ensure the process eventually exits\n const safetyTimeout = setTimeout(() => {\n console.error(\"[worker] Safety timeout reached, forcing exit\");\n process.exit(1);\n }, config.sessions.maxDurationMs + 60_000);\n safetyTimeout.unref();\n\n writeLog(\"[worker] Starting orchestrator...\");\n await orchestrator.start();\n\n // Re-assert running status — orchestrator.start() calls recoverOrphanedRuns()\n // which marks any \"running\" persisted runs as \"failed\"\n await updatePersistedRun(runPath, { status: \"running\", pid: process.pid });\n\n writeLog(\"[worker] Dispatching...\");\n const result = await orchestrator.dispatch({\n runId,\n workflow: `_run_${request.agentName}`,\n repo: request.repo,\n prompt: request.prompt,\n ...(request.branch ? { branch: request.branch } : {}),\n priority: request.priority ?? \"medium\",\n metadata: request.metadata,\n });\n\n await orchestrator.shutdown();\n\n console.log(`[worker] Run ${runId} completed: ${result.status}`);\n console.log(`[worker] Cost: $${result.costUsd.toFixed(4)}`);\n if (result.branch) {\n console.log(`[worker] Branch: ${result.branch}`);\n }\n } catch (error) {\n const errorMsg = error instanceof Error ? error.message : String(error);\n console.error(`[worker] Run ${runId} failed: ${errorMsg}`);\n\n // Update persisted run to failed status\n await updatePersistedRun(runPath, {\n status: \"failed\",\n updatedAt: new Date().toISOString(),\n }).catch(() => {});\n } finally {\n logStream.end();\n process.exit(0);\n }\n}\n\nasync function updatePersistedRun(runPath: string, updates: Partial<PersistedRun>): Promise<void> {\n try {\n const raw = await readFile(runPath, \"utf-8\");\n const run = JSON.parse(raw) as PersistedRun;\n Object.assign(run, updates);\n await writeFile(runPath, JSON.stringify(run, null, 2), \"utf-8\");\n } catch {\n // Non-critical\n }\n}\n\nmain();\n"],"mappings":"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","names":[]}
|