@botiverse/raft-daemon 0.63.5-play.20260623160336 → 0.63.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.
@@ -2683,19 +2683,6 @@ function listLegacySlockStatePaths(slockHome = resolveSlockHome(), homeDir = os.
2683
2683
  return candidates.filter((candidate) => existsSync(candidate.path));
2684
2684
  }
2685
2685
 
2686
- // src/authEnv.ts
2687
- var DAEMON_API_KEY_ENV = "SLOCK_MACHINE_API_KEY";
2688
- var SLOCK_AGENT_TOKEN_ENV = "SLOCK_AGENT_TOKEN";
2689
- function scrubDaemonAuthEnv(env) {
2690
- delete env[DAEMON_API_KEY_ENV];
2691
- return env;
2692
- }
2693
- function scrubDaemonChildEnv(env) {
2694
- delete env[DAEMON_API_KEY_ENV];
2695
- delete env[SLOCK_AGENT_TOKEN_ENV];
2696
- return env;
2697
- }
2698
-
2699
2686
  // src/agentCredentialProxy.ts
2700
2687
  import { randomBytes } from "crypto";
2701
2688
  import http from "http";
@@ -3535,6 +3522,7 @@ function latestVisibleMessages(messages, limit) {
3535
3522
  return sorted.slice(Math.max(0, sorted.length - limit));
3536
3523
  }
3537
3524
  function isMessageModelSeen(input, message) {
3525
+ if (messageSenderId(message) === input.agentId) return true;
3538
3526
  const seq = Math.floor(messageSeq(message));
3539
3527
  if (Number.isFinite(seq) && seq > 0 && typeof input.modelSeenSeq === "number" && input.modelSeenSeq >= seq) return true;
3540
3528
  return input.isMessageModelSeen?.({ target: input.target, message }) === true;
@@ -4262,9 +4250,7 @@ var LOOPBACK_NO_PROXY = "127.0.0.1,localhost";
4262
4250
  var CLI_TRANSPORT_TRACE_DIR_ENV = "SLOCK_CLI_TRANSPORT_TRACE_DIR";
4263
4251
  var safePathPart = (value) => value.replace(/[^a-zA-Z0-9_.-]/g, "_");
4264
4252
  var RAW_CREDENTIAL_ENV_DENYLIST = [
4265
- "SLOCK_AGENT_TOKEN",
4266
- "SLOCK_AGENT_CREDENTIAL_KEY",
4267
- "SLOCK_AGENT_CREDENTIAL_KEY_FILE"
4253
+ "SLOCK_AGENT_CREDENTIAL_KEY"
4268
4254
  ];
4269
4255
  var WORKSPACE_CLI_TRANSPORT_FILENAMES = [
4270
4256
  "agent-token",
@@ -4616,7 +4602,7 @@ set "SLOCK_AGENT_ACTIVE_CAPABILITIES=${DEFAULT_ACTIVE_CAPABILITIES}"\r
4616
4602
  SLOCK_SERVER_URL: ctx.config.serverUrl,
4617
4603
  PATH: `${slockDir}${path2.delimiter}${process.env.PATH ?? ""}`
4618
4604
  };
4619
- scrubDaemonChildEnv(spawnEnv);
4605
+ delete spawnEnv.SLOCK_AGENT_TOKEN;
4620
4606
  for (const key of RAW_CREDENTIAL_ENV_DENYLIST) {
4621
4607
  delete spawnEnv[key];
4622
4608
  }
@@ -5138,7 +5124,7 @@ function requiresWindowsShell(command, platform = process.platform) {
5138
5124
  }
5139
5125
  function resolveCommandOnPath(command, deps = {}) {
5140
5126
  const platform = deps.platform ?? process.platform;
5141
- const env = scrubDaemonChildEnv({ ...withWindowsUserEnvironment(deps.env ?? process.env, deps) });
5127
+ const env = withWindowsUserEnvironment(deps.env ?? process.env, deps);
5142
5128
  const execFileSyncFn = deps.execFileSyncFn ?? execFileSync;
5143
5129
  const existsSyncFn = deps.existsSyncFn ?? existsSync3;
5144
5130
  if (platform === "win32") {
@@ -5164,7 +5150,7 @@ function firstExistingPath(candidates, deps = {}) {
5164
5150
  return null;
5165
5151
  }
5166
5152
  function readCommandVersion(command, args = [], deps = {}) {
5167
- const env = scrubDaemonChildEnv({ ...withWindowsUserEnvironment(deps.env ?? process.env, deps) });
5153
+ const env = withWindowsUserEnvironment(deps.env ?? process.env, deps);
5168
5154
  const execFileSyncFn = deps.execFileSyncFn ?? execFileSync;
5169
5155
  try {
5170
5156
  const output = normalizeExecOutput(execFileSyncFn(command, [...args, "--version"], {
@@ -7244,11 +7230,11 @@ function detectCursorModels(runCommand = runCursorModelsCommand) {
7244
7230
  return parseCursorModelsOutput(String(result.stdout || ""));
7245
7231
  }
7246
7232
  function buildCursorModelProbeEnv(deps = {}) {
7247
- return scrubDaemonChildEnv(withWindowsUserEnvironment({
7233
+ return withWindowsUserEnvironment({
7248
7234
  ...deps.env ?? process.env,
7249
7235
  FORCE_COLOR: "0",
7250
7236
  NO_COLOR: "1"
7251
- }, deps));
7237
+ }, deps);
7252
7238
  }
7253
7239
  function runCursorModelsCommand() {
7254
7240
  return spawnSync("cursor-agent", ["models"], {
@@ -7304,7 +7290,7 @@ function resolveGeminiSpawn(commandArgs, deps = {}) {
7304
7290
  }
7305
7291
  const execFileSyncFn = deps.execFileSyncFn ?? execFileSync3;
7306
7292
  const existsSyncFn = deps.existsSyncFn ?? existsSync5;
7307
- const env = scrubDaemonChildEnv({ ...deps.env ?? process.env });
7293
+ const env = deps.env ?? process.env;
7308
7294
  const winPath = path8.win32;
7309
7295
  let geminiEntry = null;
7310
7296
  try {
@@ -7441,15 +7427,12 @@ var GeminiDriver = class {
7441
7427
  // src/drivers/kimi.ts
7442
7428
  import { randomUUID as randomUUID2 } from "crypto";
7443
7429
  import { spawn as spawn7 } from "child_process";
7444
- import { chmodSync, existsSync as existsSync6, readFileSync as readFileSync3, writeFileSync as writeFileSync3 } from "fs";
7430
+ import { existsSync as existsSync6, readFileSync as readFileSync3, writeFileSync as writeFileSync3 } from "fs";
7445
7431
  import os4 from "os";
7446
7432
  import path9 from "path";
7447
7433
  var KIMI_WIRE_PROTOCOL_VERSION = "1.3";
7448
7434
  var KIMI_SYSTEM_PROMPT_FILE = ".slock-kimi-system.md";
7449
7435
  var KIMI_AGENT_FILE = ".slock-kimi-agent.yaml";
7450
- var KIMI_GENERATED_CONFIG_FILE = ".slock-kimi-config.toml";
7451
- var SLOCK_KIMI_CONFIG_CONTENT_ENV = "SLOCK_KIMI_CONFIG_CONTENT";
7452
- var SLOCK_KIMI_CONFIG_FILE_ENV = "SLOCK_KIMI_CONFIG_FILE";
7453
7436
  function parseToolArguments(raw) {
7454
7437
  if (typeof raw !== "string") return raw;
7455
7438
  try {
@@ -7458,73 +7441,6 @@ function parseToolArguments(raw) {
7458
7441
  return raw;
7459
7442
  }
7460
7443
  }
7461
- function readKimiConfigSource(home = os4.homedir(), env = process.env) {
7462
- const inlineConfig = env[SLOCK_KIMI_CONFIG_CONTENT_ENV];
7463
- if (inlineConfig && inlineConfig.trim()) {
7464
- return {
7465
- raw: inlineConfig,
7466
- explicitPath: null,
7467
- sourcePath: SLOCK_KIMI_CONFIG_CONTENT_ENV
7468
- };
7469
- }
7470
- const explicitPath = env[SLOCK_KIMI_CONFIG_FILE_ENV];
7471
- const configPath = explicitPath && explicitPath.trim() ? explicitPath : path9.join(home, ".kimi", "config.toml");
7472
- try {
7473
- return {
7474
- raw: readFileSync3(configPath, "utf8"),
7475
- explicitPath: explicitPath && explicitPath.trim() ? explicitPath : null,
7476
- sourcePath: configPath
7477
- };
7478
- } catch {
7479
- return {
7480
- raw: null,
7481
- explicitPath: explicitPath && explicitPath.trim() ? explicitPath : null,
7482
- sourcePath: configPath
7483
- };
7484
- }
7485
- }
7486
- function buildKimiSpawnEnv(env = process.env) {
7487
- const spawnEnv = { ...env, FORCE_COLOR: "0", NO_COLOR: "1" };
7488
- delete spawnEnv[SLOCK_KIMI_CONFIG_CONTENT_ENV];
7489
- delete spawnEnv[SLOCK_KIMI_CONFIG_FILE_ENV];
7490
- return scrubDaemonChildEnv(spawnEnv);
7491
- }
7492
- function buildKimiEffectiveEnv(ctx, overrideEnv) {
7493
- return {
7494
- ...process.env,
7495
- ...ctx.config.envVars || {},
7496
- ...overrideEnv || {}
7497
- };
7498
- }
7499
- function buildKimiLaunchOptions(ctx, opts = {}) {
7500
- const env = buildKimiEffectiveEnv(ctx, opts.env);
7501
- const source = readKimiConfigSource(opts.home ?? os4.homedir(), env);
7502
- const args = [];
7503
- let configFilePath = null;
7504
- let configContent = null;
7505
- if (source.explicitPath) {
7506
- configFilePath = source.explicitPath;
7507
- } else if (source.raw !== null && source.sourcePath === SLOCK_KIMI_CONFIG_CONTENT_ENV) {
7508
- configFilePath = path9.join(ctx.workingDirectory, KIMI_GENERATED_CONFIG_FILE);
7509
- configContent = source.raw;
7510
- if (opts.writeGeneratedConfig !== false) {
7511
- writeFileSync3(configFilePath, source.raw, { encoding: "utf8", mode: 384 });
7512
- chmodSync(configFilePath, 384);
7513
- }
7514
- }
7515
- if (configFilePath) {
7516
- args.push("--config-file", configFilePath);
7517
- }
7518
- if (ctx.config.model && ctx.config.model !== "default") {
7519
- args.push("--model", ctx.config.model);
7520
- }
7521
- return {
7522
- args,
7523
- env: buildKimiSpawnEnv(env),
7524
- configFilePath,
7525
- configContent
7526
- };
7527
- }
7528
7444
  function resolveKimiSpawn(commandArgs, deps = {}) {
7529
7445
  return {
7530
7446
  command: resolveCommandOnPath("kimi", deps) ?? "kimi",
@@ -7548,25 +7464,7 @@ var KimiDriver = class {
7548
7464
  };
7549
7465
  model = {
7550
7466
  detectedModelsVerifiedAs: "launchable",
7551
- toLaunchSpec: (modelId, ctx, opts) => {
7552
- if (!ctx) return { args: ["--model", modelId] };
7553
- const launchCtx = {
7554
- ...ctx,
7555
- config: {
7556
- ...ctx.config,
7557
- model: modelId
7558
- }
7559
- };
7560
- const launch = buildKimiLaunchOptions(launchCtx, {
7561
- home: opts?.home,
7562
- writeGeneratedConfig: false
7563
- });
7564
- return {
7565
- args: launch.args,
7566
- env: launch.env,
7567
- configFiles: launch.configFilePath ? [launch.configFilePath] : void 0
7568
- };
7569
- }
7467
+ toLaunchSpec: (modelId) => ({ args: ["--model", modelId] })
7570
7468
  };
7571
7469
  supportsStdinNotification = true;
7572
7470
  busyDeliveryMode = "direct";
@@ -7590,23 +7488,21 @@ var KimiDriver = class {
7590
7488
  ` system_prompt_path: ./${KIMI_SYSTEM_PROMPT_FILE}`,
7591
7489
  ""
7592
7490
  ].join("\n"), "utf8");
7593
- const launch = buildKimiLaunchOptions(ctx);
7594
7491
  const args = [
7595
7492
  "--wire",
7596
7493
  "--yolo",
7597
7494
  "--agent-file",
7598
7495
  agentFilePath,
7599
7496
  "--session",
7600
- this.sessionId,
7601
- ...launch.args
7497
+ this.sessionId
7602
7498
  ];
7603
7499
  const launchRuntimeFields = runtimeConfigToLaunchFields(ctx.config);
7604
7500
  if (launchRuntimeFields.model && launchRuntimeFields.model !== "default") {
7605
7501
  args.push("--model", launchRuntimeFields.model);
7606
7502
  }
7607
7503
  const spawnEnv = (await prepareCliTransport(ctx, { NO_COLOR: "1" })).spawnEnv;
7608
- const spawnTarget = resolveKimiSpawn(args);
7609
- const proc = spawn7(spawnTarget.command, spawnTarget.args, {
7504
+ const launch = resolveKimiSpawn(args);
7505
+ const proc = spawn7(launch.command, launch.args, {
7610
7506
  cwd: ctx.workingDirectory,
7611
7507
  stdio: ["pipe", "pipe", "pipe"],
7612
7508
  env: spawnEnv,
@@ -7614,7 +7510,7 @@ var KimiDriver = class {
7614
7510
  // and has an 8191-character command-line limit. Kimi's official
7615
7511
  // installer/uv entrypoint is an executable, so launch it directly and
7616
7512
  // keep prompts on stdin / files instead of routing through cmd.exe.
7617
- shell: spawnTarget.shell
7513
+ shell: launch.shell
7618
7514
  });
7619
7515
  proc.stdin?.write(JSON.stringify({
7620
7516
  jsonrpc: "2.0",
@@ -7727,9 +7623,14 @@ var KimiDriver = class {
7727
7623
  return detectKimiModels();
7728
7624
  }
7729
7625
  };
7730
- function detectKimiModels(home = os4.homedir(), opts = {}) {
7731
- const raw = readKimiConfigSource(home, opts.env).raw;
7732
- if (raw === null) return null;
7626
+ function detectKimiModels(home = os4.homedir()) {
7627
+ const configPath = path9.join(home, ".kimi", "config.toml");
7628
+ let raw;
7629
+ try {
7630
+ raw = readFileSync3(configPath, "utf8");
7631
+ } catch {
7632
+ return null;
7633
+ }
7733
7634
  const models = [];
7734
7635
  const sectionRe = /^\s*\[models(?:\.([^\]]+)|"\.[^"]+"|\."[^"]+")\s*\]\s*$/gm;
7735
7636
  const lineRe = /^\s*\[models\.(.+?)\s*\]\s*$/gm;
@@ -8395,7 +8296,7 @@ function runOpenCodeModelsCommand(home, deps = {}) {
8395
8296
  const platform = deps.platform ?? process.platform;
8396
8297
  const spawnSyncFn = deps.spawnSyncFn ?? spawnSync2;
8397
8298
  const result = spawnSyncFn("opencode", ["models"], {
8398
- env: scrubDaemonChildEnv({ ...process.env, HOME: home, FORCE_COLOR: "0", NO_COLOR: "1" }),
8299
+ env: { ...process.env, HOME: home, FORCE_COLOR: "0", NO_COLOR: "1" },
8399
8300
  encoding: "utf8",
8400
8301
  timeout: 5e3,
8401
8302
  shell: platform === "win32"
@@ -10440,6 +10341,7 @@ var STDIN_NOTIFICATION_INITIAL_DELAY_MS = 3e3;
10440
10341
  var STDIN_NOTIFICATION_RETRY_DELAY_MS = 15e3;
10441
10342
  var RUNTIME_ERROR_DELIVERY_BACKOFF_BASE_MS = 1e4;
10442
10343
  var RUNTIME_ERROR_DELIVERY_BACKOFF_MAX_MS = 5 * 6e4;
10344
+ var RUNTIME_ERROR_FINGERPRINT_FENCE_THRESHOLD = 3;
10443
10345
  var SPAWN_FAIL_BACKOFF_BASE_MS = 1e3;
10444
10346
  var SPAWN_FAIL_BACKOFF_MAX_MS = 3e4;
10445
10347
  var SPAWN_FAIL_BACKOFF_THRESHOLD = 3;
@@ -11349,6 +11251,7 @@ var AgentProcessManager = class _AgentProcessManager {
11349
11251
  agentStartIntervalMs;
11350
11252
  startingInboxes = /* @__PURE__ */ new Map();
11351
11253
  terminalRuntimeFailures = /* @__PURE__ */ new Map();
11254
+ runtimeErrorFingerprintFences = /* @__PURE__ */ new Map();
11352
11255
  pendingStartRebinds = /* @__PURE__ */ new Map();
11353
11256
  /** Cached configs for agents whose process exited normally — enables auto-restart on next message */
11354
11257
  idleAgentConfigs = /* @__PURE__ */ new Map();
@@ -11515,6 +11418,94 @@ var AgentProcessManager = class _AgentProcessManager {
11515
11418
  if (state.timer) clearTimeout(state.timer);
11516
11419
  this.agentSpawnFailBackoff.delete(agentId);
11517
11420
  }
11421
+ // ----- RUNTIME-ERROR FINGERPRINT FENCE (per-agent) ---------------------
11422
+ // The delivery backoff above is scoped to AgentProcess and is cleared when a
11423
+ // runtime process exits. Recoverable terminal errors intentionally keep an
11424
+ // idle restart cache so the next message can wake the agent, but that also
11425
+ // means a deterministic same-fingerprint runtime error can close/restart
11426
+ // forever. Keep this counter outside AgentProcess and reset only on real turn
11427
+ // progress or explicit stop.
11428
+ runtimeErrorFingerprintFenceResetEvent(eventKind) {
11429
+ switch (eventKind) {
11430
+ case "thinking":
11431
+ case "text":
11432
+ case "tool_call":
11433
+ case "tool_output":
11434
+ case "compaction_finished":
11435
+ case "review_finished":
11436
+ case "turn_end":
11437
+ return true;
11438
+ default:
11439
+ return false;
11440
+ }
11441
+ }
11442
+ resetRuntimeErrorFingerprintFence(agentId, resetSource, ap) {
11443
+ const state = this.runtimeErrorFingerprintFences.get(agentId);
11444
+ if (!state) return;
11445
+ this.runtimeErrorFingerprintFences.delete(agentId);
11446
+ this.recordDaemonTrace("daemon.agent.runtime_error_fingerprint_fence.reset", {
11447
+ agentId,
11448
+ runtime: ap?.config.runtime,
11449
+ model: ap?.config.model,
11450
+ launchId: ap?.launchId || state.launchId || void 0,
11451
+ fingerprint: state.fingerprint,
11452
+ attempts: state.attempts,
11453
+ reset_source: resetSource
11454
+ });
11455
+ }
11456
+ formatRuntimeErrorFingerprintFenceDetail(state) {
11457
+ return [
11458
+ `Runtime stopped after ${state.attempts} repeated runtime errors with the same fingerprint (${state.fingerprint}).`,
11459
+ `Last error: ${state.lastRuntimeError}`,
11460
+ "Restart after the runtime/tooling issue is fixed."
11461
+ ].join(" ");
11462
+ }
11463
+ noteRuntimeErrorFingerprintFence(agentId, ap, message, fingerprint, terminalFailure, stickyTerminalFailure) {
11464
+ if (!fingerprint) return null;
11465
+ if (stickyTerminalFailure || terminalFailure?.actionRequired) return null;
11466
+ let state = this.runtimeErrorFingerprintFences.get(agentId);
11467
+ if (!state || state.fingerprint !== fingerprint) {
11468
+ state = {
11469
+ fingerprint,
11470
+ attempts: 0,
11471
+ lastRuntimeError: message,
11472
+ detail: "",
11473
+ launchId: ap.launchId
11474
+ };
11475
+ this.runtimeErrorFingerprintFences.set(agentId, state);
11476
+ }
11477
+ state.attempts += 1;
11478
+ state.lastRuntimeError = message;
11479
+ state.launchId = ap.launchId;
11480
+ state.detail = this.formatRuntimeErrorFingerprintFenceDetail(state);
11481
+ const fenced = state.attempts >= RUNTIME_ERROR_FINGERPRINT_FENCE_THRESHOLD;
11482
+ this.recordDaemonTrace("daemon.agent.runtime_error_fingerprint_fence", {
11483
+ agentId,
11484
+ runtime: ap.config.runtime,
11485
+ model: ap.config.model,
11486
+ launchId: ap.launchId || void 0,
11487
+ fingerprint,
11488
+ attempts: state.attempts,
11489
+ threshold: RUNTIME_ERROR_FINGERPRINT_FENCE_THRESHOLD,
11490
+ fenced,
11491
+ runtime_error_class: buildRuntimeErrorDiagnosticEnvelope(message).spanAttrs.runtime_error_class
11492
+ }, fenced ? "error" : "ok");
11493
+ return fenced ? state : null;
11494
+ }
11495
+ applyRuntimeErrorFingerprintFence(agentId, ap, state) {
11496
+ this.recordDaemonTrace("daemon.agent.runtime_error_fingerprint_fence.tripped", {
11497
+ agentId,
11498
+ runtime: ap.config.runtime,
11499
+ model: ap.config.model,
11500
+ launchId: ap.launchId || void 0,
11501
+ fingerprint: state.fingerprint,
11502
+ attempts: state.attempts,
11503
+ threshold: RUNTIME_ERROR_FINGERPRINT_FENCE_THRESHOLD
11504
+ }, "error");
11505
+ this.idleAgentConfigs.delete(agentId);
11506
+ this.sendAgentStatus(agentId, "inactive", ap.launchId);
11507
+ this.cleanupTerminalRuntimeFailure(agentId, ap, state.detail);
11508
+ }
11518
11509
  scheduleStdinNotification(agentId, ap, delayMs) {
11519
11510
  return ap.notifications.schedule(() => {
11520
11511
  this.sendStdinNotification(agentId);
@@ -12498,6 +12489,7 @@ var AgentProcessManager = class _AgentProcessManager {
12498
12489
  let prompt;
12499
12490
  let promptSource;
12500
12491
  let wakeMessageDeliveredAsInboxUpdate = false;
12492
+ let startingInboxDeliveredAsInput = false;
12501
12493
  const startingInboxMessages = this.startingInboxes.get(agentId) || [];
12502
12494
  if (runtimeConfig.runtimeProfileControl && !wakeMessage) {
12503
12495
  prompt = driver.supportsNativeStandingPrompt ? NATIVE_STANDING_PROMPT_STARTUP_INPUT : formatRuntimeProfileControlStartupInput(runtimeConfig.runtimeProfileControl, driver);
@@ -12538,6 +12530,10 @@ You also have unread messages in other channels:`;
12538
12530
  Use the inbox/read commands at a natural breakpoint if you choose to inspect those targets.`;
12539
12531
  }
12540
12532
  }
12533
+ } else if (startingInboxMessages.length > 0) {
12534
+ startingInboxDeliveredAsInput = true;
12535
+ prompt = this.formatInboxUpdateRuntimeInput(startingInboxMessages, driver);
12536
+ promptSource = "starting_inbox_update";
12541
12537
  } else if (isResume && unreadSummary && Object.keys(unreadSummary).length > 0) {
12542
12538
  prompt = `You have unread messages from while you were offline:`;
12543
12539
  for (const [ch, count] of Object.entries(unreadSummary)) {
@@ -12670,6 +12666,10 @@ Use ${communicationCommand("read_history")} to catch up on the channels listed a
12670
12666
  }
12671
12667
  if (wakeMessageDeliveredAsInboxUpdate) {
12672
12668
  this.recordInboxUpdateProjection(agentId, agentProcess, agentProcess.inbox, "spawn_wake_inbox_update", "wake", prompt);
12669
+ } else if (startingInboxDeliveredAsInput) {
12670
+ this.recordInboxUpdateProjection(agentId, agentProcess, startingInboxMessages, "spawn_starting_inbox_update", "wake", prompt);
12671
+ this.consumeVisibleMessages(agentId, { messages: startingInboxMessages, source: "spawn_starting_inbox_update" });
12672
+ this.ackInjectedRuntimeProfileMessages(agentId, startingInboxMessages, agentProcess.launchId);
12673
12673
  } else if (wakeMessage && !wakeMessageTransient) {
12674
12674
  this.consumeVisibleMessages(agentId, { messages: [wakeMessage], source: "spawn_wake_message" });
12675
12675
  this.ackInjectedRuntimeProfileMessages(agentId, [wakeMessage], agentProcess.launchId);
@@ -13311,6 +13311,7 @@ Use ${communicationCommand("read_history")} to catch up on the channels listed a
13311
13311
  this.agentVisibleBoundaries.delete(agentId);
13312
13312
  this.agentVisibleMessageIds.delete(agentId);
13313
13313
  this.resetSpawnFailBackoff(agentId);
13314
+ this.resetRuntimeErrorFingerprintFence(agentId, "explicit_stop", ap);
13314
13315
  }
13315
13316
  this.runtimeExitTraceAttrs.set(ap.runtime, {
13316
13317
  stop_source: silent ? "daemon_internal" : "explicit_request",
@@ -13495,6 +13496,19 @@ Use ${communicationCommand("read_history")} to catch up on the channels listed a
13495
13496
  return false;
13496
13497
  });
13497
13498
  }
13499
+ if (!transientDelivery && (this.queuedAgentStarts.has(agentId) || this.agentsStarting.has(agentId))) {
13500
+ const pending = this.startingInboxes.get(agentId) || [];
13501
+ pending.push(message);
13502
+ this.startingInboxes.set(agentId, pending);
13503
+ this.recordDaemonTrace("daemon.agent.delivery.routed", this.deliveryTraceAttrs(agentId, message, {
13504
+ outcome: this.agentsStarting.has(agentId) ? "queued_for_starting_process" : "queued_for_queued_start",
13505
+ accepted: true,
13506
+ process_present: false,
13507
+ cached_idle_config_present: false,
13508
+ starting_inbox_count: pending.length
13509
+ }));
13510
+ return true;
13511
+ }
13498
13512
  logger.warn(`[Agent ${agentId}] Delivery received but no running process or cached idle config exists`);
13499
13513
  if (transientDelivery) {
13500
13514
  this.recordDaemonTrace("daemon.agent.delivery.routed", this.deliveryTraceAttrs(agentId, message, {
@@ -15426,6 +15440,9 @@ Use ${communicationCommand("read_history")} to catch up on the channels listed a
15426
15440
  return;
15427
15441
  }
15428
15442
  this.noteRuntimeProgress(ap, event.kind);
15443
+ if (this.runtimeErrorFingerprintFenceResetEvent(event.kind)) {
15444
+ this.resetRuntimeErrorFingerprintFence(agentId, `runtime_progress:${event.kind}`, ap);
15445
+ }
15429
15446
  recordProgressObservedAfterStall();
15430
15447
  } else if (event.kind !== "internal_progress") {
15431
15448
  this.recordDaemonTrace("daemon.agent.event.received_without_process", {
@@ -15618,6 +15635,7 @@ Use ${communicationCommand("read_history")} to catch up on the channels listed a
15618
15635
  let visibleErrorMessage = event.message;
15619
15636
  if (ap) {
15620
15637
  const runtimeErrorDiagnostics = buildRuntimeErrorDiagnosticEnvelope(event.message);
15638
+ const runtimeErrorFingerprint = typeof runtimeErrorDiagnostics.spanAttrs.runtime_error_fingerprint === "string" ? runtimeErrorDiagnostics.spanAttrs.runtime_error_fingerprint : null;
15621
15639
  if (runtimeErrorDiagnostics.spanAttrs.runtime_error_action_required === true) {
15622
15640
  visibleErrorMessage = formatRuntimeLoginRequiredMessage(ap.driver.id);
15623
15641
  }
@@ -15634,6 +15652,17 @@ Use ${communicationCommand("read_history")} to catch up on the channels listed a
15634
15652
  terminalWakeable: Boolean(ap.driver.supportsStdinNotification && terminalFailure && !terminalFailure.actionRequired)
15635
15653
  });
15636
15654
  this.commitGatedSteeringDecisionState(agentId, ap, reduction.nextState, { event: "error" });
15655
+ const fingerprintFence = this.noteRuntimeErrorFingerprintFence(
15656
+ agentId,
15657
+ ap,
15658
+ event.message,
15659
+ runtimeErrorFingerprint,
15660
+ terminalFailure,
15661
+ stickyTerminalFailure
15662
+ );
15663
+ if (fingerprintFence) {
15664
+ visibleErrorMessage = fingerprintFence.detail;
15665
+ }
15637
15666
  this.noteRuntimeErrorDeliveryBackoff(agentId, ap, event.message, terminalFailure, stickyTerminalFailure, backoffReasonOverride);
15638
15667
  if (reduction.shouldDisableToolBoundaryFlush) {
15639
15668
  this.recordGatedSteeringEvent(agentId, ap, "disabled", {
@@ -15654,7 +15683,9 @@ Use ${communicationCommand("read_history")} to catch up on the channels listed a
15654
15683
  ...runtimeTraceCounterAttrs(ap),
15655
15684
  ...this.finalizeRuntimeProfileTurnControl(agentId, ap, "runtime_error")
15656
15685
  });
15657
- if (ap.driver.supportsStdinNotification && terminalFailure) {
15686
+ if (fingerprintFence) {
15687
+ this.applyRuntimeErrorFingerprintFence(agentId, ap, fingerprintFence);
15688
+ } else if (ap.driver.supportsStdinNotification && terminalFailure) {
15658
15689
  if (terminalFailure.actionRequired) {
15659
15690
  logger.warn(`[Agent ${agentId}] ${ap.driver.id} auth requires user action; terminating runtime process`);
15660
15691
  try {
@@ -17174,9 +17205,10 @@ var DAEMON_CORE_TRACE_ATTR_CONTRACTS = {
17174
17205
  eventAttrs: {
17175
17206
  "daemon.receive": ["seq", "deliveryId"],
17176
17207
  "daemon.deliver_to_agent_manager": ["accepted"],
17208
+ "daemon.delivery.buffered_for_start": ["pending_count"],
17177
17209
  "daemon.ack.sent": ["seq"]
17178
17210
  },
17179
- endAttrs: ["outcome", "ackSeq", "deliveryId", "error_class"]
17211
+ endAttrs: ["outcome", "ackSeq", "deliveryId", "error_class", "pending_count"]
17180
17212
  },
17181
17213
  "daemon.runtime_profile.control.received": {
17182
17214
  spanAttrs: ["agentId", "control_kind", "key_present", "launchId"],
@@ -17222,7 +17254,7 @@ var DAEMON_CORE_TRACE_ATTR_CONTRACTS = {
17222
17254
  spanAttrs: ["agentId", "event_kind", "runtime"]
17223
17255
  }
17224
17256
  };
17225
- var DAEMON_CLI_USAGE = `Usage: slock-daemon --server-url <url> (--api-key <key> or ${DAEMON_API_KEY_ENV}=<key>)`;
17257
+ var DAEMON_CLI_USAGE = "Usage: slock-daemon --server-url <url> --api-key <key>";
17226
17258
  var RunnerCredentialMintError2 = class extends Error {
17227
17259
  code;
17228
17260
  retryable;
@@ -17258,9 +17290,9 @@ function runnerCredentialErrorDetail2(error) {
17258
17290
  async function waitForRunnerCredentialRetry2() {
17259
17291
  await new Promise((resolve) => setTimeout(resolve, RUNNER_CREDENTIAL_MINT_RETRY_DELAY_MS2));
17260
17292
  }
17261
- function parseDaemonCliArgs(args, env = {}) {
17293
+ function parseDaemonCliArgs(args) {
17262
17294
  let serverUrl = "";
17263
- let apiKey = env[DAEMON_API_KEY_ENV] ?? "";
17295
+ let apiKey = "";
17264
17296
  for (let i = 0; i < args.length; i++) {
17265
17297
  if (args[i] === "--server-url" && args[i + 1]) serverUrl = args[++i];
17266
17298
  if (args[i] === "--api-key" && args[i + 1]) apiKey = args[++i];
@@ -17460,6 +17492,8 @@ var DaemonCore = class {
17460
17492
  observedMachineId = null;
17461
17493
  localTraceSink = null;
17462
17494
  traceBundleUploader = null;
17495
+ coreStartingAgentIds = /* @__PURE__ */ new Set();
17496
+ coreStartPendingDeliveries = /* @__PURE__ */ new Map();
17463
17497
  constructor(options) {
17464
17498
  this.options = options;
17465
17499
  this.daemonVersion = options.daemonVersion ?? readDaemonVersion();
@@ -17737,19 +17771,63 @@ var DaemonCore = class {
17737
17771
  }
17738
17772
  );
17739
17773
  }
17774
+ sendDeliveryAck(msg, traceparent) {
17775
+ const ackSeq = msg.seq > 0 ? msg.seq : msg.message.seq ?? 0;
17776
+ const ack = {
17777
+ type: "agent:deliver:ack",
17778
+ agentId: msg.agentId,
17779
+ seq: ackSeq,
17780
+ deliveryId: msg.deliveryId,
17781
+ ...traceparent ? { traceparent } : {}
17782
+ };
17783
+ this.connection.send(ack);
17784
+ }
17740
17785
  async startAgentFromMessage(msg) {
17741
- this.observeRuntimeContext(msg.config);
17742
- const agentCredential = await this.mintRunnerCredential(msg.agentId, msg.config);
17743
- const config = { ...msg.config, agentCredentialKey: agentCredential.apiKey, agentCredentialId: agentCredential.credentialId };
17744
- await this.agentManager.startAgent(
17745
- msg.agentId,
17746
- config,
17747
- msg.wakeMessage,
17748
- msg.unreadSummary,
17749
- msg.resumePrompt,
17750
- msg.launchId,
17751
- msg.wakeMessageTransient ?? false
17752
- );
17786
+ this.coreStartingAgentIds.add(msg.agentId);
17787
+ let wakeDeliveryAck = null;
17788
+ let replayDeliveries = [];
17789
+ try {
17790
+ this.observeRuntimeContext(msg.config);
17791
+ const agentCredential = await this.mintRunnerCredential(msg.agentId, msg.config);
17792
+ const config = { ...msg.config, agentCredentialKey: agentCredential.apiKey, agentCredentialId: agentCredential.credentialId };
17793
+ const pendingDeliveries = this.coreStartPendingDeliveries.get(msg.agentId) || [];
17794
+ this.coreStartPendingDeliveries.delete(msg.agentId);
17795
+ let wakeMessage = msg.wakeMessage;
17796
+ let wakeMessageTransient = msg.wakeMessageTransient ?? false;
17797
+ replayDeliveries = [...pendingDeliveries];
17798
+ if (!wakeMessage) {
17799
+ const wakeIndex = replayDeliveries.findIndex((delivery) => delivery.transient !== true);
17800
+ if (wakeIndex >= 0) {
17801
+ const [wakeDelivery] = replayDeliveries.splice(wakeIndex, 1);
17802
+ if (wakeDelivery) {
17803
+ wakeDeliveryAck = wakeDelivery;
17804
+ wakeMessage = wakeDelivery.message;
17805
+ wakeMessageTransient = wakeDelivery.transient ?? false;
17806
+ }
17807
+ }
17808
+ }
17809
+ await this.agentManager.startAgent(
17810
+ msg.agentId,
17811
+ config,
17812
+ wakeMessage,
17813
+ msg.unreadSummary,
17814
+ msg.resumePrompt,
17815
+ msg.launchId,
17816
+ wakeMessageTransient
17817
+ );
17818
+ this.coreStartingAgentIds.delete(msg.agentId);
17819
+ if (wakeDeliveryAck) {
17820
+ this.sendDeliveryAck(wakeDeliveryAck);
17821
+ }
17822
+ for (const delivery of replayDeliveries) {
17823
+ this.handleMessage(delivery);
17824
+ }
17825
+ } catch (err) {
17826
+ this.coreStartPendingDeliveries.delete(msg.agentId);
17827
+ throw err;
17828
+ } finally {
17829
+ this.coreStartingAgentIds.delete(msg.agentId);
17830
+ }
17753
17831
  }
17754
17832
  handleMessage(msg) {
17755
17833
  const summary = summarizeIncomingMessage(msg);
@@ -17804,6 +17882,14 @@ var DaemonCore = class {
17804
17882
  logger.info(`[Agent ${msg.agentId}] Delivery received (seq=${msg.seq}, from=@${msg.message.sender_name}, target=${formatChannelTarget(msg)})`);
17805
17883
  try {
17806
17884
  span.addEvent("daemon.receive", { seq: msg.seq, deliveryId: msg.deliveryId });
17885
+ if (this.coreStartingAgentIds.has(msg.agentId)) {
17886
+ const pending = this.coreStartPendingDeliveries.get(msg.agentId) || [];
17887
+ pending.push(msg);
17888
+ this.coreStartPendingDeliveries.set(msg.agentId, pending);
17889
+ span.addEvent("daemon.delivery.buffered_for_start", { pending_count: pending.length });
17890
+ span.end("ok", { attrs: { outcome: "buffered-for-start", pending_count: pending.length } });
17891
+ break;
17892
+ }
17807
17893
  const acceptedOrPromise = this.agentManager.deliverMessage(msg.agentId, msg.message, {
17808
17894
  deliveryId: msg.deliveryId,
17809
17895
  transient: msg.transient ?? false
@@ -17816,13 +17902,7 @@ var DaemonCore = class {
17816
17902
  }
17817
17903
  const ackSeq = msg.seq > 0 ? msg.seq : msg.message.seq ?? 0;
17818
17904
  span.addEvent("daemon.ack.sent", { seq: ackSeq });
17819
- this.connection.send({
17820
- type: "agent:deliver:ack",
17821
- agentId: msg.agentId,
17822
- seq: ackSeq,
17823
- traceparent: formatTraceparent(span.context),
17824
- deliveryId: msg.deliveryId
17825
- });
17905
+ this.sendDeliveryAck(msg, formatTraceparent(span.context));
17826
17906
  span.end("ok", { attrs: { outcome: "ack-sent", ackSeq, deliveryId: msg.deliveryId } });
17827
17907
  }, (err) => {
17828
17908
  logger.error(`[Agent ${msg.agentId}] Delivery handling failed`, err);
@@ -18186,8 +18266,6 @@ var DaemonCore = class {
18186
18266
 
18187
18267
  export {
18188
18268
  subscribeDaemonLogs,
18189
- DAEMON_API_KEY_ENV,
18190
- scrubDaemonAuthEnv,
18191
18269
  resolveWorkspaceDirectoryPath,
18192
18270
  scanWorkspaceDirectories,
18193
18271
  deleteWorkspaceDirectory,
package/dist/core.js CHANGED
@@ -1,5 +1,4 @@
1
1
  import {
2
- DAEMON_API_KEY_ENV,
3
2
  DAEMON_CLI_USAGE,
4
3
  DaemonCore,
5
4
  deleteWorkspaceDirectory,
@@ -11,11 +10,9 @@ import {
11
10
  resolveWorkspaceDirectoryPath,
12
11
  runBundledSlockCli,
13
12
  scanWorkspaceDirectories,
14
- scrubDaemonAuthEnv,
15
13
  subscribeDaemonLogs
16
- } from "./chunk-A2AHKVS2.js";
14
+ } from "./chunk-DUWRNQQE.js";
17
15
  export {
18
- DAEMON_API_KEY_ENV,
19
16
  DAEMON_CLI_USAGE,
20
17
  DaemonCore,
21
18
  deleteWorkspaceDirectory,
@@ -27,6 +24,5 @@ export {
27
24
  resolveWorkspaceDirectoryPath,
28
25
  runBundledSlockCli,
29
26
  scanWorkspaceDirectories,
30
- scrubDaemonAuthEnv,
31
27
  subscribeDaemonLogs
32
28
  };
package/dist/index.js CHANGED
@@ -2,13 +2,11 @@
2
2
  import {
3
3
  DAEMON_CLI_USAGE,
4
4
  DaemonCore,
5
- parseDaemonCliArgs,
6
- scrubDaemonAuthEnv
7
- } from "./chunk-A2AHKVS2.js";
5
+ parseDaemonCliArgs
6
+ } from "./chunk-DUWRNQQE.js";
8
7
 
9
8
  // src/index.ts
10
- var parsedArgs = parseDaemonCliArgs(process.argv.slice(2), process.env);
11
- scrubDaemonAuthEnv(process.env);
9
+ var parsedArgs = parseDaemonCliArgs(process.argv.slice(2));
12
10
  if (!parsedArgs) {
13
11
  console.error(DAEMON_CLI_USAGE);
14
12
  process.exit(1);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@botiverse/raft-daemon",
3
- "version": "0.63.5-play.20260623160336",
3
+ "version": "0.63.6",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "raft-daemon": "dist/raft-daemon.js",
@@ -62,6 +62,7 @@
62
62
  "@slock-ai/trace-client": "workspace:*",
63
63
  "@types/node": "^25.5.0",
64
64
  "@types/ws": "^8.18.1",
65
+ "fast-check": "^4.8.0",
65
66
  "tsup": "^8.5.1",
66
67
  "typescript": "^5.9.3"
67
68
  }