pi-oxidized 0.1.1

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 (1517) hide show
  1. package/.agent-tasks/pi-rust-rewrite/Cargo.lock +5022 -0
  2. package/.agent-tasks/pi-rust-rewrite/Cargo.toml +22 -0
  3. package/.agent-tasks/pi-rust-rewrite/GOALS.md +1 -0
  4. package/.agent-tasks/pi-rust-rewrite/fixtures/phase7/goldens/branch_summary.json +8 -0
  5. package/.agent-tasks/pi-rust-rewrite/fixtures/phase7/goldens/changelog.md +16 -0
  6. package/.agent-tasks/pi-rust-rewrite/fixtures/phase7/goldens/debug_dump.txt +11 -0
  7. package/.agent-tasks/pi-rust-rewrite/fixtures/phase7/goldens/events.jsonl +6 -0
  8. package/.agent-tasks/pi-rust-rewrite/fixtures/phase7/goldens/legacy_auth_migration.json +16 -0
  9. package/.agent-tasks/pi-rust-rewrite/fixtures/phase7/goldens/selector_snapshot.txt +9 -0
  10. package/.agent-tasks/pi-rust-rewrite/fixtures/phase7/goldens/session_stats.json +16 -0
  11. package/.agent-tasks/pi-rust-rewrite/fixtures/phase7/goldens/share_result.json +7 -0
  12. package/.agent-tasks/pi-rust-rewrite/fixtures/phase7/sessions/export-roundtrip.jsonl +6 -0
  13. package/.agent-tasks/pi-rust-rewrite/fixtures/provider-drain/isolation-expectations.json +21 -0
  14. package/.agent-tasks/pi-rust-rewrite/fixtures/rpc/commands.json +238 -0
  15. package/.agent-tasks/pi-rust-rewrite/fixtures/rpc/host-state.json +128 -0
  16. package/.agent-tasks/pi-rust-rewrite/fixtures/rpc/ts-goldens.json +1 -0
  17. package/.agent-tasks/pi-rust-rewrite/fixtures/rpc/ts-replay.ts +317 -0
  18. package/.agent-tasks/pi-rust-rewrite/fixtures/sessions/v1/linear-with-compaction.expected.json +576 -0
  19. package/.agent-tasks/pi-rust-rewrite/fixtures/sessions/v1/linear-with-compaction.jsonl +12 -0
  20. package/.agent-tasks/pi-rust-rewrite/fixtures/sessions/v2/branched.expected.json +387 -0
  21. package/.agent-tasks/pi-rust-rewrite/fixtures/sessions/v2/branched.jsonl +8 -0
  22. package/.agent-tasks/pi-rust-rewrite/fixtures/sessions/v3/basic.expected.json +256 -0
  23. package/.agent-tasks/pi-rust-rewrite/fixtures/sessions/v3/basic.jsonl +5 -0
  24. package/.agent-tasks/pi-rust-rewrite/fixtures/sessions/v3/branched-labels.expected.json +474 -0
  25. package/.agent-tasks/pi-rust-rewrite/fixtures/sessions/v3/branched-labels.jsonl +13 -0
  26. package/.agent-tasks/pi-rust-rewrite/fixtures/sessions/v3/branched-session.expected.json +352 -0
  27. package/.agent-tasks/pi-rust-rewrite/fixtures/sessions/v3/branched-session.jsonl +9 -0
  28. package/.agent-tasks/pi-rust-rewrite/fixtures/sessions/v3/compacted-twice.expected.json +590 -0
  29. package/.agent-tasks/pi-rust-rewrite/fixtures/sessions/v3/compacted-twice.jsonl +13 -0
  30. package/.agent-tasks/pi-rust-rewrite/fixtures/sessions/v3/custom-messages.expected.json +400 -0
  31. package/.agent-tasks/pi-rust-rewrite/fixtures/sessions/v3/custom-messages.jsonl +8 -0
  32. package/.agent-tasks/pi-rust-rewrite/fixtures/sessions/v3/forked-header.expected.json +257 -0
  33. package/.agent-tasks/pi-rust-rewrite/fixtures/sessions/v3/forked-header.jsonl +5 -0
  34. package/.agent-tasks/pi-rust-rewrite/fixtures/sessions/v3/unknown-entries.expected.json +297 -0
  35. package/.agent-tasks/pi-rust-rewrite/fixtures/sessions/v3/unknown-entries.jsonl +6 -0
  36. package/.agent-tasks/pi-rust-rewrite/fixtures/tool-schemas/bash.json +16 -0
  37. package/.agent-tasks/pi-rust-rewrite/fixtures/tool-schemas/edit.json +34 -0
  38. package/.agent-tasks/pi-rust-rewrite/fixtures/tool-schemas/find.json +20 -0
  39. package/.agent-tasks/pi-rust-rewrite/fixtures/tool-schemas/grep.json +36 -0
  40. package/.agent-tasks/pi-rust-rewrite/fixtures/tool-schemas/ls.json +13 -0
  41. package/.agent-tasks/pi-rust-rewrite/fixtures/tool-schemas/read.json +20 -0
  42. package/.agent-tasks/pi-rust-rewrite/fixtures/tool-schemas/write.json +17 -0
  43. package/.agent-tasks/pi-rust-rewrite/fixtures/tools/edit-cases.json +93 -0
  44. package/.agent-tasks/pi-rust-rewrite/helpers/reopen_session.ts +168 -0
  45. package/.agent-tasks/pi-rust-rewrite/src/lib.rs +13 -0
  46. package/.agent-tasks/pi-rust-rewrite/tests/phase7_fixtures.rs +742 -0
  47. package/.agent-tasks/pi-rust-rewrite/tests/pi_ai_contract.rs +101 -0
  48. package/.agent-tasks/pi-rust-rewrite/tests/provider_drain_isolation.rs +760 -0
  49. package/.agent-tasks/pi-rust-rewrite/tests/rpc_parity.rs +679 -0
  50. package/.agent-tasks/pi-rust-rewrite/tests/session_compat.rs +839 -0
  51. package/.agent-tasks/pi-rust-rewrite/tests/tool_parity.rs +761 -0
  52. package/.github/workflows/release-verification.yml +204 -0
  53. package/.gitmodules +5 -0
  54. package/.outline/audit/coverage.json +3262 -0
  55. package/.outline/audit/queue.json +4841 -0
  56. package/.outline/review-fix-grill/iterations/1.json +767 -0
  57. package/.outline/review-fix-grill/iterations/2.json +69 -0
  58. package/.outline/review-fix-grill/iterations/3.json +81 -0
  59. package/.outline/review-fix-grill/iterations/4.json +35 -0
  60. package/.outline/review-fix-grill/iterations/5.json +21 -0
  61. package/.outline/review-fix-grill/queue.json +6454 -0
  62. package/.references/pi/.gitattributes +23 -0
  63. package/.references/pi/.github/APPROVED_CONTRIBUTORS +281 -0
  64. package/.references/pi/.github/ISSUE_TEMPLATE/bug.yml +45 -0
  65. package/.references/pi/.github/ISSUE_TEMPLATE/config.yml +5 -0
  66. package/.references/pi/.github/ISSUE_TEMPLATE/contribution.yml +36 -0
  67. package/.references/pi/.github/ISSUE_TEMPLATE/package-report.yml +49 -0
  68. package/.references/pi/.github/workflows/approve-contributor.yml +179 -0
  69. package/.references/pi/.github/workflows/build-binaries.yml +294 -0
  70. package/.references/pi/.github/workflows/ci.yml +42 -0
  71. package/.references/pi/.github/workflows/issue-analysis.yml +634 -0
  72. package/.references/pi/.github/workflows/issue-gate.yml +129 -0
  73. package/.references/pi/.github/workflows/issue-triage-labels.yml +142 -0
  74. package/.references/pi/.github/workflows/npm-audit.yml +31 -0
  75. package/.references/pi/.github/workflows/pr-gate.yml +128 -0
  76. package/.references/pi/.github/workflows/publish-model-catalog.yml +112 -0
  77. package/.references/pi/.github/workflows/remove-inprogress-on-close.yml +31 -0
  78. package/.references/pi/.husky/pre-commit +45 -0
  79. package/.references/pi/.pi/extensions/import-repro.ts +351 -0
  80. package/.references/pi/.pi/extensions/prompt-url-widget.ts +270 -0
  81. package/.references/pi/.pi/extensions/redraws.ts +24 -0
  82. package/.references/pi/.pi/extensions/tps.ts +47 -0
  83. package/.references/pi/.pi/git/.gitignore +2 -0
  84. package/.references/pi/.pi/npm/.gitignore +2 -0
  85. package/.references/pi/.pi/prompts/cl.md +54 -0
  86. package/.references/pi/.pi/prompts/is.md +28 -0
  87. package/.references/pi/.pi/prompts/pr.md +37 -0
  88. package/.references/pi/.pi/prompts/sa.md +163 -0
  89. package/.references/pi/.pi/prompts/wr.md +40 -0
  90. package/.references/pi/.pi/skills/add-llm-provider.md +57 -0
  91. package/.references/pi/AGENTS.md +162 -0
  92. package/.references/pi/CONTRIBUTING.md +102 -0
  93. package/.references/pi/LICENSE +21 -0
  94. package/.references/pi/README.md +99 -0
  95. package/.references/pi/SECURITY.md +87 -0
  96. package/.references/pi/biome.json +39 -0
  97. package/.references/pi/bun.lock +961 -0
  98. package/.references/pi/package-lock.json +6172 -0
  99. package/.references/pi/package.json +66 -0
  100. package/.references/pi/packages/agent/CHANGELOG.md +594 -0
  101. package/.references/pi/packages/agent/README.md +488 -0
  102. package/.references/pi/packages/agent/docs/agent-harness.md +488 -0
  103. package/.references/pi/packages/agent/docs/durable-harness.md +212 -0
  104. package/.references/pi/packages/agent/docs/hooks.md +445 -0
  105. package/.references/pi/packages/agent/docs/models.md +964 -0
  106. package/.references/pi/packages/agent/docs/observability.md +376 -0
  107. package/.references/pi/packages/agent/package.json +60 -0
  108. package/.references/pi/packages/agent/src/agent-loop.ts +792 -0
  109. package/.references/pi/packages/agent/src/agent.ts +575 -0
  110. package/.references/pi/packages/agent/src/harness/agent-harness.ts +1029 -0
  111. package/.references/pi/packages/agent/src/harness/compaction/branch-summarization.ts +261 -0
  112. package/.references/pi/packages/agent/src/harness/compaction/compaction.ts +753 -0
  113. package/.references/pi/packages/agent/src/harness/compaction/utils.ts +144 -0
  114. package/.references/pi/packages/agent/src/harness/env/nodejs.ts +569 -0
  115. package/.references/pi/packages/agent/src/harness/messages.ts +164 -0
  116. package/.references/pi/packages/agent/src/harness/prompt-templates.ts +267 -0
  117. package/.references/pi/packages/agent/src/harness/session/jsonl-repo.ts +179 -0
  118. package/.references/pi/packages/agent/src/harness/session/jsonl-storage.ts +314 -0
  119. package/.references/pi/packages/agent/src/harness/session/memory-repo.ts +50 -0
  120. package/.references/pi/packages/agent/src/harness/session/memory-storage.ts +133 -0
  121. package/.references/pi/packages/agent/src/harness/session/repo-utils.ts +51 -0
  122. package/.references/pi/packages/agent/src/harness/session/session.ts +338 -0
  123. package/.references/pi/packages/agent/src/harness/session/uuid.ts +54 -0
  124. package/.references/pi/packages/agent/src/harness/skills.ts +375 -0
  125. package/.references/pi/packages/agent/src/harness/system-prompt.ts +34 -0
  126. package/.references/pi/packages/agent/src/harness/types.ts +838 -0
  127. package/.references/pi/packages/agent/src/harness/utils/shell-output.ts +135 -0
  128. package/.references/pi/packages/agent/src/harness/utils/truncate.ts +344 -0
  129. package/.references/pi/packages/agent/src/index.ts +46 -0
  130. package/.references/pi/packages/agent/src/node.ts +2 -0
  131. package/.references/pi/packages/agent/src/proxy.ts +367 -0
  132. package/.references/pi/packages/agent/src/types.ts +430 -0
  133. package/.references/pi/packages/agent/test/agent-loop.test.ts +1424 -0
  134. package/.references/pi/packages/agent/test/agent.test.ts +699 -0
  135. package/.references/pi/packages/agent/test/e2e.test.ts +404 -0
  136. package/.references/pi/packages/agent/test/harness/agent-harness-stream.test.ts +213 -0
  137. package/.references/pi/packages/agent/test/harness/agent-harness.test.ts +608 -0
  138. package/.references/pi/packages/agent/test/harness/compaction.test.ts +655 -0
  139. package/.references/pi/packages/agent/test/harness/nodejs-env.test.ts +321 -0
  140. package/.references/pi/packages/agent/test/harness/prompt-templates.test.ts +90 -0
  141. package/.references/pi/packages/agent/test/harness/repo.test.ts +92 -0
  142. package/.references/pi/packages/agent/test/harness/resource-formatting.test.ts +24 -0
  143. package/.references/pi/packages/agent/test/harness/session-test-utils.ts +55 -0
  144. package/.references/pi/packages/agent/test/harness/session-uuid.test.ts +50 -0
  145. package/.references/pi/packages/agent/test/harness/session.test.ts +203 -0
  146. package/.references/pi/packages/agent/test/harness/skills.test.ts +116 -0
  147. package/.references/pi/packages/agent/test/harness/storage.test.ts +341 -0
  148. package/.references/pi/packages/agent/test/harness/system-prompt.test.ts +66 -0
  149. package/.references/pi/packages/agent/test/harness/truncate.test.ts +169 -0
  150. package/.references/pi/packages/agent/test/scratch/simple.ts +72 -0
  151. package/.references/pi/packages/agent/test/utils/calculate.ts +32 -0
  152. package/.references/pi/packages/agent/test/utils/get-current-time.ts +46 -0
  153. package/.references/pi/packages/agent/tsconfig.build.json +13 -0
  154. package/.references/pi/packages/agent/vitest.config.ts +21 -0
  155. package/.references/pi/packages/agent/vitest.harness.config.ts +28 -0
  156. package/.references/pi/packages/ai/CHANGELOG.md +1739 -0
  157. package/.references/pi/packages/ai/README.md +1621 -0
  158. package/.references/pi/packages/ai/bedrock-provider.d.ts +1 -0
  159. package/.references/pi/packages/ai/bedrock-provider.js +1 -0
  160. package/.references/pi/packages/ai/package.json +97 -0
  161. package/.references/pi/packages/ai/scripts/generate-image-models.ts +131 -0
  162. package/.references/pi/packages/ai/scripts/generate-models.ts +2401 -0
  163. package/.references/pi/packages/ai/scripts/generate-test-image.ts +33 -0
  164. package/.references/pi/packages/ai/src/api/anthropic-messages.lazy.ts +4 -0
  165. package/.references/pi/packages/ai/src/api/anthropic-messages.ts +1313 -0
  166. package/.references/pi/packages/ai/src/api/azure-openai-responses.lazy.ts +4 -0
  167. package/.references/pi/packages/ai/src/api/azure-openai-responses.ts +298 -0
  168. package/.references/pi/packages/ai/src/api/bedrock-converse-stream.lazy.ts +30 -0
  169. package/.references/pi/packages/ai/src/api/bedrock-converse-stream.ts +1091 -0
  170. package/.references/pi/packages/ai/src/api/cloudflare.ts +15 -0
  171. package/.references/pi/packages/ai/src/api/github-copilot-headers.ts +37 -0
  172. package/.references/pi/packages/ai/src/api/google-generative-ai.lazy.ts +4 -0
  173. package/.references/pi/packages/ai/src/api/google-generative-ai.ts +509 -0
  174. package/.references/pi/packages/ai/src/api/google-shared.ts +350 -0
  175. package/.references/pi/packages/ai/src/api/google-vertex.lazy.ts +4 -0
  176. package/.references/pi/packages/ai/src/api/google-vertex.ts +584 -0
  177. package/.references/pi/packages/ai/src/api/lazy.ts +75 -0
  178. package/.references/pi/packages/ai/src/api/mistral-conversations.lazy.ts +4 -0
  179. package/.references/pi/packages/ai/src/api/mistral-conversations.ts +664 -0
  180. package/.references/pi/packages/ai/src/api/openai-codex-responses.lazy.ts +4 -0
  181. package/.references/pi/packages/ai/src/api/openai-codex-responses.ts +1573 -0
  182. package/.references/pi/packages/ai/src/api/openai-completions.lazy.ts +4 -0
  183. package/.references/pi/packages/ai/src/api/openai-completions.ts +1355 -0
  184. package/.references/pi/packages/ai/src/api/openai-prompt-cache.ts +8 -0
  185. package/.references/pi/packages/ai/src/api/openai-responses-shared.ts +613 -0
  186. package/.references/pi/packages/ai/src/api/openai-responses.lazy.ts +4 -0
  187. package/.references/pi/packages/ai/src/api/openai-responses.ts +318 -0
  188. package/.references/pi/packages/ai/src/api/openrouter-images.lazy.ts +10 -0
  189. package/.references/pi/packages/ai/src/api/openrouter-images.ts +185 -0
  190. package/.references/pi/packages/ai/src/api/pi-messages.lazy.ts +4 -0
  191. package/.references/pi/packages/ai/src/api/pi-messages.ts +436 -0
  192. package/.references/pi/packages/ai/src/api/simple-options.ts +77 -0
  193. package/.references/pi/packages/ai/src/api/transform-messages.ts +223 -0
  194. package/.references/pi/packages/ai/src/auth/context.ts +45 -0
  195. package/.references/pi/packages/ai/src/auth/credential-store.ts +51 -0
  196. package/.references/pi/packages/ai/src/auth/helpers.ts +47 -0
  197. package/.references/pi/packages/ai/src/auth/oauth/anthropic.ts +350 -0
  198. package/.references/pi/packages/ai/src/auth/oauth/device-code.ts +98 -0
  199. package/.references/pi/packages/ai/src/auth/oauth/github-copilot.ts +379 -0
  200. package/.references/pi/packages/ai/src/auth/oauth/load.ts +56 -0
  201. package/.references/pi/packages/ai/src/auth/oauth/oauth-page.ts +109 -0
  202. package/.references/pi/packages/ai/src/auth/oauth/openai-codex.ts +538 -0
  203. package/.references/pi/packages/ai/src/auth/oauth/pkce.ts +34 -0
  204. package/.references/pi/packages/ai/src/auth/oauth/radius.ts +410 -0
  205. package/.references/pi/packages/ai/src/auth/oauth/xai.ts +238 -0
  206. package/.references/pi/packages/ai/src/auth/resolve.ts +139 -0
  207. package/.references/pi/packages/ai/src/auth/types.ts +220 -0
  208. package/.references/pi/packages/ai/src/bedrock-provider.ts +6 -0
  209. package/.references/pi/packages/ai/src/bun-oauth.ts +17 -0
  210. package/.references/pi/packages/ai/src/cli.ts +118 -0
  211. package/.references/pi/packages/ai/src/compat/extension-oauth-types.ts +45 -0
  212. package/.references/pi/packages/ai/src/compat.ts +298 -0
  213. package/.references/pi/packages/ai/src/env-api-keys.ts +178 -0
  214. package/.references/pi/packages/ai/src/image-models.generated.ts +534 -0
  215. package/.references/pi/packages/ai/src/image-models.ts +42 -0
  216. package/.references/pi/packages/ai/src/images-api-registry.ts +53 -0
  217. package/.references/pi/packages/ai/src/images-models.ts +274 -0
  218. package/.references/pi/packages/ai/src/images.ts +21 -0
  219. package/.references/pi/packages/ai/src/index.ts +45 -0
  220. package/.references/pi/packages/ai/src/legacy-api-aliases.ts +108 -0
  221. package/.references/pi/packages/ai/src/models-store.ts +38 -0
  222. package/.references/pi/packages/ai/src/models.generated.ts +76 -0
  223. package/.references/pi/packages/ai/src/models.ts +705 -0
  224. package/.references/pi/packages/ai/src/oauth.ts +10 -0
  225. package/.references/pi/packages/ai/src/providers/all.ts +140 -0
  226. package/.references/pi/packages/ai/src/providers/amazon-bedrock.models.ts +1897 -0
  227. package/.references/pi/packages/ai/src/providers/amazon-bedrock.ts +80 -0
  228. package/.references/pi/packages/ai/src/providers/ant-ling.models.ts +62 -0
  229. package/.references/pi/packages/ai/src/providers/ant-ling.ts +15 -0
  230. package/.references/pi/packages/ai/src/providers/anthropic.models.ts +257 -0
  231. package/.references/pi/packages/ai/src/providers/anthropic.ts +20 -0
  232. package/.references/pi/packages/ai/src/providers/azure-openai-responses.models.ts +816 -0
  233. package/.references/pi/packages/ai/src/providers/azure-openai-responses.ts +14 -0
  234. package/.references/pi/packages/ai/src/providers/cerebras.models.ts +61 -0
  235. package/.references/pi/packages/ai/src/providers/cerebras.ts +15 -0
  236. package/.references/pi/packages/ai/src/providers/cloudflare-ai-gateway.models.ts +760 -0
  237. package/.references/pi/packages/ai/src/providers/cloudflare-ai-gateway.ts +23 -0
  238. package/.references/pi/packages/ai/src/providers/cloudflare-auth.ts +96 -0
  239. package/.references/pi/packages/ai/src/providers/cloudflare-stream.ts +28 -0
  240. package/.references/pi/packages/ai/src/providers/cloudflare-workers-ai.models.ts +241 -0
  241. package/.references/pi/packages/ai/src/providers/cloudflare-workers-ai.ts +15 -0
  242. package/.references/pi/packages/ai/src/providers/deepseek.models.ts +45 -0
  243. package/.references/pi/packages/ai/src/providers/deepseek.ts +15 -0
  244. package/.references/pi/packages/ai/src/providers/faux.ts +538 -0
  245. package/.references/pi/packages/ai/src/providers/fireworks.models.ts +297 -0
  246. package/.references/pi/packages/ai/src/providers/fireworks.ts +19 -0
  247. package/.references/pi/packages/ai/src/providers/github-copilot.models.ts +543 -0
  248. package/.references/pi/packages/ai/src/providers/github-copilot.ts +34 -0
  249. package/.references/pi/packages/ai/src/providers/google-vertex.models.ts +184 -0
  250. package/.references/pi/packages/ai/src/providers/google-vertex.ts +93 -0
  251. package/.references/pi/packages/ai/src/providers/google.models.ts +290 -0
  252. package/.references/pi/packages/ai/src/providers/google.ts +15 -0
  253. package/.references/pi/packages/ai/src/providers/groq.models.ts +127 -0
  254. package/.references/pi/packages/ai/src/providers/groq.ts +15 -0
  255. package/.references/pi/packages/ai/src/providers/huggingface.models.ts +889 -0
  256. package/.references/pi/packages/ai/src/providers/huggingface.ts +15 -0
  257. package/.references/pi/packages/ai/src/providers/images/register-builtins.ts +50 -0
  258. package/.references/pi/packages/ai/src/providers/kimi-coding.models.ts +103 -0
  259. package/.references/pi/packages/ai/src/providers/kimi-coding.ts +15 -0
  260. package/.references/pi/packages/ai/src/providers/minimax-cn.models.ts +58 -0
  261. package/.references/pi/packages/ai/src/providers/minimax-cn.ts +15 -0
  262. package/.references/pi/packages/ai/src/providers/minimax.models.ts +58 -0
  263. package/.references/pi/packages/ai/src/providers/minimax.ts +15 -0
  264. package/.references/pi/packages/ai/src/providers/mistral.models.ts +517 -0
  265. package/.references/pi/packages/ai/src/providers/mistral.ts +15 -0
  266. package/.references/pi/packages/ai/src/providers/moonshotai-cn.models.ts +190 -0
  267. package/.references/pi/packages/ai/src/providers/moonshotai-cn.ts +15 -0
  268. package/.references/pi/packages/ai/src/providers/moonshotai.models.ts +190 -0
  269. package/.references/pi/packages/ai/src/providers/moonshotai.ts +15 -0
  270. package/.references/pi/packages/ai/src/providers/nvidia.models.ts +387 -0
  271. package/.references/pi/packages/ai/src/providers/nvidia.ts +15 -0
  272. package/.references/pi/packages/ai/src/providers/openai-codex.models.ts +144 -0
  273. package/.references/pi/packages/ai/src/providers/openai-codex.ts +18 -0
  274. package/.references/pi/packages/ai/src/providers/openai.models.ts +830 -0
  275. package/.references/pi/packages/ai/src/providers/openai.ts +15 -0
  276. package/.references/pi/packages/ai/src/providers/opencode-go.models.ts +278 -0
  277. package/.references/pi/packages/ai/src/providers/opencode-go.ts +18 -0
  278. package/.references/pi/packages/ai/src/providers/opencode.models.ts +1001 -0
  279. package/.references/pi/packages/ai/src/providers/opencode.ts +24 -0
  280. package/.references/pi/packages/ai/src/providers/openrouter-images.ts +14 -0
  281. package/.references/pi/packages/ai/src/providers/openrouter.models.ts +4915 -0
  282. package/.references/pi/packages/ai/src/providers/openrouter.ts +15 -0
  283. package/.references/pi/packages/ai/src/providers/radius-config.ts +95 -0
  284. package/.references/pi/packages/ai/src/providers/radius.ts +67 -0
  285. package/.references/pi/packages/ai/src/providers/together.models.ts +382 -0
  286. package/.references/pi/packages/ai/src/providers/together.ts +15 -0
  287. package/.references/pi/packages/ai/src/providers/vercel-ai-gateway.models.ts +3268 -0
  288. package/.references/pi/packages/ai/src/providers/vercel-ai-gateway.ts +15 -0
  289. package/.references/pi/packages/ai/src/providers/xai.models.ts +62 -0
  290. package/.references/pi/packages/ai/src/providers/xai.ts +27 -0
  291. package/.references/pi/packages/ai/src/providers/xiaomi-token-plan-ams.models.ts +61 -0
  292. package/.references/pi/packages/ai/src/providers/xiaomi-token-plan-ams.ts +15 -0
  293. package/.references/pi/packages/ai/src/providers/xiaomi-token-plan-cn.models.ts +61 -0
  294. package/.references/pi/packages/ai/src/providers/xiaomi-token-plan-cn.ts +15 -0
  295. package/.references/pi/packages/ai/src/providers/xiaomi-token-plan-sgp.models.ts +61 -0
  296. package/.references/pi/packages/ai/src/providers/xiaomi-token-plan-sgp.ts +15 -0
  297. package/.references/pi/packages/ai/src/providers/xiaomi.models.ts +115 -0
  298. package/.references/pi/packages/ai/src/providers/xiaomi.ts +15 -0
  299. package/.references/pi/packages/ai/src/providers/zai-coding-cn.models.ts +116 -0
  300. package/.references/pi/packages/ai/src/providers/zai-coding-cn.ts +15 -0
  301. package/.references/pi/packages/ai/src/providers/zai.models.ts +116 -0
  302. package/.references/pi/packages/ai/src/providers/zai.ts +15 -0
  303. package/.references/pi/packages/ai/src/session-resources.ts +24 -0
  304. package/.references/pi/packages/ai/src/types.ts +738 -0
  305. package/.references/pi/packages/ai/src/utils/abort-signals.ts +41 -0
  306. package/.references/pi/packages/ai/src/utils/deferred-tools.ts +39 -0
  307. package/.references/pi/packages/ai/src/utils/diagnostics.ts +45 -0
  308. package/.references/pi/packages/ai/src/utils/error-body.ts +127 -0
  309. package/.references/pi/packages/ai/src/utils/estimate.ts +143 -0
  310. package/.references/pi/packages/ai/src/utils/event-stream.ts +88 -0
  311. package/.references/pi/packages/ai/src/utils/hash.ts +13 -0
  312. package/.references/pi/packages/ai/src/utils/headers.ts +18 -0
  313. package/.references/pi/packages/ai/src/utils/json-parse.ts +124 -0
  314. package/.references/pi/packages/ai/src/utils/node-http-proxy.ts +112 -0
  315. package/.references/pi/packages/ai/src/utils/overflow.ts +165 -0
  316. package/.references/pi/packages/ai/src/utils/provider-env.ts +52 -0
  317. package/.references/pi/packages/ai/src/utils/retry.ts +101 -0
  318. package/.references/pi/packages/ai/src/utils/sanitize-unicode.ts +25 -0
  319. package/.references/pi/packages/ai/src/utils/typebox-helpers.ts +24 -0
  320. package/.references/pi/packages/ai/src/utils/validation.ts +310 -0
  321. package/.references/pi/packages/ai/test/abort.test.ts +303 -0
  322. package/.references/pi/packages/ai/test/anthropic-adaptive-thinking-models.test.ts +39 -0
  323. package/.references/pi/packages/ai/test/anthropic-cache-write-1h-cost.test.ts +86 -0
  324. package/.references/pi/packages/ai/test/anthropic-eager-tool-input-compat.test.ts +122 -0
  325. package/.references/pi/packages/ai/test/anthropic-eager-tool-input-e2e.test.ts +155 -0
  326. package/.references/pi/packages/ai/test/anthropic-empty-thinking-signature-compat.test.ts +108 -0
  327. package/.references/pi/packages/ai/test/anthropic-force-adaptive-thinking.test.ts +125 -0
  328. package/.references/pi/packages/ai/test/anthropic-long-cache-retention-e2e.test.ts +127 -0
  329. package/.references/pi/packages/ai/test/anthropic-oauth.test.ts +137 -0
  330. package/.references/pi/packages/ai/test/anthropic-opus-4-8-smoke.test.ts +71 -0
  331. package/.references/pi/packages/ai/test/anthropic-sse-parsing.test.ts +275 -0
  332. package/.references/pi/packages/ai/test/anthropic-temperature-compat.test.ts +103 -0
  333. package/.references/pi/packages/ai/test/anthropic-thinking-disable.test.ts +172 -0
  334. package/.references/pi/packages/ai/test/anthropic-tool-name-normalization.test.ts +204 -0
  335. package/.references/pi/packages/ai/test/azure-openai-base-url.test.ts +175 -0
  336. package/.references/pi/packages/ai/test/azure-openai-responses-reasoning-replay.test.ts +136 -0
  337. package/.references/pi/packages/ai/test/azure-utils.ts +28 -0
  338. package/.references/pi/packages/ai/test/bedrock-convert-messages.test.ts +245 -0
  339. package/.references/pi/packages/ai/test/bedrock-custom-headers.test.ts +202 -0
  340. package/.references/pi/packages/ai/test/bedrock-endpoint-resolution.test.ts +208 -0
  341. package/.references/pi/packages/ai/test/bedrock-models.test.ts +65 -0
  342. package/.references/pi/packages/ai/test/bedrock-thinking-payload.test.ts +246 -0
  343. package/.references/pi/packages/ai/test/bedrock-utils.ts +18 -0
  344. package/.references/pi/packages/ai/test/cache-retention.test.ts +498 -0
  345. package/.references/pi/packages/ai/test/cloudflare-stream.test.ts +65 -0
  346. package/.references/pi/packages/ai/test/cloudflare-utils.ts +9 -0
  347. package/.references/pi/packages/ai/test/codex-websocket-cached-probe.ts +299 -0
  348. package/.references/pi/packages/ai/test/compat-env.test.ts +74 -0
  349. package/.references/pi/packages/ai/test/context-estimate.test.ts +81 -0
  350. package/.references/pi/packages/ai/test/context-overflow.test.ts +734 -0
  351. package/.references/pi/packages/ai/test/cross-provider-handoff.test.ts +502 -0
  352. package/.references/pi/packages/ai/test/data/red-circle.png +0 -0
  353. package/.references/pi/packages/ai/test/deferred-tools.test.ts +481 -0
  354. package/.references/pi/packages/ai/test/empty.test.ts +741 -0
  355. package/.references/pi/packages/ai/test/env-api-keys.test.ts +60 -0
  356. package/.references/pi/packages/ai/test/error-body.test.ts +154 -0
  357. package/.references/pi/packages/ai/test/faux-provider.test.ts +597 -0
  358. package/.references/pi/packages/ai/test/fireworks-models.test.ts +269 -0
  359. package/.references/pi/packages/ai/test/github-copilot-anthropic.test.ts +120 -0
  360. package/.references/pi/packages/ai/test/github-copilot-oauth.test.ts +444 -0
  361. package/.references/pi/packages/ai/test/google-shared-convert-tools.test.ts +187 -0
  362. package/.references/pi/packages/ai/test/google-shared-gemini3-unsigned-tool-call.test.ts +116 -0
  363. package/.references/pi/packages/ai/test/google-shared-image-tool-result-routing.test.ts +102 -0
  364. package/.references/pi/packages/ai/test/google-thinking-disable.test.ts +160 -0
  365. package/.references/pi/packages/ai/test/google-thinking-signature.test.ts +38 -0
  366. package/.references/pi/packages/ai/test/google-vertex-api-key-resolution.test.ts +223 -0
  367. package/.references/pi/packages/ai/test/image-tool-result.test.ts +501 -0
  368. package/.references/pi/packages/ai/test/images-models.test.ts +209 -0
  369. package/.references/pi/packages/ai/test/images.test.ts +90 -0
  370. package/.references/pi/packages/ai/test/interleaved-thinking.test.ts +144 -0
  371. package/.references/pi/packages/ai/test/lax-message-content.test.ts +67 -0
  372. package/.references/pi/packages/ai/test/lazy-module-load.test.ts +119 -0
  373. package/.references/pi/packages/ai/test/max-thinking.test.ts +89 -0
  374. package/.references/pi/packages/ai/test/mistral-reasoning-mode.test.ts +97 -0
  375. package/.references/pi/packages/ai/test/mistral-tool-schema.test.ts +60 -0
  376. package/.references/pi/packages/ai/test/models-runtime.test.ts +689 -0
  377. package/.references/pi/packages/ai/test/node-http-proxy.test.ts +76 -0
  378. package/.references/pi/packages/ai/test/oauth-auth.test.ts +141 -0
  379. package/.references/pi/packages/ai/test/oauth-device-code.test.ts +139 -0
  380. package/.references/pi/packages/ai/test/oauth.ts +83 -0
  381. package/.references/pi/packages/ai/test/openai-codex-cache-affinity-e2e.test.ts +35 -0
  382. package/.references/pi/packages/ai/test/openai-codex-oauth.test.ts +479 -0
  383. package/.references/pi/packages/ai/test/openai-codex-stream.test.ts +2028 -0
  384. package/.references/pi/packages/ai/test/openai-completions-cache-control-format.test.ts +189 -0
  385. package/.references/pi/packages/ai/test/openai-completions-empty-tools.test.ts +304 -0
  386. package/.references/pi/packages/ai/test/openai-completions-prompt-cache.test.ts +264 -0
  387. package/.references/pi/packages/ai/test/openai-completions-reasoning-details.test.ts +118 -0
  388. package/.references/pi/packages/ai/test/openai-completions-response-model.test.ts +140 -0
  389. package/.references/pi/packages/ai/test/openai-completions-retry.test.ts +86 -0
  390. package/.references/pi/packages/ai/test/openai-completions-thinking-as-text.test.ts +218 -0
  391. package/.references/pi/packages/ai/test/openai-completions-tool-choice.test.ts +1716 -0
  392. package/.references/pi/packages/ai/test/openai-completions-tool-result-images.test.ts +152 -0
  393. package/.references/pi/packages/ai/test/openai-responses-cache-affinity-e2e.test.ts +31 -0
  394. package/.references/pi/packages/ai/test/openai-responses-compat.test.ts +472 -0
  395. package/.references/pi/packages/ai/test/openai-responses-empty-tool-result.test.ts +58 -0
  396. package/.references/pi/packages/ai/test/openai-responses-foreign-toolcall-id.test.ts +66 -0
  397. package/.references/pi/packages/ai/test/openai-responses-message-id.test.ts +48 -0
  398. package/.references/pi/packages/ai/test/openai-responses-partial-json-cleanup.test.ts +106 -0
  399. package/.references/pi/packages/ai/test/openai-responses-reasoning-replay-e2e.test.ts +291 -0
  400. package/.references/pi/packages/ai/test/openai-responses-terminal-event.test.ts +233 -0
  401. package/.references/pi/packages/ai/test/openai-responses-tool-result-images.test.ts +194 -0
  402. package/.references/pi/packages/ai/test/openrouter-cache-write-repro.test.ts +77 -0
  403. package/.references/pi/packages/ai/test/openrouter-images.test.ts +140 -0
  404. package/.references/pi/packages/ai/test/overflow.test.ts +139 -0
  405. package/.references/pi/packages/ai/test/pi-messages.test.ts +243 -0
  406. package/.references/pi/packages/ai/test/provider-error-body-passthrough.test.ts +78 -0
  407. package/.references/pi/packages/ai/test/provider-error-body-regression.test.ts +189 -0
  408. package/.references/pi/packages/ai/test/providers.test.ts +404 -0
  409. package/.references/pi/packages/ai/test/responseid.test.ts +120 -0
  410. package/.references/pi/packages/ai/test/retry.test.ts +59 -0
  411. package/.references/pi/packages/ai/test/scratch.ts +57 -0
  412. package/.references/pi/packages/ai/test/stream.test.ts +1632 -0
  413. package/.references/pi/packages/ai/test/supports-xhigh.test.ts +145 -0
  414. package/.references/pi/packages/ai/test/together-models.test.ts +78 -0
  415. package/.references/pi/packages/ai/test/tokens.test.ts +333 -0
  416. package/.references/pi/packages/ai/test/tool-call-id-normalization.test.ts +290 -0
  417. package/.references/pi/packages/ai/test/tool-call-without-result.test.ts +327 -0
  418. package/.references/pi/packages/ai/test/total-tokens.test.ts +789 -0
  419. package/.references/pi/packages/ai/test/transform-messages-copilot-openai-to-anthropic.test.ts +191 -0
  420. package/.references/pi/packages/ai/test/unicode-surrogate.test.ts +774 -0
  421. package/.references/pi/packages/ai/test/validation.test.ts +116 -0
  422. package/.references/pi/packages/ai/test/xai-oauth.test.ts +330 -0
  423. package/.references/pi/packages/ai/test/xai-responses.test.ts +117 -0
  424. package/.references/pi/packages/ai/test/xhigh.test.ts +70 -0
  425. package/.references/pi/packages/ai/test/xiaomi-models.test.ts +17 -0
  426. package/.references/pi/packages/ai/test/xiaomi-token-plan-ams-anthropic-empty-signature-smoke.test.ts +114 -0
  427. package/.references/pi/packages/ai/test/zen.test.ts +25 -0
  428. package/.references/pi/packages/ai/tsconfig.build.json +9 -0
  429. package/.references/pi/packages/ai/vitest.config.ts +11 -0
  430. package/.references/pi/packages/coding-agent/CHANGELOG.md +5038 -0
  431. package/.references/pi/packages/coding-agent/README.md +691 -0
  432. package/.references/pi/packages/coding-agent/docs/compaction.md +396 -0
  433. package/.references/pi/packages/coding-agent/docs/containerization.md +111 -0
  434. package/.references/pi/packages/coding-agent/docs/custom-provider.md +735 -0
  435. package/.references/pi/packages/coding-agent/docs/development.md +71 -0
  436. package/.references/pi/packages/coding-agent/docs/docs.json +156 -0
  437. package/.references/pi/packages/coding-agent/docs/extensions.md +2911 -0
  438. package/.references/pi/packages/coding-agent/docs/images/doom-extension.png +0 -0
  439. package/.references/pi/packages/coding-agent/docs/images/exy.png +0 -0
  440. package/.references/pi/packages/coding-agent/docs/images/interactive-mode.png +0 -0
  441. package/.references/pi/packages/coding-agent/docs/images/tree-view.png +0 -0
  442. package/.references/pi/packages/coding-agent/docs/index.md +82 -0
  443. package/.references/pi/packages/coding-agent/docs/json.md +82 -0
  444. package/.references/pi/packages/coding-agent/docs/keybindings.md +198 -0
  445. package/.references/pi/packages/coding-agent/docs/models.md +540 -0
  446. package/.references/pi/packages/coding-agent/docs/packages.md +228 -0
  447. package/.references/pi/packages/coding-agent/docs/prompt-templates.md +95 -0
  448. package/.references/pi/packages/coding-agent/docs/providers.md +290 -0
  449. package/.references/pi/packages/coding-agent/docs/quickstart.md +165 -0
  450. package/.references/pi/packages/coding-agent/docs/rpc.md +1480 -0
  451. package/.references/pi/packages/coding-agent/docs/sdk.md +1183 -0
  452. package/.references/pi/packages/coding-agent/docs/security.md +59 -0
  453. package/.references/pi/packages/coding-agent/docs/session-format.md +422 -0
  454. package/.references/pi/packages/coding-agent/docs/sessions.md +145 -0
  455. package/.references/pi/packages/coding-agent/docs/settings.md +319 -0
  456. package/.references/pi/packages/coding-agent/docs/shell-aliases.md +13 -0
  457. package/.references/pi/packages/coding-agent/docs/skills.md +231 -0
  458. package/.references/pi/packages/coding-agent/docs/terminal-setup.md +142 -0
  459. package/.references/pi/packages/coding-agent/docs/termux.md +127 -0
  460. package/.references/pi/packages/coding-agent/docs/themes.md +297 -0
  461. package/.references/pi/packages/coding-agent/docs/tmux.md +63 -0
  462. package/.references/pi/packages/coding-agent/docs/tui.md +927 -0
  463. package/.references/pi/packages/coding-agent/docs/usage.md +310 -0
  464. package/.references/pi/packages/coding-agent/docs/windows.md +17 -0
  465. package/.references/pi/packages/coding-agent/examples/README.md +25 -0
  466. package/.references/pi/packages/coding-agent/examples/extensions/README.md +213 -0
  467. package/.references/pi/packages/coding-agent/examples/extensions/auto-commit-on-exit.ts +49 -0
  468. package/.references/pi/packages/coding-agent/examples/extensions/bash-spawn-hook.ts +30 -0
  469. package/.references/pi/packages/coding-agent/examples/extensions/bookmark.ts +50 -0
  470. package/.references/pi/packages/coding-agent/examples/extensions/border-status-editor.ts +150 -0
  471. package/.references/pi/packages/coding-agent/examples/extensions/built-in-tool-renderer.ts +249 -0
  472. package/.references/pi/packages/coding-agent/examples/extensions/claude-rules.ts +86 -0
  473. package/.references/pi/packages/coding-agent/examples/extensions/commands.ts +72 -0
  474. package/.references/pi/packages/coding-agent/examples/extensions/confirm-destructive.ts +59 -0
  475. package/.references/pi/packages/coding-agent/examples/extensions/custom-compaction.ts +128 -0
  476. package/.references/pi/packages/coding-agent/examples/extensions/custom-footer.ts +64 -0
  477. package/.references/pi/packages/coding-agent/examples/extensions/custom-header.ts +73 -0
  478. package/.references/pi/packages/coding-agent/examples/extensions/custom-provider-anthropic/index.ts +604 -0
  479. package/.references/pi/packages/coding-agent/examples/extensions/custom-provider-anthropic/package-lock.json +24 -0
  480. package/.references/pi/packages/coding-agent/examples/extensions/custom-provider-anthropic/package.json +19 -0
  481. package/.references/pi/packages/coding-agent/examples/extensions/custom-provider-gitlab-duo/index.ts +404 -0
  482. package/.references/pi/packages/coding-agent/examples/extensions/custom-provider-gitlab-duo/package.json +16 -0
  483. package/.references/pi/packages/coding-agent/examples/extensions/custom-provider-gitlab-duo/test.ts +82 -0
  484. package/.references/pi/packages/coding-agent/examples/extensions/dirty-repo-guard.ts +56 -0
  485. package/.references/pi/packages/coding-agent/examples/extensions/doom-overlay/README.md +46 -0
  486. package/.references/pi/packages/coding-agent/examples/extensions/doom-overlay/doom/build/doom.js +21 -0
  487. package/.references/pi/packages/coding-agent/examples/extensions/doom-overlay/doom/build/doom.wasm +0 -0
  488. package/.references/pi/packages/coding-agent/examples/extensions/doom-overlay/doom/build.sh +152 -0
  489. package/.references/pi/packages/coding-agent/examples/extensions/doom-overlay/doom/doomgeneric_pi.c +72 -0
  490. package/.references/pi/packages/coding-agent/examples/extensions/doom-overlay/doom-component.ts +132 -0
  491. package/.references/pi/packages/coding-agent/examples/extensions/doom-overlay/doom-engine.ts +173 -0
  492. package/.references/pi/packages/coding-agent/examples/extensions/doom-overlay/doom-keys.ts +104 -0
  493. package/.references/pi/packages/coding-agent/examples/extensions/doom-overlay/index.ts +74 -0
  494. package/.references/pi/packages/coding-agent/examples/extensions/doom-overlay/wad-finder.ts +51 -0
  495. package/.references/pi/packages/coding-agent/examples/extensions/dynamic-resources/SKILL.md +8 -0
  496. package/.references/pi/packages/coding-agent/examples/extensions/dynamic-resources/dynamic.json +79 -0
  497. package/.references/pi/packages/coding-agent/examples/extensions/dynamic-resources/dynamic.md +5 -0
  498. package/.references/pi/packages/coding-agent/examples/extensions/dynamic-resources/index.ts +15 -0
  499. package/.references/pi/packages/coding-agent/examples/extensions/dynamic-tools.ts +74 -0
  500. package/.references/pi/packages/coding-agent/examples/extensions/entry-renderer.ts +41 -0
  501. package/.references/pi/packages/coding-agent/examples/extensions/event-bus.ts +43 -0
  502. package/.references/pi/packages/coding-agent/examples/extensions/file-trigger.ts +41 -0
  503. package/.references/pi/packages/coding-agent/examples/extensions/git-checkpoint.ts +53 -0
  504. package/.references/pi/packages/coding-agent/examples/extensions/git-merge-and-resolve.ts +115 -0
  505. package/.references/pi/packages/coding-agent/examples/extensions/github-issue-autocomplete.ts +185 -0
  506. package/.references/pi/packages/coding-agent/examples/extensions/gondolin/index.ts +531 -0
  507. package/.references/pi/packages/coding-agent/examples/extensions/gondolin/package-lock.json +185 -0
  508. package/.references/pi/packages/coding-agent/examples/extensions/gondolin/package.json +19 -0
  509. package/.references/pi/packages/coding-agent/examples/extensions/handoff.ts +191 -0
  510. package/.references/pi/packages/coding-agent/examples/extensions/hello.ts +26 -0
  511. package/.references/pi/packages/coding-agent/examples/extensions/hidden-thinking-label.ts +53 -0
  512. package/.references/pi/packages/coding-agent/examples/extensions/inline-bash.ts +94 -0
  513. package/.references/pi/packages/coding-agent/examples/extensions/input-transform-streaming.ts +39 -0
  514. package/.references/pi/packages/coding-agent/examples/extensions/input-transform.ts +43 -0
  515. package/.references/pi/packages/coding-agent/examples/extensions/interactive-shell.ts +196 -0
  516. package/.references/pi/packages/coding-agent/examples/extensions/kimi-deferred-tools.ts +61 -0
  517. package/.references/pi/packages/coding-agent/examples/extensions/mac-system-theme.ts +47 -0
  518. package/.references/pi/packages/coding-agent/examples/extensions/message-renderer.ts +59 -0
  519. package/.references/pi/packages/coding-agent/examples/extensions/minimal-mode.ts +426 -0
  520. package/.references/pi/packages/coding-agent/examples/extensions/modal-editor.ts +85 -0
  521. package/.references/pi/packages/coding-agent/examples/extensions/model-status.ts +31 -0
  522. package/.references/pi/packages/coding-agent/examples/extensions/notify.ts +55 -0
  523. package/.references/pi/packages/coding-agent/examples/extensions/overlay-qa-tests.ts +1450 -0
  524. package/.references/pi/packages/coding-agent/examples/extensions/overlay-test.ts +153 -0
  525. package/.references/pi/packages/coding-agent/examples/extensions/permission-gate.ts +34 -0
  526. package/.references/pi/packages/coding-agent/examples/extensions/pirate.ts +47 -0
  527. package/.references/pi/packages/coding-agent/examples/extensions/plan-mode/README.md +66 -0
  528. package/.references/pi/packages/coding-agent/examples/extensions/plan-mode/index.ts +390 -0
  529. package/.references/pi/packages/coding-agent/examples/extensions/plan-mode/utils.ts +168 -0
  530. package/.references/pi/packages/coding-agent/examples/extensions/preset.ts +436 -0
  531. package/.references/pi/packages/coding-agent/examples/extensions/project-trust.ts +64 -0
  532. package/.references/pi/packages/coding-agent/examples/extensions/prompt-customizer.ts +97 -0
  533. package/.references/pi/packages/coding-agent/examples/extensions/protected-paths.ts +30 -0
  534. package/.references/pi/packages/coding-agent/examples/extensions/provider-payload.ts +18 -0
  535. package/.references/pi/packages/coding-agent/examples/extensions/qna.ts +122 -0
  536. package/.references/pi/packages/coding-agent/examples/extensions/question.ts +286 -0
  537. package/.references/pi/packages/coding-agent/examples/extensions/questionnaire.ts +448 -0
  538. package/.references/pi/packages/coding-agent/examples/extensions/rainbow-editor.ts +88 -0
  539. package/.references/pi/packages/coding-agent/examples/extensions/reload-runtime.ts +37 -0
  540. package/.references/pi/packages/coding-agent/examples/extensions/rpc-demo.ts +118 -0
  541. package/.references/pi/packages/coding-agent/examples/extensions/sandbox/index.ts +321 -0
  542. package/.references/pi/packages/coding-agent/examples/extensions/sandbox/package-lock.json +92 -0
  543. package/.references/pi/packages/coding-agent/examples/extensions/sandbox/package.json +19 -0
  544. package/.references/pi/packages/coding-agent/examples/extensions/send-user-message.ts +97 -0
  545. package/.references/pi/packages/coding-agent/examples/extensions/session-name.ts +27 -0
  546. package/.references/pi/packages/coding-agent/examples/extensions/shutdown-command.ts +63 -0
  547. package/.references/pi/packages/coding-agent/examples/extensions/snake.ts +343 -0
  548. package/.references/pi/packages/coding-agent/examples/extensions/space-invaders.ts +560 -0
  549. package/.references/pi/packages/coding-agent/examples/extensions/ssh.ts +220 -0
  550. package/.references/pi/packages/coding-agent/examples/extensions/status-line.ts +32 -0
  551. package/.references/pi/packages/coding-agent/examples/extensions/structured-output.ts +65 -0
  552. package/.references/pi/packages/coding-agent/examples/extensions/subagent/README.md +175 -0
  553. package/.references/pi/packages/coding-agent/examples/extensions/subagent/agents/planner.md +37 -0
  554. package/.references/pi/packages/coding-agent/examples/extensions/subagent/agents/reviewer.md +35 -0
  555. package/.references/pi/packages/coding-agent/examples/extensions/subagent/agents/scout.md +50 -0
  556. package/.references/pi/packages/coding-agent/examples/extensions/subagent/agents/worker.md +24 -0
  557. package/.references/pi/packages/coding-agent/examples/extensions/subagent/agents.ts +126 -0
  558. package/.references/pi/packages/coding-agent/examples/extensions/subagent/index.ts +1015 -0
  559. package/.references/pi/packages/coding-agent/examples/extensions/subagent/prompts/implement-and-review.md +10 -0
  560. package/.references/pi/packages/coding-agent/examples/extensions/subagent/prompts/implement.md +10 -0
  561. package/.references/pi/packages/coding-agent/examples/extensions/subagent/prompts/scout-and-plan.md +9 -0
  562. package/.references/pi/packages/coding-agent/examples/extensions/summarize.ts +207 -0
  563. package/.references/pi/packages/coding-agent/examples/extensions/system-prompt-header.ts +17 -0
  564. package/.references/pi/packages/coding-agent/examples/extensions/tic-tac-toe.ts +1008 -0
  565. package/.references/pi/packages/coding-agent/examples/extensions/timed-confirm.ts +70 -0
  566. package/.references/pi/packages/coding-agent/examples/extensions/titlebar-spinner.ts +58 -0
  567. package/.references/pi/packages/coding-agent/examples/extensions/todo.ts +297 -0
  568. package/.references/pi/packages/coding-agent/examples/extensions/tool-override.ts +144 -0
  569. package/.references/pi/packages/coding-agent/examples/extensions/tools.ts +146 -0
  570. package/.references/pi/packages/coding-agent/examples/extensions/trigger-compact.ts +50 -0
  571. package/.references/pi/packages/coding-agent/examples/extensions/truncated-tool.ts +195 -0
  572. package/.references/pi/packages/coding-agent/examples/extensions/widget-placement.ts +9 -0
  573. package/.references/pi/packages/coding-agent/examples/extensions/with-deps/index.ts +32 -0
  574. package/.references/pi/packages/coding-agent/examples/extensions/with-deps/package-lock.json +31 -0
  575. package/.references/pi/packages/coding-agent/examples/extensions/with-deps/package.json +22 -0
  576. package/.references/pi/packages/coding-agent/examples/extensions/working-indicator.ts +123 -0
  577. package/.references/pi/packages/coding-agent/examples/extensions/working-message-test.ts +25 -0
  578. package/.references/pi/packages/coding-agent/examples/rpc-extension-ui.ts +632 -0
  579. package/.references/pi/packages/coding-agent/examples/sdk/01-minimal.ts +26 -0
  580. package/.references/pi/packages/coding-agent/examples/sdk/02-custom-model.ts +50 -0
  581. package/.references/pi/packages/coding-agent/examples/sdk/03-custom-prompt.ts +75 -0
  582. package/.references/pi/packages/coding-agent/examples/sdk/04-skills.ts +55 -0
  583. package/.references/pi/packages/coding-agent/examples/sdk/05-tools.ts +48 -0
  584. package/.references/pi/packages/coding-agent/examples/sdk/06-extensions.ts +99 -0
  585. package/.references/pi/packages/coding-agent/examples/sdk/07-context-files.ts +47 -0
  586. package/.references/pi/packages/coding-agent/examples/sdk/08-prompt-templates.ts +51 -0
  587. package/.references/pi/packages/coding-agent/examples/sdk/09-api-keys-and-oauth.ts +34 -0
  588. package/.references/pi/packages/coding-agent/examples/sdk/10-settings.ts +53 -0
  589. package/.references/pi/packages/coding-agent/examples/sdk/11-sessions.ts +52 -0
  590. package/.references/pi/packages/coding-agent/examples/sdk/12-full-control.ts +72 -0
  591. package/.references/pi/packages/coding-agent/examples/sdk/13-session-runtime.ts +67 -0
  592. package/.references/pi/packages/coding-agent/examples/sdk/README.md +140 -0
  593. package/.references/pi/packages/coding-agent/install-lock/package-lock.json +1849 -0
  594. package/.references/pi/packages/coding-agent/install-lock/package.json +18 -0
  595. package/.references/pi/packages/coding-agent/npm-shrinkwrap.json +1839 -0
  596. package/.references/pi/packages/coding-agent/package.json +100 -0
  597. package/.references/pi/packages/coding-agent/scripts/migrate-sessions.sh +93 -0
  598. package/.references/pi/packages/coding-agent/src/bun/cli.ts +15 -0
  599. package/.references/pi/packages/coding-agent/src/bun/register-bedrock.ts +4 -0
  600. package/.references/pi/packages/coding-agent/src/bun/restore-sandbox-env.ts +36 -0
  601. package/.references/pi/packages/coding-agent/src/cli/args.ts +390 -0
  602. package/.references/pi/packages/coding-agent/src/cli/config-selector.ts +56 -0
  603. package/.references/pi/packages/coding-agent/src/cli/file-processor.ts +87 -0
  604. package/.references/pi/packages/coding-agent/src/cli/initial-message.ts +43 -0
  605. package/.references/pi/packages/coding-agent/src/cli/list-models.ts +111 -0
  606. package/.references/pi/packages/coding-agent/src/cli/project-trust.ts +62 -0
  607. package/.references/pi/packages/coding-agent/src/cli/session-picker.ts +55 -0
  608. package/.references/pi/packages/coding-agent/src/cli/startup-ui.ts +239 -0
  609. package/.references/pi/packages/coding-agent/src/cli.ts +20 -0
  610. package/.references/pi/packages/coding-agent/src/config.ts +566 -0
  611. package/.references/pi/packages/coding-agent/src/core/agent-session-runtime.ts +438 -0
  612. package/.references/pi/packages/coding-agent/src/core/agent-session-services.ts +207 -0
  613. package/.references/pi/packages/coding-agent/src/core/agent-session.ts +3279 -0
  614. package/.references/pi/packages/coding-agent/src/core/auth-guidance.ts +25 -0
  615. package/.references/pi/packages/coding-agent/src/core/auth-storage.ts +271 -0
  616. package/.references/pi/packages/coding-agent/src/core/bash-executor.ts +156 -0
  617. package/.references/pi/packages/coding-agent/src/core/cache-stats.ts +164 -0
  618. package/.references/pi/packages/coding-agent/src/core/compaction/branch-summarization.ts +371 -0
  619. package/.references/pi/packages/coding-agent/src/core/compaction/compaction.ts +872 -0
  620. package/.references/pi/packages/coding-agent/src/core/compaction/index.ts +7 -0
  621. package/.references/pi/packages/coding-agent/src/core/compaction/utils.ts +170 -0
  622. package/.references/pi/packages/coding-agent/src/core/defaults.ts +3 -0
  623. package/.references/pi/packages/coding-agent/src/core/diagnostics.ts +15 -0
  624. package/.references/pi/packages/coding-agent/src/core/event-bus.ts +33 -0
  625. package/.references/pi/packages/coding-agent/src/core/exec.ts +107 -0
  626. package/.references/pi/packages/coding-agent/src/core/experimental.ts +3 -0
  627. package/.references/pi/packages/coding-agent/src/core/export-html/ansi-to-html.ts +258 -0
  628. package/.references/pi/packages/coding-agent/src/core/export-html/index.ts +316 -0
  629. package/.references/pi/packages/coding-agent/src/core/export-html/template.css +1066 -0
  630. package/.references/pi/packages/coding-agent/src/core/export-html/template.html +55 -0
  631. package/.references/pi/packages/coding-agent/src/core/export-html/template.js +1864 -0
  632. package/.references/pi/packages/coding-agent/src/core/export-html/tool-renderer.ts +172 -0
  633. package/.references/pi/packages/coding-agent/src/core/export-html/vendor/highlight.min.js +1213 -0
  634. package/.references/pi/packages/coding-agent/src/core/export-html/vendor/marked.min.js +78 -0
  635. package/.references/pi/packages/coding-agent/src/core/extensions/index.ts +184 -0
  636. package/.references/pi/packages/coding-agent/src/core/extensions/loader.ts +708 -0
  637. package/.references/pi/packages/coding-agent/src/core/extensions/runner.ts +1189 -0
  638. package/.references/pi/packages/coding-agent/src/core/extensions/types.ts +1674 -0
  639. package/.references/pi/packages/coding-agent/src/core/extensions/wrapper.ts +45 -0
  640. package/.references/pi/packages/coding-agent/src/core/footer-data-provider.ts +388 -0
  641. package/.references/pi/packages/coding-agent/src/core/http-dispatcher.ts +106 -0
  642. package/.references/pi/packages/coding-agent/src/core/index.ts +80 -0
  643. package/.references/pi/packages/coding-agent/src/core/keybindings.ts +370 -0
  644. package/.references/pi/packages/coding-agent/src/core/messages.ts +195 -0
  645. package/.references/pi/packages/coding-agent/src/core/model-config.ts +287 -0
  646. package/.references/pi/packages/coding-agent/src/core/model-registry.ts +126 -0
  647. package/.references/pi/packages/coding-agent/src/core/model-resolver.ts +705 -0
  648. package/.references/pi/packages/coding-agent/src/core/model-runtime.ts +566 -0
  649. package/.references/pi/packages/coding-agent/src/core/models-store.ts +57 -0
  650. package/.references/pi/packages/coding-agent/src/core/output-guard.ts +108 -0
  651. package/.references/pi/packages/coding-agent/src/core/package-manager.ts +2650 -0
  652. package/.references/pi/packages/coding-agent/src/core/project-trust.ts +96 -0
  653. package/.references/pi/packages/coding-agent/src/core/prompt-templates.ts +284 -0
  654. package/.references/pi/packages/coding-agent/src/core/provider-attribution.ts +97 -0
  655. package/.references/pi/packages/coding-agent/src/core/provider-composer.ts +548 -0
  656. package/.references/pi/packages/coding-agent/src/core/radius.ts +1 -0
  657. package/.references/pi/packages/coding-agent/src/core/remote-catalog-provider.ts +83 -0
  658. package/.references/pi/packages/coding-agent/src/core/resolve-config-value.ts +287 -0
  659. package/.references/pi/packages/coding-agent/src/core/resource-loader.ts +1039 -0
  660. package/.references/pi/packages/coding-agent/src/core/runtime-credentials.ts +48 -0
  661. package/.references/pi/packages/coding-agent/src/core/sdk.ts +393 -0
  662. package/.references/pi/packages/coding-agent/src/core/session-cwd.ts +59 -0
  663. package/.references/pi/packages/coding-agent/src/core/session-manager.ts +1623 -0
  664. package/.references/pi/packages/coding-agent/src/core/settings-manager.ts +1234 -0
  665. package/.references/pi/packages/coding-agent/src/core/skills.ts +487 -0
  666. package/.references/pi/packages/coding-agent/src/core/slash-commands.ts +42 -0
  667. package/.references/pi/packages/coding-agent/src/core/source-info.ts +40 -0
  668. package/.references/pi/packages/coding-agent/src/core/system-prompt.ts +162 -0
  669. package/.references/pi/packages/coding-agent/src/core/telemetry.ts +13 -0
  670. package/.references/pi/packages/coding-agent/src/core/timings.ts +50 -0
  671. package/.references/pi/packages/coding-agent/src/core/tools/bash.ts +470 -0
  672. package/.references/pi/packages/coding-agent/src/core/tools/edit-diff.ts +560 -0
  673. package/.references/pi/packages/coding-agent/src/core/tools/edit.ts +437 -0
  674. package/.references/pi/packages/coding-agent/src/core/tools/file-mutation-queue.ts +61 -0
  675. package/.references/pi/packages/coding-agent/src/core/tools/find.ts +374 -0
  676. package/.references/pi/packages/coding-agent/src/core/tools/grep.ts +385 -0
  677. package/.references/pi/packages/coding-agent/src/core/tools/index.ts +196 -0
  678. package/.references/pi/packages/coding-agent/src/core/tools/ls.ts +225 -0
  679. package/.references/pi/packages/coding-agent/src/core/tools/output-accumulator.ts +222 -0
  680. package/.references/pi/packages/coding-agent/src/core/tools/path-utils.ts +118 -0
  681. package/.references/pi/packages/coding-agent/src/core/tools/read.ts +351 -0
  682. package/.references/pi/packages/coding-agent/src/core/tools/render-utils.ts +85 -0
  683. package/.references/pi/packages/coding-agent/src/core/tools/tool-definition-wrapper.ts +45 -0
  684. package/.references/pi/packages/coding-agent/src/core/tools/truncate.ts +276 -0
  685. package/.references/pi/packages/coding-agent/src/core/tools/write.ts +267 -0
  686. package/.references/pi/packages/coding-agent/src/core/trust-manager.ts +244 -0
  687. package/.references/pi/packages/coding-agent/src/index.ts +394 -0
  688. package/.references/pi/packages/coding-agent/src/main.ts +857 -0
  689. package/.references/pi/packages/coding-agent/src/migrations.ts +315 -0
  690. package/.references/pi/packages/coding-agent/src/modes/index.ts +15 -0
  691. package/.references/pi/packages/coding-agent/src/modes/interactive/assets/clankolas.png +0 -0
  692. package/.references/pi/packages/coding-agent/src/modes/interactive/components/armin.ts +382 -0
  693. package/.references/pi/packages/coding-agent/src/modes/interactive/components/assistant-message.ts +180 -0
  694. package/.references/pi/packages/coding-agent/src/modes/interactive/components/bash-execution.ts +220 -0
  695. package/.references/pi/packages/coding-agent/src/modes/interactive/components/bordered-loader.ts +68 -0
  696. package/.references/pi/packages/coding-agent/src/modes/interactive/components/branch-summary-message.ts +58 -0
  697. package/.references/pi/packages/coding-agent/src/modes/interactive/components/compaction-summary-message.ts +59 -0
  698. package/.references/pi/packages/coding-agent/src/modes/interactive/components/config-selector.ts +942 -0
  699. package/.references/pi/packages/coding-agent/src/modes/interactive/components/countdown-timer.ts +39 -0
  700. package/.references/pi/packages/coding-agent/src/modes/interactive/components/custom-editor.ts +80 -0
  701. package/.references/pi/packages/coding-agent/src/modes/interactive/components/custom-entry.ts +62 -0
  702. package/.references/pi/packages/coding-agent/src/modes/interactive/components/custom-message.ts +99 -0
  703. package/.references/pi/packages/coding-agent/src/modes/interactive/components/daxnuts.ts +164 -0
  704. package/.references/pi/packages/coding-agent/src/modes/interactive/components/diff.ts +147 -0
  705. package/.references/pi/packages/coding-agent/src/modes/interactive/components/dynamic-border.ts +25 -0
  706. package/.references/pi/packages/coding-agent/src/modes/interactive/components/earendil-announcement.ts +53 -0
  707. package/.references/pi/packages/coding-agent/src/modes/interactive/components/extension-editor.ts +167 -0
  708. package/.references/pi/packages/coding-agent/src/modes/interactive/components/extension-input.ts +87 -0
  709. package/.references/pi/packages/coding-agent/src/modes/interactive/components/extension-selector.ts +112 -0
  710. package/.references/pi/packages/coding-agent/src/modes/interactive/components/first-time-setup.ts +145 -0
  711. package/.references/pi/packages/coding-agent/src/modes/interactive/components/footer.ts +245 -0
  712. package/.references/pi/packages/coding-agent/src/modes/interactive/components/index.ts +38 -0
  713. package/.references/pi/packages/coding-agent/src/modes/interactive/components/keybinding-hints.ts +48 -0
  714. package/.references/pi/packages/coding-agent/src/modes/interactive/components/login-dialog.ts +233 -0
  715. package/.references/pi/packages/coding-agent/src/modes/interactive/components/model-selector.ts +361 -0
  716. package/.references/pi/packages/coding-agent/src/modes/interactive/components/oauth-selector.ts +214 -0
  717. package/.references/pi/packages/coding-agent/src/modes/interactive/components/scoped-models-selector.ts +360 -0
  718. package/.references/pi/packages/coding-agent/src/modes/interactive/components/session-selector-search.ts +194 -0
  719. package/.references/pi/packages/coding-agent/src/modes/interactive/components/session-selector.ts +1031 -0
  720. package/.references/pi/packages/coding-agent/src/modes/interactive/components/settings-selector.ts +838 -0
  721. package/.references/pi/packages/coding-agent/src/modes/interactive/components/show-images-selector.ts +50 -0
  722. package/.references/pi/packages/coding-agent/src/modes/interactive/components/skill-invocation-message.ts +55 -0
  723. package/.references/pi/packages/coding-agent/src/modes/interactive/components/status-indicator.ts +114 -0
  724. package/.references/pi/packages/coding-agent/src/modes/interactive/components/theme-selector.ts +67 -0
  725. package/.references/pi/packages/coding-agent/src/modes/interactive/components/thinking-selector.ts +75 -0
  726. package/.references/pi/packages/coding-agent/src/modes/interactive/components/tool-execution.ts +377 -0
  727. package/.references/pi/packages/coding-agent/src/modes/interactive/components/tree-selector.ts +1427 -0
  728. package/.references/pi/packages/coding-agent/src/modes/interactive/components/trust-selector.ts +134 -0
  729. package/.references/pi/packages/coding-agent/src/modes/interactive/components/user-message-selector.ts +155 -0
  730. package/.references/pi/packages/coding-agent/src/modes/interactive/components/user-message.ts +57 -0
  731. package/.references/pi/packages/coding-agent/src/modes/interactive/components/visual-truncate.ts +50 -0
  732. package/.references/pi/packages/coding-agent/src/modes/interactive/interactive-mode.ts +6005 -0
  733. package/.references/pi/packages/coding-agent/src/modes/interactive/model-search.ts +21 -0
  734. package/.references/pi/packages/coding-agent/src/modes/interactive/theme/dark.json +87 -0
  735. package/.references/pi/packages/coding-agent/src/modes/interactive/theme/light.json +86 -0
  736. package/.references/pi/packages/coding-agent/src/modes/interactive/theme/theme-controller.ts +126 -0
  737. package/.references/pi/packages/coding-agent/src/modes/interactive/theme/theme-schema.json +340 -0
  738. package/.references/pi/packages/coding-agent/src/modes/interactive/theme/theme.ts +1294 -0
  739. package/.references/pi/packages/coding-agent/src/modes/print-mode.ts +159 -0
  740. package/.references/pi/packages/coding-agent/src/modes/rpc/jsonl.ts +58 -0
  741. package/.references/pi/packages/coding-agent/src/modes/rpc/rpc-client.ts +592 -0
  742. package/.references/pi/packages/coding-agent/src/modes/rpc/rpc-mode.ts +795 -0
  743. package/.references/pi/packages/coding-agent/src/modes/rpc/rpc-types.ts +281 -0
  744. package/.references/pi/packages/coding-agent/src/package-manager-cli.ts +887 -0
  745. package/.references/pi/packages/coding-agent/src/rpc-entry.ts +12 -0
  746. package/.references/pi/packages/coding-agent/src/utils/ansi.ts +60 -0
  747. package/.references/pi/packages/coding-agent/src/utils/changelog.ts +196 -0
  748. package/.references/pi/packages/coding-agent/src/utils/child-process.ts +137 -0
  749. package/.references/pi/packages/coding-agent/src/utils/clipboard-image.ts +300 -0
  750. package/.references/pi/packages/coding-agent/src/utils/clipboard-native.ts +33 -0
  751. package/.references/pi/packages/coding-agent/src/utils/clipboard.ts +141 -0
  752. package/.references/pi/packages/coding-agent/src/utils/deprecation.ts +14 -0
  753. package/.references/pi/packages/coding-agent/src/utils/exif-orientation.ts +183 -0
  754. package/.references/pi/packages/coding-agent/src/utils/frontmatter.ts +39 -0
  755. package/.references/pi/packages/coding-agent/src/utils/fs-watch.ts +30 -0
  756. package/.references/pi/packages/coding-agent/src/utils/git.ts +226 -0
  757. package/.references/pi/packages/coding-agent/src/utils/highlight-js-lib-index.d.ts +19 -0
  758. package/.references/pi/packages/coding-agent/src/utils/html.ts +51 -0
  759. package/.references/pi/packages/coding-agent/src/utils/image-convert.ts +49 -0
  760. package/.references/pi/packages/coding-agent/src/utils/image-process.ts +119 -0
  761. package/.references/pi/packages/coding-agent/src/utils/image-resize-core.ts +164 -0
  762. package/.references/pi/packages/coding-agent/src/utils/image-resize-worker.ts +42 -0
  763. package/.references/pi/packages/coding-agent/src/utils/image-resize.ts +123 -0
  764. package/.references/pi/packages/coding-agent/src/utils/json.ts +6 -0
  765. package/.references/pi/packages/coding-agent/src/utils/mime.ts +116 -0
  766. package/.references/pi/packages/coding-agent/src/utils/open-browser.ts +24 -0
  767. package/.references/pi/packages/coding-agent/src/utils/paths.ts +118 -0
  768. package/.references/pi/packages/coding-agent/src/utils/photon.ts +139 -0
  769. package/.references/pi/packages/coding-agent/src/utils/pi-user-agent.ts +4 -0
  770. package/.references/pi/packages/coding-agent/src/utils/shell.ts +225 -0
  771. package/.references/pi/packages/coding-agent/src/utils/sleep.ts +18 -0
  772. package/.references/pi/packages/coding-agent/src/utils/syntax-highlight.ts +146 -0
  773. package/.references/pi/packages/coding-agent/src/utils/tools-manager.ts +369 -0
  774. package/.references/pi/packages/coding-agent/src/utils/version-check.ts +80 -0
  775. package/.references/pi/packages/coding-agent/src/utils/windows-self-update.ts +84 -0
  776. package/.references/pi/packages/coding-agent/test/agent-session-auto-compaction-queue.test.ts +450 -0
  777. package/.references/pi/packages/coding-agent/test/agent-session-branching.test.ts +156 -0
  778. package/.references/pi/packages/coding-agent/test/agent-session-compaction.test.ts +208 -0
  779. package/.references/pi/packages/coding-agent/test/agent-session-concurrent.test.ts +629 -0
  780. package/.references/pi/packages/coding-agent/test/agent-session-dynamic-provider.test.ts +122 -0
  781. package/.references/pi/packages/coding-agent/test/agent-session-dynamic-tools.test.ts +185 -0
  782. package/.references/pi/packages/coding-agent/test/agent-session-retry.test.ts +322 -0
  783. package/.references/pi/packages/coding-agent/test/agent-session-runtime-events.test.ts +257 -0
  784. package/.references/pi/packages/coding-agent/test/agent-session-stats.test.ts +169 -0
  785. package/.references/pi/packages/coding-agent/test/agent-session-tree-navigation.test.ts +323 -0
  786. package/.references/pi/packages/coding-agent/test/ansi-utils.test.ts +110 -0
  787. package/.references/pi/packages/coding-agent/test/args.test.ts +441 -0
  788. package/.references/pi/packages/coding-agent/test/assistant-message.test.ts +130 -0
  789. package/.references/pi/packages/coding-agent/test/auth-storage.test.ts +217 -0
  790. package/.references/pi/packages/coding-agent/test/bash-close-hang-windows.test.ts +126 -0
  791. package/.references/pi/packages/coding-agent/test/bash-execution-width.test.ts +80 -0
  792. package/.references/pi/packages/coding-agent/test/block-images.test.ts +148 -0
  793. package/.references/pi/packages/coding-agent/test/cache-stats.test.ts +143 -0
  794. package/.references/pi/packages/coding-agent/test/changelog.test.ts +49 -0
  795. package/.references/pi/packages/coding-agent/test/clipboard-image-bmp-conversion.test.ts +88 -0
  796. package/.references/pi/packages/coding-agent/test/clipboard-image.test.ts +184 -0
  797. package/.references/pi/packages/coding-agent/test/clipboard-native.test.ts +32 -0
  798. package/.references/pi/packages/coding-agent/test/clipboard.test.ts +166 -0
  799. package/.references/pi/packages/coding-agent/test/compaction-extensions-example.test.ts +66 -0
  800. package/.references/pi/packages/coding-agent/test/compaction-extensions.test.ts +415 -0
  801. package/.references/pi/packages/coding-agent/test/compaction-serialization.test.ts +79 -0
  802. package/.references/pi/packages/coding-agent/test/compaction-summary-reasoning.test.ts +134 -0
  803. package/.references/pi/packages/coding-agent/test/compaction.test.ts +596 -0
  804. package/.references/pi/packages/coding-agent/test/config-value-migration.test.ts +178 -0
  805. package/.references/pi/packages/coding-agent/test/config.test.ts +437 -0
  806. package/.references/pi/packages/coding-agent/test/edit-tool-legacy-input.test.ts +116 -0
  807. package/.references/pi/packages/coding-agent/test/edit-tool-no-full-redraw.test.ts +235 -0
  808. package/.references/pi/packages/coding-agent/test/experimental.test.ts +44 -0
  809. package/.references/pi/packages/coding-agent/test/export-html-skill-block.test.ts +40 -0
  810. package/.references/pi/packages/coding-agent/test/export-html-whitespace.test.ts +42 -0
  811. package/.references/pi/packages/coding-agent/test/export-html-xss.test.ts +67 -0
  812. package/.references/pi/packages/coding-agent/test/extensions-discovery.test.ts +528 -0
  813. package/.references/pi/packages/coding-agent/test/extensions-input-event.test.ts +125 -0
  814. package/.references/pi/packages/coding-agent/test/extensions-runner.test.ts +986 -0
  815. package/.references/pi/packages/coding-agent/test/file-mutation-queue.test.ts +274 -0
  816. package/.references/pi/packages/coding-agent/test/first-time-setup-fork.test.ts +39 -0
  817. package/.references/pi/packages/coding-agent/test/first-time-setup.test.ts +95 -0
  818. package/.references/pi/packages/coding-agent/test/fixtures/assistant-message-with-thinking-code.json +33 -0
  819. package/.references/pi/packages/coding-agent/test/fixtures/before-compaction.jsonl +1003 -0
  820. package/.references/pi/packages/coding-agent/test/fixtures/empty-agent/.gitkeep +0 -0
  821. package/.references/pi/packages/coding-agent/test/fixtures/empty-cwd/.gitkeep +0 -0
  822. package/.references/pi/packages/coding-agent/test/fixtures/large-session.jsonl +1019 -0
  823. package/.references/pi/packages/coding-agent/test/fixtures/skills/consecutive-hyphens/SKILL.md +8 -0
  824. package/.references/pi/packages/coding-agent/test/fixtures/skills/disable-model-invocation/SKILL.md +9 -0
  825. package/.references/pi/packages/coding-agent/test/fixtures/skills/invalid-name-chars/SKILL.md +8 -0
  826. package/.references/pi/packages/coding-agent/test/fixtures/skills/invalid-yaml/SKILL.md +8 -0
  827. package/.references/pi/packages/coding-agent/test/fixtures/skills/long-name/SKILL.md +8 -0
  828. package/.references/pi/packages/coding-agent/test/fixtures/skills/missing-description/SKILL.md +7 -0
  829. package/.references/pi/packages/coding-agent/test/fixtures/skills/multiline-description/SKILL.md +11 -0
  830. package/.references/pi/packages/coding-agent/test/fixtures/skills/name-mismatch/SKILL.md +8 -0
  831. package/.references/pi/packages/coding-agent/test/fixtures/skills/nested/child-skill/SKILL.md +8 -0
  832. package/.references/pi/packages/coding-agent/test/fixtures/skills/no-frontmatter/SKILL.md +3 -0
  833. package/.references/pi/packages/coding-agent/test/fixtures/skills/root-skill-preferred/SKILL.md +3 -0
  834. package/.references/pi/packages/coding-agent/test/fixtures/skills/root-skill-preferred/nested-child/SKILL.md +3 -0
  835. package/.references/pi/packages/coding-agent/test/fixtures/skills/unknown-field/SKILL.md +10 -0
  836. package/.references/pi/packages/coding-agent/test/fixtures/skills/valid-skill/SKILL.md +8 -0
  837. package/.references/pi/packages/coding-agent/test/fixtures/skills-collision/first/calendar/SKILL.md +8 -0
  838. package/.references/pi/packages/coding-agent/test/fixtures/skills-collision/second/calendar/SKILL.md +8 -0
  839. package/.references/pi/packages/coding-agent/test/footer-data-provider.test.ts +265 -0
  840. package/.references/pi/packages/coding-agent/test/footer-width.test.ts +144 -0
  841. package/.references/pi/packages/coding-agent/test/format-resume-command.test.ts +135 -0
  842. package/.references/pi/packages/coding-agent/test/frontmatter.test.ts +60 -0
  843. package/.references/pi/packages/coding-agent/test/git-merge-and-resolve-extension.test.ts +206 -0
  844. package/.references/pi/packages/coding-agent/test/git-ssh-url.test.ts +91 -0
  845. package/.references/pi/packages/coding-agent/test/git-update.test.ts +484 -0
  846. package/.references/pi/packages/coding-agent/test/http-dispatcher.test.ts +53 -0
  847. package/.references/pi/packages/coding-agent/test/image-process.test.ts +53 -0
  848. package/.references/pi/packages/coding-agent/test/image-processing.test.ts +170 -0
  849. package/.references/pi/packages/coding-agent/test/image-resize-callers.test.ts +53 -0
  850. package/.references/pi/packages/coding-agent/test/initial-message.test.ts +48 -0
  851. package/.references/pi/packages/coding-agent/test/input-transform-streaming-example.test.ts +84 -0
  852. package/.references/pi/packages/coding-agent/test/interactive-mode-anthropic-warning.test.ts +89 -0
  853. package/.references/pi/packages/coding-agent/test/interactive-mode-clone-command.test.ts +72 -0
  854. package/.references/pi/packages/coding-agent/test/interactive-mode-compaction.test.ts +85 -0
  855. package/.references/pi/packages/coding-agent/test/interactive-mode-import-command.test.ts +143 -0
  856. package/.references/pi/packages/coding-agent/test/interactive-mode-startup-input.test.ts +72 -0
  857. package/.references/pi/packages/coding-agent/test/interactive-mode-status.test.ts +1123 -0
  858. package/.references/pi/packages/coding-agent/test/interactive-mode-suspend.test.ts +149 -0
  859. package/.references/pi/packages/coding-agent/test/keybindings-migration.test.ts +88 -0
  860. package/.references/pi/packages/coding-agent/test/max-thinking.test.ts +45 -0
  861. package/.references/pi/packages/coding-agent/test/model-registry.test.ts +1934 -0
  862. package/.references/pi/packages/coding-agent/test/model-resolver.test.ts +690 -0
  863. package/.references/pi/packages/coding-agent/test/model-runtime-auth-options.test.ts +256 -0
  864. package/.references/pi/packages/coding-agent/test/model-runtime-cloudflare-compat.test.ts +95 -0
  865. package/.references/pi/packages/coding-agent/test/model-runtime-modify-models-compat.test.ts +85 -0
  866. package/.references/pi/packages/coding-agent/test/model-runtime-test-utils.ts +25 -0
  867. package/.references/pi/packages/coding-agent/test/models-store.test.ts +51 -0
  868. package/.references/pi/packages/coding-agent/test/oauth-selector.test.ts +147 -0
  869. package/.references/pi/packages/coding-agent/test/package-command-paths.test.ts +746 -0
  870. package/.references/pi/packages/coding-agent/test/package-manager-ssh.test.ts +97 -0
  871. package/.references/pi/packages/coding-agent/test/package-manager.test.ts +2512 -0
  872. package/.references/pi/packages/coding-agent/test/path-utils.test.ts +174 -0
  873. package/.references/pi/packages/coding-agent/test/paths.test.ts +150 -0
  874. package/.references/pi/packages/coding-agent/test/pi-user-agent.test.ts +12 -0
  875. package/.references/pi/packages/coding-agent/test/plan-mode-extension.test.ts +167 -0
  876. package/.references/pi/packages/coding-agent/test/plan-mode-utils.test.ts +261 -0
  877. package/.references/pi/packages/coding-agent/test/print-mode.test.ts +142 -0
  878. package/.references/pi/packages/coding-agent/test/prompt-templates.test.ts +615 -0
  879. package/.references/pi/packages/coding-agent/test/radius.test.ts +151 -0
  880. package/.references/pi/packages/coding-agent/test/remote-catalog-provider.test.ts +118 -0
  881. package/.references/pi/packages/coding-agent/test/resolve-config-value.test.ts +121 -0
  882. package/.references/pi/packages/coding-agent/test/resource-loader.test.ts +739 -0
  883. package/.references/pi/packages/coding-agent/test/restore-sandbox-env.test.ts +77 -0
  884. package/.references/pi/packages/coding-agent/test/rpc-client-clone.test.ts +29 -0
  885. package/.references/pi/packages/coding-agent/test/rpc-client-process-exit.test.ts +38 -0
  886. package/.references/pi/packages/coding-agent/test/rpc-example.ts +86 -0
  887. package/.references/pi/packages/coding-agent/test/rpc-jsonl.test.ts +65 -0
  888. package/.references/pi/packages/coding-agent/test/rpc-prompt-response-semantics.test.ts +288 -0
  889. package/.references/pi/packages/coding-agent/test/rpc.test.ts +377 -0
  890. package/.references/pi/packages/coding-agent/test/runtime-credentials.test.ts +42 -0
  891. package/.references/pi/packages/coding-agent/test/sdk-codex-cache-probe-tool-loop.ts +497 -0
  892. package/.references/pi/packages/coding-agent/test/sdk-openrouter-attribution.test.ts +266 -0
  893. package/.references/pi/packages/coding-agent/test/sdk-session-manager.test.ts +95 -0
  894. package/.references/pi/packages/coding-agent/test/sdk-skills.test.ts +109 -0
  895. package/.references/pi/packages/coding-agent/test/sdk-stream-options.test.ts +188 -0
  896. package/.references/pi/packages/coding-agent/test/session-cwd.test.ts +91 -0
  897. package/.references/pi/packages/coding-agent/test/session-file-invalid.test.ts +65 -0
  898. package/.references/pi/packages/coding-agent/test/session-id-readonly.test.ts +190 -0
  899. package/.references/pi/packages/coding-agent/test/session-info-modified-timestamp.test.ts +83 -0
  900. package/.references/pi/packages/coding-agent/test/session-manager/build-context.test.ts +305 -0
  901. package/.references/pi/packages/coding-agent/test/session-manager/custom-session-id.test.ts +169 -0
  902. package/.references/pi/packages/coding-agent/test/session-manager/file-operations.test.ts +315 -0
  903. package/.references/pi/packages/coding-agent/test/session-manager/labels.test.ts +211 -0
  904. package/.references/pi/packages/coding-agent/test/session-manager/migration.test.ts +78 -0
  905. package/.references/pi/packages/coding-agent/test/session-manager/save-entry.test.ts +55 -0
  906. package/.references/pi/packages/coding-agent/test/session-manager/tree-traversal.test.ts +533 -0
  907. package/.references/pi/packages/coding-agent/test/session-selector-path-delete.test.ts +354 -0
  908. package/.references/pi/packages/coding-agent/test/session-selector-rename.test.ts +111 -0
  909. package/.references/pi/packages/coding-agent/test/session-selector-search.test.ts +195 -0
  910. package/.references/pi/packages/coding-agent/test/settings-manager-bug.test.ts +147 -0
  911. package/.references/pi/packages/coding-agent/test/settings-manager.test.ts +511 -0
  912. package/.references/pi/packages/coding-agent/test/skills.test.ts +432 -0
  913. package/.references/pi/packages/coding-agent/test/startup-session-name.test.ts +135 -0
  914. package/.references/pi/packages/coding-agent/test/status-indicator.test.ts +32 -0
  915. package/.references/pi/packages/coding-agent/test/stdout-cleanliness.test.ts +128 -0
  916. package/.references/pi/packages/coding-agent/test/streaming-render-debug.ts +97 -0
  917. package/.references/pi/packages/coding-agent/test/suite/README.md +16 -0
  918. package/.references/pi/packages/coding-agent/test/suite/agent-session-bash-persistence.test.ts +242 -0
  919. package/.references/pi/packages/coding-agent/test/suite/agent-session-compaction.test.ts +446 -0
  920. package/.references/pi/packages/coding-agent/test/suite/agent-session-model-extension.test.ts +373 -0
  921. package/.references/pi/packages/coding-agent/test/suite/agent-session-prompt.test.ts +398 -0
  922. package/.references/pi/packages/coding-agent/test/suite/agent-session-queue.test.ts +445 -0
  923. package/.references/pi/packages/coding-agent/test/suite/agent-session-retry-events.test.ts +364 -0
  924. package/.references/pi/packages/coding-agent/test/suite/agent-session-runtime.test.ts +609 -0
  925. package/.references/pi/packages/coding-agent/test/suite/harness.ts +219 -0
  926. package/.references/pi/packages/coding-agent/test/suite/lax-message-content.test.ts +162 -0
  927. package/.references/pi/packages/coding-agent/test/suite/regressions/1717-2113-agent-session-event-settlement.test.ts +95 -0
  928. package/.references/pi/packages/coding-agent/test/suite/regressions/2023-queued-slash-command-followup.test.ts +80 -0
  929. package/.references/pi/packages/coding-agent/test/suite/regressions/2753-reload-stale-resource-settings.test.ts +105 -0
  930. package/.references/pi/packages/coding-agent/test/suite/regressions/2781-skill-collision-precedence.test.ts +120 -0
  931. package/.references/pi/packages/coding-agent/test/suite/regressions/2791-fswatch-error-crash.test.ts +106 -0
  932. package/.references/pi/packages/coding-agent/test/suite/regressions/2835-tools-allowlist-filters-extension-tools.test.ts +94 -0
  933. package/.references/pi/packages/coding-agent/test/suite/regressions/2860-replaced-session-context.test.ts +279 -0
  934. package/.references/pi/packages/coding-agent/test/suite/regressions/3217-scoped-model-order.test.ts +104 -0
  935. package/.references/pi/packages/coding-agent/test/suite/regressions/3302-find-path-glob.test.ts +72 -0
  936. package/.references/pi/packages/coding-agent/test/suite/regressions/3303-find-nested-gitignore.test.ts +83 -0
  937. package/.references/pi/packages/coding-agent/test/suite/regressions/3317-network-connection-lost-retry.test.ts +33 -0
  938. package/.references/pi/packages/coding-agent/test/suite/regressions/3592-no-builtin-tools-keeps-extension-tools.test.ts +119 -0
  939. package/.references/pi/packages/coding-agent/test/suite/regressions/3616-settings-inmemory-reload.test.ts +86 -0
  940. package/.references/pi/packages/coding-agent/test/suite/regressions/3686-session-name-event.test.ts +61 -0
  941. package/.references/pi/packages/coding-agent/test/suite/regressions/3688-tree-cancel-compacting.test.ts +36 -0
  942. package/.references/pi/packages/coding-agent/test/suite/regressions/3982-message-end-cost-override.test.ts +56 -0
  943. package/.references/pi/packages/coding-agent/test/suite/regressions/4167-thinking-toggle-pending-tool-render.test.ts +182 -0
  944. package/.references/pi/packages/coding-agent/test/suite/regressions/5080-signal-shutdown-extension-cleanup.test.ts +185 -0
  945. package/.references/pi/packages/coding-agent/test/suite/regressions/5109-exclude-tools.test.ts +81 -0
  946. package/.references/pi/packages/coding-agent/test/suite/regressions/5208-late-bash-output.test.ts +29 -0
  947. package/.references/pi/packages/coding-agent/test/suite/regressions/5217-compaction-reason.test.ts +95 -0
  948. package/.references/pi/packages/coding-agent/test/suite/regressions/5303-bash-output-truncation.test.ts +79 -0
  949. package/.references/pi/packages/coding-agent/test/suite/regressions/5433-extension-oauth-prompt-input.test.ts +119 -0
  950. package/.references/pi/packages/coding-agent/test/suite/regressions/5596-missing-theme-export.test.ts +89 -0
  951. package/.references/pi/packages/coding-agent/test/suite/regressions/5661-uppercase-header-values.test.ts +91 -0
  952. package/.references/pi/packages/coding-agent/test/suite/regressions/5724-sigterm-signal-exit.test.ts +94 -0
  953. package/.references/pi/packages/coding-agent/test/suite/regressions/5868-rpc-unknown-command-id.test.ts +113 -0
  954. package/.references/pi/packages/coding-agent/test/suite/regressions/5943-session-start-notify.test.ts +515 -0
  955. package/.references/pi/packages/coding-agent/test/suite/regressions/5996-session-name-newlines.test.ts +40 -0
  956. package/.references/pi/packages/coding-agent/test/suite/regressions/6019-explicit-provider-retry-message.test.ts +31 -0
  957. package/.references/pi/packages/coding-agent/test/suite/regressions/6162-extension-active-tools-next-turn.test.ts +192 -0
  958. package/.references/pi/packages/coding-agent/test/suite/regressions/6260-inline-extension-naming.test.ts +99 -0
  959. package/.references/pi/packages/coding-agent/test/suite/regressions/6324-branch-summary-ambient-auth.test.ts +61 -0
  960. package/.references/pi/packages/coding-agent/test/suite/regressions/6363-agent-settled-event.test.ts +158 -0
  961. package/.references/pi/packages/coding-agent/test/suite/regressions/extension-factory-cache.test.ts +131 -0
  962. package/.references/pi/packages/coding-agent/test/suite/regressions/pre-prompt-compaction-no-continue.test.ts +75 -0
  963. package/.references/pi/packages/coding-agent/test/syntax-highlight.test.ts +76 -0
  964. package/.references/pi/packages/coding-agent/test/system-prompt.test.ts +114 -0
  965. package/.references/pi/packages/coding-agent/test/test-harness.test.ts +321 -0
  966. package/.references/pi/packages/coding-agent/test/test-harness.ts +463 -0
  967. package/.references/pi/packages/coding-agent/test/test-theme-colors.ts +246 -0
  968. package/.references/pi/packages/coding-agent/test/theme-detection.test.ts +133 -0
  969. package/.references/pi/packages/coding-agent/test/theme-export.test.ts +104 -0
  970. package/.references/pi/packages/coding-agent/test/theme-picker.test.ts +51 -0
  971. package/.references/pi/packages/coding-agent/test/tool-execution-component.test.ts +529 -0
  972. package/.references/pi/packages/coding-agent/test/tools.test.ts +1213 -0
  973. package/.references/pi/packages/coding-agent/test/tree-selector.test.ts +702 -0
  974. package/.references/pi/packages/coding-agent/test/trigger-compact-extension.test.ts +59 -0
  975. package/.references/pi/packages/coding-agent/test/truncate-to-width.test.ts +81 -0
  976. package/.references/pi/packages/coding-agent/test/trust-manager.test.ts +67 -0
  977. package/.references/pi/packages/coding-agent/test/trust-selector.test.ts +87 -0
  978. package/.references/pi/packages/coding-agent/test/user-message.test.ts +25 -0
  979. package/.references/pi/packages/coding-agent/test/utilities.ts +318 -0
  980. package/.references/pi/packages/coding-agent/test/version-check.test.ts +91 -0
  981. package/.references/pi/packages/coding-agent/tsconfig.build.json +17 -0
  982. package/.references/pi/packages/coding-agent/tsconfig.examples.json +16 -0
  983. package/.references/pi/packages/coding-agent/vitest.config.ts +38 -0
  984. package/.references/pi/packages/orchestrator/CHANGELOG.md +19 -0
  985. package/.references/pi/packages/orchestrator/README.md +11 -0
  986. package/.references/pi/packages/orchestrator/package.json +45 -0
  987. package/.references/pi/packages/orchestrator/src/cli.ts +161 -0
  988. package/.references/pi/packages/orchestrator/src/config.ts +69 -0
  989. package/.references/pi/packages/orchestrator/src/handler.ts +161 -0
  990. package/.references/pi/packages/orchestrator/src/index.ts +10 -0
  991. package/.references/pi/packages/orchestrator/src/ipc/client.ts +63 -0
  992. package/.references/pi/packages/orchestrator/src/ipc/protocol.ts +142 -0
  993. package/.references/pi/packages/orchestrator/src/ipc/server.ts +209 -0
  994. package/.references/pi/packages/orchestrator/src/radius.ts +440 -0
  995. package/.references/pi/packages/orchestrator/src/rpc-process.ts +201 -0
  996. package/.references/pi/packages/orchestrator/src/serve.ts +77 -0
  997. package/.references/pi/packages/orchestrator/src/storage.ts +70 -0
  998. package/.references/pi/packages/orchestrator/src/supervisor.ts +354 -0
  999. package/.references/pi/packages/orchestrator/src/types.ts +25 -0
  1000. package/.references/pi/packages/orchestrator/tsconfig.build.json +9 -0
  1001. package/.references/pi/packages/tui/CHANGELOG.md +1005 -0
  1002. package/.references/pi/packages/tui/README.md +791 -0
  1003. package/.references/pi/packages/tui/native/darwin/prebuilds/darwin-arm64/darwin-modifiers.node +0 -0
  1004. package/.references/pi/packages/tui/native/darwin/prebuilds/darwin-x64/darwin-modifiers.node +0 -0
  1005. package/.references/pi/packages/tui/native/darwin/src/darwin-modifiers.c +70 -0
  1006. package/.references/pi/packages/tui/native/win32/prebuilds/win32-arm64/win32-console-mode.node +0 -0
  1007. package/.references/pi/packages/tui/native/win32/prebuilds/win32-x64/win32-console-mode.node +0 -0
  1008. package/.references/pi/packages/tui/native/win32/src/win32-console-mode.c +53 -0
  1009. package/.references/pi/packages/tui/package.json +47 -0
  1010. package/.references/pi/packages/tui/src/autocomplete.ts +786 -0
  1011. package/.references/pi/packages/tui/src/components/box.ts +137 -0
  1012. package/.references/pi/packages/tui/src/components/cancellable-loader.ts +40 -0
  1013. package/.references/pi/packages/tui/src/components/editor.ts +2333 -0
  1014. package/.references/pi/packages/tui/src/components/image.ts +126 -0
  1015. package/.references/pi/packages/tui/src/components/input.ts +447 -0
  1016. package/.references/pi/packages/tui/src/components/loader.ts +92 -0
  1017. package/.references/pi/packages/tui/src/components/markdown.ts +858 -0
  1018. package/.references/pi/packages/tui/src/components/select-list.ts +229 -0
  1019. package/.references/pi/packages/tui/src/components/settings-list.ts +250 -0
  1020. package/.references/pi/packages/tui/src/components/spacer.ts +28 -0
  1021. package/.references/pi/packages/tui/src/components/text.ts +106 -0
  1022. package/.references/pi/packages/tui/src/components/truncated-text.ts +65 -0
  1023. package/.references/pi/packages/tui/src/editor-component.ts +74 -0
  1024. package/.references/pi/packages/tui/src/fuzzy.ts +137 -0
  1025. package/.references/pi/packages/tui/src/index.ts +114 -0
  1026. package/.references/pi/packages/tui/src/keybindings.ts +244 -0
  1027. package/.references/pi/packages/tui/src/keys.ts +1401 -0
  1028. package/.references/pi/packages/tui/src/kill-ring.ts +46 -0
  1029. package/.references/pi/packages/tui/src/native-modifiers.ts +59 -0
  1030. package/.references/pi/packages/tui/src/stdin-buffer.ts +434 -0
  1031. package/.references/pi/packages/tui/src/terminal-colors.ts +73 -0
  1032. package/.references/pi/packages/tui/src/terminal-image.ts +488 -0
  1033. package/.references/pi/packages/tui/src/terminal.ts +531 -0
  1034. package/.references/pi/packages/tui/src/tui.ts +1714 -0
  1035. package/.references/pi/packages/tui/src/undo-stack.ts +28 -0
  1036. package/.references/pi/packages/tui/src/utils.ts +1209 -0
  1037. package/.references/pi/packages/tui/src/word-navigation.ts +117 -0
  1038. package/.references/pi/packages/tui/test/autocomplete.test.ts +542 -0
  1039. package/.references/pi/packages/tui/test/bug-regression-isimageline-startswith-bug.test.ts +237 -0
  1040. package/.references/pi/packages/tui/test/chat-simple.ts +129 -0
  1041. package/.references/pi/packages/tui/test/editor.test.ts +4051 -0
  1042. package/.references/pi/packages/tui/test/fuzzy.test.ts +112 -0
  1043. package/.references/pi/packages/tui/test/image-test.ts +56 -0
  1044. package/.references/pi/packages/tui/test/input.test.ts +647 -0
  1045. package/.references/pi/packages/tui/test/key-tester.ts +123 -0
  1046. package/.references/pi/packages/tui/test/keybindings.test.ts +46 -0
  1047. package/.references/pi/packages/tui/test/keys.test.ts +622 -0
  1048. package/.references/pi/packages/tui/test/markdown.test.ts +1442 -0
  1049. package/.references/pi/packages/tui/test/overlay-non-capturing.test.ts +1202 -0
  1050. package/.references/pi/packages/tui/test/overlay-options.test.ts +541 -0
  1051. package/.references/pi/packages/tui/test/overlay-short-content.test.ts +61 -0
  1052. package/.references/pi/packages/tui/test/regression-overlay-cjk-boundary.test.ts +68 -0
  1053. package/.references/pi/packages/tui/test/regression-regional-indicator-width.test.ts +52 -0
  1054. package/.references/pi/packages/tui/test/select-list.test.ts +116 -0
  1055. package/.references/pi/packages/tui/test/stdin-buffer.test.ts +458 -0
  1056. package/.references/pi/packages/tui/test/tab-width.test.ts +87 -0
  1057. package/.references/pi/packages/tui/test/terminal-colors.test.ts +249 -0
  1058. package/.references/pi/packages/tui/test/terminal-image.test.ts +492 -0
  1059. package/.references/pi/packages/tui/test/terminal.test.ts +233 -0
  1060. package/.references/pi/packages/tui/test/test-themes.ts +38 -0
  1061. package/.references/pi/packages/tui/test/truncate-to-width.test.ts +76 -0
  1062. package/.references/pi/packages/tui/test/truncated-text.test.ts +129 -0
  1063. package/.references/pi/packages/tui/test/tui-cell-size-input.test.ts +81 -0
  1064. package/.references/pi/packages/tui/test/tui-overlay-style-leak.test.ts +80 -0
  1065. package/.references/pi/packages/tui/test/tui-render.test.ts +767 -0
  1066. package/.references/pi/packages/tui/test/tui-shrink.test.ts +44 -0
  1067. package/.references/pi/packages/tui/test/viewport-overwrite-repro.ts +106 -0
  1068. package/.references/pi/packages/tui/test/virtual-terminal.ts +218 -0
  1069. package/.references/pi/packages/tui/test/word-navigation.test.ts +191 -0
  1070. package/.references/pi/packages/tui/test/wrap-ansi.test.ts +266 -0
  1071. package/.references/pi/packages/tui/tsconfig.build.json +9 -0
  1072. package/.references/pi/packages/tui/vitest.config.ts +7 -0
  1073. package/.references/pi/pi-test.bat +14 -0
  1074. package/.references/pi/pi-test.ps1 +71 -0
  1075. package/.references/pi/pi-test.sh +57 -0
  1076. package/.references/pi/scripts/browser-smoke-entry.ts +61 -0
  1077. package/.references/pi/scripts/build-binaries.sh +245 -0
  1078. package/.references/pi/scripts/check-browser-smoke.mjs +36 -0
  1079. package/.references/pi/scripts/check-lockfile-commit.mjs +120 -0
  1080. package/.references/pi/scripts/check-pinned-deps.mjs +63 -0
  1081. package/.references/pi/scripts/check-ts-relative-imports.mjs +74 -0
  1082. package/.references/pi/scripts/cost.ts +183 -0
  1083. package/.references/pi/scripts/edit-tool-stats.mjs +834 -0
  1084. package/.references/pi/scripts/generate-coding-agent-install-lock.mjs +439 -0
  1085. package/.references/pi/scripts/generate-coding-agent-shrinkwrap.mjs +365 -0
  1086. package/.references/pi/scripts/local-release.mjs +284 -0
  1087. package/.references/pi/scripts/profile-coding-agent-node.mjs +639 -0
  1088. package/.references/pi/scripts/publish-model-catalog.mjs +295 -0
  1089. package/.references/pi/scripts/publish.mjs +125 -0
  1090. package/.references/pi/scripts/read-tool-stats.mjs +505 -0
  1091. package/.references/pi/scripts/release-notes.mjs +364 -0
  1092. package/.references/pi/scripts/release.mjs +207 -0
  1093. package/.references/pi/scripts/repro-5893-wsl-bash.mjs +55 -0
  1094. package/.references/pi/scripts/session-context-stats.mjs +405 -0
  1095. package/.references/pi/scripts/session-transcripts.ts +406 -0
  1096. package/.references/pi/scripts/stats.ts +233 -0
  1097. package/.references/pi/scripts/sync-versions.js +96 -0
  1098. package/.references/pi/scripts/tool-stats.ts +232 -0
  1099. package/.references/pi/scripts/update-source-imports-to-ts.sh +10 -0
  1100. package/.references/pi/test.sh +81 -0
  1101. package/.references/pi/tsconfig.base.json +25 -0
  1102. package/.references/pi/tsconfig.json +27 -0
  1103. package/AGENTS.md +8 -0
  1104. package/Cargo.lock +5169 -0
  1105. package/Cargo.toml +39 -0
  1106. package/LICENSE +21 -0
  1107. package/README.md +43 -0
  1108. package/aliases/pi-rusty/Cargo.toml +19 -0
  1109. package/aliases/pi-rusty/LICENSE +21 -0
  1110. package/aliases/pi-rusty/README.md +10 -0
  1111. package/aliases/pi-rusty/src/main.rs +8 -0
  1112. package/bun.lock +687 -0
  1113. package/crates/pi/Cargo.toml +66 -0
  1114. package/crates/pi/LICENSE +21 -0
  1115. package/crates/pi/assets/export-html/template.css +1066 -0
  1116. package/crates/pi/assets/export-html/template.html +55 -0
  1117. package/crates/pi/assets/export-html/template.js +1864 -0
  1118. package/crates/pi/assets/export-html/vendor/dark.json +29 -0
  1119. package/crates/pi/assets/export-html/vendor/highlight.min.js +1213 -0
  1120. package/crates/pi/assets/export-html/vendor/light.json +6 -0
  1121. package/crates/pi/assets/export-html/vendor/marked.min.js +78 -0
  1122. package/crates/pi/src/cli/args.rs +889 -0
  1123. package/crates/pi/src/cli/bootstrap.rs +2134 -0
  1124. package/crates/pi/src/cli/entry.rs +1332 -0
  1125. package/crates/pi/src/cli/help.rs +326 -0
  1126. package/crates/pi/src/cli/mod.rs +22 -0
  1127. package/crates/pi/src/cli/package_manager_cli.rs +1515 -0
  1128. package/crates/pi/src/core/agent_session/bash.rs +453 -0
  1129. package/crates/pi/src/core/agent_session/compaction.rs +1804 -0
  1130. package/crates/pi/src/core/agent_session/events.rs +621 -0
  1131. package/crates/pi/src/core/agent_session/extension.rs +2146 -0
  1132. package/crates/pi/src/core/agent_session/extension_runner.rs +471 -0
  1133. package/crates/pi/src/core/agent_session/mod.rs +1768 -0
  1134. package/crates/pi/src/core/agent_session/model.rs +775 -0
  1135. package/crates/pi/src/core/agent_session/persistence.rs +265 -0
  1136. package/crates/pi/src/core/agent_session/prompt.rs +2289 -0
  1137. package/crates/pi/src/core/agent_session/retry.rs +448 -0
  1138. package/crates/pi/src/core/agent_session/stats.rs +302 -0
  1139. package/crates/pi/src/core/agent_session/subscribe.rs +450 -0
  1140. package/crates/pi/src/core/agent_session/tools.rs +515 -0
  1141. package/crates/pi/src/core/agent_session/tree.rs +1219 -0
  1142. package/crates/pi/src/core/agent_session_runtime.rs +1612 -0
  1143. package/crates/pi/src/core/agent_session_services.rs +1613 -0
  1144. package/crates/pi/src/core/compaction/branch.rs +767 -0
  1145. package/crates/pi/src/core/compaction/mod.rs +1955 -0
  1146. package/crates/pi/src/core/compaction/utils.rs +357 -0
  1147. package/crates/pi/src/core/config.rs +1102 -0
  1148. package/crates/pi/src/core/config_value.rs +179 -0
  1149. package/crates/pi/src/core/experimental.rs +29 -0
  1150. package/crates/pi/src/core/export_html/ansi_to_html.rs +279 -0
  1151. package/crates/pi/src/core/export_html/mod.rs +787 -0
  1152. package/crates/pi/src/core/export_html/session_data.rs +149 -0
  1153. package/crates/pi/src/core/extension_host/acquire/tests.rs +579 -0
  1154. package/crates/pi/src/core/extension_host/acquire.rs +431 -0
  1155. package/crates/pi/src/core/extension_host/tests.rs +2353 -0
  1156. package/crates/pi/src/core/extension_host.rs +2541 -0
  1157. package/crates/pi/src/core/lockfile.rs +913 -0
  1158. package/crates/pi/src/core/messages.rs +706 -0
  1159. package/crates/pi/src/core/migrations.rs +828 -0
  1160. package/crates/pi/src/core/mod.rs +28 -0
  1161. package/crates/pi/src/core/model_resolver.rs +1473 -0
  1162. package/crates/pi/src/core/model_runtime.rs +2720 -0
  1163. package/crates/pi/src/core/output_guard.rs +977 -0
  1164. package/crates/pi/src/core/package_manager/tests.rs +1304 -0
  1165. package/crates/pi/src/core/package_manager.rs +2015 -0
  1166. package/crates/pi/src/core/platform/clipboard.rs +702 -0
  1167. package/crates/pi/src/core/platform/command.rs +223 -0
  1168. package/crates/pi/src/core/platform/debug_dump.rs +274 -0
  1169. package/crates/pi/src/core/platform/external_editor.rs +294 -0
  1170. package/crates/pi/src/core/platform/first_run.rs +120 -0
  1171. package/crates/pi/src/core/platform/image.rs +237 -0
  1172. package/crates/pi/src/core/platform/mod.rs +27 -0
  1173. package/crates/pi/src/core/platform/open_browser.rs +187 -0
  1174. package/crates/pi/src/core/platform/release_packaging.rs +785 -0
  1175. package/crates/pi/src/core/resources/diagnostics.rs +148 -0
  1176. package/crates/pi/src/core/resources/discovery.rs +2570 -0
  1177. package/crates/pi/src/core/resources/frontmatter.rs +205 -0
  1178. package/crates/pi/src/core/resources/mod.rs +1402 -0
  1179. package/crates/pi/src/core/resources/prompts.rs +510 -0
  1180. package/crates/pi/src/core/resources/skills.rs +981 -0
  1181. package/crates/pi/src/core/resources/slash.rs +199 -0
  1182. package/crates/pi/src/core/resources/source_info.rs +141 -0
  1183. package/crates/pi/src/core/resources/themes.rs +297 -0
  1184. package/crates/pi/src/core/session_transfer.rs +390 -0
  1185. package/crates/pi/src/core/sessions/context.rs +657 -0
  1186. package/crates/pi/src/core/sessions/cwd.rs +176 -0
  1187. package/crates/pi/src/core/sessions/entries.rs +1364 -0
  1188. package/crates/pi/src/core/sessions/list.rs +610 -0
  1189. package/crates/pi/src/core/sessions/mod.rs +2117 -0
  1190. package/crates/pi/src/core/settings.rs +3794 -0
  1191. package/crates/pi/src/core/share.rs +577 -0
  1192. package/crates/pi/src/core/system_prompt.rs +654 -0
  1193. package/crates/pi/src/core/tools/bash.rs +1574 -0
  1194. package/crates/pi/src/core/tools/edit.rs +919 -0
  1195. package/crates/pi/src/core/tools/edit_diff.rs +1150 -0
  1196. package/crates/pi/src/core/tools/find.rs +652 -0
  1197. package/crates/pi/src/core/tools/grep.rs +965 -0
  1198. package/crates/pi/src/core/tools/ls.rs +545 -0
  1199. package/crates/pi/src/core/tools/mod.rs +312 -0
  1200. package/crates/pi/src/core/tools/mutation_queue.rs +392 -0
  1201. package/crates/pi/src/core/tools/output_accumulator.rs +689 -0
  1202. package/crates/pi/src/core/tools/path_utils.rs +517 -0
  1203. package/crates/pi/src/core/tools/read.rs +1413 -0
  1204. package/crates/pi/src/core/tools/truncate.rs +644 -0
  1205. package/crates/pi/src/core/tools/write.rs +524 -0
  1206. package/crates/pi/src/core/trust.rs +1414 -0
  1207. package/crates/pi/src/core/update/changelog.rs +583 -0
  1208. package/crates/pi/src/core/update/deprecation.rs +148 -0
  1209. package/crates/pi/src/core/update/mod.rs +8 -0
  1210. package/crates/pi/src/core/update/self_update.rs +1327 -0
  1211. package/crates/pi/src/core/update/user_agent.rs +59 -0
  1212. package/crates/pi/src/core/update/version_check.rs +511 -0
  1213. package/crates/pi/src/core/update/windows_quarantine.rs +262 -0
  1214. package/crates/pi/src/lib.rs +23 -0
  1215. package/crates/pi/src/main.rs +13 -0
  1216. package/crates/pi/src/modes/interactive/footer.rs +260 -0
  1217. package/crates/pi/src/modes/interactive/header.rs +83 -0
  1218. package/crates/pi/src/modes/interactive/input.rs +923 -0
  1219. package/crates/pi/src/modes/interactive/messages.rs +640 -0
  1220. package/crates/pi/src/modes/interactive/mod.rs +51 -0
  1221. package/crates/pi/src/modes/interactive/progress.rs +181 -0
  1222. package/crates/pi/src/modes/interactive/runtime.rs +7227 -0
  1223. package/crates/pi/src/modes/interactive/selectors.rs +146 -0
  1224. package/crates/pi/src/modes/interactive/snapshots/pi__modes__interactive__tests__bash_state_widths.snap +138 -0
  1225. package/crates/pi/src/modes/interactive/snapshots/pi__modes__interactive__tests__compact_state_widths.snap +137 -0
  1226. package/crates/pi/src/modes/interactive/snapshots/pi__modes__interactive__tests__custom_branch_skill_messages.snap +145 -0
  1227. package/crates/pi/src/modes/interactive/snapshots/pi__modes__interactive__tests__empty_state_widths.snap +136 -0
  1228. package/crates/pi/src/modes/interactive/snapshots/pi__modes__interactive__tests__error_state_widths.snap +139 -0
  1229. package/crates/pi/src/modes/interactive/snapshots/pi__modes__interactive__tests__loading_state_widths.snap +136 -0
  1230. package/crates/pi/src/modes/interactive/snapshots/pi__modes__interactive__tests__queue_state_widths.snap +139 -0
  1231. package/crates/pi/src/modes/interactive/snapshots/pi__modes__interactive__tests__retry_state_widths.snap +136 -0
  1232. package/crates/pi/src/modes/interactive/snapshots/pi__modes__interactive__tests__streaming_state_widths.snap +137 -0
  1233. package/crates/pi/src/modes/interactive/snapshots/pi__modes__interactive__tests__user_assistant_messages.snap +145 -0
  1234. package/crates/pi/src/modes/interactive/startup.rs +194 -0
  1235. package/crates/pi/src/modes/interactive/state.rs +759 -0
  1236. package/crates/pi/src/modes/interactive/status.rs +70 -0
  1237. package/crates/pi/src/modes/interactive/tests.rs +945 -0
  1238. package/crates/pi/src/modes/interactive/theme.rs +1402 -0
  1239. package/crates/pi/src/modes/interactive/tool_renderer.rs +152 -0
  1240. package/crates/pi/src/modes/interactive/view.rs +511 -0
  1241. package/crates/pi/src/modes/mod.rs +6 -0
  1242. package/crates/pi/src/modes/print/input.rs +415 -0
  1243. package/crates/pi/src/modes/print/json.rs +195 -0
  1244. package/crates/pi/src/modes/print/mod.rs +403 -0
  1245. package/crates/pi/src/modes/print/text.rs +412 -0
  1246. package/crates/pi/src/modes/rpc/extension_ui.rs +361 -0
  1247. package/crates/pi/src/modes/rpc/jsonl.rs +429 -0
  1248. package/crates/pi/src/modes/rpc/mod.rs +19 -0
  1249. package/crates/pi/src/modes/rpc/mode_host.rs +466 -0
  1250. package/crates/pi/src/modes/rpc/server.rs +3037 -0
  1251. package/crates/pi/src/modes/rpc/types.rs +2999 -0
  1252. package/crates/pi/src/modes/run.rs +636 -0
  1253. package/crates/pi/tests/fixtures/fake_extension_host.rs +104 -0
  1254. package/crates/pi/tests/fixtures/tool-schemas/bash.json +16 -0
  1255. package/crates/pi/tests/fixtures/tool-schemas/edit.json +34 -0
  1256. package/crates/pi/tests/fixtures/tool-schemas/find.json +20 -0
  1257. package/crates/pi/tests/fixtures/tool-schemas/grep.json +36 -0
  1258. package/crates/pi/tests/fixtures/tool-schemas/ls.json +13 -0
  1259. package/crates/pi/tests/fixtures/tool-schemas/read.json +20 -0
  1260. package/crates/pi/tests/fixtures/tool-schemas/write.json +17 -0
  1261. package/crates/pi-agent/Cargo.toml +30 -0
  1262. package/crates/pi-agent/LICENSE +21 -0
  1263. package/crates/pi-agent/src/agent.rs +1780 -0
  1264. package/crates/pi-agent/src/bus.rs +770 -0
  1265. package/crates/pi-agent/src/config.rs +445 -0
  1266. package/crates/pi-agent/src/drain.rs +941 -0
  1267. package/crates/pi-agent/src/error.rs +61 -0
  1268. package/crates/pi-agent/src/event.rs +270 -0
  1269. package/crates/pi-agent/src/lib.rs +49 -0
  1270. package/crates/pi-agent/src/message.rs +296 -0
  1271. package/crates/pi-agent/src/queue.rs +222 -0
  1272. package/crates/pi-agent/src/run.rs +1870 -0
  1273. package/crates/pi-agent/src/schedule.rs +2153 -0
  1274. package/crates/pi-agent/src/state.rs +377 -0
  1275. package/crates/pi-agent/src/tool.rs +496 -0
  1276. package/crates/pi-ai/Cargo.toml +45 -0
  1277. package/crates/pi-ai/LICENSE +21 -0
  1278. package/crates/pi-ai/data/builtin-models.json +25193 -0
  1279. package/crates/pi-ai/src/auth/config_value.rs +598 -0
  1280. package/crates/pi-ai/src/auth/context.rs +215 -0
  1281. package/crates/pi-ai/src/auth/credential_store.rs +318 -0
  1282. package/crates/pi-ai/src/auth/env_keys.rs +647 -0
  1283. package/crates/pi-ai/src/auth/error.rs +194 -0
  1284. package/crates/pi-ai/src/auth/file_store.rs +1179 -0
  1285. package/crates/pi-ai/src/auth/http.rs +526 -0
  1286. package/crates/pi-ai/src/auth/mod.rs +29 -0
  1287. package/crates/pi-ai/src/auth/oauth/anthropic.rs +1482 -0
  1288. package/crates/pi-ai/src/auth/oauth/callback_server.rs +584 -0
  1289. package/crates/pi-ai/src/auth/oauth/device_code.rs +573 -0
  1290. package/crates/pi-ai/src/auth/oauth/github_copilot.rs +1527 -0
  1291. package/crates/pi-ai/src/auth/oauth/mod.rs +26 -0
  1292. package/crates/pi-ai/src/auth/oauth/openai_codex.rs +2005 -0
  1293. package/crates/pi-ai/src/auth/oauth/page.rs +159 -0
  1294. package/crates/pi-ai/src/auth/oauth/pkce.rs +145 -0
  1295. package/crates/pi-ai/src/auth/oauth/radius.rs +1685 -0
  1296. package/crates/pi-ai/src/auth/oauth/xai.rs +989 -0
  1297. package/crates/pi-ai/src/auth/resolve.rs +701 -0
  1298. package/crates/pi-ai/src/auth/runtime_credentials.rs +226 -0
  1299. package/crates/pi-ai/src/auth/types.rs +534 -0
  1300. package/crates/pi-ai/src/catalog/merge.rs +316 -0
  1301. package/crates/pi-ai/src/catalog/mod.rs +485 -0
  1302. package/crates/pi-ai/src/lib.rs +13 -0
  1303. package/crates/pi-ai/src/models_store.rs +974 -0
  1304. package/crates/pi-ai/src/provider.rs +285 -0
  1305. package/crates/pi-ai/src/providers/anthropic_messages.rs +1473 -0
  1306. package/crates/pi-ai/src/providers/azure_openai_responses.rs +559 -0
  1307. package/crates/pi-ai/src/providers/bedrock_converse_stream.rs +2430 -0
  1308. package/crates/pi-ai/src/providers/google_generative_ai.rs +622 -0
  1309. package/crates/pi-ai/src/providers/google_vertex.rs +1565 -0
  1310. package/crates/pi-ai/src/providers/mistral_conversations.rs +1245 -0
  1311. package/crates/pi-ai/src/providers/mod.rs +35 -0
  1312. package/crates/pi-ai/src/providers/openai_codex_responses.rs +2003 -0
  1313. package/crates/pi-ai/src/providers/openai_completions.rs +1873 -0
  1314. package/crates/pi-ai/src/providers/openai_responses.rs +757 -0
  1315. package/crates/pi-ai/src/providers/pi_messages.rs +1235 -0
  1316. package/crates/pi-ai/src/providers/registry.rs +923 -0
  1317. package/crates/pi-ai/src/providers/shared/google.rs +1193 -0
  1318. package/crates/pi-ai/src/providers/shared/responses.rs +1873 -0
  1319. package/crates/pi-ai/src/providers/shared.rs +671 -0
  1320. package/crates/pi-ai/src/providers/stream_state.rs +683 -0
  1321. package/crates/pi-ai/src/providers/transport.rs +488 -0
  1322. package/crates/pi-ai/src/text.rs +322 -0
  1323. package/crates/pi-ai/src/types.rs +1050 -0
  1324. package/crates/pi-ai/tests/conformance_anthropic_mistral.rs +664 -0
  1325. package/crates/pi-ai/tests/conformance_bedrock_pi_messages.rs +908 -0
  1326. package/crates/pi-ai/tests/conformance_codex.rs +815 -0
  1327. package/crates/pi-ai/tests/conformance_google.rs +743 -0
  1328. package/crates/pi-ai/tests/conformance_openai.rs +607 -0
  1329. package/crates/pi-ai/tests/fixtures/provenance/anthropic-sse-parsing.test.ts +275 -0
  1330. package/crates/pi-ai/tests/fixtures/provenance/mistral-reasoning-mode.test.ts +97 -0
  1331. package/crates/pi-ai/tests/fixtures/provenance/upstream/src/api/anthropic-messages.ts +1313 -0
  1332. package/crates/pi-ai/tests/fixtures/provenance/upstream/src/api/bedrock-converse-stream.ts +1091 -0
  1333. package/crates/pi-ai/tests/fixtures/provenance/upstream/src/api/google-generative-ai.ts +509 -0
  1334. package/crates/pi-ai/tests/fixtures/provenance/upstream/src/api/google-shared.ts +350 -0
  1335. package/crates/pi-ai/tests/fixtures/provenance/upstream/src/api/mistral-conversations.ts +664 -0
  1336. package/crates/pi-ai/tests/fixtures/provenance/upstream/src/api/openai-completions.ts +1355 -0
  1337. package/crates/pi-ai/tests/fixtures/provenance/upstream/src/api/openai-responses-shared.ts +613 -0
  1338. package/crates/pi-ai/tests/fixtures/provenance/upstream/src/api/openai-responses.ts +318 -0
  1339. package/crates/pi-ai/tests/fixtures/provenance/upstream/test/abort.test.ts +303 -0
  1340. package/crates/pi-ai/tests/fixtures/provenance/upstream/test/azure-openai-base-url.test.ts +175 -0
  1341. package/crates/pi-ai/tests/fixtures/provenance/upstream/test/bedrock-endpoint-resolution.test.ts +208 -0
  1342. package/crates/pi-ai/tests/fixtures/provenance/upstream/test/bedrock-thinking-payload.test.ts +246 -0
  1343. package/crates/pi-ai/tests/fixtures/provenance/upstream/test/google-vertex-api-key-resolution.test.ts +223 -0
  1344. package/crates/pi-ai/tests/fixtures/provenance/upstream/test/openai-codex-stream.test.ts +2028 -0
  1345. package/crates/pi-ai/tests/fixtures/provenance/upstream/test/openai-completions-prompt-cache.test.ts +264 -0
  1346. package/crates/pi-ai/tests/fixtures/provenance/upstream/test/openai-completions-retry.test.ts +86 -0
  1347. package/crates/pi-ai/tests/fixtures/provenance/upstream/test/openai-completions-thinking-as-text.test.ts +218 -0
  1348. package/crates/pi-ai/tests/fixtures/provenance/upstream/test/openai-completions-tool-choice.test.ts +1716 -0
  1349. package/crates/pi-ai/tests/fixtures/provenance/upstream/test/openai-responses-partial-json-cleanup.test.ts +106 -0
  1350. package/crates/pi-ai/tests/fixtures/provenance/upstream/test/openai-responses-terminal-event.test.ts +233 -0
  1351. package/crates/pi-ai/tests/fixtures/provenance/upstream/test/pi-messages.test.ts +243 -0
  1352. package/crates/pi-ai/tests/fixtures/provenance/upstream/test/provider-error-body-passthrough.test.ts +78 -0
  1353. package/crates/pi-ai/tests/fixtures/providers/anthropic-messages/cases.jsonl +4 -0
  1354. package/crates/pi-ai/tests/fixtures/providers/azure-openai-responses/cases.jsonl +2 -0
  1355. package/crates/pi-ai/tests/fixtures/providers/bedrock-converse-stream/cases.jsonl +8 -0
  1356. package/crates/pi-ai/tests/fixtures/providers/google-generative-ai/cases.jsonl +6 -0
  1357. package/crates/pi-ai/tests/fixtures/providers/google-vertex/cases.jsonl +6 -0
  1358. package/crates/pi-ai/tests/fixtures/providers/mistral-conversations/cases.jsonl +4 -0
  1359. package/crates/pi-ai/tests/fixtures/providers/openai-codex-responses/cases.jsonl +7 -0
  1360. package/crates/pi-ai/tests/fixtures/providers/openai-completions/cases.jsonl +9 -0
  1361. package/crates/pi-ai/tests/fixtures/providers/openai-responses/cases.jsonl +5 -0
  1362. package/crates/pi-ai/tests/fixtures/providers/pi-messages/cases.jsonl +8 -0
  1363. package/crates/pi-ai/tests/provider_registry_contract.rs +85 -0
  1364. package/crates/pi-ai/tests/support/golden.rs +191 -0
  1365. package/crates/pi-ai/tests/support/http.rs +525 -0
  1366. package/crates/pi-ai/tests/support/mod.rs +4 -0
  1367. package/crates/pi-ext/Cargo.toml +34 -0
  1368. package/crates/pi-ext/LICENSE +21 -0
  1369. package/crates/pi-ext/src/adapters.rs +1915 -0
  1370. package/crates/pi-ext/src/client.rs +1883 -0
  1371. package/crates/pi-ext/src/host.rs +318 -0
  1372. package/crates/pi-ext/src/lib.rs +10 -0
  1373. package/crates/pi-ext/src/protocol.rs +1880 -0
  1374. package/crates/pi-ext/src/sanitize.rs +524 -0
  1375. package/crates/pi-ext/src/test_support.rs +93 -0
  1376. package/crates/pi-ext/tests/fixtures/fake_jsonl_host.rs +35 -0
  1377. package/crates/pi-ext/tests/fixtures/protocol/frames.jsonl +30 -0
  1378. package/crates/pi-ext/tests/scaling.rs +530 -0
  1379. package/crates/pi-tui/Cargo.toml +56 -0
  1380. package/crates/pi-tui/LICENSE +21 -0
  1381. package/crates/pi-tui/src/bin/pi_tui_pty_fixture.rs +722 -0
  1382. package/crates/pi-tui/src/component.rs +101 -0
  1383. package/crates/pi-tui/src/components/editor/mod.rs +2626 -0
  1384. package/crates/pi-tui/src/components/editor/paste.rs +406 -0
  1385. package/crates/pi-tui/src/components/editor/state.rs +240 -0
  1386. package/crates/pi-tui/src/components/image.rs +352 -0
  1387. package/crates/pi-tui/src/components/input.rs +742 -0
  1388. package/crates/pi-tui/src/components/loader.rs +364 -0
  1389. package/crates/pi-tui/src/components/markdown.rs +1154 -0
  1390. package/crates/pi-tui/src/components/mod.rs +30 -0
  1391. package/crates/pi-tui/src/components/padded.rs +212 -0
  1392. package/crates/pi-tui/src/components/select_list.rs +464 -0
  1393. package/crates/pi-tui/src/components/settings_list.rs +597 -0
  1394. package/crates/pi-tui/src/components/spacer.rs +67 -0
  1395. package/crates/pi-tui/src/components/text.rs +225 -0
  1396. package/crates/pi-tui/src/components/truncated_text.rs +137 -0
  1397. package/crates/pi-tui/src/components/util.rs +324 -0
  1398. package/crates/pi-tui/src/editor_support/autocomplete.rs +1039 -0
  1399. package/crates/pi-tui/src/editor_support/history.rs +248 -0
  1400. package/crates/pi-tui/src/editor_support/kill_ring.rs +139 -0
  1401. package/crates/pi-tui/src/editor_support/mod.rs +29 -0
  1402. package/crates/pi-tui/src/editor_support/undo.rs +73 -0
  1403. package/crates/pi-tui/src/editor_support/word_nav.rs +412 -0
  1404. package/crates/pi-tui/src/editor_support/wrap.rs +317 -0
  1405. package/crates/pi-tui/src/focus.rs +564 -0
  1406. package/crates/pi-tui/src/frame.rs +163 -0
  1407. package/crates/pi-tui/src/fuzzy.rs +221 -0
  1408. package/crates/pi-tui/src/image.rs +749 -0
  1409. package/crates/pi-tui/src/keybindings.rs +602 -0
  1410. package/crates/pi-tui/src/keys.rs +1242 -0
  1411. package/crates/pi-tui/src/layout.rs +563 -0
  1412. package/crates/pi-tui/src/lib.rs +16 -0
  1413. package/crates/pi-tui/src/link.rs +408 -0
  1414. package/crates/pi-tui/src/overlay.rs +895 -0
  1415. package/crates/pi-tui/src/terminal/backend.rs +348 -0
  1416. package/crates/pi-tui/src/terminal/caps.rs +237 -0
  1417. package/crates/pi-tui/src/terminal/guard.rs +476 -0
  1418. package/crates/pi-tui/src/terminal/input.rs +266 -0
  1419. package/crates/pi-tui/src/terminal/mod.rs +31 -0
  1420. package/crates/pi-tui/src/terminal/probe.rs +498 -0
  1421. package/crates/pi-tui/src/terminal/sink.rs +128 -0
  1422. package/crates/pi-tui/src/terminal/writer.rs +1541 -0
  1423. package/crates/pi-tui/src/text/ansi.rs +415 -0
  1424. package/crates/pi-tui/src/text/mod.rs +29 -0
  1425. package/crates/pi-tui/src/text/slice.rs +645 -0
  1426. package/crates/pi-tui/src/text/tests.rs +359 -0
  1427. package/crates/pi-tui/src/text/width.rs +311 -0
  1428. package/crates/pi-tui/src/text/wrap.rs +344 -0
  1429. package/crates/pi-tui/tests/pty_no_flicker.rs +929 -0
  1430. package/deny.toml +38 -0
  1431. package/npm-package/bin/pi.js +31 -0
  1432. package/npm-package/package.json +35 -0
  1433. package/npm-package/tests/archive.test.ts +139 -0
  1434. package/npm-package/tests/wrapper.test.ts +70 -0
  1435. package/package.json +34 -0
  1436. package/packages/extension-host/bun.lock +664 -0
  1437. package/packages/extension-host/fixtures/extensions/all-events.ts +55 -0
  1438. package/packages/extension-host/fixtures/extensions/control-compat-shadow.ts +14 -0
  1439. package/packages/extension-host/fixtures/extensions/control-compat.ts +35 -0
  1440. package/packages/extension-host/fixtures/extensions/crash.ts +36 -0
  1441. package/packages/extension-host/fixtures/extensions/hooks.ts +45 -0
  1442. package/packages/extension-host/fixtures/extensions/hostile.ts +39 -0
  1443. package/packages/extension-host/fixtures/extensions/idle.ts +9 -0
  1444. package/packages/extension-host/fixtures/extensions/provider-stream.ts +121 -0
  1445. package/packages/extension-host/fixtures/extensions/terminal-input-fast.ts +20 -0
  1446. package/packages/extension-host/fixtures/extensions/terminal-input-slow.ts +23 -0
  1447. package/packages/extension-host/fixtures/extensions/tool-progress.ts +72 -0
  1448. package/packages/extension-host/fixtures/extensions/tool.ts +71 -0
  1449. package/packages/extension-host/fixtures/extensions/virtual-imports.ts +87 -0
  1450. package/packages/extension-host/fixtures/extensions/widget-active.ts +16 -0
  1451. package/packages/extension-host/fixtures/photon-probe.ts +45 -0
  1452. package/packages/extension-host/fixtures/runtime-import.ts +54 -0
  1453. package/packages/extension-host/package.json +54 -0
  1454. package/packages/extension-host/src/host.ts +1651 -0
  1455. package/packages/extension-host/src/index.ts +21 -0
  1456. package/packages/extension-host/src/main.ts +51 -0
  1457. package/packages/extension-host/src/protocol.ts +10 -0
  1458. package/packages/extension-host/src/refs.d.ts +364 -0
  1459. package/packages/extension-host/src/sanitize.ts +503 -0
  1460. package/packages/extension-host/src/virtual-modules.ts +90 -0
  1461. package/packages/extension-host/tests/acceptance.test.ts +1498 -0
  1462. package/packages/extension-host/tests/host.test.ts +244 -0
  1463. package/packages/extension-host/tests/sanitize.test.ts +359 -0
  1464. package/packages/extension-host/tests/scaling.test.ts +661 -0
  1465. package/packages/extension-host/tests/virtual-modules.test.ts +122 -0
  1466. package/packages/extension-host/tsconfig.build.json +44 -0
  1467. package/packages/extension-host/tsconfig.check.json +29 -0
  1468. package/packages/extension-host/tsconfig.json +8 -0
  1469. package/packages/pi-tui-protocol/package.json +41 -0
  1470. package/packages/pi-tui-protocol/src/client.ts +341 -0
  1471. package/packages/pi-tui-protocol/src/codec.ts +439 -0
  1472. package/packages/pi-tui-protocol/src/index.ts +77 -0
  1473. package/packages/pi-tui-protocol/src/types.ts +358 -0
  1474. package/packages/pi-tui-protocol/tests/client.test.ts +175 -0
  1475. package/packages/pi-tui-protocol/tests/codec.test.ts +196 -0
  1476. package/packages/pi-tui-protocol/tests/fixtures/frames.jsonl +30 -0
  1477. package/packages/pi-tui-protocol/tsconfig.build.json +23 -0
  1478. package/packages/pi-tui-protocol/tsconfig.json +9 -0
  1479. package/rust-toolchain.toml +3 -0
  1480. package/rustfmt.toml +5 -0
  1481. package/scripts/bench-extension-scaling.ts +466 -0
  1482. package/scripts/build-extension-host.ts +51 -0
  1483. package/scripts/generate-builtin-models.ts +344 -0
  1484. package/scripts/generate-session-fixtures.ts +1758 -0
  1485. package/scripts/generate-tool-schemas.ts +444 -0
  1486. package/scripts/package-npm.ts +263 -0
  1487. package/scripts/package-release.ts +422 -0
  1488. package/scripts/release/archive.ts +594 -0
  1489. package/scripts/release/args.ts +187 -0
  1490. package/scripts/release/extract-host-asset.ts +224 -0
  1491. package/scripts/release/host.ts +825 -0
  1492. package/scripts/release/runner.ts +435 -0
  1493. package/scripts/release/runtime.ts +130 -0
  1494. package/scripts/release/stage.ts +437 -0
  1495. package/scripts/release/targets.ts +150 -0
  1496. package/scripts/tests/archive.test.ts +210 -0
  1497. package/scripts/tests/args.test.ts +180 -0
  1498. package/scripts/tests/cli-dry-run.test.ts +61 -0
  1499. package/scripts/tests/compat-authority.test.ts +79 -0
  1500. package/scripts/tests/compat-matrix.test.ts +389 -0
  1501. package/scripts/tests/extract-host-asset.test.ts +176 -0
  1502. package/scripts/tests/host.test.ts +443 -0
  1503. package/scripts/tests/npm-installed-smoke.test.ts +104 -0
  1504. package/scripts/tests/package-release.test.ts +516 -0
  1505. package/scripts/tests/repro-guards.test.ts +241 -0
  1506. package/scripts/tests/runner.test.ts +188 -0
  1507. package/scripts/tests/stage.test.ts +232 -0
  1508. package/scripts/tests/targets.test.ts +93 -0
  1509. package/scripts/tsconfig.json +47 -0
  1510. package/scripts/verification/compat-matrix.json +455 -0
  1511. package/scripts/verification/compat-matrix.ts +632 -0
  1512. package/scripts/verification/e2e-smoke.ts +1093 -0
  1513. package/scripts/verification/extension.ts +339 -0
  1514. package/scripts/verification/foundation.test.ts +339 -0
  1515. package/scripts/verification/npm-installed-smoke.ts +117 -0
  1516. package/scripts/verification/performance.ts +1425 -0
  1517. package/scripts/verification/pty.ts +332 -0
@@ -0,0 +1,2541 @@
1
+ //! Product-side [`ExtensionRunner`] over the pi-ext [`HostClient`].
2
+ //!
3
+ //! The bundled TypeScript extension host owns the real `ExtensionRunner`
4
+ //! (the 15-hook merge table, mutable results, command dispatch, transform
5
+ //! chains). Rust is the validation boundary: it sends **one** event request
6
+ //! per hook and trusts only the validated typed response, converts the host's
7
+ //! registration snapshot into pi-ext tool/provider adapters, pumps unsolicited
8
+ //! tool/provider/uiSlot/error traffic into bounded typed subscribers, drops
9
+ //! stale generations, isolates every host failure as a single non-retryable
10
+ //! `extension_error`, and owns reload generation / slot invalidation /
11
+ //! exactly-once shutdown.
12
+ //!
13
+ //! See the authoritative `agent://ExtensionPlan` for the locked boundary
14
+ //! decisions. `AgentSession` never depends on `pi-ext` directly; it talks to
15
+ //! this runner through the [`ExtensionRunner`] trait seam defined in
16
+ //! [`super::agent_session::extension_runner`].
17
+
18
+ use std::collections::{BTreeMap, HashMap, HashSet};
19
+ use std::sync::atomic::{AtomicBool, AtomicU64, Ordering};
20
+ use std::sync::{Arc, Mutex as StdMutex, RwLock};
21
+ use std::time::Duration;
22
+
23
+ use futures::future::BoxFuture;
24
+ use pi_agent::{
25
+ AfterToolCallResult, AgentMessage, AgentTool, AgentToolResult, BeforeToolCallResult, ToolError,
26
+ ToolExecutionMode, ToolUpdates,
27
+ };
28
+ use pi_ai::{AssistantMessage, AssistantMessageEvent, ToolResultContent};
29
+ use pi_ext::adapters::{
30
+ self, CommandRegistration, ExtensionAgentTool, ExtensionProvider, FlagRegistration,
31
+ ProviderRegistration, Registry, RendererRegistration, ShortcutRegistration, ToolRegistration,
32
+ };
33
+ use pi_ext::client::{HostClient, HostClientError, HostEvent, HostUiRequest, HostUiResponse};
34
+ use pi_ext::host::{self, HostError, HostSpec};
35
+ use pi_ext::protocol::{
36
+ self, DisposeSlot, ExtensionErrorEvent, FlagValueWire, FlagsSetRequest, FlagsSetResponse,
37
+ NotifyRequest, ProviderEvent, ShortcutExecuteRequest, ShortcutExecuteResponse, ToolUpdate,
38
+ UiEventRequest, UiEventResponse, UiSlot,
39
+ };
40
+ use pi_ext::sanitize::{SanitizedSlot, sanitize_slot};
41
+ use serde::{Deserialize, Serialize};
42
+ use serde_json::{Map, Value};
43
+ use tokio::sync::{broadcast, mpsc, watch};
44
+ use tokio_util::sync::CancellationToken;
45
+
46
+ use super::agent_session::events::AgentSessionEvent;
47
+ use super::agent_session::extension_runner::{
48
+ BeforeAgentStartResult, CancelResult, ExtensionRunner, InputTransformResult,
49
+ };
50
+ use super::model_runtime::{
51
+ ModelRuntime, ModelRuntimeError, ProviderConfigInput, ProviderModelDefinition,
52
+ };
53
+ use super::resources::{ExtensionResourcePath, ResourceExtensionPaths};
54
+
55
+ /// Lifecycle hook deadline (control RPC).
56
+ pub const HOOK_TIMEOUT: Duration = Duration::from_secs(30);
57
+
58
+ /// Deadline for the `hello` handshake + extension load.
59
+ pub const START_TIMEOUT: Duration = Duration::from_secs(30);
60
+
61
+ /// Bounded capacity for the tool-update / provider-event / error broadcasts.
62
+ pub const EVENT_CHANNEL_CAPACITY: usize = 256;
63
+
64
+ /// Open method string: client requests the host's registration snapshot.
65
+ pub const LOAD_METHOD: &str = "extensions.load";
66
+
67
+ /// Open method string: dispatch a registered slash command.
68
+ pub const COMMAND_EXECUTE_METHOD: &str = "command.execute";
69
+ /// Private compact streaming update request. Extensions still observe `message_update`.
70
+ pub const MESSAGE_UPDATE_DELTA_METHOD: &str = "message_update_delta";
71
+
72
+ /// Open method string: render an extension tool call/result as HTML (export).
73
+ pub const TOOL_RENDER_HTML_METHOD: &str = "tool.renderHtml";
74
+
75
+ /// The 33 lifecycle event `type` discriminants mirrored from the reference
76
+ /// `ExtensionAPI.on()` overloads. The host reports which of these have at
77
+ /// least one handler; Rust gates IPC on that set.
78
+ pub const ALL_EVENT_TYPES: &[&str] = &[
79
+ "project_trust",
80
+ "resources_discover",
81
+ "session_start",
82
+ "session_info_changed",
83
+ "session_before_switch",
84
+ "session_before_fork",
85
+ "session_before_compact",
86
+ "session_compact",
87
+ "session_shutdown",
88
+ "session_before_tree",
89
+ "session_tree",
90
+ "context",
91
+ "before_provider_request",
92
+ "before_provider_headers",
93
+ "after_provider_response",
94
+ "before_agent_start",
95
+ "agent_start",
96
+ "agent_end",
97
+ "agent_settled",
98
+ "turn_start",
99
+ "turn_end",
100
+ "message_start",
101
+ "message_update",
102
+ "message_end",
103
+ "tool_execution_start",
104
+ "tool_execution_update",
105
+ "tool_execution_end",
106
+ "model_select",
107
+ "thinking_level_select",
108
+ "tool_call",
109
+ "tool_result",
110
+ "user_bash",
111
+ "input",
112
+ ];
113
+
114
+ /// Which phase of an extension tool to render as HTML.
115
+ #[derive(Clone, Copy, Debug, Eq, PartialEq)]
116
+ pub enum ToolRenderPhase {
117
+ /// Render the tool-call invocation (`renderCall`).
118
+ Call,
119
+ /// Render the tool-result payload (`renderResult`).
120
+ Result,
121
+ }
122
+
123
+ impl ToolRenderPhase {
124
+ const fn as_str(self) -> &'static str {
125
+ match self {
126
+ Self::Call => "call",
127
+ Self::Result => "result",
128
+ }
129
+ }
130
+ }
131
+
132
+ /// Sanitized extension UI activity delivered to an active product mode.
133
+ #[derive(Debug, Clone)]
134
+ pub enum ExtensionUiEvent {
135
+ /// Fire-and-forget notification.
136
+ Notify(NotifyRequest),
137
+ /// Sanitized keyed slot update.
138
+ Slot(SanitizedSlot),
139
+ /// Keyed slot disposal.
140
+ Dispose {
141
+ /// Stable extension widget key to remove.
142
+ key: String,
143
+ },
144
+ }
145
+
146
+ /// Failure while starting the extension host.
147
+ #[derive(Debug, thiserror::Error)]
148
+ pub enum HostStartError {
149
+ /// No host executable could be resolved.
150
+ #[error("extension host not available: {0}")]
151
+ Resolve(#[from] HostError),
152
+ /// Product-policy acquisition of the pinned host asset failed.
153
+ #[error("extension host unavailable: {0}")]
154
+ Acquire(#[source] acquire::HostAcquireError),
155
+ /// The host process could not be spawned.
156
+ #[error("extension host spawn failed: {0}")]
157
+ Spawn(String),
158
+ /// The `hello` handshake failed (version mismatch or transport).
159
+ #[error("extension host handshake failed: {0}")]
160
+ Handshake(String),
161
+ /// The registration snapshot could not be loaded or decoded.
162
+ #[error("extension host load failed: {0}")]
163
+ Load(String),
164
+ /// Validated flags could not be synchronized to the host.
165
+ #[error("extension host flag synchronization failed: {0}")]
166
+ FlagSync(String),
167
+ }
168
+
169
+ impl From<HostClientError> for HostStartError {
170
+ fn from(value: HostClientError) -> Self {
171
+ match value {
172
+ HostClientError::Spawn { message } => Self::Spawn(message),
173
+ HostClientError::Handshake { message } => Self::Handshake(message),
174
+ other => Self::Load(other.to_string()),
175
+ }
176
+ }
177
+ }
178
+
179
+ impl From<acquire::HostAcquireError> for HostStartError {
180
+ fn from(value: acquire::HostAcquireError) -> Self {
181
+ match value {
182
+ // Preserve the long-standing resolve diagnostic verbatim.
183
+ acquire::HostAcquireError::Resolution(error) => Self::Resolve(error),
184
+ other => Self::Acquire(other),
185
+ }
186
+ }
187
+ }
188
+
189
+ // ---------------------------------------------------------------------------
190
+ // Registration snapshot wire types (host → Rust load response)
191
+ // ---------------------------------------------------------------------------
192
+
193
+ #[derive(Serialize)]
194
+ #[serde(rename_all = "camelCase")]
195
+ struct ExtensionsLoadRequest<'a> {
196
+ extension_paths: &'a [String],
197
+ cwd: &'a str,
198
+ project_trusted: bool,
199
+ }
200
+
201
+ /// Wire form of [`ToolRegistration`] received from the host load response.
202
+ #[derive(Debug, Clone, Deserialize)]
203
+ #[serde(rename_all = "camelCase")]
204
+ struct ToolWire {
205
+ name: String,
206
+ #[serde(default)]
207
+ label: String,
208
+ #[serde(default)]
209
+ description: String,
210
+ #[serde(default)]
211
+ parameters: Value,
212
+ #[serde(default)]
213
+ execution_mode: Option<pi_agent::ToolExecutionMode>,
214
+ }
215
+
216
+ /// Wire form of [`CommandRegistration`].
217
+ #[derive(Debug, Clone, Deserialize)]
218
+ #[serde(rename_all = "camelCase")]
219
+ struct CommandWire {
220
+ name: String,
221
+ #[serde(default)]
222
+ description: Option<String>,
223
+ #[serde(default)]
224
+ source: Option<String>,
225
+ }
226
+
227
+ /// Wire form of [`ShortcutRegistration`].
228
+ #[derive(Debug, Clone, Deserialize)]
229
+ #[serde(rename_all = "camelCase")]
230
+ struct ShortcutWire {
231
+ key: String,
232
+ #[serde(default)]
233
+ description: Option<String>,
234
+ #[serde(default)]
235
+ extension_path: Option<String>,
236
+ }
237
+
238
+ /// Wire form of [`FlagRegistration`] with its current resolved value.
239
+ #[derive(Debug, Clone, Deserialize)]
240
+ #[serde(rename_all = "camelCase")]
241
+ struct FlagWire {
242
+ name: String,
243
+ #[serde(default)]
244
+ description: Option<String>,
245
+ #[serde(default, rename = "type")]
246
+ kind: Option<String>,
247
+ #[serde(default)]
248
+ default: Option<String>,
249
+ /// Currently resolved value (from CLI / settings), if any.
250
+ #[serde(default)]
251
+ value: Option<Value>,
252
+ #[serde(default)]
253
+ extension_path: Option<String>,
254
+ }
255
+
256
+ /// Wire form of [`RendererRegistration`].
257
+ #[derive(Debug, Clone, Deserialize)]
258
+ #[serde(rename_all = "camelCase")]
259
+ struct RendererWire {
260
+ #[serde(default, rename = "type")]
261
+ kind: Option<String>,
262
+ name: String,
263
+ }
264
+
265
+ /// Wire form of a host-registered custom provider.
266
+ ///
267
+ /// Matches the host's `buildRegistrySnapshot` camelCase payload: full
268
+ /// `ProviderConfig` fields plus a boolean `streamSimple` flag (the function
269
+ /// itself never crosses the wire; the host keeps it and Rust proxies via
270
+ /// [`ExtensionProvider`] when the flag is true).
271
+ #[derive(Debug, Clone, Deserialize)]
272
+ #[serde(rename_all = "camelCase")]
273
+ struct ProviderWire {
274
+ name: String,
275
+ /// Display name (`config.name` in TypeScript); wire key is `displayName`.
276
+ #[serde(default)]
277
+ display_name: Option<String>,
278
+ #[serde(default)]
279
+ base_url: Option<String>,
280
+ #[serde(default)]
281
+ api: Option<String>,
282
+ #[serde(default)]
283
+ api_key: Option<String>,
284
+ #[serde(default)]
285
+ headers: Option<BTreeMap<String, String>>,
286
+ #[serde(default)]
287
+ auth_header: Option<bool>,
288
+ #[serde(default)]
289
+ models: Option<Vec<ProviderModelDefinition>>,
290
+ /// `true` when the host holds a live `streamSimple` function for this provider.
291
+ #[serde(default)]
292
+ stream_simple: bool,
293
+ /// Optional extension path used in diagnostic messages when present.
294
+ #[serde(default)]
295
+ extension_path: Option<String>,
296
+ }
297
+
298
+ impl ProviderWire {
299
+ fn to_config_input(&self) -> ProviderConfigInput {
300
+ ProviderConfigInput {
301
+ name: self.display_name.clone(),
302
+ base_url: self.base_url.clone(),
303
+ api_key: self.api_key.clone(),
304
+ api: self.api.clone(),
305
+ headers: self.headers.clone(),
306
+ auth_header: self.auth_header,
307
+ models: self.models.clone(),
308
+ model_overrides: None,
309
+ oauth: None,
310
+ }
311
+ }
312
+ }
313
+
314
+ /// Full host registration snapshot returned by `extensions.load`.
315
+ #[derive(Debug, Clone, Default, Deserialize)]
316
+ #[serde(rename_all = "camelCase")]
317
+ pub struct RegistrySnapshotWire {
318
+ /// Registered extension tools (host already applied first-wins).
319
+ #[serde(default)]
320
+ tools: Vec<ToolWire>,
321
+ /// Registered slash commands.
322
+ #[serde(default)]
323
+ commands: Vec<CommandWire>,
324
+ /// Registered keyboard shortcuts.
325
+ #[serde(default)]
326
+ shortcuts: Vec<ShortcutWire>,
327
+ /// Registered CLI flags with current values.
328
+ #[serde(default)]
329
+ flags: Vec<FlagWire>,
330
+ /// Registered renderers (message / tool / widget).
331
+ #[serde(default)]
332
+ renderers: Vec<RendererWire>,
333
+ /// Registered custom providers.
334
+ #[serde(default)]
335
+ providers: Vec<ProviderWire>,
336
+ /// Lifecycle event types with at least one handler installed.
337
+ #[serde(default)]
338
+ handlers: Vec<String>,
339
+ /// Whether `ui.onTerminalInput` has at least one active handler.
340
+ #[serde(default)]
341
+ terminal_input: bool,
342
+ /// Number of extensions successfully loaded (host diagnostic field).
343
+ #[serde(default)]
344
+ extensions: Option<u64>,
345
+ /// Per-path load errors (sibling isolation).
346
+ #[serde(default)]
347
+ errors: Vec<LoadErrorWire>,
348
+ }
349
+
350
+ /// Per-extension load error from the host snapshot.
351
+ #[derive(Debug, Clone, Default, Deserialize)]
352
+ #[serde(rename_all = "camelCase")]
353
+ struct LoadErrorWire {
354
+ #[serde(default)]
355
+ path: Option<String>,
356
+ #[serde(default)]
357
+ error: Option<String>,
358
+ #[serde(default)]
359
+ message: Option<String>,
360
+ }
361
+
362
+ /// Built registry snapshot: pi-ext [`Registry`] plus ready tool/provider
363
+ /// adapters and the handler-presence set.
364
+ #[derive(Default)]
365
+ struct RegistrySnapshot {
366
+ /// Aggregate registrations (first-wins dedup applied on build).
367
+ registry: Registry,
368
+ /// Ordered, undeduplicated shortcut registrations for product last-wins resolution.
369
+ raw_shortcuts: Vec<ShortcutRegistration>,
370
+ /// Extension tool adapters keyed by tool name.
371
+ tools: HashMap<String, Arc<dyn AgentTool>>,
372
+ /// Lifecycle event types with at least one handler.
373
+ handlers: HashSet<String>,
374
+ /// Whether terminal input must be offered to the host before native dispatch.
375
+ terminal_input: bool,
376
+ /// Resolved flag values (host value if present, else default).
377
+ flag_values: HashMap<String, Value>,
378
+ /// Provider config inputs keyed by provider id (for `ModelRuntime` registration).
379
+ provider_configs: HashMap<String, ProviderConfigInput>,
380
+ /// Provider ids that expose a host-side `streamSimple` handler.
381
+ stream_provider_ids: HashSet<String>,
382
+ /// Optional extension path per provider (diagnostics).
383
+ provider_extension_paths: HashMap<String, String>,
384
+ /// Host-reported per-path load errors.
385
+ load_errors: Vec<(String, String)>,
386
+ }
387
+
388
+ fn build_snapshot(wire: RegistrySnapshotWire, client: &Arc<HostClient>) -> RegistrySnapshot {
389
+ let mut snapshot = RegistrySnapshot {
390
+ terminal_input: wire.terminal_input,
391
+ ..RegistrySnapshot::default()
392
+ };
393
+
394
+ for tool in wire.tools {
395
+ let meta = ToolRegistration {
396
+ name: tool.name.clone(),
397
+ label: tool.label,
398
+ description: tool.description,
399
+ parameters: tool.parameters,
400
+ execution_mode: tool.execution_mode,
401
+ };
402
+ // First registration wins (host already dedups; this is the Rust-side
403
+ // trust boundary for a duplicated name).
404
+ if snapshot.registry.register_tool(meta.clone()) {
405
+ let adapter = ExtensionAgentTool::new(meta, Arc::clone(client));
406
+ snapshot
407
+ .tools
408
+ .insert(adapter.name().to_owned(), Arc::new(adapter));
409
+ }
410
+ }
411
+
412
+ for command in wire.commands {
413
+ let _ = snapshot.registry.register_command(CommandRegistration {
414
+ name: command.name,
415
+ description: command.description,
416
+ source: command.source,
417
+ });
418
+ }
419
+
420
+ for shortcut in wire.shortcuts {
421
+ let registration = ShortcutRegistration {
422
+ key: shortcut.key,
423
+ description: shortcut.description,
424
+ extension_path: shortcut.extension_path,
425
+ };
426
+ snapshot.raw_shortcuts.push(registration.clone());
427
+ let _ = snapshot.registry.register_shortcut(registration);
428
+ }
429
+
430
+ for flag in wire.flags {
431
+ if snapshot.registry.register_flag(FlagRegistration {
432
+ name: flag.name.clone(),
433
+ description: flag.description,
434
+ kind: match flag.kind.as_deref() {
435
+ Some("boolean") => adapters::FlagKind::Boolean,
436
+ _ => adapters::FlagKind::String,
437
+ },
438
+ default: flag.default.clone(),
439
+ extension_path: flag.extension_path,
440
+ }) {
441
+ // First-wins: prefer the host-resolved value, fall back to default.
442
+ let value = flag
443
+ .value
444
+ .clone()
445
+ .or_else(|| flag.default.map(Value::String))
446
+ .unwrap_or_else(|| Value::String(String::new()));
447
+ snapshot.flag_values.insert(flag.name, value);
448
+ }
449
+ }
450
+
451
+ for renderer in wire.renderers {
452
+ let _ = snapshot.registry.register_renderer(RendererRegistration {
453
+ kind: match renderer.kind.as_deref() {
454
+ Some("tool") => adapters::RendererKind::Tool,
455
+ Some("widget") => adapters::RendererKind::Widget,
456
+ _ => adapters::RendererKind::Message,
457
+ },
458
+ name: renderer.name,
459
+ });
460
+ }
461
+
462
+ for provider in wire.providers {
463
+ let name = provider.name.clone();
464
+ let stream_simple = provider.stream_simple;
465
+ let extension_path = provider.extension_path.clone();
466
+ let config = provider.to_config_input();
467
+ if snapshot.registry.register_provider(ProviderRegistration {
468
+ name: name.clone(),
469
+ base_url: config.base_url.clone(),
470
+ api: config.api.clone(),
471
+ }) {
472
+ snapshot.provider_configs.insert(name.clone(), config);
473
+ if stream_simple {
474
+ snapshot.stream_provider_ids.insert(name.clone());
475
+ }
476
+ if let Some(path) = extension_path {
477
+ snapshot.provider_extension_paths.insert(name, path);
478
+ }
479
+ }
480
+ }
481
+
482
+ for err in wire.errors {
483
+ let path = err.path.unwrap_or_else(|| "<unknown>".to_owned());
484
+ let message = err
485
+ .error
486
+ .or(err.message)
487
+ .unwrap_or_else(|| "extension load failed".to_owned());
488
+ snapshot.load_errors.push((path, message));
489
+ }
490
+
491
+ snapshot.handlers = wire.handlers.into_iter().collect();
492
+ let _ = wire.extensions;
493
+ snapshot
494
+ }
495
+
496
+ // ---------------------------------------------------------------------------
497
+ // Hook response wire types (validated typed responses trusted by Rust)
498
+ // ---------------------------------------------------------------------------
499
+
500
+ #[derive(Debug, Clone, Deserialize)]
501
+ #[serde(rename_all = "camelCase")]
502
+ struct CancelWire {
503
+ #[serde(default)]
504
+ cancel: bool,
505
+ #[serde(default)]
506
+ reason: Option<String>,
507
+ }
508
+
509
+ #[derive(Debug, Clone, Deserialize)]
510
+ #[serde(rename_all = "camelCase")]
511
+ struct BeforeToolCallWire {
512
+ #[serde(default)]
513
+ block: bool,
514
+ #[serde(default)]
515
+ reason: Option<String>,
516
+ }
517
+
518
+ #[derive(Debug, Clone, Default, Deserialize)]
519
+ #[serde(rename_all = "camelCase")]
520
+ struct AfterToolCallWire {
521
+ #[serde(default)]
522
+ content: Option<Vec<ToolResultContent>>,
523
+ #[serde(default)]
524
+ details: Option<Value>,
525
+ #[serde(default)]
526
+ is_error: Option<bool>,
527
+ #[serde(default)]
528
+ terminate: Option<bool>,
529
+ }
530
+
531
+ #[derive(Debug, Clone, Deserialize)]
532
+ #[serde(tag = "action", rename_all = "camelCase")]
533
+ enum InputTransformWire {
534
+ Continue,
535
+ Transform {
536
+ text: String,
537
+ #[serde(default)]
538
+ images: Option<Value>,
539
+ },
540
+ Handled,
541
+ }
542
+
543
+ #[derive(Debug, Clone, Default, Deserialize)]
544
+ #[serde(rename_all = "camelCase")]
545
+ struct BeforeAgentStartWire {
546
+ #[serde(default)]
547
+ messages: Vec<AgentMessage>,
548
+ #[serde(default)]
549
+ system_prompt: Option<String>,
550
+ }
551
+ #[derive(Debug, Clone, Deserialize)]
552
+ #[serde(rename_all = "camelCase")]
553
+ struct ResourcePathWire {
554
+ path: String,
555
+ extension_path: String,
556
+ }
557
+
558
+ #[derive(Debug, Clone, Default, Deserialize)]
559
+ #[serde(rename_all = "camelCase")]
560
+ struct ResourcesDiscoverWire {
561
+ #[serde(default, rename = "skillPaths")]
562
+ skills: Option<Vec<ResourcePathWire>>,
563
+ #[serde(default, rename = "promptPaths")]
564
+ prompts: Option<Vec<ResourcePathWire>>,
565
+ #[serde(default, rename = "themePaths")]
566
+ themes: Option<Vec<ResourcePathWire>>,
567
+ }
568
+
569
+ #[derive(Debug, Clone, Default, Deserialize)]
570
+ struct MessageEndWire {
571
+ message: Option<AgentMessage>,
572
+ }
573
+
574
+ #[derive(Debug, Clone, Deserialize)]
575
+ #[serde(rename_all = "camelCase")]
576
+ struct CommandExecuteWire {
577
+ #[serde(default)]
578
+ ok: bool,
579
+ }
580
+
581
+ #[derive(Debug, Clone, Deserialize)]
582
+ #[serde(rename_all = "camelCase")]
583
+ struct ToolRenderHtmlWire {
584
+ #[serde(default)]
585
+ html: Option<String>,
586
+ }
587
+
588
+ // ---------------------------------------------------------------------------
589
+ // Runner
590
+ // ---------------------------------------------------------------------------
591
+
592
+ /// Slot subscription state: latest sanitized slot (or `None` when disposed).
593
+ type SlotWatch = watch::Sender<Option<SanitizedSlot>>;
594
+
595
+ /// Message shown when a hook/tool call targets a runner retired by a reload.
596
+ const RETIRED_MESSAGE: &str = "extension host retired by reload";
597
+
598
+ /// In-flight hook/tool traffic gate for the reload cutover.
599
+ ///
600
+ /// Every hook RPC and gated tool adapter holds a [`TrafficPermit`] for the
601
+ /// duration of its host round-trip. [`TrafficGate::close`] stops new
602
+ /// admissions and [`TrafficGate::drain`] waits until every held permit is
603
+ /// released, so a retired transport is reaped only after in-flight old-host
604
+ /// traffic has finished against the still-live client.
605
+ #[derive(Default)]
606
+ struct TrafficGate {
607
+ /// Permits currently held. `SeqCst` pairs with `closed` for the
608
+ /// admission-vs-drain handoff (increment-then-check vs close-then-read).
609
+ inflight: AtomicU64,
610
+ /// Set once the runner is retired; no new permits are granted.
611
+ closed: AtomicBool,
612
+ /// Notified whenever `inflight` returns to zero.
613
+ idle: tokio::sync::Notify,
614
+ }
615
+
616
+ impl TrafficGate {
617
+ /// Admit one host RPC, or `None` once the gate is closed.
618
+ fn enter(self: &Arc<Self>) -> Option<TrafficPermit> {
619
+ // Increment BEFORE the closed check: a drainer that stores `closed`
620
+ // and then observes `inflight == 0` can never miss this admission.
621
+ self.inflight.fetch_add(1, Ordering::SeqCst);
622
+ if self.closed.load(Ordering::SeqCst) {
623
+ self.release();
624
+ return None;
625
+ }
626
+ Some(TrafficPermit {
627
+ gate: Arc::clone(self),
628
+ })
629
+ }
630
+
631
+ fn release(&self) {
632
+ if self.inflight.fetch_sub(1, Ordering::SeqCst) == 1 {
633
+ self.idle.notify_waiters();
634
+ }
635
+ }
636
+
637
+ /// Stop admitting new traffic.
638
+ fn close(&self) {
639
+ self.closed.store(true, Ordering::SeqCst);
640
+ }
641
+
642
+ /// Wait until every held permit is released. Call after [`Self::close`].
643
+ async fn drain(&self) {
644
+ loop {
645
+ let idle = self.idle.notified();
646
+ tokio::pin!(idle);
647
+ idle.as_mut().enable();
648
+ if self.inflight.load(Ordering::SeqCst) == 0 {
649
+ return;
650
+ }
651
+ idle.await;
652
+ }
653
+ }
654
+ }
655
+
656
+ /// RAII admission token for one in-flight host RPC.
657
+ struct TrafficPermit {
658
+ gate: Arc<TrafficGate>,
659
+ }
660
+
661
+ impl Drop for TrafficPermit {
662
+ fn drop(&mut self) {
663
+ self.gate.release();
664
+ }
665
+ }
666
+
667
+ /// Host-backed tool adapter wrapped with the runner's [`TrafficGate`].
668
+ ///
669
+ /// A reload cutover drains in-flight executions before reaping the old
670
+ /// transport; calls arriving after retirement fail with a clean
671
+ /// [`ToolError`] instead of racing the dead client.
672
+ struct GatedHostTool {
673
+ delegate: Arc<dyn AgentTool>,
674
+ traffic: Arc<TrafficGate>,
675
+ }
676
+
677
+ impl AgentTool for GatedHostTool {
678
+ fn name(&self) -> &str {
679
+ self.delegate.name()
680
+ }
681
+
682
+ fn label(&self) -> &str {
683
+ self.delegate.label()
684
+ }
685
+
686
+ fn description(&self) -> &str {
687
+ self.delegate.description()
688
+ }
689
+
690
+ fn parameters(&self) -> &Value {
691
+ self.delegate.parameters()
692
+ }
693
+
694
+ fn execution_mode(&self) -> Option<ToolExecutionMode> {
695
+ self.delegate.execution_mode()
696
+ }
697
+
698
+ fn prepare_arguments(&self, raw: &Map<String, Value>) -> Result<Map<String, Value>, ToolError> {
699
+ self.delegate.prepare_arguments(raw)
700
+ }
701
+
702
+ fn validate_arguments(
703
+ &self,
704
+ args: &Map<String, Value>,
705
+ ) -> Result<Map<String, Value>, ToolError> {
706
+ self.delegate.validate_arguments(args)
707
+ }
708
+
709
+ fn prepare_and_validate_arguments(
710
+ &self,
711
+ raw: Map<String, Value>,
712
+ ) -> BoxFuture<'_, Result<Map<String, Value>, ToolError>> {
713
+ Box::pin(async move {
714
+ let Some(_permit) = self.traffic.enter() else {
715
+ return Err(ToolError::new(RETIRED_MESSAGE));
716
+ };
717
+ self.delegate.prepare_and_validate_arguments(raw).await
718
+ })
719
+ }
720
+
721
+ fn execute(
722
+ &self,
723
+ tool_call_id: &str,
724
+ args: Map<String, Value>,
725
+ cancel: CancellationToken,
726
+ updates: ToolUpdates,
727
+ ) -> BoxFuture<'static, Result<AgentToolResult, ToolError>> {
728
+ let delegate = Arc::clone(&self.delegate);
729
+ let traffic = Arc::clone(&self.traffic);
730
+ let tool_call_id = tool_call_id.to_owned();
731
+ Box::pin(async move {
732
+ let Some(_permit) = traffic.enter() else {
733
+ return Err(ToolError::new(RETIRED_MESSAGE));
734
+ };
735
+ delegate.execute(&tool_call_id, args, cancel, updates).await
736
+ })
737
+ }
738
+ }
739
+
740
+ struct Inner {
741
+ client: Arc<HostClient>,
742
+ snapshot: RwLock<RegistrySnapshot>,
743
+ flag_values: RwLock<HashMap<String, Value>>,
744
+ slots: RwLock<HashMap<String, SlotWatch>>,
745
+ tool_updates_tx: broadcast::Sender<ToolUpdate>,
746
+ provider_events_tx: broadcast::Sender<ProviderEvent>,
747
+ errors_tx: broadcast::Sender<ExtensionErrorEvent>,
748
+ ui_tx: broadcast::Sender<ExtensionUiEvent>,
749
+ ui_requests_tx: mpsc::Sender<HostUiRequest>,
750
+ ui_requests_rx: StdMutex<Option<mpsc::Receiver<HostUiRequest>>>,
751
+ ui_requests_claimed: AtomicBool,
752
+ /// Paths passed to `extensions.load` (restart reuses them).
753
+ extension_paths: Vec<String>,
754
+ /// Cwd passed to `extensions.load`.
755
+ load_cwd: String,
756
+ /// Project trust passed to `extensions.load` and preserved across restart.
757
+ project_trusted: bool,
758
+ /// Monotonic reload generation; bumps invalidate every active slot.
759
+ reload_generation: AtomicU64,
760
+ /// Host transport is gone (EOF / crash / protocol error). All hooks and
761
+ /// handler-presence queries short-circuit to no-ops once set.
762
+ disabled: AtomicBool,
763
+ /// Runner invalidated after session replacement (`/reload` / runtime swap).
764
+ stale: AtomicBool,
765
+ /// `shutdown` has completed at least once.
766
+ shutdown_done: AtomicBool,
767
+ /// Serializes shutdown so concurrent callers await the same completed reap.
768
+ shutdown_lock: tokio::sync::Mutex<()>,
769
+ /// Per-hook control-RPC deadline (`HOOK_TIMEOUT` in production; shorter in
770
+ /// tests to exercise the timeout path quickly).
771
+ hook_timeout: Duration,
772
+ /// Reload-cutover admission gate held across every hook/tool host RPC.
773
+ traffic: Arc<TrafficGate>,
774
+ }
775
+
776
+ impl Inner {
777
+ fn new(
778
+ client: Arc<HostClient>,
779
+ mut snapshot: RegistrySnapshot,
780
+ extension_paths: Vec<String>,
781
+ load_cwd: String,
782
+ project_trusted: bool,
783
+ hook_timeout: Duration,
784
+ ) -> Self {
785
+ let (tool_updates_tx, _) = broadcast::channel(EVENT_CHANNEL_CAPACITY);
786
+ let (provider_events_tx, _) = broadcast::channel(EVENT_CHANNEL_CAPACITY);
787
+ let (errors_tx, _) = broadcast::channel(EVENT_CHANNEL_CAPACITY);
788
+ let (ui_tx, _) = broadcast::channel(EVENT_CHANNEL_CAPACITY);
789
+ let (ui_requests_tx, ui_requests_rx) = mpsc::channel(EVENT_CHANNEL_CAPACITY);
790
+ let flag_values = snapshot.flag_values.clone();
791
+ let traffic = Arc::new(TrafficGate::default());
792
+ // Host-backed tool adapters participate in the reload-cutover drain:
793
+ // in-flight executions keep the old transport alive until they
794
+ // finish, and post-retirement calls fail cleanly.
795
+ snapshot.tools = snapshot
796
+ .tools
797
+ .into_iter()
798
+ .map(|(name, delegate)| {
799
+ let gated: Arc<dyn AgentTool> = Arc::new(GatedHostTool {
800
+ delegate,
801
+ traffic: Arc::clone(&traffic),
802
+ });
803
+ (name, gated)
804
+ })
805
+ .collect();
806
+ Self {
807
+ client,
808
+ snapshot: RwLock::new(snapshot),
809
+ flag_values: RwLock::new(flag_values),
810
+ slots: RwLock::new(HashMap::new()),
811
+ tool_updates_tx,
812
+ provider_events_tx,
813
+ errors_tx,
814
+ ui_tx,
815
+ ui_requests_tx,
816
+ ui_requests_rx: StdMutex::new(Some(ui_requests_rx)),
817
+ ui_requests_claimed: AtomicBool::new(false),
818
+ extension_paths,
819
+ load_cwd,
820
+ project_trusted,
821
+ reload_generation: AtomicU64::new(1),
822
+ disabled: AtomicBool::new(false),
823
+ stale: AtomicBool::new(false),
824
+ shutdown_done: AtomicBool::new(false),
825
+ shutdown_lock: tokio::sync::Mutex::new(()),
826
+ hook_timeout,
827
+ traffic,
828
+ }
829
+ }
830
+
831
+ fn has_handlers(&self, event: &str) -> bool {
832
+ if self.disabled.load(Ordering::Relaxed) || self.stale.load(Ordering::Relaxed) {
833
+ return false;
834
+ }
835
+ self.snapshot
836
+ .read()
837
+ .is_ok_and(|guard| guard.handlers.contains(event))
838
+ }
839
+
840
+ fn active(&self) -> bool {
841
+ !self.disabled.load(Ordering::Relaxed) && !self.stale.load(Ordering::Relaxed)
842
+ }
843
+
844
+ /// Whether a slash command named `name` is registered (handler-presence
845
+ /// and disabled/stale gates apply).
846
+ fn has_command(&self, name: &str) -> bool {
847
+ if !self.active() {
848
+ return false;
849
+ }
850
+ self.snapshot.read().is_ok_and(|guard| {
851
+ guard
852
+ .registry
853
+ .commands()
854
+ .iter()
855
+ .any(|command| command.name == name)
856
+ })
857
+ }
858
+
859
+ /// Send one hook request. Returns the validated response frame, or an
860
+ /// error when the host is gone / timed out / returned an error frame.
861
+ async fn hook_request(
862
+ &self,
863
+ method: &str,
864
+ payload: Value,
865
+ ) -> Result<protocol::Frame, HostClientError> {
866
+ let Some(_permit) = self.traffic.enter() else {
867
+ return Err(HostClientError::NotRunning);
868
+ };
869
+ if !self.active() {
870
+ return Err(HostClientError::NotRunning);
871
+ }
872
+ self.client
873
+ .request_raw(method, payload, self.hook_timeout)
874
+ .await
875
+ }
876
+
877
+ /// Map a transport failure to a single non-retryable `extension_error`,
878
+ /// publish it to subscribers, and flip the disabled flag on fatal
879
+ /// conditions. Never aborts the caller.
880
+ fn report_host_error(&self, err: &HostClientError) {
881
+ let fatal = matches!(
882
+ err,
883
+ HostClientError::Closed { .. }
884
+ | HostClientError::Protocol { .. }
885
+ | HostClientError::NotRunning
886
+ );
887
+ if fatal {
888
+ self.disabled.store(true, Ordering::Relaxed);
889
+ }
890
+ let event = ExtensionErrorEvent {
891
+ code: error_code(err).to_owned(),
892
+ message: err.to_string(),
893
+ retryable: false,
894
+ data: None,
895
+ };
896
+ let _ = self.errors_tx.send(event);
897
+ }
898
+
899
+ fn publish_error(&self, code: &str, message: &str, data: Option<Value>) {
900
+ let event = ExtensionErrorEvent {
901
+ code: code.to_owned(),
902
+ message: message.to_owned(),
903
+ retryable: false,
904
+ data,
905
+ };
906
+ let _ = self.errors_tx.send(event);
907
+ }
908
+
909
+ fn slot_send(&self, slot: SanitizedSlot) {
910
+ // Teardown must not be reanimated: after invalidate/shutdown a
911
+ // delayed in-flight slot would otherwise re-insert a watch entry.
912
+ // Both the active check AND the synchronous ui_tx publish run UNDER
913
+ // the slots lock, so they serialize against dispose_all_slots and a
914
+ // Slot event can never be published after the teardown Dispose.
915
+ let Ok(mut slots) = self.slots.write() else {
916
+ return;
917
+ };
918
+ if !self.active() {
919
+ return;
920
+ }
921
+ let sender = slots
922
+ .entry(slot.key.clone())
923
+ .or_insert_with(|| watch::channel(None).0);
924
+ let _ = sender.send(Some(slot.clone()));
925
+ let _ = self.ui_tx.send(ExtensionUiEvent::Slot(slot));
926
+ }
927
+
928
+ fn slot_dispose(&self, key: &str) {
929
+ // Same lock discipline as slot_send: watch update and public publish
930
+ // are one atomic step relative to teardown.
931
+ let Ok(mut slots) = self.slots.write() else {
932
+ return;
933
+ };
934
+ if !self.active() {
935
+ return;
936
+ }
937
+ if let Some(sender) = slots.get(key) {
938
+ let _ = sender.send(None);
939
+ }
940
+ slots.remove(key);
941
+ let _ = self.ui_tx.send(ExtensionUiEvent::Dispose {
942
+ key: key.to_owned(),
943
+ });
944
+ }
945
+
946
+ fn notify_send(&self, notification: NotifyRequest) {
947
+ // Same lock discipline as slot_send/slot_dispose: the active check
948
+ // and the synchronous publish serialize against teardown so a Notify
949
+ // can never land after the teardown Dispose.
950
+ let Ok(_slots) = self.slots.write() else {
951
+ return;
952
+ };
953
+ if !self.active() {
954
+ return;
955
+ }
956
+ let _ = self.ui_tx.send(ExtensionUiEvent::Notify(notification));
957
+ }
958
+
959
+ fn dispose_all_slots(&self) {
960
+ // Publishing the Dispose events while still holding the lock keeps
961
+ // Slot-before-teardown-Dispose ordering: any concurrent slot_send
962
+ // either published before we acquired the lock or is dropped by the
963
+ // inactive gate afterwards. `broadcast::Sender::send` never blocks.
964
+ let Ok(mut slots) = self.slots.write() else {
965
+ return;
966
+ };
967
+ for (key, sender) in slots.iter() {
968
+ let _ = sender.send(None);
969
+ let _ = self
970
+ .ui_tx
971
+ .send(ExtensionUiEvent::Dispose { key: key.clone() });
972
+ }
973
+ slots.clear();
974
+ }
975
+ }
976
+
977
+ fn error_code(err: &HostClientError) -> &'static str {
978
+ match err {
979
+ HostClientError::Handshake { .. } => "extension_handshake",
980
+ HostClientError::Timeout { .. } => "extension_timeout",
981
+ HostClientError::Cancelled { .. } => "extension_cancelled",
982
+ HostClientError::Closed { .. } => "extension_closed",
983
+ HostClientError::Protocol { .. } => "extension_protocol",
984
+ HostClientError::Remote { .. } => "extension_remote",
985
+ HostClientError::Spawn { .. } => "extension_spawn",
986
+ HostClientError::NotRunning => "extension_not_running",
987
+ HostClientError::Payload(_) => "extension_payload",
988
+ }
989
+ }
990
+
991
+ /// Product extension runner backed by a live pi-ext [`HostClient`].
992
+ ///
993
+ /// Construct with [`HostExtensionRunner::start`] (resolve + spawn) or
994
+ /// [`HostExtensionRunner::connect`] (pre-built client, used by tests and the
995
+ /// reload restart closure). All [`ExtensionRunner`] hooks send a single event
996
+ /// request and trust only the validated typed response; the host owns the
997
+ /// 15-hook merge. Host failures are isolated as a single non-retryable
998
+ /// `extension_error` and never abort the session.
999
+ pub struct HostExtensionRunner {
1000
+ inner: Arc<Inner>,
1001
+ }
1002
+
1003
+ impl HostExtensionRunner {
1004
+ /// Resolve, spawn, handshake, and load the host, returning a ready runner.
1005
+ ///
1006
+ /// # Errors
1007
+ ///
1008
+ /// Returns [`HostStartError::Resolve`] when no host executable is
1009
+ /// available, [`HostStartError::Spawn`] when the process cannot start,
1010
+ /// [`HostStartError::Handshake`] on version mismatch, or
1011
+ /// [`HostStartError::Load`] when the registration snapshot is unreadable.
1012
+ pub async fn start(extension_paths: Vec<String>) -> Result<Arc<Self>, HostStartError> {
1013
+ let spec = host::resolve_host()?;
1014
+ Self::spawn_from(&spec, extension_paths).await
1015
+ }
1016
+
1017
+ /// Spawn from an explicit [`HostSpec`], then bind.
1018
+ ///
1019
+ /// # Errors
1020
+ ///
1021
+ /// See [`HostExtensionRunner::start`].
1022
+ pub async fn spawn_from(
1023
+ spec: &HostSpec,
1024
+ extension_paths: Vec<String>,
1025
+ ) -> Result<Arc<Self>, HostStartError> {
1026
+ let client =
1027
+ Arc::new(HostClient::spawn(spec).map_err(|e| HostStartError::Spawn(e.to_string()))?);
1028
+ let startup = Self::connect(Arc::clone(&client), extension_paths).await;
1029
+ Self::finish_startup(&client, startup).await
1030
+ }
1031
+
1032
+ /// Bind a runner to a pre-built client: handshake, load, spawn the event
1033
+ /// pump. Used by [`start`](Self::start), the reload restart path, and the
1034
+ /// fake-host test harness.
1035
+ ///
1036
+ /// # Errors
1037
+ ///
1038
+ /// Returns [`HostStartError::Handshake`] or [`HostStartError::Load`].
1039
+ pub async fn connect(
1040
+ client: Arc<HostClient>,
1041
+ extension_paths: Vec<String>,
1042
+ ) -> Result<Arc<Self>, HostStartError> {
1043
+ Self::connect_with_timeout(client, extension_paths, HOOK_TIMEOUT).await
1044
+ }
1045
+
1046
+ /// Bind a runner with a custom hook timeout (test harness; production uses
1047
+ /// [`connect`](Self::connect) which applies [`HOOK_TIMEOUT`]).
1048
+ ///
1049
+ /// # Errors
1050
+ ///
1051
+ /// Returns [`HostStartError::Handshake`] or [`HostStartError::Load`].
1052
+ pub async fn connect_with_timeout(
1053
+ client: Arc<HostClient>,
1054
+ extension_paths: Vec<String>,
1055
+ hook_timeout: Duration,
1056
+ ) -> Result<Arc<Self>, HostStartError> {
1057
+ let load_cwd = std::env::current_dir()
1058
+ .map(|p| p.to_string_lossy().into_owned())
1059
+ .unwrap_or_default();
1060
+ Self::connect_with_cwd_and_trust(client, extension_paths, load_cwd, false, hook_timeout)
1061
+ .await
1062
+ }
1063
+
1064
+ /// Bind a runner with an explicit load cwd (services factory / tests).
1065
+ ///
1066
+ /// # Errors
1067
+ ///
1068
+ /// Returns [`HostStartError::Handshake`] or [`HostStartError::Load`].
1069
+ pub async fn connect_with_cwd(
1070
+ client: Arc<HostClient>,
1071
+ extension_paths: Vec<String>,
1072
+ load_cwd: impl Into<String>,
1073
+ hook_timeout: Duration,
1074
+ ) -> Result<Arc<Self>, HostStartError> {
1075
+ Self::connect_with_cwd_and_trust(client, extension_paths, load_cwd, false, hook_timeout)
1076
+ .await
1077
+ }
1078
+
1079
+ /// Bind a runner with an explicit load cwd and project-trust value.
1080
+ ///
1081
+ /// # Errors
1082
+ ///
1083
+ /// Returns [`HostStartError::Handshake`] or [`HostStartError::Load`].
1084
+ pub async fn connect_with_cwd_and_trust(
1085
+ client: Arc<HostClient>,
1086
+ extension_paths: Vec<String>,
1087
+ load_cwd: impl Into<String>,
1088
+ project_trusted: bool,
1089
+ hook_timeout: Duration,
1090
+ ) -> Result<Arc<Self>, HostStartError> {
1091
+ client.handshake().await?;
1092
+ let load_cwd = load_cwd.into();
1093
+ let snapshot = Self::load(&client, &extension_paths, &load_cwd, project_trusted).await?;
1094
+ let inner = Arc::new(Inner::new(
1095
+ Arc::clone(&client),
1096
+ snapshot,
1097
+ extension_paths,
1098
+ load_cwd,
1099
+ project_trusted,
1100
+ hook_timeout,
1101
+ ));
1102
+ let runner = Arc::new(Self {
1103
+ inner: Arc::clone(&inner),
1104
+ });
1105
+ spawn_event_pump(inner);
1106
+ Ok(runner)
1107
+ }
1108
+
1109
+ async fn finish_startup(
1110
+ client: &HostClient,
1111
+ startup: Result<Arc<Self>, HostStartError>,
1112
+ ) -> Result<Arc<Self>, HostStartError> {
1113
+ if startup.is_err() {
1114
+ let _ = client.shutdown().await;
1115
+ }
1116
+ startup
1117
+ }
1118
+
1119
+ async fn load(
1120
+ client: &Arc<HostClient>,
1121
+ extension_paths: &[String],
1122
+ cwd: &str,
1123
+ project_trusted: bool,
1124
+ ) -> Result<RegistrySnapshot, HostStartError> {
1125
+ let payload = serde_json::to_value(ExtensionsLoadRequest {
1126
+ extension_paths,
1127
+ cwd,
1128
+ project_trusted,
1129
+ })
1130
+ .map_err(|error| HostStartError::Load(error.to_string()))?;
1131
+ let frame = client
1132
+ .request_raw(LOAD_METHOD, payload, START_TIMEOUT)
1133
+ .await?;
1134
+ let wire: RegistrySnapshotWire = serde_json::from_value(frame.payload)
1135
+ .map_err(|e| HostStartError::Load(e.to_string()))?;
1136
+ Ok(build_snapshot(wire, client))
1137
+ }
1138
+
1139
+ /// Borrowed host client (for provider registration by the model runtime).
1140
+ #[must_use]
1141
+ pub fn client(&self) -> &Arc<HostClient> {
1142
+ &self.inner.client
1143
+ }
1144
+
1145
+ /// Extension paths used for the current host load.
1146
+ #[must_use]
1147
+ pub fn extension_paths(&self) -> Vec<String> {
1148
+ self.inner.extension_paths.clone()
1149
+ }
1150
+
1151
+ /// Host-reported per-path load errors from the latest snapshot.
1152
+ #[must_use]
1153
+ pub fn load_errors(&self) -> Vec<(String, String)> {
1154
+ self.inner
1155
+ .snapshot
1156
+ .read()
1157
+ .map(|guard| guard.load_errors.clone())
1158
+ .unwrap_or_default()
1159
+ }
1160
+
1161
+ /// Registered provider config inputs keyed by provider id.
1162
+ #[must_use]
1163
+ pub fn provider_configs(&self) -> HashMap<String, ProviderConfigInput> {
1164
+ self.inner
1165
+ .snapshot
1166
+ .read()
1167
+ .map(|guard| guard.provider_configs.clone())
1168
+ .unwrap_or_default()
1169
+ }
1170
+
1171
+ /// Provider ids that expose a host-side `streamSimple` handler.
1172
+ #[must_use]
1173
+ pub fn stream_provider_ids(&self) -> HashSet<String> {
1174
+ self.inner
1175
+ .snapshot
1176
+ .read()
1177
+ .map(|guard| guard.stream_provider_ids.clone())
1178
+ .unwrap_or_default()
1179
+ }
1180
+
1181
+ /// Optional extension path per provider (diagnostics).
1182
+ #[must_use]
1183
+ pub fn provider_extension_paths(&self) -> HashMap<String, String> {
1184
+ self.inner
1185
+ .snapshot
1186
+ .read()
1187
+ .map(|guard| guard.provider_extension_paths.clone())
1188
+ .unwrap_or_default()
1189
+ }
1190
+
1191
+ /// Registered extension flags as name → type, for CLI validation.
1192
+ #[must_use]
1193
+ pub fn registered_flag_types(
1194
+ &self,
1195
+ ) -> BTreeMap<String, super::agent_session_services::ExtensionFlagType> {
1196
+ use super::agent_session_services::ExtensionFlagType;
1197
+ self.inner
1198
+ .snapshot
1199
+ .read()
1200
+ .map(|guard| {
1201
+ guard
1202
+ .registry
1203
+ .flags()
1204
+ .iter()
1205
+ .map(|flag| {
1206
+ let kind = match flag.kind {
1207
+ adapters::FlagKind::Boolean => ExtensionFlagType::Boolean,
1208
+ adapters::FlagKind::String => ExtensionFlagType::String,
1209
+ };
1210
+ (flag.name.clone(), kind)
1211
+ })
1212
+ .collect()
1213
+ })
1214
+ .unwrap_or_default()
1215
+ }
1216
+
1217
+ /// Registered extension provider adapters keyed by provider id, freshly
1218
+ /// bound to the live host client (callers register them with the model
1219
+ /// runtime). Rebuilt per call since [`ExtensionProvider`] is not `Clone`.
1220
+ ///
1221
+ /// Includes every host-registered provider. Custom-stream selection still
1222
+ /// requires `streamSimple: true` at registration time
1223
+ /// ([`Self::register_providers_on`]); baseURL-only providers stay native.
1224
+ #[must_use]
1225
+ pub fn providers(&self) -> HashMap<String, ExtensionProvider> {
1226
+ let client = Arc::clone(&self.inner.client);
1227
+ self.inner
1228
+ .snapshot
1229
+ .read()
1230
+ .map(|guard| {
1231
+ guard
1232
+ .registry
1233
+ .providers()
1234
+ .iter()
1235
+ .map(|provider| {
1236
+ (
1237
+ provider.name.clone(),
1238
+ ExtensionProvider::new(provider.name.clone(), Arc::clone(&client)),
1239
+ )
1240
+ })
1241
+ .collect()
1242
+ })
1243
+ .unwrap_or_default()
1244
+ }
1245
+
1246
+ /// Register this host's provider configs + stream adapters on `runtime`.
1247
+ ///
1248
+ /// Each provider failure becomes a diagnostic string; siblings continue.
1249
+ /// Stream handlers are registered only when `streamSimple` was true.
1250
+ #[must_use]
1251
+ pub fn register_providers_on(
1252
+ &self,
1253
+ runtime: &ModelRuntime,
1254
+ ) -> Vec<(String, Result<(), ModelRuntimeError>)> {
1255
+ let configs = self.provider_configs();
1256
+ let stream_ids = self.stream_provider_ids();
1257
+ let paths = self.provider_extension_paths();
1258
+ let mut results = Vec::with_capacity(configs.len());
1259
+ for (name, config) in configs {
1260
+ let path = paths.get(&name).cloned().unwrap_or_else(|| name.clone());
1261
+ let outcome = runtime.register_provider(&name, config);
1262
+ if outcome.is_ok() && stream_ids.contains(&name) {
1263
+ let adapter = ExtensionProvider::new(name.clone(), Arc::clone(self.client()));
1264
+ runtime.register_extension_stream_provider(name.clone(), Arc::new(adapter));
1265
+ }
1266
+ results.push((path, outcome));
1267
+ }
1268
+ results
1269
+ }
1270
+
1271
+ /// Unregister every provider currently owned by this runner from `runtime`.
1272
+ pub fn unregister_providers_from(&self, runtime: &ModelRuntime) {
1273
+ for name in self.provider_configs().keys() {
1274
+ runtime.unregister_provider(name);
1275
+ }
1276
+ }
1277
+
1278
+ /// Snapshot of the pi-ext [`Registry`] (tools/commands/shortcuts/flags/
1279
+ /// renderers/providers with first-wins dedup applied).
1280
+ #[must_use]
1281
+ pub fn registry(&self) -> Registry {
1282
+ self.inner
1283
+ .snapshot
1284
+ .read()
1285
+ .map(|guard| clone_registry(&guard.registry))
1286
+ .unwrap_or_default()
1287
+ }
1288
+
1289
+ /// Ordered, undeduplicated host shortcut registrations.
1290
+ ///
1291
+ /// Product code applies last-wins filtering after combining extension and native shortcuts.
1292
+ #[must_use]
1293
+ pub fn raw_shortcuts(&self) -> Vec<ShortcutRegistration> {
1294
+ self.inner
1295
+ .snapshot
1296
+ .read()
1297
+ .map(|guard| guard.raw_shortcuts.clone())
1298
+ .unwrap_or_default()
1299
+ }
1300
+
1301
+ /// Current reload generation (starts at 1, bumps on each reload).
1302
+ #[must_use]
1303
+ pub fn reload_generation(&self) -> u64 {
1304
+ self.inner.reload_generation.load(Ordering::Relaxed)
1305
+ }
1306
+
1307
+ /// Whether the host transport is still believed alive.
1308
+ #[must_use]
1309
+ pub fn is_running(&self) -> bool {
1310
+ self.inner.client.is_running() && !self.inner.disabled.load(Ordering::Relaxed)
1311
+ }
1312
+
1313
+ /// Synchronize a complete validated flag overlay with the host.
1314
+ ///
1315
+ /// The local flag snapshot is updated only after the host acknowledges the request.
1316
+ ///
1317
+ /// # Errors
1318
+ ///
1319
+ /// Returns [`HostClientError::Payload`] when the request or response payload
1320
+ /// cannot be (de)serialized, or when the host rejects the overlay
1321
+ /// (`ok == false`). Propagates the transport-level error from
1322
+ /// [`hook_request`](HostClientInner::hook_request) otherwise:
1323
+ /// [`HostClientError::NotRunning`] when the host is down, and
1324
+ /// [`HostClientError::Timeout`], [`HostClientError::Closed`], or
1325
+ /// [`HostClientError::Remote`] on transport failure.
1326
+ pub async fn apply_flag_values(
1327
+ &self,
1328
+ values: &BTreeMap<String, FlagValueWire>,
1329
+ ) -> Result<(), HostClientError> {
1330
+ let payload = protocol::to_payload(&FlagsSetRequest {
1331
+ values: values.clone(),
1332
+ })
1333
+ .map_err(|error| HostClientError::Payload(format!("encode flags.set: {error}")))?;
1334
+ let frame = self
1335
+ .inner
1336
+ .hook_request(protocol::FLAGS_SET_METHOD, payload)
1337
+ .await?;
1338
+ let response: FlagsSetResponse = protocol::from_payload(&frame.payload)
1339
+ .map_err(|error| HostClientError::Payload(format!("decode flags.set: {error}")))?;
1340
+ if !response.ok {
1341
+ return Err(HostClientError::Payload(
1342
+ "flags.set rejected by extension host".to_owned(),
1343
+ ));
1344
+ }
1345
+ if let Ok(mut flags) = self.inner.flag_values.write() {
1346
+ for (name, value) in values {
1347
+ let value = match value {
1348
+ FlagValueWire::Boolean(value) => Value::Bool(*value),
1349
+ FlagValueWire::String(value) => Value::String(value.clone()),
1350
+ };
1351
+ flags.insert(name.clone(), value);
1352
+ }
1353
+ }
1354
+ Ok(())
1355
+ }
1356
+
1357
+ /// Dispatch one effective extension shortcut.
1358
+ ///
1359
+ /// # Errors
1360
+ ///
1361
+ /// Returns [`HostClientError::Payload`] when the request or response payload
1362
+ /// cannot be (de)serialized. Propagates the transport-level error from
1363
+ /// [`hook_request`](HostClientInner::hook_request) otherwise:
1364
+ /// [`HostClientError::NotRunning`] when the host is down, and
1365
+ /// [`HostClientError::Timeout`], [`HostClientError::Closed`], or
1366
+ /// [`HostClientError::Remote`] on transport failure.
1367
+ pub async fn execute_shortcut(
1368
+ &self,
1369
+ key: impl Into<String>,
1370
+ ) -> Result<ShortcutExecuteResponse, HostClientError> {
1371
+ let payload =
1372
+ protocol::to_payload(&ShortcutExecuteRequest { key: key.into() }).map_err(|error| {
1373
+ HostClientError::Payload(format!("encode shortcut.execute: {error}"))
1374
+ })?;
1375
+ let frame = self
1376
+ .inner
1377
+ .hook_request(protocol::SHORTCUT_EXECUTE_METHOD, payload)
1378
+ .await?;
1379
+ protocol::from_payload(&frame.payload)
1380
+ .map_err(|error| HostClientError::Payload(format!("decode shortcut.execute: {error}")))
1381
+ }
1382
+
1383
+ /// Deliver one event to a keyed UI slot generation.
1384
+ ///
1385
+ /// # Errors
1386
+ ///
1387
+ /// Returns [`HostClientError::Payload`] when the request or response payload
1388
+ /// cannot be (de)serialized. Propagates the transport-level error from
1389
+ /// [`hook_request`](HostClientInner::hook_request) otherwise:
1390
+ /// [`HostClientError::NotRunning`] when the host is down, and
1391
+ /// [`HostClientError::Timeout`], [`HostClientError::Closed`], or
1392
+ /// [`HostClientError::Remote`] on transport failure.
1393
+ pub async fn send_ui_event(
1394
+ &self,
1395
+ request: UiEventRequest,
1396
+ ) -> Result<UiEventResponse, HostClientError> {
1397
+ let payload = protocol::to_payload(&request)
1398
+ .map_err(|error| HostClientError::Payload(format!("encode uiEvent: {error}")))?;
1399
+ let frame = self
1400
+ .inner
1401
+ .hook_request(protocol::Method::UiEvent.as_str(), payload)
1402
+ .await?;
1403
+ protocol::from_payload(&frame.payload)
1404
+ .map_err(|error| HostClientError::Payload(format!("decode uiEvent: {error}")))
1405
+ }
1406
+
1407
+ // -- Slot / tool-update / provider / error subscriptions ---------------
1408
+
1409
+ /// Subscribe to a keyed UI slot lifecycle. The receiver yields the latest
1410
+ /// sanitized slot, or `None` when the slot is disposed or invalidated by a
1411
+ /// reload. New keys start disposed (`None`) until the host pushes content.
1412
+ #[must_use]
1413
+ pub fn subscribe_slot(&self, key: &str) -> watch::Receiver<Option<SanitizedSlot>> {
1414
+ if let Ok(mut slots) = self.inner.slots.write() {
1415
+ let sender = slots
1416
+ .entry(key.to_owned())
1417
+ .or_insert_with(|| watch::channel(None).0);
1418
+ return sender.subscribe();
1419
+ }
1420
+ // Lock poisoned: hand back a dead receiver.
1421
+ let (tx, rx) = watch::channel(None);
1422
+ let _ = tx.send(None);
1423
+ rx
1424
+ }
1425
+
1426
+ /// Currently live slot keys.
1427
+ #[must_use]
1428
+ pub fn slot_keys(&self) -> Vec<String> {
1429
+ self.inner
1430
+ .slots
1431
+ .read()
1432
+ .map(|guard| guard.keys().cloned().collect())
1433
+ .unwrap_or_default()
1434
+ }
1435
+
1436
+ /// Snapshot all currently live sanitized slots.
1437
+ ///
1438
+ /// This lets a mode attach after `session_start` without losing widgets
1439
+ /// already published before its broadcast subscription existed.
1440
+ #[must_use]
1441
+ pub fn current_slots(&self) -> Vec<SanitizedSlot> {
1442
+ let mut slots = self
1443
+ .inner
1444
+ .slots
1445
+ .read()
1446
+ .map(|guard| {
1447
+ guard
1448
+ .values()
1449
+ .filter_map(|sender| sender.borrow().clone())
1450
+ .collect::<Vec<_>>()
1451
+ })
1452
+ .unwrap_or_default();
1453
+ slots.sort_by(|left, right| left.key.cmp(&right.key));
1454
+ slots
1455
+ }
1456
+
1457
+ /// Subscribe to unsolicited partial tool updates from extension tools.
1458
+ #[must_use]
1459
+ pub fn subscribe_tool_updates(&self) -> broadcast::Receiver<ToolUpdate> {
1460
+ self.inner.tool_updates_tx.subscribe()
1461
+ }
1462
+
1463
+ /// Subscribe to unsolicited custom-provider stream events.
1464
+ #[must_use]
1465
+ pub fn subscribe_provider_events(&self) -> broadcast::Receiver<ProviderEvent> {
1466
+ self.inner.provider_events_tx.subscribe()
1467
+ }
1468
+
1469
+ /// Subscribe to non-retryable extension errors (host crashes, timeouts,
1470
+ /// remote error frames, handler-reported failures).
1471
+ #[must_use]
1472
+ pub fn subscribe_errors(&self) -> broadcast::Receiver<ExtensionErrorEvent> {
1473
+ self.inner.errors_tx.subscribe()
1474
+ }
1475
+
1476
+ /// Whether the loaded host has an active `ui.onTerminalInput` handler.
1477
+ #[must_use]
1478
+ pub fn has_terminal_input_handlers(&self) -> bool {
1479
+ self.inner
1480
+ .snapshot
1481
+ .read()
1482
+ .is_ok_and(|snapshot| snapshot.terminal_input)
1483
+ }
1484
+
1485
+ /// Offer canonical terminal input to the host's sequential 4 ms actor.
1486
+ ///
1487
+ /// # Errors
1488
+ ///
1489
+ /// Returns [`HostClientError`] when the host transport is down, the 4 ms
1490
+ /// deadline elapses, or the response payload cannot be decoded.
1491
+ pub async fn terminal_input(
1492
+ &self,
1493
+ data: &str,
1494
+ ) -> Result<protocol::TerminalInputResult, HostClientError> {
1495
+ let frame = self
1496
+ .inner
1497
+ .client
1498
+ .request(
1499
+ protocol::Method::TerminalInput,
1500
+ serde_json::json!({ "data": data }),
1501
+ Duration::from_millis(4),
1502
+ )
1503
+ .await?;
1504
+ protocol::from_payload(&frame.payload)
1505
+ .map_err(|error| HostClientError::Payload(format!("decode terminalInput: {error}")))
1506
+ }
1507
+
1508
+ /// Subscribe to host notifications and sanitized slot lifecycle.
1509
+ #[must_use]
1510
+ pub fn subscribe_ui(&self) -> broadcast::Receiver<ExtensionUiEvent> {
1511
+ self.inner.ui_tx.subscribe()
1512
+ }
1513
+
1514
+ /// Claim the sole lossless receiver for correlated host dialog requests.
1515
+ ///
1516
+ /// A product mode calls this exactly once when it binds. Subsequent callers
1517
+ /// receive `None`, preventing two modes from racing responses.
1518
+ #[must_use]
1519
+ pub fn take_ui_requests(&self) -> Option<mpsc::Receiver<HostUiRequest>> {
1520
+ let receiver = self
1521
+ .inner
1522
+ .ui_requests_rx
1523
+ .lock()
1524
+ .unwrap_or_else(std::sync::PoisonError::into_inner)
1525
+ .take();
1526
+ if receiver.is_some() {
1527
+ self.inner
1528
+ .ui_requests_claimed
1529
+ .store(true, Ordering::Release);
1530
+ }
1531
+ receiver
1532
+ }
1533
+
1534
+ /// Answer a correlated host-initiated dialog request.
1535
+ ///
1536
+ /// # Errors
1537
+ ///
1538
+ /// Returns a transport error if the host has already exited.
1539
+ pub async fn respond_ui(&self, response: HostUiResponse) -> Result<(), HostClientError> {
1540
+ self.inner.client.respond_ui(response).await
1541
+ }
1542
+
1543
+ // -- Custom tool HTML rendering (session export) ----------------------
1544
+
1545
+ /// Render an extension tool call or result as sanitized HTML for session
1546
+ /// export. Returns `Ok(None)` when no renderer is registered for
1547
+ /// `tool_name`. The host runs the registered `renderCall` / `renderResult`
1548
+ /// and returns an HTML fragment; Rust strips `<script>` / `<style>` blocks
1549
+ /// and escapes the remaining markup so plugin bytes never inject active
1550
+ /// content into an exported document.
1551
+ ///
1552
+ /// # Errors
1553
+ ///
1554
+ /// Returns [`ExtensionRunner` error](super::agent_session::extension_runner::ExtensionRunnerError)
1555
+ /// semantics: transport failures are reported as a non-retryable
1556
+ /// `extension_error` and the call resolves to `Ok(None)` (isolation).
1557
+ pub async fn render_extension_tool_html(
1558
+ &self,
1559
+ phase: ToolRenderPhase,
1560
+ tool_name: &str,
1561
+ payload: &Value,
1562
+ ) -> Option<String> {
1563
+ let _permit = self.inner.traffic.enter()?;
1564
+ if !self.inner.active() {
1565
+ return None;
1566
+ }
1567
+ let request = serde_json::json!({
1568
+ "phase": phase.as_str(),
1569
+ "toolName": tool_name,
1570
+ "payload": payload,
1571
+ });
1572
+ match self
1573
+ .inner
1574
+ .client
1575
+ .request_raw(TOOL_RENDER_HTML_METHOD, request, self.inner.hook_timeout)
1576
+ .await
1577
+ {
1578
+ Ok(frame) => match serde_json::from_value::<ToolRenderHtmlWire>(frame.payload) {
1579
+ Ok(wire) => wire.html.as_deref().map(sanitize_html),
1580
+ Err(_) => None,
1581
+ },
1582
+ Err(err) => {
1583
+ self.inner.report_host_error(&err);
1584
+ None
1585
+ }
1586
+ }
1587
+ }
1588
+
1589
+ // -- Reload / invalidate / shutdown -----------------------------------
1590
+
1591
+ /// Bump the reload generation, dispose every active slot, and reap the
1592
+ /// current host exactly once (reap-only; the session layer owns the
1593
+ /// typed `session_shutdown{reload}` emission before calling this). The
1594
+ /// caller re-creates the runner (via [`HostExtensionRunner::start`] /
1595
+ /// [`connect`](Self::connect)) for the clean registration pass. Returns
1596
+ /// the new generation.
1597
+ pub async fn reload(&self) -> u64 {
1598
+ let generation = self
1599
+ .inner
1600
+ .reload_generation
1601
+ .fetch_add(1, Ordering::Relaxed)
1602
+ .saturating_add(1);
1603
+ Self::shutdown_once_with_inner(&self.inner).await;
1604
+ self.inner.stale.store(true, Ordering::Relaxed);
1605
+ generation
1606
+ }
1607
+
1608
+ /// Transactional restart: prepare a fresh host and restore its flags while
1609
+ /// the old host and its runtime registrations remain live. Once the
1610
+ /// replacement is ready, replace the runtime registrations and return the
1611
+ /// new runner **without reaping the old transport**: the caller finishes
1612
+ /// the session-side cutover (trait runner, host handle, tool registry)
1613
+ /// while the old host is still live, then calls
1614
+ /// [`Self::retire_after_cutover`] on the old runner.
1615
+ ///
1616
+ /// # Errors
1617
+ ///
1618
+ /// Returns [`HostStartError`] when the replacement host fails to start or
1619
+ /// synchronize flags. The old runner and its runtime registrations remain
1620
+ /// usable on either failure.
1621
+ pub async fn restart_and_rewire(
1622
+ &self,
1623
+ runtime: &ModelRuntime,
1624
+ preserved_flags: HashMap<String, Value>,
1625
+ ) -> Result<Arc<Self>, HostStartError> {
1626
+ self.restart_and_rewire_with(
1627
+ runtime,
1628
+ preserved_flags,
1629
+ |paths, cwd, project_trusted| async move {
1630
+ Self::start_with_cwd_and_trust(paths, cwd, project_trusted).await
1631
+ },
1632
+ )
1633
+ .await
1634
+ }
1635
+
1636
+ pub(crate) async fn restart_and_rewire_with<F, Fut>(
1637
+ &self,
1638
+ runtime: &ModelRuntime,
1639
+ preserved_flags: HashMap<String, Value>,
1640
+ start: F,
1641
+ ) -> Result<Arc<Self>, HostStartError>
1642
+ where
1643
+ F: FnOnce(Vec<String>, String, bool) -> Fut,
1644
+ Fut: std::future::Future<Output = Result<Arc<Self>, HostStartError>>,
1645
+ {
1646
+ // 1. Spawn the replacement while the old host and all of its
1647
+ // registrations remain usable.
1648
+ let replacement = start(
1649
+ self.inner.extension_paths.clone(),
1650
+ self.inner.load_cwd.clone(),
1651
+ self.inner.project_trusted,
1652
+ )
1653
+ .await?;
1654
+ // 2. Restore flags before cutting any old surface over.
1655
+ let preserved_flags = match preserved_flags
1656
+ .into_iter()
1657
+ .map(|(name, value)| {
1658
+ let value = match value {
1659
+ Value::Bool(value) => FlagValueWire::Boolean(value),
1660
+ Value::String(value) => FlagValueWire::String(value),
1661
+ other => {
1662
+ return Err(HostStartError::FlagSync(format!(
1663
+ "flag {name:?} has unsupported value {other}"
1664
+ )));
1665
+ }
1666
+ };
1667
+ Ok((name, value))
1668
+ })
1669
+ .collect::<Result<BTreeMap<_, _>, _>>()
1670
+ {
1671
+ Ok(flags) => flags,
1672
+ Err(error) => {
1673
+ replacement.shutdown_once().await;
1674
+ return Err(error);
1675
+ }
1676
+ };
1677
+ if let Err(error) = replacement.apply_flag_values(&preserved_flags).await {
1678
+ replacement.shutdown_once().await;
1679
+ return Err(HostStartError::FlagSync(error.to_string()));
1680
+ }
1681
+ // 3. Cut runtime traffic over synchronously so it can never retain a
1682
+ // stream adapter backed by the old host.
1683
+ self.unregister_providers_from(runtime);
1684
+ let _ = replacement.register_providers_on(runtime);
1685
+ // The old transport stays live: concurrent hooks/tools admitted
1686
+ // before the session-side cutover must never observe a reaped
1687
+ // client. The caller reaps via `retire_after_cutover` once the
1688
+ // trait runner, host handle, and tool registry point at the
1689
+ // replacement.
1690
+ Ok(replacement)
1691
+ }
1692
+
1693
+ /// Retire this runner after a successful reload cutover.
1694
+ ///
1695
+ /// Closes the traffic gate (new hook/tool calls on this retired runner
1696
+ /// fail cleanly without touching the transport), lets in-flight old-host
1697
+ /// traffic finish against the still-live client (bounded by the hook
1698
+ /// deadline plus grace so a hung call cannot pin two hosts forever), then
1699
+ /// bumps the reload generation, disposes slots, and reaps the transport
1700
+ /// exactly once via [`Self::reload`].
1701
+ pub async fn retire_after_cutover(&self) {
1702
+ self.inner.traffic.close();
1703
+ self.inner.stale.store(true, Ordering::Relaxed);
1704
+ let drain_deadline = self
1705
+ .inner
1706
+ .hook_timeout
1707
+ .saturating_add(Duration::from_secs(1));
1708
+ let _ = tokio::time::timeout(drain_deadline, self.inner.traffic.drain()).await;
1709
+ let _ = self.reload().await;
1710
+ }
1711
+
1712
+ /// Resolve + spawn with an explicit load cwd.
1713
+ ///
1714
+ /// # Errors
1715
+ ///
1716
+ /// See [`HostExtensionRunner::start_with_cwd_and_trust`].
1717
+ pub async fn start_with_cwd(
1718
+ extension_paths: Vec<String>,
1719
+ load_cwd: impl Into<String>,
1720
+ ) -> Result<Arc<Self>, HostStartError> {
1721
+ Self::start_with_cwd_and_trust(extension_paths, load_cwd, false).await
1722
+ }
1723
+
1724
+ /// Resolve + spawn with an explicit load cwd and project-trust value.
1725
+ ///
1726
+ /// Resolution follows product policy: env/sibling precedence first, then
1727
+ /// [`acquire`](acquire::resolve_or_acquire) of the pinned host asset when
1728
+ /// nothing is configured and `extension_paths` is non-empty (no download
1729
+ /// ever happens without discovered extensions).
1730
+ ///
1731
+ /// # Errors
1732
+ ///
1733
+ /// See [`HostExtensionRunner::start`]; additionally
1734
+ /// [`HostStartError::Acquire`] when acquisition fails.
1735
+ pub async fn start_with_cwd_and_trust(
1736
+ extension_paths: Vec<String>,
1737
+ load_cwd: impl Into<String>,
1738
+ project_trusted: bool,
1739
+ ) -> Result<Arc<Self>, HostStartError> {
1740
+ let spec = acquire::resolve_or_acquire(!extension_paths.is_empty()).await?;
1741
+ Self::spawn_with_cwd_and_trust(&spec, extension_paths, load_cwd, project_trusted).await
1742
+ }
1743
+
1744
+ /// Spawn from an explicit [`HostSpec`] with a load cwd and project-trust
1745
+ /// value (the injection point for product-acquired hosts).
1746
+ ///
1747
+ /// # Errors
1748
+ ///
1749
+ /// See [`HostExtensionRunner::start`].
1750
+ pub async fn spawn_with_cwd_and_trust(
1751
+ spec: &HostSpec,
1752
+ extension_paths: Vec<String>,
1753
+ load_cwd: impl Into<String>,
1754
+ project_trusted: bool,
1755
+ ) -> Result<Arc<Self>, HostStartError> {
1756
+ let client =
1757
+ Arc::new(HostClient::spawn(spec).map_err(|e| HostStartError::Spawn(e.to_string()))?);
1758
+ let startup = Self::connect_with_cwd_and_trust(
1759
+ Arc::clone(&client),
1760
+ extension_paths,
1761
+ load_cwd,
1762
+ project_trusted,
1763
+ HOOK_TIMEOUT,
1764
+ )
1765
+ .await;
1766
+ Self::finish_startup(&client, startup).await
1767
+ }
1768
+
1769
+ /// Mark this runner stale (session replacement). Subsequent hooks and
1770
+ /// handler-presence queries short-circuit to no-ops; active slots are
1771
+ /// disposed so the host disposes the previous component generation.
1772
+ pub fn invalidate(&self) {
1773
+ self.inner.stale.store(true, Ordering::Relaxed);
1774
+ self.inner.dispose_all_slots();
1775
+ }
1776
+
1777
+ /// Graceful shutdown of the host client, exactly once. Repeated calls are
1778
+ /// no-ops. Slot subscriptions are disposed and the runner is marked
1779
+ /// disabled.
1780
+ pub async fn shutdown_once(&self) {
1781
+ Self::shutdown_once_with_inner(&self.inner).await;
1782
+ }
1783
+ }
1784
+
1785
+ fn clone_registry(source: &Registry) -> Registry {
1786
+ let mut copy = Registry::new();
1787
+ for tool in source.tools() {
1788
+ let _ = copy.register_tool(tool.clone());
1789
+ }
1790
+ for command in source.commands() {
1791
+ let _ = copy.register_command(command.clone());
1792
+ }
1793
+ for shortcut in source.shortcuts() {
1794
+ let _ = copy.register_shortcut(shortcut.clone());
1795
+ }
1796
+ for flag in source.flags() {
1797
+ let _ = copy.register_flag(flag.clone());
1798
+ }
1799
+ for renderer in source.renderers() {
1800
+ let _ = copy.register_renderer(renderer.clone());
1801
+ }
1802
+ for provider in source.providers() {
1803
+ let _ = copy.register_provider(provider.clone());
1804
+ }
1805
+ copy
1806
+ }
1807
+
1808
+ /// Spawn the unsolicited-event pump. Routes typed host events into the bounded
1809
+ /// subscribers; on fatal host conditions marks the runner disabled and emits a
1810
+ /// single non-retryable `extension_error`.
1811
+ fn spawn_event_pump(inner: Arc<Inner>) {
1812
+ let mut rx = inner.client.subscribe();
1813
+ tokio::spawn(async move {
1814
+ loop {
1815
+ match rx.recv().await {
1816
+ Ok(HostEvent::UiRequest(request)) => {
1817
+ if !inner.active() || !inner.ui_requests_claimed.load(Ordering::Acquire) {
1818
+ let _ = inner.client.respond_ui(default_ui_response(&request)).await;
1819
+ } else if let Err(error) = inner.ui_requests_tx.send(request).await {
1820
+ let _ = inner.client.respond_ui(default_ui_response(&error.0)).await;
1821
+ }
1822
+ }
1823
+ Ok(HostEvent::Notify(notification)) => {
1824
+ inner.notify_send(notification);
1825
+ }
1826
+ Ok(HostEvent::UiSlot(slot)) => {
1827
+ forward_slot(&inner, &slot);
1828
+ }
1829
+ Ok(HostEvent::DisposeSlot(d)) => {
1830
+ forward_dispose(&inner, &d);
1831
+ }
1832
+ Ok(HostEvent::ToolUpdate(update)) => {
1833
+ let _ = inner.tool_updates_tx.send(update);
1834
+ }
1835
+ Ok(HostEvent::ProviderEvent(event)) => {
1836
+ let _ = inner.provider_events_tx.send(event);
1837
+ }
1838
+ Ok(HostEvent::ExtensionError(event)) => {
1839
+ let _ = inner.errors_tx.send(event);
1840
+ }
1841
+ Ok(HostEvent::Raw(frame)) => {
1842
+ inner.disabled.store(true, Ordering::Relaxed);
1843
+ inner.publish_error(
1844
+ "extension_protocol",
1845
+ &format!("unhandled host frame: {} {}", frame.kind, frame.method),
1846
+ None,
1847
+ );
1848
+ HostExtensionRunner::shutdown_once_with_inner(&inner).await;
1849
+ break;
1850
+ }
1851
+ Err(broadcast::error::RecvError::Lagged(skipped)) => {
1852
+ inner.publish_error(
1853
+ "extension_event_lagged",
1854
+ &format!("dropped {skipped} extension host events"),
1855
+ None,
1856
+ );
1857
+ }
1858
+ Ok(HostEvent::Eof) => {
1859
+ // Host stdout closed: fatal. Disable once, report, then
1860
+ // shut down / reap the transport exactly once before exit.
1861
+ inner.disabled.store(true, Ordering::Relaxed);
1862
+ inner.publish_error("extension_closed", "extension host stream closed", None);
1863
+ HostExtensionRunner::shutdown_once_with_inner(&inner).await;
1864
+ break;
1865
+ }
1866
+ Ok(HostEvent::ProtocolError(message)) => {
1867
+ inner.disabled.store(true, Ordering::Relaxed);
1868
+ inner.publish_error("extension_protocol", &message, None);
1869
+ HostExtensionRunner::shutdown_once_with_inner(&inner).await;
1870
+ break;
1871
+ }
1872
+ Err(broadcast::error::RecvError::Closed) => break,
1873
+ }
1874
+ }
1875
+ });
1876
+ }
1877
+
1878
+ fn default_ui_response(request: &HostUiRequest) -> HostUiResponse {
1879
+ match request {
1880
+ HostUiRequest::Select { id, .. } => HostUiResponse::Select {
1881
+ id: *id,
1882
+ value: None,
1883
+ },
1884
+ HostUiRequest::Confirm { id, .. } => HostUiResponse::Confirm {
1885
+ id: *id,
1886
+ confirmed: false,
1887
+ },
1888
+ HostUiRequest::Input { id, .. } => HostUiResponse::Input {
1889
+ id: *id,
1890
+ value: None,
1891
+ },
1892
+ HostUiRequest::Editor { id, .. } => HostUiResponse::Editor {
1893
+ id: *id,
1894
+ value: None,
1895
+ },
1896
+ }
1897
+ }
1898
+
1899
+ fn forward_slot(inner: &Arc<Inner>, slot: &UiSlot) {
1900
+ // Rust is the trust boundary: re-scrub every run/style/link field even
1901
+ // though the host is supposed to send structured runs.
1902
+ let sanitized = sanitize_slot(slot);
1903
+ if sanitized.had_rejections {
1904
+ inner.publish_error(
1905
+ "extension_sanitized",
1906
+ "extension uiSlot contained rejected control sequences or oversized fields",
1907
+ None,
1908
+ );
1909
+ }
1910
+ inner.slot_send(sanitized);
1911
+ }
1912
+
1913
+ fn forward_dispose(inner: &Arc<Inner>, dispose: &DisposeSlot) {
1914
+ inner.slot_dispose(&dispose.key);
1915
+ }
1916
+
1917
+ /// Strip `<script>` / `<style>` blocks and escape ampersand / angle brackets
1918
+ /// so an extension-supplied HTML fragment cannot inject active content into an
1919
+ /// exported session document. Attribute-level injection is out of scope for
1920
+ /// the export path (fragments are written into a known template).
1921
+ fn sanitize_html(html: &str) -> String {
1922
+ let lower = html.to_ascii_lowercase();
1923
+ let mut kept = String::with_capacity(html.len());
1924
+ let mut cursor = 0usize;
1925
+ while cursor < html.len() {
1926
+ let script_rel = lower[cursor..].find("<script");
1927
+ let style_rel = lower[cursor..].find("<style");
1928
+ // Earliest dangerous open tag and its matching close marker.
1929
+ let (start, open_len, close_marker): (usize, usize, &str) = match (script_rel, style_rel) {
1930
+ (None, None) => {
1931
+ kept.push_str(&html[cursor..]);
1932
+ break;
1933
+ }
1934
+ (Some(rel), None) => (cursor + rel, "<script".len(), "</script>"),
1935
+ (None, Some(rel)) => (cursor + rel, "<style".len(), "</style>"),
1936
+ (Some(script), Some(style)) => {
1937
+ if script <= style {
1938
+ (cursor + script, "<script".len(), "</script>")
1939
+ } else {
1940
+ (cursor + style, "<style".len(), "</style>")
1941
+ }
1942
+ }
1943
+ };
1944
+ // Preserve everything before the dangerous block.
1945
+ kept.push_str(&html[cursor..start]);
1946
+ let search_from = start + open_len;
1947
+ match lower[search_from..].find(close_marker) {
1948
+ Some(rel) => {
1949
+ cursor = search_from + rel + close_marker.len();
1950
+ }
1951
+ None => {
1952
+ // Unterminated dangerous block: drop the remainder entirely.
1953
+ cursor = html.len();
1954
+ }
1955
+ }
1956
+ }
1957
+ // Escape the surviving markup so no raw tags can become active in the
1958
+ // exported document.
1959
+ kept.replace('&', "&amp;")
1960
+ .replace('<', "&lt;")
1961
+ .replace('>', "&gt;")
1962
+ }
1963
+
1964
+ /// Assistant metadata without the growing `content` array.
1965
+ fn compact_assistant_meta(message: &AssistantMessage) -> Value {
1966
+ let mut value = serde_json::to_value(message).unwrap_or_else(|_| Value::Object(Map::new()));
1967
+ if let Value::Object(object) = &mut value {
1968
+ object.remove("content");
1969
+ }
1970
+ value
1971
+ }
1972
+
1973
+ /// The single content block addressed by a streaming event, if any.
1974
+ fn compact_assistant_block(message: &AssistantMessage, content_index: u64) -> Value {
1975
+ usize::try_from(content_index)
1976
+ .ok()
1977
+ .and_then(|index| message.content.get(index))
1978
+ .and_then(|content| serde_json::to_value(content).ok())
1979
+ .unwrap_or(Value::Null)
1980
+ }
1981
+
1982
+ fn compact_message_update_event(event: &AssistantMessageEvent) -> Value {
1983
+ use AssistantMessageEvent as Ev;
1984
+ // (type name, partial, contentIndex, delta text, include block)
1985
+ let (kind, partial, content_index, delta, with_block) = match event {
1986
+ Ev::Start { partial } => ("start", partial, None, None, false),
1987
+ Ev::TextStart {
1988
+ content_index,
1989
+ partial,
1990
+ } => ("text_start", partial, Some(*content_index), None, true),
1991
+ Ev::TextDelta {
1992
+ content_index,
1993
+ delta,
1994
+ partial,
1995
+ } => (
1996
+ "text_delta",
1997
+ partial,
1998
+ Some(*content_index),
1999
+ Some(delta),
2000
+ false,
2001
+ ),
2002
+ Ev::TextEnd {
2003
+ content_index,
2004
+ partial,
2005
+ ..
2006
+ } => ("text_end", partial, Some(*content_index), None, true),
2007
+ Ev::ThinkingStart {
2008
+ content_index,
2009
+ partial,
2010
+ } => ("thinking_start", partial, Some(*content_index), None, true),
2011
+ Ev::ThinkingDelta {
2012
+ content_index,
2013
+ delta,
2014
+ partial,
2015
+ } => (
2016
+ "thinking_delta",
2017
+ partial,
2018
+ Some(*content_index),
2019
+ Some(delta),
2020
+ false,
2021
+ ),
2022
+ Ev::ThinkingEnd {
2023
+ content_index,
2024
+ partial,
2025
+ ..
2026
+ } => ("thinking_end", partial, Some(*content_index), None, true),
2027
+ Ev::ToolCallStart {
2028
+ content_index,
2029
+ partial,
2030
+ } => ("toolcall_start", partial, Some(*content_index), None, true),
2031
+ Ev::ToolCallDelta {
2032
+ content_index,
2033
+ delta,
2034
+ partial,
2035
+ } => (
2036
+ "toolcall_delta",
2037
+ partial,
2038
+ Some(*content_index),
2039
+ Some(delta),
2040
+ false,
2041
+ ),
2042
+ Ev::ToolCallEnd {
2043
+ content_index,
2044
+ partial,
2045
+ ..
2046
+ } => ("toolcall_end", partial, Some(*content_index), None, true),
2047
+ Ev::Done { reason, message } => {
2048
+ return serde_json::json!({
2049
+ "type": "done",
2050
+ "reason": reason,
2051
+ "final": message,
2052
+ });
2053
+ }
2054
+ Ev::Error { reason, error } => {
2055
+ return serde_json::json!({
2056
+ "type": "error",
2057
+ "reason": reason,
2058
+ "final": error,
2059
+ });
2060
+ }
2061
+ };
2062
+
2063
+ let mut object = Map::new();
2064
+ object.insert("type".to_owned(), Value::String(kind.to_owned()));
2065
+ object.insert("meta".to_owned(), compact_assistant_meta(partial));
2066
+ if let Some(content_index) = content_index {
2067
+ object.insert("contentIndex".to_owned(), Value::from(content_index));
2068
+ if with_block {
2069
+ object.insert(
2070
+ "block".to_owned(),
2071
+ compact_assistant_block(partial, content_index),
2072
+ );
2073
+ }
2074
+ }
2075
+ if let Some(delta) = delta {
2076
+ object.insert("delta".to_owned(), Value::String(delta.clone()));
2077
+ }
2078
+ Value::Object(object)
2079
+ }
2080
+
2081
+ // ---------------------------------------------------------------------------
2082
+ // ExtensionRunner trait impl
2083
+ // ---------------------------------------------------------------------------
2084
+
2085
+ impl ExtensionRunner for HostExtensionRunner {
2086
+ fn has_handlers(&self, event: &str) -> bool {
2087
+ self.inner.has_handlers(event)
2088
+ }
2089
+
2090
+ fn emit(
2091
+ &self,
2092
+ event: AgentSessionEvent,
2093
+ ) -> BoxFuture<
2094
+ '_,
2095
+ Result<Option<CancelResult>, super::agent_session::extension_runner::ExtensionRunnerError>,
2096
+ > {
2097
+ let inner = Arc::clone(&self.inner);
2098
+ Box::pin(async move {
2099
+ let method = match event.type_name() {
2100
+ "compaction_start" => "session_before_compact",
2101
+ "compaction_end" => "session_compact",
2102
+ "thinking_level_changed" => "thinking_level_select",
2103
+ name => name,
2104
+ };
2105
+ if !inner.has_handlers(method) {
2106
+ return Ok(None);
2107
+ }
2108
+ let payload =
2109
+ serde_json::to_value(&event).unwrap_or_else(|_| Value::Object(Map::new()));
2110
+ match inner.hook_request(method, payload).await {
2111
+ Ok(frame) => {
2112
+ let result = serde_json::from_value::<Option<CancelWire>>(frame.payload)
2113
+ .ok()
2114
+ .flatten()
2115
+ .map(|wire| CancelResult {
2116
+ cancel: wire.cancel,
2117
+ reason: wire.reason,
2118
+ });
2119
+ Ok(result)
2120
+ }
2121
+ Err(err) => {
2122
+ inner.report_host_error(&err);
2123
+ Ok(None)
2124
+ }
2125
+ }
2126
+ })
2127
+ }
2128
+
2129
+ fn emit_message_update_delta<'a>(
2130
+ &'a self,
2131
+ event: &'a AssistantMessageEvent,
2132
+ ) -> BoxFuture<
2133
+ 'a,
2134
+ Result<Option<CancelResult>, super::agent_session::extension_runner::ExtensionRunnerError>,
2135
+ > {
2136
+ let inner = Arc::clone(&self.inner);
2137
+ let payload = serde_json::json!({
2138
+ "type": MESSAGE_UPDATE_DELTA_METHOD,
2139
+ "event": compact_message_update_event(event),
2140
+ });
2141
+ Box::pin(async move {
2142
+ if !inner.has_handlers("message_update") {
2143
+ return Ok(None);
2144
+ }
2145
+ match inner
2146
+ .hook_request(MESSAGE_UPDATE_DELTA_METHOD, payload)
2147
+ .await
2148
+ {
2149
+ Ok(frame) => {
2150
+ let result = serde_json::from_value::<Option<CancelWire>>(frame.payload)
2151
+ .ok()
2152
+ .flatten()
2153
+ .map(|wire| CancelResult {
2154
+ cancel: wire.cancel,
2155
+ reason: wire.reason,
2156
+ });
2157
+ Ok(result)
2158
+ }
2159
+ Err(error) => {
2160
+ inner.report_host_error(&error);
2161
+ Ok(None)
2162
+ }
2163
+ }
2164
+ })
2165
+ }
2166
+
2167
+ fn emit_message_end(
2168
+ &self,
2169
+ message: AgentMessage,
2170
+ ) -> BoxFuture<
2171
+ '_,
2172
+ Result<Option<AgentMessage>, super::agent_session::extension_runner::ExtensionRunnerError>,
2173
+ > {
2174
+ let inner = Arc::clone(&self.inner);
2175
+ Box::pin(async move {
2176
+ if !inner.has_handlers("message_end") {
2177
+ return Ok(None);
2178
+ }
2179
+ let payload = serde_json::to_value(&message).unwrap_or(Value::Null);
2180
+ match inner.hook_request("message_end", payload).await {
2181
+ Ok(frame) => {
2182
+ let replacement = serde_json::from_value::<MessageEndWire>(frame.payload)
2183
+ .ok()
2184
+ .and_then(|wire| wire.message);
2185
+ // Enforce the role-preservation invariant the host merge
2186
+ // guarantees; a mismatched role is dropped + reported.
2187
+ let role_matches = replacement
2188
+ .as_ref()
2189
+ .is_some_and(|replacement| replacement.role() == message.role());
2190
+ match replacement {
2191
+ Some(message) if role_matches => Ok(Some(message)),
2192
+ Some(_) => {
2193
+ inner.publish_error(
2194
+ "extension_message_end",
2195
+ "message_end handler returned a message with a different role",
2196
+ None,
2197
+ );
2198
+ Ok(None)
2199
+ }
2200
+ None => Ok(None),
2201
+ }
2202
+ }
2203
+ Err(err) => {
2204
+ inner.report_host_error(&err);
2205
+ Ok(None)
2206
+ }
2207
+ }
2208
+ })
2209
+ }
2210
+
2211
+ fn emit_tool_call(
2212
+ &self,
2213
+ tool_name: &str,
2214
+ tool_call_id: &str,
2215
+ input: Map<String, Value>,
2216
+ ) -> BoxFuture<
2217
+ '_,
2218
+ Result<
2219
+ Option<BeforeToolCallResult>,
2220
+ super::agent_session::extension_runner::ExtensionRunnerError,
2221
+ >,
2222
+ > {
2223
+ let inner = Arc::clone(&self.inner);
2224
+ let tool_name = tool_name.to_owned();
2225
+ let tool_call_id = tool_call_id.to_owned();
2226
+ Box::pin(async move {
2227
+ if !inner.has_handlers("tool_call") {
2228
+ return Ok(None);
2229
+ }
2230
+ let payload = serde_json::json!({
2231
+ "toolName": tool_name,
2232
+ "toolCallId": tool_call_id,
2233
+ "input": input,
2234
+ });
2235
+ match inner.hook_request("tool_call", payload).await {
2236
+ Ok(frame) => {
2237
+ let result =
2238
+ serde_json::from_value::<Option<BeforeToolCallWire>>(frame.payload)
2239
+ .ok()
2240
+ .flatten()
2241
+ .map(|wire| BeforeToolCallResult {
2242
+ block: wire.block,
2243
+ reason: wire.reason,
2244
+ });
2245
+ Ok(result)
2246
+ }
2247
+ Err(err) => {
2248
+ inner.report_host_error(&err);
2249
+ Ok(None)
2250
+ }
2251
+ }
2252
+ })
2253
+ }
2254
+
2255
+ fn emit_tool_result(
2256
+ &self,
2257
+ tool_name: &str,
2258
+ tool_call_id: &str,
2259
+ input: Map<String, Value>,
2260
+ content: Vec<ToolResultContent>,
2261
+ details: Value,
2262
+ is_error: bool,
2263
+ ) -> BoxFuture<
2264
+ '_,
2265
+ Result<
2266
+ Option<AfterToolCallResult>,
2267
+ super::agent_session::extension_runner::ExtensionRunnerError,
2268
+ >,
2269
+ > {
2270
+ let inner = Arc::clone(&self.inner);
2271
+ let tool_name = tool_name.to_owned();
2272
+ let tool_call_id = tool_call_id.to_owned();
2273
+ Box::pin(async move {
2274
+ if !inner.has_handlers("tool_result") {
2275
+ return Ok(None);
2276
+ }
2277
+ let payload = serde_json::json!({
2278
+ "toolName": tool_name,
2279
+ "toolCallId": tool_call_id,
2280
+ "input": input,
2281
+ "content": content,
2282
+ "details": details,
2283
+ "isError": is_error,
2284
+ });
2285
+ match inner.hook_request("tool_result", payload).await {
2286
+ Ok(frame) => {
2287
+ let result = serde_json::from_value::<Option<AfterToolCallWire>>(frame.payload)
2288
+ .ok()
2289
+ .flatten()
2290
+ .map(|wire| AfterToolCallResult {
2291
+ content: wire.content,
2292
+ details: wire.details,
2293
+ is_error: wire.is_error,
2294
+ terminate: wire.terminate,
2295
+ });
2296
+ Ok(result)
2297
+ }
2298
+ Err(err) => {
2299
+ inner.report_host_error(&err);
2300
+ Ok(None)
2301
+ }
2302
+ }
2303
+ })
2304
+ }
2305
+
2306
+ fn emit_input(
2307
+ &self,
2308
+ text: &str,
2309
+ images: Option<Value>,
2310
+ source: &str,
2311
+ streaming_behavior: Option<&str>,
2312
+ ) -> BoxFuture<
2313
+ '_,
2314
+ Result<InputTransformResult, super::agent_session::extension_runner::ExtensionRunnerError>,
2315
+ > {
2316
+ let inner = Arc::clone(&self.inner);
2317
+ let text = text.to_owned();
2318
+ let source = source.to_owned();
2319
+ let streaming_behavior = streaming_behavior.map(str::to_owned);
2320
+ Box::pin(async move {
2321
+ if !inner.has_handlers("input") {
2322
+ return Ok(InputTransformResult::default());
2323
+ }
2324
+ let payload = serde_json::json!({
2325
+ "text": text,
2326
+ "images": images,
2327
+ "source": source,
2328
+ "streamingBehavior": streaming_behavior,
2329
+ });
2330
+ match inner.hook_request("input", payload).await {
2331
+ Ok(frame) => {
2332
+ let (handled, mapped_text, mapped_images) =
2333
+ match serde_json::from_value::<InputTransformWire>(frame.payload) {
2334
+ Ok(InputTransformWire::Handled) => (true, None, None),
2335
+ Ok(InputTransformWire::Transform { text, images }) => {
2336
+ (false, Some(text), images)
2337
+ }
2338
+ _ => (false, None, None),
2339
+ };
2340
+ Ok(InputTransformResult {
2341
+ handled,
2342
+ text: mapped_text,
2343
+ images: mapped_images,
2344
+ })
2345
+ }
2346
+ Err(err) => {
2347
+ inner.report_host_error(&err);
2348
+ Ok(InputTransformResult::default())
2349
+ }
2350
+ }
2351
+ })
2352
+ }
2353
+
2354
+ fn emit_before_agent_start(
2355
+ &self,
2356
+ prompt: &str,
2357
+ images: Option<Value>,
2358
+ ) -> BoxFuture<
2359
+ '_,
2360
+ Result<
2361
+ Option<BeforeAgentStartResult>,
2362
+ super::agent_session::extension_runner::ExtensionRunnerError,
2363
+ >,
2364
+ > {
2365
+ let inner = Arc::clone(&self.inner);
2366
+ let prompt = prompt.to_owned();
2367
+ Box::pin(async move {
2368
+ if !inner.has_handlers("before_agent_start") {
2369
+ return Ok(None);
2370
+ }
2371
+ let payload = serde_json::json!({
2372
+ "prompt": prompt,
2373
+ "images": images,
2374
+ });
2375
+ match inner.hook_request("before_agent_start", payload).await {
2376
+ Ok(frame) => {
2377
+ let wire =
2378
+ serde_json::from_value::<Option<BeforeAgentStartWire>>(frame.payload)
2379
+ .ok()
2380
+ .flatten();
2381
+ Ok(wire.map(|wire| BeforeAgentStartResult {
2382
+ messages: wire.messages,
2383
+ system_prompt: wire.system_prompt,
2384
+ }))
2385
+ }
2386
+ Err(err) => {
2387
+ inner.report_host_error(&err);
2388
+ Ok(None)
2389
+ }
2390
+ }
2391
+ })
2392
+ }
2393
+
2394
+ fn emit_resources_discover(
2395
+ &self,
2396
+ cwd: &str,
2397
+ reason: &str,
2398
+ ) -> BoxFuture<
2399
+ '_,
2400
+ Result<
2401
+ ResourceExtensionPaths,
2402
+ super::agent_session::extension_runner::ExtensionRunnerError,
2403
+ >,
2404
+ > {
2405
+ let inner = Arc::clone(&self.inner);
2406
+ let cwd = cwd.to_owned();
2407
+ let reason = reason.to_owned();
2408
+ Box::pin(async move {
2409
+ if !inner.has_handlers("resources_discover") {
2410
+ return Ok(ResourceExtensionPaths::default());
2411
+ }
2412
+ let payload = serde_json::json!({ "cwd": cwd, "reason": reason });
2413
+ match inner.hook_request("resources_discover", payload).await {
2414
+ Ok(frame) => {
2415
+ let wire = serde_json::from_value::<ResourcesDiscoverWire>(frame.payload)
2416
+ .unwrap_or_default();
2417
+ let discovered = |paths: Option<Vec<ResourcePathWire>>| {
2418
+ paths
2419
+ .unwrap_or_default()
2420
+ .into_iter()
2421
+ .map(|entry| {
2422
+ ExtensionResourcePath::discovered(entry.path, &entry.extension_path)
2423
+ })
2424
+ .collect()
2425
+ };
2426
+ Ok(ResourceExtensionPaths {
2427
+ skill_paths: discovered(wire.skills),
2428
+ prompt_paths: discovered(wire.prompts),
2429
+ theme_paths: discovered(wire.themes),
2430
+ })
2431
+ }
2432
+ Err(err) => {
2433
+ inner.report_host_error(&err);
2434
+ Ok(ResourceExtensionPaths::default())
2435
+ }
2436
+ }
2437
+ })
2438
+ }
2439
+
2440
+ fn get_registered_commands(&self) -> Vec<String> {
2441
+ self.inner
2442
+ .snapshot
2443
+ .read()
2444
+ .map(|guard| {
2445
+ guard
2446
+ .registry
2447
+ .commands()
2448
+ .iter()
2449
+ .map(|command| command.name.clone())
2450
+ .collect()
2451
+ })
2452
+ .unwrap_or_default()
2453
+ }
2454
+
2455
+ fn execute_command(
2456
+ &self,
2457
+ name: &str,
2458
+ args: &str,
2459
+ ) -> BoxFuture<'_, Result<bool, super::agent_session::extension_runner::ExtensionRunnerError>>
2460
+ {
2461
+ let inner = Arc::clone(&self.inner);
2462
+ let name = name.to_owned();
2463
+ let args = args.to_owned();
2464
+ Box::pin(async move {
2465
+ if !inner.has_command(&name) {
2466
+ return Ok(false);
2467
+ }
2468
+ let Some(_permit) = inner.traffic.enter() else {
2469
+ return Ok(false);
2470
+ };
2471
+ if !inner.active() {
2472
+ return Ok(false);
2473
+ }
2474
+ let payload = serde_json::json!({ "name": name, "args": args });
2475
+ match inner
2476
+ .client
2477
+ .request_raw(COMMAND_EXECUTE_METHOD, payload, inner.hook_timeout)
2478
+ .await
2479
+ {
2480
+ Ok(frame) => {
2481
+ let ok = serde_json::from_value::<CommandExecuteWire>(frame.payload)
2482
+ .is_ok_and(|wire| wire.ok);
2483
+ Ok(ok)
2484
+ }
2485
+ Err(err) => {
2486
+ inner.report_host_error(&err);
2487
+ Ok(true)
2488
+ }
2489
+ }
2490
+ })
2491
+ }
2492
+
2493
+ fn get_all_registered_tools(&self) -> HashMap<String, Arc<dyn AgentTool>> {
2494
+ self.inner
2495
+ .snapshot
2496
+ .read()
2497
+ .map(|guard| guard.tools.clone())
2498
+ .unwrap_or_default()
2499
+ }
2500
+
2501
+ fn get_flag_values(&self) -> HashMap<String, Value> {
2502
+ self.inner
2503
+ .flag_values
2504
+ .read()
2505
+ .map(|guard| guard.clone())
2506
+ .unwrap_or_default()
2507
+ }
2508
+
2509
+ fn invalidate(&self) {
2510
+ HostExtensionRunner::invalidate(self);
2511
+ }
2512
+
2513
+ fn emit_error(&self, message: String) {
2514
+ self.inner.publish_error("extension_error", &message, None);
2515
+ }
2516
+ }
2517
+
2518
+ impl HostExtensionRunner {
2519
+ async fn shutdown_once_with_inner(inner: &Arc<Inner>) {
2520
+ let _guard = inner.shutdown_lock.lock().await;
2521
+ if inner.shutdown_done.load(Ordering::Relaxed) {
2522
+ return;
2523
+ }
2524
+ Self::reap_inner(inner).await;
2525
+ inner.shutdown_done.store(true, Ordering::Relaxed);
2526
+ }
2527
+
2528
+ async fn reap_inner(inner: &Arc<Inner>) {
2529
+ // Order matters for the slot_send/slot_dispose teardown gate: the
2530
+ // flag must be set before dispose_all_slots takes the slots lock.
2531
+ inner.disabled.store(true, Ordering::Relaxed);
2532
+ inner.dispose_all_slots();
2533
+ let _ = inner.client.shutdown().await;
2534
+ }
2535
+ }
2536
+
2537
+ /// Product-policy acquisition of the pinned extension-host release asset.
2538
+ pub mod acquire;
2539
+
2540
+ #[cfg(test)]
2541
+ mod tests;