@prestyj/cli 5.4.1 → 5.6.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 (325) hide show
  1. package/README.md +25 -12
  2. package/assets/end-notification.mp3 +0 -0
  3. package/assets/skills/evidence-led-ui/LICENSES.md +68 -0
  4. package/assets/skills/evidence-led-ui/SKILL.md +139 -0
  5. package/{LICENSE → assets/skills/evidence-led-ui/corpus/awesome-design-md/LICENSE} +1 -1
  6. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/airbnb/DESIGN.md +545 -0
  7. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/airtable/DESIGN.md +554 -0
  8. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/apple/DESIGN.md +562 -0
  9. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/binance/DESIGN.md +634 -0
  10. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/bmw/DESIGN.md +544 -0
  11. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/bmw-m/DESIGN.md +503 -0
  12. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/bugatti/DESIGN.md +454 -0
  13. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/cal/DESIGN.md +542 -0
  14. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/claude/DESIGN.md +589 -0
  15. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/clay/DESIGN.md +541 -0
  16. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/clickhouse/DESIGN.md +544 -0
  17. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/cohere/DESIGN.md +451 -0
  18. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/coinbase/DESIGN.md +570 -0
  19. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/composio/DESIGN.md +506 -0
  20. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/cursor/DESIGN.md +537 -0
  21. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/dell-1996/DESIGN.md +632 -0
  22. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/elevenlabs/DESIGN.md +504 -0
  23. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/expo/DESIGN.md +526 -0
  24. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/ferrari/DESIGN.md +531 -0
  25. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/figma/DESIGN.md +578 -0
  26. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/framer/DESIGN.md +544 -0
  27. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/hashicorp/DESIGN.md +575 -0
  28. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/hp/DESIGN.md +670 -0
  29. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/ibm/DESIGN.md +550 -0
  30. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/intercom/DESIGN.md +546 -0
  31. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/kraken/DESIGN.md +125 -0
  32. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/lamborghini/DESIGN.md +288 -0
  33. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/linear.app/DESIGN.md +548 -0
  34. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/lovable/DESIGN.md +298 -0
  35. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/mastercard/DESIGN.md +365 -0
  36. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/meta/DESIGN.md +683 -0
  37. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/minimax/DESIGN.md +746 -0
  38. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/mintlify/DESIGN.md +852 -0
  39. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/miro/DESIGN.md +825 -0
  40. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/mistral.ai/DESIGN.md +773 -0
  41. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/mongodb/DESIGN.md +767 -0
  42. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/nike/DESIGN.md +575 -0
  43. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/nintendo-2001/DESIGN.md +649 -0
  44. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/notion/DESIGN.md +821 -0
  45. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/nvidia/DESIGN.md +640 -0
  46. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/ollama/DESIGN.md +539 -0
  47. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/opencode.ai/DESIGN.md +521 -0
  48. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/pinterest/DESIGN.md +597 -0
  49. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/playstation/DESIGN.md +661 -0
  50. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/posthog/DESIGN.md +690 -0
  51. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/raycast/DESIGN.md +669 -0
  52. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/renault/DESIGN.md +589 -0
  53. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/replicate/DESIGN.md +616 -0
  54. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/resend/DESIGN.md +585 -0
  55. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/revolut/DESIGN.md +636 -0
  56. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/runwayml/DESIGN.md +244 -0
  57. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/sanity/DESIGN.md +357 -0
  58. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/sentry/DESIGN.md +551 -0
  59. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/shopify/DESIGN.md +516 -0
  60. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/slack/DESIGN.md +482 -0
  61. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/spacex/DESIGN.md +363 -0
  62. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/spotify/DESIGN.md +246 -0
  63. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/starbucks/DESIGN.md +580 -0
  64. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/stripe/DESIGN.md +487 -0
  65. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/supabase/DESIGN.md +462 -0
  66. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/superhuman/DESIGN.md +448 -0
  67. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/tesla/DESIGN.md +286 -0
  68. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/theverge/DESIGN.md +339 -0
  69. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/together.ai/DESIGN.md +633 -0
  70. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/uber/DESIGN.md +636 -0
  71. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/vercel/DESIGN.md +736 -0
  72. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/vodafone/DESIGN.md +538 -0
  73. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/voltagent/DESIGN.md +521 -0
  74. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/warp/DESIGN.md +526 -0
  75. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/webflow/DESIGN.md +588 -0
  76. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/wired/DESIGN.md +497 -0
  77. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/wise/DESIGN.md +544 -0
  78. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/x.ai/DESIGN.md +465 -0
  79. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/zapier/DESIGN.md +537 -0
  80. package/assets/skills/evidence-led-ui/data/corpus-manifest.json +768 -0
  81. package/assets/skills/evidence-led-ui/data/observations.json +47053 -0
  82. package/assets/skills/evidence-led-ui/references/anti-defaults.md +203 -0
  83. package/assets/skills/evidence-led-ui/references/archetypes.md +97 -0
  84. package/assets/skills/evidence-led-ui/references/craft-rulings.md +167 -0
  85. package/assets/skills/evidence-led-ui/references/methodology.md +72 -0
  86. package/assets/skills/evidence-led-ui/references/observed-patterns.md +68 -0
  87. package/assets/skills/evidence-led-ui/references/production-contract.md +120 -0
  88. package/assets/skills/evidence-led-ui/references/provenance.md +117 -0
  89. package/assets/skills/evidence-led-ui/references/quality-rubric.md +126 -0
  90. package/dist/app-sidecar.js +272 -74
  91. package/dist/app-sidecar.js.map +1 -1
  92. package/dist/chat-agents/general.d.ts +7 -0
  93. package/dist/chat-agents/general.d.ts.map +1 -0
  94. package/dist/chat-agents/general.js +16 -0
  95. package/dist/chat-agents/general.js.map +1 -0
  96. package/dist/chat-agents/general.test.d.ts +2 -0
  97. package/dist/chat-agents/general.test.d.ts.map +1 -0
  98. package/dist/chat-agents/general.test.js +50 -0
  99. package/dist/chat-agents/general.test.js.map +1 -0
  100. package/dist/chat-agents/index.d.ts +11 -0
  101. package/dist/chat-agents/index.d.ts.map +1 -0
  102. package/dist/chat-agents/index.js +89 -0
  103. package/dist/chat-agents/index.js.map +1 -0
  104. package/dist/chat-agents/jiwa.d.ts +53 -0
  105. package/dist/chat-agents/jiwa.d.ts.map +1 -0
  106. package/dist/chat-agents/jiwa.js +352 -0
  107. package/dist/chat-agents/jiwa.js.map +1 -0
  108. package/dist/chat-agents/jiwa.test.d.ts +2 -0
  109. package/dist/chat-agents/jiwa.test.d.ts.map +1 -0
  110. package/dist/chat-agents/jiwa.test.js +66 -0
  111. package/dist/chat-agents/jiwa.test.js.map +1 -0
  112. package/dist/chat-agents/memory.d.ts +53 -0
  113. package/dist/chat-agents/memory.d.ts.map +1 -0
  114. package/dist/chat-agents/memory.js +362 -0
  115. package/dist/chat-agents/memory.js.map +1 -0
  116. package/dist/chat-agents/memory.test.d.ts +2 -0
  117. package/dist/chat-agents/memory.test.d.ts.map +1 -0
  118. package/dist/chat-agents/memory.test.js +155 -0
  119. package/dist/chat-agents/memory.test.js.map +1 -0
  120. package/dist/chat-agents/research.d.ts +7 -0
  121. package/dist/chat-agents/research.d.ts.map +1 -0
  122. package/dist/chat-agents/research.js +18 -0
  123. package/dist/chat-agents/research.js.map +1 -0
  124. package/dist/chat-agents/shared.d.ts +11 -0
  125. package/dist/chat-agents/shared.d.ts.map +1 -0
  126. package/dist/chat-agents/shared.js +52 -0
  127. package/dist/chat-agents/shared.js.map +1 -0
  128. package/dist/chat-agents/specialists.test.d.ts +2 -0
  129. package/dist/chat-agents/specialists.test.d.ts.map +1 -0
  130. package/dist/chat-agents/specialists.test.js +97 -0
  131. package/dist/chat-agents/specialists.test.js.map +1 -0
  132. package/dist/chat-agents/therapist.d.ts +7 -0
  133. package/dist/chat-agents/therapist.d.ts.map +1 -0
  134. package/dist/chat-agents/therapist.js +20 -0
  135. package/dist/chat-agents/therapist.js.map +1 -0
  136. package/dist/chat-agents/types.d.ts +4 -0
  137. package/dist/chat-agents/types.d.ts.map +1 -0
  138. package/dist/chat-agents/types.js +7 -0
  139. package/dist/chat-agents/types.js.map +1 -0
  140. package/dist/cli/auth.js +1 -1
  141. package/dist/cli/auth.js.map +1 -1
  142. package/dist/cli.d.ts.map +1 -1
  143. package/dist/cli.js +72 -22
  144. package/dist/cli.js.map +1 -1
  145. package/dist/core/agent-session-memory-tail.test.d.ts +2 -0
  146. package/dist/core/agent-session-memory-tail.test.d.ts.map +1 -0
  147. package/dist/core/agent-session-memory-tail.test.js +122 -0
  148. package/dist/core/agent-session-memory-tail.test.js.map +1 -0
  149. package/dist/core/agent-session-subagent-policy.test.d.ts +2 -0
  150. package/dist/core/agent-session-subagent-policy.test.d.ts.map +1 -0
  151. package/dist/core/agent-session-subagent-policy.test.js +36 -0
  152. package/dist/core/agent-session-subagent-policy.test.js.map +1 -0
  153. package/dist/core/agent-session.d.ts +39 -11
  154. package/dist/core/agent-session.d.ts.map +1 -1
  155. package/dist/core/agent-session.js +178 -125
  156. package/dist/core/agent-session.js.map +1 -1
  157. package/dist/core/agents.d.ts +1 -1
  158. package/dist/core/agents.d.ts.map +1 -1
  159. package/dist/core/agents.js +4 -2
  160. package/dist/core/agents.js.map +1 -1
  161. package/dist/core/auth-providers.js +5 -5
  162. package/dist/core/auth-providers.js.map +1 -1
  163. package/dist/core/compaction/compactor.d.ts +7 -0
  164. package/dist/core/compaction/compactor.d.ts.map +1 -1
  165. package/dist/core/compaction/compactor.js +73 -9
  166. package/dist/core/compaction/compactor.js.map +1 -1
  167. package/dist/core/compaction/compactor.test.js +31 -4
  168. package/dist/core/compaction/compactor.test.js.map +1 -1
  169. package/dist/core/event-bus.d.ts +2 -0
  170. package/dist/core/event-bus.d.ts.map +1 -1
  171. package/dist/core/event-bus.js.map +1 -1
  172. package/dist/core/goal-worker.test.js +3 -2
  173. package/dist/core/goal-worker.test.js.map +1 -1
  174. package/dist/core/loop-breaker.d.ts +23 -16
  175. package/dist/core/loop-breaker.d.ts.map +1 -1
  176. package/dist/core/loop-breaker.js +52 -11
  177. package/dist/core/loop-breaker.js.map +1 -1
  178. package/dist/core/loop-breaker.test.js +37 -16
  179. package/dist/core/loop-breaker.test.js.map +1 -1
  180. package/dist/core/mcp/defaults.d.ts +1 -1
  181. package/dist/core/mcp/defaults.js +1 -1
  182. package/dist/core/mcp/store.d.ts +2 -2
  183. package/dist/core/mcp/store.test.js +1 -1
  184. package/dist/core/mcp/store.test.js.map +1 -1
  185. package/dist/core/nolan-prompt.d.ts +3 -3
  186. package/dist/core/nolan-prompt.d.ts.map +1 -1
  187. package/dist/core/nolan-prompt.js +10 -10
  188. package/dist/core/nolan-prompt.js.map +1 -1
  189. package/dist/core/nolan-prompt.test.js +17 -0
  190. package/dist/core/nolan-prompt.test.js.map +1 -1
  191. package/dist/core/progress/rebuild.d.ts +3 -3
  192. package/dist/core/progress/rebuild.d.ts.map +1 -1
  193. package/dist/core/progress/rebuild.js +33 -27
  194. package/dist/core/progress/rebuild.js.map +1 -1
  195. package/dist/core/progress/rebuild.test.js +15 -0
  196. package/dist/core/progress/rebuild.test.js.map +1 -1
  197. package/dist/core/project-discovery.d.ts +1 -1
  198. package/dist/core/project-discovery.d.ts.map +1 -1
  199. package/dist/core/project-discovery.js +5 -6
  200. package/dist/core/project-discovery.js.map +1 -1
  201. package/dist/core/project-discovery.test.js +14 -1
  202. package/dist/core/project-discovery.test.js.map +1 -1
  203. package/dist/core/radio.d.ts +3 -0
  204. package/dist/core/radio.d.ts.map +1 -1
  205. package/dist/core/radio.js +150 -21
  206. package/dist/core/radio.js.map +1 -1
  207. package/dist/core/radio.test.d.ts +2 -0
  208. package/dist/core/radio.test.d.ts.map +1 -0
  209. package/dist/core/radio.test.js +101 -0
  210. package/dist/core/radio.test.js.map +1 -0
  211. package/dist/core/session-history.test.js +1 -1
  212. package/dist/core/session-history.test.js.map +1 -1
  213. package/dist/core/session-manager.d.ts +1 -1
  214. package/dist/core/session-manager.d.ts.map +1 -1
  215. package/dist/core/session-manager.js +2 -1
  216. package/dist/core/session-manager.js.map +1 -1
  217. package/dist/core/session-manager.test.js +18 -0
  218. package/dist/core/session-manager.test.js.map +1 -1
  219. package/dist/core/settings-manager.d.ts +1 -0
  220. package/dist/core/settings-manager.d.ts.map +1 -1
  221. package/dist/core/settings-manager.js +1 -1
  222. package/dist/core/settings-manager.js.map +1 -1
  223. package/dist/core/skills-routing.test.d.ts +2 -0
  224. package/dist/core/skills-routing.test.d.ts.map +1 -0
  225. package/dist/core/skills-routing.test.js +70 -0
  226. package/dist/core/skills-routing.test.js.map +1 -0
  227. package/dist/core/skills.d.ts +2 -0
  228. package/dist/core/skills.d.ts.map +1 -1
  229. package/dist/core/skills.js +32 -9
  230. package/dist/core/skills.js.map +1 -1
  231. package/dist/core/subagent-manager.d.ts +73 -0
  232. package/dist/core/subagent-manager.d.ts.map +1 -0
  233. package/dist/core/subagent-manager.js +412 -0
  234. package/dist/core/subagent-manager.js.map +1 -0
  235. package/dist/core/subagent-manager.test.d.ts +2 -0
  236. package/dist/core/subagent-manager.test.d.ts.map +1 -0
  237. package/dist/core/subagent-manager.test.js +103 -0
  238. package/dist/core/subagent-manager.test.js.map +1 -0
  239. package/dist/core/subagent-policy.d.ts +4 -0
  240. package/dist/core/subagent-policy.d.ts.map +1 -0
  241. package/dist/core/subagent-policy.js +19 -0
  242. package/dist/core/subagent-policy.js.map +1 -0
  243. package/dist/modes/json-mode.d.ts.map +1 -1
  244. package/dist/modes/json-mode.js +3 -4
  245. package/dist/modes/json-mode.js.map +1 -1
  246. package/dist/modes/subagent-worker-mode.d.ts +14 -0
  247. package/dist/modes/subagent-worker-mode.d.ts.map +1 -0
  248. package/dist/modes/subagent-worker-mode.js +191 -0
  249. package/dist/modes/subagent-worker-mode.js.map +1 -0
  250. package/dist/system-prompt.js +2 -2
  251. package/dist/system-prompt.js.map +1 -1
  252. package/dist/system-prompt.test.js +7 -5
  253. package/dist/system-prompt.test.js.map +1 -1
  254. package/dist/tools/generate-image.d.ts.map +1 -1
  255. package/dist/tools/generate-image.js +12 -5
  256. package/dist/tools/generate-image.js.map +1 -1
  257. package/dist/tools/generate-image.test.js +17 -0
  258. package/dist/tools/generate-image.test.js.map +1 -1
  259. package/dist/tools/goals.d.ts +3 -3
  260. package/dist/tools/index.d.ts +10 -2
  261. package/dist/tools/index.d.ts.map +1 -1
  262. package/dist/tools/index.js +17 -1
  263. package/dist/tools/index.js.map +1 -1
  264. package/dist/tools/skill.d.ts.map +1 -1
  265. package/dist/tools/skill.js +8 -3
  266. package/dist/tools/skill.js.map +1 -1
  267. package/dist/tools/subagent-control.d.ts +6 -0
  268. package/dist/tools/subagent-control.d.ts.map +1 -0
  269. package/dist/tools/subagent-control.js +95 -0
  270. package/dist/tools/subagent-control.js.map +1 -0
  271. package/dist/tools/subagent-control.test.d.ts +2 -0
  272. package/dist/tools/subagent-control.test.d.ts.map +1 -0
  273. package/dist/tools/subagent-control.test.js +40 -0
  274. package/dist/tools/subagent-control.test.js.map +1 -0
  275. package/dist/tools/subagent-shared.d.ts +24 -0
  276. package/dist/tools/subagent-shared.d.ts.map +1 -0
  277. package/dist/tools/subagent-shared.js +53 -0
  278. package/dist/tools/subagent-shared.js.map +1 -0
  279. package/dist/tools/subagent-shared.test.d.ts +2 -0
  280. package/dist/tools/subagent-shared.test.d.ts.map +1 -0
  281. package/dist/tools/subagent-shared.test.js +29 -0
  282. package/dist/tools/subagent-shared.test.js.map +1 -0
  283. package/dist/tools/subagent.d.ts.map +1 -1
  284. package/dist/tools/subagent.js +21 -64
  285. package/dist/tools/subagent.js.map +1 -1
  286. package/dist/tools/subagent.test.js +27 -1
  287. package/dist/tools/subagent.test.js.map +1 -1
  288. package/dist/tools/web-fetch.d.ts +1 -0
  289. package/dist/tools/web-fetch.d.ts.map +1 -1
  290. package/dist/tools/web-fetch.js +112 -35
  291. package/dist/tools/web-fetch.js.map +1 -1
  292. package/dist/tools/web-fetch.test.js +146 -1
  293. package/dist/tools/web-fetch.test.js.map +1 -1
  294. package/dist/tools/web-search.d.ts +10 -0
  295. package/dist/tools/web-search.d.ts.map +1 -1
  296. package/dist/tools/web-search.js +236 -28
  297. package/dist/tools/web-search.js.map +1 -1
  298. package/dist/tools/web-search.test.js +77 -6
  299. package/dist/tools/web-search.test.js.map +1 -1
  300. package/dist/ui/App.d.ts +2 -0
  301. package/dist/ui/App.d.ts.map +1 -1
  302. package/dist/ui/App.js +61 -2
  303. package/dist/ui/App.js.map +1 -1
  304. package/dist/ui/components/SkillsOverlay.d.ts.map +1 -1
  305. package/dist/ui/components/SkillsOverlay.js +8 -3
  306. package/dist/ui/components/SkillsOverlay.js.map +1 -1
  307. package/dist/ui/hooks/useAgentLoop.d.ts.map +1 -1
  308. package/dist/ui/hooks/useAgentLoop.js +7 -18
  309. package/dist/ui/hooks/useAgentLoop.js.map +1 -1
  310. package/dist/ui/hooks/useAgentLoop.test.js +27 -0
  311. package/dist/ui/hooks/useAgentLoop.test.js.map +1 -1
  312. package/dist/ui/hooks/useModeState.d.ts +4 -2
  313. package/dist/ui/hooks/useModeState.d.ts.map +1 -1
  314. package/dist/ui/hooks/useModeState.js +14 -3
  315. package/dist/ui/hooks/useModeState.js.map +1 -1
  316. package/dist/ui/login.d.ts.map +1 -1
  317. package/dist/ui/login.js +13 -5
  318. package/dist/ui/login.js.map +1 -1
  319. package/dist/ui/render.d.ts +14 -0
  320. package/dist/ui/render.d.ts.map +1 -1
  321. package/dist/ui/render.js +2 -0
  322. package/dist/ui/render.js.map +1 -1
  323. package/dist/ui/render.test.js +17 -0
  324. package/dist/ui/render.test.js.map +1 -1
  325. package/package.json +7 -6
@@ -20,7 +20,11 @@ import { randomUUID } from "node:crypto";
20
20
  import { parseArgs } from "node:util";
21
21
  import { formatError } from "@prestyj/ai";
22
22
  import { runJsonMode } from "./modes/json-mode.js";
23
+ import { runSubagentWorkerMode } from "./modes/subagent-worker-mode.js";
23
24
  import { AgentSession } from "./core/agent-session.js";
25
+ import { CHAT_AGENT_IDS, chatAgentSessionsDir, createChatAgent, parseChatAgentId, sessionsDirForChatAgent, switchChatAgent, } from "./chat-agents/index.js";
26
+ import { buildJiwaTools, JiwaStore } from "./chat-agents/jiwa.js";
27
+ import { buildMemoryTools, MemoryStore } from "./chat-agents/memory.js";
24
28
  import { buildNolanSystemPrompt, buildNolanAutopilotSystemPrompt } from "./core/nolan-prompt.js";
25
29
  import { buildNolanDigest, buildNolanAutopilotContext, buildNolanAutopilotPlanContext, } from "./core/nolan-context.js";
26
30
  import { parseAutopilotVerdict } from "./core/autopilot-verdict.js";
@@ -46,7 +50,7 @@ import { loadCustomCommands } from "./core/custom-commands.js";
46
50
  import { discoverProjects, listRecentSessions } from "./core/project-discovery.js";
47
51
  import { loadTasksSync, saveTasksSync, pruneDoneTasksSync, getNextPendingTask, markTaskInProgress, } from "./core/task-store.js";
48
52
  import { initLogger, log } from "./core/logger.js";
49
- import { RADIO_STATIONS, getCurrentStation, playRadio, stopRadio } from "./core/radio.js";
53
+ import { RADIO_STATIONS, getCurrentStation, getRadioVolume, playRadio, setRadioVolume, stopRadio, } from "./core/radio.js";
50
54
  import { enrichProcessPath } from "./core/shell-path.js";
51
55
  import { downscaleForPreview, validateVisionImage } from "./utils/image.js";
52
56
  import { startServeMode } from "./modes/serve-mode.js";
@@ -457,6 +461,11 @@ function daemonJson(res, status, body) {
457
461
  res.end(JSON.stringify(body));
458
462
  }
459
463
  async function main() {
464
+ // Hidden persistent-worker dispatch must win before strict JSON/server parsing.
465
+ if (process.argv.includes("--subagent-worker")) {
466
+ await runSubagentWorkerMode();
467
+ return;
468
+ }
460
469
  // Sub-agent JSON-mode dispatch must win before any sidecar/server setup.
461
470
  if (await runJsonModeIfRequested())
462
471
  return;
@@ -502,6 +511,20 @@ async function main() {
502
511
  // request to its window's session via the `x-gg-session` header (and the
503
512
  // `?session=` query for the SSE /events stream).
504
513
  const sessions = new Map();
514
+ const memoryStore = new MemoryStore({
515
+ onChange: ({ memories }) => {
516
+ for (const ctx of sessions.values()) {
517
+ ctx.broadcast("memory_change", { count: memories.length });
518
+ }
519
+ },
520
+ });
521
+ const jiwaStore = new JiwaStore({
522
+ onChange: ({ jiwa }) => {
523
+ for (const ctx of sessions.values()) {
524
+ ctx.broadcast("jiwa_change", { count: jiwa.length });
525
+ }
526
+ },
527
+ });
505
528
  // XP/rank progress — loaded once per daemon; awards fan out to every window.
506
529
  // Each frame is tagged `origin: true` only for the session that earned the
507
530
  // XP, so that window alone plays sounds/chips while the rest just re-render.
@@ -600,7 +623,7 @@ async function main() {
600
623
  return;
601
624
  }
602
625
  // ── Daemon-level routes (session lifecycle) ──────────────────────────
603
- // Create a session for a window: { cwd, sessionPath? } → { sessionId }.
626
+ // Create a session for a window: { mode?, cwd, sessionPath? } → { sessionId }.
604
627
  if (method === "POST" && url === "/session") {
605
628
  void daemonReadBody(req).then(async (raw) => {
606
629
  let body = {};
@@ -610,15 +633,22 @@ async function main() {
610
633
  catch {
611
634
  /* empty/invalid body → defaults below */
612
635
  }
636
+ const mode = body.mode === "chat" ? "chat" : "code";
637
+ const chatAgent = parseChatAgentId(body.chatAgent);
613
638
  const sessionCwd = typeof body.cwd === "string" && body.cwd
614
639
  ? body.cwd
615
640
  : (process.env.GG_APP_CWD ?? process.cwd());
616
641
  const sessionPath = typeof body.sessionPath === "string" && body.sessionPath ? body.sessionPath : undefined;
617
642
  const id = randomUUID();
618
643
  try {
619
- const ctx = await createSession({ auth, paths, progress }, { id, cwd: sessionCwd, sessionPath });
644
+ const ctx = await createSession({ auth, paths, progress, memoryStore, jiwaStore }, { id, mode, chatAgent, cwd: sessionCwd, sessionPath });
620
645
  sessions.set(id, ctx);
621
- log("INFO", "app-sidecar", "session created", { id, cwd: sessionCwd });
646
+ log("INFO", "app-sidecar", "session created", {
647
+ id,
648
+ mode,
649
+ chatAgent,
650
+ cwd: sessionCwd,
651
+ });
622
652
  daemonJson(res, 200, { sessionId: id });
623
653
  }
624
654
  catch (err) {
@@ -681,16 +711,40 @@ async function main() {
681
711
  process.stdout.write(`GG_APP_LISTENING ${addr.port}\n`);
682
712
  log("INFO", "app-sidecar", "daemon listening", { port: String(addr.port), host });
683
713
  });
684
- const shutdown = async () => {
714
+ const shellPid = process.ppid;
715
+ let shuttingDown = false;
716
+ async function shutdown() {
717
+ if (shuttingDown)
718
+ return;
719
+ shuttingDown = true;
720
+ clearInterval(parentWatch);
685
721
  // Radio playback is app-wide (one stream across all windows), so it stops
686
722
  // at the daemon level, not per session.
687
723
  stopRadio();
688
724
  await Promise.all([...sessions.values()].map((c) => c.dispose().catch(() => { })));
689
725
  server.close();
690
726
  process.exit(0);
691
- };
727
+ }
692
728
  process.on("SIGINT", () => void shutdown());
693
729
  process.on("SIGTERM", () => void shutdown());
730
+ process.once("exit", stopRadio);
731
+ // Tauri can disappear without delivering a signal (force-quit, dev runner
732
+ // teardown, crash). Detect reparenting or a dead shell so the daemon and its
733
+ // radio player do not survive as audible orphans.
734
+ const parentWatch = setInterval(() => {
735
+ let parentAlive = process.ppid === shellPid;
736
+ if (parentAlive && shellPid > 1) {
737
+ try {
738
+ process.kill(shellPid, 0);
739
+ }
740
+ catch (error) {
741
+ parentAlive = error.code === "EPERM";
742
+ }
743
+ }
744
+ if (!parentAlive)
745
+ void shutdown();
746
+ }, 1_000);
747
+ parentWatch.unref?.();
694
748
  }
695
749
  /** Nolan's read-only tool allow-list. Excludes every mutating tool (write/edit/
696
750
  * bash/tasks/subagent/generate_image/enter_plan/exit_plan/task_*) so the mentor
@@ -745,8 +799,14 @@ function buildNolanContext(buildSession, cwd, gitBranch, question, workflowComma
745
799
  });
746
800
  }
747
801
  async function createProgressManager(agentDir, broadcastAll) {
748
- // Boot: recovery chain main → backup → one-time session-history rebuild → empty.
749
- let file = await loadProgress({ rebuild: () => rebuildFromSessions() });
802
+ // Boot: recovery chain main → backup → coding + chat session rebuild → empty.
803
+ const coderSessionsDir = path.join(agentDir, "sessions");
804
+ let file = await loadProgress({
805
+ rebuild: () => rebuildFromSessions([
806
+ coderSessionsDir,
807
+ ...CHAT_AGENT_IDS.map((agentId) => chatAgentSessionsDir(coderSessionsDir, agentId)),
808
+ ]),
809
+ });
750
810
  // Don't re-celebrate an old levelUp event on boot.
751
811
  let lastSeenNonce = file.lastEvent?.nonce ?? null;
752
812
  log("INFO", "app-sidecar", "progress loaded", {
@@ -794,7 +854,7 @@ async function createProgressManager(agentDir, broadcastAll) {
794
854
  });
795
855
  }
796
856
  }
797
- // Watch ~/.gg (dir watch survives the atomic tmp+rename) for progress.json
857
+ // Watch ~/.ezcoder (dir watch survives the atomic tmp+rename) for progress.json
798
858
  // writes from other daemon processes; debounce, reload read-only, dedupe by nonce.
799
859
  let watchDebounce = null;
800
860
  try {
@@ -834,8 +894,10 @@ async function createProgressManager(agentDir, broadcastAll) {
834
894
  * logger, PATH, shared auth file, and radio live at the daemon level.
835
895
  */
836
896
  async function createSession(deps, opts) {
837
- const { auth, progress } = deps;
897
+ const { auth, progress, memoryStore, jiwaStore } = deps;
838
898
  const paths = deps.paths;
899
+ const mode = opts.mode;
900
+ let chatAgent = opts.chatAgent;
839
901
  const cwd = opts.cwd;
840
902
  // Base host for parsing request-URL query params (value is irrelevant to
841
903
  // parsing); the daemon owns the real listen host.
@@ -938,66 +1000,77 @@ async function createSession(deps, opts) {
938
1000
  // empty/unset starts a fresh session.
939
1001
  const resumeSessionPath = opts.sessionPath;
940
1002
  let abort = new AbortController();
941
- const session = new AgentSession({
1003
+ const baseSessionOptions = {
942
1004
  provider,
943
1005
  model,
944
1006
  cwd,
945
1007
  thinkingLevel,
946
1008
  sessionId: resumeSessionPath,
947
1009
  signal: abort.signal,
948
- // The shell gates window readiness on the GG_APP_LISTENING handshake, which
949
- // can't fire until initialize() resolves. Connect MCP in the background so a
950
- // slow or hanging stdio server (e.g. a first-run `npx -y @playwright/mcp`
951
- // download) can't delay the sidecar past the webview's startup timeout
952
- // ("sidecar did not start in time"). Tools attach when the servers come up.
1010
+ // Keep MCP startup off the readiness path in both modes.
953
1011
  backgroundMcpConnect: true,
954
- // Plan mode: the agent's enter_plan/exit_plan tools drive these. We flip
955
- // session plan state (rebuilds the system prompt + enforces read-only
956
- // tools) and surface the transition to the webview.
957
- onEnterPlan: async (reason) => {
958
- // During a task run there is no human present to approve a plan, and a
959
- // submitted plan would strand the task in-progress while the run-all loop
960
- // advances to the next one. Decline plan mode so the agent implements the
961
- // task directly — mirrors the TUI's isUnattendedRun guard (App.tsx). The
962
- // enter_plan tool turns a false return into an "implement directly" hint.
963
- if (taskRunActive)
964
- return false;
965
- await session.setPlanMode(true);
966
- broadcast("plan_enter", { reason: reason ?? "" });
967
- // Persist the plan-mode banner so a resumed session still shows it.
968
- void session.persistAppMarker("plan", { reason: reason ?? "" }).catch(() => { });
969
- },
970
- onExitPlan: async (planPath) => {
971
- // A model can call exit_plan even when enter_plan was declined. During a
972
- // task run, never route the plan into review (no approver) — that would
973
- // hang the task and stall run-all. Leave plan mode and tell it to build.
974
- if (taskRunActive) {
1012
+ };
1013
+ let session;
1014
+ if (mode === "chat") {
1015
+ session = createChatAgent(chatAgent, {
1016
+ ...baseSessionOptions,
1017
+ sessionsDir: paths.sessionsDir,
1018
+ additionalTools: [...buildMemoryTools(memoryStore), ...buildJiwaTools(jiwaStore)],
1019
+ getSystemPromptTail: () => `${memoryStore.renderForPrompt()}\n\n${jiwaStore.renderForPrompt()}`,
1020
+ onAgentChange: async (nextAgent) => {
1021
+ chatAgent = nextAgent;
1022
+ broadcast("chat_agent_change", { chatAgent: nextAgent });
1023
+ await session.persistAppMarker("agent_handoff", { chatAgent: nextAgent }).catch((error) => {
1024
+ log("WARN", "app-sidecar", "agent handoff marker persist failed", {
1025
+ message: error instanceof Error ? error.message : String(error),
1026
+ });
1027
+ });
1028
+ },
1029
+ });
1030
+ }
1031
+ else {
1032
+ session = new AgentSession({
1033
+ ...baseSessionOptions,
1034
+ // Plan mode belongs only to the coding agent.
1035
+ onEnterPlan: async (reason) => {
1036
+ // Unattended task runs cannot approve plans; implement directly instead.
1037
+ if (taskRunActive)
1038
+ return false;
1039
+ await session.setPlanMode(true);
1040
+ broadcast("plan_enter", { reason: reason ?? "" });
1041
+ void session.persistAppMarker("plan", { reason: reason ?? "" }).catch(() => { });
1042
+ },
1043
+ onExitPlan: async (planPath) => {
1044
+ if (taskRunActive) {
1045
+ await session.setPlanMode(false);
1046
+ return ("Plan review is unavailable during a task run. Skip review and implement " +
1047
+ "the plan directly now: make the changes, verify them, then mark the task done.");
1048
+ }
975
1049
  await session.setPlanMode(false);
976
- return ("Plan review is unavailable during a task run. Skip review and implement " +
977
- "the plan directly now: make the changes, verify them, then mark the task done.");
978
- }
979
- await session.setPlanMode(false);
980
- // Surface the plan's path + markdown so the webview can show the review
981
- // modal (Accept / Feedback / Reject). Best-effort content read.
982
- let content;
983
- try {
984
- content = await fs.readFile(planPath, "utf-8");
985
- }
986
- catch {
987
- content = "";
988
- }
989
- // Record the submitted plan so the autopilot gate can route this turn
990
- // into a PLAN review instead of a stale work review (plan mode is
991
- // already false here, so the gate's planMode check alone never catches
992
- // a submission). setPendingPlan bumps planGeneration, which invalidates
993
- // any in-flight Nolan plan review racing a user action.
994
- setPendingPlan(planPath, content);
995
- broadcast("plan_exit", { planPath, content });
996
- return "Plan submitted for user review. Wait for the user to approve, reject, or dismiss it before implementing.";
997
- },
998
- });
1050
+ let content;
1051
+ try {
1052
+ content = await fs.readFile(planPath, "utf-8");
1053
+ }
1054
+ catch {
1055
+ content = "";
1056
+ }
1057
+ setPendingPlan(planPath, content);
1058
+ broadcast("plan_exit", { planPath, content });
1059
+ return "Plan submitted for user review. Wait for the user to approve, reject, or dismiss it before implementing.";
1060
+ },
1061
+ });
1062
+ }
999
1063
  await session.initialize();
1000
- log("INFO", "app-sidecar", "session ready", { provider, model, cwd });
1064
+ if (mode === "chat") {
1065
+ const restoredAgent = [...session.getAppMarkers()]
1066
+ .reverse()
1067
+ .find((marker) => marker.kind === "agent_handoff")?.data.chatAgent;
1068
+ if (typeof restoredAgent === "string") {
1069
+ chatAgent = parseChatAgentId(restoredAgent);
1070
+ await switchChatAgent(session, chatAgent, false);
1071
+ }
1072
+ }
1073
+ log("INFO", "app-sidecar", "session ready", { provider, model, mode, chatAgent, cwd });
1001
1074
  // Footer extras (context window, git branch, background tasks). The git
1002
1075
  // branch is resolved once at startup and refreshed lazily; the context
1003
1076
  // window follows the active model.
@@ -1060,6 +1133,7 @@ async function createSession(deps, opts) {
1060
1133
  });
1061
1134
  session.eventBus.on("model_change", (d) => broadcast("model_change", d));
1062
1135
  session.eventBus.on("hook", (d) => broadcast("hook", d));
1136
+ session.eventBus.on("subagent_state", (d) => broadcast("subagent_state", d));
1063
1137
  session.eventBus.on("compaction_start", (d) => broadcast("compaction_start", d));
1064
1138
  session.eventBus.on("compaction_end", (d) => broadcast("compaction_end", d));
1065
1139
  let running = false;
@@ -1071,7 +1145,7 @@ async function createSession(deps, opts) {
1071
1145
  // ezcoder-app.json on boot; flipped via POST /autopilot. When on, POST /prompt runs
1072
1146
  // runAutopilotCycle after the user's turn settles — Nolan auto-reviews the work
1073
1147
  // and drives the review→prompt→review loop.
1074
- let autopilot = await loadAutopilot(cwd);
1148
+ let autopilot = mode === "code" && (await loadAutopilot(cwd));
1075
1149
  // True while an autopilot review is in flight (used to defer nolanAuto model
1076
1150
  // switches, like nolanRunning does for chat Nolan, and to drive the spinner).
1077
1151
  let autopilotReviewing = false;
@@ -1139,7 +1213,7 @@ async function createSession(deps, opts) {
1139
1213
  let nolanRunning = false;
1140
1214
  let pendingNolanModel = null;
1141
1215
  const nolanToolCallNames = new Map();
1142
- // Nolan's per-project model override. null → Nolan (chat + autopilot) follows GG
1216
+ // Nolan's per-project model override. null → Nolan (chat + autopilot) follows EZ
1143
1217
  // Coder's model, including live switches (the historical behavior). Set → Nolan
1144
1218
  // is pinned to his own model and EZ Coder switches no longer touch him. A
1145
1219
  // stale persisted pin (model dropped from the registry / provider logged
@@ -1149,7 +1223,7 @@ async function createSession(deps, opts) {
1149
1223
  providerConnected: () => true, // async auth checked below
1150
1224
  });
1151
1225
  if (nolanModelOverride && !(await auth.hasProviderAuth(nolanModelOverride.provider))) {
1152
- log("WARN", "app-sidecar", "ken model override provider not connected — following GG", {
1226
+ log("WARN", "app-sidecar", "Nolan model override provider not connected — following EZ Coder", {
1153
1227
  provider: nolanModelOverride.provider,
1154
1228
  model: nolanModelOverride.model,
1155
1229
  });
@@ -1764,6 +1838,8 @@ async function createSession(deps, opts) {
1764
1838
  const st = session.getState();
1765
1839
  json(res, 200, {
1766
1840
  ...st,
1841
+ mode,
1842
+ chatAgent,
1767
1843
  running,
1768
1844
  ready: true,
1769
1845
  thinkingLevel: session.getThinkingLevel() ?? null,
@@ -1779,6 +1855,46 @@ async function createSession(deps, opts) {
1779
1855
  json(res, 200, progress.snapshot());
1780
1856
  return;
1781
1857
  }
1858
+ if (method === "GET" && url === "/memories") {
1859
+ void memoryStore
1860
+ .snapshot()
1861
+ .then((snapshot) => json(res, 200, snapshot))
1862
+ .catch((error) => json(res, 500, { error: error instanceof Error ? error.message : String(error) }));
1863
+ return;
1864
+ }
1865
+ if (method === "DELETE" && url.startsWith("/memories/")) {
1866
+ const id = decodeURIComponent(url.slice("/memories/".length));
1867
+ if (!id) {
1868
+ json(res, 400, { error: "memory id is required" });
1869
+ return;
1870
+ }
1871
+ void memoryStore
1872
+ .forget(id)
1873
+ .then(() => memoryStore.snapshot())
1874
+ .then((snapshot) => json(res, 200, snapshot))
1875
+ .catch((error) => json(res, 500, { error: error instanceof Error ? error.message : String(error) }));
1876
+ return;
1877
+ }
1878
+ if (method === "GET" && url === "/jiwa") {
1879
+ void jiwaStore
1880
+ .snapshot()
1881
+ .then((snapshot) => json(res, 200, snapshot))
1882
+ .catch((error) => json(res, 500, { error: error instanceof Error ? error.message : String(error) }));
1883
+ return;
1884
+ }
1885
+ if (method === "DELETE" && url.startsWith("/jiwa/")) {
1886
+ const id = decodeURIComponent(url.slice("/jiwa/".length));
1887
+ if (!id) {
1888
+ json(res, 400, { error: "Jiwa entry id is required" });
1889
+ return;
1890
+ }
1891
+ void jiwaStore
1892
+ .forget(id)
1893
+ .then(() => jiwaStore.snapshot())
1894
+ .then((snapshot) => json(res, 200, snapshot))
1895
+ .catch((error) => json(res, 500, { error: error instanceof Error ? error.message : String(error) }));
1896
+ return;
1897
+ }
1782
1898
  if (method === "GET" && (url === "/events" || url.startsWith("/events?"))) {
1783
1899
  res.writeHead(200, {
1784
1900
  "content-type": "text/event-stream",
@@ -1794,6 +1910,8 @@ async function createSession(deps, opts) {
1794
1910
  type: "ready",
1795
1911
  data: {
1796
1912
  ...st,
1913
+ mode,
1914
+ chatAgent,
1797
1915
  running,
1798
1916
  thinkingLevel: session.getThinkingLevel() ?? null,
1799
1917
  supportedThinkingLevels: getSupportedThinkingLevels(st.provider, st.model),
@@ -1909,7 +2027,36 @@ async function createSession(deps, opts) {
1909
2027
  json(res, 400, { error: "missing cwd query param" });
1910
2028
  return;
1911
2029
  }
1912
- void listRecentSessions(target, 5)
2030
+ const requestedAgent = new URL(url, `http://${host}`).searchParams.get("chatAgent");
2031
+ if (requestedAgent === "all") {
2032
+ void Promise.all(CHAT_AGENT_IDS.map(async (agentId) => {
2033
+ const agentSessions = await listRecentSessions(target, 5, chatAgentSessionsDir(paths.sessionsDir, agentId));
2034
+ return agentSessions.map((item) => ({ ...item, chatAgent: agentId }));
2035
+ }))
2036
+ .then(async (groups) => {
2037
+ const dated = await Promise.all(groups.flat().map(async (item) => ({
2038
+ item,
2039
+ mtime: await fs
2040
+ .stat(item.path)
2041
+ .then((stat) => stat.mtimeMs)
2042
+ .catch(() => 0),
2043
+ })));
2044
+ const recent = dated
2045
+ .sort((left, right) => right.mtime - left.mtime)
2046
+ .slice(0, 5)
2047
+ .map(({ item }) => item);
2048
+ json(res, 200, { sessions: recent });
2049
+ })
2050
+ .catch(() => json(res, 200, { sessions: [] }));
2051
+ return;
2052
+ }
2053
+ // The picker may be served by a sidecar currently running in Chat mode.
2054
+ // An omitted chatAgent always means coding history; chat callers identify
2055
+ // their namespace explicitly (one agent or "all").
2056
+ const sessionsDir = requestedAgent
2057
+ ? sessionsDirForChatAgent(paths.sessionsDir, requestedAgent)
2058
+ : paths.sessionsDir;
2059
+ void listRecentSessions(target, 5, sessionsDir)
1913
2060
  .then((sessions) => json(res, 200, { sessions }))
1914
2061
  .catch(() => json(res, 200, { sessions: [] }));
1915
2062
  return;
@@ -2174,12 +2321,17 @@ async function createSession(deps, opts) {
2174
2321
  }
2175
2322
  // Assistant tool_call blocks: detect sub-agent delegations.
2176
2323
  if (msg.role === "assistant" && typeof msg.content !== "string") {
2177
- const subagentCalls = msg.content.filter((c) => c.type === "tool_call" && c.name === "subagent");
2324
+ const subagentCalls = msg.content.filter((c) => c.type === "tool_call" && (c.name === "subagent" || c.name === "spawn_agent"));
2178
2325
  if (subagentCalls.length > 0) {
2179
2326
  const agents = subagentCalls.map((c) => {
2180
2327
  const result = toolResultMap.get(c.id);
2181
2328
  return {
2182
- agentName: typeof c.args?.agent === "string" ? c.args.agent : undefined,
2329
+ agentName: c.name === "spawn_agent" && typeof c.args?.task_name === "string"
2330
+ ? c.args.task_name
2331
+ : typeof c.args?.agent === "string"
2332
+ ? c.args.agent
2333
+ : undefined,
2334
+ // Async workers are intentionally non-resumable; restored rows are historical.
2183
2335
  status: result?.isError ? "error" : "done",
2184
2336
  toolUseCount: 0,
2185
2337
  };
@@ -2211,6 +2363,10 @@ async function createSession(deps, opts) {
2211
2363
  return;
2212
2364
  }
2213
2365
  if (method === "GET" && url === "/commands") {
2366
+ if (mode === "chat") {
2367
+ json(res, 200, { commands: [] });
2368
+ return;
2369
+ }
2214
2370
  // Workflow commands with agent functionality: built-in prompt templates +
2215
2371
  // the user's own `.ezcoder/commands/*.md`. UI commands (model/quit/etc.) are
2216
2372
  // handled webview-side and intentionally excluded.
@@ -2258,7 +2414,7 @@ async function createSession(deps, opts) {
2258
2414
  // an autopilot cycle is active but between injected runs (build idle,
2259
2415
  // Nolan reviewing) so the message never starts a run that collides with
2260
2416
  // an injected one on the same session. Attachments are persisted to
2261
- // .gg/uploads first so the queued media rides the same native-block
2417
+ // .ezcoder/uploads first so the queued media rides the same native-block
2262
2418
  // path as a non-queued attachment prompt when it drains.
2263
2419
  const prepared = attachments.length > 0 ? await prepareAttachments(cwd, attachments) : [];
2264
2420
  const count = session.queueMessage(text, prepared);
@@ -2351,6 +2507,10 @@ async function createSession(deps, opts) {
2351
2507
  // webview keeps the bubbles separate. The context digest is assembled fresh
2352
2508
  // from the BUILD session's transcript each turn (one-way mirror).
2353
2509
  if (method === "POST" && url === "/ken/prompt") {
2510
+ if (mode === "chat") {
2511
+ json(res, 404, { error: "Nolan is not available in EZ Chat." });
2512
+ return;
2513
+ }
2354
2514
  void readBody(req).then(async (raw) => {
2355
2515
  let text;
2356
2516
  try {
@@ -2406,6 +2566,10 @@ async function createSession(deps, opts) {
2406
2566
  return;
2407
2567
  }
2408
2568
  if (method === "POST" && url === "/autopilot") {
2569
+ if (mode === "chat") {
2570
+ json(res, 404, { error: "Autopilot is not available in EZ Chat." });
2571
+ return;
2572
+ }
2409
2573
  void readBody(req).then(async (raw) => {
2410
2574
  let enabled;
2411
2575
  try {
@@ -2464,7 +2628,34 @@ async function createSession(deps, opts) {
2464
2628
  // duplicate audio across windows (the original per-window goal), now for
2465
2629
  // free. (To restore per-window radio, key playback by sessionId.)
2466
2630
  if (method === "GET" && url === "/radio") {
2467
- json(res, 200, { stations: RADIO_STATIONS, current: getCurrentStation() });
2631
+ json(res, 200, {
2632
+ stations: RADIO_STATIONS,
2633
+ current: getCurrentStation(),
2634
+ volume: getRadioVolume(),
2635
+ });
2636
+ return;
2637
+ }
2638
+ if (method === "POST" && url === "/radio/volume") {
2639
+ void readBody(req).then((raw) => {
2640
+ let volume;
2641
+ try {
2642
+ volume = Number(JSON.parse(raw).volume);
2643
+ }
2644
+ catch {
2645
+ json(res, 400, { error: "invalid JSON body" });
2646
+ return;
2647
+ }
2648
+ if (!Number.isFinite(volume)) {
2649
+ json(res, 400, { error: "volume must be a number" });
2650
+ return;
2651
+ }
2652
+ const result = setRadioVolume(volume);
2653
+ if (!result.ok) {
2654
+ json(res, 400, { error: result.error ?? "Radio volume failed to update." });
2655
+ return;
2656
+ }
2657
+ json(res, 200, { current: getCurrentStation(), volume: getRadioVolume() });
2658
+ });
2468
2659
  return;
2469
2660
  }
2470
2661
  if (method === "POST" && url === "/radio") {
@@ -2657,7 +2848,7 @@ async function createSession(deps, opts) {
2657
2848
  await auth.reload();
2658
2849
  await session.switchModel(target.provider, target.id);
2659
2850
  // Nolan follows EZ Coder's model only while un-pinned; a user-set Nolan
2660
- // override survives GG model switches untouched.
2851
+ // override survives EZ Coder model switches untouched.
2661
2852
  if (!nolanModelOverride) {
2662
2853
  await syncNolanModel(target.provider, target.id);
2663
2854
  await syncNolanAutoModel(target.provider, target.id);
@@ -2690,8 +2881,8 @@ async function createSession(deps, opts) {
2690
2881
  broadcast("thinking_change", payload);
2691
2882
  // Un-pinned Nolan just followed the switch — update his footer chip too.
2692
2883
  // When Nolan is pinned, his effective model did not change, so skip the
2693
- // no-op event (keeps footer/event tests from treating a GG switch as a
2694
- // Nolan switch).
2884
+ // no-op event (keeps footer/event tests from treating an EZ Coder
2885
+ // switch as a Nolan switch).
2695
2886
  if (!nolanModelOverride)
2696
2887
  broadcast("ken_model_change", nolanStatePayload());
2697
2888
  // The new model usually has a different context window — push extras so
@@ -2723,7 +2914,7 @@ async function createSession(deps, opts) {
2723
2914
  const st = session.getState();
2724
2915
  await syncNolanModel(st.provider, st.model);
2725
2916
  await syncNolanAutoModel(st.provider, st.model);
2726
- log("INFO", "app-sidecar", "ken model pin cleared — following GG", {
2917
+ log("INFO", "app-sidecar", "Nolan model pin cleared — following EZ Coder", {
2727
2918
  provider: st.provider,
2728
2919
  model: st.model,
2729
2920
  });
@@ -2821,7 +3012,10 @@ async function createSession(deps, opts) {
2821
3012
  }
2822
3013
  void session
2823
3014
  .newSession()
2824
- .then(() => {
3015
+ .then(async () => {
3016
+ if (mode === "chat") {
3017
+ await session.persistAppMarker("agent_handoff", { chatAgent });
3018
+ }
2825
3019
  injectedAutopilotPrompts = [];
2826
3020
  clearPendingPlan();
2827
3021
  broadcast("session_reset", {});
@@ -3320,6 +3514,10 @@ async function createSession(deps, opts) {
3320
3514
  }
3321
3515
  return {
3322
3516
  id: opts.id,
3517
+ mode,
3518
+ get chatAgent() {
3519
+ return chatAgent;
3520
+ },
3323
3521
  cwd,
3324
3522
  sessionPath: opts.sessionPath,
3325
3523
  session,