dilaya-cli 0.1.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 +145 -0
- package/dist/index.js +3543 -0
- package/package.json +37 -0
package/README.md
ADDED
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
# dilaya
|
|
2
|
+
|
|
3
|
+
A **dumb (AI-free) poller** that wakes a Claude agent only when there's work.
|
|
4
|
+
|
|
5
|
+
Each Dilaya app (a Postgres schema) can have **one agent**: a prompt that runs on demand
|
|
6
|
+
instead of an AI session sitting idle 24/7. This CLI is the local half of that loop:
|
|
7
|
+
|
|
8
|
+
1. It asks the app's MCP server one cheap question on a fixed interval — *"is there work?"*
|
|
9
|
+
(a DynamoDB-backed read; Aurora stays scaled to zero, no model tokens spent).
|
|
10
|
+
2. Only when the answer is **yes** does it launch an interactive `claude` inside a detached
|
|
11
|
+
**tmux** session, running from the agent's project dir.
|
|
12
|
+
3. The agent does all available work, optionally has a back-and-forth via the `await-work`
|
|
13
|
+
tool, decides how it should next be woken (`set-agent-mode`), then marks itself **idle**.
|
|
14
|
+
The poller reaps the idle session.
|
|
15
|
+
|
|
16
|
+
Because the agent runs in tmux (not headless `claude -p`), you can **attach to the live
|
|
17
|
+
session** to watch it work or message it: `dilaya agent attach`.
|
|
18
|
+
|
|
19
|
+
You pay for Claude only while there's actual work. The poller itself is free.
|
|
20
|
+
|
|
21
|
+
## Why a separate CLI
|
|
22
|
+
|
|
23
|
+
The long-lived poll token must **never enter the LLM's context**. So the agent (in Claude
|
|
24
|
+
Code) only ever handles a *single-use, 15-minute setup token*; the CLI exchanges that for a
|
|
25
|
+
long-lived, opaque poll token that it stores locally (`chmod 600`) and that only ever
|
|
26
|
+
reveals "work or not". The user never has to touch the CLI by hand — Claude Code drives the
|
|
27
|
+
whole install via `get-agent-setup-instructions`.
|
|
28
|
+
|
|
29
|
+
## Install
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
npm i -g dilaya-cli # or from source: npm i -g <path-to>/dilaya-cli
|
|
33
|
+
dilaya --version # package is `dilaya-cli`; the command it installs is `dilaya`
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Requires Node ≥ 18, plus **`claude` and `tmux`** on `PATH` (the agent runs inside tmux).
|
|
37
|
+
|
|
38
|
+
## Usage
|
|
39
|
+
|
|
40
|
+
Normally you don't run these yourself — ask the app's agent to "install the agent loop on
|
|
41
|
+
this machine" and Claude Code runs them for you. For reference:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
# 1. Exchange a setup token (from the MCP tool get-agent-setup-token) for a poll token.
|
|
45
|
+
dilaya agent setup --schema myapp \
|
|
46
|
+
--url https://<host>/myapp/agent/token \
|
|
47
|
+
--setup-token <single-use-token> \
|
|
48
|
+
--project-dir ~/.dilaya-agents/myapp \
|
|
49
|
+
--interval 30s
|
|
50
|
+
|
|
51
|
+
# 2. Install + start it as a background service (launchd on macOS, systemd-user on Linux).
|
|
52
|
+
dilaya agent install --schema myapp --interval 30s
|
|
53
|
+
|
|
54
|
+
# Inspect / control
|
|
55
|
+
dilaya agent status --schema myapp # service + poller + tmux session state
|
|
56
|
+
dilaya agent attach --schema myapp # attach to the live agent (type to talk; Ctrl-b then d to detach)
|
|
57
|
+
dilaya agent logs --schema myapp # tail the agent log
|
|
58
|
+
dilaya agent stop --schema myapp # stop poller (and kill any running session)
|
|
59
|
+
dilaya agent uninstall --schema myapp # stop + remove the service
|
|
60
|
+
|
|
61
|
+
# What the service actually runs (foreground poll loop):
|
|
62
|
+
dilaya agent run --schema myapp
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## How a wake works
|
|
66
|
+
|
|
67
|
+
`poll` returns `{ shouldWake, mode, lifecycle }`. When there's work and no session is live,
|
|
68
|
+
the poller starts one interactive `claude` (no `-p`) inside tmux, from the project dir:
|
|
69
|
+
|
|
70
|
+
- **`mode: "new"`** — start a fresh Claude session
|
|
71
|
+
(`claude --permission-mode auto --session-id <uuid> /dilaya-agent`).
|
|
72
|
+
Cheaper; the agent starts clean. Used when the agent last finished its task.
|
|
73
|
+
- **`mode: "continue"`** — resume the previous session (`--resume <id>`), keeping context.
|
|
74
|
+
Used when the agent was mid-task or expecting a reply.
|
|
75
|
+
|
|
76
|
+
The agent itself picks the next mode by calling `set-agent-mode` before it goes idle.
|
|
77
|
+
|
|
78
|
+
Interactive `claude` never self-exits, so the poller decides when a run is over from
|
|
79
|
+
`lifecycle`:
|
|
80
|
+
|
|
81
|
+
- **`running`** — the agent called `begin-agent-run`; the poller leaves it alone. It **never
|
|
82
|
+
time-kills** a running agent (coding work can take hours).
|
|
83
|
+
- **`idle`** — the agent called `set-agent-mode`; the poller reaps the tmux session after a
|
|
84
|
+
short grace (~12s) — **unless you're attached** (attached sessions are never reaped).
|
|
85
|
+
|
|
86
|
+
Only one session per schema exists at a time: the loop checks for a live session before
|
|
87
|
+
starting another, so a second agent can never run concurrently. A session that starts but
|
|
88
|
+
never reports `running` (e.g. `claude` failed to launch) is reaped after a startup timeout
|
|
89
|
+
(~5 min) and retried.
|
|
90
|
+
|
|
91
|
+
## Files it writes
|
|
92
|
+
|
|
93
|
+
Per schema, under `~/.config/dilaya/<schema>/`:
|
|
94
|
+
|
|
95
|
+
| File | Purpose |
|
|
96
|
+
| --- | --- |
|
|
97
|
+
| `config.json` | schema, poll URL, **poll token** (chmod 600), project dir, interval, last session id |
|
|
98
|
+
| `poller.pid` | liveness of the poll loop |
|
|
99
|
+
| `agent.log` | poll + agent activity (what `logs` tails) |
|
|
100
|
+
|
|
101
|
+
The running agent itself lives in a **detached tmux session** (`dilaya-<schema>` on a
|
|
102
|
+
dedicated tmux socket `dilaya`), not a file — `dilaya agent attach` connects to it.
|
|
103
|
+
|
|
104
|
+
Service definition: `~/Library/LaunchAgents/com.dilaya.agent.<schema>.plist` (macOS) or
|
|
105
|
+
`~/.config/systemd/user/dilaya-agent-<schema>.service` (Linux).
|
|
106
|
+
|
|
107
|
+
## Caveats
|
|
108
|
+
|
|
109
|
+
- **Login-scoped.** Starts at login (not pre-login boot); laptop sleep pauses polling.
|
|
110
|
+
On Linux run `loginctl enable-linger` to keep the service alive after logout.
|
|
111
|
+
- **Requires tmux** — the agent runs inside it (`install` preflights it). The poller talks to
|
|
112
|
+
tmux on a dedicated socket (`-L dilaya`), so it never touches your default tmux server.
|
|
113
|
+
- The spawned `claude` uses your existing MCP auth; if that token expires, ticks fail until
|
|
114
|
+
you re-login.
|
|
115
|
+
- The poller runs `claude --permission-mode auto` (interactive, inside tmux), so the project
|
|
116
|
+
dir's `.claude/settings.local.json` must allowlist every tool the agent uses — auto mode
|
|
117
|
+
runs allowlisted tools without prompting, and deny rules still win. Override the mode with
|
|
118
|
+
`dilaya agent setup --permission-mode <mode>`.
|
|
119
|
+
- One agent per schema; run `setup`/`install` once per app you want a loop for.
|
|
120
|
+
|
|
121
|
+
## Build (from source)
|
|
122
|
+
|
|
123
|
+
```bash
|
|
124
|
+
npm install
|
|
125
|
+
npm run typecheck
|
|
126
|
+
npm run build # esbuild → dist/index.js (with shebang)
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
## Releasing
|
|
130
|
+
|
|
131
|
+
Publishing to npm is automated. To cut a release:
|
|
132
|
+
|
|
133
|
+
1. Bump `version` in `package.json`, then commit and push to `main`.
|
|
134
|
+
2. Create a **GitHub Release** whose tag matches that version (`v0.1.0` or `0.1.0`).
|
|
135
|
+
|
|
136
|
+
The `Publish to npm` workflow ([.github/workflows/publish.yml](.github/workflows/publish.yml))
|
|
137
|
+
then verifies the tag matches `package.json`, type-checks, and runs `npm publish`. It needs
|
|
138
|
+
an `NPM_TOKEN` repository secret — an npm **automation** token (it bypasses 2FA in CI):
|
|
139
|
+
|
|
140
|
+
```bash
|
|
141
|
+
gh secret set NPM_TOKEN --repo hereya/dilaya-cli # paste the npm automation token
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
The GitHub repo is private; the npm package (`dilaya-cli`, unscoped) is published **public**
|
|
145
|
+
so `npm i -g dilaya-cli` works for everyone. It installs the `dilaya` command.
|