@slock-ai/daemon 0.57.0-play.20260606141931 → 0.57.1

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.
@@ -1980,19 +1980,6 @@ function listLegacySlockStatePaths(slockHome = resolveSlockHome(), homeDir = os.
1980
1980
  return candidates.filter((candidate) => existsSync(candidate.path));
1981
1981
  }
1982
1982
 
1983
- // src/authEnv.ts
1984
- var DAEMON_API_KEY_ENV = "SLOCK_MACHINE_API_KEY";
1985
- var SLOCK_AGENT_TOKEN_ENV = "SLOCK_AGENT_TOKEN";
1986
- function scrubDaemonAuthEnv(env) {
1987
- delete env[DAEMON_API_KEY_ENV];
1988
- return env;
1989
- }
1990
- function scrubDaemonChildEnv(env) {
1991
- delete env[DAEMON_API_KEY_ENV];
1992
- delete env[SLOCK_AGENT_TOKEN_ENV];
1993
- return env;
1994
- }
1995
-
1996
1983
  // src/agentCredentialProxy.ts
1997
1984
  import { randomBytes } from "crypto";
1998
1985
  import http from "http";
@@ -2248,6 +2235,412 @@ function reduceApmGatedFlushReadiness(state, input) {
2248
2235
  };
2249
2236
  }
2250
2237
 
2238
+ // src/agentInboxStateMachine.ts
2239
+ var DEFAULT_HELD_CONTEXT_LIMIT = 3;
2240
+ function planAgentInboxSideEffect(input) {
2241
+ const heldContextLimit = input.heldContextLimit ?? DEFAULT_HELD_CONTEXT_LIMIT;
2242
+ const trace = [
2243
+ {
2244
+ step: "input",
2245
+ data: compactTraceData({
2246
+ action: input.action,
2247
+ target: input.target,
2248
+ continueAnyway: input.continueAnyway,
2249
+ pendingCount: input.pendingMessages.length,
2250
+ recentCount: input.recentMessages.length,
2251
+ existingSeenUpToSeq: input.existingSeenUpToSeq,
2252
+ modelSeenSeq: input.modelSeenSeq
2253
+ })
2254
+ }
2255
+ ];
2256
+ if (input.continueAnyway) {
2257
+ appendTrace(trace, "continue_anyway_bypass");
2258
+ return forwardPlan(input, {
2259
+ action: input.action,
2260
+ decision: "bypass",
2261
+ target: input.target,
2262
+ inboxTrustState: "trusted",
2263
+ reason: "continue_anyway"
2264
+ }, trace);
2265
+ }
2266
+ if (input.pendingMessages.length > 0) {
2267
+ appendTrace(trace, "pending_messages_found", { pendingCount: input.pendingMessages.length });
2268
+ const pending = sortInboxMessagesBySeq(normalizeInboxVisibleMessages(input.pendingMessages, input.target));
2269
+ const boundary2 = resolveFreshnessBoundary(pending);
2270
+ if (!boundary2.ok) {
2271
+ appendTrace(trace, "pending_context_missing_boundary");
2272
+ return forwardWithoutDecision(input, trace);
2273
+ }
2274
+ const alreadySeenPending = [];
2275
+ const unconsumedMessages = [];
2276
+ for (const message of pending) {
2277
+ if (isMessageModelSeen(input, message)) {
2278
+ alreadySeenPending.push(message);
2279
+ } else {
2280
+ unconsumedMessages.push(message);
2281
+ }
2282
+ }
2283
+ appendTrace(trace, "pending_context_classified", {
2284
+ pendingCount: pending.length,
2285
+ unseenCount: unconsumedMessages.length
2286
+ });
2287
+ if (unconsumedMessages.length === 0) {
2288
+ const contiguousBoundary = maxKnownContiguousBoundary(input);
2289
+ const canAdvanceBoundary = typeof contiguousBoundary === "number" && contiguousBoundary >= boundary2.seenUpToSeq;
2290
+ appendTrace(trace, "pending_context_already_seen", { boundarySeq: boundary2.seenUpToSeq });
2291
+ return forwardPlan(input, {
2292
+ action: input.action,
2293
+ decision: "forward",
2294
+ target: input.target,
2295
+ inboxTrustState: "trusted",
2296
+ reason: "exact_target_pending_already_seen",
2297
+ pendingCount: pending.length,
2298
+ pendingMaxSeq: boundary2.seenUpToSeq,
2299
+ modelSeenSeq: contiguousBoundary,
2300
+ heldMessageCount: 0,
2301
+ omittedMessageCount: 0
2302
+ }, trace, {
2303
+ forwardSeenUpToSeq: input.action === "send" && canAdvanceBoundary ? boundary2.seenUpToSeq : void 0,
2304
+ consumeEffect: {
2305
+ type: "consume_visible_messages",
2306
+ target: input.target,
2307
+ messages: exactSeenConsumeMessages(input, pending),
2308
+ boundarySeq: canAdvanceBoundary ? boundary2.seenUpToSeq : void 0,
2309
+ source: "side_effect_preflight_context"
2310
+ }
2311
+ });
2312
+ }
2313
+ const heldBoundary = resolveFreshnessBoundary(unconsumedMessages);
2314
+ if (heldBoundary.ok) {
2315
+ const heldMessages = latestVisibleMessages(unconsumedMessages, heldContextLimit);
2316
+ const omittedMessageCount = Math.max(0, unconsumedMessages.length - heldMessages.length);
2317
+ const context = {
2318
+ heldMessages,
2319
+ newMessageCount: unconsumedMessages.length,
2320
+ shownMessageCount: heldMessages.length,
2321
+ omittedMessageCount,
2322
+ seenUpToSeq: heldBoundary.seenUpToSeq
2323
+ };
2324
+ appendTrace(trace, "held_context_built", {
2325
+ boundarySeq: boundary2.seenUpToSeq,
2326
+ heldBoundarySeq: heldBoundary.seenUpToSeq,
2327
+ heldCount: context.shownMessageCount,
2328
+ omittedCount: context.omittedMessageCount
2329
+ });
2330
+ return heldPlan(input, {
2331
+ decision: {
2332
+ action: input.action,
2333
+ decision: "local_hold",
2334
+ target: input.target,
2335
+ inboxTrustState: "trusted",
2336
+ reason: "exact_target_pending",
2337
+ pendingCount: input.pendingMessages.length,
2338
+ pendingMaxSeq: heldBoundary.seenUpToSeq,
2339
+ modelSeenSeq: input.modelSeenSeq,
2340
+ heldMessageCount: context.shownMessageCount,
2341
+ omittedMessageCount: context.omittedMessageCount
2342
+ },
2343
+ context,
2344
+ consumeMessages: sortInboxMessagesBySeq([
2345
+ ...exactSeenConsumeMessages(input, alreadySeenPending),
2346
+ ...context.heldMessages
2347
+ ]),
2348
+ consumeBoundarySeq: heldBoundary.seenUpToSeq
2349
+ }, trace);
2350
+ }
2351
+ appendTrace(trace, "pending_unseen_context_missing_boundary");
2352
+ return forwardWithoutDecision(input, trace);
2353
+ }
2354
+ const boundary = Math.max(input.existingSeenUpToSeq ?? 0, input.modelSeenSeq ?? 0);
2355
+ appendTrace(trace, "model_boundary_checked", { boundary });
2356
+ if (boundary > 0) {
2357
+ appendTrace(trace, "model_boundary_selected", { boundary });
2358
+ return forwardPlan(input, {
2359
+ action: input.action,
2360
+ decision: "forward",
2361
+ target: input.target,
2362
+ inboxTrustState: "trusted",
2363
+ reason: "model_seen_boundary",
2364
+ pendingCount: 0,
2365
+ modelSeenSeq: boundary
2366
+ }, trace, { forwardSeenUpToSeq: input.action === "send" ? boundary : void 0 });
2367
+ }
2368
+ if (input.recentMessages.length > 0) {
2369
+ return planFirstTouchRecentContext(input, heldContextLimit, trace);
2370
+ }
2371
+ appendTrace(trace, "no_context_available");
2372
+ return forwardPlan(input, {
2373
+ action: input.action,
2374
+ decision: "forward",
2375
+ target: input.target,
2376
+ inboxTrustState: "trusted",
2377
+ reason: "no_exact_target_pending_or_recent_context",
2378
+ pendingCount: 0,
2379
+ modelSeenSeq: 0
2380
+ }, trace);
2381
+ }
2382
+ function normalizeInboxVisibleMessage(message, target) {
2383
+ const targetFields = target ? parseTargetFields(target) : {};
2384
+ const normalized = {
2385
+ ...targetFields,
2386
+ ...message,
2387
+ message_id: message.message_id ?? message.id,
2388
+ timestamp: message.timestamp ?? message.createdAt,
2389
+ sender_type: message.sender_type ?? message.senderType,
2390
+ sender_name: message.sender_name ?? message.senderName,
2391
+ sender_description: message.sender_description ?? message.senderDescription ?? null
2392
+ };
2393
+ const senderId = messageSenderId(message);
2394
+ if (senderId) normalized.sender_id = senderId;
2395
+ return normalized;
2396
+ }
2397
+ function normalizeInboxVisibleMessages(messages, target) {
2398
+ return messages.map((message) => normalizeInboxVisibleMessage(message, target));
2399
+ }
2400
+ function maxInboxMessageSeq(messages) {
2401
+ let maxSeq = 0;
2402
+ for (const message of messages) {
2403
+ const seq = Math.floor(messageSeq(message));
2404
+ if (Number.isFinite(seq) && seq > 0) maxSeq = Math.max(maxSeq, seq);
2405
+ }
2406
+ return maxSeq > 0 ? maxSeq : void 0;
2407
+ }
2408
+ function maxKnownContiguousBoundary(input) {
2409
+ const boundary = Math.max(input.existingSeenUpToSeq ?? 0, input.modelSeenSeq ?? 0);
2410
+ return boundary > 0 ? boundary : void 0;
2411
+ }
2412
+ function exactSeenConsumeMessages(input, messages) {
2413
+ const boundary = maxKnownContiguousBoundary(input);
2414
+ return messages.map((message) => {
2415
+ const seq = Math.floor(messageSeq(message));
2416
+ if (Number.isFinite(seq) && seq > 0 && typeof boundary === "number" && boundary >= seq) {
2417
+ return message;
2418
+ }
2419
+ const id = typeof message.message_id === "string" && message.message_id.length > 0 ? message.message_id : typeof message.id === "string" && message.id.length > 0 ? message.id : void 0;
2420
+ return id ? { ...message, seq: void 0 } : message;
2421
+ });
2422
+ }
2423
+ function sortInboxMessagesBySeq(messages) {
2424
+ return [...messages].sort((a, b) => messageSeq(a) - messageSeq(b));
2425
+ }
2426
+ function planFirstTouchRecentContext(input, heldContextLimit, trace) {
2427
+ const recent = sortInboxMessagesBySeq(normalizeInboxVisibleMessages(input.recentMessages, input.target));
2428
+ const unconsumedMessages = recent.filter((message) => !isMessageModelSeen(input, message));
2429
+ appendTrace(trace, "recent_context_loaded", {
2430
+ recentCount: recent.length,
2431
+ unseenCount: unconsumedMessages.length
2432
+ });
2433
+ const boundary = resolveFreshnessBoundary(recent);
2434
+ if (!boundary.ok) {
2435
+ appendTrace(trace, "recent_context_missing_boundary");
2436
+ return forwardPlan(input, {
2437
+ action: input.action,
2438
+ decision: "forward",
2439
+ target: input.target,
2440
+ inboxTrustState: "untrusted",
2441
+ reason: "target_first_touch_recent_context_without_seq_boundary",
2442
+ pendingCount: 0,
2443
+ modelSeenSeq: 0
2444
+ }, trace);
2445
+ }
2446
+ appendTrace(trace, "recent_boundary_resolved", { boundarySeq: boundary.seenUpToSeq });
2447
+ if (unconsumedMessages.length === 0) {
2448
+ appendTrace(trace, "recent_context_already_seen");
2449
+ return forwardPlan(input, {
2450
+ action: input.action,
2451
+ decision: "forward",
2452
+ target: input.target,
2453
+ inboxTrustState: "untrusted",
2454
+ reason: "target_first_touch_recent_context_already_seen",
2455
+ pendingCount: 0,
2456
+ pendingMaxSeq: boundary.seenUpToSeq,
2457
+ modelSeenSeq: boundary.seenUpToSeq,
2458
+ heldMessageCount: 0,
2459
+ omittedMessageCount: 0
2460
+ }, trace, {
2461
+ forwardSeenUpToSeq: input.action === "send" ? boundary.seenUpToSeq : void 0,
2462
+ consumeEffect: {
2463
+ type: "consume_visible_messages",
2464
+ target: input.target,
2465
+ messages: recent,
2466
+ boundarySeq: boundary.seenUpToSeq,
2467
+ source: "side_effect_preflight_context"
2468
+ }
2469
+ });
2470
+ }
2471
+ const heldBoundary = resolveFreshnessBoundary(unconsumedMessages);
2472
+ if (!heldBoundary.ok) {
2473
+ appendTrace(trace, "unseen_context_missing_boundary");
2474
+ return forwardPlan(input, {
2475
+ action: input.action,
2476
+ decision: "forward",
2477
+ target: input.target,
2478
+ inboxTrustState: "untrusted",
2479
+ reason: "target_first_touch_unseen_context_without_seq_boundary",
2480
+ pendingCount: 0,
2481
+ modelSeenSeq: 0
2482
+ }, trace);
2483
+ }
2484
+ appendTrace(trace, "unseen_boundary_resolved", { boundarySeq: heldBoundary.seenUpToSeq });
2485
+ const heldMessages = latestVisibleMessages(unconsumedMessages, heldContextLimit);
2486
+ const omittedMessageCount = Math.max(0, unconsumedMessages.length - heldMessages.length);
2487
+ appendTrace(trace, "unseen_hold_selected", {
2488
+ heldCount: heldMessages.length,
2489
+ omittedCount: omittedMessageCount,
2490
+ consumeBoundarySeq: boundary.seenUpToSeq
2491
+ });
2492
+ return heldPlan(input, {
2493
+ decision: {
2494
+ action: input.action,
2495
+ decision: "syncing_hold",
2496
+ target: input.target,
2497
+ inboxTrustState: "untrusted",
2498
+ reason: "target_first_touch_recent_context",
2499
+ pendingCount: 0,
2500
+ pendingMaxSeq: heldBoundary.seenUpToSeq,
2501
+ modelSeenSeq: 0,
2502
+ heldMessageCount: heldMessages.length,
2503
+ omittedMessageCount
2504
+ },
2505
+ context: {
2506
+ heldMessages,
2507
+ newMessageCount: unconsumedMessages.length,
2508
+ shownMessageCount: heldMessages.length,
2509
+ omittedMessageCount,
2510
+ seenUpToSeq: boundary.seenUpToSeq
2511
+ },
2512
+ consumeMessages: recent,
2513
+ consumeBoundarySeq: boundary.seenUpToSeq
2514
+ }, trace);
2515
+ }
2516
+ function heldPlan(input, held, trace) {
2517
+ const producerFactId = buildApmFreshnessDecisionProducerFactId(input.agentId, held.decision);
2518
+ const decision = { ...held.decision, producerFactId };
2519
+ appendTrace(trace, "plan_built", {
2520
+ outcome: "held",
2521
+ decision: decision.decision,
2522
+ effectCount: 2,
2523
+ localResponseState: "held",
2524
+ seenUpToSeq: held.context.seenUpToSeq
2525
+ });
2526
+ return {
2527
+ outcome: "held",
2528
+ target: input.target,
2529
+ effects: [
2530
+ {
2531
+ type: "consume_visible_messages",
2532
+ target: input.target,
2533
+ messages: held.consumeMessages,
2534
+ boundarySeq: held.consumeBoundarySeq,
2535
+ source: "side_effect_preflight_context"
2536
+ },
2537
+ { type: "record_freshness_decision", decision }
2538
+ ],
2539
+ trace,
2540
+ localResponse: projectApmHeldFreshnessEnvelope({
2541
+ producerFactId,
2542
+ action: input.action,
2543
+ heldMessages: held.context.heldMessages,
2544
+ newMessageCount: held.context.newMessageCount,
2545
+ omittedMessageCount: held.context.omittedMessageCount,
2546
+ seenUpToSeq: held.context.seenUpToSeq
2547
+ }).body
2548
+ };
2549
+ }
2550
+ function forwardPlan(input, decision, trace, options = {}) {
2551
+ appendTrace(trace, "plan_built", {
2552
+ outcome: "forward",
2553
+ decision: decision.decision,
2554
+ effectCount: options.consumeEffect ? 2 : 1,
2555
+ forwardSeenUpToSeq: options.forwardSeenUpToSeq
2556
+ });
2557
+ return {
2558
+ outcome: "forward",
2559
+ target: input.target,
2560
+ forwardSeenUpToSeq: options.forwardSeenUpToSeq,
2561
+ effects: [
2562
+ ...options.consumeEffect ? [options.consumeEffect] : [],
2563
+ { type: "record_freshness_decision", decision }
2564
+ ],
2565
+ trace
2566
+ };
2567
+ }
2568
+ function forwardWithoutDecision(input, trace) {
2569
+ appendTrace(trace, "plan_built", {
2570
+ outcome: "forward",
2571
+ decision: "none",
2572
+ effectCount: 0
2573
+ });
2574
+ return {
2575
+ outcome: "forward",
2576
+ target: input.target,
2577
+ effects: [],
2578
+ trace
2579
+ };
2580
+ }
2581
+ function resolveFreshnessBoundary(messages) {
2582
+ const seenUpToSeq = maxInboxMessageSeq(messages);
2583
+ return typeof seenUpToSeq === "number" ? { ok: true, seenUpToSeq } : { ok: false, reason: "missing_seq_boundary" };
2584
+ }
2585
+ function latestVisibleMessages(messages, limit) {
2586
+ const sorted = sortInboxMessagesBySeq(messages);
2587
+ return sorted.slice(Math.max(0, sorted.length - limit));
2588
+ }
2589
+ function isMessageModelSeen(input, message) {
2590
+ const seq = Math.floor(messageSeq(message));
2591
+ if (Number.isFinite(seq) && seq > 0 && typeof input.modelSeenSeq === "number" && input.modelSeenSeq >= seq) return true;
2592
+ return input.isMessageModelSeen?.({ target: input.target, message }) === true;
2593
+ }
2594
+ function messageSeq(message) {
2595
+ return Number(message.seq ?? 0);
2596
+ }
2597
+ function messageSenderId(message) {
2598
+ if (typeof message.sender_id === "string" && message.sender_id.length > 0) return message.sender_id;
2599
+ if (typeof message.senderId === "string" && message.senderId.length > 0) return message.senderId;
2600
+ return void 0;
2601
+ }
2602
+ function appendTrace(trace, step, data) {
2603
+ const compacted = compactTraceData(data);
2604
+ trace.push(Object.keys(compacted).length > 0 ? { step, data: compacted } : { step });
2605
+ }
2606
+ function compactTraceData(data) {
2607
+ const compacted = {};
2608
+ if (!data) return compacted;
2609
+ for (const [key, value] of Object.entries(data)) {
2610
+ if (value !== void 0) compacted[key] = value;
2611
+ }
2612
+ return compacted;
2613
+ }
2614
+ function parseTargetFields(target) {
2615
+ if (target.startsWith("dm:@")) {
2616
+ const rest = target.slice("dm:@".length);
2617
+ const [peer, threadId] = rest.split(":", 2);
2618
+ if (threadId) {
2619
+ return {
2620
+ channel_type: "thread",
2621
+ channel_name: threadId,
2622
+ parent_channel_type: "dm",
2623
+ parent_channel_name: peer
2624
+ };
2625
+ }
2626
+ return { channel_type: "dm", channel_name: peer };
2627
+ }
2628
+ if (target.startsWith("#")) {
2629
+ const rest = target.slice(1);
2630
+ const [channel, threadId] = rest.split(":", 2);
2631
+ if (threadId) {
2632
+ return {
2633
+ channel_type: "thread",
2634
+ channel_name: threadId,
2635
+ parent_channel_type: "channel",
2636
+ parent_channel_name: channel
2637
+ };
2638
+ }
2639
+ return { channel_type: "channel", channel_name: channel };
2640
+ }
2641
+ return {};
2642
+ }
2643
+
2251
2644
  // src/agentInboxProjection.ts
2252
2645
  function projectAgentInboxSnapshot(messages) {
2253
2646
  const buckets = /* @__PURE__ */ new Map();
@@ -2277,16 +2670,16 @@ function projectBucket(target, messages) {
2277
2670
  channelType: latest.channel_type,
2278
2671
  pendingCount: messages.length,
2279
2672
  firstPendingMsgId: messageId(first),
2280
- firstPendingSeq: messageSeq(first),
2673
+ firstPendingSeq: messageSeq2(first),
2281
2674
  latestMsgId: messageId(latest),
2282
- latestSeq: messageSeq(latest),
2675
+ latestSeq: messageSeq2(latest),
2283
2676
  latestSenderName: latest.sender_name ?? latest.senderName,
2284
2677
  latestSenderType: normalizeSenderType(latest.sender_type ?? latest.senderType),
2285
2678
  flags: [...flags].sort()
2286
2679
  });
2287
2680
  }
2288
2681
  function compareInboxMessages(a, b) {
2289
- return (messageSeq(a) ?? 0) - (messageSeq(b) ?? 0) || (messageId(a) ?? "").localeCompare(messageId(b) ?? "");
2682
+ return (messageSeq2(a) ?? 0) - (messageSeq2(b) ?? 0) || (messageId(a) ?? "").localeCompare(messageId(b) ?? "");
2290
2683
  }
2291
2684
  function formatInboxMessageTarget(message) {
2292
2685
  if (message.channel_type === "thread" && message.parent_channel_name && message.channel_name) {
@@ -2302,7 +2695,7 @@ function messageId(message) {
2302
2695
  if (!message) return void 0;
2303
2696
  return nonEmptyString(message.message_id) ?? nonEmptyString(message.id);
2304
2697
  }
2305
- function messageSeq(message) {
2698
+ function messageSeq2(message) {
2306
2699
  if (!message || typeof message.seq !== "number" || !Number.isFinite(message.seq) || message.seq <= 0) return void 0;
2307
2700
  return Math.floor(message.seq);
2308
2701
  }
@@ -2827,42 +3220,9 @@ async function readRequestBody(req) {
2827
3220
  }
2828
3221
  return Buffer.concat(chunks);
2829
3222
  }
2830
- function messageSeq2(message) {
3223
+ function messageSeq3(message) {
2831
3224
  return Number(message.seq ?? 0);
2832
3225
  }
2833
- function maxMessageSeq(messages) {
2834
- let maxSeq = 0;
2835
- for (const message of messages) {
2836
- const seq = Math.floor(messageSeq2(message));
2837
- if (Number.isFinite(seq) && seq > 0) maxSeq = Math.max(maxSeq, seq);
2838
- }
2839
- return maxSeq > 0 ? maxSeq : void 0;
2840
- }
2841
- function messageSenderId(message) {
2842
- if (typeof message.sender_id === "string" && message.sender_id.length > 0) return message.sender_id;
2843
- if (typeof message.senderId === "string" && message.senderId.length > 0) return message.senderId;
2844
- return void 0;
2845
- }
2846
- function isSelfAuthoredMessage(registration, message) {
2847
- return messageSenderId(message) === registration.agentId;
2848
- }
2849
- function isMessageModelSeen(coordinator, target, message) {
2850
- const seq = Math.floor(messageSeq2(message));
2851
- const boundary = coordinator.getBoundary(target);
2852
- if (Number.isFinite(seq) && seq > 0 && typeof boundary === "number" && boundary >= seq) return true;
2853
- return coordinator.isMessageModelSeen?.({ target, message }) === true;
2854
- }
2855
- function resolveFreshnessBoundary(messages) {
2856
- const seenUpToSeq = maxMessageSeq(messages);
2857
- return typeof seenUpToSeq === "number" ? { ok: true, seenUpToSeq } : { ok: false, reason: "missing_seq_boundary" };
2858
- }
2859
- function sortBySeq(messages) {
2860
- return [...messages].sort((a, b) => messageSeq2(a) - messageSeq2(b));
2861
- }
2862
- function latestVisibleMessages(messages, limit) {
2863
- const sorted = sortBySeq(messages);
2864
- return sorted.slice(Math.max(0, sorted.length - limit));
2865
- }
2866
3226
  function localAgentApiInboxResponse(registration) {
2867
3227
  const coordinator = registration.inboxCoordinator;
2868
3228
  if (!coordinator) return void 0;
@@ -2910,9 +3270,9 @@ function localAgentApiEventsResponse(registration, target) {
2910
3270
  return { status: 400, body: parsedQuery.error };
2911
3271
  }
2912
3272
  if (pending.length === 0) return void 0;
2913
- const normalized = sortBySeq(normalizeVisibleMessages(pending));
3273
+ const normalized = sortInboxMessagesBySeq(normalizeInboxVisibleMessages(pending));
2914
3274
  const filtered = parsedQuery.sinceSeq !== null ? normalized.filter((message) => {
2915
- const seq = messageSeq2(message);
3275
+ const seq = messageSeq3(message);
2916
3276
  return Number.isFinite(seq) && seq > parsedQuery.sinceSeq;
2917
3277
  }) : normalized;
2918
3278
  const events = filtered.slice(0, parsedQuery.limit);
@@ -2921,7 +3281,7 @@ function localAgentApiEventsResponse(registration, target) {
2921
3281
  const lastSeenMsgId = newestEvent?.message_id ?? newestEvent?.id ?? null;
2922
3282
  const lastSeenSeq = newestEvent?.seq ?? parsedQuery.sinceSeq;
2923
3283
  if (events.length > 0) {
2924
- coordinator.consumeVisibleMessages({ messages: events, source: "agent_api_events" });
3284
+ coordinator.consumeVisibleMessages({ messages: events, source: "agent_api_events_local" });
2925
3285
  }
2926
3286
  coordinator.recordDrainOutcome?.({
2927
3287
  source: "daemon_pending",
@@ -2943,30 +3303,6 @@ function localAgentApiEventsResponse(registration, target) {
2943
3303
  }
2944
3304
  };
2945
3305
  }
2946
- function localHeldContext(input) {
2947
- if (input.messages.length === 0) return { ok: false, reason: "empty_context" };
2948
- const normalized = sortBySeq(normalizeVisibleMessages(input.messages, input.target));
2949
- const heldMessages = latestVisibleMessages(normalized, LOCAL_HELD_CONTEXT_LIMIT);
2950
- const omittedMessageCount = Math.max(0, normalized.length - heldMessages.length);
2951
- const boundary = resolveFreshnessBoundary(normalized);
2952
- if (!boundary.ok) return boundary;
2953
- input.coordinator.consumeVisibleMessages({
2954
- target: input.target,
2955
- messages: heldMessages,
2956
- boundarySeq: boundary.seenUpToSeq,
2957
- source: input.source
2958
- });
2959
- return {
2960
- ok: true,
2961
- context: {
2962
- heldMessages,
2963
- newMessageCount: normalized.length,
2964
- shownMessageCount: heldMessages.length,
2965
- omittedMessageCount,
2966
- seenUpToSeq: boundary.seenUpToSeq
2967
- }
2968
- };
2969
- }
2970
3306
  function recordFreshnessDecision(coordinator, decision) {
2971
3307
  coordinator?.recordFreshnessDecision?.(decision);
2972
3308
  }
@@ -2980,53 +3316,6 @@ function sideEffectTarget(action, body) {
2980
3316
  const field = action === "send" ? body.target : body.channel;
2981
3317
  return typeof field === "string" && field.length > 0 ? field : void 0;
2982
3318
  }
2983
- function parseTargetFields(target) {
2984
- if (target.startsWith("dm:@")) {
2985
- const rest = target.slice("dm:@".length);
2986
- const [peer, threadId] = rest.split(":", 2);
2987
- if (threadId) {
2988
- return {
2989
- channel_type: "thread",
2990
- channel_name: threadId,
2991
- parent_channel_type: "dm",
2992
- parent_channel_name: peer
2993
- };
2994
- }
2995
- return { channel_type: "dm", channel_name: peer };
2996
- }
2997
- if (target.startsWith("#")) {
2998
- const rest = target.slice(1);
2999
- const [channel, threadId] = rest.split(":", 2);
3000
- if (threadId) {
3001
- return {
3002
- channel_type: "thread",
3003
- channel_name: threadId,
3004
- parent_channel_type: "channel",
3005
- parent_channel_name: channel
3006
- };
3007
- }
3008
- return { channel_type: "channel", channel_name: channel };
3009
- }
3010
- return {};
3011
- }
3012
- function normalizeVisibleMessage(message, target) {
3013
- const targetFields = target ? parseTargetFields(target) : {};
3014
- const normalized = {
3015
- ...targetFields,
3016
- ...message,
3017
- message_id: message.message_id ?? message.id,
3018
- timestamp: message.timestamp ?? message.createdAt,
3019
- sender_type: message.sender_type ?? message.senderType,
3020
- sender_name: message.sender_name ?? message.senderName,
3021
- sender_description: message.sender_description ?? message.senderDescription ?? null
3022
- };
3023
- const senderId = messageSenderId(message);
3024
- if (senderId) normalized.sender_id = senderId;
3025
- return normalized;
3026
- }
3027
- function normalizeVisibleMessages(messages, target) {
3028
- return messages.map((message) => normalizeVisibleMessage(message, target));
3029
- }
3030
3319
  async function loadRecentTargetMessages(registration, headers, target) {
3031
3320
  const historyUrl = new URL2("/internal/agent-api/history", registration.serverUrl);
3032
3321
  historyUrl.searchParams.set("channel", target);
@@ -3036,181 +3325,57 @@ async function loadRecentTargetMessages(registration, headers, target) {
3036
3325
  historyHeaders.delete("content-type");
3037
3326
  const res = await fetch(historyUrl, { method: "GET", headers: historyHeaders });
3038
3327
  if (!res.ok) return [];
3039
- const parsed = await res.json().catch(() => null);
3040
- return Array.isArray(parsed?.messages) ? normalizeVisibleMessages(parsed.messages, target) : [];
3041
- }
3042
- async function prepareAgentApiSideEffectForward(registration, headers, rawBody, action) {
3043
- let body;
3044
- try {
3045
- body = rawBody ? JSON.parse(rawBody) : {};
3046
- } catch {
3047
- return { bodyText: rawBody };
3048
- }
3049
- const target = sideEffectTarget(action, body);
3050
- const coordinator = registration.inboxCoordinator;
3051
- if (!target || !coordinator) {
3052
- return { bodyText: JSON.stringify(body), target };
3053
- }
3054
- if (action === "send" && body.continueAnyway === true) {
3055
- recordFreshnessDecision(coordinator, {
3056
- action,
3057
- decision: "bypass",
3058
- target,
3059
- inboxTrustState: "trusted",
3060
- reason: "continue_anyway"
3061
- });
3062
- return { bodyText: JSON.stringify(body), target };
3063
- }
3064
- const pending = coordinator.getPendingMessages(target);
3065
- if (pending.length > 0) {
3066
- const modelSeenSeq = coordinator.getBoundary(target);
3067
- const contextResult = localHeldContext({
3068
- target,
3069
- messages: pending,
3070
- coordinator,
3071
- source: "side_effect_preflight_context"
3072
- });
3073
- if (contextResult.ok) {
3074
- const { context } = contextResult;
3075
- const decision = {
3076
- action,
3077
- decision: "local_hold",
3078
- target,
3079
- inboxTrustState: "trusted",
3080
- reason: "exact_target_pending",
3081
- pendingCount: pending.length,
3082
- pendingMaxSeq: context.seenUpToSeq,
3083
- modelSeenSeq,
3084
- heldMessageCount: context.shownMessageCount,
3085
- omittedMessageCount: context.omittedMessageCount
3086
- };
3087
- const producerFactId = buildApmFreshnessDecisionProducerFactId(registration.agentId, decision);
3088
- const localResponse = projectApmHeldFreshnessEnvelope({
3089
- producerFactId,
3090
- action,
3091
- heldMessages: context.heldMessages,
3092
- newMessageCount: context.newMessageCount,
3093
- omittedMessageCount: context.omittedMessageCount,
3094
- seenUpToSeq: context.seenUpToSeq
3095
- }).body;
3096
- recordFreshnessDecision(coordinator, { ...decision, producerFactId });
3097
- return {
3098
- bodyText: JSON.stringify(body),
3099
- target,
3100
- localResponse
3101
- };
3102
- }
3103
- return {
3104
- bodyText: JSON.stringify(body),
3105
- target
3106
- };
3107
- }
3108
- const existingBoundary = typeof body.seenUpToSeq === "number" && Number.isFinite(body.seenUpToSeq) ? Math.max(0, Math.floor(body.seenUpToSeq)) : void 0;
3109
- const loadedBoundary = coordinator.getBoundary(target);
3110
- const boundary = Math.max(existingBoundary ?? 0, loadedBoundary ?? 0);
3111
- if (boundary > 0) {
3112
- if (action === "send") body.seenUpToSeq = boundary;
3113
- recordFreshnessDecision(coordinator, {
3114
- action,
3115
- decision: "forward",
3116
- target,
3117
- inboxTrustState: "trusted",
3118
- reason: "model_seen_boundary",
3119
- pendingCount: 0,
3120
- modelSeenSeq: boundary
3121
- });
3122
- return { bodyText: JSON.stringify(body), target };
3123
- }
3124
- const recent = await loadRecentTargetMessages(registration, headers, target);
3125
- if (recent.length > 0) {
3126
- const unconsumedCounterparty = recent.filter(
3127
- (message) => !isSelfAuthoredMessage(registration, message) && !isMessageModelSeen(coordinator, target, message)
3128
- );
3129
- const boundary2 = resolveFreshnessBoundary(recent);
3130
- if (!boundary2.ok) {
3131
- recordFreshnessDecision(coordinator, {
3132
- action,
3133
- decision: "forward",
3134
- target,
3135
- inboxTrustState: "untrusted",
3136
- reason: "target_first_touch_recent_context_without_seq_boundary",
3137
- pendingCount: 0,
3138
- modelSeenSeq: 0
3139
- });
3140
- return { bodyText: JSON.stringify(body), target };
3141
- }
3142
- if (unconsumedCounterparty.length === 0) {
3143
- const { seenUpToSeq: seenUpToSeq2 } = boundary2;
3144
- if (action === "send") body.seenUpToSeq = seenUpToSeq2;
3145
- coordinator.consumeVisibleMessages({ target, messages: recent, boundarySeq: seenUpToSeq2, source: "side_effect_preflight_context" });
3146
- recordFreshnessDecision(coordinator, {
3147
- action,
3148
- decision: "forward",
3149
- target,
3150
- inboxTrustState: "untrusted",
3151
- reason: "target_first_touch_recent_context_already_seen",
3152
- pendingCount: 0,
3153
- pendingMaxSeq: seenUpToSeq2,
3154
- modelSeenSeq: seenUpToSeq2,
3155
- heldMessageCount: 0,
3156
- omittedMessageCount: 0
3157
- });
3158
- return { bodyText: JSON.stringify(body), target };
3328
+ const parsed = await res.json().catch(() => null);
3329
+ return Array.isArray(parsed?.messages) ? normalizeInboxVisibleMessages(parsed.messages, target) : [];
3330
+ }
3331
+ function applyAgentInboxStateMachineEffects(coordinator, effects) {
3332
+ for (const effect of effects) {
3333
+ if (effect.type === "record_freshness_decision") {
3334
+ recordFreshnessDecision(coordinator, effect.decision);
3335
+ continue;
3159
3336
  }
3160
- const heldBoundary = resolveFreshnessBoundary(unconsumedCounterparty);
3161
- if (!heldBoundary.ok) {
3162
- recordFreshnessDecision(coordinator, {
3163
- action,
3164
- decision: "forward",
3165
- target,
3166
- inboxTrustState: "untrusted",
3167
- reason: "target_first_touch_counterparty_context_without_seq_boundary",
3168
- pendingCount: 0,
3169
- modelSeenSeq: 0
3170
- });
3171
- return { bodyText: JSON.stringify(body), target };
3172
- }
3173
- const heldMessages = latestVisibleMessages(unconsumedCounterparty, LOCAL_HELD_CONTEXT_LIMIT);
3174
- const omittedMessageCount = Math.max(0, unconsumedCounterparty.length - heldMessages.length);
3175
- const { seenUpToSeq } = boundary2;
3176
- coordinator.consumeVisibleMessages({ target, messages: recent, boundarySeq: seenUpToSeq, source: "side_effect_preflight_context" });
3177
- const decision = {
3178
- action,
3179
- decision: "syncing_hold",
3180
- target,
3181
- inboxTrustState: "untrusted",
3182
- reason: "target_first_touch_recent_context",
3183
- pendingCount: 0,
3184
- pendingMaxSeq: heldBoundary.seenUpToSeq,
3185
- modelSeenSeq: 0,
3186
- heldMessageCount: heldMessages.length,
3187
- omittedMessageCount
3188
- };
3189
- const producerFactId = buildApmFreshnessDecisionProducerFactId(registration.agentId, decision);
3190
- recordFreshnessDecision(coordinator, { ...decision, producerFactId });
3191
- return {
3192
- bodyText: JSON.stringify(body),
3193
- target,
3194
- localResponse: projectApmHeldFreshnessEnvelope({
3195
- producerFactId,
3196
- action,
3197
- heldMessages,
3198
- newMessageCount: unconsumedCounterparty.length,
3199
- omittedMessageCount,
3200
- seenUpToSeq
3201
- }).body
3202
- };
3337
+ coordinator.consumeVisibleMessages({
3338
+ target: effect.target,
3339
+ messages: effect.messages,
3340
+ boundarySeq: effect.boundarySeq,
3341
+ source: effect.source
3342
+ });
3343
+ }
3344
+ }
3345
+ async function prepareAgentApiSideEffectForward(registration, headers, rawBody, action) {
3346
+ let body;
3347
+ try {
3348
+ body = rawBody ? JSON.parse(rawBody) : {};
3349
+ } catch {
3350
+ return { bodyText: rawBody };
3351
+ }
3352
+ const target = sideEffectTarget(action, body);
3353
+ const coordinator = registration.inboxCoordinator;
3354
+ if (!target || !coordinator) {
3355
+ return { bodyText: JSON.stringify(body), target };
3203
3356
  }
3204
- recordFreshnessDecision(coordinator, {
3357
+ const pending = coordinator.getPendingMessages(target);
3358
+ const existingBoundary = typeof body.seenUpToSeq === "number" && Number.isFinite(body.seenUpToSeq) ? Math.max(0, Math.floor(body.seenUpToSeq)) : void 0;
3359
+ const continueAnyway = action === "send" && body.continueAnyway === true;
3360
+ const shouldLoadRecent = pending.length === 0 && !continueAnyway && Math.max(existingBoundary ?? 0, coordinator.getBoundary(target) ?? 0) <= 0;
3361
+ const recent = shouldLoadRecent ? await loadRecentTargetMessages(registration, headers, target) : [];
3362
+ const plan = planAgentInboxSideEffect({
3363
+ agentId: registration.agentId,
3205
3364
  action,
3206
- decision: "forward",
3207
3365
  target,
3208
- inboxTrustState: "trusted",
3209
- reason: "no_exact_target_pending_or_recent_context",
3210
- pendingCount: 0,
3211
- modelSeenSeq: 0
3366
+ continueAnyway,
3367
+ existingSeenUpToSeq: existingBoundary,
3368
+ modelSeenSeq: coordinator.getBoundary(target),
3369
+ pendingMessages: pending,
3370
+ recentMessages: recent,
3371
+ isMessageModelSeen: (messageInput) => coordinator.isMessageModelSeen?.(messageInput) === true,
3372
+ heldContextLimit: LOCAL_HELD_CONTEXT_LIMIT
3212
3373
  });
3213
- return { bodyText: JSON.stringify(body), target };
3374
+ applyAgentInboxStateMachineEffects(coordinator, plan.effects);
3375
+ if (typeof plan.forwardSeenUpToSeq === "number") {
3376
+ if (action === "send") body.seenUpToSeq = plan.forwardSeenUpToSeq;
3377
+ }
3378
+ return { bodyText: JSON.stringify(body), target, localResponse: plan.localResponse };
3214
3379
  }
3215
3380
  function shouldBufferJsonResponse(upstream, pathname, registration) {
3216
3381
  if (!registration.inboxCoordinator) return false;
@@ -3230,27 +3395,26 @@ function consumeVisibleResponse(registration, targetUrl, sendTarget, responseTex
3230
3395
  if (targetUrl.pathname === "/internal/agent-api/send" && parsed.state === "held" && Array.isArray(parsed.heldMessages)) {
3231
3396
  coordinator.consumeVisibleMessages({
3232
3397
  target: sendTarget,
3233
- messages: normalizeVisibleMessages(parsed.heldMessages, sendTarget),
3398
+ messages: normalizeInboxVisibleMessages(parsed.heldMessages, sendTarget),
3234
3399
  boundarySeq: typeof parsed.seenUpToSeq === "number" ? parsed.seenUpToSeq : void 0,
3235
3400
  source: "server_held_context"
3236
3401
  });
3237
3402
  return;
3238
3403
  }
3239
3404
  if (targetUrl.pathname === "/internal/agent-api/send" && parsed.state === "sent") {
3240
- const messageSeq3 = typeof parsed.messageSeq === "number" && Number.isFinite(parsed.messageSeq) ? Math.floor(parsed.messageSeq) : void 0;
3241
- if (sendTarget && messageSeq3 && messageSeq3 > 0) {
3405
+ const messageSeq4 = typeof parsed.messageSeq === "number" && Number.isFinite(parsed.messageSeq) ? Math.floor(parsed.messageSeq) : void 0;
3406
+ if (sendTarget && messageSeq4 && messageSeq4 > 0) {
3242
3407
  coordinator.consumeVisibleMessages({
3243
3408
  target: sendTarget,
3244
- messages: normalizeVisibleMessages([{ seq: messageSeq3, id: parsed.messageId }], sendTarget),
3245
- boundarySeq: messageSeq3,
3409
+ messages: normalizeInboxVisibleMessages([{ id: parsed.messageId }], sendTarget),
3246
3410
  source: "agent_api_send_commit"
3247
3411
  });
3248
3412
  }
3249
3413
  return;
3250
3414
  }
3251
3415
  if (targetUrl.pathname === "/internal/agent-api/events" && Array.isArray(parsed.events)) {
3252
- const messages = normalizeVisibleMessages(parsed.events);
3253
- coordinator.consumeVisibleMessages({ messages, source: "agent_api_events" });
3416
+ const messages = normalizeInboxVisibleMessages(parsed.events);
3417
+ coordinator.consumeVisibleMessages({ messages, source: "agent_api_events_server" });
3254
3418
  coordinator.recordDrainOutcome?.({
3255
3419
  source: "server_events",
3256
3420
  sinceCursorKind: parseAgentApiEventsQuery(targetUrl).sinceCursorKind,
@@ -3262,8 +3426,8 @@ function consumeVisibleResponse(registration, targetUrl, sendTarget, responseTex
3262
3426
  }
3263
3427
  if (targetUrl.pathname === "/internal/agent-api/history" && Array.isArray(parsed.messages)) {
3264
3428
  const target = targetUrl.searchParams.get("channel") ?? void 0;
3265
- const messages = normalizeVisibleMessages(parsed.messages, target);
3266
- coordinator.consumeVisibleMessages({ target, messages, boundarySeq: maxMessageSeq(messages), source: "agent_api_history" });
3429
+ const messages = normalizeInboxVisibleMessages(parsed.messages, target);
3430
+ coordinator.consumeVisibleMessages({ target, messages, boundarySeq: maxInboxMessageSeq(messages), source: "agent_api_history" });
3267
3431
  }
3268
3432
  }
3269
3433
  async function registerAgentCredentialProxy(input) {
@@ -3302,9 +3466,7 @@ var LOOPBACK_NO_PROXY = "127.0.0.1,localhost";
3302
3466
  var CLI_TRANSPORT_TRACE_DIR_ENV = "SLOCK_CLI_TRANSPORT_TRACE_DIR";
3303
3467
  var safePathPart = (value) => value.replace(/[^a-zA-Z0-9_.-]/g, "_");
3304
3468
  var RAW_CREDENTIAL_ENV_DENYLIST = [
3305
- "SLOCK_AGENT_TOKEN",
3306
- "SLOCK_AGENT_CREDENTIAL_KEY",
3307
- "SLOCK_AGENT_CREDENTIAL_KEY_FILE"
3469
+ "SLOCK_AGENT_CREDENTIAL_KEY"
3308
3470
  ];
3309
3471
  var cachedOpencliBinPath;
3310
3472
  function resolveOpencliBinPath() {
@@ -3519,7 +3681,7 @@ exec ${shellSingleQuote(process.execPath)} ${shellSingleQuote(opencliBinPath)} "
3519
3681
  ...agentCredentialProxy ? {} : { SLOCK_AGENT_TOKEN_FILE: tokenFile },
3520
3682
  PATH: `${slockDir}${path2.delimiter}${process.env.PATH ?? ""}`
3521
3683
  };
3522
- scrubDaemonChildEnv(spawnEnv);
3684
+ delete spawnEnv.SLOCK_AGENT_TOKEN;
3523
3685
  for (const key of RAW_CREDENTIAL_ENV_DENYLIST) {
3524
3686
  delete spawnEnv[key];
3525
3687
  }
@@ -3948,7 +4110,7 @@ function resolveCommandOnWindows(command, env, execFileSyncFn, existsSyncFn) {
3948
4110
  }
3949
4111
  function resolveCommandOnPath(command, deps = {}) {
3950
4112
  const platform = deps.platform ?? process.platform;
3951
- const env = scrubDaemonChildEnv({ ...withWindowsUserEnvironment(deps.env ?? process.env, deps) });
4113
+ const env = withWindowsUserEnvironment(deps.env ?? process.env, deps);
3952
4114
  const execFileSyncFn = deps.execFileSyncFn ?? execFileSync;
3953
4115
  const existsSyncFn = deps.existsSyncFn ?? existsSync2;
3954
4116
  if (platform === "win32") {
@@ -3974,7 +4136,7 @@ function firstExistingPath(candidates, deps = {}) {
3974
4136
  return null;
3975
4137
  }
3976
4138
  function readCommandVersion(command, args = [], deps = {}) {
3977
- const env = scrubDaemonChildEnv({ ...withWindowsUserEnvironment(deps.env ?? process.env, deps) });
4139
+ const env = withWindowsUserEnvironment(deps.env ?? process.env, deps);
3978
4140
  const execFileSyncFn = deps.execFileSyncFn ?? execFileSync;
3979
4141
  try {
3980
4142
  const output = normalizeExecOutput(execFileSyncFn(command, [...args, "--version"], {
@@ -5328,11 +5490,11 @@ function detectCursorModels(runCommand = runCursorModelsCommand) {
5328
5490
  return parseCursorModelsOutput(String(result.stdout || ""));
5329
5491
  }
5330
5492
  function buildCursorModelProbeEnv(deps = {}) {
5331
- return scrubDaemonChildEnv(withWindowsUserEnvironment({
5493
+ return withWindowsUserEnvironment({
5332
5494
  ...deps.env ?? process.env,
5333
5495
  FORCE_COLOR: "0",
5334
5496
  NO_COLOR: "1"
5335
- }, deps));
5497
+ }, deps);
5336
5498
  }
5337
5499
  function runCursorModelsCommand() {
5338
5500
  return spawnSync("cursor-agent", ["models"], {
@@ -5388,7 +5550,7 @@ function resolveGeminiSpawn(commandArgs, deps = {}) {
5388
5550
  }
5389
5551
  const execFileSyncFn = deps.execFileSyncFn ?? execFileSync3;
5390
5552
  const existsSyncFn = deps.existsSyncFn ?? existsSync4;
5391
- const env = scrubDaemonChildEnv({ ...deps.env ?? process.env });
5553
+ const env = deps.env ?? process.env;
5392
5554
  const winPath = path6.win32;
5393
5555
  let geminiEntry = null;
5394
5556
  try {
@@ -5528,15 +5690,12 @@ var GeminiDriver = class {
5528
5690
  // src/drivers/kimi.ts
5529
5691
  import { randomUUID as randomUUID2 } from "crypto";
5530
5692
  import { spawn as spawn7 } from "child_process";
5531
- import { chmodSync, existsSync as existsSync5, readFileSync as readFileSync3, writeFileSync as writeFileSync3 } from "fs";
5693
+ import { existsSync as existsSync5, readFileSync as readFileSync3, writeFileSync as writeFileSync3 } from "fs";
5532
5694
  import os3 from "os";
5533
5695
  import path7 from "path";
5534
5696
  var KIMI_WIRE_PROTOCOL_VERSION = "1.3";
5535
5697
  var KIMI_SYSTEM_PROMPT_FILE = ".slock-kimi-system.md";
5536
5698
  var KIMI_AGENT_FILE = ".slock-kimi-agent.yaml";
5537
- var KIMI_GENERATED_CONFIG_FILE = ".slock-kimi-config.toml";
5538
- var SLOCK_KIMI_CONFIG_CONTENT_ENV = "SLOCK_KIMI_CONFIG_CONTENT";
5539
- var SLOCK_KIMI_CONFIG_FILE_ENV = "SLOCK_KIMI_CONFIG_FILE";
5540
5699
  function parseToolArguments(raw) {
5541
5700
  if (typeof raw !== "string") return raw;
5542
5701
  try {
@@ -5545,73 +5704,6 @@ function parseToolArguments(raw) {
5545
5704
  return raw;
5546
5705
  }
5547
5706
  }
5548
- function readKimiConfigSource(home = os3.homedir(), env = process.env) {
5549
- const inlineConfig = env[SLOCK_KIMI_CONFIG_CONTENT_ENV];
5550
- if (inlineConfig && inlineConfig.trim()) {
5551
- return {
5552
- raw: inlineConfig,
5553
- explicitPath: null,
5554
- sourcePath: SLOCK_KIMI_CONFIG_CONTENT_ENV
5555
- };
5556
- }
5557
- const explicitPath = env[SLOCK_KIMI_CONFIG_FILE_ENV];
5558
- const configPath = explicitPath && explicitPath.trim() ? explicitPath : path7.join(home, ".kimi", "config.toml");
5559
- try {
5560
- return {
5561
- raw: readFileSync3(configPath, "utf8"),
5562
- explicitPath: explicitPath && explicitPath.trim() ? explicitPath : null,
5563
- sourcePath: configPath
5564
- };
5565
- } catch {
5566
- return {
5567
- raw: null,
5568
- explicitPath: explicitPath && explicitPath.trim() ? explicitPath : null,
5569
- sourcePath: configPath
5570
- };
5571
- }
5572
- }
5573
- function buildKimiSpawnEnv(env = process.env) {
5574
- const spawnEnv = { ...env, FORCE_COLOR: "0", NO_COLOR: "1" };
5575
- delete spawnEnv[SLOCK_KIMI_CONFIG_CONTENT_ENV];
5576
- delete spawnEnv[SLOCK_KIMI_CONFIG_FILE_ENV];
5577
- return scrubDaemonChildEnv(spawnEnv);
5578
- }
5579
- function buildKimiEffectiveEnv(ctx, overrideEnv) {
5580
- return {
5581
- ...process.env,
5582
- ...ctx.config.envVars || {},
5583
- ...overrideEnv || {}
5584
- };
5585
- }
5586
- function buildKimiLaunchOptions(ctx, opts = {}) {
5587
- const env = buildKimiEffectiveEnv(ctx, opts.env);
5588
- const source = readKimiConfigSource(opts.home ?? os3.homedir(), env);
5589
- const args = [];
5590
- let configFilePath = null;
5591
- let configContent = null;
5592
- if (source.explicitPath) {
5593
- configFilePath = source.explicitPath;
5594
- } else if (source.raw !== null && source.sourcePath === SLOCK_KIMI_CONFIG_CONTENT_ENV) {
5595
- configFilePath = path7.join(ctx.workingDirectory, KIMI_GENERATED_CONFIG_FILE);
5596
- configContent = source.raw;
5597
- if (opts.writeGeneratedConfig !== false) {
5598
- writeFileSync3(configFilePath, source.raw, { encoding: "utf8", mode: 384 });
5599
- chmodSync(configFilePath, 384);
5600
- }
5601
- }
5602
- if (configFilePath) {
5603
- args.push("--config-file", configFilePath);
5604
- }
5605
- if (ctx.config.model && ctx.config.model !== "default") {
5606
- args.push("--model", ctx.config.model);
5607
- }
5608
- return {
5609
- args,
5610
- env: buildKimiSpawnEnv(env),
5611
- configFilePath,
5612
- configContent
5613
- };
5614
- }
5615
5707
  function resolveKimiSpawn(commandArgs, deps = {}) {
5616
5708
  return {
5617
5709
  command: resolveCommandOnPath("kimi", deps) ?? "kimi",
@@ -5635,25 +5727,7 @@ var KimiDriver = class {
5635
5727
  };
5636
5728
  model = {
5637
5729
  detectedModelsVerifiedAs: "launchable",
5638
- toLaunchSpec: (modelId, ctx, opts) => {
5639
- if (!ctx) return { args: ["--model", modelId] };
5640
- const launchCtx = {
5641
- ...ctx,
5642
- config: {
5643
- ...ctx.config,
5644
- model: modelId
5645
- }
5646
- };
5647
- const launch = buildKimiLaunchOptions(launchCtx, {
5648
- home: opts?.home,
5649
- writeGeneratedConfig: false
5650
- });
5651
- return {
5652
- args: launch.args,
5653
- env: launch.env,
5654
- configFiles: launch.configFilePath ? [launch.configFilePath] : void 0
5655
- };
5656
- }
5730
+ toLaunchSpec: (modelId) => ({ args: ["--model", modelId] })
5657
5731
  };
5658
5732
  supportsStdinNotification = true;
5659
5733
  mcpToolPrefix = "";
@@ -5679,23 +5753,21 @@ var KimiDriver = class {
5679
5753
  ` system_prompt_path: ./${KIMI_SYSTEM_PROMPT_FILE}`,
5680
5754
  ""
5681
5755
  ].join("\n"), "utf8");
5682
- const launch = buildKimiLaunchOptions(ctx);
5683
5756
  const args = [
5684
5757
  "--wire",
5685
5758
  "--yolo",
5686
5759
  "--agent-file",
5687
5760
  agentFilePath,
5688
5761
  "--session",
5689
- this.sessionId,
5690
- ...launch.args
5762
+ this.sessionId
5691
5763
  ];
5692
5764
  const launchRuntimeFields = runtimeConfigToLaunchFields(ctx.config);
5693
5765
  if (launchRuntimeFields.model && launchRuntimeFields.model !== "default") {
5694
5766
  args.push("--model", launchRuntimeFields.model);
5695
5767
  }
5696
5768
  const spawnEnv = (await prepareCliTransport(ctx, { NO_COLOR: "1" })).spawnEnv;
5697
- const spawnTarget = resolveKimiSpawn(args);
5698
- const proc = spawn7(spawnTarget.command, spawnTarget.args, {
5769
+ const launch = resolveKimiSpawn(args);
5770
+ const proc = spawn7(launch.command, launch.args, {
5699
5771
  cwd: ctx.workingDirectory,
5700
5772
  stdio: ["pipe", "pipe", "pipe"],
5701
5773
  env: spawnEnv,
@@ -5703,7 +5775,7 @@ var KimiDriver = class {
5703
5775
  // and has an 8191-character command-line limit. Kimi's official
5704
5776
  // installer/uv entrypoint is an executable, so launch it directly and
5705
5777
  // keep prompts on stdin / files instead of routing through cmd.exe.
5706
- shell: spawnTarget.shell
5778
+ shell: launch.shell
5707
5779
  });
5708
5780
  proc.stdin?.write(JSON.stringify({
5709
5781
  jsonrpc: "2.0",
@@ -5817,9 +5889,14 @@ var KimiDriver = class {
5817
5889
  return detectKimiModels();
5818
5890
  }
5819
5891
  };
5820
- function detectKimiModels(home = os3.homedir(), opts = {}) {
5821
- const raw = readKimiConfigSource(home, opts.env).raw;
5822
- if (raw === null) return null;
5892
+ function detectKimiModels(home = os3.homedir()) {
5893
+ const configPath = path7.join(home, ".kimi", "config.toml");
5894
+ let raw;
5895
+ try {
5896
+ raw = readFileSync3(configPath, "utf8");
5897
+ } catch {
5898
+ return null;
5899
+ }
5823
5900
  const models = [];
5824
5901
  const sectionRe = /^\s*\[models(?:\.([^\]]+)|"\.[^"]+"|\."[^"]+")\s*\]\s*$/gm;
5825
5902
  const lineRe = /^\s*\[models\.(.+?)\s*\]\s*$/gm;
@@ -6059,7 +6136,7 @@ function runOpenCodeModelsCommand(home, deps = {}) {
6059
6136
  const platform = deps.platform ?? process.platform;
6060
6137
  const spawnSyncFn = deps.spawnSyncFn ?? spawnSync2;
6061
6138
  const result = spawnSyncFn("opencode", ["models"], {
6062
- env: scrubDaemonChildEnv({ ...process.env, HOME: home, FORCE_COLOR: "0", NO_COLOR: "1" }),
6139
+ env: { ...process.env, HOME: home, FORCE_COLOR: "0", NO_COLOR: "1" },
6063
6140
  encoding: "utf8",
6064
6141
  timeout: 5e3,
6065
6142
  shell: platform === "win32"
@@ -7304,9 +7381,26 @@ var RuntimeProgressState = class {
7304
7381
  };
7305
7382
 
7306
7383
  // src/runtimeNotificationState.ts
7384
+ function computeInboxNoticeFingerprint(messages) {
7385
+ const keys = [];
7386
+ for (const m of messages) {
7387
+ const seq = typeof m.seq === "number" && Number.isFinite(m.seq) && m.seq > 0 ? Math.floor(m.seq) : null;
7388
+ if (seq !== null) {
7389
+ keys.push(`s:${seq}`);
7390
+ continue;
7391
+ }
7392
+ const id = typeof m.message_id === "string" && m.message_id.length > 0 ? m.message_id : typeof m.id === "string" && m.id.length > 0 ? m.id : "";
7393
+ if (id.length > 0) keys.push(`m:${id}`);
7394
+ }
7395
+ if (keys.length === 0) return "";
7396
+ keys.sort();
7397
+ return keys.join(",");
7398
+ }
7307
7399
  var RuntimeNotificationState = class {
7308
7400
  timerValue = null;
7309
7401
  pendingCountValue = 0;
7402
+ lastNoticeFingerprint = null;
7403
+ lastNoticeSessionId = null;
7310
7404
  get pendingCount() {
7311
7405
  return this.pendingCountValue;
7312
7406
  }
@@ -7337,6 +7431,25 @@ var RuntimeNotificationState = class {
7337
7431
  clear() {
7338
7432
  this.clearPending();
7339
7433
  this.clearTimer();
7434
+ this.clearNoticeFingerprint();
7435
+ }
7436
+ /**
7437
+ * True iff this exact unread-set was already successfully written in THIS
7438
+ * session (per-(agent,session) scope — never suppress across a session
7439
+ * change). Empty fingerprint always returns false (fail toward sending).
7440
+ */
7441
+ isDuplicateNotice(fingerprint, sessionId) {
7442
+ if (fingerprint.length === 0) return false;
7443
+ return this.lastNoticeFingerprint === fingerprint && this.lastNoticeSessionId === sessionId;
7444
+ }
7445
+ /** Register a fingerprint as written — call ONLY after a successful stdin write. */
7446
+ recordNoticeWritten(fingerprint, sessionId) {
7447
+ this.lastNoticeFingerprint = fingerprint;
7448
+ this.lastNoticeSessionId = sessionId;
7449
+ }
7450
+ clearNoticeFingerprint() {
7451
+ this.lastNoticeFingerprint = null;
7452
+ this.lastNoticeSessionId = null;
7340
7453
  }
7341
7454
  schedule(callback, delayMs) {
7342
7455
  if (this.timerValue) return false;
@@ -7468,34 +7581,24 @@ function toLocalTime(iso) {
7468
7581
  function formatChannelLabel(message) {
7469
7582
  return message.channel_type === "dm" ? `DM:@${message.channel_name}` : `#${message.channel_name}`;
7470
7583
  }
7471
- function formatMessageTarget(message) {
7472
- if (message.channel_type === "thread" && message.parent_channel_name) {
7473
- const shortId = getMessageShortId(message.channel_name);
7474
- if (message.parent_channel_type === "dm") {
7475
- return `dm:@${message.parent_channel_name}:${shortId}`;
7584
+ function computeTarget(channelType, channelName, parentChannelName, parentChannelType) {
7585
+ if (channelType === "thread" && parentChannelName) {
7586
+ const shortId = getMessageShortId(String(channelName ?? ""));
7587
+ if (parentChannelType === "dm") {
7588
+ return `dm:@${parentChannelName}:${shortId}`;
7476
7589
  }
7477
- return `#${message.parent_channel_name}:${shortId}`;
7590
+ return `#${parentChannelName}:${shortId}`;
7478
7591
  }
7479
- if (message.channel_type === "dm") {
7480
- return `dm:@${message.channel_name}`;
7592
+ if (channelType === "dm") {
7593
+ return `dm:@${channelName}`;
7481
7594
  }
7482
- return `#${message.channel_name}`;
7595
+ return `#${channelName}`;
7596
+ }
7597
+ function formatMessageTarget(message) {
7598
+ return computeTarget(message.channel_type, message.channel_name, message.parent_channel_name, message.parent_channel_type);
7483
7599
  }
7484
7600
  function formatVisibleMessageTarget(message) {
7485
- if (message.channel_type === "thread" && message.parent_channel_name && message.channel_name) {
7486
- const shortId = getMessageShortId(String(message.channel_name));
7487
- if (message.parent_channel_type === "dm") {
7488
- return `dm:@${message.parent_channel_name}:${shortId}`;
7489
- }
7490
- return `#${message.parent_channel_name}:${shortId}`;
7491
- }
7492
- if (message.channel_type === "dm" && message.channel_name) {
7493
- return `dm:@${message.channel_name}`;
7494
- }
7495
- if (message.channel_name) {
7496
- return `#${message.channel_name}`;
7497
- }
7498
- return null;
7601
+ return computeTarget(message.channel_type, message.channel_name, message.parent_channel_name, message.parent_channel_type);
7499
7602
  }
7500
7603
  function getMessageShortId(messageId2) {
7501
7604
  return messageId2.startsWith("thread-") ? messageId2.slice(7) : messageId2.slice(0, 8);
@@ -7717,6 +7820,8 @@ var TRAJECTORY_COALESCE_MS = 350;
7717
7820
  var ACTIVITY_HEARTBEAT_MS = 6e4;
7718
7821
  var STDIN_NOTIFICATION_INITIAL_DELAY_MS = 3e3;
7719
7822
  var STDIN_NOTIFICATION_RETRY_DELAY_MS = 15e3;
7823
+ var RUNTIME_ERROR_DELIVERY_BACKOFF_BASE_MS = 1e4;
7824
+ var RUNTIME_ERROR_DELIVERY_BACKOFF_MAX_MS = 5 * 6e4;
7720
7825
  var COMPACTION_STALE_MS = 5 * 6e4;
7721
7826
  var RUNTIME_PROGRESS_STALE_MS = 15 * 6e4;
7722
7827
  var DEFAULT_RUNTIME_START_TIMEOUT_MS = 2 * 6e4;
@@ -8130,6 +8235,14 @@ function createRuntimeTraceCounters() {
8130
8235
  thinkingEvents: 0
8131
8236
  };
8132
8237
  }
8238
+ function createRuntimeErrorDeliveryBackoffState() {
8239
+ return {
8240
+ attempts: 0,
8241
+ untilMs: 0,
8242
+ timer: null,
8243
+ reason: null
8244
+ };
8245
+ }
8133
8246
  function cleanupAgentCredentialProxy(agentId, launchId) {
8134
8247
  unregisterAgentCredentialProxyForLaunch({ agentId, launchId });
8135
8248
  }
@@ -8574,6 +8687,10 @@ var AgentProcessManager = class _AgentProcessManager {
8574
8687
  defaultAgentEnvVarsProvider;
8575
8688
  tracer;
8576
8689
  stdinNotificationRetryMs;
8690
+ runtimeErrorDeliveryBackoffBaseMs;
8691
+ runtimeErrorDeliveryBackoffMaxMs;
8692
+ runtimeErrorDeliveryBackoffJitterRatio;
8693
+ runtimeErrorDeliveryBackoffFailPointForTesting;
8577
8694
  cliTransportTraceDir = null;
8578
8695
  deliveryTraceContexts = /* @__PURE__ */ new WeakMap();
8579
8696
  runtimeExitTraceAttrs = /* @__PURE__ */ new WeakMap();
@@ -8597,6 +8714,19 @@ var AgentProcessManager = class _AgentProcessManager {
8597
8714
  0,
8598
8715
  Math.floor(opts.stdinNotificationRetryMs ?? STDIN_NOTIFICATION_RETRY_DELAY_MS)
8599
8716
  );
8717
+ this.runtimeErrorDeliveryBackoffBaseMs = Math.max(
8718
+ 0,
8719
+ Math.floor(opts.runtimeErrorDeliveryBackoff?.baseMs ?? RUNTIME_ERROR_DELIVERY_BACKOFF_BASE_MS)
8720
+ );
8721
+ this.runtimeErrorDeliveryBackoffMaxMs = Math.max(
8722
+ this.runtimeErrorDeliveryBackoffBaseMs,
8723
+ Math.floor(opts.runtimeErrorDeliveryBackoff?.maxMs ?? RUNTIME_ERROR_DELIVERY_BACKOFF_MAX_MS)
8724
+ );
8725
+ this.runtimeErrorDeliveryBackoffJitterRatio = Math.max(
8726
+ 0,
8727
+ Math.min(1, opts.runtimeErrorDeliveryBackoff?.jitterRatio ?? 0.1)
8728
+ );
8729
+ this.runtimeErrorDeliveryBackoffFailPointForTesting = opts.runtimeErrorDeliveryBackoff?.failPointForTesting ?? null;
8600
8730
  this.maxConcurrentAgentStarts = Math.max(
8601
8731
  1,
8602
8732
  Math.floor(
@@ -8650,6 +8780,183 @@ var AgentProcessManager = class _AgentProcessManager {
8650
8780
  this.sendStdinNotification(agentId);
8651
8781
  }, delayMs);
8652
8782
  }
8783
+ clearRuntimeErrorDeliveryBackoff(ap) {
8784
+ if (ap.runtimeErrorDeliveryBackoff.timer) {
8785
+ clearTimeout(ap.runtimeErrorDeliveryBackoff.timer);
8786
+ }
8787
+ ap.runtimeErrorDeliveryBackoff = createRuntimeErrorDeliveryBackoffState();
8788
+ }
8789
+ clearRuntimeErrorDeliveryBackoffAfterProgress(agentId, ap, eventKind) {
8790
+ if (ap.runtimeErrorDeliveryBackoff.attempts === 0 && ap.runtimeErrorDeliveryBackoff.untilMs === 0) return;
8791
+ const attempts = ap.runtimeErrorDeliveryBackoff.attempts;
8792
+ const reason = ap.runtimeErrorDeliveryBackoff.reason;
8793
+ this.clearRuntimeErrorDeliveryBackoff(ap);
8794
+ this.recordDaemonTrace("daemon.agent.runtime_error_delivery_backoff.reset", {
8795
+ agentId,
8796
+ runtime: ap.config.runtime,
8797
+ model: ap.config.model,
8798
+ launchId: ap.launchId || void 0,
8799
+ reason: reason || void 0,
8800
+ attempts,
8801
+ reset_source: eventKind
8802
+ });
8803
+ }
8804
+ runtimeErrorDeliveryBackoffRemainingMs(ap) {
8805
+ return Math.max(0, ap.runtimeErrorDeliveryBackoff.untilMs - Date.now());
8806
+ }
8807
+ scheduleRuntimeErrorDeliveryBackoffFlush(agentId, ap) {
8808
+ const delayMs = this.runtimeErrorDeliveryBackoffRemainingMs(ap);
8809
+ if (delayMs <= 0 || ap.runtimeErrorDeliveryBackoff.timer) return false;
8810
+ ap.runtimeErrorDeliveryBackoff.timer = setTimeout(() => {
8811
+ ap.runtimeErrorDeliveryBackoff.timer = null;
8812
+ this.flushRuntimeErrorDeliveryBackoff(agentId);
8813
+ }, delayMs);
8814
+ ap.runtimeErrorDeliveryBackoff.timer.unref?.();
8815
+ return true;
8816
+ }
8817
+ recoverableRuntimeDeliveryBackoffReason(message, terminalFailure, stickyTerminalFailure, reasonOverride) {
8818
+ if (stickyTerminalFailure || terminalFailure?.actionRequired) return null;
8819
+ if (reasonOverride !== void 0) return reasonOverride;
8820
+ if (terminalFailure) return "recoverable_terminal_runtime_error";
8821
+ const runtimeErrorClass = buildRuntimeErrorDiagnosticEnvelope(message).spanAttrs.runtime_error_class;
8822
+ switch (runtimeErrorClass) {
8823
+ case "RateLimitError":
8824
+ return "rate_limited";
8825
+ case "ProviderServerError":
8826
+ return "provider_server_error";
8827
+ case "ProviderConnectionError":
8828
+ return "provider_connection_error";
8829
+ case "ProviderStreamError":
8830
+ return "provider_stream_error";
8831
+ default:
8832
+ return null;
8833
+ }
8834
+ }
8835
+ noteRuntimeErrorDeliveryBackoff(agentId, ap, message, terminalFailure, stickyTerminalFailure, reasonOverride) {
8836
+ const reason = this.recoverableRuntimeDeliveryBackoffReason(message, terminalFailure, stickyTerminalFailure, reasonOverride);
8837
+ if (!reason) return false;
8838
+ const attempts = ap.runtimeErrorDeliveryBackoff.attempts + 1;
8839
+ const exponentialDelayMs = this.runtimeErrorDeliveryBackoffBaseMs * 2 ** Math.max(0, attempts - 1);
8840
+ const cappedDelayMs = Math.min(this.runtimeErrorDeliveryBackoffMaxMs, exponentialDelayMs);
8841
+ const jitterMs = Math.floor(cappedDelayMs * this.runtimeErrorDeliveryBackoffJitterRatio * Math.random());
8842
+ const delayMs = Math.min(this.runtimeErrorDeliveryBackoffMaxMs, cappedDelayMs + jitterMs);
8843
+ if (ap.runtimeErrorDeliveryBackoff.timer) {
8844
+ clearTimeout(ap.runtimeErrorDeliveryBackoff.timer);
8845
+ ap.runtimeErrorDeliveryBackoff.timer = null;
8846
+ }
8847
+ ap.runtimeErrorDeliveryBackoff.attempts = attempts;
8848
+ ap.runtimeErrorDeliveryBackoff.reason = reason;
8849
+ ap.runtimeErrorDeliveryBackoff.untilMs = Date.now() + delayMs;
8850
+ if (ap.inbox.length > 0) {
8851
+ this.scheduleRuntimeErrorDeliveryBackoffFlush(agentId, ap);
8852
+ }
8853
+ this.recordDaemonTrace("daemon.agent.runtime_error_delivery_backoff", {
8854
+ agentId,
8855
+ runtime: ap.config.runtime,
8856
+ model: ap.config.model,
8857
+ launchId: ap.launchId || void 0,
8858
+ reason,
8859
+ attempts,
8860
+ delay_ms: delayMs,
8861
+ until_ms: ap.runtimeErrorDeliveryBackoff.untilMs,
8862
+ inbox_count: ap.inbox.length,
8863
+ pending_notification_count: ap.notifications.pendingCount
8864
+ });
8865
+ return true;
8866
+ }
8867
+ queueDeliveryForRuntimeErrorBackoff(agentId, ap, message) {
8868
+ const remainingMs = this.runtimeErrorDeliveryBackoffRemainingMs(ap);
8869
+ if (remainingMs <= 0) return false;
8870
+ ap.inbox.push(message);
8871
+ if (!ap.isIdle && ap.driver.supportsStdinNotification && ap.sessionId) {
8872
+ ap.notifications.add();
8873
+ }
8874
+ const scheduled = this.scheduleRuntimeErrorDeliveryBackoffFlush(agentId, ap);
8875
+ this.recordDaemonTrace("daemon.agent.delivery.routed", this.deliveryTraceAttrs(agentId, message, {
8876
+ outcome: "queued_runtime_error_backoff",
8877
+ accepted: true,
8878
+ process_present: true,
8879
+ runtime: ap.config.runtime,
8880
+ session_id_present: Boolean(ap.sessionId),
8881
+ launchId: ap.launchId || void 0,
8882
+ is_idle: ap.isIdle,
8883
+ inbox_count: ap.inbox.length,
8884
+ pending_notification_count: ap.notifications.pendingCount,
8885
+ runtime_error_backoff_remaining_ms: remainingMs,
8886
+ runtime_error_backoff_attempts: ap.runtimeErrorDeliveryBackoff.attempts,
8887
+ runtime_error_backoff_reason: ap.runtimeErrorDeliveryBackoff.reason || void 0,
8888
+ runtime_error_backoff_timer_scheduled: scheduled || ap.runtimeErrorDeliveryBackoff.timer !== null
8889
+ }));
8890
+ return true;
8891
+ }
8892
+ flushRuntimeErrorDeliveryBackoff(agentId) {
8893
+ const ap = this.agents.get(agentId);
8894
+ if (!ap) return false;
8895
+ const remainingMs = this.runtimeErrorDeliveryBackoffRemainingMs(ap);
8896
+ if (remainingMs > 0) {
8897
+ this.scheduleRuntimeErrorDeliveryBackoffFlush(agentId, ap);
8898
+ return false;
8899
+ }
8900
+ if (ap.inbox.length === 0) return false;
8901
+ const reason = ap.runtimeErrorDeliveryBackoff.reason || "runtime_error_backoff";
8902
+ if (ap.isIdle && ap.driver.supportsStdinNotification && ap.sessionId) {
8903
+ const messages = [...ap.inbox];
8904
+ ap.notifications.clearPending();
8905
+ ap.notifications.clearTimer();
8906
+ this.commitApmIdleState(agentId, ap, false);
8907
+ this.startRuntimeTrace(agentId, ap, "runtime-error-backoff-idle-delivery", messages);
8908
+ this.broadcastActivity(agentId, "working", "Message received");
8909
+ const accepted2 = this.deliverInboxUpdateViaStdin(
8910
+ agentId,
8911
+ ap,
8912
+ messages,
8913
+ "idle",
8914
+ "runtime_error_backoff_idle_delivery"
8915
+ );
8916
+ this.recordDaemonTrace("daemon.agent.runtime_error_delivery_backoff.flush", {
8917
+ agentId,
8918
+ runtime: ap.config.runtime,
8919
+ model: ap.config.model,
8920
+ launchId: ap.launchId || void 0,
8921
+ reason,
8922
+ mode: "idle",
8923
+ outcome: accepted2 ? "written" : "not_written",
8924
+ inbox_count: ap.inbox.length,
8925
+ messages_count: messages.length
8926
+ });
8927
+ return accepted2;
8928
+ }
8929
+ if (!ap.driver.supportsStdinNotification || !ap.sessionId) {
8930
+ this.recordDaemonTrace("daemon.agent.runtime_error_delivery_backoff.flush", {
8931
+ agentId,
8932
+ runtime: ap.config.runtime,
8933
+ model: ap.config.model,
8934
+ launchId: ap.launchId || void 0,
8935
+ reason,
8936
+ outcome: "queued_without_stdin",
8937
+ inbox_count: ap.inbox.length,
8938
+ session_id_present: Boolean(ap.sessionId),
8939
+ supports_stdin_notification: ap.driver.supportsStdinNotification
8940
+ });
8941
+ return false;
8942
+ }
8943
+ if (ap.notifications.pendingCount === 0) {
8944
+ ap.notifications.add(ap.inbox.length);
8945
+ }
8946
+ const accepted = this.sendStdinNotification(agentId);
8947
+ this.recordDaemonTrace("daemon.agent.runtime_error_delivery_backoff.flush", {
8948
+ agentId,
8949
+ runtime: ap.config.runtime,
8950
+ model: ap.config.model,
8951
+ launchId: ap.launchId || void 0,
8952
+ reason,
8953
+ mode: "busy",
8954
+ outcome: accepted ? "written" : "not_written",
8955
+ inbox_count: ap.inbox.length,
8956
+ pending_notification_count: ap.notifications.pendingCount
8957
+ });
8958
+ return accepted;
8959
+ }
8653
8960
  allPendingVisibleMessages(agentId) {
8654
8961
  const collect = (messages) => (messages ?? []).filter((message) => typeof message.seq === "number" && message.seq > 0);
8655
8962
  return [
@@ -8696,10 +9003,13 @@ var AgentProcessManager = class _AgentProcessManager {
8696
9003
  if (byTarget.size === 0) return;
8697
9004
  const boundaryMap = this.visibleBoundaryMap(agentId);
8698
9005
  const visibleIds = this.visibleMessageIdMap(agentId);
9006
+ const advancesBoundary = input.source === "spawn_wake_message" || input.source === "agent_api_events_local" || input.source.startsWith("stdin_");
8699
9007
  for (const [target, bucket] of byTarget) {
8700
- const highWaterSeq = Math.max(bucket.maxSeq, bucket.boundarySeq);
8701
- const previous = boundaryMap.get(target) ?? 0;
8702
- boundaryMap.set(target, Math.max(previous, highWaterSeq));
9008
+ if (advancesBoundary) {
9009
+ const highWaterSeq = Math.max(bucket.maxSeq, bucket.boundarySeq);
9010
+ const previous = boundaryMap.get(target) ?? 0;
9011
+ boundaryMap.set(target, Math.max(previous, highWaterSeq));
9012
+ }
8703
9013
  if (bucket.ids.size > 0) {
8704
9014
  let targetIds = visibleIds.get(target);
8705
9015
  if (!targetIds) {
@@ -8763,6 +9073,7 @@ var AgentProcessManager = class _AgentProcessManager {
8763
9073
  active.notifications.remove(removedActive);
8764
9074
  if (active.inbox.length === 0) {
8765
9075
  active.notifications.clear();
9076
+ this.clearRuntimeErrorDeliveryBackoff(active);
8766
9077
  }
8767
9078
  }
8768
9079
  const removedCount = removedActive + removedStarting;
@@ -9277,6 +9588,7 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
9277
9588
  recentStdout: [],
9278
9589
  recentStderr: [],
9279
9590
  lastRuntimeError: null,
9591
+ runtimeErrorDeliveryBackoff: createRuntimeErrorDeliveryBackoffState(),
9280
9592
  spawnError: null,
9281
9593
  exitCode: null,
9282
9594
  exitSignal: null,
@@ -9379,6 +9691,7 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
9379
9691
  const ap = this.agents.get(agentId);
9380
9692
  if (ap.runtime !== runtime) return;
9381
9693
  ap.notifications.clearTimer();
9694
+ this.clearRuntimeErrorDeliveryBackoff(ap);
9382
9695
  if (ap.pendingTrajectory?.timer) {
9383
9696
  clearTimeout(ap.pendingTrajectory.timer);
9384
9697
  }
@@ -9496,6 +9809,7 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
9496
9809
  logger.warn(`[Agent ${agentId}] Recoverable provider stream failure (${reason}) \u2014 keeping agent wakeable`);
9497
9810
  this.sendAgentStatus(agentId, "active", ap.launchId);
9498
9811
  } else if (startupTimeoutTermination) {
9812
+ this.cacheStartupTimeoutRetryConfig(agentId, ap);
9499
9813
  logger.warn(`[Agent ${agentId}] Startup timeout cleanup completed (${reason})`);
9500
9814
  } else {
9501
9815
  this.idleAgentConfigs.delete(agentId);
@@ -9566,6 +9880,23 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
9566
9880
  this.agents.delete(agentId);
9567
9881
  this.idleAgentConfigs.delete(agentId);
9568
9882
  }
9883
+ cacheStartupTimeoutRetryConfig(agentId, ap) {
9884
+ const retryConfig = {
9885
+ ...stripManagedRunnerCredential(ap.config),
9886
+ sessionId: ap.sessionId
9887
+ };
9888
+ this.idleAgentConfigs.set(agentId, {
9889
+ config: retryConfig,
9890
+ sessionId: ap.sessionId,
9891
+ launchId: ap.launchId
9892
+ });
9893
+ this.recordDaemonTrace("daemon.agent.startup_timeout.retry_config_cached", {
9894
+ agentId,
9895
+ launchId: ap.launchId || void 0,
9896
+ runtime: ap.config.runtime,
9897
+ session_id_present: Boolean(ap.sessionId)
9898
+ });
9899
+ }
9569
9900
  async buildSpawnConfig(agentId, config) {
9570
9901
  const baseConfig = config.serverUrl === this.serverUrl ? config : { ...config, serverUrl: this.serverUrl };
9571
9902
  const runnerConfig = await this.ensureManagedRunnerCredential(agentId, baseConfig);
@@ -9793,6 +10124,7 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
9793
10124
  return;
9794
10125
  }
9795
10126
  ap.notifications.clearTimer();
10127
+ this.clearRuntimeErrorDeliveryBackoff(ap);
9796
10128
  if (ap.activityHeartbeat) {
9797
10129
  clearInterval(ap.activityHeartbeat);
9798
10130
  }
@@ -9847,6 +10179,14 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
9847
10179
  this.deliveryTraceContexts.set(message, traceContext);
9848
10180
  }
9849
10181
  const transientDelivery = this.isTransientDelivery(message);
10182
+ if (!transientDelivery && this.isVisibleMessageModelSeen(agentId, formatMessageTarget(message), message)) {
10183
+ this.recordDaemonTrace("daemon.agent.delivery.routed", this.deliveryTraceAttrs(agentId, message, {
10184
+ outcome: "dropped_already_consumed",
10185
+ accepted: true,
10186
+ process_present: Boolean(this.agents.get(agentId))
10187
+ }));
10188
+ return true;
10189
+ }
9850
10190
  const ap = this.agents.get(agentId);
9851
10191
  if (!ap) {
9852
10192
  if (this.agentsStarting.has(agentId) || this.queuedAgentStarts.has(agentId)) {
@@ -9990,6 +10330,9 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
9990
10330
  return true;
9991
10331
  }
9992
10332
  }
10333
+ if (!transientDelivery && this.queueDeliveryForRuntimeErrorBackoff(agentId, ap, message)) {
10334
+ return true;
10335
+ }
9993
10336
  if (ap.isIdle && ap.driver.supportsStdinNotification && ap.sessionId) {
9994
10337
  if (transientDelivery) {
9995
10338
  this.commitApmIdleState(agentId, ap, false);
@@ -11042,6 +11385,19 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
11042
11385
  return written;
11043
11386
  }
11044
11387
  case "deliver_stdin": {
11388
+ const runtimeErrorBackoffRemainingMs = this.runtimeErrorDeliveryBackoffRemainingMs(ap);
11389
+ if (runtimeErrorBackoffRemainingMs > 0) {
11390
+ const scheduled = this.scheduleRuntimeErrorDeliveryBackoffFlush(agentId, ap);
11391
+ this.recordApmGatedSteeringEffectTrace(agentId, ap, effect, {
11392
+ outcome: "suppressed_runtime_error_backoff",
11393
+ runtime_error_backoff_remaining_ms: runtimeErrorBackoffRemainingMs,
11394
+ runtime_error_backoff_attempts: ap.runtimeErrorDeliveryBackoff.attempts,
11395
+ runtime_error_backoff_reason: ap.runtimeErrorDeliveryBackoff.reason || void 0,
11396
+ runtime_error_backoff_timer_scheduled: scheduled || ap.runtimeErrorDeliveryBackoff.timer !== null,
11397
+ delivered_messages_count: 0
11398
+ });
11399
+ return false;
11400
+ }
11045
11401
  const messages = [...ap.inbox];
11046
11402
  ap.notifications.clear();
11047
11403
  if (messages.length === 0) {
@@ -11151,7 +11507,7 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
11151
11507
  logger.warn(`[Agent ${agentId}] ${ap.driver.id} did not emit a startup runtime event within ${timeoutMs}ms; terminating process`);
11152
11508
  this.broadcastActivity(agentId, "error", detail, [{ kind: "text", text: `Error: ${detail}` }], ap.launchId);
11153
11509
  this.sendAgentStatus(agentId, "inactive", ap.launchId);
11154
- this.idleAgentConfigs.delete(agentId);
11510
+ this.cacheStartupTimeoutRetryConfig(agentId, ap);
11155
11511
  try {
11156
11512
  this.runtimeExitTraceAttrs.set(ap.runtime, {
11157
11513
  stop_source: "startup_timeout",
@@ -11282,6 +11638,7 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
11282
11638
  }
11283
11639
  if (event.kind === "internal_progress") {
11284
11640
  ap.runtimeProgress.noteInternalProgress();
11641
+ this.clearRuntimeErrorDeliveryBackoffAfterProgress(agentId, ap, event.kind);
11285
11642
  this.recordRuntimeTraceEvent(agentId, ap, "runtime.progress.internal_observed", {
11286
11643
  turn_outcome: "held",
11287
11644
  turn_subtype: "runtime_progress",
@@ -11306,6 +11663,7 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
11306
11663
  this.completeCompactionIfActive(agentId, "Context compaction finished (inferred from resumed output)");
11307
11664
  this.queueTrajectoryText(agentId, "thinking", event.text);
11308
11665
  if (ap) {
11666
+ this.clearRuntimeErrorDeliveryBackoffAfterProgress(agentId, ap, event.kind);
11309
11667
  const reduction = reduceApmGatedAssistantContinuation(ap.gatedSteering);
11310
11668
  this.commitGatedSteeringDecisionState(agentId, ap, reduction.nextState, { event: "thinking" });
11311
11669
  }
@@ -11315,6 +11673,7 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
11315
11673
  this.completeCompactionIfActive(agentId, "Context compaction finished (inferred from resumed output)");
11316
11674
  this.queueTrajectoryText(agentId, "text", event.text);
11317
11675
  if (ap) {
11676
+ this.clearRuntimeErrorDeliveryBackoffAfterProgress(agentId, ap, event.kind);
11318
11677
  const reduction = reduceApmGatedAssistantContinuation(ap.gatedSteering);
11319
11678
  this.commitGatedSteeringDecisionState(agentId, ap, reduction.nextState, { event: "text" });
11320
11679
  }
@@ -11325,6 +11684,7 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
11325
11684
  this.flushPendingTrajectory(agentId);
11326
11685
  const invocation = normalizeToolDisplayInvocation(event.name, event.input);
11327
11686
  if (ap) {
11687
+ this.clearRuntimeErrorDeliveryBackoffAfterProgress(agentId, ap, event.kind);
11328
11688
  const reduction = reduceApmGatedToolUse(ap.gatedSteering, { kind: "tool_call" });
11329
11689
  this.recordRuntimeTraceEvent(agentId, ap, "tool.call.started", { tool: invocation.toolName });
11330
11690
  this.commitGatedSteeringDecisionState(agentId, ap, reduction.nextState, {
@@ -11344,6 +11704,7 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
11344
11704
  case "tool_output": {
11345
11705
  const invocation = normalizeToolDisplayInvocation(event.name, {});
11346
11706
  if (ap) {
11707
+ this.clearRuntimeErrorDeliveryBackoffAfterProgress(agentId, ap, event.kind);
11347
11708
  const reduction = reduceApmGatedToolUse(ap.gatedSteering, { kind: "tool_output" });
11348
11709
  this.recordRuntimeTraceEvent(agentId, ap, "tool.output.observed", { tool: invocation.toolName });
11349
11710
  this.recordRuntimeTraceEvent(agentId, ap, "runtime.continuation.expected");
@@ -11403,6 +11764,8 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
11403
11764
  this.commitApmIdleState(agentId, ap, true);
11404
11765
  if (stickyTerminalFailure) {
11405
11766
  this.broadcastActivity(agentId, "error", stickyTerminalFailure.detail);
11767
+ } else if (ap.lastRuntimeError && ap.runtimeErrorDeliveryBackoff.attempts > 0) {
11768
+ this.broadcastActivity(agentId, "error", ap.lastRuntimeError);
11406
11769
  } else {
11407
11770
  this.broadcastActivity(agentId, "online", "Idle");
11408
11771
  }
@@ -11452,12 +11815,19 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
11452
11815
  visibleErrorMessage = formatRuntimeLoginRequiredMessage(ap.driver.id);
11453
11816
  }
11454
11817
  const shouldDisableToolBoundaryFlush = ap.runtime.descriptor.busyDelivery === "gated" && this.isThinkingBlockMutationError(event.message);
11455
- const terminalFailure = classifyTerminalFailure(ap);
11818
+ const backoffFailPoint = this.runtimeErrorDeliveryBackoffFailPointForTesting?.({
11819
+ agentId,
11820
+ message: event.message
11821
+ }) ?? null;
11822
+ const terminalFailure = backoffFailPoint && Object.prototype.hasOwnProperty.call(backoffFailPoint, "terminalFailure") ? backoffFailPoint.terminalFailure ?? null : classifyTerminalFailure(ap);
11823
+ const stickyTerminalFailure = backoffFailPoint && Object.prototype.hasOwnProperty.call(backoffFailPoint, "stickyTerminalFailure") ? backoffFailPoint.stickyTerminalFailure ?? null : classifyStickyTerminalFailure(ap);
11824
+ const backoffReasonOverride = backoffFailPoint && Object.prototype.hasOwnProperty.call(backoffFailPoint, "reason") ? backoffFailPoint.reason ?? null : void 0;
11456
11825
  const reduction = reduceApmGatedError(ap.gatedSteering, {
11457
11826
  disableToolBoundaryFlush: shouldDisableToolBoundaryFlush,
11458
11827
  terminalWakeable: Boolean(ap.driver.supportsStdinNotification && terminalFailure && !terminalFailure.actionRequired)
11459
11828
  });
11460
11829
  this.commitGatedSteeringDecisionState(agentId, ap, reduction.nextState, { event: "error" });
11830
+ this.noteRuntimeErrorDeliveryBackoff(agentId, ap, event.message, terminalFailure, stickyTerminalFailure, backoffReasonOverride);
11461
11831
  if (reduction.shouldDisableToolBoundaryFlush) {
11462
11832
  this.recordGatedSteeringEvent(agentId, ap, "disabled", {
11463
11833
  reason: "thinking_block_mutation_error",
@@ -11478,7 +11848,6 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
11478
11848
  ...this.finalizeRuntimeProfileTurnControl(agentId, ap, "runtime_error")
11479
11849
  });
11480
11850
  if (ap.driver.supportsStdinNotification && terminalFailure) {
11481
- const stickyTerminalFailure = classifyStickyTerminalFailure(ap);
11482
11851
  if (terminalFailure.actionRequired) {
11483
11852
  logger.warn(`[Agent ${agentId}] ${ap.driver.id} auth requires user action; terminating runtime process`);
11484
11853
  try {
@@ -11496,7 +11865,8 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
11496
11865
  this.sendAgentStatus(agentId, "inactive", ap.launchId);
11497
11866
  logger.warn(`[Agent ${agentId}] ${ap.driver.id} terminal runtime error requires explicit recovery`);
11498
11867
  } else {
11499
- ap.notifications.clear();
11868
+ ap.notifications.clearPending();
11869
+ ap.notifications.clearTimer();
11500
11870
  logger.info(`[Agent ${agentId}] Marked ${ap.driver.id} wakeable after terminal runtime error`);
11501
11871
  }
11502
11872
  }
@@ -11607,6 +11977,27 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
11607
11977
  if (count === 0) return false;
11608
11978
  if (ap.isIdle) return false;
11609
11979
  if (!ap.sessionId) return false;
11980
+ const runtimeErrorBackoffRemainingMs = this.runtimeErrorDeliveryBackoffRemainingMs(ap);
11981
+ if (runtimeErrorBackoffRemainingMs > 0) {
11982
+ ap.notifications.add(count);
11983
+ const scheduled = this.scheduleRuntimeErrorDeliveryBackoffFlush(agentId, ap);
11984
+ this.recordDaemonTrace("daemon.agent.stdin_notification", {
11985
+ agentId,
11986
+ runtime: ap.config.runtime,
11987
+ model: ap.config.model,
11988
+ launchId: ap.launchId || void 0,
11989
+ outcome: "suppressed_runtime_error_backoff",
11990
+ mode: "busy",
11991
+ pending_notification_count: count,
11992
+ inbox_count: ap.inbox.length,
11993
+ session_id_present: true,
11994
+ runtime_error_backoff_remaining_ms: runtimeErrorBackoffRemainingMs,
11995
+ runtime_error_backoff_attempts: ap.runtimeErrorDeliveryBackoff.attempts,
11996
+ runtime_error_backoff_reason: ap.runtimeErrorDeliveryBackoff.reason || void 0,
11997
+ runtime_error_backoff_timer_scheduled: scheduled || ap.runtimeErrorDeliveryBackoff.timer !== null
11998
+ });
11999
+ return false;
12000
+ }
11610
12001
  if (ap.gatedSteering.compacting) {
11611
12002
  this.recordRuntimeTraceEvent(agentId, ap, "runtime.compaction_boundary.delivery_suppressed", {
11612
12003
  pendingNotificationCount: count,
@@ -11622,6 +12013,22 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
11622
12013
  const inboxCount = ap.inbox.length;
11623
12014
  if (inboxCount === 0) return false;
11624
12015
  const changedMessages = ap.inbox.slice(Math.max(0, ap.inbox.length - count));
12016
+ const noticeFingerprint = computeInboxNoticeFingerprint(changedMessages);
12017
+ if (ap.notifications.isDuplicateNotice(noticeFingerprint, ap.sessionId)) {
12018
+ this.recordDaemonTrace("daemon.agent.stdin_notification", {
12019
+ agentId,
12020
+ runtime: ap.config.runtime,
12021
+ model: ap.config.model,
12022
+ launchId: ap.launchId || void 0,
12023
+ outcome: "suppressed_duplicate",
12024
+ mode: "busy",
12025
+ pending_notification_count: count,
12026
+ inbox_count: ap.inbox.length,
12027
+ session_id_present: true
12028
+ });
12029
+ logger.info(`[Agent ${agentId}] Suppressing duplicate stdin inbox notice (unread-set unchanged since last write); pending=${ap.inbox.length}`);
12030
+ return false;
12031
+ }
11625
12032
  const inboxRows = projectAgentInboxSnapshot(changedMessages);
11626
12033
  const notification = `[Slock inbox notice:
11627
12034
  ${formatAgentInboxDelta(inboxRows, { totalPendingMessages: inboxCount })}]`;
@@ -11659,6 +12066,7 @@ ${formatAgentInboxDelta(inboxRows, { totalPendingMessages: inboxCount })}]`;
11659
12066
  inbox_target_count: inboxRows.length,
11660
12067
  session_id_present: true
11661
12068
  });
12069
+ ap.notifications.recordNoticeWritten(noticeFingerprint, ap.sessionId);
11662
12070
  return true;
11663
12071
  } else {
11664
12072
  ap.notifications.add(count);
@@ -11955,6 +12363,8 @@ var DaemonConnection = class {
11955
12363
  lastDroppedSendLogAt = 0;
11956
12364
  lastInboundAt = null;
11957
12365
  lastInboundMessageKind = null;
12366
+ pendingActivityByAgent = /* @__PURE__ */ new Map();
12367
+ latestObservedLaunchIdByAgent = /* @__PURE__ */ new Map();
11958
12368
  constructor(options) {
11959
12369
  this.options = options;
11960
12370
  this.clock = options.clock ?? systemClock;
@@ -11968,6 +12378,7 @@ var DaemonConnection = class {
11968
12378
  }
11969
12379
  disconnect() {
11970
12380
  this.shouldConnect = false;
12381
+ this.pendingActivityByAgent.clear();
11971
12382
  this.clearWatchdog();
11972
12383
  if (this.reconnectTimer) {
11973
12384
  this.clock.clearTimeout(this.reconnectTimer);
@@ -11981,9 +12392,15 @@ var DaemonConnection = class {
11981
12392
  }
11982
12393
  send(msg) {
11983
12394
  if (this.ws?.readyState === WebSocket.OPEN) {
12395
+ this.observeLaunchIdentity(msg);
12396
+ if (msg.type === "agent:activity") {
12397
+ this.pendingActivityByAgent.delete(msg.agentId);
12398
+ }
11984
12399
  this.ws.send(JSON.stringify(msg));
11985
12400
  return;
11986
12401
  }
12402
+ this.observeLaunchIdentity(msg);
12403
+ this.queueReplayableMessage(msg);
11987
12404
  const now = this.clock.now();
11988
12405
  if (now - this.lastDroppedSendLogAt > 5e3) {
11989
12406
  this.lastDroppedSendLogAt = now;
@@ -12026,6 +12443,7 @@ var DaemonConnection = class {
12026
12443
  reconnect_attempt: priorReconnectAttempt,
12027
12444
  inbound_watchdog_ms: this.options.inboundWatchdogMs ?? INBOUND_WATCHDOG_MS
12028
12445
  });
12446
+ this.flushPendingActivity(ws);
12029
12447
  this.options.onConnect();
12030
12448
  });
12031
12449
  ws.on("message", (data) => {
@@ -12123,6 +12541,65 @@ var DaemonConnection = class {
12123
12541
  this.lastInboundAt = this.clock.now();
12124
12542
  this.lastInboundMessageKind = messageKind;
12125
12543
  }
12544
+ queueReplayableMessage(msg) {
12545
+ if (msg.type !== "agent:activity") return;
12546
+ const latestLaunchId = this.latestObservedLaunchIdByAgent.get(msg.agentId);
12547
+ if (msg.launchId && latestLaunchId && msg.launchId !== latestLaunchId) {
12548
+ this.trace("daemon.connection.pending_activity_invalidated", {
12549
+ reason: "launch_changed",
12550
+ message_type: msg.type,
12551
+ agentId: msg.agentId,
12552
+ stale_launch_id_present: true,
12553
+ next_launch_id_present: true
12554
+ });
12555
+ return;
12556
+ }
12557
+ this.pendingActivityByAgent.set(msg.agentId, msg);
12558
+ }
12559
+ observeLaunchIdentity(msg) {
12560
+ const identity = this.agentLaunchIdentity(msg);
12561
+ if (!identity?.launchId) return;
12562
+ if (msg.type !== "agent:activity") {
12563
+ this.latestObservedLaunchIdByAgent.set(identity.agentId, identity.launchId);
12564
+ }
12565
+ const pending = this.pendingActivityByAgent.get(identity.agentId);
12566
+ if (!pending || pending.launchId === identity.launchId) return;
12567
+ this.pendingActivityByAgent.delete(identity.agentId);
12568
+ this.trace("daemon.connection.pending_activity_invalidated", {
12569
+ reason: "launch_changed",
12570
+ message_type: msg.type,
12571
+ agentId: identity.agentId,
12572
+ stale_launch_id_present: Boolean(pending.launchId),
12573
+ next_launch_id_present: true
12574
+ });
12575
+ }
12576
+ agentLaunchIdentity(msg) {
12577
+ switch (msg.type) {
12578
+ case "agent:activity":
12579
+ case "agent:status":
12580
+ case "agent:session":
12581
+ case "agent:runtime_profile":
12582
+ case "agent:runtime_profile:migration:ack":
12583
+ case "agent:runtime_profile:migration_done":
12584
+ case "agent:runtime_profile:daemon_release_notice:ack":
12585
+ return { agentId: msg.agentId, launchId: msg.launchId };
12586
+ default:
12587
+ return null;
12588
+ }
12589
+ }
12590
+ flushPendingActivity(ws) {
12591
+ if (this.pendingActivityByAgent.size === 0) return;
12592
+ if (this.ws !== ws || ws.readyState !== WebSocket.OPEN) return;
12593
+ const pending = [...this.pendingActivityByAgent.values()];
12594
+ this.pendingActivityByAgent.clear();
12595
+ for (const msg of pending) {
12596
+ ws.send(JSON.stringify(msg));
12597
+ }
12598
+ this.trace("daemon.connection.outbound_replayed", {
12599
+ message_type: "agent:activity",
12600
+ message_count: pending.length
12601
+ });
12602
+ }
12126
12603
  lastInboundAgeBucket() {
12127
12604
  return durationMsBucket(this.lastInboundAt == null ? null : this.clock.now() - this.lastInboundAt);
12128
12605
  }
@@ -12945,7 +13422,7 @@ var DEFAULT_TRACE_UPLOAD_URL = "https://slock-trace-upload.botiverse.dev";
12945
13422
  var RUNNER_CREDENTIAL_SCOPES = ["send", "read", "mentions", "tasks", "reactions", "server", "channels", "knowledge"];
12946
13423
  var RUNNER_CREDENTIAL_MINT_MAX_ATTEMPTS2 = 3;
12947
13424
  var RUNNER_CREDENTIAL_MINT_RETRY_DELAY_MS2 = 250;
12948
- var DAEMON_CLI_USAGE = `Usage: slock-daemon --server-url <url> (--api-key <key> or ${DAEMON_API_KEY_ENV}=<key>)`;
13425
+ var DAEMON_CLI_USAGE = "Usage: slock-daemon --server-url <url> --api-key <key>";
12949
13426
  var RunnerCredentialMintError2 = class extends Error {
12950
13427
  code;
12951
13428
  retryable;
@@ -12981,9 +13458,9 @@ function runnerCredentialErrorDetail2(error) {
12981
13458
  async function waitForRunnerCredentialRetry2() {
12982
13459
  await new Promise((resolve) => setTimeout(resolve, RUNNER_CREDENTIAL_MINT_RETRY_DELAY_MS2));
12983
13460
  }
12984
- function parseDaemonCliArgs(args, env = {}) {
13461
+ function parseDaemonCliArgs(args) {
12985
13462
  let serverUrl = "";
12986
- let apiKey = env[DAEMON_API_KEY_ENV] ?? "";
13463
+ let apiKey = "";
12987
13464
  for (let i = 0; i < args.length; i++) {
12988
13465
  if (args[i] === "--server-url" && args[i + 1]) serverUrl = args[++i];
12989
13466
  if (args[i] === "--api-key" && args[i + 1]) apiKey = args[++i];
@@ -13752,8 +14229,6 @@ var DaemonCore = class {
13752
14229
  };
13753
14230
 
13754
14231
  export {
13755
- DAEMON_API_KEY_ENV,
13756
- scrubDaemonAuthEnv,
13757
14232
  subscribeDaemonLogs,
13758
14233
  resolveWorkspaceDirectoryPath,
13759
14234
  scanWorkspaceDirectories,