@botiverse/raft-daemon 0.70.0 → 0.70.2

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.
@@ -1,5 +1,5 @@
1
1
  // src/core.ts
2
- import path19 from "path";
2
+ import path20 from "path";
3
3
  import os8 from "os";
4
4
  import { createRequire as createRequire3 } from "module";
5
5
  import { accessSync } from "fs";
@@ -1105,6 +1105,7 @@ function projectTraceScopeAttrs(scope) {
1105
1105
  addOptionalStringAttr(attrs, "route_pattern", scope.request?.routePattern);
1106
1106
  addOptionalStringAttr(attrs, "method", scope.request?.method);
1107
1107
  addOptionalStringAttr(attrs, "caller_kind", scope.request?.callerKind);
1108
+ addOptionalStringAttr(attrs, "user_id", scope.request?.userId);
1108
1109
  if (typeof scope.request?.userIdPresent === "boolean") {
1109
1110
  attrs.user_id_present = scope.request.userIdPresent;
1110
1111
  }
@@ -1280,10 +1281,24 @@ var RecordingActiveSpan = class {
1280
1281
  }
1281
1282
  addEvent(name, attrs) {
1282
1283
  if (this.ended) return;
1283
- this.events.push({
1284
+ const event = {
1284
1285
  name,
1285
1286
  timeMs: this.clock(),
1286
1287
  ...attrs ? { attrs } : {}
1288
+ };
1289
+ const eventIndex = this.events.length;
1290
+ this.events.push(event);
1291
+ this.sink.recordEvent?.({
1292
+ span: {
1293
+ context: this.context,
1294
+ name: this.name,
1295
+ surface: this.surface,
1296
+ kind: this.kind,
1297
+ startTimeMs: this.startTimeMs,
1298
+ ...this.attrs ? { attrs: this.attrs } : {}
1299
+ },
1300
+ event,
1301
+ eventIndex
1287
1302
  });
1288
1303
  }
1289
1304
  end(status = "ok", options = {}) {
@@ -1291,7 +1306,7 @@ var RecordingActiveSpan = class {
1291
1306
  this.ended = true;
1292
1307
  const endTimeMs = this.clock();
1293
1308
  const attrs = mergeAttrs(this.attrs, options.attrs);
1294
- this.sink.record({
1309
+ const completed = {
1295
1310
  context: this.context,
1296
1311
  name: this.name,
1297
1312
  surface: this.surface,
@@ -1302,7 +1317,9 @@ var RecordingActiveSpan = class {
1302
1317
  durationMs: Math.max(0, endTimeMs - this.startTimeMs),
1303
1318
  ...attrs ? { attrs } : {},
1304
1319
  events: [...this.events]
1305
- });
1320
+ };
1321
+ this.sink.recordSpanFact?.({ span: completed });
1322
+ this.sink.record(completed);
1306
1323
  }
1307
1324
  };
1308
1325
  function mergeAttrs(base, extra) {
@@ -1337,6 +1354,125 @@ function randomHex(length) {
1337
1354
  return [...bytes].map((byte) => byte.toString(16).padStart(2, "0")).join("");
1338
1355
  }
1339
1356
 
1357
+ // ../shared/src/tracing/eventRows.ts
1358
+ var PROMOTED_IDENTITY_ATTRS = [
1359
+ "server_id",
1360
+ "machine_id",
1361
+ "agent_id",
1362
+ "launch_id",
1363
+ "session_id",
1364
+ "request_id",
1365
+ "route_pattern",
1366
+ "caller_kind"
1367
+ ];
1368
+ var PROMOTED_CLOSED_ATTRS = [
1369
+ "outcome",
1370
+ "reason",
1371
+ "event_kind",
1372
+ "source",
1373
+ "authority",
1374
+ "activity_write_site",
1375
+ "activity_source",
1376
+ "hint_source",
1377
+ "resolved_activity",
1378
+ "previous_activity",
1379
+ "next_activity",
1380
+ "repair_kind",
1381
+ "action",
1382
+ "error_class",
1383
+ "status_bucket",
1384
+ "shadow_agent_id",
1385
+ "shadow_signal_site",
1386
+ "shadow_observation_class",
1387
+ "shadow_prior_projection",
1388
+ "shadow_projection",
1389
+ "shadow_legacy_outcome",
1390
+ "shadow_action",
1391
+ "shadow_reason",
1392
+ "shadow_direction",
1393
+ "shadow_plan_kind"
1394
+ ];
1395
+ var TRACE_EVENT_ROW_PROMOTED_ATTRS = [
1396
+ ...PROMOTED_IDENTITY_ATTRS,
1397
+ ...PROMOTED_CLOSED_ATTRS
1398
+ ];
1399
+
1400
+ // ../shared/src/tracing/fields.ts
1401
+ function defineTraceFields(definitions) {
1402
+ for (const definition of definitions) {
1403
+ if (definition.fieldClass === "content_safety" && !definition.contentRule) {
1404
+ throw new Error(`Trace content-safety field "${definition.key}" must define a contentRule`);
1405
+ }
1406
+ if ((definition.fieldClass === "query_axis" || definition.fieldClass === "family_query_axis") && definition.valueKind === "content") {
1407
+ throw new Error(`Trace query-axis field "${definition.key}" cannot be content`);
1408
+ }
1409
+ if (definition.fieldClass === "family_query_axis" && !definition.scope) {
1410
+ throw new Error(`Trace family query-axis field "${definition.key}" must define a family scope`);
1411
+ }
1412
+ }
1413
+ return definitions;
1414
+ }
1415
+ var TRACE_B0_FIELD_DEFINITIONS = defineTraceFields([
1416
+ { key: "row_kind", fieldClass: "query_axis", placement: "span_or_event", valueKind: "closed_enum", enumBinding: "stable" },
1417
+ { key: "trace_id", fieldClass: "query_axis", placement: "span", valueKind: "identity", highCardinality: true },
1418
+ { key: "span_id", fieldClass: "query_axis", placement: "span", valueKind: "identity", highCardinality: true },
1419
+ { key: "parent_span_id", fieldClass: "query_axis", placement: "span", valueKind: "identity", highCardinality: true },
1420
+ { key: "span_name", fieldClass: "query_axis", placement: "span", valueKind: "closed_enum", enumBinding: "pending_457" },
1421
+ { key: "span_surface", fieldClass: "query_axis", placement: "span", valueKind: "closed_enum", enumBinding: "stable" },
1422
+ { key: "span_kind", fieldClass: "query_axis", placement: "span", valueKind: "closed_enum", enumBinding: "stable" },
1423
+ { key: "span_status", fieldClass: "query_axis", placement: "span", valueKind: "closed_enum", enumBinding: "stable" },
1424
+ { key: "event_name", fieldClass: "query_axis", placement: "event", valueKind: "closed_enum", enumBinding: "pending_457" },
1425
+ { key: "event_kind", fieldClass: "query_axis", placement: "span_or_event", valueKind: "closed_enum", enumBinding: "pending_457" },
1426
+ { key: "event_index", fieldClass: "query_axis", placement: "event", valueKind: "identity" },
1427
+ { key: "event_time", fieldClass: "query_axis", placement: "event", valueKind: "timestamp" },
1428
+ { key: "event_time_ms", fieldClass: "query_axis", placement: "event", valueKind: "numeric" },
1429
+ { key: "lifecycle_observed_at_ms", fieldClass: "query_axis", placement: "span_or_event", valueKind: "numeric" },
1430
+ { key: "activity_observed_at_ms", fieldClass: "query_axis", placement: "span_or_event", valueKind: "numeric" },
1431
+ { key: "advances_observed_clock", fieldClass: "query_axis", placement: "span_or_event", valueKind: "closed_enum", enumBinding: "pending_457" },
1432
+ { key: "duration_ms", fieldClass: "query_axis", placement: "span_or_event", valueKind: "numeric" },
1433
+ { key: "request_id", fieldClass: "query_axis", placement: "span", valueKind: "identity", highCardinality: true },
1434
+ { key: "route_pattern", fieldClass: "query_axis", placement: "span", valueKind: "route" },
1435
+ { key: "caller_kind", fieldClass: "query_axis", placement: "span", valueKind: "closed_enum", enumBinding: "stable" },
1436
+ { key: "server_id", fieldClass: "query_axis", placement: "span", valueKind: "identity", highCardinality: true },
1437
+ { key: "machine_id", fieldClass: "query_axis", placement: "span", valueKind: "identity", highCardinality: true },
1438
+ { key: "agent_id", fieldClass: "query_axis", placement: "span_or_event", valueKind: "identity", highCardinality: true },
1439
+ { key: "launch_id", fieldClass: "query_axis", placement: "span", valueKind: "identity", highCardinality: true },
1440
+ { key: "session_id", fieldClass: "query_axis", placement: "span", valueKind: "identity", highCardinality: true },
1441
+ { key: "observation_class", fieldClass: "query_axis", placement: "span_or_event", valueKind: "closed_enum", enumBinding: "pending_457" },
1442
+ { key: "action", fieldClass: "query_axis", placement: "span_or_event", valueKind: "closed_enum", enumBinding: "pending_457" },
1443
+ { key: "source", fieldClass: "query_axis", placement: "span_or_event", valueKind: "closed_enum", enumBinding: "pending_457" },
1444
+ { key: "served_from", fieldClass: "query_axis", placement: "span_or_event", valueKind: "closed_enum", enumBinding: "pending_457" },
1445
+ { key: "authority", fieldClass: "query_axis", placement: "span_or_event", valueKind: "closed_enum", enumBinding: "pending_457" },
1446
+ { key: "decided_by", fieldClass: "query_axis", placement: "span_or_event", valueKind: "closed_enum", enumBinding: "pending_457" },
1447
+ { key: "error_class", fieldClass: "query_axis", placement: "span_or_event", valueKind: "closed_enum", enumBinding: "pending_457" },
1448
+ { key: "query_name", fieldClass: "query_axis", placement: "span_or_event", valueKind: "closed_enum", enumBinding: "query_registry" },
1449
+ { key: "phase", fieldClass: "query_axis", placement: "span_or_event", valueKind: "closed_enum", enumBinding: "pending_457" },
1450
+ { key: "hint_source", fieldClass: "family_query_axis", placement: "event", valueKind: "closed_enum", scope: "family:activity" },
1451
+ { key: "resolved_activity", fieldClass: "family_query_axis", placement: "event", valueKind: "closed_enum", scope: "family:activity" },
1452
+ { key: "previous_activity", fieldClass: "family_query_axis", placement: "event", valueKind: "closed_enum", scope: "family:activity" },
1453
+ { key: "next_activity", fieldClass: "family_query_axis", placement: "event", valueKind: "closed_enum", scope: "family:activity" },
1454
+ { key: "repair_kind", fieldClass: "family_query_axis", placement: "event", valueKind: "closed_enum", scope: "family:activity" },
1455
+ { key: "activity_write_site", fieldClass: "family_query_axis", placement: "event", valueKind: "closed_enum", scope: "family:activity" },
1456
+ { key: "activity_source", fieldClass: "family_query_axis", placement: "event", valueKind: "closed_enum", scope: "family:activity" },
1457
+ { key: "status_bucket", fieldClass: "family_query_axis", placement: "event", valueKind: "closed_enum", scope: "family:activity" },
1458
+ { key: "shadow_agent_id", fieldClass: "family_query_axis", placement: "event", valueKind: "identity", scope: "family:lifecycle_shadow", highCardinality: true },
1459
+ { key: "shadow_signal_site", fieldClass: "family_query_axis", placement: "event", valueKind: "closed_enum", scope: "family:lifecycle_shadow", enumBinding: "pending_457" },
1460
+ { key: "shadow_observation_class", fieldClass: "family_query_axis", placement: "event", valueKind: "closed_enum", scope: "family:lifecycle_shadow", enumBinding: "pending_457" },
1461
+ { key: "shadow_prior_projection", fieldClass: "family_query_axis", placement: "event", valueKind: "closed_enum", scope: "family:lifecycle_shadow", enumBinding: "pending_457" },
1462
+ { key: "shadow_projection", fieldClass: "family_query_axis", placement: "event", valueKind: "closed_enum", scope: "family:lifecycle_shadow", enumBinding: "pending_457" },
1463
+ { key: "shadow_legacy_outcome", fieldClass: "family_query_axis", placement: "event", valueKind: "closed_enum", scope: "family:lifecycle_shadow", enumBinding: "pending_457" },
1464
+ { key: "shadow_action", fieldClass: "family_query_axis", placement: "event", valueKind: "closed_enum", scope: "family:lifecycle_shadow", enumBinding: "pending_457" },
1465
+ { key: "shadow_reason", fieldClass: "family_query_axis", placement: "event", valueKind: "closed_enum", scope: "family:lifecycle_shadow", enumBinding: "pending_457" },
1466
+ { key: "shadow_direction", fieldClass: "family_query_axis", placement: "event", valueKind: "closed_enum", scope: "family:lifecycle_shadow", enumBinding: "pending_457" },
1467
+ { key: "shadow_plan_kind", fieldClass: "family_query_axis", placement: "event", valueKind: "closed_enum", scope: "family:lifecycle_shadow", enumBinding: "pending_457" },
1468
+ { key: "row_count", fieldClass: "detail", placement: "span_or_event", valueKind: "detail" },
1469
+ { key: "retry_count", fieldClass: "detail", placement: "span_or_event", valueKind: "detail" },
1470
+ { key: "error_message", fieldClass: "detail", placement: "span_or_event", valueKind: "detail", contentRule: "scrub_and_short_retention" },
1471
+ { key: "query_text", fieldClass: "content_safety", placement: "span_or_event", valueKind: "content", contentRule: "scrub_and_short_retention" },
1472
+ { key: "raw_payload", fieldClass: "content_safety", placement: "span_or_event", valueKind: "content", contentRule: "drop" },
1473
+ { key: "token", fieldClass: "content_safety", placement: "span_or_event", valueKind: "content", contentRule: "drop" }
1474
+ ]);
1475
+
1340
1476
  // ../shared/src/toolDisplay.ts
1341
1477
  var TOOL_DISPLAY_METADATA = {
1342
1478
  send_message: { logLabel: "Sending message", activityLabel: "Sending message\u2026", summaryKind: "message_target" },
@@ -1986,7 +2122,8 @@ var agentApiResolveChannelResponseSchema = passthroughObject({
1986
2122
  channelId: z2.string().trim().min(1)
1987
2123
  });
1988
2124
  var agentApiThreadUnfollowBodySchema = passthroughObject({
1989
- thread: z2.string().trim().min(1)
2125
+ thread: z2.string().trim().min(1),
2126
+ reason: z2.string().trim().min(1).max(200).optional()
1990
2127
  });
1991
2128
  var agentApiTaskClaimBodySchema = passthroughObject({
1992
2129
  channel: z2.string().trim().min(1),
@@ -2146,6 +2283,7 @@ var agentApiServerInfoResponseSchema = passthroughObject({
2146
2283
  serverId: z2.string(),
2147
2284
  machineId: z2.string().nullable().optional(),
2148
2285
  machineName: z2.string().nullable().optional(),
2286
+ machineDescription: z2.string().nullable().optional(),
2149
2287
  machineHostname: z2.string().nullable().optional(),
2150
2288
  machineOs: z2.string().nullable().optional(),
2151
2289
  daemonVersion: z2.string().nullable().optional(),
@@ -3008,6 +3146,14 @@ var daemonApiContract = {
3008
3146
  })
3009
3147
  };
3010
3148
 
3149
+ // ../shared/src/authRefreshTiming.ts
3150
+ var AUTH_REFRESH_ROTATED_REPLAY_GRACE_MS = 1e4;
3151
+ var AUTH_REFRESH_ROTATION_DISCOVERY_LAG_BUDGET_MS = 1e3;
3152
+ var AUTH_REFRESH_ROTATED_TOKEN_WAIT_MS = 4e3;
3153
+ var AUTH_REFRESH_ROTATION_RETRY_RTT_BUDGET_MS = 1e3;
3154
+ var AUTH_REFRESH_ROTATION_LOSER_WORST_CHAIN_MS = AUTH_REFRESH_ROTATION_DISCOVERY_LAG_BUDGET_MS + AUTH_REFRESH_ROTATED_TOKEN_WAIT_MS + AUTH_REFRESH_ROTATION_RETRY_RTT_BUDGET_MS;
3155
+ var AUTH_REFRESH_ROTATION_REPLAY_GRACE_MARGIN_MS = AUTH_REFRESH_ROTATED_REPLAY_GRACE_MS - AUTH_REFRESH_ROTATION_LOSER_WORST_CHAIN_MS;
3156
+
3011
3157
  // ../shared/src/agentInbox.ts
3012
3158
  function formatAgentInboxDelta(rows, options = {}) {
3013
3159
  const totalPendingMessages = options.totalPendingMessages;
@@ -3187,6 +3333,55 @@ var SUPPORTED_TRANSLATION_LANGUAGE_SET = new Set(
3187
3333
  SUPPORTED_TRANSLATION_LANGUAGE_CODES
3188
3334
  );
3189
3335
 
3336
+ // ../shared/src/oauthScopes.ts
3337
+ var RAFT_OAUTH_SCOPE_CATALOG = {
3338
+ openid: {
3339
+ phase: "identity",
3340
+ defaultAllowed: true,
3341
+ publicDiscovery: true,
3342
+ requiresResource: false,
3343
+ label: "OpenID identity"
3344
+ },
3345
+ profile: {
3346
+ phase: "identity",
3347
+ defaultAllowed: true,
3348
+ publicDiscovery: true,
3349
+ requiresResource: false,
3350
+ label: "Basic profile"
3351
+ },
3352
+ identity: {
3353
+ phase: "identity",
3354
+ defaultAllowed: true,
3355
+ publicDiscovery: true,
3356
+ requiresResource: false,
3357
+ label: "Raft identity card"
3358
+ },
3359
+ "agent:event:write": {
3360
+ phase: "agent_inbound",
3361
+ defaultAllowed: false,
3362
+ publicDiscovery: true,
3363
+ requiresResource: true,
3364
+ label: "Send structured events to an agent"
3365
+ },
3366
+ "agent:notification:write": {
3367
+ phase: "agent_inbound",
3368
+ defaultAllowed: false,
3369
+ publicDiscovery: true,
3370
+ requiresResource: true,
3371
+ label: "Send notifications to an agent"
3372
+ },
3373
+ "agent:action_request:write": {
3374
+ phase: "agent_inbound",
3375
+ defaultAllowed: false,
3376
+ publicDiscovery: false,
3377
+ requiresResource: true,
3378
+ label: "Request agent action"
3379
+ }
3380
+ };
3381
+ var RAFT_OAUTH_SCOPES_SUPPORTED = Object.keys(RAFT_OAUTH_SCOPE_CATALOG);
3382
+ var RAFT_OAUTH_DEFAULT_ALLOWED_SCOPES = RAFT_OAUTH_SCOPES_SUPPORTED.filter((scope) => RAFT_OAUTH_SCOPE_CATALOG[scope].defaultAllowed);
3383
+ var RAFT_OAUTH_PUBLIC_DISCOVERY_SCOPES = RAFT_OAUTH_SCOPES_SUPPORTED.filter((scope) => RAFT_OAUTH_SCOPE_CATALOG[scope].publicDiscovery);
3384
+
3190
3385
  // ../shared/src/testing/failpoints.ts
3191
3386
  var NoopFailpointRegistry = class {
3192
3387
  get enabled() {
@@ -4025,8 +4220,8 @@ async function executeResponseRequest(url, init, {
4025
4220
  }
4026
4221
 
4027
4222
  // src/directUploadCapability.ts
4028
- function joinUrl(base, path20) {
4029
- return `${base.replace(/\/+$/, "")}${path20}`;
4223
+ function joinUrl(base, path21) {
4224
+ return `${base.replace(/\/+$/, "")}${path21}`;
4030
4225
  }
4031
4226
  function jsonHeaders(apiKey) {
4032
4227
  return {
@@ -5659,7 +5854,7 @@ function shortMessageId2(value) {
5659
5854
  return value.slice(0, 8);
5660
5855
  }
5661
5856
  function normalizeSenderType(value) {
5662
- return value === "human" || value === "agent" || value === "system" ? value : void 0;
5857
+ return value === "human" || value === "agent" || value === "system" || value === "third_party_app" ? value : void 0;
5663
5858
  }
5664
5859
  function nonEmptyString(value) {
5665
5860
  return typeof value === "string" && value.trim().length > 0 ? value : void 0;
@@ -6047,6 +6242,10 @@ async function readRequestBody(req) {
6047
6242
  function messageSeq3(message) {
6048
6243
  return Number(message.seq ?? 0);
6049
6244
  }
6245
+ function isThirdPartyAgentEvent(message) {
6246
+ const thirdPartyEvent = message.third_party_event;
6247
+ return typeof thirdPartyEvent?.id === "string" && thirdPartyEvent.id.length > 0;
6248
+ }
6050
6249
  function localAgentApiInboxResponse(registration) {
6051
6250
  const coordinator = registration.inboxCoordinator;
6052
6251
  if (!coordinator) return void 0;
@@ -6097,6 +6296,7 @@ function localAgentApiEventsResponse(registration, target) {
6097
6296
  const normalized = sortInboxMessagesBySeq(normalizeInboxVisibleMessages(pending));
6098
6297
  const filtered = parsedQuery.sinceSeq !== null ? normalized.filter((message) => {
6099
6298
  const seq = messageSeq3(message);
6299
+ if ((!Number.isFinite(seq) || seq <= 0) && isThirdPartyAgentEvent(message)) return true;
6100
6300
  return Number.isFinite(seq) && seq > parsedQuery.sinceSeq;
6101
6301
  }) : normalized;
6102
6302
  const events = filtered.slice(0, parsedQuery.limit);
@@ -7665,7 +7865,7 @@ function codexNotificationDiagnosticEvent(message) {
7665
7865
  return null;
7666
7866
  }
7667
7867
  const sessionId = codexMessageThreadId(message);
7668
- const path20 = boundedString(params.path);
7868
+ const path21 = boundedString(params.path);
7669
7869
  return {
7670
7870
  kind: "runtime_diagnostic",
7671
7871
  severity: "warning",
@@ -7673,7 +7873,7 @@ function codexNotificationDiagnosticEvent(message) {
7673
7873
  itemType: message.method,
7674
7874
  message: diagnosticMessage,
7675
7875
  ...details ? { details } : {},
7676
- ...path20 ? { path: path20 } : {},
7876
+ ...path21 ? { path: path21 } : {},
7677
7877
  ...params.range !== void 0 ? { range: params.range } : {},
7678
7878
  payloadBytes: payloadBytes(params),
7679
7879
  ...sessionId ? { sessionId } : {}
@@ -12531,6 +12731,9 @@ function computeTarget(channelType, channelName, parentChannelName, parentChanne
12531
12731
  return `#${channelName}`;
12532
12732
  }
12533
12733
  function formatAgentMessageVisibleTarget(message) {
12734
+ if (message.third_party_event) {
12735
+ return `agent-event:${getMessageShortId(message.third_party_event.id)}`;
12736
+ }
12534
12737
  return computeTarget(message.channel_type, message.channel_name, message.parent_channel_name, message.parent_channel_type);
12535
12738
  }
12536
12739
  function formatProxyVisibleMessageTarget(message) {
@@ -18297,6 +18500,7 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
18297
18500
  const launchId = launchIdOverride || ap?.launchId || void 0;
18298
18501
  const clientSeq = this.nextActivityClientSeq(agentId);
18299
18502
  const producerFactId = this.buildActivityProducerFactId(agentId, launchId, clientSeq);
18503
+ const observedAtMs = Date.now();
18300
18504
  this.sendToServer({
18301
18505
  type: "agent:activity",
18302
18506
  agentId,
@@ -18308,6 +18512,7 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
18308
18512
  launchId,
18309
18513
  clientSeq,
18310
18514
  producerFactId,
18515
+ observedAtMs,
18311
18516
  isHeartbeat: false
18312
18517
  });
18313
18518
  this.recordActivityProducedTrace(agentId, activityKind, detail, detailKind, entries, ap, launchId, clientSeq, producerFactId, false);
@@ -18327,6 +18532,7 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
18327
18532
  const heartbeatLaunchId = launchIdOverride || ap.launchId || void 0;
18328
18533
  const heartbeatClientSeq = this.nextActivityClientSeq(agentId);
18329
18534
  const heartbeatProducerFactId = this.buildActivityProducerFactId(agentId, heartbeatLaunchId, heartbeatClientSeq);
18535
+ const heartbeatObservedAtMs = Date.now();
18330
18536
  this.sendToServer({
18331
18537
  type: "agent:activity",
18332
18538
  agentId,
@@ -18337,6 +18543,7 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
18337
18543
  launchId: heartbeatLaunchId,
18338
18544
  clientSeq: heartbeatClientSeq,
18339
18545
  producerFactId: heartbeatProducerFactId,
18546
+ observedAtMs: heartbeatObservedAtMs,
18340
18547
  // The one knowing site: this timer re-broadcasts stale
18341
18548
  // lastActivity, so it declares its replay provenance.
18342
18549
  isHeartbeat: true
@@ -18612,12 +18819,29 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
18612
18819
  }
18613
18820
  this.commitApmIdleState(agentId, ap, false);
18614
18821
  }
18615
- interruptCompactionIfActive(agentId) {
18822
+ interruptCompactionIfActive(agentId, options = {}) {
18616
18823
  const ap = this.agents.get(agentId);
18617
- if (!ap || ap.compaction.kind !== "active" && !ap.gatedSteering.compacting) return;
18824
+ if (!ap || ap.compaction.kind !== "active" && !ap.gatedSteering.compacting) return false;
18618
18825
  this.clearCompactionWatchdog(ap);
18619
18826
  const reduction = reduceApmGatedCompaction(ap.gatedSteering, { kind: "compaction_interrupted" });
18620
- this.commitGatedSteeringDecisionState(agentId, ap, reduction.nextState);
18827
+ this.commitGatedSteeringDecisionState(agentId, ap, reduction.nextState, { event: "compaction_interrupted" });
18828
+ if (options.traceAttrs) {
18829
+ this.recordRuntimeTraceEvent(agentId, ap, "runtime.context_compaction.interrupted", options.traceAttrs);
18830
+ }
18831
+ if (options.detail) {
18832
+ this.broadcastActivity(
18833
+ agentId,
18834
+ "error",
18835
+ options.detail,
18836
+ options.entries ?? [],
18837
+ void 0,
18838
+ options.detailKind ?? "runtime_error"
18839
+ );
18840
+ }
18841
+ if (options.flushBoundaryMessages) {
18842
+ this.flushCompactionBoundaryMessages(agentId, ap);
18843
+ }
18844
+ return true;
18621
18845
  }
18622
18846
  flushReviewBoundaryMessages(agentId, ap) {
18623
18847
  const reduction = reduceApmGatedReviewBoundaryFlush(ap.gatedSteering, {
@@ -19345,6 +19569,17 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
19345
19569
  if (event.kind === "delivery_error") {
19346
19570
  if (ap) {
19347
19571
  this.restoreRuntimeDeliveryAfterAsyncRejection(agentId, ap, event);
19572
+ this.interruptCompactionIfActive(agentId, {
19573
+ detail: `Context compaction interrupted after runtime delivery failed: ${event.message}`,
19574
+ entries: [{ kind: "text", text: `Error: ${event.message}` }],
19575
+ flushBoundaryMessages: true,
19576
+ traceAttrs: {
19577
+ reason: "delivery_error",
19578
+ request_method: event.requestMethod,
19579
+ source: event.source,
19580
+ payloadBytes: event.payloadBytes
19581
+ }
19582
+ });
19348
19583
  } else {
19349
19584
  this.recordDaemonTrace("daemon.agent.delivery_error.received_without_process", {
19350
19585
  agentId,
@@ -21368,6 +21603,563 @@ function assertLegacyDaemonKeyNotAdoptedByComputer(options) {
21368
21603
  if (match) throw new LegacyDaemonKeyAdoptedByComputerError(match);
21369
21604
  }
21370
21605
 
21606
+ // src/agentMigrationExport.ts
21607
+ import { createHash as createHash7 } from "crypto";
21608
+ import { createReadStream } from "fs";
21609
+ import { lstat as lstat2, readdir as readdir4, readFile as readFile3, readlink } from "fs/promises";
21610
+ import path19 from "path";
21611
+ var AGENT_MIGRATION_BUNDLE_SCHEMA_VERSION = "agent-bundle/v1";
21612
+ var REGENERABLE_DIRECTORY_NAMES = [
21613
+ ".venv",
21614
+ "__pycache__",
21615
+ "dist",
21616
+ "node_modules",
21617
+ "target"
21618
+ ];
21619
+ var SECRET_FILE_NAMES = /* @__PURE__ */ new Set([
21620
+ ".env",
21621
+ ".env.local",
21622
+ ".env.development",
21623
+ ".env.production",
21624
+ ".env.test",
21625
+ "credentials.json",
21626
+ "credential.json"
21627
+ ]);
21628
+ var ENV_KEY_PATTERN = /^\s*(?:export\s+)?([A-Za-z_][A-Za-z0-9_]*)\s*=/;
21629
+ async function buildAgentMigrationExportManifest(input) {
21630
+ const slockHome = path19.resolve(input.slockHome);
21631
+ const workspace = path19.resolve(input.workspacePath ?? path19.join(slockHome, "agents", input.agentId));
21632
+ const proposedIncludes = normalizeProposalPaths(input.cooperativeManifest?.include, workspace, "include");
21633
+ const proposedRegenerableExcludes = normalizeProposalPaths(input.cooperativeManifest?.exclude_regenerable, workspace, "exclude_regenerable");
21634
+ const cleanedProposal = normalizeProposalPaths(input.cooperativeManifest?.cleaned, workspace, "cleaned");
21635
+ const state = {
21636
+ workspace,
21637
+ files: [],
21638
+ excludedRegenerable: [],
21639
+ promotedIncludes: [],
21640
+ proposalRefusals: [
21641
+ ...proposedIncludes.refusals,
21642
+ ...proposedRegenerableExcludes.refusals,
21643
+ ...cleanedProposal.refusals
21644
+ ],
21645
+ unreachable: [],
21646
+ secretsDisclosed: [],
21647
+ seenWorkspacePaths: /* @__PURE__ */ new Set(),
21648
+ explicitIncludePaths: new Set(proposedIncludes.paths)
21649
+ };
21650
+ await walkWorkspace(workspace, "", new Set(proposedRegenerableExcludes.paths), state, { forceIncludeRegenerable: false });
21651
+ for (const requestedPath of proposedIncludes.paths) {
21652
+ if (!state.seenWorkspacePaths.has(requestedPath)) {
21653
+ await includeWorkspacePath(requestedPath, state, { forceIncludeRegenerable: true });
21654
+ }
21655
+ }
21656
+ for (const requestedPath of proposedRegenerableExcludes.paths) {
21657
+ if (isRegenerablePath(requestedPath)) continue;
21658
+ state.promotedIncludes.push({ path: requestedPath, reason: "exclude_not_regenerable" });
21659
+ await includeWorkspacePath(requestedPath, state, { forceIncludeRegenerable: true });
21660
+ }
21661
+ const crossTreeRefs = await buildCrossTreeRefs(input.runtimeSessionRefs ?? []);
21662
+ const secretDisclosureProposal = normalizeProposalPaths(input.cooperativeManifest?.secrets_disclosed, workspace, "secrets_disclosed");
21663
+ state.proposalRefusals.push(...secretDisclosureProposal.refusals);
21664
+ return {
21665
+ schemaVersion: AGENT_MIGRATION_BUNDLE_SCHEMA_VERSION,
21666
+ agentId: input.agentId,
21667
+ mode: input.mode,
21668
+ createdAt: (input.now ?? /* @__PURE__ */ new Date()).toISOString(),
21669
+ roots: {
21670
+ slockHome,
21671
+ workspace
21672
+ },
21673
+ defaults: {
21674
+ unknownFiles: "include",
21675
+ excludePolicy: "regenerable_only",
21676
+ regenerableDirectoryNames: [...REGENERABLE_DIRECTORY_NAMES]
21677
+ },
21678
+ files: sortBundleEntries(state.files),
21679
+ excludedRegenerable: sortByPath(state.excludedRegenerable),
21680
+ promotedIncludes: sortByPath(state.promotedIncludes),
21681
+ proposalRefusals: sortByPath(state.proposalRefusals),
21682
+ unreachable: sortByPath(state.unreachable),
21683
+ secretsDisclosed: sortByPath([
21684
+ ...state.secretsDisclosed,
21685
+ ...normalizeProvidedSecretDisclosures(secretDisclosureProposal.paths)
21686
+ ]),
21687
+ cleaned: cleanedProposal.paths,
21688
+ crossTreeRefs: crossTreeRefs.sort((a, b) => a.bundlePath.localeCompare(b.bundlePath))
21689
+ };
21690
+ }
21691
+ async function walkWorkspace(root, relativeDir, proposedRegenerableExcludes, state, opts) {
21692
+ const absoluteDir = path19.join(root, relativeDir);
21693
+ let entries;
21694
+ try {
21695
+ entries = await readdir4(absoluteDir, { withFileTypes: true });
21696
+ } catch {
21697
+ state.unreachable.push({
21698
+ path: relativeDir || ".",
21699
+ sourcePath: absoluteDir,
21700
+ reason: "read_error"
21701
+ });
21702
+ return;
21703
+ }
21704
+ entries.sort((a, b) => a.name.localeCompare(b.name));
21705
+ for (const entry of entries) {
21706
+ const relativePath = toPosixPath(path19.join(relativeDir, entry.name));
21707
+ if (entry.isDirectory()) {
21708
+ if (!opts.forceIncludeRegenerable && isRegenerablePath(relativePath)) {
21709
+ if (state.explicitIncludePaths.has(relativePath)) {
21710
+ await walkWorkspace(root, relativePath, proposedRegenerableExcludes, state, { forceIncludeRegenerable: true });
21711
+ continue;
21712
+ }
21713
+ if (hasExplicitIncludeDescendant(relativePath, state.explicitIncludePaths)) {
21714
+ await walkWorkspace(root, relativePath, proposedRegenerableExcludes, state, opts);
21715
+ continue;
21716
+ }
21717
+ state.excludedRegenerable.push({
21718
+ path: relativePath,
21719
+ reason: proposedRegenerableExcludes.has(relativePath) ? "cooperative_exclude_regenerable" : "regenerable_default",
21720
+ regenerableHint: `${entry.name} is treated as rebuildable/installable state and is not bundled by default`
21721
+ });
21722
+ continue;
21723
+ }
21724
+ await walkWorkspace(root, relativePath, proposedRegenerableExcludes, state, opts);
21725
+ continue;
21726
+ }
21727
+ await includeWorkspacePath(relativePath, state, { forceIncludeRegenerable: opts.forceIncludeRegenerable });
21728
+ }
21729
+ }
21730
+ async function includeWorkspacePath(workspaceRelativePath, state, opts) {
21731
+ const normalizedRelativePath = normalizeRelativePath(workspaceRelativePath);
21732
+ if (state.seenWorkspacePaths.has(normalizedRelativePath)) return;
21733
+ const sourcePath = path19.join(state.workspace, normalizedRelativePath);
21734
+ let stat4;
21735
+ try {
21736
+ stat4 = await lstat2(sourcePath);
21737
+ } catch {
21738
+ state.unreachable.push({
21739
+ path: normalizedRelativePath,
21740
+ sourcePath,
21741
+ reason: "missing"
21742
+ });
21743
+ return;
21744
+ }
21745
+ if (stat4.isDirectory()) {
21746
+ if (!opts.forceIncludeRegenerable && isRegenerablePath(normalizedRelativePath)) {
21747
+ state.excludedRegenerable.push({
21748
+ path: normalizedRelativePath,
21749
+ reason: "cooperative_exclude_regenerable",
21750
+ regenerableHint: `${path19.basename(normalizedRelativePath)} is treated as rebuildable/installable state and is not bundled by default`
21751
+ });
21752
+ return;
21753
+ }
21754
+ await walkWorkspace(state.workspace, normalizedRelativePath, /* @__PURE__ */ new Set(), state, opts);
21755
+ return;
21756
+ }
21757
+ state.seenWorkspacePaths.add(normalizedRelativePath);
21758
+ const baseEntry = {
21759
+ source: "workspace",
21760
+ sourcePath,
21761
+ workspaceRelativePath: normalizedRelativePath,
21762
+ bundlePath: `workspace/${normalizedRelativePath}`,
21763
+ mode: stat4.mode,
21764
+ mtimeMs: stat4.mtimeMs
21765
+ };
21766
+ if (stat4.isSymbolicLink()) {
21767
+ state.files.push({
21768
+ ...baseEntry,
21769
+ kind: "symlink",
21770
+ linkTarget: await readlink(sourcePath)
21771
+ });
21772
+ return;
21773
+ }
21774
+ if (!stat4.isFile()) {
21775
+ state.unreachable.push({
21776
+ path: normalizedRelativePath,
21777
+ sourcePath,
21778
+ reason: "unsupported_file_type"
21779
+ });
21780
+ return;
21781
+ }
21782
+ const secretShapes = await detectSecretShapes(sourcePath, normalizedRelativePath);
21783
+ if (secretShapes.length > 0) {
21784
+ state.secretsDisclosed.push({ path: normalizedRelativePath, shapes: secretShapes });
21785
+ }
21786
+ state.files.push({
21787
+ ...baseEntry,
21788
+ kind: "file",
21789
+ sizeBytes: stat4.size,
21790
+ sha256: await sha256File(sourcePath),
21791
+ secretShapes: secretShapes.length > 0 ? secretShapes : void 0
21792
+ });
21793
+ }
21794
+ async function buildCrossTreeRefs(refs) {
21795
+ const result = [];
21796
+ for (const ref of refs) {
21797
+ const sourcePath = path19.resolve(ref.path);
21798
+ const bundlePath = `runtime/${safeBundleSegment(ref.runtime)}/${safeBundleSegment(ref.label)}/${safeBundleSegment(path19.basename(sourcePath) || "session")}`;
21799
+ const entry = {
21800
+ runtime: ref.runtime,
21801
+ label: ref.label,
21802
+ sourcePath,
21803
+ bundlePath,
21804
+ reachable: ref.reachable !== false,
21805
+ reason: ref.reason
21806
+ };
21807
+ try {
21808
+ const stat4 = await lstat2(sourcePath);
21809
+ if (stat4.isFile()) {
21810
+ entry.sizeBytes = stat4.size;
21811
+ entry.sha256 = await sha256File(sourcePath);
21812
+ }
21813
+ } catch {
21814
+ entry.reachable = false;
21815
+ }
21816
+ result.push(entry);
21817
+ }
21818
+ return result;
21819
+ }
21820
+ async function sha256File(filePath) {
21821
+ const hash = createHash7("sha256");
21822
+ await new Promise((resolve, reject) => {
21823
+ const stream = createReadStream(filePath);
21824
+ stream.on("data", (chunk) => hash.update(chunk));
21825
+ stream.on("error", reject);
21826
+ stream.on("end", resolve);
21827
+ });
21828
+ return hash.digest("hex");
21829
+ }
21830
+ async function detectSecretShapes(sourcePath, relativePath) {
21831
+ const basename = path19.basename(relativePath);
21832
+ const lowerBasename = basename.toLowerCase();
21833
+ const shapes = /* @__PURE__ */ new Set();
21834
+ if (SECRET_FILE_NAMES.has(lowerBasename) || lowerBasename.startsWith(".env.")) {
21835
+ shapes.add(`file:${basename}`);
21836
+ try {
21837
+ const text = await readFile3(sourcePath, "utf8");
21838
+ for (const line of text.split(/\r?\n/)) {
21839
+ const match = ENV_KEY_PATTERN.exec(line);
21840
+ if (match) shapes.add(`env:${match[1]}`);
21841
+ }
21842
+ } catch {
21843
+ shapes.add("content:unreadable");
21844
+ }
21845
+ }
21846
+ if (/(?:secret|token|credential|api[-_]?key)/i.test(relativePath)) {
21847
+ shapes.add(`path:${basename}`);
21848
+ }
21849
+ return [...shapes].sort();
21850
+ }
21851
+ function normalizeProvidedSecretDisclosures(disclosures) {
21852
+ return disclosures.map((entry) => ({
21853
+ path: entry,
21854
+ shapes: ["provided"]
21855
+ }));
21856
+ }
21857
+ function normalizeProposalPaths(paths, workspace, source) {
21858
+ if (!paths) return { paths: [], refusals: [] };
21859
+ const result = [];
21860
+ const refusals = [];
21861
+ for (const value of paths) {
21862
+ const trimmed = value.trim();
21863
+ if (!trimmed) continue;
21864
+ if (path19.isAbsolute(trimmed)) {
21865
+ const relative = path19.relative(workspace, trimmed);
21866
+ if (relative.startsWith("..") || path19.isAbsolute(relative)) {
21867
+ refusals.push({
21868
+ path: trimmed,
21869
+ reason: "outside_workspace",
21870
+ source
21871
+ });
21872
+ continue;
21873
+ }
21874
+ try {
21875
+ result.push(normalizeRelativePath(relative));
21876
+ } catch {
21877
+ refusals.push({
21878
+ path: trimmed,
21879
+ reason: "unsafe_path",
21880
+ source
21881
+ });
21882
+ }
21883
+ continue;
21884
+ }
21885
+ try {
21886
+ result.push(normalizeRelativePath(trimmed));
21887
+ } catch {
21888
+ refusals.push({
21889
+ path: trimmed,
21890
+ reason: "unsafe_path",
21891
+ source
21892
+ });
21893
+ }
21894
+ }
21895
+ return { paths: [...new Set(result)], refusals };
21896
+ }
21897
+ function normalizeRelativePath(value) {
21898
+ const normalized = path19.normalize(value).replace(/^[\\/]+/, "");
21899
+ if (!normalized || normalized === "." || normalized.startsWith("..") || path19.isAbsolute(normalized)) {
21900
+ throw new Error(`unsafe migration export path: ${value}`);
21901
+ }
21902
+ return toPosixPath(normalized);
21903
+ }
21904
+ function isRegenerablePath(relativePath) {
21905
+ return normalizeRelativePath(relativePath).split("/").some((segment) => REGENERABLE_DIRECTORY_NAMES.includes(segment));
21906
+ }
21907
+ function hasExplicitIncludeDescendant(relativePath, explicitIncludePaths) {
21908
+ const prefix = `${relativePath}/`;
21909
+ for (const includePath of explicitIncludePaths) {
21910
+ if (includePath.startsWith(prefix)) return true;
21911
+ }
21912
+ return false;
21913
+ }
21914
+ function safeBundleSegment(value) {
21915
+ return value.replace(/[^a-zA-Z0-9._-]+/g, "-").replace(/^-+|-+$/g, "") || "unknown";
21916
+ }
21917
+ function toPosixPath(value) {
21918
+ return value.split(path19.sep).join("/");
21919
+ }
21920
+ function sortBundleEntries(entries) {
21921
+ return [...entries].sort((a, b) => a.bundlePath.localeCompare(b.bundlePath));
21922
+ }
21923
+ function sortByPath(entries) {
21924
+ return [...entries].sort((a, b) => a.path.localeCompare(b.path));
21925
+ }
21926
+
21927
+ // src/agentMigrationHttpTransport.ts
21928
+ import { createHash as createHash8, randomBytes as randomBytes2, timingSafeEqual } from "crypto";
21929
+ import http2 from "http";
21930
+ var MigrationBundleStreamError = class extends Error {
21931
+ constructor(code) {
21932
+ super(code);
21933
+ this.code = code;
21934
+ }
21935
+ };
21936
+ var AgentMigrationGrantRegistry = class {
21937
+ grants = /* @__PURE__ */ new Map();
21938
+ now;
21939
+ constructor(now = () => /* @__PURE__ */ new Date()) {
21940
+ this.now = now;
21941
+ }
21942
+ createGrant(input) {
21943
+ const token = input.token ?? randomBytes2(32).toString("base64url");
21944
+ const manifestSha256 = sha256Buffer(canonicalJsonBuffer(input.manifest));
21945
+ const grant = {
21946
+ grantId: input.grantId ?? randomBytes2(16).toString("hex"),
21947
+ tokenHash: hashToken(token),
21948
+ expiresAt: input.expiresAt,
21949
+ oneTimeUse: input.oneTimeUse ?? true,
21950
+ state: "issued",
21951
+ manifest: input.manifest,
21952
+ manifestSha256,
21953
+ bundleEtag: `"agent-migration-${manifestSha256}"`
21954
+ };
21955
+ this.grants.set(grant.grantId, grant);
21956
+ return { grant, token };
21957
+ }
21958
+ get(grantId) {
21959
+ return this.grants.get(grantId);
21960
+ }
21961
+ authenticate(grantId, token) {
21962
+ const grant = this.grants.get(grantId);
21963
+ if (!grant || !token || !verifyTokenHash(token, grant.tokenHash)) {
21964
+ return { ok: false, status: 401, code: "migration_grant_auth_failed" };
21965
+ }
21966
+ if (grant.state === "revoked" || grant.state === "consumed") {
21967
+ return { ok: false, status: 410, code: "migration_grant_unavailable" };
21968
+ }
21969
+ if (this.now().getTime() >= grant.expiresAt.getTime()) {
21970
+ grant.state = "expired";
21971
+ return { ok: false, status: 410, code: "migration_grant_unavailable" };
21972
+ }
21973
+ return { ok: true, grant };
21974
+ }
21975
+ revokeAll() {
21976
+ for (const grant of this.grants.values()) {
21977
+ if (grant.state !== "consumed" && grant.state !== "expired") {
21978
+ grant.state = "revoked";
21979
+ }
21980
+ }
21981
+ }
21982
+ };
21983
+ function createAgentMigrationHttpTransport(options = {}) {
21984
+ const registry = new AgentMigrationGrantRegistry(options.now);
21985
+ const bundleStreamFactory = options.bundleStreamFactory ?? defaultBundleStream;
21986
+ const server = http2.createServer((req, res) => {
21987
+ void handleMigrationRequest(req, res, registry, bundleStreamFactory);
21988
+ });
21989
+ return {
21990
+ grants: registry,
21991
+ server,
21992
+ listen: (port = 0, host = "127.0.0.1") => new Promise((resolve, reject) => {
21993
+ server.once("error", reject);
21994
+ server.listen(port, host, () => {
21995
+ server.off("error", reject);
21996
+ const address = server.address();
21997
+ if (!address || typeof address === "string") {
21998
+ reject(new Error("migration transport listen did not produce a TCP address"));
21999
+ return;
22000
+ }
22001
+ resolve({ url: `http://${address.address}:${address.port}` });
22002
+ });
22003
+ }),
22004
+ close: () => new Promise((resolve, reject) => {
22005
+ registry.revokeAll();
22006
+ server.close((err) => {
22007
+ if (err) reject(err);
22008
+ else resolve();
22009
+ });
22010
+ })
22011
+ };
22012
+ }
22013
+ async function handleMigrationRequest(req, res, registry, bundleStreamFactory) {
22014
+ const parsed = new URL(req.url ?? "/", "http://127.0.0.1");
22015
+ const match = /^\/migration\/([^/]+)\/([^/]+)(?:\/([^/]+))?$/.exec(parsed.pathname);
22016
+ if (!match) {
22017
+ sendJson(res, 404, { code: "migration_route_not_found" });
22018
+ return;
22019
+ }
22020
+ const [, grantId, resource, resourceId] = match;
22021
+ const auth = registry.authenticate(decodeURIComponent(grantId), extractBearerToken(req));
22022
+ if (!auth.ok) {
22023
+ sendJson(res, auth.status, { code: auth.code });
22024
+ return;
22025
+ }
22026
+ if (resource === "manifest" && req.method === "GET" && !resourceId) {
22027
+ sendJson(res, 200, {
22028
+ manifestSha256: auth.grant.manifestSha256,
22029
+ manifest: auth.grant.manifest
22030
+ }, {
22031
+ "X-Raft-Manifest-Sha": auth.grant.manifestSha256,
22032
+ ETag: `"manifest-${auth.grant.manifestSha256}"`
22033
+ });
22034
+ return;
22035
+ }
22036
+ if (resource === "bundle.tar" && !resourceId) {
22037
+ if (req.method === "HEAD") {
22038
+ sendHead(res, auth.grant);
22039
+ return;
22040
+ }
22041
+ if (req.method === "GET") {
22042
+ await streamBundle(res, auth.grant, bundleStreamFactory);
22043
+ return;
22044
+ }
22045
+ }
22046
+ if (resource === "chunk" && req.method === "GET" && resourceId) {
22047
+ sendJson(res, 501, { code: "migration_chunk_not_implemented" });
22048
+ return;
22049
+ }
22050
+ sendJson(res, 405, { code: "migration_method_not_allowed" });
22051
+ }
22052
+ function sendHead(res, grant) {
22053
+ res.statusCode = 200;
22054
+ res.setHeader("X-Raft-Manifest-Sha", grant.manifestSha256);
22055
+ res.setHeader("ETag", grant.bundleEtag);
22056
+ res.setHeader("Accept-Ranges", "none");
22057
+ res.setHeader("X-Raft-Bundle-Size", "unknown");
22058
+ res.end();
22059
+ }
22060
+ async function streamBundle(res, grant, bundleStreamFactory) {
22061
+ if (grant.state === "streaming") {
22062
+ sendJson(res, 409, { code: "migration_bundle_stream_in_progress" });
22063
+ return;
22064
+ }
22065
+ if (grant.oneTimeUse && grant.state !== "issued" && grant.state !== "interrupted") {
22066
+ sendJson(res, 410, { code: "migration_grant_unavailable" });
22067
+ return;
22068
+ }
22069
+ let stream;
22070
+ try {
22071
+ stream = bundleStreamFactory(grant);
22072
+ } catch (err) {
22073
+ const code = err instanceof MigrationBundleStreamError ? err.code : "migration_bundle_stream_failed";
22074
+ sendJson(res, 500, { code });
22075
+ return;
22076
+ }
22077
+ grant.state = "streaming";
22078
+ let completed = false;
22079
+ res.on("close", () => {
22080
+ if (!completed && grant.state === "streaming") {
22081
+ grant.state = "interrupted";
22082
+ }
22083
+ });
22084
+ try {
22085
+ res.statusCode = 200;
22086
+ res.setHeader("Content-Type", "application/x-tar");
22087
+ res.setHeader("X-Raft-Manifest-Sha", grant.manifestSha256);
22088
+ res.setHeader("ETag", grant.bundleEtag);
22089
+ for await (const chunk of stream) {
22090
+ if (!res.write(chunk)) {
22091
+ await onceDrain(res);
22092
+ }
22093
+ }
22094
+ completed = true;
22095
+ grant.state = "consumed";
22096
+ res.end();
22097
+ } catch {
22098
+ if (!completed && grant.state === "streaming") {
22099
+ grant.state = "interrupted";
22100
+ }
22101
+ if (!res.headersSent) {
22102
+ sendJson(res, 500, { code: "migration_bundle_stream_failed" });
22103
+ } else {
22104
+ res.destroy();
22105
+ }
22106
+ }
22107
+ }
22108
+ function defaultBundleStream(grant) {
22109
+ void grant;
22110
+ throw new MigrationBundleStreamError("migration_bundle_stream_not_wired");
22111
+ }
22112
+ function extractBearerToken(req) {
22113
+ const directHeader = singleHeader(req.headers["x-raft-migration-token"]);
22114
+ if (directHeader) return directHeader;
22115
+ const authorization = singleHeader(req.headers.authorization);
22116
+ if (!authorization) return null;
22117
+ const match = /^Bearer\s+(.+)$/i.exec(authorization);
22118
+ return match?.[1] ?? null;
22119
+ }
22120
+ function singleHeader(value) {
22121
+ if (!value) return null;
22122
+ return Array.isArray(value) ? value[0] ?? null : value;
22123
+ }
22124
+ function sendJson(res, status, body, headers = {}) {
22125
+ const payload = JSON.stringify(body);
22126
+ res.writeHead(status, {
22127
+ "Content-Type": "application/json",
22128
+ "Content-Length": Buffer.byteLength(payload).toString(),
22129
+ ...headers
22130
+ });
22131
+ res.end(payload);
22132
+ }
22133
+ function hashToken(token) {
22134
+ return sha256Buffer(Buffer.from(token, "utf8"));
22135
+ }
22136
+ function verifyTokenHash(token, expectedHashHex) {
22137
+ const actual = Buffer.from(hashToken(token), "hex");
22138
+ const expected = Buffer.from(expectedHashHex, "hex");
22139
+ if (actual.byteLength !== expected.byteLength) return false;
22140
+ return timingSafeEqual(actual, expected);
22141
+ }
22142
+ function sha256Buffer(buffer) {
22143
+ return createHash8("sha256").update(buffer).digest("hex");
22144
+ }
22145
+ function canonicalJsonBuffer(value) {
22146
+ return Buffer.from(canonicalJson(value), "utf8");
22147
+ }
22148
+ function canonicalJson(value) {
22149
+ return JSON.stringify(sortJsonValue(value));
22150
+ }
22151
+ function sortJsonValue(value) {
22152
+ if (Array.isArray(value)) return value.map(sortJsonValue);
22153
+ if (!value || typeof value !== "object") return value;
22154
+ return Object.keys(value).sort().reduce((result, key) => {
22155
+ result[key] = sortJsonValue(value[key]);
22156
+ return result;
22157
+ }, {});
22158
+ }
22159
+ function onceDrain(res) {
22160
+ return new Promise((resolve) => res.once("drain", resolve));
22161
+ }
22162
+
21371
22163
  // src/core.ts
21372
22164
  var DEFAULT_TRACE_UPLOAD_URL = "https://slock-trace-upload.botiverse.dev";
21373
22165
  var RUNNER_CREDENTIAL_SCOPES = ["send", "read", "mentions", "tasks", "reactions", "server", "channels", "knowledge"];
@@ -21549,13 +22341,13 @@ function readDaemonVersion(moduleUrl = import.meta.url) {
21549
22341
  }
21550
22342
  }
21551
22343
  function resolveSlockCliPath(moduleUrl = import.meta.url) {
21552
- const thisDir = path19.dirname(fileURLToPath(moduleUrl));
21553
- const bundledDistPath = path19.resolve(thisDir, "cli", "index.js");
22344
+ const thisDir = path20.dirname(fileURLToPath(moduleUrl));
22345
+ const bundledDistPath = path20.resolve(thisDir, "cli", "index.js");
21554
22346
  try {
21555
22347
  accessSync(bundledDistPath);
21556
22348
  return bundledDistPath;
21557
22349
  } catch {
21558
- const workspaceDistPath = path19.resolve(thisDir, "..", "..", "cli", "dist", "index.js");
22350
+ const workspaceDistPath = path20.resolve(thisDir, "..", "..", "cli", "dist", "index.js");
21559
22351
  accessSync(workspaceDistPath);
21560
22352
  return workspaceDistPath;
21561
22353
  }
@@ -21569,7 +22361,7 @@ function resolveSlockCliPathOrEmpty(moduleUrl = import.meta.url) {
21569
22361
  }
21570
22362
  async function runBundledSlockCli(argv) {
21571
22363
  process.argv = [process.execPath, "slock", ...argv];
21572
- await import("./dist-I6ATP6I5.js");
22364
+ await import("./dist-CWN2CLOA.js");
21573
22365
  }
21574
22366
  function detectRuntimes(tracer = noopTracer) {
21575
22367
  const ids = [];
@@ -21777,7 +22569,7 @@ var DaemonCore = class {
21777
22569
  }
21778
22570
  resolveMachineStateRoot() {
21779
22571
  if (this.options.machineStateDir) return this.options.machineStateDir;
21780
- if (this.options.dataDir) return path19.join(path19.dirname(this.options.dataDir), "machines");
22572
+ if (this.options.dataDir) return path20.join(path20.dirname(this.options.dataDir), "machines");
21781
22573
  return resolveDefaultMachineStateRoot();
21782
22574
  }
21783
22575
  shouldEnableLocalTrace() {
@@ -21805,7 +22597,7 @@ var DaemonCore = class {
21805
22597
  sinks: [this.localTraceSink]
21806
22598
  }));
21807
22599
  this.agentManager.setTracer(this.tracer);
21808
- this.agentManager.setCliTransportTraceDir(path19.join(machineDir, "traces"));
22600
+ this.agentManager.setCliTransportTraceDir(path20.join(machineDir, "traces"));
21809
22601
  }
21810
22602
  installTraceBundleUploader(machineDir) {
21811
22603
  if (!this.shouldEnableLocalTrace()) return;
@@ -22094,7 +22886,7 @@ var DaemonCore = class {
22094
22886
  session_id_present: Boolean(msg.config.sessionId)
22095
22887
  }, "error");
22096
22888
  this.connection.send({ type: "agent:status", agentId: msg.agentId, status: "inactive", launchId: msg.launchId });
22097
- this.connection.send({ type: "agent:activity", agentId: msg.agentId, activity: "offline", detail: classification.userMessage, launchId: msg.launchId });
22889
+ this.connection.send({ type: "agent:activity", agentId: msg.agentId, activity: "offline", detail: classification.userMessage, launchId: msg.launchId, observedAtMs: Date.now() });
22098
22890
  });
22099
22891
  break;
22100
22892
  case "agent:stop":
@@ -22514,6 +23306,10 @@ export {
22514
23306
  resolveWorkspaceDirectoryPath,
22515
23307
  scanWorkspaceDirectories,
22516
23308
  deleteWorkspaceDirectory,
23309
+ AGENT_MIGRATION_BUNDLE_SCHEMA_VERSION,
23310
+ buildAgentMigrationExportManifest,
23311
+ AgentMigrationGrantRegistry,
23312
+ createAgentMigrationHttpTransport,
22517
23313
  DAEMON_CORE_TRACE_ATTR_CONTRACTS,
22518
23314
  DAEMON_CLI_USAGE,
22519
23315
  parseDaemonCliArgs,