@ouro.bot/cli 0.1.0-alpha.816 → 0.1.0-alpha.818

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 (50) hide show
  1. package/assets/sanctuary-host-launcher.sh +16 -0
  2. package/changelog.json +16 -0
  3. package/deploy/unraid/Dockerfile +6 -0
  4. package/deploy/unraid/README.txt +296 -62
  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/core.js +2 -1
  16. package/dist/heart/daemon/container-spec-auditor-main.js +8 -7
  17. package/dist/heart/daemon/container-spec-auditor.js +16 -9
  18. package/dist/heart/daemon/sanctuary-acceptance-adapter.js +95 -91
  19. package/dist/heart/daemon/sanctuary-acceptance-harness.js +95 -169
  20. package/dist/heart/daemon/sanctuary-acceptance-scenarios.js +4 -5
  21. package/dist/heart/daemon/sanctuary-authority-codec.js +86 -0
  22. package/dist/heart/daemon/sanctuary-authority-epoch.js +256 -0
  23. package/dist/heart/daemon/sanctuary-authority-installation.js +140 -0
  24. package/dist/heart/daemon/sanctuary-authority-ledger.js +241 -0
  25. package/dist/heart/daemon/sanctuary-authority-root-lifecycle.js +780 -0
  26. package/dist/heart/daemon/sanctuary-authority-vault-migration.js +79 -0
  27. package/dist/heart/daemon/sanctuary-host-authority.js +1008 -0
  28. package/dist/heart/daemon/sanctuary-host-detached-supervisor.js +494 -0
  29. package/dist/heart/daemon/sanctuary-host-executor.js +670 -0
  30. package/dist/heart/daemon/sanctuary-host-linux-kernel.js +334 -0
  31. package/dist/heart/daemon/sanctuary-host-supervisor-entry.js +207 -0
  32. package/dist/heart/daemon/sanctuary-host-supervisor.js +95 -0
  33. package/dist/heart/daemon/sanctuary-telegram-authority-entry.js +445 -0
  34. package/dist/heart/daemon/sanctuary-telegram-authority-gateway.js +585 -0
  35. package/dist/heart/daemon/sanctuary-telegram-authority-service.js +615 -0
  36. package/dist/heart/daemon/sense-manager.js +20 -10
  37. package/dist/repertoire/tools-sanctuary-host.js +202 -0
  38. package/dist/repertoire/tools.js +15 -6
  39. package/dist/senses/private-runtime.js +2 -2
  40. package/dist/senses/root-host-approval-port.js +345 -0
  41. package/dist/senses/root-host-approval-runtime.js +393 -0
  42. package/dist/senses/sanctuary-authority-resident.js +102 -0
  43. package/dist/senses/telegram-admission.js +7 -0
  44. package/dist/senses/telegram-attachments.js +5 -1
  45. package/dist/senses/telegram-authority-transport.js +231 -0
  46. package/dist/senses/telegram-client.js +31 -8
  47. package/dist/senses/telegram-entry.js +1 -1
  48. package/dist/senses/telegram.js +168 -28
  49. package/npm-shrinkwrap.json +2 -2
  50. 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;
@@ -959,6 +991,40 @@ function createTelegramSenseApp(options) {
959
991
  },
960
992
  }) : undefined);
961
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
+ }
962
1028
  interactiveControl = useSanctuaryRuntime && approvalTransport
963
1029
  ? (options._createInteractiveControl ?? sanctuary_interactive_control_1.createSanctuaryInteractiveControl)({
964
1030
  agentRoot,
@@ -1020,7 +1086,10 @@ function createTelegramSenseApp(options) {
1020
1086
  approvalReconcileTimer = setTimeout(() => {
1021
1087
  approvalReconcileTimer = undefined;
1022
1088
  scheduleApprovalReconcile();
1023
- const reconciliation = runWithAcceptanceAuditOwner(() => approvalTransport.reconcileExpired()).catch((error) => {
1089
+ const reconciliation = runWithAcceptanceAuditOwner(async () => {
1090
+ await approvalTransport.reconcileExpired();
1091
+ await rootHostRuntime?.recover();
1092
+ }).catch((error) => {
1024
1093
  acceptanceAuditBarrier();
1025
1094
  (0, runtime_1.emitNervesEvent)({
1026
1095
  level: "error",
@@ -1185,10 +1254,20 @@ function createTelegramSenseApp(options) {
1185
1254
  },
1186
1255
  validateTerminalAnswer: (answer) => contracts.map((contract) => contract.validateTerminalAnswer?.(answer)).find((rejection) => rejection !== undefined),
1187
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
+ }
1188
1267
  return {
1189
1268
  ...runAgentOptions,
1190
1269
  ...(requiredToolCalls ? { requiredToolCalls } : {}),
1191
- toolContext: { ...runAgentOptions.toolContext, relationshipAuthorization },
1270
+ toolContext: currentToolContext,
1192
1271
  };
1193
1272
  };
1194
1273
  };
@@ -1278,6 +1357,15 @@ function createTelegramSenseApp(options) {
1278
1357
  },
1279
1358
  claimFriend: options.admission.claimFriend,
1280
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
+ } : {}),
1281
1369
  commitApprovedIngress: async (input) => {
1282
1370
  const sessionKey = `telegram:${input.botId}:${input.userId}`;
1283
1371
  const reference = `telegram-admission:${input.admissionId}`;
@@ -1338,8 +1426,9 @@ function createTelegramSenseApp(options) {
1338
1426
  const ingested = await (0, telegram_attachments_1.ingestTelegramAttachments)({
1339
1427
  agentName: options.agentName,
1340
1428
  agentRoot,
1341
- botToken,
1429
+ ...(botToken ? { botToken } : {}),
1342
1430
  api,
1431
+ ...(authorityTransport ? { downloadFile: authorityTransport.downloadFile } : {}),
1343
1432
  ...(options.attachmentFetch ? { fetch: options.attachmentFetch } : {}),
1344
1433
  attachments: message.attachments ?? [],
1345
1434
  });
@@ -1459,10 +1548,11 @@ function createTelegramSenseApp(options) {
1459
1548
  chatId: message.chatId,
1460
1549
  sessionKey: currentSessionKey,
1461
1550
  userMessage: message.text,
1551
+ authority: message.authority,
1462
1552
  fullVisibilityProgress: fullVisibility.progress,
1463
1553
  }),
1464
1554
  } : {}),
1465
- ...(approvalRuntime ? { approvalCoordinatorFactory: approvalRuntime.coordinator } : {}),
1555
+ ...(approvalRuntime ? { approvalCoordinatorFactory: rootHostRuntime ? approvalCoordinatorFactory : approvalRuntime.coordinator } : {}),
1466
1556
  }), toolReceiptObserver);
1467
1557
  const result = collected.result;
1468
1558
  let responseFallbackArtifactId;
@@ -1517,9 +1607,9 @@ function createTelegramSenseApp(options) {
1517
1607
  ...lifecycleCoordinates,
1518
1608
  ...(acceptanceMarker ? {
1519
1609
  outcome: "error",
1520
- 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])),
1521
1611
  deliveryCount: deliveredMessageIds.length,
1522
- } : { error: redactTelegramPrivateValues(error, [botToken, authorizedUserId, authorizedChatId, String(message.updateId), message.messageId]) }),
1612
+ } : { error: redactTelegramPrivateValues(error, [...transportPrivateValues, String(message.updateId), message.messageId]) }),
1523
1613
  }, Math.max(Date.now(), lifecycleStartedAt + 1)),
1524
1614
  });
1525
1615
  const fallback = "I couldn't complete that turn. The failure was recorded; please try again.";
@@ -1533,7 +1623,7 @@ function createTelegramSenseApp(options) {
1533
1623
  const grounded = groundedAcceptance;
1534
1624
  const schemaVersion = grounded ? "sanctuary-telegram-turn-receipt-v4" : "sanctuary-telegram-turn-receipt-v3";
1535
1625
  const hmac = (purpose, value) => sanctuaryTelegramTurnReceiptDigest(identityKey, schemaVersion, purpose, value);
1536
- const redact = (value) => [botToken, authorizedUserId, authorizedChatId, String(message.updateId), message.messageId]
1626
+ const redact = (value) => [...transportPrivateValues, String(message.updateId), message.messageId]
1537
1627
  .reduce((text, privateValue) => privateValue.length >= 5 ? text.replaceAll(privateValue, "[REDACTED]") : text, value);
1538
1628
  const deliveries = deliveredMessageIds.map((messageId, index) => {
1539
1629
  const chunk = deliveredChunks[index];
@@ -1592,6 +1682,13 @@ function createTelegramSenseApp(options) {
1592
1682
  await admissionController.handleUnknown(message);
1593
1683
  return;
1594
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
+ });
1595
1692
  const hydrated = await hydrateAuthorizedMessage({
1596
1693
  updateId: message.updateId,
1597
1694
  messageId: String(message.messageId),
@@ -1610,6 +1707,8 @@ function createTelegramSenseApp(options) {
1610
1707
  } : undefined;
1611
1708
  const onUpdate = async (update) => {
1612
1709
  const callback = update.callback_query;
1710
+ if (callback && rootHostRuntime && await runWithAcceptanceAuditOwner(() => rootHostRuntime.handleUpdate(update)))
1711
+ return true;
1613
1712
  if (callback?.data?.startsWith("admit:") && admissionController && callback.message) {
1614
1713
  return runWithAcceptanceAuditOwner(async () => {
1615
1714
  const actor = await options.admission?.resolveOwner({ botId: botId, userId: String(callback.from.id), chatId: String(callback.message.chat.id), sessionKey: configuredOwnerSessionKey });
@@ -1643,6 +1742,10 @@ function createTelegramSenseApp(options) {
1643
1742
  inboxStore,
1644
1743
  onMessage,
1645
1744
  onUpdate,
1745
+ ...(authorityTransport ? {
1746
+ settleTransport: authorityTransport.settleTransport,
1747
+ transportMetadata: authorityTransport.metadataForUpdate,
1748
+ } : {}),
1646
1749
  acceptanceEventMeta: (update, distinctAccount) => {
1647
1750
  const marker = options.acceptanceMarker ? options.acceptanceMarker() : (0, sanctuary_acceptance_marker_1.readSanctuaryAcceptanceMarker)(options.agentName);
1648
1751
  if (!marker)
@@ -1712,6 +1815,7 @@ function createTelegramSenseApp(options) {
1712
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" } });
1713
1816
  }
1714
1817
  await runWithAcceptanceAuditOwner(async () => { await approvalRuntime?.recover(); });
1818
+ await runWithAcceptanceAuditOwner(async () => { await rootHostRuntime?.recover(); });
1715
1819
  await runWithAcceptanceAuditOwner(async () => { await interactiveControl?.start(); });
1716
1820
  try {
1717
1821
  await runWithAcceptanceAuditOwner(async () => { await approvalTransport?.reconcileExpired(); });
@@ -1813,7 +1917,7 @@ function loadTelegramSenseCredentials(agentName) {
1813
1917
  }
1814
1918
  return parseTelegramSenseCredentials(runtime.config);
1815
1919
  }
1816
- async function createProductionTelegramRelationshipComposition(agentName, credentials, agentRootOverride) {
1920
+ async function createProductionTelegramRelationshipComposition(agentName, credentials, agentRootOverride, authorityTransport) {
1817
1921
  const agentRoot = agentRootOverride ?? (0, identity_1.getAgentRoot)(agentName);
1818
1922
  const botId = canonicalTelegramId(credentials.botId ?? telegramBotIdFromToken(credentials.botToken), "bot id");
1819
1923
  const ownerUserId = canonicalTelegramId(credentials.authorizedUserId, "authorized user id");
@@ -1922,6 +2026,7 @@ async function createProductionTelegramRelationshipComposition(agentName, creden
1922
2026
  const live = await store.get(current.id);
1923
2027
  if (!live || !exactTelegramIdentity(live, bindings[0].externalId))
1924
2028
  throw new Error("Telegram contact identity changed");
2029
+ await authorityTransport?.revokeChat({ userId: bindings[0].externalId, chatId: bindings[0].externalId });
1925
2030
  const { capabilityProfileId: _removedProfile, ...withoutProfile } = live;
1926
2031
  await store.put(live.id, { ...withoutProfile, admissionState: "revoked", initiativePolicy: "none", updatedAt: new Date().toISOString() });
1927
2032
  (0, tools_awaiting_1.cancelRelationshipFollowUps)(agentRoot, agentName, { friendId: live.id, channel: "telegram", key: sessionKey });
@@ -2053,18 +2158,53 @@ async function createProductionTelegramRelationshipComposition(agentName, creden
2053
2158
  },
2054
2159
  };
2055
2160
  }
2056
- async function startTelegramSenseApp(agentName) {
2057
- const loaded = loadTelegramSenseCredentials(agentName);
2058
- const credentials = { ...loaded, botId: telegramBotIdFromToken(loaded.botToken) };
2059
- const app = createTelegramSenseApp({
2060
- agentName,
2061
- credentials,
2062
- ...(await createProductionTelegramRelationshipComposition(agentName, credentials)),
2063
- ...(agentName === "sanctuary" ? { privilegedFailsafe: {
2064
- eventRoot: (0, router_1.getExternalEventRoot)(),
2065
- verifyProtectiveState: createSabQueueProtectiveStateVerifier(),
2066
- } } : {}),
2067
- });
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
+ }
2068
2208
  (0, runtime_1.emitNervesEvent)({
2069
2209
  component: "senses",
2070
2210
  event: "senses.telegram_app_ready",
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@ouro.bot/cli",
3
- "version": "0.1.0-alpha.816",
3
+ "version": "0.1.0-alpha.818",
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.816",
9
+ "version": "0.1.0-alpha.818",
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.816",
3
+ "version": "0.1.0-alpha.818",
4
4
  "engines": {
5
5
  "node": ">=22"
6
6
  },