@botiverse/raft-daemon 0.59.0 → 0.60.0-play.20260615055221

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
 
@@ -2096,6 +2130,19 @@ function listLegacySlockStatePaths(slockHome = resolveSlockHome(), homeDir = os.
2096
2130
  return candidates.filter((candidate) => existsSync(candidate.path));
2097
2131
  }
2098
2132
 
2133
+ // src/authEnv.ts
2134
+ var DAEMON_API_KEY_ENV = "SLOCK_MACHINE_API_KEY";
2135
+ var SLOCK_AGENT_TOKEN_ENV = "SLOCK_AGENT_TOKEN";
2136
+ function scrubDaemonAuthEnv(env) {
2137
+ delete env[DAEMON_API_KEY_ENV];
2138
+ return env;
2139
+ }
2140
+ function scrubDaemonChildEnv(env) {
2141
+ delete env[DAEMON_API_KEY_ENV];
2142
+ delete env[SLOCK_AGENT_TOKEN_ENV];
2143
+ return env;
2144
+ }
2145
+
2099
2146
  // src/agentCredentialProxy.ts
2100
2147
  import { randomBytes } from "crypto";
2101
2148
  import http from "http";
@@ -3583,8 +3630,36 @@ var LOOPBACK_NO_PROXY = "127.0.0.1,localhost";
3583
3630
  var CLI_TRANSPORT_TRACE_DIR_ENV = "SLOCK_CLI_TRANSPORT_TRACE_DIR";
3584
3631
  var safePathPart = (value) => value.replace(/[^a-zA-Z0-9_.-]/g, "_");
3585
3632
  var RAW_CREDENTIAL_ENV_DENYLIST = [
3586
- "SLOCK_AGENT_CREDENTIAL_KEY"
3633
+ "SLOCK_AGENT_TOKEN",
3634
+ "SLOCK_AGENT_CREDENTIAL_KEY",
3635
+ "SLOCK_AGENT_CREDENTIAL_KEY_FILE"
3587
3636
  ];
3637
+ function deriveCliFallbackCandidates(cliPath) {
3638
+ if (!cliPath || cliPath === "__cli") return [];
3639
+ const normalized = cliPath.split(path2.sep).join("/");
3640
+ const marker = "/node_modules/";
3641
+ const idx = normalized.indexOf(marker);
3642
+ if (idx === -1) return [];
3643
+ const globalRoot = cliPath.slice(0, idx + marker.length - 1);
3644
+ const tail = path2.join("dist", "cli", "index.js");
3645
+ return [
3646
+ path2.join(globalRoot, "@botiverse", "raft-daemon", tail),
3647
+ path2.join(globalRoot, "@slock-ai", "daemon", tail)
3648
+ ].filter((candidate) => candidate !== cliPath);
3649
+ }
3650
+ function deriveOpencliFallbackCandidates(binPath) {
3651
+ if (!binPath) return [];
3652
+ const normalized = binPath.split(path2.sep).join("/");
3653
+ const marker = "/node_modules/";
3654
+ const first = normalized.indexOf(marker);
3655
+ if (first === -1) return [];
3656
+ const pkgMarker = "/node_modules/@jackwener/opencli/";
3657
+ const last = normalized.lastIndexOf(pkgMarker);
3658
+ if (last === -1) return [];
3659
+ const suffix = normalized.slice(last + pkgMarker.length);
3660
+ const candidate = path2.join(binPath.slice(0, first + marker.length - 1), "@jackwener", "opencli", ...suffix.split("/"));
3661
+ return candidate === binPath ? [] : [candidate];
3662
+ }
3588
3663
  var cachedOpencliBinPath;
3589
3664
  function resolveOpencliBinPath() {
3590
3665
  if (cachedOpencliBinPath !== void 0) return cachedOpencliBinPath;
@@ -3619,6 +3694,64 @@ function resolveOpencliBinPath() {
3619
3694
  return null;
3620
3695
  }
3621
3696
  }
3697
+ function writeOpencliWrapper(slockDir, opencliBinPath, platform = process.platform) {
3698
+ const fallbacks = deriveOpencliFallbackCandidates(opencliBinPath);
3699
+ let binPath = opencliBinPath;
3700
+ if (!existsSync2(binPath)) {
3701
+ const fallback = fallbacks.find((candidate) => existsSync2(candidate));
3702
+ if (fallback) binPath = fallback;
3703
+ }
3704
+ const posixFallbackBlock = fallbacks.length === 0 ? "" : `if [ ! -e "$OPENCLI_BIN" ]; then
3705
+ ${fallbacks.map((candidate, i) => ` ${i === 0 ? "if" : "elif"} [ -e ${shellSingleQuote(candidate)} ]; then OPENCLI_BIN=${shellSingleQuote(candidate)};`).join("\n")}
3706
+ fi
3707
+ fi
3708
+ `;
3709
+ writeFileSync(
3710
+ path2.join(slockDir, "opencli"),
3711
+ `#!/usr/bin/env bash
3712
+ OPENCLI_BIN=${shellSingleQuote(binPath)}
3713
+ ${posixFallbackBlock}exec ${shellSingleQuote(process.execPath)} "$OPENCLI_BIN" "$@"
3714
+ `,
3715
+ { mode: 493 }
3716
+ );
3717
+ if (platform === "win32") {
3718
+ const opencliCmdBody = [
3719
+ "@echo off",
3720
+ "set PYTHONIOENCODING=utf-8",
3721
+ "set PYTHONUTF8=1",
3722
+ "set LANG=C.UTF-8",
3723
+ "set LC_ALL=C.UTF-8",
3724
+ "chcp 65001 >NUL 2>NUL",
3725
+ `set "OPENCLI_BIN=${binPath}"`,
3726
+ ...fallbacks.map((candidate) => `if not exist "%OPENCLI_BIN%" set "OPENCLI_BIN=${candidate}"`),
3727
+ `"${process.execPath}" "%OPENCLI_BIN%" %*`,
3728
+ ""
3729
+ ].join("\r\n") + "\r\n";
3730
+ writeFileSync(path2.join(slockDir, "opencli.cmd"), opencliCmdBody);
3731
+ }
3732
+ }
3733
+ function regenerateExistingOpencliWrappers(agentsRoot, platform = process.platform, opencliBinPath = resolveOpencliBinPath()) {
3734
+ if (!opencliBinPath) return { scanned: 0, rewritten: 0 };
3735
+ let entries;
3736
+ try {
3737
+ entries = readdirSync(agentsRoot);
3738
+ } catch {
3739
+ return { scanned: 0, rewritten: 0 };
3740
+ }
3741
+ let scanned = 0;
3742
+ let rewritten = 0;
3743
+ for (const entry of entries) {
3744
+ const slockDir = path2.join(agentsRoot, entry, ".slock");
3745
+ if (!existsSync2(path2.join(slockDir, "opencli"))) continue;
3746
+ scanned++;
3747
+ try {
3748
+ writeOpencliWrapper(slockDir, opencliBinPath, platform);
3749
+ rewritten++;
3750
+ } catch {
3751
+ }
3752
+ }
3753
+ return { scanned, rewritten };
3754
+ }
3622
3755
  function windowsUtf8Env() {
3623
3756
  return {
3624
3757
  PYTHONIOENCODING: "utf-8",
@@ -3676,6 +3809,21 @@ async function prepareCliTransport(ctx, extraEnv = {}, platform = process.platfo
3676
3809
  if (!ctx.slockCliPath) {
3677
3810
  throw new Error(`${ctx.config.runtime} driver: slockCliPath is required (daemon must inject it)`);
3678
3811
  }
3812
+ let cliPath = ctx.slockCliPath;
3813
+ const cliFallbackCandidates = deriveCliFallbackCandidates(cliPath);
3814
+ if (cliPath !== "__cli" && !existsSync2(cliPath)) {
3815
+ const fallback = cliFallbackCandidates.find((candidate) => existsSync2(candidate));
3816
+ if (fallback) {
3817
+ console.error(
3818
+ `[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.`
3819
+ );
3820
+ cliPath = fallback;
3821
+ } else {
3822
+ console.error(
3823
+ `[cliTransport] bundled CLI missing at ${cliPath} and no global fallback found; wrappers will be broken until the daemon is restarted from a valid install.`
3824
+ );
3825
+ }
3826
+ }
3679
3827
  const slockDir = path2.join(ctx.workingDirectory, ".slock");
3680
3828
  mkdirSync(slockDir, { recursive: true });
3681
3829
  const slockHome = resolveSlockHome();
@@ -3704,9 +3852,15 @@ async function prepareCliTransport(ctx, extraEnv = {}, platform = process.platfo
3704
3852
  const posixWrapper = path2.join(slockDir, "slock");
3705
3853
  const posixRaftWrapper = path2.join(slockDir, "raft");
3706
3854
  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)} ` : "";
3855
+ const posixCliFallbackBlock = cliPath === "__cli" || cliFallbackCandidates.length === 0 ? "" : `if [ ! -e "$SLOCK_CLI" ]; then
3856
+ ${cliFallbackCandidates.map((candidate, i) => ` ${i === 0 ? "if" : "elif"} [ -e ${shellSingleQuote(candidate)} ]; then SLOCK_CLI=${shellSingleQuote(candidate)};`).join("\n")}
3857
+ fi
3858
+ fi
3859
+ `;
3707
3860
  const posixBody = `#!/usr/bin/env bash
3708
3861
  ${posixLoopbackNoProxyPrelude()}
3709
- ${posixCredentialPrefix}exec ${shellSingleQuote(process.execPath)} ${shellSingleQuote(ctx.slockCliPath)} "$@"
3862
+ SLOCK_CLI=${shellSingleQuote(cliPath)}
3863
+ ${posixCliFallbackBlock}${posixCredentialPrefix}exec ${shellSingleQuote(process.execPath)} "$SLOCK_CLI" "$@"
3710
3864
  `;
3711
3865
  writeFileSync(posixWrapper, posixBody, { mode: 493 });
3712
3866
  writeFileSync(posixRaftWrapper, posixBody, { mode: 493 });
@@ -3717,6 +3871,7 @@ ${posixCredentialPrefix}exec ${shellSingleQuote(process.execPath)} ${shellSingle
3717
3871
  set "SLOCK_AGENT_PROXY_TOKEN_FILE=${agentCredentialProxyTokenFile}"\r
3718
3872
  set "SLOCK_AGENT_ACTIVE_CAPABILITIES=${DEFAULT_ACTIVE_CAPABILITIES}"\r
3719
3873
  ` : "";
3874
+ const cmdCliFallbackLines = cliPath === "__cli" ? [] : cliFallbackCandidates.map((candidate) => `if not exist "%SLOCK_CLI%" set "SLOCK_CLI=${candidate}"`);
3720
3875
  const cmdBody = [
3721
3876
  "@echo off",
3722
3877
  "set PYTHONIOENCODING=utf-8",
@@ -3726,7 +3881,9 @@ set "SLOCK_AGENT_ACTIVE_CAPABILITIES=${DEFAULT_ACTIVE_CAPABILITIES}"\r
3726
3881
  "chcp 65001 >NUL 2>NUL",
3727
3882
  ...cmdLoopbackNoProxyLines(),
3728
3883
  cmdCredentialLine.trimEnd(),
3729
- `"${process.execPath}" "${ctx.slockCliPath}" %*`,
3884
+ `set "SLOCK_CLI=${cliPath}"`,
3885
+ ...cmdCliFallbackLines,
3886
+ `"${process.execPath}" "%SLOCK_CLI%" %*`,
3730
3887
  ""
3731
3888
  ].filter((line) => line.length > 0).join("\r\n") + "\r\n";
3732
3889
  writeFileSync(cmdWrapper, cmdBody);
@@ -3750,7 +3907,14 @@ set "SLOCK_AGENT_ACTIVE_CAPABILITIES=${DEFAULT_ACTIVE_CAPABILITIES}"\r
3750
3907
  ...powershellLoopbackNoProxyLines(),
3751
3908
  ...psCredentialLines,
3752
3909
  `$node = ${powershellSingleQuote(process.execPath)}`,
3753
- `$cli = ${powershellSingleQuote(ctx.slockCliPath)}`,
3910
+ `$cli = ${powershellSingleQuote(cliPath)}`,
3911
+ ...cliPath === "__cli" || cliFallbackCandidates.length === 0 ? [] : [
3912
+ "if (-not (Test-Path $cli)) {",
3913
+ ` foreach ($candidate in @(${cliFallbackCandidates.map(powershellSingleQuote).join(", ")})) {`,
3914
+ " if (Test-Path $candidate) { $cli = $candidate; break }",
3915
+ " }",
3916
+ "}"
3917
+ ],
3754
3918
  "if ($MyInvocation.ExpectingInput) {",
3755
3919
  " $input | & $node $cli @args",
3756
3920
  "} else {",
@@ -3764,28 +3928,7 @@ set "SLOCK_AGENT_ACTIVE_CAPABILITIES=${DEFAULT_ACTIVE_CAPABILITIES}"\r
3764
3928
  }
3765
3929
  const opencliBinPath = resolveOpencliBinPath();
3766
3930
  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
- }
3931
+ writeOpencliWrapper(slockDir, opencliBinPath, platform);
3789
3932
  }
3790
3933
  const wrapperPath = platform === "win32" ? path2.join(slockDir, "slock.cmd") : posixWrapper;
3791
3934
  const launchRuntimeFields = runtimeConfigToLaunchFields(ctx.config);
@@ -3804,7 +3947,7 @@ exec ${shellSingleQuote(process.execPath)} ${shellSingleQuote(opencliBinPath)} "
3804
3947
  ...agentCredentialProxy ? {} : { SLOCK_AGENT_TOKEN_FILE: tokenFile },
3805
3948
  PATH: `${slockDir}${path2.delimiter}${process.env.PATH ?? ""}`
3806
3949
  };
3807
- delete spawnEnv.SLOCK_AGENT_TOKEN;
3950
+ scrubDaemonChildEnv(spawnEnv);
3808
3951
  for (const key of RAW_CREDENTIAL_ENV_DENYLIST) {
3809
3952
  delete spawnEnv[key];
3810
3953
  }
@@ -4079,7 +4222,7 @@ import path4 from "path";
4079
4222
 
4080
4223
  // src/drivers/probe.ts
4081
4224
  import { execFileSync } from "child_process";
4082
- import { existsSync as existsSync2 } from "fs";
4225
+ import { existsSync as existsSync3 } from "fs";
4083
4226
  import path3 from "path";
4084
4227
  function normalizeExecOutput(raw) {
4085
4228
  return Buffer.isBuffer(raw) ? raw.toString("utf8") : String(raw ?? "");
@@ -4231,11 +4374,17 @@ function resolveCommandOnWindows(command, env, execFileSyncFn, existsSyncFn) {
4231
4374
  return null;
4232
4375
  }
4233
4376
  }
4377
+ function requiresWindowsShell(command, platform = process.platform) {
4378
+ if (platform !== "win32") return false;
4379
+ if (!command) return false;
4380
+ const lower = command.toLowerCase();
4381
+ return lower.endsWith(".cmd") || lower.endsWith(".bat");
4382
+ }
4234
4383
  function resolveCommandOnPath(command, deps = {}) {
4235
4384
  const platform = deps.platform ?? process.platform;
4236
- const env = withWindowsUserEnvironment(deps.env ?? process.env, deps);
4385
+ const env = scrubDaemonChildEnv({ ...withWindowsUserEnvironment(deps.env ?? process.env, deps) });
4237
4386
  const execFileSyncFn = deps.execFileSyncFn ?? execFileSync;
4238
- const existsSyncFn = deps.existsSyncFn ?? existsSync2;
4387
+ const existsSyncFn = deps.existsSyncFn ?? existsSync3;
4239
4388
  if (platform === "win32") {
4240
4389
  return resolveCommandOnWindows(command, env, execFileSyncFn, existsSyncFn);
4241
4390
  }
@@ -4252,14 +4401,14 @@ function resolveCommandOnPath(command, deps = {}) {
4252
4401
  }
4253
4402
  }
4254
4403
  function firstExistingPath(candidates, deps = {}) {
4255
- const exists = deps.existsSyncFn ?? existsSync2;
4404
+ const exists = deps.existsSyncFn ?? existsSync3;
4256
4405
  for (const candidate of candidates) {
4257
4406
  if (exists(candidate)) return candidate;
4258
4407
  }
4259
4408
  return null;
4260
4409
  }
4261
4410
  function readCommandVersion(command, args = [], deps = {}) {
4262
- const env = withWindowsUserEnvironment(deps.env ?? process.env, deps);
4411
+ const env = scrubDaemonChildEnv({ ...withWindowsUserEnvironment(deps.env ?? process.env, deps) });
4263
4412
  const execFileSyncFn = deps.execFileSyncFn ?? execFileSync;
4264
4413
  try {
4265
4414
  const output = normalizeExecOutput(execFileSyncFn(command, [...args, "--version"], {
@@ -4298,6 +4447,10 @@ function resolveClaudeCommand(deps = {}) {
4298
4447
  CLAUDE_DESKTOP_CLI_SYSTEM_PATH
4299
4448
  ], deps);
4300
4449
  }
4450
+ function resolveClaudeLaunchCommand(config, deps = {}) {
4451
+ const launchRuntimeFields = runtimeConfigToLaunchFields(config);
4452
+ return launchRuntimeFields.command?.trim() || resolveClaudeCommand(deps);
4453
+ }
4301
4454
  function probeClaude(deps = {}) {
4302
4455
  const command = resolveClaudeCommand(deps);
4303
4456
  if (!command) return { available: false };
@@ -4354,7 +4507,7 @@ function buildClaudeSpawnSpec(claudeCommand, platform = process.platform) {
4354
4507
  }
4355
4508
 
4356
4509
  // src/drivers/claudeProviderIsolation.ts
4357
- import { existsSync as existsSync3, mkdirSync as mkdirSync2, symlinkSync } from "fs";
4510
+ import { existsSync as existsSync4, mkdirSync as mkdirSync2, symlinkSync } from "fs";
4358
4511
  import os2 from "os";
4359
4512
  import path5 from "path";
4360
4513
  function isClaudeCustomProviderConfig(config) {
@@ -4372,7 +4525,7 @@ function getClaudeProviderStatePaths(workingDirectory) {
4372
4525
  }
4373
4526
  function linkIfPresent(source, target) {
4374
4527
  try {
4375
- if (!existsSync3(source) || existsSync3(target)) return;
4528
+ if (!existsSync4(source) || existsSync4(target)) return;
4376
4529
  mkdirSync2(path5.dirname(target), { recursive: true, mode: 448 });
4377
4530
  symlinkSync(source, target, "dir");
4378
4531
  } catch {
@@ -4444,7 +4597,7 @@ var ClaudeDriver = class {
4444
4597
  logger.info(
4445
4598
  `[Agent ${ctx.agentId}] transport=cli cli=${ctx.slockCliPath} token_file=${tokenFile}`
4446
4599
  );
4447
- const claudeCommand = resolveClaudeCommand();
4600
+ const claudeCommand = resolveClaudeLaunchCommand(ctx.config);
4448
4601
  const spawnSpec = buildClaudeSpawnSpec(claudeCommand);
4449
4602
  const proc = spawn(spawnSpec.command, args, {
4450
4603
  cwd: ctx.workingDirectory,
@@ -4493,7 +4646,7 @@ var ClaudeDriver = class {
4493
4646
 
4494
4647
  // src/drivers/codex.ts
4495
4648
  import { spawn as spawn2, execFileSync as execFileSync2, execSync } from "child_process";
4496
- import { existsSync as existsSync4, readFileSync as readFileSync2 } from "fs";
4649
+ import { existsSync as existsSync5, readFileSync as readFileSync2 } from "fs";
4497
4650
  import os3 from "os";
4498
4651
  import path6 from "path";
4499
4652
 
@@ -4882,7 +5035,7 @@ var CodexEventNormalizer = class {
4882
5035
 
4883
5036
  // src/drivers/codex.ts
4884
5037
  function ensureGitRepoForCodex(workingDirectory, deps = {}) {
4885
- const existsSyncFn = deps.existsSyncFn ?? existsSync4;
5038
+ const existsSyncFn = deps.existsSyncFn ?? existsSync5;
4886
5039
  const execSyncFn = deps.execSyncFn ?? execSync;
4887
5040
  const gitDir = path6.join(workingDirectory, ".git");
4888
5041
  if (existsSyncFn(gitDir)) return;
@@ -4900,7 +5053,7 @@ function isWindowsSandboxRunner(commandPath) {
4900
5053
  return path6.basename(commandPath).toLowerCase().startsWith("codex-command-runner");
4901
5054
  }
4902
5055
  function resolveWindowsNpmCodexEntry(deps = {}) {
4903
- const existsSyncFn = deps.existsSyncFn ?? existsSync4;
5056
+ const existsSyncFn = deps.existsSyncFn ?? existsSync5;
4904
5057
  const execFileSyncFn = deps.execFileSyncFn ?? execFileSync2;
4905
5058
  const env = deps.env ?? process.env;
4906
5059
  const winPath = path6.win32;
@@ -4922,7 +5075,7 @@ function resolveWindowsNpmCodexEntry(deps = {}) {
4922
5075
  return null;
4923
5076
  }
4924
5077
  function resolveWindowsCodexDesktopEntry(deps = {}) {
4925
- const existsSyncFn = deps.existsSyncFn ?? existsSync4;
5078
+ const existsSyncFn = deps.existsSyncFn ?? existsSync5;
4926
5079
  const env = deps.env ?? process.env;
4927
5080
  const homeDir = deps.homeDir;
4928
5081
  const winPath = path6.win32;
@@ -5037,7 +5190,7 @@ var CodexDriver = class {
5037
5190
  threadParams.config = { model_reasoning_effort: launchRuntimeFields.reasoningEffort };
5038
5191
  }
5039
5192
  if (launchRuntimeFields.mode.kind === "fast") {
5040
- threadParams.serviceTier = "priority";
5193
+ threadParams.serviceTier = "fast";
5041
5194
  }
5042
5195
  if (ctx.config.sessionId) {
5043
5196
  return {
@@ -5237,10 +5390,11 @@ var ANTIGRAVITY_ENV_OVERRIDES = {
5237
5390
  SSH_TTY: void 0
5238
5391
  };
5239
5392
  function resolveAntigravitySpawn(commandArgs, deps = {}) {
5393
+ const command = resolveCommandOnPath("agy", deps) ?? "agy";
5240
5394
  return {
5241
- command: resolveCommandOnPath("agy", deps) ?? "agy",
5395
+ command,
5242
5396
  args: commandArgs,
5243
- shell: false
5397
+ shell: requiresWindowsShell(command, deps.platform)
5244
5398
  };
5245
5399
  }
5246
5400
  function buildAntigravityArgs(ctx) {
@@ -5648,11 +5802,11 @@ function detectCursorModels(runCommand = runCursorModelsCommand) {
5648
5802
  return parseCursorModelsOutput(String(result.stdout || ""));
5649
5803
  }
5650
5804
  function buildCursorModelProbeEnv(deps = {}) {
5651
- return withWindowsUserEnvironment({
5805
+ return scrubDaemonChildEnv(withWindowsUserEnvironment({
5652
5806
  ...deps.env ?? process.env,
5653
5807
  FORCE_COLOR: "0",
5654
5808
  NO_COLOR: "1"
5655
- }, deps);
5809
+ }, deps));
5656
5810
  }
5657
5811
  function runCursorModelsCommand() {
5658
5812
  return spawnSync("cursor-agent", ["models"], {
@@ -5664,7 +5818,7 @@ function runCursorModelsCommand() {
5664
5818
 
5665
5819
  // src/drivers/gemini.ts
5666
5820
  import { execFileSync as execFileSync3, spawn as spawn6 } from "child_process";
5667
- import { existsSync as existsSync5 } from "fs";
5821
+ import { existsSync as existsSync6 } from "fs";
5668
5822
  import path7 from "path";
5669
5823
  async function buildGeminiSpawnEnv(ctx, platform = process.platform) {
5670
5824
  const { spawnEnv } = await prepareCliTransport(ctx, { NO_COLOR: "1" }, platform);
@@ -5707,8 +5861,8 @@ function resolveGeminiSpawn(commandArgs, deps = {}) {
5707
5861
  return { command: resolveCommandOnPath("gemini", deps) ?? "gemini", args: commandArgs };
5708
5862
  }
5709
5863
  const execFileSyncFn = deps.execFileSyncFn ?? execFileSync3;
5710
- const existsSyncFn = deps.existsSyncFn ?? existsSync5;
5711
- const env = deps.env ?? process.env;
5864
+ const existsSyncFn = deps.existsSyncFn ?? existsSync6;
5865
+ const env = scrubDaemonChildEnv({ ...deps.env ?? process.env });
5712
5866
  const winPath = path7.win32;
5713
5867
  let geminiEntry = null;
5714
5868
  try {
@@ -5845,12 +5999,15 @@ var GeminiDriver = class {
5845
5999
  // src/drivers/kimi.ts
5846
6000
  import { randomUUID as randomUUID2 } from "crypto";
5847
6001
  import { spawn as spawn7 } from "child_process";
5848
- import { existsSync as existsSync6, readFileSync as readFileSync3, writeFileSync as writeFileSync3 } from "fs";
6002
+ import { chmodSync, existsSync as existsSync7, readFileSync as readFileSync3, writeFileSync as writeFileSync3 } from "fs";
5849
6003
  import os4 from "os";
5850
6004
  import path8 from "path";
5851
6005
  var KIMI_WIRE_PROTOCOL_VERSION = "1.3";
5852
6006
  var KIMI_SYSTEM_PROMPT_FILE = ".slock-kimi-system.md";
5853
6007
  var KIMI_AGENT_FILE = ".slock-kimi-agent.yaml";
6008
+ var KIMI_GENERATED_CONFIG_FILE = ".slock-kimi-config.toml";
6009
+ var SLOCK_KIMI_CONFIG_CONTENT_ENV = "SLOCK_KIMI_CONFIG_CONTENT";
6010
+ var SLOCK_KIMI_CONFIG_FILE_ENV = "SLOCK_KIMI_CONFIG_FILE";
5854
6011
  function parseToolArguments(raw) {
5855
6012
  if (typeof raw !== "string") return raw;
5856
6013
  try {
@@ -5859,6 +6016,73 @@ function parseToolArguments(raw) {
5859
6016
  return raw;
5860
6017
  }
5861
6018
  }
6019
+ function readKimiConfigSource(home = os4.homedir(), env = process.env) {
6020
+ const inlineConfig = env[SLOCK_KIMI_CONFIG_CONTENT_ENV];
6021
+ if (inlineConfig && inlineConfig.trim()) {
6022
+ return {
6023
+ raw: inlineConfig,
6024
+ explicitPath: null,
6025
+ sourcePath: SLOCK_KIMI_CONFIG_CONTENT_ENV
6026
+ };
6027
+ }
6028
+ const explicitPath = env[SLOCK_KIMI_CONFIG_FILE_ENV];
6029
+ const configPath = explicitPath && explicitPath.trim() ? explicitPath : path8.join(home, ".kimi", "config.toml");
6030
+ try {
6031
+ return {
6032
+ raw: readFileSync3(configPath, "utf8"),
6033
+ explicitPath: explicitPath && explicitPath.trim() ? explicitPath : null,
6034
+ sourcePath: configPath
6035
+ };
6036
+ } catch {
6037
+ return {
6038
+ raw: null,
6039
+ explicitPath: explicitPath && explicitPath.trim() ? explicitPath : null,
6040
+ sourcePath: configPath
6041
+ };
6042
+ }
6043
+ }
6044
+ function buildKimiSpawnEnv(env = process.env) {
6045
+ const spawnEnv = { ...env, FORCE_COLOR: "0", NO_COLOR: "1" };
6046
+ delete spawnEnv[SLOCK_KIMI_CONFIG_CONTENT_ENV];
6047
+ delete spawnEnv[SLOCK_KIMI_CONFIG_FILE_ENV];
6048
+ return scrubDaemonChildEnv(spawnEnv);
6049
+ }
6050
+ function buildKimiEffectiveEnv(ctx, overrideEnv) {
6051
+ return {
6052
+ ...process.env,
6053
+ ...ctx.config.envVars || {},
6054
+ ...overrideEnv || {}
6055
+ };
6056
+ }
6057
+ function buildKimiLaunchOptions(ctx, opts = {}) {
6058
+ const env = buildKimiEffectiveEnv(ctx, opts.env);
6059
+ const source = readKimiConfigSource(opts.home ?? os4.homedir(), env);
6060
+ const args = [];
6061
+ let configFilePath = null;
6062
+ let configContent = null;
6063
+ if (source.explicitPath) {
6064
+ configFilePath = source.explicitPath;
6065
+ } else if (source.raw !== null && source.sourcePath === SLOCK_KIMI_CONFIG_CONTENT_ENV) {
6066
+ configFilePath = path8.join(ctx.workingDirectory, KIMI_GENERATED_CONFIG_FILE);
6067
+ configContent = source.raw;
6068
+ if (opts.writeGeneratedConfig !== false) {
6069
+ writeFileSync3(configFilePath, source.raw, { encoding: "utf8", mode: 384 });
6070
+ chmodSync(configFilePath, 384);
6071
+ }
6072
+ }
6073
+ if (configFilePath) {
6074
+ args.push("--config-file", configFilePath);
6075
+ }
6076
+ if (ctx.config.model && ctx.config.model !== "default") {
6077
+ args.push("--model", ctx.config.model);
6078
+ }
6079
+ return {
6080
+ args,
6081
+ env: buildKimiSpawnEnv(env),
6082
+ configFilePath,
6083
+ configContent
6084
+ };
6085
+ }
5862
6086
  function resolveKimiSpawn(commandArgs, deps = {}) {
5863
6087
  return {
5864
6088
  command: resolveCommandOnPath("kimi", deps) ?? "kimi",
@@ -5882,7 +6106,25 @@ var KimiDriver = class {
5882
6106
  };
5883
6107
  model = {
5884
6108
  detectedModelsVerifiedAs: "launchable",
5885
- toLaunchSpec: (modelId) => ({ args: ["--model", modelId] })
6109
+ toLaunchSpec: (modelId, ctx, opts) => {
6110
+ if (!ctx) return { args: ["--model", modelId] };
6111
+ const launchCtx = {
6112
+ ...ctx,
6113
+ config: {
6114
+ ...ctx.config,
6115
+ model: modelId
6116
+ }
6117
+ };
6118
+ const launch = buildKimiLaunchOptions(launchCtx, {
6119
+ home: opts?.home,
6120
+ writeGeneratedConfig: false
6121
+ });
6122
+ return {
6123
+ args: launch.args,
6124
+ env: launch.env,
6125
+ configFiles: launch.configFilePath ? [launch.configFilePath] : void 0
6126
+ };
6127
+ }
5886
6128
  };
5887
6129
  supportsStdinNotification = true;
5888
6130
  busyDeliveryMode = "direct";
@@ -5896,7 +6138,7 @@ var KimiDriver = class {
5896
6138
  this.promptRequestId = randomUUID2();
5897
6139
  const systemPromptPath = path8.join(ctx.workingDirectory, KIMI_SYSTEM_PROMPT_FILE);
5898
6140
  const agentFilePath = path8.join(ctx.workingDirectory, KIMI_AGENT_FILE);
5899
- if (!isResume || !existsSync6(systemPromptPath)) {
6141
+ if (!isResume || !existsSync7(systemPromptPath)) {
5900
6142
  writeFileSync3(systemPromptPath, ctx.prompt, "utf8");
5901
6143
  }
5902
6144
  writeFileSync3(agentFilePath, [
@@ -5906,21 +6148,23 @@ var KimiDriver = class {
5906
6148
  ` system_prompt_path: ./${KIMI_SYSTEM_PROMPT_FILE}`,
5907
6149
  ""
5908
6150
  ].join("\n"), "utf8");
6151
+ const launch = buildKimiLaunchOptions(ctx);
5909
6152
  const args = [
5910
6153
  "--wire",
5911
6154
  "--yolo",
5912
6155
  "--agent-file",
5913
6156
  agentFilePath,
5914
6157
  "--session",
5915
- this.sessionId
6158
+ this.sessionId,
6159
+ ...launch.args
5916
6160
  ];
5917
6161
  const launchRuntimeFields = runtimeConfigToLaunchFields(ctx.config);
5918
6162
  if (launchRuntimeFields.model && launchRuntimeFields.model !== "default") {
5919
6163
  args.push("--model", launchRuntimeFields.model);
5920
6164
  }
5921
6165
  const spawnEnv = (await prepareCliTransport(ctx, { NO_COLOR: "1" })).spawnEnv;
5922
- const launch = resolveKimiSpawn(args);
5923
- const proc = spawn7(launch.command, launch.args, {
6166
+ const spawnTarget = resolveKimiSpawn(args);
6167
+ const proc = spawn7(spawnTarget.command, spawnTarget.args, {
5924
6168
  cwd: ctx.workingDirectory,
5925
6169
  stdio: ["pipe", "pipe", "pipe"],
5926
6170
  env: spawnEnv,
@@ -5928,7 +6172,7 @@ var KimiDriver = class {
5928
6172
  // and has an 8191-character command-line limit. Kimi's official
5929
6173
  // installer/uv entrypoint is an executable, so launch it directly and
5930
6174
  // keep prompts on stdin / files instead of routing through cmd.exe.
5931
- shell: launch.shell
6175
+ shell: spawnTarget.shell
5932
6176
  });
5933
6177
  proc.stdin?.write(JSON.stringify({
5934
6178
  jsonrpc: "2.0",
@@ -6041,14 +6285,9 @@ var KimiDriver = class {
6041
6285
  return detectKimiModels();
6042
6286
  }
6043
6287
  };
6044
- function detectKimiModels(home = os4.homedir()) {
6045
- const configPath = path8.join(home, ".kimi", "config.toml");
6046
- let raw;
6047
- try {
6048
- raw = readFileSync3(configPath, "utf8");
6049
- } catch {
6050
- return null;
6051
- }
6288
+ function detectKimiModels(home = os4.homedir(), opts = {}) {
6289
+ const raw = readKimiConfigSource(home, opts.env).raw;
6290
+ if (raw === null) return null;
6052
6291
  const models = [];
6053
6292
  const sectionRe = /^\s*\[models(?:\.([^\]]+)|"\.[^"]+"|\."[^"]+")\s*\]\s*$/gm;
6054
6293
  const lineRe = /^\s*\[models\.(.+?)\s*\]\s*$/gm;
@@ -6069,7 +6308,7 @@ function detectKimiModels(home = os4.homedir()) {
6069
6308
 
6070
6309
  // src/drivers/opencode.ts
6071
6310
  import { spawn as spawn8, spawnSync as spawnSync2 } from "child_process";
6072
- import { existsSync as existsSync7, readFileSync as readFileSync4 } from "fs";
6311
+ import { existsSync as existsSync8, readFileSync as readFileSync4 } from "fs";
6073
6312
  import os5 from "os";
6074
6313
  import path9 from "path";
6075
6314
  var SLOCK_AGENT_NAME = "slock";
@@ -6286,7 +6525,7 @@ function runOpenCodeModelsCommand(home, deps = {}) {
6286
6525
  const platform = deps.platform ?? process.platform;
6287
6526
  const spawnSyncFn = deps.spawnSyncFn ?? spawnSync2;
6288
6527
  const result = spawnSyncFn("opencode", ["models"], {
6289
- env: { ...process.env, HOME: home, FORCE_COLOR: "0", NO_COLOR: "1" },
6528
+ env: scrubDaemonChildEnv({ ...process.env, HOME: home, FORCE_COLOR: "0", NO_COLOR: "1" }),
6290
6529
  encoding: "utf8",
6291
6530
  timeout: 5e3,
6292
6531
  shell: platform === "win32"
@@ -6317,7 +6556,7 @@ function openCodeSpecForEntry(entry, commandArgs) {
6317
6556
  return { command: process.execPath, args: [entry, ...commandArgs], shell: false };
6318
6557
  }
6319
6558
  function resolveWindowsOpenCodePackageEntry(commandPath, deps = {}) {
6320
- const existsSyncFn = deps.existsSyncFn ?? existsSync7;
6559
+ const existsSyncFn = deps.existsSyncFn ?? existsSync8;
6321
6560
  const execFileSyncFn = deps.execFileSyncFn;
6322
6561
  const env = deps.env ?? process.env;
6323
6562
  const winPath = path9.win32;
@@ -6545,7 +6784,7 @@ var OpenCodeDriver = class {
6545
6784
  // src/drivers/pi.ts
6546
6785
  import { randomUUID as randomUUID3 } from "crypto";
6547
6786
  import { EventEmitter } from "events";
6548
- import { mkdirSync as mkdirSync3, readdirSync } from "fs";
6787
+ import { mkdirSync as mkdirSync3, readdirSync as readdirSync2 } from "fs";
6549
6788
  import path10 from "path";
6550
6789
  import {
6551
6790
  AuthStorage,
@@ -6589,7 +6828,7 @@ function resolvePiModelFromRegistry(modelId, modelRegistry) {
6589
6828
  function findPiSessionFile(sessionDir, sessionId) {
6590
6829
  let entries;
6591
6830
  try {
6592
- entries = readdirSync(sessionDir);
6831
+ entries = readdirSync2(sessionDir);
6593
6832
  } catch {
6594
6833
  return null;
6595
6834
  }
@@ -7819,7 +8058,7 @@ function findSessionJsonl(root, predicate) {
7819
8058
  if (depth < 0 || visited >= maxEntries) return null;
7820
8059
  let entries;
7821
8060
  try {
7822
- entries = readdirSync2(dir, { withFileTypes: true }).sort((a, b) => b.name.localeCompare(a.name));
8061
+ entries = readdirSync3(dir, { withFileTypes: true }).sort((a, b) => b.name.localeCompare(a.name));
7823
8062
  } catch {
7824
8063
  return null;
7825
8064
  }
@@ -13428,7 +13667,7 @@ function acquireDaemonMachineLock(options) {
13428
13667
  }
13429
13668
 
13430
13669
  // src/localTraceSink.ts
13431
- import { appendFileSync, mkdirSync as mkdirSync6, readdirSync as readdirSync3, rmSync as rmSync4, statSync as statSync3, writeFileSync as writeFileSync6 } from "fs";
13670
+ import { appendFileSync, mkdirSync as mkdirSync6, readdirSync as readdirSync4, rmSync as rmSync4, statSync as statSync3, writeFileSync as writeFileSync6 } from "fs";
13432
13671
  import path14 from "path";
13433
13672
  var DEFAULT_MAX_FILE_BYTES = 5 * 1024 * 1024;
13434
13673
  var DEFAULT_MAX_FILE_AGE_MS = 5 * 60 * 1e3;
@@ -13507,7 +13746,7 @@ var LocalRotatingTraceSink = class {
13507
13746
  }
13508
13747
  }
13509
13748
  pruneOldFiles() {
13510
- const files = readdirSync3(this.traceDir).filter((name) => name.startsWith("daemon-trace-") && name.endsWith(".jsonl")).sort();
13749
+ const files = readdirSync4(this.traceDir).filter((name) => name.startsWith("daemon-trace-") && name.endsWith(".jsonl")).sort();
13511
13750
  const excess = files.length - this.maxFiles;
13512
13751
  if (excess <= 0) return;
13513
13752
  for (const file of files.slice(0, excess)) {
@@ -14091,7 +14330,7 @@ var DAEMON_CORE_TRACE_ATTR_CONTRACTS = {
14091
14330
  spanAttrs: ["running_agents_count", "idle_agents_count"]
14092
14331
  }
14093
14332
  };
14094
- var DAEMON_CLI_USAGE = "Usage: slock-daemon --server-url <url> --api-key <key>";
14333
+ var DAEMON_CLI_USAGE = `Usage: slock-daemon --server-url <url> (--api-key <key> or ${DAEMON_API_KEY_ENV}=<key>)`;
14095
14334
  var RunnerCredentialMintError2 = class extends Error {
14096
14335
  code;
14097
14336
  retryable;
@@ -14127,9 +14366,9 @@ function runnerCredentialErrorDetail2(error) {
14127
14366
  async function waitForRunnerCredentialRetry2() {
14128
14367
  await new Promise((resolve) => setTimeout(resolve, RUNNER_CREDENTIAL_MINT_RETRY_DELAY_MS2));
14129
14368
  }
14130
- function parseDaemonCliArgs(args) {
14369
+ function parseDaemonCliArgs(args, env = {}) {
14131
14370
  let serverUrl = "";
14132
- let apiKey = "";
14371
+ let apiKey = env[DAEMON_API_KEY_ENV] ?? "";
14133
14372
  for (let i = 0; i < args.length; i++) {
14134
14373
  if (args[i] === "--server-url" && args[i + 1]) serverUrl = args[++i];
14135
14374
  if (args[i] === "--api-key" && args[i + 1]) apiKey = args[++i];
@@ -14166,7 +14405,7 @@ function resolveSlockCliPathOrEmpty(moduleUrl = import.meta.url) {
14166
14405
  }
14167
14406
  async function runBundledSlockCli(argv) {
14168
14407
  process.argv = [process.execPath, "slock", ...argv];
14169
- await import("./dist-CLQ4P4XZ.js");
14408
+ await import("./dist-JVLCJ2QO.js");
14170
14409
  }
14171
14410
  function detectRuntimes(tracer = noopTracer) {
14172
14411
  const ids = [];
@@ -14302,6 +14541,11 @@ var DaemonCore = class {
14302
14541
  computerVersion;
14303
14542
  slockCliPath;
14304
14543
  slockHome;
14544
+ agentsDataDir;
14545
+ // One-shot guard: rewrite stale per-agent opencli wrappers to the current
14546
+ // self-healing form on the first connect of this daemon process (a SEA
14547
+ // computer switch / daemon upgrade restarts the daemon → triggers this).
14548
+ opencliWrappersRegenerated = false;
14305
14549
  runtimeDetector;
14306
14550
  agentManager;
14307
14551
  connection;
@@ -14328,8 +14572,9 @@ var DaemonCore = class {
14328
14572
  onFire: (job) => this.onReminderFire(job)
14329
14573
  });
14330
14574
  let connection;
14575
+ this.agentsDataDir = options.dataDir ?? resolveSlockHomePath("agents", this.slockHome);
14331
14576
  const agentManagerOptions = {
14332
- dataDir: options.dataDir ?? resolveSlockHomePath("agents", this.slockHome),
14577
+ dataDir: this.agentsDataDir,
14333
14578
  serverUrl: options.serverUrl,
14334
14579
  defaultAgentEnvVarsProvider: options.defaultAgentEnvVarsProvider,
14335
14580
  slockCliPath: this.slockCliPath,
@@ -14859,6 +15104,17 @@ var DaemonCore = class {
14859
15104
  const { ids: runtimes, versions: runtimeVersions } = this.runtimeDetector();
14860
15105
  const runtimeInfo = runtimes.map((id) => runtimeVersions[id] ? `${id} (${runtimeVersions[id]})` : id);
14861
15106
  logger.info(`[Daemon] Detected runtimes: ${runtimeInfo.join(", ") || "none"}`);
15107
+ if (!this.opencliWrappersRegenerated) {
15108
+ this.opencliWrappersRegenerated = true;
15109
+ try {
15110
+ const { scanned, rewritten } = regenerateExistingOpencliWrappers(this.agentsDataDir);
15111
+ if (scanned > 0) {
15112
+ logger.info(`[Daemon] Refreshed ${rewritten}/${scanned} opencli wrapper(s) to current self-healing form`);
15113
+ }
15114
+ } catch (err) {
15115
+ logger.warn(`[Daemon] opencli wrapper refresh skipped: ${err instanceof Error ? err.message : String(err)}`);
15116
+ }
15117
+ }
14862
15118
  const runningAgentIds = this.agentManager.getRunningAgentIds();
14863
15119
  const idleAgentSessions = this.agentManager.getIdleAgentSessionIds();
14864
15120
  const runtimeProfileReports = this.agentManager.getAgentRuntimeProfileReports();
@@ -14948,6 +15204,8 @@ var DaemonCore = class {
14948
15204
  };
14949
15205
 
14950
15206
  export {
15207
+ DAEMON_API_KEY_ENV,
15208
+ scrubDaemonAuthEnv,
14951
15209
  subscribeDaemonLogs,
14952
15210
  resolveWorkspaceDirectoryPath,
14953
15211
  scanWorkspaceDirectories,
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
@@ -1,4 +1,5 @@
1
1
  import {
2
+ DAEMON_API_KEY_ENV,
2
3
  DAEMON_CLI_USAGE,
3
4
  DaemonCore,
4
5
  deleteWorkspaceDirectory,
@@ -10,9 +11,11 @@ import {
10
11
  resolveWorkspaceDirectoryPath,
11
12
  runBundledSlockCli,
12
13
  scanWorkspaceDirectories,
14
+ scrubDaemonAuthEnv,
13
15
  subscribeDaemonLogs
14
- } from "./chunk-FTEZQN4P.js";
16
+ } from "./chunk-62SH5AE4.js";
15
17
  export {
18
+ DAEMON_API_KEY_ENV,
16
19
  DAEMON_CLI_USAGE,
17
20
  DaemonCore,
18
21
  deleteWorkspaceDirectory,
@@ -24,5 +27,6 @@ export {
24
27
  resolveWorkspaceDirectoryPath,
25
28
  runBundledSlockCli,
26
29
  scanWorkspaceDirectories,
30
+ scrubDaemonAuthEnv,
27
31
  subscribeDaemonLogs
28
32
  };
@@ -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
@@ -2,11 +2,13 @@
2
2
  import {
3
3
  DAEMON_CLI_USAGE,
4
4
  DaemonCore,
5
- parseDaemonCliArgs
6
- } from "./chunk-FTEZQN4P.js";
5
+ parseDaemonCliArgs,
6
+ scrubDaemonAuthEnv
7
+ } from "./chunk-62SH5AE4.js";
7
8
 
8
9
  // src/index.ts
9
- var parsedArgs = parseDaemonCliArgs(process.argv.slice(2));
10
+ var parsedArgs = parseDaemonCliArgs(process.argv.slice(2), process.env);
11
+ scrubDaemonAuthEnv(process.env);
10
12
  if (!parsedArgs) {
11
13
  console.error(DAEMON_CLI_USAGE);
12
14
  process.exit(1);
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-play.20260615055221",
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",