@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/index.js CHANGED
@@ -3708,7 +3708,7 @@ var $ZodUnion = /* @__PURE__ */ $constructor("$ZodUnion", (inst, def) => {
3708
3708
  defineLazyInternal(inst, "optout", (zod) => zod.def.options.some((o) => o._zod.optout === "optional") ? "optional" : void 0);
3709
3709
  defineLazyInternal(inst, "values", (zod) => {
3710
3710
  if (zod.def.options.every((o) => o._zod.values)) {
3711
- return new Set(zod.def.options.flatMap((option) => Array.from(option._zod.values)));
3711
+ return new Set(zod.def.options.flatMap((option2) => Array.from(option2._zod.values)));
3712
3712
  }
3713
3713
  return void 0;
3714
3714
  });
@@ -3726,8 +3726,8 @@ var $ZodUnion = /* @__PURE__ */ $constructor("$ZodUnion", (inst, def) => {
3726
3726
  }
3727
3727
  let async = false;
3728
3728
  const results = [];
3729
- for (const option of def.options) {
3730
- const result = option._zod.run({
3729
+ for (const option2 of def.options) {
3730
+ const result = option2._zod.run({
3731
3731
  value: payload.value,
3732
3732
  issues: []
3733
3733
  }, ctx);
@@ -3786,8 +3786,8 @@ var $ZodXor = /* @__PURE__ */ $constructor("$ZodXor", (inst, def) => {
3786
3786
  }
3787
3787
  let async = false;
3788
3788
  const results = [];
3789
- for (const option of def.options) {
3790
- const result = option._zod.run({
3789
+ for (const option2 of def.options) {
3790
+ const result = option2._zod.run({
3791
3791
  value: payload.value,
3792
3792
  issues: []
3793
3793
  }, ctx);
@@ -3811,10 +3811,10 @@ function getDiscriminatedOption(union2, value) {
3811
3811
  if (!map2) {
3812
3812
  map2 = /* @__PURE__ */ new Map();
3813
3813
  const { options, discriminator } = internals.def;
3814
- for (const option of options) {
3815
- for (const v of option._zod.propValues?.[discriminator] ?? [])
3814
+ for (const option2 of options) {
3815
+ for (const v of option2._zod.propValues?.[discriminator] ?? [])
3816
3816
  if (!map2.has(v))
3817
- map2.set(v, option);
3817
+ map2.set(v, option2);
3818
3818
  }
3819
3819
  internals.bag.optionsMap = map2;
3820
3820
  }
@@ -3826,10 +3826,10 @@ var $ZodDiscriminatedUnion = /* @__PURE__ */ $constructor("$ZodDiscriminatedUnio
3826
3826
  const _super = inst._zod.parse;
3827
3827
  defineLazyInternal(inst, "propValues", (zod) => {
3828
3828
  const propValues = {};
3829
- for (const option of zod.def.options) {
3830
- const pv = option._zod.propValues;
3829
+ for (const option2 of zod.def.options) {
3830
+ const pv = option2._zod.propValues;
3831
3831
  if (!pv || Object.keys(pv).length === 0)
3832
- throw new Error(`Invalid discriminated union option at index "${zod.def.options.indexOf(option)}"`);
3832
+ throw new Error(`Invalid discriminated union option at index "${zod.def.options.indexOf(option2)}"`);
3833
3833
  for (const [k, v] of Object.entries(pv)) {
3834
3834
  if (!Object.prototype.hasOwnProperty.call(propValues, k)) {
3835
3835
  assignProp(propValues, k, /* @__PURE__ */ new Set());
@@ -3841,8 +3841,8 @@ var $ZodDiscriminatedUnion = /* @__PURE__ */ $constructor("$ZodDiscriminatedUnio
3841
3841
  }
3842
3842
  return propValues;
3843
3843
  });
3844
- def.options.forEach((option, i) => {
3845
- const propShape = propShapes.get(option._zod.def);
3844
+ def.options.forEach((option2, i) => {
3845
+ const propShape = propShapes.get(option2._zod.def);
3846
3846
  if (propShape && !Object.prototype.hasOwnProperty.call(propShape, def.discriminator)) {
3847
3847
  throw new Error(`Invalid discriminated union option at index "${i}"`);
3848
3848
  }
@@ -13773,8 +13773,8 @@ function generateDiscriminatedUnionCheck(doc, ctx, def, accessor) {
13773
13773
  doc.write(`let ${outputVar};`);
13774
13774
  let firstBranch = true;
13775
13775
  const claimed = /* @__PURE__ */ new Set();
13776
- for (const option of def.options) {
13777
- const values = option._zod.propValues?.[def.discriminator];
13776
+ for (const option2 of def.options) {
13777
+ const values = option2._zod.propValues?.[def.discriminator];
13778
13778
  if (!values || values.size === 0) {
13779
13779
  throw new ZodCompileUnsupportedError("discriminated union option without static discriminator values");
13780
13780
  }
@@ -13788,7 +13788,7 @@ function generateDiscriminatedUnionCheck(doc, ctx, def, accessor) {
13788
13788
  const prefix = firstBranch ? "if" : "else if";
13789
13789
  doc.write(`${prefix} (${conditions.join(" || ")}) {`);
13790
13790
  doc.indented((d) => {
13791
- const branchOutput = generateCheck(d, ctx, option, accessor);
13791
+ const branchOutput = generateCheck(d, ctx, option2, accessor);
13792
13792
  d.write(`${outputVar} = ${branchOutput};`);
13793
13793
  });
13794
13794
  doc.write(`}`);
@@ -15338,14 +15338,14 @@ function compactTypeUnion(schema) {
15338
15338
  if (!Array.isArray(options) || options.length === 0 || schema.type !== void 0)
15339
15339
  return;
15340
15340
  const types = [];
15341
- for (const option of options) {
15342
- if (!option || typeof option !== "object")
15341
+ for (const option2 of options) {
15342
+ if (!option2 || typeof option2 !== "object")
15343
15343
  return;
15344
- compactTypeUnion(option);
15345
- const keys = Object.keys(option);
15344
+ compactTypeUnion(option2);
15345
+ const keys = Object.keys(option2);
15346
15346
  if (keys.length !== 1 || keys[0] !== "type")
15347
15347
  return;
15348
- const type = option.type;
15348
+ const type = option2.type;
15349
15349
  for (const member of Array.isArray(type) ? type : [type]) {
15350
15350
  if (typeof member !== "string")
15351
15351
  return;
@@ -15635,8 +15635,8 @@ function isTransforming(_schema, _ctx) {
15635
15635
  return false;
15636
15636
  }
15637
15637
  if (def.type === "union") {
15638
- for (const option of def.options) {
15639
- if (isTransforming(option, ctx))
15638
+ for (const option2 of def.options) {
15639
+ if (isTransforming(option2, ctx))
15640
15640
  return true;
15641
15641
  }
15642
15642
  return false;
@@ -19712,6 +19712,487 @@ function encodeSessionFailedEvent(message) {
19712
19712
  return JSON.stringify(decodeSessionFailedEvent(JSON.stringify(message)));
19713
19713
  }
19714
19714
 
19715
+ // ../protocol/src/bot.ts
19716
+ var BOT_BINDING_APPROVAL_REQUEST_KIND = "bot.binding.approval.request";
19717
+ var BOT_BINDING_APPROVED_KIND = "bot.binding.approved";
19718
+ var BOT_BINDING_UNAVAILABLE_KIND = "bot.binding.unavailable";
19719
+ var BOT_SESSION_PROMPT_KIND = "bot.session.prompt";
19720
+ var IDENTIFIER_PATTERN3 = /^[a-zA-Z0-9][a-zA-Z0-9._:-]{0,127}$/;
19721
+ var DIRECTORY_IDENTIFIER_PATTERN3 = /^[a-zA-Z0-9][a-zA-Z0-9_-]{0,2047}$/;
19722
+ var TOKEN_PATTERN = /^[a-zA-Z0-9_-]{32,256}$/;
19723
+ var SHA256_PATTERN = /^[a-f0-9]{64}$/;
19724
+ var MAX_INSTRUCTIONS_LENGTH = 1e5;
19725
+ var BotDeliveryTargetReference = class {
19726
+ alias;
19727
+ deliveryTargetId;
19728
+ constructor(alias, deliveryTargetId) {
19729
+ this.alias = alias;
19730
+ this.deliveryTargetId = deliveryTargetId;
19731
+ }
19732
+ };
19733
+ var BotCompletionDeliveryPolicy = class {
19734
+ };
19735
+ var NoBotCompletionDeliveryPolicy = class extends BotCompletionDeliveryPolicy {
19736
+ kind = "none";
19737
+ };
19738
+ var RequiredBotCompletionDeliveryPolicy = class extends BotCompletionDeliveryPolicy {
19739
+ deliveryTargetId;
19740
+ kind = "required";
19741
+ messageTemplate;
19742
+ constructor(deliveryTargetId, messageTemplate) {
19743
+ super();
19744
+ this.deliveryTargetId = deliveryTargetId;
19745
+ this.messageTemplate = messageTemplate;
19746
+ }
19747
+ };
19748
+ var BotReplyRoute = class {
19749
+ };
19750
+ var OwnerBotReplyRoute = class extends BotReplyRoute {
19751
+ kind = "owner";
19752
+ };
19753
+ var BotConnectionReplyRoute = class extends BotReplyRoute {
19754
+ connectionId;
19755
+ deliveryTargetId;
19756
+ kind = "connection";
19757
+ constructor(connectionId, deliveryTargetId) {
19758
+ super();
19759
+ this.connectionId = connectionId;
19760
+ this.deliveryTargetId = deliveryTargetId;
19761
+ }
19762
+ };
19763
+ var BotExecutionBindingApprovalRequest = class {
19764
+ agentConfigRevision;
19765
+ agentRef;
19766
+ allowedDeliveryTargets;
19767
+ behaviorDigest;
19768
+ behaviorInstructions;
19769
+ behaviorRevisionId;
19770
+ bindingId;
19771
+ bindingRevision;
19772
+ botId;
19773
+ completionPolicy;
19774
+ kind = BOT_BINDING_APPROVAL_REQUEST_KIND;
19775
+ requestId;
19776
+ requiredCapabilities;
19777
+ runtimeId;
19778
+ workspaceRef;
19779
+ constructor(requestId, botId, behaviorRevisionId, bindingId, bindingRevision, runtimeId, agentRef, workspaceRef, agentConfigRevision, behaviorInstructions, behaviorDigest, requiredCapabilities, allowedDeliveryTargets, completionPolicy) {
19780
+ this.requestId = requestId;
19781
+ this.botId = botId;
19782
+ this.behaviorRevisionId = behaviorRevisionId;
19783
+ this.bindingId = bindingId;
19784
+ this.bindingRevision = bindingRevision;
19785
+ this.runtimeId = runtimeId;
19786
+ this.agentRef = agentRef;
19787
+ this.workspaceRef = workspaceRef;
19788
+ this.agentConfigRevision = agentConfigRevision;
19789
+ this.behaviorInstructions = behaviorInstructions;
19790
+ this.behaviorDigest = behaviorDigest;
19791
+ this.requiredCapabilities = Object.freeze([...requiredCapabilities]);
19792
+ this.allowedDeliveryTargets = Object.freeze(
19793
+ allowedDeliveryTargets.map(
19794
+ (target) => new BotDeliveryTargetReference(target.alias, target.deliveryTargetId)
19795
+ )
19796
+ );
19797
+ this.completionPolicy = completionPolicy;
19798
+ }
19799
+ };
19800
+ var BotExecutionBindingApprovedEvent = class {
19801
+ agentIdentityDigest;
19802
+ behaviorRevisionId;
19803
+ bindingId;
19804
+ bindingRevision;
19805
+ botId;
19806
+ kind = BOT_BINDING_APPROVED_KIND;
19807
+ localGrantId;
19808
+ requestId;
19809
+ workspaceIdentityDigest;
19810
+ constructor(requestId, botId, behaviorRevisionId, bindingId, bindingRevision, localGrantId, agentIdentityDigest, workspaceIdentityDigest) {
19811
+ this.requestId = requestId;
19812
+ this.botId = botId;
19813
+ this.behaviorRevisionId = behaviorRevisionId;
19814
+ this.bindingId = bindingId;
19815
+ this.bindingRevision = bindingRevision;
19816
+ this.localGrantId = localGrantId;
19817
+ this.agentIdentityDigest = agentIdentityDigest;
19818
+ this.workspaceIdentityDigest = workspaceIdentityDigest;
19819
+ }
19820
+ };
19821
+ var BotExecutionBindingUnavailableEvent = class {
19822
+ behaviorRevisionId;
19823
+ bindingId;
19824
+ bindingRevision;
19825
+ botId;
19826
+ code;
19827
+ kind = BOT_BINDING_UNAVAILABLE_KIND;
19828
+ message;
19829
+ requestId;
19830
+ constructor(requestId, botId, behaviorRevisionId, bindingId, bindingRevision, code, message) {
19831
+ this.requestId = requestId;
19832
+ this.botId = botId;
19833
+ this.behaviorRevisionId = behaviorRevisionId;
19834
+ this.bindingId = bindingId;
19835
+ this.bindingRevision = bindingRevision;
19836
+ this.code = code;
19837
+ this.message = message;
19838
+ }
19839
+ };
19840
+ var BotSessionPromptCommand = class {
19841
+ additionalDirectoryIds;
19842
+ agentId;
19843
+ allowedDeliveryTargets;
19844
+ behaviorDigest;
19845
+ behaviorInstructions;
19846
+ behaviorRevisionId;
19847
+ bindingId;
19848
+ bindingRevision;
19849
+ botId;
19850
+ commandId;
19851
+ conversationId;
19852
+ directoryId;
19853
+ executionCapabilityId;
19854
+ executionCapabilitySecret;
19855
+ executionDeadlineAt;
19856
+ executionId;
19857
+ images;
19858
+ kind = BOT_SESSION_PROMPT_KIND;
19859
+ localGrantId;
19860
+ prompt;
19861
+ replyRoute;
19862
+ resources;
19863
+ sessionId;
19864
+ turnId;
19865
+ constructor(sessionId, commandId, agentId, bindingId, directoryId2, additionalDirectoryIds, images, resources, prompt, executionId, executionCapabilityId, executionCapabilitySecret, executionDeadlineAt, botId, conversationId, turnId, behaviorRevisionId, bindingRevision, localGrantId, behaviorInstructions, behaviorDigest, allowedDeliveryTargets, replyRoute) {
19866
+ this.sessionId = sessionId;
19867
+ this.commandId = commandId;
19868
+ this.agentId = agentId;
19869
+ this.bindingId = bindingId;
19870
+ this.directoryId = directoryId2;
19871
+ this.additionalDirectoryIds = Object.freeze([...additionalDirectoryIds]);
19872
+ this.images = Object.freeze([...images]);
19873
+ this.resources = Object.freeze([...resources]);
19874
+ this.prompt = prompt;
19875
+ this.executionId = executionId;
19876
+ this.executionCapabilityId = executionCapabilityId;
19877
+ this.executionCapabilitySecret = executionCapabilitySecret;
19878
+ this.executionDeadlineAt = executionDeadlineAt;
19879
+ this.botId = botId;
19880
+ this.conversationId = conversationId;
19881
+ this.turnId = turnId;
19882
+ this.behaviorRevisionId = behaviorRevisionId;
19883
+ this.bindingRevision = bindingRevision;
19884
+ this.localGrantId = localGrantId;
19885
+ this.behaviorInstructions = behaviorInstructions;
19886
+ this.behaviorDigest = behaviorDigest;
19887
+ this.allowedDeliveryTargets = Object.freeze(
19888
+ allowedDeliveryTargets.map(
19889
+ (target) => new BotDeliveryTargetReference(target.alias, target.deliveryTargetId)
19890
+ )
19891
+ );
19892
+ this.replyRoute = replyRoute;
19893
+ }
19894
+ };
19895
+ function isRecord2(value) {
19896
+ return typeof value === "object" && value !== null && !Array.isArray(value);
19897
+ }
19898
+ function parseJson3(encoded) {
19899
+ let value;
19900
+ try {
19901
+ value = JSON.parse(encoded);
19902
+ } catch (cause) {
19903
+ throw new ProtocolMessageError("Message is not valid JSON", { cause });
19904
+ }
19905
+ if (!isRecord2(value)) {
19906
+ throw new ProtocolMessageError("Message must be a JSON object");
19907
+ }
19908
+ return value;
19909
+ }
19910
+ function assertExactKeys2(value, expected) {
19911
+ const keys = Object.keys(value);
19912
+ if (keys.length !== expected.length || keys.some((key) => !expected.includes(key))) {
19913
+ throw new ProtocolMessageError("Message fields do not match the Bot protocol");
19914
+ }
19915
+ }
19916
+ function readText2(value, key, maximumLength, allowEmpty) {
19917
+ const field = value[key];
19918
+ if (typeof field !== "string" || field.length > maximumLength || !allowEmpty && field.length === 0) {
19919
+ throw new ProtocolMessageError(`Invalid Bot protocol field: ${key}`);
19920
+ }
19921
+ return field;
19922
+ }
19923
+ function readIdentifier2(value, key) {
19924
+ const field = readText2(value, key, 128, false);
19925
+ if (!IDENTIFIER_PATTERN3.test(field)) {
19926
+ throw new ProtocolMessageError(`Invalid Bot identifier field: ${key}`);
19927
+ }
19928
+ return field;
19929
+ }
19930
+ function readDirectoryIdentifier2(value, key) {
19931
+ const field = readText2(value, key, 2048, false);
19932
+ if (!DIRECTORY_IDENTIFIER_PATTERN3.test(field)) {
19933
+ throw new ProtocolMessageError(`Invalid Bot directory field: ${key}`);
19934
+ }
19935
+ return field;
19936
+ }
19937
+ function readInteger(value, key) {
19938
+ const field = value[key];
19939
+ if (typeof field !== "number" || !Number.isSafeInteger(field) || field < 1) {
19940
+ throw new ProtocolMessageError(`Invalid Bot integer field: ${key}`);
19941
+ }
19942
+ return field;
19943
+ }
19944
+ function readTimestamp(value, key) {
19945
+ const field = readText2(value, key, 64, false);
19946
+ if (Number.isNaN(Date.parse(field))) {
19947
+ throw new ProtocolMessageError(`Invalid Bot timestamp field: ${key}`);
19948
+ }
19949
+ return field;
19950
+ }
19951
+ function readDigest(value, key) {
19952
+ const field = readText2(value, key, 64, false);
19953
+ if (!SHA256_PATTERN.test(field)) {
19954
+ throw new ProtocolMessageError(`Invalid Bot digest field: ${key}`);
19955
+ }
19956
+ return field;
19957
+ }
19958
+ function readToken(value, key) {
19959
+ const field = readText2(value, key, 256, false);
19960
+ if (!TOKEN_PATTERN.test(field)) {
19961
+ throw new ProtocolMessageError(`Invalid Bot token field: ${key}`);
19962
+ }
19963
+ return field;
19964
+ }
19965
+ function readIdentifiers(value, key, maximumCount) {
19966
+ const field = value[key];
19967
+ if (!Array.isArray(field) || field.length > maximumCount) {
19968
+ throw new ProtocolMessageError(`Invalid Bot identifier list: ${key}`);
19969
+ }
19970
+ const identifiers = [];
19971
+ const unique = /* @__PURE__ */ new Set();
19972
+ for (const candidate of field) {
19973
+ if (typeof candidate !== "string" || !IDENTIFIER_PATTERN3.test(candidate) || unique.has(candidate)) {
19974
+ throw new ProtocolMessageError(`Invalid Bot identifier list: ${key}`);
19975
+ }
19976
+ unique.add(candidate);
19977
+ identifiers.push(candidate);
19978
+ }
19979
+ return Object.freeze(identifiers);
19980
+ }
19981
+ function readTargets(value, key) {
19982
+ const field = value[key];
19983
+ if (!Array.isArray(field) || field.length > 64) {
19984
+ throw new ProtocolMessageError(`Invalid Bot delivery targets: ${key}`);
19985
+ }
19986
+ const targets = [];
19987
+ const identifiers = /* @__PURE__ */ new Set();
19988
+ const aliases = /* @__PURE__ */ new Set();
19989
+ for (const candidate of field) {
19990
+ if (!isRecord2(candidate)) {
19991
+ throw new ProtocolMessageError(`Invalid Bot delivery targets: ${key}`);
19992
+ }
19993
+ assertExactKeys2(candidate, ["alias", "deliveryTargetId"]);
19994
+ const alias = readIdentifier2(candidate, "alias");
19995
+ const deliveryTargetId = readIdentifier2(candidate, "deliveryTargetId");
19996
+ if (aliases.has(alias) || identifiers.has(deliveryTargetId)) {
19997
+ throw new ProtocolMessageError(`Duplicate Bot delivery target: ${key}`);
19998
+ }
19999
+ aliases.add(alias);
20000
+ identifiers.add(deliveryTargetId);
20001
+ targets.push(new BotDeliveryTargetReference(alias, deliveryTargetId));
20002
+ }
20003
+ return Object.freeze(targets);
20004
+ }
20005
+ function readCompletionPolicy(value) {
20006
+ if (!isRecord2(value)) {
20007
+ throw new ProtocolMessageError("Invalid Bot completion policy");
20008
+ }
20009
+ const kind = readText2(value, "kind", 32, false);
20010
+ if (kind === "none") {
20011
+ assertExactKeys2(value, ["kind"]);
20012
+ return new NoBotCompletionDeliveryPolicy();
20013
+ }
20014
+ if (kind === "required") {
20015
+ assertExactKeys2(value, ["deliveryTargetId", "kind", "messageTemplate"]);
20016
+ return new RequiredBotCompletionDeliveryPolicy(
20017
+ readIdentifier2(value, "deliveryTargetId"),
20018
+ readText2(value, "messageTemplate", 1e4, false)
20019
+ );
20020
+ }
20021
+ throw new ProtocolMessageError("Invalid Bot completion policy");
20022
+ }
20023
+ function readReplyRoute(value) {
20024
+ if (!isRecord2(value)) {
20025
+ throw new ProtocolMessageError("Invalid Bot reply route");
20026
+ }
20027
+ const kind = readText2(value, "kind", 32, false);
20028
+ if (kind === "owner") {
20029
+ assertExactKeys2(value, ["kind"]);
20030
+ return new OwnerBotReplyRoute();
20031
+ }
20032
+ if (kind === "connection") {
20033
+ assertExactKeys2(value, ["connectionId", "deliveryTargetId", "kind"]);
20034
+ return new BotConnectionReplyRoute(
20035
+ readIdentifier2(value, "connectionId"),
20036
+ readIdentifier2(value, "deliveryTargetId")
20037
+ );
20038
+ }
20039
+ throw new ProtocolMessageError("Invalid Bot reply route");
20040
+ }
20041
+ function decodeBotExecutionBindingApprovalRequest(encoded) {
20042
+ const value = parseJson3(encoded);
20043
+ assertExactKeys2(value, [
20044
+ "agentConfigRevision",
20045
+ "agentRef",
20046
+ "allowedDeliveryTargets",
20047
+ "behaviorDigest",
20048
+ "behaviorInstructions",
20049
+ "behaviorRevisionId",
20050
+ "bindingId",
20051
+ "bindingRevision",
20052
+ "botId",
20053
+ "completionPolicy",
20054
+ "kind",
20055
+ "requestId",
20056
+ "requiredCapabilities",
20057
+ "runtimeId",
20058
+ "workspaceRef"
20059
+ ]);
20060
+ if (value["kind"] !== BOT_BINDING_APPROVAL_REQUEST_KIND) {
20061
+ throw new ProtocolMessageError("Invalid Bot binding approval request kind");
20062
+ }
20063
+ return new BotExecutionBindingApprovalRequest(
20064
+ readIdentifier2(value, "requestId"),
20065
+ readIdentifier2(value, "botId"),
20066
+ readIdentifier2(value, "behaviorRevisionId"),
20067
+ readIdentifier2(value, "bindingId"),
20068
+ readInteger(value, "bindingRevision"),
20069
+ readIdentifier2(value, "runtimeId"),
20070
+ readIdentifier2(value, "agentRef"),
20071
+ readDirectoryIdentifier2(value, "workspaceRef"),
20072
+ readInteger(value, "agentConfigRevision"),
20073
+ readText2(value, "behaviorInstructions", MAX_INSTRUCTIONS_LENGTH, true),
20074
+ readDigest(value, "behaviorDigest"),
20075
+ readIdentifiers(value, "requiredCapabilities", 32),
20076
+ readTargets(value, "allowedDeliveryTargets"),
20077
+ readCompletionPolicy(value["completionPolicy"])
20078
+ );
20079
+ }
20080
+ function decodeBotExecutionBindingApprovedEvent(encoded) {
20081
+ const value = parseJson3(encoded);
20082
+ assertExactKeys2(value, [
20083
+ "agentIdentityDigest",
20084
+ "behaviorRevisionId",
20085
+ "bindingId",
20086
+ "bindingRevision",
20087
+ "botId",
20088
+ "kind",
20089
+ "localGrantId",
20090
+ "requestId",
20091
+ "workspaceIdentityDigest"
20092
+ ]);
20093
+ if (value["kind"] !== BOT_BINDING_APPROVED_KIND) {
20094
+ throw new ProtocolMessageError("Invalid Bot binding approval event kind");
20095
+ }
20096
+ return new BotExecutionBindingApprovedEvent(
20097
+ readIdentifier2(value, "requestId"),
20098
+ readIdentifier2(value, "botId"),
20099
+ readIdentifier2(value, "behaviorRevisionId"),
20100
+ readIdentifier2(value, "bindingId"),
20101
+ readInteger(value, "bindingRevision"),
20102
+ readIdentifier2(value, "localGrantId"),
20103
+ readDigest(value, "agentIdentityDigest"),
20104
+ readDigest(value, "workspaceIdentityDigest")
20105
+ );
20106
+ }
20107
+ function encodeBotExecutionBindingApprovedEvent(event) {
20108
+ return JSON.stringify(decodeBotExecutionBindingApprovedEvent(JSON.stringify(event)));
20109
+ }
20110
+ function decodeBotExecutionBindingUnavailableEvent(encoded) {
20111
+ const value = parseJson3(encoded);
20112
+ assertExactKeys2(value, [
20113
+ "behaviorRevisionId",
20114
+ "bindingId",
20115
+ "bindingRevision",
20116
+ "botId",
20117
+ "code",
20118
+ "kind",
20119
+ "message",
20120
+ "requestId"
20121
+ ]);
20122
+ if (value["kind"] !== BOT_BINDING_UNAVAILABLE_KIND) {
20123
+ throw new ProtocolMessageError("Invalid Bot binding unavailable event kind");
20124
+ }
20125
+ return new BotExecutionBindingUnavailableEvent(
20126
+ readIdentifier2(value, "requestId"),
20127
+ readIdentifier2(value, "botId"),
20128
+ readIdentifier2(value, "behaviorRevisionId"),
20129
+ readIdentifier2(value, "bindingId"),
20130
+ readInteger(value, "bindingRevision"),
20131
+ readIdentifier2(value, "code"),
20132
+ readText2(value, "message", 500, false)
20133
+ );
20134
+ }
20135
+ function encodeBotExecutionBindingUnavailableEvent(event) {
20136
+ return JSON.stringify(decodeBotExecutionBindingUnavailableEvent(JSON.stringify(event)));
20137
+ }
20138
+ function decodeBotSessionPromptCommand(encoded) {
20139
+ const value = parseJson3(encoded);
20140
+ assertExactKeys2(value, [
20141
+ "additionalDirectoryIds",
20142
+ "agentId",
20143
+ "allowedDeliveryTargets",
20144
+ "behaviorDigest",
20145
+ "behaviorInstructions",
20146
+ "behaviorRevisionId",
20147
+ "bindingId",
20148
+ "bindingRevision",
20149
+ "botId",
20150
+ "commandId",
20151
+ "conversationId",
20152
+ "directoryId",
20153
+ "executionCapabilityId",
20154
+ "executionCapabilitySecret",
20155
+ "executionDeadlineAt",
20156
+ "executionId",
20157
+ "images",
20158
+ "kind",
20159
+ "localGrantId",
20160
+ "prompt",
20161
+ "replyRoute",
20162
+ "resources",
20163
+ "sessionId",
20164
+ "turnId"
20165
+ ]);
20166
+ if (value["kind"] !== BOT_SESSION_PROMPT_KIND) {
20167
+ throw new ProtocolMessageError("Invalid Bot Session prompt kind");
20168
+ }
20169
+ return new BotSessionPromptCommand(
20170
+ readIdentifier2(value, "sessionId"),
20171
+ readIdentifier2(value, "commandId"),
20172
+ readIdentifier2(value, "agentId"),
20173
+ readIdentifier2(value, "bindingId"),
20174
+ readDirectoryIdentifier2(value, "directoryId"),
20175
+ readIdentifiers(value, "additionalDirectoryIds", 16),
20176
+ decodePromptImagesValue(value["images"]),
20177
+ decodePromptResourcesValue(value["resources"]),
20178
+ readText2(value, "prompt", 1e4, false),
20179
+ readIdentifier2(value, "executionId"),
20180
+ readIdentifier2(value, "executionCapabilityId"),
20181
+ readToken(value, "executionCapabilitySecret"),
20182
+ readTimestamp(value, "executionDeadlineAt"),
20183
+ readIdentifier2(value, "botId"),
20184
+ readIdentifier2(value, "conversationId"),
20185
+ readIdentifier2(value, "turnId"),
20186
+ readIdentifier2(value, "behaviorRevisionId"),
20187
+ readInteger(value, "bindingRevision"),
20188
+ readIdentifier2(value, "localGrantId"),
20189
+ readText2(value, "behaviorInstructions", MAX_INSTRUCTIONS_LENGTH, true),
20190
+ readDigest(value, "behaviorDigest"),
20191
+ readTargets(value, "allowedDeliveryTargets"),
20192
+ readReplyRoute(value["replyRoute"])
20193
+ );
20194
+ }
20195
+
19715
20196
  // ../protocol/src/mobius-api.ts
19716
20197
  var MOBIUS_API_PREFIX = "/mobius/api";
19717
20198
  var API_PREFIX_PATTERN = /^\/[a-zA-Z0-9._~-]+(?:\/[a-zA-Z0-9._~-]+)*$/;
@@ -19885,13 +20366,18 @@ var decodeNativeSessionCancel = (encoded) => decode4(nativeSessionCancelSchema,
19885
20366
  var SESSION_EVENT_KIND = "session.event";
19886
20367
  var SESSION_EVENT_ACK_KIND = "session.event.ack";
19887
20368
  var SESSION_EVENT_COMMITTED_KIND = "session.event.committed";
19888
- var IDENTIFIER_PATTERN3 = /^[a-zA-Z0-9][a-zA-Z0-9._:-]{0,127}$/;
20369
+ var SESSION_EVENT_REJECTED_KIND = "session.event.rejected";
20370
+ var SessionEventRejectionCode = {
20371
+ SessionDeleted: "session_deleted",
20372
+ SessionNotFound: "session_not_found"
20373
+ };
20374
+ var IDENTIFIER_PATTERN4 = /^[a-zA-Z0-9][a-zA-Z0-9._:-]{0,127}$/;
19889
20375
  var CURSOR_PATTERN = /^[A-Za-z0-9_-]{1,512}$/;
19890
20376
  var MAX_RECORDED_EVENT_LENGTH = 8 * 1024 * 1024;
19891
20377
  var DECIMAL_SEQUENCE_PATTERN = /^(?:0|[1-9][0-9]*)$/;
19892
20378
  var eventSourceSchema = external_exports.discriminatedUnion("kind", [
19893
20379
  external_exports.strictObject({
19894
- attemptId: external_exports.string().min(1).max(128).regex(IDENTIFIER_PATTERN3),
20380
+ attemptId: external_exports.string().min(1).max(128).regex(IDENTIFIER_PATTERN4),
19895
20381
  kind: external_exports.literal("attempt"),
19896
20382
  sourceSeq: external_exports.string().min(1).max(40).regex(DECIMAL_SEQUENCE_PATTERN)
19897
20383
  }).readonly(),
@@ -19901,29 +20387,35 @@ var eventSourceSchema = external_exports.discriminatedUnion("kind", [
19901
20387
  }).readonly()
19902
20388
  ]);
19903
20389
  var eventEnvelopeSchema = external_exports.strictObject({
19904
- eventId: external_exports.string().min(1).max(128).regex(IDENTIFIER_PATTERN3),
20390
+ eventId: external_exports.string().min(1).max(128).regex(IDENTIFIER_PATTERN4),
19905
20391
  kind: external_exports.literal(SESSION_EVENT_KIND),
19906
20392
  payload: external_exports.string().min(2).max(MAX_RECORDED_EVENT_LENGTH),
19907
- sessionId: external_exports.string().min(1).max(128).regex(IDENTIFIER_PATTERN3),
20393
+ sessionId: external_exports.string().min(1).max(128).regex(IDENTIFIER_PATTERN4),
19908
20394
  source: eventSourceSchema
19909
20395
  }).readonly();
19910
20396
  var committedEventSchema = external_exports.strictObject({
19911
20397
  cursor: external_exports.string().min(1).max(512).regex(CURSOR_PATTERN),
19912
- eventId: external_exports.string().min(1).max(128).regex(IDENTIFIER_PATTERN3),
20398
+ eventId: external_exports.string().min(1).max(128).regex(IDENTIFIER_PATTERN4),
19913
20399
  kind: external_exports.literal(SESSION_EVENT_COMMITTED_KIND),
19914
20400
  payload: external_exports.string().min(2).max(MAX_RECORDED_EVENT_LENGTH),
19915
20401
  recordedAt: external_exports.string().datetime({ offset: true }),
19916
20402
  sequence: external_exports.string().min(1).max(40).regex(DECIMAL_SEQUENCE_PATTERN),
19917
- sessionId: external_exports.string().min(1).max(128).regex(IDENTIFIER_PATTERN3),
20403
+ sessionId: external_exports.string().min(1).max(128).regex(IDENTIFIER_PATTERN4),
19918
20404
  source: eventSourceSchema
19919
20405
  }).readonly();
19920
20406
  var eventAcknowledgementSchema = external_exports.strictObject({
19921
20407
  cursor: external_exports.string().min(1).max(512).regex(CURSOR_PATTERN),
19922
20408
  duplicate: external_exports.boolean(),
19923
- eventId: external_exports.string().min(1).max(128).regex(IDENTIFIER_PATTERN3),
20409
+ eventId: external_exports.string().min(1).max(128).regex(IDENTIFIER_PATTERN4),
19924
20410
  kind: external_exports.literal(SESSION_EVENT_ACK_KIND),
19925
20411
  sequence: external_exports.string().min(1).max(40).regex(DECIMAL_SEQUENCE_PATTERN),
19926
- sessionId: external_exports.string().min(1).max(128).regex(IDENTIFIER_PATTERN3)
20412
+ sessionId: external_exports.string().min(1).max(128).regex(IDENTIFIER_PATTERN4)
20413
+ }).readonly();
20414
+ var eventRejectionSchema = external_exports.strictObject({
20415
+ code: external_exports.enum(SessionEventRejectionCode),
20416
+ eventId: external_exports.string().min(1).max(128).regex(IDENTIFIER_PATTERN4),
20417
+ kind: external_exports.literal(SESSION_EVENT_REJECTED_KIND),
20418
+ sessionId: external_exports.string().min(1).max(128).regex(IDENTIFIER_PATTERN4)
19927
20419
  }).readonly();
19928
20420
  function decode5(encoded, schema) {
19929
20421
  let value;
@@ -19951,6 +20443,7 @@ var encode4 = (message, schema) => {
19951
20443
  };
19952
20444
  var encodeSessionEventEnvelope = (message) => encode4(message, eventEnvelopeSchema);
19953
20445
  var decodeSessionEventAcknowledgement = (encoded) => decode5(encoded, eventAcknowledgementSchema);
20446
+ var decodeSessionEventRejection = (encoded) => decode5(encoded, eventRejectionSchema);
19954
20447
 
19955
20448
  // src/agent-catalog/local-agent.ts
19956
20449
  import { realpathSync, statSync } from "node:fs";
@@ -20599,7 +21092,7 @@ import {
20599
21092
 
20600
21093
  // src/acp/activity.ts
20601
21094
  var TRUNCATION_MARKER = "\n\u2026 output truncated by Mobius";
20602
- function isRecord2(value) {
21095
+ function isRecord3(value) {
20603
21096
  return typeof value === "object" && value !== null && !Array.isArray(value);
20604
21097
  }
20605
21098
  var AcpActivity = class _AcpActivity {
@@ -20866,7 +21359,7 @@ function contentPhase(content) {
20866
21359
  return "";
20867
21360
  }
20868
21361
  const codex = metadata["codex"];
20869
- if (!isRecord2(codex)) {
21362
+ if (!isRecord3(codex)) {
20870
21363
  return "";
20871
21364
  }
20872
21365
  const phase = codex["phase"];
@@ -21104,7 +21597,7 @@ var SessionConfigProtocolError = class extends Error {
21104
21597
  this.name = "SessionConfigProtocolError";
21105
21598
  }
21106
21599
  };
21107
- function isRecord3(value) {
21600
+ function isRecord4(value) {
21108
21601
  return typeof value === "object" && value !== null && !Array.isArray(value);
21109
21602
  }
21110
21603
  function readString2(value, fallback = "") {
@@ -21116,13 +21609,13 @@ function truncate2(value, maximum) {
21116
21609
  function readBoolean(value, fallback = false) {
21117
21610
  return typeof value === "boolean" ? value : fallback;
21118
21611
  }
21119
- function normalizeConfigValue(option, groupId = "", groupName = "") {
21612
+ function normalizeConfigValue(option2, groupId = "", groupName = "") {
21120
21613
  return {
21121
- description: truncate2(readString2(option["description"]), 500),
21614
+ description: truncate2(readString2(option2["description"]), 500),
21122
21615
  groupId: truncate2(groupId, 128),
21123
21616
  groupName: truncate2(groupName, 255),
21124
- name: truncate2(readString2(option["name"], readString2(option["value"])), 255),
21125
- value: truncate2(readString2(option["value"]), 500)
21617
+ name: truncate2(readString2(option2["name"], readString2(option2["value"])), 255),
21618
+ value: truncate2(readString2(option2["value"]), 500)
21126
21619
  };
21127
21620
  }
21128
21621
  function normalizeConfigValues(value) {
@@ -21131,7 +21624,7 @@ function normalizeConfigValues(value) {
21131
21624
  }
21132
21625
  const normalized = [];
21133
21626
  for (const entry of value) {
21134
- if (!isRecord3(entry)) {
21627
+ if (!isRecord4(entry)) {
21135
21628
  continue;
21136
21629
  }
21137
21630
  const groupedOptions = entry["options"];
@@ -21139,7 +21632,7 @@ function normalizeConfigValues(value) {
21139
21632
  const groupId = readString2(entry["group"]);
21140
21633
  const groupName = readString2(entry["name"]);
21141
21634
  for (const groupedOption of groupedOptions) {
21142
- if (isRecord3(groupedOption)) {
21635
+ if (isRecord4(groupedOption)) {
21143
21636
  normalized.push(normalizeConfigValue(groupedOption, groupId, groupName));
21144
21637
  }
21145
21638
  }
@@ -21152,21 +21645,21 @@ function normalizeConfigValues(value) {
21152
21645
  function normalizeConfigOptions(value, modes) {
21153
21646
  const normalized = [];
21154
21647
  if (Array.isArray(value)) {
21155
- for (const option of value) {
21156
- if (!isRecord3(option)) {
21648
+ for (const option2 of value) {
21649
+ if (!isRecord4(option2)) {
21157
21650
  continue;
21158
21651
  }
21159
- const id = truncate2(readString2(option["id"]), 128);
21160
- const name = truncate2(readString2(option["name"], id), 255);
21652
+ const id = truncate2(readString2(option2["id"]), 128);
21653
+ const name = truncate2(readString2(option2["name"], id), 255);
21161
21654
  if (id.length === 0 || name.length === 0) {
21162
21655
  continue;
21163
21656
  }
21164
- if (option["type"] === "boolean") {
21657
+ if (option2["type"] === "boolean") {
21165
21658
  normalized.push({
21166
- booleanValue: readBoolean(option["currentValue"]),
21167
- category: truncate2(readString2(option["category"]), 128),
21659
+ booleanValue: readBoolean(option2["currentValue"]),
21660
+ category: truncate2(readString2(option2["category"]), 128),
21168
21661
  currentValue: "",
21169
- description: truncate2(readString2(option["description"]), 500),
21662
+ description: truncate2(readString2(option2["description"]), 500),
21170
21663
  id,
21171
21664
  name,
21172
21665
  type: "boolean",
@@ -21174,15 +21667,15 @@ function normalizeConfigOptions(value, modes) {
21174
21667
  });
21175
21668
  continue;
21176
21669
  }
21177
- if (option["type"] === "select") {
21178
- const values = normalizeConfigValues(option["options"]);
21179
- const currentValue = truncate2(readString2(option["currentValue"]), 500);
21670
+ if (option2["type"] === "select") {
21671
+ const values = normalizeConfigValues(option2["options"]);
21672
+ const currentValue = truncate2(readString2(option2["currentValue"]), 500);
21180
21673
  if (currentValue.length > 0 && values.some((entry) => entry.value === currentValue)) {
21181
21674
  normalized.push({
21182
21675
  booleanValue: false,
21183
- category: truncate2(readString2(option["category"]), 128),
21676
+ category: truncate2(readString2(option2["category"]), 128),
21184
21677
  currentValue,
21185
- description: truncate2(readString2(option["description"]), 500),
21678
+ description: truncate2(readString2(option2["description"]), 500),
21186
21679
  id,
21187
21680
  name,
21188
21681
  type: "select",
@@ -21192,12 +21685,12 @@ function normalizeConfigOptions(value, modes) {
21192
21685
  }
21193
21686
  }
21194
21687
  }
21195
- if (isRecord3(modes)) {
21688
+ if (isRecord4(modes)) {
21196
21689
  const values = [];
21197
21690
  const availableModes = modes["availableModes"];
21198
21691
  if (Array.isArray(availableModes)) {
21199
21692
  for (const mode of availableModes) {
21200
- if (!isRecord3(mode)) {
21693
+ if (!isRecord4(mode)) {
21201
21694
  continue;
21202
21695
  }
21203
21696
  const id = truncate2(readString2(mode["id"]), 500);
@@ -21230,7 +21723,7 @@ function normalizeConfigOptions(value, modes) {
21230
21723
  return normalized.slice(0, 100);
21231
21724
  }
21232
21725
  function ensureReasoningEffortOption(current) {
21233
- if (current.some((option) => option.category === "thought_level")) {
21726
+ if (current.some((option2) => option2.category === "thought_level")) {
21234
21727
  return current;
21235
21728
  }
21236
21729
  const unavailable = {
@@ -21251,7 +21744,7 @@ function ensureReasoningEffortOption(current) {
21251
21744
  }
21252
21745
  ]
21253
21746
  };
21254
- const modelIndex = current.findIndex((option) => option.category === "model");
21747
+ const modelIndex = current.findIndex((option2) => option2.category === "model");
21255
21748
  if (current.length < MAXIMUM_CONFIG_OPTIONS) {
21256
21749
  if (modelIndex < 0) {
21257
21750
  return [...current, unavailable];
@@ -21275,20 +21768,20 @@ function ensureReasoningEffortOption(current) {
21275
21768
  return [...current.slice(0, MAXIMUM_CONFIG_OPTIONS - 2), model, unavailable];
21276
21769
  }
21277
21770
  function normalizeStandardLifecycle(response) {
21278
- const lifecycle = isRecord3(response) ? response : {};
21771
+ const lifecycle = isRecord4(response) ? response : {};
21279
21772
  return ensureReasoningEffortOption(normalizeConfigOptions(lifecycle["configOptions"], lifecycle["modes"]));
21280
21773
  }
21281
21774
  function replaceStandardConfigOptions(current, value) {
21282
21775
  const next = normalizeConfigOptions(value, void 0);
21283
- const withMode = next.some((option) => option.category === "mode") ? next : [...current.filter((option) => option.category === "mode"), ...next].slice(0, 100);
21776
+ const withMode = next.some((option2) => option2.category === "mode") ? next : [...current.filter((option2) => option2.category === "mode"), ...next].slice(0, 100);
21284
21777
  return ensureReasoningEffortOption(withMode);
21285
21778
  }
21286
21779
  function updateCurrentValue(current, configId, value) {
21287
- return current.map((option) => option.id === configId ? { ...option, currentValue: value } : option);
21780
+ return current.map((option2) => option2.id === configId ? { ...option2, currentValue: value } : option2);
21288
21781
  }
21289
21782
  var StandardSessionConfigProtocol = class {
21290
21783
  configure = async (current, change, nativeSessionId, transport) => {
21291
- const existing = current.find((option) => option.id === change.configId);
21784
+ const existing = current.find((option2) => option2.id === change.configId);
21292
21785
  if (existing === void 0) {
21293
21786
  return current;
21294
21787
  }
@@ -21317,7 +21810,7 @@ var StandardSessionConfigProtocol = class {
21317
21810
  "ACP agent exited while changing session configuration",
21318
21811
  change.signal
21319
21812
  );
21320
- if (!isRecord3(response) || !Array.isArray(response["configOptions"])) {
21813
+ if (!isRecord4(response) || !Array.isArray(response["configOptions"])) {
21321
21814
  throw new SessionConfigProtocolError("The Agent returned an invalid session configuration response");
21322
21815
  }
21323
21816
  return replaceStandardConfigOptions(current, response["configOptions"]);
@@ -21331,31 +21824,31 @@ var standardSessionConfigProtocol = new StandardSessionConfigProtocol();
21331
21824
  var LEGACY_MODEL_CONFIG_ID = "grok_build_legacy_model";
21332
21825
  var LEGACY_REASONING_EFFORT_CONFIG_ID = "grok_build_legacy_reasoning_effort";
21333
21826
  function legacyOptions(response) {
21334
- if (!isRecord3(response)) {
21827
+ if (!isRecord4(response)) {
21335
21828
  return [];
21336
21829
  }
21337
21830
  const metadata = response["_meta"];
21338
- if (!isRecord3(metadata)) {
21831
+ if (!isRecord4(metadata)) {
21339
21832
  return [];
21340
21833
  }
21341
21834
  const sessionConfig = metadata["x.ai/sessionConfig"];
21342
- if (!isRecord3(sessionConfig) || !Array.isArray(sessionConfig["options"])) {
21835
+ if (!isRecord4(sessionConfig) || !Array.isArray(sessionConfig["options"])) {
21343
21836
  return [];
21344
21837
  }
21345
- return sessionConfig["options"].slice(0, 500).filter(isRecord3);
21838
+ return sessionConfig["options"].slice(0, 500).filter(isRecord4);
21346
21839
  }
21347
- function legacyValue(option) {
21348
- const value = readString2(option["id"]);
21840
+ function legacyValue(option2) {
21841
+ const value = readString2(option2["id"]);
21349
21842
  return {
21350
- description: readString2(option["description"]).slice(0, 500),
21843
+ description: readString2(option2["description"]).slice(0, 500),
21351
21844
  groupId: "",
21352
21845
  groupName: "",
21353
- name: readString2(option["label"], value).slice(0, 255),
21846
+ name: readString2(option2["label"], value).slice(0, 255),
21354
21847
  value: value.slice(0, 500)
21355
21848
  };
21356
21849
  }
21357
21850
  function modelsRecord(response) {
21358
- if (!isRecord3(response) || !isRecord3(response["models"])) {
21851
+ if (!isRecord4(response) || !isRecord4(response["models"])) {
21359
21852
  return {};
21360
21853
  }
21361
21854
  return response["models"];
@@ -21364,9 +21857,9 @@ function legacyModelOptions(response) {
21364
21857
  const options = legacyOptions(response);
21365
21858
  const models = modelsRecord(response);
21366
21859
  const values = [];
21367
- for (const option of options) {
21368
- if (option["category"] === "model") {
21369
- const value = legacyValue(option);
21860
+ for (const option2 of options) {
21861
+ if (option2["category"] === "model") {
21862
+ const value = legacyValue(option2);
21370
21863
  if (value.value.length > 0 && !values.some((existing) => existing.value === value.value)) {
21371
21864
  values.push(value);
21372
21865
  }
@@ -21374,7 +21867,7 @@ function legacyModelOptions(response) {
21374
21867
  }
21375
21868
  if (values.length === 0 && Array.isArray(models["availableModels"])) {
21376
21869
  for (const model of models["availableModels"]) {
21377
- if (!isRecord3(model)) {
21870
+ if (!isRecord4(model)) {
21378
21871
  continue;
21379
21872
  }
21380
21873
  const value = readString2(model["modelId"]).slice(0, 500);
@@ -21392,7 +21885,7 @@ function legacyModelOptions(response) {
21392
21885
  }
21393
21886
  }
21394
21887
  }
21395
- const selected = options.find((option) => option["category"] === "model" && option["selected"] === true);
21888
+ const selected = options.find((option2) => option2["category"] === "model" && option2["selected"] === true);
21396
21889
  const currentValue = readString2(
21397
21890
  models["currentModelId"],
21398
21891
  selected === void 0 ? "" : readString2(selected["id"])
@@ -21415,11 +21908,11 @@ function legacyModelOptions(response) {
21415
21908
  function legacyReasoningEffortOptions(response) {
21416
21909
  const options = legacyOptions(response);
21417
21910
  const values = [];
21418
- for (const option of options) {
21419
- if (option["category"] !== "mode") {
21911
+ for (const option2 of options) {
21912
+ if (option2["category"] !== "mode") {
21420
21913
  continue;
21421
21914
  }
21422
- const value = legacyValue(option);
21915
+ const value = legacyValue(option2);
21423
21916
  if (value.value.length > 0 && !values.some((existing) => existing.value === value.value)) {
21424
21917
  values.push(value);
21425
21918
  }
@@ -21427,7 +21920,7 @@ function legacyReasoningEffortOptions(response) {
21427
21920
  if (values.length === 0) {
21428
21921
  return [];
21429
21922
  }
21430
- const selected = options.find((option) => option["category"] === "mode" && option["selected"] === true);
21923
+ const selected = options.find((option2) => option2["category"] === "mode" && option2["selected"] === true);
21431
21924
  if (selected === void 0) {
21432
21925
  values.unshift({
21433
21926
  description: "Use the selected model's default reasoning effort",
@@ -21454,41 +21947,41 @@ function legacyReasoningEffortOptions(response) {
21454
21947
  return [result];
21455
21948
  }
21456
21949
  function normalizeGrokLifecycle(response) {
21457
- const lifecycle = isRecord3(response) ? response : {};
21950
+ const lifecycle = isRecord4(response) ? response : {};
21458
21951
  const standard = normalizeConfigOptions(lifecycle["configOptions"], lifecycle["modes"]);
21459
21952
  const normalized = [...standard];
21460
- if (!normalized.some((option) => option.category === "model")) {
21953
+ if (!normalized.some((option2) => option2.category === "model")) {
21461
21954
  normalized.push(...legacyModelOptions(response));
21462
21955
  }
21463
- if (!normalized.some((option) => option.category === "thought_level")) {
21956
+ if (!normalized.some((option2) => option2.category === "thought_level")) {
21464
21957
  const efforts = legacyReasoningEffortOptions(response);
21465
21958
  if (efforts.length > 0) {
21466
- const modelIndex = normalized.findIndex((option) => option.category === "model");
21959
+ const modelIndex = normalized.findIndex((option2) => option2.category === "model");
21467
21960
  normalized.splice(modelIndex < 0 ? normalized.length : modelIndex + 1, 0, ...efforts);
21468
21961
  }
21469
21962
  }
21470
21963
  return ensureReasoningEffortOption(normalized.slice(0, 100));
21471
21964
  }
21472
21965
  function updateCurrentValue2(current, category, value) {
21473
- return current.map((option) => option.category === category ? { ...option, currentValue: value } : option);
21966
+ return current.map((option2) => option2.category === category ? { ...option2, currentValue: value } : option2);
21474
21967
  }
21475
21968
  function validateGrokResponse(response, modelId) {
21476
- if (!isRecord3(response) || !isRecord3(response["_meta"])) {
21969
+ if (!isRecord4(response) || !isRecord4(response["_meta"])) {
21477
21970
  throw new SessionConfigProtocolError("Grok Build returned an invalid session configuration response");
21478
21971
  }
21479
21972
  const model = response["_meta"]["model"];
21480
- const appliedModel = isRecord3(model) ? model["Ok"] : model;
21973
+ const appliedModel = isRecord4(model) ? model["Ok"] : model;
21481
21974
  if (appliedModel !== modelId) {
21482
21975
  throw new SessionConfigProtocolError("Grok Build returned an invalid session configuration response");
21483
21976
  }
21484
21977
  }
21485
21978
  var GrokBuildSessionConfigProtocol = class {
21486
21979
  configure = async (current, change, nativeSessionId, transport) => {
21487
- const existing = current.find((option) => option.id === change.configId);
21980
+ const existing = current.find((option2) => option2.id === change.configId);
21488
21981
  if (existing === void 0 || existing.id !== LEGACY_MODEL_CONFIG_ID && existing.id !== LEGACY_REASONING_EFFORT_CONFIG_ID) {
21489
21982
  return await standardSessionConfigProtocol.configure(current, change, nativeSessionId, transport);
21490
21983
  }
21491
- const model = current.find((option) => option.category === "model");
21984
+ const model = current.find((option2) => option2.category === "model");
21492
21985
  if (model === void 0) {
21493
21986
  return current;
21494
21987
  }
@@ -21514,10 +22007,10 @@ var GrokBuildSessionConfigProtocol = class {
21514
22007
  validateGrokResponse(response, modelId);
21515
22008
  const updated = updateCurrentValue2(current, existing.category, change.value);
21516
22009
  return existing.category === "thought_level" ? updated.map(
21517
- (option) => option.category === "thought_level" ? {
21518
- ...option,
21519
- values: option.values.filter((value) => value.value !== AGENT_DEFAULT_REASONING_EFFORT)
21520
- } : option
22010
+ (option2) => option2.category === "thought_level" ? {
22011
+ ...option2,
22012
+ values: option2.values.filter((value) => value.value !== AGENT_DEFAULT_REASONING_EFFORT)
22013
+ } : option2
21521
22014
  ) : updated;
21522
22015
  };
21523
22016
  normalizeLifecycle = (response) => normalizeGrokLifecycle(response);
@@ -21920,7 +22413,7 @@ function createWritableAcpStream(output2) {
21920
22413
  function truncate3(value, maximumLength) {
21921
22414
  return value.length <= maximumLength ? value : `${value.slice(0, Math.max(0, maximumLength - 1))}\u2026`;
21922
22415
  }
21923
- function isRecord4(value) {
22416
+ function isRecord5(value) {
21924
22417
  return typeof value === "object" && value !== null && !Array.isArray(value);
21925
22418
  }
21926
22419
  function readString4(value, fallback = "") {
@@ -21948,12 +22441,12 @@ function normalizeElicitationOptions(schema) {
21948
22441
  const normalized = [];
21949
22442
  const oneOf = schema["oneOf"];
21950
22443
  if (Array.isArray(oneOf)) {
21951
- for (const option of oneOf) {
21952
- if (isRecord4(option) && typeof option["const"] === "string") {
22444
+ for (const option2 of oneOf) {
22445
+ if (isRecord5(option2) && typeof option2["const"] === "string") {
21953
22446
  normalized.push({
21954
- description: truncate3(readString4(option["description"]), 500),
21955
- label: truncate3(readString4(option["title"], option["const"]), 255),
21956
- value: truncate3(option["const"], 500)
22447
+ description: truncate3(readString4(option2["description"]), 500),
22448
+ label: truncate3(readString4(option2["title"], option2["const"]), 255),
22449
+ value: truncate3(option2["const"], 500)
21957
22450
  });
21958
22451
  }
21959
22452
  }
@@ -21969,7 +22462,7 @@ function normalizeElicitationOptions(schema) {
21969
22462
  return normalized.slice(0, 200);
21970
22463
  }
21971
22464
  const items = schema["items"];
21972
- if (!isRecord4(items)) {
22465
+ if (!isRecord5(items)) {
21973
22466
  return normalized;
21974
22467
  }
21975
22468
  const anyOf = items["anyOf"];
@@ -21982,7 +22475,7 @@ function numericString(value) {
21982
22475
  return typeof value === "number" && Number.isFinite(value) ? value.toString() : "";
21983
22476
  }
21984
22477
  function normalizeElicitationFields(requestedSchema) {
21985
- if (!isRecord4(requestedSchema) || !isRecord4(requestedSchema["properties"])) {
22478
+ if (!isRecord5(requestedSchema) || !isRecord5(requestedSchema["properties"])) {
21986
22479
  return [];
21987
22480
  }
21988
22481
  const properties = requestedSchema["properties"];
@@ -21992,7 +22485,7 @@ function normalizeElicitationFields(requestedSchema) {
21992
22485
  );
21993
22486
  const normalized = [];
21994
22487
  for (const [name, property] of Object.entries(properties)) {
21995
- if (!isRecord4(property)) {
22488
+ if (!isRecord5(property)) {
21996
22489
  continue;
21997
22490
  }
21998
22491
  const type = elicitationFieldType(property["type"]);
@@ -22083,7 +22576,7 @@ function validateElicitationContent(encoded, requestedSchema) {
22083
22576
  "invalid_elicitation_response"
22084
22577
  );
22085
22578
  }
22086
- if (!isRecord4(decoded) || !isRecord4(requestedSchema) || !isRecord4(requestedSchema["properties"])) {
22579
+ if (!isRecord5(decoded) || !isRecord5(requestedSchema) || !isRecord5(requestedSchema["properties"])) {
22087
22580
  throw new AcpExecutionError(
22088
22581
  "Elicitation response does not match the requested form",
22089
22582
  {},
@@ -22103,7 +22596,7 @@ function validateElicitationContent(encoded, requestedSchema) {
22103
22596
  const validated = {};
22104
22597
  for (const [name, value] of Object.entries(decoded)) {
22105
22598
  const property = properties[name];
22106
- if (!isRecord4(property)) {
22599
+ if (!isRecord5(property)) {
22107
22600
  throw new AcpExecutionError(
22108
22601
  `Elicitation field ${name} was not requested`,
22109
22602
  {},
@@ -22140,7 +22633,7 @@ function validateElicitationContent(encoded, requestedSchema) {
22140
22633
  );
22141
22634
  }
22142
22635
  const allowed = normalizeElicitationOptions(property);
22143
- if (allowed.length > 0 && value.some((entry) => !allowed.some((option) => option.value === entry))) {
22636
+ if (allowed.length > 0 && value.some((entry) => !allowed.some((option2) => option2.value === entry))) {
22144
22637
  throw new AcpExecutionError(
22145
22638
  `Elicitation field ${name} contains an invalid selection`,
22146
22639
  {},
@@ -22637,7 +23130,7 @@ var AcpProcessSession = class _AcpProcessSession {
22637
23130
  };
22638
23131
  nativeSessionId = () => this.#nativeSessionId;
22639
23132
  configure = async (options) => {
22640
- const existing = this.#configOptions.find((option) => option.id === options.configId);
23133
+ const existing = this.#configOptions.find((option2) => option2.id === options.configId);
22641
23134
  if (existing === void 0 || existing.type !== options.valueType) {
22642
23135
  throw new AcpExecutionError(
22643
23136
  "The requested ACP configuration option is unavailable",
@@ -22887,10 +23380,10 @@ var AcpProcessSession = class _AcpProcessSession {
22887
23380
  onPermission = async (request, signal) => {
22888
23381
  this.assertNativeSession(request.sessionId);
22889
23382
  const interactionId = `permission-${crypto.randomUUID()}`;
22890
- const options = request.options.slice(0, 20).map((option) => ({
22891
- kind: option.kind,
22892
- name: truncate3(option.name, 255),
22893
- optionId: truncate3(option.optionId, 255)
23383
+ const options = request.options.slice(0, 20).map((option2) => ({
23384
+ kind: option2.kind,
23385
+ name: truncate3(option2.name, 255),
23386
+ optionId: truncate3(option2.optionId, 255)
22894
23387
  }));
22895
23388
  if (options.length === 0) {
22896
23389
  throw new AcpExecutionError(
@@ -22899,7 +23392,7 @@ var AcpProcessSession = class _AcpProcessSession {
22899
23392
  "invalid_agent_permission_request"
22900
23393
  );
22901
23394
  }
22902
- const pending = new PendingPermission(interactionId, new Set(options.map((option) => option.optionId)));
23395
+ const pending = new PendingPermission(interactionId, new Set(options.map((option2) => option2.optionId)));
22903
23396
  this.#pendingPermissions.set(interactionId, pending);
22904
23397
  const abort = () => {
22905
23398
  void this.cancelPermission(interactionId);
@@ -23109,7 +23602,7 @@ var AcpProcessSession = class _AcpProcessSession {
23109
23602
  }
23110
23603
  if (update.sessionUpdate === "current_mode_update") {
23111
23604
  this.#configOptions = this.#configOptions.map(
23112
- (option) => option.category === "mode" ? { ...option, currentValue: update.currentModeId } : option
23605
+ (option2) => option2.category === "mode" ? { ...option2, currentValue: update.currentModeId } : option2
23113
23606
  );
23114
23607
  this.#configRevision += 1;
23115
23608
  await this.emitConfigUpdate();
@@ -23681,71 +24174,905 @@ async function runAcpPrompt(options) {
23681
24174
  } finally {
23682
24175
  await sessions.close();
23683
24176
  }
23684
- }
23685
-
23686
- // src/audit/audit-store.ts
23687
- import { mkdirSync as mkdirSync2 } from "node:fs";
23688
- import { dirname as dirname2 } from "node:path";
23689
- import { DatabaseSync as DatabaseSync2 } from "node:sqlite";
23690
- var AuditStore = class {
23691
- database;
23692
- constructor(path2) {
23693
- mkdirSync2(dirname2(path2), { recursive: true });
23694
- this.database = new DatabaseSync2(path2);
23695
- this.database.exec(`
23696
- CREATE TABLE IF NOT EXISTS audit_events (
23697
- id INTEGER PRIMARY KEY AUTOINCREMENT,
23698
- recorded_at TEXT NOT NULL,
23699
- event TEXT NOT NULL,
23700
- command_id TEXT NOT NULL,
23701
- session_id TEXT NOT NULL,
23702
- details_json TEXT NOT NULL DEFAULT '{}'
23703
- ) STRICT
23704
- `);
23705
- const columns = this.database.prepare("PRAGMA table_info(audit_events)").all();
23706
- if (!columns.some((column) => Reflect.get(column, "name") === "details_json")) {
23707
- this.database.exec("ALTER TABLE audit_events ADD COLUMN details_json TEXT NOT NULL DEFAULT '{}'");
23708
- }
24177
+ }
24178
+
24179
+ // src/audit/audit-store.ts
24180
+ import { mkdirSync as mkdirSync2 } from "node:fs";
24181
+ import { dirname as dirname2 } from "node:path";
24182
+ import { DatabaseSync as DatabaseSync2 } from "node:sqlite";
24183
+ var AuditStore = class {
24184
+ database;
24185
+ constructor(path2) {
24186
+ mkdirSync2(dirname2(path2), { recursive: true });
24187
+ this.database = new DatabaseSync2(path2);
24188
+ this.database.exec(`
24189
+ CREATE TABLE IF NOT EXISTS audit_events (
24190
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
24191
+ recorded_at TEXT NOT NULL,
24192
+ event TEXT NOT NULL,
24193
+ command_id TEXT NOT NULL,
24194
+ session_id TEXT NOT NULL,
24195
+ details_json TEXT NOT NULL DEFAULT '{}'
24196
+ ) STRICT
24197
+ `);
24198
+ const columns = this.database.prepare("PRAGMA table_info(audit_events)").all();
24199
+ if (!columns.some((column) => Reflect.get(column, "name") === "details_json")) {
24200
+ this.database.exec("ALTER TABLE audit_events ADD COLUMN details_json TEXT NOT NULL DEFAULT '{}'");
24201
+ }
24202
+ }
24203
+ record(record2) {
24204
+ this.database.prepare(
24205
+ `
24206
+ INSERT INTO audit_events (
24207
+ recorded_at,
24208
+ event,
24209
+ command_id,
24210
+ session_id,
24211
+ details_json
24212
+ ) VALUES (?, ?, ?, ?, ?)
24213
+ `
24214
+ ).run(
24215
+ (/* @__PURE__ */ new Date()).toISOString(),
24216
+ record2.event,
24217
+ record2.commandId,
24218
+ record2.sessionId,
24219
+ JSON.stringify(record2.details ?? {})
24220
+ );
24221
+ }
24222
+ close() {
24223
+ this.database.close();
24224
+ }
24225
+ };
24226
+
24227
+ // src/authorization/local-authorization-error.ts
24228
+ var LocalAuthorizationError = class extends Error {
24229
+ code = "local_authorization_failed";
24230
+ constructor(message, options = {}) {
24231
+ super(message, options);
24232
+ this.name = "LocalAuthorizationError";
24233
+ }
24234
+ };
24235
+
24236
+ // src/bots/bot-execution-context.ts
24237
+ import { randomBytes } from "node:crypto";
24238
+
24239
+ // src/bots/local-bot-grant-store.ts
24240
+ import { createHash, randomUUID } from "node:crypto";
24241
+ import { stat as stat2 } from "node:fs/promises";
24242
+ import { DatabaseSync as DatabaseSync3 } from "node:sqlite";
24243
+ var LOCAL_BOT_GRANT_LIFETIME_MILLISECONDS = 90 * 24 * 60 * 60 * 1e3;
24244
+ var LocalBotAuthorizationError = class extends Error {
24245
+ code;
24246
+ constructor(code, message, options = {}) {
24247
+ super(message, options);
24248
+ this.code = code;
24249
+ this.name = "LocalBotAuthorizationError";
24250
+ }
24251
+ };
24252
+ var LocalBotGrant = class {
24253
+ agent;
24254
+ agentIdentityDigest;
24255
+ allowedDeliveryTargetIds;
24256
+ behaviorDigest;
24257
+ behaviorRevisionId;
24258
+ bindingId;
24259
+ bindingRevision;
24260
+ botId;
24261
+ expiresAt;
24262
+ localGrantId;
24263
+ revocationEpoch;
24264
+ workspaceIdentityDigest;
24265
+ workspacePath;
24266
+ constructor(localGrantId, botId, behaviorRevisionId, behaviorDigest, bindingId, bindingRevision, agent, agentIdentityDigest, workspacePath, workspaceIdentityDigest, allowedDeliveryTargetIds, expiresAt, revocationEpoch) {
24267
+ this.localGrantId = localGrantId;
24268
+ this.botId = botId;
24269
+ this.behaviorRevisionId = behaviorRevisionId;
24270
+ this.behaviorDigest = behaviorDigest;
24271
+ this.bindingId = bindingId;
24272
+ this.bindingRevision = bindingRevision;
24273
+ this.agent = agent;
24274
+ this.agentIdentityDigest = agentIdentityDigest;
24275
+ this.workspacePath = workspacePath;
24276
+ this.workspaceIdentityDigest = workspaceIdentityDigest;
24277
+ this.allowedDeliveryTargetIds = Object.freeze([...allowedDeliveryTargetIds]);
24278
+ this.expiresAt = expiresAt;
24279
+ this.revocationEpoch = revocationEpoch;
24280
+ }
24281
+ };
24282
+ function digest(value) {
24283
+ return createHash("sha256").update(value, "utf8").digest("hex");
24284
+ }
24285
+ function agentDigest(agent) {
24286
+ return digest(
24287
+ JSON.stringify({
24288
+ adapter: agent.adapterIdentity,
24289
+ agent: agent.agentIdentity,
24290
+ agentVersion: agent.agentVersion,
24291
+ arguments: agent.arguments,
24292
+ id: agent.id
24293
+ })
24294
+ );
24295
+ }
24296
+ async function workspaceDigest(path2) {
24297
+ const metadata = await stat2(path2);
24298
+ if (!metadata.isDirectory()) {
24299
+ throw new LocalBotAuthorizationError("binding_incompatible", "The Bot workspace is not a directory");
24300
+ }
24301
+ return digest(
24302
+ JSON.stringify({
24303
+ changedAtMilliseconds: metadata.ctimeMs,
24304
+ device: metadata.dev,
24305
+ inode: metadata.ino,
24306
+ path: path2
24307
+ })
24308
+ );
24309
+ }
24310
+ function exactTargets(left, right) {
24311
+ if (left.length !== right.length) {
24312
+ return false;
24313
+ }
24314
+ const expected = [...left].sort();
24315
+ const actual = [...right].sort();
24316
+ return expected.every((target, index) => target === actual[index]);
24317
+ }
24318
+ function rowString(row, key) {
24319
+ const value = Reflect.get(row, key);
24320
+ if (typeof value !== "string") {
24321
+ throw new LocalBotAuthorizationError("local_grant_invalid", "The local Bot grant is invalid");
24322
+ }
24323
+ return value;
24324
+ }
24325
+ function rowInteger(row, key) {
24326
+ const value = Reflect.get(row, key);
24327
+ if (typeof value !== "number" || !Number.isSafeInteger(value)) {
24328
+ throw new LocalBotAuthorizationError("local_grant_invalid", "The local Bot grant is invalid");
24329
+ }
24330
+ return value;
24331
+ }
24332
+ function parseTargets(encoded) {
24333
+ let value;
24334
+ try {
24335
+ value = JSON.parse(encoded);
24336
+ } catch (cause) {
24337
+ throw new LocalBotAuthorizationError("local_grant_invalid", "The local Bot grant is invalid", { cause });
24338
+ }
24339
+ if (!Array.isArray(value) || value.some((target) => typeof target !== "string")) {
24340
+ throw new LocalBotAuthorizationError("local_grant_invalid", "The local Bot grant is invalid");
24341
+ }
24342
+ return value.filter((target) => typeof target === "string");
24343
+ }
24344
+ var LocalBotGrantStore = class {
24345
+ #database;
24346
+ constructor(path2) {
24347
+ this.#database = new DatabaseSync3(path2);
24348
+ this.#database.exec(`
24349
+ CREATE TABLE IF NOT EXISTS local_bot_grants (
24350
+ local_grant_id TEXT PRIMARY KEY,
24351
+ bot_id TEXT NOT NULL,
24352
+ behavior_revision_id TEXT NOT NULL,
24353
+ behavior_digest TEXT NOT NULL,
24354
+ binding_id TEXT NOT NULL UNIQUE,
24355
+ binding_revision INTEGER NOT NULL,
24356
+ agent_ref TEXT NOT NULL,
24357
+ agent_identity_digest TEXT NOT NULL,
24358
+ workspace_ref TEXT NOT NULL,
24359
+ workspace_path TEXT NOT NULL,
24360
+ workspace_identity_digest TEXT NOT NULL,
24361
+ allowed_delivery_target_ids_json TEXT NOT NULL,
24362
+ unattended_policy_json TEXT NOT NULL,
24363
+ created_at INTEGER NOT NULL,
24364
+ expires_at INTEGER NOT NULL,
24365
+ revocation_epoch INTEGER NOT NULL DEFAULT 0,
24366
+ revoked_at INTEGER
24367
+ ) STRICT;
24368
+ CREATE TABLE IF NOT EXISTS local_bot_binding_resolutions (
24369
+ request_id TEXT PRIMARY KEY,
24370
+ binding_id TEXT NOT NULL,
24371
+ local_grant_id TEXT NOT NULL,
24372
+ resolved_at INTEGER NOT NULL,
24373
+ result TEXT NOT NULL CHECK (result IN ('approved', 'unavailable')),
24374
+ error_code TEXT,
24375
+ error_message TEXT
24376
+ ) STRICT;
24377
+ `);
24378
+ }
24379
+ approve = async (request, catalog, directories, bindingAuthorityId, now, signal) => {
24380
+ signal.throwIfAborted();
24381
+ const existing = this.#database.prepare(
24382
+ `SELECT grants.* FROM local_bot_binding_resolutions AS resolutions
24383
+ INNER JOIN local_bot_grants AS grants
24384
+ ON grants.local_grant_id = resolutions.local_grant_id
24385
+ WHERE resolutions.request_id = ? AND resolutions.binding_id = ?
24386
+ AND resolutions.result = 'approved'`
24387
+ ).get(request.requestId, request.bindingId);
24388
+ if (existing !== void 0) {
24389
+ return new BotExecutionBindingApprovedEvent(
24390
+ request.requestId,
24391
+ request.botId,
24392
+ request.behaviorRevisionId,
24393
+ request.bindingId,
24394
+ request.bindingRevision,
24395
+ rowString(existing, "local_grant_id"),
24396
+ rowString(existing, "agent_identity_digest"),
24397
+ rowString(existing, "workspace_identity_digest")
24398
+ );
24399
+ }
24400
+ const resolved = await this.resolveProposal(request, catalog, directories, bindingAuthorityId, signal);
24401
+ const localGrantId = `lbg_${randomUUID()}`;
24402
+ const expiresAt = now + LOCAL_BOT_GRANT_LIFETIME_MILLISECONDS;
24403
+ this.#database.exec("BEGIN IMMEDIATE");
24404
+ try {
24405
+ this.#database.prepare(
24406
+ `INSERT INTO local_bot_grants (
24407
+ local_grant_id, bot_id, behavior_revision_id, behavior_digest,
24408
+ binding_id, binding_revision, agent_ref,
24409
+ agent_identity_digest, workspace_ref, workspace_path,
24410
+ workspace_identity_digest, allowed_delivery_target_ids_json,
24411
+ unattended_policy_json, created_at, expires_at
24412
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`
24413
+ ).run(
24414
+ localGrantId,
24415
+ request.botId,
24416
+ request.behaviorRevisionId,
24417
+ request.behaviorDigest,
24418
+ request.bindingId,
24419
+ request.bindingRevision,
24420
+ request.agentRef,
24421
+ resolved.agentIdentityDigest,
24422
+ request.workspaceRef,
24423
+ resolved.workspacePath,
24424
+ resolved.workspaceIdentityDigest,
24425
+ JSON.stringify(request.allowedDeliveryTargets.map((target) => target.deliveryTargetId)),
24426
+ JSON.stringify({ localSideEffects: "owner-approval-required" }),
24427
+ now,
24428
+ expiresAt
24429
+ );
24430
+ this.#database.prepare(
24431
+ `INSERT INTO local_bot_binding_resolutions (
24432
+ request_id, binding_id, local_grant_id, resolved_at, result
24433
+ ) VALUES (?, ?, ?, ?, 'approved')`
24434
+ ).run(request.requestId, request.bindingId, localGrantId, now);
24435
+ this.#database.exec("COMMIT");
24436
+ } catch (cause) {
24437
+ this.#database.exec("ROLLBACK");
24438
+ throw cause;
24439
+ }
24440
+ signal.throwIfAborted();
24441
+ return new BotExecutionBindingApprovedEvent(
24442
+ request.requestId,
24443
+ request.botId,
24444
+ request.behaviorRevisionId,
24445
+ request.bindingId,
24446
+ request.bindingRevision,
24447
+ localGrantId,
24448
+ resolved.agentIdentityDigest,
24449
+ resolved.workspaceIdentityDigest
24450
+ );
24451
+ };
24452
+ resolveExecution = async (command, catalog, directories, bindingAuthorityId, now, signal) => {
24453
+ signal.throwIfAborted();
24454
+ const row = this.#database.prepare(
24455
+ `SELECT * FROM local_bot_grants
24456
+ WHERE local_grant_id = ? AND bot_id = ?
24457
+ AND behavior_revision_id = ? AND behavior_digest = ?
24458
+ AND binding_id = ? AND binding_revision = ?
24459
+ AND agent_ref = ? AND workspace_ref = ?
24460
+ AND revoked_at IS NULL AND expires_at > ?`
24461
+ ).get(
24462
+ command.localGrantId,
24463
+ command.botId,
24464
+ command.behaviorRevisionId,
24465
+ command.behaviorDigest,
24466
+ command.bindingId,
24467
+ command.bindingRevision,
24468
+ command.agentId,
24469
+ command.directoryId,
24470
+ now
24471
+ );
24472
+ if (row === void 0) {
24473
+ throw new LocalBotAuthorizationError(
24474
+ "binding_not_approved",
24475
+ "The Bot execution binding is not locally approved"
24476
+ );
24477
+ }
24478
+ const approvedTargets = parseTargets(rowString(row, "allowed_delivery_target_ids_json"));
24479
+ const requestedTargets = command.allowedDeliveryTargets.map((target) => target.deliveryTargetId);
24480
+ if (!exactTargets(approvedTargets, requestedTargets)) {
24481
+ throw new LocalBotAuthorizationError(
24482
+ "binding_not_approved",
24483
+ "The Bot execution target policy changed after local approval"
24484
+ );
24485
+ }
24486
+ const agent = catalog.find(command.agentId);
24487
+ const [adapterUnchanged, agentUnchanged] = await Promise.all([
24488
+ revalidateExecutable(agent.adapterIdentity),
24489
+ revalidateExecutable(agent.agentIdentity)
24490
+ ]);
24491
+ signal.throwIfAborted();
24492
+ const workspacePath = await directories.resolve(bindingAuthorityId, command.directoryId, signal);
24493
+ const currentAgentDigest = agentDigest(agent);
24494
+ const currentWorkspaceDigest = await workspaceDigest(workspacePath);
24495
+ signal.throwIfAborted();
24496
+ if (!adapterUnchanged || !agentUnchanged || currentAgentDigest !== rowString(row, "agent_identity_digest") || currentWorkspaceDigest !== rowString(row, "workspace_identity_digest") || workspacePath !== rowString(row, "workspace_path")) {
24497
+ this.revoke(rowString(row, "local_grant_id"), now);
24498
+ throw new LocalBotAuthorizationError(
24499
+ "binding_not_approved",
24500
+ "The Bot execution target changed and requires local approval"
24501
+ );
24502
+ }
24503
+ if (command.behaviorInstructions.length > 0 && !agent.capabilities.embeddedContextPrompt) {
24504
+ throw new LocalBotAuthorizationError(
24505
+ "binding_incompatible",
24506
+ "The local Agent cannot apply the approved Bot behavior"
24507
+ );
24508
+ }
24509
+ return new LocalBotGrant(
24510
+ rowString(row, "local_grant_id"),
24511
+ command.botId,
24512
+ command.behaviorRevisionId,
24513
+ command.behaviorDigest,
24514
+ command.bindingId,
24515
+ command.bindingRevision,
24516
+ agent,
24517
+ currentAgentDigest,
24518
+ workspacePath,
24519
+ currentWorkspaceDigest,
24520
+ approvedTargets,
24521
+ rowInteger(row, "expires_at"),
24522
+ rowInteger(row, "revocation_epoch")
24523
+ );
24524
+ };
24525
+ recordUnavailable = (request, code, message, now) => {
24526
+ this.#database.prepare(
24527
+ `INSERT OR IGNORE INTO local_bot_binding_resolutions (
24528
+ request_id, binding_id, local_grant_id, resolved_at,
24529
+ result, error_code, error_message
24530
+ ) VALUES (?, ?, '', ?, 'unavailable', ?, ?)`
24531
+ ).run(request.requestId, request.bindingId, now, code, message);
24532
+ };
24533
+ close = () => {
24534
+ this.#database.close();
24535
+ };
24536
+ resolveProposal = async (request, catalog, directories, bindingAuthorityId, signal) => {
24537
+ const agent = catalog.find(request.agentRef);
24538
+ if (request.requiredCapabilities.includes("embedded-context") && !agent.capabilities.embeddedContextPrompt) {
24539
+ throw new LocalBotAuthorizationError(
24540
+ "binding_incompatible",
24541
+ "The local Agent cannot apply embedded Bot context"
24542
+ );
24543
+ }
24544
+ if (request.requiredCapabilities.some((capability) => capability !== "embedded-context")) {
24545
+ throw new LocalBotAuthorizationError(
24546
+ "binding_incompatible",
24547
+ "The Bot requires an unsupported local Agent capability"
24548
+ );
24549
+ }
24550
+ const [adapterUnchanged, agentUnchanged] = await Promise.all([
24551
+ revalidateExecutable(agent.adapterIdentity),
24552
+ revalidateExecutable(agent.agentIdentity)
24553
+ ]);
24554
+ signal.throwIfAborted();
24555
+ if (!adapterUnchanged || !agentUnchanged) {
24556
+ throw new LocalBotAuthorizationError(
24557
+ "binding_incompatible",
24558
+ "The local Agent executable changed before approval"
24559
+ );
24560
+ }
24561
+ const workspacePath = await directories.resolve(bindingAuthorityId, request.workspaceRef, signal);
24562
+ return {
24563
+ agent,
24564
+ agentIdentityDigest: agentDigest(agent),
24565
+ workspaceIdentityDigest: await workspaceDigest(workspacePath),
24566
+ workspacePath
24567
+ };
24568
+ };
24569
+ revoke = (localGrantId, now) => {
24570
+ this.#database.prepare(
24571
+ `UPDATE local_bot_grants
24572
+ SET revoked_at = COALESCE(revoked_at, ?), revocation_epoch = revocation_epoch + 1
24573
+ WHERE local_grant_id = ? AND revoked_at IS NULL`
24574
+ ).run(now, localGrantId);
24575
+ };
24576
+ };
24577
+
24578
+ // src/bots/bot-execution-context.ts
24579
+ var ActiveBotExecutionContext = class {
24580
+ command;
24581
+ contextHandle;
24582
+ constructor(contextHandle, command) {
24583
+ this.contextHandle = contextHandle;
24584
+ this.command = command;
24585
+ }
24586
+ resolveTarget = (target) => {
24587
+ if (target === "current") {
24588
+ if (!(this.command.replyRoute instanceof BotConnectionReplyRoute)) {
24589
+ throw new LocalBotAuthorizationError(
24590
+ "delivery_target_not_allowed",
24591
+ "This Bot conversation has no external reply target"
24592
+ );
24593
+ }
24594
+ return this.command.replyRoute.deliveryTargetId;
24595
+ }
24596
+ const resolved = this.command.allowedDeliveryTargets.find((candidate) => candidate.alias === target);
24597
+ if (resolved === void 0) {
24598
+ throw new LocalBotAuthorizationError(
24599
+ "delivery_target_not_allowed",
24600
+ "The named Bot delivery target is not approved"
24601
+ );
24602
+ }
24603
+ return resolved.deliveryTargetId;
24604
+ };
24605
+ };
24606
+ var BotExecutionContextLease = class {
24607
+ context;
24608
+ #release;
24609
+ #released = false;
24610
+ constructor(context, release) {
24611
+ this.context = context;
24612
+ this.#release = release;
24613
+ }
24614
+ release = () => {
24615
+ if (this.#released) {
24616
+ return;
24617
+ }
24618
+ this.#released = true;
24619
+ this.#release();
24620
+ };
24621
+ };
24622
+ var BotExecutionContextRegistry = class {
24623
+ #activeByHandle = /* @__PURE__ */ new Map();
24624
+ #handlesBySession = /* @__PURE__ */ new Map();
24625
+ #inactiveHandles = /* @__PURE__ */ new Set();
24626
+ #now;
24627
+ constructor(now = Date.now) {
24628
+ this.#now = now;
24629
+ }
24630
+ activate = (command) => {
24631
+ let handle = this.#handlesBySession.get(command.sessionId);
24632
+ if (handle === void 0) {
24633
+ handle = `ctx_${randomBytes(32).toString("base64url")}`;
24634
+ this.#handlesBySession.set(command.sessionId, handle);
24635
+ }
24636
+ if (this.#activeByHandle.has(handle)) {
24637
+ throw new LocalBotAuthorizationError("session_busy", "The Bot execution context is already active");
24638
+ }
24639
+ const context = new ActiveBotExecutionContext(handle, command);
24640
+ this.#inactiveHandles.delete(handle);
24641
+ this.#activeByHandle.set(handle, context);
24642
+ return new BotExecutionContextLease(context, () => {
24643
+ if (this.#activeByHandle.get(handle) === context) {
24644
+ this.#activeByHandle.delete(handle);
24645
+ this.#inactiveHandles.add(handle);
24646
+ }
24647
+ });
24648
+ };
24649
+ read = (handle) => {
24650
+ const context = this.#activeByHandle.get(handle);
24651
+ if (context === void 0) {
24652
+ if (this.#inactiveHandles.has(handle)) {
24653
+ throw new LocalBotAuthorizationError(
24654
+ "execution_capability_expired",
24655
+ "The Bot execution capability has expired"
24656
+ );
24657
+ }
24658
+ throw new LocalBotAuthorizationError(
24659
+ "execution_context_required",
24660
+ "An active Bot execution context is required"
24661
+ );
24662
+ }
24663
+ if (Date.parse(context.command.executionDeadlineAt) <= this.#now()) {
24664
+ throw new LocalBotAuthorizationError(
24665
+ "execution_capability_expired",
24666
+ "The Bot execution capability has expired"
24667
+ );
24668
+ }
24669
+ return context;
24670
+ };
24671
+ };
24672
+
24673
+ // src/bots/bot-message-command.ts
24674
+ import { randomUUID as randomUUID2 } from "node:crypto";
24675
+ import { createConnection } from "node:net";
24676
+ var BOT_IPC_RESPONSE_LIMIT = 64 * 1024;
24677
+ var BOT_IPC_TIMEOUT_MILLISECONDS = 2e4;
24678
+ var BotMessageCommandError = class extends Error {
24679
+ code;
24680
+ constructor(code, message, options = {}) {
24681
+ super(message, options);
24682
+ this.code = code;
24683
+ this.name = "BotMessageCommandError";
24684
+ }
24685
+ };
24686
+ function isRecord6(value) {
24687
+ return typeof value === "object" && value !== null && !Array.isArray(value);
24688
+ }
24689
+ function requiredEnvironment(environment, name) {
24690
+ const value = environment[name]?.trim();
24691
+ if (value === void 0 || value.length === 0) {
24692
+ throw new BotMessageCommandError(
24693
+ "execution_context_required",
24694
+ "This command is available only inside an active Mobius Bot execution"
24695
+ );
24696
+ }
24697
+ return value;
24698
+ }
24699
+ function option(arguments_, name) {
24700
+ const index = arguments_.indexOf(name);
24701
+ if (index < 0 || index + 1 >= arguments_.length || arguments_[index + 1]?.startsWith("--") === true) {
24702
+ throw new BotMessageCommandError(
24703
+ "invalid_request",
24704
+ "Usage: mobius bot message send --target <current|alias> --text <message>"
24705
+ );
24706
+ }
24707
+ const value = arguments_[index + 1];
24708
+ if (value === void 0) {
24709
+ throw new BotMessageCommandError("invalid_request", "The Bot message option is missing");
24710
+ }
24711
+ return value;
24712
+ }
24713
+ function validateArguments(arguments_) {
24714
+ if (arguments_.length !== 4) {
24715
+ throw new BotMessageCommandError(
24716
+ "invalid_request",
24717
+ "Usage: mobius bot message send --target <current|alias> --text <message>"
24718
+ );
24719
+ }
24720
+ const names = [arguments_[0], arguments_[2]];
24721
+ if (!names.includes("--target") || !names.includes("--text") || names[0] === names[1]) {
24722
+ throw new BotMessageCommandError(
24723
+ "invalid_request",
24724
+ "Usage: mobius bot message send --target <current|alias> --text <message>"
24725
+ );
24726
+ }
24727
+ }
24728
+ function decodeResponse(encoded) {
24729
+ let value;
24730
+ try {
24731
+ value = JSON.parse(encoded);
24732
+ } catch (cause) {
24733
+ throw new BotMessageCommandError("bot_service_unavailable", "The local Bot service returned invalid data", {
24734
+ cause
24735
+ });
24736
+ }
24737
+ if (!isRecord6(value) || typeof value["ok"] !== "boolean") {
24738
+ throw new BotMessageCommandError("bot_service_unavailable", "The local Bot service returned invalid data");
24739
+ }
24740
+ if (value["ok"] === true && typeof value["outboundMessageId"] === "string") {
24741
+ return value["outboundMessageId"];
24742
+ }
24743
+ const error61 = value["error"];
24744
+ if (value["ok"] === false && isRecord6(error61) && typeof error61["code"] === "string" && typeof error61["message"] === "string") {
24745
+ throw new BotMessageCommandError(error61["code"], error61["message"]);
24746
+ }
24747
+ throw new BotMessageCommandError("bot_service_unavailable", "The local Bot service returned invalid data");
24748
+ }
24749
+ async function requestLocalBotService(socketPath, payload, signal) {
24750
+ signal.throwIfAborted();
24751
+ return await new Promise((resolve5, reject) => {
24752
+ const socket = createConnection(socketPath);
24753
+ const chunks = [];
24754
+ let length = 0;
24755
+ let finished = false;
24756
+ const finish = () => {
24757
+ socket.removeAllListeners();
24758
+ socket.destroy();
24759
+ };
24760
+ const fail = (error61) => {
24761
+ if (finished) {
24762
+ return;
24763
+ }
24764
+ finished = true;
24765
+ finish();
24766
+ if (error61 instanceof BotMessageCommandError) {
24767
+ reject(error61);
24768
+ return;
24769
+ }
24770
+ reject(
24771
+ new BotMessageCommandError(
24772
+ "execution_context_required",
24773
+ "The active Mobius Bot execution is unavailable",
24774
+ { cause: error61 }
24775
+ )
24776
+ );
24777
+ };
24778
+ const abort = () => fail(signal.reason);
24779
+ socket.setTimeout(BOT_IPC_TIMEOUT_MILLISECONDS, () => {
24780
+ fail(new BotMessageCommandError("bot_service_unavailable", "The local Bot service timed out"));
24781
+ });
24782
+ socket.once("error", fail);
24783
+ socket.once("connect", () => socket.end(`${payload}
24784
+ `));
24785
+ socket.on("data", (chunk) => {
24786
+ length += chunk.byteLength;
24787
+ if (length > BOT_IPC_RESPONSE_LIMIT) {
24788
+ fail(new BotMessageCommandError("bot_service_unavailable", "The local Bot response is too large"));
24789
+ return;
24790
+ }
24791
+ chunks.push(chunk);
24792
+ });
24793
+ socket.once("end", () => {
24794
+ if (finished) {
24795
+ return;
24796
+ }
24797
+ finished = true;
24798
+ signal.removeEventListener("abort", abort);
24799
+ try {
24800
+ resolve5(decodeResponse(Buffer.concat(chunks).toString("utf8")));
24801
+ } catch (error61) {
24802
+ reject(error61);
24803
+ } finally {
24804
+ finish();
24805
+ }
24806
+ });
24807
+ signal.addEventListener("abort", abort, { once: true });
24808
+ });
24809
+ }
24810
+ async function executeBotMessageCommand(arguments_, environment, signal) {
24811
+ validateArguments(arguments_);
24812
+ const contextHandle = requiredEnvironment(environment, "MOBIUS_BOT_CONTEXT");
24813
+ const socketPath = requiredEnvironment(environment, "MOBIUS_BOT_SOCKET");
24814
+ const target = option(arguments_, "--target");
24815
+ const text = option(arguments_, "--text");
24816
+ if (!/^[a-zA-Z0-9][a-zA-Z0-9._:-]{0,127}$/.test(target) || text.trim().length === 0 || text.length > 1e4) {
24817
+ throw new BotMessageCommandError("invalid_request", "The Bot outbound message is invalid");
24818
+ }
24819
+ return await requestLocalBotService(
24820
+ socketPath,
24821
+ JSON.stringify({
24822
+ contextHandle,
24823
+ idempotencyKey: `cli_${randomUUID2()}`,
24824
+ target,
24825
+ text
24826
+ }),
24827
+ signal
24828
+ );
24829
+ }
24830
+
24831
+ // src/bots/bot-outbound-ipc.ts
24832
+ import { chmod, mkdir, unlink } from "node:fs/promises";
24833
+ import { createServer } from "node:net";
24834
+ import { dirname as dirname3, isAbsolute } from "node:path";
24835
+ import { fetch } from "undici";
24836
+ var BOT_IPC_REQUEST_LIMIT = 32 * 1024;
24837
+ var BOT_IPC_TIMEOUT_MILLISECONDS2 = 2e4;
24838
+ var BOT_RELAY_TIMEOUT_MILLISECONDS = 2e4;
24839
+ var IDENTIFIER_PATTERN5 = /^[a-zA-Z0-9][a-zA-Z0-9._:-]{0,127}$/;
24840
+ var WINDOWS_NAMED_PIPE_PREFIX = "\\\\.\\pipe\\";
24841
+ var BotOutboundIpcRequest = class {
24842
+ contextHandle;
24843
+ idempotencyKey;
24844
+ target;
24845
+ text;
24846
+ constructor(contextHandle, idempotencyKey, target, text) {
24847
+ this.contextHandle = contextHandle;
24848
+ this.idempotencyKey = idempotencyKey;
24849
+ this.target = target;
24850
+ this.text = text;
24851
+ }
24852
+ };
24853
+ function isRecord7(value) {
24854
+ return typeof value === "object" && value !== null && !Array.isArray(value);
24855
+ }
24856
+ function decodeRequest(encoded) {
24857
+ let value;
24858
+ try {
24859
+ value = JSON.parse(encoded);
24860
+ } catch (cause) {
24861
+ throw new LocalBotAuthorizationError("invalid_request", "The local Bot request is invalid", { cause });
24862
+ }
24863
+ if (!isRecord7(value)) {
24864
+ throw new LocalBotAuthorizationError("invalid_request", "The local Bot request is invalid");
24865
+ }
24866
+ const keys = Object.keys(value);
24867
+ if (keys.length !== 4 || !keys.every((key) => ["contextHandle", "idempotencyKey", "target", "text"].includes(key))) {
24868
+ throw new LocalBotAuthorizationError("invalid_request", "The local Bot request fields are invalid");
24869
+ }
24870
+ const contextHandle = value["contextHandle"];
24871
+ const idempotencyKey = value["idempotencyKey"];
24872
+ const target = value["target"];
24873
+ const text = value["text"];
24874
+ if (typeof contextHandle !== "string" || !/^ctx_[a-zA-Z0-9_-]{43}$/.test(contextHandle) || typeof idempotencyKey !== "string" || !IDENTIFIER_PATTERN5.test(idempotencyKey) || typeof target !== "string" || !IDENTIFIER_PATTERN5.test(target) || typeof text !== "string" || text.trim().length === 0 || text.length > 1e4) {
24875
+ throw new LocalBotAuthorizationError("invalid_request", "The local Bot request is invalid");
24876
+ }
24877
+ return new BotOutboundIpcRequest(contextHandle, idempotencyKey, target, text);
24878
+ }
24879
+ function relayEndpoint(relayUrl, context, target) {
24880
+ const endpoint = new URL(relayUrl);
24881
+ if (endpoint.protocol !== "ws:" && endpoint.protocol !== "wss:") {
24882
+ throw new LocalBotAuthorizationError("bot_service_unavailable", "The Mobius Relay URL is invalid");
24883
+ }
24884
+ endpoint.protocol = endpoint.protocol === "wss:" ? "https:" : "http:";
24885
+ endpoint.search = "";
24886
+ const execution = encodeURIComponent(context.command.executionId);
24887
+ if (target === "current") {
24888
+ context.resolveTarget(target);
24889
+ endpoint.pathname = `${MOBIUS_API_PREFIX}/v1/bot-executions/${execution}/reply-messages`;
24890
+ return endpoint;
24891
+ }
24892
+ const deliveryTargetId = context.resolveTarget(target);
24893
+ endpoint.pathname = `${MOBIUS_API_PREFIX}/v1/bot-executions/${execution}/delivery-targets/${encodeURIComponent(deliveryTargetId)}/messages`;
24894
+ return endpoint;
24895
+ }
24896
+ function daemonToken(relayUrl) {
24897
+ const token = relayUrl.searchParams.get("token") ?? "";
24898
+ if (!/^[a-zA-Z0-9_-]{32,256}$/.test(token)) {
24899
+ throw new LocalBotAuthorizationError("bot_service_unavailable", "The Runtime credential is unavailable");
24900
+ }
24901
+ return token;
24902
+ }
24903
+ async function decodeRelayResponse(response) {
24904
+ const encoded = await response.text();
24905
+ let value;
24906
+ try {
24907
+ value = JSON.parse(encoded);
24908
+ } catch (cause) {
24909
+ throw new LocalBotAuthorizationError("bot_service_unavailable", "The Mobius Relay returned invalid data", {
24910
+ cause
24911
+ });
24912
+ }
24913
+ if (response.status === 202 && isRecord7(value) && typeof value["outboundMessageId"] === "string") {
24914
+ return value["outboundMessageId"];
23709
24915
  }
23710
- record(record2) {
23711
- this.database.prepare(
23712
- `
23713
- INSERT INTO audit_events (
23714
- recorded_at,
23715
- event,
23716
- command_id,
23717
- session_id,
23718
- details_json
23719
- ) VALUES (?, ?, ?, ?, ?)
23720
- `
23721
- ).run(
23722
- (/* @__PURE__ */ new Date()).toISOString(),
23723
- record2.event,
23724
- record2.commandId,
23725
- record2.sessionId,
23726
- JSON.stringify(record2.details ?? {})
23727
- );
24916
+ if (isRecord7(value) && isRecord7(value["error"])) {
24917
+ const error61 = value["error"];
24918
+ if (typeof error61["code"] === "string" && typeof error61["message"] === "string") {
24919
+ throw new LocalBotAuthorizationError(error61["code"], error61["message"]);
24920
+ }
23728
24921
  }
23729
- close() {
23730
- this.database.close();
24922
+ throw new LocalBotAuthorizationError("bot_service_unavailable", "The Mobius Relay rejected the Bot action");
24923
+ }
24924
+ var BotOutboundIpcServer = class {
24925
+ #registry;
24926
+ #relayUrl;
24927
+ #server;
24928
+ #socketPath;
24929
+ #usesFilesystemSocket;
24930
+ constructor(socketPath, relayUrl, registry2) {
24931
+ const usesFilesystemSocket = !socketPath.startsWith(WINDOWS_NAMED_PIPE_PREFIX);
24932
+ if (usesFilesystemSocket && !isAbsolute(socketPath)) {
24933
+ throw new Error("The Bot IPC path must be absolute");
24934
+ }
24935
+ this.#registry = registry2;
24936
+ this.#relayUrl = new URL(relayUrl);
24937
+ this.#server = createServer({ allowHalfOpen: true }, (socket) => this.accept(socket));
24938
+ this.#socketPath = socketPath;
24939
+ this.#usesFilesystemSocket = usesFilesystemSocket;
23731
24940
  }
23732
- };
23733
-
23734
- // src/authorization/local-authorization-error.ts
23735
- var LocalAuthorizationError = class extends Error {
23736
- code = "local_authorization_failed";
23737
- constructor(message, options = {}) {
23738
- super(message, options);
23739
- this.name = "LocalAuthorizationError";
24941
+ get socketPath() {
24942
+ return this.#socketPath;
23740
24943
  }
24944
+ listen = async (signal) => {
24945
+ signal.throwIfAborted();
24946
+ if (this.#usesFilesystemSocket) {
24947
+ await mkdir(dirname3(this.#socketPath), { mode: 448, recursive: true });
24948
+ await unlink(this.#socketPath).catch((error61) => {
24949
+ if (!isRecord7(error61) || error61["code"] !== "ENOENT") {
24950
+ throw error61;
24951
+ }
24952
+ });
24953
+ }
24954
+ await new Promise((resolve5, reject) => {
24955
+ const fail = (error61) => reject(error61);
24956
+ this.#server.once("error", fail);
24957
+ this.#server.listen(this.#socketPath, () => {
24958
+ this.#server.removeListener("error", fail);
24959
+ resolve5();
24960
+ });
24961
+ });
24962
+ if (this.#usesFilesystemSocket) {
24963
+ await chmod(this.#socketPath, 384);
24964
+ }
24965
+ signal.addEventListener("abort", this.abort, { once: true });
24966
+ if (signal.aborted) {
24967
+ this.abort();
24968
+ }
24969
+ };
24970
+ close = async () => {
24971
+ if (this.#server.listening) {
24972
+ await new Promise((resolve5, reject) => {
24973
+ this.#server.close((error61) => {
24974
+ if (error61 === void 0) {
24975
+ resolve5();
24976
+ return;
24977
+ }
24978
+ reject(error61);
24979
+ });
24980
+ });
24981
+ }
24982
+ if (this.#usesFilesystemSocket) {
24983
+ await unlink(this.#socketPath).catch((error61) => {
24984
+ if (!isRecord7(error61) || error61["code"] !== "ENOENT") {
24985
+ throw error61;
24986
+ }
24987
+ });
24988
+ }
24989
+ };
24990
+ #abort = () => {
24991
+ this.#server.close();
24992
+ };
24993
+ abort = () => this.#abort();
24994
+ accept = (socket) => {
24995
+ const chunks = [];
24996
+ let length = 0;
24997
+ let rejected = false;
24998
+ const controller = new AbortController();
24999
+ socket.setTimeout(BOT_IPC_TIMEOUT_MILLISECONDS2, () => {
25000
+ controller.abort(new Error("Bot IPC request timed out"));
25001
+ socket.destroy();
25002
+ });
25003
+ socket.on("data", (chunk) => {
25004
+ length += chunk.byteLength;
25005
+ if (length > BOT_IPC_REQUEST_LIMIT) {
25006
+ rejected = true;
25007
+ controller.abort(new Error("Bot IPC request is too large"));
25008
+ socket.end(
25009
+ JSON.stringify({
25010
+ error: { code: "invalid_request", message: "The local Bot request is too large" },
25011
+ ok: false
25012
+ })
25013
+ );
25014
+ return;
25015
+ }
25016
+ chunks.push(chunk);
25017
+ });
25018
+ socket.once("error", () => controller.abort());
25019
+ socket.once("close", () => controller.abort());
25020
+ socket.once("end", () => {
25021
+ if (rejected) {
25022
+ return;
25023
+ }
25024
+ void this.handle(Buffer.concat(chunks).toString("utf8").trim(), controller.signal).then(
25025
+ (outboundMessageId) => {
25026
+ if (!socket.destroyed) {
25027
+ socket.end(JSON.stringify({ ok: true, outboundMessageId }));
25028
+ }
25029
+ },
25030
+ (error61) => {
25031
+ if (socket.destroyed) {
25032
+ return;
25033
+ }
25034
+ const code = error61 instanceof LocalBotAuthorizationError ? error61.code : "bot_service_unavailable";
25035
+ const message = error61 instanceof LocalBotAuthorizationError ? error61.message : "The local Bot action could not be completed";
25036
+ socket.end(JSON.stringify({ error: { code, message }, ok: false }));
25037
+ }
25038
+ );
25039
+ });
25040
+ };
25041
+ handle = async (encoded, signal) => {
25042
+ const request = decodeRequest(encoded);
25043
+ const context = this.#registry.read(request.contextHandle);
25044
+ const timeout = AbortSignal.timeout(BOT_RELAY_TIMEOUT_MILLISECONDS);
25045
+ const requestSignal = AbortSignal.any([signal, timeout]);
25046
+ let response;
25047
+ try {
25048
+ response = await fetch(relayEndpoint(this.#relayUrl, context, request.target), {
25049
+ body: JSON.stringify({ idempotencyKey: request.idempotencyKey, text: request.text }),
25050
+ headers: {
25051
+ authorization: `Bearer ${daemonToken(this.#relayUrl)}`,
25052
+ "content-type": "application/json",
25053
+ "x-mobius-bot-execution-capability": context.command.executionCapabilitySecret
25054
+ },
25055
+ method: "POST",
25056
+ signal: requestSignal
25057
+ });
25058
+ } catch (cause) {
25059
+ signal.throwIfAborted();
25060
+ throw new LocalBotAuthorizationError(
25061
+ timeout.aborted ? "bot_service_timeout" : "bot_service_unavailable",
25062
+ timeout.aborted ? "The Mobius Bot action timed out" : "The Mobius Relay is unavailable",
25063
+ { cause }
25064
+ );
25065
+ }
25066
+ return await decodeRelayResponse(response);
25067
+ };
23741
25068
  };
23742
25069
 
23743
25070
  // src/pairing/pair-local-machine.ts
23744
- import { randomUUID } from "node:crypto";
23745
- import { mkdir as mkdir3, open as open4, realpath as realpath6, rename as rename3, stat as stat5, writeFile as writeFile2 } from "node:fs/promises";
25071
+ import { randomUUID as randomUUID3 } from "node:crypto";
25072
+ import { mkdir as mkdir4, open as open4, realpath as realpath6, rename as rename3, stat as stat6, writeFile as writeFile2 } from "node:fs/promises";
23746
25073
  import { hostname as hostname3 } from "node:os";
23747
25074
  import { basename, join as join14, resolve as resolve3 } from "node:path";
23748
- import { fetch as fetch2 } from "undici";
25075
+ import { fetch as fetch3 } from "undici";
23749
25076
 
23750
25077
  // src/agent-catalog/agent-discovery.ts
23751
25078
  var AgentDiscovery = class {
@@ -23853,8 +25180,8 @@ var LocalAgentInventory = class {
23853
25180
  };
23854
25181
 
23855
25182
  // src/agent-installation/managed-npm-package.ts
23856
- import { mkdir, mkdtemp, open as open2, realpath as realpath2, rename, rm, stat as stat2 } from "node:fs/promises";
23857
- import { delimiter, dirname as dirname3, isAbsolute, join as join4, relative, sep } from "node:path";
25183
+ import { mkdir as mkdir2, mkdtemp, open as open2, realpath as realpath2, rename, rm, stat as stat3 } from "node:fs/promises";
25184
+ import { delimiter, dirname as dirname4, isAbsolute as isAbsolute2, join as join4, relative, sep } from "node:path";
23858
25185
  var INSTALL_TIMEOUT_MILLISECONDS = 5 * 60 * 1e3;
23859
25186
  var PACKAGE_METADATA_LIMIT_BYTES = 64 * 1024;
23860
25187
  var PACKAGE_LOCK_LIMIT_BYTES = 8 * 1024 * 1024;
@@ -23901,7 +25228,7 @@ var ManagedNpmPackageError = class extends Error {
23901
25228
  this.name = "ManagedNpmPackageError";
23902
25229
  }
23903
25230
  };
23904
- function isRecord5(value) {
25231
+ function isRecord8(value) {
23905
25232
  return typeof value === "object" && value !== null && !Array.isArray(value);
23906
25233
  }
23907
25234
  function packagePath(root, packageName) {
@@ -23909,7 +25236,7 @@ function packagePath(root, packageName) {
23909
25236
  }
23910
25237
  function isContainedPath(root, candidate) {
23911
25238
  const difference = relative(root, candidate);
23912
- return difference.length > 0 && difference !== ".." && !difference.startsWith(`..${sep}`) && !isAbsolute(difference);
25239
+ return difference.length > 0 && difference !== ".." && !difference.startsWith(`..${sep}`) && !isAbsolute2(difference);
23913
25240
  }
23914
25241
  async function readJsonRecord(path2, maximumBytes) {
23915
25242
  try {
@@ -23923,7 +25250,7 @@ async function readJsonRecord(path2, maximumBytes) {
23923
25250
  );
23924
25251
  }
23925
25252
  const value = JSON.parse(await handle.readFile({ encoding: "utf8" }));
23926
- if (!isRecord5(value)) {
25253
+ if (!isRecord8(value)) {
23927
25254
  throw new ManagedNpmPackageError(
23928
25255
  "managed_package_verification_failed",
23929
25256
  "The managed npm package metadata is invalid"
@@ -23949,7 +25276,7 @@ function readBinPath(packageMetadata, executableName) {
23949
25276
  if (typeof bin === "string") {
23950
25277
  return bin;
23951
25278
  }
23952
- if (isRecord5(bin) && typeof bin[executableName] === "string") {
25279
+ if (isRecord8(bin) && typeof bin[executableName] === "string") {
23953
25280
  return bin[executableName];
23954
25281
  }
23955
25282
  throw new ManagedNpmPackageError(
@@ -23965,7 +25292,7 @@ function verifyPackageLockEntry(lock, definition, verifyDependencyClosure) {
23965
25292
  );
23966
25293
  }
23967
25294
  const packages = lock["packages"];
23968
- if (!isRecord5(packages)) {
25295
+ if (!isRecord8(packages)) {
23969
25296
  throw new ManagedNpmPackageError(
23970
25297
  "managed_package_verification_failed",
23971
25298
  "The managed npm package lockfile is invalid"
@@ -23979,7 +25306,7 @@ function verifyPackageLockEntry(lock, definition, verifyDependencyClosure) {
23979
25306
  if (verifyDependencyClosure && normalizedKey.length > 0) {
23980
25307
  let resolved;
23981
25308
  try {
23982
- if (!normalizedKey.split("/").includes("node_modules") || !isRecord5(candidate) || typeof candidate["version"] !== "string" || candidate["version"].length === 0 || typeof candidate["integrity"] !== "string" || !/^sha512-[A-Za-z0-9+/]{86}==$/.test(candidate["integrity"]) || typeof candidate["resolved"] !== "string") {
25309
+ if (!normalizedKey.split("/").includes("node_modules") || !isRecord8(candidate) || typeof candidate["version"] !== "string" || candidate["version"].length === 0 || typeof candidate["integrity"] !== "string" || !/^sha512-[A-Za-z0-9+/]{86}==$/.test(candidate["integrity"]) || typeof candidate["resolved"] !== "string") {
23983
25310
  throw new Error("Invalid locked dependency");
23984
25311
  }
23985
25312
  resolved = new URL(candidate["resolved"]);
@@ -24002,7 +25329,7 @@ function verifyPackageLockEntry(lock, definition, verifyDependencyClosure) {
24002
25329
  matches += 1;
24003
25330
  }
24004
25331
  }
24005
- if (matches !== 1 || !isRecord5(entry) || entry["integrity"] !== definition.integrity || entry["resolved"] !== definition.tarballUrl || entry["version"] !== definition.version) {
25332
+ if (matches !== 1 || !isRecord8(entry) || entry["integrity"] !== definition.integrity || entry["resolved"] !== definition.tarballUrl || entry["version"] !== definition.version) {
24006
25333
  throw new ManagedNpmPackageError(
24007
25334
  "managed_package_verification_failed",
24008
25335
  "The managed npm package lockfile does not match the pinned artifact"
@@ -24075,7 +25402,7 @@ var ManagedNpmPackageInstaller = class {
24075
25402
  install = async (root, definition, environment, signal) => {
24076
25403
  signal.throwIfAborted();
24077
25404
  try {
24078
- const metadata = await stat2(root);
25405
+ const metadata = await stat3(root);
24079
25406
  if (metadata.isDirectory()) {
24080
25407
  return await validateManagedNpmPackage(root, definition);
24081
25408
  }
@@ -24084,8 +25411,8 @@ var ManagedNpmPackageInstaller = class {
24084
25411
  throw error61;
24085
25412
  }
24086
25413
  }
24087
- const parent = dirname3(root);
24088
- await mkdir(parent, { mode: 448, recursive: true });
25414
+ const parent = dirname4(root);
25415
+ await mkdir2(parent, { mode: 448, recursive: true });
24089
25416
  const staging = await mkdtemp(join4(parent, `.${definition.version}.staging-`));
24090
25417
  try {
24091
25418
  const npm = await findExecutableOnPath(process.platform === "win32" ? "npm.cmd" : "npm", environment);
@@ -24119,7 +25446,7 @@ var ManagedNpmPackageInstaller = class {
24119
25446
  NPM_CONFIG_IGNORE_SCRIPTS: "true",
24120
25447
  NPM_CONFIG_PACKAGE_LOCK: "true",
24121
25448
  NPM_CONFIG_REGISTRY: "https://registry.npmjs.org/",
24122
- PATH: `${dirname3(process.execPath)}${delimiter}/usr/bin${delimiter}/bin`
25449
+ PATH: `${dirname4(process.execPath)}${delimiter}/usr/bin${delimiter}/bin`
24123
25450
  };
24124
25451
  if (definition.includeOptionalDependencies) {
24125
25452
  installEnvironment["NPM_CONFIG_INCLUDE"] = "optional";
@@ -24342,8 +25669,8 @@ var CursorCliAgentSpecification = class extends DirectAcpAgentDefinition {
24342
25669
  };
24343
25670
 
24344
25671
  // src/agent-catalog/agents/deepseek-harness-agent.ts
24345
- import { realpath as realpath3, stat as stat3 } from "node:fs/promises";
24346
- import { isAbsolute as isAbsolute2, join as join6, normalize } from "node:path";
25672
+ import { realpath as realpath3, stat as stat4 } from "node:fs/promises";
25673
+ import { isAbsolute as isAbsolute3, join as join6, normalize } from "node:path";
24347
25674
 
24348
25675
  // src/agent-installation/deepseek-managed-package.ts
24349
25676
  var DeepSeekHarnessManagedPackage = class extends SriManagedNpmPackageDefinition {
@@ -24361,12 +25688,12 @@ var DEEPSEEK_HARNESS_PACKAGE = new DeepSeekHarnessManagedPackage(
24361
25688
 
24362
25689
  // src/agent-catalog/agents/deepseek-harness-agent.ts
24363
25690
  async function validateAgentHome(path2) {
24364
- if (!isAbsolute2(path2) || normalize(path2) !== path2) {
25691
+ if (!isAbsolute3(path2) || normalize(path2) !== path2) {
24365
25692
  throw new AgentProbeError("agent_environment_invalid", "The configured Agent home is invalid");
24366
25693
  }
24367
25694
  try {
24368
25695
  const resolved = await realpath3(path2);
24369
- const metadata = await stat3(resolved);
25696
+ const metadata = await stat4(resolved);
24370
25697
  if (!metadata.isDirectory() || typeof process.getuid === "function" && metadata.uid !== process.getuid()) {
24371
25698
  throw new Error("Agent home is not a user-owned directory");
24372
25699
  }
@@ -24449,7 +25776,7 @@ var DeepSeekHarnessAgentSpecification = class extends DirectAcpAgentDefinition {
24449
25776
 
24450
25777
  // src/agent-catalog/agents/grok-build-agent.ts
24451
25778
  import { realpath as realpath4 } from "node:fs/promises";
24452
- import { isAbsolute as isAbsolute3, join as join7, relative as relative2, sep as sep2 } from "node:path";
25779
+ import { isAbsolute as isAbsolute4, join as join7, relative as relative2, sep as sep2 } from "node:path";
24453
25780
 
24454
25781
  // src/agent-installation/grok-managed-package.ts
24455
25782
  var GROK_BUILD_MANAGED_VERSION = "1.0.21";
@@ -24512,7 +25839,7 @@ function grokBuildManagedPackage(platform, architecture) {
24512
25839
  // src/agent-catalog/agents/grok-build-agent.ts
24513
25840
  function isContainedPath2(root, candidate) {
24514
25841
  const difference = relative2(root, candidate);
24515
- return difference.length > 0 && difference !== ".." && !difference.startsWith(`..${sep2}`) && !isAbsolute3(difference);
25842
+ return difference.length > 0 && difference !== ".." && !difference.startsWith(`..${sep2}`) && !isAbsolute4(difference);
24516
25843
  }
24517
25844
  var GrokBuildAgentSpecification = class extends DirectAcpAgentDefinition {
24518
25845
  adapterVersion = GROK_BUILD_MANAGED_VERSION;
@@ -24574,13 +25901,13 @@ var GrokBuildAgentSpecification = class extends DirectAcpAgentDefinition {
24574
25901
  import { join as join9 } from "node:path";
24575
25902
 
24576
25903
  // src/agent-installation/managed-agent-archive.ts
24577
- import { createHash } from "node:crypto";
25904
+ import { createHash as createHash2 } from "node:crypto";
24578
25905
  import { createReadStream } from "node:fs";
24579
- import { chmod, copyFile, mkdir as mkdir2, mkdtemp as mkdtemp2, open as open3, realpath as realpath5, rename as rename2, rm as rm2, stat as stat4, writeFile } from "node:fs/promises";
24580
- import { dirname as dirname4, isAbsolute as isAbsolute4, join as join8, relative as relative3, sep as sep3 } from "node:path";
25906
+ import { chmod as chmod2, copyFile, mkdir as mkdir3, mkdtemp as mkdtemp2, open as open3, realpath as realpath5, rename as rename2, rm as rm2, stat as stat5, writeFile } from "node:fs/promises";
25907
+ import { dirname as dirname5, isAbsolute as isAbsolute5, join as join8, relative as relative3, sep as sep3 } from "node:path";
24581
25908
 
24582
25909
  // src/agent-installation/verified-download.ts
24583
- import { fetch } from "undici";
25910
+ import { fetch as fetch2 } from "undici";
24584
25911
 
24585
25912
  // src/network/environment-proxy.ts
24586
25913
  import { EnvHttpProxyAgent } from "undici";
@@ -24632,16 +25959,16 @@ var ManagedAgentArchiveError = class extends Error {
24632
25959
  this.name = "ManagedAgentArchiveError";
24633
25960
  }
24634
25961
  };
24635
- function isRecord6(value) {
25962
+ function isRecord9(value) {
24636
25963
  return typeof value === "object" && value !== null && !Array.isArray(value);
24637
25964
  }
24638
25965
  function isContainedPath3(root, candidate) {
24639
25966
  const difference = relative3(root, candidate);
24640
- return difference.length > 0 && difference !== ".." && !difference.startsWith(`..${sep3}`) && !isAbsolute4(difference);
25967
+ return difference.length > 0 && difference !== ".." && !difference.startsWith(`..${sep3}`) && !isAbsolute5(difference);
24641
25968
  }
24642
25969
  async function hashFile(path2, signal) {
24643
25970
  signal.throwIfAborted();
24644
- const digest = createHash("sha256");
25971
+ const digest2 = createHash2("sha256");
24645
25972
  const stream = createReadStream(path2, { signal });
24646
25973
  try {
24647
25974
  for await (const chunk of stream) {
@@ -24652,9 +25979,9 @@ async function hashFile(path2, signal) {
24652
25979
  "The managed Agent archive produced invalid bytes"
24653
25980
  );
24654
25981
  }
24655
- digest.update(chunk);
25982
+ digest2.update(chunk);
24656
25983
  }
24657
- return digest.digest("hex");
25984
+ return digest2.digest("hex");
24658
25985
  } catch (error61) {
24659
25986
  if (signal.aborted) {
24660
25987
  signal.throwIfAborted();
@@ -24689,7 +26016,7 @@ async function readManifest(path2) {
24689
26016
  );
24690
26017
  }
24691
26018
  const parsed = JSON.parse(await handle.readFile({ encoding: "utf8" }));
24692
- if (!isRecord6(parsed)) {
26019
+ if (!isRecord9(parsed)) {
24693
26020
  throw new ManagedAgentArchiveError(
24694
26021
  "managed_archive_verification_failed",
24695
26022
  "The managed Agent archive manifest is invalid"
@@ -24712,7 +26039,7 @@ async function readManifest(path2) {
24712
26039
  async function validateManagedAgentArchive(root, definition, signal) {
24713
26040
  try {
24714
26041
  const rootPath = await realpath5(root);
24715
- const rootMetadata = await stat4(rootPath);
26042
+ const rootMetadata = await stat5(rootPath);
24716
26043
  if (!rootMetadata.isDirectory() || typeof process.getuid === "function" && rootMetadata.uid !== process.getuid()) {
24717
26044
  throw new Error("Managed Agent root is not user-owned");
24718
26045
  }
@@ -24927,7 +26254,7 @@ var PiAgentSpecification = class extends BridgedAcpAgentDefinition {
24927
26254
  };
24928
26255
 
24929
26256
  // src/agent-catalog/agents/workbuddy-agent.ts
24930
- import { isAbsolute as isAbsolute5, join as join11 } from "node:path";
26257
+ import { isAbsolute as isAbsolute6, join as join11 } from "node:path";
24931
26258
 
24932
26259
  // src/agent-installation/workbuddy-managed-package.ts
24933
26260
  var WORKBUDDY_MANAGED_VERSION = "2.146.0";
@@ -24993,7 +26320,7 @@ var WorkBuddyAgentSpecification = class extends DirectAcpAgentDefinition {
24993
26320
  }
24994
26321
  const requestedPaths = [join11("/Applications", ...WORKBUDDY_MACOS_EXECUTABLE_PATH)];
24995
26322
  const homeDirectory = context.environment["HOME"];
24996
- if (homeDirectory !== void 0 && isAbsolute5(homeDirectory)) {
26323
+ if (homeDirectory !== void 0 && isAbsolute6(homeDirectory)) {
24997
26324
  requestedPaths.unshift(join11(homeDirectory, "Applications", ...WORKBUDDY_MACOS_EXECUTABLE_PATH));
24998
26325
  }
24999
26326
  const executables = [];
@@ -25039,7 +26366,7 @@ import {
25039
26366
  } from "@agentclientprotocol/sdk";
25040
26367
 
25041
26368
  // src/agent-catalog/executable-discovery.ts
25042
- import { isAbsolute as isAbsolute6, join as join13 } from "node:path";
26369
+ import { isAbsolute as isAbsolute7, join as join13 } from "node:path";
25043
26370
 
25044
26371
  // src/agent-installation/managed-adapter-installer.ts
25045
26372
  import { join as join12 } from "node:path";
@@ -25144,7 +26471,7 @@ async function resolveManagedAdapterExecutable(specification, context) {
25144
26471
  async function resolveSpecificationExecutables(executableName, overrideVariable, resolveInstalled, resolveManaged, context) {
25145
26472
  const override = context.environment[overrideVariable];
25146
26473
  if (override !== void 0) {
25147
- if (override.length === 0 || !isAbsolute6(override)) {
26474
+ if (override.length === 0 || !isAbsolute7(override)) {
25148
26475
  return [];
25149
26476
  }
25150
26477
  const executable = await resolveExecutablePath(override, context.platform);
@@ -25564,8 +26891,8 @@ async function discoverLocalAgentInventory(options) {
25564
26891
  // src/pairing/pair-local-machine.ts
25565
26892
  var PAIRING_TIMEOUT_MILLISECONDS = 2e4;
25566
26893
  var PAIRING_CODE_PATTERN = /^[A-HJ-NP-Z2-9]{4}(?:-[A-HJ-NP-Z2-9]{4}){4}$/;
25567
- var IDENTIFIER_PATTERN4 = /^[a-zA-Z0-9][a-zA-Z0-9._:-]{0,127}$/;
25568
- var TOKEN_PATTERN = /^[a-zA-Z0-9_-]{32,256}$/;
26894
+ var IDENTIFIER_PATTERN6 = /^[a-zA-Z0-9][a-zA-Z0-9._:-]{0,127}$/;
26895
+ var TOKEN_PATTERN2 = /^[a-zA-Z0-9_-]{32,256}$/;
25569
26896
  var MAX_CONNECTION_FILE_LENGTH = 16 * 1024;
25570
26897
  var CLAIM_RESPONSE_KEYS = ["channelId", "daemonToken", "runtimeId"];
25571
26898
  var SAVED_CONNECTION_KEYS = ["defaultWorkspace", "channelId", "daemonToken", "relayOrigin"];
@@ -25577,36 +26904,36 @@ var PairingClientError = class extends Error {
25577
26904
  this.name = "PairingClientError";
25578
26905
  }
25579
26906
  };
25580
- function isRecord7(value) {
26907
+ function isRecord10(value) {
25581
26908
  return typeof value === "object" && value !== null && !Array.isArray(value);
25582
26909
  }
25583
26910
  function hasExactKeys(value, expectedKeys) {
25584
26911
  const keys = Object.keys(value);
25585
26912
  return keys.length === expectedKeys.length && expectedKeys.every((key) => Object.hasOwn(value, key));
25586
26913
  }
25587
- function readSingleOption(arguments_, option) {
26914
+ function readSingleOption(arguments_, option2) {
25588
26915
  const values = [];
25589
26916
  for (let index = 0; index < arguments_.length; index += 1) {
25590
- if (arguments_[index] !== option) {
26917
+ if (arguments_[index] !== option2) {
25591
26918
  continue;
25592
26919
  }
25593
26920
  const value = arguments_[index + 1];
25594
26921
  if (value === void 0 || value.startsWith("--")) {
25595
- throw new PairingClientError("invalid_arguments", `${option} requires a value`);
26922
+ throw new PairingClientError("invalid_arguments", `${option2} requires a value`);
25596
26923
  }
25597
26924
  values.push(value);
25598
26925
  index += 1;
25599
26926
  }
25600
26927
  if (values.length !== 1) {
25601
- throw new PairingClientError("invalid_arguments", `${option} must be provided exactly once`);
26928
+ throw new PairingClientError("invalid_arguments", `${option2} must be provided exactly once`);
25602
26929
  }
25603
26930
  return values[0] ?? "";
25604
26931
  }
25605
26932
  function assertKnownArguments(arguments_) {
25606
26933
  for (let index = 0; index < arguments_.length; index += 2) {
25607
- const option = arguments_[index];
25608
- if (option !== "--url" && option !== "--code" && option !== "--workspace") {
25609
- throw new PairingClientError("invalid_arguments", `Unknown pairing option: ${option ?? "missing option"}`);
26934
+ const option2 = arguments_[index];
26935
+ if (option2 !== "--url" && option2 !== "--code" && option2 !== "--workspace") {
26936
+ throw new PairingClientError("invalid_arguments", `Unknown pairing option: ${option2 ?? "missing option"}`);
25610
26937
  }
25611
26938
  }
25612
26939
  }
@@ -25654,7 +26981,7 @@ function parseChannelArgument(arguments_) {
25654
26981
  throw new PairingClientError("invalid_arguments", "Usage: mobius start --channel <channel-id>");
25655
26982
  }
25656
26983
  const channelId = arguments_[1] ?? "";
25657
- if (!IDENTIFIER_PATTERN4.test(channelId)) {
26984
+ if (!IDENTIFIER_PATTERN6.test(channelId)) {
25658
26985
  throw new PairingClientError("invalid_channel_id", "The saved channel ID is invalid");
25659
26986
  }
25660
26987
  return channelId;
@@ -25662,9 +26989,9 @@ function parseChannelArgument(arguments_) {
25662
26989
  async function resolveDefaultWorkspace(path2) {
25663
26990
  const requestedWorkspace = resolve3(path2);
25664
26991
  try {
25665
- await mkdir3(requestedWorkspace, { recursive: true, mode: 448 });
26992
+ await mkdir4(requestedWorkspace, { recursive: true, mode: 448 });
25666
26993
  const defaultWorkspace = await realpath6(requestedWorkspace);
25667
- const metadata = await stat5(defaultWorkspace);
26994
+ const metadata = await stat6(defaultWorkspace);
25668
26995
  if (!metadata.isDirectory()) {
25669
26996
  throw new PairingClientError("invalid_workspace", "The default workspace is not a directory");
25670
26997
  }
@@ -25693,9 +27020,9 @@ async function readJsonResponse(response) {
25693
27020
  }
25694
27021
  }
25695
27022
  function readRelayError(value) {
25696
- if (isRecord7(value)) {
27023
+ if (isRecord10(value)) {
25697
27024
  const error61 = value["error"];
25698
- if (isRecord7(error61)) {
27025
+ if (isRecord10(error61)) {
25699
27026
  const code = error61["code"];
25700
27027
  const message = error61["message"];
25701
27028
  if (typeof code === "string" && typeof message === "string") {
@@ -25706,16 +27033,16 @@ function readRelayError(value) {
25706
27033
  return new PairingClientError("pairing_failed", "The relay could not pair this machine");
25707
27034
  }
25708
27035
  function decodeClaimResponse(value) {
25709
- if (!isRecord7(value) || !hasExactKeys(value, CLAIM_RESPONSE_KEYS)) {
27036
+ if (!isRecord10(value) || !hasExactKeys(value, CLAIM_RESPONSE_KEYS)) {
25710
27037
  throw new PairingClientError("invalid_relay_response", "The relay returned an invalid pairing response");
25711
27038
  }
25712
27039
  const channelId = value["channelId"];
25713
- const daemonToken = value["daemonToken"];
27040
+ const daemonToken2 = value["daemonToken"];
25714
27041
  const runtimeId = value["runtimeId"];
25715
- if (typeof channelId !== "string" || !IDENTIFIER_PATTERN4.test(channelId) || typeof daemonToken !== "string" || !TOKEN_PATTERN.test(daemonToken) || typeof runtimeId !== "string" || !IDENTIFIER_PATTERN4.test(runtimeId)) {
27042
+ if (typeof channelId !== "string" || !IDENTIFIER_PATTERN6.test(channelId) || typeof daemonToken2 !== "string" || !TOKEN_PATTERN2.test(daemonToken2) || typeof runtimeId !== "string" || !IDENTIFIER_PATTERN6.test(runtimeId)) {
25716
27043
  throw new PairingClientError("invalid_relay_response", "The relay returned an invalid pairing response");
25717
27044
  }
25718
- return { channelId, daemonToken, runtimeId };
27045
+ return { channelId, daemonToken: daemonToken2, runtimeId };
25719
27046
  }
25720
27047
  async function claimPairing(options, defaultWorkspace, localAgents, installableAgents, signal) {
25721
27048
  const agents = localAgents.map((agent) => ({
@@ -25728,7 +27055,7 @@ async function claimPairing(options, defaultWorkspace, localAgents, installableA
25728
27055
  const endpoint = mobiusApiUrl(options.relayOrigin, "/pairings/claim");
25729
27056
  let response;
25730
27057
  try {
25731
- response = await fetch2(endpoint, {
27058
+ response = await fetch3(endpoint, {
25732
27059
  body: JSON.stringify({
25733
27060
  agents,
25734
27061
  installableAgents,
@@ -25750,18 +27077,18 @@ async function claimPairing(options, defaultWorkspace, localAgents, installableA
25750
27077
  }
25751
27078
  return decodeClaimResponse(value);
25752
27079
  }
25753
- async function persistConnection(channelId, relayOrigin, daemonToken, defaultWorkspace) {
27080
+ async function persistConnection(channelId, relayOrigin, daemonToken2, defaultWorkspace) {
25754
27081
  const connectionsDirectory = join14(readStateDirectory(), "connections");
25755
- await mkdir3(connectionsDirectory, { mode: 448, recursive: true });
27082
+ await mkdir4(connectionsDirectory, { mode: 448, recursive: true });
25756
27083
  const connectionPath = join14(connectionsDirectory, `${channelId}.json`);
25757
- const temporaryPath = join14(connectionsDirectory, `.${channelId}.${randomUUID()}.tmp`);
27084
+ const temporaryPath = join14(connectionsDirectory, `.${channelId}.${randomUUID3()}.tmp`);
25758
27085
  await writeFile2(
25759
27086
  temporaryPath,
25760
27087
  `${JSON.stringify(
25761
27088
  {
25762
27089
  defaultWorkspace,
25763
27090
  channelId,
25764
- daemonToken,
27091
+ daemonToken: daemonToken2,
25765
27092
  relayOrigin: relayOrigin.toString()
25766
27093
  },
25767
27094
  null,
@@ -25774,20 +27101,20 @@ async function persistConnection(channelId, relayOrigin, daemonToken, defaultWor
25774
27101
  return connectionPath;
25775
27102
  }
25776
27103
  function decodeSavedConnection(value, expectedChannelId) {
25777
- if (!isRecord7(value) || !hasExactKeys(value, SAVED_CONNECTION_KEYS)) {
27104
+ if (!isRecord10(value) || !hasExactKeys(value, SAVED_CONNECTION_KEYS)) {
25778
27105
  throw new PairingClientError("invalid_connection", "The saved connection is invalid");
25779
27106
  }
25780
27107
  const defaultWorkspace = value["defaultWorkspace"];
25781
27108
  const channelId = value["channelId"];
25782
- const daemonToken = value["daemonToken"];
27109
+ const daemonToken2 = value["daemonToken"];
25783
27110
  const relayOrigin = value["relayOrigin"];
25784
- if (typeof defaultWorkspace !== "string" || typeof channelId !== "string" || channelId !== expectedChannelId || !IDENTIFIER_PATTERN4.test(channelId) || typeof daemonToken !== "string" || !TOKEN_PATTERN.test(daemonToken) || typeof relayOrigin !== "string") {
27111
+ if (typeof defaultWorkspace !== "string" || typeof channelId !== "string" || channelId !== expectedChannelId || !IDENTIFIER_PATTERN6.test(channelId) || typeof daemonToken2 !== "string" || !TOKEN_PATTERN2.test(daemonToken2) || typeof relayOrigin !== "string") {
25785
27112
  throw new PairingClientError("invalid_connection", "The saved connection is invalid");
25786
27113
  }
25787
27114
  return {
25788
27115
  defaultWorkspace,
25789
27116
  channelId,
25790
- daemonToken,
27117
+ daemonToken: daemonToken2,
25791
27118
  relayOrigin: parseRelayOrigin(relayOrigin)
25792
27119
  };
25793
27120
  }
@@ -25888,12 +27215,13 @@ async function resumeLocalMachine(arguments_, signal = new AbortController().sig
25888
27215
  }
25889
27216
 
25890
27217
  // src/run-daemon.ts
25891
- import { basename as basename3 } from "node:path";
27218
+ import { randomUUID as randomUUID6 } from "node:crypto";
27219
+ import { basename as basename3, join as join16 } from "node:path";
25892
27220
  import { styleText } from "node:util";
25893
- import { fetch as fetch5, WebSocket as WebSocket2 } from "undici";
27221
+ import { fetch as fetch6, WebSocket as WebSocket2 } from "undici";
25894
27222
 
25895
27223
  // src/agent-catalog/publish-agent-catalog.ts
25896
- import { fetch as fetch3 } from "undici";
27224
+ import { fetch as fetch4 } from "undici";
25897
27225
  var CATALOG_UPDATE_TIMEOUT_MILLISECONDS = 2e4;
25898
27226
  var AgentCatalogPublishError = class extends Error {
25899
27227
  code = "agent_catalog_update_failed";
@@ -25918,7 +27246,7 @@ async function publishAgentCatalog(config2, signal) {
25918
27246
  let response;
25919
27247
  const catalog = config2.catalog.read();
25920
27248
  try {
25921
- response = await fetch3(catalogEndpoint(config2.relayUrl), {
27249
+ response = await fetch4(catalogEndpoint(config2.relayUrl), {
25922
27250
  body: JSON.stringify({
25923
27251
  agents: catalog.agents.map((agent) => ({
25924
27252
  agentPath: agent.agentIdentity.requestedPath,
@@ -26413,9 +27741,9 @@ var FixedInstallationExecutor = class {
26413
27741
  };
26414
27742
 
26415
27743
  // src/authorization/workspace-directory.ts
26416
- import { readdir, realpath as realpath7, stat as stat6 } from "node:fs/promises";
27744
+ import { readdir, realpath as realpath7, stat as stat7 } from "node:fs/promises";
26417
27745
  import { homedir as homedir2 } from "node:os";
26418
- import { basename as basename2, dirname as dirname5, isAbsolute as isAbsolute7, join as join15, normalize as normalize2, relative as relative4 } from "node:path";
27746
+ import { basename as basename2, dirname as dirname6, isAbsolute as isAbsolute8, join as join15, normalize as normalize2, relative as relative4 } from "node:path";
26419
27747
  var WorkspaceDirectoryListing = class {
26420
27748
  directoryId;
26421
27749
  directoryLabel;
@@ -26467,7 +27795,7 @@ var WorkspaceDirectoryService = class {
26467
27795
  }
26468
27796
  if (id.startsWith("path-")) {
26469
27797
  const path2 = decodePath(id, "path-");
26470
- if (isAbsolute7(path2)) {
27798
+ if (isAbsolute8(path2)) {
26471
27799
  return path2;
26472
27800
  }
26473
27801
  }
@@ -26475,15 +27803,15 @@ var WorkspaceDirectoryService = class {
26475
27803
  };
26476
27804
  resolvePath = async (requested, signal) => {
26477
27805
  signal.throwIfAborted();
26478
- if (!isAbsolute7(requested) || requested.includes("\0") || normalize2(requested) !== requested) {
27806
+ if (!isAbsolute8(requested) || requested.includes("\0") || normalize2(requested) !== requested) {
26479
27807
  throw new LocalAuthorizationError("The local directory path is invalid");
26480
27808
  }
26481
27809
  try {
26482
27810
  const target = await realpath7(requested);
26483
27811
  signal.throwIfAborted();
26484
- const metadata = await stat6(target);
27812
+ const metadata = await stat7(target);
26485
27813
  signal.throwIfAborted();
26486
- if (!isAbsolute7(target) || normalize2(target) !== target || !metadata.isDirectory()) {
27814
+ if (!isAbsolute8(target) || normalize2(target) !== target || !metadata.isDirectory()) {
26487
27815
  throw new LocalAuthorizationError("The selected location is not a directory");
26488
27816
  }
26489
27817
  return target;
@@ -26499,7 +27827,7 @@ var WorkspaceDirectoryService = class {
26499
27827
  };
26500
27828
  label = (path2) => {
26501
27829
  const suffix = relative4(homedir2(), path2);
26502
- return suffix === "" ? "~" : !isAbsolute7(suffix) && suffix !== ".." && !suffix.startsWith(`..${process.platform === "win32" ? "\\" : "/"}`) ? `~/${suffix.replaceAll("\\", "/")}` : path2;
27830
+ return suffix === "" ? "~" : !isAbsolute8(suffix) && suffix !== ".." && !suffix.startsWith(`..${process.platform === "win32" ? "\\" : "/"}`) ? `~/${suffix.replaceAll("\\", "/")}` : path2;
26503
27831
  };
26504
27832
  identify = async (bindingId, requestedPath, signal) => {
26505
27833
  this.authorizeMachine(bindingId);
@@ -26539,7 +27867,7 @@ var WorkspaceDirectoryService = class {
26539
27867
  }
26540
27868
  }
26541
27869
  entries.sort((a, b) => a.name.localeCompare(b.name));
26542
- const parent = dirname5(target);
27870
+ const parent = dirname6(target);
26543
27871
  return new WorkspaceDirectoryListing(
26544
27872
  id,
26545
27873
  this.label(target),
@@ -26563,8 +27891,44 @@ var WorkspaceDirectoryService = class {
26563
27891
  };
26564
27892
  };
26565
27893
 
27894
+ // src/bots/bot-context-applicator.ts
27895
+ var AppliedBotContext = class {
27896
+ resources;
27897
+ constructor(resources) {
27898
+ this.resources = Object.freeze([...resources]);
27899
+ }
27900
+ };
27901
+ var EmbeddedBotContextApplicator = class {
27902
+ apply = async (command, grant, resources, signal) => {
27903
+ signal.throwIfAborted();
27904
+ if (grant.botId !== command.botId || grant.behaviorRevisionId !== command.behaviorRevisionId || grant.behaviorDigest !== command.behaviorDigest) {
27905
+ throw new LocalBotAuthorizationError(
27906
+ "binding_not_approved",
27907
+ "The Bot behavior does not match its local authorization"
27908
+ );
27909
+ }
27910
+ if (command.behaviorInstructions.length === 0) {
27911
+ return new AppliedBotContext(resources);
27912
+ }
27913
+ if (!grant.agent.capabilities.embeddedContextPrompt) {
27914
+ throw new LocalBotAuthorizationError(
27915
+ "binding_incompatible",
27916
+ "The local Agent cannot enforce the Bot behavior context"
27917
+ );
27918
+ }
27919
+ const trustedContext = {
27920
+ mimeType: "text/markdown",
27921
+ name: "Mobius Bot behavior",
27922
+ text: command.behaviorInstructions,
27923
+ type: "embedded",
27924
+ uri: `mobius://bots/${encodeURIComponent(command.botId)}/behavior-revisions/${encodeURIComponent(command.behaviorRevisionId)}?sha256=${command.behaviorDigest}`
27925
+ };
27926
+ return new AppliedBotContext([trustedContext, ...resources]);
27927
+ };
27928
+ };
27929
+
26566
27930
  // src/native-sessions/service.ts
26567
- import { randomUUID as randomUUID2 } from "node:crypto";
27931
+ import { randomUUID as randomUUID4 } from "node:crypto";
26568
27932
 
26569
27933
  // src/native-sessions/codex-history.ts
26570
27934
  import { spawn as spawn4 } from "node:child_process";
@@ -26880,7 +28244,7 @@ var NativeSessionService = class {
26880
28244
  if (authorized === null) {
26881
28245
  continue;
26882
28246
  }
26883
- const entryId = randomUUID2();
28247
+ const entryId = randomUUID4();
26884
28248
  if (this.#entries.size >= 5e3) {
26885
28249
  this.#entries.clear();
26886
28250
  }
@@ -26908,7 +28272,7 @@ var NativeSessionService = class {
26908
28272
  "invalid_native_session_response"
26909
28273
  );
26910
28274
  }
26911
- nextCursor = randomUUID2();
28275
+ nextCursor = randomUUID4();
26912
28276
  if (this.#cursors.size >= 500) {
26913
28277
  this.#cursors.clear();
26914
28278
  }
@@ -27126,13 +28490,13 @@ var NativeSessionService = class {
27126
28490
  };
27127
28491
 
27128
28492
  // src/prompt-artifact-resolver.ts
27129
- import { createHash as createHash2 } from "node:crypto";
27130
- import { fetch as fetch4 } from "undici";
28493
+ import { createHash as createHash3 } from "node:crypto";
28494
+ import { fetch as fetch5 } from "undici";
27131
28495
  var ARTIFACT_SCHEME = "mobius-artifact:";
27132
28496
  var ARTIFACT_DOWNLOAD_TIMEOUT_MILLISECONDS = 2e4;
27133
28497
  var MAX_AGENT_IMAGE_BASE64_LENGTH = 4e6;
27134
28498
  var MAX_AGENT_RESOURCE_BYTE_LENGTH = 1e6;
27135
- var IDENTIFIER_PATTERN5 = /^[a-zA-Z0-9][a-zA-Z0-9._:-]{0,127}$/;
28499
+ var IDENTIFIER_PATTERN7 = /^[a-zA-Z0-9][a-zA-Z0-9._:-]{0,127}$/;
27136
28500
  var PromptArtifactError = class extends Error {
27137
28501
  code;
27138
28502
  constructor(code, message, options = {}) {
@@ -27175,7 +28539,7 @@ function parseReference(resource) {
27175
28539
  const encodedByteLength2 = url2.searchParams.get("byteLength") ?? "";
27176
28540
  const sha256 = url2.searchParams.get("sha256") ?? "";
27177
28541
  const byteLength = Number(encodedByteLength2);
27178
- 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)) {
28542
+ 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)) {
27179
28543
  throw new PromptArtifactError("artifact_reference_invalid", "The prompt artifact reference is invalid");
27180
28544
  }
27181
28545
  return new PromptArtifactReference(artifactId, byteLength, sha256, resource);
@@ -27236,7 +28600,7 @@ async function download(config2, command, reference, signal) {
27236
28600
  const requestSignal = AbortSignal.any([signal, timeoutSignal]);
27237
28601
  let response;
27238
28602
  try {
27239
- response = await fetch4(downloadUrl(config2, command, reference), {
28603
+ response = await fetch5(downloadUrl(config2, command, reference), {
27240
28604
  dispatcher: environmentProxyDispatcher,
27241
28605
  headers: { accept: reference.resource.mimeType },
27242
28606
  signal: requestSignal
@@ -27256,7 +28620,7 @@ async function download(config2, command, reference, signal) {
27256
28620
  );
27257
28621
  }
27258
28622
  const bytes = await responseBytes(response, reference.byteLength, requestSignal);
27259
- if (createHash2("sha256").update(bytes).digest("hex") !== reference.sha256) {
28623
+ if (createHash3("sha256").update(bytes).digest("hex") !== reference.sha256) {
27260
28624
  throw new PromptArtifactError(
27261
28625
  "artifact_integrity_failed",
27262
28626
  "The prompt artifact failed integrity validation"
@@ -27401,7 +28765,7 @@ function connectRelay(url2, signal) {
27401
28765
  }
27402
28766
 
27403
28767
  // src/relay-connection/liveness.ts
27404
- import { randomUUID as randomUUID3 } from "node:crypto";
28768
+ import { randomUUID as randomUUID5 } from "node:crypto";
27405
28769
  var HEARTBEAT_ACK_TIMEOUT_MILLISECONDS = 1e4;
27406
28770
  var HEARTBEAT_INTERVAL_MILLISECONDS = 2e4;
27407
28771
  var RelayLivenessState = class {
@@ -27489,7 +28853,7 @@ var RelayConnectionLiveness = class {
27489
28853
  }
27490
28854
  throw new Error("Heartbeat was scheduled in an invalid state");
27491
28855
  }
27492
- const heartbeatId = randomUUID3();
28856
+ const heartbeatId = randomUUID5();
27493
28857
  this.#state = new AwaitingHeartbeatAckState(
27494
28858
  heartbeatId,
27495
28859
  this.#timer.schedule(this.#handleTimeout, HEARTBEAT_ACK_TIMEOUT_MILLISECONDS)
@@ -27505,8 +28869,8 @@ var RelayConnectionLiveness = class {
27505
28869
 
27506
28870
  // src/relay-connection/session-event-outbox.ts
27507
28871
  import { mkdirSync as mkdirSync3 } from "node:fs";
27508
- import { dirname as dirname6 } from "node:path";
27509
- import { DatabaseSync as DatabaseSync3 } from "node:sqlite";
28872
+ import { dirname as dirname7 } from "node:path";
28873
+ import { DatabaseSync as DatabaseSync4 } from "node:sqlite";
27510
28874
  function readPendingEnvelope(row) {
27511
28875
  if (typeof row !== "object" || row === null || Array.isArray(row)) {
27512
28876
  throw new Error("SQLite returned an invalid session event outbox row");
@@ -27520,8 +28884,8 @@ function readPendingEnvelope(row) {
27520
28884
  var SessionEventOutbox = class {
27521
28885
  #database;
27522
28886
  constructor(path2) {
27523
- mkdirSync3(dirname6(path2), { recursive: true });
27524
- this.#database = new DatabaseSync3(path2);
28887
+ mkdirSync3(dirname7(path2), { recursive: true });
28888
+ this.#database = new DatabaseSync4(path2);
27525
28889
  this.#database.exec(`
27526
28890
  CREATE TABLE IF NOT EXISTS relay_session_event_outbox (
27527
28891
  ordinal INTEGER PRIMARY KEY AUTOINCREMENT,
@@ -27531,6 +28895,15 @@ var SessionEventOutbox = class {
27531
28895
  ) STRICT;
27532
28896
  CREATE INDEX IF NOT EXISTS relay_session_event_outbox_order
27533
28897
  ON relay_session_event_outbox(ordinal);
28898
+ CREATE TABLE IF NOT EXISTS relay_session_event_dead_letters (
28899
+ ordinal INTEGER PRIMARY KEY,
28900
+ event_id TEXT NOT NULL UNIQUE,
28901
+ session_id TEXT NOT NULL,
28902
+ envelope_json TEXT NOT NULL,
28903
+ rejection_code TEXT NOT NULL CHECK (
28904
+ rejection_code IN ('session_deleted', 'session_not_found')
28905
+ )
28906
+ ) STRICT;
27534
28907
  CREATE TABLE IF NOT EXISTS relay_session_event_sources (
27535
28908
  source_key TEXT PRIMARY KEY,
27536
28909
  next_source_seq INTEGER NOT NULL
@@ -27603,6 +28976,35 @@ var SessionEventOutbox = class {
27603
28976
  WHERE event_id = ? AND session_id = ?`
27604
28977
  ).run(acknowledgement.eventId, acknowledgement.sessionId);
27605
28978
  };
28979
+ quarantine = (rejection) => {
28980
+ this.#database.exec("BEGIN IMMEDIATE");
28981
+ try {
28982
+ const insertion = this.#database.prepare(
28983
+ `INSERT INTO relay_session_event_dead_letters (
28984
+ ordinal, event_id, session_id, envelope_json, rejection_code
28985
+ )
28986
+ SELECT ordinal, event_id, session_id, envelope_json, ?
28987
+ FROM relay_session_event_outbox
28988
+ WHERE event_id = ? AND session_id = ?`
28989
+ ).run(rejection.code, rejection.eventId, rejection.sessionId);
28990
+ if (insertion.changes !== 1) {
28991
+ this.#database.exec("COMMIT");
28992
+ return false;
28993
+ }
28994
+ const deletion = this.#database.prepare(
28995
+ `DELETE FROM relay_session_event_outbox
28996
+ WHERE event_id = ? AND session_id = ?`
28997
+ ).run(rejection.eventId, rejection.sessionId);
28998
+ if (deletion.changes !== 1) {
28999
+ throw new Error("The rejected session event could not be removed from the durable outbox");
29000
+ }
29001
+ this.#database.exec("COMMIT");
29002
+ return true;
29003
+ } catch (error61) {
29004
+ this.#database.exec("ROLLBACK");
29005
+ throw error61;
29006
+ }
29007
+ };
27606
29008
  close = () => {
27607
29009
  this.#database.close();
27608
29010
  };
@@ -27674,6 +29076,12 @@ var RELAY_RECONNECT_DELAY_MILLISECONDS = 500;
27674
29076
  var RELAY_CONNECTION_REFRESH_MILLISECONDS = 20 * 60 * 1e3;
27675
29077
  var ACTIVE_TURN_RECONCILIATION_TIMEOUT_MILLISECONDS = 2e4;
27676
29078
  var ACTIVE_TURN_RECONCILIATION_CLOSE_CODE = 4009;
29079
+ function botIpcSocketPath() {
29080
+ if (process.platform === "win32") {
29081
+ return `\\\\.\\pipe\\mobius-bot-${randomUUID6()}`;
29082
+ }
29083
+ return join16("/tmp", `mobius-bot-${randomUUID6()}.sock`);
29084
+ }
27677
29085
  var RelayConnectionRefreshState = class {
27678
29086
  };
27679
29087
  var ScheduledRelayConnectionRefreshState = class extends RelayConnectionRefreshState {
@@ -27931,7 +29339,7 @@ async function reconcileActiveTurn(config2, turn, signal) {
27931
29339
  const requestSignal = AbortSignal.any([signal, timeoutSignal]);
27932
29340
  let response;
27933
29341
  try {
27934
- response = await fetch5(activeTurnReconciliationEndpoint(config2, turn), {
29342
+ response = await fetch6(activeTurnReconciliationEndpoint(config2, turn), {
27935
29343
  body: JSON.stringify({ outcome: { kind: "running" } }),
27936
29344
  dispatcher: environmentProxyDispatcher,
27937
29345
  headers: { "content-type": "application/json" },
@@ -28034,13 +29442,13 @@ function reportFailure(publisher, command, code, message, attemptId) {
28034
29442
  );
28035
29443
  }
28036
29444
  function operationErrorCode(error61) {
28037
- if (error61 instanceof AcpExecutionError || error61 instanceof LocalAuthorizationError || error61 instanceof LocalAgentCatalogError || error61 instanceof PromptArtifactError) {
29445
+ if (error61 instanceof AcpExecutionError || error61 instanceof LocalAuthorizationError || error61 instanceof LocalAgentCatalogError || error61 instanceof LocalBotAuthorizationError || error61 instanceof PromptArtifactError) {
28038
29446
  return error61.code;
28039
29447
  }
28040
29448
  return "session_operation_failed";
28041
29449
  }
28042
29450
  function operationErrorMessage(error61) {
28043
- if (error61 instanceof AcpExecutionError || error61 instanceof LocalAuthorizationError || error61 instanceof LocalAgentCatalogError || error61 instanceof PromptArtifactError) {
29451
+ if (error61 instanceof AcpExecutionError || error61 instanceof LocalAuthorizationError || error61 instanceof LocalAgentCatalogError || error61 instanceof LocalBotAuthorizationError || error61 instanceof PromptArtifactError) {
28044
29452
  return error61.message;
28045
29453
  }
28046
29454
  return "The local agent operation could not be completed";
@@ -28305,6 +29713,175 @@ async function executePrompt(outbox, publisher, command, config2, directories, a
28305
29713
  console.error("Mobius daemon command failed", error61);
28306
29714
  }
28307
29715
  }
29716
+ function botExecutionAgent(agent, contextHandle, socketPath) {
29717
+ return new LocalAgentDefinition(
29718
+ agent.id,
29719
+ agent.label,
29720
+ agent.command,
29721
+ agent.arguments,
29722
+ {
29723
+ ...agent.environment,
29724
+ MOBIUS_BOT_CONTEXT: contextHandle,
29725
+ MOBIUS_BOT_SOCKET: socketPath,
29726
+ MOBIUS_RELAY_TOKEN: "",
29727
+ MOBIUS_RELAY_URL: ""
29728
+ },
29729
+ agent.adapterVersion,
29730
+ agent.agentVersion,
29731
+ agent.adapterIdentity,
29732
+ agent.agentIdentity,
29733
+ agent.promptTimeoutMilliseconds,
29734
+ agent.capabilities
29735
+ );
29736
+ }
29737
+ async function executeBotPrompt(outbox, publisher, command, config2, directories, audit, sessions, grants, contexts, applicator, ipc, attemptId, signal) {
29738
+ try {
29739
+ if (command.additionalDirectoryIds.length > 0) {
29740
+ throw new LocalBotAuthorizationError(
29741
+ "binding_not_approved",
29742
+ "The Bot execution requested unapproved additional directories"
29743
+ );
29744
+ }
29745
+ const deadline = Date.parse(command.executionDeadlineAt);
29746
+ const remaining = deadline - Date.now();
29747
+ if (!Number.isSafeInteger(deadline) || remaining <= 0) {
29748
+ throw new LocalBotAuthorizationError("turn_expired", "The Bot execution deadline has expired");
29749
+ }
29750
+ const grant = await grants.resolveExecution(
29751
+ command,
29752
+ config2.catalog,
29753
+ directories,
29754
+ config2.bindingId,
29755
+ Date.now(),
29756
+ signal
29757
+ );
29758
+ const attachments = await resolvePromptArtifacts(config2, command, signal);
29759
+ const applied = await applicator.apply(command, grant, attachments.resources, signal);
29760
+ const lease = contexts.activate(command);
29761
+ try {
29762
+ const deadlineSignal = AbortSignal.timeout(remaining);
29763
+ const executionSignal = AbortSignal.any([signal, deadlineSignal]);
29764
+ const agent = botExecutionAgent(grant.agent, lease.context.contextHandle, ipc.socketPath);
29765
+ audit.record({
29766
+ commandId: command.commandId,
29767
+ details: {
29768
+ behaviorRevisionId: command.behaviorRevisionId,
29769
+ bindingId: command.bindingId,
29770
+ botId: command.botId,
29771
+ executionId: command.executionId,
29772
+ localGrantId: command.localGrantId
29773
+ },
29774
+ event: "bot_session_authorized",
29775
+ sessionId: command.sessionId
29776
+ });
29777
+ outbox.transitionExecution(command.commandId, "running");
29778
+ publisher.recordAttempt(
29779
+ command.sessionId,
29780
+ encodeSessionStartedEvent({
29781
+ attemptId,
29782
+ commandId: command.commandId,
29783
+ kind: SESSION_STARTED_KIND,
29784
+ sessionId: command.sessionId
29785
+ }),
29786
+ attemptId
29787
+ );
29788
+ const result = await sessions.runPrompt({
29789
+ additionalDirectories: [],
29790
+ agent,
29791
+ commandId: command.commandId,
29792
+ cwd: grant.workspacePath,
29793
+ images: attachments.images,
29794
+ onActivity: (activity) => {
29795
+ publisher.recordAttempt(
29796
+ command.sessionId,
29797
+ encodeAgentActivityEvent({
29798
+ activityId: activity.activityId,
29799
+ activityType: activity.activityType,
29800
+ commandId: command.commandId,
29801
+ content: activity.content,
29802
+ detail: activity.detail,
29803
+ input: activity.input,
29804
+ kind: AGENT_ACTIVITY_KIND,
29805
+ locations: activity.locations,
29806
+ name: activity.name,
29807
+ output: activity.output,
29808
+ sequence: activity.sequence,
29809
+ sessionId: command.sessionId,
29810
+ status: activity.status,
29811
+ title: activity.title,
29812
+ toolKind: activity.toolKind
29813
+ }),
29814
+ attemptId
29815
+ );
29816
+ return Promise.resolve();
29817
+ },
29818
+ onText: (text) => {
29819
+ publisher.recordAttempt(
29820
+ command.sessionId,
29821
+ encodeAgentMessageDeltaEvent({
29822
+ commandId: command.commandId,
29823
+ kind: AGENT_MESSAGE_DELTA_KIND,
29824
+ sessionId: command.sessionId,
29825
+ text
29826
+ }),
29827
+ attemptId
29828
+ );
29829
+ return Promise.resolve();
29830
+ },
29831
+ prompt: command.prompt,
29832
+ resources: applied.resources,
29833
+ sessionId: command.sessionId,
29834
+ signal: executionSignal
29835
+ });
29836
+ publisher.recordAttempt(
29837
+ command.sessionId,
29838
+ encodeSessionCompletedEvent({
29839
+ commandId: command.commandId,
29840
+ kind: SESSION_COMPLETED_KIND,
29841
+ sessionId: command.sessionId,
29842
+ stopReason: result.stopReason
29843
+ }),
29844
+ attemptId
29845
+ );
29846
+ outbox.transitionExecution(
29847
+ command.commandId,
29848
+ result.stopReason === "cancelled" ? "cancelled" : "succeeded"
29849
+ );
29850
+ audit.record({
29851
+ commandId: command.commandId,
29852
+ details: { botId: command.botId, executionId: command.executionId },
29853
+ event: result.stopReason === "cancelled" ? "bot_session_cancelled" : "bot_session_completed",
29854
+ sessionId: command.sessionId
29855
+ });
29856
+ } finally {
29857
+ lease.release();
29858
+ }
29859
+ } catch (error61) {
29860
+ const failure = Date.parse(command.executionDeadlineAt) <= Date.now() ? new LocalBotAuthorizationError("turn_expired", "The Bot execution deadline has expired", {
29861
+ cause: error61
29862
+ }) : error61;
29863
+ audit.record({
29864
+ commandId: command.commandId,
29865
+ details: {
29866
+ botId: command.botId,
29867
+ code: operationErrorCode(failure),
29868
+ executionId: command.executionId
29869
+ },
29870
+ event: "bot_session_failed",
29871
+ sessionId: command.sessionId
29872
+ });
29873
+ const code = operationErrorCode(failure);
29874
+ reportFailure(
29875
+ publisher,
29876
+ command,
29877
+ code === "session_operation_failed" ? "agent_execution_failed" : code,
29878
+ code === "session_operation_failed" ? "The local agent could not complete the Bot request" : operationErrorMessage(failure),
29879
+ attemptId
29880
+ );
29881
+ outbox.transitionExecution(command.commandId, "failed");
29882
+ console.error("Mobius daemon Bot command failed", failure);
29883
+ }
29884
+ }
28308
29885
  function waitForRelayRetry(signal, timer) {
28309
29886
  if (signal.aborted) {
28310
29887
  return Promise.resolve();
@@ -28341,7 +29918,7 @@ async function publishAgentCatalogUntilAvailable(config2, signal, timer) {
28341
29918
  }
28342
29919
  }
28343
29920
  }
28344
- async function runRelayConnection(config2, directories, audit, sessions, installations, installationObserver, nativeSessions, outbox, publisher, activeTurns, activeAttemptIds, onConnected, signal, timer) {
29921
+ async function runRelayConnection(config2, directories, audit, sessions, installations, installationObserver, nativeSessions, outbox, publisher, grants, contexts, applicator, ipc, activeTurns, activeAttemptIds, onConnected, signal, timer) {
28345
29922
  const relayUrl = new URL(config2.relayUrl);
28346
29923
  relayUrl.searchParams.set("liveness", "1");
28347
29924
  const socket = await connectRelay(relayUrl, signal);
@@ -28424,6 +30001,76 @@ async function runRelayConnection(config2, directories, audit, sessions, install
28424
30001
  outbox.acknowledge(decodeSessionEventAcknowledgement(encoded));
28425
30002
  return;
28426
30003
  }
30004
+ if (kind === SESSION_EVENT_REJECTED_KIND) {
30005
+ const rejection = decodeSessionEventRejection(encoded);
30006
+ if (outbox.quarantine(rejection)) {
30007
+ audit.record({
30008
+ commandId: rejection.eventId,
30009
+ details: { code: rejection.code },
30010
+ event: "session_event_rejected",
30011
+ sessionId: rejection.sessionId
30012
+ });
30013
+ } else {
30014
+ console.warn("Mobius daemon ignored a rejection for an unknown session event");
30015
+ }
30016
+ return;
30017
+ }
30018
+ if (kind === BOT_BINDING_APPROVAL_REQUEST_KIND) {
30019
+ const request = decodeBotExecutionBindingApprovalRequest(encoded);
30020
+ void grants.approve(
30021
+ request,
30022
+ config2.catalog,
30023
+ directories,
30024
+ config2.bindingId,
30025
+ Date.now(),
30026
+ connectionController.signal
30027
+ ).then((approved) => {
30028
+ audit.record({
30029
+ commandId: request.requestId,
30030
+ details: {
30031
+ behaviorRevisionId: request.behaviorRevisionId,
30032
+ bindingId: request.bindingId,
30033
+ botId: request.botId,
30034
+ localGrantId: approved.localGrantId
30035
+ },
30036
+ event: "bot_binding_approved",
30037
+ sessionId: `bot-binding:${request.bindingId}`
30038
+ });
30039
+ if (socket.readyState === WebSocket2.OPEN) {
30040
+ send(socket, encodeBotExecutionBindingApprovedEvent(approved));
30041
+ }
30042
+ }).catch((error61) => {
30043
+ if (connectionController.signal.aborted) {
30044
+ return;
30045
+ }
30046
+ const code = error61 instanceof LocalBotAuthorizationError ? error61.code : "binding_incompatible";
30047
+ const message = error61 instanceof LocalBotAuthorizationError ? error61.message : "The local execution target is incompatible";
30048
+ grants.recordUnavailable(request, code, message, Date.now());
30049
+ audit.record({
30050
+ commandId: request.requestId,
30051
+ details: { bindingId: request.bindingId, botId: request.botId, code },
30052
+ event: "bot_binding_unavailable",
30053
+ sessionId: `bot-binding:${request.bindingId}`
30054
+ });
30055
+ if (socket.readyState === WebSocket2.OPEN) {
30056
+ send(
30057
+ socket,
30058
+ encodeBotExecutionBindingUnavailableEvent(
30059
+ new BotExecutionBindingUnavailableEvent(
30060
+ request.requestId,
30061
+ request.botId,
30062
+ request.behaviorRevisionId,
30063
+ request.bindingId,
30064
+ request.bindingRevision,
30065
+ code,
30066
+ message
30067
+ )
30068
+ )
30069
+ );
30070
+ }
30071
+ });
30072
+ return;
30073
+ }
28427
30074
  if (kind === NATIVE_SESSION_CANCEL_KIND) {
28428
30075
  const command2 = decodeNativeSessionCancel(encoded);
28429
30076
  const pending = nativeRequests.get(command2.requestId);
@@ -28622,6 +30269,44 @@ async function runRelayConnection(config2, directories, audit, sessions, install
28622
30269
  });
28623
30270
  return;
28624
30271
  }
30272
+ if (kind === BOT_SESSION_PROMPT_KIND) {
30273
+ const command2 = decodeBotSessionPromptCommand(encoded);
30274
+ if (activeTurns.has(command2.commandId)) {
30275
+ return;
30276
+ }
30277
+ const receipt2 = outbox.claimExecution(command2.commandId, command2.sessionId, encoded);
30278
+ if (receipt2.kind === "duplicate") {
30279
+ return;
30280
+ }
30281
+ const turn2 = new ActiveDaemonTurn(command2, receipt2.attemptId);
30282
+ activeTurns.set(command2.commandId, turn2);
30283
+ activeAttemptIds.set(command2.sessionId, receipt2.attemptId);
30284
+ void executeBotPrompt(
30285
+ outbox,
30286
+ publisher,
30287
+ command2,
30288
+ config2,
30289
+ directories,
30290
+ audit,
30291
+ sessions,
30292
+ grants,
30293
+ contexts,
30294
+ applicator,
30295
+ ipc,
30296
+ receipt2.attemptId,
30297
+ turn2.signal
30298
+ ).catch((error61) => {
30299
+ console.error("Mobius daemon Bot turn failed", error61);
30300
+ }).finally(() => {
30301
+ activeTurns.delete(command2.commandId);
30302
+ if (activeAttemptIds.get(command2.sessionId) === receipt2.attemptId) {
30303
+ activeAttemptIds.delete(command2.sessionId);
30304
+ }
30305
+ turn2.finish();
30306
+ connectionRefresh.afterTurnFinished();
30307
+ });
30308
+ return;
30309
+ }
28625
30310
  if (kind !== SESSION_PROMPT_KIND) {
28626
30311
  throw new Error("Unsupported protocol message");
28627
30312
  }
@@ -28712,6 +30397,10 @@ async function runDaemon(config2, audit, signal, timer = systemDaemonTimer) {
28712
30397
  const sessionStore = new SqliteAcpSessionStore(config2.auditDatabasePath);
28713
30398
  const outbox = new SessionEventOutbox(config2.auditDatabasePath);
28714
30399
  const publisher = new DaemonSessionEventPublisher(outbox);
30400
+ const grants = new LocalBotGrantStore(config2.auditDatabasePath);
30401
+ const contexts = new BotExecutionContextRegistry();
30402
+ const applicator = new EmbeddedBotContextApplicator();
30403
+ const ipc = new BotOutboundIpcServer(botIpcSocketPath(), config2.relayUrl, contexts);
28715
30404
  const activeTurns = /* @__PURE__ */ new Map();
28716
30405
  const activeAttemptIds = /* @__PURE__ */ new Map();
28717
30406
  const recordSessionEvent = (sessionId, payload) => {
@@ -28750,6 +30439,7 @@ async function runDaemon(config2, audit, signal, timer = systemDaemonTimer) {
28750
30439
  };
28751
30440
  const catalogPublication = publishAgentCatalogUntilAvailable(config2, signal, timer);
28752
30441
  try {
30442
+ await ipc.listen(signal);
28753
30443
  while (!signal.aborted) {
28754
30444
  try {
28755
30445
  await runRelayConnection(
@@ -28762,6 +30452,10 @@ async function runDaemon(config2, audit, signal, timer = systemDaemonTimer) {
28762
30452
  nativeSessions,
28763
30453
  outbox,
28764
30454
  publisher,
30455
+ grants,
30456
+ contexts,
30457
+ applicator,
30458
+ ipc,
28765
30459
  activeTurns,
28766
30460
  activeAttemptIds,
28767
30461
  announceConnection,
@@ -28793,12 +30487,20 @@ async function runDaemon(config2, audit, signal, timer = systemDaemonTimer) {
28793
30487
  await installations.close();
28794
30488
  } finally {
28795
30489
  try {
28796
- await sessions.close();
30490
+ await ipc.close();
28797
30491
  } finally {
28798
30492
  try {
28799
- sessionStore.close();
30493
+ await sessions.close();
28800
30494
  } finally {
28801
- outbox.close();
30495
+ try {
30496
+ sessionStore.close();
30497
+ } finally {
30498
+ try {
30499
+ grants.close();
30500
+ } finally {
30501
+ outbox.close();
30502
+ }
30503
+ }
28802
30504
  }
28803
30505
  }
28804
30506
  }
@@ -28808,9 +30510,13 @@ async function runDaemon(config2, audit, signal, timer = systemDaemonTimer) {
28808
30510
  export {
28809
30511
  AcpExecutionError,
28810
30512
  AuditStore,
30513
+ BotExecutionContextRegistry,
30514
+ BotMessageCommandError,
30515
+ BotOutboundIpcServer,
28811
30516
  LocalAuthorizationError,
28812
30517
  PairingClientError,
28813
30518
  createAcpClient,
30519
+ executeBotMessageCommand,
28814
30520
  loadDaemonConfig,
28815
30521
  pairLocalMachine,
28816
30522
  resumeLocalMachine,