@pi-harness/pi-harness 0.1.22 → 0.1.24

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 (307) hide show
  1. package/README.md +12 -10
  2. package/apps/web/dist/assets/index-BcLXLKqO.js +24 -0
  3. package/apps/web/dist/assets/index-xF647pQJ.css +2 -0
  4. package/apps/web/dist/index.html +2 -2
  5. package/apps/web/package.json +6 -6
  6. package/apps/web/profile/cordis.yml +1 -0
  7. package/apps/web/server-dist/bin.js +45 -7
  8. package/apps/web/server-dist/bin.js.map +1 -1
  9. package/apps/web/src/server/bin.ts +45 -7
  10. package/apps/web/test/bin.test.ts +313 -0
  11. package/node_modules/@pi-harness/api-gateway/dist/index.d.ts.map +1 -1
  12. package/node_modules/@pi-harness/api-gateway/dist/index.js +295 -86
  13. package/node_modules/@pi-harness/api-gateway/dist/index.js.map +1 -1
  14. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/agent-teams.json +1 -1
  15. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/anchored-standard.json +1 -1
  16. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/annotation.json +1 -1
  17. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/archify.json +1 -1
  18. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/at-file.json +1 -1
  19. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/auto-mode.json +1 -1
  20. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/better-sidebar.json +1 -1
  21. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/browser-fetch.json +1 -1
  22. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/browser-session.json +1 -1
  23. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/canvas-draw.json +1 -1
  24. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/change-verifier.json +1 -1
  25. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/cleaner.json +1 -1
  26. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/cli-notifier.json +1 -1
  27. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/code2skill.json +1 -1
  28. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/colleague-skill.json +1 -1
  29. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/context-doctor.json +1 -1
  30. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/context.json +1 -1
  31. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/cost-meter.json +1 -1
  32. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/dependency-checker.json +1 -1
  33. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/docker-sandbox.json +1 -1
  34. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/fail-logger.json +1 -1
  35. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/genui.json +1 -1
  36. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/git-time-capsule.json +1 -1
  37. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/graph-memory.json +1 -1
  38. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/history-compressor.json +1 -1
  39. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/hol-guard.json +3 -3
  40. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/i18n-pair.json +1 -1
  41. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/image-compressor.json +1 -1
  42. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/llm-verifier.json +1 -1
  43. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/mcp-client.json +1 -1
  44. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/mcp-panel.json +1 -1
  45. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/memory.json +1 -1
  46. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/mirage-bridge.json +1 -1
  47. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/mock-server.json +1 -1
  48. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/modlens.json +1 -1
  49. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/module-search.json +1 -1
  50. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/obsidian-sync.json +1 -1
  51. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/openpets.json +1 -1
  52. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/plan-execute.json +1 -1
  53. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/plugin-check.json +1 -1
  54. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/plugin-dev.json +1 -1
  55. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/plugin-finder.json +1 -1
  56. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/plugin-radar.json +1 -1
  57. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/plugin-stars.json +1 -1
  58. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/prompt-guard.json +1 -1
  59. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/prompt-library.json +1 -1
  60. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/readme-gen.json +1 -1
  61. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/recall-unread.json +1 -1
  62. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/reverse-skill.json +1 -1
  63. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/reviewer-bot.json +1 -1
  64. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/runtime-doctor.json +1 -1
  65. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/secure-audit.json +1 -1
  66. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/session-bookmarks.json +1 -1
  67. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/session-bridge.json +1 -1
  68. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/session-compare.json +1 -1
  69. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/session-export.json +1 -1
  70. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/session-insights.json +1 -1
  71. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/session-search.json +1 -1
  72. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/skill-catalog.json +1 -1
  73. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/skill-guard.json +1 -1
  74. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/sql-lens.json +1 -1
  75. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/synapse.json +1 -1
  76. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/tab-manager.json +1 -1
  77. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/taskboard.json +1 -1
  78. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/telemetry-blocker.json +1 -1
  79. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/test-harness.json +1 -1
  80. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/theme-studio.json +1 -1
  81. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/token-guard.json +1 -1
  82. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/turn-rewind.json +1 -1
  83. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/undo-savepoint.json +1 -1
  84. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/vision-toolkit.json +1 -1
  85. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/web-research.json +1 -1
  86. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/workspace-navigator.json +1 -1
  87. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/workspace-search.json +1 -1
  88. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/yaml-validator.json +1 -1
  89. package/node_modules/@pi-harness/api-gateway/package.json +1 -1
  90. package/node_modules/@pi-harness/cli/dist/main.d.ts +1 -0
  91. package/node_modules/@pi-harness/cli/dist/main.d.ts.map +1 -1
  92. package/node_modules/@pi-harness/cli/dist/main.js +11 -0
  93. package/node_modules/@pi-harness/cli/dist/main.js.map +1 -1
  94. package/node_modules/@pi-harness/cli/dist/node-stdio.d.ts.map +1 -1
  95. package/node_modules/@pi-harness/cli/dist/node-stdio.js +3 -1
  96. package/node_modules/@pi-harness/cli/dist/node-stdio.js.map +1 -1
  97. package/node_modules/@pi-harness/cli/dist/relaunch.d.ts.map +1 -1
  98. package/node_modules/@pi-harness/cli/dist/relaunch.js +4 -1
  99. package/node_modules/@pi-harness/cli/dist/relaunch.js.map +1 -1
  100. package/node_modules/@pi-harness/cli/package.json +1 -1
  101. package/node_modules/@pi-harness/host-webserver/dist/index.d.ts +1 -0
  102. package/node_modules/@pi-harness/host-webserver/dist/index.d.ts.map +1 -1
  103. package/node_modules/@pi-harness/host-webserver/dist/index.js +86 -3
  104. package/node_modules/@pi-harness/host-webserver/dist/index.js.map +1 -1
  105. package/node_modules/@pi-harness/host-webserver/package.json +1 -1
  106. package/node_modules/@pi-harness/web-app/dist/index.d.ts +3 -0
  107. package/node_modules/@pi-harness/web-app/dist/index.d.ts.map +1 -1
  108. package/node_modules/@pi-harness/web-app/dist/index.js +21 -8
  109. package/node_modules/@pi-harness/web-app/dist/index.js.map +1 -1
  110. package/node_modules/@pi-harness/web-app/package.json +1 -1
  111. package/package.json +8 -8
  112. package/packages/api-gateway/dist/index.d.ts.map +1 -1
  113. package/packages/api-gateway/dist/index.js +295 -86
  114. package/packages/api-gateway/dist/index.js.map +1 -1
  115. package/packages/api-gateway/dist/marketplace-entries/official/agent-teams.json +1 -1
  116. package/packages/api-gateway/dist/marketplace-entries/official/anchored-standard.json +1 -1
  117. package/packages/api-gateway/dist/marketplace-entries/official/annotation.json +1 -1
  118. package/packages/api-gateway/dist/marketplace-entries/official/archify.json +1 -1
  119. package/packages/api-gateway/dist/marketplace-entries/official/at-file.json +1 -1
  120. package/packages/api-gateway/dist/marketplace-entries/official/auto-mode.json +1 -1
  121. package/packages/api-gateway/dist/marketplace-entries/official/better-sidebar.json +1 -1
  122. package/packages/api-gateway/dist/marketplace-entries/official/browser-fetch.json +1 -1
  123. package/packages/api-gateway/dist/marketplace-entries/official/browser-session.json +1 -1
  124. package/packages/api-gateway/dist/marketplace-entries/official/canvas-draw.json +1 -1
  125. package/packages/api-gateway/dist/marketplace-entries/official/change-verifier.json +1 -1
  126. package/packages/api-gateway/dist/marketplace-entries/official/cleaner.json +1 -1
  127. package/packages/api-gateway/dist/marketplace-entries/official/cli-notifier.json +1 -1
  128. package/packages/api-gateway/dist/marketplace-entries/official/code2skill.json +1 -1
  129. package/packages/api-gateway/dist/marketplace-entries/official/colleague-skill.json +1 -1
  130. package/packages/api-gateway/dist/marketplace-entries/official/context-doctor.json +1 -1
  131. package/packages/api-gateway/dist/marketplace-entries/official/context.json +1 -1
  132. package/packages/api-gateway/dist/marketplace-entries/official/cost-meter.json +1 -1
  133. package/packages/api-gateway/dist/marketplace-entries/official/dependency-checker.json +1 -1
  134. package/packages/api-gateway/dist/marketplace-entries/official/docker-sandbox.json +1 -1
  135. package/packages/api-gateway/dist/marketplace-entries/official/fail-logger.json +1 -1
  136. package/packages/api-gateway/dist/marketplace-entries/official/genui.json +1 -1
  137. package/packages/api-gateway/dist/marketplace-entries/official/git-time-capsule.json +1 -1
  138. package/packages/api-gateway/dist/marketplace-entries/official/graph-memory.json +1 -1
  139. package/packages/api-gateway/dist/marketplace-entries/official/history-compressor.json +1 -1
  140. package/packages/api-gateway/dist/marketplace-entries/official/hol-guard.json +3 -3
  141. package/packages/api-gateway/dist/marketplace-entries/official/i18n-pair.json +1 -1
  142. package/packages/api-gateway/dist/marketplace-entries/official/image-compressor.json +1 -1
  143. package/packages/api-gateway/dist/marketplace-entries/official/llm-verifier.json +1 -1
  144. package/packages/api-gateway/dist/marketplace-entries/official/mcp-client.json +1 -1
  145. package/packages/api-gateway/dist/marketplace-entries/official/mcp-panel.json +1 -1
  146. package/packages/api-gateway/dist/marketplace-entries/official/memory.json +1 -1
  147. package/packages/api-gateway/dist/marketplace-entries/official/mirage-bridge.json +1 -1
  148. package/packages/api-gateway/dist/marketplace-entries/official/mock-server.json +1 -1
  149. package/packages/api-gateway/dist/marketplace-entries/official/modlens.json +1 -1
  150. package/packages/api-gateway/dist/marketplace-entries/official/module-search.json +1 -1
  151. package/packages/api-gateway/dist/marketplace-entries/official/obsidian-sync.json +1 -1
  152. package/packages/api-gateway/dist/marketplace-entries/official/openpets.json +1 -1
  153. package/packages/api-gateway/dist/marketplace-entries/official/plan-execute.json +1 -1
  154. package/packages/api-gateway/dist/marketplace-entries/official/plugin-check.json +1 -1
  155. package/packages/api-gateway/dist/marketplace-entries/official/plugin-dev.json +1 -1
  156. package/packages/api-gateway/dist/marketplace-entries/official/plugin-finder.json +1 -1
  157. package/packages/api-gateway/dist/marketplace-entries/official/plugin-radar.json +1 -1
  158. package/packages/api-gateway/dist/marketplace-entries/official/plugin-stars.json +1 -1
  159. package/packages/api-gateway/dist/marketplace-entries/official/prompt-guard.json +1 -1
  160. package/packages/api-gateway/dist/marketplace-entries/official/prompt-library.json +1 -1
  161. package/packages/api-gateway/dist/marketplace-entries/official/readme-gen.json +1 -1
  162. package/packages/api-gateway/dist/marketplace-entries/official/recall-unread.json +1 -1
  163. package/packages/api-gateway/dist/marketplace-entries/official/reverse-skill.json +1 -1
  164. package/packages/api-gateway/dist/marketplace-entries/official/reviewer-bot.json +1 -1
  165. package/packages/api-gateway/dist/marketplace-entries/official/runtime-doctor.json +1 -1
  166. package/packages/api-gateway/dist/marketplace-entries/official/secure-audit.json +1 -1
  167. package/packages/api-gateway/dist/marketplace-entries/official/session-bookmarks.json +1 -1
  168. package/packages/api-gateway/dist/marketplace-entries/official/session-bridge.json +1 -1
  169. package/packages/api-gateway/dist/marketplace-entries/official/session-compare.json +1 -1
  170. package/packages/api-gateway/dist/marketplace-entries/official/session-export.json +1 -1
  171. package/packages/api-gateway/dist/marketplace-entries/official/session-insights.json +1 -1
  172. package/packages/api-gateway/dist/marketplace-entries/official/session-search.json +1 -1
  173. package/packages/api-gateway/dist/marketplace-entries/official/skill-catalog.json +1 -1
  174. package/packages/api-gateway/dist/marketplace-entries/official/skill-guard.json +1 -1
  175. package/packages/api-gateway/dist/marketplace-entries/official/sql-lens.json +1 -1
  176. package/packages/api-gateway/dist/marketplace-entries/official/synapse.json +1 -1
  177. package/packages/api-gateway/dist/marketplace-entries/official/tab-manager.json +1 -1
  178. package/packages/api-gateway/dist/marketplace-entries/official/taskboard.json +1 -1
  179. package/packages/api-gateway/dist/marketplace-entries/official/telemetry-blocker.json +1 -1
  180. package/packages/api-gateway/dist/marketplace-entries/official/test-harness.json +1 -1
  181. package/packages/api-gateway/dist/marketplace-entries/official/theme-studio.json +1 -1
  182. package/packages/api-gateway/dist/marketplace-entries/official/token-guard.json +1 -1
  183. package/packages/api-gateway/dist/marketplace-entries/official/turn-rewind.json +1 -1
  184. package/packages/api-gateway/dist/marketplace-entries/official/undo-savepoint.json +1 -1
  185. package/packages/api-gateway/dist/marketplace-entries/official/vision-toolkit.json +1 -1
  186. package/packages/api-gateway/dist/marketplace-entries/official/web-research.json +1 -1
  187. package/packages/api-gateway/dist/marketplace-entries/official/workspace-navigator.json +1 -1
  188. package/packages/api-gateway/dist/marketplace-entries/official/workspace-search.json +1 -1
  189. package/packages/api-gateway/dist/marketplace-entries/official/yaml-validator.json +1 -1
  190. package/packages/api-gateway/package.json +1 -1
  191. package/packages/api-gateway/src/index.ts +310 -87
  192. package/packages/api-gateway/src/marketplace-entries/official/agent-teams.json +1 -1
  193. package/packages/api-gateway/src/marketplace-entries/official/anchored-standard.json +1 -1
  194. package/packages/api-gateway/src/marketplace-entries/official/annotation.json +1 -1
  195. package/packages/api-gateway/src/marketplace-entries/official/archify.json +1 -1
  196. package/packages/api-gateway/src/marketplace-entries/official/at-file.json +1 -1
  197. package/packages/api-gateway/src/marketplace-entries/official/auto-mode.json +1 -1
  198. package/packages/api-gateway/src/marketplace-entries/official/better-sidebar.json +1 -1
  199. package/packages/api-gateway/src/marketplace-entries/official/browser-fetch.json +1 -1
  200. package/packages/api-gateway/src/marketplace-entries/official/browser-session.json +1 -1
  201. package/packages/api-gateway/src/marketplace-entries/official/canvas-draw.json +1 -1
  202. package/packages/api-gateway/src/marketplace-entries/official/change-verifier.json +1 -1
  203. package/packages/api-gateway/src/marketplace-entries/official/cleaner.json +1 -1
  204. package/packages/api-gateway/src/marketplace-entries/official/cli-notifier.json +1 -1
  205. package/packages/api-gateway/src/marketplace-entries/official/code2skill.json +1 -1
  206. package/packages/api-gateway/src/marketplace-entries/official/colleague-skill.json +1 -1
  207. package/packages/api-gateway/src/marketplace-entries/official/context-doctor.json +1 -1
  208. package/packages/api-gateway/src/marketplace-entries/official/context.json +1 -1
  209. package/packages/api-gateway/src/marketplace-entries/official/cost-meter.json +1 -1
  210. package/packages/api-gateway/src/marketplace-entries/official/dependency-checker.json +1 -1
  211. package/packages/api-gateway/src/marketplace-entries/official/docker-sandbox.json +1 -1
  212. package/packages/api-gateway/src/marketplace-entries/official/fail-logger.json +1 -1
  213. package/packages/api-gateway/src/marketplace-entries/official/genui.json +1 -1
  214. package/packages/api-gateway/src/marketplace-entries/official/git-time-capsule.json +1 -1
  215. package/packages/api-gateway/src/marketplace-entries/official/graph-memory.json +1 -1
  216. package/packages/api-gateway/src/marketplace-entries/official/history-compressor.json +1 -1
  217. package/packages/api-gateway/src/marketplace-entries/official/hol-guard.json +3 -3
  218. package/packages/api-gateway/src/marketplace-entries/official/i18n-pair.json +1 -1
  219. package/packages/api-gateway/src/marketplace-entries/official/image-compressor.json +1 -1
  220. package/packages/api-gateway/src/marketplace-entries/official/llm-verifier.json +1 -1
  221. package/packages/api-gateway/src/marketplace-entries/official/mcp-client.json +1 -1
  222. package/packages/api-gateway/src/marketplace-entries/official/mcp-panel.json +1 -1
  223. package/packages/api-gateway/src/marketplace-entries/official/memory.json +1 -1
  224. package/packages/api-gateway/src/marketplace-entries/official/mirage-bridge.json +1 -1
  225. package/packages/api-gateway/src/marketplace-entries/official/mock-server.json +1 -1
  226. package/packages/api-gateway/src/marketplace-entries/official/modlens.json +1 -1
  227. package/packages/api-gateway/src/marketplace-entries/official/module-search.json +1 -1
  228. package/packages/api-gateway/src/marketplace-entries/official/obsidian-sync.json +1 -1
  229. package/packages/api-gateway/src/marketplace-entries/official/openpets.json +1 -1
  230. package/packages/api-gateway/src/marketplace-entries/official/plan-execute.json +1 -1
  231. package/packages/api-gateway/src/marketplace-entries/official/plugin-check.json +1 -1
  232. package/packages/api-gateway/src/marketplace-entries/official/plugin-dev.json +1 -1
  233. package/packages/api-gateway/src/marketplace-entries/official/plugin-finder.json +1 -1
  234. package/packages/api-gateway/src/marketplace-entries/official/plugin-radar.json +1 -1
  235. package/packages/api-gateway/src/marketplace-entries/official/plugin-stars.json +1 -1
  236. package/packages/api-gateway/src/marketplace-entries/official/prompt-guard.json +1 -1
  237. package/packages/api-gateway/src/marketplace-entries/official/prompt-library.json +1 -1
  238. package/packages/api-gateway/src/marketplace-entries/official/readme-gen.json +1 -1
  239. package/packages/api-gateway/src/marketplace-entries/official/recall-unread.json +1 -1
  240. package/packages/api-gateway/src/marketplace-entries/official/reverse-skill.json +1 -1
  241. package/packages/api-gateway/src/marketplace-entries/official/reviewer-bot.json +1 -1
  242. package/packages/api-gateway/src/marketplace-entries/official/runtime-doctor.json +1 -1
  243. package/packages/api-gateway/src/marketplace-entries/official/secure-audit.json +1 -1
  244. package/packages/api-gateway/src/marketplace-entries/official/session-bookmarks.json +1 -1
  245. package/packages/api-gateway/src/marketplace-entries/official/session-bridge.json +1 -1
  246. package/packages/api-gateway/src/marketplace-entries/official/session-compare.json +1 -1
  247. package/packages/api-gateway/src/marketplace-entries/official/session-export.json +1 -1
  248. package/packages/api-gateway/src/marketplace-entries/official/session-insights.json +1 -1
  249. package/packages/api-gateway/src/marketplace-entries/official/session-search.json +1 -1
  250. package/packages/api-gateway/src/marketplace-entries/official/skill-catalog.json +1 -1
  251. package/packages/api-gateway/src/marketplace-entries/official/skill-guard.json +1 -1
  252. package/packages/api-gateway/src/marketplace-entries/official/sql-lens.json +1 -1
  253. package/packages/api-gateway/src/marketplace-entries/official/synapse.json +1 -1
  254. package/packages/api-gateway/src/marketplace-entries/official/tab-manager.json +1 -1
  255. package/packages/api-gateway/src/marketplace-entries/official/taskboard.json +1 -1
  256. package/packages/api-gateway/src/marketplace-entries/official/telemetry-blocker.json +1 -1
  257. package/packages/api-gateway/src/marketplace-entries/official/test-harness.json +1 -1
  258. package/packages/api-gateway/src/marketplace-entries/official/theme-studio.json +1 -1
  259. package/packages/api-gateway/src/marketplace-entries/official/token-guard.json +1 -1
  260. package/packages/api-gateway/src/marketplace-entries/official/turn-rewind.json +1 -1
  261. package/packages/api-gateway/src/marketplace-entries/official/undo-savepoint.json +1 -1
  262. package/packages/api-gateway/src/marketplace-entries/official/vision-toolkit.json +1 -1
  263. package/packages/api-gateway/src/marketplace-entries/official/web-research.json +1 -1
  264. package/packages/api-gateway/src/marketplace-entries/official/workspace-navigator.json +1 -1
  265. package/packages/api-gateway/src/marketplace-entries/official/workspace-search.json +1 -1
  266. package/packages/api-gateway/src/marketplace-entries/official/yaml-validator.json +1 -1
  267. package/packages/api-gateway/test/index.test.ts +799 -3
  268. package/packages/api-gateway/test/marketplace-schema.test.ts +139 -0
  269. package/packages/api-gateway/test/packed-package.test.ts +70 -0
  270. package/packages/api-gateway/test/reference-docs.test.ts +50 -0
  271. package/packages/api-gateway/test/release-contract.test.ts +77 -0
  272. package/packages/api-gateway/test/release-package.test.ts +33 -2
  273. package/packages/api-gateway/test/release-version.test.ts +46 -4
  274. package/packages/bundle-web-app/dist/index.d.ts +3 -0
  275. package/packages/bundle-web-app/dist/index.d.ts.map +1 -1
  276. package/packages/bundle-web-app/dist/index.js +21 -8
  277. package/packages/bundle-web-app/dist/index.js.map +1 -1
  278. package/packages/bundle-web-app/package.json +1 -1
  279. package/packages/bundle-web-app/src/index.ts +25 -8
  280. package/packages/bundle-web-app/test/index.test.ts +116 -4
  281. package/packages/cli/dist/main.d.ts +1 -0
  282. package/packages/cli/dist/main.d.ts.map +1 -1
  283. package/packages/cli/dist/main.js +11 -0
  284. package/packages/cli/dist/main.js.map +1 -1
  285. package/packages/cli/dist/node-stdio.d.ts.map +1 -1
  286. package/packages/cli/dist/node-stdio.js +3 -1
  287. package/packages/cli/dist/node-stdio.js.map +1 -1
  288. package/packages/cli/dist/relaunch.d.ts.map +1 -1
  289. package/packages/cli/dist/relaunch.js +4 -1
  290. package/packages/cli/dist/relaunch.js.map +1 -1
  291. package/packages/cli/package.json +1 -1
  292. package/packages/cli/src/main.ts +11 -0
  293. package/packages/cli/src/node-stdio.ts +6 -3
  294. package/packages/cli/src/relaunch.ts +4 -1
  295. package/packages/cli/test/cli.test.ts +3 -1
  296. package/packages/cli/test/main.test.ts +134 -0
  297. package/packages/cli/test/node-stdio.test.ts +43 -0
  298. package/packages/cli/test/relaunch.test.ts +110 -0
  299. package/packages/host-webserver/dist/index.d.ts +1 -0
  300. package/packages/host-webserver/dist/index.d.ts.map +1 -1
  301. package/packages/host-webserver/dist/index.js +86 -3
  302. package/packages/host-webserver/dist/index.js.map +1 -1
  303. package/packages/host-webserver/package.json +1 -1
  304. package/packages/host-webserver/src/index.ts +95 -3
  305. package/packages/host-webserver/test/index.test.ts +160 -1
  306. package/apps/web/dist/assets/index-BVI_IS-R.css +0 -2
  307. package/apps/web/dist/assets/index-w0KQgv8x.js +0 -22
@@ -0,0 +1,139 @@
1
+ import { readdirSync, readFileSync } from "node:fs";
2
+ import { join, relative, resolve } from "node:path";
3
+ import { describe, expect, test } from "vitest";
4
+ import { MARKETPLACE_PLUGINS } from "../src/marketplace.js";
5
+
6
+ const repositoryRoot = resolve(import.meta.dirname, "../../..");
7
+ const schemaPath = resolve(repositoryRoot, "docs/marketplace-entry.schema.json");
8
+ const entriesRoot = resolve(import.meta.dirname, "../src/marketplace-entries");
9
+
10
+ type Schema = Record<string, unknown>;
11
+ type JsonType = "array" | "boolean" | "integer" | "null" | "number" | "object" | "string";
12
+
13
+ // The repository has no JSON Schema validator dependency (ajv is only a transitive draft-07 build), so this test interprets exactly the keyword subset the published schema uses. Any keyword outside this set fails loudly instead of being silently ignored, so a schema edit cannot escape the check.
14
+ const supportedKeywords = new Set([
15
+ "$schema",
16
+ "title",
17
+ "description",
18
+ "type",
19
+ "required",
20
+ "additionalProperties",
21
+ "properties",
22
+ "pattern",
23
+ "minLength",
24
+ "enum",
25
+ "const",
26
+ "items",
27
+ "minItems",
28
+ "uniqueItems",
29
+ "minimum",
30
+ "maximum",
31
+ "if",
32
+ "then",
33
+ "else",
34
+ ]);
35
+
36
+ function isRecord(value: unknown): value is Record<string, unknown> {
37
+ return value !== null && typeof value === "object" && !Array.isArray(value);
38
+ }
39
+
40
+ function jsonType(value: unknown): JsonType {
41
+ if (value === null) return "null";
42
+ if (Array.isArray(value)) return "array";
43
+ if (typeof value === "number") return Number.isInteger(value) ? "integer" : "number";
44
+ return typeof value as JsonType;
45
+ }
46
+
47
+ function sameJson(left: unknown, right: unknown): boolean {
48
+ return JSON.stringify(left) === JSON.stringify(right);
49
+ }
50
+
51
+ function validate(schema: Schema, value: unknown, path = "$"): string[] {
52
+ for (const keyword of Object.keys(schema)) {
53
+ if (!supportedKeywords.has(keyword)) throw new Error(`Unsupported schema keyword "${keyword}" at ${path}`);
54
+ }
55
+ const errors: string[] = [];
56
+ if (schema.type !== undefined) {
57
+ const allowed = (Array.isArray(schema.type) ? schema.type : [schema.type]) as JsonType[];
58
+ const actual = jsonType(value);
59
+ if (!allowed.some((type) => type === actual || (type === "number" && actual === "integer")))
60
+ errors.push(`${path}: expected ${allowed.join("|")}, got ${actual}`);
61
+ }
62
+ if (Array.isArray(schema.enum) && !schema.enum.some((candidate) => sameJson(candidate, value)))
63
+ errors.push(`${path}: not one of ${JSON.stringify(schema.enum)}`);
64
+ if ("const" in schema && !sameJson(schema.const, value)) errors.push(`${path}: expected ${JSON.stringify(schema.const)}`);
65
+ if (typeof value === "string") {
66
+ if (typeof schema.pattern === "string" && !new RegExp(schema.pattern, "u").test(value))
67
+ errors.push(`${path}: ${JSON.stringify(value)} does not match ${schema.pattern}`);
68
+ if (typeof schema.minLength === "number" && value.length < schema.minLength) errors.push(`${path}: shorter than ${schema.minLength}`);
69
+ }
70
+ if (typeof value === "number") {
71
+ if (typeof schema.minimum === "number" && value < schema.minimum) errors.push(`${path}: ${value} < ${schema.minimum}`);
72
+ if (typeof schema.maximum === "number" && value > schema.maximum) errors.push(`${path}: ${value} > ${schema.maximum}`);
73
+ }
74
+ if (Array.isArray(value)) {
75
+ if (typeof schema.minItems === "number" && value.length < schema.minItems) errors.push(`${path}: fewer than ${schema.minItems} items`);
76
+ if (schema.uniqueItems === true && new Set(value.map((item) => JSON.stringify(item))).size !== value.length) errors.push(`${path}: items are not unique`);
77
+ if (isRecord(schema.items)) value.forEach((item, index) => errors.push(...validate(schema.items as Schema, item, `${path}[${index}]`)));
78
+ }
79
+ if (isRecord(value)) {
80
+ const properties = isRecord(schema.properties) ? schema.properties : {};
81
+ if (Array.isArray(schema.required))
82
+ for (const key of schema.required as string[]) if (!(key in value)) errors.push(`${path}: missing required property "${key}"`);
83
+ for (const [key, property] of Object.entries(properties)) {
84
+ if (key in value) errors.push(...validate(property as Schema, value[key], `${path}.${key}`));
85
+ }
86
+ if (schema.additionalProperties === false) {
87
+ for (const key of Object.keys(value)) if (!(key in properties)) errors.push(`${path}: unexpected property "${key}"`);
88
+ }
89
+ }
90
+ if (isRecord(schema.if)) {
91
+ const branch = validate(schema.if, value, path).length === 0 ? schema.then : schema.else;
92
+ if (isRecord(branch)) errors.push(...validate(branch, value, path));
93
+ }
94
+ return errors;
95
+ }
96
+
97
+ function entryFiles(directory: string): string[] {
98
+ return readdirSync(directory, { withFileTypes: true }).flatMap((entry) => {
99
+ const path = join(directory, entry.name);
100
+ if (entry.isDirectory()) return entryFiles(path);
101
+ return entry.isFile() && entry.name.endsWith(".json") ? [path] : [];
102
+ });
103
+ }
104
+
105
+ const schema = JSON.parse(readFileSync(schemaPath, "utf8")) as Schema;
106
+ const files = entryFiles(entriesRoot).sort();
107
+ const readEntry = (path: string): Record<string, unknown> => JSON.parse(readFileSync(path, "utf8")) as Record<string, unknown>;
108
+ const validEntry = (): Record<string, unknown> => readEntry(join(entriesRoot, "official", "agent-teams.json"));
109
+ const groupEntry = (): Record<string, unknown> => readEntry(join(entriesRoot, "official", "cordis-group.json"));
110
+
111
+ describe("marketplace entry schema", () => {
112
+ test("covers every shipped entry file", () => {
113
+ expect(files.length).toBe(MARKETPLACE_PLUGINS.length);
114
+ });
115
+
116
+ test.each(files.map((path) => [relative(entriesRoot, path), path] as const))("accepts %s", (_name, path) => {
117
+ expect(validate(schema, readEntry(path))).toEqual([]);
118
+ });
119
+
120
+ test("accepts core plugin subpaths and group entries with array config", () => {
121
+ expect(validate(schema, validEntry())).toEqual([]);
122
+ expect(validate(schema, groupEntry())).toEqual([]);
123
+ expect(validate(schema, { ...validEntry(), statistics: { downloads30d: 12, quality: 0.5, updatedAt: "2026-01-01T00:00:00.000Z" } })).toEqual([]);
124
+ });
125
+
126
+ test("rejects entries the runtime validator rejects", () => {
127
+ const withoutCategory = validEntry();
128
+ delete withoutCategory.category;
129
+ expect(validate(schema, withoutCategory)).toContain('$: missing required property "category"');
130
+ expect(validate(schema, { ...validEntry(), category: { id: "Not Kebab", label: "x" } })).not.toEqual([]);
131
+ expect(validate(schema, { ...validEntry(), category: { id: "collaboration", label: " " } })).not.toEqual([]);
132
+ expect(validate(schema, { ...validEntry(), packageName: "Not/Valid Name" })).not.toEqual([]);
133
+ expect(validate(schema, { ...validEntry(), profile: { name: "@pi-harness/core/plugins/agent-teams", config: [] } })).not.toEqual([]);
134
+ expect(validate(schema, { ...groupEntry(), profile: { name: "@deepseek-ai/cordis-plugin-group", group: true, config: {} } })).not.toEqual([]);
135
+ expect(validate(schema, { ...validEntry(), capabilities: [] })).not.toEqual([]);
136
+ expect(validate(schema, { ...validEntry(), repository: "http://example.com" })).not.toEqual([]);
137
+ expect(validate(schema, { ...validEntry(), unexpected: true })).not.toEqual([]);
138
+ });
139
+ });
@@ -0,0 +1,70 @@
1
+ import { execFile } from "node:child_process";
2
+ import { mkdtemp, rm, writeFile } from "node:fs/promises";
3
+ import { tmpdir } from "node:os";
4
+ import { resolve } from "node:path";
5
+ import { promisify } from "node:util";
6
+ import { afterEach, describe, expect, it } from "vitest";
7
+
8
+ const execFileAsync = promisify(execFile);
9
+ const fixtures: string[] = [];
10
+ const repositoryRoot = resolve(import.meta.dirname, "../../..");
11
+
12
+ // Stands in for npm so the smoke test can be exercised without packing and globally installing the real workspace: `pack` reports tarball names and `install` lays out
13
+ // the tree the script inspects, optionally without the files the root bin map points at.
14
+ const fakeNpmSource = `import { mkdirSync, writeFileSync } from "node:fs";
15
+ import { dirname, join } from "node:path";
16
+ import process from "node:process";
17
+
18
+ const args = process.argv.slice(2);
19
+ if (args[0] === "pack") {
20
+ process.stdout.write(args.includes("--workspace") ? "core.tgz\\n" : "harness.tgz\\n");
21
+ process.exit(0);
22
+ }
23
+ if (args[0] !== "install") process.exit(1);
24
+ const prefix = args[args.indexOf("--prefix") + 1];
25
+ const harnessRoot = join(prefix, "lib", "node_modules", "@pi-harness", "pi-harness");
26
+ const agentRoot = join(harnessRoot, "node_modules", "@earendil-works", "pi-coding-agent");
27
+ const write = (path, content) => {
28
+ mkdirSync(dirname(path), { recursive: true });
29
+ writeFileSync(path, content);
30
+ };
31
+ const bin = { "pi-harness": "./apps/web/server-dist/bin.js", pih: "./packages/cli/dist/bin.js" };
32
+ write(join(harnessRoot, "package.json"), JSON.stringify({ name: "@pi-harness/pi-harness", version: "9.9.9", bin, dependencies: { "@earendil-works/pi-coding-agent": "0.84.4" } }));
33
+ write(join(agentRoot, "package.json"), JSON.stringify({ name: "@earendil-works/pi-coding-agent", version: "0.84.4", dependencies: {} }));
34
+ write(join(agentRoot, "dist", "cli", "args.js"), "");
35
+ if (process.env.PACKED_PACKAGE_FIXTURE_BINS === "1") for (const target of Object.values(bin)) write(join(harnessRoot, target), "");
36
+ `;
37
+
38
+ const createFakeNpm = async (): Promise<string> => {
39
+ const fixture = await mkdtemp(resolve(tmpdir(), "pi-harness-packed-package-fixture-"));
40
+ fixtures.push(fixture);
41
+ const fakeNpm = resolve(fixture, "npm.mjs");
42
+ await writeFile(fakeNpm, fakeNpmSource);
43
+ return fakeNpm;
44
+ };
45
+
46
+ const runSmokeTest = async (fakeNpm: string, bins: boolean): ReturnType<typeof execFileAsync> =>
47
+ execFileAsync(process.execPath, [resolve(repositoryRoot, "scripts/test-packed-package.mjs")], {
48
+ env: { ...process.env, npm_execpath: fakeNpm, PACKED_PACKAGE_FIXTURE_BINS: bins ? "1" : "0" },
49
+ });
50
+
51
+ afterEach(async () => {
52
+ await Promise.all(fixtures.splice(0).map((fixture) => rm(fixture, { recursive: true, force: true })));
53
+ });
54
+
55
+ describe("packed package smoke test", () => {
56
+ it("accepts a tarball whose bin entrypoints are present", async () => {
57
+ const fakeNpm = await createFakeNpm();
58
+
59
+ const { stdout } = await runSmokeTest(fakeNpm, true);
60
+
61
+ expect(stdout).toContain("Packed package smoke test passed");
62
+ });
63
+
64
+ it("rejects a tarball that ships no runnable bin entrypoint", async () => {
65
+ // `npm pack --ignore-scripts` never runs prepack, so an unbuilt workspace produces a tarball with a bin map pointing at files the tarball does not contain.
66
+ const fakeNpm = await createFakeNpm();
67
+
68
+ await expect(runSmokeTest(fakeNpm, false)).rejects.toThrow(/missing the pi-harness entrypoint \.\/apps\/web\/server-dist\/bin\.js/u);
69
+ });
70
+ });
@@ -0,0 +1,50 @@
1
+ import { readdir, readFile } from "node:fs/promises";
2
+ import { resolve } from "node:path";
3
+ import { describe, expect, it } from "vitest";
4
+
5
+ const repositoryRoot = resolve(import.meta.dirname, "../../..");
6
+
7
+ const readText = async (path: string): Promise<string> => readFile(resolve(repositoryRoot, path), "utf8");
8
+
9
+ // The number of built-in plugins that `docs/README.reference.md` still has no `###` section for. It may only ever go down.
10
+ const undocumentedBudget = 53;
11
+
12
+ describe("reference documentation", () => {
13
+ it("documents every registered API route", async () => {
14
+ // The reference is the inventory a reader audits the unauthenticated local port with, so an undocumented route is an invisible attack surface.
15
+ const gateway = await readText("packages/api-gateway/src/index.ts");
16
+ const reference = await readText("docs/README.reference.md");
17
+ const routes = [...gateway.matchAll(/path: "(\/api[^"]*)"/gu)].map((match) => match[1] ?? "");
18
+
19
+ expect(routes.length).toBeGreaterThan(0);
20
+ for (const route of routes) expect(reference, `${route} is not documented`).toContain(`\`${route}\``);
21
+ });
22
+
23
+ it("claims documentation coverage only for the plugins it actually describes", async () => {
24
+ const readme = await readText("README.md");
25
+ const reference = await readText("docs/README.reference.md");
26
+ const sections = new Set([...reference.matchAll(/^### (.+)$/gmu)].map((match) => (match[1] ?? "").toLowerCase().replaceAll(/[^a-z]/gu, "")));
27
+ const plugins = (await readdir(resolve(repositoryRoot, "packages/core/src/plugins"), { withFileTypes: true }))
28
+ .filter((entry) => entry.isFile() && entry.name.endsWith(".ts"))
29
+ .map((entry) => entry.name.replace(/\.ts$/u, "").replaceAll("-", ""));
30
+ const undocumented = plugins.filter((plugin) => !sections.has(plugin));
31
+
32
+ // A ratchet, not a floor: documenting more plugins only lowers the count, while a plugin that arrives without a reference section pushes it over the budget. Lower the budget whenever it drops.
33
+ expect(undocumented.length, `undocumented built-in plugins: ${undocumented.join(", ")}`).toBeLessThanOrEqual(undocumentedBudget);
34
+ expect(readme).not.toMatch(/documents every built-in plugin/u);
35
+ expect(reference).not.toMatch(/canonical reference for the complete plugin catalog/u);
36
+ });
37
+
38
+ it("documents the model the shipped web profile actually selects", async () => {
39
+ const profile = await readText("apps/web/profile/cordis.yml");
40
+ const reference = await readText("docs/README.reference.md");
41
+ const readme = await readText("README.md");
42
+ const provider = /provider: .*\?\? '([^']+)'/u.exec(profile)?.[1];
43
+ const model = /model: .*\?\? '([^']+)'/u.exec(profile)?.[1];
44
+
45
+ expect(provider).toBeDefined();
46
+ expect(model).toBeDefined();
47
+ expect(reference).toContain(`\`${provider ?? ""}/${model ?? ""}\``);
48
+ for (const variable of ["PI_HARNESS_PROVIDER", "PI_HARNESS_MODEL"]) expect(readme, `${variable} is undocumented`).toContain(variable);
49
+ });
50
+ });
@@ -0,0 +1,77 @@
1
+ import { readdirSync, readFileSync, statSync } from "node:fs";
2
+ import { dirname, join, relative, resolve } from "node:path";
3
+ import { describe, expect, test } from "vitest";
4
+
5
+ const repositoryRoot = resolve(import.meta.dirname, "../../..");
6
+
7
+ const readText = (path: string): string => readFileSync(resolve(repositoryRoot, path), "utf8");
8
+ const readJson = (path: string): Record<string, unknown> => JSON.parse(readText(path)) as Record<string, unknown>;
9
+
10
+ function sourceFiles(directory: string, extension: string): string[] {
11
+ return readdirSync(directory, { withFileTypes: true }).flatMap((entry) => {
12
+ const path = join(directory, entry.name);
13
+ if (entry.isDirectory()) return sourceFiles(path, extension);
14
+ return entry.isFile() && entry.name.endsWith(extension) ? [path] : [];
15
+ });
16
+ }
17
+
18
+ // Reduces a bare module specifier such as "@scope/name/subpath" or "name/subpath" to the npm package that provides it.
19
+ function packageNameOf(specifier: string): string {
20
+ const segments = specifier.split("/");
21
+ return specifier.startsWith("@") ? segments.slice(0, 2).join("/") : (segments[0] ?? specifier);
22
+ }
23
+
24
+ function workspaceNameFor(binTarget: string): string {
25
+ let directory = dirname(resolve(repositoryRoot, binTarget));
26
+ while (directory !== repositoryRoot) {
27
+ const manifest = join(directory, "package.json");
28
+ if (statSync(manifest, { throwIfNoEntry: false })?.isFile()) return (JSON.parse(readFileSync(manifest, "utf8")) as { name: string }).name;
29
+ directory = dirname(directory);
30
+ }
31
+ throw new Error(`No workspace manifest above ${binTarget}`);
32
+ }
33
+
34
+ describe("release contract", () => {
35
+ const workflow = readText(".github/workflows/release.yml");
36
+
37
+ test("publish step retries after a failed publish instead of trusting the release tag", () => {
38
+ // The tag is pushed before npm publish runs, so its existence must never be used as evidence that a package version was submitted.
39
+ expect(workflow).not.toContain("RELEASE_TAG_EXISTS");
40
+ expect(workflow).not.toContain("was already submitted");
41
+ expect(workflow).not.toContain("tag_exists=$tag_exists");
42
+ expect(workflow).toContain("npm publish --workspace @pi-harness/core --access public");
43
+ expect(workflow).toContain("npm publish --access public");
44
+ });
45
+
46
+ test("pins every action to a full commit SHA with its release tag recorded", () => {
47
+ const uses = [...workflow.matchAll(/^\s+uses:\s*(.+)$/gmu)].map((match) => match[1] ?? "");
48
+ expect(uses.length).toBeGreaterThanOrEqual(2);
49
+ for (const reference of uses) expect(reference).toMatch(/^[\w.-]+\/[\w.-]+@[0-9a-f]{40} # v\d+\.\d+\.\d+$/u);
50
+ });
51
+
52
+ test("prepack builds every workspace that a root bin points at", () => {
53
+ const root = readJson("package.json") as { bin: Record<string, string>; scripts: Record<string, string> };
54
+ expect(root.scripts.prepack).toBe("npm run build:web");
55
+ const built = [...root.scripts["build:web"]!.matchAll(/npm run build -w (\S+)/gu)].map((match) => match[1]);
56
+ for (const target of Object.values(root.bin)) expect(built, `${target} is not built by build:web`).toContain(workspaceNameFor(target));
57
+ expect(built.indexOf("@pi-harness/core")).toBeLessThan(built.indexOf("@pi-harness/cli"));
58
+ });
59
+
60
+ test("core declares every package its sources and shipped profiles load", () => {
61
+ const core = readJson("packages/core/package.json") as { name: string; dependencies: Record<string, string> };
62
+ const specifierPattern =
63
+ /(?:from\s*|import\s*\(\s*|import\.meta\.resolve\(\s*|require(?:\.resolve)?\(\s*)["']([@a-z][^"'\s]*)["']|"(@[a-z0-9._~-]+\/[a-z0-9._~-]+(?:\/[a-z0-9._~-]+)*)"/gu;
64
+ const required = new Map<string, string>();
65
+ for (const file of sourceFiles(resolve(repositoryRoot, "packages/core/src"), ".ts")) {
66
+ for (const match of readFileSync(file, "utf8").matchAll(specifierPattern))
67
+ required.set(packageNameOf(match[1] ?? match[2] ?? ""), relative(repositoryRoot, file));
68
+ }
69
+ for (const file of sourceFiles(resolve(repositoryRoot, "packages/core/profiles"), ".yml")) {
70
+ for (const match of readFileSync(file, "utf8").matchAll(/^\s*name:\s*"?([^"\s]+)"?\s*$/gmu))
71
+ required.set(packageNameOf(match[1] ?? ""), relative(repositoryRoot, file));
72
+ }
73
+ const external = [...required].filter(([name]) => !name.startsWith("node:") && !name.includes(":") && name !== core.name);
74
+ expect(external.length).toBeGreaterThan(0);
75
+ for (const [name, file] of external) expect(core.dependencies[name], `${name} (used by ${file}) is missing from ${core.name} dependencies`).toBeDefined();
76
+ });
77
+ });
@@ -1,4 +1,4 @@
1
- import { readFile } from "node:fs/promises";
1
+ import { readdir, readFile, stat } from "node:fs/promises";
2
2
  import { resolve } from "node:path";
3
3
  import { describe, expect, it } from "vitest";
4
4
 
@@ -33,6 +33,37 @@ describe("release package", () => {
33
33
  expect(workflow).toContain("npm publish --workspace @pi-harness/core --access public");
34
34
  expect(workflow).toContain("npm publish --access public");
35
35
  expect(workflow).toContain("Verify package availability");
36
- expect(workflow).toContain("RELEASE_TAG_EXISTS: ${{ steps.release.outputs.tag_exists }}");
36
+ expect(workflow).not.toContain("RELEASE_TAG_EXISTS");
37
+ });
38
+
39
+ it("cleans every compiled workspace output", async () => {
40
+ // `tsc` never removes stale emit, so an output directory that no clean script touches keeps publishing files whose sources are gone.
41
+ const rootManifest = await readJson("package.json");
42
+ const rootClean = (rootManifest.scripts as Record<string, string>).clean ?? "";
43
+ const outputs: string[] = [];
44
+
45
+ for (const root of ["packages", "apps", "examples"]) {
46
+ for (const entry of await readdir(resolve(repositoryRoot, root), { withFileTypes: true })) {
47
+ if (!entry.isDirectory()) continue;
48
+ const workspace = `${root}/${entry.name}`;
49
+ const buildConfigPath = resolve(repositoryRoot, workspace, "tsconfig.build.json");
50
+ const hasBuildConfig = await stat(buildConfigPath).then(
51
+ () => true,
52
+ () => false,
53
+ );
54
+ if (!hasBuildConfig) continue;
55
+ const buildConfig = JSON.parse(await readFile(buildConfigPath, "utf8")) as { compilerOptions?: { outDir?: string } };
56
+ const outDir = buildConfig.compilerOptions?.outDir;
57
+ expect(outDir, `${workspace}/tsconfig.build.json declares no outDir`).toBeDefined();
58
+ const workspaceManifest = await readJson(`${workspace}/package.json`);
59
+ const workspaceClean = (workspaceManifest.scripts as Record<string, string> | undefined)?.clean;
60
+ outputs.push(`${workspace}/${outDir ?? ""}`);
61
+ expect(workspaceClean !== undefined || rootClean.includes(`${workspace}/${outDir ?? ""}`), `${workspace}/${outDir ?? ""} survives npm run clean`).toBe(
62
+ true,
63
+ );
64
+ }
65
+ }
66
+
67
+ expect(outputs.length).toBeGreaterThan(0);
37
68
  });
38
69
  });
@@ -37,10 +37,9 @@ describe("release version preparation", () => {
37
37
  "packages/api-gateway": { name: "@pi-harness/api-gateway", version: "0.1.2" },
38
38
  },
39
39
  });
40
- await writeJson(fixture, "packages/api-gateway/src/marketplace-entries/official/internal.json", {
41
- packageName: "@pi-harness/core/plugins/example",
42
- version: "0.1.2",
43
- });
40
+ const formattedInternalEntry = `{\n "packageName": "@pi-harness/core/plugins/example",\n "version": "0.1.2",\n "hooks": ["tool", "panel"],\n "profile": { "config": { "version": "keep-me" } }\n}\n`;
41
+ await mkdir(resolve(fixture, "packages/api-gateway/src/marketplace-entries/official"), { recursive: true });
42
+ await writeFile(resolve(fixture, "packages/api-gateway/src/marketplace-entries/official/internal.json"), formattedInternalEntry);
44
43
  await writeJson(fixture, "packages/api-gateway/src/marketplace-entries/official/external.json", { packageName: "external-plugin", version: "4.5.6" });
45
44
 
46
45
  await execFileAsync(process.execPath, [resolve(repositoryRoot, "scripts/set-release-version.mjs"), "0.1.3"], { cwd: fixture });
@@ -72,8 +71,51 @@ describe("release version preparation", () => {
72
71
  },
73
72
  });
74
73
  expect(internalEntry.version).toBe("0.1.3");
74
+ expect(await readFile(resolve(fixture, "packages/api-gateway/src/marketplace-entries/official/internal.json"), "utf8")).toBe(
75
+ formattedInternalEntry.replace('"version": "0.1.2"', '"version": "0.1.3"'),
76
+ );
75
77
  expect(externalEntry.version).toBe("4.5.6");
76
78
  expect(packedInternalEntry.version).toBe("0.1.3");
77
79
  expect(packedExternalEntry.version).toBe("4.5.6");
78
80
  });
81
+
82
+ it("re-runs against a checkout that already carries the release version", async () => {
83
+ // A re-dispatched release run checks out the release commit, so every manifest and marketplace entry already holds the requested version.
84
+ const fixture = await mkdtemp(resolve(tmpdir(), "pi-harness-release-version-"));
85
+ fixtures.push(fixture);
86
+ await Promise.all([mkdir(resolve(fixture, "apps")), mkdir(resolve(fixture, "examples"))]);
87
+ await writeJson(fixture, "package.json", { name: "@pi-harness/pi-harness", version: "0.1.3", dependencies: { "@pi-harness/core": "^0.1.3" } });
88
+ await writeJson(fixture, "packages/core/package.json", { name: "@pi-harness/core", version: "0.1.3" });
89
+ await writeJson(fixture, "packages/api-gateway/package.json", { name: "@pi-harness/api-gateway", version: "0.1.3" });
90
+ await writeJson(fixture, "package-lock.json", {
91
+ name: "@pi-harness/pi-harness",
92
+ version: "0.1.3",
93
+ lockfileVersion: 3,
94
+ packages: { "": { name: "@pi-harness/pi-harness", version: "0.1.3", dependencies: { "@pi-harness/core": "^0.1.3" } } },
95
+ });
96
+ const formattedInternalEntry = `{\n "packageName": "@pi-harness/core/plugins/example",\n "version": "0.1.3",\n "hooks": ["tool", "panel"]\n}\n`;
97
+ await mkdir(resolve(fixture, "packages/api-gateway/src/marketplace-entries/official"), { recursive: true });
98
+ await writeFile(resolve(fixture, "packages/api-gateway/src/marketplace-entries/official/internal.json"), formattedInternalEntry);
99
+
100
+ await execFileAsync(process.execPath, [resolve(repositoryRoot, "scripts/set-release-version.mjs"), "0.1.3"], { cwd: fixture });
101
+
102
+ expect(await readFile(resolve(fixture, "packages/api-gateway/src/marketplace-entries/official/internal.json"), "utf8")).toBe(formattedInternalEntry);
103
+ expect(await readFile(resolve(fixture, "packages/api-gateway/dist/marketplace-entries/official/internal.json"), "utf8")).toBe(formattedInternalEntry);
104
+ });
105
+
106
+ it("rejects an internal marketplace entry without a top-level version field", async () => {
107
+ const fixture = await mkdtemp(resolve(tmpdir(), "pi-harness-release-version-"));
108
+ fixtures.push(fixture);
109
+ await Promise.all([mkdir(resolve(fixture, "apps")), mkdir(resolve(fixture, "examples"))]);
110
+ await writeJson(fixture, "package.json", { name: "@pi-harness/pi-harness", version: "0.1.2" });
111
+ await writeJson(fixture, "packages/core/package.json", { name: "@pi-harness/core", version: "0.1.2" });
112
+ await writeJson(fixture, "packages/api-gateway/package.json", { name: "@pi-harness/api-gateway", version: "0.1.2" });
113
+ await writeJson(fixture, "package-lock.json", { name: "@pi-harness/pi-harness", version: "0.1.2", lockfileVersion: 3, packages: {} });
114
+ await mkdir(resolve(fixture, "packages/api-gateway/src/marketplace-entries/official"), { recursive: true });
115
+ await writeJson(fixture, "packages/api-gateway/src/marketplace-entries/official/internal.json", { packageName: "@pi-harness/core/plugins/example" });
116
+
117
+ await expect(execFileAsync(process.execPath, [resolve(repositoryRoot, "scripts/set-release-version.mjs"), "0.1.3"], { cwd: fixture })).rejects.toThrow(
118
+ /has no top-level version field to update/u,
119
+ );
120
+ });
79
121
  });
@@ -1,8 +1,11 @@
1
+ import { type PlatformPath } from "node:path";
1
2
  import type { Context } from "@deepseek-ai/cordis";
2
3
  import "@pi-harness/host-webserver";
3
4
  export interface WebAppConfig {
4
5
  readonly staticDir?: string;
5
6
  }
7
+ type ContainmentPath = Pick<PlatformPath, "isAbsolute" | "relative" | "sep">;
8
+ export declare function isInsideStaticRoot(root: string, candidate: string, pathApi?: ContainmentPath): boolean;
6
9
  declare const _default: {
7
10
  name: string;
8
11
  inject: string[];
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAEnD,OAAO,4BAA4B,CAAC;AAEpC,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;CAC7B;;;;mBAuCgB,OAAO,UAAU,YAAY;;AAH9C,wBAsBE"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAA4C,KAAK,YAAY,EAAE,MAAM,WAAW,CAAC;AAExF,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAEnD,OAAO,4BAA4B,CAAC;AAEpC,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;CAC7B;AAwBD,KAAK,eAAe,GAAG,IAAI,CAAC,YAAY,EAAE,YAAY,GAAG,UAAU,GAAG,KAAK,CAAC,CAAC;AAI7E,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,GAAE,eAA8B,GAAG,OAAO,CAGpH;;;;mBAwBgB,OAAO,UAAU,YAAY;;AAH9C,wBAuBE"}
@@ -1,6 +1,6 @@
1
1
  import { createReadStream, existsSync } from "node:fs";
2
2
  import { realpath, stat } from "node:fs/promises";
3
- import { join, resolve } from "node:path";
3
+ import { isAbsolute, join, relative, resolve, sep } from "node:path";
4
4
  import { pipeline } from "node:stream/promises";
5
5
  import "@pi-harness/host-webserver";
6
6
  const MIME_TYPES = {
@@ -8,16 +8,28 @@ const MIME_TYPES = {
8
8
  ".html": "text/html; charset=utf-8",
9
9
  ".js": "text/javascript; charset=utf-8",
10
10
  ".json": "application/json; charset=utf-8",
11
+ ".png": "image/png",
11
12
  ".svg": "image/svg+xml",
13
+ ".webmanifest": "application/manifest+json",
14
+ };
15
+ // The console renders model- and tool-produced markdown through dangerouslySetInnerHTML, so a CSP is the second line of defence behind the sanitizer: a bypass still cannot load a remote script or exfiltrate to another origin. frame-ancestors keeps any page the operator visits from framing the unauthenticated console, which the Host/Origin guard cannot block because browsers send no Origin on a frame navigation. Inline styles stay allowed because React writes element style attributes; nosniff is safe because every extension the bundle ships has an entry in MIME_TYPES.
16
+ const SECURITY_HEADERS = {
17
+ "content-security-policy": "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob:; font-src 'self'; connect-src 'self'; worker-src 'self' blob:; object-src 'none'; base-uri 'none'; form-action 'none'; frame-ancestors 'none'",
18
+ "x-content-type-options": "nosniff",
12
19
  };
13
20
  function contentType(path) {
14
21
  const extension = path.slice(path.lastIndexOf(".")).toLowerCase();
15
22
  return MIME_TYPES[extension] ?? "application/octet-stream";
16
23
  }
24
+ const platformPath = { isAbsolute, relative, sep };
25
+ // Containment is decided with path.relative instead of a "/"-prefixed string compare so backslash-separated Windows paths and other drives are handled; the pathApi parameter exists so tests can exercise path.win32 on any host.
26
+ export function isInsideStaticRoot(root, candidate, pathApi = platformPath) {
27
+ const remainder = pathApi.relative(root, candidate);
28
+ return remainder === "" || (remainder !== ".." && !remainder.startsWith(".." + pathApi.sep) && !pathApi.isAbsolute(remainder));
29
+ }
17
30
  function safePath(root, pathname) {
18
31
  const candidate = resolve(root, "." + pathname);
19
- const rootWithSlash = root.endsWith("/") ? root : root + "/";
20
- if (candidate !== root && !candidate.startsWith(rootWithSlash))
32
+ if (!isInsideStaticRoot(root, candidate))
21
33
  return undefined;
22
34
  return candidate;
23
35
  }
@@ -25,13 +37,12 @@ async function sendFile(path, response) {
25
37
  const info = await stat(path);
26
38
  if (!info.isFile())
27
39
  throw new Error("Not a file");
28
- response.writeHead(200, { "content-type": contentType(path), "content-length": info.size, "cache-control": "no-cache" });
40
+ response.writeHead(200, { "content-type": contentType(path), "content-length": info.size, "cache-control": "no-cache", ...SECURITY_HEADERS });
29
41
  await pipeline(createReadStream(path), response);
30
42
  }
31
43
  async function sendSafeFile(root, path, response) {
32
44
  const [rootReal, pathReal] = await Promise.all([realpath(root), realpath(path)]);
33
- const rootWithSlash = rootReal.endsWith("/") ? rootReal : rootReal + "/";
34
- if (pathReal !== rootReal && !pathReal.startsWith(rootWithSlash))
45
+ if (!isInsideStaticRoot(rootReal, pathReal))
35
46
  throw new Error("Static file escapes web root");
36
47
  await sendFile(pathReal, response);
37
48
  }
@@ -51,8 +62,10 @@ export default {
51
62
  await sendSafeFile(root, requested, response);
52
63
  return;
53
64
  }
54
- catch {
55
- // SPA fallback below.
65
+ catch (error) {
66
+ // SPA fallback below, but only while nothing has reached the wire: once sendFile has written the 200 header the request is committed to that file, so a second writeHead would throw ERR_HTTP_HEADERS_SENT over the real failure.
67
+ if (response.headersSent)
68
+ throw error;
56
69
  }
57
70
  }
58
71
  await sendSafeFile(root, index, response);
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-harness/web-app",
3
- "version": "0.1.22",
3
+ "version": "0.1.24",
4
4
  "private": true,
5
5
  "description": "Patchable Web application bundle for Pi Harness",
6
6
  "homepage": "https://github.com/pi-harness/pi-harness#readme",