appback-remoteagent 0.14.0 → 0.14.2

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/.env.example CHANGED
@@ -7,6 +7,7 @@ TELEGRAM_EMPTY_RESPONSE_RETRIES=1
7
7
  TELEGRAM_RETRYABLE_ERROR_RETRIES=2
8
8
  TELEGRAM_RETRYABLE_ERROR_DELAY_MS=5000
9
9
  TELEGRAM_UNTAGGED_INTENT_RETRIES=2
10
+ TELEGRAM_POLLING_MAX_CONCURRENCY=8
10
11
  TELEGRAM_SCHEDULER_TICK_MS=1000
11
12
  TELEGRAM_TIERED_POLLING_MIN_BOTS=5
12
13
  TELEGRAM_ACTIVE_POLL_INTERVAL_MS=3000
package/dist/config.js CHANGED
@@ -133,7 +133,7 @@ export const config = {
133
133
  telegramCommandMenuEnabled: readBoolean("TELEGRAM_COMMAND_MENU_ENABLED", true),
134
134
  telegramPollingBackoffMinMs: readTimeout("TELEGRAM_POLLING_BACKOFF_MIN_MS", 60_000),
135
135
  telegramPollingBackoffMaxMs: readTimeout("TELEGRAM_POLLING_BACKOFF_MAX_MS", 900_000),
136
- telegramPollingMaxConcurrency: readTimeout("TELEGRAM_POLLING_MAX_CONCURRENCY", 3),
136
+ telegramPollingMaxConcurrency: readTimeout("TELEGRAM_POLLING_MAX_CONCURRENCY", 8),
137
137
  telegramSchedulerTickMs: readTimeout("TELEGRAM_SCHEDULER_TICK_MS", 1000),
138
138
  telegramTieredPollingMinBots: readTimeout("TELEGRAM_TIERED_POLLING_MIN_BOTS", 5),
139
139
  telegramActivePollIntervalMs: readTimeout("TELEGRAM_ACTIVE_POLL_INTERVAL_MS", 3000),
package/dist/index.js CHANGED
@@ -161,28 +161,35 @@ async function startManualPollingScheduler(bots) {
161
161
  let activePolls = [...runtimeStates.values()].filter((state) => state.inFlight).length;
162
162
  const pollingStates = await botPollingState.list();
163
163
  const rankByBotId = computeRecentMessageRanks(botIds, pollingStates);
164
- for (const bot of pollingBots) {
165
- if (activePolls >= config.telegramPollingMaxConcurrency) {
166
- break;
167
- }
164
+ const dueBots = pollingBots
165
+ .map((bot) => {
168
166
  const botId = String(bot.botInfo.id);
169
167
  const runtime = runtimeStates.get(botId);
170
- if (!runtime || runtime.inFlight) {
171
- continue;
172
- }
173
- const state = await botPollingState.get(botId, bot.botInfo.username);
174
- const nextPollAt = state.nextPollAt ? Date.parse(state.nextPollAt) : 0;
175
- if (Number.isFinite(nextPollAt) && nextPollAt > now) {
176
- continue;
168
+ const state = pollingStates[botId];
169
+ const nextPollAt = state?.nextPollAt ? Date.parse(state.nextPollAt) : 0;
170
+ return {
171
+ bot,
172
+ botId,
173
+ runtime,
174
+ state,
175
+ rank: rankByBotId.get(botId) ?? pollingBots.length,
176
+ nextPollAt: Number.isFinite(nextPollAt) ? nextPollAt : 0,
177
+ };
178
+ })
179
+ .filter((entry) => entry.runtime && !entry.runtime.inFlight && entry.nextPollAt <= now)
180
+ .sort((left, right) => left.nextPollAt - right.nextPollAt || left.rank - right.rank);
181
+ for (const entry of dueBots) {
182
+ if (activePolls >= config.telegramPollingMaxConcurrency) {
183
+ break;
177
184
  }
178
- runtime.inFlight = true;
185
+ entry.runtime.inFlight = true;
179
186
  activePolls += 1;
180
- void pollTelegramBot(bot, runtime, {
187
+ void pollTelegramBot(entry.bot, entry.runtime, {
181
188
  totalBots: pollingBots.length,
182
- botRank: rankByBotId.get(botId) ?? pollingBots.length,
183
- state,
189
+ botRank: entry.rank,
190
+ state: entry.state,
184
191
  }).finally(() => {
185
- runtime.inFlight = false;
192
+ entry.runtime.inFlight = false;
186
193
  });
187
194
  }
188
195
  await sleep(config.telegramSchedulerTickMs);
@@ -2,10 +2,7 @@ export function computeRecentMessageRanks(botIds, states) {
2
2
  const ranked = botIds
3
3
  .map((botId) => ({
4
4
  botId,
5
- timestamp: parseStateTime(states[botId]?.lastMessageAt)
6
- ?? parseStateTime(states[botId]?.lastUpdateAt)
7
- ?? parseStateTime(states[botId]?.lastPollAt)
8
- ?? 0,
5
+ timestamp: parseStateTime(states[botId]?.lastMessageAt) ?? 0,
9
6
  }))
10
7
  .sort((left, right) => right.timestamp - left.timestamp);
11
8
  return new Map(ranked.map((entry, index) => [entry.botId, index + 1]));
@@ -30,3 +30,4 @@ RemoteAgent no longer uses deep sleep, wake, or a special main bot for polling c
30
30
  - `/bot doctor` removes bots that Telegram reports as permanently dead.
31
31
  - `/bot remove <username|id>` removes a configured bot from the runtime.
32
32
  - Polling state is stored by Telegram bot id, not by display order.
33
+ - The default polling concurrency is 8 because Telegram long polling can hold each request for up to 30 seconds. Lower values can make later bots look unresponsive when many bots are configured.
package/docs/RELEASING.md CHANGED
@@ -28,7 +28,7 @@ A release is only considered complete when all of the following are done in orde
28
28
  4. Run `npm run build`
29
29
  5. Commit the completed work
30
30
  6. Push `main` to `origin/main`
31
- 7. Publish `appback-remoteagent@<version>` to npm
31
+ 7. Publish `appback-remoteagent@<version>` to npm from server 30's npm credentials
32
32
  8. Install that exact npm version on server 30 and server 26
33
33
  9. Restart `remoteagent.service` on each target if runtime code changed
34
34
  10. Verify the relevant runtime path, logs, or Telegram behavior on each target
@@ -64,18 +64,65 @@ git status
64
64
  git add -A
65
65
  git commit -m "Release 0.12.3"
66
66
  git push origin main
67
- npm publish
67
+ npm pack
68
68
  ```
69
69
 
70
- Typical target deployment sequence for server 30 and server 26:
70
+ ## npm publish procedure
71
+
72
+ Use this package-specific path for `appback-remoteagent`.
73
+
74
+ Do not publish this package from machine 21 with the `21token`. That token is scoped for `@appbackhub` packages and cannot publish the unscoped `appback-remoteagent` package. It can authenticate but `npm publish` fails with:
75
+
76
+ ```text
77
+ 403 Forbidden - You may not perform that action with these credentials.
78
+ ```
79
+
80
+ The successful publish path is:
71
81
 
72
82
  ```bash
73
- VERSION=0.13.0
83
+ VERSION=0.14.0
84
+ npm pack
85
+ scp appback-remoteagent-$VERSION.tgz au2223@192.168.0.30:/tmp/appback-remoteagent-$VERSION.tgz
86
+ ssh au2223@192.168.0.30 "bash -lc 'npm publish /tmp/appback-remoteagent-$VERSION.tgz'"
87
+ npm view appback-remoteagent version
88
+ ssh au2223@192.168.0.30 'bash -lc "npm view appback-remoteagent version"'
89
+ rm -f appback-remoteagent-$VERSION.tgz
90
+ ssh au2223@192.168.0.30 "rm -f /tmp/appback-remoteagent-$VERSION.tgz"
91
+ ```
92
+
93
+ If registry caching briefly returns the previous version after publish, wait a few seconds and rerun `npm view appback-remoteagent version` before installing to servers.
94
+
95
+ ## Target deployment sequence
96
+
97
+ Server 30 uses a systemd service:
98
+
99
+ ```bash
100
+ VERSION=0.14.0
101
+ ssh au2223@192.168.0.30 "VERSION=$VERSION bash -s" <<'REMOTE'
102
+ set -euo pipefail
103
+ sudo -n env "PATH=$PATH" npm install -g appback-remoteagent@$VERSION
104
+ /home/au2223/.nvm/versions/node/v22.22.0/bin/remoteagent-install
105
+ sudo -n systemctl restart remoteagent
106
+ systemctl is-active remoteagent
107
+ journalctl -u remoteagent --since '2 minutes ago' --no-pager
108
+ REMOTE
109
+ ```
110
+
111
+ Server 26 currently uses user-level start/stop scripts, not a systemd `remoteagent.service`:
112
+
113
+ ```bash
114
+ VERSION=0.14.0
115
+ ssh ospadmin@192.168.0.26 "VERSION=$VERSION bash -s" <<'REMOTE'
116
+ set -euo pipefail
74
117
  npm install -g appback-remoteagent@$VERSION
75
118
  remoteagent-install
76
- sudo systemctl restart remoteagent
77
- systemctl is-active remoteagent
78
- journalctl -u remoteagent --since "2 minutes ago" --no-pager
119
+ ~/.remoteagent/stop-remoteagent.sh || true
120
+ sleep 2
121
+ ~/.remoteagent/start-remoteagent.sh
122
+ sleep 3
123
+ pgrep -af "appback-remoteagent/dist/index.js"
124
+ tail -80 ~/.remoteagent/logs/agent.log
125
+ REMOTE
79
126
  ```
80
127
 
81
128
  ## Other Runtime Follow-up
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "appback-remoteagent",
3
- "version": "0.14.0",
3
+ "version": "0.14.2",
4
4
  "description": "Personal installable session server for continuing local AI work across PC and Telegram",
5
5
  "license": "MIT",
6
6
  "type": "module",