@agentmessier/restwalker 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +137 -0
- package/bin/restwalker.js +81 -0
- package/index.html +1161 -0
- package/install.sh +176 -0
- package/node/app.ts +767 -0
- package/node/db.ts +392 -0
- package/node/mcp.ts +217 -0
- package/node/package-lock.json +4552 -0
- package/node/package.json +32 -0
- package/node/runner.ts +174 -0
- package/node/scheduler.ts +221 -0
- package/node/schema.ts +46 -0
- package/node/session.ts +119 -0
- package/node/tsconfig.json +14 -0
- package/package.json +39 -0
- package/uninstall.sh +36 -0
package/README.md
ADDED
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
# restwalker
|
|
2
|
+
|
|
3
|
+
> While you rest, it walks.
|
|
4
|
+
|
|
5
|
+
Idle-time Claude task runner — a Mac background service that queues and runs Claude Code agent tasks during your off-hours, gated by live Claude usage so it never burns your interactive budget.
|
|
6
|
+
|
|
7
|
+
Runs as a LaunchAgent on port **47290** with a SQLite database, a dashboard UI, a REST API (OpenAPI 3.0), and an MCP server for Claude Code.
|
|
8
|
+
|
|
9
|
+
## How it works
|
|
10
|
+
|
|
11
|
+
1. You add tasks to the queue (via dashboard, REST API, or MCP tools in Claude Code)
|
|
12
|
+
2. The gate checks live Claude usage from `api.anthropic.com` — same source as `ccstatusline`
|
|
13
|
+
3. When usage is low and you're outside your coding window, tasks run automatically
|
|
14
|
+
4. Sessions are recorded; results, token counts, and transcripts are stored per task
|
|
15
|
+
|
|
16
|
+
### Budget gates (all configurable)
|
|
17
|
+
|
|
18
|
+
| Gate | Default | Behaviour |
|
|
19
|
+
|---|---|---|
|
|
20
|
+
| Coding window | 4 PM – 2 AM | Always paused during active hours |
|
|
21
|
+
| 5h usage | ≥ 75% | Pause to protect interactive budget |
|
|
22
|
+
| Weekly ceiling | ≥ 65% | Pause background jobs |
|
|
23
|
+
| Weekly hard stop | ≥ 90% | Hard stop regardless |
|
|
24
|
+
|
|
25
|
+
## Install
|
|
26
|
+
|
|
27
|
+
**Requirements:** macOS, Node.js 20+, Claude Code CLI (must be logged in)
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
git clone https://github.com/agentmessier-ai/restwalker.git
|
|
31
|
+
cd restwalker
|
|
32
|
+
./install.sh
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
The installer:
|
|
36
|
+
- Installs Node dependencies
|
|
37
|
+
- Installs and starts the LaunchAgent (auto-restarts on login)
|
|
38
|
+
- Interactively offers to register the MCP server with Claude Code
|
|
39
|
+
|
|
40
|
+
Open `http://localhost:47290` to confirm it's running.
|
|
41
|
+
|
|
42
|
+
### Custom Node path
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
NODE=/opt/homebrew/bin/node ./install.sh
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Uninstall
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
./uninstall.sh
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Stops the service, removes the LaunchAgent, and optionally deletes `~/.restwalker/` (DB + logs).
|
|
55
|
+
|
|
56
|
+
## Dashboard
|
|
57
|
+
|
|
58
|
+
`http://localhost:47290`
|
|
59
|
+
|
|
60
|
+
- Live gate status, 5h and weekly usage, next window
|
|
61
|
+
- 48h trend chart with threshold overlays and coding-window shading
|
|
62
|
+
- Task queue: add, paginate, expand rows to view session transcripts and reasoning blocks
|
|
63
|
+
- Agent providers: configure which CLI runs tasks and with what arguments
|
|
64
|
+
- Settings: all thresholds configurable without restart
|
|
65
|
+
|
|
66
|
+
## Task queue
|
|
67
|
+
|
|
68
|
+
Tasks have a description (the prompt), an optional working directory, model, provider, and schedule:
|
|
69
|
+
|
|
70
|
+
| Schedule | Behaviour |
|
|
71
|
+
|---|---|
|
|
72
|
+
| `once` | Runs once when the gate opens |
|
|
73
|
+
| `hourly` / `daily` / `weekly` / `monthly` | Automatically re-queues after each run |
|
|
74
|
+
|
|
75
|
+
## Agent providers
|
|
76
|
+
|
|
77
|
+
The default provider runs `claude --print --permission-mode auto --model {{model}} {{task}}`. You can add any provider with a custom command and args template using `{{task}}`, `{{model}}`, and `{{cwd}}` placeholders.
|
|
78
|
+
|
|
79
|
+
## MCP server
|
|
80
|
+
|
|
81
|
+
The MCP server (`node/mcp.ts`) exposes 17 tools for Claude Code via stdio transport:
|
|
82
|
+
|
|
83
|
+
| Group | Tools |
|
|
84
|
+
|---|---|
|
|
85
|
+
| Status | `status`, `can_run`, `usage_history`, `sync` |
|
|
86
|
+
| Queue | `queue_stats`, `queue_list`, `queue_get`, `queue_add`, `queue_cancel`, `queue_force_run`, `queue_session` |
|
|
87
|
+
| Providers | `list_providers`, `add_provider`, `set_default_provider` |
|
|
88
|
+
| Discovery | `list_models`, `list_projects` |
|
|
89
|
+
| Settings | `get_settings`, `update_settings` |
|
|
90
|
+
|
|
91
|
+
Register manually if you skipped it during install:
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
claude mcp add --scope user restwalker -- node /path/to/node_modules/.bin/tsx /path/to/node/mcp.ts
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## API
|
|
98
|
+
|
|
99
|
+
Full OpenAPI 3.0 spec and interactive docs at **`http://localhost:47290/docs`**.
|
|
100
|
+
|
|
101
|
+
Key endpoints:
|
|
102
|
+
|
|
103
|
+
| Endpoint | Method | Description |
|
|
104
|
+
|---|---|---|
|
|
105
|
+
| `/queue` | GET | List tasks (paginated) |
|
|
106
|
+
| `/queue` | POST | Add a task |
|
|
107
|
+
| `/queue/:id/force-run` | POST | Force-run bypassing the gate |
|
|
108
|
+
| `/queue/:id/session` | GET | Session transcript with thinking blocks |
|
|
109
|
+
| `/queue/stats` | GET | Counts by status |
|
|
110
|
+
| `/providers` | GET/POST | List or add agent providers |
|
|
111
|
+
| `/models` | GET | Live Anthropic model list |
|
|
112
|
+
| `/projects` | GET | Claude Code projects from history |
|
|
113
|
+
| `/status` | GET | Full daemon state |
|
|
114
|
+
| `/can-run` | GET | Quick gate check |
|
|
115
|
+
| `/settings` | GET/POST | Read or update thresholds |
|
|
116
|
+
| `/healthz` | GET | `{ok: true}` |
|
|
117
|
+
|
|
118
|
+
## Files
|
|
119
|
+
|
|
120
|
+
| Path | Purpose |
|
|
121
|
+
|---|---|
|
|
122
|
+
| `node/app.ts` | Fastify app, OpenAPI spec, routes, schedule checker |
|
|
123
|
+
| `node/db.ts` | Drizzle ORM repositories (tasks, providers, settings, snapshots) |
|
|
124
|
+
| `node/schema.ts` | Drizzle table definitions — single source of truth |
|
|
125
|
+
| `node/runner.ts` | better-queue worker, provider resolution, gate logic |
|
|
126
|
+
| `node/scheduler.ts` | Keychain read, Anthropic API fetch, time gate, budget logic |
|
|
127
|
+
| `node/session.ts` | Session JSONL parser and analysis |
|
|
128
|
+
| `node/mcp.ts` | MCP server (stdio, 17 tools) |
|
|
129
|
+
| `index.html` | Dashboard UI (no build step) |
|
|
130
|
+
| `install.sh` | One-command installer with interactive MCP registration |
|
|
131
|
+
| `uninstall.sh` | Clean removal |
|
|
132
|
+
|
|
133
|
+
## Logs
|
|
134
|
+
|
|
135
|
+
```bash
|
|
136
|
+
tail -f ~/.restwalker/restwalker.log
|
|
137
|
+
```
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* restwalker CLI — install, start, and manage the idle-time Claude task runner.
|
|
4
|
+
*
|
|
5
|
+
* Usage:
|
|
6
|
+
* npx @agentmessier/restwalker install # install LaunchAgent + register MCP
|
|
7
|
+
* npx @agentmessier/restwalker uninstall # remove LaunchAgent
|
|
8
|
+
* npx @agentmessier/restwalker start # start the daemon in the foreground
|
|
9
|
+
* npx @agentmessier/restwalker status # check if daemon is running
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { execFileSync, spawn } from 'child_process'
|
|
13
|
+
import { fileURLToPath } from 'url'
|
|
14
|
+
import { dirname, join } from 'path'
|
|
15
|
+
import { existsSync } from 'fs'
|
|
16
|
+
|
|
17
|
+
const __dirname = dirname(fileURLToPath(import.meta.url))
|
|
18
|
+
const ROOT = join(__dirname, '..')
|
|
19
|
+
|
|
20
|
+
const cmd = process.argv[2]
|
|
21
|
+
|
|
22
|
+
function sh(script, args = []) {
|
|
23
|
+
const full = join(ROOT, script)
|
|
24
|
+
if (!existsSync(full)) {
|
|
25
|
+
console.error(`Script not found: ${full}`)
|
|
26
|
+
process.exit(1)
|
|
27
|
+
}
|
|
28
|
+
execFileSync('bash', [full, ...args], { stdio: 'inherit', cwd: ROOT })
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
switch (cmd) {
|
|
32
|
+
case 'install':
|
|
33
|
+
sh('install.sh', process.argv.slice(3))
|
|
34
|
+
break
|
|
35
|
+
|
|
36
|
+
case 'uninstall':
|
|
37
|
+
sh('uninstall.sh')
|
|
38
|
+
break
|
|
39
|
+
|
|
40
|
+
case 'start': {
|
|
41
|
+
const tsx = join(ROOT, 'node', 'node_modules', '.bin', 'tsx')
|
|
42
|
+
const app = join(ROOT, 'node', 'app.ts')
|
|
43
|
+
if (!existsSync(tsx)) {
|
|
44
|
+
console.error('Dependencies not installed. Run: npx @agentmessier/restwalker install')
|
|
45
|
+
process.exit(1)
|
|
46
|
+
}
|
|
47
|
+
const proc = spawn(process.execPath, [tsx, app], { stdio: 'inherit', cwd: ROOT })
|
|
48
|
+
proc.on('exit', code => process.exit(code ?? 0))
|
|
49
|
+
break
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
case 'status': {
|
|
53
|
+
try {
|
|
54
|
+
const res = await fetch('http://localhost:47290/healthz')
|
|
55
|
+
if (res.ok) {
|
|
56
|
+
const data = await res.json()
|
|
57
|
+
console.log('restwalker is running —', JSON.stringify(data))
|
|
58
|
+
} else {
|
|
59
|
+
console.log('restwalker returned', res.status)
|
|
60
|
+
process.exit(1)
|
|
61
|
+
}
|
|
62
|
+
} catch {
|
|
63
|
+
console.log('restwalker is not running (nothing on port 47290)')
|
|
64
|
+
process.exit(1)
|
|
65
|
+
}
|
|
66
|
+
break
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
default:
|
|
70
|
+
console.log(`
|
|
71
|
+
restwalker — idle-time Claude task runner
|
|
72
|
+
|
|
73
|
+
Usage:
|
|
74
|
+
npx @agentmessier/restwalker install install LaunchAgent + register MCP
|
|
75
|
+
npx @agentmessier/restwalker uninstall remove LaunchAgent
|
|
76
|
+
npx @agentmessier/restwalker start run daemon in foreground
|
|
77
|
+
npx @agentmessier/restwalker status check if daemon is running
|
|
78
|
+
|
|
79
|
+
Dashboard: http://localhost:47290
|
|
80
|
+
`)
|
|
81
|
+
}
|