pi-usereq 0.6.0 → 0.10.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 (774) hide show
  1. package/.gitignore +2 -0
  2. package/CHANGELOG.md +44 -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 +2658 -2035
  21. package/pi-usereq/docs/REQUIREMENTS.md +345 -191
  22. package/pi-usereq/docs/WORKFLOW.md +387 -363
  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 +546 -65
  699. package/src/core/debug-runtime.ts +542 -0
  700. package/src/core/extension-status.ts +324 -202
  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 +585 -315
  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 +1650 -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/settings-menu.ts +33 -7
  713. package/src/core/source-analyzer.ts +27 -7
  714. package/src/core/token-counter.ts +61 -79
  715. package/src/core/tool-runner.ts +38 -317
  716. package/src/index.ts +2629 -1220
  717. package/src/resources/images/favicon.svg +21 -0
  718. package/src/resources/images/pi.dev.png +0 -0
  719. package/src/resources/instructions/git_commit.md +16 -0
  720. package/src/resources/instructions/git_read-only.md +2 -0
  721. package/src/resources/prompts/analyze.md +12 -13
  722. package/src/resources/prompts/change.md +21 -59
  723. package/src/resources/prompts/check.md +14 -16
  724. package/src/resources/prompts/cover.md +21 -59
  725. package/src/resources/prompts/create.md +5 -4
  726. package/src/resources/prompts/fix.md +20 -58
  727. package/src/resources/prompts/flowchart.md +14 -49
  728. package/src/resources/prompts/implement.md +14 -50
  729. package/src/resources/prompts/new.md +20 -58
  730. package/src/resources/prompts/readme.md +14 -50
  731. package/src/resources/prompts/recreate.md +14 -45
  732. package/src/resources/prompts/refactor.md +20 -58
  733. package/src/resources/prompts/references.md +7 -43
  734. package/src/resources/prompts/renumber.md +8 -39
  735. package/src/resources/prompts/workflow.md +14 -50
  736. package/src/resources/prompts/write.md +5 -4
  737. package/tests/attended-results-scenarios.ts +30 -136
  738. package/tests/cli-command-option-parity.test.ts +148 -192
  739. package/tests/debug-extension-harness.test.ts +74 -73
  740. package/tests/extension-registration.test.ts +3626 -685
  741. package/tests/fixtures_attended_results/project/compress-line-numbers.json +1 -1
  742. package/tests/fixtures_attended_results/project/compress.json +1 -1
  743. package/tests/fixtures_attended_results/project/find-line-numbers.json +1 -1
  744. package/tests/fixtures_attended_results/project/find.json +1 -1
  745. package/tests/fixtures_attended_results/project/references.json +2 -2
  746. package/tests/fixtures_attended_results/standalone/files-compress/fixture_go.go.json +1 -1
  747. package/tests/fixtures_attended_results/standalone/files-compress-line-numbers/fixture_go.go.json +1 -1
  748. package/tests/fixtures_attended_results/standalone/files-find/fixture_go.go.json +1 -1
  749. package/tests/fixtures_attended_results/standalone/files-find-line-numbers/fixture_go.go.json +1 -1
  750. package/tests/fixtures_attended_results/standalone/files-references/fixture_c.c.json +1 -1
  751. package/tests/fixtures_attended_results/standalone/files-references/fixture_cpp.cpp.json +1 -1
  752. package/tests/fixtures_attended_results/standalone/files-references/fixture_csharp.cs.json +1 -1
  753. package/tests/fixtures_attended_results/standalone/files-references/fixture_elixir.ex.json +1 -1
  754. package/tests/fixtures_attended_results/standalone/files-references/fixture_go.go.json +1 -1
  755. package/tests/fixtures_attended_results/standalone/files-references/fixture_haskell.hs.json +1 -1
  756. package/tests/fixtures_attended_results/standalone/files-references/fixture_java.java.json +1 -1
  757. package/tests/fixtures_attended_results/standalone/files-references/fixture_javascript.js.json +1 -1
  758. package/tests/fixtures_attended_results/standalone/files-references/fixture_kotlin.kt.json +1 -1
  759. package/tests/fixtures_attended_results/standalone/files-references/fixture_lua.lua.json +1 -1
  760. package/tests/fixtures_attended_results/standalone/files-references/fixture_perl.pl.json +1 -1
  761. package/tests/fixtures_attended_results/standalone/files-references/fixture_php.php.json +1 -1
  762. package/tests/fixtures_attended_results/standalone/files-references/fixture_python.py.json +1 -1
  763. package/tests/fixtures_attended_results/standalone/files-references/fixture_ruby.rb.json +1 -1
  764. package/tests/fixtures_attended_results/standalone/files-references/fixture_rust.rs.json +1 -1
  765. package/tests/fixtures_attended_results/standalone/files-references/fixture_scala.scala.json +1 -1
  766. package/tests/fixtures_attended_results/standalone/files-references/fixture_shell.sh.json +1 -1
  767. package/tests/fixtures_attended_results/standalone/files-references/fixture_swift.swift.json +1 -1
  768. package/tests/fixtures_attended_results/standalone/files-references/fixture_typescript.ts.json +1 -1
  769. package/tests/fixtures_attended_results/standalone/files-references/fixture_zig.zig.json +1 -1
  770. package/tests/helpers.ts +24 -15
  771. package/tests/oracle-project.test.ts +29 -30
  772. package/tests/oracle-standalone.test.ts +27 -1
  773. package/tests/prompt-rendering.test.ts +40 -9
  774. package/tests/python_oracle_stubs/tiktoken.py +76 -0
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * @file
3
3
  * @brief Loads, normalizes, and persists pi-usereq project configuration.
4
- * @details Defines the configuration schema, default directory conventions, JSON serialization helpers, and prompt placeholder expansion paths. Runtime is dominated by filesystem reads and writes plus linear normalization over configured entries. Side effects include config-file persistence under `.pi-usereq`.
4
+ * @details Defines the configuration schema, default directory conventions, JSON serialization helpers, and prompt placeholder expansion paths. Runtime is dominated by filesystem reads and writes plus linear normalization over configured entries. Side effects include config-file persistence under `.pi-usereq.json`.
5
5
  */
6
6
 
7
7
  import fs from "node:fs";
@@ -12,18 +12,38 @@ import {
12
12
  buildRuntimePathFacts,
13
13
  formatRuntimePathForDisplay,
14
14
  getConfigPath,
15
+ normalizeRelativeDirContract,
15
16
  } from "./path-context.js";
16
17
  import {
18
+ DEFAULT_PI_NOTIFY_CMD,
19
+ DEFAULT_PI_NOTIFY_PUSHOVER_TEXT,
20
+ DEFAULT_PI_NOTIFY_PUSHOVER_TITLE,
17
21
  DEFAULT_PI_NOTIFY_SOUND_HIGH_CMD,
18
22
  DEFAULT_PI_NOTIFY_SOUND_LOW_CMD,
19
23
  DEFAULT_PI_NOTIFY_SOUND_MID_CMD,
20
24
  DEFAULT_PI_NOTIFY_SOUND_TOGGLE_SHORTCUT,
25
+ hasPiNotifyPushoverCredentials,
21
26
  normalizePiNotifyCommand,
22
27
  normalizePiNotifyPushoverCredential,
23
28
  normalizePiNotifyPushoverPriority,
24
29
  normalizePiNotifyShortcut,
25
30
  normalizePiNotifySoundLevel,
31
+ normalizePiNotifyTemplateValue,
26
32
  } from "./pi-notify.js";
33
+ import {
34
+ DEFAULT_DEBUG_ENABLED,
35
+ DEFAULT_DEBUG_LOG_FILE,
36
+ DEFAULT_DEBUG_LOG_ON_STATUS,
37
+ DEFAULT_DEBUG_STATUS_CHANGES,
38
+ DEFAULT_DEBUG_WORKFLOW_EVENTS,
39
+ normalizeDebugEnabled,
40
+ normalizeDebugEnabledPrompts,
41
+ normalizeDebugEnabledTools,
42
+ normalizeDebugLogFile,
43
+ normalizeDebugLogOnStatus,
44
+ normalizeDebugStatusChanges,
45
+ normalizeDebugWorkflowEvents,
46
+ } from "./debug-runtime.js";
27
47
  import { normalizeEnabledPiUsereqTools } from "./pi-usereq-tools.js";
28
48
  import { makeRelativeIfContainsProject } from "./utils.js";
29
49
 
@@ -37,26 +57,60 @@ export interface StaticCheckEntry {
37
57
  params?: string[];
38
58
  }
39
59
 
60
+ /**
61
+ * @brief Represents the persisted per-language static-check enable flag.
62
+ * @details Narrows persisted per-language enablement to the documented `enable|disable` domain reused by configuration loading, menu toggles, and static-check dispatch. The alias is compile-time only and introduces no runtime cost.
63
+ */
64
+ export type StaticCheckEnabled = "enable" | "disable";
65
+
66
+ /**
67
+ * @brief Describes one persisted per-language static-check configuration object.
68
+ * @details Couples the per-language enable flag with the ordered checker-entry list so menu toggles, config serialization, and execution dispatch can distinguish configured-but-disabled languages from enabled active checker lists. The interface is compile-time only and introduces no runtime cost.
69
+ */
70
+ export interface StaticCheckLanguageConfig {
71
+ enabled: StaticCheckEnabled;
72
+ checkers: StaticCheckEntry[];
73
+ }
74
+
40
75
  /**
41
76
  * @brief Defines the persisted pi-usereq project configuration schema.
42
- * @details Captures documentation paths, source/test directory selection, static-check configuration, enabled startup tools, and notification settings while excluding runtime-derived path metadata. The interface is compile-time only and introduces no runtime side effects.
77
+ * @details Captures documentation paths, source/test directory selection, per-language static-check enablement and checker configuration, prompt-command worktree settings, enabled startup tools, and notification settings while excluding runtime-derived path metadata. The interface is compile-time only and introduces no runtime side effects.
43
78
  */
44
79
  export interface UseReqConfig {
45
80
  "docs-dir": string;
46
81
  "tests-dir": string;
47
82
  "src-dir": string[];
48
- "static-check": Record<string, StaticCheckEntry[]>;
83
+ "static-check": Record<string, StaticCheckLanguageConfig>;
49
84
  "enabled-tools": string[];
50
- "notify-beep-on-end": boolean;
51
- "notify-beep-on-esc": boolean;
52
- "notify-beep-on-error": boolean;
85
+ AUTO_GIT_COMMIT: "enable" | "disable";
86
+ GIT_WORKTREE_ENABLED: "enable" | "disable";
87
+ GIT_WORKTREE_PREFIX: string;
88
+ DEBUG_ENABLED: "enable" | "disable";
89
+ DEBUG_LOG_FILE: string;
90
+ DEBUG_STATUS_CHANGES: "enable" | "disable";
91
+ DEBUG_WORKFLOW_EVENTS: "enable" | "disable";
92
+ DEBUG_LOG_ON_STATUS: "any" | "idle" | "checking" | "running" | "merging" | "error";
93
+ DEBUG_ENABLED_TOOLS: string[];
94
+ DEBUG_ENABLED_PROMPTS: string[];
95
+ "notify-enabled": boolean;
96
+ "notify-on-completed": boolean;
97
+ "notify-on-interrupted": boolean;
98
+ "notify-on-failed": boolean;
53
99
  "notify-sound": "none" | "low" | "mid" | "high";
100
+ "notify-sound-on-completed": boolean;
101
+ "notify-sound-on-interrupted": boolean;
102
+ "notify-sound-on-failed": boolean;
54
103
  "notify-sound-toggle-shortcut": string;
55
- "notify-pushover-global-disable": boolean;
56
- "notify-pushover-on-success": boolean;
104
+ "notify-pushover-enabled": boolean;
105
+ "notify-pushover-on-completed": boolean;
106
+ "notify-pushover-on-interrupted": boolean;
107
+ "notify-pushover-on-failed": boolean;
57
108
  "notify-pushover-user-key": string;
58
109
  "notify-pushover-api-token": string;
59
110
  "notify-pushover-priority": 0 | 1;
111
+ "notify-pushover-title": string;
112
+ "notify-pushover-text": string;
113
+ PI_NOTIFY_CMD: string;
60
114
  PI_NOTIFY_SOUND_LOW_CMD: string;
61
115
  PI_NOTIFY_SOUND_MID_CMD: string;
62
116
  PI_NOTIFY_SOUND_HIGH_CMD: string;
@@ -78,9 +132,250 @@ export const DEFAULT_TESTS_DIR = "tests";
78
132
  * @details The array seeds newly created configs and repairs invalid persisted source selections. Access complexity is O(1).
79
133
  */
80
134
  export const DEFAULT_SRC_DIRS = ["src"];
135
+ /**
136
+ * @brief Defines the canonical supported static-check language order used by default config serialization.
137
+ * @details The array lists every supported user-configurable language exactly once so default config builders and config serializers can emit deterministic per-language records. Access complexity is O(1).
138
+ */
139
+ export const DEFAULT_STATIC_CHECK_LANGUAGES = [
140
+ "C",
141
+ "C#",
142
+ "C++",
143
+ "Elixir",
144
+ "Go",
145
+ "Haskell",
146
+ "Java",
147
+ "JavaScript",
148
+ "Kotlin",
149
+ "Lua",
150
+ "Perl",
151
+ "PHP",
152
+ "Python",
153
+ "Ruby",
154
+ "Rust",
155
+ "Scala",
156
+ "Shell",
157
+ "Swift",
158
+ "TypeScript",
159
+ "Zig",
160
+ ] as const;
161
+
162
+ /**
163
+ * @brief Defines the default static-check entries per language.
164
+ * @details Seeds the documented default Command checker lists for enabled-by-default languages while languages omitted from the map default to empty checker lists. Access complexity is O(1).
165
+ * @satisfies REQ-250, REQ-251, REQ-252
166
+ */
167
+ const DEFAULT_STATIC_CHECK_CHECKERS: Record<string, StaticCheckEntry[]> = {
168
+ C: [
169
+ {
170
+ module: "Command",
171
+ cmd: "cppcheck",
172
+ params: [
173
+ "--error-exitcode=1",
174
+ "--enable=warning,style,performance,portability",
175
+ "--std=c11",
176
+ ],
177
+ },
178
+ {
179
+ module: "Command",
180
+ cmd: "clang-format",
181
+ params: ["--dry-run", "--Werror"],
182
+ },
183
+ ],
184
+ "C++": [
185
+ {
186
+ module: "Command",
187
+ cmd: "cppcheck",
188
+ params: [
189
+ "--error-exitcode=1",
190
+ "--enable=warning,style,performance,portability",
191
+ "--std=c++20",
192
+ ],
193
+ },
194
+ {
195
+ module: "Command",
196
+ cmd: "clang-format",
197
+ params: ["--dry-run", "--Werror"],
198
+ },
199
+ ],
200
+ Python: [
201
+ {
202
+ module: "Command",
203
+ cmd: "pyright",
204
+ params: ["--outputjson"],
205
+ },
206
+ {
207
+ module: "Command",
208
+ cmd: "ruff",
209
+ params: ["check"],
210
+ },
211
+ ],
212
+ JavaScript: [
213
+ {
214
+ module: "Command",
215
+ cmd: "node",
216
+ params: ["--check"],
217
+ },
218
+ ],
219
+ TypeScript: [
220
+ {
221
+ module: "Command",
222
+ cmd: "npx",
223
+ params: ["eslint"],
224
+ },
225
+ ],
226
+ };
227
+
228
+ /**
229
+ * @brief Clones one static-check entry into its persisted shape.
230
+ * @details Copies only the stable module, cmd, and params fields so runtime-only or unknown metadata never leaks into persisted configuration payloads. Runtime is O(p) in parameter count. No external state is mutated.
231
+ * @param[in] entry {StaticCheckEntry} Source static-check entry.
232
+ * @return {StaticCheckEntry} Persistable static-check entry clone.
233
+ */
234
+ function cloneStaticCheckEntry(entry: StaticCheckEntry): StaticCheckEntry {
235
+ const params = Array.isArray(entry.params)
236
+ ? entry.params.map((value) => String(value)).filter((value) => value.trim().length > 0)
237
+ : [];
238
+ return {
239
+ module: String(entry.module ?? ""),
240
+ ...(typeof entry.cmd === "string" && entry.cmd.trim() ? { cmd: entry.cmd.trim() } : {}),
241
+ ...(params.length > 0 ? { params } : {}),
242
+ };
243
+ }
244
+
245
+ /**
246
+ * @brief Builds one per-language static-check configuration object.
247
+ * @details Clones the supplied checker entries, derives `enabled` from the explicit argument or checker-list emptiness, and preserves checker order for menu and dispatch determinism. Runtime is O(c + p). No external state is mutated.
248
+ * @param[in] checkers {StaticCheckEntry[]} Ordered checker entries.
249
+ * @param[in] enabled {StaticCheckEnabled | undefined} Optional explicit enable flag.
250
+ * @return {StaticCheckLanguageConfig} Normalized per-language config object.
251
+ */
252
+ export function createStaticCheckLanguageConfig(
253
+ checkers: StaticCheckEntry[],
254
+ enabled?: StaticCheckEnabled,
255
+ ): StaticCheckLanguageConfig {
256
+ const normalizedCheckers = checkers.map(cloneStaticCheckEntry);
257
+ return {
258
+ enabled: enabled ?? (normalizedCheckers.length > 0 ? "enable" : "disable"),
259
+ checkers: normalizedCheckers,
260
+ };
261
+ }
262
+
263
+ /**
264
+ * @brief Returns the documented default static-check configuration.
265
+ * @details Emits one per-language config object for every supported language, enabling only languages with documented default checker entries and leaving all remaining languages disabled with empty checker lists. Runtime is O(l + c). No external state is mutated.
266
+ * @return {Record<string, StaticCheckLanguageConfig>} Fresh default static-check config.
267
+ * @satisfies REQ-249, REQ-250, REQ-251, REQ-252
268
+ */
269
+ export function getDefaultStaticCheckConfig(): Record<string, StaticCheckLanguageConfig> {
270
+ return Object.fromEntries(DEFAULT_STATIC_CHECK_LANGUAGES.map((language) => [
271
+ language,
272
+ createStaticCheckLanguageConfig(DEFAULT_STATIC_CHECK_CHECKERS[language] ?? []),
273
+ ]));
274
+ }
275
+
276
+ /**
277
+ * @brief Normalizes one persisted per-language static-check enable flag.
278
+ * @details Accepts only the documented `enable|disable` values and falls back to the supplied default when the candidate is absent or invalid. Runtime is O(1). No external state is mutated.
279
+ * @param[in] value {unknown} Candidate persisted enable flag.
280
+ * @param[in] defaultValue {StaticCheckEnabled} Fallback enable flag.
281
+ * @return {StaticCheckEnabled} Canonical per-language enable flag.
282
+ * @satisfies REQ-249
283
+ */
284
+ export function normalizeStaticCheckEnabled(
285
+ value: unknown,
286
+ defaultValue: StaticCheckEnabled,
287
+ ): StaticCheckEnabled {
288
+ return value === "enable" || value === "disable" ? value : defaultValue;
289
+ }
290
+
291
+ /**
292
+ * @brief Resolves the active checker list for one language.
293
+ * @details Returns the persisted checker list only when the language is enabled; disabled or missing languages yield an empty list without mutating the source config. Runtime is O(c). No external state is mutated.
294
+ * @param[in] staticCheckConfig {Record<string, StaticCheckLanguageConfig>} Effective static-check config.
295
+ * @param[in] language {string} Canonical language name.
296
+ * @return {StaticCheckEntry[]} Active checker list for the language.
297
+ * @satisfies REQ-019
298
+ */
299
+ export function getActiveStaticCheckEntries(
300
+ staticCheckConfig: Record<string, StaticCheckLanguageConfig>,
301
+ language: string,
302
+ ): StaticCheckEntry[] {
303
+ const languageConfig = staticCheckConfig[language];
304
+ if (!languageConfig || languageConfig.enabled !== "enable") {
305
+ return [];
306
+ }
307
+ return languageConfig.checkers.map(cloneStaticCheckEntry);
308
+ }
309
+
310
+ /**
311
+ * @brief Defines the default automatic git-commit prompt mode.
312
+ * @details New project configs enable bundled commit-instruction injection unless the persisted project config explicitly disables it. Access complexity is O(1).
313
+ * @satisfies CTN-001, REQ-212
314
+ */
315
+ export const DEFAULT_AUTO_GIT_COMMIT = "enable" as const;
316
+ /**
317
+ * @brief Normalizes one persisted automatic git-commit mode value.
318
+ * @details Accepts only the documented `enable|disable` values and falls back to `DEFAULT_AUTO_GIT_COMMIT` for all other payloads. Runtime is O(1). No side effects occur.
319
+ * @param[in] value {unknown} Candidate persisted automatic git-commit payload.
320
+ * @return {"enable" | "disable"} Canonical automatic git-commit mode.
321
+ * @satisfies REQ-212
322
+ */
323
+ export function normalizeAutoGitCommit(value: unknown): "enable" | "disable" {
324
+ return value === "disable" ? "disable" : DEFAULT_AUTO_GIT_COMMIT;
325
+ }
326
+ /**
327
+ * @brief Defines the default worktree orchestration mode.
328
+ * @details New project configs enable prompt-command worktree orchestration unless the persisted project config explicitly disables it. Access complexity is O(1).
329
+ * @satisfies CTN-001, REQ-204
330
+ */
331
+ export const DEFAULT_GIT_WORKTREE_ENABLED = "enable" as const;
332
+ /**
333
+ * @brief Normalizes one persisted worktree-enable flag value.
334
+ * @details Accepts only the documented `enable|disable` values and falls back to `DEFAULT_GIT_WORKTREE_ENABLED` for all other payloads. Runtime is O(1). No side effects occur.
335
+ * @param[in] value {unknown} Candidate persisted worktree-enable payload.
336
+ * @return {"enable" | "disable"} Canonical persisted worktree-enable mode.
337
+ * @satisfies REQ-204
338
+ */
339
+ export function normalizeGitWorktreeEnabled(value: unknown): "enable" | "disable" {
340
+ return value === "disable" ? "disable" : DEFAULT_GIT_WORKTREE_ENABLED;
341
+ }
342
+ /**
343
+ * @brief Resolves the effective worktree mode after automatic-commit policy is applied.
344
+ * @details Forces `disable` whenever `AUTO_GIT_COMMIT` is disabled; otherwise preserves the normalized persisted worktree flag. Runtime is O(1). No side effects occur.
345
+ * @param[in] autoGitCommit {"enable" | "disable"} Effective automatic git-commit mode.
346
+ * @param[in] gitWorktreeEnabled {"enable" | "disable"} Normalized persisted worktree-enable mode.
347
+ * @return {"enable" | "disable"} Effective worktree mode used by menus, persistence, and prompt execution.
348
+ * @satisfies REQ-204, REQ-215
349
+ */
350
+ export function resolveEffectiveGitWorktreeEnabled(
351
+ autoGitCommit: "enable" | "disable",
352
+ gitWorktreeEnabled: "enable" | "disable",
353
+ ): "enable" | "disable" {
354
+ return autoGitCommit === "disable" ? "disable" : gitWorktreeEnabled;
355
+ }
356
+ /**
357
+ * @brief Defines the default static prefix used by generated prompt-command worktree names.
358
+ * @details The prefix is concatenated verbatim ahead of the repository basename inside slash-command-owned worktree-name generation. Access complexity is O(1).
359
+ * @satisfies CTN-001, REQ-205
360
+ */
361
+ export const DEFAULT_GIT_WORKTREE_PREFIX = "PI-useReq-";
362
+ /**
363
+ * @brief Normalizes one persisted worktree-name prefix value.
364
+ * @details Accepts only non-empty strings, trims surrounding whitespace, and falls back to `DEFAULT_GIT_WORKTREE_PREFIX` when the candidate is absent or blank. Runtime is O(n) in prefix length. No side effects occur.
365
+ * @param[in] value {unknown} Candidate persisted prefix payload.
366
+ * @return {string} Canonical worktree-name prefix.
367
+ * @satisfies REQ-205
368
+ */
369
+ export function normalizeGitWorktreePrefix(value: unknown): string {
370
+ if (typeof value !== "string") {
371
+ return DEFAULT_GIT_WORKTREE_PREFIX;
372
+ }
373
+ const trimmedValue = value.trim();
374
+ return trimmedValue === "" ? DEFAULT_GIT_WORKTREE_PREFIX : trimmedValue;
375
+ }
81
376
  /**
82
377
  * @brief Computes the per-project config file path.
83
- * @details Joins the project base with `.pi-usereq/config.json`, producing the canonical persistence location used by CLI and extension code. Time complexity is O(1). No I/O side effects occur.
378
+ * @details Joins the project base with `.pi-usereq.json`, producing the canonical persistence location used by CLI and extension code. Time complexity is O(1). No I/O side effects occur.
84
379
  * @param[in] projectBase {string} Absolute project root path.
85
380
  * @return {string} Absolute config file path.
86
381
  */
@@ -90,41 +385,116 @@ export function getProjectConfigPath(projectBase: string): string {
90
385
 
91
386
  /**
92
387
  * @brief Builds the default project configuration.
93
- * @details Populates canonical docs/test/source directories, the default startup tool set, default pi-notify fields, and default Pushover settings while excluding runtime-derived path metadata. Time complexity is O(n) in default tool count. No filesystem side effects occur.
388
+ * @details Populates canonical docs/test/source directories, documented per-language static-check defaults, default prompt-command worktree settings, default debug fields including dedicated workflow-event logging, the default startup tool set, default command-notify, sound, and Pushover fields, and excludes runtime-derived path metadata. Time complexity is O(n) in default selector count plus default static-check entry count. No filesystem side effects occur.
94
389
  * @param[in] projectBase {string} Absolute project root path.
95
390
  * @return {UseReqConfig} Fresh default configuration object.
96
- * @satisfies CTN-001, CTN-012, REQ-066, REQ-129, REQ-146, REQ-163
391
+ * @satisfies CTN-001, CTN-012, CTN-013, REQ-066, REQ-146, REQ-163, REQ-174, REQ-178, REQ-184, REQ-185, REQ-196, REQ-204, REQ-205, REQ-212, REQ-236, REQ-237, REQ-238, REQ-239, REQ-249, REQ-250, REQ-251, REQ-252, REQ-277
97
392
  */
98
393
  export function getDefaultConfig(_projectBase: string): UseReqConfig {
99
394
  return {
100
395
  "docs-dir": DEFAULT_DOCS_DIR,
101
396
  "tests-dir": DEFAULT_TESTS_DIR,
102
397
  "src-dir": [...DEFAULT_SRC_DIRS],
103
- "static-check": {},
398
+ "static-check": getDefaultStaticCheckConfig(),
104
399
  "enabled-tools": normalizeEnabledPiUsereqTools(undefined),
105
- "notify-beep-on-end": true,
106
- "notify-beep-on-esc": true,
107
- "notify-beep-on-error": true,
400
+ AUTO_GIT_COMMIT: DEFAULT_AUTO_GIT_COMMIT,
401
+ GIT_WORKTREE_ENABLED: DEFAULT_GIT_WORKTREE_ENABLED,
402
+ GIT_WORKTREE_PREFIX: DEFAULT_GIT_WORKTREE_PREFIX,
403
+ DEBUG_ENABLED: DEFAULT_DEBUG_ENABLED,
404
+ DEBUG_LOG_FILE: DEFAULT_DEBUG_LOG_FILE,
405
+ DEBUG_STATUS_CHANGES: DEFAULT_DEBUG_STATUS_CHANGES,
406
+ DEBUG_WORKFLOW_EVENTS: DEFAULT_DEBUG_WORKFLOW_EVENTS,
407
+ DEBUG_LOG_ON_STATUS: DEFAULT_DEBUG_LOG_ON_STATUS,
408
+ DEBUG_ENABLED_TOOLS: [],
409
+ DEBUG_ENABLED_PROMPTS: [],
410
+ "notify-enabled": false,
411
+ "notify-on-completed": true,
412
+ "notify-on-interrupted": false,
413
+ "notify-on-failed": false,
108
414
  "notify-sound": "none",
415
+ "notify-sound-on-completed": true,
416
+ "notify-sound-on-interrupted": false,
417
+ "notify-sound-on-failed": false,
109
418
  "notify-sound-toggle-shortcut": DEFAULT_PI_NOTIFY_SOUND_TOGGLE_SHORTCUT,
110
- "notify-pushover-global-disable": false,
111
- "notify-pushover-on-success": false,
419
+ "notify-pushover-enabled": false,
420
+ "notify-pushover-on-completed": true,
421
+ "notify-pushover-on-interrupted": false,
422
+ "notify-pushover-on-failed": false,
112
423
  "notify-pushover-user-key": "",
113
424
  "notify-pushover-api-token": "",
114
425
  "notify-pushover-priority": 0,
426
+ "notify-pushover-title": DEFAULT_PI_NOTIFY_PUSHOVER_TITLE,
427
+ "notify-pushover-text": DEFAULT_PI_NOTIFY_PUSHOVER_TEXT,
428
+ PI_NOTIFY_CMD: DEFAULT_PI_NOTIFY_CMD,
115
429
  PI_NOTIFY_SOUND_LOW_CMD: DEFAULT_PI_NOTIFY_SOUND_LOW_CMD,
116
430
  PI_NOTIFY_SOUND_MID_CMD: DEFAULT_PI_NOTIFY_SOUND_MID_CMD,
117
431
  PI_NOTIFY_SOUND_HIGH_CMD: DEFAULT_PI_NOTIFY_SOUND_HIGH_CMD,
118
432
  };
119
433
  }
120
434
 
435
+ /**
436
+ * @brief Normalizes one raw checker-entry array from persisted config.
437
+ * @details Accepts only object entries with a non-empty module string, trims optional command text, filters blank params, and drops malformed records without applying any legacy schema migrations. Runtime is O(c + p). No external state is mutated.
438
+ * @param[in] value {unknown} Candidate persisted checker array.
439
+ * @return {StaticCheckEntry[]} Normalized checker-entry vector.
440
+ */
441
+ function normalizeStaticCheckEntries(value: unknown): StaticCheckEntry[] {
442
+ if (!Array.isArray(value)) {
443
+ return [];
444
+ }
445
+ const entries: StaticCheckEntry[] = [];
446
+ for (const item of value) {
447
+ if (!item || typeof item !== "object") {
448
+ continue;
449
+ }
450
+ const entry = item as Record<string, unknown>;
451
+ if (typeof entry.module !== "string" || entry.module.trim() === "") {
452
+ continue;
453
+ }
454
+ entries.push(cloneStaticCheckEntry({
455
+ module: entry.module,
456
+ ...(typeof entry.cmd === "string" ? { cmd: entry.cmd } : {}),
457
+ ...(Array.isArray(entry.params) ? { params: entry.params.map(String) } : {}),
458
+ }));
459
+ }
460
+ return entries;
461
+ }
462
+
463
+ /**
464
+ * @brief Normalizes the persisted per-language static-check configuration map.
465
+ * @details Accepts only object-valued language entries using the new `{ enabled, checkers }` schema, normalizes missing or invalid `enabled` values from checker-list presence, and drops malformed or legacy non-object language payloads without migration. Runtime is O(l + c + p). No external state is mutated.
466
+ * @param[in] value {unknown} Candidate persisted static-check payload.
467
+ * @return {Record<string, StaticCheckLanguageConfig>} Normalized per-language static-check map.
468
+ * @satisfies REQ-249
469
+ */
470
+ function normalizeStaticCheckConfig(
471
+ value: unknown,
472
+ ): Record<string, StaticCheckLanguageConfig> {
473
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
474
+ return {};
475
+ }
476
+ const config: Record<string, StaticCheckLanguageConfig> = {};
477
+ for (const [language, languageValue] of Object.entries(value as Record<string, unknown>)) {
478
+ if (!languageValue || typeof languageValue !== "object" || Array.isArray(languageValue)) {
479
+ continue;
480
+ }
481
+ const languageRecord = languageValue as Record<string, unknown>;
482
+ const checkers = normalizeStaticCheckEntries(languageRecord.checkers);
483
+ config[language] = createStaticCheckLanguageConfig(
484
+ checkers,
485
+ normalizeStaticCheckEnabled(languageRecord.enabled, checkers.length > 0 ? "enable" : "disable"),
486
+ );
487
+ }
488
+ return config;
489
+ }
490
+
121
491
  /**
122
492
  * @brief Loads and sanitizes the persisted project configuration.
123
- * @details Returns defaults when the config file does not exist. Otherwise parses JSON, validates directory and static-check field shapes, normalizes enabled tool names plus pi-notify and Pushover fields, applies enabled beep defaults for missing flag payloads, and ignores removed or runtime-derived path metadata. Runtime is O(n) in config size. Side effects are limited to filesystem reads.
493
+ * @details Returns defaults when the config file does not exist. Otherwise parses JSON, validates directory and per-language static-check object shapes, normalizes enabled tool names plus prompt-command worktree, debug, notify, sound, and Pushover fields including dedicated workflow-event logging, preserves non-empty template text verbatim, forces the effective worktree mode off when automatic git commit is disabled, forces effective Pushover disablement until both credentials are populated, applies documented per-flag defaults for missing payloads, and ignores removed, malformed, or runtime-derived path metadata without legacy schema migration. Runtime is O(n) in config size. Side effects are limited to filesystem reads.
124
494
  * @param[in] projectBase {string} Absolute project root path.
125
495
  * @return {UseReqConfig} Sanitized effective configuration.
126
496
  * @throws {ReqError} Throws with exit code `11` when the config file contains invalid JSON or a non-object payload.
127
- * @satisfies CTN-012, REQ-066, REQ-129, REQ-146, REQ-163
497
+ * @satisfies CTN-012, CTN-013, REQ-066, REQ-146, REQ-163, REQ-174, REQ-178, REQ-184, REQ-185, REQ-196, REQ-204, REQ-205, REQ-212, REQ-215, REQ-234, REQ-235, REQ-236, REQ-237, REQ-238, REQ-239, REQ-249, REQ-277
128
498
  */
129
499
  export function loadConfig(projectBase: string): UseReqConfig {
130
500
  const configPath = getProjectConfigPath(projectBase);
@@ -143,25 +513,65 @@ export function loadConfig(projectBase: string): UseReqConfig {
143
513
  throw new ReqError(`Error: invalid ${configPath}`, 11);
144
514
  }
145
515
  const data = payload as Record<string, unknown>;
146
- const docsDir = typeof data["docs-dir"] === "string" && data["docs-dir"].trim() ? data["docs-dir"] : DEFAULT_DOCS_DIR;
147
- const testsDir = typeof data["tests-dir"] === "string" && data["tests-dir"].trim() ? data["tests-dir"] : DEFAULT_TESTS_DIR;
148
- const srcDir = Array.isArray(data["src-dir"]) && data["src-dir"].every((item) => typeof item === "string" && item.trim())
149
- ? (data["src-dir"] as string[])
150
- : [...DEFAULT_SRC_DIRS];
151
- const staticCheck = typeof data["static-check"] === "object" && data["static-check"] !== null
152
- ? (data["static-check"] as Record<string, StaticCheckEntry[]>)
153
- : {};
516
+ const docsDirCandidate = typeof data["docs-dir"] === "string"
517
+ ? normalizeRelativeDirContract(data["docs-dir"])
518
+ : "";
519
+ const testsDirCandidate = typeof data["tests-dir"] === "string"
520
+ ? normalizeRelativeDirContract(data["tests-dir"])
521
+ : "";
522
+ const srcDirCandidate = Array.isArray(data["src-dir"])
523
+ ? data["src-dir"]
524
+ .filter((item): item is string => typeof item === "string")
525
+ .map((item) => normalizeRelativeDirContract(item))
526
+ .filter((item) => item !== "")
527
+ : [];
528
+ const docsDir = docsDirCandidate || DEFAULT_DOCS_DIR;
529
+ const testsDir = testsDirCandidate || DEFAULT_TESTS_DIR;
530
+ const srcDir = srcDirCandidate.length > 0 ? srcDirCandidate : [...DEFAULT_SRC_DIRS];
531
+ const staticCheck = normalizeStaticCheckConfig(data["static-check"]);
154
532
  const enabledTools = normalizeEnabledPiUsereqTools(data["enabled-tools"]);
155
- const notifyBeepOnEnd = data["notify-beep-on-end"] !== false;
156
- const notifyBeepOnEsc = data["notify-beep-on-esc"] !== false;
157
- const notifyBeepOnError = data["notify-beep-on-error"] !== false;
533
+ const autoGitCommit = normalizeAutoGitCommit(data.AUTO_GIT_COMMIT);
534
+ const gitWorktreeEnabled = resolveEffectiveGitWorktreeEnabled(
535
+ autoGitCommit,
536
+ normalizeGitWorktreeEnabled(data.GIT_WORKTREE_ENABLED),
537
+ );
538
+ const gitWorktreePrefix = normalizeGitWorktreePrefix(data.GIT_WORKTREE_PREFIX);
539
+ const debugEnabled = normalizeDebugEnabled(data.DEBUG_ENABLED);
540
+ const debugLogFile = normalizeDebugLogFile(data.DEBUG_LOG_FILE);
541
+ const debugStatusChanges = normalizeDebugStatusChanges(data.DEBUG_STATUS_CHANGES);
542
+ const debugWorkflowEvents = normalizeDebugWorkflowEvents(data.DEBUG_WORKFLOW_EVENTS);
543
+ const debugLogOnStatus = normalizeDebugLogOnStatus(data.DEBUG_LOG_ON_STATUS);
544
+ const debugEnabledTools = normalizeDebugEnabledTools(data.DEBUG_ENABLED_TOOLS);
545
+ const debugEnabledPrompts = normalizeDebugEnabledPrompts(data.DEBUG_ENABLED_PROMPTS);
546
+ const notifyEnabled = data["notify-enabled"] === true;
547
+ const notifyOnCompleted = data["notify-on-completed"] !== false;
548
+ const notifyOnInterrupted = data["notify-on-interrupted"] === true;
549
+ const notifyOnFailed = data["notify-on-failed"] === true;
158
550
  const notifySound = normalizePiNotifySoundLevel(data["notify-sound"]);
551
+ const notifySoundOnCompleted = data["notify-sound-on-completed"] !== false;
552
+ const notifySoundOnInterrupted = data["notify-sound-on-interrupted"] === true;
553
+ const notifySoundOnFailed = data["notify-sound-on-failed"] === true;
159
554
  const notifySoundToggleShortcut = normalizePiNotifyShortcut(data["notify-sound-toggle-shortcut"]);
160
- const pushoverGlobalDisable = data["notify-pushover-global-disable"] === true;
161
- const pushoverOnSuccess = data["notify-pushover-on-success"] === true;
555
+ const pushoverOnCompleted = data["notify-pushover-on-completed"] !== false;
556
+ const pushoverOnInterrupted = data["notify-pushover-on-interrupted"] === true;
557
+ const pushoverOnFailed = data["notify-pushover-on-failed"] === true;
162
558
  const pushoverUserKey = normalizePiNotifyPushoverCredential(data["notify-pushover-user-key"]);
163
559
  const pushoverApiToken = normalizePiNotifyPushoverCredential(data["notify-pushover-api-token"]);
560
+ const pushoverEnabled = data["notify-pushover-enabled"] === true
561
+ && hasPiNotifyPushoverCredentials({
562
+ "notify-pushover-user-key": pushoverUserKey,
563
+ "notify-pushover-api-token": pushoverApiToken,
564
+ });
164
565
  const pushoverPriority = normalizePiNotifyPushoverPriority(data["notify-pushover-priority"]);
566
+ const pushoverTitle = normalizePiNotifyTemplateValue(
567
+ data["notify-pushover-title"],
568
+ DEFAULT_PI_NOTIFY_PUSHOVER_TITLE,
569
+ );
570
+ const pushoverText = normalizePiNotifyTemplateValue(
571
+ data["notify-pushover-text"],
572
+ DEFAULT_PI_NOTIFY_PUSHOVER_TEXT,
573
+ );
574
+ const notifyCommand = normalizePiNotifyCommand(data.PI_NOTIFY_CMD, DEFAULT_PI_NOTIFY_CMD);
165
575
  const lowSoundCommand = normalizePiNotifyCommand(data.PI_NOTIFY_SOUND_LOW_CMD, DEFAULT_PI_NOTIFY_SOUND_LOW_CMD);
166
576
  const midSoundCommand = normalizePiNotifyCommand(data.PI_NOTIFY_SOUND_MID_CMD, DEFAULT_PI_NOTIFY_SOUND_MID_CMD);
167
577
  const highSoundCommand = normalizePiNotifyCommand(data.PI_NOTIFY_SOUND_HIGH_CMD, DEFAULT_PI_NOTIFY_SOUND_HIGH_CMD);
@@ -172,16 +582,35 @@ export function loadConfig(projectBase: string): UseReqConfig {
172
582
  "src-dir": srcDir,
173
583
  "static-check": staticCheck,
174
584
  "enabled-tools": enabledTools,
175
- "notify-beep-on-end": notifyBeepOnEnd,
176
- "notify-beep-on-esc": notifyBeepOnEsc,
177
- "notify-beep-on-error": notifyBeepOnError,
585
+ AUTO_GIT_COMMIT: autoGitCommit,
586
+ GIT_WORKTREE_ENABLED: gitWorktreeEnabled,
587
+ GIT_WORKTREE_PREFIX: gitWorktreePrefix,
588
+ DEBUG_ENABLED: debugEnabled,
589
+ DEBUG_LOG_FILE: debugLogFile,
590
+ DEBUG_STATUS_CHANGES: debugStatusChanges,
591
+ DEBUG_WORKFLOW_EVENTS: debugWorkflowEvents,
592
+ DEBUG_LOG_ON_STATUS: debugLogOnStatus,
593
+ DEBUG_ENABLED_TOOLS: debugEnabledTools,
594
+ DEBUG_ENABLED_PROMPTS: debugEnabledPrompts,
595
+ "notify-enabled": notifyEnabled,
596
+ "notify-on-completed": notifyOnCompleted,
597
+ "notify-on-interrupted": notifyOnInterrupted,
598
+ "notify-on-failed": notifyOnFailed,
178
599
  "notify-sound": notifySound,
600
+ "notify-sound-on-completed": notifySoundOnCompleted,
601
+ "notify-sound-on-interrupted": notifySoundOnInterrupted,
602
+ "notify-sound-on-failed": notifySoundOnFailed,
179
603
  "notify-sound-toggle-shortcut": notifySoundToggleShortcut,
180
- "notify-pushover-global-disable": pushoverGlobalDisable,
181
- "notify-pushover-on-success": pushoverOnSuccess,
604
+ "notify-pushover-enabled": pushoverEnabled,
605
+ "notify-pushover-on-completed": pushoverOnCompleted,
606
+ "notify-pushover-on-interrupted": pushoverOnInterrupted,
607
+ "notify-pushover-on-failed": pushoverOnFailed,
182
608
  "notify-pushover-user-key": pushoverUserKey,
183
609
  "notify-pushover-api-token": pushoverApiToken,
184
610
  "notify-pushover-priority": pushoverPriority,
611
+ "notify-pushover-title": pushoverTitle,
612
+ "notify-pushover-text": pushoverText,
613
+ PI_NOTIFY_CMD: notifyCommand,
185
614
  PI_NOTIFY_SOUND_LOW_CMD: lowSoundCommand,
186
615
  PI_NOTIFY_SOUND_MID_CMD: midSoundCommand,
187
616
  PI_NOTIFY_SOUND_HIGH_CMD: highSoundCommand,
@@ -190,37 +619,67 @@ export function loadConfig(projectBase: string): UseReqConfig {
190
619
 
191
620
  /**
192
621
  * @brief Builds the persisted configuration payload that excludes runtime-derived fields.
193
- * @details Copies only the canonical persisted configuration keys into a fresh object so runtime-derived metadata such as `base-path` and `git-path` can never be written to disk while preserving notification and Pushover settings verbatim. Runtime is O(n) in config size. No external state is mutated.
622
+ * @details Copies only the canonical persisted configuration keys into a fresh object so runtime-derived metadata such as `base-path` and `git-path` can never be written to disk, serializes per-language static-check objects with key order `enabled` then `checkers`, normalizes `GIT_WORKTREE_PREFIX` plus debug fields including dedicated workflow-event logging, forces persisted worktree disablement when automatic git commit is disabled, forces persisted Pushover disablement until both credentials are populated, and preserves the remaining notification and Pushover settings. Runtime is O(n) in config size. No external state is mutated.
194
623
  * @param[in] config {UseReqConfig} Effective configuration object.
195
624
  * @return {UseReqConfig} Persistable configuration payload.
196
- * @satisfies CTN-012, REQ-146, REQ-163
625
+ * @satisfies CTN-012, CTN-013, REQ-146, REQ-163, REQ-204, REQ-205, REQ-212, REQ-215, REQ-234, REQ-236, REQ-237, REQ-238, REQ-239, REQ-249, REQ-277
197
626
  */
198
627
  function buildPersistedConfig(config: UseReqConfig): UseReqConfig {
199
628
  return {
200
- "docs-dir": config["docs-dir"],
201
- "tests-dir": config["tests-dir"],
202
- "src-dir": [...config["src-dir"]],
629
+ "docs-dir": normalizeRelativeDirContract(config["docs-dir"]) || DEFAULT_DOCS_DIR,
630
+ "tests-dir": normalizeRelativeDirContract(config["tests-dir"]) || DEFAULT_TESTS_DIR,
631
+ "src-dir": (() => {
632
+ const normalizedSrcDir = config["src-dir"]
633
+ .map((entry) => normalizeRelativeDirContract(entry))
634
+ .filter((entry) => entry !== "");
635
+ return normalizedSrcDir.length > 0 ? normalizedSrcDir : [...DEFAULT_SRC_DIRS];
636
+ })(),
203
637
  "static-check": Object.fromEntries(
204
- Object.entries(config["static-check"]).map(([language, entries]) => [
638
+ Object.entries(config["static-check"]).map(([language, languageConfig]) => [
205
639
  language,
206
- entries.map((entry) => ({
207
- module: entry.module,
208
- ...(entry.cmd ? { cmd: entry.cmd } : {}),
209
- ...(entry.params ? { params: [...entry.params] } : {}),
210
- })),
640
+ {
641
+ enabled: normalizeStaticCheckEnabled(
642
+ languageConfig.enabled,
643
+ languageConfig.checkers.length > 0 ? "enable" : "disable",
644
+ ),
645
+ checkers: languageConfig.checkers.map(cloneStaticCheckEntry),
646
+ },
211
647
  ]),
212
648
  ),
213
649
  "enabled-tools": [...config["enabled-tools"]],
214
- "notify-beep-on-end": config["notify-beep-on-end"],
215
- "notify-beep-on-esc": config["notify-beep-on-esc"],
216
- "notify-beep-on-error": config["notify-beep-on-error"],
650
+ AUTO_GIT_COMMIT: normalizeAutoGitCommit(config.AUTO_GIT_COMMIT),
651
+ GIT_WORKTREE_ENABLED: resolveEffectiveGitWorktreeEnabled(
652
+ normalizeAutoGitCommit(config.AUTO_GIT_COMMIT),
653
+ config.GIT_WORKTREE_ENABLED,
654
+ ),
655
+ GIT_WORKTREE_PREFIX: normalizeGitWorktreePrefix(config.GIT_WORKTREE_PREFIX),
656
+ DEBUG_ENABLED: normalizeDebugEnabled(config.DEBUG_ENABLED),
657
+ DEBUG_LOG_FILE: normalizeDebugLogFile(config.DEBUG_LOG_FILE),
658
+ DEBUG_STATUS_CHANGES: normalizeDebugStatusChanges(config.DEBUG_STATUS_CHANGES),
659
+ DEBUG_WORKFLOW_EVENTS: normalizeDebugWorkflowEvents(config.DEBUG_WORKFLOW_EVENTS),
660
+ DEBUG_LOG_ON_STATUS: normalizeDebugLogOnStatus(config.DEBUG_LOG_ON_STATUS),
661
+ DEBUG_ENABLED_TOOLS: normalizeDebugEnabledTools(config.DEBUG_ENABLED_TOOLS),
662
+ DEBUG_ENABLED_PROMPTS: normalizeDebugEnabledPrompts(config.DEBUG_ENABLED_PROMPTS),
663
+ "notify-enabled": config["notify-enabled"],
664
+ "notify-on-completed": config["notify-on-completed"],
665
+ "notify-on-interrupted": config["notify-on-interrupted"],
666
+ "notify-on-failed": config["notify-on-failed"],
217
667
  "notify-sound": config["notify-sound"],
668
+ "notify-sound-on-completed": config["notify-sound-on-completed"],
669
+ "notify-sound-on-interrupted": config["notify-sound-on-interrupted"],
670
+ "notify-sound-on-failed": config["notify-sound-on-failed"],
218
671
  "notify-sound-toggle-shortcut": config["notify-sound-toggle-shortcut"],
219
- "notify-pushover-global-disable": config["notify-pushover-global-disable"],
220
- "notify-pushover-on-success": config["notify-pushover-on-success"],
672
+ "notify-pushover-enabled": config["notify-pushover-enabled"]
673
+ && hasPiNotifyPushoverCredentials(config),
674
+ "notify-pushover-on-completed": config["notify-pushover-on-completed"],
675
+ "notify-pushover-on-interrupted": config["notify-pushover-on-interrupted"],
676
+ "notify-pushover-on-failed": config["notify-pushover-on-failed"],
221
677
  "notify-pushover-user-key": config["notify-pushover-user-key"],
222
678
  "notify-pushover-api-token": config["notify-pushover-api-token"],
223
679
  "notify-pushover-priority": config["notify-pushover-priority"],
680
+ "notify-pushover-title": config["notify-pushover-title"],
681
+ "notify-pushover-text": config["notify-pushover-text"],
682
+ PI_NOTIFY_CMD: config.PI_NOTIFY_CMD,
224
683
  PI_NOTIFY_SOUND_LOW_CMD: config.PI_NOTIFY_SOUND_LOW_CMD,
225
684
  PI_NOTIFY_SOUND_MID_CMD: config.PI_NOTIFY_SOUND_MID_CMD,
226
685
  PI_NOTIFY_SOUND_HIGH_CMD: config.PI_NOTIFY_SOUND_HIGH_CMD,
@@ -229,7 +688,7 @@ function buildPersistedConfig(config: UseReqConfig): UseReqConfig {
229
688
 
230
689
  /**
231
690
  * @brief Persists the project configuration to disk.
232
- * @details Creates the parent `.pi-usereq` directory when necessary, strips runtime-derived fields from the serialized payload, and writes formatted JSON terminated by a newline. Runtime is O(n) in serialized config size. Side effects include directory creation and file overwrite.
691
+ * @details Creates the base directory path when necessary, strips runtime-derived fields from the serialized payload, and writes formatted JSON terminated by a newline to `.pi-usereq.json`. Runtime is O(n) in serialized config size. Side effects include directory creation and file overwrite.
233
692
  * @param[in] projectBase {string} Absolute project root path.
234
693
  * @param[in] config {UseReqConfig} Configuration object to persist.
235
694
  * @return {void} No return value.
@@ -249,9 +708,17 @@ export function saveConfig(projectBase: string, config: UseReqConfig): void {
249
708
  * @return {UseReqConfig} Normalized configuration copy.
250
709
  */
251
710
  export function normalizeConfigPaths(projectBase: string, config: UseReqConfig): UseReqConfig {
252
- const docsDir = makeRelativeIfContainsProject(config["docs-dir"], projectBase).replace(/[/\\]+$/, "") || DEFAULT_DOCS_DIR;
253
- const testsDir = makeRelativeIfContainsProject(config["tests-dir"], projectBase).replace(/[/\\]+$/, "") || DEFAULT_TESTS_DIR;
254
- const srcDirs = config["src-dir"].map((value) => makeRelativeIfContainsProject(value, projectBase).replace(/[/\\]+$/, "")).filter(Boolean);
711
+ const docsDir = normalizeRelativeDirContract(
712
+ makeRelativeIfContainsProject(config["docs-dir"], projectBase),
713
+ ) || DEFAULT_DOCS_DIR;
714
+ const testsDir = normalizeRelativeDirContract(
715
+ makeRelativeIfContainsProject(config["tests-dir"], projectBase),
716
+ ) || DEFAULT_TESTS_DIR;
717
+ const srcDirs = config["src-dir"]
718
+ .map((value) => normalizeRelativeDirContract(
719
+ makeRelativeIfContainsProject(value, projectBase),
720
+ ))
721
+ .filter((value) => value !== "");
255
722
  return {
256
723
  ...config,
257
724
  "docs-dir": docsDir,
@@ -268,8 +735,12 @@ export function normalizeConfigPaths(projectBase: string, config: UseReqConfig):
268
735
  * @return {Record<string, string>} Placeholder-to-string replacement map including runtime path tokens.
269
736
  * @satisfies REQ-002, REQ-103, REQ-106, REQ-107, CTN-011
270
737
  */
271
- export function buildPromptReplacementPaths(projectBase: string, config: UseReqConfig): Record<string, string> {
272
- const runtimePathContext = buildRuntimePathContext(projectBase, config);
738
+ export function buildPromptReplacementPaths(
739
+ basePath: string,
740
+ contextPath: string,
741
+ config: UseReqConfig,
742
+ ): Record<string, string> {
743
+ const runtimePathContext = buildRuntimePathContext(basePath, contextPath, config);
273
744
  const runtimePathFacts = buildRuntimePathFacts(runtimePathContext);
274
745
  const guidelineEntries = fs.existsSync(runtimePathContext.guidelinesPath)
275
746
  ? fs.readdirSync(runtimePathContext.guidelinesPath)
@@ -278,21 +749,31 @@ export function buildPromptReplacementPaths(projectBase: string, config: UseReqC
278
749
  .sort((left, right) => left.localeCompare(right))
279
750
  : [];
280
751
 
281
- const srcValue = config["src-dir"].map((value) => `\`${value.replace(/[/\\]+$/, "")}/\``).join(", ");
282
- const testValue = `\`${config["tests-dir"].replace(/[/\\]+$/, "")}/\``;
752
+ const normalizedDocsDir = normalizeRelativeDirContract(config["docs-dir"])
753
+ || DEFAULT_DOCS_DIR;
754
+ const normalizedTestsDir = normalizeRelativeDirContract(config["tests-dir"])
755
+ || DEFAULT_TESTS_DIR;
756
+ const normalizedSrcDir = config["src-dir"]
757
+ .map((value) => normalizeRelativeDirContract(value))
758
+ .filter((value) => value !== "");
759
+ const effectiveSrcDir = normalizedSrcDir.length > 0
760
+ ? normalizedSrcDir
761
+ : [...DEFAULT_SRC_DIRS];
762
+ const srcValue = effectiveSrcDir.map((value) => `\`${value}/\``).join(", ");
763
+ const testValue = `\`${normalizedTestsDir}/\``;
283
764
  const guidelinesValue = guidelineEntries.length > 0
284
765
  ? guidelineEntries.map((entry) => `\`${entry}\``).join(", ")
285
- : `\`${runtimePathFacts.guidelines_path}/\``;
766
+ : `\`${runtimePathFacts.guidelines_path}\``;
286
767
 
287
768
  return {
288
- "%%DOC_PATH%%": config["docs-dir"].replace(/[/\\]+$/, ""),
769
+ "%%DOC_PATH%%": normalizedDocsDir,
289
770
  "%%GUIDELINES_FILES%%": guidelinesValue,
290
771
  "%%GUIDELINES_PATH%%": runtimePathFacts.guidelines_path,
291
- "%%TEMPLATE_PATH%%": runtimePathFacts.templates_path,
772
+ "%%TEMPLATE_PATH%%": runtimePathFacts.template_path,
292
773
  "%%SRC_PATHS%%": srcValue,
293
774
  "%%TEST_PATH%%": testValue,
294
775
  "%%PROJECT_BASE%%": runtimePathFacts.base_path,
295
- "%%EXECUTION_PATH%%": runtimePathFacts.execution_path,
776
+ "%%CONTEXT_PATH%%": runtimePathFacts.context_path,
296
777
  "%%INSTALLATION_PATH%%": runtimePathFacts.installation_path,
297
778
  "%%CONFIG_PATH%%": runtimePathFacts.config_path,
298
779
  };