@moxt-ai/mobius 0.0.20 → 0.0.22

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.
Files changed (37) hide show
  1. package/dist/bots/bot-context-applicator.d.ts +14 -0
  2. package/dist/bots/bot-context-applicator.d.ts.map +1 -0
  3. package/dist/bots/bot-context-applicator.js +32 -0
  4. package/dist/bots/bot-context-applicator.js.map +1 -0
  5. package/dist/bots/bot-execution-context.d.ts +20 -0
  6. package/dist/bots/bot-execution-context.d.ts.map +1 -0
  7. package/dist/bots/bot-execution-context.js +82 -0
  8. package/dist/bots/bot-execution-context.js.map +1 -0
  9. package/dist/bots/bot-message-command.d.ts +6 -0
  10. package/dist/bots/bot-message-command.d.ts.map +1 -0
  11. package/dist/bots/bot-message-command.js +140 -0
  12. package/dist/bots/bot-message-command.js.map +1 -0
  13. package/dist/bots/bot-outbound-ipc.d.ts +12 -0
  14. package/dist/bots/bot-outbound-ipc.d.ts.map +1 -0
  15. package/dist/bots/bot-outbound-ipc.js +245 -0
  16. package/dist/bots/bot-outbound-ipc.js.map +1 -0
  17. package/dist/bots/local-bot-grant-store.d.ts +34 -0
  18. package/dist/bots/local-bot-grant-store.d.ts.map +1 -0
  19. package/dist/bots/local-bot-grant-store.js +263 -0
  20. package/dist/bots/local-bot-grant-store.js.map +1 -0
  21. package/dist/cli.js +1924 -209
  22. package/dist/cli.js.map +4 -4
  23. package/dist/index.d.ts +3 -0
  24. package/dist/index.d.ts.map +1 -1
  25. package/dist/index.js +1970 -264
  26. package/dist/index.js.map +4 -4
  27. package/dist/prompt-artifact-resolver.d.ts +8 -2
  28. package/dist/prompt-artifact-resolver.d.ts.map +1 -1
  29. package/dist/prompt-artifact-resolver.js.map +1 -1
  30. package/dist/relay-connection/session-event-outbox.d.ts +2 -1
  31. package/dist/relay-connection/session-event-outbox.d.ts.map +1 -1
  32. package/dist/relay-connection/session-event-outbox.js +39 -0
  33. package/dist/relay-connection/session-event-outbox.js.map +1 -1
  34. package/dist/run-daemon.d.ts.map +1 -1
  35. package/dist/run-daemon.js +246 -8
  36. package/dist/run-daemon.js.map +1 -1
  37. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -6,12 +6,12 @@ var __export = (target, all) => {
6
6
  };
7
7
 
8
8
  // src/cli.ts
9
- import { mkdir as mkdir4 } from "node:fs/promises";
9
+ import { mkdir as mkdir5 } from "node:fs/promises";
10
10
 
11
11
  // package.json
12
12
  var package_default = {
13
13
  name: "@moxt-ai/mobius",
14
- version: "0.0.20",
14
+ version: "0.0.22",
15
15
  description: "Mobius CLI for pairing and running local AI agent services.",
16
16
  type: "module",
17
17
  bin: {
@@ -1616,7 +1616,7 @@ function isContainedPath3(root, candidate) {
1616
1616
  }
1617
1617
  async function hashFile(path2, signal) {
1618
1618
  signal.throwIfAborted();
1619
- const digest = createHash("sha256");
1619
+ const digest2 = createHash("sha256");
1620
1620
  const stream = createReadStream(path2, { signal });
1621
1621
  try {
1622
1622
  for await (const chunk of stream) {
@@ -1627,9 +1627,9 @@ async function hashFile(path2, signal) {
1627
1627
  "The managed Agent archive produced invalid bytes"
1628
1628
  );
1629
1629
  }
1630
- digest.update(chunk);
1630
+ digest2.update(chunk);
1631
1631
  }
1632
- return digest.digest("hex");
1632
+ return digest2.digest("hex");
1633
1633
  } catch (error61) {
1634
1634
  if (signal.aborted) {
1635
1635
  signal.throwIfAborted();
@@ -2611,6 +2611,164 @@ var AuditStore = class {
2611
2611
  }
2612
2612
  };
2613
2613
 
2614
+ // src/bots/bot-message-command.ts
2615
+ import { randomUUID } from "node:crypto";
2616
+ import { createConnection } from "node:net";
2617
+ var BOT_IPC_RESPONSE_LIMIT = 64 * 1024;
2618
+ var BOT_IPC_TIMEOUT_MILLISECONDS = 2e4;
2619
+ var BotMessageCommandError = class extends Error {
2620
+ code;
2621
+ constructor(code, message, options = {}) {
2622
+ super(message, options);
2623
+ this.code = code;
2624
+ this.name = "BotMessageCommandError";
2625
+ }
2626
+ };
2627
+ function isRecord3(value) {
2628
+ return typeof value === "object" && value !== null && !Array.isArray(value);
2629
+ }
2630
+ function requiredEnvironment(environment, name) {
2631
+ const value = environment[name]?.trim();
2632
+ if (value === void 0 || value.length === 0) {
2633
+ throw new BotMessageCommandError(
2634
+ "execution_context_required",
2635
+ "This command is available only inside an active Mobius Bot execution"
2636
+ );
2637
+ }
2638
+ return value;
2639
+ }
2640
+ function option(arguments_, name) {
2641
+ const index = arguments_.indexOf(name);
2642
+ if (index < 0 || index + 1 >= arguments_.length || arguments_[index + 1]?.startsWith("--") === true) {
2643
+ throw new BotMessageCommandError(
2644
+ "invalid_request",
2645
+ "Usage: mobius bot message send --target <current|alias> --text <message>"
2646
+ );
2647
+ }
2648
+ const value = arguments_[index + 1];
2649
+ if (value === void 0) {
2650
+ throw new BotMessageCommandError("invalid_request", "The Bot message option is missing");
2651
+ }
2652
+ return value;
2653
+ }
2654
+ function validateArguments(arguments_) {
2655
+ if (arguments_.length !== 4) {
2656
+ throw new BotMessageCommandError(
2657
+ "invalid_request",
2658
+ "Usage: mobius bot message send --target <current|alias> --text <message>"
2659
+ );
2660
+ }
2661
+ const names = [arguments_[0], arguments_[2]];
2662
+ if (!names.includes("--target") || !names.includes("--text") || names[0] === names[1]) {
2663
+ throw new BotMessageCommandError(
2664
+ "invalid_request",
2665
+ "Usage: mobius bot message send --target <current|alias> --text <message>"
2666
+ );
2667
+ }
2668
+ }
2669
+ function decodeResponse(encoded) {
2670
+ let value;
2671
+ try {
2672
+ value = JSON.parse(encoded);
2673
+ } catch (cause) {
2674
+ throw new BotMessageCommandError("bot_service_unavailable", "The local Bot service returned invalid data", {
2675
+ cause
2676
+ });
2677
+ }
2678
+ if (!isRecord3(value) || typeof value["ok"] !== "boolean") {
2679
+ throw new BotMessageCommandError("bot_service_unavailable", "The local Bot service returned invalid data");
2680
+ }
2681
+ if (value["ok"] === true && typeof value["outboundMessageId"] === "string") {
2682
+ return value["outboundMessageId"];
2683
+ }
2684
+ const error61 = value["error"];
2685
+ if (value["ok"] === false && isRecord3(error61) && typeof error61["code"] === "string" && typeof error61["message"] === "string") {
2686
+ throw new BotMessageCommandError(error61["code"], error61["message"]);
2687
+ }
2688
+ throw new BotMessageCommandError("bot_service_unavailable", "The local Bot service returned invalid data");
2689
+ }
2690
+ async function requestLocalBotService(socketPath, payload, signal) {
2691
+ signal.throwIfAborted();
2692
+ return await new Promise((resolve5, reject) => {
2693
+ const socket = createConnection(socketPath);
2694
+ const chunks = [];
2695
+ let length = 0;
2696
+ let finished = false;
2697
+ const finish = () => {
2698
+ socket.removeAllListeners();
2699
+ socket.destroy();
2700
+ };
2701
+ const fail = (error61) => {
2702
+ if (finished) {
2703
+ return;
2704
+ }
2705
+ finished = true;
2706
+ finish();
2707
+ if (error61 instanceof BotMessageCommandError) {
2708
+ reject(error61);
2709
+ return;
2710
+ }
2711
+ reject(
2712
+ new BotMessageCommandError(
2713
+ "execution_context_required",
2714
+ "The active Mobius Bot execution is unavailable",
2715
+ { cause: error61 }
2716
+ )
2717
+ );
2718
+ };
2719
+ const abort = () => fail(signal.reason);
2720
+ socket.setTimeout(BOT_IPC_TIMEOUT_MILLISECONDS, () => {
2721
+ fail(new BotMessageCommandError("bot_service_unavailable", "The local Bot service timed out"));
2722
+ });
2723
+ socket.once("error", fail);
2724
+ socket.once("connect", () => socket.end(`${payload}
2725
+ `));
2726
+ socket.on("data", (chunk) => {
2727
+ length += chunk.byteLength;
2728
+ if (length > BOT_IPC_RESPONSE_LIMIT) {
2729
+ fail(new BotMessageCommandError("bot_service_unavailable", "The local Bot response is too large"));
2730
+ return;
2731
+ }
2732
+ chunks.push(chunk);
2733
+ });
2734
+ socket.once("end", () => {
2735
+ if (finished) {
2736
+ return;
2737
+ }
2738
+ finished = true;
2739
+ signal.removeEventListener("abort", abort);
2740
+ try {
2741
+ resolve5(decodeResponse(Buffer.concat(chunks).toString("utf8")));
2742
+ } catch (error61) {
2743
+ reject(error61);
2744
+ } finally {
2745
+ finish();
2746
+ }
2747
+ });
2748
+ signal.addEventListener("abort", abort, { once: true });
2749
+ });
2750
+ }
2751
+ async function executeBotMessageCommand(arguments_, environment, signal) {
2752
+ validateArguments(arguments_);
2753
+ const contextHandle = requiredEnvironment(environment, "MOBIUS_BOT_CONTEXT");
2754
+ const socketPath = requiredEnvironment(environment, "MOBIUS_BOT_SOCKET");
2755
+ const target = option(arguments_, "--target");
2756
+ const text = option(arguments_, "--text");
2757
+ if (!/^[a-zA-Z0-9][a-zA-Z0-9._:-]{0,127}$/.test(target) || text.trim().length === 0 || text.length > 1e4) {
2758
+ throw new BotMessageCommandError("invalid_request", "The Bot outbound message is invalid");
2759
+ }
2760
+ return await requestLocalBotService(
2761
+ socketPath,
2762
+ JSON.stringify({
2763
+ contextHandle,
2764
+ idempotencyKey: `cli_${randomUUID()}`,
2765
+ target,
2766
+ text
2767
+ }),
2768
+ signal
2769
+ );
2770
+ }
2771
+
2614
2772
  // src/config.ts
2615
2773
  import { join as join13 } from "node:path";
2616
2774
 
@@ -6287,7 +6445,7 @@ var $ZodUnion = /* @__PURE__ */ $constructor("$ZodUnion", (inst, def) => {
6287
6445
  defineLazyInternal(inst, "optout", (zod) => zod.def.options.some((o) => o._zod.optout === "optional") ? "optional" : void 0);
6288
6446
  defineLazyInternal(inst, "values", (zod) => {
6289
6447
  if (zod.def.options.every((o) => o._zod.values)) {
6290
- return new Set(zod.def.options.flatMap((option) => Array.from(option._zod.values)));
6448
+ return new Set(zod.def.options.flatMap((option2) => Array.from(option2._zod.values)));
6291
6449
  }
6292
6450
  return void 0;
6293
6451
  });
@@ -6305,8 +6463,8 @@ var $ZodUnion = /* @__PURE__ */ $constructor("$ZodUnion", (inst, def) => {
6305
6463
  }
6306
6464
  let async = false;
6307
6465
  const results = [];
6308
- for (const option of def.options) {
6309
- const result = option._zod.run({
6466
+ for (const option2 of def.options) {
6467
+ const result = option2._zod.run({
6310
6468
  value: payload.value,
6311
6469
  issues: []
6312
6470
  }, ctx);
@@ -6365,8 +6523,8 @@ var $ZodXor = /* @__PURE__ */ $constructor("$ZodXor", (inst, def) => {
6365
6523
  }
6366
6524
  let async = false;
6367
6525
  const results = [];
6368
- for (const option of def.options) {
6369
- const result = option._zod.run({
6526
+ for (const option2 of def.options) {
6527
+ const result = option2._zod.run({
6370
6528
  value: payload.value,
6371
6529
  issues: []
6372
6530
  }, ctx);
@@ -6390,10 +6548,10 @@ function getDiscriminatedOption(union2, value) {
6390
6548
  if (!map2) {
6391
6549
  map2 = /* @__PURE__ */ new Map();
6392
6550
  const { options, discriminator } = internals.def;
6393
- for (const option of options) {
6394
- for (const v of option._zod.propValues?.[discriminator] ?? [])
6551
+ for (const option2 of options) {
6552
+ for (const v of option2._zod.propValues?.[discriminator] ?? [])
6395
6553
  if (!map2.has(v))
6396
- map2.set(v, option);
6554
+ map2.set(v, option2);
6397
6555
  }
6398
6556
  internals.bag.optionsMap = map2;
6399
6557
  }
@@ -6405,10 +6563,10 @@ var $ZodDiscriminatedUnion = /* @__PURE__ */ $constructor("$ZodDiscriminatedUnio
6405
6563
  const _super = inst._zod.parse;
6406
6564
  defineLazyInternal(inst, "propValues", (zod) => {
6407
6565
  const propValues = {};
6408
- for (const option of zod.def.options) {
6409
- const pv = option._zod.propValues;
6566
+ for (const option2 of zod.def.options) {
6567
+ const pv = option2._zod.propValues;
6410
6568
  if (!pv || Object.keys(pv).length === 0)
6411
- throw new Error(`Invalid discriminated union option at index "${zod.def.options.indexOf(option)}"`);
6569
+ throw new Error(`Invalid discriminated union option at index "${zod.def.options.indexOf(option2)}"`);
6412
6570
  for (const [k, v] of Object.entries(pv)) {
6413
6571
  if (!Object.prototype.hasOwnProperty.call(propValues, k)) {
6414
6572
  assignProp(propValues, k, /* @__PURE__ */ new Set());
@@ -6420,8 +6578,8 @@ var $ZodDiscriminatedUnion = /* @__PURE__ */ $constructor("$ZodDiscriminatedUnio
6420
6578
  }
6421
6579
  return propValues;
6422
6580
  });
6423
- def.options.forEach((option, i) => {
6424
- const propShape = propShapes.get(option._zod.def);
6581
+ def.options.forEach((option2, i) => {
6582
+ const propShape = propShapes.get(option2._zod.def);
6425
6583
  if (propShape && !Object.prototype.hasOwnProperty.call(propShape, def.discriminator)) {
6426
6584
  throw new Error(`Invalid discriminated union option at index "${i}"`);
6427
6585
  }
@@ -16352,8 +16510,8 @@ function generateDiscriminatedUnionCheck(doc, ctx, def, accessor) {
16352
16510
  doc.write(`let ${outputVar};`);
16353
16511
  let firstBranch = true;
16354
16512
  const claimed = /* @__PURE__ */ new Set();
16355
- for (const option of def.options) {
16356
- const values = option._zod.propValues?.[def.discriminator];
16513
+ for (const option2 of def.options) {
16514
+ const values = option2._zod.propValues?.[def.discriminator];
16357
16515
  if (!values || values.size === 0) {
16358
16516
  throw new ZodCompileUnsupportedError("discriminated union option without static discriminator values");
16359
16517
  }
@@ -16367,7 +16525,7 @@ function generateDiscriminatedUnionCheck(doc, ctx, def, accessor) {
16367
16525
  const prefix = firstBranch ? "if" : "else if";
16368
16526
  doc.write(`${prefix} (${conditions.join(" || ")}) {`);
16369
16527
  doc.indented((d) => {
16370
- const branchOutput = generateCheck(d, ctx, option, accessor);
16528
+ const branchOutput = generateCheck(d, ctx, option2, accessor);
16371
16529
  d.write(`${outputVar} = ${branchOutput};`);
16372
16530
  });
16373
16531
  doc.write(`}`);
@@ -17917,14 +18075,14 @@ function compactTypeUnion(schema) {
17917
18075
  if (!Array.isArray(options) || options.length === 0 || schema.type !== void 0)
17918
18076
  return;
17919
18077
  const types = [];
17920
- for (const option of options) {
17921
- if (!option || typeof option !== "object")
18078
+ for (const option2 of options) {
18079
+ if (!option2 || typeof option2 !== "object")
17922
18080
  return;
17923
- compactTypeUnion(option);
17924
- const keys = Object.keys(option);
18081
+ compactTypeUnion(option2);
18082
+ const keys = Object.keys(option2);
17925
18083
  if (keys.length !== 1 || keys[0] !== "type")
17926
18084
  return;
17927
- const type = option.type;
18085
+ const type = option2.type;
17928
18086
  for (const member of Array.isArray(type) ? type : [type]) {
17929
18087
  if (typeof member !== "string")
17930
18088
  return;
@@ -18214,8 +18372,8 @@ function isTransforming(_schema, _ctx) {
18214
18372
  return false;
18215
18373
  }
18216
18374
  if (def.type === "union") {
18217
- for (const option of def.options) {
18218
- if (isTransforming(option, ctx))
18375
+ for (const option2 of def.options) {
18376
+ if (isTransforming(option2, ctx))
18219
18377
  return true;
18220
18378
  }
18221
18379
  return false;
@@ -21956,7 +22114,7 @@ var ProtocolMessageError = class extends Error {
21956
22114
  this.name = "ProtocolMessageError";
21957
22115
  }
21958
22116
  };
21959
- function isRecord3(value) {
22117
+ function isRecord4(value) {
21960
22118
  return typeof value === "object" && value !== null && !Array.isArray(value);
21961
22119
  }
21962
22120
  function parseJson2(encoded) {
@@ -21968,7 +22126,7 @@ function parseJson2(encoded) {
21968
22126
  cause: error61
21969
22127
  });
21970
22128
  }
21971
- if (!isRecord3(value)) {
22129
+ if (!isRecord4(value)) {
21972
22130
  throw new ProtocolMessageError("Message must be a JSON object");
21973
22131
  }
21974
22132
  return value;
@@ -22052,7 +22210,7 @@ function readActivityContent(value) {
22052
22210
  }
22053
22211
  function readActivityDetail(value) {
22054
22212
  const field = value["detail"];
22055
- if (!isRecord3(field)) {
22213
+ if (!isRecord4(field)) {
22056
22214
  throw new ProtocolMessageError("Invalid activity detail field");
22057
22215
  }
22058
22216
  const kind = readString(field, "kind", 32);
@@ -22291,6 +22449,487 @@ function encodeSessionFailedEvent(message) {
22291
22449
  return JSON.stringify(decodeSessionFailedEvent(JSON.stringify(message)));
22292
22450
  }
22293
22451
 
22452
+ // ../protocol/src/bot.ts
22453
+ var BOT_BINDING_APPROVAL_REQUEST_KIND = "bot.binding.approval.request";
22454
+ var BOT_BINDING_APPROVED_KIND = "bot.binding.approved";
22455
+ var BOT_BINDING_UNAVAILABLE_KIND = "bot.binding.unavailable";
22456
+ var BOT_SESSION_PROMPT_KIND = "bot.session.prompt";
22457
+ var IDENTIFIER_PATTERN3 = /^[a-zA-Z0-9][a-zA-Z0-9._:-]{0,127}$/;
22458
+ var DIRECTORY_IDENTIFIER_PATTERN3 = /^[a-zA-Z0-9][a-zA-Z0-9_-]{0,2047}$/;
22459
+ var TOKEN_PATTERN = /^[a-zA-Z0-9_-]{32,256}$/;
22460
+ var SHA256_PATTERN = /^[a-f0-9]{64}$/;
22461
+ var MAX_INSTRUCTIONS_LENGTH = 1e5;
22462
+ var BotDeliveryTargetReference = class {
22463
+ alias;
22464
+ deliveryTargetId;
22465
+ constructor(alias, deliveryTargetId) {
22466
+ this.alias = alias;
22467
+ this.deliveryTargetId = deliveryTargetId;
22468
+ }
22469
+ };
22470
+ var BotCompletionDeliveryPolicy = class {
22471
+ };
22472
+ var NoBotCompletionDeliveryPolicy = class extends BotCompletionDeliveryPolicy {
22473
+ kind = "none";
22474
+ };
22475
+ var RequiredBotCompletionDeliveryPolicy = class extends BotCompletionDeliveryPolicy {
22476
+ deliveryTargetId;
22477
+ kind = "required";
22478
+ messageTemplate;
22479
+ constructor(deliveryTargetId, messageTemplate) {
22480
+ super();
22481
+ this.deliveryTargetId = deliveryTargetId;
22482
+ this.messageTemplate = messageTemplate;
22483
+ }
22484
+ };
22485
+ var BotReplyRoute = class {
22486
+ };
22487
+ var OwnerBotReplyRoute = class extends BotReplyRoute {
22488
+ kind = "owner";
22489
+ };
22490
+ var BotConnectionReplyRoute = class extends BotReplyRoute {
22491
+ connectionId;
22492
+ deliveryTargetId;
22493
+ kind = "connection";
22494
+ constructor(connectionId, deliveryTargetId) {
22495
+ super();
22496
+ this.connectionId = connectionId;
22497
+ this.deliveryTargetId = deliveryTargetId;
22498
+ }
22499
+ };
22500
+ var BotExecutionBindingApprovalRequest = class {
22501
+ agentConfigRevision;
22502
+ agentRef;
22503
+ allowedDeliveryTargets;
22504
+ behaviorDigest;
22505
+ behaviorInstructions;
22506
+ behaviorRevisionId;
22507
+ bindingId;
22508
+ bindingRevision;
22509
+ botId;
22510
+ completionPolicy;
22511
+ kind = BOT_BINDING_APPROVAL_REQUEST_KIND;
22512
+ requestId;
22513
+ requiredCapabilities;
22514
+ runtimeId;
22515
+ workspaceRef;
22516
+ constructor(requestId, botId, behaviorRevisionId, bindingId, bindingRevision, runtimeId, agentRef, workspaceRef, agentConfigRevision, behaviorInstructions, behaviorDigest, requiredCapabilities, allowedDeliveryTargets, completionPolicy) {
22517
+ this.requestId = requestId;
22518
+ this.botId = botId;
22519
+ this.behaviorRevisionId = behaviorRevisionId;
22520
+ this.bindingId = bindingId;
22521
+ this.bindingRevision = bindingRevision;
22522
+ this.runtimeId = runtimeId;
22523
+ this.agentRef = agentRef;
22524
+ this.workspaceRef = workspaceRef;
22525
+ this.agentConfigRevision = agentConfigRevision;
22526
+ this.behaviorInstructions = behaviorInstructions;
22527
+ this.behaviorDigest = behaviorDigest;
22528
+ this.requiredCapabilities = Object.freeze([...requiredCapabilities]);
22529
+ this.allowedDeliveryTargets = Object.freeze(
22530
+ allowedDeliveryTargets.map(
22531
+ (target) => new BotDeliveryTargetReference(target.alias, target.deliveryTargetId)
22532
+ )
22533
+ );
22534
+ this.completionPolicy = completionPolicy;
22535
+ }
22536
+ };
22537
+ var BotExecutionBindingApprovedEvent = class {
22538
+ agentIdentityDigest;
22539
+ behaviorRevisionId;
22540
+ bindingId;
22541
+ bindingRevision;
22542
+ botId;
22543
+ kind = BOT_BINDING_APPROVED_KIND;
22544
+ localGrantId;
22545
+ requestId;
22546
+ workspaceIdentityDigest;
22547
+ constructor(requestId, botId, behaviorRevisionId, bindingId, bindingRevision, localGrantId, agentIdentityDigest, workspaceIdentityDigest) {
22548
+ this.requestId = requestId;
22549
+ this.botId = botId;
22550
+ this.behaviorRevisionId = behaviorRevisionId;
22551
+ this.bindingId = bindingId;
22552
+ this.bindingRevision = bindingRevision;
22553
+ this.localGrantId = localGrantId;
22554
+ this.agentIdentityDigest = agentIdentityDigest;
22555
+ this.workspaceIdentityDigest = workspaceIdentityDigest;
22556
+ }
22557
+ };
22558
+ var BotExecutionBindingUnavailableEvent = class {
22559
+ behaviorRevisionId;
22560
+ bindingId;
22561
+ bindingRevision;
22562
+ botId;
22563
+ code;
22564
+ kind = BOT_BINDING_UNAVAILABLE_KIND;
22565
+ message;
22566
+ requestId;
22567
+ constructor(requestId, botId, behaviorRevisionId, bindingId, bindingRevision, code, message) {
22568
+ this.requestId = requestId;
22569
+ this.botId = botId;
22570
+ this.behaviorRevisionId = behaviorRevisionId;
22571
+ this.bindingId = bindingId;
22572
+ this.bindingRevision = bindingRevision;
22573
+ this.code = code;
22574
+ this.message = message;
22575
+ }
22576
+ };
22577
+ var BotSessionPromptCommand = class {
22578
+ additionalDirectoryIds;
22579
+ agentId;
22580
+ allowedDeliveryTargets;
22581
+ behaviorDigest;
22582
+ behaviorInstructions;
22583
+ behaviorRevisionId;
22584
+ bindingId;
22585
+ bindingRevision;
22586
+ botId;
22587
+ commandId;
22588
+ conversationId;
22589
+ directoryId;
22590
+ executionCapabilityId;
22591
+ executionCapabilitySecret;
22592
+ executionDeadlineAt;
22593
+ executionId;
22594
+ images;
22595
+ kind = BOT_SESSION_PROMPT_KIND;
22596
+ localGrantId;
22597
+ prompt;
22598
+ replyRoute;
22599
+ resources;
22600
+ sessionId;
22601
+ turnId;
22602
+ constructor(sessionId, commandId, agentId, bindingId, directoryId2, additionalDirectoryIds, images, resources, prompt, executionId, executionCapabilityId, executionCapabilitySecret, executionDeadlineAt, botId, conversationId, turnId, behaviorRevisionId, bindingRevision, localGrantId, behaviorInstructions, behaviorDigest, allowedDeliveryTargets, replyRoute) {
22603
+ this.sessionId = sessionId;
22604
+ this.commandId = commandId;
22605
+ this.agentId = agentId;
22606
+ this.bindingId = bindingId;
22607
+ this.directoryId = directoryId2;
22608
+ this.additionalDirectoryIds = Object.freeze([...additionalDirectoryIds]);
22609
+ this.images = Object.freeze([...images]);
22610
+ this.resources = Object.freeze([...resources]);
22611
+ this.prompt = prompt;
22612
+ this.executionId = executionId;
22613
+ this.executionCapabilityId = executionCapabilityId;
22614
+ this.executionCapabilitySecret = executionCapabilitySecret;
22615
+ this.executionDeadlineAt = executionDeadlineAt;
22616
+ this.botId = botId;
22617
+ this.conversationId = conversationId;
22618
+ this.turnId = turnId;
22619
+ this.behaviorRevisionId = behaviorRevisionId;
22620
+ this.bindingRevision = bindingRevision;
22621
+ this.localGrantId = localGrantId;
22622
+ this.behaviorInstructions = behaviorInstructions;
22623
+ this.behaviorDigest = behaviorDigest;
22624
+ this.allowedDeliveryTargets = Object.freeze(
22625
+ allowedDeliveryTargets.map(
22626
+ (target) => new BotDeliveryTargetReference(target.alias, target.deliveryTargetId)
22627
+ )
22628
+ );
22629
+ this.replyRoute = replyRoute;
22630
+ }
22631
+ };
22632
+ function isRecord5(value) {
22633
+ return typeof value === "object" && value !== null && !Array.isArray(value);
22634
+ }
22635
+ function parseJson3(encoded) {
22636
+ let value;
22637
+ try {
22638
+ value = JSON.parse(encoded);
22639
+ } catch (cause) {
22640
+ throw new ProtocolMessageError("Message is not valid JSON", { cause });
22641
+ }
22642
+ if (!isRecord5(value)) {
22643
+ throw new ProtocolMessageError("Message must be a JSON object");
22644
+ }
22645
+ return value;
22646
+ }
22647
+ function assertExactKeys2(value, expected) {
22648
+ const keys = Object.keys(value);
22649
+ if (keys.length !== expected.length || keys.some((key) => !expected.includes(key))) {
22650
+ throw new ProtocolMessageError("Message fields do not match the Bot protocol");
22651
+ }
22652
+ }
22653
+ function readText2(value, key, maximumLength, allowEmpty) {
22654
+ const field = value[key];
22655
+ if (typeof field !== "string" || field.length > maximumLength || !allowEmpty && field.length === 0) {
22656
+ throw new ProtocolMessageError(`Invalid Bot protocol field: ${key}`);
22657
+ }
22658
+ return field;
22659
+ }
22660
+ function readIdentifier2(value, key) {
22661
+ const field = readText2(value, key, 128, false);
22662
+ if (!IDENTIFIER_PATTERN3.test(field)) {
22663
+ throw new ProtocolMessageError(`Invalid Bot identifier field: ${key}`);
22664
+ }
22665
+ return field;
22666
+ }
22667
+ function readDirectoryIdentifier2(value, key) {
22668
+ const field = readText2(value, key, 2048, false);
22669
+ if (!DIRECTORY_IDENTIFIER_PATTERN3.test(field)) {
22670
+ throw new ProtocolMessageError(`Invalid Bot directory field: ${key}`);
22671
+ }
22672
+ return field;
22673
+ }
22674
+ function readInteger(value, key) {
22675
+ const field = value[key];
22676
+ if (typeof field !== "number" || !Number.isSafeInteger(field) || field < 1) {
22677
+ throw new ProtocolMessageError(`Invalid Bot integer field: ${key}`);
22678
+ }
22679
+ return field;
22680
+ }
22681
+ function readTimestamp(value, key) {
22682
+ const field = readText2(value, key, 64, false);
22683
+ if (Number.isNaN(Date.parse(field))) {
22684
+ throw new ProtocolMessageError(`Invalid Bot timestamp field: ${key}`);
22685
+ }
22686
+ return field;
22687
+ }
22688
+ function readDigest(value, key) {
22689
+ const field = readText2(value, key, 64, false);
22690
+ if (!SHA256_PATTERN.test(field)) {
22691
+ throw new ProtocolMessageError(`Invalid Bot digest field: ${key}`);
22692
+ }
22693
+ return field;
22694
+ }
22695
+ function readToken(value, key) {
22696
+ const field = readText2(value, key, 256, false);
22697
+ if (!TOKEN_PATTERN.test(field)) {
22698
+ throw new ProtocolMessageError(`Invalid Bot token field: ${key}`);
22699
+ }
22700
+ return field;
22701
+ }
22702
+ function readIdentifiers(value, key, maximumCount) {
22703
+ const field = value[key];
22704
+ if (!Array.isArray(field) || field.length > maximumCount) {
22705
+ throw new ProtocolMessageError(`Invalid Bot identifier list: ${key}`);
22706
+ }
22707
+ const identifiers = [];
22708
+ const unique = /* @__PURE__ */ new Set();
22709
+ for (const candidate of field) {
22710
+ if (typeof candidate !== "string" || !IDENTIFIER_PATTERN3.test(candidate) || unique.has(candidate)) {
22711
+ throw new ProtocolMessageError(`Invalid Bot identifier list: ${key}`);
22712
+ }
22713
+ unique.add(candidate);
22714
+ identifiers.push(candidate);
22715
+ }
22716
+ return Object.freeze(identifiers);
22717
+ }
22718
+ function readTargets(value, key) {
22719
+ const field = value[key];
22720
+ if (!Array.isArray(field) || field.length > 64) {
22721
+ throw new ProtocolMessageError(`Invalid Bot delivery targets: ${key}`);
22722
+ }
22723
+ const targets = [];
22724
+ const identifiers = /* @__PURE__ */ new Set();
22725
+ const aliases = /* @__PURE__ */ new Set();
22726
+ for (const candidate of field) {
22727
+ if (!isRecord5(candidate)) {
22728
+ throw new ProtocolMessageError(`Invalid Bot delivery targets: ${key}`);
22729
+ }
22730
+ assertExactKeys2(candidate, ["alias", "deliveryTargetId"]);
22731
+ const alias = readIdentifier2(candidate, "alias");
22732
+ const deliveryTargetId = readIdentifier2(candidate, "deliveryTargetId");
22733
+ if (aliases.has(alias) || identifiers.has(deliveryTargetId)) {
22734
+ throw new ProtocolMessageError(`Duplicate Bot delivery target: ${key}`);
22735
+ }
22736
+ aliases.add(alias);
22737
+ identifiers.add(deliveryTargetId);
22738
+ targets.push(new BotDeliveryTargetReference(alias, deliveryTargetId));
22739
+ }
22740
+ return Object.freeze(targets);
22741
+ }
22742
+ function readCompletionPolicy(value) {
22743
+ if (!isRecord5(value)) {
22744
+ throw new ProtocolMessageError("Invalid Bot completion policy");
22745
+ }
22746
+ const kind = readText2(value, "kind", 32, false);
22747
+ if (kind === "none") {
22748
+ assertExactKeys2(value, ["kind"]);
22749
+ return new NoBotCompletionDeliveryPolicy();
22750
+ }
22751
+ if (kind === "required") {
22752
+ assertExactKeys2(value, ["deliveryTargetId", "kind", "messageTemplate"]);
22753
+ return new RequiredBotCompletionDeliveryPolicy(
22754
+ readIdentifier2(value, "deliveryTargetId"),
22755
+ readText2(value, "messageTemplate", 1e4, false)
22756
+ );
22757
+ }
22758
+ throw new ProtocolMessageError("Invalid Bot completion policy");
22759
+ }
22760
+ function readReplyRoute(value) {
22761
+ if (!isRecord5(value)) {
22762
+ throw new ProtocolMessageError("Invalid Bot reply route");
22763
+ }
22764
+ const kind = readText2(value, "kind", 32, false);
22765
+ if (kind === "owner") {
22766
+ assertExactKeys2(value, ["kind"]);
22767
+ return new OwnerBotReplyRoute();
22768
+ }
22769
+ if (kind === "connection") {
22770
+ assertExactKeys2(value, ["connectionId", "deliveryTargetId", "kind"]);
22771
+ return new BotConnectionReplyRoute(
22772
+ readIdentifier2(value, "connectionId"),
22773
+ readIdentifier2(value, "deliveryTargetId")
22774
+ );
22775
+ }
22776
+ throw new ProtocolMessageError("Invalid Bot reply route");
22777
+ }
22778
+ function decodeBotExecutionBindingApprovalRequest(encoded) {
22779
+ const value = parseJson3(encoded);
22780
+ assertExactKeys2(value, [
22781
+ "agentConfigRevision",
22782
+ "agentRef",
22783
+ "allowedDeliveryTargets",
22784
+ "behaviorDigest",
22785
+ "behaviorInstructions",
22786
+ "behaviorRevisionId",
22787
+ "bindingId",
22788
+ "bindingRevision",
22789
+ "botId",
22790
+ "completionPolicy",
22791
+ "kind",
22792
+ "requestId",
22793
+ "requiredCapabilities",
22794
+ "runtimeId",
22795
+ "workspaceRef"
22796
+ ]);
22797
+ if (value["kind"] !== BOT_BINDING_APPROVAL_REQUEST_KIND) {
22798
+ throw new ProtocolMessageError("Invalid Bot binding approval request kind");
22799
+ }
22800
+ return new BotExecutionBindingApprovalRequest(
22801
+ readIdentifier2(value, "requestId"),
22802
+ readIdentifier2(value, "botId"),
22803
+ readIdentifier2(value, "behaviorRevisionId"),
22804
+ readIdentifier2(value, "bindingId"),
22805
+ readInteger(value, "bindingRevision"),
22806
+ readIdentifier2(value, "runtimeId"),
22807
+ readIdentifier2(value, "agentRef"),
22808
+ readDirectoryIdentifier2(value, "workspaceRef"),
22809
+ readInteger(value, "agentConfigRevision"),
22810
+ readText2(value, "behaviorInstructions", MAX_INSTRUCTIONS_LENGTH, true),
22811
+ readDigest(value, "behaviorDigest"),
22812
+ readIdentifiers(value, "requiredCapabilities", 32),
22813
+ readTargets(value, "allowedDeliveryTargets"),
22814
+ readCompletionPolicy(value["completionPolicy"])
22815
+ );
22816
+ }
22817
+ function decodeBotExecutionBindingApprovedEvent(encoded) {
22818
+ const value = parseJson3(encoded);
22819
+ assertExactKeys2(value, [
22820
+ "agentIdentityDigest",
22821
+ "behaviorRevisionId",
22822
+ "bindingId",
22823
+ "bindingRevision",
22824
+ "botId",
22825
+ "kind",
22826
+ "localGrantId",
22827
+ "requestId",
22828
+ "workspaceIdentityDigest"
22829
+ ]);
22830
+ if (value["kind"] !== BOT_BINDING_APPROVED_KIND) {
22831
+ throw new ProtocolMessageError("Invalid Bot binding approval event kind");
22832
+ }
22833
+ return new BotExecutionBindingApprovedEvent(
22834
+ readIdentifier2(value, "requestId"),
22835
+ readIdentifier2(value, "botId"),
22836
+ readIdentifier2(value, "behaviorRevisionId"),
22837
+ readIdentifier2(value, "bindingId"),
22838
+ readInteger(value, "bindingRevision"),
22839
+ readIdentifier2(value, "localGrantId"),
22840
+ readDigest(value, "agentIdentityDigest"),
22841
+ readDigest(value, "workspaceIdentityDigest")
22842
+ );
22843
+ }
22844
+ function encodeBotExecutionBindingApprovedEvent(event) {
22845
+ return JSON.stringify(decodeBotExecutionBindingApprovedEvent(JSON.stringify(event)));
22846
+ }
22847
+ function decodeBotExecutionBindingUnavailableEvent(encoded) {
22848
+ const value = parseJson3(encoded);
22849
+ assertExactKeys2(value, [
22850
+ "behaviorRevisionId",
22851
+ "bindingId",
22852
+ "bindingRevision",
22853
+ "botId",
22854
+ "code",
22855
+ "kind",
22856
+ "message",
22857
+ "requestId"
22858
+ ]);
22859
+ if (value["kind"] !== BOT_BINDING_UNAVAILABLE_KIND) {
22860
+ throw new ProtocolMessageError("Invalid Bot binding unavailable event kind");
22861
+ }
22862
+ return new BotExecutionBindingUnavailableEvent(
22863
+ readIdentifier2(value, "requestId"),
22864
+ readIdentifier2(value, "botId"),
22865
+ readIdentifier2(value, "behaviorRevisionId"),
22866
+ readIdentifier2(value, "bindingId"),
22867
+ readInteger(value, "bindingRevision"),
22868
+ readIdentifier2(value, "code"),
22869
+ readText2(value, "message", 500, false)
22870
+ );
22871
+ }
22872
+ function encodeBotExecutionBindingUnavailableEvent(event) {
22873
+ return JSON.stringify(decodeBotExecutionBindingUnavailableEvent(JSON.stringify(event)));
22874
+ }
22875
+ function decodeBotSessionPromptCommand(encoded) {
22876
+ const value = parseJson3(encoded);
22877
+ assertExactKeys2(value, [
22878
+ "additionalDirectoryIds",
22879
+ "agentId",
22880
+ "allowedDeliveryTargets",
22881
+ "behaviorDigest",
22882
+ "behaviorInstructions",
22883
+ "behaviorRevisionId",
22884
+ "bindingId",
22885
+ "bindingRevision",
22886
+ "botId",
22887
+ "commandId",
22888
+ "conversationId",
22889
+ "directoryId",
22890
+ "executionCapabilityId",
22891
+ "executionCapabilitySecret",
22892
+ "executionDeadlineAt",
22893
+ "executionId",
22894
+ "images",
22895
+ "kind",
22896
+ "localGrantId",
22897
+ "prompt",
22898
+ "replyRoute",
22899
+ "resources",
22900
+ "sessionId",
22901
+ "turnId"
22902
+ ]);
22903
+ if (value["kind"] !== BOT_SESSION_PROMPT_KIND) {
22904
+ throw new ProtocolMessageError("Invalid Bot Session prompt kind");
22905
+ }
22906
+ return new BotSessionPromptCommand(
22907
+ readIdentifier2(value, "sessionId"),
22908
+ readIdentifier2(value, "commandId"),
22909
+ readIdentifier2(value, "agentId"),
22910
+ readIdentifier2(value, "bindingId"),
22911
+ readDirectoryIdentifier2(value, "directoryId"),
22912
+ readIdentifiers(value, "additionalDirectoryIds", 16),
22913
+ decodePromptImagesValue(value["images"]),
22914
+ decodePromptResourcesValue(value["resources"]),
22915
+ readText2(value, "prompt", 1e4, false),
22916
+ readIdentifier2(value, "executionId"),
22917
+ readIdentifier2(value, "executionCapabilityId"),
22918
+ readToken(value, "executionCapabilitySecret"),
22919
+ readTimestamp(value, "executionDeadlineAt"),
22920
+ readIdentifier2(value, "botId"),
22921
+ readIdentifier2(value, "conversationId"),
22922
+ readIdentifier2(value, "turnId"),
22923
+ readIdentifier2(value, "behaviorRevisionId"),
22924
+ readInteger(value, "bindingRevision"),
22925
+ readIdentifier2(value, "localGrantId"),
22926
+ readText2(value, "behaviorInstructions", MAX_INSTRUCTIONS_LENGTH, true),
22927
+ readDigest(value, "behaviorDigest"),
22928
+ readTargets(value, "allowedDeliveryTargets"),
22929
+ readReplyRoute(value["replyRoute"])
22930
+ );
22931
+ }
22932
+
22294
22933
  // ../protocol/src/mobius-api.ts
22295
22934
  var MOBIUS_API_PREFIX = "/mobius/api";
22296
22935
  var API_PREFIX_PATTERN = /^\/[a-zA-Z0-9._~-]+(?:\/[a-zA-Z0-9._~-]+)*$/;
@@ -22464,13 +23103,18 @@ var decodeNativeSessionCancel = (encoded) => decode4(nativeSessionCancelSchema,
22464
23103
  var SESSION_EVENT_KIND = "session.event";
22465
23104
  var SESSION_EVENT_ACK_KIND = "session.event.ack";
22466
23105
  var SESSION_EVENT_COMMITTED_KIND = "session.event.committed";
22467
- var IDENTIFIER_PATTERN3 = /^[a-zA-Z0-9][a-zA-Z0-9._:-]{0,127}$/;
23106
+ var SESSION_EVENT_REJECTED_KIND = "session.event.rejected";
23107
+ var SessionEventRejectionCode = {
23108
+ SessionDeleted: "session_deleted",
23109
+ SessionNotFound: "session_not_found"
23110
+ };
23111
+ var IDENTIFIER_PATTERN4 = /^[a-zA-Z0-9][a-zA-Z0-9._:-]{0,127}$/;
22468
23112
  var CURSOR_PATTERN = /^[A-Za-z0-9_-]{1,512}$/;
22469
23113
  var MAX_RECORDED_EVENT_LENGTH = 8 * 1024 * 1024;
22470
23114
  var DECIMAL_SEQUENCE_PATTERN = /^(?:0|[1-9][0-9]*)$/;
22471
23115
  var eventSourceSchema = external_exports.discriminatedUnion("kind", [
22472
23116
  external_exports.strictObject({
22473
- attemptId: external_exports.string().min(1).max(128).regex(IDENTIFIER_PATTERN3),
23117
+ attemptId: external_exports.string().min(1).max(128).regex(IDENTIFIER_PATTERN4),
22474
23118
  kind: external_exports.literal("attempt"),
22475
23119
  sourceSeq: external_exports.string().min(1).max(40).regex(DECIMAL_SEQUENCE_PATTERN)
22476
23120
  }).readonly(),
@@ -22480,29 +23124,35 @@ var eventSourceSchema = external_exports.discriminatedUnion("kind", [
22480
23124
  }).readonly()
22481
23125
  ]);
22482
23126
  var eventEnvelopeSchema = external_exports.strictObject({
22483
- eventId: external_exports.string().min(1).max(128).regex(IDENTIFIER_PATTERN3),
23127
+ eventId: external_exports.string().min(1).max(128).regex(IDENTIFIER_PATTERN4),
22484
23128
  kind: external_exports.literal(SESSION_EVENT_KIND),
22485
23129
  payload: external_exports.string().min(2).max(MAX_RECORDED_EVENT_LENGTH),
22486
- sessionId: external_exports.string().min(1).max(128).regex(IDENTIFIER_PATTERN3),
23130
+ sessionId: external_exports.string().min(1).max(128).regex(IDENTIFIER_PATTERN4),
22487
23131
  source: eventSourceSchema
22488
23132
  }).readonly();
22489
23133
  var committedEventSchema = external_exports.strictObject({
22490
23134
  cursor: external_exports.string().min(1).max(512).regex(CURSOR_PATTERN),
22491
- eventId: external_exports.string().min(1).max(128).regex(IDENTIFIER_PATTERN3),
23135
+ eventId: external_exports.string().min(1).max(128).regex(IDENTIFIER_PATTERN4),
22492
23136
  kind: external_exports.literal(SESSION_EVENT_COMMITTED_KIND),
22493
23137
  payload: external_exports.string().min(2).max(MAX_RECORDED_EVENT_LENGTH),
22494
23138
  recordedAt: external_exports.string().datetime({ offset: true }),
22495
23139
  sequence: external_exports.string().min(1).max(40).regex(DECIMAL_SEQUENCE_PATTERN),
22496
- sessionId: external_exports.string().min(1).max(128).regex(IDENTIFIER_PATTERN3),
23140
+ sessionId: external_exports.string().min(1).max(128).regex(IDENTIFIER_PATTERN4),
22497
23141
  source: eventSourceSchema
22498
23142
  }).readonly();
22499
23143
  var eventAcknowledgementSchema = external_exports.strictObject({
22500
23144
  cursor: external_exports.string().min(1).max(512).regex(CURSOR_PATTERN),
22501
23145
  duplicate: external_exports.boolean(),
22502
- eventId: external_exports.string().min(1).max(128).regex(IDENTIFIER_PATTERN3),
23146
+ eventId: external_exports.string().min(1).max(128).regex(IDENTIFIER_PATTERN4),
22503
23147
  kind: external_exports.literal(SESSION_EVENT_ACK_KIND),
22504
23148
  sequence: external_exports.string().min(1).max(40).regex(DECIMAL_SEQUENCE_PATTERN),
22505
- sessionId: external_exports.string().min(1).max(128).regex(IDENTIFIER_PATTERN3)
23149
+ sessionId: external_exports.string().min(1).max(128).regex(IDENTIFIER_PATTERN4)
23150
+ }).readonly();
23151
+ var eventRejectionSchema = external_exports.strictObject({
23152
+ code: external_exports.enum(SessionEventRejectionCode),
23153
+ eventId: external_exports.string().min(1).max(128).regex(IDENTIFIER_PATTERN4),
23154
+ kind: external_exports.literal(SESSION_EVENT_REJECTED_KIND),
23155
+ sessionId: external_exports.string().min(1).max(128).regex(IDENTIFIER_PATTERN4)
22506
23156
  }).readonly();
22507
23157
  function decode5(encoded, schema) {
22508
23158
  let value;
@@ -22530,6 +23180,7 @@ var encode4 = (message, schema) => {
22530
23180
  };
22531
23181
  var encodeSessionEventEnvelope = (message) => encode4(message, eventEnvelopeSchema);
22532
23182
  var decodeSessionEventAcknowledgement = (encoded) => decode5(encoded, eventAcknowledgementSchema);
23183
+ var decodeSessionEventRejection = (encoded) => decode5(encoded, eventRejectionSchema);
22533
23184
 
22534
23185
  // src/config.ts
22535
23186
  function loadDefaultWorkspace() {
@@ -22550,15 +23201,15 @@ function createDaemonConfig(connection, agents = [], installableAgents = []) {
22550
23201
  }
22551
23202
 
22552
23203
  // src/pairing/pair-local-machine.ts
22553
- import { randomUUID } from "node:crypto";
23204
+ import { randomUUID as randomUUID2 } from "node:crypto";
22554
23205
  import { mkdir as mkdir3, open as open4, realpath as realpath6, rename as rename3, stat as stat5, writeFile as writeFile2 } from "node:fs/promises";
22555
23206
  import { hostname as hostname3 } from "node:os";
22556
23207
  import { basename, join as join14, resolve as resolve3 } from "node:path";
22557
23208
  import { fetch as fetch2 } from "undici";
22558
23209
  var PAIRING_TIMEOUT_MILLISECONDS = 2e4;
22559
23210
  var PAIRING_CODE_PATTERN = /^[A-HJ-NP-Z2-9]{4}(?:-[A-HJ-NP-Z2-9]{4}){4}$/;
22560
- var IDENTIFIER_PATTERN4 = /^[a-zA-Z0-9][a-zA-Z0-9._:-]{0,127}$/;
22561
- var TOKEN_PATTERN = /^[a-zA-Z0-9_-]{32,256}$/;
23211
+ var IDENTIFIER_PATTERN5 = /^[a-zA-Z0-9][a-zA-Z0-9._:-]{0,127}$/;
23212
+ var TOKEN_PATTERN2 = /^[a-zA-Z0-9_-]{32,256}$/;
22562
23213
  var MAX_CONNECTION_FILE_LENGTH = 16 * 1024;
22563
23214
  var CLAIM_RESPONSE_KEYS = ["channelId", "daemonToken", "runtimeId"];
22564
23215
  var SAVED_CONNECTION_KEYS = ["defaultWorkspace", "channelId", "daemonToken", "relayOrigin"];
@@ -22570,36 +23221,36 @@ var PairingClientError = class extends Error {
22570
23221
  this.name = "PairingClientError";
22571
23222
  }
22572
23223
  };
22573
- function isRecord4(value) {
23224
+ function isRecord6(value) {
22574
23225
  return typeof value === "object" && value !== null && !Array.isArray(value);
22575
23226
  }
22576
23227
  function hasExactKeys(value, expectedKeys) {
22577
23228
  const keys = Object.keys(value);
22578
23229
  return keys.length === expectedKeys.length && expectedKeys.every((key) => Object.hasOwn(value, key));
22579
23230
  }
22580
- function readSingleOption(arguments_, option) {
23231
+ function readSingleOption(arguments_, option2) {
22581
23232
  const values = [];
22582
23233
  for (let index = 0; index < arguments_.length; index += 1) {
22583
- if (arguments_[index] !== option) {
23234
+ if (arguments_[index] !== option2) {
22584
23235
  continue;
22585
23236
  }
22586
23237
  const value = arguments_[index + 1];
22587
23238
  if (value === void 0 || value.startsWith("--")) {
22588
- throw new PairingClientError("invalid_arguments", `${option} requires a value`);
23239
+ throw new PairingClientError("invalid_arguments", `${option2} requires a value`);
22589
23240
  }
22590
23241
  values.push(value);
22591
23242
  index += 1;
22592
23243
  }
22593
23244
  if (values.length !== 1) {
22594
- throw new PairingClientError("invalid_arguments", `${option} must be provided exactly once`);
23245
+ throw new PairingClientError("invalid_arguments", `${option2} must be provided exactly once`);
22595
23246
  }
22596
23247
  return values[0] ?? "";
22597
23248
  }
22598
23249
  function assertKnownArguments(arguments_) {
22599
23250
  for (let index = 0; index < arguments_.length; index += 2) {
22600
- const option = arguments_[index];
22601
- if (option !== "--url" && option !== "--code" && option !== "--workspace") {
22602
- throw new PairingClientError("invalid_arguments", `Unknown pairing option: ${option ?? "missing option"}`);
23251
+ const option2 = arguments_[index];
23252
+ if (option2 !== "--url" && option2 !== "--code" && option2 !== "--workspace") {
23253
+ throw new PairingClientError("invalid_arguments", `Unknown pairing option: ${option2 ?? "missing option"}`);
22603
23254
  }
22604
23255
  }
22605
23256
  }
@@ -22647,7 +23298,7 @@ function parseChannelArgument(arguments_) {
22647
23298
  throw new PairingClientError("invalid_arguments", "Usage: mobius start --channel <channel-id>");
22648
23299
  }
22649
23300
  const channelId = arguments_[1] ?? "";
22650
- if (!IDENTIFIER_PATTERN4.test(channelId)) {
23301
+ if (!IDENTIFIER_PATTERN5.test(channelId)) {
22651
23302
  throw new PairingClientError("invalid_channel_id", "The saved channel ID is invalid");
22652
23303
  }
22653
23304
  return channelId;
@@ -22686,9 +23337,9 @@ async function readJsonResponse(response) {
22686
23337
  }
22687
23338
  }
22688
23339
  function readRelayError(value) {
22689
- if (isRecord4(value)) {
23340
+ if (isRecord6(value)) {
22690
23341
  const error61 = value["error"];
22691
- if (isRecord4(error61)) {
23342
+ if (isRecord6(error61)) {
22692
23343
  const code = error61["code"];
22693
23344
  const message = error61["message"];
22694
23345
  if (typeof code === "string" && typeof message === "string") {
@@ -22699,16 +23350,16 @@ function readRelayError(value) {
22699
23350
  return new PairingClientError("pairing_failed", "The relay could not pair this machine");
22700
23351
  }
22701
23352
  function decodeClaimResponse(value) {
22702
- if (!isRecord4(value) || !hasExactKeys(value, CLAIM_RESPONSE_KEYS)) {
23353
+ if (!isRecord6(value) || !hasExactKeys(value, CLAIM_RESPONSE_KEYS)) {
22703
23354
  throw new PairingClientError("invalid_relay_response", "The relay returned an invalid pairing response");
22704
23355
  }
22705
23356
  const channelId = value["channelId"];
22706
- const daemonToken = value["daemonToken"];
23357
+ const daemonToken2 = value["daemonToken"];
22707
23358
  const runtimeId = value["runtimeId"];
22708
- if (typeof channelId !== "string" || !IDENTIFIER_PATTERN4.test(channelId) || typeof daemonToken !== "string" || !TOKEN_PATTERN.test(daemonToken) || typeof runtimeId !== "string" || !IDENTIFIER_PATTERN4.test(runtimeId)) {
23359
+ if (typeof channelId !== "string" || !IDENTIFIER_PATTERN5.test(channelId) || typeof daemonToken2 !== "string" || !TOKEN_PATTERN2.test(daemonToken2) || typeof runtimeId !== "string" || !IDENTIFIER_PATTERN5.test(runtimeId)) {
22709
23360
  throw new PairingClientError("invalid_relay_response", "The relay returned an invalid pairing response");
22710
23361
  }
22711
- return { channelId, daemonToken, runtimeId };
23362
+ return { channelId, daemonToken: daemonToken2, runtimeId };
22712
23363
  }
22713
23364
  async function claimPairing(options, defaultWorkspace, localAgents, installableAgents, signal) {
22714
23365
  const agents = localAgents.map((agent) => ({
@@ -22743,18 +23394,18 @@ async function claimPairing(options, defaultWorkspace, localAgents, installableA
22743
23394
  }
22744
23395
  return decodeClaimResponse(value);
22745
23396
  }
22746
- async function persistConnection(channelId, relayOrigin, daemonToken, defaultWorkspace) {
23397
+ async function persistConnection(channelId, relayOrigin, daemonToken2, defaultWorkspace) {
22747
23398
  const connectionsDirectory = join14(readStateDirectory(), "connections");
22748
23399
  await mkdir3(connectionsDirectory, { mode: 448, recursive: true });
22749
23400
  const connectionPath = join14(connectionsDirectory, `${channelId}.json`);
22750
- const temporaryPath = join14(connectionsDirectory, `.${channelId}.${randomUUID()}.tmp`);
23401
+ const temporaryPath = join14(connectionsDirectory, `.${channelId}.${randomUUID2()}.tmp`);
22751
23402
  await writeFile2(
22752
23403
  temporaryPath,
22753
23404
  `${JSON.stringify(
22754
23405
  {
22755
23406
  defaultWorkspace,
22756
23407
  channelId,
22757
- daemonToken,
23408
+ daemonToken: daemonToken2,
22758
23409
  relayOrigin: relayOrigin.toString()
22759
23410
  },
22760
23411
  null,
@@ -22767,20 +23418,20 @@ async function persistConnection(channelId, relayOrigin, daemonToken, defaultWor
22767
23418
  return connectionPath;
22768
23419
  }
22769
23420
  function decodeSavedConnection(value, expectedChannelId) {
22770
- if (!isRecord4(value) || !hasExactKeys(value, SAVED_CONNECTION_KEYS)) {
23421
+ if (!isRecord6(value) || !hasExactKeys(value, SAVED_CONNECTION_KEYS)) {
22771
23422
  throw new PairingClientError("invalid_connection", "The saved connection is invalid");
22772
23423
  }
22773
23424
  const defaultWorkspace = value["defaultWorkspace"];
22774
23425
  const channelId = value["channelId"];
22775
- const daemonToken = value["daemonToken"];
23426
+ const daemonToken2 = value["daemonToken"];
22776
23427
  const relayOrigin = value["relayOrigin"];
22777
- if (typeof defaultWorkspace !== "string" || typeof channelId !== "string" || channelId !== expectedChannelId || !IDENTIFIER_PATTERN4.test(channelId) || typeof daemonToken !== "string" || !TOKEN_PATTERN.test(daemonToken) || typeof relayOrigin !== "string") {
23428
+ if (typeof defaultWorkspace !== "string" || typeof channelId !== "string" || channelId !== expectedChannelId || !IDENTIFIER_PATTERN5.test(channelId) || typeof daemonToken2 !== "string" || !TOKEN_PATTERN2.test(daemonToken2) || typeof relayOrigin !== "string") {
22778
23429
  throw new PairingClientError("invalid_connection", "The saved connection is invalid");
22779
23430
  }
22780
23431
  return {
22781
23432
  defaultWorkspace,
22782
23433
  channelId,
22783
- daemonToken,
23434
+ daemonToken: daemonToken2,
22784
23435
  relayOrigin: parseRelayOrigin(relayOrigin)
22785
23436
  };
22786
23437
  }
@@ -22881,9 +23532,10 @@ async function resumeLocalMachine(arguments_, signal = new AbortController().sig
22881
23532
  }
22882
23533
 
22883
23534
  // src/run-daemon.ts
22884
- import { basename as basename3 } from "node:path";
23535
+ import { randomUUID as randomUUID6 } from "node:crypto";
23536
+ import { basename as basename3, join as join16 } from "node:path";
22885
23537
  import { styleText } from "node:util";
22886
- import { fetch as fetch5, WebSocket as WebSocket2 } from "undici";
23538
+ import { fetch as fetch6, WebSocket as WebSocket2 } from "undici";
22887
23539
 
22888
23540
  // src/acp/session-manager.ts
22889
23541
  import { spawn as spawn3 } from "node:child_process";
@@ -22896,7 +23548,7 @@ import {
22896
23548
 
22897
23549
  // src/acp/activity.ts
22898
23550
  var TRUNCATION_MARKER = "\n\u2026 output truncated by Mobius";
22899
- function isRecord5(value) {
23551
+ function isRecord7(value) {
22900
23552
  return typeof value === "object" && value !== null && !Array.isArray(value);
22901
23553
  }
22902
23554
  var AcpActivity = class _AcpActivity {
@@ -23163,7 +23815,7 @@ function contentPhase(content) {
23163
23815
  return "";
23164
23816
  }
23165
23817
  const codex = metadata["codex"];
23166
- if (!isRecord5(codex)) {
23818
+ if (!isRecord7(codex)) {
23167
23819
  return "";
23168
23820
  }
23169
23821
  const phase = codex["phase"];
@@ -23401,7 +24053,7 @@ var SessionConfigProtocolError = class extends Error {
23401
24053
  this.name = "SessionConfigProtocolError";
23402
24054
  }
23403
24055
  };
23404
- function isRecord6(value) {
24056
+ function isRecord8(value) {
23405
24057
  return typeof value === "object" && value !== null && !Array.isArray(value);
23406
24058
  }
23407
24059
  function readString2(value, fallback = "") {
@@ -23413,13 +24065,13 @@ function truncate2(value, maximum) {
23413
24065
  function readBoolean(value, fallback = false) {
23414
24066
  return typeof value === "boolean" ? value : fallback;
23415
24067
  }
23416
- function normalizeConfigValue(option, groupId = "", groupName = "") {
24068
+ function normalizeConfigValue(option2, groupId = "", groupName = "") {
23417
24069
  return {
23418
- description: truncate2(readString2(option["description"]), 500),
24070
+ description: truncate2(readString2(option2["description"]), 500),
23419
24071
  groupId: truncate2(groupId, 128),
23420
24072
  groupName: truncate2(groupName, 255),
23421
- name: truncate2(readString2(option["name"], readString2(option["value"])), 255),
23422
- value: truncate2(readString2(option["value"]), 500)
24073
+ name: truncate2(readString2(option2["name"], readString2(option2["value"])), 255),
24074
+ value: truncate2(readString2(option2["value"]), 500)
23423
24075
  };
23424
24076
  }
23425
24077
  function normalizeConfigValues(value) {
@@ -23428,7 +24080,7 @@ function normalizeConfigValues(value) {
23428
24080
  }
23429
24081
  const normalized = [];
23430
24082
  for (const entry of value) {
23431
- if (!isRecord6(entry)) {
24083
+ if (!isRecord8(entry)) {
23432
24084
  continue;
23433
24085
  }
23434
24086
  const groupedOptions = entry["options"];
@@ -23436,7 +24088,7 @@ function normalizeConfigValues(value) {
23436
24088
  const groupId = readString2(entry["group"]);
23437
24089
  const groupName = readString2(entry["name"]);
23438
24090
  for (const groupedOption of groupedOptions) {
23439
- if (isRecord6(groupedOption)) {
24091
+ if (isRecord8(groupedOption)) {
23440
24092
  normalized.push(normalizeConfigValue(groupedOption, groupId, groupName));
23441
24093
  }
23442
24094
  }
@@ -23449,21 +24101,21 @@ function normalizeConfigValues(value) {
23449
24101
  function normalizeConfigOptions(value, modes) {
23450
24102
  const normalized = [];
23451
24103
  if (Array.isArray(value)) {
23452
- for (const option of value) {
23453
- if (!isRecord6(option)) {
24104
+ for (const option2 of value) {
24105
+ if (!isRecord8(option2)) {
23454
24106
  continue;
23455
24107
  }
23456
- const id = truncate2(readString2(option["id"]), 128);
23457
- const name = truncate2(readString2(option["name"], id), 255);
24108
+ const id = truncate2(readString2(option2["id"]), 128);
24109
+ const name = truncate2(readString2(option2["name"], id), 255);
23458
24110
  if (id.length === 0 || name.length === 0) {
23459
24111
  continue;
23460
24112
  }
23461
- if (option["type"] === "boolean") {
24113
+ if (option2["type"] === "boolean") {
23462
24114
  normalized.push({
23463
- booleanValue: readBoolean(option["currentValue"]),
23464
- category: truncate2(readString2(option["category"]), 128),
24115
+ booleanValue: readBoolean(option2["currentValue"]),
24116
+ category: truncate2(readString2(option2["category"]), 128),
23465
24117
  currentValue: "",
23466
- description: truncate2(readString2(option["description"]), 500),
24118
+ description: truncate2(readString2(option2["description"]), 500),
23467
24119
  id,
23468
24120
  name,
23469
24121
  type: "boolean",
@@ -23471,15 +24123,15 @@ function normalizeConfigOptions(value, modes) {
23471
24123
  });
23472
24124
  continue;
23473
24125
  }
23474
- if (option["type"] === "select") {
23475
- const values = normalizeConfigValues(option["options"]);
23476
- const currentValue = truncate2(readString2(option["currentValue"]), 500);
24126
+ if (option2["type"] === "select") {
24127
+ const values = normalizeConfigValues(option2["options"]);
24128
+ const currentValue = truncate2(readString2(option2["currentValue"]), 500);
23477
24129
  if (currentValue.length > 0 && values.some((entry) => entry.value === currentValue)) {
23478
24130
  normalized.push({
23479
24131
  booleanValue: false,
23480
- category: truncate2(readString2(option["category"]), 128),
24132
+ category: truncate2(readString2(option2["category"]), 128),
23481
24133
  currentValue,
23482
- description: truncate2(readString2(option["description"]), 500),
24134
+ description: truncate2(readString2(option2["description"]), 500),
23483
24135
  id,
23484
24136
  name,
23485
24137
  type: "select",
@@ -23489,12 +24141,12 @@ function normalizeConfigOptions(value, modes) {
23489
24141
  }
23490
24142
  }
23491
24143
  }
23492
- if (isRecord6(modes)) {
24144
+ if (isRecord8(modes)) {
23493
24145
  const values = [];
23494
24146
  const availableModes = modes["availableModes"];
23495
24147
  if (Array.isArray(availableModes)) {
23496
24148
  for (const mode of availableModes) {
23497
- if (!isRecord6(mode)) {
24149
+ if (!isRecord8(mode)) {
23498
24150
  continue;
23499
24151
  }
23500
24152
  const id = truncate2(readString2(mode["id"]), 500);
@@ -23527,7 +24179,7 @@ function normalizeConfigOptions(value, modes) {
23527
24179
  return normalized.slice(0, 100);
23528
24180
  }
23529
24181
  function ensureReasoningEffortOption(current) {
23530
- if (current.some((option) => option.category === "thought_level")) {
24182
+ if (current.some((option2) => option2.category === "thought_level")) {
23531
24183
  return current;
23532
24184
  }
23533
24185
  const unavailable = {
@@ -23548,7 +24200,7 @@ function ensureReasoningEffortOption(current) {
23548
24200
  }
23549
24201
  ]
23550
24202
  };
23551
- const modelIndex = current.findIndex((option) => option.category === "model");
24203
+ const modelIndex = current.findIndex((option2) => option2.category === "model");
23552
24204
  if (current.length < MAXIMUM_CONFIG_OPTIONS) {
23553
24205
  if (modelIndex < 0) {
23554
24206
  return [...current, unavailable];
@@ -23572,20 +24224,20 @@ function ensureReasoningEffortOption(current) {
23572
24224
  return [...current.slice(0, MAXIMUM_CONFIG_OPTIONS - 2), model, unavailable];
23573
24225
  }
23574
24226
  function normalizeStandardLifecycle(response) {
23575
- const lifecycle = isRecord6(response) ? response : {};
24227
+ const lifecycle = isRecord8(response) ? response : {};
23576
24228
  return ensureReasoningEffortOption(normalizeConfigOptions(lifecycle["configOptions"], lifecycle["modes"]));
23577
24229
  }
23578
24230
  function replaceStandardConfigOptions(current, value) {
23579
24231
  const next = normalizeConfigOptions(value, void 0);
23580
- const withMode = next.some((option) => option.category === "mode") ? next : [...current.filter((option) => option.category === "mode"), ...next].slice(0, 100);
24232
+ const withMode = next.some((option2) => option2.category === "mode") ? next : [...current.filter((option2) => option2.category === "mode"), ...next].slice(0, 100);
23581
24233
  return ensureReasoningEffortOption(withMode);
23582
24234
  }
23583
24235
  function updateCurrentValue(current, configId, value) {
23584
- return current.map((option) => option.id === configId ? { ...option, currentValue: value } : option);
24236
+ return current.map((option2) => option2.id === configId ? { ...option2, currentValue: value } : option2);
23585
24237
  }
23586
24238
  var StandardSessionConfigProtocol = class {
23587
24239
  configure = async (current, change, nativeSessionId, transport) => {
23588
- const existing = current.find((option) => option.id === change.configId);
24240
+ const existing = current.find((option2) => option2.id === change.configId);
23589
24241
  if (existing === void 0) {
23590
24242
  return current;
23591
24243
  }
@@ -23614,7 +24266,7 @@ var StandardSessionConfigProtocol = class {
23614
24266
  "ACP agent exited while changing session configuration",
23615
24267
  change.signal
23616
24268
  );
23617
- if (!isRecord6(response) || !Array.isArray(response["configOptions"])) {
24269
+ if (!isRecord8(response) || !Array.isArray(response["configOptions"])) {
23618
24270
  throw new SessionConfigProtocolError("The Agent returned an invalid session configuration response");
23619
24271
  }
23620
24272
  return replaceStandardConfigOptions(current, response["configOptions"]);
@@ -23628,31 +24280,31 @@ var standardSessionConfigProtocol = new StandardSessionConfigProtocol();
23628
24280
  var LEGACY_MODEL_CONFIG_ID = "grok_build_legacy_model";
23629
24281
  var LEGACY_REASONING_EFFORT_CONFIG_ID = "grok_build_legacy_reasoning_effort";
23630
24282
  function legacyOptions(response) {
23631
- if (!isRecord6(response)) {
24283
+ if (!isRecord8(response)) {
23632
24284
  return [];
23633
24285
  }
23634
24286
  const metadata = response["_meta"];
23635
- if (!isRecord6(metadata)) {
24287
+ if (!isRecord8(metadata)) {
23636
24288
  return [];
23637
24289
  }
23638
24290
  const sessionConfig = metadata["x.ai/sessionConfig"];
23639
- if (!isRecord6(sessionConfig) || !Array.isArray(sessionConfig["options"])) {
24291
+ if (!isRecord8(sessionConfig) || !Array.isArray(sessionConfig["options"])) {
23640
24292
  return [];
23641
24293
  }
23642
- return sessionConfig["options"].slice(0, 500).filter(isRecord6);
24294
+ return sessionConfig["options"].slice(0, 500).filter(isRecord8);
23643
24295
  }
23644
- function legacyValue(option) {
23645
- const value = readString2(option["id"]);
24296
+ function legacyValue(option2) {
24297
+ const value = readString2(option2["id"]);
23646
24298
  return {
23647
- description: readString2(option["description"]).slice(0, 500),
24299
+ description: readString2(option2["description"]).slice(0, 500),
23648
24300
  groupId: "",
23649
24301
  groupName: "",
23650
- name: readString2(option["label"], value).slice(0, 255),
24302
+ name: readString2(option2["label"], value).slice(0, 255),
23651
24303
  value: value.slice(0, 500)
23652
24304
  };
23653
24305
  }
23654
24306
  function modelsRecord(response) {
23655
- if (!isRecord6(response) || !isRecord6(response["models"])) {
24307
+ if (!isRecord8(response) || !isRecord8(response["models"])) {
23656
24308
  return {};
23657
24309
  }
23658
24310
  return response["models"];
@@ -23661,9 +24313,9 @@ function legacyModelOptions(response) {
23661
24313
  const options = legacyOptions(response);
23662
24314
  const models = modelsRecord(response);
23663
24315
  const values = [];
23664
- for (const option of options) {
23665
- if (option["category"] === "model") {
23666
- const value = legacyValue(option);
24316
+ for (const option2 of options) {
24317
+ if (option2["category"] === "model") {
24318
+ const value = legacyValue(option2);
23667
24319
  if (value.value.length > 0 && !values.some((existing) => existing.value === value.value)) {
23668
24320
  values.push(value);
23669
24321
  }
@@ -23671,7 +24323,7 @@ function legacyModelOptions(response) {
23671
24323
  }
23672
24324
  if (values.length === 0 && Array.isArray(models["availableModels"])) {
23673
24325
  for (const model of models["availableModels"]) {
23674
- if (!isRecord6(model)) {
24326
+ if (!isRecord8(model)) {
23675
24327
  continue;
23676
24328
  }
23677
24329
  const value = readString2(model["modelId"]).slice(0, 500);
@@ -23689,7 +24341,7 @@ function legacyModelOptions(response) {
23689
24341
  }
23690
24342
  }
23691
24343
  }
23692
- const selected = options.find((option) => option["category"] === "model" && option["selected"] === true);
24344
+ const selected = options.find((option2) => option2["category"] === "model" && option2["selected"] === true);
23693
24345
  const currentValue = readString2(
23694
24346
  models["currentModelId"],
23695
24347
  selected === void 0 ? "" : readString2(selected["id"])
@@ -23712,11 +24364,11 @@ function legacyModelOptions(response) {
23712
24364
  function legacyReasoningEffortOptions(response) {
23713
24365
  const options = legacyOptions(response);
23714
24366
  const values = [];
23715
- for (const option of options) {
23716
- if (option["category"] !== "mode") {
24367
+ for (const option2 of options) {
24368
+ if (option2["category"] !== "mode") {
23717
24369
  continue;
23718
24370
  }
23719
- const value = legacyValue(option);
24371
+ const value = legacyValue(option2);
23720
24372
  if (value.value.length > 0 && !values.some((existing) => existing.value === value.value)) {
23721
24373
  values.push(value);
23722
24374
  }
@@ -23724,7 +24376,7 @@ function legacyReasoningEffortOptions(response) {
23724
24376
  if (values.length === 0) {
23725
24377
  return [];
23726
24378
  }
23727
- const selected = options.find((option) => option["category"] === "mode" && option["selected"] === true);
24379
+ const selected = options.find((option2) => option2["category"] === "mode" && option2["selected"] === true);
23728
24380
  if (selected === void 0) {
23729
24381
  values.unshift({
23730
24382
  description: "Use the selected model's default reasoning effort",
@@ -23751,41 +24403,41 @@ function legacyReasoningEffortOptions(response) {
23751
24403
  return [result];
23752
24404
  }
23753
24405
  function normalizeGrokLifecycle(response) {
23754
- const lifecycle = isRecord6(response) ? response : {};
24406
+ const lifecycle = isRecord8(response) ? response : {};
23755
24407
  const standard = normalizeConfigOptions(lifecycle["configOptions"], lifecycle["modes"]);
23756
24408
  const normalized = [...standard];
23757
- if (!normalized.some((option) => option.category === "model")) {
24409
+ if (!normalized.some((option2) => option2.category === "model")) {
23758
24410
  normalized.push(...legacyModelOptions(response));
23759
24411
  }
23760
- if (!normalized.some((option) => option.category === "thought_level")) {
24412
+ if (!normalized.some((option2) => option2.category === "thought_level")) {
23761
24413
  const efforts = legacyReasoningEffortOptions(response);
23762
24414
  if (efforts.length > 0) {
23763
- const modelIndex = normalized.findIndex((option) => option.category === "model");
24415
+ const modelIndex = normalized.findIndex((option2) => option2.category === "model");
23764
24416
  normalized.splice(modelIndex < 0 ? normalized.length : modelIndex + 1, 0, ...efforts);
23765
24417
  }
23766
24418
  }
23767
24419
  return ensureReasoningEffortOption(normalized.slice(0, 100));
23768
24420
  }
23769
24421
  function updateCurrentValue2(current, category, value) {
23770
- return current.map((option) => option.category === category ? { ...option, currentValue: value } : option);
24422
+ return current.map((option2) => option2.category === category ? { ...option2, currentValue: value } : option2);
23771
24423
  }
23772
24424
  function validateGrokResponse(response, modelId) {
23773
- if (!isRecord6(response) || !isRecord6(response["_meta"])) {
24425
+ if (!isRecord8(response) || !isRecord8(response["_meta"])) {
23774
24426
  throw new SessionConfigProtocolError("Grok Build returned an invalid session configuration response");
23775
24427
  }
23776
24428
  const model = response["_meta"]["model"];
23777
- const appliedModel = isRecord6(model) ? model["Ok"] : model;
24429
+ const appliedModel = isRecord8(model) ? model["Ok"] : model;
23778
24430
  if (appliedModel !== modelId) {
23779
24431
  throw new SessionConfigProtocolError("Grok Build returned an invalid session configuration response");
23780
24432
  }
23781
24433
  }
23782
24434
  var GrokBuildSessionConfigProtocol = class {
23783
24435
  configure = async (current, change, nativeSessionId, transport) => {
23784
- const existing = current.find((option) => option.id === change.configId);
24436
+ const existing = current.find((option2) => option2.id === change.configId);
23785
24437
  if (existing === void 0 || existing.id !== LEGACY_MODEL_CONFIG_ID && existing.id !== LEGACY_REASONING_EFFORT_CONFIG_ID) {
23786
24438
  return await standardSessionConfigProtocol.configure(current, change, nativeSessionId, transport);
23787
24439
  }
23788
- const model = current.find((option) => option.category === "model");
24440
+ const model = current.find((option2) => option2.category === "model");
23789
24441
  if (model === void 0) {
23790
24442
  return current;
23791
24443
  }
@@ -23811,10 +24463,10 @@ var GrokBuildSessionConfigProtocol = class {
23811
24463
  validateGrokResponse(response, modelId);
23812
24464
  const updated = updateCurrentValue2(current, existing.category, change.value);
23813
24465
  return existing.category === "thought_level" ? updated.map(
23814
- (option) => option.category === "thought_level" ? {
23815
- ...option,
23816
- values: option.values.filter((value) => value.value !== AGENT_DEFAULT_REASONING_EFFORT)
23817
- } : option
24466
+ (option2) => option2.category === "thought_level" ? {
24467
+ ...option2,
24468
+ values: option2.values.filter((value) => value.value !== AGENT_DEFAULT_REASONING_EFFORT)
24469
+ } : option2
23818
24470
  ) : updated;
23819
24471
  };
23820
24472
  normalizeLifecycle = (response) => normalizeGrokLifecycle(response);
@@ -24217,7 +24869,7 @@ function createWritableAcpStream(output2) {
24217
24869
  function truncate3(value, maximumLength) {
24218
24870
  return value.length <= maximumLength ? value : `${value.slice(0, Math.max(0, maximumLength - 1))}\u2026`;
24219
24871
  }
24220
- function isRecord7(value) {
24872
+ function isRecord9(value) {
24221
24873
  return typeof value === "object" && value !== null && !Array.isArray(value);
24222
24874
  }
24223
24875
  function readString4(value, fallback = "") {
@@ -24245,12 +24897,12 @@ function normalizeElicitationOptions(schema) {
24245
24897
  const normalized = [];
24246
24898
  const oneOf = schema["oneOf"];
24247
24899
  if (Array.isArray(oneOf)) {
24248
- for (const option of oneOf) {
24249
- if (isRecord7(option) && typeof option["const"] === "string") {
24900
+ for (const option2 of oneOf) {
24901
+ if (isRecord9(option2) && typeof option2["const"] === "string") {
24250
24902
  normalized.push({
24251
- description: truncate3(readString4(option["description"]), 500),
24252
- label: truncate3(readString4(option["title"], option["const"]), 255),
24253
- value: truncate3(option["const"], 500)
24903
+ description: truncate3(readString4(option2["description"]), 500),
24904
+ label: truncate3(readString4(option2["title"], option2["const"]), 255),
24905
+ value: truncate3(option2["const"], 500)
24254
24906
  });
24255
24907
  }
24256
24908
  }
@@ -24266,7 +24918,7 @@ function normalizeElicitationOptions(schema) {
24266
24918
  return normalized.slice(0, 200);
24267
24919
  }
24268
24920
  const items = schema["items"];
24269
- if (!isRecord7(items)) {
24921
+ if (!isRecord9(items)) {
24270
24922
  return normalized;
24271
24923
  }
24272
24924
  const anyOf = items["anyOf"];
@@ -24279,7 +24931,7 @@ function numericString(value) {
24279
24931
  return typeof value === "number" && Number.isFinite(value) ? value.toString() : "";
24280
24932
  }
24281
24933
  function normalizeElicitationFields(requestedSchema) {
24282
- if (!isRecord7(requestedSchema) || !isRecord7(requestedSchema["properties"])) {
24934
+ if (!isRecord9(requestedSchema) || !isRecord9(requestedSchema["properties"])) {
24283
24935
  return [];
24284
24936
  }
24285
24937
  const properties = requestedSchema["properties"];
@@ -24289,7 +24941,7 @@ function normalizeElicitationFields(requestedSchema) {
24289
24941
  );
24290
24942
  const normalized = [];
24291
24943
  for (const [name, property] of Object.entries(properties)) {
24292
- if (!isRecord7(property)) {
24944
+ if (!isRecord9(property)) {
24293
24945
  continue;
24294
24946
  }
24295
24947
  const type = elicitationFieldType(property["type"]);
@@ -24380,7 +25032,7 @@ function validateElicitationContent(encoded, requestedSchema) {
24380
25032
  "invalid_elicitation_response"
24381
25033
  );
24382
25034
  }
24383
- if (!isRecord7(decoded) || !isRecord7(requestedSchema) || !isRecord7(requestedSchema["properties"])) {
25035
+ if (!isRecord9(decoded) || !isRecord9(requestedSchema) || !isRecord9(requestedSchema["properties"])) {
24384
25036
  throw new AcpExecutionError(
24385
25037
  "Elicitation response does not match the requested form",
24386
25038
  {},
@@ -24400,7 +25052,7 @@ function validateElicitationContent(encoded, requestedSchema) {
24400
25052
  const validated = {};
24401
25053
  for (const [name, value] of Object.entries(decoded)) {
24402
25054
  const property = properties[name];
24403
- if (!isRecord7(property)) {
25055
+ if (!isRecord9(property)) {
24404
25056
  throw new AcpExecutionError(
24405
25057
  `Elicitation field ${name} was not requested`,
24406
25058
  {},
@@ -24437,7 +25089,7 @@ function validateElicitationContent(encoded, requestedSchema) {
24437
25089
  );
24438
25090
  }
24439
25091
  const allowed = normalizeElicitationOptions(property);
24440
- if (allowed.length > 0 && value.some((entry) => !allowed.some((option) => option.value === entry))) {
25092
+ if (allowed.length > 0 && value.some((entry) => !allowed.some((option2) => option2.value === entry))) {
24441
25093
  throw new AcpExecutionError(
24442
25094
  `Elicitation field ${name} contains an invalid selection`,
24443
25095
  {},
@@ -24934,7 +25586,7 @@ var AcpProcessSession = class _AcpProcessSession {
24934
25586
  };
24935
25587
  nativeSessionId = () => this.#nativeSessionId;
24936
25588
  configure = async (options) => {
24937
- const existing = this.#configOptions.find((option) => option.id === options.configId);
25589
+ const existing = this.#configOptions.find((option2) => option2.id === options.configId);
24938
25590
  if (existing === void 0 || existing.type !== options.valueType) {
24939
25591
  throw new AcpExecutionError(
24940
25592
  "The requested ACP configuration option is unavailable",
@@ -25184,10 +25836,10 @@ var AcpProcessSession = class _AcpProcessSession {
25184
25836
  onPermission = async (request, signal) => {
25185
25837
  this.assertNativeSession(request.sessionId);
25186
25838
  const interactionId = `permission-${crypto.randomUUID()}`;
25187
- const options = request.options.slice(0, 20).map((option) => ({
25188
- kind: option.kind,
25189
- name: truncate3(option.name, 255),
25190
- optionId: truncate3(option.optionId, 255)
25839
+ const options = request.options.slice(0, 20).map((option2) => ({
25840
+ kind: option2.kind,
25841
+ name: truncate3(option2.name, 255),
25842
+ optionId: truncate3(option2.optionId, 255)
25191
25843
  }));
25192
25844
  if (options.length === 0) {
25193
25845
  throw new AcpExecutionError(
@@ -25196,7 +25848,7 @@ var AcpProcessSession = class _AcpProcessSession {
25196
25848
  "invalid_agent_permission_request"
25197
25849
  );
25198
25850
  }
25199
- const pending = new PendingPermission(interactionId, new Set(options.map((option) => option.optionId)));
25851
+ const pending = new PendingPermission(interactionId, new Set(options.map((option2) => option2.optionId)));
25200
25852
  this.#pendingPermissions.set(interactionId, pending);
25201
25853
  const abort = () => {
25202
25854
  void this.cancelPermission(interactionId);
@@ -25406,7 +26058,7 @@ var AcpProcessSession = class _AcpProcessSession {
25406
26058
  }
25407
26059
  if (update.sessionUpdate === "current_mode_update") {
25408
26060
  this.#configOptions = this.#configOptions.map(
25409
- (option) => option.category === "mode" ? { ...option, currentValue: update.currentModeId } : option
26061
+ (option2) => option2.category === "mode" ? { ...option2, currentValue: update.currentModeId } : option2
25410
26062
  );
25411
26063
  this.#configRevision += 1;
25412
26064
  await this.emitConfigUpdate();
@@ -26638,45 +27290,755 @@ var WorkspaceDirectoryService = class {
26638
27290
  };
26639
27291
  };
26640
27292
 
26641
- // src/native-sessions/service.ts
26642
- import { randomUUID as randomUUID2 } from "node:crypto";
26643
-
26644
- // src/native-sessions/codex-history.ts
26645
- import { spawn as spawn4 } from "node:child_process";
26646
- var responseSchema = external_exports.union([
26647
- external_exports.object({
26648
- id: external_exports.number(),
26649
- error: external_exports.object({ code: external_exports.number(), message: external_exports.string() })
26650
- }),
26651
- external_exports.object({ id: external_exports.number(), result: external_exports.unknown() }),
26652
- external_exports.object({ method: external_exports.string() })
26653
- ]);
26654
- var threadSchema = external_exports.object({
26655
- thread: external_exports.object({
26656
- id: nativeSessionIdSchema,
26657
- cwd: external_exports.string().min(1).max(2048).refine((path2) => !path2.includes("\0"))
26658
- })
26659
- });
26660
- var turnsSchema = external_exports.object({
26661
- data: external_exports.array(external_exports.object({ items: external_exports.array(external_exports.unknown()).max(1e5) })).max(SESSION_HISTORY_PREVIEW_MESSAGE_LIMIT),
26662
- nextCursor: external_exports.string().nullish()
26663
- });
26664
- var itemTypeSchema = external_exports.object({ type: external_exports.string().min(1).max(80) });
26665
- var userMessageSchema = external_exports.object({
26666
- content: external_exports.array(external_exports.unknown()).max(1e4)
26667
- });
26668
- var textSchema = external_exports.object({ text: external_exports.string() });
26669
- var imageSchema = external_exports.object({ url: external_exports.string() });
26670
- var agentMessageSchema = textSchema.extend({ phase: external_exports.string().nullish() });
26671
- function decodeHistory(thread, value) {
26672
- const page = turnsSchema.parse(value);
26673
- const messages = [];
26674
- let characters = 0;
26675
- let imageCharacters = 0;
26676
- let truncated = page.nextCursor != null;
26677
- for (const turn of page.data.toReversed()) {
26678
- for (const item of turn.items) {
26679
- const { type } = itemTypeSchema.parse(item);
27293
+ // src/bots/local-bot-grant-store.ts
27294
+ import { createHash as createHash2, randomUUID as randomUUID3 } from "node:crypto";
27295
+ import { stat as stat7 } from "node:fs/promises";
27296
+ import { DatabaseSync as DatabaseSync3 } from "node:sqlite";
27297
+ var LOCAL_BOT_GRANT_LIFETIME_MILLISECONDS = 90 * 24 * 60 * 60 * 1e3;
27298
+ var LocalBotAuthorizationError = class extends Error {
27299
+ code;
27300
+ constructor(code, message, options = {}) {
27301
+ super(message, options);
27302
+ this.code = code;
27303
+ this.name = "LocalBotAuthorizationError";
27304
+ }
27305
+ };
27306
+ var LocalBotGrant = class {
27307
+ agent;
27308
+ agentIdentityDigest;
27309
+ allowedDeliveryTargetIds;
27310
+ behaviorDigest;
27311
+ behaviorRevisionId;
27312
+ bindingId;
27313
+ bindingRevision;
27314
+ botId;
27315
+ expiresAt;
27316
+ localGrantId;
27317
+ revocationEpoch;
27318
+ workspaceIdentityDigest;
27319
+ workspacePath;
27320
+ constructor(localGrantId, botId, behaviorRevisionId, behaviorDigest, bindingId, bindingRevision, agent, agentIdentityDigest, workspacePath, workspaceIdentityDigest, allowedDeliveryTargetIds, expiresAt, revocationEpoch) {
27321
+ this.localGrantId = localGrantId;
27322
+ this.botId = botId;
27323
+ this.behaviorRevisionId = behaviorRevisionId;
27324
+ this.behaviorDigest = behaviorDigest;
27325
+ this.bindingId = bindingId;
27326
+ this.bindingRevision = bindingRevision;
27327
+ this.agent = agent;
27328
+ this.agentIdentityDigest = agentIdentityDigest;
27329
+ this.workspacePath = workspacePath;
27330
+ this.workspaceIdentityDigest = workspaceIdentityDigest;
27331
+ this.allowedDeliveryTargetIds = Object.freeze([...allowedDeliveryTargetIds]);
27332
+ this.expiresAt = expiresAt;
27333
+ this.revocationEpoch = revocationEpoch;
27334
+ }
27335
+ };
27336
+ function digest(value) {
27337
+ return createHash2("sha256").update(value, "utf8").digest("hex");
27338
+ }
27339
+ function agentDigest(agent) {
27340
+ return digest(
27341
+ JSON.stringify({
27342
+ adapter: agent.adapterIdentity,
27343
+ agent: agent.agentIdentity,
27344
+ agentVersion: agent.agentVersion,
27345
+ arguments: agent.arguments,
27346
+ id: agent.id
27347
+ })
27348
+ );
27349
+ }
27350
+ async function workspaceDigest(path2) {
27351
+ const metadata = await stat7(path2);
27352
+ if (!metadata.isDirectory()) {
27353
+ throw new LocalBotAuthorizationError("binding_incompatible", "The Bot workspace is not a directory");
27354
+ }
27355
+ return digest(
27356
+ JSON.stringify({
27357
+ changedAtMilliseconds: metadata.ctimeMs,
27358
+ device: metadata.dev,
27359
+ inode: metadata.ino,
27360
+ path: path2
27361
+ })
27362
+ );
27363
+ }
27364
+ function exactTargets(left, right) {
27365
+ if (left.length !== right.length) {
27366
+ return false;
27367
+ }
27368
+ const expected = [...left].sort();
27369
+ const actual = [...right].sort();
27370
+ return expected.every((target, index) => target === actual[index]);
27371
+ }
27372
+ function rowString(row, key) {
27373
+ const value = Reflect.get(row, key);
27374
+ if (typeof value !== "string") {
27375
+ throw new LocalBotAuthorizationError("local_grant_invalid", "The local Bot grant is invalid");
27376
+ }
27377
+ return value;
27378
+ }
27379
+ function rowInteger(row, key) {
27380
+ const value = Reflect.get(row, key);
27381
+ if (typeof value !== "number" || !Number.isSafeInteger(value)) {
27382
+ throw new LocalBotAuthorizationError("local_grant_invalid", "The local Bot grant is invalid");
27383
+ }
27384
+ return value;
27385
+ }
27386
+ function parseTargets(encoded) {
27387
+ let value;
27388
+ try {
27389
+ value = JSON.parse(encoded);
27390
+ } catch (cause) {
27391
+ throw new LocalBotAuthorizationError("local_grant_invalid", "The local Bot grant is invalid", { cause });
27392
+ }
27393
+ if (!Array.isArray(value) || value.some((target) => typeof target !== "string")) {
27394
+ throw new LocalBotAuthorizationError("local_grant_invalid", "The local Bot grant is invalid");
27395
+ }
27396
+ return value.filter((target) => typeof target === "string");
27397
+ }
27398
+ var LocalBotGrantStore = class {
27399
+ #database;
27400
+ constructor(path2) {
27401
+ this.#database = new DatabaseSync3(path2);
27402
+ this.#database.exec(`
27403
+ CREATE TABLE IF NOT EXISTS local_bot_grants (
27404
+ local_grant_id TEXT PRIMARY KEY,
27405
+ bot_id TEXT NOT NULL,
27406
+ behavior_revision_id TEXT NOT NULL,
27407
+ behavior_digest TEXT NOT NULL,
27408
+ binding_id TEXT NOT NULL UNIQUE,
27409
+ binding_revision INTEGER NOT NULL,
27410
+ agent_ref TEXT NOT NULL,
27411
+ agent_identity_digest TEXT NOT NULL,
27412
+ workspace_ref TEXT NOT NULL,
27413
+ workspace_path TEXT NOT NULL,
27414
+ workspace_identity_digest TEXT NOT NULL,
27415
+ allowed_delivery_target_ids_json TEXT NOT NULL,
27416
+ unattended_policy_json TEXT NOT NULL,
27417
+ created_at INTEGER NOT NULL,
27418
+ expires_at INTEGER NOT NULL,
27419
+ revocation_epoch INTEGER NOT NULL DEFAULT 0,
27420
+ revoked_at INTEGER
27421
+ ) STRICT;
27422
+ CREATE TABLE IF NOT EXISTS local_bot_binding_resolutions (
27423
+ request_id TEXT PRIMARY KEY,
27424
+ binding_id TEXT NOT NULL,
27425
+ local_grant_id TEXT NOT NULL,
27426
+ resolved_at INTEGER NOT NULL,
27427
+ result TEXT NOT NULL CHECK (result IN ('approved', 'unavailable')),
27428
+ error_code TEXT,
27429
+ error_message TEXT
27430
+ ) STRICT;
27431
+ `);
27432
+ }
27433
+ approve = async (request, catalog, directories, bindingAuthorityId, now, signal) => {
27434
+ signal.throwIfAborted();
27435
+ const existing = this.#database.prepare(
27436
+ `SELECT grants.* FROM local_bot_binding_resolutions AS resolutions
27437
+ INNER JOIN local_bot_grants AS grants
27438
+ ON grants.local_grant_id = resolutions.local_grant_id
27439
+ WHERE resolutions.request_id = ? AND resolutions.binding_id = ?
27440
+ AND resolutions.result = 'approved'`
27441
+ ).get(request.requestId, request.bindingId);
27442
+ if (existing !== void 0) {
27443
+ return new BotExecutionBindingApprovedEvent(
27444
+ request.requestId,
27445
+ request.botId,
27446
+ request.behaviorRevisionId,
27447
+ request.bindingId,
27448
+ request.bindingRevision,
27449
+ rowString(existing, "local_grant_id"),
27450
+ rowString(existing, "agent_identity_digest"),
27451
+ rowString(existing, "workspace_identity_digest")
27452
+ );
27453
+ }
27454
+ const resolved = await this.resolveProposal(request, catalog, directories, bindingAuthorityId, signal);
27455
+ const localGrantId = `lbg_${randomUUID3()}`;
27456
+ const expiresAt = now + LOCAL_BOT_GRANT_LIFETIME_MILLISECONDS;
27457
+ this.#database.exec("BEGIN IMMEDIATE");
27458
+ try {
27459
+ this.#database.prepare(
27460
+ `INSERT INTO local_bot_grants (
27461
+ local_grant_id, bot_id, behavior_revision_id, behavior_digest,
27462
+ binding_id, binding_revision, agent_ref,
27463
+ agent_identity_digest, workspace_ref, workspace_path,
27464
+ workspace_identity_digest, allowed_delivery_target_ids_json,
27465
+ unattended_policy_json, created_at, expires_at
27466
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`
27467
+ ).run(
27468
+ localGrantId,
27469
+ request.botId,
27470
+ request.behaviorRevisionId,
27471
+ request.behaviorDigest,
27472
+ request.bindingId,
27473
+ request.bindingRevision,
27474
+ request.agentRef,
27475
+ resolved.agentIdentityDigest,
27476
+ request.workspaceRef,
27477
+ resolved.workspacePath,
27478
+ resolved.workspaceIdentityDigest,
27479
+ JSON.stringify(request.allowedDeliveryTargets.map((target) => target.deliveryTargetId)),
27480
+ JSON.stringify({ localSideEffects: "owner-approval-required" }),
27481
+ now,
27482
+ expiresAt
27483
+ );
27484
+ this.#database.prepare(
27485
+ `INSERT INTO local_bot_binding_resolutions (
27486
+ request_id, binding_id, local_grant_id, resolved_at, result
27487
+ ) VALUES (?, ?, ?, ?, 'approved')`
27488
+ ).run(request.requestId, request.bindingId, localGrantId, now);
27489
+ this.#database.exec("COMMIT");
27490
+ } catch (cause) {
27491
+ this.#database.exec("ROLLBACK");
27492
+ throw cause;
27493
+ }
27494
+ signal.throwIfAborted();
27495
+ return new BotExecutionBindingApprovedEvent(
27496
+ request.requestId,
27497
+ request.botId,
27498
+ request.behaviorRevisionId,
27499
+ request.bindingId,
27500
+ request.bindingRevision,
27501
+ localGrantId,
27502
+ resolved.agentIdentityDigest,
27503
+ resolved.workspaceIdentityDigest
27504
+ );
27505
+ };
27506
+ resolveExecution = async (command, catalog, directories, bindingAuthorityId, now, signal) => {
27507
+ signal.throwIfAborted();
27508
+ const row = this.#database.prepare(
27509
+ `SELECT * FROM local_bot_grants
27510
+ WHERE local_grant_id = ? AND bot_id = ?
27511
+ AND behavior_revision_id = ? AND behavior_digest = ?
27512
+ AND binding_id = ? AND binding_revision = ?
27513
+ AND agent_ref = ? AND workspace_ref = ?
27514
+ AND revoked_at IS NULL AND expires_at > ?`
27515
+ ).get(
27516
+ command.localGrantId,
27517
+ command.botId,
27518
+ command.behaviorRevisionId,
27519
+ command.behaviorDigest,
27520
+ command.bindingId,
27521
+ command.bindingRevision,
27522
+ command.agentId,
27523
+ command.directoryId,
27524
+ now
27525
+ );
27526
+ if (row === void 0) {
27527
+ throw new LocalBotAuthorizationError(
27528
+ "binding_not_approved",
27529
+ "The Bot execution binding is not locally approved"
27530
+ );
27531
+ }
27532
+ const approvedTargets = parseTargets(rowString(row, "allowed_delivery_target_ids_json"));
27533
+ const requestedTargets = command.allowedDeliveryTargets.map((target) => target.deliveryTargetId);
27534
+ if (!exactTargets(approvedTargets, requestedTargets)) {
27535
+ throw new LocalBotAuthorizationError(
27536
+ "binding_not_approved",
27537
+ "The Bot execution target policy changed after local approval"
27538
+ );
27539
+ }
27540
+ const agent = catalog.find(command.agentId);
27541
+ const [adapterUnchanged, agentUnchanged] = await Promise.all([
27542
+ revalidateExecutable(agent.adapterIdentity),
27543
+ revalidateExecutable(agent.agentIdentity)
27544
+ ]);
27545
+ signal.throwIfAborted();
27546
+ const workspacePath = await directories.resolve(bindingAuthorityId, command.directoryId, signal);
27547
+ const currentAgentDigest = agentDigest(agent);
27548
+ const currentWorkspaceDigest = await workspaceDigest(workspacePath);
27549
+ signal.throwIfAborted();
27550
+ if (!adapterUnchanged || !agentUnchanged || currentAgentDigest !== rowString(row, "agent_identity_digest") || currentWorkspaceDigest !== rowString(row, "workspace_identity_digest") || workspacePath !== rowString(row, "workspace_path")) {
27551
+ this.revoke(rowString(row, "local_grant_id"), now);
27552
+ throw new LocalBotAuthorizationError(
27553
+ "binding_not_approved",
27554
+ "The Bot execution target changed and requires local approval"
27555
+ );
27556
+ }
27557
+ if (command.behaviorInstructions.length > 0 && !agent.capabilities.embeddedContextPrompt) {
27558
+ throw new LocalBotAuthorizationError(
27559
+ "binding_incompatible",
27560
+ "The local Agent cannot apply the approved Bot behavior"
27561
+ );
27562
+ }
27563
+ return new LocalBotGrant(
27564
+ rowString(row, "local_grant_id"),
27565
+ command.botId,
27566
+ command.behaviorRevisionId,
27567
+ command.behaviorDigest,
27568
+ command.bindingId,
27569
+ command.bindingRevision,
27570
+ agent,
27571
+ currentAgentDigest,
27572
+ workspacePath,
27573
+ currentWorkspaceDigest,
27574
+ approvedTargets,
27575
+ rowInteger(row, "expires_at"),
27576
+ rowInteger(row, "revocation_epoch")
27577
+ );
27578
+ };
27579
+ recordUnavailable = (request, code, message, now) => {
27580
+ this.#database.prepare(
27581
+ `INSERT OR IGNORE INTO local_bot_binding_resolutions (
27582
+ request_id, binding_id, local_grant_id, resolved_at,
27583
+ result, error_code, error_message
27584
+ ) VALUES (?, ?, '', ?, 'unavailable', ?, ?)`
27585
+ ).run(request.requestId, request.bindingId, now, code, message);
27586
+ };
27587
+ close = () => {
27588
+ this.#database.close();
27589
+ };
27590
+ resolveProposal = async (request, catalog, directories, bindingAuthorityId, signal) => {
27591
+ const agent = catalog.find(request.agentRef);
27592
+ if (request.requiredCapabilities.includes("embedded-context") && !agent.capabilities.embeddedContextPrompt) {
27593
+ throw new LocalBotAuthorizationError(
27594
+ "binding_incompatible",
27595
+ "The local Agent cannot apply embedded Bot context"
27596
+ );
27597
+ }
27598
+ if (request.requiredCapabilities.some((capability) => capability !== "embedded-context")) {
27599
+ throw new LocalBotAuthorizationError(
27600
+ "binding_incompatible",
27601
+ "The Bot requires an unsupported local Agent capability"
27602
+ );
27603
+ }
27604
+ const [adapterUnchanged, agentUnchanged] = await Promise.all([
27605
+ revalidateExecutable(agent.adapterIdentity),
27606
+ revalidateExecutable(agent.agentIdentity)
27607
+ ]);
27608
+ signal.throwIfAborted();
27609
+ if (!adapterUnchanged || !agentUnchanged) {
27610
+ throw new LocalBotAuthorizationError(
27611
+ "binding_incompatible",
27612
+ "The local Agent executable changed before approval"
27613
+ );
27614
+ }
27615
+ const workspacePath = await directories.resolve(bindingAuthorityId, request.workspaceRef, signal);
27616
+ return {
27617
+ agent,
27618
+ agentIdentityDigest: agentDigest(agent),
27619
+ workspaceIdentityDigest: await workspaceDigest(workspacePath),
27620
+ workspacePath
27621
+ };
27622
+ };
27623
+ revoke = (localGrantId, now) => {
27624
+ this.#database.prepare(
27625
+ `UPDATE local_bot_grants
27626
+ SET revoked_at = COALESCE(revoked_at, ?), revocation_epoch = revocation_epoch + 1
27627
+ WHERE local_grant_id = ? AND revoked_at IS NULL`
27628
+ ).run(now, localGrantId);
27629
+ };
27630
+ };
27631
+
27632
+ // src/bots/bot-context-applicator.ts
27633
+ var AppliedBotContext = class {
27634
+ resources;
27635
+ constructor(resources) {
27636
+ this.resources = Object.freeze([...resources]);
27637
+ }
27638
+ };
27639
+ var EmbeddedBotContextApplicator = class {
27640
+ apply = async (command, grant, resources, signal) => {
27641
+ signal.throwIfAborted();
27642
+ if (grant.botId !== command.botId || grant.behaviorRevisionId !== command.behaviorRevisionId || grant.behaviorDigest !== command.behaviorDigest) {
27643
+ throw new LocalBotAuthorizationError(
27644
+ "binding_not_approved",
27645
+ "The Bot behavior does not match its local authorization"
27646
+ );
27647
+ }
27648
+ if (command.behaviorInstructions.length === 0) {
27649
+ return new AppliedBotContext(resources);
27650
+ }
27651
+ if (!grant.agent.capabilities.embeddedContextPrompt) {
27652
+ throw new LocalBotAuthorizationError(
27653
+ "binding_incompatible",
27654
+ "The local Agent cannot enforce the Bot behavior context"
27655
+ );
27656
+ }
27657
+ const trustedContext = {
27658
+ mimeType: "text/markdown",
27659
+ name: "Mobius Bot behavior",
27660
+ text: command.behaviorInstructions,
27661
+ type: "embedded",
27662
+ uri: `mobius://bots/${encodeURIComponent(command.botId)}/behavior-revisions/${encodeURIComponent(command.behaviorRevisionId)}?sha256=${command.behaviorDigest}`
27663
+ };
27664
+ return new AppliedBotContext([trustedContext, ...resources]);
27665
+ };
27666
+ };
27667
+
27668
+ // src/bots/bot-execution-context.ts
27669
+ import { randomBytes } from "node:crypto";
27670
+ var ActiveBotExecutionContext = class {
27671
+ command;
27672
+ contextHandle;
27673
+ constructor(contextHandle, command) {
27674
+ this.contextHandle = contextHandle;
27675
+ this.command = command;
27676
+ }
27677
+ resolveTarget = (target) => {
27678
+ if (target === "current") {
27679
+ if (!(this.command.replyRoute instanceof BotConnectionReplyRoute)) {
27680
+ throw new LocalBotAuthorizationError(
27681
+ "delivery_target_not_allowed",
27682
+ "This Bot conversation has no external reply target"
27683
+ );
27684
+ }
27685
+ return this.command.replyRoute.deliveryTargetId;
27686
+ }
27687
+ const resolved = this.command.allowedDeliveryTargets.find((candidate) => candidate.alias === target);
27688
+ if (resolved === void 0) {
27689
+ throw new LocalBotAuthorizationError(
27690
+ "delivery_target_not_allowed",
27691
+ "The named Bot delivery target is not approved"
27692
+ );
27693
+ }
27694
+ return resolved.deliveryTargetId;
27695
+ };
27696
+ };
27697
+ var BotExecutionContextLease = class {
27698
+ context;
27699
+ #release;
27700
+ #released = false;
27701
+ constructor(context, release) {
27702
+ this.context = context;
27703
+ this.#release = release;
27704
+ }
27705
+ release = () => {
27706
+ if (this.#released) {
27707
+ return;
27708
+ }
27709
+ this.#released = true;
27710
+ this.#release();
27711
+ };
27712
+ };
27713
+ var BotExecutionContextRegistry = class {
27714
+ #activeByHandle = /* @__PURE__ */ new Map();
27715
+ #handlesBySession = /* @__PURE__ */ new Map();
27716
+ #inactiveHandles = /* @__PURE__ */ new Set();
27717
+ #now;
27718
+ constructor(now = Date.now) {
27719
+ this.#now = now;
27720
+ }
27721
+ activate = (command) => {
27722
+ let handle = this.#handlesBySession.get(command.sessionId);
27723
+ if (handle === void 0) {
27724
+ handle = `ctx_${randomBytes(32).toString("base64url")}`;
27725
+ this.#handlesBySession.set(command.sessionId, handle);
27726
+ }
27727
+ if (this.#activeByHandle.has(handle)) {
27728
+ throw new LocalBotAuthorizationError("session_busy", "The Bot execution context is already active");
27729
+ }
27730
+ const context = new ActiveBotExecutionContext(handle, command);
27731
+ this.#inactiveHandles.delete(handle);
27732
+ this.#activeByHandle.set(handle, context);
27733
+ return new BotExecutionContextLease(context, () => {
27734
+ if (this.#activeByHandle.get(handle) === context) {
27735
+ this.#activeByHandle.delete(handle);
27736
+ this.#inactiveHandles.add(handle);
27737
+ }
27738
+ });
27739
+ };
27740
+ read = (handle) => {
27741
+ const context = this.#activeByHandle.get(handle);
27742
+ if (context === void 0) {
27743
+ if (this.#inactiveHandles.has(handle)) {
27744
+ throw new LocalBotAuthorizationError(
27745
+ "execution_capability_expired",
27746
+ "The Bot execution capability has expired"
27747
+ );
27748
+ }
27749
+ throw new LocalBotAuthorizationError(
27750
+ "execution_context_required",
27751
+ "An active Bot execution context is required"
27752
+ );
27753
+ }
27754
+ if (Date.parse(context.command.executionDeadlineAt) <= this.#now()) {
27755
+ throw new LocalBotAuthorizationError(
27756
+ "execution_capability_expired",
27757
+ "The Bot execution capability has expired"
27758
+ );
27759
+ }
27760
+ return context;
27761
+ };
27762
+ };
27763
+
27764
+ // src/bots/bot-outbound-ipc.ts
27765
+ import { chmod as chmod2, mkdir as mkdir4, unlink } from "node:fs/promises";
27766
+ import { createServer } from "node:net";
27767
+ import { dirname as dirname6, isAbsolute as isAbsolute8 } from "node:path";
27768
+ import { fetch as fetch4 } from "undici";
27769
+ var BOT_IPC_REQUEST_LIMIT = 32 * 1024;
27770
+ var BOT_IPC_TIMEOUT_MILLISECONDS2 = 2e4;
27771
+ var BOT_RELAY_TIMEOUT_MILLISECONDS = 2e4;
27772
+ var IDENTIFIER_PATTERN6 = /^[a-zA-Z0-9][a-zA-Z0-9._:-]{0,127}$/;
27773
+ var WINDOWS_NAMED_PIPE_PREFIX = "\\\\.\\pipe\\";
27774
+ var BotOutboundIpcRequest = class {
27775
+ contextHandle;
27776
+ idempotencyKey;
27777
+ target;
27778
+ text;
27779
+ constructor(contextHandle, idempotencyKey, target, text) {
27780
+ this.contextHandle = contextHandle;
27781
+ this.idempotencyKey = idempotencyKey;
27782
+ this.target = target;
27783
+ this.text = text;
27784
+ }
27785
+ };
27786
+ function isRecord10(value) {
27787
+ return typeof value === "object" && value !== null && !Array.isArray(value);
27788
+ }
27789
+ function decodeRequest(encoded) {
27790
+ let value;
27791
+ try {
27792
+ value = JSON.parse(encoded);
27793
+ } catch (cause) {
27794
+ throw new LocalBotAuthorizationError("invalid_request", "The local Bot request is invalid", { cause });
27795
+ }
27796
+ if (!isRecord10(value)) {
27797
+ throw new LocalBotAuthorizationError("invalid_request", "The local Bot request is invalid");
27798
+ }
27799
+ const keys = Object.keys(value);
27800
+ if (keys.length !== 4 || !keys.every((key) => ["contextHandle", "idempotencyKey", "target", "text"].includes(key))) {
27801
+ throw new LocalBotAuthorizationError("invalid_request", "The local Bot request fields are invalid");
27802
+ }
27803
+ const contextHandle = value["contextHandle"];
27804
+ const idempotencyKey = value["idempotencyKey"];
27805
+ const target = value["target"];
27806
+ const text = value["text"];
27807
+ if (typeof contextHandle !== "string" || !/^ctx_[a-zA-Z0-9_-]{43}$/.test(contextHandle) || typeof idempotencyKey !== "string" || !IDENTIFIER_PATTERN6.test(idempotencyKey) || typeof target !== "string" || !IDENTIFIER_PATTERN6.test(target) || typeof text !== "string" || text.trim().length === 0 || text.length > 1e4) {
27808
+ throw new LocalBotAuthorizationError("invalid_request", "The local Bot request is invalid");
27809
+ }
27810
+ return new BotOutboundIpcRequest(contextHandle, idempotencyKey, target, text);
27811
+ }
27812
+ function relayEndpoint(relayUrl, context, target) {
27813
+ const endpoint = new URL(relayUrl);
27814
+ if (endpoint.protocol !== "ws:" && endpoint.protocol !== "wss:") {
27815
+ throw new LocalBotAuthorizationError("bot_service_unavailable", "The Mobius Relay URL is invalid");
27816
+ }
27817
+ endpoint.protocol = endpoint.protocol === "wss:" ? "https:" : "http:";
27818
+ endpoint.search = "";
27819
+ const execution = encodeURIComponent(context.command.executionId);
27820
+ if (target === "current") {
27821
+ context.resolveTarget(target);
27822
+ endpoint.pathname = `${MOBIUS_API_PREFIX}/v1/bot-executions/${execution}/reply-messages`;
27823
+ return endpoint;
27824
+ }
27825
+ const deliveryTargetId = context.resolveTarget(target);
27826
+ endpoint.pathname = `${MOBIUS_API_PREFIX}/v1/bot-executions/${execution}/delivery-targets/${encodeURIComponent(deliveryTargetId)}/messages`;
27827
+ return endpoint;
27828
+ }
27829
+ function daemonToken(relayUrl) {
27830
+ const token = relayUrl.searchParams.get("token") ?? "";
27831
+ if (!/^[a-zA-Z0-9_-]{32,256}$/.test(token)) {
27832
+ throw new LocalBotAuthorizationError("bot_service_unavailable", "The Runtime credential is unavailable");
27833
+ }
27834
+ return token;
27835
+ }
27836
+ async function decodeRelayResponse(response) {
27837
+ const encoded = await response.text();
27838
+ let value;
27839
+ try {
27840
+ value = JSON.parse(encoded);
27841
+ } catch (cause) {
27842
+ throw new LocalBotAuthorizationError("bot_service_unavailable", "The Mobius Relay returned invalid data", {
27843
+ cause
27844
+ });
27845
+ }
27846
+ if (response.status === 202 && isRecord10(value) && typeof value["outboundMessageId"] === "string") {
27847
+ return value["outboundMessageId"];
27848
+ }
27849
+ if (isRecord10(value) && isRecord10(value["error"])) {
27850
+ const error61 = value["error"];
27851
+ if (typeof error61["code"] === "string" && typeof error61["message"] === "string") {
27852
+ throw new LocalBotAuthorizationError(error61["code"], error61["message"]);
27853
+ }
27854
+ }
27855
+ throw new LocalBotAuthorizationError("bot_service_unavailable", "The Mobius Relay rejected the Bot action");
27856
+ }
27857
+ var BotOutboundIpcServer = class {
27858
+ #registry;
27859
+ #relayUrl;
27860
+ #server;
27861
+ #socketPath;
27862
+ #usesFilesystemSocket;
27863
+ constructor(socketPath, relayUrl, registry2) {
27864
+ const usesFilesystemSocket = !socketPath.startsWith(WINDOWS_NAMED_PIPE_PREFIX);
27865
+ if (usesFilesystemSocket && !isAbsolute8(socketPath)) {
27866
+ throw new Error("The Bot IPC path must be absolute");
27867
+ }
27868
+ this.#registry = registry2;
27869
+ this.#relayUrl = new URL(relayUrl);
27870
+ this.#server = createServer({ allowHalfOpen: true }, (socket) => this.accept(socket));
27871
+ this.#socketPath = socketPath;
27872
+ this.#usesFilesystemSocket = usesFilesystemSocket;
27873
+ }
27874
+ get socketPath() {
27875
+ return this.#socketPath;
27876
+ }
27877
+ listen = async (signal) => {
27878
+ signal.throwIfAborted();
27879
+ if (this.#usesFilesystemSocket) {
27880
+ await mkdir4(dirname6(this.#socketPath), { mode: 448, recursive: true });
27881
+ await unlink(this.#socketPath).catch((error61) => {
27882
+ if (!isRecord10(error61) || error61["code"] !== "ENOENT") {
27883
+ throw error61;
27884
+ }
27885
+ });
27886
+ }
27887
+ await new Promise((resolve5, reject) => {
27888
+ const fail = (error61) => reject(error61);
27889
+ this.#server.once("error", fail);
27890
+ this.#server.listen(this.#socketPath, () => {
27891
+ this.#server.removeListener("error", fail);
27892
+ resolve5();
27893
+ });
27894
+ });
27895
+ if (this.#usesFilesystemSocket) {
27896
+ await chmod2(this.#socketPath, 384);
27897
+ }
27898
+ signal.addEventListener("abort", this.abort, { once: true });
27899
+ if (signal.aborted) {
27900
+ this.abort();
27901
+ }
27902
+ };
27903
+ close = async () => {
27904
+ if (this.#server.listening) {
27905
+ await new Promise((resolve5, reject) => {
27906
+ this.#server.close((error61) => {
27907
+ if (error61 === void 0) {
27908
+ resolve5();
27909
+ return;
27910
+ }
27911
+ reject(error61);
27912
+ });
27913
+ });
27914
+ }
27915
+ if (this.#usesFilesystemSocket) {
27916
+ await unlink(this.#socketPath).catch((error61) => {
27917
+ if (!isRecord10(error61) || error61["code"] !== "ENOENT") {
27918
+ throw error61;
27919
+ }
27920
+ });
27921
+ }
27922
+ };
27923
+ #abort = () => {
27924
+ this.#server.close();
27925
+ };
27926
+ abort = () => this.#abort();
27927
+ accept = (socket) => {
27928
+ const chunks = [];
27929
+ let length = 0;
27930
+ let rejected = false;
27931
+ const controller = new AbortController();
27932
+ socket.setTimeout(BOT_IPC_TIMEOUT_MILLISECONDS2, () => {
27933
+ controller.abort(new Error("Bot IPC request timed out"));
27934
+ socket.destroy();
27935
+ });
27936
+ socket.on("data", (chunk) => {
27937
+ length += chunk.byteLength;
27938
+ if (length > BOT_IPC_REQUEST_LIMIT) {
27939
+ rejected = true;
27940
+ controller.abort(new Error("Bot IPC request is too large"));
27941
+ socket.end(
27942
+ JSON.stringify({
27943
+ error: { code: "invalid_request", message: "The local Bot request is too large" },
27944
+ ok: false
27945
+ })
27946
+ );
27947
+ return;
27948
+ }
27949
+ chunks.push(chunk);
27950
+ });
27951
+ socket.once("error", () => controller.abort());
27952
+ socket.once("close", () => controller.abort());
27953
+ socket.once("end", () => {
27954
+ if (rejected) {
27955
+ return;
27956
+ }
27957
+ void this.handle(Buffer.concat(chunks).toString("utf8").trim(), controller.signal).then(
27958
+ (outboundMessageId) => {
27959
+ if (!socket.destroyed) {
27960
+ socket.end(JSON.stringify({ ok: true, outboundMessageId }));
27961
+ }
27962
+ },
27963
+ (error61) => {
27964
+ if (socket.destroyed) {
27965
+ return;
27966
+ }
27967
+ const code = error61 instanceof LocalBotAuthorizationError ? error61.code : "bot_service_unavailable";
27968
+ const message = error61 instanceof LocalBotAuthorizationError ? error61.message : "The local Bot action could not be completed";
27969
+ socket.end(JSON.stringify({ error: { code, message }, ok: false }));
27970
+ }
27971
+ );
27972
+ });
27973
+ };
27974
+ handle = async (encoded, signal) => {
27975
+ const request = decodeRequest(encoded);
27976
+ const context = this.#registry.read(request.contextHandle);
27977
+ const timeout = AbortSignal.timeout(BOT_RELAY_TIMEOUT_MILLISECONDS);
27978
+ const requestSignal = AbortSignal.any([signal, timeout]);
27979
+ let response;
27980
+ try {
27981
+ response = await fetch4(relayEndpoint(this.#relayUrl, context, request.target), {
27982
+ body: JSON.stringify({ idempotencyKey: request.idempotencyKey, text: request.text }),
27983
+ headers: {
27984
+ authorization: `Bearer ${daemonToken(this.#relayUrl)}`,
27985
+ "content-type": "application/json",
27986
+ "x-mobius-bot-execution-capability": context.command.executionCapabilitySecret
27987
+ },
27988
+ method: "POST",
27989
+ signal: requestSignal
27990
+ });
27991
+ } catch (cause) {
27992
+ signal.throwIfAborted();
27993
+ throw new LocalBotAuthorizationError(
27994
+ timeout.aborted ? "bot_service_timeout" : "bot_service_unavailable",
27995
+ timeout.aborted ? "The Mobius Bot action timed out" : "The Mobius Relay is unavailable",
27996
+ { cause }
27997
+ );
27998
+ }
27999
+ return await decodeRelayResponse(response);
28000
+ };
28001
+ };
28002
+
28003
+ // src/native-sessions/service.ts
28004
+ import { randomUUID as randomUUID4 } from "node:crypto";
28005
+
28006
+ // src/native-sessions/codex-history.ts
28007
+ import { spawn as spawn4 } from "node:child_process";
28008
+ var responseSchema = external_exports.union([
28009
+ external_exports.object({
28010
+ id: external_exports.number(),
28011
+ error: external_exports.object({ code: external_exports.number(), message: external_exports.string() })
28012
+ }),
28013
+ external_exports.object({ id: external_exports.number(), result: external_exports.unknown() }),
28014
+ external_exports.object({ method: external_exports.string() })
28015
+ ]);
28016
+ var threadSchema = external_exports.object({
28017
+ thread: external_exports.object({
28018
+ id: nativeSessionIdSchema,
28019
+ cwd: external_exports.string().min(1).max(2048).refine((path2) => !path2.includes("\0"))
28020
+ })
28021
+ });
28022
+ var turnsSchema = external_exports.object({
28023
+ data: external_exports.array(external_exports.object({ items: external_exports.array(external_exports.unknown()).max(1e5) })).max(SESSION_HISTORY_PREVIEW_MESSAGE_LIMIT),
28024
+ nextCursor: external_exports.string().nullish()
28025
+ });
28026
+ var itemTypeSchema = external_exports.object({ type: external_exports.string().min(1).max(80) });
28027
+ var userMessageSchema = external_exports.object({
28028
+ content: external_exports.array(external_exports.unknown()).max(1e4)
28029
+ });
28030
+ var textSchema = external_exports.object({ text: external_exports.string() });
28031
+ var imageSchema = external_exports.object({ url: external_exports.string() });
28032
+ var agentMessageSchema = textSchema.extend({ phase: external_exports.string().nullish() });
28033
+ function decodeHistory(thread, value) {
28034
+ const page = turnsSchema.parse(value);
28035
+ const messages = [];
28036
+ let characters = 0;
28037
+ let imageCharacters = 0;
28038
+ let truncated = page.nextCursor != null;
28039
+ for (const turn of page.data.toReversed()) {
28040
+ for (const item of turn.items) {
28041
+ const { type } = itemTypeSchema.parse(item);
26680
28042
  let message;
26681
28043
  if (type === "userMessage") {
26682
28044
  const { content } = userMessageSchema.parse(item);
@@ -26955,7 +28317,7 @@ var NativeSessionService = class {
26955
28317
  if (authorized === null) {
26956
28318
  continue;
26957
28319
  }
26958
- const entryId = randomUUID2();
28320
+ const entryId = randomUUID4();
26959
28321
  if (this.#entries.size >= 5e3) {
26960
28322
  this.#entries.clear();
26961
28323
  }
@@ -26983,7 +28345,7 @@ var NativeSessionService = class {
26983
28345
  "invalid_native_session_response"
26984
28346
  );
26985
28347
  }
26986
- nextCursor = randomUUID2();
28348
+ nextCursor = randomUUID4();
26987
28349
  if (this.#cursors.size >= 500) {
26988
28350
  this.#cursors.clear();
26989
28351
  }
@@ -27201,13 +28563,13 @@ var NativeSessionService = class {
27201
28563
  };
27202
28564
 
27203
28565
  // src/prompt-artifact-resolver.ts
27204
- import { createHash as createHash2 } from "node:crypto";
27205
- import { fetch as fetch4 } from "undici";
28566
+ import { createHash as createHash3 } from "node:crypto";
28567
+ import { fetch as fetch5 } from "undici";
27206
28568
  var ARTIFACT_SCHEME = "mobius-artifact:";
27207
28569
  var ARTIFACT_DOWNLOAD_TIMEOUT_MILLISECONDS = 2e4;
27208
28570
  var MAX_AGENT_IMAGE_BASE64_LENGTH = 4e6;
27209
28571
  var MAX_AGENT_RESOURCE_BYTE_LENGTH = 1e6;
27210
- var IDENTIFIER_PATTERN5 = /^[a-zA-Z0-9][a-zA-Z0-9._:-]{0,127}$/;
28572
+ var IDENTIFIER_PATTERN7 = /^[a-zA-Z0-9][a-zA-Z0-9._:-]{0,127}$/;
27211
28573
  var PromptArtifactError = class extends Error {
27212
28574
  code;
27213
28575
  constructor(code, message, options = {}) {
@@ -27250,7 +28612,7 @@ function parseReference(resource) {
27250
28612
  const encodedByteLength2 = url2.searchParams.get("byteLength") ?? "";
27251
28613
  const sha256 = url2.searchParams.get("sha256") ?? "";
27252
28614
  const byteLength = Number(encodedByteLength2);
27253
- if (url2.protocol !== ARTIFACT_SCHEME || url2.hash.length > 0 || resource.type !== "link" || resource.text.length > 0 || !IDENTIFIER_PATTERN5.test(artifactId) || keys.length !== 2 || keys[0] !== "byteLength" || keys[1] !== "sha256" || !/^[1-9][0-9]*$/.test(encodedByteLength2) || !Number.isSafeInteger(byteLength) || !/^[a-f0-9]{64}$/.test(sha256)) {
28615
+ if (url2.protocol !== ARTIFACT_SCHEME || url2.hash.length > 0 || resource.type !== "link" || resource.text.length > 0 || !IDENTIFIER_PATTERN7.test(artifactId) || keys.length !== 2 || keys[0] !== "byteLength" || keys[1] !== "sha256" || !/^[1-9][0-9]*$/.test(encodedByteLength2) || !Number.isSafeInteger(byteLength) || !/^[a-f0-9]{64}$/.test(sha256)) {
27254
28616
  throw new PromptArtifactError("artifact_reference_invalid", "The prompt artifact reference is invalid");
27255
28617
  }
27256
28618
  return new PromptArtifactReference(artifactId, byteLength, sha256, resource);
@@ -27311,7 +28673,7 @@ async function download(config2, command, reference, signal) {
27311
28673
  const requestSignal = AbortSignal.any([signal, timeoutSignal]);
27312
28674
  let response;
27313
28675
  try {
27314
- response = await fetch4(downloadUrl(config2, command, reference), {
28676
+ response = await fetch5(downloadUrl(config2, command, reference), {
27315
28677
  dispatcher: environmentProxyDispatcher,
27316
28678
  headers: { accept: reference.resource.mimeType },
27317
28679
  signal: requestSignal
@@ -27331,7 +28693,7 @@ async function download(config2, command, reference, signal) {
27331
28693
  );
27332
28694
  }
27333
28695
  const bytes = await responseBytes(response, reference.byteLength, requestSignal);
27334
- if (createHash2("sha256").update(bytes).digest("hex") !== reference.sha256) {
28696
+ if (createHash3("sha256").update(bytes).digest("hex") !== reference.sha256) {
27335
28697
  throw new PromptArtifactError(
27336
28698
  "artifact_integrity_failed",
27337
28699
  "The prompt artifact failed integrity validation"
@@ -27476,7 +28838,7 @@ function connectRelay(url2, signal) {
27476
28838
  }
27477
28839
 
27478
28840
  // src/relay-connection/liveness.ts
27479
- import { randomUUID as randomUUID3 } from "node:crypto";
28841
+ import { randomUUID as randomUUID5 } from "node:crypto";
27480
28842
  var HEARTBEAT_ACK_TIMEOUT_MILLISECONDS = 1e4;
27481
28843
  var HEARTBEAT_INTERVAL_MILLISECONDS = 2e4;
27482
28844
  var RelayLivenessState = class {
@@ -27564,7 +28926,7 @@ var RelayConnectionLiveness = class {
27564
28926
  }
27565
28927
  throw new Error("Heartbeat was scheduled in an invalid state");
27566
28928
  }
27567
- const heartbeatId = randomUUID3();
28929
+ const heartbeatId = randomUUID5();
27568
28930
  this.#state = new AwaitingHeartbeatAckState(
27569
28931
  heartbeatId,
27570
28932
  this.#timer.schedule(this.#handleTimeout, HEARTBEAT_ACK_TIMEOUT_MILLISECONDS)
@@ -27580,8 +28942,8 @@ var RelayConnectionLiveness = class {
27580
28942
 
27581
28943
  // src/relay-connection/session-event-outbox.ts
27582
28944
  import { mkdirSync as mkdirSync3 } from "node:fs";
27583
- import { dirname as dirname6 } from "node:path";
27584
- import { DatabaseSync as DatabaseSync3 } from "node:sqlite";
28945
+ import { dirname as dirname7 } from "node:path";
28946
+ import { DatabaseSync as DatabaseSync4 } from "node:sqlite";
27585
28947
  function readPendingEnvelope(row) {
27586
28948
  if (typeof row !== "object" || row === null || Array.isArray(row)) {
27587
28949
  throw new Error("SQLite returned an invalid session event outbox row");
@@ -27595,8 +28957,8 @@ function readPendingEnvelope(row) {
27595
28957
  var SessionEventOutbox = class {
27596
28958
  #database;
27597
28959
  constructor(path2) {
27598
- mkdirSync3(dirname6(path2), { recursive: true });
27599
- this.#database = new DatabaseSync3(path2);
28960
+ mkdirSync3(dirname7(path2), { recursive: true });
28961
+ this.#database = new DatabaseSync4(path2);
27600
28962
  this.#database.exec(`
27601
28963
  CREATE TABLE IF NOT EXISTS relay_session_event_outbox (
27602
28964
  ordinal INTEGER PRIMARY KEY AUTOINCREMENT,
@@ -27606,6 +28968,15 @@ var SessionEventOutbox = class {
27606
28968
  ) STRICT;
27607
28969
  CREATE INDEX IF NOT EXISTS relay_session_event_outbox_order
27608
28970
  ON relay_session_event_outbox(ordinal);
28971
+ CREATE TABLE IF NOT EXISTS relay_session_event_dead_letters (
28972
+ ordinal INTEGER PRIMARY KEY,
28973
+ event_id TEXT NOT NULL UNIQUE,
28974
+ session_id TEXT NOT NULL,
28975
+ envelope_json TEXT NOT NULL,
28976
+ rejection_code TEXT NOT NULL CHECK (
28977
+ rejection_code IN ('session_deleted', 'session_not_found')
28978
+ )
28979
+ ) STRICT;
27609
28980
  CREATE TABLE IF NOT EXISTS relay_session_event_sources (
27610
28981
  source_key TEXT PRIMARY KEY,
27611
28982
  next_source_seq INTEGER NOT NULL
@@ -27678,6 +29049,35 @@ var SessionEventOutbox = class {
27678
29049
  WHERE event_id = ? AND session_id = ?`
27679
29050
  ).run(acknowledgement.eventId, acknowledgement.sessionId);
27680
29051
  };
29052
+ quarantine = (rejection) => {
29053
+ this.#database.exec("BEGIN IMMEDIATE");
29054
+ try {
29055
+ const insertion = this.#database.prepare(
29056
+ `INSERT INTO relay_session_event_dead_letters (
29057
+ ordinal, event_id, session_id, envelope_json, rejection_code
29058
+ )
29059
+ SELECT ordinal, event_id, session_id, envelope_json, ?
29060
+ FROM relay_session_event_outbox
29061
+ WHERE event_id = ? AND session_id = ?`
29062
+ ).run(rejection.code, rejection.eventId, rejection.sessionId);
29063
+ if (insertion.changes !== 1) {
29064
+ this.#database.exec("COMMIT");
29065
+ return false;
29066
+ }
29067
+ const deletion = this.#database.prepare(
29068
+ `DELETE FROM relay_session_event_outbox
29069
+ WHERE event_id = ? AND session_id = ?`
29070
+ ).run(rejection.eventId, rejection.sessionId);
29071
+ if (deletion.changes !== 1) {
29072
+ throw new Error("The rejected session event could not be removed from the durable outbox");
29073
+ }
29074
+ this.#database.exec("COMMIT");
29075
+ return true;
29076
+ } catch (error61) {
29077
+ this.#database.exec("ROLLBACK");
29078
+ throw error61;
29079
+ }
29080
+ };
27681
29081
  close = () => {
27682
29082
  this.#database.close();
27683
29083
  };
@@ -27749,6 +29149,12 @@ var RELAY_RECONNECT_DELAY_MILLISECONDS = 500;
27749
29149
  var RELAY_CONNECTION_REFRESH_MILLISECONDS = 20 * 60 * 1e3;
27750
29150
  var ACTIVE_TURN_RECONCILIATION_TIMEOUT_MILLISECONDS = 2e4;
27751
29151
  var ACTIVE_TURN_RECONCILIATION_CLOSE_CODE = 4009;
29152
+ function botIpcSocketPath() {
29153
+ if (process.platform === "win32") {
29154
+ return `\\\\.\\pipe\\mobius-bot-${randomUUID6()}`;
29155
+ }
29156
+ return join16("/tmp", `mobius-bot-${randomUUID6()}.sock`);
29157
+ }
27752
29158
  var RelayConnectionRefreshState = class {
27753
29159
  };
27754
29160
  var ScheduledRelayConnectionRefreshState = class extends RelayConnectionRefreshState {
@@ -28006,7 +29412,7 @@ async function reconcileActiveTurn(config2, turn, signal) {
28006
29412
  const requestSignal = AbortSignal.any([signal, timeoutSignal]);
28007
29413
  let response;
28008
29414
  try {
28009
- response = await fetch5(activeTurnReconciliationEndpoint(config2, turn), {
29415
+ response = await fetch6(activeTurnReconciliationEndpoint(config2, turn), {
28010
29416
  body: JSON.stringify({ outcome: { kind: "running" } }),
28011
29417
  dispatcher: environmentProxyDispatcher,
28012
29418
  headers: { "content-type": "application/json" },
@@ -28109,13 +29515,13 @@ function reportFailure(publisher, command, code, message, attemptId) {
28109
29515
  );
28110
29516
  }
28111
29517
  function operationErrorCode(error61) {
28112
- if (error61 instanceof AcpExecutionError || error61 instanceof LocalAuthorizationError || error61 instanceof LocalAgentCatalogError || error61 instanceof PromptArtifactError) {
29518
+ if (error61 instanceof AcpExecutionError || error61 instanceof LocalAuthorizationError || error61 instanceof LocalAgentCatalogError || error61 instanceof LocalBotAuthorizationError || error61 instanceof PromptArtifactError) {
28113
29519
  return error61.code;
28114
29520
  }
28115
29521
  return "session_operation_failed";
28116
29522
  }
28117
29523
  function operationErrorMessage(error61) {
28118
- if (error61 instanceof AcpExecutionError || error61 instanceof LocalAuthorizationError || error61 instanceof LocalAgentCatalogError || error61 instanceof PromptArtifactError) {
29524
+ if (error61 instanceof AcpExecutionError || error61 instanceof LocalAuthorizationError || error61 instanceof LocalAgentCatalogError || error61 instanceof LocalBotAuthorizationError || error61 instanceof PromptArtifactError) {
28119
29525
  return error61.message;
28120
29526
  }
28121
29527
  return "The local agent operation could not be completed";
@@ -28380,6 +29786,175 @@ async function executePrompt(outbox, publisher, command, config2, directories, a
28380
29786
  console.error("Mobius daemon command failed", error61);
28381
29787
  }
28382
29788
  }
29789
+ function botExecutionAgent(agent, contextHandle, socketPath) {
29790
+ return new LocalAgentDefinition(
29791
+ agent.id,
29792
+ agent.label,
29793
+ agent.command,
29794
+ agent.arguments,
29795
+ {
29796
+ ...agent.environment,
29797
+ MOBIUS_BOT_CONTEXT: contextHandle,
29798
+ MOBIUS_BOT_SOCKET: socketPath,
29799
+ MOBIUS_RELAY_TOKEN: "",
29800
+ MOBIUS_RELAY_URL: ""
29801
+ },
29802
+ agent.adapterVersion,
29803
+ agent.agentVersion,
29804
+ agent.adapterIdentity,
29805
+ agent.agentIdentity,
29806
+ agent.promptTimeoutMilliseconds,
29807
+ agent.capabilities
29808
+ );
29809
+ }
29810
+ async function executeBotPrompt(outbox, publisher, command, config2, directories, audit, sessions, grants, contexts, applicator, ipc, attemptId, signal) {
29811
+ try {
29812
+ if (command.additionalDirectoryIds.length > 0) {
29813
+ throw new LocalBotAuthorizationError(
29814
+ "binding_not_approved",
29815
+ "The Bot execution requested unapproved additional directories"
29816
+ );
29817
+ }
29818
+ const deadline = Date.parse(command.executionDeadlineAt);
29819
+ const remaining = deadline - Date.now();
29820
+ if (!Number.isSafeInteger(deadline) || remaining <= 0) {
29821
+ throw new LocalBotAuthorizationError("turn_expired", "The Bot execution deadline has expired");
29822
+ }
29823
+ const grant = await grants.resolveExecution(
29824
+ command,
29825
+ config2.catalog,
29826
+ directories,
29827
+ config2.bindingId,
29828
+ Date.now(),
29829
+ signal
29830
+ );
29831
+ const attachments = await resolvePromptArtifacts(config2, command, signal);
29832
+ const applied = await applicator.apply(command, grant, attachments.resources, signal);
29833
+ const lease = contexts.activate(command);
29834
+ try {
29835
+ const deadlineSignal = AbortSignal.timeout(remaining);
29836
+ const executionSignal = AbortSignal.any([signal, deadlineSignal]);
29837
+ const agent = botExecutionAgent(grant.agent, lease.context.contextHandle, ipc.socketPath);
29838
+ audit.record({
29839
+ commandId: command.commandId,
29840
+ details: {
29841
+ behaviorRevisionId: command.behaviorRevisionId,
29842
+ bindingId: command.bindingId,
29843
+ botId: command.botId,
29844
+ executionId: command.executionId,
29845
+ localGrantId: command.localGrantId
29846
+ },
29847
+ event: "bot_session_authorized",
29848
+ sessionId: command.sessionId
29849
+ });
29850
+ outbox.transitionExecution(command.commandId, "running");
29851
+ publisher.recordAttempt(
29852
+ command.sessionId,
29853
+ encodeSessionStartedEvent({
29854
+ attemptId,
29855
+ commandId: command.commandId,
29856
+ kind: SESSION_STARTED_KIND,
29857
+ sessionId: command.sessionId
29858
+ }),
29859
+ attemptId
29860
+ );
29861
+ const result = await sessions.runPrompt({
29862
+ additionalDirectories: [],
29863
+ agent,
29864
+ commandId: command.commandId,
29865
+ cwd: grant.workspacePath,
29866
+ images: attachments.images,
29867
+ onActivity: (activity) => {
29868
+ publisher.recordAttempt(
29869
+ command.sessionId,
29870
+ encodeAgentActivityEvent({
29871
+ activityId: activity.activityId,
29872
+ activityType: activity.activityType,
29873
+ commandId: command.commandId,
29874
+ content: activity.content,
29875
+ detail: activity.detail,
29876
+ input: activity.input,
29877
+ kind: AGENT_ACTIVITY_KIND,
29878
+ locations: activity.locations,
29879
+ name: activity.name,
29880
+ output: activity.output,
29881
+ sequence: activity.sequence,
29882
+ sessionId: command.sessionId,
29883
+ status: activity.status,
29884
+ title: activity.title,
29885
+ toolKind: activity.toolKind
29886
+ }),
29887
+ attemptId
29888
+ );
29889
+ return Promise.resolve();
29890
+ },
29891
+ onText: (text) => {
29892
+ publisher.recordAttempt(
29893
+ command.sessionId,
29894
+ encodeAgentMessageDeltaEvent({
29895
+ commandId: command.commandId,
29896
+ kind: AGENT_MESSAGE_DELTA_KIND,
29897
+ sessionId: command.sessionId,
29898
+ text
29899
+ }),
29900
+ attemptId
29901
+ );
29902
+ return Promise.resolve();
29903
+ },
29904
+ prompt: command.prompt,
29905
+ resources: applied.resources,
29906
+ sessionId: command.sessionId,
29907
+ signal: executionSignal
29908
+ });
29909
+ publisher.recordAttempt(
29910
+ command.sessionId,
29911
+ encodeSessionCompletedEvent({
29912
+ commandId: command.commandId,
29913
+ kind: SESSION_COMPLETED_KIND,
29914
+ sessionId: command.sessionId,
29915
+ stopReason: result.stopReason
29916
+ }),
29917
+ attemptId
29918
+ );
29919
+ outbox.transitionExecution(
29920
+ command.commandId,
29921
+ result.stopReason === "cancelled" ? "cancelled" : "succeeded"
29922
+ );
29923
+ audit.record({
29924
+ commandId: command.commandId,
29925
+ details: { botId: command.botId, executionId: command.executionId },
29926
+ event: result.stopReason === "cancelled" ? "bot_session_cancelled" : "bot_session_completed",
29927
+ sessionId: command.sessionId
29928
+ });
29929
+ } finally {
29930
+ lease.release();
29931
+ }
29932
+ } catch (error61) {
29933
+ const failure = Date.parse(command.executionDeadlineAt) <= Date.now() ? new LocalBotAuthorizationError("turn_expired", "The Bot execution deadline has expired", {
29934
+ cause: error61
29935
+ }) : error61;
29936
+ audit.record({
29937
+ commandId: command.commandId,
29938
+ details: {
29939
+ botId: command.botId,
29940
+ code: operationErrorCode(failure),
29941
+ executionId: command.executionId
29942
+ },
29943
+ event: "bot_session_failed",
29944
+ sessionId: command.sessionId
29945
+ });
29946
+ const code = operationErrorCode(failure);
29947
+ reportFailure(
29948
+ publisher,
29949
+ command,
29950
+ code === "session_operation_failed" ? "agent_execution_failed" : code,
29951
+ code === "session_operation_failed" ? "The local agent could not complete the Bot request" : operationErrorMessage(failure),
29952
+ attemptId
29953
+ );
29954
+ outbox.transitionExecution(command.commandId, "failed");
29955
+ console.error("Mobius daemon Bot command failed", failure);
29956
+ }
29957
+ }
28383
29958
  function waitForRelayRetry(signal, timer) {
28384
29959
  if (signal.aborted) {
28385
29960
  return Promise.resolve();
@@ -28416,7 +29991,7 @@ async function publishAgentCatalogUntilAvailable(config2, signal, timer) {
28416
29991
  }
28417
29992
  }
28418
29993
  }
28419
- async function runRelayConnection(config2, directories, audit, sessions, installations, installationObserver, nativeSessions, outbox, publisher, activeTurns, activeAttemptIds, onConnected, signal, timer) {
29994
+ async function runRelayConnection(config2, directories, audit, sessions, installations, installationObserver, nativeSessions, outbox, publisher, grants, contexts, applicator, ipc, activeTurns, activeAttemptIds, onConnected, signal, timer) {
28420
29995
  const relayUrl = new URL(config2.relayUrl);
28421
29996
  relayUrl.searchParams.set("liveness", "1");
28422
29997
  const socket = await connectRelay(relayUrl, signal);
@@ -28499,6 +30074,76 @@ async function runRelayConnection(config2, directories, audit, sessions, install
28499
30074
  outbox.acknowledge(decodeSessionEventAcknowledgement(encoded));
28500
30075
  return;
28501
30076
  }
30077
+ if (kind === SESSION_EVENT_REJECTED_KIND) {
30078
+ const rejection = decodeSessionEventRejection(encoded);
30079
+ if (outbox.quarantine(rejection)) {
30080
+ audit.record({
30081
+ commandId: rejection.eventId,
30082
+ details: { code: rejection.code },
30083
+ event: "session_event_rejected",
30084
+ sessionId: rejection.sessionId
30085
+ });
30086
+ } else {
30087
+ console.warn("Mobius daemon ignored a rejection for an unknown session event");
30088
+ }
30089
+ return;
30090
+ }
30091
+ if (kind === BOT_BINDING_APPROVAL_REQUEST_KIND) {
30092
+ const request = decodeBotExecutionBindingApprovalRequest(encoded);
30093
+ void grants.approve(
30094
+ request,
30095
+ config2.catalog,
30096
+ directories,
30097
+ config2.bindingId,
30098
+ Date.now(),
30099
+ connectionController.signal
30100
+ ).then((approved) => {
30101
+ audit.record({
30102
+ commandId: request.requestId,
30103
+ details: {
30104
+ behaviorRevisionId: request.behaviorRevisionId,
30105
+ bindingId: request.bindingId,
30106
+ botId: request.botId,
30107
+ localGrantId: approved.localGrantId
30108
+ },
30109
+ event: "bot_binding_approved",
30110
+ sessionId: `bot-binding:${request.bindingId}`
30111
+ });
30112
+ if (socket.readyState === WebSocket2.OPEN) {
30113
+ send(socket, encodeBotExecutionBindingApprovedEvent(approved));
30114
+ }
30115
+ }).catch((error61) => {
30116
+ if (connectionController.signal.aborted) {
30117
+ return;
30118
+ }
30119
+ const code = error61 instanceof LocalBotAuthorizationError ? error61.code : "binding_incompatible";
30120
+ const message = error61 instanceof LocalBotAuthorizationError ? error61.message : "The local execution target is incompatible";
30121
+ grants.recordUnavailable(request, code, message, Date.now());
30122
+ audit.record({
30123
+ commandId: request.requestId,
30124
+ details: { bindingId: request.bindingId, botId: request.botId, code },
30125
+ event: "bot_binding_unavailable",
30126
+ sessionId: `bot-binding:${request.bindingId}`
30127
+ });
30128
+ if (socket.readyState === WebSocket2.OPEN) {
30129
+ send(
30130
+ socket,
30131
+ encodeBotExecutionBindingUnavailableEvent(
30132
+ new BotExecutionBindingUnavailableEvent(
30133
+ request.requestId,
30134
+ request.botId,
30135
+ request.behaviorRevisionId,
30136
+ request.bindingId,
30137
+ request.bindingRevision,
30138
+ code,
30139
+ message
30140
+ )
30141
+ )
30142
+ );
30143
+ }
30144
+ });
30145
+ return;
30146
+ }
28502
30147
  if (kind === NATIVE_SESSION_CANCEL_KIND) {
28503
30148
  const command2 = decodeNativeSessionCancel(encoded);
28504
30149
  const pending = nativeRequests.get(command2.requestId);
@@ -28697,6 +30342,44 @@ async function runRelayConnection(config2, directories, audit, sessions, install
28697
30342
  });
28698
30343
  return;
28699
30344
  }
30345
+ if (kind === BOT_SESSION_PROMPT_KIND) {
30346
+ const command2 = decodeBotSessionPromptCommand(encoded);
30347
+ if (activeTurns.has(command2.commandId)) {
30348
+ return;
30349
+ }
30350
+ const receipt2 = outbox.claimExecution(command2.commandId, command2.sessionId, encoded);
30351
+ if (receipt2.kind === "duplicate") {
30352
+ return;
30353
+ }
30354
+ const turn2 = new ActiveDaemonTurn(command2, receipt2.attemptId);
30355
+ activeTurns.set(command2.commandId, turn2);
30356
+ activeAttemptIds.set(command2.sessionId, receipt2.attemptId);
30357
+ void executeBotPrompt(
30358
+ outbox,
30359
+ publisher,
30360
+ command2,
30361
+ config2,
30362
+ directories,
30363
+ audit,
30364
+ sessions,
30365
+ grants,
30366
+ contexts,
30367
+ applicator,
30368
+ ipc,
30369
+ receipt2.attemptId,
30370
+ turn2.signal
30371
+ ).catch((error61) => {
30372
+ console.error("Mobius daemon Bot turn failed", error61);
30373
+ }).finally(() => {
30374
+ activeTurns.delete(command2.commandId);
30375
+ if (activeAttemptIds.get(command2.sessionId) === receipt2.attemptId) {
30376
+ activeAttemptIds.delete(command2.sessionId);
30377
+ }
30378
+ turn2.finish();
30379
+ connectionRefresh.afterTurnFinished();
30380
+ });
30381
+ return;
30382
+ }
28700
30383
  if (kind !== SESSION_PROMPT_KIND) {
28701
30384
  throw new Error("Unsupported protocol message");
28702
30385
  }
@@ -28787,6 +30470,10 @@ async function runDaemon(config2, audit, signal, timer = systemDaemonTimer) {
28787
30470
  const sessionStore = new SqliteAcpSessionStore(config2.auditDatabasePath);
28788
30471
  const outbox = new SessionEventOutbox(config2.auditDatabasePath);
28789
30472
  const publisher = new DaemonSessionEventPublisher(outbox);
30473
+ const grants = new LocalBotGrantStore(config2.auditDatabasePath);
30474
+ const contexts = new BotExecutionContextRegistry();
30475
+ const applicator = new EmbeddedBotContextApplicator();
30476
+ const ipc = new BotOutboundIpcServer(botIpcSocketPath(), config2.relayUrl, contexts);
28790
30477
  const activeTurns = /* @__PURE__ */ new Map();
28791
30478
  const activeAttemptIds = /* @__PURE__ */ new Map();
28792
30479
  const recordSessionEvent = (sessionId, payload) => {
@@ -28825,6 +30512,7 @@ async function runDaemon(config2, audit, signal, timer = systemDaemonTimer) {
28825
30512
  };
28826
30513
  const catalogPublication = publishAgentCatalogUntilAvailable(config2, signal, timer);
28827
30514
  try {
30515
+ await ipc.listen(signal);
28828
30516
  while (!signal.aborted) {
28829
30517
  try {
28830
30518
  await runRelayConnection(
@@ -28837,6 +30525,10 @@ async function runDaemon(config2, audit, signal, timer = systemDaemonTimer) {
28837
30525
  nativeSessions,
28838
30526
  outbox,
28839
30527
  publisher,
30528
+ grants,
30529
+ contexts,
30530
+ applicator,
30531
+ ipc,
28840
30532
  activeTurns,
28841
30533
  activeAttemptIds,
28842
30534
  announceConnection,
@@ -28868,12 +30560,20 @@ async function runDaemon(config2, audit, signal, timer = systemDaemonTimer) {
28868
30560
  await installations.close();
28869
30561
  } finally {
28870
30562
  try {
28871
- await sessions.close();
30563
+ await ipc.close();
28872
30564
  } finally {
28873
30565
  try {
28874
- sessionStore.close();
30566
+ await sessions.close();
28875
30567
  } finally {
28876
- outbox.close();
30568
+ try {
30569
+ sessionStore.close();
30570
+ } finally {
30571
+ try {
30572
+ grants.close();
30573
+ } finally {
30574
+ outbox.close();
30575
+ }
30576
+ }
28877
30577
  }
28878
30578
  }
28879
30579
  }
@@ -28891,11 +30591,13 @@ Usage:
28891
30591
  mobius pair --url <relay-url> --code <pairing-code> [--workspace <directory>]
28892
30592
  mobius start --channel <channel-id>
28893
30593
  mobius agents [--json]
30594
+ mobius bot message send --target <current|alias> --text <message>
28894
30595
 
28895
30596
  Commands:
28896
30597
  pair Pair this machine and start its local daemon
28897
30598
  start Start the local daemon for a saved channel
28898
30599
  agents Show detected, missing, and integration-ready Agents
30600
+ bot Invoke Bot-scoped actions from an active local execution
28899
30601
 
28900
30602
  Pairing grants this browser access to the machine with your user account's permissions.
28901
30603
  New conversations default to ~/.mobius/workspace; choose other directories in the browser.
@@ -28911,7 +30613,7 @@ async function main() {
28911
30613
  if (arguments_.length > 1 || arguments_.length === 1 && arguments_[0] !== "--json") {
28912
30614
  throw new Error("Usage: mobius agents [--json]");
28913
30615
  }
28914
- await mkdir4(loadDefaultWorkspace(), { recursive: true, mode: 448 });
30616
+ await mkdir5(loadDefaultWorkspace(), { recursive: true, mode: 448 });
28915
30617
  const inventory = await discoverLocalAgentInventory({
28916
30618
  defaultWorkspace: loadDefaultWorkspace(),
28917
30619
  environment: process.env,
@@ -28920,6 +30622,18 @@ async function main() {
28920
30622
  process.stdout.write(formatAgentDiagnostics(inventory, arguments_[0] === "--json"));
28921
30623
  return;
28922
30624
  }
30625
+ if (command === "bot") {
30626
+ if (process.argv[3] !== "message" || process.argv[4] !== "send") {
30627
+ throw new BotMessageCommandError(
30628
+ "invalid_request",
30629
+ "Usage: mobius bot message send --target <current|alias> --text <message>"
30630
+ );
30631
+ }
30632
+ const outboundMessageId = await executeBotMessageCommand(process.argv.slice(5), process.env, shutdown.signal);
30633
+ process.stdout.write(`${JSON.stringify({ outboundMessageId })}
30634
+ `);
30635
+ return;
30636
+ }
28923
30637
  let config2;
28924
30638
  if (command === "pair") {
28925
30639
  process.stdout.write(`mobius version: ${package_default.version}
@@ -28959,7 +30673,8 @@ try {
28959
30673
  } catch (error61) {
28960
30674
  if (!shutdown.signal.aborted) {
28961
30675
  const message = error61 instanceof Error ? error61.message : "Unknown failure";
28962
- process.stderr.write(`Mobius daemon failed: ${message}
30676
+ const code = error61 instanceof BotMessageCommandError ? `${error61.code}: ` : "";
30677
+ process.stderr.write(`Mobius daemon failed: ${code}${message}
28963
30678
  `);
28964
30679
  process.exitCode = 1;
28965
30680
  }