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,463 @@
1
+ import test from "node:test";
2
+ import assert from "node:assert/strict";
3
+ import { spawnSync } from "node:child_process";
4
+ import fs from "node:fs";
5
+ import path from "node:path";
6
+ import { fileURLToPath } from "node:url";
7
+ import {
8
+ inspectExtension,
9
+ replayCommand,
10
+ replaySessionStart,
11
+ replayTool,
12
+ type OfflineContractSnapshot,
13
+ } from "../scripts/lib/extension-debug-harness.js";
14
+ import { buildParityReport, type SdkContractSnapshot } from "../scripts/lib/sdk-smoke.js";
15
+ import { getProjectConfigPath } from "../src/core/config.js";
16
+ import { PI_USEREQ_STATUS_HOOK_NAMES } from "../src/core/extension-status.js";
17
+ import { initFixtureRepo } from "./helpers.js";
18
+
19
+ /**
20
+ * @brief Persists a targeted enabled-tool list into a fixture project config.
21
+ * @details Loads `.pi-usereq/config.json`, replaces the `enabled-tools` array with the supplied values, and writes the updated JSON back to disk with a trailing newline. Runtime is O(n) in config size. Side effects include filesystem reads and file overwrite.
22
+ * @param[in] projectBase {string} Fixture project root.
23
+ * @param[in] enabledTools {string[]} Enabled-tool names to persist.
24
+ * @return {void} No return value.
25
+ */
26
+ function writeEnabledTools(projectBase: string, enabledTools: string[]): void {
27
+ const configPath = getProjectConfigPath(projectBase);
28
+ const config = JSON.parse(fs.readFileSync(configPath, "utf8")) as Record<string, unknown>;
29
+ config["enabled-tools"] = enabledTools;
30
+ fs.writeFileSync(configPath, `${JSON.stringify(config, null, 2)}\n`, "utf8");
31
+ }
32
+
33
+ /**
34
+ * @brief Builds a minimal offline snapshot fixture for parity-comparator tests.
35
+ * @details Returns a deterministic inventory snapshot containing one command, one tool, and one active tool so mismatch categories can be unit-tested without invoking the real SDK. Runtime is O(1). No side effects occur.
36
+ * @return {OfflineContractSnapshot} Synthetic offline snapshot.
37
+ */
38
+ function buildOfflineFixture(): OfflineContractSnapshot {
39
+ return {
40
+ extensionPath: "/repo/src/index.ts",
41
+ requestedCwd: "/repo",
42
+ effectiveCtxCwd: "/repo",
43
+ effectiveProcessCwd: "/repo",
44
+ commands: [
45
+ {
46
+ name: "req-analyze",
47
+ description: "Run pi-usereq prompt analyze",
48
+ source: "extension",
49
+ sourceInfo: {
50
+ path: "/repo/src/index.ts",
51
+ source: "extension",
52
+ scope: "project",
53
+ origin: "top-level",
54
+ baseDir: "/repo/src",
55
+ },
56
+ },
57
+ ],
58
+ tools: [
59
+ {
60
+ name: "git-path",
61
+ description: "Return the runtime-derived git root path for the current working directory.",
62
+ promptGuidelines: [],
63
+ hasParameters: false,
64
+ sourceInfo: {
65
+ path: "/repo/src/index.ts",
66
+ source: "extension",
67
+ scope: "project",
68
+ origin: "top-level",
69
+ baseDir: "/repo/src",
70
+ },
71
+ },
72
+ ],
73
+ eventHandlers: ["session_start"],
74
+ activeTools: ["git-path"],
75
+ sentUserMessages: [],
76
+ };
77
+ }
78
+
79
+ /**
80
+ * @brief Builds a minimal SDK snapshot fixture for parity-comparator tests.
81
+ * @details Returns a deterministic SDK inventory snapshot aligned with `buildOfflineFixture()` unless overridden by the caller. Runtime is O(1). No side effects occur.
82
+ * @param[in] overrides {Partial<SdkContractSnapshot> | undefined} Optional field overrides.
83
+ * @return {SdkContractSnapshot} Synthetic SDK snapshot.
84
+ */
85
+ function buildSdkFixture(overrides?: Partial<SdkContractSnapshot>): SdkContractSnapshot {
86
+ return {
87
+ extensionPath: "/repo/src/index.ts",
88
+ requestedCwd: "/repo",
89
+ commands: [
90
+ {
91
+ name: "req-analyze",
92
+ description: "Run pi-usereq prompt analyze",
93
+ sourceInfo: {
94
+ path: "src/index.ts",
95
+ source: "extension",
96
+ scope: "project",
97
+ origin: "top-level",
98
+ baseDir: "src",
99
+ },
100
+ },
101
+ ],
102
+ tools: [
103
+ {
104
+ name: "git-path",
105
+ description: "Return the runtime-derived git root path for the current working directory.",
106
+ hasParameters: false,
107
+ sourceInfo: {
108
+ path: "src/index.ts",
109
+ source: "extension",
110
+ scope: "project",
111
+ origin: "top-level",
112
+ baseDir: "src",
113
+ },
114
+ },
115
+ ],
116
+ activeTools: ["git-path"],
117
+ runtimeShape: "extensionsResult.runtime.pi",
118
+ ...overrides,
119
+ };
120
+ }
121
+
122
+ /**
123
+ * @brief Executes `scripts/pi-usereq-debug.sh` in a subprocess.
124
+ * @details Resolves the repository-local wrapper path from the current test module, runs it through `bash` so shell semantics remain stable, and captures the resulting stdout, stderr, and exit status for wrapper-focused assertions. Runtime is dominated by subprocess execution. Side effects are limited to child-process creation.
125
+ * @param[in] args {string[]} Wrapper CLI arguments excluding the script path.
126
+ * @param[in] cwd {string} Working directory exposed to the wrapper as the caller cwd.
127
+ * @return {import("node:child_process").SpawnSyncReturns<string>} Captured subprocess result.
128
+ */
129
+ function runPiUsereqDebug(args: string[], cwd: string) {
130
+ const scriptPath = fileURLToPath(new URL("../scripts/pi-usereq-debug.sh", import.meta.url));
131
+ return spawnSync("bash", [scriptPath, ...args], {
132
+ cwd,
133
+ encoding: "utf8",
134
+ });
135
+ }
136
+
137
+ test("inspectExtension records commands, tools, events, and manual examples", async () => {
138
+ const { projectBase } = initFixtureRepo();
139
+ try {
140
+ const report = await inspectExtension(projectBase);
141
+
142
+ assert.ok(report.commands.some((command) => command.name === "req-analyze"));
143
+ assert.ok(report.tools.some((tool) => tool.name === "git-path"));
144
+ assert.deepEqual(report.eventHandlers, [...PI_USEREQ_STATUS_HOOK_NAMES]);
145
+
146
+ for (const command of report.commands.filter((entry) => entry.name.startsWith("req-"))) {
147
+ assert.match(report.manual, new RegExp(`prompt /${command.name}`));
148
+ assert.match(report.manual, new RegExp(`--name ${command.name}`));
149
+ }
150
+ for (const tool of report.tools) {
151
+ assert.match(report.manual, new RegExp(`tool ${tool.name}`));
152
+ assert.match(report.manual, new RegExp(`--name ${tool.name}`));
153
+ }
154
+ } finally {
155
+ fs.rmSync(projectBase, { recursive: true, force: true });
156
+ }
157
+ });
158
+
159
+ test("inspectExtension surfaces agent-oriented find tool descriptions and schema details", async () => {
160
+ const { projectBase } = initFixtureRepo({ fixtures: [] });
161
+ try {
162
+ const report = await inspectExtension(projectBase);
163
+ const filesFind = report.tools.find((tool) => tool.name === "files-find");
164
+ const find = report.tools.find((tool) => tool.name === "find");
165
+
166
+ assert.ok(filesFind, "missing files-find tool");
167
+ assert.ok(find, "missing find tool");
168
+ assert.match(filesFind.description ?? "", /LLM-oriented JSON payload/);
169
+ assert.ok(filesFind.promptGuidelines?.some((line) => line.includes("Supported tags [Typescript]:")));
170
+ assert.match(String((filesFind.parameters as { description?: string } | undefined)?.description ?? ""), /supported_tags_by_language/);
171
+ assert.match(find.description ?? "", /configured project source directories/);
172
+ assert.ok(find.promptGuidelines?.some((line) => line.includes("Regex rule:")));
173
+ assert.match(String((find.parameters as { description?: string } | undefined)?.description ?? ""), /Regex matches construct names only/);
174
+ } finally {
175
+ fs.rmSync(projectBase, { recursive: true, force: true });
176
+ }
177
+ });
178
+
179
+ test("inspectExtension surfaces agent-oriented compression tool descriptions and schema details", async () => {
180
+ const { projectBase } = initFixtureRepo({ fixtures: [] });
181
+ try {
182
+ const report = await inspectExtension(projectBase);
183
+ const filesCompress = report.tools.find((tool) => tool.name === "files-compress");
184
+ const compress = report.tools.find((tool) => tool.name === "compress");
185
+
186
+ assert.ok(filesCompress, "missing files-compress tool");
187
+ assert.ok(compress, "missing compress tool");
188
+ assert.match(filesCompress.description ?? "", /request, summary, repository, files, and execution sections/);
189
+ assert.ok(filesCompress.promptGuidelines?.some((line) => line.includes("Line-number behavior:")));
190
+ assert.match(String((filesCompress.parameters as { description?: string } | undefined)?.description ?? ""), /structured compressed lines/);
191
+ assert.match(compress.description ?? "", /configured project source directories/);
192
+ assert.ok(compress.promptGuidelines?.some((line) => line.includes("Configuration contract:")));
193
+ assert.match(String((compress.parameters as { description?: string } | undefined)?.description ?? ""), /structured compressed lines/);
194
+ } finally {
195
+ fs.rmSync(projectBase, { recursive: true, force: true });
196
+ }
197
+ });
198
+
199
+ test("inspectExtension surfaces structured utility tool descriptions and schema details", async () => {
200
+ const { projectBase } = initFixtureRepo({ fixtures: [] });
201
+ try {
202
+ const report = await inspectExtension(projectBase);
203
+ const gitPath = report.tools.find((tool) => tool.name === "git-path");
204
+ const filesStaticCheck = report.tools.find((tool) => tool.name === "files-static-check");
205
+ const gitCheck = report.tools.find((tool) => tool.name === "git-check");
206
+ const docsCheck = report.tools.find((tool) => tool.name === "docs-check");
207
+ const gitWtCreate = report.tools.find((tool) => tool.name === "git-wt-create");
208
+
209
+ assert.ok(gitPath, "missing git-path tool");
210
+ assert.ok(filesStaticCheck, "missing files-static-check tool");
211
+ assert.ok(gitCheck, "missing git-check tool");
212
+ assert.ok(docsCheck, "missing docs-check tool");
213
+ assert.ok(gitWtCreate, "missing git-wt-create tool");
214
+
215
+ assert.match(gitPath.description ?? "", /JSON-first payload/);
216
+ assert.ok(gitPath.promptGuidelines?.some((line) => line.includes("Output contract:")));
217
+ assert.match(String((gitPath.parameters as { description?: string } | undefined)?.description ?? ""), /path_value/);
218
+
219
+ assert.match(filesStaticCheck.description ?? "", /selection status/);
220
+ assert.ok(filesStaticCheck.promptGuidelines?.some((line) => line.includes("Failure contract:")));
221
+ assert.match(String((filesStaticCheck.parameters as { description?: string } | undefined)?.description ?? ""), /configured checker modules/);
222
+
223
+ assert.match(gitCheck.description ?? "", /JSON-first payload/);
224
+ assert.ok(gitCheck.promptGuidelines?.some((line) => line.includes("Behavior contract:")));
225
+ assert.match(String((gitCheck.parameters as { description?: string } | undefined)?.description ?? ""), /clean-versus-error repository status/);
226
+
227
+ assert.match(docsCheck.description ?? "", /remediation prompt commands/);
228
+ assert.ok(docsCheck.promptGuidelines?.some((line) => line.includes("Specialization trigger:")));
229
+ assert.match(String((docsCheck.parameters as { description?: string } | undefined)?.description ?? ""), /prompt_command remediation/);
230
+
231
+ assert.match(gitWtCreate.description ?? "", /derived path/);
232
+ assert.ok(gitWtCreate.promptGuidelines?.some((line) => line.includes("Specialization trigger:")));
233
+ assert.match(String((gitWtCreate.parameters as { description?: string } | undefined)?.description ?? ""), /worktree_path/);
234
+ } finally {
235
+ fs.rmSync(projectBase, { recursive: true, force: true });
236
+ }
237
+ });
238
+
239
+ test("replaySessionStart captures active tools, statuses, and cwd semantics", async () => {
240
+ const { projectBase } = initFixtureRepo();
241
+ try {
242
+ writeEnabledTools(projectBase, ["git-path", "static-check"]);
243
+ const report = await replaySessionStart(projectBase);
244
+ const status = report.ui.statuses["pi-usereq"] ?? "";
245
+
246
+ assert.deepEqual([...report.activeTools].sort(), ["git-path", "static-check"]);
247
+ assert.equal(report.effectiveCtxCwd, projectBase);
248
+ assert.equal(report.effectiveProcessCwd, projectBase);
249
+ assert.match(
250
+ status,
251
+ /<accent>git:<\/accent><warning>.*<\/warning><dim> • <\/dim><accent>base:<\/accent><warning>\.<\/warning><dim> • <\/dim><accent>docs:<\/accent><warning>pi-usereq\/docs<\/warning><dim> • <\/dim><accent>tests:<\/accent><warning>tests<\/warning><dim> • <\/dim><accent>src:<\/accent><warning>src<\/warning><dim> • <\/dim><accent>tools:<\/accent><warning>2<\/warning>/,
252
+ );
253
+ assert.match(
254
+ status,
255
+ /<accent>context:<\/accent><bg-from-fg-accent><warning>CLEAR<\/warning><\/bg-from-fg-accent>/,
256
+ );
257
+ assert.match(status, /<accent>elapsed:<\/accent><warning>idle<\/warning>/);
258
+ assert.match(status, /<accent>last:<\/accent><warning>N\/A<\/warning>/);
259
+ assert.match(status, /<accent>beep:<\/accent><warning>none<\/warning>/);
260
+ assert.match(status, /<accent>sound:<\/accent><warning>none<\/warning>/);
261
+ assert.equal(report.ui.notifications.length, 0);
262
+ } finally {
263
+ fs.rmSync(projectBase, { recursive: true, force: true });
264
+ }
265
+ });
266
+
267
+ test("replayCommand captures prompt command payloads", async () => {
268
+ const { projectBase } = initFixtureRepo();
269
+ try {
270
+ const report = await replayCommand("req-analyze", "Inspect src/index.ts for prompt coverage", projectBase);
271
+
272
+ assert.equal(report.effectiveCtxCwd, projectBase);
273
+ assert.equal(report.effectiveProcessCwd, projectBase);
274
+ assert.equal(report.sentUserMessages.length, 1);
275
+ assert.match(String(report.sentUserMessages[0]?.content), /Inspect src\/index\.ts for prompt coverage/);
276
+ } finally {
277
+ fs.rmSync(projectBase, { recursive: true, force: true });
278
+ }
279
+ });
280
+
281
+ test("replayCommand captures interactive UI side effects", async () => {
282
+ const { projectBase } = initFixtureRepo();
283
+ try {
284
+ const report = await replayCommand(
285
+ "pi-usereq",
286
+ "",
287
+ projectBase,
288
+ undefined,
289
+ {
290
+ selects: ["startup tools", "Disable all configurable tools", "Back", "Save and close"],
291
+ inputs: [],
292
+ },
293
+ );
294
+
295
+ assert.deepEqual(report.activeTools, []);
296
+ assert.ok(report.ui.notifications.some((entry) => entry.message === "Disabled all configurable active tools"));
297
+ assert.match(report.ui.statuses["pi-usereq"] ?? "", /<accent>tools:<\/accent><warning>0<\/warning>/);
298
+ } finally {
299
+ fs.rmSync(projectBase, { recursive: true, force: true });
300
+ }
301
+ });
302
+
303
+ test("replayTool captures tool results and cwd semantics", async () => {
304
+ const { projectBase } = initFixtureRepo();
305
+ try {
306
+ const report = await replayTool("git-path", {}, projectBase);
307
+ const toolResult = report.toolResult as {
308
+ content?: Array<{ type: string; text?: string }>;
309
+ details?: {
310
+ request: { project_base_path: string };
311
+ result: { path_value: string; path_present: boolean };
312
+ runtime_paths: { git_path: string };
313
+ execution: { code: number };
314
+ };
315
+ };
316
+
317
+ assert.equal(report.effectiveCtxCwd, projectBase);
318
+ assert.equal(report.effectiveProcessCwd, projectBase);
319
+ assert.deepEqual(JSON.parse(toolResult.content?.[0]?.text ?? "{}"), JSON.parse(JSON.stringify(toolResult.details)));
320
+ assert.equal(toolResult.details?.request.project_base_path, projectBase);
321
+ assert.equal(toolResult.details?.result.path_value, toolResult.details?.runtime_paths.git_path);
322
+ assert.equal(toolResult.details?.result.path_present, true);
323
+ assert.equal(toolResult.details?.execution.code, 0);
324
+ } finally {
325
+ fs.rmSync(projectBase, { recursive: true, force: true });
326
+ }
327
+ });
328
+
329
+ test("pi-usereq-debug tool forwards --params unchanged for files-find", () => {
330
+ const { projectBase } = initFixtureRepo({ fixtures: [] });
331
+ try {
332
+ fs.writeFileSync(path.join(projectBase, "src", "find_target.py"), "def foo():\n return 1\n", "utf8");
333
+ const expectedParams = {
334
+ tag: "FUNCTION",
335
+ pattern: "^foo$",
336
+ files: ["src/find_target.py"],
337
+ enableLineNumbers: true,
338
+ };
339
+ const result = runPiUsereqDebug(
340
+ ["tool", "files-find", "--params", JSON.stringify(expectedParams), "--format", "json"],
341
+ projectBase,
342
+ );
343
+
344
+ assert.equal(result.status, 0, result.stderr);
345
+ const report = JSON.parse(result.stdout) as { toolParams: Record<string, unknown> };
346
+ assert.deepEqual(report.toolParams, expectedParams);
347
+ } finally {
348
+ fs.rmSync(projectBase, { recursive: true, force: true });
349
+ }
350
+ });
351
+
352
+ test("pi-usereq-debug tool converts --args text into forwarded params JSON", () => {
353
+ const { projectBase } = initFixtureRepo({ fixtures: [] });
354
+ try {
355
+ fs.writeFileSync(path.join(projectBase, "src", "find_target.py"), "def foo():\n return 1\n", "utf8");
356
+ const expectedParams = {
357
+ tag: "FUNCTION",
358
+ pattern: "^foo$",
359
+ files: ["src/find_target.py"],
360
+ enableLineNumbers: true,
361
+ };
362
+ const result = runPiUsereqDebug(
363
+ [
364
+ "tool",
365
+ "files-find",
366
+ "--args",
367
+ "FUNCTION ^foo$ src/find_target.py --enable-line-numbers",
368
+ "--format",
369
+ "json",
370
+ ],
371
+ projectBase,
372
+ );
373
+
374
+ assert.equal(result.status, 0, result.stderr);
375
+ const report = JSON.parse(result.stdout) as { toolParams: Record<string, unknown> };
376
+ assert.deepEqual(report.toolParams, expectedParams);
377
+ } finally {
378
+ fs.rmSync(projectBase, { recursive: true, force: true });
379
+ }
380
+ });
381
+
382
+ test("buildParityReport returns ok for aligned inventories and reports mismatch categories", async () => {
383
+ const offline = buildOfflineFixture();
384
+ const alignedReport = buildParityReport(offline, buildSdkFixture());
385
+ assert.equal(alignedReport.ok, true);
386
+ assert.equal(alignedReport.mismatches.length, 0);
387
+
388
+ const mismatchReport = buildParityReport(
389
+ offline,
390
+ buildSdkFixture({
391
+ commands: [
392
+ {
393
+ name: "req-analyze",
394
+ description: "Different command",
395
+ sourceInfo: {
396
+ path: "src/other.ts",
397
+ source: "extension",
398
+ scope: "project",
399
+ origin: "top-level",
400
+ baseDir: "src",
401
+ },
402
+ },
403
+ {
404
+ name: "req-change",
405
+ description: "Extra command",
406
+ sourceInfo: {
407
+ path: "src/index.ts",
408
+ source: "extension",
409
+ scope: "project",
410
+ origin: "top-level",
411
+ baseDir: "src",
412
+ },
413
+ },
414
+ ],
415
+ tools: [
416
+ {
417
+ name: "git-path",
418
+ description: "Different tool",
419
+ hasParameters: true,
420
+ sourceInfo: {
421
+ path: "src/other.ts",
422
+ source: "extension",
423
+ scope: "project",
424
+ origin: "top-level",
425
+ baseDir: "src",
426
+ },
427
+ },
428
+ {
429
+ name: "static-check",
430
+ description: "Extra tool",
431
+ hasParameters: false,
432
+ sourceInfo: {
433
+ path: "src/index.ts",
434
+ source: "extension",
435
+ scope: "project",
436
+ origin: "top-level",
437
+ baseDir: "src",
438
+ },
439
+ },
440
+ ],
441
+ activeTools: ["static-check"],
442
+ }),
443
+ );
444
+
445
+ const categories = new Set(mismatchReport.mismatches.map((mismatch) => mismatch.category));
446
+ assert.equal(mismatchReport.ok, false);
447
+ assert.ok(categories.has("command-name"));
448
+ assert.ok(categories.has("command-description"));
449
+ assert.ok(categories.has("command-source-info"));
450
+ assert.ok(categories.has("tool-name"));
451
+ assert.ok(categories.has("tool-description"));
452
+ assert.ok(categories.has("tool-parameter-schema"));
453
+ assert.ok(categories.has("tool-source-info"));
454
+ assert.ok(categories.has("active-tools"));
455
+
456
+ const packageJson = JSON.parse(fs.readFileSync(path.join(process.cwd(), "package.json"), "utf8")) as { scripts?: Record<string, string> };
457
+ assert.ok(packageJson.scripts?.["debug:ext"]);
458
+ assert.ok(packageJson.scripts?.["debug:ext:inspect"]);
459
+ assert.ok(packageJson.scripts?.["debug:ext:session"]);
460
+ assert.ok(packageJson.scripts?.["debug:ext:command"]);
461
+ assert.ok(packageJson.scripts?.["debug:ext:tool"]);
462
+ assert.ok(packageJson.scripts?.["debug:ext:sdk"]);
463
+ });