@botiverse/raft-daemon 0.65.0 → 0.66.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.
@@ -820,17 +820,26 @@ function projectApmHeldFreshnessActivity(input) {
820
820
  countLine,
821
821
  ...decisionLines
822
822
  ].filter((line) => Boolean(line)).join("\n");
823
+ const statusEntry = {
824
+ kind: "status",
825
+ activity: "working",
826
+ detail: title,
827
+ producerFactId: input.producerFactId
828
+ };
829
+ const entry = {
830
+ kind: "slock_action",
831
+ producerFactId: input.producerFactId,
832
+ title,
833
+ text
834
+ };
823
835
  return {
824
836
  clauseId: "SMR-006",
825
837
  projector: "held-envelope",
826
838
  surface: "agent:activity",
827
839
  producerFactId: input.producerFactId,
828
- entry: {
829
- kind: "slock_action",
830
- producerFactId: input.producerFactId,
831
- title,
832
- text
833
- }
840
+ statusEntry,
841
+ entry,
842
+ entries: [statusEntry, entry]
834
843
  };
835
844
  }
836
845
  function projectApmFreshnessDecisionTrace(input) {
@@ -1347,6 +1356,7 @@ var TOOL_DISPLAY_METADATA = {
1347
1356
  claim_tasks: { logLabel: "Claiming tasks", activityLabel: "Claiming tasks\u2026", summaryKind: "claim_tasks" },
1348
1357
  unclaim_task: { logLabel: "Unclaiming task", activityLabel: "Unclaiming task\u2026", summaryKind: "task_ref" },
1349
1358
  update_task_status: { logLabel: "Updating task status", activityLabel: "Updating task status\u2026", summaryKind: "task_ref" },
1359
+ add_channel_member: { logLabel: "Adding channel member", activityLabel: "Adding channel member\u2026", summaryKind: "target" },
1350
1360
  join_channel: { logLabel: "Joining channel", activityLabel: "Joining channel\u2026", summaryKind: "target" },
1351
1361
  leave_channel: { logLabel: "Leaving channel", activityLabel: "Leaving channel\u2026", summaryKind: "target" },
1352
1362
  upload_file: { logLabel: "Uploading file", activityLabel: "Uploading file\u2026", summaryKind: "file_path" },
@@ -1378,6 +1388,7 @@ var KNOWN_TOOL_ALIASES = {
1378
1388
  claim_tasks: "claim_tasks",
1379
1389
  unclaim_task: "unclaim_task",
1380
1390
  update_task_status: "update_task_status",
1391
+ add_channel_member: "add_channel_member",
1381
1392
  join_channel: "join_channel",
1382
1393
  leave_channel: "leave_channel",
1383
1394
  upload_file: "upload_file",
@@ -1595,8 +1606,44 @@ function resolveSlockCliInvocation(toolName, input) {
1595
1606
  return { toolName: "search_messages", input: { query: readOptionValue(rest, "--query") } };
1596
1607
  case "server info":
1597
1608
  return { toolName: "list_server", input: {} };
1609
+ case "server update":
1610
+ return {
1611
+ toolName: "update_server",
1612
+ input: {
1613
+ name: readOptionValue(rest, "--name"),
1614
+ avatar_file: readOptionValue(rest, "--avatar-file")
1615
+ }
1616
+ };
1598
1617
  case "channel members":
1599
1618
  return { toolName: "list_channel_members", input: { channel: rest[0] } };
1619
+ case "channel update":
1620
+ return {
1621
+ toolName: "update_channel",
1622
+ input: {
1623
+ target: readOptionValue(rest, "--target"),
1624
+ name: readOptionValue(rest, "--name"),
1625
+ description: readOptionValue(rest, "--description"),
1626
+ visibility: rest.includes("--private") ? "private" : rest.includes("--public") ? "public" : void 0
1627
+ }
1628
+ };
1629
+ case "channel add-member":
1630
+ return {
1631
+ toolName: "add_channel_member",
1632
+ input: {
1633
+ target: readOptionValue(rest, "--target"),
1634
+ user: readOptionValue(rest, "--user"),
1635
+ agent: readOptionValue(rest, "--agent")
1636
+ }
1637
+ };
1638
+ case "channel remove-member":
1639
+ return {
1640
+ toolName: "remove_channel_member",
1641
+ input: {
1642
+ target: readOptionValue(rest, "--target"),
1643
+ user: readOptionValue(rest, "--user"),
1644
+ agent: readOptionValue(rest, "--agent")
1645
+ }
1646
+ };
1600
1647
  case "channel join":
1601
1648
  return { toolName: "join_channel", input: { target: readOptionValue(rest, "--target") } };
1602
1649
  case "channel leave":
@@ -1830,6 +1877,21 @@ var agentApiHistoryQuerySchema = passthroughObject({
1830
1877
  around: optionalStringSchema,
1831
1878
  limit: optionalStringSchema
1832
1879
  });
1880
+ var agentApiKnowledgeGetQuerySchema = passthroughObject({
1881
+ topic: z2.string().trim().min(1),
1882
+ reason: optionalStringSchema,
1883
+ turn_id: optionalStringSchema,
1884
+ trace_id: optionalStringSchema
1885
+ });
1886
+ var agentApiKnowledgeGetResponseSchema = passthroughObject({
1887
+ ok: z2.literal(true),
1888
+ docId: z2.string(),
1889
+ topicOrPath: z2.string(),
1890
+ docVersion: z2.string(),
1891
+ docState: z2.string(),
1892
+ contentType: z2.string(),
1893
+ content: z2.string()
1894
+ });
1833
1895
  var agentApiMessageSearchQuerySchema = passthroughObject({
1834
1896
  q: optionalStringSchema,
1835
1897
  channel: optionalStringSchema,
@@ -1867,6 +1929,58 @@ var agentApiMessageReactionBodySchema = passthroughObject({
1867
1929
  var agentApiChannelMembershipParamsSchema = passthroughObject({
1868
1930
  channelId: z2.string().trim().min(1).transform(asChannelId)
1869
1931
  });
1932
+ var agentApiAttachmentDownloadParamsSchema = passthroughObject({
1933
+ attachmentId: z2.string().trim().min(1)
1934
+ });
1935
+ var agentApiAttachmentCommentsParamsSchema = passthroughObject({
1936
+ attachmentId: z2.string().trim().min(1)
1937
+ });
1938
+ var agentApiAttachmentCommentsQuerySchema = passthroughObject({
1939
+ limit: optionalStringSchema
1940
+ });
1941
+ var agentApiAttachmentCommentAnchorSchema = passthroughObject({
1942
+ type: z2.string().trim().min(1),
1943
+ data: z2.record(z2.string(), z2.unknown())
1944
+ });
1945
+ var agentApiAttachmentCommentReactionSchema = passthroughObject({
1946
+ emoji: z2.string().trim().min(1),
1947
+ reactorType: z2.string().trim().min(1),
1948
+ reactorId: z2.string().trim().min(1),
1949
+ createdAt: z2.string().datetime()
1950
+ });
1951
+ var agentApiAttachmentCommentResolvedBySchema = passthroughObject({
1952
+ reactorId: z2.string().trim().min(1),
1953
+ reactorType: z2.string().trim().min(1)
1954
+ });
1955
+ var agentApiAttachmentCommentSchema = passthroughObject({
1956
+ id: z2.string().trim().min(1),
1957
+ channelId: z2.string().trim().min(1).optional(),
1958
+ senderId: z2.string().trim().min(1),
1959
+ senderType: z2.enum(["user", "agent"]),
1960
+ senderName: z2.string().trim().min(1),
1961
+ senderAvatarUrl: nullableStringSchema.optional(),
1962
+ senderGravatarHash: nullableStringSchema.optional(),
1963
+ content: z2.string(),
1964
+ createdAt: z2.string().datetime(),
1965
+ reactions: z2.array(agentApiAttachmentCommentReactionSchema),
1966
+ anchor: agentApiAttachmentCommentAnchorSchema.nullable(),
1967
+ resolved: z2.boolean().optional(),
1968
+ resolvedBy: agentApiAttachmentCommentResolvedBySchema.nullable().optional(),
1969
+ resolvedAt: z2.string().datetime().nullable().optional()
1970
+ });
1971
+ var agentApiAttachmentCommentsResponseSchema = passthroughObject({
1972
+ comments: z2.array(agentApiAttachmentCommentSchema),
1973
+ threadChannelId: nullableStringSchema.optional(),
1974
+ viewer: passthroughObject({
1975
+ canComment: z2.boolean(),
1976
+ reason: z2.string().optional(),
1977
+ canResolve: z2.boolean(),
1978
+ resolveAction: passthroughObject({
1979
+ type: z2.string().trim().min(1),
1980
+ emoji: z2.string().trim().min(1)
1981
+ }).optional()
1982
+ }).optional()
1983
+ });
1870
1984
  var agentApiChannelMembersQuerySchema = passthroughObject({
1871
1985
  channel: z2.string().trim().min(1)
1872
1986
  });
@@ -2021,6 +2135,9 @@ var agentApiIntegrationAppPrepareBodySchema = passthroughObject({
2021
2135
  unsafeDemoUrlOverride: optionalBooleanSchema,
2022
2136
  draftHint: optionalStringSchema
2023
2137
  });
2138
+ var agentApiIntegrationAppRotateSecretBodySchema = passthroughObject({
2139
+ clientKey: z2.string().trim().min(1)
2140
+ });
2024
2141
  var agentApiActionPrepareBodySchema = passthroughObject({
2025
2142
  target: z2.string().trim().min(1),
2026
2143
  action: actionCardActionSchema
@@ -2028,6 +2145,9 @@ var agentApiActionPrepareBodySchema = passthroughObject({
2028
2145
  var agentApiServerInfoResponseSchema = passthroughObject({
2029
2146
  runtimeContext: passthroughObject({
2030
2147
  agentId: z2.string(),
2148
+ runtime: z2.string().optional(),
2149
+ model: z2.string().optional(),
2150
+ reasoningEffort: reasoningEffortSchema.nullable().optional(),
2031
2151
  serverId: z2.string(),
2032
2152
  machineId: z2.string().nullable().optional(),
2033
2153
  machineName: z2.string().nullable().optional(),
@@ -2044,10 +2164,12 @@ var agentApiServerInfoResponseSchema = passthroughObject({
2044
2164
  joined: z2.boolean()
2045
2165
  })),
2046
2166
  agents: z2.array(passthroughObject({
2047
- name: z2.string()
2167
+ name: z2.string(),
2168
+ role: z2.enum(["owner", "admin", "member"]).nullable().optional()
2048
2169
  })),
2049
2170
  humans: z2.array(passthroughObject({
2050
- name: z2.string()
2171
+ name: z2.string(),
2172
+ role: z2.enum(["owner", "admin", "member"]).nullable().optional()
2051
2173
  }))
2052
2174
  });
2053
2175
  var agentApiMentionActionsPendingQuerySchema = passthroughObject({
@@ -2122,6 +2244,12 @@ var agentApiIntegrationAppPrepareResponseSchema = passthroughObject({
2122
2244
  integrationUpdateAppRegistrationOperationSchema
2123
2245
  ])
2124
2246
  });
2247
+ var agentApiIntegrationAppRotateSecretResponseSchema = passthroughObject({
2248
+ clientId: z2.string(),
2249
+ clientKey: z2.string(),
2250
+ clientName: z2.string(),
2251
+ clientSecret: z2.string()
2252
+ });
2125
2253
  var agentApiAttachmentEnvelopeSchema = passthroughObject({
2126
2254
  id: z2.string(),
2127
2255
  filename: z2.string()
@@ -2257,6 +2385,21 @@ var agentApiChannelMembersResponseSchema = passthroughObject({
2257
2385
  role: optionalStringSchema
2258
2386
  }))
2259
2387
  });
2388
+ var agentApiChannelMuteResponseSchema = passthroughObject({
2389
+ activityMuted: optionalBooleanSchema,
2390
+ muteFromSeq: nullableNumberSchema.optional(),
2391
+ attention: passthroughObject({
2392
+ state: optionalStringSchema,
2393
+ ordinaryActivity: optionalStringSchema,
2394
+ unmuteCommand: optionalStringSchema,
2395
+ unmuteApi: optionalStringSchema,
2396
+ muteCommand: optionalStringSchema,
2397
+ muteApi: optionalStringSchema,
2398
+ stillArrives: optionalStringArraySchema,
2399
+ threadBoundary: optionalStringSchema,
2400
+ catchUp: optionalStringSchema
2401
+ }).optional()
2402
+ });
2260
2403
  var agentApiTaskClaimResultSchema = passthroughObject({
2261
2404
  taskNumber: z2.number().int().positive().optional(),
2262
2405
  messageId: optionalStringSchema,
@@ -2369,6 +2512,16 @@ var agentApiContract = {
2369
2512
  request: { query: agentApiHistoryQuerySchema },
2370
2513
  response: { body: agentApiHistoryResponseSchema }
2371
2514
  }),
2515
+ knowledgeGet: route({
2516
+ key: "knowledgeGet",
2517
+ method: "GET",
2518
+ path: "/knowledge",
2519
+ client: { resource: "knowledge", method: "get" },
2520
+ capability: "knowledge",
2521
+ description: "Fetch a Slock Manual for Agents topic from the current server.",
2522
+ request: { query: agentApiKnowledgeGetQuerySchema },
2523
+ response: { body: agentApiKnowledgeGetResponseSchema }
2524
+ }),
2372
2525
  messageSend: route({
2373
2526
  key: "messageSend",
2374
2527
  method: "POST",
@@ -2439,6 +2592,26 @@ var agentApiContract = {
2439
2592
  request: { params: agentApiChannelMembershipParamsSchema },
2440
2593
  response: { body: agentApiOkResponseSchema }
2441
2594
  }),
2595
+ channelMute: route({
2596
+ key: "channelMute",
2597
+ method: "POST",
2598
+ path: "/channels/:channelId/mute",
2599
+ client: { resource: "channels", method: "mute" },
2600
+ capability: "channels",
2601
+ description: "Mute ordinary activity delivery for a visible regular channel as the bound agent credential.",
2602
+ request: { params: agentApiChannelMembershipParamsSchema },
2603
+ response: { body: agentApiChannelMuteResponseSchema }
2604
+ }),
2605
+ channelUnmute: route({
2606
+ key: "channelUnmute",
2607
+ method: "POST",
2608
+ path: "/channels/:channelId/unmute",
2609
+ client: { resource: "channels", method: "unmute" },
2610
+ capability: "channels",
2611
+ description: "Unmute ordinary activity delivery for a visible regular channel as the bound agent credential.",
2612
+ request: { params: agentApiChannelMembershipParamsSchema },
2613
+ response: { body: agentApiChannelMuteResponseSchema }
2614
+ }),
2442
2615
  channelMembers: route({
2443
2616
  key: "channelMembers",
2444
2617
  method: "GET",
@@ -2629,6 +2802,16 @@ var agentApiContract = {
2629
2802
  request: { body: agentApiProfileUpdateBodySchema },
2630
2803
  response: { body: agentApiProfileViewSchema }
2631
2804
  }),
2805
+ profileAvatarUpdate: route({
2806
+ key: "profileAvatarUpdate",
2807
+ method: "POST",
2808
+ path: "/profile/avatar",
2809
+ client: { resource: "profile", method: "updateAvatar" },
2810
+ capability: "server",
2811
+ description: "Update the bound agent profile avatar using multipart form data.",
2812
+ request: {},
2813
+ response: { body: agentApiProfileViewSchema }
2814
+ }),
2632
2815
  integrationList: route({
2633
2816
  key: "integrationList",
2634
2817
  method: "GET",
@@ -2659,6 +2842,22 @@ var agentApiContract = {
2659
2842
  request: { body: agentApiIntegrationAppPrepareBodySchema },
2660
2843
  response: { body: agentApiIntegrationAppPrepareResponseSchema }
2661
2844
  }),
2845
+ integrationAppRotateSecret: route({
2846
+ key: "integrationAppRotateSecret",
2847
+ method: "POST",
2848
+ path: "/integrations/app/rotate-secret",
2849
+ client: { resource: "integrations", method: "rotateAppSecret" },
2850
+ // Mirrors integrationAppPrepare's "read" capability: the AgentApiCapability
2851
+ // enum has no generic "mutation"/"integrations" scope, and the sibling
2852
+ // integration app routes (prepare/login) all gate on "read". Owner-scope is
2853
+ // enforced server-side in rotateClientSecretForAgent's WHERE clause (and the
2854
+ // bound agent credential), so the capability tier is not the security
2855
+ // boundary here. Keep parity with integrationAppPrepare.
2856
+ capability: "read",
2857
+ description: "Regenerate the one-time client secret for a server-local integration app the calling agent owns; invalidates the previous secret.",
2858
+ request: { body: agentApiIntegrationAppRotateSecretBodySchema },
2859
+ response: { body: agentApiIntegrationAppRotateSecretResponseSchema }
2860
+ }),
2662
2861
  actionPrepare: route({
2663
2862
  key: "actionPrepare",
2664
2863
  method: "POST",
@@ -2678,6 +2877,131 @@ var agentApiContract = {
2678
2877
  description: "Upload a multipart attachment as the bound agent credential.",
2679
2878
  request: {},
2680
2879
  response: { body: agentApiAttachmentUploadResponseSchema }
2880
+ }),
2881
+ attachmentDownload: route({
2882
+ key: "attachmentDownload",
2883
+ method: "GET",
2884
+ path: "/attachments/:attachmentId",
2885
+ client: { resource: "attachments", method: "download" },
2886
+ capability: "read",
2887
+ description: "Download attachment bytes visible to the bound agent credential.",
2888
+ request: { params: agentApiAttachmentDownloadParamsSchema },
2889
+ response: { kind: "binary" }
2890
+ }),
2891
+ attachmentCommentsList: route({
2892
+ key: "attachmentCommentsList",
2893
+ method: "GET",
2894
+ path: "/attachments/:attachmentId/comments",
2895
+ client: { resource: "attachments", method: "comments" },
2896
+ capability: "read",
2897
+ description: "List comments scoped to an attachment visible to the bound agent credential.",
2898
+ request: { params: agentApiAttachmentCommentsParamsSchema, query: agentApiAttachmentCommentsQuerySchema },
2899
+ response: { body: agentApiAttachmentCommentsResponseSchema }
2900
+ })
2901
+ };
2902
+
2903
+ // ../shared/src/daemonApiContract.ts
2904
+ import { z as z3 } from "zod";
2905
+ var DAEMON_API_BASE_PATH = "/internal/agent-api";
2906
+ var optionalStringSchema2 = z3.string().trim().optional();
2907
+ var optionalNonNegativeIntSchema = z3.number().int().nonnegative().optional();
2908
+ var optionalQueryIntSchema = z3.union([z3.number().int().nonnegative(), z3.string().trim().min(1)]).optional();
2909
+ var nullableNumberSchema2 = z3.number().finite().nullable();
2910
+ var passthroughObject2 = (shape) => z3.object(shape).passthrough();
2911
+ var daemonApiInboxFlagSchema = z3.enum(["mention", "thread", "dm", "task"]);
2912
+ var daemonApiInboxTargetRowSchema = passthroughObject2({
2913
+ target: z3.string().trim().min(1),
2914
+ channelId: optionalStringSchema2,
2915
+ channelType: optionalStringSchema2,
2916
+ pendingCount: z3.number().int().nonnegative(),
2917
+ firstPendingMsgId: optionalStringSchema2,
2918
+ firstPendingSeq: optionalNonNegativeIntSchema,
2919
+ latestMsgId: optionalStringSchema2,
2920
+ latestSeq: optionalNonNegativeIntSchema,
2921
+ latestSenderName: optionalStringSchema2,
2922
+ latestSenderType: z3.enum(["human", "agent", "system"]).optional(),
2923
+ flags: z3.array(daemonApiInboxFlagSchema)
2924
+ });
2925
+ var daemonApiInboxCheckResponseSchema = passthroughObject2({
2926
+ rows: z3.array(daemonApiInboxTargetRowSchema).optional()
2927
+ });
2928
+ var daemonApiWakeHintsQuerySchema = passthroughObject2({
2929
+ since: z3.union([z3.literal("latest"), z3.number().int().nonnegative(), z3.string().trim().min(1)]).optional(),
2930
+ limit: optionalQueryIntSchema
2931
+ });
2932
+ var daemonApiWakeHintSchema = passthroughObject2({
2933
+ hintId: optionalStringSchema2,
2934
+ hint_id: optionalStringSchema2,
2935
+ eventId: optionalStringSchema2,
2936
+ event_id: optionalStringSchema2,
2937
+ messageId: z3.string().nullable().optional(),
2938
+ message_id: z3.string().nullable().optional(),
2939
+ seq: optionalNonNegativeIntSchema,
2940
+ id: optionalStringSchema2,
2941
+ target: optionalStringSchema2,
2942
+ targetType: optionalStringSchema2,
2943
+ target_type: optionalStringSchema2,
2944
+ reason: optionalStringSchema2,
2945
+ wake_reason: optionalStringSchema2,
2946
+ createdAt: optionalStringSchema2,
2947
+ created_at: optionalStringSchema2
2948
+ });
2949
+ var daemonApiWakeHintsFetchResponseSchema = passthroughObject2({
2950
+ hints: z3.array(daemonApiWakeHintSchema).optional(),
2951
+ wake_hints: z3.array(daemonApiWakeHintSchema).optional(),
2952
+ last_seen_hint_seq: nullableNumberSchema2.optional(),
2953
+ last_hint_seq: nullableNumberSchema2.optional(),
2954
+ has_more: z3.boolean().optional()
2955
+ });
2956
+ var daemonApiActivityEventSchema = passthroughObject2({
2957
+ schema: optionalStringSchema2
2958
+ });
2959
+ var daemonApiActivityForwardBodySchema = passthroughObject2({
2960
+ schema: z3.literal("raft-agent-activity-ingest.v1"),
2961
+ coreSessionId: optionalStringSchema2,
2962
+ adapterInstance: optionalStringSchema2,
2963
+ events: z3.array(daemonApiActivityEventSchema),
2964
+ dropped: optionalNonNegativeIntSchema
2965
+ });
2966
+ var daemonApiActivityForwardResponseSchema = passthroughObject2({
2967
+ ok: z3.literal(true).optional(),
2968
+ acceptedCount: z3.number().int().nonnegative().optional(),
2969
+ rejectedCount: z3.number().int().nonnegative().optional(),
2970
+ droppedCount: z3.number().int().nonnegative().optional()
2971
+ });
2972
+ function route2(input) {
2973
+ return {
2974
+ ...input,
2975
+ fullPath: `${DAEMON_API_BASE_PATH}${input.path}`
2976
+ };
2977
+ }
2978
+ var daemonApiContract = {
2979
+ inboxCheck: route2({
2980
+ key: "inboxCheck",
2981
+ method: "GET",
2982
+ path: "/inbox",
2983
+ client: { resource: "inbox", method: "check" },
2984
+ description: "Read the managed-runner daemon inbox snapshot without draining message content.",
2985
+ request: {},
2986
+ response: { body: daemonApiInboxCheckResponseSchema }
2987
+ }),
2988
+ wakeHintsFetch: route2({
2989
+ key: "wakeHintsFetch",
2990
+ method: "GET",
2991
+ path: "/wake-hints",
2992
+ client: { resource: "wakeHints", method: "fetch" },
2993
+ description: "Peek content-free wake hints without advancing delivery cursors.",
2994
+ request: { query: daemonApiWakeHintsQuerySchema },
2995
+ response: { body: daemonApiWakeHintsFetchResponseSchema }
2996
+ }),
2997
+ activityForward: route2({
2998
+ key: "activityForward",
2999
+ method: "POST",
3000
+ path: "/activity",
3001
+ client: { resource: "activity", method: "forward" },
3002
+ description: "Forward plugin-observed activity from a local bridge to the daemon/server activity ingest path.",
3003
+ request: { body: daemonApiActivityForwardBodySchema },
3004
+ response: { body: daemonApiActivityForwardResponseSchema }
2681
3005
  })
2682
3006
  };
2683
3007
 
@@ -2708,7 +3032,7 @@ function shortMessageId(value) {
2708
3032
  }
2709
3033
 
2710
3034
  // ../shared/src/externalAgentIntegration.ts
2711
- import { z as z3 } from "zod";
3035
+ import { z as z4 } from "zod";
2712
3036
  var EXTERNAL_AGENT_COMMS_PROTOCOL_VERSION = "agent-comms-core.v1";
2713
3037
  var EXTERNAL_AGENT_PROOF_SCHEMA_VERSION = "agent-proof.v1";
2714
3038
  var EXTERNAL_RUNTIME_INTEGRATION_MANIFEST_SCHEMA = "slock-external-runtime-integration.v1";
@@ -2752,35 +3076,35 @@ var externalAgentAdapterFailureValues = [
2752
3076
  "auth_revoked"
2753
3077
  ];
2754
3078
  var externalAgentServerApiModeValues = ["interim-agent-api-events", "agent-inbox-protocol"];
2755
- var nonEmptyStringSchema = z3.string().min(1);
2756
- var isoTimestampSchema = z3.string().refine((value) => !Number.isNaN(Date.parse(value)), {
3079
+ var nonEmptyStringSchema = z4.string().min(1);
3080
+ var isoTimestampSchema = z4.string().refine((value) => !Number.isNaN(Date.parse(value)), {
2757
3081
  message: "must be a parseable timestamp"
2758
3082
  });
2759
- var externalRuntimeIntegrationManifestSchema = z3.object({
2760
- schema: z3.literal(EXTERNAL_RUNTIME_INTEGRATION_MANIFEST_SCHEMA),
3083
+ var externalRuntimeIntegrationManifestSchema = z4.object({
3084
+ schema: z4.literal(EXTERNAL_RUNTIME_INTEGRATION_MANIFEST_SCHEMA),
2761
3085
  runtimeId: nonEmptyStringSchema,
2762
- integrationPattern: z3.enum(externalAgentIntegrationPatternValues),
2763
- commsMode: z3.enum(externalAgentCommsModeValues),
2764
- commsProtocolVersion: z3.literal(EXTERNAL_AGENT_COMMS_PROTOCOL_VERSION),
2765
- proofSchemaVersion: z3.literal(EXTERNAL_AGENT_PROOF_SCHEMA_VERSION),
3086
+ integrationPattern: z4.enum(externalAgentIntegrationPatternValues),
3087
+ commsMode: z4.enum(externalAgentCommsModeValues),
3088
+ commsProtocolVersion: z4.literal(EXTERNAL_AGENT_COMMS_PROTOCOL_VERSION),
3089
+ proofSchemaVersion: z4.literal(EXTERNAL_AGENT_PROOF_SCHEMA_VERSION),
2766
3090
  minSlockCliVersion: nonEmptyStringSchema,
2767
- multiplex: z3.boolean(),
2768
- agentIsolation: z3.enum(externalAgentIsolationValues),
2769
- bridgeLifecycle: z3.object({
2770
- explicitStartOnly: z3.literal(true),
2771
- oneShotCommandsBridgeIndependent: z3.literal(true),
2772
- requiresBridgeFailureCodes: z3.array(z3.enum(["BRIDGE_NOT_RUNNING", "NO_CORE_SESSION"])).min(1),
2773
- autoStartDefault: z3.literal(false)
3091
+ multiplex: z4.boolean(),
3092
+ agentIsolation: z4.enum(externalAgentIsolationValues),
3093
+ bridgeLifecycle: z4.object({
3094
+ explicitStartOnly: z4.literal(true),
3095
+ oneShotCommandsBridgeIndependent: z4.literal(true),
3096
+ requiresBridgeFailureCodes: z4.array(z4.enum(["BRIDGE_NOT_RUNNING", "NO_CORE_SESSION"])).min(1),
3097
+ autoStartDefault: z4.literal(false)
2774
3098
  }).strict(),
2775
- serverApi: z3.object({
2776
- mode: z3.enum(externalAgentServerApiModeValues),
2777
- deliveryOnly: z3.boolean(),
2778
- cursorAuthority: z3.literal("model_seen_only")
3099
+ serverApi: z4.object({
3100
+ mode: z4.enum(externalAgentServerApiModeValues),
3101
+ deliveryOnly: z4.boolean(),
3102
+ cursorAuthority: z4.literal("model_seen_only")
2779
3103
  }).strict(),
2780
- wakeAdapter: z3.object({
2781
- kind: z3.enum(externalAgentWakeAdapterKindValues),
3104
+ wakeAdapter: z4.object({
3105
+ kind: z4.enum(externalAgentWakeAdapterKindValues),
2782
3106
  protocol: nonEmptyStringSchema,
2783
- requiresInteractiveSession: z3.boolean().optional()
3107
+ requiresInteractiveSession: z4.boolean().optional()
2784
3108
  }).strict()
2785
3109
  }).strict().superRefine((value, ctx) => {
2786
3110
  if (!value.bridgeLifecycle.requiresBridgeFailureCodes.includes("BRIDGE_NOT_RUNNING")) {
@@ -2805,8 +3129,8 @@ var externalRuntimeIntegrationManifestSchema = z3.object({
2805
3129
  });
2806
3130
  }
2807
3131
  });
2808
- var externalAgentWakeEventBaseSchema = z3.object({
2809
- schema: z3.literal(EXTERNAL_AGENT_WAKE_EVENT_SCHEMA),
3132
+ var externalAgentWakeEventBaseSchema = z4.object({
3133
+ schema: z4.literal(EXTERNAL_AGENT_WAKE_EVENT_SCHEMA),
2810
3134
  eventId: nonEmptyStringSchema,
2811
3135
  attemptId: nonEmptyStringSchema,
2812
3136
  messageId: nonEmptyStringSchema,
@@ -2816,30 +3140,30 @@ var externalAgentWakeEventBaseSchema = z3.object({
2816
3140
  adapterInstance: nonEmptyStringSchema,
2817
3141
  runtimeSession: nonEmptyStringSchema.nullable(),
2818
3142
  occurredAt: isoTimestampSchema,
2819
- lifecycleState: z3.enum(externalAgentCommsLifecycleStateValues),
2820
- authority: z3.object({
2821
- source: z3.enum(externalAgentLifecycleSourceValues),
2822
- provenance: z3.enum(externalAgentLifecycleProvenanceValues)
3143
+ lifecycleState: z4.enum(externalAgentCommsLifecycleStateValues),
3144
+ authority: z4.object({
3145
+ source: z4.enum(externalAgentLifecycleSourceValues),
3146
+ provenance: z4.enum(externalAgentLifecycleProvenanceValues)
2823
3147
  }).strict()
2824
3148
  }).strict();
2825
3149
  var externalAgentProofEventEnvelopeSchema = externalAgentWakeEventBaseSchema.extend({
2826
- kind: z3.literal("proof"),
2827
- proofLevel: z3.enum(externalAgentWakeProofLevelValues),
2828
- outcome: z3.literal("ok"),
2829
- failureMeta: z3.undefined().optional(),
2830
- reason: z3.string().optional()
3150
+ kind: z4.literal("proof"),
3151
+ proofLevel: z4.enum(externalAgentWakeProofLevelValues),
3152
+ outcome: z4.literal("ok"),
3153
+ failureMeta: z4.undefined().optional(),
3154
+ reason: z4.string().optional()
2831
3155
  });
2832
3156
  var externalAgentFailedWakeEventEnvelopeSchema = externalAgentWakeEventBaseSchema.extend({
2833
- kind: z3.literal("wake_attempt"),
2834
- proofLevel: z3.undefined().optional(),
2835
- outcome: z3.literal("failed"),
2836
- failureMeta: z3.object({
2837
- failureClass: z3.enum(externalAgentAdapterFailureValues),
2838
- retryAfterMs: z3.number().int().positive().optional()
3157
+ kind: z4.literal("wake_attempt"),
3158
+ proofLevel: z4.undefined().optional(),
3159
+ outcome: z4.literal("failed"),
3160
+ failureMeta: z4.object({
3161
+ failureClass: z4.enum(externalAgentAdapterFailureValues),
3162
+ retryAfterMs: z4.number().int().positive().optional()
2839
3163
  }).strict(),
2840
3164
  reason: nonEmptyStringSchema
2841
3165
  });
2842
- var externalAgentWakeEventEnvelopeSchema = z3.discriminatedUnion("kind", [
3166
+ var externalAgentWakeEventEnvelopeSchema = z4.discriminatedUnion("kind", [
2843
3167
  externalAgentProofEventEnvelopeSchema,
2844
3168
  externalAgentFailedWakeEventEnvelopeSchema
2845
3169
  ]);
@@ -3382,7 +3706,7 @@ var TRIAL_DURATION_DAYS = (TRIAL_END_DATE.getTime() - TRIAL_START_DATE.getTime()
3382
3706
  // src/agentProcessManager.ts
3383
3707
  import { existsSync as existsSync8, mkdirSync as mkdirSync4, readFileSync as readFileSync6, readdirSync as readdirSync4, statSync, writeFileSync as writeFileSync4 } from "fs";
3384
3708
  import { mkdir, writeFile, access, readdir as readdir2, stat as stat2, readFile, rm as rm2, lstat, realpath, open } from "fs/promises";
3385
- import { createHash as createHash3, randomUUID as randomUUID5 } from "crypto";
3709
+ import { createHash as createHash3, randomUUID as randomUUID6 } from "crypto";
3386
3710
  import path14 from "path";
3387
3711
  import { gzipSync } from "zlib";
3388
3712
  import os6 from "os";
@@ -3797,40 +4121,20 @@ function buildCommunicationSection(audience) {
3797
4121
  const installation = describeSlockInstallation(audience);
3798
4122
  return `## Communication \u2014 raft CLI ONLY
3799
4123
 
3800
- Use the \`raft\` CLI for chat / task / attachment operations (\`slock\` remains a legacy alias). ${installation} Use ONLY these commands for communication:
3801
-
3802
- 1. **\`raft message check\`** \u2014 Non-blocking check for new messages. Use freely during work \u2014 at natural breakpoints or after notifications.
3803
- 2. **\`raft message send\`** \u2014 Send a message to a channel or DM.
3804
- 3. **\`raft server info\`** \u2014 List channels in this server, which ones you have joined, plus all agents and humans.
3805
- 4. **\`raft channel members\`** \u2014 List the members (agents and humans) of a specific channel, DM, or thread target.
3806
- 5. **\`raft channel join\`** \u2014 Join a visible public channel. This only affects your own agent membership.
3807
- 6. **\`raft channel leave\`** \u2014 Leave a regular channel you have joined. This only affects your own agent membership.
3808
- 7. **\`raft channel mute\`** \u2014 Mute ordinary Activity delivery for a regular channel for your agent. Personal @mentions and DMs still pierce; a task pierces only when it personally @mentions you (being a task does not pierce).
3809
- 8. **\`raft channel unmute\`** \u2014 Unmute ordinary Activity delivery for a regular channel for your agent. Muted-window messages are not retroactively promoted.
3810
- 9. **\`raft thread unfollow\`** \u2014 Stop receiving ordinary delivery for a thread you no longer need to follow. This only affects your own agent attention state.
3811
- 10. **\`raft message read\`** \u2014 Read past messages from a channel, DM, or thread. Supports \`before\` / \`after\` anchors and \`around\` for centered context.
3812
- 11. **\`raft message search\`** \u2014 Search messages visible to you, then inspect a hit with \`raft message read\`.
3813
- 12. **\`raft message resolve\`** \u2014 Verify that a cited message id exists exactly and print its canonical message row. Use this when checking whether a referenced id is real; \`read --around\` is for context, not proof.
3814
- 13. **\`raft message react\`** \u2014 Add or remove your reaction on a message. Use sparingly: prefer acknowledgement/follow-up signals like \u{1F440}, and do not auto-react to every merge, deploy, or task completion with celebratory emoji.
3815
- 14. **\`raft task list\`** \u2014 View a channel's task board.
3816
- 15. **\`raft task create\`** \u2014 Create new task-messages in a channel (supports batch titles; equivalent to sending a new message and publishing it as a task-message, not claiming it for yourself).
3817
- 16. **\`raft task claim\`** \u2014 Claim tasks by number or message ID using repeatable flags; examples: \`raft task claim --channel "#channel" --number 1 --number 2\`, or \`raft task claim --channel "#channel" --message-id abc12345\`.
3818
- 17. **\`raft task unclaim\`** \u2014 Release your claim on a task.
3819
- 18. **\`raft task update\`** \u2014 Change a task's status (e.g. to in_review or done).
3820
- 19. **\`raft attachment upload\`** \u2014 Upload a file to attach to a message. Uses content sniffing for image previews; pass \`--mime-type\` only when you know the exact type. Returns an attachment ID to pass to \`raft message send\`.
3821
- 20. **\`raft attachment view\`** \u2014 Download an attached file by its attachment ID so you can inspect it locally.
3822
- 21. **\`raft profile show\`** \u2014 Show your own profile, or another visible profile via \`@handle\`. Mirrors the canonical Slock profile view.
3823
- 22. **\`raft profile update\`** \u2014 Update your own profile. Supports \`--avatar-file <path>\`, \`--avatar-url pixel:random:<seed>\`, \`--display-name <name>\`, and \`--description <text>\`. Use \`--avatar-url pixel:random:<seed>\` when you want a new pixel avatar but do not have a local image file. Values must be non-empty. Provide at least one flag per call; multiple flags can be combined.
3824
- 23. **\`raft integration list\`** \u2014 List built-in Slock apps, registered third-party services, and this agent's active Slock Agent Logins.
3825
- 24. **\`raft integration login\`** \u2014 Provision or reuse this agent's login for a built-in Slock app or registered third-party service.
3826
- 25. **\`raft integration env\`** \u2014 Print per-agent local CLI environment for a manifest-backed service that requires isolated HOME/XDG state.
3827
- 26. **\`raft reminder schedule\`** \u2014 Schedule a reminder for yourself later, at a specific time, or on a recurring cadence.
3828
- 27. **\`raft reminder list\`** \u2014 List your reminders, including lifecycle history for each reminder.
3829
- 28. **\`raft reminder snooze\`** \u2014 Push a reminder later without replacing it.
3830
- 29. **\`raft reminder update\`** \u2014 Change a reminder's title, schedule, or recurrence without creating a new reminder.
3831
- 30. **\`raft reminder cancel\`** \u2014 Cancel one of your reminders by ID.
3832
- 31. **\`raft reminder log\`** \u2014 Show the event log for a reminder, including fires, dismissals, and reschedules.
3833
- 32. **\`raft action prepare\`** \u2014 Prepare an action card for a human to commit (B-mode quick-commit shortcut). Posts a card the human can click to execute the action under their own identity. Pass \`--target <ch>\` and pipe the action JSON on stdin (variants: \`channel:create\`, \`agent:create\`).
4124
+ Use the \`raft\` CLI for chat / task / attachment operations (\`slock\` remains a legacy alias). ${installation} Use ONLY these command families for communication and management:
4125
+
4126
+ 1. **Messages** \u2014 \`raft message check\`, \`raft message send\`, \`raft message read\`, \`raft message search\`, \`raft message resolve\`, \`raft message react\`.
4127
+ 2. **Server and channel awareness** \u2014 \`raft server info\`, \`raft channel members\`.
4128
+ 3. **Your channel/thread attention** \u2014 \`raft channel join\`, \`raft channel leave\`, \`raft channel mute\`, \`raft channel unmute\`, \`raft thread unfollow\`.
4129
+ 4. **Admin channel/server management** \u2014 \`raft channel create\`, \`raft channel update\`, \`raft channel add-member\`, \`raft channel remove-member\`, \`raft server update\`.
4130
+ 5. **Tasks** \u2014 \`raft task list\`, \`raft task create\`, \`raft task claim\`, \`raft task unclaim\`, \`raft task update\`.
4131
+ 6. **Attachments** \u2014 \`raft attachment upload\`, \`raft attachment view\`.
4132
+ 7. **Profiles** \u2014 \`raft profile show\`, \`raft profile update\`.
4133
+ 8. **Integrations** \u2014 \`raft integration list\`, \`raft integration login\`, \`raft integration env\`, \`raft integration invoke\`.
4134
+ 9. **Reminders** \u2014 \`raft reminder schedule\`, \`raft reminder list\`, \`raft reminder snooze\`, \`raft reminder update\`, \`raft reminder cancel\`, \`raft reminder log\`.
4135
+ 10. **Action cards** \u2014 \`raft action prepare\`.
4136
+
4137
+ Run any subcommand with \`--help\` for syntax.
3834
4138
 
3835
4139
  The CLI prints human-readable canonical text on success (matching the format you see in received messages and history). On failure it prints canonical labeled text to stderr:
3836
4140
  - \`Error:\` human-readable error summary
@@ -3947,7 +4251,7 @@ Only top-level channel / DM messages can become tasks. Messages inside threads a
3947
4251
 
3948
4252
  **Workflow:**
3949
4253
  1. Receive a message that requires action \u2192 claim it first (by task number if already a task, or by message ID if it's a regular message). Use repeat flags: \`raft task claim --channel "#channel" --number 1 --number 2\` or \`raft task claim --channel "#channel" --message-id abc12345\`.
3950
- 2. If the claim fails, someone else is working on it \u2014 move on to another task
4254
+ 2. If the claim fails, someone else is working on it \u2014 do not work on that task unless an owner/admin explicitly redirects it to you
3951
4255
  3. Post updates in the task's thread: \`raft message send --target "#channel:msgShortId" <<'${D}'\` followed by the message body and \`${D}\`
3952
4256
  4. When done, set status to \`in_review\` so a human can validate via \`raft task update\`
3953
4257
  5. After approval (e.g. "looks good", "merge it"), set status to \`done\`
@@ -4001,7 +4305,7 @@ function buildConversationEtiquetteSection(taskClaimCmd = "`raft task claim`") {
4001
4305
 
4002
4306
  - **Respect ongoing conversations.** If a human is having a back-and-forth with another person (human or agent) on a topic, their follow-up messages are directed at that person \u2014 only join if you are explicitly @mentioned or clearly addressed.
4003
4307
  - **Only the person doing the work should report on it.** If someone else completed a task or submitted a PR, don't echo or summarize their work \u2014 let them respond to questions about it.
4004
- - **Claim before you start.** Always call ${taskClaimCmd} before doing any work on a task. If the claim fails, stop immediately and pick a different task.
4308
+ - **Claim before you start.** Always call ${taskClaimCmd} before doing any work on a task. If the claim fails, do not work on that task unless an owner/admin explicitly redirects it to you.
4005
4309
  - **Before stopping, check for concrete blockers you own.** If you still owe a specific handoff, review, decision, or reply that is currently blocking a specific person, send one minimal actionable message to that person or channel before stopping.
4006
4310
  - **Skip idle narration.** Only send messages when you have actionable content \u2014 avoid broadcasting that you are waiting or idle.`;
4007
4311
  }
@@ -4154,7 +4458,7 @@ function buildPrompt(config, opts) {
4154
4458
  ...opts.extraCriticalRules,
4155
4459
  "- Use only the provided `raft` CLI commands for messaging.",
4156
4460
  "- Do not combine multiple `raft` CLI commands in one shell command. Run one `raft` command per tool call, read its output, then decide the next command.",
4157
- "- Always claim a task via `raft task claim` before starting work on it. If the claim fails, move on to a different task."
4461
+ "- Always claim a task via `raft task claim` before starting work on it. If the claim fails, do not work on that task unless an owner/admin explicitly redirects it to you."
4158
4462
  ];
4159
4463
  const runtimeProfileControl = config.runtimeProfileControl?.kind === "daemon_release_notice" ? config.runtimeProfileControl : null;
4160
4464
  const runtimeProfileControlStartupStep = runtimeProfileControl ? [
@@ -4177,7 +4481,7 @@ function buildPrompt(config, opts) {
4177
4481
  const channelAwarenessSection = cliGuideSections.channelAwareness;
4178
4482
  const thirdPartyIntegrationsSection = `### Third-party integrations
4179
4483
 
4180
- 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.`;
4484
+ 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 manifest-backed HTTP API actions, prefer \`raft integration invoke --service <service> --list-actions\` and then \`raft integration invoke --service <service> --action <name>\`; the CLI performs the stateless Agent Login callback handoff and service-session setup for you. 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; for HTTP API action services, use \`raft integration invoke\` instead. 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 local 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 \`raft integration login\` 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 a stateless Login with Raft API-action session handoff URL; prefer \`raft integration invoke\` over manually opening or curling it. 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 outside the documented CLI flow, 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.`;
4181
4485
  const readingHistorySection = cliGuideSections.readingHistory;
4182
4486
  const historicalReferenceSection = cliGuideSections.historicalReferences;
4183
4487
  const tasksSection = cliGuideSections.tasks;
@@ -6525,14 +6829,15 @@ var ClaudeEventNormalizer = class {
6525
6829
  const stopReason = typeof event.stop_reason === "string" ? event.stop_reason : null;
6526
6830
  const resultSessionId = eventSessionId ?? this.currentSession;
6527
6831
  const usageTelemetry = parseClaudeResultUsageTelemetry(event, resultSessionId);
6832
+ const isMaxTokenError = stopReason === "max_tokens" && (event.is_error === true || subtype !== "success");
6528
6833
  switch (subtype) {
6529
6834
  case "success":
6530
- if (event.is_error && stopReason !== "max_tokens") {
6835
+ if (event.is_error) {
6531
6836
  pushResultError(event, "Execution failed");
6532
6837
  }
6533
6838
  break;
6534
6839
  case "error_during_execution":
6535
- if (stopReason !== "max_tokens") {
6840
+ if (stopReason !== "max_tokens" || isMaxTokenError) {
6536
6841
  pushResultError(event, "Execution failed");
6537
6842
  }
6538
6843
  break;
@@ -11520,6 +11825,9 @@ var AgentStartPendingDeliveryBuffer = class {
11520
11825
  get size() {
11521
11826
  return this.pending.size;
11522
11827
  }
11828
+ agentIds() {
11829
+ return [...this.pending.keys()];
11830
+ }
11523
11831
  values(agentId) {
11524
11832
  return [...this.pending.get(agentId) ?? []];
11525
11833
  }
@@ -11606,6 +11914,230 @@ var AgentStartPendingDeliveryBuffer = class {
11606
11914
  }
11607
11915
  };
11608
11916
 
11917
+ // src/agentNoProcessResidency.ts
11918
+ import { randomUUID as randomUUID5 } from "crypto";
11919
+ var AgentNoProcessResidencyTransitions = class {
11920
+ open = /* @__PURE__ */ new Map();
11921
+ transitionSeq = 0;
11922
+ enter(input) {
11923
+ const existing = this.open.get(input.agentId);
11924
+ if (existing && existing.state === input.state && existing.agentLaunchId === input.agentLaunchId) {
11925
+ return [];
11926
+ }
11927
+ const rows = [];
11928
+ if (existing) {
11929
+ rows.push(this.closeRow(existing, { closeResult: "advanced" }));
11930
+ }
11931
+ const current = {
11932
+ agentId: input.agentId,
11933
+ agentLaunchId: input.agentLaunchId,
11934
+ agentLaunchIdPresent: input.agentLaunchIdPresent,
11935
+ serverId: input.serverId,
11936
+ machineId: input.machineId,
11937
+ runtime: input.runtime,
11938
+ driver: input.driver,
11939
+ launchSource: input.launchSource,
11940
+ state: input.state,
11941
+ stateInstanceId: randomUUID5(),
11942
+ isWaitState: input.isWaitState,
11943
+ fenceKind: input.fenceKind,
11944
+ deadlineUnixMs: typeof input.deadlineUnixMs === "number" ? input.deadlineUnixMs : void 0,
11945
+ failureKind: input.failureKind,
11946
+ negativeEvidenceBucket: input.negativeEvidenceBucket
11947
+ };
11948
+ this.open.set(input.agentId, current);
11949
+ rows.push(this.enterRow(current));
11950
+ return rows;
11951
+ }
11952
+ close(agentId, input) {
11953
+ const existing = this.open.get(agentId);
11954
+ if (!existing) return [];
11955
+ this.open.delete(agentId);
11956
+ return [this.closeRow(existing, input)];
11957
+ }
11958
+ enterRow(open2) {
11959
+ return this.baseRow(open2, {
11960
+ transition_kind: "enter",
11961
+ phase_result: "entered",
11962
+ is_wait_state: open2.isWaitState,
11963
+ fence_kind: open2.fenceKind,
11964
+ deadline_unix_ms: open2.deadlineUnixMs,
11965
+ failure_kind: open2.failureKind,
11966
+ negative_evidence_bucket: open2.negativeEvidenceBucket
11967
+ });
11968
+ }
11969
+ closeRow(open2, input) {
11970
+ return this.baseRow(open2, {
11971
+ transition_kind: "close",
11972
+ close_result: input.closeResult,
11973
+ is_wait_state: open2.isWaitState,
11974
+ fence_kind: open2.fenceKind,
11975
+ deadline_unix_ms: open2.deadlineUnixMs,
11976
+ failure_kind: input.failureKind ?? open2.failureKind,
11977
+ negative_evidence_bucket: input.negativeEvidenceBucket ?? open2.negativeEvidenceBucket
11978
+ });
11979
+ }
11980
+ baseRow(open2, attrs) {
11981
+ const transitionSeq = ++this.transitionSeq;
11982
+ const row = {
11983
+ span_name: "launch_residency_transition",
11984
+ phase: "process_residency",
11985
+ agent_launch_id: open2.agentLaunchId,
11986
+ agent_id: open2.agentId,
11987
+ server_id: open2.serverId,
11988
+ machine_id: open2.machineId,
11989
+ runtime: open2.runtime,
11990
+ driver: open2.driver,
11991
+ launch_source: open2.launchSource,
11992
+ state_instance_id: open2.stateInstanceId,
11993
+ residency_state_instance_id: open2.stateInstanceId,
11994
+ transition_seq: transitionSeq,
11995
+ residency_transition_seq: transitionSeq,
11996
+ transition_kind: attrs.transition_kind,
11997
+ state: open2.state,
11998
+ residency: open2.state,
11999
+ agent_launch_id_present: open2.agentLaunchIdPresent
12000
+ };
12001
+ return withoutUndefined({
12002
+ ...row,
12003
+ phase_result: attrs.phase_result,
12004
+ close_result: attrs.close_result,
12005
+ is_wait_state: attrs.is_wait_state,
12006
+ fence_kind: attrs.fence_kind,
12007
+ deadline_unix_ms: attrs.deadline_unix_ms,
12008
+ failure_kind: attrs.failure_kind,
12009
+ negative_evidence_bucket: attrs.negative_evidence_bucket
12010
+ });
12011
+ }
12012
+ };
12013
+ function withoutUndefined(input) {
12014
+ return Object.fromEntries(Object.entries(input).filter(([, value]) => value !== void 0));
12015
+ }
12016
+ var AgentNoProcessResidency = class {
12017
+ static assertInvariants(context, snapshot) {
12018
+ const running = new Set(snapshot.runningAgentIds);
12019
+ const idle = new Set(snapshot.idleAgentIds);
12020
+ const terminal = new Set(snapshot.terminalFailureAgentIds);
12021
+ const activeCooldown = new Set(snapshot.activeCooldownAgentIds);
12022
+ const queued = new Set(snapshot.queuedAgentIds);
12023
+ const starting = new Set(snapshot.startingAgentIds);
12024
+ for (const agentId of activeCooldown) {
12025
+ if (!idle.has(agentId)) {
12026
+ throw new Error(`Agent no-process residency invariant violation after ${context}: active cooldown without restart config for ${agentId}`);
12027
+ }
12028
+ }
12029
+ for (const agentId of terminal) {
12030
+ if (idle.has(agentId)) {
12031
+ throw new Error(`Agent no-process residency invariant violation after ${context}: terminal failure and idle restart config both present for ${agentId}`);
12032
+ }
12033
+ if (running.has(agentId)) {
12034
+ throw new Error(`Agent no-process residency invariant violation after ${context}: terminal failure while process is still registered for ${agentId}`);
12035
+ }
12036
+ }
12037
+ const allowedPending = this.allowedStartPendingSnapshot(snapshot);
12038
+ const allowed = /* @__PURE__ */ new Set([
12039
+ ...allowedPending.queuedAgentIds,
12040
+ ...allowedPending.startingAgentIds,
12041
+ ...allowedPending.terminalRecoveryAgentIds,
12042
+ ...allowedPending.cooldownAgentIds
12043
+ ]);
12044
+ for (const agentId of snapshot.pendingDeliveryAgentIds) {
12045
+ if (!allowed.has(agentId)) {
12046
+ throw new Error(`Agent no-process residency invariant violation after ${context}: pending delivery without queued/starting/terminal/cooldown residency for ${agentId}`);
12047
+ }
12048
+ }
12049
+ for (const agentId of snapshot.fingerprintFenceAgentIds) {
12050
+ if (!running.has(agentId) && !idle.has(agentId) && !terminal.has(agentId)) {
12051
+ throw new Error(`Agent no-process residency invariant violation after ${context}: fingerprint fence without running process, idle retry config, or terminal failure for ${agentId}`);
12052
+ }
12053
+ }
12054
+ for (const agentId of queued) {
12055
+ if (starting.has(agentId)) {
12056
+ throw new Error(`Agent no-process residency invariant violation after ${context}: queued and starting facts overlap for ${agentId}`);
12057
+ }
12058
+ }
12059
+ }
12060
+ static allowedStartPendingSnapshot(snapshot) {
12061
+ const idle = new Set(snapshot.idleAgentIds);
12062
+ const cooldownAgentIds = snapshot.activeCooldownAgentIds.filter((agentId) => idle.has(agentId));
12063
+ return {
12064
+ queuedAgentIds: [...snapshot.queuedAgentIds],
12065
+ startingAgentIds: [...snapshot.startingAgentIds],
12066
+ terminalRecoveryAgentIds: [...snapshot.terminalFailureAgentIds],
12067
+ cooldownAgentIds
12068
+ };
12069
+ }
12070
+ };
12071
+
12072
+ // src/launchPhaseTransition.ts
12073
+ var LAUNCH_RUNTIME_READINESS_TRANSITION_SPAN = "launch_runtime_readiness_transition";
12074
+ function launchReadinessNegativeEvidence(identity) {
12075
+ return identity.agent_launch_id ? null : "missing_launch_id";
12076
+ }
12077
+ function buildLaunchReadinessEnterAttrs(state) {
12078
+ return {
12079
+ ...state.identity,
12080
+ phase: "runtime_readiness",
12081
+ span_name: LAUNCH_RUNTIME_READINESS_TRANSITION_SPAN,
12082
+ transition_kind: "enter",
12083
+ phase_result: "entered",
12084
+ state: "awaiting_runtime_ready",
12085
+ state_instance_id: state.stateInstanceId,
12086
+ transition_seq: state.enterSeq,
12087
+ is_wait_state: true,
12088
+ fence_kind: state.fenceKind,
12089
+ deadline_unix_ms: state.deadlineUnixMs ?? void 0,
12090
+ negative_evidence_bucket: state.negativeEvidenceBucket ?? void 0
12091
+ };
12092
+ }
12093
+ function buildLaunchReadinessCloseAttrs(state, closeResult, closeSeq) {
12094
+ return {
12095
+ ...state.identity,
12096
+ phase: "runtime_readiness",
12097
+ span_name: LAUNCH_RUNTIME_READINESS_TRANSITION_SPAN,
12098
+ transition_kind: "close",
12099
+ state: "awaiting_runtime_ready",
12100
+ state_instance_id: state.stateInstanceId,
12101
+ transition_seq: closeSeq,
12102
+ close_result: closeResult,
12103
+ negative_evidence_bucket: state.negativeEvidenceBucket ?? void 0
12104
+ };
12105
+ }
12106
+ var LAUNCH_ACTIVATION_DELIVERY_TRANSITION_SPAN = "launch_activation_delivery_transition";
12107
+ function buildLaunchActivationEnterAttrs(state) {
12108
+ return {
12109
+ ...state.identity,
12110
+ phase: "activation_delivery",
12111
+ span_name: LAUNCH_ACTIVATION_DELIVERY_TRANSITION_SPAN,
12112
+ transition_kind: "enter",
12113
+ phase_result: "entered",
12114
+ state: "awaiting_activation_delivery",
12115
+ state_instance_id: state.stateInstanceId,
12116
+ transition_seq: state.enterSeq,
12117
+ // Activation delivery has no independent fence yet — the launch's phase-5
12118
+ // readiness wait (fenced by the startup timeout) is the upstream deadline.
12119
+ // A stuck activation (session never ready-for-delivery) surfaces as an open
12120
+ // row, not a fenced one.
12121
+ is_wait_state: true,
12122
+ fence_kind: "none",
12123
+ negative_evidence_bucket: state.negativeEvidenceBucket ?? void 0
12124
+ };
12125
+ }
12126
+ function buildLaunchActivationCloseAttrs(state, closeResult, closeSeq, deliveredVia) {
12127
+ return {
12128
+ ...state.identity,
12129
+ phase: "activation_delivery",
12130
+ span_name: LAUNCH_ACTIVATION_DELIVERY_TRANSITION_SPAN,
12131
+ transition_kind: "close",
12132
+ state: "awaiting_activation_delivery",
12133
+ state_instance_id: state.stateInstanceId,
12134
+ transition_seq: closeSeq,
12135
+ close_result: closeResult,
12136
+ delivered_via: deliveredVia ?? void 0,
12137
+ negative_evidence_bucket: state.negativeEvidenceBucket ?? void 0
12138
+ };
12139
+ }
12140
+
11609
12141
  // src/agentVisibleDeliveryLedger.ts
11610
12142
  function getMessageShortId(messageId2) {
11611
12143
  return messageId2.startsWith("thread-") ? messageId2.slice(7) : messageId2.slice(0, 8);
@@ -12954,7 +13486,9 @@ Do not copy these answers verbatim.
12954
13486
 
12955
13487
  ## FAQ 15: How do I create agents or channels?
12956
13488
  ### Answer idea
12957
- - When the owner agrees to a new agent or channel, **post an action card** with \`raft action prepare\`. The card lives inline in chat; the owner clicks the action button, the matching create dialog opens prefilled with your values (editable), and the resource is created under their identity when they submit.
13489
+ - If you have \`channel:create\` scope and your server role has channel-management authority, create channels directly with \`raft channel create --name <name>\` (add \`--private\` for private channels). This creates the channel under your agent identity and joins you to it.
13490
+ - If you also have the matching channel-management scopes and authority, edit regular channels with \`raft channel update --target "#channel-name" --name "#new-name"\`, add humans or agents with \`raft channel add-member --target "#channel-name" --user @alice\` or \`--agent @scout\`, and remove them with \`raft channel remove-member --target "#channel-name" --user @alice\` or \`--agent @scout\`. Adding members is the direct follow-up for private channels you create under your agent identity.
13491
+ - When a human should review/commit the action, or when creating a new agent, **post an action card** with \`raft action prepare\`. The card lives inline in chat; the owner clicks the action button, the matching create dialog opens prefilled with your values (editable), and the resource is created under their identity when they submit.
12958
13492
  - v1 supports three action types via \`raft action prepare --target '<channel>' <<'SLOCKACTION' { ... } SLOCKACTION\`:
12959
13493
  - \`{type: "channel:create", name, visibility: "public" | "private", description?, initialHumans?: ["@alice"], initialAgents?: ["@scout"], draftHint?}\`
12960
13494
  - \`{type: "agent:create", name, description?, suggestedComputer?, requiredComputer?, draftHint?}\` \u2014 runtime / model / reasoning effort are the owner's call. Use \`requiredComputer\` only when the owner explicitly says the new agent must run on that computer; use \`suggestedComputer\` for a soft preference.
@@ -12964,12 +13498,12 @@ Do not copy these answers verbatim.
12964
13498
  - Manual fallback (only when the owner explicitly wants to do it themselves or asks how to repeat it): the + buttons in the Agents and Channels sidebar sections. Lead with the action card; mention the + button only on request.
12965
13499
 
12966
13500
  ### Next step
12967
- - Prefill the values you have, post the action card with a short \`draftHint\` explaining why these values, and tell the owner: "click the button on the card to review and commit." Then propose the first task to send once the card flips to Done.
13501
+ - For direct channel creation, name the channel, create it, add needed members if requested/appropriate, then post the first useful update there. For human-committed actions, prefill the values you have, post the action card with a short \`draftHint\` explaining why these values, and tell the owner: "click the button on the card to review and commit." Then propose the first task to send once the card flips to Done.
12968
13502
 
12969
13503
  ### Guardrail
12970
- - Do not imply you already created agents or channels unless the card state is \`executed\`.
13504
+ - Do not imply you created or edited a channel unless the corresponding \`raft channel create\` / \`raft channel update\` command succeeded. Do not imply you added or removed a channel member unless the corresponding member command succeeded. Do not imply you created an agent or a human-committed channel unless the card state is \`executed\`.
12971
13505
  - Do not prefill runtime / model / reasoning effort on \`agent:create\`. Computer placement is only allowed as the structured \`suggestedComputer\` / \`requiredComputer\` field when the owner's request includes that placement; never rely on \`draftHint\` for a computer constraint.
12972
- - If the action type the user wants is not yet supported (e.g. \`channel:add_member\`), say so plainly and offer the manual UI path; do not invent action types the schema does not accept.
13506
+ - If the action type or direct CLI command the user wants is not yet supported, say so plainly and offer the manual UI path; do not invent action types the schema does not accept.
12973
13507
  `;
12974
13508
  }
12975
13509
  function buildOnboardingSeedFiles() {
@@ -13538,7 +14072,10 @@ var AgentProcessManager = class _AgentProcessManager {
13538
14072
  }
13539
14073
  agentStarts;
13540
14074
  startingInboxes = new AgentStartPendingDeliveryBuffer();
14075
+ /** Monotonic ordering counter for launch phase-5/6 exported rows (audit only, not a pairing key). */
14076
+ launchTransitionSeq = 0;
13541
14077
  terminalRuntimeFailures = /* @__PURE__ */ new Map();
14078
+ noProcessResidencyTransitions = new AgentNoProcessResidencyTransitions();
13542
14079
  runtimeErrorFingerprintFences = /* @__PURE__ */ new Map();
13543
14080
  pendingStartRebinds = /* @__PURE__ */ new Map();
13544
14081
  /** Cached configs for agents whose process exited normally — enables auto-restart on next message */
@@ -13618,13 +14155,26 @@ var AgentProcessManager = class _AgentProcessManager {
13618
14155
  this.cliTransportTraceDir = traceDir;
13619
14156
  }
13620
14157
  assertStartPendingDeliveryInvariants(context) {
14158
+ const residencySnapshot = this.noProcessResidencySnapshot();
14159
+ AgentNoProcessResidency.assertInvariants(context, residencySnapshot);
14160
+ this.startingInboxes.assertInvariants(
14161
+ context,
14162
+ AgentNoProcessResidency.allowedStartPendingSnapshot(residencySnapshot)
14163
+ );
14164
+ }
14165
+ noProcessResidencySnapshot() {
13621
14166
  const startSnapshot = this.agentStarts.snapshot();
13622
- this.startingInboxes.assertInvariants(context, {
14167
+ const now = this.clockNow();
14168
+ return {
14169
+ runningAgentIds: [...this.agents.keys()],
13623
14170
  queuedAgentIds: startSnapshot.queuedAgentIds,
13624
14171
  startingAgentIds: startSnapshot.startingAgentIds,
13625
- terminalRecoveryAgentIds: [...this.terminalRuntimeFailures.keys()],
13626
- cooldownAgentIds: [...this.agentSpawnFailBackoff.keys()]
13627
- });
14172
+ idleAgentIds: [...this.idleAgentConfigs.keys()],
14173
+ terminalFailureAgentIds: [...this.terminalRuntimeFailures.keys()],
14174
+ activeCooldownAgentIds: [...this.agentSpawnFailBackoff.entries()].filter(([, state]) => state.untilMs > now).map(([agentId]) => agentId),
14175
+ fingerprintFenceAgentIds: [...this.runtimeErrorFingerprintFences.keys()],
14176
+ pendingDeliveryAgentIds: this.startingInboxes.agentIds()
14177
+ };
13628
14178
  }
13629
14179
  getVisibleBoundary(agentId, target) {
13630
14180
  return this.agentVisibleDelivery.getBoundary(agentId, target);
@@ -13682,15 +14232,17 @@ var AgentProcessManager = class _AgentProcessManager {
13682
14232
  if (s) {
13683
14233
  s.timer = null;
13684
14234
  s.untilMs = 0;
14235
+ this.closeNoProcessResidency(agentId, "timeout", { negativeEvidenceBucket: "spawn_fail_cooldown_expired" });
13685
14236
  }
13686
14237
  }, Math.max(1, state.untilMs - this.clockNow()));
13687
14238
  return { backoffActive: true, attempts: state.attempts, untilMs: state.untilMs };
13688
14239
  }
13689
- resetSpawnFailBackoff(agentId) {
14240
+ resetSpawnFailBackoff(agentId, closeResult = "advanced") {
13690
14241
  const state = this.agentSpawnFailBackoff.get(agentId);
13691
14242
  if (!state) return;
13692
14243
  if (state.timer) clearTimeout(state.timer);
13693
14244
  this.agentSpawnFailBackoff.delete(agentId);
14245
+ this.closeNoProcessResidency(agentId, closeResult, { negativeEvidenceBucket: "spawn_fail_cooldown_reset" });
13694
14246
  }
13695
14247
  // ----- RUNTIME-ERROR FINGERPRINT FENCE (per-agent) ---------------------
13696
14248
  // The delivery backoff above is scoped to AgentProcess and is cleared when a
@@ -14223,19 +14775,19 @@ var AgentProcessManager = class _AgentProcessManager {
14223
14775
  if (input.decision !== "local_hold" && input.decision !== "syncing_hold") return;
14224
14776
  const ap = this.agents.get(agentId);
14225
14777
  const messageCount = input.decision === "syncing_hold" ? input.heldMessageCount ?? input.pendingCount ?? 0 : input.pendingCount ?? input.heldMessageCount ?? 0;
14226
- const entry = projectApmHeldFreshnessActivity({
14778
+ const activity = projectApmHeldFreshnessActivity({
14227
14779
  producerFactId,
14228
14780
  action: input.action,
14229
14781
  decision: input.decision,
14230
14782
  target: input.target,
14231
14783
  messageCount
14232
- }).entry;
14784
+ });
14233
14785
  this.sendToServer({
14234
14786
  type: "agent:activity",
14235
14787
  agentId,
14236
- activity: ap?.lastActivity || "online",
14237
- detail: ap?.lastActivityDetail || "",
14238
- entries: [entry],
14788
+ activity: activity.statusEntry.activity,
14789
+ detail: activity.statusEntry.detail,
14790
+ entries: activity.entries,
14239
14791
  launchId: ap?.launchId || void 0,
14240
14792
  clientSeq: ap ? this.nextActivityClientSeq(agentId) : void 0
14241
14793
  });
@@ -14283,6 +14835,64 @@ var AgentProcessManager = class _AgentProcessManager {
14283
14835
  });
14284
14836
  span.end(status);
14285
14837
  }
14838
+ emitNoProcessResidencyRows(rows) {
14839
+ for (const row of rows) {
14840
+ this.recordDaemonTrace("launch_residency_transition", row);
14841
+ }
14842
+ }
14843
+ noProcessResidencyIdentity(agentId, config, launchId, launchSource, driverId) {
14844
+ const runtimeContext = config.runtimeContext;
14845
+ const agentLaunchIdPresent = typeof launchId === "string" && launchId.length > 0;
14846
+ return {
14847
+ agentId,
14848
+ agentLaunchId: agentLaunchIdPresent ? launchId : "missing_launch_id",
14849
+ agentLaunchIdPresent,
14850
+ serverId: runtimeContext?.serverId || "unknown_server",
14851
+ machineId: runtimeContext?.machineId || "unknown_machine",
14852
+ runtime: config.runtime || "unknown_runtime",
14853
+ driver: driverId || this.driverResolver(config.runtime || "claude").id,
14854
+ launchSource
14855
+ };
14856
+ }
14857
+ enterNoProcessResidency(state, identity, opts) {
14858
+ const launchEvidence = identity.agentLaunchIdPresent ? {} : {
14859
+ failureKind: opts.failureKind ?? "missing_launch_id",
14860
+ negativeEvidenceBucket: opts.negativeEvidenceBucket ?? "missing_launch_id"
14861
+ };
14862
+ this.emitNoProcessResidencyRows(this.noProcessResidencyTransitions.enter({
14863
+ ...identity,
14864
+ state,
14865
+ ...opts,
14866
+ ...launchEvidence
14867
+ }));
14868
+ }
14869
+ closeNoProcessResidency(agentId, closeResult, opts = {}) {
14870
+ this.emitNoProcessResidencyRows(this.noProcessResidencyTransitions.close(agentId, {
14871
+ closeResult,
14872
+ failureKind: opts.failureKind,
14873
+ negativeEvidenceBucket: opts.negativeEvidenceBucket
14874
+ }));
14875
+ }
14876
+ startLaunchSource(config, wakeMessage, resumePrompt) {
14877
+ if (config.runtimeProfileControl && !wakeMessage) return "runtime_profile";
14878
+ if (config.sessionId || resumePrompt) return "session_resume";
14879
+ if (wakeMessage) return "wake_message";
14880
+ return "explicit_start";
14881
+ }
14882
+ enterSpawnFailCooldownResidency(agentId, cached, untilMs, source, reason) {
14883
+ if (untilMs <= this.clockNow()) return;
14884
+ this.enterNoProcessResidency(
14885
+ "spawn_fail_cooldown",
14886
+ this.noProcessResidencyIdentity(agentId, cached.config, cached.launchId, source),
14887
+ {
14888
+ isWaitState: true,
14889
+ fenceKind: "spawn_fail_backoff",
14890
+ deadlineUnixMs: untilMs,
14891
+ failureKind: reason,
14892
+ negativeEvidenceBucket: reason
14893
+ }
14894
+ );
14895
+ }
14286
14896
  processLifecycleIdentityAttrs(agentId, ap) {
14287
14897
  const runtimeContext = ap.config.runtimeContext;
14288
14898
  return {
@@ -14510,6 +15120,15 @@ var AgentProcessManager = class _AgentProcessManager {
14510
15120
  this.agentStarts.enqueue(item);
14511
15121
  this.recordDaemonTrace("daemon.agent.start.queued", this.startQueueTraceAttrs(agentId, config, wakeMessage, unreadSummary, resumePrompt, launchId, wakeMessageTransient));
14512
15122
  const startSnapshot = this.agentStarts.snapshot();
15123
+ this.enterNoProcessResidency(
15124
+ "queued_start",
15125
+ this.noProcessResidencyIdentity(agentId, config, launchId, this.startLaunchSource(config, wakeMessage, resumePrompt)),
15126
+ {
15127
+ isWaitState: true,
15128
+ fenceKind: "start_scheduler",
15129
+ deadlineUnixMs: this.clockNow() + Math.max(1, startSnapshot.minStartIntervalMs)
15130
+ }
15131
+ );
14513
15132
  logger.info(
14514
15133
  `[Agent ${agentId}] Start queued (queue=${startSnapshot.queueDepth}, active=${startSnapshot.activeStarts}, max=${startSnapshot.maxConcurrentStarts}, interval=${startSnapshot.minStartIntervalMs}ms)`
14515
15134
  );
@@ -14532,6 +15151,7 @@ var AgentProcessManager = class _AgentProcessManager {
14532
15151
  if (dequeued.kind === "empty") return;
14533
15152
  if (dequeued.kind === "stale") {
14534
15153
  const { item: item2 } = dequeued;
15154
+ this.closeNoProcessResidency(item2.agentId, "suppressed", { negativeEvidenceBucket: "stale_queue_item" });
14535
15155
  this.recordDaemonTrace("daemon.agent.start.skipped", {
14536
15156
  ...this.startQueueTraceAttrs(item2.agentId, item2.config, item2.wakeMessage, item2.unreadSummary, item2.resumePrompt, item2.launchId, item2.wakeMessageTransient),
14537
15157
  reason: "stale_queue_item"
@@ -14541,6 +15161,7 @@ var AgentProcessManager = class _AgentProcessManager {
14541
15161
  }
14542
15162
  const { item } = dequeued;
14543
15163
  if (this.agents.has(item.agentId) || this.agentStarts.hasStarting(item.agentId)) {
15164
+ this.closeNoProcessResidency(item.agentId, "suppressed", { negativeEvidenceBucket: "already_running_or_starting" });
14544
15165
  this.recordDaemonTrace("daemon.agent.start.skipped", {
14545
15166
  ...this.startQueueTraceAttrs(item.agentId, item.config, item.wakeMessage, item.unreadSummary, item.resumePrompt, item.launchId, item.wakeMessageTransient),
14546
15167
  reason: "already_running_or_starting"
@@ -14556,6 +15177,15 @@ var AgentProcessManager = class _AgentProcessManager {
14556
15177
  return;
14557
15178
  }
14558
15179
  this.agentStarts.claimStartSlot(item.agentId);
15180
+ this.enterNoProcessResidency(
15181
+ "starting_process",
15182
+ this.noProcessResidencyIdentity(item.agentId, item.config, item.launchId, this.startLaunchSource(item.config, item.wakeMessage, item.resumePrompt)),
15183
+ {
15184
+ isWaitState: true,
15185
+ fenceKind: "runtime_start_timeout",
15186
+ deadlineUnixMs: this.clockNow() + runtimeStartTimeoutMs()
15187
+ }
15188
+ );
14559
15189
  const startSnapshot = this.agentStarts.snapshot();
14560
15190
  logger.info(
14561
15191
  `[Agent ${item.agentId}] Dequeued start (remaining=${startSnapshot.queueDepth}, active=${startSnapshot.activeStarts})`
@@ -14595,6 +15225,7 @@ var AgentProcessManager = class _AgentProcessManager {
14595
15225
  cancelQueuedAgentStart(agentId, reason) {
14596
15226
  const item = this.agentStarts.cancelQueued(agentId);
14597
15227
  if (!item) return false;
15228
+ this.closeNoProcessResidency(agentId, "suppressed", { negativeEvidenceBucket: "start_cancelled" });
14598
15229
  this.startingInboxes.cancelStart(agentId);
14599
15230
  this.assertStartPendingDeliveryInvariants("cancel-queued-start");
14600
15231
  this.recordDaemonTrace("daemon.agent.start.cancelled", {
@@ -14607,6 +15238,7 @@ var AgentProcessManager = class _AgentProcessManager {
14607
15238
  }
14608
15239
  cancelAllQueuedAgentStarts(reason) {
14609
15240
  const cancelled = this.agentStarts.cancelAllQueued((item) => {
15241
+ this.closeNoProcessResidency(item.agentId, "suppressed", { negativeEvidenceBucket: "start_cancelled" });
14610
15242
  this.recordDaemonTrace("daemon.agent.start.cancelled", {
14611
15243
  ...this.startQueueTraceAttrs(item.agentId, item.config, item.wakeMessage, item.unreadSummary, item.resumePrompt, item.launchId, item.wakeMessageTransient),
14612
15244
  reason
@@ -14687,6 +15319,15 @@ var AgentProcessManager = class _AgentProcessManager {
14687
15319
  wakeMessageTransient = pendingStartRebind.wakeMessageTransient === true;
14688
15320
  }
14689
15321
  }
15322
+ this.enterNoProcessResidency(
15323
+ "starting_process",
15324
+ this.noProcessResidencyIdentity(agentId, config, launchId, this.startLaunchSource(config, wakeMessage, resumePrompt)),
15325
+ {
15326
+ isWaitState: true,
15327
+ fenceKind: "runtime_start_timeout",
15328
+ deadlineUnixMs: this.clockNow() + runtimeStartTimeoutMs()
15329
+ }
15330
+ );
14690
15331
  this.recordDaemonTrace("daemon.agent.spawn.started", this.startQueueTraceAttrs(agentId, config, wakeMessage, unreadSummary, resumePrompt, launchId, wakeMessageTransient));
14691
15332
  const driver = this.driverResolver(config.runtime || "claude");
14692
15333
  const legacyWakeRuntimeProfile = wakeMessage ? runtimeProfileNotificationFromMessage(wakeMessage) : null;
@@ -14795,6 +15436,7 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
14795
15436
  if (canDeferEmptyStart) {
14796
15437
  const pendingMessages = this.startingInboxes.drainOnSpawn(agentId);
14797
15438
  this.agentStarts.clearStarting(agentId);
15439
+ this.closeNoProcessResidency(agentId, "suppressed", { negativeEvidenceBucket: "defer_until_concrete_message" });
14798
15440
  this.assertStartPendingDeliveryInvariants("defer-empty-start-drain");
14799
15441
  this.idleAgentConfigs.set(agentId, {
14800
15442
  config: this.buildRestartSafeConfig(runtimeConfig, runtimeConfig.sessionId || null),
@@ -14838,7 +15480,7 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
14838
15480
  };
14839
15481
  const initialSessionId = this.initialAgentProcessSessionId(driver, liveProcessConfig);
14840
15482
  const restartSessionId = initialSessionId || (driver.requiresSessionInitForDelivery ? liveProcessConfig.sessionId || null : null);
14841
- const processInstanceId = randomUUID5();
15483
+ const processInstanceId = randomUUID6();
14842
15484
  agentProcess = {
14843
15485
  runtime,
14844
15486
  driver,
@@ -14854,6 +15496,9 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
14854
15496
  activityHeartbeat: null,
14855
15497
  startupTimeoutTimer: null,
14856
15498
  startupReadinessSatisfied: false,
15499
+ readinessTransition: null,
15500
+ activationTransition: null,
15501
+ initialActivationDelivered: false,
14857
15502
  compactionWatchdog: null,
14858
15503
  compactionStartedAt: null,
14859
15504
  runtimeProgress: new RuntimeProgressState(Date.now()),
@@ -14879,7 +15524,6 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
14879
15524
  gatedSteering: createGatedSteeringState()
14880
15525
  };
14881
15526
  this.startingInboxes.drainOnSpawn(agentId);
14882
- this.assertStartPendingDeliveryInvariants("spawn-drain");
14883
15527
  this.agents.set(agentId, agentProcess);
14884
15528
  this.idleAgentConfigs.set(agentId, {
14885
15529
  config: this.buildRestartSafeConfig(runtimeConfig, restartSessionId),
@@ -15004,6 +15648,8 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
15004
15648
  if (ap.activityHeartbeat) {
15005
15649
  clearInterval(ap.activityHeartbeat);
15006
15650
  }
15651
+ this.closeRuntimeReadinessTransition(ap, "terminal");
15652
+ this.closeActivationTransition(ap, "terminal");
15007
15653
  this.clearRuntimeStartupTimeout(ap);
15008
15654
  this.clearStalledRecoverySigtermWatchdog(ap);
15009
15655
  const finalCode = ap.exitCode ?? code;
@@ -15096,6 +15742,24 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
15096
15742
  this.startAgent(agentId, nextConfig, queuedWakeMessage, unreadSummary2, void 0, ap.launchId || void 0).catch((err) => {
15097
15743
  logger.error(`[Agent ${agentId}] Failed to continue with queued message`, err);
15098
15744
  if (this.reportRunnerCredentialMintFailure(agentId, err, ap.launchId, "queued_continuation")) {
15745
+ this.idleAgentConfigs.set(agentId, {
15746
+ config: nextConfig,
15747
+ sessionId: ap.sessionId,
15748
+ launchId: ap.launchId
15749
+ });
15750
+ const report = this.recordSpawnFailure(agentId, "runner_credential_mint");
15751
+ this.assertStartPendingDeliveryInvariants("queued-continuation-runner-credential-mint-failure");
15752
+ if (report.backoffActive) {
15753
+ this.enterSpawnFailCooldownResidency(agentId, { config: nextConfig, launchId: ap.launchId }, report.untilMs, "queued_continuation", "runner_credential_mint");
15754
+ }
15755
+ this.recordDaemonTrace("daemon.agent.spawn.fail_backoff", {
15756
+ agentId,
15757
+ source: "queued_continuation",
15758
+ reason: "runner_credential_mint",
15759
+ attempts: report.attempts,
15760
+ cooldown_active: report.backoffActive,
15761
+ until_ms: report.untilMs
15762
+ });
15099
15763
  return;
15100
15764
  }
15101
15765
  this.idleAgentConfigs.set(agentId, {
@@ -15170,7 +15834,11 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
15170
15834
  }, "error");
15171
15835
  throw new Error(`Runtime session failed to start: ${startResult.reason}${startResult.error ? ` (${startResult.error})` : ""}`);
15172
15836
  }
15173
- this.terminalRuntimeFailures.delete(agentId);
15837
+ this.closeNoProcessResidency(agentId, "advanced");
15838
+ if (this.terminalRuntimeFailures.delete(agentId)) {
15839
+ this.closeNoProcessResidency(agentId, "advanced", { negativeEvidenceBucket: "terminal_recovery_start_succeeded" });
15840
+ }
15841
+ this.assertStartPendingDeliveryInvariants("spawn-drain");
15174
15842
  this.recordDaemonTrace("daemon.agent.spawn.created", {
15175
15843
  ...this.startQueueTraceAttrs(agentId, effectiveConfig, wakeMessage, unreadSummary, resumePrompt, agentProcess.launchId || void 0, wakeMessageTransient),
15176
15844
  detached: false,
@@ -15192,9 +15860,16 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
15192
15860
  this.sendToServer({ type: "agent:session", agentId, sessionId: agentProcess.sessionId, launchId: agentProcess.launchId || void 0 });
15193
15861
  }
15194
15862
  this.broadcastActivity(agentId, "working", "Starting\u2026");
15195
- this.startRuntimeStartupTimeout(agentId, agentProcess);
15863
+ this.startRuntimeStartupTimeout(agentId, agentProcess, startCause);
15864
+ if (wakeMessage || startingInboxMessages.length > 0) {
15865
+ this.openActivationTransition(agentId, agentProcess, startCause);
15866
+ if (wakeMessageDeliveredAsInboxUpdate || startingInboxDeliveredAsInput) {
15867
+ this.closeActivationTransition(agentProcess, "advanced", "spawn_prompt");
15868
+ }
15869
+ }
15196
15870
  } catch (err) {
15197
15871
  this.agentStarts.clearStarting(agentId);
15872
+ this.closeNoProcessResidency(agentId, "terminal", { negativeEvidenceBucket: "runtime_start_failed" });
15198
15873
  this.pendingStartRebinds.delete(agentId);
15199
15874
  this.cleanupFailedRuntimeStart(agentId, agentProcess, err);
15200
15875
  throw err;
@@ -15216,6 +15891,8 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
15216
15891
  clearTimeout(ap.compactionWatchdog);
15217
15892
  ap.compactionWatchdog = null;
15218
15893
  }
15894
+ this.closeRuntimeReadinessTransition(ap, "terminal");
15895
+ this.closeActivationTransition(ap, "terminal");
15219
15896
  this.clearRuntimeStartupTimeout(ap);
15220
15897
  this.clearStalledRecoverySigtermWatchdog(ap);
15221
15898
  this.endRuntimeTrace(ap, "error", {
@@ -15228,7 +15905,9 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
15228
15905
  this.revokeManagedRunnerCredential(agentId, ap.config, ap.launchId);
15229
15906
  this.agents.delete(agentId);
15230
15907
  this.idleAgentConfigs.delete(agentId);
15231
- this.terminalRuntimeFailures.delete(agentId);
15908
+ if (this.terminalRuntimeFailures.delete(agentId)) {
15909
+ this.closeNoProcessResidency(agentId, "terminal", { negativeEvidenceBucket: "runtime_start_failed" });
15910
+ }
15232
15911
  }
15233
15912
  cleanupTerminalRuntimeFailure(agentId, ap, detail) {
15234
15913
  if (this.agents.get(agentId) !== ap) return;
@@ -15243,6 +15922,8 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
15243
15922
  ap.activityHeartbeat = null;
15244
15923
  }
15245
15924
  this.clearCompactionWatchdog(ap);
15925
+ this.closeRuntimeReadinessTransition(ap, "terminal");
15926
+ this.closeActivationTransition(ap, "terminal");
15246
15927
  this.clearRuntimeStartupTimeout(ap);
15247
15928
  this.clearStalledRecoverySigtermWatchdog(ap);
15248
15929
  cleanupAgentCredentialProxy(agentId, ap.launchId);
@@ -15251,9 +15932,18 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
15251
15932
  if (ap.inbox.length > 0) {
15252
15933
  this.startingInboxes.bufferMessagesDuringStart(agentId, ap.inbox);
15253
15934
  }
15935
+ this.agents.delete(agentId);
15254
15936
  this.terminalRuntimeFailures.set(agentId, { detail, launchId: ap.launchId });
15937
+ this.enterNoProcessResidency(
15938
+ "terminal_runtime_error",
15939
+ this.noProcessResidencyIdentity(agentId, ap.config, ap.launchId, "terminal_runtime_error", ap.driver.id),
15940
+ {
15941
+ isWaitState: false,
15942
+ failureKind: "terminal_runtime_error",
15943
+ negativeEvidenceBucket: "terminal_runtime_error"
15944
+ }
15945
+ );
15255
15946
  this.assertStartPendingDeliveryInvariants("terminal-runtime-failure-cleanup");
15256
- this.agents.delete(agentId);
15257
15947
  const diagnostics = buildRuntimeErrorDiagnosticEnvelope(detail);
15258
15948
  this.recordDaemonTrace("daemon.agent.terminal_runtime_error.cleanup", {
15259
15949
  agentId,
@@ -15517,7 +16207,9 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
15517
16207
  this.cancelQueuedAgentStart(agentId, "stop requested");
15518
16208
  this.pendingStartRebinds.delete(agentId);
15519
16209
  this.idleAgentConfigs.delete(agentId);
15520
- this.terminalRuntimeFailures.delete(agentId);
16210
+ if (this.terminalRuntimeFailures.delete(agentId)) {
16211
+ this.closeNoProcessResidency(agentId, "suppressed", { negativeEvidenceBucket: "explicit_stop" });
16212
+ }
15521
16213
  const ap = this.agents.get(agentId);
15522
16214
  if (!ap) {
15523
16215
  if (!silent) {
@@ -15538,7 +16230,7 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
15538
16230
  if (!silent) {
15539
16231
  this.activityClientSeqByAgent.delete(agentId);
15540
16232
  this.agentVisibleDelivery.clearAgent(agentId);
15541
- this.resetSpawnFailBackoff(agentId);
16233
+ this.resetSpawnFailBackoff(agentId, "suppressed");
15542
16234
  this.resetRuntimeErrorFingerprintFence(agentId, "explicit_stop", ap);
15543
16235
  }
15544
16236
  this.runtimeExitTraceAttrs.set(ap.runtime, {
@@ -15676,6 +16368,7 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
15676
16368
  const state = this.agentSpawnFailBackoff.get(agentId);
15677
16369
  const startingInboxCount = this.startingInboxes.bufferDuringStart(agentId, message);
15678
16370
  this.assertStartPendingDeliveryInvariants("delivery-spawn-fail-cooldown");
16371
+ this.enterSpawnFailCooldownResidency(agentId, cached, state.untilMs, "idle_auto_restart", "spawn_fail_cooldown_active");
15679
16372
  this.recordDaemonTrace("daemon.agent.delivery.routed", this.deliveryTraceAttrs(agentId, message, {
15680
16373
  outcome: "spawn_fail_cooldown_active",
15681
16374
  accepted: true,
@@ -15702,11 +16395,17 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
15702
16395
  }));
15703
16396
  return this.startAgent(agentId, cached.config, message, void 0, void 0, cached.launchId || void 0, transientDelivery).then(() => {
15704
16397
  this.resetSpawnFailBackoff(agentId);
16398
+ this.assertStartPendingDeliveryInvariants("idle-auto-restart-success");
15705
16399
  return true;
15706
16400
  }, (err) => {
15707
16401
  logger.error(`[Agent ${agentId}] Failed to auto-restart`, err);
15708
16402
  if (this.reportRunnerCredentialMintFailure(agentId, err, cached.launchId, "idle_auto_restart")) {
16403
+ this.idleAgentConfigs.set(agentId, cached);
15709
16404
  const report2 = this.recordSpawnFailure(agentId, "runner_credential_mint");
16405
+ this.assertStartPendingDeliveryInvariants("idle-auto-restart-runner-credential-mint-failure");
16406
+ if (report2.backoffActive) {
16407
+ this.enterSpawnFailCooldownResidency(agentId, cached, report2.untilMs, "idle_auto_restart", "runner_credential_mint");
16408
+ }
15710
16409
  this.recordDaemonTrace("daemon.agent.spawn.fail_backoff", {
15711
16410
  agentId,
15712
16411
  source: "idle_auto_restart",
@@ -15719,6 +16418,10 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
15719
16418
  }
15720
16419
  this.idleAgentConfigs.set(agentId, cached);
15721
16420
  const report = this.recordSpawnFailure(agentId, "spawn_error");
16421
+ this.assertStartPendingDeliveryInvariants("idle-auto-restart-spawn-failure");
16422
+ if (report.backoffActive) {
16423
+ this.enterSpawnFailCooldownResidency(agentId, cached, report.untilMs, "idle_auto_restart", "spawn_error");
16424
+ }
15722
16425
  this.recordDaemonTrace("daemon.agent.spawn.fail_backoff", {
15723
16426
  agentId,
15724
16427
  source: "idle_auto_restart",
@@ -16336,6 +17039,7 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
16336
17039
  logger.info(`[Agent ${agentId}] Starting from idle state for runtime profile ${kind} ${key}`);
16337
17040
  if (this.isSpawnFailBackoffActive(agentId)) {
16338
17041
  const state = this.agentSpawnFailBackoff.get(agentId);
17042
+ this.enterSpawnFailCooldownResidency(agentId, cached, state.untilMs, "runtime_profile_auto_restart", "spawn_fail_cooldown_active");
16339
17043
  span.end("ok", {
16340
17044
  attrs: {
16341
17045
  outcome: "spawn_fail_cooldown_active",
@@ -16350,11 +17054,17 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
16350
17054
  this.idleAgentConfigs.delete(agentId);
16351
17055
  return this.startAgent(agentId, cached.config, message, void 0, void 0, cached.launchId || void 0).then(() => {
16352
17056
  this.resetSpawnFailBackoff(agentId);
17057
+ this.assertStartPendingDeliveryInvariants("runtime-profile-auto-restart-success");
16353
17058
  return true;
16354
17059
  }, (err) => {
16355
17060
  logger.error(`[Agent ${agentId}] Failed to auto-restart for runtime profile notification`, err);
16356
17061
  if (this.reportRunnerCredentialMintFailure(agentId, err, cached.launchId, "runtime_profile_auto_restart")) {
17062
+ this.idleAgentConfigs.set(agentId, cached);
16357
17063
  const report2 = this.recordSpawnFailure(agentId, "runner_credential_mint");
17064
+ this.assertStartPendingDeliveryInvariants("runtime-profile-auto-restart-runner-credential-mint-failure");
17065
+ if (report2.backoffActive) {
17066
+ this.enterSpawnFailCooldownResidency(agentId, cached, report2.untilMs, "runtime_profile_auto_restart", "runner_credential_mint");
17067
+ }
16358
17068
  this.recordDaemonTrace("daemon.agent.spawn.fail_backoff", {
16359
17069
  agentId,
16360
17070
  source: "runtime_profile_auto_restart",
@@ -16374,6 +17084,10 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
16374
17084
  }
16375
17085
  this.idleAgentConfigs.set(agentId, cached);
16376
17086
  const report = this.recordSpawnFailure(agentId, "spawn_error");
17087
+ this.assertStartPendingDeliveryInvariants("runtime-profile-auto-restart-spawn-failure");
17088
+ if (report.backoffActive) {
17089
+ this.enterSpawnFailCooldownResidency(agentId, cached, report.untilMs, "runtime_profile_auto_restart", "spawn_error");
17090
+ }
16377
17091
  this.recordDaemonTrace("daemon.agent.spawn.fail_backoff", {
16378
17092
  agentId,
16379
17093
  source: "runtime_profile_auto_restart",
@@ -16677,7 +17391,7 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
16677
17391
  const gzipped = gzipSync(raw);
16678
17392
  const bundleSha256 = createHash3("sha256").update(gzipped).digest("hex");
16679
17393
  const bundleSizeBytes = gzipped.byteLength;
16680
- const bundleId = randomUUID5();
17394
+ const bundleId = randomUUID6();
16681
17395
  const uploadResult = await uploadWithSignedCapability({
16682
17396
  serverUrl: this.serverUrl,
16683
17397
  apiKey: this.daemonApiKey,
@@ -17458,9 +18172,100 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
17458
18172
  }
17459
18173
  return true;
17460
18174
  }
17461
- startRuntimeStartupTimeout(agentId, ap) {
18175
+ launchIdentityAttrs(agentId, ap, launchSource) {
18176
+ const runtimeContext = ap.config.runtimeContext;
18177
+ return {
18178
+ agent_launch_id: ap.launchId ?? null,
18179
+ agent_id: agentId,
18180
+ server_id: runtimeContext?.serverId ?? null,
18181
+ machine_id: runtimeContext?.machineId ?? null,
18182
+ runtime: ap.config.runtime,
18183
+ driver: ap.driver.id,
18184
+ launch_source: launchSource
18185
+ };
18186
+ }
18187
+ /**
18188
+ * Phase-5 exported-row ENTER: opens the runtime-readiness wait row (task
18189
+ * #149). Idempotent — a second call while a row is open is a no-op so the
18190
+ * (agent_launch_id, state_instance_id) pair keeps exactly-one enter.
18191
+ */
18192
+ openRuntimeReadinessTransition(agentId, ap, launchSource, fenceKind, deadlineUnixMs) {
18193
+ if (ap.readinessTransition) return;
18194
+ const identity = this.launchIdentityAttrs(agentId, ap, launchSource);
18195
+ const state = {
18196
+ stateInstanceId: randomUUID6(),
18197
+ enterSeq: this.launchTransitionSeq++,
18198
+ identity,
18199
+ fenceKind,
18200
+ deadlineUnixMs,
18201
+ negativeEvidenceBucket: launchReadinessNegativeEvidence(identity)
18202
+ };
18203
+ ap.readinessTransition = state;
18204
+ this.recordDaemonTrace(LAUNCH_RUNTIME_READINESS_TRANSITION_SPAN, buildLaunchReadinessEnterAttrs(state));
18205
+ }
18206
+ /**
18207
+ * Phase-5 exported-row CLOSE: closes the open runtime-readiness wait row with
18208
+ * a closed `close_result` (task #149). Idempotent — no-op when no row is open,
18209
+ * so overlapping close paths (ready event, timeout fire, process exit,
18210
+ * cleanup) emit exactly one close.
18211
+ */
18212
+ closeRuntimeReadinessTransition(ap, closeResult) {
18213
+ const state = ap.readinessTransition;
18214
+ if (!state) return;
18215
+ ap.readinessTransition = null;
18216
+ this.recordDaemonTrace(
18217
+ LAUNCH_RUNTIME_READINESS_TRANSITION_SPAN,
18218
+ buildLaunchReadinessCloseAttrs(state, closeResult, this.launchTransitionSeq++),
18219
+ closeResult === "advanced" ? "ok" : "error"
18220
+ );
18221
+ }
18222
+ /**
18223
+ * Phase-6 exported-row ENTER: opens the activation-delivery wait row when a
18224
+ * launch carries an initial activation (wake / buffered inbox) not yet
18225
+ * delivered (task #149). Idempotent + only opens when there is something to
18226
+ * deliver, so explicit starts with no activation produce no phase-6 row.
18227
+ */
18228
+ openActivationTransition(agentId, ap, launchSource) {
18229
+ if (ap.activationTransition || ap.initialActivationDelivered) return;
18230
+ const identity = this.launchIdentityAttrs(agentId, ap, launchSource);
18231
+ const state = {
18232
+ stateInstanceId: randomUUID6(),
18233
+ enterSeq: this.launchTransitionSeq++,
18234
+ identity,
18235
+ negativeEvidenceBucket: launchReadinessNegativeEvidence(identity)
18236
+ };
18237
+ ap.activationTransition = state;
18238
+ this.recordDaemonTrace(LAUNCH_ACTIVATION_DELIVERY_TRANSITION_SPAN, buildLaunchActivationEnterAttrs(state));
18239
+ }
18240
+ /**
18241
+ * Phase-6 exported-row CLOSE: closes the open activation-delivery wait with a
18242
+ * closed `close_result` (+ `delivered_via` on advanced). Idempotent — no-op
18243
+ * when no row is open, so overlapping paths (spawn-prompt, first stdin,
18244
+ * process exit, cleanup) emit exactly one close. Marks the initial activation
18245
+ * delivered on `advanced` so later normal deliveries are not re-counted.
18246
+ */
18247
+ closeActivationTransition(ap, closeResult, deliveredVia) {
18248
+ if (closeResult === "advanced") ap.initialActivationDelivered = true;
18249
+ const state = ap.activationTransition;
18250
+ if (!state) return;
18251
+ ap.activationTransition = null;
18252
+ this.recordDaemonTrace(
18253
+ LAUNCH_ACTIVATION_DELIVERY_TRANSITION_SPAN,
18254
+ buildLaunchActivationCloseAttrs(state, closeResult, this.launchTransitionSeq++, deliveredVia),
18255
+ closeResult === "advanced" ? "ok" : "error"
18256
+ );
18257
+ }
18258
+ startRuntimeStartupTimeout(agentId, ap, launchSource) {
17462
18259
  const timeoutMs = runtimeStartTimeoutMs();
17463
- if (timeoutMs <= 0) return;
18260
+ const fenced = timeoutMs > 0;
18261
+ this.openRuntimeReadinessTransition(
18262
+ agentId,
18263
+ ap,
18264
+ launchSource,
18265
+ fenced ? "runtime_startup_timeout" : "none",
18266
+ fenced ? Date.now() + timeoutMs : null
18267
+ );
18268
+ if (!fenced) return;
17464
18269
  ap.startupTimeoutTimer = setTimeout(() => {
17465
18270
  this.handleRuntimeStartupTimeout(agentId, ap, timeoutMs);
17466
18271
  }, timeoutMs);
@@ -17487,6 +18292,7 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
17487
18292
  this.clearRuntimeStartupTimeout(ap);
17488
18293
  return;
17489
18294
  }
18295
+ this.closeRuntimeReadinessTransition(ap, "timeout");
17490
18296
  this.clearRuntimeStartupTimeout(ap);
17491
18297
  this.commitGatedSteeringDecisionState(agentId, ap, reduction.nextState);
17492
18298
  const terminalFailureDetail = classifyTerminalFailure(ap);
@@ -17524,6 +18330,8 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
17524
18330
  handleRuntimeStartupRequestError(agentId, ap, event) {
17525
18331
  const current = this.agents.get(agentId);
17526
18332
  if (current !== ap) return;
18333
+ this.closeRuntimeReadinessTransition(ap, "terminal");
18334
+ this.closeActivationTransition(ap, "terminal");
17527
18335
  this.clearRuntimeStartupTimeout(ap);
17528
18336
  this.interruptCompactionIfActive(agentId);
17529
18337
  this.interruptReviewIfActive(agentId);
@@ -17727,6 +18535,7 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
17727
18535
  const wasStalled = ap.runtimeProgress.isStale;
17728
18536
  if (this.runtimeStartupReadinessSatisfiedByEvent(ap, event)) {
17729
18537
  ap.startupReadinessSatisfied = true;
18538
+ this.closeRuntimeReadinessTransition(ap, "advanced");
17730
18539
  this.clearRuntimeStartupTimeout(ap);
17731
18540
  }
17732
18541
  this.noteRuntimeTraceCounter(ap, event);
@@ -18443,6 +19252,7 @@ ${formatAgentInboxDelta(inboxRows, { totalPendingMessages: inboxCount })}]`;
18443
19252
  cursors_advanced: "none"
18444
19253
  });
18445
19254
  ap.notifications.recordNoticeWritten(computeInboxNoticeFingerprint(messages), ap.sessionId, messages);
19255
+ this.closeActivationTransition(ap, "advanced", "stdin");
18446
19256
  return true;
18447
19257
  }
18448
19258
  /** Deliver a message to an agent via stdin, formatting it the same way as the MCP bridge */
@@ -18548,6 +19358,7 @@ ${RESPONSE_TARGET_HINT}`);
18548
19358
  outcome: "written",
18549
19359
  stdin_write_attempted: true
18550
19360
  });
19361
+ this.closeActivationTransition(ap, "advanced", "stdin");
18551
19362
  return true;
18552
19363
  }
18553
19364
  /** List ONE level of a directory — directories returned without children (lazy-loaded on demand) */
@@ -18964,7 +19775,7 @@ var ReminderCache = class {
18964
19775
  };
18965
19776
 
18966
19777
  // src/machineLock.ts
18967
- import { createHash as createHash4, randomUUID as randomUUID6 } from "crypto";
19778
+ import { createHash as createHash4, randomUUID as randomUUID7 } from "crypto";
18968
19779
  import { mkdirSync as mkdirSync5, readFileSync as readFileSync7, rmSync as rmSync3, statSync as statSync2, writeFileSync as writeFileSync5 } from "fs";
18969
19780
  import os7 from "os";
18970
19781
  import path15 from "path";
@@ -19021,7 +19832,7 @@ function acquireDaemonMachineLock(options) {
19021
19832
  const lockId = getDaemonMachineLockId(options.apiKey);
19022
19833
  const machineDir = path15.join(rootDir, lockId);
19023
19834
  const lockDir = path15.join(machineDir, "daemon.lock");
19024
- const token = randomUUID6();
19835
+ const token = randomUUID7();
19025
19836
  mkdirSync5(machineDir, { recursive: true });
19026
19837
  for (let attempt = 0; attempt < 2; attempt += 1) {
19027
19838
  try {
@@ -19343,7 +20154,7 @@ function createTraceClient(options) {
19343
20154
  }
19344
20155
 
19345
20156
  // src/traceBundleUpload.ts
19346
- import { createHash as createHash6, randomUUID as randomUUID7 } from "crypto";
20157
+ import { createHash as createHash6, randomUUID as randomUUID8 } from "crypto";
19347
20158
  import { gzipSync as gzipSync2 } from "zlib";
19348
20159
  import { mkdir as mkdir2, readFile as readFile2, readdir as readdir3, stat as stat3, writeFile as writeFile2 } from "fs/promises";
19349
20160
  import path17 from "path";
@@ -19474,7 +20285,7 @@ var DaemonTraceBundleUploader = class {
19474
20285
  }
19475
20286
  const gzipped = gzipSync2(raw);
19476
20287
  const bundleSha256 = sha256Hex(gzipped);
19477
- const bundleId = randomUUID7();
20288
+ const bundleId = randomUUID8();
19478
20289
  await uploadWithSignedCapability({
19479
20290
  serverUrl: this.options.serverUrl,
19480
20291
  apiKey: this.options.apiKey,
@@ -19576,6 +20387,34 @@ var DAEMON_CORE_TRACE_ATTR_CONTRACTS = {
19576
20387
  "daemon.agent.spawn.failed": {
19577
20388
  spanAttrs: ["agentId", "launchId", "runtime", "model", "failure_reason", "failure_detail", "session_id_present"]
19578
20389
  },
20390
+ "launch_residency_transition": {
20391
+ spanAttrs: [
20392
+ "span_name",
20393
+ "phase",
20394
+ "agent_launch_id",
20395
+ "agent_id",
20396
+ "server_id",
20397
+ "machine_id",
20398
+ "runtime",
20399
+ "driver",
20400
+ "launch_source",
20401
+ "state_instance_id",
20402
+ "residency_state_instance_id",
20403
+ "transition_seq",
20404
+ "residency_transition_seq",
20405
+ "transition_kind",
20406
+ "phase_result",
20407
+ "close_result",
20408
+ "state",
20409
+ "residency",
20410
+ "agent_launch_id_present",
20411
+ "is_wait_state",
20412
+ "fence_kind",
20413
+ "deadline_unix_ms",
20414
+ "failure_kind",
20415
+ "negative_evidence_bucket"
20416
+ ]
20417
+ },
19579
20418
  "daemon.agent.delivery": {
19580
20419
  spanAttrs: ["agentId", "deliveryId", "delivery_correlation_id", "messageId", "message_id_present", "seq"],
19581
20420
  eventAttrs: {
@@ -19715,7 +20554,7 @@ function resolveSlockCliPathOrEmpty(moduleUrl = import.meta.url) {
19715
20554
  }
19716
20555
  async function runBundledSlockCli(argv) {
19717
20556
  process.argv = [process.execPath, "slock", ...argv];
19718
- await import("./dist-OGRAMTIO.js");
20557
+ await import("./dist-PCKZII47.js");
19719
20558
  }
19720
20559
  function detectRuntimes(tracer = noopTracer) {
19721
20560
  const ids = [];