@opengsd/gsd-pi 1.0.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 (2880) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +96 -0
  3. package/package.json +171 -0
  4. package/packages/contracts/dist/index.d.ts +3 -0
  5. package/packages/contracts/dist/index.d.ts.map +1 -0
  6. package/packages/contracts/dist/index.js +5 -0
  7. package/packages/contracts/dist/index.js.map +1 -0
  8. package/packages/contracts/dist/rpc.d.ts +549 -0
  9. package/packages/contracts/dist/rpc.d.ts.map +1 -0
  10. package/packages/contracts/dist/rpc.js +53 -0
  11. package/packages/contracts/dist/rpc.js.map +1 -0
  12. package/packages/contracts/dist/rpc.test.d.ts +2 -0
  13. package/packages/contracts/dist/rpc.test.d.ts.map +1 -0
  14. package/packages/contracts/dist/rpc.test.js +54 -0
  15. package/packages/contracts/dist/rpc.test.js.map +1 -0
  16. package/packages/contracts/dist/workflow.d.ts +201 -0
  17. package/packages/contracts/dist/workflow.d.ts.map +1 -0
  18. package/packages/contracts/dist/workflow.js +225 -0
  19. package/packages/contracts/dist/workflow.js.map +1 -0
  20. package/packages/contracts/package.json +39 -0
  21. package/packages/contracts/src/index.ts +5 -0
  22. package/packages/contracts/src/rpc.test.ts +80 -0
  23. package/packages/contracts/src/rpc.ts +286 -0
  24. package/packages/contracts/src/workflow.ts +237 -0
  25. package/packages/contracts/tsconfig.json +25 -0
  26. package/packages/daemon/package.json +49 -0
  27. package/packages/daemon/src/channel-manager.ts +223 -0
  28. package/packages/daemon/src/cli.ts +96 -0
  29. package/packages/daemon/src/commands.ts +110 -0
  30. package/packages/daemon/src/config.ts +137 -0
  31. package/packages/daemon/src/daemon.test.ts +763 -0
  32. package/packages/daemon/src/daemon.ts +199 -0
  33. package/packages/daemon/src/discord-bot.test.ts +792 -0
  34. package/packages/daemon/src/discord-bot.ts +491 -0
  35. package/packages/daemon/src/event-bridge.test.ts +620 -0
  36. package/packages/daemon/src/event-bridge.ts +494 -0
  37. package/packages/daemon/src/event-formatter.test.ts +401 -0
  38. package/packages/daemon/src/event-formatter.ts +413 -0
  39. package/packages/daemon/src/index.ts +55 -0
  40. package/packages/daemon/src/launchd.test.ts +356 -0
  41. package/packages/daemon/src/launchd.ts +242 -0
  42. package/packages/daemon/src/logger.ts +89 -0
  43. package/packages/daemon/src/message-batcher.test.ts +308 -0
  44. package/packages/daemon/src/message-batcher.ts +216 -0
  45. package/packages/daemon/src/orchestrator.test.ts +584 -0
  46. package/packages/daemon/src/orchestrator.ts +469 -0
  47. package/packages/daemon/src/project-scanner.test.ts +235 -0
  48. package/packages/daemon/src/project-scanner.ts +99 -0
  49. package/packages/daemon/src/session-manager.test.ts +822 -0
  50. package/packages/daemon/src/session-manager.ts +400 -0
  51. package/packages/daemon/src/types.ts +184 -0
  52. package/packages/daemon/src/verbosity.test.ts +171 -0
  53. package/packages/daemon/src/verbosity.ts +101 -0
  54. package/packages/daemon/tsconfig.json +24 -0
  55. package/packages/mcp-server/README.md +275 -0
  56. package/packages/mcp-server/package.json +53 -0
  57. package/packages/mcp-server/src/alias-telemetry.test.ts +78 -0
  58. package/packages/mcp-server/src/alias-telemetry.ts +30 -0
  59. package/packages/mcp-server/src/cli.ts +70 -0
  60. package/packages/mcp-server/src/env-writer.test.ts +433 -0
  61. package/packages/mcp-server/src/env-writer.ts +292 -0
  62. package/packages/mcp-server/src/import-candidates.test.ts +53 -0
  63. package/packages/mcp-server/src/index.ts +43 -0
  64. package/packages/mcp-server/src/mcp-server.test.ts +1395 -0
  65. package/packages/mcp-server/src/parse-workflow-args.test.ts +80 -0
  66. package/packages/mcp-server/src/readers/captures.ts +119 -0
  67. package/packages/mcp-server/src/readers/doctor-lite.ts +225 -0
  68. package/packages/mcp-server/src/readers/graph.test.ts +679 -0
  69. package/packages/mcp-server/src/readers/graph.ts +863 -0
  70. package/packages/mcp-server/src/readers/index.ts +28 -0
  71. package/packages/mcp-server/src/readers/knowledge.ts +111 -0
  72. package/packages/mcp-server/src/readers/metrics.ts +118 -0
  73. package/packages/mcp-server/src/readers/paths.test.ts +67 -0
  74. package/packages/mcp-server/src/readers/paths.ts +334 -0
  75. package/packages/mcp-server/src/readers/readers.test.ts +513 -0
  76. package/packages/mcp-server/src/readers/roadmap.ts +263 -0
  77. package/packages/mcp-server/src/readers/state.ts +223 -0
  78. package/packages/mcp-server/src/remote-questions.test.ts +397 -0
  79. package/packages/mcp-server/src/remote-questions.ts +967 -0
  80. package/packages/mcp-server/src/secure-env-collect.test.ts +260 -0
  81. package/packages/mcp-server/src/server.ts +1342 -0
  82. package/packages/mcp-server/src/session-manager.ts +404 -0
  83. package/packages/mcp-server/src/tool-credentials.test.ts +95 -0
  84. package/packages/mcp-server/src/tool-credentials.ts +97 -0
  85. package/packages/mcp-server/src/types.ts +96 -0
  86. package/packages/mcp-server/src/workflow-tools-parity.test.ts +257 -0
  87. package/packages/mcp-server/src/workflow-tools.test.ts +2350 -0
  88. package/packages/mcp-server/src/workflow-tools.ts +2257 -0
  89. package/packages/mcp-server/tsconfig.json +25 -0
  90. package/packages/mcp-server/tsconfig.test.json +19 -0
  91. package/packages/native/dist/ast/index.d.ts +4 -0
  92. package/packages/native/dist/ast/index.js +11 -0
  93. package/packages/native/dist/ast/types.d.ts +69 -0
  94. package/packages/native/dist/ast/types.js +2 -0
  95. package/packages/native/dist/clipboard/index.d.ts +28 -0
  96. package/packages/native/dist/clipboard/index.js +38 -0
  97. package/packages/native/dist/clipboard/types.d.ts +7 -0
  98. package/packages/native/dist/clipboard/types.js +2 -0
  99. package/packages/native/dist/diff/index.d.ts +33 -0
  100. package/packages/native/dist/diff/index.js +43 -0
  101. package/packages/native/dist/diff/types.d.ts +23 -0
  102. package/packages/native/dist/diff/types.js +2 -0
  103. package/packages/native/dist/fd/index.d.ts +26 -0
  104. package/packages/native/dist/fd/index.js +30 -0
  105. package/packages/native/dist/fd/types.d.ts +29 -0
  106. package/packages/native/dist/fd/types.js +2 -0
  107. package/packages/native/dist/glob/index.d.ts +28 -0
  108. package/packages/native/dist/glob/index.js +35 -0
  109. package/packages/native/dist/glob/types.d.ts +50 -0
  110. package/packages/native/dist/glob/types.js +2 -0
  111. package/packages/native/dist/grep/index.d.ts +21 -0
  112. package/packages/native/dist/grep/index.js +28 -0
  113. package/packages/native/dist/grep/types.d.ts +99 -0
  114. package/packages/native/dist/grep/types.js +2 -0
  115. package/packages/native/dist/gsd-parser/index.d.ts +45 -0
  116. package/packages/native/dist/gsd-parser/index.js +61 -0
  117. package/packages/native/dist/gsd-parser/types.d.ts +55 -0
  118. package/packages/native/dist/gsd-parser/types.js +8 -0
  119. package/packages/native/dist/highlight/index.d.ts +28 -0
  120. package/packages/native/dist/highlight/index.js +38 -0
  121. package/packages/native/dist/highlight/types.d.ts +25 -0
  122. package/packages/native/dist/highlight/types.js +2 -0
  123. package/packages/native/dist/html/index.d.ts +15 -0
  124. package/packages/native/dist/html/index.js +19 -0
  125. package/packages/native/dist/html/types.d.ts +7 -0
  126. package/packages/native/dist/html/types.js +2 -0
  127. package/packages/native/dist/image/index.d.ts +15 -0
  128. package/packages/native/dist/image/index.js +23 -0
  129. package/packages/native/dist/image/types.d.ts +35 -0
  130. package/packages/native/dist/image/types.js +29 -0
  131. package/packages/native/dist/index.d.ts +46 -0
  132. package/packages/native/dist/index.js +85 -0
  133. package/packages/native/dist/json-parse/index.d.ts +23 -0
  134. package/packages/native/dist/json-parse/index.js +78 -0
  135. package/packages/native/dist/native.d.ts +57 -0
  136. package/packages/native/dist/native.js +113 -0
  137. package/packages/native/dist/ps/index.d.ts +38 -0
  138. package/packages/native/dist/ps/index.js +53 -0
  139. package/packages/native/dist/stream-process/index.d.ts +35 -0
  140. package/packages/native/dist/stream-process/index.js +254 -0
  141. package/packages/native/dist/text/index.d.ts +55 -0
  142. package/packages/native/dist/text/index.js +76 -0
  143. package/packages/native/dist/text/types.d.ts +27 -0
  144. package/packages/native/dist/text/types.js +13 -0
  145. package/packages/native/dist/truncate/index.d.ts +29 -0
  146. package/packages/native/dist/truncate/index.js +30 -0
  147. package/packages/native/dist/ttsr/index.d.ts +27 -0
  148. package/packages/native/dist/ttsr/index.js +37 -0
  149. package/packages/native/dist/ttsr/types.d.ts +9 -0
  150. package/packages/native/dist/ttsr/types.js +2 -0
  151. package/packages/native/dist/xxhash/index.d.ts +22 -0
  152. package/packages/native/dist/xxhash/index.js +89 -0
  153. package/packages/native/package.json +97 -0
  154. package/packages/native/src/__tests__/_test-coverage-guard.test.mjs +98 -0
  155. package/packages/native/src/__tests__/clipboard.test.mjs +126 -0
  156. package/packages/native/src/__tests__/diff.test.mjs +189 -0
  157. package/packages/native/src/__tests__/fd.test.mjs +199 -0
  158. package/packages/native/src/__tests__/glob.test.mjs +237 -0
  159. package/packages/native/src/__tests__/grep.test.mjs +179 -0
  160. package/packages/native/src/__tests__/highlight.test.mjs +156 -0
  161. package/packages/native/src/__tests__/html.test.mjs +98 -0
  162. package/packages/native/src/__tests__/image.test.mjs +137 -0
  163. package/packages/native/src/__tests__/json-parse.test.mjs +158 -0
  164. package/packages/native/src/__tests__/module-compat.test.mjs +123 -0
  165. package/packages/native/src/__tests__/ps.test.mjs +115 -0
  166. package/packages/native/src/__tests__/stream-process.test.mjs +108 -0
  167. package/packages/native/src/__tests__/text.test.mjs +295 -0
  168. package/packages/native/src/__tests__/truncate.test.mjs +160 -0
  169. package/packages/native/src/__tests__/ttsr.test.mjs +135 -0
  170. package/packages/native/src/__tests__/xxhash.test.mjs +122 -0
  171. package/packages/native/src/ast/index.ts +12 -0
  172. package/packages/native/src/ast/types.ts +75 -0
  173. package/packages/native/src/clipboard/index.ts +40 -0
  174. package/packages/native/src/clipboard/types.ts +7 -0
  175. package/packages/native/src/diff/index.ts +61 -0
  176. package/packages/native/src/diff/types.ts +24 -0
  177. package/packages/native/src/fd/index.ts +36 -0
  178. package/packages/native/src/fd/types.ts +31 -0
  179. package/packages/native/src/glob/index.ts +44 -0
  180. package/packages/native/src/glob/types.ts +53 -0
  181. package/packages/native/src/grep/index.ts +49 -0
  182. package/packages/native/src/grep/types.ts +105 -0
  183. package/packages/native/src/gsd-parser/index.ts +98 -0
  184. package/packages/native/src/gsd-parser/types.ts +62 -0
  185. package/packages/native/src/highlight/index.ts +44 -0
  186. package/packages/native/src/highlight/types.ts +25 -0
  187. package/packages/native/src/html/index.ts +24 -0
  188. package/packages/native/src/html/types.ts +7 -0
  189. package/packages/native/src/image/index.ts +28 -0
  190. package/packages/native/src/image/types.ts +41 -0
  191. package/packages/native/src/index.ts +128 -0
  192. package/packages/native/src/json-parse/index.ts +76 -0
  193. package/packages/native/src/native.ts +154 -0
  194. package/packages/native/src/ps/index.ts +52 -0
  195. package/packages/native/src/stream-process/index.ts +313 -0
  196. package/packages/native/src/text/index.ts +125 -0
  197. package/packages/native/src/text/types.ts +29 -0
  198. package/packages/native/src/truncate/index.ts +50 -0
  199. package/packages/native/src/ttsr/index.ts +39 -0
  200. package/packages/native/src/ttsr/types.ts +10 -0
  201. package/packages/native/src/xxhash/index.ts +98 -0
  202. package/packages/native/tsconfig.json +9 -0
  203. package/packages/native/tsconfig.tsbuildinfo +1 -0
  204. package/packages/pi-agent-core/package.json +23 -0
  205. package/packages/pi-agent-core/src/agent-loop.test.ts +733 -0
  206. package/packages/pi-agent-core/src/agent-loop.ts +851 -0
  207. package/packages/pi-agent-core/src/agent.test.ts +129 -0
  208. package/packages/pi-agent-core/src/agent.ts +668 -0
  209. package/packages/pi-agent-core/src/index.ts +10 -0
  210. package/packages/pi-agent-core/src/proxy.ts +334 -0
  211. package/packages/pi-agent-core/src/token-audit.test.ts +189 -0
  212. package/packages/pi-agent-core/src/token-audit.ts +287 -0
  213. package/packages/pi-agent-core/src/types.ts +358 -0
  214. package/packages/pi-agent-core/tsconfig.json +28 -0
  215. package/packages/pi-ai/bedrock-provider.d.ts +1 -0
  216. package/packages/pi-ai/bedrock-provider.js +1 -0
  217. package/packages/pi-ai/package.json +48 -0
  218. package/packages/pi-ai/scripts/generate-models.ts +1671 -0
  219. package/packages/pi-ai/src/api-registry.ts +86 -0
  220. package/packages/pi-ai/src/bedrock-provider.ts +6 -0
  221. package/packages/pi-ai/src/cli.ts +133 -0
  222. package/packages/pi-ai/src/env-api-keys.ts +148 -0
  223. package/packages/pi-ai/src/index.ts +36 -0
  224. package/packages/pi-ai/src/models/capability-patches.ts +51 -0
  225. package/packages/pi-ai/src/models/custom.ts +337 -0
  226. package/packages/pi-ai/src/models/fake-model.ts +30 -0
  227. package/packages/pi-ai/src/models/generated/amazon-bedrock.ts +1554 -0
  228. package/packages/pi-ai/src/models/generated/anthropic.ts +398 -0
  229. package/packages/pi-ai/src/models/generated/azure-openai-responses.ts +704 -0
  230. package/packages/pi-ai/src/models/generated/cerebras.ts +75 -0
  231. package/packages/pi-ai/src/models/generated/github-copilot.ts +446 -0
  232. package/packages/pi-ai/src/models/generated/google-antigravity.ts +177 -0
  233. package/packages/pi-ai/src/models/generated/google-gemini-cli.ts +109 -0
  234. package/packages/pi-ai/src/models/generated/google-vertex.ts +211 -0
  235. package/packages/pi-ai/src/models/generated/google.ts +466 -0
  236. package/packages/pi-ai/src/models/generated/groq.ts +160 -0
  237. package/packages/pi-ai/src/models/generated/huggingface.ts +349 -0
  238. package/packages/pi-ai/src/models/generated/index.ts +52 -0
  239. package/packages/pi-ai/src/models/generated/kimi-coding.ts +41 -0
  240. package/packages/pi-ai/src/models/generated/minimax-cn.ts +109 -0
  241. package/packages/pi-ai/src/models/generated/minimax.ts +109 -0
  242. package/packages/pi-ai/src/models/generated/mistral.ts +449 -0
  243. package/packages/pi-ai/src/models/generated/openai-codex.ts +177 -0
  244. package/packages/pi-ai/src/models/generated/openai.ts +721 -0
  245. package/packages/pi-ai/src/models/generated/opencode-go.ts +126 -0
  246. package/packages/pi-ai/src/models/generated/opencode.ts +534 -0
  247. package/packages/pi-ai/src/models/generated/openrouter.ts +4291 -0
  248. package/packages/pi-ai/src/models/generated/vercel-ai-gateway.ts +2608 -0
  249. package/packages/pi-ai/src/models/generated/xai.ts +415 -0
  250. package/packages/pi-ai/src/models/generated/zai.ts +241 -0
  251. package/packages/pi-ai/src/models/index.ts +115 -0
  252. package/packages/pi-ai/src/models.generated.test.ts +362 -0
  253. package/packages/pi-ai/src/models.test.ts +404 -0
  254. package/packages/pi-ai/src/models.ts +3 -0
  255. package/packages/pi-ai/src/oauth.ts +1 -0
  256. package/packages/pi-ai/src/providers/amazon-bedrock.test.ts +164 -0
  257. package/packages/pi-ai/src/providers/amazon-bedrock.ts +797 -0
  258. package/packages/pi-ai/src/providers/anthropic-auth.test.ts +92 -0
  259. package/packages/pi-ai/src/providers/anthropic-bearer-auth.test.ts +36 -0
  260. package/packages/pi-ai/src/providers/anthropic-shared.cache-breakpoint.test.ts +289 -0
  261. package/packages/pi-ai/src/providers/anthropic-shared.test.ts +134 -0
  262. package/packages/pi-ai/src/providers/anthropic-shared.ts +899 -0
  263. package/packages/pi-ai/src/providers/anthropic-vertex.ts +130 -0
  264. package/packages/pi-ai/src/providers/anthropic.ts +240 -0
  265. package/packages/pi-ai/src/providers/api-family.test.ts +129 -0
  266. package/packages/pi-ai/src/providers/api-family.ts +57 -0
  267. package/packages/pi-ai/src/providers/azure-openai-responses.ts +248 -0
  268. package/packages/pi-ai/src/providers/fake.ts +376 -0
  269. package/packages/pi-ai/src/providers/github-copilot-headers.ts +37 -0
  270. package/packages/pi-ai/src/providers/google-gemini-cli.test.ts +90 -0
  271. package/packages/pi-ai/src/providers/google-gemini-cli.ts +982 -0
  272. package/packages/pi-ai/src/providers/google-shared.test.ts +137 -0
  273. package/packages/pi-ai/src/providers/google-shared.ts +364 -0
  274. package/packages/pi-ai/src/providers/google-vertex.ts +500 -0
  275. package/packages/pi-ai/src/providers/google.ts +467 -0
  276. package/packages/pi-ai/src/providers/minimax-tool-name.test.ts +118 -0
  277. package/packages/pi-ai/src/providers/mistral.ts +597 -0
  278. package/packages/pi-ai/src/providers/openai-codex-responses.test.ts +63 -0
  279. package/packages/pi-ai/src/providers/openai-codex-responses.ts +1007 -0
  280. package/packages/pi-ai/src/providers/openai-completions.test.ts +75 -0
  281. package/packages/pi-ai/src/providers/openai-completions.ts +830 -0
  282. package/packages/pi-ai/src/providers/openai-responses-shared.ts +496 -0
  283. package/packages/pi-ai/src/providers/openai-responses.ts +205 -0
  284. package/packages/pi-ai/src/providers/openai-shared.ts +193 -0
  285. package/packages/pi-ai/src/providers/provider-capabilities.test.ts +174 -0
  286. package/packages/pi-ai/src/providers/provider-capabilities.ts +215 -0
  287. package/packages/pi-ai/src/providers/register-builtins.ts +216 -0
  288. package/packages/pi-ai/src/providers/simple-options.test.ts +60 -0
  289. package/packages/pi-ai/src/providers/simple-options.ts +61 -0
  290. package/packages/pi-ai/src/providers/think-tag-parser.test.ts +44 -0
  291. package/packages/pi-ai/src/providers/think-tag-parser.ts +94 -0
  292. package/packages/pi-ai/src/providers/transform-messages-report.test.ts +189 -0
  293. package/packages/pi-ai/src/providers/transform-messages.ts +289 -0
  294. package/packages/pi-ai/src/stream.ts +59 -0
  295. package/packages/pi-ai/src/types.ts +413 -0
  296. package/packages/pi-ai/src/utils/event-stream.ts +87 -0
  297. package/packages/pi-ai/src/utils/hash.ts +13 -0
  298. package/packages/pi-ai/src/utils/json-parse.ts +51 -0
  299. package/packages/pi-ai/src/utils/oauth/github-copilot.test.ts +282 -0
  300. package/packages/pi-ai/src/utils/oauth/github-copilot.ts +470 -0
  301. package/packages/pi-ai/src/utils/oauth/google-antigravity.test.ts +80 -0
  302. package/packages/pi-ai/src/utils/oauth/google-antigravity.ts +323 -0
  303. package/packages/pi-ai/src/utils/oauth/google-gemini-cli.test.ts +80 -0
  304. package/packages/pi-ai/src/utils/oauth/google-gemini-cli.ts +468 -0
  305. package/packages/pi-ai/src/utils/oauth/google-oauth-utils.ts +201 -0
  306. package/packages/pi-ai/src/utils/oauth/index.ts +134 -0
  307. package/packages/pi-ai/src/utils/oauth/openai-codex.ts +472 -0
  308. package/packages/pi-ai/src/utils/oauth/pkce.ts +34 -0
  309. package/packages/pi-ai/src/utils/oauth/types.ts +49 -0
  310. package/packages/pi-ai/src/utils/overflow.ts +129 -0
  311. package/packages/pi-ai/src/utils/repair-tool-json.ts +241 -0
  312. package/packages/pi-ai/src/utils/sanitize-unicode.ts +25 -0
  313. package/packages/pi-ai/src/utils/tests/json-parse.test.ts +17 -0
  314. package/packages/pi-ai/src/utils/tests/overflow.test.ts +58 -0
  315. package/packages/pi-ai/src/utils/tests/repair-tool-json.test.ts +240 -0
  316. package/packages/pi-ai/src/utils/typebox-helpers.ts +24 -0
  317. package/packages/pi-ai/src/utils/validation.ts +69 -0
  318. package/packages/pi-ai/src/web-runtime-env-api-keys.ts +86 -0
  319. package/packages/pi-ai/src/web-runtime-oauth.ts +9 -0
  320. package/packages/pi-ai/tsconfig.json +28 -0
  321. package/packages/pi-coding-agent/package.json +52 -0
  322. package/packages/pi-coding-agent/scripts/copy-assets.cjs +55 -0
  323. package/packages/pi-coding-agent/src/cli/abort-signal-timeout.test.ts +73 -0
  324. package/packages/pi-coding-agent/src/cli/abort-signal-timeout.ts +18 -0
  325. package/packages/pi-coding-agent/src/cli/args.test.ts +44 -0
  326. package/packages/pi-coding-agent/src/cli/args.ts +357 -0
  327. package/packages/pi-coding-agent/src/cli/config-selector.ts +52 -0
  328. package/packages/pi-coding-agent/src/cli/file-processor.ts +96 -0
  329. package/packages/pi-coding-agent/src/cli/list-models.ts +164 -0
  330. package/packages/pi-coding-agent/src/cli/session-picker.ts +51 -0
  331. package/packages/pi-coding-agent/src/cli.ts +20 -0
  332. package/packages/pi-coding-agent/src/config.ts +245 -0
  333. package/packages/pi-coding-agent/src/core/agent-session-abort-order.test.ts +491 -0
  334. package/packages/pi-coding-agent/src/core/agent-session-model-switch.test.ts +93 -0
  335. package/packages/pi-coding-agent/src/core/agent-session-renderable-tools.test.ts +70 -0
  336. package/packages/pi-coding-agent/src/core/agent-session-thinking-level.test.ts +79 -0
  337. package/packages/pi-coding-agent/src/core/agent-session-tool-refresh.test.ts +172 -0
  338. package/packages/pi-coding-agent/src/core/agent-session.ts +3150 -0
  339. package/packages/pi-coding-agent/src/core/artifact-manager.ts +125 -0
  340. package/packages/pi-coding-agent/src/core/auth-storage.test.ts +654 -0
  341. package/packages/pi-coding-agent/src/core/auth-storage.ts +925 -0
  342. package/packages/pi-coding-agent/src/core/bash-executor.ts +316 -0
  343. package/packages/pi-coding-agent/src/core/blob-store.ts +154 -0
  344. package/packages/pi-coding-agent/src/core/chat-controller-ordering.test.ts +1571 -0
  345. package/packages/pi-coding-agent/src/core/compaction/branch-summarization.ts +307 -0
  346. package/packages/pi-coding-agent/src/core/compaction/compaction.test.ts +598 -0
  347. package/packages/pi-coding-agent/src/core/compaction/compaction.ts +986 -0
  348. package/packages/pi-coding-agent/src/core/compaction/index.ts +7 -0
  349. package/packages/pi-coding-agent/src/core/compaction/utils.ts +368 -0
  350. package/packages/pi-coding-agent/src/core/compaction-orchestrator.test.ts +154 -0
  351. package/packages/pi-coding-agent/src/core/compaction-orchestrator.ts +440 -0
  352. package/packages/pi-coding-agent/src/core/compaction-threshold.test.ts +121 -0
  353. package/packages/pi-coding-agent/src/core/compaction-utils.test.ts +117 -0
  354. package/packages/pi-coding-agent/src/core/constants.ts +59 -0
  355. package/packages/pi-coding-agent/src/core/contextual-tips.test.ts +259 -0
  356. package/packages/pi-coding-agent/src/core/contextual-tips.ts +232 -0
  357. package/packages/pi-coding-agent/src/core/db-snapshot.test.ts +32 -0
  358. package/packages/pi-coding-agent/src/core/db-snapshot.ts +66 -0
  359. package/packages/pi-coding-agent/src/core/defaults.ts +3 -0
  360. package/packages/pi-coding-agent/src/core/diagnostics.ts +15 -0
  361. package/packages/pi-coding-agent/src/core/discovery-cache.test.ts +163 -0
  362. package/packages/pi-coding-agent/src/core/discovery-cache.ts +104 -0
  363. package/packages/pi-coding-agent/src/core/event-bus.ts +33 -0
  364. package/packages/pi-coding-agent/src/core/exec.ts +106 -0
  365. package/packages/pi-coding-agent/src/core/export-html/ansi-to-html.ts +258 -0
  366. package/packages/pi-coding-agent/src/core/export-html/index.ts +306 -0
  367. package/packages/pi-coding-agent/src/core/export-html/template.css +971 -0
  368. package/packages/pi-coding-agent/src/core/export-html/template.html +54 -0
  369. package/packages/pi-coding-agent/src/core/export-html/template.js +1583 -0
  370. package/packages/pi-coding-agent/src/core/export-html/tool-renderer.ts +114 -0
  371. package/packages/pi-coding-agent/src/core/export-html/vendor/highlight.min.js +1213 -0
  372. package/packages/pi-coding-agent/src/core/export-html/vendor/marked.min.js +6 -0
  373. package/packages/pi-coding-agent/src/core/extensions/extension-discovery.ts +119 -0
  374. package/packages/pi-coding-agent/src/core/extensions/extension-manifest.test.ts +77 -0
  375. package/packages/pi-coding-agent/src/core/extensions/extension-manifest.ts +62 -0
  376. package/packages/pi-coding-agent/src/core/extensions/extension-registry.ts +222 -0
  377. package/packages/pi-coding-agent/src/core/extensions/extension-sort.test.ts +134 -0
  378. package/packages/pi-coding-agent/src/core/extensions/extension-sort.ts +137 -0
  379. package/packages/pi-coding-agent/src/core/extensions/index.ts +186 -0
  380. package/packages/pi-coding-agent/src/core/extensions/loader.test.ts +275 -0
  381. package/packages/pi-coding-agent/src/core/extensions/loader.ts +1139 -0
  382. package/packages/pi-coding-agent/src/core/extensions/project-trust.ts +51 -0
  383. package/packages/pi-coding-agent/src/core/extensions/provider-registration.test.ts +81 -0
  384. package/packages/pi-coding-agent/src/core/extensions/runner.test.ts +282 -0
  385. package/packages/pi-coding-agent/src/core/extensions/runner.ts +1241 -0
  386. package/packages/pi-coding-agent/src/core/extensions/types.ts +1872 -0
  387. package/packages/pi-coding-agent/src/core/extensions/wrapper.ts +127 -0
  388. package/packages/pi-coding-agent/src/core/fallback-resolver.test.ts +242 -0
  389. package/packages/pi-coding-agent/src/core/fallback-resolver.ts +164 -0
  390. package/packages/pi-coding-agent/src/core/footer-data-provider.ts +144 -0
  391. package/packages/pi-coding-agent/src/core/fs-utils.test.ts +54 -0
  392. package/packages/pi-coding-agent/src/core/fs-utils.ts +12 -0
  393. package/packages/pi-coding-agent/src/core/hooks-runner.test.ts +271 -0
  394. package/packages/pi-coding-agent/src/core/hooks-runner.ts +460 -0
  395. package/packages/pi-coding-agent/src/core/image-overflow-recovery.test.ts +228 -0
  396. package/packages/pi-coding-agent/src/core/image-overflow-recovery.ts +118 -0
  397. package/packages/pi-coding-agent/src/core/index.ts +80 -0
  398. package/packages/pi-coding-agent/src/core/keybindings.ts +211 -0
  399. package/packages/pi-coding-agent/src/core/lifecycle-hooks.test.ts +227 -0
  400. package/packages/pi-coding-agent/src/core/lifecycle-hooks.ts +280 -0
  401. package/packages/pi-coding-agent/src/core/local-model-check.ts +45 -0
  402. package/packages/pi-coding-agent/src/core/lock-utils.ts +113 -0
  403. package/packages/pi-coding-agent/src/core/lsp/client.ts +968 -0
  404. package/packages/pi-coding-agent/src/core/lsp/config.ts +356 -0
  405. package/packages/pi-coding-agent/src/core/lsp/defaults.json +456 -0
  406. package/packages/pi-coding-agent/src/core/lsp/edits.ts +109 -0
  407. package/packages/pi-coding-agent/src/core/lsp/helpers.ts +54 -0
  408. package/packages/pi-coding-agent/src/core/lsp/index.ts +1065 -0
  409. package/packages/pi-coding-agent/src/core/lsp/lsp-integration.test.ts +451 -0
  410. package/packages/pi-coding-agent/src/core/lsp/lsp-legacy-alias.test.ts +70 -0
  411. package/packages/pi-coding-agent/src/core/lsp/lsp.md +39 -0
  412. package/packages/pi-coding-agent/src/core/lsp/lspmux.ts +190 -0
  413. package/packages/pi-coding-agent/src/core/lsp/types.ts +445 -0
  414. package/packages/pi-coding-agent/src/core/lsp/utils.ts +706 -0
  415. package/packages/pi-coding-agent/src/core/messages.test.ts +114 -0
  416. package/packages/pi-coding-agent/src/core/messages.ts +226 -0
  417. package/packages/pi-coding-agent/src/core/model-discovery.test.ts +144 -0
  418. package/packages/pi-coding-agent/src/core/model-discovery.ts +318 -0
  419. package/packages/pi-coding-agent/src/core/model-registry-auth-header.test.ts +44 -0
  420. package/packages/pi-coding-agent/src/core/model-registry-auth-mode.test.ts +730 -0
  421. package/packages/pi-coding-agent/src/core/model-registry-custom-caps.test.ts +245 -0
  422. package/packages/pi-coding-agent/src/core/model-registry-discovery.test.ts +210 -0
  423. package/packages/pi-coding-agent/src/core/model-registry-env-fallback.test.ts +59 -0
  424. package/packages/pi-coding-agent/src/core/model-registry.ts +1053 -0
  425. package/packages/pi-coding-agent/src/core/model-resolver-initial-model-auth.test.ts +78 -0
  426. package/packages/pi-coding-agent/src/core/model-resolver.test.ts +85 -0
  427. package/packages/pi-coding-agent/src/core/model-resolver.ts +511 -0
  428. package/packages/pi-coding-agent/src/core/models-json-writer.test.ts +145 -0
  429. package/packages/pi-coding-agent/src/core/models-json-writer.ts +188 -0
  430. package/packages/pi-coding-agent/src/core/package-commands.test.ts +262 -0
  431. package/packages/pi-coding-agent/src/core/package-commands.ts +310 -0
  432. package/packages/pi-coding-agent/src/core/package-manager.ts +1845 -0
  433. package/packages/pi-coding-agent/src/core/prompt-templates.ts +299 -0
  434. package/packages/pi-coding-agent/src/core/redact-secrets.test.ts +86 -0
  435. package/packages/pi-coding-agent/src/core/redact-secrets.ts +58 -0
  436. package/packages/pi-coding-agent/src/core/resolve-config-value.test.ts +295 -0
  437. package/packages/pi-coding-agent/src/core/resolve-config-value.ts +118 -0
  438. package/packages/pi-coding-agent/src/core/resource-loader-cache-reset.test.ts +107 -0
  439. package/packages/pi-coding-agent/src/core/resource-loader.ts +929 -0
  440. package/packages/pi-coding-agent/src/core/retry-handler.test.ts +518 -0
  441. package/packages/pi-coding-agent/src/core/retry-handler.ts +576 -0
  442. package/packages/pi-coding-agent/src/core/retryable-error-regex.ts +18 -0
  443. package/packages/pi-coding-agent/src/core/sdk-tool-filter.test.ts +60 -0
  444. package/packages/pi-coding-agent/src/core/sdk.test.ts +113 -0
  445. package/packages/pi-coding-agent/src/core/sdk.ts +688 -0
  446. package/packages/pi-coding-agent/src/core/session-manager.test.ts +129 -0
  447. package/packages/pi-coding-agent/src/core/session-manager.ts +1646 -0
  448. package/packages/pi-coding-agent/src/core/settings-manager-security.test.ts +102 -0
  449. package/packages/pi-coding-agent/src/core/settings-manager.ts +1247 -0
  450. package/packages/pi-coding-agent/src/core/skill-tool.test.ts +117 -0
  451. package/packages/pi-coding-agent/src/core/skills.ts +490 -0
  452. package/packages/pi-coding-agent/src/core/slash-commands.ts +43 -0
  453. package/packages/pi-coding-agent/src/core/system-prompt.ts +296 -0
  454. package/packages/pi-coding-agent/src/core/timings.ts +25 -0
  455. package/packages/pi-coding-agent/src/core/token-telemetry.ts +77 -0
  456. package/packages/pi-coding-agent/src/core/tools/bash-background.test.ts +91 -0
  457. package/packages/pi-coding-agent/src/core/tools/bash-interceptor.test.ts +198 -0
  458. package/packages/pi-coding-agent/src/core/tools/bash-interceptor.ts +115 -0
  459. package/packages/pi-coding-agent/src/core/tools/bash-spawn-windows.test.ts +77 -0
  460. package/packages/pi-coding-agent/src/core/tools/bash.ts +478 -0
  461. package/packages/pi-coding-agent/src/core/tools/edit-diff.test.ts +85 -0
  462. package/packages/pi-coding-agent/src/core/tools/edit-diff.ts +402 -0
  463. package/packages/pi-coding-agent/src/core/tools/edit.ts +242 -0
  464. package/packages/pi-coding-agent/src/core/tools/find.ts +209 -0
  465. package/packages/pi-coding-agent/src/core/tools/grep.ts +356 -0
  466. package/packages/pi-coding-agent/src/core/tools/hashline-edit.ts +318 -0
  467. package/packages/pi-coding-agent/src/core/tools/hashline-read.ts +207 -0
  468. package/packages/pi-coding-agent/src/core/tools/hashline.test.ts +456 -0
  469. package/packages/pi-coding-agent/src/core/tools/hashline.ts +525 -0
  470. package/packages/pi-coding-agent/src/core/tools/index.ts +226 -0
  471. package/packages/pi-coding-agent/src/core/tools/ls.ts +178 -0
  472. package/packages/pi-coding-agent/src/core/tools/path-utils.test.ts +67 -0
  473. package/packages/pi-coding-agent/src/core/tools/path-utils.ts +106 -0
  474. package/packages/pi-coding-agent/src/core/tools/read.ts +235 -0
  475. package/packages/pi-coding-agent/src/core/tools/spawn-shell-windows.test.ts +31 -0
  476. package/packages/pi-coding-agent/src/core/tools/tool-compatibility-registry.ts +83 -0
  477. package/packages/pi-coding-agent/src/core/tools/tool-target-metadata.test.ts +127 -0
  478. package/packages/pi-coding-agent/src/core/tools/tool-target.ts +48 -0
  479. package/packages/pi-coding-agent/src/core/tools/truncate.ts +267 -0
  480. package/packages/pi-coding-agent/src/core/tools/write.ts +133 -0
  481. package/packages/pi-coding-agent/src/index.ts +422 -0
  482. package/packages/pi-coding-agent/src/main.ts +649 -0
  483. package/packages/pi-coding-agent/src/migrations.ts +295 -0
  484. package/packages/pi-coding-agent/src/modes/index.ts +16 -0
  485. package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/assistant-message-design.test.ts +128 -0
  486. package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/chat-frame-compaction-tone.test.ts +93 -0
  487. package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/collapsible-message.test.ts +111 -0
  488. package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/login-dialog.test.ts +24 -0
  489. package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/provider-display-name.test.ts +28 -0
  490. package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/timestamp.test.ts +41 -0
  491. package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/tool-execution.test.ts +512 -0
  492. package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/user-message-design.test.ts +139 -0
  493. package/packages/pi-coding-agent/src/modes/interactive/components/adaptive-layout.test.ts +66 -0
  494. package/packages/pi-coding-agent/src/modes/interactive/components/adaptive-layout.ts +161 -0
  495. package/packages/pi-coding-agent/src/modes/interactive/components/animated-component.test.ts +115 -0
  496. package/packages/pi-coding-agent/src/modes/interactive/components/animated-component.ts +107 -0
  497. package/packages/pi-coding-agent/src/modes/interactive/components/armin.ts +360 -0
  498. package/packages/pi-coding-agent/src/modes/interactive/components/assistant-message.ts +200 -0
  499. package/packages/pi-coding-agent/src/modes/interactive/components/bash-execution.test.ts +35 -0
  500. package/packages/pi-coding-agent/src/modes/interactive/components/bash-execution.ts +287 -0
  501. package/packages/pi-coding-agent/src/modes/interactive/components/bordered-loader.ts +66 -0
  502. package/packages/pi-coding-agent/src/modes/interactive/components/branch-summary-message.ts +54 -0
  503. package/packages/pi-coding-agent/src/modes/interactive/components/collapsible-message.ts +45 -0
  504. package/packages/pi-coding-agent/src/modes/interactive/components/compaction-summary-message.ts +73 -0
  505. package/packages/pi-coding-agent/src/modes/interactive/components/config-selector.ts +599 -0
  506. package/packages/pi-coding-agent/src/modes/interactive/components/countdown-timer.ts +43 -0
  507. package/packages/pi-coding-agent/src/modes/interactive/components/custom-editor.ts +97 -0
  508. package/packages/pi-coding-agent/src/modes/interactive/components/custom-message.ts +89 -0
  509. package/packages/pi-coding-agent/src/modes/interactive/components/daxnuts.test.ts +68 -0
  510. package/packages/pi-coding-agent/src/modes/interactive/components/daxnuts.ts +159 -0
  511. package/packages/pi-coding-agent/src/modes/interactive/components/diff.ts +153 -0
  512. package/packages/pi-coding-agent/src/modes/interactive/components/dynamic-border.test.ts +99 -0
  513. package/packages/pi-coding-agent/src/modes/interactive/components/dynamic-border.ts +97 -0
  514. package/packages/pi-coding-agent/src/modes/interactive/components/extension-editor.ts +150 -0
  515. package/packages/pi-coding-agent/src/modes/interactive/components/extension-input.ts +92 -0
  516. package/packages/pi-coding-agent/src/modes/interactive/components/extension-selector.ts +152 -0
  517. package/packages/pi-coding-agent/src/modes/interactive/components/footer.ts +266 -0
  518. package/packages/pi-coding-agent/src/modes/interactive/components/index.ts +33 -0
  519. package/packages/pi-coding-agent/src/modes/interactive/components/interactive-key-handling.test.ts +122 -0
  520. package/packages/pi-coding-agent/src/modes/interactive/components/keybinding-hints.ts +84 -0
  521. package/packages/pi-coding-agent/src/modes/interactive/components/login-dialog.ts +256 -0
  522. package/packages/pi-coding-agent/src/modes/interactive/components/model-selector.ts +693 -0
  523. package/packages/pi-coding-agent/src/modes/interactive/components/oauth-selector.ts +127 -0
  524. package/packages/pi-coding-agent/src/modes/interactive/components/provider-manager.ts +231 -0
  525. package/packages/pi-coding-agent/src/modes/interactive/components/render-cache.ts +22 -0
  526. package/packages/pi-coding-agent/src/modes/interactive/components/scoped-models-selector.ts +342 -0
  527. package/packages/pi-coding-agent/src/modes/interactive/components/selector-footers.test.ts +63 -0
  528. package/packages/pi-coding-agent/src/modes/interactive/components/session-selector-search.ts +194 -0
  529. package/packages/pi-coding-agent/src/modes/interactive/components/session-selector.ts +1015 -0
  530. package/packages/pi-coding-agent/src/modes/interactive/components/settings-selector.ts +466 -0
  531. package/packages/pi-coding-agent/src/modes/interactive/components/show-images-selector.ts +47 -0
  532. package/packages/pi-coding-agent/src/modes/interactive/components/skill-invocation-message.ts +61 -0
  533. package/packages/pi-coding-agent/src/modes/interactive/components/theme-selector.test.ts +27 -0
  534. package/packages/pi-coding-agent/src/modes/interactive/components/theme-selector.ts +67 -0
  535. package/packages/pi-coding-agent/src/modes/interactive/components/thinking-selector.ts +66 -0
  536. package/packages/pi-coding-agent/src/modes/interactive/components/timestamp.ts +49 -0
  537. package/packages/pi-coding-agent/src/modes/interactive/components/tool-card-cleanup-and-success-runtime.test.ts +303 -0
  538. package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +1457 -0
  539. package/packages/pi-coding-agent/src/modes/interactive/components/transcript-design.ts +345 -0
  540. package/packages/pi-coding-agent/src/modes/interactive/components/tree-render-utils.ts +84 -0
  541. package/packages/pi-coding-agent/src/modes/interactive/components/tree-selector.ts +1125 -0
  542. package/packages/pi-coding-agent/src/modes/interactive/components/user-message-selector.test.ts +28 -0
  543. package/packages/pi-coding-agent/src/modes/interactive/components/user-message-selector.ts +154 -0
  544. package/packages/pi-coding-agent/src/modes/interactive/components/user-message.ts +76 -0
  545. package/packages/pi-coding-agent/src/modes/interactive/components/visual-truncate.ts +50 -0
  546. package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.test.ts +230 -0
  547. package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +1066 -0
  548. package/packages/pi-coding-agent/src/modes/interactive/controllers/extension-ui-controller.ts +68 -0
  549. package/packages/pi-coding-agent/src/modes/interactive/controllers/input-controller.test.ts +373 -0
  550. package/packages/pi-coding-agent/src/modes/interactive/controllers/input-controller.ts +157 -0
  551. package/packages/pi-coding-agent/src/modes/interactive/controllers/model-controller.ts +76 -0
  552. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode-lifecycle.test.ts +63 -0
  553. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode-ordering.test.ts +73 -0
  554. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode-state.ts +40 -0
  555. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +4418 -0
  556. package/packages/pi-coding-agent/src/modes/interactive/slash-command-handlers.test.ts +95 -0
  557. package/packages/pi-coding-agent/src/modes/interactive/slash-command-handlers.ts +695 -0
  558. package/packages/pi-coding-agent/src/modes/interactive/theme/theme-highlight.test.ts +23 -0
  559. package/packages/pi-coding-agent/src/modes/interactive/theme/theme-schema.ts +96 -0
  560. package/packages/pi-coding-agent/src/modes/interactive/theme/theme.ts +1130 -0
  561. package/packages/pi-coding-agent/src/modes/interactive/theme/themes.ts +388 -0
  562. package/packages/pi-coding-agent/src/modes/interactive/tui-mode.test.ts +68 -0
  563. package/packages/pi-coding-agent/src/modes/interactive/tui-mode.ts +29 -0
  564. package/packages/pi-coding-agent/src/modes/interactive/utils/shorten-path.ts +15 -0
  565. package/packages/pi-coding-agent/src/modes/interactive/utils/tool-call-summary.test.ts +39 -0
  566. package/packages/pi-coding-agent/src/modes/interactive/utils/tool-call-summary.ts +56 -0
  567. package/packages/pi-coding-agent/src/modes/print-mode.ts +106 -0
  568. package/packages/pi-coding-agent/src/modes/rpc/jsonl.ts +64 -0
  569. package/packages/pi-coding-agent/src/modes/rpc/remote-terminal.ts +109 -0
  570. package/packages/pi-coding-agent/src/modes/rpc/rpc-client.ts +574 -0
  571. package/packages/pi-coding-agent/src/modes/rpc/rpc-mode.ts +891 -0
  572. package/packages/pi-coding-agent/src/modes/rpc/rpc-protocol-v2.test.ts +971 -0
  573. package/packages/pi-coding-agent/src/modes/rpc/rpc-types.ts +4 -0
  574. package/packages/pi-coding-agent/src/modes/shared/command-context-actions.ts +53 -0
  575. package/packages/pi-coding-agent/src/resources/extensions/memory/index.ts +270 -0
  576. package/packages/pi-coding-agent/src/resources/extensions/memory/pipeline.ts +567 -0
  577. package/packages/pi-coding-agent/src/resources/extensions/memory/storage-safety-guard.test.ts +31 -0
  578. package/packages/pi-coding-agent/src/resources/extensions/memory/storage.test.ts +98 -0
  579. package/packages/pi-coding-agent/src/resources/extensions/memory/storage.ts +479 -0
  580. package/packages/pi-coding-agent/src/tests/path-display.test.ts +85 -0
  581. package/packages/pi-coding-agent/src/tests/system-prompt-cache-stability.test.ts +102 -0
  582. package/packages/pi-coding-agent/src/tests/system-prompt-file-safety.test.ts +22 -0
  583. package/packages/pi-coding-agent/src/tests/system-prompt-skill-filter.test.ts +157 -0
  584. package/packages/pi-coding-agent/src/tests/token-telemetry.test.ts +200 -0
  585. package/packages/pi-coding-agent/src/types/ambient-modules.d.ts +69 -0
  586. package/packages/pi-coding-agent/src/utils/changelog.ts +99 -0
  587. package/packages/pi-coding-agent/src/utils/clipboard-image.ts +227 -0
  588. package/packages/pi-coding-agent/src/utils/clipboard-native.ts +11 -0
  589. package/packages/pi-coding-agent/src/utils/clipboard.ts +14 -0
  590. package/packages/pi-coding-agent/src/utils/error.ts +6 -0
  591. package/packages/pi-coding-agent/src/utils/frontmatter.ts +39 -0
  592. package/packages/pi-coding-agent/src/utils/git.ts +192 -0
  593. package/packages/pi-coding-agent/src/utils/image-convert.ts +28 -0
  594. package/packages/pi-coding-agent/src/utils/image-resize.ts +225 -0
  595. package/packages/pi-coding-agent/src/utils/mime.ts +30 -0
  596. package/packages/pi-coding-agent/src/utils/path-display.ts +36 -0
  597. package/packages/pi-coding-agent/src/utils/photon.ts +2 -0
  598. package/packages/pi-coding-agent/src/utils/shell.ts +212 -0
  599. package/packages/pi-coding-agent/src/utils/sleep.ts +18 -0
  600. package/packages/pi-coding-agent/src/utils/tools-manager.ts +286 -0
  601. package/packages/pi-coding-agent/tsconfig.json +28 -0
  602. package/packages/pi-tui/dist/__tests__/autocomplete.test.d.ts +2 -0
  603. package/packages/pi-tui/dist/__tests__/autocomplete.test.d.ts.map +1 -0
  604. package/packages/pi-tui/dist/__tests__/autocomplete.test.js +206 -0
  605. package/packages/pi-tui/dist/__tests__/autocomplete.test.js.map +1 -0
  606. package/packages/pi-tui/dist/__tests__/fuzzy.test.d.ts +2 -0
  607. package/packages/pi-tui/dist/__tests__/fuzzy.test.d.ts.map +1 -0
  608. package/packages/pi-tui/dist/__tests__/fuzzy.test.js +100 -0
  609. package/packages/pi-tui/dist/__tests__/fuzzy.test.js.map +1 -0
  610. package/packages/pi-tui/dist/__tests__/keys.test.d.ts +2 -0
  611. package/packages/pi-tui/dist/__tests__/keys.test.d.ts.map +1 -0
  612. package/packages/pi-tui/dist/__tests__/keys.test.js +18 -0
  613. package/packages/pi-tui/dist/__tests__/keys.test.js.map +1 -0
  614. package/packages/pi-tui/dist/__tests__/loader.test.d.ts +2 -0
  615. package/packages/pi-tui/dist/__tests__/loader.test.d.ts.map +1 -0
  616. package/packages/pi-tui/dist/__tests__/loader.test.js +24 -0
  617. package/packages/pi-tui/dist/__tests__/loader.test.js.map +1 -0
  618. package/packages/pi-tui/dist/__tests__/overlay-layout.test.d.ts +2 -0
  619. package/packages/pi-tui/dist/__tests__/overlay-layout.test.d.ts.map +1 -0
  620. package/packages/pi-tui/dist/__tests__/overlay-layout.test.js +227 -0
  621. package/packages/pi-tui/dist/__tests__/overlay-layout.test.js.map +1 -0
  622. package/packages/pi-tui/dist/__tests__/stdin-buffer.test.d.ts +2 -0
  623. package/packages/pi-tui/dist/__tests__/stdin-buffer.test.d.ts.map +1 -0
  624. package/packages/pi-tui/dist/__tests__/stdin-buffer.test.js +80 -0
  625. package/packages/pi-tui/dist/__tests__/stdin-buffer.test.js.map +1 -0
  626. package/packages/pi-tui/dist/__tests__/style.test.d.ts +2 -0
  627. package/packages/pi-tui/dist/__tests__/style.test.d.ts.map +1 -0
  628. package/packages/pi-tui/dist/__tests__/style.test.js +129 -0
  629. package/packages/pi-tui/dist/__tests__/style.test.js.map +1 -0
  630. package/packages/pi-tui/dist/__tests__/terminal.test.d.ts +2 -0
  631. package/packages/pi-tui/dist/__tests__/terminal.test.d.ts.map +1 -0
  632. package/packages/pi-tui/dist/__tests__/terminal.test.js +103 -0
  633. package/packages/pi-tui/dist/__tests__/terminal.test.js.map +1 -0
  634. package/packages/pi-tui/dist/__tests__/tui.test.d.ts +2 -0
  635. package/packages/pi-tui/dist/__tests__/tui.test.d.ts.map +1 -0
  636. package/packages/pi-tui/dist/__tests__/tui.test.js +315 -0
  637. package/packages/pi-tui/dist/__tests__/tui.test.js.map +1 -0
  638. package/packages/pi-tui/dist/__tests__/utils.test.d.ts +2 -0
  639. package/packages/pi-tui/dist/__tests__/utils.test.d.ts.map +1 -0
  640. package/packages/pi-tui/dist/__tests__/utils.test.js +17 -0
  641. package/packages/pi-tui/dist/__tests__/utils.test.js.map +1 -0
  642. package/packages/pi-tui/dist/autocomplete.d.ts +55 -0
  643. package/packages/pi-tui/dist/autocomplete.d.ts.map +1 -0
  644. package/packages/pi-tui/dist/autocomplete.js +540 -0
  645. package/packages/pi-tui/dist/autocomplete.js.map +1 -0
  646. package/packages/pi-tui/dist/components/__tests__/box.test.d.ts +2 -0
  647. package/packages/pi-tui/dist/components/__tests__/box.test.d.ts.map +1 -0
  648. package/packages/pi-tui/dist/components/__tests__/box.test.js +20 -0
  649. package/packages/pi-tui/dist/components/__tests__/box.test.js.map +1 -0
  650. package/packages/pi-tui/dist/components/__tests__/cancellable-loader.test.d.ts +2 -0
  651. package/packages/pi-tui/dist/components/__tests__/cancellable-loader.test.d.ts.map +1 -0
  652. package/packages/pi-tui/dist/components/__tests__/cancellable-loader.test.js +38 -0
  653. package/packages/pi-tui/dist/components/__tests__/cancellable-loader.test.js.map +1 -0
  654. package/packages/pi-tui/dist/components/__tests__/editor.test.d.ts +2 -0
  655. package/packages/pi-tui/dist/components/__tests__/editor.test.d.ts.map +1 -0
  656. package/packages/pi-tui/dist/components/__tests__/editor.test.js +89 -0
  657. package/packages/pi-tui/dist/components/__tests__/editor.test.js.map +1 -0
  658. package/packages/pi-tui/dist/components/__tests__/input.test.d.ts +2 -0
  659. package/packages/pi-tui/dist/components/__tests__/input.test.d.ts.map +1 -0
  660. package/packages/pi-tui/dist/components/__tests__/input.test.js +81 -0
  661. package/packages/pi-tui/dist/components/__tests__/input.test.js.map +1 -0
  662. package/packages/pi-tui/dist/components/__tests__/leak-fixes-runtime.test.d.ts +2 -0
  663. package/packages/pi-tui/dist/components/__tests__/leak-fixes-runtime.test.d.ts.map +1 -0
  664. package/packages/pi-tui/dist/components/__tests__/leak-fixes-runtime.test.js +161 -0
  665. package/packages/pi-tui/dist/components/__tests__/leak-fixes-runtime.test.js.map +1 -0
  666. package/packages/pi-tui/dist/components/__tests__/loader.test.d.ts +2 -0
  667. package/packages/pi-tui/dist/components/__tests__/loader.test.d.ts.map +1 -0
  668. package/packages/pi-tui/dist/components/__tests__/loader.test.js +81 -0
  669. package/packages/pi-tui/dist/components/__tests__/loader.test.js.map +1 -0
  670. package/packages/pi-tui/dist/components/__tests__/markdown-list.test.d.ts +2 -0
  671. package/packages/pi-tui/dist/components/__tests__/markdown-list.test.d.ts.map +1 -0
  672. package/packages/pi-tui/dist/components/__tests__/markdown-list.test.js +36 -0
  673. package/packages/pi-tui/dist/components/__tests__/markdown-list.test.js.map +1 -0
  674. package/packages/pi-tui/dist/components/__tests__/markdown-maxlines.test.d.ts +2 -0
  675. package/packages/pi-tui/dist/components/__tests__/markdown-maxlines.test.d.ts.map +1 -0
  676. package/packages/pi-tui/dist/components/__tests__/markdown-maxlines.test.js +70 -0
  677. package/packages/pi-tui/dist/components/__tests__/markdown-maxlines.test.js.map +1 -0
  678. package/packages/pi-tui/dist/components/__tests__/select-list.test.d.ts +2 -0
  679. package/packages/pi-tui/dist/components/__tests__/select-list.test.d.ts.map +1 -0
  680. package/packages/pi-tui/dist/components/__tests__/select-list.test.js +42 -0
  681. package/packages/pi-tui/dist/components/__tests__/select-list.test.js.map +1 -0
  682. package/packages/pi-tui/dist/components/__tests__/truncated-text.test.d.ts +2 -0
  683. package/packages/pi-tui/dist/components/__tests__/truncated-text.test.d.ts.map +1 -0
  684. package/packages/pi-tui/dist/components/__tests__/truncated-text.test.js +14 -0
  685. package/packages/pi-tui/dist/components/__tests__/truncated-text.test.js.map +1 -0
  686. package/packages/pi-tui/dist/components/box.d.ts +23 -0
  687. package/packages/pi-tui/dist/components/box.d.ts.map +1 -0
  688. package/packages/pi-tui/dist/components/box.js +111 -0
  689. package/packages/pi-tui/dist/components/box.js.map +1 -0
  690. package/packages/pi-tui/dist/components/cancellable-loader.d.ts +22 -0
  691. package/packages/pi-tui/dist/components/cancellable-loader.d.ts.map +1 -0
  692. package/packages/pi-tui/dist/components/cancellable-loader.js +38 -0
  693. package/packages/pi-tui/dist/components/cancellable-loader.js.map +1 -0
  694. package/packages/pi-tui/dist/components/editor.d.ts +245 -0
  695. package/packages/pi-tui/dist/components/editor.d.ts.map +1 -0
  696. package/packages/pi-tui/dist/components/editor.js +1825 -0
  697. package/packages/pi-tui/dist/components/editor.js.map +1 -0
  698. package/packages/pi-tui/dist/components/image.d.ts +37 -0
  699. package/packages/pi-tui/dist/components/image.d.ts.map +1 -0
  700. package/packages/pi-tui/dist/components/image.js +84 -0
  701. package/packages/pi-tui/dist/components/image.js.map +1 -0
  702. package/packages/pi-tui/dist/components/image.test.d.ts +6 -0
  703. package/packages/pi-tui/dist/components/image.test.d.ts.map +1 -0
  704. package/packages/pi-tui/dist/components/image.test.js +33 -0
  705. package/packages/pi-tui/dist/components/image.test.js.map +1 -0
  706. package/packages/pi-tui/dist/components/input.d.ts +42 -0
  707. package/packages/pi-tui/dist/components/input.d.ts.map +1 -0
  708. package/packages/pi-tui/dist/components/input.js +479 -0
  709. package/packages/pi-tui/dist/components/input.js.map +1 -0
  710. package/packages/pi-tui/dist/components/loader.d.ts +24 -0
  711. package/packages/pi-tui/dist/components/loader.d.ts.map +1 -0
  712. package/packages/pi-tui/dist/components/loader.js +74 -0
  713. package/packages/pi-tui/dist/components/loader.js.map +1 -0
  714. package/packages/pi-tui/dist/components/markdown.d.ts +106 -0
  715. package/packages/pi-tui/dist/components/markdown.d.ts.map +1 -0
  716. package/packages/pi-tui/dist/components/markdown.js +668 -0
  717. package/packages/pi-tui/dist/components/markdown.js.map +1 -0
  718. package/packages/pi-tui/dist/components/select-list.d.ts +32 -0
  719. package/packages/pi-tui/dist/components/select-list.d.ts.map +1 -0
  720. package/packages/pi-tui/dist/components/select-list.js +155 -0
  721. package/packages/pi-tui/dist/components/select-list.js.map +1 -0
  722. package/packages/pi-tui/dist/components/settings-list.d.ts +50 -0
  723. package/packages/pi-tui/dist/components/settings-list.d.ts.map +1 -0
  724. package/packages/pi-tui/dist/components/settings-list.js +179 -0
  725. package/packages/pi-tui/dist/components/settings-list.js.map +1 -0
  726. package/packages/pi-tui/dist/components/spacer.d.ts +12 -0
  727. package/packages/pi-tui/dist/components/spacer.d.ts.map +1 -0
  728. package/packages/pi-tui/dist/components/spacer.js +22 -0
  729. package/packages/pi-tui/dist/components/spacer.js.map +1 -0
  730. package/packages/pi-tui/dist/components/text.d.ts +19 -0
  731. package/packages/pi-tui/dist/components/text.d.ts.map +1 -0
  732. package/packages/pi-tui/dist/components/text.js +83 -0
  733. package/packages/pi-tui/dist/components/text.js.map +1 -0
  734. package/packages/pi-tui/dist/components/truncated-text.d.ts +13 -0
  735. package/packages/pi-tui/dist/components/truncated-text.d.ts.map +1 -0
  736. package/packages/pi-tui/dist/components/truncated-text.js +54 -0
  737. package/packages/pi-tui/dist/components/truncated-text.js.map +1 -0
  738. package/packages/pi-tui/dist/editor-component.d.ts +41 -0
  739. package/packages/pi-tui/dist/editor-component.d.ts.map +1 -0
  740. package/packages/pi-tui/dist/editor-component.js +2 -0
  741. package/packages/pi-tui/dist/editor-component.js.map +1 -0
  742. package/packages/pi-tui/dist/fuzzy.d.ts +16 -0
  743. package/packages/pi-tui/dist/fuzzy.d.ts.map +1 -0
  744. package/packages/pi-tui/dist/fuzzy.js +111 -0
  745. package/packages/pi-tui/dist/fuzzy.js.map +1 -0
  746. package/packages/pi-tui/dist/index.d.ts +24 -0
  747. package/packages/pi-tui/dist/index.d.ts.map +1 -0
  748. package/packages/pi-tui/dist/index.js +35 -0
  749. package/packages/pi-tui/dist/index.js.map +1 -0
  750. package/packages/pi-tui/dist/keybindings.d.ts +39 -0
  751. package/packages/pi-tui/dist/keybindings.d.ts.map +1 -0
  752. package/packages/pi-tui/dist/keybindings.js +116 -0
  753. package/packages/pi-tui/dist/keybindings.js.map +1 -0
  754. package/packages/pi-tui/dist/keys.d.ts +142 -0
  755. package/packages/pi-tui/dist/keys.d.ts.map +1 -0
  756. package/packages/pi-tui/dist/keys.js +994 -0
  757. package/packages/pi-tui/dist/keys.js.map +1 -0
  758. package/packages/pi-tui/dist/kill-ring.d.ts +28 -0
  759. package/packages/pi-tui/dist/kill-ring.d.ts.map +1 -0
  760. package/packages/pi-tui/dist/kill-ring.js +46 -0
  761. package/packages/pi-tui/dist/kill-ring.js.map +1 -0
  762. package/packages/pi-tui/dist/overlay-layout.d.ts +55 -0
  763. package/packages/pi-tui/dist/overlay-layout.d.ts.map +1 -0
  764. package/packages/pi-tui/dist/overlay-layout.js +314 -0
  765. package/packages/pi-tui/dist/overlay-layout.js.map +1 -0
  766. package/packages/pi-tui/dist/stdin-buffer.d.ts +55 -0
  767. package/packages/pi-tui/dist/stdin-buffer.d.ts.map +1 -0
  768. package/packages/pi-tui/dist/stdin-buffer.js +342 -0
  769. package/packages/pi-tui/dist/stdin-buffer.js.map +1 -0
  770. package/packages/pi-tui/dist/style.d.ts +52 -0
  771. package/packages/pi-tui/dist/style.d.ts.map +1 -0
  772. package/packages/pi-tui/dist/style.js +219 -0
  773. package/packages/pi-tui/dist/style.js.map +1 -0
  774. package/packages/pi-tui/dist/terminal-image.d.ts +68 -0
  775. package/packages/pi-tui/dist/terminal-image.d.ts.map +1 -0
  776. package/packages/pi-tui/dist/terminal-image.js +181 -0
  777. package/packages/pi-tui/dist/terminal-image.js.map +1 -0
  778. package/packages/pi-tui/dist/terminal.d.ts +89 -0
  779. package/packages/pi-tui/dist/terminal.d.ts.map +1 -0
  780. package/packages/pi-tui/dist/terminal.js +295 -0
  781. package/packages/pi-tui/dist/terminal.js.map +1 -0
  782. package/packages/pi-tui/dist/tui.d.ts +213 -0
  783. package/packages/pi-tui/dist/tui.d.ts.map +1 -0
  784. package/packages/pi-tui/dist/tui.js +978 -0
  785. package/packages/pi-tui/dist/tui.js.map +1 -0
  786. package/packages/pi-tui/dist/undo-stack.d.ts +17 -0
  787. package/packages/pi-tui/dist/undo-stack.d.ts.map +1 -0
  788. package/packages/pi-tui/dist/undo-stack.js +27 -0
  789. package/packages/pi-tui/dist/undo-stack.js.map +1 -0
  790. package/packages/pi-tui/dist/utils.d.ts +72 -0
  791. package/packages/pi-tui/dist/utils.d.ts.map +1 -0
  792. package/packages/pi-tui/dist/utils.js +120 -0
  793. package/packages/pi-tui/dist/utils.js.map +1 -0
  794. package/packages/pi-tui/package.json +35 -0
  795. package/packages/pi-tui/src/__tests__/autocomplete.test.ts +264 -0
  796. package/packages/pi-tui/src/__tests__/fuzzy.test.ts +120 -0
  797. package/packages/pi-tui/src/__tests__/keys.test.ts +21 -0
  798. package/packages/pi-tui/src/__tests__/loader.test.ts +30 -0
  799. package/packages/pi-tui/src/__tests__/overlay-layout.test.ts +266 -0
  800. package/packages/pi-tui/src/__tests__/stdin-buffer.test.ts +99 -0
  801. package/packages/pi-tui/src/__tests__/style.test.ts +156 -0
  802. package/packages/pi-tui/src/__tests__/terminal.test.ts +121 -0
  803. package/packages/pi-tui/src/__tests__/tui.test.ts +377 -0
  804. package/packages/pi-tui/src/__tests__/utils.test.ts +22 -0
  805. package/packages/pi-tui/src/autocomplete.ts +675 -0
  806. package/packages/pi-tui/src/components/__tests__/box.test.ts +25 -0
  807. package/packages/pi-tui/src/components/__tests__/cancellable-loader.test.ts +45 -0
  808. package/packages/pi-tui/src/components/__tests__/editor.test.ts +119 -0
  809. package/packages/pi-tui/src/components/__tests__/input.test.ts +111 -0
  810. package/packages/pi-tui/src/components/__tests__/leak-fixes-runtime.test.ts +219 -0
  811. package/packages/pi-tui/src/components/__tests__/loader.test.ts +122 -0
  812. package/packages/pi-tui/src/components/__tests__/markdown-list.test.ts +40 -0
  813. package/packages/pi-tui/src/components/__tests__/markdown-maxlines.test.ts +82 -0
  814. package/packages/pi-tui/src/components/__tests__/select-list.test.ts +70 -0
  815. package/packages/pi-tui/src/components/__tests__/truncated-text.test.ts +17 -0
  816. package/packages/pi-tui/src/components/box.ts +150 -0
  817. package/packages/pi-tui/src/components/cancellable-loader.ts +42 -0
  818. package/packages/pi-tui/src/components/editor.ts +2196 -0
  819. package/packages/pi-tui/src/components/image.test.ts +41 -0
  820. package/packages/pi-tui/src/components/image.ts +131 -0
  821. package/packages/pi-tui/src/components/input.ts +558 -0
  822. package/packages/pi-tui/src/components/loader.ts +83 -0
  823. package/packages/pi-tui/src/components/markdown.ts +842 -0
  824. package/packages/pi-tui/src/components/select-list.ts +194 -0
  825. package/packages/pi-tui/src/components/settings-list.ts +251 -0
  826. package/packages/pi-tui/src/components/spacer.ts +28 -0
  827. package/packages/pi-tui/src/components/text.ts +107 -0
  828. package/packages/pi-tui/src/components/truncated-text.ts +72 -0
  829. package/packages/pi-tui/src/editor-component.ts +77 -0
  830. package/packages/pi-tui/src/fuzzy.ts +138 -0
  831. package/packages/pi-tui/src/index.ts +98 -0
  832. package/packages/pi-tui/src/keybindings.ts +189 -0
  833. package/packages/pi-tui/src/keys.ts +1196 -0
  834. package/packages/pi-tui/src/kill-ring.ts +46 -0
  835. package/packages/pi-tui/src/overlay-layout.ts +408 -0
  836. package/packages/pi-tui/src/stdin-buffer.ts +419 -0
  837. package/packages/pi-tui/src/style.ts +295 -0
  838. package/packages/pi-tui/src/terminal-image.ts +260 -0
  839. package/packages/pi-tui/src/terminal.ts +377 -0
  840. package/packages/pi-tui/src/tui.ts +1182 -0
  841. package/packages/pi-tui/src/undo-stack.ts +28 -0
  842. package/packages/pi-tui/src/utils.ts +154 -0
  843. package/packages/pi-tui/tsconfig.json +28 -0
  844. package/packages/pi-tui/tsconfig.tsbuildinfo +1 -0
  845. package/packages/rpc-client/README.md +132 -0
  846. package/packages/rpc-client/examples/basic-usage.ts +13 -0
  847. package/packages/rpc-client/package.json +42 -0
  848. package/packages/rpc-client/src/index.ts +10 -0
  849. package/packages/rpc-client/src/jsonl.ts +64 -0
  850. package/packages/rpc-client/src/rpc-client.test.ts +625 -0
  851. package/packages/rpc-client/src/rpc-client.ts +663 -0
  852. package/packages/rpc-client/src/rpc-types.ts +4 -0
  853. package/packages/rpc-client/tsconfig.examples.json +17 -0
  854. package/packages/rpc-client/tsconfig.json +25 -0
  855. package/pkg/dist/core/export-html/template.css +971 -0
  856. package/pkg/dist/core/export-html/template.html +54 -0
  857. package/pkg/dist/core/export-html/template.js +1583 -0
  858. package/pkg/dist/core/export-html/vendor/highlight.min.js +1213 -0
  859. package/pkg/dist/core/export-html/vendor/marked.min.js +6 -0
  860. package/pkg/package.json +8 -0
  861. package/scripts/ensure-workspace-builds.cjs +123 -0
  862. package/scripts/install.js +526 -0
  863. package/scripts/lib/workspace-manifest.cjs +86 -0
  864. package/scripts/link-workspace-packages.cjs +82 -0
  865. package/scripts/postinstall.js +11 -0
  866. package/src/resources/GSD-WORKFLOW.md +664 -0
  867. package/src/resources/agents/debugger.md +58 -0
  868. package/src/resources/agents/doc-writer.md +43 -0
  869. package/src/resources/agents/git-ops.md +56 -0
  870. package/src/resources/agents/javascript-pro.md +55 -0
  871. package/src/resources/agents/planner.md +55 -0
  872. package/src/resources/agents/refactorer.md +47 -0
  873. package/src/resources/agents/researcher.md +29 -0
  874. package/src/resources/agents/reviewer.md +48 -0
  875. package/src/resources/agents/scout.md +56 -0
  876. package/src/resources/agents/security.md +59 -0
  877. package/src/resources/agents/tester.md +50 -0
  878. package/src/resources/agents/typescript-pro.md +61 -0
  879. package/src/resources/agents/worker.md +31 -0
  880. package/src/resources/extensions/ask-user-questions.ts +478 -0
  881. package/src/resources/extensions/async-jobs/async-bash-timeout.test.ts +122 -0
  882. package/src/resources/extensions/async-jobs/async-bash-tool.ts +263 -0
  883. package/src/resources/extensions/async-jobs/await-tool.test.ts +200 -0
  884. package/src/resources/extensions/async-jobs/await-tool.ts +136 -0
  885. package/src/resources/extensions/async-jobs/cancel-job-tool.ts +35 -0
  886. package/src/resources/extensions/async-jobs/extension-manifest.json +13 -0
  887. package/src/resources/extensions/async-jobs/index.ts +153 -0
  888. package/src/resources/extensions/async-jobs/job-manager.ts +242 -0
  889. package/src/resources/extensions/aws-auth/index.ts +144 -0
  890. package/src/resources/extensions/bg-shell/bg-shell-command.ts +219 -0
  891. package/src/resources/extensions/bg-shell/bg-shell-lifecycle.ts +413 -0
  892. package/src/resources/extensions/bg-shell/bg-shell-tool.ts +985 -0
  893. package/src/resources/extensions/bg-shell/extension-manifest.json +14 -0
  894. package/src/resources/extensions/bg-shell/index.ts +54 -0
  895. package/src/resources/extensions/bg-shell/interaction.ts +200 -0
  896. package/src/resources/extensions/bg-shell/output-formatter.ts +262 -0
  897. package/src/resources/extensions/bg-shell/overlay.ts +441 -0
  898. package/src/resources/extensions/bg-shell/process-manager.ts +469 -0
  899. package/src/resources/extensions/bg-shell/readiness-detector.ts +126 -0
  900. package/src/resources/extensions/bg-shell/types.ts +291 -0
  901. package/src/resources/extensions/bg-shell/utilities.ts +93 -0
  902. package/src/resources/extensions/browser-tools/BROWSER-TOOLS-V2-PROPOSAL.md +1277 -0
  903. package/src/resources/extensions/browser-tools/capture.ts +229 -0
  904. package/src/resources/extensions/browser-tools/core.ts +1196 -0
  905. package/src/resources/extensions/browser-tools/evaluate-helpers.ts +184 -0
  906. package/src/resources/extensions/browser-tools/extension-manifest.json +37 -0
  907. package/src/resources/extensions/browser-tools/index.ts +163 -0
  908. package/src/resources/extensions/browser-tools/lifecycle.ts +270 -0
  909. package/src/resources/extensions/browser-tools/package.json +24 -0
  910. package/src/resources/extensions/browser-tools/refs.ts +264 -0
  911. package/src/resources/extensions/browser-tools/settle.ts +197 -0
  912. package/src/resources/extensions/browser-tools/state.ts +408 -0
  913. package/src/resources/extensions/browser-tools/tests/browser-tools-integration.test.mjs +601 -0
  914. package/src/resources/extensions/browser-tools/tests/browser-tools-unit.test.cjs +651 -0
  915. package/src/resources/extensions/browser-tools/tests/capture-sharp-optional.test.cjs +91 -0
  916. package/src/resources/extensions/browser-tools/tools/action-cache.ts +216 -0
  917. package/src/resources/extensions/browser-tools/tools/assertions.ts +342 -0
  918. package/src/resources/extensions/browser-tools/tools/codegen.ts +274 -0
  919. package/src/resources/extensions/browser-tools/tools/device.ts +183 -0
  920. package/src/resources/extensions/browser-tools/tools/extract.ts +229 -0
  921. package/src/resources/extensions/browser-tools/tools/forms.ts +805 -0
  922. package/src/resources/extensions/browser-tools/tools/injection-detect.ts +221 -0
  923. package/src/resources/extensions/browser-tools/tools/inspection.ts +492 -0
  924. package/src/resources/extensions/browser-tools/tools/intent.ts +629 -0
  925. package/src/resources/extensions/browser-tools/tools/interaction.ts +865 -0
  926. package/src/resources/extensions/browser-tools/tools/navigation.ts +232 -0
  927. package/src/resources/extensions/browser-tools/tools/network-mock.ts +244 -0
  928. package/src/resources/extensions/browser-tools/tools/pages.ts +303 -0
  929. package/src/resources/extensions/browser-tools/tools/pdf.ts +92 -0
  930. package/src/resources/extensions/browser-tools/tools/refs.ts +541 -0
  931. package/src/resources/extensions/browser-tools/tools/screenshot.ts +102 -0
  932. package/src/resources/extensions/browser-tools/tools/session.ts +400 -0
  933. package/src/resources/extensions/browser-tools/tools/state-persistence.ts +202 -0
  934. package/src/resources/extensions/browser-tools/tools/verify.ts +117 -0
  935. package/src/resources/extensions/browser-tools/tools/visual-diff.ts +209 -0
  936. package/src/resources/extensions/browser-tools/tools/wait.ts +247 -0
  937. package/src/resources/extensions/browser-tools/tools/zoom.ts +105 -0
  938. package/src/resources/extensions/browser-tools/utils.ts +660 -0
  939. package/src/resources/extensions/claude-code-cli/index.ts +28 -0
  940. package/src/resources/extensions/claude-code-cli/models.ts +51 -0
  941. package/src/resources/extensions/claude-code-cli/package.json +11 -0
  942. package/src/resources/extensions/claude-code-cli/partial-builder.ts +305 -0
  943. package/src/resources/extensions/claude-code-cli/readiness.ts +242 -0
  944. package/src/resources/extensions/claude-code-cli/sdk-types.ts +149 -0
  945. package/src/resources/extensions/claude-code-cli/stream-adapter.ts +1981 -0
  946. package/src/resources/extensions/claude-code-cli/tests/partial-builder.test.ts +256 -0
  947. package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +2380 -0
  948. package/src/resources/extensions/cmux/index.ts +479 -0
  949. package/src/resources/extensions/cmux/package.json +7 -0
  950. package/src/resources/extensions/context7/extension-manifest.json +12 -0
  951. package/src/resources/extensions/context7/index.ts +435 -0
  952. package/src/resources/extensions/context7/package.json +11 -0
  953. package/src/resources/extensions/get-secrets-from-user.ts +608 -0
  954. package/src/resources/extensions/github-sync/cli.ts +367 -0
  955. package/src/resources/extensions/github-sync/index.ts +93 -0
  956. package/src/resources/extensions/github-sync/mapping.ts +81 -0
  957. package/src/resources/extensions/github-sync/sync.ts +594 -0
  958. package/src/resources/extensions/github-sync/templates.ts +339 -0
  959. package/src/resources/extensions/github-sync/tests/cli.test.ts +89 -0
  960. package/src/resources/extensions/github-sync/tests/commit-linking.test.ts +43 -0
  961. package/src/resources/extensions/github-sync/tests/inline-code.test.ts +66 -0
  962. package/src/resources/extensions/github-sync/tests/mapping.test.ts +104 -0
  963. package/src/resources/extensions/github-sync/tests/sync-source.test.ts +14 -0
  964. package/src/resources/extensions/github-sync/tests/templates.test.ts +209 -0
  965. package/src/resources/extensions/github-sync/types.ts +47 -0
  966. package/src/resources/extensions/google-search/extension-manifest.json +13 -0
  967. package/src/resources/extensions/google-search/index.ts +6 -0
  968. package/src/resources/extensions/google-search/package.json +9 -0
  969. package/src/resources/extensions/gsd/abandon-detect.ts +62 -0
  970. package/src/resources/extensions/gsd/activity-log.ts +184 -0
  971. package/src/resources/extensions/gsd/atomic-write.ts +185 -0
  972. package/src/resources/extensions/gsd/auto/contracts.ts +159 -0
  973. package/src/resources/extensions/gsd/auto/custom-verify-retry-store.ts +72 -0
  974. package/src/resources/extensions/gsd/auto/detect-stuck.ts +138 -0
  975. package/src/resources/extensions/gsd/auto/finalize-timeout.ts +49 -0
  976. package/src/resources/extensions/gsd/auto/infra-errors.ts +92 -0
  977. package/src/resources/extensions/gsd/auto/lease-conflict-notice.ts +62 -0
  978. package/src/resources/extensions/gsd/auto/loop-deps.ts +302 -0
  979. package/src/resources/extensions/gsd/auto/loop.ts +1448 -0
  980. package/src/resources/extensions/gsd/auto/orchestrator.ts +417 -0
  981. package/src/resources/extensions/gsd/auto/phases.ts +3014 -0
  982. package/src/resources/extensions/gsd/auto/resolve.ts +176 -0
  983. package/src/resources/extensions/gsd/auto/run-unit.ts +306 -0
  984. package/src/resources/extensions/gsd/auto/session.ts +427 -0
  985. package/src/resources/extensions/gsd/auto/turn-epoch.ts +108 -0
  986. package/src/resources/extensions/gsd/auto/types.ts +130 -0
  987. package/src/resources/extensions/gsd/auto/unit-runner-events.ts +19 -0
  988. package/src/resources/extensions/gsd/auto/verification-retry-policy.ts +82 -0
  989. package/src/resources/extensions/gsd/auto/workflow-custom-engine-dispatch-outcome.ts +28 -0
  990. package/src/resources/extensions/gsd/auto/workflow-custom-engine-iteration.ts +52 -0
  991. package/src/resources/extensions/gsd/auto/workflow-custom-engine-reconcile-outcome.ts +58 -0
  992. package/src/resources/extensions/gsd/auto/workflow-custom-engine-reconcile.ts +71 -0
  993. package/src/resources/extensions/gsd/auto/workflow-custom-engine-retry.ts +90 -0
  994. package/src/resources/extensions/gsd/auto/workflow-custom-engine-verify-outcome.ts +50 -0
  995. package/src/resources/extensions/gsd/auto/workflow-dispatch-claim.ts +179 -0
  996. package/src/resources/extensions/gsd/auto/workflow-dispatch-ledger.ts +45 -0
  997. package/src/resources/extensions/gsd/auto/workflow-iteration-completion.ts +26 -0
  998. package/src/resources/extensions/gsd/auto/workflow-journal-reporter.ts +33 -0
  999. package/src/resources/extensions/gsd/auto/workflow-kernel.ts +542 -0
  1000. package/src/resources/extensions/gsd/auto/workflow-memory-pressure.ts +71 -0
  1001. package/src/resources/extensions/gsd/auto/workflow-phase-reporter.ts +22 -0
  1002. package/src/resources/extensions/gsd/auto/workflow-session-lock.ts +68 -0
  1003. package/src/resources/extensions/gsd/auto/workflow-sidecar-iteration.ts +46 -0
  1004. package/src/resources/extensions/gsd/auto/workflow-sidecar-queue.ts +46 -0
  1005. package/src/resources/extensions/gsd/auto/workflow-turn-reporter.ts +68 -0
  1006. package/src/resources/extensions/gsd/auto/workflow-unit-dispatch.ts +89 -0
  1007. package/src/resources/extensions/gsd/auto/workflow-worker-heartbeat.ts +51 -0
  1008. package/src/resources/extensions/gsd/auto-artifact-paths.ts +218 -0
  1009. package/src/resources/extensions/gsd/auto-budget.ts +57 -0
  1010. package/src/resources/extensions/gsd/auto-dashboard.ts +1239 -0
  1011. package/src/resources/extensions/gsd/auto-direct-dispatch.ts +311 -0
  1012. package/src/resources/extensions/gsd/auto-dispatch.ts +1827 -0
  1013. package/src/resources/extensions/gsd/auto-model-selection.ts +755 -0
  1014. package/src/resources/extensions/gsd/auto-post-unit.ts +2375 -0
  1015. package/src/resources/extensions/gsd/auto-prompts.ts +4108 -0
  1016. package/src/resources/extensions/gsd/auto-recovery.ts +1217 -0
  1017. package/src/resources/extensions/gsd/auto-runtime-state.ts +63 -0
  1018. package/src/resources/extensions/gsd/auto-start.ts +1561 -0
  1019. package/src/resources/extensions/gsd/auto-status-message.ts +45 -0
  1020. package/src/resources/extensions/gsd/auto-supervisor.ts +86 -0
  1021. package/src/resources/extensions/gsd/auto-timeout-recovery.ts +308 -0
  1022. package/src/resources/extensions/gsd/auto-timers.ts +366 -0
  1023. package/src/resources/extensions/gsd/auto-tool-tracking.ts +156 -0
  1024. package/src/resources/extensions/gsd/auto-unit-closeout.ts +138 -0
  1025. package/src/resources/extensions/gsd/auto-utils.ts +25 -0
  1026. package/src/resources/extensions/gsd/auto-verification.ts +955 -0
  1027. package/src/resources/extensions/gsd/auto-worktree-repair.ts +194 -0
  1028. package/src/resources/extensions/gsd/auto-worktree.ts +2570 -0
  1029. package/src/resources/extensions/gsd/auto.ts +3167 -0
  1030. package/src/resources/extensions/gsd/blocked-models.ts +98 -0
  1031. package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +685 -0
  1032. package/src/resources/extensions/gsd/bootstrap/crash-log.ts +32 -0
  1033. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +1408 -0
  1034. package/src/resources/extensions/gsd/bootstrap/dynamic-tools.ts +144 -0
  1035. package/src/resources/extensions/gsd/bootstrap/exec-tools.ts +123 -0
  1036. package/src/resources/extensions/gsd/bootstrap/journal-tools.ts +67 -0
  1037. package/src/resources/extensions/gsd/bootstrap/memory-tools.ts +166 -0
  1038. package/src/resources/extensions/gsd/bootstrap/notify-interceptor.ts +34 -0
  1039. package/src/resources/extensions/gsd/bootstrap/provider-error-resume.ts +61 -0
  1040. package/src/resources/extensions/gsd/bootstrap/query-tools.ts +68 -0
  1041. package/src/resources/extensions/gsd/bootstrap/register-extension.ts +154 -0
  1042. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +1203 -0
  1043. package/src/resources/extensions/gsd/bootstrap/register-shortcuts.ts +101 -0
  1044. package/src/resources/extensions/gsd/bootstrap/sanitize-complete-milestone.ts +61 -0
  1045. package/src/resources/extensions/gsd/bootstrap/subagent-input.ts +32 -0
  1046. package/src/resources/extensions/gsd/bootstrap/system-context.ts +770 -0
  1047. package/src/resources/extensions/gsd/bootstrap/tests/write-gate-basepath.test.ts +103 -0
  1048. package/src/resources/extensions/gsd/bootstrap/tests/write-gate-shouldblock-basepath.test.ts +97 -0
  1049. package/src/resources/extensions/gsd/bootstrap/tool-call-loop-guard.ts +103 -0
  1050. package/src/resources/extensions/gsd/bootstrap/write-gate.ts +1059 -0
  1051. package/src/resources/extensions/gsd/branch-patterns.ts +16 -0
  1052. package/src/resources/extensions/gsd/browser-evidence.ts +29 -0
  1053. package/src/resources/extensions/gsd/cache.ts +40 -0
  1054. package/src/resources/extensions/gsd/captures.ts +571 -0
  1055. package/src/resources/extensions/gsd/changelog.ts +213 -0
  1056. package/src/resources/extensions/gsd/claude-import.ts +705 -0
  1057. package/src/resources/extensions/gsd/clean-root-preflight.ts +564 -0
  1058. package/src/resources/extensions/gsd/closeout-recovery.ts +290 -0
  1059. package/src/resources/extensions/gsd/codebase-generator.ts +616 -0
  1060. package/src/resources/extensions/gsd/collision-diagnostics.ts +332 -0
  1061. package/src/resources/extensions/gsd/commands/catalog.ts +577 -0
  1062. package/src/resources/extensions/gsd/commands/context.ts +159 -0
  1063. package/src/resources/extensions/gsd/commands/dispatcher.ts +101 -0
  1064. package/src/resources/extensions/gsd/commands/handlers/auto.ts +179 -0
  1065. package/src/resources/extensions/gsd/commands/handlers/core.ts +597 -0
  1066. package/src/resources/extensions/gsd/commands/handlers/escalate.ts +216 -0
  1067. package/src/resources/extensions/gsd/commands/handlers/notifications-handler.ts +144 -0
  1068. package/src/resources/extensions/gsd/commands/handlers/onboarding.ts +196 -0
  1069. package/src/resources/extensions/gsd/commands/handlers/ops.ts +359 -0
  1070. package/src/resources/extensions/gsd/commands/handlers/parallel.ts +147 -0
  1071. package/src/resources/extensions/gsd/commands/handlers/workflow.ts +691 -0
  1072. package/src/resources/extensions/gsd/commands/index.ts +20 -0
  1073. package/src/resources/extensions/gsd/commands-add-tests.ts +137 -0
  1074. package/src/resources/extensions/gsd/commands-backlog.ts +182 -0
  1075. package/src/resources/extensions/gsd/commands-bootstrap.ts +280 -0
  1076. package/src/resources/extensions/gsd/commands-closeout.ts +109 -0
  1077. package/src/resources/extensions/gsd/commands-cmux.ts +182 -0
  1078. package/src/resources/extensions/gsd/commands-codebase.ts +198 -0
  1079. package/src/resources/extensions/gsd/commands-config.ts +119 -0
  1080. package/src/resources/extensions/gsd/commands-debug.ts +510 -0
  1081. package/src/resources/extensions/gsd/commands-do.ts +110 -0
  1082. package/src/resources/extensions/gsd/commands-eval-review.ts +716 -0
  1083. package/src/resources/extensions/gsd/commands-extensions.ts +1088 -0
  1084. package/src/resources/extensions/gsd/commands-extract-learnings.ts +493 -0
  1085. package/src/resources/extensions/gsd/commands-handlers.ts +510 -0
  1086. package/src/resources/extensions/gsd/commands-inspect.ts +99 -0
  1087. package/src/resources/extensions/gsd/commands-logs.ts +537 -0
  1088. package/src/resources/extensions/gsd/commands-maintenance.ts +544 -0
  1089. package/src/resources/extensions/gsd/commands-mcp-status.ts +402 -0
  1090. package/src/resources/extensions/gsd/commands-memory.ts +551 -0
  1091. package/src/resources/extensions/gsd/commands-pr-branch.ts +234 -0
  1092. package/src/resources/extensions/gsd/commands-prefs-wizard.ts +1848 -0
  1093. package/src/resources/extensions/gsd/commands-rate.ts +55 -0
  1094. package/src/resources/extensions/gsd/commands-scan.ts +126 -0
  1095. package/src/resources/extensions/gsd/commands-session-report.ts +101 -0
  1096. package/src/resources/extensions/gsd/commands-ship.ts +292 -0
  1097. package/src/resources/extensions/gsd/commands-verdict.ts +229 -0
  1098. package/src/resources/extensions/gsd/commands-workflow-templates.ts +684 -0
  1099. package/src/resources/extensions/gsd/commands-worktree.ts +383 -0
  1100. package/src/resources/extensions/gsd/commands.ts +17 -0
  1101. package/src/resources/extensions/gsd/compaction-snapshot.ts +165 -0
  1102. package/src/resources/extensions/gsd/complexity-classifier.ts +331 -0
  1103. package/src/resources/extensions/gsd/component-loader.ts +592 -0
  1104. package/src/resources/extensions/gsd/component-types.ts +362 -0
  1105. package/src/resources/extensions/gsd/config-overlay.ts +331 -0
  1106. package/src/resources/extensions/gsd/constants.ts +69 -0
  1107. package/src/resources/extensions/gsd/context-budget.ts +309 -0
  1108. package/src/resources/extensions/gsd/context-injector.ts +100 -0
  1109. package/src/resources/extensions/gsd/context-masker.ts +74 -0
  1110. package/src/resources/extensions/gsd/context-store.ts +497 -0
  1111. package/src/resources/extensions/gsd/crash-recovery.ts +427 -0
  1112. package/src/resources/extensions/gsd/custom-execution-policy.ts +74 -0
  1113. package/src/resources/extensions/gsd/custom-verification.ts +183 -0
  1114. package/src/resources/extensions/gsd/custom-workflow-engine.ts +274 -0
  1115. package/src/resources/extensions/gsd/dashboard-overlay.ts +684 -0
  1116. package/src/resources/extensions/gsd/db/auto-workers.ts +310 -0
  1117. package/src/resources/extensions/gsd/db/command-queue.ts +149 -0
  1118. package/src/resources/extensions/gsd/db/milestone-leases.ts +300 -0
  1119. package/src/resources/extensions/gsd/db/runtime-kv.ts +127 -0
  1120. package/src/resources/extensions/gsd/db/unit-dispatches.ts +554 -0
  1121. package/src/resources/extensions/gsd/db-adapter.ts +75 -0
  1122. package/src/resources/extensions/gsd/db-base-schema.ts +387 -0
  1123. package/src/resources/extensions/gsd/db-connection-cache.ts +45 -0
  1124. package/src/resources/extensions/gsd/db-coordination-schema.ts +109 -0
  1125. package/src/resources/extensions/gsd/db-decision-requirement-rows.ts +77 -0
  1126. package/src/resources/extensions/gsd/db-gate-rows.ts +19 -0
  1127. package/src/resources/extensions/gsd/db-lightweight-query-rows.ts +50 -0
  1128. package/src/resources/extensions/gsd/db-memory-fts-schema.ts +66 -0
  1129. package/src/resources/extensions/gsd/db-migration-backup.ts +34 -0
  1130. package/src/resources/extensions/gsd/db-migration-steps.ts +464 -0
  1131. package/src/resources/extensions/gsd/db-milestone-artifact-rows.ts +70 -0
  1132. package/src/resources/extensions/gsd/db-open-state.ts +47 -0
  1133. package/src/resources/extensions/gsd/db-provider.ts +148 -0
  1134. package/src/resources/extensions/gsd/db-runtime-kv-schema.ts +30 -0
  1135. package/src/resources/extensions/gsd/db-schema-metadata.ts +33 -0
  1136. package/src/resources/extensions/gsd/db-task-slice-rows.ts +150 -0
  1137. package/src/resources/extensions/gsd/db-transaction.ts +76 -0
  1138. package/src/resources/extensions/gsd/db-verification-evidence-rows.ts +14 -0
  1139. package/src/resources/extensions/gsd/db-verification-evidence-schema.ts +22 -0
  1140. package/src/resources/extensions/gsd/db-writer.ts +966 -0
  1141. package/src/resources/extensions/gsd/debug-logger.ts +178 -0
  1142. package/src/resources/extensions/gsd/debug-session-store.ts +377 -0
  1143. package/src/resources/extensions/gsd/deep-project-setup-policy.ts +257 -0
  1144. package/src/resources/extensions/gsd/definition-io.ts +18 -0
  1145. package/src/resources/extensions/gsd/definition-loader.ts +469 -0
  1146. package/src/resources/extensions/gsd/delegation-policy.ts +197 -0
  1147. package/src/resources/extensions/gsd/detection.ts +1339 -0
  1148. package/src/resources/extensions/gsd/dev-execution-policy.ts +51 -0
  1149. package/src/resources/extensions/gsd/dev-workflow-engine.ts +110 -0
  1150. package/src/resources/extensions/gsd/diff-context.ts +214 -0
  1151. package/src/resources/extensions/gsd/dispatch-guard.ts +211 -0
  1152. package/src/resources/extensions/gsd/docs/COORDINATION.md +42 -0
  1153. package/src/resources/extensions/gsd/docs/claude-marketplace-import.md +214 -0
  1154. package/src/resources/extensions/gsd/docs/preferences-reference.md +755 -0
  1155. package/src/resources/extensions/gsd/doctor-checks.ts +5 -0
  1156. package/src/resources/extensions/gsd/doctor-engine-checks.ts +196 -0
  1157. package/src/resources/extensions/gsd/doctor-environment.ts +643 -0
  1158. package/src/resources/extensions/gsd/doctor-format.ts +99 -0
  1159. package/src/resources/extensions/gsd/doctor-git-checks.ts +622 -0
  1160. package/src/resources/extensions/gsd/doctor-global-checks.ts +84 -0
  1161. package/src/resources/extensions/gsd/doctor-proactive.ts +488 -0
  1162. package/src/resources/extensions/gsd/doctor-providers.ts +523 -0
  1163. package/src/resources/extensions/gsd/doctor-runtime-checks.ts +793 -0
  1164. package/src/resources/extensions/gsd/doctor-types.ts +134 -0
  1165. package/src/resources/extensions/gsd/doctor.ts +802 -0
  1166. package/src/resources/extensions/gsd/ecosystem/gsd-extension-api.ts +233 -0
  1167. package/src/resources/extensions/gsd/ecosystem/loader.ts +201 -0
  1168. package/src/resources/extensions/gsd/engine-resolver.ts +57 -0
  1169. package/src/resources/extensions/gsd/engine-types.ts +71 -0
  1170. package/src/resources/extensions/gsd/env-utils.ts +31 -0
  1171. package/src/resources/extensions/gsd/error-classifier.ts +188 -0
  1172. package/src/resources/extensions/gsd/error-utils.ts +6 -0
  1173. package/src/resources/extensions/gsd/errors.ts +29 -0
  1174. package/src/resources/extensions/gsd/escalation.ts +369 -0
  1175. package/src/resources/extensions/gsd/eval-review-schema.ts +243 -0
  1176. package/src/resources/extensions/gsd/exec-history.ts +153 -0
  1177. package/src/resources/extensions/gsd/exec-sandbox.ts +333 -0
  1178. package/src/resources/extensions/gsd/execution-policy.ts +43 -0
  1179. package/src/resources/extensions/gsd/exit-command.ts +30 -0
  1180. package/src/resources/extensions/gsd/export-html.ts +1008 -0
  1181. package/src/resources/extensions/gsd/export.ts +318 -0
  1182. package/src/resources/extensions/gsd/extension-manifest.json +33 -0
  1183. package/src/resources/extensions/gsd/file-lock.ts +132 -0
  1184. package/src/resources/extensions/gsd/files.ts +1009 -0
  1185. package/src/resources/extensions/gsd/forensics.ts +1342 -0
  1186. package/src/resources/extensions/gsd/fresh-run-ui.ts +43 -0
  1187. package/src/resources/extensions/gsd/gate-registry.ts +251 -0
  1188. package/src/resources/extensions/gsd/git-conflict-state.ts +23 -0
  1189. package/src/resources/extensions/gsd/git-constants.ts +41 -0
  1190. package/src/resources/extensions/gsd/git-self-heal.ts +158 -0
  1191. package/src/resources/extensions/gsd/git-service.ts +1412 -0
  1192. package/src/resources/extensions/gsd/gitignore.ts +336 -0
  1193. package/src/resources/extensions/gsd/graph-context.ts +212 -0
  1194. package/src/resources/extensions/gsd/graph.ts +349 -0
  1195. package/src/resources/extensions/gsd/gsd-command-home.ts +209 -0
  1196. package/src/resources/extensions/gsd/gsd-db.ts +3190 -0
  1197. package/src/resources/extensions/gsd/gsd-home.ts +30 -0
  1198. package/src/resources/extensions/gsd/guided-flow-queue.ts +443 -0
  1199. package/src/resources/extensions/gsd/guided-flow.ts +2887 -0
  1200. package/src/resources/extensions/gsd/guided-unit-context.ts +30 -0
  1201. package/src/resources/extensions/gsd/health-widget-core.ts +140 -0
  1202. package/src/resources/extensions/gsd/health-widget.ts +148 -0
  1203. package/src/resources/extensions/gsd/history.ts +144 -0
  1204. package/src/resources/extensions/gsd/hook-emitter.ts +188 -0
  1205. package/src/resources/extensions/gsd/index.ts +37 -0
  1206. package/src/resources/extensions/gsd/init-wizard.ts +704 -0
  1207. package/src/resources/extensions/gsd/interrupted-session.ts +269 -0
  1208. package/src/resources/extensions/gsd/journal.ts +218 -0
  1209. package/src/resources/extensions/gsd/json-persistence.ts +78 -0
  1210. package/src/resources/extensions/gsd/jsonl-utils.ts +21 -0
  1211. package/src/resources/extensions/gsd/key-manager.ts +1018 -0
  1212. package/src/resources/extensions/gsd/knowledge-backfill.ts +164 -0
  1213. package/src/resources/extensions/gsd/knowledge-capture.ts +160 -0
  1214. package/src/resources/extensions/gsd/knowledge-parser.ts +174 -0
  1215. package/src/resources/extensions/gsd/knowledge-projection.ts +241 -0
  1216. package/src/resources/extensions/gsd/legacy-telemetry.ts +99 -0
  1217. package/src/resources/extensions/gsd/markdown-renderer.ts +982 -0
  1218. package/src/resources/extensions/gsd/marketplace-discovery.ts +508 -0
  1219. package/src/resources/extensions/gsd/mcp-filter.ts +80 -0
  1220. package/src/resources/extensions/gsd/mcp-project-config.ts +128 -0
  1221. package/src/resources/extensions/gsd/md-importer.ts +748 -0
  1222. package/src/resources/extensions/gsd/memory-backfill.ts +212 -0
  1223. package/src/resources/extensions/gsd/memory-consolidation-scanner.ts +277 -0
  1224. package/src/resources/extensions/gsd/memory-embeddings.ts +235 -0
  1225. package/src/resources/extensions/gsd/memory-extractor.ts +434 -0
  1226. package/src/resources/extensions/gsd/memory-ingest.ts +286 -0
  1227. package/src/resources/extensions/gsd/memory-relations.ts +240 -0
  1228. package/src/resources/extensions/gsd/memory-source-store.ts +138 -0
  1229. package/src/resources/extensions/gsd/memory-store.ts +909 -0
  1230. package/src/resources/extensions/gsd/metrics.ts +1040 -0
  1231. package/src/resources/extensions/gsd/migrate/audit.ts +219 -0
  1232. package/src/resources/extensions/gsd/migrate/command.ts +341 -0
  1233. package/src/resources/extensions/gsd/migrate/index.ts +44 -0
  1234. package/src/resources/extensions/gsd/migrate/parser.ts +323 -0
  1235. package/src/resources/extensions/gsd/migrate/parsers.ts +676 -0
  1236. package/src/resources/extensions/gsd/migrate/preview.ts +58 -0
  1237. package/src/resources/extensions/gsd/migrate/safety.ts +149 -0
  1238. package/src/resources/extensions/gsd/migrate/transformer.ts +411 -0
  1239. package/src/resources/extensions/gsd/migrate/types.ts +370 -0
  1240. package/src/resources/extensions/gsd/migrate/validator.ts +55 -0
  1241. package/src/resources/extensions/gsd/migrate/writer.ts +592 -0
  1242. package/src/resources/extensions/gsd/migrate-external.ts +215 -0
  1243. package/src/resources/extensions/gsd/migration-auto-check.ts +121 -0
  1244. package/src/resources/extensions/gsd/milestone-actions.ts +193 -0
  1245. package/src/resources/extensions/gsd/milestone-id-reservation.ts +47 -0
  1246. package/src/resources/extensions/gsd/milestone-id-utils.ts +32 -0
  1247. package/src/resources/extensions/gsd/milestone-ids.ts +136 -0
  1248. package/src/resources/extensions/gsd/milestone-scope-classifier.ts +373 -0
  1249. package/src/resources/extensions/gsd/milestone-summary-classifier.ts +42 -0
  1250. package/src/resources/extensions/gsd/milestone-validation-gates.ts +53 -0
  1251. package/src/resources/extensions/gsd/model-cost-table.ts +89 -0
  1252. package/src/resources/extensions/gsd/model-router.ts +844 -0
  1253. package/src/resources/extensions/gsd/namespaced-registry.ts +467 -0
  1254. package/src/resources/extensions/gsd/namespaced-resolver.ts +307 -0
  1255. package/src/resources/extensions/gsd/native-git-bridge.ts +1447 -0
  1256. package/src/resources/extensions/gsd/native-parser-bridge.ts +267 -0
  1257. package/src/resources/extensions/gsd/notification-overlay.ts +322 -0
  1258. package/src/resources/extensions/gsd/notification-store.ts +342 -0
  1259. package/src/resources/extensions/gsd/notification-widget.ts +69 -0
  1260. package/src/resources/extensions/gsd/notifications.ts +153 -0
  1261. package/src/resources/extensions/gsd/observability-validator.ts +456 -0
  1262. package/src/resources/extensions/gsd/onboarding-state.ts +146 -0
  1263. package/src/resources/extensions/gsd/orphan-stash-audit.ts +117 -0
  1264. package/src/resources/extensions/gsd/package.json +11 -0
  1265. package/src/resources/extensions/gsd/parallel-eligibility.ts +248 -0
  1266. package/src/resources/extensions/gsd/parallel-merge.ts +270 -0
  1267. package/src/resources/extensions/gsd/parallel-monitor-overlay.ts +507 -0
  1268. package/src/resources/extensions/gsd/parallel-orchestrator.ts +1077 -0
  1269. package/src/resources/extensions/gsd/parsers-legacy.ts +292 -0
  1270. package/src/resources/extensions/gsd/paths.ts +722 -0
  1271. package/src/resources/extensions/gsd/pending-auto-start.ts +81 -0
  1272. package/src/resources/extensions/gsd/phase-anchor.ts +71 -0
  1273. package/src/resources/extensions/gsd/planning-depth.ts +137 -0
  1274. package/src/resources/extensions/gsd/planning-path-scope.ts +45 -0
  1275. package/src/resources/extensions/gsd/plugin-importer.ts +411 -0
  1276. package/src/resources/extensions/gsd/post-execution-checks.ts +665 -0
  1277. package/src/resources/extensions/gsd/post-unit-hooks.ts +86 -0
  1278. package/src/resources/extensions/gsd/pr-evidence.ts +182 -0
  1279. package/src/resources/extensions/gsd/pre-execution-checks.ts +890 -0
  1280. package/src/resources/extensions/gsd/preferences-mcp.ts +27 -0
  1281. package/src/resources/extensions/gsd/preferences-models.ts +572 -0
  1282. package/src/resources/extensions/gsd/preferences-skills.ts +147 -0
  1283. package/src/resources/extensions/gsd/preferences-types.ts +579 -0
  1284. package/src/resources/extensions/gsd/preferences-validation.ts +1453 -0
  1285. package/src/resources/extensions/gsd/preferences.ts +697 -0
  1286. package/src/resources/extensions/gsd/preparation.ts +1419 -0
  1287. package/src/resources/extensions/gsd/process-task-path.ts +81 -0
  1288. package/src/resources/extensions/gsd/progress-score.ts +161 -0
  1289. package/src/resources/extensions/gsd/project-research-policy.ts +259 -0
  1290. package/src/resources/extensions/gsd/prompt-cache-optimizer.ts +217 -0
  1291. package/src/resources/extensions/gsd/prompt-loader.ts +248 -0
  1292. package/src/resources/extensions/gsd/prompt-ordering.ts +200 -0
  1293. package/src/resources/extensions/gsd/prompt-validation.ts +157 -0
  1294. package/src/resources/extensions/gsd/prompts/add-tests.md +36 -0
  1295. package/src/resources/extensions/gsd/prompts/complete-milestone.md +91 -0
  1296. package/src/resources/extensions/gsd/prompts/complete-slice.md +49 -0
  1297. package/src/resources/extensions/gsd/prompts/debug-diagnose.md +27 -0
  1298. package/src/resources/extensions/gsd/prompts/debug-session-manager.md +80 -0
  1299. package/src/resources/extensions/gsd/prompts/discuss-headless.md +252 -0
  1300. package/src/resources/extensions/gsd/prompts/discuss.md +368 -0
  1301. package/src/resources/extensions/gsd/prompts/doctor-heal.md +31 -0
  1302. package/src/resources/extensions/gsd/prompts/execute-task.md +73 -0
  1303. package/src/resources/extensions/gsd/prompts/forensics.md +155 -0
  1304. package/src/resources/extensions/gsd/prompts/gate-evaluate.md +32 -0
  1305. package/src/resources/extensions/gsd/prompts/guided-discuss-milestone.md +116 -0
  1306. package/src/resources/extensions/gsd/prompts/guided-discuss-project.md +113 -0
  1307. package/src/resources/extensions/gsd/prompts/guided-discuss-requirements.md +99 -0
  1308. package/src/resources/extensions/gsd/prompts/guided-discuss-slice.md +74 -0
  1309. package/src/resources/extensions/gsd/prompts/guided-research-decision.md +70 -0
  1310. package/src/resources/extensions/gsd/prompts/guided-research-project.md +102 -0
  1311. package/src/resources/extensions/gsd/prompts/guided-research-slice.md +15 -0
  1312. package/src/resources/extensions/gsd/prompts/guided-resume-task.md +1 -0
  1313. package/src/resources/extensions/gsd/prompts/guided-workflow-preferences.md +68 -0
  1314. package/src/resources/extensions/gsd/prompts/heal-skill.md +45 -0
  1315. package/src/resources/extensions/gsd/prompts/parallel-research-slices.md +28 -0
  1316. package/src/resources/extensions/gsd/prompts/plan-milestone.md +114 -0
  1317. package/src/resources/extensions/gsd/prompts/plan-slice.md +55 -0
  1318. package/src/resources/extensions/gsd/prompts/queue.md +128 -0
  1319. package/src/resources/extensions/gsd/prompts/quick-task.md +40 -0
  1320. package/src/resources/extensions/gsd/prompts/reactive-execute.md +44 -0
  1321. package/src/resources/extensions/gsd/prompts/reassess-roadmap.md +68 -0
  1322. package/src/resources/extensions/gsd/prompts/refine-slice.md +79 -0
  1323. package/src/resources/extensions/gsd/prompts/replan-slice.md +39 -0
  1324. package/src/resources/extensions/gsd/prompts/research-milestone.md +47 -0
  1325. package/src/resources/extensions/gsd/prompts/research-slice.md +58 -0
  1326. package/src/resources/extensions/gsd/prompts/rethink.md +95 -0
  1327. package/src/resources/extensions/gsd/prompts/review-migration.md +66 -0
  1328. package/src/resources/extensions/gsd/prompts/rewrite-docs.md +33 -0
  1329. package/src/resources/extensions/gsd/prompts/run-uat.md +89 -0
  1330. package/src/resources/extensions/gsd/prompts/scan.md +79 -0
  1331. package/src/resources/extensions/gsd/prompts/system.md +180 -0
  1332. package/src/resources/extensions/gsd/prompts/triage-captures.md +68 -0
  1333. package/src/resources/extensions/gsd/prompts/validate-milestone.md +88 -0
  1334. package/src/resources/extensions/gsd/prompts/workflow-oneshot.md +26 -0
  1335. package/src/resources/extensions/gsd/prompts/workflow-start.md +28 -0
  1336. package/src/resources/extensions/gsd/prompts/worktree-merge.md +125 -0
  1337. package/src/resources/extensions/gsd/provider-error-pause.ts +49 -0
  1338. package/src/resources/extensions/gsd/provider-switch-observer.ts +185 -0
  1339. package/src/resources/extensions/gsd/python-resolver.ts +76 -0
  1340. package/src/resources/extensions/gsd/queue-order.ts +235 -0
  1341. package/src/resources/extensions/gsd/queue-reorder-ui.ts +295 -0
  1342. package/src/resources/extensions/gsd/quick.ts +297 -0
  1343. package/src/resources/extensions/gsd/reactive-graph.ts +337 -0
  1344. package/src/resources/extensions/gsd/recovery-classification.ts +139 -0
  1345. package/src/resources/extensions/gsd/repo-identity.ts +683 -0
  1346. package/src/resources/extensions/gsd/reports.ts +505 -0
  1347. package/src/resources/extensions/gsd/repository-registry.ts +108 -0
  1348. package/src/resources/extensions/gsd/rethink.ts +164 -0
  1349. package/src/resources/extensions/gsd/roadmap-mutations.ts +134 -0
  1350. package/src/resources/extensions/gsd/roadmap-slices.ts +294 -0
  1351. package/src/resources/extensions/gsd/root-write-leak-guard.ts +101 -0
  1352. package/src/resources/extensions/gsd/routing-history.ts +286 -0
  1353. package/src/resources/extensions/gsd/rule-registry.ts +599 -0
  1354. package/src/resources/extensions/gsd/rule-types.ts +68 -0
  1355. package/src/resources/extensions/gsd/run-manager.ts +214 -0
  1356. package/src/resources/extensions/gsd/safe-fs.ts +48 -0
  1357. package/src/resources/extensions/gsd/safety/content-validator.ts +98 -0
  1358. package/src/resources/extensions/gsd/safety/destructive-guard.ts +49 -0
  1359. package/src/resources/extensions/gsd/safety/evidence-collector.ts +265 -0
  1360. package/src/resources/extensions/gsd/safety/evidence-cross-ref.ts +155 -0
  1361. package/src/resources/extensions/gsd/safety/file-change-validator.ts +124 -0
  1362. package/src/resources/extensions/gsd/safety/git-checkpoint.ts +130 -0
  1363. package/src/resources/extensions/gsd/safety/safety-harness.ts +114 -0
  1364. package/src/resources/extensions/gsd/schemas/__fixtures__/valid-project.md +26 -0
  1365. package/src/resources/extensions/gsd/schemas/__fixtures__/valid-requirements.md +57 -0
  1366. package/src/resources/extensions/gsd/schemas/__fixtures__/valid-roadmap.md +19 -0
  1367. package/src/resources/extensions/gsd/schemas/parsers.ts +346 -0
  1368. package/src/resources/extensions/gsd/schemas/validate.ts +452 -0
  1369. package/src/resources/extensions/gsd/service-tier.ts +199 -0
  1370. package/src/resources/extensions/gsd/session-forensics.ts +580 -0
  1371. package/src/resources/extensions/gsd/session-lock.ts +732 -0
  1372. package/src/resources/extensions/gsd/session-model-override.ts +36 -0
  1373. package/src/resources/extensions/gsd/session-status-io.ts +179 -0
  1374. package/src/resources/extensions/gsd/setup-catalog.ts +105 -0
  1375. package/src/resources/extensions/gsd/shortcut-defs.ts +56 -0
  1376. package/src/resources/extensions/gsd/skill-catalog.ts +1088 -0
  1377. package/src/resources/extensions/gsd/skill-discovery.ts +157 -0
  1378. package/src/resources/extensions/gsd/skill-health.ts +422 -0
  1379. package/src/resources/extensions/gsd/skill-manifest.ts +175 -0
  1380. package/src/resources/extensions/gsd/skill-telemetry.ts +141 -0
  1381. package/src/resources/extensions/gsd/skills/gsd-headless/SKILL.md +242 -0
  1382. package/src/resources/extensions/gsd/skills/gsd-headless/references/answer-injection.md +83 -0
  1383. package/src/resources/extensions/gsd/skills/gsd-headless/references/commands.md +64 -0
  1384. package/src/resources/extensions/gsd/skills/gsd-headless/references/multi-session.md +176 -0
  1385. package/src/resources/extensions/gsd/slice-cadence.ts +411 -0
  1386. package/src/resources/extensions/gsd/slice-parallel-conflict.ts +86 -0
  1387. package/src/resources/extensions/gsd/slice-parallel-eligibility.ts +73 -0
  1388. package/src/resources/extensions/gsd/slice-parallel-orchestrator.ts +913 -0
  1389. package/src/resources/extensions/gsd/smart-entry-routing.ts +77 -0
  1390. package/src/resources/extensions/gsd/state-reconciliation/drift/completion.ts +172 -0
  1391. package/src/resources/extensions/gsd/state-reconciliation/drift/merge-state.ts +417 -0
  1392. package/src/resources/extensions/gsd/state-reconciliation/drift/project-md.ts +66 -0
  1393. package/src/resources/extensions/gsd/state-reconciliation/drift/roadmap.ts +101 -0
  1394. package/src/resources/extensions/gsd/state-reconciliation/drift/sketch-flag.ts +68 -0
  1395. package/src/resources/extensions/gsd/state-reconciliation/drift/stale-render.ts +185 -0
  1396. package/src/resources/extensions/gsd/state-reconciliation/drift/stale-worker.ts +46 -0
  1397. package/src/resources/extensions/gsd/state-reconciliation/errors.ts +67 -0
  1398. package/src/resources/extensions/gsd/state-reconciliation/index.ts +142 -0
  1399. package/src/resources/extensions/gsd/state-reconciliation/registry.ts +27 -0
  1400. package/src/resources/extensions/gsd/state-reconciliation/spawn-gate.ts +65 -0
  1401. package/src/resources/extensions/gsd/state-reconciliation/types.ts +83 -0
  1402. package/src/resources/extensions/gsd/state-reconciliation.ts +25 -0
  1403. package/src/resources/extensions/gsd/state-transition-matrix.ts +152 -0
  1404. package/src/resources/extensions/gsd/state.ts +1730 -0
  1405. package/src/resources/extensions/gsd/status-guards.ts +41 -0
  1406. package/src/resources/extensions/gsd/structured-data-formatter.ts +146 -0
  1407. package/src/resources/extensions/gsd/sync-lock.ts +152 -0
  1408. package/src/resources/extensions/gsd/templates/PREFERENCES.md +101 -0
  1409. package/src/resources/extensions/gsd/templates/context.md +108 -0
  1410. package/src/resources/extensions/gsd/templates/decisions.md +8 -0
  1411. package/src/resources/extensions/gsd/templates/knowledge.md +19 -0
  1412. package/src/resources/extensions/gsd/templates/milestone-summary.md +81 -0
  1413. package/src/resources/extensions/gsd/templates/milestone-validation.md +74 -0
  1414. package/src/resources/extensions/gsd/templates/plan.md +152 -0
  1415. package/src/resources/extensions/gsd/templates/project.md +41 -0
  1416. package/src/resources/extensions/gsd/templates/reassessment.md +29 -0
  1417. package/src/resources/extensions/gsd/templates/requirements.md +81 -0
  1418. package/src/resources/extensions/gsd/templates/research.md +79 -0
  1419. package/src/resources/extensions/gsd/templates/roadmap.md +131 -0
  1420. package/src/resources/extensions/gsd/templates/runtime.md +21 -0
  1421. package/src/resources/extensions/gsd/templates/secrets-manifest.md +22 -0
  1422. package/src/resources/extensions/gsd/templates/slice-context.md +58 -0
  1423. package/src/resources/extensions/gsd/templates/slice-summary.md +108 -0
  1424. package/src/resources/extensions/gsd/templates/state.md +17 -0
  1425. package/src/resources/extensions/gsd/templates/task-plan.md +95 -0
  1426. package/src/resources/extensions/gsd/templates/task-summary.md +66 -0
  1427. package/src/resources/extensions/gsd/templates/uat.md +54 -0
  1428. package/src/resources/extensions/gsd/tests/active-milestone-id-guard.test.ts +91 -0
  1429. package/src/resources/extensions/gsd/tests/activity-log.test.ts +175 -0
  1430. package/src/resources/extensions/gsd/tests/agent-end-retry.test.ts +80 -0
  1431. package/src/resources/extensions/gsd/tests/artifact-corruption-2630.test.ts +296 -0
  1432. package/src/resources/extensions/gsd/tests/artifact-retry-cap.test.ts +145 -0
  1433. package/src/resources/extensions/gsd/tests/artifact-validators.test.ts +524 -0
  1434. package/src/resources/extensions/gsd/tests/artifacts-table-preserved-on-cache-invalidate.test.ts +143 -0
  1435. package/src/resources/extensions/gsd/tests/ask-user-questions-dedup.test.ts +120 -0
  1436. package/src/resources/extensions/gsd/tests/atomic-write.test.ts +144 -0
  1437. package/src/resources/extensions/gsd/tests/auto-abort-pause-regression.test.ts +47 -0
  1438. package/src/resources/extensions/gsd/tests/auto-blocked-remediation-message.test.ts +89 -0
  1439. package/src/resources/extensions/gsd/tests/auto-budget-alerts.test.ts +62 -0
  1440. package/src/resources/extensions/gsd/tests/auto-dashboard.test.ts +807 -0
  1441. package/src/resources/extensions/gsd/tests/auto-deterministic-error-classification-4973.test.ts +457 -0
  1442. package/src/resources/extensions/gsd/tests/auto-discuss-milestone-deadlock-4973.test.ts +289 -0
  1443. package/src/resources/extensions/gsd/tests/auto-loop-no-copy-artifacts.test.ts +72 -0
  1444. package/src/resources/extensions/gsd/tests/auto-loop-symlink-worktree.test.ts +190 -0
  1445. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +5503 -0
  1446. package/src/resources/extensions/gsd/tests/auto-migrating-recovery.test.ts +63 -0
  1447. package/src/resources/extensions/gsd/tests/auto-milestone-target.test.ts +61 -0
  1448. package/src/resources/extensions/gsd/tests/auto-mode-guards.test.ts +79 -0
  1449. package/src/resources/extensions/gsd/tests/auto-mode-interactive-guard.test.ts +71 -0
  1450. package/src/resources/extensions/gsd/tests/auto-model-selection-tool-poisoning.test.ts +742 -0
  1451. package/src/resources/extensions/gsd/tests/auto-model-selection.test.ts +479 -0
  1452. package/src/resources/extensions/gsd/tests/auto-orchestrator.test.ts +1300 -0
  1453. package/src/resources/extensions/gsd/tests/auto-pause-double-entry-guard.test.ts +76 -0
  1454. package/src/resources/extensions/gsd/tests/auto-paused-session-validation.test.ts +103 -0
  1455. package/src/resources/extensions/gsd/tests/auto-paused-ui-cleanup.test.ts +759 -0
  1456. package/src/resources/extensions/gsd/tests/auto-phases-lifecycle.test.ts +390 -0
  1457. package/src/resources/extensions/gsd/tests/auto-post-unit-artifact-diagnostic.test.ts +32 -0
  1458. package/src/resources/extensions/gsd/tests/auto-post-unit-evidence-crossref-4909.test.ts +60 -0
  1459. package/src/resources/extensions/gsd/tests/auto-post-unit-step-message.test.ts +218 -0
  1460. package/src/resources/extensions/gsd/tests/auto-pr-bugs.test.ts +66 -0
  1461. package/src/resources/extensions/gsd/tests/auto-project-root-env.test.ts +74 -0
  1462. package/src/resources/extensions/gsd/tests/auto-prompts-fallback.test.ts +35 -0
  1463. package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +1773 -0
  1464. package/src/resources/extensions/gsd/tests/auto-remediate-slice-status.test.ts +48 -0
  1465. package/src/resources/extensions/gsd/tests/auto-remote-session-lock-cleanup.test.ts +64 -0
  1466. package/src/resources/extensions/gsd/tests/auto-retry-mcp-churn-fixes.test.ts +98 -0
  1467. package/src/resources/extensions/gsd/tests/auto-runtime-state.test.ts +59 -0
  1468. package/src/resources/extensions/gsd/tests/auto-session-encapsulation.test.ts +277 -0
  1469. package/src/resources/extensions/gsd/tests/auto-session-scope.test.ts +348 -0
  1470. package/src/resources/extensions/gsd/tests/auto-start-bootstrap-await-3420.test.ts +45 -0
  1471. package/src/resources/extensions/gsd/tests/auto-start-clean-runtime-db-gated.test.ts +61 -0
  1472. package/src/resources/extensions/gsd/tests/auto-start-cold-db-bootstrap.test.ts +27 -0
  1473. package/src/resources/extensions/gsd/tests/auto-start-index-lock.test.ts +26 -0
  1474. package/src/resources/extensions/gsd/tests/auto-start-needs-discussion.test.ts +175 -0
  1475. package/src/resources/extensions/gsd/tests/auto-start-orphan-bootstrap.test.ts +161 -0
  1476. package/src/resources/extensions/gsd/tests/auto-start-project-milestone-reconcile.test.ts +49 -0
  1477. package/src/resources/extensions/gsd/tests/auto-start-time-persistence.test.ts +32 -0
  1478. package/src/resources/extensions/gsd/tests/auto-start-validation-block.test.ts +52 -0
  1479. package/src/resources/extensions/gsd/tests/auto-start-worktree-db-path.test.ts +19 -0
  1480. package/src/resources/extensions/gsd/tests/auto-status-message.test.ts +46 -0
  1481. package/src/resources/extensions/gsd/tests/auto-stop-notification.test.ts +31 -0
  1482. package/src/resources/extensions/gsd/tests/auto-supervisor.test.mjs +70 -0
  1483. package/src/resources/extensions/gsd/tests/auto-thinking-restore.test.ts +54 -0
  1484. package/src/resources/extensions/gsd/tests/auto-unit-closeout.test.ts +68 -0
  1485. package/src/resources/extensions/gsd/tests/auto-warning-noise-regression.test.ts +106 -0
  1486. package/src/resources/extensions/gsd/tests/auto-workers.test.ts +134 -0
  1487. package/src/resources/extensions/gsd/tests/auto-worktree-auto-resolve.test.ts +80 -0
  1488. package/src/resources/extensions/gsd/tests/auto-worktree-registry.test.ts +244 -0
  1489. package/src/resources/extensions/gsd/tests/auto-worktree-repair.test.ts +199 -0
  1490. package/src/resources/extensions/gsd/tests/auto-wrapup-inflight-guard.test.ts +171 -0
  1491. package/src/resources/extensions/gsd/tests/autocomplete-regressions-1675.test.ts +143 -0
  1492. package/src/resources/extensions/gsd/tests/block-db-writes.test.ts +63 -0
  1493. package/src/resources/extensions/gsd/tests/blocked-models.test.ts +98 -0
  1494. package/src/resources/extensions/gsd/tests/bootstrap-derive-state-db-open.test.ts +23 -0
  1495. package/src/resources/extensions/gsd/tests/brief-command.test.ts +89 -0
  1496. package/src/resources/extensions/gsd/tests/browser-teardown.test.ts +92 -0
  1497. package/src/resources/extensions/gsd/tests/browser-tools-compatibility-declarations.test.ts +62 -0
  1498. package/src/resources/extensions/gsd/tests/budget-prediction.test.ts +147 -0
  1499. package/src/resources/extensions/gsd/tests/bundled-skill-triggers.test.ts +77 -0
  1500. package/src/resources/extensions/gsd/tests/bundled-workflow-defs.test.ts +180 -0
  1501. package/src/resources/extensions/gsd/tests/cache-staleness-regression.test.ts +290 -0
  1502. package/src/resources/extensions/gsd/tests/canonical-milestone-root.test.ts +108 -0
  1503. package/src/resources/extensions/gsd/tests/capability-router.test.ts +371 -0
  1504. package/src/resources/extensions/gsd/tests/captures.test.ts +524 -0
  1505. package/src/resources/extensions/gsd/tests/check-auto-start-pending-gate.test.ts +203 -0
  1506. package/src/resources/extensions/gsd/tests/check-auto-start-ready-guard.test.ts +148 -0
  1507. package/src/resources/extensions/gsd/tests/checkout-branch-stash-guard.test.ts +87 -0
  1508. package/src/resources/extensions/gsd/tests/claude-import-marketplace-discovery.test.ts +191 -0
  1509. package/src/resources/extensions/gsd/tests/claude-import-tui.test.ts +350 -0
  1510. package/src/resources/extensions/gsd/tests/claude-skill-dirs.test.ts +51 -0
  1511. package/src/resources/extensions/gsd/tests/clean-root-preflight.test.ts +509 -0
  1512. package/src/resources/extensions/gsd/tests/clear-stale-autostart.test.ts +76 -0
  1513. package/src/resources/extensions/gsd/tests/cli-provider-rate-limit.test.ts +47 -0
  1514. package/src/resources/extensions/gsd/tests/closeout-git-deferral.test.ts +16 -0
  1515. package/src/resources/extensions/gsd/tests/closeout-recovery.test.ts +101 -0
  1516. package/src/resources/extensions/gsd/tests/cmux.test.ts +333 -0
  1517. package/src/resources/extensions/gsd/tests/codebase-generator.test.ts +669 -0
  1518. package/src/resources/extensions/gsd/tests/cold-resume-db-reopen.test.ts +43 -0
  1519. package/src/resources/extensions/gsd/tests/collect-from-manifest.test.ts +506 -0
  1520. package/src/resources/extensions/gsd/tests/collision-diagnostics.test.ts +705 -0
  1521. package/src/resources/extensions/gsd/tests/command-queue.test.ts +141 -0
  1522. package/src/resources/extensions/gsd/tests/commands-backlog.test.ts +158 -0
  1523. package/src/resources/extensions/gsd/tests/commands-config.test.ts +31 -0
  1524. package/src/resources/extensions/gsd/tests/commands-dispatcher-unmerged-milestone.test.ts +188 -0
  1525. package/src/resources/extensions/gsd/tests/commands-dispatcher-validation-block.test.ts +178 -0
  1526. package/src/resources/extensions/gsd/tests/commands-do.test.ts +175 -0
  1527. package/src/resources/extensions/gsd/tests/commands-eval-review.test.ts +612 -0
  1528. package/src/resources/extensions/gsd/tests/commands-extensions-version-compare.test.ts +58 -0
  1529. package/src/resources/extensions/gsd/tests/commands-extract-learnings.test.ts +663 -0
  1530. package/src/resources/extensions/gsd/tests/commands-inspect-open-db.test.ts +46 -0
  1531. package/src/resources/extensions/gsd/tests/commands-logs.test.ts +241 -0
  1532. package/src/resources/extensions/gsd/tests/commands-pr-branch.test.ts +68 -0
  1533. package/src/resources/extensions/gsd/tests/commands-scan.test.ts +351 -0
  1534. package/src/resources/extensions/gsd/tests/commands-session-report.test.ts +82 -0
  1535. package/src/resources/extensions/gsd/tests/commands-ship-eval-warn.test.ts +156 -0
  1536. package/src/resources/extensions/gsd/tests/commands-ship.test.ts +71 -0
  1537. package/src/resources/extensions/gsd/tests/commands-verdict.test.ts +439 -0
  1538. package/src/resources/extensions/gsd/tests/commands-workflow-custom.test.ts +311 -0
  1539. package/src/resources/extensions/gsd/tests/commands-worktree-clean.test.ts +48 -0
  1540. package/src/resources/extensions/gsd/tests/compaction-snapshot.test.ts +136 -0
  1541. package/src/resources/extensions/gsd/tests/complete-milestone-excerpt.test.ts +366 -0
  1542. package/src/resources/extensions/gsd/tests/complete-milestone-prompt-rendering.test.ts +47 -0
  1543. package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +743 -0
  1544. package/src/resources/extensions/gsd/tests/complete-slice-composer.test.ts +193 -0
  1545. package/src/resources/extensions/gsd/tests/complete-slice-gate-closure.test.ts +167 -0
  1546. package/src/resources/extensions/gsd/tests/complete-slice-prompt-task-summary-layout.test.ts +18 -0
  1547. package/src/resources/extensions/gsd/tests/complete-slice-string-coercion.test.ts +247 -0
  1548. package/src/resources/extensions/gsd/tests/complete-slice-verification-gate.test.ts +156 -0
  1549. package/src/resources/extensions/gsd/tests/complete-slice.test.ts +556 -0
  1550. package/src/resources/extensions/gsd/tests/complete-task-normalize-lists.test.ts +50 -0
  1551. package/src/resources/extensions/gsd/tests/complete-task-rollback-evidence.test.ts +105 -0
  1552. package/src/resources/extensions/gsd/tests/complete-task.test.ts +513 -0
  1553. package/src/resources/extensions/gsd/tests/completed-at-reconcile.test.ts +84 -0
  1554. package/src/resources/extensions/gsd/tests/completed-units-metrics-sync.test.ts +61 -0
  1555. package/src/resources/extensions/gsd/tests/completion-hierarchy-guards.test.ts +192 -0
  1556. package/src/resources/extensions/gsd/tests/complexity-classifier.test.ts +206 -0
  1557. package/src/resources/extensions/gsd/tests/component-loader.test.ts +582 -0
  1558. package/src/resources/extensions/gsd/tests/component-types.test.ts +127 -0
  1559. package/src/resources/extensions/gsd/tests/context-budget.test.ts +389 -0
  1560. package/src/resources/extensions/gsd/tests/context-injector.test.ts +313 -0
  1561. package/src/resources/extensions/gsd/tests/context-masker.test.ts +122 -0
  1562. package/src/resources/extensions/gsd/tests/context-store-decisions-from-memories.test.ts +312 -0
  1563. package/src/resources/extensions/gsd/tests/context-store.test.ts +715 -0
  1564. package/src/resources/extensions/gsd/tests/core-overlay-fallback.test.ts +185 -0
  1565. package/src/resources/extensions/gsd/tests/cost-projection.test.ts +120 -0
  1566. package/src/resources/extensions/gsd/tests/crash-handler-secondary.test.ts +294 -0
  1567. package/src/resources/extensions/gsd/tests/crash-recovery-via-db.test.ts +331 -0
  1568. package/src/resources/extensions/gsd/tests/crash-recovery.test.ts +709 -0
  1569. package/src/resources/extensions/gsd/tests/current-directory-root-homedir-fallback.test.ts +63 -0
  1570. package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +902 -0
  1571. package/src/resources/extensions/gsd/tests/custom-verification.test.ts +415 -0
  1572. package/src/resources/extensions/gsd/tests/custom-verify-retry-store.test.ts +139 -0
  1573. package/src/resources/extensions/gsd/tests/custom-workflow-engine.test.ts +483 -0
  1574. package/src/resources/extensions/gsd/tests/cwd-fallback-hardening.test.ts +138 -0
  1575. package/src/resources/extensions/gsd/tests/dashboard-budget.test.ts +360 -0
  1576. package/src/resources/extensions/gsd/tests/dashboard-custom-engine.test.ts +23 -0
  1577. package/src/resources/extensions/gsd/tests/db-access-guardrails.test.ts +110 -0
  1578. package/src/resources/extensions/gsd/tests/db-adapter.test.ts +82 -0
  1579. package/src/resources/extensions/gsd/tests/db-authority-regression.test.ts +208 -0
  1580. package/src/resources/extensions/gsd/tests/db-base-schema.test.ts +62 -0
  1581. package/src/resources/extensions/gsd/tests/db-connection-cache.test.ts +60 -0
  1582. package/src/resources/extensions/gsd/tests/db-coordination-schema.test.ts +39 -0
  1583. package/src/resources/extensions/gsd/tests/db-decision-requirement-rows.test.ts +135 -0
  1584. package/src/resources/extensions/gsd/tests/db-gate-rows.test.ts +53 -0
  1585. package/src/resources/extensions/gsd/tests/db-lightweight-query-rows.test.ts +45 -0
  1586. package/src/resources/extensions/gsd/tests/db-memory-fts-schema.test.ts +86 -0
  1587. package/src/resources/extensions/gsd/tests/db-migration-backup.test.ts +105 -0
  1588. package/src/resources/extensions/gsd/tests/db-migration-steps.integration.test.ts +428 -0
  1589. package/src/resources/extensions/gsd/tests/db-migration-steps.test.ts +159 -0
  1590. package/src/resources/extensions/gsd/tests/db-milestone-artifact-rows.test.ts +53 -0
  1591. package/src/resources/extensions/gsd/tests/db-open-state.test.ts +56 -0
  1592. package/src/resources/extensions/gsd/tests/db-path-worktree-symlink.test.ts +95 -0
  1593. package/src/resources/extensions/gsd/tests/db-provider.test.ts +105 -0
  1594. package/src/resources/extensions/gsd/tests/db-runtime-kv-schema.test.ts +37 -0
  1595. package/src/resources/extensions/gsd/tests/db-schema-metadata.test.ts +115 -0
  1596. package/src/resources/extensions/gsd/tests/db-task-slice-rows.test.ts +130 -0
  1597. package/src/resources/extensions/gsd/tests/db-transaction.test.ts +110 -0
  1598. package/src/resources/extensions/gsd/tests/db-verification-evidence-schema.test.ts +76 -0
  1599. package/src/resources/extensions/gsd/tests/db-writer-path-containment.test.ts +152 -0
  1600. package/src/resources/extensions/gsd/tests/db-writer-root-artifact.test.ts +221 -0
  1601. package/src/resources/extensions/gsd/tests/db-writer-scope.test.ts +230 -0
  1602. package/src/resources/extensions/gsd/tests/db-writer.test.ts +980 -0
  1603. package/src/resources/extensions/gsd/tests/debug-command-handler.test.ts +942 -0
  1604. package/src/resources/extensions/gsd/tests/debug-command-lifecycle.integration.test.ts +1229 -0
  1605. package/src/resources/extensions/gsd/tests/debug-logger.test.ts +187 -0
  1606. package/src/resources/extensions/gsd/tests/debug-session-store.test.ts +565 -0
  1607. package/src/resources/extensions/gsd/tests/decision-scope-cascade.test.ts +370 -0
  1608. package/src/resources/extensions/gsd/tests/decisions-projection-from-memories.test.ts +453 -0
  1609. package/src/resources/extensions/gsd/tests/decisions-stop-table-writes.test.ts +348 -0
  1610. package/src/resources/extensions/gsd/tests/deep-mode-integration.test.ts +406 -0
  1611. package/src/resources/extensions/gsd/tests/deep-planning-mode-dispatch.test.ts +923 -0
  1612. package/src/resources/extensions/gsd/tests/deep-project-auto-loop.test.ts +1705 -0
  1613. package/src/resources/extensions/gsd/tests/deep-project-setup-policy.test.ts +193 -0
  1614. package/src/resources/extensions/gsd/tests/defer-milestone-stamp.test.ts +30 -0
  1615. package/src/resources/extensions/gsd/tests/deferred-milestone-dir-4996.test.ts +65 -0
  1616. package/src/resources/extensions/gsd/tests/deferred-slice-dispatch.test.ts +203 -0
  1617. package/src/resources/extensions/gsd/tests/definition-io.test.ts +57 -0
  1618. package/src/resources/extensions/gsd/tests/definition-loader.test.ts +762 -0
  1619. package/src/resources/extensions/gsd/tests/delegation-policy.test.ts +151 -0
  1620. package/src/resources/extensions/gsd/tests/derive-state-crossval.test.ts +514 -0
  1621. package/src/resources/extensions/gsd/tests/derive-state-db-disk-reconcile.test.ts +133 -0
  1622. package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +1388 -0
  1623. package/src/resources/extensions/gsd/tests/derive-state-deps.test.ts +641 -0
  1624. package/src/resources/extensions/gsd/tests/derive-state-draft.test.ts +313 -0
  1625. package/src/resources/extensions/gsd/tests/derive-state-helpers.test.ts +558 -0
  1626. package/src/resources/extensions/gsd/tests/derive-state.test.ts +1049 -0
  1627. package/src/resources/extensions/gsd/tests/detect-stuck-respects-retry.test.ts +173 -0
  1628. package/src/resources/extensions/gsd/tests/detection.test.ts +1367 -0
  1629. package/src/resources/extensions/gsd/tests/dev-engine-wrapper.test.ts +314 -0
  1630. package/src/resources/extensions/gsd/tests/diff-context.test.ts +136 -0
  1631. package/src/resources/extensions/gsd/tests/discord-invite-links.test.ts +47 -0
  1632. package/src/resources/extensions/gsd/tests/discuss-cold-start-db-open.test.ts +71 -0
  1633. package/src/resources/extensions/gsd/tests/discuss-command-targeting-5471.test.ts +125 -0
  1634. package/src/resources/extensions/gsd/tests/discuss-empty-db-fallback.test.ts +62 -0
  1635. package/src/resources/extensions/gsd/tests/discuss-headless-rendering.test.ts +37 -0
  1636. package/src/resources/extensions/gsd/tests/discuss-incremental-persistence.test.ts +45 -0
  1637. package/src/resources/extensions/gsd/tests/discuss-milestone-structured-questions.test.ts +115 -0
  1638. package/src/resources/extensions/gsd/tests/discuss-prompt.test.ts +15 -0
  1639. package/src/resources/extensions/gsd/tests/discuss-queued-milestones.test.ts +170 -0
  1640. package/src/resources/extensions/gsd/tests/discuss-tool-scope-leak.test.ts +35 -0
  1641. package/src/resources/extensions/gsd/tests/discuss-tool-scoping.test.ts +138 -0
  1642. package/src/resources/extensions/gsd/tests/dispatch-backgroundable-annotation.test.ts +55 -0
  1643. package/src/resources/extensions/gsd/tests/dispatch-complete-milestone-guard.test.ts +276 -0
  1644. package/src/resources/extensions/gsd/tests/dispatch-guard-closed-status.test.ts +43 -0
  1645. package/src/resources/extensions/gsd/tests/dispatch-guard-summary-db-mismatch.test.ts +77 -0
  1646. package/src/resources/extensions/gsd/tests/dispatch-guard.test.ts +446 -0
  1647. package/src/resources/extensions/gsd/tests/dispatch-missing-task-plans.test.ts +279 -0
  1648. package/src/resources/extensions/gsd/tests/dispatch-rule-coverage.test.ts +358 -0
  1649. package/src/resources/extensions/gsd/tests/dispatch-uat-last-completed.test.ts +206 -0
  1650. package/src/resources/extensions/gsd/tests/dispatcher-stuck-planning.test.ts +55 -0
  1651. package/src/resources/extensions/gsd/tests/dist-redirect.mjs +112 -0
  1652. package/src/resources/extensions/gsd/tests/doctor-empty-worktree.test.ts +65 -0
  1653. package/src/resources/extensions/gsd/tests/doctor-fix-flag.test.ts +92 -0
  1654. package/src/resources/extensions/gsd/tests/doctor-forensics-db-open-regression.test.ts +50 -0
  1655. package/src/resources/extensions/gsd/tests/doctor-heal-fixable-warnings.test.ts +14 -0
  1656. package/src/resources/extensions/gsd/tests/doctor-orphan-milestone-4996.test.ts +100 -0
  1657. package/src/resources/extensions/gsd/tests/doctor-providers.test.ts +828 -0
  1658. package/src/resources/extensions/gsd/tests/doctor-runtime-checks.test.ts +47 -0
  1659. package/src/resources/extensions/gsd/tests/doctor-scope-db-unavailable.test.ts +43 -0
  1660. package/src/resources/extensions/gsd/tests/double-merge-guard.test.ts +36 -0
  1661. package/src/resources/extensions/gsd/tests/draft-promotion.test.ts +149 -0
  1662. package/src/resources/extensions/gsd/tests/dynamic-routing-default.test.ts +20 -0
  1663. package/src/resources/extensions/gsd/tests/engine-interfaces-contract.test.ts +271 -0
  1664. package/src/resources/extensions/gsd/tests/enhanced-verification-integration.test.ts +531 -0
  1665. package/src/resources/extensions/gsd/tests/ensure-db-open.test.ts +530 -0
  1666. package/src/resources/extensions/gsd/tests/ensure-preconditions-guard-4996.test.ts +93 -0
  1667. package/src/resources/extensions/gsd/tests/error-success-mask.test.ts +32 -0
  1668. package/src/resources/extensions/gsd/tests/escalation.test.ts +819 -0
  1669. package/src/resources/extensions/gsd/tests/est-annotation-timeout.test.ts +53 -0
  1670. package/src/resources/extensions/gsd/tests/eval-review-schema.test.ts +282 -0
  1671. package/src/resources/extensions/gsd/tests/event-replay-idempotency.test.ts +140 -0
  1672. package/src/resources/extensions/gsd/tests/evidence-cross-ref.test.ts +121 -0
  1673. package/src/resources/extensions/gsd/tests/exec-history.test.ts +252 -0
  1674. package/src/resources/extensions/gsd/tests/exec-sandbox.test.ts +407 -0
  1675. package/src/resources/extensions/gsd/tests/execute-summary-save-empty-project.test.ts +109 -0
  1676. package/src/resources/extensions/gsd/tests/execute-task-prompt-existing-artifact-guard.test.ts +33 -0
  1677. package/src/resources/extensions/gsd/tests/execute-task-rendering.test.ts +62 -0
  1678. package/src/resources/extensions/gsd/tests/execution-entry-missing-context-4671.test.ts +187 -0
  1679. package/src/resources/extensions/gsd/tests/exit-command.test.ts +101 -0
  1680. package/src/resources/extensions/gsd/tests/export-html-all.test.ts +116 -0
  1681. package/src/resources/extensions/gsd/tests/export-html-enhancements.test.ts +387 -0
  1682. package/src/resources/extensions/gsd/tests/extension-bootstrap-isolation.test.ts +164 -0
  1683. package/src/resources/extensions/gsd/tests/extension-selector-separator.test.ts +144 -0
  1684. package/src/resources/extensions/gsd/tests/false-degraded-mode-warning.test.ts +43 -0
  1685. package/src/resources/extensions/gsd/tests/fast-forward-reused-milestone-branch.test.ts +219 -0
  1686. package/src/resources/extensions/gsd/tests/file-change-validator.test.ts +108 -0
  1687. package/src/resources/extensions/gsd/tests/file-lock.test.ts +177 -0
  1688. package/src/resources/extensions/gsd/tests/files-loadfile-eisdir.test.ts +18 -0
  1689. package/src/resources/extensions/gsd/tests/finalize-survivor-branch.test.ts +151 -0
  1690. package/src/resources/extensions/gsd/tests/finalize-timeout-guard.test.ts +103 -0
  1691. package/src/resources/extensions/gsd/tests/find-missing-summaries-closed-runtime.test.ts +47 -0
  1692. package/src/resources/extensions/gsd/tests/fixtures/pr-body/commands-ship-basic.md +52 -0
  1693. package/src/resources/extensions/gsd/tests/fixtures/pr-body/commands-ship-empty-optionals.md +42 -0
  1694. package/src/resources/extensions/gsd/tests/fixtures/pr-body/swarm-lane-no-blockers.md +55 -0
  1695. package/src/resources/extensions/gsd/tests/fixtures/pr-body/swarm-lane-with-blockers.md +60 -0
  1696. package/src/resources/extensions/gsd/tests/flag-file-db.test.ts +278 -0
  1697. package/src/resources/extensions/gsd/tests/flat-rate-routing-guard.test.ts +305 -0
  1698. package/src/resources/extensions/gsd/tests/forensics-error-filter.test.ts +121 -0
  1699. package/src/resources/extensions/gsd/tests/forensics-issue-routing.test.ts +43 -0
  1700. package/src/resources/extensions/gsd/tests/forensics-prompt-rendering.test.ts +36 -0
  1701. package/src/resources/extensions/gsd/tests/forensics-stuck-loops.test.ts +215 -0
  1702. package/src/resources/extensions/gsd/tests/format-shortcut.test.ts +100 -0
  1703. package/src/resources/extensions/gsd/tests/freeform-decisions.test.ts +298 -0
  1704. package/src/resources/extensions/gsd/tests/fresh-run-ui.test.ts +65 -0
  1705. package/src/resources/extensions/gsd/tests/frontmatter-parse-noise.test.ts +34 -0
  1706. package/src/resources/extensions/gsd/tests/gate-1b-orphan-discrimination.test.ts +193 -0
  1707. package/src/resources/extensions/gsd/tests/gate-1b-recovery-bound-corrections.test.ts +246 -0
  1708. package/src/resources/extensions/gsd/tests/gate-1b-recovery-bound.test.ts +218 -0
  1709. package/src/resources/extensions/gsd/tests/gate-dispatch.test.ts +216 -0
  1710. package/src/resources/extensions/gsd/tests/gate-registry.test.ts +140 -0
  1711. package/src/resources/extensions/gsd/tests/gate-state-canonicalization.test.ts +102 -0
  1712. package/src/resources/extensions/gsd/tests/gate-storage.test.ts +156 -0
  1713. package/src/resources/extensions/gsd/tests/git-checkpoint.test.ts +103 -0
  1714. package/src/resources/extensions/gsd/tests/gitignore-bg-shell-runtime.test.ts +77 -0
  1715. package/src/resources/extensions/gsd/tests/google-search-stub.test.ts +91 -0
  1716. package/src/resources/extensions/gsd/tests/graph-context.test.ts +337 -0
  1717. package/src/resources/extensions/gsd/tests/graph-operations.test.ts +599 -0
  1718. package/src/resources/extensions/gsd/tests/gsd-command-home.test.ts +134 -0
  1719. package/src/resources/extensions/gsd/tests/gsd-db-failed-open-restore.test.ts +117 -0
  1720. package/src/resources/extensions/gsd/tests/gsd-db-workspace-scope.test.ts +226 -0
  1721. package/src/resources/extensions/gsd/tests/gsd-db.test.ts +1210 -0
  1722. package/src/resources/extensions/gsd/tests/gsd-home.test.ts +43 -0
  1723. package/src/resources/extensions/gsd/tests/gsd-inspect.test.ts +114 -0
  1724. package/src/resources/extensions/gsd/tests/gsd-no-project-error-runtime.test.ts +95 -0
  1725. package/src/resources/extensions/gsd/tests/gsd-recover.test.ts +440 -0
  1726. package/src/resources/extensions/gsd/tests/gsd-root-canonical.test.ts +66 -0
  1727. package/src/resources/extensions/gsd/tests/gsd-root-home-guard.test.ts +149 -0
  1728. package/src/resources/extensions/gsd/tests/gsd-tools.test.ts +445 -0
  1729. package/src/resources/extensions/gsd/tests/gsdroot-worktree-detection.test.ts +146 -0
  1730. package/src/resources/extensions/gsd/tests/guided-discuss-milestone-prompt-rendering.test.ts +43 -0
  1731. package/src/resources/extensions/gsd/tests/guided-discuss-project-prompt-rendering.test.ts +43 -0
  1732. package/src/resources/extensions/gsd/tests/guided-discuss-requirements-prompt-rendering.test.ts +45 -0
  1733. package/src/resources/extensions/gsd/tests/guided-dispatch-root.test.ts +106 -0
  1734. package/src/resources/extensions/gsd/tests/guided-flow-dynamic-routing.test.ts +135 -0
  1735. package/src/resources/extensions/gsd/tests/guided-flow-prompt-consolidation.test.ts +147 -0
  1736. package/src/resources/extensions/gsd/tests/guided-flow-session-isolation.test.ts +219 -0
  1737. package/src/resources/extensions/gsd/tests/guided-flow-state-rebuild.test.ts +140 -0
  1738. package/src/resources/extensions/gsd/tests/guided-flow.test.ts +21 -0
  1739. package/src/resources/extensions/gsd/tests/guided-tool-contract.test.ts +65 -0
  1740. package/src/resources/extensions/gsd/tests/handler-worktree-write-isolation.test.ts +57 -0
  1741. package/src/resources/extensions/gsd/tests/has-pending-deep-stage.test.ts +130 -0
  1742. package/src/resources/extensions/gsd/tests/header-renderer.test.ts +40 -0
  1743. package/src/resources/extensions/gsd/tests/headless-answers.test.ts +350 -0
  1744. package/src/resources/extensions/gsd/tests/headless-milestone-parity.test.ts +127 -0
  1745. package/src/resources/extensions/gsd/tests/headless-query.test.ts +184 -0
  1746. package/src/resources/extensions/gsd/tests/health-widget.test.ts +251 -0
  1747. package/src/resources/extensions/gsd/tests/help-menu-coverage.test.ts +57 -0
  1748. package/src/resources/extensions/gsd/tests/hook-key-parsing.test.ts +56 -0
  1749. package/src/resources/extensions/gsd/tests/hook-model-resolution.test.ts +103 -0
  1750. package/src/resources/extensions/gsd/tests/import-done-milestones-runtime.test.ts +145 -0
  1751. package/src/resources/extensions/gsd/tests/in-flight-tool-tracking.test.ts +32 -0
  1752. package/src/resources/extensions/gsd/tests/infra-error.test.ts +129 -0
  1753. package/src/resources/extensions/gsd/tests/infra-errors-cooldown.test.ts +189 -0
  1754. package/src/resources/extensions/gsd/tests/init-prefs-routing.test.ts +275 -0
  1755. package/src/resources/extensions/gsd/tests/init-skip-git.test.ts +16 -0
  1756. package/src/resources/extensions/gsd/tests/init-wizard.test.ts +239 -0
  1757. package/src/resources/extensions/gsd/tests/insert-slice-no-wipe.test.ts +88 -0
  1758. package/src/resources/extensions/gsd/tests/integration/all-milestones-complete-merge.test.ts +199 -0
  1759. package/src/resources/extensions/gsd/tests/integration/atomic-task-closeout.test.ts +72 -0
  1760. package/src/resources/extensions/gsd/tests/integration/auto-preflight.test.ts +38 -0
  1761. package/src/resources/extensions/gsd/tests/integration/auto-recovery.test.ts +966 -0
  1762. package/src/resources/extensions/gsd/tests/integration/auto-secrets-gate.test.ts +194 -0
  1763. package/src/resources/extensions/gsd/tests/integration/auto-stash-merge.test.ts +121 -0
  1764. package/src/resources/extensions/gsd/tests/integration/auto-worktree-milestone-merge.test.ts +964 -0
  1765. package/src/resources/extensions/gsd/tests/integration/auto-worktree.test.ts +430 -0
  1766. package/src/resources/extensions/gsd/tests/integration/commands-eval-review.integration.test.ts +256 -0
  1767. package/src/resources/extensions/gsd/tests/integration/continue-here.test.ts +281 -0
  1768. package/src/resources/extensions/gsd/tests/integration/doctor-completion-deferral.test.ts +88 -0
  1769. package/src/resources/extensions/gsd/tests/integration/doctor-delimiter-fix.test.ts +83 -0
  1770. package/src/resources/extensions/gsd/tests/integration/doctor-enhancements.test.ts +243 -0
  1771. package/src/resources/extensions/gsd/tests/integration/doctor-environment-worktree.test.ts +164 -0
  1772. package/src/resources/extensions/gsd/tests/integration/doctor-environment.test.ts +403 -0
  1773. package/src/resources/extensions/gsd/tests/integration/doctor-false-positives.test.ts +243 -0
  1774. package/src/resources/extensions/gsd/tests/integration/doctor-fixlevel.test.ts +263 -0
  1775. package/src/resources/extensions/gsd/tests/integration/doctor-git-symlink-cwd.test.ts +90 -0
  1776. package/src/resources/extensions/gsd/tests/integration/doctor-git.test.ts +954 -0
  1777. package/src/resources/extensions/gsd/tests/integration/doctor-proactive.test.ts +431 -0
  1778. package/src/resources/extensions/gsd/tests/integration/doctor-roadmap-summary-atomicity.test.ts +123 -0
  1779. package/src/resources/extensions/gsd/tests/integration/doctor-runtime.test.ts +549 -0
  1780. package/src/resources/extensions/gsd/tests/integration/doctor.test.ts +612 -0
  1781. package/src/resources/extensions/gsd/tests/integration/e2e-workflow-pipeline-integration.test.ts +476 -0
  1782. package/src/resources/extensions/gsd/tests/integration/feature-branch-lifecycle-integration.test.ts +415 -0
  1783. package/src/resources/extensions/gsd/tests/integration/git-locale.test.ts +130 -0
  1784. package/src/resources/extensions/gsd/tests/integration/git-self-heal.test.ts +131 -0
  1785. package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +2040 -0
  1786. package/src/resources/extensions/gsd/tests/integration/gitignore-staging-2570.test.ts +150 -0
  1787. package/src/resources/extensions/gsd/tests/integration/gitignore-tracked-gsd.test.ts +257 -0
  1788. package/src/resources/extensions/gsd/tests/integration/headless-command.ts +534 -0
  1789. package/src/resources/extensions/gsd/tests/integration/idle-recovery.test.ts +474 -0
  1790. package/src/resources/extensions/gsd/tests/integration/inherited-repo-home-dir.test.ts +191 -0
  1791. package/src/resources/extensions/gsd/tests/integration/integration-lifecycle.test.ts +274 -0
  1792. package/src/resources/extensions/gsd/tests/integration/integration-mixed-milestones.test.ts +539 -0
  1793. package/src/resources/extensions/gsd/tests/integration/integration-proof.test.ts +634 -0
  1794. package/src/resources/extensions/gsd/tests/integration/merge-cwd-restore.test.ts +169 -0
  1795. package/src/resources/extensions/gsd/tests/integration/merge-preserve-worktree-on-preteardown-error.test.ts +77 -0
  1796. package/src/resources/extensions/gsd/tests/integration/migrate-command.test.ts +405 -0
  1797. package/src/resources/extensions/gsd/tests/integration/milestone-transition-worktree.test.ts +119 -0
  1798. package/src/resources/extensions/gsd/tests/integration/parallel-merge.test.ts +669 -0
  1799. package/src/resources/extensions/gsd/tests/integration/parallel-workers-multi-milestone-e2e.test.ts +337 -0
  1800. package/src/resources/extensions/gsd/tests/integration/paths.test.ts +98 -0
  1801. package/src/resources/extensions/gsd/tests/integration/plugin-importer-live.test.ts +481 -0
  1802. package/src/resources/extensions/gsd/tests/integration/queue-completed-milestone-perf.test.ts +161 -0
  1803. package/src/resources/extensions/gsd/tests/integration/queue-reorder-e2e.test.ts +335 -0
  1804. package/src/resources/extensions/gsd/tests/integration/quick-branch-lifecycle.test.ts +253 -0
  1805. package/src/resources/extensions/gsd/tests/integration/run-uat.test.ts +689 -0
  1806. package/src/resources/extensions/gsd/tests/integration/state-machine-edge-cases.test.ts +1356 -0
  1807. package/src/resources/extensions/gsd/tests/integration/state-machine-live-validation.test.ts +980 -0
  1808. package/src/resources/extensions/gsd/tests/integration/state-machine-runtime-failures.test.ts +832 -0
  1809. package/src/resources/extensions/gsd/tests/integration/test-isolation.ts +53 -0
  1810. package/src/resources/extensions/gsd/tests/integration/token-savings.test.ts +341 -0
  1811. package/src/resources/extensions/gsd/tests/integration/workspace-collapse-integration.test.ts +369 -0
  1812. package/src/resources/extensions/gsd/tests/integration/worktree-e2e.test.ts +248 -0
  1813. package/src/resources/extensions/gsd/tests/integration-edge.test.ts +223 -0
  1814. package/src/resources/extensions/gsd/tests/interactive-routing-bypass.test.ts +71 -0
  1815. package/src/resources/extensions/gsd/tests/interactive-tool-idle-exemption.test.ts +119 -0
  1816. package/src/resources/extensions/gsd/tests/interrupted-session-auto.test.ts +241 -0
  1817. package/src/resources/extensions/gsd/tests/interrupted-session-ui.test.ts +180 -0
  1818. package/src/resources/extensions/gsd/tests/isolation-none-branch-guard.test.ts +19 -0
  1819. package/src/resources/extensions/gsd/tests/issue-4540-regressions.test.ts +288 -0
  1820. package/src/resources/extensions/gsd/tests/iterate-engine-integration.test.ts +429 -0
  1821. package/src/resources/extensions/gsd/tests/journal-integration.test.ts +1473 -0
  1822. package/src/resources/extensions/gsd/tests/journal-query-tool.test.ts +179 -0
  1823. package/src/resources/extensions/gsd/tests/journal.test.ts +373 -0
  1824. package/src/resources/extensions/gsd/tests/json-persistence-atomic.test.ts +183 -0
  1825. package/src/resources/extensions/gsd/tests/key-manager.test.ts +501 -0
  1826. package/src/resources/extensions/gsd/tests/knowledge-backfill-projection.test.ts +323 -0
  1827. package/src/resources/extensions/gsd/tests/knowledge-capture.test.ts +242 -0
  1828. package/src/resources/extensions/gsd/tests/knowledge.test.ts +434 -0
  1829. package/src/resources/extensions/gsd/tests/lazy-pi-tui-import.test.ts +53 -0
  1830. package/src/resources/extensions/gsd/tests/lease-conflict-notice.test.ts +38 -0
  1831. package/src/resources/extensions/gsd/tests/legacy-component-format-telemetry.test.ts +62 -0
  1832. package/src/resources/extensions/gsd/tests/legacy-telemetry.test.ts +144 -0
  1833. package/src/resources/extensions/gsd/tests/load-knowledge-block-rules-only.test.ts +209 -0
  1834. package/src/resources/extensions/gsd/tests/load-memory-block.test.ts +36 -0
  1835. package/src/resources/extensions/gsd/tests/manifest-status.test.ts +274 -0
  1836. package/src/resources/extensions/gsd/tests/markdown-renderer.test.ts +1292 -0
  1837. package/src/resources/extensions/gsd/tests/marketplace-test-fixtures.ts +91 -0
  1838. package/src/resources/extensions/gsd/tests/mcp-client-security.test.ts +47 -0
  1839. package/src/resources/extensions/gsd/tests/mcp-filter.test.ts +287 -0
  1840. package/src/resources/extensions/gsd/tests/mcp-project-config.test.ts +89 -0
  1841. package/src/resources/extensions/gsd/tests/mcp-status.test.ts +183 -0
  1842. package/src/resources/extensions/gsd/tests/md-importer.test.ts +416 -0
  1843. package/src/resources/extensions/gsd/tests/measurement.test.ts +531 -0
  1844. package/src/resources/extensions/gsd/tests/memory-consolidation-scanner.test.ts +316 -0
  1845. package/src/resources/extensions/gsd/tests/memory-decay-factor.test.ts +90 -0
  1846. package/src/resources/extensions/gsd/tests/memory-embeddings.test.ts +213 -0
  1847. package/src/resources/extensions/gsd/tests/memory-extractor.test.ts +244 -0
  1848. package/src/resources/extensions/gsd/tests/memory-ingest.test.ts +153 -0
  1849. package/src/resources/extensions/gsd/tests/memory-leak-guards.test.ts +91 -0
  1850. package/src/resources/extensions/gsd/tests/memory-maintenance.test.ts +107 -0
  1851. package/src/resources/extensions/gsd/tests/memory-pressure-stuck-state.test.ts +79 -0
  1852. package/src/resources/extensions/gsd/tests/memory-relations.test.ts +175 -0
  1853. package/src/resources/extensions/gsd/tests/memory-store.test.ts +460 -0
  1854. package/src/resources/extensions/gsd/tests/memory-tools.test.ts +327 -0
  1855. package/src/resources/extensions/gsd/tests/merge-conflict-stops-loop.test.ts +303 -0
  1856. package/src/resources/extensions/gsd/tests/merge-db-cycle.test.ts +179 -0
  1857. package/src/resources/extensions/gsd/tests/merge-self-branch-guard.test.ts +105 -0
  1858. package/src/resources/extensions/gsd/tests/metrics-atomic-merge.test.ts +222 -0
  1859. package/src/resources/extensions/gsd/tests/metrics-lock-hardening.test.ts +400 -0
  1860. package/src/resources/extensions/gsd/tests/metrics-lock-not-acquired.test.ts +141 -0
  1861. package/src/resources/extensions/gsd/tests/metrics-lock-retry-sleep.test.ts +287 -0
  1862. package/src/resources/extensions/gsd/tests/metrics-milestone-scope.test.ts +64 -0
  1863. package/src/resources/extensions/gsd/tests/metrics-prune-cache-invalidation.test.ts +149 -0
  1864. package/src/resources/extensions/gsd/tests/metrics-scope.test.ts +378 -0
  1865. package/src/resources/extensions/gsd/tests/metrics.test.ts +519 -0
  1866. package/src/resources/extensions/gsd/tests/migrate-external-worktree.test.ts +165 -0
  1867. package/src/resources/extensions/gsd/tests/migrate-hierarchy.test.ts +429 -0
  1868. package/src/resources/extensions/gsd/tests/migrate-parser.test.ts +782 -0
  1869. package/src/resources/extensions/gsd/tests/migrate-safety-audit.test.ts +242 -0
  1870. package/src/resources/extensions/gsd/tests/migrate-transformer.test.ts +651 -0
  1871. package/src/resources/extensions/gsd/tests/migrate-validator-parsers.test.ts +448 -0
  1872. package/src/resources/extensions/gsd/tests/migrate-writer-integration.test.ts +347 -0
  1873. package/src/resources/extensions/gsd/tests/migrate-writer.test.ts +361 -0
  1874. package/src/resources/extensions/gsd/tests/migration-auto-check.test.ts +135 -0
  1875. package/src/resources/extensions/gsd/tests/milestone-id-gap-reuse-4996.test.ts +152 -0
  1876. package/src/resources/extensions/gsd/tests/milestone-id-reservation.test.ts +73 -0
  1877. package/src/resources/extensions/gsd/tests/milestone-leases.test.ts +152 -0
  1878. package/src/resources/extensions/gsd/tests/milestone-merge-stash-restore.test.ts +364 -0
  1879. package/src/resources/extensions/gsd/tests/milestone-report-path.test.ts +68 -0
  1880. package/src/resources/extensions/gsd/tests/milestone-scope-classifier.test.ts +206 -0
  1881. package/src/resources/extensions/gsd/tests/milestone-status-authoritative.test.ts +116 -0
  1882. package/src/resources/extensions/gsd/tests/milestone-status-tool.test.ts +202 -0
  1883. package/src/resources/extensions/gsd/tests/milestone-summary-classifier.test.ts +30 -0
  1884. package/src/resources/extensions/gsd/tests/milestone-transition-state-rebuild.test.ts +122 -0
  1885. package/src/resources/extensions/gsd/tests/model-cost-table.test.ts +111 -0
  1886. package/src/resources/extensions/gsd/tests/model-isolation.test.ts +305 -0
  1887. package/src/resources/extensions/gsd/tests/model-router.test.ts +990 -0
  1888. package/src/resources/extensions/gsd/tests/model-unittype-mapping.test.ts +90 -0
  1889. package/src/resources/extensions/gsd/tests/must-have-parser.test.ts +278 -0
  1890. package/src/resources/extensions/gsd/tests/namespaced-registry.test.ts +1027 -0
  1891. package/src/resources/extensions/gsd/tests/namespaced-resolver.test.ts +671 -0
  1892. package/src/resources/extensions/gsd/tests/native-git-bridge-exec-fallback.test.ts +228 -0
  1893. package/src/resources/extensions/gsd/tests/native-git-infra-errors.test.ts +50 -0
  1894. package/src/resources/extensions/gsd/tests/native-has-changes-cache.test.ts +61 -0
  1895. package/src/resources/extensions/gsd/tests/needs-remediation-revalidation.test.ts +55 -0
  1896. package/src/resources/extensions/gsd/tests/next-milestone-id.test.ts +23 -0
  1897. package/src/resources/extensions/gsd/tests/none-mode-gates.test.ts +200 -0
  1898. package/src/resources/extensions/gsd/tests/note-captures-executed.test.ts +50 -0
  1899. package/src/resources/extensions/gsd/tests/notification-overlay.test.ts +129 -0
  1900. package/src/resources/extensions/gsd/tests/notification-store.test.ts +325 -0
  1901. package/src/resources/extensions/gsd/tests/notification-widget.test.ts +87 -0
  1902. package/src/resources/extensions/gsd/tests/notifications-handler.test.ts +134 -0
  1903. package/src/resources/extensions/gsd/tests/notifications.test.ts +134 -0
  1904. package/src/resources/extensions/gsd/tests/onboarding-state.test.ts +105 -0
  1905. package/src/resources/extensions/gsd/tests/originalbase-path-comparison.test.ts +159 -0
  1906. package/src/resources/extensions/gsd/tests/orphan-merge-bootstrap.test.ts +144 -0
  1907. package/src/resources/extensions/gsd/tests/orphan-stash-audit.test.ts +201 -0
  1908. package/src/resources/extensions/gsd/tests/orphaned-worktree-audit.test.ts +374 -0
  1909. package/src/resources/extensions/gsd/tests/overrides.test.ts +124 -0
  1910. package/src/resources/extensions/gsd/tests/parallel-budget-atomicity.test.ts +330 -0
  1911. package/src/resources/extensions/gsd/tests/parallel-commit-scope.test.ts +164 -0
  1912. package/src/resources/extensions/gsd/tests/parallel-crash-recovery.test.ts +273 -0
  1913. package/src/resources/extensions/gsd/tests/parallel-eligibility-ghost.test.ts +170 -0
  1914. package/src/resources/extensions/gsd/tests/parallel-milestone-isolation.test.ts +106 -0
  1915. package/src/resources/extensions/gsd/tests/parallel-monitor-overlay.test.ts +114 -0
  1916. package/src/resources/extensions/gsd/tests/parallel-orchestration.test.ts +736 -0
  1917. package/src/resources/extensions/gsd/tests/parallel-orchestrator-fast-forward.test.ts +113 -0
  1918. package/src/resources/extensions/gsd/tests/parallel-orchestrator-zombie-cleanup.test.ts +332 -0
  1919. package/src/resources/extensions/gsd/tests/parallel-research-dispatch.test.ts +308 -0
  1920. package/src/resources/extensions/gsd/tests/parallel-skill-prompt-integration.test.ts +158 -0
  1921. package/src/resources/extensions/gsd/tests/parallel-worker-lock-contention.test.ts +226 -0
  1922. package/src/resources/extensions/gsd/tests/parallel-worker-monitoring.test.ts +199 -0
  1923. package/src/resources/extensions/gsd/tests/park-db-sync.test.ts +157 -0
  1924. package/src/resources/extensions/gsd/tests/park-edge-cases.test.ts +253 -0
  1925. package/src/resources/extensions/gsd/tests/park-milestone.test.ts +420 -0
  1926. package/src/resources/extensions/gsd/tests/parsers.test.ts +1892 -0
  1927. package/src/resources/extensions/gsd/tests/path-cache-decoupled.test.ts +209 -0
  1928. package/src/resources/extensions/gsd/tests/path-normalization-unified.test.ts +175 -0
  1929. package/src/resources/extensions/gsd/tests/paths-cache.test.ts +170 -0
  1930. package/src/resources/extensions/gsd/tests/paused-session-via-db.test.ts +121 -0
  1931. package/src/resources/extensions/gsd/tests/pending-autostart-scope.test.ts +144 -0
  1932. package/src/resources/extensions/gsd/tests/phantom-ghost-detection.test.ts +42 -0
  1933. package/src/resources/extensions/gsd/tests/phantom-milestone-default-queued.test.ts +24 -0
  1934. package/src/resources/extensions/gsd/tests/phase-anchor.test.ts +83 -0
  1935. package/src/resources/extensions/gsd/tests/phases-merge-error-stops-auto.test.ts +126 -0
  1936. package/src/resources/extensions/gsd/tests/pipeline-variant-dispatch.test.ts +404 -0
  1937. package/src/resources/extensions/gsd/tests/plan-gate-failed-doctor-heal-hint.test.ts +37 -0
  1938. package/src/resources/extensions/gsd/tests/plan-milestone-artifact-verification.test.ts +102 -0
  1939. package/src/resources/extensions/gsd/tests/plan-milestone-boundary-map-preservation.test.ts +114 -0
  1940. package/src/resources/extensions/gsd/tests/plan-milestone-queue-context.test.ts +48 -0
  1941. package/src/resources/extensions/gsd/tests/plan-milestone-rendering.test.ts +45 -0
  1942. package/src/resources/extensions/gsd/tests/plan-milestone-sketch-render.test.ts +157 -0
  1943. package/src/resources/extensions/gsd/tests/plan-milestone-title.test.ts +71 -0
  1944. package/src/resources/extensions/gsd/tests/plan-milestone.test.ts +349 -0
  1945. package/src/resources/extensions/gsd/tests/plan-quality-validator.test.ts +474 -0
  1946. package/src/resources/extensions/gsd/tests/plan-slice-prompt.test.ts +306 -0
  1947. package/src/resources/extensions/gsd/tests/plan-slice.test.ts +712 -0
  1948. package/src/resources/extensions/gsd/tests/plan-task.test.ts +183 -0
  1949. package/src/resources/extensions/gsd/tests/planning-crossval.test.ts +305 -0
  1950. package/src/resources/extensions/gsd/tests/planning-depth-setter.test.ts +172 -0
  1951. package/src/resources/extensions/gsd/tests/plugin-importer.test.ts +1383 -0
  1952. package/src/resources/extensions/gsd/tests/post-exec-retry-bypass.test.ts +536 -0
  1953. package/src/resources/extensions/gsd/tests/post-execution-checks.test.ts +1065 -0
  1954. package/src/resources/extensions/gsd/tests/post-mutation-hook.test.ts +171 -0
  1955. package/src/resources/extensions/gsd/tests/post-unit-git-failure.test.ts +25 -0
  1956. package/src/resources/extensions/gsd/tests/post-unit-hooks.test.ts +300 -0
  1957. package/src/resources/extensions/gsd/tests/post-unit-state-rebuild.test.ts +567 -0
  1958. package/src/resources/extensions/gsd/tests/pr-evidence-equivalence.test.ts +102 -0
  1959. package/src/resources/extensions/gsd/tests/pr-evidence-hardening.test.ts +165 -0
  1960. package/src/resources/extensions/gsd/tests/pr-evidence.test.ts +79 -0
  1961. package/src/resources/extensions/gsd/tests/pre-exec-backtick-strip.test.ts +149 -0
  1962. package/src/resources/extensions/gsd/tests/pre-exec-gate-loop.test.ts +275 -0
  1963. package/src/resources/extensions/gsd/tests/pre-execution-checks.test.ts +2246 -0
  1964. package/src/resources/extensions/gsd/tests/pre-execution-fail-closed.test.ts +244 -0
  1965. package/src/resources/extensions/gsd/tests/pre-execution-pause-wiring.test.ts +708 -0
  1966. package/src/resources/extensions/gsd/tests/preferences-formatting.test.ts +87 -0
  1967. package/src/resources/extensions/gsd/tests/preferences-mcp.test.ts +128 -0
  1968. package/src/resources/extensions/gsd/tests/preferences-worktree-sync.test.ts +118 -0
  1969. package/src/resources/extensions/gsd/tests/preferences.test.ts +1314 -0
  1970. package/src/resources/extensions/gsd/tests/preflight-context-draft-filter.test.ts +115 -0
  1971. package/src/resources/extensions/gsd/tests/prefs-missing-models-crash.test.ts +148 -0
  1972. package/src/resources/extensions/gsd/tests/prefs-wizard-coverage.test.ts +222 -0
  1973. package/src/resources/extensions/gsd/tests/process-task-path.test.ts +51 -0
  1974. package/src/resources/extensions/gsd/tests/progressive-planning.test.ts +620 -0
  1975. package/src/resources/extensions/gsd/tests/project-relocation-recovery.test.ts +297 -0
  1976. package/src/resources/extensions/gsd/tests/project-root-cwd-crash.test.ts +35 -0
  1977. package/src/resources/extensions/gsd/tests/projection-no-plan-overwrite.test.ts +56 -0
  1978. package/src/resources/extensions/gsd/tests/projection-regression.test.ts +277 -0
  1979. package/src/resources/extensions/gsd/tests/prompt-budget-enforcement.test.ts +677 -0
  1980. package/src/resources/extensions/gsd/tests/prompt-cache-optimizer.test.ts +326 -0
  1981. package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +574 -0
  1982. package/src/resources/extensions/gsd/tests/prompt-db.test.ts +387 -0
  1983. package/src/resources/extensions/gsd/tests/prompt-duplication-cuts.test.ts +230 -0
  1984. package/src/resources/extensions/gsd/tests/prompt-loader-extension-dir.test.ts +49 -0
  1985. package/src/resources/extensions/gsd/tests/prompt-loader-replacement.test.ts +178 -0
  1986. package/src/resources/extensions/gsd/tests/prompt-loader-working-directory.test.ts +19 -0
  1987. package/src/resources/extensions/gsd/tests/prompt-loader.test.ts +23 -0
  1988. package/src/resources/extensions/gsd/tests/prompt-ordering.test.ts +296 -0
  1989. package/src/resources/extensions/gsd/tests/prompt-path-audit.test.ts +40 -0
  1990. package/src/resources/extensions/gsd/tests/prompt-step-ordering.test.ts +91 -0
  1991. package/src/resources/extensions/gsd/tests/prompt-system-gate-coverage.test.ts +208 -0
  1992. package/src/resources/extensions/gsd/tests/prompt-tool-names.test.ts +69 -0
  1993. package/src/resources/extensions/gsd/tests/prompts-no-gitignored-test-refs.test.ts +56 -0
  1994. package/src/resources/extensions/gsd/tests/provider-errors.test.ts +744 -0
  1995. package/src/resources/extensions/gsd/tests/provider-switch-observer.test.ts +252 -0
  1996. package/src/resources/extensions/gsd/tests/python-resolver.test.ts +131 -0
  1997. package/src/resources/extensions/gsd/tests/quality-gates.test.ts +344 -0
  1998. package/src/resources/extensions/gsd/tests/query-tools-db-open.test.ts +51 -0
  1999. package/src/resources/extensions/gsd/tests/queue-auto-guard.test.ts +39 -0
  2000. package/src/resources/extensions/gsd/tests/queue-draft-detection.test.ts +101 -0
  2001. package/src/resources/extensions/gsd/tests/queue-execution-guard.test.ts +166 -0
  2002. package/src/resources/extensions/gsd/tests/queue-order.test.ts +192 -0
  2003. package/src/resources/extensions/gsd/tests/queue-prompt-rendering.test.ts +37 -0
  2004. package/src/resources/extensions/gsd/tests/queue-reorder-ui.test.ts +54 -0
  2005. package/src/resources/extensions/gsd/tests/queued-discuss-fast-path.test.ts +106 -0
  2006. package/src/resources/extensions/gsd/tests/quick-auto-guard.test.ts +36 -0
  2007. package/src/resources/extensions/gsd/tests/quick-external-gsd.test.ts +40 -0
  2008. package/src/resources/extensions/gsd/tests/quick-turn-end-cleanup.test.ts +61 -0
  2009. package/src/resources/extensions/gsd/tests/rate-limit-model-fallback.test.ts +90 -0
  2010. package/src/resources/extensions/gsd/tests/reactive-executor.test.ts +511 -0
  2011. package/src/resources/extensions/gsd/tests/reactive-graph.test.ts +363 -0
  2012. package/src/resources/extensions/gsd/tests/ready-phrase-no-files-4573.test.ts +728 -0
  2013. package/src/resources/extensions/gsd/tests/reassess-default-optin.test.ts +146 -0
  2014. package/src/resources/extensions/gsd/tests/reassess-detection.test.ts +154 -0
  2015. package/src/resources/extensions/gsd/tests/reassess-handler.test.ts +442 -0
  2016. package/src/resources/extensions/gsd/tests/reassess-prompt.test.ts +135 -0
  2017. package/src/resources/extensions/gsd/tests/reconciliation-edge-cases.test.ts +162 -0
  2018. package/src/resources/extensions/gsd/tests/recovery-attempts-reset.test.ts +144 -0
  2019. package/src/resources/extensions/gsd/tests/regex-hardening.test.ts +161 -0
  2020. package/src/resources/extensions/gsd/tests/register-extension-guard.test.ts +126 -0
  2021. package/src/resources/extensions/gsd/tests/register-hooks-compaction-checkpoint.test.ts +252 -0
  2022. package/src/resources/extensions/gsd/tests/register-hooks-depth-verification.test.ts +442 -0
  2023. package/src/resources/extensions/gsd/tests/register-shortcuts.test.ts +131 -0
  2024. package/src/resources/extensions/gsd/tests/remediation-completion-guard.test.ts +197 -0
  2025. package/src/resources/extensions/gsd/tests/remote-notification-from-desktop.test.ts +107 -0
  2026. package/src/resources/extensions/gsd/tests/remote-questions.test.ts +774 -0
  2027. package/src/resources/extensions/gsd/tests/remote-status.test.ts +99 -0
  2028. package/src/resources/extensions/gsd/tests/reopen-slice.test.ts +155 -0
  2029. package/src/resources/extensions/gsd/tests/reopen-task.test.ts +165 -0
  2030. package/src/resources/extensions/gsd/tests/replan-handler.test.ts +410 -0
  2031. package/src/resources/extensions/gsd/tests/replan-slice.test.ts +609 -0
  2032. package/src/resources/extensions/gsd/tests/repo-identity-worktree.test.ts +258 -0
  2033. package/src/resources/extensions/gsd/tests/repository-registry.test.ts +101 -0
  2034. package/src/resources/extensions/gsd/tests/require-slice-discussion-dispatch.test.ts +170 -0
  2035. package/src/resources/extensions/gsd/tests/requirements.test.ts +110 -0
  2036. package/src/resources/extensions/gsd/tests/research-milestone-composer.test.ts +132 -0
  2037. package/src/resources/extensions/gsd/tests/resolve-ts-hooks.mjs +23 -0
  2038. package/src/resources/extensions/gsd/tests/resolve-ts.mjs +9 -0
  2039. package/src/resources/extensions/gsd/tests/resource-loader-import-path.test.ts +50 -0
  2040. package/src/resources/extensions/gsd/tests/restore-tools-after-discuss.test.ts +65 -0
  2041. package/src/resources/extensions/gsd/tests/resume-dispatch-worktree.test.ts +102 -0
  2042. package/src/resources/extensions/gsd/tests/resume-missing-worktree-warning.test.ts +209 -0
  2043. package/src/resources/extensions/gsd/tests/retry-diagnostic-reasoning.test.ts +161 -0
  2044. package/src/resources/extensions/gsd/tests/retry-state-reset.test.ts +305 -0
  2045. package/src/resources/extensions/gsd/tests/rewrite-count-persist.test.ts +82 -0
  2046. package/src/resources/extensions/gsd/tests/rewrite-docs-abandon-detect.test.ts +195 -0
  2047. package/src/resources/extensions/gsd/tests/right-sized-workflow-prompts.test.ts +213 -0
  2048. package/src/resources/extensions/gsd/tests/roadmap-parse-regression.test.ts +399 -0
  2049. package/src/resources/extensions/gsd/tests/roadmap-slices.test.ts +464 -0
  2050. package/src/resources/extensions/gsd/tests/rogue-file-detection.test.ts +294 -0
  2051. package/src/resources/extensions/gsd/tests/routing-history.test.ts +229 -0
  2052. package/src/resources/extensions/gsd/tests/rule-registry.test.ts +411 -0
  2053. package/src/resources/extensions/gsd/tests/run-manager.test.ts +229 -0
  2054. package/src/resources/extensions/gsd/tests/run-uat-composer.test.ts +151 -0
  2055. package/src/resources/extensions/gsd/tests/run-uat-replay-cap.test.ts +94 -0
  2056. package/src/resources/extensions/gsd/tests/runtime-invariant-modules.test.ts +94 -0
  2057. package/src/resources/extensions/gsd/tests/runtime-kv.test.ts +120 -0
  2058. package/src/resources/extensions/gsd/tests/safety-harness-false-positives.test.ts +268 -0
  2059. package/src/resources/extensions/gsd/tests/save-gate-result-render.test.ts +95 -0
  2060. package/src/resources/extensions/gsd/tests/schema-v21-sequence.test.ts +413 -0
  2061. package/src/resources/extensions/gsd/tests/schema-v27-v28-sequence.test.ts +156 -0
  2062. package/src/resources/extensions/gsd/tests/schema-v9-sequence.test.ts +176 -0
  2063. package/src/resources/extensions/gsd/tests/secure-env-collect.test.ts +364 -0
  2064. package/src/resources/extensions/gsd/tests/select-resumable-milestone.test.ts +96 -0
  2065. package/src/resources/extensions/gsd/tests/service-tier.test.ts +131 -0
  2066. package/src/resources/extensions/gsd/tests/session-forensics-readonly-classification.test.ts +70 -0
  2067. package/src/resources/extensions/gsd/tests/session-lock-multipath.test.ts +166 -0
  2068. package/src/resources/extensions/gsd/tests/session-lock-regression.test.ts +379 -0
  2069. package/src/resources/extensions/gsd/tests/session-lock-transient-read.test.ts +224 -0
  2070. package/src/resources/extensions/gsd/tests/session-model-override.test.ts +40 -0
  2071. package/src/resources/extensions/gsd/tests/session-start-footer.test.ts +387 -0
  2072. package/src/resources/extensions/gsd/tests/session-switch-abort-misclassification.test.ts +304 -0
  2073. package/src/resources/extensions/gsd/tests/shared-wal.test.ts +239 -0
  2074. package/src/resources/extensions/gsd/tests/show-config-command.test.ts +58 -0
  2075. package/src/resources/extensions/gsd/tests/sidecar-queue.test.ts +182 -0
  2076. package/src/resources/extensions/gsd/tests/signal-handlers.test.ts +130 -0
  2077. package/src/resources/extensions/gsd/tests/silent-catch-diagnostics.test.ts +244 -0
  2078. package/src/resources/extensions/gsd/tests/single-writer-invariant.test.ts +180 -0
  2079. package/src/resources/extensions/gsd/tests/single-writer-v3-tool-surface.test.ts +158 -0
  2080. package/src/resources/extensions/gsd/tests/skill-activation.test.ts +352 -0
  2081. package/src/resources/extensions/gsd/tests/skill-catalog.test.ts +193 -0
  2082. package/src/resources/extensions/gsd/tests/skill-lifecycle.test.ts +126 -0
  2083. package/src/resources/extensions/gsd/tests/skill-manifest.test.ts +112 -0
  2084. package/src/resources/extensions/gsd/tests/skip-slice-cascades-tasks.test.ts +125 -0
  2085. package/src/resources/extensions/gsd/tests/skip-slice-state-rebuild.test.ts +63 -0
  2086. package/src/resources/extensions/gsd/tests/skipped-validation-completion.test.ts +144 -0
  2087. package/src/resources/extensions/gsd/tests/skipped-validation-db-atomicity.test.ts +57 -0
  2088. package/src/resources/extensions/gsd/tests/slice-cadence.test.ts +301 -0
  2089. package/src/resources/extensions/gsd/tests/slice-context-injection.test.ts +79 -0
  2090. package/src/resources/extensions/gsd/tests/slice-disk-reconcile.test.ts +187 -0
  2091. package/src/resources/extensions/gsd/tests/slice-parallel-conflict.test.ts +92 -0
  2092. package/src/resources/extensions/gsd/tests/slice-parallel-eligibility.test.ts +95 -0
  2093. package/src/resources/extensions/gsd/tests/slice-parallel-orchestrator.test.ts +348 -0
  2094. package/src/resources/extensions/gsd/tests/slice-sequence-insert.test.ts +124 -0
  2095. package/src/resources/extensions/gsd/tests/smart-entry-complete.test.ts +76 -0
  2096. package/src/resources/extensions/gsd/tests/smart-entry-draft.test.ts +33 -0
  2097. package/src/resources/extensions/gsd/tests/smart-entry-routing.test.ts +113 -0
  2098. package/src/resources/extensions/gsd/tests/sqlite-unavailable-gate.test.ts +29 -0
  2099. package/src/resources/extensions/gsd/tests/stale-dirlistcache-4648.test.ts +65 -0
  2100. package/src/resources/extensions/gsd/tests/stale-lockfile-recovery.test.ts +45 -0
  2101. package/src/resources/extensions/gsd/tests/stale-milestone-id-reservation.test.ts +79 -0
  2102. package/src/resources/extensions/gsd/tests/stale-queued-milestone.test.ts +147 -0
  2103. package/src/resources/extensions/gsd/tests/stale-slice-rows.test.ts +49 -0
  2104. package/src/resources/extensions/gsd/tests/stale-worktree-cwd.test.ts +152 -0
  2105. package/src/resources/extensions/gsd/tests/stalled-tool-recovery.test.ts +148 -0
  2106. package/src/resources/extensions/gsd/tests/start-auto-detached.test.ts +334 -0
  2107. package/src/resources/extensions/gsd/tests/stash-pop-gsd-conflict.test.ts +203 -0
  2108. package/src/resources/extensions/gsd/tests/stash-queued-context-files.test.ts +442 -0
  2109. package/src/resources/extensions/gsd/tests/state-corruption-2945.test.ts +424 -0
  2110. package/src/resources/extensions/gsd/tests/state-derivation-parity.test.ts +257 -0
  2111. package/src/resources/extensions/gsd/tests/state-machine-full-walkthrough.test.ts +1645 -0
  2112. package/src/resources/extensions/gsd/tests/state-reconciliation-drift.test.ts +1137 -0
  2113. package/src/resources/extensions/gsd/tests/state-transition-matrix.test.ts +44 -0
  2114. package/src/resources/extensions/gsd/tests/status-db-open.test.ts +42 -0
  2115. package/src/resources/extensions/gsd/tests/status-guards.test.ts +50 -0
  2116. package/src/resources/extensions/gsd/tests/steer-worktree-path.test.ts +123 -0
  2117. package/src/resources/extensions/gsd/tests/stop-auto-merge-back.test.ts +95 -0
  2118. package/src/resources/extensions/gsd/tests/stop-auto-race-null-unit.test.ts +18 -0
  2119. package/src/resources/extensions/gsd/tests/stop-backtrack.test.ts +216 -0
  2120. package/src/resources/extensions/gsd/tests/structured-data-formatter.test.ts +285 -0
  2121. package/src/resources/extensions/gsd/tests/stuck-detection-coverage.test.ts +232 -0
  2122. package/src/resources/extensions/gsd/tests/stuck-state-via-db.test.ts +197 -0
  2123. package/src/resources/extensions/gsd/tests/subagent-agent-discovery.test.ts +91 -0
  2124. package/src/resources/extensions/gsd/tests/subagent-model-dispatch.test.ts +174 -0
  2125. package/src/resources/extensions/gsd/tests/summary-render-parity.test.ts +226 -0
  2126. package/src/resources/extensions/gsd/tests/survivor-branch-complete.test.ts +121 -0
  2127. package/src/resources/extensions/gsd/tests/symlink-extension-discovery.test.ts +125 -0
  2128. package/src/resources/extensions/gsd/tests/symlink-numbered-variants.test.ts +145 -0
  2129. package/src/resources/extensions/gsd/tests/sync-lock.test.ts +153 -0
  2130. package/src/resources/extensions/gsd/tests/sync-worktree-skip-current.test.ts +40 -0
  2131. package/src/resources/extensions/gsd/tests/system-context-memory.test.ts +112 -0
  2132. package/src/resources/extensions/gsd/tests/system-context-message-routing.test.ts +99 -0
  2133. package/src/resources/extensions/gsd/tests/teardown-chdir-failure-clears-registry.test.ts +162 -0
  2134. package/src/resources/extensions/gsd/tests/teardown-cleanup-parity.test.ts +98 -0
  2135. package/src/resources/extensions/gsd/tests/teardown-failure-clears-registry.test.ts +186 -0
  2136. package/src/resources/extensions/gsd/tests/terminated-transient.test.ts +128 -0
  2137. package/src/resources/extensions/gsd/tests/test-helpers.test.ts +98 -0
  2138. package/src/resources/extensions/gsd/tests/test-helpers.ts +214 -0
  2139. package/src/resources/extensions/gsd/tests/test-utils.ts +165 -0
  2140. package/src/resources/extensions/gsd/tests/token-cost-display.test.ts +118 -0
  2141. package/src/resources/extensions/gsd/tests/token-counter.test.ts +242 -0
  2142. package/src/resources/extensions/gsd/tests/token-profile.test.ts +100 -0
  2143. package/src/resources/extensions/gsd/tests/token-tool-gating.test.ts +382 -0
  2144. package/src/resources/extensions/gsd/tests/tool-call-loop-guard.test.ts +179 -0
  2145. package/src/resources/extensions/gsd/tests/tool-compatibility.test.ts +306 -0
  2146. package/src/resources/extensions/gsd/tests/tool-invocation-error-loop-break.test.ts +211 -0
  2147. package/src/resources/extensions/gsd/tests/tool-naming.test.ts +155 -0
  2148. package/src/resources/extensions/gsd/tests/tool-param-optionality.test.ts +383 -0
  2149. package/src/resources/extensions/gsd/tests/triage-dispatch.test.ts +138 -0
  2150. package/src/resources/extensions/gsd/tests/triage-resolution.test.ts +612 -0
  2151. package/src/resources/extensions/gsd/tests/tui-header-lifecycle.test.ts +330 -0
  2152. package/src/resources/extensions/gsd/tests/tui-render-kit.test.ts +88 -0
  2153. package/src/resources/extensions/gsd/tests/turn-epoch.test.ts +153 -0
  2154. package/src/resources/extensions/gsd/tests/uat-stuck-loop-orphaned-worktree.test.ts +289 -0
  2155. package/src/resources/extensions/gsd/tests/unborn-branch.test.ts +85 -0
  2156. package/src/resources/extensions/gsd/tests/undo.test.ts +462 -0
  2157. package/src/resources/extensions/gsd/tests/unique-milestone-ids.test.ts +203 -0
  2158. package/src/resources/extensions/gsd/tests/unit-context-composer.test.ts +529 -0
  2159. package/src/resources/extensions/gsd/tests/unit-context-manifest.test.ts +462 -0
  2160. package/src/resources/extensions/gsd/tests/unit-dispatches.test.ts +326 -0
  2161. package/src/resources/extensions/gsd/tests/unit-ownership.test.ts +258 -0
  2162. package/src/resources/extensions/gsd/tests/unit-runtime.test.ts +335 -0
  2163. package/src/resources/extensions/gsd/tests/unmerged-milestone-guard.test.ts +112 -0
  2164. package/src/resources/extensions/gsd/tests/unstructured-continue-context-injection.test.ts +67 -0
  2165. package/src/resources/extensions/gsd/tests/uok-audit-unified.test.ts +101 -0
  2166. package/src/resources/extensions/gsd/tests/uok-contracts.test.ts +245 -0
  2167. package/src/resources/extensions/gsd/tests/uok-execution-graph.test.ts +85 -0
  2168. package/src/resources/extensions/gsd/tests/uok-flags.test.ts +69 -0
  2169. package/src/resources/extensions/gsd/tests/uok-gate-runner.test.ts +145 -0
  2170. package/src/resources/extensions/gsd/tests/uok-gitops-turn-action.test.ts +241 -0
  2171. package/src/resources/extensions/gsd/tests/uok-gitops-wiring.test.ts +58 -0
  2172. package/src/resources/extensions/gsd/tests/uok-kernel-path.test.ts +178 -0
  2173. package/src/resources/extensions/gsd/tests/uok-loop-adapter-writer.test.ts +163 -0
  2174. package/src/resources/extensions/gsd/tests/uok-model-policy.test.ts +89 -0
  2175. package/src/resources/extensions/gsd/tests/uok-parity-report.test.ts +42 -0
  2176. package/src/resources/extensions/gsd/tests/uok-plan-v2-wiring.test.ts +262 -0
  2177. package/src/resources/extensions/gsd/tests/uok-preferences.test.ts +42 -0
  2178. package/src/resources/extensions/gsd/tests/uok-writer.test.ts +75 -0
  2179. package/src/resources/extensions/gsd/tests/update-command.test.ts +86 -0
  2180. package/src/resources/extensions/gsd/tests/vacuous-truth-slices.test.ts +115 -0
  2181. package/src/resources/extensions/gsd/tests/vacuum-recovery.test.ts +154 -0
  2182. package/src/resources/extensions/gsd/tests/validate-directory.test.ts +269 -0
  2183. package/src/resources/extensions/gsd/tests/validate-extension-package.test.ts +168 -0
  2184. package/src/resources/extensions/gsd/tests/validate-milestone-prompt-verification-classes.test.ts +21 -0
  2185. package/src/resources/extensions/gsd/tests/validate-milestone-stuck-guard.test.ts +300 -0
  2186. package/src/resources/extensions/gsd/tests/validate-milestone-write-order.test.ts +371 -0
  2187. package/src/resources/extensions/gsd/tests/validate-milestone.test.ts +766 -0
  2188. package/src/resources/extensions/gsd/tests/validation-block-guard.test.ts +104 -0
  2189. package/src/resources/extensions/gsd/tests/validation-gate-patterns.test.ts +178 -0
  2190. package/src/resources/extensions/gsd/tests/validation.test.ts +72 -0
  2191. package/src/resources/extensions/gsd/tests/validator-scope-parity.test.ts +239 -0
  2192. package/src/resources/extensions/gsd/tests/verdict-parser.test.ts +156 -0
  2193. package/src/resources/extensions/gsd/tests/verification-evidence.test.ts +601 -0
  2194. package/src/resources/extensions/gsd/tests/verification-gate.test.ts +1265 -0
  2195. package/src/resources/extensions/gsd/tests/verification-operational-gate.test.ts +112 -0
  2196. package/src/resources/extensions/gsd/tests/verification-retry-policy.test.ts +83 -0
  2197. package/src/resources/extensions/gsd/tests/verification-verdict.test.ts +78 -0
  2198. package/src/resources/extensions/gsd/tests/verify-artifact-tightened.test.ts +204 -0
  2199. package/src/resources/extensions/gsd/tests/visualizer-critical-path.test.ts +109 -0
  2200. package/src/resources/extensions/gsd/tests/visualizer-data.test.ts +84 -0
  2201. package/src/resources/extensions/gsd/tests/visualizer-overlay.test.ts +359 -0
  2202. package/src/resources/extensions/gsd/tests/visualizer-views.test.ts +716 -0
  2203. package/src/resources/extensions/gsd/tests/wave1-critical-regressions.test.ts +49 -0
  2204. package/src/resources/extensions/gsd/tests/wave2-events-regressions.test.ts +48 -0
  2205. package/src/resources/extensions/gsd/tests/wave3-session-regressions.test.ts +47 -0
  2206. package/src/resources/extensions/gsd/tests/wave4-write-safety-regressions.test.ts +70 -0
  2207. package/src/resources/extensions/gsd/tests/wave5-consistency-regressions.test.ts +165 -0
  2208. package/src/resources/extensions/gsd/tests/windows-path-normalization.test.ts +97 -0
  2209. package/src/resources/extensions/gsd/tests/worker-model-override.test.ts +56 -0
  2210. package/src/resources/extensions/gsd/tests/worker-registry.test.ts +146 -0
  2211. package/src/resources/extensions/gsd/tests/workflow-custom-engine-dispatch-outcome.test.ts +55 -0
  2212. package/src/resources/extensions/gsd/tests/workflow-custom-engine-iteration.test.ts +93 -0
  2213. package/src/resources/extensions/gsd/tests/workflow-custom-engine-reconcile-outcome.test.ts +108 -0
  2214. package/src/resources/extensions/gsd/tests/workflow-custom-engine-reconcile.test.ts +146 -0
  2215. package/src/resources/extensions/gsd/tests/workflow-custom-engine-retry.test.ts +136 -0
  2216. package/src/resources/extensions/gsd/tests/workflow-custom-engine-verify-outcome.test.ts +95 -0
  2217. package/src/resources/extensions/gsd/tests/workflow-dispatch-claim.test.ts +313 -0
  2218. package/src/resources/extensions/gsd/tests/workflow-dispatch-ledger.test.ts +82 -0
  2219. package/src/resources/extensions/gsd/tests/workflow-events.test.ts +205 -0
  2220. package/src/resources/extensions/gsd/tests/workflow-install.test.ts +113 -0
  2221. package/src/resources/extensions/gsd/tests/workflow-iteration-completion.test.ts +44 -0
  2222. package/src/resources/extensions/gsd/tests/workflow-journal-reporter.test.ts +49 -0
  2223. package/src/resources/extensions/gsd/tests/workflow-kernel.test.ts +630 -0
  2224. package/src/resources/extensions/gsd/tests/workflow-logger-audit.test.ts +123 -0
  2225. package/src/resources/extensions/gsd/tests/workflow-logger-wiring.test.ts +92 -0
  2226. package/src/resources/extensions/gsd/tests/workflow-logger.test.ts +411 -0
  2227. package/src/resources/extensions/gsd/tests/workflow-manifest.test.ts +336 -0
  2228. package/src/resources/extensions/gsd/tests/workflow-mcp-auto-prep.test.ts +76 -0
  2229. package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +771 -0
  2230. package/src/resources/extensions/gsd/tests/workflow-memory-pressure.test.ts +91 -0
  2231. package/src/resources/extensions/gsd/tests/workflow-phase-reporter.test.ts +40 -0
  2232. package/src/resources/extensions/gsd/tests/workflow-plugins.test.ts +310 -0
  2233. package/src/resources/extensions/gsd/tests/workflow-projections.test.ts +405 -0
  2234. package/src/resources/extensions/gsd/tests/workflow-protocol-excerpt.test.ts +99 -0
  2235. package/src/resources/extensions/gsd/tests/workflow-reconcile.test.ts +91 -0
  2236. package/src/resources/extensions/gsd/tests/workflow-session-lock.test.ts +135 -0
  2237. package/src/resources/extensions/gsd/tests/workflow-sidecar-iteration.test.ts +110 -0
  2238. package/src/resources/extensions/gsd/tests/workflow-sidecar-queue.test.ts +116 -0
  2239. package/src/resources/extensions/gsd/tests/workflow-templates.test.ts +198 -0
  2240. package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +1397 -0
  2241. package/src/resources/extensions/gsd/tests/workflow-turn-reporter.test.ts +87 -0
  2242. package/src/resources/extensions/gsd/tests/workflow-unit-dispatch.test.ts +160 -0
  2243. package/src/resources/extensions/gsd/tests/workflow-worker-heartbeat.test.ts +154 -0
  2244. package/src/resources/extensions/gsd/tests/working-output-messages.test.ts +93 -0
  2245. package/src/resources/extensions/gsd/tests/workspace-index.test.ts +38 -0
  2246. package/src/resources/extensions/gsd/tests/workspace.test.ts +196 -0
  2247. package/src/resources/extensions/gsd/tests/worktree-bugfix.test.ts +117 -0
  2248. package/src/resources/extensions/gsd/tests/worktree-db-integration.test.ts +202 -0
  2249. package/src/resources/extensions/gsd/tests/worktree-db-respawn-truncation.test.ts +219 -0
  2250. package/src/resources/extensions/gsd/tests/worktree-db-same-file.test.ts +165 -0
  2251. package/src/resources/extensions/gsd/tests/worktree-db.test.ts +440 -0
  2252. package/src/resources/extensions/gsd/tests/worktree-expected-warnings.test.ts +39 -0
  2253. package/src/resources/extensions/gsd/tests/worktree-git-pathspec.test.ts +39 -0
  2254. package/src/resources/extensions/gsd/tests/worktree-health-dispatch.test.ts +207 -0
  2255. package/src/resources/extensions/gsd/tests/worktree-health-monorepo.test.ts +109 -0
  2256. package/src/resources/extensions/gsd/tests/worktree-health.test.ts +181 -0
  2257. package/src/resources/extensions/gsd/tests/worktree-integration.test.ts +216 -0
  2258. package/src/resources/extensions/gsd/tests/worktree-journal-events.test.ts +397 -0
  2259. package/src/resources/extensions/gsd/tests/worktree-lifecycle.test.ts +992 -0
  2260. package/src/resources/extensions/gsd/tests/worktree-main-branch.test.ts +27 -0
  2261. package/src/resources/extensions/gsd/tests/worktree-manager.test.ts +290 -0
  2262. package/src/resources/extensions/gsd/tests/worktree-nested-git-safety.test.ts +110 -0
  2263. package/src/resources/extensions/gsd/tests/worktree-path-injection.test.ts +242 -0
  2264. package/src/resources/extensions/gsd/tests/worktree-post-create-hook.test.ts +165 -0
  2265. package/src/resources/extensions/gsd/tests/worktree-preferences-sync.test.ts +180 -0
  2266. package/src/resources/extensions/gsd/tests/worktree-project-root-degrade.test.ts +66 -0
  2267. package/src/resources/extensions/gsd/tests/worktree-projection-writers.test.ts +206 -0
  2268. package/src/resources/extensions/gsd/tests/worktree-root-resolution.test.ts +50 -0
  2269. package/src/resources/extensions/gsd/tests/worktree-root.test.ts +69 -0
  2270. package/src/resources/extensions/gsd/tests/worktree-safety.test.ts +417 -0
  2271. package/src/resources/extensions/gsd/tests/worktree-state-projection.test.ts +120 -0
  2272. package/src/resources/extensions/gsd/tests/worktree-submodule-safety.test.ts +228 -0
  2273. package/src/resources/extensions/gsd/tests/worktree-symlink-removal.test.ts +134 -0
  2274. package/src/resources/extensions/gsd/tests/worktree-sync-milestones.test.ts +705 -0
  2275. package/src/resources/extensions/gsd/tests/worktree-sync-overwrite-loop.test.ts +156 -0
  2276. package/src/resources/extensions/gsd/tests/worktree-sync-tasks.test.ts +85 -0
  2277. package/src/resources/extensions/gsd/tests/worktree-teardown-safety.test.ts +148 -0
  2278. package/src/resources/extensions/gsd/tests/worktree-telemetry.test.ts +283 -0
  2279. package/src/resources/extensions/gsd/tests/worktree-write-gate.test.ts +206 -0
  2280. package/src/resources/extensions/gsd/tests/worktree.test.ts +304 -0
  2281. package/src/resources/extensions/gsd/tests/write-gate-planning-unit.test.ts +476 -0
  2282. package/src/resources/extensions/gsd/tests/write-gate-predicates.test.ts +188 -0
  2283. package/src/resources/extensions/gsd/tests/write-gate.test.ts +726 -0
  2284. package/src/resources/extensions/gsd/tests/write-intercept.test.ts +76 -0
  2285. package/src/resources/extensions/gsd/tests/zero-slice-roadmap-guided.test.ts +25 -0
  2286. package/src/resources/extensions/gsd/tests/zombie-gsd-state.test.ts +81 -0
  2287. package/src/resources/extensions/gsd/token-counter.ts +83 -0
  2288. package/src/resources/extensions/gsd/tool-contract.ts +82 -0
  2289. package/src/resources/extensions/gsd/tools/complete-milestone.ts +273 -0
  2290. package/src/resources/extensions/gsd/tools/complete-slice.ts +568 -0
  2291. package/src/resources/extensions/gsd/tools/complete-task.ts +473 -0
  2292. package/src/resources/extensions/gsd/tools/context-mode-tool-result.ts +25 -0
  2293. package/src/resources/extensions/gsd/tools/exec-search-tool.ts +81 -0
  2294. package/src/resources/extensions/gsd/tools/exec-tool.ts +286 -0
  2295. package/src/resources/extensions/gsd/tools/memory-tools.ts +427 -0
  2296. package/src/resources/extensions/gsd/tools/plan-milestone.ts +370 -0
  2297. package/src/resources/extensions/gsd/tools/plan-slice.ts +443 -0
  2298. package/src/resources/extensions/gsd/tools/plan-task.ts +161 -0
  2299. package/src/resources/extensions/gsd/tools/reassess-roadmap.ts +289 -0
  2300. package/src/resources/extensions/gsd/tools/reopen-milestone.ts +152 -0
  2301. package/src/resources/extensions/gsd/tools/reopen-slice.ts +152 -0
  2302. package/src/resources/extensions/gsd/tools/reopen-task.ts +146 -0
  2303. package/src/resources/extensions/gsd/tools/replan-slice.ts +242 -0
  2304. package/src/resources/extensions/gsd/tools/resume-tool.ts +40 -0
  2305. package/src/resources/extensions/gsd/tools/skip-slice.ts +133 -0
  2306. package/src/resources/extensions/gsd/tools/validate-milestone.ts +301 -0
  2307. package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +991 -0
  2308. package/src/resources/extensions/gsd/triage-resolution.ts +578 -0
  2309. package/src/resources/extensions/gsd/triage-ui.ts +196 -0
  2310. package/src/resources/extensions/gsd/tui/render-kit.ts +153 -0
  2311. package/src/resources/extensions/gsd/types.ts +721 -0
  2312. package/src/resources/extensions/gsd/undo.ts +465 -0
  2313. package/src/resources/extensions/gsd/unit-context-composer.ts +285 -0
  2314. package/src/resources/extensions/gsd/unit-context-manifest.ts +796 -0
  2315. package/src/resources/extensions/gsd/unit-id.ts +14 -0
  2316. package/src/resources/extensions/gsd/unit-ownership.ts +275 -0
  2317. package/src/resources/extensions/gsd/unit-runtime.ts +267 -0
  2318. package/src/resources/extensions/gsd/unmerged-milestone-guard.ts +150 -0
  2319. package/src/resources/extensions/gsd/uok/audit-toggle.ts +9 -0
  2320. package/src/resources/extensions/gsd/uok/audit.ts +85 -0
  2321. package/src/resources/extensions/gsd/uok/contracts.ts +306 -0
  2322. package/src/resources/extensions/gsd/uok/dispatch-envelope.ts +60 -0
  2323. package/src/resources/extensions/gsd/uok/execution-graph.ts +263 -0
  2324. package/src/resources/extensions/gsd/uok/flags.ts +45 -0
  2325. package/src/resources/extensions/gsd/uok/gate-runner.ts +206 -0
  2326. package/src/resources/extensions/gsd/uok/gitops.ts +80 -0
  2327. package/src/resources/extensions/gsd/uok/kernel.ts +124 -0
  2328. package/src/resources/extensions/gsd/uok/loop-adapter.ts +212 -0
  2329. package/src/resources/extensions/gsd/uok/model-policy.ts +112 -0
  2330. package/src/resources/extensions/gsd/uok/parity-report.ts +84 -0
  2331. package/src/resources/extensions/gsd/uok/plan-v2.ts +209 -0
  2332. package/src/resources/extensions/gsd/uok/timeline.ts +158 -0
  2333. package/src/resources/extensions/gsd/uok/writer.ts +113 -0
  2334. package/src/resources/extensions/gsd/user-input-boundary.ts +166 -0
  2335. package/src/resources/extensions/gsd/validate-directory.ts +186 -0
  2336. package/src/resources/extensions/gsd/validation-block-guard.ts +83 -0
  2337. package/src/resources/extensions/gsd/validation.ts +45 -0
  2338. package/src/resources/extensions/gsd/verdict-parser.ts +110 -0
  2339. package/src/resources/extensions/gsd/verification-evidence.ts +270 -0
  2340. package/src/resources/extensions/gsd/verification-gate.ts +848 -0
  2341. package/src/resources/extensions/gsd/verification-verdict.ts +47 -0
  2342. package/src/resources/extensions/gsd/visualizer-data.ts +953 -0
  2343. package/src/resources/extensions/gsd/visualizer-overlay.ts +570 -0
  2344. package/src/resources/extensions/gsd/visualizer-views.ts +1229 -0
  2345. package/src/resources/extensions/gsd/watch/header-renderer.ts +331 -0
  2346. package/src/resources/extensions/gsd/watch/splash-palette.ts +11 -0
  2347. package/src/resources/extensions/gsd/workflow-dispatch.ts +106 -0
  2348. package/src/resources/extensions/gsd/workflow-engine.ts +38 -0
  2349. package/src/resources/extensions/gsd/workflow-events.ts +166 -0
  2350. package/src/resources/extensions/gsd/workflow-install.ts +422 -0
  2351. package/src/resources/extensions/gsd/workflow-logger.ts +381 -0
  2352. package/src/resources/extensions/gsd/workflow-manifest.ts +260 -0
  2353. package/src/resources/extensions/gsd/workflow-mcp-auto-prep.ts +60 -0
  2354. package/src/resources/extensions/gsd/workflow-mcp.ts +459 -0
  2355. package/src/resources/extensions/gsd/workflow-migration.ts +340 -0
  2356. package/src/resources/extensions/gsd/workflow-plugins.ts +402 -0
  2357. package/src/resources/extensions/gsd/workflow-projections.ts +567 -0
  2358. package/src/resources/extensions/gsd/workflow-protocol.ts +160 -0
  2359. package/src/resources/extensions/gsd/workflow-reconcile.ts +681 -0
  2360. package/src/resources/extensions/gsd/workflow-templates/accessibility-audit.md +88 -0
  2361. package/src/resources/extensions/gsd/workflow-templates/api-breaking-change.md +117 -0
  2362. package/src/resources/extensions/gsd/workflow-templates/bugfix.md +88 -0
  2363. package/src/resources/extensions/gsd/workflow-templates/changelog-gen.md +82 -0
  2364. package/src/resources/extensions/gsd/workflow-templates/ci-bootstrap.md +144 -0
  2365. package/src/resources/extensions/gsd/workflow-templates/dead-code.md +81 -0
  2366. package/src/resources/extensions/gsd/workflow-templates/dep-upgrade.md +75 -0
  2367. package/src/resources/extensions/gsd/workflow-templates/docs-sync.yaml +76 -0
  2368. package/src/resources/extensions/gsd/workflow-templates/env-audit.yaml +88 -0
  2369. package/src/resources/extensions/gsd/workflow-templates/full-project.md +42 -0
  2370. package/src/resources/extensions/gsd/workflow-templates/hotfix.md +46 -0
  2371. package/src/resources/extensions/gsd/workflow-templates/issue-triage.md +84 -0
  2372. package/src/resources/extensions/gsd/workflow-templates/observability-setup.md +133 -0
  2373. package/src/resources/extensions/gsd/workflow-templates/onboarding-check.md +74 -0
  2374. package/src/resources/extensions/gsd/workflow-templates/performance-audit.md +125 -0
  2375. package/src/resources/extensions/gsd/workflow-templates/pr-review.md +67 -0
  2376. package/src/resources/extensions/gsd/workflow-templates/pr-triage.md +83 -0
  2377. package/src/resources/extensions/gsd/workflow-templates/refactor.md +84 -0
  2378. package/src/resources/extensions/gsd/workflow-templates/registry.json +269 -0
  2379. package/src/resources/extensions/gsd/workflow-templates/release.md +118 -0
  2380. package/src/resources/extensions/gsd/workflow-templates/rename-symbol.yaml +99 -0
  2381. package/src/resources/extensions/gsd/workflow-templates/security-audit.md +74 -0
  2382. package/src/resources/extensions/gsd/workflow-templates/small-feature.md +82 -0
  2383. package/src/resources/extensions/gsd/workflow-templates/spike.md +76 -0
  2384. package/src/resources/extensions/gsd/workflow-templates/test-backfill.yaml +73 -0
  2385. package/src/resources/extensions/gsd/workflow-templates.ts +278 -0
  2386. package/src/resources/extensions/gsd/working-output-messages.ts +120 -0
  2387. package/src/resources/extensions/gsd/workspace-index.ts +277 -0
  2388. package/src/resources/extensions/gsd/workspace.ts +95 -0
  2389. package/src/resources/extensions/gsd/worktree-command-bootstrap.ts +46 -0
  2390. package/src/resources/extensions/gsd/worktree-command.ts +834 -0
  2391. package/src/resources/extensions/gsd/worktree-health.ts +178 -0
  2392. package/src/resources/extensions/gsd/worktree-lifecycle.ts +1989 -0
  2393. package/src/resources/extensions/gsd/worktree-manager.ts +909 -0
  2394. package/src/resources/extensions/gsd/worktree-root.ts +182 -0
  2395. package/src/resources/extensions/gsd/worktree-safety.ts +329 -0
  2396. package/src/resources/extensions/gsd/worktree-session-state.ts +35 -0
  2397. package/src/resources/extensions/gsd/worktree-state-projection.ts +447 -0
  2398. package/src/resources/extensions/gsd/worktree-telemetry.ts +366 -0
  2399. package/src/resources/extensions/gsd/worktree.ts +235 -0
  2400. package/src/resources/extensions/gsd/write-intercept.ts +99 -0
  2401. package/src/resources/extensions/mac-tools/extension-manifest.json +16 -0
  2402. package/src/resources/extensions/mac-tools/index.ts +852 -0
  2403. package/src/resources/extensions/mac-tools/swift-cli/Package.swift +22 -0
  2404. package/src/resources/extensions/mac-tools/swift-cli/Sources/main.swift +1318 -0
  2405. package/src/resources/extensions/mcp-client/auth.ts +160 -0
  2406. package/src/resources/extensions/mcp-client/index.ts +526 -0
  2407. package/src/resources/extensions/mcp-client/manager.ts +516 -0
  2408. package/src/resources/extensions/mcp-client/tests/global-config.test.ts +91 -0
  2409. package/src/resources/extensions/mcp-client/tests/manager.test.ts +165 -0
  2410. package/src/resources/extensions/mcp-client/tests/server-name-spaces.test.ts +89 -0
  2411. package/src/resources/extensions/ollama/index.ts +158 -0
  2412. package/src/resources/extensions/ollama/model-capabilities.ts +186 -0
  2413. package/src/resources/extensions/ollama/ndjson-stream.ts +63 -0
  2414. package/src/resources/extensions/ollama/ollama-auth-mode.test.ts +128 -0
  2415. package/src/resources/extensions/ollama/ollama-chat-provider.ts +459 -0
  2416. package/src/resources/extensions/ollama/ollama-client.ts +262 -0
  2417. package/src/resources/extensions/ollama/ollama-commands.ts +248 -0
  2418. package/src/resources/extensions/ollama/ollama-discovery.ts +134 -0
  2419. package/src/resources/extensions/ollama/ollama-status-indicator.test.ts +215 -0
  2420. package/src/resources/extensions/ollama/ollama-tool.ts +287 -0
  2421. package/src/resources/extensions/ollama/tests/model-capabilities.test.ts +258 -0
  2422. package/src/resources/extensions/ollama/tests/ollama-chat-provider-stream.test.ts +82 -0
  2423. package/src/resources/extensions/ollama/tests/ollama-client-timeout-env.test.ts +147 -0
  2424. package/src/resources/extensions/ollama/tests/ollama-client.test.ts +38 -0
  2425. package/src/resources/extensions/ollama/tests/ollama-discovery.test.ts +55 -0
  2426. package/src/resources/extensions/ollama/thinking-parser.ts +116 -0
  2427. package/src/resources/extensions/ollama/types.ts +153 -0
  2428. package/src/resources/extensions/package.json +3 -0
  2429. package/src/resources/extensions/remote-questions/commands.ts +480 -0
  2430. package/src/resources/extensions/remote-questions/config.ts +126 -0
  2431. package/src/resources/extensions/remote-questions/discord-adapter.ts +148 -0
  2432. package/src/resources/extensions/remote-questions/extension-manifest.json +11 -0
  2433. package/src/resources/extensions/remote-questions/format.ts +315 -0
  2434. package/src/resources/extensions/remote-questions/http-client.ts +76 -0
  2435. package/src/resources/extensions/remote-questions/manager.ts +270 -0
  2436. package/src/resources/extensions/remote-questions/mod.ts +16 -0
  2437. package/src/resources/extensions/remote-questions/notify.ts +90 -0
  2438. package/src/resources/extensions/remote-questions/remote-command.ts +437 -0
  2439. package/src/resources/extensions/remote-questions/slack-adapter.ts +141 -0
  2440. package/src/resources/extensions/remote-questions/status.ts +31 -0
  2441. package/src/resources/extensions/remote-questions/store.ts +81 -0
  2442. package/src/resources/extensions/remote-questions/telegram-adapter.ts +231 -0
  2443. package/src/resources/extensions/remote-questions/tests/command-polling.test.ts +256 -0
  2444. package/src/resources/extensions/remote-questions/tests/remote-answer-normalization.test.ts +92 -0
  2445. package/src/resources/extensions/remote-questions/tests/telegram-commands.test.ts +267 -0
  2446. package/src/resources/extensions/remote-questions/types.ts +102 -0
  2447. package/src/resources/extensions/search-the-web/cache.ts +78 -0
  2448. package/src/resources/extensions/search-the-web/command-search-provider.ts +105 -0
  2449. package/src/resources/extensions/search-the-web/extension-manifest.json +13 -0
  2450. package/src/resources/extensions/search-the-web/format.ts +258 -0
  2451. package/src/resources/extensions/search-the-web/http.ts +238 -0
  2452. package/src/resources/extensions/search-the-web/index.ts +64 -0
  2453. package/src/resources/extensions/search-the-web/native-search.ts +276 -0
  2454. package/src/resources/extensions/search-the-web/provider.ts +150 -0
  2455. package/src/resources/extensions/search-the-web/tavily.ts +116 -0
  2456. package/src/resources/extensions/search-the-web/tool-fetch-page.ts +589 -0
  2457. package/src/resources/extensions/search-the-web/tool-llm-context.ts +608 -0
  2458. package/src/resources/extensions/search-the-web/tool-search.ts +677 -0
  2459. package/src/resources/extensions/search-the-web/url-utils.ts +144 -0
  2460. package/src/resources/extensions/shared/cmux-events.ts +59 -0
  2461. package/src/resources/extensions/shared/confirm-ui.ts +126 -0
  2462. package/src/resources/extensions/shared/format-utils.ts +99 -0
  2463. package/src/resources/extensions/shared/frontmatter.ts +117 -0
  2464. package/src/resources/extensions/shared/gsd-phase-state.ts +95 -0
  2465. package/src/resources/extensions/shared/html-shell.ts +412 -0
  2466. package/src/resources/extensions/shared/interview-ui.ts +848 -0
  2467. package/src/resources/extensions/shared/layout-utils.ts +75 -0
  2468. package/src/resources/extensions/shared/mod.ts +31 -0
  2469. package/src/resources/extensions/shared/next-action-ui.ts +226 -0
  2470. package/src/resources/extensions/shared/path-display.ts +19 -0
  2471. package/src/resources/extensions/shared/rtk-session-stats.ts +248 -0
  2472. package/src/resources/extensions/shared/rtk-shared.ts +58 -0
  2473. package/src/resources/extensions/shared/rtk.ts +98 -0
  2474. package/src/resources/extensions/shared/sanitize.ts +55 -0
  2475. package/src/resources/extensions/shared/terminal.ts +28 -0
  2476. package/src/resources/extensions/shared/tests/ask-user-freetext.test.ts +161 -0
  2477. package/src/resources/extensions/shared/tests/format-utils.test.ts +155 -0
  2478. package/src/resources/extensions/shared/tests/gsd-phase-state.test.ts +90 -0
  2479. package/src/resources/extensions/shared/tests/interview-notes-loop.test.ts +198 -0
  2480. package/src/resources/extensions/shared/tests/interview-preview.test.ts +185 -0
  2481. package/src/resources/extensions/shared/tests/next-action-ui-hasui.test.ts +144 -0
  2482. package/src/resources/extensions/shared/tests/preview-layout.test.ts +120 -0
  2483. package/src/resources/extensions/shared/tui.ts +11 -0
  2484. package/src/resources/extensions/shared/ui.ts +401 -0
  2485. package/src/resources/extensions/slash-commands/audit.ts +89 -0
  2486. package/src/resources/extensions/slash-commands/clear.ts +10 -0
  2487. package/src/resources/extensions/slash-commands/create-extension.ts +311 -0
  2488. package/src/resources/extensions/slash-commands/create-slash-command.ts +234 -0
  2489. package/src/resources/extensions/slash-commands/extension-manifest.json +11 -0
  2490. package/src/resources/extensions/slash-commands/index.ts +12 -0
  2491. package/src/resources/extensions/subagent/agents.ts +166 -0
  2492. package/src/resources/extensions/subagent/extension-manifest.json +13 -0
  2493. package/src/resources/extensions/subagent/index.ts +1938 -0
  2494. package/src/resources/extensions/subagent/isolation.ts +504 -0
  2495. package/src/resources/extensions/subagent/launch.ts +131 -0
  2496. package/src/resources/extensions/subagent/run-store.ts +218 -0
  2497. package/src/resources/extensions/subagent/tests/agents-conflicts.test.ts +33 -0
  2498. package/src/resources/extensions/subagent/tests/launch.test.ts +115 -0
  2499. package/src/resources/extensions/subagent/tests/model-override.test.ts +55 -0
  2500. package/src/resources/extensions/subagent/tests/run-store.test.ts +111 -0
  2501. package/src/resources/extensions/subagent/worker-registry.ts +100 -0
  2502. package/src/resources/extensions/ttsr/extension-manifest.json +11 -0
  2503. package/src/resources/extensions/ttsr/index.ts +168 -0
  2504. package/src/resources/extensions/ttsr/rule-loader.ts +75 -0
  2505. package/src/resources/extensions/ttsr/ttsr-interrupt.md +6 -0
  2506. package/src/resources/extensions/ttsr/ttsr-manager.ts +465 -0
  2507. package/src/resources/extensions/universal-config/discovery.ts +104 -0
  2508. package/src/resources/extensions/universal-config/extension-manifest.json +13 -0
  2509. package/src/resources/extensions/universal-config/format.ts +191 -0
  2510. package/src/resources/extensions/universal-config/index.ts +120 -0
  2511. package/src/resources/extensions/universal-config/package.json +11 -0
  2512. package/src/resources/extensions/universal-config/scanners.ts +642 -0
  2513. package/src/resources/extensions/universal-config/tests/discovery.test.ts +119 -0
  2514. package/src/resources/extensions/universal-config/tests/format.test.ts +127 -0
  2515. package/src/resources/extensions/universal-config/tests/scanners.test.ts +456 -0
  2516. package/src/resources/extensions/universal-config/tools.ts +60 -0
  2517. package/src/resources/extensions/universal-config/types.ts +135 -0
  2518. package/src/resources/extensions/visual-brief/artifact-policy.ts +41 -0
  2519. package/src/resources/extensions/visual-brief/extension-manifest.json +8 -0
  2520. package/src/resources/extensions/visual-brief/index.ts +8 -0
  2521. package/src/resources/extensions/visual-brief/page-contract.ts +136 -0
  2522. package/src/resources/extensions/visual-brief/prompts.ts +183 -0
  2523. package/src/resources/extensions/visual-brief/tests/visual-brief.test.ts +212 -0
  2524. package/src/resources/extensions/voice/extension-manifest.json +12 -0
  2525. package/src/resources/extensions/voice/index.ts +264 -0
  2526. package/src/resources/extensions/voice/linux-ready.ts +86 -0
  2527. package/src/resources/extensions/voice/speech-recognizer.py +504 -0
  2528. package/src/resources/extensions/voice/speech-recognizer.swift +154 -0
  2529. package/src/resources/extensions/voice/tests/linux-ready.test.ts +140 -0
  2530. package/src/resources/skills/accessibility/SKILL.md +522 -0
  2531. package/src/resources/skills/accessibility/references/WCAG.md +162 -0
  2532. package/src/resources/skills/agent-browser/SKILL.md +517 -0
  2533. package/src/resources/skills/agent-browser/references/authentication.md +202 -0
  2534. package/src/resources/skills/agent-browser/references/commands.md +263 -0
  2535. package/src/resources/skills/agent-browser/references/profiling.md +120 -0
  2536. package/src/resources/skills/agent-browser/references/proxy-support.md +194 -0
  2537. package/src/resources/skills/agent-browser/references/session-management.md +193 -0
  2538. package/src/resources/skills/agent-browser/references/snapshot-refs.md +194 -0
  2539. package/src/resources/skills/agent-browser/references/video-recording.md +173 -0
  2540. package/src/resources/skills/agent-browser/templates/authenticated-session.sh +105 -0
  2541. package/src/resources/skills/agent-browser/templates/capture-workflow.sh +69 -0
  2542. package/src/resources/skills/agent-browser/templates/form-automation.sh +62 -0
  2543. package/src/resources/skills/api-design/SKILL.md +190 -0
  2544. package/src/resources/skills/best-practices/SKILL.md +583 -0
  2545. package/src/resources/skills/btw/SKILL.md +42 -0
  2546. package/src/resources/skills/code-optimizer/SKILL.md +160 -0
  2547. package/src/resources/skills/code-optimizer/references/algorithmic-complexity.md +66 -0
  2548. package/src/resources/skills/code-optimizer/references/build-compilation.md +90 -0
  2549. package/src/resources/skills/code-optimizer/references/bundle-dependencies.md +82 -0
  2550. package/src/resources/skills/code-optimizer/references/caching-memoization.md +76 -0
  2551. package/src/resources/skills/code-optimizer/references/concurrency-async.md +80 -0
  2552. package/src/resources/skills/code-optimizer/references/config-infra.md +71 -0
  2553. package/src/resources/skills/code-optimizer/references/data-structures.md +80 -0
  2554. package/src/resources/skills/code-optimizer/references/database-queries.md +76 -0
  2555. package/src/resources/skills/code-optimizer/references/dead-code-redundancy.md +84 -0
  2556. package/src/resources/skills/code-optimizer/references/error-resilience.md +80 -0
  2557. package/src/resources/skills/code-optimizer/references/io-network.md +89 -0
  2558. package/src/resources/skills/code-optimizer/references/logging-observability.md +64 -0
  2559. package/src/resources/skills/code-optimizer/references/memory-resources.md +66 -0
  2560. package/src/resources/skills/code-optimizer/references/rendering-ui.md +90 -0
  2561. package/src/resources/skills/code-optimizer/references/security-performance.md +68 -0
  2562. package/src/resources/skills/core-web-vitals/SKILL.md +441 -0
  2563. package/src/resources/skills/core-web-vitals/references/LCP.md +208 -0
  2564. package/src/resources/skills/create-gsd-extension/SKILL.md +93 -0
  2565. package/src/resources/skills/create-gsd-extension/references/compaction-session-control.md +77 -0
  2566. package/src/resources/skills/create-gsd-extension/references/custom-commands.md +139 -0
  2567. package/src/resources/skills/create-gsd-extension/references/custom-rendering.md +108 -0
  2568. package/src/resources/skills/create-gsd-extension/references/custom-tools.md +183 -0
  2569. package/src/resources/skills/create-gsd-extension/references/custom-ui.md +490 -0
  2570. package/src/resources/skills/create-gsd-extension/references/events-reference.md +126 -0
  2571. package/src/resources/skills/create-gsd-extension/references/extension-lifecycle.md +64 -0
  2572. package/src/resources/skills/create-gsd-extension/references/extensionapi-reference.md +75 -0
  2573. package/src/resources/skills/create-gsd-extension/references/extensioncontext-reference.md +53 -0
  2574. package/src/resources/skills/create-gsd-extension/references/key-rules-gotchas.md +37 -0
  2575. package/src/resources/skills/create-gsd-extension/references/mode-behavior.md +32 -0
  2576. package/src/resources/skills/create-gsd-extension/references/model-provider-management.md +89 -0
  2577. package/src/resources/skills/create-gsd-extension/references/packaging-distribution.md +55 -0
  2578. package/src/resources/skills/create-gsd-extension/references/remote-execution-overrides.md +90 -0
  2579. package/src/resources/skills/create-gsd-extension/references/state-management.md +70 -0
  2580. package/src/resources/skills/create-gsd-extension/references/system-prompt-modification.md +52 -0
  2581. package/src/resources/skills/create-gsd-extension/templates/extension-skeleton.ts +51 -0
  2582. package/src/resources/skills/create-gsd-extension/templates/stateful-tool-skeleton.ts +143 -0
  2583. package/src/resources/skills/create-gsd-extension/templates/templates.test.ts +104 -0
  2584. package/src/resources/skills/create-gsd-extension/workflows/add-capability.md +57 -0
  2585. package/src/resources/skills/create-gsd-extension/workflows/create-extension.md +176 -0
  2586. package/src/resources/skills/create-gsd-extension/workflows/debug-extension.md +76 -0
  2587. package/src/resources/skills/create-mcp-server/SKILL.md +121 -0
  2588. package/src/resources/skills/create-skill/SKILL.md +186 -0
  2589. package/src/resources/skills/create-skill/references/api-security.md +226 -0
  2590. package/src/resources/skills/create-skill/references/be-clear-and-direct.md +531 -0
  2591. package/src/resources/skills/create-skill/references/common-patterns.md +595 -0
  2592. package/src/resources/skills/create-skill/references/core-principles.md +437 -0
  2593. package/src/resources/skills/create-skill/references/executable-code.md +175 -0
  2594. package/src/resources/skills/create-skill/references/gsd-skill-ecosystem.md +68 -0
  2595. package/src/resources/skills/create-skill/references/iteration-and-testing.md +474 -0
  2596. package/src/resources/skills/create-skill/references/recommended-structure.md +168 -0
  2597. package/src/resources/skills/create-skill/references/skill-structure.md +372 -0
  2598. package/src/resources/skills/create-skill/references/use-xml-tags.md +466 -0
  2599. package/src/resources/skills/create-skill/references/using-scripts.md +113 -0
  2600. package/src/resources/skills/create-skill/references/using-templates.md +112 -0
  2601. package/src/resources/skills/create-skill/references/workflows-and-validation.md +510 -0
  2602. package/src/resources/skills/create-skill/templates/router-skill.md +73 -0
  2603. package/src/resources/skills/create-skill/templates/simple-skill.md +33 -0
  2604. package/src/resources/skills/create-skill/workflows/add-reference.md +96 -0
  2605. package/src/resources/skills/create-skill/workflows/add-script.md +93 -0
  2606. package/src/resources/skills/create-skill/workflows/add-template.md +74 -0
  2607. package/src/resources/skills/create-skill/workflows/add-workflow.md +120 -0
  2608. package/src/resources/skills/create-skill/workflows/audit-skill.md +148 -0
  2609. package/src/resources/skills/create-skill/workflows/create-new-skill.md +196 -0
  2610. package/src/resources/skills/create-skill/workflows/get-guidance.md +121 -0
  2611. package/src/resources/skills/create-skill/workflows/upgrade-to-router.md +161 -0
  2612. package/src/resources/skills/create-skill/workflows/verify-skill.md +204 -0
  2613. package/src/resources/skills/create-workflow/SKILL.md +130 -0
  2614. package/src/resources/skills/create-workflow/references/feature-patterns.md +128 -0
  2615. package/src/resources/skills/create-workflow/references/verification-policies.md +76 -0
  2616. package/src/resources/skills/create-workflow/references/yaml-schema-v1.md +46 -0
  2617. package/src/resources/skills/create-workflow/templates/blog-post-pipeline.yaml +60 -0
  2618. package/src/resources/skills/create-workflow/templates/code-audit.yaml +60 -0
  2619. package/src/resources/skills/create-workflow/templates/release-checklist.yaml +66 -0
  2620. package/src/resources/skills/create-workflow/templates/workflow-definition.yaml +32 -0
  2621. package/src/resources/skills/create-workflow/workflows/create-from-scratch.md +104 -0
  2622. package/src/resources/skills/create-workflow/workflows/create-from-template.md +72 -0
  2623. package/src/resources/skills/debug-like-expert/SKILL.md +231 -0
  2624. package/src/resources/skills/debug-like-expert/references/debugging-mindset.md +253 -0
  2625. package/src/resources/skills/debug-like-expert/references/hypothesis-testing.md +373 -0
  2626. package/src/resources/skills/debug-like-expert/references/investigation-techniques.md +337 -0
  2627. package/src/resources/skills/debug-like-expert/references/verification-patterns.md +425 -0
  2628. package/src/resources/skills/debug-like-expert/references/when-to-research.md +361 -0
  2629. package/src/resources/skills/decompose-into-slices/SKILL.md +139 -0
  2630. package/src/resources/skills/dependency-upgrade/SKILL.md +158 -0
  2631. package/src/resources/skills/design-an-interface/SKILL.md +102 -0
  2632. package/src/resources/skills/forensics/SKILL.md +153 -0
  2633. package/src/resources/skills/frontend-design/SKILL.md +45 -0
  2634. package/src/resources/skills/github-workflows/SKILL.md +90 -0
  2635. package/src/resources/skills/github-workflows/references/gh/SKILL.md +276 -0
  2636. package/src/resources/skills/github-workflows/references/gh/references/issue-stories.md +204 -0
  2637. package/src/resources/skills/github-workflows/references/gh/references/labels.md +170 -0
  2638. package/src/resources/skills/github-workflows/references/gh/references/milestones.md +158 -0
  2639. package/src/resources/skills/github-workflows/references/gh/references/projects-v2.md +177 -0
  2640. package/src/resources/skills/github-workflows/references/gh/scripts/experiment_cleanup.py +191 -0
  2641. package/src/resources/skills/github-workflows/references/gh/scripts/github_project_setup.py +799 -0
  2642. package/src/resources/skills/github-workflows/references/gh/tests/__init__.py +0 -0
  2643. package/src/resources/skills/github-workflows/references/gh/tests/test_github_project_setup.py +608 -0
  2644. package/src/resources/skills/grill-me/SKILL.md +93 -0
  2645. package/src/resources/skills/handoff/SKILL.md +121 -0
  2646. package/src/resources/skills/lint/SKILL.md +145 -0
  2647. package/src/resources/skills/make-interfaces-feel-better/SKILL.md +122 -0
  2648. package/src/resources/skills/make-interfaces-feel-better/animations.md +379 -0
  2649. package/src/resources/skills/make-interfaces-feel-better/performance.md +88 -0
  2650. package/src/resources/skills/make-interfaces-feel-better/surfaces.md +247 -0
  2651. package/src/resources/skills/make-interfaces-feel-better/typography.md +123 -0
  2652. package/src/resources/skills/observability/SKILL.md +174 -0
  2653. package/src/resources/skills/react-best-practices/README.md +123 -0
  2654. package/src/resources/skills/react-best-practices/SKILL.md +136 -0
  2655. package/src/resources/skills/react-best-practices/metadata.json +15 -0
  2656. package/src/resources/skills/react-best-practices/rules/_sections.md +46 -0
  2657. package/src/resources/skills/react-best-practices/rules/_template.md +28 -0
  2658. package/src/resources/skills/react-best-practices/rules/advanced-event-handler-refs.md +55 -0
  2659. package/src/resources/skills/react-best-practices/rules/advanced-init-once.md +42 -0
  2660. package/src/resources/skills/react-best-practices/rules/advanced-use-latest.md +39 -0
  2661. package/src/resources/skills/react-best-practices/rules/async-api-routes.md +38 -0
  2662. package/src/resources/skills/react-best-practices/rules/async-defer-await.md +80 -0
  2663. package/src/resources/skills/react-best-practices/rules/async-dependencies.md +51 -0
  2664. package/src/resources/skills/react-best-practices/rules/async-parallel.md +28 -0
  2665. package/src/resources/skills/react-best-practices/rules/async-suspense-boundaries.md +99 -0
  2666. package/src/resources/skills/react-best-practices/rules/bundle-barrel-imports.md +59 -0
  2667. package/src/resources/skills/react-best-practices/rules/bundle-conditional.md +31 -0
  2668. package/src/resources/skills/react-best-practices/rules/bundle-defer-third-party.md +49 -0
  2669. package/src/resources/skills/react-best-practices/rules/bundle-dynamic-imports.md +35 -0
  2670. package/src/resources/skills/react-best-practices/rules/bundle-preload.md +50 -0
  2671. package/src/resources/skills/react-best-practices/rules/client-event-listeners.md +74 -0
  2672. package/src/resources/skills/react-best-practices/rules/client-localstorage-schema.md +71 -0
  2673. package/src/resources/skills/react-best-practices/rules/client-passive-event-listeners.md +48 -0
  2674. package/src/resources/skills/react-best-practices/rules/client-swr-dedup.md +56 -0
  2675. package/src/resources/skills/react-best-practices/rules/js-batch-dom-css.md +107 -0
  2676. package/src/resources/skills/react-best-practices/rules/js-cache-function-results.md +80 -0
  2677. package/src/resources/skills/react-best-practices/rules/js-cache-property-access.md +28 -0
  2678. package/src/resources/skills/react-best-practices/rules/js-cache-storage.md +70 -0
  2679. package/src/resources/skills/react-best-practices/rules/js-combine-iterations.md +32 -0
  2680. package/src/resources/skills/react-best-practices/rules/js-early-exit.md +50 -0
  2681. package/src/resources/skills/react-best-practices/rules/js-hoist-regexp.md +45 -0
  2682. package/src/resources/skills/react-best-practices/rules/js-index-maps.md +37 -0
  2683. package/src/resources/skills/react-best-practices/rules/js-length-check-first.md +49 -0
  2684. package/src/resources/skills/react-best-practices/rules/js-min-max-loop.md +82 -0
  2685. package/src/resources/skills/react-best-practices/rules/js-set-map-lookups.md +24 -0
  2686. package/src/resources/skills/react-best-practices/rules/js-tosorted-immutable.md +57 -0
  2687. package/src/resources/skills/react-best-practices/rules/rendering-activity.md +26 -0
  2688. package/src/resources/skills/react-best-practices/rules/rendering-animate-svg-wrapper.md +47 -0
  2689. package/src/resources/skills/react-best-practices/rules/rendering-conditional-render.md +40 -0
  2690. package/src/resources/skills/react-best-practices/rules/rendering-content-visibility.md +38 -0
  2691. package/src/resources/skills/react-best-practices/rules/rendering-hoist-jsx.md +46 -0
  2692. package/src/resources/skills/react-best-practices/rules/rendering-hydration-no-flicker.md +82 -0
  2693. package/src/resources/skills/react-best-practices/rules/rendering-hydration-suppress-warning.md +30 -0
  2694. package/src/resources/skills/react-best-practices/rules/rendering-svg-precision.md +28 -0
  2695. package/src/resources/skills/react-best-practices/rules/rendering-usetransition-loading.md +75 -0
  2696. package/src/resources/skills/react-best-practices/rules/rerender-defer-reads.md +39 -0
  2697. package/src/resources/skills/react-best-practices/rules/rerender-dependencies.md +45 -0
  2698. package/src/resources/skills/react-best-practices/rules/rerender-derived-state-no-effect.md +40 -0
  2699. package/src/resources/skills/react-best-practices/rules/rerender-derived-state.md +29 -0
  2700. package/src/resources/skills/react-best-practices/rules/rerender-functional-setstate.md +74 -0
  2701. package/src/resources/skills/react-best-practices/rules/rerender-lazy-state-init.md +58 -0
  2702. package/src/resources/skills/react-best-practices/rules/rerender-memo-with-default-value.md +38 -0
  2703. package/src/resources/skills/react-best-practices/rules/rerender-memo.md +44 -0
  2704. package/src/resources/skills/react-best-practices/rules/rerender-move-effect-to-event.md +45 -0
  2705. package/src/resources/skills/react-best-practices/rules/rerender-simple-expression-in-memo.md +35 -0
  2706. package/src/resources/skills/react-best-practices/rules/rerender-transitions.md +40 -0
  2707. package/src/resources/skills/react-best-practices/rules/rerender-use-ref-transient-values.md +73 -0
  2708. package/src/resources/skills/react-best-practices/rules/server-after-nonblocking.md +73 -0
  2709. package/src/resources/skills/react-best-practices/rules/server-auth-actions.md +96 -0
  2710. package/src/resources/skills/react-best-practices/rules/server-cache-lru.md +41 -0
  2711. package/src/resources/skills/react-best-practices/rules/server-cache-react.md +76 -0
  2712. package/src/resources/skills/react-best-practices/rules/server-dedup-props.md +65 -0
  2713. package/src/resources/skills/react-best-practices/rules/server-parallel-fetching.md +83 -0
  2714. package/src/resources/skills/react-best-practices/rules/server-serialization.md +38 -0
  2715. package/src/resources/skills/review/SKILL.md +218 -0
  2716. package/src/resources/skills/security-review/SKILL.md +181 -0
  2717. package/src/resources/skills/spike-wrap-up/SKILL.md +138 -0
  2718. package/src/resources/skills/tdd/SKILL.md +112 -0
  2719. package/src/resources/skills/test/SKILL.md +204 -0
  2720. package/src/resources/skills/userinterface-wiki/SKILL.md +253 -0
  2721. package/src/resources/skills/userinterface-wiki/rules/_sections.md +66 -0
  2722. package/src/resources/skills/userinterface-wiki/rules/_template.md +24 -0
  2723. package/src/resources/skills/userinterface-wiki/rules/a11y-reduced-motion-check.md +30 -0
  2724. package/src/resources/skills/userinterface-wiki/rules/a11y-toggle-setting.md +30 -0
  2725. package/src/resources/skills/userinterface-wiki/rules/a11y-visual-equivalent.md +36 -0
  2726. package/src/resources/skills/userinterface-wiki/rules/a11y-volume-control.md +28 -0
  2727. package/src/resources/skills/userinterface-wiki/rules/appropriate-confirmations-only.md +19 -0
  2728. package/src/resources/skills/userinterface-wiki/rules/appropriate-errors-warnings.md +18 -0
  2729. package/src/resources/skills/userinterface-wiki/rules/appropriate-no-decorative.md +21 -0
  2730. package/src/resources/skills/userinterface-wiki/rules/appropriate-no-high-frequency.md +28 -0
  2731. package/src/resources/skills/userinterface-wiki/rules/appropriate-no-punishing.md +27 -0
  2732. package/src/resources/skills/userinterface-wiki/rules/container-callback-ref.md +31 -0
  2733. package/src/resources/skills/userinterface-wiki/rules/container-guard-initial-zero.md +25 -0
  2734. package/src/resources/skills/userinterface-wiki/rules/container-no-excessive-use.md +13 -0
  2735. package/src/resources/skills/userinterface-wiki/rules/container-overflow-hidden.md +25 -0
  2736. package/src/resources/skills/userinterface-wiki/rules/container-transition-delay.md +21 -0
  2737. package/src/resources/skills/userinterface-wiki/rules/container-two-div-pattern.md +35 -0
  2738. package/src/resources/skills/userinterface-wiki/rules/container-use-resize-observer.md +48 -0
  2739. package/src/resources/skills/userinterface-wiki/rules/context-cleanup-nodes.md +25 -0
  2740. package/src/resources/skills/userinterface-wiki/rules/context-resume-suspended.md +28 -0
  2741. package/src/resources/skills/userinterface-wiki/rules/context-reuse-single.md +30 -0
  2742. package/src/resources/skills/userinterface-wiki/rules/design-filter-for-character.md +25 -0
  2743. package/src/resources/skills/userinterface-wiki/rules/design-noise-for-percussion.md +26 -0
  2744. package/src/resources/skills/userinterface-wiki/rules/design-oscillator-for-tonal.md +22 -0
  2745. package/src/resources/skills/userinterface-wiki/rules/duration-max-300ms.md +21 -0
  2746. package/src/resources/skills/userinterface-wiki/rules/duration-press-hover.md +21 -0
  2747. package/src/resources/skills/userinterface-wiki/rules/duration-shorten-before-curve.md +21 -0
  2748. package/src/resources/skills/userinterface-wiki/rules/duration-small-state.md +15 -0
  2749. package/src/resources/skills/userinterface-wiki/rules/easing-entrance-ease-out.md +21 -0
  2750. package/src/resources/skills/userinterface-wiki/rules/easing-exit-ease-in.md +21 -0
  2751. package/src/resources/skills/userinterface-wiki/rules/easing-for-state-change.md +27 -0
  2752. package/src/resources/skills/userinterface-wiki/rules/easing-linear-only-progress.md +21 -0
  2753. package/src/resources/skills/userinterface-wiki/rules/easing-natural-decay.md +22 -0
  2754. package/src/resources/skills/userinterface-wiki/rules/easing-no-linear-motion.md +22 -0
  2755. package/src/resources/skills/userinterface-wiki/rules/easing-transition-ease-in-out.md +15 -0
  2756. package/src/resources/skills/userinterface-wiki/rules/envelope-exponential-decay.md +21 -0
  2757. package/src/resources/skills/userinterface-wiki/rules/envelope-no-zero-target.md +21 -0
  2758. package/src/resources/skills/userinterface-wiki/rules/envelope-set-initial-value.md +22 -0
  2759. package/src/resources/skills/userinterface-wiki/rules/exit-key-required.md +29 -0
  2760. package/src/resources/skills/userinterface-wiki/rules/exit-matches-initial.md +29 -0
  2761. package/src/resources/skills/userinterface-wiki/rules/exit-prop-required.md +33 -0
  2762. package/src/resources/skills/userinterface-wiki/rules/exit-requires-wrapper.md +27 -0
  2763. package/src/resources/skills/userinterface-wiki/rules/impl-default-subtle.md +21 -0
  2764. package/src/resources/skills/userinterface-wiki/rules/impl-preload-audio.md +34 -0
  2765. package/src/resources/skills/userinterface-wiki/rules/impl-reset-current-time.md +26 -0
  2766. package/src/resources/skills/userinterface-wiki/rules/mode-pop-layout-for-lists.md +25 -0
  2767. package/src/resources/skills/userinterface-wiki/rules/mode-sync-layout-conflict.md +29 -0
  2768. package/src/resources/skills/userinterface-wiki/rules/mode-wait-doubles-duration.md +25 -0
  2769. package/src/resources/skills/userinterface-wiki/rules/morphing-aria-hidden.md +21 -0
  2770. package/src/resources/skills/userinterface-wiki/rules/morphing-consistent-viewbox.md +23 -0
  2771. package/src/resources/skills/userinterface-wiki/rules/morphing-group-variants.md +33 -0
  2772. package/src/resources/skills/userinterface-wiki/rules/morphing-jump-non-grouped.md +29 -0
  2773. package/src/resources/skills/userinterface-wiki/rules/morphing-reduced-motion.md +28 -0
  2774. package/src/resources/skills/userinterface-wiki/rules/morphing-spring-rotation.md +23 -0
  2775. package/src/resources/skills/userinterface-wiki/rules/morphing-strokelinecap-round.md +21 -0
  2776. package/src/resources/skills/userinterface-wiki/rules/morphing-three-lines.md +32 -0
  2777. package/src/resources/skills/userinterface-wiki/rules/morphing-use-collapsed.md +33 -0
  2778. package/src/resources/skills/userinterface-wiki/rules/native-backdrop-styling.md +27 -0
  2779. package/src/resources/skills/userinterface-wiki/rules/native-placeholder-styling.md +27 -0
  2780. package/src/resources/skills/userinterface-wiki/rules/native-selection-styling.md +18 -0
  2781. package/src/resources/skills/userinterface-wiki/rules/nested-consistent-timing.md +25 -0
  2782. package/src/resources/skills/userinterface-wiki/rules/nested-propagate-required.md +41 -0
  2783. package/src/resources/skills/userinterface-wiki/rules/none-context-menu-entrance.md +25 -0
  2784. package/src/resources/skills/userinterface-wiki/rules/none-high-frequency.md +29 -0
  2785. package/src/resources/skills/userinterface-wiki/rules/none-keyboard-navigation.md +32 -0
  2786. package/src/resources/skills/userinterface-wiki/rules/param-click-duration.md +21 -0
  2787. package/src/resources/skills/userinterface-wiki/rules/param-filter-frequency-range.md +21 -0
  2788. package/src/resources/skills/userinterface-wiki/rules/param-q-value-range.md +21 -0
  2789. package/src/resources/skills/userinterface-wiki/rules/param-reasonable-gain.md +21 -0
  2790. package/src/resources/skills/userinterface-wiki/rules/physics-active-state.md +23 -0
  2791. package/src/resources/skills/userinterface-wiki/rules/physics-no-excessive-stagger.md +22 -0
  2792. package/src/resources/skills/userinterface-wiki/rules/physics-spring-for-overshoot.md +23 -0
  2793. package/src/resources/skills/userinterface-wiki/rules/physics-subtle-deformation.md +22 -0
  2794. package/src/resources/skills/userinterface-wiki/rules/prefetch-hit-slop.md +27 -0
  2795. package/src/resources/skills/userinterface-wiki/rules/prefetch-keyboard-tab.md +19 -0
  2796. package/src/resources/skills/userinterface-wiki/rules/prefetch-not-everything.md +22 -0
  2797. package/src/resources/skills/userinterface-wiki/rules/prefetch-touch-fallback.md +34 -0
  2798. package/src/resources/skills/userinterface-wiki/rules/prefetch-trajectory-over-hover.md +32 -0
  2799. package/src/resources/skills/userinterface-wiki/rules/prefetch-use-selectively.md +13 -0
  2800. package/src/resources/skills/userinterface-wiki/rules/presence-disable-interactions.md +31 -0
  2801. package/src/resources/skills/userinterface-wiki/rules/presence-hook-in-child.md +31 -0
  2802. package/src/resources/skills/userinterface-wiki/rules/presence-safe-to-remove.md +37 -0
  2803. package/src/resources/skills/userinterface-wiki/rules/pseudo-content-required.md +28 -0
  2804. package/src/resources/skills/userinterface-wiki/rules/pseudo-first-line-styling.md +27 -0
  2805. package/src/resources/skills/userinterface-wiki/rules/pseudo-hit-target-expansion.md +31 -0
  2806. package/src/resources/skills/userinterface-wiki/rules/pseudo-marker-styling.md +28 -0
  2807. package/src/resources/skills/userinterface-wiki/rules/pseudo-over-dom-node.md +32 -0
  2808. package/src/resources/skills/userinterface-wiki/rules/pseudo-position-relative-parent.md +33 -0
  2809. package/src/resources/skills/userinterface-wiki/rules/pseudo-z-index-layering.md +37 -0
  2810. package/src/resources/skills/userinterface-wiki/rules/spring-for-gestures.md +27 -0
  2811. package/src/resources/skills/userinterface-wiki/rules/spring-for-interruptible.md +27 -0
  2812. package/src/resources/skills/userinterface-wiki/rules/spring-params-balanced.md +29 -0
  2813. package/src/resources/skills/userinterface-wiki/rules/spring-preserves-velocity.md +28 -0
  2814. package/src/resources/skills/userinterface-wiki/rules/staging-dim-background.md +22 -0
  2815. package/src/resources/skills/userinterface-wiki/rules/staging-one-focal-point.md +24 -0
  2816. package/src/resources/skills/userinterface-wiki/rules/staging-z-index-hierarchy.md +22 -0
  2817. package/src/resources/skills/userinterface-wiki/rules/timing-consistent.md +24 -0
  2818. package/src/resources/skills/userinterface-wiki/rules/timing-no-entrance-context-menu.md +22 -0
  2819. package/src/resources/skills/userinterface-wiki/rules/timing-under-300ms.md +22 -0
  2820. package/src/resources/skills/userinterface-wiki/rules/transition-name-cleanup.md +28 -0
  2821. package/src/resources/skills/userinterface-wiki/rules/transition-name-required.md +27 -0
  2822. package/src/resources/skills/userinterface-wiki/rules/transition-name-unique.md +24 -0
  2823. package/src/resources/skills/userinterface-wiki/rules/transition-over-js-library.md +32 -0
  2824. package/src/resources/skills/userinterface-wiki/rules/transition-style-pseudo-elements.md +24 -0
  2825. package/src/resources/skills/userinterface-wiki/rules/type-antialiased-on-retina.md +18 -0
  2826. package/src/resources/skills/userinterface-wiki/rules/type-disambiguation-stylistic-set.md +15 -0
  2827. package/src/resources/skills/userinterface-wiki/rules/type-font-display-swap.md +28 -0
  2828. package/src/resources/skills/userinterface-wiki/rules/type-justify-with-hyphens.md +24 -0
  2829. package/src/resources/skills/userinterface-wiki/rules/type-letter-spacing-uppercase.md +28 -0
  2830. package/src/resources/skills/userinterface-wiki/rules/type-no-font-synthesis.md +18 -0
  2831. package/src/resources/skills/userinterface-wiki/rules/type-oldstyle-nums-for-prose.md +21 -0
  2832. package/src/resources/skills/userinterface-wiki/rules/type-opentype-contextual-alternates.md +15 -0
  2833. package/src/resources/skills/userinterface-wiki/rules/type-optical-sizing-auto.md +25 -0
  2834. package/src/resources/skills/userinterface-wiki/rules/type-proper-fractions.md +15 -0
  2835. package/src/resources/skills/userinterface-wiki/rules/type-slashed-zero.md +17 -0
  2836. package/src/resources/skills/userinterface-wiki/rules/type-tabular-nums-for-data.md +21 -0
  2837. package/src/resources/skills/userinterface-wiki/rules/type-text-wrap-balance-headings.md +21 -0
  2838. package/src/resources/skills/userinterface-wiki/rules/type-text-wrap-pretty.md +16 -0
  2839. package/src/resources/skills/userinterface-wiki/rules/type-underline-offset.md +25 -0
  2840. package/src/resources/skills/userinterface-wiki/rules/type-variable-weight-continuous.md +23 -0
  2841. package/src/resources/skills/userinterface-wiki/rules/ux-aesthetic-usability.md +32 -0
  2842. package/src/resources/skills/userinterface-wiki/rules/ux-cognitive-load-reduce.md +49 -0
  2843. package/src/resources/skills/userinterface-wiki/rules/ux-common-region-boundaries.md +50 -0
  2844. package/src/resources/skills/userinterface-wiki/rules/ux-doherty-perceived-speed.md +29 -0
  2845. package/src/resources/skills/userinterface-wiki/rules/ux-doherty-under-400ms.md +30 -0
  2846. package/src/resources/skills/userinterface-wiki/rules/ux-fitts-hit-area.md +32 -0
  2847. package/src/resources/skills/userinterface-wiki/rules/ux-fitts-target-size.md +31 -0
  2848. package/src/resources/skills/userinterface-wiki/rules/ux-goal-gradient-progress.md +33 -0
  2849. package/src/resources/skills/userinterface-wiki/rules/ux-hicks-minimize-choices.md +45 -0
  2850. package/src/resources/skills/userinterface-wiki/rules/ux-jakobs-familiar-patterns.md +37 -0
  2851. package/src/resources/skills/userinterface-wiki/rules/ux-millers-chunking.md +23 -0
  2852. package/src/resources/skills/userinterface-wiki/rules/ux-pareto-prioritize-features.md +36 -0
  2853. package/src/resources/skills/userinterface-wiki/rules/ux-peak-end-finish-strong.md +35 -0
  2854. package/src/resources/skills/userinterface-wiki/rules/ux-postels-accept-messy-input.md +45 -0
  2855. package/src/resources/skills/userinterface-wiki/rules/ux-pragnanz-simplify.md +33 -0
  2856. package/src/resources/skills/userinterface-wiki/rules/ux-progressive-disclosure.md +41 -0
  2857. package/src/resources/skills/userinterface-wiki/rules/ux-proximity-grouping.md +38 -0
  2858. package/src/resources/skills/userinterface-wiki/rules/ux-serial-position.md +31 -0
  2859. package/src/resources/skills/userinterface-wiki/rules/ux-similarity-consistency.md +35 -0
  2860. package/src/resources/skills/userinterface-wiki/rules/ux-teslers-complexity.md +28 -0
  2861. package/src/resources/skills/userinterface-wiki/rules/ux-uniform-connectedness.md +43 -0
  2862. package/src/resources/skills/userinterface-wiki/rules/ux-von-restorff-emphasis.md +29 -0
  2863. package/src/resources/skills/userinterface-wiki/rules/ux-zeigarnik-show-incomplete.md +36 -0
  2864. package/src/resources/skills/userinterface-wiki/rules/visual-animate-shadow-pseudo.md +49 -0
  2865. package/src/resources/skills/userinterface-wiki/rules/visual-border-alpha-colors.md +25 -0
  2866. package/src/resources/skills/userinterface-wiki/rules/visual-button-shadow-anatomy.md +49 -0
  2867. package/src/resources/skills/userinterface-wiki/rules/visual-concentric-radius.md +40 -0
  2868. package/src/resources/skills/userinterface-wiki/rules/visual-consistent-spacing-scale.md +35 -0
  2869. package/src/resources/skills/userinterface-wiki/rules/visual-layered-shadows.md +30 -0
  2870. package/src/resources/skills/userinterface-wiki/rules/visual-no-pure-black-shadow.md +25 -0
  2871. package/src/resources/skills/userinterface-wiki/rules/visual-shadow-direction.md +25 -0
  2872. package/src/resources/skills/userinterface-wiki/rules/visual-shadow-matches-elevation.md +23 -0
  2873. package/src/resources/skills/userinterface-wiki/rules/weight-duration-matches-action.md +29 -0
  2874. package/src/resources/skills/userinterface-wiki/rules/weight-match-action.md +32 -0
  2875. package/src/resources/skills/verify-before-complete/SKILL.md +98 -0
  2876. package/src/resources/skills/web-design-guidelines/SKILL.md +39 -0
  2877. package/src/resources/skills/web-quality-audit/SKILL.md +168 -0
  2878. package/src/resources/skills/web-quality-audit/scripts/analyze.sh +91 -0
  2879. package/src/resources/skills/write-docs/SKILL.md +82 -0
  2880. package/src/resources/skills/write-milestone-brief/SKILL.md +135 -0
@@ -0,0 +1,4418 @@
1
+ // Project/App: GSD-2
2
+ // File Purpose: Interactive TUI mode and session UI rendering.
3
+ // GSD2 - Interactive TUI mode for coding-agent sessions.
4
+ /**
5
+ * Interactive mode for the coding agent.
6
+ * Handles TUI rendering and user interaction, delegating business logic to AgentSession.
7
+ */
8
+
9
+ import * as fs from "node:fs";
10
+ import * as os from "node:os";
11
+ import * as path from "node:path";
12
+ import { listDescendants } from "@gsd/native";
13
+ import type { AgentMessage } from "@gsd/pi-agent-core";
14
+ import type { AssistantMessage, ImageContent, Message, Model, OAuthProviderId } from "@gsd/pi-ai";
15
+ import type {
16
+ AutocompleteItem,
17
+ EditorComponent,
18
+ EditorTheme,
19
+ KeyId,
20
+ MarkdownTheme,
21
+ OverlayHandle,
22
+ OverlayOptions,
23
+ SlashCommand,
24
+ } from "@gsd/pi-tui";
25
+ import {
26
+ CombinedAutocompleteProvider,
27
+ type Component,
28
+ Container,
29
+ fuzzyFilter,
30
+ Loader,
31
+ Markdown,
32
+ matchesKey,
33
+ ProcessTerminal,
34
+ Spacer,
35
+ type Terminal as TuiTerminal,
36
+ Text,
37
+ TruncatedText,
38
+ TUI,
39
+ visibleWidth,
40
+ } from "@gsd/pi-tui";
41
+ import { spawn, spawnSync } from "child_process";
42
+ import {
43
+ APP_NAME,
44
+ getAuthPath,
45
+ getDebugLogPath,
46
+ getUpdateInstruction,
47
+ VERSION,
48
+ } from "../../config.js";
49
+ import { type AgentSession, type AgentSessionEvent, parseSkillBlock } from "../../core/agent-session.js";
50
+ import type { CompactionResult } from "../../core/compaction/index.js";
51
+ import type {
52
+ ExtensionContext,
53
+ ExtensionRunner,
54
+ ExtensionUIContext,
55
+ ExtensionUIDialogOptions,
56
+ ExtensionWidgetOptions,
57
+ } from "../../core/extensions/index.js";
58
+ import { FooterDataProvider, type ReadonlyFooterDataProvider } from "../../core/footer-data-provider.js";
59
+ import { type AppAction, KeybindingsManager } from "../../core/keybindings.js";
60
+ import { createCompactionSummaryMessage } from "../../core/messages.js";
61
+ import { resolveModelScope } from "../../core/model-resolver.js";
62
+ import type { ResourceDiagnostic } from "../../core/resource-loader.js";
63
+ import { type SessionContext, SessionManager } from "../../core/session-manager.js";
64
+ import { BUILTIN_SLASH_COMMANDS } from "../../core/slash-commands.js";
65
+ import type { TruncationResult } from "../../core/tools/truncate.js";
66
+ import { getChangelogPath, getNewEntries, parseChangelog } from "../../utils/changelog.js";
67
+ import { readClipboardImage } from "../../utils/clipboard-image.js";
68
+ import { ensureTool } from "../../utils/tools-manager.js";
69
+ import { AssistantMessageComponent } from "./components/assistant-message.js";
70
+ import { AdaptiveLayoutComponent } from "./components/adaptive-layout.js";
71
+ import { BashExecutionComponent } from "./components/bash-execution.js";
72
+ import { BorderedLoader } from "./components/bordered-loader.js";
73
+ import { BranchSummaryMessageComponent } from "./components/branch-summary-message.js";
74
+ import { CompactionSummaryMessageComponent } from "./components/compaction-summary-message.js";
75
+ import { CustomEditor } from "./components/custom-editor.js";
76
+ import { CustomMessageComponent } from "./components/custom-message.js";
77
+ import { DaxnutsComponent } from "./components/daxnuts.js";
78
+ import { DynamicBorder } from "./components/dynamic-border.js";
79
+ import { ExtensionEditorComponent } from "./components/extension-editor.js";
80
+ import { ExtensionInputComponent } from "./components/extension-input.js";
81
+ import { ExtensionSelectorComponent } from "./components/extension-selector.js";
82
+ import { FooterComponent } from "./components/footer.js";
83
+ import { appKey, appKeyHint, editorKey, formatKeyForDisplay, keyHint, rawKeyHint } from "./components/keybinding-hints.js";
84
+ import { LoginDialogComponent } from "./components/login-dialog.js";
85
+ import { ModelSelectorComponent, providerDisplayName } from "./components/model-selector.js";
86
+ import { OAuthSelectorComponent } from "./components/oauth-selector.js";
87
+ import { ProviderManagerComponent } from "./components/provider-manager.js";
88
+ import { ScopedModelsSelectorComponent } from "./components/scoped-models-selector.js";
89
+ import { SessionSelectorComponent } from "./components/session-selector.js";
90
+ import { SettingsSelectorComponent } from "./components/settings-selector.js";
91
+ import { SkillInvocationMessageComponent } from "./components/skill-invocation-message.js";
92
+ import { ToolExecutionComponent } from "./components/tool-execution.js";
93
+ import { TreeSelectorComponent } from "./components/tree-selector.js";
94
+ import { UserMessageComponent } from "./components/user-message.js";
95
+ import { UserMessageSelectorComponent } from "./components/user-message-selector.js";
96
+ import { ContextualTips } from "../../core/contextual-tips.js";
97
+ import { type SlashCommandContext, dispatchSlashCommand, getAppKeyDisplay } from "./slash-command-handlers.js";
98
+ import { handleAgentEvent } from "./controllers/chat-controller.js";
99
+ import { createExtensionUIContext as buildExtensionUIContext } from "./controllers/extension-ui-controller.js";
100
+ import { setupEditorSubmitHandler as setupEditorSubmitHandlerController } from "./controllers/input-controller.js";
101
+ import {
102
+ findExactModelMatch as findExactModelMatchController,
103
+ getModelCandidates as getModelCandidatesController,
104
+ handleModelCommand as handleModelCommandController,
105
+ updateAvailableProviderCount as updateAvailableProviderCountController,
106
+ } from "./controllers/model-controller.js";
107
+ import {
108
+ getAvailableThemes,
109
+ getAvailableThemesWithPaths,
110
+ getEditorTheme,
111
+ getMarkdownTheme,
112
+ getThemeByName,
113
+ initTheme,
114
+ onThemeChange,
115
+ stopThemeWatcher,
116
+ setRegisteredThemes,
117
+ setTheme,
118
+ setThemeInstance,
119
+ Theme,
120
+ type ThemeColor,
121
+ theme,
122
+ } from "./theme/theme.js";
123
+
124
+ /** Interface for components that can be expanded/collapsed */
125
+ interface Expandable {
126
+ setExpanded(expanded: boolean): void;
127
+ }
128
+
129
+ function isExpandable(obj: unknown): obj is Expandable {
130
+ return typeof obj === "object" && obj !== null && "setExpanded" in obj && typeof obj.setExpanded === "function";
131
+ }
132
+
133
+ export type AssistantReplaySegment =
134
+ | { kind: "assistant"; startIndex: number; endIndex: number }
135
+ | { kind: "tool"; contentIndex: number };
136
+
137
+ function isVisibleAssistantReplayText(block: any): boolean {
138
+ return (
139
+ (block?.type === "text" && typeof block.text === "string" && block.text.trim().length > 0)
140
+ || (block?.type === "thinking" && typeof block.thinking === "string" && block.thinking.trim().length > 0)
141
+ );
142
+ }
143
+
144
+ /**
145
+ * Build replay segments for historical assistant messages so rebuild paths
146
+ * preserve the original content[] ordering between assistant prose and tools.
147
+ */
148
+ export function buildAssistantReplaySegments(contentBlocks: Array<any>): AssistantReplaySegment[] {
149
+ const segments: AssistantReplaySegment[] = [];
150
+ let runStart = -1;
151
+ let runEnd = -1;
152
+
153
+ const closeRun = () => {
154
+ if (runStart !== -1) {
155
+ segments.push({ kind: "assistant", startIndex: runStart, endIndex: runEnd });
156
+ runStart = -1;
157
+ runEnd = -1;
158
+ }
159
+ };
160
+
161
+ for (let i = 0; i < contentBlocks.length; i++) {
162
+ const block = contentBlocks[i];
163
+ const isAssistantText = isVisibleAssistantReplayText(block);
164
+ const isInvisibleAssistantText = block?.type === "text" || block?.type === "thinking";
165
+ const isTool = block?.type === "toolCall" || block?.type === "serverToolUse";
166
+
167
+ if (isAssistantText) {
168
+ if (runStart === -1) runStart = i;
169
+ runEnd = i;
170
+ continue;
171
+ }
172
+
173
+ if (isInvisibleAssistantText) continue;
174
+
175
+ closeRun();
176
+
177
+ if (isTool) {
178
+ segments.push({ kind: "tool", contentIndex: i });
179
+ }
180
+ }
181
+
182
+ closeRun();
183
+
184
+ return segments;
185
+ }
186
+
187
+ export function getToolExpansionStartupHint(toolOutputExpanded: boolean, keybindings: KeybindingsManager): string {
188
+ return appKeyHint(keybindings, "expandTools", toolOutputExpanded ? "to collapse tools" : "to expand tools");
189
+ }
190
+
191
+ type CompactionQueuedMessage = {
192
+ text: string;
193
+ mode: "steer" | "followUp";
194
+ };
195
+
196
+ export type ExtensionNotifyType = "info" | "warning" | "error" | "success" | undefined;
197
+
198
+ export function shouldRenderExtensionNotifyInChat(type: ExtensionNotifyType): boolean {
199
+ return type !== "warning";
200
+ }
201
+
202
+ function hasAnsiStyling(message: string): boolean {
203
+ return /\x1b\[[0-9;]*m/.test(message);
204
+ }
205
+
206
+ function stripAnsiStyling(message: string): string {
207
+ return message.replace(/\x1b\[[0-9;]*m/g, "");
208
+ }
209
+
210
+ function styleGsdStatusCardMessage(message: string): string | null {
211
+ const plain = stripAnsiStyling(message);
212
+ if (!/(Verification Gate|Commit|Snapshot|GSD .*Complete|Next step)/.test(plain)) return null;
213
+
214
+ const styled = plain.split("\n").map((line) => {
215
+ if (line.includes("╭─ ✓") || line.includes("✓ Verification Gate") || line.includes("✓ Commit") || line.includes("✓ Snapshot")) {
216
+ return line.replace(/(╭─)\s+(.*)/, (_match, border, title) =>
217
+ `${theme.fg("borderAccent", border)} ${theme.fg("success", theme.bold(title))}`);
218
+ }
219
+ if (line.includes("╭─ ✕") || line.includes("✕ Verification Gate")) {
220
+ return line.replace(/(╭─)\s+(.*)/, (_match, border, title) =>
221
+ `${theme.fg("borderAccent", border)} ${theme.fg("error", theme.bold(title))}`);
222
+ }
223
+ if (line.includes("╭─ Next step")) {
224
+ return line.replace(/(╭─)\s+(.*)/, (_match, border, title) =>
225
+ `${theme.fg("borderAccent", border)} ${theme.fg("accent", theme.bold(title))}`);
226
+ }
227
+ if (/^\s*╰/.test(line)) {
228
+ return theme.fg("borderAccent", line);
229
+ }
230
+ const contentMatch = /^(\s*)(.*)$/u.exec(line);
231
+ const indent = contentMatch?.[1] ?? "";
232
+ const text = contentMatch?.[2] ?? line;
233
+ if (/(Completed:|Next:|Continue:|Auto-run:)/.test(text)) {
234
+ const styled = text
235
+ .replace(/(Completed:|Next:|Continue:|Auto-run:)/g, (label) => theme.fg("dim", label))
236
+ .replace(/(\/gsd\s+(?:next|auto|status))/g, (command) => theme.fg("success", command));
237
+ return `${indent}${styled}`;
238
+ }
239
+ return text ? `${indent}${theme.fg("text", text)}` : line;
240
+ });
241
+ return styled.join("\n");
242
+ }
243
+
244
+ export interface ExtensionNotifyRenderResult {
245
+ rendered: boolean;
246
+ statusSpacer?: Spacer;
247
+ statusText?: Text;
248
+ }
249
+
250
+ export function renderExtensionNotifyInChat(
251
+ chatContainer: Container,
252
+ message: string,
253
+ type?: ExtensionNotifyType,
254
+ ): ExtensionNotifyRenderResult {
255
+ if (!shouldRenderExtensionNotifyInChat(type)) {
256
+ return { rendered: false };
257
+ }
258
+
259
+ const spacer = new Spacer(1);
260
+ chatContainer.addChild(spacer);
261
+
262
+ if (type === "error") {
263
+ chatContainer.addChild(new Text(theme.fg("error", `Error: ${message}`), 1, 0));
264
+ return { rendered: true };
265
+ }
266
+ if (type === "success") {
267
+ chatContainer.addChild(new DynamicBorder((text) => theme.fg("success", text)));
268
+ chatContainer.addChild(new Text(theme.fg("success", message), 1, 0));
269
+ chatContainer.addChild(new DynamicBorder((text) => theme.fg("success", text)));
270
+ chatContainer.addChild(new Spacer(1));
271
+ return { rendered: true };
272
+ }
273
+
274
+ const styledStatusCard = styleGsdStatusCardMessage(message);
275
+ const statusText = new Text(
276
+ styledStatusCard ?? (hasAnsiStyling(message) ? message : theme.fg("dim", message)),
277
+ 1,
278
+ 0,
279
+ );
280
+ chatContainer.addChild(statusText);
281
+ return { rendered: true, statusSpacer: spacer, statusText };
282
+ }
283
+
284
+ export function renderBlockingErrorBanner(container: Container, message: string | undefined): void {
285
+ container.clear();
286
+ if (message === undefined) return;
287
+
288
+ container.addChild(new Spacer(1));
289
+ container.addChild(new Text(theme.fg("error", `Error: ${message}`), 1, 0));
290
+ }
291
+
292
+ /**
293
+ * Options for InteractiveMode initialization.
294
+ */
295
+ export interface InteractiveModeOptions {
296
+ /** Providers that were migrated to auth.json (shows warning) */
297
+ migratedProviders?: string[];
298
+ /** Warning message if session model couldn't be restored */
299
+ modelFallbackMessage?: string;
300
+ /** Initial message to send on startup (can include @file content) */
301
+ initialMessage?: string;
302
+ /** Images to attach to the initial message */
303
+ initialImages?: ImageContent[];
304
+ /** Additional messages to send after the initial message */
305
+ initialMessages?: string[];
306
+ /** Force verbose startup (overrides quietStartup setting) */
307
+ verbose?: boolean;
308
+ /** Override the terminal implementation used by the TUI. */
309
+ terminal?: TuiTerminal;
310
+ /** When false, reuse the session's existing extension bindings instead of rebinding them for TUI mode. */
311
+ bindExtensions?: boolean;
312
+ /** Submit editor prompts directly to AgentSession instead of using the interactive prompt loop. */
313
+ submitPromptsDirectly?: boolean;
314
+ /** Control what happens when the user requests shutdown from the TUI. */
315
+ shutdownBehavior?: "exit_process" | "stop_ui" | "ignore";
316
+ }
317
+
318
+ export class InteractiveMode {
319
+ // Cap rendered chat components to prevent unbounded memory/CPU growth.
320
+ // Only render-components are removed — session transcript stays on disk.
321
+ private static readonly MAX_CHAT_COMPONENTS = 100;
322
+
323
+ private session: AgentSession;
324
+ private ui: TUI;
325
+ private chatContainer: Container;
326
+ private pendingMessagesContainer: Container;
327
+ private adaptiveLayout: AdaptiveLayoutComponent;
328
+ private statusContainer: Container;
329
+ private pinnedMessageContainer: Container;
330
+ private blockingErrorContainer: Container;
331
+ private defaultEditor: CustomEditor;
332
+ private editor: EditorComponent;
333
+ private autocompleteProvider: CombinedAutocompleteProvider | undefined;
334
+ private editorContainer: Container;
335
+ private footer: FooterComponent;
336
+ private footerDataProvider: FooterDataProvider;
337
+ private keybindings: KeybindingsManager;
338
+ private version: string;
339
+ private isInitialized = false;
340
+ private onInputCallback?: (text: string) => void;
341
+ private loadingAnimation: Loader | undefined = undefined;
342
+ private pendingWorkingMessage: string | null | undefined = undefined;
343
+ private readonly defaultWorkingMessage = "Working...";
344
+ private lastBlockingError: string | undefined = undefined;
345
+
346
+ private lastSigintTime = 0;
347
+ private lastEscapeTime = 0;
348
+ private changelogMarkdown: string | undefined = undefined;
349
+
350
+ // Status line tracking (for mutating immediately-sequential status updates)
351
+ private lastStatusSpacer: Spacer | undefined = undefined;
352
+ private lastStatusText: Text | undefined = undefined;
353
+
354
+ // Streaming message tracking
355
+ private streamingComponent: AssistantMessageComponent | undefined = undefined;
356
+ private streamingMessage: AssistantMessage | undefined = undefined;
357
+
358
+ // Tool execution tracking: toolCallId -> component
359
+ private pendingTools = new Map<string, ToolExecutionComponent>();
360
+
361
+ // Tool output expansion state
362
+ private toolOutputExpanded = true;
363
+
364
+ // Pasted image tracking
365
+ private pendingImages: ImageContent[] = [];
366
+
367
+ // Thinking block visibility state
368
+ private hideThinkingBlock = false;
369
+
370
+ // Skill commands: command name -> skill file path
371
+ private skillCommands = new Map<string, string>();
372
+
373
+ // Agent subscription unsubscribe function
374
+ private unsubscribe?: () => void;
375
+
376
+ // Branch change listener unsubscribe function
377
+ private _branchChangeUnsub?: () => void;
378
+ private _themeChangeUnsub?: () => void;
379
+ private markdownThemeCache?: MarkdownTheme;
380
+ private markdownThemeCacheIndent?: string;
381
+
382
+ // Track if editor is in bash mode (text starts with !)
383
+ private isBashMode = false;
384
+
385
+ // Contextual tips — session-scoped, non-intrusive hints
386
+ private contextualTips = new ContextualTips();
387
+
388
+ // Track current bash execution component
389
+ private bashComponent: BashExecutionComponent | undefined = undefined;
390
+
391
+ // Track pending bash components (shown in pending area, moved to chat on submit)
392
+ private pendingBashComponents: BashExecutionComponent[] = [];
393
+
394
+ // Auto-compaction state
395
+ private autoCompactionLoader: Loader | undefined = undefined;
396
+ private autoCompactionEscapeHandler?: () => void;
397
+
398
+ // Auto-retry state
399
+ private retryLoader: Loader | undefined = undefined;
400
+ private retryEscapeHandler?: () => void;
401
+
402
+ // Messages queued while compaction is running
403
+ private compactionQueuedMessages: CompactionQueuedMessage[] = [];
404
+
405
+ // Shutdown state
406
+ private shutdownRequested = false;
407
+
408
+ // Extension UI state
409
+ private extensionSelector: ExtensionSelectorComponent | undefined = undefined;
410
+ private extensionInput: ExtensionInputComponent | undefined = undefined;
411
+ private extensionEditor: ExtensionEditorComponent | undefined = undefined;
412
+ private extensionTerminalInputUnsubscribers = new Set<() => void>();
413
+ private stdinErrorHandler: ((err: Error) => void) | undefined = undefined;
414
+
415
+ // Extension widgets (components rendered above/below the editor)
416
+ private extensionWidgetsAbove = new Map<string, Component & { dispose?(): void }>();
417
+ private extensionWidgetsBelow = new Map<string, Component & { dispose?(): void }>();
418
+ private widgetContainerAbove!: Container;
419
+ private widgetContainerBelow!: Container;
420
+
421
+ // Custom footer from extension (undefined = use built-in footer)
422
+ private customFooter: (Component & { dispose?(): void }) | undefined = undefined;
423
+
424
+ // Header container that holds the built-in or custom header
425
+ private headerContainer: Container;
426
+
427
+ // Built-in header (logo + keybinding hints + changelog)
428
+ private builtInHeader: Component | undefined = undefined;
429
+
430
+ // Custom header from extension (undefined = use built-in header)
431
+ private customHeader: (Component & { dispose?(): void }) | undefined = undefined;
432
+
433
+ // Convenience accessors
434
+ private get agent() {
435
+ return this.session.agent;
436
+ }
437
+ private get sessionManager() {
438
+ return this.session.sessionManager;
439
+ }
440
+ private get settingsManager() {
441
+ return this.session.settingsManager;
442
+ }
443
+
444
+ constructor(
445
+ session: AgentSession,
446
+ private options: InteractiveModeOptions = {},
447
+ ) {
448
+ this.session = session;
449
+ this.version = VERSION;
450
+ this.ui = new TUI(options.terminal ?? new ProcessTerminal(), this.settingsManager.getShowHardwareCursor());
451
+ this.ui.setClearOnShrink(this.settingsManager.getClearOnShrink());
452
+ this.headerContainer = new Container();
453
+ this.chatContainer = new Container();
454
+ this.pendingMessagesContainer = new Container();
455
+ this.adaptiveLayout = new AdaptiveLayoutComponent(() => ({
456
+ override: this.settingsManager.getAdaptiveMode(),
457
+ activeToolCount: this.pendingTools.size,
458
+ gsdPhase: this.pendingWorkingMessage ?? undefined,
459
+ lastError: this.lastBlockingError,
460
+ sessionName: this.sessionManager.getSessionName(),
461
+ cwd: process.cwd(),
462
+ }));
463
+ this.statusContainer = new Container();
464
+ this.pinnedMessageContainer = new Container();
465
+ this.blockingErrorContainer = new Container();
466
+ this.widgetContainerAbove = new Container();
467
+ this.widgetContainerBelow = new Container();
468
+ this.keybindings = KeybindingsManager.create();
469
+ const editorPaddingX = this.settingsManager.getEditorPaddingX();
470
+ const autocompleteMaxVisible = this.settingsManager.getAutocompleteMaxVisible();
471
+ this.defaultEditor = new CustomEditor(this.ui, getEditorTheme(), this.keybindings, {
472
+ paddingX: editorPaddingX,
473
+ autocompleteMaxVisible,
474
+ });
475
+ this.editor = this.defaultEditor;
476
+ this.editorContainer = new Container();
477
+ this.editorContainer.addChild(this.editor as Component);
478
+ this.footerDataProvider = new FooterDataProvider();
479
+ this.footer = new FooterComponent(session, this.footerDataProvider);
480
+ this.footer.setAutoCompactEnabled(session.autoCompactionEnabled);
481
+
482
+ // Load hide thinking block setting
483
+ this.hideThinkingBlock = this.settingsManager.getHideThinkingBlock();
484
+
485
+ // Register themes from resource loader and initialize
486
+ setRegisteredThemes(this.session.resourceLoader.getThemes().themes);
487
+ initTheme(this.settingsManager.getTheme(), true);
488
+ }
489
+
490
+ private setupAutocomplete(): void {
491
+ // Define commands for autocomplete
492
+ const slashCommands: SlashCommand[] = BUILTIN_SLASH_COMMANDS.map((command) => ({
493
+ name: command.name,
494
+ description: command.description,
495
+ }));
496
+
497
+ const modelCommand = slashCommands.find((command) => command.name === "model");
498
+ if (modelCommand) {
499
+ modelCommand.getArgumentCompletions = (prefix: string): AutocompleteItem[] | null => {
500
+ // Get available models (scoped or from registry)
501
+ const models =
502
+ this.session.scopedModels.length > 0
503
+ ? this.session.scopedModels.map((s) => s.model)
504
+ : this.session.modelRegistry.getAvailable();
505
+
506
+ if (models.length === 0) return null;
507
+
508
+ // Create items with provider/id format
509
+ const items = models.map((m) => ({
510
+ id: m.id,
511
+ provider: m.provider,
512
+ label: `${m.provider}/${m.id}`,
513
+ }));
514
+
515
+ // Fuzzy filter by model ID + provider (allows "opus anthropic" to match)
516
+ const filtered = fuzzyFilter(items, prefix, (item) => `${item.id} ${item.provider}`);
517
+
518
+ if (filtered.length === 0) return null;
519
+
520
+ return filtered.map((item) => ({
521
+ value: item.label,
522
+ label: item.id,
523
+ description: providerDisplayName(item.provider),
524
+ }));
525
+ };
526
+ }
527
+
528
+ // Add argument completions for /thinking
529
+ const thinkingCommand = slashCommands.find((command) => command.name === "thinking");
530
+ if (thinkingCommand) {
531
+ thinkingCommand.getArgumentCompletions = (prefix: string): AutocompleteItem[] | null => {
532
+ const levels = [
533
+ { value: "off", label: "off", description: "Disable extended thinking" },
534
+ { value: "minimal", label: "minimal", description: "Minimal thinking budget" },
535
+ { value: "low", label: "low", description: "Low thinking budget" },
536
+ { value: "medium", label: "medium", description: "Medium thinking budget" },
537
+ { value: "high", label: "high", description: "High thinking budget" },
538
+ { value: "xhigh", label: "xhigh", description: "Maximum thinking budget" },
539
+ ];
540
+ const filtered = levels.filter((l) => l.value.startsWith(prefix.trim().toLowerCase()));
541
+ return filtered.length > 0 ? filtered : null;
542
+ };
543
+ }
544
+
545
+ // Convert prompt templates to SlashCommand format for autocomplete
546
+ const templateCommands: SlashCommand[] = this.session.promptTemplates.map((cmd) => ({
547
+ name: cmd.name,
548
+ description: cmd.description,
549
+ }));
550
+
551
+ // Convert extension commands to SlashCommand format
552
+ const builtinCommandNames = new Set(slashCommands.map((c) => c.name));
553
+ const extensionCommands: SlashCommand[] = (
554
+ this.session.extensionRunner?.getRegisteredCommands(builtinCommandNames) ?? []
555
+ ).map((cmd) => ({
556
+ name: cmd.name,
557
+ description: cmd.description ?? "(extension command)",
558
+ getArgumentCompletions: cmd.getArgumentCompletions,
559
+ }));
560
+
561
+ // Build skill commands from session.skills (if enabled)
562
+ this.skillCommands.clear();
563
+ const skillCommandList: SlashCommand[] = [];
564
+ if (this.settingsManager.getEnableSkillCommands()) {
565
+ for (const skill of this.session.resourceLoader.getSkills().skills) {
566
+ const commandName = `skill:${skill.name}`;
567
+ this.skillCommands.set(commandName, skill.filePath);
568
+ skillCommandList.push({ name: commandName, description: skill.description });
569
+ }
570
+ }
571
+
572
+ // Setup autocomplete
573
+ this.autocompleteProvider = new CombinedAutocompleteProvider(
574
+ [...slashCommands, ...templateCommands, ...extensionCommands, ...skillCommandList],
575
+ process.cwd(),
576
+ {
577
+ respectGitignore: this.settingsManager.getRespectGitignoreInPicker(),
578
+ excludeDirs: this.settingsManager.getSearchExcludeDirs(),
579
+ },
580
+ );
581
+ this.defaultEditor.setAutocompleteProvider(this.autocompleteProvider);
582
+ if (this.editor !== this.defaultEditor) {
583
+ this.editor.setAutocompleteProvider?.(this.autocompleteProvider);
584
+ }
585
+ }
586
+
587
+ private installStdinErrorRecovery(): void {
588
+ if (this.stdinErrorHandler) return;
589
+ this.stdinErrorHandler = (err: Error) => {
590
+ const errno = err as NodeJS.ErrnoException;
591
+ const isReadEio = errno.code === "EIO" || /read EIO/i.test(err.message);
592
+ if (!isReadEio) return;
593
+
594
+ process.stderr.write(`[pi] stdin EIO detected, aborting active stream\n`);
595
+ if (this.session.isStreaming) {
596
+ this.agent.abort("unknown");
597
+ this.showWarning("Terminal input was interrupted (EIO). Aborted the active response; send your message again.");
598
+ }
599
+ };
600
+ process.stdin.on("error", this.stdinErrorHandler);
601
+ }
602
+
603
+ async init(): Promise<void> {
604
+ if (this.isInitialized) return;
605
+
606
+ // Load changelog (only show new entries, skip for resumed sessions)
607
+ this.changelogMarkdown = this.getChangelogForDisplay();
608
+
609
+ // Ensure rg is available (downloads if missing, adds to PATH via getBinDir)
610
+ // rg is needed for grep tool and bash commands
611
+ await ensureTool("rg");
612
+
613
+ // Add header container as first child
614
+ this.ui.addChild(this.headerContainer);
615
+
616
+ // Add header with keybindings from config (unless silenced)
617
+ if (this.options.verbose || !this.settingsManager.getQuietStartup()) {
618
+ const logo = theme.bold(theme.fg("accent", APP_NAME)) + theme.fg("dim", ` v${this.version}`);
619
+
620
+ // Build startup instructions using keybinding hint helpers
621
+ const kb = this.keybindings;
622
+ const hint = (action: AppAction, desc: string) => appKeyHint(kb, action, desc);
623
+
624
+ const instructions = [
625
+ hint("interrupt", "to interrupt"),
626
+ hint("clear", "to clear"),
627
+ rawKeyHint(`${appKey(kb, "clear")} twice`, "to exit"),
628
+ hint("exit", "to exit (empty)"),
629
+ hint("suspend", "to suspend"),
630
+ keyHint("deleteToLineEnd", "to delete to end"),
631
+ hint("cycleThinkingLevel", "to cycle thinking level"),
632
+ rawKeyHint(`${appKey(kb, "cycleModelForward")}/${appKey(kb, "cycleModelBackward")}`, "to cycle models"),
633
+ hint("selectModel", "to select model"),
634
+ getToolExpansionStartupHint(this.toolOutputExpanded, kb),
635
+ hint("toggleThinking", "to expand thinking"),
636
+ hint("externalEditor", "for external editor"),
637
+ rawKeyHint("/", "for commands"),
638
+ rawKeyHint("!", "to run bash"),
639
+ rawKeyHint("!!", "to run bash (no context)"),
640
+ hint("followUp", "to queue follow-up"),
641
+ hint("dequeue", "to edit all queued messages"),
642
+ hint("pasteImage", "to paste image"),
643
+ rawKeyHint("drop files", "to attach"),
644
+ ].join("\n");
645
+ this.builtInHeader = new Text(`${logo}\n${instructions}`, 1, 0);
646
+
647
+ // Setup UI layout
648
+ this.headerContainer.addChild(new Spacer(1));
649
+ this.headerContainer.addChild(this.builtInHeader);
650
+ this.headerContainer.addChild(new Spacer(1));
651
+
652
+ // Add changelog if provided
653
+ if (this.changelogMarkdown) {
654
+ this.headerContainer.addChild(new DynamicBorder());
655
+ if (this.settingsManager.getCollapseChangelog()) {
656
+ const versionMatch = this.changelogMarkdown.match(/##\s+\[?(\d+\.\d+\.\d+)\]?/);
657
+ const latestVersion = versionMatch ? versionMatch[1] : this.version;
658
+ const condensedText = `Updated to v${latestVersion}. Use ${theme.bold("/changelog")} to view full changelog.`;
659
+ this.headerContainer.addChild(new Text(condensedText, 1, 0));
660
+ } else {
661
+ this.headerContainer.addChild(new Text(theme.bold(theme.fg("accent", "What's New")), 1, 0));
662
+ this.headerContainer.addChild(new Spacer(1));
663
+ this.headerContainer.addChild(
664
+ new Markdown(this.changelogMarkdown.trim(), 1, 0, this.getMarkdownThemeWithSettings()),
665
+ );
666
+ this.headerContainer.addChild(new Spacer(1));
667
+ }
668
+ this.headerContainer.addChild(new DynamicBorder());
669
+ }
670
+ } else {
671
+ // Minimal header when silenced
672
+ this.builtInHeader = new Text("", 0, 0);
673
+ this.headerContainer.addChild(this.builtInHeader);
674
+ if (this.changelogMarkdown) {
675
+ // Still show changelog notification even in silent mode
676
+ this.headerContainer.addChild(new Spacer(1));
677
+ const versionMatch = this.changelogMarkdown.match(/##\s+\[?(\d+\.\d+\.\d+)\]?/);
678
+ const latestVersion = versionMatch ? versionMatch[1] : this.version;
679
+ const condensedText = `Updated to v${latestVersion}. Use ${theme.bold("/changelog")} to view full changelog.`;
680
+ this.headerContainer.addChild(new Text(condensedText, 1, 0));
681
+ }
682
+ }
683
+
684
+ this.ui.addChild(this.adaptiveLayout);
685
+ this.ui.addChild(this.chatContainer);
686
+ this.ui.addChild(this.pendingMessagesContainer);
687
+ this.ui.addChild(this.statusContainer);
688
+ this.ui.addChild(this.pinnedMessageContainer);
689
+ this.ui.addChild(this.blockingErrorContainer);
690
+ this.renderWidgets(); // Initialize with default spacer
691
+ this.ui.addChild(this.widgetContainerAbove);
692
+ this.ui.addChild(this.editorContainer);
693
+ this.ui.addChild(this.widgetContainerBelow);
694
+ this.ui.addChild(this.footer);
695
+ this.ui.setFocus(this.editor);
696
+
697
+ this.setupKeyHandlers();
698
+ this.setupEditorSubmitHandler();
699
+
700
+ // Initialize extensions first so resources are shown before messages
701
+ await this.initExtensions();
702
+
703
+ // Render initial messages AFTER showing loaded resources
704
+ this.renderInitialMessages();
705
+
706
+ // Start the UI
707
+ this.ui.start();
708
+ this.installStdinErrorRecovery();
709
+ this.isInitialized = true;
710
+
711
+ // Set terminal title
712
+ this.updateTerminalTitle();
713
+
714
+ // Subscribe to agent events
715
+ this.subscribeToAgent();
716
+
717
+ // Set up theme file watcher
718
+ this._themeChangeUnsub = onThemeChange(() => {
719
+ this.clearMarkdownThemeCache();
720
+ this.ui.invalidate();
721
+ this.updateEditorBorderColor();
722
+ this.ui.requestRender();
723
+ });
724
+
725
+ // Set up git branch watcher (uses provider instead of footer)
726
+ this._branchChangeUnsub = this.footerDataProvider.onBranchChange(() => {
727
+ this.ui.requestRender();
728
+ });
729
+
730
+ // Initialize available provider count for footer display
731
+ await this.updateAvailableProviderCount();
732
+ }
733
+
734
+ /**
735
+ * Update terminal title with session name and cwd.
736
+ */
737
+ private updateTerminalTitle(): void {
738
+ const cwdBasename = path.basename(process.cwd());
739
+ const sessionName = this.sessionManager.getSessionName();
740
+ if (sessionName) {
741
+ this.ui.terminal.setTitle(`π - ${sessionName} - ${cwdBasename}`);
742
+ } else {
743
+ this.ui.terminal.setTitle(`π - ${cwdBasename}`);
744
+ }
745
+ }
746
+
747
+ /**
748
+ * Run the interactive mode. This is the main entry point.
749
+ * Initializes the UI, shows warnings, processes initial messages, and starts the interactive loop.
750
+ */
751
+ async run(): Promise<void> {
752
+ await this.init();
753
+
754
+ // Start version check asynchronously
755
+ this.checkForNewVersion().then((newVersion) => {
756
+ if (newVersion) {
757
+ this.showNewVersionNotification(newVersion);
758
+ }
759
+ });
760
+
761
+ // Check tmux keyboard setup asynchronously
762
+ this.checkTmuxKeyboardSetup().then((warning) => {
763
+ if (warning) {
764
+ this.showWarning(warning);
765
+ }
766
+ });
767
+
768
+ // Show startup warnings
769
+ const { migratedProviders, modelFallbackMessage, initialMessage, initialImages, initialMessages } = this.options;
770
+
771
+ if (migratedProviders && migratedProviders.length > 0) {
772
+ this.showWarning(`Migrated credentials to auth.json: ${migratedProviders.join(", ")}`);
773
+ }
774
+
775
+ const modelsJsonError = this.session.modelRegistry.getError();
776
+ if (modelsJsonError) {
777
+ this.showError(`models.json error: ${modelsJsonError}`);
778
+ }
779
+
780
+ if (modelFallbackMessage) {
781
+ this.showWarning(modelFallbackMessage);
782
+ }
783
+
784
+ // Process initial messages
785
+ if (initialMessage) {
786
+ try {
787
+ await this.session.prompt(initialMessage, { images: initialImages });
788
+ } catch (error: unknown) {
789
+ const errorMessage = error instanceof Error ? error.message : "Unknown error occurred";
790
+ this.showError(errorMessage);
791
+ }
792
+ }
793
+
794
+ if (initialMessages) {
795
+ for (const message of initialMessages) {
796
+ try {
797
+ await this.session.prompt(message);
798
+ } catch (error: unknown) {
799
+ const errorMessage = error instanceof Error ? error.message : "Unknown error occurred";
800
+ this.showError(errorMessage);
801
+ }
802
+ }
803
+ }
804
+
805
+ // Main interactive loop
806
+ while (true) {
807
+ const userInput = await this.getUserInput();
808
+ const images = this.pendingImages.length > 0 ? [...this.pendingImages] : undefined;
809
+ this.pendingImages.length = 0;
810
+ try {
811
+ await this.session.prompt(userInput, { images });
812
+ } catch (error: unknown) {
813
+ const errorMessage = error instanceof Error ? error.message : "Unknown error occurred";
814
+ this.showError(errorMessage);
815
+ }
816
+ }
817
+ }
818
+
819
+ /**
820
+ * Check npm registry for a newer version.
821
+ */
822
+ private async checkForNewVersion(): Promise<string | undefined> {
823
+ if (process.env.PI_SKIP_VERSION_CHECK || process.env.PI_OFFLINE) return undefined;
824
+
825
+ try {
826
+ const response = await fetch("https://registry.npmjs.org/@gsd/pi-coding-agent/latest", {
827
+ signal: AbortSignal.timeout(10000),
828
+ });
829
+ if (!response.ok) return undefined;
830
+
831
+ const data = (await response.json()) as { version?: string };
832
+ const latestVersion = data.version;
833
+
834
+ if (latestVersion && latestVersion !== this.version) {
835
+ return latestVersion;
836
+ }
837
+
838
+ return undefined;
839
+ } catch {
840
+ return undefined;
841
+ }
842
+ }
843
+
844
+ private async checkTmuxKeyboardSetup(): Promise<string | undefined> {
845
+ if (!process.env.TMUX) return undefined;
846
+
847
+ const runTmuxShow = (option: string): Promise<string | undefined> => {
848
+ return new Promise((resolve) => {
849
+ const proc = spawn("tmux", ["show", "-gv", option], {
850
+ stdio: ["ignore", "pipe", "ignore"],
851
+ });
852
+ let stdout = "";
853
+ const timer = setTimeout(() => {
854
+ proc.kill();
855
+ resolve(undefined);
856
+ }, 2000);
857
+
858
+ proc.stdout?.on("data", (data) => {
859
+ stdout += data.toString();
860
+ });
861
+ proc.on("error", () => {
862
+ clearTimeout(timer);
863
+ resolve(undefined);
864
+ });
865
+ proc.on("close", (code) => {
866
+ clearTimeout(timer);
867
+ resolve(code === 0 ? stdout.trim() : undefined);
868
+ });
869
+ });
870
+ };
871
+
872
+ const [extendedKeys, extendedKeysFormat] = await Promise.all([
873
+ runTmuxShow("extended-keys"),
874
+ runTmuxShow("extended-keys-format"),
875
+ ]);
876
+
877
+ if (extendedKeys !== "on" && extendedKeys !== "always") {
878
+ return "tmux extended-keys is off. Modified Enter keys may not work. Add `set -g extended-keys on` to ~/.tmux.conf and restart tmux.";
879
+ }
880
+
881
+ if (extendedKeysFormat === "xterm") {
882
+ return "tmux extended-keys-format is xterm. Pi works best with csi-u. Add `set -g extended-keys-format csi-u` to ~/.tmux.conf and restart tmux.";
883
+ }
884
+
885
+ return undefined;
886
+ }
887
+
888
+ /**
889
+ * Get changelog entries to display on startup.
890
+ * Only shows new entries since last seen version, skips for resumed sessions.
891
+ */
892
+ private getChangelogForDisplay(): string | undefined {
893
+ // Skip changelog for resumed/continued sessions (already have messages)
894
+ if (this.session.state.messages.length > 0) {
895
+ return undefined;
896
+ }
897
+
898
+ const lastVersion = this.settingsManager.getLastChangelogVersion();
899
+ const changelogPath = getChangelogPath();
900
+ const entries = parseChangelog(changelogPath);
901
+
902
+ if (!lastVersion) {
903
+ // Fresh install - just record the version, don't show changelog
904
+ this.settingsManager.setLastChangelogVersion(VERSION);
905
+ return undefined;
906
+ } else {
907
+ const newEntries = getNewEntries(entries, lastVersion);
908
+ if (newEntries.length > 0) {
909
+ this.settingsManager.setLastChangelogVersion(VERSION);
910
+ return newEntries.map((e) => e.content).join("\n\n");
911
+ }
912
+ }
913
+
914
+ return undefined;
915
+ }
916
+
917
+ private getMarkdownThemeWithSettings(): MarkdownTheme {
918
+ const codeBlockIndent = this.settingsManager.getCodeBlockIndent();
919
+ if (this.markdownThemeCache && this.markdownThemeCacheIndent === codeBlockIndent) {
920
+ return this.markdownThemeCache;
921
+ }
922
+
923
+ this.markdownThemeCacheIndent = codeBlockIndent;
924
+ this.markdownThemeCache = {
925
+ ...getMarkdownTheme(),
926
+ codeBlockIndent,
927
+ };
928
+ return this.markdownThemeCache;
929
+ }
930
+
931
+ private clearMarkdownThemeCache(): void {
932
+ this.markdownThemeCache = undefined;
933
+ this.markdownThemeCacheIndent = undefined;
934
+ }
935
+
936
+ // =========================================================================
937
+ // Extension System
938
+ // =========================================================================
939
+
940
+ private formatDisplayPath(p: string): string {
941
+ const home = os.homedir();
942
+ let result = p;
943
+
944
+ // Replace home directory with ~
945
+ if (result.startsWith(home)) {
946
+ result = `~${result.slice(home.length)}`;
947
+ }
948
+
949
+ return result;
950
+ }
951
+
952
+ /**
953
+ * Get a short path relative to the package root for display.
954
+ */
955
+ private getShortPath(fullPath: string, source: string): string {
956
+ // For npm packages, show path relative to node_modules/pkg/
957
+ const npmMatch = fullPath.match(/node_modules\/(@?[^/]+(?:\/[^/]+)?)\/(.*)/);
958
+ if (npmMatch && source.startsWith("npm:")) {
959
+ return npmMatch[2];
960
+ }
961
+
962
+ // For git packages, show path relative to repo root
963
+ const gitMatch = fullPath.match(/git\/[^/]+\/[^/]+\/(.*)/);
964
+ if (gitMatch && source.startsWith("git:")) {
965
+ return gitMatch[1];
966
+ }
967
+
968
+ // For local/auto, just use formatDisplayPath
969
+ return this.formatDisplayPath(fullPath);
970
+ }
971
+
972
+ private getDisplaySourceInfo(
973
+ source: string,
974
+ scope: string,
975
+ ): { label: string; scopeLabel?: string; color: "accent" | "muted" } {
976
+ if (source === "local") {
977
+ if (scope === "user") {
978
+ return { label: "user", color: "muted" };
979
+ }
980
+ if (scope === "project") {
981
+ return { label: "project", color: "muted" };
982
+ }
983
+ if (scope === "temporary") {
984
+ return { label: "path", scopeLabel: "temp", color: "muted" };
985
+ }
986
+ return { label: "path", color: "muted" };
987
+ }
988
+
989
+ if (source === "cli") {
990
+ return { label: "path", scopeLabel: scope === "temporary" ? "temp" : undefined, color: "muted" };
991
+ }
992
+
993
+ const scopeLabel =
994
+ scope === "user" ? "user" : scope === "project" ? "project" : scope === "temporary" ? "temp" : undefined;
995
+ return { label: source, scopeLabel, color: "accent" };
996
+ }
997
+
998
+ private getScopeGroup(source: string, scope: string): "user" | "project" | "path" {
999
+ if (source === "cli" || scope === "temporary") return "path";
1000
+ if (scope === "user") return "user";
1001
+ if (scope === "project") return "project";
1002
+ return "path";
1003
+ }
1004
+
1005
+ private isPackageSource(source: string): boolean {
1006
+ return source.startsWith("npm:") || source.startsWith("git:");
1007
+ }
1008
+
1009
+ private buildScopeGroups(
1010
+ paths: string[],
1011
+ metadata: Map<string, { source: string; scope: string; origin: string }>,
1012
+ ): Array<{ scope: "user" | "project" | "path"; paths: string[]; packages: Map<string, string[]> }> {
1013
+ const groups: Record<
1014
+ "user" | "project" | "path",
1015
+ { scope: "user" | "project" | "path"; paths: string[]; packages: Map<string, string[]> }
1016
+ > = {
1017
+ user: { scope: "user", paths: [], packages: new Map() },
1018
+ project: { scope: "project", paths: [], packages: new Map() },
1019
+ path: { scope: "path", paths: [], packages: new Map() },
1020
+ };
1021
+
1022
+ for (const p of paths) {
1023
+ const meta = this.findMetadata(p, metadata);
1024
+ const source = meta?.source ?? "local";
1025
+ const scope = meta?.scope ?? "project";
1026
+ const groupKey = this.getScopeGroup(source, scope);
1027
+ const group = groups[groupKey];
1028
+
1029
+ if (this.isPackageSource(source)) {
1030
+ const list = group.packages.get(source) ?? [];
1031
+ list.push(p);
1032
+ group.packages.set(source, list);
1033
+ } else {
1034
+ group.paths.push(p);
1035
+ }
1036
+ }
1037
+
1038
+ return [groups.project, groups.user, groups.path].filter(
1039
+ (group) => group.paths.length > 0 || group.packages.size > 0,
1040
+ );
1041
+ }
1042
+
1043
+ private formatScopeGroups(
1044
+ groups: Array<{ scope: "user" | "project" | "path"; paths: string[]; packages: Map<string, string[]> }>,
1045
+ options: {
1046
+ formatPath: (p: string) => string;
1047
+ formatPackagePath: (p: string, source: string) => string;
1048
+ },
1049
+ ): string {
1050
+ const lines: string[] = [];
1051
+
1052
+ for (const group of groups) {
1053
+ lines.push(` ${theme.fg("accent", group.scope)}`);
1054
+
1055
+ const sortedPaths = [...group.paths].sort((a, b) => a.localeCompare(b));
1056
+ for (const p of sortedPaths) {
1057
+ lines.push(theme.fg("dim", ` ${options.formatPath(p)}`));
1058
+ }
1059
+
1060
+ const sortedPackages = Array.from(group.packages.entries()).sort(([a], [b]) => a.localeCompare(b));
1061
+ for (const [source, paths] of sortedPackages) {
1062
+ lines.push(` ${theme.fg("mdLink", source)}`);
1063
+ const sortedPackagePaths = [...paths].sort((a, b) => a.localeCompare(b));
1064
+ for (const p of sortedPackagePaths) {
1065
+ lines.push(theme.fg("dim", ` ${options.formatPackagePath(p, source)}`));
1066
+ }
1067
+ }
1068
+ }
1069
+
1070
+ return lines.join("\n");
1071
+ }
1072
+
1073
+ /**
1074
+ * Find metadata for a path, checking parent directories if exact match fails.
1075
+ * Package manager stores metadata for directories, but we display file paths.
1076
+ */
1077
+ private findMetadata(
1078
+ p: string,
1079
+ metadata: Map<string, { source: string; scope: string; origin: string }>,
1080
+ ): { source: string; scope: string; origin: string } | undefined {
1081
+ // Try exact match first
1082
+ const exact = metadata.get(p);
1083
+ if (exact) return exact;
1084
+
1085
+ // Try parent directories (package manager stores directory paths)
1086
+ let current = p;
1087
+ let parent = path.dirname(current);
1088
+ while (parent !== current) {
1089
+ const meta = metadata.get(parent);
1090
+ if (meta) return meta;
1091
+ current = parent;
1092
+ parent = path.dirname(current);
1093
+ }
1094
+
1095
+ return undefined;
1096
+ }
1097
+
1098
+ /**
1099
+ * Format a path with its source/scope info from metadata.
1100
+ */
1101
+ private formatPathWithSource(
1102
+ p: string,
1103
+ metadata: Map<string, { source: string; scope: string; origin: string }>,
1104
+ ): string {
1105
+ const meta = this.findMetadata(p, metadata);
1106
+ if (meta) {
1107
+ const shortPath = this.getShortPath(p, meta.source);
1108
+ const { label, scopeLabel } = this.getDisplaySourceInfo(meta.source, meta.scope);
1109
+ const labelText = scopeLabel ? `${label} (${scopeLabel})` : label;
1110
+ return `${labelText} ${shortPath}`;
1111
+ }
1112
+ return this.formatDisplayPath(p);
1113
+ }
1114
+
1115
+ /**
1116
+ * Format resource diagnostics with nice collision display using metadata.
1117
+ */
1118
+ private formatDiagnostics(
1119
+ diagnostics: readonly ResourceDiagnostic[],
1120
+ metadata: Map<string, { source: string; scope: string; origin: string }>,
1121
+ ): string {
1122
+ const lines: string[] = [];
1123
+
1124
+ // Group collision diagnostics by name
1125
+ const collisions = new Map<string, ResourceDiagnostic[]>();
1126
+ const otherDiagnostics: ResourceDiagnostic[] = [];
1127
+
1128
+ for (const d of diagnostics) {
1129
+ if (d.type === "collision" && d.collision) {
1130
+ const list = collisions.get(d.collision.name) ?? [];
1131
+ list.push(d);
1132
+ collisions.set(d.collision.name, list);
1133
+ } else {
1134
+ otherDiagnostics.push(d);
1135
+ }
1136
+ }
1137
+
1138
+ // Format collision diagnostics grouped by name
1139
+ for (const [name, collisionList] of collisions) {
1140
+ const first = collisionList[0]?.collision;
1141
+ if (!first) continue;
1142
+ lines.push(theme.fg("warning", ` "${name}" collision:`));
1143
+ // Show winner
1144
+ lines.push(
1145
+ theme.fg("dim", ` ${theme.fg("success", "✓")} ${this.formatPathWithSource(first.winnerPath, metadata)}`),
1146
+ );
1147
+ // Show all losers
1148
+ for (const d of collisionList) {
1149
+ if (d.collision) {
1150
+ lines.push(
1151
+ theme.fg(
1152
+ "dim",
1153
+ ` ${theme.fg("warning", "✗")} ${this.formatPathWithSource(d.collision.loserPath, metadata)} (skipped)`,
1154
+ ),
1155
+ );
1156
+ }
1157
+ }
1158
+ }
1159
+
1160
+ // Format other diagnostics (skill name collisions, parse errors, etc.)
1161
+ for (const d of otherDiagnostics) {
1162
+ if (d.path) {
1163
+ // Use metadata-aware formatting for paths
1164
+ const sourceInfo = this.formatPathWithSource(d.path, metadata);
1165
+ lines.push(theme.fg(d.type === "error" ? "error" : "warning", ` ${sourceInfo}`));
1166
+ lines.push(theme.fg(d.type === "error" ? "error" : "warning", ` ${d.message}`));
1167
+ } else {
1168
+ lines.push(theme.fg(d.type === "error" ? "error" : "warning", ` ${d.message}`));
1169
+ }
1170
+ }
1171
+
1172
+ return lines.join("\n");
1173
+ }
1174
+
1175
+ private showLoadedResources(options?: {
1176
+ extensionPaths?: string[];
1177
+ force?: boolean;
1178
+ showDiagnosticsWhenQuiet?: boolean;
1179
+ }): void {
1180
+ const showListing = options?.force || this.options.verbose || !this.settingsManager.getQuietStartup();
1181
+ const showDiagnostics = showListing || options?.showDiagnosticsWhenQuiet === true;
1182
+ if (!showListing && !showDiagnostics) {
1183
+ return;
1184
+ }
1185
+
1186
+ const metadata = this.session.resourceLoader.getPathMetadata();
1187
+ const sectionHeader = (name: string, color: ThemeColor = "mdHeading") => theme.fg(color, `[${name}]`);
1188
+
1189
+ const skillsResult = this.session.resourceLoader.getSkills();
1190
+ const promptsResult = this.session.resourceLoader.getPrompts();
1191
+ const themesResult = this.session.resourceLoader.getThemes();
1192
+
1193
+ if (showListing) {
1194
+ const contextFiles = this.session.resourceLoader.getAgentsFiles().agentsFiles;
1195
+ if (contextFiles.length > 0) {
1196
+ this.chatContainer.addChild(new Spacer(1));
1197
+ const contextList = contextFiles
1198
+ .map((f) => theme.fg("dim", ` ${this.formatDisplayPath(f.path)}`))
1199
+ .join("\n");
1200
+ this.chatContainer.addChild(new Text(`${sectionHeader("Context")}\n${contextList}`, 0, 0));
1201
+ this.chatContainer.addChild(new Spacer(1));
1202
+ }
1203
+
1204
+ const skills = skillsResult.skills;
1205
+ if (skills.length > 0) {
1206
+ const skillPaths = skills.map((s) => s.filePath);
1207
+ const groups = this.buildScopeGroups(skillPaths, metadata);
1208
+ const skillList = this.formatScopeGroups(groups, {
1209
+ formatPath: (p) => this.formatDisplayPath(p),
1210
+ formatPackagePath: (p, source) => this.getShortPath(p, source),
1211
+ });
1212
+ this.chatContainer.addChild(new Text(`${sectionHeader("Skills")}\n${skillList}`, 0, 0));
1213
+ this.chatContainer.addChild(new Spacer(1));
1214
+ }
1215
+
1216
+ const templates = this.session.promptTemplates;
1217
+ if (templates.length > 0) {
1218
+ const templatePaths = templates.map((t) => t.filePath);
1219
+ const groups = this.buildScopeGroups(templatePaths, metadata);
1220
+ const templateByPath = new Map(templates.map((t) => [t.filePath, t]));
1221
+ const templateList = this.formatScopeGroups(groups, {
1222
+ formatPath: (p) => {
1223
+ const template = templateByPath.get(p);
1224
+ return template ? `/${template.name}` : this.formatDisplayPath(p);
1225
+ },
1226
+ formatPackagePath: (p) => {
1227
+ const template = templateByPath.get(p);
1228
+ return template ? `/${template.name}` : this.formatDisplayPath(p);
1229
+ },
1230
+ });
1231
+ this.chatContainer.addChild(new Text(`${sectionHeader("Prompts")}\n${templateList}`, 0, 0));
1232
+ this.chatContainer.addChild(new Spacer(1));
1233
+ }
1234
+
1235
+ const extensionPaths = options?.extensionPaths ?? [];
1236
+ if (extensionPaths.length > 0) {
1237
+ const groups = this.buildScopeGroups(extensionPaths, metadata);
1238
+ const extList = this.formatScopeGroups(groups, {
1239
+ formatPath: (p) => this.formatDisplayPath(p),
1240
+ formatPackagePath: (p, source) => this.getShortPath(p, source),
1241
+ });
1242
+ this.chatContainer.addChild(new Text(`${sectionHeader("Extensions", "mdHeading")}\n${extList}`, 0, 0));
1243
+ this.chatContainer.addChild(new Spacer(1));
1244
+ }
1245
+
1246
+ // Show loaded themes (excluding built-in)
1247
+ const loadedThemes = themesResult.themes;
1248
+ const customThemes = loadedThemes.filter((t) => t.sourcePath);
1249
+ if (customThemes.length > 0) {
1250
+ const themePaths = customThemes.map((t) => t.sourcePath!);
1251
+ const groups = this.buildScopeGroups(themePaths, metadata);
1252
+ const themeList = this.formatScopeGroups(groups, {
1253
+ formatPath: (p) => this.formatDisplayPath(p),
1254
+ formatPackagePath: (p, source) => this.getShortPath(p, source),
1255
+ });
1256
+ this.chatContainer.addChild(new Text(`${sectionHeader("Themes")}\n${themeList}`, 0, 0));
1257
+ this.chatContainer.addChild(new Spacer(1));
1258
+ }
1259
+ }
1260
+
1261
+ if (showDiagnostics) {
1262
+ const skillDiagnostics = skillsResult.diagnostics;
1263
+ if (skillDiagnostics.length > 0) {
1264
+ const collisionDiags = skillDiagnostics.filter(d => d.type === "collision");
1265
+ const issueDiags = skillDiagnostics.filter(d => d.type !== "collision");
1266
+
1267
+ if (collisionDiags.length > 0) {
1268
+ const collisionLines = this.formatDiagnostics(collisionDiags, metadata);
1269
+ this.chatContainer.addChild(new Text(`${theme.fg("warning", "[Skill conflicts]")}\n${collisionLines}`, 0, 0));
1270
+ this.chatContainer.addChild(new Spacer(1));
1271
+ }
1272
+
1273
+ if (issueDiags.length > 0) {
1274
+ const issueLines = this.formatDiagnostics(issueDiags, metadata);
1275
+ this.chatContainer.addChild(new Text(`${theme.fg("warning", "[Skill issues]")}\n${issueLines}`, 0, 0));
1276
+ this.chatContainer.addChild(new Spacer(1));
1277
+ }
1278
+ }
1279
+
1280
+ const promptDiagnostics = promptsResult.diagnostics;
1281
+ if (promptDiagnostics.length > 0) {
1282
+ const warningLines = this.formatDiagnostics(promptDiagnostics, metadata);
1283
+ this.chatContainer.addChild(
1284
+ new Text(`${theme.fg("warning", "[Prompt conflicts]")}\n${warningLines}`, 0, 0),
1285
+ );
1286
+ this.chatContainer.addChild(new Spacer(1));
1287
+ }
1288
+
1289
+ const extensionDiagnostics: ResourceDiagnostic[] = [];
1290
+ const extensionErrors = this.session.resourceLoader.getExtensions().errors;
1291
+ if (extensionErrors.length > 0) {
1292
+ for (const error of extensionErrors) {
1293
+ extensionDiagnostics.push({ type: "error", message: error.error, path: error.path });
1294
+ }
1295
+ }
1296
+
1297
+ const commandDiagnostics = this.session.extensionRunner?.getCommandDiagnostics() ?? [];
1298
+ extensionDiagnostics.push(...commandDiagnostics);
1299
+
1300
+ const shortcutDiagnostics = this.session.extensionRunner?.getShortcutDiagnostics() ?? [];
1301
+ extensionDiagnostics.push(...shortcutDiagnostics);
1302
+
1303
+ if (extensionDiagnostics.length > 0) {
1304
+ const warningLines = this.formatDiagnostics(extensionDiagnostics, metadata);
1305
+ this.chatContainer.addChild(
1306
+ new Text(`${theme.fg("warning", "[Extension issues]")}\n${warningLines}`, 0, 0),
1307
+ );
1308
+ this.chatContainer.addChild(new Spacer(1));
1309
+ }
1310
+
1311
+ const themeDiagnostics = themesResult.diagnostics;
1312
+ if (themeDiagnostics.length > 0) {
1313
+ const warningLines = this.formatDiagnostics(themeDiagnostics, metadata);
1314
+ this.chatContainer.addChild(new Text(`${theme.fg("warning", "[Theme conflicts]")}\n${warningLines}`, 0, 0));
1315
+ this.chatContainer.addChild(new Spacer(1));
1316
+ }
1317
+ }
1318
+ }
1319
+
1320
+ /**
1321
+ * Initialize the extension system with TUI-based UI context.
1322
+ */
1323
+ private async initExtensions(): Promise<void> {
1324
+ if (this.options.bindExtensions !== false) {
1325
+ const uiContext = this.createExtensionUIContext();
1326
+ await this.session.bindExtensions({
1327
+ uiContext,
1328
+ commandContextActions: {
1329
+ waitForIdle: () => this.session.agent.waitForIdle(),
1330
+ newSession: async (options) => {
1331
+ if (this.loadingAnimation) {
1332
+ this.loadingAnimation.stop();
1333
+ this.loadingAnimation = undefined;
1334
+ }
1335
+ this.statusContainer.clear();
1336
+
1337
+ // Delegate to AgentSession (handles setup + agent state sync)
1338
+ const success = await this.session.newSession(options);
1339
+ if (!success) {
1340
+ return { cancelled: true };
1341
+ }
1342
+
1343
+ // Clear UI state
1344
+ this.chatContainer.clear();
1345
+ this.pendingMessagesContainer.clear();
1346
+ this.compactionQueuedMessages = [];
1347
+ this.streamingComponent = undefined;
1348
+ this.streamingMessage = undefined;
1349
+ this.pendingTools.clear();
1350
+ this.clearBlockingError();
1351
+
1352
+ // Render any messages added via setup, or show empty session
1353
+ this.renderInitialMessages();
1354
+ this.ui.requestRender();
1355
+
1356
+ return { cancelled: false };
1357
+ },
1358
+ fork: async (entryId) => {
1359
+ const result = await this.session.fork(entryId);
1360
+ if (result.cancelled) {
1361
+ return { cancelled: true };
1362
+ }
1363
+
1364
+ this.chatContainer.clear();
1365
+ this.renderInitialMessages();
1366
+ this.editor.setText(result.selectedText);
1367
+ this.showStatus("Forked to new session");
1368
+
1369
+ return { cancelled: false };
1370
+ },
1371
+ navigateTree: async (targetId, options) => {
1372
+ const result = await this.session.navigateTree(targetId, {
1373
+ summarize: options?.summarize,
1374
+ customInstructions: options?.customInstructions,
1375
+ replaceInstructions: options?.replaceInstructions,
1376
+ label: options?.label,
1377
+ });
1378
+ if (result.cancelled) {
1379
+ return { cancelled: true };
1380
+ }
1381
+
1382
+ this.chatContainer.clear();
1383
+ this.renderInitialMessages();
1384
+ if (result.editorText && !this.editor.getText().trim()) {
1385
+ this.editor.setText(result.editorText);
1386
+ }
1387
+ this.showStatus("Navigated to selected point");
1388
+
1389
+ return { cancelled: false };
1390
+ },
1391
+ switchSession: async (sessionPath) => {
1392
+ await this.handleResumeSession(sessionPath);
1393
+ return { cancelled: false };
1394
+ },
1395
+ reload: async () => {
1396
+ await this.handleReloadCommand();
1397
+ },
1398
+ },
1399
+ shutdownHandler: () => {
1400
+ this.shutdownRequested = true;
1401
+ if (!this.session.isStreaming) {
1402
+ void this.shutdown();
1403
+ }
1404
+ },
1405
+ onError: (error) => {
1406
+ this.showExtensionError(error.extensionPath, error.error, error.stack);
1407
+ },
1408
+ });
1409
+ }
1410
+
1411
+ setRegisteredThemes(this.session.resourceLoader.getThemes().themes);
1412
+ this.setupAutocomplete();
1413
+
1414
+ const extensionRunner = this.session.extensionRunner;
1415
+ if (!extensionRunner) {
1416
+ this.showLoadedResources({ extensionPaths: [], force: false });
1417
+ return;
1418
+ }
1419
+
1420
+ this.setupExtensionShortcuts(extensionRunner);
1421
+ this.showLoadedResources({ extensionPaths: extensionRunner.getExtensionPaths(), force: false });
1422
+ }
1423
+
1424
+ /**
1425
+ * Get a tool definition by name (for custom rendering).
1426
+ */
1427
+ private getRegisteredToolDefinition(toolName: string) {
1428
+ return this.session.getRenderableToolDefinition(toolName);
1429
+ }
1430
+
1431
+ /**
1432
+ * Format web search result content for display in the TUI.
1433
+ */
1434
+ private formatWebSearchResult(content: unknown): string {
1435
+ if (!content) return "Web search completed";
1436
+
1437
+ // Error result
1438
+ if (typeof content === "object" && "type" in (content as any) && (content as any).type === "web_search_tool_result_error") {
1439
+ const error = content as any;
1440
+ return `Search error: ${error.error_code || "unknown"}`;
1441
+ }
1442
+
1443
+ // Array of search results
1444
+ if (Array.isArray(content)) {
1445
+ const results = content.filter((r: any) => r.type === "web_search_result");
1446
+ if (results.length === 0) return "No results found";
1447
+ return results
1448
+ .map((r: any) => {
1449
+ const title = r.title || "Untitled";
1450
+ const url = r.url || "";
1451
+ return `${title}\n ${url}`;
1452
+ })
1453
+ .join("\n");
1454
+ }
1455
+
1456
+ return "Web search completed";
1457
+ }
1458
+
1459
+ /**
1460
+ * Set up keyboard shortcuts registered by extensions.
1461
+ */
1462
+ private setupExtensionShortcuts(extensionRunner: ExtensionRunner): void {
1463
+ const shortcuts = extensionRunner.getShortcuts(this.keybindings.getEffectiveConfig());
1464
+ if (shortcuts.size === 0) return;
1465
+
1466
+ // Create a context for shortcut handlers
1467
+ const createContext = (): ExtensionContext => ({
1468
+ ui: this.createExtensionUIContext(),
1469
+ hasUI: true,
1470
+ cwd: process.cwd(),
1471
+ sessionManager: this.sessionManager,
1472
+ modelRegistry: this.session.modelRegistry,
1473
+ model: this.session.model,
1474
+ isIdle: () => !this.session.isStreaming,
1475
+ abort: () => this.session.abort({ origin: "user" }),
1476
+ hasPendingMessages: () => this.session.pendingMessageCount > 0,
1477
+ shutdown: () => {
1478
+ this.shutdownRequested = true;
1479
+ },
1480
+ getContextUsage: () => this.session.getContextUsage(),
1481
+ compact: (options) => {
1482
+ void (async () => {
1483
+ try {
1484
+ const result = await this.executeCompaction(options?.customInstructions, false);
1485
+ if (result) {
1486
+ options?.onComplete?.(result);
1487
+ }
1488
+ } catch (error) {
1489
+ const err = error instanceof Error ? error : new Error(String(error));
1490
+ options?.onError?.(err);
1491
+ }
1492
+ })();
1493
+ },
1494
+ getSystemPrompt: () => this.session.systemPrompt,
1495
+ setCompactionThresholdOverride: (percent) => {
1496
+ this.session.settingsManager.setCompactionThresholdOverride(percent);
1497
+ },
1498
+ });
1499
+
1500
+ // Set up the extension shortcut handler on the default editor
1501
+ this.defaultEditor.onExtensionShortcut = (data: string) => {
1502
+ for (const [shortcutStr, shortcut] of shortcuts) {
1503
+ // Cast to KeyId - extension shortcuts use the same format
1504
+ if (matchesKey(data, shortcutStr as KeyId)) {
1505
+ // Run handler async, don't block input
1506
+ Promise.resolve(shortcut.handler(createContext())).catch((err) => {
1507
+ this.showError(`Shortcut handler error: ${err instanceof Error ? err.message : String(err)}`);
1508
+ });
1509
+ return true;
1510
+ }
1511
+ }
1512
+ return false;
1513
+ };
1514
+ }
1515
+
1516
+ /**
1517
+ * Set extension status text in the footer.
1518
+ */
1519
+ private setExtensionStatus(key: string, text: string | undefined): void {
1520
+ this.footerDataProvider.setExtensionStatus(key, text);
1521
+ this.ui.requestRender();
1522
+ }
1523
+
1524
+ /**
1525
+ * Set an extension widget (string array or custom component).
1526
+ */
1527
+ private setExtensionWidget(
1528
+ key: string,
1529
+ content: string[] | ((tui: TUI, thm: Theme) => Component & { dispose?(): void }) | undefined,
1530
+ options?: ExtensionWidgetOptions,
1531
+ ): void {
1532
+ const placement = options?.placement ?? "aboveEditor";
1533
+ const removeExisting = (map: Map<string, Component & { dispose?(): void }>) => {
1534
+ const existing = map.get(key);
1535
+ if (existing?.dispose) existing.dispose();
1536
+ map.delete(key);
1537
+ };
1538
+
1539
+ removeExisting(this.extensionWidgetsAbove);
1540
+ removeExisting(this.extensionWidgetsBelow);
1541
+
1542
+ if (content === undefined) {
1543
+ this.renderWidgets();
1544
+ return;
1545
+ }
1546
+
1547
+ let component: Component & { dispose?(): void };
1548
+
1549
+ if (Array.isArray(content)) {
1550
+ // Wrap string array in a Container with Text components
1551
+ const container = new Container();
1552
+ for (const line of content.slice(0, InteractiveMode.MAX_WIDGET_LINES)) {
1553
+ container.addChild(new Text(line, 1, 0));
1554
+ }
1555
+ if (content.length > InteractiveMode.MAX_WIDGET_LINES) {
1556
+ container.addChild(new Text(theme.fg("muted", "... (widget truncated)"), 1, 0));
1557
+ }
1558
+ component = container;
1559
+ } else {
1560
+ // Factory function - create component
1561
+ component = content(this.ui, theme);
1562
+ }
1563
+
1564
+ const targetMap = placement === "belowEditor" ? this.extensionWidgetsBelow : this.extensionWidgetsAbove;
1565
+ targetMap.set(key, component);
1566
+ this.renderWidgets();
1567
+ }
1568
+
1569
+ private clearExtensionWidgets(): void {
1570
+ for (const widget of this.extensionWidgetsAbove.values()) {
1571
+ widget.dispose?.();
1572
+ }
1573
+ for (const widget of this.extensionWidgetsBelow.values()) {
1574
+ widget.dispose?.();
1575
+ }
1576
+ this.extensionWidgetsAbove.clear();
1577
+ this.extensionWidgetsBelow.clear();
1578
+ this.renderWidgets();
1579
+ }
1580
+
1581
+ private resetExtensionUI(): void {
1582
+ if (this.extensionSelector) {
1583
+ this.hideExtensionSelector();
1584
+ }
1585
+ if (this.extensionInput) {
1586
+ this.hideExtensionInput();
1587
+ }
1588
+ if (this.extensionEditor) {
1589
+ this.hideExtensionEditor();
1590
+ }
1591
+ this.ui.hideOverlay();
1592
+ this.clearExtensionTerminalInputListeners();
1593
+ this.setExtensionFooter(undefined);
1594
+ this.setExtensionHeader(undefined);
1595
+ this.clearExtensionWidgets();
1596
+ this.footerDataProvider.clearExtensionStatuses();
1597
+ this.footer.invalidate();
1598
+ this.setCustomEditorComponent(undefined);
1599
+ this.defaultEditor.onExtensionShortcut = undefined;
1600
+ this.updateTerminalTitle();
1601
+ if (this.loadingAnimation) {
1602
+ this.loadingAnimation.setMessage(
1603
+ `${this.defaultWorkingMessage} (${appKey(this.keybindings, "interrupt")} to interrupt)`,
1604
+ );
1605
+ }
1606
+ }
1607
+
1608
+ // Maximum total widget lines to prevent viewport overflow
1609
+ private static readonly MAX_WIDGET_LINES = 10;
1610
+
1611
+ /**
1612
+ * Render all extension widgets to the widget container.
1613
+ */
1614
+ private renderWidgets(): void {
1615
+ if (!this.widgetContainerAbove || !this.widgetContainerBelow) return;
1616
+
1617
+ // widgetContainerAbove: spacer collapses when pinned content is visible
1618
+ // so there's no extra blank line between pinned output and the editor border.
1619
+ // Use detachChildren() (not clear()) — the extensionWidgetsAbove map owns
1620
+ // disposal; clear() would dispose every mounted widget on every re-render.
1621
+ this.widgetContainerAbove.detachChildren();
1622
+ const pinned = this.pinnedMessageContainer;
1623
+ this.widgetContainerAbove.addChild({
1624
+ render: () => pinned.children.length > 0 ? [] : [""],
1625
+ invalidate: () => {},
1626
+ });
1627
+ for (const component of this.extensionWidgetsAbove.values()) {
1628
+ this.widgetContainerAbove.addChild(component);
1629
+ }
1630
+
1631
+ this.renderWidgetContainer(this.widgetContainerBelow, this.extensionWidgetsBelow, false, false);
1632
+ this.ui.requestRender();
1633
+ }
1634
+
1635
+ private renderWidgetContainer(
1636
+ container: Container,
1637
+ widgets: Map<string, Component & { dispose?(): void }>,
1638
+ spacerWhenEmpty: boolean,
1639
+ leadingSpacer: boolean,
1640
+ ): void {
1641
+ // Detach without disposing — the widgets map owns lifecycle; disposing
1642
+ // here would kill refresh timers and subscriptions on every re-render.
1643
+ container.detachChildren();
1644
+
1645
+ if (widgets.size === 0) {
1646
+ if (spacerWhenEmpty) {
1647
+ container.addChild(new Spacer(1));
1648
+ }
1649
+ return;
1650
+ }
1651
+
1652
+ if (leadingSpacer) {
1653
+ container.addChild(new Spacer(1));
1654
+ }
1655
+ for (const component of widgets.values()) {
1656
+ container.addChild(component);
1657
+ }
1658
+ }
1659
+
1660
+ /**
1661
+ * Set a custom footer component, or restore the built-in footer.
1662
+ */
1663
+ private setExtensionFooter(
1664
+ factory:
1665
+ | ((tui: TUI, thm: Theme, footerData: ReadonlyFooterDataProvider) => Component & { dispose?(): void })
1666
+ | undefined,
1667
+ ): void {
1668
+ // Dispose existing custom footer
1669
+ if (this.customFooter?.dispose) {
1670
+ this.customFooter.dispose();
1671
+ }
1672
+
1673
+ // Remove current footer from UI
1674
+ if (this.customFooter) {
1675
+ this.ui.removeChild(this.customFooter);
1676
+ } else {
1677
+ this.ui.removeChild(this.footer);
1678
+ }
1679
+
1680
+ if (factory) {
1681
+ // Create and add custom footer, passing the data provider
1682
+ this.customFooter = factory(this.ui, theme, this.footerDataProvider);
1683
+ this.ui.addChild(this.customFooter);
1684
+ } else {
1685
+ // Restore built-in footer
1686
+ this.customFooter = undefined;
1687
+ this.ui.addChild(this.footer);
1688
+ }
1689
+
1690
+ this.ui.requestRender();
1691
+ }
1692
+
1693
+ /**
1694
+ * Set a custom header component, or restore the built-in header.
1695
+ */
1696
+ private setExtensionHeader(factory: ((tui: TUI, thm: Theme) => Component & { dispose?(): void }) | undefined): void {
1697
+ // Header may not be initialized yet if called during early initialization
1698
+ if (!this.builtInHeader) {
1699
+ return;
1700
+ }
1701
+
1702
+ // Dispose existing custom header
1703
+ if (this.customHeader?.dispose) {
1704
+ this.customHeader.dispose();
1705
+ }
1706
+
1707
+ // Find the index of the current header in the header container
1708
+ const currentHeader = this.customHeader || this.builtInHeader;
1709
+ const index = this.headerContainer.children.indexOf(currentHeader);
1710
+
1711
+ if (factory) {
1712
+ // Create and add custom header
1713
+ this.customHeader = factory(this.ui, theme);
1714
+ if (index !== -1) {
1715
+ this.headerContainer.children[index] = this.customHeader;
1716
+ } else {
1717
+ // If not found (e.g. builtInHeader was never added), add at the top
1718
+ this.headerContainer.children.unshift(this.customHeader);
1719
+ }
1720
+ } else {
1721
+ // Restore built-in header
1722
+ this.customHeader = undefined;
1723
+ if (index !== -1) {
1724
+ this.headerContainer.children[index] = this.builtInHeader;
1725
+ }
1726
+ }
1727
+
1728
+ this.ui.requestRender();
1729
+ }
1730
+
1731
+ private addExtensionTerminalInputListener(
1732
+ handler: (data: string) => { consume?: boolean; data?: string } | undefined,
1733
+ ): () => void {
1734
+ const unsubscribe = this.ui.addInputListener(handler);
1735
+ this.extensionTerminalInputUnsubscribers.add(unsubscribe);
1736
+ return () => {
1737
+ unsubscribe();
1738
+ this.extensionTerminalInputUnsubscribers.delete(unsubscribe);
1739
+ };
1740
+ }
1741
+
1742
+ private clearExtensionTerminalInputListeners(): void {
1743
+ for (const unsubscribe of this.extensionTerminalInputUnsubscribers) {
1744
+ unsubscribe();
1745
+ }
1746
+ this.extensionTerminalInputUnsubscribers.clear();
1747
+ }
1748
+
1749
+ /**
1750
+ * Create the ExtensionUIContext for extensions.
1751
+ */
1752
+ private createExtensionUIContext(): ExtensionUIContext {
1753
+ return buildExtensionUIContext(this);
1754
+ }
1755
+
1756
+ getExtensionUIContext(): ExtensionUIContext {
1757
+ return this.createExtensionUIContext();
1758
+ }
1759
+
1760
+ /**
1761
+ * Show a selector for extensions.
1762
+ */
1763
+ private showExtensionSelector(
1764
+ title: string,
1765
+ options: string[],
1766
+ opts?: ExtensionUIDialogOptions,
1767
+ ): Promise<string | undefined> {
1768
+ // If a previous selector is still active, dispose it before creating a
1769
+ // new one. This avoids leaking the previous promise and DOM state when
1770
+ // showExtensionSelector is called rapidly.
1771
+ if (this.extensionSelector) {
1772
+ this.hideExtensionSelector();
1773
+ }
1774
+
1775
+ return new Promise((resolve) => {
1776
+ if (opts?.signal?.aborted) {
1777
+ resolve(undefined);
1778
+ return;
1779
+ }
1780
+
1781
+ const onAbort = () => {
1782
+ this.hideExtensionSelector();
1783
+ resolve(undefined);
1784
+ };
1785
+ opts?.signal?.addEventListener("abort", onAbort, { once: true });
1786
+
1787
+ this.extensionSelector = new ExtensionSelectorComponent(
1788
+ title,
1789
+ options,
1790
+ (option) => {
1791
+ opts?.signal?.removeEventListener("abort", onAbort);
1792
+ this.hideExtensionSelector();
1793
+ resolve(option);
1794
+ },
1795
+ () => {
1796
+ opts?.signal?.removeEventListener("abort", onAbort);
1797
+ this.hideExtensionSelector();
1798
+ resolve(undefined);
1799
+ },
1800
+ { tui: this.ui, timeout: opts?.timeout },
1801
+ );
1802
+
1803
+ this.editorContainer.clear();
1804
+ this.editorContainer.addChild(this.extensionSelector);
1805
+ this.ui.setFocus(this.extensionSelector);
1806
+ this.ui.requestRender();
1807
+ });
1808
+ }
1809
+
1810
+ /**
1811
+ * Hide the extension selector.
1812
+ */
1813
+ private hideExtensionSelector(): void {
1814
+ this.extensionSelector?.dispose();
1815
+ this.editorContainer.clear();
1816
+ this.editorContainer.addChild(this.editor);
1817
+ this.extensionSelector = undefined;
1818
+ this.ui.setFocus(this.editor);
1819
+ this.ui.requestRender();
1820
+ }
1821
+
1822
+ /**
1823
+ * Show a confirmation dialog for extensions.
1824
+ */
1825
+ private async showExtensionConfirm(
1826
+ title: string,
1827
+ message: string,
1828
+ opts?: ExtensionUIDialogOptions,
1829
+ ): Promise<boolean> {
1830
+ const result = await this.showExtensionSelector(`${title}\n${message}`, ["Yes", "No"], opts);
1831
+ return result === "Yes";
1832
+ }
1833
+
1834
+ /**
1835
+ * Show a text input for extensions.
1836
+ */
1837
+ private showExtensionInput(
1838
+ title: string,
1839
+ placeholder?: string,
1840
+ opts?: ExtensionUIDialogOptions,
1841
+ ): Promise<string | undefined> {
1842
+ return new Promise((resolve) => {
1843
+ if (opts?.signal?.aborted) {
1844
+ resolve(undefined);
1845
+ return;
1846
+ }
1847
+
1848
+ const onAbort = () => {
1849
+ this.hideExtensionInput();
1850
+ resolve(undefined);
1851
+ };
1852
+ opts?.signal?.addEventListener("abort", onAbort, { once: true });
1853
+
1854
+ this.extensionInput = new ExtensionInputComponent(
1855
+ title,
1856
+ placeholder,
1857
+ (value) => {
1858
+ opts?.signal?.removeEventListener("abort", onAbort);
1859
+ this.hideExtensionInput();
1860
+ resolve(value);
1861
+ },
1862
+ () => {
1863
+ opts?.signal?.removeEventListener("abort", onAbort);
1864
+ this.hideExtensionInput();
1865
+ resolve(undefined);
1866
+ },
1867
+ { tui: this.ui, timeout: opts?.timeout, secure: opts?.secure },
1868
+ );
1869
+
1870
+ this.editorContainer.clear();
1871
+ this.editorContainer.addChild(this.extensionInput);
1872
+ this.ui.setFocus(this.extensionInput);
1873
+ this.ui.requestRender();
1874
+ });
1875
+ }
1876
+
1877
+ /**
1878
+ * Hide the extension input.
1879
+ */
1880
+ private hideExtensionInput(): void {
1881
+ this.extensionInput?.dispose();
1882
+ this.editorContainer.clear();
1883
+ this.editorContainer.addChild(this.editor);
1884
+ this.extensionInput = undefined;
1885
+ this.ui.setFocus(this.editor);
1886
+ this.ui.requestRender();
1887
+ }
1888
+
1889
+ /**
1890
+ * Show a multi-line editor for extensions (with Ctrl+G support).
1891
+ */
1892
+ private showExtensionEditor(title: string, prefill?: string): Promise<string | undefined> {
1893
+ return new Promise((resolve) => {
1894
+ this.extensionEditor = new ExtensionEditorComponent(
1895
+ this.ui,
1896
+ this.keybindings,
1897
+ title,
1898
+ prefill,
1899
+ (value) => {
1900
+ this.hideExtensionEditor();
1901
+ resolve(value);
1902
+ },
1903
+ () => {
1904
+ this.hideExtensionEditor();
1905
+ resolve(undefined);
1906
+ },
1907
+ );
1908
+
1909
+ this.editorContainer.clear();
1910
+ this.editorContainer.addChild(this.extensionEditor);
1911
+ this.ui.setFocus(this.extensionEditor);
1912
+ this.ui.requestRender();
1913
+ });
1914
+ }
1915
+
1916
+ /**
1917
+ * Hide the extension editor.
1918
+ */
1919
+ private hideExtensionEditor(): void {
1920
+ this.editorContainer.clear();
1921
+ this.editorContainer.addChild(this.editor);
1922
+ this.extensionEditor = undefined;
1923
+ this.ui.setFocus(this.editor);
1924
+ this.ui.requestRender();
1925
+ }
1926
+
1927
+ /**
1928
+ * Set a custom editor component from an extension.
1929
+ * Pass undefined to restore the default editor.
1930
+ */
1931
+ private setCustomEditorComponent(
1932
+ factory: ((tui: TUI, theme: EditorTheme, keybindings: KeybindingsManager) => EditorComponent) | undefined,
1933
+ ): void {
1934
+ // Save text from current editor before switching
1935
+ const currentText = this.editor.getText();
1936
+
1937
+ this.editorContainer.clear();
1938
+
1939
+ if (factory) {
1940
+ // Create the custom editor with tui, theme, and keybindings
1941
+ const newEditor = factory(this.ui, getEditorTheme(), this.keybindings);
1942
+
1943
+ // Wire up callbacks from the default editor
1944
+ newEditor.onSubmit = this.defaultEditor.onSubmit;
1945
+ newEditor.onChange = this.defaultEditor.onChange;
1946
+
1947
+ // Copy text from previous editor
1948
+ newEditor.setText(currentText);
1949
+
1950
+ // Copy appearance settings if supported
1951
+ if (newEditor.borderColor !== undefined) {
1952
+ newEditor.borderColor = this.defaultEditor.borderColor;
1953
+ }
1954
+ if (newEditor.setPaddingX !== undefined) {
1955
+ newEditor.setPaddingX(this.defaultEditor.getPaddingX());
1956
+ }
1957
+
1958
+ // Set autocomplete if supported
1959
+ if (newEditor.setAutocompleteProvider && this.autocompleteProvider) {
1960
+ newEditor.setAutocompleteProvider(this.autocompleteProvider);
1961
+ }
1962
+
1963
+ // If extending CustomEditor, copy app-level handlers
1964
+ // Use duck typing since instanceof fails across jiti module boundaries
1965
+ const customEditor = newEditor as unknown as Record<string, unknown>;
1966
+ if ("actionHandlers" in customEditor && customEditor.actionHandlers instanceof Map) {
1967
+ if (!customEditor.onEscape) {
1968
+ customEditor.onEscape = () => this.defaultEditor.onEscape?.();
1969
+ }
1970
+ if (!customEditor.onCtrlD) {
1971
+ customEditor.onCtrlD = () => this.defaultEditor.onCtrlD?.();
1972
+ }
1973
+ if (!customEditor.onPasteImage) {
1974
+ customEditor.onPasteImage = () => this.defaultEditor.onPasteImage?.();
1975
+ }
1976
+ if (!customEditor.onExtensionShortcut) {
1977
+ customEditor.onExtensionShortcut = (data: string) => this.defaultEditor.onExtensionShortcut?.(data);
1978
+ }
1979
+ // Copy action handlers (clear, suspend, model switching, etc.)
1980
+ for (const [action, handler] of this.defaultEditor.actionHandlers) {
1981
+ (customEditor.actionHandlers as Map<string, () => void>).set(action, handler);
1982
+ }
1983
+ }
1984
+
1985
+ this.editor = newEditor;
1986
+ } else {
1987
+ // Restore default editor with text from custom editor
1988
+ this.defaultEditor.setText(currentText);
1989
+ this.editor = this.defaultEditor;
1990
+ }
1991
+
1992
+ // Ensure pasted image path handler is set on the active editor
1993
+ if (!this.editor.onPasteImagePath) {
1994
+ this.editor.onPasteImagePath = (filePath: string) => {
1995
+ this.handlePastedImagePath(filePath);
1996
+ };
1997
+ }
1998
+
1999
+ this.editorContainer.addChild(this.editor as Component);
2000
+ this.ui.setFocus(this.editor as Component);
2001
+ this.ui.requestRender();
2002
+ }
2003
+
2004
+ /**
2005
+ * Show a notification for extensions.
2006
+ */
2007
+ private showExtensionNotify(message: string, type?: ExtensionNotifyType): void {
2008
+ if (type === "error") {
2009
+ this.lastBlockingError = message;
2010
+ renderBlockingErrorBanner(this.blockingErrorContainer, this.lastBlockingError);
2011
+ }
2012
+ const result = renderExtensionNotifyInChat(this.chatContainer, message, type);
2013
+ if (!result.rendered) {
2014
+ return;
2015
+ }
2016
+ if (result.statusSpacer && result.statusText) {
2017
+ this.lastStatusSpacer = result.statusSpacer;
2018
+ this.lastStatusText = result.statusText;
2019
+ }
2020
+ this.ui.requestRender();
2021
+ }
2022
+
2023
+ /** Show a custom component with keyboard focus. Overlay mode renders on top of existing content. */
2024
+ private async showExtensionCustom<T>(
2025
+ factory: (
2026
+ tui: TUI,
2027
+ theme: Theme,
2028
+ keybindings: KeybindingsManager,
2029
+ done: (result: T) => void,
2030
+ ) => (Component & { dispose?(): void }) | Promise<Component & { dispose?(): void }>,
2031
+ options?: {
2032
+ overlay?: boolean;
2033
+ overlayOptions?: OverlayOptions | (() => OverlayOptions);
2034
+ onHandle?: (handle: OverlayHandle) => void;
2035
+ },
2036
+ ): Promise<T> {
2037
+ const savedText = this.editor.getText();
2038
+ const isOverlay = options?.overlay ?? false;
2039
+
2040
+ const restoreEditor = () => {
2041
+ this.editorContainer.clear();
2042
+ this.editorContainer.addChild(this.editor);
2043
+ this.editor.setText(savedText);
2044
+ this.ui.setFocus(this.editor);
2045
+ this.ui.requestRender();
2046
+ };
2047
+
2048
+ return new Promise((resolve, reject) => {
2049
+ let component: Component & { dispose?(): void };
2050
+ let closed = false;
2051
+
2052
+ const close = (result: T) => {
2053
+ if (closed) return;
2054
+ closed = true;
2055
+ if (isOverlay) this.ui.hideOverlay();
2056
+ else restoreEditor();
2057
+ // Note: both branches above already call requestRender
2058
+ resolve(result);
2059
+ try {
2060
+ component?.dispose?.();
2061
+ } catch {
2062
+ /* ignore dispose errors */
2063
+ }
2064
+ };
2065
+
2066
+ Promise.resolve(factory(this.ui, theme, this.keybindings, close))
2067
+ .then((c) => {
2068
+ if (closed) return;
2069
+ component = c;
2070
+ if (isOverlay) {
2071
+ // Resolve overlay options - can be static or dynamic function
2072
+ const resolveOptions = (): OverlayOptions | undefined => {
2073
+ if (options?.overlayOptions) {
2074
+ const opts =
2075
+ typeof options.overlayOptions === "function"
2076
+ ? options.overlayOptions()
2077
+ : options.overlayOptions;
2078
+ return opts;
2079
+ }
2080
+ // Fallback: use component's width property if available
2081
+ const w = (component as { width?: number }).width;
2082
+ return w ? { width: w } : undefined;
2083
+ };
2084
+ const handle = this.ui.showOverlay(component, resolveOptions());
2085
+ // Expose handle to caller for visibility control
2086
+ options?.onHandle?.(handle);
2087
+ } else {
2088
+ this.editorContainer.clear();
2089
+ this.editorContainer.addChild(component);
2090
+ this.ui.setFocus(component);
2091
+ this.ui.requestRender();
2092
+ }
2093
+ })
2094
+ .catch((err) => {
2095
+ if (closed) return;
2096
+ if (!isOverlay) restoreEditor();
2097
+ reject(err);
2098
+ });
2099
+ });
2100
+ }
2101
+
2102
+ /**
2103
+ * Show an extension error in the UI.
2104
+ */
2105
+ private showExtensionError(extensionPath: string, error: string, stack?: string): void {
2106
+ const errorMsg = `Extension "${extensionPath}" error: ${error}`;
2107
+ const errorText = new Text(theme.fg("error", errorMsg), 1, 0);
2108
+ this.chatContainer.addChild(errorText);
2109
+ if (stack) {
2110
+ // Show stack trace in dim color, indented
2111
+ const stackLines = stack
2112
+ .split("\n")
2113
+ .slice(1) // Skip first line (duplicates error message)
2114
+ .map((line) => theme.fg("dim", ` ${line.trim()}`))
2115
+ .join("\n");
2116
+ if (stackLines) {
2117
+ this.chatContainer.addChild(new Text(stackLines, 1, 0));
2118
+ }
2119
+ }
2120
+ this.ui.requestRender();
2121
+ }
2122
+
2123
+ // =========================================================================
2124
+ // Key Handlers
2125
+ // =========================================================================
2126
+
2127
+ private setupKeyHandlers(): void {
2128
+ // Set up handlers on defaultEditor - they use this.editor for text access
2129
+ // so they work correctly regardless of which editor is active
2130
+ this.defaultEditor.onEscape = () => {
2131
+ if (this.loadingAnimation) {
2132
+ this.restoreQueuedMessagesToEditor({ abort: true });
2133
+ } else if (this.session.isBashRunning) {
2134
+ this.session.abortBash();
2135
+ } else if (this.isBashMode) {
2136
+ this.editor.setText("");
2137
+ this.pendingImages.length = 0;
2138
+ this.isBashMode = false;
2139
+ this.updateEditorBorderColor();
2140
+ } else if (!this.editor.getText().trim()) {
2141
+ // Double-escape with empty editor triggers /tree, /fork, or nothing based on setting
2142
+ const action = this.settingsManager.getDoubleEscapeAction();
2143
+ if (action !== "none") {
2144
+ const now = Date.now();
2145
+ if (now - this.lastEscapeTime < 500) {
2146
+ if (action === "tree") {
2147
+ this.showTreeSelector();
2148
+ } else {
2149
+ this.showUserMessageSelector();
2150
+ }
2151
+ this.lastEscapeTime = 0;
2152
+ } else {
2153
+ this.lastEscapeTime = now;
2154
+ }
2155
+ }
2156
+ }
2157
+ };
2158
+
2159
+ // Register app action handlers
2160
+ this.defaultEditor.onAction("clear", () => this.handleCtrlC());
2161
+ this.defaultEditor.onCtrlD = () => this.handleCtrlD();
2162
+ this.defaultEditor.onAction("suspend", () => this.handleCtrlZ());
2163
+ this.defaultEditor.onAction("cycleThinkingLevel", () => this.cycleThinkingLevel());
2164
+ this.defaultEditor.onAction("cycleModelForward", () => this.cycleModel("forward"));
2165
+ this.defaultEditor.onAction("cycleModelBackward", () => this.cycleModel("backward"));
2166
+
2167
+ // Global debug handler on TUI (works regardless of focus)
2168
+ this.ui.onDebug = () => this.handleDebugCommand();
2169
+ this.defaultEditor.onAction("selectModel", () => this.showModelSelector());
2170
+ this.defaultEditor.onAction("expandTools", () => this.toggleToolOutputExpansion());
2171
+ this.defaultEditor.onAction("toggleThinking", () => this.toggleThinkingBlockVisibility());
2172
+ this.defaultEditor.onAction("externalEditor", () => this.openExternalEditor());
2173
+ this.defaultEditor.onAction("followUp", () => this.handleFollowUp());
2174
+ this.defaultEditor.onAction("dequeue", () => this.handleDequeue());
2175
+ this.defaultEditor.onAction("newSession", () => this.handleClearCommand());
2176
+ this.defaultEditor.onAction("tree", () => this.showTreeSelector());
2177
+ this.defaultEditor.onAction("fork", () => this.showUserMessageSelector());
2178
+ this.defaultEditor.onAction("resume", () => this.showSessionSelector());
2179
+
2180
+ this.defaultEditor.onChange = (text: string) => {
2181
+ const wasBashMode = this.isBashMode;
2182
+ this.isBashMode = text.trimStart().startsWith("!");
2183
+ if (wasBashMode !== this.isBashMode) {
2184
+ this.updateEditorBorderColor();
2185
+ }
2186
+ };
2187
+
2188
+ // Handle clipboard image paste (triggered on Ctrl+V)
2189
+ this.defaultEditor.onPasteImage = () => {
2190
+ this.handleClipboardImagePaste();
2191
+ };
2192
+
2193
+ // Handle image file paths pasted via terminal emulator (e.g. iTerm2).
2194
+ // Set on defaultEditor here; setCustomEditorComponent guards re-assignment for custom editors.
2195
+ this.defaultEditor.onPasteImagePath = (filePath: string) => {
2196
+ this.handlePastedImagePath(filePath);
2197
+ };
2198
+ }
2199
+
2200
+ private async handleClipboardImagePaste(): Promise<void> {
2201
+ try {
2202
+ const image = await readClipboardImage();
2203
+ if (!image) {
2204
+ return;
2205
+ }
2206
+
2207
+ // Store image as base64 ImageContent for sending with the prompt
2208
+ const imageContent: ImageContent = {
2209
+ type: "image",
2210
+ data: Buffer.from(image.bytes).toString("base64"),
2211
+ mimeType: image.mimeType,
2212
+ };
2213
+ this.pendingImages.push(imageContent);
2214
+
2215
+ // Insert friendly placeholder instead of file path
2216
+ const imageNum = this.pendingImages.length;
2217
+ this.editor.insertTextAtCursor?.(`[Image #${imageNum}]`);
2218
+ this.ui.requestRender();
2219
+ } catch {
2220
+ // Silently ignore clipboard errors (may not have permission, etc.)
2221
+ }
2222
+ }
2223
+
2224
+ // MIME types restricted to formats commonly accepted by AI vision APIs.
2225
+ // SVG is excluded — it is XML/JS-bearing and not safe to forward as image content.
2226
+ // TIFF/HEIC/HEIF/AVIF are excluded for compatibility; users can convert before pasting.
2227
+ private static readonly MIME_BY_EXT: Record<string, string> = {
2228
+ png: "image/png",
2229
+ jpg: "image/jpeg",
2230
+ jpeg: "image/jpeg",
2231
+ gif: "image/gif",
2232
+ webp: "image/webp",
2233
+ };
2234
+
2235
+ // Magic-byte signatures used to verify file content matches its extension,
2236
+ // preventing arbitrary-file-read via crafted paste of e.g. "/etc/passwd.png".
2237
+ private static matchesImageSignature(buf: Buffer, mimeType: string): boolean {
2238
+ if (buf.length < 12) return false;
2239
+ switch (mimeType) {
2240
+ case "image/png":
2241
+ return buf[0] === 0x89 && buf[1] === 0x50 && buf[2] === 0x4e && buf[3] === 0x47;
2242
+ case "image/jpeg":
2243
+ return buf[0] === 0xff && buf[1] === 0xd8 && buf[2] === 0xff;
2244
+ case "image/gif":
2245
+ return (
2246
+ buf[0] === 0x47 && buf[1] === 0x49 && buf[2] === 0x46 && buf[3] === 0x38 &&
2247
+ (buf[4] === 0x37 || buf[4] === 0x39) && buf[5] === 0x61
2248
+ );
2249
+ case "image/webp":
2250
+ return (
2251
+ buf[0] === 0x52 && buf[1] === 0x49 && buf[2] === 0x46 && buf[3] === 0x46 &&
2252
+ buf[8] === 0x57 && buf[9] === 0x45 && buf[10] === 0x42 && buf[11] === 0x50
2253
+ );
2254
+ default:
2255
+ return false;
2256
+ }
2257
+ }
2258
+
2259
+ private handlePastedImagePath(filePath: string): void {
2260
+ try {
2261
+ const ext = path.extname(filePath).slice(1).toLowerCase();
2262
+ const mimeType = InteractiveMode.MIME_BY_EXT[ext];
2263
+ if (!mimeType) {
2264
+ // Unsupported / unsafe extension — fall back to inserting raw path.
2265
+ this.editor.insertTextAtCursor?.(filePath);
2266
+ this.ui.requestRender();
2267
+ return;
2268
+ }
2269
+
2270
+ // Reject symlinks to prevent reading sensitive files via a symlinked
2271
+ // `.png` that points at e.g. ~/.ssh/id_rsa.
2272
+ const lst = fs.lstatSync(filePath);
2273
+ if (!lst.isFile()) {
2274
+ this.editor.insertTextAtCursor?.(filePath);
2275
+ this.ui.requestRender();
2276
+ return;
2277
+ }
2278
+
2279
+ const data = fs.readFileSync(filePath);
2280
+
2281
+ // Magic-byte check — confirms file content actually matches the
2282
+ // extension before we forward bytes to a model.
2283
+ if (!InteractiveMode.matchesImageSignature(data, mimeType)) {
2284
+ this.editor.insertTextAtCursor?.(filePath);
2285
+ this.ui.requestRender();
2286
+ return;
2287
+ }
2288
+
2289
+ this.pendingImages.push({
2290
+ type: "image",
2291
+ data: data.toString("base64"),
2292
+ mimeType,
2293
+ });
2294
+
2295
+ const imageNum = this.pendingImages.length;
2296
+ this.editor.insertTextAtCursor?.(`[Image #${imageNum}]`);
2297
+ this.ui.requestRender();
2298
+ } catch {
2299
+ // Fall back to inserting the raw path if file can't be read
2300
+ this.editor.insertTextAtCursor?.(filePath);
2301
+ this.ui.requestRender();
2302
+ }
2303
+ }
2304
+
2305
+ private getSlashCommandContext(): SlashCommandContext {
2306
+ return {
2307
+ session: this.session,
2308
+ ui: this.ui,
2309
+ keybindings: this.keybindings,
2310
+ chatContainer: this.chatContainer,
2311
+ statusContainer: this.statusContainer,
2312
+ editorContainer: this.editorContainer,
2313
+ headerContainer: this.headerContainer,
2314
+ pendingMessagesContainer: this.pendingMessagesContainer,
2315
+ editor: this.editor,
2316
+ defaultEditor: this.defaultEditor,
2317
+ sessionManager: this.sessionManager,
2318
+ settingsManager: this.settingsManager,
2319
+ invalidateFooter: () => this.footer.invalidate(),
2320
+ showStatus: (msg) => this.showStatus(msg),
2321
+ showError: (msg) => this.showError(msg),
2322
+ showWarning: (msg) => this.showWarning(msg),
2323
+ showSelector: (create) => this.showSelector(create),
2324
+ updateEditorBorderColor: () => this.updateEditorBorderColor(),
2325
+ getMarkdownThemeWithSettings: () => this.getMarkdownThemeWithSettings(),
2326
+ requestRender: () => this.ui.requestRender(),
2327
+ updateTerminalTitle: () => this.updateTerminalTitle(),
2328
+ showSettingsSelector: () => this.showSettingsSelector(),
2329
+ showModelsSelector: () => this.showModelsSelector(),
2330
+ handleModelCommand: (searchTerm) => this.handleModelCommand(searchTerm),
2331
+ showUserMessageSelector: () => this.showUserMessageSelector(),
2332
+ showTreeSelector: () => this.showTreeSelector(),
2333
+ showProviderManager: () => this.showProviderManager(),
2334
+ showOAuthSelector: (mode) => this.showOAuthSelector(mode),
2335
+ showSessionSelector: () => this.showSessionSelector(),
2336
+ handleClearCommand: () => this.handleClearCommand(),
2337
+ handleReloadCommand: () => this.handleReloadCommand(),
2338
+ handleDebugCommand: () => this.handleDebugCommand(),
2339
+ shutdown: () => this.shutdown(),
2340
+ executeCompaction: (instructions, isAuto) => this.executeCompaction(instructions, isAuto),
2341
+ handleBashCommand: (command, options) => this.handleBashCommand(command, options?.excludeFromContext, options?.displayCommand, options?.loginShell),
2342
+ };
2343
+ }
2344
+
2345
+ private setupEditorSubmitHandler(): void {
2346
+ setupEditorSubmitHandlerController(this as any);
2347
+ }
2348
+
2349
+ private subscribeToAgent(): void {
2350
+ let eventQueue: Promise<void> = Promise.resolve();
2351
+ this.unsubscribe = this.session.subscribe((event) => {
2352
+ eventQueue = eventQueue.then(() => this.handleEvent(event)).catch(() => {});
2353
+ });
2354
+ }
2355
+
2356
+ private async handleEvent(event: AgentSessionEvent): Promise<void> {
2357
+ await handleAgentEvent(this as any, event);
2358
+ }
2359
+
2360
+ /** Extract text content from a user message */
2361
+ private getUserMessageText(message: Message): string {
2362
+ if (message.role !== "user") return "";
2363
+ const textBlocks =
2364
+ typeof message.content === "string"
2365
+ ? [{ type: "text", text: message.content }]
2366
+ : message.content.filter((c: { type: string }) => c.type === "text");
2367
+ return textBlocks.map((c) => (c as { text: string }).text).join("");
2368
+ }
2369
+
2370
+ /**
2371
+ * Show a status message in the chat.
2372
+ *
2373
+ * If multiple status messages are emitted back-to-back (without anything else being added to the chat),
2374
+ * we update the previous status line instead of appending new ones to avoid log spam.
2375
+ */
2376
+ private showStatus(message: string, options?: { append?: boolean }): void {
2377
+ const append = options?.append ?? false;
2378
+ const children = this.chatContainer.children;
2379
+ const last = children.length > 0 ? children[children.length - 1] : undefined;
2380
+ const secondLast = children.length > 1 ? children[children.length - 2] : undefined;
2381
+
2382
+ if (!append && last && secondLast && last === this.lastStatusText && secondLast === this.lastStatusSpacer) {
2383
+ this.lastStatusText.setText(theme.fg("dim", message));
2384
+ this.ui.requestRender();
2385
+ return;
2386
+ }
2387
+
2388
+ const spacer = new Spacer(1);
2389
+ const text = new Text(theme.fg("dim", message), 1, 0);
2390
+ this.chatContainer.addChild(spacer);
2391
+ this.chatContainer.addChild(text);
2392
+ this.lastStatusSpacer = spacer;
2393
+ this.lastStatusText = text;
2394
+ this.ui.requestRender();
2395
+ }
2396
+
2397
+ private addMessageToChat(message: AgentMessage, options?: { populateHistory?: boolean }): void {
2398
+ const timestampFormat = this.settingsManager.getTimestampFormat();
2399
+ switch (message.role) {
2400
+ case "bashExecution": {
2401
+ const component = new BashExecutionComponent(message.command, this.ui, message.excludeFromContext);
2402
+ if (message.output) {
2403
+ component.appendOutput(message.output);
2404
+ }
2405
+ component.setComplete(
2406
+ message.exitCode,
2407
+ message.cancelled,
2408
+ message.truncated ? ({ truncated: true } as TruncationResult) : undefined,
2409
+ message.fullOutputPath,
2410
+ );
2411
+ this.chatContainer.addChild(component);
2412
+ break;
2413
+ }
2414
+ case "custom": {
2415
+ if (message.display) {
2416
+ const renderer = this.session.extensionRunner?.getMessageRenderer(message.customType);
2417
+ const component = new CustomMessageComponent(message, renderer, this.getMarkdownThemeWithSettings());
2418
+ component.setExpanded(this.toolOutputExpanded);
2419
+ this.chatContainer.addChild(component);
2420
+ }
2421
+ break;
2422
+ }
2423
+ case "compactionSummary": {
2424
+ this.chatContainer.addChild(new Spacer(1));
2425
+ const component = new CompactionSummaryMessageComponent(message, this.getMarkdownThemeWithSettings());
2426
+ component.setExpanded(this.toolOutputExpanded);
2427
+ this.chatContainer.addChild(component);
2428
+ break;
2429
+ }
2430
+ case "branchSummary": {
2431
+ this.chatContainer.addChild(new Spacer(1));
2432
+ const component = new BranchSummaryMessageComponent(message, this.getMarkdownThemeWithSettings());
2433
+ component.setExpanded(this.toolOutputExpanded);
2434
+ this.chatContainer.addChild(component);
2435
+ break;
2436
+ }
2437
+ case "user": {
2438
+ const textContent = this.getUserMessageText(message);
2439
+ if (textContent) {
2440
+ const skillBlock = parseSkillBlock(textContent);
2441
+ if (skillBlock) {
2442
+ // Render skill block (collapsible)
2443
+ this.chatContainer.addChild(new Spacer(1));
2444
+ const component = new SkillInvocationMessageComponent(
2445
+ skillBlock,
2446
+ this.getMarkdownThemeWithSettings(),
2447
+ );
2448
+ component.setExpanded(this.toolOutputExpanded);
2449
+ this.chatContainer.addChild(component);
2450
+ // Render user message separately if present
2451
+ if (skillBlock.userMessage) {
2452
+ const userComponent = new UserMessageComponent(
2453
+ skillBlock.userMessage,
2454
+ this.getMarkdownThemeWithSettings(),
2455
+ message.timestamp,
2456
+ timestampFormat,
2457
+ );
2458
+ this.chatContainer.addChild(userComponent);
2459
+ }
2460
+ } else {
2461
+ const userComponent = new UserMessageComponent(textContent, this.getMarkdownThemeWithSettings(), message.timestamp, timestampFormat);
2462
+ this.chatContainer.addChild(userComponent);
2463
+ }
2464
+ if (options?.populateHistory) {
2465
+ this.editor.addToHistory?.(textContent);
2466
+ }
2467
+ }
2468
+ break;
2469
+ }
2470
+ case "assistant": {
2471
+ const assistantComponent = new AssistantMessageComponent(
2472
+ message,
2473
+ this.hideThinkingBlock,
2474
+ this.getMarkdownThemeWithSettings(),
2475
+ timestampFormat,
2476
+ );
2477
+ this.chatContainer.addChild(assistantComponent);
2478
+ break;
2479
+ }
2480
+ case "toolResult": {
2481
+ // Tool results are rendered inline with tool calls, handled separately
2482
+ break;
2483
+ }
2484
+ default: {
2485
+ const _exhaustive: never = message;
2486
+ }
2487
+ }
2488
+ this.trimChatHistory();
2489
+ }
2490
+
2491
+ /**
2492
+ * Remove oldest components when chat exceeds MAX_CHAT_COMPONENTS.
2493
+ * Only render-components are removed — session data stays in SessionManager.
2494
+ */
2495
+ private trimChatHistory(): void {
2496
+ while (this.chatContainer.children.length > InteractiveMode.MAX_CHAT_COMPONENTS) {
2497
+ const oldest = this.chatContainer.children[0];
2498
+ this.chatContainer.removeChild(oldest);
2499
+ }
2500
+ }
2501
+
2502
+ /**
2503
+ * Render session context to chat. Used for initial load and rebuild after compaction.
2504
+ * @param sessionContext Session context to render
2505
+ * @param options.updateFooter Update footer state
2506
+ * @param options.populateHistory Add user messages to editor history
2507
+ */
2508
+ private renderSessionContext(
2509
+ sessionContext: SessionContext,
2510
+ options: { updateFooter?: boolean; populateHistory?: boolean } = {},
2511
+ ): void {
2512
+ this.pendingTools.clear();
2513
+ const timestampFormat = this.settingsManager.getTimestampFormat();
2514
+
2515
+ if (options.updateFooter) {
2516
+ this.footer.invalidate();
2517
+ this.updateEditorBorderColor();
2518
+ }
2519
+
2520
+ for (const message of sessionContext.messages) {
2521
+ // Assistant messages need special handling for tool calls
2522
+ if (message.role === "assistant") {
2523
+ const hasToolBlocks = message.content.some((c) => c.type === "toolCall" || c.type === "serverToolUse");
2524
+ if (!hasToolBlocks) {
2525
+ this.addMessageToChat(message);
2526
+ continue;
2527
+ }
2528
+
2529
+ const assistantSegments: AssistantMessageComponent[] = [];
2530
+ const replaySegments = buildAssistantReplaySegments(message.content);
2531
+
2532
+ for (const segment of replaySegments) {
2533
+ if (segment.kind === "assistant") {
2534
+ const assistantComponent = new AssistantMessageComponent(
2535
+ message,
2536
+ this.hideThinkingBlock,
2537
+ this.getMarkdownThemeWithSettings(),
2538
+ timestampFormat,
2539
+ { startIndex: segment.startIndex, endIndex: segment.endIndex },
2540
+ );
2541
+ this.chatContainer.addChild(assistantComponent);
2542
+ assistantSegments.push(assistantComponent);
2543
+ continue;
2544
+ }
2545
+
2546
+ const content = message.content[segment.contentIndex];
2547
+ if (content.type === "toolCall") {
2548
+ const component = new ToolExecutionComponent(
2549
+ content.name,
2550
+ content.arguments,
2551
+ { showImages: this.settingsManager.getShowImages() },
2552
+ this.getRegisteredToolDefinition(content.name),
2553
+ this.ui,
2554
+ );
2555
+ component.setExpanded(this.toolOutputExpanded);
2556
+ this.chatContainer.addChild(component);
2557
+
2558
+ if (message.stopReason === "aborted" || message.stopReason === "error") {
2559
+ let errorMessage: string;
2560
+ if (message.stopReason === "aborted") {
2561
+ const retryAttempt = this.session.retryAttempt;
2562
+ errorMessage =
2563
+ retryAttempt > 0
2564
+ ? `Aborted after ${retryAttempt} retry attempt${retryAttempt > 1 ? "s" : ""}`
2565
+ : "Operation aborted";
2566
+ } else {
2567
+ errorMessage = message.errorMessage || "Error";
2568
+ }
2569
+ component.updateResult({ content: [{ type: "text", text: errorMessage }], isError: true });
2570
+ } else {
2571
+ this.pendingTools.set(content.id, component);
2572
+ }
2573
+ } else if (content.type === "serverToolUse") {
2574
+ // Server-side tool (e.g., native web search)
2575
+ const component = new ToolExecutionComponent(
2576
+ content.name,
2577
+ content.input ?? {},
2578
+ { showImages: this.settingsManager.getShowImages() },
2579
+ undefined,
2580
+ this.ui,
2581
+ );
2582
+ component.setExpanded(this.toolOutputExpanded);
2583
+ this.chatContainer.addChild(component);
2584
+ // Find matching webSearchResult in this message's content
2585
+ const resultBlock = message.content.find(
2586
+ (c) => c.type === "webSearchResult" && c.toolUseId === content.id,
2587
+ );
2588
+ if (resultBlock && resultBlock.type === "webSearchResult") {
2589
+ const searchContent = resultBlock.content;
2590
+ const isError = searchContent && typeof searchContent === "object" && "type" in (searchContent as any) && (searchContent as any).type === "web_search_tool_result_error";
2591
+ const resultText = this.formatWebSearchResult(searchContent);
2592
+ component.updateResult({
2593
+ content: [{ type: "text", text: resultText }],
2594
+ isError: !!isError,
2595
+ });
2596
+ } else {
2597
+ // No result yet (aborted stream?) — show as pending
2598
+ this.pendingTools.set(content.id, component);
2599
+ }
2600
+ }
2601
+ }
2602
+
2603
+ // Match streaming-mode behavior: show metadata once on the final
2604
+ // assistant prose segment for this message.
2605
+ const lastAssistantSegment = assistantSegments[assistantSegments.length - 1];
2606
+ lastAssistantSegment?.setShowMetadata(true);
2607
+ } else if (message.role === "toolResult") {
2608
+ // Match tool results to pending tool components
2609
+ const component = this.pendingTools.get(message.toolCallId);
2610
+ if (component) {
2611
+ component.updateResult(message);
2612
+ this.pendingTools.delete(message.toolCallId);
2613
+ }
2614
+ } else {
2615
+ // All other messages use standard rendering
2616
+ this.addMessageToChat(message, options);
2617
+ }
2618
+ }
2619
+
2620
+ // Any pendingTools entries left over after replay are historical tool
2621
+ // calls whose results were squashed out of session context (commonly by
2622
+ // compaction). Mark them finished so the frame stops showing "Running".
2623
+ for (const component of this.pendingTools.values()) {
2624
+ component.markHistoricalNoResult();
2625
+ }
2626
+ this.pendingTools.clear();
2627
+ this.trimChatHistory();
2628
+ this.ui.requestRender();
2629
+ }
2630
+
2631
+ renderInitialMessages(): void {
2632
+ // Get aligned messages and entries from session context
2633
+ const context = this.sessionManager.buildSessionContext();
2634
+ this.renderSessionContext(context, {
2635
+ updateFooter: true,
2636
+ populateHistory: true,
2637
+ });
2638
+ this.populatePinnedFromMessages(context.messages);
2639
+
2640
+ // Show compaction info if session was compacted
2641
+ const allEntries = this.sessionManager.getEntries();
2642
+ const compactionCount = allEntries.filter((e) => e.type === "compaction").length;
2643
+ if (compactionCount > 0) {
2644
+ const times = compactionCount === 1 ? "1 time" : `${compactionCount} times`;
2645
+ this.showStatus(`Session compacted ${times}`);
2646
+ }
2647
+ }
2648
+
2649
+ async getUserInput(): Promise<string> {
2650
+ return new Promise((resolve) => {
2651
+ this.onInputCallback = (text: string) => {
2652
+ this.onInputCallback = undefined;
2653
+ resolve(text);
2654
+ };
2655
+ });
2656
+ }
2657
+
2658
+ private rebuildChatFromMessages(): void {
2659
+ this.chatContainer.clear();
2660
+ this.pinnedMessageContainer.clear();
2661
+ const context = this.sessionManager.buildSessionContext();
2662
+ this.renderSessionContext(context);
2663
+ // Pinned content NOT re-populated here — the streaming lifecycle in
2664
+ // chat-controller.ts manages the pinned zone during active work.
2665
+ // populatePinnedFromMessages() remains in renderInitialMessages()
2666
+ // for the session-resume case at startup.
2667
+ }
2668
+
2669
+ /**
2670
+ * After rebuilding chat from messages, pin the last assistant text above the
2671
+ * editor if tool results would otherwise push it out of the viewport.
2672
+ */
2673
+ private populatePinnedFromMessages(messages: AgentMessage[]): void {
2674
+ this.pinnedMessageContainer.clear();
2675
+
2676
+ // Walk backwards to find the last assistant message
2677
+ let lastAssistant: AssistantMessage | undefined;
2678
+ for (let i = messages.length - 1; i >= 0; i--) {
2679
+ const msg = messages[i];
2680
+ if (msg && "role" in msg && msg.role === "assistant") {
2681
+ lastAssistant = msg as AssistantMessage;
2682
+ break;
2683
+ }
2684
+ }
2685
+ if (!lastAssistant) return;
2686
+
2687
+ // Check if any tool calls follow the last text block
2688
+ const content = lastAssistant.content;
2689
+ let lastTextIndex = -1;
2690
+ let hasToolAfterText = false;
2691
+ for (let i = 0; i < content.length; i++) {
2692
+ if (content[i].type === "text") lastTextIndex = i;
2693
+ }
2694
+ if (lastTextIndex >= 0) {
2695
+ for (let i = lastTextIndex + 1; i < content.length; i++) {
2696
+ if (content[i].type === "toolCall" || content[i].type === "serverToolUse") {
2697
+ hasToolAfterText = true;
2698
+ break;
2699
+ }
2700
+ }
2701
+ }
2702
+ if (!hasToolAfterText || lastTextIndex < 0) return;
2703
+
2704
+ const textBlock = content[lastTextIndex] as { type: "text"; text: string };
2705
+ const text = textBlock.text?.trim();
2706
+ if (!text) return;
2707
+
2708
+ this.pinnedMessageContainer.addChild(
2709
+ new DynamicBorder((str: string) => theme.fg("dim", str), "Latest Output"),
2710
+ );
2711
+ this.pinnedMessageContainer.addChild(
2712
+ new Markdown(text, 1, 0, this.getMarkdownThemeWithSettings()),
2713
+ );
2714
+ }
2715
+
2716
+ // =========================================================================
2717
+ // Key handlers
2718
+ // =========================================================================
2719
+
2720
+ private handleCtrlC(): void {
2721
+ const now = Date.now();
2722
+ if (now - this.lastSigintTime < 500) {
2723
+ void this.shutdown();
2724
+ } else {
2725
+ this.clearEditor();
2726
+ this.lastSigintTime = now;
2727
+ }
2728
+ }
2729
+
2730
+ private handleCtrlD(): void {
2731
+ // Only called when editor is empty (enforced by CustomEditor)
2732
+ void this.shutdown();
2733
+ }
2734
+
2735
+ /**
2736
+ * Gracefully shutdown the agent.
2737
+ * Emits shutdown event to extensions, then exits.
2738
+ */
2739
+ private isShuttingDown = false;
2740
+
2741
+ private async shutdown(): Promise<void> {
2742
+ const shutdownBehavior = this.options.shutdownBehavior ?? "exit_process";
2743
+ if (shutdownBehavior === "ignore") {
2744
+ this.showStatus("Quit is unavailable in the browser-attached terminal");
2745
+ return;
2746
+ }
2747
+
2748
+ if (this.isShuttingDown) return;
2749
+ this.isShuttingDown = true;
2750
+
2751
+ // Flush any queued settings writes before shutdown
2752
+ await this.settingsManager.flush();
2753
+
2754
+ // Emit shutdown event to extensions
2755
+ const extensionRunner = this.session.extensionRunner;
2756
+ if (extensionRunner?.hasHandlers("session_shutdown")) {
2757
+ await extensionRunner.emit({
2758
+ type: "session_shutdown",
2759
+ });
2760
+ }
2761
+
2762
+ // Wait for any pending renders to complete
2763
+ // requestRender() uses process.nextTick(), so we wait one tick
2764
+ await new Promise((resolve) => process.nextTick(resolve));
2765
+
2766
+ // Drain any in-flight Kitty key release events before stopping.
2767
+ // This prevents escape sequences from leaking to the parent shell over slow SSH.
2768
+ await this.ui.terminal.drainInput(1000);
2769
+
2770
+ this.stop();
2771
+ if (shutdownBehavior === "stop_ui") {
2772
+ return;
2773
+ }
2774
+
2775
+ // Kill ALL descendant processes to prevent orphans (next-server, pnpm dev, etc.)
2776
+ try {
2777
+ const descendants = listDescendants(process.pid);
2778
+ for (const childPid of descendants) {
2779
+ try { process.kill(childPid, "SIGTERM"); } catch {}
2780
+ }
2781
+ if (descendants.length > 0) {
2782
+ await new Promise(resolve => setTimeout(resolve, 500));
2783
+ for (const childPid of descendants) {
2784
+ try { process.kill(childPid, "SIGKILL"); } catch {}
2785
+ }
2786
+ }
2787
+ } catch {}
2788
+
2789
+ process.exit(0);
2790
+ }
2791
+
2792
+ /**
2793
+ * Check if shutdown was requested and perform shutdown if so.
2794
+ */
2795
+ private async checkShutdownRequested(): Promise<void> {
2796
+ if (!this.shutdownRequested) return;
2797
+ await this.shutdown();
2798
+ }
2799
+
2800
+ private handleCtrlZ(): void {
2801
+ // On Windows, SIGTSTP doesn't exist - Ctrl+Z is not supported
2802
+ if (process.platform === "win32") {
2803
+ return;
2804
+ }
2805
+
2806
+ // Ignore SIGINT while suspended so Ctrl+C in the terminal does not
2807
+ // kill the backgrounded process. The handler is removed on resume.
2808
+ const ignoreSigint = () => {};
2809
+ process.on("SIGINT", ignoreSigint);
2810
+
2811
+ try {
2812
+ // Set up handler to restore TUI when resumed
2813
+ process.once("SIGCONT", () => {
2814
+ process.removeListener("SIGINT", ignoreSigint);
2815
+ this.ui.start();
2816
+ this.ui.requestRender(true);
2817
+ });
2818
+
2819
+ // Stop the TUI (restore terminal to normal mode)
2820
+ this.ui.stop();
2821
+
2822
+ // Send SIGTSTP to process group (pid=0 means all processes in group)
2823
+ process.kill(0, "SIGTSTP");
2824
+ } catch {
2825
+ // If suspend fails (e.g. SIGTSTP not supported), ensure the
2826
+ // SIGINT listener doesn't leak.
2827
+ process.removeListener("SIGINT", ignoreSigint);
2828
+ }
2829
+ }
2830
+
2831
+ private async handleFollowUp(): Promise<void> {
2832
+ const text = (this.editor.getExpandedText?.() ?? this.editor.getText()).trim();
2833
+ if (!text) return;
2834
+
2835
+ if (text.startsWith("/") && !this.isKnownSlashCommand(text)) {
2836
+ const command = text.split(/\s/)[0];
2837
+ this.showError(`Unknown command: ${command}. Use slash autocomplete to see available commands.`);
2838
+ return;
2839
+ }
2840
+
2841
+ // Consume pending images
2842
+ const images = this.pendingImages.length > 0 ? [...this.pendingImages] : undefined;
2843
+ this.pendingImages.length = 0;
2844
+
2845
+ // Queue input during compaction (extension commands execute immediately)
2846
+ if (this.session.isCompacting) {
2847
+ if (this.isExtensionCommand(text)) {
2848
+ this.editor.addToHistory?.(text);
2849
+ this.editor.setText("");
2850
+ await this.session.prompt(text, { images });
2851
+ } else {
2852
+ this.queueCompactionMessage(text, "followUp");
2853
+ }
2854
+ return;
2855
+ }
2856
+
2857
+ // Alt+Enter queues a follow-up message (waits until agent finishes)
2858
+ // This handles extension commands (execute immediately), prompt template expansion, and queueing
2859
+ if (this.session.isStreaming) {
2860
+ this.editor.addToHistory?.(text);
2861
+ this.editor.setText("");
2862
+ await this.session.prompt(text, { streamingBehavior: "followUp", images });
2863
+ this.updatePendingMessagesDisplay();
2864
+ this.ui.requestRender();
2865
+ }
2866
+ // If not streaming, Alt+Enter acts like regular Enter (trigger onSubmit)
2867
+ else if (this.editor.onSubmit) {
2868
+ this.editor.onSubmit(text);
2869
+ }
2870
+ }
2871
+
2872
+ private handleDequeue(): void {
2873
+ const restored = this.restoreQueuedMessagesToEditor();
2874
+ if (restored === 0) {
2875
+ this.showStatus("No queued messages to restore");
2876
+ } else {
2877
+ this.showStatus(`Restored ${restored} queued message${restored > 1 ? "s" : ""} to editor`);
2878
+ }
2879
+ }
2880
+
2881
+ private updateEditorBorderColor(): void {
2882
+ if (this.isBashMode) {
2883
+ this.editor.borderColor = theme.getBashModeBorderColor();
2884
+ } else {
2885
+ const level = this.session.thinkingLevel || "off";
2886
+ this.editor.borderColor = theme.getThinkingBorderColor(level);
2887
+ }
2888
+ this.ui.requestRender();
2889
+ }
2890
+
2891
+ private cycleThinkingLevel(): void {
2892
+ const newLevel = this.session.cycleThinkingLevel();
2893
+ if (newLevel === undefined) {
2894
+ this.showStatus("Current model does not support thinking");
2895
+ } else {
2896
+ this.footer.invalidate();
2897
+ this.updateEditorBorderColor();
2898
+ this.showStatus(`Thinking level: ${newLevel}`);
2899
+ }
2900
+ }
2901
+
2902
+ private async cycleModel(direction: "forward" | "backward"): Promise<void> {
2903
+ try {
2904
+ const result = await this.session.cycleModel(direction);
2905
+ if (result === undefined) {
2906
+ const msg = this.session.scopedModels.length > 0 ? "Only one model in scope" : "Only one model available";
2907
+ this.showStatus(msg);
2908
+ } else {
2909
+ this.footer.invalidate();
2910
+ this.updateEditorBorderColor();
2911
+ const thinkingStr =
2912
+ result.model.reasoning && result.thinkingLevel !== "off" ? ` (thinking: ${result.thinkingLevel})` : "";
2913
+ this.showStatus(`Switched to ${result.model.name || result.model.id}${thinkingStr}`);
2914
+ }
2915
+ } catch (error) {
2916
+ this.showError(error instanceof Error ? error.message : String(error));
2917
+ }
2918
+ }
2919
+
2920
+ private toggleToolOutputExpansion(): void {
2921
+ this.setToolsExpanded(!this.toolOutputExpanded);
2922
+ }
2923
+
2924
+ private setToolsExpanded(expanded: boolean): void {
2925
+ this.toolOutputExpanded = expanded;
2926
+ for (const child of this.chatContainer.children) {
2927
+ if (isExpandable(child)) {
2928
+ child.setExpanded(expanded);
2929
+ }
2930
+ }
2931
+ this.ui.requestRender();
2932
+ }
2933
+
2934
+ private toggleThinkingBlockVisibility(): void {
2935
+ this.hideThinkingBlock = !this.hideThinkingBlock;
2936
+ this.settingsManager.setHideThinkingBlock(this.hideThinkingBlock);
2937
+
2938
+ // Rebuild chat from session messages
2939
+ this.chatContainer.clear();
2940
+ this.rebuildChatFromMessages();
2941
+
2942
+ // If streaming, re-add the streaming component with updated visibility and re-render
2943
+ if (this.streamingComponent && this.streamingMessage) {
2944
+ this.streamingComponent.setHideThinkingBlock(this.hideThinkingBlock);
2945
+ this.streamingComponent.updateContent(this.streamingMessage);
2946
+ this.chatContainer.addChild(this.streamingComponent);
2947
+ }
2948
+
2949
+ this.showStatus(`Thinking blocks: ${this.hideThinkingBlock ? "hidden" : "visible"}`);
2950
+ }
2951
+
2952
+ private openExternalEditor(): void {
2953
+ // Determine editor (respect $VISUAL, then $EDITOR)
2954
+ const editorCmd = process.env.VISUAL || process.env.EDITOR;
2955
+ if (!editorCmd) {
2956
+ let msg = "No editor configured. Set $VISUAL or $EDITOR environment variable.";
2957
+ if (process.env.TERM_PROGRAM === "iTerm.app") {
2958
+ msg +=
2959
+ "\n\nTip: If you meant to open the GSD dashboard (Ctrl+Alt+G), set Left Option Key to" +
2960
+ " \"Esc+\" in iTerm2 → Profiles → Keys. With the default \"Normal\" setting," +
2961
+ " Ctrl+Alt+G sends Ctrl+G instead.";
2962
+ }
2963
+ this.showWarning(msg);
2964
+ return;
2965
+ }
2966
+
2967
+ const currentText = this.editor.getExpandedText?.() ?? this.editor.getText();
2968
+ const tmpFile = path.join(os.tmpdir(), `pi-editor-${Date.now()}.pi.md`);
2969
+
2970
+ try {
2971
+ // Write current content to temp file
2972
+ fs.writeFileSync(tmpFile, currentText, "utf-8");
2973
+
2974
+ // Stop TUI to release terminal
2975
+ this.ui.stop();
2976
+
2977
+ // Split by space to support editor arguments (e.g., "code --wait")
2978
+ const [editor, ...editorArgs] = editorCmd.split(" ");
2979
+
2980
+ // Spawn editor synchronously with inherited stdio for interactive editing
2981
+ const result = spawnSync(editor, [...editorArgs, tmpFile], {
2982
+ stdio: "inherit",
2983
+ shell: process.platform === "win32",
2984
+ });
2985
+
2986
+ // On successful exit (status 0), replace editor content
2987
+ if (result.status === 0) {
2988
+ const newContent = fs.readFileSync(tmpFile, "utf-8").replace(/\n$/, "");
2989
+ this.editor.setText(newContent);
2990
+ }
2991
+ // On non-zero exit, keep original text (no action needed)
2992
+ } finally {
2993
+ // Clean up temp file
2994
+ try {
2995
+ fs.unlinkSync(tmpFile);
2996
+ } catch {
2997
+ // Ignore cleanup errors
2998
+ }
2999
+
3000
+ // Restart TUI
3001
+ this.ui.start();
3002
+ // Force full re-render since external editor uses alternate screen
3003
+ this.ui.requestRender(true);
3004
+ }
3005
+ }
3006
+
3007
+ // =========================================================================
3008
+ // UI helpers
3009
+ // =========================================================================
3010
+
3011
+ clearEditor(): void {
3012
+ this.editor.setText("");
3013
+ this.ui.requestRender();
3014
+ }
3015
+
3016
+ showError(errorMessage: string): void {
3017
+ this.lastBlockingError = errorMessage;
3018
+ renderBlockingErrorBanner(this.blockingErrorContainer, this.lastBlockingError);
3019
+ this.chatContainer.addChild(new Spacer(1));
3020
+ this.chatContainer.addChild(new Text(theme.fg("error", `Error: ${errorMessage}`), 1, 0));
3021
+ this.ui.requestRender();
3022
+ }
3023
+
3024
+ clearBlockingError(): void {
3025
+ this.lastBlockingError = undefined;
3026
+ renderBlockingErrorBanner(this.blockingErrorContainer, undefined);
3027
+ this.ui.requestRender();
3028
+ }
3029
+
3030
+ showWarning(warningMessage: string): void {
3031
+ this.chatContainer.addChild(new Spacer(1));
3032
+ this.chatContainer.addChild(new Text(theme.fg("warning", `Warning: ${warningMessage}`), 1, 0));
3033
+ this.ui.requestRender();
3034
+ }
3035
+
3036
+ showSuccess(successMessage: string): void {
3037
+ this.chatContainer.addChild(new Spacer(1));
3038
+ this.chatContainer.addChild(new DynamicBorder((text) => theme.fg("success", text)));
3039
+ this.chatContainer.addChild(
3040
+ new Text(theme.fg("success", successMessage), 1, 0),
3041
+ );
3042
+ this.chatContainer.addChild(new DynamicBorder((text) => theme.fg("success", text)));
3043
+ this.chatContainer.addChild(new Spacer(1));
3044
+ this.ui.requestRender();
3045
+ }
3046
+
3047
+ showTip(message: string): void {
3048
+ this.chatContainer.addChild(new Spacer(1));
3049
+ this.chatContainer.addChild(new Text(theme.fg("dim", `💡 ${message}`), 1, 0));
3050
+ this.ui.requestRender();
3051
+ }
3052
+
3053
+ getContextPercent(): number | undefined {
3054
+ return this.session.getContextUsage()?.percent ?? undefined;
3055
+ }
3056
+
3057
+ showNewVersionNotification(newVersion: string): void {
3058
+ const action = theme.fg("accent", getUpdateInstruction("@gsd/pi-coding-agent"));
3059
+ const updateInstruction = theme.fg("muted", `New version ${newVersion} is available. `) + action;
3060
+ const changelogUrl = theme.fg(
3061
+ "accent",
3062
+ "https://github.com/badlogic/pi-mono/blob/main/packages/coding-agent/CHANGELOG.md",
3063
+ );
3064
+ const changelogLine = theme.fg("muted", "Changelog: ") + changelogUrl;
3065
+
3066
+ this.chatContainer.addChild(new Spacer(1));
3067
+ this.chatContainer.addChild(new DynamicBorder((text) => theme.fg("warning", text)));
3068
+ this.chatContainer.addChild(
3069
+ new Text(
3070
+ `${theme.bold(theme.fg("warning", "Update Available"))}\n${updateInstruction}\n${changelogLine}`,
3071
+ 1,
3072
+ 0,
3073
+ ),
3074
+ );
3075
+ this.chatContainer.addChild(new DynamicBorder((text) => theme.fg("warning", text)));
3076
+ this.ui.requestRender();
3077
+ }
3078
+
3079
+ /**
3080
+ * Get all queued messages (read-only).
3081
+ * Combines session queue and compaction queue.
3082
+ */
3083
+ private getAllQueuedMessages(): { steering: string[]; followUp: string[] } {
3084
+ return {
3085
+ steering: [
3086
+ ...this.session.getSteeringMessages(),
3087
+ ...this.compactionQueuedMessages.filter((msg) => msg.mode === "steer").map((msg) => msg.text),
3088
+ ],
3089
+ followUp: [
3090
+ ...this.session.getFollowUpMessages(),
3091
+ ...this.compactionQueuedMessages.filter((msg) => msg.mode === "followUp").map((msg) => msg.text),
3092
+ ],
3093
+ };
3094
+ }
3095
+
3096
+ /**
3097
+ * Clear all queued messages and return their contents.
3098
+ * Clears both session queue and compaction queue.
3099
+ */
3100
+ private clearAllQueues(): { steering: string[]; followUp: string[] } {
3101
+ const { steering, followUp } = this.session.clearQueue();
3102
+ const compactionSteering = this.compactionQueuedMessages
3103
+ .filter((msg) => msg.mode === "steer")
3104
+ .map((msg) => msg.text);
3105
+ const compactionFollowUp = this.compactionQueuedMessages
3106
+ .filter((msg) => msg.mode === "followUp")
3107
+ .map((msg) => msg.text);
3108
+ this.compactionQueuedMessages = [];
3109
+ return {
3110
+ steering: [...steering, ...compactionSteering],
3111
+ followUp: [...followUp, ...compactionFollowUp],
3112
+ };
3113
+ }
3114
+
3115
+ private updatePendingMessagesDisplay(): void {
3116
+ this.pendingMessagesContainer.clear();
3117
+ const { steering: steeringMessages, followUp: followUpMessages } = this.getAllQueuedMessages();
3118
+ if (steeringMessages.length > 0 || followUpMessages.length > 0) {
3119
+ this.pendingMessagesContainer.addChild(new Spacer(1));
3120
+ for (const message of steeringMessages) {
3121
+ const text = theme.fg("dim", `Steering: ${message}`);
3122
+ this.pendingMessagesContainer.addChild(new TruncatedText(text, 1, 0));
3123
+ }
3124
+ for (const message of followUpMessages) {
3125
+ const text = theme.fg("dim", `Follow-up: ${message}`);
3126
+ this.pendingMessagesContainer.addChild(new TruncatedText(text, 1, 0));
3127
+ }
3128
+ const dequeueHint = getAppKeyDisplay(this.keybindings, "dequeue");
3129
+ const hintText = theme.fg("dim", `↳ ${dequeueHint} to edit all queued messages`);
3130
+ this.pendingMessagesContainer.addChild(new TruncatedText(hintText, 1, 0));
3131
+ }
3132
+ }
3133
+
3134
+ private restoreQueuedMessagesToEditor(options?: { abort?: boolean; currentText?: string }): number {
3135
+ const { steering, followUp } = this.clearAllQueues();
3136
+ const allQueued = [...steering, ...followUp];
3137
+ if (allQueued.length === 0) {
3138
+ this.updatePendingMessagesDisplay();
3139
+ if (options?.abort) {
3140
+ this.agent.abort("user");
3141
+ }
3142
+ return 0;
3143
+ }
3144
+ const queuedText = allQueued.join("\n\n");
3145
+ const currentText = options?.currentText ?? this.editor.getText();
3146
+ const combinedText = [queuedText, currentText].filter((t) => t.trim()).join("\n\n");
3147
+ this.editor.setText(combinedText);
3148
+ this.updatePendingMessagesDisplay();
3149
+ if (options?.abort) {
3150
+ this.agent.abort("user");
3151
+ }
3152
+ return allQueued.length;
3153
+ }
3154
+
3155
+ private queueCompactionMessage(text: string, mode: "steer" | "followUp"): void {
3156
+ if (text.startsWith("/") && !this.isKnownSlashCommand(text)) {
3157
+ const command = text.split(/\s/)[0];
3158
+ this.showError(`Unknown command: ${command}. Use slash autocomplete to see available commands.`);
3159
+ return;
3160
+ }
3161
+
3162
+ this.compactionQueuedMessages.push({ text, mode });
3163
+ this.editor.addToHistory?.(text);
3164
+ this.editor.setText("");
3165
+ this.updatePendingMessagesDisplay();
3166
+ this.showStatus("Queued message for after compaction");
3167
+ }
3168
+
3169
+ private isExtensionCommand(text: string): boolean {
3170
+ if (!text.startsWith("/")) return false;
3171
+
3172
+ const extensionRunner = this.session.extensionRunner;
3173
+ if (!extensionRunner) return false;
3174
+
3175
+ const spaceIndex = text.indexOf(" ");
3176
+ const commandName = spaceIndex === -1 ? text.slice(1) : text.slice(1, spaceIndex);
3177
+ return !!extensionRunner.getCommand(commandName);
3178
+ }
3179
+
3180
+ private isKnownSlashCommand(text: string): boolean {
3181
+ if (!text.startsWith("/")) return false;
3182
+
3183
+ const spaceIndex = text.indexOf(" ");
3184
+ const commandName = spaceIndex === -1 ? text.slice(1) : text.slice(1, spaceIndex);
3185
+
3186
+ if (BUILTIN_SLASH_COMMANDS.some((command) => command.name === commandName)) {
3187
+ return true;
3188
+ }
3189
+
3190
+ if (this.isExtensionCommand(text)) {
3191
+ return true;
3192
+ }
3193
+
3194
+ if (this.session.promptTemplates.some((template) => template.name === commandName)) {
3195
+ return true;
3196
+ }
3197
+
3198
+ if (commandName.startsWith("skill:") && this.settingsManager.getEnableSkillCommands()) {
3199
+ const skillName = commandName.slice("skill:".length);
3200
+ return this.session.resourceLoader.getSkills().skills.some((skill) => skill.name === skillName);
3201
+ }
3202
+
3203
+ return false;
3204
+ }
3205
+
3206
+ private async flushCompactionQueue(options?: { willRetry?: boolean }): Promise<void> {
3207
+ if (this.compactionQueuedMessages.length === 0) {
3208
+ return;
3209
+ }
3210
+
3211
+ const queuedMessages = [...this.compactionQueuedMessages];
3212
+ this.compactionQueuedMessages = [];
3213
+ this.updatePendingMessagesDisplay();
3214
+
3215
+ const restoreQueue = (error: unknown) => {
3216
+ this.session.clearQueue();
3217
+ this.compactionQueuedMessages = queuedMessages;
3218
+ this.updatePendingMessagesDisplay();
3219
+ this.showError(
3220
+ `Failed to send queued message${queuedMessages.length > 1 ? "s" : ""}: ${
3221
+ error instanceof Error ? error.message : String(error)
3222
+ }`,
3223
+ );
3224
+ };
3225
+
3226
+ try {
3227
+ if (options?.willRetry) {
3228
+ // When retry is pending, queue messages for the retry turn
3229
+ for (const message of queuedMessages) {
3230
+ if (this.isExtensionCommand(message.text)) {
3231
+ await this.session.prompt(message.text);
3232
+ } else if (message.mode === "followUp") {
3233
+ await this.session.followUp(message.text);
3234
+ } else {
3235
+ await this.session.steer(message.text);
3236
+ }
3237
+ }
3238
+ this.updatePendingMessagesDisplay();
3239
+ return;
3240
+ }
3241
+
3242
+ // Find first non-extension-command message to use as prompt
3243
+ const firstPromptIndex = queuedMessages.findIndex((message) => !this.isExtensionCommand(message.text));
3244
+ if (firstPromptIndex === -1) {
3245
+ // All extension commands - execute them all
3246
+ for (const message of queuedMessages) {
3247
+ await this.session.prompt(message.text);
3248
+ }
3249
+ return;
3250
+ }
3251
+
3252
+ // Execute any extension commands before the first prompt
3253
+ const preCommands = queuedMessages.slice(0, firstPromptIndex);
3254
+ const firstPrompt = queuedMessages[firstPromptIndex];
3255
+ const rest = queuedMessages.slice(firstPromptIndex + 1);
3256
+
3257
+ for (const message of preCommands) {
3258
+ await this.session.prompt(message.text);
3259
+ }
3260
+
3261
+ // Send first prompt (starts streaming)
3262
+ const promptPromise = this.session.prompt(firstPrompt.text).catch((error) => {
3263
+ restoreQueue(error);
3264
+ });
3265
+
3266
+ // Queue remaining messages
3267
+ for (const message of rest) {
3268
+ if (this.isExtensionCommand(message.text)) {
3269
+ await this.session.prompt(message.text);
3270
+ } else if (message.mode === "followUp") {
3271
+ await this.session.followUp(message.text);
3272
+ } else {
3273
+ await this.session.steer(message.text);
3274
+ }
3275
+ }
3276
+ this.updatePendingMessagesDisplay();
3277
+ void promptPromise;
3278
+ } catch (error) {
3279
+ restoreQueue(error);
3280
+ }
3281
+ }
3282
+
3283
+ /** Move pending bash components from pending area to chat */
3284
+ private flushPendingBashComponents(): void {
3285
+ for (const component of this.pendingBashComponents) {
3286
+ this.pendingMessagesContainer.removeChild(component);
3287
+ this.chatContainer.addChild(component);
3288
+ }
3289
+ this.pendingBashComponents = [];
3290
+ }
3291
+
3292
+ // =========================================================================
3293
+ // Selectors
3294
+ // =========================================================================
3295
+
3296
+ /**
3297
+ * Shows a selector component in place of the editor.
3298
+ * @param create Factory that receives a `done` callback and returns the component and focus target
3299
+ */
3300
+ private showSelector(create: (done: () => void) => { component: Component; focus: Component }): void {
3301
+ const done = () => {
3302
+ this.editorContainer.clear();
3303
+ this.editorContainer.addChild(this.editor);
3304
+ this.ui.setFocus(this.editor);
3305
+ };
3306
+ const { component, focus } = create(done);
3307
+ this.editorContainer.clear();
3308
+ this.editorContainer.addChild(component);
3309
+ this.ui.setFocus(focus);
3310
+ this.ui.requestRender();
3311
+ }
3312
+
3313
+ private showSettingsSelector(): void {
3314
+ this.showSelector((done) => {
3315
+ const selector = new SettingsSelectorComponent(
3316
+ {
3317
+ autoCompact: this.session.autoCompactionEnabled,
3318
+ showImages: this.settingsManager.getShowImages(),
3319
+ autoResizeImages: this.settingsManager.getImageAutoResize(),
3320
+ blockImages: this.settingsManager.getBlockImages(),
3321
+ enableSkillCommands: this.settingsManager.getEnableSkillCommands(),
3322
+ steeringMode: this.session.steeringMode,
3323
+ followUpMode: this.session.followUpMode,
3324
+ transport: this.settingsManager.getTransport(),
3325
+ thinkingLevel: this.session.thinkingLevel,
3326
+ availableThinkingLevels: this.session.getAvailableThinkingLevels(),
3327
+ currentTheme: this.settingsManager.getTheme() || "dark",
3328
+ availableThemes: getAvailableThemes(),
3329
+ hideThinkingBlock: this.hideThinkingBlock,
3330
+ collapseChangelog: this.settingsManager.getCollapseChangelog(),
3331
+ doubleEscapeAction: this.settingsManager.getDoubleEscapeAction(),
3332
+ treeFilterMode: this.settingsManager.getTreeFilterMode(),
3333
+ showHardwareCursor: this.settingsManager.getShowHardwareCursor(),
3334
+ editorPaddingX: this.settingsManager.getEditorPaddingX(),
3335
+ autocompleteMaxVisible: this.settingsManager.getAutocompleteMaxVisible(),
3336
+ respectGitignoreInPicker: this.settingsManager.getRespectGitignoreInPicker(),
3337
+ quietStartup: this.settingsManager.getQuietStartup(),
3338
+ clearOnShrink: this.settingsManager.getClearOnShrink(),
3339
+ timestampFormat: this.settingsManager.getTimestampFormat(),
3340
+ adaptiveMode: this.settingsManager.getAdaptiveMode(),
3341
+ },
3342
+ {
3343
+ onAutoCompactChange: (enabled) => {
3344
+ this.session.setAutoCompactionEnabled(enabled);
3345
+ this.footer.setAutoCompactEnabled(enabled);
3346
+ },
3347
+ onShowImagesChange: (enabled) => {
3348
+ this.settingsManager.setShowImages(enabled);
3349
+ for (const child of this.chatContainer.children) {
3350
+ if (child instanceof ToolExecutionComponent) {
3351
+ child.setShowImages(enabled);
3352
+ }
3353
+ }
3354
+ },
3355
+ onAutoResizeImagesChange: (enabled) => {
3356
+ this.settingsManager.setImageAutoResize(enabled);
3357
+ },
3358
+ onBlockImagesChange: (blocked) => {
3359
+ this.settingsManager.setBlockImages(blocked);
3360
+ },
3361
+ onEnableSkillCommandsChange: (enabled) => {
3362
+ this.settingsManager.setEnableSkillCommands(enabled);
3363
+ this.setupAutocomplete();
3364
+ },
3365
+ onSteeringModeChange: (mode) => {
3366
+ this.session.setSteeringMode(mode);
3367
+ },
3368
+ onFollowUpModeChange: (mode) => {
3369
+ this.session.setFollowUpMode(mode);
3370
+ },
3371
+ onTransportChange: (transport) => {
3372
+ this.settingsManager.setTransport(transport);
3373
+ this.session.agent.setTransport(transport);
3374
+ },
3375
+ onThinkingLevelChange: (level) => {
3376
+ this.session.setThinkingLevel(level);
3377
+ this.footer.invalidate();
3378
+ this.updateEditorBorderColor();
3379
+ },
3380
+ onThemeChange: (themeName) => {
3381
+ const result = setTheme(themeName, true);
3382
+ this.settingsManager.setTheme(themeName);
3383
+ this.clearMarkdownThemeCache();
3384
+ this.ui.invalidate();
3385
+ if (!result.success) {
3386
+ this.showError(`Failed to load theme "${themeName}": ${result.error}\nFell back to dark theme.`);
3387
+ }
3388
+ },
3389
+ onThemePreview: (themeName) => {
3390
+ const result = setTheme(themeName, true);
3391
+ if (result.success) {
3392
+ this.clearMarkdownThemeCache();
3393
+ this.ui.invalidate();
3394
+ this.ui.requestRender();
3395
+ }
3396
+ },
3397
+ onHideThinkingBlockChange: (hidden) => {
3398
+ this.hideThinkingBlock = hidden;
3399
+ this.settingsManager.setHideThinkingBlock(hidden);
3400
+ for (const child of this.chatContainer.children) {
3401
+ if (child instanceof AssistantMessageComponent) {
3402
+ child.setHideThinkingBlock(hidden);
3403
+ }
3404
+ }
3405
+ this.chatContainer.clear();
3406
+ this.rebuildChatFromMessages();
3407
+ },
3408
+ onCollapseChangelogChange: (collapsed) => {
3409
+ this.settingsManager.setCollapseChangelog(collapsed);
3410
+ },
3411
+ onQuietStartupChange: (enabled) => {
3412
+ this.settingsManager.setQuietStartup(enabled);
3413
+ },
3414
+ onDoubleEscapeActionChange: (action) => {
3415
+ this.settingsManager.setDoubleEscapeAction(action);
3416
+ },
3417
+ onTreeFilterModeChange: (mode) => {
3418
+ this.settingsManager.setTreeFilterMode(mode);
3419
+ },
3420
+ onShowHardwareCursorChange: (enabled) => {
3421
+ this.settingsManager.setShowHardwareCursor(enabled);
3422
+ this.ui.setShowHardwareCursor(enabled);
3423
+ },
3424
+ onEditorPaddingXChange: (padding) => {
3425
+ this.settingsManager.setEditorPaddingX(padding);
3426
+ this.defaultEditor.setPaddingX(padding);
3427
+ if (this.editor !== this.defaultEditor && this.editor.setPaddingX !== undefined) {
3428
+ this.editor.setPaddingX(padding);
3429
+ }
3430
+ },
3431
+ onAutocompleteMaxVisibleChange: (maxVisible) => {
3432
+ this.settingsManager.setAutocompleteMaxVisible(maxVisible);
3433
+ this.defaultEditor.setAutocompleteMaxVisible(maxVisible);
3434
+ if (this.editor !== this.defaultEditor && this.editor.setAutocompleteMaxVisible !== undefined) {
3435
+ this.editor.setAutocompleteMaxVisible(maxVisible);
3436
+ }
3437
+ },
3438
+ onClearOnShrinkChange: (enabled) => {
3439
+ this.settingsManager.setClearOnShrink(enabled);
3440
+ this.ui.setClearOnShrink(enabled);
3441
+ },
3442
+ onRespectGitignoreInPickerChange: (enabled) => {
3443
+ this.settingsManager.setRespectGitignoreInPicker(enabled);
3444
+ this.autocompleteProvider?.setRespectGitignore(enabled);
3445
+ },
3446
+ onTimestampFormatChange: (format) => {
3447
+ this.settingsManager.setTimestampFormat(format);
3448
+ },
3449
+ onAdaptiveModeChange: (mode) => {
3450
+ this.settingsManager.setAdaptiveMode(mode);
3451
+ this.ui.requestRender();
3452
+ },
3453
+ onCancel: () => {
3454
+ done();
3455
+ this.ui.requestRender();
3456
+ },
3457
+ },
3458
+ );
3459
+ return { component: selector, focus: selector.getSettingsList() };
3460
+ });
3461
+ }
3462
+
3463
+ private async handleModelCommand(searchTerm?: string): Promise<void> {
3464
+ await handleModelCommandController(this, searchTerm);
3465
+ }
3466
+
3467
+ private async findExactModelMatch(searchTerm: string): Promise<Model<any> | undefined> {
3468
+ return findExactModelMatchController(this, searchTerm);
3469
+ }
3470
+
3471
+ private async getModelCandidates(): Promise<Model<any>[]> {
3472
+ return getModelCandidatesController(this);
3473
+ }
3474
+
3475
+ /** Update the footer's available provider count from current model candidates */
3476
+ private async updateAvailableProviderCount(): Promise<void> {
3477
+ await updateAvailableProviderCountController(this);
3478
+ }
3479
+
3480
+ private showModelSelector(initialSearchInput?: string): void {
3481
+ this.showSelector((done) => {
3482
+ const selector = new ModelSelectorComponent(
3483
+ this.ui,
3484
+ this.session.model,
3485
+ this.settingsManager,
3486
+ this.session.modelRegistry,
3487
+ this.session.scopedModels,
3488
+ async (model) => {
3489
+ try {
3490
+ await this.session.setModel(model);
3491
+ this.footer.invalidate();
3492
+ this.updateEditorBorderColor();
3493
+ done();
3494
+ this.showStatus(`Model: ${model.id}`);
3495
+ this.checkDaxnutsEasterEgg(model);
3496
+ } catch (error) {
3497
+ done();
3498
+ this.showError(error instanceof Error ? error.message : String(error));
3499
+ }
3500
+ },
3501
+ () => {
3502
+ done();
3503
+ this.ui.requestRender();
3504
+ },
3505
+ initialSearchInput,
3506
+ );
3507
+ return { component: selector, focus: selector };
3508
+ });
3509
+ }
3510
+
3511
+ private async showModelsSelector(): Promise<void> {
3512
+ // Get all available models
3513
+ this.session.modelRegistry.refresh();
3514
+ const allModels = this.session.modelRegistry.getAvailable();
3515
+
3516
+ if (allModels.length === 0) {
3517
+ this.showStatus("No models available");
3518
+ return;
3519
+ }
3520
+
3521
+ // Check if session has scoped models (from previous session-only changes or CLI --models)
3522
+ const sessionScopedModels = this.session.scopedModels;
3523
+ const hasSessionScope = sessionScopedModels.length > 0;
3524
+
3525
+ // Build enabled model IDs from session state or settings
3526
+ const enabledModelIds = new Set<string>();
3527
+ let hasFilter = false;
3528
+
3529
+ if (hasSessionScope) {
3530
+ // Use current session's scoped models
3531
+ for (const sm of sessionScopedModels) {
3532
+ enabledModelIds.add(`${sm.model.provider}/${sm.model.id}`);
3533
+ }
3534
+ hasFilter = true;
3535
+ } else {
3536
+ // Fall back to settings
3537
+ const patterns = this.settingsManager.getEnabledModels();
3538
+ if (patterns !== undefined && patterns.length > 0) {
3539
+ hasFilter = true;
3540
+ const scopedModels = await resolveModelScope(patterns, this.session.modelRegistry);
3541
+ for (const sm of scopedModels) {
3542
+ enabledModelIds.add(`${sm.model.provider}/${sm.model.id}`);
3543
+ }
3544
+ }
3545
+ }
3546
+
3547
+ // Track current enabled state (session-only until persisted)
3548
+ const currentEnabledIds = new Set(enabledModelIds);
3549
+ let currentHasFilter = hasFilter;
3550
+
3551
+ // Helper to update session's scoped models (session-only, no persist)
3552
+ const updateSessionModels = async (enabledIds: Set<string>) => {
3553
+ if (enabledIds.size > 0 && enabledIds.size < allModels.length) {
3554
+ const newScopedModels = await resolveModelScope(Array.from(enabledIds), this.session.modelRegistry);
3555
+ this.session.setScopedModels(
3556
+ newScopedModels.map((sm) => ({
3557
+ model: sm.model,
3558
+ thinkingLevel: sm.thinkingLevel,
3559
+ })),
3560
+ );
3561
+ } else {
3562
+ // All enabled or none enabled = no filter
3563
+ this.session.setScopedModels([]);
3564
+ }
3565
+ await this.updateAvailableProviderCount();
3566
+ this.ui.requestRender();
3567
+ };
3568
+
3569
+ this.showSelector((done) => {
3570
+ const selector = new ScopedModelsSelectorComponent(
3571
+ {
3572
+ allModels,
3573
+ enabledModelIds: currentEnabledIds,
3574
+ hasEnabledModelsFilter: currentHasFilter,
3575
+ },
3576
+ {
3577
+ onModelToggle: async (modelId, enabled) => {
3578
+ if (enabled) {
3579
+ currentEnabledIds.add(modelId);
3580
+ } else {
3581
+ currentEnabledIds.delete(modelId);
3582
+ }
3583
+ currentHasFilter = true;
3584
+ await updateSessionModels(currentEnabledIds);
3585
+ },
3586
+ onEnableAll: async (allModelIds) => {
3587
+ currentEnabledIds.clear();
3588
+ for (const id of allModelIds) {
3589
+ currentEnabledIds.add(id);
3590
+ }
3591
+ currentHasFilter = false;
3592
+ await updateSessionModels(currentEnabledIds);
3593
+ },
3594
+ onClearAll: async () => {
3595
+ currentEnabledIds.clear();
3596
+ currentHasFilter = true;
3597
+ await updateSessionModels(currentEnabledIds);
3598
+ },
3599
+ onToggleProvider: async (_provider, modelIds, enabled) => {
3600
+ for (const id of modelIds) {
3601
+ if (enabled) {
3602
+ currentEnabledIds.add(id);
3603
+ } else {
3604
+ currentEnabledIds.delete(id);
3605
+ }
3606
+ }
3607
+ currentHasFilter = true;
3608
+ await updateSessionModels(currentEnabledIds);
3609
+ },
3610
+ onPersist: (enabledIds) => {
3611
+ // Persist to settings
3612
+ const newPatterns =
3613
+ enabledIds.length === allModels.length
3614
+ ? undefined // All enabled = clear filter
3615
+ : enabledIds;
3616
+ this.settingsManager.setEnabledModels(newPatterns);
3617
+ this.showStatus("Model selection saved to settings");
3618
+ },
3619
+ onCancel: () => {
3620
+ done();
3621
+ this.ui.requestRender();
3622
+ },
3623
+ },
3624
+ );
3625
+ return { component: selector, focus: selector };
3626
+ });
3627
+ }
3628
+
3629
+ private showUserMessageSelector(): void {
3630
+ const userMessages = this.session.getUserMessagesForForking();
3631
+
3632
+ if (userMessages.length === 0) {
3633
+ this.showStatus("No messages to fork from");
3634
+ return;
3635
+ }
3636
+
3637
+ this.showSelector((done) => {
3638
+ const selector = new UserMessageSelectorComponent(
3639
+ userMessages.map((m) => ({ id: m.entryId, text: m.text })),
3640
+ async (entryId) => {
3641
+ const result = await this.session.fork(entryId);
3642
+ if (result.cancelled) {
3643
+ // Extension cancelled the fork
3644
+ done();
3645
+ this.ui.requestRender();
3646
+ return;
3647
+ }
3648
+
3649
+ this.chatContainer.clear();
3650
+ this.renderInitialMessages();
3651
+ this.editor.setText(result.selectedText);
3652
+ done();
3653
+ this.showStatus("Branched to new session");
3654
+ },
3655
+ () => {
3656
+ done();
3657
+ this.ui.requestRender();
3658
+ },
3659
+ );
3660
+ return { component: selector, focus: selector.getMessageList() };
3661
+ });
3662
+ }
3663
+
3664
+ private showTreeSelector(initialSelectedId?: string): void {
3665
+ const tree = this.sessionManager.getTree();
3666
+ const realLeafId = this.sessionManager.getLeafId();
3667
+ const initialFilterMode = this.settingsManager.getTreeFilterMode();
3668
+
3669
+ if (tree.length === 0) {
3670
+ this.showStatus("No entries in session");
3671
+ return;
3672
+ }
3673
+
3674
+ this.showSelector((done) => {
3675
+ const selector = new TreeSelectorComponent(
3676
+ tree,
3677
+ realLeafId,
3678
+ this.ui.terminal.rows,
3679
+ async (entryId) => {
3680
+ // Selecting the current leaf is a no-op (already there)
3681
+ if (entryId === realLeafId) {
3682
+ done();
3683
+ this.showStatus("Already at this point");
3684
+ return;
3685
+ }
3686
+
3687
+ // Ask about summarization
3688
+ done(); // Close selector first
3689
+
3690
+ // Loop until user makes a complete choice or cancels to tree
3691
+ let wantsSummary = false;
3692
+ let customInstructions: string | undefined;
3693
+
3694
+ // Check if we should skip the prompt (user preference to always default to no summary)
3695
+ if (!this.settingsManager.getBranchSummarySkipPrompt()) {
3696
+ while (true) {
3697
+ const summaryChoice = await this.showExtensionSelector("Summarize branch?", [
3698
+ "No summary",
3699
+ "Summarize",
3700
+ "Summarize with custom prompt",
3701
+ ]);
3702
+
3703
+ if (summaryChoice === undefined) {
3704
+ // User pressed escape - re-show tree selector with same selection
3705
+ this.showTreeSelector(entryId);
3706
+ return;
3707
+ }
3708
+
3709
+ wantsSummary = summaryChoice !== "No summary";
3710
+
3711
+ if (summaryChoice === "Summarize with custom prompt") {
3712
+ customInstructions = await this.showExtensionEditor("Custom summarization instructions");
3713
+ if (customInstructions === undefined) {
3714
+ // User cancelled - loop back to summary selector
3715
+ continue;
3716
+ }
3717
+ }
3718
+
3719
+ // User made a complete choice
3720
+ break;
3721
+ }
3722
+ }
3723
+
3724
+ // Set up escape handler and loader if summarizing
3725
+ let summaryLoader: Loader | undefined;
3726
+ const originalOnEscape = this.defaultEditor.onEscape;
3727
+
3728
+ if (wantsSummary) {
3729
+ this.defaultEditor.onEscape = () => {
3730
+ this.session.abortBranchSummary();
3731
+ };
3732
+ this.chatContainer.addChild(new Spacer(1));
3733
+ summaryLoader = new Loader(
3734
+ this.ui,
3735
+ (spinner) => theme.fg("accent", spinner),
3736
+ (text) => theme.fg("muted", text),
3737
+ `Summarizing branch... (${appKey(this.keybindings, "interrupt")} to cancel)`,
3738
+ );
3739
+ this.statusContainer.addChild(summaryLoader);
3740
+ this.ui.requestRender();
3741
+ }
3742
+
3743
+ try {
3744
+ const result = await this.session.navigateTree(entryId, {
3745
+ summarize: wantsSummary,
3746
+ customInstructions,
3747
+ });
3748
+
3749
+ if (result.aborted) {
3750
+ // Summarization aborted - re-show tree selector with same selection
3751
+ this.showStatus("Branch summarization cancelled");
3752
+ this.showTreeSelector(entryId);
3753
+ return;
3754
+ }
3755
+ if (result.cancelled) {
3756
+ this.showStatus("Navigation cancelled");
3757
+ return;
3758
+ }
3759
+
3760
+ // Update UI
3761
+ this.chatContainer.clear();
3762
+ this.renderInitialMessages();
3763
+ if (result.editorText && !this.editor.getText().trim()) {
3764
+ this.editor.setText(result.editorText);
3765
+ }
3766
+ this.showStatus("Navigated to selected point");
3767
+ } catch (error) {
3768
+ this.showError(error instanceof Error ? error.message : String(error));
3769
+ } finally {
3770
+ if (summaryLoader) {
3771
+ summaryLoader.stop();
3772
+ this.statusContainer.clear();
3773
+ }
3774
+ this.defaultEditor.onEscape = originalOnEscape;
3775
+ }
3776
+ },
3777
+ () => {
3778
+ done();
3779
+ this.ui.requestRender();
3780
+ },
3781
+ (entryId, label) => {
3782
+ this.sessionManager.appendLabelChange(entryId, label);
3783
+ this.ui.requestRender();
3784
+ },
3785
+ initialSelectedId,
3786
+ initialFilterMode,
3787
+ );
3788
+ return { component: selector, focus: selector };
3789
+ });
3790
+ }
3791
+
3792
+ private showSessionSelector(): void {
3793
+ this.showSelector((done) => {
3794
+ const selector = new SessionSelectorComponent(
3795
+ (onProgress) =>
3796
+ SessionManager.list(this.sessionManager.getCwd(), this.sessionManager.getSessionDir(), onProgress),
3797
+ SessionManager.listAll,
3798
+ async (sessionPath) => {
3799
+ done();
3800
+ await this.handleResumeSession(sessionPath);
3801
+ },
3802
+ () => {
3803
+ done();
3804
+ this.ui.requestRender();
3805
+ },
3806
+ () => {
3807
+ void this.shutdown();
3808
+ },
3809
+ () => this.ui.requestRender(),
3810
+ {
3811
+ renameSession: async (sessionFilePath: string, nextName: string | undefined) => {
3812
+ const next = (nextName ?? "").trim();
3813
+ if (!next) return;
3814
+ const mgr = SessionManager.open(sessionFilePath);
3815
+ mgr.appendSessionInfo(next);
3816
+ },
3817
+ showRenameHint: true,
3818
+ keybindings: this.keybindings,
3819
+ },
3820
+
3821
+ this.sessionManager.getSessionFile(),
3822
+ );
3823
+ return { component: selector, focus: selector };
3824
+ });
3825
+ }
3826
+
3827
+ private async handleResumeSession(sessionPath: string): Promise<void> {
3828
+ // Stop loading animation
3829
+ if (this.loadingAnimation) {
3830
+ this.loadingAnimation.stop();
3831
+ this.loadingAnimation = undefined;
3832
+ }
3833
+ this.statusContainer.clear();
3834
+
3835
+ // Clear UI state
3836
+ this.pendingMessagesContainer.clear();
3837
+ this.compactionQueuedMessages = [];
3838
+ this.streamingComponent = undefined;
3839
+ this.streamingMessage = undefined;
3840
+ this.pendingTools.clear();
3841
+ this.clearBlockingError();
3842
+
3843
+ // Switch session via AgentSession (emits extension session events)
3844
+ await this.session.switchSession(sessionPath);
3845
+
3846
+ // Clear and re-render the chat
3847
+ this.chatContainer.clear();
3848
+ this.renderInitialMessages();
3849
+
3850
+ if (this.session.sessionManager.wasInterrupted()) {
3851
+ this.showStatus("Resumed session (previous session ended unexpectedly — last action may be incomplete)");
3852
+ } else {
3853
+ this.showStatus("Resumed session");
3854
+ }
3855
+ }
3856
+
3857
+ private showProviderManager(): void {
3858
+ this.showSelector((done) => {
3859
+ const component = new ProviderManagerComponent(
3860
+ this.ui,
3861
+ this.session.modelRegistry.authStorage,
3862
+ this.session.modelRegistry,
3863
+ () => {
3864
+ done();
3865
+ this.ui.requestRender();
3866
+ },
3867
+ async (provider: string) => {
3868
+ this.showStatus(`Discovering models for ${provider}...`);
3869
+ try {
3870
+ const results = await this.session.modelRegistry.discoverModels([provider]);
3871
+ const result = results[0];
3872
+ if (result?.error) {
3873
+ this.showError(`Discovery failed: ${result.error}`);
3874
+ } else {
3875
+ this.showStatus(`Discovered ${result?.models.length ?? 0} models from ${provider}`);
3876
+ }
3877
+ } catch (error) {
3878
+ this.showError(error instanceof Error ? error.message : String(error));
3879
+ }
3880
+ done();
3881
+ this.ui.requestRender();
3882
+ },
3883
+ async (provider: string) => {
3884
+ // Enter key → auth setup for selected provider (#3579).
3885
+ // Only OAuth providers support the login dialog flow.
3886
+ // externalCli providers (e.g. claude-code) authenticate through
3887
+ // their own CLI — sending them to the OAuth dialog produces
3888
+ // "Unknown OAuth provider: claude-code" (#4548).
3889
+ const isOAuthProvider = this.session.modelRegistry.authStorage
3890
+ .getOAuthProviders()
3891
+ .some((p) => p.id === provider);
3892
+ if (!isOAuthProvider) {
3893
+ done();
3894
+ this.showStatus(`${provider} uses external CLI auth — use /model to select a model or run the provider's own auth command.`);
3895
+ return;
3896
+ }
3897
+ done();
3898
+ await this.showLoginDialog(provider);
3899
+ },
3900
+ );
3901
+ return { component, focus: component };
3902
+ });
3903
+ }
3904
+
3905
+ private async showOAuthSelector(mode: "login" | "logout"): Promise<void> {
3906
+ if (mode === "logout") {
3907
+ const providers = this.session.modelRegistry.authStorage.list();
3908
+ const loggedInProviders = providers.filter(
3909
+ (p) => this.session.modelRegistry.authStorage.get(p)?.type === "oauth",
3910
+ );
3911
+ if (loggedInProviders.length === 0) {
3912
+ this.showStatus("No OAuth providers logged in. Use /login first.");
3913
+ return;
3914
+ }
3915
+ }
3916
+
3917
+ this.showSelector((done) => {
3918
+ const selector = new OAuthSelectorComponent(
3919
+ mode,
3920
+ this.session.modelRegistry.authStorage,
3921
+ (providerId: string) => {
3922
+ done();
3923
+
3924
+ // OAuthSelectorComponent calls this synchronously (no await),
3925
+ // so we must catch async errors here to prevent unhandled rejections
3926
+ // when the user cancels the login dialog (#821).
3927
+ const handleAsync = async () => {
3928
+ if (mode === "login") {
3929
+ await this.showLoginDialog(providerId);
3930
+ } else {
3931
+ // Logout flow
3932
+ const providerInfo = this.session.modelRegistry.authStorage
3933
+ .getOAuthProviders()
3934
+ .find((p) => p.id === providerId);
3935
+ const providerName = providerInfo?.name || providerId;
3936
+
3937
+ try {
3938
+ this.session.modelRegistry.authStorage.logout(providerId);
3939
+ this.session.modelRegistry.refresh();
3940
+ await this.updateAvailableProviderCount();
3941
+
3942
+ // Auto-switch model if current model belongs to the logged-out provider
3943
+ const currentModel = this.session.model;
3944
+ if (currentModel?.provider === providerId) {
3945
+ try {
3946
+ const available = this.session.modelRegistry.getAvailable();
3947
+ const fallback = available.find((m) => m.provider !== providerId);
3948
+ if (fallback) {
3949
+ await this.session.setModel(fallback);
3950
+ }
3951
+ } catch {
3952
+ // Model switch failed — user can manually switch via /model
3953
+ }
3954
+ }
3955
+
3956
+ this.showStatus(`Logged out of ${providerName}`);
3957
+ } catch (error: unknown) {
3958
+ this.showError(`Logout failed: ${error instanceof Error ? error.message : String(error)}`);
3959
+ }
3960
+ }
3961
+ };
3962
+ handleAsync().catch(() => {
3963
+ // Swallow — showLoginDialog already handles its own errors.
3964
+ // This prevents unhandled rejections when login is cancelled.
3965
+ });
3966
+ },
3967
+ () => {
3968
+ done();
3969
+ this.ui.requestRender();
3970
+ },
3971
+ );
3972
+ return { component: selector, focus: selector };
3973
+ });
3974
+ }
3975
+
3976
+ private async showLoginDialog(providerId: string): Promise<void> {
3977
+ const providerInfo = this.session.modelRegistry.authStorage.getOAuthProviders().find((p) => p.id === providerId);
3978
+ const providerName = providerInfo?.name || providerId;
3979
+
3980
+ // Providers that use callback servers (can paste redirect URL)
3981
+ const usesCallbackServer = providerInfo?.usesCallbackServer ?? false;
3982
+
3983
+ // Create login dialog component
3984
+ const dialog = new LoginDialogComponent(this.ui, providerId, (_success, _message) => {
3985
+ // Completion handled below
3986
+ });
3987
+
3988
+ // Show dialog in editor container
3989
+ this.editorContainer.clear();
3990
+ this.editorContainer.addChild(dialog);
3991
+ this.ui.setFocus(dialog);
3992
+ this.ui.requestRender();
3993
+
3994
+ // Restore editor helper — also disposes the dialog to reject any
3995
+ // dangling promises and prevent the UI from getting stuck.
3996
+ const restoreEditor = () => {
3997
+ dialog.dispose();
3998
+ this.editorContainer.clear();
3999
+ this.editorContainer.addChild(this.editor);
4000
+ this.ui.setFocus(this.editor);
4001
+ this.ui.requestRender();
4002
+ };
4003
+
4004
+ try {
4005
+ await this.session.modelRegistry.authStorage.login(providerId as OAuthProviderId, {
4006
+ onAuth: (info: { url: string; instructions?: string }) => {
4007
+ dialog.showAuth(info.url, info.instructions);
4008
+
4009
+ if (!usesCallbackServer && providerId === "github-copilot") {
4010
+ // GitHub Copilot polls after onAuth
4011
+ dialog.showWaiting("Waiting for browser authentication...");
4012
+ }
4013
+ // For Anthropic: onPrompt is called immediately after
4014
+ },
4015
+
4016
+ onPrompt: async (prompt: { message: string; placeholder?: string }) => {
4017
+ return dialog.showPrompt(prompt.message, prompt.placeholder);
4018
+ },
4019
+
4020
+ onProgress: (message: string) => {
4021
+ dialog.showProgress(message);
4022
+ },
4023
+
4024
+ // Callback-server providers race browser callback with pasted redirect URL.
4025
+ // Keep manual-input promise ownership inside provider flow to avoid
4026
+ // orphaned rejections when the callback is not consumed.
4027
+ onManualCodeInput: usesCallbackServer
4028
+ ? () => dialog.showManualInput("Paste redirect URL below, or complete login in browser:")
4029
+ : undefined,
4030
+
4031
+ signal: dialog.signal,
4032
+ });
4033
+
4034
+ // Success
4035
+ restoreEditor();
4036
+ this.session.modelRegistry.refresh();
4037
+ await this.updateAvailableProviderCount();
4038
+
4039
+ // Auto-switch model if current model has no valid API key
4040
+ try {
4041
+ const currentModel = this.session.model;
4042
+ if (currentModel) {
4043
+ const currentKey = await this.session.modelRegistry.getApiKey(currentModel);
4044
+ if (!currentKey) {
4045
+ const available = this.session.modelRegistry.getAvailable();
4046
+ const newProviderModel = available.find((m) => m.provider === providerId);
4047
+ if (newProviderModel) {
4048
+ await this.session.setModel(newProviderModel);
4049
+ } else if (available.length > 0) {
4050
+ await this.session.setModel(available[0]);
4051
+ }
4052
+ }
4053
+ }
4054
+ } catch (error: unknown) {
4055
+ // Model switch failed — user can manually switch via /model
4056
+ }
4057
+
4058
+ this.showStatus(`Logged in to ${providerName}. Credentials saved to ${getAuthPath()}`);
4059
+ } catch (error: unknown) {
4060
+ restoreEditor();
4061
+ const errorMsg = error instanceof Error ? error.message : String(error);
4062
+ if (errorMsg !== "Login cancelled" && !errorMsg.includes("Superseded") && !errorMsg.includes("disposed")) {
4063
+ this.showError(`Failed to login to ${providerName}: ${errorMsg}`);
4064
+ }
4065
+ }
4066
+ }
4067
+
4068
+ // =========================================================================
4069
+ // Command handlers
4070
+ // =========================================================================
4071
+
4072
+ private async handleReloadCommand(): Promise<void> {
4073
+ if (this.session.isStreaming) {
4074
+ this.showWarning("Wait for the current response to finish before reloading.");
4075
+ return;
4076
+ }
4077
+ if (this.session.isCompacting) {
4078
+ this.showWarning("Wait for compaction to finish before reloading.");
4079
+ return;
4080
+ }
4081
+
4082
+ this.resetExtensionUI();
4083
+
4084
+ const loader = new BorderedLoader(this.ui, theme, "Reloading extensions, skills, prompts, themes...", {
4085
+ cancellable: false,
4086
+ });
4087
+ const previousEditor = this.editor;
4088
+ this.editorContainer.clear();
4089
+ this.editorContainer.addChild(loader);
4090
+ this.ui.setFocus(loader);
4091
+ this.ui.requestRender();
4092
+
4093
+ const dismissLoader = (editor: Component) => {
4094
+ loader.dispose();
4095
+ this.editorContainer.clear();
4096
+ this.editorContainer.addChild(editor);
4097
+ this.ui.setFocus(editor);
4098
+ this.ui.requestRender();
4099
+ };
4100
+
4101
+ try {
4102
+ await this.session.reload();
4103
+ setRegisteredThemes(this.session.resourceLoader.getThemes().themes);
4104
+ this.hideThinkingBlock = this.settingsManager.getHideThinkingBlock();
4105
+ const themeName = this.settingsManager.getTheme();
4106
+ const themeResult = themeName ? setTheme(themeName, true) : { success: true };
4107
+ this.clearMarkdownThemeCache();
4108
+ if (!themeResult.success) {
4109
+ this.showError(`Failed to load theme "${themeName}": ${themeResult.error}\nFell back to dark theme.`);
4110
+ }
4111
+ const editorPaddingX = this.settingsManager.getEditorPaddingX();
4112
+ const autocompleteMaxVisible = this.settingsManager.getAutocompleteMaxVisible();
4113
+ this.defaultEditor.setPaddingX(editorPaddingX);
4114
+ this.defaultEditor.setAutocompleteMaxVisible(autocompleteMaxVisible);
4115
+ if (this.editor !== this.defaultEditor) {
4116
+ this.editor.setPaddingX?.(editorPaddingX);
4117
+ this.editor.setAutocompleteMaxVisible?.(autocompleteMaxVisible);
4118
+ }
4119
+ this.ui.setShowHardwareCursor(this.settingsManager.getShowHardwareCursor());
4120
+ this.ui.setClearOnShrink(this.settingsManager.getClearOnShrink());
4121
+ this.setupAutocomplete();
4122
+ const runner = this.session.extensionRunner;
4123
+ if (runner) {
4124
+ this.setupExtensionShortcuts(runner);
4125
+ }
4126
+ this.rebuildChatFromMessages();
4127
+ dismissLoader(this.editor as Component);
4128
+ this.showLoadedResources({
4129
+ extensionPaths: runner?.getExtensionPaths() ?? [],
4130
+ force: false,
4131
+ showDiagnosticsWhenQuiet: true,
4132
+ });
4133
+ const modelsJsonError = this.session.modelRegistry.getError();
4134
+ if (modelsJsonError) {
4135
+ this.showError(`models.json error: ${modelsJsonError}`);
4136
+ }
4137
+ this.showStatus("Reloaded extensions, skills, prompts, themes");
4138
+ } catch (error) {
4139
+ dismissLoader(previousEditor as Component);
4140
+ this.showError(`Reload failed: ${error instanceof Error ? error.message : String(error)}`);
4141
+ }
4142
+ }
4143
+
4144
+ private async handleClearCommand(): Promise<void> {
4145
+ // Stop loading animation
4146
+ if (this.loadingAnimation) {
4147
+ this.loadingAnimation.stop();
4148
+ this.loadingAnimation = undefined;
4149
+ }
4150
+ this.statusContainer.clear();
4151
+
4152
+ // New session via session (emits extension session events)
4153
+ await this.session.newSession();
4154
+
4155
+ // Clear UI state
4156
+ this.headerContainer.clear();
4157
+ this.chatContainer.clear();
4158
+ this.pendingMessagesContainer.clear();
4159
+ this.compactionQueuedMessages = [];
4160
+ this.streamingComponent = undefined;
4161
+ this.streamingMessage = undefined;
4162
+ this.pendingTools.clear();
4163
+ this.pendingImages.length = 0;
4164
+ this.clearBlockingError();
4165
+
4166
+ // Reset contextual tips for the new session
4167
+ this.contextualTips.reset();
4168
+
4169
+ this.chatContainer.addChild(new Spacer(1));
4170
+ this.chatContainer.addChild(new Text(`${theme.fg("accent", "✓ New session started")}`, 1, 1));
4171
+ this.ui.requestRender();
4172
+ }
4173
+
4174
+ private handleDebugCommand(): void {
4175
+ const width = this.ui.terminal.columns;
4176
+ const height = this.ui.terminal.rows;
4177
+ const allLines = this.ui.render(width);
4178
+
4179
+ const debugLogPath = getDebugLogPath();
4180
+ const debugData = [
4181
+ `Debug output at ${new Date().toISOString()}`,
4182
+ `Terminal: ${width}x${height}`,
4183
+ `Total lines: ${allLines.length}`,
4184
+ "",
4185
+ "=== All rendered lines with visible widths ===",
4186
+ ...allLines.map((line, idx) => {
4187
+ const vw = visibleWidth(line);
4188
+ const escaped = JSON.stringify(line);
4189
+ return `[${idx}] (w=${vw}) ${escaped}`;
4190
+ }),
4191
+ "",
4192
+ "=== Agent messages (JSONL) ===",
4193
+ ...this.session.messages.map((msg) => JSON.stringify(msg)),
4194
+ "",
4195
+ ].join("\n");
4196
+
4197
+ fs.mkdirSync(path.dirname(debugLogPath), { recursive: true });
4198
+ fs.writeFileSync(debugLogPath, debugData);
4199
+
4200
+ this.chatContainer.addChild(new Spacer(1));
4201
+ this.chatContainer.addChild(
4202
+ new Text(`${theme.fg("accent", "✓ Debug log written")}\n${theme.fg("muted", debugLogPath)}`, 1, 1),
4203
+ );
4204
+ this.ui.requestRender();
4205
+ }
4206
+
4207
+ private handleDaxnuts(): void {
4208
+ this.chatContainer.addChild(new Spacer(1));
4209
+ this.chatContainer.addChild(new DaxnutsComponent(this.ui));
4210
+ this.ui.requestRender();
4211
+ }
4212
+
4213
+ private checkDaxnutsEasterEgg(model: { provider: string; id: string }): void {
4214
+ if (model.provider === "opencode" && model.id.toLowerCase().includes("kimi-k2.5")) {
4215
+ this.handleDaxnuts();
4216
+ }
4217
+ }
4218
+
4219
+ private async handleBashCommand(command: string, excludeFromContext = false, displayCommand?: string, loginShell?: boolean): Promise<void> {
4220
+ const extensionRunner = this.session.extensionRunner;
4221
+ const label = displayCommand || command;
4222
+
4223
+ // Emit user_bash event to let extensions intercept
4224
+ const eventResult = extensionRunner
4225
+ ? await extensionRunner.emitUserBash({
4226
+ type: "user_bash",
4227
+ command,
4228
+ excludeFromContext,
4229
+ cwd: process.cwd(),
4230
+ })
4231
+ : undefined;
4232
+
4233
+ // If extension returned a full result, use it directly
4234
+ if (eventResult?.result) {
4235
+ const result = eventResult.result;
4236
+
4237
+ // Create UI component for display
4238
+ this.bashComponent = new BashExecutionComponent(label, this.ui, excludeFromContext);
4239
+ if (this.session.isStreaming) {
4240
+ this.pendingMessagesContainer.addChild(this.bashComponent);
4241
+ this.pendingBashComponents.push(this.bashComponent);
4242
+ } else {
4243
+ this.chatContainer.addChild(this.bashComponent);
4244
+ }
4245
+
4246
+ // Show output and complete
4247
+ if (result.output) {
4248
+ this.bashComponent.appendOutput(result.output);
4249
+ }
4250
+ this.bashComponent.setComplete(
4251
+ result.exitCode,
4252
+ result.cancelled,
4253
+ result.truncated ? ({ truncated: true, content: result.output } as TruncationResult) : undefined,
4254
+ result.fullOutputPath,
4255
+ );
4256
+
4257
+ // Record the result in session
4258
+ this.session.recordBashResult(command, result, { excludeFromContext });
4259
+ this.bashComponent = undefined;
4260
+ this.ui.requestRender();
4261
+ return;
4262
+ }
4263
+
4264
+ // Normal execution path (possibly with custom operations)
4265
+ const isDeferred = this.session.isStreaming;
4266
+ this.bashComponent = new BashExecutionComponent(label, this.ui, excludeFromContext);
4267
+
4268
+ if (isDeferred) {
4269
+ // Show in pending area when agent is streaming
4270
+ this.pendingMessagesContainer.addChild(this.bashComponent);
4271
+ this.pendingBashComponents.push(this.bashComponent);
4272
+ } else {
4273
+ // Show in chat immediately when agent is idle
4274
+ this.chatContainer.addChild(this.bashComponent);
4275
+ }
4276
+ this.ui.requestRender();
4277
+
4278
+ try {
4279
+ const result = await this.session.executeBash(
4280
+ command,
4281
+ (chunk) => {
4282
+ if (this.bashComponent) {
4283
+ this.bashComponent.appendOutput(chunk);
4284
+ this.ui.requestRender();
4285
+ }
4286
+ },
4287
+ { excludeFromContext, operations: eventResult?.operations, loginShell },
4288
+ );
4289
+
4290
+ if (this.bashComponent) {
4291
+ this.bashComponent.setComplete(
4292
+ result.exitCode,
4293
+ result.cancelled,
4294
+ result.truncated ? ({ truncated: true, content: result.output } as TruncationResult) : undefined,
4295
+ result.fullOutputPath,
4296
+ );
4297
+ }
4298
+ } catch (error) {
4299
+ if (this.bashComponent) {
4300
+ this.bashComponent.setComplete(undefined, false);
4301
+ }
4302
+ this.showError(`Bash command failed: ${error instanceof Error ? error.message : "Unknown error"}`);
4303
+ }
4304
+
4305
+ this.bashComponent = undefined;
4306
+ this.ui.requestRender();
4307
+ }
4308
+
4309
+ private async executeCompaction(customInstructions?: string, isAuto = false): Promise<CompactionResult | undefined> {
4310
+ // Stop loading animation
4311
+ if (this.loadingAnimation) {
4312
+ this.loadingAnimation.stop();
4313
+ this.loadingAnimation = undefined;
4314
+ }
4315
+ this.statusContainer.clear();
4316
+
4317
+ // Set up escape handler during compaction
4318
+ const originalOnEscape = this.defaultEditor.onEscape;
4319
+ this.defaultEditor.onEscape = () => {
4320
+ this.session.abortCompaction();
4321
+ };
4322
+
4323
+ // Show compacting status
4324
+ this.chatContainer.addChild(new Spacer(1));
4325
+ const cancelHint = `(${appKey(this.keybindings, "interrupt")} to cancel)`;
4326
+ const label = isAuto ? `Auto-compacting context... ${cancelHint}` : `Compacting context... ${cancelHint}`;
4327
+ const compactingLoader = new Loader(
4328
+ this.ui,
4329
+ (spinner) => theme.fg("accent", spinner),
4330
+ (text) => theme.fg("muted", text),
4331
+ label,
4332
+ );
4333
+ this.statusContainer.addChild(compactingLoader);
4334
+ this.ui.requestRender();
4335
+
4336
+ let result: CompactionResult | undefined;
4337
+
4338
+ try {
4339
+ result = await this.session.compact(customInstructions);
4340
+
4341
+ // Rebuild UI
4342
+ this.rebuildChatFromMessages();
4343
+
4344
+ // Add compaction component at bottom so user sees it without scrolling
4345
+ const msg = createCompactionSummaryMessage(result.summary, result.tokensBefore, new Date().toISOString());
4346
+ this.addMessageToChat(msg);
4347
+
4348
+ this.footer.invalidate();
4349
+ } catch (error) {
4350
+ const message = error instanceof Error ? error.message : String(error);
4351
+ if (message === "Compaction cancelled" || (error instanceof Error && error.name === "AbortError")) {
4352
+ this.showError("Compaction cancelled");
4353
+ } else {
4354
+ this.showError(`Compaction failed: ${message}`);
4355
+ }
4356
+ } finally {
4357
+ compactingLoader.stop();
4358
+ this.statusContainer.clear();
4359
+ this.defaultEditor.onEscape = originalOnEscape;
4360
+ }
4361
+ void this.flushCompactionQueue({ willRetry: false });
4362
+ return result;
4363
+ }
4364
+
4365
+ requestRender(force = false): void {
4366
+ if (!this.isInitialized) return;
4367
+ this.ui.requestRender(force);
4368
+ }
4369
+
4370
+ stop(): void {
4371
+ if (this.loadingAnimation) {
4372
+ this.loadingAnimation.stop();
4373
+ this.loadingAnimation = undefined;
4374
+ }
4375
+ this.clearExtensionTerminalInputListeners();
4376
+
4377
+ // Clean up branch change listener (Fix 1)
4378
+ this._branchChangeUnsub?.();
4379
+ this._branchChangeUnsub = undefined;
4380
+
4381
+ // Clean up theme change listener and watcher (Fix 2)
4382
+ this._themeChangeUnsub?.();
4383
+ this._themeChangeUnsub = undefined;
4384
+ stopThemeWatcher();
4385
+
4386
+ // Resolve any pending getUserInput promise so the run() loop can exit (Fix 3)
4387
+ if (this.onInputCallback) {
4388
+ this.onInputCallback("");
4389
+ this.onInputCallback = undefined;
4390
+ }
4391
+
4392
+ // Dispose extension widgets, custom footer, and custom header (Fix 4)
4393
+ this.clearExtensionWidgets();
4394
+ if (this.customFooter?.dispose) {
4395
+ this.customFooter.dispose();
4396
+ }
4397
+ this.customFooter = undefined;
4398
+ if (this.customHeader?.dispose) {
4399
+ this.customHeader.dispose();
4400
+ }
4401
+ this.customHeader = undefined;
4402
+ this.autocompleteProvider = undefined;
4403
+
4404
+ this.footer.dispose();
4405
+ this.footerDataProvider.dispose();
4406
+ if (this.unsubscribe) {
4407
+ this.unsubscribe();
4408
+ }
4409
+ if (this.stdinErrorHandler) {
4410
+ process.stdin.removeListener("error", this.stdinErrorHandler);
4411
+ this.stdinErrorHandler = undefined;
4412
+ }
4413
+ if (this.isInitialized) {
4414
+ this.ui.stop();
4415
+ this.isInitialized = false;
4416
+ }
4417
+ }
4418
+ }