@gajae-code/coding-agent 0.10.1 → 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 (474) hide show
  1. package/CHANGELOG.md +70 -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/gajae-pet-widget.d.ts +1 -0
  54. package/dist/types/modes/components/model-selector.d.ts +1 -0
  55. package/dist/types/modes/components/notifications-settings-editor.d.ts +135 -0
  56. package/dist/types/modes/components/pet-capability.d.ts +37 -0
  57. package/dist/types/modes/components/pet-selector.d.ts +1 -1
  58. package/dist/types/modes/components/settings-selector.d.ts +15 -4
  59. package/dist/types/modes/components/welcome.d.ts +1 -1
  60. package/dist/types/modes/controllers/selector-controller.d.ts +35 -1
  61. package/dist/types/modes/index.d.ts +0 -4
  62. package/dist/types/modes/interactive-mode.d.ts +5 -1
  63. package/dist/types/modes/runtime-init.d.ts +2 -2
  64. package/dist/types/modes/shared/agent-wire/approval-gate.d.ts +6 -9
  65. package/dist/types/modes/shared/agent-wire/deep-interview-gate.d.ts +4 -6
  66. package/dist/types/modes/shared/agent-wire/event-contract.d.ts +6 -6
  67. package/dist/types/modes/shared/agent-wire/event-envelope.d.ts +4 -9
  68. package/dist/types/modes/shared/agent-wire/event-observation.d.ts +1 -1
  69. package/dist/types/modes/shared/agent-wire/workflow-gate-broker.d.ts +169 -30
  70. package/dist/types/modes/shared/agent-wire/workflow-gate-schema.d.ts +7 -7
  71. package/dist/types/modes/shared/agent-wire/workflow-gate-types.d.ts +105 -0
  72. package/dist/types/modes/types.d.ts +16 -1
  73. package/dist/types/runtime-mcp/client.d.ts +2 -0
  74. package/dist/types/runtime-mcp/config.d.ts +5 -1
  75. package/dist/types/runtime-mcp/manager.d.ts +8 -1
  76. package/dist/types/runtime-mcp/types.d.ts +4 -0
  77. package/dist/types/sdk/acp/adapter.d.ts +67 -0
  78. package/dist/types/sdk/acp/index.d.ts +2 -0
  79. package/dist/types/sdk/broker/broker.d.ts +53 -0
  80. package/dist/types/sdk/broker/discovery.d.ts +30 -0
  81. package/dist/types/sdk/broker/ensure.d.ts +33 -0
  82. package/dist/types/sdk/broker/identity.d.ts +3 -0
  83. package/dist/types/sdk/broker/index.d.ts +8 -0
  84. package/dist/types/sdk/broker/lifecycle-ledger.d.ts +95 -0
  85. package/dist/types/sdk/broker/lifecycle.d.ts +85 -0
  86. package/dist/types/sdk/broker/process-incarnation.d.ts +14 -0
  87. package/dist/types/sdk/broker/runtime.d.ts +33 -0
  88. package/dist/types/sdk/broker/session-index.d.ts +57 -0
  89. package/dist/types/sdk/broker/state-version.d.ts +8 -0
  90. package/dist/types/sdk/broker/transport.d.ts +9 -0
  91. package/dist/types/sdk/bus/chat-command-policy.d.ts +49 -0
  92. package/dist/types/sdk/bus/chat-daemon-cli.d.ts +21 -0
  93. package/dist/types/sdk/bus/chat-daemon-control.d.ts +111 -0
  94. package/dist/types/sdk/bus/chat-daemon-runtime.d.ts +77 -0
  95. package/dist/types/sdk/bus/chat-effect-journal.d.ts +84 -0
  96. package/dist/types/{notifications → sdk/bus}/config-commands.d.ts +7 -2
  97. package/dist/types/sdk/bus/config.d.ts +274 -0
  98. package/dist/types/sdk/bus/conversation-store.d.ts +72 -0
  99. package/dist/types/sdk/bus/discord-conversation.d.ts +58 -0
  100. package/dist/types/sdk/bus/discord-daemon.d.ts +45 -0
  101. package/dist/types/sdk/bus/discord-live-provider.d.ts +70 -0
  102. package/dist/types/sdk/bus/discord-provider.d.ts +85 -0
  103. package/dist/types/{notifications → sdk/bus}/html-format.d.ts +2 -2
  104. package/dist/types/{notifications → sdk/bus}/index.d.ts +113 -13
  105. package/dist/types/{notifications → sdk/bus}/lifecycle-control-runtime.d.ts +4 -2
  106. package/dist/types/{notifications → sdk/bus}/lifecycle-orchestrator.d.ts +18 -21
  107. package/dist/types/{notifications → sdk/bus}/managed-daemon.d.ts +1 -1
  108. package/dist/types/sdk/bus/native-runtime-compatibility.d.ts +13 -0
  109. package/dist/types/sdk/bus/notification-orchestration.d.ts +170 -0
  110. package/dist/types/{notifications → sdk/bus}/notification-service.d.ts +7 -1
  111. package/dist/types/sdk/bus/session-control.d.ts +83 -0
  112. package/dist/types/sdk/bus/slack-conversation.d.ts +56 -0
  113. package/dist/types/sdk/bus/slack-daemon.d.ts +60 -0
  114. package/dist/types/sdk/bus/slack-live-provider.d.ts +59 -0
  115. package/dist/types/sdk/bus/slack-provider.d.ts +55 -0
  116. package/dist/types/{notifications → sdk/bus}/telegram-cli.d.ts +4 -4
  117. package/dist/types/{notifications → sdk/bus}/telegram-daemon-cli.d.ts +14 -5
  118. package/dist/types/sdk/bus/telegram-daemon-contract.d.ts +12 -0
  119. package/dist/types/{notifications → sdk/bus}/telegram-daemon-control.d.ts +2 -2
  120. package/dist/types/{notifications → sdk/bus}/telegram-daemon.d.ts +55 -17
  121. package/dist/types/{notifications → sdk/bus}/telegram-reference.d.ts +2 -2
  122. package/dist/types/sdk/bus/telegram-setup.d.ts +128 -0
  123. package/dist/types/{notifications → sdk/bus}/topic-registry.d.ts +11 -0
  124. package/dist/types/sdk/cli/index.d.ts +1 -0
  125. package/dist/types/sdk/cli/session-cli.d.ts +19 -0
  126. package/dist/types/sdk/client/client.d.ts +1 -0
  127. package/dist/types/sdk/client/discovery.d.ts +27 -0
  128. package/dist/types/sdk/client/index.d.ts +2 -0
  129. package/dist/types/sdk/host/control/dispatch.d.ts +34 -0
  130. package/dist/types/sdk/host/control/index.d.ts +2 -0
  131. package/dist/types/sdk/host/control/operations.d.ts +65 -0
  132. package/dist/types/sdk/host/events.d.ts +35 -0
  133. package/dist/types/sdk/host/host.d.ts +35 -0
  134. package/dist/types/sdk/host/index.d.ts +4 -0
  135. package/dist/types/sdk/host/query/cursor.d.ts +62 -0
  136. package/dist/types/sdk/host/query/handlers.d.ts +70 -0
  137. package/dist/types/sdk/host/query/index.d.ts +3 -0
  138. package/dist/types/sdk/host/query/revision-store.d.ts +60 -0
  139. package/dist/types/sdk/host/reverse-leases.d.ts +45 -0
  140. package/dist/types/sdk/host/types.d.ts +32 -0
  141. package/dist/types/sdk/index.d.ts +6 -0
  142. package/dist/types/sdk/lifecycle-session.d.ts +14 -0
  143. package/dist/types/sdk/mcp/index.d.ts +1 -0
  144. package/dist/types/sdk/mcp/server.d.ts +37 -0
  145. package/dist/types/sdk/models.d.ts +44 -0
  146. package/dist/types/sdk/protocol/adapter-validation.d.ts +14 -0
  147. package/dist/types/sdk/protocol/operation-registry.d.ts +24 -0
  148. package/dist/types/{sdk.d.ts → sdk/session.d.ts} +44 -38
  149. package/dist/types/sdk/startup-capability.d.ts +50 -0
  150. package/dist/types/session/agent-session.d.ts +114 -21
  151. package/dist/types/session/default-model-selection.d.ts +25 -0
  152. package/dist/types/session/fallback-chain-controller.d.ts +52 -0
  153. package/dist/types/session/session-manager.d.ts +58 -1
  154. package/dist/types/setup/credential-auto-import.d.ts +36 -6
  155. package/dist/types/tools/ask-answer-registry.d.ts +1 -1
  156. package/dist/types/tools/browser/benchmark/detector-report.d.ts +63 -0
  157. package/dist/types/tools/browser/benchmark/run-suite.d.ts +18 -0
  158. package/dist/types/tools/browser/launch.d.ts +22 -0
  159. package/dist/types/tools/browser/profile-discovery.d.ts +31 -0
  160. package/dist/types/tools/browser/profile-posture.d.ts +37 -0
  161. package/dist/types/tools/browser/profile-reuse.d.ts +39 -0
  162. package/dist/types/tools/browser/profile-warmup.d.ts +39 -0
  163. package/dist/types/tools/browser/registry.d.ts +19 -0
  164. package/dist/types/tools/browser/tab-protocol.d.ts +4 -0
  165. package/dist/types/tools/index.d.ts +8 -8
  166. package/package.json +34 -13
  167. package/scripts/build-sdk-package-smoke.ts +94 -0
  168. package/scripts/capture-notifications-settings-showcase.ts +435 -0
  169. package/scripts/compile-args.ts +4 -2
  170. package/scripts/g005-daemon-smoke.ts +4 -5
  171. package/scripts/g011-daemon-path-smoke.ts +5 -5
  172. package/scripts/generate-sdk-adapter-parity-manifest.ts +163 -0
  173. package/scripts/generate-sdk-operation-inventory.ts +867 -0
  174. package/scripts/generate-telegram-baseline-manifest.ts +128 -0
  175. package/scripts/manifest-schema.ts +124 -0
  176. package/scripts/run-test-manifest.ts +153 -0
  177. package/scripts/run-threat-model-check.ts +157 -0
  178. package/scripts/verify-gjc-sdk-canonicalization.ts +3467 -0
  179. package/scripts/verify-gjc-sdk-rename.ts +90 -0
  180. package/src/append-only-mode.ts +1 -1
  181. package/src/cli/args.ts +43 -12
  182. package/src/cli/auth-gateway-cli.ts +2 -2
  183. package/src/cli/config-cli.ts +2 -1
  184. package/src/cli/daemon-cli.ts +63 -14
  185. package/src/cli/list-models.ts +1 -1
  186. package/src/cli/notify-cli.ts +288 -286
  187. package/src/cli.ts +21 -2
  188. package/src/commands/daemon.ts +50 -6
  189. package/src/commands/harness.ts +93 -36
  190. package/src/commands/launch.ts +5 -2
  191. package/src/commands/mcp-serve.ts +19 -12
  192. package/src/commands/notify.ts +36 -3
  193. package/src/commands/sdk.ts +426 -0
  194. package/src/commit/agentic/agent.ts +1 -0
  195. package/src/config/atomic-yaml-patch.ts +423 -0
  196. package/src/config/model-profile-activation.ts +240 -89
  197. package/src/config/model-profiles.ts +37 -34
  198. package/src/config/model-registry.ts +51 -26
  199. package/src/config/model-resolver.ts +138 -51
  200. package/src/config/model-selector-value.ts +50 -0
  201. package/src/config/models-config-schema.ts +14 -21
  202. package/src/config/settings-schema.ts +128 -10
  203. package/src/config/settings.ts +1120 -158
  204. package/src/coordinator-mcp/model-preset.ts +74 -20
  205. package/src/coordinator-mcp/server.ts +1597 -3052
  206. package/src/daemon/builtin.ts +8 -5
  207. package/src/daemon/control-types.ts +1 -1
  208. package/src/defaults/gjc/skills/team/SKILL.md +4 -4
  209. package/src/discovery/mcp-json.ts +327 -20
  210. package/src/extensibility/custom-tools/types.ts +1 -1
  211. package/src/extensibility/extensions/compact-handler.ts +3 -3
  212. package/src/extensibility/extensions/get-commands-handler.ts +2 -2
  213. package/src/extensibility/extensions/loader.ts +69 -5
  214. package/src/extensibility/extensions/runner.ts +112 -4
  215. package/src/extensibility/extensions/types.ts +176 -17
  216. package/src/extensibility/hooks/types.ts +1 -1
  217. package/src/extensibility/slash-commands.ts +3 -3
  218. package/src/gjc-runtime/launch-tmux.ts +170 -86
  219. package/src/gjc-runtime/psmux-detect.ts +82 -4
  220. package/src/gjc-runtime/session-state-sidecar.ts +41 -31
  221. package/src/gjc-runtime/team-runtime.ts +54 -35
  222. package/src/gjc-runtime/tmux-owner-isolation-cli.ts +53 -17
  223. package/src/gjc-runtime/tmux-owner-isolation.ts +5 -2
  224. package/src/gjc-runtime/tmux-sessions.ts +19 -13
  225. package/src/gjc-runtime/ultragoal-guard.ts +53 -6
  226. package/src/gjc-runtime/ultragoal-runtime.ts +155 -3
  227. package/src/gjc-runtime/windows-powershell-command.ts +58 -0
  228. package/src/harness-control-plane/operate.ts +9 -9
  229. package/src/harness-control-plane/owner.ts +283 -39
  230. package/src/harness-control-plane/receipts.ts +0 -1
  231. package/src/harness-control-plane/sdk-transport.ts +395 -0
  232. package/src/harness-control-plane/session-transport.ts +94 -0
  233. package/src/harness-control-plane/types.ts +1 -1
  234. package/src/internal-urls/docs-index.generated.ts +36 -37
  235. package/src/lsp/client.ts +42 -6
  236. package/src/lsp/index.ts +2 -2
  237. package/src/main.ts +299 -204
  238. package/src/modes/DESIGN.md +258 -0
  239. package/src/modes/acp/acp-agent.ts +1228 -2612
  240. package/src/modes/acp/acp-client-bridge.ts +2 -20
  241. package/src/modes/acp/acp-event-mapper.ts +18 -2
  242. package/src/modes/acp/acp-mode.ts +8 -36
  243. package/src/modes/acp/permission-mode.ts +25 -0
  244. package/src/modes/acp/startup-options.ts +6 -0
  245. package/src/modes/components/agent-dashboard.ts +37 -17
  246. package/src/modes/components/custom-editor.ts +1 -0
  247. package/src/modes/components/gajae-pet-widget.ts +169 -20
  248. package/src/modes/components/model-selector.ts +93 -35
  249. package/src/modes/components/notifications-settings-editor.ts +1379 -0
  250. package/src/modes/components/pet-capability.ts +115 -0
  251. package/src/modes/components/pet-selector.ts +4 -6
  252. package/src/modes/components/settings-selector.ts +86 -11
  253. package/src/modes/components/welcome.ts +4 -4
  254. package/src/modes/controllers/command-controller.ts +1 -2
  255. package/src/modes/controllers/event-controller.ts +11 -16
  256. package/src/modes/controllers/extension-ui-controller.ts +357 -12
  257. package/src/modes/controllers/input-controller.ts +43 -13
  258. package/src/modes/controllers/selector-controller.ts +671 -44
  259. package/src/modes/index.ts +0 -22
  260. package/src/modes/interactive-mode.ts +108 -24
  261. package/src/modes/runtime-init.ts +298 -6
  262. package/src/modes/shared/agent-wire/approval-gate.ts +9 -11
  263. package/src/modes/shared/agent-wire/deep-interview-gate.ts +10 -11
  264. package/src/modes/shared/agent-wire/event-contract.ts +7 -8
  265. package/src/modes/shared/agent-wire/event-envelope.ts +9 -17
  266. package/src/modes/shared/agent-wire/event-observation.ts +16 -7
  267. package/src/modes/shared/agent-wire/workflow-gate-broker.ts +1254 -87
  268. package/src/modes/shared/agent-wire/workflow-gate-schema.ts +15 -15
  269. package/src/modes/shared/agent-wire/workflow-gate-types.ts +113 -0
  270. package/src/modes/types.ts +16 -1
  271. package/src/runtime-mcp/client.ts +94 -19
  272. package/src/runtime-mcp/config.ts +27 -15
  273. package/src/runtime-mcp/manager.ts +343 -105
  274. package/src/runtime-mcp/oauth-flow.ts +42 -12
  275. package/src/runtime-mcp/transports/http.ts +49 -19
  276. package/src/runtime-mcp/transports/stdio.ts +47 -28
  277. package/src/runtime-mcp/types.ts +10 -0
  278. package/src/sdk/acp/adapter.ts +418 -0
  279. package/src/sdk/acp/index.ts +2 -0
  280. package/src/sdk/broker/broker.ts +642 -0
  281. package/src/sdk/broker/discovery.ts +94 -0
  282. package/src/sdk/broker/ensure.ts +249 -0
  283. package/src/sdk/broker/identity.ts +42 -0
  284. package/src/sdk/broker/index.ts +8 -0
  285. package/src/sdk/broker/internal-source-marker-2178.txt +1 -0
  286. package/src/sdk/broker/internal-source.bunfig.toml +1 -0
  287. package/src/sdk/broker/lifecycle-ledger.ts +286 -0
  288. package/src/sdk/broker/lifecycle.ts +2157 -0
  289. package/src/sdk/broker/process-incarnation.ts +159 -0
  290. package/src/sdk/broker/runtime.ts +164 -0
  291. package/src/sdk/broker/session-index.ts +318 -0
  292. package/src/sdk/broker/state-version.ts +23 -0
  293. package/src/sdk/broker/transport.ts +125 -0
  294. package/src/sdk/bus/chat-command-policy.ts +107 -0
  295. package/src/sdk/bus/chat-daemon-cli.ts +214 -0
  296. package/src/sdk/bus/chat-daemon-control.ts +713 -0
  297. package/src/sdk/bus/chat-daemon-runtime.ts +526 -0
  298. package/src/sdk/bus/chat-effect-journal.ts +353 -0
  299. package/src/{notifications → sdk/bus}/config-commands.ts +39 -10
  300. package/src/sdk/bus/config.ts +433 -0
  301. package/src/sdk/bus/conversation-store.ts +391 -0
  302. package/src/sdk/bus/discord-conversation.ts +85 -0
  303. package/src/sdk/bus/discord-daemon.ts +2275 -0
  304. package/src/sdk/bus/discord-live-provider.ts +521 -0
  305. package/src/sdk/bus/discord-provider.ts +56 -0
  306. package/src/{notifications → sdk/bus}/html-format.ts +2 -2
  307. package/src/sdk/bus/index.ts +3943 -0
  308. package/src/{notifications → sdk/bus}/lifecycle-commands.ts +2 -0
  309. package/src/{notifications → sdk/bus}/lifecycle-control-runtime.ts +225 -196
  310. package/src/{notifications → sdk/bus}/lifecycle-orchestrator.ts +161 -74
  311. package/src/{notifications → sdk/bus}/managed-daemon.ts +2 -2
  312. package/src/sdk/bus/native-runtime-compatibility.ts +42 -0
  313. package/src/sdk/bus/natives-augment.d.ts +38 -0
  314. package/src/sdk/bus/notification-orchestration.ts +535 -0
  315. package/src/{notifications → sdk/bus}/notification-service.ts +106 -12
  316. package/src/sdk/bus/session-control.ts +333 -0
  317. package/src/sdk/bus/slack-conversation.ts +74 -0
  318. package/src/sdk/bus/slack-daemon.ts +2144 -0
  319. package/src/sdk/bus/slack-live-provider.ts +380 -0
  320. package/src/sdk/bus/slack-provider.ts +76 -0
  321. package/src/{notifications → sdk/bus}/telegram-cli.ts +8 -8
  322. package/src/sdk/bus/telegram-daemon-cli.ts +330 -0
  323. package/src/sdk/bus/telegram-daemon-contract.ts +14 -0
  324. package/src/{notifications → sdk/bus}/telegram-daemon-control.ts +4 -4
  325. package/src/{notifications → sdk/bus}/telegram-daemon.ts +502 -54
  326. package/src/{notifications → sdk/bus}/telegram-reference.ts +2 -2
  327. package/src/sdk/bus/telegram-setup.ts +663 -0
  328. package/src/{notifications → sdk/bus}/topic-registry.ts +32 -0
  329. package/src/sdk/cli/index.ts +1 -0
  330. package/src/sdk/cli/session-cli.ts +275 -0
  331. package/src/sdk/client/client.ts +1 -0
  332. package/src/sdk/client/discovery.ts +108 -0
  333. package/src/sdk/client/index.ts +2 -0
  334. package/src/sdk/host/control/dispatch.ts +367 -0
  335. package/src/sdk/host/control/index.ts +10 -0
  336. package/src/sdk/host/control/operations.ts +63 -0
  337. package/src/sdk/host/events.ts +91 -0
  338. package/src/sdk/host/host.ts +296 -0
  339. package/src/sdk/host/index.ts +4 -0
  340. package/src/sdk/host/query/cursor.ts +189 -0
  341. package/src/sdk/host/query/handlers.ts +533 -0
  342. package/src/sdk/host/query/index.ts +3 -0
  343. package/src/sdk/host/query/revision-store.ts +1126 -0
  344. package/src/sdk/host/reverse-leases.ts +325 -0
  345. package/src/sdk/host/types.ts +29 -0
  346. package/src/sdk/index.ts +13 -0
  347. package/src/sdk/lifecycle-session.ts +39 -0
  348. package/src/sdk/mcp/index.ts +1 -0
  349. package/src/sdk/mcp/server.ts +332 -0
  350. package/src/sdk/models.ts +168 -0
  351. package/src/sdk/protocol/adapter-validation.ts +48 -0
  352. package/src/sdk/protocol/operation-inventory.generated.json +5654 -0
  353. package/src/sdk/protocol/operation-registry.ts +312 -0
  354. package/src/{sdk.ts → sdk/session.ts} +339 -212
  355. package/src/sdk/startup-capability.ts +189 -0
  356. package/src/session/agent-session.ts +2470 -866
  357. package/src/session/default-model-selection.ts +93 -0
  358. package/src/session/fallback-chain-controller.ts +136 -0
  359. package/src/session/session-manager.ts +447 -13
  360. package/src/session/session-storage.ts +8 -1
  361. package/src/setup/credential-auto-import.ts +290 -35
  362. package/src/setup/hermes/templates/operator-instructions.v1.md +3 -5
  363. package/src/slash-commands/builtin-registry.ts +33 -30
  364. package/src/task/executor.ts +62 -13
  365. package/src/tools/ask-answer-registry.ts +1 -1
  366. package/src/tools/ask.ts +13 -8
  367. package/src/tools/browser/STEALTH-THIRD-PARTY-NOTICES.md +26 -0
  368. package/src/tools/browser/benchmark/detector-report.ts +157 -0
  369. package/src/tools/browser/benchmark/run-suite.ts +39 -0
  370. package/src/tools/browser/launch.ts +124 -19
  371. package/src/tools/browser/profile-discovery.ts +63 -0
  372. package/src/tools/browser/profile-posture.ts +59 -0
  373. package/src/tools/browser/profile-reuse.ts +102 -0
  374. package/src/tools/browser/profile-warmup.ts +109 -0
  375. package/src/tools/browser/registry.ts +87 -11
  376. package/src/tools/browser/tab-protocol.ts +1 -0
  377. package/src/tools/browser/tab-supervisor.ts +1 -0
  378. package/src/tools/browser/tab-worker.ts +1 -1
  379. package/src/tools/browser.ts +6 -0
  380. package/src/tools/index.ts +8 -8
  381. package/src/tools/puppeteer/14_stealth_permissions.txt +57 -0
  382. package/src/tools/puppeteer/15_stealth_webrtc.txt +60 -0
  383. package/src/tools/telegram-send.ts +2 -2
  384. package/vendor/insane-search/MANIFEST.json +2 -1
  385. package/vendor/insane-search/engine/bias_check.py +4 -1
  386. package/vendor/insane-search/engine/phase0.py +26 -1
  387. package/dist/types/harness-control-plane/rpc-adapter.d.ts +0 -69
  388. package/dist/types/modes/bridge/auth.d.ts +0 -12
  389. package/dist/types/modes/bridge/bridge-client-bridge.d.ts +0 -9
  390. package/dist/types/modes/bridge/bridge-mode.d.ts +0 -47
  391. package/dist/types/modes/bridge/bridge-ui-context.d.ts +0 -88
  392. package/dist/types/modes/bridge/event-stream.d.ts +0 -8
  393. package/dist/types/modes/rpc/host-tools.d.ts +0 -1
  394. package/dist/types/modes/rpc/host-uris.d.ts +0 -1
  395. package/dist/types/modes/rpc/rpc-client.d.ts +0 -299
  396. package/dist/types/modes/rpc/rpc-mode.d.ts +0 -86
  397. package/dist/types/modes/rpc/rpc-socket-security.d.ts +0 -10
  398. package/dist/types/modes/rpc/rpc-types.d.ts +0 -810
  399. package/dist/types/modes/shared/agent-wire/command-contract.d.ts +0 -18
  400. package/dist/types/modes/shared/agent-wire/command-dispatch.d.ts +0 -37
  401. package/dist/types/modes/shared/agent-wire/command-validation.d.ts +0 -2
  402. package/dist/types/modes/shared/agent-wire/handshake.d.ts +0 -56
  403. package/dist/types/modes/shared/agent-wire/host-tool-bridge.d.ts +0 -16
  404. package/dist/types/modes/shared/agent-wire/host-uri-bridge.d.ts +0 -17
  405. package/dist/types/modes/shared/agent-wire/protocol.d.ts +0 -25
  406. package/dist/types/modes/shared/agent-wire/responses.d.ts +0 -4
  407. package/dist/types/modes/shared/agent-wire/scopes.d.ts +0 -18
  408. package/dist/types/modes/shared/agent-wire/session-registry.d.ts +0 -25
  409. package/dist/types/modes/shared/agent-wire/ui-request-broker.d.ts +0 -42
  410. package/dist/types/modes/shared/agent-wire/ui-result.d.ts +0 -27
  411. package/dist/types/modes/shared/agent-wire/unattended-action-policy.d.ts +0 -29
  412. package/dist/types/modes/shared/agent-wire/unattended-audit.d.ts +0 -68
  413. package/dist/types/modes/shared/agent-wire/unattended-run-controller.d.ts +0 -166
  414. package/dist/types/modes/shared/agent-wire/unattended-session.d.ts +0 -127
  415. package/dist/types/notifications/config.d.ts +0 -132
  416. package/src/harness-control-plane/rpc-adapter.ts +0 -290
  417. package/src/modes/bridge/auth.ts +0 -41
  418. package/src/modes/bridge/bridge-client-bridge.ts +0 -47
  419. package/src/modes/bridge/bridge-mode.ts +0 -675
  420. package/src/modes/bridge/bridge-ui-context.ts +0 -200
  421. package/src/modes/bridge/event-stream.ts +0 -70
  422. package/src/modes/rpc/host-tools.ts +0 -1
  423. package/src/modes/rpc/host-uris.ts +0 -1
  424. package/src/modes/rpc/rpc-client.ts +0 -1166
  425. package/src/modes/rpc/rpc-mode.ts +0 -1029
  426. package/src/modes/rpc/rpc-socket-security.ts +0 -115
  427. package/src/modes/rpc/rpc-types.ts +0 -637
  428. package/src/modes/shared/agent-wire/command-contract.ts +0 -18
  429. package/src/modes/shared/agent-wire/command-dispatch.ts +0 -498
  430. package/src/modes/shared/agent-wire/command-validation.ts +0 -181
  431. package/src/modes/shared/agent-wire/handshake.ts +0 -157
  432. package/src/modes/shared/agent-wire/host-tool-bridge.ts +0 -197
  433. package/src/modes/shared/agent-wire/host-uri-bridge.ts +0 -236
  434. package/src/modes/shared/agent-wire/protocol.ts +0 -46
  435. package/src/modes/shared/agent-wire/responses.ts +0 -17
  436. package/src/modes/shared/agent-wire/scopes.ts +0 -94
  437. package/src/modes/shared/agent-wire/session-registry.ts +0 -109
  438. package/src/modes/shared/agent-wire/ui-request-broker.ts +0 -150
  439. package/src/modes/shared/agent-wire/ui-result.ts +0 -48
  440. package/src/modes/shared/agent-wire/unattended-action-policy.ts +0 -365
  441. package/src/modes/shared/agent-wire/unattended-audit.ts +0 -176
  442. package/src/modes/shared/agent-wire/unattended-run-controller.ts +0 -426
  443. package/src/modes/shared/agent-wire/unattended-session.ts +0 -528
  444. package/src/notifications/config.ts +0 -219
  445. package/src/notifications/index.ts +0 -1835
  446. package/src/notifications/telegram-daemon-cli.ts +0 -243
  447. package/src/tools/puppeteer/09_stealth_locale.txt +0 -46
  448. /package/dist/types/{notifications → sdk/bus}/attachment-registry.d.ts +0 -0
  449. /package/dist/types/{notifications → sdk/bus}/chat-adapters.d.ts +0 -0
  450. /package/dist/types/{notifications → sdk/bus}/daemon-paths.d.ts +0 -0
  451. /package/dist/types/{notifications → sdk/bus}/engine.d.ts +0 -0
  452. /package/dist/types/{notifications → sdk/bus}/helpers.d.ts +0 -0
  453. /package/dist/types/{notifications → sdk/bus}/lifecycle-commands.d.ts +0 -0
  454. /package/dist/types/{notifications → sdk/bus}/operator-runtime.d.ts +0 -0
  455. /package/dist/types/{notifications → sdk/bus}/rate-limit-pool.d.ts +0 -0
  456. /package/dist/types/{notifications → sdk/bus}/recent-activity.d.ts +0 -0
  457. /package/dist/types/{notifications → sdk/bus}/reply-sent-store.d.ts +0 -0
  458. /package/dist/types/{notifications → sdk/bus}/rich-draft.d.ts +0 -0
  459. /package/dist/types/{notifications → sdk/bus}/rich-render.d.ts +0 -0
  460. /package/dist/types/{notifications → sdk/bus}/threaded-inbound.d.ts +0 -0
  461. /package/dist/types/{notifications → sdk/bus}/threaded-render.d.ts +0 -0
  462. /package/src/{notifications → sdk/bus}/attachment-registry.ts +0 -0
  463. /package/src/{notifications → sdk/bus}/chat-adapters.ts +0 -0
  464. /package/src/{notifications → sdk/bus}/daemon-paths.ts +0 -0
  465. /package/src/{notifications → sdk/bus}/engine.ts +0 -0
  466. /package/src/{notifications → sdk/bus}/helpers.ts +0 -0
  467. /package/src/{notifications → sdk/bus}/operator-runtime.ts +0 -0
  468. /package/src/{notifications → sdk/bus}/rate-limit-pool.ts +0 -0
  469. /package/src/{notifications → sdk/bus}/recent-activity.ts +0 -0
  470. /package/src/{notifications → sdk/bus}/reply-sent-store.ts +0 -0
  471. /package/src/{notifications → sdk/bus}/rich-draft.ts +0 -0
  472. /package/src/{notifications → sdk/bus}/rich-render.ts +0 -0
  473. /package/src/{notifications → sdk/bus}/threaded-inbound.ts +0 -0
  474. /package/src/{notifications → sdk/bus}/threaded-render.ts +0 -0
@@ -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
+ }
@@ -0,0 +1,102 @@
1
+ /**
2
+ * Profile-reuse orchestration (plan Phase 2 wiring).
3
+ *
4
+ * Single entry point the launch path calls to decide, for a default headless
5
+ * session, whether to warm up from an isolated copy of the user's real Chrome
6
+ * profile. Ties together discovery + posture + isolated warm-up. Filesystem
7
+ * effects (the copy) are performed only when the posture resolves to `real`.
8
+ * The heavy pieces are injectable so this is unit-testable without a browser.
9
+ */
10
+
11
+ import * as fs from "node:fs";
12
+ import * as os from "node:os";
13
+ import * as path from "node:path";
14
+ import { type DiscoveredProfile, type DiscoveryEnv, discoverDefaultChromeProfile } from "./profile-discovery";
15
+ import { decideProfilePosture, type ProfileReusePosture } from "./profile-posture";
16
+ import { collectWarmupArtifacts, type WarmupManifest } from "./profile-warmup";
17
+
18
+ export interface ResolveProfileReuseInputs {
19
+ posture?: ProfileReusePosture;
20
+ /** Caller explicitly requested real-profile reuse (e.g. app.browser === "chrome"). */
21
+ explicitlyRequested?: boolean;
22
+ discoveryEnv: DiscoveryEnv;
23
+ /** Destination for the isolated warm-up copy; defaults to an ephemeral temp dir. */
24
+ destDir?: string;
25
+ /** Injectable copier (defaults to collectWarmupArtifacts). */
26
+ copy?: (sourceProfileDir: string, destDir: string) => WarmupManifest;
27
+ /** Injectable temp-dir factory (defaults to fs.mkdtemp under os.tmpdir()). */
28
+ makeTempDir?: () => string;
29
+ }
30
+
31
+ export interface ProfileReuseResult {
32
+ mode: "real" | "synthetic";
33
+ reason: string;
34
+ warning: string | null;
35
+ discovered: DiscoveredProfile | null;
36
+ /** Isolated copy directory when mode === "real", else null. */
37
+ warmupDir: string | null;
38
+ manifest: WarmupManifest | null;
39
+ }
40
+
41
+ function defaultTempDir(): string {
42
+ return fs.mkdtempSync(path.join(os.tmpdir(), "gjc-profile-warmup-"));
43
+ }
44
+
45
+ function errorMessage(error: unknown): string {
46
+ return error instanceof Error ? error.message : String(error);
47
+ }
48
+
49
+ /**
50
+ * Resolve profile reuse for a default session. When the posture resolves to
51
+ * `real`, copies an allowlisted, lock-free subset of the discovered profile
52
+ * into an isolated dir and returns that dir for the launcher to use.
53
+ */
54
+ export function resolveProfileReuse(inputs: ResolveProfileReuseInputs): ProfileReuseResult {
55
+ const discovered = discoverDefaultChromeProfile(inputs.discoveryEnv);
56
+ const decision = decideProfilePosture({
57
+ posture: inputs.posture,
58
+ realProfileAvailable: discovered !== null,
59
+ explicitlyRequested: inputs.explicitlyRequested,
60
+ });
61
+
62
+ if (decision.mode !== "real" || !discovered) {
63
+ return {
64
+ mode: "synthetic",
65
+ reason: decision.reason,
66
+ warning: null,
67
+ discovered,
68
+ warmupDir: null,
69
+ manifest: null,
70
+ };
71
+ }
72
+
73
+ const ownsDestDir = inputs.destDir === undefined;
74
+ let destDir: string | undefined;
75
+ const copy = inputs.copy ?? collectWarmupArtifacts;
76
+ try {
77
+ destDir = inputs.destDir ?? (inputs.makeTempDir ?? defaultTempDir)();
78
+ const manifest = copy(discovered.profileDir, destDir);
79
+ return {
80
+ mode: "real",
81
+ reason: decision.reason,
82
+ warning: decision.warning,
83
+ discovered,
84
+ warmupDir: destDir,
85
+ manifest,
86
+ };
87
+ } catch (error) {
88
+ if (ownsDestDir && destDir) {
89
+ try {
90
+ fs.rmSync(destDir, { recursive: true, force: true });
91
+ } catch {}
92
+ }
93
+ return {
94
+ mode: "synthetic",
95
+ reason: "synthetic-copy-failed",
96
+ warning: `Could not safely copy the discovered Chrome profile; using synthetic browser state instead: ${errorMessage(error)}`,
97
+ discovered,
98
+ warmupDir: null,
99
+ manifest: null,
100
+ };
101
+ }
102
+ }
@@ -0,0 +1,109 @@
1
+ /**
2
+ * Isolated profile warm-up (plan Phase 2, R-C3).
3
+ *
4
+ * Aggressive real-profile reuse seeds a session with the user's cookies /
5
+ * localStorage / cache. To stay safe (never lock or corrupt the live browser
6
+ * session) we NEVER bind the source profile directly: we copy an allowlisted
7
+ * subset of artifacts into an ephemeral, isolated directory and drive Chromium
8
+ * against that copy. Chromium single-instance lock files (SingletonLock/Socket/
9
+ * Cookie) are explicitly excluded so the isolated copy can never contend with a
10
+ * running browser.
11
+ *
12
+ * This module is pure filesystem logic (no browser, no network) so it is
13
+ * deterministically unit-testable.
14
+ */
15
+
16
+ import * as fs from "node:fs";
17
+ import * as path from "node:path";
18
+
19
+ /** Chromium single-instance lock artifacts — must never be copied. */
20
+ export const CHROME_LOCK_ARTIFACTS = ["SingletonLock", "SingletonSocket", "SingletonCookie"] as const;
21
+ const CHROME_LOCK_ARTIFACT_SET = new Set<string>(CHROME_LOCK_ARTIFACTS);
22
+
23
+ /**
24
+ * Profile-relative artifacts worth seeding for warm-up. Kept intentionally
25
+ * small: session state (cookies, storage) plus a light cache. Anything not
26
+ * listed is skipped, which also keeps the isolated copy cheap.
27
+ */
28
+ export const WARMUP_ARTIFACTS = [
29
+ "Cookies",
30
+ "Cookies-journal",
31
+ "Local Storage",
32
+ "Session Storage",
33
+ "IndexedDB",
34
+ "Network",
35
+ "Preferences",
36
+ ] as const;
37
+
38
+ export interface WarmupManifest {
39
+ sourceProfileDir: string;
40
+ destDir: string;
41
+ copied: string[];
42
+ skippedMissing: string[];
43
+ /** Always empty unless a lock artifact was seen (never copied). */
44
+ excludedLocks: string[];
45
+ }
46
+
47
+ function copyRecursive(src: string, dest: string, manifest: WarmupManifest): void {
48
+ const stat = fs.statSync(src);
49
+ if (stat.isDirectory()) {
50
+ fs.mkdirSync(dest, { recursive: true });
51
+ for (const entry of fs.readdirSync(src)) {
52
+ if (CHROME_LOCK_ARTIFACT_SET.has(entry)) {
53
+ if (!manifest.excludedLocks.includes(entry)) manifest.excludedLocks.push(entry);
54
+ continue;
55
+ }
56
+ copyRecursive(path.join(src, entry), path.join(dest, entry), manifest);
57
+ }
58
+ } else {
59
+ fs.mkdirSync(path.dirname(dest), { recursive: true });
60
+ fs.copyFileSync(src, dest);
61
+ }
62
+ }
63
+
64
+ /**
65
+ * Copy warm-up artifacts from `sourceProfileDir` into an isolated `destDir`.
66
+ *
67
+ * Guarantees:
68
+ * - The source profile is only ever read, never written or locked.
69
+ * - Chromium lock artifacts are never copied (recorded in `excludedLocks`).
70
+ * - Missing artifacts are skipped, not fatal (recorded in `skippedMissing`).
71
+ */
72
+ export function collectWarmupArtifacts(sourceProfileDir: string, destDir: string): WarmupManifest {
73
+ const manifest: WarmupManifest = {
74
+ sourceProfileDir,
75
+ destDir,
76
+ copied: [],
77
+ skippedMissing: [],
78
+ excludedLocks: [],
79
+ };
80
+
81
+ if (!fs.existsSync(sourceProfileDir)) {
82
+ throw new Error(`source profile directory does not exist: ${sourceProfileDir}`);
83
+ }
84
+ const resolvedSource = path.resolve(sourceProfileDir);
85
+ const resolvedDest = path.resolve(destDir);
86
+ if (resolvedDest === resolvedSource || resolvedDest.startsWith(`${resolvedSource}${path.sep}`)) {
87
+ throw new Error("warm-up destination must be outside the source profile directory");
88
+ }
89
+ fs.mkdirSync(destDir, { recursive: true });
90
+
91
+ // Record (but never copy) any lock artifacts present in the source.
92
+ for (const lock of CHROME_LOCK_ARTIFACTS) {
93
+ if (fs.existsSync(path.join(sourceProfileDir, lock))) {
94
+ manifest.excludedLocks.push(lock);
95
+ }
96
+ }
97
+
98
+ for (const artifact of WARMUP_ARTIFACTS) {
99
+ const src = path.join(sourceProfileDir, artifact);
100
+ if (!fs.existsSync(src)) {
101
+ manifest.skippedMissing.push(artifact);
102
+ continue;
103
+ }
104
+ copyRecursive(src, path.join(destDir, artifact), manifest);
105
+ manifest.copied.push(artifact);
106
+ }
107
+
108
+ return manifest;
109
+ }