@lesscap/baton-cli 0.9.5 → 0.9.6

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 +87 -53
  2. package/package.json +1 -1
package/dist/baton.mjs CHANGED
@@ -7563,7 +7563,7 @@ var createProvisionerClient = (config) => {
7563
7563
  import { execFile as execFile3 } from "node:child_process";
7564
7564
  import { lstat, mkdir as mkdir3, realpath, writeFile as writeFile2 } from "node:fs/promises";
7565
7565
  import { hostname } from "node:os";
7566
- import { join as join5 } from "node:path";
7566
+ import { dirname as dirname2, join as join5 } from "node:path";
7567
7567
  import { setTimeout as setTimeout2 } from "node:timers/promises";
7568
7568
  import { promisify as promisify3 } from "node:util";
7569
7569
 
@@ -7634,11 +7634,17 @@ var startAgent = async (config, agent, signal) => {
7634
7634
  throw new Error(`launchd start failed; inspect ${plist} and ${agent.log}`);
7635
7635
  }
7636
7636
  };
7637
- var launchWorkerAgent = async (config, creation, repoPath, workerEnv2, signal) => startAgent(
7637
+ var launchWorkerAgent = async (config, creation, repoPath, configPath, workerEnv2, signal) => startAgent(
7638
7638
  config,
7639
7639
  {
7640
7640
  label: `dev.fmap.baton-worker-creation-${creation.id}`,
7641
- args: [config.nodePath ?? process.execPath, config.cliPath, "worker", "run"],
7641
+ args: [
7642
+ config.nodePath ?? process.execPath,
7643
+ config.cliPath,
7644
+ "worker",
7645
+ "run",
7646
+ ...configPath === null ? [] : ["--config", configPath]
7647
+ ],
7642
7648
  cwd: repoPath,
7643
7649
  env: {
7644
7650
  PATH: workerEnv2.PATH ?? process.env.PATH ?? "/usr/bin:/bin",
@@ -7699,13 +7705,20 @@ var directory = async (path) => {
7699
7705
  const info = await lstat(path);
7700
7706
  if (!info.isDirectory() || info.isSymbolicLink()) throw new Error(`unsafe directory: ${path}`);
7701
7707
  };
7702
- var provisionWorker = async (config, creation, client, signal) => {
7703
- const repoPath = join5(
7704
- config.projectsRoot,
7705
- `project-${creation.projectId}`,
7706
- `creation-${creation.id}`
7707
- );
7708
- const progress = (step) => client.report(creation.id, { status: "running", step, repoPath }, signal);
7708
+ var gitIn = async (config, repoPath, args, signal, failure = "Git repository initialization failed") => {
7709
+ try {
7710
+ const { stdout } = await promisify3(execFile3)("git", ["-C", repoPath, ...args], {
7711
+ env: commandEnvironment(config),
7712
+ signal,
7713
+ timeout: 1e4
7714
+ });
7715
+ return stdout;
7716
+ } catch (error) {
7717
+ signal.throwIfAborted();
7718
+ throw new Error(failure, { cause: error });
7719
+ }
7720
+ };
7721
+ var initRepository = async (config, creation, repoPath, progress, signal) => {
7709
7722
  await progress("directory");
7710
7723
  signal.throwIfAborted();
7711
7724
  await mkdir3(config.projectsRoot, { recursive: true, mode: 448 });
@@ -7715,33 +7728,51 @@ var provisionWorker = async (config, creation, client, signal) => {
7715
7728
  mode: 448
7716
7729
  });
7717
7730
  await progress("git");
7718
- const git2 = async (args) => {
7719
- try {
7720
- await promisify3(execFile3)("git", ["-C", repoPath, ...args], {
7721
- env: commandEnvironment(config),
7722
- signal,
7723
- timeout: 1e4
7724
- });
7725
- } catch (error) {
7726
- signal.throwIfAborted();
7727
- throw new Error("Git repository initialization failed", { cause: error });
7728
- }
7729
- };
7730
- await git2(["init", "-b", "main"]);
7731
+ await gitIn(config, repoPath, ["init", "-b", "main"], signal);
7731
7732
  await writeFile2(join5(repoPath, ".git/info/exclude"), "\n.baton.json\n", { flag: "a" });
7732
- await git2([
7733
- "-c",
7734
- "user.name=Baton",
7735
- "-c",
7736
- "user.email=baton@localhost",
7737
- "commit",
7738
- "--allow-empty",
7739
- "-m",
7740
- "chore: initialize repository"
7741
- ]);
7733
+ await gitIn(
7734
+ config,
7735
+ repoPath,
7736
+ [
7737
+ "-c",
7738
+ "user.name=Baton",
7739
+ "-c",
7740
+ "user.email=baton@localhost",
7741
+ "commit",
7742
+ "--allow-empty",
7743
+ "-m",
7744
+ "chore: initialize repository"
7745
+ ],
7746
+ signal
7747
+ );
7748
+ };
7749
+ var adoptRepository = async (config, creation, repoPath, progress, signal) => {
7750
+ await progress("directory");
7751
+ signal.throwIfAborted();
7752
+ const real = await realpath(repoPath);
7753
+ const project2 = join5(await realpath(config.projectsRoot), `project-${creation.projectId}`);
7754
+ if (dirname2(real) !== project2 || !(await lstat(real)).isDirectory())
7755
+ throw new Error(`unsafe directory: ${repoPath}`);
7756
+ await progress("git");
7757
+ const top = await gitIn(
7758
+ config,
7759
+ real,
7760
+ ["rev-parse", "--show-toplevel"],
7761
+ signal,
7762
+ `not a Git repository: ${repoPath}`
7763
+ );
7764
+ if (await realpath(top.trim()) !== real)
7765
+ throw new Error(`not the root of a Git work tree: ${repoPath}`);
7766
+ };
7767
+ var provisionWorker = async (config, creation, client, signal) => {
7768
+ const shared = creation.repoPath !== null;
7769
+ const repoPath = creation.repoPath ?? join5(config.projectsRoot, `project-${creation.projectId}`, `creation-${creation.id}`);
7770
+ const progress = (step) => client.report(creation.id, { status: "running", step, repoPath }, signal);
7771
+ await (shared ? adoptRepository : initRepository)(config, creation, repoPath, progress, signal);
7742
7772
  await progress("register");
7743
7773
  const result = await client.register(creation.id, hostname(), signal);
7744
7774
  const state = workerStatePath(config, creation);
7775
+ const root = await realpath(config.projectsRoot);
7745
7776
  await directory(join5(root, ".worker-state"));
7746
7777
  await directory(join5(root, ".worker-state", `project-${creation.projectId}`));
7747
7778
  await mkdir3(state, { mode: 448 });
@@ -7760,15 +7791,13 @@ var provisionWorker = async (config, creation, client, signal) => {
7760
7791
  machineId: result.worker.machineId,
7761
7792
  apiToken: result.apiToken
7762
7793
  });
7763
- await writeFile2(join5(repoPath, ".baton.json"), `${JSON.stringify(cfg, null, 2)}
7764
- `, {
7765
- flag: "wx",
7766
- mode: 384
7767
- });
7794
+ const configPath = shared ? join5(state, "worker.json") : join5(repoPath, ".baton.json");
7795
+ await writeFile2(configPath, `${JSON.stringify(cfg, null, 2)}
7796
+ `, { flag: "wx", mode: 384 });
7768
7797
  await progress("start");
7769
7798
  signal.throwIfAborted();
7770
7799
  const workerEnv2 = await workerTemplateEnvironment(config, creation, state);
7771
- await launchWorkerAgent(config, creation, repoPath, workerEnv2, signal);
7800
+ await launchWorkerAgent(config, creation, repoPath, shared ? configPath : null, workerEnv2, signal);
7772
7801
  await progress("connect");
7773
7802
  const deadline = Date.now() + 6e4;
7774
7803
  while (Date.now() < deadline) {
@@ -10013,13 +10042,13 @@ import { hostname as osHostname } from "node:os";
10013
10042
  // src/worker/bundled-skills.ts
10014
10043
  import { spawnSync as spawnSync2 } from "node:child_process";
10015
10044
  import { cpSync, existsSync as existsSync5 } from "node:fs";
10016
- import { dirname as dirname3, join as join14 } from "node:path";
10045
+ import { dirname as dirname4, join as join14 } from "node:path";
10017
10046
  import { fileURLToPath } from "node:url";
10018
10047
 
10019
10048
  // src/worker/git-exclude.ts
10020
10049
  import { spawnSync } from "node:child_process";
10021
10050
  import { appendFileSync, existsSync as existsSync4, mkdirSync as mkdirSync3, readFileSync as readFileSync5 } from "node:fs";
10022
- import { dirname as dirname2, isAbsolute as isAbsolute3, resolve as resolve3 } from "node:path";
10051
+ import { dirname as dirname3, isAbsolute as isAbsolute3, resolve as resolve3 } from "node:path";
10023
10052
  var ensureExcluded = (cwd, pattern) => {
10024
10053
  const result = spawnSync("git", ["-C", cwd, "rev-parse", "--git-path", "info/exclude"], {
10025
10054
  encoding: "utf8",
@@ -10034,7 +10063,7 @@ var ensureExcluded = (cwd, pattern) => {
10034
10063
  const path = isAbsolute3(location) ? location : resolve3(cwd, location);
10035
10064
  const current = existsSync4(path) ? readFileSync5(path, "utf8") : "";
10036
10065
  if (current.split("\n").includes(pattern)) return;
10037
- mkdirSync3(dirname2(path), { recursive: true });
10066
+ mkdirSync3(dirname3(path), { recursive: true });
10038
10067
  appendFileSync(path, `${current && !current.endsWith("\n") ? "\n" : ""}${pattern}
10039
10068
  `);
10040
10069
  };
@@ -10043,7 +10072,7 @@ var ensureExcluded = (cwd, pattern) => {
10043
10072
  var SKILL_NAME = "baton-publish-artifact";
10044
10073
  var TARGETS = [`.claude/skills/${SKILL_NAME}`, `.agents/skills/${SKILL_NAME}`];
10045
10074
  var bundledSkillPath = () => {
10046
- const here = dirname3(fileURLToPath(import.meta.url));
10075
+ const here = dirname4(fileURLToPath(import.meta.url));
10047
10076
  const candidates = [
10048
10077
  join14(here, "..", "skills", SKILL_NAME),
10049
10078
  join14(here, "..", "..", "skills", SKILL_NAME)
@@ -10651,7 +10680,7 @@ import { join as join17 } from "node:path";
10651
10680
  // src/worker/service-process.ts
10652
10681
  import { spawn as spawn3 } from "node:child_process";
10653
10682
  import { closeSync, existsSync as existsSync6, openSync } from "node:fs";
10654
- import { dirname as dirname4, join as join16 } from "node:path";
10683
+ import { dirname as dirname5, join as join16 } from "node:path";
10655
10684
  import { fileURLToPath as fileURLToPath2 } from "node:url";
10656
10685
  var START_TIMEOUT_MS = 1e4;
10657
10686
  var isWrapperMessage = (message) => {
@@ -10661,7 +10690,7 @@ var isWrapperMessage = (message) => {
10661
10690
  return value.type === "error" && typeof value.error === "string";
10662
10691
  };
10663
10692
  var binPath = () => {
10664
- const here = dirname4(fileURLToPath2(import.meta.url));
10693
+ const here = dirname5(fileURLToPath2(import.meta.url));
10665
10694
  const devShim = join16(here, "..", "..", "bin", "baton.mjs");
10666
10695
  return existsSync6(devShim) ? devShim : fileURLToPath2(import.meta.url);
10667
10696
  };
@@ -10823,7 +10852,7 @@ import { spawn as spawn4 } from "node:child_process";
10823
10852
  import { randomUUID as randomUUID2 } from "node:crypto";
10824
10853
  import { existsSync as existsSync7 } from "node:fs";
10825
10854
  import { mkdir as mkdir6, rm as rm3, stat as stat5 } from "node:fs/promises";
10826
- import { dirname as dirname5, join as join21 } from "node:path";
10855
+ import { dirname as dirname6, join as join21 } from "node:path";
10827
10856
  import { fileURLToPath as fileURLToPath3 } from "node:url";
10828
10857
  import { query as query2 } from "@anthropic-ai/claude-agent-sdk";
10829
10858
 
@@ -11086,7 +11115,7 @@ var stopRecordedRunner = async (record, expected, graceMs = 5e3) => {
11086
11115
 
11087
11116
  // src/worker/session-supervisor.ts
11088
11117
  var binPath2 = () => {
11089
- const here = dirname5(fileURLToPath3(import.meta.url));
11118
+ const here = dirname6(fileURLToPath3(import.meta.url));
11090
11119
  const devShim = join21(here, "..", "..", "bin", "baton.mjs");
11091
11120
  return existsSync7(devShim) ? devShim : fileURLToPath3(import.meta.url);
11092
11121
  };
@@ -11332,7 +11361,7 @@ var import_websocket_server = __toESM(require_websocket_server(), 1);
11332
11361
  import { existsSync as existsSync8, readdirSync as readdirSync2 } from "node:fs";
11333
11362
  import { createRequire as createModuleRequire } from "node:module";
11334
11363
  import { homedir as homedir5 } from "node:os";
11335
- import { dirname as dirname6, join as join22 } from "node:path";
11364
+ import { dirname as dirname7, join as join22 } from "node:path";
11336
11365
  import { fileURLToPath as fileURLToPath4 } from "node:url";
11337
11366
  var MAX_TERMINALS = 10;
11338
11367
  var claudePtyCommand = (agentSessionId, hasJsonl, env = process.env) => ({
@@ -11353,7 +11382,7 @@ var piPtyCommand = (agentSessionId, env = process.env) => {
11353
11382
  const override = env.BATON_PI_BIN?.trim();
11354
11383
  if (override) return { file: override, args };
11355
11384
  const entry = fileURLToPath4(import.meta.resolve("@earendil-works/pi-coding-agent"));
11356
- return { file: process.execPath, args: [join22(dirname6(entry), "bundle", "cli.js"), ...args] };
11385
+ return { file: process.execPath, args: [join22(dirname7(entry), "bundle", "cli.js"), ...args] };
11357
11386
  };
11358
11387
  var hasSessionJsonl = (agentSessionId) => {
11359
11388
  const root = join22(homedir5(), ".claude", "projects");
@@ -11558,7 +11587,7 @@ var runWorkerDaemon = async (cfg, client, signal) => {
11558
11587
  import { randomUUID as randomUUID3 } from "node:crypto";
11559
11588
  import { existsSync as existsSync9, mkdirSync as mkdirSync5, readFileSync as readFileSync6, writeFileSync as writeFileSync5 } from "node:fs";
11560
11589
  import { homedir as homedir6 } from "node:os";
11561
- import { dirname as dirname7, join as join23 } from "node:path";
11590
+ import { dirname as dirname8, join as join23 } from "node:path";
11562
11591
  var machineIdPath = (env = process.env) => join23(env.XDG_DATA_HOME ?? join23(env.HOME ?? homedir6(), ".local/share"), "baton", "machine-id");
11563
11592
  var readOrCreateMachineId = (path = machineIdPath()) => {
11564
11593
  if (existsSync9(path)) {
@@ -11566,7 +11595,7 @@ var readOrCreateMachineId = (path = machineIdPath()) => {
11566
11595
  if (s) return s;
11567
11596
  }
11568
11597
  const id = randomUUID3();
11569
- mkdirSync5(dirname7(path), { recursive: true });
11598
+ mkdirSync5(dirname8(path), { recursive: true });
11570
11599
  writeFileSync5(path, `${id}
11571
11600
  `, "utf8");
11572
11601
  return id;
@@ -11600,7 +11629,11 @@ var workerCreateCommand = defineCommand({
11600
11629
  description: "mini-glm-codeplan | mini-dashscope-codeplan | mini-codex"
11601
11630
  },
11602
11631
  name: { type: "string", required: true, description: "worker name" },
11603
- agentKind: { type: "string", description: AGENT_KINDS.join(", ") }
11632
+ agentKind: { type: "string", description: AGENT_KINDS.join(", ") },
11633
+ repoPath: {
11634
+ type: "string",
11635
+ description: "share an existing worker's directory in this project (default: a new one)"
11636
+ }
11604
11637
  },
11605
11638
  run: async ({ args }) => {
11606
11639
  if (!isWorkerTemplateId(args.template)) throw new Error("invalid worker template");
@@ -11615,7 +11648,8 @@ var workerCreateCommand = defineCommand({
11615
11648
  {
11616
11649
  templateId: args.template,
11617
11650
  name,
11618
- agentKind
11651
+ agentKind,
11652
+ ...args.repoPath ? { repoPath: args.repoPath } : {}
11619
11653
  }
11620
11654
  );
11621
11655
  console.log(renderOne(creation, fmtWorkerCreation, Boolean(args.json)));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lesscap/baton-cli",
3
- "version": "0.9.5",
3
+ "version": "0.9.6",
4
4
  "license": "MIT",
5
5
  "publishConfig": {
6
6
  "access": "public"