@lesscap/baton-cli 0.1.2 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/baton.mjs +169 -174
  2. package/package.json +13 -9
package/dist/baton.mjs CHANGED
@@ -577,6 +577,7 @@ var sessionsClient = (baseUrl) => {
577
577
  }),
578
578
  resume: (id) => request(u(`/sessions/${id}/resume`), { method: "POST" }),
579
579
  stop: (id) => request(u(`/sessions/${id}/stop`), { method: "POST" }),
580
+ clear: (id) => request(u(`/sessions/${id}/clear`), { method: "POST" }),
580
581
  rename: (id, name) => request(u(`/sessions/${id}/rename`), { method: "POST", body: { name } }),
581
582
  listByProject: (projectId) => request(u(`/projects/${projectId}/sessions`), { method: "GET" }),
582
583
  get: (id) => request(u(`/sessions/${id}`), { method: "GET" }),
@@ -1018,6 +1019,38 @@ var requirement = defineCommand({
1018
1019
  }
1019
1020
  });
1020
1021
 
1022
+ // src/commands/session/shared.ts
1023
+ import { homedir } from "node:os";
1024
+ import { join as join2 } from "node:path";
1025
+ var defaultWorktreeDir = (env = process.env) => env.BATON_WORKTREE_DIR ?? join2(env.XDG_DATA_HOME ?? join2(env.HOME ?? homedir(), ".local/share"), "baton", "worktrees");
1026
+ var slug = (s) => s.toLowerCase().replace(/[^a-z0-9_-]+/g, "-");
1027
+ var resolveSession = async (client, projectId, handle) => {
1028
+ const asInt = Number(handle);
1029
+ if (Number.isInteger(asInt) && asInt > 0) {
1030
+ const byId = await client.sessions.get(asInt).catch(() => null);
1031
+ if (byId) return { id: byId.id, name: byId.name };
1032
+ }
1033
+ const byName = await client.sessions.findByName(projectId, handle);
1034
+ if (byName) return { id: byName.id, name: byName.name };
1035
+ throw new Error(`session "${handle}" not found in project ${projectId}`);
1036
+ };
1037
+
1038
+ // src/commands/session/clear.ts
1039
+ var sessionClearCommand = defineCommand({
1040
+ meta: { name: "clear", description: "reset the conversation context (keeps the session + worktree)" },
1041
+ args: {
1042
+ session: { type: "positional", required: true, description: "session int id or name" },
1043
+ project: { type: "string", description: "project id (overrides .baton.json)" },
1044
+ ...common
1045
+ },
1046
+ run: async ({ args }) => {
1047
+ const c = clientFor(args);
1048
+ const handle = await resolveSession(c, resolveProjectId(args), args.session);
1049
+ const s = await c.sessions.clear(handle.id);
1050
+ console.log(renderOne(s, fmtSession, Boolean(args.json)));
1051
+ }
1052
+ });
1053
+
1021
1054
  // src/commands/session/create.ts
1022
1055
  var sessionCreateCommand = defineCommand({
1023
1056
  meta: { name: "create", description: "create + start a session on a worker" },
@@ -1038,22 +1071,6 @@ var sessionCreateCommand = defineCommand({
1038
1071
  }
1039
1072
  });
1040
1073
 
1041
- // src/commands/session/shared.ts
1042
- import { homedir } from "node:os";
1043
- import { join as join2 } from "node:path";
1044
- var defaultWorktreeDir = (env = process.env) => env.BATON_WORKTREE_DIR ?? join2(env.XDG_DATA_HOME ?? join2(env.HOME ?? homedir(), ".local/share"), "baton", "worktrees");
1045
- var slug = (s) => s.toLowerCase().replace(/[^a-z0-9_-]+/g, "-");
1046
- var resolveSession = async (client, projectId, handle) => {
1047
- const asInt = Number(handle);
1048
- if (Number.isInteger(asInt) && asInt > 0) {
1049
- const byId = await client.sessions.get(asInt).catch(() => null);
1050
- if (byId) return { id: byId.id, name: byId.name };
1051
- }
1052
- const byName = await client.sessions.findByName(projectId, handle);
1053
- if (byName) return { id: byName.id, name: byName.name };
1054
- throw new Error(`session "${handle}" not found in project ${projectId}`);
1055
- };
1056
-
1057
1074
  // src/commands/session/get.ts
1058
1075
  var sessionGetCommand = defineCommand({
1059
1076
  meta: { name: "get", description: "get a session by int id or name" },
@@ -1620,34 +1637,15 @@ function getBaseURL() {
1620
1637
  }
1621
1638
 
1622
1639
  // src/session/runner.ts
1623
- import { spawn, spawnSync } from "node:child_process";
1640
+ import { spawnSync } from "node:child_process";
1641
+ import { query as query2 } from "@anthropic-ai/claude-agent-sdk";
1624
1642
 
1625
1643
  // src/session/runner/log.ts
1626
- var claudeBin = () => process.env.BATON_CLAUDE_BIN ?? "claude";
1627
- var buildClaudeArgs = (claudeSessionId, text, resuming) => [
1628
- "--print",
1629
- resuming ? "--resume" : "--session-id",
1630
- claudeSessionId,
1631
- "--output-format",
1632
- "stream-json",
1633
- "--verbose",
1634
- "--dangerously-skip-permissions",
1635
- text
1636
- ];
1637
- var STDERR_TAIL_BYTES = 2048;
1638
- var tailBuffer = (cap = STDERR_TAIL_BYTES) => {
1639
- let buf = "";
1640
- return {
1641
- append(chunk) {
1642
- buf = (buf + chunk).slice(-cap);
1643
- },
1644
- toString() {
1645
- return buf;
1646
- }
1647
- };
1648
- };
1649
1644
  var maskedEnvKeys = (env) => env ? Object.keys(env).sort().join(", ") : "(none)";
1650
- var previewText = (text, max = 80) => text.length > max ? `${text.slice(0, max)}\u2026` : text;
1645
+
1646
+ // src/session/runner/sdk-env.ts
1647
+ var buildSdkEnv = (overlay) => overlay ? { ...process.env, ...overlay } : void 0;
1648
+ var claudeExecutable = () => process.env.BATON_CLAUDE_BIN;
1651
1649
 
1652
1650
  // src/session/runner/transcript.ts
1653
1651
  import { readdirSync, readFileSync as readFileSync2, statSync } from "node:fs";
@@ -1709,6 +1707,17 @@ var readFirstExchange = (agentSessionId) => {
1709
1707
  }
1710
1708
  };
1711
1709
 
1710
+ // ../shared/src/domain/attachment.ts
1711
+ var isImageAttachment = (att) => att.contentType.startsWith("image/");
1712
+ var labelAttachments = (attachments) => {
1713
+ const counters = { image: 0, file: 0 };
1714
+ return attachments.map((att) => {
1715
+ const kind = isImageAttachment(att) ? "image" : "file";
1716
+ counters[kind] += 1;
1717
+ return `${kind}-${counters[kind]}`;
1718
+ });
1719
+ };
1720
+
1712
1721
  // src/session/runner/attachments.ts
1713
1722
  import { createWriteStream } from "node:fs";
1714
1723
  import { mkdir, writeFile } from "node:fs/promises";
@@ -1749,96 +1758,84 @@ var materializeAttachments = async (opts) => {
1749
1758
  }
1750
1759
  return relPaths;
1751
1760
  };
1752
- var augmentPrompt = (text, relPaths) => {
1761
+ var augmentPrompt = (text, relPaths, labels) => {
1753
1762
  if (relPaths.length === 0) return text;
1754
1763
  const header = [
1755
- "[Attached files \u2014 already saved in the working directory:]",
1756
- ...relPaths.map((p) => `- ${p}`)
1764
+ "[Attached files \u2014 already saved in the working directory. Reference them by label:]",
1765
+ ...relPaths.map((p, i) => `- {${labels[i]}} ${p}`)
1757
1766
  ].join("\n");
1758
1767
  return text.length > 0 ? `${header}
1759
1768
 
1760
1769
  ${text}` : header;
1761
1770
  };
1762
1771
 
1763
- // src/session/runner/spawn.ts
1764
- import { createInterface as createInterface2 } from "node:readline";
1765
- var spawnClaude = async (config, worker2, text, resuming, spawnImpl, log, envOverlay) => {
1766
- const childEnv = envOverlay ? { ...process.env, ...envOverlay } : process.env;
1767
- const bin = claudeBin();
1768
- const args = buildClaudeArgs(config.agentSessionId, text, resuming);
1769
- log(`[spawn] ${bin} ${args.slice(0, -1).join(" ")} -- "${previewText(text)}"`);
1770
- log(`[spawn] cwd: ${config.worktreePath}`);
1771
- log(`[spawn] runtime env keys: ${maskedEnvKeys(envOverlay)}`);
1772
- let child;
1773
- try {
1774
- child = spawnImpl(bin, args, {
1775
- cwd: config.worktreePath,
1776
- stdio: ["ignore", "pipe", "pipe"],
1777
- env: childEnv
1778
- });
1779
- } catch (err) {
1780
- const message = err instanceof Error ? err.message : String(err);
1781
- log(`[spawn] failed: ${message}`);
1782
- await worker2.emitEvent("turn_error", { message: `spawn failed: ${message}` });
1783
- return null;
1784
- }
1785
- if (!child.stdout) {
1786
- log("[spawn] no stdout from claude \u2014 aborting turn");
1787
- await worker2.emitEvent("turn_error", { message: "no stdout from claude" });
1788
- return null;
1789
- }
1790
- const tail = tailBuffer();
1791
- if (child.stderr) {
1792
- const errLines = createInterface2({ input: child.stderr });
1793
- void (async () => {
1794
- for await (const line of errLines) {
1795
- tail.append(`${line}
1796
- `);
1797
- log(`[claude] ${line}`);
1798
- }
1799
- })();
1800
- }
1801
- return { child, tail };
1772
+ // src/session/runner/query.ts
1773
+ import "@anthropic-ai/claude-agent-sdk";
1774
+ var startQuery = (config, text, resuming, queryFn, abortController, log, envOverlay) => {
1775
+ const env = buildSdkEnv(envOverlay);
1776
+ const exe = claudeExecutable();
1777
+ const options = {
1778
+ cwd: config.worktreePath,
1779
+ permissionMode: "bypassPermissions",
1780
+ includePartialMessages: false,
1781
+ abortController,
1782
+ stderr: (line) => log(`[claude] ${line.trimEnd()}`),
1783
+ ...resuming ? { resume: config.agentSessionId } : { sessionId: config.agentSessionId },
1784
+ ...env ? { env } : {},
1785
+ ...exe ? { pathToClaudeCodeExecutable: exe } : {}
1786
+ };
1787
+ return queryFn({ prompt: text, options });
1802
1788
  };
1803
1789
 
1804
1790
  // src/session/runner/stream.ts
1805
- import { createInterface as createInterface3 } from "node:readline";
1806
- var streamSdkEvents = async (stdout, worker2) => {
1807
- const rl = createInterface3({ input: stdout });
1808
- for await (const line of rl) {
1809
- const trimmed = line.trim();
1810
- if (!trimmed) continue;
1811
- let payload;
1812
- try {
1813
- payload = JSON.parse(trimmed);
1814
- } catch {
1815
- payload = { raw: trimmed };
1816
- }
1817
- await worker2.emitEvent("sdk_event", payload);
1791
+ var streamSdkEvents = async (messages, worker2) => {
1792
+ let result = null;
1793
+ for await (const message of messages) {
1794
+ await worker2.emitEvent("sdk_event", message);
1795
+ if (message.type === "result") result = toTurnResult(message);
1818
1796
  }
1797
+ return result;
1798
+ };
1799
+ var toTurnResult = (message) => {
1800
+ const rec = message;
1801
+ const subtype = typeof rec.subtype === "string" ? rec.subtype : "unknown";
1802
+ const isError = rec.is_error === true || subtype !== "success";
1803
+ const resultText = typeof rec.result === "string" ? rec.result : "";
1804
+ return { subtype, isError, resultText };
1819
1805
  };
1820
1806
 
1821
1807
  // src/session/runner/turn.ts
1822
- var finalizeTurn = async (child, tail, worker2, log) => {
1823
- const exitCode = await new Promise(
1824
- (resolve) => child.once("exit", (code) => resolve(code ?? -1))
1825
- );
1826
- log(`[exit] code=${exitCode}`);
1827
- const stderrTail = tail.toString();
1828
- if (exitCode !== 0) {
1808
+ var turnTimeoutMs = () => Number(process.env.BATON_TURN_TIMEOUT_MS) || 30 * 6e4;
1809
+ var TIMEOUT = /* @__PURE__ */ Symbol("turn-timeout");
1810
+ var finalizeTurn = async (result, worker2, log) => {
1811
+ if (!result) {
1812
+ log("[exit] stream ended with no result");
1813
+ await worker2.emitEvent("turn_error", { message: "claude produced no result" });
1814
+ await worker2.emitEvent("turn_complete", {});
1815
+ return -1;
1816
+ }
1817
+ log(`[exit] subtype=${result.subtype} isError=${result.isError}`);
1818
+ if (result.isError) {
1829
1819
  await worker2.emitEvent("turn_error", {
1830
- message: `claude exited with code ${exitCode}`,
1831
- exitCode,
1832
- stderrTail
1820
+ message: result.resultText || `claude result: ${result.subtype}`,
1821
+ subtype: result.subtype
1833
1822
  });
1834
1823
  }
1835
- await worker2.emitEvent("turn_complete", {
1836
- exitCode,
1837
- ...stderrTail ? { stderrTail } : {}
1824
+ await worker2.emitEvent("turn_complete", { subtype: result.subtype });
1825
+ return result.isError ? 1 : 0;
1826
+ };
1827
+ var buildPrompt = async (config, rawText, attachments, log, fetchImpl) => {
1828
+ if (attachments.length === 0) return rawText;
1829
+ const relPaths = await materializeAttachments({
1830
+ worktreePath: config.worktreePath,
1831
+ serverBase: config.server,
1832
+ attachments,
1833
+ fetchImpl
1838
1834
  });
1839
- return exitCode;
1835
+ log(`[attach] downloaded ${relPaths.length} file(s) \u2192 ${config.worktreePath}/attachments`);
1836
+ return augmentPrompt(rawText, relPaths, labelAttachments(attachments));
1840
1837
  };
1841
- var runTurn = async (config, worker2, msg, resuming, spawnImpl, log = (m) => console.log(m), envOverlay, fetchImpl) => {
1838
+ var runTurn = async (config, worker2, msg, resuming, queryFn, log = (m) => console.log(m), envOverlay, fetchImpl) => {
1842
1839
  await worker2.emitEvent("turn_start", { messageId: msg.id });
1843
1840
  const payload = msg.payload;
1844
1841
  const rawText = typeof payload?.text === "string" ? payload.text : "";
@@ -1847,33 +1844,42 @@ var runTurn = async (config, worker2, msg, resuming, spawnImpl, log = (m) => con
1847
1844
  await worker2.emitEvent("turn_error", { message: "user_message missing text and attachments" });
1848
1845
  return -1;
1849
1846
  }
1850
- let text = rawText;
1851
- if (attachments.length > 0) {
1852
- try {
1853
- const relPaths = await materializeAttachments({
1854
- worktreePath: config.worktreePath,
1855
- serverBase: config.server,
1856
- attachments,
1857
- fetchImpl
1858
- });
1859
- log(`[attach] downloaded ${relPaths.length} file(s) \u2192 ${config.worktreePath}/attachments`);
1860
- text = augmentPrompt(rawText, relPaths);
1861
- } catch (err) {
1862
- const message = err instanceof Error ? err.message : String(err);
1863
- await worker2.emitEvent("turn_error", { message: `attachment download failed: ${message}` });
1864
- return -1;
1865
- }
1847
+ let text;
1848
+ try {
1849
+ text = await buildPrompt(config, rawText, attachments, log, fetchImpl);
1850
+ } catch (err) {
1851
+ const message = err instanceof Error ? err.message : String(err);
1852
+ await worker2.emitEvent("turn_error", { message: `attachment download failed: ${message}` });
1853
+ return -1;
1866
1854
  }
1867
- const result = await spawnClaude(config, worker2, text, resuming, spawnImpl, log, envOverlay);
1868
- if (!result) return -1;
1855
+ const abort = new AbortController();
1856
+ const ceiling = turnTimeoutMs();
1857
+ let timer;
1858
+ const timeout = new Promise((resolve) => {
1859
+ timer = setTimeout(() => resolve(TIMEOUT), ceiling);
1860
+ });
1869
1861
  try {
1870
- await streamSdkEvents(result.child.stdout, worker2);
1871
- return await finalizeTurn(result.child, result.tail, worker2, log);
1862
+ const messages = startQuery(config, text, resuming, queryFn, abort, log, envOverlay);
1863
+ const consume = streamSdkEvents(messages, worker2);
1864
+ void consume.catch(() => {
1865
+ });
1866
+ const outcome = await Promise.race([consume, timeout]);
1867
+ if (outcome === TIMEOUT) {
1868
+ log(`[watchdog] turn exceeded ${ceiling}ms \u2014 aborting claude`);
1869
+ abort.abort();
1870
+ await worker2.emitEvent("turn_error", { message: `turn exceeded ${ceiling}ms \u2014 claude aborted` });
1871
+ await worker2.emitEvent("turn_complete", {});
1872
+ return -1;
1873
+ }
1874
+ return await finalizeTurn(outcome, worker2, log);
1872
1875
  } catch (err) {
1873
1876
  const message = err instanceof Error ? err.message : String(err);
1874
1877
  log(`[run] ${message}`);
1875
- await worker2.emitEvent("turn_error", { message, stderrTail: result.tail.toString() });
1878
+ await worker2.emitEvent("turn_error", { message });
1879
+ await worker2.emitEvent("turn_complete", {});
1876
1880
  return -1;
1881
+ } finally {
1882
+ clearTimeout(timer);
1877
1883
  }
1878
1884
  };
1879
1885
 
@@ -1908,9 +1914,9 @@ var restoreTty = () => {
1908
1914
  };
1909
1915
  var runDaemon = async (config, deps, signal) => {
1910
1916
  const log = deps.log ?? ((m) => console.log(`[#${config.sessionId} ${config.name}] ${m}`));
1911
- const sp = deps.spawnImpl ?? spawn;
1917
+ const qf = deps.queryFn ?? query2;
1912
1918
  const ESCtor = deps.eventSourceImpl ?? EventSource;
1913
- log(`bin: ${claudeBin()} cwd: ${config.worktreePath}`);
1919
+ log(`bin: ${claudeExecutable() ?? "(sdk bundled)"} cwd: ${config.worktreePath}`);
1914
1920
  log(`runtime env keys: ${maskedEnvKeys(deps.env)}`);
1915
1921
  const state = {
1916
1922
  firstSpawnDone: findTranscriptPath(config.agentSessionId) !== null,
@@ -1933,7 +1939,7 @@ var runDaemon = async (config, deps, signal) => {
1933
1939
  deps.worker,
1934
1940
  msg,
1935
1941
  resuming,
1936
- sp,
1942
+ qf,
1937
1943
  log,
1938
1944
  deps.env,
1939
1945
  deps.fetchImpl
@@ -2137,6 +2143,7 @@ var session = defineCommand({
2137
2143
  create: sessionCreateCommand,
2138
2144
  resume: sessionResumeCommand,
2139
2145
  stop: sessionStopCommand,
2146
+ clear: sessionClearCommand,
2140
2147
  rename: sessionRenameCommand,
2141
2148
  rm: sessionRmCommand,
2142
2149
  send: sessionSendCommand,
@@ -2288,11 +2295,12 @@ var task = defineCommand({
2288
2295
  import { hostname as osHostname } from "node:os";
2289
2296
 
2290
2297
  // src/worker/daemon.ts
2291
- import { spawn as spawn2 } from "node:child_process";
2298
+ import { spawn } from "node:child_process";
2292
2299
  import { randomUUID } from "node:crypto";
2293
2300
  import { existsSync as existsSync4 } from "node:fs";
2294
2301
  import { dirname as dirname2, join as join5 } from "node:path";
2295
2302
  import { fileURLToPath } from "node:url";
2303
+ import { query as query3 } from "@anthropic-ai/claude-agent-sdk";
2296
2304
 
2297
2305
  // src/session/runner/title.ts
2298
2306
  var clip = (s, max) => s.length > max ? s.slice(0, max) : s;
@@ -2300,7 +2308,7 @@ var isDeclined = (title) => title.replace(/[^a-z]/gi, "").toUpperCase() === "NON
2300
2308
  var sanitizeTitle = (raw) => raw.replace(/[\r\n]+/g, " ").replace(/["'`]/g, "").replace(/^\s*(title|session)\s*[:-]\s*/i, "").replace(/\s+/g, " ").trim().slice(0, 40).trim();
2301
2309
  var TITLE_TIMEOUT_MS = 3e4;
2302
2310
  var generateTitle = async (input) => {
2303
- const { worktreePath, userText, assistantText, spawnImpl } = input;
2311
+ const { worktreePath, userText, assistantText, queryFn } = input;
2304
2312
  if (`${userText}${assistantText}`.trim().length < 4) return null;
2305
2313
  const exchange = [
2306
2314
  `User: ${clip(userText, 800)}`,
@@ -2308,44 +2316,31 @@ var generateTitle = async (input) => {
2308
2316
  ].filter(Boolean).join("\n");
2309
2317
  const prompt = `Reply with ONLY a 2-5 word title (no quotes, no punctuation) summarizing this coding session. If it is too short or generic to title meaningfully, reply with exactly NONE:
2310
2318
  ${exchange}`;
2311
- const out = await new Promise((resolve) => {
2312
- let buf = "";
2313
- let done = false;
2314
- const finish = (s) => {
2315
- if (!done) {
2316
- done = true;
2317
- resolve(s);
2318
- }
2319
- };
2320
- let child;
2321
- try {
2322
- child = spawnImpl(claudeBin(), ["--print", "--dangerously-skip-permissions", prompt], {
2319
+ const exe = claudeExecutable();
2320
+ const abort = new AbortController();
2321
+ const timer = setTimeout(() => abort.abort(), TITLE_TIMEOUT_MS);
2322
+ let out = "";
2323
+ try {
2324
+ const messages = queryFn({
2325
+ prompt,
2326
+ options: {
2323
2327
  cwd: worktreePath,
2324
- stdio: ["ignore", "pipe", "pipe"],
2325
- env: process.env
2326
- });
2327
- } catch {
2328
- return finish("");
2329
- }
2330
- const timer = setTimeout(() => {
2331
- try {
2332
- child.kill();
2333
- } catch {
2328
+ permissionMode: "bypassPermissions",
2329
+ allowedTools: [],
2330
+ includePartialMessages: false,
2331
+ abortController: abort,
2332
+ ...exe ? { pathToClaudeCodeExecutable: exe } : {}
2334
2333
  }
2335
- finish("");
2336
- }, TITLE_TIMEOUT_MS);
2337
- child.stdout?.on("data", (d) => {
2338
- buf += String(d);
2339
- });
2340
- child.on("exit", () => {
2341
- clearTimeout(timer);
2342
- finish(buf);
2343
- });
2344
- child.on("error", () => {
2345
- clearTimeout(timer);
2346
- finish("");
2347
2334
  });
2348
- });
2335
+ for await (const m of messages) {
2336
+ if (m.type === "result" && typeof m.result === "string")
2337
+ out = m.result;
2338
+ }
2339
+ } catch {
2340
+ return null;
2341
+ } finally {
2342
+ clearTimeout(timer);
2343
+ }
2349
2344
  const title = sanitizeTitle(out);
2350
2345
  return !title || isDeclined(title) ? null : title;
2351
2346
  };
@@ -2411,7 +2406,7 @@ var runWorkerDaemon = async (cfg, client, signal) => {
2411
2406
  };
2412
2407
  const spawnChild = (sessionId, worktreePath) => {
2413
2408
  if (children.has(sessionId)) return;
2414
- const child = spawn2(process.execPath, [binPath(), "session", "run", String(sessionId)], {
2409
+ const child = spawn(process.execPath, [binPath(), "session", "run", String(sessionId)], {
2415
2410
  detached: true,
2416
2411
  stdio: "inherit",
2417
2412
  env: {
@@ -2471,7 +2466,7 @@ var runWorkerDaemon = async (cfg, client, signal) => {
2471
2466
  worktreePath,
2472
2467
  userText: exchange.userText,
2473
2468
  assistantText: exchange.assistantText,
2474
- spawnImpl: spawn2
2469
+ queryFn: query3
2475
2470
  });
2476
2471
  if (!title) return log(`title #${sessionId}: not enough to title yet, skipping`);
2477
2472
  await client.sessions.setName(sessionId, title, cfg.apiToken);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lesscap/baton-cli",
3
- "version": "0.1.2",
3
+ "version": "0.2.0",
4
4
  "type": "module",
5
5
  "description": "baton CLI — register/run a worker, manage projects/requirements/tasks/sessions",
6
6
  "bin": {
@@ -9,19 +9,23 @@
9
9
  "files": [
10
10
  "dist"
11
11
  ],
12
+ "scripts": {
13
+ "baton": "tsx src/index.ts",
14
+ "build": "esbuild src/index.ts --bundle --platform=node --format=esm --packages=bundle --external:@anthropic-ai/claude-agent-sdk --banner:js=\"#!/usr/bin/env node\" --outfile=dist/baton.mjs && chmod +x dist/baton.mjs",
15
+ "prepublishOnly": "pnpm build",
16
+ "typecheck": "tsc --noEmit -p tsconfig.json",
17
+ "test": "tsx --test 'src/**/*.test.ts'"
18
+ },
12
19
  "devDependencies": {
20
+ "@baton/shared": "workspace:*",
13
21
  "@types/node": "^25.9.1",
14
22
  "citty": "^0.2.2",
15
23
  "esbuild": "^0.28.0",
16
24
  "eventsource": "^4.1.0",
17
25
  "tsx": "^4.22.4",
18
- "typescript": "^6.0.3",
19
- "@baton/shared": "0.0.0"
26
+ "typescript": "^6.0.3"
20
27
  },
21
- "scripts": {
22
- "baton": "tsx src/index.ts",
23
- "build": "esbuild src/index.ts --bundle --platform=node --format=esm --packages=bundle --banner:js=\"#!/usr/bin/env node\" --outfile=dist/baton.mjs && chmod +x dist/baton.mjs",
24
- "typecheck": "tsc --noEmit -p tsconfig.json",
25
- "test": "tsx --test 'src/**/*.test.ts'"
28
+ "dependencies": {
29
+ "@anthropic-ai/claude-agent-sdk": "^0.3.161"
26
30
  }
27
- }
31
+ }