@a1hvdy/cc-openclaw 0.30.0 → 0.31.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.
Files changed (206) hide show
  1. package/dist/src/channels/telegram-mirror/card-renderer.js +9 -5
  2. package/dist/src/channels/telegram-mirror/commands.js +0 -8
  3. package/dist/src/channels/telegram-mirror/status-line.js +32 -2
  4. package/dist/src/constants.js +16 -2
  5. package/dist/src/lib/config.js +40 -0
  6. package/dist/src/openai-compat/non-streaming-handler.js +2 -2
  7. package/dist/src/openai-compat/streaming-handler.js +2 -2
  8. package/package.json +3 -2
  9. package/dist/src/channels/adapter.d.ts +0 -103
  10. package/dist/src/channels/telegram-mirror/askuser.d.ts +0 -107
  11. package/dist/src/channels/telegram-mirror/burst-accumulator.d.ts +0 -96
  12. package/dist/src/channels/telegram-mirror/callback-mapping.d.ts +0 -61
  13. package/dist/src/channels/telegram-mirror/card-renderer.d.ts +0 -68
  14. package/dist/src/channels/telegram-mirror/card-state.d.ts +0 -83
  15. package/dist/src/channels/telegram-mirror/commands.d.ts +0 -183
  16. package/dist/src/channels/telegram-mirror/compose-buffer.d.ts +0 -71
  17. package/dist/src/channels/telegram-mirror/cost-views.d.ts +0 -58
  18. package/dist/src/channels/telegram-mirror/failure/callback-data-overflow.d.ts +0 -21
  19. package/dist/src/channels/telegram-mirror/failure/gateway-down.d.ts +0 -15
  20. package/dist/src/channels/telegram-mirror/failure/in-flight-conflict.d.ts +0 -15
  21. package/dist/src/channels/telegram-mirror/failure/index.d.ts +0 -23
  22. package/dist/src/channels/telegram-mirror/failure/model-5xx.d.ts +0 -16
  23. package/dist/src/channels/telegram-mirror/failure/network-blip.d.ts +0 -17
  24. package/dist/src/channels/telegram-mirror/failure/pool-exhausted-fallback.d.ts +0 -15
  25. package/dist/src/channels/telegram-mirror/failure/rate-limit.d.ts +0 -16
  26. package/dist/src/channels/telegram-mirror/failure/returning-after-24h.d.ts +0 -14
  27. package/dist/src/channels/telegram-mirror/failure/types.d.ts +0 -30
  28. package/dist/src/channels/telegram-mirror/inbound-handler.d.ts +0 -73
  29. package/dist/src/channels/telegram-mirror/index.d.ts +0 -32
  30. package/dist/src/channels/telegram-mirror/plan-attachment.d.ts +0 -120
  31. package/dist/src/channels/telegram-mirror/quota-reader.d.ts +0 -42
  32. package/dist/src/channels/telegram-mirror/sessions-keyboard.d.ts +0 -84
  33. package/dist/src/channels/telegram-mirror/soak-log.d.ts +0 -99
  34. package/dist/src/channels/telegram-mirror/state-machine.d.ts +0 -113
  35. package/dist/src/channels/telegram-mirror/status-line.d.ts +0 -51
  36. package/dist/src/channels/telegram-mirror/sync-commands.d.ts +0 -100
  37. package/dist/src/channels/telegram-mirror/threshold-watcher.d.ts +0 -54
  38. package/dist/src/channels/telegram-mirror/turn-bridge.d.ts +0 -125
  39. package/dist/src/cli/checks/bridge-wiring.d.ts +0 -14
  40. package/dist/src/cli/checks/config-schema.d.ts +0 -11
  41. package/dist/src/cli/checks/critical-openclaw-json-keys.d.ts +0 -21
  42. package/dist/src/cli/checks/install-path.d.ts +0 -11
  43. package/dist/src/cli/checks/patch-scaffold.d.ts +0 -17
  44. package/dist/src/cli/doctor.d.ts +0 -20
  45. package/dist/src/cli/index.d.ts +0 -8
  46. package/dist/src/cli/migrate.d.ts +0 -29
  47. package/dist/src/command-router/cc-handler.d.ts +0 -67
  48. package/dist/src/command-router/index.d.ts +0 -2
  49. package/dist/src/command-router/launch-policy.d.ts +0 -92
  50. package/dist/src/command-router/resume-policy.d.ts +0 -18
  51. package/dist/src/command-router/turn-formatter.d.ts +0 -19
  52. package/dist/src/config/loader.d.ts +0 -8
  53. package/dist/src/config/schema.d.ts +0 -192
  54. package/dist/src/constants.d.ts +0 -191
  55. package/dist/src/council/build-agent-prompt.d.ts +0 -11
  56. package/dist/src/council/cleanup-worktrees.d.ts +0 -10
  57. package/dist/src/council/consensus.d.ts +0 -20
  58. package/dist/src/council/council.d.ts +0 -67
  59. package/dist/src/council/index.d.ts +0 -2
  60. package/dist/src/council/system-prompt.d.ts +0 -16
  61. package/dist/src/council/write-worktree-claude-md.d.ts +0 -10
  62. package/dist/src/engines/base-oneshot-session.d.ts +0 -87
  63. package/dist/src/engines/heartbeat-guard.d.ts +0 -93
  64. package/dist/src/engines/index.d.ts +0 -8
  65. package/dist/src/engines/persistent-codex-session.d.ts +0 -16
  66. package/dist/src/engines/persistent-cursor-session.d.ts +0 -21
  67. package/dist/src/engines/persistent-custom-session.d.ts +0 -78
  68. package/dist/src/engines/persistent-gemini-session.d.ts +0 -21
  69. package/dist/src/engines/persistent-session.d.ts +0 -95
  70. package/dist/src/engines/resolve-bin.d.ts +0 -14
  71. package/dist/src/engines/subprocess-pool.d.ts +0 -78
  72. package/dist/src/health/handler.d.ts +0 -39
  73. package/dist/src/health/index.d.ts +0 -1
  74. package/dist/src/health/metrics.d.ts +0 -52
  75. package/dist/src/index.d.ts +0 -57
  76. package/dist/src/lib/auto-recovery.d.ts +0 -43
  77. package/dist/src/lib/cache-parity-decide.d.ts +0 -64
  78. package/dist/src/lib/cache-parity.d.ts +0 -38
  79. package/dist/src/lib/cc-cli-scan.d.ts +0 -52
  80. package/dist/src/lib/circuit-breaker.d.ts +0 -21
  81. package/dist/src/lib/config-service.d.ts +0 -106
  82. package/dist/src/lib/config.d.ts +0 -136
  83. package/dist/src/lib/cost-rollup.d.ts +0 -36
  84. package/dist/src/lib/debounce.d.ts +0 -12
  85. package/dist/src/lib/debug-tap.d.ts +0 -13
  86. package/dist/src/lib/domain-error.d.ts +0 -59
  87. package/dist/src/lib/drift-detector.d.ts +0 -46
  88. package/dist/src/lib/env-overrides.d.ts +0 -47
  89. package/dist/src/lib/error-formatter.d.ts +0 -91
  90. package/dist/src/lib/error-renderer.d.ts +0 -20
  91. package/dist/src/lib/heartbeat-config.d.ts +0 -34
  92. package/dist/src/lib/heartbeat-workaround.d.ts +0 -44
  93. package/dist/src/lib/html-render.d.ts +0 -50
  94. package/dist/src/lib/http-agent.d.ts +0 -47
  95. package/dist/src/lib/index.d.ts +0 -7
  96. package/dist/src/lib/index.js +0 -10
  97. package/dist/src/lib/json-array.d.ts +0 -10
  98. package/dist/src/lib/markdown-to-mdv2.d.ts +0 -53
  99. package/dist/src/lib/markdown-v2.d.ts +0 -27
  100. package/dist/src/lib/perf/async-compact.d.ts +0 -26
  101. package/dist/src/lib/perf/direct-sdk.d.ts +0 -26
  102. package/dist/src/lib/perf/haiku-route.d.ts +0 -19
  103. package/dist/src/lib/perf/predictive-continuation.d.ts +0 -18
  104. package/dist/src/lib/perf/read-batch.d.ts +0 -33
  105. package/dist/src/lib/perf/skill-list-collapse.d.ts +0 -22
  106. package/dist/src/lib/perf/speculative-bubble.d.ts +0 -27
  107. package/dist/src/lib/perf/typing-prefetch.d.ts +0 -25
  108. package/dist/src/lib/probes.d.ts +0 -50
  109. package/dist/src/lib/register-guard.d.ts +0 -56
  110. package/dist/src/lib/req-shape-log.d.ts +0 -31
  111. package/dist/src/lib/safe-upstream-probes.d.ts +0 -25
  112. package/dist/src/lib/session-registry.d.ts +0 -66
  113. package/dist/src/lib/spawn-async.d.ts +0 -18
  114. package/dist/src/lib/status-tee-reader.d.ts +0 -29
  115. package/dist/src/lib/sysprompt-strip.d.ts +0 -53
  116. package/dist/src/lib/telegram-bot-api.d.ts +0 -146
  117. package/dist/src/lib/telemetry.d.ts +0 -38
  118. package/dist/src/lib/test-mode.d.ts +0 -26
  119. package/dist/src/lib/trajectory.d.ts +0 -44
  120. package/dist/src/lib/vendor-paths.d.ts +0 -12
  121. package/dist/src/lifecycle/boot.d.ts +0 -48
  122. package/dist/src/lifecycle/patch-manifest.d.ts +0 -82
  123. package/dist/src/lifecycle/phase-import-upstream.d.ts +0 -12
  124. package/dist/src/lifecycle/phase-install-patches.d.ts +0 -12
  125. package/dist/src/lifecycle/phase-schedule-jobs.d.ts +0 -12
  126. package/dist/src/lifecycle/phase-start-server.d.ts +0 -11
  127. package/dist/src/lifecycle/phase-validate-config.d.ts +0 -9
  128. package/dist/src/lifecycle/phase-validate-upstream.d.ts +0 -11
  129. package/dist/src/lifecycle/phase-wire-handlers.d.ts +0 -12
  130. package/dist/src/lifecycle/safe-restart.d.ts +0 -99
  131. package/dist/src/logger.d.ts +0 -14
  132. package/dist/src/mcp/bridge.d.ts +0 -21
  133. package/dist/src/mcp/index.d.ts +0 -2
  134. package/dist/src/models.d.ts +0 -68
  135. package/dist/src/observability/event-bus.d.ts +0 -86
  136. package/dist/src/observability/get-event-bus.d.ts +0 -25
  137. package/dist/src/observability/observability-service.d.ts +0 -19
  138. package/dist/src/observability/perf-telemetry.d.ts +0 -65
  139. package/dist/src/observability/subscribers/metrics.d.ts +0 -11
  140. package/dist/src/observability/subscribers/session-capture.d.ts +0 -15
  141. package/dist/src/openai-compat/autonomy-rule.d.ts +0 -26
  142. package/dist/src/openai-compat/bridges/allowlist.d.ts +0 -19
  143. package/dist/src/openai-compat/bridges/factory.d.ts +0 -30
  144. package/dist/src/openai-compat/bridges/media-bridge.d.ts +0 -34
  145. package/dist/src/openai-compat/bridges/openclaw-api-shim.d.ts +0 -54
  146. package/dist/src/openai-compat/bridges/openclaw-native-tools.d.ts +0 -61
  147. package/dist/src/openai-compat/bridges/openclaw-tool-registry.d.ts +0 -26
  148. package/dist/src/openai-compat/bridges/tts-media-bridge.d.ts +0 -19
  149. package/dist/src/openai-compat/chat-cwd.d.ts +0 -22
  150. package/dist/src/openai-compat/cli-stream-parser.d.ts +0 -134
  151. package/dist/src/openai-compat/index.d.ts +0 -1
  152. package/dist/src/openai-compat/message-extractor.d.ts +0 -84
  153. package/dist/src/openai-compat/mode-flags.d.ts +0 -34
  154. package/dist/src/openai-compat/non-streaming-handler.d.ts +0 -29
  155. package/dist/src/openai-compat/openai-chunk-types.d.ts +0 -35
  156. package/dist/src/openai-compat/openai-compat.d.ts +0 -49
  157. package/dist/src/openai-compat/openai-types.d.ts +0 -71
  158. package/dist/src/openai-compat/parse-route-body.d.ts +0 -24
  159. package/dist/src/openai-compat/prompts.d.ts +0 -47
  160. package/dist/src/openai-compat/request-coalescer.d.ts +0 -77
  161. package/dist/src/openai-compat/response-formatter.d.ts +0 -33
  162. package/dist/src/openai-compat/session-key-resolver.d.ts +0 -41
  163. package/dist/src/openai-compat/skill-resolver.d.ts +0 -59
  164. package/dist/src/openai-compat/sse-translator.d.ts +0 -51
  165. package/dist/src/openai-compat/status-reporter.d.ts +0 -30
  166. package/dist/src/openai-compat/streaming-handler.d.ts +0 -52
  167. package/dist/src/openai-compat/tool-calls-parser.d.ts +0 -34
  168. package/dist/src/openai-compat/tool-results-serializer.d.ts +0 -60
  169. package/dist/src/openai-compat/tts-rule.d.ts +0 -20
  170. package/dist/src/openai-compat/voice-recovery.d.ts +0 -56
  171. package/dist/src/patches/cache-parity-registry.d.ts +0 -103
  172. package/dist/src/patches/claude-md-injection.d.ts +0 -10
  173. package/dist/src/patches/cwd-redirect.d.ts +0 -10
  174. package/dist/src/patches/embedded-server-route.d.ts +0 -23
  175. package/dist/src/patches/pricing-overrides.d.ts +0 -10
  176. package/dist/src/patches/resume-registry-restore.d.ts +0 -11
  177. package/dist/src/patches/session-pid-tracking.d.ts +0 -10
  178. package/dist/src/patches/sysprompt-strip.d.ts +0 -46
  179. package/dist/src/patches/tools-restoration.d.ts +0 -12
  180. package/dist/src/persistence/migration-v0.d.ts +0 -24
  181. package/dist/src/persistence/session-registry.d.ts +0 -58
  182. package/dist/src/proxy/anthropic-adapter.d.ts +0 -136
  183. package/dist/src/proxy/handler.d.ts +0 -39
  184. package/dist/src/proxy/index.d.ts +0 -4
  185. package/dist/src/proxy/schema-cleaner.d.ts +0 -11
  186. package/dist/src/proxy/thought-cache.d.ts +0 -19
  187. package/dist/src/session/embedded-server.d.ts +0 -25
  188. package/dist/src/session/inbox-manager.d.ts +0 -38
  189. package/dist/src/session/index.d.ts +0 -3
  190. package/dist/src/session/persisted-sessions.d.ts +0 -50
  191. package/dist/src/session/session-manager.d.ts +0 -247
  192. package/dist/src/session/watchdogs.d.ts +0 -92
  193. package/dist/src/session-bootstrap/boot-self-heal.d.ts +0 -32
  194. package/dist/src/session-bootstrap/cwd-patch.d.ts +0 -50
  195. package/dist/src/session-bootstrap/index.d.ts +0 -3
  196. package/dist/src/session-bootstrap/resume-registry.d.ts +0 -27
  197. package/dist/src/session-bootstrap/session-hygiene.d.ts +0 -23
  198. package/dist/src/session-bootstrap/sysprompt-strip.d.ts +0 -24
  199. package/dist/src/session-bootstrap/think-conflict-resolver.d.ts +0 -32
  200. package/dist/src/types/route.d.ts +0 -11
  201. package/dist/src/types/runtime-config.d.ts +0 -208
  202. package/dist/src/types/sse.d.ts +0 -29
  203. package/dist/src/types/tool-bridge.d.ts +0 -82
  204. package/dist/src/types/upstream.d.ts +0 -580
  205. package/dist/src/types.d.ts +0 -498
  206. package/dist/src/validation.d.ts +0 -31
@@ -30,8 +30,12 @@ function basename(p) {
30
30
  * Glyph picked per tool-call status. Mirrors terminal "running / done /
31
31
  * errored" iconography that A1 already reads in the live Claude Code TUI.
32
32
  */
33
- function toolGlyph(tc) {
34
- if (tc.isError)
33
+ function toolGlyph(tc, suppressToolErrors = false) {
34
+ // OpenClaw 2026.5.20 #81561 — when the user set messages.suppressToolErrors,
35
+ // an errored-but-completed tool reads as a normal "✓" rather than the "✗"
36
+ // error glyph. tc.result is set for an errored tool (it carries the error
37
+ // body), so the completed-✓ branch below picks it up once "✗" is skipped.
38
+ if (tc.isError && !suppressToolErrors)
35
39
  return '✗';
36
40
  if (tc.result !== undefined)
37
41
  return '✓';
@@ -260,8 +264,8 @@ export function toolIcon(name) {
260
264
  return '🔌';
261
265
  return '🔹';
262
266
  }
263
- export function renderToolLine(tc) {
264
- const glyph = toolGlyph(tc);
267
+ export function renderToolLine(tc, suppressToolErrors = false) {
268
+ const glyph = toolGlyph(tc, suppressToolErrors);
265
269
  const icon = toolIcon(tc.name);
266
270
  // Status glyph + emoji are HTML-safe; the tool name is HTML-escaped and the
267
271
  // input detail rides in a <code> span (v0.27.0 M1 HTML styling).
@@ -384,7 +388,7 @@ export function renderTurn(turn, meta) {
384
388
  let acc = 0;
385
389
  for (let i = turn.toolCalls.length - 1; i >= 0; i--) {
386
390
  const tc = turn.toolCalls[i];
387
- const line = renderToolLine(tc);
391
+ const line = renderToolLine(tc, meta?.suppressToolErrors);
388
392
  // v0.27.4 M2 — for Edit/Write/MultiEdit show a diff (from input) instead of
389
393
  // the "File updated" result; other tools keep the result preview.
390
394
  const diffText = toolDiffBlock(tc);
@@ -44,14 +44,6 @@ export function parseSlash(text) {
44
44
  return { cmd: cmd.toLowerCase(), args: tokens.slice(1) };
45
45
  }
46
46
  // ── /sessions ────────────────────────────────────────────────────────────
47
- function enrichRows(entries, stateLookup) {
48
- return entries.map((e) => ({
49
- slug: e.slug,
50
- sessionName: e.sessionName,
51
- state: stateLookup(e.slug),
52
- lastUsedAt: e.lastUsedAt,
53
- }));
54
- }
55
47
  /**
56
48
  * v0.28.0 — `/sessions` is now a `claude -r`-style picker over the REAL Claude
57
49
  * Code sessions. It mirrors `~/.claude/projects/**` (the store every `claude`
@@ -4,7 +4,7 @@
4
4
  * Builds the Claude-Code-CLI-style status line that sits at the top of the
5
5
  * Telegram live-mirror card, e.g.:
6
6
  *
7
- * [Opus 4.7] · CC 2.1.145 · ⏱ 2h13m · 🔧 3 · bypass
7
+ * [Opus 4.7] · CC 2.1.145 · GW 2026.5.20 · ⏱ 2h13m · 🔧 3 · bypass
8
8
  *
9
9
  * STRICT no-fake-data rule (per the v0.26.2 brief): every segment is rendered
10
10
  * ONLY when its value is genuinely available. Missing model / version / etc.
@@ -40,6 +40,33 @@ export function getCcVersion() {
40
40
  export function _resetCcVersionForTests() {
41
41
  _ccVersion = undefined;
42
42
  }
43
+ // ── Gateway version (cached; resolved at most once per process) ──────────────
44
+ // `openclaw --version` prints e.g. "OpenClaw 2026.5.20 (e510042)". Mirrors the
45
+ // getCcVersion() resolve-once-and-cache contract (including a failed lookup as
46
+ // `null`). Surfaced on the status line as "GW <ver>" so the card shows which
47
+ // OpenClaw core is actually running alongside the CC CLI version.
48
+ let _gatewayVersion;
49
+ export function getGatewayVersion() {
50
+ if (_gatewayVersion !== undefined)
51
+ return _gatewayVersion;
52
+ try {
53
+ const out = execFileSync('openclaw', ['--version'], {
54
+ timeout: 5_000,
55
+ stdio: ['ignore', 'pipe', 'ignore'],
56
+ encoding: 'utf8',
57
+ });
58
+ const m = /(\d+\.\d+\.\d+)/.exec(out);
59
+ _gatewayVersion = m ? m[1] : null;
60
+ }
61
+ catch {
62
+ _gatewayVersion = null;
63
+ }
64
+ return _gatewayVersion;
65
+ }
66
+ /** Test-only — reset the cached gateway version. */
67
+ export function _resetGatewayVersionForTests() {
68
+ _gatewayVersion = undefined;
69
+ }
43
70
  // ── Model id → short label ─────────────────────────────────────────────────
44
71
  // "claude-opus-4-7" → "Opus 4.7"; "claude-sonnet-4-6" → "Sonnet 4.6". Unknown
45
72
  // shapes pass through unchanged (still real data, just not prettified).
@@ -69,7 +96,7 @@ export function fmtElapsed(ms) {
69
96
  /**
70
97
  * Render the status line for a turn. Returns `undefined` when NOTHING is
71
98
  * available to show (so callers omit the line entirely). Segments, in order:
72
- * [model] · CC <ver> · ⏱ <elapsed> · 🔧 <toolCount> · bypass
99
+ * [model] · CC <ver> · GW <ver> · ⏱ <elapsed> · 🔧 <toolCount> · bypass
73
100
  * Every segment is conditional on real data.
74
101
  */
75
102
  export function renderStatusLine(turn, meta, now = Date.now()) {
@@ -80,6 +107,9 @@ export function renderStatusLine(turn, meta, now = Date.now()) {
80
107
  const ver = getCcVersion();
81
108
  if (ver)
82
109
  segs.push(`CC ${ver}`);
110
+ const gwVer = getGatewayVersion();
111
+ if (gwVer)
112
+ segs.push(`GW ${gwVer}`);
83
113
  // Turn elapsed is always real (Turn.startedAt is set at card creation). Use
84
114
  // endedAt once the turn is done so the finalized card shows total duration.
85
115
  const elapsedMs = (turn.endedAt ?? now) - turn.startedAt;
@@ -28,14 +28,28 @@ export const SESSION_READY_FALLBACK_MS = 2_000;
28
28
  *
29
29
  * v0.20.0: env-overridable via `CC_OPENCLAW_TURN_TIMEOUT_MS` (see
30
30
  * src/lib/env-overrides.ts). Setting `=0` disables the per-turn timer
31
- * entirely, matching direct-CLI behavior on long tool turns. */
31
+ * entirely, matching direct-CLI behavior on long tool turns.
32
+ *
33
+ * OpenClaw 2026.5.20 (#83979): core now HONORS
34
+ * `models.providers.cc-openclaw.timeoutSeconds` above its idle watchdog —
35
+ * previously the outer request was killed at ~120s regardless of that value,
36
+ * so this 900_000 alignment was a workaround fighting a hidden ceiling. It is
37
+ * now a genuine, end-to-end envelope. Keep it aligned to timeoutSeconds (do
38
+ * NOT reduce below the configured outer bound). */
32
39
  export const TURN_TIMEOUT_MS = 900_000;
33
40
  /** Runtime watchdog threshold for "stuck" sessions. If a session is
34
41
  * `isBusy === true` AND its stats.lastActivity hasn't moved in this many
35
42
  * ms, the SessionManager watchdog aborts + disposes the session. Mirrors
36
43
  * the boot-time orphan reaper in gateway-pm2-wrapper.sh:53-60, but runs
37
44
  * continuously on a setInterval. Env-overridable via
38
- * CC_OPENCLAW_STALLED_KILL_MS. v0.10.0. */
45
+ * CC_OPENCLAW_STALLED_KILL_MS. v0.10.0.
46
+ *
47
+ * NOTE (OpenClaw 2026.5.20 #83979): this is ORTHOGONAL to core's now-honored
48
+ * provider idle watchdog — that bounds first-token / inter-token waits on the
49
+ * request; this bounds a wedged Claude SUBPROCESS that emits no output at all.
50
+ * The core fix does NOT make this redundant. Keep it. Raise (don't remove) via
51
+ * CC_OPENCLAW_STALLED_KILL_MS only if legitimately long no-output tool runs
52
+ * (e.g. a long Bash) trip it. */
39
53
  export const STALLED_SESSION_KILL_MS = 180_000;
40
54
  /** How often the stalled-session watchdog scans the sessions Map. */
41
55
  export const STALLED_WATCH_INTERVAL_MS = 30_000;
@@ -351,6 +351,46 @@ export function _resetTtsAutoModeCacheForTests() {
351
351
  _ttsAutoModeCache = null;
352
352
  _ttsAutoModeCacheChecked = false;
353
353
  }
354
+ // ── Suppress tool errors (OpenClaw 2026.5.20 #81561) ────────────────────────
355
+ // Reads `messages.suppressToolErrors` from `~/.openclaw/openclaw.json` once and
356
+ // caches it. When true, the user has opted out of tool-failure noise, so the
357
+ // Telegram live-card renders an errored-but-completed tool with its normal "✓"
358
+ // glyph instead of the "✗" error glyph (the card-side equivalent of the core's
359
+ // "no separate warning payloads" behavior). The TURN-level "❌ <reason>" header
360
+ // is unaffected — that's terminal turn state, not a per-tool warning.
361
+ //
362
+ // Same custom-file-reader rationale as getTtsAutoMode(): openclaw.json is a
363
+ // plugin-side decision that shouldn't reach through OpenClaw's typed runtime.
364
+ // Tests override via the CC_OPENCLAW_SUPPRESS_TOOL_ERRORS env var.
365
+ let _suppressToolErrorsCache = null;
366
+ let _suppressToolErrorsCacheChecked = false;
367
+ export function getSuppressToolErrors() {
368
+ // Test-time / explicit override takes precedence.
369
+ const envOverride = process.env.CC_OPENCLAW_SUPPRESS_TOOL_ERRORS?.trim().toLowerCase();
370
+ if (envOverride === '1' || envOverride === 'true' || envOverride === 'on')
371
+ return true;
372
+ if (envOverride === '0' || envOverride === 'false' || envOverride === 'off')
373
+ return false;
374
+ if (!_suppressToolErrorsCacheChecked) {
375
+ _suppressToolErrorsCacheChecked = true;
376
+ try {
377
+ const configPath = process.env.OPENCLAW_CONFIG_PATH || join(homedir(), '.openclaw', 'openclaw.json');
378
+ const raw = readFileSync(configPath, 'utf8');
379
+ const parsed = JSON.parse(raw);
380
+ _suppressToolErrorsCache = parsed.messages?.suppressToolErrors ?? null;
381
+ }
382
+ catch {
383
+ // File missing / unreadable / invalid JSON — fall through to false.
384
+ _suppressToolErrorsCache = null;
385
+ }
386
+ }
387
+ return _suppressToolErrorsCache === true;
388
+ }
389
+ /** Test-only: reset the suppress-tool-errors cache so the next call re-reads. */
390
+ export function _resetSuppressToolErrorsCacheForTests() {
391
+ _suppressToolErrorsCache = null;
392
+ _suppressToolErrorsCacheChecked = false;
393
+ }
354
394
  export function getClaudeBin() {
355
395
  const cfg = getConfigService();
356
396
  if (cfg)
@@ -23,7 +23,7 @@
23
23
  import { reportStatus, getToolDescription } from './status-reporter.js';
24
24
  import { parseToolCallsFromText } from './tool-calls-parser.js';
25
25
  import { formatCompletionResponse } from './response-formatter.js';
26
- import { getSurfaceThinkingEnabled, getTtsAutoMode, getCardAnswerMirrorEnabled } from '../lib/config.js';
26
+ import { getSurfaceThinkingEnabled, getTtsAutoMode, getCardAnswerMirrorEnabled, getSuppressToolErrors } from '../lib/config.js';
27
27
  import { emit as emitTrajectory, emitTurnTrace } from '../lib/trajectory.js';
28
28
  import { formatError, ERROR_CODES } from '../lib/error-formatter.js';
29
29
  import { applyVoiceRecovery, _logVoiceDebug, detectVoiceIntent, hasTtsMarkers } from './voice-recovery.js';
@@ -55,7 +55,7 @@ slashCommand) {
55
55
  // cards THIS module instance sees (see handleStreaming counterpart).
56
56
  process.stderr.write(`[cc-openclaw/openai-compat] handleNonStreaming pid=${process.pid} hasTools=${hasTools} ${mirrorCardStateDebug()} session=${sessionName}\n`);
57
57
  // v0.26.2 M1+M2 — feed the CC-CLI status line (model + bypass + quota; see streaming).
58
- mirrorSetCardMeta({ model, bypassPermissions: true, ...mirrorReadQuotaMeta() });
58
+ mirrorSetCardMeta({ model, bypassPermissions: true, suppressToolErrors: getSuppressToolErrors(), ...mirrorReadQuotaMeta() });
59
59
  // v0.14.0 turn-trace probe: capture wall-clock duration of the turn.
60
60
  const turnStartMs = Date.now();
61
61
  // v0.15.0 Slice 1: hoist userText so the catch-path probe emit can reference
@@ -41,7 +41,7 @@ import { formatCompletionChunk } from './response-formatter.js';
41
41
  import { isToolStreamMode } from './mode-flags.js';
42
42
  import { emit as emitTrajectory, emitTurnTrace } from '../lib/trajectory.js';
43
43
  import { formatError, ERROR_CODES } from '../lib/error-formatter.js';
44
- import { getSurfaceThinkingEnabled, getTtsAutoMode, getCardAnswerMirrorEnabled } from '../lib/config.js';
44
+ import { getSurfaceThinkingEnabled, getTtsAutoMode, getCardAnswerMirrorEnabled, getSuppressToolErrors } from '../lib/config.js';
45
45
  import { applyVoiceRecovery, detectVoiceIntent, hasTtsMarkers, _logVoiceDebug } from './voice-recovery.js';
46
46
  import { pushToolUse as mirrorPushToolUse, pushToolResult as mirrorPushToolResult, pushAssistantText as mirrorPushAssistantText, pushThinking as mirrorPushThinking, finalizeActiveCards as mirrorFinalizeActiveCards, extractInsightForCard as mirrorExtractInsightForCard, failActiveCards as mirrorFailActiveCards, classifyFailure, setCardMeta as mirrorSetCardMeta, readQuotaMeta as mirrorReadQuotaMeta, } from '../channels/telegram-mirror/turn-bridge.js';
47
47
  import { cardStateDebug as mirrorCardStateDebug } from '../channels/telegram-mirror/card-state.js';
@@ -83,7 +83,7 @@ onFinalText) {
83
83
  // v0.26.2 M1+M2 — feed the CC-CLI status line. The openai-compat path always
84
84
  // runs permissionMode 'bypassPermissions' (openai-compat.ts) so we assert it.
85
85
  // Quota is read once here (real status-tee snapshot or omitted).
86
- mirrorSetCardMeta({ model, bypassPermissions: true, ...mirrorReadQuotaMeta() });
86
+ mirrorSetCardMeta({ model, bypassPermissions: true, suppressToolErrors: getSuppressToolErrors(), ...mirrorReadQuotaMeta() });
87
87
  // #4 dual-surface seam — hoist once per turn (read off the hot delta loop).
88
88
  // Default OFF: card is the activity pane, gateway draft is the answer pane.
89
89
  const mirrorAnswerToCard = getCardAnswerMirrorEnabled();
package/package.json CHANGED
@@ -1,12 +1,11 @@
1
1
  {
2
2
  "name": "@a1hvdy/cc-openclaw",
3
- "version": "0.30.0",
3
+ "version": "0.31.0",
4
4
  "description": "A1xAI's Anthropic CLI bridge plugin for OpenClaw",
5
5
  "author": "@a1cy",
6
6
  "license": "MIT",
7
7
  "type": "module",
8
8
  "main": "dist/src/index.js",
9
- "types": "dist/src/index.d.ts",
10
9
  "homepage": "https://github.com/A1cy/cc-openclaw",
11
10
  "repository": "github:A1cy/cc-openclaw",
12
11
  "engines": {
@@ -23,6 +22,8 @@
23
22
  },
24
23
  "files": [
25
24
  "dist/",
25
+ "!dist/**/*.d.ts",
26
+ "!dist/**/*.d.ts.map",
26
27
  "configs/",
27
28
  "skills/",
28
29
  "openclaw.plugin.json",
@@ -1,103 +0,0 @@
1
- /**
2
- * Channel Adapter — generic interface for delivering session UX
3
- * to chat channels (Telegram, Discord, Signal, etc.).
4
- *
5
- * Telegram is the first concrete implementation (src/channels/telegram/).
6
- * Discord and Signal are deferred to v1.1 (Nice-to-Have).
7
- *
8
- * Each adapter:
9
- * - Renders live session cards (progress, tool calls, summaries)
10
- * - Receives inbound channel messages and forwards them as session inputs
11
- * - Sends session outputs back to the channel
12
- * - Provides idempotent register() to wire OpenClaw plugin lifecycle hooks
13
- *
14
- * AUDIT — B2 (PRP_v3 §11 vs reality, 2026-04-28):
15
- *
16
- * PRP_v3 §11.1 documents an event vocabulary (`session.created`,
17
- * `session.turn.start`, `session.tool.start`, `plugin.heartbeat`, etc.)
18
- * that does NOT exist in the actual codebase. Every `api.on()` call
19
- * site in src/ uses the openclaw-claude-code hook-event vocabulary
20
- * documented in `ChannelHookEvent` below. Likewise §11.2's
21
- * `api.emit('session.result', ...)` is unimplemented — no `api.emit`
22
- * call sites exist.
23
- *
24
- * Resolution: this audit treats the *code* as canonical and the spec
25
- * as drifted. The `ChannelHookEvent` literal union captures the actual
26
- * contract any future channel adapter must speak. The §11.x doc
27
- * sections need a v3.1 revision to match — tracked as a docs-tier
28
- * follow-up (Tier 3 §24), not a code-tier blocker.
29
- */
30
- /**
31
- * Canonical hook event vocabulary — every event name passed to `api.on()`
32
- * across src/channels/, src/command-router/, and src/session-bootstrap/
33
- * (verified by `rg "api\\.on\\(" src/`).
34
- *
35
- * This is the contract: any channel/handler that wants to subscribe to
36
- * gateway events MUST use one of these names. Adding a new event name
37
- * here without a corresponding gateway emitter is dead-code-typing.
38
- */
39
- type ChannelHookEvent = 'before_dispatch' | 'before_prompt_build' | 'before_model_resolve' | 'before_tool_call' | 'after_tool_call' | 'reply_dispatch' | 'message_sending';
40
- /** Hook handler signature — gateway passes (event, ctx?) positional args. */
41
- type ChannelHookHandler = (...args: unknown[]) => unknown | Promise<unknown>;
42
- export interface PluginApi {
43
- /**
44
- * Subscribe to a gateway hook event.
45
- *
46
- * Accepts `ChannelHookEvent` for compile-time event-name checking, or
47
- * `string` as an escape hatch for adapter-specific events not yet
48
- * canonicalized into the union. Future tightening: drop the `| string`
49
- * overload once all hook sites use the union.
50
- */
51
- on(event: ChannelHookEvent, handler: ChannelHookHandler): void;
52
- on(event: string, handler: ChannelHookHandler): void;
53
- }
54
- /**
55
- * Outbound message from session → channel.
56
- */
57
- export interface ChannelMessage {
58
- channel: string;
59
- target: string;
60
- text?: string;
61
- buttons?: ChannelButton[];
62
- metadata?: Record<string, unknown>;
63
- }
64
- export interface ChannelButton {
65
- text: string;
66
- callbackData?: string;
67
- url?: string;
68
- }
69
- /**
70
- * Inbound envelope from channel → session.
71
- */
72
- export interface ChannelInbound {
73
- channel: string;
74
- fromUserId: string;
75
- text: string;
76
- metadata?: Record<string, unknown>;
77
- }
78
- /**
79
- * Channel adapter contract. Each concrete adapter (e.g. Telegram) implements
80
- * this interface so cc-openclaw can route session events to any wired channel.
81
- */
82
- export interface ChannelAdapter {
83
- /** Adapter identifier — must be unique across registered adapters. */
84
- readonly id: string;
85
- /**
86
- * Idempotent registration of OpenClaw plugin lifecycle hooks.
87
- * Multiple calls with the same api MUST NOT stack listeners.
88
- */
89
- register(api: PluginApi): void;
90
- /** Send an outbound message to the channel. */
91
- send(message: ChannelMessage): Promise<void>;
92
- /** Update an existing live card in-place (rendering progress). */
93
- updateCard?(target: string, message: ChannelMessage): Promise<void>;
94
- /** Render a final completion summary to the channel. */
95
- completionSummary?(target: string, summary: ChannelMessage): Promise<void>;
96
- }
97
- /**
98
- * Helper to wire any ChannelAdapter via the plugin's main register() flow.
99
- * Centralizes the per-adapter `register()` call so src/index.ts can
100
- * iterate a list of adapters without coupling to each adapter's internals.
101
- */
102
- export declare function registerChannelAdapter(api: PluginApi, adapter: ChannelAdapter): void;
103
- export {};
@@ -1,107 +0,0 @@
1
- /**
2
- * src/channels/telegram-mirror/askuser.ts — v0.26.3 M5.
3
- *
4
- * Renders Claude Code's AskUserQuestion tool as native Telegram inline
5
- * keyboards, "next-turn model" (Path A, chosen by A1 2026-05-20):
6
- *
7
- * agent calls AskUserQuestion → turn ends
8
- * → we send a keyboard message (single-select: one button per option +
9
- * "✍️ Write something else"; multi-select: checkbox toggles + Submit)
10
- * → user taps → api.registerInteractiveHandler fires
11
- * → we answer the callback, edit the message to show the choice, and
12
- * api.enqueueNextTurnInjection() queues the answer as context for the
13
- * agent's NEXT turn (it is acted on when the next message runs — the
14
- * documented primitive injects context, it does not start a turn).
15
- *
16
- * Feasibility proven 2026-05-20: the headless subprocess DOES emit an
17
- * AskUserQuestion tool_use (pushToolUse name=AskUserQuestion). The tool emits
18
- * twice (dual content_block_start + assistant-block), so capture dedups by
19
- * tool_use id.
20
- *
21
- * Telegram has no ANSI color — checkboxes use ☐/☑ glyphs.
22
- */
23
- /** Namespace prefix for callback_data so api.registerInteractiveHandler routes
24
- * taps here. Matched at the first ':' by the gateway (must be [A-Za-z0-9._-]+). */
25
- export declare const ASKUSER_NS = "ccmirror";
26
- interface QOption {
27
- label: string;
28
- description?: string;
29
- }
30
- interface ParsedQuestion {
31
- header: string;
32
- question: string;
33
- multiSelect: boolean;
34
- options: QOption[];
35
- }
36
- /**
37
- * v0.28.0 — build a single inline button that, when tapped, resumes a Claude
38
- * Code session. Reuses the proven askuser callback path: the payload is stashed
39
- * in the shared (globalThis-anchored) CallbackMap and the callback_data is
40
- * `ccmirror:<id>`, so taps route through the same before_dispatch interceptor.
41
- */
42
- export declare function buildResumeButton(uuid: string, label: string): {
43
- text: string;
44
- callback_data: string;
45
- };
46
- /** Minimal subset of the registerInteractiveHandler ctx we use. */
47
- export interface InteractiveCtx {
48
- callback: {
49
- id?: string;
50
- data?: string;
51
- namespace?: string;
52
- payload?: string;
53
- };
54
- chatId?: string | number;
55
- conversationId?: string;
56
- sessionKey?: string;
57
- threadId?: number;
58
- respond?: {
59
- editMessage?: (text: string) => Promise<unknown>;
60
- answer?: (text?: string) => Promise<unknown>;
61
- };
62
- }
63
- /** Minimal subset of the plugin api we use (next-turn injection). */
64
- export interface InjectApi {
65
- enqueueNextTurnInjection?: (injection: {
66
- sessionKey: string;
67
- text: string;
68
- placement?: 'prepend_context' | 'append_context';
69
- idempotencyKey?: string;
70
- }) => unknown;
71
- }
72
- /** Record the real agent session key for a chat (called from inbound before_dispatch). */
73
- export declare function rememberSessionKey(chatId: string, sessionKey: string | undefined): void;
74
- /** Parse the FIRST question from an AskUserQuestion tool input. Defensive —
75
- * returns undefined if the shape isn't usable (no fabrication). */
76
- export declare function parseFirstQuestion(input: Record<string, unknown> | undefined): ParsedQuestion | undefined;
77
- /**
78
- * Capture an AskUserQuestion tool_use and render the keyboard. Called from
79
- * turn-bridge when name === 'AskUserQuestion'. Dedups the dual-emission by
80
- * tool_use id. Best-effort: a send failure must not break the turn.
81
- */
82
- export declare function captureAskUserQuestion(chatId: string, threadId: number | undefined, input: Record<string, unknown> | undefined, toolUseId: string | undefined): Promise<void>;
83
- /**
84
- * Handle an inline-button tap routed from api.registerInteractiveHandler.
85
- * Resolves the callback payload, updates state, and on a terminal choice
86
- * (single-select option, multi-select Submit) injects the answer for the next
87
- * turn. "Write something else" just prompts the user to type — their typed
88
- * message becomes the next turn naturally, so no injection is needed.
89
- */
90
- export declare function handleTap(ctx: InteractiveCtx, api: InjectApi): Promise<void>;
91
- /** True if an inbound message text is actually an AskUserQuestion button tap.
92
- * The gateway delivers taps on plugin-sent keyboards as before_dispatch
93
- * messages with text = the callback_data (`ccmirror:<id>`), NOT as routed
94
- * interactive-handler callbacks — so we intercept them in before_dispatch. */
95
- export declare function isAskUserCallback(text: string): boolean;
96
- /**
97
- * Handle a tap that arrived as a before_dispatch message (text=`ccmirror:<id>`).
98
- * Builds a synthetic ctx (conversationId = chatId resolves the remembered
99
- * session key) and runs the normal tap logic. Caller MUST claim the event so
100
- * the literal callback_data never reaches the agent.
101
- */
102
- export declare function handleTapData(text: string, chatId: string, api: InjectApi): Promise<void>;
103
- /** Test-only — reset module state. */
104
- export declare function _resetAskUserForTests(): void;
105
- /** Test-only — peek pending question count. */
106
- export declare function _pendingCount(): number;
107
- export {};
@@ -1,96 +0,0 @@
1
- /**
2
- * src/channels/telegram-mirror/burst-accumulator.ts — v0.25.0 M8.
3
- *
4
- * Per-chat 5-second settle window for non-slash inbound messages. When
5
- * the user fires multiple message bubbles within 5s of each other, the
6
- * accumulator concatenates them into one user-message payload (joined by
7
- * "\n\n") before delivery to the engine. A gap > 5s flushes the prior
8
- * buffer immediately and starts a new one.
9
- *
10
- * Decision: ADR-007 — 5s is the empirical saddle point. <3s gaps are
11
- * almost always related thoughts; >8s gaps are almost always new turns.
12
- * 5s matches the WARMUP_COOLDOWN_MS in typing-prefetch.ts (consistency).
13
- *
14
- * Routing responsibility lives in the inbound dispatcher (later milestone):
15
- * • Slash messages bypass this class — dispatched immediately via
16
- * dispatchCommand (commands.ts).
17
- * • Compose-active chats bypass this class — drafts go to ComposeBuffer
18
- * (compose-buffer.ts). M7 takes priority over M8 per ADR-007.
19
- * • Everything else flows through submit() here.
20
- *
21
- * The flush flow has TWO triggers:
22
- * 1. A new submit() that arrives AFTER the settle window — that submit
23
- * returns the prior buffer in `flushed` and starts a fresh buffer.
24
- * 2. A periodic flushIfReady() check that runs on a timer when no new
25
- * inbound has arrived since the window opened.
26
- *
27
- * Tests inject a deterministic clock; production passes Date.now.
28
- */
29
- export interface BurstAccumulatorOptions {
30
- /** Settle window in milliseconds (default 5000 per ADR-007). */
31
- settleMs?: number;
32
- /** Injectable clock for tests; defaults to Date.now. */
33
- now?: () => number;
34
- /** Custom separator between concatenated drafts (default "\n\n"). */
35
- separator?: string;
36
- }
37
- export interface SubmitResult {
38
- /**
39
- * When the new submit() arrives AFTER the prior buffer's settle window,
40
- * the prior buffer is returned here for immediate delivery; the new
41
- * message starts a fresh buffer in its place. Undefined otherwise.
42
- */
43
- flushed?: string;
44
- }
45
- export declare class BurstAccumulator {
46
- private readonly sessions;
47
- private readonly settleMs;
48
- private readonly now;
49
- private readonly separator;
50
- constructor(opts?: BurstAccumulatorOptions);
51
- /**
52
- * Submit a non-slash inbound message. Returns `flushed` populated when
53
- * the prior buffer for the chat had timed out and this submit forced
54
- * its flush; in that case the new message starts a fresh buffer.
55
- *
56
- * The returned `flushed` payload is the only value the caller delivers
57
- * to the engine — the new message itself stays buffered for at least
58
- * `settleMs` more, so it gets a chance to coalesce with follow-ups.
59
- */
60
- submit(chatId: string, text: string): SubmitResult;
61
- /**
62
- * Periodic check — when the settle window has elapsed without any new
63
- * inbound, returns the buffered payload and clears the session. When
64
- * the window has NOT yet elapsed, returns undefined and leaves the
65
- * buffer intact. Returns undefined for chats without an active buffer.
66
- *
67
- * Production wiring: call from a 1Hz interval timer per known chatId
68
- * (or from the inbound dispatcher's idle-tick).
69
- */
70
- flushIfReady(chatId: string): string | undefined;
71
- /**
72
- * Force-flush the buffer for a chat regardless of timing. Used when an
73
- * explicit signal arrives that the current buffer must deliver now —
74
- * e.g. a slash command was typed (its dispatcher flushes burst first,
75
- * then routes the slash, so the bursted text reaches the engine before
76
- * the slash response).
77
- */
78
- flushNow(chatId: string): string | undefined;
79
- /**
80
- * True when a buffer exists for the chat (regardless of settle state).
81
- * Used by the inbound dispatcher to decide whether a slash arrival
82
- * should trigger flushNow before routing.
83
- */
84
- hasBuffer(chatId: string): boolean;
85
- /**
86
- * Number of drafts currently buffered for the chat. Useful for status
87
- * surfaces and for tests asserting the buffer state.
88
- */
89
- draftCount(chatId: string): number;
90
- /**
91
- * Clear all sessions. Test helper.
92
- */
93
- clear(): void;
94
- private fresh;
95
- private format;
96
- }
@@ -1,61 +0,0 @@
1
- /**
2
- * src/channels/telegram-mirror/callback-mapping.ts — v0.25.0 M3.
3
- *
4
- * ADR-004 — Telegram's callback_data is capped at 64 bytes UTF-8. For
5
- * payloads larger than that (most action+slug combinations are), the bot
6
- * writes a short opaque base36 id into callback_data and stashes the real
7
- * payload here. TTL prevents unbounded memory growth as users tap through
8
- * keyboards or never tap at all.
9
- *
10
- * Default TTL is 10 minutes per ADR-004 monitoring signal (callback miss
11
- * rate > 2% in soak → revisit TTL). The class accepts an injectable clock
12
- * so tests can fast-forward without setTimeout games.
13
- *
14
- * No I/O, no global state. Each subsystem that hands out callback_data
15
- * owns its own CallbackMap instance — keeps ownership boundaries clean
16
- * for M4 (per-command), M9 (plan keyboards), M11 (cost subview).
17
- */
18
- export interface CallbackMapOptions {
19
- /** TTL in milliseconds (default 10 minutes per ADR-004). */
20
- ttlMs?: number;
21
- /** Injectable clock for tests; defaults to Date.now. */
22
- now?: () => number;
23
- /** Length of the opaque id string (default 8 base36 chars ≈ 41 bits entropy). */
24
- idLength?: number;
25
- }
26
- export declare class CallbackMap {
27
- private readonly entries;
28
- private readonly ttlMs;
29
- private readonly now;
30
- private readonly idLength;
31
- constructor(opts?: CallbackMapOptions);
32
- /**
33
- * Allocate a fresh opaque id and stash the payload behind it. Returns the
34
- * id, which fits in a Telegram callback_data field with room to spare.
35
- * Idempotent only at the data-shape level — calling create() with the
36
- * same payload twice produces two distinct ids.
37
- */
38
- create(payload: unknown): string;
39
- /**
40
- * Resolve a callback id to its stashed payload. Returns undefined if the
41
- * id was never minted OR if it has expired since. Stale entries are
42
- * dropped lazily on access — no background timer needed.
43
- */
44
- get(id: string): unknown | undefined;
45
- /**
46
- * Manually evict an id (e.g., one-shot Approve/Reject buttons after the
47
- * user taps once). Returns true if an entry was deleted.
48
- */
49
- delete(id: string): boolean;
50
- /**
51
- * Current entry count (after pruning expired). Useful for monitoring
52
- * and the 2% callback-miss-rate signal in soak.
53
- */
54
- size(): number;
55
- /**
56
- * Drop everything. Test helper; production code never calls this.
57
- */
58
- clear(): void;
59
- private prune;
60
- private randomId;
61
- }