@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,11 +1,12 @@
1
- import { execFile } from "node:child_process";
2
- import { mkdir, mkdtemp, readFile, rm, stat, unlink, writeFile } from "node:fs/promises";
1
+ import { execFile, type ExecFileException } from "node:child_process";
2
+ import { mkdir, mkdtemp, readFile, rename, rm, stat, unlink, writeFile } from "node:fs/promises";
3
3
  import type { IncomingMessage, ServerResponse } from "node:http";
4
- import { basename, isAbsolute, join, relative, resolve } from "node:path";
4
+ import { basename, isAbsolute, join, relative, resolve, sep } from "node:path";
5
5
  import { tmpdir } from "node:os";
6
6
  import type { Context } from "@deepseek-ai/cordis";
7
7
  import { SessionManager, type AgentSessionEvent, type ExtensionUIContext } from "@earendil-works/pi-coding-agent";
8
8
  import type Loader from "@deepseek-ai/cordis-plugin-loader";
9
+ import { atomicWriteFile } from "@pi-harness/core";
9
10
  import type { PiPluginUiRegistry, PiRuntimeService, PiModelsService, PiHarnessLaunch } from "@pi-harness/core";
10
11
  import type { WebServer } from "@pi-harness/host-webserver";
11
12
  import {
@@ -33,20 +34,35 @@ interface ApiServices {
33
34
 
34
35
  const loadMarketplaceStatistics = createMarketplaceStatisticsLoader();
35
36
 
37
+ const DEFAULT_BODY_LIMIT_BYTES = 64 * 1024;
38
+ const IMPORT_CONTENT_LIMIT_BYTES = 10 * 1024 * 1024;
39
+ // 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.
40
+ const IMPORT_BODY_LIMIT_BYTES = 16 * 1024 * 1024;
41
+ // Retained trajectory events are replayed to every SSE client and returned by /api/session, so the array must stay bounded.
42
+ const MAX_RETAINED_EVENTS = 2000;
43
+ const GIT_TIMEOUT_MS = 15_000;
44
+
45
+ class PayloadTooLargeError extends Error {
46
+ constructor() {
47
+ super("Request body is too large");
48
+ this.name = "PayloadTooLargeError";
49
+ }
50
+ }
51
+
36
52
  function sendJson(response: ServerResponse, status: number, payload: unknown): void {
37
53
  const body = JSON.stringify(payload);
38
54
  response.writeHead(status, { "content-type": "application/json; charset=utf-8", "cache-control": "no-store", "content-length": Buffer.byteLength(body) });
39
55
  response.end(body);
40
56
  }
41
57
 
42
- async function bodyText(request: IncomingMessage): Promise<string> {
58
+ async function bodyText(request: IncomingMessage, maxBytes = DEFAULT_BODY_LIMIT_BYTES): Promise<string> {
43
59
  const chunks: string[] = [];
44
60
  let length = 0;
45
61
  for await (const chunk of request) {
46
62
  const input: string | Uint8Array = chunk as string | Uint8Array;
47
63
  const value = typeof input === "string" ? input : Buffer.from(input).toString("utf8");
48
64
  length += Buffer.byteLength(value);
49
- if (length > 64 * 1024) throw new Error("Request body is too large");
65
+ if (length > maxBytes) throw new PayloadTooLargeError();
50
66
  chunks.push(value);
51
67
  }
52
68
  return chunks.join("");
@@ -139,26 +155,67 @@ function sessionMetadataFile(manager: SessionManager): string {
139
155
  return resolve(manager.getSessionDir(), ".pi-harness-session-meta.json");
140
156
  }
141
157
 
142
- async function readSessionMetadata(manager: SessionManager): Promise<SessionMetadataMap> {
158
+ interface MetadataLogger {
159
+ warn(message: string): void;
160
+ }
161
+
162
+ // 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.
163
+ async function readSessionMetadata(manager: SessionManager, logger: MetadataLogger): Promise<SessionMetadataMap> {
164
+ const file = sessionMetadataFile(manager);
165
+ let raw: string;
166
+ try {
167
+ raw = await readFile(file, "utf8");
168
+ } catch (error) {
169
+ if ((error as NodeJS.ErrnoException).code === "ENOENT") return {};
170
+ await quarantineSessionMetadata(file, logger, error);
171
+ return {};
172
+ }
143
173
  try {
144
- const parsed: unknown = JSON.parse(await readFile(sessionMetadataFile(manager), "utf8"));
145
- if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) return {};
174
+ const parsed: unknown = JSON.parse(raw);
175
+ if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) throw new Error("session metadata must be a JSON object");
146
176
  return parsed as SessionMetadataMap;
147
- } catch {
177
+ } catch (error) {
178
+ await quarantineSessionMetadata(file, logger, error);
148
179
  return {};
149
180
  }
150
181
  }
151
182
 
183
+ async function quarantineSessionMetadata(file: string, logger: MetadataLogger, error: unknown): Promise<void> {
184
+ const quarantined = `${file}.corrupt-${Date.now()}`;
185
+ try {
186
+ await rename(file, quarantined);
187
+ logger.warn(`Session metadata at ${file} is unreadable (${errorText(error)}); moved it to ${quarantined} and starting from an empty map`);
188
+ } catch (renameError) {
189
+ logger.warn(`Session metadata at ${file} is unreadable (${errorText(error)}) and could not be quarantined: ${errorText(renameError)}`);
190
+ }
191
+ }
192
+
152
193
  async function writeSessionMetadata(manager: SessionManager, metadata: SessionMetadataMap): Promise<void> {
153
194
  await mkdir(manager.getSessionDir(), { recursive: true });
154
- await writeFile(sessionMetadataFile(manager), JSON.stringify(metadata, null, 2) + "\n", "utf8");
195
+ await atomicWriteFile(sessionMetadataFile(manager), JSON.stringify(metadata, null, 2) + "\n", { encoding: "utf8" });
196
+ }
197
+
198
+ // Every read-modify-write of the metadata file runs through this chain so concurrent requests cannot interleave and drop each other's updates.
199
+ let sessionMetadataQueue: Promise<unknown> = Promise.resolve();
200
+
201
+ function mutateSessionMetadata<T>(manager: SessionManager, logger: MetadataLogger, mutate: (metadata: SessionMetadataMap) => Promise<T> | T): Promise<T> {
202
+ const operation = sessionMetadataQueue
203
+ .catch(() => undefined)
204
+ .then(async () => {
205
+ const metadata = await readSessionMetadata(manager, logger);
206
+ const result = await mutate(metadata);
207
+ await writeSessionMetadata(manager, metadata);
208
+ return result;
209
+ });
210
+ sessionMetadataQueue = operation;
211
+ return operation;
155
212
  }
156
213
 
157
214
  function sessionPathInDirectory(path: string, manager: SessionManager): boolean {
158
215
  const root = resolve(manager.getSessionDir());
159
216
  const target = resolve(path);
160
217
  const relativePath = relative(root, target);
161
- return relativePath !== "" && !isAbsolute(relativePath) && relativePath !== ".." && !relativePath.startsWith(".." + "/") && target.endsWith(".jsonl");
218
+ return relativePath !== "" && !isAbsolute(relativePath) && relativePath !== ".." && !relativePath.startsWith(".." + sep) && target.endsWith(".jsonl");
162
219
  }
163
220
 
164
221
  const webSessionUi = {
@@ -452,25 +509,69 @@ function writeSse(response: ServerResponse, payload: unknown): void {
452
509
  response.write(`data: ${JSON.stringify(jsonSafe(payload))}\n\n`);
453
510
  }
454
511
 
455
- function gitStatus(cwd: string): Promise<string> {
456
- return new Promise((resolve) => {
457
- execFile("git", ["status", "--short", "--untracked-files=all"], { cwd, maxBuffer: 512 * 1024 }, (error, stdout) => resolve(error ? "" : stdout));
512
+ type GitTermination = "timeout" | "output-limit";
513
+
514
+ // 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.
515
+ function gitTermination(error: ExecFileException | null): GitTermination | undefined {
516
+ if (error === null) return undefined;
517
+ if (error.code === "ERR_CHILD_PROCESS_STDIO_MAXBUFFER") return "output-limit";
518
+ if (error.killed === true) return "timeout";
519
+ return undefined;
520
+ }
521
+
522
+ function gitTerminationMessage(command: string, termination: GitTermination): string {
523
+ return termination === "timeout"
524
+ ? `git ${command} timed out after ${GIT_TIMEOUT_MS / 1000} seconds`
525
+ : `git ${command} produced more output than the buffer limit allows`;
526
+ }
527
+
528
+ interface GitStatusResult {
529
+ readonly output: string;
530
+ readonly truncated: boolean;
531
+ }
532
+
533
+ function gitStatus(cwd: string): Promise<GitStatusResult> {
534
+ return new Promise((resolveStatus, rejectStatus) => {
535
+ execFile("git", ["status", "--short", "--untracked-files=all"], { cwd, timeout: GIT_TIMEOUT_MS, maxBuffer: 512 * 1024 }, (error, stdout, stderr) => {
536
+ if (error === null) {
537
+ resolveStatus({ output: stdout, truncated: false });
538
+ return;
539
+ }
540
+ const termination = gitTermination(error);
541
+ if (termination === "output-limit") {
542
+ // Keep the complete lines that arrived before the kill; the final line may have been cut mid-path.
543
+ resolveStatus({ output: stdout.slice(0, stdout.lastIndexOf("\n") + 1), truncated: true });
544
+ return;
545
+ }
546
+ if (termination === undefined && error.code === 128 && /not a git repository/i.test(stderr)) {
547
+ resolveStatus({ output: "", truncated: false });
548
+ return;
549
+ }
550
+ rejectStatus(new Error(termination ? gitTerminationMessage("status", termination) : stderr.trim() || error.message, { cause: error }));
551
+ });
458
552
  });
459
553
  }
460
554
 
461
555
  function gitDiff(cwd: string, path: string): Promise<string> {
462
556
  return new Promise((resolveOutput) => {
463
- execFile("git", ["diff", "--no-ext-diff", "--", path], { cwd, maxBuffer: 1024 * 1024 }, (error, stdout) =>
557
+ execFile("git", ["diff", "--no-ext-diff", "--", path], { cwd, timeout: GIT_TIMEOUT_MS, maxBuffer: 1024 * 1024 }, (error, stdout) =>
464
558
  resolveOutput(error && stdout.length === 0 ? "" : stdout),
465
559
  );
466
560
  });
467
561
  }
468
562
 
469
- function gitCommand(cwd: string, args: readonly string[]): Promise<{ stdout: string; stderr: string; code: number }> {
563
+ interface GitCommandResult {
564
+ readonly stdout: string;
565
+ readonly stderr: string;
566
+ readonly code: number;
567
+ readonly terminated: GitTermination | undefined;
568
+ }
569
+
570
+ function gitCommand(cwd: string, args: readonly string[]): Promise<GitCommandResult> {
470
571
  return new Promise((resolveResult) => {
471
- execFile("git", [...args], { cwd, maxBuffer: 2 * 1024 * 1024 }, (error, stdout, stderr) => {
572
+ execFile("git", [...args], { cwd, timeout: GIT_TIMEOUT_MS, maxBuffer: 2 * 1024 * 1024 }, (error, stdout, stderr) => {
472
573
  const code = error && typeof error.code === "number" ? error.code : error ? 1 : 0;
473
- resolveResult({ stdout, stderr, code });
574
+ resolveResult({ stdout, stderr, code, terminated: gitTermination(error) });
474
575
  });
475
576
  });
476
577
  }
@@ -559,7 +660,11 @@ export default {
559
660
  const events: AgentSessionEvent[] = [];
560
661
  const eventClients = new Set<ServerResponse>();
561
662
  const handleEvent = (event: AgentSessionEvent) => {
562
- events.push(event);
663
+ // Streaming deltas reach clients live over SSE and each one carries the whole partial message, so only durable events are retained for snapshots.
664
+ if (event.type !== "message_update") {
665
+ events.push(event);
666
+ if (events.length > MAX_RETAINED_EVENTS) events.splice(0, events.length - MAX_RETAINED_EVENTS);
667
+ }
563
668
  for (const response of eventClients) {
564
669
  if (response.writableEnded || response.destroyed) {
565
670
  eventClients.delete(response);
@@ -686,7 +791,12 @@ export default {
686
791
  return;
687
792
  }
688
793
  const path = join(services.launch.agentDir, "settings.json");
689
- await writeFile(path, JSON.stringify(parsed, null, 2) + "\n", "utf8");
794
+ // Replace the file atomically so an interrupted write never leaves a truncated settings.json behind; keep the existing permission bits.
795
+ const mode = await stat(path).then(
796
+ (info) => info.mode & 0o777,
797
+ () => 0o644,
798
+ );
799
+ await atomicWriteFile(path, JSON.stringify(parsed, null, 2) + "\n", { encoding: "utf8", mode });
690
800
  await services.runtime.session.settingsManager.reload();
691
801
  sendJson(response, 200, piConfig(services));
692
802
  } catch (error) {
@@ -1192,8 +1302,14 @@ export default {
1192
1302
  const disposeFiles = services.webServer.register({
1193
1303
  path: "/api/files",
1194
1304
  async handler(_request, response) {
1195
- const output = await gitStatus(activeCwd(services));
1196
- const items = output
1305
+ let status: GitStatusResult;
1306
+ try {
1307
+ status = await gitStatus(activeCwd(services));
1308
+ } catch (error) {
1309
+ sendJson(response, 500, { error: errorText(error) });
1310
+ return;
1311
+ }
1312
+ const items = status.output
1197
1313
  .split("\n")
1198
1314
  .map((line) => line.trimEnd())
1199
1315
  .filter((line) => line.length > 0)
@@ -1205,7 +1321,7 @@ export default {
1205
1321
  label: status === "??" ? "untracked" : status.includes("D") ? "deleted" : status.includes("A") ? "added" : "modified",
1206
1322
  };
1207
1323
  });
1208
- sendJson(response, 200, { items });
1324
+ sendJson(response, 200, { items, ...(status.truncated ? { truncated: true } : {}) });
1209
1325
  },
1210
1326
  });
1211
1327
  const disposeFileDiff = services.webServer.register({
@@ -1224,7 +1340,7 @@ export default {
1224
1340
  const root = resolve(activeCwd(services));
1225
1341
  const absolute = resolve(root, requested);
1226
1342
  const relativePath = relative(root, absolute);
1227
- if (isAbsolute(relativePath) || relativePath === ".." || relativePath.startsWith(".." + "/")) {
1343
+ if (isAbsolute(relativePath) || relativePath === ".." || relativePath.startsWith(".." + sep)) {
1228
1344
  sendJson(response, 400, { error: "path must stay inside the workspace" });
1229
1345
  return;
1230
1346
  }
@@ -1251,11 +1367,19 @@ export default {
1251
1367
  }
1252
1368
  const root = resolve(activeCwd(services));
1253
1369
  const add = await gitCommand(root, ["add", "-A", "--", ...paths]);
1370
+ if (add.terminated) {
1371
+ sendJson(response, 500, { error: gitTerminationMessage("add", add.terminated) });
1372
+ return;
1373
+ }
1254
1374
  if (add.code !== 0) {
1255
1375
  sendJson(response, 409, { error: add.stderr.trim() || "Unable to stage workspace files" });
1256
1376
  return;
1257
1377
  }
1258
1378
  const commit = await gitCommand(root, ["commit", "-m", payload.message.trim(), "--", ...paths]);
1379
+ if (commit.terminated) {
1380
+ sendJson(response, 500, { error: gitTerminationMessage("commit", commit.terminated) });
1381
+ return;
1382
+ }
1259
1383
  if (commit.code !== 0) {
1260
1384
  sendJson(response, 409, { error: commit.stdout.trim() || commit.stderr.trim() || "Nothing to commit" });
1261
1385
  return;
@@ -1286,16 +1410,36 @@ export default {
1286
1410
  sendJson(response, 400, { error: paths.message });
1287
1411
  return;
1288
1412
  }
1289
- const untracked = await gitCommand(root, ["ls-files", "--others", "--exclude-standard", "--", ...paths]);
1290
- const restore = await gitCommand(root, ["restore", "--worktree", "--staged", "--", ...paths]);
1291
- if (restore.code !== 0 && !restore.stderr.includes("pathspec")) {
1292
- sendJson(response, 409, { error: restore.stderr.trim() || "Unable to restore workspace files" });
1413
+ const untracked = await gitCommand(root, ["ls-files", "-z", "--others", "--exclude-standard", "--", ...paths]);
1414
+ // `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.
1415
+ let tracked = await gitCommand(root, ["ls-files", "-z", "--with-tree=HEAD", "--", ...paths]);
1416
+ if (tracked.code !== 0 && tracked.terminated === undefined) tracked = await gitCommand(root, ["ls-files", "-z", "--", ...paths]);
1417
+ const listing = [untracked, tracked].find((result) => result.terminated !== undefined || result.code !== 0);
1418
+ if (listing) {
1419
+ if (listing.terminated) sendJson(response, 500, { error: gitTerminationMessage("ls-files", listing.terminated) });
1420
+ else sendJson(response, 409, { error: listing.stderr.trim() || "Unable to inspect workspace files" });
1421
+ return;
1422
+ }
1423
+ const untrackedPaths = untracked.stdout.split("\0").filter(Boolean);
1424
+ const trackedPaths = tracked.stdout.split("\0").filter(Boolean);
1425
+ const known = [...untrackedPaths, ...trackedPaths];
1426
+ const unknown = paths.filter((path) => !known.some((candidate) => candidate === path || candidate.startsWith(path + "/")));
1427
+ if (unknown.length > 0) {
1428
+ sendJson(response, 409, { error: `Paths did not match any file known to git: ${unknown.join(", ")}` });
1293
1429
  return;
1294
1430
  }
1295
- for (const path of untracked.stdout
1296
- .split("\n")
1297
- .map((item) => item.trim())
1298
- .filter(Boolean)) {
1431
+ if (trackedPaths.length > 0) {
1432
+ const restore = await gitCommand(root, ["restore", "--worktree", "--staged", "--", ...trackedPaths]);
1433
+ if (restore.terminated) {
1434
+ sendJson(response, 500, { error: gitTerminationMessage("restore", restore.terminated) });
1435
+ return;
1436
+ }
1437
+ if (restore.code !== 0) {
1438
+ sendJson(response, 409, { error: restore.stderr.trim() || "Unable to restore workspace files" });
1439
+ return;
1440
+ }
1441
+ }
1442
+ for (const path of untrackedPaths) {
1299
1443
  await rm(resolve(root, path), { recursive: true, force: true });
1300
1444
  }
1301
1445
  sendJson(response, 200, { reverted: true, paths });
@@ -1332,6 +1476,10 @@ export default {
1332
1476
  const disposePrompt = services.webServer.register({
1333
1477
  path: "/api/prompt",
1334
1478
  async handler(request, response) {
1479
+ if (request.method !== "POST") {
1480
+ sendJson(response, 405, { error: "Method not allowed" });
1481
+ return;
1482
+ }
1335
1483
  if (busy) {
1336
1484
  sendJson(response, 409, { error: "Another prompt is already running" });
1337
1485
  return;
@@ -1583,9 +1731,9 @@ export default {
1583
1731
  events.length = 0;
1584
1732
  }
1585
1733
  await unlink(path);
1586
- const metadata = await readSessionMetadata(manager);
1587
- delete metadata[path];
1588
- await writeSessionMetadata(manager, metadata);
1734
+ await mutateSessionMetadata(manager, context.logger, (metadata) => {
1735
+ delete metadata[path];
1736
+ });
1589
1737
  sendJson(response, 200, { deleted: true, path, sessionFile: services.runtime.session.sessionFile });
1590
1738
  } catch (error) {
1591
1739
  sendJson(response, 400, { error: errorText(error) });
@@ -1607,16 +1755,17 @@ export default {
1607
1755
  sendJson(response, 400, { error: "Invalid session path" });
1608
1756
  return;
1609
1757
  }
1610
- const metadata = await readSessionMetadata(manager);
1611
- const currentMetadata = metadata[path] ?? {};
1612
- const nextMetadata: SessionMetadata = {
1613
- ...currentMetadata,
1614
- ...(payload.archived === undefined ? {} : { archived: payload.archived === true }),
1615
- ...(payload.pinned === undefined ? {} : { pinned: payload.pinned === true }),
1616
- };
1617
- metadata[path] = nextMetadata;
1618
- await writeSessionMetadata(manager, metadata);
1619
- sendJson(response, 200, { path, metadata: metadata[path] });
1758
+ const nextMetadata = await mutateSessionMetadata(manager, context.logger, (metadata) => {
1759
+ const currentMetadata = metadata[path] ?? {};
1760
+ const updated: SessionMetadata = {
1761
+ ...currentMetadata,
1762
+ ...(payload.archived === undefined ? {} : { archived: payload.archived === true }),
1763
+ ...(payload.pinned === undefined ? {} : { pinned: payload.pinned === true }),
1764
+ };
1765
+ metadata[path] = updated;
1766
+ return updated;
1767
+ });
1768
+ sendJson(response, 200, { path, metadata: nextMetadata });
1620
1769
  } catch (error) {
1621
1770
  sendJson(response, 400, { error: errorText(error) });
1622
1771
  }
@@ -1654,21 +1803,21 @@ export default {
1654
1803
  sendJson(response, 409, { error: "Cannot batch-delete the active session" });
1655
1804
  return;
1656
1805
  }
1657
- const metadata = await readSessionMetadata(manager);
1658
- for (const path of paths) {
1659
- if (action === "delete") {
1660
- await unlink(path);
1661
- delete metadata[path];
1662
- } else {
1663
- const current = metadata[path] ?? {};
1664
- metadata[path] = {
1665
- ...current,
1666
- ...(action === "archive" || action === "unarchive" ? { archived: action === "archive" } : {}),
1667
- ...(action === "pin" || action === "unpin" ? { pinned: action === "pin" } : {}),
1668
- };
1806
+ await mutateSessionMetadata(manager, context.logger, async (metadata) => {
1807
+ for (const path of paths) {
1808
+ if (action === "delete") {
1809
+ await unlink(path);
1810
+ delete metadata[path];
1811
+ } else {
1812
+ const current = metadata[path] ?? {};
1813
+ metadata[path] = {
1814
+ ...current,
1815
+ ...(action === "archive" || action === "unarchive" ? { archived: action === "archive" } : {}),
1816
+ ...(action === "pin" || action === "unpin" ? { pinned: action === "pin" } : {}),
1817
+ };
1818
+ }
1669
1819
  }
1670
- }
1671
- await writeSessionMetadata(manager, metadata);
1820
+ });
1672
1821
  sendJson(response, 200, { action, count: paths.length });
1673
1822
  } catch (error) {
1674
1823
  sendJson(response, 400, { error: errorText(error) });
@@ -1716,11 +1865,21 @@ export default {
1716
1865
  return;
1717
1866
  }
1718
1867
  try {
1719
- const payload = JSON.parse(await bodyText(request)) as { path?: unknown; content?: unknown; filename?: unknown; cwd?: unknown };
1868
+ const payload = JSON.parse(await bodyText(request, IMPORT_BODY_LIMIT_BYTES)) as {
1869
+ path?: unknown;
1870
+ content?: unknown;
1871
+ filename?: unknown;
1872
+ cwd?: unknown;
1873
+ };
1720
1874
  const suppliedPath = typeof payload.path === "string" ? payload.path : "";
1721
1875
  const content = typeof payload.content === "string" ? payload.content : undefined;
1722
- if ((!suppliedPath || !isAbsolute(suppliedPath)) && content === undefined) {
1723
- sendJson(response, 400, { error: "A JSONL file path or file content is required" });
1876
+ // `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.
1877
+ if (suppliedPath && content !== undefined) {
1878
+ sendJson(response, 400, { error: "Provide either a JSONL file path or file content, not both" });
1879
+ return;
1880
+ }
1881
+ if (content === undefined && (!suppliedPath || !isAbsolute(suppliedPath) || !suppliedPath.endsWith(".jsonl"))) {
1882
+ sendJson(response, 400, { error: "An absolute .jsonl file path or file content is required" });
1724
1883
  return;
1725
1884
  }
1726
1885
  const manager = services.runtime.session.sessionManager;
@@ -1730,12 +1889,12 @@ export default {
1730
1889
  }
1731
1890
  const targetCwd = typeof payload.cwd === "string" && payload.cwd.trim() ? resolve(payload.cwd) : activeCwd(services);
1732
1891
  const temporaryDirectory = content === undefined ? undefined : await mkdtemp(join(tmpdir(), "pi-harness-import-"));
1733
- const importPath =
1734
- suppliedPath ||
1735
- join(temporaryDirectory as string, basename(typeof payload.filename === "string" && payload.filename.trim() ? payload.filename : "import.jsonl"));
1892
+ const requestedName = basename(typeof payload.filename === "string" && payload.filename.trim() ? payload.filename : "import.jsonl");
1893
+ const importName = requestedName === "" || requestedName === "." || requestedName === ".." ? "import.jsonl" : requestedName;
1894
+ const importPath = temporaryDirectory === undefined ? suppliedPath : join(temporaryDirectory, importName);
1736
1895
  try {
1737
1896
  if (content !== undefined) {
1738
- if (Buffer.byteLength(content, "utf8") > 10 * 1024 * 1024) {
1897
+ if (Buffer.byteLength(content, "utf8") > IMPORT_CONTENT_LIMIT_BYTES) {
1739
1898
  sendJson(response, 413, { error: "Imported session must be at most 10 MiB" });
1740
1899
  return;
1741
1900
  }
@@ -1759,7 +1918,7 @@ export default {
1759
1918
  if (temporaryDirectory) await rm(temporaryDirectory, { recursive: true, force: true });
1760
1919
  }
1761
1920
  } catch (error) {
1762
- sendJson(response, 400, { error: errorText(error) });
1921
+ sendJson(response, error instanceof PayloadTooLargeError ? 413 : 400, { error: errorText(error) });
1763
1922
  }
1764
1923
  },
1765
1924
  });
@@ -1796,7 +1955,7 @@ export default {
1796
1955
  const page = Math.max(0, Number.parseInt(url.searchParams.get("page") ?? "0", 10) || 0);
1797
1956
  const pageSize = Math.min(100, Math.max(1, Number.parseInt(url.searchParams.get("pageSize") ?? "50", 10) || 50));
1798
1957
  const includeArchived = url.searchParams.get("includeArchived") === "true";
1799
- const metadata = await readSessionMetadata(manager);
1958
+ const metadata = await readSessionMetadata(manager, context.logger);
1800
1959
  const items =
1801
1960
  typeof manager.isPersisted === "function" && manager.isPersisted() ? await SessionManager.list(services.launch.cwd, manager.getSessionDir()) : [];
1802
1961
  const filtered = items.filter((item) => includeArchived || metadata[item.path]?.archived !== true);
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "id": "agent-teams",
3
3
  "packageName": "@pi-harness/core/plugins/agent-teams",
4
- "version": "0.1.21",
4
+ "version": "0.1.23",
5
5
  "name": "Agent Team Board",
6
6
  "description": "Maintain a bounded, session-local collaboration ledger of named roles, dependency-aware tasks, and mailbox notes without spawning agents or sending external messages.",
7
7
  "author": "Pi Harness",
@@ -13,17 +13,8 @@
13
13
  "id": "collaboration",
14
14
  "label": "会话协作"
15
15
  },
16
- "capabilities": [
17
- "collaboration ledger",
18
- "tasks",
19
- "mailbox notes",
20
- "dependency graph",
21
- "cycle detection"
22
- ],
23
- "hooks": [
24
- "session lifecycle",
25
- "plugin UI"
26
- ],
16
+ "capabilities": ["collaboration ledger", "tasks", "mailbox notes", "dependency graph", "cycle detection"],
17
+ "hooks": ["session lifecycle", "plugin UI"],
27
18
  "profile": {
28
19
  "name": "@pi-harness/core/plugins/agent-teams",
29
20
  "config": {}
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "id": "anchored-standard",
3
3
  "packageName": "@pi-harness/core/plugins/anchored-standard",
4
- "version": "0.1.21",
4
+ "version": "0.1.23",
5
5
  "name": "Anchored Standard",
6
6
  "description": "Audit agent trajectories against an explicit tool-call allowlist and flag activity outside the anchored run.",
7
7
  "author": "Pi Harness",
@@ -13,15 +13,8 @@
13
13
  "id": "security",
14
14
  "label": "安全"
15
15
  },
16
- "capabilities": [
17
- "trajectory audit",
18
- "tool allowlist",
19
- "run anchoring"
20
- ],
21
- "hooks": [
22
- "session events",
23
- "plugin UI"
24
- ],
16
+ "capabilities": ["trajectory audit", "tool allowlist", "run anchoring"],
17
+ "hooks": ["session events", "plugin UI"],
25
18
  "profile": {
26
19
  "name": "@pi-harness/core/plugins/anchored-standard",
27
20
  "config": {}
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "id": "annotation",
3
3
  "packageName": "@pi-harness/core/plugins/annotation",
4
- "version": "0.1.21",
4
+ "version": "0.1.23",
5
5
  "name": "Annotations",
6
6
  "description": "Capture bounded selections and notes from the conversation for later agent context.",
7
7
  "author": "Pi Harness",
@@ -13,13 +13,8 @@
13
13
  "id": "context",
14
14
  "label": "上下文管理"
15
15
  },
16
- "capabilities": [
17
- "annotations",
18
- "context"
19
- ],
20
- "hooks": [
21
- "plugin UI"
22
- ],
16
+ "capabilities": ["annotations", "context"],
17
+ "hooks": ["plugin UI"],
23
18
  "profile": {
24
19
  "name": "@pi-harness/core/plugins/annotation",
25
20
  "config": {}
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "id": "archify",
3
3
  "packageName": "@pi-harness/core/plugins/archify",
4
- "version": "0.1.21",
4
+ "version": "0.1.23",
5
5
  "name": "Architecture Map",
6
6
  "description": "Build a bounded, read-only architecture map from workspace components and package dependencies.",
7
7
  "author": "Pi Harness",
@@ -13,17 +13,8 @@
13
13
  "id": "developer",
14
14
  "label": "开发工具"
15
15
  },
16
- "capabilities": [
17
- "architecture map",
18
- "workspace scan",
19
- "dependency map",
20
- "Mermaid"
21
- ],
22
- "hooks": [
23
- "workspace files",
24
- "package manifest",
25
- "plugin UI"
26
- ],
16
+ "capabilities": ["architecture map", "workspace scan", "dependency map", "Mermaid"],
17
+ "hooks": ["workspace files", "package manifest", "plugin UI"],
27
18
  "profile": {
28
19
  "name": "@pi-harness/core/plugins/archify",
29
20
  "config": {}
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "id": "at-file",
3
3
  "packageName": "@pi-harness/core/plugins/at-file",
4
- "version": "0.1.21",
4
+ "version": "0.1.23",
5
5
  "name": "@file Context",
6
6
  "description": "Attach a bounded 256 KiB strict UTF-8 workspace file using canonical workspace path confinement and no-follow regular-file reads, framing it as offline, read-only, untrusted model context with closing-tag neutralization and cancellable sequential execution.",
7
7
  "author": "Pi Harness",
@@ -22,11 +22,7 @@
22
22
  "cancellable sequential execution",
23
23
  "descriptor-safe normalized panel"
24
24
  ],
25
- "hooks": [
26
- "file context tool",
27
- "workspace file read",
28
- "plugin UI"
29
- ],
25
+ "hooks": ["file context tool", "workspace file read", "plugin UI"],
30
26
  "profile": {
31
27
  "name": "@pi-harness/core/plugins/at-file",
32
28
  "config": {}
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "id": "auto-mode",
3
3
  "packageName": "@pi-harness/core/plugins/auto-mode",
4
- "version": "0.1.21",
4
+ "version": "0.1.23",
5
5
  "name": "Auto Mode",
6
6
  "description": "Execute argv commands under a safe policy that blocks shell wrappers and requires confirmation for risky operations.",
7
7
  "author": "Pi Harness",
@@ -13,15 +13,8 @@
13
13
  "id": "security",
14
14
  "label": "安全"
15
15
  },
16
- "capabilities": [
17
- "command policy",
18
- "confirmation gate",
19
- "safe execution"
20
- ],
21
- "hooks": [
22
- "argv execution",
23
- "plugin UI"
24
- ],
16
+ "capabilities": ["command policy", "confirmation gate", "safe execution"],
17
+ "hooks": ["argv execution", "plugin UI"],
25
18
  "profile": {
26
19
  "name": "@pi-harness/core/plugins/auto-mode",
27
20
  "config": {