pi-usereq 0.4.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 (361) hide show
  1. package/.g.conf +20 -0
  2. package/.github/workflows/release-npm.yml +131 -0
  3. package/.gitignore +270 -0
  4. package/CHANGELOG.md +221 -0
  5. package/LICENSE +674 -0
  6. package/README.md +260 -0
  7. package/TODO.md +20 -0
  8. package/docs/pi.dev/agent-document-manifest.json +6399 -0
  9. package/docs/pi.dev/coding-agent-docs/compaction.md +394 -0
  10. package/docs/pi.dev/coding-agent-docs/custom-provider.md +596 -0
  11. package/docs/pi.dev/coding-agent-docs/development.md +71 -0
  12. package/docs/pi.dev/coding-agent-docs/extensions.md +2262 -0
  13. package/docs/pi.dev/coding-agent-docs/images/doom-extension.png +0 -0
  14. package/docs/pi.dev/coding-agent-docs/images/exy.png +0 -0
  15. package/docs/pi.dev/coding-agent-docs/images/interactive-mode.png +0 -0
  16. package/docs/pi.dev/coding-agent-docs/images/tree-view.png +0 -0
  17. package/docs/pi.dev/coding-agent-docs/json.md +82 -0
  18. package/docs/pi.dev/coding-agent-docs/keybindings.md +175 -0
  19. package/docs/pi.dev/coding-agent-docs/models.md +392 -0
  20. package/docs/pi.dev/coding-agent-docs/packages.md +218 -0
  21. package/docs/pi.dev/coding-agent-docs/prompt-templates.md +67 -0
  22. package/docs/pi.dev/coding-agent-docs/providers.md +195 -0
  23. package/docs/pi.dev/coding-agent-docs/rpc.md +1377 -0
  24. package/docs/pi.dev/coding-agent-docs/sdk.md +1124 -0
  25. package/docs/pi.dev/coding-agent-docs/session.md +412 -0
  26. package/docs/pi.dev/coding-agent-docs/settings.md +247 -0
  27. package/docs/pi.dev/coding-agent-docs/shell-aliases.md +13 -0
  28. package/docs/pi.dev/coding-agent-docs/skills.md +232 -0
  29. package/docs/pi.dev/coding-agent-docs/terminal-setup.md +106 -0
  30. package/docs/pi.dev/coding-agent-docs/termux.md +127 -0
  31. package/docs/pi.dev/coding-agent-docs/themes.md +295 -0
  32. package/docs/pi.dev/coding-agent-docs/tmux.md +61 -0
  33. package/docs/pi.dev/coding-agent-docs/tree.md +231 -0
  34. package/docs/pi.dev/coding-agent-docs/tui.md +887 -0
  35. package/docs/pi.dev/coding-agent-docs/windows.md +17 -0
  36. package/docs/pi.dev/mom-docs/artifacts-server.md +475 -0
  37. package/docs/pi.dev/mom-docs/events.md +307 -0
  38. package/docs/pi.dev/mom-docs/new.md +970 -0
  39. package/docs/pi.dev/mom-docs/sandbox.md +153 -0
  40. package/docs/pi.dev/mom-docs/slack-bot-minimal-guide.md +399 -0
  41. package/docs/pi.dev/mom-docs/v86.md +319 -0
  42. package/docs/pi.dev/pods-docs/gml-4.5.md +189 -0
  43. package/docs/pi.dev/pods-docs/gpt-oss.md +233 -0
  44. package/docs/pi.dev/pods-docs/implementation-plan.md +183 -0
  45. package/docs/pi.dev/pods-docs/kimi-k2.md +197 -0
  46. package/docs/pi.dev/pods-docs/models.md +116 -0
  47. package/docs/pi.dev/pods-docs/plan.md +166 -0
  48. package/docs/pi.dev/pods-docs/qwen3-coder.md +132 -0
  49. package/images/flowchart-bw.png +0 -0
  50. package/images/flowchart-bw.svg +102 -0
  51. package/images/flowchart.md +100 -0
  52. package/images/flowchart.png +0 -0
  53. package/images/flowchart.svg +3 -0
  54. package/package.json +46 -0
  55. package/req/docs/REFERENCES.md +4554 -0
  56. package/req/docs/REQUIREMENTS.md +475 -0
  57. package/req/docs/WORKFLOW.md +1059 -0
  58. package/scripts/debug-extension.ts +497 -0
  59. package/scripts/lib/extension-debug-harness.ts +450 -0
  60. package/scripts/lib/recording-extension-api.ts +786 -0
  61. package/scripts/lib/sdk-smoke.ts +503 -0
  62. package/scripts/pi-usereq-debug.sh +330 -0
  63. package/scripts/tool-args-to-params.ts +208 -0
  64. package/src/cli.ts +349 -0
  65. package/src/core/agent-tool-json.ts +621 -0
  66. package/src/core/compress-files.ts +72 -0
  67. package/src/core/compress-payload.ts +648 -0
  68. package/src/core/compress.ts +464 -0
  69. package/src/core/config.ts +272 -0
  70. package/src/core/doxygen-parser.ts +318 -0
  71. package/src/core/errors.ts +31 -0
  72. package/src/core/extension-status.ts +660 -0
  73. package/src/core/find-constructs.ts +319 -0
  74. package/src/core/find-payload.ts +915 -0
  75. package/src/core/generate-markdown.ts +120 -0
  76. package/src/core/path-context.ts +196 -0
  77. package/src/core/pi-notify.ts +430 -0
  78. package/src/core/pi-usereq-tools.ts +140 -0
  79. package/src/core/prompts.ts +184 -0
  80. package/src/core/reference-payload.ts +818 -0
  81. package/src/core/resources.ts +63 -0
  82. package/src/core/runtime-project-paths.ts +99 -0
  83. package/src/core/settings-menu.ts +233 -0
  84. package/src/core/source-analyzer.ts +1721 -0
  85. package/src/core/static-check.ts +674 -0
  86. package/src/core/token-counter.ts +729 -0
  87. package/src/core/tool-runner.ts +717 -0
  88. package/src/core/utils.ts +185 -0
  89. package/src/index.ts +2209 -0
  90. package/src/resources/guidelines/Google_C++_Style_Guide.md +3711 -0
  91. package/src/resources/guidelines/Google_Python_Style_Guide.md +3709 -0
  92. package/src/resources/prompts/analyze.md +130 -0
  93. package/src/resources/prompts/change.md +227 -0
  94. package/src/resources/prompts/check.md +139 -0
  95. package/src/resources/prompts/cover.md +219 -0
  96. package/src/resources/prompts/create.md +104 -0
  97. package/src/resources/prompts/fix.md +221 -0
  98. package/src/resources/prompts/flowchart.md +220 -0
  99. package/src/resources/prompts/implement.md +163 -0
  100. package/src/resources/prompts/new.md +226 -0
  101. package/src/resources/prompts/readme.md +182 -0
  102. package/src/resources/prompts/recreate.md +213 -0
  103. package/src/resources/prompts/refactor.md +213 -0
  104. package/src/resources/prompts/references.md +100 -0
  105. package/src/resources/prompts/renumber.md +119 -0
  106. package/src/resources/prompts/workflow.md +202 -0
  107. package/src/resources/prompts/write.md +99 -0
  108. package/src/resources/sounds/Machine-alert-beep-sound-effect.mp3 +0 -0
  109. package/src/resources/sounds/Soft-high-tech-notification-sound-effect.mp3 +0 -0
  110. package/src/resources/templates/Document_Source_Code_in_Doxygen_Style.md +130 -0
  111. package/src/resources/templates/HDT_Test_Authoring_Guide.md +318 -0
  112. package/src/resources/templates/Requirements_Template.md +78 -0
  113. package/tests/attended-results-scenarios.ts +758 -0
  114. package/tests/attended-results.test.ts +39 -0
  115. package/tests/cli-command-option-parity.test.ts +815 -0
  116. package/tests/debug-extension-harness.test.ts +463 -0
  117. package/tests/extension-registration.test.ts +2006 -0
  118. package/tests/fixtures/fixture_c.c +361 -0
  119. package/tests/fixtures/fixture_cpp.cpp +407 -0
  120. package/tests/fixtures/fixture_csharp.cs +411 -0
  121. package/tests/fixtures/fixture_elixir.ex +409 -0
  122. package/tests/fixtures/fixture_go.go +341 -0
  123. package/tests/fixtures/fixture_haskell.hs +250 -0
  124. package/tests/fixtures/fixture_java.java +430 -0
  125. package/tests/fixtures/fixture_javascript.js +383 -0
  126. package/tests/fixtures/fixture_kotlin.kt +451 -0
  127. package/tests/fixtures/fixture_lua.lua +276 -0
  128. package/tests/fixtures/fixture_perl.pl +310 -0
  129. package/tests/fixtures/fixture_php.php +433 -0
  130. package/tests/fixtures/fixture_python.py +502 -0
  131. package/tests/fixtures/fixture_ruby.rb +345 -0
  132. package/tests/fixtures/fixture_rust.rs +380 -0
  133. package/tests/fixtures/fixture_scala.scala +398 -0
  134. package/tests/fixtures/fixture_shell.sh +276 -0
  135. package/tests/fixtures/fixture_swift.swift +397 -0
  136. package/tests/fixtures/fixture_typescript.ts +434 -0
  137. package/tests/fixtures/fixture_zig.zig +295 -0
  138. package/tests/fixtures_attended_results/project/compress-line-numbers.json +5 -0
  139. package/tests/fixtures_attended_results/project/compress.json +5 -0
  140. package/tests/fixtures_attended_results/project/enable-static-check-invalid-command.json +5 -0
  141. package/tests/fixtures_attended_results/project/enable-static-check-valid.json +5 -0
  142. package/tests/fixtures_attended_results/project/files-static-check.json +5 -0
  143. package/tests/fixtures_attended_results/project/find-line-numbers.json +5 -0
  144. package/tests/fixtures_attended_results/project/find.json +5 -0
  145. package/tests/fixtures_attended_results/project/get-base-path.json +5 -0
  146. package/tests/fixtures_attended_results/project/git-check-clean.json +5 -0
  147. package/tests/fixtures_attended_results/project/git-check-dirty.json +5 -0
  148. package/tests/fixtures_attended_results/project/git-path.json +5 -0
  149. package/tests/fixtures_attended_results/project/git-wt-create-invalid.json +5 -0
  150. package/tests/fixtures_attended_results/project/git-wt-create-valid.json +5 -0
  151. package/tests/fixtures_attended_results/project/git-wt-delete-nonexistent.json +5 -0
  152. package/tests/fixtures_attended_results/project/git-wt-delete-valid.json +5 -0
  153. package/tests/fixtures_attended_results/project/git-wt-name.json +5 -0
  154. package/tests/fixtures_attended_results/project/references.json +5 -0
  155. package/tests/fixtures_attended_results/project/static-check.json +5 -0
  156. package/tests/fixtures_attended_results/project/tokens.json +5 -0
  157. package/tests/fixtures_attended_results/standalone/files-compress/fixture_c.c.json +5 -0
  158. package/tests/fixtures_attended_results/standalone/files-compress/fixture_cpp.cpp.json +5 -0
  159. package/tests/fixtures_attended_results/standalone/files-compress/fixture_csharp.cs.json +5 -0
  160. package/tests/fixtures_attended_results/standalone/files-compress/fixture_elixir.ex.json +5 -0
  161. package/tests/fixtures_attended_results/standalone/files-compress/fixture_go.go.json +5 -0
  162. package/tests/fixtures_attended_results/standalone/files-compress/fixture_haskell.hs.json +5 -0
  163. package/tests/fixtures_attended_results/standalone/files-compress/fixture_java.java.json +5 -0
  164. package/tests/fixtures_attended_results/standalone/files-compress/fixture_javascript.js.json +5 -0
  165. package/tests/fixtures_attended_results/standalone/files-compress/fixture_kotlin.kt.json +5 -0
  166. package/tests/fixtures_attended_results/standalone/files-compress/fixture_lua.lua.json +5 -0
  167. package/tests/fixtures_attended_results/standalone/files-compress/fixture_perl.pl.json +5 -0
  168. package/tests/fixtures_attended_results/standalone/files-compress/fixture_php.php.json +5 -0
  169. package/tests/fixtures_attended_results/standalone/files-compress/fixture_python.py.json +5 -0
  170. package/tests/fixtures_attended_results/standalone/files-compress/fixture_ruby.rb.json +5 -0
  171. package/tests/fixtures_attended_results/standalone/files-compress/fixture_rust.rs.json +5 -0
  172. package/tests/fixtures_attended_results/standalone/files-compress/fixture_scala.scala.json +5 -0
  173. package/tests/fixtures_attended_results/standalone/files-compress/fixture_shell.sh.json +5 -0
  174. package/tests/fixtures_attended_results/standalone/files-compress/fixture_swift.swift.json +5 -0
  175. package/tests/fixtures_attended_results/standalone/files-compress/fixture_typescript.ts.json +5 -0
  176. package/tests/fixtures_attended_results/standalone/files-compress/fixture_zig.zig.json +5 -0
  177. package/tests/fixtures_attended_results/standalone/files-compress-line-numbers/fixture_c.c.json +5 -0
  178. package/tests/fixtures_attended_results/standalone/files-compress-line-numbers/fixture_cpp.cpp.json +5 -0
  179. package/tests/fixtures_attended_results/standalone/files-compress-line-numbers/fixture_csharp.cs.json +5 -0
  180. package/tests/fixtures_attended_results/standalone/files-compress-line-numbers/fixture_elixir.ex.json +5 -0
  181. package/tests/fixtures_attended_results/standalone/files-compress-line-numbers/fixture_go.go.json +5 -0
  182. package/tests/fixtures_attended_results/standalone/files-compress-line-numbers/fixture_haskell.hs.json +5 -0
  183. package/tests/fixtures_attended_results/standalone/files-compress-line-numbers/fixture_java.java.json +5 -0
  184. package/tests/fixtures_attended_results/standalone/files-compress-line-numbers/fixture_javascript.js.json +5 -0
  185. package/tests/fixtures_attended_results/standalone/files-compress-line-numbers/fixture_kotlin.kt.json +5 -0
  186. package/tests/fixtures_attended_results/standalone/files-compress-line-numbers/fixture_lua.lua.json +5 -0
  187. package/tests/fixtures_attended_results/standalone/files-compress-line-numbers/fixture_perl.pl.json +5 -0
  188. package/tests/fixtures_attended_results/standalone/files-compress-line-numbers/fixture_php.php.json +5 -0
  189. package/tests/fixtures_attended_results/standalone/files-compress-line-numbers/fixture_python.py.json +5 -0
  190. package/tests/fixtures_attended_results/standalone/files-compress-line-numbers/fixture_ruby.rb.json +5 -0
  191. package/tests/fixtures_attended_results/standalone/files-compress-line-numbers/fixture_rust.rs.json +5 -0
  192. package/tests/fixtures_attended_results/standalone/files-compress-line-numbers/fixture_scala.scala.json +5 -0
  193. package/tests/fixtures_attended_results/standalone/files-compress-line-numbers/fixture_shell.sh.json +5 -0
  194. package/tests/fixtures_attended_results/standalone/files-compress-line-numbers/fixture_swift.swift.json +5 -0
  195. package/tests/fixtures_attended_results/standalone/files-compress-line-numbers/fixture_typescript.ts.json +5 -0
  196. package/tests/fixtures_attended_results/standalone/files-compress-line-numbers/fixture_zig.zig.json +5 -0
  197. package/tests/fixtures_attended_results/standalone/files-find/fixture_c.c.json +5 -0
  198. package/tests/fixtures_attended_results/standalone/files-find/fixture_cpp.cpp.json +5 -0
  199. package/tests/fixtures_attended_results/standalone/files-find/fixture_csharp.cs.json +5 -0
  200. package/tests/fixtures_attended_results/standalone/files-find/fixture_elixir.ex.json +5 -0
  201. package/tests/fixtures_attended_results/standalone/files-find/fixture_go.go.json +5 -0
  202. package/tests/fixtures_attended_results/standalone/files-find/fixture_haskell.hs.json +5 -0
  203. package/tests/fixtures_attended_results/standalone/files-find/fixture_java.java.json +5 -0
  204. package/tests/fixtures_attended_results/standalone/files-find/fixture_javascript.js.json +5 -0
  205. package/tests/fixtures_attended_results/standalone/files-find/fixture_kotlin.kt.json +5 -0
  206. package/tests/fixtures_attended_results/standalone/files-find/fixture_lua.lua.json +5 -0
  207. package/tests/fixtures_attended_results/standalone/files-find/fixture_perl.pl.json +5 -0
  208. package/tests/fixtures_attended_results/standalone/files-find/fixture_php.php.json +5 -0
  209. package/tests/fixtures_attended_results/standalone/files-find/fixture_python.py.json +5 -0
  210. package/tests/fixtures_attended_results/standalone/files-find/fixture_ruby.rb.json +5 -0
  211. package/tests/fixtures_attended_results/standalone/files-find/fixture_rust.rs.json +5 -0
  212. package/tests/fixtures_attended_results/standalone/files-find/fixture_scala.scala.json +5 -0
  213. package/tests/fixtures_attended_results/standalone/files-find/fixture_shell.sh.json +5 -0
  214. package/tests/fixtures_attended_results/standalone/files-find/fixture_swift.swift.json +5 -0
  215. package/tests/fixtures_attended_results/standalone/files-find/fixture_typescript.ts.json +5 -0
  216. package/tests/fixtures_attended_results/standalone/files-find/fixture_zig.zig.json +5 -0
  217. package/tests/fixtures_attended_results/standalone/files-find-line-numbers/fixture_c.c.json +5 -0
  218. package/tests/fixtures_attended_results/standalone/files-find-line-numbers/fixture_cpp.cpp.json +5 -0
  219. package/tests/fixtures_attended_results/standalone/files-find-line-numbers/fixture_csharp.cs.json +5 -0
  220. package/tests/fixtures_attended_results/standalone/files-find-line-numbers/fixture_elixir.ex.json +5 -0
  221. package/tests/fixtures_attended_results/standalone/files-find-line-numbers/fixture_go.go.json +5 -0
  222. package/tests/fixtures_attended_results/standalone/files-find-line-numbers/fixture_haskell.hs.json +5 -0
  223. package/tests/fixtures_attended_results/standalone/files-find-line-numbers/fixture_java.java.json +5 -0
  224. package/tests/fixtures_attended_results/standalone/files-find-line-numbers/fixture_javascript.js.json +5 -0
  225. package/tests/fixtures_attended_results/standalone/files-find-line-numbers/fixture_kotlin.kt.json +5 -0
  226. package/tests/fixtures_attended_results/standalone/files-find-line-numbers/fixture_lua.lua.json +5 -0
  227. package/tests/fixtures_attended_results/standalone/files-find-line-numbers/fixture_perl.pl.json +5 -0
  228. package/tests/fixtures_attended_results/standalone/files-find-line-numbers/fixture_php.php.json +5 -0
  229. package/tests/fixtures_attended_results/standalone/files-find-line-numbers/fixture_python.py.json +5 -0
  230. package/tests/fixtures_attended_results/standalone/files-find-line-numbers/fixture_ruby.rb.json +5 -0
  231. package/tests/fixtures_attended_results/standalone/files-find-line-numbers/fixture_rust.rs.json +5 -0
  232. package/tests/fixtures_attended_results/standalone/files-find-line-numbers/fixture_scala.scala.json +5 -0
  233. package/tests/fixtures_attended_results/standalone/files-find-line-numbers/fixture_shell.sh.json +5 -0
  234. package/tests/fixtures_attended_results/standalone/files-find-line-numbers/fixture_swift.swift.json +5 -0
  235. package/tests/fixtures_attended_results/standalone/files-find-line-numbers/fixture_typescript.ts.json +5 -0
  236. package/tests/fixtures_attended_results/standalone/files-find-line-numbers/fixture_zig.zig.json +5 -0
  237. package/tests/fixtures_attended_results/standalone/files-references/fixture_c.c.json +5 -0
  238. package/tests/fixtures_attended_results/standalone/files-references/fixture_cpp.cpp.json +5 -0
  239. package/tests/fixtures_attended_results/standalone/files-references/fixture_csharp.cs.json +5 -0
  240. package/tests/fixtures_attended_results/standalone/files-references/fixture_elixir.ex.json +5 -0
  241. package/tests/fixtures_attended_results/standalone/files-references/fixture_go.go.json +5 -0
  242. package/tests/fixtures_attended_results/standalone/files-references/fixture_haskell.hs.json +5 -0
  243. package/tests/fixtures_attended_results/standalone/files-references/fixture_java.java.json +5 -0
  244. package/tests/fixtures_attended_results/standalone/files-references/fixture_javascript.js.json +5 -0
  245. package/tests/fixtures_attended_results/standalone/files-references/fixture_kotlin.kt.json +5 -0
  246. package/tests/fixtures_attended_results/standalone/files-references/fixture_lua.lua.json +5 -0
  247. package/tests/fixtures_attended_results/standalone/files-references/fixture_perl.pl.json +5 -0
  248. package/tests/fixtures_attended_results/standalone/files-references/fixture_php.php.json +5 -0
  249. package/tests/fixtures_attended_results/standalone/files-references/fixture_python.py.json +5 -0
  250. package/tests/fixtures_attended_results/standalone/files-references/fixture_ruby.rb.json +5 -0
  251. package/tests/fixtures_attended_results/standalone/files-references/fixture_rust.rs.json +5 -0
  252. package/tests/fixtures_attended_results/standalone/files-references/fixture_scala.scala.json +5 -0
  253. package/tests/fixtures_attended_results/standalone/files-references/fixture_shell.sh.json +5 -0
  254. package/tests/fixtures_attended_results/standalone/files-references/fixture_swift.swift.json +5 -0
  255. package/tests/fixtures_attended_results/standalone/files-references/fixture_typescript.ts.json +5 -0
  256. package/tests/fixtures_attended_results/standalone/files-references/fixture_zig.zig.json +5 -0
  257. package/tests/fixtures_attended_results/standalone/files-tokens/fixture_c.c.json +5 -0
  258. package/tests/fixtures_attended_results/standalone/files-tokens/fixture_cpp.cpp.json +5 -0
  259. package/tests/fixtures_attended_results/standalone/files-tokens/fixture_csharp.cs.json +5 -0
  260. package/tests/fixtures_attended_results/standalone/files-tokens/fixture_elixir.ex.json +5 -0
  261. package/tests/fixtures_attended_results/standalone/files-tokens/fixture_go.go.json +5 -0
  262. package/tests/fixtures_attended_results/standalone/files-tokens/fixture_haskell.hs.json +5 -0
  263. package/tests/fixtures_attended_results/standalone/files-tokens/fixture_java.java.json +5 -0
  264. package/tests/fixtures_attended_results/standalone/files-tokens/fixture_javascript.js.json +5 -0
  265. package/tests/fixtures_attended_results/standalone/files-tokens/fixture_kotlin.kt.json +5 -0
  266. package/tests/fixtures_attended_results/standalone/files-tokens/fixture_lua.lua.json +5 -0
  267. package/tests/fixtures_attended_results/standalone/files-tokens/fixture_perl.pl.json +5 -0
  268. package/tests/fixtures_attended_results/standalone/files-tokens/fixture_php.php.json +5 -0
  269. package/tests/fixtures_attended_results/standalone/files-tokens/fixture_python.py.json +5 -0
  270. package/tests/fixtures_attended_results/standalone/files-tokens/fixture_ruby.rb.json +5 -0
  271. package/tests/fixtures_attended_results/standalone/files-tokens/fixture_rust.rs.json +5 -0
  272. package/tests/fixtures_attended_results/standalone/files-tokens/fixture_scala.scala.json +5 -0
  273. package/tests/fixtures_attended_results/standalone/files-tokens/fixture_shell.sh.json +5 -0
  274. package/tests/fixtures_attended_results/standalone/files-tokens/fixture_swift.swift.json +5 -0
  275. package/tests/fixtures_attended_results/standalone/files-tokens/fixture_typescript.ts.json +5 -0
  276. package/tests/fixtures_attended_results/standalone/files-tokens/fixture_zig.zig.json +5 -0
  277. package/tests/fixtures_attended_results/standalone/test-static-check-command/fixture_c.c.json +5 -0
  278. package/tests/fixtures_attended_results/standalone/test-static-check-command/fixture_cpp.cpp.json +5 -0
  279. package/tests/fixtures_attended_results/standalone/test-static-check-command/fixture_csharp.cs.json +5 -0
  280. package/tests/fixtures_attended_results/standalone/test-static-check-command/fixture_elixir.ex.json +5 -0
  281. package/tests/fixtures_attended_results/standalone/test-static-check-command/fixture_go.go.json +5 -0
  282. package/tests/fixtures_attended_results/standalone/test-static-check-command/fixture_haskell.hs.json +5 -0
  283. package/tests/fixtures_attended_results/standalone/test-static-check-command/fixture_java.java.json +5 -0
  284. package/tests/fixtures_attended_results/standalone/test-static-check-command/fixture_javascript.js.json +5 -0
  285. package/tests/fixtures_attended_results/standalone/test-static-check-command/fixture_kotlin.kt.json +5 -0
  286. package/tests/fixtures_attended_results/standalone/test-static-check-command/fixture_lua.lua.json +5 -0
  287. package/tests/fixtures_attended_results/standalone/test-static-check-command/fixture_perl.pl.json +5 -0
  288. package/tests/fixtures_attended_results/standalone/test-static-check-command/fixture_php.php.json +5 -0
  289. package/tests/fixtures_attended_results/standalone/test-static-check-command/fixture_python.py.json +5 -0
  290. package/tests/fixtures_attended_results/standalone/test-static-check-command/fixture_ruby.rb.json +5 -0
  291. package/tests/fixtures_attended_results/standalone/test-static-check-command/fixture_rust.rs.json +5 -0
  292. package/tests/fixtures_attended_results/standalone/test-static-check-command/fixture_scala.scala.json +5 -0
  293. package/tests/fixtures_attended_results/standalone/test-static-check-command/fixture_shell.sh.json +5 -0
  294. package/tests/fixtures_attended_results/standalone/test-static-check-command/fixture_swift.swift.json +5 -0
  295. package/tests/fixtures_attended_results/standalone/test-static-check-command/fixture_typescript.ts.json +5 -0
  296. package/tests/fixtures_attended_results/standalone/test-static-check-command/fixture_zig.zig.json +5 -0
  297. package/tests/fixtures_attended_results/standalone/test-static-check-dummy/fixture_c.c.json +5 -0
  298. package/tests/fixtures_attended_results/standalone/test-static-check-dummy/fixture_cpp.cpp.json +5 -0
  299. package/tests/fixtures_attended_results/standalone/test-static-check-dummy/fixture_csharp.cs.json +5 -0
  300. package/tests/fixtures_attended_results/standalone/test-static-check-dummy/fixture_elixir.ex.json +5 -0
  301. package/tests/fixtures_attended_results/standalone/test-static-check-dummy/fixture_go.go.json +5 -0
  302. package/tests/fixtures_attended_results/standalone/test-static-check-dummy/fixture_haskell.hs.json +5 -0
  303. package/tests/fixtures_attended_results/standalone/test-static-check-dummy/fixture_java.java.json +5 -0
  304. package/tests/fixtures_attended_results/standalone/test-static-check-dummy/fixture_javascript.js.json +5 -0
  305. package/tests/fixtures_attended_results/standalone/test-static-check-dummy/fixture_kotlin.kt.json +5 -0
  306. package/tests/fixtures_attended_results/standalone/test-static-check-dummy/fixture_lua.lua.json +5 -0
  307. package/tests/fixtures_attended_results/standalone/test-static-check-dummy/fixture_perl.pl.json +5 -0
  308. package/tests/fixtures_attended_results/standalone/test-static-check-dummy/fixture_php.php.json +5 -0
  309. package/tests/fixtures_attended_results/standalone/test-static-check-dummy/fixture_python.py.json +5 -0
  310. package/tests/fixtures_attended_results/standalone/test-static-check-dummy/fixture_ruby.rb.json +5 -0
  311. package/tests/fixtures_attended_results/standalone/test-static-check-dummy/fixture_rust.rs.json +5 -0
  312. package/tests/fixtures_attended_results/standalone/test-static-check-dummy/fixture_scala.scala.json +5 -0
  313. package/tests/fixtures_attended_results/standalone/test-static-check-dummy/fixture_shell.sh.json +5 -0
  314. package/tests/fixtures_attended_results/standalone/test-static-check-dummy/fixture_swift.swift.json +5 -0
  315. package/tests/fixtures_attended_results/standalone/test-static-check-dummy/fixture_typescript.ts.json +5 -0
  316. package/tests/fixtures_attended_results/standalone/test-static-check-dummy/fixture_zig.zig.json +5 -0
  317. package/tests/fixtures_attended_results/standalone/test-static-check-pylance/fixture_c.c.json +5 -0
  318. package/tests/fixtures_attended_results/standalone/test-static-check-pylance/fixture_cpp.cpp.json +5 -0
  319. package/tests/fixtures_attended_results/standalone/test-static-check-pylance/fixture_csharp.cs.json +5 -0
  320. package/tests/fixtures_attended_results/standalone/test-static-check-pylance/fixture_elixir.ex.json +5 -0
  321. package/tests/fixtures_attended_results/standalone/test-static-check-pylance/fixture_go.go.json +5 -0
  322. package/tests/fixtures_attended_results/standalone/test-static-check-pylance/fixture_haskell.hs.json +5 -0
  323. package/tests/fixtures_attended_results/standalone/test-static-check-pylance/fixture_java.java.json +5 -0
  324. package/tests/fixtures_attended_results/standalone/test-static-check-pylance/fixture_javascript.js.json +5 -0
  325. package/tests/fixtures_attended_results/standalone/test-static-check-pylance/fixture_kotlin.kt.json +5 -0
  326. package/tests/fixtures_attended_results/standalone/test-static-check-pylance/fixture_lua.lua.json +5 -0
  327. package/tests/fixtures_attended_results/standalone/test-static-check-pylance/fixture_perl.pl.json +5 -0
  328. package/tests/fixtures_attended_results/standalone/test-static-check-pylance/fixture_php.php.json +5 -0
  329. package/tests/fixtures_attended_results/standalone/test-static-check-pylance/fixture_python.py.json +5 -0
  330. package/tests/fixtures_attended_results/standalone/test-static-check-pylance/fixture_ruby.rb.json +5 -0
  331. package/tests/fixtures_attended_results/standalone/test-static-check-pylance/fixture_rust.rs.json +5 -0
  332. package/tests/fixtures_attended_results/standalone/test-static-check-pylance/fixture_scala.scala.json +5 -0
  333. package/tests/fixtures_attended_results/standalone/test-static-check-pylance/fixture_shell.sh.json +5 -0
  334. package/tests/fixtures_attended_results/standalone/test-static-check-pylance/fixture_swift.swift.json +5 -0
  335. package/tests/fixtures_attended_results/standalone/test-static-check-pylance/fixture_typescript.ts.json +5 -0
  336. package/tests/fixtures_attended_results/standalone/test-static-check-pylance/fixture_zig.zig.json +5 -0
  337. package/tests/fixtures_attended_results/standalone/test-static-check-ruff/fixture_c.c.json +5 -0
  338. package/tests/fixtures_attended_results/standalone/test-static-check-ruff/fixture_cpp.cpp.json +5 -0
  339. package/tests/fixtures_attended_results/standalone/test-static-check-ruff/fixture_csharp.cs.json +5 -0
  340. package/tests/fixtures_attended_results/standalone/test-static-check-ruff/fixture_elixir.ex.json +5 -0
  341. package/tests/fixtures_attended_results/standalone/test-static-check-ruff/fixture_go.go.json +5 -0
  342. package/tests/fixtures_attended_results/standalone/test-static-check-ruff/fixture_haskell.hs.json +5 -0
  343. package/tests/fixtures_attended_results/standalone/test-static-check-ruff/fixture_java.java.json +5 -0
  344. package/tests/fixtures_attended_results/standalone/test-static-check-ruff/fixture_javascript.js.json +5 -0
  345. package/tests/fixtures_attended_results/standalone/test-static-check-ruff/fixture_kotlin.kt.json +5 -0
  346. package/tests/fixtures_attended_results/standalone/test-static-check-ruff/fixture_lua.lua.json +5 -0
  347. package/tests/fixtures_attended_results/standalone/test-static-check-ruff/fixture_perl.pl.json +5 -0
  348. package/tests/fixtures_attended_results/standalone/test-static-check-ruff/fixture_php.php.json +5 -0
  349. package/tests/fixtures_attended_results/standalone/test-static-check-ruff/fixture_python.py.json +5 -0
  350. package/tests/fixtures_attended_results/standalone/test-static-check-ruff/fixture_ruby.rb.json +5 -0
  351. package/tests/fixtures_attended_results/standalone/test-static-check-ruff/fixture_rust.rs.json +5 -0
  352. package/tests/fixtures_attended_results/standalone/test-static-check-ruff/fixture_scala.scala.json +5 -0
  353. package/tests/fixtures_attended_results/standalone/test-static-check-ruff/fixture_shell.sh.json +5 -0
  354. package/tests/fixtures_attended_results/standalone/test-static-check-ruff/fixture_swift.swift.json +5 -0
  355. package/tests/fixtures_attended_results/standalone/test-static-check-ruff/fixture_typescript.ts.json +5 -0
  356. package/tests/fixtures_attended_results/standalone/test-static-check-ruff/fixture_zig.zig.json +5 -0
  357. package/tests/helpers.ts +204 -0
  358. package/tests/oracle-project.test.ts +63 -0
  359. package/tests/oracle-standalone.test.ts +48 -0
  360. package/tests/prompt-rendering.test.ts +66 -0
  361. package/tests/release-workflow.test.ts +133 -0
@@ -0,0 +1,621 @@
1
+ /**
2
+ * @file
3
+ * @brief Builds structured agent-tool JSON payloads for path, git, docs, worktree, and static-check tools.
4
+ * @details Converts extension-tool execution state into deterministic JSON-first payloads optimized for direct LLM traversal. The module normalizes execution metadata, path facts, required-doc status, worktree mutation facts, and static-check file-selection facts without depending on presentation-oriented text. Runtime is O(F) in the number of described files plus path normalization cost. Side effects are limited to filesystem reads.
5
+ */
6
+
7
+ import fs from "node:fs";
8
+ import path from "node:path";
9
+ import type { StaticCheckEntry } from "./config.js";
10
+ import type { RuntimePathFacts } from "./path-context.js";
11
+ import { ReqError } from "./errors.js";
12
+ import { STATIC_CHECK_EXT_TO_LANG } from "./static-check.js";
13
+ import type { ToolResult } from "./tool-runner.js";
14
+
15
+ /**
16
+ * @brief Describes normalized execution metadata shared by structured tool payloads.
17
+ * @details Separates numeric status, line-oriented diagnostics, and optional raw text so downstream agents can branch on stable fields before consulting residual text. The interface is compile-time only and introduces no runtime cost.
18
+ */
19
+ export interface ToolExecutionSection {
20
+ code: number;
21
+ stdout_line_count: number;
22
+ stderr_line_count: number;
23
+ stdout_lines: string[];
24
+ stderr_lines: string[];
25
+ stdout_text?: string;
26
+ stderr_text?: string;
27
+ }
28
+
29
+ /**
30
+ * @brief Describes the standard execute return wrapper used by structured agent tools.
31
+ * @details Mirrors the same JSON payload into both the text content channel and the machine-readable details channel so agents can consume stable fields without reparsing ad-hoc prose. The interface is compile-time only and introduces no runtime cost.
32
+ */
33
+ export interface StructuredToolExecuteResult<T> {
34
+ content: Array<{ type: "text"; text: string }>;
35
+ details: T;
36
+ }
37
+
38
+ /**
39
+ * @brief Describes the structured payload returned by path-query tools.
40
+ * @details Exposes the requested config key, caller cwd, resolved project base, resolved path value, and shared runtime path facts as direct-access fields. The interface is compile-time only and introduces no runtime cost.
41
+ */
42
+ export interface PathQueryToolPayload {
43
+ request: {
44
+ tool_name: string;
45
+ scope: "project-config";
46
+ working_directory_path: string;
47
+ project_base_path: string;
48
+ query_key: "git-path" | "base-path";
49
+ };
50
+ result: {
51
+ status: "resolved" | "empty";
52
+ path_key: "git-path" | "base-path";
53
+ path_value: string;
54
+ path_present: boolean;
55
+ };
56
+ runtime_paths: RuntimePathFacts;
57
+ execution: ToolExecutionSection;
58
+ }
59
+
60
+ /**
61
+ * @brief Describes the structured payload returned by `git-check`.
62
+ * @details Exposes git-root presence, repository validation status, shared runtime path facts, and normalized execution diagnostics as stable fields. The interface is compile-time only and introduces no runtime cost.
63
+ */
64
+ export interface GitCheckToolPayload {
65
+ request: {
66
+ tool_name: "git-check";
67
+ scope: "project-config";
68
+ project_base_path: string;
69
+ configured_git_path: string;
70
+ git_path_present: boolean;
71
+ };
72
+ result: {
73
+ status: "clean" | "error";
74
+ worktree_status: "clean" | "unknown";
75
+ head_status: "valid" | "unknown";
76
+ error_message?: string;
77
+ };
78
+ runtime_paths: RuntimePathFacts;
79
+ execution: ToolExecutionSection;
80
+ }
81
+
82
+ /**
83
+ * @brief Describes one canonical-doc status record returned by `docs-check`.
84
+ * @details Binds each required filename to its prompt generator, normalized path facts, and presence status so agents can branch per missing document deterministically. The interface is compile-time only and introduces no runtime cost.
85
+ */
86
+ export interface DocsCheckFileRecord {
87
+ file_name: string;
88
+ canonical_path: string;
89
+ absolute_path: string;
90
+ prompt_command: string;
91
+ exists: boolean;
92
+ is_file: boolean;
93
+ status: "present" | "missing";
94
+ }
95
+
96
+ /**
97
+ * @brief Describes the structured payload returned by `docs-check`.
98
+ * @details Exposes docs-root selection, per-document presence facts, remediation prompt commands, shared runtime path facts, and execution diagnostics as stable JSON fields. The interface is compile-time only and introduces no runtime cost.
99
+ */
100
+ export interface DocsCheckToolPayload {
101
+ request: {
102
+ tool_name: "docs-check";
103
+ scope: "canonical-docs";
104
+ project_base_path: string;
105
+ docs_directory_path: string;
106
+ required_file_count: number;
107
+ required_file_names: string[];
108
+ };
109
+ summary: {
110
+ present_file_count: number;
111
+ missing_file_count: number;
112
+ };
113
+ files: DocsCheckFileRecord[];
114
+ runtime_paths: RuntimePathFacts;
115
+ execution: ToolExecutionSection;
116
+ }
117
+
118
+ /**
119
+ * @brief Describes the structured payload returned by `git-wt-name`.
120
+ * @details Exposes the generated worktree name, its normative format, shared runtime path facts, and execution diagnostics as direct-access fields. The interface is compile-time only and introduces no runtime cost.
121
+ */
122
+ export interface WorktreeNameToolPayload {
123
+ request: {
124
+ tool_name: "git-wt-name";
125
+ scope: "project-config";
126
+ project_base_path: string;
127
+ configured_git_path: string;
128
+ };
129
+ result: {
130
+ status: "generated" | "error";
131
+ worktree_name?: string;
132
+ format_text: "useReq-<project>-<sanitized-branch>-<YYYYMMDDHHMMSS>";
133
+ error_message?: string;
134
+ };
135
+ runtime_paths: RuntimePathFacts;
136
+ execution: ToolExecutionSection;
137
+ }
138
+
139
+ /**
140
+ * @brief Describes the structured payload returned by worktree mutation tools.
141
+ * @details Exposes the requested operation, exact worktree name, derived worktree path, mutation status, shared runtime path facts, and execution diagnostics as stable JSON fields. The interface is compile-time only and introduces no runtime cost.
142
+ */
143
+ export interface WorktreeMutationToolPayload {
144
+ request: {
145
+ tool_name: "git-wt-create" | "git-wt-delete";
146
+ scope: "project-config";
147
+ operation: "create" | "delete";
148
+ project_base_path: string;
149
+ configured_git_path: string;
150
+ worktree_name: string;
151
+ };
152
+ result: {
153
+ status: "created" | "deleted" | "error";
154
+ worktree_name: string;
155
+ branch_name: string;
156
+ worktree_path: string;
157
+ error_message?: string;
158
+ };
159
+ runtime_paths: RuntimePathFacts;
160
+ execution: ToolExecutionSection;
161
+ }
162
+
163
+ /**
164
+ * @brief Describes one file-selection record inside a static-check payload.
165
+ * @details Exposes request order, normalized path facts, detected language, configured checker modules, and stable selection status without forcing agents to parse checker output text. The interface is compile-time only and introduces no runtime cost.
166
+ */
167
+ export interface StaticCheckFileRecord {
168
+ request_index: number;
169
+ input_path: string;
170
+ canonical_path: string;
171
+ absolute_path: string;
172
+ exists: boolean;
173
+ is_file: boolean;
174
+ language_name?: string;
175
+ configured_checker_count: number;
176
+ configured_checker_modules: string[];
177
+ status: "selected" | "skipped" | "unsupported_language" | "no_configured_checkers";
178
+ error_message?: string;
179
+ }
180
+
181
+ /**
182
+ * @brief Describes the structured payload returned by static-check agent tools.
183
+ * @details Exposes scope selection, configured checker coverage, per-file selection facts, shared runtime path facts, and normalized execution diagnostics while keeping residual checker text optional under execution. The interface is compile-time only and introduces no runtime cost.
184
+ */
185
+ export interface StaticCheckToolPayload {
186
+ request: {
187
+ tool_name: "files-static-check" | "static-check";
188
+ scope: "explicit-files" | "configured-source-and-test-directories";
189
+ project_base_path: string;
190
+ configured_language_count: number;
191
+ configured_languages: string[];
192
+ selection_directory_paths: string[];
193
+ excluded_directory_paths: string[];
194
+ requested_file_count: number;
195
+ requested_input_paths: string[];
196
+ };
197
+ summary: {
198
+ selected_file_count: number;
199
+ skipped_file_count: number;
200
+ unsupported_file_count: number;
201
+ no_configured_checker_file_count: number;
202
+ total_configured_checker_count: number;
203
+ };
204
+ files: StaticCheckFileRecord[];
205
+ runtime_paths: RuntimePathFacts;
206
+ execution: ToolExecutionSection;
207
+ }
208
+
209
+ /**
210
+ * @brief Serializes one structured payload as pretty-printed JSON.
211
+ * @details Uses two-space indentation and omits a trailing newline so the mirrored text payload remains deterministic and compact. Runtime is O(n) in payload size. No external state is mutated.
212
+ * @param[in] payload {unknown} Structured JSON-compatible payload.
213
+ * @return {string} Pretty-printed JSON text.
214
+ */
215
+ function formatJsonToolPayload(payload: unknown): string {
216
+ return JSON.stringify(payload, null, 2);
217
+ }
218
+
219
+ /**
220
+ * @brief Splits one stdout or stderr text block into normalized non-empty lines.
221
+ * @details Trims trailing newlines, preserves internal line order, and omits empty records so downstream agents can branch on stable arrays without reparsing blank output. Runtime is O(n) in text length. No external state is mutated.
222
+ * @param[in] text {string} Raw output text.
223
+ * @return {string[]} Normalized non-empty output lines.
224
+ */
225
+ function splitToolOutputLines(text: string): string[] {
226
+ const trimmed = text.trim();
227
+ return trimmed === "" ? [] : trimmed.split(/\r?\n/);
228
+ }
229
+
230
+ /**
231
+ * @brief Normalizes one path into a canonical slash-separated form relative to the project base when possible.
232
+ * @details Resolves the candidate against the provided base, emits a relative path for in-project targets, and falls back to an absolute slash-normalized path for external targets. Runtime is O(p) in path length. No external state is mutated.
233
+ * @param[in] baseDir {string} Absolute project base path.
234
+ * @param[in] candidatePath {string} Relative or absolute path candidate.
235
+ * @return {string} Canonical slash-normalized path.
236
+ */
237
+ function canonicalizeToolPath(baseDir: string, candidatePath: string): string {
238
+ const absolutePath = path.resolve(baseDir, candidatePath);
239
+ const relativePath = path.relative(baseDir, absolutePath);
240
+ if (relativePath !== "" && !relativePath.startsWith("..") && !path.isAbsolute(relativePath)) {
241
+ return relativePath.split(path.sep).join("/");
242
+ }
243
+ return absolutePath.split(path.sep).join("/");
244
+ }
245
+
246
+ /**
247
+ * @brief Converts one structured tool payload into the standard execute wrapper.
248
+ * @details Mirrors the same payload into `content[0].text` and `details` so agents can use direct JSON fields or raw JSON text interchangeably without divergence. Runtime is O(n) in payload size. No external state is mutated.
249
+ * @param[in] payload {T} Structured payload containing an `execution` section.
250
+ * @return {StructuredToolExecuteResult<T>} Standard execute wrapper with mirrored payload.
251
+ */
252
+ export function buildStructuredToolExecuteResult<T extends { execution: ToolExecutionSection }>(
253
+ payload: T,
254
+ ): StructuredToolExecuteResult<T> {
255
+ return {
256
+ content: [{ type: "text", text: formatJsonToolPayload(payload) }],
257
+ details: payload,
258
+ };
259
+ }
260
+
261
+ /**
262
+ * @brief Converts one raw `ToolResult` into a normalized execution section.
263
+ * @details Separates numeric exit status, line-oriented stdout/stderr arrays, and optional raw text so downstream agents can consume structured facts before consulting residual text. Runtime is O(n) in output size. No external state is mutated.
264
+ * @param[in] result {ToolResult} Raw tool result.
265
+ * @return {ToolExecutionSection} Normalized execution metadata.
266
+ */
267
+ export function buildToolExecutionSection(result: ToolResult): ToolExecutionSection {
268
+ const stdoutText = result.stdout.trimEnd();
269
+ const stderrText = result.stderr.trimEnd();
270
+ const stdoutLines = splitToolOutputLines(stdoutText);
271
+ const stderrLines = splitToolOutputLines(stderrText);
272
+ return {
273
+ code: result.code,
274
+ stdout_line_count: stdoutLines.length,
275
+ stderr_line_count: stderrLines.length,
276
+ stdout_lines: stdoutLines,
277
+ stderr_lines: stderrLines,
278
+ stdout_text: stdoutText === "" ? undefined : stdoutText,
279
+ stderr_text: stderrText === "" ? undefined : stderrText,
280
+ };
281
+ }
282
+
283
+ /**
284
+ * @brief Converts one `ReqError` into a synthetic `ToolResult` for structured payload emission.
285
+ * @details Preserves the numeric exit code and message in stderr so agent tools can return deterministic JSON even when the underlying runner fails. Non-`ReqError` values are rethrown. Runtime is O(1). No external state is mutated.
286
+ * @param[in] error {unknown} Thrown value captured from a runner.
287
+ * @return {ToolResult} Synthetic tool result with empty stdout.
288
+ * @throws {unknown} Rethrows non-`ReqError` failures unchanged.
289
+ */
290
+ export function normalizeToolFailure(error: unknown): ToolResult {
291
+ if (error instanceof ReqError) {
292
+ return {
293
+ stdout: "",
294
+ stderr: error.message,
295
+ code: error.code,
296
+ };
297
+ }
298
+ throw error;
299
+ }
300
+
301
+ /**
302
+ * @brief Builds the structured payload returned by `git-path` or `get-base-path`.
303
+ * @details Exposes the resolved runtime path value as a direct-access field and preserves normalized execution metadata separately from path facts. Runtime is O(p) in path length. No external state is mutated.
304
+ * @param[in] toolName {"git-path" | "get-base-path"} Target tool name.
305
+ * @param[in] workingDirectoryPath {string} Caller working directory.
306
+ * @param[in] projectBasePath {string} Resolved project base path.
307
+ * @param[in] resolvedPath {string} Resolved config path value.
308
+ * @param[in] runtimePaths {RuntimePathFacts} Shared runtime path facts.
309
+ * @param[in] execution {ToolExecutionSection} Normalized execution metadata.
310
+ * @return {PathQueryToolPayload} Structured path-query payload.
311
+ */
312
+ export function buildPathQueryToolPayload(
313
+ toolName: "git-path" | "get-base-path",
314
+ workingDirectoryPath: string,
315
+ projectBasePath: string,
316
+ resolvedPath: string,
317
+ runtimePaths: RuntimePathFacts,
318
+ execution: ToolExecutionSection,
319
+ ): PathQueryToolPayload {
320
+ const queryKey = toolName === "git-path" ? "git-path" : "base-path";
321
+ return {
322
+ request: {
323
+ tool_name: toolName,
324
+ scope: "project-config",
325
+ working_directory_path: path.resolve(workingDirectoryPath).split(path.sep).join("/"),
326
+ project_base_path: path.resolve(projectBasePath).split(path.sep).join("/"),
327
+ query_key: queryKey,
328
+ },
329
+ result: {
330
+ status: resolvedPath === "" ? "empty" : "resolved",
331
+ path_key: queryKey,
332
+ path_value: resolvedPath,
333
+ path_present: resolvedPath !== "",
334
+ },
335
+ runtime_paths: runtimePaths,
336
+ execution,
337
+ };
338
+ }
339
+
340
+ /**
341
+ * @brief Builds the structured payload returned by `git-check`.
342
+ * @details Encodes runtime git-root presence plus clean-versus-error status as direct fields while preserving raw diagnostics under execution. Runtime is O(p) in path length. No external state is mutated.
343
+ * @param[in] projectBasePath {string} Resolved project base path.
344
+ * @param[in] configuredGitPath {string | undefined} Runtime git root path.
345
+ * @param[in] runtimePaths {RuntimePathFacts} Shared runtime path facts.
346
+ * @param[in] execution {ToolExecutionSection} Normalized execution metadata.
347
+ * @return {GitCheckToolPayload} Structured git-check payload.
348
+ */
349
+ export function buildGitCheckToolPayload(
350
+ projectBasePath: string,
351
+ configuredGitPath: string | undefined,
352
+ runtimePaths: RuntimePathFacts,
353
+ execution: ToolExecutionSection,
354
+ ): GitCheckToolPayload {
355
+ const errorMessage = execution.stderr_lines[0];
356
+ return {
357
+ request: {
358
+ tool_name: "git-check",
359
+ scope: "project-config",
360
+ project_base_path: path.resolve(projectBasePath).split(path.sep).join("/"),
361
+ configured_git_path: configuredGitPath ?? "",
362
+ git_path_present: Boolean(configuredGitPath),
363
+ },
364
+ result: {
365
+ status: execution.code === 0 ? "clean" : "error",
366
+ worktree_status: execution.code === 0 ? "clean" : "unknown",
367
+ head_status: execution.code === 0 ? "valid" : "unknown",
368
+ error_message: execution.code === 0 ? undefined : errorMessage,
369
+ },
370
+ runtime_paths: runtimePaths,
371
+ execution,
372
+ };
373
+ }
374
+
375
+ /**
376
+ * @brief Builds the structured payload returned by `docs-check`.
377
+ * @details Enumerates required canonical documents, binds each missing file to its remediation prompt command, and emits summary counts plus normalized execution metadata. Runtime is O(k) in required file count plus filesystem reads. Side effects are limited to filesystem reads.
378
+ * @param[in] projectBasePath {string} Resolved project base path.
379
+ * @param[in] docsDirPath {string} Configured docs directory relative to the project base.
380
+ * @param[in] runtimePaths {RuntimePathFacts} Shared runtime path facts.
381
+ * @return {DocsCheckToolPayload} Structured docs-check payload.
382
+ */
383
+ export function buildDocsCheckToolPayload(
384
+ projectBasePath: string,
385
+ docsDirPath: string,
386
+ runtimePaths: RuntimePathFacts,
387
+ ): DocsCheckToolPayload {
388
+ const normalizedProjectBasePath = path.resolve(projectBasePath);
389
+ const normalizedDocsRootPath = path.join(normalizedProjectBasePath, docsDirPath.replace(/[/\\]+$/, ""));
390
+ const files: DocsCheckFileRecord[] = [
391
+ ["REQUIREMENTS.md", "/req-write"],
392
+ ["WORKFLOW.md", "/req-workflow"],
393
+ ["REFERENCES.md", "/req-references"],
394
+ ].map(([fileName, promptCommand]) => {
395
+ const absolutePath = path.join(normalizedDocsRootPath, fileName);
396
+ const exists = fs.existsSync(absolutePath);
397
+ const isFile = exists && fs.statSync(absolutePath).isFile();
398
+ return {
399
+ file_name: fileName,
400
+ canonical_path: canonicalizeToolPath(normalizedProjectBasePath, absolutePath),
401
+ absolute_path: absolutePath.split(path.sep).join("/"),
402
+ prompt_command: promptCommand,
403
+ exists,
404
+ is_file: isFile,
405
+ status: isFile ? "present" : "missing",
406
+ };
407
+ });
408
+ const missingFiles = files.filter((file) => file.status === "missing");
409
+ const execution = buildToolExecutionSection({
410
+ stdout: "",
411
+ stderr: missingFiles
412
+ .map((file) => `missing: ${file.canonical_path}: generate with ${file.prompt_command}`)
413
+ .join("\n"),
414
+ code: missingFiles.length === 0 ? 0 : 1,
415
+ });
416
+ return {
417
+ request: {
418
+ tool_name: "docs-check",
419
+ scope: "canonical-docs",
420
+ project_base_path: normalizedProjectBasePath.split(path.sep).join("/"),
421
+ docs_directory_path: normalizedDocsRootPath.split(path.sep).join("/"),
422
+ required_file_count: files.length,
423
+ required_file_names: files.map((file) => file.file_name),
424
+ },
425
+ summary: {
426
+ present_file_count: files.length - missingFiles.length,
427
+ missing_file_count: missingFiles.length,
428
+ },
429
+ files,
430
+ runtime_paths: runtimePaths,
431
+ execution,
432
+ };
433
+ }
434
+
435
+ /**
436
+ * @brief Builds the structured payload returned by `git-wt-name`.
437
+ * @details Preserves the generated worktree name plus its normative format string as direct-access fields and reports failures through structured execution metadata. Runtime is O(n) in output size. No external state is mutated.
438
+ * @param[in] projectBasePath {string} Resolved project base path.
439
+ * @param[in] configuredGitPath {string | undefined} Runtime git root path.
440
+ * @param[in] runtimePaths {RuntimePathFacts} Shared runtime path facts.
441
+ * @param[in] execution {ToolExecutionSection} Normalized execution metadata.
442
+ * @return {WorktreeNameToolPayload} Structured worktree-name payload.
443
+ */
444
+ export function buildWorktreeNameToolPayload(
445
+ projectBasePath: string,
446
+ configuredGitPath: string | undefined,
447
+ runtimePaths: RuntimePathFacts,
448
+ execution: ToolExecutionSection,
449
+ ): WorktreeNameToolPayload {
450
+ const worktreeName = execution.stdout_lines[0];
451
+ return {
452
+ request: {
453
+ tool_name: "git-wt-name",
454
+ scope: "project-config",
455
+ project_base_path: path.resolve(projectBasePath).split(path.sep).join("/"),
456
+ configured_git_path: configuredGitPath ?? "",
457
+ },
458
+ result: {
459
+ status: execution.code === 0 && worktreeName ? "generated" : "error",
460
+ worktree_name: worktreeName,
461
+ format_text: "useReq-<project>-<sanitized-branch>-<YYYYMMDDHHMMSS>",
462
+ error_message: execution.code === 0 ? undefined : execution.stderr_lines[0],
463
+ },
464
+ runtime_paths: runtimePaths,
465
+ execution,
466
+ };
467
+ }
468
+
469
+ /**
470
+ * @brief Builds the structured payload returned by `git-wt-create` or `git-wt-delete`.
471
+ * @details Exposes the requested operation, exact worktree name, derived worktree path, and mutation outcome as stable JSON fields while preserving raw diagnostics under execution. Runtime is O(p) in path length. No external state is mutated.
472
+ * @param[in] toolName {"git-wt-create" | "git-wt-delete"} Target tool name.
473
+ * @param[in] projectBasePath {string} Resolved project base path.
474
+ * @param[in] configuredGitPath {string | undefined} Runtime git root path.
475
+ * @param[in] worktreeName {string} Exact requested worktree name.
476
+ * @param[in] runtimePaths {RuntimePathFacts} Shared runtime path facts.
477
+ * @param[in] execution {ToolExecutionSection} Normalized execution metadata.
478
+ * @return {WorktreeMutationToolPayload} Structured worktree mutation payload.
479
+ */
480
+ export function buildWorktreeMutationToolPayload(
481
+ toolName: "git-wt-create" | "git-wt-delete",
482
+ projectBasePath: string,
483
+ configuredGitPath: string | undefined,
484
+ worktreeName: string,
485
+ runtimePaths: RuntimePathFacts,
486
+ execution: ToolExecutionSection,
487
+ ): WorktreeMutationToolPayload {
488
+ const gitRoot = configuredGitPath ? path.resolve(configuredGitPath) : "";
489
+ const worktreePath = gitRoot === ""
490
+ ? ""
491
+ : path.join(path.dirname(gitRoot), worktreeName).split(path.sep).join("/");
492
+ const operation = toolName === "git-wt-create" ? "create" : "delete";
493
+ return {
494
+ request: {
495
+ tool_name: toolName,
496
+ scope: "project-config",
497
+ operation,
498
+ project_base_path: path.resolve(projectBasePath).split(path.sep).join("/"),
499
+ configured_git_path: configuredGitPath ?? "",
500
+ worktree_name: worktreeName,
501
+ },
502
+ result: {
503
+ status: execution.code === 0
504
+ ? (operation === "create" ? "created" : "deleted")
505
+ : "error",
506
+ worktree_name: worktreeName,
507
+ branch_name: worktreeName,
508
+ worktree_path: worktreePath,
509
+ error_message: execution.code === 0 ? undefined : execution.stderr_lines[0],
510
+ },
511
+ runtime_paths: runtimePaths,
512
+ execution,
513
+ };
514
+ }
515
+
516
+ /**
517
+ * @brief Builds one static-check file-selection record.
518
+ * @details Resolves filesystem status, detects the configured language by file extension, counts configured checker entries, and emits a stable selection status without parsing checker output text. Runtime is O(p + c) in path length plus configured checker count. Side effects are limited to filesystem reads.
519
+ * @param[in] inputPath {string} Caller-supplied file path.
520
+ * @param[in] requestIndex {number} Zero-based request position.
521
+ * @param[in] projectBasePath {string} Resolved project base path.
522
+ * @param[in] staticCheckConfig {Record<string, StaticCheckEntry[]>} Effective static-check configuration.
523
+ * @return {StaticCheckFileRecord} Structured file-selection record.
524
+ */
525
+ function buildStaticCheckFileRecord(
526
+ inputPath: string,
527
+ requestIndex: number,
528
+ projectBasePath: string,
529
+ staticCheckConfig: Record<string, StaticCheckEntry[]>,
530
+ ): StaticCheckFileRecord {
531
+ const absolutePath = path.resolve(projectBasePath, inputPath);
532
+ const exists = fs.existsSync(absolutePath);
533
+ const isFile = exists && fs.statSync(absolutePath).isFile();
534
+ const languageName = isFile ? STATIC_CHECK_EXT_TO_LANG[path.extname(absolutePath).toLowerCase()] : undefined;
535
+ const configuredCheckers = languageName ? [...(staticCheckConfig[languageName] ?? [])] : [];
536
+ let status: StaticCheckFileRecord["status"] = "selected";
537
+ let errorMessage: string | undefined;
538
+ if (!exists) {
539
+ status = "skipped";
540
+ errorMessage = "not found";
541
+ } else if (!isFile) {
542
+ status = "skipped";
543
+ errorMessage = "not a file";
544
+ } else if (!languageName) {
545
+ status = "unsupported_language";
546
+ errorMessage = "unsupported language";
547
+ } else if (configuredCheckers.length === 0) {
548
+ status = "no_configured_checkers";
549
+ errorMessage = "no configured checkers";
550
+ }
551
+ return {
552
+ request_index: requestIndex,
553
+ input_path: inputPath,
554
+ canonical_path: canonicalizeToolPath(projectBasePath, absolutePath),
555
+ absolute_path: absolutePath.split(path.sep).join("/"),
556
+ exists,
557
+ is_file: isFile,
558
+ language_name: languageName,
559
+ configured_checker_count: configuredCheckers.length,
560
+ configured_checker_modules: configuredCheckers.map((checker) => checker.module),
561
+ status,
562
+ error_message: errorMessage,
563
+ };
564
+ }
565
+
566
+ /**
567
+ * @brief Builds the structured payload returned by `files-static-check` or `static-check`.
568
+ * @details Exposes configured checker coverage, per-file selection facts, and normalized execution diagnostics while leaving raw checker output under execution for residual inspection only. Runtime is O(F + C). Side effects are limited to filesystem reads.
569
+ * @param[in] toolName {"files-static-check" | "static-check"} Target tool name.
570
+ * @param[in] scope {"explicit-files" | "configured-source-and-test-directories"} Selection scope label.
571
+ * @param[in] projectBasePath {string} Resolved project base path.
572
+ * @param[in] requestedPaths {string[]} Explicit or discovered file paths.
573
+ * @param[in] selectionDirectoryPaths {string[]} Directories that produced the selection.
574
+ * @param[in] excludedDirectoryPaths {string[]} Directory roots excluded from project selection.
575
+ * @param[in] staticCheckConfig {Record<string, StaticCheckEntry[]>} Effective static-check configuration.
576
+ * @param[in] runtimePaths {RuntimePathFacts} Shared runtime path facts.
577
+ * @param[in] execution {ToolExecutionSection} Normalized execution metadata.
578
+ * @return {StaticCheckToolPayload} Structured static-check payload.
579
+ */
580
+ export function buildStaticCheckToolPayload(
581
+ toolName: "files-static-check" | "static-check",
582
+ scope: "explicit-files" | "configured-source-and-test-directories",
583
+ projectBasePath: string,
584
+ requestedPaths: string[],
585
+ selectionDirectoryPaths: string[],
586
+ excludedDirectoryPaths: string[],
587
+ staticCheckConfig: Record<string, StaticCheckEntry[]>,
588
+ runtimePaths: RuntimePathFacts,
589
+ execution: ToolExecutionSection,
590
+ ): StaticCheckToolPayload {
591
+ const files = requestedPaths.map((inputPath, index) => buildStaticCheckFileRecord(
592
+ inputPath,
593
+ index,
594
+ projectBasePath,
595
+ staticCheckConfig,
596
+ ));
597
+ const configuredLanguages = Object.keys(staticCheckConfig).sort((left, right) => left.localeCompare(right));
598
+ return {
599
+ request: {
600
+ tool_name: toolName,
601
+ scope,
602
+ project_base_path: path.resolve(projectBasePath).split(path.sep).join("/"),
603
+ configured_language_count: configuredLanguages.length,
604
+ configured_languages: configuredLanguages,
605
+ selection_directory_paths: [...selectionDirectoryPaths],
606
+ excluded_directory_paths: [...excludedDirectoryPaths],
607
+ requested_file_count: requestedPaths.length,
608
+ requested_input_paths: [...requestedPaths],
609
+ },
610
+ summary: {
611
+ selected_file_count: files.filter((file) => file.status === "selected").length,
612
+ skipped_file_count: files.filter((file) => file.status === "skipped").length,
613
+ unsupported_file_count: files.filter((file) => file.status === "unsupported_language").length,
614
+ no_configured_checker_file_count: files.filter((file) => file.status === "no_configured_checkers").length,
615
+ total_configured_checker_count: files.reduce((sum, file) => sum + file.configured_checker_count, 0),
616
+ },
617
+ files,
618
+ runtime_paths: runtimePaths,
619
+ execution,
620
+ };
621
+ }
@@ -0,0 +1,72 @@
1
+ /**
2
+ * @file
3
+ * @brief Compresses explicit source-file lists into compact fenced-markdown excerpts.
4
+ * @details Bridges file validation, language detection, per-file source compression, and final markdown packaging for prompt consumption. Runtime is O(F + S) where F is file count and S is total source size processed. Side effects are limited to filesystem reads and optional stderr logging.
5
+ */
6
+
7
+ import fs from "node:fs";
8
+ import path from "node:path";
9
+ import { compressFileDetailed, detectLanguage } from "./compress.js";
10
+
11
+ /**
12
+ * @brief Formats one source path for markdown output.
13
+ * @details Returns the original file path when no base is provided. Otherwise computes a normalized POSIX-style relative path against the resolved output base. Time complexity is O(p) in path length. No I/O side effects occur.
14
+ * @param[in] filePath {string} Source file path.
15
+ * @param[in] outputBase {string | undefined} Optional base directory for relative formatting.
16
+ * @return {string} Display path used in the markdown header.
17
+ */
18
+ function formatOutputPath(filePath: string, outputBase?: string): string {
19
+ if (!outputBase) return filePath;
20
+ return path.posix.normalize(path.relative(outputBase, path.resolve(filePath)).split(path.sep).join("/"));
21
+ }
22
+
23
+ /**
24
+ * @brief Compresses a list of explicit source files into concatenated markdown sections.
25
+ * @details Validates file existence, infers each supported language, invokes per-file compression, preserves optional line numbers, and emits one fenced block per successful file. Runtime is O(F + S) where F is file count and S is total processed source size. Side effects are limited to filesystem reads and optional stderr progress logging.
26
+ * @param[in] filePaths {string[]} Explicit file paths to process.
27
+ * @param[in] includeLineNumbers {boolean} When `true`, preserve original source line numbers in the emitted code block.
28
+ * @param[in] verbose {boolean} When `true`, write progress and skip diagnostics to stderr.
29
+ * @param[in] outputBase {string | undefined} Optional base directory used to shorten output paths.
30
+ * @return {string} Markdown document containing one section per successfully compressed file.
31
+ * @throws {Error} Throws when no valid source files can be processed.
32
+ */
33
+ export function compressFiles(
34
+ filePaths: string[],
35
+ includeLineNumbers = true,
36
+ verbose = false,
37
+ outputBase?: string,
38
+ ): string {
39
+ const parts: string[] = [];
40
+ let okCount = 0;
41
+ let failCount = 0;
42
+ const resolvedOutputBase = outputBase ? path.resolve(outputBase) : undefined;
43
+
44
+ for (const filePath of filePaths) {
45
+ if (!fs.existsSync(filePath) || !fs.statSync(filePath).isFile()) {
46
+ if (verbose) console.error(` SKIP ${filePath} (not found)`);
47
+ continue;
48
+ }
49
+ const language = detectLanguage(filePath);
50
+ if (!language) {
51
+ if (verbose) console.error(` SKIP ${filePath} (unsupported extension)`);
52
+ continue;
53
+ }
54
+ try {
55
+ const compressed = compressFileDetailed(filePath, language, includeLineNumbers);
56
+ const outputPath = formatOutputPath(filePath, resolvedOutputBase);
57
+ parts.push(`@@@ ${outputPath} | ${language}\n> Lines: ${compressed.source_start_line_number}-${compressed.source_end_line_number}\n\
58
+ \`\`\`\n${compressed.compressed_source_text}\n\`\`\``);
59
+ okCount += 1;
60
+ if (verbose) console.error(` OK ${filePath}`);
61
+ } catch (error) {
62
+ failCount += 1;
63
+ if (verbose) console.error(` FAIL ${filePath} (${error instanceof Error ? error.message : String(error)})`);
64
+ }
65
+ }
66
+
67
+ if (parts.length === 0) {
68
+ throw new Error("No valid source files processed");
69
+ }
70
+ if (verbose) console.error(`\n Compressed: ${okCount} ok, ${failCount} failed`);
71
+ return parts.join("\n\n");
72
+ }