@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
@@ -1,61 +0,0 @@
1
- import { describe, it, expect, vi } from 'vitest';
2
- import { createRegisterGuard, defaultRegisterGuard } from '../src/lib/register-guard.js';
3
- describe('register-guard 1,000-cycle stacking proof', () => {
4
- it('PRP NFR: same api repeated 1,000 times → exactly 1 body invocation', () => {
5
- const guard = createRegisterGuard();
6
- const body = vi.fn();
7
- const api = { on: vi.fn() };
8
- for (let i = 0; i < 1000; i++) {
9
- guard.guard('test/module', api, body);
10
- }
11
- expect(body).toHaveBeenCalledTimes(1);
12
- });
13
- it('1,000 alternating new-api cycles → exactly 1 body invocation (id-only tracking, prevents listener stacking across plugin contexts)', () => {
14
- // Production reality (observed 2026-04-29): the openclaw gateway calls
15
- // register() multiple times per process — once per plugin context
16
- // (gateway thread, per-agent thread). Each context passes a different
17
- // `api` instance, but every api wraps the SAME shared event bus.
18
- // Re-firing on new api would stack listeners N× → duplicate emissions
19
- // (the doubled-greeting bug). We track by id only.
20
- const guard = createRegisterGuard();
21
- const body = vi.fn();
22
- for (let i = 0; i < 1000; i++) {
23
- const freshApi = { on: vi.fn() };
24
- guard.guard('test/module', freshApi, body);
25
- }
26
- expect(body).toHaveBeenCalledTimes(1);
27
- });
28
- it('1,000 cycles: api.on() never accumulates listeners on same api', () => {
29
- const guard = createRegisterGuard();
30
- const api = { on: vi.fn() };
31
- for (let i = 0; i < 1000; i++) {
32
- guard.guard('test/module', api, () => {
33
- api.on('event', () => { });
34
- });
35
- }
36
- // Body ran once → exactly 1 api.on() call total
37
- expect(api.on).toHaveBeenCalledTimes(1);
38
- });
39
- it('multi-id 1,000-cycle test: 5 module ids × 200 cycles each = 5 unique body calls per module', () => {
40
- const guard = createRegisterGuard();
41
- const bodies = Array.from({ length: 5 }, () => vi.fn());
42
- const api = { on: vi.fn() };
43
- for (let cycle = 0; cycle < 200; cycle++) {
44
- for (let i = 0; i < 5; i++) {
45
- guard.guard(`module/${i}`, api, bodies[i]);
46
- }
47
- }
48
- bodies.forEach((b) => expect(b).toHaveBeenCalledTimes(1));
49
- });
50
- it('defaultRegisterGuard singleton: 1,000 cycles same id+api → 1 body call', () => {
51
- defaultRegisterGuard._resetForTests();
52
- const body = vi.fn();
53
- const api = { on: vi.fn() };
54
- for (let i = 0; i < 1000; i++) {
55
- defaultRegisterGuard.guard('singleton-test', api, body);
56
- }
57
- expect(body).toHaveBeenCalledTimes(1);
58
- defaultRegisterGuard._resetForTests();
59
- });
60
- });
61
- //# sourceMappingURL=register-guard-stacking.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"register-guard-stacking.test.js","sourceRoot":"","sources":["../../tests/register-guard-stacking.test.ts"],"names":[],"mappings":"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"}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=register-guard.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"register-guard.test.d.ts","sourceRoot":"","sources":["../../tests/register-guard.test.ts"],"names":[],"mappings":""}
@@ -1,129 +0,0 @@
1
- import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
2
- import { createRegisterGuard, defaultRegisterGuard } from '../src/lib/register-guard.js';
3
- describe('createRegisterGuard()', () => {
4
- it('runs body on first call with given (id, api)', () => {
5
- const guard = createRegisterGuard();
6
- const body = vi.fn();
7
- guard.guard('test-id', { on: vi.fn() }, body);
8
- expect(body).toHaveBeenCalledOnce();
9
- });
10
- it('skips body on second call with same (id, api)', () => {
11
- const guard = createRegisterGuard();
12
- const body = vi.fn();
13
- const api = { on: vi.fn() };
14
- guard.guard('test-id', api, body);
15
- guard.guard('test-id', api, body);
16
- expect(body).toHaveBeenCalledOnce();
17
- });
18
- it('skips body when api changes for same id (id-only tracking — production-correct, prevents listener stacking across plugin contexts)', () => {
19
- const guard = createRegisterGuard();
20
- const body = vi.fn();
21
- guard.guard('test-id', { on: vi.fn() }, body);
22
- guard.guard('test-id', { on: vi.fn() }, body);
23
- expect(body).toHaveBeenCalledTimes(1);
24
- });
25
- it('isolates registration state by id', () => {
26
- const guard = createRegisterGuard();
27
- const body = vi.fn();
28
- const api = { on: vi.fn() };
29
- guard.guard('id-a', api, body);
30
- guard.guard('id-b', api, body);
31
- expect(body).toHaveBeenCalledTimes(2);
32
- });
33
- it('isRegistered() reports state per id', () => {
34
- const guard = createRegisterGuard();
35
- expect(guard.isRegistered('x')).toBe(false);
36
- guard.guard('x', { on: vi.fn() }, () => { });
37
- expect(guard.isRegistered('x')).toBe(true);
38
- });
39
- it('_resetForTests() clears all state', () => {
40
- const guard = createRegisterGuard();
41
- guard.guard('x', { on: vi.fn() }, () => { });
42
- guard._resetForTests();
43
- expect(guard.isRegistered('x')).toBe(false);
44
- });
45
- it('1,000-cycle stacking test — register-guard fires body exactly once', () => {
46
- const guard = createRegisterGuard();
47
- const body = vi.fn();
48
- const api = { on: vi.fn() };
49
- for (let i = 0; i < 1000; i++) {
50
- guard.guard('stress', api, body);
51
- }
52
- expect(body).toHaveBeenCalledOnce();
53
- });
54
- describe('OPENCLAW_REGISTER_DEBUG=1 telemetry emit', () => {
55
- const origDebug = process.env.OPENCLAW_REGISTER_DEBUG;
56
- beforeEach(() => {
57
- process.env.OPENCLAW_REGISTER_DEBUG = '1';
58
- });
59
- afterEach(() => {
60
- if (origDebug === undefined)
61
- delete process.env.OPENCLAW_REGISTER_DEBUG;
62
- else
63
- process.env.OPENCLAW_REGISTER_DEBUG = origDebug;
64
- });
65
- it('emits register-guard.fire event to stderr on first registration', () => {
66
- const stderrSpy = vi.spyOn(process.stderr, 'write').mockImplementation(() => true);
67
- const guard = createRegisterGuard();
68
- guard.guard('debug-fire', { on: vi.fn() }, () => { });
69
- expect(stderrSpy).toHaveBeenCalledOnce();
70
- const written = stderrSpy.mock.calls[0][0];
71
- const payload = JSON.parse(written.trim());
72
- expect(payload.type).toBe('register-guard.fire');
73
- expect(payload.id).toBe('debug-fire');
74
- expect(payload.ts).toMatch(/^\d{4}-\d{2}-\d{2}T/);
75
- stderrSpy.mockRestore();
76
- });
77
- it('emits register-guard.skip event to stderr on duplicate same-api call', () => {
78
- const guard = createRegisterGuard();
79
- const api = { on: vi.fn() };
80
- // First call — registers (fire event)
81
- guard.guard('debug-skip', api, () => { });
82
- const stderrSpy = vi.spyOn(process.stderr, 'write').mockImplementation(() => true);
83
- // Second call with same api — should emit skip
84
- guard.guard('debug-skip', api, () => { });
85
- expect(stderrSpy).toHaveBeenCalledOnce();
86
- const written = stderrSpy.mock.calls[0][0];
87
- const payload = JSON.parse(written.trim());
88
- expect(payload.type).toBe('register-guard.skip');
89
- expect(payload.id).toBe('debug-skip');
90
- expect(payload.reason).toBe('already-registered');
91
- stderrSpy.mockRestore();
92
- });
93
- it('emits register-guard.skip on re-registration with new api (id-only tracking)', () => {
94
- const guard = createRegisterGuard();
95
- // First registration — consumes the first fire event
96
- guard.guard('debug-refire', { on: vi.fn() }, () => { });
97
- const stderrSpy = vi.spyOn(process.stderr, 'write').mockImplementation(() => true);
98
- // Second registration with NEW api — should skip (id-only semantics)
99
- guard.guard('debug-refire', { on: vi.fn() }, () => { });
100
- expect(stderrSpy).toHaveBeenCalledOnce();
101
- const written = stderrSpy.mock.calls[0][0];
102
- const payload = JSON.parse(written.trim());
103
- expect(payload.type).toBe('register-guard.skip');
104
- expect(payload.id).toBe('debug-refire');
105
- expect(payload.reason).toBe('already-registered');
106
- stderrSpy.mockRestore();
107
- });
108
- it('does NOT emit to stderr when OPENCLAW_REGISTER_DEBUG is unset', () => {
109
- delete process.env.OPENCLAW_REGISTER_DEBUG;
110
- const stderrSpy = vi.spyOn(process.stderr, 'write').mockImplementation(() => true);
111
- const guard = createRegisterGuard();
112
- const api = { on: vi.fn() };
113
- guard.guard('no-debug', api, () => { });
114
- guard.guard('no-debug', api, () => { }); // skip path
115
- expect(stderrSpy).not.toHaveBeenCalled();
116
- stderrSpy.mockRestore();
117
- });
118
- });
119
- });
120
- describe('defaultRegisterGuard singleton', () => {
121
- beforeEach(() => { defaultRegisterGuard._resetForTests(); });
122
- it('exists and is usable', () => {
123
- expect(defaultRegisterGuard).toBeDefined();
124
- const body = vi.fn();
125
- defaultRegisterGuard.guard('singleton-test', {}, body);
126
- expect(body).toHaveBeenCalledOnce();
127
- });
128
- });
129
- //# sourceMappingURL=register-guard.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"register-guard.test.js","sourceRoot":"","sources":["../../tests/register-guard.test.ts"],"names":[],"mappings":"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"}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=route-flag-rollback.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"route-flag-rollback.test.d.ts","sourceRoot":"","sources":["../../tests/route-flag-rollback.test.ts"],"names":[],"mappings":""}
@@ -1,70 +0,0 @@
1
- import { describe, it, expect, beforeEach, afterEach } from 'vitest';
2
- import { selectEngine, captureSessionRoute, ROUTE_FLAG_ENV, } from '../src/lib/route-flag.js';
3
- describe('route-flag mid-session rollback (PRP backward-compat #4)', () => {
4
- const original = process.env[ROUTE_FLAG_ENV];
5
- beforeEach(() => { delete process.env[ROUTE_FLAG_ENV]; });
6
- afterEach(() => { process.env[ROUTE_FLAG_ENV] = original; });
7
- it('observes env AT CALL TIME (no caching) — flip mid-loop reflects immediately', () => {
8
- const observations = [];
9
- process.env[ROUTE_FLAG_ENV] = '1';
10
- observations.push(selectEngine());
11
- delete process.env[ROUTE_FLAG_ENV];
12
- observations.push(selectEngine());
13
- process.env[ROUTE_FLAG_ENV] = '1';
14
- observations.push(selectEngine());
15
- expect(observations).toEqual(['cc-openclaw', 'claude-local', 'cc-openclaw']);
16
- });
17
- it('captureSessionRoute pins engine at start; later env flips do NOT change snapshot', () => {
18
- process.env[ROUTE_FLAG_ENV] = '1';
19
- const route = captureSessionRoute();
20
- expect(route.engine).toBe('cc-openclaw');
21
- // Simulate operator flipping the env mid-session
22
- delete process.env[ROUTE_FLAG_ENV];
23
- expect(route.engine).toBe('cc-openclaw'); // captured value preserved
24
- expect(selectEngine()).toBe('claude-local'); // but new sessions see new value
25
- });
26
- it('100 alternating flips: env oscillation is correctly observed', () => {
27
- const results = [];
28
- for (let i = 0; i < 100; i++) {
29
- if (i % 2 === 0)
30
- process.env[ROUTE_FLAG_ENV] = '1';
31
- else
32
- delete process.env[ROUTE_FLAG_ENV];
33
- results.push(selectEngine());
34
- }
35
- const unique = [...new Set(results)];
36
- expect(unique).toEqual(expect.arrayContaining(['cc-openclaw', 'claude-local']));
37
- expect(results[0]).toBe('cc-openclaw');
38
- expect(results[1]).toBe('claude-local');
39
- });
40
- it('rollback scenario: 5 sessions captured under cc-openclaw, then flag flipped — all 5 still report cc-openclaw', () => {
41
- process.env[ROUTE_FLAG_ENV] = '1';
42
- const sessions = Array.from({ length: 5 }, () => captureSessionRoute());
43
- delete process.env[ROUTE_FLAG_ENV];
44
- for (const s of sessions) {
45
- expect(s.engine).toBe('cc-openclaw');
46
- }
47
- expect(selectEngine()).toBe('claude-local');
48
- });
49
- it('rollback scenario: P0/P1 incident — flip env=0, new sessions instantly route to claude-local', () => {
50
- // Simulate P0 incident response per PRP "Rollback Procedure":
51
- // 1. Within session boundary: set OPENCLAW_USE_CC_OPENCLAW=0; new sessions route to claude-local. No restart needed.
52
- process.env[ROUTE_FLAG_ENV] = '1';
53
- const before = selectEngine();
54
- expect(before).toBe('cc-openclaw');
55
- // Operator response — flip env
56
- process.env[ROUTE_FLAG_ENV] = '0';
57
- const after = selectEngine();
58
- expect(after).toBe('claude-local');
59
- // Rollback verified: instant within-session-boundary (next selectEngine() call)
60
- });
61
- it('captureSessionRoute snapshots are independent — concurrent sessions see their own pinned engine', () => {
62
- process.env[ROUTE_FLAG_ENV] = '1';
63
- const sessionA = captureSessionRoute();
64
- delete process.env[ROUTE_FLAG_ENV];
65
- const sessionB = captureSessionRoute();
66
- expect(sessionA.engine).toBe('cc-openclaw');
67
- expect(sessionB.engine).toBe('claude-local');
68
- });
69
- });
70
- //# sourceMappingURL=route-flag-rollback.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"route-flag-rollback.test.js","sourceRoot":"","sources":["../../tests/route-flag-rollback.test.ts"],"names":[],"mappings":"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"}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=route-flag.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"route-flag.test.d.ts","sourceRoot":"","sources":["../../tests/route-flag.test.ts"],"names":[],"mappings":""}
@@ -1,101 +0,0 @@
1
- import { describe, it, expect, beforeEach, afterEach } from 'vitest';
2
- import { selectEngine, isCcOpenclawEnabled, captureSessionRoute, ACTIVE_FLAG_ENV, ROUTE_FLAG_ENV, } from '../src/lib/route-flag.js';
3
- describe('route-flag basic semantics', () => {
4
- const original = process.env[ROUTE_FLAG_ENV];
5
- const originalActive = process.env[ACTIVE_FLAG_ENV];
6
- beforeEach(() => {
7
- delete process.env[ROUTE_FLAG_ENV];
8
- delete process.env[ACTIVE_FLAG_ENV];
9
- });
10
- afterEach(() => {
11
- process.env[ROUTE_FLAG_ENV] = original;
12
- process.env[ACTIVE_FLAG_ENV] = originalActive;
13
- });
14
- it("default 'claude-local' when env unset", () => {
15
- expect(selectEngine()).toBe('claude-local');
16
- });
17
- it("'cc-openclaw' when env='1'", () => {
18
- process.env[ROUTE_FLAG_ENV] = '1';
19
- expect(selectEngine()).toBe('cc-openclaw');
20
- });
21
- it("'cc-openclaw' when env='true' (case-insensitive)", () => {
22
- process.env[ROUTE_FLAG_ENV] = 'TRUE';
23
- expect(selectEngine()).toBe('cc-openclaw');
24
- });
25
- it("'cc-openclaw' when env='on' (case-insensitive)", () => {
26
- process.env[ROUTE_FLAG_ENV] = 'ON';
27
- expect(selectEngine()).toBe('cc-openclaw');
28
- });
29
- it("'claude-local' when env='0'", () => {
30
- process.env[ROUTE_FLAG_ENV] = '0';
31
- expect(selectEngine()).toBe('claude-local');
32
- });
33
- it("'claude-local' for any non-truthy value", () => {
34
- for (const v of ['', 'no', 'off', 'false', 'random']) {
35
- process.env[ROUTE_FLAG_ENV] = v;
36
- expect(selectEngine()).toBe('claude-local');
37
- }
38
- });
39
- it('isCcOpenclawEnabled() matches selectEngine logic', () => {
40
- expect(isCcOpenclawEnabled()).toBe(false);
41
- process.env[ROUTE_FLAG_ENV] = '1';
42
- expect(isCcOpenclawEnabled()).toBe(true);
43
- });
44
- it('captureSessionRoute returns frozen snapshot', () => {
45
- const route = captureSessionRoute();
46
- expect(Object.isFrozen(route)).toBe(true);
47
- expect(route.engine).toBe('claude-local');
48
- expect(route.capturedAt).toMatch(/^\d{4}-\d{2}-\d{2}T/);
49
- });
50
- });
51
- describe('route-flag B3 — ACTIVE_FLAG_ENV (new) + ROUTE_FLAG_ENV (deprecated alias)', () => {
52
- const original = process.env[ROUTE_FLAG_ENV];
53
- const originalActive = process.env[ACTIVE_FLAG_ENV];
54
- beforeEach(() => {
55
- delete process.env[ROUTE_FLAG_ENV];
56
- delete process.env[ACTIVE_FLAG_ENV];
57
- });
58
- afterEach(() => {
59
- process.env[ROUTE_FLAG_ENV] = original;
60
- process.env[ACTIVE_FLAG_ENV] = originalActive;
61
- });
62
- it('exports ACTIVE_FLAG_ENV with the v3 §10 contract name', () => {
63
- expect(ACTIVE_FLAG_ENV).toBe('OPENCLAW_CC_OPENCLAW_ACTIVE');
64
- });
65
- it('exports ROUTE_FLAG_ENV unchanged (deprecated alias)', () => {
66
- expect(ROUTE_FLAG_ENV).toBe('OPENCLAW_USE_CC_OPENCLAW');
67
- });
68
- it("'cc-openclaw' when only ACTIVE_FLAG_ENV is set", () => {
69
- process.env[ACTIVE_FLAG_ENV] = '1';
70
- expect(selectEngine()).toBe('cc-openclaw');
71
- expect(isCcOpenclawEnabled()).toBe(true);
72
- });
73
- it("'cc-openclaw' when only deprecated ROUTE_FLAG_ENV is set (alias still honored)", () => {
74
- process.env[ROUTE_FLAG_ENV] = '1';
75
- expect(selectEngine()).toBe('cc-openclaw');
76
- expect(isCcOpenclawEnabled()).toBe(true);
77
- });
78
- it("ACTIVE_FLAG_ENV takes precedence — new=0 wins over deprecated=1", () => {
79
- process.env[ACTIVE_FLAG_ENV] = '0';
80
- process.env[ROUTE_FLAG_ENV] = '1';
81
- expect(selectEngine()).toBe('claude-local');
82
- expect(isCcOpenclawEnabled()).toBe(false);
83
- });
84
- it("ACTIVE_FLAG_ENV takes precedence — new=1 wins over deprecated=0", () => {
85
- process.env[ACTIVE_FLAG_ENV] = '1';
86
- process.env[ROUTE_FLAG_ENV] = '0';
87
- expect(selectEngine()).toBe('cc-openclaw');
88
- expect(isCcOpenclawEnabled()).toBe(true);
89
- });
90
- it("falls through to deprecated alias only when ACTIVE_FLAG_ENV is undefined (not empty)", () => {
91
- process.env[ACTIVE_FLAG_ENV] = '';
92
- process.env[ROUTE_FLAG_ENV] = '1';
93
- // Empty string → falsy → returns false; does NOT fall through
94
- expect(selectEngine()).toBe('claude-local');
95
- });
96
- it('default claude-local when both are unset', () => {
97
- expect(selectEngine()).toBe('claude-local');
98
- expect(isCcOpenclawEnabled()).toBe(false);
99
- });
100
- });
101
- //# sourceMappingURL=route-flag.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"route-flag.test.js","sourceRoot":"","sources":["../../tests/route-flag.test.ts"],"names":[],"mappings":"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"}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=session-bootstrap.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"session-bootstrap.test.d.ts","sourceRoot":"","sources":["../../tests/session-bootstrap.test.ts"],"names":[],"mappings":""}
@@ -1,183 +0,0 @@
1
- import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
2
- import { registerCwdPatch, registerSyspromptStrip, registerThinkConflictResolver, stripSysprompt } from '../src/session-bootstrap/index.js';
3
- import { defaultRegisterGuard } from '../src/lib/register-guard.js';
4
- import { register as registerSyspromptStripDirect } from '../src/session-bootstrap/sysprompt-strip.js';
5
- describe('session-bootstrap registers', () => {
6
- it('cwd-patch registers service without throwing', () => {
7
- const on = vi.fn();
8
- const registerService = vi.fn();
9
- expect(() => registerCwdPatch({ on, registerService })).not.toThrow();
10
- // cwd-patch wires prototype patches (not api.on() hooks) + registers a lifecycle service
11
- expect(registerService).toHaveBeenCalledWith(expect.objectContaining({ id: 'claude-local-enhancer' }));
12
- });
13
- it('sysprompt-strip is callable (env-gated wiring)', () => {
14
- const on = vi.fn();
15
- expect(() => registerSyspromptStrip({ on })).not.toThrow();
16
- expect(on).toHaveBeenCalledWith('before_prompt_build', expect.any(Function));
17
- });
18
- it('think-conflict-resolver wires handlers', () => {
19
- const on = vi.fn();
20
- registerThinkConflictResolver({ on });
21
- expect(on).toHaveBeenCalled();
22
- // Expects: before_dispatch (think) + before_prompt_build (think) +
23
- // before_dispatch (CoS) + before_prompt_build (CoS) = 4 hooks
24
- expect(on).toHaveBeenCalledTimes(4);
25
- });
26
- });
27
- describe('stripSysprompt (pure function)', () => {
28
- it('returns unchanged when nothing to strip', () => {
29
- const result = stripSysprompt('hello world');
30
- expect(result.content).toBe('hello world');
31
- expect(result.changed).toBe(false);
32
- expect(result.aggressiveStripped).toBe(false);
33
- });
34
- it('strips SELF_IMPROVEMENT_REMINDER filename marker', () => {
35
- const input = 'before\n## SELF_IMPROVEMENT_REMINDER.md\nafter';
36
- const result = stripSysprompt(input);
37
- expect(result.content).not.toContain('SELF_IMPROVEMENT_REMINDER.md');
38
- expect(result.changed).toBe(true);
39
- });
40
- it('strips Self-Improvement Reminder block', () => {
41
- const input = 'before\n## Self-Improvement Reminder\nsome content\n## Next Section\nafter';
42
- const result = stripSysprompt(input);
43
- expect(result.content).not.toContain('Self-Improvement Reminder');
44
- expect(result.content).toContain('## Next Section');
45
- expect(result.changed).toBe(true);
46
- });
47
- it('strips <location> lines from skills catalog', () => {
48
- const input = 'catalog\n <location>/home/user/.openclaw/skills/foo/SKILL.md</location>\nend';
49
- const result = stripSysprompt(input);
50
- expect(result.content).not.toContain('<location>');
51
- expect(result.changed).toBe(true);
52
- });
53
- it('aggressive: strips Tool escalation block (forceEnabled)', () => {
54
- const input = 'before\n**Tool escalation:**\n1. do this\n2. do that\n**Scope selection rule:**\nafter';
55
- const result = stripSysprompt(input, { forceEnabled: true });
56
- expect(result.content).not.toContain('Tool escalation');
57
- expect(result.aggressiveStripped).toBe(true);
58
- });
59
- it('aggressive: does not strip when no match (forceEnabled)', () => {
60
- const result = stripSysprompt('clean content', { forceEnabled: true });
61
- expect(result.aggressiveStripped).toBe(false);
62
- expect(result.changed).toBe(false);
63
- });
64
- });
65
- describe('idempotency guards', () => {
66
- it('cwd-patch is idempotent on same api', () => {
67
- const on = vi.fn();
68
- const registerService = vi.fn();
69
- const api = { on, registerService };
70
- // First call already registered above in previous test (different api object),
71
- // so use a fresh module state by passing a new api object.
72
- // The guard checks same api reference — calling with the same object twice logs warn.
73
- registerCwdPatch(api);
74
- const callsAfterFirst = on.mock.calls.length;
75
- registerCwdPatch(api);
76
- // No additional on() calls after the second register (idempotency guard fired)
77
- expect(on.mock.calls.length).toBe(callsAfterFirst);
78
- });
79
- it('sysprompt-strip is idempotent on same api', () => {
80
- const on = vi.fn();
81
- const api = { on };
82
- registerSyspromptStrip(api);
83
- const callsAfterFirst = on.mock.calls.length;
84
- registerSyspromptStrip(api);
85
- expect(on.mock.calls.length).toBe(callsAfterFirst);
86
- });
87
- it('think-conflict-resolver is idempotent on same api', () => {
88
- const on = vi.fn();
89
- const api = { on };
90
- registerThinkConflictResolver(api);
91
- const callsAfterFirst = on.mock.calls.length;
92
- registerThinkConflictResolver(api);
93
- expect(on.mock.calls.length).toBe(callsAfterFirst);
94
- });
95
- });
96
- // ── sysprompt-strip register() direct coverage ────────────────────────────
97
- describe('session-bootstrap/sysprompt-strip register() hook behaviour', () => {
98
- beforeEach(() => {
99
- defaultRegisterGuard._resetForTests();
100
- });
101
- afterEach(() => {
102
- defaultRegisterGuard._resetForTests();
103
- });
104
- it('register() wires before_prompt_build hook', () => {
105
- const on = vi.fn();
106
- const api = { on, logger: console };
107
- registerSyspromptStripDirect(api);
108
- expect(on).toHaveBeenCalledWith('before_prompt_build', expect.any(Function));
109
- });
110
- it('before_prompt_build handler returns undefined when event is undefined', () => {
111
- const on = vi.fn();
112
- registerSyspromptStripDirect({ on });
113
- const handler = on.mock.calls.find(([e]) => e === 'before_prompt_build')[1];
114
- expect(handler(undefined)).toBeUndefined();
115
- });
116
- it('before_prompt_build handler returns undefined when event has no systemPrompt', () => {
117
- const on = vi.fn();
118
- registerSyspromptStripDirect({ on });
119
- const handler = on.mock.calls.find(([e]) => e === 'before_prompt_build')[1];
120
- expect(handler({})).toBeUndefined();
121
- });
122
- it('before_prompt_build handler returns undefined when systemPrompt is empty string', () => {
123
- const on = vi.fn();
124
- registerSyspromptStripDirect({ on });
125
- const handler = on.mock.calls.find(([e]) => e === 'before_prompt_build')[1];
126
- expect(handler({ systemPrompt: '' })).toBeUndefined();
127
- });
128
- it('before_prompt_build handler strips systemPrompt when content matches', () => {
129
- const on = vi.fn();
130
- const logger = { info: vi.fn(), warn: vi.fn(), error: vi.fn(), debug: vi.fn(), log: vi.fn() };
131
- registerSyspromptStripDirect({ on, logger });
132
- const handler = on.mock.calls.find(([e]) => e === 'before_prompt_build')[1];
133
- const event = { systemPrompt: 'before\n## SELF_IMPROVEMENT_REMINDER.md\nafter' };
134
- const result = handler(event);
135
- expect(result).toBeUndefined(); // always returns undefined
136
- expect(event.systemPrompt).not.toContain('SELF_IMPROVEMENT_REMINDER.md');
137
- });
138
- it('before_prompt_build handler leaves unchanged systemPrompt alone', () => {
139
- const on = vi.fn();
140
- registerSyspromptStripDirect({ on });
141
- const handler = on.mock.calls.find(([e]) => e === 'before_prompt_build')[1];
142
- const event = { systemPrompt: 'clean system prompt content' };
143
- const originalPrompt = event.systemPrompt;
144
- handler(event);
145
- expect(event.systemPrompt).toBe(originalPrompt);
146
- });
147
- it('register() is idempotent — second call with same api is a no-op', () => {
148
- const on = vi.fn();
149
- const api = { on };
150
- registerSyspromptStripDirect(api);
151
- const callsAfterFirst = on.mock.calls.length;
152
- registerSyspromptStripDirect(api);
153
- expect(on.mock.calls.length).toBe(callsAfterFirst);
154
- });
155
- it('register() with OPENCLAW_AGGRESSIVE_STRIP=0 still wires the hook', () => {
156
- const origEnv = process.env.OPENCLAW_AGGRESSIVE_STRIP;
157
- process.env.OPENCLAW_AGGRESSIVE_STRIP = '0';
158
- const on = vi.fn();
159
- const logger = { info: vi.fn(), warn: vi.fn(), error: vi.fn(), debug: vi.fn(), log: vi.fn() };
160
- registerSyspromptStripDirect({ on, logger });
161
- // Hook is still registered even when strip is disabled
162
- expect(on).toHaveBeenCalledWith('before_prompt_build', expect.any(Function));
163
- // logger.info called with opt-out message
164
- expect(logger.info).toHaveBeenCalledWith(expect.stringContaining('opt-out'));
165
- if (origEnv === undefined)
166
- delete process.env.OPENCLAW_AGGRESSIVE_STRIP;
167
- else
168
- process.env.OPENCLAW_AGGRESSIVE_STRIP = origEnv;
169
- });
170
- it('register() with OPENCLAW_AGGRESSIVE_STRIP=1 logs active message', () => {
171
- const origEnv = process.env.OPENCLAW_AGGRESSIVE_STRIP;
172
- process.env.OPENCLAW_AGGRESSIVE_STRIP = '1';
173
- const on = vi.fn();
174
- const logger = { info: vi.fn(), warn: vi.fn(), error: vi.fn(), debug: vi.fn(), log: vi.fn() };
175
- registerSyspromptStripDirect({ on, logger });
176
- expect(logger.info).toHaveBeenCalledWith(expect.stringContaining('aggressive strip active'));
177
- if (origEnv === undefined)
178
- delete process.env.OPENCLAW_AGGRESSIVE_STRIP;
179
- else
180
- process.env.OPENCLAW_AGGRESSIVE_STRIP = origEnv;
181
- });
182
- });
183
- //# sourceMappingURL=session-bootstrap.test.js.map