@botiverse/raft-daemon 0.59.0 → 0.60.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.
@@ -1422,6 +1422,11 @@ function parseModeConfig(value) {
1422
1422
  if (value.kind === "fast") return { kind: "fast" };
1423
1423
  return { kind: "default" };
1424
1424
  }
1425
+ function parseCommandConfig(runtime, value) {
1426
+ if (runtime !== "claude" || typeof value !== "string") return void 0;
1427
+ const command = value.trim();
1428
+ return command ? command : void 0;
1429
+ }
1425
1430
  function hydrateRuntimeConfig(input) {
1426
1431
  const stored = isPlainRecord(input.runtimeConfig) && input.runtimeConfig.version === RUNTIME_CONFIG_VERSION ? input.runtimeConfig : null;
1427
1432
  const runtime = typeof stored?.runtime === "string" && stored.runtime.trim() || typeof input.runtime === "string" && input.runtime.trim() || "claude";
@@ -1432,6 +1437,7 @@ function hydrateRuntimeConfig(input) {
1432
1437
  const legacyClaudeApiKey = runtime === "claude" ? legacyEnvVars?.ANTHROPIC_API_KEY : void 0;
1433
1438
  const legacyClaudeCustomModel = runtime === "claude" ? legacyEnvVars?.ANTHROPIC_CUSTOM_MODEL_OPTION : void 0;
1434
1439
  const provider = stored ? parseProviderConfig(runtime, stored.provider, legacyClaudeApiUrl, legacyClaudeApiKey) : runtime === "claude" && legacyClaudeApiUrl && legacyClaudeApiKey ? { kind: "custom", apiUrl: legacyClaudeApiUrl, apiKey: legacyClaudeApiKey } : runtime === "claude" ? { kind: "default" } : void 0;
1440
+ const command = stored ? parseCommandConfig(runtime, stored.command) : void 0;
1435
1441
  return {
1436
1442
  version: RUNTIME_CONFIG_VERSION,
1437
1443
  runtime,
@@ -1439,7 +1445,8 @@ function hydrateRuntimeConfig(input) {
1439
1445
  model: stored ? parseModelConfig(runtime, stored.model, fallbackModel, provider, legacyClaudeCustomModel) : modelConfigFromLegacy(runtime, fallbackModel),
1440
1446
  mode: stored ? parseModeConfig(stored.mode) : { kind: "default" },
1441
1447
  reasoningEffort: stored?.reasoningEffort ?? input.reasoningEffort ?? null,
1442
- envVars: stripControlledRuntimeEnvVars(runtime, stored ? storedEnvVars : legacyEnvVars)
1448
+ envVars: stripControlledRuntimeEnvVars(runtime, stored ? storedEnvVars : legacyEnvVars),
1449
+ ...command ? { command } : {}
1443
1450
  };
1444
1451
  }
1445
1452
  function runtimeConfigModelValue(config) {
@@ -1466,16 +1473,26 @@ function runtimeConfigToLaunchFields(config) {
1466
1473
  model: runtimeConfigModelValue(normalized),
1467
1474
  mode: normalized.mode,
1468
1475
  reasoningEffort: normalized.reasoningEffort ?? null,
1469
- envVars: Object.keys(envVars).length > 0 ? envVars : null
1476
+ envVars: Object.keys(envVars).length > 0 ? envVars : null,
1477
+ ...normalized.command ? { command: normalized.command } : {}
1470
1478
  };
1471
1479
  }
1472
1480
  var PLAN_CONFIG = {
1473
1481
  free: {
1474
- displayName: "Hobby",
1482
+ displayName: "Free",
1475
1483
  limits: { maxMachines: 2, maxAgents: 5, maxChannels: 5, messageHistoryDays: 30, includedAgents: 5 },
1476
1484
  comingSoon: false,
1477
1485
  price: 0,
1478
- extraAgentPrice: 0
1486
+ extraAgentPrice: 0,
1487
+ displayFeatures: [
1488
+ "Channels",
1489
+ "Tasks",
1490
+ "Unlimited agents on your own computers",
1491
+ "Agent Reminders",
1492
+ "Basic observability",
1493
+ "30 days of message history",
1494
+ "100 MB file uploads/month"
1495
+ ]
1479
1496
  },
1480
1497
  founder: {
1481
1498
  displayName: "Founder",
@@ -1488,23 +1505,40 @@ var PLAN_CONFIG = {
1488
1505
  var DISPLAY_PLAN_CONFIG = {
1489
1506
  free: PLAN_CONFIG.free,
1490
1507
  pro: {
1491
- displayName: "Team",
1492
- limits: { maxMachines: 8, maxAgents: 40, maxChannels: 20, messageHistoryDays: -1, includedAgents: 40 },
1493
- comingSoon: true,
1508
+ displayName: "Pro",
1509
+ limits: { maxMachines: -1, maxAgents: 10, maxChannels: -1, messageHistoryDays: -1, includedAgents: 10 },
1510
+ comingSoon: false,
1494
1511
  price: 20,
1495
- extraAgentPrice: 0
1512
+ priceCadence: "/ seat pack / month",
1513
+ extraAgentPrice: 0,
1514
+ displayFeatures: [
1515
+ "1 human seat + 10 agent seats per Pro Seat Pack",
1516
+ "Unlimited message history",
1517
+ "Higher file upload limits",
1518
+ "Joint Channels",
1519
+ "More professional features coming soon"
1520
+ ],
1521
+ displayNote: "$17.60 / seat pack / month when billed yearly"
1496
1522
  },
1497
- max: {
1498
- displayName: "Business",
1499
- limits: { maxMachines: 40, maxAgents: 200, maxChannels: -1, messageHistoryDays: -1, includedAgents: 200 },
1500
- comingSoon: true,
1501
- price: 200,
1502
- extraAgentPrice: 0
1523
+ enterprise: {
1524
+ displayName: "Enterprise",
1525
+ limits: { maxMachines: -1, maxAgents: -1, maxChannels: -1, messageHistoryDays: -1, includedAgents: -1 },
1526
+ comingSoon: false,
1527
+ price: 0,
1528
+ priceLabel: "Coming soon",
1529
+ priceCadence: null,
1530
+ extraAgentPrice: 0,
1531
+ displayFeatures: [
1532
+ "Custom commercial terms",
1533
+ "Security and compliance review",
1534
+ "Dedicated support and onboarding",
1535
+ "Custom deployment planning"
1536
+ ]
1503
1537
  }
1504
1538
  };
1505
1539
 
1506
1540
  // src/agentProcessManager.ts
1507
- import { mkdirSync as mkdirSync4, readdirSync as readdirSync2, statSync, writeFileSync as writeFileSync4 } from "fs";
1541
+ import { mkdirSync as mkdirSync4, readdirSync as readdirSync3, statSync, writeFileSync as writeFileSync4 } from "fs";
1508
1542
  import { mkdir, writeFile, access, readdir as readdir2, stat as stat2, readFile, rm as rm2 } from "fs/promises";
1509
1543
  import { createHash as createHash3 } from "crypto";
1510
1544
  import path12 from "path";
@@ -1514,7 +1548,7 @@ import os6 from "os";
1514
1548
  import { spawn } from "child_process";
1515
1549
 
1516
1550
  // src/drivers/cliTransport.ts
1517
- import { mkdirSync, readFileSync, rmSync, writeFileSync } from "fs";
1551
+ import { existsSync as existsSync2, mkdirSync, readdirSync, readFileSync, rmSync, writeFileSync } from "fs";
1518
1552
  import { createRequire } from "module";
1519
1553
  import path2 from "path";
1520
1554
 
@@ -3585,6 +3619,32 @@ var safePathPart = (value) => value.replace(/[^a-zA-Z0-9_.-]/g, "_");
3585
3619
  var RAW_CREDENTIAL_ENV_DENYLIST = [
3586
3620
  "SLOCK_AGENT_CREDENTIAL_KEY"
3587
3621
  ];
3622
+ function deriveCliFallbackCandidates(cliPath) {
3623
+ if (!cliPath || cliPath === "__cli") return [];
3624
+ const normalized = cliPath.split(path2.sep).join("/");
3625
+ const marker = "/node_modules/";
3626
+ const idx = normalized.indexOf(marker);
3627
+ if (idx === -1) return [];
3628
+ const globalRoot = cliPath.slice(0, idx + marker.length - 1);
3629
+ const tail = path2.join("dist", "cli", "index.js");
3630
+ return [
3631
+ path2.join(globalRoot, "@botiverse", "raft-daemon", tail),
3632
+ path2.join(globalRoot, "@slock-ai", "daemon", tail)
3633
+ ].filter((candidate) => candidate !== cliPath);
3634
+ }
3635
+ function deriveOpencliFallbackCandidates(binPath) {
3636
+ if (!binPath) return [];
3637
+ const normalized = binPath.split(path2.sep).join("/");
3638
+ const marker = "/node_modules/";
3639
+ const first = normalized.indexOf(marker);
3640
+ if (first === -1) return [];
3641
+ const pkgMarker = "/node_modules/@jackwener/opencli/";
3642
+ const last = normalized.lastIndexOf(pkgMarker);
3643
+ if (last === -1) return [];
3644
+ const suffix = normalized.slice(last + pkgMarker.length);
3645
+ const candidate = path2.join(binPath.slice(0, first + marker.length - 1), "@jackwener", "opencli", ...suffix.split("/"));
3646
+ return candidate === binPath ? [] : [candidate];
3647
+ }
3588
3648
  var cachedOpencliBinPath;
3589
3649
  function resolveOpencliBinPath() {
3590
3650
  if (cachedOpencliBinPath !== void 0) return cachedOpencliBinPath;
@@ -3619,6 +3679,64 @@ function resolveOpencliBinPath() {
3619
3679
  return null;
3620
3680
  }
3621
3681
  }
3682
+ function writeOpencliWrapper(slockDir, opencliBinPath, platform = process.platform) {
3683
+ const fallbacks = deriveOpencliFallbackCandidates(opencliBinPath);
3684
+ let binPath = opencliBinPath;
3685
+ if (!existsSync2(binPath)) {
3686
+ const fallback = fallbacks.find((candidate) => existsSync2(candidate));
3687
+ if (fallback) binPath = fallback;
3688
+ }
3689
+ const posixFallbackBlock = fallbacks.length === 0 ? "" : `if [ ! -e "$OPENCLI_BIN" ]; then
3690
+ ${fallbacks.map((candidate, i) => ` ${i === 0 ? "if" : "elif"} [ -e ${shellSingleQuote(candidate)} ]; then OPENCLI_BIN=${shellSingleQuote(candidate)};`).join("\n")}
3691
+ fi
3692
+ fi
3693
+ `;
3694
+ writeFileSync(
3695
+ path2.join(slockDir, "opencli"),
3696
+ `#!/usr/bin/env bash
3697
+ OPENCLI_BIN=${shellSingleQuote(binPath)}
3698
+ ${posixFallbackBlock}exec ${shellSingleQuote(process.execPath)} "$OPENCLI_BIN" "$@"
3699
+ `,
3700
+ { mode: 493 }
3701
+ );
3702
+ if (platform === "win32") {
3703
+ const opencliCmdBody = [
3704
+ "@echo off",
3705
+ "set PYTHONIOENCODING=utf-8",
3706
+ "set PYTHONUTF8=1",
3707
+ "set LANG=C.UTF-8",
3708
+ "set LC_ALL=C.UTF-8",
3709
+ "chcp 65001 >NUL 2>NUL",
3710
+ `set "OPENCLI_BIN=${binPath}"`,
3711
+ ...fallbacks.map((candidate) => `if not exist "%OPENCLI_BIN%" set "OPENCLI_BIN=${candidate}"`),
3712
+ `"${process.execPath}" "%OPENCLI_BIN%" %*`,
3713
+ ""
3714
+ ].join("\r\n") + "\r\n";
3715
+ writeFileSync(path2.join(slockDir, "opencli.cmd"), opencliCmdBody);
3716
+ }
3717
+ }
3718
+ function regenerateExistingOpencliWrappers(agentsRoot, platform = process.platform, opencliBinPath = resolveOpencliBinPath()) {
3719
+ if (!opencliBinPath) return { scanned: 0, rewritten: 0 };
3720
+ let entries;
3721
+ try {
3722
+ entries = readdirSync(agentsRoot);
3723
+ } catch {
3724
+ return { scanned: 0, rewritten: 0 };
3725
+ }
3726
+ let scanned = 0;
3727
+ let rewritten = 0;
3728
+ for (const entry of entries) {
3729
+ const slockDir = path2.join(agentsRoot, entry, ".slock");
3730
+ if (!existsSync2(path2.join(slockDir, "opencli"))) continue;
3731
+ scanned++;
3732
+ try {
3733
+ writeOpencliWrapper(slockDir, opencliBinPath, platform);
3734
+ rewritten++;
3735
+ } catch {
3736
+ }
3737
+ }
3738
+ return { scanned, rewritten };
3739
+ }
3622
3740
  function windowsUtf8Env() {
3623
3741
  return {
3624
3742
  PYTHONIOENCODING: "utf-8",
@@ -3676,6 +3794,21 @@ async function prepareCliTransport(ctx, extraEnv = {}, platform = process.platfo
3676
3794
  if (!ctx.slockCliPath) {
3677
3795
  throw new Error(`${ctx.config.runtime} driver: slockCliPath is required (daemon must inject it)`);
3678
3796
  }
3797
+ let cliPath = ctx.slockCliPath;
3798
+ const cliFallbackCandidates = deriveCliFallbackCandidates(cliPath);
3799
+ if (cliPath !== "__cli" && !existsSync2(cliPath)) {
3800
+ const fallback = cliFallbackCandidates.find((candidate) => existsSync2(candidate));
3801
+ if (fallback) {
3802
+ console.error(
3803
+ `[cliTransport] bundled CLI missing at ${cliPath} (package tree mutated under a running daemon?); using ${fallback}. Restart the daemon from its current install to clear this.`
3804
+ );
3805
+ cliPath = fallback;
3806
+ } else {
3807
+ console.error(
3808
+ `[cliTransport] bundled CLI missing at ${cliPath} and no global fallback found; wrappers will be broken until the daemon is restarted from a valid install.`
3809
+ );
3810
+ }
3811
+ }
3679
3812
  const slockDir = path2.join(ctx.workingDirectory, ".slock");
3680
3813
  mkdirSync(slockDir, { recursive: true });
3681
3814
  const slockHome = resolveSlockHome();
@@ -3704,9 +3837,15 @@ async function prepareCliTransport(ctx, extraEnv = {}, platform = process.platfo
3704
3837
  const posixWrapper = path2.join(slockDir, "slock");
3705
3838
  const posixRaftWrapper = path2.join(slockDir, "raft");
3706
3839
  const posixCredentialPrefix = agentCredentialProxy ? `SLOCK_AGENT_PROXY_URL=${shellSingleQuote(agentCredentialProxy.proxyUrl)} SLOCK_AGENT_PROXY_TOKEN_FILE=${shellSingleQuote(agentCredentialProxyTokenFile)} SLOCK_AGENT_ACTIVE_CAPABILITIES=${shellSingleQuote(DEFAULT_ACTIVE_CAPABILITIES)} ` : "";
3840
+ const posixCliFallbackBlock = cliPath === "__cli" || cliFallbackCandidates.length === 0 ? "" : `if [ ! -e "$SLOCK_CLI" ]; then
3841
+ ${cliFallbackCandidates.map((candidate, i) => ` ${i === 0 ? "if" : "elif"} [ -e ${shellSingleQuote(candidate)} ]; then SLOCK_CLI=${shellSingleQuote(candidate)};`).join("\n")}
3842
+ fi
3843
+ fi
3844
+ `;
3707
3845
  const posixBody = `#!/usr/bin/env bash
3708
3846
  ${posixLoopbackNoProxyPrelude()}
3709
- ${posixCredentialPrefix}exec ${shellSingleQuote(process.execPath)} ${shellSingleQuote(ctx.slockCliPath)} "$@"
3847
+ SLOCK_CLI=${shellSingleQuote(cliPath)}
3848
+ ${posixCliFallbackBlock}${posixCredentialPrefix}exec ${shellSingleQuote(process.execPath)} "$SLOCK_CLI" "$@"
3710
3849
  `;
3711
3850
  writeFileSync(posixWrapper, posixBody, { mode: 493 });
3712
3851
  writeFileSync(posixRaftWrapper, posixBody, { mode: 493 });
@@ -3717,6 +3856,7 @@ ${posixCredentialPrefix}exec ${shellSingleQuote(process.execPath)} ${shellSingle
3717
3856
  set "SLOCK_AGENT_PROXY_TOKEN_FILE=${agentCredentialProxyTokenFile}"\r
3718
3857
  set "SLOCK_AGENT_ACTIVE_CAPABILITIES=${DEFAULT_ACTIVE_CAPABILITIES}"\r
3719
3858
  ` : "";
3859
+ const cmdCliFallbackLines = cliPath === "__cli" ? [] : cliFallbackCandidates.map((candidate) => `if not exist "%SLOCK_CLI%" set "SLOCK_CLI=${candidate}"`);
3720
3860
  const cmdBody = [
3721
3861
  "@echo off",
3722
3862
  "set PYTHONIOENCODING=utf-8",
@@ -3726,7 +3866,9 @@ set "SLOCK_AGENT_ACTIVE_CAPABILITIES=${DEFAULT_ACTIVE_CAPABILITIES}"\r
3726
3866
  "chcp 65001 >NUL 2>NUL",
3727
3867
  ...cmdLoopbackNoProxyLines(),
3728
3868
  cmdCredentialLine.trimEnd(),
3729
- `"${process.execPath}" "${ctx.slockCliPath}" %*`,
3869
+ `set "SLOCK_CLI=${cliPath}"`,
3870
+ ...cmdCliFallbackLines,
3871
+ `"${process.execPath}" "%SLOCK_CLI%" %*`,
3730
3872
  ""
3731
3873
  ].filter((line) => line.length > 0).join("\r\n") + "\r\n";
3732
3874
  writeFileSync(cmdWrapper, cmdBody);
@@ -3750,7 +3892,14 @@ set "SLOCK_AGENT_ACTIVE_CAPABILITIES=${DEFAULT_ACTIVE_CAPABILITIES}"\r
3750
3892
  ...powershellLoopbackNoProxyLines(),
3751
3893
  ...psCredentialLines,
3752
3894
  `$node = ${powershellSingleQuote(process.execPath)}`,
3753
- `$cli = ${powershellSingleQuote(ctx.slockCliPath)}`,
3895
+ `$cli = ${powershellSingleQuote(cliPath)}`,
3896
+ ...cliPath === "__cli" || cliFallbackCandidates.length === 0 ? [] : [
3897
+ "if (-not (Test-Path $cli)) {",
3898
+ ` foreach ($candidate in @(${cliFallbackCandidates.map(powershellSingleQuote).join(", ")})) {`,
3899
+ " if (Test-Path $candidate) { $cli = $candidate; break }",
3900
+ " }",
3901
+ "}"
3902
+ ],
3754
3903
  "if ($MyInvocation.ExpectingInput) {",
3755
3904
  " $input | & $node $cli @args",
3756
3905
  "} else {",
@@ -3764,28 +3913,7 @@ set "SLOCK_AGENT_ACTIVE_CAPABILITIES=${DEFAULT_ACTIVE_CAPABILITIES}"\r
3764
3913
  }
3765
3914
  const opencliBinPath = resolveOpencliBinPath();
3766
3915
  if (opencliBinPath) {
3767
- const opencliPosixWrapper = path2.join(slockDir, "opencli");
3768
- writeFileSync(
3769
- opencliPosixWrapper,
3770
- `#!/usr/bin/env bash
3771
- exec ${shellSingleQuote(process.execPath)} ${shellSingleQuote(opencliBinPath)} "$@"
3772
- `,
3773
- { mode: 493 }
3774
- );
3775
- if (platform === "win32") {
3776
- const opencliCmdWrapper = path2.join(slockDir, "opencli.cmd");
3777
- const opencliCmdBody = [
3778
- "@echo off",
3779
- "set PYTHONIOENCODING=utf-8",
3780
- "set PYTHONUTF8=1",
3781
- "set LANG=C.UTF-8",
3782
- "set LC_ALL=C.UTF-8",
3783
- "chcp 65001 >NUL 2>NUL",
3784
- `"${process.execPath}" "${opencliBinPath}" %*`,
3785
- ""
3786
- ].join("\r\n") + "\r\n";
3787
- writeFileSync(opencliCmdWrapper, opencliCmdBody);
3788
- }
3916
+ writeOpencliWrapper(slockDir, opencliBinPath, platform);
3789
3917
  }
3790
3918
  const wrapperPath = platform === "win32" ? path2.join(slockDir, "slock.cmd") : posixWrapper;
3791
3919
  const launchRuntimeFields = runtimeConfigToLaunchFields(ctx.config);
@@ -4079,7 +4207,7 @@ import path4 from "path";
4079
4207
 
4080
4208
  // src/drivers/probe.ts
4081
4209
  import { execFileSync } from "child_process";
4082
- import { existsSync as existsSync2 } from "fs";
4210
+ import { existsSync as existsSync3 } from "fs";
4083
4211
  import path3 from "path";
4084
4212
  function normalizeExecOutput(raw) {
4085
4213
  return Buffer.isBuffer(raw) ? raw.toString("utf8") : String(raw ?? "");
@@ -4231,11 +4359,17 @@ function resolveCommandOnWindows(command, env, execFileSyncFn, existsSyncFn) {
4231
4359
  return null;
4232
4360
  }
4233
4361
  }
4362
+ function requiresWindowsShell(command, platform = process.platform) {
4363
+ if (platform !== "win32") return false;
4364
+ if (!command) return false;
4365
+ const lower = command.toLowerCase();
4366
+ return lower.endsWith(".cmd") || lower.endsWith(".bat");
4367
+ }
4234
4368
  function resolveCommandOnPath(command, deps = {}) {
4235
4369
  const platform = deps.platform ?? process.platform;
4236
4370
  const env = withWindowsUserEnvironment(deps.env ?? process.env, deps);
4237
4371
  const execFileSyncFn = deps.execFileSyncFn ?? execFileSync;
4238
- const existsSyncFn = deps.existsSyncFn ?? existsSync2;
4372
+ const existsSyncFn = deps.existsSyncFn ?? existsSync3;
4239
4373
  if (platform === "win32") {
4240
4374
  return resolveCommandOnWindows(command, env, execFileSyncFn, existsSyncFn);
4241
4375
  }
@@ -4252,7 +4386,7 @@ function resolveCommandOnPath(command, deps = {}) {
4252
4386
  }
4253
4387
  }
4254
4388
  function firstExistingPath(candidates, deps = {}) {
4255
- const exists = deps.existsSyncFn ?? existsSync2;
4389
+ const exists = deps.existsSyncFn ?? existsSync3;
4256
4390
  for (const candidate of candidates) {
4257
4391
  if (exists(candidate)) return candidate;
4258
4392
  }
@@ -4298,6 +4432,10 @@ function resolveClaudeCommand(deps = {}) {
4298
4432
  CLAUDE_DESKTOP_CLI_SYSTEM_PATH
4299
4433
  ], deps);
4300
4434
  }
4435
+ function resolveClaudeLaunchCommand(config, deps = {}) {
4436
+ const launchRuntimeFields = runtimeConfigToLaunchFields(config);
4437
+ return launchRuntimeFields.command?.trim() || resolveClaudeCommand(deps);
4438
+ }
4301
4439
  function probeClaude(deps = {}) {
4302
4440
  const command = resolveClaudeCommand(deps);
4303
4441
  if (!command) return { available: false };
@@ -4354,7 +4492,7 @@ function buildClaudeSpawnSpec(claudeCommand, platform = process.platform) {
4354
4492
  }
4355
4493
 
4356
4494
  // src/drivers/claudeProviderIsolation.ts
4357
- import { existsSync as existsSync3, mkdirSync as mkdirSync2, symlinkSync } from "fs";
4495
+ import { existsSync as existsSync4, mkdirSync as mkdirSync2, symlinkSync } from "fs";
4358
4496
  import os2 from "os";
4359
4497
  import path5 from "path";
4360
4498
  function isClaudeCustomProviderConfig(config) {
@@ -4372,7 +4510,7 @@ function getClaudeProviderStatePaths(workingDirectory) {
4372
4510
  }
4373
4511
  function linkIfPresent(source, target) {
4374
4512
  try {
4375
- if (!existsSync3(source) || existsSync3(target)) return;
4513
+ if (!existsSync4(source) || existsSync4(target)) return;
4376
4514
  mkdirSync2(path5.dirname(target), { recursive: true, mode: 448 });
4377
4515
  symlinkSync(source, target, "dir");
4378
4516
  } catch {
@@ -4444,7 +4582,7 @@ var ClaudeDriver = class {
4444
4582
  logger.info(
4445
4583
  `[Agent ${ctx.agentId}] transport=cli cli=${ctx.slockCliPath} token_file=${tokenFile}`
4446
4584
  );
4447
- const claudeCommand = resolveClaudeCommand();
4585
+ const claudeCommand = resolveClaudeLaunchCommand(ctx.config);
4448
4586
  const spawnSpec = buildClaudeSpawnSpec(claudeCommand);
4449
4587
  const proc = spawn(spawnSpec.command, args, {
4450
4588
  cwd: ctx.workingDirectory,
@@ -4493,7 +4631,7 @@ var ClaudeDriver = class {
4493
4631
 
4494
4632
  // src/drivers/codex.ts
4495
4633
  import { spawn as spawn2, execFileSync as execFileSync2, execSync } from "child_process";
4496
- import { existsSync as existsSync4, readFileSync as readFileSync2 } from "fs";
4634
+ import { existsSync as existsSync5, readFileSync as readFileSync2 } from "fs";
4497
4635
  import os3 from "os";
4498
4636
  import path6 from "path";
4499
4637
 
@@ -4882,7 +5020,7 @@ var CodexEventNormalizer = class {
4882
5020
 
4883
5021
  // src/drivers/codex.ts
4884
5022
  function ensureGitRepoForCodex(workingDirectory, deps = {}) {
4885
- const existsSyncFn = deps.existsSyncFn ?? existsSync4;
5023
+ const existsSyncFn = deps.existsSyncFn ?? existsSync5;
4886
5024
  const execSyncFn = deps.execSyncFn ?? execSync;
4887
5025
  const gitDir = path6.join(workingDirectory, ".git");
4888
5026
  if (existsSyncFn(gitDir)) return;
@@ -4900,7 +5038,7 @@ function isWindowsSandboxRunner(commandPath) {
4900
5038
  return path6.basename(commandPath).toLowerCase().startsWith("codex-command-runner");
4901
5039
  }
4902
5040
  function resolveWindowsNpmCodexEntry(deps = {}) {
4903
- const existsSyncFn = deps.existsSyncFn ?? existsSync4;
5041
+ const existsSyncFn = deps.existsSyncFn ?? existsSync5;
4904
5042
  const execFileSyncFn = deps.execFileSyncFn ?? execFileSync2;
4905
5043
  const env = deps.env ?? process.env;
4906
5044
  const winPath = path6.win32;
@@ -4922,7 +5060,7 @@ function resolveWindowsNpmCodexEntry(deps = {}) {
4922
5060
  return null;
4923
5061
  }
4924
5062
  function resolveWindowsCodexDesktopEntry(deps = {}) {
4925
- const existsSyncFn = deps.existsSyncFn ?? existsSync4;
5063
+ const existsSyncFn = deps.existsSyncFn ?? existsSync5;
4926
5064
  const env = deps.env ?? process.env;
4927
5065
  const homeDir = deps.homeDir;
4928
5066
  const winPath = path6.win32;
@@ -5037,7 +5175,7 @@ var CodexDriver = class {
5037
5175
  threadParams.config = { model_reasoning_effort: launchRuntimeFields.reasoningEffort };
5038
5176
  }
5039
5177
  if (launchRuntimeFields.mode.kind === "fast") {
5040
- threadParams.serviceTier = "priority";
5178
+ threadParams.serviceTier = "fast";
5041
5179
  }
5042
5180
  if (ctx.config.sessionId) {
5043
5181
  return {
@@ -5237,10 +5375,11 @@ var ANTIGRAVITY_ENV_OVERRIDES = {
5237
5375
  SSH_TTY: void 0
5238
5376
  };
5239
5377
  function resolveAntigravitySpawn(commandArgs, deps = {}) {
5378
+ const command = resolveCommandOnPath("agy", deps) ?? "agy";
5240
5379
  return {
5241
- command: resolveCommandOnPath("agy", deps) ?? "agy",
5380
+ command,
5242
5381
  args: commandArgs,
5243
- shell: false
5382
+ shell: requiresWindowsShell(command, deps.platform)
5244
5383
  };
5245
5384
  }
5246
5385
  function buildAntigravityArgs(ctx) {
@@ -5664,7 +5803,7 @@ function runCursorModelsCommand() {
5664
5803
 
5665
5804
  // src/drivers/gemini.ts
5666
5805
  import { execFileSync as execFileSync3, spawn as spawn6 } from "child_process";
5667
- import { existsSync as existsSync5 } from "fs";
5806
+ import { existsSync as existsSync6 } from "fs";
5668
5807
  import path7 from "path";
5669
5808
  async function buildGeminiSpawnEnv(ctx, platform = process.platform) {
5670
5809
  const { spawnEnv } = await prepareCliTransport(ctx, { NO_COLOR: "1" }, platform);
@@ -5707,7 +5846,7 @@ function resolveGeminiSpawn(commandArgs, deps = {}) {
5707
5846
  return { command: resolveCommandOnPath("gemini", deps) ?? "gemini", args: commandArgs };
5708
5847
  }
5709
5848
  const execFileSyncFn = deps.execFileSyncFn ?? execFileSync3;
5710
- const existsSyncFn = deps.existsSyncFn ?? existsSync5;
5849
+ const existsSyncFn = deps.existsSyncFn ?? existsSync6;
5711
5850
  const env = deps.env ?? process.env;
5712
5851
  const winPath = path7.win32;
5713
5852
  let geminiEntry = null;
@@ -5845,7 +5984,7 @@ var GeminiDriver = class {
5845
5984
  // src/drivers/kimi.ts
5846
5985
  import { randomUUID as randomUUID2 } from "crypto";
5847
5986
  import { spawn as spawn7 } from "child_process";
5848
- import { existsSync as existsSync6, readFileSync as readFileSync3, writeFileSync as writeFileSync3 } from "fs";
5987
+ import { existsSync as existsSync7, readFileSync as readFileSync3, writeFileSync as writeFileSync3 } from "fs";
5849
5988
  import os4 from "os";
5850
5989
  import path8 from "path";
5851
5990
  var KIMI_WIRE_PROTOCOL_VERSION = "1.3";
@@ -5896,7 +6035,7 @@ var KimiDriver = class {
5896
6035
  this.promptRequestId = randomUUID2();
5897
6036
  const systemPromptPath = path8.join(ctx.workingDirectory, KIMI_SYSTEM_PROMPT_FILE);
5898
6037
  const agentFilePath = path8.join(ctx.workingDirectory, KIMI_AGENT_FILE);
5899
- if (!isResume || !existsSync6(systemPromptPath)) {
6038
+ if (!isResume || !existsSync7(systemPromptPath)) {
5900
6039
  writeFileSync3(systemPromptPath, ctx.prompt, "utf8");
5901
6040
  }
5902
6041
  writeFileSync3(agentFilePath, [
@@ -6069,7 +6208,7 @@ function detectKimiModels(home = os4.homedir()) {
6069
6208
 
6070
6209
  // src/drivers/opencode.ts
6071
6210
  import { spawn as spawn8, spawnSync as spawnSync2 } from "child_process";
6072
- import { existsSync as existsSync7, readFileSync as readFileSync4 } from "fs";
6211
+ import { existsSync as existsSync8, readFileSync as readFileSync4 } from "fs";
6073
6212
  import os5 from "os";
6074
6213
  import path9 from "path";
6075
6214
  var SLOCK_AGENT_NAME = "slock";
@@ -6317,7 +6456,7 @@ function openCodeSpecForEntry(entry, commandArgs) {
6317
6456
  return { command: process.execPath, args: [entry, ...commandArgs], shell: false };
6318
6457
  }
6319
6458
  function resolveWindowsOpenCodePackageEntry(commandPath, deps = {}) {
6320
- const existsSyncFn = deps.existsSyncFn ?? existsSync7;
6459
+ const existsSyncFn = deps.existsSyncFn ?? existsSync8;
6321
6460
  const execFileSyncFn = deps.execFileSyncFn;
6322
6461
  const env = deps.env ?? process.env;
6323
6462
  const winPath = path9.win32;
@@ -6545,7 +6684,7 @@ var OpenCodeDriver = class {
6545
6684
  // src/drivers/pi.ts
6546
6685
  import { randomUUID as randomUUID3 } from "crypto";
6547
6686
  import { EventEmitter } from "events";
6548
- import { mkdirSync as mkdirSync3, readdirSync } from "fs";
6687
+ import { mkdirSync as mkdirSync3, readdirSync as readdirSync2 } from "fs";
6549
6688
  import path10 from "path";
6550
6689
  import {
6551
6690
  AuthStorage,
@@ -6589,7 +6728,7 @@ function resolvePiModelFromRegistry(modelId, modelRegistry) {
6589
6728
  function findPiSessionFile(sessionDir, sessionId) {
6590
6729
  let entries;
6591
6730
  try {
6592
- entries = readdirSync(sessionDir);
6731
+ entries = readdirSync2(sessionDir);
6593
6732
  } catch {
6594
6733
  return null;
6595
6734
  }
@@ -7819,7 +7958,7 @@ function findSessionJsonl(root, predicate) {
7819
7958
  if (depth < 0 || visited >= maxEntries) return null;
7820
7959
  let entries;
7821
7960
  try {
7822
- entries = readdirSync2(dir, { withFileTypes: true }).sort((a, b) => b.name.localeCompare(a.name));
7961
+ entries = readdirSync3(dir, { withFileTypes: true }).sort((a, b) => b.name.localeCompare(a.name));
7823
7962
  } catch {
7824
7963
  return null;
7825
7964
  }
@@ -13428,7 +13567,7 @@ function acquireDaemonMachineLock(options) {
13428
13567
  }
13429
13568
 
13430
13569
  // src/localTraceSink.ts
13431
- import { appendFileSync, mkdirSync as mkdirSync6, readdirSync as readdirSync3, rmSync as rmSync4, statSync as statSync3, writeFileSync as writeFileSync6 } from "fs";
13570
+ import { appendFileSync, mkdirSync as mkdirSync6, readdirSync as readdirSync4, rmSync as rmSync4, statSync as statSync3, writeFileSync as writeFileSync6 } from "fs";
13432
13571
  import path14 from "path";
13433
13572
  var DEFAULT_MAX_FILE_BYTES = 5 * 1024 * 1024;
13434
13573
  var DEFAULT_MAX_FILE_AGE_MS = 5 * 60 * 1e3;
@@ -13507,7 +13646,7 @@ var LocalRotatingTraceSink = class {
13507
13646
  }
13508
13647
  }
13509
13648
  pruneOldFiles() {
13510
- const files = readdirSync3(this.traceDir).filter((name) => name.startsWith("daemon-trace-") && name.endsWith(".jsonl")).sort();
13649
+ const files = readdirSync4(this.traceDir).filter((name) => name.startsWith("daemon-trace-") && name.endsWith(".jsonl")).sort();
13511
13650
  const excess = files.length - this.maxFiles;
13512
13651
  if (excess <= 0) return;
13513
13652
  for (const file of files.slice(0, excess)) {
@@ -14166,7 +14305,7 @@ function resolveSlockCliPathOrEmpty(moduleUrl = import.meta.url) {
14166
14305
  }
14167
14306
  async function runBundledSlockCli(argv) {
14168
14307
  process.argv = [process.execPath, "slock", ...argv];
14169
- await import("./dist-CLQ4P4XZ.js");
14308
+ await import("./dist-JVLCJ2QO.js");
14170
14309
  }
14171
14310
  function detectRuntimes(tracer = noopTracer) {
14172
14311
  const ids = [];
@@ -14302,6 +14441,11 @@ var DaemonCore = class {
14302
14441
  computerVersion;
14303
14442
  slockCliPath;
14304
14443
  slockHome;
14444
+ agentsDataDir;
14445
+ // One-shot guard: rewrite stale per-agent opencli wrappers to the current
14446
+ // self-healing form on the first connect of this daemon process (a SEA
14447
+ // computer switch / daemon upgrade restarts the daemon → triggers this).
14448
+ opencliWrappersRegenerated = false;
14305
14449
  runtimeDetector;
14306
14450
  agentManager;
14307
14451
  connection;
@@ -14328,8 +14472,9 @@ var DaemonCore = class {
14328
14472
  onFire: (job) => this.onReminderFire(job)
14329
14473
  });
14330
14474
  let connection;
14475
+ this.agentsDataDir = options.dataDir ?? resolveSlockHomePath("agents", this.slockHome);
14331
14476
  const agentManagerOptions = {
14332
- dataDir: options.dataDir ?? resolveSlockHomePath("agents", this.slockHome),
14477
+ dataDir: this.agentsDataDir,
14333
14478
  serverUrl: options.serverUrl,
14334
14479
  defaultAgentEnvVarsProvider: options.defaultAgentEnvVarsProvider,
14335
14480
  slockCliPath: this.slockCliPath,
@@ -14859,6 +15004,17 @@ var DaemonCore = class {
14859
15004
  const { ids: runtimes, versions: runtimeVersions } = this.runtimeDetector();
14860
15005
  const runtimeInfo = runtimes.map((id) => runtimeVersions[id] ? `${id} (${runtimeVersions[id]})` : id);
14861
15006
  logger.info(`[Daemon] Detected runtimes: ${runtimeInfo.join(", ") || "none"}`);
15007
+ if (!this.opencliWrappersRegenerated) {
15008
+ this.opencliWrappersRegenerated = true;
15009
+ try {
15010
+ const { scanned, rewritten } = regenerateExistingOpencliWrappers(this.agentsDataDir);
15011
+ if (scanned > 0) {
15012
+ logger.info(`[Daemon] Refreshed ${rewritten}/${scanned} opencli wrapper(s) to current self-healing form`);
15013
+ }
15014
+ } catch (err) {
15015
+ logger.warn(`[Daemon] opencli wrapper refresh skipped: ${err instanceof Error ? err.message : String(err)}`);
15016
+ }
15017
+ }
14862
15018
  const runningAgentIds = this.agentManager.getRunningAgentIds();
14863
15019
  const idleAgentSessions = this.agentManager.getIdleAgentSessionIds();
14864
15020
  const runtimeProfileReports = this.agentManager.getAgentRuntimeProfileReports();
package/dist/cli/index.js CHANGED
@@ -1302,7 +1302,6 @@ function formatVerificationHandoff(action) {
1302
1302
  const mins = Math.max(0, Math.floor(action.expiresInSeconds / 60));
1303
1303
  if (action.verificationUriComplete) {
1304
1304
  return `Open this link to approve (code pre-filled): ${action.verificationUriComplete}
1305
- (fallback) Open ${action.verificationUri} and enter code ${action.userCode}.
1306
1305
  Expires in ~${mins}m.
1307
1306
  `;
1308
1307
  }
@@ -1317,8 +1316,6 @@ function formatStartHandoff(authorization, options, paths) {
1317
1316
  `;
1318
1317
  if (authorization.verificationUriComplete) {
1319
1318
  out += ` Open this link (code pre-filled): ${authorization.verificationUriComplete}
1320
- `;
1321
- out += ` (fallback) Open ${authorization.verificationUri} and enter code ${authorization.userCode}.
1322
1319
  `;
1323
1320
  } else {
1324
1321
  out += ` Open ${authorization.verificationUri} and enter code ${authorization.userCode}.
@@ -15815,11 +15812,20 @@ var RUNTIME_MODELS = {
15815
15812
  };
15816
15813
  var PLAN_CONFIG = {
15817
15814
  free: {
15818
- displayName: "Hobby",
15815
+ displayName: "Free",
15819
15816
  limits: { maxMachines: 2, maxAgents: 5, maxChannels: 5, messageHistoryDays: 30, includedAgents: 5 },
15820
15817
  comingSoon: false,
15821
15818
  price: 0,
15822
- extraAgentPrice: 0
15819
+ extraAgentPrice: 0,
15820
+ displayFeatures: [
15821
+ "Channels",
15822
+ "Tasks",
15823
+ "Unlimited agents on your own computers",
15824
+ "Agent Reminders",
15825
+ "Basic observability",
15826
+ "30 days of message history",
15827
+ "100 MB file uploads/month"
15828
+ ]
15823
15829
  },
15824
15830
  founder: {
15825
15831
  displayName: "Founder",
@@ -15832,18 +15838,35 @@ var PLAN_CONFIG = {
15832
15838
  var DISPLAY_PLAN_CONFIG = {
15833
15839
  free: PLAN_CONFIG.free,
15834
15840
  pro: {
15835
- displayName: "Team",
15836
- limits: { maxMachines: 8, maxAgents: 40, maxChannels: 20, messageHistoryDays: -1, includedAgents: 40 },
15837
- comingSoon: true,
15841
+ displayName: "Pro",
15842
+ limits: { maxMachines: -1, maxAgents: 10, maxChannels: -1, messageHistoryDays: -1, includedAgents: 10 },
15843
+ comingSoon: false,
15838
15844
  price: 20,
15839
- extraAgentPrice: 0
15845
+ priceCadence: "/ seat pack / month",
15846
+ extraAgentPrice: 0,
15847
+ displayFeatures: [
15848
+ "1 human seat + 10 agent seats per Pro Seat Pack",
15849
+ "Unlimited message history",
15850
+ "Higher file upload limits",
15851
+ "Joint Channels",
15852
+ "More professional features coming soon"
15853
+ ],
15854
+ displayNote: "$17.60 / seat pack / month when billed yearly"
15840
15855
  },
15841
- max: {
15842
- displayName: "Business",
15843
- limits: { maxMachines: 40, maxAgents: 200, maxChannels: -1, messageHistoryDays: -1, includedAgents: 200 },
15844
- comingSoon: true,
15845
- price: 200,
15846
- extraAgentPrice: 0
15856
+ enterprise: {
15857
+ displayName: "Enterprise",
15858
+ limits: { maxMachines: -1, maxAgents: -1, maxChannels: -1, messageHistoryDays: -1, includedAgents: -1 },
15859
+ comingSoon: false,
15860
+ price: 0,
15861
+ priceLabel: "Coming soon",
15862
+ priceCadence: null,
15863
+ extraAgentPrice: 0,
15864
+ displayFeatures: [
15865
+ "Custom commercial terms",
15866
+ "Security and compliance review",
15867
+ "Dedicated support and onboarding",
15868
+ "Custom deployment planning"
15869
+ ]
15847
15870
  }
15848
15871
  };
15849
15872
 
package/dist/core.js CHANGED
@@ -11,7 +11,7 @@ import {
11
11
  runBundledSlockCli,
12
12
  scanWorkspaceDirectories,
13
13
  subscribeDaemonLogs
14
- } from "./chunk-FTEZQN4P.js";
14
+ } from "./chunk-65UFKNJJ.js";
15
15
  export {
16
16
  DAEMON_CLI_USAGE,
17
17
  DaemonCore,
@@ -1289,7 +1289,6 @@ function formatVerificationHandoff(action) {
1289
1289
  const mins = Math.max(0, Math.floor(action.expiresInSeconds / 60));
1290
1290
  if (action.verificationUriComplete) {
1291
1291
  return `Open this link to approve (code pre-filled): ${action.verificationUriComplete}
1292
- (fallback) Open ${action.verificationUri} and enter code ${action.userCode}.
1293
1292
  Expires in ~${mins}m.
1294
1293
  `;
1295
1294
  }
@@ -1304,8 +1303,6 @@ function formatStartHandoff(authorization, options, paths) {
1304
1303
  `;
1305
1304
  if (authorization.verificationUriComplete) {
1306
1305
  out += ` Open this link (code pre-filled): ${authorization.verificationUriComplete}
1307
- `;
1308
- out += ` (fallback) Open ${authorization.verificationUri} and enter code ${authorization.userCode}.
1309
1306
  `;
1310
1307
  } else {
1311
1308
  out += ` Open ${authorization.verificationUri} and enter code ${authorization.userCode}.
@@ -15621,11 +15618,20 @@ var RUNTIME_MODELS = {
15621
15618
  };
15622
15619
  var PLAN_CONFIG = {
15623
15620
  free: {
15624
- displayName: "Hobby",
15621
+ displayName: "Free",
15625
15622
  limits: { maxMachines: 2, maxAgents: 5, maxChannels: 5, messageHistoryDays: 30, includedAgents: 5 },
15626
15623
  comingSoon: false,
15627
15624
  price: 0,
15628
- extraAgentPrice: 0
15625
+ extraAgentPrice: 0,
15626
+ displayFeatures: [
15627
+ "Channels",
15628
+ "Tasks",
15629
+ "Unlimited agents on your own computers",
15630
+ "Agent Reminders",
15631
+ "Basic observability",
15632
+ "30 days of message history",
15633
+ "100 MB file uploads/month"
15634
+ ]
15629
15635
  },
15630
15636
  founder: {
15631
15637
  displayName: "Founder",
@@ -15638,18 +15644,35 @@ var PLAN_CONFIG = {
15638
15644
  var DISPLAY_PLAN_CONFIG = {
15639
15645
  free: PLAN_CONFIG.free,
15640
15646
  pro: {
15641
- displayName: "Team",
15642
- limits: { maxMachines: 8, maxAgents: 40, maxChannels: 20, messageHistoryDays: -1, includedAgents: 40 },
15643
- comingSoon: true,
15647
+ displayName: "Pro",
15648
+ limits: { maxMachines: -1, maxAgents: 10, maxChannels: -1, messageHistoryDays: -1, includedAgents: 10 },
15649
+ comingSoon: false,
15644
15650
  price: 20,
15645
- extraAgentPrice: 0
15651
+ priceCadence: "/ seat pack / month",
15652
+ extraAgentPrice: 0,
15653
+ displayFeatures: [
15654
+ "1 human seat + 10 agent seats per Pro Seat Pack",
15655
+ "Unlimited message history",
15656
+ "Higher file upload limits",
15657
+ "Joint Channels",
15658
+ "More professional features coming soon"
15659
+ ],
15660
+ displayNote: "$17.60 / seat pack / month when billed yearly"
15646
15661
  },
15647
- max: {
15648
- displayName: "Business",
15649
- limits: { maxMachines: 40, maxAgents: 200, maxChannels: -1, messageHistoryDays: -1, includedAgents: 200 },
15650
- comingSoon: true,
15651
- price: 200,
15652
- extraAgentPrice: 0
15662
+ enterprise: {
15663
+ displayName: "Enterprise",
15664
+ limits: { maxMachines: -1, maxAgents: -1, maxChannels: -1, messageHistoryDays: -1, includedAgents: -1 },
15665
+ comingSoon: false,
15666
+ price: 0,
15667
+ priceLabel: "Coming soon",
15668
+ priceCadence: null,
15669
+ extraAgentPrice: 0,
15670
+ displayFeatures: [
15671
+ "Custom commercial terms",
15672
+ "Security and compliance review",
15673
+ "Dedicated support and onboarding",
15674
+ "Custom deployment planning"
15675
+ ]
15653
15676
  }
15654
15677
  };
15655
15678
  var AGENT_COMMS_PROTOCOL_VERSION = "agent-comms-core.v1";
package/dist/index.js CHANGED
@@ -3,7 +3,7 @@ import {
3
3
  DAEMON_CLI_USAGE,
4
4
  DaemonCore,
5
5
  parseDaemonCliArgs
6
- } from "./chunk-FTEZQN4P.js";
6
+ } from "./chunk-65UFKNJJ.js";
7
7
 
8
8
  // src/index.ts
9
9
  var parsedArgs = parseDaemonCliArgs(process.argv.slice(2));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@botiverse/raft-daemon",
3
- "version": "0.59.0",
3
+ "version": "0.60.0",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "raft-daemon": "dist/raft-daemon.js",
@@ -43,8 +43,8 @@
43
43
  "release:alpha": "npm version prerelease --preid=alpha --no-git-tag-version && cd ../.. && pnpm install --lockfile-only && git add packages/daemon/package.json pnpm-lock.yaml && git commit -m \"chore: bump @botiverse/raft-daemon to v$(node -p \"require('./packages/daemon/package.json').version\")\" && git tag daemon-v$(node -p \"require('./packages/daemon/package.json').version\") && git push && git push --tags"
44
44
  },
45
45
  "dependencies": {
46
- "@earendil-works/pi-ai": "0.79.1",
47
- "@earendil-works/pi-coding-agent": "0.79.1",
46
+ "@earendil-works/pi-ai": "0.79.3",
47
+ "@earendil-works/pi-coding-agent": "0.79.3",
48
48
  "@jackwener/opencli": "^1.8.3",
49
49
  "@modelcontextprotocol/sdk": "^1.29.0",
50
50
  "commander": "^12.1.0",