@a5c-ai/babysitter-breakpoints 0.0.27
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/.codex/skills/babysitter-breakpoint/SKILL.md +35 -0
- package/.codex/skills/babysitter-breakpoint/references/breakpoint-api.md +57 -0
- package/README.md +154 -0
- package/api/db.js +93 -0
- package/api/routes.js +475 -0
- package/api/server.js +33 -0
- package/bin/breakpoints.js +275 -0
- package/db/migrations/001_init.sql +56 -0
- package/db/migrations/002_extensions.sql +13 -0
- package/db/schema.sql +60 -0
- package/extensions/config.js +47 -0
- package/extensions/index.js +46 -0
- package/extensions/telegram.js +605 -0
- package/package.json +29 -0
- package/scripts/dev-runner.js +41 -0
- package/scripts/dev.ps1 +10 -0
- package/scripts/dev.sh +13 -0
- package/scripts/init-db.js +20 -0
- package/web/app.js +511 -0
- package/web/index.html +151 -0
- package/web/server.js +14 -0
- package/web/styles.css +431 -0
- package/worker/queue.js +85 -0
- package/worker/worker.js +50 -0
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: babysitter-breakpoint
|
|
3
|
+
description: Use the breakpoint API to communicate with users during babysitter runs (post breakpoints, poll for release, fetch feedback, and read context files). Trigger whenever a babysitter workflow needs approval, input, or status updates via breakpoints.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# babysitter-breakpoint
|
|
7
|
+
|
|
8
|
+
Use this skill to handle all user communication via the `breakpoints` CLI. Do
|
|
9
|
+
not prompt the user directly. Always post a breakpoint and poll until it is
|
|
10
|
+
released, then fetch feedback and continue.
|
|
11
|
+
|
|
12
|
+
## Workflow
|
|
13
|
+
|
|
14
|
+
1. Create a breakpoint with the required payload and `payload.context.files`.
|
|
15
|
+
2. Poll `breakpoints breakpoint wait <id> --interval 3` until `released`.
|
|
16
|
+
3. Apply feedback from the printed details and continue.
|
|
17
|
+
|
|
18
|
+
## Payload structure
|
|
19
|
+
|
|
20
|
+
Always include a `context.files` array for referenced files:
|
|
21
|
+
|
|
22
|
+
```json
|
|
23
|
+
{
|
|
24
|
+
"context": {
|
|
25
|
+
"runId": "run-...",
|
|
26
|
+
"files": [
|
|
27
|
+
{ "path": ".a5c/runs/<runId>/artifacts/process.md", "format": "markdown" },
|
|
28
|
+
{ "path": ".a5c/runs/<runId>/inputs.json", "format": "code", "language": "json" },
|
|
29
|
+
{ "path": ".a5c/runs/<runId>/code/main.js", "format": "code", "language": "javascript" }
|
|
30
|
+
]
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
See `references/breakpoint-api.md` for curl examples and endpoints.
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# Breakpoint CLI + API
|
|
2
|
+
|
|
3
|
+
Use the `breakpoints` CLI to communicate with the user. The CLI wraps the local
|
|
4
|
+
API. Never prompt directly.
|
|
5
|
+
|
|
6
|
+
## Base URL
|
|
7
|
+
- Default: `http://localhost:3000`
|
|
8
|
+
- Override with `BREAKPOINT_API_URL` if set.
|
|
9
|
+
|
|
10
|
+
## Auth
|
|
11
|
+
- Agent token: `AGENT_TOKEN`
|
|
12
|
+
- Human token: `HUMAN_TOKEN`
|
|
13
|
+
- Use `Authorization: Bearer <token>` when set.
|
|
14
|
+
|
|
15
|
+
## Create a breakpoint (agent)
|
|
16
|
+
```bash
|
|
17
|
+
breakpoints breakpoint create \
|
|
18
|
+
--question "Approve process + inputs + main.js?" \
|
|
19
|
+
--run-id run-... \
|
|
20
|
+
--title "Approval needed" \
|
|
21
|
+
--file ".a5c/runs/<runId>/artifacts/process.md,markdown" \
|
|
22
|
+
--file ".a5c/runs/<runId>/inputs.json,code,json" \
|
|
23
|
+
--file ".a5c/runs/<runId>/code/main.js,code,javascript"
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Poll for status
|
|
27
|
+
```bash
|
|
28
|
+
breakpoints breakpoint status <id>
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Fetch full details (including feedback)
|
|
32
|
+
```bash
|
|
33
|
+
breakpoints breakpoint show <id>
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Wait for release (prints details)
|
|
37
|
+
```bash
|
|
38
|
+
breakpoints breakpoint wait <id> --interval 3
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Fetch context file content (API)
|
|
42
|
+
```bash
|
|
43
|
+
curl -s "$BREAKPOINT_API_URL/api/breakpoints/<id>/context?path=path/to/file"
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Release with feedback (human)
|
|
47
|
+
```bash
|
|
48
|
+
curl -s -X POST "$BREAKPOINT_API_URL/api/breakpoints/<id>/feedback" \
|
|
49
|
+
-H "Content-Type: application/json" \
|
|
50
|
+
-H "Authorization: Bearer $HUMAN_TOKEN" \
|
|
51
|
+
-d '{"author":"reviewer","comment":"approved","release":true}'
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Notes
|
|
55
|
+
- Poll every 2-10 seconds.
|
|
56
|
+
- Continue orchestration only after `status` becomes `released` and feedback is retrieved.
|
|
57
|
+
- Context files must be listed in the breakpoint payload and use allowlisted extensions.
|
package/README.md
ADDED
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
# Breakpoint Manager
|
|
2
|
+
|
|
3
|
+
Lightweight breakpoint manager with API, queue worker, and web UI.
|
|
4
|
+
|
|
5
|
+
This package now lives at `packages/breakpoints`.
|
|
6
|
+
|
|
7
|
+
## Requirements
|
|
8
|
+
- Node.js 18+
|
|
9
|
+
|
|
10
|
+
## Setup
|
|
11
|
+
```bash
|
|
12
|
+
cd packages/breakpoints
|
|
13
|
+
npm install
|
|
14
|
+
npm run init:db
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Run (dev)
|
|
18
|
+
```bash
|
|
19
|
+
cd packages/breakpoints
|
|
20
|
+
npm run dev
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Run (installed CLI)
|
|
24
|
+
```bash
|
|
25
|
+
breakpoints start
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Or run separately:
|
|
29
|
+
```bash
|
|
30
|
+
npm run start:api
|
|
31
|
+
npm run start:worker
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## CLI Examples
|
|
35
|
+
Start the full system (API + web UI + worker):
|
|
36
|
+
```bash
|
|
37
|
+
breakpoints start
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Create a breakpoint (agent):
|
|
41
|
+
```bash
|
|
42
|
+
breakpoints breakpoint create --question "Need approval?" --title "Approval"
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Check status:
|
|
46
|
+
```bash
|
|
47
|
+
breakpoints breakpoint status <id>
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Wait for release:
|
|
51
|
+
```bash
|
|
52
|
+
breakpoints breakpoint wait <id> --interval 3
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Install the babysitter-breakpoint skill:
|
|
56
|
+
```bash
|
|
57
|
+
breakpoints install-skill --target codex --scope global
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Configuration
|
|
61
|
+
Environment variables:
|
|
62
|
+
- `PORT` (default 3185)
|
|
63
|
+
- `WEB_PORT` (default 3184)
|
|
64
|
+
- `DB_PATH` (default `~/.a5c/breakpoints/db/breakpoints.db`)
|
|
65
|
+
- `REPO_ROOT` (default package root / current working directory)
|
|
66
|
+
- `AGENT_TOKEN` (optional)
|
|
67
|
+
- `HUMAN_TOKEN` (optional)
|
|
68
|
+
- `WORKER_POLL_MS` (default 2000)
|
|
69
|
+
- `WORKER_BATCH_SIZE` (default 10)
|
|
70
|
+
|
|
71
|
+
## API Examples
|
|
72
|
+
Create breakpoint (agent):
|
|
73
|
+
```bash
|
|
74
|
+
curl -X POST http://localhost:3185/api/breakpoints \
|
|
75
|
+
-H "Content-Type: application/json" \
|
|
76
|
+
-H "Authorization: Bearer $AGENT_TOKEN" \
|
|
77
|
+
-d '{"agentId":"agent-1","title":"Need review","payload":{"summary":"check this"},"tags":["review"],"ttlSeconds":3600}'
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Check status:
|
|
81
|
+
```bash
|
|
82
|
+
curl http://localhost:3185/api/breakpoints/<id>/status
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
Release with feedback (human):
|
|
86
|
+
```bash
|
|
87
|
+
curl -X POST http://localhost:3185/api/breakpoints/<id>/feedback \
|
|
88
|
+
-H "Content-Type: application/json" \
|
|
89
|
+
-H "Authorization: Bearer $HUMAN_TOKEN" \
|
|
90
|
+
-d '{"author":"reviewer","comment":"Looks good","release":true}'
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## Breakpoint Context Payload
|
|
94
|
+
To enable context rendering in the UI, include a `context.files` array in the
|
|
95
|
+
breakpoint payload:
|
|
96
|
+
```json
|
|
97
|
+
{
|
|
98
|
+
"context": {
|
|
99
|
+
"runId": "run-...",
|
|
100
|
+
"files": [
|
|
101
|
+
{ "path": "docs/plan.md", "format": "markdown" },
|
|
102
|
+
{ "path": "api/routes.js", "format": "code", "language": "javascript" }
|
|
103
|
+
]
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
The API serves file content via:
|
|
109
|
+
```
|
|
110
|
+
GET /api/breakpoints/:id/context?path=path/to/file
|
|
111
|
+
```
|
|
112
|
+
Only allowlisted extensions are served, and the file must be listed in the
|
|
113
|
+
breakpoint payload.
|
|
114
|
+
|
|
115
|
+
## Web UI
|
|
116
|
+
Open `http://localhost:3184` and provide the human token in the UI.
|
|
117
|
+
|
|
118
|
+
## Install the babysitter-breakpoint skill
|
|
119
|
+
```bash
|
|
120
|
+
breakpoints install-skill
|
|
121
|
+
```
|
|
122
|
+
Defaults to global Codex install. Options:
|
|
123
|
+
```bash
|
|
124
|
+
breakpoints install-skill --target codex --scope global
|
|
125
|
+
breakpoints install-skill --target codex --scope local
|
|
126
|
+
breakpoints install-skill --target claude --scope global
|
|
127
|
+
breakpoints install-skill --target claude --scope local
|
|
128
|
+
breakpoints install-skill --target cursor --scope global
|
|
129
|
+
breakpoints install-skill --target cursor --scope local
|
|
130
|
+
```
|
|
131
|
+
Global targets use `CODEX_HOME` or `~/.codex` for Codex, and `~/.claude` or `~/.cursor` for Claude/Cursor. Local installs write to `.codex/skills`, `.claude/skills`, or `.cursor/skills` under the package root. Restart the app after install.
|
|
132
|
+
|
|
133
|
+
When installed from npm, the skill is bundled at `.codex/skills/babysitter-breakpoint/` inside the package and copied to the target location by `breakpoints install-skill`.
|
|
134
|
+
|
|
135
|
+
## Breakpoint CLI (agent-friendly)
|
|
136
|
+
Create a breakpoint:
|
|
137
|
+
```bash
|
|
138
|
+
breakpoints breakpoint create \
|
|
139
|
+
--question "Approve process + inputs + main.js?" \
|
|
140
|
+
--run-id run-123 \
|
|
141
|
+
--title "Approval needed" \
|
|
142
|
+
--file ".a5c/runs/run-123/artifacts/process.md,markdown" \
|
|
143
|
+
--file ".a5c/runs/run-123/inputs.json,code,json" \
|
|
144
|
+
--file ".a5c/runs/run-123/code/main.js,code,javascript"
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
Wait for release (prints full details when released):
|
|
148
|
+
```bash
|
|
149
|
+
breakpoints breakpoint wait <id> --interval 3
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
## Notes
|
|
153
|
+
- Tags are stored as JSON in SQLite; tag filtering uses a simple string match.
|
|
154
|
+
- The queue worker processes TTL expiration jobs; notification jobs are stubbed.
|
package/api/db.js
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const fs = require("fs");
|
|
4
|
+
const path = require("path");
|
|
5
|
+
const os = require("os");
|
|
6
|
+
const sqlite3 = require("sqlite3");
|
|
7
|
+
|
|
8
|
+
function defaultDbPath() {
|
|
9
|
+
const home = os.homedir();
|
|
10
|
+
return path.join(home, ".a5c", "breakpoints", "db", "breakpoints.db");
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function expandHome(value) {
|
|
14
|
+
if (!value) return value;
|
|
15
|
+
if (value === "~") return os.homedir();
|
|
16
|
+
if (value.startsWith(`~${path.sep}`)) {
|
|
17
|
+
return path.join(os.homedir(), value.slice(2));
|
|
18
|
+
}
|
|
19
|
+
if (value.startsWith("~/")) {
|
|
20
|
+
return path.join(os.homedir(), value.slice(2));
|
|
21
|
+
}
|
|
22
|
+
return value;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function resolveDbPath(value) {
|
|
26
|
+
const expanded = expandHome(value);
|
|
27
|
+
if (!expanded) return expanded;
|
|
28
|
+
const normalized = path.normalize(expanded);
|
|
29
|
+
if (normalized.endsWith(path.sep)) {
|
|
30
|
+
return path.join(normalized, "breakpoints.db");
|
|
31
|
+
}
|
|
32
|
+
if (!path.extname(normalized)) {
|
|
33
|
+
return path.join(normalized, "breakpoints.db");
|
|
34
|
+
}
|
|
35
|
+
return normalized;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const DB_PATH = resolveDbPath(process.env.DB_PATH || defaultDbPath());
|
|
39
|
+
|
|
40
|
+
function openDb() {
|
|
41
|
+
fs.mkdirSync(path.dirname(DB_PATH), { recursive: true });
|
|
42
|
+
return new sqlite3.Database(DB_PATH);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function run(db, sql, params = []) {
|
|
46
|
+
return new Promise((resolve, reject) => {
|
|
47
|
+
db.run(sql, params, function onRun(err) {
|
|
48
|
+
if (err) return reject(err);
|
|
49
|
+
resolve(this);
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function get(db, sql, params = []) {
|
|
55
|
+
return new Promise((resolve, reject) => {
|
|
56
|
+
db.get(sql, params, (err, row) => {
|
|
57
|
+
if (err) return reject(err);
|
|
58
|
+
resolve(row);
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function all(db, sql, params = []) {
|
|
64
|
+
return new Promise((resolve, reject) => {
|
|
65
|
+
db.all(sql, params, (err, rows) => {
|
|
66
|
+
if (err) return reject(err);
|
|
67
|
+
resolve(rows);
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
async function initDb(db) {
|
|
73
|
+
const schemaPath = path.join(__dirname, "..", "db", "schema.sql");
|
|
74
|
+
const schema = fs.readFileSync(schemaPath, "utf8");
|
|
75
|
+
fs.mkdirSync(path.dirname(DB_PATH), { recursive: true });
|
|
76
|
+
await run(db, "PRAGMA foreign_keys = ON;");
|
|
77
|
+
const statements = schema
|
|
78
|
+
.split(";")
|
|
79
|
+
.map((statement) => statement.trim())
|
|
80
|
+
.filter((statement) => statement.length);
|
|
81
|
+
for (const statement of statements) {
|
|
82
|
+
await run(db, statement);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
module.exports = {
|
|
87
|
+
DB_PATH,
|
|
88
|
+
openDb,
|
|
89
|
+
run,
|
|
90
|
+
get,
|
|
91
|
+
all,
|
|
92
|
+
initDb,
|
|
93
|
+
};
|