@ouro.bot/cli 0.1.0-alpha.815 → 0.1.0-alpha.817

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 (63) hide show
  1. package/assets/sanctuary-host-launcher.sh +16 -0
  2. package/changelog.json +18 -0
  3. package/deploy/unraid/Dockerfile +6 -0
  4. package/deploy/unraid/README.txt +305 -365
  5. package/deploy/unraid/docker-man-template-transaction.mjs +192 -7
  6. package/deploy/unraid/sanctuary-acceptance-adapter.sh +1 -1
  7. package/deploy/unraid/sanctuary-acceptance-contract.json +7 -7
  8. package/deploy/unraid/sanctuary-authority-installation.json +36 -0
  9. package/deploy/unraid/sanctuary-authority-service.sh +30 -0
  10. package/deploy/unraid/sanctuary-unit16-host-broker.mjs +62 -9
  11. package/deploy/unraid/sanctuary-unit16-run.sh +15 -15
  12. package/deploy/unraid/sanctuary.ouro/bundle-meta.json +1 -1
  13. package/deploy/unraid/sanctuary.ouro/tool-profiles.json +2 -2
  14. package/deploy/unraid/sanctuary.xml +2 -1
  15. package/dist/heart/approval-store.js +11 -1
  16. package/dist/heart/core.js +2 -1
  17. package/dist/heart/daemon/container-spec-auditor-main.js +9 -8
  18. package/dist/heart/daemon/container-spec-auditor.js +17 -24
  19. package/dist/heart/daemon/sanctuary-acceptance-adapter.js +95 -91
  20. package/dist/heart/daemon/sanctuary-acceptance-harness.js +95 -169
  21. package/dist/heart/daemon/sanctuary-acceptance-scenarios.js +4 -5
  22. package/dist/heart/daemon/sanctuary-authority-codec.js +86 -0
  23. package/dist/heart/daemon/sanctuary-authority-epoch.js +256 -0
  24. package/dist/heart/daemon/sanctuary-authority-installation.js +140 -0
  25. package/dist/heart/daemon/sanctuary-authority-ledger.js +241 -0
  26. package/dist/heart/daemon/sanctuary-authority-root-lifecycle.js +780 -0
  27. package/dist/heart/daemon/sanctuary-authority-vault-migration.js +79 -0
  28. package/dist/heart/daemon/sanctuary-host-authority.js +1008 -0
  29. package/dist/heart/daemon/sanctuary-host-detached-supervisor.js +494 -0
  30. package/dist/heart/daemon/sanctuary-host-executor.js +670 -0
  31. package/dist/heart/daemon/sanctuary-host-linux-kernel.js +334 -0
  32. package/dist/heart/daemon/sanctuary-host-supervisor-entry.js +207 -0
  33. package/dist/heart/daemon/sanctuary-host-supervisor.js +95 -0
  34. package/dist/heart/daemon/sanctuary-telegram-authority-entry.js +445 -0
  35. package/dist/heart/daemon/sanctuary-telegram-authority-gateway.js +585 -0
  36. package/dist/heart/daemon/sanctuary-telegram-authority-service.js +615 -0
  37. package/dist/heart/daemon/sense-manager.js +20 -10
  38. package/dist/heart/external-events/router.js +31 -15
  39. package/dist/heart/steward-policy.js +374 -58
  40. package/dist/heart/tool-approval.js +8 -1
  41. package/dist/repertoire/relationship-authorization.js +128 -0
  42. package/dist/repertoire/tools-base.js +9 -13
  43. package/dist/repertoire/tools-sanctuary-host.js +202 -0
  44. package/dist/repertoire/tools-steward-policy.js +34 -10
  45. package/dist/repertoire/tools-unraid.js +79 -32
  46. package/dist/repertoire/tools.js +37 -25
  47. package/dist/repertoire/unraid-restart.js +179 -52
  48. package/dist/senses/private-runtime.js +27 -12
  49. package/dist/senses/root-host-approval-port.js +345 -0
  50. package/dist/senses/root-host-approval-runtime.js +393 -0
  51. package/dist/senses/sanctuary-authority-resident.js +102 -0
  52. package/dist/senses/sanctuary-health-runner.js +0 -1
  53. package/dist/senses/sanctuary-media-catalog-contract.js +4 -1
  54. package/dist/senses/sanctuary-runtime.js +2 -0
  55. package/dist/senses/telegram-admission.js +7 -0
  56. package/dist/senses/telegram-approval-runtime.js +130 -12
  57. package/dist/senses/telegram-attachments.js +5 -1
  58. package/dist/senses/telegram-authority-transport.js +231 -0
  59. package/dist/senses/telegram-client.js +31 -8
  60. package/dist/senses/telegram-entry.js +1 -1
  61. package/dist/senses/telegram.js +174 -28
  62. package/npm-shrinkwrap.json +2 -2
  63. package/package.json +1 -1
@@ -69,6 +69,9 @@ const sanctuary_download_credit_presentation_1 = require("./sanctuary-download-c
69
69
  const shared_turn_1 = require("./shared-turn");
70
70
  const config_1 = require("../heart/config");
71
71
  const telegram_client_1 = require("./telegram-client");
72
+ const sanctuary_authority_resident_1 = require("./sanctuary-authority-resident");
73
+ const root_host_approval_runtime_1 = require("./root-host-approval-runtime");
74
+ const tools_sanctuary_host_1 = require("../repertoire/tools-sanctuary-host");
72
75
  const sanctuary_runtime_2 = require("./sanctuary-runtime");
73
76
  const sanctuary_full_visibility_contract_1 = require("./sanctuary-full-visibility-contract");
74
77
  const sanctuary_install_state_contract_1 = require("./sanctuary-install-state-contract");
@@ -671,8 +674,10 @@ function migrateTelegramSessionIdentity(agentRoot, legacyUserId, legacyChatId, s
671
674
  }
672
675
  function redactTelegramPrivateValues(error, privateValues) {
673
676
  let message = error instanceof Error ? error.message : String(error);
674
- for (const privateValue of privateValues)
675
- message = message.split(privateValue).join("[redacted]");
677
+ for (const privateValue of privateValues) {
678
+ if (privateValue)
679
+ message = message.split(privateValue).join("[redacted]");
680
+ }
676
681
  return message;
677
682
  }
678
683
  function parseTelegramSenseCredentials(value) {
@@ -683,10 +688,25 @@ function parseTelegramSenseCredentials(value) {
683
688
  };
684
689
  }
685
690
  function createTelegramSenseApp(options) {
686
- const botToken = requiredText(options.credentials.botToken, "bot token");
691
+ const authorityTransport = options.authorityTransport;
692
+ if (authorityTransport && options.agentName !== "sanctuary") {
693
+ throw new Error("Sanctuary Telegram authority transport cannot serve another agent");
694
+ }
695
+ if (authorityTransport && options.credentials.botToken !== undefined) {
696
+ throw new Error("Sanctuary Telegram authority transport forbids a resident bot token");
697
+ }
698
+ const botToken = options.credentials.botToken === undefined
699
+ ? null
700
+ : requiredText(options.credentials.botToken, "bot token");
701
+ if (!botToken && !authorityTransport) {
702
+ throw new Error("Telegram bot token is missing; Sanctuary requires an explicit gateway transport");
703
+ }
687
704
  const botId = options.credentials.botId !== undefined
688
705
  ? canonicalTelegramId(options.credentials.botId, "bot id")
689
- : options.admission ? telegramBotIdFromToken(botToken) : null;
706
+ : options.admission && botToken ? telegramBotIdFromToken(botToken) : null;
707
+ if (authorityTransport && botId === null) {
708
+ throw new Error("Sanctuary Telegram authority transport requires a pinned bot id");
709
+ }
690
710
  const authorizedUserId = canonicalTelegramId(options.credentials.authorizedUserId, "authorized user id");
691
711
  const authorizedChatId = canonicalTelegramId(options.credentials.authorizedChatId, "authorized chat id");
692
712
  const agentRoot = options._agentRoot ?? (0, identity_1.getAgentRoot)(options.agentName);
@@ -694,8 +714,9 @@ function createTelegramSenseApp(options) {
694
714
  ? readOrCreateTelegramIdentityKey(agentRoot)
695
715
  : canonicalTelegramIdentityKey(options.identityKey);
696
716
  const subject = opaqueTelegramSubject(identityKey, botId ?? botToken, authorizedUserId, authorizedChatId);
697
- const transportError = (error) => redactTelegramPrivateValues(error, [botToken, authorizedUserId, authorizedChatId]);
698
- const api = options.api ?? (0, telegram_client_1.createTelegramBotApi)({ token: botToken });
717
+ const transportPrivateValues = [botToken ?? "", authorizedUserId, authorizedChatId];
718
+ const transportError = (error) => redactTelegramPrivateValues(error, transportPrivateValues);
719
+ const api = authorityTransport?.api ?? options.api ?? (0, telegram_client_1.createTelegramBotApi)({ token: botToken });
699
720
  const offsetStore = options.offsetStore ?? new telegram_client_1.FileTelegramOffsetStore(path.join(agentRoot, "state", "senses", "telegram", "offset.json"));
700
721
  const inboxStore = options.inboxStore ?? new telegram_client_1.FileTelegramUpdateInboxStore(path.join(agentRoot, "state", "senses", "telegram", "inbox.json"));
701
722
  const admissionStore = options.admission
@@ -752,11 +773,11 @@ function createTelegramSenseApp(options) {
752
773
  if (!/^[0-9a-f]{64}$/u.test(scenarioHandleDigest))
753
774
  throw new Error("Telegram acceptance audit scenario handle is invalid");
754
775
  if (!acceptanceAuditLease) {
755
- acceptanceAuditLease = acquireTelegramAcceptanceAudit(options.acceptanceReceiptRoot ?? agentRoot, options.agentName, identityKey, [botToken, authorizedUserId, authorizedChatId], scenarioHandleDigest, options._acceptanceAuditReleaseHook, options._acceptanceAuditMaxBytes);
776
+ acceptanceAuditLease = acquireTelegramAcceptanceAudit(options.acceptanceReceiptRoot ?? agentRoot, options.agentName, identityKey, transportPrivateValues, scenarioHandleDigest, options._acceptanceAuditReleaseHook, options._acceptanceAuditMaxBytes);
756
777
  }
757
778
  else if (scenarioHandleDigest !== acceptanceAuditLease.scenarioHandleDigest) {
758
779
  retireAcceptanceAudit();
759
- acceptanceAuditLease = acquireTelegramAcceptanceAudit(options.acceptanceReceiptRoot ?? agentRoot, options.agentName, identityKey, [botToken, authorizedUserId, authorizedChatId], scenarioHandleDigest, options._acceptanceAuditReleaseHook, options._acceptanceAuditMaxBytes);
780
+ acceptanceAuditLease = acquireTelegramAcceptanceAudit(options.acceptanceReceiptRoot ?? agentRoot, options.agentName, identityKey, transportPrivateValues, scenarioHandleDigest, options._acceptanceAuditReleaseHook, options._acceptanceAuditMaxBytes);
760
781
  }
761
782
  return acceptanceAuditLease;
762
783
  };
@@ -847,6 +868,17 @@ function createTelegramSenseApp(options) {
847
868
  };
848
869
  let effectJournal;
849
870
  let approvalRuntime;
871
+ let rootHostRuntime;
872
+ const approvalCoordinatorFactory = (context) => ({
873
+ propose: (request) => {
874
+ if (request.toolCall.type === "function" && request.toolCall.function.name === "sanctuary_host_execute") {
875
+ if (!rootHostRuntime)
876
+ throw new Error("root host approval coordinator is unavailable");
877
+ return rootHostRuntime.coordinator(context).propose(request);
878
+ }
879
+ return approvalRuntime.coordinator(context).propose(request);
880
+ },
881
+ });
850
882
  const getEffectJournal = () => {
851
883
  effectJournal ??= new telegram_effect_adapter_1.FileTelegramEffectJournal(path.join(agentRoot, "state", "telegram", "effects"));
852
884
  return effectJournal;
@@ -913,6 +945,12 @@ function createTelegramSenseApp(options) {
913
945
  subject,
914
946
  identityKey,
915
947
  toolContext: toolContext ?? {},
948
+ ...(options.resolveRelationshipAuthorization ? {
949
+ resolveOwnerRelationship: (binding) => options.resolveRelationshipAuthorization({
950
+ friendId: binding.friendId, requestId: binding.requestId, sessionEventId: binding.sessionEventId, sessionKey: binding.sessionKey,
951
+ botId: botId, userId: authorizedUserId, chatId: authorizedChatId,
952
+ }),
953
+ } : {}),
916
954
  resolveLiveToolContext: async (record) => {
917
955
  const sessionPath = (0, shared_turn_1.getSenseSessionPath)(options.agentName, configuredOwnerFriendId, "telegram", configuredOwnerSessionKey, agentRoot);
918
956
  if (record.transport !== "telegram" || record.requesterId !== subject
@@ -953,6 +991,40 @@ function createTelegramSenseApp(options) {
953
991
  },
954
992
  }) : undefined);
955
993
  approvalTransport = options.approvalTransport ?? approvalRuntime?.transport;
994
+ const port = authorityTransport?.hostApproval;
995
+ if (useSanctuaryRuntime && port?.pins.expectedBotId === botId
996
+ && port.pins.expectedOwnerUserId === authorizedUserId && port.pins.expectedOwnerChatId === authorizedChatId) {
997
+ rootHostRuntime = (0, root_host_approval_runtime_1.createRootHostApprovalRuntime)({
998
+ agentRoot, port, effectBarrier: acceptanceAuditBarrier, approvalCoordinatorFactory,
999
+ resolveContext: async (binding) => {
1000
+ const sessionPath = (0, shared_turn_1.getSenseSessionPath)(options.agentName, configuredOwnerFriendId, "telegram", configuredOwnerSessionKey, agentRoot);
1001
+ if (binding.agentRoot !== agentRoot || binding.friendId !== configuredOwnerFriendId
1002
+ || binding.sessionKey !== configuredOwnerSessionKey || binding.sessionPath !== sessionPath) {
1003
+ throw new Error("root host continuation owner session changed");
1004
+ }
1005
+ const relationshipAuthorization = await resolveLiveRelationshipAuthorization({
1006
+ friendId: binding.friendId, requestId: binding.requestId, sessionEventId: binding.sessionEventId,
1007
+ sessionKey: binding.sessionKey, botId: botId, userId: authorizedUserId, chatId: authorizedChatId,
1008
+ });
1009
+ const friendStore = new friends_1.FileFriendStore(path.join(agentRoot, "friends"));
1010
+ const friend = await friendStore.get(binding.friendId);
1011
+ if (!friend)
1012
+ throw new Error("root host owner Friend is unavailable");
1013
+ return {
1014
+ ...toolContext, signin: async () => undefined, agentName: options.agentName, agentRoot,
1015
+ currentSession: { friendId: friend.id, channel: "telegram", key: binding.sessionKey, sessionPath },
1016
+ context: { friend, channel: (0, friends_1.getChannelCapabilities)("telegram") }, friendStore, relationshipAuthorization,
1017
+ rootHost: { port },
1018
+ };
1019
+ },
1020
+ deliver: async (text, approvalId) => {
1021
+ await approvalEffects.sendText({
1022
+ idempotencyKey: `root-host:${approvalId}:continuation:${(0, node_crypto_1.createHash)("sha256").update(text).digest("hex")}`,
1023
+ chatId: authorizedChatId, text, authorClass: "butler",
1024
+ });
1025
+ },
1026
+ });
1027
+ }
956
1028
  interactiveControl = useSanctuaryRuntime && approvalTransport
957
1029
  ? (options._createInteractiveControl ?? sanctuary_interactive_control_1.createSanctuaryInteractiveControl)({
958
1030
  agentRoot,
@@ -1014,7 +1086,10 @@ function createTelegramSenseApp(options) {
1014
1086
  approvalReconcileTimer = setTimeout(() => {
1015
1087
  approvalReconcileTimer = undefined;
1016
1088
  scheduleApprovalReconcile();
1017
- const reconciliation = runWithAcceptanceAuditOwner(() => approvalTransport.reconcileExpired()).catch((error) => {
1089
+ const reconciliation = runWithAcceptanceAuditOwner(async () => {
1090
+ await approvalTransport.reconcileExpired();
1091
+ await rootHostRuntime?.recover();
1092
+ }).catch((error) => {
1018
1093
  acceptanceAuditBarrier();
1019
1094
  (0, runtime_1.emitNervesEvent)({
1020
1095
  level: "error",
@@ -1179,10 +1254,20 @@ function createTelegramSenseApp(options) {
1179
1254
  },
1180
1255
  validateTerminalAnswer: (answer) => contracts.map((contract) => contract.validateTerminalAnswer?.(answer)).find((rejection) => rejection !== undefined),
1181
1256
  };
1257
+ const currentToolContext = { ...runAgentOptions.toolContext, relationshipAuthorization };
1258
+ if (isSanctuaryOwner && rootHostRuntime && input.authority && await authorityTransport.hostApproval.refresh()) {
1259
+ currentToolContext.rootHost = { port: authorityTransport.hostApproval, observation: input.authority };
1260
+ try {
1261
+ await (0, tools_sanctuary_host_1.authorizeRootHostContext)(currentToolContext);
1262
+ }
1263
+ catch {
1264
+ delete currentToolContext.rootHost;
1265
+ }
1266
+ }
1182
1267
  return {
1183
1268
  ...runAgentOptions,
1184
1269
  ...(requiredToolCalls ? { requiredToolCalls } : {}),
1185
- toolContext: { ...runAgentOptions.toolContext, relationshipAuthorization },
1270
+ toolContext: currentToolContext,
1186
1271
  };
1187
1272
  };
1188
1273
  };
@@ -1272,6 +1357,15 @@ function createTelegramSenseApp(options) {
1272
1357
  },
1273
1358
  claimFriend: options.admission.claimFriend,
1274
1359
  revokeFriend: options.admission.revokeFriend,
1360
+ ...(authorityTransport ? {
1361
+ registerCommunication: (input) => authorityTransport.admitChat({
1362
+ admissionId: input.id,
1363
+ updateId: input.updateId,
1364
+ userId: input.userId,
1365
+ chatId: input.chatId,
1366
+ }),
1367
+ revokeCommunication: (input) => authorityTransport.revokeChat(input),
1368
+ } : {}),
1275
1369
  commitApprovedIngress: async (input) => {
1276
1370
  const sessionKey = `telegram:${input.botId}:${input.userId}`;
1277
1371
  const reference = `telegram-admission:${input.admissionId}`;
@@ -1332,8 +1426,9 @@ function createTelegramSenseApp(options) {
1332
1426
  const ingested = await (0, telegram_attachments_1.ingestTelegramAttachments)({
1333
1427
  agentName: options.agentName,
1334
1428
  agentRoot,
1335
- botToken,
1429
+ ...(botToken ? { botToken } : {}),
1336
1430
  api,
1431
+ ...(authorityTransport ? { downloadFile: authorityTransport.downloadFile } : {}),
1337
1432
  ...(options.attachmentFetch ? { fetch: options.attachmentFetch } : {}),
1338
1433
  attachments: message.attachments ?? [],
1339
1434
  });
@@ -1453,10 +1548,11 @@ function createTelegramSenseApp(options) {
1453
1548
  chatId: message.chatId,
1454
1549
  sessionKey: currentSessionKey,
1455
1550
  userMessage: message.text,
1551
+ authority: message.authority,
1456
1552
  fullVisibilityProgress: fullVisibility.progress,
1457
1553
  }),
1458
1554
  } : {}),
1459
- ...(approvalRuntime ? { approvalCoordinatorFactory: approvalRuntime.coordinator } : {}),
1555
+ ...(approvalRuntime ? { approvalCoordinatorFactory: rootHostRuntime ? approvalCoordinatorFactory : approvalRuntime.coordinator } : {}),
1460
1556
  }), toolReceiptObserver);
1461
1557
  const result = collected.result;
1462
1558
  let responseFallbackArtifactId;
@@ -1511,9 +1607,9 @@ function createTelegramSenseApp(options) {
1511
1607
  ...lifecycleCoordinates,
1512
1608
  ...(acceptanceMarker ? {
1513
1609
  outcome: "error",
1514
- errorDigest: auditDigest("error", redactTelegramPrivateValues(error, [botToken, authorizedUserId, authorizedChatId, String(message.updateId), message.messageId])),
1610
+ errorDigest: auditDigest("error", redactTelegramPrivateValues(error, [...transportPrivateValues, String(message.updateId), message.messageId])),
1515
1611
  deliveryCount: deliveredMessageIds.length,
1516
- } : { error: redactTelegramPrivateValues(error, [botToken, authorizedUserId, authorizedChatId, String(message.updateId), message.messageId]) }),
1612
+ } : { error: redactTelegramPrivateValues(error, [...transportPrivateValues, String(message.updateId), message.messageId]) }),
1517
1613
  }, Math.max(Date.now(), lifecycleStartedAt + 1)),
1518
1614
  });
1519
1615
  const fallback = "I couldn't complete that turn. The failure was recorded; please try again.";
@@ -1527,7 +1623,7 @@ function createTelegramSenseApp(options) {
1527
1623
  const grounded = groundedAcceptance;
1528
1624
  const schemaVersion = grounded ? "sanctuary-telegram-turn-receipt-v4" : "sanctuary-telegram-turn-receipt-v3";
1529
1625
  const hmac = (purpose, value) => sanctuaryTelegramTurnReceiptDigest(identityKey, schemaVersion, purpose, value);
1530
- const redact = (value) => [botToken, authorizedUserId, authorizedChatId, String(message.updateId), message.messageId]
1626
+ const redact = (value) => [...transportPrivateValues, String(message.updateId), message.messageId]
1531
1627
  .reduce((text, privateValue) => privateValue.length >= 5 ? text.replaceAll(privateValue, "[REDACTED]") : text, value);
1532
1628
  const deliveries = deliveredMessageIds.map((messageId, index) => {
1533
1629
  const chunk = deliveredChunks[index];
@@ -1586,6 +1682,13 @@ function createTelegramSenseApp(options) {
1586
1682
  await admissionController.handleUnknown(message);
1587
1683
  return;
1588
1684
  }
1685
+ // Existing household Friends need a root-observed communication binding after gateway migration.
1686
+ await authorityTransport?.admitChat({
1687
+ admissionId: (0, node_crypto_1.createHash)("sha256").update(`telegram-communication-v1\0${message.botId}\0${message.userId}\0${message.chatId}`).digest("hex").slice(0, 20),
1688
+ updateId: message.updateId,
1689
+ userId: message.userId,
1690
+ chatId: message.chatId,
1691
+ });
1589
1692
  const hydrated = await hydrateAuthorizedMessage({
1590
1693
  updateId: message.updateId,
1591
1694
  messageId: String(message.messageId),
@@ -1604,6 +1707,8 @@ function createTelegramSenseApp(options) {
1604
1707
  } : undefined;
1605
1708
  const onUpdate = async (update) => {
1606
1709
  const callback = update.callback_query;
1710
+ if (callback && rootHostRuntime && await runWithAcceptanceAuditOwner(() => rootHostRuntime.handleUpdate(update)))
1711
+ return true;
1607
1712
  if (callback?.data?.startsWith("admit:") && admissionController && callback.message) {
1608
1713
  return runWithAcceptanceAuditOwner(async () => {
1609
1714
  const actor = await options.admission?.resolveOwner({ botId: botId, userId: String(callback.from.id), chatId: String(callback.message.chat.id), sessionKey: configuredOwnerSessionKey });
@@ -1637,6 +1742,10 @@ function createTelegramSenseApp(options) {
1637
1742
  inboxStore,
1638
1743
  onMessage,
1639
1744
  onUpdate,
1745
+ ...(authorityTransport ? {
1746
+ settleTransport: authorityTransport.settleTransport,
1747
+ transportMetadata: authorityTransport.metadataForUpdate,
1748
+ } : {}),
1640
1749
  acceptanceEventMeta: (update, distinctAccount) => {
1641
1750
  const marker = options.acceptanceMarker ? options.acceptanceMarker() : (0, sanctuary_acceptance_marker_1.readSanctuaryAcceptanceMarker)(options.agentName);
1642
1751
  if (!marker)
@@ -1706,6 +1815,7 @@ function createTelegramSenseApp(options) {
1706
1815
  (0, runtime_1.emitNervesEvent)({ level: "error", component: "senses", event: "senses.sanctuary_routine_recovery_error", message: "Sanctuary routine action recovery requires inspection", meta: { agentName: options.agentName, subject, category: error instanceof Error ? error.name : "unknown" } });
1707
1816
  }
1708
1817
  await runWithAcceptanceAuditOwner(async () => { await approvalRuntime?.recover(); });
1818
+ await runWithAcceptanceAuditOwner(async () => { await rootHostRuntime?.recover(); });
1709
1819
  await runWithAcceptanceAuditOwner(async () => { await interactiveControl?.start(); });
1710
1820
  try {
1711
1821
  await runWithAcceptanceAuditOwner(async () => { await approvalTransport?.reconcileExpired(); });
@@ -1807,7 +1917,7 @@ function loadTelegramSenseCredentials(agentName) {
1807
1917
  }
1808
1918
  return parseTelegramSenseCredentials(runtime.config);
1809
1919
  }
1810
- async function createProductionTelegramRelationshipComposition(agentName, credentials, agentRootOverride) {
1920
+ async function createProductionTelegramRelationshipComposition(agentName, credentials, agentRootOverride, authorityTransport) {
1811
1921
  const agentRoot = agentRootOverride ?? (0, identity_1.getAgentRoot)(agentName);
1812
1922
  const botId = canonicalTelegramId(credentials.botId ?? telegramBotIdFromToken(credentials.botToken), "bot id");
1813
1923
  const ownerUserId = canonicalTelegramId(credentials.authorizedUserId, "authorized user id");
@@ -1916,6 +2026,7 @@ async function createProductionTelegramRelationshipComposition(agentName, creden
1916
2026
  const live = await store.get(current.id);
1917
2027
  if (!live || !exactTelegramIdentity(live, bindings[0].externalId))
1918
2028
  throw new Error("Telegram contact identity changed");
2029
+ await authorityTransport?.revokeChat({ userId: bindings[0].externalId, chatId: bindings[0].externalId });
1919
2030
  const { capabilityProfileId: _removedProfile, ...withoutProfile } = live;
1920
2031
  await store.put(live.id, { ...withoutProfile, admissionState: "revoked", initiativePolicy: "none", updatedAt: new Date().toISOString() });
1921
2032
  (0, tools_awaiting_1.cancelRelationshipFollowUps)(agentRoot, agentName, { friendId: live.id, channel: "telegram", key: sessionKey });
@@ -2047,18 +2158,53 @@ async function createProductionTelegramRelationshipComposition(agentName, creden
2047
2158
  },
2048
2159
  };
2049
2160
  }
2050
- async function startTelegramSenseApp(agentName) {
2051
- const loaded = loadTelegramSenseCredentials(agentName);
2052
- const credentials = { ...loaded, botId: telegramBotIdFromToken(loaded.botToken) };
2053
- const app = createTelegramSenseApp({
2054
- agentName,
2055
- credentials,
2056
- ...(await createProductionTelegramRelationshipComposition(agentName, credentials)),
2057
- ...(agentName === "sanctuary" ? { privilegedFailsafe: {
2058
- eventRoot: (0, router_1.getExternalEventRoot)(),
2059
- verifyProtectiveState: createSabQueueProtectiveStateVerifier(),
2060
- } } : {}),
2061
- });
2161
+ async function startTelegramSenseApp(agentName, waitForAuthority = false) {
2162
+ let authorityTransport;
2163
+ let credentials;
2164
+ if (agentName === "sanctuary") {
2165
+ const runtime = (0, runtime_credentials_1.readRuntimeCredentialConfig)(agentName);
2166
+ const machine = (0, runtime_credentials_1.readMachineRuntimeCredentialConfig)(agentName);
2167
+ if (!runtime.ok || !machine.ok)
2168
+ throw new Error("Sanctuary Telegram credential inventory is unavailable; migration readback is required");
2169
+ let waiting = false;
2170
+ for (;;) {
2171
+ try {
2172
+ ;
2173
+ ({ credentials, authorityTransport } = (0, sanctuary_authority_resident_1.openSanctuaryResidentAuthority)(runtime.config, machine.config));
2174
+ break;
2175
+ }
2176
+ catch (error) {
2177
+ if (!waitForAuthority || error?.code !== "ENOENT")
2178
+ throw error;
2179
+ if (!waiting) {
2180
+ waiting = true;
2181
+ (0, runtime_1.emitNervesEvent)({ level: "warn", component: "senses", event: "senses.sanctuary_gateway_waiting", message: "Telegram is unavailable while root gateway pins are not yet published", meta: { agentName } });
2182
+ }
2183
+ await new Promise((resolve) => setTimeout(resolve, 1000));
2184
+ }
2185
+ }
2186
+ }
2187
+ else {
2188
+ const loaded = loadTelegramSenseCredentials(agentName);
2189
+ credentials = { ...loaded, botId: telegramBotIdFromToken(loaded.botToken) };
2190
+ }
2191
+ let app;
2192
+ try {
2193
+ app = createTelegramSenseApp({
2194
+ agentName,
2195
+ credentials,
2196
+ authorityTransport,
2197
+ ...(await createProductionTelegramRelationshipComposition(agentName, credentials, undefined, authorityTransport)),
2198
+ ...(agentName === "sanctuary" ? { privilegedFailsafe: {
2199
+ eventRoot: (0, router_1.getExternalEventRoot)(),
2200
+ verifyProtectiveState: createSabQueueProtectiveStateVerifier(),
2201
+ } } : {}),
2202
+ });
2203
+ }
2204
+ catch (error) {
2205
+ authorityTransport?.api.stop();
2206
+ throw error;
2207
+ }
2062
2208
  (0, runtime_1.emitNervesEvent)({
2063
2209
  component: "senses",
2064
2210
  event: "senses.telegram_app_ready",
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@ouro.bot/cli",
3
- "version": "0.1.0-alpha.815",
3
+ "version": "0.1.0-alpha.817",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@ouro.bot/cli",
9
- "version": "0.1.0-alpha.815",
9
+ "version": "0.1.0-alpha.817",
10
10
  "dependencies": {
11
11
  "@anthropic-ai/sdk": "^0.78.0",
12
12
  "@azure/identity": "^4.13.0",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ouro.bot/cli",
3
- "version": "0.1.0-alpha.815",
3
+ "version": "0.1.0-alpha.817",
4
4
  "engines": {
5
5
  "node": ">=22"
6
6
  },