@ouro.bot/cli 0.1.0-alpha.831 → 0.1.0-alpha.832

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.
package/changelog.json CHANGED
@@ -1,6 +1,12 @@
1
1
  {
2
2
  "_note": "This changelog is maintained as part of the PR/version-bump workflow. Agent-curated, not auto-generated. Agents read this file directly via read_file to understand what changed between versions.",
3
3
  "versions": [
4
+ {
5
+ "version": "0.1.0-alpha.832",
6
+ "changes": [
7
+ "Sanctuary authority gateway: a getUpdates 409 conflict (and transient 5xx) after a gateway restart is retried internally until the previous Telegram long-poll session expires, so the tokenless resident never sees the reclaim window."
8
+ ]
9
+ },
4
10
  {
5
11
  "version": "0.1.0-alpha.831",
6
12
  "changes": [
@@ -1,5 +1,5 @@
1
1
  {
2
- "runtimeVersion": "0.1.0-alpha.831",
2
+ "runtimeVersion": "0.1.0-alpha.832",
3
3
  "bundleSchemaVersion": 3,
4
4
  "lastUpdated": "2026-09-03T00:00:00.000Z"
5
5
  }
@@ -1,7 +1,7 @@
1
1
  <?xml version="1.0"?>
2
2
  <Container version="2">
3
3
  <Name>ouro-butler</Name>
4
- <Repository>ghcr.io/ourostack/ouroboros-butler:0.1.0-alpha.831</Repository>
4
+ <Repository>ghcr.io/ourostack/ouroboros-butler:0.1.0-alpha.832</Repository>
5
5
  <Registry>https://github.com/ourostack/ouroboros/pkgs/container/ouroboros-butler</Registry>
6
6
  <Network>host</Network>
7
7
  <Shell>sh</Shell>
@@ -38,6 +38,7 @@ exports.createSanctuaryTelegramAuthorityServer = createSanctuaryTelegramAuthorit
38
38
  const fs = __importStar(require("node:fs"));
39
39
  const net = __importStar(require("node:net"));
40
40
  const path = __importStar(require("node:path"));
41
+ const telegram_client_1 = require("../../senses/telegram-client");
41
42
  const telegram_effect_adapter_1 = require("../../senses/telegram-effect-adapter");
42
43
  const frontend_socket_client_1 = require("../frontend-socket-client");
43
44
  const sanctuary_authority_codec_1 = require("./sanctuary-authority-codec");
@@ -68,8 +69,17 @@ function exactBody(value, required, optional = []) {
68
69
  function boundedText(value, maxLength) {
69
70
  return typeof value === "string" && value.length > 0 && value.length <= maxLength;
70
71
  }
72
+ // After a gateway restart, Telegram keeps the previous getUpdates long-poll
73
+ // alive server-side and answers 409 Conflict to the new poller until that
74
+ // session expires (about the previous poll's timeout). Retry through that
75
+ // window so the tokenless resident never sees the reclaim error; a transient
76
+ // 5xx from Telegram is retried the same way.
77
+ const AUTHORITY_POLL_RECLAIM_ATTEMPTS = 20;
78
+ const AUTHORITY_POLL_RECLAIM_DELAY_MS = 4_000;
71
79
  class SanctuaryTelegramAuthorityService {
72
80
  #api;
81
+ #pollReclaimAttempts;
82
+ #pollReclaimDelayMs;
73
83
  #gateway;
74
84
  #downloadFile;
75
85
  #hostAuthority;
@@ -86,10 +96,37 @@ class SanctuaryTelegramAuthorityService {
86
96
  this.#hostAuthority = options.hostAuthority;
87
97
  this.#hostExecutor = options.hostExecutor;
88
98
  this.#downloadFile = options.downloadFile;
99
+ this.#pollReclaimAttempts = options.pollReclaimAttempts ?? AUTHORITY_POLL_RECLAIM_ATTEMPTS;
100
+ this.#pollReclaimDelayMs = options.pollReclaimDelayMs ?? AUTHORITY_POLL_RECLAIM_DELAY_MS;
89
101
  }
90
102
  async drainHostExecutions() {
91
103
  await Promise.allSettled(this.#hostExecutions.values());
92
104
  }
105
+ async #pollUpdates() {
106
+ for (let attempt = 1;; attempt += 1) {
107
+ try {
108
+ return await this.#api.request("getUpdates", {
109
+ offset: this.#gateway.cursor(),
110
+ timeout: 50,
111
+ allowed_updates: ["message", "callback_query"],
112
+ });
113
+ }
114
+ catch (error) {
115
+ const status = error instanceof telegram_client_1.TelegramApiError ? error.status : null;
116
+ const reclaimable = status === 409 || (status !== null && status >= 500);
117
+ if (!reclaimable || attempt >= this.#pollReclaimAttempts)
118
+ throw error;
119
+ (0, runtime_1.emitNervesEvent)({
120
+ level: "warn",
121
+ component: "daemon",
122
+ event: "daemon.sanctuary_authority_poll_reclaim",
123
+ message: "getUpdates conflicted while reclaiming the Telegram session; retrying",
124
+ meta: { status, attempt },
125
+ });
126
+ await new Promise((resolve) => setTimeout(resolve, this.#pollReclaimDelayMs));
127
+ }
128
+ }
129
+ }
93
130
  #hostReady() {
94
131
  return this.#hostExecutor !== undefined && (this.#hostExecutor.isHealthy?.() ?? true);
95
132
  }
@@ -103,11 +140,7 @@ class SanctuaryTelegramAuthorityService {
103
140
  if (method === "telegram.poll") {
104
141
  if (!emptyParams(params))
105
142
  throw new Error("Sanctuary Telegram poll params are invalid");
106
- const updates = await this.#api.request("getUpdates", {
107
- offset: this.#gateway.cursor(),
108
- timeout: 50,
109
- allowed_updates: ["message", "callback_query"],
110
- });
143
+ const updates = await this.#pollUpdates();
111
144
  if (!Array.isArray(updates))
112
145
  throw new Error("Sanctuary Telegram poll result must be an array");
113
146
  this.#gateway.capture(updates);
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@ouro.bot/cli",
3
- "version": "0.1.0-alpha.831",
3
+ "version": "0.1.0-alpha.832",
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.831",
9
+ "version": "0.1.0-alpha.832",
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.831",
3
+ "version": "0.1.0-alpha.832",
4
4
  "engines": {
5
5
  "node": ">=22"
6
6
  },