pi-usereq 0.7.0 → 0.11.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 (773) hide show
  1. package/.gitignore +2 -0
  2. package/CHANGELOG.md +24 -0
  3. package/README.md +1 -1
  4. package/docs/pi.dev/coding-agent-docs/custom-provider.md +42 -1
  5. package/docs/pi.dev/coding-agent-docs/extensions.md +302 -28
  6. package/docs/pi.dev/coding-agent-docs/keybindings.md +23 -1
  7. package/docs/pi.dev/coding-agent-docs/models.md +3 -0
  8. package/docs/pi.dev/coding-agent-docs/packages.md +2 -2
  9. package/docs/pi.dev/coding-agent-docs/prompt-templates.md +21 -0
  10. package/docs/pi.dev/coding-agent-docs/providers.md +1 -0
  11. package/docs/pi.dev/coding-agent-docs/rpc.md +36 -6
  12. package/docs/pi.dev/coding-agent-docs/sdk.md +30 -5
  13. package/docs/pi.dev/coding-agent-docs/session.md +1 -1
  14. package/docs/pi.dev/coding-agent-docs/settings.md +2 -1
  15. package/docs/pi.dev/coding-agent-docs/skills.md +12 -12
  16. package/docs/pi.dev/coding-agent-docs/tree.md +2 -0
  17. package/docs/pi.dev/coding-agent-docs/tui.md +31 -0
  18. package/docs/pi.dev/mom-docs/new.md +4 -4
  19. package/package.json +1 -1
  20. package/pi-usereq/docs/REFERENCES.md +5214 -24470
  21. package/pi-usereq/docs/REQUIREMENTS.md +307 -170
  22. package/pi-usereq/docs/WORKFLOW.md +334 -316
  23. package/pi.dev-src/pi-mono/agent/src/agent-loop.ts +683 -0
  24. package/pi.dev-src/pi-mono/agent/src/agent.ts +543 -0
  25. package/pi.dev-src/pi-mono/agent/src/index.ts +8 -0
  26. package/pi.dev-src/pi-mono/agent/src/proxy.ts +367 -0
  27. package/pi.dev-src/pi-mono/agent/src/types.ts +364 -0
  28. package/pi.dev-src/pi-mono/agent/test/agent-loop.test.ts +1181 -0
  29. package/pi.dev-src/pi-mono/agent/test/agent.test.ts +463 -0
  30. package/pi.dev-src/pi-mono/agent/test/e2e.test.ts +404 -0
  31. package/pi.dev-src/pi-mono/agent/test/utils/calculate.ts +32 -0
  32. package/pi.dev-src/pi-mono/agent/test/utils/get-current-time.ts +46 -0
  33. package/pi.dev-src/pi-mono/agent/vitest.config.ts +9 -0
  34. package/pi.dev-src/pi-mono/ai/bedrock-provider.d.ts +1 -0
  35. package/pi.dev-src/pi-mono/ai/bedrock-provider.js +1 -0
  36. package/pi.dev-src/pi-mono/ai/scripts/generate-models.ts +1635 -0
  37. package/pi.dev-src/pi-mono/ai/scripts/generate-test-image.ts +34 -0
  38. package/pi.dev-src/pi-mono/ai/src/api-registry.ts +98 -0
  39. package/pi.dev-src/pi-mono/ai/src/bedrock-provider.ts +6 -0
  40. package/pi.dev-src/pi-mono/ai/src/cli.ts +133 -0
  41. package/pi.dev-src/pi-mono/ai/src/env-api-keys.ts +134 -0
  42. package/pi.dev-src/pi-mono/ai/src/index.ts +35 -0
  43. package/pi.dev-src/pi-mono/ai/src/models.generated.ts +14928 -0
  44. package/pi.dev-src/pi-mono/ai/src/models.ts +82 -0
  45. package/pi.dev-src/pi-mono/ai/src/oauth.ts +1 -0
  46. package/pi.dev-src/pi-mono/ai/src/providers/amazon-bedrock.ts +929 -0
  47. package/pi.dev-src/pi-mono/ai/src/providers/anthropic.ts +1125 -0
  48. package/pi.dev-src/pi-mono/ai/src/providers/azure-openai-responses.ts +253 -0
  49. package/pi.dev-src/pi-mono/ai/src/providers/faux.ts +499 -0
  50. package/pi.dev-src/pi-mono/ai/src/providers/github-copilot-headers.ts +37 -0
  51. package/pi.dev-src/pi-mono/ai/src/providers/google-gemini-cli.ts +996 -0
  52. package/pi.dev-src/pi-mono/ai/src/providers/google-shared.ts +354 -0
  53. package/pi.dev-src/pi-mono/ai/src/providers/google-vertex.ts +543 -0
  54. package/pi.dev-src/pi-mono/ai/src/providers/google.ts +500 -0
  55. package/pi.dev-src/pi-mono/ai/src/providers/mistral.ts +629 -0
  56. package/pi.dev-src/pi-mono/ai/src/providers/openai-codex-responses.ts +984 -0
  57. package/pi.dev-src/pi-mono/ai/src/providers/openai-completions.ts +1063 -0
  58. package/pi.dev-src/pi-mono/ai/src/providers/openai-responses-shared.ts +539 -0
  59. package/pi.dev-src/pi-mono/ai/src/providers/openai-responses.ts +264 -0
  60. package/pi.dev-src/pi-mono/ai/src/providers/register-builtins.ts +433 -0
  61. package/pi.dev-src/pi-mono/ai/src/providers/simple-options.ts +47 -0
  62. package/pi.dev-src/pi-mono/ai/src/providers/transform-messages.ts +220 -0
  63. package/pi.dev-src/pi-mono/ai/src/stream.ts +59 -0
  64. package/pi.dev-src/pi-mono/ai/src/types.ts +417 -0
  65. package/pi.dev-src/pi-mono/ai/src/utils/event-stream.ts +87 -0
  66. package/pi.dev-src/pi-mono/ai/src/utils/hash.ts +13 -0
  67. package/pi.dev-src/pi-mono/ai/src/utils/headers.ts +7 -0
  68. package/pi.dev-src/pi-mono/ai/src/utils/json-parse.ts +124 -0
  69. package/pi.dev-src/pi-mono/ai/src/utils/overflow.ts +138 -0
  70. package/pi.dev-src/pi-mono/ai/src/utils/sanitize-unicode.ts +25 -0
  71. package/pi.dev-src/pi-mono/ai/src/utils/typebox-helpers.ts +24 -0
  72. package/pi.dev-src/pi-mono/ai/src/utils/validation.ts +324 -0
  73. package/pi.dev-src/pi-mono/ai/test/abort.test.ts +260 -0
  74. package/pi.dev-src/pi-mono/ai/test/anthropic-oauth.test.ts +99 -0
  75. package/pi.dev-src/pi-mono/ai/test/anthropic-opus-4-7-smoke.test.ts +72 -0
  76. package/pi.dev-src/pi-mono/ai/test/anthropic-sse-parsing.test.ts +113 -0
  77. package/pi.dev-src/pi-mono/ai/test/anthropic-thinking-disable.test.ts +152 -0
  78. package/pi.dev-src/pi-mono/ai/test/anthropic-tool-name-normalization.test.ts +205 -0
  79. package/pi.dev-src/pi-mono/ai/test/azure-utils.ts +28 -0
  80. package/pi.dev-src/pi-mono/ai/test/bedrock-endpoint-resolution.test.ts +131 -0
  81. package/pi.dev-src/pi-mono/ai/test/bedrock-models.test.ts +66 -0
  82. package/pi.dev-src/pi-mono/ai/test/bedrock-thinking-payload.test.ts +107 -0
  83. package/pi.dev-src/pi-mono/ai/test/bedrock-utils.ts +18 -0
  84. package/pi.dev-src/pi-mono/ai/test/cache-retention.test.ts +335 -0
  85. package/pi.dev-src/pi-mono/ai/test/context-overflow.test.ts +714 -0
  86. package/pi.dev-src/pi-mono/ai/test/cross-provider-handoff.test.ts +458 -0
  87. package/pi.dev-src/pi-mono/ai/test/data/red-circle.png +0 -0
  88. package/pi.dev-src/pi-mono/ai/test/empty.test.ts +742 -0
  89. package/pi.dev-src/pi-mono/ai/test/faux-provider.test.ts +597 -0
  90. package/pi.dev-src/pi-mono/ai/test/fireworks-models.test.ts +49 -0
  91. package/pi.dev-src/pi-mono/ai/test/github-copilot-anthropic.test.ts +108 -0
  92. package/pi.dev-src/pi-mono/ai/test/github-copilot-oauth.test.ts +196 -0
  93. package/pi.dev-src/pi-mono/ai/test/google-gemini-cli-claude-thinking-header.test.ts +103 -0
  94. package/pi.dev-src/pi-mono/ai/test/google-gemini-cli-empty-stream.test.ts +108 -0
  95. package/pi.dev-src/pi-mono/ai/test/google-gemini-cli-retry-delay.test.ts +53 -0
  96. package/pi.dev-src/pi-mono/ai/test/google-shared-convert-tools.test.ts +187 -0
  97. package/pi.dev-src/pi-mono/ai/test/google-shared-gemini3-unsigned-tool-call.test.ts +172 -0
  98. package/pi.dev-src/pi-mono/ai/test/google-shared-image-tool-result-routing.test.ts +124 -0
  99. package/pi.dev-src/pi-mono/ai/test/google-thinking-disable.test.ts +183 -0
  100. package/pi.dev-src/pi-mono/ai/test/google-thinking-signature.test.ts +38 -0
  101. package/pi.dev-src/pi-mono/ai/test/google-tool-call-missing-args.test.ts +105 -0
  102. package/pi.dev-src/pi-mono/ai/test/google-vertex-api-key-resolution.test.ts +144 -0
  103. package/pi.dev-src/pi-mono/ai/test/image-tool-result.test.ts +481 -0
  104. package/pi.dev-src/pi-mono/ai/test/interleaved-thinking.test.ts +145 -0
  105. package/pi.dev-src/pi-mono/ai/test/lazy-module-load.test.ts +102 -0
  106. package/pi.dev-src/pi-mono/ai/test/mistral-reasoning-mode.test.ts +66 -0
  107. package/pi.dev-src/pi-mono/ai/test/mistral-tool-schema.test.ts +61 -0
  108. package/pi.dev-src/pi-mono/ai/test/oauth.ts +89 -0
  109. package/pi.dev-src/pi-mono/ai/test/openai-codex-cache-affinity-e2e.test.ts +36 -0
  110. package/pi.dev-src/pi-mono/ai/test/openai-codex-stream.test.ts +686 -0
  111. package/pi.dev-src/pi-mono/ai/test/openai-completions-cache-control-format.test.ts +189 -0
  112. package/pi.dev-src/pi-mono/ai/test/openai-completions-prompt-cache.test.ts +198 -0
  113. package/pi.dev-src/pi-mono/ai/test/openai-completions-thinking-as-text.test.ts +214 -0
  114. package/pi.dev-src/pi-mono/ai/test/openai-completions-tool-choice.test.ts +560 -0
  115. package/pi.dev-src/pi-mono/ai/test/openai-completions-tool-result-images.test.ts +101 -0
  116. package/pi.dev-src/pi-mono/ai/test/openai-responses-cache-affinity-e2e.test.ts +32 -0
  117. package/pi.dev-src/pi-mono/ai/test/openai-responses-copilot-provider.test.ts +128 -0
  118. package/pi.dev-src/pi-mono/ai/test/openai-responses-foreign-toolcall-id.test.ts +66 -0
  119. package/pi.dev-src/pi-mono/ai/test/openai-responses-partial-json-cleanup.test.ts +101 -0
  120. package/pi.dev-src/pi-mono/ai/test/openai-responses-reasoning-replay-e2e.test.ts +292 -0
  121. package/pi.dev-src/pi-mono/ai/test/openai-responses-tool-result-images.test.ts +200 -0
  122. package/pi.dev-src/pi-mono/ai/test/openrouter-cache-write-repro.test.ts +78 -0
  123. package/pi.dev-src/pi-mono/ai/test/overflow.test.ts +64 -0
  124. package/pi.dev-src/pi-mono/ai/test/responseid.test.ts +145 -0
  125. package/pi.dev-src/pi-mono/ai/test/stream.test.ts +1405 -0
  126. package/pi.dev-src/pi-mono/ai/test/supports-xhigh.test.ts +34 -0
  127. package/pi.dev-src/pi-mono/ai/test/tokens.test.ts +304 -0
  128. package/pi.dev-src/pi-mono/ai/test/tool-call-id-normalization.test.ts +291 -0
  129. package/pi.dev-src/pi-mono/ai/test/tool-call-without-result.test.ts +313 -0
  130. package/pi.dev-src/pi-mono/ai/test/total-tokens.test.ts +695 -0
  131. package/pi.dev-src/pi-mono/ai/test/transform-messages-copilot-openai-to-anthropic.test.ts +191 -0
  132. package/pi.dev-src/pi-mono/ai/test/unicode-surrogate.test.ts +754 -0
  133. package/pi.dev-src/pi-mono/ai/test/validation.test.ts +116 -0
  134. package/pi.dev-src/pi-mono/ai/test/xhigh.test.ts +71 -0
  135. package/pi.dev-src/pi-mono/ai/test/zen.test.ts +25 -0
  136. package/pi.dev-src/pi-mono/ai/vitest.config.ts +9 -0
  137. package/pi.dev-src/pi-mono/coding-agent/examples/extensions/antigravity-image-gen.ts +418 -0
  138. package/pi.dev-src/pi-mono/coding-agent/examples/extensions/auto-commit-on-exit.ts +49 -0
  139. package/pi.dev-src/pi-mono/coding-agent/examples/extensions/bash-spawn-hook.ts +30 -0
  140. package/pi.dev-src/pi-mono/coding-agent/examples/extensions/bookmark.ts +50 -0
  141. package/pi.dev-src/pi-mono/coding-agent/examples/extensions/built-in-tool-renderer.ts +249 -0
  142. package/pi.dev-src/pi-mono/coding-agent/examples/extensions/claude-rules.ts +86 -0
  143. package/pi.dev-src/pi-mono/coding-agent/examples/extensions/commands.ts +72 -0
  144. package/pi.dev-src/pi-mono/coding-agent/examples/extensions/confirm-destructive.ts +59 -0
  145. package/pi.dev-src/pi-mono/coding-agent/examples/extensions/custom-compaction.ts +127 -0
  146. package/pi.dev-src/pi-mono/coding-agent/examples/extensions/custom-footer.ts +64 -0
  147. package/pi.dev-src/pi-mono/coding-agent/examples/extensions/custom-header.ts +73 -0
  148. package/pi.dev-src/pi-mono/coding-agent/examples/extensions/custom-provider-anthropic/index.ts +604 -0
  149. package/pi.dev-src/pi-mono/coding-agent/examples/extensions/custom-provider-anthropic/package-lock.json +24 -0
  150. package/pi.dev-src/pi-mono/coding-agent/examples/extensions/custom-provider-gitlab-duo/index.ts +349 -0
  151. package/pi.dev-src/pi-mono/coding-agent/examples/extensions/custom-provider-gitlab-duo/test.ts +82 -0
  152. package/pi.dev-src/pi-mono/coding-agent/examples/extensions/custom-provider-qwen-cli/index.ts +345 -0
  153. package/pi.dev-src/pi-mono/coding-agent/examples/extensions/dirty-repo-guard.ts +56 -0
  154. package/pi.dev-src/pi-mono/coding-agent/examples/extensions/doom-overlay/doom/build.sh +152 -0
  155. package/pi.dev-src/pi-mono/coding-agent/examples/extensions/doom-overlay/doom/doomgeneric_pi.c +72 -0
  156. package/pi.dev-src/pi-mono/coding-agent/examples/extensions/doom-overlay/doom-component.ts +132 -0
  157. package/pi.dev-src/pi-mono/coding-agent/examples/extensions/doom-overlay/doom-engine.ts +173 -0
  158. package/pi.dev-src/pi-mono/coding-agent/examples/extensions/doom-overlay/doom-keys.ts +104 -0
  159. package/pi.dev-src/pi-mono/coding-agent/examples/extensions/doom-overlay/index.ts +74 -0
  160. package/pi.dev-src/pi-mono/coding-agent/examples/extensions/doom-overlay/wad-finder.ts +51 -0
  161. package/pi.dev-src/pi-mono/coding-agent/examples/extensions/dynamic-resources/SKILL.md +8 -0
  162. package/pi.dev-src/pi-mono/coding-agent/examples/extensions/dynamic-resources/dynamic.json +79 -0
  163. package/pi.dev-src/pi-mono/coding-agent/examples/extensions/dynamic-resources/dynamic.md +5 -0
  164. package/pi.dev-src/pi-mono/coding-agent/examples/extensions/dynamic-resources/index.ts +15 -0
  165. package/pi.dev-src/pi-mono/coding-agent/examples/extensions/dynamic-tools.ts +74 -0
  166. package/pi.dev-src/pi-mono/coding-agent/examples/extensions/event-bus.ts +43 -0
  167. package/pi.dev-src/pi-mono/coding-agent/examples/extensions/file-trigger.ts +41 -0
  168. package/pi.dev-src/pi-mono/coding-agent/examples/extensions/git-checkpoint.ts +53 -0
  169. package/pi.dev-src/pi-mono/coding-agent/examples/extensions/github-issue-autocomplete.ts +185 -0
  170. package/pi.dev-src/pi-mono/coding-agent/examples/extensions/handoff.ts +153 -0
  171. package/pi.dev-src/pi-mono/coding-agent/examples/extensions/hello.ts +26 -0
  172. package/pi.dev-src/pi-mono/coding-agent/examples/extensions/hidden-thinking-label.ts +53 -0
  173. package/pi.dev-src/pi-mono/coding-agent/examples/extensions/inline-bash.ts +94 -0
  174. package/pi.dev-src/pi-mono/coding-agent/examples/extensions/input-transform.ts +43 -0
  175. package/pi.dev-src/pi-mono/coding-agent/examples/extensions/interactive-shell.ts +196 -0
  176. package/pi.dev-src/pi-mono/coding-agent/examples/extensions/mac-system-theme.ts +47 -0
  177. package/pi.dev-src/pi-mono/coding-agent/examples/extensions/message-renderer.ts +59 -0
  178. package/pi.dev-src/pi-mono/coding-agent/examples/extensions/minimal-mode.ts +426 -0
  179. package/pi.dev-src/pi-mono/coding-agent/examples/extensions/modal-editor.ts +85 -0
  180. package/pi.dev-src/pi-mono/coding-agent/examples/extensions/model-status.ts +31 -0
  181. package/pi.dev-src/pi-mono/coding-agent/examples/extensions/notify.ts +55 -0
  182. package/pi.dev-src/pi-mono/coding-agent/examples/extensions/overlay-qa-tests.ts +1348 -0
  183. package/pi.dev-src/pi-mono/coding-agent/examples/extensions/overlay-test.ts +150 -0
  184. package/pi.dev-src/pi-mono/coding-agent/examples/extensions/permission-gate.ts +34 -0
  185. package/pi.dev-src/pi-mono/coding-agent/examples/extensions/pirate.ts +47 -0
  186. package/pi.dev-src/pi-mono/coding-agent/examples/extensions/plan-mode/index.ts +340 -0
  187. package/pi.dev-src/pi-mono/coding-agent/examples/extensions/plan-mode/utils.ts +168 -0
  188. package/pi.dev-src/pi-mono/coding-agent/examples/extensions/preset.ts +430 -0
  189. package/pi.dev-src/pi-mono/coding-agent/examples/extensions/prompt-customizer.ts +97 -0
  190. package/pi.dev-src/pi-mono/coding-agent/examples/extensions/protected-paths.ts +30 -0
  191. package/pi.dev-src/pi-mono/coding-agent/examples/extensions/provider-payload.ts +18 -0
  192. package/pi.dev-src/pi-mono/coding-agent/examples/extensions/qna.ts +122 -0
  193. package/pi.dev-src/pi-mono/coding-agent/examples/extensions/question.ts +264 -0
  194. package/pi.dev-src/pi-mono/coding-agent/examples/extensions/questionnaire.ts +427 -0
  195. package/pi.dev-src/pi-mono/coding-agent/examples/extensions/rainbow-editor.ts +88 -0
  196. package/pi.dev-src/pi-mono/coding-agent/examples/extensions/reload-runtime.ts +37 -0
  197. package/pi.dev-src/pi-mono/coding-agent/examples/extensions/rpc-demo.ts +118 -0
  198. package/pi.dev-src/pi-mono/coding-agent/examples/extensions/sandbox/index.ts +321 -0
  199. package/pi.dev-src/pi-mono/coding-agent/examples/extensions/sandbox/package-lock.json +92 -0
  200. package/pi.dev-src/pi-mono/coding-agent/examples/extensions/send-user-message.ts +97 -0
  201. package/pi.dev-src/pi-mono/coding-agent/examples/extensions/session-name.ts +27 -0
  202. package/pi.dev-src/pi-mono/coding-agent/examples/extensions/shutdown-command.ts +63 -0
  203. package/pi.dev-src/pi-mono/coding-agent/examples/extensions/snake.ts +343 -0
  204. package/pi.dev-src/pi-mono/coding-agent/examples/extensions/space-invaders.ts +560 -0
  205. package/pi.dev-src/pi-mono/coding-agent/examples/extensions/ssh.ts +220 -0
  206. package/pi.dev-src/pi-mono/coding-agent/examples/extensions/status-line.ts +32 -0
  207. package/pi.dev-src/pi-mono/coding-agent/examples/extensions/structured-output.ts +65 -0
  208. package/pi.dev-src/pi-mono/coding-agent/examples/extensions/subagent/agents/planner.md +37 -0
  209. package/pi.dev-src/pi-mono/coding-agent/examples/extensions/subagent/agents/reviewer.md +35 -0
  210. package/pi.dev-src/pi-mono/coding-agent/examples/extensions/subagent/agents/scout.md +50 -0
  211. package/pi.dev-src/pi-mono/coding-agent/examples/extensions/subagent/agents/worker.md +24 -0
  212. package/pi.dev-src/pi-mono/coding-agent/examples/extensions/subagent/agents.ts +126 -0
  213. package/pi.dev-src/pi-mono/coding-agent/examples/extensions/subagent/index.ts +987 -0
  214. package/pi.dev-src/pi-mono/coding-agent/examples/extensions/subagent/prompts/implement-and-review.md +10 -0
  215. package/pi.dev-src/pi-mono/coding-agent/examples/extensions/subagent/prompts/implement.md +10 -0
  216. package/pi.dev-src/pi-mono/coding-agent/examples/extensions/subagent/prompts/scout-and-plan.md +9 -0
  217. package/pi.dev-src/pi-mono/coding-agent/examples/extensions/summarize.ts +206 -0
  218. package/pi.dev-src/pi-mono/coding-agent/examples/extensions/system-prompt-header.ts +17 -0
  219. package/pi.dev-src/pi-mono/coding-agent/examples/extensions/tic-tac-toe.ts +1008 -0
  220. package/pi.dev-src/pi-mono/coding-agent/examples/extensions/timed-confirm.ts +70 -0
  221. package/pi.dev-src/pi-mono/coding-agent/examples/extensions/titlebar-spinner.ts +58 -0
  222. package/pi.dev-src/pi-mono/coding-agent/examples/extensions/todo.ts +297 -0
  223. package/pi.dev-src/pi-mono/coding-agent/examples/extensions/tool-override.ts +144 -0
  224. package/pi.dev-src/pi-mono/coding-agent/examples/extensions/tools.ts +141 -0
  225. package/pi.dev-src/pi-mono/coding-agent/examples/extensions/trigger-compact.ts +50 -0
  226. package/pi.dev-src/pi-mono/coding-agent/examples/extensions/truncated-tool.ts +195 -0
  227. package/pi.dev-src/pi-mono/coding-agent/examples/extensions/widget-placement.ts +9 -0
  228. package/pi.dev-src/pi-mono/coding-agent/examples/extensions/with-deps/index.ts +32 -0
  229. package/pi.dev-src/pi-mono/coding-agent/examples/extensions/with-deps/package-lock.json +31 -0
  230. package/pi.dev-src/pi-mono/coding-agent/examples/extensions/working-indicator.ts +123 -0
  231. package/pi.dev-src/pi-mono/coding-agent/examples/extensions/working-message-test.ts +25 -0
  232. package/pi.dev-src/pi-mono/coding-agent/examples/rpc-extension-ui.ts +632 -0
  233. package/pi.dev-src/pi-mono/coding-agent/examples/sdk/01-minimal.ts +22 -0
  234. package/pi.dev-src/pi-mono/coding-agent/examples/sdk/02-custom-model.ts +49 -0
  235. package/pi.dev-src/pi-mono/coding-agent/examples/sdk/03-custom-prompt.ts +62 -0
  236. package/pi.dev-src/pi-mono/coding-agent/examples/sdk/04-skills.ts +55 -0
  237. package/pi.dev-src/pi-mono/coding-agent/examples/sdk/05-tools.ts +44 -0
  238. package/pi.dev-src/pi-mono/coding-agent/examples/sdk/06-extensions.ts +90 -0
  239. package/pi.dev-src/pi-mono/coding-agent/examples/sdk/07-context-files.ts +42 -0
  240. package/pi.dev-src/pi-mono/coding-agent/examples/sdk/08-prompt-templates.ts +51 -0
  241. package/pi.dev-src/pi-mono/coding-agent/examples/sdk/09-api-keys-and-oauth.ts +48 -0
  242. package/pi.dev-src/pi-mono/coding-agent/examples/sdk/10-settings.ts +53 -0
  243. package/pi.dev-src/pi-mono/coding-agent/examples/sdk/11-sessions.ts +48 -0
  244. package/pi.dev-src/pi-mono/coding-agent/examples/sdk/12-full-control.ts +73 -0
  245. package/pi.dev-src/pi-mono/coding-agent/examples/sdk/13-session-runtime.ts +67 -0
  246. package/pi.dev-src/pi-mono/coding-agent/scripts/migrate-sessions.sh +93 -0
  247. package/pi.dev-src/pi-mono/coding-agent/src/bun/cli.ts +6 -0
  248. package/pi.dev-src/pi-mono/coding-agent/src/bun/register-bedrock.ts +4 -0
  249. package/pi.dev-src/pi-mono/coding-agent/src/cli/args.ts +335 -0
  250. package/pi.dev-src/pi-mono/coding-agent/src/cli/config-selector.ts +52 -0
  251. package/pi.dev-src/pi-mono/coding-agent/src/cli/file-processor.ts +100 -0
  252. package/pi.dev-src/pi-mono/coding-agent/src/cli/initial-message.ts +43 -0
  253. package/pi.dev-src/pi-mono/coding-agent/src/cli/list-models.ts +110 -0
  254. package/pi.dev-src/pi-mono/coding-agent/src/cli/session-picker.ts +52 -0
  255. package/pi.dev-src/pi-mono/coding-agent/src/cli.ts +17 -0
  256. package/pi.dev-src/pi-mono/coding-agent/src/config.ts +261 -0
  257. package/pi.dev-src/pi-mono/coding-agent/src/core/agent-session-runtime.ts +394 -0
  258. package/pi.dev-src/pi-mono/coding-agent/src/core/agent-session-services.ts +196 -0
  259. package/pi.dev-src/pi-mono/coding-agent/src/core/agent-session.ts +3096 -0
  260. package/pi.dev-src/pi-mono/coding-agent/src/core/auth-storage.ts +493 -0
  261. package/pi.dev-src/pi-mono/coding-agent/src/core/bash-executor.ts +154 -0
  262. package/pi.dev-src/pi-mono/coding-agent/src/core/compaction/branch-summarization.ts +355 -0
  263. package/pi.dev-src/pi-mono/coding-agent/src/core/compaction/compaction.ts +839 -0
  264. package/pi.dev-src/pi-mono/coding-agent/src/core/compaction/index.ts +7 -0
  265. package/pi.dev-src/pi-mono/coding-agent/src/core/compaction/utils.ts +170 -0
  266. package/pi.dev-src/pi-mono/coding-agent/src/core/defaults.ts +3 -0
  267. package/pi.dev-src/pi-mono/coding-agent/src/core/diagnostics.ts +15 -0
  268. package/pi.dev-src/pi-mono/coding-agent/src/core/event-bus.ts +33 -0
  269. package/pi.dev-src/pi-mono/coding-agent/src/core/exec.ts +107 -0
  270. package/pi.dev-src/pi-mono/coding-agent/src/core/export-html/ansi-to-html.ts +258 -0
  271. package/pi.dev-src/pi-mono/coding-agent/src/core/export-html/index.ts +314 -0
  272. package/pi.dev-src/pi-mono/coding-agent/src/core/export-html/template.css +1017 -0
  273. package/pi.dev-src/pi-mono/coding-agent/src/core/export-html/template.html +55 -0
  274. package/pi.dev-src/pi-mono/coding-agent/src/core/export-html/template.js +1770 -0
  275. package/pi.dev-src/pi-mono/coding-agent/src/core/export-html/tool-renderer.ts +158 -0
  276. package/pi.dev-src/pi-mono/coding-agent/src/core/export-html/vendor/highlight.min.js +1213 -0
  277. package/pi.dev-src/pi-mono/coding-agent/src/core/export-html/vendor/marked.min.js +6 -0
  278. package/pi.dev-src/pi-mono/coding-agent/src/core/extensions/index.ts +171 -0
  279. package/pi.dev-src/pi-mono/coding-agent/src/core/extensions/loader.ts +606 -0
  280. package/pi.dev-src/pi-mono/coding-agent/src/core/extensions/runner.ts +1019 -0
  281. package/pi.dev-src/pi-mono/coding-agent/src/core/extensions/types.ts +1542 -0
  282. package/pi.dev-src/pi-mono/coding-agent/src/core/extensions/wrapper.ts +30 -0
  283. package/pi.dev-src/pi-mono/coding-agent/src/core/footer-data-provider.ts +354 -0
  284. package/pi.dev-src/pi-mono/coding-agent/src/core/index.ts +77 -0
  285. package/pi.dev-src/pi-mono/coding-agent/src/core/keybindings.ts +370 -0
  286. package/pi.dev-src/pi-mono/coding-agent/src/core/messages.ts +195 -0
  287. package/pi.dev-src/pi-mono/coding-agent/src/core/model-registry.ts +858 -0
  288. package/pi.dev-src/pi-mono/coding-agent/src/core/model-resolver.ts +629 -0
  289. package/pi.dev-src/pi-mono/coding-agent/src/core/output-guard.ts +74 -0
  290. package/pi.dev-src/pi-mono/coding-agent/src/core/package-manager.ts +2408 -0
  291. package/pi.dev-src/pi-mono/coding-agent/src/core/prompt-templates.ts +296 -0
  292. package/pi.dev-src/pi-mono/coding-agent/src/core/resolve-config-value.ts +142 -0
  293. package/pi.dev-src/pi-mono/coding-agent/src/core/resource-loader.ts +917 -0
  294. package/pi.dev-src/pi-mono/coding-agent/src/core/sdk.ts +380 -0
  295. package/pi.dev-src/pi-mono/coding-agent/src/core/session-cwd.ts +59 -0
  296. package/pi.dev-src/pi-mono/coding-agent/src/core/session-manager.ts +1425 -0
  297. package/pi.dev-src/pi-mono/coding-agent/src/core/settings-manager.ts +999 -0
  298. package/pi.dev-src/pi-mono/coding-agent/src/core/skills.ts +508 -0
  299. package/pi.dev-src/pi-mono/coding-agent/src/core/slash-commands.ts +39 -0
  300. package/pi.dev-src/pi-mono/coding-agent/src/core/source-info.ts +40 -0
  301. package/pi.dev-src/pi-mono/coding-agent/src/core/system-prompt.ts +172 -0
  302. package/pi.dev-src/pi-mono/coding-agent/src/core/telemetry.ts +13 -0
  303. package/pi.dev-src/pi-mono/coding-agent/src/core/timings.ts +31 -0
  304. package/pi.dev-src/pi-mono/coding-agent/src/core/tools/bash.ts +448 -0
  305. package/pi.dev-src/pi-mono/coding-agent/src/core/tools/edit-diff.ts +445 -0
  306. package/pi.dev-src/pi-mono/coding-agent/src/core/tools/edit.ts +487 -0
  307. package/pi.dev-src/pi-mono/coding-agent/src/core/tools/file-mutation-queue.ts +39 -0
  308. package/pi.dev-src/pi-mono/coding-agent/src/core/tools/find.ts +370 -0
  309. package/pi.dev-src/pi-mono/coding-agent/src/core/tools/grep.ts +384 -0
  310. package/pi.dev-src/pi-mono/coding-agent/src/core/tools/index.ts +196 -0
  311. package/pi.dev-src/pi-mono/coding-agent/src/core/tools/ls.ts +229 -0
  312. package/pi.dev-src/pi-mono/coding-agent/src/core/tools/path-utils.ts +94 -0
  313. package/pi.dev-src/pi-mono/coding-agent/src/core/tools/read.ts +273 -0
  314. package/pi.dev-src/pi-mono/coding-agent/src/core/tools/render-utils.ts +64 -0
  315. package/pi.dev-src/pi-mono/coding-agent/src/core/tools/tool-definition-wrapper.ts +45 -0
  316. package/pi.dev-src/pi-mono/coding-agent/src/core/tools/truncate.ts +265 -0
  317. package/pi.dev-src/pi-mono/coding-agent/src/core/tools/write.ts +281 -0
  318. package/pi.dev-src/pi-mono/coding-agent/src/index.ts +352 -0
  319. package/pi.dev-src/pi-mono/coding-agent/src/main.ts +731 -0
  320. package/pi.dev-src/pi-mono/coding-agent/src/migrations.ts +314 -0
  321. package/pi.dev-src/pi-mono/coding-agent/src/modes/index.ts +9 -0
  322. package/pi.dev-src/pi-mono/coding-agent/src/modes/interactive/assets/clankolas.png +0 -0
  323. package/pi.dev-src/pi-mono/coding-agent/src/modes/interactive/components/armin.ts +382 -0
  324. package/pi.dev-src/pi-mono/coding-agent/src/modes/interactive/components/assistant-message.ts +147 -0
  325. package/pi.dev-src/pi-mono/coding-agent/src/modes/interactive/components/bash-execution.ts +218 -0
  326. package/pi.dev-src/pi-mono/coding-agent/src/modes/interactive/components/bordered-loader.ts +68 -0
  327. package/pi.dev-src/pi-mono/coding-agent/src/modes/interactive/components/branch-summary-message.ts +58 -0
  328. package/pi.dev-src/pi-mono/coding-agent/src/modes/interactive/components/compaction-summary-message.ts +59 -0
  329. package/pi.dev-src/pi-mono/coding-agent/src/modes/interactive/components/config-selector.ts +592 -0
  330. package/pi.dev-src/pi-mono/coding-agent/src/modes/interactive/components/countdown-timer.ts +38 -0
  331. package/pi.dev-src/pi-mono/coding-agent/src/modes/interactive/components/custom-editor.ts +80 -0
  332. package/pi.dev-src/pi-mono/coding-agent/src/modes/interactive/components/custom-message.ts +99 -0
  333. package/pi.dev-src/pi-mono/coding-agent/src/modes/interactive/components/daxnuts.ts +164 -0
  334. package/pi.dev-src/pi-mono/coding-agent/src/modes/interactive/components/diff.ts +147 -0
  335. package/pi.dev-src/pi-mono/coding-agent/src/modes/interactive/components/dynamic-border.ts +25 -0
  336. package/pi.dev-src/pi-mono/coding-agent/src/modes/interactive/components/earendil-announcement.ts +53 -0
  337. package/pi.dev-src/pi-mono/coding-agent/src/modes/interactive/components/extension-editor.ts +147 -0
  338. package/pi.dev-src/pi-mono/coding-agent/src/modes/interactive/components/extension-input.ts +87 -0
  339. package/pi.dev-src/pi-mono/coding-agent/src/modes/interactive/components/extension-selector.ts +107 -0
  340. package/pi.dev-src/pi-mono/coding-agent/src/modes/interactive/components/footer.ts +220 -0
  341. package/pi.dev-src/pi-mono/coding-agent/src/modes/interactive/components/index.ts +32 -0
  342. package/pi.dev-src/pi-mono/coding-agent/src/modes/interactive/components/keybinding-hints.ts +24 -0
  343. package/pi.dev-src/pi-mono/coding-agent/src/modes/interactive/components/login-dialog.ts +178 -0
  344. package/pi.dev-src/pi-mono/coding-agent/src/modes/interactive/components/model-selector.ts +338 -0
  345. package/pi.dev-src/pi-mono/coding-agent/src/modes/interactive/components/oauth-selector.ts +121 -0
  346. package/pi.dev-src/pi-mono/coding-agent/src/modes/interactive/components/scoped-models-selector.ts +355 -0
  347. package/pi.dev-src/pi-mono/coding-agent/src/modes/interactive/components/session-selector-search.ts +194 -0
  348. package/pi.dev-src/pi-mono/coding-agent/src/modes/interactive/components/session-selector.ts +1026 -0
  349. package/pi.dev-src/pi-mono/coding-agent/src/modes/interactive/components/settings-selector.ts +456 -0
  350. package/pi.dev-src/pi-mono/coding-agent/src/modes/interactive/components/show-images-selector.ts +50 -0
  351. package/pi.dev-src/pi-mono/coding-agent/src/modes/interactive/components/skill-invocation-message.ts +55 -0
  352. package/pi.dev-src/pi-mono/coding-agent/src/modes/interactive/components/theme-selector.ts +67 -0
  353. package/pi.dev-src/pi-mono/coding-agent/src/modes/interactive/components/thinking-selector.ts +74 -0
  354. package/pi.dev-src/pi-mono/coding-agent/src/modes/interactive/components/tool-execution.ts +352 -0
  355. package/pi.dev-src/pi-mono/coding-agent/src/modes/interactive/components/tree-selector.ts +1246 -0
  356. package/pi.dev-src/pi-mono/coding-agent/src/modes/interactive/components/user-message-selector.ts +155 -0
  357. package/pi.dev-src/pi-mono/coding-agent/src/modes/interactive/components/user-message.ts +35 -0
  358. package/pi.dev-src/pi-mono/coding-agent/src/modes/interactive/components/visual-truncate.ts +50 -0
  359. package/pi.dev-src/pi-mono/coding-agent/src/modes/interactive/interactive-mode.ts +5155 -0
  360. package/pi.dev-src/pi-mono/coding-agent/src/modes/interactive/theme/dark.json +85 -0
  361. package/pi.dev-src/pi-mono/coding-agent/src/modes/interactive/theme/light.json +84 -0
  362. package/pi.dev-src/pi-mono/coding-agent/src/modes/interactive/theme/theme-schema.json +335 -0
  363. package/pi.dev-src/pi-mono/coding-agent/src/modes/interactive/theme/theme.ts +1141 -0
  364. package/pi.dev-src/pi-mono/coding-agent/src/modes/print-mode.ts +158 -0
  365. package/pi.dev-src/pi-mono/coding-agent/src/modes/rpc/jsonl.ts +58 -0
  366. package/pi.dev-src/pi-mono/coding-agent/src/modes/rpc/rpc-client.ts +515 -0
  367. package/pi.dev-src/pi-mono/coding-agent/src/modes/rpc/rpc-mode.ts +745 -0
  368. package/pi.dev-src/pi-mono/coding-agent/src/modes/rpc/rpc-types.ts +264 -0
  369. package/pi.dev-src/pi-mono/coding-agent/src/package-manager-cli.ts +270 -0
  370. package/pi.dev-src/pi-mono/coding-agent/src/utils/changelog.ts +99 -0
  371. package/pi.dev-src/pi-mono/coding-agent/src/utils/child-process.ts +86 -0
  372. package/pi.dev-src/pi-mono/coding-agent/src/utils/clipboard-image.ts +300 -0
  373. package/pi.dev-src/pi-mono/coding-agent/src/utils/clipboard-native.ts +22 -0
  374. package/pi.dev-src/pi-mono/coding-agent/src/utils/clipboard.ts +81 -0
  375. package/pi.dev-src/pi-mono/coding-agent/src/utils/exif-orientation.ts +183 -0
  376. package/pi.dev-src/pi-mono/coding-agent/src/utils/frontmatter.ts +39 -0
  377. package/pi.dev-src/pi-mono/coding-agent/src/utils/fs-watch.ts +30 -0
  378. package/pi.dev-src/pi-mono/coding-agent/src/utils/git.ts +192 -0
  379. package/pi.dev-src/pi-mono/coding-agent/src/utils/image-convert.ts +41 -0
  380. package/pi.dev-src/pi-mono/coding-agent/src/utils/image-resize.ts +176 -0
  381. package/pi.dev-src/pi-mono/coding-agent/src/utils/mime.ts +30 -0
  382. package/pi.dev-src/pi-mono/coding-agent/src/utils/paths.ts +20 -0
  383. package/pi.dev-src/pi-mono/coding-agent/src/utils/photon.ts +139 -0
  384. package/pi.dev-src/pi-mono/coding-agent/src/utils/shell.ts +210 -0
  385. package/pi.dev-src/pi-mono/coding-agent/src/utils/sleep.ts +18 -0
  386. package/pi.dev-src/pi-mono/coding-agent/src/utils/tools-manager.ts +287 -0
  387. package/pi.dev-src/pi-mono/coding-agent/test/agent-session-auto-compaction-queue.test.ts +437 -0
  388. package/pi.dev-src/pi-mono/coding-agent/test/agent-session-branching.test.ts +156 -0
  389. package/pi.dev-src/pi-mono/coding-agent/test/agent-session-compaction.test.ts +208 -0
  390. package/pi.dev-src/pi-mono/coding-agent/test/agent-session-concurrent.test.ts +618 -0
  391. package/pi.dev-src/pi-mono/coding-agent/test/agent-session-dynamic-provider.test.ts +117 -0
  392. package/pi.dev-src/pi-mono/coding-agent/test/agent-session-dynamic-tools.test.ts +182 -0
  393. package/pi.dev-src/pi-mono/coding-agent/test/agent-session-retry.test.ts +318 -0
  394. package/pi.dev-src/pi-mono/coding-agent/test/agent-session-runtime-events.test.ts +208 -0
  395. package/pi.dev-src/pi-mono/coding-agent/test/agent-session-stats.test.ts +143 -0
  396. package/pi.dev-src/pi-mono/coding-agent/test/agent-session-tree-navigation.test.ts +323 -0
  397. package/pi.dev-src/pi-mono/coding-agent/test/args.test.ts +328 -0
  398. package/pi.dev-src/pi-mono/coding-agent/test/assistant-message.test.ts +57 -0
  399. package/pi.dev-src/pi-mono/coding-agent/test/auth-storage.test.ts +462 -0
  400. package/pi.dev-src/pi-mono/coding-agent/test/bash-close-hang-windows.test.ts +126 -0
  401. package/pi.dev-src/pi-mono/coding-agent/test/bash-execution-width.test.ts +80 -0
  402. package/pi.dev-src/pi-mono/coding-agent/test/block-images.test.ts +120 -0
  403. package/pi.dev-src/pi-mono/coding-agent/test/clipboard-image-bmp-conversion.test.ts +88 -0
  404. package/pi.dev-src/pi-mono/coding-agent/test/clipboard-image.test.ts +136 -0
  405. package/pi.dev-src/pi-mono/coding-agent/test/compaction-extensions-example.test.ts +66 -0
  406. package/pi.dev-src/pi-mono/coding-agent/test/compaction-extensions.test.ts +415 -0
  407. package/pi.dev-src/pi-mono/coding-agent/test/compaction-serialization.test.ts +79 -0
  408. package/pi.dev-src/pi-mono/coding-agent/test/compaction-summary-reasoning.test.ts +118 -0
  409. package/pi.dev-src/pi-mono/coding-agent/test/compaction-thinking-model.test.ts +223 -0
  410. package/pi.dev-src/pi-mono/coding-agent/test/compaction.test.ts +550 -0
  411. package/pi.dev-src/pi-mono/coding-agent/test/config.test.ts +30 -0
  412. package/pi.dev-src/pi-mono/coding-agent/test/edit-tool-legacy-input.test.ts +116 -0
  413. package/pi.dev-src/pi-mono/coding-agent/test/edit-tool-no-full-redraw.test.ts +235 -0
  414. package/pi.dev-src/pi-mono/coding-agent/test/export-html-whitespace.test.ts +12 -0
  415. package/pi.dev-src/pi-mono/coding-agent/test/export-html-xss.test.ts +28 -0
  416. package/pi.dev-src/pi-mono/coding-agent/test/extensions-discovery.test.ts +463 -0
  417. package/pi.dev-src/pi-mono/coding-agent/test/extensions-input-event.test.ts +112 -0
  418. package/pi.dev-src/pi-mono/coding-agent/test/extensions-runner.test.ts +805 -0
  419. package/pi.dev-src/pi-mono/coding-agent/test/file-mutation-queue.test.ts +163 -0
  420. package/pi.dev-src/pi-mono/coding-agent/test/fixtures/assistant-message-with-thinking-code.json +33 -0
  421. package/pi.dev-src/pi-mono/coding-agent/test/fixtures/before-compaction.jsonl +1003 -0
  422. package/pi.dev-src/pi-mono/coding-agent/test/fixtures/empty-agent/.gitkeep +0 -0
  423. package/pi.dev-src/pi-mono/coding-agent/test/fixtures/empty-cwd/.gitkeep +0 -0
  424. package/pi.dev-src/pi-mono/coding-agent/test/fixtures/large-session.jsonl +1019 -0
  425. package/pi.dev-src/pi-mono/coding-agent/test/fixtures/skills/consecutive-hyphens/SKILL.md +8 -0
  426. package/pi.dev-src/pi-mono/coding-agent/test/fixtures/skills/disable-model-invocation/SKILL.md +9 -0
  427. package/pi.dev-src/pi-mono/coding-agent/test/fixtures/skills/invalid-name-chars/SKILL.md +8 -0
  428. package/pi.dev-src/pi-mono/coding-agent/test/fixtures/skills/invalid-yaml/SKILL.md +8 -0
  429. package/pi.dev-src/pi-mono/coding-agent/test/fixtures/skills/long-name/SKILL.md +8 -0
  430. package/pi.dev-src/pi-mono/coding-agent/test/fixtures/skills/missing-description/SKILL.md +7 -0
  431. package/pi.dev-src/pi-mono/coding-agent/test/fixtures/skills/multiline-description/SKILL.md +11 -0
  432. package/pi.dev-src/pi-mono/coding-agent/test/fixtures/skills/name-mismatch/SKILL.md +8 -0
  433. package/pi.dev-src/pi-mono/coding-agent/test/fixtures/skills/nested/child-skill/SKILL.md +8 -0
  434. package/pi.dev-src/pi-mono/coding-agent/test/fixtures/skills/no-frontmatter/SKILL.md +3 -0
  435. package/pi.dev-src/pi-mono/coding-agent/test/fixtures/skills/root-skill-preferred/SKILL.md +3 -0
  436. package/pi.dev-src/pi-mono/coding-agent/test/fixtures/skills/root-skill-preferred/nested-child/SKILL.md +3 -0
  437. package/pi.dev-src/pi-mono/coding-agent/test/fixtures/skills/unknown-field/SKILL.md +10 -0
  438. package/pi.dev-src/pi-mono/coding-agent/test/fixtures/skills/valid-skill/SKILL.md +8 -0
  439. package/pi.dev-src/pi-mono/coding-agent/test/fixtures/skills-collision/first/calendar/SKILL.md +8 -0
  440. package/pi.dev-src/pi-mono/coding-agent/test/fixtures/skills-collision/second/calendar/SKILL.md +8 -0
  441. package/pi.dev-src/pi-mono/coding-agent/test/footer-data-provider.test.ts +265 -0
  442. package/pi.dev-src/pi-mono/coding-agent/test/footer-width.test.ts +115 -0
  443. package/pi.dev-src/pi-mono/coding-agent/test/frontmatter.test.ts +60 -0
  444. package/pi.dev-src/pi-mono/coding-agent/test/git-ssh-url.test.ts +78 -0
  445. package/pi.dev-src/pi-mono/coding-agent/test/git-update.test.ts +411 -0
  446. package/pi.dev-src/pi-mono/coding-agent/test/image-processing.test.ts +145 -0
  447. package/pi.dev-src/pi-mono/coding-agent/test/image-resize-callers.test.ts +53 -0
  448. package/pi.dev-src/pi-mono/coding-agent/test/initial-message.test.ts +48 -0
  449. package/pi.dev-src/pi-mono/coding-agent/test/interactive-mode-anthropic-warning.test.ts +73 -0
  450. package/pi.dev-src/pi-mono/coding-agent/test/interactive-mode-clone-command.test.ts +77 -0
  451. package/pi.dev-src/pi-mono/coding-agent/test/interactive-mode-compaction.test.ts +57 -0
  452. package/pi.dev-src/pi-mono/coding-agent/test/interactive-mode-import-command.test.ts +144 -0
  453. package/pi.dev-src/pi-mono/coding-agent/test/interactive-mode-status.test.ts +635 -0
  454. package/pi.dev-src/pi-mono/coding-agent/test/interactive-mode-suspend.test.ts +149 -0
  455. package/pi.dev-src/pi-mono/coding-agent/test/keybindings-migration.test.ts +88 -0
  456. package/pi.dev-src/pi-mono/coding-agent/test/model-registry.test.ts +1209 -0
  457. package/pi.dev-src/pi-mono/coding-agent/test/model-resolver.test.ts +436 -0
  458. package/pi.dev-src/pi-mono/coding-agent/test/package-command-paths.test.ts +144 -0
  459. package/pi.dev-src/pi-mono/coding-agent/test/package-manager-ssh.test.ts +97 -0
  460. package/pi.dev-src/pi-mono/coding-agent/test/package-manager.test.ts +1795 -0
  461. package/pi.dev-src/pi-mono/coding-agent/test/path-utils.test.ts +162 -0
  462. package/pi.dev-src/pi-mono/coding-agent/test/plan-mode-utils.test.ts +261 -0
  463. package/pi.dev-src/pi-mono/coding-agent/test/print-mode.test.ts +140 -0
  464. package/pi.dev-src/pi-mono/coding-agent/test/prompt-templates.test.ts +515 -0
  465. package/pi.dev-src/pi-mono/coding-agent/test/resource-loader.test.ts +576 -0
  466. package/pi.dev-src/pi-mono/coding-agent/test/rpc-client-clone.test.ts +29 -0
  467. package/pi.dev-src/pi-mono/coding-agent/test/rpc-example.ts +86 -0
  468. package/pi.dev-src/pi-mono/coding-agent/test/rpc-jsonl.test.ts +65 -0
  469. package/pi.dev-src/pi-mono/coding-agent/test/rpc-prompt-response-semantics.test.ts +285 -0
  470. package/pi.dev-src/pi-mono/coding-agent/test/rpc.test.ts +321 -0
  471. package/pi.dev-src/pi-mono/coding-agent/test/sdk-codex-cache-probe-tool-loop.ts +364 -0
  472. package/pi.dev-src/pi-mono/coding-agent/test/sdk-openrouter-attribution.test.ts +181 -0
  473. package/pi.dev-src/pi-mono/coding-agent/test/sdk-session-manager.test.ts +95 -0
  474. package/pi.dev-src/pi-mono/coding-agent/test/sdk-skills.test.ts +109 -0
  475. package/pi.dev-src/pi-mono/coding-agent/test/session-cwd.test.ts +91 -0
  476. package/pi.dev-src/pi-mono/coding-agent/test/session-info-modified-timestamp.test.ts +83 -0
  477. package/pi.dev-src/pi-mono/coding-agent/test/session-manager/build-context.test.ts +268 -0
  478. package/pi.dev-src/pi-mono/coding-agent/test/session-manager/custom-session-id.test.ts +109 -0
  479. package/pi.dev-src/pi-mono/coding-agent/test/session-manager/file-operations.test.ts +208 -0
  480. package/pi.dev-src/pi-mono/coding-agent/test/session-manager/labels.test.ts +198 -0
  481. package/pi.dev-src/pi-mono/coding-agent/test/session-manager/migration.test.ts +78 -0
  482. package/pi.dev-src/pi-mono/coding-agent/test/session-manager/save-entry.test.ts +55 -0
  483. package/pi.dev-src/pi-mono/coding-agent/test/session-manager/tree-traversal.test.ts +533 -0
  484. package/pi.dev-src/pi-mono/coding-agent/test/session-selector-path-delete.test.ts +315 -0
  485. package/pi.dev-src/pi-mono/coding-agent/test/session-selector-rename.test.ts +111 -0
  486. package/pi.dev-src/pi-mono/coding-agent/test/session-selector-search.test.ts +195 -0
  487. package/pi.dev-src/pi-mono/coding-agent/test/settings-manager-bug.test.ts +147 -0
  488. package/pi.dev-src/pi-mono/coding-agent/test/settings-manager.test.ts +319 -0
  489. package/pi.dev-src/pi-mono/coding-agent/test/skills.test.ts +432 -0
  490. package/pi.dev-src/pi-mono/coding-agent/test/stdout-cleanliness.test.ts +103 -0
  491. package/pi.dev-src/pi-mono/coding-agent/test/streaming-render-debug.ts +97 -0
  492. package/pi.dev-src/pi-mono/coding-agent/test/suite/agent-session-bash-persistence.test.ts +242 -0
  493. package/pi.dev-src/pi-mono/coding-agent/test/suite/agent-session-compaction.test.ts +343 -0
  494. package/pi.dev-src/pi-mono/coding-agent/test/suite/agent-session-model-extension.test.ts +325 -0
  495. package/pi.dev-src/pi-mono/coding-agent/test/suite/agent-session-prompt.test.ts +323 -0
  496. package/pi.dev-src/pi-mono/coding-agent/test/suite/agent-session-queue.test.ts +422 -0
  497. package/pi.dev-src/pi-mono/coding-agent/test/suite/agent-session-retry-events.test.ts +358 -0
  498. package/pi.dev-src/pi-mono/coding-agent/test/suite/agent-session-runtime.test.ts +553 -0
  499. package/pi.dev-src/pi-mono/coding-agent/test/suite/harness.ts +208 -0
  500. package/pi.dev-src/pi-mono/coding-agent/test/suite/regressions/2023-queued-slash-command-followup.test.ts +80 -0
  501. package/pi.dev-src/pi-mono/coding-agent/test/suite/regressions/2753-reload-stale-resource-settings.test.ts +100 -0
  502. package/pi.dev-src/pi-mono/coding-agent/test/suite/regressions/2781-skill-collision-precedence.test.ts +120 -0
  503. package/pi.dev-src/pi-mono/coding-agent/test/suite/regressions/2791-fswatch-error-crash.test.ts +106 -0
  504. package/pi.dev-src/pi-mono/coding-agent/test/suite/regressions/2835-tools-allowlist-filters-extension-tools.test.ts +94 -0
  505. package/pi.dev-src/pi-mono/coding-agent/test/suite/regressions/2860-replaced-session-context.test.ts +274 -0
  506. package/pi.dev-src/pi-mono/coding-agent/test/suite/regressions/3217-scoped-model-order.test.ts +104 -0
  507. package/pi.dev-src/pi-mono/coding-agent/test/suite/regressions/3302-find-path-glob.test.ts +72 -0
  508. package/pi.dev-src/pi-mono/coding-agent/test/suite/regressions/3303-find-nested-gitignore.test.ts +83 -0
  509. package/pi.dev-src/pi-mono/coding-agent/test/suite/regressions/3317-network-connection-lost-retry.test.ts +33 -0
  510. package/pi.dev-src/pi-mono/coding-agent/test/system-prompt.test.ts +102 -0
  511. package/pi.dev-src/pi-mono/coding-agent/test/test-harness.test.ts +321 -0
  512. package/pi.dev-src/pi-mono/coding-agent/test/test-harness.ts +446 -0
  513. package/pi.dev-src/pi-mono/coding-agent/test/test-theme-colors.ts +246 -0
  514. package/pi.dev-src/pi-mono/coding-agent/test/theme-export.test.ts +104 -0
  515. package/pi.dev-src/pi-mono/coding-agent/test/tool-execution-component.test.ts +331 -0
  516. package/pi.dev-src/pi-mono/coding-agent/test/tools.test.ts +889 -0
  517. package/pi.dev-src/pi-mono/coding-agent/test/tree-selector.test.ts +655 -0
  518. package/pi.dev-src/pi-mono/coding-agent/test/trigger-compact-extension.test.ts +57 -0
  519. package/pi.dev-src/pi-mono/coding-agent/test/truncate-to-width.test.ts +81 -0
  520. package/pi.dev-src/pi-mono/coding-agent/test/user-message.test.ts +25 -0
  521. package/pi.dev-src/pi-mono/coding-agent/test/utilities.ts +316 -0
  522. package/pi.dev-src/pi-mono/coding-agent/tsconfig.examples.json +16 -0
  523. package/pi.dev-src/pi-mono/coding-agent/vitest.config.ts +26 -0
  524. package/pi.dev-src/pi-mono/mom/dev.sh +30 -0
  525. package/pi.dev-src/pi-mono/mom/docker.sh +95 -0
  526. package/pi.dev-src/pi-mono/mom/scripts/migrate-timestamps.ts +121 -0
  527. package/pi.dev-src/pi-mono/mom/src/agent.ts +882 -0
  528. package/pi.dev-src/pi-mono/mom/src/context.ts +180 -0
  529. package/pi.dev-src/pi-mono/mom/src/download.ts +117 -0
  530. package/pi.dev-src/pi-mono/mom/src/events.ts +442 -0
  531. package/pi.dev-src/pi-mono/mom/src/fs-watch.ts +30 -0
  532. package/pi.dev-src/pi-mono/mom/src/log.ts +271 -0
  533. package/pi.dev-src/pi-mono/mom/src/main.ts +367 -0
  534. package/pi.dev-src/pi-mono/mom/src/sandbox.ts +221 -0
  535. package/pi.dev-src/pi-mono/mom/src/slack.ts +623 -0
  536. package/pi.dev-src/pi-mono/mom/src/store.ts +234 -0
  537. package/pi.dev-src/pi-mono/mom/src/tools/attach.ts +47 -0
  538. package/pi.dev-src/pi-mono/mom/src/tools/bash.ts +97 -0
  539. package/pi.dev-src/pi-mono/mom/src/tools/edit.ts +165 -0
  540. package/pi.dev-src/pi-mono/mom/src/tools/index.ts +19 -0
  541. package/pi.dev-src/pi-mono/mom/src/tools/read.ts +159 -0
  542. package/pi.dev-src/pi-mono/mom/src/tools/truncate.ts +236 -0
  543. package/pi.dev-src/pi-mono/mom/src/tools/write.ts +45 -0
  544. package/pi.dev-src/pi-mono/mom/test/events.test.ts +50 -0
  545. package/pi.dev-src/pi-mono/pods/scripts/model_run.sh +83 -0
  546. package/pi.dev-src/pi-mono/pods/scripts/pod_setup.sh +336 -0
  547. package/pi.dev-src/pi-mono/pods/src/cli.ts +360 -0
  548. package/pi.dev-src/pi-mono/pods/src/commands/models.ts +753 -0
  549. package/pi.dev-src/pi-mono/pods/src/commands/pods.ts +205 -0
  550. package/pi.dev-src/pi-mono/pods/src/commands/prompt.ts +84 -0
  551. package/pi.dev-src/pi-mono/pods/src/config.ts +80 -0
  552. package/pi.dev-src/pi-mono/pods/src/index.ts +2 -0
  553. package/pi.dev-src/pi-mono/pods/src/model-configs.ts +111 -0
  554. package/pi.dev-src/pi-mono/pods/src/models.json +295 -0
  555. package/pi.dev-src/pi-mono/pods/src/ssh.ts +151 -0
  556. package/pi.dev-src/pi-mono/pods/src/types.ts +27 -0
  557. package/pi.dev-src/pi-mono/tui/src/autocomplete.ts +783 -0
  558. package/pi.dev-src/pi-mono/tui/src/components/box.ts +137 -0
  559. package/pi.dev-src/pi-mono/tui/src/components/cancellable-loader.ts +40 -0
  560. package/pi.dev-src/pi-mono/tui/src/components/editor.ts +2280 -0
  561. package/pi.dev-src/pi-mono/tui/src/components/image.ts +104 -0
  562. package/pi.dev-src/pi-mono/tui/src/components/input.ts +503 -0
  563. package/pi.dev-src/pi-mono/tui/src/components/loader.ts +86 -0
  564. package/pi.dev-src/pi-mono/tui/src/components/markdown.ts +852 -0
  565. package/pi.dev-src/pi-mono/tui/src/components/select-list.ts +229 -0
  566. package/pi.dev-src/pi-mono/tui/src/components/settings-list.ts +250 -0
  567. package/pi.dev-src/pi-mono/tui/src/components/spacer.ts +28 -0
  568. package/pi.dev-src/pi-mono/tui/src/components/text.ts +106 -0
  569. package/pi.dev-src/pi-mono/tui/src/components/truncated-text.ts +65 -0
  570. package/pi.dev-src/pi-mono/tui/src/editor-component.ts +74 -0
  571. package/pi.dev-src/pi-mono/tui/src/fuzzy.ts +133 -0
  572. package/pi.dev-src/pi-mono/tui/src/index.ts +106 -0
  573. package/pi.dev-src/pi-mono/tui/src/keybindings.ts +244 -0
  574. package/pi.dev-src/pi-mono/tui/src/keys.ts +1400 -0
  575. package/pi.dev-src/pi-mono/tui/src/kill-ring.ts +46 -0
  576. package/pi.dev-src/pi-mono/tui/src/stdin-buffer.ts +386 -0
  577. package/pi.dev-src/pi-mono/tui/src/terminal-image.ts +414 -0
  578. package/pi.dev-src/pi-mono/tui/src/terminal.ts +373 -0
  579. package/pi.dev-src/pi-mono/tui/src/tui.ts +1243 -0
  580. package/pi.dev-src/pi-mono/tui/src/undo-stack.ts +28 -0
  581. package/pi.dev-src/pi-mono/tui/src/utils.ts +1085 -0
  582. package/pi.dev-src/pi-mono/tui/test/autocomplete.test.ts +542 -0
  583. package/pi.dev-src/pi-mono/tui/test/bug-regression-isimageline-startswith-bug.test.ts +237 -0
  584. package/pi.dev-src/pi-mono/tui/test/chat-simple.ts +129 -0
  585. package/pi.dev-src/pi-mono/tui/test/editor.test.ts +3812 -0
  586. package/pi.dev-src/pi-mono/tui/test/fuzzy.test.ts +98 -0
  587. package/pi.dev-src/pi-mono/tui/test/image-test.ts +56 -0
  588. package/pi.dev-src/pi-mono/tui/test/input.test.ts +580 -0
  589. package/pi.dev-src/pi-mono/tui/test/key-tester.ts +105 -0
  590. package/pi.dev-src/pi-mono/tui/test/keybindings.test.ts +38 -0
  591. package/pi.dev-src/pi-mono/tui/test/keys.test.ts +614 -0
  592. package/pi.dev-src/pi-mono/tui/test/markdown.test.ts +1236 -0
  593. package/pi.dev-src/pi-mono/tui/test/overlay-non-capturing.test.ts +609 -0
  594. package/pi.dev-src/pi-mono/tui/test/overlay-options.test.ts +538 -0
  595. package/pi.dev-src/pi-mono/tui/test/overlay-short-content.test.ts +56 -0
  596. package/pi.dev-src/pi-mono/tui/test/regression-regional-indicator-width.test.ts +52 -0
  597. package/pi.dev-src/pi-mono/tui/test/select-list.test.ts +116 -0
  598. package/pi.dev-src/pi-mono/tui/test/stdin-buffer.test.ts +422 -0
  599. package/pi.dev-src/pi-mono/tui/test/terminal-image.test.ts +279 -0
  600. package/pi.dev-src/pi-mono/tui/test/test-themes.ts +38 -0
  601. package/pi.dev-src/pi-mono/tui/test/truncate-to-width.test.ts +62 -0
  602. package/pi.dev-src/pi-mono/tui/test/truncated-text.test.ts +129 -0
  603. package/pi.dev-src/pi-mono/tui/test/tui-cell-size-input.test.ts +81 -0
  604. package/pi.dev-src/pi-mono/tui/test/tui-overlay-style-leak.test.ts +72 -0
  605. package/pi.dev-src/pi-mono/tui/test/tui-render.test.ts +509 -0
  606. package/pi.dev-src/pi-mono/tui/test/viewport-overwrite-repro.ts +106 -0
  607. package/pi.dev-src/pi-mono/tui/test/virtual-terminal.ts +218 -0
  608. package/pi.dev-src/pi-mono/tui/test/wrap-ansi.test.ts +207 -0
  609. package/pi.dev-src/pi-mono/tui/vitest.config.ts +7 -0
  610. package/pi.dev-src/pi-mono/web-ui/example/index.html +13 -0
  611. package/pi.dev-src/pi-mono/web-ui/example/src/app.css +1 -0
  612. package/pi.dev-src/pi-mono/web-ui/example/src/custom-messages.ts +99 -0
  613. package/pi.dev-src/pi-mono/web-ui/example/src/main.ts +421 -0
  614. package/pi.dev-src/pi-mono/web-ui/example/tsconfig.json +23 -0
  615. package/pi.dev-src/pi-mono/web-ui/example/vite.config.ts +6 -0
  616. package/pi.dev-src/pi-mono/web-ui/scripts/count-prompt-tokens.ts +88 -0
  617. package/pi.dev-src/pi-mono/web-ui/src/ChatPanel.ts +209 -0
  618. package/pi.dev-src/pi-mono/web-ui/src/app.css +68 -0
  619. package/pi.dev-src/pi-mono/web-ui/src/components/AgentInterface.ts +403 -0
  620. package/pi.dev-src/pi-mono/web-ui/src/components/AttachmentTile.ts +107 -0
  621. package/pi.dev-src/pi-mono/web-ui/src/components/ConsoleBlock.ts +72 -0
  622. package/pi.dev-src/pi-mono/web-ui/src/components/CustomProviderCard.ts +100 -0
  623. package/pi.dev-src/pi-mono/web-ui/src/components/ExpandableSection.ts +46 -0
  624. package/pi.dev-src/pi-mono/web-ui/src/components/Input.ts +113 -0
  625. package/pi.dev-src/pi-mono/web-ui/src/components/MessageEditor.ts +405 -0
  626. package/pi.dev-src/pi-mono/web-ui/src/components/MessageList.ts +98 -0
  627. package/pi.dev-src/pi-mono/web-ui/src/components/Messages.ts +383 -0
  628. package/pi.dev-src/pi-mono/web-ui/src/components/ProviderKeyInput.ts +153 -0
  629. package/pi.dev-src/pi-mono/web-ui/src/components/SandboxedIframe.ts +626 -0
  630. package/pi.dev-src/pi-mono/web-ui/src/components/StreamingMessageContainer.ts +103 -0
  631. package/pi.dev-src/pi-mono/web-ui/src/components/ThinkingBlock.ts +43 -0
  632. package/pi.dev-src/pi-mono/web-ui/src/components/message-renderer-registry.ts +28 -0
  633. package/pi.dev-src/pi-mono/web-ui/src/components/sandbox/ArtifactsRuntimeProvider.ts +220 -0
  634. package/pi.dev-src/pi-mono/web-ui/src/components/sandbox/AttachmentsRuntimeProvider.ts +66 -0
  635. package/pi.dev-src/pi-mono/web-ui/src/components/sandbox/ConsoleRuntimeProvider.ts +186 -0
  636. package/pi.dev-src/pi-mono/web-ui/src/components/sandbox/FileDownloadRuntimeProvider.ts +110 -0
  637. package/pi.dev-src/pi-mono/web-ui/src/components/sandbox/RuntimeMessageBridge.ts +82 -0
  638. package/pi.dev-src/pi-mono/web-ui/src/components/sandbox/RuntimeMessageRouter.ts +216 -0
  639. package/pi.dev-src/pi-mono/web-ui/src/components/sandbox/SandboxRuntimeProvider.ts +52 -0
  640. package/pi.dev-src/pi-mono/web-ui/src/dialogs/ApiKeyPromptDialog.ts +75 -0
  641. package/pi.dev-src/pi-mono/web-ui/src/dialogs/AttachmentOverlay.ts +636 -0
  642. package/pi.dev-src/pi-mono/web-ui/src/dialogs/CustomProviderDialog.ts +274 -0
  643. package/pi.dev-src/pi-mono/web-ui/src/dialogs/ModelSelector.ts +370 -0
  644. package/pi.dev-src/pi-mono/web-ui/src/dialogs/PersistentStorageDialog.ts +144 -0
  645. package/pi.dev-src/pi-mono/web-ui/src/dialogs/ProvidersModelsTab.ts +212 -0
  646. package/pi.dev-src/pi-mono/web-ui/src/dialogs/SessionListDialog.ts +150 -0
  647. package/pi.dev-src/pi-mono/web-ui/src/dialogs/SettingsDialog.ts +218 -0
  648. package/pi.dev-src/pi-mono/web-ui/src/index.ts +120 -0
  649. package/pi.dev-src/pi-mono/web-ui/src/prompts/prompts.ts +282 -0
  650. package/pi.dev-src/pi-mono/web-ui/src/storage/app-storage.ts +60 -0
  651. package/pi.dev-src/pi-mono/web-ui/src/storage/backends/indexeddb-storage-backend.ts +193 -0
  652. package/pi.dev-src/pi-mono/web-ui/src/storage/store.ts +33 -0
  653. package/pi.dev-src/pi-mono/web-ui/src/storage/stores/custom-providers-store.ts +62 -0
  654. package/pi.dev-src/pi-mono/web-ui/src/storage/stores/provider-keys-store.ts +33 -0
  655. package/pi.dev-src/pi-mono/web-ui/src/storage/stores/sessions-store.ts +136 -0
  656. package/pi.dev-src/pi-mono/web-ui/src/storage/stores/settings-store.ts +34 -0
  657. package/pi.dev-src/pi-mono/web-ui/src/storage/types.ts +206 -0
  658. package/pi.dev-src/pi-mono/web-ui/src/tools/artifacts/ArtifactElement.ts +14 -0
  659. package/pi.dev-src/pi-mono/web-ui/src/tools/artifacts/ArtifactPill.ts +26 -0
  660. package/pi.dev-src/pi-mono/web-ui/src/tools/artifacts/Console.ts +93 -0
  661. package/pi.dev-src/pi-mono/web-ui/src/tools/artifacts/DocxArtifact.ts +213 -0
  662. package/pi.dev-src/pi-mono/web-ui/src/tools/artifacts/ExcelArtifact.ts +231 -0
  663. package/pi.dev-src/pi-mono/web-ui/src/tools/artifacts/GenericArtifact.ts +117 -0
  664. package/pi.dev-src/pi-mono/web-ui/src/tools/artifacts/HtmlArtifact.ts +195 -0
  665. package/pi.dev-src/pi-mono/web-ui/src/tools/artifacts/ImageArtifact.ts +116 -0
  666. package/pi.dev-src/pi-mono/web-ui/src/tools/artifacts/MarkdownArtifact.ts +82 -0
  667. package/pi.dev-src/pi-mono/web-ui/src/tools/artifacts/PdfArtifact.ts +201 -0
  668. package/pi.dev-src/pi-mono/web-ui/src/tools/artifacts/SvgArtifact.ts +119 -0
  669. package/pi.dev-src/pi-mono/web-ui/src/tools/artifacts/TextArtifact.ts +148 -0
  670. package/pi.dev-src/pi-mono/web-ui/src/tools/artifacts/artifacts-tool-renderer.ts +310 -0
  671. package/pi.dev-src/pi-mono/web-ui/src/tools/artifacts/artifacts.ts +713 -0
  672. package/pi.dev-src/pi-mono/web-ui/src/tools/artifacts/index.ts +7 -0
  673. package/pi.dev-src/pi-mono/web-ui/src/tools/extract-document.ts +275 -0
  674. package/pi.dev-src/pi-mono/web-ui/src/tools/index.ts +46 -0
  675. package/pi.dev-src/pi-mono/web-ui/src/tools/javascript-repl.ts +293 -0
  676. package/pi.dev-src/pi-mono/web-ui/src/tools/renderer-registry.ts +130 -0
  677. package/pi.dev-src/pi-mono/web-ui/src/tools/renderers/BashRenderer.ts +52 -0
  678. package/pi.dev-src/pi-mono/web-ui/src/tools/renderers/CalculateRenderer.ts +58 -0
  679. package/pi.dev-src/pi-mono/web-ui/src/tools/renderers/DefaultRenderer.ts +103 -0
  680. package/pi.dev-src/pi-mono/web-ui/src/tools/renderers/GetCurrentTimeRenderer.ts +92 -0
  681. package/pi.dev-src/pi-mono/web-ui/src/tools/types.ts +15 -0
  682. package/pi.dev-src/pi-mono/web-ui/src/utils/attachment-utils.ts +472 -0
  683. package/pi.dev-src/pi-mono/web-ui/src/utils/auth-token.ts +22 -0
  684. package/pi.dev-src/pi-mono/web-ui/src/utils/format.ts +42 -0
  685. package/pi.dev-src/pi-mono/web-ui/src/utils/i18n.ts +653 -0
  686. package/pi.dev-src/pi-mono/web-ui/src/utils/model-discovery.ts +277 -0
  687. package/pi.dev-src/pi-mono/web-ui/src/utils/proxy-utils.ts +139 -0
  688. package/pi.dev-src/pi-mono/web-ui/src/utils/test-sessions.ts +2357 -0
  689. package/pi.dev-src/pi-mono/web-ui/tsconfig.json +7 -0
  690. package/scripts/lib/extension-debug-harness.ts +3 -10
  691. package/scripts/lib/recording-extension-api.ts +71 -2
  692. package/scripts/pi-usereq-debug.sh +1 -1
  693. package/scripts/tool-args-to-params.ts +4 -15
  694. package/src/cli.ts +24 -68
  695. package/src/core/agent-tool-json.ts +53 -239
  696. package/src/core/compress-payload.ts +4 -74
  697. package/src/core/compress.ts +26 -15
  698. package/src/core/config.ts +468 -42
  699. package/src/core/debug-runtime.ts +542 -0
  700. package/src/core/extension-status.ts +314 -59
  701. package/src/core/find-constructs.ts +3 -3
  702. package/src/core/find-payload.ts +26 -132
  703. package/src/core/path-context.ts +346 -81
  704. package/src/core/pi-notify.ts +115 -5
  705. package/src/core/pi-usereq-tools.ts +57 -19
  706. package/src/core/prompt-command-catalog.ts +46 -0
  707. package/src/core/prompt-command-runtime.ts +1816 -0
  708. package/src/core/prompt-command-state.ts +211 -0
  709. package/src/core/prompts.ts +173 -41
  710. package/src/core/reference-payload.ts +5 -63
  711. package/src/core/resources.ts +61 -5
  712. package/src/core/runtime-project-paths.ts +21 -1
  713. package/src/core/settings-menu.ts +12 -6
  714. package/src/core/source-analyzer.ts +27 -7
  715. package/src/core/token-counter.ts +6 -76
  716. package/src/core/tool-runner.ts +38 -317
  717. package/src/index.ts +2047 -947
  718. package/src/resources/instructions/git_commit.md +16 -0
  719. package/src/resources/instructions/git_read-only.md +2 -0
  720. package/src/resources/prompts/analyze.md +12 -13
  721. package/src/resources/prompts/change.md +21 -59
  722. package/src/resources/prompts/check.md +14 -16
  723. package/src/resources/prompts/cover.md +21 -59
  724. package/src/resources/prompts/create.md +5 -4
  725. package/src/resources/prompts/fix.md +20 -58
  726. package/src/resources/prompts/flowchart.md +14 -49
  727. package/src/resources/prompts/implement.md +14 -50
  728. package/src/resources/prompts/new.md +20 -58
  729. package/src/resources/prompts/readme.md +14 -50
  730. package/src/resources/prompts/recreate.md +14 -45
  731. package/src/resources/prompts/refactor.md +20 -58
  732. package/src/resources/prompts/references.md +7 -43
  733. package/src/resources/prompts/renumber.md +8 -39
  734. package/src/resources/prompts/workflow.md +14 -50
  735. package/src/resources/prompts/write.md +5 -4
  736. package/tests/attended-results-scenarios.ts +30 -136
  737. package/tests/cli-command-option-parity.test.ts +148 -192
  738. package/tests/debug-extension-harness.test.ts +77 -70
  739. package/tests/extension-registration.test.ts +3205 -658
  740. package/tests/fixtures_attended_results/project/compress-line-numbers.json +1 -1
  741. package/tests/fixtures_attended_results/project/compress.json +1 -1
  742. package/tests/fixtures_attended_results/project/find-line-numbers.json +1 -1
  743. package/tests/fixtures_attended_results/project/find.json +1 -1
  744. package/tests/fixtures_attended_results/project/references.json +2 -2
  745. package/tests/fixtures_attended_results/standalone/files-compress/fixture_go.go.json +1 -1
  746. package/tests/fixtures_attended_results/standalone/files-compress-line-numbers/fixture_go.go.json +1 -1
  747. package/tests/fixtures_attended_results/standalone/files-find/fixture_go.go.json +1 -1
  748. package/tests/fixtures_attended_results/standalone/files-find-line-numbers/fixture_go.go.json +1 -1
  749. package/tests/fixtures_attended_results/standalone/files-references/fixture_c.c.json +1 -1
  750. package/tests/fixtures_attended_results/standalone/files-references/fixture_cpp.cpp.json +1 -1
  751. package/tests/fixtures_attended_results/standalone/files-references/fixture_csharp.cs.json +1 -1
  752. package/tests/fixtures_attended_results/standalone/files-references/fixture_elixir.ex.json +1 -1
  753. package/tests/fixtures_attended_results/standalone/files-references/fixture_go.go.json +1 -1
  754. package/tests/fixtures_attended_results/standalone/files-references/fixture_haskell.hs.json +1 -1
  755. package/tests/fixtures_attended_results/standalone/files-references/fixture_java.java.json +1 -1
  756. package/tests/fixtures_attended_results/standalone/files-references/fixture_javascript.js.json +1 -1
  757. package/tests/fixtures_attended_results/standalone/files-references/fixture_kotlin.kt.json +1 -1
  758. package/tests/fixtures_attended_results/standalone/files-references/fixture_lua.lua.json +1 -1
  759. package/tests/fixtures_attended_results/standalone/files-references/fixture_perl.pl.json +1 -1
  760. package/tests/fixtures_attended_results/standalone/files-references/fixture_php.php.json +1 -1
  761. package/tests/fixtures_attended_results/standalone/files-references/fixture_python.py.json +1 -1
  762. package/tests/fixtures_attended_results/standalone/files-references/fixture_ruby.rb.json +1 -1
  763. package/tests/fixtures_attended_results/standalone/files-references/fixture_rust.rs.json +1 -1
  764. package/tests/fixtures_attended_results/standalone/files-references/fixture_scala.scala.json +1 -1
  765. package/tests/fixtures_attended_results/standalone/files-references/fixture_shell.sh.json +1 -1
  766. package/tests/fixtures_attended_results/standalone/files-references/fixture_swift.swift.json +1 -1
  767. package/tests/fixtures_attended_results/standalone/files-references/fixture_typescript.ts.json +1 -1
  768. package/tests/fixtures_attended_results/standalone/files-references/fixture_zig.zig.json +1 -1
  769. package/tests/helpers.ts +24 -15
  770. package/tests/oracle-project.test.ts +29 -30
  771. package/tests/oracle-standalone.test.ts +27 -1
  772. package/tests/prompt-rendering.test.ts +40 -9
  773. package/tests/python_oracle_stubs/tiktoken.py +76 -0
@@ -0,0 +1,882 @@
1
+ import { Agent, type AgentEvent } from "@mariozechner/pi-agent-core";
2
+ import { getModel, type ImageContent } from "@mariozechner/pi-ai";
3
+ import {
4
+ AgentSession,
5
+ AuthStorage,
6
+ convertToLlm,
7
+ createExtensionRuntime,
8
+ formatSkillsForPrompt,
9
+ loadSkillsFromDir,
10
+ ModelRegistry,
11
+ type ResourceLoader,
12
+ SessionManager,
13
+ type Skill,
14
+ } from "@mariozechner/pi-coding-agent";
15
+ import { existsSync, readFileSync } from "fs";
16
+ import { mkdir, writeFile } from "fs/promises";
17
+ import { homedir } from "os";
18
+ import { join } from "path";
19
+ import { createMomSettingsManager, syncLogToSessionManager } from "./context.js";
20
+ import * as log from "./log.js";
21
+ import { createExecutor, type SandboxConfig } from "./sandbox.js";
22
+ import type { ChannelInfo, SlackContext, UserInfo } from "./slack.js";
23
+ import type { ChannelStore } from "./store.js";
24
+ import { createMomTools, setUploadFunction } from "./tools/index.js";
25
+
26
+ // Hardcoded model for now - TODO: make configurable (issue #63)
27
+ const model = getModel("anthropic", "claude-sonnet-4-5");
28
+
29
+ export interface PendingMessage {
30
+ userName: string;
31
+ text: string;
32
+ attachments: { local: string }[];
33
+ timestamp: number;
34
+ }
35
+
36
+ export interface AgentRunner {
37
+ run(
38
+ ctx: SlackContext,
39
+ store: ChannelStore,
40
+ pendingMessages?: PendingMessage[],
41
+ ): Promise<{ stopReason: string; errorMessage?: string }>;
42
+ abort(): void;
43
+ }
44
+
45
+ async function getAnthropicApiKey(authStorage: AuthStorage): Promise<string> {
46
+ const key = await authStorage.getApiKey("anthropic");
47
+ if (!key) {
48
+ throw new Error(
49
+ "No API key found for anthropic.\n\n" +
50
+ "Set an API key environment variable, or use /login with Anthropic and link to auth.json from " +
51
+ join(homedir(), ".pi", "mom", "auth.json"),
52
+ );
53
+ }
54
+ return key;
55
+ }
56
+
57
+ const IMAGE_MIME_TYPES: Record<string, string> = {
58
+ jpg: "image/jpeg",
59
+ jpeg: "image/jpeg",
60
+ png: "image/png",
61
+ gif: "image/gif",
62
+ webp: "image/webp",
63
+ };
64
+
65
+ function getImageMimeType(filename: string): string | undefined {
66
+ return IMAGE_MIME_TYPES[filename.toLowerCase().split(".").pop() || ""];
67
+ }
68
+
69
+ function getMemory(channelDir: string): string {
70
+ const parts: string[] = [];
71
+
72
+ // Read workspace-level memory (shared across all channels)
73
+ const workspaceMemoryPath = join(channelDir, "..", "MEMORY.md");
74
+ if (existsSync(workspaceMemoryPath)) {
75
+ try {
76
+ const content = readFileSync(workspaceMemoryPath, "utf-8").trim();
77
+ if (content) {
78
+ parts.push(`### Global Workspace Memory\n${content}`);
79
+ }
80
+ } catch (error) {
81
+ log.logWarning("Failed to read workspace memory", `${workspaceMemoryPath}: ${error}`);
82
+ }
83
+ }
84
+
85
+ // Read channel-specific memory
86
+ const channelMemoryPath = join(channelDir, "MEMORY.md");
87
+ if (existsSync(channelMemoryPath)) {
88
+ try {
89
+ const content = readFileSync(channelMemoryPath, "utf-8").trim();
90
+ if (content) {
91
+ parts.push(`### Channel-Specific Memory\n${content}`);
92
+ }
93
+ } catch (error) {
94
+ log.logWarning("Failed to read channel memory", `${channelMemoryPath}: ${error}`);
95
+ }
96
+ }
97
+
98
+ if (parts.length === 0) {
99
+ return "(no working memory yet)";
100
+ }
101
+
102
+ return parts.join("\n\n");
103
+ }
104
+
105
+ function loadMomSkills(channelDir: string, workspacePath: string): Skill[] {
106
+ const skillMap = new Map<string, Skill>();
107
+
108
+ // channelDir is the host path (e.g., /Users/.../data/C0A34FL8PMH)
109
+ // hostWorkspacePath is the parent directory on host
110
+ // workspacePath is the container path (e.g., /workspace)
111
+ const hostWorkspacePath = join(channelDir, "..");
112
+
113
+ // Helper to translate host paths to container paths
114
+ const translatePath = (hostPath: string): string => {
115
+ if (hostPath.startsWith(hostWorkspacePath)) {
116
+ return workspacePath + hostPath.slice(hostWorkspacePath.length);
117
+ }
118
+ return hostPath;
119
+ };
120
+
121
+ // Load workspace-level skills (global)
122
+ const workspaceSkillsDir = join(hostWorkspacePath, "skills");
123
+ for (const skill of loadSkillsFromDir({ dir: workspaceSkillsDir, source: "workspace" }).skills) {
124
+ // Translate paths to container paths for system prompt
125
+ skill.filePath = translatePath(skill.filePath);
126
+ skill.baseDir = translatePath(skill.baseDir);
127
+ skillMap.set(skill.name, skill);
128
+ }
129
+
130
+ // Load channel-specific skills (override workspace skills on collision)
131
+ const channelSkillsDir = join(channelDir, "skills");
132
+ for (const skill of loadSkillsFromDir({ dir: channelSkillsDir, source: "channel" }).skills) {
133
+ skill.filePath = translatePath(skill.filePath);
134
+ skill.baseDir = translatePath(skill.baseDir);
135
+ skillMap.set(skill.name, skill);
136
+ }
137
+
138
+ return Array.from(skillMap.values());
139
+ }
140
+
141
+ function buildSystemPrompt(
142
+ workspacePath: string,
143
+ channelId: string,
144
+ memory: string,
145
+ sandboxConfig: SandboxConfig,
146
+ channels: ChannelInfo[],
147
+ users: UserInfo[],
148
+ skills: Skill[],
149
+ ): string {
150
+ const channelPath = `${workspacePath}/${channelId}`;
151
+ const isDocker = sandboxConfig.type === "docker";
152
+
153
+ // Format channel mappings
154
+ const channelMappings =
155
+ channels.length > 0 ? channels.map((c) => `${c.id}\t#${c.name}`).join("\n") : "(no channels loaded)";
156
+
157
+ // Format user mappings
158
+ const userMappings =
159
+ users.length > 0 ? users.map((u) => `${u.id}\t@${u.userName}\t${u.displayName}`).join("\n") : "(no users loaded)";
160
+
161
+ const envDescription = isDocker
162
+ ? `You are running inside a Docker container (Alpine Linux).
163
+ - Bash working directory: / (use cd or absolute paths)
164
+ - Install tools with: apk add <package>
165
+ - Your changes persist across sessions`
166
+ : `You are running directly on the host machine.
167
+ - Bash working directory: ${process.cwd()}
168
+ - Be careful with system modifications`;
169
+
170
+ return `You are mom, a Slack bot assistant. Be concise. No emojis.
171
+
172
+ ## Context
173
+ - For current date/time, use: date
174
+ - You have access to previous conversation context including tool results from prior turns.
175
+ - For older history beyond your context, search log.jsonl (contains user messages and your final responses, but not tool results).
176
+
177
+ ## Slack Formatting (mrkdwn, NOT Markdown)
178
+ Bold: *text*, Italic: _text_, Code: \`code\`, Block: \`\`\`code\`\`\`, Links: <url|text>
179
+ Do NOT use **double asterisks** or [markdown](links).
180
+
181
+ ## Slack IDs
182
+ Channels: ${channelMappings}
183
+
184
+ Users: ${userMappings}
185
+
186
+ When mentioning users, use <@username> format (e.g., <@mario>).
187
+
188
+ ## Environment
189
+ ${envDescription}
190
+
191
+ ## Workspace Layout
192
+ ${workspacePath}/
193
+ ├── MEMORY.md # Global memory (all channels)
194
+ ├── skills/ # Global CLI tools you create
195
+ └── ${channelId}/ # This channel
196
+ ├── MEMORY.md # Channel-specific memory
197
+ ├── log.jsonl # Message history (no tool results)
198
+ ├── attachments/ # User-shared files
199
+ ├── scratch/ # Your working directory
200
+ └── skills/ # Channel-specific tools
201
+
202
+ ## Skills (Custom CLI Tools)
203
+ You can create reusable CLI tools for recurring tasks (email, APIs, data processing, etc.).
204
+
205
+ ### Creating Skills
206
+ Store in \`${workspacePath}/skills/<name>/\` (global) or \`${channelPath}/skills/<name>/\` (channel-specific).
207
+ Each skill directory needs a \`SKILL.md\` with YAML frontmatter:
208
+
209
+ \`\`\`markdown
210
+ ---
211
+ name: skill-name
212
+ description: Short description of what this skill does
213
+ ---
214
+
215
+ # Skill Name
216
+
217
+ Usage instructions, examples, etc.
218
+ Scripts are in: {baseDir}/
219
+ \`\`\`
220
+
221
+ \`name\` and \`description\` are required. Use \`{baseDir}\` as placeholder for the skill's directory path.
222
+
223
+ ### Available Skills
224
+ ${skills.length > 0 ? formatSkillsForPrompt(skills) : "(no skills installed yet)"}
225
+
226
+ ## Events
227
+ You can schedule events that wake you up at specific times or when external things happen. Events are JSON files in \`${workspacePath}/events/\`.
228
+
229
+ ### Event Types
230
+
231
+ **Immediate** - Triggers as soon as harness sees the file. Use in scripts/webhooks to signal external events.
232
+ \`\`\`json
233
+ {"type": "immediate", "channelId": "${channelId}", "text": "New GitHub issue opened"}
234
+ \`\`\`
235
+
236
+ **One-shot** - Triggers once at a specific time. Use for reminders.
237
+ \`\`\`json
238
+ {"type": "one-shot", "channelId": "${channelId}", "text": "Remind Mario about dentist", "at": "2025-12-15T09:00:00+01:00"}
239
+ \`\`\`
240
+
241
+ **Periodic** - Triggers on a cron schedule. Use for recurring tasks.
242
+ \`\`\`json
243
+ {"type": "periodic", "channelId": "${channelId}", "text": "Check inbox and summarize", "schedule": "0 9 * * 1-5", "timezone": "${Intl.DateTimeFormat().resolvedOptions().timeZone}"}
244
+ \`\`\`
245
+
246
+ ### Cron Format
247
+ \`minute hour day-of-month month day-of-week\`
248
+ - \`0 9 * * *\` = daily at 9:00
249
+ - \`0 9 * * 1-5\` = weekdays at 9:00
250
+ - \`30 14 * * 1\` = Mondays at 14:30
251
+ - \`0 0 1 * *\` = first of each month at midnight
252
+
253
+ ### Timezones
254
+ All \`at\` timestamps must include offset (e.g., \`+01:00\`). Periodic events use IANA timezone names. The harness runs in ${Intl.DateTimeFormat().resolvedOptions().timeZone}. When users mention times without timezone, assume ${Intl.DateTimeFormat().resolvedOptions().timeZone}.
255
+
256
+ ### Creating Events
257
+ Use unique filenames to avoid overwriting existing events. Include a timestamp or random suffix:
258
+ \`\`\`bash
259
+ cat > ${workspacePath}/events/dentist-reminder-$(date +%s).json << 'EOF'
260
+ {"type": "one-shot", "channelId": "${channelId}", "text": "Dentist tomorrow", "at": "2025-12-14T09:00:00+01:00"}
261
+ EOF
262
+ \`\`\`
263
+ Or check if file exists first before creating.
264
+
265
+ ### Managing Events
266
+ - List: \`ls ${workspacePath}/events/\`
267
+ - View: \`cat ${workspacePath}/events/foo.json\`
268
+ - Delete/cancel: \`rm ${workspacePath}/events/foo.json\`
269
+
270
+ ### When Events Trigger
271
+ You receive a message like:
272
+ \`\`\`
273
+ [EVENT:dentist-reminder.json:one-shot:2025-12-14T09:00:00+01:00] Dentist tomorrow
274
+ \`\`\`
275
+ Immediate and one-shot events auto-delete after triggering. Periodic events persist until you delete them.
276
+
277
+ ### Silent Completion
278
+ For periodic events where there's nothing to report, respond with just \`[SILENT]\` (no other text). This deletes the status message and posts nothing to Slack. Use this to avoid spamming the channel when periodic checks find nothing actionable.
279
+
280
+ ### Debouncing
281
+ When writing programs that create immediate events (email watchers, webhook handlers, etc.), always debounce. If 50 emails arrive in a minute, don't create 50 immediate events. Instead collect events over a window and create ONE immediate event summarizing what happened, or just signal "new activity, check inbox" rather than per-item events. Or simpler: use a periodic event to check for new items every N minutes instead of immediate events.
282
+
283
+ ### Limits
284
+ Maximum 5 events can be queued. Don't create excessive immediate or periodic events.
285
+
286
+ ## Memory
287
+ Write to MEMORY.md files to persist context across conversations.
288
+ - Global (${workspacePath}/MEMORY.md): skills, preferences, project info
289
+ - Channel (${channelPath}/MEMORY.md): channel-specific decisions, ongoing work
290
+ Update when you learn something important or when asked to remember something.
291
+
292
+ ### Current Memory
293
+ ${memory}
294
+
295
+ ## System Configuration Log
296
+ Maintain ${workspacePath}/SYSTEM.md to log all environment modifications:
297
+ - Installed packages (apk add, npm install, pip install)
298
+ - Environment variables set
299
+ - Config files modified (~/.gitconfig, cron jobs, etc.)
300
+ - Skill dependencies installed
301
+
302
+ Update this file whenever you modify the environment. On fresh container, read it first to restore your setup.
303
+
304
+ ## Log Queries (for older history)
305
+ Format: \`{"date":"...","ts":"...","user":"...","userName":"...","text":"...","isBot":false}\`
306
+ The log contains user messages and your final responses (not tool calls/results).
307
+ ${isDocker ? "Install jq: apk add jq" : ""}
308
+
309
+ \`\`\`bash
310
+ # Recent messages
311
+ tail -30 log.jsonl | jq -c '{date: .date[0:19], user: (.userName // .user), text}'
312
+
313
+ # Search for specific topic
314
+ grep -i "topic" log.jsonl | jq -c '{date: .date[0:19], user: (.userName // .user), text}'
315
+
316
+ # Messages from specific user
317
+ grep '"userName":"mario"' log.jsonl | tail -20 | jq -c '{date: .date[0:19], text}'
318
+ \`\`\`
319
+
320
+ ## Tools
321
+ - bash: Run shell commands (primary tool). Install packages as needed.
322
+ - read: Read files
323
+ - write: Create/overwrite files
324
+ - edit: Surgical file edits
325
+ - attach: Share files to Slack
326
+
327
+ Each tool requires a "label" parameter (shown to user).
328
+ `;
329
+ }
330
+
331
+ function truncate(text: string, maxLen: number): string {
332
+ if (text.length <= maxLen) return text;
333
+ return `${text.substring(0, maxLen - 3)}...`;
334
+ }
335
+
336
+ function extractToolResultText(result: unknown): string {
337
+ if (typeof result === "string") {
338
+ return result;
339
+ }
340
+
341
+ if (
342
+ result &&
343
+ typeof result === "object" &&
344
+ "content" in result &&
345
+ Array.isArray((result as { content: unknown }).content)
346
+ ) {
347
+ const content = (result as { content: Array<{ type: string; text?: string }> }).content;
348
+ const textParts: string[] = [];
349
+ for (const part of content) {
350
+ if (part.type === "text" && part.text) {
351
+ textParts.push(part.text);
352
+ }
353
+ }
354
+ if (textParts.length > 0) {
355
+ return textParts.join("\n");
356
+ }
357
+ }
358
+
359
+ return JSON.stringify(result);
360
+ }
361
+
362
+ function formatToolArgsForSlack(_toolName: string, args: Record<string, unknown>): string {
363
+ const lines: string[] = [];
364
+
365
+ for (const [key, value] of Object.entries(args)) {
366
+ if (key === "label") continue;
367
+
368
+ if (key === "path" && typeof value === "string") {
369
+ const offset = args.offset as number | undefined;
370
+ const limit = args.limit as number | undefined;
371
+ if (offset !== undefined && limit !== undefined) {
372
+ lines.push(`${value}:${offset}-${offset + limit}`);
373
+ } else {
374
+ lines.push(value);
375
+ }
376
+ continue;
377
+ }
378
+
379
+ if (key === "offset" || key === "limit") continue;
380
+
381
+ if (typeof value === "string") {
382
+ lines.push(value);
383
+ } else {
384
+ lines.push(JSON.stringify(value));
385
+ }
386
+ }
387
+
388
+ return lines.join("\n");
389
+ }
390
+
391
+ // Cache runners per channel
392
+ const channelRunners = new Map<string, AgentRunner>();
393
+
394
+ /**
395
+ * Get or create an AgentRunner for a channel.
396
+ * Runners are cached - one per channel, persistent across messages.
397
+ */
398
+ export function getOrCreateRunner(sandboxConfig: SandboxConfig, channelId: string, channelDir: string): AgentRunner {
399
+ const existing = channelRunners.get(channelId);
400
+ if (existing) return existing;
401
+
402
+ const runner = createRunner(sandboxConfig, channelId, channelDir);
403
+ channelRunners.set(channelId, runner);
404
+ return runner;
405
+ }
406
+
407
+ /**
408
+ * Create a new AgentRunner for a channel.
409
+ * Sets up the session and subscribes to events once.
410
+ */
411
+ function createRunner(sandboxConfig: SandboxConfig, channelId: string, channelDir: string): AgentRunner {
412
+ const executor = createExecutor(sandboxConfig);
413
+ const workspacePath = executor.getWorkspacePath(channelDir.replace(`/${channelId}`, ""));
414
+
415
+ // Create tools
416
+ const tools = createMomTools(executor);
417
+
418
+ // Initial system prompt (will be updated each run with fresh memory/channels/users/skills)
419
+ const memory = getMemory(channelDir);
420
+ const skills = loadMomSkills(channelDir, workspacePath);
421
+ const systemPrompt = buildSystemPrompt(workspacePath, channelId, memory, sandboxConfig, [], [], skills);
422
+
423
+ // Create session manager and settings manager
424
+ // Use a fixed context.jsonl file per channel (not timestamped like coding-agent)
425
+ const contextFile = join(channelDir, "context.jsonl");
426
+ const sessionManager = SessionManager.open(contextFile, channelDir);
427
+ const settingsManager = createMomSettingsManager(join(channelDir, ".."));
428
+
429
+ // Create AuthStorage and ModelRegistry
430
+ // Auth stored outside workspace so agent can't access it
431
+ const authStorage = AuthStorage.create(join(homedir(), ".pi", "mom", "auth.json"));
432
+ const modelRegistry = ModelRegistry.create(authStorage);
433
+
434
+ // Create agent
435
+ const agent = new Agent({
436
+ initialState: {
437
+ systemPrompt,
438
+ model,
439
+ thinkingLevel: "off",
440
+ tools,
441
+ },
442
+ convertToLlm,
443
+ getApiKey: async () => getAnthropicApiKey(authStorage),
444
+ });
445
+
446
+ // Load existing messages
447
+ const loadedSession = sessionManager.buildSessionContext();
448
+ if (loadedSession.messages.length > 0) {
449
+ agent.state.messages = loadedSession.messages;
450
+ log.logInfo(`[${channelId}] Loaded ${loadedSession.messages.length} messages from context.jsonl`);
451
+ }
452
+
453
+ const resourceLoader: ResourceLoader = {
454
+ getExtensions: () => ({ extensions: [], errors: [], runtime: createExtensionRuntime() }),
455
+ getSkills: () => ({ skills: [], diagnostics: [] }),
456
+ getPrompts: () => ({ prompts: [], diagnostics: [] }),
457
+ getThemes: () => ({ themes: [], diagnostics: [] }),
458
+ getAgentsFiles: () => ({ agentsFiles: [] }),
459
+ getSystemPrompt: () => systemPrompt,
460
+ getAppendSystemPrompt: () => [],
461
+ extendResources: () => {},
462
+ reload: async () => {},
463
+ };
464
+
465
+ const baseToolsOverride = Object.fromEntries(tools.map((tool) => [tool.name, tool]));
466
+
467
+ // Create AgentSession wrapper
468
+ const session = new AgentSession({
469
+ agent,
470
+ sessionManager,
471
+ settingsManager,
472
+ cwd: process.cwd(),
473
+ modelRegistry,
474
+ resourceLoader,
475
+ baseToolsOverride,
476
+ });
477
+
478
+ // Mutable per-run state - event handler references this
479
+ const runState = {
480
+ ctx: null as SlackContext | null,
481
+ logCtx: null as { channelId: string; userName?: string; channelName?: string } | null,
482
+ queue: null as {
483
+ enqueue(fn: () => Promise<void>, errorContext: string): void;
484
+ enqueueMessage(text: string, target: "main" | "thread", errorContext: string, doLog?: boolean): void;
485
+ } | null,
486
+ pendingTools: new Map<string, { toolName: string; args: unknown; startTime: number }>(),
487
+ totalUsage: {
488
+ input: 0,
489
+ output: 0,
490
+ cacheRead: 0,
491
+ cacheWrite: 0,
492
+ cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
493
+ },
494
+ stopReason: "stop",
495
+ errorMessage: undefined as string | undefined,
496
+ };
497
+
498
+ // Subscribe to events ONCE
499
+ session.subscribe(async (event) => {
500
+ // Skip if no active run
501
+ if (!runState.ctx || !runState.logCtx || !runState.queue) return;
502
+
503
+ const { ctx, logCtx, queue, pendingTools } = runState;
504
+
505
+ if (event.type === "tool_execution_start") {
506
+ const agentEvent = event as AgentEvent & { type: "tool_execution_start" };
507
+ const args = agentEvent.args as { label?: string };
508
+ const label = args.label || agentEvent.toolName;
509
+
510
+ pendingTools.set(agentEvent.toolCallId, {
511
+ toolName: agentEvent.toolName,
512
+ args: agentEvent.args,
513
+ startTime: Date.now(),
514
+ });
515
+
516
+ log.logToolStart(logCtx, agentEvent.toolName, label, agentEvent.args as Record<string, unknown>);
517
+ queue.enqueue(() => ctx.respond(`_→ ${label}_`, false), "tool label");
518
+ } else if (event.type === "tool_execution_end") {
519
+ const agentEvent = event as AgentEvent & { type: "tool_execution_end" };
520
+ const resultStr = extractToolResultText(agentEvent.result);
521
+ const pending = pendingTools.get(agentEvent.toolCallId);
522
+ pendingTools.delete(agentEvent.toolCallId);
523
+
524
+ const durationMs = pending ? Date.now() - pending.startTime : 0;
525
+
526
+ if (agentEvent.isError) {
527
+ log.logToolError(logCtx, agentEvent.toolName, durationMs, resultStr);
528
+ } else {
529
+ log.logToolSuccess(logCtx, agentEvent.toolName, durationMs, resultStr);
530
+ }
531
+
532
+ // Post args + result to thread
533
+ const label = pending?.args ? (pending.args as { label?: string }).label : undefined;
534
+ const argsFormatted = pending
535
+ ? formatToolArgsForSlack(agentEvent.toolName, pending.args as Record<string, unknown>)
536
+ : "(args not found)";
537
+ const duration = (durationMs / 1000).toFixed(1);
538
+ let threadMessage = `*${agentEvent.isError ? "✗" : "✓"} ${agentEvent.toolName}*`;
539
+ if (label) threadMessage += `: ${label}`;
540
+ threadMessage += ` (${duration}s)\n`;
541
+ if (argsFormatted) threadMessage += `\`\`\`\n${argsFormatted}\n\`\`\`\n`;
542
+ threadMessage += `*Result:*\n\`\`\`\n${resultStr}\n\`\`\``;
543
+
544
+ queue.enqueueMessage(threadMessage, "thread", "tool result thread", false);
545
+
546
+ if (agentEvent.isError) {
547
+ queue.enqueue(() => ctx.respond(`_Error: ${truncate(resultStr, 200)}_`, false), "tool error");
548
+ }
549
+ } else if (event.type === "message_start") {
550
+ const agentEvent = event as AgentEvent & { type: "message_start" };
551
+ if (agentEvent.message.role === "assistant") {
552
+ log.logResponseStart(logCtx);
553
+ }
554
+ } else if (event.type === "message_end") {
555
+ const agentEvent = event as AgentEvent & { type: "message_end" };
556
+ if (agentEvent.message.role === "assistant") {
557
+ const assistantMsg = agentEvent.message as any;
558
+
559
+ if (assistantMsg.stopReason) {
560
+ runState.stopReason = assistantMsg.stopReason;
561
+ }
562
+ if (assistantMsg.errorMessage) {
563
+ runState.errorMessage = assistantMsg.errorMessage;
564
+ }
565
+
566
+ if (assistantMsg.usage) {
567
+ runState.totalUsage.input += assistantMsg.usage.input;
568
+ runState.totalUsage.output += assistantMsg.usage.output;
569
+ runState.totalUsage.cacheRead += assistantMsg.usage.cacheRead;
570
+ runState.totalUsage.cacheWrite += assistantMsg.usage.cacheWrite;
571
+ runState.totalUsage.cost.input += assistantMsg.usage.cost.input;
572
+ runState.totalUsage.cost.output += assistantMsg.usage.cost.output;
573
+ runState.totalUsage.cost.cacheRead += assistantMsg.usage.cost.cacheRead;
574
+ runState.totalUsage.cost.cacheWrite += assistantMsg.usage.cost.cacheWrite;
575
+ runState.totalUsage.cost.total += assistantMsg.usage.cost.total;
576
+ }
577
+
578
+ const content = agentEvent.message.content;
579
+ const thinkingParts: string[] = [];
580
+ const textParts: string[] = [];
581
+ for (const part of content) {
582
+ if (part.type === "thinking") {
583
+ thinkingParts.push((part as any).thinking);
584
+ } else if (part.type === "text") {
585
+ textParts.push((part as any).text);
586
+ }
587
+ }
588
+
589
+ const text = textParts.join("\n");
590
+
591
+ for (const thinking of thinkingParts) {
592
+ log.logThinking(logCtx, thinking);
593
+ queue.enqueueMessage(`_${thinking}_`, "main", "thinking main");
594
+ queue.enqueueMessage(`_${thinking}_`, "thread", "thinking thread", false);
595
+ }
596
+
597
+ if (text.trim()) {
598
+ log.logResponse(logCtx, text);
599
+ queue.enqueueMessage(text, "main", "response main");
600
+ queue.enqueueMessage(text, "thread", "response thread", false);
601
+ }
602
+ }
603
+ } else if (event.type === "compaction_start") {
604
+ log.logInfo(`Compaction started (reason: ${event.reason})`);
605
+ queue.enqueue(() => ctx.respond("_Compacting context..._", false), "compaction start");
606
+ } else if (event.type === "compaction_end") {
607
+ if (event.result) {
608
+ log.logInfo(`Compaction complete: ${event.result.tokensBefore} tokens compacted`);
609
+ } else if (event.aborted) {
610
+ log.logInfo("Compaction aborted");
611
+ }
612
+ } else if (event.type === "auto_retry_start") {
613
+ const retryEvent = event as any;
614
+ log.logWarning(`Retrying (${retryEvent.attempt}/${retryEvent.maxAttempts})`, retryEvent.errorMessage);
615
+ queue.enqueue(
616
+ () => ctx.respond(`_Retrying (${retryEvent.attempt}/${retryEvent.maxAttempts})..._`, false),
617
+ "retry",
618
+ );
619
+ }
620
+ });
621
+
622
+ // Slack message limit
623
+ const SLACK_MAX_LENGTH = 40000;
624
+ const splitForSlack = (text: string): string[] => {
625
+ if (text.length <= SLACK_MAX_LENGTH) return [text];
626
+ const parts: string[] = [];
627
+ let remaining = text;
628
+ let partNum = 1;
629
+ while (remaining.length > 0) {
630
+ const chunk = remaining.substring(0, SLACK_MAX_LENGTH - 50);
631
+ remaining = remaining.substring(SLACK_MAX_LENGTH - 50);
632
+ const suffix = remaining.length > 0 ? `\n_(continued ${partNum}...)_` : "";
633
+ parts.push(chunk + suffix);
634
+ partNum++;
635
+ }
636
+ return parts;
637
+ };
638
+
639
+ return {
640
+ async run(
641
+ ctx: SlackContext,
642
+ _store: ChannelStore,
643
+ _pendingMessages?: PendingMessage[],
644
+ ): Promise<{ stopReason: string; errorMessage?: string }> {
645
+ // Ensure channel directory exists
646
+ await mkdir(channelDir, { recursive: true });
647
+
648
+ // Sync messages from log.jsonl that arrived while we were offline or busy
649
+ // Exclude the current message (it will be added via prompt())
650
+ const syncedCount = syncLogToSessionManager(sessionManager, channelDir, ctx.message.ts);
651
+ if (syncedCount > 0) {
652
+ log.logInfo(`[${channelId}] Synced ${syncedCount} messages from log.jsonl`);
653
+ }
654
+
655
+ // Reload messages from context.jsonl
656
+ // This picks up any messages synced above
657
+ const reloadedSession = sessionManager.buildSessionContext();
658
+ if (reloadedSession.messages.length > 0) {
659
+ agent.state.messages = reloadedSession.messages;
660
+ log.logInfo(`[${channelId}] Reloaded ${reloadedSession.messages.length} messages from context`);
661
+ }
662
+
663
+ // Update system prompt with fresh memory, channel/user info, and skills
664
+ const memory = getMemory(channelDir);
665
+ const skills = loadMomSkills(channelDir, workspacePath);
666
+ const systemPrompt = buildSystemPrompt(
667
+ workspacePath,
668
+ channelId,
669
+ memory,
670
+ sandboxConfig,
671
+ ctx.channels,
672
+ ctx.users,
673
+ skills,
674
+ );
675
+ session.agent.state.systemPrompt = systemPrompt;
676
+
677
+ // Set up file upload function
678
+ setUploadFunction(async (filePath: string, title?: string) => {
679
+ const hostPath = translateToHostPath(filePath, channelDir, workspacePath, channelId);
680
+ await ctx.uploadFile(hostPath, title);
681
+ });
682
+
683
+ // Reset per-run state
684
+ runState.ctx = ctx;
685
+ runState.logCtx = {
686
+ channelId: ctx.message.channel,
687
+ userName: ctx.message.userName,
688
+ channelName: ctx.channelName,
689
+ };
690
+ runState.pendingTools.clear();
691
+ runState.totalUsage = {
692
+ input: 0,
693
+ output: 0,
694
+ cacheRead: 0,
695
+ cacheWrite: 0,
696
+ cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
697
+ };
698
+ runState.stopReason = "stop";
699
+ runState.errorMessage = undefined;
700
+
701
+ // Create queue for this run
702
+ let queueChain = Promise.resolve();
703
+ runState.queue = {
704
+ enqueue(fn: () => Promise<void>, errorContext: string): void {
705
+ queueChain = queueChain.then(async () => {
706
+ try {
707
+ await fn();
708
+ } catch (err) {
709
+ const errMsg = err instanceof Error ? err.message : String(err);
710
+ log.logWarning(`Slack API error (${errorContext})`, errMsg);
711
+ try {
712
+ await ctx.respondInThread(`_Error: ${errMsg}_`);
713
+ } catch {
714
+ // Ignore
715
+ }
716
+ }
717
+ });
718
+ },
719
+ enqueueMessage(text: string, target: "main" | "thread", errorContext: string, doLog = true): void {
720
+ const parts = splitForSlack(text);
721
+ for (const part of parts) {
722
+ this.enqueue(
723
+ () => (target === "main" ? ctx.respond(part, doLog) : ctx.respondInThread(part)),
724
+ errorContext,
725
+ );
726
+ }
727
+ },
728
+ };
729
+
730
+ // Log context info
731
+ log.logInfo(`Context sizes - system: ${systemPrompt.length} chars, memory: ${memory.length} chars`);
732
+ log.logInfo(`Channels: ${ctx.channels.length}, Users: ${ctx.users.length}`);
733
+
734
+ // Build user message with timestamp and username prefix
735
+ // Format: "[YYYY-MM-DD HH:MM:SS+HH:MM] [username]: message" so LLM knows when and who
736
+ const now = new Date();
737
+ const pad = (n: number) => n.toString().padStart(2, "0");
738
+ const offset = -now.getTimezoneOffset();
739
+ const offsetSign = offset >= 0 ? "+" : "-";
740
+ const offsetHours = pad(Math.floor(Math.abs(offset) / 60));
741
+ const offsetMins = pad(Math.abs(offset) % 60);
742
+ const timestamp = `${now.getFullYear()}-${pad(now.getMonth() + 1)}-${pad(now.getDate())} ${pad(now.getHours())}:${pad(now.getMinutes())}:${pad(now.getSeconds())}${offsetSign}${offsetHours}:${offsetMins}`;
743
+ let userMessage = `[${timestamp}] [${ctx.message.userName || "unknown"}]: ${ctx.message.text}`;
744
+
745
+ const imageAttachments: ImageContent[] = [];
746
+ const nonImagePaths: string[] = [];
747
+
748
+ for (const a of ctx.message.attachments || []) {
749
+ const fullPath = `${workspacePath}/${a.local}`;
750
+ const mimeType = getImageMimeType(a.local);
751
+
752
+ if (mimeType && existsSync(fullPath)) {
753
+ try {
754
+ imageAttachments.push({
755
+ type: "image",
756
+ mimeType,
757
+ data: readFileSync(fullPath).toString("base64"),
758
+ });
759
+ } catch {
760
+ nonImagePaths.push(fullPath);
761
+ }
762
+ } else {
763
+ nonImagePaths.push(fullPath);
764
+ }
765
+ }
766
+
767
+ if (nonImagePaths.length > 0) {
768
+ userMessage += `\n\n<slack_attachments>\n${nonImagePaths.join("\n")}\n</slack_attachments>`;
769
+ }
770
+
771
+ // Debug: write context to last_prompt.jsonl
772
+ const debugContext = {
773
+ systemPrompt,
774
+ messages: session.messages,
775
+ newUserMessage: userMessage,
776
+ imageAttachmentCount: imageAttachments.length,
777
+ };
778
+ await writeFile(join(channelDir, "last_prompt.jsonl"), JSON.stringify(debugContext, null, 2));
779
+
780
+ await session.prompt(userMessage, imageAttachments.length > 0 ? { images: imageAttachments } : undefined);
781
+
782
+ // Wait for queued messages
783
+ await queueChain;
784
+
785
+ // Handle error case - update main message and post error to thread
786
+ if (runState.stopReason === "error" && runState.errorMessage) {
787
+ try {
788
+ await ctx.replaceMessage("_Sorry, something went wrong_");
789
+ await ctx.respondInThread(`_Error: ${runState.errorMessage}_`);
790
+ } catch (err) {
791
+ const errMsg = err instanceof Error ? err.message : String(err);
792
+ log.logWarning("Failed to post error message", errMsg);
793
+ }
794
+ } else {
795
+ // Final message update
796
+ const messages = session.messages;
797
+ const lastAssistant = messages.filter((m) => m.role === "assistant").pop();
798
+ const finalText =
799
+ lastAssistant?.content
800
+ .filter((c): c is { type: "text"; text: string } => c.type === "text")
801
+ .map((c) => c.text)
802
+ .join("\n") || "";
803
+
804
+ // Check for [SILENT] marker - delete message and thread instead of posting
805
+ if (finalText.trim() === "[SILENT]" || finalText.trim().startsWith("[SILENT]")) {
806
+ try {
807
+ await ctx.deleteMessage();
808
+ log.logInfo("Silent response - deleted message and thread");
809
+ } catch (err) {
810
+ const errMsg = err instanceof Error ? err.message : String(err);
811
+ log.logWarning("Failed to delete message for silent response", errMsg);
812
+ }
813
+ } else if (finalText.trim()) {
814
+ try {
815
+ const mainText =
816
+ finalText.length > SLACK_MAX_LENGTH
817
+ ? `${finalText.substring(0, SLACK_MAX_LENGTH - 50)}\n\n_(see thread for full response)_`
818
+ : finalText;
819
+ await ctx.replaceMessage(mainText);
820
+ } catch (err) {
821
+ const errMsg = err instanceof Error ? err.message : String(err);
822
+ log.logWarning("Failed to replace message with final text", errMsg);
823
+ }
824
+ }
825
+ }
826
+
827
+ // Log usage summary with context info
828
+ if (runState.totalUsage.cost.total > 0) {
829
+ // Get last non-aborted assistant message for context calculation
830
+ const messages = session.messages;
831
+ const lastAssistantMessage = messages
832
+ .slice()
833
+ .reverse()
834
+ .find((m) => m.role === "assistant" && (m as any).stopReason !== "aborted") as any;
835
+
836
+ const contextTokens = lastAssistantMessage
837
+ ? lastAssistantMessage.usage.input +
838
+ lastAssistantMessage.usage.output +
839
+ lastAssistantMessage.usage.cacheRead +
840
+ lastAssistantMessage.usage.cacheWrite
841
+ : 0;
842
+ const contextWindow = model.contextWindow || 200000;
843
+
844
+ const summary = log.logUsageSummary(runState.logCtx!, runState.totalUsage, contextTokens, contextWindow);
845
+ runState.queue.enqueue(() => ctx.respondInThread(summary), "usage summary");
846
+ await queueChain;
847
+ }
848
+
849
+ // Clear run state
850
+ runState.ctx = null;
851
+ runState.logCtx = null;
852
+ runState.queue = null;
853
+
854
+ return { stopReason: runState.stopReason, errorMessage: runState.errorMessage };
855
+ },
856
+
857
+ abort(): void {
858
+ session.abort();
859
+ },
860
+ };
861
+ }
862
+
863
+ /**
864
+ * Translate container path back to host path for file operations
865
+ */
866
+ function translateToHostPath(
867
+ containerPath: string,
868
+ channelDir: string,
869
+ workspacePath: string,
870
+ channelId: string,
871
+ ): string {
872
+ if (workspacePath === "/workspace") {
873
+ const prefix = `/workspace/${channelId}/`;
874
+ if (containerPath.startsWith(prefix)) {
875
+ return join(channelDir, containerPath.slice(prefix.length));
876
+ }
877
+ if (containerPath.startsWith("/workspace/")) {
878
+ return join(channelDir, "..", containerPath.slice("/workspace/".length));
879
+ }
880
+ }
881
+ return containerPath;
882
+ }