fix(telegram): apply bot token to the real alias + in-container reload path
Verified against a live board: the open workshop board accepts a remote config write but refuses a remote /admin/reload (only loopback is allowed, and the gateway runs inside a container so even host→localhost is non-loopback). And the board's telegram channel is provisioned under alias `default`, not `main`. - bridge configureTelegram: write channels.telegram.default.bot_token (was .main), and make the remote /admin/reload best-effort — never fail on its rejection; the board applies the reload itself. Companion change in zeroclaw firmware (main.py reload_watcher): the in-container supervisor polls /api/config/reload-status and triggers the loopback /admin/reload when a change is pending. Proven E2E on the live board — remote PUT → pending_reload → watcher reload within ~3s, channel back up. Co-Authored-By: Claude Opus 4.8 <[email protected]>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
59aa2365c2
commit
a4d06ebddb
+20
-14
@@ -140,17 +140,18 @@ export async function promptAndWait(node: NodeRef, message: string, agent = 'def
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the team's Telegram bot token on their node and restart it so the channel
|
* Set the team's Telegram bot token on their node so the channel picks it up.
|
||||||
* comes up. Two calls against the board's ZeroClaw gateway (bearer = the node's
|
* Writes `channels.telegram.default.bot_token` via PUT /api/config/prop — the
|
||||||
* server-side token):
|
* gateway auto-creates the alias if absent (`ensure_map_key_for_path`) and
|
||||||
* 1. PUT /api/config/prop — writes `channels.telegram.main.bot_token`. The
|
* enc2-encrypts the secret on disk. That write also flips the node's
|
||||||
* gateway auto-creates the `main` alias (`ensure_map_key_for_path`) and
|
* `pending_reload` flag.
|
||||||
* enc2-encrypts the secret on disk.
|
*
|
||||||
* 2. POST /admin/reload — in-place daemon reload; re-instantiates every
|
* The reload that actually starts the channel is done ON the board, not here:
|
||||||
* subsystem (channels included) from fresh config, so the newly-added
|
* the gateway runs inside a container, so a remote POST /admin/reload is refused
|
||||||
* Telegram channel starts. Same PID, sub-second downtime.
|
* (only loopback is allowed on an open board). The node's in-container watcher
|
||||||
* Remote /admin/reload requires the board to have `gateway.allow_remote_admin`
|
* (`reload_watcher` in the App-Lab app) sees `pending_reload` and triggers the
|
||||||
* enabled (+ pairing); on an open board it 403s — surfaced as a thrown error.
|
* loopback reload within a few seconds. We still fire a best-effort remote
|
||||||
|
* reload for paired boards that permit it, but never fail on its rejection.
|
||||||
*/
|
*/
|
||||||
export async function configureTelegram(node: NodeRef, token: string): Promise<void> {
|
export async function configureTelegram(node: NodeRef, token: string): Promise<void> {
|
||||||
const auth = { authorization: `Bearer ${node.token}` }
|
const auth = { authorization: `Bearer ${node.token}` }
|
||||||
@@ -158,14 +159,19 @@ export async function configureTelegram(node: NodeRef, token: string): Promise<v
|
|||||||
method: 'PUT',
|
method: 'PUT',
|
||||||
headers: { ...auth, 'content-type': 'application/json' },
|
headers: { ...auth, 'content-type': 'application/json' },
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
path: 'channels.telegram.main.bot_token',
|
path: 'channels.telegram.default.bot_token',
|
||||||
value: token,
|
value: token,
|
||||||
comment: 'set via APESS onboarding',
|
comment: 'set via APESS onboarding',
|
||||||
}),
|
}),
|
||||||
})
|
})
|
||||||
if (!put.ok) throw new Error(`config write failed (${put.status})`)
|
if (!put.ok) throw new Error(`config write failed (${put.status})`)
|
||||||
const reload = await fetch(`${node.url}/admin/reload`, { method: 'POST', headers: auth })
|
// Best-effort: instant reload on boards that allow remote admin; the board's
|
||||||
if (!reload.ok) throw new Error(`node reload failed (${reload.status})`)
|
// own watcher applies it otherwise. Never throw on a refused remote reload.
|
||||||
|
try {
|
||||||
|
await fetch(`${node.url}/admin/reload`, { method: 'POST', headers: auth })
|
||||||
|
} catch {
|
||||||
|
/* watcher will apply it */
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SubscribeOptions {
|
export interface SubscribeOptions {
|
||||||
|
|||||||
Reference in New Issue
Block a user