@botiverse/raft-daemon 0.63.7-play.20260628145435 → 0.64.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1698,6 +1698,10 @@ function summarizeToolInput(toolName, input) {
1698
1698
  // ../shared/src/attachmentPreview.ts
1699
1699
  var CSV_PREVIEW_MAX_FILE_SIZE_BYTES = 5 * 1024 * 1024;
1700
1700
 
1701
+ // ../shared/src/brandedIds.ts
1702
+ var asMessageId = (id) => id;
1703
+ var asChannelId = (id) => id;
1704
+
1701
1705
  // ../shared/src/actionCards.ts
1702
1706
  import { z } from "zod";
1703
1707
  var uuidSchema = z.uuid();
@@ -1808,6 +1812,11 @@ var optionalNumberSchema = z2.number().finite().optional();
1808
1812
  var nullableStringSchema = z2.string().nullable();
1809
1813
  var nullableNumberSchema = z2.number().finite().nullable();
1810
1814
  var optionalIsoTimestampSchema = z2.string().datetime().optional();
1815
+ var agentStatusSchema = z2.enum(["active", "inactive", "stopped"]);
1816
+ var reminderStatusSchema = z2.enum(["scheduled", "fired", "canceled"]);
1817
+ var reminderEventTypeSchema = z2.enum(["scheduled", "fired", "snoozed", "updated", "canceled"]);
1818
+ var reasoningEffortSchema = z2.enum(["low", "medium", "high", "xhigh"]);
1819
+ var profileVisibilityMembershipStatusSchema = z2.enum(["active", "removed"]);
1811
1820
  var passthroughObject = (shape) => z2.object(shape).passthrough();
1812
1821
  var taskStatusSchema = z2.enum(["todo", "in_progress", "in_review", "done", "closed"]);
1813
1822
  var agentApiEventsQuerySchema = passthroughObject({
@@ -1821,6 +1830,17 @@ var agentApiHistoryQuerySchema = passthroughObject({
1821
1830
  around: optionalStringSchema,
1822
1831
  limit: optionalStringSchema
1823
1832
  });
1833
+ var agentApiMessageSearchQuerySchema = passthroughObject({
1834
+ q: optionalStringSchema,
1835
+ channel: optionalStringSchema,
1836
+ sender: optionalStringSchema,
1837
+ senderId: optionalStringSchema,
1838
+ sort: z2.enum(["relevance", "recent"]).optional(),
1839
+ before: optionalStringSchema,
1840
+ after: optionalStringSchema,
1841
+ limit: optionalStringSchema,
1842
+ offset: optionalStringSchema
1843
+ });
1824
1844
  var agentApiSendBodySchema = passthroughObject({
1825
1845
  target: z2.string().optional(),
1826
1846
  content: z2.string().optional(),
@@ -1834,10 +1854,10 @@ var agentApiSendBodySchema = passthroughObject({
1834
1854
  seenUpToSeq: optionalNumberSchema
1835
1855
  });
1836
1856
  var agentApiMessageResolveParamsSchema = passthroughObject({
1837
- msgId: z2.string().trim().min(1)
1857
+ msgId: z2.string().trim().min(1).transform(asMessageId)
1838
1858
  });
1839
1859
  var agentApiMessageReactionParamsSchema = passthroughObject({
1840
- msgId: z2.string().trim().min(1)
1860
+ msgId: z2.string().trim().min(1).transform(asMessageId)
1841
1861
  });
1842
1862
  var agentApiMessageReactionBodySchema = passthroughObject({
1843
1863
  emoji: z2.string().trim().min(1).max(16).refine((value) => !/\s/.test(value), {
@@ -1845,8 +1865,20 @@ var agentApiMessageReactionBodySchema = passthroughObject({
1845
1865
  })
1846
1866
  });
1847
1867
  var agentApiChannelMembershipParamsSchema = passthroughObject({
1868
+ channelId: z2.string().trim().min(1).transform(asChannelId)
1869
+ });
1870
+ var agentApiChannelMembersQuerySchema = passthroughObject({
1871
+ channel: z2.string().trim().min(1)
1872
+ });
1873
+ var agentApiResolveChannelBodySchema = passthroughObject({
1874
+ target: z2.string().trim().min(1)
1875
+ });
1876
+ var agentApiResolveChannelResponseSchema = passthroughObject({
1848
1877
  channelId: z2.string().trim().min(1)
1849
1878
  });
1879
+ var agentApiThreadUnfollowBodySchema = passthroughObject({
1880
+ thread: z2.string().trim().min(1)
1881
+ });
1850
1882
  var agentApiTaskClaimBodySchema = passthroughObject({
1851
1883
  channel: z2.string().trim().min(1),
1852
1884
  task_numbers: z2.array(z2.number().int().positive()).optional(),
@@ -1871,6 +1903,128 @@ var agentApiTaskUpdateStatusBodySchema = passthroughObject({
1871
1903
  task_number: z2.number().int().positive(),
1872
1904
  status: taskStatusSchema
1873
1905
  });
1906
+ var agentApiReminderListQuerySchema = passthroughObject({
1907
+ status: optionalStringSchema,
1908
+ all: optionalStringSchema
1909
+ });
1910
+ var agentApiReminderParamsSchema = passthroughObject({
1911
+ reminderId: z2.string().trim().min(1)
1912
+ });
1913
+ var agentApiReminderScheduleBodySchema = passthroughObject({
1914
+ title: z2.string(),
1915
+ fireAt: optionalStringSchema,
1916
+ delaySeconds: optionalNumberSchema,
1917
+ msgId: z2.string().nullable().optional(),
1918
+ payload: z2.unknown().optional(),
1919
+ repeat: optionalStringSchema,
1920
+ tz: optionalStringSchema,
1921
+ channel: optionalStringSchema
1922
+ });
1923
+ var agentApiReminderSnoozeBodySchema = passthroughObject({
1924
+ delaySeconds: z2.number().finite()
1925
+ });
1926
+ var agentApiReminderUpdateBodySchema = passthroughObject({
1927
+ fireAt: optionalStringSchema,
1928
+ delaySeconds: optionalNumberSchema,
1929
+ repeat: optionalStringSchema,
1930
+ title: optionalStringSchema,
1931
+ tz: optionalStringSchema
1932
+ });
1933
+ var agentApiProfileShowQuerySchema = passthroughObject({
1934
+ target: optionalStringSchema
1935
+ });
1936
+ var agentApiProfileUpdateBodySchema = passthroughObject({
1937
+ avatarUrl: optionalStringSchema,
1938
+ displayName: optionalStringSchema,
1939
+ description: optionalStringSchema
1940
+ });
1941
+ var agentApiProfileCreatedAgentSchema = passthroughObject({
1942
+ id: z2.string(),
1943
+ name: z2.string(),
1944
+ displayName: nullableStringSchema,
1945
+ avatarUrl: nullableStringSchema,
1946
+ runtime: z2.string(),
1947
+ status: agentStatusSchema
1948
+ });
1949
+ var agentApiProfileCreatorSchema = z2.union([
1950
+ passthroughObject({
1951
+ type: z2.literal("human"),
1952
+ id: z2.string(),
1953
+ name: z2.string(),
1954
+ displayName: nullableStringSchema,
1955
+ avatarUrl: nullableStringSchema,
1956
+ gravatarHash: z2.string()
1957
+ }),
1958
+ passthroughObject({
1959
+ type: z2.literal("agent"),
1960
+ id: z2.string(),
1961
+ name: z2.string(),
1962
+ displayName: nullableStringSchema,
1963
+ avatarUrl: nullableStringSchema,
1964
+ deletedAt: nullableStringSchema
1965
+ })
1966
+ ]);
1967
+ var agentApiProfileViewSchema = z2.discriminatedUnion("kind", [
1968
+ passthroughObject({
1969
+ kind: z2.literal("human"),
1970
+ id: z2.string(),
1971
+ isSelf: z2.boolean(),
1972
+ name: z2.string(),
1973
+ displayName: nullableStringSchema,
1974
+ description: nullableStringSchema,
1975
+ avatarUrl: nullableStringSchema,
1976
+ email: nullableStringSchema,
1977
+ role: z2.enum(["owner", "admin", "member"]).nullable(),
1978
+ joinedAt: nullableStringSchema,
1979
+ membershipStatus: profileVisibilityMembershipStatusSchema,
1980
+ createdAgents: z2.array(agentApiProfileCreatedAgentSchema)
1981
+ }),
1982
+ passthroughObject({
1983
+ kind: z2.literal("agent"),
1984
+ id: z2.string(),
1985
+ isSelf: z2.boolean(),
1986
+ name: z2.string(),
1987
+ displayName: nullableStringSchema,
1988
+ description: nullableStringSchema,
1989
+ avatarUrl: nullableStringSchema,
1990
+ status: agentStatusSchema,
1991
+ serverRole: z2.enum(["owner", "admin", "member"]).nullable(),
1992
+ runtime: z2.string(),
1993
+ model: z2.string(),
1994
+ reasoningEffort: reasoningEffortSchema.nullable(),
1995
+ executionMode: nullableStringSchema,
1996
+ computerId: nullableStringSchema,
1997
+ computerName: nullableStringSchema,
1998
+ computerHostname: nullableStringSchema,
1999
+ daemonVersion: nullableStringSchema,
2000
+ creator: agentApiProfileCreatorSchema.nullable(),
2001
+ createdAgents: z2.array(agentApiProfileCreatedAgentSchema),
2002
+ createdAt: z2.string(),
2003
+ deletedAt: nullableStringSchema
2004
+ })
2005
+ ]);
2006
+ var agentApiIntegrationLoginBodySchema = passthroughObject({
2007
+ service: z2.string().trim().min(1),
2008
+ scopes: optionalStringArraySchema,
2009
+ target: optionalStringSchema
2010
+ });
2011
+ var agentApiIntegrationAppPrepareBodySchema = passthroughObject({
2012
+ mode: z2.enum(["register", "update"]),
2013
+ target: z2.string().trim().min(1),
2014
+ clientKey: z2.string().trim().min(1),
2015
+ name: optionalStringSchema,
2016
+ description: optionalStringSchema,
2017
+ homepageUrl: optionalStringSchema,
2018
+ returnUrl: optionalStringSchema,
2019
+ agentManifestUrl: optionalStringSchema,
2020
+ scopes: optionalStringArraySchema,
2021
+ unsafeDemoUrlOverride: optionalBooleanSchema,
2022
+ draftHint: optionalStringSchema
2023
+ });
2024
+ var agentApiActionPrepareBodySchema = passthroughObject({
2025
+ target: z2.string().trim().min(1),
2026
+ action: actionCardActionSchema
2027
+ });
1874
2028
  var agentApiServerInfoResponseSchema = passthroughObject({
1875
2029
  runtimeContext: passthroughObject({
1876
2030
  agentId: z2.string(),
@@ -1885,7 +2039,7 @@ var agentApiServerInfoResponseSchema = passthroughObject({
1885
2039
  serverRole: z2.string().nullable().optional(),
1886
2040
  serverCapabilities: passthroughObject({}).optional(),
1887
2041
  channels: z2.array(passthroughObject({
1888
- id: z2.string(),
2042
+ id: z2.string().transform(asChannelId),
1889
2043
  name: z2.string(),
1890
2044
  joined: z2.boolean()
1891
2045
  })),
@@ -1916,10 +2070,69 @@ var agentApiMentionActionsExecuteResponseSchema = passthroughObject({
1916
2070
  action: z2.enum(["notify", "add"]),
1917
2071
  results: z2.array(agentApiMentionActionEnvelopeSchema)
1918
2072
  });
2073
+ var agentApiIntegrationServiceSchema = passthroughObject({
2074
+ id: z2.string(),
2075
+ clientId: z2.string(),
2076
+ appType: z2.enum(["server_local", "slock_builtin", "third_party_global"]).optional(),
2077
+ name: z2.string(),
2078
+ description: nullableStringSchema,
2079
+ homepageUrl: nullableStringSchema,
2080
+ returnUrl: nullableStringSchema,
2081
+ agentManifestUrl: nullableStringSchema,
2082
+ agentManifestUrlSource: z2.enum(["explicit", "well_known"]).nullable().optional(),
2083
+ createdAt: z2.string(),
2084
+ updatedAt: z2.string()
2085
+ });
2086
+ var agentApiActiveIntegrationLoginSchema = passthroughObject({
2087
+ id: z2.string(),
2088
+ serviceId: z2.string(),
2089
+ clientId: z2.string(),
2090
+ appType: z2.enum(["server_local", "slock_builtin", "third_party_global"]).optional(),
2091
+ name: z2.string(),
2092
+ description: nullableStringSchema,
2093
+ homepageUrl: nullableStringSchema,
2094
+ returnUrl: nullableStringSchema,
2095
+ agentManifestUrl: nullableStringSchema,
2096
+ agentManifestUrlSource: z2.enum(["explicit", "well_known"]).nullable().optional(),
2097
+ scopes: z2.array(z2.string()),
2098
+ createdAt: z2.string()
2099
+ });
2100
+ var agentApiIntegrationListResponseSchema = passthroughObject({
2101
+ services: z2.array(agentApiIntegrationServiceSchema),
2102
+ activeLogins: z2.array(agentApiActiveIntegrationLoginSchema)
2103
+ });
2104
+ var agentApiIntegrationLoginResponseSchema = passthroughObject({
2105
+ status: z2.enum(["logged_in", "already_logged_in", "approval_required"]),
2106
+ service: agentApiIntegrationServiceSchema,
2107
+ scopes: z2.array(z2.string()),
2108
+ requestId: z2.string(),
2109
+ approval: passthroughObject({
2110
+ requestId: z2.string(),
2111
+ target: nullableStringSchema,
2112
+ actionCardMessageId: nullableStringSchema
2113
+ }).optional()
2114
+ });
2115
+ var agentApiIntegrationAppPrepareResponseSchema = passthroughObject({
2116
+ status: z2.literal("prepared"),
2117
+ mode: z2.enum(["register", "update"]),
2118
+ target: z2.string(),
2119
+ actionCardMessageId: z2.string(),
2120
+ action: z2.discriminatedUnion("type", [
2121
+ integrationRegisterAppOperationSchema,
2122
+ integrationUpdateAppRegistrationOperationSchema
2123
+ ])
2124
+ });
1919
2125
  var agentApiAttachmentEnvelopeSchema = passthroughObject({
1920
2126
  id: z2.string(),
1921
2127
  filename: z2.string()
1922
2128
  });
2129
+ var agentApiAttachmentUploadResponseSchema = passthroughObject({
2130
+ id: z2.string().trim().min(1),
2131
+ filename: z2.string(),
2132
+ mimeType: nullableStringSchema,
2133
+ sizeBytes: z2.number().int().nonnegative(),
2134
+ thumbnailUrl: nullableStringSchema
2135
+ });
1923
2136
  var agentApiMessageEnvelopeSchema = passthroughObject({
1924
2137
  seq: optionalNumberSchema,
1925
2138
  id: optionalStringSchema,
@@ -2004,6 +2217,46 @@ var agentApiMessageResolveResponseSchema = passthroughObject({
2004
2217
  var agentApiOkResponseSchema = passthroughObject({
2005
2218
  ok: z2.literal(true)
2006
2219
  });
2220
+ var agentApiSearchResultSchema = passthroughObject({
2221
+ id: z2.string(),
2222
+ seq: z2.number().int().nonnegative(),
2223
+ channelId: z2.string(),
2224
+ threadId: z2.string().nullable(),
2225
+ parentMessageId: z2.string().nullable(),
2226
+ parentMessageContent: z2.string().nullable(),
2227
+ parentChannelId: z2.string(),
2228
+ parentChannelName: z2.string(),
2229
+ parentChannelType: z2.string(),
2230
+ parentChannelArchivedAt: nullableStringSchema,
2231
+ senderId: z2.string(),
2232
+ senderType: z2.string(),
2233
+ senderName: z2.string(),
2234
+ channelName: z2.string(),
2235
+ channelType: z2.string(),
2236
+ channelArchivedAt: nullableStringSchema,
2237
+ content: z2.string(),
2238
+ snippet: z2.string(),
2239
+ createdAt: z2.string().datetime()
2240
+ });
2241
+ var agentApiMessageSearchResponseSchema = passthroughObject({
2242
+ results: z2.array(agentApiSearchResultSchema),
2243
+ hasMore: z2.boolean()
2244
+ });
2245
+ var agentApiChannelMembersResponseSchema = passthroughObject({
2246
+ channel: passthroughObject({
2247
+ ref: z2.string(),
2248
+ type: z2.string()
2249
+ }),
2250
+ agents: z2.array(passthroughObject({
2251
+ name: z2.string(),
2252
+ status: optionalStringSchema
2253
+ })),
2254
+ humans: z2.array(passthroughObject({
2255
+ name: z2.string(),
2256
+ description: z2.string().nullable().optional(),
2257
+ role: optionalStringSchema
2258
+ }))
2259
+ });
2007
2260
  var agentApiTaskClaimResultSchema = passthroughObject({
2008
2261
  taskNumber: z2.number().int().positive().optional(),
2009
2262
  messageId: optionalStringSchema,
@@ -2047,6 +2300,48 @@ var agentApiTaskUpdateStatusResponseSchema = z2.union([
2047
2300
  agentApiTaskUpdateStatusSuccessResponseSchema,
2048
2301
  agentApiHeldFreshnessResponseSchema
2049
2302
  ]);
2303
+ var agentApiActionPrepareResponseSchema = passthroughObject({
2304
+ messageId: z2.string(),
2305
+ metadata: passthroughObject({
2306
+ kind: z2.literal("action-card")
2307
+ })
2308
+ });
2309
+ var agentApiReminderRecurrenceSchema = z2.object({
2310
+ kind: z2.enum(["interval", "daily", "weekly", "unsupported"]),
2311
+ description: z2.string()
2312
+ });
2313
+ var agentApiReminderSummarySchema = z2.object({
2314
+ reminderId: z2.string(),
2315
+ ownerAgentId: z2.string(),
2316
+ title: z2.string(),
2317
+ fireAt: z2.string(),
2318
+ firedAt: nullableStringSchema.optional(),
2319
+ createdAt: z2.string(),
2320
+ status: reminderStatusSchema,
2321
+ msgRef: nullableStringSchema,
2322
+ msgPermalink: nullableStringSchema,
2323
+ recurrence: agentApiReminderRecurrenceSchema.nullable()
2324
+ });
2325
+ var agentApiReminderEventSummarySchema = z2.object({
2326
+ eventId: z2.string(),
2327
+ reminderId: z2.string(),
2328
+ eventType: reminderEventTypeSchema,
2329
+ actorType: z2.enum(["agent", "human", "system"]),
2330
+ actorId: nullableStringSchema,
2331
+ occurredAt: z2.string(),
2332
+ nextFireAt: nullableStringSchema,
2333
+ metadata: z2.record(z2.string(), z2.unknown()).nullable()
2334
+ });
2335
+ var agentApiReminderListResponseSchema = passthroughObject({
2336
+ reminders: z2.array(agentApiReminderSummarySchema)
2337
+ });
2338
+ var agentApiReminderResponseSchema = passthroughObject({
2339
+ reminder: agentApiReminderSummarySchema,
2340
+ warning: optionalStringSchema
2341
+ });
2342
+ var agentApiReminderLogResponseSchema = passthroughObject({
2343
+ events: z2.array(agentApiReminderEventSummarySchema)
2344
+ });
2050
2345
  function route(input) {
2051
2346
  return {
2052
2347
  ...input,
@@ -2094,6 +2389,16 @@ var agentApiContract = {
2094
2389
  request: { params: agentApiMessageResolveParamsSchema },
2095
2390
  response: { body: agentApiMessageResolveResponseSchema }
2096
2391
  }),
2392
+ messageSearch: route({
2393
+ key: "messageSearch",
2394
+ method: "GET",
2395
+ path: "/search",
2396
+ client: { resource: "messages", method: "search" },
2397
+ capability: "read",
2398
+ description: "Search messages visible to the bound agent credential.",
2399
+ request: { query: agentApiMessageSearchQuerySchema },
2400
+ response: { body: agentApiMessageSearchResponseSchema }
2401
+ }),
2097
2402
  messageReactionAdd: route({
2098
2403
  key: "messageReactionAdd",
2099
2404
  method: "POST",
@@ -2134,6 +2439,36 @@ var agentApiContract = {
2134
2439
  request: { params: agentApiChannelMembershipParamsSchema },
2135
2440
  response: { body: agentApiOkResponseSchema }
2136
2441
  }),
2442
+ channelMembers: route({
2443
+ key: "channelMembers",
2444
+ method: "GET",
2445
+ path: "/channel-members",
2446
+ client: { resource: "channels", method: "members" },
2447
+ capability: "channels",
2448
+ description: "List agents and humans in a visible channel, DM, or thread.",
2449
+ request: { query: agentApiChannelMembersQuerySchema },
2450
+ response: { body: agentApiChannelMembersResponseSchema }
2451
+ }),
2452
+ resolveChannel: route({
2453
+ key: "resolveChannel",
2454
+ method: "POST",
2455
+ path: "/resolve-channel",
2456
+ client: { resource: "channels", method: "resolve" },
2457
+ capability: "send",
2458
+ description: "Resolve a writable channel, DM, or thread target for the bound agent credential.",
2459
+ request: { body: agentApiResolveChannelBodySchema },
2460
+ response: { body: agentApiResolveChannelResponseSchema }
2461
+ }),
2462
+ threadUnfollow: route({
2463
+ key: "threadUnfollow",
2464
+ method: "POST",
2465
+ path: "/threads/unfollow",
2466
+ client: { resource: "threads", method: "unfollow" },
2467
+ capability: "channels",
2468
+ description: "Stop ordinary delivery for a followed thread as the bound agent credential.",
2469
+ request: { body: agentApiThreadUnfollowBodySchema },
2470
+ response: { body: agentApiOkResponseSchema }
2471
+ }),
2137
2472
  serverInfo: route({
2138
2473
  key: "serverInfo",
2139
2474
  method: "GET",
@@ -2213,6 +2548,136 @@ var agentApiContract = {
2213
2548
  description: "Update a task status.",
2214
2549
  request: { body: agentApiTaskUpdateStatusBodySchema },
2215
2550
  response: { body: agentApiTaskUpdateStatusResponseSchema }
2551
+ }),
2552
+ reminderList: route({
2553
+ key: "reminderList",
2554
+ method: "GET",
2555
+ path: "/reminders",
2556
+ client: { resource: "reminders", method: "list" },
2557
+ capability: "read",
2558
+ description: "List reminders owned by the bound agent credential.",
2559
+ request: { query: agentApiReminderListQuerySchema },
2560
+ response: { body: agentApiReminderListResponseSchema }
2561
+ }),
2562
+ reminderCreate: route({
2563
+ key: "reminderCreate",
2564
+ method: "POST",
2565
+ path: "/reminders",
2566
+ client: { resource: "reminders", method: "create" },
2567
+ capability: "tasks",
2568
+ description: "Create a reminder owned by the bound agent credential.",
2569
+ request: { body: agentApiReminderScheduleBodySchema },
2570
+ response: { body: agentApiReminderResponseSchema }
2571
+ }),
2572
+ reminderCancel: route({
2573
+ key: "reminderCancel",
2574
+ method: "DELETE",
2575
+ path: "/reminders/:reminderId",
2576
+ client: { resource: "reminders", method: "cancel" },
2577
+ capability: "tasks",
2578
+ description: "Cancel a scheduled or fired reminder owned by the bound agent credential.",
2579
+ request: { params: agentApiReminderParamsSchema },
2580
+ response: { body: agentApiReminderResponseSchema }
2581
+ }),
2582
+ reminderSnooze: route({
2583
+ key: "reminderSnooze",
2584
+ method: "POST",
2585
+ path: "/reminders/:reminderId/snooze",
2586
+ client: { resource: "reminders", method: "snooze" },
2587
+ capability: "tasks",
2588
+ description: "Snooze a scheduled or fired reminder owned by the bound agent credential.",
2589
+ request: { params: agentApiReminderParamsSchema, body: agentApiReminderSnoozeBodySchema },
2590
+ response: { body: agentApiReminderResponseSchema }
2591
+ }),
2592
+ reminderUpdate: route({
2593
+ key: "reminderUpdate",
2594
+ method: "PATCH",
2595
+ path: "/reminders/:reminderId",
2596
+ client: { resource: "reminders", method: "update" },
2597
+ capability: "tasks",
2598
+ description: "Update a scheduled reminder owned by the bound agent credential.",
2599
+ request: { params: agentApiReminderParamsSchema, body: agentApiReminderUpdateBodySchema },
2600
+ response: { body: agentApiReminderResponseSchema }
2601
+ }),
2602
+ reminderLog: route({
2603
+ key: "reminderLog",
2604
+ method: "GET",
2605
+ path: "/reminders/:reminderId/log",
2606
+ client: { resource: "reminders", method: "log" },
2607
+ capability: "read",
2608
+ description: "Read lifecycle events for a reminder owned by the bound agent credential.",
2609
+ request: { params: agentApiReminderParamsSchema },
2610
+ response: { body: agentApiReminderLogResponseSchema }
2611
+ }),
2612
+ profileShow: route({
2613
+ key: "profileShow",
2614
+ method: "GET",
2615
+ path: "/profile",
2616
+ client: { resource: "profile", method: "show" },
2617
+ capability: "read",
2618
+ description: "Show the bound agent profile, or another visible profile when target is provided.",
2619
+ request: { query: agentApiProfileShowQuerySchema },
2620
+ response: { body: agentApiProfileViewSchema }
2621
+ }),
2622
+ profileUpdate: route({
2623
+ key: "profileUpdate",
2624
+ method: "POST",
2625
+ path: "/profile",
2626
+ client: { resource: "profile", method: "update" },
2627
+ capability: "server",
2628
+ description: "Update the bound agent profile metadata.",
2629
+ request: { body: agentApiProfileUpdateBodySchema },
2630
+ response: { body: agentApiProfileViewSchema }
2631
+ }),
2632
+ integrationList: route({
2633
+ key: "integrationList",
2634
+ method: "GET",
2635
+ path: "/integrations",
2636
+ client: { resource: "integrations", method: "list" },
2637
+ capability: "read",
2638
+ description: "List available integration services and active agent logins.",
2639
+ request: {},
2640
+ response: { body: agentApiIntegrationListResponseSchema }
2641
+ }),
2642
+ integrationLogin: route({
2643
+ key: "integrationLogin",
2644
+ method: "POST",
2645
+ path: "/integrations/login",
2646
+ client: { resource: "integrations", method: "login" },
2647
+ capability: "read",
2648
+ description: "Provision or reuse this agent's login for a registered integration service.",
2649
+ request: { body: agentApiIntegrationLoginBodySchema },
2650
+ response: { body: agentApiIntegrationLoginResponseSchema }
2651
+ }),
2652
+ integrationAppPrepare: route({
2653
+ key: "integrationAppPrepare",
2654
+ method: "POST",
2655
+ path: "/integrations/app/prepare",
2656
+ client: { resource: "integrations", method: "prepareApp" },
2657
+ capability: "read",
2658
+ description: "Prepare a third-party integration registration/update action card.",
2659
+ request: { body: agentApiIntegrationAppPrepareBodySchema },
2660
+ response: { body: agentApiIntegrationAppPrepareResponseSchema }
2661
+ }),
2662
+ actionPrepare: route({
2663
+ key: "actionPrepare",
2664
+ method: "POST",
2665
+ path: "/prepare-action",
2666
+ client: { resource: "actions", method: "prepare" },
2667
+ capability: "tasks",
2668
+ description: "Prepare an action card for a human to commit.",
2669
+ request: { body: agentApiActionPrepareBodySchema },
2670
+ response: { body: agentApiActionPrepareResponseSchema }
2671
+ }),
2672
+ attachmentUpload: route({
2673
+ key: "attachmentUpload",
2674
+ method: "POST",
2675
+ path: "/upload",
2676
+ client: { resource: "attachments", method: "upload" },
2677
+ capability: "send",
2678
+ description: "Upload a multipart attachment as the bound agent credential.",
2679
+ request: {},
2680
+ response: { body: agentApiAttachmentUploadResponseSchema }
2216
2681
  })
2217
2682
  };
2218
2683
 
@@ -3710,7 +4175,7 @@ function buildPrompt(config, opts) {
3710
4175
  const channelAwarenessSection = cliGuideSections.channelAwareness;
3711
4176
  const thirdPartyIntegrationsSection = `### Third-party integrations
3712
4177
 
3713
- If a built-in Slock app or registered third-party service requires login, use Slock Agent Login through the CLI instead of asking the human to copy tokens or complete human OAuth for you. If a human asks you to sign into, open, use, or fetch identity from a third-party app or built-in Slock app, first run \`raft integration list\` and match the app to a listed service before browsing the app. Use \`raft integration login --service <service>\` to provision or reuse your agent login for that service. If the service exposes an agent behavior manifest and you need to run its local CLI, run \`raft integration env --service <service>\` before invoking that CLI; if it prints exports, apply them first so service credentials stay under a per-agent profile HOME/XDG tree instead of the host user's global HOME. If it reports that no local env is required, do not invent HOME/XDG overrides. If it fails, do not run that local CLI with the host user's HOME; report that the service manifest is unsupported. Slock does not execute commands from remote manifests automatically. If the CLI reports that the \`integration\` command is unknown, the local daemon/CLI is too old for Slock Agent Login; report that the machine must be upgraded/restarted instead of calling internal HTTP endpoints yourself. When the command returns \`Agent login ready\` or \`Already logged in\`, the agent-side login is ready. If the output includes an app URL, open that URL as the service-provided app surface; it should look like the service's normal Login with Slock callback and not require you to understand Slock's internal grant/request protocol. Do not crawl third-party routes looking for a session before trying the registered-service login path. Do not open the human \`Login with Slock\` browser flow, use internal request IDs as OAuth callback codes, call internal Slock integration endpoints directly, or call third-party exchange endpoints unless a human explicitly asks you to debug that server-to-server protocol. If the service or human asks for your Slock Agent identity card, use \`raft profile show\`. Third-party pages may show \`Login with Slock\`; for agent-facing access, prefer the listed service / Slock Agent Login path.`;
4178
+ If a built-in Slock app or registered third-party service requires login, use Slock Agent Login through the CLI instead of asking the human to copy tokens or complete human OAuth for you. If a human asks you to sign into, open, use, or fetch identity from a third-party app or built-in Slock app, first run \`raft integration list\` and match the app to a listed service before browsing the app. Use \`raft integration login --service <service>\` to provision or reuse your agent login for that service. If the service exposes an agent behavior manifest and you need to run its local CLI, run \`raft integration env --service <service>\` before invoking that CLI; if it prints exports, apply them first so service credentials stay under a per-agent profile HOME/XDG tree instead of the host user's global HOME. If it reports that no local env is required, do not invent HOME/XDG overrides. If it fails, do not run that local CLI with the host user's HOME; report that the service manifest is unsupported. Slock does not execute commands from remote manifests automatically. If the CLI reports that the \`integration\` command is unknown, the local daemon/CLI is too old for Slock Agent Login; report that the machine must be upgraded/restarted instead of calling internal HTTP endpoints yourself. When the command returns \`Agent login ready\` or \`Already logged in\`, the agent-side login is ready. If the output includes a service callback handoff URL, treat it as the registered OAuth callback carrying an Agent Login request code, not as a normal browser app URL; open it only when the service documents a stateless Agent Login callback that accepts that URL directly. Otherwise use the service docs, API, or manifest entry point. Do not crawl third-party routes looking for a session before trying the registered-service login path. Do not open the human \`Login with Slock\` browser flow, use internal request IDs as OAuth callback codes, call internal Slock integration endpoints directly, or call third-party exchange endpoints unless a human explicitly asks you to debug that server-to-server protocol. If the service or human asks for your Slock Agent identity card, use \`raft profile show\`. Third-party pages may show \`Login with Slock\`; for agent-facing access, prefer the listed service / Slock Agent Login path.`;
3714
4179
  const readingHistorySection = cliGuideSections.readingHistory;
3715
4180
  const historicalReferenceSection = cliGuideSections.historicalReferences;
3716
4181
  const tasksSection = cliGuideSections.tasks;
@@ -3898,19 +4363,6 @@ function listLegacySlockStatePaths(slockHome = resolveSlockHome(), homeDir = os.
3898
4363
  return candidates.filter((candidate) => existsSync(candidate.path));
3899
4364
  }
3900
4365
 
3901
- // src/authEnv.ts
3902
- var DAEMON_API_KEY_ENV = "SLOCK_MACHINE_API_KEY";
3903
- var SLOCK_AGENT_TOKEN_ENV = "SLOCK_AGENT_TOKEN";
3904
- function scrubDaemonAuthEnv(env) {
3905
- delete env[DAEMON_API_KEY_ENV];
3906
- return env;
3907
- }
3908
- function scrubDaemonChildEnv(env) {
3909
- delete env[DAEMON_API_KEY_ENV];
3910
- delete env[SLOCK_AGENT_TOKEN_ENV];
3911
- return env;
3912
- }
3913
-
3914
4366
  // src/agentCredentialProxy.ts
3915
4367
  import { randomBytes } from "crypto";
3916
4368
  import http from "http";
@@ -5479,9 +5931,7 @@ var LOOPBACK_NO_PROXY = "127.0.0.1,localhost";
5479
5931
  var CLI_TRANSPORT_TRACE_DIR_ENV = "SLOCK_CLI_TRANSPORT_TRACE_DIR";
5480
5932
  var safePathPart = (value) => value.replace(/[^a-zA-Z0-9_.-]/g, "_");
5481
5933
  var RAW_CREDENTIAL_ENV_DENYLIST = [
5482
- "SLOCK_AGENT_TOKEN",
5483
- "SLOCK_AGENT_CREDENTIAL_KEY",
5484
- "SLOCK_AGENT_CREDENTIAL_KEY_FILE"
5934
+ "SLOCK_AGENT_CREDENTIAL_KEY"
5485
5935
  ];
5486
5936
  var WORKSPACE_CLI_TRANSPORT_FILENAMES = [
5487
5937
  "agent-token",
@@ -5836,7 +6286,7 @@ set "SLOCK_AGENT_ACTIVE_CAPABILITIES=${DEFAULT_ACTIVE_CAPABILITIES}"\r
5836
6286
  SLOCK_SERVER_URL: ctx.config.serverUrl,
5837
6287
  PATH: `${slockDir}${path2.delimiter}${process.env.PATH ?? ""}`
5838
6288
  };
5839
- scrubDaemonChildEnv(spawnEnv);
6289
+ delete spawnEnv.SLOCK_AGENT_TOKEN;
5840
6290
  for (const key of RAW_CREDENTIAL_ENV_DENYLIST) {
5841
6291
  delete spawnEnv[key];
5842
6292
  }
@@ -6358,7 +6808,7 @@ function requiresWindowsShell(command, platform = process.platform) {
6358
6808
  }
6359
6809
  function resolveCommandOnPath(command, deps = {}) {
6360
6810
  const platform = deps.platform ?? process.platform;
6361
- const env = scrubDaemonChildEnv({ ...withWindowsUserEnvironment(deps.env ?? process.env, deps) });
6811
+ const env = withWindowsUserEnvironment(deps.env ?? process.env, deps);
6362
6812
  const execFileSyncFn = deps.execFileSyncFn ?? execFileSync;
6363
6813
  const existsSyncFn = deps.existsSyncFn ?? existsSync3;
6364
6814
  if (platform === "win32") {
@@ -6384,7 +6834,7 @@ function firstExistingPath(candidates, deps = {}) {
6384
6834
  return null;
6385
6835
  }
6386
6836
  function readCommandVersion(command, args = [], deps = {}) {
6387
- const env = scrubDaemonChildEnv({ ...withWindowsUserEnvironment(deps.env ?? process.env, deps) });
6837
+ const env = withWindowsUserEnvironment(deps.env ?? process.env, deps);
6388
6838
  const execFileSyncFn = deps.execFileSyncFn ?? execFileSync;
6389
6839
  try {
6390
6840
  const output = normalizeExecOutput(execFileSyncFn(command, [...args, "--version"], {
@@ -8468,11 +8918,11 @@ function detectCursorModels(runCommand = runCursorModelsCommand) {
8468
8918
  return parseCursorModelsOutput(String(result.stdout || ""));
8469
8919
  }
8470
8920
  function buildCursorModelProbeEnv(deps = {}) {
8471
- return scrubDaemonChildEnv(withWindowsUserEnvironment({
8921
+ return withWindowsUserEnvironment({
8472
8922
  ...deps.env ?? process.env,
8473
8923
  FORCE_COLOR: "0",
8474
8924
  NO_COLOR: "1"
8475
- }, deps));
8925
+ }, deps);
8476
8926
  }
8477
8927
  function runCursorModelsCommand() {
8478
8928
  return spawnSync("cursor-agent", ["models"], {
@@ -8528,7 +8978,7 @@ function resolveGeminiSpawn(commandArgs, deps = {}) {
8528
8978
  }
8529
8979
  const execFileSyncFn = deps.execFileSyncFn ?? execFileSync3;
8530
8980
  const existsSyncFn = deps.existsSyncFn ?? existsSync5;
8531
- const env = scrubDaemonChildEnv({ ...deps.env ?? process.env });
8981
+ const env = deps.env ?? process.env;
8532
8982
  const winPath = path8.win32;
8533
8983
  let geminiEntry = null;
8534
8984
  try {
@@ -8665,15 +9115,12 @@ var GeminiDriver = class {
8665
9115
  // src/drivers/kimi.ts
8666
9116
  import { randomUUID as randomUUID2 } from "crypto";
8667
9117
  import { spawn as spawn7 } from "child_process";
8668
- import { chmodSync, existsSync as existsSync6, readFileSync as readFileSync3, writeFileSync as writeFileSync3 } from "fs";
9118
+ import { existsSync as existsSync6, readFileSync as readFileSync3, writeFileSync as writeFileSync3 } from "fs";
8669
9119
  import os4 from "os";
8670
9120
  import path9 from "path";
8671
9121
  var KIMI_WIRE_PROTOCOL_VERSION = "1.3";
8672
9122
  var KIMI_SYSTEM_PROMPT_FILE = ".slock-kimi-system.md";
8673
9123
  var KIMI_AGENT_FILE = ".slock-kimi-agent.yaml";
8674
- var KIMI_GENERATED_CONFIG_FILE = ".slock-kimi-config.toml";
8675
- var SLOCK_KIMI_CONFIG_CONTENT_ENV = "SLOCK_KIMI_CONFIG_CONTENT";
8676
- var SLOCK_KIMI_CONFIG_FILE_ENV = "SLOCK_KIMI_CONFIG_FILE";
8677
9124
  function parseToolArguments(raw) {
8678
9125
  if (typeof raw !== "string") return raw;
8679
9126
  try {
@@ -8682,73 +9129,6 @@ function parseToolArguments(raw) {
8682
9129
  return raw;
8683
9130
  }
8684
9131
  }
8685
- function readKimiConfigSource(home = os4.homedir(), env = process.env) {
8686
- const inlineConfig = env[SLOCK_KIMI_CONFIG_CONTENT_ENV];
8687
- if (inlineConfig && inlineConfig.trim()) {
8688
- return {
8689
- raw: inlineConfig,
8690
- explicitPath: null,
8691
- sourcePath: SLOCK_KIMI_CONFIG_CONTENT_ENV
8692
- };
8693
- }
8694
- const explicitPath = env[SLOCK_KIMI_CONFIG_FILE_ENV];
8695
- const configPath = explicitPath && explicitPath.trim() ? explicitPath : path9.join(home, ".kimi", "config.toml");
8696
- try {
8697
- return {
8698
- raw: readFileSync3(configPath, "utf8"),
8699
- explicitPath: explicitPath && explicitPath.trim() ? explicitPath : null,
8700
- sourcePath: configPath
8701
- };
8702
- } catch {
8703
- return {
8704
- raw: null,
8705
- explicitPath: explicitPath && explicitPath.trim() ? explicitPath : null,
8706
- sourcePath: configPath
8707
- };
8708
- }
8709
- }
8710
- function buildKimiSpawnEnv(env = process.env) {
8711
- const spawnEnv = { ...env, FORCE_COLOR: "0", NO_COLOR: "1" };
8712
- delete spawnEnv[SLOCK_KIMI_CONFIG_CONTENT_ENV];
8713
- delete spawnEnv[SLOCK_KIMI_CONFIG_FILE_ENV];
8714
- return scrubDaemonChildEnv(spawnEnv);
8715
- }
8716
- function buildKimiEffectiveEnv(ctx, overrideEnv) {
8717
- return {
8718
- ...process.env,
8719
- ...ctx.config.envVars || {},
8720
- ...overrideEnv || {}
8721
- };
8722
- }
8723
- function buildKimiLaunchOptions(ctx, opts = {}) {
8724
- const env = buildKimiEffectiveEnv(ctx, opts.env);
8725
- const source = readKimiConfigSource(opts.home ?? os4.homedir(), env);
8726
- const args = [];
8727
- let configFilePath = null;
8728
- let configContent = null;
8729
- if (source.explicitPath) {
8730
- configFilePath = source.explicitPath;
8731
- } else if (source.raw !== null && source.sourcePath === SLOCK_KIMI_CONFIG_CONTENT_ENV) {
8732
- configFilePath = path9.join(ctx.workingDirectory, KIMI_GENERATED_CONFIG_FILE);
8733
- configContent = source.raw;
8734
- if (opts.writeGeneratedConfig !== false) {
8735
- writeFileSync3(configFilePath, source.raw, { encoding: "utf8", mode: 384 });
8736
- chmodSync(configFilePath, 384);
8737
- }
8738
- }
8739
- if (configFilePath) {
8740
- args.push("--config-file", configFilePath);
8741
- }
8742
- if (ctx.config.model && ctx.config.model !== "default") {
8743
- args.push("--model", ctx.config.model);
8744
- }
8745
- return {
8746
- args,
8747
- env: buildKimiSpawnEnv(env),
8748
- configFilePath,
8749
- configContent
8750
- };
8751
- }
8752
9132
  function resolveKimiSpawn(commandArgs, deps = {}) {
8753
9133
  return {
8754
9134
  command: resolveCommandOnPath("kimi", deps) ?? "kimi",
@@ -8772,25 +9152,7 @@ var KimiDriver = class {
8772
9152
  };
8773
9153
  model = {
8774
9154
  detectedModelsVerifiedAs: "launchable",
8775
- toLaunchSpec: (modelId, ctx, opts) => {
8776
- if (!ctx) return { args: ["--model", modelId] };
8777
- const launchCtx = {
8778
- ...ctx,
8779
- config: {
8780
- ...ctx.config,
8781
- model: modelId
8782
- }
8783
- };
8784
- const launch = buildKimiLaunchOptions(launchCtx, {
8785
- home: opts?.home,
8786
- writeGeneratedConfig: false
8787
- });
8788
- return {
8789
- args: launch.args,
8790
- env: launch.env,
8791
- configFiles: launch.configFilePath ? [launch.configFilePath] : void 0
8792
- };
8793
- }
9155
+ toLaunchSpec: (modelId) => ({ args: ["--model", modelId] })
8794
9156
  };
8795
9157
  supportsStdinNotification = true;
8796
9158
  busyDeliveryMode = "direct";
@@ -8814,23 +9176,21 @@ var KimiDriver = class {
8814
9176
  ` system_prompt_path: ./${KIMI_SYSTEM_PROMPT_FILE}`,
8815
9177
  ""
8816
9178
  ].join("\n"), "utf8");
8817
- const launch = buildKimiLaunchOptions(ctx);
8818
9179
  const args = [
8819
9180
  "--wire",
8820
9181
  "--yolo",
8821
9182
  "--agent-file",
8822
9183
  agentFilePath,
8823
9184
  "--session",
8824
- this.sessionId,
8825
- ...launch.args
9185
+ this.sessionId
8826
9186
  ];
8827
9187
  const launchRuntimeFields = runtimeConfigToLaunchFields(hydrateRuntimeConfig(ctx.config));
8828
9188
  if (launchRuntimeFields.model && launchRuntimeFields.model !== "default") {
8829
9189
  args.push("--model", launchRuntimeFields.model);
8830
9190
  }
8831
9191
  const spawnEnv = (await prepareCliTransport(ctx, { NO_COLOR: "1" })).spawnEnv;
8832
- const spawnTarget = resolveKimiSpawn(args);
8833
- const proc = spawn7(spawnTarget.command, spawnTarget.args, {
9192
+ const launch = resolveKimiSpawn(args);
9193
+ const proc = spawn7(launch.command, launch.args, {
8834
9194
  cwd: ctx.workingDirectory,
8835
9195
  stdio: ["pipe", "pipe", "pipe"],
8836
9196
  env: spawnEnv,
@@ -8838,7 +9198,7 @@ var KimiDriver = class {
8838
9198
  // and has an 8191-character command-line limit. Kimi's official
8839
9199
  // installer/uv entrypoint is an executable, so launch it directly and
8840
9200
  // keep prompts on stdin / files instead of routing through cmd.exe.
8841
- shell: spawnTarget.shell
9201
+ shell: launch.shell
8842
9202
  });
8843
9203
  proc.stdin?.write(JSON.stringify({
8844
9204
  jsonrpc: "2.0",
@@ -8951,9 +9311,14 @@ var KimiDriver = class {
8951
9311
  return detectKimiModels();
8952
9312
  }
8953
9313
  };
8954
- function detectKimiModels(home = os4.homedir(), opts = {}) {
8955
- const raw = readKimiConfigSource(home, opts.env).raw;
8956
- if (raw === null) return null;
9314
+ function detectKimiModels(home = os4.homedir()) {
9315
+ const configPath = path9.join(home, ".kimi", "config.toml");
9316
+ let raw;
9317
+ try {
9318
+ raw = readFileSync3(configPath, "utf8");
9319
+ } catch {
9320
+ return null;
9321
+ }
8957
9322
  const models = [];
8958
9323
  const sectionRe = /^\s*\[models(?:\.([^\]]+)|"\.[^"]+"|\."[^"]+")\s*\]\s*$/gm;
8959
9324
  const lineRe = /^\s*\[models\.(.+?)\s*\]\s*$/gm;
@@ -9619,7 +9984,7 @@ function runOpenCodeModelsCommand(home, deps = {}) {
9619
9984
  const platform = deps.platform ?? process.platform;
9620
9985
  const spawnSyncFn = deps.spawnSyncFn ?? spawnSync2;
9621
9986
  const result = spawnSyncFn("opencode", ["models"], {
9622
- env: scrubDaemonChildEnv({ ...process.env, HOME: home, FORCE_COLOR: "0", NO_COLOR: "1" }),
9987
+ env: { ...process.env, HOME: home, FORCE_COLOR: "0", NO_COLOR: "1" },
9623
9988
  encoding: "utf8",
9624
9989
  timeout: 5e3,
9625
9990
  shell: platform === "win32"
@@ -10958,6 +11323,459 @@ async function deleteWorkspaceDirectory(dataDir, directoryName) {
10958
11323
  }
10959
11324
  }
10960
11325
 
11326
+ // src/agentStartCoordinator.ts
11327
+ var AgentStartCoordinator = class {
11328
+ starting = /* @__PURE__ */ new Set();
11329
+ queuedByAgent = /* @__PURE__ */ new Map();
11330
+ queue = [];
11331
+ activeStarts = 0;
11332
+ pumpTimer = null;
11333
+ lastStartAt = 0;
11334
+ lastStartAgentId = null;
11335
+ maxConcurrentStarts;
11336
+ minStartIntervalMs;
11337
+ constructor(opts) {
11338
+ this.maxConcurrentStarts = Math.max(1, Math.floor(opts.maxConcurrentStarts));
11339
+ this.minStartIntervalMs = Math.max(0, Math.floor(opts.minStartIntervalMs));
11340
+ this.assertInvariants("constructor");
11341
+ }
11342
+ snapshot() {
11343
+ return {
11344
+ activeStarts: this.activeStarts,
11345
+ queueDepth: this.queue.length,
11346
+ maxConcurrentStarts: this.maxConcurrentStarts,
11347
+ minStartIntervalMs: this.minStartIntervalMs,
11348
+ startingAgentIds: [...this.starting],
11349
+ queuedAgentIds: [...this.queuedByAgent.keys()],
11350
+ pumpTimerActive: this.pumpTimer !== null
11351
+ };
11352
+ }
11353
+ hasStarting(agentId) {
11354
+ return this.starting.has(agentId);
11355
+ }
11356
+ hasQueued(agentId) {
11357
+ return this.queuedByAgent.has(agentId);
11358
+ }
11359
+ getQueued(agentId) {
11360
+ return this.queuedByAgent.get(agentId);
11361
+ }
11362
+ enqueue(item) {
11363
+ if (this.starting.has(item.agentId)) {
11364
+ throw new Error(`Agent start invariant violation after enqueue: ${item.agentId} is already starting`);
11365
+ }
11366
+ if (this.queuedByAgent.has(item.agentId)) {
11367
+ throw new Error(`Agent start invariant violation after enqueue: ${item.agentId} is already queued`);
11368
+ }
11369
+ this.queue.push(item);
11370
+ this.queuedByAgent.set(item.agentId, item);
11371
+ this.assertInvariants("enqueue");
11372
+ }
11373
+ markStarting(agentId) {
11374
+ if (this.queuedByAgent.has(agentId)) {
11375
+ throw new Error(`Agent start invariant violation after markStarting: ${agentId} is still queued`);
11376
+ }
11377
+ this.starting.add(agentId);
11378
+ this.assertInvariants("markStarting");
11379
+ }
11380
+ clearStarting(agentId) {
11381
+ this.starting.delete(agentId);
11382
+ this.assertInvariants("clearStarting");
11383
+ }
11384
+ getPumpState(now = Date.now()) {
11385
+ if (this.pumpTimer) return { kind: "blocked", reason: "timer_active" };
11386
+ if (this.queue.length === 0) return { kind: "blocked", reason: "queue_empty" };
11387
+ if (this.activeStarts >= this.maxConcurrentStarts) return { kind: "blocked", reason: "capacity_full" };
11388
+ const item = this.queue[0];
11389
+ if (!item) return { kind: "blocked", reason: "queue_empty" };
11390
+ const shouldRateLimit = item.agentId !== this.lastStartAgentId;
11391
+ const elapsed = now - this.lastStartAt;
11392
+ const waitMs = shouldRateLimit ? Math.max(0, this.minStartIntervalMs - elapsed) : 0;
11393
+ if (waitMs > 0) return { kind: "rate_limited", item, waitMs };
11394
+ return { kind: "ready", item };
11395
+ }
11396
+ schedulePump(waitMs, callback) {
11397
+ if (this.pumpTimer) return;
11398
+ this.pumpTimer = setTimeout(() => {
11399
+ this.pumpTimer = null;
11400
+ callback();
11401
+ }, waitMs);
11402
+ this.assertInvariants("schedulePump");
11403
+ }
11404
+ dequeue() {
11405
+ const item = this.queue.shift();
11406
+ if (!item) {
11407
+ this.assertInvariants("dequeue empty");
11408
+ return { kind: "empty" };
11409
+ }
11410
+ if (this.queuedByAgent.get(item.agentId) !== item) {
11411
+ this.assertInvariants("dequeue stale");
11412
+ return { kind: "stale", item };
11413
+ }
11414
+ this.queuedByAgent.delete(item.agentId);
11415
+ this.assertInvariants("dequeue");
11416
+ return { kind: "item", item };
11417
+ }
11418
+ claimStartSlot(agentId, now = Date.now()) {
11419
+ this.activeStarts++;
11420
+ this.lastStartAt = now;
11421
+ this.lastStartAgentId = agentId;
11422
+ this.assertInvariants("claimStartSlot");
11423
+ }
11424
+ releaseStartSlot() {
11425
+ if (this.activeStarts <= 0) return false;
11426
+ this.activeStarts = Math.max(0, this.activeStarts - 1);
11427
+ this.assertInvariants("releaseStartSlot");
11428
+ return true;
11429
+ }
11430
+ cancelQueued(agentId) {
11431
+ const item = this.queuedByAgent.get(agentId);
11432
+ if (!item) return void 0;
11433
+ this.queuedByAgent.delete(agentId);
11434
+ this.queue = this.queue.filter((candidate) => candidate !== item);
11435
+ this.clearPumpTimerIfIdle();
11436
+ this.assertInvariants("cancelQueued");
11437
+ return item;
11438
+ }
11439
+ cancelAllQueued(onCancel) {
11440
+ const items = [];
11441
+ for (const item of this.queue) {
11442
+ if (this.queuedByAgent.get(item.agentId) === item) {
11443
+ items.push(item);
11444
+ onCancel?.(item);
11445
+ }
11446
+ }
11447
+ this.queue = [];
11448
+ this.queuedByAgent.clear();
11449
+ this.clearPumpTimer();
11450
+ this.assertInvariants("cancelAllQueued");
11451
+ return items;
11452
+ }
11453
+ assertInvariants(context) {
11454
+ if (this.activeStarts < 0) {
11455
+ throw new Error(`Agent start invariant violation after ${context}: activeStarts is negative`);
11456
+ }
11457
+ if (this.activeStarts > this.maxConcurrentStarts) {
11458
+ throw new Error(`Agent start invariant violation after ${context}: activeStarts exceeds maxConcurrentStarts`);
11459
+ }
11460
+ const queuedIds = /* @__PURE__ */ new Set();
11461
+ for (const item of this.queue) {
11462
+ if (queuedIds.has(item.agentId)) {
11463
+ throw new Error(`Agent start invariant violation after ${context}: duplicate queued agent ${item.agentId}`);
11464
+ }
11465
+ queuedIds.add(item.agentId);
11466
+ if (this.queuedByAgent.get(item.agentId) !== item) {
11467
+ throw new Error(`Agent start invariant violation after ${context}: queue/map mismatch for ${item.agentId}`);
11468
+ }
11469
+ if (this.starting.has(item.agentId)) {
11470
+ throw new Error(`Agent start invariant violation after ${context}: ${item.agentId} is queued and starting`);
11471
+ }
11472
+ }
11473
+ if (queuedIds.size !== this.queuedByAgent.size) {
11474
+ throw new Error(`Agent start invariant violation after ${context}: queue/map size mismatch`);
11475
+ }
11476
+ for (const [agentId, item] of this.queuedByAgent) {
11477
+ if (!queuedIds.has(agentId)) {
11478
+ throw new Error(`Agent start invariant violation after ${context}: map-only queued agent ${agentId}`);
11479
+ }
11480
+ if (item.agentId !== agentId) {
11481
+ throw new Error(`Agent start invariant violation after ${context}: map key/item agent mismatch for ${agentId}`);
11482
+ }
11483
+ }
11484
+ }
11485
+ setMaxConcurrentStartsForTesting(value) {
11486
+ this.maxConcurrentStarts = Math.max(1, Math.floor(value));
11487
+ if (this.activeStarts > this.maxConcurrentStarts) {
11488
+ this.activeStarts = this.maxConcurrentStarts;
11489
+ }
11490
+ this.assertInvariants("setMaxConcurrentStartsForTesting");
11491
+ }
11492
+ setActiveStartsForTesting(value) {
11493
+ this.activeStarts = Math.max(0, Math.floor(value));
11494
+ this.assertInvariants("setActiveStartsForTesting");
11495
+ }
11496
+ clearPumpTimerIfIdle() {
11497
+ if (this.queue.length === 0) {
11498
+ this.clearPumpTimer();
11499
+ }
11500
+ }
11501
+ clearPumpTimer() {
11502
+ if (this.pumpTimer) {
11503
+ clearTimeout(this.pumpTimer);
11504
+ this.pumpTimer = null;
11505
+ }
11506
+ }
11507
+ };
11508
+
11509
+ // src/agentStartPendingDeliveryBuffer.ts
11510
+ var AgentStartPendingDeliveryBuffer = class {
11511
+ pending = /* @__PURE__ */ new Map();
11512
+ count(agentId) {
11513
+ return this.pending.get(agentId)?.length ?? 0;
11514
+ }
11515
+ has(agentId) {
11516
+ return this.pending.has(agentId);
11517
+ }
11518
+ get size() {
11519
+ return this.pending.size;
11520
+ }
11521
+ values(agentId) {
11522
+ return [...this.pending.get(agentId) ?? []];
11523
+ }
11524
+ bufferDuringStart(agentId, message) {
11525
+ return this.append(agentId, [message], "bufferDuringStart");
11526
+ }
11527
+ bufferMessagesDuringStart(agentId, messages) {
11528
+ return this.append(agentId, messages, "bufferMessagesDuringStart");
11529
+ }
11530
+ rebindWake(agentId, previousWakeMessage, nextWakeMessage, sameWakeMessage) {
11531
+ if (!previousWakeMessage || !nextWakeMessage || sameWakeMessage(previousWakeMessage, nextWakeMessage)) {
11532
+ return this.count(agentId);
11533
+ }
11534
+ return this.append(agentId, [previousWakeMessage], "rebindWake");
11535
+ }
11536
+ drainOnSpawn(agentId) {
11537
+ const messages = this.pending.get(agentId) ?? [];
11538
+ this.pending.delete(agentId);
11539
+ this.assertInternalInvariants("drainOnSpawn");
11540
+ return messages;
11541
+ }
11542
+ cancelStart(agentId) {
11543
+ this.pending.delete(agentId);
11544
+ this.assertInternalInvariants("cancelStart");
11545
+ }
11546
+ cancelAllStarts() {
11547
+ this.pending.clear();
11548
+ this.assertInternalInvariants("cancelAllStarts");
11549
+ }
11550
+ suppressConsumed(agentId, predicate) {
11551
+ const messages = this.pending.get(agentId);
11552
+ if (!messages || messages.length === 0) return 0;
11553
+ let removed = 0;
11554
+ const retained = messages.filter((message) => {
11555
+ const matched = predicate(message);
11556
+ if (matched) removed += 1;
11557
+ return !matched;
11558
+ });
11559
+ if (retained.length === 0) {
11560
+ this.pending.delete(agentId);
11561
+ } else {
11562
+ this.pending.set(agentId, retained);
11563
+ }
11564
+ this.assertInternalInvariants("suppressConsumed");
11565
+ return removed;
11566
+ }
11567
+ purge(agentId, predicate) {
11568
+ return this.suppressConsumed(agentId, predicate);
11569
+ }
11570
+ assertInvariants(context, snapshot) {
11571
+ this.assertInternalInvariants(context);
11572
+ const allowed = /* @__PURE__ */ new Set([
11573
+ ...snapshot.queuedAgentIds,
11574
+ ...snapshot.startingAgentIds,
11575
+ ...snapshot.terminalRecoveryAgentIds ?? [],
11576
+ ...snapshot.cooldownAgentIds ?? []
11577
+ ]);
11578
+ for (const agentId of this.pending.keys()) {
11579
+ if (!allowed.has(agentId)) {
11580
+ throw new Error(`Agent start pending delivery invariant violation after ${context}: pending messages for non-starting agent ${agentId}`);
11581
+ }
11582
+ }
11583
+ }
11584
+ append(agentId, messages, context) {
11585
+ if (messages.length === 0) return this.count(agentId);
11586
+ const existing = this.pending.get(agentId);
11587
+ if (existing) {
11588
+ existing.push(...messages);
11589
+ } else {
11590
+ this.pending.set(agentId, [...messages]);
11591
+ }
11592
+ this.assertInternalInvariants(context);
11593
+ return this.count(agentId);
11594
+ }
11595
+ assertInternalInvariants(context) {
11596
+ for (const [agentId, messages] of this.pending) {
11597
+ if (!agentId) {
11598
+ throw new Error(`Agent start pending delivery invariant violation after ${context}: empty agent id`);
11599
+ }
11600
+ if (messages.length === 0) {
11601
+ throw new Error(`Agent start pending delivery invariant violation after ${context}: empty pending buffer for ${agentId}`);
11602
+ }
11603
+ }
11604
+ }
11605
+ };
11606
+
11607
+ // src/agentVisibleDeliveryLedger.ts
11608
+ function getMessageShortId(messageId2) {
11609
+ return messageId2.startsWith("thread-") ? messageId2.slice(7) : messageId2.slice(0, 8);
11610
+ }
11611
+ function computeTarget(channelType, channelName, parentChannelName, parentChannelType) {
11612
+ if (channelType === "thread" && parentChannelName) {
11613
+ const shortId = getMessageShortId(String(channelName ?? ""));
11614
+ if (parentChannelType === "dm") {
11615
+ return `dm:@${parentChannelName}:${shortId}`;
11616
+ }
11617
+ return `#${parentChannelName}:${shortId}`;
11618
+ }
11619
+ if (channelType === "dm") {
11620
+ return `dm:@${channelName}`;
11621
+ }
11622
+ return `#${channelName}`;
11623
+ }
11624
+ function formatAgentMessageVisibleTarget(message) {
11625
+ return computeTarget(message.channel_type, message.channel_name, message.parent_channel_name, message.parent_channel_type);
11626
+ }
11627
+ function formatProxyVisibleMessageTarget(message) {
11628
+ return computeTarget(message.channel_type, message.channel_name, message.parent_channel_name, message.parent_channel_type);
11629
+ }
11630
+ function hasTargetMetadata(message) {
11631
+ if (message.channel_type === "thread") return Boolean(message.parent_channel_name && message.channel_name);
11632
+ return Boolean(message.channel_type && message.channel_name);
11633
+ }
11634
+ function visibleMessageId(message) {
11635
+ if (typeof message.message_id === "string") return String(message.message_id);
11636
+ if (typeof message.id === "string") return String(message.id);
11637
+ return "";
11638
+ }
11639
+ function isTrueDeliveryConsumeSource(source) {
11640
+ return source === "spawn_wake_message" || source === "agent_api_events_local" || source.startsWith("stdin_");
11641
+ }
11642
+ var AgentVisibleDeliveryLedger = class {
11643
+ boundaryByAgent = /* @__PURE__ */ new Map();
11644
+ messageIdsByAgent = /* @__PURE__ */ new Map();
11645
+ clearAgent(agentId) {
11646
+ this.boundaryByAgent.delete(agentId);
11647
+ this.messageIdsByAgent.delete(agentId);
11648
+ }
11649
+ hasAgentState(agentId) {
11650
+ return this.boundaryByAgent.has(agentId) || this.messageIdsByAgent.has(agentId);
11651
+ }
11652
+ getBoundary(agentId, target) {
11653
+ return this.boundaryByAgent.get(agentId)?.get(target);
11654
+ }
11655
+ getMessageIdSet(agentId, target) {
11656
+ return this.messageIdsByAgent.get(agentId)?.get(target);
11657
+ }
11658
+ isModelSeen(agentId, target, message) {
11659
+ const seq = Number(message.seq ?? 0);
11660
+ const boundary = this.getBoundary(agentId, target);
11661
+ if (Number.isFinite(seq) && seq > 0 && typeof boundary === "number" && boundary >= Math.floor(seq)) return true;
11662
+ const id = visibleMessageId(message);
11663
+ return id.length > 0 && this.getMessageIdSet(agentId, target)?.has(id) === true;
11664
+ }
11665
+ recordConsumed(agentId, input) {
11666
+ if (input.messages.length === 0 && (!input.target || typeof input.boundarySeq !== "number")) return null;
11667
+ const byTarget = /* @__PURE__ */ new Map();
11668
+ const ensureBucket = (target) => {
11669
+ let bucket = byTarget.get(target);
11670
+ if (!bucket) {
11671
+ bucket = { maxSeq: 0, boundarySeq: 0, seqs: /* @__PURE__ */ new Set(), ids: /* @__PURE__ */ new Set() };
11672
+ byTarget.set(target, bucket);
11673
+ }
11674
+ return bucket;
11675
+ };
11676
+ for (const message of input.messages) {
11677
+ const messageTarget = formatProxyVisibleMessageTarget(message);
11678
+ if (input.target && hasTargetMetadata(message) && messageTarget !== input.target) {
11679
+ throw new Error(`AgentVisibleDeliveryLedger target mismatch: explicit target ${input.target} does not match visible message target ${messageTarget}`);
11680
+ }
11681
+ const target = input.target ?? messageTarget;
11682
+ if (!target) continue;
11683
+ const bucket = ensureBucket(target);
11684
+ const seq = Number(message.seq ?? 0);
11685
+ if (Number.isFinite(seq) && seq > 0) {
11686
+ const normalizedSeq = Math.floor(seq);
11687
+ bucket.maxSeq = Math.max(bucket.maxSeq, normalizedSeq);
11688
+ bucket.seqs.add(normalizedSeq);
11689
+ }
11690
+ const id = visibleMessageId(message);
11691
+ if (id.length > 0) bucket.ids.add(id);
11692
+ }
11693
+ if (input.target && typeof input.boundarySeq === "number" && Number.isFinite(input.boundarySeq) && input.boundarySeq > 0) {
11694
+ const bucket = ensureBucket(input.target);
11695
+ bucket.boundarySeq = Math.max(bucket.boundarySeq, Math.floor(input.boundarySeq));
11696
+ }
11697
+ if (byTarget.size === 0) return null;
11698
+ const advancesBoundary = isTrueDeliveryConsumeSource(input.source);
11699
+ for (const [target, bucket] of byTarget) {
11700
+ const previousBoundary = this.getBoundary(agentId, target);
11701
+ if (advancesBoundary) {
11702
+ const highWaterSeq = Math.max(bucket.maxSeq, bucket.boundarySeq);
11703
+ const boundaryMap = this.boundaryMap(agentId);
11704
+ boundaryMap.set(target, Math.max(previousBoundary ?? 0, highWaterSeq));
11705
+ }
11706
+ if (bucket.ids.size > 0) {
11707
+ const targetIds = this.messageIdSet(agentId, target);
11708
+ for (const id of bucket.ids) targetIds.add(id);
11709
+ }
11710
+ this.assertConsumedInvariants("recordConsumed", agentId, target, bucket, {
11711
+ advancesBoundary,
11712
+ previousBoundary
11713
+ });
11714
+ }
11715
+ return {
11716
+ targets: [...byTarget.keys()],
11717
+ messagesCount: input.messages.length,
11718
+ shouldSuppress(message) {
11719
+ const target = formatAgentMessageVisibleTarget(message);
11720
+ const bucket = byTarget.get(target);
11721
+ if (!bucket) return false;
11722
+ const seq = typeof message.seq === "number" ? Math.floor(message.seq) : 0;
11723
+ const id = visibleMessageId(message);
11724
+ return seq > 0 && bucket.boundarySeq > 0 && seq <= bucket.boundarySeq || seq > 0 && bucket.seqs.has(seq) || id.length > 0 && bucket.ids.has(id);
11725
+ }
11726
+ };
11727
+ }
11728
+ boundaryMap(agentId) {
11729
+ let map = this.boundaryByAgent.get(agentId);
11730
+ if (!map) {
11731
+ map = /* @__PURE__ */ new Map();
11732
+ this.boundaryByAgent.set(agentId, map);
11733
+ }
11734
+ return map;
11735
+ }
11736
+ messageIdMap(agentId) {
11737
+ let map = this.messageIdsByAgent.get(agentId);
11738
+ if (!map) {
11739
+ map = /* @__PURE__ */ new Map();
11740
+ this.messageIdsByAgent.set(agentId, map);
11741
+ }
11742
+ return map;
11743
+ }
11744
+ messageIdSet(agentId, target) {
11745
+ const map = this.messageIdMap(agentId);
11746
+ let ids = map.get(target);
11747
+ if (!ids) {
11748
+ ids = /* @__PURE__ */ new Set();
11749
+ map.set(target, ids);
11750
+ }
11751
+ return ids;
11752
+ }
11753
+ assertConsumedInvariants(context, agentId, target, bucket, options) {
11754
+ const boundary = this.getBoundary(agentId, target);
11755
+ if (!options.advancesBoundary && boundary !== options.previousBoundary) {
11756
+ throw new Error(`Agent visible delivery ledger invariant violation after ${context}: set-only source advanced boundary for ${agentId} ${target}`);
11757
+ }
11758
+ if (options.advancesBoundary) {
11759
+ const highWaterSeq = Math.max(bucket.maxSeq, bucket.boundarySeq);
11760
+ const normalizedBoundary = boundary ?? 0;
11761
+ if (normalizedBoundary < (options.previousBoundary ?? 0)) {
11762
+ throw new Error(`Agent visible delivery ledger invariant violation after ${context}: boundary regressed for ${agentId} ${target}`);
11763
+ }
11764
+ if (highWaterSeq > 0 && normalizedBoundary < highWaterSeq) {
11765
+ throw new Error(`Agent visible delivery ledger invariant violation after ${context}: boundary below consumed high-water for ${agentId} ${target}`);
11766
+ }
11767
+ }
11768
+ if (bucket.ids.size > 0) {
11769
+ const targetIds = this.getMessageIdSet(agentId, target);
11770
+ for (const id of bucket.ids) {
11771
+ if (targetIds?.has(id) !== true) {
11772
+ throw new Error(`Agent visible delivery ledger invariant violation after ${context}: missing consumed message id for ${agentId} ${target}`);
11773
+ }
11774
+ }
11775
+ }
11776
+ }
11777
+ };
11778
+
10961
11779
  // src/runtimeErrorDiagnostics.ts
10962
11780
  import { createHash as createHash2 } from "crypto";
10963
11781
  var MAX_RUNTIME_ERROR_MESSAGE_EXCERPT_CHARS = 4096;
@@ -11467,26 +12285,10 @@ function toLocalTime(iso) {
11467
12285
  function formatChannelLabel(message) {
11468
12286
  return message.channel_type === "dm" ? `DM:@${message.channel_name}` : `#${message.channel_name}`;
11469
12287
  }
11470
- function computeTarget(channelType, channelName, parentChannelName, parentChannelType) {
11471
- if (channelType === "thread" && parentChannelName) {
11472
- const shortId = getMessageShortId(String(channelName ?? ""));
11473
- if (parentChannelType === "dm") {
11474
- return `dm:@${parentChannelName}:${shortId}`;
11475
- }
11476
- return `#${parentChannelName}:${shortId}`;
11477
- }
11478
- if (channelType === "dm") {
11479
- return `dm:@${channelName}`;
11480
- }
11481
- return `#${channelName}`;
11482
- }
11483
12288
  function formatMessageTarget(message) {
11484
- return computeTarget(message.channel_type, message.channel_name, message.parent_channel_name, message.parent_channel_type);
12289
+ return formatAgentMessageVisibleTarget(message);
11485
12290
  }
11486
- function formatVisibleMessageTarget(message) {
11487
- return computeTarget(message.channel_type, message.channel_name, message.parent_channel_name, message.parent_channel_type);
11488
- }
11489
- function getMessageShortId(messageId2) {
12291
+ function getMessageShortId2(messageId2) {
11490
12292
  return messageId2.startsWith("thread-") ? messageId2.slice(7) : messageId2.slice(0, 8);
11491
12293
  }
11492
12294
  var RESPONSE_TARGET_HINT = "Reply in the channel or create/reply in a thread as appropriate; use each message's `target` and `msg` fields to choose the exact target.";
@@ -11753,31 +12555,11 @@ function formatTaskAssigneeType(type) {
11753
12555
  return type ?? null;
11754
12556
  }
11755
12557
  function formatThreadContextMessage(message) {
11756
- const msgId = message.message_id ? getMessageShortId(message.message_id) : "-";
12558
+ const msgId = message.message_id ? getMessageShortId2(message.message_id) : "-";
11757
12559
  const time = message.timestamp ? toLocalTime(message.timestamp) : "-";
11758
12560
  const senderType = formatVisibleActorType(message.sender_type);
11759
12561
  return `- [msg=${msgId} time=${time}${senderType}] ${formatSenderHandle(message)}: ${message.content}`;
11760
12562
  }
11761
- function communicationCommand(name) {
11762
- switch (name) {
11763
- case "send_message":
11764
- return "raft message send";
11765
- case "read_history":
11766
- return "raft message read";
11767
- case "check_messages":
11768
- return "raft message check";
11769
- case "claim_tasks":
11770
- return "raft task claim";
11771
- default:
11772
- return `raft ${name.replace(/_/g, " ")}`;
11773
- }
11774
- }
11775
- function dynamicReplyInstruction() {
11776
- return "reply using `raft message send --target <exact target>`";
11777
- }
11778
- function dynamicClaimInstruction() {
11779
- return "claim the relevant task with `raft task claim`";
11780
- }
11781
12563
  function formatIncomingMessage(message, options = {}) {
11782
12564
  const threadJoinPrefix = message.thread_join_context ? [
11783
12565
  `[Slock thread context: you were added to a new thread via @mention.]`,
@@ -11793,7 +12575,7 @@ function formatIncomingMessage(message, options = {}) {
11793
12575
  ""
11794
12576
  ].join("\n") : "";
11795
12577
  const target = formatMessageTarget(message);
11796
- const msgId = message.message_id ? getMessageShortId(message.message_id) : "-";
12578
+ const msgId = message.message_id ? getMessageShortId2(message.message_id) : "-";
11797
12579
  const time = message.timestamp ? toLocalTime(message.timestamp) : "-";
11798
12580
  const senderType = formatVisibleActorType(message.sender_type);
11799
12581
  const attachSuffix = formatAttachmentSuffix(message.attachments, options.attachmentHint);
@@ -12752,17 +13534,8 @@ var AgentProcessManager = class _AgentProcessManager {
12752
13534
  this.activityClientSeqByAgent.set(agentId, next);
12753
13535
  return next;
12754
13536
  }
12755
- agentsStarting = /* @__PURE__ */ new Set();
12756
- // Prevent concurrent starts of same agent
12757
- queuedAgentStarts = /* @__PURE__ */ new Map();
12758
- agentStartQueue = [];
12759
- activeAgentStartCount = 0;
12760
- agentStartPumpTimer = null;
12761
- lastAgentStartAt = 0;
12762
- lastAgentStartAgentId = null;
12763
- maxConcurrentAgentStarts;
12764
- agentStartIntervalMs;
12765
- startingInboxes = /* @__PURE__ */ new Map();
13537
+ agentStarts;
13538
+ startingInboxes = new AgentStartPendingDeliveryBuffer();
12766
13539
  terminalRuntimeFailures = /* @__PURE__ */ new Map();
12767
13540
  runtimeErrorFingerprintFences = /* @__PURE__ */ new Map();
12768
13541
  pendingStartRebinds = /* @__PURE__ */ new Map();
@@ -12786,8 +13559,7 @@ var AgentProcessManager = class _AgentProcessManager {
12786
13559
  cliTransportTraceDir = null;
12787
13560
  deliveryTraceContexts = /* @__PURE__ */ new WeakMap();
12788
13561
  runtimeExitTraceAttrs = /* @__PURE__ */ new WeakMap();
12789
- agentVisibleBoundaries = /* @__PURE__ */ new Map();
12790
- agentVisibleMessageIds = /* @__PURE__ */ new Map();
13562
+ agentVisibleDelivery = new AgentVisibleDeliveryLedger();
12791
13563
  // Spawn-fail backoff state per-agent (lifted outside AgentProcess because spawn fails
12792
13564
  // BEFORE ap exists; rate-state must persist across stop/respawn so churn can't bypass).
12793
13565
  // Explicit stop clears (fresh launch resets dedup clock — CC1 lifecycle pattern); silent
@@ -12832,18 +13604,10 @@ var AgentProcessManager = class _AgentProcessManager {
12832
13604
  Math.min(1, opts.runtimeErrorDeliveryBackoff?.jitterRatio ?? 0.1)
12833
13605
  );
12834
13606
  this.runtimeErrorDeliveryBackoffFailPointForTesting = opts.runtimeErrorDeliveryBackoff?.failPointForTesting ?? null;
12835
- this.maxConcurrentAgentStarts = Math.max(
12836
- 1,
12837
- Math.floor(
12838
- opts.runtimeStartScheduler?.maxConcurrentStarts ?? readPositiveIntegerEnv("SLOCK_DAEMON_MAX_CONCURRENT_AGENT_STARTS", DEFAULT_MAX_CONCURRENT_AGENT_STARTS)
12839
- )
12840
- );
12841
- this.agentStartIntervalMs = Math.max(
12842
- 0,
12843
- Math.floor(
12844
- opts.runtimeStartScheduler?.minStartIntervalMs ?? readNonNegativeIntegerEnv("SLOCK_DAEMON_AGENT_START_INTERVAL_MS", DEFAULT_AGENT_START_INTERVAL_MS)
12845
- )
12846
- );
13607
+ this.agentStarts = new AgentStartCoordinator({
13608
+ maxConcurrentStarts: opts.runtimeStartScheduler?.maxConcurrentStarts ?? readPositiveIntegerEnv("SLOCK_DAEMON_MAX_CONCURRENT_AGENT_STARTS", DEFAULT_MAX_CONCURRENT_AGENT_STARTS),
13609
+ minStartIntervalMs: opts.runtimeStartScheduler?.minStartIntervalMs ?? readNonNegativeIntegerEnv("SLOCK_DAEMON_AGENT_START_INTERVAL_MS", DEFAULT_AGENT_START_INTERVAL_MS)
13610
+ });
12847
13611
  }
12848
13612
  setTracer(tracer) {
12849
13613
  this.tracer = tracer;
@@ -12851,34 +13615,23 @@ var AgentProcessManager = class _AgentProcessManager {
12851
13615
  setCliTransportTraceDir(traceDir) {
12852
13616
  this.cliTransportTraceDir = traceDir;
12853
13617
  }
12854
- visibleBoundaryMap(agentId) {
12855
- let map = this.agentVisibleBoundaries.get(agentId);
12856
- if (!map) {
12857
- map = /* @__PURE__ */ new Map();
12858
- this.agentVisibleBoundaries.set(agentId, map);
12859
- }
12860
- return map;
13618
+ assertStartPendingDeliveryInvariants(context) {
13619
+ const startSnapshot = this.agentStarts.snapshot();
13620
+ this.startingInboxes.assertInvariants(context, {
13621
+ queuedAgentIds: startSnapshot.queuedAgentIds,
13622
+ startingAgentIds: startSnapshot.startingAgentIds,
13623
+ terminalRecoveryAgentIds: [...this.terminalRuntimeFailures.keys()],
13624
+ cooldownAgentIds: [...this.agentSpawnFailBackoff.keys()]
13625
+ });
12861
13626
  }
12862
13627
  getVisibleBoundary(agentId, target) {
12863
- return this.agentVisibleBoundaries.get(agentId)?.get(target);
12864
- }
12865
- visibleMessageIdMap(agentId) {
12866
- let map = this.agentVisibleMessageIds.get(agentId);
12867
- if (!map) {
12868
- map = /* @__PURE__ */ new Map();
12869
- this.agentVisibleMessageIds.set(agentId, map);
12870
- }
12871
- return map;
13628
+ return this.agentVisibleDelivery.getBoundary(agentId, target);
12872
13629
  }
12873
13630
  getVisibleMessageIdSet(agentId, target) {
12874
- return this.agentVisibleMessageIds.get(agentId)?.get(target);
13631
+ return this.agentVisibleDelivery.getMessageIdSet(agentId, target);
12875
13632
  }
12876
13633
  isVisibleMessageModelSeen(agentId, target, message) {
12877
- const seq = Number(message.seq ?? 0);
12878
- const boundary = this.getVisibleBoundary(agentId, target);
12879
- if (Number.isFinite(seq) && seq > 0 && typeof boundary === "number" && boundary >= Math.floor(seq)) return true;
12880
- const id = typeof message.message_id === "string" ? message.message_id : typeof message.id === "string" ? message.id : "";
12881
- return id.length > 0 && this.getVisibleMessageIdSet(agentId, target)?.has(id) === true;
13634
+ return this.agentVisibleDelivery.isModelSeen(agentId, target, message);
12882
13635
  }
12883
13636
  // ----- SPAWN-FAIL BACKOFF (per-agent) ----------------------------------
12884
13637
  // Anchored at auto_restart_from_idle (apm:3596) + runtime_profile_auto_restart (apm:4137).
@@ -13320,7 +14073,7 @@ var AgentProcessManager = class _AgentProcessManager {
13320
14073
  const collect = (messages) => (messages ?? []).filter((message) => typeof message.seq === "number" && message.seq > 0);
13321
14074
  return [
13322
14075
  ...collect(this.agents.get(agentId)?.inbox),
13323
- ...collect(this.startingInboxes.get(agentId))
14076
+ ...collect(this.startingInboxes.values(agentId))
13324
14077
  ];
13325
14078
  }
13326
14079
  pendingVisibleMessages(agentId, target) {
@@ -13333,61 +14086,13 @@ var AgentProcessManager = class _AgentProcessManager {
13333
14086
  * same seq must not be injected later through the local pending queue.
13334
14087
  */
13335
14088
  consumeVisibleMessages(agentId, input) {
13336
- if (input.messages.length === 0 && (!input.target || typeof input.boundarySeq !== "number")) return;
13337
- const byTarget = /* @__PURE__ */ new Map();
13338
- const ensureBucket = (target) => {
13339
- let bucket = byTarget.get(target);
13340
- if (!bucket) {
13341
- bucket = { maxSeq: 0, boundarySeq: 0, seqs: /* @__PURE__ */ new Set(), ids: /* @__PURE__ */ new Set() };
13342
- byTarget.set(target, bucket);
13343
- }
13344
- return bucket;
13345
- };
13346
- for (const message of input.messages) {
13347
- const seq = Number(message.seq ?? 0);
13348
- const target = input.target ?? formatVisibleMessageTarget(message);
13349
- if (!target) continue;
13350
- const bucket = ensureBucket(target);
13351
- if (Number.isFinite(seq) && seq > 0) {
13352
- bucket.maxSeq = Math.max(bucket.maxSeq, Math.floor(seq));
13353
- bucket.seqs.add(Math.floor(seq));
13354
- }
13355
- const id = typeof message.message_id === "string" ? message.message_id : typeof message.id === "string" ? message.id : null;
13356
- if (id) bucket.ids.add(id);
13357
- }
13358
- if (input.target && typeof input.boundarySeq === "number" && Number.isFinite(input.boundarySeq) && input.boundarySeq > 0) {
13359
- const bucket = ensureBucket(input.target);
13360
- bucket.boundarySeq = Math.max(bucket.boundarySeq, Math.floor(input.boundarySeq));
13361
- }
13362
- if (byTarget.size === 0) return;
13363
- const boundaryMap = this.visibleBoundaryMap(agentId);
13364
- const visibleIds = this.visibleMessageIdMap(agentId);
13365
- const advancesBoundary = input.source === "spawn_wake_message" || input.source === "agent_api_events_local" || input.source.startsWith("stdin_");
13366
- for (const [target, bucket] of byTarget) {
13367
- if (advancesBoundary) {
13368
- const highWaterSeq = Math.max(bucket.maxSeq, bucket.boundarySeq);
13369
- const previous = boundaryMap.get(target) ?? 0;
13370
- boundaryMap.set(target, Math.max(previous, highWaterSeq));
13371
- }
13372
- if (bucket.ids.size > 0) {
13373
- let targetIds = visibleIds.get(target);
13374
- if (!targetIds) {
13375
- targetIds = /* @__PURE__ */ new Set();
13376
- visibleIds.set(target, targetIds);
13377
- }
13378
- for (const id of bucket.ids) targetIds.add(id);
13379
- }
13380
- }
14089
+ const consumed = this.agentVisibleDelivery.recordConsumed(agentId, input);
14090
+ if (!consumed) return;
13381
14091
  const suppress = (messages) => {
13382
14092
  if (!messages || messages.length === 0) return 0;
13383
14093
  let removed = 0;
13384
14094
  const retained = messages.filter((message) => {
13385
- const target = formatMessageTarget(message);
13386
- const bucket = byTarget.get(target);
13387
- if (!bucket) return true;
13388
- const seq = typeof message.seq === "number" ? Math.floor(message.seq) : 0;
13389
- const id = message.message_id ?? "";
13390
- const matched = seq > 0 && bucket.boundarySeq > 0 && seq <= bucket.boundarySeq || seq > 0 && bucket.seqs.has(seq) || id.length > 0 && bucket.ids.has(id);
14095
+ const matched = consumed.shouldSuppress(message);
13391
14096
  if (matched) removed += 1;
13392
14097
  return !matched;
13393
14098
  });
@@ -13396,12 +14101,13 @@ var AgentProcessManager = class _AgentProcessManager {
13396
14101
  };
13397
14102
  const active = this.agents.get(agentId);
13398
14103
  const removedActive = suppress(active?.inbox);
13399
- const removedStarting = suppress(this.startingInboxes.get(agentId));
14104
+ const removedStarting = this.startingInboxes.suppressConsumed(agentId, consumed.shouldSuppress);
14105
+ this.assertStartPendingDeliveryInvariants("visible-consume");
13400
14106
  this.recordDaemonTrace("daemon.agent.inbox.visible_consumed", {
13401
14107
  agentId,
13402
14108
  source: input.source,
13403
- targets: [...byTarget.keys()],
13404
- messages_count: input.messages.length,
14109
+ targets: consumed.targets,
14110
+ messages_count: consumed.messagesCount,
13405
14111
  suppressed_pending_count: removedActive + removedStarting
13406
14112
  });
13407
14113
  }
@@ -13423,11 +14129,8 @@ var AgentProcessManager = class _AgentProcessManager {
13423
14129
  };
13424
14130
  const active = this.agents.get(agentId);
13425
14131
  const removedActive = purge(active?.inbox);
13426
- const startingInbox = this.startingInboxes.get(agentId);
13427
- const removedStarting = purge(startingInbox);
13428
- if (startingInbox && startingInbox.length === 0) {
13429
- this.startingInboxes.delete(agentId);
13430
- }
14132
+ const removedStarting = this.startingInboxes.purge(agentId, (message) => channelIdSet.has(message.channel_id));
14133
+ this.assertStartPendingDeliveryInvariants("purge-starting-inbox");
13431
14134
  if (active && removedActive > 0) {
13432
14135
  active.notifications.remove(removedActive);
13433
14136
  if (active.inbox.length === 0) {
@@ -13444,7 +14147,7 @@ var AgentProcessManager = class _AgentProcessManager {
13444
14147
  removed_starting_count: removedStarting,
13445
14148
  removed_count: removedCount,
13446
14149
  active_inbox_count: active?.inbox.length ?? 0,
13447
- starting_inbox_count: this.startingInboxes.get(agentId)?.length ?? 0
14150
+ starting_inbox_count: this.startingInboxes.count(agentId)
13448
14151
  });
13449
14152
  return { removedCount };
13450
14153
  }
@@ -13591,6 +14294,7 @@ var AgentProcessManager = class _AgentProcessManager {
13591
14294
  };
13592
14295
  }
13593
14296
  startQueueTraceAttrs(agentId, config, wakeMessage, unreadSummary, resumePrompt, launchId, wakeMessageTransient = false) {
14297
+ const startSnapshot = this.agentStarts.snapshot();
13594
14298
  return {
13595
14299
  agentId,
13596
14300
  launchId,
@@ -13602,10 +14306,10 @@ var AgentProcessManager = class _AgentProcessManager {
13602
14306
  wake_message_transient: Boolean(wakeMessage && wakeMessageTransient),
13603
14307
  unread_channels_count: unreadSummary ? Object.keys(unreadSummary).length : 0,
13604
14308
  resume_prompt_present: Boolean(resumePrompt),
13605
- queue_depth: this.agentStartQueue.length,
13606
- active_starts: this.activeAgentStartCount,
13607
- max_concurrent_starts: this.maxConcurrentAgentStarts,
13608
- min_start_interval_ms: this.agentStartIntervalMs,
14309
+ queue_depth: startSnapshot.queueDepth,
14310
+ active_starts: startSnapshot.activeStarts,
14311
+ max_concurrent_starts: startSnapshot.maxConcurrentStarts,
14312
+ min_start_interval_ms: startSnapshot.minStartIntervalMs,
13609
14313
  ...this.runtimeLaunchPolicyTraceAttrs(config)
13610
14314
  };
13611
14315
  }
@@ -13691,18 +14395,20 @@ var AgentProcessManager = class _AgentProcessManager {
13691
14395
  return left === right;
13692
14396
  }
13693
14397
  rebindQueuedStart(agentId, start, reason) {
13694
- const item = this.queuedAgentStarts.get(agentId);
14398
+ const item = this.agentStarts.getQueued(agentId);
13695
14399
  if (!item) {
13696
14400
  return false;
13697
14401
  }
13698
14402
  const previousLaunchId = item.launchId || null;
13699
14403
  const nextLaunchId = start.launchId || previousLaunchId;
13700
14404
  const previousWakeMessage = item.wakeMessage;
13701
- if (previousWakeMessage && start.wakeMessage && !this.sameWakeMessage(previousWakeMessage, start.wakeMessage)) {
13702
- const pending = this.startingInboxes.get(agentId) || [];
13703
- pending.push(previousWakeMessage);
13704
- this.startingInboxes.set(agentId, pending);
13705
- }
14405
+ this.startingInboxes.rebindWake(
14406
+ agentId,
14407
+ previousWakeMessage,
14408
+ start.wakeMessage,
14409
+ (left, right) => this.sameWakeMessage(left, right)
14410
+ );
14411
+ this.assertStartPendingDeliveryInvariants("rebind-queued-start");
13706
14412
  item.config = start.config;
13707
14413
  item.unreadSummary = start.unreadSummary;
13708
14414
  item.resumePrompt = start.resumePrompt;
@@ -13769,7 +14475,7 @@ var AgentProcessManager = class _AgentProcessManager {
13769
14475
  logger.info(`[Agent ${agentId}] Start rebound (already running)`);
13770
14476
  return;
13771
14477
  }
13772
- if (this.agentsStarting.has(agentId)) {
14478
+ if (this.agentStarts.hasStarting(agentId)) {
13773
14479
  this.recordDaemonTrace("daemon.agent.start.ignored", {
13774
14480
  ...this.startQueueTraceAttrs(agentId, config, wakeMessage, unreadSummary, resumePrompt, launchId, wakeMessageTransient),
13775
14481
  reason: "already_starting"
@@ -13778,7 +14484,7 @@ var AgentProcessManager = class _AgentProcessManager {
13778
14484
  logger.info(`[Agent ${agentId}] Start rebind deferred (startup in progress)`);
13779
14485
  return;
13780
14486
  }
13781
- if (this.queuedAgentStarts.has(agentId)) {
14487
+ if (this.agentStarts.hasQueued(agentId)) {
13782
14488
  this.recordDaemonTrace("daemon.agent.start.ignored", {
13783
14489
  ...this.startQueueTraceAttrs(agentId, config, wakeMessage, unreadSummary, resumePrompt, launchId, wakeMessageTransient),
13784
14490
  reason: "already_queued"
@@ -13799,46 +14505,40 @@ var AgentProcessManager = class _AgentProcessManager {
13799
14505
  resolve,
13800
14506
  reject
13801
14507
  };
13802
- this.agentStartQueue.push(item);
13803
- this.queuedAgentStarts.set(agentId, item);
14508
+ this.agentStarts.enqueue(item);
13804
14509
  this.recordDaemonTrace("daemon.agent.start.queued", this.startQueueTraceAttrs(agentId, config, wakeMessage, unreadSummary, resumePrompt, launchId, wakeMessageTransient));
14510
+ const startSnapshot = this.agentStarts.snapshot();
13805
14511
  logger.info(
13806
- `[Agent ${agentId}] Start queued (queue=${this.agentStartQueue.length}, active=${this.activeAgentStartCount}, max=${this.maxConcurrentAgentStarts}, interval=${this.agentStartIntervalMs}ms)`
14512
+ `[Agent ${agentId}] Start queued (queue=${startSnapshot.queueDepth}, active=${startSnapshot.activeStarts}, max=${startSnapshot.maxConcurrentStarts}, interval=${startSnapshot.minStartIntervalMs}ms)`
13807
14513
  );
13808
14514
  this.pumpAgentStartQueue();
13809
14515
  });
13810
14516
  }
13811
14517
  pumpAgentStartQueue() {
13812
- if (this.agentStartPumpTimer) return;
13813
- if (this.agentStartQueue.length === 0) return;
13814
- if (this.activeAgentStartCount >= this.maxConcurrentAgentStarts) return;
13815
- const next = this.agentStartQueue[0];
13816
- const shouldRateLimit = next ? next.agentId !== this.lastAgentStartAgentId : true;
13817
- const elapsed = Date.now() - this.lastAgentStartAt;
13818
- const waitMs = shouldRateLimit ? Math.max(0, this.agentStartIntervalMs - elapsed) : 0;
13819
- if (waitMs > 0) {
14518
+ const pumpState = this.agentStarts.getPumpState();
14519
+ if (pumpState.kind === "blocked") return;
14520
+ if (pumpState.kind === "rate_limited") {
14521
+ const { item: next, waitMs } = pumpState;
13820
14522
  this.recordDaemonTrace("daemon.agent.start.rate_limited", {
13821
14523
  ...this.startQueueTraceAttrs(next.agentId, next.config, next.wakeMessage, next.unreadSummary, next.resumePrompt, next.launchId, next.wakeMessageTransient),
13822
14524
  wait_ms: waitMs
13823
14525
  });
13824
- this.agentStartPumpTimer = setTimeout(() => {
13825
- this.agentStartPumpTimer = null;
13826
- this.pumpAgentStartQueue();
13827
- }, waitMs);
14526
+ this.agentStarts.schedulePump(waitMs, () => this.pumpAgentStartQueue());
13828
14527
  return;
13829
14528
  }
13830
- const item = this.agentStartQueue.shift();
13831
- if (!item) return;
13832
- if (this.queuedAgentStarts.get(item.agentId) !== item) {
14529
+ const dequeued = this.agentStarts.dequeue();
14530
+ if (dequeued.kind === "empty") return;
14531
+ if (dequeued.kind === "stale") {
14532
+ const { item: item2 } = dequeued;
13833
14533
  this.recordDaemonTrace("daemon.agent.start.skipped", {
13834
- ...this.startQueueTraceAttrs(item.agentId, item.config, item.wakeMessage, item.unreadSummary, item.resumePrompt, item.launchId, item.wakeMessageTransient),
14534
+ ...this.startQueueTraceAttrs(item2.agentId, item2.config, item2.wakeMessage, item2.unreadSummary, item2.resumePrompt, item2.launchId, item2.wakeMessageTransient),
13835
14535
  reason: "stale_queue_item"
13836
14536
  });
13837
14537
  this.pumpAgentStartQueue();
13838
14538
  return;
13839
14539
  }
13840
- this.queuedAgentStarts.delete(item.agentId);
13841
- if (this.agents.has(item.agentId) || this.agentsStarting.has(item.agentId)) {
14540
+ const { item } = dequeued;
14541
+ if (this.agents.has(item.agentId) || this.agentStarts.hasStarting(item.agentId)) {
13842
14542
  this.recordDaemonTrace("daemon.agent.start.skipped", {
13843
14543
  ...this.startQueueTraceAttrs(item.agentId, item.config, item.wakeMessage, item.unreadSummary, item.resumePrompt, item.launchId, item.wakeMessageTransient),
13844
14544
  reason: "already_running_or_starting"
@@ -13853,11 +14553,10 @@ var AgentProcessManager = class _AgentProcessManager {
13853
14553
  this.pumpAgentStartQueue();
13854
14554
  return;
13855
14555
  }
13856
- this.activeAgentStartCount++;
13857
- this.lastAgentStartAt = Date.now();
13858
- this.lastAgentStartAgentId = item.agentId;
14556
+ this.agentStarts.claimStartSlot(item.agentId);
14557
+ const startSnapshot = this.agentStarts.snapshot();
13859
14558
  logger.info(
13860
- `[Agent ${item.agentId}] Dequeued start (remaining=${this.agentStartQueue.length}, active=${this.activeAgentStartCount})`
14559
+ `[Agent ${item.agentId}] Dequeued start (remaining=${startSnapshot.queueDepth}, active=${startSnapshot.activeStarts})`
13861
14560
  );
13862
14561
  this.recordDaemonTrace("daemon.agent.start.dequeued", this.startQueueTraceAttrs(item.agentId, item.config, item.wakeMessage, item.unreadSummary, item.resumePrompt, item.launchId, item.wakeMessageTransient));
13863
14562
  this.startAgentNow(
@@ -13877,30 +14576,25 @@ var AgentProcessManager = class _AgentProcessManager {
13877
14576
  });
13878
14577
  }
13879
14578
  releaseAgentStartSlot(agentId, reason) {
13880
- if (this.activeAgentStartCount <= 0) return;
13881
- this.activeAgentStartCount = Math.max(0, this.activeAgentStartCount - 1);
14579
+ if (!this.agentStarts.releaseStartSlot()) return;
14580
+ const startSnapshot = this.agentStarts.snapshot();
13882
14581
  this.recordDaemonTrace("daemon.agent.start.slot_released", {
13883
14582
  agentId,
13884
14583
  reason,
13885
- active_starts: this.activeAgentStartCount,
13886
- queue_depth: this.agentStartQueue.length,
13887
- max_concurrent_starts: this.maxConcurrentAgentStarts
14584
+ active_starts: startSnapshot.activeStarts,
14585
+ queue_depth: startSnapshot.queueDepth,
14586
+ max_concurrent_starts: startSnapshot.maxConcurrentStarts
13888
14587
  });
13889
14588
  logger.info(
13890
- `[Agent ${agentId}] Start slot released (${reason}) (active=${this.activeAgentStartCount}, queue=${this.agentStartQueue.length})`
14589
+ `[Agent ${agentId}] Start slot released (${reason}) (active=${startSnapshot.activeStarts}, queue=${startSnapshot.queueDepth})`
13891
14590
  );
13892
14591
  this.pumpAgentStartQueue();
13893
14592
  }
13894
14593
  cancelQueuedAgentStart(agentId, reason) {
13895
- const item = this.queuedAgentStarts.get(agentId);
14594
+ const item = this.agentStarts.cancelQueued(agentId);
13896
14595
  if (!item) return false;
13897
- this.queuedAgentStarts.delete(agentId);
13898
- this.agentStartQueue = this.agentStartQueue.filter((candidate) => candidate !== item);
13899
- this.startingInboxes.delete(agentId);
13900
- if (this.agentStartQueue.length === 0 && this.agentStartPumpTimer) {
13901
- clearTimeout(this.agentStartPumpTimer);
13902
- this.agentStartPumpTimer = null;
13903
- }
14596
+ this.startingInboxes.cancelStart(agentId);
14597
+ this.assertStartPendingDeliveryInvariants("cancel-queued-start");
13904
14598
  this.recordDaemonTrace("daemon.agent.start.cancelled", {
13905
14599
  ...this.startQueueTraceAttrs(agentId, item.config, item.wakeMessage, item.unreadSummary, item.resumePrompt, item.launchId, item.wakeMessageTransient),
13906
14600
  reason
@@ -13910,23 +14604,18 @@ var AgentProcessManager = class _AgentProcessManager {
13910
14604
  return true;
13911
14605
  }
13912
14606
  cancelAllQueuedAgentStarts(reason) {
13913
- for (const item of this.agentStartQueue) {
13914
- if (this.queuedAgentStarts.get(item.agentId) === item) {
13915
- this.recordDaemonTrace("daemon.agent.start.cancelled", {
13916
- ...this.startQueueTraceAttrs(item.agentId, item.config, item.wakeMessage, item.unreadSummary, item.resumePrompt, item.launchId, item.wakeMessageTransient),
13917
- reason
13918
- }, "cancelled");
13919
- logger.info(`[Agent ${item.agentId}] Queued start cancelled (${reason})`);
13920
- item.resolve();
13921
- }
13922
- }
13923
- this.agentStartQueue = [];
13924
- this.queuedAgentStarts.clear();
13925
- this.startingInboxes.clear();
13926
- if (this.agentStartPumpTimer) {
13927
- clearTimeout(this.agentStartPumpTimer);
13928
- this.agentStartPumpTimer = null;
14607
+ const cancelled = this.agentStarts.cancelAllQueued((item) => {
14608
+ this.recordDaemonTrace("daemon.agent.start.cancelled", {
14609
+ ...this.startQueueTraceAttrs(item.agentId, item.config, item.wakeMessage, item.unreadSummary, item.resumePrompt, item.launchId, item.wakeMessageTransient),
14610
+ reason
14611
+ }, "cancelled");
14612
+ logger.info(`[Agent ${item.agentId}] Queued start cancelled (${reason})`);
14613
+ });
14614
+ for (const item of cancelled) {
14615
+ item.resolve();
13929
14616
  }
14617
+ this.startingInboxes.cancelAllStarts();
14618
+ this.assertStartPendingDeliveryInvariants("cancel-all-queued-starts");
13930
14619
  }
13931
14620
  async startAgentNow(agentId, config, wakeMessage, unreadSummary, resumePrompt, launchId, wakeMessageTransient = false) {
13932
14621
  if (this.agents.has(agentId)) {
@@ -13938,7 +14627,7 @@ var AgentProcessManager = class _AgentProcessManager {
13938
14627
  logger.info(`[Agent ${agentId}] Start rebound (already running)`);
13939
14628
  return;
13940
14629
  }
13941
- if (this.agentsStarting.has(agentId)) {
14630
+ if (this.agentStarts.hasStarting(agentId)) {
13942
14631
  this.recordDaemonTrace("daemon.agent.spawn.skipped", {
13943
14632
  ...this.startQueueTraceAttrs(agentId, config, wakeMessage, unreadSummary, resumePrompt, launchId, wakeMessageTransient),
13944
14633
  reason: "already_starting"
@@ -13947,7 +14636,7 @@ var AgentProcessManager = class _AgentProcessManager {
13947
14636
  logger.info(`[Agent ${agentId}] Start rebind deferred (startup in progress)`);
13948
14637
  return;
13949
14638
  }
13950
- this.agentsStarting.add(agentId);
14639
+ this.agentStarts.markStarting(agentId);
13951
14640
  let agentProcess = null;
13952
14641
  let pendingStartRebind;
13953
14642
  const originalLaunchId = launchId || null;
@@ -13980,11 +14669,13 @@ var AgentProcessManager = class _AgentProcessManager {
13980
14669
  if (pendingStartRebind) {
13981
14670
  this.pendingStartRebinds.delete(agentId);
13982
14671
  const previousWakeMessage = wakeMessage;
13983
- if (previousWakeMessage && pendingStartRebind.wakeMessage && !this.sameWakeMessage(previousWakeMessage, pendingStartRebind.wakeMessage)) {
13984
- const pending = this.startingInboxes.get(agentId) || [];
13985
- pending.push(previousWakeMessage);
13986
- this.startingInboxes.set(agentId, pending);
13987
- }
14672
+ this.startingInboxes.rebindWake(
14673
+ agentId,
14674
+ previousWakeMessage,
14675
+ pendingStartRebind.wakeMessage,
14676
+ (left, right) => this.sameWakeMessage(left, right)
14677
+ );
14678
+ this.assertStartPendingDeliveryInvariants("rebind-starting-start");
13988
14679
  config = pendingStartRebind.config;
13989
14680
  unreadSummary = pendingStartRebind.unreadSummary;
13990
14681
  resumePrompt = pendingStartRebind.resumePrompt;
@@ -14025,7 +14716,7 @@ var AgentProcessManager = class _AgentProcessManager {
14025
14716
  let promptSource;
14026
14717
  let wakeMessageDeliveredAsInboxUpdate = false;
14027
14718
  let startingInboxDeliveredAsInput = false;
14028
- const startingInboxMessages = this.startingInboxes.get(agentId) || [];
14719
+ const startingInboxMessages = this.startingInboxes.values(agentId);
14029
14720
  if (runtimeConfig.runtimeProfileControl && !wakeMessage) {
14030
14721
  prompt = driver.supportsNativeStandingPrompt ? NATIVE_STANDING_PROMPT_STARTUP_INPUT : formatRuntimeProfileControlStartupInput(runtimeConfig.runtimeProfileControl, driver);
14031
14722
  promptSource = "runtime_profile_control";
@@ -14077,7 +14768,7 @@ Use the inbox/read commands at a natural breakpoint if you choose to inspect tho
14077
14768
  }
14078
14769
  prompt += `
14079
14770
 
14080
- Use ${communicationCommand("read_history")} to catch up on the channels listed above, then stop. Read each listed channel at most once unless a read fails. Do NOT call ${communicationCommand("check_messages")} in this mode. If the history reveals a direct request, assignment, @mention, review request, or task clearly addressed to you, switch into active handling instead of stopping: ${dynamicReplyInstruction()} and ${dynamicClaimInstruction()} before starting work. Otherwise, do NOT send any message in this mode. ${getMessageDeliveryText(driver)}`;
14771
+ Use \`raft message read\` to catch up on the channels listed above, then stop. Read each listed channel at most once unless a read fails. Do NOT call \`raft message check\` in this mode. If the history reveals a direct request, assignment, @mention, review request, or task clearly addressed to you, switch into active handling instead of stopping: reply using \`raft message send --target <exact target>\` and claim the relevant task with \`raft task claim\` before starting work. Otherwise, do NOT send any message in this mode. ${getMessageDeliveryText(driver)}`;
14081
14772
  promptSource = "resume_unread_summary";
14082
14773
  } else if (isResume) {
14083
14774
  prompt = `No new messages while you were away. Nothing to do \u2014 just stop. ${getMessageDeliveryText(driver)}`;
@@ -14100,9 +14791,9 @@ Use ${communicationCommand("read_history")} to catch up on the channels listed a
14100
14791
  const effectiveLaunchId = launchId || null;
14101
14792
  const canDeferEmptyStart = driver.deferSpawnUntilMessage === true && !wakeMessage && !runtimeConfig.runtimeProfileControl && (!unreadSummary || Object.keys(unreadSummary).length === 0);
14102
14793
  if (canDeferEmptyStart) {
14103
- const pendingMessages = this.startingInboxes.get(agentId) || [];
14104
- this.startingInboxes.delete(agentId);
14105
- this.agentsStarting.delete(agentId);
14794
+ const pendingMessages = this.startingInboxes.drainOnSpawn(agentId);
14795
+ this.agentStarts.clearStarting(agentId);
14796
+ this.assertStartPendingDeliveryInvariants("defer-empty-start-drain");
14106
14797
  this.idleAgentConfigs.set(agentId, {
14107
14798
  config: this.buildRestartSafeConfig(runtimeConfig, runtimeConfig.sessionId || null),
14108
14799
  sessionId: runtimeConfig.sessionId || null,
@@ -14185,7 +14876,8 @@ Use ${communicationCommand("read_history")} to catch up on the channels listed a
14185
14876
  pendingTrajectory: null,
14186
14877
  gatedSteering: createGatedSteeringState()
14187
14878
  };
14188
- this.startingInboxes.delete(agentId);
14879
+ this.startingInboxes.drainOnSpawn(agentId);
14880
+ this.assertStartPendingDeliveryInvariants("spawn-drain");
14189
14881
  this.agents.set(agentId, agentProcess);
14190
14882
  this.idleAgentConfigs.set(agentId, {
14191
14883
  config: this.buildRestartSafeConfig(runtimeConfig, restartSessionId),
@@ -14196,7 +14888,7 @@ Use ${communicationCommand("read_history")} to catch up on the channels listed a
14196
14888
  this.recordStartRebind(agentId, pendingStartRebind, "startup_registered", originalLaunchId, effectiveLaunchId, agentProcess.sessionId);
14197
14889
  }
14198
14890
  this.startRuntimeTrace(agentId, agentProcess, "spawn", wakeMessage ? [wakeMessage] : void 0, runtimeInputTraceAttrs);
14199
- this.agentsStarting.delete(agentId);
14891
+ this.agentStarts.clearStarting(agentId);
14200
14892
  if (runtimeConfig.runtimeProfileControl) {
14201
14893
  this.ackInjectedRuntimeProfileControl(agentId, runtimeConfig.runtimeProfileControl, agentProcess.launchId);
14202
14894
  }
@@ -14500,7 +15192,7 @@ Use ${communicationCommand("read_history")} to catch up on the channels listed a
14500
15192
  this.broadcastActivity(agentId, "working", "Starting\u2026");
14501
15193
  this.startRuntimeStartupTimeout(agentId, agentProcess);
14502
15194
  } catch (err) {
14503
- this.agentsStarting.delete(agentId);
15195
+ this.agentStarts.clearStarting(agentId);
14504
15196
  this.pendingStartRebinds.delete(agentId);
14505
15197
  this.cleanupFailedRuntimeStart(agentId, agentProcess, err);
14506
15198
  throw err;
@@ -14554,11 +15246,11 @@ Use ${communicationCommand("read_history")} to catch up on the channels listed a
14554
15246
  cleanupAgentCredentialProxy(agentId, ap.launchId);
14555
15247
  this.revokeManagedRunnerCredential(agentId, ap.config, ap.launchId);
14556
15248
  this.idleAgentConfigs.delete(agentId);
14557
- const pending = this.startingInboxes.get(agentId) || [];
14558
15249
  if (ap.inbox.length > 0) {
14559
- this.startingInboxes.set(agentId, [...pending, ...ap.inbox]);
15250
+ this.startingInboxes.bufferMessagesDuringStart(agentId, ap.inbox);
14560
15251
  }
14561
15252
  this.terminalRuntimeFailures.set(agentId, { detail, launchId: ap.launchId });
15253
+ this.assertStartPendingDeliveryInvariants("terminal-runtime-failure-cleanup");
14562
15254
  this.agents.delete(agentId);
14563
15255
  const diagnostics = buildRuntimeErrorDiagnosticEnvelope(detail);
14564
15256
  this.recordDaemonTrace("daemon.agent.terminal_runtime_error.cleanup", {
@@ -14801,10 +15493,9 @@ Use ${communicationCommand("read_history")} to catch up on the channels listed a
14801
15493
  );
14802
15494
  }
14803
15495
  queueRuntimeProfileNotificationDuringStart(agentId, message, kind, key) {
14804
- const pending = this.startingInboxes.get(agentId) || [];
14805
- pending.push(message);
14806
- this.startingInboxes.set(agentId, pending);
14807
- const queuedStart = this.queuedAgentStarts.get(agentId);
15496
+ const startingInboxCount = this.startingInboxes.bufferDuringStart(agentId, message);
15497
+ this.assertStartPendingDeliveryInvariants("runtime-profile-during-start");
15498
+ const queuedStart = this.agentStarts.getQueued(agentId);
14808
15499
  this.recordDaemonTrace("daemon.agent.runtime_profile.routed", {
14809
15500
  agentId,
14810
15501
  kind,
@@ -14812,7 +15503,7 @@ Use ${communicationCommand("read_history")} to catch up on the channels listed a
14812
15503
  key_hash: hashRuntimeProfileKey(key),
14813
15504
  outcome: "queued_during_start",
14814
15505
  startup_pending: true,
14815
- starting_inbox_count: pending.length,
15506
+ starting_inbox_count: startingInboxCount,
14816
15507
  launchId: queuedStart?.launchId
14817
15508
  });
14818
15509
  logger.info(`[Agent ${agentId}] Queued runtime profile ${kind} ${key} during startup`);
@@ -14844,8 +15535,7 @@ Use ${communicationCommand("read_history")} to catch up on the channels listed a
14844
15535
  this.agents.delete(agentId);
14845
15536
  if (!silent) {
14846
15537
  this.activityClientSeqByAgent.delete(agentId);
14847
- this.agentVisibleBoundaries.delete(agentId);
14848
- this.agentVisibleMessageIds.delete(agentId);
15538
+ this.agentVisibleDelivery.clearAgent(agentId);
14849
15539
  this.resetSpawnFailBackoff(agentId);
14850
15540
  this.resetRuntimeErrorFingerprintFence(agentId, "explicit_stop", ap);
14851
15541
  }
@@ -14911,9 +15601,9 @@ Use ${communicationCommand("read_history")} to catch up on the channels listed a
14911
15601
  }
14912
15602
  const ap = this.agents.get(agentId);
14913
15603
  if (!ap) {
14914
- if (this.agentsStarting.has(agentId) || this.queuedAgentStarts.has(agentId)) {
15604
+ if (this.agentStarts.hasStarting(agentId) || this.agentStarts.hasQueued(agentId)) {
14915
15605
  if (transientDelivery) {
14916
- const queuedStart2 = this.queuedAgentStarts.get(agentId);
15606
+ const queuedStart2 = this.agentStarts.getQueued(agentId);
14917
15607
  this.recordDaemonTrace("daemon.agent.delivery.routed", this.deliveryTraceAttrs(agentId, message, {
14918
15608
  outcome: "transient_dropped_during_start",
14919
15609
  accepted: true,
@@ -14923,16 +15613,15 @@ Use ${communicationCommand("read_history")} to catch up on the channels listed a
14923
15613
  }));
14924
15614
  return true;
14925
15615
  }
14926
- const queuedStart = this.queuedAgentStarts.get(agentId);
14927
- const pending = this.startingInboxes.get(agentId) || [];
14928
- pending.push(message);
14929
- this.startingInboxes.set(agentId, pending);
15616
+ const queuedStart = this.agentStarts.getQueued(agentId);
15617
+ const startingInboxCount = this.startingInboxes.bufferDuringStart(agentId, message);
15618
+ this.assertStartPendingDeliveryInvariants("delivery-during-start");
14930
15619
  this.recordDaemonTrace("daemon.agent.delivery.routed", this.deliveryTraceAttrs(agentId, message, {
14931
15620
  outcome: "queued_during_start",
14932
15621
  accepted: true,
14933
15622
  process_present: false,
14934
15623
  startup_pending: true,
14935
- starting_inbox_count: pending.length,
15624
+ starting_inbox_count: startingInboxCount,
14936
15625
  launchId: queuedStart?.launchId
14937
15626
  }));
14938
15627
  return true;
@@ -14950,16 +15639,15 @@ Use ${communicationCommand("read_history")} to catch up on the channels listed a
14950
15639
  }));
14951
15640
  return true;
14952
15641
  }
14953
- const pending = this.startingInboxes.get(agentId) || [];
14954
- pending.push(message);
14955
- this.startingInboxes.set(agentId, pending);
15642
+ const startingInboxCount = this.startingInboxes.bufferDuringStart(agentId, message);
15643
+ this.assertStartPendingDeliveryInvariants("delivery-terminal-runtime-error");
14956
15644
  this.recordDaemonTrace("daemon.agent.delivery.routed", this.deliveryTraceAttrs(agentId, message, {
14957
15645
  outcome: "queued_terminal_runtime_error_no_process",
14958
15646
  accepted: true,
14959
15647
  process_present: false,
14960
15648
  cached_idle_config_present: false,
14961
15649
  terminal_runtime_failure: true,
14962
- starting_inbox_count: pending.length,
15650
+ starting_inbox_count: startingInboxCount,
14963
15651
  launchId: terminalRuntimeFailure.launchId || void 0
14964
15652
  }));
14965
15653
  this.sendAgentStatus(agentId, "inactive", terminalRuntimeFailure.launchId);
@@ -14984,9 +15672,8 @@ Use ${communicationCommand("read_history")} to catch up on the channels listed a
14984
15672
  logger.info(`[Agent ${agentId}] Starting from idle state for new message`);
14985
15673
  if (this.isSpawnFailBackoffActive(agentId)) {
14986
15674
  const state = this.agentSpawnFailBackoff.get(agentId);
14987
- const pending = this.startingInboxes.get(agentId) || [];
14988
- pending.push(message);
14989
- this.startingInboxes.set(agentId, pending);
15675
+ const startingInboxCount = this.startingInboxes.bufferDuringStart(agentId, message);
15676
+ this.assertStartPendingDeliveryInvariants("delivery-spawn-fail-cooldown");
14990
15677
  this.recordDaemonTrace("daemon.agent.delivery.routed", this.deliveryTraceAttrs(agentId, message, {
14991
15678
  outcome: "spawn_fail_cooldown_active",
14992
15679
  accepted: true,
@@ -14997,7 +15684,7 @@ Use ${communicationCommand("read_history")} to catch up on the channels listed a
14997
15684
  launchId: cached.launchId || void 0,
14998
15685
  spawn_fail_attempts: state.attempts,
14999
15686
  spawn_fail_until_ms: state.untilMs,
15000
- starting_inbox_count: pending.length
15687
+ starting_inbox_count: startingInboxCount
15001
15688
  }));
15002
15689
  return true;
15003
15690
  }
@@ -15041,16 +15728,15 @@ Use ${communicationCommand("read_history")} to catch up on the channels listed a
15041
15728
  return false;
15042
15729
  });
15043
15730
  }
15044
- if (!transientDelivery && (this.queuedAgentStarts.has(agentId) || this.agentsStarting.has(agentId))) {
15045
- const pending = this.startingInboxes.get(agentId) || [];
15046
- pending.push(message);
15047
- this.startingInboxes.set(agentId, pending);
15731
+ if (!transientDelivery && (this.agentStarts.hasQueued(agentId) || this.agentStarts.hasStarting(agentId))) {
15732
+ const startingInboxCount = this.startingInboxes.bufferDuringStart(agentId, message);
15733
+ this.assertStartPendingDeliveryInvariants("delivery-queued-or-starting");
15048
15734
  this.recordDaemonTrace("daemon.agent.delivery.routed", this.deliveryTraceAttrs(agentId, message, {
15049
- outcome: this.agentsStarting.has(agentId) ? "queued_for_starting_process" : "queued_for_queued_start",
15735
+ outcome: this.agentStarts.hasStarting(agentId) ? "queued_for_starting_process" : "queued_for_queued_start",
15050
15736
  accepted: true,
15051
15737
  process_present: false,
15052
15738
  cached_idle_config_present: false,
15053
- starting_inbox_count: pending.length
15739
+ starting_inbox_count: startingInboxCount
15054
15740
  }));
15055
15741
  return true;
15056
15742
  }
@@ -15631,8 +16317,8 @@ Use ${communicationCommand("read_history")} to catch up on the channels listed a
15631
16317
  });
15632
16318
  return written;
15633
16319
  }
15634
- if (this.agentsStarting.has(agentId) || this.queuedAgentStarts.has(agentId)) {
15635
- const queuedStart = this.queuedAgentStarts.get(agentId);
16320
+ if (this.agentStarts.hasStarting(agentId) || this.agentStarts.hasQueued(agentId)) {
16321
+ const queuedStart = this.agentStarts.getQueued(agentId);
15636
16322
  this.queueRuntimeProfileNotificationDuringStart(agentId, message, kind, key);
15637
16323
  span.end("ok", {
15638
16324
  attrs: {
@@ -18952,7 +19638,7 @@ var DAEMON_CORE_TRACE_ATTR_CONTRACTS = {
18952
19638
  spanAttrs: ["agentId", "event_kind", "runtime"]
18953
19639
  }
18954
19640
  };
18955
- var DAEMON_CLI_USAGE = `Usage: slock-daemon --server-url <url> (--api-key <key> or ${DAEMON_API_KEY_ENV}=<key>)`;
19641
+ var DAEMON_CLI_USAGE = "Usage: slock-daemon --server-url <url> --api-key <key>";
18956
19642
  var RunnerCredentialMintError2 = class extends Error {
18957
19643
  code;
18958
19644
  retryable;
@@ -18988,9 +19674,9 @@ function runnerCredentialErrorDetail2(error) {
18988
19674
  async function waitForRunnerCredentialRetry2() {
18989
19675
  await new Promise((resolve) => setTimeout(resolve, RUNNER_CREDENTIAL_MINT_RETRY_DELAY_MS2));
18990
19676
  }
18991
- function parseDaemonCliArgs(args, env = {}) {
19677
+ function parseDaemonCliArgs(args) {
18992
19678
  let serverUrl = "";
18993
- let apiKey = env[DAEMON_API_KEY_ENV] ?? "";
19679
+ let apiKey = "";
18994
19680
  for (let i = 0; i < args.length; i++) {
18995
19681
  if (args[i] === "--server-url" && args[i + 1]) serverUrl = args[++i];
18996
19682
  if (args[i] === "--api-key" && args[i + 1]) apiKey = args[++i];
@@ -19027,7 +19713,7 @@ function resolveSlockCliPathOrEmpty(moduleUrl = import.meta.url) {
19027
19713
  }
19028
19714
  async function runBundledSlockCli(argv) {
19029
19715
  process.argv = [process.execPath, "slock", ...argv];
19030
- await import("./dist-CBVXAPI6.js");
19716
+ await import("./dist-TPCGG5OS.js");
19031
19717
  }
19032
19718
  function detectRuntimes(tracer = noopTracer) {
19033
19719
  const ids = [];
@@ -19964,8 +20650,6 @@ var DaemonCore = class {
19964
20650
 
19965
20651
  export {
19966
20652
  subscribeDaemonLogs,
19967
- DAEMON_API_KEY_ENV,
19968
- scrubDaemonAuthEnv,
19969
20653
  resolveWorkspaceDirectoryPath,
19970
20654
  scanWorkspaceDirectories,
19971
20655
  deleteWorkspaceDirectory,