@agentreel/agent 0.1.4 → 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/dist/cli.js CHANGED
@@ -123,6 +123,13 @@ var init_install = __esm({
123
123
 
124
124
  // src/config.ts
125
125
  import { readFileSync as readFileSync2, writeFileSync as writeFileSync2, existsSync as existsSync2, chmodSync } from "fs";
126
+ function isCaptureDisabledByEnv() {
127
+ const v = process.env.AGENTREEL_DISABLE;
128
+ return v === "1" || v === "true" || v === "yes";
129
+ }
130
+ function isCapturePaused(cfg = readConfig()) {
131
+ return isCaptureDisabledByEnv() || cfg.paused === true;
132
+ }
126
133
  function readConfig() {
127
134
  if (!existsSync2(CONFIG_PATH)) return { ...DEFAULT };
128
135
  try {
@@ -749,7 +756,13 @@ async function initCommand() {
749
756
  );
750
757
  }
751
758
  console.log(
752
- "\n" + pc.dim("Anything: ") + pc.cyan("agentreel status") + pc.dim(" shows queue, last sync, last error.\n")
759
+ "\n" + pc.dim("Anything: ") + pc.cyan("agentreel status") + pc.dim(" shows queue, last sync, last error.")
760
+ );
761
+ console.log(
762
+ pc.dim("Privacy: ") + pc.cyan("agentreel pause") + pc.dim(" to stop capturing temporarily, ") + pc.cyan("agentreel forget --all") + pc.dim(" to wipe local sessions.")
763
+ );
764
+ console.log(
765
+ pc.dim(" Or set ") + pc.cyan("AGENTREEL_DISABLE=1") + pc.dim(" before launching Claude Code to skip a single session.\n")
753
766
  );
754
767
  }
755
768
 
@@ -797,6 +810,15 @@ async function statusCommand() {
797
810
  );
798
811
  console.log(" api base: " + cfg.apiBaseUrl);
799
812
  console.log(" authenticated: " + (cfg.apiKey ? pc2.green("yes") : pc2.yellow("no")));
813
+ if (cfg.paused) {
814
+ const since = cfg.pausedAt ? new Date(cfg.pausedAt).toLocaleString() : "?";
815
+ console.log(" capture: " + pc2.yellow(`paused (since ${since})`));
816
+ console.log(pc2.dim(" run `agentreel resume` to capture again"));
817
+ } else if (isCaptureDisabledByEnv()) {
818
+ console.log(" capture: " + pc2.yellow("disabled (AGENTREEL_DISABLE in env)"));
819
+ } else {
820
+ console.log(" capture: " + pc2.green("active"));
821
+ }
800
822
  const d = daemonStatus();
801
823
  console.log(
802
824
  " daemon: " + (d.running ? pc2.green(`running (pid ${d.pid})`) : pc2.dim("stopped"))
@@ -1325,12 +1347,16 @@ var NOISY_PATH = /[\\/](node_modules|\.next|\.turbo|dist|build|\.git|coverage|\.
1325
1347
 
1326
1348
  // src/cursor/session.ts
1327
1349
  init_db();
1350
+ init_config();
1328
1351
  import { nanoid } from "nanoid";
1329
1352
  var IDLE_MS = 5 * 60 * 1e3;
1330
1353
  var GLOBAL_KEY = "__global__";
1331
1354
  var CursorSessionManager = class {
1332
1355
  open = /* @__PURE__ */ new Map();
1333
1356
  ingest(snapshot) {
1357
+ if (isCapturePaused()) {
1358
+ return { sessionId: "__paused__", isNew: false };
1359
+ }
1334
1360
  const key = snapshot.workspace ?? GLOBAL_KEY;
1335
1361
  const ts2 = snapshot.timestamp;
1336
1362
  const cwd = snapshot.workspace ?? "";
@@ -1482,6 +1508,135 @@ async function pushCommand() {
1482
1508
  // src/cli.ts
1483
1509
  init_daemon();
1484
1510
 
1511
+ // src/commands/privacy.ts
1512
+ init_config();
1513
+ init_db();
1514
+ import pc7 from "picocolors";
1515
+ import { createInterface } from "readline";
1516
+ function pauseCommand() {
1517
+ const cfg = readConfig();
1518
+ if (cfg.paused) {
1519
+ console.log(pc7.dim("\xB7 already paused"));
1520
+ if (cfg.pausedAt) {
1521
+ console.log(pc7.dim(` since ${new Date(cfg.pausedAt).toLocaleString()}`));
1522
+ }
1523
+ return;
1524
+ }
1525
+ cfg.paused = true;
1526
+ cfg.pausedAt = Date.now();
1527
+ writeConfig(cfg);
1528
+ console.log(pc7.yellow("\u23F8 capture paused"));
1529
+ console.log(
1530
+ pc7.dim(
1531
+ " Claude Code hooks and the Cursor watcher will no-op until you " + pc7.cyan("agentreel resume") + pc7.dim(".")
1532
+ )
1533
+ );
1534
+ console.log(
1535
+ pc7.dim(
1536
+ " Existing local events stay put. They won't upload while paused (the daemon still runs, but the queue won't grow)."
1537
+ )
1538
+ );
1539
+ }
1540
+ function resumeCommand() {
1541
+ const cfg = readConfig();
1542
+ if (!cfg.paused) {
1543
+ console.log(pc7.dim("\xB7 capture is already active"));
1544
+ return;
1545
+ }
1546
+ const pausedAt = cfg.pausedAt;
1547
+ cfg.paused = false;
1548
+ cfg.pausedAt = void 0;
1549
+ writeConfig(cfg);
1550
+ const duration = pausedAt ? fmtDuration2(Date.now() - pausedAt) : null;
1551
+ console.log(pc7.green("\u25B6 capture resumed"));
1552
+ if (duration) {
1553
+ console.log(pc7.dim(` paused for ${duration}`));
1554
+ }
1555
+ }
1556
+ async function forgetCommand(ids, opts) {
1557
+ const db = getDb();
1558
+ if (opts.all) {
1559
+ const total = db.prepare(`SELECT COUNT(*) AS c FROM sessions`).get().c;
1560
+ if (total === 0) {
1561
+ console.log(pc7.dim("\xB7 nothing to forget \u2014 local DB is empty"));
1562
+ return;
1563
+ }
1564
+ if (!opts.force && !await confirm(`Delete all ${total} local sessions? `)) {
1565
+ console.log(pc7.dim("\xB7 cancelled"));
1566
+ return;
1567
+ }
1568
+ db.transaction(() => {
1569
+ db.exec(`DELETE FROM events`);
1570
+ db.exec(`DELETE FROM sessions`);
1571
+ db.exec(`DELETE FROM meta WHERE key LIKE 'cost_%'`);
1572
+ })();
1573
+ console.log(pc7.green("\u2713") + ` forgot ${total} sessions and their events`);
1574
+ console.log(
1575
+ pc7.dim(
1576
+ " Cloud-side rows are untouched. Delete them from the dashboard if you also want them gone from agentreel.dev."
1577
+ )
1578
+ );
1579
+ return;
1580
+ }
1581
+ if (ids.length === 0) {
1582
+ console.error(
1583
+ pc7.red("\u2717 provide one or more session ids, or --all to wipe everything")
1584
+ );
1585
+ console.error(pc7.dim(` example: agentreel forget abcd1234`));
1586
+ process.exit(1);
1587
+ }
1588
+ const stmt = db.prepare(
1589
+ `SELECT id FROM sessions WHERE id = ? OR id LIKE ?`
1590
+ );
1591
+ const delEvents = db.prepare(`DELETE FROM events WHERE session_id = ?`);
1592
+ const delSession = db.prepare(`DELETE FROM sessions WHERE id = ?`);
1593
+ const delMeta = db.prepare(`DELETE FROM meta WHERE key LIKE ?`);
1594
+ const matched = [];
1595
+ for (const raw of ids) {
1596
+ const rows = stmt.all(raw, `${raw}%`);
1597
+ if (rows.length === 0) {
1598
+ console.error(pc7.yellow(`\xB7 no session matched "${raw}"`));
1599
+ continue;
1600
+ }
1601
+ for (const r of rows) matched.push(r.id);
1602
+ }
1603
+ if (matched.length === 0) {
1604
+ console.error(pc7.red("\u2717 nothing matched, nothing deleted"));
1605
+ process.exit(1);
1606
+ }
1607
+ if (!opts.force && !await confirm(`Delete ${matched.length} session(s) and their events? `)) {
1608
+ console.log(pc7.dim("\xB7 cancelled"));
1609
+ return;
1610
+ }
1611
+ db.transaction(() => {
1612
+ for (const id of matched) {
1613
+ delEvents.run(id);
1614
+ delSession.run(id);
1615
+ delMeta.run(`cost_%:${id}`);
1616
+ }
1617
+ })();
1618
+ console.log(pc7.green("\u2713") + ` forgot ${matched.length} session(s)`);
1619
+ }
1620
+ function confirm(prompt) {
1621
+ return new Promise((resolve2) => {
1622
+ const rl = createInterface({ input: process.stdin, output: process.stdout });
1623
+ rl.question(prompt + "[y/N] ", (answer) => {
1624
+ rl.close();
1625
+ resolve2(/^y(es)?$/i.test(answer.trim()));
1626
+ });
1627
+ });
1628
+ }
1629
+ function fmtDuration2(ms) {
1630
+ const s = Math.round(ms / 1e3);
1631
+ if (s < 60) return `${s}s`;
1632
+ const m = Math.floor(s / 60);
1633
+ if (m < 60) return `${m}m ${s % 60}s`;
1634
+ const h = Math.floor(m / 60);
1635
+ if (h < 24) return `${h}h ${m % 60}m`;
1636
+ const d = Math.floor(h / 24);
1637
+ return `${d}d ${h % 24}h`;
1638
+ }
1639
+
1485
1640
  // src/hooks/handler.ts
1486
1641
  init_db();
1487
1642
  init_paths();
@@ -1588,6 +1743,7 @@ function recomputeSessionCost(sessionId, transcriptPath) {
1588
1743
  }
1589
1744
 
1590
1745
  // src/hooks/handler.ts
1746
+ init_config();
1591
1747
  var HOOK_EVENT_TO_TYPE = {
1592
1748
  SessionStart: "session_start",
1593
1749
  SessionEnd: "session_end",
@@ -1618,6 +1774,10 @@ function logError(err) {
1618
1774
  }
1619
1775
  async function runHook(eventArg) {
1620
1776
  try {
1777
+ if (isCapturePaused()) {
1778
+ await readStdin().catch(() => "");
1779
+ return;
1780
+ }
1621
1781
  const raw = await readStdin();
1622
1782
  if (!raw.trim()) return;
1623
1783
  const input = JSON.parse(raw);
@@ -1670,7 +1830,7 @@ async function runHook(eventArg) {
1670
1830
  }
1671
1831
 
1672
1832
  // src/cli.ts
1673
- var VERSION = true ? "0.1.4" : "dev";
1833
+ var VERSION = true ? "0.1.5" : "dev";
1674
1834
  var program = new Command();
1675
1835
  program.name("agentreel").description("AgentReel \u2014 capture Claude Code and Cursor sessions locally").version(VERSION);
1676
1836
  program.command("init").description("install Claude Code hooks and create the local SQLite buffer").action(async () => {
@@ -1694,6 +1854,15 @@ program.command("daemon").description("run the background uploader (30s ticks, 1
1694
1854
  program.command("stop").description("stop the running background uploader").action(() => {
1695
1855
  stopCommand();
1696
1856
  });
1857
+ program.command("pause").description("pause local capture \u2014 hooks and watcher no-op until `resume`").action(() => {
1858
+ pauseCommand();
1859
+ });
1860
+ program.command("resume").description("resume local capture after `pause`").action(() => {
1861
+ resumeCommand();
1862
+ });
1863
+ program.command("forget [session-ids...]").description("delete captured sessions from the local SQLite buffer").option("--all", "wipe every session (asks for confirmation)").option("--force", "skip the confirmation prompt (use with care)").action(async (ids, opts) => {
1864
+ await forgetCommand(ids ?? [], opts);
1865
+ });
1697
1866
  program.command("logout").description("clear local credentials").action(async () => {
1698
1867
  await logoutCommand();
1699
1868
  });
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/paths.ts","../src/hooks/install.ts","../src/config.ts","../src/db.ts","../src/upload/client.ts","../src/upload/queue.ts","../src/upload/flush.ts","../src/commands/daemon.ts","../src/cli.ts","../src/commands/init.ts","../src/commands/status.ts","../src/commands/auth.ts","../src/commands/watch.ts","../src/cursor/paths.ts","../src/cursor/watcher.ts","../src/cursor/entries.ts","../src/cursor/diff.ts","../src/redact/ignore.ts","../src/redact/patterns.ts","../src/redact/scrubber.ts","../src/cursor/session.ts","../src/commands/push.ts","../src/hooks/handler.ts","../src/cost/transcript.ts","../src/cost/pricing.ts"],"sourcesContent":["import { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { mkdirSync } from \"node:fs\";\n\nexport const HOME = homedir();\nexport const AGENTREEL_DIR = join(HOME, \".agentreel\");\nexport const DB_PATH = join(AGENTREEL_DIR, \"sessions.db\");\nexport const CONFIG_PATH = join(AGENTREEL_DIR, \"config.json\");\nexport const QUEUE_DIR = join(AGENTREEL_DIR, \"queue\");\nexport const LOG_PATH = join(AGENTREEL_DIR, \"agent.log\");\nexport const DAEMON_PID_PATH = join(AGENTREEL_DIR, \"daemon.pid\");\nexport const DAEMON_LOG_PATH = join(AGENTREEL_DIR, \"daemon.log\");\n\nexport const CLAUDE_DIR = join(HOME, \".claude\");\nexport const CLAUDE_SETTINGS_PATH = join(CLAUDE_DIR, \"settings.json\");\n\nexport function ensureAgentreelDir(): void {\n mkdirSync(AGENTREEL_DIR, { recursive: true });\n mkdirSync(QUEUE_DIR, { recursive: true });\n}\n","import { readFileSync, writeFileSync, existsSync, copyFileSync, mkdirSync } from \"node:fs\";\nimport { dirname } from \"node:path\";\nimport { CLAUDE_DIR, CLAUDE_SETTINGS_PATH } from \"../paths.js\";\n\nconst HOOK_MARKER = \"agentreel:v1\";\n\nconst HOOK_EVENTS = [\n \"SessionStart\",\n \"SessionEnd\",\n \"UserPromptSubmit\",\n \"PreToolUse\",\n \"PostToolUse\",\n \"Notification\",\n \"Stop\",\n \"SubagentStop\",\n \"PreCompact\",\n] as const;\n\ntype HookEntry = {\n type: \"command\";\n command: string;\n timeout?: number;\n};\n\ntype HookGroup = {\n matcher?: string;\n hooks: HookEntry[];\n __agentreel?: string;\n};\n\ntype ClaudeSettings = {\n hooks?: Record<string, HookGroup[]>;\n [key: string]: unknown;\n};\n\nfunction readSettings(): ClaudeSettings {\n if (!existsSync(CLAUDE_SETTINGS_PATH)) return {};\n const raw = readFileSync(CLAUDE_SETTINGS_PATH, \"utf8\");\n if (!raw.trim()) return {};\n return JSON.parse(raw) as ClaudeSettings;\n}\n\nfunction backupSettings(): string | null {\n if (!existsSync(CLAUDE_SETTINGS_PATH)) return null;\n const stamp = new Date().toISOString().replace(/[:.]/g, \"-\");\n const backup = `${CLAUDE_SETTINGS_PATH}.agentreel-backup-${stamp}`;\n copyFileSync(CLAUDE_SETTINGS_PATH, backup);\n return backup;\n}\n\nfunction buildHookEntry(event: string, hookCommandPrefix: string): HookEntry {\n // Final command shape: `<prefix> hook <Event>`. The prefix can be an\n // absolute path to dist/cli.js (global / dev installs) or an `npx -y …`\n // form (when the user ran us via npx and we don't have a stable on-disk\n // location to point Claude Code at).\n return {\n type: \"command\",\n command: `${hookCommandPrefix} hook ${event}`,\n timeout: 5,\n };\n}\n\nexport function quotePath(p: string): string {\n return /[\\s'\"$`\\\\]/.test(p) ? `\"${p.replace(/\"/g, '\\\\\"')}\"` : p;\n}\n\nexport interface InstallResult {\n backup: string | null;\n installedEvents: string[];\n hookCommandPrefix: string;\n}\n\nexport function installClaudeCodeHooks(hookCommandPrefix: string): InstallResult {\n mkdirSync(CLAUDE_DIR, { recursive: true });\n mkdirSync(dirname(CLAUDE_SETTINGS_PATH), { recursive: true });\n const backup = backupSettings();\n\n const settings = readSettings();\n settings.hooks ??= {};\n\n for (const event of HOOK_EVENTS) {\n const groups = settings.hooks[event] ?? [];\n // Drop any prior agentreel-managed group so re-running is idempotent.\n const filtered = groups.filter((g) => g.__agentreel !== HOOK_MARKER);\n filtered.push({\n matcher: \".*\",\n __agentreel: HOOK_MARKER,\n hooks: [buildHookEntry(event, hookCommandPrefix)],\n });\n settings.hooks[event] = filtered;\n }\n\n writeFileSync(CLAUDE_SETTINGS_PATH, JSON.stringify(settings, null, 2) + \"\\n\", \"utf8\");\n return { backup, installedEvents: [...HOOK_EVENTS], hookCommandPrefix };\n}\n\nexport function uninstallClaudeCodeHooks(): { backup: string | null } {\n if (!existsSync(CLAUDE_SETTINGS_PATH)) return { backup: null };\n const backup = backupSettings();\n const settings = readSettings();\n if (settings.hooks) {\n for (const event of Object.keys(settings.hooks)) {\n const groups = settings.hooks[event] ?? [];\n const remaining = groups.filter((g) => g.__agentreel !== HOOK_MARKER);\n if (remaining.length === 0) delete settings.hooks[event];\n else settings.hooks[event] = remaining;\n }\n if (Object.keys(settings.hooks).length === 0) delete settings.hooks;\n }\n writeFileSync(CLAUDE_SETTINGS_PATH, JSON.stringify(settings, null, 2) + \"\\n\", \"utf8\");\n return { backup };\n}\n","import { readFileSync, writeFileSync, existsSync, chmodSync } from \"node:fs\";\nimport { CONFIG_PATH, ensureAgentreelDir } from \"./paths.js\";\n\nexport interface AgentConfig {\n apiKey?: string;\n apiBaseUrl: string;\n workspaceId?: string;\n installedAt?: number;\n hooksInstalled?: boolean;\n schemaVersion: 1;\n}\n\nconst DEFAULT: AgentConfig = {\n apiBaseUrl: \"https://api.agentreel.dev\",\n schemaVersion: 1,\n};\n\nexport function readConfig(): AgentConfig {\n if (!existsSync(CONFIG_PATH)) return { ...DEFAULT };\n try {\n const raw = readFileSync(CONFIG_PATH, \"utf8\");\n return { ...DEFAULT, ...JSON.parse(raw) };\n } catch {\n return { ...DEFAULT };\n }\n}\n\nexport function writeConfig(cfg: AgentConfig): void {\n ensureAgentreelDir();\n // mode 0o600 — config.json holds the API key; only the owning user\n // should ever be able to read it. chmod after write to be sure even\n // if the file already existed with looser perms.\n writeFileSync(CONFIG_PATH, JSON.stringify(cfg, null, 2) + \"\\n\", {\n encoding: \"utf8\",\n mode: 0o600,\n });\n try {\n chmodSync(CONFIG_PATH, 0o600);\n } catch {\n // Non-Unix or filesystem without mode bits — best effort.\n }\n}\n","import Database from \"better-sqlite3\";\nimport type { Database as DB } from \"better-sqlite3\";\nimport { DB_PATH, ensureAgentreelDir } from \"./paths.js\";\nimport type { AgentEvent, Session, Tool } from \"@agentreel/shared-types\";\n\nlet _db: DB | null = null;\n\nexport function getDb(): DB {\n if (_db) return _db;\n ensureAgentreelDir();\n const db = new Database(DB_PATH);\n db.pragma(\"journal_mode = WAL\");\n db.pragma(\"synchronous = NORMAL\");\n migrate(db);\n _db = db;\n return db;\n}\n\nfunction migrate(db: DB): void {\n db.exec(`\n CREATE TABLE IF NOT EXISTS sessions (\n id TEXT PRIMARY KEY,\n tool TEXT NOT NULL,\n started_at INTEGER NOT NULL,\n ended_at INTEGER,\n cwd TEXT,\n total_cost_cents INTEGER,\n total_tokens INTEGER\n );\n CREATE TABLE IF NOT EXISTS events (\n id TEXT PRIMARY KEY,\n session_id TEXT NOT NULL,\n tool TEXT NOT NULL,\n type TEXT NOT NULL,\n ts INTEGER NOT NULL,\n cwd TEXT,\n payload TEXT NOT NULL,\n uploaded_at INTEGER\n );\n CREATE INDEX IF NOT EXISTS idx_events_session ON events(session_id, ts);\n CREATE INDEX IF NOT EXISTS idx_events_pending ON events(uploaded_at) WHERE uploaded_at IS NULL;\n CREATE TABLE IF NOT EXISTS meta (\n key TEXT PRIMARY KEY,\n value TEXT\n );\n `);\n}\n\nexport function getMeta(key: string): string | null {\n const db = getDb();\n const row = db.prepare(`SELECT value FROM meta WHERE key = ?`).get(key) as\n | { value: string }\n | undefined;\n return row?.value ?? null;\n}\n\nexport function setMeta(key: string, value: string | null): void {\n const db = getDb();\n if (value == null) {\n db.prepare(`DELETE FROM meta WHERE key = ?`).run(key);\n return;\n }\n db.prepare(\n `INSERT INTO meta (key, value) VALUES (?, ?)\n ON CONFLICT(key) DO UPDATE SET value = excluded.value`,\n ).run(key, value);\n}\n\nexport function pendingByteSize(): number {\n const db = getDb();\n const row = db\n .prepare(\n `SELECT COALESCE(SUM(LENGTH(payload)), 0) AS bytes\n FROM events WHERE uploaded_at IS NULL`,\n )\n .get() as { bytes: number };\n return row.bytes;\n}\n\nexport function upsertSession(s: Session): void {\n const db = getDb();\n db.prepare(\n `INSERT INTO sessions (id, tool, started_at, ended_at, cwd, total_cost_cents, total_tokens)\n VALUES (@id, @tool, @startedAt, @endedAt, @cwd, @totalCostCents, @totalTokens)\n ON CONFLICT(id) DO UPDATE SET\n ended_at = COALESCE(excluded.ended_at, sessions.ended_at),\n cwd = COALESCE(excluded.cwd, sessions.cwd),\n total_cost_cents = COALESCE(excluded.total_cost_cents, sessions.total_cost_cents),\n total_tokens = COALESCE(excluded.total_tokens, sessions.total_tokens)`,\n ).run({\n id: s.id,\n tool: s.tool,\n startedAt: s.startedAt,\n endedAt: s.endedAt ?? null,\n cwd: s.cwd ?? null,\n totalCostCents: s.totalCostCents ?? null,\n totalTokens: s.totalTokens ?? null,\n });\n}\n\nexport function insertEvent(e: AgentEvent): void {\n const db = getDb();\n db.prepare(\n `INSERT OR IGNORE INTO events (id, session_id, tool, type, ts, cwd, payload)\n VALUES (?, ?, ?, ?, ?, ?, ?)`,\n ).run(e.id, e.sessionId, e.tool, e.type, e.ts, e.cwd ?? null, JSON.stringify(e.payload ?? {}));\n}\n\nexport function countEvents(): { total: number; pending: number } {\n const db = getDb();\n const total = db.prepare(`SELECT COUNT(*) AS c FROM events`).get() as { c: number };\n const pending = db\n .prepare(`SELECT COUNT(*) AS c FROM events WHERE uploaded_at IS NULL`)\n .get() as { c: number };\n return { total: total.c, pending: pending.c };\n}\n\nexport function listRecentSessions(limit = 10): Array<{\n id: string;\n tool: Tool;\n started_at: number;\n ended_at: number | null;\n cwd: string | null;\n}> {\n const db = getDb();\n return db\n .prepare(\n `SELECT id, tool, started_at, ended_at, cwd\n FROM sessions ORDER BY started_at DESC LIMIT ?`,\n )\n .all(limit) as Array<{\n id: string;\n tool: Tool;\n started_at: number;\n ended_at: number | null;\n cwd: string | null;\n }>;\n}\n","import type { AgentConfig } from \"../config.js\";\n\nexport interface IngestSession {\n id: string;\n tool: string;\n started_at: number;\n ended_at?: number | null;\n cwd?: string | null;\n total_cost_cents?: number | null;\n total_tokens?: number | null;\n}\n\nexport interface IngestEvent {\n id: string;\n session_id: string;\n ts: number;\n type: string;\n tool: string;\n cwd?: string | null;\n payload: unknown;\n}\n\nexport interface IngestResponse {\n ok: boolean;\n sessions_written?: number;\n events_written?: number;\n error?: string;\n reason?: string;\n}\n\nexport class IngestError extends Error {\n constructor(\n message: string,\n readonly status: number,\n readonly body: IngestResponse | null,\n ) {\n super(message);\n this.name = \"IngestError\";\n }\n /** 4xx (except 408/429) — payload-shaped problem the agent can't fix by retrying. */\n get isPermanent(): boolean {\n return this.status >= 400 && this.status < 500 && this.status !== 408 && this.status !== 429;\n }\n}\n\nexport async function postIngest(\n cfg: AgentConfig,\n body: { sessions?: IngestSession[]; events?: IngestEvent[] },\n): Promise<IngestResponse> {\n if (!cfg.apiKey) {\n throw new Error(\"Not linked. Run: agentreel link <key>\");\n }\n const url = `${cfg.apiBaseUrl.replace(/\\/$/, \"\")}/api/v1/sessions/ingest`;\n const res = await fetch(url, {\n method: \"POST\",\n headers: {\n \"content-type\": \"application/json\",\n authorization: `Bearer ${cfg.apiKey}`,\n },\n body: JSON.stringify(body),\n });\n let data: IngestResponse | null = null;\n try {\n data = (await res.json()) as IngestResponse;\n } catch {\n // Non-JSON body — treat as transient if 5xx, permanent otherwise.\n }\n if (!res.ok || !data?.ok) {\n const reason = data?.reason ? ` (${data.reason})` : \"\";\n const tag = data?.error ?? `http-${res.status}`;\n throw new IngestError(`${tag}${reason}`, res.status, data);\n }\n return data;\n}\n","import { getDb } from \"../db.js\";\nimport type { IngestEvent, IngestSession } from \"./client.js\";\n\ninterface DBSessionRow {\n id: string;\n tool: string;\n started_at: number;\n ended_at: number | null;\n cwd: string | null;\n total_cost_cents: number | null;\n total_tokens: number | null;\n}\n\ninterface DBEventRow {\n id: string;\n session_id: string;\n tool: string;\n type: string;\n ts: number;\n cwd: string | null;\n payload: string;\n}\n\nexport interface PendingBatch {\n sessions: IngestSession[];\n events: IngestEvent[];\n eventIds: string[]; // for the post-write mark\n}\n\n// Cloud cap is 5 MB; we stay well under that to leave room for JSON framing\n// + auth headers and to keep individual round-trips snappy.\nexport const MAX_BATCH_BYTES = 1024 * 1024; // 1 MB\nexport const MAX_BATCH_EVENTS = 500;\n\nexport function takePendingBatch(\n maxEvents = MAX_BATCH_EVENTS,\n maxBytes = MAX_BATCH_BYTES,\n): PendingBatch {\n const db = getDb();\n const candidateRows = db\n .prepare(\n `SELECT id, session_id, tool, type, ts, cwd, payload\n FROM events\n WHERE uploaded_at IS NULL\n ORDER BY ts ASC\n LIMIT ?`,\n )\n .all(maxEvents) as DBEventRow[];\n\n if (candidateRows.length === 0) return { sessions: [], events: [], eventIds: [] };\n\n // Trim to byte budget. Always include at least one event so a single\n // oversized payload doesn't get stuck in the queue forever — the server\n // can reject it and we'll mark it uploaded to skip past.\n const eventRows: DBEventRow[] = [];\n let bytes = 0;\n for (const row of candidateRows) {\n const rowBytes = Buffer.byteLength(row.payload, \"utf8\");\n if (eventRows.length > 0 && bytes + rowBytes > maxBytes) break;\n eventRows.push(row);\n bytes += rowBytes;\n }\n\n const sessionIds = [...new Set(eventRows.map((e) => e.session_id))];\n const placeholders = sessionIds.map(() => \"?\").join(\",\");\n const sessionRows = db\n .prepare(\n `SELECT id, tool, started_at, ended_at, cwd, total_cost_cents, total_tokens\n FROM sessions WHERE id IN (${placeholders})`,\n )\n .all(...sessionIds) as DBSessionRow[];\n\n const sessions: IngestSession[] = sessionRows.map((s) => ({\n id: s.id,\n tool: s.tool,\n started_at: s.started_at,\n ended_at: s.ended_at,\n cwd: s.cwd,\n total_cost_cents: s.total_cost_cents,\n total_tokens: s.total_tokens,\n }));\n\n const events: IngestEvent[] = eventRows.map((e) => ({\n id: e.id,\n session_id: e.session_id,\n ts: e.ts,\n type: e.type,\n tool: e.tool,\n cwd: e.cwd,\n payload: safeParse(e.payload),\n }));\n\n return { sessions, events, eventIds: eventRows.map((r) => r.id) };\n}\n\nexport function markUploaded(eventIds: string[]): void {\n if (eventIds.length === 0) return;\n const db = getDb();\n const now = Date.now();\n const stmt = db.prepare(`UPDATE events SET uploaded_at = ? WHERE id = ?`);\n const tx = db.transaction((ids: string[]) => {\n for (const id of ids) stmt.run(now, id);\n });\n tx(eventIds);\n}\n\nfunction safeParse(s: string): unknown {\n try {\n return JSON.parse(s);\n } catch {\n return s;\n }\n}\n","import { getMeta, setMeta } from \"../db.js\";\nimport { readConfig } from \"../config.js\";\nimport { IngestError, postIngest } from \"./client.js\";\nimport { MAX_BATCH_BYTES, MAX_BATCH_EVENTS, markUploaded, takePendingBatch } from \"./queue.js\";\n\nexport const META_LAST_SYNC_AT = \"last_sync_at\";\nexport const META_LAST_ERROR_AT = \"last_error_at\";\nexport const META_LAST_ERROR_MSG = \"last_error_msg\";\nexport const META_CONSECUTIVE_FAILS = \"consecutive_failures\";\nexport const META_NEXT_ATTEMPT_AT = \"next_attempt_at\";\n\nconst BACKOFF_BASE_MS = 1_000;\nconst BACKOFF_MAX_MS = 5 * 60_000;\n\nexport interface FlushResult {\n uploadedEvents: number;\n uploadedSessions: number;\n /** True if there are still events pending after this flush (hit batch cap, more to do). */\n moreAvailable: boolean;\n}\n\n/** Compute the wall-clock time the next attempt is allowed to start. */\nexport function nextAttemptAt(): number {\n const raw = getMeta(META_NEXT_ATTEMPT_AT);\n return raw ? Number(raw) : 0;\n}\n\nexport function consecutiveFailures(): number {\n const raw = getMeta(META_CONSECUTIVE_FAILS);\n return raw ? Number(raw) : 0;\n}\n\nfunction recordSuccess() {\n const now = Date.now();\n setMeta(META_LAST_SYNC_AT, String(now));\n setMeta(META_LAST_ERROR_AT, null);\n setMeta(META_LAST_ERROR_MSG, null);\n setMeta(META_CONSECUTIVE_FAILS, \"0\");\n setMeta(META_NEXT_ATTEMPT_AT, \"0\");\n}\n\nfunction recordFailure(err: Error, permanent: boolean) {\n const now = Date.now();\n const fails = consecutiveFailures() + 1;\n setMeta(META_LAST_ERROR_AT, String(now));\n setMeta(META_LAST_ERROR_MSG, truncate(err.message, 500));\n setMeta(META_CONSECUTIVE_FAILS, String(fails));\n if (permanent) {\n // Permanent errors (4xx like bad-prefix, plan-limit) — back off the\n // longest window so we don't hammer the server, but don't give up\n // forever; user may upgrade plan or re-link, and we want the next\n // tick to recover within minutes.\n setMeta(META_NEXT_ATTEMPT_AT, String(now + BACKOFF_MAX_MS));\n return;\n }\n // Exponential: 1s, 2s, 4s, ..., capped at 5min, with 0–25% jitter.\n const exp = Math.min(BACKOFF_MAX_MS, BACKOFF_BASE_MS * 2 ** (fails - 1));\n const jitter = exp * 0.25 * Math.random();\n setMeta(META_NEXT_ATTEMPT_AT, String(now + exp + jitter));\n}\n\nfunction truncate(s: string, n: number) {\n return s.length > n ? s.slice(0, n - 1) + \"…\" : s;\n}\n\n/**\n * Flush a single batch. Returns moreAvailable=true if the queue still has\n * events the daemon should pick up on the next tick (we hit the byte/event\n * cap mid-flush). Throws on failure — caller decides whether to swallow.\n */\nexport async function flushOnce(): Promise<FlushResult> {\n const cfg = readConfig();\n if (!cfg.apiKey) {\n throw new Error(\"Not linked. Run: agentreel link <api-key>\");\n }\n const batch = takePendingBatch(MAX_BATCH_EVENTS, MAX_BATCH_BYTES);\n if (batch.events.length === 0) {\n // Nothing to do isn't an error — but don't stamp last_sync, since\n // we didn't actually round-trip anything.\n return { uploadedEvents: 0, uploadedSessions: 0, moreAvailable: false };\n }\n try {\n const res = await postIngest(cfg, { sessions: batch.sessions, events: batch.events });\n markUploaded(batch.eventIds);\n recordSuccess();\n return {\n uploadedEvents: res.events_written ?? 0,\n uploadedSessions: res.sessions_written ?? 0,\n moreAvailable: batch.events.length === MAX_BATCH_EVENTS,\n };\n } catch (err) {\n const permanent = err instanceof IngestError && err.isPermanent;\n recordFailure(err as Error, permanent);\n throw err;\n }\n}\n","import pc from \"picocolors\";\nimport { spawn } from \"node:child_process\";\nimport {\n existsSync,\n openSync,\n readFileSync,\n unlinkSync,\n writeFileSync,\n} from \"node:fs\";\nimport {\n DAEMON_LOG_PATH,\n DAEMON_PID_PATH,\n ensureAgentreelDir,\n} from \"../paths.js\";\nimport { pendingByteSize } from \"../db.js\";\nimport { flushOnce, nextAttemptAt } from \"../upload/flush.js\";\nimport { MAX_BATCH_BYTES } from \"../upload/queue.js\";\nimport { IngestError } from \"../upload/client.js\";\nimport { readConfig } from \"../config.js\";\n\nconst TICK_INTERVAL_MS = 30_000;\nconst EARLY_FLUSH_BYTES = MAX_BATCH_BYTES; // flush early once pending crosses 1 MB\n\nexport interface DaemonOpts {\n detach?: boolean;\n}\n\nexport async function daemonCommand(opts: DaemonOpts = {}): Promise<void> {\n const cfg = readConfig();\n if (!cfg.apiKey) {\n console.error(pc.red(\"✗ Not linked. Run \") + pc.cyan(\"agentreel link <api-key>\"));\n process.exit(1);\n }\n\n if (opts.detach) {\n spawnDetached();\n return;\n }\n\n if (!claimPidFile()) {\n process.exit(1);\n }\n\n const release = () => {\n try {\n unlinkSync(DAEMON_PID_PATH);\n } catch {\n /* ignore */\n }\n };\n\n let stopping = false;\n const stop = () => {\n if (stopping) return;\n stopping = true;\n console.log(pc.dim(\"\\n daemon stopping…\"));\n release();\n process.exit(0);\n };\n process.on(\"SIGINT\", stop);\n process.on(\"SIGTERM\", stop);\n process.on(\"beforeExit\", release);\n\n console.log(pc.green(\"●\") + \" agentreel daemon running\");\n console.log(pc.dim(` api: ${cfg.apiBaseUrl}`));\n console.log(pc.dim(` tick: every ${TICK_INTERVAL_MS / 1000}s, early flush at ${(EARLY_FLUSH_BYTES / 1024).toFixed(0)} KB`));\n console.log(pc.dim(\" Ctrl-C to stop\"));\n\n // Loop until killed. Each iteration:\n // 1. honor backoff (next_attempt_at) before doing anything\n // 2. drain the queue in batches as long as moreAvailable\n // 3. sleep up to 30s, but wake early if pending bytes cross 1 MB\n for (;;) {\n if (stopping) return;\n\n // Backoff: if a prior failure scheduled a retry in the future, wait.\n const nextAt = nextAttemptAt();\n const now = Date.now();\n if (nextAt > now) {\n await sleepInterruptible(nextAt - now, () => stopping);\n continue;\n }\n\n // Drain.\n try {\n for (;;) {\n const res = await flushOnce();\n if (res.uploadedEvents > 0) {\n console.log(\n pc.dim(` [${ts()}]`) +\n pc.green(\" ✓\") +\n ` ${res.uploadedEvents} events · ${res.uploadedSessions} sessions`,\n );\n }\n if (!res.moreAvailable) break;\n }\n } catch (err) {\n const e = err as Error;\n if (err instanceof IngestError && err.isPermanent) {\n console.error(\n pc.dim(` [${ts()}]`) + pc.red(\" ✗ \") + e.message + pc.dim(\" (5min backoff)\"),\n );\n } else {\n console.error(pc.dim(` [${ts()}]`) + pc.yellow(\" · \") + e.message);\n }\n // flushOnce already recorded the backoff window.\n }\n\n // Wait for the next tick, but wake early if the queue hits 1 MB.\n await waitForTickOrPressure(TICK_INTERVAL_MS, EARLY_FLUSH_BYTES, () => stopping);\n }\n}\n\nfunction claimPidFile(): boolean {\n ensureAgentreelDir();\n if (existsSync(DAEMON_PID_PATH)) {\n const raw = readFileSync(DAEMON_PID_PATH, \"utf8\").trim();\n const pid = Number(raw);\n if (Number.isFinite(pid) && pid > 0 && isAlive(pid)) {\n console.error(pc.red(`✗ daemon already running (pid ${pid})`));\n console.error(pc.dim(` if this is wrong, remove ${DAEMON_PID_PATH}`));\n return false;\n }\n // Stale pid file — overwrite.\n }\n writeFileSync(DAEMON_PID_PATH, String(process.pid), { encoding: \"utf8\", mode: 0o600 });\n return true;\n}\n\nfunction isAlive(pid: number): boolean {\n try {\n process.kill(pid, 0);\n return true;\n } catch {\n return false;\n }\n}\n\nfunction sleepInterruptible(ms: number, shouldStop: () => boolean): Promise<void> {\n return new Promise((resolve) => {\n if (ms <= 0) return resolve();\n const start = Date.now();\n const t = setInterval(() => {\n if (shouldStop() || Date.now() - start >= ms) {\n clearInterval(t);\n resolve();\n }\n }, 250);\n });\n}\n\nfunction spawnDetached(): void {\n ensureAgentreelDir();\n // If a live pid is already on disk, refuse — we'd just hit the same\n // claimPidFile check from inside the child and lose stderr to the log.\n if (existsSync(DAEMON_PID_PATH)) {\n const raw = readFileSync(DAEMON_PID_PATH, \"utf8\").trim();\n const pid = Number(raw);\n if (Number.isFinite(pid) && pid > 0 && isAlive(pid)) {\n console.error(pc.red(`✗ daemon already running (pid ${pid})`));\n console.error(pc.dim(\" use \") + pc.cyan(\"agentreel stop\") + pc.dim(\" first\"));\n process.exit(1);\n }\n }\n\n // Open the log in append mode so child stdout/stderr persist across\n // restarts. argv[0] is the same node binary; pass `daemon` (no\n // --detach) so the child runs the foreground loop.\n const out = openSync(DAEMON_LOG_PATH, \"a\");\n const err = openSync(DAEMON_LOG_PATH, \"a\");\n const child = spawn(process.execPath, [process.argv[1]!, \"daemon\"], {\n detached: true,\n stdio: [\"ignore\", out, err],\n env: process.env,\n });\n // Don't keep the parent alive waiting on the child; let it become\n // an orphan adopted by init. Releasing the IPC handle is necessary\n // even though we passed `ignore` — defensive.\n child.unref();\n console.log(pc.green(\"●\") + ` daemon started (pid ${child.pid})`);\n console.log(pc.dim(` log: ${DAEMON_LOG_PATH}`));\n console.log(pc.dim(` stop: agentreel stop`));\n}\n\nexport function stopCommand(): void {\n if (!existsSync(DAEMON_PID_PATH)) {\n console.log(pc.dim(\"· daemon not running\"));\n return;\n }\n const raw = readFileSync(DAEMON_PID_PATH, \"utf8\").trim();\n const pid = Number(raw);\n if (!Number.isFinite(pid) || pid <= 0) {\n try {\n unlinkSync(DAEMON_PID_PATH);\n } catch {\n /* ignore */\n }\n console.log(pc.dim(\"· cleared stale pid file\"));\n return;\n }\n if (!isAlive(pid)) {\n try {\n unlinkSync(DAEMON_PID_PATH);\n } catch {\n /* ignore */\n }\n console.log(pc.dim(`· no live daemon for pid ${pid} — cleared stale pid file`));\n return;\n }\n try {\n process.kill(pid, \"SIGTERM\");\n console.log(pc.green(\"✓\") + ` sent SIGTERM to pid ${pid}`);\n } catch (err) {\n console.error(pc.red(\"✗ \") + (err as Error).message);\n process.exit(1);\n }\n}\n\nfunction waitForTickOrPressure(\n tickMs: number,\n pressureBytes: number,\n shouldStop: () => boolean,\n): Promise<void> {\n return new Promise((resolve) => {\n const start = Date.now();\n const t = setInterval(() => {\n if (shouldStop()) {\n clearInterval(t);\n return resolve();\n }\n if (Date.now() - start >= tickMs) {\n clearInterval(t);\n return resolve();\n }\n // Pressure check: cheap COUNT/SUM query on the indexed pending column.\n try {\n if (pendingByteSize() >= pressureBytes) {\n clearInterval(t);\n return resolve();\n }\n } catch {\n // db locked / not initialized — let the tick handle it.\n }\n }, 1_000);\n });\n}\n\nfunction ts(): string {\n const d = new Date();\n return d.toTimeString().slice(0, 8);\n}\n","import { Command } from \"commander\";\nimport { initCommand } from \"./commands/init.js\";\n\n// Replaced at build time by tsup's `define`. Fallback covers running via\n// ts-node where the literal isn't substituted.\ndeclare const __AGENTREEL_VERSION__: string;\nconst VERSION =\n typeof __AGENTREEL_VERSION__ === \"string\" ? __AGENTREEL_VERSION__ : \"dev\";\nimport { statusCommand } from \"./commands/status.js\";\nimport { linkCommand, logoutCommand, uninstallCommand } from \"./commands/auth.js\";\nimport { watchCommand } from \"./commands/watch.js\";\nimport { pushCommand } from \"./commands/push.js\";\nimport { daemonCommand, stopCommand } from \"./commands/daemon.js\";\nimport { runHook } from \"./hooks/handler.js\";\n\nconst program = new Command();\n\nprogram\n .name(\"agentreel\")\n .description(\"AgentReel — capture Claude Code and Cursor sessions locally\")\n .version(VERSION);\n\nprogram\n .command(\"init\")\n .description(\"install Claude Code hooks and create the local SQLite buffer\")\n .action(async () => {\n await initCommand();\n });\n\nprogram\n .command(\"status\")\n .description(\"show local capture status, recent sessions, queue depth\")\n .action(async () => {\n await statusCommand();\n });\n\nprogram\n .command(\"watch\")\n .description(\"watch Cursor's local history and capture edits as events\")\n .action(async () => {\n await watchCommand();\n });\n\nprogram\n .command(\"link [api-key]\")\n .description(\"authenticate the local agent with agentreel.dev\")\n .option(\"--api <url>\", \"override the API base URL (default https://api.agentreel.dev)\")\n .action(async (apiKey: string | undefined, opts: { api?: string }) => {\n await linkCommand(apiKey, opts);\n });\n\nprogram\n .command(\"push\")\n .description(\"upload pending events to agentreel.dev\")\n .action(async () => {\n await pushCommand();\n });\n\nprogram\n .command(\"daemon\")\n .description(\"run the background uploader (30s ticks, 1MB early-flush, exponential backoff)\")\n .option(\"--detach\", \"fork into the background and return immediately; logs to ~/.agentreel/daemon.log\")\n .action(async (opts: { detach?: boolean }) => {\n await daemonCommand({ detach: opts.detach });\n });\n\nprogram\n .command(\"stop\")\n .description(\"stop the running background uploader\")\n .action(() => {\n stopCommand();\n });\n\nprogram\n .command(\"logout\")\n .description(\"clear local credentials\")\n .action(async () => {\n await logoutCommand();\n });\n\nprogram\n .command(\"uninstall\")\n .description(\"remove AgentReel hooks from ~/.claude/settings.json\")\n .action(async () => {\n await uninstallCommand();\n });\n\nprogram\n .command(\"hook <event>\")\n .description(\"internal: hook handler invoked by Claude Code (reads JSON from stdin)\")\n .action(async (event: string) => {\n await runHook(event);\n });\n\nprogram.parseAsync(process.argv).catch((err) => {\n // Top-level: if we got this far on a hook invocation, something is very wrong.\n // For all other commands, print and exit non-zero.\n const cmd = process.argv[2];\n if (cmd === \"hook\") {\n process.exit(0);\n }\n console.error(err);\n process.exit(1);\n});\n","import { realpathSync } from \"node:fs\";\nimport { fileURLToPath } from \"node:url\";\nimport { sep } from \"node:path\";\nimport pc from \"picocolors\";\nimport { installClaudeCodeHooks, quotePath } from \"../hooks/install.js\";\nimport { readConfig, writeConfig } from \"../config.js\";\nimport { getDb } from \"../db.js\";\nimport { ensureAgentreelDir } from \"../paths.js\";\n\nconst PACKAGE_NAME = \"@agentreel/agent\";\n\ninterface ResolvedBinary {\n absolutePath: string;\n isEphemeral: boolean; // true when running from an npx temp dir\n}\n\nfunction resolveAgentBinary(): ResolvedBinary {\n // tsup builds to dist/cli.js with a node shebang; npm symlinks it to\n // <prefix>/bin/agentreel. The realpath through that symlink is stable for\n // npm i -g and for in-tree development. For `npx` installs it points\n // inside ~/.npm/_npx/<hash>/ which gets cleaned eventually — we detect\n // that and fall back to an `npx -y …` hook command instead.\n const here = fileURLToPath(import.meta.url);\n const real = realpathSync(here);\n const isEphemeral = real.includes(`${sep}_npx${sep}`) || real.includes(\"/_npx/\");\n return { absolutePath: real, isEphemeral };\n}\n\nfunction chooseHookPrefix(bin: ResolvedBinary): { prefix: string; mode: \"absolute\" | \"npx\" } {\n if (process.env.AGENTREEL_HOOK_COMMAND) {\n return { prefix: process.env.AGENTREEL_HOOK_COMMAND, mode: \"absolute\" };\n }\n if (bin.isEphemeral) {\n return { prefix: `npx -y ${PACKAGE_NAME}`, mode: \"npx\" };\n }\n return { prefix: quotePath(bin.absolutePath), mode: \"absolute\" };\n}\n\nexport async function initCommand(): Promise<void> {\n ensureAgentreelDir();\n\n // Touch the DB so the file exists and migrations run.\n getDb();\n\n const cfg = readConfig();\n if (!cfg.installedAt) cfg.installedAt = Date.now();\n cfg.hooksInstalled = true;\n writeConfig(cfg);\n\n const binary = resolveAgentBinary();\n const { prefix, mode } = chooseHookPrefix(binary);\n const result = installClaudeCodeHooks(prefix);\n\n console.log(pc.bold(pc.cyan(\"\\n AgentReel \")) + pc.dim(\"Loom for AI coding sessions\\n\"));\n console.log(pc.green(\"✓\") + \" Created ~/.agentreel/sessions.db\");\n console.log(pc.green(\"✓\") + \" Wrote ~/.agentreel/config.json\");\n console.log(\n pc.green(\"✓\") +\n ` Installed ${result.installedEvents.length} Claude Code hooks → ~/.claude/settings.json`,\n );\n if (result.backup) {\n console.log(pc.dim(` (backup: ${result.backup})`));\n }\n console.log();\n console.log(pc.dim(\" Hook command: \") + pc.dim(`${prefix} hook <Event>`));\n if (mode === \"npx\") {\n console.log(\n pc.dim(\" \") +\n pc.yellow(\"•\") +\n pc.dim(\n ` Hooks resolve via npx every time Claude Code fires an event.\\n ` +\n ` For faster cold starts, run: npm i -g ${PACKAGE_NAME}`,\n ),\n );\n }\n console.log();\n if (!cfg.apiKey) {\n console.log(pc.bold(\"Next steps:\"));\n console.log(\n \" \" + pc.dim(\"1.\") + \" \" + pc.cyan(\"agentreel link <key>\") +\n pc.dim(\" — get a key from https://agentreel.dev/dashboard/settings\"),\n );\n console.log(\n \" \" + pc.dim(\"2.\") + \" \" + pc.cyan(\"agentreel daemon --detach\") +\n pc.dim(\" — start the background uploader\"),\n );\n console.log(\n \" \" + pc.dim(\"3.\") + \" open Claude Code and work as normal.\",\n );\n } else {\n console.log(pc.bold(\"Next:\"));\n console.log(\n \" \" + pc.cyan(\"agentreel daemon --detach\") +\n pc.dim(\" — start the background uploader (already linked)\"),\n );\n }\n console.log(\n \"\\n\" + pc.dim(\"Anything: \") + pc.cyan(\"agentreel status\") + pc.dim(\" shows queue, last sync, last error.\\n\"),\n );\n}\n","import pc from \"picocolors\";\nimport { existsSync, readFileSync } from \"node:fs\";\nimport {\n CLAUDE_SETTINGS_PATH,\n DB_PATH,\n CONFIG_PATH,\n DAEMON_PID_PATH,\n} from \"../paths.js\";\nimport { countEvents, getMeta, listRecentSessions, pendingByteSize } from \"../db.js\";\nimport { readConfig } from \"../config.js\";\nimport {\n META_LAST_ERROR_AT,\n META_LAST_ERROR_MSG,\n META_LAST_SYNC_AT,\n META_NEXT_ATTEMPT_AT,\n consecutiveFailures,\n} from \"../upload/flush.js\";\n\nfunction fmtDuration(ms: number): string {\n const s = Math.round(ms / 1000);\n if (s < 60) return `${s}s`;\n const m = Math.floor(s / 60);\n if (m < 60) return `${m}m ${s % 60}s`;\n const h = Math.floor(m / 60);\n return `${h}h ${m % 60}m`;\n}\n\nfunction fmtAgo(ms: number): string {\n return fmtDuration(Date.now() - ms) + \" ago\";\n}\n\nfunction fmtBytes(n: number): string {\n if (n < 1024) return `${n} B`;\n if (n < 1024 * 1024) return `${(n / 1024).toFixed(1)} KB`;\n return `${(n / 1024 / 1024).toFixed(2)} MB`;\n}\n\nfunction daemonStatus(): { running: boolean; pid: number | null } {\n if (!existsSync(DAEMON_PID_PATH)) return { running: false, pid: null };\n try {\n const pid = Number(readFileSync(DAEMON_PID_PATH, \"utf8\").trim());\n if (!Number.isFinite(pid) || pid <= 0) return { running: false, pid: null };\n process.kill(pid, 0);\n return { running: true, pid };\n } catch {\n return { running: false, pid: null };\n }\n}\n\nexport async function statusCommand(): Promise<void> {\n const cfg = readConfig();\n console.log(pc.bold(pc.cyan(\"AgentReel status\\n\")));\n console.log(\" config: \" + (existsSync(CONFIG_PATH) ? CONFIG_PATH : pc.red(\"missing\")));\n console.log(\" database: \" + (existsSync(DB_PATH) ? DB_PATH : pc.red(\"not initialized\")));\n console.log(\n \" claude hooks: \" +\n (existsSync(CLAUDE_SETTINGS_PATH) ? CLAUDE_SETTINGS_PATH : pc.red(\"not installed\")),\n );\n console.log(\" api base: \" + cfg.apiBaseUrl);\n console.log(\" authenticated: \" + (cfg.apiKey ? pc.green(\"yes\") : pc.yellow(\"no\")));\n\n const d = daemonStatus();\n console.log(\n \" daemon: \" +\n (d.running ? pc.green(`running (pid ${d.pid})`) : pc.dim(\"stopped\")),\n );\n console.log();\n\n if (!existsSync(DB_PATH)) {\n console.log(pc.yellow(\"Run `agentreel init` to install hooks.\"));\n return;\n }\n\n const { total, pending } = countEvents();\n const pendingBytes = pendingByteSize();\n console.log(` events captured: ${total}`);\n console.log(` pending upload: ${pending}` + (pending > 0 ? pc.dim(` (${fmtBytes(pendingBytes)})`) : \"\"));\n\n const lastSync = numMeta(META_LAST_SYNC_AT);\n const lastErr = numMeta(META_LAST_ERROR_AT);\n const lastErrMsg = getMeta(META_LAST_ERROR_MSG);\n const fails = consecutiveFailures();\n const nextAt = numMeta(META_NEXT_ATTEMPT_AT);\n\n console.log(\n ` last sync: ` +\n (lastSync ? pc.green(fmtAgo(lastSync)) : pc.dim(\"never\")),\n );\n if (lastErr) {\n console.log(\n ` last error: ` +\n pc.red(fmtAgo(lastErr)) +\n pc.dim(` · ${fails} consecutive`),\n );\n if (lastErrMsg) console.log(pc.dim(` ${lastErrMsg}`));\n if (nextAt && nextAt > Date.now()) {\n console.log(\n pc.dim(` next attempt in ${fmtDuration(nextAt - Date.now())}`),\n );\n }\n }\n console.log();\n\n const sessions = listRecentSessions(5);\n if (sessions.length === 0) {\n console.log(pc.dim(\" no sessions yet — start a Claude Code session to capture one.\"));\n return;\n }\n console.log(pc.bold(\"recent sessions:\"));\n for (const s of sessions) {\n const dur = s.ended_at ? fmtDuration(s.ended_at - s.started_at) : pc.dim(\"active\");\n const ts = new Date(s.started_at).toLocaleString();\n console.log(` ${pc.dim(s.id.slice(0, 8))} ${s.tool.padEnd(11)} ${ts} ${dur}`);\n }\n}\n\nfunction numMeta(key: string): number | null {\n const v = getMeta(key);\n if (!v) return null;\n const n = Number(v);\n return Number.isFinite(n) && n > 0 ? n : null;\n}\n","import pc from \"picocolors\";\nimport { readConfig, writeConfig } from \"../config.js\";\nimport { postIngest } from \"../upload/client.js\";\n\nexport async function logoutCommand(): Promise<void> {\n const cfg = readConfig();\n cfg.apiKey = undefined;\n cfg.workspaceId = undefined;\n writeConfig(cfg);\n console.log(pc.green(\"✓\") + \" Cleared local credentials.\");\n}\n\ninterface LinkOpts {\n api?: string;\n}\n\nexport async function linkCommand(rawKey: string | undefined, opts: LinkOpts): Promise<void> {\n const key = (rawKey ?? (await promptHidden(\"Paste your AgentReel API key: \"))).trim();\n if (!key) {\n console.error(pc.red(\"✗ No key provided.\"));\n process.exit(1);\n }\n if (!key.startsWith(\"ar_live_\")) {\n console.error(pc.red(\"✗ Keys start with `ar_live_`. Did you paste the right value?\"));\n process.exit(1);\n }\n\n const cfg = readConfig();\n cfg.apiKey = key;\n if (opts.api) cfg.apiBaseUrl = opts.api;\n\n console.log(pc.dim(` validating against ${cfg.apiBaseUrl}…`));\n try {\n await postIngest(cfg, {});\n } catch (err) {\n console.error(pc.red(\"✗ Validation failed: \") + (err as Error).message);\n process.exit(1);\n }\n writeConfig(cfg);\n console.log(pc.green(\"✓\") + \" Linked.\");\n console.log(pc.dim(\" api: \") + cfg.apiBaseUrl);\n console.log(pc.dim(\" key: \") + key.slice(0, 12) + \"…\");\n}\n\nexport async function uninstallCommand(): Promise<void> {\n const { uninstallClaudeCodeHooks } = await import(\"../hooks/install.js\");\n const { stopCommand } = await import(\"./daemon.js\");\n // Stop first so we don't leave a daemon flushing into a half-uninstalled\n // setup. stopCommand() is idempotent — silent when nothing is running.\n stopCommand();\n const { backup } = uninstallClaudeCodeHooks();\n console.log(pc.green(\"✓\") + \" Removed AgentReel hooks from ~/.claude/settings.json\");\n if (backup) console.log(pc.dim(` (backup: ${backup})`));\n}\n\nconst CTRL_C = 0x03;\nconst BACKSPACE = 0x7f;\nconst BACKSPACE_ALT = 0x08;\nconst NEWLINE = 0x0a;\nconst CARRIAGE = 0x0d;\n\nfunction promptHidden(prompt: string): Promise<string> {\n return new Promise((resolve) => {\n process.stdout.write(prompt);\n let buf = \"\";\n const stdin = process.stdin;\n stdin.setRawMode?.(true);\n stdin.resume();\n stdin.setEncoding(\"utf8\");\n const onData = (chunk: string) => {\n for (const ch of chunk) {\n const code = ch.charCodeAt(0);\n if (code === NEWLINE || code === CARRIAGE) {\n stdin.setRawMode?.(false);\n stdin.pause();\n stdin.removeListener(\"data\", onData);\n process.stdout.write(\"\\n\");\n return resolve(buf);\n }\n if (code === CTRL_C) {\n stdin.setRawMode?.(false);\n process.exit(130);\n }\n if (code === BACKSPACE || code === BACKSPACE_ALT) {\n buf = buf.slice(0, -1);\n } else {\n buf += ch;\n }\n }\n };\n stdin.on(\"data\", onData);\n });\n}\n","import pc from \"picocolors\";\nimport { existsSync } from \"node:fs\";\nimport { basename } from \"node:path\";\nimport { cursorHistoryDir } from \"../cursor/paths.js\";\nimport { startCursorWatcher } from \"../cursor/watcher.js\";\nimport { CursorSessionManager } from \"../cursor/session.js\";\nimport { ensureAgentreelDir } from \"../paths.js\";\nimport { getDb } from \"../db.js\";\n\nexport async function watchCommand(): Promise<void> {\n ensureAgentreelDir();\n // Touch DB so the schema exists.\n getDb();\n\n const dir = cursorHistoryDir();\n if (!existsSync(dir)) {\n console.error(pc.red(\"✗ Cursor history directory not found:\"));\n console.error(\" \" + dir);\n console.error();\n console.error(pc.dim(\"Open Cursor at least once, edit a file, then re-run.\"));\n console.error(pc.dim(\"(Or set AGENTREEL_CURSOR_HISTORY_DIR to a custom path.)\"));\n process.exit(1);\n }\n\n console.log(pc.bold(pc.cyan(\"AgentReel · Cursor watcher\\n\")));\n console.log(pc.dim(\" watching \") + dir);\n console.log(pc.dim(\" press Ctrl+C to stop\\n\"));\n\n const sessions = new CursorSessionManager();\n\n const watcher = startCursorWatcher(dir, async (snap) => {\n const { sessionId, isNew } = sessions.ingest(snap);\n const ts = new Date(snap.timestamp).toLocaleTimeString();\n const ws = snap.workspace ? basename(snap.workspace) : pc.dim(\"no-workspace\");\n const file = snap.filePath.split(\"/\").slice(-2).join(\"/\");\n const sourceLabel =\n snap.source === \"cursor-ai\"\n ? pc.magenta(\"ai\")\n : snap.source === \"cursor-manual\"\n ? pc.cyan(\"man\")\n : pc.dim(\"?\");\n const stats = snap.binary\n ? pc.dim(\"binary\")\n : `${pc.green(\"+\" + snap.added)} ${pc.red(\"-\" + snap.removed)}`;\n if (isNew) {\n console.log(\n `${pc.dim(ts)} ${pc.yellow(\"session\")} ${pc.dim(sessionId)} ${ws}`,\n );\n }\n console.log(`${pc.dim(ts)} edit ${sourceLabel} ${file.padEnd(36)} ${stats}`);\n });\n\n // Graceful shutdown — flush sessions, close watcher.\n const shutdown = async () => {\n console.log(pc.dim(\"\\n closing sessions…\"));\n sessions.closeAll();\n await watcher.close();\n process.exit(0);\n };\n process.on(\"SIGINT\", shutdown);\n process.on(\"SIGTERM\", shutdown);\n}\n","import { homedir, platform } from \"node:os\";\nimport { join } from \"node:path\";\n\n// Cursor is a VS Code fork; its history layout matches Code's:\n// <userData>/User/History/<hashId>/{entries.json, <id>.<ext>, ...}\nexport function defaultCursorHistoryDir(): string {\n const home = homedir();\n switch (platform()) {\n case \"darwin\":\n return join(home, \"Library\", \"Application Support\", \"Cursor\", \"User\", \"History\");\n case \"win32\": {\n const appData = process.env.APPDATA ?? join(home, \"AppData\", \"Roaming\");\n return join(appData, \"Cursor\", \"User\", \"History\");\n }\n default:\n return join(home, \".config\", \"Cursor\", \"User\", \"History\");\n }\n}\n\nexport function cursorHistoryDir(): string {\n return process.env.AGENTREEL_CURSOR_HISTORY_DIR ?? defaultCursorHistoryDir();\n}\n","import chokidar, { type FSWatcher } from \"chokidar\";\nimport { readFile } from \"node:fs/promises\";\nimport { existsSync } from \"node:fs\";\nimport { basename, dirname, join } from \"node:path\";\nimport {\n findWorkspaceRoot,\n isProbablyBinary,\n readEntries,\n resourceToPath,\n type HistoryEntry,\n} from \"./entries.js\";\nimport { computeDiff } from \"./diff.js\";\nimport { isIgnored } from \"../redact/ignore.js\";\nimport { scrubString } from \"../redact/scrubber.js\";\n\nexport interface SnapshotEvent {\n filePath: string;\n workspace: string | null;\n source: \"cursor-ai\" | \"cursor-manual\" | \"unknown\";\n timestamp: number;\n patch: string;\n added: number;\n removed: number;\n binary: boolean;\n}\n\nexport type SnapshotHandler = (e: SnapshotEvent) => void | Promise<void>;\n\nexport interface WatcherOptions {\n /** Discard the very first entry for any tracked file (Cursor's \"first observation\" snapshot). Default true. */\n skipFirstObservation?: boolean;\n}\n\nexport function startCursorWatcher(\n historyDir: string,\n onSnapshot: SnapshotHandler,\n opts: WatcherOptions = {},\n): FSWatcher {\n const skipFirst = opts.skipFirstObservation ?? true;\n\n const watcher = chokidar.watch(historyDir, {\n ignoreInitial: true,\n depth: 2,\n persistent: true,\n awaitWriteFinish: { stabilityThreshold: 120, pollInterval: 40 },\n });\n\n watcher.on(\"add\", async (path) => {\n try {\n const folder = dirname(path);\n const file = basename(path);\n // The folder name is the resource hash; siblings include entries.json\n // and one snapshot file per saved version.\n if (file === \"entries.json\") return;\n // Wait briefly for entries.json to mention this file — Cursor writes\n // the snapshot before updating the manifest in some versions.\n const ctx = await waitForEntry(folder, file, 2_000);\n if (!ctx) return;\n await processSnapshot(folder, ctx, skipFirst, onSnapshot);\n } catch (err) {\n // The watcher must never crash the host process.\n // eslint-disable-next-line no-console\n console.error(\"[agentreel] cursor watcher: error processing\", path, err);\n }\n });\n\n return watcher;\n}\n\ninterface SnapshotContext {\n resource: string;\n current: HistoryEntry;\n previous: HistoryEntry | null;\n currentIdx: number;\n}\n\nasync function waitForEntry(\n folder: string,\n fileId: string,\n totalMs: number,\n): Promise<SnapshotContext | null> {\n const start = Date.now();\n while (Date.now() - start < totalMs) {\n const file = await readEntries(folder);\n if (file) {\n const idx = file.entries.findIndex((e) => e.id === fileId);\n if (idx >= 0) {\n const current = file.entries[idx];\n if (!current) return null;\n const previous = idx > 0 ? (file.entries[idx - 1] ?? null) : null;\n return { resource: file.resource, current, previous, currentIdx: idx };\n }\n }\n await sleep(150);\n }\n return null;\n}\n\nasync function processSnapshot(\n folder: string,\n ctx: SnapshotContext,\n skipFirst: boolean,\n onSnapshot: SnapshotHandler,\n): Promise<void> {\n const filePath = resourceToPath(ctx.resource);\n if (!filePath) return;\n\n // Skip files inside common dependency / build dirs — high noise, low value.\n if (NOISY_PATH.test(filePath)) return;\n\n // Honor per-workspace .agentreelignore (gitignore syntax).\n const workspace = findWorkspaceRoot(filePath);\n if (isIgnored(workspace, filePath)) return;\n\n if (!ctx.previous) {\n // First time Cursor has seen this file — no diff to compute.\n if (skipFirst) return;\n }\n\n const newSnapshot = join(folder, ctx.current.id);\n let before = \"\";\n let after = \"\";\n if (ctx.previous) {\n const prevPath = join(folder, ctx.previous.id);\n if (existsSync(prevPath)) {\n before = await safeRead(prevPath);\n }\n }\n if (existsSync(newSnapshot)) {\n after = await safeRead(newSnapshot);\n }\n\n // No real change — chokidar can fire spurious \"add\" events on some\n // filesystems. Skip silently.\n if (before === after) return;\n\n const binary = isProbablyBinary(filePath);\n let patch = \"\";\n let added = 0;\n let removed = 0;\n if (!binary) {\n // Scrub BEFORE diffing so secrets never enter the patch text. We diff\n // the redacted versions instead — the dashboard will still show the\n // shape of the change, just with [REDACTED:*] in place of values.\n const beforeSafe = scrubString(before);\n const afterSafe = scrubString(after);\n const result = computeDiff(beforeSafe, afterSafe);\n patch = result.patch;\n added = result.added;\n removed = result.removed;\n }\n\n const source = classifySource(ctx.current.source);\n onSnapshot({\n filePath,\n workspace,\n source,\n timestamp: ctx.current.timestamp ?? Date.now(),\n patch,\n added,\n removed,\n binary,\n });\n}\n\nfunction classifySource(raw?: string): SnapshotEvent[\"source\"] {\n if (!raw) return \"cursor-manual\";\n const s = raw.toLowerCase();\n if (s.includes(\"composer\") || s.includes(\"ai\") || s.includes(\"chat\")) return \"cursor-ai\";\n return \"cursor-manual\";\n}\n\nasync function safeRead(path: string): Promise<string> {\n try {\n return await readFile(path, \"utf8\");\n } catch {\n return \"\";\n }\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((r) => setTimeout(r, ms));\n}\n\nconst NOISY_PATH =\n /[\\\\/](node_modules|\\.next|\\.turbo|dist|build|\\.git|coverage|\\.cache|\\.venv|venv|target|out)[\\\\/]/;\n","import { readFile } from \"node:fs/promises\";\nimport { existsSync, statSync } from \"node:fs\";\nimport { join, dirname, resolve, sep } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\nexport interface HistoryEntry {\n id: string; // filename of the snapshot, e.g. \"rEMc.ts\"\n timestamp: number; // ms epoch\n source?: string; // e.g. \"Cursor.Composer\" for AI edits, \"\" for manual\n}\n\nexport interface HistoryFile {\n version: number;\n resource: string; // file:///...\n entries: HistoryEntry[];\n}\n\nexport async function readEntries(historyFolder: string): Promise<HistoryFile | null> {\n const path = join(historyFolder, \"entries.json\");\n if (!existsSync(path)) return null;\n try {\n const raw = await readFile(path, \"utf8\");\n return JSON.parse(raw) as HistoryFile;\n } catch {\n return null;\n }\n}\n\nexport function resourceToPath(resource: string): string | null {\n if (!resource.startsWith(\"file://\")) return null;\n try {\n return fileURLToPath(resource);\n } catch {\n return null;\n }\n}\n\n// Walk up from `path` looking for a directory that contains `.git`. That\n// directory is the workspace root for the purposes of grouping events.\nexport function findWorkspaceRoot(path: string): string | null {\n let dir = dirname(resolve(path));\n while (dir && dir !== sep) {\n const git = join(dir, \".git\");\n try {\n if (existsSync(git)) return dir;\n } catch {\n // ignore\n }\n const parent = dirname(dir);\n if (parent === dir) break;\n dir = parent;\n }\n return null;\n}\n\nexport function isProbablyBinary(path: string): boolean {\n try {\n const s = statSync(path);\n if (s.size > 1024 * 1024) return true; // >1MB — skip diff\n } catch {\n return false;\n }\n // Lightweight extension allowlist for v1. Anything else, treat as binary\n // and skip diffing (we still record the event, just without a patch).\n const text =\n /\\.(ts|tsx|js|jsx|mjs|cjs|json|jsonc|md|mdx|css|scss|html|xml|yaml|yml|toml|sh|bash|zsh|fish|py|rb|go|rs|java|kt|swift|c|cc|cpp|h|hpp|cs|php|sql|prisma|graphql|gql|env|gitignore|dockerfile|tf|hcl|lua|vue|svelte|astro|txt|csv|tsv|log|conf|ini)$/i;\n return !text.test(path);\n}\n","import { diffLines } from \"diff\";\nimport DiffMatchPatch from \"diff-match-patch\";\n\nexport interface DiffResult {\n /** diff-match-patch wire format — compact, reversible. Stored on the event. */\n patch: string;\n /** Line-level adds/removes — surfaced in the dashboard list. */\n added: number;\n removed: number;\n}\n\nconst dmp = new DiffMatchPatch.diff_match_patch();\n// Allow expensive cleanup on small diffs; cap at 1MB to avoid pathological inputs.\ndmp.Diff_Timeout = 1.0;\n\nexport function computeDiff(before: string, after: string): DiffResult {\n // Patch — compact DMP format, much smaller than unified diff for small edits.\n const patches = dmp.patch_make(before, after);\n const patch = dmp.patch_toText(patches);\n\n // Line-level stats (cheap; users see these in the timeline list).\n let added = 0;\n let removed = 0;\n for (const part of diffLines(before, after)) {\n const n =\n part.count ??\n (part.value.match(/\\n/g)?.length ?? (part.value.length > 0 ? 1 : 0));\n if (part.added) added += n;\n else if (part.removed) removed += n;\n }\n\n return { patch, added, removed };\n}\n","import { existsSync, readFileSync, statSync } from \"node:fs\";\nimport { join, relative, sep } from \"node:path\";\nimport ignore, { type Ignore } from \"ignore\";\n\nconst FILENAME = \".agentreelignore\";\nconst TTL_MS = 5_000; // re-read the file at most every 5 seconds per workspace\n\ninterface CacheEntry {\n matcher: Ignore | null;\n loadedAt: number;\n fileMtime: number;\n}\n\nconst cache = new Map<string, CacheEntry>();\n\nfunction loadFor(workspace: string): Ignore | null {\n const path = join(workspace, FILENAME);\n if (!existsSync(path)) return null;\n try {\n const raw = readFileSync(path, \"utf8\");\n return ignore({ allowRelativePaths: true }).add(raw);\n } catch {\n return null;\n }\n}\n\nfunction getCached(workspace: string): Ignore | null {\n const entry = cache.get(workspace);\n const path = join(workspace, FILENAME);\n let mtime = 0;\n try {\n mtime = existsSync(path) ? statSync(path).mtimeMs : 0;\n } catch {\n mtime = 0;\n }\n const now = Date.now();\n if (entry && now - entry.loadedAt < TTL_MS && entry.fileMtime === mtime) {\n return entry.matcher;\n }\n const matcher = loadFor(workspace);\n cache.set(workspace, { matcher, loadedAt: now, fileMtime: mtime });\n return matcher;\n}\n\n/**\n * Returns true if `filePath` should be skipped because it matches a rule\n * in the workspace's `.agentreelignore`. Returns false when the workspace\n * has no ignore file or the path doesn't match.\n */\nexport function isIgnored(workspace: string | null | undefined, filePath: string): boolean {\n if (!workspace) return false;\n const matcher = getCached(workspace);\n if (!matcher) return false;\n const rel = relative(workspace, filePath);\n // ignore can't reason about paths that escape the workspace.\n if (!rel || rel.startsWith(\"..\") || rel.startsWith(sep)) return false;\n // gitignore syntax expects forward slashes.\n return matcher.ignores(rel.split(sep).join(\"/\"));\n}\n","// Order matters. Multiline / specific patterns first, generic last.\n\nexport interface RedactionRule {\n name: string;\n re: RegExp;\n replacement: string | ((match: string) => string);\n}\n\nexport const PATTERNS: RedactionRule[] = [\n // PEM-encoded private keys (multiline, must run early)\n {\n name: \"pem-private-key\",\n re: /-----BEGIN [A-Z0-9 ]*PRIVATE KEY-----[\\s\\S]+?-----END [A-Z0-9 ]*PRIVATE KEY-----/g,\n replacement: \"[REDACTED:private-key]\",\n },\n\n // JWT (header.payload.signature) — eyJ-prefixed base64url segments\n {\n name: \"jwt\",\n re: /\\beyJ[A-Za-z0-9_-]{8,}\\.eyJ[A-Za-z0-9_-]{8,}\\.[A-Za-z0-9_-]{8,}\\b/g,\n replacement: \"[REDACTED:jwt]\",\n },\n\n // GitHub fine-grained PATs (84 chars after prefix is the official format)\n {\n name: \"github-fine-grained-pat\",\n re: /\\bgithub_pat_[A-Za-z0-9_]{82,}\\b/g,\n replacement: \"[REDACTED:gh-fine-pat]\",\n },\n // GitHub OAuth, PAT, app, server, refresh tokens\n {\n name: \"github-token\",\n re: /\\bgh[pousr]_[A-Za-z0-9]{36,255}\\b/g,\n replacement: \"[REDACTED:gh-token]\",\n },\n\n // Anthropic\n {\n name: \"anthropic-key\",\n re: /\\bsk-ant-(?:api\\d{2}-)?[A-Za-z0-9_-]{40,}\\b/g,\n replacement: \"[REDACTED:anthropic-key]\",\n },\n\n // OpenAI (sk-proj-..., sk-svcacct-..., legacy sk-...)\n {\n name: \"openai-key\",\n re: /\\bsk-(?:proj-|svcacct-|admin-)?[A-Za-z0-9_-]{20,}\\b/g,\n replacement: \"[REDACTED:openai-key]\",\n },\n\n // Stripe\n {\n name: \"stripe-secret\",\n re: /\\bsk_(?:test|live)_[A-Za-z0-9]{16,}\\b/g,\n replacement: \"[REDACTED:stripe-secret]\",\n },\n {\n name: \"stripe-restricted\",\n re: /\\brk_(?:test|live)_[A-Za-z0-9]{16,}\\b/g,\n replacement: \"[REDACTED:stripe-restricted]\",\n },\n {\n name: \"stripe-publishable\",\n re: /\\bpk_(?:test|live)_[A-Za-z0-9]{16,}\\b/g,\n replacement: \"[REDACTED:stripe-publishable]\",\n },\n {\n name: \"stripe-webhook\",\n re: /\\bwhsec_[A-Za-z0-9]{32,}\\b/g,\n replacement: \"[REDACTED:stripe-webhook]\",\n },\n\n // AWS access key IDs (and STS / temporary forms)\n {\n name: \"aws-access-key-id\",\n re: /\\b(?:AKIA|ASIA|AGPA|AROA|AIDA|ANPA|ANVA|AIPA)[0-9A-Z]{16}\\b/g,\n replacement: \"[REDACTED:aws-key-id]\",\n },\n\n // Slack tokens\n {\n name: \"slack-token\",\n re: /\\bxox[baprs]-[A-Za-z0-9-]{10,}\\b/g,\n replacement: \"[REDACTED:slack-token]\",\n },\n\n // Google API keys\n {\n name: \"google-api-key\",\n re: /\\bAIza[A-Za-z0-9_-]{35}\\b/g,\n replacement: \"[REDACTED:google-api-key]\",\n },\n\n // npm tokens\n {\n name: \"npm-token\",\n re: /\\bnpm_[A-Za-z0-9]{36}\\b/g,\n replacement: \"[REDACTED:npm-token]\",\n },\n\n // dotenv-style KEY=VALUE on its own line, where the KEY name looks sensitive.\n // This is a fallback for arbitrary secrets that don't match a specific\n // provider pattern. Captures the key, replaces the value.\n {\n name: \"dotenv-secret\",\n re: /^(\\s*(?:export\\s+)?[A-Z][A-Z0-9_]*?(?:KEY|TOKEN|SECRET|PASSWORD|PASSWD|PWD|API|AUTH|CREDENTIAL|PRIVATE|SESSION|COOKIE|BEARER|DSN)[A-Z0-9_]*\\s*=\\s*)(['\"]?)([^\\n'\"]{4,})\\2/gm,\n replacement: (m: string) => {\n // m is the full match; we keep the \"KEY=\" and quote, replace the value.\n // Re-run a small regex against m to preserve the prefix.\n const inner =\n /^(\\s*(?:export\\s+)?[A-Z][A-Z0-9_]*\\s*=\\s*)(['\"]?)([^\\n'\"]{4,})\\2/.exec(m);\n if (!inner) return \"[REDACTED:dotenv-secret]\";\n const [, prefix, quote] = inner;\n return `${prefix ?? \"\"}${quote ?? \"\"}[REDACTED:dotenv-secret]${quote ?? \"\"}`;\n },\n },\n\n // Email addresses\n {\n name: \"email\",\n re: /\\b[A-Za-z0-9._%+\\-]+@[A-Za-z0-9.\\-]+\\.[A-Za-z]{2,}\\b/g,\n replacement: \"[REDACTED:email]\",\n },\n\n // IPv4 — validates each octet is 0-255 to cut version-string false positives.\n // Skips three benign forms below in the post-filter.\n {\n name: \"ipv4\",\n re: /\\b(?:(?:25[0-5]|2[0-4]\\d|1\\d{2}|[1-9]?\\d)\\.){3}(?:25[0-5]|2[0-4]\\d|1\\d{2}|[1-9]?\\d)\\b/g,\n replacement: (m: string) => {\n if (m === \"0.0.0.0\" || m === \"127.0.0.1\" || m === \"255.255.255.255\") return m;\n return \"[REDACTED:ip]\";\n },\n },\n];\n\n// Sensitive key-name shapes used by the recursive object walker. If an\n// object's key name matches AND the value is a non-trivial string, we redact\n// the whole value regardless of provider-pattern match.\n// Names that almost-always carry a secret value. Avoid generic words like\n// `session` (matches `session_id`) or bare `token` (matches `csrf_token`\n// inputs that are themselves not sensitive in our context).\nexport const SENSITIVE_KEY_RE =\n /(?:^|[_\\-.])(?:api[_-]?key|access[_-]?token|secret|password|passwd|pwd|authorization|bearer|credential|private[_-]?key|client[_-]?secret|webhook[_-]?secret|service[_-]?account|refresh[_-]?token)(?:$|[_\\-.])/i;\n","import { PATTERNS, SENSITIVE_KEY_RE } from \"./patterns.js\";\n\n/** Run all redaction patterns against a string. Idempotent. */\nexport function scrubString(input: string): string {\n if (!input) return input;\n let s = input;\n for (const rule of PATTERNS) {\n if (typeof rule.replacement === \"function\") {\n s = s.replace(rule.re, rule.replacement);\n } else {\n s = s.replace(rule.re, rule.replacement);\n }\n }\n return s;\n}\n\n/**\n * Recursively redact a JSON-shaped value. Strings get pattern-scrubbed;\n * object properties whose KEY name looks sensitive (`apiKey`, `password`,\n * etc.) have their entire string value replaced — that catches arbitrary\n * secrets that don't match any provider pattern.\n *\n * Cycle-safe via a WeakSet seen.\n */\nexport function scrubAny<T>(value: T, seen: WeakSet<object> = new WeakSet()): T {\n if (value == null) return value;\n if (typeof value === \"string\") return scrubString(value) as T;\n if (typeof value !== \"object\") return value;\n if (seen.has(value as object)) return value;\n seen.add(value as object);\n\n if (Array.isArray(value)) {\n return value.map((v) => scrubAny(v, seen)) as T;\n }\n\n const out: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(value as Record<string, unknown>)) {\n if (SENSITIVE_KEY_RE.test(k) && typeof v === \"string\" && v.length >= 4) {\n out[k] = \"[REDACTED:by-key-name]\";\n } else {\n out[k] = scrubAny(v, seen);\n }\n }\n return out as T;\n}\n","import { nanoid } from \"nanoid\";\nimport { insertEvent, upsertSession } from \"../db.js\";\nimport type { AgentEvent } from \"@agentreel/shared-types\";\nimport type { SnapshotEvent } from \"./watcher.js\";\n\nconst IDLE_MS = 5 * 60 * 1000; // 5 minute gap = new session\nconst GLOBAL_KEY = \"__global__\";\n\ninterface OpenSession {\n id: string;\n startedAt: number;\n lastTs: number;\n cwd: string;\n}\n\nexport class CursorSessionManager {\n private open = new Map<string, OpenSession>();\n\n ingest(snapshot: SnapshotEvent): { sessionId: string; isNew: boolean } {\n const key = snapshot.workspace ?? GLOBAL_KEY;\n const ts = snapshot.timestamp;\n const cwd = snapshot.workspace ?? \"\";\n\n let session = this.open.get(key);\n let isNew = false;\n if (!session || ts - session.lastTs > IDLE_MS) {\n // Close out the previous session for this key, if any.\n if (session) this.closeSession(session, session.lastTs);\n session = {\n id: `cur_${nanoid(10)}`,\n startedAt: ts,\n lastTs: ts,\n cwd,\n };\n this.open.set(key, session);\n isNew = true;\n upsertSession({\n id: session.id,\n tool: \"cursor\",\n startedAt: ts,\n cwd,\n });\n } else {\n session.lastTs = ts;\n }\n\n const event: AgentEvent = {\n id: nanoid(),\n sessionId: session.id,\n tool: \"cursor\",\n type: \"tool_use_post\",\n ts,\n cwd,\n payload: {\n tool_name: \"Edit\",\n file_path: snapshot.filePath,\n added: snapshot.added,\n removed: snapshot.removed,\n binary: snapshot.binary,\n source: snapshot.source,\n patch: snapshot.patch,\n },\n };\n insertEvent(event);\n return { sessionId: session.id, isNew };\n }\n\n /** Stamp ended_at on every open session — call on shutdown. */\n closeAll(): void {\n const now = Date.now();\n for (const s of this.open.values()) this.closeSession(s, Math.max(s.lastTs, now));\n this.open.clear();\n }\n\n private closeSession(s: OpenSession, endedAt: number) {\n upsertSession({\n id: s.id,\n tool: \"cursor\",\n startedAt: s.startedAt,\n endedAt,\n cwd: s.cwd,\n });\n }\n}\n","import pc from \"picocolors\";\nimport { readConfig } from \"../config.js\";\nimport { flushOnce } from \"../upload/flush.js\";\nimport { IngestError } from \"../upload/client.js\";\n\nexport async function pushCommand(): Promise<void> {\n const cfg = readConfig();\n if (!cfg.apiKey) {\n console.error(pc.red(\"✗ Not linked. Run \") + pc.cyan(\"agentreel link <api-key>\"));\n process.exit(1);\n }\n\n let totalSessions = 0;\n let totalEvents = 0;\n\n // Drain in batches of MAX_BATCH_EVENTS / MAX_BATCH_BYTES until empty.\n for (;;) {\n let res;\n try {\n res = await flushOnce();\n } catch (err) {\n const e = err as Error;\n if (err instanceof IngestError) {\n console.error(pc.red(\"✗ \") + e.message);\n if (err.isPermanent) {\n console.error(\n pc.dim(\" not retrying — fix the cause (re-link, upgrade plan, etc.) and run push again.\"),\n );\n }\n } else {\n console.error(pc.red(\"✗ \") + e.message);\n }\n process.exit(1);\n }\n totalSessions += res.uploadedSessions;\n totalEvents += res.uploadedEvents;\n if (!res.moreAvailable) break;\n }\n\n if (totalEvents === 0) {\n console.log(pc.green(\"✓\") + \" queue is empty — nothing to upload.\");\n return;\n }\n console.log(\n pc.green(\"✓\") +\n ` uploaded ${totalEvents} events · ${totalSessions} session rows touched`,\n );\n}\n","import { nanoid } from \"nanoid\";\nimport { appendFileSync } from \"node:fs\";\nimport type { AgentEvent, ClaudeCodeHookInput, EventType } from \"@agentreel/shared-types\";\nimport { insertEvent, upsertSession } from \"../db.js\";\nimport { LOG_PATH, ensureAgentreelDir } from \"../paths.js\";\nimport { scrubAny } from \"../redact/scrubber.js\";\nimport { recomputeSessionCost } from \"../cost/transcript.js\";\n\nconst HOOK_EVENT_TO_TYPE: Record<string, EventType> = {\n SessionStart: \"session_start\",\n SessionEnd: \"session_end\",\n UserPromptSubmit: \"user_prompt_submit\",\n PreToolUse: \"tool_use_pre\",\n PostToolUse: \"tool_use_post\",\n Notification: \"notification\",\n Stop: \"stop\",\n SubagentStop: \"subagent_stop\",\n PreCompact: \"pre_compact\",\n};\n\nasync function readStdin(): Promise<string> {\n if (process.stdin.isTTY) return \"\";\n const chunks: Buffer[] = [];\n for await (const chunk of process.stdin) {\n chunks.push(chunk as Buffer);\n }\n return Buffer.concat(chunks).toString(\"utf8\");\n}\n\nfunction logError(err: unknown): void {\n try {\n ensureAgentreelDir();\n const line = `[${new Date().toISOString()}] hook error: ${\n err instanceof Error ? err.stack ?? err.message : String(err)\n }\\n`;\n appendFileSync(LOG_PATH, line);\n } catch {\n // swallow — never block Claude Code\n }\n}\n\nexport async function runHook(eventArg?: string): Promise<void> {\n // Hooks must never block or fail Claude Code. Wrap everything.\n try {\n const raw = await readStdin();\n if (!raw.trim()) return;\n const input = JSON.parse(raw) as ClaudeCodeHookInput;\n\n const hookEventName = input.hook_event_name ?? eventArg ?? \"Unknown\";\n const type: EventType = HOOK_EVENT_TO_TYPE[hookEventName] ?? \"unknown\";\n const ts = Date.now();\n const sessionId = input.session_id ?? \"unknown-session\";\n\n if (type === \"session_start\") {\n upsertSession({\n id: sessionId,\n tool: \"claude-code\",\n startedAt: ts,\n cwd: input.cwd,\n });\n } else if (type === \"session_end\") {\n upsertSession({\n id: sessionId,\n tool: \"claude-code\",\n startedAt: ts,\n endedAt: ts,\n cwd: input.cwd,\n });\n } else {\n // Make sure the session row exists so events have a parent.\n upsertSession({\n id: sessionId,\n tool: \"claude-code\",\n startedAt: ts,\n cwd: input.cwd,\n });\n }\n\n // Scrub the entire payload before persistence — never let raw secrets\n // touch SQLite, even briefly. scrubAny handles strings recursively and\n // also redacts values whose KEY name looks sensitive.\n const safePayload = scrubAny(input);\n const event: AgentEvent = {\n id: nanoid(),\n sessionId,\n tool: \"claude-code\",\n type,\n ts,\n cwd: input.cwd,\n payload: safePayload,\n };\n insertEvent(event);\n\n // After every hook fire, walk the transcript tail and update the\n // session's running cost / token totals. Incremental via offset\n // cache, so this stays cheap even on long sessions.\n try {\n recomputeSessionCost(sessionId, input.transcript_path);\n } catch (err) {\n // Cost is best-effort — never let a parse glitch break capture.\n logError(err);\n }\n } catch (err) {\n logError(err);\n }\n}\n","import { existsSync, statSync, openSync, readSync, closeSync } from \"node:fs\";\nimport { getDb, getMeta, setMeta } from \"../db.js\";\nimport { costCentsFor, ratesFor, type UsageBreakdown } from \"./pricing.js\";\n\ninterface TranscriptLine {\n type?: string;\n message?: {\n model?: string;\n usage?: Partial<{\n input_tokens: number;\n output_tokens: number;\n cache_read_input_tokens: number;\n cache_creation_input_tokens: number;\n }>;\n };\n}\n\nconst KEY_OFFSET = (sid: string) => `cost_offset:${sid}`;\nconst KEY_TOKENS = (sid: string) => `cost_tokens:${sid}`;\nconst KEY_CENTS = (sid: string) => `cost_cents:${sid}`;\nconst KEY_PATH = (sid: string) => `cost_path:${sid}`;\n\ninterface SessionTotals {\n totalCostCents: number;\n totalTokens: number;\n}\n\n/**\n * Parse the tail of a session's transcript JSONL, sum every assistant\n * `message.usage` block we haven't seen yet, and update the session row\n * with running cost / token totals.\n *\n * Safe to call on every hook fire — incremental via byte offset, so a\n * 50 MB transcript on the 200th tool call only re-reads the last few KB.\n */\nexport function recomputeSessionCost(sessionId: string, transcriptPath: string | undefined): void {\n if (!transcriptPath) {\n // First call may not have the path; remember the last good one.\n transcriptPath = getMeta(KEY_PATH(sessionId)) ?? undefined;\n } else {\n setMeta(KEY_PATH(sessionId), transcriptPath);\n }\n if (!transcriptPath || !existsSync(transcriptPath)) return;\n\n const stat = statSync(transcriptPath);\n const totalSize = stat.size;\n const offset = Number(getMeta(KEY_OFFSET(sessionId)) ?? \"0\");\n if (offset >= totalSize) return; // nothing new\n\n const buf = Buffer.alloc(totalSize - offset);\n const fd = openSync(transcriptPath, \"r\");\n try {\n readSync(fd, buf, 0, buf.length, offset);\n } finally {\n closeSync(fd);\n }\n\n const text = buf.toString(\"utf8\");\n // The tail may end mid-line if a writer is still flushing. Stash any\n // partial trailing line and only consume up through the last newline.\n const lastNewline = text.lastIndexOf(\"\\n\");\n if (lastNewline === -1) return; // no complete line yet\n const consumable = text.slice(0, lastNewline);\n const consumedBytes = Buffer.byteLength(consumable, \"utf8\") + 1; // include the \\n\n\n let addedTokens = 0;\n let addedCents = 0;\n for (const raw of consumable.split(\"\\n\")) {\n if (!raw) continue;\n let line: TranscriptLine;\n try {\n line = JSON.parse(raw) as TranscriptLine;\n } catch {\n continue;\n }\n if (line.type !== \"assistant\") continue;\n const usage = line.message?.usage;\n if (!usage) continue;\n\n const u: UsageBreakdown = {\n inputTokens: usage.input_tokens ?? 0,\n outputTokens: usage.output_tokens ?? 0,\n cacheReadTokens: usage.cache_read_input_tokens ?? 0,\n cacheCreationTokens: usage.cache_creation_input_tokens ?? 0,\n };\n const rates = ratesFor(line.message?.model);\n addedCents += costCentsFor(u, rates);\n addedTokens +=\n u.inputTokens + u.outputTokens + u.cacheReadTokens + u.cacheCreationTokens;\n }\n\n const prevTokens = Number(getMeta(KEY_TOKENS(sessionId)) ?? \"0\");\n const prevCents = Number(getMeta(KEY_CENTS(sessionId)) ?? \"0\");\n const newTokens = prevTokens + addedTokens;\n const newCents = prevCents + addedCents;\n\n setMeta(KEY_OFFSET(sessionId), String(offset + consumedBytes));\n setMeta(KEY_TOKENS(sessionId), String(newTokens));\n setMeta(KEY_CENTS(sessionId), String(newCents));\n\n // Stamp the totals on the session row so the upload picks them up.\n // Use COALESCE-style write — if the row vanished (shouldn't happen),\n // the UPDATE is a noop.\n const db = getDb();\n db.prepare(\n `UPDATE sessions\n SET total_cost_cents = ?, total_tokens = ?\n WHERE id = ?`,\n ).run(newCents, newTokens, sessionId);\n}\n\nexport function getSessionTotals(sessionId: string): SessionTotals {\n return {\n totalCostCents: Number(getMeta(KEY_CENTS(sessionId)) ?? \"0\"),\n totalTokens: Number(getMeta(KEY_TOKENS(sessionId)) ?? \"0\"),\n };\n}\n","// Anthropic published rates. Cents per million tokens.\n//\n// Update this table whenever Anthropic publishes new rates or releases\n// a new model family. Rates are intentionally hardcoded here (vs a\n// server fetch) so the agent works fully offline.\n\nexport interface ModelRates {\n /** Cents per million input tokens. */\n input: number;\n /** Cents per million output tokens. */\n output: number;\n /** Cents per million cache-read input tokens. */\n cacheRead: number;\n /** Cents per million cache-creation input tokens. */\n cacheCreation: number;\n}\n\nexport const MODEL_RATES: Record<string, ModelRates> = {\n // Claude 4.x\n \"claude-opus-4-7\": { input: 1500, output: 7500, cacheRead: 150, cacheCreation: 1875 },\n \"claude-opus-4-6\": { input: 1500, output: 7500, cacheRead: 150, cacheCreation: 1875 },\n \"claude-sonnet-4-6\": { input: 300, output: 1500, cacheRead: 30, cacheCreation: 375 },\n \"claude-sonnet-4-5\": { input: 300, output: 1500, cacheRead: 30, cacheCreation: 375 },\n \"claude-haiku-4-5\": { input: 80, output: 400, cacheRead: 8, cacheCreation: 100 },\n\n // Legacy 3.x (still seen in older transcripts)\n \"claude-3-5-sonnet\": { input: 300, output: 1500, cacheRead: 30, cacheCreation: 375 },\n \"claude-3-5-haiku\": { input: 80, output: 400, cacheRead: 8, cacheCreation: 100 },\n \"claude-3-opus\": { input: 1500, output: 7500, cacheRead: 150, cacheCreation: 1875 },\n};\n\nconst FALLBACK: ModelRates = MODEL_RATES[\"claude-sonnet-4-6\"]!;\n\n/**\n * Look up rates for a model id like `claude-sonnet-4-5-20250929`. We\n * match by prefix so date-stamped variants don't drop out of the table.\n */\nexport function ratesFor(model: string | undefined): ModelRates {\n if (!model) return FALLBACK;\n // Try exact, then strip a trailing date suffix.\n if (MODEL_RATES[model]) return MODEL_RATES[model];\n const stripped = model.replace(/-\\d{8}$/, \"\");\n if (MODEL_RATES[stripped]) return MODEL_RATES[stripped];\n // Try ever-shorter prefixes — handles unknown date suffixes.\n for (const key of Object.keys(MODEL_RATES)) {\n if (model.startsWith(key)) return MODEL_RATES[key]!;\n }\n return FALLBACK;\n}\n\nexport interface UsageBreakdown {\n inputTokens: number;\n outputTokens: number;\n cacheReadTokens: number;\n cacheCreationTokens: number;\n}\n\n/** Cost in cents. Rounded UP so we never under-report. */\nexport function costCentsFor(usage: UsageBreakdown, rates: ModelRates): number {\n const c =\n (usage.inputTokens * rates.input +\n usage.outputTokens * rates.output +\n usage.cacheReadTokens * rates.cacheRead +\n usage.cacheCreationTokens * rates.cacheCreation) /\n 1_000_000;\n return Math.ceil(c);\n}\n"],"mappings":"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","names":["mkdirSync","readFileSync","writeFileSync","existsSync","pc","existsSync","readFileSync","writeFileSync","resolve","pc","existsSync","readFileSync","ts","pc","uninstallClaudeCodeHooks","stopCommand","resolve","pc","existsSync","basename","homedir","join","readFile","existsSync","dirname","join","existsSync","join","dirname","sep","fileURLToPath","existsSync","readFileSync","statSync","join","sep","dirname","join","existsSync","readFile","ts","existsSync","pc","ts","basename","pc","nanoid","existsSync","statSync","openSync","existsSync","statSync","openSync","ts","nanoid"]}
1
+ {"version":3,"sources":["../src/paths.ts","../src/hooks/install.ts","../src/config.ts","../src/db.ts","../src/upload/client.ts","../src/upload/queue.ts","../src/upload/flush.ts","../src/commands/daemon.ts","../src/cli.ts","../src/commands/init.ts","../src/commands/status.ts","../src/commands/auth.ts","../src/commands/watch.ts","../src/cursor/paths.ts","../src/cursor/watcher.ts","../src/cursor/entries.ts","../src/cursor/diff.ts","../src/redact/ignore.ts","../src/redact/patterns.ts","../src/redact/scrubber.ts","../src/cursor/session.ts","../src/commands/push.ts","../src/commands/privacy.ts","../src/hooks/handler.ts","../src/cost/transcript.ts","../src/cost/pricing.ts"],"sourcesContent":["import { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { mkdirSync } from \"node:fs\";\n\nexport const HOME = homedir();\nexport const AGENTREEL_DIR = join(HOME, \".agentreel\");\nexport const DB_PATH = join(AGENTREEL_DIR, \"sessions.db\");\nexport const CONFIG_PATH = join(AGENTREEL_DIR, \"config.json\");\nexport const QUEUE_DIR = join(AGENTREEL_DIR, \"queue\");\nexport const LOG_PATH = join(AGENTREEL_DIR, \"agent.log\");\nexport const DAEMON_PID_PATH = join(AGENTREEL_DIR, \"daemon.pid\");\nexport const DAEMON_LOG_PATH = join(AGENTREEL_DIR, \"daemon.log\");\n\nexport const CLAUDE_DIR = join(HOME, \".claude\");\nexport const CLAUDE_SETTINGS_PATH = join(CLAUDE_DIR, \"settings.json\");\n\nexport function ensureAgentreelDir(): void {\n mkdirSync(AGENTREEL_DIR, { recursive: true });\n mkdirSync(QUEUE_DIR, { recursive: true });\n}\n","import { readFileSync, writeFileSync, existsSync, copyFileSync, mkdirSync } from \"node:fs\";\nimport { dirname } from \"node:path\";\nimport { CLAUDE_DIR, CLAUDE_SETTINGS_PATH } from \"../paths.js\";\n\nconst HOOK_MARKER = \"agentreel:v1\";\n\nconst HOOK_EVENTS = [\n \"SessionStart\",\n \"SessionEnd\",\n \"UserPromptSubmit\",\n \"PreToolUse\",\n \"PostToolUse\",\n \"Notification\",\n \"Stop\",\n \"SubagentStop\",\n \"PreCompact\",\n] as const;\n\ntype HookEntry = {\n type: \"command\";\n command: string;\n timeout?: number;\n};\n\ntype HookGroup = {\n matcher?: string;\n hooks: HookEntry[];\n __agentreel?: string;\n};\n\ntype ClaudeSettings = {\n hooks?: Record<string, HookGroup[]>;\n [key: string]: unknown;\n};\n\nfunction readSettings(): ClaudeSettings {\n if (!existsSync(CLAUDE_SETTINGS_PATH)) return {};\n const raw = readFileSync(CLAUDE_SETTINGS_PATH, \"utf8\");\n if (!raw.trim()) return {};\n return JSON.parse(raw) as ClaudeSettings;\n}\n\nfunction backupSettings(): string | null {\n if (!existsSync(CLAUDE_SETTINGS_PATH)) return null;\n const stamp = new Date().toISOString().replace(/[:.]/g, \"-\");\n const backup = `${CLAUDE_SETTINGS_PATH}.agentreel-backup-${stamp}`;\n copyFileSync(CLAUDE_SETTINGS_PATH, backup);\n return backup;\n}\n\nfunction buildHookEntry(event: string, hookCommandPrefix: string): HookEntry {\n // Final command shape: `<prefix> hook <Event>`. The prefix can be an\n // absolute path to dist/cli.js (global / dev installs) or an `npx -y …`\n // form (when the user ran us via npx and we don't have a stable on-disk\n // location to point Claude Code at).\n return {\n type: \"command\",\n command: `${hookCommandPrefix} hook ${event}`,\n timeout: 5,\n };\n}\n\nexport function quotePath(p: string): string {\n return /[\\s'\"$`\\\\]/.test(p) ? `\"${p.replace(/\"/g, '\\\\\"')}\"` : p;\n}\n\nexport interface InstallResult {\n backup: string | null;\n installedEvents: string[];\n hookCommandPrefix: string;\n}\n\nexport function installClaudeCodeHooks(hookCommandPrefix: string): InstallResult {\n mkdirSync(CLAUDE_DIR, { recursive: true });\n mkdirSync(dirname(CLAUDE_SETTINGS_PATH), { recursive: true });\n const backup = backupSettings();\n\n const settings = readSettings();\n settings.hooks ??= {};\n\n for (const event of HOOK_EVENTS) {\n const groups = settings.hooks[event] ?? [];\n // Drop any prior agentreel-managed group so re-running is idempotent.\n const filtered = groups.filter((g) => g.__agentreel !== HOOK_MARKER);\n filtered.push({\n matcher: \".*\",\n __agentreel: HOOK_MARKER,\n hooks: [buildHookEntry(event, hookCommandPrefix)],\n });\n settings.hooks[event] = filtered;\n }\n\n writeFileSync(CLAUDE_SETTINGS_PATH, JSON.stringify(settings, null, 2) + \"\\n\", \"utf8\");\n return { backup, installedEvents: [...HOOK_EVENTS], hookCommandPrefix };\n}\n\nexport function uninstallClaudeCodeHooks(): { backup: string | null } {\n if (!existsSync(CLAUDE_SETTINGS_PATH)) return { backup: null };\n const backup = backupSettings();\n const settings = readSettings();\n if (settings.hooks) {\n for (const event of Object.keys(settings.hooks)) {\n const groups = settings.hooks[event] ?? [];\n const remaining = groups.filter((g) => g.__agentreel !== HOOK_MARKER);\n if (remaining.length === 0) delete settings.hooks[event];\n else settings.hooks[event] = remaining;\n }\n if (Object.keys(settings.hooks).length === 0) delete settings.hooks;\n }\n writeFileSync(CLAUDE_SETTINGS_PATH, JSON.stringify(settings, null, 2) + \"\\n\", \"utf8\");\n return { backup };\n}\n","import { readFileSync, writeFileSync, existsSync, chmodSync } from \"node:fs\";\nimport { CONFIG_PATH, ensureAgentreelDir } from \"./paths.js\";\n\nexport interface AgentConfig {\n apiKey?: string;\n apiBaseUrl: string;\n workspaceId?: string;\n installedAt?: number;\n hooksInstalled?: boolean;\n /** When true, hooks + watcher no-op (don't capture). Toggled via\n * `agentreel pause` / `agentreel resume`. Kept here so the state\n * survives shell exits — pausing for an evening should hold until\n * the user resumes, not until reboot. */\n paused?: boolean;\n pausedAt?: number;\n schemaVersion: 1;\n}\n\n/**\n * The user's explicit decision to skip capture for the current shell:\n * AGENTREEL_DISABLE=1 claude\n * Or temporarily via:\n * AGENTREEL_DISABLE=1 npx @agentreel/agent push\n * No state mutation — purely a process-level switch.\n */\nexport function isCaptureDisabledByEnv(): boolean {\n const v = process.env.AGENTREEL_DISABLE;\n return v === \"1\" || v === \"true\" || v === \"yes\";\n}\n\n/** True if capture should be skipped for ANY reason (env or persisted pause). */\nexport function isCapturePaused(cfg: AgentConfig = readConfig()): boolean {\n return isCaptureDisabledByEnv() || cfg.paused === true;\n}\n\nconst DEFAULT: AgentConfig = {\n apiBaseUrl: \"https://api.agentreel.dev\",\n schemaVersion: 1,\n};\n\nexport function readConfig(): AgentConfig {\n if (!existsSync(CONFIG_PATH)) return { ...DEFAULT };\n try {\n const raw = readFileSync(CONFIG_PATH, \"utf8\");\n return { ...DEFAULT, ...JSON.parse(raw) };\n } catch {\n return { ...DEFAULT };\n }\n}\n\nexport function writeConfig(cfg: AgentConfig): void {\n ensureAgentreelDir();\n // mode 0o600 — config.json holds the API key; only the owning user\n // should ever be able to read it. chmod after write to be sure even\n // if the file already existed with looser perms.\n writeFileSync(CONFIG_PATH, JSON.stringify(cfg, null, 2) + \"\\n\", {\n encoding: \"utf8\",\n mode: 0o600,\n });\n try {\n chmodSync(CONFIG_PATH, 0o600);\n } catch {\n // Non-Unix or filesystem without mode bits — best effort.\n }\n}\n","import Database from \"better-sqlite3\";\nimport type { Database as DB } from \"better-sqlite3\";\nimport { DB_PATH, ensureAgentreelDir } from \"./paths.js\";\nimport type { AgentEvent, Session, Tool } from \"@agentreel/shared-types\";\n\nlet _db: DB | null = null;\n\nexport function getDb(): DB {\n if (_db) return _db;\n ensureAgentreelDir();\n const db = new Database(DB_PATH);\n db.pragma(\"journal_mode = WAL\");\n db.pragma(\"synchronous = NORMAL\");\n migrate(db);\n _db = db;\n return db;\n}\n\nfunction migrate(db: DB): void {\n db.exec(`\n CREATE TABLE IF NOT EXISTS sessions (\n id TEXT PRIMARY KEY,\n tool TEXT NOT NULL,\n started_at INTEGER NOT NULL,\n ended_at INTEGER,\n cwd TEXT,\n total_cost_cents INTEGER,\n total_tokens INTEGER\n );\n CREATE TABLE IF NOT EXISTS events (\n id TEXT PRIMARY KEY,\n session_id TEXT NOT NULL,\n tool TEXT NOT NULL,\n type TEXT NOT NULL,\n ts INTEGER NOT NULL,\n cwd TEXT,\n payload TEXT NOT NULL,\n uploaded_at INTEGER\n );\n CREATE INDEX IF NOT EXISTS idx_events_session ON events(session_id, ts);\n CREATE INDEX IF NOT EXISTS idx_events_pending ON events(uploaded_at) WHERE uploaded_at IS NULL;\n CREATE TABLE IF NOT EXISTS meta (\n key TEXT PRIMARY KEY,\n value TEXT\n );\n `);\n}\n\nexport function getMeta(key: string): string | null {\n const db = getDb();\n const row = db.prepare(`SELECT value FROM meta WHERE key = ?`).get(key) as\n | { value: string }\n | undefined;\n return row?.value ?? null;\n}\n\nexport function setMeta(key: string, value: string | null): void {\n const db = getDb();\n if (value == null) {\n db.prepare(`DELETE FROM meta WHERE key = ?`).run(key);\n return;\n }\n db.prepare(\n `INSERT INTO meta (key, value) VALUES (?, ?)\n ON CONFLICT(key) DO UPDATE SET value = excluded.value`,\n ).run(key, value);\n}\n\nexport function pendingByteSize(): number {\n const db = getDb();\n const row = db\n .prepare(\n `SELECT COALESCE(SUM(LENGTH(payload)), 0) AS bytes\n FROM events WHERE uploaded_at IS NULL`,\n )\n .get() as { bytes: number };\n return row.bytes;\n}\n\nexport function upsertSession(s: Session): void {\n const db = getDb();\n db.prepare(\n `INSERT INTO sessions (id, tool, started_at, ended_at, cwd, total_cost_cents, total_tokens)\n VALUES (@id, @tool, @startedAt, @endedAt, @cwd, @totalCostCents, @totalTokens)\n ON CONFLICT(id) DO UPDATE SET\n ended_at = COALESCE(excluded.ended_at, sessions.ended_at),\n cwd = COALESCE(excluded.cwd, sessions.cwd),\n total_cost_cents = COALESCE(excluded.total_cost_cents, sessions.total_cost_cents),\n total_tokens = COALESCE(excluded.total_tokens, sessions.total_tokens)`,\n ).run({\n id: s.id,\n tool: s.tool,\n startedAt: s.startedAt,\n endedAt: s.endedAt ?? null,\n cwd: s.cwd ?? null,\n totalCostCents: s.totalCostCents ?? null,\n totalTokens: s.totalTokens ?? null,\n });\n}\n\nexport function insertEvent(e: AgentEvent): void {\n const db = getDb();\n db.prepare(\n `INSERT OR IGNORE INTO events (id, session_id, tool, type, ts, cwd, payload)\n VALUES (?, ?, ?, ?, ?, ?, ?)`,\n ).run(e.id, e.sessionId, e.tool, e.type, e.ts, e.cwd ?? null, JSON.stringify(e.payload ?? {}));\n}\n\nexport function countEvents(): { total: number; pending: number } {\n const db = getDb();\n const total = db.prepare(`SELECT COUNT(*) AS c FROM events`).get() as { c: number };\n const pending = db\n .prepare(`SELECT COUNT(*) AS c FROM events WHERE uploaded_at IS NULL`)\n .get() as { c: number };\n return { total: total.c, pending: pending.c };\n}\n\nexport function listRecentSessions(limit = 10): Array<{\n id: string;\n tool: Tool;\n started_at: number;\n ended_at: number | null;\n cwd: string | null;\n}> {\n const db = getDb();\n return db\n .prepare(\n `SELECT id, tool, started_at, ended_at, cwd\n FROM sessions ORDER BY started_at DESC LIMIT ?`,\n )\n .all(limit) as Array<{\n id: string;\n tool: Tool;\n started_at: number;\n ended_at: number | null;\n cwd: string | null;\n }>;\n}\n","import type { AgentConfig } from \"../config.js\";\n\nexport interface IngestSession {\n id: string;\n tool: string;\n started_at: number;\n ended_at?: number | null;\n cwd?: string | null;\n total_cost_cents?: number | null;\n total_tokens?: number | null;\n}\n\nexport interface IngestEvent {\n id: string;\n session_id: string;\n ts: number;\n type: string;\n tool: string;\n cwd?: string | null;\n payload: unknown;\n}\n\nexport interface IngestResponse {\n ok: boolean;\n sessions_written?: number;\n events_written?: number;\n error?: string;\n reason?: string;\n}\n\nexport class IngestError extends Error {\n constructor(\n message: string,\n readonly status: number,\n readonly body: IngestResponse | null,\n ) {\n super(message);\n this.name = \"IngestError\";\n }\n /** 4xx (except 408/429) — payload-shaped problem the agent can't fix by retrying. */\n get isPermanent(): boolean {\n return this.status >= 400 && this.status < 500 && this.status !== 408 && this.status !== 429;\n }\n}\n\nexport async function postIngest(\n cfg: AgentConfig,\n body: { sessions?: IngestSession[]; events?: IngestEvent[] },\n): Promise<IngestResponse> {\n if (!cfg.apiKey) {\n throw new Error(\"Not linked. Run: agentreel link <key>\");\n }\n const url = `${cfg.apiBaseUrl.replace(/\\/$/, \"\")}/api/v1/sessions/ingest`;\n const res = await fetch(url, {\n method: \"POST\",\n headers: {\n \"content-type\": \"application/json\",\n authorization: `Bearer ${cfg.apiKey}`,\n },\n body: JSON.stringify(body),\n });\n let data: IngestResponse | null = null;\n try {\n data = (await res.json()) as IngestResponse;\n } catch {\n // Non-JSON body — treat as transient if 5xx, permanent otherwise.\n }\n if (!res.ok || !data?.ok) {\n const reason = data?.reason ? ` (${data.reason})` : \"\";\n const tag = data?.error ?? `http-${res.status}`;\n throw new IngestError(`${tag}${reason}`, res.status, data);\n }\n return data;\n}\n","import { getDb } from \"../db.js\";\nimport type { IngestEvent, IngestSession } from \"./client.js\";\n\ninterface DBSessionRow {\n id: string;\n tool: string;\n started_at: number;\n ended_at: number | null;\n cwd: string | null;\n total_cost_cents: number | null;\n total_tokens: number | null;\n}\n\ninterface DBEventRow {\n id: string;\n session_id: string;\n tool: string;\n type: string;\n ts: number;\n cwd: string | null;\n payload: string;\n}\n\nexport interface PendingBatch {\n sessions: IngestSession[];\n events: IngestEvent[];\n eventIds: string[]; // for the post-write mark\n}\n\n// Cloud cap is 5 MB; we stay well under that to leave room for JSON framing\n// + auth headers and to keep individual round-trips snappy.\nexport const MAX_BATCH_BYTES = 1024 * 1024; // 1 MB\nexport const MAX_BATCH_EVENTS = 500;\n\nexport function takePendingBatch(\n maxEvents = MAX_BATCH_EVENTS,\n maxBytes = MAX_BATCH_BYTES,\n): PendingBatch {\n const db = getDb();\n const candidateRows = db\n .prepare(\n `SELECT id, session_id, tool, type, ts, cwd, payload\n FROM events\n WHERE uploaded_at IS NULL\n ORDER BY ts ASC\n LIMIT ?`,\n )\n .all(maxEvents) as DBEventRow[];\n\n if (candidateRows.length === 0) return { sessions: [], events: [], eventIds: [] };\n\n // Trim to byte budget. Always include at least one event so a single\n // oversized payload doesn't get stuck in the queue forever — the server\n // can reject it and we'll mark it uploaded to skip past.\n const eventRows: DBEventRow[] = [];\n let bytes = 0;\n for (const row of candidateRows) {\n const rowBytes = Buffer.byteLength(row.payload, \"utf8\");\n if (eventRows.length > 0 && bytes + rowBytes > maxBytes) break;\n eventRows.push(row);\n bytes += rowBytes;\n }\n\n const sessionIds = [...new Set(eventRows.map((e) => e.session_id))];\n const placeholders = sessionIds.map(() => \"?\").join(\",\");\n const sessionRows = db\n .prepare(\n `SELECT id, tool, started_at, ended_at, cwd, total_cost_cents, total_tokens\n FROM sessions WHERE id IN (${placeholders})`,\n )\n .all(...sessionIds) as DBSessionRow[];\n\n const sessions: IngestSession[] = sessionRows.map((s) => ({\n id: s.id,\n tool: s.tool,\n started_at: s.started_at,\n ended_at: s.ended_at,\n cwd: s.cwd,\n total_cost_cents: s.total_cost_cents,\n total_tokens: s.total_tokens,\n }));\n\n const events: IngestEvent[] = eventRows.map((e) => ({\n id: e.id,\n session_id: e.session_id,\n ts: e.ts,\n type: e.type,\n tool: e.tool,\n cwd: e.cwd,\n payload: safeParse(e.payload),\n }));\n\n return { sessions, events, eventIds: eventRows.map((r) => r.id) };\n}\n\nexport function markUploaded(eventIds: string[]): void {\n if (eventIds.length === 0) return;\n const db = getDb();\n const now = Date.now();\n const stmt = db.prepare(`UPDATE events SET uploaded_at = ? WHERE id = ?`);\n const tx = db.transaction((ids: string[]) => {\n for (const id of ids) stmt.run(now, id);\n });\n tx(eventIds);\n}\n\nfunction safeParse(s: string): unknown {\n try {\n return JSON.parse(s);\n } catch {\n return s;\n }\n}\n","import { getMeta, setMeta } from \"../db.js\";\nimport { readConfig } from \"../config.js\";\nimport { IngestError, postIngest } from \"./client.js\";\nimport { MAX_BATCH_BYTES, MAX_BATCH_EVENTS, markUploaded, takePendingBatch } from \"./queue.js\";\n\nexport const META_LAST_SYNC_AT = \"last_sync_at\";\nexport const META_LAST_ERROR_AT = \"last_error_at\";\nexport const META_LAST_ERROR_MSG = \"last_error_msg\";\nexport const META_CONSECUTIVE_FAILS = \"consecutive_failures\";\nexport const META_NEXT_ATTEMPT_AT = \"next_attempt_at\";\n\nconst BACKOFF_BASE_MS = 1_000;\nconst BACKOFF_MAX_MS = 5 * 60_000;\n\nexport interface FlushResult {\n uploadedEvents: number;\n uploadedSessions: number;\n /** True if there are still events pending after this flush (hit batch cap, more to do). */\n moreAvailable: boolean;\n}\n\n/** Compute the wall-clock time the next attempt is allowed to start. */\nexport function nextAttemptAt(): number {\n const raw = getMeta(META_NEXT_ATTEMPT_AT);\n return raw ? Number(raw) : 0;\n}\n\nexport function consecutiveFailures(): number {\n const raw = getMeta(META_CONSECUTIVE_FAILS);\n return raw ? Number(raw) : 0;\n}\n\nfunction recordSuccess() {\n const now = Date.now();\n setMeta(META_LAST_SYNC_AT, String(now));\n setMeta(META_LAST_ERROR_AT, null);\n setMeta(META_LAST_ERROR_MSG, null);\n setMeta(META_CONSECUTIVE_FAILS, \"0\");\n setMeta(META_NEXT_ATTEMPT_AT, \"0\");\n}\n\nfunction recordFailure(err: Error, permanent: boolean) {\n const now = Date.now();\n const fails = consecutiveFailures() + 1;\n setMeta(META_LAST_ERROR_AT, String(now));\n setMeta(META_LAST_ERROR_MSG, truncate(err.message, 500));\n setMeta(META_CONSECUTIVE_FAILS, String(fails));\n if (permanent) {\n // Permanent errors (4xx like bad-prefix, plan-limit) — back off the\n // longest window so we don't hammer the server, but don't give up\n // forever; user may upgrade plan or re-link, and we want the next\n // tick to recover within minutes.\n setMeta(META_NEXT_ATTEMPT_AT, String(now + BACKOFF_MAX_MS));\n return;\n }\n // Exponential: 1s, 2s, 4s, ..., capped at 5min, with 0–25% jitter.\n const exp = Math.min(BACKOFF_MAX_MS, BACKOFF_BASE_MS * 2 ** (fails - 1));\n const jitter = exp * 0.25 * Math.random();\n setMeta(META_NEXT_ATTEMPT_AT, String(now + exp + jitter));\n}\n\nfunction truncate(s: string, n: number) {\n return s.length > n ? s.slice(0, n - 1) + \"…\" : s;\n}\n\n/**\n * Flush a single batch. Returns moreAvailable=true if the queue still has\n * events the daemon should pick up on the next tick (we hit the byte/event\n * cap mid-flush). Throws on failure — caller decides whether to swallow.\n */\nexport async function flushOnce(): Promise<FlushResult> {\n const cfg = readConfig();\n if (!cfg.apiKey) {\n throw new Error(\"Not linked. Run: agentreel link <api-key>\");\n }\n const batch = takePendingBatch(MAX_BATCH_EVENTS, MAX_BATCH_BYTES);\n if (batch.events.length === 0) {\n // Nothing to do isn't an error — but don't stamp last_sync, since\n // we didn't actually round-trip anything.\n return { uploadedEvents: 0, uploadedSessions: 0, moreAvailable: false };\n }\n try {\n const res = await postIngest(cfg, { sessions: batch.sessions, events: batch.events });\n markUploaded(batch.eventIds);\n recordSuccess();\n return {\n uploadedEvents: res.events_written ?? 0,\n uploadedSessions: res.sessions_written ?? 0,\n moreAvailable: batch.events.length === MAX_BATCH_EVENTS,\n };\n } catch (err) {\n const permanent = err instanceof IngestError && err.isPermanent;\n recordFailure(err as Error, permanent);\n throw err;\n }\n}\n","import pc from \"picocolors\";\nimport { spawn } from \"node:child_process\";\nimport {\n existsSync,\n openSync,\n readFileSync,\n unlinkSync,\n writeFileSync,\n} from \"node:fs\";\nimport {\n DAEMON_LOG_PATH,\n DAEMON_PID_PATH,\n ensureAgentreelDir,\n} from \"../paths.js\";\nimport { pendingByteSize } from \"../db.js\";\nimport { flushOnce, nextAttemptAt } from \"../upload/flush.js\";\nimport { MAX_BATCH_BYTES } from \"../upload/queue.js\";\nimport { IngestError } from \"../upload/client.js\";\nimport { readConfig } from \"../config.js\";\n\nconst TICK_INTERVAL_MS = 30_000;\nconst EARLY_FLUSH_BYTES = MAX_BATCH_BYTES; // flush early once pending crosses 1 MB\n\nexport interface DaemonOpts {\n detach?: boolean;\n}\n\nexport async function daemonCommand(opts: DaemonOpts = {}): Promise<void> {\n const cfg = readConfig();\n if (!cfg.apiKey) {\n console.error(pc.red(\"✗ Not linked. Run \") + pc.cyan(\"agentreel link <api-key>\"));\n process.exit(1);\n }\n\n if (opts.detach) {\n spawnDetached();\n return;\n }\n\n if (!claimPidFile()) {\n process.exit(1);\n }\n\n const release = () => {\n try {\n unlinkSync(DAEMON_PID_PATH);\n } catch {\n /* ignore */\n }\n };\n\n let stopping = false;\n const stop = () => {\n if (stopping) return;\n stopping = true;\n console.log(pc.dim(\"\\n daemon stopping…\"));\n release();\n process.exit(0);\n };\n process.on(\"SIGINT\", stop);\n process.on(\"SIGTERM\", stop);\n process.on(\"beforeExit\", release);\n\n console.log(pc.green(\"●\") + \" agentreel daemon running\");\n console.log(pc.dim(` api: ${cfg.apiBaseUrl}`));\n console.log(pc.dim(` tick: every ${TICK_INTERVAL_MS / 1000}s, early flush at ${(EARLY_FLUSH_BYTES / 1024).toFixed(0)} KB`));\n console.log(pc.dim(\" Ctrl-C to stop\"));\n\n // Loop until killed. Each iteration:\n // 1. honor backoff (next_attempt_at) before doing anything\n // 2. drain the queue in batches as long as moreAvailable\n // 3. sleep up to 30s, but wake early if pending bytes cross 1 MB\n for (;;) {\n if (stopping) return;\n\n // Backoff: if a prior failure scheduled a retry in the future, wait.\n const nextAt = nextAttemptAt();\n const now = Date.now();\n if (nextAt > now) {\n await sleepInterruptible(nextAt - now, () => stopping);\n continue;\n }\n\n // Drain.\n try {\n for (;;) {\n const res = await flushOnce();\n if (res.uploadedEvents > 0) {\n console.log(\n pc.dim(` [${ts()}]`) +\n pc.green(\" ✓\") +\n ` ${res.uploadedEvents} events · ${res.uploadedSessions} sessions`,\n );\n }\n if (!res.moreAvailable) break;\n }\n } catch (err) {\n const e = err as Error;\n if (err instanceof IngestError && err.isPermanent) {\n console.error(\n pc.dim(` [${ts()}]`) + pc.red(\" ✗ \") + e.message + pc.dim(\" (5min backoff)\"),\n );\n } else {\n console.error(pc.dim(` [${ts()}]`) + pc.yellow(\" · \") + e.message);\n }\n // flushOnce already recorded the backoff window.\n }\n\n // Wait for the next tick, but wake early if the queue hits 1 MB.\n await waitForTickOrPressure(TICK_INTERVAL_MS, EARLY_FLUSH_BYTES, () => stopping);\n }\n}\n\nfunction claimPidFile(): boolean {\n ensureAgentreelDir();\n if (existsSync(DAEMON_PID_PATH)) {\n const raw = readFileSync(DAEMON_PID_PATH, \"utf8\").trim();\n const pid = Number(raw);\n if (Number.isFinite(pid) && pid > 0 && isAlive(pid)) {\n console.error(pc.red(`✗ daemon already running (pid ${pid})`));\n console.error(pc.dim(` if this is wrong, remove ${DAEMON_PID_PATH}`));\n return false;\n }\n // Stale pid file — overwrite.\n }\n writeFileSync(DAEMON_PID_PATH, String(process.pid), { encoding: \"utf8\", mode: 0o600 });\n return true;\n}\n\nfunction isAlive(pid: number): boolean {\n try {\n process.kill(pid, 0);\n return true;\n } catch {\n return false;\n }\n}\n\nfunction sleepInterruptible(ms: number, shouldStop: () => boolean): Promise<void> {\n return new Promise((resolve) => {\n if (ms <= 0) return resolve();\n const start = Date.now();\n const t = setInterval(() => {\n if (shouldStop() || Date.now() - start >= ms) {\n clearInterval(t);\n resolve();\n }\n }, 250);\n });\n}\n\nfunction spawnDetached(): void {\n ensureAgentreelDir();\n // If a live pid is already on disk, refuse — we'd just hit the same\n // claimPidFile check from inside the child and lose stderr to the log.\n if (existsSync(DAEMON_PID_PATH)) {\n const raw = readFileSync(DAEMON_PID_PATH, \"utf8\").trim();\n const pid = Number(raw);\n if (Number.isFinite(pid) && pid > 0 && isAlive(pid)) {\n console.error(pc.red(`✗ daemon already running (pid ${pid})`));\n console.error(pc.dim(\" use \") + pc.cyan(\"agentreel stop\") + pc.dim(\" first\"));\n process.exit(1);\n }\n }\n\n // Open the log in append mode so child stdout/stderr persist across\n // restarts. argv[0] is the same node binary; pass `daemon` (no\n // --detach) so the child runs the foreground loop.\n const out = openSync(DAEMON_LOG_PATH, \"a\");\n const err = openSync(DAEMON_LOG_PATH, \"a\");\n const child = spawn(process.execPath, [process.argv[1]!, \"daemon\"], {\n detached: true,\n stdio: [\"ignore\", out, err],\n env: process.env,\n });\n // Don't keep the parent alive waiting on the child; let it become\n // an orphan adopted by init. Releasing the IPC handle is necessary\n // even though we passed `ignore` — defensive.\n child.unref();\n console.log(pc.green(\"●\") + ` daemon started (pid ${child.pid})`);\n console.log(pc.dim(` log: ${DAEMON_LOG_PATH}`));\n console.log(pc.dim(` stop: agentreel stop`));\n}\n\nexport function stopCommand(): void {\n if (!existsSync(DAEMON_PID_PATH)) {\n console.log(pc.dim(\"· daemon not running\"));\n return;\n }\n const raw = readFileSync(DAEMON_PID_PATH, \"utf8\").trim();\n const pid = Number(raw);\n if (!Number.isFinite(pid) || pid <= 0) {\n try {\n unlinkSync(DAEMON_PID_PATH);\n } catch {\n /* ignore */\n }\n console.log(pc.dim(\"· cleared stale pid file\"));\n return;\n }\n if (!isAlive(pid)) {\n try {\n unlinkSync(DAEMON_PID_PATH);\n } catch {\n /* ignore */\n }\n console.log(pc.dim(`· no live daemon for pid ${pid} — cleared stale pid file`));\n return;\n }\n try {\n process.kill(pid, \"SIGTERM\");\n console.log(pc.green(\"✓\") + ` sent SIGTERM to pid ${pid}`);\n } catch (err) {\n console.error(pc.red(\"✗ \") + (err as Error).message);\n process.exit(1);\n }\n}\n\nfunction waitForTickOrPressure(\n tickMs: number,\n pressureBytes: number,\n shouldStop: () => boolean,\n): Promise<void> {\n return new Promise((resolve) => {\n const start = Date.now();\n const t = setInterval(() => {\n if (shouldStop()) {\n clearInterval(t);\n return resolve();\n }\n if (Date.now() - start >= tickMs) {\n clearInterval(t);\n return resolve();\n }\n // Pressure check: cheap COUNT/SUM query on the indexed pending column.\n try {\n if (pendingByteSize() >= pressureBytes) {\n clearInterval(t);\n return resolve();\n }\n } catch {\n // db locked / not initialized — let the tick handle it.\n }\n }, 1_000);\n });\n}\n\nfunction ts(): string {\n const d = new Date();\n return d.toTimeString().slice(0, 8);\n}\n","import { Command } from \"commander\";\nimport { initCommand } from \"./commands/init.js\";\n\n// Replaced at build time by tsup's `define`. Fallback covers running via\n// ts-node where the literal isn't substituted.\ndeclare const __AGENTREEL_VERSION__: string;\nconst VERSION =\n typeof __AGENTREEL_VERSION__ === \"string\" ? __AGENTREEL_VERSION__ : \"dev\";\nimport { statusCommand } from \"./commands/status.js\";\nimport { linkCommand, logoutCommand, uninstallCommand } from \"./commands/auth.js\";\nimport { watchCommand } from \"./commands/watch.js\";\nimport { pushCommand } from \"./commands/push.js\";\nimport { daemonCommand, stopCommand } from \"./commands/daemon.js\";\nimport {\n forgetCommand,\n pauseCommand,\n resumeCommand,\n} from \"./commands/privacy.js\";\nimport { runHook } from \"./hooks/handler.js\";\n\nconst program = new Command();\n\nprogram\n .name(\"agentreel\")\n .description(\"AgentReel — capture Claude Code and Cursor sessions locally\")\n .version(VERSION);\n\nprogram\n .command(\"init\")\n .description(\"install Claude Code hooks and create the local SQLite buffer\")\n .action(async () => {\n await initCommand();\n });\n\nprogram\n .command(\"status\")\n .description(\"show local capture status, recent sessions, queue depth\")\n .action(async () => {\n await statusCommand();\n });\n\nprogram\n .command(\"watch\")\n .description(\"watch Cursor's local history and capture edits as events\")\n .action(async () => {\n await watchCommand();\n });\n\nprogram\n .command(\"link [api-key]\")\n .description(\"authenticate the local agent with agentreel.dev\")\n .option(\"--api <url>\", \"override the API base URL (default https://api.agentreel.dev)\")\n .action(async (apiKey: string | undefined, opts: { api?: string }) => {\n await linkCommand(apiKey, opts);\n });\n\nprogram\n .command(\"push\")\n .description(\"upload pending events to agentreel.dev\")\n .action(async () => {\n await pushCommand();\n });\n\nprogram\n .command(\"daemon\")\n .description(\"run the background uploader (30s ticks, 1MB early-flush, exponential backoff)\")\n .option(\"--detach\", \"fork into the background and return immediately; logs to ~/.agentreel/daemon.log\")\n .action(async (opts: { detach?: boolean }) => {\n await daemonCommand({ detach: opts.detach });\n });\n\nprogram\n .command(\"stop\")\n .description(\"stop the running background uploader\")\n .action(() => {\n stopCommand();\n });\n\nprogram\n .command(\"pause\")\n .description(\"pause local capture — hooks and watcher no-op until `resume`\")\n .action(() => {\n pauseCommand();\n });\n\nprogram\n .command(\"resume\")\n .description(\"resume local capture after `pause`\")\n .action(() => {\n resumeCommand();\n });\n\nprogram\n .command(\"forget [session-ids...]\")\n .description(\"delete captured sessions from the local SQLite buffer\")\n .option(\"--all\", \"wipe every session (asks for confirmation)\")\n .option(\"--force\", \"skip the confirmation prompt (use with care)\")\n .action(async (ids: string[], opts: { all?: boolean; force?: boolean }) => {\n await forgetCommand(ids ?? [], opts);\n });\n\nprogram\n .command(\"logout\")\n .description(\"clear local credentials\")\n .action(async () => {\n await logoutCommand();\n });\n\nprogram\n .command(\"uninstall\")\n .description(\"remove AgentReel hooks from ~/.claude/settings.json\")\n .action(async () => {\n await uninstallCommand();\n });\n\nprogram\n .command(\"hook <event>\")\n .description(\"internal: hook handler invoked by Claude Code (reads JSON from stdin)\")\n .action(async (event: string) => {\n await runHook(event);\n });\n\nprogram.parseAsync(process.argv).catch((err) => {\n // Top-level: if we got this far on a hook invocation, something is very wrong.\n // For all other commands, print and exit non-zero.\n const cmd = process.argv[2];\n if (cmd === \"hook\") {\n process.exit(0);\n }\n console.error(err);\n process.exit(1);\n});\n","import { realpathSync } from \"node:fs\";\nimport { fileURLToPath } from \"node:url\";\nimport { sep } from \"node:path\";\nimport pc from \"picocolors\";\nimport { installClaudeCodeHooks, quotePath } from \"../hooks/install.js\";\nimport { readConfig, writeConfig } from \"../config.js\";\nimport { getDb } from \"../db.js\";\nimport { ensureAgentreelDir } from \"../paths.js\";\n\nconst PACKAGE_NAME = \"@agentreel/agent\";\n\ninterface ResolvedBinary {\n absolutePath: string;\n isEphemeral: boolean; // true when running from an npx temp dir\n}\n\nfunction resolveAgentBinary(): ResolvedBinary {\n // tsup builds to dist/cli.js with a node shebang; npm symlinks it to\n // <prefix>/bin/agentreel. The realpath through that symlink is stable for\n // npm i -g and for in-tree development. For `npx` installs it points\n // inside ~/.npm/_npx/<hash>/ which gets cleaned eventually — we detect\n // that and fall back to an `npx -y …` hook command instead.\n const here = fileURLToPath(import.meta.url);\n const real = realpathSync(here);\n const isEphemeral = real.includes(`${sep}_npx${sep}`) || real.includes(\"/_npx/\");\n return { absolutePath: real, isEphemeral };\n}\n\nfunction chooseHookPrefix(bin: ResolvedBinary): { prefix: string; mode: \"absolute\" | \"npx\" } {\n if (process.env.AGENTREEL_HOOK_COMMAND) {\n return { prefix: process.env.AGENTREEL_HOOK_COMMAND, mode: \"absolute\" };\n }\n if (bin.isEphemeral) {\n return { prefix: `npx -y ${PACKAGE_NAME}`, mode: \"npx\" };\n }\n return { prefix: quotePath(bin.absolutePath), mode: \"absolute\" };\n}\n\nexport async function initCommand(): Promise<void> {\n ensureAgentreelDir();\n\n // Touch the DB so the file exists and migrations run.\n getDb();\n\n const cfg = readConfig();\n if (!cfg.installedAt) cfg.installedAt = Date.now();\n cfg.hooksInstalled = true;\n writeConfig(cfg);\n\n const binary = resolveAgentBinary();\n const { prefix, mode } = chooseHookPrefix(binary);\n const result = installClaudeCodeHooks(prefix);\n\n console.log(pc.bold(pc.cyan(\"\\n AgentReel \")) + pc.dim(\"Loom for AI coding sessions\\n\"));\n console.log(pc.green(\"✓\") + \" Created ~/.agentreel/sessions.db\");\n console.log(pc.green(\"✓\") + \" Wrote ~/.agentreel/config.json\");\n console.log(\n pc.green(\"✓\") +\n ` Installed ${result.installedEvents.length} Claude Code hooks → ~/.claude/settings.json`,\n );\n if (result.backup) {\n console.log(pc.dim(` (backup: ${result.backup})`));\n }\n console.log();\n console.log(pc.dim(\" Hook command: \") + pc.dim(`${prefix} hook <Event>`));\n if (mode === \"npx\") {\n console.log(\n pc.dim(\" \") +\n pc.yellow(\"•\") +\n pc.dim(\n ` Hooks resolve via npx every time Claude Code fires an event.\\n ` +\n ` For faster cold starts, run: npm i -g ${PACKAGE_NAME}`,\n ),\n );\n }\n console.log();\n if (!cfg.apiKey) {\n console.log(pc.bold(\"Next steps:\"));\n console.log(\n \" \" + pc.dim(\"1.\") + \" \" + pc.cyan(\"agentreel link <key>\") +\n pc.dim(\" — get a key from https://agentreel.dev/dashboard/settings\"),\n );\n console.log(\n \" \" + pc.dim(\"2.\") + \" \" + pc.cyan(\"agentreel daemon --detach\") +\n pc.dim(\" — start the background uploader\"),\n );\n console.log(\n \" \" + pc.dim(\"3.\") + \" open Claude Code and work as normal.\",\n );\n } else {\n console.log(pc.bold(\"Next:\"));\n console.log(\n \" \" + pc.cyan(\"agentreel daemon --detach\") +\n pc.dim(\" — start the background uploader (already linked)\"),\n );\n }\n console.log(\n \"\\n\" + pc.dim(\"Anything: \") + pc.cyan(\"agentreel status\") + pc.dim(\" shows queue, last sync, last error.\"),\n );\n console.log(\n pc.dim(\"Privacy: \") +\n pc.cyan(\"agentreel pause\") +\n pc.dim(\" to stop capturing temporarily, \") +\n pc.cyan(\"agentreel forget --all\") +\n pc.dim(\" to wipe local sessions.\"),\n );\n console.log(\n pc.dim(\" Or set \") +\n pc.cyan(\"AGENTREEL_DISABLE=1\") +\n pc.dim(\" before launching Claude Code to skip a single session.\\n\"),\n );\n}\n","import pc from \"picocolors\";\nimport { existsSync, readFileSync } from \"node:fs\";\nimport {\n CLAUDE_SETTINGS_PATH,\n DB_PATH,\n CONFIG_PATH,\n DAEMON_PID_PATH,\n} from \"../paths.js\";\nimport { countEvents, getMeta, listRecentSessions, pendingByteSize } from \"../db.js\";\nimport { isCaptureDisabledByEnv, readConfig } from \"../config.js\";\nimport {\n META_LAST_ERROR_AT,\n META_LAST_ERROR_MSG,\n META_LAST_SYNC_AT,\n META_NEXT_ATTEMPT_AT,\n consecutiveFailures,\n} from \"../upload/flush.js\";\n\nfunction fmtDuration(ms: number): string {\n const s = Math.round(ms / 1000);\n if (s < 60) return `${s}s`;\n const m = Math.floor(s / 60);\n if (m < 60) return `${m}m ${s % 60}s`;\n const h = Math.floor(m / 60);\n return `${h}h ${m % 60}m`;\n}\n\nfunction fmtAgo(ms: number): string {\n return fmtDuration(Date.now() - ms) + \" ago\";\n}\n\nfunction fmtBytes(n: number): string {\n if (n < 1024) return `${n} B`;\n if (n < 1024 * 1024) return `${(n / 1024).toFixed(1)} KB`;\n return `${(n / 1024 / 1024).toFixed(2)} MB`;\n}\n\nfunction daemonStatus(): { running: boolean; pid: number | null } {\n if (!existsSync(DAEMON_PID_PATH)) return { running: false, pid: null };\n try {\n const pid = Number(readFileSync(DAEMON_PID_PATH, \"utf8\").trim());\n if (!Number.isFinite(pid) || pid <= 0) return { running: false, pid: null };\n process.kill(pid, 0);\n return { running: true, pid };\n } catch {\n return { running: false, pid: null };\n }\n}\n\nexport async function statusCommand(): Promise<void> {\n const cfg = readConfig();\n console.log(pc.bold(pc.cyan(\"AgentReel status\\n\")));\n console.log(\" config: \" + (existsSync(CONFIG_PATH) ? CONFIG_PATH : pc.red(\"missing\")));\n console.log(\" database: \" + (existsSync(DB_PATH) ? DB_PATH : pc.red(\"not initialized\")));\n console.log(\n \" claude hooks: \" +\n (existsSync(CLAUDE_SETTINGS_PATH) ? CLAUDE_SETTINGS_PATH : pc.red(\"not installed\")),\n );\n console.log(\" api base: \" + cfg.apiBaseUrl);\n console.log(\" authenticated: \" + (cfg.apiKey ? pc.green(\"yes\") : pc.yellow(\"no\")));\n\n // Capture state — surfaced at the top so the privacy switch is impossible to miss.\n if (cfg.paused) {\n const since = cfg.pausedAt ? new Date(cfg.pausedAt).toLocaleString() : \"?\";\n console.log(\" capture: \" + pc.yellow(`paused (since ${since})`));\n console.log(pc.dim(\" run `agentreel resume` to capture again\"));\n } else if (isCaptureDisabledByEnv()) {\n console.log(\" capture: \" + pc.yellow(\"disabled (AGENTREEL_DISABLE in env)\"));\n } else {\n console.log(\" capture: \" + pc.green(\"active\"));\n }\n\n const d = daemonStatus();\n console.log(\n \" daemon: \" +\n (d.running ? pc.green(`running (pid ${d.pid})`) : pc.dim(\"stopped\")),\n );\n console.log();\n\n if (!existsSync(DB_PATH)) {\n console.log(pc.yellow(\"Run `agentreel init` to install hooks.\"));\n return;\n }\n\n const { total, pending } = countEvents();\n const pendingBytes = pendingByteSize();\n console.log(` events captured: ${total}`);\n console.log(` pending upload: ${pending}` + (pending > 0 ? pc.dim(` (${fmtBytes(pendingBytes)})`) : \"\"));\n\n const lastSync = numMeta(META_LAST_SYNC_AT);\n const lastErr = numMeta(META_LAST_ERROR_AT);\n const lastErrMsg = getMeta(META_LAST_ERROR_MSG);\n const fails = consecutiveFailures();\n const nextAt = numMeta(META_NEXT_ATTEMPT_AT);\n\n console.log(\n ` last sync: ` +\n (lastSync ? pc.green(fmtAgo(lastSync)) : pc.dim(\"never\")),\n );\n if (lastErr) {\n console.log(\n ` last error: ` +\n pc.red(fmtAgo(lastErr)) +\n pc.dim(` · ${fails} consecutive`),\n );\n if (lastErrMsg) console.log(pc.dim(` ${lastErrMsg}`));\n if (nextAt && nextAt > Date.now()) {\n console.log(\n pc.dim(` next attempt in ${fmtDuration(nextAt - Date.now())}`),\n );\n }\n }\n console.log();\n\n const sessions = listRecentSessions(5);\n if (sessions.length === 0) {\n console.log(pc.dim(\" no sessions yet — start a Claude Code session to capture one.\"));\n return;\n }\n console.log(pc.bold(\"recent sessions:\"));\n for (const s of sessions) {\n const dur = s.ended_at ? fmtDuration(s.ended_at - s.started_at) : pc.dim(\"active\");\n const ts = new Date(s.started_at).toLocaleString();\n console.log(` ${pc.dim(s.id.slice(0, 8))} ${s.tool.padEnd(11)} ${ts} ${dur}`);\n }\n}\n\nfunction numMeta(key: string): number | null {\n const v = getMeta(key);\n if (!v) return null;\n const n = Number(v);\n return Number.isFinite(n) && n > 0 ? n : null;\n}\n","import pc from \"picocolors\";\nimport { readConfig, writeConfig } from \"../config.js\";\nimport { postIngest } from \"../upload/client.js\";\n\nexport async function logoutCommand(): Promise<void> {\n const cfg = readConfig();\n cfg.apiKey = undefined;\n cfg.workspaceId = undefined;\n writeConfig(cfg);\n console.log(pc.green(\"✓\") + \" Cleared local credentials.\");\n}\n\ninterface LinkOpts {\n api?: string;\n}\n\nexport async function linkCommand(rawKey: string | undefined, opts: LinkOpts): Promise<void> {\n const key = (rawKey ?? (await promptHidden(\"Paste your AgentReel API key: \"))).trim();\n if (!key) {\n console.error(pc.red(\"✗ No key provided.\"));\n process.exit(1);\n }\n if (!key.startsWith(\"ar_live_\")) {\n console.error(pc.red(\"✗ Keys start with `ar_live_`. Did you paste the right value?\"));\n process.exit(1);\n }\n\n const cfg = readConfig();\n cfg.apiKey = key;\n if (opts.api) cfg.apiBaseUrl = opts.api;\n\n console.log(pc.dim(` validating against ${cfg.apiBaseUrl}…`));\n try {\n await postIngest(cfg, {});\n } catch (err) {\n console.error(pc.red(\"✗ Validation failed: \") + (err as Error).message);\n process.exit(1);\n }\n writeConfig(cfg);\n console.log(pc.green(\"✓\") + \" Linked.\");\n console.log(pc.dim(\" api: \") + cfg.apiBaseUrl);\n console.log(pc.dim(\" key: \") + key.slice(0, 12) + \"…\");\n}\n\nexport async function uninstallCommand(): Promise<void> {\n const { uninstallClaudeCodeHooks } = await import(\"../hooks/install.js\");\n const { stopCommand } = await import(\"./daemon.js\");\n // Stop first so we don't leave a daemon flushing into a half-uninstalled\n // setup. stopCommand() is idempotent — silent when nothing is running.\n stopCommand();\n const { backup } = uninstallClaudeCodeHooks();\n console.log(pc.green(\"✓\") + \" Removed AgentReel hooks from ~/.claude/settings.json\");\n if (backup) console.log(pc.dim(` (backup: ${backup})`));\n}\n\nconst CTRL_C = 0x03;\nconst BACKSPACE = 0x7f;\nconst BACKSPACE_ALT = 0x08;\nconst NEWLINE = 0x0a;\nconst CARRIAGE = 0x0d;\n\nfunction promptHidden(prompt: string): Promise<string> {\n return new Promise((resolve) => {\n process.stdout.write(prompt);\n let buf = \"\";\n const stdin = process.stdin;\n stdin.setRawMode?.(true);\n stdin.resume();\n stdin.setEncoding(\"utf8\");\n const onData = (chunk: string) => {\n for (const ch of chunk) {\n const code = ch.charCodeAt(0);\n if (code === NEWLINE || code === CARRIAGE) {\n stdin.setRawMode?.(false);\n stdin.pause();\n stdin.removeListener(\"data\", onData);\n process.stdout.write(\"\\n\");\n return resolve(buf);\n }\n if (code === CTRL_C) {\n stdin.setRawMode?.(false);\n process.exit(130);\n }\n if (code === BACKSPACE || code === BACKSPACE_ALT) {\n buf = buf.slice(0, -1);\n } else {\n buf += ch;\n }\n }\n };\n stdin.on(\"data\", onData);\n });\n}\n","import pc from \"picocolors\";\nimport { existsSync } from \"node:fs\";\nimport { basename } from \"node:path\";\nimport { cursorHistoryDir } from \"../cursor/paths.js\";\nimport { startCursorWatcher } from \"../cursor/watcher.js\";\nimport { CursorSessionManager } from \"../cursor/session.js\";\nimport { ensureAgentreelDir } from \"../paths.js\";\nimport { getDb } from \"../db.js\";\n\nexport async function watchCommand(): Promise<void> {\n ensureAgentreelDir();\n // Touch DB so the schema exists.\n getDb();\n\n const dir = cursorHistoryDir();\n if (!existsSync(dir)) {\n console.error(pc.red(\"✗ Cursor history directory not found:\"));\n console.error(\" \" + dir);\n console.error();\n console.error(pc.dim(\"Open Cursor at least once, edit a file, then re-run.\"));\n console.error(pc.dim(\"(Or set AGENTREEL_CURSOR_HISTORY_DIR to a custom path.)\"));\n process.exit(1);\n }\n\n console.log(pc.bold(pc.cyan(\"AgentReel · Cursor watcher\\n\")));\n console.log(pc.dim(\" watching \") + dir);\n console.log(pc.dim(\" press Ctrl+C to stop\\n\"));\n\n const sessions = new CursorSessionManager();\n\n const watcher = startCursorWatcher(dir, async (snap) => {\n const { sessionId, isNew } = sessions.ingest(snap);\n const ts = new Date(snap.timestamp).toLocaleTimeString();\n const ws = snap.workspace ? basename(snap.workspace) : pc.dim(\"no-workspace\");\n const file = snap.filePath.split(\"/\").slice(-2).join(\"/\");\n const sourceLabel =\n snap.source === \"cursor-ai\"\n ? pc.magenta(\"ai\")\n : snap.source === \"cursor-manual\"\n ? pc.cyan(\"man\")\n : pc.dim(\"?\");\n const stats = snap.binary\n ? pc.dim(\"binary\")\n : `${pc.green(\"+\" + snap.added)} ${pc.red(\"-\" + snap.removed)}`;\n if (isNew) {\n console.log(\n `${pc.dim(ts)} ${pc.yellow(\"session\")} ${pc.dim(sessionId)} ${ws}`,\n );\n }\n console.log(`${pc.dim(ts)} edit ${sourceLabel} ${file.padEnd(36)} ${stats}`);\n });\n\n // Graceful shutdown — flush sessions, close watcher.\n const shutdown = async () => {\n console.log(pc.dim(\"\\n closing sessions…\"));\n sessions.closeAll();\n await watcher.close();\n process.exit(0);\n };\n process.on(\"SIGINT\", shutdown);\n process.on(\"SIGTERM\", shutdown);\n}\n","import { homedir, platform } from \"node:os\";\nimport { join } from \"node:path\";\n\n// Cursor is a VS Code fork; its history layout matches Code's:\n// <userData>/User/History/<hashId>/{entries.json, <id>.<ext>, ...}\nexport function defaultCursorHistoryDir(): string {\n const home = homedir();\n switch (platform()) {\n case \"darwin\":\n return join(home, \"Library\", \"Application Support\", \"Cursor\", \"User\", \"History\");\n case \"win32\": {\n const appData = process.env.APPDATA ?? join(home, \"AppData\", \"Roaming\");\n return join(appData, \"Cursor\", \"User\", \"History\");\n }\n default:\n return join(home, \".config\", \"Cursor\", \"User\", \"History\");\n }\n}\n\nexport function cursorHistoryDir(): string {\n return process.env.AGENTREEL_CURSOR_HISTORY_DIR ?? defaultCursorHistoryDir();\n}\n","import chokidar, { type FSWatcher } from \"chokidar\";\nimport { readFile } from \"node:fs/promises\";\nimport { existsSync } from \"node:fs\";\nimport { basename, dirname, join } from \"node:path\";\nimport {\n findWorkspaceRoot,\n isProbablyBinary,\n readEntries,\n resourceToPath,\n type HistoryEntry,\n} from \"./entries.js\";\nimport { computeDiff } from \"./diff.js\";\nimport { isIgnored } from \"../redact/ignore.js\";\nimport { scrubString } from \"../redact/scrubber.js\";\n\nexport interface SnapshotEvent {\n filePath: string;\n workspace: string | null;\n source: \"cursor-ai\" | \"cursor-manual\" | \"unknown\";\n timestamp: number;\n patch: string;\n added: number;\n removed: number;\n binary: boolean;\n}\n\nexport type SnapshotHandler = (e: SnapshotEvent) => void | Promise<void>;\n\nexport interface WatcherOptions {\n /** Discard the very first entry for any tracked file (Cursor's \"first observation\" snapshot). Default true. */\n skipFirstObservation?: boolean;\n}\n\nexport function startCursorWatcher(\n historyDir: string,\n onSnapshot: SnapshotHandler,\n opts: WatcherOptions = {},\n): FSWatcher {\n const skipFirst = opts.skipFirstObservation ?? true;\n\n const watcher = chokidar.watch(historyDir, {\n ignoreInitial: true,\n depth: 2,\n persistent: true,\n awaitWriteFinish: { stabilityThreshold: 120, pollInterval: 40 },\n });\n\n watcher.on(\"add\", async (path) => {\n try {\n const folder = dirname(path);\n const file = basename(path);\n // The folder name is the resource hash; siblings include entries.json\n // and one snapshot file per saved version.\n if (file === \"entries.json\") return;\n // Wait briefly for entries.json to mention this file — Cursor writes\n // the snapshot before updating the manifest in some versions.\n const ctx = await waitForEntry(folder, file, 2_000);\n if (!ctx) return;\n await processSnapshot(folder, ctx, skipFirst, onSnapshot);\n } catch (err) {\n // The watcher must never crash the host process.\n // eslint-disable-next-line no-console\n console.error(\"[agentreel] cursor watcher: error processing\", path, err);\n }\n });\n\n return watcher;\n}\n\ninterface SnapshotContext {\n resource: string;\n current: HistoryEntry;\n previous: HistoryEntry | null;\n currentIdx: number;\n}\n\nasync function waitForEntry(\n folder: string,\n fileId: string,\n totalMs: number,\n): Promise<SnapshotContext | null> {\n const start = Date.now();\n while (Date.now() - start < totalMs) {\n const file = await readEntries(folder);\n if (file) {\n const idx = file.entries.findIndex((e) => e.id === fileId);\n if (idx >= 0) {\n const current = file.entries[idx];\n if (!current) return null;\n const previous = idx > 0 ? (file.entries[idx - 1] ?? null) : null;\n return { resource: file.resource, current, previous, currentIdx: idx };\n }\n }\n await sleep(150);\n }\n return null;\n}\n\nasync function processSnapshot(\n folder: string,\n ctx: SnapshotContext,\n skipFirst: boolean,\n onSnapshot: SnapshotHandler,\n): Promise<void> {\n const filePath = resourceToPath(ctx.resource);\n if (!filePath) return;\n\n // Skip files inside common dependency / build dirs — high noise, low value.\n if (NOISY_PATH.test(filePath)) return;\n\n // Honor per-workspace .agentreelignore (gitignore syntax).\n const workspace = findWorkspaceRoot(filePath);\n if (isIgnored(workspace, filePath)) return;\n\n if (!ctx.previous) {\n // First time Cursor has seen this file — no diff to compute.\n if (skipFirst) return;\n }\n\n const newSnapshot = join(folder, ctx.current.id);\n let before = \"\";\n let after = \"\";\n if (ctx.previous) {\n const prevPath = join(folder, ctx.previous.id);\n if (existsSync(prevPath)) {\n before = await safeRead(prevPath);\n }\n }\n if (existsSync(newSnapshot)) {\n after = await safeRead(newSnapshot);\n }\n\n // No real change — chokidar can fire spurious \"add\" events on some\n // filesystems. Skip silently.\n if (before === after) return;\n\n const binary = isProbablyBinary(filePath);\n let patch = \"\";\n let added = 0;\n let removed = 0;\n if (!binary) {\n // Scrub BEFORE diffing so secrets never enter the patch text. We diff\n // the redacted versions instead — the dashboard will still show the\n // shape of the change, just with [REDACTED:*] in place of values.\n const beforeSafe = scrubString(before);\n const afterSafe = scrubString(after);\n const result = computeDiff(beforeSafe, afterSafe);\n patch = result.patch;\n added = result.added;\n removed = result.removed;\n }\n\n const source = classifySource(ctx.current.source);\n onSnapshot({\n filePath,\n workspace,\n source,\n timestamp: ctx.current.timestamp ?? Date.now(),\n patch,\n added,\n removed,\n binary,\n });\n}\n\nfunction classifySource(raw?: string): SnapshotEvent[\"source\"] {\n if (!raw) return \"cursor-manual\";\n const s = raw.toLowerCase();\n if (s.includes(\"composer\") || s.includes(\"ai\") || s.includes(\"chat\")) return \"cursor-ai\";\n return \"cursor-manual\";\n}\n\nasync function safeRead(path: string): Promise<string> {\n try {\n return await readFile(path, \"utf8\");\n } catch {\n return \"\";\n }\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((r) => setTimeout(r, ms));\n}\n\nconst NOISY_PATH =\n /[\\\\/](node_modules|\\.next|\\.turbo|dist|build|\\.git|coverage|\\.cache|\\.venv|venv|target|out)[\\\\/]/;\n","import { readFile } from \"node:fs/promises\";\nimport { existsSync, statSync } from \"node:fs\";\nimport { join, dirname, resolve, sep } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\nexport interface HistoryEntry {\n id: string; // filename of the snapshot, e.g. \"rEMc.ts\"\n timestamp: number; // ms epoch\n source?: string; // e.g. \"Cursor.Composer\" for AI edits, \"\" for manual\n}\n\nexport interface HistoryFile {\n version: number;\n resource: string; // file:///...\n entries: HistoryEntry[];\n}\n\nexport async function readEntries(historyFolder: string): Promise<HistoryFile | null> {\n const path = join(historyFolder, \"entries.json\");\n if (!existsSync(path)) return null;\n try {\n const raw = await readFile(path, \"utf8\");\n return JSON.parse(raw) as HistoryFile;\n } catch {\n return null;\n }\n}\n\nexport function resourceToPath(resource: string): string | null {\n if (!resource.startsWith(\"file://\")) return null;\n try {\n return fileURLToPath(resource);\n } catch {\n return null;\n }\n}\n\n// Walk up from `path` looking for a directory that contains `.git`. That\n// directory is the workspace root for the purposes of grouping events.\nexport function findWorkspaceRoot(path: string): string | null {\n let dir = dirname(resolve(path));\n while (dir && dir !== sep) {\n const git = join(dir, \".git\");\n try {\n if (existsSync(git)) return dir;\n } catch {\n // ignore\n }\n const parent = dirname(dir);\n if (parent === dir) break;\n dir = parent;\n }\n return null;\n}\n\nexport function isProbablyBinary(path: string): boolean {\n try {\n const s = statSync(path);\n if (s.size > 1024 * 1024) return true; // >1MB — skip diff\n } catch {\n return false;\n }\n // Lightweight extension allowlist for v1. Anything else, treat as binary\n // and skip diffing (we still record the event, just without a patch).\n const text =\n /\\.(ts|tsx|js|jsx|mjs|cjs|json|jsonc|md|mdx|css|scss|html|xml|yaml|yml|toml|sh|bash|zsh|fish|py|rb|go|rs|java|kt|swift|c|cc|cpp|h|hpp|cs|php|sql|prisma|graphql|gql|env|gitignore|dockerfile|tf|hcl|lua|vue|svelte|astro|txt|csv|tsv|log|conf|ini)$/i;\n return !text.test(path);\n}\n","import { diffLines } from \"diff\";\nimport DiffMatchPatch from \"diff-match-patch\";\n\nexport interface DiffResult {\n /** diff-match-patch wire format — compact, reversible. Stored on the event. */\n patch: string;\n /** Line-level adds/removes — surfaced in the dashboard list. */\n added: number;\n removed: number;\n}\n\nconst dmp = new DiffMatchPatch.diff_match_patch();\n// Allow expensive cleanup on small diffs; cap at 1MB to avoid pathological inputs.\ndmp.Diff_Timeout = 1.0;\n\nexport function computeDiff(before: string, after: string): DiffResult {\n // Patch — compact DMP format, much smaller than unified diff for small edits.\n const patches = dmp.patch_make(before, after);\n const patch = dmp.patch_toText(patches);\n\n // Line-level stats (cheap; users see these in the timeline list).\n let added = 0;\n let removed = 0;\n for (const part of diffLines(before, after)) {\n const n =\n part.count ??\n (part.value.match(/\\n/g)?.length ?? (part.value.length > 0 ? 1 : 0));\n if (part.added) added += n;\n else if (part.removed) removed += n;\n }\n\n return { patch, added, removed };\n}\n","import { existsSync, readFileSync, statSync } from \"node:fs\";\nimport { join, relative, sep } from \"node:path\";\nimport ignore, { type Ignore } from \"ignore\";\n\nconst FILENAME = \".agentreelignore\";\nconst TTL_MS = 5_000; // re-read the file at most every 5 seconds per workspace\n\ninterface CacheEntry {\n matcher: Ignore | null;\n loadedAt: number;\n fileMtime: number;\n}\n\nconst cache = new Map<string, CacheEntry>();\n\nfunction loadFor(workspace: string): Ignore | null {\n const path = join(workspace, FILENAME);\n if (!existsSync(path)) return null;\n try {\n const raw = readFileSync(path, \"utf8\");\n return ignore({ allowRelativePaths: true }).add(raw);\n } catch {\n return null;\n }\n}\n\nfunction getCached(workspace: string): Ignore | null {\n const entry = cache.get(workspace);\n const path = join(workspace, FILENAME);\n let mtime = 0;\n try {\n mtime = existsSync(path) ? statSync(path).mtimeMs : 0;\n } catch {\n mtime = 0;\n }\n const now = Date.now();\n if (entry && now - entry.loadedAt < TTL_MS && entry.fileMtime === mtime) {\n return entry.matcher;\n }\n const matcher = loadFor(workspace);\n cache.set(workspace, { matcher, loadedAt: now, fileMtime: mtime });\n return matcher;\n}\n\n/**\n * Returns true if `filePath` should be skipped because it matches a rule\n * in the workspace's `.agentreelignore`. Returns false when the workspace\n * has no ignore file or the path doesn't match.\n */\nexport function isIgnored(workspace: string | null | undefined, filePath: string): boolean {\n if (!workspace) return false;\n const matcher = getCached(workspace);\n if (!matcher) return false;\n const rel = relative(workspace, filePath);\n // ignore can't reason about paths that escape the workspace.\n if (!rel || rel.startsWith(\"..\") || rel.startsWith(sep)) return false;\n // gitignore syntax expects forward slashes.\n return matcher.ignores(rel.split(sep).join(\"/\"));\n}\n","// Order matters. Multiline / specific patterns first, generic last.\n\nexport interface RedactionRule {\n name: string;\n re: RegExp;\n replacement: string | ((match: string) => string);\n}\n\nexport const PATTERNS: RedactionRule[] = [\n // PEM-encoded private keys (multiline, must run early)\n {\n name: \"pem-private-key\",\n re: /-----BEGIN [A-Z0-9 ]*PRIVATE KEY-----[\\s\\S]+?-----END [A-Z0-9 ]*PRIVATE KEY-----/g,\n replacement: \"[REDACTED:private-key]\",\n },\n\n // JWT (header.payload.signature) — eyJ-prefixed base64url segments\n {\n name: \"jwt\",\n re: /\\beyJ[A-Za-z0-9_-]{8,}\\.eyJ[A-Za-z0-9_-]{8,}\\.[A-Za-z0-9_-]{8,}\\b/g,\n replacement: \"[REDACTED:jwt]\",\n },\n\n // GitHub fine-grained PATs (84 chars after prefix is the official format)\n {\n name: \"github-fine-grained-pat\",\n re: /\\bgithub_pat_[A-Za-z0-9_]{82,}\\b/g,\n replacement: \"[REDACTED:gh-fine-pat]\",\n },\n // GitHub OAuth, PAT, app, server, refresh tokens\n {\n name: \"github-token\",\n re: /\\bgh[pousr]_[A-Za-z0-9]{36,255}\\b/g,\n replacement: \"[REDACTED:gh-token]\",\n },\n\n // Anthropic\n {\n name: \"anthropic-key\",\n re: /\\bsk-ant-(?:api\\d{2}-)?[A-Za-z0-9_-]{40,}\\b/g,\n replacement: \"[REDACTED:anthropic-key]\",\n },\n\n // OpenAI (sk-proj-..., sk-svcacct-..., legacy sk-...)\n {\n name: \"openai-key\",\n re: /\\bsk-(?:proj-|svcacct-|admin-)?[A-Za-z0-9_-]{20,}\\b/g,\n replacement: \"[REDACTED:openai-key]\",\n },\n\n // Stripe\n {\n name: \"stripe-secret\",\n re: /\\bsk_(?:test|live)_[A-Za-z0-9]{16,}\\b/g,\n replacement: \"[REDACTED:stripe-secret]\",\n },\n {\n name: \"stripe-restricted\",\n re: /\\brk_(?:test|live)_[A-Za-z0-9]{16,}\\b/g,\n replacement: \"[REDACTED:stripe-restricted]\",\n },\n {\n name: \"stripe-publishable\",\n re: /\\bpk_(?:test|live)_[A-Za-z0-9]{16,}\\b/g,\n replacement: \"[REDACTED:stripe-publishable]\",\n },\n {\n name: \"stripe-webhook\",\n re: /\\bwhsec_[A-Za-z0-9]{32,}\\b/g,\n replacement: \"[REDACTED:stripe-webhook]\",\n },\n\n // AWS access key IDs (and STS / temporary forms)\n {\n name: \"aws-access-key-id\",\n re: /\\b(?:AKIA|ASIA|AGPA|AROA|AIDA|ANPA|ANVA|AIPA)[0-9A-Z]{16}\\b/g,\n replacement: \"[REDACTED:aws-key-id]\",\n },\n\n // Slack tokens\n {\n name: \"slack-token\",\n re: /\\bxox[baprs]-[A-Za-z0-9-]{10,}\\b/g,\n replacement: \"[REDACTED:slack-token]\",\n },\n\n // Google API keys\n {\n name: \"google-api-key\",\n re: /\\bAIza[A-Za-z0-9_-]{35}\\b/g,\n replacement: \"[REDACTED:google-api-key]\",\n },\n\n // npm tokens\n {\n name: \"npm-token\",\n re: /\\bnpm_[A-Za-z0-9]{36}\\b/g,\n replacement: \"[REDACTED:npm-token]\",\n },\n\n // dotenv-style KEY=VALUE on its own line, where the KEY name looks sensitive.\n // This is a fallback for arbitrary secrets that don't match a specific\n // provider pattern. Captures the key, replaces the value.\n {\n name: \"dotenv-secret\",\n re: /^(\\s*(?:export\\s+)?[A-Z][A-Z0-9_]*?(?:KEY|TOKEN|SECRET|PASSWORD|PASSWD|PWD|API|AUTH|CREDENTIAL|PRIVATE|SESSION|COOKIE|BEARER|DSN)[A-Z0-9_]*\\s*=\\s*)(['\"]?)([^\\n'\"]{4,})\\2/gm,\n replacement: (m: string) => {\n // m is the full match; we keep the \"KEY=\" and quote, replace the value.\n // Re-run a small regex against m to preserve the prefix.\n const inner =\n /^(\\s*(?:export\\s+)?[A-Z][A-Z0-9_]*\\s*=\\s*)(['\"]?)([^\\n'\"]{4,})\\2/.exec(m);\n if (!inner) return \"[REDACTED:dotenv-secret]\";\n const [, prefix, quote] = inner;\n return `${prefix ?? \"\"}${quote ?? \"\"}[REDACTED:dotenv-secret]${quote ?? \"\"}`;\n },\n },\n\n // Email addresses\n {\n name: \"email\",\n re: /\\b[A-Za-z0-9._%+\\-]+@[A-Za-z0-9.\\-]+\\.[A-Za-z]{2,}\\b/g,\n replacement: \"[REDACTED:email]\",\n },\n\n // IPv4 — validates each octet is 0-255 to cut version-string false positives.\n // Skips three benign forms below in the post-filter.\n {\n name: \"ipv4\",\n re: /\\b(?:(?:25[0-5]|2[0-4]\\d|1\\d{2}|[1-9]?\\d)\\.){3}(?:25[0-5]|2[0-4]\\d|1\\d{2}|[1-9]?\\d)\\b/g,\n replacement: (m: string) => {\n if (m === \"0.0.0.0\" || m === \"127.0.0.1\" || m === \"255.255.255.255\") return m;\n return \"[REDACTED:ip]\";\n },\n },\n];\n\n// Sensitive key-name shapes used by the recursive object walker. If an\n// object's key name matches AND the value is a non-trivial string, we redact\n// the whole value regardless of provider-pattern match.\n// Names that almost-always carry a secret value. Avoid generic words like\n// `session` (matches `session_id`) or bare `token` (matches `csrf_token`\n// inputs that are themselves not sensitive in our context).\nexport const SENSITIVE_KEY_RE =\n /(?:^|[_\\-.])(?:api[_-]?key|access[_-]?token|secret|password|passwd|pwd|authorization|bearer|credential|private[_-]?key|client[_-]?secret|webhook[_-]?secret|service[_-]?account|refresh[_-]?token)(?:$|[_\\-.])/i;\n","import { PATTERNS, SENSITIVE_KEY_RE } from \"./patterns.js\";\n\n/** Run all redaction patterns against a string. Idempotent. */\nexport function scrubString(input: string): string {\n if (!input) return input;\n let s = input;\n for (const rule of PATTERNS) {\n if (typeof rule.replacement === \"function\") {\n s = s.replace(rule.re, rule.replacement);\n } else {\n s = s.replace(rule.re, rule.replacement);\n }\n }\n return s;\n}\n\n/**\n * Recursively redact a JSON-shaped value. Strings get pattern-scrubbed;\n * object properties whose KEY name looks sensitive (`apiKey`, `password`,\n * etc.) have their entire string value replaced — that catches arbitrary\n * secrets that don't match any provider pattern.\n *\n * Cycle-safe via a WeakSet seen.\n */\nexport function scrubAny<T>(value: T, seen: WeakSet<object> = new WeakSet()): T {\n if (value == null) return value;\n if (typeof value === \"string\") return scrubString(value) as T;\n if (typeof value !== \"object\") return value;\n if (seen.has(value as object)) return value;\n seen.add(value as object);\n\n if (Array.isArray(value)) {\n return value.map((v) => scrubAny(v, seen)) as T;\n }\n\n const out: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(value as Record<string, unknown>)) {\n if (SENSITIVE_KEY_RE.test(k) && typeof v === \"string\" && v.length >= 4) {\n out[k] = \"[REDACTED:by-key-name]\";\n } else {\n out[k] = scrubAny(v, seen);\n }\n }\n return out as T;\n}\n","import { nanoid } from \"nanoid\";\nimport { insertEvent, upsertSession } from \"../db.js\";\nimport { isCapturePaused } from \"../config.js\";\nimport type { AgentEvent } from \"@agentreel/shared-types\";\nimport type { SnapshotEvent } from \"./watcher.js\";\n\nconst IDLE_MS = 5 * 60 * 1000; // 5 minute gap = new session\nconst GLOBAL_KEY = \"__global__\";\n\ninterface OpenSession {\n id: string;\n startedAt: number;\n lastTs: number;\n cwd: string;\n}\n\nexport class CursorSessionManager {\n private open = new Map<string, OpenSession>();\n\n ingest(snapshot: SnapshotEvent): { sessionId: string; isNew: boolean } {\n // Honor the global pause/disable flag the same way Claude Code hooks do.\n // We still return a session id so the watcher's bookkeeping is happy,\n // but skip the actual DB writes that would surface in upload.\n if (isCapturePaused()) {\n return { sessionId: \"__paused__\", isNew: false };\n }\n const key = snapshot.workspace ?? GLOBAL_KEY;\n const ts = snapshot.timestamp;\n const cwd = snapshot.workspace ?? \"\";\n\n let session = this.open.get(key);\n let isNew = false;\n if (!session || ts - session.lastTs > IDLE_MS) {\n // Close out the previous session for this key, if any.\n if (session) this.closeSession(session, session.lastTs);\n session = {\n id: `cur_${nanoid(10)}`,\n startedAt: ts,\n lastTs: ts,\n cwd,\n };\n this.open.set(key, session);\n isNew = true;\n upsertSession({\n id: session.id,\n tool: \"cursor\",\n startedAt: ts,\n cwd,\n });\n } else {\n session.lastTs = ts;\n }\n\n const event: AgentEvent = {\n id: nanoid(),\n sessionId: session.id,\n tool: \"cursor\",\n type: \"tool_use_post\",\n ts,\n cwd,\n payload: {\n tool_name: \"Edit\",\n file_path: snapshot.filePath,\n added: snapshot.added,\n removed: snapshot.removed,\n binary: snapshot.binary,\n source: snapshot.source,\n patch: snapshot.patch,\n },\n };\n insertEvent(event);\n return { sessionId: session.id, isNew };\n }\n\n /** Stamp ended_at on every open session — call on shutdown. */\n closeAll(): void {\n const now = Date.now();\n for (const s of this.open.values()) this.closeSession(s, Math.max(s.lastTs, now));\n this.open.clear();\n }\n\n private closeSession(s: OpenSession, endedAt: number) {\n upsertSession({\n id: s.id,\n tool: \"cursor\",\n startedAt: s.startedAt,\n endedAt,\n cwd: s.cwd,\n });\n }\n}\n","import pc from \"picocolors\";\nimport { readConfig } from \"../config.js\";\nimport { flushOnce } from \"../upload/flush.js\";\nimport { IngestError } from \"../upload/client.js\";\n\nexport async function pushCommand(): Promise<void> {\n const cfg = readConfig();\n if (!cfg.apiKey) {\n console.error(pc.red(\"✗ Not linked. Run \") + pc.cyan(\"agentreel link <api-key>\"));\n process.exit(1);\n }\n\n let totalSessions = 0;\n let totalEvents = 0;\n\n // Drain in batches of MAX_BATCH_EVENTS / MAX_BATCH_BYTES until empty.\n for (;;) {\n let res;\n try {\n res = await flushOnce();\n } catch (err) {\n const e = err as Error;\n if (err instanceof IngestError) {\n console.error(pc.red(\"✗ \") + e.message);\n if (err.isPermanent) {\n console.error(\n pc.dim(\" not retrying — fix the cause (re-link, upgrade plan, etc.) and run push again.\"),\n );\n }\n } else {\n console.error(pc.red(\"✗ \") + e.message);\n }\n process.exit(1);\n }\n totalSessions += res.uploadedSessions;\n totalEvents += res.uploadedEvents;\n if (!res.moreAvailable) break;\n }\n\n if (totalEvents === 0) {\n console.log(pc.green(\"✓\") + \" queue is empty — nothing to upload.\");\n return;\n }\n console.log(\n pc.green(\"✓\") +\n ` uploaded ${totalEvents} events · ${totalSessions} session rows touched`,\n );\n}\n","import pc from \"picocolors\";\nimport { createInterface } from \"node:readline\";\nimport { readConfig, writeConfig } from \"../config.js\";\nimport { getDb } from \"../db.js\";\n\nexport function pauseCommand(): void {\n const cfg = readConfig();\n if (cfg.paused) {\n console.log(pc.dim(\"· already paused\"));\n if (cfg.pausedAt) {\n console.log(pc.dim(` since ${new Date(cfg.pausedAt).toLocaleString()}`));\n }\n return;\n }\n cfg.paused = true;\n cfg.pausedAt = Date.now();\n writeConfig(cfg);\n console.log(pc.yellow(\"⏸ capture paused\"));\n console.log(\n pc.dim(\n \" Claude Code hooks and the Cursor watcher will no-op until you \" +\n pc.cyan(\"agentreel resume\") +\n pc.dim(\".\"),\n ),\n );\n console.log(\n pc.dim(\n \" Existing local events stay put. They won't upload while paused (the daemon still runs, but the queue won't grow).\",\n ),\n );\n}\n\nexport function resumeCommand(): void {\n const cfg = readConfig();\n if (!cfg.paused) {\n console.log(pc.dim(\"· capture is already active\"));\n return;\n }\n const pausedAt = cfg.pausedAt;\n cfg.paused = false;\n cfg.pausedAt = undefined;\n writeConfig(cfg);\n const duration = pausedAt ? fmtDuration(Date.now() - pausedAt) : null;\n console.log(pc.green(\"▶ capture resumed\"));\n if (duration) {\n console.log(pc.dim(` paused for ${duration}`));\n }\n}\n\ninterface ForgetOpts {\n all?: boolean;\n force?: boolean;\n}\n\n/**\n * Delete captured sessions + events from the local SQLite buffer.\n * Without --all, requires session ids. The ON DELETE CASCADE on events\n * (events.session_id FK) means deleting a session row drops its events\n * automatically.\n */\nexport async function forgetCommand(\n ids: string[],\n opts: ForgetOpts,\n): Promise<void> {\n const db = getDb();\n\n if (opts.all) {\n const total = (db.prepare(`SELECT COUNT(*) AS c FROM sessions`).get() as {\n c: number;\n }).c;\n if (total === 0) {\n console.log(pc.dim(\"· nothing to forget — local DB is empty\"));\n return;\n }\n if (!opts.force && !(await confirm(`Delete all ${total} local sessions? `))) {\n console.log(pc.dim(\"· cancelled\"));\n return;\n }\n db.transaction(() => {\n db.exec(`DELETE FROM events`);\n db.exec(`DELETE FROM sessions`);\n // Cost/offset meta keyed by session_id is now orphaned — wipe it too.\n db.exec(`DELETE FROM meta WHERE key LIKE 'cost_%'`);\n })();\n console.log(pc.green(\"✓\") + ` forgot ${total} sessions and their events`);\n console.log(\n pc.dim(\n \" Cloud-side rows are untouched. Delete them from the dashboard if you also want them gone from agentreel.dev.\",\n ),\n );\n return;\n }\n\n if (ids.length === 0) {\n console.error(\n pc.red(\"✗ provide one or more session ids, or --all to wipe everything\"),\n );\n console.error(pc.dim(` example: agentreel forget abcd1234`));\n process.exit(1);\n }\n\n // Allow short-id prefix matching for convenience (`agentreel forget ef194acc`).\n const stmt = db.prepare(\n `SELECT id FROM sessions WHERE id = ? OR id LIKE ?`,\n );\n const delEvents = db.prepare(`DELETE FROM events WHERE session_id = ?`);\n const delSession = db.prepare(`DELETE FROM sessions WHERE id = ?`);\n const delMeta = db.prepare(`DELETE FROM meta WHERE key LIKE ?`);\n\n const matched: string[] = [];\n for (const raw of ids) {\n const rows = stmt.all(raw, `${raw}%`) as Array<{ id: string }>;\n if (rows.length === 0) {\n console.error(pc.yellow(`· no session matched \"${raw}\"`));\n continue;\n }\n for (const r of rows) matched.push(r.id);\n }\n if (matched.length === 0) {\n console.error(pc.red(\"✗ nothing matched, nothing deleted\"));\n process.exit(1);\n }\n if (!opts.force && !(await confirm(`Delete ${matched.length} session(s) and their events? `))) {\n console.log(pc.dim(\"· cancelled\"));\n return;\n }\n db.transaction(() => {\n for (const id of matched) {\n delEvents.run(id);\n delSession.run(id);\n delMeta.run(`cost_%:${id}`);\n }\n })();\n console.log(pc.green(\"✓\") + ` forgot ${matched.length} session(s)`);\n}\n\nfunction confirm(prompt: string): Promise<boolean> {\n return new Promise((resolve) => {\n const rl = createInterface({ input: process.stdin, output: process.stdout });\n rl.question(prompt + \"[y/N] \", (answer) => {\n rl.close();\n resolve(/^y(es)?$/i.test(answer.trim()));\n });\n });\n}\n\nfunction fmtDuration(ms: number): string {\n const s = Math.round(ms / 1000);\n if (s < 60) return `${s}s`;\n const m = Math.floor(s / 60);\n if (m < 60) return `${m}m ${s % 60}s`;\n const h = Math.floor(m / 60);\n if (h < 24) return `${h}h ${m % 60}m`;\n const d = Math.floor(h / 24);\n return `${d}d ${h % 24}h`;\n}\n","import { nanoid } from \"nanoid\";\nimport { appendFileSync } from \"node:fs\";\nimport type { AgentEvent, ClaudeCodeHookInput, EventType } from \"@agentreel/shared-types\";\nimport { insertEvent, upsertSession } from \"../db.js\";\nimport { LOG_PATH, ensureAgentreelDir } from \"../paths.js\";\nimport { scrubAny } from \"../redact/scrubber.js\";\nimport { recomputeSessionCost } from \"../cost/transcript.js\";\nimport { isCapturePaused } from \"../config.js\";\n\nconst HOOK_EVENT_TO_TYPE: Record<string, EventType> = {\n SessionStart: \"session_start\",\n SessionEnd: \"session_end\",\n UserPromptSubmit: \"user_prompt_submit\",\n PreToolUse: \"tool_use_pre\",\n PostToolUse: \"tool_use_post\",\n Notification: \"notification\",\n Stop: \"stop\",\n SubagentStop: \"subagent_stop\",\n PreCompact: \"pre_compact\",\n};\n\nasync function readStdin(): Promise<string> {\n if (process.stdin.isTTY) return \"\";\n const chunks: Buffer[] = [];\n for await (const chunk of process.stdin) {\n chunks.push(chunk as Buffer);\n }\n return Buffer.concat(chunks).toString(\"utf8\");\n}\n\nfunction logError(err: unknown): void {\n try {\n ensureAgentreelDir();\n const line = `[${new Date().toISOString()}] hook error: ${\n err instanceof Error ? err.stack ?? err.message : String(err)\n }\\n`;\n appendFileSync(LOG_PATH, line);\n } catch {\n // swallow — never block Claude Code\n }\n}\n\nexport async function runHook(eventArg?: string): Promise<void> {\n // Hooks must never block or fail Claude Code. Wrap everything.\n try {\n // Honor explicit opt-outs before reading the payload — env var for\n // single-shell suppression, persisted pause for \"stop capturing\n // until I resume.\" Either way: silently consume stdin (Claude Code\n // streams hook input via pipe; not draining it could leave handles\n // dangling) and return cleanly.\n if (isCapturePaused()) {\n await readStdin().catch(() => \"\");\n return;\n }\n\n const raw = await readStdin();\n if (!raw.trim()) return;\n const input = JSON.parse(raw) as ClaudeCodeHookInput;\n\n const hookEventName = input.hook_event_name ?? eventArg ?? \"Unknown\";\n const type: EventType = HOOK_EVENT_TO_TYPE[hookEventName] ?? \"unknown\";\n const ts = Date.now();\n const sessionId = input.session_id ?? \"unknown-session\";\n\n if (type === \"session_start\") {\n upsertSession({\n id: sessionId,\n tool: \"claude-code\",\n startedAt: ts,\n cwd: input.cwd,\n });\n } else if (type === \"session_end\") {\n upsertSession({\n id: sessionId,\n tool: \"claude-code\",\n startedAt: ts,\n endedAt: ts,\n cwd: input.cwd,\n });\n } else {\n // Make sure the session row exists so events have a parent.\n upsertSession({\n id: sessionId,\n tool: \"claude-code\",\n startedAt: ts,\n cwd: input.cwd,\n });\n }\n\n // Scrub the entire payload before persistence — never let raw secrets\n // touch SQLite, even briefly. scrubAny handles strings recursively and\n // also redacts values whose KEY name looks sensitive.\n const safePayload = scrubAny(input);\n const event: AgentEvent = {\n id: nanoid(),\n sessionId,\n tool: \"claude-code\",\n type,\n ts,\n cwd: input.cwd,\n payload: safePayload,\n };\n insertEvent(event);\n\n // After every hook fire, walk the transcript tail and update the\n // session's running cost / token totals. Incremental via offset\n // cache, so this stays cheap even on long sessions.\n try {\n recomputeSessionCost(sessionId, input.transcript_path);\n } catch (err) {\n // Cost is best-effort — never let a parse glitch break capture.\n logError(err);\n }\n } catch (err) {\n logError(err);\n }\n}\n","import { existsSync, statSync, openSync, readSync, closeSync } from \"node:fs\";\nimport { getDb, getMeta, setMeta } from \"../db.js\";\nimport { costCentsFor, ratesFor, type UsageBreakdown } from \"./pricing.js\";\n\ninterface TranscriptLine {\n type?: string;\n message?: {\n model?: string;\n usage?: Partial<{\n input_tokens: number;\n output_tokens: number;\n cache_read_input_tokens: number;\n cache_creation_input_tokens: number;\n }>;\n };\n}\n\nconst KEY_OFFSET = (sid: string) => `cost_offset:${sid}`;\nconst KEY_TOKENS = (sid: string) => `cost_tokens:${sid}`;\nconst KEY_CENTS = (sid: string) => `cost_cents:${sid}`;\nconst KEY_PATH = (sid: string) => `cost_path:${sid}`;\n\ninterface SessionTotals {\n totalCostCents: number;\n totalTokens: number;\n}\n\n/**\n * Parse the tail of a session's transcript JSONL, sum every assistant\n * `message.usage` block we haven't seen yet, and update the session row\n * with running cost / token totals.\n *\n * Safe to call on every hook fire — incremental via byte offset, so a\n * 50 MB transcript on the 200th tool call only re-reads the last few KB.\n */\nexport function recomputeSessionCost(sessionId: string, transcriptPath: string | undefined): void {\n if (!transcriptPath) {\n // First call may not have the path; remember the last good one.\n transcriptPath = getMeta(KEY_PATH(sessionId)) ?? undefined;\n } else {\n setMeta(KEY_PATH(sessionId), transcriptPath);\n }\n if (!transcriptPath || !existsSync(transcriptPath)) return;\n\n const stat = statSync(transcriptPath);\n const totalSize = stat.size;\n const offset = Number(getMeta(KEY_OFFSET(sessionId)) ?? \"0\");\n if (offset >= totalSize) return; // nothing new\n\n const buf = Buffer.alloc(totalSize - offset);\n const fd = openSync(transcriptPath, \"r\");\n try {\n readSync(fd, buf, 0, buf.length, offset);\n } finally {\n closeSync(fd);\n }\n\n const text = buf.toString(\"utf8\");\n // The tail may end mid-line if a writer is still flushing. Stash any\n // partial trailing line and only consume up through the last newline.\n const lastNewline = text.lastIndexOf(\"\\n\");\n if (lastNewline === -1) return; // no complete line yet\n const consumable = text.slice(0, lastNewline);\n const consumedBytes = Buffer.byteLength(consumable, \"utf8\") + 1; // include the \\n\n\n let addedTokens = 0;\n let addedCents = 0;\n for (const raw of consumable.split(\"\\n\")) {\n if (!raw) continue;\n let line: TranscriptLine;\n try {\n line = JSON.parse(raw) as TranscriptLine;\n } catch {\n continue;\n }\n if (line.type !== \"assistant\") continue;\n const usage = line.message?.usage;\n if (!usage) continue;\n\n const u: UsageBreakdown = {\n inputTokens: usage.input_tokens ?? 0,\n outputTokens: usage.output_tokens ?? 0,\n cacheReadTokens: usage.cache_read_input_tokens ?? 0,\n cacheCreationTokens: usage.cache_creation_input_tokens ?? 0,\n };\n const rates = ratesFor(line.message?.model);\n addedCents += costCentsFor(u, rates);\n addedTokens +=\n u.inputTokens + u.outputTokens + u.cacheReadTokens + u.cacheCreationTokens;\n }\n\n const prevTokens = Number(getMeta(KEY_TOKENS(sessionId)) ?? \"0\");\n const prevCents = Number(getMeta(KEY_CENTS(sessionId)) ?? \"0\");\n const newTokens = prevTokens + addedTokens;\n const newCents = prevCents + addedCents;\n\n setMeta(KEY_OFFSET(sessionId), String(offset + consumedBytes));\n setMeta(KEY_TOKENS(sessionId), String(newTokens));\n setMeta(KEY_CENTS(sessionId), String(newCents));\n\n // Stamp the totals on the session row so the upload picks them up.\n // Use COALESCE-style write — if the row vanished (shouldn't happen),\n // the UPDATE is a noop.\n const db = getDb();\n db.prepare(\n `UPDATE sessions\n SET total_cost_cents = ?, total_tokens = ?\n WHERE id = ?`,\n ).run(newCents, newTokens, sessionId);\n}\n\nexport function getSessionTotals(sessionId: string): SessionTotals {\n return {\n totalCostCents: Number(getMeta(KEY_CENTS(sessionId)) ?? \"0\"),\n totalTokens: Number(getMeta(KEY_TOKENS(sessionId)) ?? \"0\"),\n };\n}\n","// Anthropic published rates. Cents per million tokens.\n//\n// Update this table whenever Anthropic publishes new rates or releases\n// a new model family. Rates are intentionally hardcoded here (vs a\n// server fetch) so the agent works fully offline.\n\nexport interface ModelRates {\n /** Cents per million input tokens. */\n input: number;\n /** Cents per million output tokens. */\n output: number;\n /** Cents per million cache-read input tokens. */\n cacheRead: number;\n /** Cents per million cache-creation input tokens. */\n cacheCreation: number;\n}\n\nexport const MODEL_RATES: Record<string, ModelRates> = {\n // Claude 4.x\n \"claude-opus-4-7\": { input: 1500, output: 7500, cacheRead: 150, cacheCreation: 1875 },\n \"claude-opus-4-6\": { input: 1500, output: 7500, cacheRead: 150, cacheCreation: 1875 },\n \"claude-sonnet-4-6\": { input: 300, output: 1500, cacheRead: 30, cacheCreation: 375 },\n \"claude-sonnet-4-5\": { input: 300, output: 1500, cacheRead: 30, cacheCreation: 375 },\n \"claude-haiku-4-5\": { input: 80, output: 400, cacheRead: 8, cacheCreation: 100 },\n\n // Legacy 3.x (still seen in older transcripts)\n \"claude-3-5-sonnet\": { input: 300, output: 1500, cacheRead: 30, cacheCreation: 375 },\n \"claude-3-5-haiku\": { input: 80, output: 400, cacheRead: 8, cacheCreation: 100 },\n \"claude-3-opus\": { input: 1500, output: 7500, cacheRead: 150, cacheCreation: 1875 },\n};\n\nconst FALLBACK: ModelRates = MODEL_RATES[\"claude-sonnet-4-6\"]!;\n\n/**\n * Look up rates for a model id like `claude-sonnet-4-5-20250929`. We\n * match by prefix so date-stamped variants don't drop out of the table.\n */\nexport function ratesFor(model: string | undefined): ModelRates {\n if (!model) return FALLBACK;\n // Try exact, then strip a trailing date suffix.\n if (MODEL_RATES[model]) return MODEL_RATES[model];\n const stripped = model.replace(/-\\d{8}$/, \"\");\n if (MODEL_RATES[stripped]) return MODEL_RATES[stripped];\n // Try ever-shorter prefixes — handles unknown date suffixes.\n for (const key of Object.keys(MODEL_RATES)) {\n if (model.startsWith(key)) return MODEL_RATES[key]!;\n }\n return FALLBACK;\n}\n\nexport interface UsageBreakdown {\n inputTokens: number;\n outputTokens: number;\n cacheReadTokens: number;\n cacheCreationTokens: number;\n}\n\n/** Cost in cents. Rounded UP so we never under-report. */\nexport function costCentsFor(usage: UsageBreakdown, rates: ModelRates): number {\n const c =\n (usage.inputTokens * rates.input +\n usage.outputTokens * rates.output +\n usage.cacheReadTokens * rates.cacheRead +\n usage.cacheCreationTokens * rates.cacheCreation) /\n 1_000_000;\n return Math.ceil(c);\n}\n"],"mappings":"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","names":["mkdirSync","readFileSync","writeFileSync","existsSync","pc","existsSync","readFileSync","writeFileSync","resolve","pc","existsSync","readFileSync","ts","pc","uninstallClaudeCodeHooks","stopCommand","resolve","pc","existsSync","basename","homedir","join","readFile","existsSync","dirname","join","existsSync","join","dirname","sep","fileURLToPath","existsSync","readFileSync","statSync","join","sep","dirname","join","existsSync","readFile","ts","existsSync","pc","ts","basename","pc","pc","fmtDuration","resolve","nanoid","existsSync","statSync","openSync","existsSync","statSync","openSync","ts","nanoid"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agentreel/agent",
3
- "version": "0.1.4",
3
+ "version": "0.1.5",
4
4
  "description": "Loom for AI coding sessions — captures every Claude Code and Cursor session locally and ships it to a scrubbable, shareable replay.",
5
5
  "keywords": [
6
6
  "claude-code",