@a1hvdy/cc-openclaw 0.24.0 → 0.25.0
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/dist/src/channels/telegram-mirror/burst-accumulator.d.ts +96 -0
- package/dist/src/channels/telegram-mirror/burst-accumulator.js +130 -0
- package/dist/src/channels/telegram-mirror/burst-accumulator.js.map +1 -0
- package/dist/src/channels/telegram-mirror/callback-mapping.d.ts +61 -0
- package/dist/src/channels/telegram-mirror/callback-mapping.js +99 -0
- package/dist/src/channels/telegram-mirror/callback-mapping.js.map +1 -0
- package/dist/src/channels/telegram-mirror/card-renderer.d.ts +74 -0
- package/dist/src/channels/telegram-mirror/card-renderer.js +131 -0
- package/dist/src/channels/telegram-mirror/card-renderer.js.map +1 -0
- package/dist/src/channels/telegram-mirror/commands.d.ts +142 -0
- package/dist/src/channels/telegram-mirror/commands.js +389 -0
- package/dist/src/channels/telegram-mirror/commands.js.map +1 -0
- package/dist/src/channels/telegram-mirror/compose-buffer.d.ts +71 -0
- package/dist/src/channels/telegram-mirror/compose-buffer.js +110 -0
- package/dist/src/channels/telegram-mirror/compose-buffer.js.map +1 -0
- package/dist/src/channels/telegram-mirror/cost-views.d.ts +58 -0
- package/dist/src/channels/telegram-mirror/cost-views.js +121 -0
- package/dist/src/channels/telegram-mirror/cost-views.js.map +1 -0
- package/dist/src/channels/telegram-mirror/failure/callback-data-overflow.d.ts +21 -0
- package/dist/src/channels/telegram-mirror/failure/callback-data-overflow.js +30 -0
- package/dist/src/channels/telegram-mirror/failure/callback-data-overflow.js.map +1 -0
- package/dist/src/channels/telegram-mirror/failure/gateway-down.d.ts +15 -0
- package/dist/src/channels/telegram-mirror/failure/gateway-down.js +27 -0
- package/dist/src/channels/telegram-mirror/failure/gateway-down.js.map +1 -0
- package/dist/src/channels/telegram-mirror/failure/in-flight-conflict.d.ts +15 -0
- package/dist/src/channels/telegram-mirror/failure/in-flight-conflict.js +27 -0
- package/dist/src/channels/telegram-mirror/failure/in-flight-conflict.js.map +1 -0
- package/dist/src/channels/telegram-mirror/failure/index.d.ts +23 -0
- package/dist/src/channels/telegram-mirror/failure/index.js +35 -0
- package/dist/src/channels/telegram-mirror/failure/index.js.map +1 -0
- package/dist/src/channels/telegram-mirror/failure/model-5xx.d.ts +16 -0
- package/dist/src/channels/telegram-mirror/failure/model-5xx.js +24 -0
- package/dist/src/channels/telegram-mirror/failure/model-5xx.js.map +1 -0
- package/dist/src/channels/telegram-mirror/failure/network-blip.d.ts +17 -0
- package/dist/src/channels/telegram-mirror/failure/network-blip.js +25 -0
- package/dist/src/channels/telegram-mirror/failure/network-blip.js.map +1 -0
- package/dist/src/channels/telegram-mirror/failure/pool-exhausted-fallback.d.ts +15 -0
- package/dist/src/channels/telegram-mirror/failure/pool-exhausted-fallback.js +24 -0
- package/dist/src/channels/telegram-mirror/failure/pool-exhausted-fallback.js.map +1 -0
- package/dist/src/channels/telegram-mirror/failure/rate-limit.d.ts +16 -0
- package/dist/src/channels/telegram-mirror/failure/rate-limit.js +26 -0
- package/dist/src/channels/telegram-mirror/failure/rate-limit.js.map +1 -0
- package/dist/src/channels/telegram-mirror/failure/returning-after-24h.d.ts +14 -0
- package/dist/src/channels/telegram-mirror/failure/returning-after-24h.js +33 -0
- package/dist/src/channels/telegram-mirror/failure/returning-after-24h.js.map +1 -0
- package/dist/src/channels/telegram-mirror/failure/types.d.ts +30 -0
- package/dist/src/channels/telegram-mirror/failure/types.js +9 -0
- package/dist/src/channels/telegram-mirror/failure/types.js.map +1 -0
- package/dist/src/channels/telegram-mirror/index.d.ts +30 -0
- package/dist/src/channels/telegram-mirror/index.js +41 -0
- package/dist/src/channels/telegram-mirror/index.js.map +1 -0
- package/dist/src/channels/telegram-mirror/plan-attachment.d.ts +120 -0
- package/dist/src/channels/telegram-mirror/plan-attachment.js +138 -0
- package/dist/src/channels/telegram-mirror/plan-attachment.js.map +1 -0
- package/dist/src/channels/telegram-mirror/quota-reader.d.ts +41 -0
- package/dist/src/channels/telegram-mirror/quota-reader.js +29 -0
- package/dist/src/channels/telegram-mirror/quota-reader.js.map +1 -0
- package/dist/src/channels/telegram-mirror/sessions-keyboard.d.ts +84 -0
- package/dist/src/channels/telegram-mirror/sessions-keyboard.js +113 -0
- package/dist/src/channels/telegram-mirror/sessions-keyboard.js.map +1 -0
- package/dist/src/channels/telegram-mirror/soak-log.d.ts +98 -0
- package/dist/src/channels/telegram-mirror/soak-log.js +136 -0
- package/dist/src/channels/telegram-mirror/soak-log.js.map +1 -0
- package/dist/src/channels/telegram-mirror/state-machine.d.ts +102 -0
- package/dist/src/channels/telegram-mirror/state-machine.js +117 -0
- package/dist/src/channels/telegram-mirror/state-machine.js.map +1 -0
- package/dist/src/channels/telegram-mirror/sync-commands.d.ts +63 -0
- package/dist/src/channels/telegram-mirror/sync-commands.js +51 -0
- package/dist/src/channels/telegram-mirror/sync-commands.js.map +1 -0
- package/dist/src/channels/telegram-mirror/threshold-watcher.d.ts +54 -0
- package/dist/src/channels/telegram-mirror/threshold-watcher.js +77 -0
- package/dist/src/channels/telegram-mirror/threshold-watcher.js.map +1 -0
- package/dist/src/command-router/cc-handler.js +1 -1
- package/dist/src/command-router/cc-handler.js.map +1 -1
- package/dist/src/index.js +12 -8
- package/dist/src/index.js.map +1 -1
- package/dist/src/lib/auto-recovery.js +1 -1
- package/dist/src/lib/auto-recovery.js.map +1 -1
- package/dist/src/lib/drift-detector.js +1 -1
- package/dist/src/lib/drift-detector.js.map +1 -1
- package/dist/src/lib/error-renderer.d.ts +23 -0
- package/dist/src/lib/error-renderer.js +106 -0
- package/dist/src/lib/error-renderer.js.map +1 -0
- package/dist/src/lib/perf/speculative-bubble.d.ts +27 -0
- package/dist/src/lib/perf/speculative-bubble.js +36 -0
- package/dist/src/lib/perf/speculative-bubble.js.map +1 -0
- package/dist/src/lib/session-registry.d.ts +66 -0
- package/dist/src/lib/session-registry.js +188 -0
- package/dist/src/lib/session-registry.js.map +1 -0
- package/dist/src/lib/telegram-bot-api.d.ts +100 -0
- package/dist/src/lib/telegram-bot-api.js +204 -0
- package/dist/src/lib/telegram-bot-api.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"error-renderer.js","sourceRoot":"","sources":["../../../src/lib/error-renderer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* src/lib/perf/speculative-bubble.ts — v0.25.0 M16 migration target.
|
|
3
|
+
*
|
|
4
|
+
* Migrated from src/channels/telegram/speculative-bubble.ts unchanged
|
|
5
|
+
* except for the sendTg import path (legacy card-renderer → new
|
|
6
|
+
* src/lib/telegram-bot-api.ts).
|
|
7
|
+
*
|
|
8
|
+
* M9 (perf overhaul idea #9). Fires a Telegram sendMessage at t≈50ms
|
|
9
|
+
* after the user submits, BEFORE the model returns first token. Pure
|
|
10
|
+
* perception fix — shortens the user-visible "did the bot get my
|
|
11
|
+
* message?" window from ~400-800ms to ~50ms.
|
|
12
|
+
*
|
|
13
|
+
* Flag: CC_OPENCLAW_PERF_SPEC_BUBBLE (default OFF; opt-in via =1).
|
|
14
|
+
*/
|
|
15
|
+
export interface SpeculativeBubbleOptions {
|
|
16
|
+
chatId: string;
|
|
17
|
+
threadId?: string | undefined;
|
|
18
|
+
/** Text to emit. Defaults to a one-cell braille spinner + "Thinking…". */
|
|
19
|
+
text?: string;
|
|
20
|
+
/** Reply-to message id (the user's submitted message). Optional. */
|
|
21
|
+
replyToMessageId?: number | null;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Emit the speculative bubble. Returns the new message_id on success,
|
|
25
|
+
* null if the flag is off / chatId is missing / send failed. Never throws.
|
|
26
|
+
*/
|
|
27
|
+
export declare function emitSpeculativeThinking(opts: SpeculativeBubbleOptions): Promise<number | null>;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* src/lib/perf/speculative-bubble.ts — v0.25.0 M16 migration target.
|
|
3
|
+
*
|
|
4
|
+
* Migrated from src/channels/telegram/speculative-bubble.ts unchanged
|
|
5
|
+
* except for the sendTg import path (legacy card-renderer → new
|
|
6
|
+
* src/lib/telegram-bot-api.ts).
|
|
7
|
+
*
|
|
8
|
+
* M9 (perf overhaul idea #9). Fires a Telegram sendMessage at t≈50ms
|
|
9
|
+
* after the user submits, BEFORE the model returns first token. Pure
|
|
10
|
+
* perception fix — shortens the user-visible "did the bot get my
|
|
11
|
+
* message?" window from ~400-800ms to ~50ms.
|
|
12
|
+
*
|
|
13
|
+
* Flag: CC_OPENCLAW_PERF_SPEC_BUBBLE (default OFF; opt-in via =1).
|
|
14
|
+
*/
|
|
15
|
+
import { getPerfSpecBubbleEnabled } from '../config.js';
|
|
16
|
+
import { sendTg } from '../telegram-bot-api.js';
|
|
17
|
+
const DEFAULT_TEXT = '⠋ Thinking…';
|
|
18
|
+
/**
|
|
19
|
+
* Emit the speculative bubble. Returns the new message_id on success,
|
|
20
|
+
* null if the flag is off / chatId is missing / send failed. Never throws.
|
|
21
|
+
*/
|
|
22
|
+
export async function emitSpeculativeThinking(opts) {
|
|
23
|
+
if (!getPerfSpecBubbleEnabled())
|
|
24
|
+
return null;
|
|
25
|
+
if (!opts.chatId)
|
|
26
|
+
return null;
|
|
27
|
+
const text = opts.text || DEFAULT_TEXT;
|
|
28
|
+
try {
|
|
29
|
+
const res = (await sendTg(opts.chatId, text, opts.threadId, undefined, opts.replyToMessageId ?? null));
|
|
30
|
+
return res?.message_id ?? null;
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=speculative-bubble.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"speculative-bubble.js","sourceRoot":"","sources":["../../../../src/lib/perf/speculative-bubble.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,wBAAwB,EAAE,MAAM,cAAc,CAAC;AACxD,OAAO,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAEhD,MAAM,YAAY,GAAG,aAAa,CAAC;AAWnC;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAC3C,IAA8B;IAE9B,IAAI,CAAC,wBAAwB,EAAE;QAAE,OAAO,IAAI,CAAC;IAC7C,IAAI,CAAC,IAAI,CAAC,MAAM;QAAE,OAAO,IAAI,CAAC;IAC9B,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,IAAI,YAAY,CAAC;IACvC,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,CAAC,MAAM,MAAM,CACvB,IAAI,CAAC,MAAM,EACX,IAAI,EACJ,IAAI,CAAC,QAAQ,EACb,SAAS,EACT,IAAI,CAAC,gBAAgB,IAAI,IAAI,CAC9B,CAAmC,CAAC;QACrC,OAAO,GAAG,EAAE,UAAU,IAAI,IAAI,CAAC;IACjC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* src/lib/session-registry.ts — v0.25.0 M1: slug ↔ sessionName persistence.
|
|
3
|
+
*
|
|
4
|
+
* Telegram Terminal Mirror needs to remember which Claude session belongs to
|
|
5
|
+
* each project slug ("cc-openclaw" / "loopedin" / "how-to-a1" / ...) across
|
|
6
|
+
* gateway restarts. /sessions, /new, /stop, callback-data lookups all rely
|
|
7
|
+
* on this mapping.
|
|
8
|
+
*
|
|
9
|
+
* Decision: ADR-003 — JSON file at ~/.openclaw/session-registry.json with
|
|
10
|
+
* atomic tmpfile + rename writes; corrupted-file fallback to empty in-memory
|
|
11
|
+
* state with a one-line warn log. Rationale: registry is tiny (≤50 entries,
|
|
12
|
+
* ~120 bytes each), JSON is grep-able, survives gateway restarts; SQLite is
|
|
13
|
+
* overkill at this scale; plugin-local files get blown away on upgrade.
|
|
14
|
+
*
|
|
15
|
+
* Atomic-write pattern mirrors src/session-bootstrap/resume-registry.ts —
|
|
16
|
+
* the same writeFileSync(tmp) + renameSync(tmp, path) shape, which is the
|
|
17
|
+
* canonical idiom in cc-openclaw.
|
|
18
|
+
*
|
|
19
|
+
* Concurrency model: in-process only. JS is single-threaded, so back-to-back
|
|
20
|
+
* register() calls serialize naturally; the renameSync at the end of save()
|
|
21
|
+
* is also atomic on POSIX. Cross-process writes (multiple gateways pointing
|
|
22
|
+
* at the same HOME) are NOT supported and would race; cc-openclaw is
|
|
23
|
+
* single-gateway-per-host by design.
|
|
24
|
+
*/
|
|
25
|
+
export interface SessionRegistryEntry {
|
|
26
|
+
/** Short human-readable project identifier, e.g. "cc-openclaw". */
|
|
27
|
+
slug: string;
|
|
28
|
+
/** Claude session name used by PersistentClaudeSession / session-manager. */
|
|
29
|
+
sessionName: string;
|
|
30
|
+
/** ISO timestamp of the first register(slug, …) call. */
|
|
31
|
+
createdAt: string;
|
|
32
|
+
/** ISO timestamp of the most recent register or touch. */
|
|
33
|
+
lastUsedAt: string;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Insert or update a slug → sessionName mapping. Returns the resulting
|
|
37
|
+
* entry. Throws on empty slug or empty sessionName.
|
|
38
|
+
*/
|
|
39
|
+
export declare function register(slug: string, sessionName: string): SessionRegistryEntry;
|
|
40
|
+
/**
|
|
41
|
+
* Remove the entry for the given slug. Returns true if an entry was removed,
|
|
42
|
+
* false if no entry matched.
|
|
43
|
+
*/
|
|
44
|
+
export declare function unregister(slug: string): boolean;
|
|
45
|
+
/**
|
|
46
|
+
* Snapshot copy of all registered entries. Caller may not mutate the result.
|
|
47
|
+
*/
|
|
48
|
+
export declare function list(): SessionRegistryEntry[];
|
|
49
|
+
/**
|
|
50
|
+
* Lookup by slug; returns undefined when no entry matches.
|
|
51
|
+
*/
|
|
52
|
+
export declare function getBySlug(slug: string): SessionRegistryEntry | undefined;
|
|
53
|
+
/**
|
|
54
|
+
* Lookup by sessionName; returns undefined when no entry matches.
|
|
55
|
+
*/
|
|
56
|
+
export declare function getByName(sessionName: string): SessionRegistryEntry | undefined;
|
|
57
|
+
/**
|
|
58
|
+
* Touch lastUsedAt without changing sessionName. Useful for /sessions tap
|
|
59
|
+
* activity tracking (M3). Returns the updated entry or undefined.
|
|
60
|
+
*/
|
|
61
|
+
export declare function touch(slug: string): SessionRegistryEntry | undefined;
|
|
62
|
+
/**
|
|
63
|
+
* Test-only: clear the in-memory cache so the next load() re-reads disk.
|
|
64
|
+
* Production code never calls this.
|
|
65
|
+
*/
|
|
66
|
+
export declare function _resetForTests(): void;
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* src/lib/session-registry.ts — v0.25.0 M1: slug ↔ sessionName persistence.
|
|
3
|
+
*
|
|
4
|
+
* Telegram Terminal Mirror needs to remember which Claude session belongs to
|
|
5
|
+
* each project slug ("cc-openclaw" / "loopedin" / "how-to-a1" / ...) across
|
|
6
|
+
* gateway restarts. /sessions, /new, /stop, callback-data lookups all rely
|
|
7
|
+
* on this mapping.
|
|
8
|
+
*
|
|
9
|
+
* Decision: ADR-003 — JSON file at ~/.openclaw/session-registry.json with
|
|
10
|
+
* atomic tmpfile + rename writes; corrupted-file fallback to empty in-memory
|
|
11
|
+
* state with a one-line warn log. Rationale: registry is tiny (≤50 entries,
|
|
12
|
+
* ~120 bytes each), JSON is grep-able, survives gateway restarts; SQLite is
|
|
13
|
+
* overkill at this scale; plugin-local files get blown away on upgrade.
|
|
14
|
+
*
|
|
15
|
+
* Atomic-write pattern mirrors src/session-bootstrap/resume-registry.ts —
|
|
16
|
+
* the same writeFileSync(tmp) + renameSync(tmp, path) shape, which is the
|
|
17
|
+
* canonical idiom in cc-openclaw.
|
|
18
|
+
*
|
|
19
|
+
* Concurrency model: in-process only. JS is single-threaded, so back-to-back
|
|
20
|
+
* register() calls serialize naturally; the renameSync at the end of save()
|
|
21
|
+
* is also atomic on POSIX. Cross-process writes (multiple gateways pointing
|
|
22
|
+
* at the same HOME) are NOT supported and would race; cc-openclaw is
|
|
23
|
+
* single-gateway-per-host by design.
|
|
24
|
+
*/
|
|
25
|
+
import { writeFileSync, readFileSync, renameSync, mkdirSync, existsSync } from 'fs';
|
|
26
|
+
import { homedir } from 'os';
|
|
27
|
+
import { join, dirname } from 'path';
|
|
28
|
+
const SCHEMA_VERSION = 1;
|
|
29
|
+
const TAG = '[cc-openclaw/session-registry]';
|
|
30
|
+
/**
|
|
31
|
+
* Resolve the registry file path. Honors CC_OPENCLAW_SESSION_REGISTRY_PATH
|
|
32
|
+
* for tests / non-default installs; defaults to ~/.openclaw/session-registry.json.
|
|
33
|
+
*/
|
|
34
|
+
function registryPath() {
|
|
35
|
+
const override = process.env.CC_OPENCLAW_SESSION_REGISTRY_PATH;
|
|
36
|
+
if (override && override.length > 0)
|
|
37
|
+
return override;
|
|
38
|
+
return join(homedir(), '.openclaw', 'session-registry.json');
|
|
39
|
+
}
|
|
40
|
+
let cache;
|
|
41
|
+
let cachedFor;
|
|
42
|
+
/**
|
|
43
|
+
* Returns true iff x looks like a SessionRegistryEntry — used to defensively
|
|
44
|
+
* filter rows out of a possibly-malformed-but-parseable JSON file.
|
|
45
|
+
*/
|
|
46
|
+
function isEntry(x) {
|
|
47
|
+
if (!x || typeof x !== 'object')
|
|
48
|
+
return false;
|
|
49
|
+
const e = x;
|
|
50
|
+
return (typeof e.slug === 'string' &&
|
|
51
|
+
e.slug.length > 0 &&
|
|
52
|
+
typeof e.sessionName === 'string' &&
|
|
53
|
+
e.sessionName.length > 0 &&
|
|
54
|
+
typeof e.createdAt === 'string' &&
|
|
55
|
+
typeof e.lastUsedAt === 'string');
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Load the registry from disk into the in-memory cache. Falls back to an
|
|
59
|
+
* empty registry on any read/parse/shape error and emits a single warn log.
|
|
60
|
+
*/
|
|
61
|
+
function load() {
|
|
62
|
+
const path = registryPath();
|
|
63
|
+
if (cache && cachedFor === path)
|
|
64
|
+
return cache;
|
|
65
|
+
cachedFor = path;
|
|
66
|
+
if (!existsSync(path)) {
|
|
67
|
+
cache = { version: SCHEMA_VERSION, updatedAt: new Date().toISOString(), entries: [] };
|
|
68
|
+
return cache;
|
|
69
|
+
}
|
|
70
|
+
try {
|
|
71
|
+
const raw = readFileSync(path, 'utf8');
|
|
72
|
+
const parsed = JSON.parse(raw);
|
|
73
|
+
if (!parsed || typeof parsed !== 'object') {
|
|
74
|
+
throw new Error('registry root is not an object');
|
|
75
|
+
}
|
|
76
|
+
const root = parsed;
|
|
77
|
+
if (!Array.isArray(root.entries)) {
|
|
78
|
+
throw new Error('registry.entries is not an array');
|
|
79
|
+
}
|
|
80
|
+
const entries = root.entries.filter(isEntry);
|
|
81
|
+
cache = {
|
|
82
|
+
version: typeof root.version === 'number' ? root.version : SCHEMA_VERSION,
|
|
83
|
+
updatedAt: typeof root.updatedAt === 'string' ? root.updatedAt : new Date().toISOString(),
|
|
84
|
+
entries,
|
|
85
|
+
};
|
|
86
|
+
return cache;
|
|
87
|
+
}
|
|
88
|
+
catch (err) {
|
|
89
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
90
|
+
console.warn(`${TAG} Corrupted registry at ${path} (${msg}) — falling back to empty state.`);
|
|
91
|
+
cache = { version: SCHEMA_VERSION, updatedAt: new Date().toISOString(), entries: [] };
|
|
92
|
+
return cache;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Atomic write: serialize, write to <path>.tmp, rename onto <path>. The
|
|
97
|
+
* rename is the atomic step on POSIX (same-directory rename is guaranteed).
|
|
98
|
+
*/
|
|
99
|
+
function save(state) {
|
|
100
|
+
const path = registryPath();
|
|
101
|
+
state.updatedAt = new Date().toISOString();
|
|
102
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
103
|
+
const tmp = path + '.tmp';
|
|
104
|
+
writeFileSync(tmp, JSON.stringify(state, null, 2));
|
|
105
|
+
renameSync(tmp, path);
|
|
106
|
+
cache = state;
|
|
107
|
+
cachedFor = path;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Insert or update a slug → sessionName mapping. Returns the resulting
|
|
111
|
+
* entry. Throws on empty slug or empty sessionName.
|
|
112
|
+
*/
|
|
113
|
+
export function register(slug, sessionName) {
|
|
114
|
+
if (!slug)
|
|
115
|
+
throw new Error('session-registry: slug is required');
|
|
116
|
+
if (!sessionName)
|
|
117
|
+
throw new Error('session-registry: sessionName is required');
|
|
118
|
+
const state = load();
|
|
119
|
+
const now = new Date().toISOString();
|
|
120
|
+
const existing = state.entries.find((e) => e.slug === slug);
|
|
121
|
+
let entry;
|
|
122
|
+
if (existing) {
|
|
123
|
+
existing.sessionName = sessionName;
|
|
124
|
+
existing.lastUsedAt = now;
|
|
125
|
+
entry = existing;
|
|
126
|
+
}
|
|
127
|
+
else {
|
|
128
|
+
entry = { slug, sessionName, createdAt: now, lastUsedAt: now };
|
|
129
|
+
state.entries.push(entry);
|
|
130
|
+
}
|
|
131
|
+
save(state);
|
|
132
|
+
return { ...entry };
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Remove the entry for the given slug. Returns true if an entry was removed,
|
|
136
|
+
* false if no entry matched.
|
|
137
|
+
*/
|
|
138
|
+
export function unregister(slug) {
|
|
139
|
+
const state = load();
|
|
140
|
+
const idx = state.entries.findIndex((e) => e.slug === slug);
|
|
141
|
+
if (idx < 0)
|
|
142
|
+
return false;
|
|
143
|
+
state.entries.splice(idx, 1);
|
|
144
|
+
save(state);
|
|
145
|
+
return true;
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Snapshot copy of all registered entries. Caller may not mutate the result.
|
|
149
|
+
*/
|
|
150
|
+
export function list() {
|
|
151
|
+
return load().entries.map((e) => ({ ...e }));
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Lookup by slug; returns undefined when no entry matches.
|
|
155
|
+
*/
|
|
156
|
+
export function getBySlug(slug) {
|
|
157
|
+
const e = load().entries.find((x) => x.slug === slug);
|
|
158
|
+
return e ? { ...e } : undefined;
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Lookup by sessionName; returns undefined when no entry matches.
|
|
162
|
+
*/
|
|
163
|
+
export function getByName(sessionName) {
|
|
164
|
+
const e = load().entries.find((x) => x.sessionName === sessionName);
|
|
165
|
+
return e ? { ...e } : undefined;
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Touch lastUsedAt without changing sessionName. Useful for /sessions tap
|
|
169
|
+
* activity tracking (M3). Returns the updated entry or undefined.
|
|
170
|
+
*/
|
|
171
|
+
export function touch(slug) {
|
|
172
|
+
const state = load();
|
|
173
|
+
const e = state.entries.find((x) => x.slug === slug);
|
|
174
|
+
if (!e)
|
|
175
|
+
return undefined;
|
|
176
|
+
e.lastUsedAt = new Date().toISOString();
|
|
177
|
+
save(state);
|
|
178
|
+
return { ...e };
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Test-only: clear the in-memory cache so the next load() re-reads disk.
|
|
182
|
+
* Production code never calls this.
|
|
183
|
+
*/
|
|
184
|
+
export function _resetForTests() {
|
|
185
|
+
cache = undefined;
|
|
186
|
+
cachedFor = undefined;
|
|
187
|
+
}
|
|
188
|
+
//# sourceMappingURL=session-registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-registry.js","sourceRoot":"","sources":["../../../src/lib/session-registry.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* src/lib/telegram-bot-api.ts — v0.25.0 M16 extracted HTTP layer.
|
|
3
|
+
*
|
|
4
|
+
* Pre-M16 the Telegram Bot API helpers lived inside the legacy live-card +
|
|
5
|
+
* card-renderer modules. M16 deletes those modules, but a handful of lib/
|
|
6
|
+
* utilities (error-renderer.ts, perf/speculative-bubble.ts) still need to
|
|
7
|
+
* dispatch Telegram messages. This file is the migrated, slim HTTP layer:
|
|
8
|
+
* • telegramApi(method, params) — generic POST to api.telegram.org
|
|
9
|
+
* • sendTg(chatId, text, ...) — sendMessage with MarkdownV2 + plain
|
|
10
|
+
* text fallback (preserves v0.20.1
|
|
11
|
+
* content-punctuation fix).
|
|
12
|
+
* • editTg(chatId, msgId, text…) — editMessageText with same fallback +
|
|
13
|
+
* 429 retry handling.
|
|
14
|
+
* • BOT_TOKEN exported as a mutable getter (mutated via setBotToken /
|
|
15
|
+
* initBotTokenFromConfig at boot).
|
|
16
|
+
*
|
|
17
|
+
* Token sourcing on boot (initBotTokenFromConfig):
|
|
18
|
+
* 1. api.config.channels.telegram.accounts[defaultAccount].botToken
|
|
19
|
+
* 2. ~/.openclaw/openclaw.json → same JSON path
|
|
20
|
+
* 3. fallthrough: BOT_TOKEN stays '' and renderer/sendTg return false.
|
|
21
|
+
*
|
|
22
|
+
* The mirror channel's register() (M0..M14 + M15-cutover-default) calls
|
|
23
|
+
* initBotTokenFromConfig(api) at boot — the same shape the legacy live-card
|
|
24
|
+
* used to do.
|
|
25
|
+
*/
|
|
26
|
+
export declare const OPENCLAW_CONFIG_PATH: string;
|
|
27
|
+
/**
|
|
28
|
+
* Mutable getter for the current bot token. Callers should treat it as
|
|
29
|
+
* read-only at runtime; use setBotToken / initBotTokenFromConfig to mutate.
|
|
30
|
+
*/
|
|
31
|
+
export declare function getBotToken(): string;
|
|
32
|
+
/**
|
|
33
|
+
* Imperative setter — for tests + explicit init paths. Returns the
|
|
34
|
+
* previous value so test cleanup can restore.
|
|
35
|
+
*/
|
|
36
|
+
export declare function setBotToken(token: string): string;
|
|
37
|
+
/**
|
|
38
|
+
* Back-compat alias — legacy code did `import { BOT_TOKEN } from ...`. We
|
|
39
|
+
* preserve the binding via a frozen wrapper that always reflects the
|
|
40
|
+
* current token. Existing read-sites get the current value; existing
|
|
41
|
+
* write-sites (none expected — legacy only wrote via setBotToken under
|
|
42
|
+
* a different name) would need migration.
|
|
43
|
+
*
|
|
44
|
+
* Using a getter-backed object also lets `if (!BOT_TOKEN)` work
|
|
45
|
+
* idiomatically; the property is read on every access.
|
|
46
|
+
*/
|
|
47
|
+
export declare const BOT_TOKEN: {
|
|
48
|
+
readonly value: string;
|
|
49
|
+
};
|
|
50
|
+
/**
|
|
51
|
+
* Boot-time initialiser. Reads the configured Telegram bot token from
|
|
52
|
+
* either api.config.channels.telegram.accounts or ~/.openclaw/openclaw.json.
|
|
53
|
+
* Returns true when a token was loaded.
|
|
54
|
+
*/
|
|
55
|
+
export interface BotConfigSource {
|
|
56
|
+
config?: {
|
|
57
|
+
channels?: {
|
|
58
|
+
telegram?: {
|
|
59
|
+
defaultAccount?: string;
|
|
60
|
+
accounts?: Record<string, {
|
|
61
|
+
botToken?: string;
|
|
62
|
+
}>;
|
|
63
|
+
};
|
|
64
|
+
};
|
|
65
|
+
};
|
|
66
|
+
logger?: {
|
|
67
|
+
info: (msg: string) => void;
|
|
68
|
+
warn: (msg: string) => void;
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
export declare function initBotTokenFromConfig(api?: BotConfigSource): boolean;
|
|
72
|
+
export interface TelegramApiResponse {
|
|
73
|
+
ok: boolean;
|
|
74
|
+
result?: {
|
|
75
|
+
message_id?: number;
|
|
76
|
+
};
|
|
77
|
+
error_code?: number;
|
|
78
|
+
description?: string;
|
|
79
|
+
parameters?: {
|
|
80
|
+
retry_after?: number;
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Low-level POST to api.telegram.org. Resolves with the parsed JSON
|
|
85
|
+
* response, or {ok:false} on JSON parse failure / network error
|
|
86
|
+
* (rejection is the caller's signal for a truly unreachable endpoint).
|
|
87
|
+
*/
|
|
88
|
+
export declare function telegramApi(method: string, params: Record<string, unknown>): Promise<TelegramApiResponse>;
|
|
89
|
+
/**
|
|
90
|
+
* sendMessage with MarkdownV2 first + plain-text fallback. The fallback
|
|
91
|
+
* is the v0.20.1 fix: prior implementation stripped punctuation on
|
|
92
|
+
* MarkdownV2 parse errors; current behaviour retries with parse_mode
|
|
93
|
+
* omitted so all content survives.
|
|
94
|
+
*/
|
|
95
|
+
export declare function sendTg(chatId: string | number, text: string, threadId?: string | number, replyMarkup?: unknown, replyToMessageId?: number | null): Promise<TelegramApiResponse>;
|
|
96
|
+
/**
|
|
97
|
+
* editMessageText with MarkdownV2-first + 429 retry-after handling +
|
|
98
|
+
* plain-text fallback.
|
|
99
|
+
*/
|
|
100
|
+
export declare function editTg(chatId: string | number, messageId: number, text: string, replyMarkup?: unknown): Promise<TelegramApiResponse>;
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* src/lib/telegram-bot-api.ts — v0.25.0 M16 extracted HTTP layer.
|
|
3
|
+
*
|
|
4
|
+
* Pre-M16 the Telegram Bot API helpers lived inside the legacy live-card +
|
|
5
|
+
* card-renderer modules. M16 deletes those modules, but a handful of lib/
|
|
6
|
+
* utilities (error-renderer.ts, perf/speculative-bubble.ts) still need to
|
|
7
|
+
* dispatch Telegram messages. This file is the migrated, slim HTTP layer:
|
|
8
|
+
* • telegramApi(method, params) — generic POST to api.telegram.org
|
|
9
|
+
* • sendTg(chatId, text, ...) — sendMessage with MarkdownV2 + plain
|
|
10
|
+
* text fallback (preserves v0.20.1
|
|
11
|
+
* content-punctuation fix).
|
|
12
|
+
* • editTg(chatId, msgId, text…) — editMessageText with same fallback +
|
|
13
|
+
* 429 retry handling.
|
|
14
|
+
* • BOT_TOKEN exported as a mutable getter (mutated via setBotToken /
|
|
15
|
+
* initBotTokenFromConfig at boot).
|
|
16
|
+
*
|
|
17
|
+
* Token sourcing on boot (initBotTokenFromConfig):
|
|
18
|
+
* 1. api.config.channels.telegram.accounts[defaultAccount].botToken
|
|
19
|
+
* 2. ~/.openclaw/openclaw.json → same JSON path
|
|
20
|
+
* 3. fallthrough: BOT_TOKEN stays '' and renderer/sendTg return false.
|
|
21
|
+
*
|
|
22
|
+
* The mirror channel's register() (M0..M14 + M15-cutover-default) calls
|
|
23
|
+
* initBotTokenFromConfig(api) at boot — the same shape the legacy live-card
|
|
24
|
+
* used to do.
|
|
25
|
+
*/
|
|
26
|
+
import { request as httpsRequest } from 'node:https';
|
|
27
|
+
import { readFileSync } from 'node:fs';
|
|
28
|
+
import { homedir } from 'node:os';
|
|
29
|
+
import { join } from 'node:path';
|
|
30
|
+
export const OPENCLAW_CONFIG_PATH = join(homedir(), '.openclaw', 'openclaw.json');
|
|
31
|
+
const PLUGIN_TAG = '[cc-openclaw/telegram-bot-api]';
|
|
32
|
+
// ─── Bot token state ───────────────────────────────────────────────────────
|
|
33
|
+
let _botToken = '';
|
|
34
|
+
/**
|
|
35
|
+
* Mutable getter for the current bot token. Callers should treat it as
|
|
36
|
+
* read-only at runtime; use setBotToken / initBotTokenFromConfig to mutate.
|
|
37
|
+
*/
|
|
38
|
+
export function getBotToken() {
|
|
39
|
+
return _botToken;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Imperative setter — for tests + explicit init paths. Returns the
|
|
43
|
+
* previous value so test cleanup can restore.
|
|
44
|
+
*/
|
|
45
|
+
export function setBotToken(token) {
|
|
46
|
+
const prev = _botToken;
|
|
47
|
+
_botToken = token;
|
|
48
|
+
return prev;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Back-compat alias — legacy code did `import { BOT_TOKEN } from ...`. We
|
|
52
|
+
* preserve the binding via a frozen wrapper that always reflects the
|
|
53
|
+
* current token. Existing read-sites get the current value; existing
|
|
54
|
+
* write-sites (none expected — legacy only wrote via setBotToken under
|
|
55
|
+
* a different name) would need migration.
|
|
56
|
+
*
|
|
57
|
+
* Using a getter-backed object also lets `if (!BOT_TOKEN)` work
|
|
58
|
+
* idiomatically; the property is read on every access.
|
|
59
|
+
*/
|
|
60
|
+
export const BOT_TOKEN = Object.freeze({
|
|
61
|
+
get value() {
|
|
62
|
+
return _botToken;
|
|
63
|
+
},
|
|
64
|
+
});
|
|
65
|
+
export function initBotTokenFromConfig(api) {
|
|
66
|
+
const logger = api?.logger;
|
|
67
|
+
// 1. api.config.channels.telegram path
|
|
68
|
+
try {
|
|
69
|
+
const tg = api?.config?.channels?.telegram;
|
|
70
|
+
if (tg?.accounts) {
|
|
71
|
+
const key = tg.defaultAccount ?? 'default';
|
|
72
|
+
const token = tg.accounts[key]?.botToken;
|
|
73
|
+
if (token) {
|
|
74
|
+
_botToken = token;
|
|
75
|
+
logger?.info(`${PLUGIN_TAG} bot token loaded from api.config`);
|
|
76
|
+
return true;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
catch {
|
|
81
|
+
/* fall through to file path */
|
|
82
|
+
}
|
|
83
|
+
// 2. ~/.openclaw/openclaw.json
|
|
84
|
+
try {
|
|
85
|
+
const raw = readFileSync(OPENCLAW_CONFIG_PATH, 'utf8');
|
|
86
|
+
const parsed = JSON.parse(raw);
|
|
87
|
+
const tg = parsed.channels?.telegram;
|
|
88
|
+
if (tg?.accounts) {
|
|
89
|
+
const key = tg.defaultAccount ?? 'default';
|
|
90
|
+
const token = tg.accounts[key]?.botToken;
|
|
91
|
+
if (token) {
|
|
92
|
+
_botToken = token;
|
|
93
|
+
logger?.info(`${PLUGIN_TAG} bot token loaded from ${OPENCLAW_CONFIG_PATH}`);
|
|
94
|
+
return true;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
catch (err) {
|
|
99
|
+
logger?.warn(`${PLUGIN_TAG} config-file fallback failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
100
|
+
}
|
|
101
|
+
return false;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Low-level POST to api.telegram.org. Resolves with the parsed JSON
|
|
105
|
+
* response, or {ok:false} on JSON parse failure / network error
|
|
106
|
+
* (rejection is the caller's signal for a truly unreachable endpoint).
|
|
107
|
+
*/
|
|
108
|
+
export function telegramApi(method, params) {
|
|
109
|
+
return new Promise((resolve, reject) => {
|
|
110
|
+
const body = JSON.stringify(params);
|
|
111
|
+
const options = {
|
|
112
|
+
hostname: 'api.telegram.org',
|
|
113
|
+
path: `/bot${_botToken}/${method}`,
|
|
114
|
+
method: 'POST',
|
|
115
|
+
headers: {
|
|
116
|
+
'Content-Type': 'application/json',
|
|
117
|
+
'Content-Length': Buffer.byteLength(body),
|
|
118
|
+
},
|
|
119
|
+
};
|
|
120
|
+
const req = httpsRequest(options, (res) => {
|
|
121
|
+
let data = '';
|
|
122
|
+
res.on('data', (chunk) => (data += chunk));
|
|
123
|
+
res.on('end', () => {
|
|
124
|
+
try {
|
|
125
|
+
resolve(JSON.parse(data));
|
|
126
|
+
}
|
|
127
|
+
catch {
|
|
128
|
+
resolve({ ok: false, description: 'JSON parse error' });
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
});
|
|
132
|
+
req.on('error', (err) => reject(err));
|
|
133
|
+
req.setTimeout(10_000, () => {
|
|
134
|
+
req.destroy(new Error('Telegram API timeout'));
|
|
135
|
+
});
|
|
136
|
+
req.write(body);
|
|
137
|
+
req.end();
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* sendMessage with MarkdownV2 first + plain-text fallback. The fallback
|
|
142
|
+
* is the v0.20.1 fix: prior implementation stripped punctuation on
|
|
143
|
+
* MarkdownV2 parse errors; current behaviour retries with parse_mode
|
|
144
|
+
* omitted so all content survives.
|
|
145
|
+
*/
|
|
146
|
+
export async function sendTg(chatId, text, threadId, replyMarkup, replyToMessageId) {
|
|
147
|
+
try {
|
|
148
|
+
const base = { chat_id: chatId, disable_web_page_preview: true };
|
|
149
|
+
if (threadId)
|
|
150
|
+
base.message_thread_id = Number(threadId);
|
|
151
|
+
if (replyMarkup)
|
|
152
|
+
base.reply_markup = replyMarkup;
|
|
153
|
+
if (replyToMessageId)
|
|
154
|
+
base.reply_to_message_id = Number(replyToMessageId);
|
|
155
|
+
const res = await telegramApi('sendMessage', { ...base, text, parse_mode: 'MarkdownV2' });
|
|
156
|
+
if (res.ok)
|
|
157
|
+
return res;
|
|
158
|
+
return telegramApi('sendMessage', { ...base, text: text || 'Session update' });
|
|
159
|
+
}
|
|
160
|
+
catch {
|
|
161
|
+
return { ok: false };
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* editMessageText with MarkdownV2-first + 429 retry-after handling +
|
|
166
|
+
* plain-text fallback.
|
|
167
|
+
*/
|
|
168
|
+
export async function editTg(chatId, messageId, text, replyMarkup) {
|
|
169
|
+
try {
|
|
170
|
+
const params = {
|
|
171
|
+
chat_id: chatId,
|
|
172
|
+
message_id: messageId,
|
|
173
|
+
text,
|
|
174
|
+
parse_mode: 'MarkdownV2',
|
|
175
|
+
disable_web_page_preview: true,
|
|
176
|
+
};
|
|
177
|
+
if (replyMarkup)
|
|
178
|
+
params.reply_markup = replyMarkup;
|
|
179
|
+
const res = await telegramApi('editMessageText', params);
|
|
180
|
+
if (!res.ok && (res.error_code === 429 || res.description?.includes('Too Many Requests'))) {
|
|
181
|
+
const retryAfterSec = res.parameters?.retry_after || 5;
|
|
182
|
+
const waitMs = Math.min(retryAfterSec * 1000, 30_000);
|
|
183
|
+
await new Promise((r) => setTimeout(r, waitMs));
|
|
184
|
+
const retry = await telegramApi('editMessageText', params);
|
|
185
|
+
if (retry.ok)
|
|
186
|
+
return retry;
|
|
187
|
+
}
|
|
188
|
+
if (res.ok)
|
|
189
|
+
return res;
|
|
190
|
+
const fallback = {
|
|
191
|
+
chat_id: chatId,
|
|
192
|
+
message_id: messageId,
|
|
193
|
+
text: text || 'Session update',
|
|
194
|
+
disable_web_page_preview: true,
|
|
195
|
+
};
|
|
196
|
+
if (replyMarkup)
|
|
197
|
+
fallback.reply_markup = replyMarkup;
|
|
198
|
+
return telegramApi('editMessageText', fallback);
|
|
199
|
+
}
|
|
200
|
+
catch {
|
|
201
|
+
return { ok: false };
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
//# sourceMappingURL=telegram-bot-api.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"telegram-bot-api.js","sourceRoot":"","sources":["../../../src/lib/telegram-bot-api.ts"],"names":[],"mappings":"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"}
|