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,2999 @@
1
+ //! RPC protocol wire types for headless operation.
2
+ //!
3
+ //! Port of `.references/pi/packages/coding-agent/src/modes/rpc/rpc-types.ts`.
4
+ //!
5
+ //! Commands arrive as JSON lines on stdin. Responses, extension UI requests, and
6
+ //! agent events leave as JSON lines on stdout. Unknown command discriminants are
7
+ //! retained as [`RpcCommand::Unknown`] so the server can echo `id` + `type`
8
+ //! without a serde hard-fail.
9
+
10
+ use pi_agent::{AgentMessage, QueueMode};
11
+ use pi_ai::{ImageContent, Model, ModelThinkingLevel};
12
+ use serde::de::{self, Deserializer};
13
+ use serde::ser::{SerializeMap, Serializer};
14
+ use serde::{Deserialize, Serialize};
15
+ use serde_json::{Map, Value};
16
+
17
+ use crate::core::compaction::CompactionResult;
18
+ use crate::core::resources::{SourceInfo, SourceOrigin, SourceScope};
19
+ use crate::core::sessions::SessionEntry;
20
+
21
+ // ---------------------------------------------------------------------------
22
+ // Local payload types not yet owned by product-core modules
23
+ // ---------------------------------------------------------------------------
24
+
25
+ /// Bash execution result returned by the `bash` RPC command.
26
+ ///
27
+ /// Matches `.references/pi/packages/coding-agent/src/core/bash-executor.ts`
28
+ /// `BashResult`. Defined here until the product bash-executor surface lands.
29
+ #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
30
+ #[serde(rename_all = "camelCase")]
31
+ pub struct BashResult {
32
+ /// Combined stdout + stderr (sanitized, possibly truncated).
33
+ pub output: String,
34
+ /// Process exit code (`None` when killed/cancelled).
35
+ #[serde(default, skip_serializing_if = "Option::is_none")]
36
+ pub exit_code: Option<i32>,
37
+ /// Whether the command was cancelled via signal.
38
+ pub cancelled: bool,
39
+ /// Whether the output was truncated.
40
+ pub truncated: bool,
41
+ /// Path to a spill file holding full output when truncated.
42
+ #[serde(default, skip_serializing_if = "Option::is_none")]
43
+ pub full_output_path: Option<String>,
44
+ }
45
+
46
+ /// Context-window usage snapshot embedded in [`SessionStats`].
47
+ ///
48
+ /// Matches `ContextUsage` from coding-agent `extensions/types.ts`.
49
+ #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
50
+ #[serde(rename_all = "camelCase")]
51
+ pub struct ContextUsage {
52
+ /// Estimated context tokens, or `null` when unknown (e.g. right after compaction).
53
+ #[serde(default)]
54
+ pub tokens: Option<u64>,
55
+ /// Model context-window size.
56
+ pub context_window: u64,
57
+ /// Usage as a percentage of the context window, or `null` when tokens unknown.
58
+ #[serde(default)]
59
+ pub percent: Option<f64>,
60
+ }
61
+
62
+ /// Token counters inside [`SessionStats`].
63
+ #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
64
+ #[serde(rename_all = "camelCase")]
65
+ pub struct SessionStatsTokens {
66
+ /// Input tokens.
67
+ pub input: u64,
68
+ /// Output tokens.
69
+ pub output: u64,
70
+ /// Cache-read tokens.
71
+ pub cache_read: u64,
72
+ /// Cache-write tokens.
73
+ pub cache_write: u64,
74
+ /// Total tokens.
75
+ pub total: u64,
76
+ }
77
+
78
+ /// Session statistics for the `get_session_stats` RPC command.
79
+ ///
80
+ /// Matches `SessionStats` from coding-agent `agent-session.ts`.
81
+ #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
82
+ #[serde(rename_all = "camelCase")]
83
+ pub struct SessionStats {
84
+ /// Absolute session file path, when persisted.
85
+ #[serde(default, skip_serializing_if = "Option::is_none")]
86
+ pub session_file: Option<String>,
87
+ /// Session id.
88
+ pub session_id: String,
89
+ /// Count of user messages.
90
+ pub user_messages: u64,
91
+ /// Count of assistant messages.
92
+ pub assistant_messages: u64,
93
+ /// Count of tool-call content blocks.
94
+ pub tool_calls: u64,
95
+ /// Count of tool-result messages.
96
+ pub tool_results: u64,
97
+ /// Total messages in the session.
98
+ pub total_messages: u64,
99
+ /// Aggregated token usage.
100
+ pub tokens: SessionStatsTokens,
101
+ /// Aggregated cost.
102
+ pub cost: f64,
103
+ /// Optional context-window usage.
104
+ #[serde(default, skip_serializing_if = "Option::is_none")]
105
+ pub context_usage: Option<ContextUsage>,
106
+ }
107
+
108
+ /// Tree node returned by `get_tree`.
109
+ ///
110
+ /// Mirrors `SessionTreeNode` from coding-agent `session-manager.ts`. Product
111
+ /// `SessionTreeNode` is not yet `Serialize`; this wire-facing twin reuses
112
+ /// [`SessionEntry`] which already round-trips JSONL.
113
+ #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
114
+ #[serde(rename_all = "camelCase")]
115
+ pub struct RpcSessionTreeNode {
116
+ /// Entry at this node.
117
+ pub entry: SessionEntry,
118
+ /// Children sorted by timestamp ascending.
119
+ pub children: Vec<RpcSessionTreeNode>,
120
+ /// Resolved label for this entry, if any.
121
+ #[serde(default, skip_serializing_if = "Option::is_none")]
122
+ pub label: Option<String>,
123
+ /// Timestamp of the latest label change for this entry, if any.
124
+ #[serde(default, skip_serializing_if = "Option::is_none")]
125
+ pub label_timestamp: Option<String>,
126
+ }
127
+
128
+ /// Wire-facing [`SourceInfo`] with serde (product `SourceInfo` is not yet serde).
129
+ #[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
130
+ #[serde(rename_all = "camelCase")]
131
+ pub struct RpcSourceInfo {
132
+ /// Absolute (or synthetic) path of the resource.
133
+ pub path: String,
134
+ /// Source label (`local`, `auto`, `cli`, package id, …).
135
+ pub source: String,
136
+ /// Scope relative to the project boundary.
137
+ pub scope: RpcSourceScope,
138
+ /// Package vs top-level origin.
139
+ pub origin: RpcSourceOrigin,
140
+ /// Optional base directory used for relative resolution.
141
+ #[serde(default, skip_serializing_if = "Option::is_none")]
142
+ pub base_dir: Option<String>,
143
+ }
144
+
145
+ impl From<&SourceInfo> for RpcSourceInfo {
146
+ fn from(value: &SourceInfo) -> Self {
147
+ Self {
148
+ path: value.path.clone(),
149
+ source: value.source.clone(),
150
+ scope: RpcSourceScope::from(value.scope),
151
+ origin: RpcSourceOrigin::from(value.origin),
152
+ base_dir: value.base_dir.clone(),
153
+ }
154
+ }
155
+ }
156
+
157
+ impl From<SourceInfo> for RpcSourceInfo {
158
+ fn from(value: SourceInfo) -> Self {
159
+ Self::from(&value)
160
+ }
161
+ }
162
+
163
+ /// Wire discriminant for [`SourceScope`].
164
+ #[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize, Deserialize)]
165
+ #[serde(rename_all = "camelCase")]
166
+ pub enum RpcSourceScope {
167
+ /// Global agent directory.
168
+ User,
169
+ /// Project-local.
170
+ Project,
171
+ /// Temporary/CLI or synthetic.
172
+ Temporary,
173
+ }
174
+
175
+ impl From<SourceScope> for RpcSourceScope {
176
+ fn from(value: SourceScope) -> Self {
177
+ match value {
178
+ SourceScope::User => Self::User,
179
+ SourceScope::Project => Self::Project,
180
+ SourceScope::Temporary => Self::Temporary,
181
+ }
182
+ }
183
+ }
184
+
185
+ /// Wire discriminant for [`SourceOrigin`].
186
+ #[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize, Deserialize)]
187
+ pub enum RpcSourceOrigin {
188
+ /// Installed or local package root.
189
+ #[serde(rename = "package")]
190
+ Package,
191
+ /// Settings array, auto-discovery, or CLI temporary path.
192
+ #[serde(rename = "top-level")]
193
+ TopLevel,
194
+ }
195
+
196
+ impl From<SourceOrigin> for RpcSourceOrigin {
197
+ fn from(value: SourceOrigin) -> Self {
198
+ match value {
199
+ SourceOrigin::Package => Self::Package,
200
+ SourceOrigin::TopLevel => Self::TopLevel,
201
+ }
202
+ }
203
+ }
204
+
205
+ /// Streaming behavior for a prompt that arrives while the agent is busy.
206
+ #[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize, Deserialize)]
207
+ #[serde(rename_all = "camelCase")]
208
+ pub enum StreamingBehavior {
209
+ /// Inject as a steering message.
210
+ Steer,
211
+ /// Queue as a follow-up after the current turn.
212
+ FollowUp,
213
+ }
214
+
215
+ // ---------------------------------------------------------------------------
216
+ // RpcCommand (stdin)
217
+ // ---------------------------------------------------------------------------
218
+
219
+ /// All 31 known RPC commands, plus an unknown catch-all.
220
+ ///
221
+ /// Each known variant carries an optional correlation `id`. The unknown arm
222
+ /// preserves the raw `type` string and remaining fields so the server can echo
223
+ /// `id`/`type` on error without serde hard-failing the line.
224
+ #[derive(Clone, Debug, PartialEq)]
225
+ pub enum RpcCommand {
226
+ /// Submit a user prompt (async — events follow; response at preflight).
227
+ Prompt {
228
+ /// Correlation id.
229
+ id: Option<String>,
230
+ /// Prompt text.
231
+ message: String,
232
+ /// Optional inline images.
233
+ images: Option<Vec<ImageContent>>,
234
+ /// How to handle the prompt while streaming.
235
+ streaming_behavior: Option<StreamingBehavior>,
236
+ },
237
+ /// Steer into the current turn.
238
+ Steer {
239
+ /// Correlation id.
240
+ id: Option<String>,
241
+ /// Steering text.
242
+ message: String,
243
+ /// Optional inline images.
244
+ images: Option<Vec<ImageContent>>,
245
+ },
246
+ /// Queue a follow-up after the current turn.
247
+ FollowUp {
248
+ /// Correlation id.
249
+ id: Option<String>,
250
+ /// Follow-up text.
251
+ message: String,
252
+ /// Optional inline images.
253
+ images: Option<Vec<ImageContent>>,
254
+ },
255
+ /// Abort the current agent turn.
256
+ Abort {
257
+ /// Correlation id.
258
+ id: Option<String>,
259
+ },
260
+ /// Start a new session, optionally forked from a parent session file.
261
+ NewSession {
262
+ /// Correlation id.
263
+ id: Option<String>,
264
+ /// Optional parent session path.
265
+ parent_session: Option<String>,
266
+ },
267
+ /// Snapshot current session state.
268
+ GetState {
269
+ /// Correlation id.
270
+ id: Option<String>,
271
+ },
272
+ /// Select a model by provider + id.
273
+ SetModel {
274
+ /// Correlation id.
275
+ id: Option<String>,
276
+ /// Provider identifier.
277
+ provider: String,
278
+ /// Model identifier.
279
+ model_id: String,
280
+ },
281
+ /// Cycle to the next available model.
282
+ CycleModel {
283
+ /// Correlation id.
284
+ id: Option<String>,
285
+ },
286
+ /// List available models.
287
+ GetAvailableModels {
288
+ /// Correlation id.
289
+ id: Option<String>,
290
+ },
291
+ /// Set the reasoning/thinking level.
292
+ SetThinkingLevel {
293
+ /// Correlation id.
294
+ id: Option<String>,
295
+ /// Target level (includes `off`).
296
+ level: ModelThinkingLevel,
297
+ },
298
+ /// Cycle to the next thinking level.
299
+ CycleThinkingLevel {
300
+ /// Correlation id.
301
+ id: Option<String>,
302
+ },
303
+ /// Set the steering queue drain mode.
304
+ SetSteeringMode {
305
+ /// Correlation id.
306
+ id: Option<String>,
307
+ /// Drain mode.
308
+ mode: QueueMode,
309
+ },
310
+ /// Set the follow-up queue drain mode.
311
+ SetFollowUpMode {
312
+ /// Correlation id.
313
+ id: Option<String>,
314
+ /// Drain mode.
315
+ mode: QueueMode,
316
+ },
317
+ /// Compact the session.
318
+ Compact {
319
+ /// Correlation id.
320
+ id: Option<String>,
321
+ /// Optional custom instructions for the summarizer.
322
+ custom_instructions: Option<String>,
323
+ },
324
+ /// Enable or disable auto-compaction.
325
+ SetAutoCompaction {
326
+ /// Correlation id.
327
+ id: Option<String>,
328
+ /// Whether auto-compaction is enabled.
329
+ enabled: bool,
330
+ },
331
+ /// Enable or disable auto-retry.
332
+ SetAutoRetry {
333
+ /// Correlation id.
334
+ id: Option<String>,
335
+ /// Whether auto-retry is enabled.
336
+ enabled: bool,
337
+ },
338
+ /// Abort an in-flight auto-retry.
339
+ AbortRetry {
340
+ /// Correlation id.
341
+ id: Option<String>,
342
+ },
343
+ /// Execute a bash command via the session.
344
+ Bash {
345
+ /// Correlation id.
346
+ id: Option<String>,
347
+ /// Shell command.
348
+ command: String,
349
+ /// When true, exclude output from model context.
350
+ exclude_from_context: Option<bool>,
351
+ },
352
+ /// Abort a running bash command.
353
+ AbortBash {
354
+ /// Correlation id.
355
+ id: Option<String>,
356
+ },
357
+ /// Return session statistics.
358
+ GetSessionStats {
359
+ /// Correlation id.
360
+ id: Option<String>,
361
+ },
362
+ /// Export the session to HTML.
363
+ ExportHtml {
364
+ /// Correlation id.
365
+ id: Option<String>,
366
+ /// Optional output path.
367
+ output_path: Option<String>,
368
+ },
369
+ /// Switch to another session file.
370
+ SwitchSession {
371
+ /// Correlation id.
372
+ id: Option<String>,
373
+ /// Path of the session to open.
374
+ session_path: String,
375
+ },
376
+ /// Fork the session before `entry_id`.
377
+ Fork {
378
+ /// Correlation id.
379
+ id: Option<String>,
380
+ /// Entry id to fork before.
381
+ entry_id: String,
382
+ },
383
+ /// Clone the session at the current leaf.
384
+ Clone {
385
+ /// Correlation id.
386
+ id: Option<String>,
387
+ },
388
+ /// List user messages available for forking.
389
+ GetForkMessages {
390
+ /// Correlation id.
391
+ id: Option<String>,
392
+ },
393
+ /// List session entries, optionally after `since`.
394
+ GetEntries {
395
+ /// Correlation id.
396
+ id: Option<String>,
397
+ /// Optional entry id; returns entries strictly after this id.
398
+ since: Option<String>,
399
+ },
400
+ /// Return the session tree.
401
+ GetTree {
402
+ /// Correlation id.
403
+ id: Option<String>,
404
+ },
405
+ /// Return the last assistant text content, if any.
406
+ GetLastAssistantText {
407
+ /// Correlation id.
408
+ id: Option<String>,
409
+ },
410
+ /// Set the display name of the current session.
411
+ SetSessionName {
412
+ /// Correlation id.
413
+ id: Option<String>,
414
+ /// New session name.
415
+ name: String,
416
+ },
417
+ /// Return all agent messages in the current session.
418
+ GetMessages {
419
+ /// Correlation id.
420
+ id: Option<String>,
421
+ },
422
+ /// List available slash commands (extension/prompt/skill).
423
+ GetCommands {
424
+ /// Correlation id.
425
+ id: Option<String>,
426
+ },
427
+ /// Unknown command discriminant preserved for error echo.
428
+ Unknown {
429
+ /// Correlation id when present.
430
+ id: Option<String>,
431
+ /// Raw `type` string from the wire.
432
+ command_type: String,
433
+ /// Remaining fields (excluding `type` and `id`).
434
+ payload: Map<String, Value>,
435
+ },
436
+ }
437
+
438
+ impl RpcCommand {
439
+ /// Optional correlation id shared by every command variant.
440
+ #[must_use]
441
+ pub fn id(&self) -> Option<&str> {
442
+ match self {
443
+ Self::Prompt { id, .. }
444
+ | Self::Steer { id, .. }
445
+ | Self::FollowUp { id, .. }
446
+ | Self::Abort { id }
447
+ | Self::NewSession { id, .. }
448
+ | Self::GetState { id }
449
+ | Self::SetModel { id, .. }
450
+ | Self::CycleModel { id }
451
+ | Self::GetAvailableModels { id }
452
+ | Self::SetThinkingLevel { id, .. }
453
+ | Self::CycleThinkingLevel { id }
454
+ | Self::SetSteeringMode { id, .. }
455
+ | Self::SetFollowUpMode { id, .. }
456
+ | Self::Compact { id, .. }
457
+ | Self::SetAutoCompaction { id, .. }
458
+ | Self::SetAutoRetry { id, .. }
459
+ | Self::AbortRetry { id }
460
+ | Self::Bash { id, .. }
461
+ | Self::AbortBash { id }
462
+ | Self::GetSessionStats { id }
463
+ | Self::ExportHtml { id, .. }
464
+ | Self::SwitchSession { id, .. }
465
+ | Self::Fork { id, .. }
466
+ | Self::Clone { id }
467
+ | Self::GetForkMessages { id }
468
+ | Self::GetEntries { id, .. }
469
+ | Self::GetTree { id }
470
+ | Self::GetLastAssistantText { id }
471
+ | Self::SetSessionName { id, .. }
472
+ | Self::GetMessages { id }
473
+ | Self::GetCommands { id }
474
+ | Self::Unknown { id, .. } => id.as_deref(),
475
+ }
476
+ }
477
+
478
+ /// Wire `type` discriminant for this command.
479
+ #[must_use]
480
+ pub fn command_type(&self) -> &str {
481
+ match self {
482
+ Self::Prompt { .. } => "prompt",
483
+ Self::Steer { .. } => "steer",
484
+ Self::FollowUp { .. } => "follow_up",
485
+ Self::Abort { .. } => "abort",
486
+ Self::NewSession { .. } => "new_session",
487
+ Self::GetState { .. } => "get_state",
488
+ Self::SetModel { .. } => "set_model",
489
+ Self::CycleModel { .. } => "cycle_model",
490
+ Self::GetAvailableModels { .. } => "get_available_models",
491
+ Self::SetThinkingLevel { .. } => "set_thinking_level",
492
+ Self::CycleThinkingLevel { .. } => "cycle_thinking_level",
493
+ Self::SetSteeringMode { .. } => "set_steering_mode",
494
+ Self::SetFollowUpMode { .. } => "set_follow_up_mode",
495
+ Self::Compact { .. } => "compact",
496
+ Self::SetAutoCompaction { .. } => "set_auto_compaction",
497
+ Self::SetAutoRetry { .. } => "set_auto_retry",
498
+ Self::AbortRetry { .. } => "abort_retry",
499
+ Self::Bash { .. } => "bash",
500
+ Self::AbortBash { .. } => "abort_bash",
501
+ Self::GetSessionStats { .. } => "get_session_stats",
502
+ Self::ExportHtml { .. } => "export_html",
503
+ Self::SwitchSession { .. } => "switch_session",
504
+ Self::Fork { .. } => "fork",
505
+ Self::Clone { .. } => "clone",
506
+ Self::GetForkMessages { .. } => "get_fork_messages",
507
+ Self::GetEntries { .. } => "get_entries",
508
+ Self::GetTree { .. } => "get_tree",
509
+ Self::GetLastAssistantText { .. } => "get_last_assistant_text",
510
+ Self::SetSessionName { .. } => "set_session_name",
511
+ Self::GetMessages { .. } => "get_messages",
512
+ Self::GetCommands { .. } => "get_commands",
513
+ Self::Unknown { command_type, .. } => command_type.as_str(),
514
+ }
515
+ }
516
+ }
517
+
518
+ impl Serialize for RpcCommand {
519
+ fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
520
+ where
521
+ S: Serializer,
522
+ {
523
+ serialize_rpc_command(self, serializer)
524
+ }
525
+ }
526
+
527
+ fn serialize_rpc_command<S: Serializer>(
528
+ command: &RpcCommand,
529
+ serializer: S,
530
+ ) -> Result<S::Ok, S::Error> {
531
+ match command {
532
+ RpcCommand::Prompt {
533
+ id,
534
+ message,
535
+ images,
536
+ streaming_behavior,
537
+ } => serialize_prompt(
538
+ serializer,
539
+ id.as_deref(),
540
+ message,
541
+ images.as_deref(),
542
+ *streaming_behavior,
543
+ ),
544
+ RpcCommand::Steer {
545
+ id,
546
+ message,
547
+ images,
548
+ } => serialize_message_images(
549
+ serializer,
550
+ id.as_deref(),
551
+ "steer",
552
+ message,
553
+ images.as_deref(),
554
+ ),
555
+ RpcCommand::FollowUp {
556
+ id,
557
+ message,
558
+ images,
559
+ } => serialize_message_images(
560
+ serializer,
561
+ id.as_deref(),
562
+ "follow_up",
563
+ message,
564
+ images.as_deref(),
565
+ ),
566
+ RpcCommand::Abort { id } => serialize_type_only(serializer, id.as_deref(), "abort"),
567
+ RpcCommand::NewSession { id, parent_session } => {
568
+ serialize_new_session(serializer, id.as_deref(), parent_session.as_deref())
569
+ }
570
+ RpcCommand::GetState { id } => serialize_type_only(serializer, id.as_deref(), "get_state"),
571
+ RpcCommand::SetModel {
572
+ id,
573
+ provider,
574
+ model_id,
575
+ } => serialize_set_model(serializer, id.as_deref(), provider, model_id),
576
+ RpcCommand::CycleModel { id } => {
577
+ serialize_type_only(serializer, id.as_deref(), "cycle_model")
578
+ }
579
+ RpcCommand::GetAvailableModels { id } => {
580
+ serialize_type_only(serializer, id.as_deref(), "get_available_models")
581
+ }
582
+ RpcCommand::SetThinkingLevel { id, level } => {
583
+ serialize_set_thinking_level(serializer, id.as_deref(), *level)
584
+ }
585
+ RpcCommand::CycleThinkingLevel { id } => {
586
+ serialize_type_only(serializer, id.as_deref(), "cycle_thinking_level")
587
+ }
588
+ RpcCommand::SetSteeringMode { id, mode } => {
589
+ serialize_queue_mode(serializer, id.as_deref(), "set_steering_mode", *mode)
590
+ }
591
+ RpcCommand::SetFollowUpMode { id, mode } => {
592
+ serialize_queue_mode(serializer, id.as_deref(), "set_follow_up_mode", *mode)
593
+ }
594
+ other => serialize_rpc_command_rest(other, serializer),
595
+ }
596
+ }
597
+
598
+ fn serialize_rpc_command_rest<S: Serializer>(
599
+ command: &RpcCommand,
600
+ serializer: S,
601
+ ) -> Result<S::Ok, S::Error> {
602
+ match command {
603
+ RpcCommand::Compact {
604
+ id,
605
+ custom_instructions,
606
+ } => serialize_compact(serializer, id.as_deref(), custom_instructions.as_deref()),
607
+ RpcCommand::SetAutoCompaction { id, enabled } => {
608
+ serialize_enabled(serializer, id.as_deref(), "set_auto_compaction", *enabled)
609
+ }
610
+ RpcCommand::SetAutoRetry { id, enabled } => {
611
+ serialize_enabled(serializer, id.as_deref(), "set_auto_retry", *enabled)
612
+ }
613
+ RpcCommand::AbortRetry { id } => {
614
+ serialize_type_only(serializer, id.as_deref(), "abort_retry")
615
+ }
616
+ RpcCommand::Bash {
617
+ id,
618
+ command,
619
+ exclude_from_context,
620
+ } => serialize_bash(serializer, id.as_deref(), command, *exclude_from_context),
621
+ RpcCommand::AbortBash { id } => {
622
+ serialize_type_only(serializer, id.as_deref(), "abort_bash")
623
+ }
624
+ RpcCommand::GetSessionStats { id } => {
625
+ serialize_type_only(serializer, id.as_deref(), "get_session_stats")
626
+ }
627
+ RpcCommand::ExportHtml { id, output_path } => {
628
+ serialize_export_html(serializer, id.as_deref(), output_path.as_deref())
629
+ }
630
+ RpcCommand::SwitchSession { id, session_path } => {
631
+ serialize_switch_session(serializer, id.as_deref(), session_path)
632
+ }
633
+ RpcCommand::Fork { id, entry_id } => serialize_fork(serializer, id.as_deref(), entry_id),
634
+ RpcCommand::Clone { id } => serialize_type_only(serializer, id.as_deref(), "clone"),
635
+ RpcCommand::GetForkMessages { id } => {
636
+ serialize_type_only(serializer, id.as_deref(), "get_fork_messages")
637
+ }
638
+ RpcCommand::GetEntries { id, since } => {
639
+ serialize_get_entries(serializer, id.as_deref(), since.as_deref())
640
+ }
641
+ RpcCommand::GetTree { id } => serialize_type_only(serializer, id.as_deref(), "get_tree"),
642
+ RpcCommand::GetLastAssistantText { id } => {
643
+ serialize_type_only(serializer, id.as_deref(), "get_last_assistant_text")
644
+ }
645
+ RpcCommand::SetSessionName { id, name } => {
646
+ serialize_set_session_name(serializer, id.as_deref(), name)
647
+ }
648
+ RpcCommand::GetMessages { id } => {
649
+ serialize_type_only(serializer, id.as_deref(), "get_messages")
650
+ }
651
+ RpcCommand::GetCommands { id } => {
652
+ serialize_type_only(serializer, id.as_deref(), "get_commands")
653
+ }
654
+ RpcCommand::Unknown {
655
+ id,
656
+ command_type,
657
+ payload,
658
+ } => serialize_unknown(serializer, id.as_deref(), command_type, payload),
659
+ _ => serialize_type_only(serializer, None, "abort"),
660
+ }
661
+ }
662
+
663
+ fn serialize_prompt<S: Serializer>(
664
+ serializer: S,
665
+ id: Option<&str>,
666
+ message: &str,
667
+ images: Option<&[ImageContent]>,
668
+ streaming_behavior: Option<StreamingBehavior>,
669
+ ) -> Result<S::Ok, S::Error> {
670
+ let mut map = serializer.serialize_map(None)?;
671
+ serialize_id(&mut map, id)?;
672
+ map.serialize_entry("type", "prompt")?;
673
+ map.serialize_entry("message", message)?;
674
+ if let Some(images) = images {
675
+ map.serialize_entry("images", images)?;
676
+ }
677
+ if let Some(behavior) = streaming_behavior {
678
+ map.serialize_entry("streamingBehavior", &behavior)?;
679
+ }
680
+ map.end()
681
+ }
682
+
683
+ fn serialize_message_images<S: Serializer>(
684
+ serializer: S,
685
+ id: Option<&str>,
686
+ type_name: &str,
687
+ message: &str,
688
+ images: Option<&[ImageContent]>,
689
+ ) -> Result<S::Ok, S::Error> {
690
+ let mut map = serializer.serialize_map(None)?;
691
+ serialize_id(&mut map, id)?;
692
+ map.serialize_entry("type", type_name)?;
693
+ map.serialize_entry("message", message)?;
694
+ if let Some(images) = images {
695
+ map.serialize_entry("images", images)?;
696
+ }
697
+ map.end()
698
+ }
699
+
700
+ fn serialize_new_session<S: Serializer>(
701
+ serializer: S,
702
+ id: Option<&str>,
703
+ parent_session: Option<&str>,
704
+ ) -> Result<S::Ok, S::Error> {
705
+ let mut map = serializer.serialize_map(None)?;
706
+ serialize_id(&mut map, id)?;
707
+ map.serialize_entry("type", "new_session")?;
708
+ if let Some(parent) = parent_session {
709
+ map.serialize_entry("parentSession", parent)?;
710
+ }
711
+ map.end()
712
+ }
713
+
714
+ fn serialize_set_model<S: Serializer>(
715
+ serializer: S,
716
+ id: Option<&str>,
717
+ provider: &str,
718
+ model_id: &str,
719
+ ) -> Result<S::Ok, S::Error> {
720
+ let mut map = serializer.serialize_map(None)?;
721
+ serialize_id(&mut map, id)?;
722
+ map.serialize_entry("type", "set_model")?;
723
+ map.serialize_entry("provider", provider)?;
724
+ map.serialize_entry("modelId", model_id)?;
725
+ map.end()
726
+ }
727
+
728
+ fn serialize_set_thinking_level<S: Serializer>(
729
+ serializer: S,
730
+ id: Option<&str>,
731
+ level: ModelThinkingLevel,
732
+ ) -> Result<S::Ok, S::Error> {
733
+ let mut map = serializer.serialize_map(None)?;
734
+ serialize_id(&mut map, id)?;
735
+ map.serialize_entry("type", "set_thinking_level")?;
736
+ map.serialize_entry("level", &level)?;
737
+ map.end()
738
+ }
739
+
740
+ fn serialize_queue_mode<S: Serializer>(
741
+ serializer: S,
742
+ id: Option<&str>,
743
+ type_name: &str,
744
+ mode: QueueMode,
745
+ ) -> Result<S::Ok, S::Error> {
746
+ let mut map = serializer.serialize_map(None)?;
747
+ serialize_id(&mut map, id)?;
748
+ map.serialize_entry("type", type_name)?;
749
+ map.serialize_entry("mode", &mode)?;
750
+ map.end()
751
+ }
752
+
753
+ fn serialize_compact<S: Serializer>(
754
+ serializer: S,
755
+ id: Option<&str>,
756
+ custom_instructions: Option<&str>,
757
+ ) -> Result<S::Ok, S::Error> {
758
+ let mut map = serializer.serialize_map(None)?;
759
+ serialize_id(&mut map, id)?;
760
+ map.serialize_entry("type", "compact")?;
761
+ if let Some(custom) = custom_instructions {
762
+ map.serialize_entry("customInstructions", custom)?;
763
+ }
764
+ map.end()
765
+ }
766
+
767
+ fn serialize_enabled<S: Serializer>(
768
+ serializer: S,
769
+ id: Option<&str>,
770
+ type_name: &str,
771
+ enabled: bool,
772
+ ) -> Result<S::Ok, S::Error> {
773
+ let mut map = serializer.serialize_map(None)?;
774
+ serialize_id(&mut map, id)?;
775
+ map.serialize_entry("type", type_name)?;
776
+ map.serialize_entry("enabled", &enabled)?;
777
+ map.end()
778
+ }
779
+
780
+ fn serialize_bash<S: Serializer>(
781
+ serializer: S,
782
+ id: Option<&str>,
783
+ command: &str,
784
+ exclude_from_context: Option<bool>,
785
+ ) -> Result<S::Ok, S::Error> {
786
+ let mut map = serializer.serialize_map(None)?;
787
+ serialize_id(&mut map, id)?;
788
+ map.serialize_entry("type", "bash")?;
789
+ map.serialize_entry("command", command)?;
790
+ if let Some(exclude) = exclude_from_context {
791
+ map.serialize_entry("excludeFromContext", &exclude)?;
792
+ }
793
+ map.end()
794
+ }
795
+
796
+ fn serialize_export_html<S: Serializer>(
797
+ serializer: S,
798
+ id: Option<&str>,
799
+ output_path: Option<&str>,
800
+ ) -> Result<S::Ok, S::Error> {
801
+ let mut map = serializer.serialize_map(None)?;
802
+ serialize_id(&mut map, id)?;
803
+ map.serialize_entry("type", "export_html")?;
804
+ if let Some(path) = output_path {
805
+ map.serialize_entry("outputPath", path)?;
806
+ }
807
+ map.end()
808
+ }
809
+
810
+ fn serialize_switch_session<S: Serializer>(
811
+ serializer: S,
812
+ id: Option<&str>,
813
+ session_path: &str,
814
+ ) -> Result<S::Ok, S::Error> {
815
+ let mut map = serializer.serialize_map(None)?;
816
+ serialize_id(&mut map, id)?;
817
+ map.serialize_entry("type", "switch_session")?;
818
+ map.serialize_entry("sessionPath", session_path)?;
819
+ map.end()
820
+ }
821
+
822
+ fn serialize_fork<S: Serializer>(
823
+ serializer: S,
824
+ id: Option<&str>,
825
+ entry_id: &str,
826
+ ) -> Result<S::Ok, S::Error> {
827
+ let mut map = serializer.serialize_map(None)?;
828
+ serialize_id(&mut map, id)?;
829
+ map.serialize_entry("type", "fork")?;
830
+ map.serialize_entry("entryId", entry_id)?;
831
+ map.end()
832
+ }
833
+
834
+ fn serialize_get_entries<S: Serializer>(
835
+ serializer: S,
836
+ id: Option<&str>,
837
+ since: Option<&str>,
838
+ ) -> Result<S::Ok, S::Error> {
839
+ let mut map = serializer.serialize_map(None)?;
840
+ serialize_id(&mut map, id)?;
841
+ map.serialize_entry("type", "get_entries")?;
842
+ if let Some(since) = since {
843
+ map.serialize_entry("since", since)?;
844
+ }
845
+ map.end()
846
+ }
847
+
848
+ fn serialize_set_session_name<S: Serializer>(
849
+ serializer: S,
850
+ id: Option<&str>,
851
+ name: &str,
852
+ ) -> Result<S::Ok, S::Error> {
853
+ let mut map = serializer.serialize_map(None)?;
854
+ serialize_id(&mut map, id)?;
855
+ map.serialize_entry("type", "set_session_name")?;
856
+ map.serialize_entry("name", name)?;
857
+ map.end()
858
+ }
859
+
860
+ fn serialize_unknown<S: Serializer>(
861
+ serializer: S,
862
+ id: Option<&str>,
863
+ command_type: &str,
864
+ payload: &Map<String, Value>,
865
+ ) -> Result<S::Ok, S::Error> {
866
+ let mut map = serializer.serialize_map(None)?;
867
+ serialize_id(&mut map, id)?;
868
+ map.serialize_entry("type", command_type)?;
869
+ for (key, value) in payload {
870
+ map.serialize_entry(key, value)?;
871
+ }
872
+ map.end()
873
+ }
874
+
875
+ impl<'de> Deserialize<'de> for RpcCommand {
876
+ fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
877
+ where
878
+ D: Deserializer<'de>,
879
+ {
880
+ let value = Value::deserialize(deserializer)?;
881
+ Self::parse_value(&value).map_err(|error| de::Error::custom(error.message))
882
+ }
883
+ }
884
+
885
+ #[derive(Debug)]
886
+ pub(crate) struct RpcCommandParseError {
887
+ pub(crate) id: Option<String>,
888
+ pub(crate) message: String,
889
+ }
890
+
891
+ impl RpcCommand {
892
+ pub(crate) fn parse_value(value: &Value) -> Result<Self, RpcCommandParseError> {
893
+ let obj = value.as_object().ok_or_else(|| RpcCommandParseError {
894
+ id: None,
895
+ message: "rpc command must be a JSON object".to_owned(),
896
+ })?;
897
+ let id = optional_string(obj, "id")
898
+ .map_err(|message| RpcCommandParseError { id: None, message })?;
899
+ let command_type = obj
900
+ .get("type")
901
+ .and_then(Value::as_str)
902
+ .ok_or_else(|| RpcCommandParseError {
903
+ id: id.clone(),
904
+ message: "rpc command missing type".to_owned(),
905
+ })?
906
+ .to_owned();
907
+ parse_known_command(obj, id.clone(), command_type)
908
+ .map_err(|message| RpcCommandParseError { id, message })
909
+ }
910
+ }
911
+
912
+ fn parse_known_command(
913
+ obj: &Map<String, Value>,
914
+ id: Option<String>,
915
+ command_type: String,
916
+ ) -> Result<RpcCommand, String> {
917
+ match command_type.as_str() {
918
+ "prompt" => parse_prompt(obj, id),
919
+ "steer" => parse_message_images_cmd(obj, id, "steer"),
920
+ "follow_up" => parse_message_images_cmd(obj, id, "follow_up"),
921
+ "abort" => Ok(RpcCommand::Abort { id }),
922
+ "new_session" => Ok(RpcCommand::NewSession {
923
+ id,
924
+ parent_session: optional_string(obj, "parentSession")?,
925
+ }),
926
+ "get_state" => Ok(RpcCommand::GetState { id }),
927
+ "set_model" => Ok(RpcCommand::SetModel {
928
+ id,
929
+ provider: required_string_owned(obj, "provider")?,
930
+ model_id: required_string_owned(obj, "modelId")?,
931
+ }),
932
+ "cycle_model" => Ok(RpcCommand::CycleModel { id }),
933
+ "get_available_models" => Ok(RpcCommand::GetAvailableModels { id }),
934
+ "set_thinking_level" => parse_set_thinking_level(obj, id),
935
+ "cycle_thinking_level" => Ok(RpcCommand::CycleThinkingLevel { id }),
936
+ "set_steering_mode" => parse_queue_mode_cmd(obj, id, true),
937
+ "set_follow_up_mode" => parse_queue_mode_cmd(obj, id, false),
938
+ "compact" => Ok(RpcCommand::Compact {
939
+ id,
940
+ custom_instructions: optional_string(obj, "customInstructions")?,
941
+ }),
942
+ "set_auto_compaction" => Ok(RpcCommand::SetAutoCompaction {
943
+ id,
944
+ enabled: required_bool_owned(obj, "enabled")?,
945
+ }),
946
+ "set_auto_retry" => Ok(RpcCommand::SetAutoRetry {
947
+ id,
948
+ enabled: required_bool_owned(obj, "enabled")?,
949
+ }),
950
+ "abort_retry" => Ok(RpcCommand::AbortRetry { id }),
951
+ "bash" => Ok(RpcCommand::Bash {
952
+ id,
953
+ command: required_string_owned(obj, "command")?,
954
+ exclude_from_context: optional_bool(obj, "excludeFromContext")?,
955
+ }),
956
+ "abort_bash" => Ok(RpcCommand::AbortBash { id }),
957
+ "get_session_stats" => Ok(RpcCommand::GetSessionStats { id }),
958
+ "export_html" => Ok(RpcCommand::ExportHtml {
959
+ id,
960
+ output_path: optional_string(obj, "outputPath")?,
961
+ }),
962
+ "switch_session" => Ok(RpcCommand::SwitchSession {
963
+ id,
964
+ session_path: required_string_owned(obj, "sessionPath")?,
965
+ }),
966
+ "fork" => Ok(RpcCommand::Fork {
967
+ id,
968
+ entry_id: required_string_owned(obj, "entryId")?,
969
+ }),
970
+ "clone" => Ok(RpcCommand::Clone { id }),
971
+ "get_fork_messages" => Ok(RpcCommand::GetForkMessages { id }),
972
+ "get_entries" => Ok(RpcCommand::GetEntries {
973
+ id,
974
+ since: optional_string(obj, "since")?,
975
+ }),
976
+ "get_tree" => Ok(RpcCommand::GetTree { id }),
977
+ "get_last_assistant_text" => Ok(RpcCommand::GetLastAssistantText { id }),
978
+ "set_session_name" => Ok(RpcCommand::SetSessionName {
979
+ id,
980
+ name: required_string_owned(obj, "name")?,
981
+ }),
982
+ "get_messages" => Ok(RpcCommand::GetMessages { id }),
983
+ "get_commands" => Ok(RpcCommand::GetCommands { id }),
984
+ _ => Ok(parse_unknown_command(obj, id, command_type)),
985
+ }
986
+ }
987
+
988
+ fn parse_prompt(obj: &Map<String, Value>, id: Option<String>) -> Result<RpcCommand, String> {
989
+ let message = required_string_owned(obj, "message")?;
990
+ let images = optional_images_owned(obj)?;
991
+ let streaming_behavior = match obj.get("streamingBehavior") {
992
+ None | Some(Value::Null) => None,
993
+ Some(v) => Some(StreamingBehavior::deserialize(v).map_err(|e| e.to_string())?),
994
+ };
995
+ Ok(RpcCommand::Prompt {
996
+ id,
997
+ message,
998
+ images,
999
+ streaming_behavior,
1000
+ })
1001
+ }
1002
+
1003
+ fn parse_message_images_cmd(
1004
+ obj: &Map<String, Value>,
1005
+ id: Option<String>,
1006
+ kind: &str,
1007
+ ) -> Result<RpcCommand, String> {
1008
+ let message = required_string_owned(obj, "message")?;
1009
+ let images = optional_images_owned(obj)?;
1010
+ match kind {
1011
+ "steer" => Ok(RpcCommand::Steer {
1012
+ id,
1013
+ message,
1014
+ images,
1015
+ }),
1016
+ _ => Ok(RpcCommand::FollowUp {
1017
+ id,
1018
+ message,
1019
+ images,
1020
+ }),
1021
+ }
1022
+ }
1023
+
1024
+ fn parse_set_thinking_level(
1025
+ obj: &Map<String, Value>,
1026
+ id: Option<String>,
1027
+ ) -> Result<RpcCommand, String> {
1028
+ let level = obj
1029
+ .get("level")
1030
+ .ok_or_else(|| "set_thinking_level missing level".to_owned())?;
1031
+ let level = ModelThinkingLevel::deserialize(level).map_err(|e| e.to_string())?;
1032
+ Ok(RpcCommand::SetThinkingLevel { id, level })
1033
+ }
1034
+
1035
+ fn parse_queue_mode_cmd(
1036
+ obj: &Map<String, Value>,
1037
+ id: Option<String>,
1038
+ steering: bool,
1039
+ ) -> Result<RpcCommand, String> {
1040
+ let mode = obj
1041
+ .get("mode")
1042
+ .ok_or_else(|| "queue mode command missing mode".to_owned())?;
1043
+ let mode = QueueMode::deserialize(mode).map_err(|e| e.to_string())?;
1044
+ if steering {
1045
+ Ok(RpcCommand::SetSteeringMode { id, mode })
1046
+ } else {
1047
+ Ok(RpcCommand::SetFollowUpMode { id, mode })
1048
+ }
1049
+ }
1050
+
1051
+ fn parse_unknown_command(
1052
+ obj: &Map<String, Value>,
1053
+ id: Option<String>,
1054
+ command_type: String,
1055
+ ) -> RpcCommand {
1056
+ let mut payload = Map::new();
1057
+ for (key, value) in obj {
1058
+ if key == "type" || key == "id" {
1059
+ continue;
1060
+ }
1061
+ payload.insert(key.clone(), value.clone());
1062
+ }
1063
+ RpcCommand::Unknown {
1064
+ id,
1065
+ command_type,
1066
+ payload,
1067
+ }
1068
+ }
1069
+
1070
+ fn required_string_owned(obj: &Map<String, Value>, key: &str) -> Result<String, String> {
1071
+ match obj.get(key) {
1072
+ Some(Value::String(s)) => Ok(s.clone()),
1073
+ Some(other) => Err(format!("field {key} must be a string, got {other}")),
1074
+ None => Err(format!("missing field {key}")),
1075
+ }
1076
+ }
1077
+
1078
+ fn required_bool_owned(obj: &Map<String, Value>, key: &str) -> Result<bool, String> {
1079
+ match obj.get(key) {
1080
+ Some(Value::Bool(b)) => Ok(*b),
1081
+ Some(other) => Err(format!("field {key} must be a boolean, got {other}")),
1082
+ None => Err(format!("missing field {key}")),
1083
+ }
1084
+ }
1085
+
1086
+ fn optional_images_owned(obj: &Map<String, Value>) -> Result<Option<Vec<ImageContent>>, String> {
1087
+ match obj.get("images") {
1088
+ None | Some(Value::Null) => Ok(None),
1089
+ Some(v) => {
1090
+ let images = Vec::<ImageContent>::deserialize(v).map_err(|e| e.to_string())?;
1091
+ Ok(Some(images))
1092
+ }
1093
+ }
1094
+ }
1095
+
1096
+ // ---------------------------------------------------------------------------
1097
+ // RpcSessionState / RpcSlashCommand
1098
+ // ---------------------------------------------------------------------------
1099
+
1100
+ /// Snapshot returned by `get_state`.
1101
+ #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
1102
+ #[serde(rename_all = "camelCase")]
1103
+ pub struct RpcSessionState {
1104
+ /// Active model, if any.
1105
+ #[serde(default, skip_serializing_if = "Option::is_none")]
1106
+ pub model: Option<Model>,
1107
+ /// Current thinking level (includes `off`).
1108
+ pub thinking_level: ModelThinkingLevel,
1109
+ /// Whether the agent is currently streaming.
1110
+ pub is_streaming: bool,
1111
+ /// Whether compaction is in progress.
1112
+ pub is_compacting: bool,
1113
+ /// Steering queue drain mode.
1114
+ pub steering_mode: QueueMode,
1115
+ /// Follow-up queue drain mode.
1116
+ pub follow_up_mode: QueueMode,
1117
+ /// Absolute session file path, when persisted.
1118
+ #[serde(default, skip_serializing_if = "Option::is_none")]
1119
+ pub session_file: Option<String>,
1120
+ /// Session id.
1121
+ pub session_id: String,
1122
+ /// Optional display name.
1123
+ #[serde(default, skip_serializing_if = "Option::is_none")]
1124
+ pub session_name: Option<String>,
1125
+ /// Whether auto-compaction is enabled.
1126
+ pub auto_compaction_enabled: bool,
1127
+ /// Number of messages currently in the session.
1128
+ pub message_count: u64,
1129
+ /// Number of pending queued messages.
1130
+ pub pending_message_count: u64,
1131
+ }
1132
+
1133
+ /// Kind of slash command exposed by `get_commands`.
1134
+ #[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize, Deserialize)]
1135
+ #[serde(rename_all = "camelCase")]
1136
+ pub enum RpcSlashCommandSource {
1137
+ /// Registered by a TypeScript extension.
1138
+ Extension,
1139
+ /// Prompt template.
1140
+ Prompt,
1141
+ /// Skill (`skill:{name}`).
1142
+ Skill,
1143
+ }
1144
+
1145
+ /// A command available for invocation via prompt.
1146
+ #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
1147
+ #[serde(rename_all = "camelCase")]
1148
+ pub struct RpcSlashCommand {
1149
+ /// Command name (without leading slash).
1150
+ pub name: String,
1151
+ /// Human-readable description.
1152
+ #[serde(default, skip_serializing_if = "Option::is_none")]
1153
+ pub description: Option<String>,
1154
+ /// What kind of command this is.
1155
+ pub source: RpcSlashCommandSource,
1156
+ /// Source metadata for the owning resource.
1157
+ pub source_info: RpcSourceInfo,
1158
+ }
1159
+
1160
+ // ---------------------------------------------------------------------------
1161
+ // RpcResponse (stdout)
1162
+ // ---------------------------------------------------------------------------
1163
+
1164
+ /// Typed success payload for each command that returns `data`.
1165
+ ///
1166
+ /// Serialization is untagged (payload is the raw `data` object). Deserialization
1167
+ /// of full responses is command-directed via [`RpcResponse`] so overlapping
1168
+ /// shapes (e.g. `{cancelled}` vs bash `{cancelled,...}`) never collide.
1169
+ #[derive(Clone, Debug, PartialEq, Serialize)]
1170
+ #[serde(untagged)]
1171
+ pub enum RpcResponseData {
1172
+ /// `{ cancelled }` for `new_session` / `switch_session` / `clone`.
1173
+ Cancelled {
1174
+ /// Whether the user cancelled the operation.
1175
+ cancelled: bool,
1176
+ },
1177
+ /// Full session state.
1178
+ SessionState(RpcSessionState),
1179
+ /// Selected model from `set_model`.
1180
+ Model(Model),
1181
+ /// `cycle_model` result (or JSON `null`).
1182
+ CycleModel(Option<CycleModelData>),
1183
+ /// `{ models: [...] }` from `get_available_models`.
1184
+ AvailableModels {
1185
+ /// Available models.
1186
+ models: Vec<Model>,
1187
+ },
1188
+ /// `cycle_thinking_level` result (or JSON `null`).
1189
+ CycleThinkingLevel(Option<CycleThinkingLevelData>),
1190
+ /// Compaction result.
1191
+ Compaction(CompactionResult),
1192
+ /// Bash result.
1193
+ Bash(BashResult),
1194
+ /// Session stats.
1195
+ SessionStats(SessionStats),
1196
+ /// `{ path }` from `export_html`.
1197
+ ExportHtml {
1198
+ /// Written HTML path.
1199
+ path: String,
1200
+ },
1201
+ /// `{ text, cancelled }` from `fork`.
1202
+ Fork {
1203
+ /// Selected user text at the fork point.
1204
+ text: String,
1205
+ /// Whether the user cancelled.
1206
+ cancelled: bool,
1207
+ },
1208
+ /// `{ messages: [{ entryId, text }] }` from `get_fork_messages`.
1209
+ ForkMessages {
1210
+ /// Forkable user messages.
1211
+ messages: Vec<ForkMessage>,
1212
+ },
1213
+ /// `{ entries, leafId }` from `get_entries`.
1214
+ Entries {
1215
+ /// Session entries.
1216
+ entries: Vec<SessionEntry>,
1217
+ /// Current leaf id.
1218
+ #[serde(rename = "leafId")]
1219
+ leaf_id: Option<String>,
1220
+ },
1221
+ /// `{ tree, leafId }` from `get_tree`.
1222
+ Tree {
1223
+ /// Session tree.
1224
+ tree: Vec<RpcSessionTreeNode>,
1225
+ /// Current leaf id.
1226
+ #[serde(rename = "leafId")]
1227
+ leaf_id: Option<String>,
1228
+ },
1229
+ /// `{ text }` from `get_last_assistant_text` (text may be null).
1230
+ LastAssistantText {
1231
+ /// Last assistant text, or null.
1232
+ text: Option<String>,
1233
+ },
1234
+ /// `{ messages }` from `get_messages`.
1235
+ Messages {
1236
+ /// Agent messages.
1237
+ messages: Vec<AgentMessage>,
1238
+ },
1239
+ /// `{ commands }` from `get_commands`.
1240
+ Commands {
1241
+ /// Available slash commands.
1242
+ commands: Vec<RpcSlashCommand>,
1243
+ },
1244
+ }
1245
+
1246
+ impl RpcResponseData {
1247
+ /// Deserialize a `data` payload using the echoed command discriminant.
1248
+ fn deserialize_for_command(command: &str, value: &Value) -> Result<Self, String> {
1249
+ match command {
1250
+ "new_session" | "switch_session" | "clone" => parse_cancelled_data(command, value),
1251
+ "get_state" => Ok(Self::SessionState(
1252
+ RpcSessionState::deserialize(value).map_err(|e| e.to_string())?,
1253
+ )),
1254
+ "set_model" => Ok(Self::Model(
1255
+ Model::deserialize(value).map_err(|e| e.to_string())?,
1256
+ )),
1257
+ "cycle_model" => parse_cycle_model_data(value),
1258
+ "get_available_models" => parse_available_models_data(value),
1259
+ "cycle_thinking_level" => parse_cycle_thinking_data(value),
1260
+ "compact" => Ok(Self::Compaction(
1261
+ CompactionResult::deserialize(value).map_err(|e| e.to_string())?,
1262
+ )),
1263
+ "bash" => Ok(Self::Bash(
1264
+ BashResult::deserialize(value).map_err(|e| e.to_string())?,
1265
+ )),
1266
+ "get_session_stats" => Ok(Self::SessionStats(
1267
+ SessionStats::deserialize(value).map_err(|e| e.to_string())?,
1268
+ )),
1269
+ "export_html" => parse_export_html_data(value),
1270
+ "fork" => parse_fork_data(value),
1271
+ "get_fork_messages" => parse_fork_messages_data(value),
1272
+ "get_entries" => parse_entries_data(value),
1273
+ "get_tree" => parse_tree_data(value),
1274
+ "get_last_assistant_text" => parse_last_assistant_text_data(value),
1275
+ "get_messages" => parse_messages_data(value),
1276
+ "get_commands" => parse_commands_data(value),
1277
+ other => Err(format!("no typed data parser for command {other}")),
1278
+ }
1279
+ }
1280
+ }
1281
+
1282
+ fn parse_cancelled_data(command: &str, value: &Value) -> Result<RpcResponseData, String> {
1283
+ let cancelled = value
1284
+ .get("cancelled")
1285
+ .and_then(Value::as_bool)
1286
+ .ok_or_else(|| format!("{command} data missing cancelled"))?;
1287
+ Ok(RpcResponseData::Cancelled { cancelled })
1288
+ }
1289
+
1290
+ fn parse_cycle_model_data(value: &Value) -> Result<RpcResponseData, String> {
1291
+ if value.is_null() {
1292
+ return Ok(RpcResponseData::CycleModel(None));
1293
+ }
1294
+ let data = CycleModelData::deserialize(value).map_err(|e| e.to_string())?;
1295
+ Ok(RpcResponseData::CycleModel(Some(data)))
1296
+ }
1297
+
1298
+ fn parse_available_models_data(value: &Value) -> Result<RpcResponseData, String> {
1299
+ let models = value
1300
+ .get("models")
1301
+ .ok_or_else(|| "get_available_models data missing models".to_owned())?;
1302
+ let models = Vec::<Model>::deserialize(models).map_err(|e| e.to_string())?;
1303
+ Ok(RpcResponseData::AvailableModels { models })
1304
+ }
1305
+
1306
+ fn parse_cycle_thinking_data(value: &Value) -> Result<RpcResponseData, String> {
1307
+ if value.is_null() {
1308
+ return Ok(RpcResponseData::CycleThinkingLevel(None));
1309
+ }
1310
+ let data = CycleThinkingLevelData::deserialize(value).map_err(|e| e.to_string())?;
1311
+ Ok(RpcResponseData::CycleThinkingLevel(Some(data)))
1312
+ }
1313
+
1314
+ fn parse_export_html_data(value: &Value) -> Result<RpcResponseData, String> {
1315
+ let path = value
1316
+ .get("path")
1317
+ .and_then(Value::as_str)
1318
+ .ok_or_else(|| "export_html data missing path".to_owned())?
1319
+ .to_owned();
1320
+ Ok(RpcResponseData::ExportHtml { path })
1321
+ }
1322
+
1323
+ fn parse_fork_data(value: &Value) -> Result<RpcResponseData, String> {
1324
+ let text = value
1325
+ .get("text")
1326
+ .and_then(Value::as_str)
1327
+ .ok_or_else(|| "fork data missing text".to_owned())?
1328
+ .to_owned();
1329
+ let cancelled = value
1330
+ .get("cancelled")
1331
+ .and_then(Value::as_bool)
1332
+ .ok_or_else(|| "fork data missing cancelled".to_owned())?;
1333
+ Ok(RpcResponseData::Fork { text, cancelled })
1334
+ }
1335
+
1336
+ fn parse_fork_messages_data(value: &Value) -> Result<RpcResponseData, String> {
1337
+ let messages = value
1338
+ .get("messages")
1339
+ .ok_or_else(|| "get_fork_messages data missing messages".to_owned())?;
1340
+ let messages = Vec::<ForkMessage>::deserialize(messages).map_err(|e| e.to_string())?;
1341
+ Ok(RpcResponseData::ForkMessages { messages })
1342
+ }
1343
+
1344
+ fn parse_leaf_id(value: &Value, command: &str) -> Result<Option<String>, String> {
1345
+ match value.get("leafId") {
1346
+ None | Some(Value::Null) => Ok(None),
1347
+ Some(Value::String(s)) => Ok(Some(s.clone())),
1348
+ Some(other) => Err(format!("{command} leafId must be string|null, got {other}")),
1349
+ }
1350
+ }
1351
+
1352
+ fn parse_entries_data(value: &Value) -> Result<RpcResponseData, String> {
1353
+ let entries = value
1354
+ .get("entries")
1355
+ .ok_or_else(|| "get_entries data missing entries".to_owned())?;
1356
+ let entries = Vec::<SessionEntry>::deserialize(entries).map_err(|e| e.to_string())?;
1357
+ let leaf_id = parse_leaf_id(value, "get_entries")?;
1358
+ Ok(RpcResponseData::Entries { entries, leaf_id })
1359
+ }
1360
+
1361
+ fn parse_tree_data(value: &Value) -> Result<RpcResponseData, String> {
1362
+ let tree = value
1363
+ .get("tree")
1364
+ .ok_or_else(|| "get_tree data missing tree".to_owned())?;
1365
+ let tree = Vec::<RpcSessionTreeNode>::deserialize(tree).map_err(|e| e.to_string())?;
1366
+ let leaf_id = parse_leaf_id(value, "get_tree")?;
1367
+ Ok(RpcResponseData::Tree { tree, leaf_id })
1368
+ }
1369
+
1370
+ fn parse_last_assistant_text_data(value: &Value) -> Result<RpcResponseData, String> {
1371
+ let text = match value.get("text") {
1372
+ None | Some(Value::Null) => None,
1373
+ Some(Value::String(s)) => Some(s.clone()),
1374
+ Some(other) => {
1375
+ return Err(format!(
1376
+ "get_last_assistant_text text must be string|null, got {other}"
1377
+ ));
1378
+ }
1379
+ };
1380
+ Ok(RpcResponseData::LastAssistantText { text })
1381
+ }
1382
+
1383
+ fn parse_messages_data(value: &Value) -> Result<RpcResponseData, String> {
1384
+ let messages = value
1385
+ .get("messages")
1386
+ .ok_or_else(|| "get_messages data missing messages".to_owned())?;
1387
+ let messages = Vec::<AgentMessage>::deserialize(messages).map_err(|e| e.to_string())?;
1388
+ Ok(RpcResponseData::Messages { messages })
1389
+ }
1390
+
1391
+ fn parse_commands_data(value: &Value) -> Result<RpcResponseData, String> {
1392
+ let commands = value
1393
+ .get("commands")
1394
+ .ok_or_else(|| "get_commands data missing commands".to_owned())?;
1395
+ let commands = Vec::<RpcSlashCommand>::deserialize(commands).map_err(|e| e.to_string())?;
1396
+ Ok(RpcResponseData::Commands { commands })
1397
+ }
1398
+
1399
+ /// Payload for a successful `cycle_model` response.
1400
+ #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
1401
+ #[serde(rename_all = "camelCase")]
1402
+ pub struct CycleModelData {
1403
+ /// Newly selected model.
1404
+ pub model: Model,
1405
+ /// Thinking level after the cycle.
1406
+ pub thinking_level: ModelThinkingLevel,
1407
+ /// Whether the model is scoped.
1408
+ pub is_scoped: bool,
1409
+ }
1410
+
1411
+ /// Payload for a successful `cycle_thinking_level` response.
1412
+ #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
1413
+ #[serde(rename_all = "camelCase")]
1414
+ pub struct CycleThinkingLevelData {
1415
+ /// New thinking level.
1416
+ pub level: ModelThinkingLevel,
1417
+ }
1418
+
1419
+ /// One forkable user message.
1420
+ #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
1421
+ #[serde(rename_all = "camelCase")]
1422
+ pub struct ForkMessage {
1423
+ /// Entry id.
1424
+ pub entry_id: String,
1425
+ /// User text.
1426
+ pub text: String,
1427
+ }
1428
+
1429
+ /// Success or error response envelope (`type: "response"`).
1430
+ #[derive(Clone, Debug, PartialEq)]
1431
+ pub enum RpcResponse {
1432
+ /// Successful command response.
1433
+ Success {
1434
+ /// Correlation id.
1435
+ id: Option<String>,
1436
+ /// Command discriminant echoed back.
1437
+ command: String,
1438
+ /// Optional typed data payload (boxed: variants differ widely in size).
1439
+ data: Option<Box<RpcResponseData>>,
1440
+ },
1441
+ /// Failed command response.
1442
+ Error {
1443
+ /// Correlation id (echoed when known).
1444
+ id: Option<String>,
1445
+ /// Command discriminant or `"parse"`.
1446
+ command: String,
1447
+ /// Error message.
1448
+ error: String,
1449
+ },
1450
+ }
1451
+
1452
+ impl RpcResponse {
1453
+ /// Build a success response with no data.
1454
+ #[must_use]
1455
+ pub fn ok(id: Option<String>, command: impl Into<String>) -> Self {
1456
+ Self::Success {
1457
+ id,
1458
+ command: command.into(),
1459
+ data: None,
1460
+ }
1461
+ }
1462
+
1463
+ /// Build a success response with data.
1464
+ #[must_use]
1465
+ pub fn ok_data(id: Option<String>, command: impl Into<String>, data: RpcResponseData) -> Self {
1466
+ Self::Success {
1467
+ id,
1468
+ command: command.into(),
1469
+ data: Some(Box::new(data)),
1470
+ }
1471
+ }
1472
+
1473
+ /// Build an error response.
1474
+ #[must_use]
1475
+ pub fn err(id: Option<String>, command: impl Into<String>, error: impl Into<String>) -> Self {
1476
+ Self::Error {
1477
+ id,
1478
+ command: command.into(),
1479
+ error: error.into(),
1480
+ }
1481
+ }
1482
+
1483
+ /// Correlation id.
1484
+ #[must_use]
1485
+ pub fn id(&self) -> Option<&str> {
1486
+ match self {
1487
+ Self::Success { id, .. } | Self::Error { id, .. } => id.as_deref(),
1488
+ }
1489
+ }
1490
+
1491
+ /// Echoed command discriminant.
1492
+ #[must_use]
1493
+ pub fn command(&self) -> &str {
1494
+ match self {
1495
+ Self::Success { command, .. } | Self::Error { command, .. } => command.as_str(),
1496
+ }
1497
+ }
1498
+
1499
+ /// Whether this is a success response.
1500
+ #[must_use]
1501
+ pub const fn is_success(&self) -> bool {
1502
+ matches!(self, Self::Success { .. })
1503
+ }
1504
+ }
1505
+
1506
+ impl Serialize for RpcResponse {
1507
+ fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1508
+ where
1509
+ S: Serializer,
1510
+ {
1511
+ match self {
1512
+ Self::Success { id, command, data } => {
1513
+ let mut map = serializer.serialize_map(None)?;
1514
+ serialize_id(&mut map, id.as_deref())?;
1515
+ map.serialize_entry("type", "response")?;
1516
+ map.serialize_entry("command", command)?;
1517
+ map.serialize_entry("success", &true)?;
1518
+ if let Some(data) = data {
1519
+ map.serialize_entry("data", data.as_ref())?;
1520
+ }
1521
+ map.end()
1522
+ }
1523
+ Self::Error { id, command, error } => {
1524
+ let mut map = serializer.serialize_map(None)?;
1525
+ serialize_id(&mut map, id.as_deref())?;
1526
+ map.serialize_entry("type", "response")?;
1527
+ map.serialize_entry("command", command)?;
1528
+ map.serialize_entry("success", &false)?;
1529
+ map.serialize_entry("error", error)?;
1530
+ map.end()
1531
+ }
1532
+ }
1533
+ }
1534
+ }
1535
+
1536
+ impl<'de> Deserialize<'de> for RpcResponse {
1537
+ fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
1538
+ where
1539
+ D: Deserializer<'de>,
1540
+ {
1541
+ let value = Value::deserialize(deserializer)?;
1542
+ let obj = value
1543
+ .as_object()
1544
+ .ok_or_else(|| de::Error::custom("rpc response must be a JSON object"))?;
1545
+
1546
+ let type_field = obj
1547
+ .get("type")
1548
+ .and_then(Value::as_str)
1549
+ .ok_or_else(|| de::Error::custom("rpc response missing type"))?;
1550
+ if type_field != "response" {
1551
+ return Err(de::Error::custom(format!(
1552
+ "expected type \"response\", got {type_field:?}"
1553
+ )));
1554
+ }
1555
+
1556
+ let id = optional_string(obj, "id").map_err(de::Error::custom)?;
1557
+ let command = required_string(obj, "command")?;
1558
+ let success = obj
1559
+ .get("success")
1560
+ .and_then(Value::as_bool)
1561
+ .ok_or_else(|| de::Error::custom("rpc response missing success"))?;
1562
+
1563
+ if success {
1564
+ let data = match obj.get("data") {
1565
+ None => None,
1566
+ Some(v) => Some(Box::new(
1567
+ RpcResponseData::deserialize_for_command(command.as_str(), v)
1568
+ .map_err(de::Error::custom)?,
1569
+ )),
1570
+ };
1571
+ Ok(Self::Success { id, command, data })
1572
+ } else {
1573
+ let error = required_string(obj, "error")?;
1574
+ Ok(Self::Error { id, command, error })
1575
+ }
1576
+ }
1577
+ }
1578
+
1579
+ // ---------------------------------------------------------------------------
1580
+ // Extension UI request / response
1581
+ // ---------------------------------------------------------------------------
1582
+
1583
+ /// Notify severity for [`RpcExtensionUiRequest::Notify`].
1584
+ #[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize, Deserialize)]
1585
+ #[serde(rename_all = "camelCase")]
1586
+ pub enum NotifyType {
1587
+ /// Informational.
1588
+ Info,
1589
+ /// Warning.
1590
+ Warning,
1591
+ /// Error.
1592
+ Error,
1593
+ }
1594
+
1595
+ /// Widget placement for [`RpcExtensionUiRequest::SetWidget`].
1596
+ #[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize, Deserialize)]
1597
+ #[serde(rename_all = "camelCase")]
1598
+ pub enum WidgetPlacement {
1599
+ /// Above the editor.
1600
+ AboveEditor,
1601
+ /// Below the editor.
1602
+ BelowEditor,
1603
+ }
1604
+
1605
+ /// Extension UI request emitted on stdout (`type: "extension_ui_request"`).
1606
+ #[derive(Clone, Debug, PartialEq)]
1607
+ pub enum RpcExtensionUiRequest {
1608
+ /// Present a select list.
1609
+ Select {
1610
+ /// Correlation id.
1611
+ id: String,
1612
+ /// Dialog title.
1613
+ title: String,
1614
+ /// Options to choose from.
1615
+ options: Vec<String>,
1616
+ /// Optional timeout in milliseconds.
1617
+ timeout: Option<u64>,
1618
+ },
1619
+ /// Present a confirm dialog.
1620
+ Confirm {
1621
+ /// Correlation id.
1622
+ id: String,
1623
+ /// Dialog title.
1624
+ title: String,
1625
+ /// Dialog message.
1626
+ message: String,
1627
+ /// Optional timeout in milliseconds.
1628
+ timeout: Option<u64>,
1629
+ },
1630
+ /// Present a single-line input.
1631
+ Input {
1632
+ /// Correlation id.
1633
+ id: String,
1634
+ /// Dialog title.
1635
+ title: String,
1636
+ /// Optional placeholder.
1637
+ placeholder: Option<String>,
1638
+ /// Optional timeout in milliseconds.
1639
+ timeout: Option<u64>,
1640
+ },
1641
+ /// Present a multi-line editor.
1642
+ Editor {
1643
+ /// Correlation id.
1644
+ id: String,
1645
+ /// Dialog title.
1646
+ title: String,
1647
+ /// Optional prefilled text.
1648
+ prefill: Option<String>,
1649
+ },
1650
+ /// Fire-and-forget notification.
1651
+ Notify {
1652
+ /// Correlation id.
1653
+ id: String,
1654
+ /// Notification text.
1655
+ message: String,
1656
+ /// Optional severity.
1657
+ notify_type: Option<NotifyType>,
1658
+ },
1659
+ /// Set or clear a status key.
1660
+ SetStatus {
1661
+ /// Correlation id.
1662
+ id: String,
1663
+ /// Status key.
1664
+ status_key: String,
1665
+ /// Status text (`undefined` clears).
1666
+ status_text: Option<String>,
1667
+ },
1668
+ /// Set or clear a widget.
1669
+ SetWidget {
1670
+ /// Correlation id.
1671
+ id: String,
1672
+ /// Widget key.
1673
+ widget_key: String,
1674
+ /// Widget lines (`undefined` clears).
1675
+ widget_lines: Option<Vec<String>>,
1676
+ /// Optional placement.
1677
+ widget_placement: Option<WidgetPlacement>,
1678
+ },
1679
+ /// Set the window/tab title.
1680
+ SetTitle {
1681
+ /// Correlation id.
1682
+ id: String,
1683
+ /// New title.
1684
+ title: String,
1685
+ },
1686
+ /// Replace editor text.
1687
+ SetEditorText {
1688
+ /// Correlation id.
1689
+ id: String,
1690
+ /// New editor text.
1691
+ text: String,
1692
+ },
1693
+ }
1694
+
1695
+ impl RpcExtensionUiRequest {
1696
+ /// Correlation id.
1697
+ #[must_use]
1698
+ pub fn id(&self) -> &str {
1699
+ match self {
1700
+ Self::Select { id, .. }
1701
+ | Self::Confirm { id, .. }
1702
+ | Self::Input { id, .. }
1703
+ | Self::Editor { id, .. }
1704
+ | Self::Notify { id, .. }
1705
+ | Self::SetStatus { id, .. }
1706
+ | Self::SetWidget { id, .. }
1707
+ | Self::SetTitle { id, .. }
1708
+ | Self::SetEditorText { id, .. } => id.as_str(),
1709
+ }
1710
+ }
1711
+
1712
+ /// Wire `method` discriminant.
1713
+ #[must_use]
1714
+ pub fn method(&self) -> &str {
1715
+ match self {
1716
+ Self::Select { .. } => "select",
1717
+ Self::Confirm { .. } => "confirm",
1718
+ Self::Input { .. } => "input",
1719
+ Self::Editor { .. } => "editor",
1720
+ Self::Notify { .. } => "notify",
1721
+ Self::SetStatus { .. } => "setStatus",
1722
+ Self::SetWidget { .. } => "setWidget",
1723
+ Self::SetTitle { .. } => "setTitle",
1724
+ Self::SetEditorText { .. } => "set_editor_text",
1725
+ }
1726
+ }
1727
+ }
1728
+
1729
+ impl Serialize for RpcExtensionUiRequest {
1730
+ fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1731
+ where
1732
+ S: Serializer,
1733
+ {
1734
+ match self {
1735
+ Self::Select {
1736
+ id,
1737
+ title,
1738
+ options,
1739
+ timeout,
1740
+ } => serialize_ui_select(serializer, id, title, options, *timeout),
1741
+ Self::Confirm {
1742
+ id,
1743
+ title,
1744
+ message,
1745
+ timeout,
1746
+ } => serialize_ui_confirm(serializer, id, title, message, *timeout),
1747
+ Self::Input {
1748
+ id,
1749
+ title,
1750
+ placeholder,
1751
+ timeout,
1752
+ } => serialize_ui_input(serializer, id, title, placeholder.as_deref(), *timeout),
1753
+ Self::Editor { id, title, prefill } => {
1754
+ serialize_ui_editor(serializer, id, title, prefill.as_deref())
1755
+ }
1756
+ Self::Notify {
1757
+ id,
1758
+ message,
1759
+ notify_type,
1760
+ } => serialize_ui_notify(serializer, id, message, *notify_type),
1761
+ Self::SetStatus {
1762
+ id,
1763
+ status_key,
1764
+ status_text,
1765
+ } => serialize_ui_set_status(serializer, id, status_key, status_text.as_deref()),
1766
+ Self::SetWidget {
1767
+ id,
1768
+ widget_key,
1769
+ widget_lines,
1770
+ widget_placement,
1771
+ } => serialize_ui_set_widget(
1772
+ serializer,
1773
+ id,
1774
+ widget_key,
1775
+ widget_lines.as_deref(),
1776
+ *widget_placement,
1777
+ ),
1778
+ Self::SetTitle { id, title } => serialize_ui_set_title(serializer, id, title),
1779
+ Self::SetEditorText { id, text } => serialize_ui_set_editor_text(serializer, id, text),
1780
+ }
1781
+ }
1782
+ }
1783
+
1784
+ fn serialize_ui_select<S: Serializer>(
1785
+ serializer: S,
1786
+ id: &str,
1787
+ title: &str,
1788
+ options: &[String],
1789
+ timeout: Option<u64>,
1790
+ ) -> Result<S::Ok, S::Error> {
1791
+ let mut map = serializer.serialize_map(None)?;
1792
+ map.serialize_entry("type", "extension_ui_request")?;
1793
+ map.serialize_entry("id", id)?;
1794
+ map.serialize_entry("method", "select")?;
1795
+ map.serialize_entry("title", title)?;
1796
+ map.serialize_entry("options", options)?;
1797
+ if let Some(timeout) = timeout {
1798
+ map.serialize_entry("timeout", &timeout)?;
1799
+ }
1800
+ map.end()
1801
+ }
1802
+
1803
+ fn serialize_ui_confirm<S: Serializer>(
1804
+ serializer: S,
1805
+ id: &str,
1806
+ title: &str,
1807
+ message: &str,
1808
+ timeout: Option<u64>,
1809
+ ) -> Result<S::Ok, S::Error> {
1810
+ let mut map = serializer.serialize_map(None)?;
1811
+ map.serialize_entry("type", "extension_ui_request")?;
1812
+ map.serialize_entry("id", id)?;
1813
+ map.serialize_entry("method", "confirm")?;
1814
+ map.serialize_entry("title", title)?;
1815
+ map.serialize_entry("message", message)?;
1816
+ if let Some(timeout) = timeout {
1817
+ map.serialize_entry("timeout", &timeout)?;
1818
+ }
1819
+ map.end()
1820
+ }
1821
+
1822
+ fn serialize_ui_input<S: Serializer>(
1823
+ serializer: S,
1824
+ id: &str,
1825
+ title: &str,
1826
+ placeholder: Option<&str>,
1827
+ timeout: Option<u64>,
1828
+ ) -> Result<S::Ok, S::Error> {
1829
+ let mut map = serializer.serialize_map(None)?;
1830
+ map.serialize_entry("type", "extension_ui_request")?;
1831
+ map.serialize_entry("id", id)?;
1832
+ map.serialize_entry("method", "input")?;
1833
+ map.serialize_entry("title", title)?;
1834
+ if let Some(placeholder) = placeholder {
1835
+ map.serialize_entry("placeholder", placeholder)?;
1836
+ }
1837
+ if let Some(timeout) = timeout {
1838
+ map.serialize_entry("timeout", &timeout)?;
1839
+ }
1840
+ map.end()
1841
+ }
1842
+
1843
+ fn serialize_ui_editor<S: Serializer>(
1844
+ serializer: S,
1845
+ id: &str,
1846
+ title: &str,
1847
+ prefill: Option<&str>,
1848
+ ) -> Result<S::Ok, S::Error> {
1849
+ let mut map = serializer.serialize_map(None)?;
1850
+ map.serialize_entry("type", "extension_ui_request")?;
1851
+ map.serialize_entry("id", id)?;
1852
+ map.serialize_entry("method", "editor")?;
1853
+ map.serialize_entry("title", title)?;
1854
+ if let Some(prefill) = prefill {
1855
+ map.serialize_entry("prefill", prefill)?;
1856
+ }
1857
+ map.end()
1858
+ }
1859
+
1860
+ fn serialize_ui_notify<S: Serializer>(
1861
+ serializer: S,
1862
+ id: &str,
1863
+ message: &str,
1864
+ notify_type: Option<NotifyType>,
1865
+ ) -> Result<S::Ok, S::Error> {
1866
+ let mut map = serializer.serialize_map(None)?;
1867
+ map.serialize_entry("type", "extension_ui_request")?;
1868
+ map.serialize_entry("id", id)?;
1869
+ map.serialize_entry("method", "notify")?;
1870
+ map.serialize_entry("message", message)?;
1871
+ if let Some(notify_type) = notify_type {
1872
+ map.serialize_entry("notifyType", &notify_type)?;
1873
+ }
1874
+ map.end()
1875
+ }
1876
+
1877
+ fn serialize_ui_set_status<S: Serializer>(
1878
+ serializer: S,
1879
+ id: &str,
1880
+ status_key: &str,
1881
+ status_text: Option<&str>,
1882
+ ) -> Result<S::Ok, S::Error> {
1883
+ let mut map = serializer.serialize_map(None)?;
1884
+ map.serialize_entry("type", "extension_ui_request")?;
1885
+ map.serialize_entry("id", id)?;
1886
+ map.serialize_entry("method", "setStatus")?;
1887
+ map.serialize_entry("statusKey", status_key)?;
1888
+ if let Some(text) = status_text {
1889
+ map.serialize_entry("statusText", text)?;
1890
+ } else {
1891
+ map.serialize_entry("statusText", &Value::Null)?;
1892
+ }
1893
+ map.end()
1894
+ }
1895
+
1896
+ fn serialize_ui_set_widget<S: Serializer>(
1897
+ serializer: S,
1898
+ id: &str,
1899
+ widget_key: &str,
1900
+ widget_lines: Option<&[String]>,
1901
+ widget_placement: Option<WidgetPlacement>,
1902
+ ) -> Result<S::Ok, S::Error> {
1903
+ let mut map = serializer.serialize_map(None)?;
1904
+ map.serialize_entry("type", "extension_ui_request")?;
1905
+ map.serialize_entry("id", id)?;
1906
+ map.serialize_entry("method", "setWidget")?;
1907
+ map.serialize_entry("widgetKey", widget_key)?;
1908
+ match widget_lines {
1909
+ Some(lines) => map.serialize_entry("widgetLines", lines)?,
1910
+ None => map.serialize_entry("widgetLines", &Value::Null)?,
1911
+ }
1912
+ if let Some(placement) = widget_placement {
1913
+ map.serialize_entry("widgetPlacement", &placement)?;
1914
+ }
1915
+ map.end()
1916
+ }
1917
+
1918
+ fn serialize_ui_set_title<S: Serializer>(
1919
+ serializer: S,
1920
+ id: &str,
1921
+ title: &str,
1922
+ ) -> Result<S::Ok, S::Error> {
1923
+ let mut map = serializer.serialize_map(None)?;
1924
+ map.serialize_entry("type", "extension_ui_request")?;
1925
+ map.serialize_entry("id", id)?;
1926
+ map.serialize_entry("method", "setTitle")?;
1927
+ map.serialize_entry("title", title)?;
1928
+ map.end()
1929
+ }
1930
+
1931
+ fn serialize_ui_set_editor_text<S: Serializer>(
1932
+ serializer: S,
1933
+ id: &str,
1934
+ text: &str,
1935
+ ) -> Result<S::Ok, S::Error> {
1936
+ let mut map = serializer.serialize_map(None)?;
1937
+ map.serialize_entry("type", "extension_ui_request")?;
1938
+ map.serialize_entry("id", id)?;
1939
+ map.serialize_entry("method", "set_editor_text")?;
1940
+ map.serialize_entry("text", text)?;
1941
+ map.end()
1942
+ }
1943
+
1944
+ impl<'de> Deserialize<'de> for RpcExtensionUiRequest {
1945
+ fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
1946
+ where
1947
+ D: Deserializer<'de>,
1948
+ {
1949
+ let value = Value::deserialize(deserializer)?;
1950
+ let obj = value
1951
+ .as_object()
1952
+ .ok_or_else(|| de::Error::custom("extension_ui_request must be a JSON object"))?;
1953
+ let type_field = obj
1954
+ .get("type")
1955
+ .and_then(Value::as_str)
1956
+ .ok_or_else(|| de::Error::custom("extension_ui_request missing type"))?;
1957
+ if type_field != "extension_ui_request" {
1958
+ return Err(de::Error::custom(format!(
1959
+ "expected type \"extension_ui_request\", got {type_field:?}"
1960
+ )));
1961
+ }
1962
+ let id = required_string(obj, "id")?;
1963
+ let method = required_string(obj, "method")?;
1964
+ parse_ui_request(obj, id, &method).map_err(de::Error::custom)
1965
+ }
1966
+ }
1967
+
1968
+ fn parse_ui_request(
1969
+ obj: &Map<String, Value>,
1970
+ id: String,
1971
+ method: &str,
1972
+ ) -> Result<RpcExtensionUiRequest, String> {
1973
+ match method {
1974
+ "select" => parse_ui_select(obj, id),
1975
+ "confirm" => Ok(RpcExtensionUiRequest::Confirm {
1976
+ id,
1977
+ title: required_string_owned(obj, "title")?,
1978
+ message: required_string_owned(obj, "message")?,
1979
+ timeout: optional_u64(obj, "timeout")?,
1980
+ }),
1981
+ "input" => Ok(RpcExtensionUiRequest::Input {
1982
+ id,
1983
+ title: required_string_owned(obj, "title")?,
1984
+ placeholder: optional_string(obj, "placeholder")?,
1985
+ timeout: optional_u64(obj, "timeout")?,
1986
+ }),
1987
+ "editor" => Ok(RpcExtensionUiRequest::Editor {
1988
+ id,
1989
+ title: required_string_owned(obj, "title")?,
1990
+ prefill: optional_string(obj, "prefill")?,
1991
+ }),
1992
+ "notify" => parse_ui_notify(obj, id),
1993
+ "setStatus" => parse_ui_set_status(obj, id),
1994
+ "setWidget" => parse_ui_set_widget(obj, id),
1995
+ "setTitle" => Ok(RpcExtensionUiRequest::SetTitle {
1996
+ id,
1997
+ title: required_string_owned(obj, "title")?,
1998
+ }),
1999
+ "set_editor_text" => Ok(RpcExtensionUiRequest::SetEditorText {
2000
+ id,
2001
+ text: required_string_owned(obj, "text")?,
2002
+ }),
2003
+ other => Err(format!("unknown extension_ui_request method: {other}")),
2004
+ }
2005
+ }
2006
+
2007
+ fn parse_ui_select(obj: &Map<String, Value>, id: String) -> Result<RpcExtensionUiRequest, String> {
2008
+ let title = required_string_owned(obj, "title")?;
2009
+ let options = obj
2010
+ .get("options")
2011
+ .ok_or_else(|| "select missing options".to_owned())?;
2012
+ let options = Vec::<String>::deserialize(options).map_err(|e| e.to_string())?;
2013
+ Ok(RpcExtensionUiRequest::Select {
2014
+ id,
2015
+ title,
2016
+ options,
2017
+ timeout: optional_u64(obj, "timeout")?,
2018
+ })
2019
+ }
2020
+
2021
+ fn parse_ui_notify(obj: &Map<String, Value>, id: String) -> Result<RpcExtensionUiRequest, String> {
2022
+ let notify_type = match obj.get("notifyType") {
2023
+ None | Some(Value::Null) => None,
2024
+ Some(v) => Some(NotifyType::deserialize(v).map_err(|e| e.to_string())?),
2025
+ };
2026
+ Ok(RpcExtensionUiRequest::Notify {
2027
+ id,
2028
+ message: required_string_owned(obj, "message")?,
2029
+ notify_type,
2030
+ })
2031
+ }
2032
+
2033
+ fn parse_ui_set_status(
2034
+ obj: &Map<String, Value>,
2035
+ id: String,
2036
+ ) -> Result<RpcExtensionUiRequest, String> {
2037
+ let status_text = match obj.get("statusText") {
2038
+ None | Some(Value::Null) => None,
2039
+ Some(Value::String(s)) => Some(s.clone()),
2040
+ Some(other) => {
2041
+ return Err(format!("statusText must be string or null, got {other}"));
2042
+ }
2043
+ };
2044
+ Ok(RpcExtensionUiRequest::SetStatus {
2045
+ id,
2046
+ status_key: required_string_owned(obj, "statusKey")?,
2047
+ status_text,
2048
+ })
2049
+ }
2050
+
2051
+ fn parse_ui_set_widget(
2052
+ obj: &Map<String, Value>,
2053
+ id: String,
2054
+ ) -> Result<RpcExtensionUiRequest, String> {
2055
+ let widget_lines = match obj.get("widgetLines") {
2056
+ None | Some(Value::Null) => None,
2057
+ Some(v) => Some(Vec::<String>::deserialize(v).map_err(|e| e.to_string())?),
2058
+ };
2059
+ let widget_placement = match obj.get("widgetPlacement") {
2060
+ None | Some(Value::Null) => None,
2061
+ Some(v) => Some(WidgetPlacement::deserialize(v).map_err(|e| e.to_string())?),
2062
+ };
2063
+ Ok(RpcExtensionUiRequest::SetWidget {
2064
+ id,
2065
+ widget_key: required_string_owned(obj, "widgetKey")?,
2066
+ widget_lines,
2067
+ widget_placement,
2068
+ })
2069
+ }
2070
+
2071
+ /// Response to an extension UI request (`type: "extension_ui_response"`).
2072
+ #[derive(Clone, Debug, PartialEq)]
2073
+ pub enum RpcExtensionUiResponse {
2074
+ /// Select/input/editor value.
2075
+ Value {
2076
+ /// Correlation id.
2077
+ id: String,
2078
+ /// Selected or entered value.
2079
+ value: String,
2080
+ },
2081
+ /// Confirm result.
2082
+ Confirmed {
2083
+ /// Correlation id.
2084
+ id: String,
2085
+ /// Whether confirmed.
2086
+ confirmed: bool,
2087
+ },
2088
+ /// User cancelled the dialog.
2089
+ Cancelled {
2090
+ /// Correlation id.
2091
+ id: String,
2092
+ },
2093
+ }
2094
+
2095
+ impl RpcExtensionUiResponse {
2096
+ /// Correlation id.
2097
+ #[must_use]
2098
+ pub fn id(&self) -> &str {
2099
+ match self {
2100
+ Self::Value { id, .. } | Self::Confirmed { id, .. } | Self::Cancelled { id } => {
2101
+ id.as_str()
2102
+ }
2103
+ }
2104
+ }
2105
+ }
2106
+
2107
+ impl Serialize for RpcExtensionUiResponse {
2108
+ fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
2109
+ where
2110
+ S: Serializer,
2111
+ {
2112
+ match self {
2113
+ Self::Value { id, value } => {
2114
+ let mut map = serializer.serialize_map(None)?;
2115
+ map.serialize_entry("type", "extension_ui_response")?;
2116
+ map.serialize_entry("id", id)?;
2117
+ map.serialize_entry("value", value)?;
2118
+ map.end()
2119
+ }
2120
+ Self::Confirmed { id, confirmed } => {
2121
+ let mut map = serializer.serialize_map(None)?;
2122
+ map.serialize_entry("type", "extension_ui_response")?;
2123
+ map.serialize_entry("id", id)?;
2124
+ map.serialize_entry("confirmed", confirmed)?;
2125
+ map.end()
2126
+ }
2127
+ Self::Cancelled { id } => {
2128
+ let mut map = serializer.serialize_map(None)?;
2129
+ map.serialize_entry("type", "extension_ui_response")?;
2130
+ map.serialize_entry("id", id)?;
2131
+ map.serialize_entry("cancelled", &true)?;
2132
+ map.end()
2133
+ }
2134
+ }
2135
+ }
2136
+ }
2137
+
2138
+ impl<'de> Deserialize<'de> for RpcExtensionUiResponse {
2139
+ fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
2140
+ where
2141
+ D: Deserializer<'de>,
2142
+ {
2143
+ let value = Value::deserialize(deserializer)?;
2144
+ let obj = value
2145
+ .as_object()
2146
+ .ok_or_else(|| de::Error::custom("extension_ui_response must be a JSON object"))?;
2147
+
2148
+ let type_field = obj
2149
+ .get("type")
2150
+ .and_then(Value::as_str)
2151
+ .ok_or_else(|| de::Error::custom("extension_ui_response missing type"))?;
2152
+ if type_field != "extension_ui_response" {
2153
+ return Err(de::Error::custom(format!(
2154
+ "expected type \"extension_ui_response\", got {type_field:?}"
2155
+ )));
2156
+ }
2157
+
2158
+ let id = required_string(obj, "id")?;
2159
+
2160
+ if let Some(Value::Bool(true)) = obj.get("cancelled") {
2161
+ return Ok(Self::Cancelled { id });
2162
+ }
2163
+ if let Some(Value::Bool(confirmed)) = obj.get("confirmed") {
2164
+ return Ok(Self::Confirmed {
2165
+ id,
2166
+ confirmed: *confirmed,
2167
+ });
2168
+ }
2169
+ if let Some(Value::String(value)) = obj.get("value") {
2170
+ return Ok(Self::Value {
2171
+ id,
2172
+ value: value.clone(),
2173
+ });
2174
+ }
2175
+
2176
+ Err(de::Error::custom(
2177
+ "extension_ui_response must include value, confirmed, or cancelled:true",
2178
+ ))
2179
+ }
2180
+ }
2181
+
2182
+ // ---------------------------------------------------------------------------
2183
+ // Serde helpers
2184
+ // ---------------------------------------------------------------------------
2185
+
2186
+ fn serialize_id<S>(map: &mut S, id: Option<&str>) -> Result<(), S::Error>
2187
+ where
2188
+ S: SerializeMap,
2189
+ {
2190
+ if let Some(id) = id {
2191
+ map.serialize_entry("id", id)?;
2192
+ }
2193
+ Ok(())
2194
+ }
2195
+
2196
+ fn serialize_type_only<S>(
2197
+ serializer: S,
2198
+ id: Option<&str>,
2199
+ type_name: &str,
2200
+ ) -> Result<S::Ok, S::Error>
2201
+ where
2202
+ S: Serializer,
2203
+ {
2204
+ let mut map = serializer.serialize_map(None)?;
2205
+ serialize_id(&mut map, id)?;
2206
+ map.serialize_entry("type", type_name)?;
2207
+ map.end()
2208
+ }
2209
+
2210
+ fn optional_string(obj: &Map<String, Value>, key: &str) -> Result<Option<String>, String> {
2211
+ match obj.get(key) {
2212
+ None | Some(Value::Null) => Ok(None),
2213
+ Some(Value::String(value)) => Ok(Some(value.clone())),
2214
+ Some(other) => Err(format!("field {key} must be a string, got {other}")),
2215
+ }
2216
+ }
2217
+
2218
+ fn required_string<E: de::Error>(obj: &Map<String, Value>, key: &str) -> Result<String, E> {
2219
+ match obj.get(key) {
2220
+ Some(Value::String(s)) => Ok(s.clone()),
2221
+ Some(other) => Err(E::custom(format!(
2222
+ "field {key} must be a string, got {other}"
2223
+ ))),
2224
+ None => Err(E::custom(format!("missing field {key}"))),
2225
+ }
2226
+ }
2227
+
2228
+ fn optional_bool(obj: &Map<String, Value>, key: &str) -> Result<Option<bool>, String> {
2229
+ match obj.get(key) {
2230
+ None | Some(Value::Null) => Ok(None),
2231
+ Some(Value::Bool(value)) => Ok(Some(*value)),
2232
+ Some(other) => Err(format!("field {key} must be a boolean, got {other}")),
2233
+ }
2234
+ }
2235
+
2236
+ fn optional_u64(obj: &Map<String, Value>, key: &str) -> Result<Option<u64>, String> {
2237
+ match obj.get(key) {
2238
+ None | Some(Value::Null) => Ok(None),
2239
+ Some(Value::Number(number)) => number
2240
+ .as_u64()
2241
+ .map(Some)
2242
+ .ok_or_else(|| format!("field {key} must be an unsigned integer, got {number}")),
2243
+ Some(other) => Err(format!(
2244
+ "field {key} must be an unsigned integer, got {other}"
2245
+ )),
2246
+ }
2247
+ }
2248
+
2249
+ // ---------------------------------------------------------------------------
2250
+ // Tests
2251
+ // ---------------------------------------------------------------------------
2252
+
2253
+ #[cfg(test)]
2254
+ mod tests {
2255
+ use super::*;
2256
+ use pi_ai::{ModelCost, ModelInput};
2257
+ use serde_json::json;
2258
+ use std::collections::BTreeMap;
2259
+
2260
+ type TestResult = Result<(), String>;
2261
+
2262
+ fn fail(msg: impl Into<String>) -> String {
2263
+ msg.into()
2264
+ }
2265
+
2266
+ fn sample_model() -> Model {
2267
+ Model {
2268
+ id: "gpt-4o".into(),
2269
+ name: "GPT-4o".into(),
2270
+ api: "openai-completions".into(),
2271
+ provider: "openai".into(),
2272
+ base_url: "https://api.openai.com/v1".into(),
2273
+ reasoning: false,
2274
+ thinking_level_map: None,
2275
+ input: vec![ModelInput::Text],
2276
+ cost: ModelCost {
2277
+ input: 0.0,
2278
+ output: 0.0,
2279
+ cache_read: 0.0,
2280
+ cache_write: 0.0,
2281
+ tiers: None,
2282
+ },
2283
+ context_window: 128_000,
2284
+ max_tokens: 16_384,
2285
+ headers: None,
2286
+ compat: None,
2287
+ extra: BTreeMap::default(),
2288
+ }
2289
+ }
2290
+
2291
+ fn assert_json_eq(actual: &Value, expected: &Value) -> TestResult {
2292
+ if actual == expected {
2293
+ Ok(())
2294
+ } else {
2295
+ Err(fail(format!(
2296
+ "JSON mismatch\n actual: {actual}\n expected: {expected}"
2297
+ )))
2298
+ }
2299
+ }
2300
+
2301
+ fn roundtrip_command(cmd: &RpcCommand) -> Result<RpcCommand, String> {
2302
+ let value = serde_json::to_value(cmd).map_err(|e| fail(e.to_string()))?;
2303
+ serde_json::from_value(value).map_err(|e| fail(e.to_string()))
2304
+ }
2305
+
2306
+ fn roundtrip_response(resp: &RpcResponse) -> Result<RpcResponse, String> {
2307
+ let value = serde_json::to_value(resp).map_err(|e| fail(e.to_string()))?;
2308
+ serde_json::from_value(value).map_err(|e| fail(e.to_string()))
2309
+ }
2310
+
2311
+ fn to_value<T: serde::Serialize>(v: &T) -> Result<Value, String> {
2312
+ serde_json::to_value(v).map_err(|e| fail(e.to_string()))
2313
+ }
2314
+
2315
+ fn from_value<T: serde::de::DeserializeOwned>(v: Value) -> Result<T, String> {
2316
+ serde_json::from_value(v).map_err(|e| fail(e.to_string()))
2317
+ }
2318
+
2319
+ #[test]
2320
+ fn command_prompt_wire_fields() -> TestResult {
2321
+ let cmd = RpcCommand::Prompt {
2322
+ id: Some("1".into()),
2323
+ message: "hi".into(),
2324
+ images: None,
2325
+ streaming_behavior: Some(StreamingBehavior::FollowUp),
2326
+ };
2327
+ let value = to_value(&cmd)?;
2328
+ assert_json_eq(
2329
+ &value,
2330
+ &json!({
2331
+ "id": "1",
2332
+ "type": "prompt",
2333
+ "message": "hi",
2334
+ "streamingBehavior": "followUp"
2335
+ }),
2336
+ )?;
2337
+ if roundtrip_command(&cmd)? != cmd {
2338
+ return Err(fail("prompt roundtrip mismatch"));
2339
+ }
2340
+ Ok(())
2341
+ }
2342
+
2343
+ #[test]
2344
+ fn command_set_model_camel_case() -> TestResult {
2345
+ let cmd = RpcCommand::SetModel {
2346
+ id: None,
2347
+ provider: "openai".into(),
2348
+ model_id: "gpt-4o".into(),
2349
+ };
2350
+ let value = to_value(&cmd)?;
2351
+ assert_json_eq(
2352
+ &value,
2353
+ &json!({
2354
+ "type": "set_model",
2355
+ "provider": "openai",
2356
+ "modelId": "gpt-4o"
2357
+ }),
2358
+ )?;
2359
+ if roundtrip_command(&cmd)? != cmd {
2360
+ return Err(fail("set_model roundtrip mismatch"));
2361
+ }
2362
+ Ok(())
2363
+ }
2364
+
2365
+ #[test]
2366
+ fn command_queue_modes_use_kebab_wire() -> TestResult {
2367
+ let cmd = RpcCommand::SetSteeringMode {
2368
+ id: Some("q".into()),
2369
+ mode: QueueMode::OneAtATime,
2370
+ };
2371
+ let value = to_value(&cmd)?;
2372
+ if value["mode"] != "one-at-a-time" {
2373
+ return Err(fail(format!("mode wire: {}", value["mode"])));
2374
+ }
2375
+ if roundtrip_command(&cmd)? != cmd {
2376
+ return Err(fail("queue mode roundtrip mismatch"));
2377
+ }
2378
+ Ok(())
2379
+ }
2380
+
2381
+ #[test]
2382
+ fn command_set_thinking_level_includes_off() -> TestResult {
2383
+ let cmd = RpcCommand::SetThinkingLevel {
2384
+ id: None,
2385
+ level: ModelThinkingLevel::Off,
2386
+ };
2387
+ let value = to_value(&cmd)?;
2388
+ if value["level"] != "off" {
2389
+ return Err(fail(format!("level wire: {}", value["level"])));
2390
+ }
2391
+ if roundtrip_command(&cmd)? != cmd {
2392
+ return Err(fail("thinking level roundtrip mismatch"));
2393
+ }
2394
+ Ok(())
2395
+ }
2396
+
2397
+ #[test]
2398
+ fn command_bash_exclude_from_context() -> TestResult {
2399
+ let cmd = RpcCommand::Bash {
2400
+ id: Some("b".into()),
2401
+ command: "echo hi".into(),
2402
+ exclude_from_context: Some(true),
2403
+ };
2404
+ let value = to_value(&cmd)?;
2405
+ assert_json_eq(
2406
+ &value,
2407
+ &json!({
2408
+ "id": "b",
2409
+ "type": "bash",
2410
+ "command": "echo hi",
2411
+ "excludeFromContext": true
2412
+ }),
2413
+ )?;
2414
+ if roundtrip_command(&cmd)? != cmd {
2415
+ return Err(fail("bash roundtrip mismatch"));
2416
+ }
2417
+ Ok(())
2418
+ }
2419
+
2420
+ fn sample_commands() -> Vec<RpcCommand> {
2421
+ vec![
2422
+ RpcCommand::Prompt {
2423
+ id: Some("1".into()),
2424
+ message: "m".into(),
2425
+ images: None,
2426
+ streaming_behavior: Some(StreamingBehavior::Steer),
2427
+ },
2428
+ RpcCommand::Steer {
2429
+ id: None,
2430
+ message: "s".into(),
2431
+ images: None,
2432
+ },
2433
+ RpcCommand::FollowUp {
2434
+ id: None,
2435
+ message: "f".into(),
2436
+ images: None,
2437
+ },
2438
+ RpcCommand::Abort { id: None },
2439
+ RpcCommand::NewSession {
2440
+ id: None,
2441
+ parent_session: Some("/tmp/s".into()),
2442
+ },
2443
+ RpcCommand::GetState { id: None },
2444
+ RpcCommand::SetModel {
2445
+ id: None,
2446
+ provider: "p".into(),
2447
+ model_id: "m".into(),
2448
+ },
2449
+ RpcCommand::CycleModel { id: None },
2450
+ RpcCommand::GetAvailableModels { id: None },
2451
+ RpcCommand::SetThinkingLevel {
2452
+ id: None,
2453
+ level: ModelThinkingLevel::High,
2454
+ },
2455
+ RpcCommand::CycleThinkingLevel { id: None },
2456
+ RpcCommand::SetSteeringMode {
2457
+ id: None,
2458
+ mode: QueueMode::All,
2459
+ },
2460
+ RpcCommand::SetFollowUpMode {
2461
+ id: None,
2462
+ mode: QueueMode::OneAtATime,
2463
+ },
2464
+ RpcCommand::Compact {
2465
+ id: None,
2466
+ custom_instructions: Some("x".into()),
2467
+ },
2468
+ RpcCommand::SetAutoCompaction {
2469
+ id: None,
2470
+ enabled: true,
2471
+ },
2472
+ RpcCommand::SetAutoRetry {
2473
+ id: None,
2474
+ enabled: false,
2475
+ },
2476
+ RpcCommand::AbortRetry { id: None },
2477
+ RpcCommand::Bash {
2478
+ id: None,
2479
+ command: "true".into(),
2480
+ exclude_from_context: None,
2481
+ },
2482
+ RpcCommand::AbortBash { id: None },
2483
+ RpcCommand::GetSessionStats { id: None },
2484
+ RpcCommand::ExportHtml {
2485
+ id: None,
2486
+ output_path: Some("out.html".into()),
2487
+ },
2488
+ RpcCommand::SwitchSession {
2489
+ id: None,
2490
+ session_path: "/s".into(),
2491
+ },
2492
+ RpcCommand::Fork {
2493
+ id: None,
2494
+ entry_id: "e1".into(),
2495
+ },
2496
+ RpcCommand::Clone { id: None },
2497
+ RpcCommand::GetForkMessages { id: None },
2498
+ RpcCommand::GetEntries {
2499
+ id: None,
2500
+ since: Some("e0".into()),
2501
+ },
2502
+ RpcCommand::GetTree { id: None },
2503
+ RpcCommand::GetLastAssistantText { id: None },
2504
+ RpcCommand::SetSessionName {
2505
+ id: None,
2506
+ name: "n".into(),
2507
+ },
2508
+ RpcCommand::GetMessages { id: None },
2509
+ RpcCommand::GetCommands { id: None },
2510
+ ]
2511
+ }
2512
+
2513
+ #[test]
2514
+ fn all_31_known_command_types_roundtrip() -> TestResult {
2515
+ let samples = sample_commands();
2516
+ if samples.len() != 31 {
2517
+ return Err(fail(format!("expected 31 samples, got {}", samples.len())));
2518
+ }
2519
+ for cmd in &samples {
2520
+ let rt = roundtrip_command(cmd)?;
2521
+ if &rt != cmd {
2522
+ return Err(fail(format!("roundtrip failed for {}", cmd.command_type())));
2523
+ }
2524
+ if rt.command_type() != cmd.command_type() {
2525
+ return Err(fail(format!("type mismatch for {}", cmd.command_type())));
2526
+ }
2527
+ }
2528
+ Ok(())
2529
+ }
2530
+
2531
+ #[test]
2532
+ fn unknown_command_preserves_type_id_and_payload() -> TestResult {
2533
+ let raw = json!({
2534
+ "id": "42",
2535
+ "type": "future_command",
2536
+ "foo": 1,
2537
+ "bar": "x"
2538
+ });
2539
+ let cmd: RpcCommand = from_value(raw)?;
2540
+ match &cmd {
2541
+ RpcCommand::Unknown {
2542
+ id,
2543
+ command_type,
2544
+ payload,
2545
+ } => {
2546
+ if id.as_deref() != Some("42") {
2547
+ return Err(fail(format!("id={id:?}")));
2548
+ }
2549
+ if command_type != "future_command" {
2550
+ return Err(fail(format!("type={command_type}")));
2551
+ }
2552
+ if payload.get("foo") != Some(&json!(1)) {
2553
+ return Err(fail("missing foo"));
2554
+ }
2555
+ if payload.get("bar") != Some(&json!("x")) {
2556
+ return Err(fail("missing bar"));
2557
+ }
2558
+ if payload.contains_key("type") || payload.contains_key("id") {
2559
+ return Err(fail("payload should exclude type/id"));
2560
+ }
2561
+ }
2562
+ other => return Err(fail(format!("expected Unknown, got {other:?}"))),
2563
+ }
2564
+ let re = to_value(&cmd)?;
2565
+ if re["id"] != "42" || re["type"] != "future_command" || re["foo"] != 1 || re["bar"] != "x"
2566
+ {
2567
+ return Err(fail(format!("reserialized unknown: {re}")));
2568
+ }
2569
+ Ok(())
2570
+ }
2571
+
2572
+ #[test]
2573
+ fn known_optional_command_fields_reject_wrong_types() -> TestResult {
2574
+ for raw in [
2575
+ json!({"type": "get_state", "id": 123}),
2576
+ json!({"type": "new_session", "parentSession": false}),
2577
+ json!({"type": "compact", "customInstructions": 7}),
2578
+ json!({"type": "bash", "command": "true", "excludeFromContext": "true"}),
2579
+ json!({"type": "export_html", "outputPath": []}),
2580
+ json!({"type": "get_entries", "since": {}}),
2581
+ ] {
2582
+ if from_value::<RpcCommand>(raw.clone()).is_ok() {
2583
+ return Err(fail(format!("wrongly accepted optional field: {raw}")));
2584
+ }
2585
+ }
2586
+ Ok(())
2587
+ }
2588
+
2589
+ #[test]
2590
+ fn known_optional_command_fields_accept_null() -> TestResult {
2591
+ let command = from_value::<RpcCommand>(json!({
2592
+ "type": "bash",
2593
+ "id": null,
2594
+ "command": "true",
2595
+ "excludeFromContext": null
2596
+ }))?;
2597
+ if !matches!(
2598
+ command,
2599
+ RpcCommand::Bash {
2600
+ id: None,
2601
+ exclude_from_context: None,
2602
+ ..
2603
+ }
2604
+ ) {
2605
+ return Err(fail(format!("unexpected parsed command: {command:?}")));
2606
+ }
2607
+ Ok(())
2608
+ }
2609
+
2610
+ #[test]
2611
+ fn response_success_without_data() -> TestResult {
2612
+ let resp = RpcResponse::ok(Some("1".into()), "prompt");
2613
+ let value = to_value(&resp)?;
2614
+ assert_json_eq(
2615
+ &value,
2616
+ &json!({
2617
+ "id": "1",
2618
+ "type": "response",
2619
+ "command": "prompt",
2620
+ "success": true
2621
+ }),
2622
+ )?;
2623
+ if roundtrip_response(&resp)? != resp {
2624
+ return Err(fail("success response roundtrip mismatch"));
2625
+ }
2626
+ Ok(())
2627
+ }
2628
+
2629
+ #[test]
2630
+ fn response_error_wire() -> TestResult {
2631
+ let resp = RpcResponse::err(
2632
+ Some("9".into()),
2633
+ "future_command",
2634
+ "Unknown command: future_command",
2635
+ );
2636
+ let value = to_value(&resp)?;
2637
+ assert_json_eq(
2638
+ &value,
2639
+ &json!({
2640
+ "id": "9",
2641
+ "type": "response",
2642
+ "command": "future_command",
2643
+ "success": false,
2644
+ "error": "Unknown command: future_command"
2645
+ }),
2646
+ )?;
2647
+ if roundtrip_response(&resp)? != resp {
2648
+ return Err(fail("error response roundtrip mismatch"));
2649
+ }
2650
+ Ok(())
2651
+ }
2652
+
2653
+ #[test]
2654
+ fn response_cancelled_data() -> TestResult {
2655
+ let resp = RpcResponse::ok_data(
2656
+ None,
2657
+ "new_session",
2658
+ RpcResponseData::Cancelled { cancelled: true },
2659
+ );
2660
+ let value = to_value(&resp)?;
2661
+ if value["success"] != true || value["data"]["cancelled"] != true {
2662
+ return Err(fail(format!("cancelled wire: {value}")));
2663
+ }
2664
+ if roundtrip_response(&resp)? != resp {
2665
+ return Err(fail("cancelled roundtrip mismatch"));
2666
+ }
2667
+ Ok(())
2668
+ }
2669
+
2670
+ #[test]
2671
+ fn response_cycle_model_null_data() -> TestResult {
2672
+ let resp = RpcResponse::ok_data(None, "cycle_model", RpcResponseData::CycleModel(None));
2673
+ let value = to_value(&resp)?;
2674
+ if value["data"] != Value::Null {
2675
+ return Err(fail(format!("expected null data, got {}", value["data"])));
2676
+ }
2677
+ let de: RpcResponse = from_value(value)?;
2678
+ match de {
2679
+ RpcResponse::Success {
2680
+ data: Some(boxed), ..
2681
+ } if matches!(boxed.as_ref(), RpcResponseData::CycleModel(None)) => Ok(()),
2682
+ other => Err(fail(format!("expected CycleModel(None), got {other:?}"))),
2683
+ }
2684
+ }
2685
+
2686
+ #[test]
2687
+ fn response_get_state_session_state_fields() -> TestResult {
2688
+ let state = RpcSessionState {
2689
+ model: Some(sample_model()),
2690
+ thinking_level: ModelThinkingLevel::Low,
2691
+ is_streaming: false,
2692
+ is_compacting: false,
2693
+ steering_mode: QueueMode::All,
2694
+ follow_up_mode: QueueMode::OneAtATime,
2695
+ session_file: Some("/tmp/s.jsonl".into()),
2696
+ session_id: "sid".into(),
2697
+ session_name: Some("work".into()),
2698
+ auto_compaction_enabled: true,
2699
+ message_count: 3,
2700
+ pending_message_count: 0,
2701
+ };
2702
+ let resp = RpcResponse::ok_data(
2703
+ Some("g".into()),
2704
+ "get_state",
2705
+ RpcResponseData::SessionState(state),
2706
+ );
2707
+ let value = to_value(&resp)?;
2708
+ if value["data"]["thinkingLevel"] != "low"
2709
+ || value["data"]["isStreaming"] != false
2710
+ || value["data"]["steeringMode"] != "all"
2711
+ || value["data"]["followUpMode"] != "one-at-a-time"
2712
+ || value["data"]["sessionId"] != "sid"
2713
+ || value["data"]["messageCount"] != 3
2714
+ || value["data"]["pendingMessageCount"] != 0
2715
+ || value["data"]["autoCompactionEnabled"] != true
2716
+ {
2717
+ return Err(fail(format!("get_state fields: {}", value["data"])));
2718
+ }
2719
+ if roundtrip_response(&resp)? != resp {
2720
+ return Err(fail("get_state roundtrip mismatch"));
2721
+ }
2722
+ Ok(())
2723
+ }
2724
+
2725
+ #[test]
2726
+ fn response_bash_result_camel_case() -> TestResult {
2727
+ let data = RpcResponseData::Bash(BashResult {
2728
+ output: "ok".into(),
2729
+ exit_code: Some(0),
2730
+ cancelled: false,
2731
+ truncated: false,
2732
+ full_output_path: None,
2733
+ });
2734
+ let resp = RpcResponse::ok_data(None, "bash", data);
2735
+ let value = to_value(&resp)?;
2736
+ if value["data"]["exitCode"] != 0
2737
+ || value["data"]["cancelled"] != false
2738
+ || value["data"]["truncated"] != false
2739
+ || value["data"].get("fullOutputPath").is_some()
2740
+ {
2741
+ return Err(fail(format!("bash data: {}", value["data"])));
2742
+ }
2743
+ if roundtrip_response(&resp)? != resp {
2744
+ return Err(fail("bash response roundtrip mismatch"));
2745
+ }
2746
+ Ok(())
2747
+ }
2748
+
2749
+ #[test]
2750
+ fn response_session_stats_tokens() -> TestResult {
2751
+ let data = RpcResponseData::SessionStats(SessionStats {
2752
+ session_file: None,
2753
+ session_id: "s".into(),
2754
+ user_messages: 1,
2755
+ assistant_messages: 1,
2756
+ tool_calls: 0,
2757
+ tool_results: 0,
2758
+ total_messages: 2,
2759
+ tokens: SessionStatsTokens {
2760
+ input: 10,
2761
+ output: 20,
2762
+ cache_read: 0,
2763
+ cache_write: 0,
2764
+ total: 30,
2765
+ },
2766
+ cost: 0.01,
2767
+ context_usage: Some(ContextUsage {
2768
+ tokens: Some(30),
2769
+ context_window: 128_000,
2770
+ percent: Some(0.02),
2771
+ }),
2772
+ });
2773
+ let resp = RpcResponse::ok_data(None, "get_session_stats", data);
2774
+ let value = to_value(&resp)?;
2775
+ if value["data"]["sessionId"] != "s"
2776
+ || value["data"]["userMessages"] != 1
2777
+ || value["data"]["tokens"]["cacheRead"] != 0
2778
+ || value["data"]["contextUsage"]["contextWindow"] != 128_000
2779
+ {
2780
+ return Err(fail(format!("stats data: {}", value["data"])));
2781
+ }
2782
+ if roundtrip_response(&resp)? != resp {
2783
+ return Err(fail("stats roundtrip mismatch"));
2784
+ }
2785
+ Ok(())
2786
+ }
2787
+
2788
+ #[test]
2789
+ fn response_get_commands_slash_command() -> TestResult {
2790
+ let cmd = RpcSlashCommand {
2791
+ name: "skill:foo".into(),
2792
+ description: Some("Foo skill".into()),
2793
+ source: RpcSlashCommandSource::Skill,
2794
+ source_info: RpcSourceInfo {
2795
+ path: "/skills/foo".into(),
2796
+ source: "local".into(),
2797
+ scope: RpcSourceScope::Project,
2798
+ origin: RpcSourceOrigin::TopLevel,
2799
+ base_dir: None,
2800
+ },
2801
+ };
2802
+ let resp = RpcResponse::ok_data(
2803
+ None,
2804
+ "get_commands",
2805
+ RpcResponseData::Commands {
2806
+ commands: vec![cmd],
2807
+ },
2808
+ );
2809
+ let value = to_value(&resp)?;
2810
+ if value["data"]["commands"][0]["name"] != "skill:foo"
2811
+ || value["data"]["commands"][0]["source"] != "skill"
2812
+ || value["data"]["commands"][0]["sourceInfo"]["origin"] != "top-level"
2813
+ || value["data"]["commands"][0]["sourceInfo"]["scope"] != "project"
2814
+ {
2815
+ return Err(fail(format!("commands data: {}", value["data"])));
2816
+ }
2817
+ if roundtrip_response(&resp)? != resp {
2818
+ return Err(fail("get_commands roundtrip mismatch"));
2819
+ }
2820
+ Ok(())
2821
+ }
2822
+
2823
+ #[test]
2824
+ fn extension_ui_request_select_wire() -> TestResult {
2825
+ let req = RpcExtensionUiRequest::Select {
2826
+ id: "ui1".into(),
2827
+ title: "Pick".into(),
2828
+ options: vec!["a".into(), "b".into()],
2829
+ timeout: Some(1000),
2830
+ };
2831
+ let value = to_value(&req)?;
2832
+ assert_json_eq(
2833
+ &value,
2834
+ &json!({
2835
+ "type": "extension_ui_request",
2836
+ "id": "ui1",
2837
+ "method": "select",
2838
+ "title": "Pick",
2839
+ "options": ["a", "b"],
2840
+ "timeout": 1000
2841
+ }),
2842
+ )?;
2843
+ let de: RpcExtensionUiRequest = from_value(value)?;
2844
+ if de != req {
2845
+ return Err(fail("select UI request roundtrip mismatch"));
2846
+ }
2847
+ Ok(())
2848
+ }
2849
+
2850
+ #[test]
2851
+ fn extension_ui_request_set_status_null_text() -> TestResult {
2852
+ let req = RpcExtensionUiRequest::SetStatus {
2853
+ id: "s1".into(),
2854
+ status_key: "k".into(),
2855
+ status_text: None,
2856
+ };
2857
+ let value = to_value(&req)?;
2858
+ if value["method"] != "setStatus"
2859
+ || value["statusKey"] != "k"
2860
+ || value["statusText"] != Value::Null
2861
+ {
2862
+ return Err(fail(format!("setStatus wire: {value}")));
2863
+ }
2864
+ let de: RpcExtensionUiRequest = from_value(value)?;
2865
+ if de != req {
2866
+ return Err(fail("setStatus roundtrip mismatch"));
2867
+ }
2868
+ Ok(())
2869
+ }
2870
+
2871
+ #[test]
2872
+ fn extension_ui_request_set_widget_and_editor_text() -> TestResult {
2873
+ let widget = RpcExtensionUiRequest::SetWidget {
2874
+ id: "w".into(),
2875
+ widget_key: "wk".into(),
2876
+ widget_lines: Some(vec!["l1".into()]),
2877
+ widget_placement: Some(WidgetPlacement::AboveEditor),
2878
+ };
2879
+ let value = to_value(&widget)?;
2880
+ if value["method"] != "setWidget" || value["widgetPlacement"] != "aboveEditor" {
2881
+ return Err(fail(format!("setWidget wire: {value}")));
2882
+ }
2883
+ let de: RpcExtensionUiRequest = from_value(value)?;
2884
+ if de != widget {
2885
+ return Err(fail("setWidget roundtrip mismatch"));
2886
+ }
2887
+
2888
+ let editor = RpcExtensionUiRequest::SetEditorText {
2889
+ id: "e".into(),
2890
+ text: "hello".into(),
2891
+ };
2892
+ let value = to_value(&editor)?;
2893
+ if value["method"] != "set_editor_text" {
2894
+ return Err(fail(format!("set_editor_text wire: {value}")));
2895
+ }
2896
+ let de: RpcExtensionUiRequest = from_value(value)?;
2897
+ if de != editor {
2898
+ return Err(fail("set_editor_text roundtrip mismatch"));
2899
+ }
2900
+ Ok(())
2901
+ }
2902
+
2903
+ #[test]
2904
+ fn extension_ui_response_variants() -> TestResult {
2905
+ let cases = [
2906
+ RpcExtensionUiResponse::Value {
2907
+ id: "1".into(),
2908
+ value: "x".into(),
2909
+ },
2910
+ RpcExtensionUiResponse::Confirmed {
2911
+ id: "2".into(),
2912
+ confirmed: false,
2913
+ },
2914
+ RpcExtensionUiResponse::Cancelled { id: "3".into() },
2915
+ ];
2916
+ for case in &cases {
2917
+ let value = to_value(case)?;
2918
+ if value["type"] != "extension_ui_response" {
2919
+ return Err(fail(format!("ui response type: {value}")));
2920
+ }
2921
+ let de: RpcExtensionUiResponse = from_value(value)?;
2922
+ if &de != case {
2923
+ return Err(fail(format!("ui response roundtrip mismatch: {case:?}")));
2924
+ }
2925
+ }
2926
+ Ok(())
2927
+ }
2928
+
2929
+ #[test]
2930
+ fn response_fork_messages_entry_id_camel_case() -> TestResult {
2931
+ let resp = RpcResponse::ok_data(
2932
+ None,
2933
+ "get_fork_messages",
2934
+ RpcResponseData::ForkMessages {
2935
+ messages: vec![ForkMessage {
2936
+ entry_id: "e1".into(),
2937
+ text: "hello".into(),
2938
+ }],
2939
+ },
2940
+ );
2941
+ let value = to_value(&resp)?;
2942
+ if value["data"]["messages"][0]["entryId"] != "e1" {
2943
+ return Err(fail(format!("fork messages: {}", value["data"])));
2944
+ }
2945
+ if roundtrip_response(&resp)? != resp {
2946
+ return Err(fail("fork messages roundtrip mismatch"));
2947
+ }
2948
+ Ok(())
2949
+ }
2950
+
2951
+ #[test]
2952
+ fn response_last_assistant_text_null() -> TestResult {
2953
+ let resp = RpcResponse::ok_data(
2954
+ None,
2955
+ "get_last_assistant_text",
2956
+ RpcResponseData::LastAssistantText { text: None },
2957
+ );
2958
+ let value = to_value(&resp)?;
2959
+ if value["data"]["text"] != Value::Null {
2960
+ return Err(fail(format!("last assistant text: {}", value["data"])));
2961
+ }
2962
+ if roundtrip_response(&resp)? != resp {
2963
+ return Err(fail("last assistant text roundtrip mismatch"));
2964
+ }
2965
+ Ok(())
2966
+ }
2967
+
2968
+ #[test]
2969
+ fn command_id_and_type_accessors() -> TestResult {
2970
+ let cmd = RpcCommand::Unknown {
2971
+ id: Some("x".into()),
2972
+ command_type: "nope".into(),
2973
+ payload: Map::new(),
2974
+ };
2975
+ if cmd.id() != Some("x") || cmd.command_type() != "nope" {
2976
+ return Err(fail("unknown accessors mismatch"));
2977
+ }
2978
+ Ok(())
2979
+ }
2980
+
2981
+ #[test]
2982
+ fn image_content_roundtrip_inside_prompt() -> TestResult {
2983
+ let img = ImageContent::new("AAAA", "image/png");
2984
+ let cmd = RpcCommand::Prompt {
2985
+ id: None,
2986
+ message: "see".into(),
2987
+ images: Some(vec![img]),
2988
+ streaming_behavior: None,
2989
+ };
2990
+ let value = to_value(&cmd)?;
2991
+ if value["images"][0]["type"] != "image" || value["images"][0]["mimeType"] != "image/png" {
2992
+ return Err(fail(format!("image wire: {}", value["images"])));
2993
+ }
2994
+ if roundtrip_command(&cmd)? != cmd {
2995
+ return Err(fail("image prompt roundtrip mismatch"));
2996
+ }
2997
+ Ok(())
2998
+ }
2999
+ }