@pi-harness/pi-harness 0.1.21 → 0.1.23

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 (289) hide show
  1. package/README.md +1 -1
  2. package/apps/web/dist/assets/index-Bo9CNI_U.js +22 -0
  3. package/apps/web/dist/index.html +1 -1
  4. package/apps/web/package.json +6 -6
  5. package/apps/web/server-dist/bin.js +18 -5
  6. package/apps/web/server-dist/bin.js.map +1 -1
  7. package/apps/web/src/server/bin.ts +18 -5
  8. package/apps/web/test/bin.test.ts +90 -0
  9. package/node_modules/@pi-harness/api-gateway/dist/index.d.ts.map +1 -1
  10. package/node_modules/@pi-harness/api-gateway/dist/index.js +204 -66
  11. package/node_modules/@pi-harness/api-gateway/dist/index.js.map +1 -1
  12. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/agent-teams.json +3 -12
  13. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/anchored-standard.json +3 -10
  14. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/annotation.json +3 -8
  15. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/archify.json +3 -12
  16. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/at-file.json +2 -6
  17. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/auto-mode.json +3 -10
  18. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/better-sidebar.json +3 -13
  19. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/browser-fetch.json +2 -5
  20. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/browser-session.json +2 -6
  21. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/canvas-draw.json +3 -9
  22. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/change-verifier.json +3 -11
  23. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/cleaner.json +2 -6
  24. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/cli-notifier.json +3 -11
  25. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/code2skill.json +3 -10
  26. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/colleague-skill.json +3 -10
  27. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/context-doctor.json +2 -8
  28. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/context.json +2 -7
  29. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/cost-meter.json +3 -12
  30. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/dependency-checker.json +2 -6
  31. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/docker-sandbox.json +2 -6
  32. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/fail-logger.json +2 -7
  33. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/genui.json +3 -11
  34. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/git-time-capsule.json +2 -6
  35. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/graph-memory.json +3 -12
  36. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/history-compressor.json +3 -11
  37. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/hol-guard.json +4 -11
  38. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/i18n-pair.json +2 -6
  39. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/image-compressor.json +3 -10
  40. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/llm-verifier.json +3 -13
  41. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/mcp-client.json +2 -6
  42. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/mcp-panel.json +3 -10
  43. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/memory.json +3 -9
  44. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/mirage-bridge.json +3 -11
  45. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/mock-server.json +3 -10
  46. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/modlens.json +3 -9
  47. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/module-search.json +3 -11
  48. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/obsidian-sync.json +3 -10
  49. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/openpets.json +2 -7
  50. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/plan-execute.json +3 -10
  51. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/plugin-check.json +3 -10
  52. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/plugin-dev.json +3 -12
  53. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/plugin-finder.json +3 -11
  54. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/plugin-radar.json +3 -9
  55. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/plugin-stars.json +2 -6
  56. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/prompt-guard.json +3 -9
  57. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/prompt-library.json +3 -11
  58. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/readme-gen.json +2 -7
  59. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/recall-unread.json +2 -7
  60. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/reverse-skill.json +3 -11
  61. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/reviewer-bot.json +3 -10
  62. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/runtime-doctor.json +3 -13
  63. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/secure-audit.json +3 -11
  64. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/session-bookmarks.json +3 -11
  65. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/session-bridge.json +2 -7
  66. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/session-compare.json +3 -11
  67. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/session-export.json +3 -11
  68. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/session-insights.json +2 -7
  69. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/session-search.json +3 -11
  70. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/skill-catalog.json +3 -12
  71. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/skill-guard.json +2 -6
  72. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/sql-lens.json +2 -6
  73. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/synapse.json +3 -9
  74. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/tab-manager.json +3 -10
  75. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/taskboard.json +3 -10
  76. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/telemetry-blocker.json +3 -10
  77. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/test-harness.json +2 -6
  78. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/theme-studio.json +3 -11
  79. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/token-guard.json +2 -7
  80. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/turn-rewind.json +2 -7
  81. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/undo-savepoint.json +3 -9
  82. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/vision-toolkit.json +2 -6
  83. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/web-research.json +3 -10
  84. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/workspace-navigator.json +3 -13
  85. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/workspace-search.json +3 -10
  86. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/yaml-validator.json +2 -6
  87. package/node_modules/@pi-harness/api-gateway/package.json +1 -1
  88. package/node_modules/@pi-harness/cli/dist/node-stdio.d.ts.map +1 -1
  89. package/node_modules/@pi-harness/cli/dist/node-stdio.js +3 -1
  90. package/node_modules/@pi-harness/cli/dist/node-stdio.js.map +1 -1
  91. package/node_modules/@pi-harness/cli/dist/relaunch.d.ts.map +1 -1
  92. package/node_modules/@pi-harness/cli/dist/relaunch.js +6 -1
  93. package/node_modules/@pi-harness/cli/dist/relaunch.js.map +1 -1
  94. package/node_modules/@pi-harness/cli/package.json +1 -1
  95. package/node_modules/@pi-harness/host-webserver/dist/index.d.ts.map +1 -1
  96. package/node_modules/@pi-harness/host-webserver/dist/index.js +52 -3
  97. package/node_modules/@pi-harness/host-webserver/dist/index.js.map +1 -1
  98. package/node_modules/@pi-harness/host-webserver/package.json +1 -1
  99. package/node_modules/@pi-harness/web-app/dist/index.d.ts +3 -0
  100. package/node_modules/@pi-harness/web-app/dist/index.d.ts.map +1 -1
  101. package/node_modules/@pi-harness/web-app/dist/index.js +9 -5
  102. package/node_modules/@pi-harness/web-app/dist/index.js.map +1 -1
  103. package/node_modules/@pi-harness/web-app/package.json +1 -1
  104. package/package.json +7 -7
  105. package/packages/api-gateway/dist/index.d.ts.map +1 -1
  106. package/packages/api-gateway/dist/index.js +204 -66
  107. package/packages/api-gateway/dist/index.js.map +1 -1
  108. package/packages/api-gateway/dist/marketplace-entries/official/agent-teams.json +3 -12
  109. package/packages/api-gateway/dist/marketplace-entries/official/anchored-standard.json +3 -10
  110. package/packages/api-gateway/dist/marketplace-entries/official/annotation.json +3 -8
  111. package/packages/api-gateway/dist/marketplace-entries/official/archify.json +3 -12
  112. package/packages/api-gateway/dist/marketplace-entries/official/at-file.json +2 -6
  113. package/packages/api-gateway/dist/marketplace-entries/official/auto-mode.json +3 -10
  114. package/packages/api-gateway/dist/marketplace-entries/official/better-sidebar.json +3 -13
  115. package/packages/api-gateway/dist/marketplace-entries/official/browser-fetch.json +2 -5
  116. package/packages/api-gateway/dist/marketplace-entries/official/browser-session.json +2 -6
  117. package/packages/api-gateway/dist/marketplace-entries/official/canvas-draw.json +3 -9
  118. package/packages/api-gateway/dist/marketplace-entries/official/change-verifier.json +3 -11
  119. package/packages/api-gateway/dist/marketplace-entries/official/cleaner.json +2 -6
  120. package/packages/api-gateway/dist/marketplace-entries/official/cli-notifier.json +3 -11
  121. package/packages/api-gateway/dist/marketplace-entries/official/code2skill.json +3 -10
  122. package/packages/api-gateway/dist/marketplace-entries/official/colleague-skill.json +3 -10
  123. package/packages/api-gateway/dist/marketplace-entries/official/context-doctor.json +2 -8
  124. package/packages/api-gateway/dist/marketplace-entries/official/context.json +2 -7
  125. package/packages/api-gateway/dist/marketplace-entries/official/cost-meter.json +3 -12
  126. package/packages/api-gateway/dist/marketplace-entries/official/dependency-checker.json +2 -6
  127. package/packages/api-gateway/dist/marketplace-entries/official/docker-sandbox.json +2 -6
  128. package/packages/api-gateway/dist/marketplace-entries/official/fail-logger.json +2 -7
  129. package/packages/api-gateway/dist/marketplace-entries/official/genui.json +3 -11
  130. package/packages/api-gateway/dist/marketplace-entries/official/git-time-capsule.json +2 -6
  131. package/packages/api-gateway/dist/marketplace-entries/official/graph-memory.json +3 -12
  132. package/packages/api-gateway/dist/marketplace-entries/official/history-compressor.json +3 -11
  133. package/packages/api-gateway/dist/marketplace-entries/official/hol-guard.json +4 -11
  134. package/packages/api-gateway/dist/marketplace-entries/official/i18n-pair.json +2 -6
  135. package/packages/api-gateway/dist/marketplace-entries/official/image-compressor.json +3 -10
  136. package/packages/api-gateway/dist/marketplace-entries/official/llm-verifier.json +3 -13
  137. package/packages/api-gateway/dist/marketplace-entries/official/mcp-client.json +2 -6
  138. package/packages/api-gateway/dist/marketplace-entries/official/mcp-panel.json +3 -10
  139. package/packages/api-gateway/dist/marketplace-entries/official/memory.json +3 -9
  140. package/packages/api-gateway/dist/marketplace-entries/official/mirage-bridge.json +3 -11
  141. package/packages/api-gateway/dist/marketplace-entries/official/mock-server.json +3 -10
  142. package/packages/api-gateway/dist/marketplace-entries/official/modlens.json +3 -9
  143. package/packages/api-gateway/dist/marketplace-entries/official/module-search.json +3 -11
  144. package/packages/api-gateway/dist/marketplace-entries/official/obsidian-sync.json +3 -10
  145. package/packages/api-gateway/dist/marketplace-entries/official/openpets.json +2 -7
  146. package/packages/api-gateway/dist/marketplace-entries/official/plan-execute.json +3 -10
  147. package/packages/api-gateway/dist/marketplace-entries/official/plugin-check.json +3 -10
  148. package/packages/api-gateway/dist/marketplace-entries/official/plugin-dev.json +3 -12
  149. package/packages/api-gateway/dist/marketplace-entries/official/plugin-finder.json +3 -11
  150. package/packages/api-gateway/dist/marketplace-entries/official/plugin-radar.json +3 -9
  151. package/packages/api-gateway/dist/marketplace-entries/official/plugin-stars.json +2 -6
  152. package/packages/api-gateway/dist/marketplace-entries/official/prompt-guard.json +3 -9
  153. package/packages/api-gateway/dist/marketplace-entries/official/prompt-library.json +3 -11
  154. package/packages/api-gateway/dist/marketplace-entries/official/readme-gen.json +2 -7
  155. package/packages/api-gateway/dist/marketplace-entries/official/recall-unread.json +2 -7
  156. package/packages/api-gateway/dist/marketplace-entries/official/reverse-skill.json +3 -11
  157. package/packages/api-gateway/dist/marketplace-entries/official/reviewer-bot.json +3 -10
  158. package/packages/api-gateway/dist/marketplace-entries/official/runtime-doctor.json +3 -13
  159. package/packages/api-gateway/dist/marketplace-entries/official/secure-audit.json +3 -11
  160. package/packages/api-gateway/dist/marketplace-entries/official/session-bookmarks.json +3 -11
  161. package/packages/api-gateway/dist/marketplace-entries/official/session-bridge.json +2 -7
  162. package/packages/api-gateway/dist/marketplace-entries/official/session-compare.json +3 -11
  163. package/packages/api-gateway/dist/marketplace-entries/official/session-export.json +3 -11
  164. package/packages/api-gateway/dist/marketplace-entries/official/session-insights.json +2 -7
  165. package/packages/api-gateway/dist/marketplace-entries/official/session-search.json +3 -11
  166. package/packages/api-gateway/dist/marketplace-entries/official/skill-catalog.json +3 -12
  167. package/packages/api-gateway/dist/marketplace-entries/official/skill-guard.json +2 -6
  168. package/packages/api-gateway/dist/marketplace-entries/official/sql-lens.json +2 -6
  169. package/packages/api-gateway/dist/marketplace-entries/official/synapse.json +3 -9
  170. package/packages/api-gateway/dist/marketplace-entries/official/tab-manager.json +3 -10
  171. package/packages/api-gateway/dist/marketplace-entries/official/taskboard.json +3 -10
  172. package/packages/api-gateway/dist/marketplace-entries/official/telemetry-blocker.json +3 -10
  173. package/packages/api-gateway/dist/marketplace-entries/official/test-harness.json +2 -6
  174. package/packages/api-gateway/dist/marketplace-entries/official/theme-studio.json +3 -11
  175. package/packages/api-gateway/dist/marketplace-entries/official/token-guard.json +2 -7
  176. package/packages/api-gateway/dist/marketplace-entries/official/turn-rewind.json +2 -7
  177. package/packages/api-gateway/dist/marketplace-entries/official/undo-savepoint.json +3 -9
  178. package/packages/api-gateway/dist/marketplace-entries/official/vision-toolkit.json +2 -6
  179. package/packages/api-gateway/dist/marketplace-entries/official/web-research.json +3 -10
  180. package/packages/api-gateway/dist/marketplace-entries/official/workspace-navigator.json +3 -13
  181. package/packages/api-gateway/dist/marketplace-entries/official/workspace-search.json +3 -10
  182. package/packages/api-gateway/dist/marketplace-entries/official/yaml-validator.json +2 -6
  183. package/packages/api-gateway/package.json +1 -1
  184. package/packages/api-gateway/src/index.ts +227 -68
  185. package/packages/api-gateway/src/marketplace-entries/official/agent-teams.json +3 -12
  186. package/packages/api-gateway/src/marketplace-entries/official/anchored-standard.json +3 -10
  187. package/packages/api-gateway/src/marketplace-entries/official/annotation.json +3 -8
  188. package/packages/api-gateway/src/marketplace-entries/official/archify.json +3 -12
  189. package/packages/api-gateway/src/marketplace-entries/official/at-file.json +2 -6
  190. package/packages/api-gateway/src/marketplace-entries/official/auto-mode.json +3 -10
  191. package/packages/api-gateway/src/marketplace-entries/official/better-sidebar.json +3 -13
  192. package/packages/api-gateway/src/marketplace-entries/official/browser-fetch.json +2 -5
  193. package/packages/api-gateway/src/marketplace-entries/official/browser-session.json +2 -6
  194. package/packages/api-gateway/src/marketplace-entries/official/canvas-draw.json +3 -9
  195. package/packages/api-gateway/src/marketplace-entries/official/change-verifier.json +3 -11
  196. package/packages/api-gateway/src/marketplace-entries/official/cleaner.json +2 -6
  197. package/packages/api-gateway/src/marketplace-entries/official/cli-notifier.json +3 -11
  198. package/packages/api-gateway/src/marketplace-entries/official/code2skill.json +3 -10
  199. package/packages/api-gateway/src/marketplace-entries/official/colleague-skill.json +3 -10
  200. package/packages/api-gateway/src/marketplace-entries/official/context-doctor.json +2 -8
  201. package/packages/api-gateway/src/marketplace-entries/official/context.json +2 -7
  202. package/packages/api-gateway/src/marketplace-entries/official/cost-meter.json +3 -12
  203. package/packages/api-gateway/src/marketplace-entries/official/dependency-checker.json +2 -6
  204. package/packages/api-gateway/src/marketplace-entries/official/docker-sandbox.json +2 -6
  205. package/packages/api-gateway/src/marketplace-entries/official/fail-logger.json +2 -7
  206. package/packages/api-gateway/src/marketplace-entries/official/genui.json +3 -11
  207. package/packages/api-gateway/src/marketplace-entries/official/git-time-capsule.json +2 -6
  208. package/packages/api-gateway/src/marketplace-entries/official/graph-memory.json +3 -12
  209. package/packages/api-gateway/src/marketplace-entries/official/history-compressor.json +3 -11
  210. package/packages/api-gateway/src/marketplace-entries/official/hol-guard.json +4 -11
  211. package/packages/api-gateway/src/marketplace-entries/official/i18n-pair.json +2 -6
  212. package/packages/api-gateway/src/marketplace-entries/official/image-compressor.json +3 -10
  213. package/packages/api-gateway/src/marketplace-entries/official/llm-verifier.json +3 -13
  214. package/packages/api-gateway/src/marketplace-entries/official/mcp-client.json +2 -6
  215. package/packages/api-gateway/src/marketplace-entries/official/mcp-panel.json +3 -10
  216. package/packages/api-gateway/src/marketplace-entries/official/memory.json +3 -9
  217. package/packages/api-gateway/src/marketplace-entries/official/mirage-bridge.json +3 -11
  218. package/packages/api-gateway/src/marketplace-entries/official/mock-server.json +3 -10
  219. package/packages/api-gateway/src/marketplace-entries/official/modlens.json +3 -9
  220. package/packages/api-gateway/src/marketplace-entries/official/module-search.json +3 -11
  221. package/packages/api-gateway/src/marketplace-entries/official/obsidian-sync.json +3 -10
  222. package/packages/api-gateway/src/marketplace-entries/official/openpets.json +2 -7
  223. package/packages/api-gateway/src/marketplace-entries/official/plan-execute.json +3 -10
  224. package/packages/api-gateway/src/marketplace-entries/official/plugin-check.json +3 -10
  225. package/packages/api-gateway/src/marketplace-entries/official/plugin-dev.json +3 -12
  226. package/packages/api-gateway/src/marketplace-entries/official/plugin-finder.json +3 -11
  227. package/packages/api-gateway/src/marketplace-entries/official/plugin-radar.json +3 -9
  228. package/packages/api-gateway/src/marketplace-entries/official/plugin-stars.json +2 -6
  229. package/packages/api-gateway/src/marketplace-entries/official/prompt-guard.json +3 -9
  230. package/packages/api-gateway/src/marketplace-entries/official/prompt-library.json +3 -11
  231. package/packages/api-gateway/src/marketplace-entries/official/readme-gen.json +2 -7
  232. package/packages/api-gateway/src/marketplace-entries/official/recall-unread.json +2 -7
  233. package/packages/api-gateway/src/marketplace-entries/official/reverse-skill.json +3 -11
  234. package/packages/api-gateway/src/marketplace-entries/official/reviewer-bot.json +3 -10
  235. package/packages/api-gateway/src/marketplace-entries/official/runtime-doctor.json +3 -13
  236. package/packages/api-gateway/src/marketplace-entries/official/secure-audit.json +3 -11
  237. package/packages/api-gateway/src/marketplace-entries/official/session-bookmarks.json +3 -11
  238. package/packages/api-gateway/src/marketplace-entries/official/session-bridge.json +2 -7
  239. package/packages/api-gateway/src/marketplace-entries/official/session-compare.json +3 -11
  240. package/packages/api-gateway/src/marketplace-entries/official/session-export.json +3 -11
  241. package/packages/api-gateway/src/marketplace-entries/official/session-insights.json +2 -7
  242. package/packages/api-gateway/src/marketplace-entries/official/session-search.json +3 -11
  243. package/packages/api-gateway/src/marketplace-entries/official/skill-catalog.json +3 -12
  244. package/packages/api-gateway/src/marketplace-entries/official/skill-guard.json +2 -6
  245. package/packages/api-gateway/src/marketplace-entries/official/sql-lens.json +2 -6
  246. package/packages/api-gateway/src/marketplace-entries/official/synapse.json +3 -9
  247. package/packages/api-gateway/src/marketplace-entries/official/tab-manager.json +3 -10
  248. package/packages/api-gateway/src/marketplace-entries/official/taskboard.json +3 -10
  249. package/packages/api-gateway/src/marketplace-entries/official/telemetry-blocker.json +3 -10
  250. package/packages/api-gateway/src/marketplace-entries/official/test-harness.json +2 -6
  251. package/packages/api-gateway/src/marketplace-entries/official/theme-studio.json +3 -11
  252. package/packages/api-gateway/src/marketplace-entries/official/token-guard.json +2 -7
  253. package/packages/api-gateway/src/marketplace-entries/official/turn-rewind.json +2 -7
  254. package/packages/api-gateway/src/marketplace-entries/official/undo-savepoint.json +3 -9
  255. package/packages/api-gateway/src/marketplace-entries/official/vision-toolkit.json +2 -6
  256. package/packages/api-gateway/src/marketplace-entries/official/web-research.json +3 -10
  257. package/packages/api-gateway/src/marketplace-entries/official/workspace-navigator.json +3 -13
  258. package/packages/api-gateway/src/marketplace-entries/official/workspace-search.json +3 -10
  259. package/packages/api-gateway/src/marketplace-entries/official/yaml-validator.json +2 -6
  260. package/packages/api-gateway/test/index.test.ts +363 -1
  261. package/packages/api-gateway/test/marketplace-schema.test.ts +139 -0
  262. package/packages/api-gateway/test/release-contract.test.ts +77 -0
  263. package/packages/api-gateway/test/release-package.test.ts +1 -1
  264. package/packages/api-gateway/test/release-version.test.ts +6 -4
  265. package/packages/bundle-web-app/dist/index.d.ts +3 -0
  266. package/packages/bundle-web-app/dist/index.d.ts.map +1 -1
  267. package/packages/bundle-web-app/dist/index.js +9 -5
  268. package/packages/bundle-web-app/dist/index.js.map +1 -1
  269. package/packages/bundle-web-app/package.json +1 -1
  270. package/packages/bundle-web-app/src/index.ts +12 -5
  271. package/packages/bundle-web-app/test/index.test.ts +33 -2
  272. package/packages/cli/dist/node-stdio.d.ts.map +1 -1
  273. package/packages/cli/dist/node-stdio.js +3 -1
  274. package/packages/cli/dist/node-stdio.js.map +1 -1
  275. package/packages/cli/dist/relaunch.d.ts.map +1 -1
  276. package/packages/cli/dist/relaunch.js +6 -1
  277. package/packages/cli/dist/relaunch.js.map +1 -1
  278. package/packages/cli/package.json +1 -1
  279. package/packages/cli/src/node-stdio.ts +6 -3
  280. package/packages/cli/src/relaunch.ts +5 -1
  281. package/packages/cli/test/node-stdio.test.ts +43 -0
  282. package/packages/cli/test/relaunch.test.ts +35 -0
  283. package/packages/host-webserver/dist/index.d.ts.map +1 -1
  284. package/packages/host-webserver/dist/index.js +52 -3
  285. package/packages/host-webserver/dist/index.js.map +1 -1
  286. package/packages/host-webserver/package.json +1 -1
  287. package/packages/host-webserver/src/index.ts +57 -3
  288. package/packages/host-webserver/test/index.test.ts +129 -1
  289. package/apps/web/dist/assets/index-e92yZuUr.js +0 -22
@@ -1,25 +1,39 @@
1
1
  import { execFile } from "node:child_process";
2
- import { mkdir, mkdtemp, readFile, rm, stat, unlink, writeFile } from "node:fs/promises";
3
- import { basename, isAbsolute, join, relative, resolve } from "node:path";
2
+ import { mkdir, mkdtemp, readFile, rename, rm, stat, unlink, writeFile } from "node:fs/promises";
3
+ import { basename, isAbsolute, join, relative, resolve, sep } from "node:path";
4
4
  import { tmpdir } from "node:os";
5
5
  import { SessionManager } from "@earendil-works/pi-coding-agent";
6
+ import { atomicWriteFile } from "@pi-harness/core";
6
7
  import { MARKETPLACE_CAPABILITIES, MARKETPLACE_CATEGORIES, MARKETPLACE_PLUGINS, attachMarketplaceStatistics, createMarketplaceStatisticsLoader, paginateMarketplace, searchMarketplace, needsMarketplacePackageInstall, sortMarketplaceByRecommendation, } from "./marketplace.js";
7
8
  import { parseGitWorktrees } from "./workspaces.js";
8
9
  const loadMarketplaceStatistics = createMarketplaceStatisticsLoader();
10
+ const DEFAULT_BODY_LIMIT_BYTES = 64 * 1024;
11
+ const IMPORT_CONTENT_LIMIT_BYTES = 10 * 1024 * 1024;
12
+ // The import body carries the JSONL content as a JSON string, so quotes and newlines are escaped; leave headroom above the content limit for that overhead.
13
+ const IMPORT_BODY_LIMIT_BYTES = 16 * 1024 * 1024;
14
+ // Retained trajectory events are replayed to every SSE client and returned by /api/session, so the array must stay bounded.
15
+ const MAX_RETAINED_EVENTS = 2000;
16
+ const GIT_TIMEOUT_MS = 15_000;
17
+ class PayloadTooLargeError extends Error {
18
+ constructor() {
19
+ super("Request body is too large");
20
+ this.name = "PayloadTooLargeError";
21
+ }
22
+ }
9
23
  function sendJson(response, status, payload) {
10
24
  const body = JSON.stringify(payload);
11
25
  response.writeHead(status, { "content-type": "application/json; charset=utf-8", "cache-control": "no-store", "content-length": Buffer.byteLength(body) });
12
26
  response.end(body);
13
27
  }
14
- async function bodyText(request) {
28
+ async function bodyText(request, maxBytes = DEFAULT_BODY_LIMIT_BYTES) {
15
29
  const chunks = [];
16
30
  let length = 0;
17
31
  for await (const chunk of request) {
18
32
  const input = chunk;
19
33
  const value = typeof input === "string" ? input : Buffer.from(input).toString("utf8");
20
34
  length += Buffer.byteLength(value);
21
- if (length > 64 * 1024)
22
- throw new Error("Request body is too large");
35
+ if (length > maxBytes)
36
+ throw new PayloadTooLargeError();
23
37
  chunks.push(value);
24
38
  }
25
39
  return chunks.join("");
@@ -106,26 +120,63 @@ function piConfig(services) {
106
120
  function sessionMetadataFile(manager) {
107
121
  return resolve(manager.getSessionDir(), ".pi-harness-session-meta.json");
108
122
  }
109
- async function readSessionMetadata(manager) {
123
+ // A missing file is the normal first-run state. Any other read or parse failure means the file exists but is unusable; it is renamed aside so the wreckage survives for recovery and the next write cannot silently replace the only copy.
124
+ async function readSessionMetadata(manager, logger) {
125
+ const file = sessionMetadataFile(manager);
126
+ let raw;
110
127
  try {
111
- const parsed = JSON.parse(await readFile(sessionMetadataFile(manager), "utf8"));
112
- if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed))
128
+ raw = await readFile(file, "utf8");
129
+ }
130
+ catch (error) {
131
+ if (error.code === "ENOENT")
113
132
  return {};
133
+ await quarantineSessionMetadata(file, logger, error);
134
+ return {};
135
+ }
136
+ try {
137
+ const parsed = JSON.parse(raw);
138
+ if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed))
139
+ throw new Error("session metadata must be a JSON object");
114
140
  return parsed;
115
141
  }
116
- catch {
142
+ catch (error) {
143
+ await quarantineSessionMetadata(file, logger, error);
117
144
  return {};
118
145
  }
119
146
  }
147
+ async function quarantineSessionMetadata(file, logger, error) {
148
+ const quarantined = `${file}.corrupt-${Date.now()}`;
149
+ try {
150
+ await rename(file, quarantined);
151
+ logger.warn(`Session metadata at ${file} is unreadable (${errorText(error)}); moved it to ${quarantined} and starting from an empty map`);
152
+ }
153
+ catch (renameError) {
154
+ logger.warn(`Session metadata at ${file} is unreadable (${errorText(error)}) and could not be quarantined: ${errorText(renameError)}`);
155
+ }
156
+ }
120
157
  async function writeSessionMetadata(manager, metadata) {
121
158
  await mkdir(manager.getSessionDir(), { recursive: true });
122
- await writeFile(sessionMetadataFile(manager), JSON.stringify(metadata, null, 2) + "\n", "utf8");
159
+ await atomicWriteFile(sessionMetadataFile(manager), JSON.stringify(metadata, null, 2) + "\n", { encoding: "utf8" });
160
+ }
161
+ // Every read-modify-write of the metadata file runs through this chain so concurrent requests cannot interleave and drop each other's updates.
162
+ let sessionMetadataQueue = Promise.resolve();
163
+ function mutateSessionMetadata(manager, logger, mutate) {
164
+ const operation = sessionMetadataQueue
165
+ .catch(() => undefined)
166
+ .then(async () => {
167
+ const metadata = await readSessionMetadata(manager, logger);
168
+ const result = await mutate(metadata);
169
+ await writeSessionMetadata(manager, metadata);
170
+ return result;
171
+ });
172
+ sessionMetadataQueue = operation;
173
+ return operation;
123
174
  }
124
175
  function sessionPathInDirectory(path, manager) {
125
176
  const root = resolve(manager.getSessionDir());
126
177
  const target = resolve(path);
127
178
  const relativePath = relative(root, target);
128
- return relativePath !== "" && !isAbsolute(relativePath) && relativePath !== ".." && !relativePath.startsWith(".." + "/") && target.endsWith(".jsonl");
179
+ return relativePath !== "" && !isAbsolute(relativePath) && relativePath !== ".." && !relativePath.startsWith(".." + sep) && target.endsWith(".jsonl");
129
180
  }
130
181
  const webSessionUi = {
131
182
  select: (_title, options) => Promise.resolve(options[0]),
@@ -412,21 +463,52 @@ async function updateMarketplaceProfile(configPath, entryId, update) {
412
463
  function writeSse(response, payload) {
413
464
  response.write(`data: ${JSON.stringify(jsonSafe(payload))}\n\n`);
414
465
  }
466
+ // Node reports a maxBuffer overflow through a string error code and a timeout through `killed`; neither is a git exit status, so they must not be folded into an ordinary non-zero exit.
467
+ function gitTermination(error) {
468
+ if (error === null)
469
+ return undefined;
470
+ if (error.code === "ERR_CHILD_PROCESS_STDIO_MAXBUFFER")
471
+ return "output-limit";
472
+ if (error.killed === true)
473
+ return "timeout";
474
+ return undefined;
475
+ }
476
+ function gitTerminationMessage(command, termination) {
477
+ return termination === "timeout"
478
+ ? `git ${command} timed out after ${GIT_TIMEOUT_MS / 1000} seconds`
479
+ : `git ${command} produced more output than the buffer limit allows`;
480
+ }
415
481
  function gitStatus(cwd) {
416
- return new Promise((resolve) => {
417
- execFile("git", ["status", "--short", "--untracked-files=all"], { cwd, maxBuffer: 512 * 1024 }, (error, stdout) => resolve(error ? "" : stdout));
482
+ return new Promise((resolveStatus, rejectStatus) => {
483
+ execFile("git", ["status", "--short", "--untracked-files=all"], { cwd, timeout: GIT_TIMEOUT_MS, maxBuffer: 512 * 1024 }, (error, stdout, stderr) => {
484
+ if (error === null) {
485
+ resolveStatus({ output: stdout, truncated: false });
486
+ return;
487
+ }
488
+ const termination = gitTermination(error);
489
+ if (termination === "output-limit") {
490
+ // Keep the complete lines that arrived before the kill; the final line may have been cut mid-path.
491
+ resolveStatus({ output: stdout.slice(0, stdout.lastIndexOf("\n") + 1), truncated: true });
492
+ return;
493
+ }
494
+ if (termination === undefined && error.code === 128 && /not a git repository/i.test(stderr)) {
495
+ resolveStatus({ output: "", truncated: false });
496
+ return;
497
+ }
498
+ rejectStatus(new Error(termination ? gitTerminationMessage("status", termination) : stderr.trim() || error.message, { cause: error }));
499
+ });
418
500
  });
419
501
  }
420
502
  function gitDiff(cwd, path) {
421
503
  return new Promise((resolveOutput) => {
422
- execFile("git", ["diff", "--no-ext-diff", "--", path], { cwd, maxBuffer: 1024 * 1024 }, (error, stdout) => resolveOutput(error && stdout.length === 0 ? "" : stdout));
504
+ execFile("git", ["diff", "--no-ext-diff", "--", path], { cwd, timeout: GIT_TIMEOUT_MS, maxBuffer: 1024 * 1024 }, (error, stdout) => resolveOutput(error && stdout.length === 0 ? "" : stdout));
423
505
  });
424
506
  }
425
507
  function gitCommand(cwd, args) {
426
508
  return new Promise((resolveResult) => {
427
- execFile("git", [...args], { cwd, maxBuffer: 2 * 1024 * 1024 }, (error, stdout, stderr) => {
509
+ execFile("git", [...args], { cwd, timeout: GIT_TIMEOUT_MS, maxBuffer: 2 * 1024 * 1024 }, (error, stdout, stderr) => {
428
510
  const code = error && typeof error.code === "number" ? error.code : error ? 1 : 0;
429
- resolveResult({ stdout, stderr, code });
511
+ resolveResult({ stdout, stderr, code, terminated: gitTermination(error) });
430
512
  });
431
513
  });
432
514
  }
@@ -503,7 +585,12 @@ export default {
503
585
  const events = [];
504
586
  const eventClients = new Set();
505
587
  const handleEvent = (event) => {
506
- events.push(event);
588
+ // Streaming deltas reach clients live over SSE and each one carries the whole partial message, so only durable events are retained for snapshots.
589
+ if (event.type !== "message_update") {
590
+ events.push(event);
591
+ if (events.length > MAX_RETAINED_EVENTS)
592
+ events.splice(0, events.length - MAX_RETAINED_EVENTS);
593
+ }
507
594
  for (const response of eventClients) {
508
595
  if (response.writableEnded || response.destroyed) {
509
596
  eventClients.delete(response);
@@ -639,7 +726,9 @@ export default {
639
726
  return;
640
727
  }
641
728
  const path = join(services.launch.agentDir, "settings.json");
642
- await writeFile(path, JSON.stringify(parsed, null, 2) + "\n", "utf8");
729
+ // Replace the file atomically so an interrupted write never leaves a truncated settings.json behind; keep the existing permission bits.
730
+ const mode = await stat(path).then((info) => info.mode & 0o777, () => 0o644);
731
+ await atomicWriteFile(path, JSON.stringify(parsed, null, 2) + "\n", { encoding: "utf8", mode });
643
732
  await services.runtime.session.settingsManager.reload();
644
733
  sendJson(response, 200, piConfig(services));
645
734
  }
@@ -1149,8 +1238,15 @@ export default {
1149
1238
  const disposeFiles = services.webServer.register({
1150
1239
  path: "/api/files",
1151
1240
  async handler(_request, response) {
1152
- const output = await gitStatus(activeCwd(services));
1153
- const items = output
1241
+ let status;
1242
+ try {
1243
+ status = await gitStatus(activeCwd(services));
1244
+ }
1245
+ catch (error) {
1246
+ sendJson(response, 500, { error: errorText(error) });
1247
+ return;
1248
+ }
1249
+ const items = status.output
1154
1250
  .split("\n")
1155
1251
  .map((line) => line.trimEnd())
1156
1252
  .filter((line) => line.length > 0)
@@ -1162,7 +1258,7 @@ export default {
1162
1258
  label: status === "??" ? "untracked" : status.includes("D") ? "deleted" : status.includes("A") ? "added" : "modified",
1163
1259
  };
1164
1260
  });
1165
- sendJson(response, 200, { items });
1261
+ sendJson(response, 200, { items, ...(status.truncated ? { truncated: true } : {}) });
1166
1262
  },
1167
1263
  });
1168
1264
  const disposeFileDiff = services.webServer.register({
@@ -1181,7 +1277,7 @@ export default {
1181
1277
  const root = resolve(activeCwd(services));
1182
1278
  const absolute = resolve(root, requested);
1183
1279
  const relativePath = relative(root, absolute);
1184
- if (isAbsolute(relativePath) || relativePath === ".." || relativePath.startsWith(".." + "/")) {
1280
+ if (isAbsolute(relativePath) || relativePath === ".." || relativePath.startsWith(".." + sep)) {
1185
1281
  sendJson(response, 400, { error: "path must stay inside the workspace" });
1186
1282
  return;
1187
1283
  }
@@ -1208,11 +1304,19 @@ export default {
1208
1304
  }
1209
1305
  const root = resolve(activeCwd(services));
1210
1306
  const add = await gitCommand(root, ["add", "-A", "--", ...paths]);
1307
+ if (add.terminated) {
1308
+ sendJson(response, 500, { error: gitTerminationMessage("add", add.terminated) });
1309
+ return;
1310
+ }
1211
1311
  if (add.code !== 0) {
1212
1312
  sendJson(response, 409, { error: add.stderr.trim() || "Unable to stage workspace files" });
1213
1313
  return;
1214
1314
  }
1215
1315
  const commit = await gitCommand(root, ["commit", "-m", payload.message.trim(), "--", ...paths]);
1316
+ if (commit.terminated) {
1317
+ sendJson(response, 500, { error: gitTerminationMessage("commit", commit.terminated) });
1318
+ return;
1319
+ }
1216
1320
  if (commit.code !== 0) {
1217
1321
  sendJson(response, 409, { error: commit.stdout.trim() || commit.stderr.trim() || "Nothing to commit" });
1218
1322
  return;
@@ -1244,16 +1348,39 @@ export default {
1244
1348
  sendJson(response, 400, { error: paths.message });
1245
1349
  return;
1246
1350
  }
1247
- const untracked = await gitCommand(root, ["ls-files", "--others", "--exclude-standard", "--", ...paths]);
1248
- const restore = await gitCommand(root, ["restore", "--worktree", "--staged", "--", ...paths]);
1249
- if (restore.code !== 0 && !restore.stderr.includes("pathspec")) {
1250
- sendJson(response, 409, { error: restore.stderr.trim() || "Unable to restore workspace files" });
1351
+ const untracked = await gitCommand(root, ["ls-files", "-z", "--others", "--exclude-standard", "--", ...paths]);
1352
+ // `git restore` refuses the whole request when any pathspec is unknown to it, so restore only the paths git tracks. `--with-tree=HEAD` keeps staged deletions in the list; it fails on an unborn HEAD, where the plain index listing is all there is.
1353
+ let tracked = await gitCommand(root, ["ls-files", "-z", "--with-tree=HEAD", "--", ...paths]);
1354
+ if (tracked.code !== 0 && tracked.terminated === undefined)
1355
+ tracked = await gitCommand(root, ["ls-files", "-z", "--", ...paths]);
1356
+ const listing = [untracked, tracked].find((result) => result.terminated !== undefined || result.code !== 0);
1357
+ if (listing) {
1358
+ if (listing.terminated)
1359
+ sendJson(response, 500, { error: gitTerminationMessage("ls-files", listing.terminated) });
1360
+ else
1361
+ sendJson(response, 409, { error: listing.stderr.trim() || "Unable to inspect workspace files" });
1362
+ return;
1363
+ }
1364
+ const untrackedPaths = untracked.stdout.split("\0").filter(Boolean);
1365
+ const trackedPaths = tracked.stdout.split("\0").filter(Boolean);
1366
+ const known = [...untrackedPaths, ...trackedPaths];
1367
+ const unknown = paths.filter((path) => !known.some((candidate) => candidate === path || candidate.startsWith(path + "/")));
1368
+ if (unknown.length > 0) {
1369
+ sendJson(response, 409, { error: `Paths did not match any file known to git: ${unknown.join(", ")}` });
1251
1370
  return;
1252
1371
  }
1253
- for (const path of untracked.stdout
1254
- .split("\n")
1255
- .map((item) => item.trim())
1256
- .filter(Boolean)) {
1372
+ if (trackedPaths.length > 0) {
1373
+ const restore = await gitCommand(root, ["restore", "--worktree", "--staged", "--", ...trackedPaths]);
1374
+ if (restore.terminated) {
1375
+ sendJson(response, 500, { error: gitTerminationMessage("restore", restore.terminated) });
1376
+ return;
1377
+ }
1378
+ if (restore.code !== 0) {
1379
+ sendJson(response, 409, { error: restore.stderr.trim() || "Unable to restore workspace files" });
1380
+ return;
1381
+ }
1382
+ }
1383
+ for (const path of untrackedPaths) {
1257
1384
  await rm(resolve(root, path), { recursive: true, force: true });
1258
1385
  }
1259
1386
  sendJson(response, 200, { reverted: true, paths });
@@ -1291,6 +1418,10 @@ export default {
1291
1418
  const disposePrompt = services.webServer.register({
1292
1419
  path: "/api/prompt",
1293
1420
  async handler(request, response) {
1421
+ if (request.method !== "POST") {
1422
+ sendJson(response, 405, { error: "Method not allowed" });
1423
+ return;
1424
+ }
1294
1425
  if (busy) {
1295
1426
  sendJson(response, 409, { error: "Another prompt is already running" });
1296
1427
  return;
@@ -1541,9 +1672,9 @@ export default {
1541
1672
  events.length = 0;
1542
1673
  }
1543
1674
  await unlink(path);
1544
- const metadata = await readSessionMetadata(manager);
1545
- delete metadata[path];
1546
- await writeSessionMetadata(manager, metadata);
1675
+ await mutateSessionMetadata(manager, context.logger, (metadata) => {
1676
+ delete metadata[path];
1677
+ });
1547
1678
  sendJson(response, 200, { deleted: true, path, sessionFile: services.runtime.session.sessionFile });
1548
1679
  }
1549
1680
  catch (error) {
@@ -1566,16 +1697,17 @@ export default {
1566
1697
  sendJson(response, 400, { error: "Invalid session path" });
1567
1698
  return;
1568
1699
  }
1569
- const metadata = await readSessionMetadata(manager);
1570
- const currentMetadata = metadata[path] ?? {};
1571
- const nextMetadata = {
1572
- ...currentMetadata,
1573
- ...(payload.archived === undefined ? {} : { archived: payload.archived === true }),
1574
- ...(payload.pinned === undefined ? {} : { pinned: payload.pinned === true }),
1575
- };
1576
- metadata[path] = nextMetadata;
1577
- await writeSessionMetadata(manager, metadata);
1578
- sendJson(response, 200, { path, metadata: metadata[path] });
1700
+ const nextMetadata = await mutateSessionMetadata(manager, context.logger, (metadata) => {
1701
+ const currentMetadata = metadata[path] ?? {};
1702
+ const updated = {
1703
+ ...currentMetadata,
1704
+ ...(payload.archived === undefined ? {} : { archived: payload.archived === true }),
1705
+ ...(payload.pinned === undefined ? {} : { pinned: payload.pinned === true }),
1706
+ };
1707
+ metadata[path] = updated;
1708
+ return updated;
1709
+ });
1710
+ sendJson(response, 200, { path, metadata: nextMetadata });
1579
1711
  }
1580
1712
  catch (error) {
1581
1713
  sendJson(response, 400, { error: errorText(error) });
@@ -1612,22 +1744,22 @@ export default {
1612
1744
  sendJson(response, 409, { error: "Cannot batch-delete the active session" });
1613
1745
  return;
1614
1746
  }
1615
- const metadata = await readSessionMetadata(manager);
1616
- for (const path of paths) {
1617
- if (action === "delete") {
1618
- await unlink(path);
1619
- delete metadata[path];
1620
- }
1621
- else {
1622
- const current = metadata[path] ?? {};
1623
- metadata[path] = {
1624
- ...current,
1625
- ...(action === "archive" || action === "unarchive" ? { archived: action === "archive" } : {}),
1626
- ...(action === "pin" || action === "unpin" ? { pinned: action === "pin" } : {}),
1627
- };
1747
+ await mutateSessionMetadata(manager, context.logger, async (metadata) => {
1748
+ for (const path of paths) {
1749
+ if (action === "delete") {
1750
+ await unlink(path);
1751
+ delete metadata[path];
1752
+ }
1753
+ else {
1754
+ const current = metadata[path] ?? {};
1755
+ metadata[path] = {
1756
+ ...current,
1757
+ ...(action === "archive" || action === "unarchive" ? { archived: action === "archive" } : {}),
1758
+ ...(action === "pin" || action === "unpin" ? { pinned: action === "pin" } : {}),
1759
+ };
1760
+ }
1628
1761
  }
1629
- }
1630
- await writeSessionMetadata(manager, metadata);
1762
+ });
1631
1763
  sendJson(response, 200, { action, count: paths.length });
1632
1764
  }
1633
1765
  catch (error) {
@@ -1677,11 +1809,16 @@ export default {
1677
1809
  return;
1678
1810
  }
1679
1811
  try {
1680
- const payload = JSON.parse(await bodyText(request));
1812
+ const payload = JSON.parse(await bodyText(request, IMPORT_BODY_LIMIT_BYTES));
1681
1813
  const suppliedPath = typeof payload.path === "string" ? payload.path : "";
1682
1814
  const content = typeof payload.content === "string" ? payload.content : undefined;
1683
- if ((!suppliedPath || !isAbsolute(suppliedPath)) && content === undefined) {
1684
- sendJson(response, 400, { error: "A JSONL file path or file content is required" });
1815
+ // `path` reads an existing file and `content` is written to a private temporary file; accepting both would let the request choose where the content lands.
1816
+ if (suppliedPath && content !== undefined) {
1817
+ sendJson(response, 400, { error: "Provide either a JSONL file path or file content, not both" });
1818
+ return;
1819
+ }
1820
+ if (content === undefined && (!suppliedPath || !isAbsolute(suppliedPath) || !suppliedPath.endsWith(".jsonl"))) {
1821
+ sendJson(response, 400, { error: "An absolute .jsonl file path or file content is required" });
1685
1822
  return;
1686
1823
  }
1687
1824
  const manager = services.runtime.session.sessionManager;
@@ -1691,11 +1828,12 @@ export default {
1691
1828
  }
1692
1829
  const targetCwd = typeof payload.cwd === "string" && payload.cwd.trim() ? resolve(payload.cwd) : activeCwd(services);
1693
1830
  const temporaryDirectory = content === undefined ? undefined : await mkdtemp(join(tmpdir(), "pi-harness-import-"));
1694
- const importPath = suppliedPath ||
1695
- join(temporaryDirectory, basename(typeof payload.filename === "string" && payload.filename.trim() ? payload.filename : "import.jsonl"));
1831
+ const requestedName = basename(typeof payload.filename === "string" && payload.filename.trim() ? payload.filename : "import.jsonl");
1832
+ const importName = requestedName === "" || requestedName === "." || requestedName === ".." ? "import.jsonl" : requestedName;
1833
+ const importPath = temporaryDirectory === undefined ? suppliedPath : join(temporaryDirectory, importName);
1696
1834
  try {
1697
1835
  if (content !== undefined) {
1698
- if (Buffer.byteLength(content, "utf8") > 10 * 1024 * 1024) {
1836
+ if (Buffer.byteLength(content, "utf8") > IMPORT_CONTENT_LIMIT_BYTES) {
1699
1837
  sendJson(response, 413, { error: "Imported session must be at most 10 MiB" });
1700
1838
  return;
1701
1839
  }
@@ -1723,7 +1861,7 @@ export default {
1723
1861
  }
1724
1862
  }
1725
1863
  catch (error) {
1726
- sendJson(response, 400, { error: errorText(error) });
1864
+ sendJson(response, error instanceof PayloadTooLargeError ? 413 : 400, { error: errorText(error) });
1727
1865
  }
1728
1866
  },
1729
1867
  });
@@ -1761,7 +1899,7 @@ export default {
1761
1899
  const page = Math.max(0, Number.parseInt(url.searchParams.get("page") ?? "0", 10) || 0);
1762
1900
  const pageSize = Math.min(100, Math.max(1, Number.parseInt(url.searchParams.get("pageSize") ?? "50", 10) || 50));
1763
1901
  const includeArchived = url.searchParams.get("includeArchived") === "true";
1764
- const metadata = await readSessionMetadata(manager);
1902
+ const metadata = await readSessionMetadata(manager, context.logger);
1765
1903
  const items = typeof manager.isPersisted === "function" && manager.isPersisted() ? await SessionManager.list(services.launch.cwd, manager.getSessionDir()) : [];
1766
1904
  const filtered = items.filter((item) => includeArchived || metadata[item.path]?.archived !== true);
1767
1905
  const sorted = filtered.sort((a, b) => Number(metadata[b.path]?.pinned === true) - Number(metadata[a.path]?.pinned === true) || b.modified.getTime() - a.modified.getTime());