@a1hvdy/cc-openclaw 0.9.2 → 0.11.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 (297) hide show
  1. package/dist/src/channels/telegram/card-renderer.d.ts +63 -0
  2. package/dist/src/channels/telegram/card-renderer.js +149 -0
  3. package/dist/src/channels/telegram/card-renderer.js.map +1 -0
  4. package/dist/src/channels/telegram/completion-summary.js +20 -1
  5. package/dist/src/channels/telegram/completion-summary.js.map +1 -1
  6. package/dist/src/channels/telegram/insight-formatter.d.ts +36 -0
  7. package/dist/src/channels/telegram/insight-formatter.js +36 -0
  8. package/dist/src/channels/telegram/insight-formatter.js.map +1 -0
  9. package/dist/src/channels/telegram/live-card.d.ts +7 -90
  10. package/dist/src/channels/telegram/live-card.js +22 -265
  11. package/dist/src/channels/telegram/live-card.js.map +1 -1
  12. package/dist/src/channels/telegram/logger.d.ts +10 -0
  13. package/dist/src/channels/telegram/logger.js +13 -0
  14. package/dist/src/channels/telegram/logger.js.map +1 -0
  15. package/dist/src/channels/telegram/throttle-controller.d.ts +54 -0
  16. package/dist/src/channels/telegram/throttle-controller.js +132 -0
  17. package/dist/src/channels/telegram/throttle-controller.js.map +1 -0
  18. package/dist/src/channels/telegram/tool-tracker.js +3 -14
  19. package/dist/src/channels/telegram/tool-tracker.js.map +1 -1
  20. package/dist/src/cli/doctor.d.ts +24 -0
  21. package/dist/src/cli/doctor.js +194 -0
  22. package/dist/src/cli/doctor.js.map +1 -0
  23. package/dist/src/cli/index.d.ts +8 -0
  24. package/dist/src/cli/index.js +39 -0
  25. package/dist/src/cli/index.js.map +1 -0
  26. package/dist/src/command-router/cc-handler.js +35 -709
  27. package/dist/src/command-router/cc-handler.js.map +1 -1
  28. package/dist/src/command-router/launch-policy.d.ts +93 -0
  29. package/dist/src/command-router/launch-policy.js +323 -0
  30. package/dist/src/command-router/launch-policy.js.map +1 -0
  31. package/dist/src/command-router/resume-policy.d.ts +18 -0
  32. package/dist/src/command-router/resume-policy.js +236 -0
  33. package/dist/src/command-router/resume-policy.js.map +1 -0
  34. package/dist/src/command-router/turn-formatter.d.ts +19 -0
  35. package/dist/src/command-router/turn-formatter.js +144 -0
  36. package/dist/src/command-router/turn-formatter.js.map +1 -0
  37. package/dist/src/constants.d.ts +33 -2
  38. package/dist/src/constants.js +33 -2
  39. package/dist/src/constants.js.map +1 -1
  40. package/dist/src/lib/config.d.ts +3 -0
  41. package/dist/src/lib/config.js +46 -0
  42. package/dist/src/lib/config.js.map +1 -1
  43. package/dist/src/lib/trajectory.d.ts +1 -1
  44. package/dist/src/lib/trajectory.js.map +1 -1
  45. package/dist/src/openai-compat/bridges/allowlist.d.ts +10 -0
  46. package/dist/src/openai-compat/bridges/allowlist.js +17 -0
  47. package/dist/src/openai-compat/bridges/allowlist.js.map +1 -0
  48. package/dist/src/openai-compat/bridges/factory.d.ts +30 -0
  49. package/dist/src/openai-compat/bridges/factory.js +84 -0
  50. package/dist/src/openai-compat/bridges/factory.js.map +1 -0
  51. package/dist/src/openai-compat/bridges/media-bridge.d.ts +34 -0
  52. package/dist/src/openai-compat/bridges/media-bridge.js +20 -0
  53. package/dist/src/openai-compat/bridges/media-bridge.js.map +1 -0
  54. package/dist/src/openai-compat/bridges/openclaw-native-tools.d.ts +61 -0
  55. package/dist/src/openai-compat/bridges/openclaw-native-tools.js +171 -0
  56. package/dist/src/openai-compat/bridges/openclaw-native-tools.js.map +1 -0
  57. package/dist/src/openai-compat/bridges/openclaw-tool-registry.d.ts +26 -0
  58. package/dist/src/openai-compat/bridges/openclaw-tool-registry.js +38 -0
  59. package/dist/src/openai-compat/bridges/openclaw-tool-registry.js.map +1 -0
  60. package/dist/src/openai-compat/bridges/tts-media-bridge.d.ts +19 -0
  61. package/dist/src/openai-compat/bridges/tts-media-bridge.js +59 -0
  62. package/dist/src/openai-compat/bridges/tts-media-bridge.js.map +1 -0
  63. package/dist/src/openai-compat/non-streaming-handler.js +52 -3
  64. package/dist/src/openai-compat/non-streaming-handler.js.map +1 -1
  65. package/dist/src/openai-compat/openai-compat.js +64 -2
  66. package/dist/src/openai-compat/openai-compat.js.map +1 -1
  67. package/dist/src/openai-compat/streaming-handler.js +107 -1
  68. package/dist/src/openai-compat/streaming-handler.js.map +1 -1
  69. package/dist/src/openai-compat/voice-recovery.d.ts +56 -0
  70. package/dist/src/openai-compat/voice-recovery.js +231 -0
  71. package/dist/src/openai-compat/voice-recovery.js.map +1 -0
  72. package/dist/src/session/session-manager.d.ts +51 -0
  73. package/dist/src/session/session-manager.js +165 -1
  74. package/dist/src/session/session-manager.js.map +1 -1
  75. package/dist/src/types/tool-bridge.d.ts +2 -1
  76. package/dist/src/types/tool-bridge.js +1 -0
  77. package/dist/src/types/tool-bridge.js.map +1 -1
  78. package/package.json +1 -1
  79. package/dist/scripts/bench/ab-harness.d.ts +0 -58
  80. package/dist/scripts/bench/ab-harness.d.ts.map +0 -1
  81. package/dist/scripts/bench/ab-harness.js +0 -78
  82. package/dist/scripts/bench/ab-harness.js.map +0 -1
  83. package/dist/src/channels/adapter.d.ts.map +0 -1
  84. package/dist/src/channels/telegram/completion-summary.d.ts.map +0 -1
  85. package/dist/src/channels/telegram/error-renderer.d.ts.map +0 -1
  86. package/dist/src/channels/telegram/event-reducer.d.ts.map +0 -1
  87. package/dist/src/channels/telegram/index.d.ts.map +0 -1
  88. package/dist/src/channels/telegram/injector.d.ts.map +0 -1
  89. package/dist/src/channels/telegram/live-card.d.ts.map +0 -1
  90. package/dist/src/channels/telegram/state-machine.d.ts.map +0 -1
  91. package/dist/src/channels/telegram/tool-tracker.d.ts.map +0 -1
  92. package/dist/src/command-router/cc-handler.d.ts.map +0 -1
  93. package/dist/src/command-router/index.d.ts.map +0 -1
  94. package/dist/src/constants.d.ts.map +0 -1
  95. package/dist/src/council/consensus.d.ts.map +0 -1
  96. package/dist/src/council/council.d.ts.map +0 -1
  97. package/dist/src/council/index.d.ts.map +0 -1
  98. package/dist/src/engines/base-oneshot-session.d.ts.map +0 -1
  99. package/dist/src/engines/index.d.ts.map +0 -1
  100. package/dist/src/engines/persistent-codex-session.d.ts.map +0 -1
  101. package/dist/src/engines/persistent-cursor-session.d.ts.map +0 -1
  102. package/dist/src/engines/persistent-custom-session.d.ts.map +0 -1
  103. package/dist/src/engines/persistent-gemini-session.d.ts.map +0 -1
  104. package/dist/src/engines/persistent-session.d.ts.map +0 -1
  105. package/dist/src/health/handler.d.ts.map +0 -1
  106. package/dist/src/health/index.d.ts.map +0 -1
  107. package/dist/src/index.d.ts.map +0 -1
  108. package/dist/src/lib/auto-recovery.d.ts.map +0 -1
  109. package/dist/src/lib/cache-parity.d.ts.map +0 -1
  110. package/dist/src/lib/circuit-breaker.d.ts.map +0 -1
  111. package/dist/src/lib/config.d.ts.map +0 -1
  112. package/dist/src/lib/debug-tap.d.ts.map +0 -1
  113. package/dist/src/lib/drift-detector.d.ts.map +0 -1
  114. package/dist/src/lib/error-formatter.d.ts.map +0 -1
  115. package/dist/src/lib/heartbeat-workaround.d.ts.map +0 -1
  116. package/dist/src/lib/index.d.ts.map +0 -1
  117. package/dist/src/lib/register-guard.d.ts.map +0 -1
  118. package/dist/src/lib/route-flag.d.ts +0 -49
  119. package/dist/src/lib/route-flag.d.ts.map +0 -1
  120. package/dist/src/lib/route-flag.js +0 -52
  121. package/dist/src/lib/route-flag.js.map +0 -1
  122. package/dist/src/lib/sysprompt-strip.d.ts.map +0 -1
  123. package/dist/src/lib/telemetry.d.ts.map +0 -1
  124. package/dist/src/lib/test-mode.d.ts.map +0 -1
  125. package/dist/src/lib/vendor-paths.d.ts.map +0 -1
  126. package/dist/src/logger.d.ts.map +0 -1
  127. package/dist/src/mcp/bridge.d.ts.map +0 -1
  128. package/dist/src/mcp/index.d.ts.map +0 -1
  129. package/dist/src/models.d.ts.map +0 -1
  130. package/dist/src/openai-compat/cli-stream-parser.d.ts.map +0 -1
  131. package/dist/src/openai-compat/index.d.ts.map +0 -1
  132. package/dist/src/openai-compat/openai-compat.d.ts.map +0 -1
  133. package/dist/src/openai-compat/skill-resolver.d.ts.map +0 -1
  134. package/dist/src/openai-compat/sse-translator.d.ts.map +0 -1
  135. package/dist/src/proxy/anthropic-adapter.d.ts.map +0 -1
  136. package/dist/src/proxy/handler.d.ts.map +0 -1
  137. package/dist/src/proxy/index.d.ts.map +0 -1
  138. package/dist/src/proxy/schema-cleaner.d.ts.map +0 -1
  139. package/dist/src/proxy/thought-cache.d.ts.map +0 -1
  140. package/dist/src/session/embedded-server.d.ts.map +0 -1
  141. package/dist/src/session/inbox-manager.d.ts.map +0 -1
  142. package/dist/src/session/index.d.ts.map +0 -1
  143. package/dist/src/session/session-manager.d.ts.map +0 -1
  144. package/dist/src/session-bootstrap/cwd-patch.d.ts.map +0 -1
  145. package/dist/src/session-bootstrap/index.d.ts.map +0 -1
  146. package/dist/src/session-bootstrap/sysprompt-strip.d.ts.map +0 -1
  147. package/dist/src/session-bootstrap/think-conflict-resolver.d.ts.map +0 -1
  148. package/dist/src/types.d.ts.map +0 -1
  149. package/dist/src/validation.d.ts.map +0 -1
  150. package/dist/tests/_helpers/subprocess-mock.d.ts +0 -35
  151. package/dist/tests/_helpers/subprocess-mock.d.ts.map +0 -1
  152. package/dist/tests/_helpers/subprocess-mock.js +0 -136
  153. package/dist/tests/_helpers/subprocess-mock.js.map +0 -1
  154. package/dist/tests/auto-recovery.test.d.ts +0 -2
  155. package/dist/tests/auto-recovery.test.d.ts.map +0 -1
  156. package/dist/tests/auto-recovery.test.js +0 -189
  157. package/dist/tests/auto-recovery.test.js.map +0 -1
  158. package/dist/tests/bench-harness.test.d.ts +0 -2
  159. package/dist/tests/bench-harness.test.d.ts.map +0 -1
  160. package/dist/tests/bench-harness.test.js +0 -21
  161. package/dist/tests/bench-harness.test.js.map +0 -1
  162. package/dist/tests/cache-parity.test.d.ts +0 -2
  163. package/dist/tests/cache-parity.test.d.ts.map +0 -1
  164. package/dist/tests/cache-parity.test.js +0 -401
  165. package/dist/tests/cache-parity.test.js.map +0 -1
  166. package/dist/tests/command-router.test.d.ts +0 -2
  167. package/dist/tests/command-router.test.d.ts.map +0 -1
  168. package/dist/tests/command-router.test.js +0 -60
  169. package/dist/tests/command-router.test.js.map +0 -1
  170. package/dist/tests/council.test.d.ts +0 -2
  171. package/dist/tests/council.test.d.ts.map +0 -1
  172. package/dist/tests/council.test.js +0 -20
  173. package/dist/tests/council.test.js.map +0 -1
  174. package/dist/tests/drift-detector.test.d.ts +0 -2
  175. package/dist/tests/drift-detector.test.d.ts.map +0 -1
  176. package/dist/tests/drift-detector.test.js +0 -268
  177. package/dist/tests/drift-detector.test.js.map +0 -1
  178. package/dist/tests/eager-bootstrap-gating.test.d.ts +0 -9
  179. package/dist/tests/eager-bootstrap-gating.test.d.ts.map +0 -1
  180. package/dist/tests/eager-bootstrap-gating.test.js +0 -97
  181. package/dist/tests/eager-bootstrap-gating.test.js.map +0 -1
  182. package/dist/tests/engines.test.d.ts +0 -2
  183. package/dist/tests/engines.test.d.ts.map +0 -1
  184. package/dist/tests/engines.test.js +0 -8
  185. package/dist/tests/engines.test.js.map +0 -1
  186. package/dist/tests/error-formatter.test.d.ts +0 -2
  187. package/dist/tests/error-formatter.test.d.ts.map +0 -1
  188. package/dist/tests/error-formatter.test.js +0 -220
  189. package/dist/tests/error-formatter.test.js.map +0 -1
  190. package/dist/tests/health.test.d.ts +0 -2
  191. package/dist/tests/health.test.d.ts.map +0 -1
  192. package/dist/tests/health.test.js +0 -110
  193. package/dist/tests/health.test.js.map +0 -1
  194. package/dist/tests/heartbeat-workaround.test.d.ts +0 -2
  195. package/dist/tests/heartbeat-workaround.test.d.ts.map +0 -1
  196. package/dist/tests/heartbeat-workaround.test.js +0 -90
  197. package/dist/tests/heartbeat-workaround.test.js.map +0 -1
  198. package/dist/tests/index.test.d.ts +0 -2
  199. package/dist/tests/index.test.d.ts.map +0 -1
  200. package/dist/tests/index.test.js +0 -7
  201. package/dist/tests/index.test.js.map +0 -1
  202. package/dist/tests/lib-sysprompt-strip.test.d.ts +0 -2
  203. package/dist/tests/lib-sysprompt-strip.test.d.ts.map +0 -1
  204. package/dist/tests/lib-sysprompt-strip.test.js +0 -145
  205. package/dist/tests/lib-sysprompt-strip.test.js.map +0 -1
  206. package/dist/tests/listener-activation.test.d.ts +0 -2
  207. package/dist/tests/listener-activation.test.d.ts.map +0 -1
  208. package/dist/tests/listener-activation.test.js +0 -87
  209. package/dist/tests/listener-activation.test.js.map +0 -1
  210. package/dist/tests/mcp-bridge.test.d.ts +0 -2
  211. package/dist/tests/mcp-bridge.test.d.ts.map +0 -1
  212. package/dist/tests/mcp-bridge.test.js +0 -137
  213. package/dist/tests/mcp-bridge.test.js.map +0 -1
  214. package/dist/tests/openai-compat.test.d.ts +0 -2
  215. package/dist/tests/openai-compat.test.d.ts.map +0 -1
  216. package/dist/tests/openai-compat.test.js +0 -8
  217. package/dist/tests/openai-compat.test.js.map +0 -1
  218. package/dist/tests/proxy-heartbeat-integration.test.d.ts +0 -15
  219. package/dist/tests/proxy-heartbeat-integration.test.d.ts.map +0 -1
  220. package/dist/tests/proxy-heartbeat-integration.test.js +0 -122
  221. package/dist/tests/proxy-heartbeat-integration.test.js.map +0 -1
  222. package/dist/tests/proxy.test.d.ts +0 -2
  223. package/dist/tests/proxy.test.d.ts.map +0 -1
  224. package/dist/tests/proxy.test.js +0 -8
  225. package/dist/tests/proxy.test.js.map +0 -1
  226. package/dist/tests/register-guard-stacking.test.d.ts +0 -2
  227. package/dist/tests/register-guard-stacking.test.d.ts.map +0 -1
  228. package/dist/tests/register-guard-stacking.test.js +0 -61
  229. package/dist/tests/register-guard-stacking.test.js.map +0 -1
  230. package/dist/tests/register-guard.test.d.ts +0 -2
  231. package/dist/tests/register-guard.test.d.ts.map +0 -1
  232. package/dist/tests/register-guard.test.js +0 -129
  233. package/dist/tests/register-guard.test.js.map +0 -1
  234. package/dist/tests/route-flag-rollback.test.d.ts +0 -2
  235. package/dist/tests/route-flag-rollback.test.d.ts.map +0 -1
  236. package/dist/tests/route-flag-rollback.test.js +0 -70
  237. package/dist/tests/route-flag-rollback.test.js.map +0 -1
  238. package/dist/tests/route-flag.test.d.ts +0 -2
  239. package/dist/tests/route-flag.test.d.ts.map +0 -1
  240. package/dist/tests/route-flag.test.js +0 -101
  241. package/dist/tests/route-flag.test.js.map +0 -1
  242. package/dist/tests/session-bootstrap.test.d.ts +0 -2
  243. package/dist/tests/session-bootstrap.test.d.ts.map +0 -1
  244. package/dist/tests/session-bootstrap.test.js +0 -183
  245. package/dist/tests/session-bootstrap.test.js.map +0 -1
  246. package/dist/tests/session.test.d.ts +0 -2
  247. package/dist/tests/session.test.d.ts.map +0 -1
  248. package/dist/tests/session.test.js +0 -17
  249. package/dist/tests/session.test.js.map +0 -1
  250. package/dist/tests/state-machine.test.d.ts +0 -2
  251. package/dist/tests/state-machine.test.d.ts.map +0 -1
  252. package/dist/tests/state-machine.test.js +0 -133
  253. package/dist/tests/state-machine.test.js.map +0 -1
  254. package/dist/tests/streaming/cli-stream-parser.test.d.ts +0 -2
  255. package/dist/tests/streaming/cli-stream-parser.test.d.ts.map +0 -1
  256. package/dist/tests/streaming/cli-stream-parser.test.js +0 -233
  257. package/dist/tests/streaming/cli-stream-parser.test.js.map +0 -1
  258. package/dist/tests/streaming/feature-flag.test.d.ts +0 -14
  259. package/dist/tests/streaming/feature-flag.test.d.ts.map +0 -1
  260. package/dist/tests/streaming/feature-flag.test.js +0 -163
  261. package/dist/tests/streaming/feature-flag.test.js.map +0 -1
  262. package/dist/tests/streaming/no-tools-prompt.test.d.ts +0 -17
  263. package/dist/tests/streaming/no-tools-prompt.test.d.ts.map +0 -1
  264. package/dist/tests/streaming/no-tools-prompt.test.js +0 -229
  265. package/dist/tests/streaming/no-tools-prompt.test.js.map +0 -1
  266. package/dist/tests/streaming/skill-plus-tools.test.d.ts +0 -14
  267. package/dist/tests/streaming/skill-plus-tools.test.d.ts.map +0 -1
  268. package/dist/tests/streaming/skill-plus-tools.test.js +0 -234
  269. package/dist/tests/streaming/skill-plus-tools.test.js.map +0 -1
  270. package/dist/tests/streaming/sse-translator.test.d.ts +0 -2
  271. package/dist/tests/streaming/sse-translator.test.d.ts.map +0 -1
  272. package/dist/tests/streaming/sse-translator.test.js +0 -227
  273. package/dist/tests/streaming/sse-translator.test.js.map +0 -1
  274. package/dist/tests/streaming/tool-result-roundtrip.test.d.ts +0 -11
  275. package/dist/tests/streaming/tool-result-roundtrip.test.d.ts.map +0 -1
  276. package/dist/tests/streaming/tool-result-roundtrip.test.js +0 -215
  277. package/dist/tests/streaming/tool-result-roundtrip.test.js.map +0 -1
  278. package/dist/tests/streaming/tool-use-translation.test.d.ts +0 -10
  279. package/dist/tests/streaming/tool-use-translation.test.d.ts.map +0 -1
  280. package/dist/tests/streaming/tool-use-translation.test.js +0 -251
  281. package/dist/tests/streaming/tool-use-translation.test.js.map +0 -1
  282. package/dist/tests/telegram-bridge.test.d.ts +0 -2
  283. package/dist/tests/telegram-bridge.test.d.ts.map +0 -1
  284. package/dist/tests/telegram-bridge.test.js +0 -17
  285. package/dist/tests/telegram-bridge.test.js.map +0 -1
  286. package/dist/tests/telegram-injector.test.d.ts +0 -2
  287. package/dist/tests/telegram-injector.test.d.ts.map +0 -1
  288. package/dist/tests/telegram-injector.test.js +0 -74
  289. package/dist/tests/telegram-injector.test.js.map +0 -1
  290. package/dist/tests/telemetry.test.d.ts +0 -2
  291. package/dist/tests/telemetry.test.d.ts.map +0 -1
  292. package/dist/tests/telemetry.test.js +0 -405
  293. package/dist/tests/telemetry.test.js.map +0 -1
  294. package/dist/tests/test-mode.test.d.ts +0 -2
  295. package/dist/tests/test-mode.test.d.ts.map +0 -1
  296. package/dist/tests/test-mode.test.js +0 -39
  297. package/dist/tests/test-mode.test.js.map +0 -1
@@ -0,0 +1,236 @@
1
+ /**
2
+ * resume-policy — /cc+ continuation, /cc resume, rehydrate, and turn-extension logic.
3
+ *
4
+ * Extracted from cc-handler.ts (Step 4 of Phase 5 v0.11.0 decomposition).
5
+ * Each public function takes PolicyDeps as its first argument per PRP §7 Q3.
6
+ * cc-handler.ts retains ownership of the sessionManager/activeSessions/logger
7
+ * singletons and threads them in via `_deps()` on every call.
8
+ *
9
+ * Callers MUST verify `sessionManager !== null` before constructing deps:
10
+ * PolicyDeps.sessionManager is typed non-null and these handlers assume it.
11
+ * The "Claude Code handler not ready — try again in a few seconds." response
12
+ * is now produced at the dispatcher in cc-handler.ts.
13
+ */
14
+ import { DEFAULT_CWD, sessionMapKey, saveSession, loadSession, loadSessionById, scanAllSessions, IDLE_TIMEOUT_MS, ACK_TIMEOUT_MS, scheduleIdle, _postTurnContextCheck, } from './launch-policy.js';
15
+ import { sendDirectReply } from './turn-formatter.js';
16
+ const PLUGIN_TAG = '[cc-openclaw/resume-policy]';
17
+ // ── Continuation Handler ──────────────────────────────────────────────────
18
+ export function handleContinuation(deps, prompt, chatId, threadId) {
19
+ const { sessionManager, activeSessions, logger } = deps;
20
+ const key = sessionMapKey(chatId, threadId);
21
+ const active = activeSessions.get(key);
22
+ if (!active) {
23
+ return {
24
+ handled: true,
25
+ text: 'No active session to continue. Start one with /cc <prompt> or /cc resume',
26
+ };
27
+ }
28
+ if (active.needsRehydration) {
29
+ if (!active.meta.claudeSessionId) {
30
+ activeSessions.delete(key);
31
+ return {
32
+ handled: true,
33
+ text: 'Recovered session has no Claude ID — start fresh with /cc <prompt>',
34
+ };
35
+ }
36
+ logger.info(`${PLUGIN_TAG} /cc+ rehydrating recovered session: slug=${active.slug} chat=${chatId} thread=${threadId || 'none'}`);
37
+ let resolveAckId;
38
+ const ackIdPromise = new Promise((r) => {
39
+ resolveAckId = r;
40
+ });
41
+ (async () => {
42
+ try {
43
+ await rehydrateSession(deps, active.meta, chatId, threadId);
44
+ active.needsRehydration = false;
45
+ await continueTurn(deps, active, prompt, chatId, threadId, ackIdPromise);
46
+ }
47
+ catch (err) {
48
+ logger.error(`${PLUGIN_TAG} Rehydrate+continue ${active.slug} failed: ${err instanceof Error ? err.message : String(err)}`);
49
+ scheduleIdle(deps, key, active);
50
+ }
51
+ })();
52
+ return {
53
+ handled: true,
54
+ text: `⏳ [${active.meta.id || '?'}] Resuming & continuing ${active.slug}...`,
55
+ _resolveAckId: resolveAckId,
56
+ };
57
+ }
58
+ try {
59
+ sessionManager.getStatus(active.sessionName);
60
+ }
61
+ catch {
62
+ activeSessions.delete(key);
63
+ return {
64
+ handled: true,
65
+ text: 'Previous session expired. Use /cc resume or start fresh with /cc <prompt>',
66
+ };
67
+ }
68
+ if (active.idleTimer)
69
+ clearTimeout(active.idleTimer);
70
+ logger.info(`${PLUGIN_TAG} /cc+ continuation: slug=${active.slug} chat=${chatId} thread=${threadId || 'none'}`);
71
+ let resolveAckId;
72
+ const ackIdPromise = new Promise((r) => {
73
+ resolveAckId = r;
74
+ });
75
+ continueTurn(deps, active, prompt, chatId, threadId, ackIdPromise).catch((err) => {
76
+ logger.error(`${PLUGIN_TAG} Continuation ${active.slug} failed: ${err instanceof Error ? err.message : String(err)}`);
77
+ scheduleIdle(deps, key, active);
78
+ });
79
+ return {
80
+ handled: true,
81
+ text: `⏳ [${active.meta.id || '?'}] Continuing ${active.slug}...`,
82
+ _resolveAckId: resolveAckId,
83
+ };
84
+ }
85
+ // ── Resume Handler ────────────────────────────────────────────────────────
86
+ export function handleResume(deps, chatId, threadId, targetSlug) {
87
+ const { activeSessions, logger } = deps;
88
+ const key = sessionMapKey(chatId, threadId);
89
+ const currentActive = activeSessions.get(key);
90
+ if (currentActive) {
91
+ return {
92
+ handled: true,
93
+ text: `Already have active session: ${currentActive.slug}\nUse /cc stop first, or /cc+ to continue it.`,
94
+ };
95
+ }
96
+ let meta = null;
97
+ if (targetSlug) {
98
+ const isSessionId = /^[0-9a-f]{8}$/i.test(targetSlug);
99
+ if (isSessionId) {
100
+ meta = loadSessionById(targetSlug.toLowerCase());
101
+ }
102
+ if (!meta) {
103
+ meta = loadSession(targetSlug);
104
+ }
105
+ if (!meta) {
106
+ return { handled: true, text: `Session "${targetSlug}" not found.` };
107
+ }
108
+ if (meta.chatId !== chatId) {
109
+ return {
110
+ handled: true,
111
+ text: `Session "${targetSlug}" belongs to a different chat.`,
112
+ };
113
+ }
114
+ }
115
+ else {
116
+ const candidates = scanAllSessions()
117
+ .filter((s) => s.chatId === chatId &&
118
+ (s.threadId || undefined) === (threadId || undefined) &&
119
+ !!s.claudeSessionId)
120
+ .sort((a, b) => {
121
+ const timeA = new Date(a.lastContinuedAt || a.completedAt || a.startedAt).getTime();
122
+ const timeB = new Date(b.lastContinuedAt || b.completedAt || b.startedAt).getTime();
123
+ return timeB - timeA;
124
+ });
125
+ if (candidates.length === 0) {
126
+ return {
127
+ handled: true,
128
+ text: 'No resumable session found. Start fresh with /cc <prompt>',
129
+ };
130
+ }
131
+ meta = candidates[0];
132
+ }
133
+ if (!meta.claudeSessionId) {
134
+ return {
135
+ handled: true,
136
+ text: `Session ${meta.slug} has no Claude session ID — cannot resume.\nStart fresh with /cc <prompt>`,
137
+ };
138
+ }
139
+ const { slug, id: resumeId } = meta;
140
+ logger.info(`${PLUGIN_TAG} /cc resume: id=${resumeId} slug=${slug} claudeId=${meta.claudeSessionId} chat=${chatId} thread=${threadId || 'none'}`);
141
+ rehydrateSession(deps, meta, chatId, threadId).catch((err) => {
142
+ logger.error(`${PLUGIN_TAG} Resume ${slug} failed: ${err instanceof Error ? err.message : String(err)}`);
143
+ meta.state = 'failed';
144
+ meta.error = `Resume failed: ${err instanceof Error ? err.message : String(err)}`;
145
+ try {
146
+ saveSession(meta);
147
+ }
148
+ catch { /* best effort */ }
149
+ const active = activeSessions.get(key);
150
+ if (active?.slug === slug) {
151
+ if (active.idleTimer)
152
+ clearTimeout(active.idleTimer);
153
+ activeSessions.delete(key);
154
+ }
155
+ });
156
+ return { handled: true, text: `⏳ [${resumeId || '?'}] Resuming ${slug}...` };
157
+ }
158
+ // ── Rehydrate Session ─────────────────────────────────────────────────────
159
+ export async function rehydrateSession(deps, meta, chatId, threadId) {
160
+ const { sessionManager, activeSessions, logger } = deps;
161
+ const { slug, sessionName, claudeSessionId } = meta;
162
+ const key = sessionMapKey(chatId, threadId);
163
+ logger.info(`${PLUGIN_TAG} Rehydrating ${sessionName} with claudeSessionId=${claudeSessionId}...`);
164
+ await sessionManager.startSession({
165
+ name: sessionName,
166
+ cwd: meta.cwd || DEFAULT_CWD,
167
+ engine: 'claude',
168
+ permissionMode: 'bypassPermissions',
169
+ effort: 'high',
170
+ resumeSessionId: claudeSessionId,
171
+ });
172
+ const prevActive = activeSessions.get(key);
173
+ if (prevActive && prevActive.sessionName !== sessionName) {
174
+ if (prevActive.idleTimer)
175
+ clearTimeout(prevActive.idleTimer);
176
+ try {
177
+ await sessionManager.stopSession(prevActive.sessionName);
178
+ }
179
+ catch { /* ignore */ }
180
+ }
181
+ meta.state = 'idle';
182
+ meta.threadId = threadId;
183
+ meta.lastContinuedAt = new Date().toISOString();
184
+ try {
185
+ saveSession(meta);
186
+ }
187
+ catch { /* best effort */ }
188
+ const activeEntry = { sessionName, slug, meta, idleTimer: null };
189
+ activeSessions.set(key, activeEntry);
190
+ logger.info(`${PLUGIN_TAG} Session ${sessionName} resumed — idle for ${IDLE_TIMEOUT_MS / 1000}s`);
191
+ scheduleIdle(deps, key, activeEntry);
192
+ }
193
+ // ── Continuation Turn ─────────────────────────────────────────────────────
194
+ export async function continueTurn(deps, active, prompt, chatId, threadId, ackIdPromise) {
195
+ const { sessionManager, logger } = deps;
196
+ const { sessionName, meta } = active;
197
+ const key = sessionMapKey(chatId, threadId);
198
+ meta.state = 'running';
199
+ try {
200
+ saveSession(meta);
201
+ }
202
+ catch { /* best effort */ }
203
+ const opts = { telegramChatId: chatId };
204
+ if (threadId)
205
+ opts.telegramThreadId = threadId;
206
+ const ackMsgId = await Promise.race([
207
+ ackIdPromise,
208
+ new Promise((r) => setTimeout(() => r(null), ACK_TIMEOUT_MS)),
209
+ ]);
210
+ if (ackMsgId)
211
+ opts.telegramAckMessageId = ackMsgId;
212
+ const result = await sessionManager.sendMessage(sessionName, prompt, opts);
213
+ meta.state = 'idle';
214
+ meta.turns = (meta.turns || 1) + 1;
215
+ meta.lastContinuedAt = new Date().toISOString();
216
+ meta.output = (result?.output || '').slice(0, 2000);
217
+ meta.claudeSessionId = result?.sessionId ?? meta.claudeSessionId;
218
+ try {
219
+ saveSession(meta);
220
+ }
221
+ catch { /* best effort */ }
222
+ // v0.6.0: post-turn context-pressure check (continuation turn).
223
+ void _postTurnContextCheck(deps, sessionName, chatId, threadId);
224
+ // 2026-05-07 FIX — direct answer delivery (continuation turn).
225
+ if (result?.output && chatId) {
226
+ try {
227
+ await sendDirectReply(chatId, threadId, result.output, logger);
228
+ }
229
+ catch (e) {
230
+ logger.warn(`${PLUGIN_TAG} Direct answer delivery failed for ${sessionName} (continuation): ${e instanceof Error ? e.message : String(e)}`);
231
+ }
232
+ }
233
+ logger.info(`${PLUGIN_TAG} Session ${sessionName} turn ${meta.turns} complete`);
234
+ scheduleIdle(deps, key, active);
235
+ }
236
+ //# sourceMappingURL=resume-policy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resume-policy.js","sourceRoot":"","sources":["../../../src/command-router/resume-policy.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * turn-formatter — Telegram direct-send + observability formatting helpers.
3
+ *
4
+ * Extracted from cc-handler.ts (Step 1 of Phase 5 v0.11.0 decomposition).
5
+ * Contains: loadBotToken, telegramApiDirect, sendDirectReply,
6
+ * buildPhase2FlagsLine, buildObservabilityLines.
7
+ */
8
+ export declare function loadBotToken(logger?: Console): void;
9
+ export declare function sendDirectReply(chatId: string, threadId: string | undefined, text: string, logger?: Console): Promise<number | null>;
10
+ /** Returns the current BOT_TOKEN (for callers that need to check if it's set). */
11
+ export declare function hasBotToken(): boolean;
12
+ export declare function buildPhase2FlagsLine(): string;
13
+ /**
14
+ * Pillar C v0.4.0 — compose observability lines for /cc status panel.
15
+ * Reads from Pillar A metrics, Pillar B trajectory tail, and status-tee
16
+ * quota snapshot. Each source is independently fault-tolerant: if one
17
+ * fails, the line shows "?" rather than crashing the panel.
18
+ */
19
+ export declare function buildObservabilityLines(): string;
@@ -0,0 +1,144 @@
1
+ /**
2
+ * turn-formatter — Telegram direct-send + observability formatting helpers.
3
+ *
4
+ * Extracted from cc-handler.ts (Step 1 of Phase 5 v0.11.0 decomposition).
5
+ * Contains: loadBotToken, telegramApiDirect, sendDirectReply,
6
+ * buildPhase2FlagsLine, buildObservabilityLines.
7
+ */
8
+ import * as fs from 'node:fs';
9
+ import { request as httpsRequest } from 'node:https';
10
+ const PLUGIN_TAG = '[cc-openclaw/command-router]';
11
+ const OPENCLAW_CONFIG_PATH = '/home/a1xai/.openclaw/openclaw.json';
12
+ // ── Telegram Direct Send ──────────────────────────────────────────────────
13
+ let BOT_TOKEN = '';
14
+ export function loadBotToken(logger = console) {
15
+ if (BOT_TOKEN)
16
+ return;
17
+ try {
18
+ const raw = fs.readFileSync(OPENCLAW_CONFIG_PATH, 'utf8');
19
+ const cfg = JSON.parse(raw);
20
+ const tg = cfg.channels?.telegram;
21
+ if (tg?.accounts) {
22
+ const acctKey = tg.defaultAccount || 'default';
23
+ const acct = tg.accounts[acctKey] || {};
24
+ BOT_TOKEN = acct.botToken || '';
25
+ }
26
+ if (BOT_TOKEN)
27
+ logger.info(`${PLUGIN_TAG} Bot token loaded for direct replies`);
28
+ }
29
+ catch (err) {
30
+ logger.warn(`${PLUGIN_TAG} Failed to load bot token: ${err instanceof Error ? err.message : String(err)}`);
31
+ }
32
+ }
33
+ function telegramApiDirect(method, params) {
34
+ return new Promise((resolve, reject) => {
35
+ const body = JSON.stringify(params);
36
+ const options = {
37
+ hostname: 'api.telegram.org',
38
+ path: `/bot${BOT_TOKEN}/${method}`,
39
+ method: 'POST',
40
+ headers: {
41
+ 'Content-Type': 'application/json',
42
+ 'Content-Length': Buffer.byteLength(body),
43
+ },
44
+ };
45
+ const req = httpsRequest(options, (res) => {
46
+ let data = '';
47
+ res.on('data', (chunk) => (data += chunk));
48
+ res.on('end', () => {
49
+ try {
50
+ resolve(JSON.parse(data));
51
+ }
52
+ catch {
53
+ resolve({ ok: false });
54
+ }
55
+ });
56
+ });
57
+ req.on('error', reject);
58
+ req.setTimeout(10_000, () => req.destroy(new Error('Telegram API timeout')));
59
+ req.write(body);
60
+ req.end();
61
+ });
62
+ }
63
+ export async function sendDirectReply(chatId, threadId, text, logger = console) {
64
+ if (!BOT_TOKEN || !chatId)
65
+ return null;
66
+ try {
67
+ const params = {
68
+ chat_id: chatId,
69
+ text,
70
+ disable_web_page_preview: true,
71
+ };
72
+ if (threadId)
73
+ params.message_thread_id = Number(threadId);
74
+ const res = await telegramApiDirect('sendMessage', params);
75
+ if (!res.ok) {
76
+ logger.warn(`${PLUGIN_TAG} Direct reply failed: ${JSON.stringify(res.description || res)}`);
77
+ return null;
78
+ }
79
+ return res.result?.message_id ?? null;
80
+ }
81
+ catch (err) {
82
+ logger.warn(`${PLUGIN_TAG} Direct reply error: ${err instanceof Error ? err.message : String(err)}`);
83
+ return null;
84
+ }
85
+ }
86
+ /** Returns the current BOT_TOKEN (for callers that need to check if it's set). */
87
+ export function hasBotToken() {
88
+ return BOT_TOKEN !== '';
89
+ }
90
+ // ── Phase 2 Flags ─────────────────────────────────────────────────────────
91
+ export function buildPhase2FlagsLine() {
92
+ const allowBuiltins = process.env.CC_OPENCLAW_ALLOW_BUILTINS === '1';
93
+ const toolStream = process.env.CC_OPENCLAW_TOOL_STREAM === '1';
94
+ return `Flags: builtins=${allowBuiltins ? 'on' : 'off'} | toolstream=${toolStream ? 'on' : 'off'}`;
95
+ }
96
+ // ── Observability Lines ───────────────────────────────────────────────────
97
+ /**
98
+ * Pillar C v0.4.0 — compose observability lines for /cc status panel.
99
+ * Reads from Pillar A metrics, Pillar B trajectory tail, and status-tee
100
+ * quota snapshot. Each source is independently fault-tolerant: if one
101
+ * fails, the line shows "?" rather than crashing the panel.
102
+ */
103
+ export function buildObservabilityLines() {
104
+ const lines = [];
105
+ // Plan quota (status-tee)
106
+ try {
107
+ // Lazy require so this file remains testable without status-tee
108
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
109
+ const { readQuotaSnapshot, formatQuotaLine } = require('../lib/status-tee-reader.js');
110
+ lines.push(formatQuotaLine(readQuotaSnapshot()));
111
+ }
112
+ catch {
113
+ lines.push('Plan: ?%');
114
+ }
115
+ // Workers + uptime + last error (Pillar A metrics)
116
+ try {
117
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
118
+ const { metricsRegistry } = require('../health/metrics.js');
119
+ const out = metricsRegistry.serializePrometheus();
120
+ const workersMatch = /cc_openclaw_workers (\d+)/.exec(out);
121
+ const uptimeMatch = /cc_openclaw_uptime_seconds (\d+)/.exec(out);
122
+ const lastErrMatch = /cc_openclaw_last_error_seconds (\d+)/.exec(out);
123
+ const errorsMatch = /cc_openclaw_errors_total (\d+)/.exec(out);
124
+ const workers = workersMatch ? workersMatch[1] : '?';
125
+ const uptime = uptimeMatch ? Math.floor(parseInt(uptimeMatch[1], 10) / 60) : '?';
126
+ lines.push(`Workers: ${workers} | Uptime: ${uptime}m`);
127
+ const errCount = errorsMatch ? parseInt(errorsMatch[1], 10) : 0;
128
+ const lastErrTs = lastErrMatch ? parseInt(lastErrMatch[1], 10) : 0;
129
+ if (errCount === 0 || lastErrTs === 0) {
130
+ lines.push('Last error: none');
131
+ }
132
+ else {
133
+ const agoSec = Math.floor(Date.now() / 1000) - lastErrTs;
134
+ const agoLabel = agoSec < 60 ? `${agoSec}s` : agoSec < 3600 ? `${Math.floor(agoSec / 60)}m` : `${Math.floor(agoSec / 3600)}h`;
135
+ lines.push(`Last error: ${agoLabel} ago (${errCount} total)`);
136
+ }
137
+ }
138
+ catch {
139
+ lines.push('Workers: ? | Uptime: ?');
140
+ lines.push('Last error: ?');
141
+ }
142
+ return lines.join('\n');
143
+ }
144
+ //# sourceMappingURL=turn-formatter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"turn-formatter.js","sourceRoot":"","sources":["../../../src/command-router/turn-formatter.ts"],"names":[],"mappings":"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"}
@@ -15,8 +15,39 @@ export declare const GREP_HISTORY_FETCH = 500;
15
15
  export declare const SESSION_READY_TIMEOUT_MS = 30000;
16
16
  /** Fallback delay before checking if proc is alive (resume path) */
17
17
  export declare const SESSION_READY_FALLBACK_MS = 2000;
18
- /** Default timeout for a send() / turn completion */
19
- export declare const TURN_TIMEOUT_MS = 300000;
18
+ /** Default timeout for a send() / turn completion.
19
+ * v0.10.0: bumped 300_000 900_000 to align with the
20
+ * `models.providers.cc-openclaw.timeoutSeconds` outer envelope. The
21
+ * runtime stalled-session watchdog (STALLED_SESSION_KILL_MS) is the real
22
+ * ceiling for stuck subprocesses; this constant just prevents an internal
23
+ * per-turn timeout from firing before the outer wall and silently masking
24
+ * the stall as a "timeout" rather than a watchdog kill. */
25
+ export declare const TURN_TIMEOUT_MS = 900000;
26
+ /** Runtime watchdog threshold for "stuck" sessions. If a session is
27
+ * `isBusy === true` AND its stats.lastActivity hasn't moved in this many
28
+ * ms, the SessionManager watchdog aborts + disposes the session. Mirrors
29
+ * the boot-time orphan reaper in gateway-pm2-wrapper.sh:53-60, but runs
30
+ * continuously on a setInterval. Env-overridable via
31
+ * CC_OPENCLAW_STALLED_KILL_MS. v0.10.0. */
32
+ export declare const STALLED_SESSION_KILL_MS = 180000;
33
+ /** How often the stalled-session watchdog scans the sessions Map. */
34
+ export declare const STALLED_WATCH_INTERVAL_MS = 30000;
35
+ /** Runaway-loop watchdog: max new cc-openclaw subprocess spawns within
36
+ * RUNAWAY_LOOP_WINDOW_MS before the next spawn is refused.
37
+ *
38
+ * Rationale: when OpenClaw's agent-runner re-fires `before_model_resolve`
39
+ * multiple times for one user turn (the 2026-05-11 17:42 incident
40
+ * spawned 4 subprocesses in 60s on session 7be69d1b), the cc-openclaw
41
+ * side has no signal that it's the same conversation — each request
42
+ * carries a fresh runId in the X-Session-Id header, so the existing
43
+ * stalled-session watchdog never fires. This second-dimension
44
+ * watchdog catches runaway loops by spawn rate across the SessionManager.
45
+ *
46
+ * Env override: CC_OPENCLAW_LOOP_MAX_SUBPROCS. Min 2, max 20.
47
+ * v0.10.1. */
48
+ export declare const RUNAWAY_LOOP_MAX_SUBPROCS = 3;
49
+ /** Sliding window for the runaway-loop spawn-rate counter. */
50
+ export declare const RUNAWAY_LOOP_WINDOW_MS = 60000;
20
51
  /** Timeout for compact / context summary operations */
21
52
  export declare const COMPACT_TIMEOUT_MS = 60000;
22
53
  /** Delay before SIGKILL after initial SIGTERM on stop() */
@@ -18,8 +18,39 @@ export const GREP_HISTORY_FETCH = 500;
18
18
  export const SESSION_READY_TIMEOUT_MS = 30_000;
19
19
  /** Fallback delay before checking if proc is alive (resume path) */
20
20
  export const SESSION_READY_FALLBACK_MS = 2_000;
21
- /** Default timeout for a send() / turn completion */
22
- export const TURN_TIMEOUT_MS = 300_000;
21
+ /** Default timeout for a send() / turn completion.
22
+ * v0.10.0: bumped 300_000 → 900_000 to align with the
23
+ * `models.providers.cc-openclaw.timeoutSeconds` outer envelope. The
24
+ * runtime stalled-session watchdog (STALLED_SESSION_KILL_MS) is the real
25
+ * ceiling for stuck subprocesses; this constant just prevents an internal
26
+ * per-turn timeout from firing before the outer wall and silently masking
27
+ * the stall as a "timeout" rather than a watchdog kill. */
28
+ export const TURN_TIMEOUT_MS = 900_000;
29
+ /** Runtime watchdog threshold for "stuck" sessions. If a session is
30
+ * `isBusy === true` AND its stats.lastActivity hasn't moved in this many
31
+ * ms, the SessionManager watchdog aborts + disposes the session. Mirrors
32
+ * the boot-time orphan reaper in gateway-pm2-wrapper.sh:53-60, but runs
33
+ * continuously on a setInterval. Env-overridable via
34
+ * CC_OPENCLAW_STALLED_KILL_MS. v0.10.0. */
35
+ export const STALLED_SESSION_KILL_MS = 180_000;
36
+ /** How often the stalled-session watchdog scans the sessions Map. */
37
+ export const STALLED_WATCH_INTERVAL_MS = 30_000;
38
+ /** Runaway-loop watchdog: max new cc-openclaw subprocess spawns within
39
+ * RUNAWAY_LOOP_WINDOW_MS before the next spawn is refused.
40
+ *
41
+ * Rationale: when OpenClaw's agent-runner re-fires `before_model_resolve`
42
+ * multiple times for one user turn (the 2026-05-11 17:42 incident
43
+ * spawned 4 subprocesses in 60s on session 7be69d1b), the cc-openclaw
44
+ * side has no signal that it's the same conversation — each request
45
+ * carries a fresh runId in the X-Session-Id header, so the existing
46
+ * stalled-session watchdog never fires. This second-dimension
47
+ * watchdog catches runaway loops by spawn rate across the SessionManager.
48
+ *
49
+ * Env override: CC_OPENCLAW_LOOP_MAX_SUBPROCS. Min 2, max 20.
50
+ * v0.10.1. */
51
+ export const RUNAWAY_LOOP_MAX_SUBPROCS = 3;
52
+ /** Sliding window for the runaway-loop spawn-rate counter. */
53
+ export const RUNAWAY_LOOP_WINDOW_MS = 60_000;
23
54
  /** Timeout for compact / context summary operations */
24
55
  export const COMPACT_TIMEOUT_MS = 60_000;
25
56
  /** Delay before SIGKILL after initial SIGTERM on stop() */
@@ -1 +1 @@
1
- {"version":3,"file":"constants.js","sourceRoot":"","sources":["../../src/constants.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"constants.js","sourceRoot":"","sources":["../../src/constants.ts"],"names":[],"mappings":"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"}
@@ -53,6 +53,9 @@ export declare function getGeminiApiKey(): string | undefined;
53
53
  export declare function getGeminiBin(): string | undefined;
54
54
  export declare function getCodexBin(): string | undefined;
55
55
  export declare function getCursorBin(): string | undefined;
56
+ export declare function getTtsAutoMode(): 'off' | 'always' | 'inbound' | 'tagged';
57
+ /** Test-only: reset the TTS auto-mode cache so the next call re-reads. */
58
+ export declare function _resetTtsAutoModeCacheForTests(): void;
56
59
  export declare function getClaudeBin(): string | undefined;
57
60
  /**
58
61
  * PATH passed to spawned engine subprocesses. Falls back to the standard
@@ -23,6 +23,9 @@
23
23
  * `src/lib/route-flag.ts`. Cluster F (v1.0.0) will remove the legacy
24
24
  * env-read fallback and hard-fail when ConfigService is missing.
25
25
  */
26
+ import { readFileSync } from 'node:fs';
27
+ import { join } from 'node:path';
28
+ import { homedir } from 'node:os';
26
29
  import { RATE_LIMIT_MAX_REQUESTS } from '../constants.js';
27
30
  import { getConfigService } from './config-service.js';
28
31
  // ── Sysprompt strip (PRP_v3 §10) ─────────────────────────────────────────
@@ -202,6 +205,49 @@ export function getCursorBin() {
202
205
  const v = process.env.CURSOR_BIN;
203
206
  return v === undefined || v === '' ? undefined : v;
204
207
  }
208
+ // ── TTS auto-mode (v0.10.2) ─────────────────────────────────────────────────
209
+ // Reads `messages.tts.auto` from `~/.openclaw/openclaw.json` once and caches
210
+ // the result. Used by openai-compat to gate the auto-prepended TTS-syntax
211
+ // rule on `appendSystemPrompt`. Valid values match OpenClaw's TTS_AUTO_MODES
212
+ // enum: 'off' | 'always' | 'inbound' | 'tagged'. Unknown values / missing
213
+ // file → 'off' (safe default — rule is gated off).
214
+ //
215
+ // Why a custom file reader instead of ConfigService: cc-openclaw is loaded
216
+ // into OpenClaw's gateway process but exposes its own
217
+ // `~/.openclaw/openclaw.json` parsing for plugin-side decisions that
218
+ // shouldn't reach back through OpenClaw's typed runtime. Tests that need
219
+ // to override should set OPENCLAW_TTS_AUTO_MODE env var.
220
+ let _ttsAutoModeCache = null;
221
+ let _ttsAutoModeCacheChecked = false;
222
+ export function getTtsAutoMode() {
223
+ // Test-time override takes precedence
224
+ const envOverride = process.env.OPENCLAW_TTS_AUTO_MODE?.trim().toLowerCase();
225
+ if (envOverride === 'off' || envOverride === 'always' || envOverride === 'inbound' || envOverride === 'tagged') {
226
+ return envOverride;
227
+ }
228
+ if (!_ttsAutoModeCacheChecked) {
229
+ _ttsAutoModeCacheChecked = true;
230
+ try {
231
+ const configPath = process.env.OPENCLAW_CONFIG_PATH || join(homedir(), '.openclaw', 'openclaw.json');
232
+ const raw = readFileSync(configPath, 'utf8');
233
+ const parsed = JSON.parse(raw);
234
+ _ttsAutoModeCache = parsed.messages?.tts?.auto ?? null;
235
+ }
236
+ catch {
237
+ // File missing / unreadable / invalid JSON — fall through to 'off'
238
+ _ttsAutoModeCache = null;
239
+ }
240
+ }
241
+ const value = (_ttsAutoModeCache ?? 'off').toLowerCase();
242
+ if (value === 'always' || value === 'inbound' || value === 'tagged')
243
+ return value;
244
+ return 'off';
245
+ }
246
+ /** Test-only: reset the TTS auto-mode cache so the next call re-reads. */
247
+ export function _resetTtsAutoModeCacheForTests() {
248
+ _ttsAutoModeCache = null;
249
+ _ttsAutoModeCacheChecked = false;
250
+ }
205
251
  export function getClaudeBin() {
206
252
  const cfg = getConfigService();
207
253
  if (cfg)