@gajae-code/coding-agent 0.10.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 (465) hide show
  1. package/CHANGELOG.md +50 -2
  2. package/dist/types/append-only-mode.d.ts +1 -1
  3. package/dist/types/cli/args.d.ts +4 -5
  4. package/dist/types/cli/daemon-cli.d.ts +12 -1
  5. package/dist/types/cli/notify-cli.d.ts +21 -1
  6. package/dist/types/cli.d.ts +3 -0
  7. package/dist/types/commands/daemon.d.ts +39 -0
  8. package/dist/types/commands/launch.d.ts +3 -0
  9. package/dist/types/commands/notify.d.ts +28 -1
  10. package/dist/types/commands/sdk.d.ts +33 -0
  11. package/dist/types/config/atomic-yaml-patch.d.ts +85 -0
  12. package/dist/types/config/model-profile-activation.d.ts +35 -15
  13. package/dist/types/config/model-profiles.d.ts +11 -5
  14. package/dist/types/config/model-registry.d.ts +3 -3
  15. package/dist/types/config/model-resolver.d.ts +39 -6
  16. package/dist/types/config/model-selector-value.d.ts +17 -0
  17. package/dist/types/config/models-config-schema.d.ts +10 -6
  18. package/dist/types/config/settings-schema.d.ts +133 -6
  19. package/dist/types/config/settings.d.ts +63 -35
  20. package/dist/types/coordinator-mcp/model-preset.d.ts +7 -6
  21. package/dist/types/coordinator-mcp/server.d.ts +6 -49
  22. package/dist/types/daemon/builtin.d.ts +6 -5
  23. package/dist/types/daemon/control-types.d.ts +1 -1
  24. package/dist/types/discovery/mcp-json.d.ts +12 -1
  25. package/dist/types/extensibility/custom-tools/types.d.ts +1 -1
  26. package/dist/types/extensibility/extensions/compact-handler.d.ts +4 -2
  27. package/dist/types/extensibility/extensions/get-commands-handler.d.ts +2 -2
  28. package/dist/types/extensibility/extensions/loader.d.ts +10 -1
  29. package/dist/types/extensibility/extensions/runner.d.ts +3 -3
  30. package/dist/types/extensibility/extensions/types.d.ts +141 -16
  31. package/dist/types/extensibility/hooks/types.d.ts +1 -1
  32. package/dist/types/gjc-runtime/launch-tmux.d.ts +3 -2
  33. package/dist/types/gjc-runtime/psmux-detect.d.ts +3 -0
  34. package/dist/types/gjc-runtime/session-state-sidecar.d.ts +3 -0
  35. package/dist/types/gjc-runtime/team-runtime.d.ts +3 -4
  36. package/dist/types/gjc-runtime/tmux-owner-isolation-cli.d.ts +13 -0
  37. package/dist/types/gjc-runtime/tmux-sessions.d.ts +4 -1
  38. package/dist/types/gjc-runtime/windows-powershell-command.d.ts +9 -0
  39. package/dist/types/harness-control-plane/operate.d.ts +5 -5
  40. package/dist/types/harness-control-plane/owner.d.ts +18 -4
  41. package/dist/types/harness-control-plane/receipts.d.ts +0 -1
  42. package/dist/types/harness-control-plane/sdk-transport.d.ts +43 -0
  43. package/dist/types/harness-control-plane/session-transport.d.ts +48 -0
  44. package/dist/types/harness-control-plane/types.d.ts +3 -4
  45. package/dist/types/lsp/index.d.ts +1 -1
  46. package/dist/types/main.d.ts +32 -38
  47. package/dist/types/modes/acp/acp-agent.d.ts +224 -53
  48. package/dist/types/modes/acp/acp-client-bridge.d.ts +1 -0
  49. package/dist/types/modes/acp/acp-mode.d.ts +6 -15
  50. package/dist/types/modes/acp/permission-mode.d.ts +4 -0
  51. package/dist/types/modes/acp/startup-options.d.ts +6 -0
  52. package/dist/types/modes/components/agent-dashboard.d.ts +3 -0
  53. package/dist/types/modes/components/model-selector.d.ts +1 -0
  54. package/dist/types/modes/components/notifications-settings-editor.d.ts +135 -0
  55. package/dist/types/modes/components/settings-selector.d.ts +6 -4
  56. package/dist/types/modes/components/welcome.d.ts +1 -1
  57. package/dist/types/modes/controllers/selector-controller.d.ts +35 -1
  58. package/dist/types/modes/index.d.ts +0 -4
  59. package/dist/types/modes/interactive-mode.d.ts +3 -0
  60. package/dist/types/modes/runtime-init.d.ts +2 -2
  61. package/dist/types/modes/shared/agent-wire/approval-gate.d.ts +6 -9
  62. package/dist/types/modes/shared/agent-wire/deep-interview-gate.d.ts +4 -6
  63. package/dist/types/modes/shared/agent-wire/event-contract.d.ts +6 -6
  64. package/dist/types/modes/shared/agent-wire/event-envelope.d.ts +4 -9
  65. package/dist/types/modes/shared/agent-wire/event-observation.d.ts +1 -1
  66. package/dist/types/modes/shared/agent-wire/workflow-gate-broker.d.ts +169 -30
  67. package/dist/types/modes/shared/agent-wire/workflow-gate-schema.d.ts +7 -7
  68. package/dist/types/modes/shared/agent-wire/workflow-gate-types.d.ts +105 -0
  69. package/dist/types/modes/types.d.ts +5 -0
  70. package/dist/types/runtime-mcp/client.d.ts +2 -0
  71. package/dist/types/runtime-mcp/config.d.ts +5 -1
  72. package/dist/types/runtime-mcp/manager.d.ts +8 -1
  73. package/dist/types/runtime-mcp/types.d.ts +4 -0
  74. package/dist/types/sdk/acp/adapter.d.ts +67 -0
  75. package/dist/types/sdk/acp/index.d.ts +2 -0
  76. package/dist/types/sdk/broker/broker.d.ts +53 -0
  77. package/dist/types/sdk/broker/discovery.d.ts +30 -0
  78. package/dist/types/sdk/broker/ensure.d.ts +33 -0
  79. package/dist/types/sdk/broker/identity.d.ts +3 -0
  80. package/dist/types/sdk/broker/index.d.ts +8 -0
  81. package/dist/types/sdk/broker/lifecycle-ledger.d.ts +95 -0
  82. package/dist/types/sdk/broker/lifecycle.d.ts +85 -0
  83. package/dist/types/sdk/broker/process-incarnation.d.ts +14 -0
  84. package/dist/types/sdk/broker/runtime.d.ts +33 -0
  85. package/dist/types/sdk/broker/session-index.d.ts +57 -0
  86. package/dist/types/sdk/broker/state-version.d.ts +8 -0
  87. package/dist/types/sdk/broker/transport.d.ts +9 -0
  88. package/dist/types/sdk/bus/chat-command-policy.d.ts +49 -0
  89. package/dist/types/sdk/bus/chat-daemon-cli.d.ts +21 -0
  90. package/dist/types/sdk/bus/chat-daemon-control.d.ts +111 -0
  91. package/dist/types/sdk/bus/chat-daemon-runtime.d.ts +77 -0
  92. package/dist/types/sdk/bus/chat-effect-journal.d.ts +84 -0
  93. package/dist/types/{notifications → sdk/bus}/config-commands.d.ts +7 -2
  94. package/dist/types/sdk/bus/config.d.ts +274 -0
  95. package/dist/types/sdk/bus/conversation-store.d.ts +72 -0
  96. package/dist/types/sdk/bus/discord-conversation.d.ts +58 -0
  97. package/dist/types/sdk/bus/discord-daemon.d.ts +45 -0
  98. package/dist/types/sdk/bus/discord-live-provider.d.ts +70 -0
  99. package/dist/types/sdk/bus/discord-provider.d.ts +85 -0
  100. package/dist/types/{notifications → sdk/bus}/html-format.d.ts +2 -2
  101. package/dist/types/{notifications → sdk/bus}/index.d.ts +113 -13
  102. package/dist/types/{notifications → sdk/bus}/lifecycle-control-runtime.d.ts +4 -2
  103. package/dist/types/{notifications → sdk/bus}/lifecycle-orchestrator.d.ts +18 -21
  104. package/dist/types/{notifications → sdk/bus}/managed-daemon.d.ts +1 -1
  105. package/dist/types/sdk/bus/native-runtime-compatibility.d.ts +13 -0
  106. package/dist/types/sdk/bus/notification-orchestration.d.ts +170 -0
  107. package/dist/types/{notifications → sdk/bus}/notification-service.d.ts +7 -1
  108. package/dist/types/sdk/bus/session-control.d.ts +83 -0
  109. package/dist/types/sdk/bus/slack-conversation.d.ts +56 -0
  110. package/dist/types/sdk/bus/slack-daemon.d.ts +60 -0
  111. package/dist/types/sdk/bus/slack-live-provider.d.ts +59 -0
  112. package/dist/types/sdk/bus/slack-provider.d.ts +55 -0
  113. package/dist/types/{notifications → sdk/bus}/telegram-cli.d.ts +4 -4
  114. package/dist/types/{notifications → sdk/bus}/telegram-daemon-cli.d.ts +14 -5
  115. package/dist/types/sdk/bus/telegram-daemon-contract.d.ts +12 -0
  116. package/dist/types/{notifications → sdk/bus}/telegram-daemon-control.d.ts +2 -2
  117. package/dist/types/{notifications → sdk/bus}/telegram-daemon.d.ts +55 -17
  118. package/dist/types/{notifications → sdk/bus}/telegram-reference.d.ts +2 -2
  119. package/dist/types/sdk/bus/telegram-setup.d.ts +128 -0
  120. package/dist/types/{notifications → sdk/bus}/topic-registry.d.ts +11 -0
  121. package/dist/types/sdk/cli/index.d.ts +1 -0
  122. package/dist/types/sdk/cli/session-cli.d.ts +19 -0
  123. package/dist/types/sdk/client/client.d.ts +1 -0
  124. package/dist/types/sdk/client/discovery.d.ts +27 -0
  125. package/dist/types/sdk/client/index.d.ts +2 -0
  126. package/dist/types/sdk/host/control/dispatch.d.ts +34 -0
  127. package/dist/types/sdk/host/control/index.d.ts +2 -0
  128. package/dist/types/sdk/host/control/operations.d.ts +65 -0
  129. package/dist/types/sdk/host/events.d.ts +35 -0
  130. package/dist/types/sdk/host/host.d.ts +35 -0
  131. package/dist/types/sdk/host/index.d.ts +4 -0
  132. package/dist/types/sdk/host/query/cursor.d.ts +62 -0
  133. package/dist/types/sdk/host/query/handlers.d.ts +70 -0
  134. package/dist/types/sdk/host/query/index.d.ts +3 -0
  135. package/dist/types/sdk/host/query/revision-store.d.ts +60 -0
  136. package/dist/types/sdk/host/reverse-leases.d.ts +45 -0
  137. package/dist/types/sdk/host/types.d.ts +32 -0
  138. package/dist/types/sdk/index.d.ts +6 -0
  139. package/dist/types/sdk/lifecycle-session.d.ts +14 -0
  140. package/dist/types/sdk/mcp/index.d.ts +1 -0
  141. package/dist/types/sdk/mcp/server.d.ts +37 -0
  142. package/dist/types/sdk/models.d.ts +44 -0
  143. package/dist/types/sdk/protocol/adapter-validation.d.ts +14 -0
  144. package/dist/types/sdk/protocol/operation-registry.d.ts +24 -0
  145. package/dist/types/{sdk.d.ts → sdk/session.d.ts} +44 -38
  146. package/dist/types/sdk/startup-capability.d.ts +50 -0
  147. package/dist/types/session/agent-session.d.ts +114 -21
  148. package/dist/types/session/default-model-selection.d.ts +25 -0
  149. package/dist/types/session/fallback-chain-controller.d.ts +52 -0
  150. package/dist/types/session/session-manager.d.ts +58 -1
  151. package/dist/types/setup/credential-auto-import.d.ts +36 -6
  152. package/dist/types/tools/ask-answer-registry.d.ts +1 -1
  153. package/dist/types/tools/browser/benchmark/detector-report.d.ts +63 -0
  154. package/dist/types/tools/browser/benchmark/run-suite.d.ts +18 -0
  155. package/dist/types/tools/browser/launch.d.ts +22 -0
  156. package/dist/types/tools/browser/profile-discovery.d.ts +31 -0
  157. package/dist/types/tools/browser/profile-posture.d.ts +37 -0
  158. package/dist/types/tools/browser/profile-reuse.d.ts +39 -0
  159. package/dist/types/tools/browser/profile-warmup.d.ts +39 -0
  160. package/dist/types/tools/browser/registry.d.ts +19 -0
  161. package/dist/types/tools/browser/tab-protocol.d.ts +4 -0
  162. package/dist/types/tools/index.d.ts +8 -8
  163. package/package.json +34 -13
  164. package/scripts/build-sdk-package-smoke.ts +94 -0
  165. package/scripts/capture-notifications-settings-showcase.ts +435 -0
  166. package/scripts/compile-args.ts +4 -2
  167. package/scripts/g005-daemon-smoke.ts +4 -5
  168. package/scripts/g011-daemon-path-smoke.ts +5 -5
  169. package/scripts/generate-sdk-adapter-parity-manifest.ts +163 -0
  170. package/scripts/generate-sdk-operation-inventory.ts +867 -0
  171. package/scripts/generate-telegram-baseline-manifest.ts +128 -0
  172. package/scripts/manifest-schema.ts +124 -0
  173. package/scripts/run-test-manifest.ts +153 -0
  174. package/scripts/run-threat-model-check.ts +157 -0
  175. package/scripts/verify-gjc-sdk-canonicalization.ts +3467 -0
  176. package/scripts/verify-gjc-sdk-rename.ts +90 -0
  177. package/src/append-only-mode.ts +1 -1
  178. package/src/cli/args.ts +43 -12
  179. package/src/cli/auth-gateway-cli.ts +2 -2
  180. package/src/cli/config-cli.ts +2 -1
  181. package/src/cli/daemon-cli.ts +63 -14
  182. package/src/cli/list-models.ts +1 -1
  183. package/src/cli/notify-cli.ts +288 -286
  184. package/src/cli.ts +21 -2
  185. package/src/commands/daemon.ts +50 -6
  186. package/src/commands/harness.ts +93 -36
  187. package/src/commands/launch.ts +5 -2
  188. package/src/commands/mcp-serve.ts +19 -12
  189. package/src/commands/notify.ts +36 -3
  190. package/src/commands/sdk.ts +426 -0
  191. package/src/commit/agentic/agent.ts +1 -0
  192. package/src/config/atomic-yaml-patch.ts +423 -0
  193. package/src/config/model-profile-activation.ts +240 -89
  194. package/src/config/model-profiles.ts +18 -15
  195. package/src/config/model-registry.ts +51 -26
  196. package/src/config/model-resolver.ts +138 -51
  197. package/src/config/model-selector-value.ts +50 -0
  198. package/src/config/models-config-schema.ts +14 -21
  199. package/src/config/settings-schema.ts +128 -10
  200. package/src/config/settings.ts +1120 -158
  201. package/src/coordinator-mcp/model-preset.ts +74 -20
  202. package/src/coordinator-mcp/server.ts +1597 -3052
  203. package/src/daemon/builtin.ts +8 -5
  204. package/src/daemon/control-types.ts +1 -1
  205. package/src/defaults/gjc/skills/team/SKILL.md +4 -4
  206. package/src/discovery/mcp-json.ts +327 -20
  207. package/src/extensibility/custom-tools/types.ts +1 -1
  208. package/src/extensibility/extensions/compact-handler.ts +3 -3
  209. package/src/extensibility/extensions/get-commands-handler.ts +2 -2
  210. package/src/extensibility/extensions/loader.ts +69 -5
  211. package/src/extensibility/extensions/runner.ts +112 -4
  212. package/src/extensibility/extensions/types.ts +176 -17
  213. package/src/extensibility/hooks/types.ts +1 -1
  214. package/src/gjc-runtime/launch-tmux.ts +170 -86
  215. package/src/gjc-runtime/psmux-detect.ts +82 -4
  216. package/src/gjc-runtime/session-state-sidecar.ts +41 -31
  217. package/src/gjc-runtime/team-runtime.ts +54 -35
  218. package/src/gjc-runtime/tmux-owner-isolation-cli.ts +53 -17
  219. package/src/gjc-runtime/tmux-owner-isolation.ts +1 -1
  220. package/src/gjc-runtime/tmux-sessions.ts +19 -13
  221. package/src/gjc-runtime/ultragoal-guard.ts +53 -6
  222. package/src/gjc-runtime/ultragoal-runtime.ts +155 -3
  223. package/src/gjc-runtime/windows-powershell-command.ts +58 -0
  224. package/src/harness-control-plane/operate.ts +9 -9
  225. package/src/harness-control-plane/owner.ts +283 -39
  226. package/src/harness-control-plane/receipts.ts +0 -1
  227. package/src/harness-control-plane/sdk-transport.ts +395 -0
  228. package/src/harness-control-plane/session-transport.ts +94 -0
  229. package/src/harness-control-plane/types.ts +1 -1
  230. package/src/internal-urls/docs-index.generated.ts +34 -35
  231. package/src/lsp/client.ts +42 -6
  232. package/src/lsp/index.ts +2 -2
  233. package/src/main.ts +299 -204
  234. package/src/modes/DESIGN.md +258 -0
  235. package/src/modes/acp/acp-agent.ts +1228 -2612
  236. package/src/modes/acp/acp-client-bridge.ts +2 -20
  237. package/src/modes/acp/acp-event-mapper.ts +18 -2
  238. package/src/modes/acp/acp-mode.ts +8 -36
  239. package/src/modes/acp/permission-mode.ts +25 -0
  240. package/src/modes/acp/startup-options.ts +6 -0
  241. package/src/modes/components/agent-dashboard.ts +37 -17
  242. package/src/modes/components/model-selector.ts +93 -35
  243. package/src/modes/components/notifications-settings-editor.ts +1379 -0
  244. package/src/modes/components/settings-selector.ts +60 -11
  245. package/src/modes/components/welcome.ts +4 -4
  246. package/src/modes/controllers/command-controller.ts +1 -2
  247. package/src/modes/controllers/event-controller.ts +11 -16
  248. package/src/modes/controllers/extension-ui-controller.ts +348 -4
  249. package/src/modes/controllers/selector-controller.ts +674 -36
  250. package/src/modes/index.ts +0 -22
  251. package/src/modes/interactive-mode.ts +59 -20
  252. package/src/modes/runtime-init.ts +298 -6
  253. package/src/modes/shared/agent-wire/approval-gate.ts +9 -11
  254. package/src/modes/shared/agent-wire/deep-interview-gate.ts +10 -11
  255. package/src/modes/shared/agent-wire/event-contract.ts +7 -8
  256. package/src/modes/shared/agent-wire/event-envelope.ts +9 -17
  257. package/src/modes/shared/agent-wire/event-observation.ts +16 -7
  258. package/src/modes/shared/agent-wire/workflow-gate-broker.ts +1254 -87
  259. package/src/modes/shared/agent-wire/workflow-gate-schema.ts +15 -15
  260. package/src/modes/shared/agent-wire/workflow-gate-types.ts +113 -0
  261. package/src/modes/types.ts +5 -0
  262. package/src/runtime-mcp/client.ts +94 -19
  263. package/src/runtime-mcp/config.ts +27 -15
  264. package/src/runtime-mcp/manager.ts +343 -105
  265. package/src/runtime-mcp/oauth-flow.ts +42 -12
  266. package/src/runtime-mcp/transports/http.ts +49 -19
  267. package/src/runtime-mcp/transports/stdio.ts +47 -28
  268. package/src/runtime-mcp/types.ts +10 -0
  269. package/src/sdk/acp/adapter.ts +418 -0
  270. package/src/sdk/acp/index.ts +2 -0
  271. package/src/sdk/broker/broker.ts +642 -0
  272. package/src/sdk/broker/discovery.ts +94 -0
  273. package/src/sdk/broker/ensure.ts +249 -0
  274. package/src/sdk/broker/identity.ts +42 -0
  275. package/src/sdk/broker/index.ts +8 -0
  276. package/src/sdk/broker/internal-source-marker-2178.txt +1 -0
  277. package/src/sdk/broker/internal-source.bunfig.toml +1 -0
  278. package/src/sdk/broker/lifecycle-ledger.ts +286 -0
  279. package/src/sdk/broker/lifecycle.ts +2157 -0
  280. package/src/sdk/broker/process-incarnation.ts +159 -0
  281. package/src/sdk/broker/runtime.ts +164 -0
  282. package/src/sdk/broker/session-index.ts +318 -0
  283. package/src/sdk/broker/state-version.ts +23 -0
  284. package/src/sdk/broker/transport.ts +125 -0
  285. package/src/sdk/bus/chat-command-policy.ts +107 -0
  286. package/src/sdk/bus/chat-daemon-cli.ts +214 -0
  287. package/src/sdk/bus/chat-daemon-control.ts +713 -0
  288. package/src/sdk/bus/chat-daemon-runtime.ts +526 -0
  289. package/src/sdk/bus/chat-effect-journal.ts +353 -0
  290. package/src/{notifications → sdk/bus}/config-commands.ts +39 -10
  291. package/src/sdk/bus/config.ts +433 -0
  292. package/src/sdk/bus/conversation-store.ts +391 -0
  293. package/src/sdk/bus/discord-conversation.ts +85 -0
  294. package/src/sdk/bus/discord-daemon.ts +2275 -0
  295. package/src/sdk/bus/discord-live-provider.ts +521 -0
  296. package/src/sdk/bus/discord-provider.ts +56 -0
  297. package/src/{notifications → sdk/bus}/html-format.ts +2 -2
  298. package/src/sdk/bus/index.ts +3943 -0
  299. package/src/{notifications → sdk/bus}/lifecycle-commands.ts +2 -0
  300. package/src/{notifications → sdk/bus}/lifecycle-control-runtime.ts +225 -196
  301. package/src/{notifications → sdk/bus}/lifecycle-orchestrator.ts +161 -74
  302. package/src/{notifications → sdk/bus}/managed-daemon.ts +2 -2
  303. package/src/sdk/bus/native-runtime-compatibility.ts +42 -0
  304. package/src/sdk/bus/natives-augment.d.ts +38 -0
  305. package/src/sdk/bus/notification-orchestration.ts +535 -0
  306. package/src/{notifications → sdk/bus}/notification-service.ts +106 -12
  307. package/src/sdk/bus/session-control.ts +333 -0
  308. package/src/sdk/bus/slack-conversation.ts +74 -0
  309. package/src/sdk/bus/slack-daemon.ts +2144 -0
  310. package/src/sdk/bus/slack-live-provider.ts +380 -0
  311. package/src/sdk/bus/slack-provider.ts +76 -0
  312. package/src/{notifications → sdk/bus}/telegram-cli.ts +8 -8
  313. package/src/sdk/bus/telegram-daemon-cli.ts +330 -0
  314. package/src/sdk/bus/telegram-daemon-contract.ts +14 -0
  315. package/src/{notifications → sdk/bus}/telegram-daemon-control.ts +4 -4
  316. package/src/{notifications → sdk/bus}/telegram-daemon.ts +502 -54
  317. package/src/{notifications → sdk/bus}/telegram-reference.ts +2 -2
  318. package/src/sdk/bus/telegram-setup.ts +663 -0
  319. package/src/{notifications → sdk/bus}/topic-registry.ts +32 -0
  320. package/src/sdk/cli/index.ts +1 -0
  321. package/src/sdk/cli/session-cli.ts +275 -0
  322. package/src/sdk/client/client.ts +1 -0
  323. package/src/sdk/client/discovery.ts +108 -0
  324. package/src/sdk/client/index.ts +2 -0
  325. package/src/sdk/host/control/dispatch.ts +367 -0
  326. package/src/sdk/host/control/index.ts +10 -0
  327. package/src/sdk/host/control/operations.ts +63 -0
  328. package/src/sdk/host/events.ts +91 -0
  329. package/src/sdk/host/host.ts +296 -0
  330. package/src/sdk/host/index.ts +4 -0
  331. package/src/sdk/host/query/cursor.ts +189 -0
  332. package/src/sdk/host/query/handlers.ts +533 -0
  333. package/src/sdk/host/query/index.ts +3 -0
  334. package/src/sdk/host/query/revision-store.ts +1126 -0
  335. package/src/sdk/host/reverse-leases.ts +325 -0
  336. package/src/sdk/host/types.ts +29 -0
  337. package/src/sdk/index.ts +13 -0
  338. package/src/sdk/lifecycle-session.ts +39 -0
  339. package/src/sdk/mcp/index.ts +1 -0
  340. package/src/sdk/mcp/server.ts +332 -0
  341. package/src/sdk/models.ts +168 -0
  342. package/src/sdk/protocol/adapter-validation.ts +48 -0
  343. package/src/sdk/protocol/operation-inventory.generated.json +5654 -0
  344. package/src/sdk/protocol/operation-registry.ts +312 -0
  345. package/src/{sdk.ts → sdk/session.ts} +339 -212
  346. package/src/sdk/startup-capability.ts +189 -0
  347. package/src/session/agent-session.ts +2453 -894
  348. package/src/session/default-model-selection.ts +93 -0
  349. package/src/session/fallback-chain-controller.ts +136 -0
  350. package/src/session/session-manager.ts +438 -11
  351. package/src/session/session-storage.ts +8 -1
  352. package/src/setup/credential-auto-import.ts +290 -35
  353. package/src/setup/hermes/templates/operator-instructions.v1.md +3 -5
  354. package/src/slash-commands/builtin-registry.ts +2 -1
  355. package/src/task/executor.ts +62 -13
  356. package/src/tools/ask-answer-registry.ts +1 -1
  357. package/src/tools/ask.ts +13 -8
  358. package/src/tools/browser/STEALTH-THIRD-PARTY-NOTICES.md +26 -0
  359. package/src/tools/browser/benchmark/detector-report.ts +157 -0
  360. package/src/tools/browser/benchmark/run-suite.ts +39 -0
  361. package/src/tools/browser/launch.ts +124 -19
  362. package/src/tools/browser/profile-discovery.ts +63 -0
  363. package/src/tools/browser/profile-posture.ts +59 -0
  364. package/src/tools/browser/profile-reuse.ts +102 -0
  365. package/src/tools/browser/profile-warmup.ts +109 -0
  366. package/src/tools/browser/registry.ts +87 -11
  367. package/src/tools/browser/tab-protocol.ts +1 -0
  368. package/src/tools/browser/tab-supervisor.ts +1 -0
  369. package/src/tools/browser/tab-worker.ts +1 -1
  370. package/src/tools/browser.ts +6 -0
  371. package/src/tools/index.ts +8 -8
  372. package/src/tools/puppeteer/14_stealth_permissions.txt +57 -0
  373. package/src/tools/puppeteer/15_stealth_webrtc.txt +60 -0
  374. package/src/tools/telegram-send.ts +2 -2
  375. package/vendor/insane-search/MANIFEST.json +2 -1
  376. package/vendor/insane-search/engine/bias_check.py +4 -1
  377. package/vendor/insane-search/engine/phase0.py +26 -1
  378. package/dist/types/harness-control-plane/rpc-adapter.d.ts +0 -69
  379. package/dist/types/modes/bridge/auth.d.ts +0 -12
  380. package/dist/types/modes/bridge/bridge-client-bridge.d.ts +0 -9
  381. package/dist/types/modes/bridge/bridge-mode.d.ts +0 -47
  382. package/dist/types/modes/bridge/bridge-ui-context.d.ts +0 -88
  383. package/dist/types/modes/bridge/event-stream.d.ts +0 -8
  384. package/dist/types/modes/rpc/host-tools.d.ts +0 -1
  385. package/dist/types/modes/rpc/host-uris.d.ts +0 -1
  386. package/dist/types/modes/rpc/rpc-client.d.ts +0 -299
  387. package/dist/types/modes/rpc/rpc-mode.d.ts +0 -86
  388. package/dist/types/modes/rpc/rpc-socket-security.d.ts +0 -10
  389. package/dist/types/modes/rpc/rpc-types.d.ts +0 -810
  390. package/dist/types/modes/shared/agent-wire/command-contract.d.ts +0 -18
  391. package/dist/types/modes/shared/agent-wire/command-dispatch.d.ts +0 -37
  392. package/dist/types/modes/shared/agent-wire/command-validation.d.ts +0 -2
  393. package/dist/types/modes/shared/agent-wire/handshake.d.ts +0 -56
  394. package/dist/types/modes/shared/agent-wire/host-tool-bridge.d.ts +0 -16
  395. package/dist/types/modes/shared/agent-wire/host-uri-bridge.d.ts +0 -17
  396. package/dist/types/modes/shared/agent-wire/protocol.d.ts +0 -25
  397. package/dist/types/modes/shared/agent-wire/responses.d.ts +0 -4
  398. package/dist/types/modes/shared/agent-wire/scopes.d.ts +0 -18
  399. package/dist/types/modes/shared/agent-wire/session-registry.d.ts +0 -25
  400. package/dist/types/modes/shared/agent-wire/ui-request-broker.d.ts +0 -42
  401. package/dist/types/modes/shared/agent-wire/ui-result.d.ts +0 -27
  402. package/dist/types/modes/shared/agent-wire/unattended-action-policy.d.ts +0 -29
  403. package/dist/types/modes/shared/agent-wire/unattended-audit.d.ts +0 -68
  404. package/dist/types/modes/shared/agent-wire/unattended-run-controller.d.ts +0 -166
  405. package/dist/types/modes/shared/agent-wire/unattended-session.d.ts +0 -127
  406. package/dist/types/notifications/config.d.ts +0 -132
  407. package/src/harness-control-plane/rpc-adapter.ts +0 -290
  408. package/src/modes/bridge/auth.ts +0 -41
  409. package/src/modes/bridge/bridge-client-bridge.ts +0 -47
  410. package/src/modes/bridge/bridge-mode.ts +0 -675
  411. package/src/modes/bridge/bridge-ui-context.ts +0 -200
  412. package/src/modes/bridge/event-stream.ts +0 -70
  413. package/src/modes/rpc/host-tools.ts +0 -1
  414. package/src/modes/rpc/host-uris.ts +0 -1
  415. package/src/modes/rpc/rpc-client.ts +0 -1166
  416. package/src/modes/rpc/rpc-mode.ts +0 -1029
  417. package/src/modes/rpc/rpc-socket-security.ts +0 -115
  418. package/src/modes/rpc/rpc-types.ts +0 -637
  419. package/src/modes/shared/agent-wire/command-contract.ts +0 -18
  420. package/src/modes/shared/agent-wire/command-dispatch.ts +0 -498
  421. package/src/modes/shared/agent-wire/command-validation.ts +0 -181
  422. package/src/modes/shared/agent-wire/handshake.ts +0 -157
  423. package/src/modes/shared/agent-wire/host-tool-bridge.ts +0 -197
  424. package/src/modes/shared/agent-wire/host-uri-bridge.ts +0 -236
  425. package/src/modes/shared/agent-wire/protocol.ts +0 -46
  426. package/src/modes/shared/agent-wire/responses.ts +0 -17
  427. package/src/modes/shared/agent-wire/scopes.ts +0 -94
  428. package/src/modes/shared/agent-wire/session-registry.ts +0 -109
  429. package/src/modes/shared/agent-wire/ui-request-broker.ts +0 -150
  430. package/src/modes/shared/agent-wire/ui-result.ts +0 -48
  431. package/src/modes/shared/agent-wire/unattended-action-policy.ts +0 -365
  432. package/src/modes/shared/agent-wire/unattended-audit.ts +0 -176
  433. package/src/modes/shared/agent-wire/unattended-run-controller.ts +0 -426
  434. package/src/modes/shared/agent-wire/unattended-session.ts +0 -528
  435. package/src/notifications/config.ts +0 -219
  436. package/src/notifications/index.ts +0 -1835
  437. package/src/notifications/telegram-daemon-cli.ts +0 -243
  438. package/src/tools/puppeteer/09_stealth_locale.txt +0 -46
  439. /package/dist/types/{notifications → sdk/bus}/attachment-registry.d.ts +0 -0
  440. /package/dist/types/{notifications → sdk/bus}/chat-adapters.d.ts +0 -0
  441. /package/dist/types/{notifications → sdk/bus}/daemon-paths.d.ts +0 -0
  442. /package/dist/types/{notifications → sdk/bus}/engine.d.ts +0 -0
  443. /package/dist/types/{notifications → sdk/bus}/helpers.d.ts +0 -0
  444. /package/dist/types/{notifications → sdk/bus}/lifecycle-commands.d.ts +0 -0
  445. /package/dist/types/{notifications → sdk/bus}/operator-runtime.d.ts +0 -0
  446. /package/dist/types/{notifications → sdk/bus}/rate-limit-pool.d.ts +0 -0
  447. /package/dist/types/{notifications → sdk/bus}/recent-activity.d.ts +0 -0
  448. /package/dist/types/{notifications → sdk/bus}/reply-sent-store.d.ts +0 -0
  449. /package/dist/types/{notifications → sdk/bus}/rich-draft.d.ts +0 -0
  450. /package/dist/types/{notifications → sdk/bus}/rich-render.d.ts +0 -0
  451. /package/dist/types/{notifications → sdk/bus}/threaded-inbound.d.ts +0 -0
  452. /package/dist/types/{notifications → sdk/bus}/threaded-render.d.ts +0 -0
  453. /package/src/{notifications → sdk/bus}/attachment-registry.ts +0 -0
  454. /package/src/{notifications → sdk/bus}/chat-adapters.ts +0 -0
  455. /package/src/{notifications → sdk/bus}/daemon-paths.ts +0 -0
  456. /package/src/{notifications → sdk/bus}/engine.ts +0 -0
  457. /package/src/{notifications → sdk/bus}/helpers.ts +0 -0
  458. /package/src/{notifications → sdk/bus}/operator-runtime.ts +0 -0
  459. /package/src/{notifications → sdk/bus}/rate-limit-pool.ts +0 -0
  460. /package/src/{notifications → sdk/bus}/recent-activity.ts +0 -0
  461. /package/src/{notifications → sdk/bus}/reply-sent-store.ts +0 -0
  462. /package/src/{notifications → sdk/bus}/rich-draft.ts +0 -0
  463. /package/src/{notifications → sdk/bus}/rich-render.ts +0 -0
  464. /package/src/{notifications → sdk/bus}/threaded-inbound.ts +0 -0
  465. /package/src/{notifications → sdk/bus}/threaded-render.ts +0 -0
@@ -0,0 +1,157 @@
1
+ /**
2
+ * Offline stealth-detector benchmark model.
3
+ *
4
+ * Pure, deterministic logic for the anti-detection benchmark suite: it converts
5
+ * a browser-collected fingerprint probe into a normalized per-detector verdict,
6
+ * implements the falsifiable CI gate (see plan Phase 1 / R-T3), and renders a
7
+ * before/after report. No browser or network access lives here so it can be
8
+ * unit-tested deterministically; the harness that drives the real browser tool
9
+ * against vendored detector fixtures feeds its output into these functions.
10
+ */
11
+
12
+ export type SignalStatus = "pass" | "fail";
13
+
14
+ /** A single boolean fingerprint signal, e.g. "navigator.webdriver is undefined". */
15
+ export interface DetectorSignal {
16
+ /** Stable identifier, used to diff across runs. */
17
+ id: string;
18
+ /** Human-readable label for the report. */
19
+ label: string;
20
+ /** `pass` means the signal looks human; `fail` means it leaks automation. */
21
+ status: SignalStatus;
22
+ /** Optional observed value for debugging. */
23
+ detail?: string;
24
+ }
25
+
26
+ export type AutomatedVerdict = "human" | "bot" | "unknown";
27
+
28
+ /** Normalized result for one detector (e.g. bot.sannysoft, CreepJS). */
29
+ export interface DetectorResult {
30
+ detector: string;
31
+ signals: DetectorSignal[];
32
+ /** Overall automated/not classification when the detector exposes one. */
33
+ automatedVerdict: AutomatedVerdict;
34
+ /** Absolute trust score (observability-only, never a hard gate). */
35
+ trustScore: number | null;
36
+ }
37
+
38
+ /** Shape emitted by the offline probe fixture on `window.__stealthProbe`. */
39
+ export interface RawProbe {
40
+ detector: string;
41
+ signals: Array<{ id: string; label: string; pass: boolean; detail?: string }>;
42
+ automatedVerdict?: AutomatedVerdict;
43
+ trustScore?: number | null;
44
+ }
45
+
46
+ /** Convert a raw browser-collected probe into a normalized {@link DetectorResult}. */
47
+ export function parseProbe(raw: RawProbe): DetectorResult {
48
+ if (!raw || typeof raw.detector !== "string" || !Array.isArray(raw.signals)) {
49
+ throw new Error("invalid stealth probe payload");
50
+ }
51
+ const signals: DetectorSignal[] = raw.signals.map(s => ({
52
+ id: s.id,
53
+ label: s.label,
54
+ status: s.pass ? "pass" : "fail",
55
+ ...(s.detail !== undefined ? { detail: s.detail } : {}),
56
+ }));
57
+ return {
58
+ detector: raw.detector,
59
+ signals,
60
+ automatedVerdict: raw.automatedVerdict ?? "unknown",
61
+ trustScore: raw.trustScore ?? null,
62
+ };
63
+ }
64
+
65
+ function passCount(result: DetectorResult): number {
66
+ return result.signals.filter(s => s.status === "pass").length;
67
+ }
68
+
69
+ function failingSignalIds(result: DetectorResult): Set<string> {
70
+ return new Set(result.signals.filter(s => s.status === "fail").map(s => s.id));
71
+ }
72
+
73
+ export interface GateOutcome {
74
+ pass: boolean;
75
+ reasons: string[];
76
+ }
77
+
78
+ /**
79
+ * Falsifiable CI gate (plan Phase 1 / R-T3, R-C1, R-C2):
80
+ * (a) zero failing signals in the current run, AND
81
+ * current pass-count >= baseline pass-count (no silent regression), AND
82
+ * (b) either at least one signal that failed at baseline now passes,
83
+ * OR the baseline was already all-green (empty-gap regression lock).
84
+ * The absolute `trustScore` is never consulted here; it is observability-only.
85
+ */
86
+ export function evaluateGate(baseline: DetectorResult, current: DetectorResult): GateOutcome {
87
+ const reasons: string[] = [];
88
+ const currentFail = failingSignalIds(current);
89
+ if (currentFail.size > 0) {
90
+ reasons.push(
91
+ `${current.detector}: ${currentFail.size} signal(s) still leak automation: ${[...currentFail].join(", ")}`,
92
+ );
93
+ }
94
+
95
+ const baselinePass = passCount(baseline);
96
+ const currentPass = passCount(current);
97
+ if (currentPass < baselinePass) {
98
+ reasons.push(`${current.detector}: pass-count regressed (${currentPass} < baseline ${baselinePass})`);
99
+ }
100
+
101
+ const baselineFail = failingSignalIds(baseline);
102
+ const currentPassIds = new Set(current.signals.filter(s => s.status === "pass").map(s => s.id));
103
+ const newlyPassing = [...baselineFail].filter(id => currentPassIds.has(id));
104
+ const baselineAllGreen = baselineFail.size === 0;
105
+ if (!baselineAllGreen && newlyPassing.length === 0) {
106
+ reasons.push(`${current.detector}: no baseline-failing signal was fixed (improvement required)`);
107
+ }
108
+
109
+ return { pass: reasons.length === 0, reasons };
110
+ }
111
+
112
+ /** Aggregate gate across every detector; passes only when all detectors pass. */
113
+ export function evaluateSuiteGate(
114
+ baseline: readonly DetectorResult[],
115
+ current: readonly DetectorResult[],
116
+ ): GateOutcome {
117
+ const reasons: string[] = [];
118
+ const currentByName = new Map(current.map(r => [r.detector, r]));
119
+ for (const base of baseline) {
120
+ const now = currentByName.get(base.detector);
121
+ if (!now) {
122
+ reasons.push(`${base.detector}: missing from current run`);
123
+ continue;
124
+ }
125
+ reasons.push(...evaluateGate(base, now).reasons);
126
+ }
127
+ return { pass: reasons.length === 0, reasons };
128
+ }
129
+
130
+ /** Render a deterministic before/after markdown report for one run. */
131
+ export function renderReport(baseline: readonly DetectorResult[], current: readonly DetectorResult[]): string {
132
+ const lines: string[] = ["# Stealth Benchmark Report", ""];
133
+ const gate = evaluateSuiteGate(baseline, current);
134
+ lines.push(`Gate: ${gate.pass ? "PASS" : "FAIL"}`, "");
135
+ const currentByName = new Map(current.map(r => [r.detector, r]));
136
+ for (const base of baseline) {
137
+ const now = currentByName.get(base.detector);
138
+ lines.push(`## ${base.detector}`);
139
+ lines.push(
140
+ `- Automated verdict: ${base.automatedVerdict} -> ${now?.automatedVerdict ?? "n/a"}`,
141
+ `- Trust score (observability): ${base.trustScore ?? "n/a"} -> ${now?.trustScore ?? "n/a"}`,
142
+ `- Passing signals: ${passCount(base)} -> ${now ? passCount(now) : "n/a"} of ${base.signals.length}`,
143
+ "",
144
+ "| Signal | Baseline | Current |",
145
+ "|--------|----------|---------|",
146
+ );
147
+ for (const sig of base.signals) {
148
+ const nowSig = now?.signals.find(s => s.id === sig.id);
149
+ lines.push(`| ${sig.label} | ${sig.status} | ${nowSig?.status ?? "n/a"} |`);
150
+ }
151
+ lines.push("");
152
+ }
153
+ if (!gate.pass) {
154
+ lines.push("## Blocking reasons", ...gate.reasons.map(r => `- ${r}`), "");
155
+ }
156
+ return lines.join("\n");
157
+ }
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Offline stealth benchmark harness (plan Phase 1).
3
+ *
4
+ * Drives a puppeteer Page (already stealth-patched by the browser tool) against
5
+ * self-contained offline detector fixtures and collects normalized results. The
6
+ * navigation/evaluation is injected so this stays unit-testable without a real
7
+ * browser; the integration test wires a live puppeteer Page.
8
+ */
9
+
10
+ import type { Page } from "puppeteer-core";
11
+ import type { DetectorResult, RawProbe } from "./detector-report";
12
+ import { parseProbe } from "./detector-report";
13
+
14
+ /** Minimal surface of a puppeteer Page that the harness needs. */
15
+ export type SuitePage = Pick<Page, "goto" | "evaluate">;
16
+
17
+ export interface SuiteFixture {
18
+ /** file:// (or http://) URL of the offline detector fixture. */
19
+ url: string;
20
+ }
21
+
22
+ /** Read the probe the fixture placed on `window.__stealthProbe`. */
23
+ function readProbe(): RawProbe {
24
+ // Runs in the browser context.
25
+ const probe = (globalThis as unknown as { __stealthProbe?: RawProbe }).__stealthProbe;
26
+ if (!probe) throw new Error("fixture did not expose window.__stealthProbe");
27
+ return probe;
28
+ }
29
+
30
+ /** Navigate to each fixture and collect a normalized DetectorResult per fixture. */
31
+ export async function runOfflineSuite(page: SuitePage, fixtures: readonly SuiteFixture[]): Promise<DetectorResult[]> {
32
+ const results: DetectorResult[] = [];
33
+ for (const fixture of fixtures) {
34
+ await page.goto(fixture.url, { waitUntil: "load" });
35
+ const raw = await page.evaluate(readProbe);
36
+ results.push(parseProbe(raw));
37
+ }
38
+ return results;
39
+ }
@@ -14,11 +14,12 @@ import stealthWebglScript from "../puppeteer/05_stealth_webgl.txt" with { type:
14
14
  import stealthScreenScript from "../puppeteer/06_stealth_screen.txt" with { type: "text" };
15
15
  import stealthFontsScript from "../puppeteer/07_stealth_fonts.txt" with { type: "text" };
16
16
  import stealthAudioScript from "../puppeteer/08_stealth_audio.txt" with { type: "text" };
17
- import stealthLocaleScript from "../puppeteer/09_stealth_locale.txt" with { type: "text" };
18
17
  import stealthPluginsScript from "../puppeteer/10_stealth_plugins.txt" with { type: "text" };
19
18
  import stealthHardwareScript from "../puppeteer/11_stealth_hardware.txt" with { type: "text" };
20
19
  import stealthCodecsScript from "../puppeteer/12_stealth_codecs.txt" with { type: "text" };
21
20
  import stealthWorkerScript from "../puppeteer/13_stealth_worker.txt" with { type: "text" };
21
+ import stealthPermissionsScript from "../puppeteer/14_stealth_permissions.txt" with { type: "text" };
22
+ import stealthWebrtcScript from "../puppeteer/15_stealth_webrtc.txt" with { type: "text" };
22
23
  import { ToolError } from "../tool-errors";
23
24
 
24
25
  export const DEFAULT_VIEWPORT = { width: 1365, height: 768, deviceScaleFactor: 1.25 };
@@ -35,7 +36,6 @@ const STEALTH_IGNORE_DEFAULT_ARGS = [
35
36
  "--disable-default-apps",
36
37
  "--disable-component-extensions-with-background-pages",
37
38
  ];
38
- const STEALTH_ACCEPT_LANGUAGE = "en-US,en";
39
39
 
40
40
  const USER_AGENT_TARGET_TIMEOUT_MS = 5_000;
41
41
  const USER_AGENT_TARGET_TYPES = new Set(["page", "webview", "background_page"]);
@@ -230,6 +230,22 @@ function resolveSystemChromium(): string | undefined {
230
230
  export interface LaunchHeadlessOptions {
231
231
  headless: boolean;
232
232
  viewport?: { width: number; height: number; deviceScaleFactor?: number };
233
+ /**
234
+ * Optional isolated warm-up profile directory (see profile-reuse.ts). When
235
+ * set, the headless browser launches against this isolated copy of the user's
236
+ * real Chrome profile so sessions inherit real cookies/storage/cache for
237
+ * stronger stealth. Callers resolve this via resolveProfileReuse and MUST
238
+ * pass an isolated copy, never a live profile dir.
239
+ */
240
+ profileWarmupDir?: string;
241
+ /**
242
+ * Optional opt-in geo alignment (see settings browser.geo.*). When set, the
243
+ * browser is launched with a matching timezone (TZ env) and/or UI language
244
+ * (--lang) at the source. Default unset = strict no-op: the real environment
245
+ * timezone/locale are preserved (never half-spoof). Only align these to a
246
+ * coherent value (e.g. one matching a configured proxy egress).
247
+ */
248
+ geo?: { timezone?: string; locale?: string };
233
249
  }
234
250
 
235
251
  export async function launchHeadlessBrowser(opts: LaunchHeadlessOptions): Promise<Browser> {
@@ -244,8 +260,16 @@ export async function launchHeadlessBrowser(opts: LaunchHeadlessOptions): Promis
244
260
  "--no-sandbox",
245
261
  "--disable-setuid-sandbox",
246
262
  "--disable-blink-features=AutomationControlled",
263
+ // Suppress WebRTC leaking the real local/public IP via ICE candidates
264
+ // (a common bot tell). Keeps WebRTC functional over the default public
265
+ // interface only; 15_stealth_webrtc.txt adds a candidate-level guard.
266
+ "--force-webrtc-ip-handling-policy=default_public_interface_only",
247
267
  `--window-size=${initialViewport.width},${initialViewport.height}`,
248
268
  ];
269
+ if (opts.profileWarmupDir) {
270
+ // Isolated copy only (caller guarantees). Never point this at a live profile.
271
+ launchArgs.push(`--user-data-dir=${opts.profileWarmupDir}`);
272
+ }
249
273
  const proxy = process.env.PUPPETEER_PROXY;
250
274
  if (proxy) {
251
275
  launchArgs.push(`--proxy-server=${proxy}`);
@@ -256,15 +280,22 @@ export async function launchHeadlessBrowser(opts: LaunchHeadlessOptions): Promis
256
280
  launchArgs.push("--proxy-bypass-list=<-loopback>");
257
281
  }
258
282
  }
283
+ // Opt-in geo alignment (default no-op). Locale via --lang at the source;
284
+ // timezone via the TZ env passed to the Chrome subprocess.
285
+ if (opts.geo?.locale) {
286
+ launchArgs.push(`--lang=${opts.geo.locale}`);
287
+ }
259
288
  const ignoreCert = process.env.PUPPETEER_PROXY_IGNORE_CERT_ERRORS?.toLowerCase();
260
289
  if (ignoreCert === "true" || ignoreCert === "1" || ignoreCert === "yes" || ignoreCert === "on") {
261
290
  launchArgs.push("--ignore-certificate-errors");
262
291
  }
292
+ const launchEnv = opts.geo?.timezone ? { ...process.env, TZ: opts.geo.timezone } : undefined;
263
293
  return await puppeteer.launch({
264
294
  headless: opts.headless,
265
295
  defaultViewport: opts.headless ? initialViewport : null,
266
296
  executablePath: await ensureChromiumExecutable(),
267
297
  args: launchArgs,
298
+ ...(launchEnv ? { env: launchEnv } : {}),
268
299
  ignoreDefaultArgs: [...STEALTH_IGNORE_DEFAULT_ARGS],
269
300
  protocolTimeout: BROWSER_PROTOCOL_TIMEOUT_MS,
270
301
  });
@@ -308,6 +339,20 @@ export interface UserAgentOverride {
308
339
  };
309
340
  }
310
341
 
342
+ function acceptLanguageForLocale(locale: string): string {
343
+ const canonicalLocale = Intl.getCanonicalLocales(locale)[0]!;
344
+ const baseLanguage = canonicalLocale.split("-")[0]!;
345
+ return canonicalLocale === baseLanguage ? canonicalLocale : `${canonicalLocale},${baseLanguage}`;
346
+ }
347
+
348
+ async function resolveAcceptLanguage(page: Page, locale?: string): Promise<string> {
349
+ if (locale) return acceptLanguageForLocale(locale);
350
+ const languages = await page.evaluate(() => [...navigator.languages]);
351
+ const acceptLanguage = languages.filter(Boolean).join(",");
352
+ if (!acceptLanguage) throw new ToolError("Chromium reported no native navigator languages");
353
+ return acceptLanguage;
354
+ }
355
+
311
356
  function resolvePageClient(page: Page): PuppeteerCdpClient | null {
312
357
  const pageWithClient = page as Page & {
313
358
  _client?: (() => PuppeteerCdpClient) | PuppeteerCdpClient;
@@ -362,7 +407,7 @@ function patchSourceUrl(page: Page): void {
362
407
  };
363
408
  }
364
409
 
365
- async function resolveUserAgentOverride(page: Page): Promise<UserAgentOverride> {
410
+ async function resolveUserAgentOverride(page: Page, locale?: string): Promise<UserAgentOverride> {
366
411
  const rawUserAgent = await page.browser().userAgent();
367
412
  let userAgent = rawUserAgent.replace("HeadlessChrome/", "Chrome/");
368
413
  if (userAgent.includes("Linux") && !userAgent.includes("Android")) {
@@ -413,11 +458,13 @@ async function resolveUserAgentOverride(page: Page): Promise<UserAgentOverride>
413
458
  brands[order[0]!] = { brand: greaseyBrand, version: "99" };
414
459
  brands[order[1]!] = { brand: "Chromium", version: String(majorVersion) };
415
460
  brands[order[2]!] = { brand: "Google Chrome", version: String(majorVersion) };
461
+ const acceptLanguage = await resolveAcceptLanguage(page, locale);
416
462
 
417
463
  return {
418
464
  userAgent,
419
465
  platform,
420
- acceptLanguage: STEALTH_ACCEPT_LANGUAGE,
466
+ acceptLanguage,
467
+
421
468
  userAgentMetadata: {
422
469
  brands,
423
470
  fullVersion: uaVersion,
@@ -436,7 +483,17 @@ function wrapSession(session: CDPSession): PuppeteerCdpClient {
436
483
  };
437
484
  }
438
485
 
439
- async function sendUserAgentOverride(client: PuppeteerCdpClient, override: UserAgentOverride): Promise<void> {
486
+ async function sendUserAgentOverride(
487
+ client: PuppeteerCdpClient,
488
+ override: UserAgentOverride,
489
+ strict = false,
490
+ ): Promise<void> {
491
+ if (strict) {
492
+ await client.send("Network.enable");
493
+ await client.send("Network.setUserAgentOverride", override as unknown as Record<string, unknown>);
494
+ await client.send("Emulation.setUserAgentOverride", override as unknown as Record<string, unknown>);
495
+ return;
496
+ }
440
497
  try {
441
498
  await client.send("Network.enable");
442
499
  } catch {}
@@ -464,28 +521,52 @@ export interface UserAgentSession {
464
521
  /** Configure UA override on the browser + auto-attach to new targets. */
465
522
  async function configureUserAgentTargets(
466
523
  browser: Browser,
467
- state: { browserSession: CDPSession | null; override: UserAgentOverride },
524
+ state: { browserSession: CDPSession | null; override: UserAgentOverride; locale?: string },
525
+
468
526
  targetTimeoutMs = USER_AGENT_TARGET_TIMEOUT_MS,
469
527
  ): Promise<void> {
470
528
  if (!state.browserSession) {
471
529
  state.browserSession = await browser.target().createCDPSession();
472
530
  await state.browserSession.send("Target.setAutoAttach", {
473
531
  autoAttach: true,
474
- waitForDebuggerOnStart: false,
532
+ waitForDebuggerOnStart: true,
475
533
  flatten: true,
476
534
  });
477
535
  state.browserSession.on(
478
536
  "Target.attachedToTarget",
479
- async (event: { sessionId: string; targetInfo?: { type?: string } }) => {
480
- if (!targetInfoSupportsUserAgentOverride(event.targetInfo)) return;
537
+ async (event: { sessionId: string; targetInfo?: { targetId?: string; type?: string } }) => {
538
+ if (!targetInfoSupportsUserAgentOverride(event.targetInfo)) {
539
+ const connection = state.browserSession?.connection();
540
+ await connection
541
+ ?.session(event.sessionId)
542
+ ?.send("Runtime.runIfWaitingForDebugger")
543
+ .catch(() => undefined);
544
+ return;
545
+ }
481
546
  const connection = state.browserSession?.connection();
482
547
  const session = connection?.session(event.sessionId);
483
548
  if (!session) return;
484
- await withSoftTimeout(
485
- sendUserAgentOverride(wrapSession(session), state.override),
486
- targetTimeoutMs,
487
- "new target user-agent override",
488
- );
549
+ try {
550
+ if (state.locale) {
551
+ await applyClientOverrides(wrapSession(session), state.override, state.locale, true);
552
+ } else {
553
+ await withSoftTimeout(
554
+ sendUserAgentOverride(wrapSession(session), state.override),
555
+ targetTimeoutMs,
556
+ "new target user-agent override",
557
+ );
558
+ }
559
+ await session.send("Runtime.runIfWaitingForDebugger");
560
+ } catch (error) {
561
+ if (event.targetInfo?.targetId) {
562
+ await state.browserSession
563
+ ?.send("Target.closeTarget", { targetId: event.targetInfo.targetId })
564
+ .catch(() => undefined);
565
+ }
566
+ logger.debug("Closed target after geo override failure", {
567
+ error: error instanceof Error ? error.message : String(error),
568
+ });
569
+ }
489
570
  },
490
571
  );
491
572
  }
@@ -511,14 +592,33 @@ function targetInfoSupportsUserAgentOverride(targetInfo: { type?: string } | und
511
592
  }
512
593
 
513
594
  async function applyTargetUserAgentOverride(target: Target, override: UserAgentOverride): Promise<void> {
595
+ await applyTargetOverrides(target, override);
596
+ }
597
+
598
+ async function applyTargetOverrides(
599
+ target: Target,
600
+ override: UserAgentOverride,
601
+ locale?: string,
602
+ strict = false,
603
+ ): Promise<void> {
514
604
  const session = await target.createCDPSession();
515
605
  try {
516
- await sendUserAgentOverride(wrapSession(session), override);
606
+ await applyClientOverrides(wrapSession(session), override, locale, strict);
517
607
  } finally {
518
608
  await session.detach().catch(() => undefined);
519
609
  }
520
610
  }
521
611
 
612
+ async function applyClientOverrides(
613
+ client: PuppeteerCdpClient,
614
+ override: UserAgentOverride,
615
+ locale?: string,
616
+ strict = false,
617
+ ): Promise<void> {
618
+ await sendUserAgentOverride(client, override, strict);
619
+ if (locale) await client.send("Emulation.setLocaleOverride", { locale });
620
+ }
621
+
522
622
  async function withSoftTimeout<T>(promise: Promise<T>, timeoutMs: number, label: string): Promise<T | undefined> {
523
623
  let timeout: NodeJS.Timeout | undefined;
524
624
  const timeoutPromise = new Promise<undefined>(resolve => {
@@ -550,11 +650,12 @@ const STEALTH_PATCH_SCRIPTS = [
550
650
  stealthScreenScript,
551
651
  stealthFontsScript,
552
652
  stealthAudioScript,
553
- stealthLocaleScript,
554
653
  stealthPluginsScript,
555
654
  stealthHardwareScript,
556
655
  stealthCodecsScript,
557
656
  stealthWorkerScript,
657
+ stealthPermissionsScript,
658
+ stealthWebrtcScript,
558
659
  ];
559
660
 
560
661
  function buildStealthInjectionScript(scripts: readonly string[] = STEALTH_PATCH_SCRIPTS): string {
@@ -624,17 +725,21 @@ export async function applyStealthPatches(
624
725
  browser: Browser,
625
726
  page: Page,
626
727
  state: { browserSession: CDPSession | null; override: UserAgentOverride | null },
728
+ geo?: { readonly timezone?: string; readonly locale?: string },
627
729
  ): Promise<void> {
628
730
  patchSourceUrl(page);
629
731
  if (!state.override) {
630
- state.override = await resolveUserAgentOverride(page);
732
+ state.override = await resolveUserAgentOverride(page, geo?.locale);
631
733
  }
632
734
  const client = resolvePageClient(page);
633
735
  if (client) {
634
- await sendUserAgentOverride(client, state.override);
736
+ await sendUserAgentOverride(client, state.override, Boolean(geo?.locale));
635
737
  }
636
- const targetState = { browserSession: state.browserSession, override: state.override };
738
+ const targetState = { browserSession: state.browserSession, override: state.override, locale: geo?.locale };
637
739
  await configureUserAgentTargets(browser, targetState);
740
+ if (client && geo?.locale) {
741
+ await client.send("Emulation.setLocaleOverride", { locale: geo.locale });
742
+ }
638
743
  state.browserSession = targetState.browserSession;
639
744
  await injectStealthScripts(page);
640
745
  }
@@ -0,0 +1,63 @@
1
+ /**
2
+ * Default Chrome profile discovery (plan Phase 2 wiring).
3
+ *
4
+ * Locates the user's real Chrome "Default" profile directory per OS so the
5
+ * default headless launch path can warm up synthetic sessions from an isolated
6
+ * copy of it (see profile-warmup.ts + profile-posture.ts). Pure path logic with
7
+ * an injectable existence check, so it is unit-testable without touching the
8
+ * real filesystem.
9
+ */
10
+
11
+ import * as os from "node:os";
12
+ import * as path from "node:path";
13
+
14
+ export interface DiscoveryEnv {
15
+ platform: NodeJS.Platform;
16
+ home: string;
17
+ /** Injectable for tests; defaults to fs.existsSync at call sites. */
18
+ exists: (p: string) => boolean;
19
+ /** Windows LOCALAPPDATA override (tests / non-default installs). */
20
+ localAppData?: string;
21
+ }
22
+
23
+ /** Candidate Chrome user-data roots for the platform (most common first). */
24
+ export function chromeUserDataRoots(env: DiscoveryEnv): string[] {
25
+ switch (env.platform) {
26
+ case "darwin":
27
+ return [path.join(env.home, "Library", "Application Support", "Google", "Chrome")];
28
+ case "win32": {
29
+ const localAppData = env.localAppData ?? path.join(env.home, "AppData", "Local");
30
+ return [path.join(localAppData, "Google", "Chrome", "User Data")];
31
+ }
32
+ default:
33
+ return [path.join(env.home, ".config", "google-chrome"), path.join(env.home, ".config", "chromium")];
34
+ }
35
+ }
36
+
37
+ export interface DiscoveredProfile {
38
+ userDataDir: string;
39
+ profileDirectory: string;
40
+ profileDir: string;
41
+ }
42
+
43
+ /**
44
+ * Discover the default Chrome profile, or null when none is present.
45
+ * Only returns a profile whose directory actually exists.
46
+ */
47
+ export function discoverDefaultChromeProfile(
48
+ env: DiscoveryEnv,
49
+ profileDirectory = "Default",
50
+ ): DiscoveredProfile | null {
51
+ for (const userDataDir of chromeUserDataRoots(env)) {
52
+ const profileDir = path.join(userDataDir, profileDirectory);
53
+ if (env.exists(profileDir)) {
54
+ return { userDataDir, profileDirectory, profileDir };
55
+ }
56
+ }
57
+ return null;
58
+ }
59
+
60
+ /** Convenience wrapper using the live OS environment + fs. */
61
+ export function defaultDiscoveryEnv(exists: (p: string) => boolean): DiscoveryEnv {
62
+ return { platform: process.platform, home: os.homedir(), exists };
63
+ }
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Auto-default profile-reuse posture decision (plan Phase 2, Intent Reconciliation).
3
+ *
4
+ * User-confirmed policy: when a usable real Chrome profile is available, the
5
+ * browser tool uses it automatically (AUTO), emits a warning, and falls back to
6
+ * synthetic stealth when unavailable. The posture is overridable via a setting.
7
+ * This is pure decision logic (no browser, no filesystem side effects) so the
8
+ * launch/attach layer can call it and it can be unit-tested deterministically.
9
+ */
10
+
11
+ /** Configured posture: `auto` (default) prefers the real profile; `opt-in` stays synthetic unless explicitly asked. */
12
+ export type ProfileReusePosture = "auto" | "opt-in";
13
+
14
+ export const DEFAULT_PROFILE_REUSE_POSTURE: ProfileReusePosture = "auto";
15
+
16
+ export interface PostureInputs {
17
+ /** Configured posture; defaults to `auto` when unset. */
18
+ posture?: ProfileReusePosture;
19
+ /** A usable real Chrome profile was detected and is attachable/safe to copy. */
20
+ realProfileAvailable: boolean;
21
+ /** Caller explicitly requested real-profile reuse for this run (e.g. app.browser === "chrome"). */
22
+ explicitlyRequested?: boolean;
23
+ }
24
+
25
+ export interface PostureDecision {
26
+ /** `real` = use the (isolated copy of the) real profile; `synthetic` = synthetic stealth session. */
27
+ mode: "real" | "synthetic";
28
+ /** User-facing warning to emit when real credentials/state are about to be used. */
29
+ warning: string | null;
30
+ /** Machine-readable reason for logs/audit. */
31
+ reason: "auto-real" | "explicit-real" | "synthetic-fallback" | "synthetic-opt-in";
32
+ }
33
+
34
+ /**
35
+ * Decide whether to reuse the real profile or run synthetic.
36
+ *
37
+ * - `auto` + available -> real (with warning)
38
+ * - `opt-in` + explicitly asked -> real (with warning)
39
+ * - `opt-in` (no explicit ask) -> synthetic
40
+ * - not available -> synthetic (fallback), even under `auto`
41
+ */
42
+ export function decideProfilePosture(inputs: PostureInputs): PostureDecision {
43
+ const posture = inputs.posture ?? DEFAULT_PROFILE_REUSE_POSTURE;
44
+ const warning =
45
+ "Using an isolated copy of your real Chrome profile (cookies/session/cache) for stealth. " +
46
+ "Real logged-in credentials may be exercised on visited pages. Set browser.profileReuse to 'opt-in' to disable.";
47
+
48
+ if (!inputs.realProfileAvailable) {
49
+ return { mode: "synthetic", warning: null, reason: "synthetic-fallback" };
50
+ }
51
+ if (posture === "auto") {
52
+ return { mode: "real", warning, reason: "auto-real" };
53
+ }
54
+ // opt-in
55
+ if (inputs.explicitlyRequested) {
56
+ return { mode: "real", warning, reason: "explicit-real" };
57
+ }
58
+ return { mode: "synthetic", warning: null, reason: "synthetic-opt-in" };
59
+ }