@a5c-ai/babysitter-breakpoints 0.1.3 → 0.1.5

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 CHANGED
@@ -2,17 +2,21 @@
2
2
 
3
3
  Lightweight breakpoint manager with API, queue worker, and web UI.
4
4
 
5
+ This package now lives at `packages/breakpoints`.
6
+
5
7
  ## Requirements
6
8
  - Node.js 18+
7
9
 
8
10
  ## Setup
9
11
  ```bash
12
+ cd packages/breakpoints
10
13
  npm install
11
14
  npm run init:db
12
15
  ```
13
16
 
14
17
  ## Run (dev)
15
18
  ```bash
19
+ cd packages/breakpoints
16
20
  npm run dev
17
21
  ```
18
22
 
@@ -27,12 +31,38 @@ npm run start:api
27
31
  npm run start:worker
28
32
  ```
29
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
+
30
60
  ## Configuration
31
61
  Environment variables:
32
62
  - `PORT` (default 3185)
33
63
  - `WEB_PORT` (default 3184)
34
64
  - `DB_PATH` (default `~/.a5c/breakpoints/db/breakpoints.db`)
35
- - `REPO_ROOT` (default repo root)
65
+ - `REPO_ROOT` (default package root / current working directory)
36
66
  - `AGENT_TOKEN` (optional)
37
67
  - `HUMAN_TOKEN` (optional)
38
68
  - `WORKER_POLL_MS` (default 2000)
@@ -41,7 +71,7 @@ Environment variables:
41
71
  ## API Examples
42
72
  Create breakpoint (agent):
43
73
  ```bash
44
- curl -X POST http://localhost:3000/api/breakpoints \
74
+ curl -X POST http://localhost:3185/api/breakpoints \
45
75
  -H "Content-Type: application/json" \
46
76
  -H "Authorization: Bearer $AGENT_TOKEN" \
47
77
  -d '{"agentId":"agent-1","title":"Need review","payload":{"summary":"check this"},"tags":["review"],"ttlSeconds":3600}'
@@ -49,12 +79,12 @@ curl -X POST http://localhost:3000/api/breakpoints \
49
79
 
50
80
  Check status:
51
81
  ```bash
52
- curl http://localhost:3000/api/breakpoints/<id>/status
82
+ curl http://localhost:3185/api/breakpoints/<id>/status
53
83
  ```
54
84
 
55
85
  Release with feedback (human):
56
86
  ```bash
57
- curl -X POST http://localhost:3000/api/breakpoints/<id>/feedback \
87
+ curl -X POST http://localhost:3185/api/breakpoints/<id>/feedback \
58
88
  -H "Content-Type: application/json" \
59
89
  -H "Authorization: Bearer $HUMAN_TOKEN" \
60
90
  -d '{"author":"reviewer","comment":"Looks good","release":true}'
@@ -83,7 +113,7 @@ Only allowlisted extensions are served, and the file must be listed in the
83
113
  breakpoint payload.
84
114
 
85
115
  ## Web UI
86
- Open `http://localhost:3000` and provide the human token in the UI.
116
+ Open `http://localhost:3184` and provide the human token in the UI.
87
117
 
88
118
  ## Install the babysitter-breakpoint skill
89
119
  ```bash
@@ -98,7 +128,7 @@ breakpoints install-skill --target claude --scope local
98
128
  breakpoints install-skill --target cursor --scope global
99
129
  breakpoints install-skill --target cursor --scope local
100
130
  ```
101
- 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 repo root. Restart the app after install.
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.
102
132
 
103
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`.
104
134
 
package/api/db.js CHANGED
@@ -10,7 +10,32 @@ function defaultDbPath() {
10
10
  return path.join(home, ".a5c", "breakpoints", "db", "breakpoints.db");
11
11
  }
12
12
 
13
- const DB_PATH = process.env.DB_PATH || defaultDbPath();
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());
14
39
 
15
40
  function openDb() {
16
41
  fs.mkdirSync(path.dirname(DB_PATH), { recursive: true });
package/api/server.js CHANGED
@@ -8,6 +8,18 @@ const app = express();
8
8
  const port = process.env.PORT || 3185;
9
9
 
10
10
  app.use(express.json({ limit: "1mb" }));
11
+ app.use((req, res, next) => {
12
+ res.setHeader("Access-Control-Allow-Origin", "*");
13
+ res.setHeader(
14
+ "Access-Control-Allow-Headers",
15
+ "Content-Type, Authorization"
16
+ );
17
+ res.setHeader("Access-Control-Allow-Methods", "GET,POST,OPTIONS");
18
+ if (req.method === "OPTIONS") {
19
+ return res.sendStatus(204);
20
+ }
21
+ return next();
22
+ });
11
23
  app.use("/api", routes);
12
24
  app.use("/", express.static(path.join(__dirname, "..", "web")));
13
25
 
@@ -30,7 +30,7 @@ function runCommand(command, args, options = {}) {
30
30
  }
31
31
 
32
32
  function apiBase() {
33
- return process.env.BREAKPOINT_API_URL || "http://localhost:3000";
33
+ return process.env.BREAKPOINT_API_URL || "http://localhost:3185";
34
34
  }
35
35
 
36
36
  async function httpJson(method, url, body) {
@@ -164,6 +164,7 @@ function runSystem() {
164
164
  ),
165
165
  PORT: process.env.PORT || "3185",
166
166
  WEB_PORT: process.env.WEB_PORT || "3184",
167
+ REPO_ROOT: process.env.REPO_ROOT || process.cwd(),
167
168
  };
168
169
  runCommand("node", [runner], { cwd: repoRoot, env });
169
170
  }
@@ -0,0 +1,56 @@
1
+ -- Initial migration
2
+
3
+ BEGIN;
4
+
5
+ CREATE TABLE IF NOT EXISTS breakpoints (
6
+ id TEXT PRIMARY KEY,
7
+ status TEXT NOT NULL,
8
+ agent_id TEXT NOT NULL,
9
+ run_id TEXT,
10
+ title TEXT,
11
+ payload TEXT NOT NULL,
12
+ tags TEXT,
13
+ ttl_seconds INTEGER,
14
+ created_at TEXT NOT NULL,
15
+ updated_at TEXT NOT NULL,
16
+ released_at TEXT,
17
+ expired_at TEXT,
18
+ cancelled_at TEXT
19
+ );
20
+
21
+ CREATE TABLE IF NOT EXISTS feedback (
22
+ id TEXT PRIMARY KEY,
23
+ breakpoint_id TEXT NOT NULL,
24
+ author TEXT NOT NULL,
25
+ comment TEXT NOT NULL,
26
+ created_at TEXT NOT NULL,
27
+ FOREIGN KEY (breakpoint_id) REFERENCES breakpoints(id)
28
+ );
29
+
30
+ CREATE TABLE IF NOT EXISTS events (
31
+ id TEXT PRIMARY KEY,
32
+ breakpoint_id TEXT NOT NULL,
33
+ type TEXT NOT NULL,
34
+ actor TEXT NOT NULL,
35
+ timestamp TEXT NOT NULL,
36
+ metadata TEXT,
37
+ FOREIGN KEY (breakpoint_id) REFERENCES breakpoints(id)
38
+ );
39
+
40
+ CREATE TABLE IF NOT EXISTS jobs (
41
+ id TEXT PRIMARY KEY,
42
+ type TEXT NOT NULL,
43
+ status TEXT NOT NULL,
44
+ payload TEXT NOT NULL,
45
+ run_at TEXT NOT NULL,
46
+ attempts INTEGER NOT NULL DEFAULT 0,
47
+ last_error TEXT,
48
+ created_at TEXT NOT NULL,
49
+ updated_at TEXT NOT NULL
50
+ );
51
+
52
+ CREATE INDEX IF NOT EXISTS idx_breakpoints_status ON breakpoints(status);
53
+ CREATE INDEX IF NOT EXISTS idx_breakpoints_agent ON breakpoints(agent_id);
54
+ CREATE INDEX IF NOT EXISTS idx_jobs_status_run_at ON jobs(status, run_at);
55
+
56
+ COMMIT;
@@ -0,0 +1,13 @@
1
+ -- Extensions config table
2
+
3
+ BEGIN;
4
+
5
+ CREATE TABLE IF NOT EXISTS extensions_config (
6
+ name TEXT PRIMARY KEY,
7
+ enabled INTEGER NOT NULL DEFAULT 0,
8
+ config_json TEXT NOT NULL,
9
+ created_at TEXT NOT NULL,
10
+ updated_at TEXT NOT NULL
11
+ );
12
+
13
+ COMMIT;
package/db/schema.sql ADDED
@@ -0,0 +1,60 @@
1
+ -- SQLite schema for breakpoint manager
2
+
3
+ CREATE TABLE IF NOT EXISTS breakpoints (
4
+ id TEXT PRIMARY KEY,
5
+ status TEXT NOT NULL,
6
+ agent_id TEXT NOT NULL,
7
+ run_id TEXT,
8
+ title TEXT,
9
+ payload TEXT NOT NULL,
10
+ tags TEXT,
11
+ ttl_seconds INTEGER,
12
+ created_at TEXT NOT NULL,
13
+ updated_at TEXT NOT NULL,
14
+ released_at TEXT,
15
+ expired_at TEXT,
16
+ cancelled_at TEXT
17
+ );
18
+
19
+ CREATE TABLE IF NOT EXISTS feedback (
20
+ id TEXT PRIMARY KEY,
21
+ breakpoint_id TEXT NOT NULL,
22
+ author TEXT NOT NULL,
23
+ comment TEXT NOT NULL,
24
+ created_at TEXT NOT NULL,
25
+ FOREIGN KEY (breakpoint_id) REFERENCES breakpoints(id)
26
+ );
27
+
28
+ CREATE TABLE IF NOT EXISTS events (
29
+ id TEXT PRIMARY KEY,
30
+ breakpoint_id TEXT NOT NULL,
31
+ type TEXT NOT NULL,
32
+ actor TEXT NOT NULL,
33
+ timestamp TEXT NOT NULL,
34
+ metadata TEXT,
35
+ FOREIGN KEY (breakpoint_id) REFERENCES breakpoints(id)
36
+ );
37
+
38
+ CREATE TABLE IF NOT EXISTS jobs (
39
+ id TEXT PRIMARY KEY,
40
+ type TEXT NOT NULL,
41
+ status TEXT NOT NULL,
42
+ payload TEXT NOT NULL,
43
+ run_at TEXT NOT NULL,
44
+ attempts INTEGER NOT NULL DEFAULT 0,
45
+ last_error TEXT,
46
+ created_at TEXT NOT NULL,
47
+ updated_at TEXT NOT NULL
48
+ );
49
+
50
+ CREATE TABLE IF NOT EXISTS extensions_config (
51
+ name TEXT PRIMARY KEY,
52
+ enabled INTEGER NOT NULL DEFAULT 0,
53
+ config_json TEXT NOT NULL,
54
+ created_at TEXT NOT NULL,
55
+ updated_at TEXT NOT NULL
56
+ );
57
+
58
+ CREATE INDEX IF NOT EXISTS idx_breakpoints_status ON breakpoints(status);
59
+ CREATE INDEX IF NOT EXISTS idx_breakpoints_agent ON breakpoints(agent_id);
60
+ CREATE INDEX IF NOT EXISTS idx_jobs_status_run_at ON jobs(status, run_at);
package/package.json CHANGED
@@ -1,26 +1,29 @@
1
- {
2
- "name": "@a5c-ai/babysitter-breakpoints",
3
- "version": "0.1.3",
4
- "private": false,
5
- "type": "commonjs",
6
- "bin": {
7
- "breakpoints": "bin/breakpoints.js"
8
- },
9
- "files": [
10
- "bin/",
11
- "api/",
12
- "worker/",
13
- "extensions/",
14
- ".codex/skills/babysitter-breakpoint/"
15
- ],
16
- "scripts": {
17
- "start:api": "node api/server.js",
18
- "start:worker": "node worker/worker.js",
19
- "dev": "node scripts/dev-runner.js",
20
- "init:db": "node scripts/init-db.js"
21
- },
22
- "dependencies": {
23
- "express": "^4.19.2",
24
- "sqlite3": "^5.1.7"
25
- }
26
- }
1
+ {
2
+ "name": "@a5c-ai/babysitter-breakpoints",
3
+ "version": "0.1.5",
4
+ "private": false,
5
+ "type": "commonjs",
6
+ "bin": {
7
+ "breakpoints": "bin/breakpoints.js"
8
+ },
9
+ "files": [
10
+ "bin/",
11
+ "api/",
12
+ "db/",
13
+ "worker/",
14
+ "extensions/",
15
+ "scripts/",
16
+ "web/",
17
+ ".codex/skills/babysitter-breakpoint/"
18
+ ],
19
+ "scripts": {
20
+ "start:api": "node api/server.js",
21
+ "start:worker": "node worker/worker.js",
22
+ "dev": "node scripts/dev-runner.js",
23
+ "init:db": "node scripts/init-db.js"
24
+ },
25
+ "dependencies": {
26
+ "express": "^4.19.2",
27
+ "sqlite3": "^5.1.7"
28
+ }
29
+ }
@@ -0,0 +1,41 @@
1
+ "use strict";
2
+
3
+ const { spawn } = require("child_process");
4
+ const path = require("path");
5
+
6
+ const repoRoot = path.join(__dirname, "..");
7
+ const defaultEnv = {
8
+ DB_PATH:
9
+ process.env.DB_PATH ||
10
+ path.join(
11
+ require("os").homedir(),
12
+ ".a5c",
13
+ "breakpoints",
14
+ "db",
15
+ "breakpoints.db"
16
+ ),
17
+ PORT: process.env.PORT || "3185",
18
+ WEB_PORT: process.env.WEB_PORT || "3184",
19
+ REPO_ROOT: process.env.REPO_ROOT || process.cwd(),
20
+ };
21
+
22
+ function run(label, command, args) {
23
+ const proc = spawn(command, args, {
24
+ stdio: "inherit",
25
+ env: { ...process.env, ...defaultEnv },
26
+ shell: true,
27
+ cwd: repoRoot,
28
+ });
29
+ proc.on("exit", (code) => {
30
+ if (code) {
31
+ // eslint-disable-next-line no-console
32
+ console.error(`${label} exited with code ${code}`);
33
+ process.exitCode = code;
34
+ }
35
+ });
36
+ return proc;
37
+ }
38
+
39
+ run("api", "node", [path.join(repoRoot, "api", "server.js")]);
40
+ run("web", "node", [path.join(repoRoot, "web", "server.js")]);
41
+ run("worker", "node", [path.join(repoRoot, "worker", "worker.js")]);
@@ -0,0 +1,10 @@
1
+ $ErrorActionPreference = "Stop"
2
+
3
+ $repoRoot = (Resolve-Path (Join-Path $PSScriptRoot ".."))
4
+
5
+ Write-Host "Starting API and worker..."
6
+ Start-Process -FilePath "node" -ArgumentList (Join-Path $repoRoot "api/server.js") -NoNewWindow
7
+ Start-Process -FilePath "node" -ArgumentList (Join-Path $repoRoot "worker/worker.js") -NoNewWindow
8
+
9
+ Write-Host "API: http://localhost:3185"
10
+ Write-Host "Use Ctrl+C to stop."
package/scripts/dev.sh ADDED
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env sh
2
+ set -e
3
+
4
+ script_dir="$(cd "$(dirname "$0")" && pwd)"
5
+ repo_root="$(cd "$script_dir/.." && pwd)"
6
+
7
+ echo "Starting API and worker..."
8
+ node "$repo_root/api/server.js" &
9
+ node "$repo_root/worker/worker.js" &
10
+
11
+ echo "API: http://localhost:3185"
12
+ echo "Press Ctrl+C to stop."
13
+ wait
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+
3
+ const { openDb, initDb, DB_PATH } = require("../api/db");
4
+
5
+ async function main() {
6
+ const db = openDb();
7
+ try {
8
+ await initDb(db);
9
+ // eslint-disable-next-line no-console
10
+ console.log(`Database initialized at ${DB_PATH}`);
11
+ } finally {
12
+ db.close();
13
+ }
14
+ }
15
+
16
+ main().catch((err) => {
17
+ // eslint-disable-next-line no-console
18
+ console.error(err);
19
+ process.exitCode = 1;
20
+ });