@prestyj/cli 5.11.0 → 5.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (366) hide show
  1. package/assets/skills/compliance-guard/SKILL.md +251 -0
  2. package/assets/skills/compliance-guard/references/artifacts.md +186 -0
  3. package/assets/skills/compliance-guard/references/eu-uk.md +151 -0
  4. package/assets/skills/compliance-guard/references/exposure-triage.md +161 -0
  5. package/assets/skills/compliance-guard/references/lawsuit-vectors.md +141 -0
  6. package/assets/skills/compliance-guard/references/provenance.md +42 -0
  7. package/assets/skills/compliance-guard/references/sector-gates.md +173 -0
  8. package/assets/skills/compliance-guard/references/security-baseline.md +130 -0
  9. package/assets/skills/compliance-guard/references/trigger-map.md +163 -0
  10. package/assets/skills/compliance-guard/references/us.md +164 -0
  11. package/dist/app-sidecar-auth-broadcast.test.js +69 -3
  12. package/dist/app-sidecar-auth-broadcast.test.js.map +1 -1
  13. package/dist/app-sidecar-sessions.test.js +1 -1
  14. package/dist/app-sidecar.js +119 -45
  15. package/dist/app-sidecar.js.map +1 -1
  16. package/dist/chat-agents/jiwa.test.js +1 -1
  17. package/dist/cli/auth.d.ts.map +1 -1
  18. package/dist/cli/auth.js +33 -36
  19. package/dist/cli/auth.js.map +1 -1
  20. package/dist/cli.d.ts.map +1 -1
  21. package/dist/cli.js +12 -1
  22. package/dist/cli.js.map +1 -1
  23. package/dist/config.d.ts +16 -5
  24. package/dist/config.d.ts.map +1 -1
  25. package/dist/config.js +35 -76
  26. package/dist/config.js.map +1 -1
  27. package/dist/config.test.js +20 -12
  28. package/dist/config.test.js.map +1 -1
  29. package/dist/core/agent-session-checkpoint-flush.test.js +2 -2
  30. package/dist/core/agent-session-crash-durability.test.js +3 -3
  31. package/dist/core/agent-session-model-switch.test.js +1 -1
  32. package/dist/core/agent-session-process-gate.test.js +7 -1
  33. package/dist/core/agent-session-process-gate.test.js.map +1 -1
  34. package/dist/core/agent-session-review-coverage.test.js +1 -1
  35. package/dist/core/agent-session-tool-tiers.test.d.ts +2 -0
  36. package/dist/core/agent-session-tool-tiers.test.d.ts.map +1 -0
  37. package/dist/core/agent-session-tool-tiers.test.js +138 -0
  38. package/dist/core/agent-session-tool-tiers.test.js.map +1 -0
  39. package/dist/core/agent-session.d.ts +43 -3
  40. package/dist/core/agent-session.d.ts.map +1 -1
  41. package/dist/core/agent-session.js +142 -31
  42. package/dist/core/agent-session.js.map +1 -1
  43. package/dist/core/agents.d.ts +29 -1
  44. package/dist/core/agents.d.ts.map +1 -1
  45. package/dist/core/agents.js +47 -97
  46. package/dist/core/agents.js.map +1 -1
  47. package/dist/core/agents.test.js +87 -7
  48. package/dist/core/agents.test.js.map +1 -1
  49. package/dist/core/api-benchmark.d.ts +3 -3
  50. package/dist/core/api-benchmark.js +7 -7
  51. package/dist/core/auth-providers.d.ts +37 -1
  52. package/dist/core/auth-providers.d.ts.map +1 -1
  53. package/dist/core/auth-providers.js +83 -3
  54. package/dist/core/auth-providers.js.map +1 -1
  55. package/dist/core/auto-update.test.js +1 -1
  56. package/dist/core/autopilot-gate.d.ts +2 -2
  57. package/dist/core/autopilot-gate.js +1 -1
  58. package/dist/core/bash-spawn-benchmark.js +6 -6
  59. package/dist/core/bundled-agents.d.ts +3 -0
  60. package/dist/core/bundled-agents.d.ts.map +1 -0
  61. package/dist/core/bundled-agents.js +252 -0
  62. package/dist/core/bundled-agents.js.map +1 -0
  63. package/dist/core/cache-warm-benchmark.d.ts +2 -2
  64. package/dist/core/cache-warm-benchmark.js +5 -5
  65. package/dist/core/code-retrieval-chunkers.d.ts +27 -0
  66. package/dist/core/code-retrieval-chunkers.d.ts.map +1 -0
  67. package/dist/core/code-retrieval-chunkers.js +264 -0
  68. package/dist/core/code-retrieval-chunkers.js.map +1 -0
  69. package/dist/core/code-retrieval-chunkers.test.d.ts +2 -0
  70. package/dist/core/code-retrieval-chunkers.test.d.ts.map +1 -0
  71. package/dist/core/code-retrieval-chunkers.test.js +203 -0
  72. package/dist/core/code-retrieval-chunkers.test.js.map +1 -0
  73. package/dist/core/code-retrieval.d.ts +6 -0
  74. package/dist/core/code-retrieval.d.ts.map +1 -1
  75. package/dist/core/code-retrieval.js +38 -1
  76. package/dist/core/code-retrieval.js.map +1 -1
  77. package/dist/core/encode-cwd.test.js +1 -1
  78. package/dist/core/extensions/plugin-bundles.js +2 -2
  79. package/dist/core/extensions/plugin-bundles.js.map +1 -1
  80. package/dist/core/extensions/plugin-bundles.test.js +2 -2
  81. package/dist/core/extensions/plugin-bundles.test.js.map +1 -1
  82. package/dist/core/fast-apply-benchmark.d.ts +2 -2
  83. package/dist/core/fast-apply-benchmark.js +6 -6
  84. package/dist/core/foreign-session-import.test.js +1 -1
  85. package/dist/core/goal-lifecycle-smoke.test.js +2 -2
  86. package/dist/core/goal-store.js +1 -1
  87. package/dist/core/goal-store.test.js +2 -2
  88. package/dist/core/goal-verifier.test.js +2 -2
  89. package/dist/core/goal-worker-dev-server-lifecycle.test.js +1 -1
  90. package/dist/core/goal-worker.test.js +2 -2
  91. package/dist/core/hashline-edit-benchmark.d.ts +2 -2
  92. package/dist/core/hashline-edit-benchmark.js +7 -7
  93. package/dist/core/local-endpoint-store.test.js +1 -1
  94. package/dist/core/logger.d.ts +1 -1
  95. package/dist/core/logger.js +2 -2
  96. package/dist/core/logger.js.map +1 -1
  97. package/dist/core/lsp/client-navigation.test.d.ts +2 -0
  98. package/dist/core/lsp/client-navigation.test.d.ts.map +1 -0
  99. package/dist/core/lsp/client-navigation.test.js +135 -0
  100. package/dist/core/lsp/client-navigation.test.js.map +1 -0
  101. package/dist/core/lsp/client.d.ts +69 -0
  102. package/dist/core/lsp/client.d.ts.map +1 -1
  103. package/dist/core/lsp/client.js +151 -2
  104. package/dist/core/lsp/client.js.map +1 -1
  105. package/dist/core/lsp/integration.test.js +2 -2
  106. package/dist/core/lsp/manager-navigation.test.d.ts +2 -0
  107. package/dist/core/lsp/manager-navigation.test.d.ts.map +1 -0
  108. package/dist/core/lsp/manager-navigation.test.js +121 -0
  109. package/dist/core/lsp/manager-navigation.test.js.map +1 -0
  110. package/dist/core/lsp/manager.d.ts +35 -1
  111. package/dist/core/lsp/manager.d.ts.map +1 -1
  112. package/dist/core/lsp/manager.js +92 -0
  113. package/dist/core/lsp/manager.js.map +1 -1
  114. package/dist/core/lsp/servers.test.js +1 -1
  115. package/dist/core/lsp/windows.test.js +4 -4
  116. package/dist/core/mcp/catalog-cache.test.js +1 -1
  117. package/dist/core/mcp/client-session-recovery.test.js +1 -1
  118. package/dist/core/mcp/client.d.ts.map +1 -1
  119. package/dist/core/mcp/client.js +2 -10
  120. package/dist/core/mcp/client.js.map +1 -1
  121. package/dist/core/mcp/content.d.ts +19 -0
  122. package/dist/core/mcp/content.d.ts.map +1 -0
  123. package/dist/core/mcp/content.js +172 -0
  124. package/dist/core/mcp/content.js.map +1 -0
  125. package/dist/core/mcp/content.test.d.ts +2 -0
  126. package/dist/core/mcp/content.test.d.ts.map +1 -0
  127. package/dist/core/mcp/content.test.js +135 -0
  128. package/dist/core/mcp/content.test.js.map +1 -0
  129. package/dist/core/mcp/deferred-catalog.d.ts +1 -1
  130. package/dist/core/mcp/deferred-catalog.js +1 -1
  131. package/dist/core/mcp/elicitation.test.js +1 -1
  132. package/dist/core/mcp/legacy-negotiation.test.js +2 -2
  133. package/dist/core/mcp/oauth-store.test.js +2 -2
  134. package/dist/core/mcp/resolve-stdio.test.js +5 -5
  135. package/dist/core/mcp/shared-pool.test.js +5 -5
  136. package/dist/core/mcp/store.test.js +5 -5
  137. package/dist/core/mcp/when-connected.test.js +2 -2
  138. package/dist/core/nolan-model.test.js +1 -1
  139. package/dist/core/nolan-prompt.js +5 -5
  140. package/dist/core/oauth/xai.d.ts +2 -0
  141. package/dist/core/oauth/xai.d.ts.map +1 -0
  142. package/dist/core/oauth/xai.js +4 -0
  143. package/dist/core/oauth/xai.js.map +1 -0
  144. package/dist/core/persistent-shell.js +1 -1
  145. package/dist/core/persistent-shell.test.js +6 -6
  146. package/dist/core/process-manager-dev-server-repro.test.js +51 -12
  147. package/dist/core/process-manager-dev-server-repro.test.js.map +1 -1
  148. package/dist/core/process-manager-notifications.test.js +24 -14
  149. package/dist/core/process-manager-notifications.test.js.map +1 -1
  150. package/dist/core/process-manager.d.ts +22 -0
  151. package/dist/core/process-manager.d.ts.map +1 -1
  152. package/dist/core/process-manager.js +58 -2
  153. package/dist/core/process-manager.js.map +1 -1
  154. package/dist/core/progress/git-xp.test.js +2 -2
  155. package/dist/core/progress/ranks.d.ts +14 -3
  156. package/dist/core/progress/ranks.d.ts.map +1 -1
  157. package/dist/core/progress/ranks.js +181 -12
  158. package/dist/core/progress/ranks.js.map +1 -1
  159. package/dist/core/progress/ranks.test.js +48 -7
  160. package/dist/core/progress/ranks.test.js.map +1 -1
  161. package/dist/core/progress/rebuild.test.js +1 -1
  162. package/dist/core/progress/store.test.js +1 -1
  163. package/dist/core/progress/types.d.ts +2 -1
  164. package/dist/core/progress/types.d.ts.map +1 -1
  165. package/dist/core/project-discovery.d.ts.map +1 -1
  166. package/dist/core/project-discovery.js +62 -48
  167. package/dist/core/project-discovery.js.map +1 -1
  168. package/dist/core/project-discovery.test.js +10 -10
  169. package/dist/core/prompt-commands.js +3 -3
  170. package/dist/core/radio.d.ts +1 -1
  171. package/dist/core/radio.d.ts.map +1 -1
  172. package/dist/core/radio.js +90 -6
  173. package/dist/core/radio.js.map +1 -1
  174. package/dist/core/radio.test.js +15 -2
  175. package/dist/core/radio.test.js.map +1 -1
  176. package/dist/core/run-journal.test.js +2 -2
  177. package/dist/core/sandbox.test.js +6 -6
  178. package/dist/core/semantic-search-benchmark.d.ts +2 -2
  179. package/dist/core/semantic-search-benchmark.js +5 -5
  180. package/dist/core/session-compaction.test.js +1 -1
  181. package/dist/core/session-manager.d.ts.map +1 -1
  182. package/dist/core/session-manager.js +83 -67
  183. package/dist/core/session-manager.js.map +1 -1
  184. package/dist/core/session-manager.test.js +7 -7
  185. package/dist/core/session-storage-fd-leak.test.d.ts +2 -0
  186. package/dist/core/session-storage-fd-leak.test.d.ts.map +1 -0
  187. package/dist/core/session-storage-fd-leak.test.js +116 -0
  188. package/dist/core/session-storage-fd-leak.test.js.map +1 -0
  189. package/dist/core/session-storage.d.ts +22 -2
  190. package/dist/core/session-storage.d.ts.map +1 -1
  191. package/dist/core/session-storage.js +33 -6
  192. package/dist/core/session-storage.js.map +1 -1
  193. package/dist/core/session-storage.test.js +2 -2
  194. package/dist/core/settings-manager.d.ts +2 -0
  195. package/dist/core/settings-manager.d.ts.map +1 -1
  196. package/dist/core/settings-manager.js +10 -1
  197. package/dist/core/settings-manager.js.map +1 -1
  198. package/dist/core/shell-path.js +1 -1
  199. package/dist/core/shell.d.ts +1 -1
  200. package/dist/core/shell.js +2 -2
  201. package/dist/core/shell.test.js +2 -2
  202. package/dist/core/shutdown.d.ts +71 -0
  203. package/dist/core/shutdown.d.ts.map +1 -0
  204. package/dist/core/shutdown.js +144 -0
  205. package/dist/core/shutdown.js.map +1 -0
  206. package/dist/core/shutdown.test.d.ts +2 -0
  207. package/dist/core/shutdown.test.d.ts.map +1 -0
  208. package/dist/core/shutdown.test.js +160 -0
  209. package/dist/core/shutdown.test.js.map +1 -0
  210. package/dist/core/sidecar-error-reporter.js +1 -1
  211. package/dist/core/sidecar-error-reporter.test.js +2 -2
  212. package/dist/core/skills-routing.test.js +96 -0
  213. package/dist/core/skills-routing.test.js.map +1 -1
  214. package/dist/core/skills.d.ts.map +1 -1
  215. package/dist/core/skills.js +3 -0
  216. package/dist/core/skills.js.map +1 -1
  217. package/dist/core/subagent-manager.d.ts +9 -0
  218. package/dist/core/subagent-manager.d.ts.map +1 -1
  219. package/dist/core/subagent-manager.js +45 -12
  220. package/dist/core/subagent-manager.js.map +1 -1
  221. package/dist/core/subagent-manager.test.js +14 -8
  222. package/dist/core/subagent-manager.test.js.map +1 -1
  223. package/dist/core/subagent-store.test.js +3 -3
  224. package/dist/core/task-store.js +1 -1
  225. package/dist/index.js +1 -1
  226. package/dist/index.js.map +1 -1
  227. package/dist/modes/acp-mode.js +2 -2
  228. package/dist/modes/acp-mode.test.js +4 -4
  229. package/dist/modes/agent-home-mode.d.ts.map +1 -1
  230. package/dist/modes/agent-home-mode.js +15 -11
  231. package/dist/modes/agent-home-mode.js.map +1 -1
  232. package/dist/modes/json-mode.d.ts +9 -1
  233. package/dist/modes/json-mode.d.ts.map +1 -1
  234. package/dist/modes/json-mode.js +3 -1
  235. package/dist/modes/json-mode.js.map +1 -1
  236. package/dist/modes/serve-mode.d.ts +1 -1
  237. package/dist/modes/serve-mode.d.ts.map +1 -1
  238. package/dist/modes/serve-mode.js +14 -9
  239. package/dist/modes/serve-mode.js.map +1 -1
  240. package/dist/modes/subagent-worker-mode.d.ts +5 -0
  241. package/dist/modes/subagent-worker-mode.d.ts.map +1 -1
  242. package/dist/modes/subagent-worker-mode.js.map +1 -1
  243. package/dist/session.test.js +1 -1
  244. package/dist/system-prompt.d.ts +37 -1
  245. package/dist/system-prompt.d.ts.map +1 -1
  246. package/dist/system-prompt.js +123 -11
  247. package/dist/system-prompt.js.map +1 -1
  248. package/dist/system-prompt.test.js +90 -11
  249. package/dist/system-prompt.test.js.map +1 -1
  250. package/dist/system-prompt.tiering.test.d.ts +2 -0
  251. package/dist/system-prompt.tiering.test.d.ts.map +1 -0
  252. package/dist/system-prompt.tiering.test.js +105 -0
  253. package/dist/system-prompt.tiering.test.js.map +1 -0
  254. package/dist/tools/code-nav.d.ts +30 -0
  255. package/dist/tools/code-nav.d.ts.map +1 -0
  256. package/dist/tools/code-nav.js +320 -0
  257. package/dist/tools/code-nav.js.map +1 -0
  258. package/dist/tools/code-nav.test.d.ts +2 -0
  259. package/dist/tools/code-nav.test.d.ts.map +1 -0
  260. package/dist/tools/code-nav.test.js +136 -0
  261. package/dist/tools/code-nav.test.js.map +1 -0
  262. package/dist/tools/edit.test.js +1 -1
  263. package/dist/tools/generate-image.d.ts +1 -1
  264. package/dist/tools/goals.d.ts +2 -2
  265. package/dist/tools/goals.test.js +2 -2
  266. package/dist/tools/grep-parity.test.d.ts +2 -0
  267. package/dist/tools/grep-parity.test.d.ts.map +1 -0
  268. package/dist/tools/grep-parity.test.js +92 -0
  269. package/dist/tools/grep-parity.test.js.map +1 -0
  270. package/dist/tools/grep-recall.test.d.ts +2 -0
  271. package/dist/tools/grep-recall.test.d.ts.map +1 -0
  272. package/dist/tools/grep-recall.test.js +114 -0
  273. package/dist/tools/grep-recall.test.js.map +1 -0
  274. package/dist/tools/grep-spawn.test.d.ts +2 -0
  275. package/dist/tools/grep-spawn.test.d.ts.map +1 -0
  276. package/dist/tools/grep-spawn.test.js +66 -0
  277. package/dist/tools/grep-spawn.test.js.map +1 -0
  278. package/dist/tools/grep.d.ts +13 -3
  279. package/dist/tools/grep.d.ts.map +1 -1
  280. package/dist/tools/grep.js +340 -40
  281. package/dist/tools/grep.js.map +1 -1
  282. package/dist/tools/grep.test.js +17 -14
  283. package/dist/tools/grep.test.js.map +1 -1
  284. package/dist/tools/index.d.ts +7 -0
  285. package/dist/tools/index.d.ts.map +1 -1
  286. package/dist/tools/index.js +8 -1
  287. package/dist/tools/index.js.map +1 -1
  288. package/dist/tools/plan-mode.test.js +1 -1
  289. package/dist/tools/prompt-hints.d.ts +9 -0
  290. package/dist/tools/prompt-hints.d.ts.map +1 -1
  291. package/dist/tools/prompt-hints.js +61 -8
  292. package/dist/tools/prompt-hints.js.map +1 -1
  293. package/dist/tools/safe-env.js +1 -1
  294. package/dist/tools/search-code.d.ts.map +1 -1
  295. package/dist/tools/search-code.js +7 -6
  296. package/dist/tools/search-code.js.map +1 -1
  297. package/dist/tools/search-code.test.js +8 -2
  298. package/dist/tools/search-code.test.js.map +1 -1
  299. package/dist/tools/skill.js +2 -1
  300. package/dist/tools/skill.js.map +1 -1
  301. package/dist/tools/subagent-control.d.ts.map +1 -1
  302. package/dist/tools/subagent-control.js +20 -5
  303. package/dist/tools/subagent-control.js.map +1 -1
  304. package/dist/tools/subagent-control.test.js +34 -1
  305. package/dist/tools/subagent-control.test.js.map +1 -1
  306. package/dist/tools/subagent-shared.d.ts +20 -1
  307. package/dist/tools/subagent-shared.d.ts.map +1 -1
  308. package/dist/tools/subagent-shared.js +34 -7
  309. package/dist/tools/subagent-shared.js.map +1 -1
  310. package/dist/tools/subagent-shared.test.js +43 -9
  311. package/dist/tools/subagent-shared.test.js.map +1 -1
  312. package/dist/tools/subagent.d.ts.map +1 -1
  313. package/dist/tools/subagent.js +11 -8
  314. package/dist/tools/subagent.js.map +1 -1
  315. package/dist/tools/subagent.test.js +3 -0
  316. package/dist/tools/subagent.test.js.map +1 -1
  317. package/dist/tools/task-send.test.js +19 -10
  318. package/dist/tools/task-send.test.js.map +1 -1
  319. package/dist/tools/tool-search.d.ts.map +1 -1
  320. package/dist/tools/tool-search.js +2 -1
  321. package/dist/tools/tool-search.js.map +1 -1
  322. package/dist/tools/tool-tiers.d.ts +42 -0
  323. package/dist/tools/tool-tiers.d.ts.map +1 -0
  324. package/dist/tools/tool-tiers.js +78 -0
  325. package/dist/tools/tool-tiers.js.map +1 -0
  326. package/dist/tools/tool-tiers.test.d.ts +2 -0
  327. package/dist/tools/tool-tiers.test.d.ts.map +1 -0
  328. package/dist/tools/tool-tiers.test.js +48 -0
  329. package/dist/tools/tool-tiers.test.js.map +1 -0
  330. package/dist/tools/write.test.js +1 -1
  331. package/dist/ui/App.js.map +1 -1
  332. package/dist/ui/components/Banner.d.ts.map +1 -1
  333. package/dist/ui/components/Banner.js +24 -16
  334. package/dist/ui/components/Banner.js.map +1 -1
  335. package/dist/ui/components/ToolExecution.js +42 -34
  336. package/dist/ui/components/ToolExecution.js.map +1 -1
  337. package/dist/ui/components/force-color.d.ts +2 -0
  338. package/dist/ui/components/force-color.d.ts.map +1 -0
  339. package/dist/ui/components/force-color.js +11 -0
  340. package/dist/ui/components/force-color.js.map +1 -0
  341. package/dist/ui/components/themed-output.test.d.ts +2 -0
  342. package/dist/ui/components/themed-output.test.d.ts.map +1 -0
  343. package/dist/ui/components/themed-output.test.js +111 -0
  344. package/dist/ui/components/themed-output.test.js.map +1 -0
  345. package/dist/ui/error-item.d.ts +1 -1
  346. package/dist/ui/error-item.js +3 -3
  347. package/dist/ui/error-item.js.map +1 -1
  348. package/dist/ui/hooks/useAgentLoop.d.ts +3 -0
  349. package/dist/ui/hooks/useAgentLoop.d.ts.map +1 -1
  350. package/dist/ui/hooks/useAgentLoop.js +27 -2
  351. package/dist/ui/hooks/useAgentLoop.js.map +1 -1
  352. package/dist/ui/login.js +1 -1
  353. package/dist/ui/login.js.map +1 -1
  354. package/dist/ui/render.d.ts +1 -1
  355. package/dist/ui/render.js +6 -6
  356. package/dist/ui/theme/dark-ansi.json +6 -0
  357. package/dist/ui/theme/dark-daltonized.json +6 -0
  358. package/dist/ui/theme/dark.json +6 -0
  359. package/dist/ui/theme/light-ansi.json +6 -0
  360. package/dist/ui/theme/light-daltonized.json +6 -0
  361. package/dist/ui/theme/light.json +6 -0
  362. package/dist/ui/theme/theme.d.ts +6 -0
  363. package/dist/ui/theme/theme.d.ts.map +1 -1
  364. package/dist/ui/tui-terminal-recorder.test.js +1 -1
  365. package/dist/utils/git.test.js +3 -3
  366. package/package.json +4 -4
@@ -0,0 +1,172 @@
1
+ import { log } from "../logger.js";
2
+ import { shrinkToFit } from "../../utils/image.js";
3
+ /** Media types a provider will accept as an image part. */
4
+ const SUPPORTED_IMAGE_MEDIA_TYPES = new Set(["image/png", "image/jpeg", "image/gif", "image/webp"]);
5
+ /**
6
+ * Cap on image parts forwarded from a single tool call. An MCP server is
7
+ * third-party code and can return an unbounded array; each image costs real
8
+ * tokens, so keep the rest as a counted note rather than silently blowing up
9
+ * the turn.
10
+ */
11
+ const MAX_IMAGES_PER_RESULT = 4;
12
+ function record(item) {
13
+ if (item == null || typeof item !== "object")
14
+ return null;
15
+ return item;
16
+ }
17
+ function str(value) {
18
+ return typeof value === "string" && value.length > 0 ? value : undefined;
19
+ }
20
+ /**
21
+ * An MCP image part, per spec: `{ type: "image", data: <base64>, mimeType }`.
22
+ * Validated structurally because the payload crosses a trust boundary — a
23
+ * server can send anything, including a `type` that lies about the shape.
24
+ */
25
+ function asImagePart(item) {
26
+ const part = record(item);
27
+ if (!part || part.type !== "image")
28
+ return null;
29
+ const data = str(part.data);
30
+ if (!data)
31
+ return null;
32
+ return { data, mimeType: str(part.mimeType) ?? "image/png" };
33
+ }
34
+ /**
35
+ * An image delivered as an embedded resource rather than an `image` block:
36
+ * `{ type: "resource", resource: { uri, mimeType: "image/png", blob } }`. Servers
37
+ * use this shape when the image also has a URI, and it is just as viewable, so
38
+ * it must not be reduced to a note.
39
+ */
40
+ function asEmbeddedImage(item) {
41
+ const part = record(item);
42
+ if (!part || part.type !== "resource")
43
+ return null;
44
+ const resource = record(part.resource);
45
+ if (!resource)
46
+ return null;
47
+ const mimeType = str(resource.mimeType);
48
+ const blob = str(resource.blob);
49
+ if (!blob || !mimeType?.startsWith("image/"))
50
+ return null;
51
+ return { data: blob, mimeType };
52
+ }
53
+ /**
54
+ * Render a non-image block as text.
55
+ *
56
+ * Every branch returns *something*: a block this function drops is a block the
57
+ * model never learns existed, which is the defect this module exists to fix.
58
+ * `null` means "carries no information" (an empty text block), not "unsupported".
59
+ */
60
+ function asText(item, toolName) {
61
+ const part = record(item);
62
+ if (!part)
63
+ return null;
64
+ switch (part.type) {
65
+ case "text":
66
+ return typeof part.text === "string" ? part.text : null;
67
+ // Audio is not viewable by any provider we target; name it so the model can
68
+ // say what it received rather than behaving as though nothing came back.
69
+ case "audio":
70
+ return `[${toolName} returned audio (${str(part.mimeType) ?? "unknown format"})]`;
71
+ // A link is a reference, not content: pass the address through so the model
72
+ // can fetch or cite it.
73
+ case "resource_link": {
74
+ const label = str(part.title) ?? str(part.name);
75
+ const uri = str(part.uri) ?? "(no uri)";
76
+ return label ? `[resource link: ${label}] ${uri}` : `[resource link] ${uri}`;
77
+ }
78
+ case "resource": {
79
+ const resource = record(part.resource);
80
+ if (!resource)
81
+ return null;
82
+ const uri = str(resource.uri) ?? "(no uri)";
83
+ // An embedded text resource carries its content inline — this is usually
84
+ // the substantive answer (a file, a query result), so surface it in full
85
+ // under a header rather than describing it.
86
+ const text = typeof resource.text === "string" ? resource.text : undefined;
87
+ if (text !== undefined)
88
+ return `[resource ${uri}]\n${text}`;
89
+ const blob = str(resource.blob);
90
+ if (blob) {
91
+ // Non-image binary: unusable by the model, but its existence and size
92
+ // are what let it reason about what the server actually returned.
93
+ const kind = str(resource.mimeType) ?? "binary";
94
+ return `[resource ${uri} (${kind}, ${Buffer.byteLength(blob, "base64")} bytes) omitted]`;
95
+ }
96
+ return `[resource ${uri}]`;
97
+ }
98
+ default:
99
+ // Unknown block type: a future spec addition. Prefer a fallback over
100
+ // silence, but only when it actually carries text.
101
+ return typeof part.text === "string" ? part.text : null;
102
+ }
103
+ }
104
+ /**
105
+ * Convert an MCP tool's content array into a result the model can actually
106
+ * consume, covering the whole `ContentBlock` union rather than text alone.
107
+ *
108
+ * Text-only results stay plain strings so the overwhelmingly common path keeps
109
+ * its existing shape (and the agent loop's string budgeting still applies).
110
+ * Images are re-encoded through {@link shrinkToFit}, the same helper the `read`
111
+ * tool uses: an unbounded screenshot from a third-party server would otherwise
112
+ * exceed provider size limits and fail the whole turn. A media type the buffer
113
+ * contradicts is corrected there too, since providers reject mismatches.
114
+ *
115
+ * Anything not viewable — audio, a resource link, a binary blob, an unreadable
116
+ * image — becomes a text note instead of vanishing. A block silently dropped is
117
+ * one the model never learns existed, so it answers as though the server
118
+ * returned nothing; a note lets it say what it actually got.
119
+ */
120
+ export async function toToolResult(content, toolName) {
121
+ const texts = [];
122
+ const rawImages = [];
123
+ for (const item of content) {
124
+ const image = asImagePart(item) ?? asEmbeddedImage(item);
125
+ if (image) {
126
+ rawImages.push(image);
127
+ continue;
128
+ }
129
+ const text = asText(item, toolName);
130
+ if (text !== null)
131
+ texts.push(text);
132
+ }
133
+ if (rawImages.length === 0) {
134
+ return texts.join("\n") || "(empty response)";
135
+ }
136
+ const dropped = rawImages.length - MAX_IMAGES_PER_RESULT;
137
+ const kept = dropped > 0 ? rawImages.slice(0, MAX_IMAGES_PER_RESULT) : rawImages;
138
+ const parts = [];
139
+ for (const image of kept) {
140
+ try {
141
+ const raw = Buffer.from(image.data, "base64");
142
+ if (raw.length === 0) {
143
+ parts.push({ type: "text", text: `[${toolName} returned an empty image]` });
144
+ continue;
145
+ }
146
+ const { buffer, mediaType } = await shrinkToFit(raw, image.mimeType);
147
+ if (!SUPPORTED_IMAGE_MEDIA_TYPES.has(mediaType)) {
148
+ parts.push({
149
+ type: "text",
150
+ text: `[${toolName} returned an image in unsupported format ${mediaType}]`,
151
+ });
152
+ continue;
153
+ }
154
+ parts.push({ type: "image", mediaType, data: buffer.toString("base64") });
155
+ }
156
+ catch (err) {
157
+ // A malformed or undecodable image must not fail the tool call: the text
158
+ // parts of the same response are often the substantive answer.
159
+ const reason = err instanceof Error ? err.message : String(err);
160
+ log("WARN", "mcp", "Dropping unreadable MCP image part", { tool: toolName, reason });
161
+ parts.push({ type: "text", text: `[${toolName} returned an unreadable image]` });
162
+ }
163
+ }
164
+ const notes = [...texts];
165
+ if (dropped > 0) {
166
+ notes.push(`[${dropped} further image${dropped === 1 ? "" : "s"} omitted]`);
167
+ }
168
+ // Text first: it frames the images for the model, and matches `read`'s order.
169
+ const leading = notes.join("\n");
170
+ return { content: leading ? [{ type: "text", text: leading }, ...parts] : parts };
171
+ }
172
+ //# sourceMappingURL=content.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"content.js","sourceRoot":"","sources":["../../../src/core/mcp/content.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=content.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"content.test.d.ts","sourceRoot":"","sources":["../../../src/core/mcp/content.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,135 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import sharp from "sharp";
3
+ import { toToolResult } from "./content.js";
4
+ import { boundedSize } from "../../utils/image.js";
5
+ /** Mirrors the private cap in utils/image.ts — kept local rather than widening that module's API. */
6
+ const MAX_IMAGE_BYTES = 5 * 1024 * 1024;
7
+ async function pngBase64(width, height) {
8
+ const buffer = await sharp({
9
+ create: { width, height, channels: 3, background: { r: 10, g: 120, b: 200 } },
10
+ })
11
+ .png()
12
+ .toBuffer();
13
+ return buffer.toString("base64");
14
+ }
15
+ describe("toToolResult", () => {
16
+ it("keeps a text-only response a plain string", async () => {
17
+ const result = await toToolResult([{ type: "text", text: "hello" }], "mcp__x__y");
18
+ expect(result).toBe("hello");
19
+ });
20
+ it("reports an empty response only when there is genuinely nothing", async () => {
21
+ expect(await toToolResult([], "mcp__x__y")).toBe("(empty response)");
22
+ });
23
+ // Every one of these used to return "(empty response)" — the same defect as the
24
+ // image case, one block type over.
25
+ describe("non-image blocks reach the model instead of vanishing", () => {
26
+ it("surfaces an embedded text resource in full", async () => {
27
+ const result = await toToolResult([
28
+ {
29
+ type: "resource",
30
+ resource: { uri: "file:///notes.md", mimeType: "text/markdown", text: "THE ANSWER" },
31
+ },
32
+ ], "mcp__s__t");
33
+ expect(result).toContain("THE ANSWER");
34
+ expect(result).toContain("file:///notes.md");
35
+ });
36
+ it("passes a resource link's address through", async () => {
37
+ const result = await toToolResult([{ type: "resource_link", uri: "https://example.com/a", name: "report" }], "mcp__s__t");
38
+ expect(result).toContain("https://example.com/a");
39
+ expect(result).toContain("report");
40
+ });
41
+ it("names audio rather than returning nothing", async () => {
42
+ const result = await toToolResult([{ type: "audio", data: "aGk=", mimeType: "audio/wav" }], "mcp__s__t");
43
+ expect(result).toContain("audio");
44
+ expect(result).not.toBe("(empty response)");
45
+ });
46
+ it("notes a non-image binary blob with its size", async () => {
47
+ const result = await toToolResult([
48
+ {
49
+ type: "resource",
50
+ resource: { uri: "file:///a.zip", mimeType: "application/zip", blob: "AAAA" },
51
+ },
52
+ ], "mcp__s__t");
53
+ expect(result).toContain("file:///a.zip");
54
+ expect(result).toContain("application/zip");
55
+ expect(result).toContain("3 bytes");
56
+ });
57
+ it("falls back to text on an unknown future block type", async () => {
58
+ const result = await toToolResult([{ type: "video", text: "a clip" }], "mcp__s__t");
59
+ expect(result).toBe("a clip");
60
+ });
61
+ });
62
+ // Servers use this shape when the image also has a URI; it is just as viewable.
63
+ it("forwards an image delivered as an embedded resource blob", async () => {
64
+ const data = await pngBase64(8, 8);
65
+ const result = await toToolResult([
66
+ {
67
+ type: "resource",
68
+ resource: { uri: "file:///shot.png", mimeType: "image/png", blob: data },
69
+ },
70
+ ], "mcp__s__t");
71
+ const parts = result.content;
72
+ expect(parts.some((p) => p.type === "image")).toBe(true);
73
+ });
74
+ it("forwards an image-only response instead of dropping it", async () => {
75
+ const data = await pngBase64(8, 8);
76
+ const result = await toToolResult([{ type: "image", data, mimeType: "image/png" }], "mcp__s__t");
77
+ expect(typeof result).not.toBe("string");
78
+ const parts = result.content;
79
+ expect(parts).toHaveLength(1);
80
+ expect(parts[0]).toMatchObject({ type: "image", mediaType: "image/png" });
81
+ });
82
+ it("puts text before images so it frames them", async () => {
83
+ const data = await pngBase64(8, 8);
84
+ const result = await toToolResult([
85
+ { type: "text", text: "here is the chart" },
86
+ { type: "image", data, mimeType: "image/png" },
87
+ ], "mcp__s__t");
88
+ const parts = result.content;
89
+ expect(parts.map((p) => p.type)).toEqual(["text", "image"]);
90
+ expect(parts[0]?.text).toBe("here is the chart");
91
+ });
92
+ // A third-party server can return a screenshot far larger than any provider
93
+ // accepts; forwarding it verbatim would fail the whole turn.
94
+ it("shrinks an oversized image to fit provider limits", async () => {
95
+ const huge = boundedSize(8000, 8000);
96
+ const data = await pngBase64(8000, 8000);
97
+ expect(Buffer.from(data, "base64").length).toBeGreaterThan(0);
98
+ const result = await toToolResult([{ type: "image", data, mimeType: "image/png" }], "mcp__s__t");
99
+ const parts = result.content;
100
+ const image = parts.find((p) => p.type === "image");
101
+ const bytes = Buffer.from(image?.data ?? "", "base64");
102
+ expect(bytes.length).toBeLessThanOrEqual(MAX_IMAGE_BYTES);
103
+ const meta = await sharp(bytes).metadata();
104
+ expect(meta.width).toBeLessThanOrEqual(huge.width);
105
+ });
106
+ // Providers reject a media type the bytes contradict.
107
+ it("corrects a media type the payload disagrees with", async () => {
108
+ const data = await pngBase64(8, 8);
109
+ const result = await toToolResult([{ type: "image", data, mimeType: "image/jpeg" }], "mcp__s__t");
110
+ const parts = result.content;
111
+ expect(parts.find((p) => p.type === "image")?.mediaType).toBe("image/png");
112
+ });
113
+ it("degrades an unreadable image to a note and keeps the text", async () => {
114
+ const result = await toToolResult([
115
+ { type: "text", text: "rendered" },
116
+ { type: "image", data: "bm90LWFuLWltYWdl", mimeType: "image/png" },
117
+ ], "mcp__s__t");
118
+ const parts = result.content;
119
+ expect(parts[0]?.text).toBe("rendered");
120
+ expect(parts[1]?.text).toContain("unreadable image");
121
+ });
122
+ it("caps how many images one call can forward", async () => {
123
+ const data = await pngBase64(8, 8);
124
+ const many = Array.from({ length: 7 }, () => ({
125
+ type: "image",
126
+ data,
127
+ mimeType: "image/png",
128
+ }));
129
+ const result = await toToolResult(many, "mcp__s__t");
130
+ const parts = result.content;
131
+ expect(parts.filter((p) => p.type === "image")).toHaveLength(4);
132
+ expect(parts[0]?.text).toContain("3 further images omitted");
133
+ });
134
+ });
135
+ //# sourceMappingURL=content.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"content.test.js","sourceRoot":"","sources":["../../../src/core/mcp/content.test.ts"],"names":[],"mappings":"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"}
@@ -3,7 +3,7 @@ import type { AgentTool } from "@prestyj/agent";
3
3
  * Holds MCP tools OUT of the per-turn request payload until the model asks
4
4
  * for them via `tool_search`.
5
5
  *
6
- * Benchmarked (bench/RESULTS.md, bench A): injecting every MCP tool schema
6
+ * Measured: injecting every MCP tool schema
7
7
  * eagerly cost ~33KB (~8.3k tokens) per cache-miss turn with just two MCP
8
8
  * servers connected — 56% of all billed input tokens in a 6-turn session.
9
9
  * Deferring keeps the tool prefix small and byte-stable; promotion is a
@@ -2,7 +2,7 @@
2
2
  * Holds MCP tools OUT of the per-turn request payload until the model asks
3
3
  * for them via `tool_search`.
4
4
  *
5
- * Benchmarked (bench/RESULTS.md, bench A): injecting every MCP tool schema
5
+ * Measured: injecting every MCP tool schema
6
6
  * eagerly cost ~33KB (~8.3k tokens) per cache-miss turn with just two MCP
7
7
  * servers connected — 56% of all billed input tokens in a 6-turn session.
8
8
  * Deferring keeps the tool prefix small and byte-stable; promotion is a
@@ -36,7 +36,7 @@ async function callTool(tools, suffix) {
36
36
  return typeof result === "string" ? result : JSON.stringify(result);
37
37
  }
38
38
  beforeEach(async () => {
39
- dir = await fs.mkdtemp(path.join(os.tmpdir(), "gg-mcp-elicit-"));
39
+ dir = await fs.mkdtemp(path.join(os.tmpdir(), "ez-mcp-elicit-"));
40
40
  });
41
41
  afterEach(async () => {
42
42
  await Promise.all(managers.splice(0).map((instance) => instance.dispose()));
@@ -28,7 +28,7 @@ function legacyServer(overrides = {}) {
28
28
  };
29
29
  }
30
30
  beforeEach(async () => {
31
- dir = await fs.mkdtemp(path.join(os.tmpdir(), "gg-mcp-legacy-"));
31
+ dir = await fs.mkdtemp(path.join(os.tmpdir(), "ez-mcp-legacy-"));
32
32
  cachePath = path.join(dir, "mcp-catalog.json");
33
33
  });
34
34
  afterEach(async () => {
@@ -55,7 +55,7 @@ describe("2025-only stdio server under version negotiation", () => {
55
55
  it("connects a server that stays silent on the discovery probe", async () => {
56
56
  const config = legacyServer({
57
57
  name: "silent-legacy-fixture",
58
- env: { GG_FIXTURE_SILENT_ON_UNKNOWN: "1" },
58
+ env: { EZ_FIXTURE_SILENT_ON_UNKNOWN: "1" },
59
59
  // Generous connect budget: the point is that the PROBE does not consume
60
60
  // it. Without a stdio-specific probe timeout the probe inherits this
61
61
  // value, so a silent server would burn the full 30s before falling back.
@@ -8,7 +8,7 @@ describe("McpOAuthStore", () => {
8
8
  let dir;
9
9
  let file;
10
10
  beforeEach(async () => {
11
- dir = await fs.mkdtemp(path.join(os.tmpdir(), "gg-mcp-auth-"));
11
+ dir = await fs.mkdtemp(path.join(os.tmpdir(), "ez-mcp-auth-"));
12
12
  file = path.join(dir, "mcp-auth.json");
13
13
  });
14
14
  afterEach(async () => {
@@ -46,7 +46,7 @@ describe("McpOAuthProvider", () => {
46
46
  let dir;
47
47
  let store;
48
48
  beforeEach(async () => {
49
- dir = await fs.mkdtemp(path.join(os.tmpdir(), "gg-mcp-prov-"));
49
+ dir = await fs.mkdtemp(path.join(os.tmpdir(), "ez-mcp-prov-"));
50
50
  store = new McpOAuthStore(path.join(dir, "mcp-auth.json"));
51
51
  });
52
52
  afterEach(async () => {
@@ -92,7 +92,7 @@ describe("resolveStdioCommand npx-cache fallback (covers user-added MCPs)", () =
92
92
  tmp = undefined;
93
93
  });
94
94
  it("rewrites a non-bundled but npx-cached server to `node <binScript>`", () => {
95
- tmp = fs.mkdtempSync(path.join(os.tmpdir(), "gg-npx-cache-"));
95
+ tmp = fs.mkdtempSync(path.join(os.tmpdir(), "ez-npx-cache-"));
96
96
  seedNpxCache(tmp, "hash1", "@vendor/cool-mcp", "1.0.0");
97
97
  process.env.npm_config_cache = tmp;
98
98
  const out = resolveStdioCommand("npx", ["-y", "@vendor/cool-mcp"]);
@@ -100,7 +100,7 @@ describe("resolveStdioCommand npx-cache fallback (covers user-added MCPs)", () =
100
100
  expect(out.args[0]).toMatch(/cool-mcp[/\\]build[/\\]index\.js$/);
101
101
  });
102
102
  it("honours a version pin: a mismatched cached version falls through to npx", () => {
103
- tmp = fs.mkdtempSync(path.join(os.tmpdir(), "gg-npx-cache-"));
103
+ tmp = fs.mkdtempSync(path.join(os.tmpdir(), "ez-npx-cache-"));
104
104
  seedNpxCache(tmp, "hash1", "@vendor/cool-mcp", "1.0.0");
105
105
  process.env.npm_config_cache = tmp;
106
106
  // Requested @2.0.0, only 1.0.0 cached → do NOT rewrite to the wrong version.
@@ -111,7 +111,7 @@ describe("resolveStdioCommand npx-cache fallback (covers user-added MCPs)", () =
111
111
  expect(out.command).toBe("npx");
112
112
  });
113
113
  it("uses a cached copy whose version matches the pin exactly", () => {
114
- tmp = fs.mkdtempSync(path.join(os.tmpdir(), "gg-npx-cache-"));
114
+ tmp = fs.mkdtempSync(path.join(os.tmpdir(), "ez-npx-cache-"));
115
115
  seedNpxCache(tmp, "hash1", "@vendor/cool-mcp", "2.0.0");
116
116
  process.env.npm_config_cache = tmp;
117
117
  const out = resolveStdioCommand("npx", ["-y", "@vendor/cool-mcp@2.0.0"]);
@@ -119,7 +119,7 @@ describe("resolveStdioCommand npx-cache fallback (covers user-added MCPs)", () =
119
119
  expect(out.args[0]).toMatch(/cool-mcp[/\\]build[/\\]index\.js$/);
120
120
  });
121
121
  it("picks the highest cached version when the spec is unpinned", () => {
122
- tmp = fs.mkdtempSync(path.join(os.tmpdir(), "gg-npx-cache-"));
122
+ tmp = fs.mkdtempSync(path.join(os.tmpdir(), "ez-npx-cache-"));
123
123
  seedNpxCache(tmp, "old", "@vendor/cool-mcp", "1.2.0", "build/old.js");
124
124
  seedNpxCache(tmp, "new", "@vendor/cool-mcp", "1.10.0", "build/new.js");
125
125
  process.env.npm_config_cache = tmp;
@@ -131,7 +131,7 @@ describe("resolveStdioCommand npx-cache fallback (covers user-added MCPs)", () =
131
131
  it("resolves a sole bin whose key differs from the package name (e.g. zai)", () => {
132
132
  // @z_ai/mcp-server exposes bin `zai-mcp-server`, NOT `mcp-server`. A sole
133
133
  // bin must be used regardless of its key, or the rewrite silently misses.
134
- tmp = fs.mkdtempSync(path.join(os.tmpdir(), "gg-npx-cache-"));
134
+ tmp = fs.mkdtempSync(path.join(os.tmpdir(), "ez-npx-cache-"));
135
135
  const pkgDir = path.join(tmp, "_npx", "h", "node_modules", "@z_ai", "mcp-server");
136
136
  fs.mkdirSync(path.join(pkgDir, "build"), { recursive: true });
137
137
  fs.writeFileSync(path.join(pkgDir, "build", "index.js"), "#!/usr/bin/env node\n");
@@ -20,7 +20,7 @@ let cachePath;
20
20
  const managers = [];
21
21
  const pools = [];
22
22
  beforeEach(async () => {
23
- dir = await fs.mkdtemp(path.join(os.tmpdir(), "gg-mcp-shared-"));
23
+ dir = await fs.mkdtemp(path.join(os.tmpdir(), "ez-mcp-shared-"));
24
24
  cachePath = path.join(dir, "mcp-catalog.json");
25
25
  });
26
26
  afterEach(async () => {
@@ -51,14 +51,14 @@ function sharedFixture(overrides = {}) {
51
51
  return {
52
52
  name: "shared-fixture",
53
53
  command: process.execPath,
54
- args: [FIXTURE, `--gg-marker=${crypto.randomUUID()}`],
54
+ args: [FIXTURE, `--ez-marker=${crypto.randomUUID()}`],
55
55
  timeout: 10_000,
56
56
  ...overrides,
57
57
  };
58
58
  }
59
59
  /** Live child processes carrying this config's marker argument. */
60
60
  function processCount(config) {
61
- const marker = config.args?.find((arg) => arg.startsWith("--gg-marker="));
61
+ const marker = config.args?.find((arg) => arg.startsWith("--ez-marker="));
62
62
  if (!marker)
63
63
  throw new Error("fixture config has no marker argument");
64
64
  const out = execFileSync("ps", ["-eo", "command"], { encoding: "utf8" });
@@ -351,7 +351,7 @@ describe.skipIf(process.platform === "win32")("shared servers across two session
351
351
  // Kill the child out from under the pool, exactly like a crash. Located
352
352
  // with `ps` rather than `pgrep`, whose BSD build reads this fixture's
353
353
  // leading `--` marker as an illegal option.
354
- const marker = config.args.find((arg) => arg.startsWith("--gg-marker="));
354
+ const marker = config.args.find((arg) => arg.startsWith("--ez-marker="));
355
355
  const row = execFileSync("ps", ["-eo", "pid,command"], { encoding: "utf8" })
356
356
  .split("\n")
357
357
  .find((line) => line.includes(marker));
@@ -381,7 +381,7 @@ describe.skipIf(process.platform === "win32")("shared servers across two session
381
381
  const config = {
382
382
  name: "elicit-fixture",
383
383
  command: process.execPath,
384
- args: [ELICIT_FIXTURE, `--gg-marker=${crypto.randomUUID()}`],
384
+ args: [ELICIT_FIXTURE, `--ez-marker=${crypto.randomUUID()}`],
385
385
  timeout: 10_000,
386
386
  };
387
387
  const pool = newPool();
@@ -11,20 +11,20 @@ vi.mock("../../config.js", async () => {
11
11
  ...actual,
12
12
  getAppPaths: () => ({
13
13
  ...actual.getAppPaths(),
14
- mcpFile: path.join(process.env.GG_TEST_HOME, ".ezcoder", "mcp.json"),
14
+ mcpFile: path.join(process.env.EZ_TEST_HOME, ".ezcoder", "mcp.json"),
15
15
  }),
16
16
  };
17
17
  });
18
18
  import { addServer, loadServers, removeServer, getServer, fromStoredEntry, globalMcpPath, projectMcpPath, } from "./store.js";
19
19
  beforeEach(async () => {
20
- tmpHome = await fs.mkdtemp(path.join(os.tmpdir(), "gg-mcp-home-"));
21
- tmpProject = await fs.mkdtemp(path.join(os.tmpdir(), "gg-mcp-proj-"));
22
- process.env.GG_TEST_HOME = tmpHome;
20
+ tmpHome = await fs.mkdtemp(path.join(os.tmpdir(), "ez-mcp-home-"));
21
+ tmpProject = await fs.mkdtemp(path.join(os.tmpdir(), "ez-mcp-proj-"));
22
+ process.env.EZ_TEST_HOME = tmpHome;
23
23
  });
24
24
  afterEach(async () => {
25
25
  await fs.rm(tmpHome, { recursive: true, force: true });
26
26
  await fs.rm(tmpProject, { recursive: true, force: true });
27
- delete process.env.GG_TEST_HOME;
27
+ delete process.env.EZ_TEST_HOME;
28
28
  });
29
29
  describe("mcp store", () => {
30
30
  it("round-trips an http server in global scope", async () => {
@@ -7,7 +7,7 @@ import { McpCatalogCache } from "./catalog-cache.js";
7
7
  let dir;
8
8
  let manager;
9
9
  beforeEach(async () => {
10
- dir = await fs.mkdtemp(path.join(os.tmpdir(), "gg-mcp-when-connected-"));
10
+ dir = await fs.mkdtemp(path.join(os.tmpdir(), "ez-mcp-when-connected-"));
11
11
  manager = new MCPClientManager({
12
12
  catalogCache: new McpCatalogCache(path.join(dir, "mcp-catalog.json")),
13
13
  });
@@ -19,7 +19,7 @@ afterEach(async () => {
19
19
  /** A stdio command that cannot possibly start, so the connect fails fast. */
20
20
  const BROKEN = {
21
21
  name: "broken",
22
- command: "gg-nonexistent-mcp-binary",
22
+ command: "ez-nonexistent-mcp-binary",
23
23
  args: [],
24
24
  timeout: 2_000,
25
25
  };
@@ -40,7 +40,7 @@ describe("effectiveNolanModel", () => {
40
40
  nolanModelOverride: true,
41
41
  });
42
42
  });
43
- it("pin identical to the build model still reports override=true (it survives GG switches)", () => {
43
+ it("pin identical to the build model still reports override=true (it survives EZ switches)", () => {
44
44
  expect(effectiveNolanModel({ provider: "anthropic", model: "claude-opus-5" }, build)).toEqual({
45
45
  nolanProvider: "anthropic",
46
46
  nolanModel: "claude-opus-5",
@@ -44,7 +44,7 @@ export async function buildNolanSystemPrompt(cwd) {
44
44
  return [
45
45
  renderIdentity(),
46
46
  renderEdge(),
47
- renderGGCoderCapabilities(),
47
+ renderEZCoderCapabilities(),
48
48
  renderSkeptical(),
49
49
  renderTaste(),
50
50
  renderMethod(),
@@ -73,7 +73,7 @@ export async function buildNolanSystemPrompt(cwd) {
73
73
  export async function buildNolanAutopilotSystemPrompt(cwd) {
74
74
  return [
75
75
  renderIdentity(),
76
- renderGGCoderCapabilities(),
76
+ renderEZCoderCapabilities(),
77
77
  renderSkeptical(),
78
78
  renderTaste(),
79
79
  renderMethod(),
@@ -123,7 +123,7 @@ function renderEdge() {
123
123
  `directly for the same result, you added nothing. Be the strategy, the ` +
124
124
  `skeptic, or the better-shaped ask.`);
125
125
  }
126
- function renderGGCoderCapabilities() {
126
+ function renderEZCoderCapabilities() {
127
127
  return (`## What EZ Coder can do\n\n` +
128
128
  `You direct EZ Coder, so you have to know its reach. It is a full coding agent ` +
129
129
  `with these tools, and your prompts should assume them instead of making the ` +
@@ -195,7 +195,7 @@ function renderTaste() {
195
195
  }
196
196
  function renderMethod() {
197
197
  return (`## Method\n\n` +
198
- `Modular and sequential. One thing at a time, each step small enough that GG ` +
198
+ `Modular and sequential. One thing at a time, each step small enough that EZ ` +
199
199
  `Coder can nail it and you can both confirm it works before the next.\n\n` +
200
200
  `Kill the "one prompt that does everything" mega-request on sight. For a whole ` +
201
201
  `feature, break it into a sequence and hand over the first step only, then the ` +
@@ -324,7 +324,7 @@ function renderContextNote() {
324
324
  return (`## Your context\n\n` +
325
325
  `Each turn you get a digest: what they're building, the story so far, and the ` +
326
326
  `recent EZ Coder and user activity. Read it, then answer the actual question. If ` +
327
- `the digest misses something, use your read-only tools to go look. You see GG ` +
327
+ `the digest misses something, use your read-only tools to go look. You see EZ ` +
328
328
  `Coder's conversation; it never sees yours. You steer, it builds.`);
329
329
  }
330
330
  //# sourceMappingURL=nolan-prompt.js.map
@@ -0,0 +1,2 @@
1
+ export { loginXai, refreshXaiToken, grokCliBaseUrl, grokCliHeaders, isGrokCliEndpoint, } from "@prestyj/core";
2
+ //# sourceMappingURL=xai.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"xai.d.ts","sourceRoot":"","sources":["../../../src/core/oauth/xai.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,QAAQ,EACR,eAAe,EACf,cAAc,EACd,cAAc,EACd,iBAAiB,GAClB,MAAM,eAAe,CAAC"}
@@ -0,0 +1,4 @@
1
+ // Lives in @prestyj/core — re-exported here so ezcoder call sites import
2
+ // Grok OAuth the same way they import the other providers.
3
+ export { loginXai, refreshXaiToken, grokCliBaseUrl, grokCliHeaders, isGrokCliEndpoint, } from "@prestyj/core";
4
+ //# sourceMappingURL=xai.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"xai.js","sourceRoot":"","sources":["../../../src/core/oauth/xai.ts"],"names":[],"mappings":"AAAA,yEAAyE;AACzE,2DAA2D;AAC3D,OAAO,EACL,QAAQ,EACR,eAAe,EACf,cAAc,EACd,cAAc,EACd,iBAAiB,GAClB,MAAM,eAAe,CAAC"}
@@ -76,7 +76,7 @@ export class PersistentShell {
76
76
  }
77
77
  this.busy = true;
78
78
  const child = this.ensureChild();
79
- const sentinel = `__GG_PSH_${randomUUID()}__`;
79
+ const sentinel = `__EZ_PSH_${randomUUID()}__`;
80
80
  // `</dev/null` keeps stdin-reading commands (cat, read) from eating the
81
81
  // next sentinel line instead of hanging the session.
82
82
  const wrapped = `{ ${command}\n} </dev/null; echo "${sentinel}$?"\n`;