@pi-harness/pi-harness 0.1.13 → 0.1.14

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 (1333) hide show
  1. package/README.md +678 -2
  2. package/apps/web/dist/assets/index-BVI_IS-R.css +2 -0
  3. package/apps/web/dist/assets/index-C98SJjJd.js +22 -0
  4. package/apps/web/dist/index.html +2 -2
  5. package/apps/web/package.json +6 -6
  6. package/node_modules/@pi-harness/api-gateway/dist/index.d.ts.map +1 -1
  7. package/node_modules/@pi-harness/api-gateway/dist/index.js +97 -9
  8. package/node_modules/@pi-harness/api-gateway/dist/index.js.map +1 -1
  9. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/agent-teams.json +6 -6
  10. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/anchored-standard.json +1 -1
  11. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/annotation.json +1 -2
  12. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/archify.json +1 -1
  13. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/at-file.json +11 -5
  14. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/auto-mode.json +1 -1
  15. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/better-sidebar.json +1 -1
  16. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/browser-fetch.json +12 -5
  17. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/browser-session.json +14 -8
  18. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/canvas-draw.json +3 -4
  19. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/change-verifier.json +1 -1
  20. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/cleaner.json +11 -6
  21. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/cli-notifier.json +5 -5
  22. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/code2skill.json +5 -5
  23. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/colleague-skill.json +1 -2
  24. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/context-doctor.json +12 -7
  25. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/context.json +10 -5
  26. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/cordis-group.json +2 -2
  27. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/cordis-logger-console.json +4 -4
  28. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/cordis-timer.json +3 -3
  29. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/cost-meter.json +9 -6
  30. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/dependency-checker.json +13 -10
  31. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/docker-sandbox.json +10 -5
  32. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/fail-logger.json +11 -6
  33. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/genui.json +7 -5
  34. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/git-time-capsule.json +13 -8
  35. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/graph-memory.json +13 -7
  36. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/history-compressor.json +1 -1
  37. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/hol-guard.json +1 -1
  38. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/i18n-pair.json +9 -6
  39. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/image-compressor.json +1 -1
  40. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/llm-verifier.json +1 -1
  41. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/mcp-client.json +12 -7
  42. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/mcp-panel.json +1 -1
  43. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/memory.json +1 -1
  44. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/mirage-bridge.json +1 -1
  45. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/mock-server.json +1 -1
  46. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/modlens.json +4 -4
  47. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/module-search.json +1 -1
  48. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/obsidian-sync.json +1 -1
  49. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/openpets.json +9 -5
  50. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/plan-execute.json +1 -1
  51. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/plugin-check.json +1 -1
  52. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/plugin-dev.json +8 -6
  53. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/plugin-finder.json +1 -1
  54. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/plugin-radar.json +1 -1
  55. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/plugin-stars.json +15 -7
  56. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/prompt-guard.json +1 -1
  57. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/prompt-library.json +1 -1
  58. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/readme-gen.json +12 -8
  59. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/recall-unread.json +11 -6
  60. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/reverse-skill.json +1 -1
  61. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/reviewer-bot.json +1 -1
  62. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/runtime-doctor.json +1 -1
  63. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/secure-audit.json +1 -1
  64. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/session-bookmarks.json +1 -1
  65. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/session-bridge.json +13 -8
  66. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/session-compare.json +1 -1
  67. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/session-export.json +1 -1
  68. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/session-insights.json +12 -6
  69. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/session-search.json +1 -1
  70. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/skill-catalog.json +1 -1
  71. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/skill-guard.json +9 -5
  72. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/sql-lens.json +13 -7
  73. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/synapse.json +1 -1
  74. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/tab-manager.json +1 -1
  75. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/taskboard.json +1 -1
  76. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/telemetry-blocker.json +1 -1
  77. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/test-harness.json +14 -7
  78. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/theme-studio.json +1 -1
  79. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/token-guard.json +12 -6
  80. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/turn-rewind.json +11 -6
  81. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/undo-savepoint.json +1 -1
  82. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/vision-toolkit.json +8 -5
  83. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/web-research.json +1 -1
  84. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/workspace-navigator.json +1 -1
  85. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/workspace-search.json +1 -1
  86. package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/yaml-validator.json +8 -5
  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 +83 -20
  90. package/node_modules/@pi-harness/cli/dist/node-stdio.js.map +1 -1
  91. package/node_modules/@pi-harness/cli/package.json +1 -1
  92. package/node_modules/@pi-harness/core/dist/atomic-write.d.ts +8 -0
  93. package/node_modules/@pi-harness/core/dist/atomic-write.d.ts.map +1 -0
  94. package/node_modules/@pi-harness/core/dist/atomic-write.js +40 -0
  95. package/node_modules/@pi-harness/core/dist/atomic-write.js.map +1 -0
  96. package/node_modules/@pi-harness/core/dist/boot.d.ts.map +1 -1
  97. package/node_modules/@pi-harness/core/dist/boot.js +132 -10
  98. package/node_modules/@pi-harness/core/dist/boot.js.map +1 -1
  99. package/node_modules/@pi-harness/core/dist/bounded-file.d.ts +7 -0
  100. package/node_modules/@pi-harness/core/dist/bounded-file.d.ts.map +1 -0
  101. package/node_modules/@pi-harness/core/dist/bounded-file.js +50 -0
  102. package/node_modules/@pi-harness/core/dist/bounded-file.js.map +1 -0
  103. package/node_modules/@pi-harness/core/dist/config.d.ts +2 -0
  104. package/node_modules/@pi-harness/core/dist/config.d.ts.map +1 -1
  105. package/node_modules/@pi-harness/core/dist/config.js +21 -0
  106. package/node_modules/@pi-harness/core/dist/config.js.map +1 -1
  107. package/node_modules/@pi-harness/core/dist/cordis-timer.d.ts +15 -0
  108. package/node_modules/@pi-harness/core/dist/cordis-timer.d.ts.map +1 -0
  109. package/node_modules/@pi-harness/core/dist/cordis-timer.js +99 -0
  110. package/node_modules/@pi-harness/core/dist/cordis-timer.js.map +1 -0
  111. package/node_modules/@pi-harness/core/dist/plugins/agent-teams.d.ts +5 -1
  112. package/node_modules/@pi-harness/core/dist/plugins/agent-teams.d.ts.map +1 -1
  113. package/node_modules/@pi-harness/core/dist/plugins/agent-teams.js +986 -105
  114. package/node_modules/@pi-harness/core/dist/plugins/agent-teams.js.map +1 -1
  115. package/node_modules/@pi-harness/core/dist/plugins/anchored-standard.d.ts +1 -0
  116. package/node_modules/@pi-harness/core/dist/plugins/anchored-standard.d.ts.map +1 -1
  117. package/node_modules/@pi-harness/core/dist/plugins/anchored-standard.js +39 -11
  118. package/node_modules/@pi-harness/core/dist/plugins/anchored-standard.js.map +1 -1
  119. package/node_modules/@pi-harness/core/dist/plugins/annotation.d.ts +1 -0
  120. package/node_modules/@pi-harness/core/dist/plugins/annotation.d.ts.map +1 -1
  121. package/node_modules/@pi-harness/core/dist/plugins/annotation.js +35 -17
  122. package/node_modules/@pi-harness/core/dist/plugins/annotation.js.map +1 -1
  123. package/node_modules/@pi-harness/core/dist/plugins/archify.d.ts +1 -0
  124. package/node_modules/@pi-harness/core/dist/plugins/archify.d.ts.map +1 -1
  125. package/node_modules/@pi-harness/core/dist/plugins/archify.js +69 -22
  126. package/node_modules/@pi-harness/core/dist/plugins/archify.js.map +1 -1
  127. package/node_modules/@pi-harness/core/dist/plugins/at-file.d.ts +5 -1
  128. package/node_modules/@pi-harness/core/dist/plugins/at-file.d.ts.map +1 -1
  129. package/node_modules/@pi-harness/core/dist/plugins/at-file.js +120 -29
  130. package/node_modules/@pi-harness/core/dist/plugins/at-file.js.map +1 -1
  131. package/node_modules/@pi-harness/core/dist/plugins/auto-mode.d.ts.map +1 -1
  132. package/node_modules/@pi-harness/core/dist/plugins/auto-mode.js +89 -20
  133. package/node_modules/@pi-harness/core/dist/plugins/auto-mode.js.map +1 -1
  134. package/node_modules/@pi-harness/core/dist/plugins/better-sidebar.d.ts +1 -0
  135. package/node_modules/@pi-harness/core/dist/plugins/better-sidebar.d.ts.map +1 -1
  136. package/node_modules/@pi-harness/core/dist/plugins/better-sidebar.js +14 -4
  137. package/node_modules/@pi-harness/core/dist/plugins/better-sidebar.js.map +1 -1
  138. package/node_modules/@pi-harness/core/dist/plugins/browser-fetch.d.ts +1 -0
  139. package/node_modules/@pi-harness/core/dist/plugins/browser-fetch.d.ts.map +1 -1
  140. package/node_modules/@pi-harness/core/dist/plugins/browser-fetch.js +288 -96
  141. package/node_modules/@pi-harness/core/dist/plugins/browser-fetch.js.map +1 -1
  142. package/node_modules/@pi-harness/core/dist/plugins/browser-session.d.ts.map +1 -1
  143. package/node_modules/@pi-harness/core/dist/plugins/browser-session.js +445 -106
  144. package/node_modules/@pi-harness/core/dist/plugins/browser-session.js.map +1 -1
  145. package/node_modules/@pi-harness/core/dist/plugins/canvas-draw.d.ts +1 -0
  146. package/node_modules/@pi-harness/core/dist/plugins/canvas-draw.d.ts.map +1 -1
  147. package/node_modules/@pi-harness/core/dist/plugins/canvas-draw.js +71 -19
  148. package/node_modules/@pi-harness/core/dist/plugins/canvas-draw.js.map +1 -1
  149. package/node_modules/@pi-harness/core/dist/plugins/change-verifier.d.ts +1 -0
  150. package/node_modules/@pi-harness/core/dist/plugins/change-verifier.d.ts.map +1 -1
  151. package/node_modules/@pi-harness/core/dist/plugins/change-verifier.js +30 -9
  152. package/node_modules/@pi-harness/core/dist/plugins/change-verifier.js.map +1 -1
  153. package/node_modules/@pi-harness/core/dist/plugins/cleaner.d.ts +5 -1
  154. package/node_modules/@pi-harness/core/dist/plugins/cleaner.d.ts.map +1 -1
  155. package/node_modules/@pi-harness/core/dist/plugins/cleaner.js +337 -40
  156. package/node_modules/@pi-harness/core/dist/plugins/cleaner.js.map +1 -1
  157. package/node_modules/@pi-harness/core/dist/plugins/cli-notifier.d.ts +2 -1
  158. package/node_modules/@pi-harness/core/dist/plugins/cli-notifier.d.ts.map +1 -1
  159. package/node_modules/@pi-harness/core/dist/plugins/cli-notifier.js +99 -42
  160. package/node_modules/@pi-harness/core/dist/plugins/cli-notifier.js.map +1 -1
  161. package/node_modules/@pi-harness/core/dist/plugins/code2skill.d.ts +1 -0
  162. package/node_modules/@pi-harness/core/dist/plugins/code2skill.d.ts.map +1 -1
  163. package/node_modules/@pi-harness/core/dist/plugins/code2skill.js +178 -38
  164. package/node_modules/@pi-harness/core/dist/plugins/code2skill.js.map +1 -1
  165. package/node_modules/@pi-harness/core/dist/plugins/colleague-skill.d.ts +2 -1
  166. package/node_modules/@pi-harness/core/dist/plugins/colleague-skill.d.ts.map +1 -1
  167. package/node_modules/@pi-harness/core/dist/plugins/colleague-skill.js +79 -49
  168. package/node_modules/@pi-harness/core/dist/plugins/colleague-skill.js.map +1 -1
  169. package/node_modules/@pi-harness/core/dist/plugins/context-doctor.d.ts +6 -1
  170. package/node_modules/@pi-harness/core/dist/plugins/context-doctor.d.ts.map +1 -1
  171. package/node_modules/@pi-harness/core/dist/plugins/context-doctor.js +403 -39
  172. package/node_modules/@pi-harness/core/dist/plugins/context-doctor.js.map +1 -1
  173. package/node_modules/@pi-harness/core/dist/plugins/context.d.ts +1 -0
  174. package/node_modules/@pi-harness/core/dist/plugins/context.d.ts.map +1 -1
  175. package/node_modules/@pi-harness/core/dist/plugins/context.js +169 -42
  176. package/node_modules/@pi-harness/core/dist/plugins/context.js.map +1 -1
  177. package/node_modules/@pi-harness/core/dist/plugins/cost-meter.d.ts +4 -0
  178. package/node_modules/@pi-harness/core/dist/plugins/cost-meter.d.ts.map +1 -1
  179. package/node_modules/@pi-harness/core/dist/plugins/cost-meter.js +319 -93
  180. package/node_modules/@pi-harness/core/dist/plugins/cost-meter.js.map +1 -1
  181. package/node_modules/@pi-harness/core/dist/plugins/dependency-checker.d.ts +11 -2
  182. package/node_modules/@pi-harness/core/dist/plugins/dependency-checker.d.ts.map +1 -1
  183. package/node_modules/@pi-harness/core/dist/plugins/dependency-checker.js +463 -114
  184. package/node_modules/@pi-harness/core/dist/plugins/dependency-checker.js.map +1 -1
  185. package/node_modules/@pi-harness/core/dist/plugins/docker-sandbox.d.ts +1 -0
  186. package/node_modules/@pi-harness/core/dist/plugins/docker-sandbox.d.ts.map +1 -1
  187. package/node_modules/@pi-harness/core/dist/plugins/docker-sandbox.js +322 -80
  188. package/node_modules/@pi-harness/core/dist/plugins/docker-sandbox.js.map +1 -1
  189. package/node_modules/@pi-harness/core/dist/plugins/fail-logger.d.ts +1 -0
  190. package/node_modules/@pi-harness/core/dist/plugins/fail-logger.d.ts.map +1 -1
  191. package/node_modules/@pi-harness/core/dist/plugins/fail-logger.js +187 -20
  192. package/node_modules/@pi-harness/core/dist/plugins/fail-logger.js.map +1 -1
  193. package/node_modules/@pi-harness/core/dist/plugins/genui.d.ts +1 -0
  194. package/node_modules/@pi-harness/core/dist/plugins/genui.d.ts.map +1 -1
  195. package/node_modules/@pi-harness/core/dist/plugins/genui.js +103 -38
  196. package/node_modules/@pi-harness/core/dist/plugins/genui.js.map +1 -1
  197. package/node_modules/@pi-harness/core/dist/plugins/git-time-capsule.d.ts +8 -2
  198. package/node_modules/@pi-harness/core/dist/plugins/git-time-capsule.d.ts.map +1 -1
  199. package/node_modules/@pi-harness/core/dist/plugins/git-time-capsule.js +400 -54
  200. package/node_modules/@pi-harness/core/dist/plugins/git-time-capsule.js.map +1 -1
  201. package/node_modules/@pi-harness/core/dist/plugins/graph-memory.d.ts.map +1 -1
  202. package/node_modules/@pi-harness/core/dist/plugins/graph-memory.js +329 -42
  203. package/node_modules/@pi-harness/core/dist/plugins/graph-memory.js.map +1 -1
  204. package/node_modules/@pi-harness/core/dist/plugins/history-compressor.d.ts.map +1 -1
  205. package/node_modules/@pi-harness/core/dist/plugins/history-compressor.js +31 -12
  206. package/node_modules/@pi-harness/core/dist/plugins/history-compressor.js.map +1 -1
  207. package/node_modules/@pi-harness/core/dist/plugins/hol-guard.d.ts.map +1 -1
  208. package/node_modules/@pi-harness/core/dist/plugins/hol-guard.js +33 -13
  209. package/node_modules/@pi-harness/core/dist/plugins/hol-guard.js.map +1 -1
  210. package/node_modules/@pi-harness/core/dist/plugins/i18n-pair.d.ts +5 -1
  211. package/node_modules/@pi-harness/core/dist/plugins/i18n-pair.d.ts.map +1 -1
  212. package/node_modules/@pi-harness/core/dist/plugins/i18n-pair.js +308 -52
  213. package/node_modules/@pi-harness/core/dist/plugins/i18n-pair.js.map +1 -1
  214. package/node_modules/@pi-harness/core/dist/plugins/image-compressor.d.ts +7 -0
  215. package/node_modules/@pi-harness/core/dist/plugins/image-compressor.d.ts.map +1 -1
  216. package/node_modules/@pi-harness/core/dist/plugins/image-compressor.js +98 -25
  217. package/node_modules/@pi-harness/core/dist/plugins/image-compressor.js.map +1 -1
  218. package/node_modules/@pi-harness/core/dist/plugins/llm-verifier.d.ts.map +1 -1
  219. package/node_modules/@pi-harness/core/dist/plugins/llm-verifier.js +21 -11
  220. package/node_modules/@pi-harness/core/dist/plugins/llm-verifier.js.map +1 -1
  221. package/node_modules/@pi-harness/core/dist/plugins/mcp-client.d.ts.map +1 -1
  222. package/node_modules/@pi-harness/core/dist/plugins/mcp-client.js +986 -232
  223. package/node_modules/@pi-harness/core/dist/plugins/mcp-client.js.map +1 -1
  224. package/node_modules/@pi-harness/core/dist/plugins/mcp-panel.d.ts.map +1 -1
  225. package/node_modules/@pi-harness/core/dist/plugins/mcp-panel.js +30 -16
  226. package/node_modules/@pi-harness/core/dist/plugins/mcp-panel.js.map +1 -1
  227. package/node_modules/@pi-harness/core/dist/plugins/memory.d.ts.map +1 -1
  228. package/node_modules/@pi-harness/core/dist/plugins/memory.js +292 -59
  229. package/node_modules/@pi-harness/core/dist/plugins/memory.js.map +1 -1
  230. package/node_modules/@pi-harness/core/dist/plugins/mirage-bridge.d.ts.map +1 -1
  231. package/node_modules/@pi-harness/core/dist/plugins/mirage-bridge.js +20 -10
  232. package/node_modules/@pi-harness/core/dist/plugins/mirage-bridge.js.map +1 -1
  233. package/node_modules/@pi-harness/core/dist/plugins/mock-server.d.ts.map +1 -1
  234. package/node_modules/@pi-harness/core/dist/plugins/mock-server.js +85 -54
  235. package/node_modules/@pi-harness/core/dist/plugins/mock-server.js.map +1 -1
  236. package/node_modules/@pi-harness/core/dist/plugins/model.d.ts +3 -0
  237. package/node_modules/@pi-harness/core/dist/plugins/model.d.ts.map +1 -1
  238. package/node_modules/@pi-harness/core/dist/plugins/model.js +3 -0
  239. package/node_modules/@pi-harness/core/dist/plugins/model.js.map +1 -1
  240. package/node_modules/@pi-harness/core/dist/plugins/models.d.ts.map +1 -1
  241. package/node_modules/@pi-harness/core/dist/plugins/models.js +10 -2
  242. package/node_modules/@pi-harness/core/dist/plugins/models.js.map +1 -1
  243. package/node_modules/@pi-harness/core/dist/plugins/modlens.d.ts +8 -1
  244. package/node_modules/@pi-harness/core/dist/plugins/modlens.d.ts.map +1 -1
  245. package/node_modules/@pi-harness/core/dist/plugins/modlens.js +438 -31
  246. package/node_modules/@pi-harness/core/dist/plugins/modlens.js.map +1 -1
  247. package/node_modules/@pi-harness/core/dist/plugins/module-search.d.ts +1 -0
  248. package/node_modules/@pi-harness/core/dist/plugins/module-search.d.ts.map +1 -1
  249. package/node_modules/@pi-harness/core/dist/plugins/module-search.js +35 -16
  250. package/node_modules/@pi-harness/core/dist/plugins/module-search.js.map +1 -1
  251. package/node_modules/@pi-harness/core/dist/plugins/obsidian-sync.d.ts.map +1 -1
  252. package/node_modules/@pi-harness/core/dist/plugins/obsidian-sync.js +20 -11
  253. package/node_modules/@pi-harness/core/dist/plugins/obsidian-sync.js.map +1 -1
  254. package/node_modules/@pi-harness/core/dist/plugins/openpets.d.ts.map +1 -1
  255. package/node_modules/@pi-harness/core/dist/plugins/openpets.js +203 -44
  256. package/node_modules/@pi-harness/core/dist/plugins/openpets.js.map +1 -1
  257. package/node_modules/@pi-harness/core/dist/plugins/plan-execute.d.ts +4 -1
  258. package/node_modules/@pi-harness/core/dist/plugins/plan-execute.d.ts.map +1 -1
  259. package/node_modules/@pi-harness/core/dist/plugins/plan-execute.js +42 -21
  260. package/node_modules/@pi-harness/core/dist/plugins/plan-execute.js.map +1 -1
  261. package/node_modules/@pi-harness/core/dist/plugins/plugin-check.d.ts +12 -3
  262. package/node_modules/@pi-harness/core/dist/plugins/plugin-check.d.ts.map +1 -1
  263. package/node_modules/@pi-harness/core/dist/plugins/plugin-check.js +83 -12
  264. package/node_modules/@pi-harness/core/dist/plugins/plugin-check.js.map +1 -1
  265. package/node_modules/@pi-harness/core/dist/plugins/plugin-dev.d.ts +1 -0
  266. package/node_modules/@pi-harness/core/dist/plugins/plugin-dev.d.ts.map +1 -1
  267. package/node_modules/@pi-harness/core/dist/plugins/plugin-dev.js +156 -23
  268. package/node_modules/@pi-harness/core/dist/plugins/plugin-dev.js.map +1 -1
  269. package/node_modules/@pi-harness/core/dist/plugins/plugin-finder.d.ts +1 -0
  270. package/node_modules/@pi-harness/core/dist/plugins/plugin-finder.d.ts.map +1 -1
  271. package/node_modules/@pi-harness/core/dist/plugins/plugin-finder.js +131 -13
  272. package/node_modules/@pi-harness/core/dist/plugins/plugin-finder.js.map +1 -1
  273. package/node_modules/@pi-harness/core/dist/plugins/plugin-radar.d.ts +4 -0
  274. package/node_modules/@pi-harness/core/dist/plugins/plugin-radar.d.ts.map +1 -1
  275. package/node_modules/@pi-harness/core/dist/plugins/plugin-radar.js +137 -36
  276. package/node_modules/@pi-harness/core/dist/plugins/plugin-radar.js.map +1 -1
  277. package/node_modules/@pi-harness/core/dist/plugins/plugin-stars.d.ts.map +1 -1
  278. package/node_modules/@pi-harness/core/dist/plugins/plugin-stars.js +282 -81
  279. package/node_modules/@pi-harness/core/dist/plugins/plugin-stars.js.map +1 -1
  280. package/node_modules/@pi-harness/core/dist/plugins/prompt-guard.d.ts +1 -0
  281. package/node_modules/@pi-harness/core/dist/plugins/prompt-guard.d.ts.map +1 -1
  282. package/node_modules/@pi-harness/core/dist/plugins/prompt-guard.js +60 -9
  283. package/node_modules/@pi-harness/core/dist/plugins/prompt-guard.js.map +1 -1
  284. package/node_modules/@pi-harness/core/dist/plugins/prompt-library.d.ts +1 -0
  285. package/node_modules/@pi-harness/core/dist/plugins/prompt-library.d.ts.map +1 -1
  286. package/node_modules/@pi-harness/core/dist/plugins/prompt-library.js +4 -1
  287. package/node_modules/@pi-harness/core/dist/plugins/prompt-library.js.map +1 -1
  288. package/node_modules/@pi-harness/core/dist/plugins/readme-gen.d.ts +6 -2
  289. package/node_modules/@pi-harness/core/dist/plugins/readme-gen.d.ts.map +1 -1
  290. package/node_modules/@pi-harness/core/dist/plugins/readme-gen.js +514 -73
  291. package/node_modules/@pi-harness/core/dist/plugins/readme-gen.js.map +1 -1
  292. package/node_modules/@pi-harness/core/dist/plugins/recall-unread.d.ts +1 -1
  293. package/node_modules/@pi-harness/core/dist/plugins/recall-unread.d.ts.map +1 -1
  294. package/node_modules/@pi-harness/core/dist/plugins/recall-unread.js +411 -68
  295. package/node_modules/@pi-harness/core/dist/plugins/recall-unread.js.map +1 -1
  296. package/node_modules/@pi-harness/core/dist/plugins/resources.d.ts.map +1 -1
  297. package/node_modules/@pi-harness/core/dist/plugins/resources.js +66 -3
  298. package/node_modules/@pi-harness/core/dist/plugins/resources.js.map +1 -1
  299. package/node_modules/@pi-harness/core/dist/plugins/reverse-skill.d.ts.map +1 -1
  300. package/node_modules/@pi-harness/core/dist/plugins/reverse-skill.js +2 -1
  301. package/node_modules/@pi-harness/core/dist/plugins/reverse-skill.js.map +1 -1
  302. package/node_modules/@pi-harness/core/dist/plugins/reviewer-bot.d.ts +1 -0
  303. package/node_modules/@pi-harness/core/dist/plugins/reviewer-bot.d.ts.map +1 -1
  304. package/node_modules/@pi-harness/core/dist/plugins/reviewer-bot.js +35 -16
  305. package/node_modules/@pi-harness/core/dist/plugins/reviewer-bot.js.map +1 -1
  306. package/node_modules/@pi-harness/core/dist/plugins/runtime-doctor.d.ts +1 -0
  307. package/node_modules/@pi-harness/core/dist/plugins/runtime-doctor.d.ts.map +1 -1
  308. package/node_modules/@pi-harness/core/dist/plugins/runtime-doctor.js +4 -1
  309. package/node_modules/@pi-harness/core/dist/plugins/runtime-doctor.js.map +1 -1
  310. package/node_modules/@pi-harness/core/dist/plugins/runtime.d.ts.map +1 -1
  311. package/node_modules/@pi-harness/core/dist/plugins/runtime.js +104 -70
  312. package/node_modules/@pi-harness/core/dist/plugins/runtime.js.map +1 -1
  313. package/node_modules/@pi-harness/core/dist/plugins/secure-audit.d.ts +1 -0
  314. package/node_modules/@pi-harness/core/dist/plugins/secure-audit.d.ts.map +1 -1
  315. package/node_modules/@pi-harness/core/dist/plugins/secure-audit.js +30 -12
  316. package/node_modules/@pi-harness/core/dist/plugins/secure-audit.js.map +1 -1
  317. package/node_modules/@pi-harness/core/dist/plugins/session-bookmarks.d.ts +1 -0
  318. package/node_modules/@pi-harness/core/dist/plugins/session-bookmarks.d.ts.map +1 -1
  319. package/node_modules/@pi-harness/core/dist/plugins/session-bookmarks.js +4 -1
  320. package/node_modules/@pi-harness/core/dist/plugins/session-bookmarks.js.map +1 -1
  321. package/node_modules/@pi-harness/core/dist/plugins/session-bridge.d.ts +1 -0
  322. package/node_modules/@pi-harness/core/dist/plugins/session-bridge.d.ts.map +1 -1
  323. package/node_modules/@pi-harness/core/dist/plugins/session-bridge.js +401 -88
  324. package/node_modules/@pi-harness/core/dist/plugins/session-bridge.js.map +1 -1
  325. package/node_modules/@pi-harness/core/dist/plugins/session-compare.d.ts +1 -0
  326. package/node_modules/@pi-harness/core/dist/plugins/session-compare.d.ts.map +1 -1
  327. package/node_modules/@pi-harness/core/dist/plugins/session-compare.js +4 -1
  328. package/node_modules/@pi-harness/core/dist/plugins/session-compare.js.map +1 -1
  329. package/node_modules/@pi-harness/core/dist/plugins/session-export.d.ts +1 -0
  330. package/node_modules/@pi-harness/core/dist/plugins/session-export.d.ts.map +1 -1
  331. package/node_modules/@pi-harness/core/dist/plugins/session-export.js +6 -6
  332. package/node_modules/@pi-harness/core/dist/plugins/session-export.js.map +1 -1
  333. package/node_modules/@pi-harness/core/dist/plugins/session-insights.d.ts +37 -1
  334. package/node_modules/@pi-harness/core/dist/plugins/session-insights.d.ts.map +1 -1
  335. package/node_modules/@pi-harness/core/dist/plugins/session-insights.js +406 -21
  336. package/node_modules/@pi-harness/core/dist/plugins/session-insights.js.map +1 -1
  337. package/node_modules/@pi-harness/core/dist/plugins/session-search.d.ts +1 -0
  338. package/node_modules/@pi-harness/core/dist/plugins/session-search.d.ts.map +1 -1
  339. package/node_modules/@pi-harness/core/dist/plugins/session-search.js +4 -1
  340. package/node_modules/@pi-harness/core/dist/plugins/session-search.js.map +1 -1
  341. package/node_modules/@pi-harness/core/dist/plugins/session.d.ts.map +1 -1
  342. package/node_modules/@pi-harness/core/dist/plugins/session.js +8 -1
  343. package/node_modules/@pi-harness/core/dist/plugins/session.js.map +1 -1
  344. package/node_modules/@pi-harness/core/dist/plugins/skill-catalog.d.ts +1 -0
  345. package/node_modules/@pi-harness/core/dist/plugins/skill-catalog.d.ts.map +1 -1
  346. package/node_modules/@pi-harness/core/dist/plugins/skill-catalog.js +6 -5
  347. package/node_modules/@pi-harness/core/dist/plugins/skill-catalog.js.map +1 -1
  348. package/node_modules/@pi-harness/core/dist/plugins/skill-guard.d.ts +2 -1
  349. package/node_modules/@pi-harness/core/dist/plugins/skill-guard.d.ts.map +1 -1
  350. package/node_modules/@pi-harness/core/dist/plugins/skill-guard.js +241 -61
  351. package/node_modules/@pi-harness/core/dist/plugins/skill-guard.js.map +1 -1
  352. package/node_modules/@pi-harness/core/dist/plugins/sql-lens-worker.d.ts +2 -0
  353. package/node_modules/@pi-harness/core/dist/plugins/sql-lens-worker.d.ts.map +1 -0
  354. package/node_modules/@pi-harness/core/dist/plugins/sql-lens-worker.js +206 -0
  355. package/node_modules/@pi-harness/core/dist/plugins/sql-lens-worker.js.map +1 -0
  356. package/node_modules/@pi-harness/core/dist/plugins/sql-lens.d.ts +7 -1
  357. package/node_modules/@pi-harness/core/dist/plugins/sql-lens.d.ts.map +1 -1
  358. package/node_modules/@pi-harness/core/dist/plugins/sql-lens.js +301 -68
  359. package/node_modules/@pi-harness/core/dist/plugins/sql-lens.js.map +1 -1
  360. package/node_modules/@pi-harness/core/dist/plugins/stdio.d.ts +3 -0
  361. package/node_modules/@pi-harness/core/dist/plugins/stdio.d.ts.map +1 -1
  362. package/node_modules/@pi-harness/core/dist/plugins/stdio.js +62 -4
  363. package/node_modules/@pi-harness/core/dist/plugins/stdio.js.map +1 -1
  364. package/node_modules/@pi-harness/core/dist/plugins/synapse.d.ts.map +1 -1
  365. package/node_modules/@pi-harness/core/dist/plugins/synapse.js +17 -9
  366. package/node_modules/@pi-harness/core/dist/plugins/synapse.js.map +1 -1
  367. package/node_modules/@pi-harness/core/dist/plugins/tab-manager.d.ts +1 -0
  368. package/node_modules/@pi-harness/core/dist/plugins/tab-manager.d.ts.map +1 -1
  369. package/node_modules/@pi-harness/core/dist/plugins/tab-manager.js +167 -62
  370. package/node_modules/@pi-harness/core/dist/plugins/tab-manager.js.map +1 -1
  371. package/node_modules/@pi-harness/core/dist/plugins/taskboard.d.ts.map +1 -1
  372. package/node_modules/@pi-harness/core/dist/plugins/taskboard.js +50 -22
  373. package/node_modules/@pi-harness/core/dist/plugins/taskboard.js.map +1 -1
  374. package/node_modules/@pi-harness/core/dist/plugins/telemetry-blocker.d.ts +4 -1
  375. package/node_modules/@pi-harness/core/dist/plugins/telemetry-blocker.d.ts.map +1 -1
  376. package/node_modules/@pi-harness/core/dist/plugins/telemetry-blocker.js +30 -11
  377. package/node_modules/@pi-harness/core/dist/plugins/telemetry-blocker.js.map +1 -1
  378. package/node_modules/@pi-harness/core/dist/plugins/test-harness.d.ts +7 -1
  379. package/node_modules/@pi-harness/core/dist/plugins/test-harness.d.ts.map +1 -1
  380. package/node_modules/@pi-harness/core/dist/plugins/test-harness.js +255 -43
  381. package/node_modules/@pi-harness/core/dist/plugins/test-harness.js.map +1 -1
  382. package/node_modules/@pi-harness/core/dist/plugins/theme-studio.d.ts.map +1 -1
  383. package/node_modules/@pi-harness/core/dist/plugins/theme-studio.js +4 -2
  384. package/node_modules/@pi-harness/core/dist/plugins/theme-studio.js.map +1 -1
  385. package/node_modules/@pi-harness/core/dist/plugins/token-guard.d.ts.map +1 -1
  386. package/node_modules/@pi-harness/core/dist/plugins/token-guard.js +164 -32
  387. package/node_modules/@pi-harness/core/dist/plugins/token-guard.js.map +1 -1
  388. package/node_modules/@pi-harness/core/dist/plugins/tools.d.ts.map +1 -1
  389. package/node_modules/@pi-harness/core/dist/plugins/tools.js +4 -1
  390. package/node_modules/@pi-harness/core/dist/plugins/tools.js.map +1 -1
  391. package/node_modules/@pi-harness/core/dist/plugins/turn-rewind.d.ts +17 -0
  392. package/node_modules/@pi-harness/core/dist/plugins/turn-rewind.d.ts.map +1 -1
  393. package/node_modules/@pi-harness/core/dist/plugins/turn-rewind.js +340 -36
  394. package/node_modules/@pi-harness/core/dist/plugins/turn-rewind.js.map +1 -1
  395. package/node_modules/@pi-harness/core/dist/plugins/undo-savepoint.d.ts.map +1 -1
  396. package/node_modules/@pi-harness/core/dist/plugins/undo-savepoint.js +157 -51
  397. package/node_modules/@pi-harness/core/dist/plugins/undo-savepoint.js.map +1 -1
  398. package/node_modules/@pi-harness/core/dist/plugins/vision-toolkit.d.ts +22 -3
  399. package/node_modules/@pi-harness/core/dist/plugins/vision-toolkit.d.ts.map +1 -1
  400. package/node_modules/@pi-harness/core/dist/plugins/vision-toolkit.js +389 -66
  401. package/node_modules/@pi-harness/core/dist/plugins/vision-toolkit.js.map +1 -1
  402. package/node_modules/@pi-harness/core/dist/plugins/web-research.d.ts.map +1 -1
  403. package/node_modules/@pi-harness/core/dist/plugins/web-research.js +13 -4
  404. package/node_modules/@pi-harness/core/dist/plugins/web-research.js.map +1 -1
  405. package/node_modules/@pi-harness/core/dist/plugins/workspace-navigator.d.ts +8 -2
  406. package/node_modules/@pi-harness/core/dist/plugins/workspace-navigator.d.ts.map +1 -1
  407. package/node_modules/@pi-harness/core/dist/plugins/workspace-navigator.js +28 -10
  408. package/node_modules/@pi-harness/core/dist/plugins/workspace-navigator.js.map +1 -1
  409. package/node_modules/@pi-harness/core/dist/plugins/workspace-search.d.ts +7 -0
  410. package/node_modules/@pi-harness/core/dist/plugins/workspace-search.d.ts.map +1 -1
  411. package/node_modules/@pi-harness/core/dist/plugins/workspace-search.js +67 -34
  412. package/node_modules/@pi-harness/core/dist/plugins/workspace-search.js.map +1 -1
  413. package/node_modules/@pi-harness/core/dist/plugins/yaml-validator.d.ts +1 -0
  414. package/node_modules/@pi-harness/core/dist/plugins/yaml-validator.d.ts.map +1 -1
  415. package/node_modules/@pi-harness/core/dist/plugins/yaml-validator.js +156 -47
  416. package/node_modules/@pi-harness/core/dist/plugins/yaml-validator.js.map +1 -1
  417. package/node_modules/@pi-harness/core/dist/runtime.d.ts.map +1 -1
  418. package/node_modules/@pi-harness/core/dist/runtime.js +8 -3
  419. package/node_modules/@pi-harness/core/dist/runtime.js.map +1 -1
  420. package/node_modules/@pi-harness/core/dist/services.d.ts.map +1 -1
  421. package/node_modules/@pi-harness/core/dist/services.js +22 -2
  422. package/node_modules/@pi-harness/core/dist/services.js.map +1 -1
  423. package/node_modules/@pi-harness/core/dist/stdio.d.ts +1 -0
  424. package/node_modules/@pi-harness/core/dist/stdio.d.ts.map +1 -1
  425. package/node_modules/@pi-harness/core/dist/stdio.js +241 -25
  426. package/node_modules/@pi-harness/core/dist/stdio.js.map +1 -1
  427. package/node_modules/@pi-harness/core/dist/workspace-path.d.ts +1 -0
  428. package/node_modules/@pi-harness/core/dist/workspace-path.d.ts.map +1 -1
  429. package/node_modules/@pi-harness/core/dist/workspace-path.js +9 -0
  430. package/node_modules/@pi-harness/core/dist/workspace-path.js.map +1 -1
  431. package/node_modules/@pi-harness/core/package.json +1 -1
  432. package/node_modules/@pi-harness/core/profiles/default/cordis.yml +4 -2
  433. package/node_modules/@pi-harness/host-webserver/package.json +1 -1
  434. package/node_modules/@pi-harness/web-app/package.json +1 -1
  435. package/package.json +12 -7
  436. package/packages/api-gateway/dist/index.d.ts.map +1 -1
  437. package/packages/api-gateway/dist/index.js +97 -9
  438. package/packages/api-gateway/dist/index.js.map +1 -1
  439. package/packages/api-gateway/dist/marketplace-entries/official/agent-teams.json +6 -6
  440. package/packages/api-gateway/dist/marketplace-entries/official/anchored-standard.json +1 -1
  441. package/packages/api-gateway/dist/marketplace-entries/official/annotation.json +1 -2
  442. package/packages/api-gateway/dist/marketplace-entries/official/archify.json +1 -1
  443. package/packages/api-gateway/dist/marketplace-entries/official/at-file.json +11 -5
  444. package/packages/api-gateway/dist/marketplace-entries/official/auto-mode.json +1 -1
  445. package/packages/api-gateway/dist/marketplace-entries/official/better-sidebar.json +1 -1
  446. package/packages/api-gateway/dist/marketplace-entries/official/browser-fetch.json +12 -5
  447. package/packages/api-gateway/dist/marketplace-entries/official/browser-session.json +14 -8
  448. package/packages/api-gateway/dist/marketplace-entries/official/canvas-draw.json +3 -4
  449. package/packages/api-gateway/dist/marketplace-entries/official/change-verifier.json +1 -1
  450. package/packages/api-gateway/dist/marketplace-entries/official/cleaner.json +11 -6
  451. package/packages/api-gateway/dist/marketplace-entries/official/cli-notifier.json +5 -5
  452. package/packages/api-gateway/dist/marketplace-entries/official/code2skill.json +5 -5
  453. package/packages/api-gateway/dist/marketplace-entries/official/colleague-skill.json +1 -2
  454. package/packages/api-gateway/dist/marketplace-entries/official/context-doctor.json +12 -7
  455. package/packages/api-gateway/dist/marketplace-entries/official/context.json +10 -5
  456. package/packages/api-gateway/dist/marketplace-entries/official/cordis-group.json +2 -2
  457. package/packages/api-gateway/dist/marketplace-entries/official/cordis-logger-console.json +4 -4
  458. package/packages/api-gateway/dist/marketplace-entries/official/cordis-timer.json +3 -3
  459. package/packages/api-gateway/dist/marketplace-entries/official/cost-meter.json +9 -6
  460. package/packages/api-gateway/dist/marketplace-entries/official/dependency-checker.json +13 -10
  461. package/packages/api-gateway/dist/marketplace-entries/official/docker-sandbox.json +10 -5
  462. package/packages/api-gateway/dist/marketplace-entries/official/fail-logger.json +11 -6
  463. package/packages/api-gateway/dist/marketplace-entries/official/genui.json +7 -5
  464. package/packages/api-gateway/dist/marketplace-entries/official/git-time-capsule.json +13 -8
  465. package/packages/api-gateway/dist/marketplace-entries/official/graph-memory.json +13 -7
  466. package/packages/api-gateway/dist/marketplace-entries/official/history-compressor.json +1 -1
  467. package/packages/api-gateway/dist/marketplace-entries/official/hol-guard.json +1 -1
  468. package/packages/api-gateway/dist/marketplace-entries/official/i18n-pair.json +9 -6
  469. package/packages/api-gateway/dist/marketplace-entries/official/image-compressor.json +1 -1
  470. package/packages/api-gateway/dist/marketplace-entries/official/llm-verifier.json +1 -1
  471. package/packages/api-gateway/dist/marketplace-entries/official/mcp-client.json +12 -7
  472. package/packages/api-gateway/dist/marketplace-entries/official/mcp-panel.json +1 -1
  473. package/packages/api-gateway/dist/marketplace-entries/official/memory.json +1 -1
  474. package/packages/api-gateway/dist/marketplace-entries/official/mirage-bridge.json +1 -1
  475. package/packages/api-gateway/dist/marketplace-entries/official/mock-server.json +1 -1
  476. package/packages/api-gateway/dist/marketplace-entries/official/modlens.json +4 -4
  477. package/packages/api-gateway/dist/marketplace-entries/official/module-search.json +1 -1
  478. package/packages/api-gateway/dist/marketplace-entries/official/obsidian-sync.json +1 -1
  479. package/packages/api-gateway/dist/marketplace-entries/official/openpets.json +9 -5
  480. package/packages/api-gateway/dist/marketplace-entries/official/plan-execute.json +1 -1
  481. package/packages/api-gateway/dist/marketplace-entries/official/plugin-check.json +1 -1
  482. package/packages/api-gateway/dist/marketplace-entries/official/plugin-dev.json +8 -6
  483. package/packages/api-gateway/dist/marketplace-entries/official/plugin-finder.json +1 -1
  484. package/packages/api-gateway/dist/marketplace-entries/official/plugin-radar.json +1 -1
  485. package/packages/api-gateway/dist/marketplace-entries/official/plugin-stars.json +15 -7
  486. package/packages/api-gateway/dist/marketplace-entries/official/prompt-guard.json +1 -1
  487. package/packages/api-gateway/dist/marketplace-entries/official/prompt-library.json +1 -1
  488. package/packages/api-gateway/dist/marketplace-entries/official/readme-gen.json +12 -8
  489. package/packages/api-gateway/dist/marketplace-entries/official/recall-unread.json +11 -6
  490. package/packages/api-gateway/dist/marketplace-entries/official/reverse-skill.json +1 -1
  491. package/packages/api-gateway/dist/marketplace-entries/official/reviewer-bot.json +1 -1
  492. package/packages/api-gateway/dist/marketplace-entries/official/runtime-doctor.json +1 -1
  493. package/packages/api-gateway/dist/marketplace-entries/official/secure-audit.json +1 -1
  494. package/packages/api-gateway/dist/marketplace-entries/official/session-bookmarks.json +1 -1
  495. package/packages/api-gateway/dist/marketplace-entries/official/session-bridge.json +13 -8
  496. package/packages/api-gateway/dist/marketplace-entries/official/session-compare.json +1 -1
  497. package/packages/api-gateway/dist/marketplace-entries/official/session-export.json +1 -1
  498. package/packages/api-gateway/dist/marketplace-entries/official/session-insights.json +12 -6
  499. package/packages/api-gateway/dist/marketplace-entries/official/session-search.json +1 -1
  500. package/packages/api-gateway/dist/marketplace-entries/official/skill-catalog.json +1 -1
  501. package/packages/api-gateway/dist/marketplace-entries/official/skill-guard.json +9 -5
  502. package/packages/api-gateway/dist/marketplace-entries/official/sql-lens.json +13 -7
  503. package/packages/api-gateway/dist/marketplace-entries/official/synapse.json +1 -1
  504. package/packages/api-gateway/dist/marketplace-entries/official/tab-manager.json +1 -1
  505. package/packages/api-gateway/dist/marketplace-entries/official/taskboard.json +1 -1
  506. package/packages/api-gateway/dist/marketplace-entries/official/telemetry-blocker.json +1 -1
  507. package/packages/api-gateway/dist/marketplace-entries/official/test-harness.json +14 -7
  508. package/packages/api-gateway/dist/marketplace-entries/official/theme-studio.json +1 -1
  509. package/packages/api-gateway/dist/marketplace-entries/official/token-guard.json +12 -6
  510. package/packages/api-gateway/dist/marketplace-entries/official/turn-rewind.json +11 -6
  511. package/packages/api-gateway/dist/marketplace-entries/official/undo-savepoint.json +1 -1
  512. package/packages/api-gateway/dist/marketplace-entries/official/vision-toolkit.json +8 -5
  513. package/packages/api-gateway/dist/marketplace-entries/official/web-research.json +1 -1
  514. package/packages/api-gateway/dist/marketplace-entries/official/workspace-navigator.json +1 -1
  515. package/packages/api-gateway/dist/marketplace-entries/official/workspace-search.json +1 -1
  516. package/packages/api-gateway/dist/marketplace-entries/official/yaml-validator.json +8 -5
  517. package/packages/api-gateway/package.json +1 -1
  518. package/packages/api-gateway/src/index.ts +90 -9
  519. package/packages/api-gateway/src/marketplace-entries/official/agent-teams.json +6 -6
  520. package/packages/api-gateway/src/marketplace-entries/official/anchored-standard.json +1 -1
  521. package/packages/api-gateway/src/marketplace-entries/official/annotation.json +1 -2
  522. package/packages/api-gateway/src/marketplace-entries/official/archify.json +1 -1
  523. package/packages/api-gateway/src/marketplace-entries/official/at-file.json +11 -5
  524. package/packages/api-gateway/src/marketplace-entries/official/auto-mode.json +1 -1
  525. package/packages/api-gateway/src/marketplace-entries/official/better-sidebar.json +1 -1
  526. package/packages/api-gateway/src/marketplace-entries/official/browser-fetch.json +12 -5
  527. package/packages/api-gateway/src/marketplace-entries/official/browser-session.json +14 -8
  528. package/packages/api-gateway/src/marketplace-entries/official/canvas-draw.json +3 -4
  529. package/packages/api-gateway/src/marketplace-entries/official/change-verifier.json +1 -1
  530. package/packages/api-gateway/src/marketplace-entries/official/cleaner.json +11 -6
  531. package/packages/api-gateway/src/marketplace-entries/official/cli-notifier.json +5 -5
  532. package/packages/api-gateway/src/marketplace-entries/official/code2skill.json +5 -5
  533. package/packages/api-gateway/src/marketplace-entries/official/colleague-skill.json +1 -2
  534. package/packages/api-gateway/src/marketplace-entries/official/context-doctor.json +12 -7
  535. package/packages/api-gateway/src/marketplace-entries/official/context.json +10 -5
  536. package/packages/api-gateway/src/marketplace-entries/official/cordis-group.json +2 -2
  537. package/packages/api-gateway/src/marketplace-entries/official/cordis-logger-console.json +4 -4
  538. package/packages/api-gateway/src/marketplace-entries/official/cordis-timer.json +3 -3
  539. package/packages/api-gateway/src/marketplace-entries/official/cost-meter.json +9 -6
  540. package/packages/api-gateway/src/marketplace-entries/official/dependency-checker.json +13 -10
  541. package/packages/api-gateway/src/marketplace-entries/official/docker-sandbox.json +10 -5
  542. package/packages/api-gateway/src/marketplace-entries/official/fail-logger.json +11 -6
  543. package/packages/api-gateway/src/marketplace-entries/official/genui.json +7 -5
  544. package/packages/api-gateway/src/marketplace-entries/official/git-time-capsule.json +13 -8
  545. package/packages/api-gateway/src/marketplace-entries/official/graph-memory.json +13 -7
  546. package/packages/api-gateway/src/marketplace-entries/official/history-compressor.json +1 -1
  547. package/packages/api-gateway/src/marketplace-entries/official/hol-guard.json +1 -1
  548. package/packages/api-gateway/src/marketplace-entries/official/i18n-pair.json +9 -6
  549. package/packages/api-gateway/src/marketplace-entries/official/image-compressor.json +1 -1
  550. package/packages/api-gateway/src/marketplace-entries/official/llm-verifier.json +1 -1
  551. package/packages/api-gateway/src/marketplace-entries/official/mcp-client.json +12 -7
  552. package/packages/api-gateway/src/marketplace-entries/official/mcp-panel.json +1 -1
  553. package/packages/api-gateway/src/marketplace-entries/official/memory.json +1 -1
  554. package/packages/api-gateway/src/marketplace-entries/official/mirage-bridge.json +1 -1
  555. package/packages/api-gateway/src/marketplace-entries/official/mock-server.json +1 -1
  556. package/packages/api-gateway/src/marketplace-entries/official/modlens.json +4 -4
  557. package/packages/api-gateway/src/marketplace-entries/official/module-search.json +1 -1
  558. package/packages/api-gateway/src/marketplace-entries/official/obsidian-sync.json +1 -1
  559. package/packages/api-gateway/src/marketplace-entries/official/openpets.json +9 -5
  560. package/packages/api-gateway/src/marketplace-entries/official/plan-execute.json +1 -1
  561. package/packages/api-gateway/src/marketplace-entries/official/plugin-check.json +1 -1
  562. package/packages/api-gateway/src/marketplace-entries/official/plugin-dev.json +8 -6
  563. package/packages/api-gateway/src/marketplace-entries/official/plugin-finder.json +1 -1
  564. package/packages/api-gateway/src/marketplace-entries/official/plugin-radar.json +1 -1
  565. package/packages/api-gateway/src/marketplace-entries/official/plugin-stars.json +15 -7
  566. package/packages/api-gateway/src/marketplace-entries/official/prompt-guard.json +1 -1
  567. package/packages/api-gateway/src/marketplace-entries/official/prompt-library.json +1 -1
  568. package/packages/api-gateway/src/marketplace-entries/official/readme-gen.json +12 -8
  569. package/packages/api-gateway/src/marketplace-entries/official/recall-unread.json +11 -6
  570. package/packages/api-gateway/src/marketplace-entries/official/reverse-skill.json +1 -1
  571. package/packages/api-gateway/src/marketplace-entries/official/reviewer-bot.json +1 -1
  572. package/packages/api-gateway/src/marketplace-entries/official/runtime-doctor.json +1 -1
  573. package/packages/api-gateway/src/marketplace-entries/official/secure-audit.json +1 -1
  574. package/packages/api-gateway/src/marketplace-entries/official/session-bookmarks.json +1 -1
  575. package/packages/api-gateway/src/marketplace-entries/official/session-bridge.json +13 -8
  576. package/packages/api-gateway/src/marketplace-entries/official/session-compare.json +1 -1
  577. package/packages/api-gateway/src/marketplace-entries/official/session-export.json +1 -1
  578. package/packages/api-gateway/src/marketplace-entries/official/session-insights.json +12 -6
  579. package/packages/api-gateway/src/marketplace-entries/official/session-search.json +1 -1
  580. package/packages/api-gateway/src/marketplace-entries/official/skill-catalog.json +1 -1
  581. package/packages/api-gateway/src/marketplace-entries/official/skill-guard.json +9 -5
  582. package/packages/api-gateway/src/marketplace-entries/official/sql-lens.json +13 -7
  583. package/packages/api-gateway/src/marketplace-entries/official/synapse.json +1 -1
  584. package/packages/api-gateway/src/marketplace-entries/official/tab-manager.json +1 -1
  585. package/packages/api-gateway/src/marketplace-entries/official/taskboard.json +1 -1
  586. package/packages/api-gateway/src/marketplace-entries/official/telemetry-blocker.json +1 -1
  587. package/packages/api-gateway/src/marketplace-entries/official/test-harness.json +14 -7
  588. package/packages/api-gateway/src/marketplace-entries/official/theme-studio.json +1 -1
  589. package/packages/api-gateway/src/marketplace-entries/official/token-guard.json +12 -6
  590. package/packages/api-gateway/src/marketplace-entries/official/turn-rewind.json +11 -6
  591. package/packages/api-gateway/src/marketplace-entries/official/undo-savepoint.json +1 -1
  592. package/packages/api-gateway/src/marketplace-entries/official/vision-toolkit.json +8 -5
  593. package/packages/api-gateway/src/marketplace-entries/official/web-research.json +1 -1
  594. package/packages/api-gateway/src/marketplace-entries/official/workspace-navigator.json +1 -1
  595. package/packages/api-gateway/src/marketplace-entries/official/workspace-search.json +1 -1
  596. package/packages/api-gateway/src/marketplace-entries/official/yaml-validator.json +8 -5
  597. package/packages/api-gateway/test/index.test.ts +1594 -2
  598. package/packages/api-gateway/test/marketplace.test.ts +389 -2
  599. package/packages/api-gateway/test/release-package.test.ts +1 -0
  600. package/packages/bundle-web-app/package.json +1 -1
  601. package/packages/cli/dist/node-stdio.d.ts.map +1 -1
  602. package/packages/cli/dist/node-stdio.js +83 -20
  603. package/packages/cli/dist/node-stdio.js.map +1 -1
  604. package/packages/cli/package.json +1 -1
  605. package/packages/cli/src/node-stdio.ts +77 -20
  606. package/packages/cli/test/node-stdio.test.ts +118 -2
  607. package/packages/client-web/dist/agent-teams-view.d.ts +70 -0
  608. package/packages/client-web/dist/agent-teams-view.d.ts.map +1 -0
  609. package/packages/client-web/dist/agent-teams-view.js +159 -0
  610. package/packages/client-web/dist/agent-teams-view.js.map +1 -0
  611. package/packages/client-web/dist/at-file-view.d.ts +10 -0
  612. package/packages/client-web/dist/at-file-view.d.ts.map +1 -0
  613. package/packages/client-web/dist/at-file-view.js +65 -0
  614. package/packages/client-web/dist/at-file-view.js.map +1 -0
  615. package/packages/client-web/dist/browser-fetch-view.d.ts +22 -0
  616. package/packages/client-web/dist/browser-fetch-view.d.ts.map +1 -0
  617. package/packages/client-web/dist/browser-fetch-view.js +101 -0
  618. package/packages/client-web/dist/browser-fetch-view.js.map +1 -0
  619. package/packages/client-web/dist/browser-session-view.d.ts +32 -0
  620. package/packages/client-web/dist/browser-session-view.d.ts.map +1 -1
  621. package/packages/client-web/dist/browser-session-view.js +206 -3
  622. package/packages/client-web/dist/browser-session-view.js.map +1 -1
  623. package/packages/client-web/dist/cleaner-view.d.ts +29 -0
  624. package/packages/client-web/dist/cleaner-view.d.ts.map +1 -0
  625. package/packages/client-web/dist/cleaner-view.js +191 -0
  626. package/packages/client-web/dist/cleaner-view.js.map +1 -0
  627. package/packages/client-web/dist/context-doctor-view.d.ts +35 -0
  628. package/packages/client-web/dist/context-doctor-view.d.ts.map +1 -0
  629. package/packages/client-web/dist/context-doctor-view.js +129 -0
  630. package/packages/client-web/dist/context-doctor-view.js.map +1 -0
  631. package/packages/client-web/dist/context-insights-view.d.ts +31 -0
  632. package/packages/client-web/dist/context-insights-view.d.ts.map +1 -0
  633. package/packages/client-web/dist/context-insights-view.js +90 -0
  634. package/packages/client-web/dist/context-insights-view.js.map +1 -0
  635. package/packages/client-web/dist/cost-meter-view.d.ts +16 -0
  636. package/packages/client-web/dist/cost-meter-view.d.ts.map +1 -0
  637. package/packages/client-web/dist/cost-meter-view.js +43 -0
  638. package/packages/client-web/dist/cost-meter-view.js.map +1 -0
  639. package/packages/client-web/dist/dependency-checker-view.d.ts +24 -0
  640. package/packages/client-web/dist/dependency-checker-view.d.ts.map +1 -0
  641. package/packages/client-web/dist/dependency-checker-view.js +195 -0
  642. package/packages/client-web/dist/dependency-checker-view.js.map +1 -0
  643. package/packages/client-web/dist/docker-sandbox-view.d.ts +28 -0
  644. package/packages/client-web/dist/docker-sandbox-view.d.ts.map +1 -0
  645. package/packages/client-web/dist/docker-sandbox-view.js +152 -0
  646. package/packages/client-web/dist/docker-sandbox-view.js.map +1 -0
  647. package/packages/client-web/dist/fail-logger-view.d.ts +16 -0
  648. package/packages/client-web/dist/fail-logger-view.d.ts.map +1 -0
  649. package/packages/client-web/dist/fail-logger-view.js +97 -0
  650. package/packages/client-web/dist/fail-logger-view.js.map +1 -0
  651. package/packages/client-web/dist/genui-view.d.ts +28 -0
  652. package/packages/client-web/dist/genui-view.d.ts.map +1 -0
  653. package/packages/client-web/dist/genui-view.js +62 -0
  654. package/packages/client-web/dist/genui-view.js.map +1 -0
  655. package/packages/client-web/dist/git-time-capsule-view.d.ts +31 -0
  656. package/packages/client-web/dist/git-time-capsule-view.d.ts.map +1 -0
  657. package/packages/client-web/dist/git-time-capsule-view.js +203 -0
  658. package/packages/client-web/dist/git-time-capsule-view.js.map +1 -0
  659. package/packages/client-web/dist/graph-memory-view.d.ts +39 -0
  660. package/packages/client-web/dist/graph-memory-view.d.ts.map +1 -0
  661. package/packages/client-web/dist/graph-memory-view.js +82 -0
  662. package/packages/client-web/dist/graph-memory-view.js.map +1 -0
  663. package/packages/client-web/dist/i18n-pair-view.d.ts +32 -0
  664. package/packages/client-web/dist/i18n-pair-view.d.ts.map +1 -0
  665. package/packages/client-web/dist/i18n-pair-view.js +182 -0
  666. package/packages/client-web/dist/i18n-pair-view.js.map +1 -0
  667. package/packages/client-web/dist/mcp-client-view.d.ts +58 -0
  668. package/packages/client-web/dist/mcp-client-view.d.ts.map +1 -0
  669. package/packages/client-web/dist/mcp-client-view.js +121 -0
  670. package/packages/client-web/dist/mcp-client-view.js.map +1 -0
  671. package/packages/client-web/dist/modlens-view.d.ts +43 -0
  672. package/packages/client-web/dist/modlens-view.d.ts.map +1 -0
  673. package/packages/client-web/dist/modlens-view.js +176 -0
  674. package/packages/client-web/dist/modlens-view.js.map +1 -0
  675. package/packages/client-web/dist/openpets-view.d.ts +26 -0
  676. package/packages/client-web/dist/openpets-view.d.ts.map +1 -0
  677. package/packages/client-web/dist/openpets-view.js +62 -0
  678. package/packages/client-web/dist/openpets-view.js.map +1 -0
  679. package/packages/client-web/dist/panel-safe.d.ts +5 -0
  680. package/packages/client-web/dist/panel-safe.d.ts.map +1 -0
  681. package/packages/client-web/dist/panel-safe.js +58 -0
  682. package/packages/client-web/dist/panel-safe.js.map +1 -0
  683. package/packages/client-web/dist/plugin-dev-view.d.ts +15 -0
  684. package/packages/client-web/dist/plugin-dev-view.d.ts.map +1 -0
  685. package/packages/client-web/dist/plugin-dev-view.js +33 -0
  686. package/packages/client-web/dist/plugin-dev-view.js.map +1 -0
  687. package/packages/client-web/dist/plugin-stars-view.d.ts +28 -0
  688. package/packages/client-web/dist/plugin-stars-view.d.ts.map +1 -1
  689. package/packages/client-web/dist/plugin-stars-view.js +209 -1
  690. package/packages/client-web/dist/plugin-stars-view.js.map +1 -1
  691. package/packages/client-web/dist/react-room.d.ts +5 -1
  692. package/packages/client-web/dist/react-room.d.ts.map +1 -1
  693. package/packages/client-web/dist/react-room.js +463 -219
  694. package/packages/client-web/dist/react-room.js.map +1 -1
  695. package/packages/client-web/dist/readme-gen-view.d.ts +30 -0
  696. package/packages/client-web/dist/readme-gen-view.d.ts.map +1 -0
  697. package/packages/client-web/dist/readme-gen-view.js +134 -0
  698. package/packages/client-web/dist/readme-gen-view.js.map +1 -0
  699. package/packages/client-web/dist/recall-unread-view.d.ts +46 -0
  700. package/packages/client-web/dist/recall-unread-view.d.ts.map +1 -0
  701. package/packages/client-web/dist/recall-unread-view.js +104 -0
  702. package/packages/client-web/dist/recall-unread-view.js.map +1 -0
  703. package/packages/client-web/dist/session-bridge-view.d.ts +50 -0
  704. package/packages/client-web/dist/session-bridge-view.d.ts.map +1 -0
  705. package/packages/client-web/dist/session-bridge-view.js +113 -0
  706. package/packages/client-web/dist/session-bridge-view.js.map +1 -0
  707. package/packages/client-web/dist/session-insights-view.d.ts +40 -0
  708. package/packages/client-web/dist/session-insights-view.d.ts.map +1 -0
  709. package/packages/client-web/dist/session-insights-view.js +157 -0
  710. package/packages/client-web/dist/session-insights-view.js.map +1 -0
  711. package/packages/client-web/dist/skill-guard-view.d.ts +47 -0
  712. package/packages/client-web/dist/skill-guard-view.d.ts.map +1 -0
  713. package/packages/client-web/dist/skill-guard-view.js +93 -0
  714. package/packages/client-web/dist/skill-guard-view.js.map +1 -0
  715. package/packages/client-web/dist/sql-lens-view.d.ts +37 -0
  716. package/packages/client-web/dist/sql-lens-view.d.ts.map +1 -0
  717. package/packages/client-web/dist/sql-lens-view.js +235 -0
  718. package/packages/client-web/dist/sql-lens-view.js.map +1 -0
  719. package/packages/client-web/dist/test-harness-view.d.ts +24 -0
  720. package/packages/client-web/dist/test-harness-view.d.ts.map +1 -0
  721. package/packages/client-web/dist/test-harness-view.js +149 -0
  722. package/packages/client-web/dist/test-harness-view.js.map +1 -0
  723. package/packages/client-web/dist/token-guard-view.d.ts +19 -0
  724. package/packages/client-web/dist/token-guard-view.d.ts.map +1 -0
  725. package/packages/client-web/dist/token-guard-view.js +56 -0
  726. package/packages/client-web/dist/token-guard-view.js.map +1 -0
  727. package/packages/client-web/dist/turn-rewind-view.d.ts +41 -0
  728. package/packages/client-web/dist/turn-rewind-view.d.ts.map +1 -0
  729. package/packages/client-web/dist/turn-rewind-view.js +117 -0
  730. package/packages/client-web/dist/turn-rewind-view.js.map +1 -0
  731. package/packages/client-web/dist/vision-toolkit-view.d.ts +66 -0
  732. package/packages/client-web/dist/vision-toolkit-view.d.ts.map +1 -0
  733. package/packages/client-web/dist/vision-toolkit-view.js +238 -0
  734. package/packages/client-web/dist/vision-toolkit-view.js.map +1 -0
  735. package/packages/client-web/dist/yaml-validator-view.d.ts +52 -0
  736. package/packages/client-web/dist/yaml-validator-view.d.ts.map +1 -0
  737. package/packages/client-web/dist/yaml-validator-view.js +96 -0
  738. package/packages/client-web/dist/yaml-validator-view.js.map +1 -0
  739. package/packages/client-web/package.json +1 -1
  740. package/packages/client-web/src/agent-teams-view.ts +189 -0
  741. package/packages/client-web/src/at-file-view.ts +69 -0
  742. package/packages/client-web/src/browser-fetch-view.ts +114 -0
  743. package/packages/client-web/src/browser-session-view.ts +222 -3
  744. package/packages/client-web/src/cleaner-view.ts +207 -0
  745. package/packages/client-web/src/context-doctor-view.ts +140 -0
  746. package/packages/client-web/src/context-insights-view.ts +125 -0
  747. package/packages/client-web/src/cost-meter-view.ts +63 -0
  748. package/packages/client-web/src/dependency-checker-view.ts +215 -0
  749. package/packages/client-web/src/docker-sandbox-view.ts +177 -0
  750. package/packages/client-web/src/fail-logger-view.ts +112 -0
  751. package/packages/client-web/src/genui-view.ts +88 -0
  752. package/packages/client-web/src/git-time-capsule-view.ts +215 -0
  753. package/packages/client-web/src/graph-memory-view.ts +91 -0
  754. package/packages/client-web/src/i18n-pair-view.ts +194 -0
  755. package/packages/client-web/src/mcp-client-view.ts +122 -0
  756. package/packages/client-web/src/modlens-view.ts +210 -0
  757. package/packages/client-web/src/openpets-view.ts +67 -0
  758. package/packages/client-web/src/panel-safe.ts +47 -0
  759. package/packages/client-web/src/plugin-dev-view.ts +39 -0
  760. package/packages/client-web/src/plugin-stars-view.ts +239 -1
  761. package/packages/client-web/src/react-room.tsx +1770 -900
  762. package/packages/client-web/src/readme-gen-view.ts +145 -0
  763. package/packages/client-web/src/recall-unread-view.ts +105 -0
  764. package/packages/client-web/src/session-bridge-view.ts +118 -0
  765. package/packages/client-web/src/session-insights-view.ts +205 -0
  766. package/packages/client-web/src/skill-guard-view.ts +94 -0
  767. package/packages/client-web/src/sql-lens-view.ts +247 -0
  768. package/packages/client-web/src/test-harness-view.ts +170 -0
  769. package/packages/client-web/src/token-guard-view.ts +75 -0
  770. package/packages/client-web/src/turn-rewind-view.ts +120 -0
  771. package/packages/client-web/src/vision-toolkit-view.ts +280 -0
  772. package/packages/client-web/src/yaml-validator-view.ts +102 -0
  773. package/packages/client-web/test/agent-teams-view.test.ts +198 -0
  774. package/packages/client-web/test/at-file-panel.test.ts +76 -0
  775. package/packages/client-web/test/browser-fetch-panel.test.ts +44 -0
  776. package/packages/client-web/test/browser-fetch-view.test.ts +89 -0
  777. package/packages/client-web/test/browser-session-panel.test.ts +55 -0
  778. package/packages/client-web/test/browser-session-view.test.ts +99 -1
  779. package/packages/client-web/test/cleaner-panel.test.ts +66 -0
  780. package/packages/client-web/test/cleaner-view.test.ts +143 -0
  781. package/packages/client-web/test/context-doctor-view.test.ts +169 -0
  782. package/packages/client-web/test/context-insights-view.test.ts +120 -0
  783. package/packages/client-web/test/cost-meter-view.test.ts +53 -0
  784. package/packages/client-web/test/dependency-checker-panel.test.ts +51 -0
  785. package/packages/client-web/test/dependency-checker-view.test.ts +266 -0
  786. package/packages/client-web/test/docker-sandbox-panel.test.ts +44 -0
  787. package/packages/client-web/test/docker-sandbox-view.test.ts +127 -0
  788. package/packages/client-web/test/fail-logger-view.test.ts +155 -0
  789. package/packages/client-web/test/genui-view.test.ts +55 -0
  790. package/packages/client-web/test/git-time-capsule-view.test.ts +252 -0
  791. package/packages/client-web/test/graph-memory-view.test.ts +67 -0
  792. package/packages/client-web/test/i18n-pair-panel.test.ts +72 -0
  793. package/packages/client-web/test/i18n-pair-view.test.ts +164 -0
  794. package/packages/client-web/test/mcp-client-view.test.ts +106 -0
  795. package/packages/client-web/test/modlens-view.test.ts +198 -0
  796. package/packages/client-web/test/openpets-view.test.ts +57 -0
  797. package/packages/client-web/test/plugin-dev-view.test.ts +63 -0
  798. package/packages/client-web/test/plugin-stars-panel.test.ts +44 -0
  799. package/packages/client-web/test/plugin-stars-view.test.ts +88 -1
  800. package/packages/client-web/test/readme-gen-panel.test.ts +81 -0
  801. package/packages/client-web/test/readme-gen-view.test.ts +91 -0
  802. package/packages/client-web/test/recall-unread-view.test.ts +153 -0
  803. package/packages/client-web/test/session-bridge-view.test.ts +102 -0
  804. package/packages/client-web/test/session-insights-panel.test.ts +85 -0
  805. package/packages/client-web/test/session-insights-view.test.ts +152 -0
  806. package/packages/client-web/test/skill-guard-view.test.ts +138 -0
  807. package/packages/client-web/test/sql-lens-panel.test.ts +52 -0
  808. package/packages/client-web/test/sql-lens-view.test.ts +134 -0
  809. package/packages/client-web/test/test-harness-panel.test.ts +228 -0
  810. package/packages/client-web/test/token-guard-view.test.ts +93 -0
  811. package/packages/client-web/test/turn-rewind-view.test.ts +159 -0
  812. package/packages/client-web/test/vision-toolkit-view.test.ts +152 -0
  813. package/packages/client-web/test/yaml-validator-view.test.ts +100 -0
  814. package/packages/core/dist/atomic-write.d.ts +8 -0
  815. package/packages/core/dist/atomic-write.d.ts.map +1 -0
  816. package/packages/core/dist/atomic-write.js +40 -0
  817. package/packages/core/dist/atomic-write.js.map +1 -0
  818. package/packages/core/dist/boot.d.ts.map +1 -1
  819. package/packages/core/dist/boot.js +132 -10
  820. package/packages/core/dist/boot.js.map +1 -1
  821. package/packages/core/dist/bounded-file.d.ts +7 -0
  822. package/packages/core/dist/bounded-file.d.ts.map +1 -0
  823. package/packages/core/dist/bounded-file.js +50 -0
  824. package/packages/core/dist/bounded-file.js.map +1 -0
  825. package/packages/core/dist/config.d.ts +2 -0
  826. package/packages/core/dist/config.d.ts.map +1 -1
  827. package/packages/core/dist/config.js +21 -0
  828. package/packages/core/dist/config.js.map +1 -1
  829. package/packages/core/dist/cordis-timer.d.ts +15 -0
  830. package/packages/core/dist/cordis-timer.d.ts.map +1 -0
  831. package/packages/core/dist/cordis-timer.js +99 -0
  832. package/packages/core/dist/cordis-timer.js.map +1 -0
  833. package/packages/core/dist/plugins/agent-teams.d.ts +5 -1
  834. package/packages/core/dist/plugins/agent-teams.d.ts.map +1 -1
  835. package/packages/core/dist/plugins/agent-teams.js +986 -105
  836. package/packages/core/dist/plugins/agent-teams.js.map +1 -1
  837. package/packages/core/dist/plugins/anchored-standard.d.ts +1 -0
  838. package/packages/core/dist/plugins/anchored-standard.d.ts.map +1 -1
  839. package/packages/core/dist/plugins/anchored-standard.js +39 -11
  840. package/packages/core/dist/plugins/anchored-standard.js.map +1 -1
  841. package/packages/core/dist/plugins/annotation.d.ts +1 -0
  842. package/packages/core/dist/plugins/annotation.d.ts.map +1 -1
  843. package/packages/core/dist/plugins/annotation.js +35 -17
  844. package/packages/core/dist/plugins/annotation.js.map +1 -1
  845. package/packages/core/dist/plugins/archify.d.ts +1 -0
  846. package/packages/core/dist/plugins/archify.d.ts.map +1 -1
  847. package/packages/core/dist/plugins/archify.js +69 -22
  848. package/packages/core/dist/plugins/archify.js.map +1 -1
  849. package/packages/core/dist/plugins/at-file.d.ts +5 -1
  850. package/packages/core/dist/plugins/at-file.d.ts.map +1 -1
  851. package/packages/core/dist/plugins/at-file.js +120 -29
  852. package/packages/core/dist/plugins/at-file.js.map +1 -1
  853. package/packages/core/dist/plugins/auto-mode.d.ts.map +1 -1
  854. package/packages/core/dist/plugins/auto-mode.js +89 -20
  855. package/packages/core/dist/plugins/auto-mode.js.map +1 -1
  856. package/packages/core/dist/plugins/better-sidebar.d.ts +1 -0
  857. package/packages/core/dist/plugins/better-sidebar.d.ts.map +1 -1
  858. package/packages/core/dist/plugins/better-sidebar.js +14 -4
  859. package/packages/core/dist/plugins/better-sidebar.js.map +1 -1
  860. package/packages/core/dist/plugins/browser-fetch.d.ts +1 -0
  861. package/packages/core/dist/plugins/browser-fetch.d.ts.map +1 -1
  862. package/packages/core/dist/plugins/browser-fetch.js +288 -96
  863. package/packages/core/dist/plugins/browser-fetch.js.map +1 -1
  864. package/packages/core/dist/plugins/browser-session.d.ts.map +1 -1
  865. package/packages/core/dist/plugins/browser-session.js +445 -106
  866. package/packages/core/dist/plugins/browser-session.js.map +1 -1
  867. package/packages/core/dist/plugins/canvas-draw.d.ts +1 -0
  868. package/packages/core/dist/plugins/canvas-draw.d.ts.map +1 -1
  869. package/packages/core/dist/plugins/canvas-draw.js +71 -19
  870. package/packages/core/dist/plugins/canvas-draw.js.map +1 -1
  871. package/packages/core/dist/plugins/change-verifier.d.ts +1 -0
  872. package/packages/core/dist/plugins/change-verifier.d.ts.map +1 -1
  873. package/packages/core/dist/plugins/change-verifier.js +30 -9
  874. package/packages/core/dist/plugins/change-verifier.js.map +1 -1
  875. package/packages/core/dist/plugins/cleaner.d.ts +5 -1
  876. package/packages/core/dist/plugins/cleaner.d.ts.map +1 -1
  877. package/packages/core/dist/plugins/cleaner.js +337 -40
  878. package/packages/core/dist/plugins/cleaner.js.map +1 -1
  879. package/packages/core/dist/plugins/cli-notifier.d.ts +2 -1
  880. package/packages/core/dist/plugins/cli-notifier.d.ts.map +1 -1
  881. package/packages/core/dist/plugins/cli-notifier.js +99 -42
  882. package/packages/core/dist/plugins/cli-notifier.js.map +1 -1
  883. package/packages/core/dist/plugins/code2skill.d.ts +1 -0
  884. package/packages/core/dist/plugins/code2skill.d.ts.map +1 -1
  885. package/packages/core/dist/plugins/code2skill.js +178 -38
  886. package/packages/core/dist/plugins/code2skill.js.map +1 -1
  887. package/packages/core/dist/plugins/colleague-skill.d.ts +2 -1
  888. package/packages/core/dist/plugins/colleague-skill.d.ts.map +1 -1
  889. package/packages/core/dist/plugins/colleague-skill.js +79 -49
  890. package/packages/core/dist/plugins/colleague-skill.js.map +1 -1
  891. package/packages/core/dist/plugins/context-doctor.d.ts +6 -1
  892. package/packages/core/dist/plugins/context-doctor.d.ts.map +1 -1
  893. package/packages/core/dist/plugins/context-doctor.js +403 -39
  894. package/packages/core/dist/plugins/context-doctor.js.map +1 -1
  895. package/packages/core/dist/plugins/context.d.ts +1 -0
  896. package/packages/core/dist/plugins/context.d.ts.map +1 -1
  897. package/packages/core/dist/plugins/context.js +169 -42
  898. package/packages/core/dist/plugins/context.js.map +1 -1
  899. package/packages/core/dist/plugins/cost-meter.d.ts +4 -0
  900. package/packages/core/dist/plugins/cost-meter.d.ts.map +1 -1
  901. package/packages/core/dist/plugins/cost-meter.js +319 -93
  902. package/packages/core/dist/plugins/cost-meter.js.map +1 -1
  903. package/packages/core/dist/plugins/dependency-checker.d.ts +11 -2
  904. package/packages/core/dist/plugins/dependency-checker.d.ts.map +1 -1
  905. package/packages/core/dist/plugins/dependency-checker.js +463 -114
  906. package/packages/core/dist/plugins/dependency-checker.js.map +1 -1
  907. package/packages/core/dist/plugins/docker-sandbox.d.ts +1 -0
  908. package/packages/core/dist/plugins/docker-sandbox.d.ts.map +1 -1
  909. package/packages/core/dist/plugins/docker-sandbox.js +322 -80
  910. package/packages/core/dist/plugins/docker-sandbox.js.map +1 -1
  911. package/packages/core/dist/plugins/fail-logger.d.ts +1 -0
  912. package/packages/core/dist/plugins/fail-logger.d.ts.map +1 -1
  913. package/packages/core/dist/plugins/fail-logger.js +187 -20
  914. package/packages/core/dist/plugins/fail-logger.js.map +1 -1
  915. package/packages/core/dist/plugins/genui.d.ts +1 -0
  916. package/packages/core/dist/plugins/genui.d.ts.map +1 -1
  917. package/packages/core/dist/plugins/genui.js +103 -38
  918. package/packages/core/dist/plugins/genui.js.map +1 -1
  919. package/packages/core/dist/plugins/git-time-capsule.d.ts +8 -2
  920. package/packages/core/dist/plugins/git-time-capsule.d.ts.map +1 -1
  921. package/packages/core/dist/plugins/git-time-capsule.js +400 -54
  922. package/packages/core/dist/plugins/git-time-capsule.js.map +1 -1
  923. package/packages/core/dist/plugins/graph-memory.d.ts.map +1 -1
  924. package/packages/core/dist/plugins/graph-memory.js +329 -42
  925. package/packages/core/dist/plugins/graph-memory.js.map +1 -1
  926. package/packages/core/dist/plugins/history-compressor.d.ts.map +1 -1
  927. package/packages/core/dist/plugins/history-compressor.js +31 -12
  928. package/packages/core/dist/plugins/history-compressor.js.map +1 -1
  929. package/packages/core/dist/plugins/hol-guard.d.ts.map +1 -1
  930. package/packages/core/dist/plugins/hol-guard.js +33 -13
  931. package/packages/core/dist/plugins/hol-guard.js.map +1 -1
  932. package/packages/core/dist/plugins/i18n-pair.d.ts +5 -1
  933. package/packages/core/dist/plugins/i18n-pair.d.ts.map +1 -1
  934. package/packages/core/dist/plugins/i18n-pair.js +308 -52
  935. package/packages/core/dist/plugins/i18n-pair.js.map +1 -1
  936. package/packages/core/dist/plugins/image-compressor.d.ts +7 -0
  937. package/packages/core/dist/plugins/image-compressor.d.ts.map +1 -1
  938. package/packages/core/dist/plugins/image-compressor.js +98 -25
  939. package/packages/core/dist/plugins/image-compressor.js.map +1 -1
  940. package/packages/core/dist/plugins/llm-verifier.d.ts.map +1 -1
  941. package/packages/core/dist/plugins/llm-verifier.js +21 -11
  942. package/packages/core/dist/plugins/llm-verifier.js.map +1 -1
  943. package/packages/core/dist/plugins/mcp-client.d.ts.map +1 -1
  944. package/packages/core/dist/plugins/mcp-client.js +986 -232
  945. package/packages/core/dist/plugins/mcp-client.js.map +1 -1
  946. package/packages/core/dist/plugins/mcp-panel.d.ts.map +1 -1
  947. package/packages/core/dist/plugins/mcp-panel.js +30 -16
  948. package/packages/core/dist/plugins/mcp-panel.js.map +1 -1
  949. package/packages/core/dist/plugins/memory.d.ts.map +1 -1
  950. package/packages/core/dist/plugins/memory.js +292 -59
  951. package/packages/core/dist/plugins/memory.js.map +1 -1
  952. package/packages/core/dist/plugins/mirage-bridge.d.ts.map +1 -1
  953. package/packages/core/dist/plugins/mirage-bridge.js +20 -10
  954. package/packages/core/dist/plugins/mirage-bridge.js.map +1 -1
  955. package/packages/core/dist/plugins/mock-server.d.ts.map +1 -1
  956. package/packages/core/dist/plugins/mock-server.js +85 -54
  957. package/packages/core/dist/plugins/mock-server.js.map +1 -1
  958. package/packages/core/dist/plugins/model.d.ts +3 -0
  959. package/packages/core/dist/plugins/model.d.ts.map +1 -1
  960. package/packages/core/dist/plugins/model.js +3 -0
  961. package/packages/core/dist/plugins/model.js.map +1 -1
  962. package/packages/core/dist/plugins/models.d.ts.map +1 -1
  963. package/packages/core/dist/plugins/models.js +10 -2
  964. package/packages/core/dist/plugins/models.js.map +1 -1
  965. package/packages/core/dist/plugins/modlens.d.ts +8 -1
  966. package/packages/core/dist/plugins/modlens.d.ts.map +1 -1
  967. package/packages/core/dist/plugins/modlens.js +438 -31
  968. package/packages/core/dist/plugins/modlens.js.map +1 -1
  969. package/packages/core/dist/plugins/module-search.d.ts +1 -0
  970. package/packages/core/dist/plugins/module-search.d.ts.map +1 -1
  971. package/packages/core/dist/plugins/module-search.js +35 -16
  972. package/packages/core/dist/plugins/module-search.js.map +1 -1
  973. package/packages/core/dist/plugins/obsidian-sync.d.ts.map +1 -1
  974. package/packages/core/dist/plugins/obsidian-sync.js +20 -11
  975. package/packages/core/dist/plugins/obsidian-sync.js.map +1 -1
  976. package/packages/core/dist/plugins/openpets.d.ts.map +1 -1
  977. package/packages/core/dist/plugins/openpets.js +203 -44
  978. package/packages/core/dist/plugins/openpets.js.map +1 -1
  979. package/packages/core/dist/plugins/plan-execute.d.ts +4 -1
  980. package/packages/core/dist/plugins/plan-execute.d.ts.map +1 -1
  981. package/packages/core/dist/plugins/plan-execute.js +42 -21
  982. package/packages/core/dist/plugins/plan-execute.js.map +1 -1
  983. package/packages/core/dist/plugins/plugin-check.d.ts +12 -3
  984. package/packages/core/dist/plugins/plugin-check.d.ts.map +1 -1
  985. package/packages/core/dist/plugins/plugin-check.js +83 -12
  986. package/packages/core/dist/plugins/plugin-check.js.map +1 -1
  987. package/packages/core/dist/plugins/plugin-dev.d.ts +1 -0
  988. package/packages/core/dist/plugins/plugin-dev.d.ts.map +1 -1
  989. package/packages/core/dist/plugins/plugin-dev.js +156 -23
  990. package/packages/core/dist/plugins/plugin-dev.js.map +1 -1
  991. package/packages/core/dist/plugins/plugin-finder.d.ts +1 -0
  992. package/packages/core/dist/plugins/plugin-finder.d.ts.map +1 -1
  993. package/packages/core/dist/plugins/plugin-finder.js +131 -13
  994. package/packages/core/dist/plugins/plugin-finder.js.map +1 -1
  995. package/packages/core/dist/plugins/plugin-radar.d.ts +4 -0
  996. package/packages/core/dist/plugins/plugin-radar.d.ts.map +1 -1
  997. package/packages/core/dist/plugins/plugin-radar.js +137 -36
  998. package/packages/core/dist/plugins/plugin-radar.js.map +1 -1
  999. package/packages/core/dist/plugins/plugin-stars.d.ts.map +1 -1
  1000. package/packages/core/dist/plugins/plugin-stars.js +282 -81
  1001. package/packages/core/dist/plugins/plugin-stars.js.map +1 -1
  1002. package/packages/core/dist/plugins/prompt-guard.d.ts +1 -0
  1003. package/packages/core/dist/plugins/prompt-guard.d.ts.map +1 -1
  1004. package/packages/core/dist/plugins/prompt-guard.js +60 -9
  1005. package/packages/core/dist/plugins/prompt-guard.js.map +1 -1
  1006. package/packages/core/dist/plugins/prompt-library.d.ts +1 -0
  1007. package/packages/core/dist/plugins/prompt-library.d.ts.map +1 -1
  1008. package/packages/core/dist/plugins/prompt-library.js +4 -1
  1009. package/packages/core/dist/plugins/prompt-library.js.map +1 -1
  1010. package/packages/core/dist/plugins/readme-gen.d.ts +6 -2
  1011. package/packages/core/dist/plugins/readme-gen.d.ts.map +1 -1
  1012. package/packages/core/dist/plugins/readme-gen.js +514 -73
  1013. package/packages/core/dist/plugins/readme-gen.js.map +1 -1
  1014. package/packages/core/dist/plugins/recall-unread.d.ts +1 -1
  1015. package/packages/core/dist/plugins/recall-unread.d.ts.map +1 -1
  1016. package/packages/core/dist/plugins/recall-unread.js +411 -68
  1017. package/packages/core/dist/plugins/recall-unread.js.map +1 -1
  1018. package/packages/core/dist/plugins/resources.d.ts.map +1 -1
  1019. package/packages/core/dist/plugins/resources.js +66 -3
  1020. package/packages/core/dist/plugins/resources.js.map +1 -1
  1021. package/packages/core/dist/plugins/reverse-skill.d.ts.map +1 -1
  1022. package/packages/core/dist/plugins/reverse-skill.js +2 -1
  1023. package/packages/core/dist/plugins/reverse-skill.js.map +1 -1
  1024. package/packages/core/dist/plugins/reviewer-bot.d.ts +1 -0
  1025. package/packages/core/dist/plugins/reviewer-bot.d.ts.map +1 -1
  1026. package/packages/core/dist/plugins/reviewer-bot.js +35 -16
  1027. package/packages/core/dist/plugins/reviewer-bot.js.map +1 -1
  1028. package/packages/core/dist/plugins/runtime-doctor.d.ts +1 -0
  1029. package/packages/core/dist/plugins/runtime-doctor.d.ts.map +1 -1
  1030. package/packages/core/dist/plugins/runtime-doctor.js +4 -1
  1031. package/packages/core/dist/plugins/runtime-doctor.js.map +1 -1
  1032. package/packages/core/dist/plugins/runtime.d.ts.map +1 -1
  1033. package/packages/core/dist/plugins/runtime.js +104 -70
  1034. package/packages/core/dist/plugins/runtime.js.map +1 -1
  1035. package/packages/core/dist/plugins/secure-audit.d.ts +1 -0
  1036. package/packages/core/dist/plugins/secure-audit.d.ts.map +1 -1
  1037. package/packages/core/dist/plugins/secure-audit.js +30 -12
  1038. package/packages/core/dist/plugins/secure-audit.js.map +1 -1
  1039. package/packages/core/dist/plugins/session-bookmarks.d.ts +1 -0
  1040. package/packages/core/dist/plugins/session-bookmarks.d.ts.map +1 -1
  1041. package/packages/core/dist/plugins/session-bookmarks.js +4 -1
  1042. package/packages/core/dist/plugins/session-bookmarks.js.map +1 -1
  1043. package/packages/core/dist/plugins/session-bridge.d.ts +1 -0
  1044. package/packages/core/dist/plugins/session-bridge.d.ts.map +1 -1
  1045. package/packages/core/dist/plugins/session-bridge.js +401 -88
  1046. package/packages/core/dist/plugins/session-bridge.js.map +1 -1
  1047. package/packages/core/dist/plugins/session-compare.d.ts +1 -0
  1048. package/packages/core/dist/plugins/session-compare.d.ts.map +1 -1
  1049. package/packages/core/dist/plugins/session-compare.js +4 -1
  1050. package/packages/core/dist/plugins/session-compare.js.map +1 -1
  1051. package/packages/core/dist/plugins/session-export.d.ts +1 -0
  1052. package/packages/core/dist/plugins/session-export.d.ts.map +1 -1
  1053. package/packages/core/dist/plugins/session-export.js +6 -6
  1054. package/packages/core/dist/plugins/session-export.js.map +1 -1
  1055. package/packages/core/dist/plugins/session-insights.d.ts +37 -1
  1056. package/packages/core/dist/plugins/session-insights.d.ts.map +1 -1
  1057. package/packages/core/dist/plugins/session-insights.js +406 -21
  1058. package/packages/core/dist/plugins/session-insights.js.map +1 -1
  1059. package/packages/core/dist/plugins/session-search.d.ts +1 -0
  1060. package/packages/core/dist/plugins/session-search.d.ts.map +1 -1
  1061. package/packages/core/dist/plugins/session-search.js +4 -1
  1062. package/packages/core/dist/plugins/session-search.js.map +1 -1
  1063. package/packages/core/dist/plugins/session.d.ts.map +1 -1
  1064. package/packages/core/dist/plugins/session.js +8 -1
  1065. package/packages/core/dist/plugins/session.js.map +1 -1
  1066. package/packages/core/dist/plugins/skill-catalog.d.ts +1 -0
  1067. package/packages/core/dist/plugins/skill-catalog.d.ts.map +1 -1
  1068. package/packages/core/dist/plugins/skill-catalog.js +6 -5
  1069. package/packages/core/dist/plugins/skill-catalog.js.map +1 -1
  1070. package/packages/core/dist/plugins/skill-guard.d.ts +2 -1
  1071. package/packages/core/dist/plugins/skill-guard.d.ts.map +1 -1
  1072. package/packages/core/dist/plugins/skill-guard.js +241 -61
  1073. package/packages/core/dist/plugins/skill-guard.js.map +1 -1
  1074. package/packages/core/dist/plugins/sql-lens-worker.d.ts +2 -0
  1075. package/packages/core/dist/plugins/sql-lens-worker.d.ts.map +1 -0
  1076. package/packages/core/dist/plugins/sql-lens-worker.js +206 -0
  1077. package/packages/core/dist/plugins/sql-lens-worker.js.map +1 -0
  1078. package/packages/core/dist/plugins/sql-lens.d.ts +7 -1
  1079. package/packages/core/dist/plugins/sql-lens.d.ts.map +1 -1
  1080. package/packages/core/dist/plugins/sql-lens.js +301 -68
  1081. package/packages/core/dist/plugins/sql-lens.js.map +1 -1
  1082. package/packages/core/dist/plugins/stdio.d.ts +3 -0
  1083. package/packages/core/dist/plugins/stdio.d.ts.map +1 -1
  1084. package/packages/core/dist/plugins/stdio.js +62 -4
  1085. package/packages/core/dist/plugins/stdio.js.map +1 -1
  1086. package/packages/core/dist/plugins/synapse.d.ts.map +1 -1
  1087. package/packages/core/dist/plugins/synapse.js +17 -9
  1088. package/packages/core/dist/plugins/synapse.js.map +1 -1
  1089. package/packages/core/dist/plugins/tab-manager.d.ts +1 -0
  1090. package/packages/core/dist/plugins/tab-manager.d.ts.map +1 -1
  1091. package/packages/core/dist/plugins/tab-manager.js +167 -62
  1092. package/packages/core/dist/plugins/tab-manager.js.map +1 -1
  1093. package/packages/core/dist/plugins/taskboard.d.ts.map +1 -1
  1094. package/packages/core/dist/plugins/taskboard.js +50 -22
  1095. package/packages/core/dist/plugins/taskboard.js.map +1 -1
  1096. package/packages/core/dist/plugins/telemetry-blocker.d.ts +4 -1
  1097. package/packages/core/dist/plugins/telemetry-blocker.d.ts.map +1 -1
  1098. package/packages/core/dist/plugins/telemetry-blocker.js +30 -11
  1099. package/packages/core/dist/plugins/telemetry-blocker.js.map +1 -1
  1100. package/packages/core/dist/plugins/test-harness.d.ts +7 -1
  1101. package/packages/core/dist/plugins/test-harness.d.ts.map +1 -1
  1102. package/packages/core/dist/plugins/test-harness.js +255 -43
  1103. package/packages/core/dist/plugins/test-harness.js.map +1 -1
  1104. package/packages/core/dist/plugins/theme-studio.d.ts.map +1 -1
  1105. package/packages/core/dist/plugins/theme-studio.js +4 -2
  1106. package/packages/core/dist/plugins/theme-studio.js.map +1 -1
  1107. package/packages/core/dist/plugins/token-guard.d.ts.map +1 -1
  1108. package/packages/core/dist/plugins/token-guard.js +164 -32
  1109. package/packages/core/dist/plugins/token-guard.js.map +1 -1
  1110. package/packages/core/dist/plugins/tools.d.ts.map +1 -1
  1111. package/packages/core/dist/plugins/tools.js +4 -1
  1112. package/packages/core/dist/plugins/tools.js.map +1 -1
  1113. package/packages/core/dist/plugins/turn-rewind.d.ts +17 -0
  1114. package/packages/core/dist/plugins/turn-rewind.d.ts.map +1 -1
  1115. package/packages/core/dist/plugins/turn-rewind.js +340 -36
  1116. package/packages/core/dist/plugins/turn-rewind.js.map +1 -1
  1117. package/packages/core/dist/plugins/undo-savepoint.d.ts.map +1 -1
  1118. package/packages/core/dist/plugins/undo-savepoint.js +157 -51
  1119. package/packages/core/dist/plugins/undo-savepoint.js.map +1 -1
  1120. package/packages/core/dist/plugins/vision-toolkit.d.ts +22 -3
  1121. package/packages/core/dist/plugins/vision-toolkit.d.ts.map +1 -1
  1122. package/packages/core/dist/plugins/vision-toolkit.js +389 -66
  1123. package/packages/core/dist/plugins/vision-toolkit.js.map +1 -1
  1124. package/packages/core/dist/plugins/web-research.d.ts.map +1 -1
  1125. package/packages/core/dist/plugins/web-research.js +13 -4
  1126. package/packages/core/dist/plugins/web-research.js.map +1 -1
  1127. package/packages/core/dist/plugins/workspace-navigator.d.ts +8 -2
  1128. package/packages/core/dist/plugins/workspace-navigator.d.ts.map +1 -1
  1129. package/packages/core/dist/plugins/workspace-navigator.js +28 -10
  1130. package/packages/core/dist/plugins/workspace-navigator.js.map +1 -1
  1131. package/packages/core/dist/plugins/workspace-search.d.ts +7 -0
  1132. package/packages/core/dist/plugins/workspace-search.d.ts.map +1 -1
  1133. package/packages/core/dist/plugins/workspace-search.js +67 -34
  1134. package/packages/core/dist/plugins/workspace-search.js.map +1 -1
  1135. package/packages/core/dist/plugins/yaml-validator.d.ts +1 -0
  1136. package/packages/core/dist/plugins/yaml-validator.d.ts.map +1 -1
  1137. package/packages/core/dist/plugins/yaml-validator.js +156 -47
  1138. package/packages/core/dist/plugins/yaml-validator.js.map +1 -1
  1139. package/packages/core/dist/runtime.d.ts.map +1 -1
  1140. package/packages/core/dist/runtime.js +8 -3
  1141. package/packages/core/dist/runtime.js.map +1 -1
  1142. package/packages/core/dist/services.d.ts.map +1 -1
  1143. package/packages/core/dist/services.js +22 -2
  1144. package/packages/core/dist/services.js.map +1 -1
  1145. package/packages/core/dist/stdio.d.ts +1 -0
  1146. package/packages/core/dist/stdio.d.ts.map +1 -1
  1147. package/packages/core/dist/stdio.js +241 -25
  1148. package/packages/core/dist/stdio.js.map +1 -1
  1149. package/packages/core/dist/workspace-path.d.ts +1 -0
  1150. package/packages/core/dist/workspace-path.d.ts.map +1 -1
  1151. package/packages/core/dist/workspace-path.js +9 -0
  1152. package/packages/core/dist/workspace-path.js.map +1 -1
  1153. package/packages/core/package.json +1 -1
  1154. package/packages/core/profiles/default/cordis.yml +4 -2
  1155. package/packages/core/src/atomic-write.ts +45 -0
  1156. package/packages/core/src/boot.ts +123 -11
  1157. package/packages/core/src/bounded-file.ts +41 -0
  1158. package/packages/core/src/config.ts +18 -0
  1159. package/packages/core/src/cordis-timer.ts +107 -0
  1160. package/packages/core/src/plugins/agent-teams.ts +1003 -103
  1161. package/packages/core/src/plugins/anchored-standard.ts +41 -14
  1162. package/packages/core/src/plugins/annotation.ts +36 -19
  1163. package/packages/core/src/plugins/archify.ts +80 -33
  1164. package/packages/core/src/plugins/at-file.ts +110 -26
  1165. package/packages/core/src/plugins/auto-mode.ts +91 -24
  1166. package/packages/core/src/plugins/better-sidebar.ts +15 -4
  1167. package/packages/core/src/plugins/browser-fetch.ts +286 -95
  1168. package/packages/core/src/plugins/browser-session.ts +421 -102
  1169. package/packages/core/src/plugins/canvas-draw.ts +74 -21
  1170. package/packages/core/src/plugins/change-verifier.ts +33 -9
  1171. package/packages/core/src/plugins/cleaner.ts +339 -37
  1172. package/packages/core/src/plugins/cli-notifier.ts +110 -41
  1173. package/packages/core/src/plugins/code2skill.ts +175 -34
  1174. package/packages/core/src/plugins/colleague-skill.ts +72 -47
  1175. package/packages/core/src/plugins/context-doctor.ts +410 -40
  1176. package/packages/core/src/plugins/context.ts +164 -39
  1177. package/packages/core/src/plugins/cost-meter.ts +360 -113
  1178. package/packages/core/src/plugins/dependency-checker.ts +456 -119
  1179. package/packages/core/src/plugins/docker-sandbox.ts +312 -76
  1180. package/packages/core/src/plugins/fail-logger.ts +169 -18
  1181. package/packages/core/src/plugins/genui.ts +104 -42
  1182. package/packages/core/src/plugins/git-time-capsule.ts +424 -55
  1183. package/packages/core/src/plugins/graph-memory.ts +333 -60
  1184. package/packages/core/src/plugins/history-compressor.ts +29 -12
  1185. package/packages/core/src/plugins/hol-guard.ts +31 -13
  1186. package/packages/core/src/plugins/i18n-pair.ts +296 -52
  1187. package/packages/core/src/plugins/image-compressor.ts +98 -25
  1188. package/packages/core/src/plugins/llm-verifier.ts +39 -21
  1189. package/packages/core/src/plugins/mcp-client.ts +1069 -249
  1190. package/packages/core/src/plugins/mcp-panel.ts +37 -21
  1191. package/packages/core/src/plugins/memory.ts +262 -57
  1192. package/packages/core/src/plugins/mirage-bridge.ts +22 -10
  1193. package/packages/core/src/plugins/mock-server.ts +91 -60
  1194. package/packages/core/src/plugins/model.ts +4 -0
  1195. package/packages/core/src/plugins/models.ts +10 -2
  1196. package/packages/core/src/plugins/modlens.ts +463 -29
  1197. package/packages/core/src/plugins/module-search.ts +40 -19
  1198. package/packages/core/src/plugins/obsidian-sync.ts +26 -15
  1199. package/packages/core/src/plugins/openpets.ts +193 -42
  1200. package/packages/core/src/plugins/plan-execute.ts +49 -21
  1201. package/packages/core/src/plugins/plugin-check.ts +100 -16
  1202. package/packages/core/src/plugins/plugin-dev.ts +167 -23
  1203. package/packages/core/src/plugins/plugin-finder.ts +119 -12
  1204. package/packages/core/src/plugins/plugin-radar.ts +130 -39
  1205. package/packages/core/src/plugins/plugin-stars.ts +252 -80
  1206. package/packages/core/src/plugins/prompt-guard.ts +51 -12
  1207. package/packages/core/src/plugins/prompt-library.ts +14 -8
  1208. package/packages/core/src/plugins/readme-gen.ts +476 -79
  1209. package/packages/core/src/plugins/recall-unread.ts +412 -68
  1210. package/packages/core/src/plugins/resources.ts +70 -2
  1211. package/packages/core/src/plugins/reverse-skill.ts +9 -5
  1212. package/packages/core/src/plugins/reviewer-bot.ts +34 -16
  1213. package/packages/core/src/plugins/runtime-doctor.ts +4 -1
  1214. package/packages/core/src/plugins/runtime.ts +98 -68
  1215. package/packages/core/src/plugins/secure-audit.ts +33 -12
  1216. package/packages/core/src/plugins/session-bookmarks.ts +12 -6
  1217. package/packages/core/src/plugins/session-bridge.ts +404 -89
  1218. package/packages/core/src/plugins/session-compare.ts +10 -4
  1219. package/packages/core/src/plugins/session-export.ts +12 -9
  1220. package/packages/core/src/plugins/session-insights.ts +454 -31
  1221. package/packages/core/src/plugins/session-search.ts +4 -1
  1222. package/packages/core/src/plugins/session.ts +8 -1
  1223. package/packages/core/src/plugins/skill-catalog.ts +13 -8
  1224. package/packages/core/src/plugins/skill-guard.ts +254 -61
  1225. package/packages/core/src/plugins/sql-lens-worker.ts +202 -0
  1226. package/packages/core/src/plugins/sql-lens.ts +323 -71
  1227. package/packages/core/src/plugins/stdio.ts +58 -3
  1228. package/packages/core/src/plugins/synapse.ts +16 -9
  1229. package/packages/core/src/plugins/tab-manager.ts +163 -65
  1230. package/packages/core/src/plugins/taskboard.ts +81 -47
  1231. package/packages/core/src/plugins/telemetry-blocker.ts +27 -11
  1232. package/packages/core/src/plugins/test-harness.ts +275 -42
  1233. package/packages/core/src/plugins/theme-studio.ts +7 -2
  1234. package/packages/core/src/plugins/token-guard.ts +171 -31
  1235. package/packages/core/src/plugins/tools.ts +4 -1
  1236. package/packages/core/src/plugins/turn-rewind.ts +351 -37
  1237. package/packages/core/src/plugins/undo-savepoint.ts +160 -59
  1238. package/packages/core/src/plugins/vision-toolkit.ts +420 -63
  1239. package/packages/core/src/plugins/web-research.ts +19 -7
  1240. package/packages/core/src/plugins/workspace-navigator.ts +39 -14
  1241. package/packages/core/src/plugins/workspace-search.ts +75 -37
  1242. package/packages/core/src/plugins/yaml-validator.ts +165 -46
  1243. package/packages/core/src/runtime.ts +8 -2
  1244. package/packages/core/src/services.ts +22 -2
  1245. package/packages/core/src/stdio.ts +220 -25
  1246. package/packages/core/src/workspace-path.ts +10 -0
  1247. package/packages/core/test/agent-teams.test.ts +495 -2
  1248. package/packages/core/test/anchored-standard.test.ts +60 -0
  1249. package/packages/core/test/annotation.test.ts +69 -0
  1250. package/packages/core/test/archify.test.ts +212 -1
  1251. package/packages/core/test/at-file.test.ts +666 -0
  1252. package/packages/core/test/atomic-write.test.ts +52 -0
  1253. package/packages/core/test/auto-mode.test.ts +629 -0
  1254. package/packages/core/test/better-sidebar.test.ts +108 -1
  1255. package/packages/core/test/boot.test.ts +129 -1
  1256. package/packages/core/test/bounded-file.test.ts +55 -0
  1257. package/packages/core/test/browser-fetch-rebinding.test.ts +93 -0
  1258. package/packages/core/test/browser-fetch.test.ts +844 -0
  1259. package/packages/core/test/browser-session.test.ts +1236 -0
  1260. package/packages/core/test/canvas-draw.test.ts +164 -0
  1261. package/packages/core/test/change-verifier.test.ts +200 -0
  1262. package/packages/core/test/cleaner.test.ts +316 -0
  1263. package/packages/core/test/cli-notifier.test.ts +235 -0
  1264. package/packages/core/test/code2skill.test.ts +264 -0
  1265. package/packages/core/test/colleague-skill.test.ts +167 -0
  1266. package/packages/core/test/config.test.ts +8 -0
  1267. package/packages/core/test/context-doctor.test.ts +597 -2
  1268. package/packages/core/test/context-insights.test.ts +396 -0
  1269. package/packages/core/test/cordis-timer.test.ts +147 -0
  1270. package/packages/core/test/cost-meter.test.ts +362 -0
  1271. package/packages/core/test/dependency-checker.test.ts +576 -3
  1272. package/packages/core/test/docker-sandbox.test.ts +170 -0
  1273. package/packages/core/test/fail-logger.test.ts +363 -0
  1274. package/packages/core/test/genui.test.ts +162 -0
  1275. package/packages/core/test/git-time-capsule.test.ts +1364 -3
  1276. package/packages/core/test/graph-memory.test.ts +508 -0
  1277. package/packages/core/test/history-compressor.test.ts +47 -0
  1278. package/packages/core/test/hol-guard.test.ts +61 -0
  1279. package/packages/core/test/i18n-pair.test.ts +367 -0
  1280. package/packages/core/test/image-compressor.test.ts +59 -0
  1281. package/packages/core/test/llm-verifier.test.ts +4 -0
  1282. package/packages/core/test/mcp-client.test.ts +1037 -0
  1283. package/packages/core/test/mcp-panel.test.ts +91 -0
  1284. package/packages/core/test/memory.test.ts +125 -0
  1285. package/packages/core/test/mirage-bridge.test.ts +4 -0
  1286. package/packages/core/test/mock-server.test.ts +63 -0
  1287. package/packages/core/test/model.test.ts +62 -0
  1288. package/packages/core/test/models.test.ts +85 -0
  1289. package/packages/core/test/modlens.test.ts +615 -0
  1290. package/packages/core/test/module-search.test.ts +20 -0
  1291. package/packages/core/test/obsidian-sync.test.ts +57 -0
  1292. package/packages/core/test/openpets.test.ts +273 -0
  1293. package/packages/core/test/plan-execute.test.ts +86 -0
  1294. package/packages/core/test/plugin-dev.test.ts +246 -0
  1295. package/packages/core/test/plugin-finder.test.ts +105 -0
  1296. package/packages/core/test/plugin-radar.test.ts +87 -0
  1297. package/packages/core/test/plugin-stars.test.ts +429 -4
  1298. package/packages/core/test/profiles.integration.test.ts +451 -2
  1299. package/packages/core/test/prompt-guard.test.ts +78 -0
  1300. package/packages/core/test/readme-gen.test.ts +403 -3
  1301. package/packages/core/test/recall-unread.test.ts +559 -2
  1302. package/packages/core/test/registry.test.ts +16 -0
  1303. package/packages/core/test/resources.test.ts +310 -0
  1304. package/packages/core/test/reviewer-bot.test.ts +55 -0
  1305. package/packages/core/test/runtime-fixture.ts +10 -1
  1306. package/packages/core/test/runtime.test.ts +155 -2
  1307. package/packages/core/test/secure-audit.test.ts +14 -1
  1308. package/packages/core/test/services.test.ts +2772 -117
  1309. package/packages/core/test/session-bridge.test.ts +309 -1
  1310. package/packages/core/test/session-insights.test.ts +486 -0
  1311. package/packages/core/test/session.test.ts +153 -0
  1312. package/packages/core/test/skill-guard.test.ts +261 -2
  1313. package/packages/core/test/sql-lens.test.ts +244 -0
  1314. package/packages/core/test/stdio-args.test.ts +484 -1
  1315. package/packages/core/test/stdio.test.ts +159 -0
  1316. package/packages/core/test/synapse.test.ts +67 -0
  1317. package/packages/core/test/tab-manager.test.ts +58 -0
  1318. package/packages/core/test/taskboard.test.ts +73 -0
  1319. package/packages/core/test/telemetry-blocker.test.ts +61 -0
  1320. package/packages/core/test/test-harness.test.ts +297 -0
  1321. package/packages/core/test/token-guard.test.ts +362 -1
  1322. package/packages/core/test/tools.test.ts +118 -0
  1323. package/packages/core/test/turn-rewind.test.ts +532 -2
  1324. package/packages/core/test/undo-savepoint.test.ts +222 -0
  1325. package/packages/core/test/vision-toolkit.test.ts +480 -7
  1326. package/packages/core/test/web-research.test.ts +63 -0
  1327. package/packages/core/test/workspace-git-status.test.ts +19 -2
  1328. package/packages/core/test/workspace-navigator.test.ts +11 -1
  1329. package/packages/core/test/workspace-search.test.ts +88 -0
  1330. package/packages/core/test/yaml-validator.test.ts +195 -0
  1331. package/packages/host-webserver/package.json +1 -1
  1332. package/apps/web/dist/assets/index-C_AdODuM.js +0 -20
  1333. package/apps/web/dist/assets/index-De8Rm01Z.css +0 -2
@@ -1,7 +1,7 @@
1
1
  import { execFile } from "node:child_process";
2
- import { mkdir, mkdtemp, readFile, readdir, rm, writeFile } from "node:fs/promises";
2
+ import { chmod, mkdir, mkdtemp, readFile, readdir, rm, symlink, writeFile } from "node:fs/promises";
3
3
  import { tmpdir } from "node:os";
4
- import { join } from "node:path";
4
+ import { delimiter, join } from "node:path";
5
5
  import { promisify } from "node:util";
6
6
  import { Context } from "@deepseek-ai/cordis";
7
7
  import { afterEach, describe, expect, test } from "vitest";
@@ -12,6 +12,16 @@ import gitTimeCapsulePlugin from "../src/plugins/git-time-capsule.js";
12
12
  const execFileAsync = promisify(execFile);
13
13
  const temporaryDirectories: string[] = [];
14
14
 
15
+ async function waitForFile(path: string, description: string, timeoutMs = 5_000): Promise<string> {
16
+ const startedAt = Date.now();
17
+ while (true) {
18
+ const value = await readFile(path, "utf8").catch(() => undefined);
19
+ if (value !== undefined) return value;
20
+ if (Date.now() - startedAt >= timeoutMs) throw new Error(`Timed out waiting for ${description}`);
21
+ await new Promise((resolve) => setTimeout(resolve, 10));
22
+ }
23
+ }
24
+
15
25
  afterEach(async () => {
16
26
  await Promise.all(temporaryDirectories.splice(0).map((directory) => rm(directory, { recursive: true, force: true })));
17
27
  });
@@ -50,6 +60,93 @@ describe("git time capsule restore", () => {
50
60
  await expect(readFile(join(workspace, "note.txt"), "utf8")).resolves.toBe("current\n");
51
61
  });
52
62
 
63
+ test("uses the default timeout when direct restore configuration is not finite", async () => {
64
+ const workspace = await mkdtemp(join(tmpdir(), "pi-harness-capsule-direct-timeout-workspace-"));
65
+ const capsules = await mkdtemp(join(tmpdir(), "pi-harness-capsule-direct-timeout-input-"));
66
+ temporaryDirectories.push(workspace, capsules);
67
+ await execFileAsync("git", ["init", "-q", "-b", "main"], { cwd: workspace });
68
+ await execFileAsync("git", ["config", "user.email", "test@example.invalid"], { cwd: workspace });
69
+ await execFileAsync("git", ["config", "user.name", "Pi Harness Test"], { cwd: workspace });
70
+ await writeFile(join(workspace, "note.txt"), "before\n", "utf8");
71
+ await execFileAsync("git", ["add", "note.txt"], { cwd: workspace });
72
+ await execFileAsync("git", ["commit", "-qm", "fixture"], { cwd: workspace });
73
+ await writeFile(join(workspace, "note.txt"), "after\n", "utf8");
74
+ const { stdout: patch } = await execFileAsync("git", ["diff", "--binary"], { cwd: workspace });
75
+ const capsule = join(capsules, "restore.patch");
76
+ await writeFile(capsule, patch, "utf8");
77
+
78
+ await applyCapsule(workspace, capsule, Number.NaN);
79
+
80
+ await expect(readFile(join(workspace, "note.txt"), "utf8")).resolves.toBe("before\n");
81
+ });
82
+
83
+ test("rejects a symbolic-link capsule before Git reads its target", async () => {
84
+ if (process.platform === "win32") return;
85
+ const workspace = await mkdtemp(join(tmpdir(), "pi-harness-capsule-symlink-workspace-"));
86
+ const capsules = await mkdtemp(join(tmpdir(), "pi-harness-capsule-symlink-input-"));
87
+ temporaryDirectories.push(workspace, capsules);
88
+ await execFileAsync("git", ["init", "-q", "-b", "main"], { cwd: workspace });
89
+ await execFileAsync("git", ["config", "user.email", "test@example.invalid"], { cwd: workspace });
90
+ await execFileAsync("git", ["config", "user.name", "Pi Harness Test"], { cwd: workspace });
91
+ await writeFile(join(workspace, "note.txt"), "before\n", "utf8");
92
+ await execFileAsync("git", ["add", "note.txt"], { cwd: workspace });
93
+ await execFileAsync("git", ["commit", "-qm", "fixture"], { cwd: workspace });
94
+ await writeFile(join(workspace, "note.txt"), "after\n", "utf8");
95
+ const { stdout: patch } = await execFileAsync("git", ["diff", "--binary"], { cwd: workspace });
96
+ const target = join(capsules, "target.patch");
97
+ const link = join(capsules, "restore.patch");
98
+ await writeFile(target, patch, "utf8");
99
+ await symlink(target, link);
100
+
101
+ await expect(applyCapsule(workspace, link)).rejects.toThrow(/symbolic link/iu);
102
+ await expect(readFile(join(workspace, "note.txt"), "utf8")).resolves.toBe("after\n");
103
+ });
104
+
105
+ test("rejects an oversized capsule before invoking Git", async () => {
106
+ const workspace = await mkdtemp(join(tmpdir(), "pi-harness-capsule-oversized-workspace-"));
107
+ const capsules = await mkdtemp(join(tmpdir(), "pi-harness-capsule-oversized-input-"));
108
+ temporaryDirectories.push(workspace, capsules);
109
+ await execFileAsync("git", ["init", "-q", "-b", "main"], { cwd: workspace });
110
+ const capsule = join(capsules, "oversized.patch");
111
+ await writeFile(capsule, Buffer.alloc(8 * 1024 * 1024 + 1, 0x78));
112
+
113
+ await expect(applyCapsule(workspace, capsule)).rejects.toThrow(/exceeds.*8388608-byte limit/iu);
114
+ });
115
+
116
+ test("preserves caller cancellation while checking a restore", async () => {
117
+ if (process.platform === "win32") return;
118
+ const workspace = await mkdtemp(join(tmpdir(), "pi-harness-capsule-apply-cancel-workspace-"));
119
+ const capsules = await mkdtemp(join(tmpdir(), "pi-harness-capsule-apply-cancel-input-"));
120
+ temporaryDirectories.push(workspace, capsules);
121
+ const capsule = join(capsules, "restore.patch");
122
+ await writeFile(capsule, "non-empty patch fixture\n", "utf8");
123
+ const bin = join(workspace, "bin");
124
+ const started = join(workspace, "git-started");
125
+ await mkdir(bin);
126
+ await writeFile(join(bin, "git"), '#!/bin/sh\n: > "$CAPSULE_GIT_STARTED"\nexec sleep 5\n', "utf8");
127
+ await chmod(join(bin, "git"), 0o700);
128
+ const originalPath = process.env.PATH;
129
+ const originalStarted = process.env.CAPSULE_GIT_STARTED;
130
+ process.env.PATH = `${bin}${delimiter}${originalPath ?? ""}`;
131
+ process.env.CAPSULE_GIT_STARTED = started;
132
+ const controller = new AbortController();
133
+ let pending: Promise<unknown> | undefined;
134
+ try {
135
+ pending = applyCapsule(workspace, capsule, 1_000, controller.signal);
136
+ await waitForFile(started, "Git restore check to start");
137
+
138
+ controller.abort(new Error("restore caller cancelled"));
139
+
140
+ await expect(pending).rejects.toThrow("restore caller cancelled");
141
+ } finally {
142
+ if (!controller.signal.aborted) controller.abort(new Error("restore cancellation test cleanup"));
143
+ await pending?.catch(() => undefined);
144
+ process.env.PATH = originalPath;
145
+ if (originalStarted === undefined) delete process.env.CAPSULE_GIT_STARTED;
146
+ else process.env.CAPSULE_GIT_STARTED = originalStarted;
147
+ }
148
+ });
149
+
53
150
  test("requires explicit confirmation through the restore tool", async () => {
54
151
  const workspace = await mkdtemp(join(tmpdir(), "pi-harness-capsule-tool-"));
55
152
  const agentDir = await mkdtemp(join(tmpdir(), "pi-harness-capsule-agent-"));
@@ -80,6 +177,183 @@ describe("git time capsule restore", () => {
80
177
  details: { restored: true },
81
178
  });
82
179
  await expect(readFile(join(workspace, "note.txt"), "utf8")).resolves.toBe("before\n");
180
+ await expect(panels.snapshot()).resolves.toMatchObject([{ data: { latest: { action: "restore", status: "completed", files: 1 } } }]);
181
+ } finally {
182
+ await context.fiber.dispose();
183
+ }
184
+ });
185
+
186
+ test("reports a completed restore even if the source capsule disappears afterward", async () => {
187
+ if (process.platform === "win32") return;
188
+ const workspace = await mkdtemp(join(tmpdir(), "pi-harness-capsule-restore-race-workspace-"));
189
+ const agentDir = await mkdtemp(join(tmpdir(), "pi-harness-capsule-restore-race-agent-"));
190
+ temporaryDirectories.push(workspace, agentDir);
191
+ const directory = join(agentDir, "capsules");
192
+ await mkdir(directory);
193
+ await execFileAsync("git", ["init", "-q", "-b", "main"], { cwd: workspace });
194
+ await execFileAsync("git", ["config", "user.email", "test@example.invalid"], { cwd: workspace });
195
+ await execFileAsync("git", ["config", "user.name", "Pi Harness Test"], { cwd: workspace });
196
+ await writeFile(join(workspace, "note.txt"), "before\n", "utf8");
197
+ await execFileAsync("git", ["add", "note.txt"], { cwd: workspace });
198
+ await execFileAsync("git", ["commit", "-qm", "fixture"], { cwd: workspace });
199
+ await writeFile(join(workspace, "note.txt"), "after\n", "utf8");
200
+ const { stdout: patch } = await execFileAsync("git", ["diff", "--binary", "--no-textconv"], { cwd: workspace });
201
+ const capsule = join(directory, "restore-race.patch");
202
+ await writeFile(capsule, patch, "utf8");
203
+ const { stdout: realGit } = await execFileAsync("which", ["git"]);
204
+ const bin = join(workspace, "bin");
205
+ await mkdir(bin);
206
+ await writeFile(
207
+ join(bin, "git"),
208
+ '#!/bin/sh\n"$CAPSULE_REAL_GIT" "$@"\nstatus=$?\ncase " $* " in\n *" apply --reverse --binary "*) rm "$CAPSULE_SOURCE" ;;\nesac\nexit "$status"\n',
209
+ "utf8",
210
+ );
211
+ await chmod(join(bin, "git"), 0o700);
212
+ const original = { path: process.env.PATH, realGit: process.env.CAPSULE_REAL_GIT, source: process.env.CAPSULE_SOURCE };
213
+ process.env.PATH = `${bin}${delimiter}${original.path ?? ""}`;
214
+ process.env.CAPSULE_REAL_GIT = realGit.trim();
215
+ process.env.CAPSULE_SOURCE = capsule;
216
+ const context = new Context();
217
+ const tools = new PiToolRegistry();
218
+ const panels = new PiPluginUiRegistry();
219
+ context.provide("piHarnessLaunch", { cwd: workspace, agentDir, args: [], requestExit() {} });
220
+ context.provide("piTools", tools);
221
+ context.provide("piPluginUi", panels);
222
+ try {
223
+ await context.plugin(gitTimeCapsulePlugin);
224
+ const restore = tools.snapshot().customTools.find((candidate) => candidate.name === "git_restore")!;
225
+
226
+ await expect(
227
+ restore.execute("call-restore-race", { name: "restore-race.patch", confirm: true }, undefined, undefined, {} as never),
228
+ ).resolves.toMatchObject({
229
+ details: { restored: true },
230
+ });
231
+ await expect(readFile(join(workspace, "note.txt"), "utf8")).resolves.toBe("before\n");
232
+ } finally {
233
+ for (const [name, value] of [
234
+ ["PATH", original.path],
235
+ ["CAPSULE_REAL_GIT", original.realGit],
236
+ ["CAPSULE_SOURCE", original.source],
237
+ ] as const) {
238
+ if (value === undefined) delete process.env[name];
239
+ else process.env[name] = value;
240
+ }
241
+ await context.fiber.dispose();
242
+ }
243
+ });
244
+
245
+ test("rejects accessor restore parameters without invoking them", async () => {
246
+ const workspace = await mkdtemp(join(tmpdir(), "pi-harness-capsule-restore-params-workspace-"));
247
+ const agentDir = await mkdtemp(join(tmpdir(), "pi-harness-capsule-restore-params-agent-"));
248
+ temporaryDirectories.push(workspace, agentDir);
249
+ const context = new Context();
250
+ const tools = new PiToolRegistry();
251
+ const panels = new PiPluginUiRegistry();
252
+ context.provide("piHarnessLaunch", { cwd: workspace, agentDir, args: [], requestExit() {} });
253
+ context.provide("piTools", tools);
254
+ context.provide("piPluginUi", panels);
255
+ let accessed = false;
256
+ const rawParams = { name: "restore.patch" } as { name: string; confirm?: boolean };
257
+ Object.defineProperty(rawParams, "confirm", {
258
+ enumerable: true,
259
+ get() {
260
+ accessed = true;
261
+ throw new Error("accessor executed");
262
+ },
263
+ });
264
+ try {
265
+ await context.plugin(gitTimeCapsulePlugin);
266
+ const tool = tools.snapshot().customTools.find((candidate) => candidate.name === "git_restore")!;
267
+
268
+ await expect(tool.execute("call-restore-params", rawParams, undefined, undefined, {} as never)).rejects.toThrow(/parameters.*data properties/iu);
269
+ expect(accessed).toBe(false);
270
+ await expect(panels.snapshot()).resolves.toMatchObject([
271
+ { data: { latest: { action: "restore", status: "failed", error: "Git restore parameters must use data properties" } } },
272
+ ]);
273
+ } finally {
274
+ await context.fiber.dispose();
275
+ }
276
+ });
277
+
278
+ test("rejects NUL bytes in restore capsule names before filesystem access", async () => {
279
+ const workspace = await mkdtemp(join(tmpdir(), "pi-harness-capsule-restore-nul-workspace-"));
280
+ const agentDir = await mkdtemp(join(tmpdir(), "pi-harness-capsule-restore-nul-agent-"));
281
+ temporaryDirectories.push(workspace, agentDir);
282
+ const context = new Context();
283
+ const tools = new PiToolRegistry();
284
+ context.provide("piHarnessLaunch", { cwd: workspace, agentDir, args: [], requestExit() {} });
285
+ context.provide("piTools", tools);
286
+ context.provide("piPluginUi", new PiPluginUiRegistry());
287
+ try {
288
+ await context.plugin(gitTimeCapsulePlugin);
289
+ const tool = tools.snapshot().customTools.find((candidate) => candidate.name === "git_restore")!;
290
+
291
+ await expect(tool.execute("call-restore-nul", { name: "restore\0.patch", confirm: true }, undefined, undefined, {} as never)).rejects.toThrow(
292
+ /name.*must not contain NUL/iu,
293
+ );
294
+ } finally {
295
+ await context.fiber.dispose();
296
+ }
297
+ });
298
+
299
+ test("rejects ambiguous or unsafe restore capsule names before filesystem access", async () => {
300
+ const workspace = await mkdtemp(join(tmpdir(), "pi-harness-capsule-restore-name-workspace-"));
301
+ const agentDir = await mkdtemp(join(tmpdir(), "pi-harness-capsule-restore-name-agent-"));
302
+ temporaryDirectories.push(workspace, agentDir);
303
+ const context = new Context();
304
+ const tools = new PiToolRegistry();
305
+ context.provide("piHarnessLaunch", { cwd: workspace, agentDir, args: [], requestExit() {} });
306
+ context.provide("piTools", tools);
307
+ context.provide("piPluginUi", new PiPluginUiRegistry());
308
+ try {
309
+ await context.plugin(gitTimeCapsulePlugin);
310
+ const restore = tools.snapshot().customTools.find((candidate) => candidate.name === "git_restore")!;
311
+
312
+ for (const [index, name] of [
313
+ " restore.patch",
314
+ "restore.patch ",
315
+ "folder\\restore.patch",
316
+ "restore\n.patch",
317
+ "restore\u202e.patch",
318
+ `${"😀".repeat(64)}.patch`,
319
+ ].entries())
320
+ await expect(restore.execute(`call-unsafe-name-${index}`, { name, confirm: true }, undefined, undefined, {} as never)).rejects.toThrow(
321
+ /safe \.patch filename/iu,
322
+ );
323
+ } finally {
324
+ await context.fiber.dispose();
325
+ }
326
+ });
327
+
328
+ test("rejects restore through a symbolic-link capsule directory", async () => {
329
+ if (process.platform === "win32") return;
330
+ const workspace = await mkdtemp(join(tmpdir(), "pi-harness-capsule-restore-directory-workspace-"));
331
+ const agentDir = await mkdtemp(join(tmpdir(), "pi-harness-capsule-restore-directory-agent-"));
332
+ const outside = await mkdtemp(join(tmpdir(), "pi-harness-capsule-restore-directory-outside-"));
333
+ temporaryDirectories.push(workspace, agentDir, outside);
334
+ await execFileAsync("git", ["init", "-q", "-b", "main"], { cwd: workspace });
335
+ await execFileAsync("git", ["config", "user.email", "test@example.invalid"], { cwd: workspace });
336
+ await execFileAsync("git", ["config", "user.name", "Pi Harness Test"], { cwd: workspace });
337
+ await writeFile(join(workspace, "note.txt"), "before\n", "utf8");
338
+ await execFileAsync("git", ["add", "note.txt"], { cwd: workspace });
339
+ await execFileAsync("git", ["commit", "-qm", "fixture"], { cwd: workspace });
340
+ await writeFile(join(workspace, "note.txt"), "after\n", "utf8");
341
+ const { stdout: patch } = await execFileAsync("git", ["diff", "--binary"], { cwd: workspace });
342
+ await writeFile(join(outside, "restore.patch"), patch, "utf8");
343
+ await symlink(outside, join(agentDir, "capsules"));
344
+ const context = new Context();
345
+ const tools = new PiToolRegistry();
346
+ context.provide("piHarnessLaunch", { cwd: workspace, agentDir, args: [], requestExit() {} });
347
+ context.provide("piTools", tools);
348
+ context.provide("piPluginUi", new PiPluginUiRegistry());
349
+ try {
350
+ await context.plugin(gitTimeCapsulePlugin);
351
+ const tool = tools.snapshot().customTools.find((candidate) => candidate.name === "git_restore")!;
352
+
353
+ await expect(tool.execute("call-directory-link", { name: "restore.patch", confirm: true }, undefined, undefined, {} as never)).rejects.toThrow(
354
+ /directory.*symbolic link/iu,
355
+ );
356
+ await expect(readFile(join(workspace, "note.txt"), "utf8")).resolves.toBe("after\n");
83
357
  } finally {
84
358
  await context.fiber.dispose();
85
359
  }
@@ -105,11 +379,1098 @@ describe("git time capsule restore", () => {
105
379
  try {
106
380
  await context.plugin(gitTimeCapsulePlugin);
107
381
  const tool = tools.snapshot().customTools.find((candidate) => candidate.name === "git_snapshot");
108
- await expect(tool!.execute("call-1", {}, undefined, undefined, {} as never)).resolves.toMatchObject({ details: { files: 1 } });
382
+ const first = await tool!.execute("call-1", {}, undefined, undefined, {} as never);
383
+ expect(first).toMatchObject({ details: { files: 1 } });
384
+ expect(JSON.stringify(first)).not.toContain(agentDir);
385
+ expect(JSON.stringify(first)).not.toContain(workspace);
109
386
  await expect(tool!.execute("call-2", {}, undefined, undefined, {} as never)).resolves.toMatchObject({ details: { files: 1 } });
110
387
  await expect(readdir(join(agentDir, "capsules"))).resolves.toHaveLength(2);
111
388
  } finally {
112
389
  await context.fiber.dispose();
113
390
  }
114
391
  });
392
+
393
+ test("returns detached panel state that cannot mutate the latest capsule", async () => {
394
+ const workspace = await mkdtemp(join(tmpdir(), "pi-harness-capsule-panel-clone-workspace-"));
395
+ const agentDir = await mkdtemp(join(tmpdir(), "pi-harness-capsule-panel-clone-agent-"));
396
+ temporaryDirectories.push(workspace, agentDir);
397
+ await execFileAsync("git", ["init", "-q", "-b", "main"], { cwd: workspace });
398
+ await execFileAsync("git", ["config", "user.email", "test@example.invalid"], { cwd: workspace });
399
+ await execFileAsync("git", ["config", "user.name", "Pi Harness Test"], { cwd: workspace });
400
+ await writeFile(join(workspace, "tracked.txt"), "before\n", "utf8");
401
+ await execFileAsync("git", ["add", "tracked.txt"], { cwd: workspace });
402
+ await execFileAsync("git", ["commit", "-qm", "fixture"], { cwd: workspace });
403
+ await writeFile(join(workspace, "tracked.txt"), "after\n", "utf8");
404
+ const context = new Context();
405
+ const tools = new PiToolRegistry();
406
+ const panels = new PiPluginUiRegistry();
407
+ context.provide("piHarnessLaunch", { cwd: workspace, agentDir, args: [], requestExit() {} });
408
+ context.provide("piTools", tools);
409
+ context.provide("piPluginUi", panels);
410
+ try {
411
+ await context.plugin(gitTimeCapsulePlugin);
412
+ const tool = tools.snapshot().customTools.find((candidate) => candidate.name === "git_snapshot")!;
413
+ await tool.execute("call-panel-clone", {}, undefined, undefined, {} as never);
414
+ const first = await panels.snapshot();
415
+ const firstData = first[0]?.data as { latest: { name: string } };
416
+ const originalName = firstData.latest.name;
417
+ firstData.latest.name = "mutated.patch";
418
+
419
+ const second = await panels.snapshot();
420
+
421
+ expect((second[0]?.data as { latest: { name: string } }).latest.name).toBe(originalName);
422
+ } finally {
423
+ await context.fiber.dispose();
424
+ }
425
+ });
426
+
427
+ test("records a bounded failed capture for the panel", async () => {
428
+ const workspace = await mkdtemp(join(tmpdir(), "pi-harness-capsule-failure-workspace-"));
429
+ const agentDir = await mkdtemp(join(tmpdir(), "pi-harness-capsule-failure-agent-"));
430
+ temporaryDirectories.push(workspace, agentDir);
431
+ const context = new Context();
432
+ const tools = new PiToolRegistry();
433
+ const panels = new PiPluginUiRegistry();
434
+ context.provide("piHarnessLaunch", { cwd: workspace, agentDir, args: [], requestExit() {} });
435
+ context.provide("piTools", tools);
436
+ context.provide("piPluginUi", panels);
437
+ try {
438
+ await context.plugin(gitTimeCapsulePlugin);
439
+ const tool = tools.snapshot().customTools.find((candidate) => candidate.name === "git_snapshot")!;
440
+ await expect(tool.execute("call-failure", {}, undefined, undefined, {} as never)).rejects.toThrow("Git time capsule requires a Git working tree");
441
+
442
+ await expect(panels.snapshot()).resolves.toMatchObject([
443
+ {
444
+ id: "git-time-capsule-panel",
445
+ data: { latest: { action: "capture", status: "failed", error: "Git time capsule requires a Git working tree" } },
446
+ },
447
+ ]);
448
+ const snapshot = await panels.snapshot();
449
+ expect((snapshot[0]?.data as { latest: { error: string } }).latest.error.length).toBeLessThanOrEqual(2_000);
450
+ } finally {
451
+ await context.fiber.dispose();
452
+ }
453
+ });
454
+
455
+ test("sanitizes tool and panel failures while preserving the original cause", async () => {
456
+ if (process.platform === "win32") return;
457
+ const workspace = await mkdtemp(join(tmpdir(), "pi-harness-capsule-safe-error-workspace-"));
458
+ const agentDir = await mkdtemp(join(tmpdir(), "pi-harness-capsule-safe-error-agent-"));
459
+ temporaryDirectories.push(workspace, agentDir);
460
+ const bin = join(workspace, "bin");
461
+ await mkdir(bin);
462
+ await writeFile(
463
+ join(bin, "git"),
464
+ '#!/bin/sh\nif [ "$1" = "rev-parse" ]; then printf "true\\n"; exit 0; fi\nprintf "fatal: %s\\342\\200\\256\\001\\n" "$CAPSULE_ERROR_PATH" >&2\nexit 2\n',
465
+ "utf8",
466
+ );
467
+ await chmod(join(bin, "git"), 0o700);
468
+ const originalPath = process.env.PATH;
469
+ const originalErrorPath = process.env.CAPSULE_ERROR_PATH;
470
+ process.env.PATH = `${bin}${delimiter}${originalPath ?? ""}`;
471
+ process.env.CAPSULE_ERROR_PATH = workspace;
472
+ const context = new Context();
473
+ const tools = new PiToolRegistry();
474
+ const panels = new PiPluginUiRegistry();
475
+ context.provide("piHarnessLaunch", { cwd: workspace, agentDir, args: [], requestExit() {} });
476
+ context.provide("piTools", tools);
477
+ context.provide("piPluginUi", panels);
478
+ try {
479
+ await context.plugin(gitTimeCapsulePlugin);
480
+ const tool = tools.snapshot().customTools.find((candidate) => candidate.name === "git_snapshot")!;
481
+ let failure: unknown;
482
+ try {
483
+ await tool.execute("call-safe-error", {}, undefined, undefined, {} as never);
484
+ } catch (error) {
485
+ failure = error;
486
+ }
487
+
488
+ expect(failure).toBeInstanceOf(Error);
489
+ expect((failure as Error).message.length).toBeLessThanOrEqual(2_000);
490
+ expect((failure as Error).message).not.toContain(workspace);
491
+ expect((failure as Error).message).not.toMatch(/[\p{Cc}\p{Cf}]/u);
492
+ expect((failure as Error).cause).toBeInstanceOf(Error);
493
+ const data = (await panels.snapshot())[0]?.data as { latest: { error: string } };
494
+ expect(data.latest.error).toBe((failure as Error).message);
495
+ } finally {
496
+ process.env.PATH = originalPath;
497
+ if (originalErrorPath === undefined) delete process.env.CAPSULE_ERROR_PATH;
498
+ else process.env.CAPSULE_ERROR_PATH = originalErrorPath;
499
+ await context.fiber.dispose();
500
+ }
501
+ });
502
+
503
+ test("times out a hung Git process while creating a capsule", async () => {
504
+ if (process.platform === "win32") return;
505
+ const workspace = await mkdtemp(join(tmpdir(), "pi-harness-capsule-timeout-workspace-"));
506
+ const agentDir = await mkdtemp(join(tmpdir(), "pi-harness-capsule-timeout-agent-"));
507
+ temporaryDirectories.push(workspace, agentDir);
508
+ const bin = join(workspace, "bin");
509
+ await mkdir(bin);
510
+ await writeFile(join(bin, "git"), "#!/bin/sh\nexec sleep 1\n", "utf8");
511
+ await chmod(join(bin, "git"), 0o700);
512
+ const originalPath = process.env.PATH;
513
+ process.env.PATH = `${bin}${delimiter}${originalPath ?? ""}`;
514
+ const context = new Context();
515
+ const tools = new PiToolRegistry();
516
+ context.provide("piHarnessLaunch", { cwd: workspace, agentDir, args: [], requestExit() {} });
517
+ context.provide("piTools", tools);
518
+ context.provide("piPluginUi", new PiPluginUiRegistry());
519
+ try {
520
+ await context.plugin(gitTimeCapsulePlugin, { timeoutMs: 500 });
521
+ const pending = tools
522
+ .snapshot()
523
+ .customTools.find((candidate) => candidate.name === "git_snapshot")!
524
+ .execute("call-1", {}, undefined, undefined, {} as never);
525
+ await expect(pending).rejects.toThrow(/timed out after 500 ms/iu);
526
+ } finally {
527
+ process.env.PATH = originalPath;
528
+ await context.fiber.dispose();
529
+ }
530
+ });
531
+
532
+ test("cancels an in-flight Git snapshot when the caller aborts", async () => {
533
+ if (process.platform === "win32") return;
534
+ const workspace = await mkdtemp(join(tmpdir(), "pi-harness-capsule-cancel-workspace-"));
535
+ const agentDir = await mkdtemp(join(tmpdir(), "pi-harness-capsule-cancel-agent-"));
536
+ temporaryDirectories.push(workspace, agentDir);
537
+ const bin = join(workspace, "bin");
538
+ const started = join(workspace, "git-started");
539
+ await mkdir(bin);
540
+ await writeFile(join(bin, "git"), '#!/bin/sh\necho "$$" > "$CAPSULE_GIT_STARTED"\nexec sleep 5\n', "utf8");
541
+ await chmod(join(bin, "git"), 0o700);
542
+ const originalPath = process.env.PATH;
543
+ const originalStarted = process.env.CAPSULE_GIT_STARTED;
544
+ process.env.PATH = `${bin}${delimiter}${originalPath ?? ""}`;
545
+ process.env.CAPSULE_GIT_STARTED = started;
546
+ const context = new Context();
547
+ const tools = new PiToolRegistry();
548
+ context.provide("piHarnessLaunch", { cwd: workspace, agentDir, args: [], requestExit() {} });
549
+ context.provide("piTools", tools);
550
+ context.provide("piPluginUi", new PiPluginUiRegistry());
551
+ try {
552
+ await context.plugin(gitTimeCapsulePlugin, { timeoutMs: 1_000 });
553
+ const tool = tools.snapshot().customTools.find((candidate) => candidate.name === "git_snapshot")!;
554
+ const controller = new AbortController();
555
+ const pending = tool.execute("call-cancel", {}, controller.signal, undefined, {} as never);
556
+ await waitForFile(started, "Git snapshot process to start");
557
+
558
+ controller.abort(new Error("snapshot caller cancelled"));
559
+
560
+ await expect(pending).rejects.toThrow("snapshot caller cancelled");
561
+ } finally {
562
+ process.env.PATH = originalPath;
563
+ if (originalStarted === undefined) delete process.env.CAPSULE_GIT_STARTED;
564
+ else process.env.CAPSULE_GIT_STARTED = originalStarted;
565
+ await context.fiber.dispose();
566
+ }
567
+ });
568
+
569
+ test("records a caller cancellation that arrives before execution starts", async () => {
570
+ const workspace = await mkdtemp(join(tmpdir(), "pi-harness-capsule-pre-cancel-workspace-"));
571
+ const agentDir = await mkdtemp(join(tmpdir(), "pi-harness-capsule-pre-cancel-agent-"));
572
+ temporaryDirectories.push(workspace, agentDir);
573
+ const context = new Context();
574
+ const tools = new PiToolRegistry();
575
+ const panels = new PiPluginUiRegistry();
576
+ context.provide("piHarnessLaunch", { cwd: workspace, agentDir, args: [], requestExit() {} });
577
+ context.provide("piTools", tools);
578
+ context.provide("piPluginUi", panels);
579
+ const controller = new AbortController();
580
+ controller.abort(new Error("caller cancelled before start"));
581
+ try {
582
+ await context.plugin(gitTimeCapsulePlugin);
583
+ const tool = tools.snapshot().customTools.find((candidate) => candidate.name === "git_snapshot")!;
584
+
585
+ await expect(tool.execute("call-pre-cancel", {}, controller.signal, undefined, {} as never)).rejects.toThrow("caller cancelled before start");
586
+ await expect(panels.snapshot()).resolves.toMatchObject([
587
+ { data: { latest: { action: "capture", status: "cancelled", error: "caller cancelled before start" } } },
588
+ ]);
589
+ } finally {
590
+ await context.fiber.dispose();
591
+ }
592
+ });
593
+
594
+ test("cancels an in-flight Git snapshot when the plugin is disposed", async () => {
595
+ if (process.platform === "win32") return;
596
+ const workspace = await mkdtemp(join(tmpdir(), "pi-harness-capsule-dispose-workspace-"));
597
+ const agentDir = await mkdtemp(join(tmpdir(), "pi-harness-capsule-dispose-agent-"));
598
+ temporaryDirectories.push(workspace, agentDir);
599
+ const bin = join(workspace, "bin");
600
+ const started = join(workspace, "git-started");
601
+ await mkdir(bin);
602
+ await writeFile(join(bin, "git"), '#!/bin/sh\necho "$$" > "$CAPSULE_GIT_STARTED"\nexec sleep 5\n', "utf8");
603
+ await chmod(join(bin, "git"), 0o700);
604
+ const originalPath = process.env.PATH;
605
+ const originalStarted = process.env.CAPSULE_GIT_STARTED;
606
+ process.env.PATH = `${bin}${delimiter}${originalPath ?? ""}`;
607
+ process.env.CAPSULE_GIT_STARTED = started;
608
+ const context = new Context();
609
+ const tools = new PiToolRegistry();
610
+ context.provide("piHarnessLaunch", { cwd: workspace, agentDir, args: [], requestExit() {} });
611
+ context.provide("piTools", tools);
612
+ context.provide("piPluginUi", new PiPluginUiRegistry());
613
+ let disposed = false;
614
+ try {
615
+ await context.plugin(gitTimeCapsulePlugin, { timeoutMs: 1_000 });
616
+ const tool = tools.snapshot().customTools.find((candidate) => candidate.name === "git_snapshot")!;
617
+ const pending = tool.execute("call-dispose", {}, undefined, undefined, {} as never);
618
+ await waitForFile(started, "Git snapshot process to start");
619
+
620
+ await context.fiber.dispose();
621
+ disposed = true;
622
+
623
+ await expect(pending).rejects.toThrow("Git time capsule plugin disposed");
624
+ } finally {
625
+ process.env.PATH = originalPath;
626
+ if (originalStarted === undefined) delete process.env.CAPSULE_GIT_STARTED;
627
+ else process.env.CAPSULE_GIT_STARTED = originalStarted;
628
+ if (!disposed) await context.fiber.dispose();
629
+ }
630
+ });
631
+
632
+ test("serializes concurrent capsule operations", async () => {
633
+ if (process.platform === "win32") return;
634
+ const workspace = await mkdtemp(join(tmpdir(), "pi-harness-capsule-serial-workspace-"));
635
+ const agentDir = await mkdtemp(join(tmpdir(), "pi-harness-capsule-serial-agent-"));
636
+ temporaryDirectories.push(workspace, agentDir);
637
+ await execFileAsync("git", ["init", "-q", "-b", "main"], { cwd: workspace });
638
+ await execFileAsync("git", ["config", "user.email", "test@example.invalid"], { cwd: workspace });
639
+ await execFileAsync("git", ["config", "user.name", "Pi Harness Test"], { cwd: workspace });
640
+ await writeFile(join(workspace, "tracked.txt"), "before\n", "utf8");
641
+ await execFileAsync("git", ["add", "tracked.txt"], { cwd: workspace });
642
+ await execFileAsync("git", ["commit", "-qm", "fixture"], { cwd: workspace });
643
+ await writeFile(join(workspace, "tracked.txt"), "after\n", "utf8");
644
+ const { stdout } = await execFileAsync("which", ["git"]);
645
+ const bin = join(workspace, "bin");
646
+ const started = join(workspace, "git-started");
647
+ const once = join(workspace, "git-once");
648
+ const lock = join(workspace, "git-lock");
649
+ await mkdir(bin);
650
+ await writeFile(
651
+ join(bin, "git"),
652
+ '#!/bin/sh\nif mkdir "$CAPSULE_GIT_ONCE" 2>/dev/null; then\n mkdir "$CAPSULE_GIT_LOCK"\n : > "$CAPSULE_GIT_STARTED"\n sleep 1\n rmdir "$CAPSULE_GIT_LOCK"\nelif [ -d "$CAPSULE_GIT_LOCK" ]; then\n echo "concurrent Git invocation" >&2\n exit 92\nfi\nexec "$REAL_GIT" "$@"\n',
653
+ "utf8",
654
+ );
655
+ await chmod(join(bin, "git"), 0o700);
656
+ const environment = {
657
+ PATH: process.env.PATH,
658
+ REAL_GIT: process.env.REAL_GIT,
659
+ CAPSULE_GIT_STARTED: process.env.CAPSULE_GIT_STARTED,
660
+ CAPSULE_GIT_ONCE: process.env.CAPSULE_GIT_ONCE,
661
+ CAPSULE_GIT_LOCK: process.env.CAPSULE_GIT_LOCK,
662
+ };
663
+ process.env.PATH = `${bin}${delimiter}${process.env.PATH ?? ""}`;
664
+ process.env.REAL_GIT = stdout.trim();
665
+ process.env.CAPSULE_GIT_STARTED = started;
666
+ process.env.CAPSULE_GIT_ONCE = once;
667
+ process.env.CAPSULE_GIT_LOCK = lock;
668
+ const context = new Context();
669
+ const tools = new PiToolRegistry();
670
+ context.provide("piHarnessLaunch", { cwd: workspace, agentDir, args: [], requestExit() {} });
671
+ context.provide("piTools", tools);
672
+ context.provide("piPluginUi", new PiPluginUiRegistry());
673
+ try {
674
+ await context.plugin(gitTimeCapsulePlugin, { timeoutMs: 5_000 });
675
+ const tool = tools.snapshot().customTools.find((candidate) => candidate.name === "git_snapshot")!;
676
+ const first = tool.execute("call-serial-1", {}, undefined, undefined, {} as never);
677
+ await waitForFile(started, "first serialized Git operation to start");
678
+ const second = tool.execute("call-serial-2", {}, undefined, undefined, {} as never);
679
+
680
+ await expect(Promise.all([first, second])).resolves.toHaveLength(2);
681
+ } finally {
682
+ for (const [name, value] of Object.entries(environment)) {
683
+ if (value === undefined) delete process.env[name];
684
+ else process.env[name] = value;
685
+ }
686
+ await context.fiber.dispose();
687
+ }
688
+ });
689
+
690
+ test("rejects a queued operation promptly when its caller aborts", async () => {
691
+ if (process.platform === "win32") return;
692
+ const workspace = await mkdtemp(join(tmpdir(), "pi-harness-capsule-queued-cancel-workspace-"));
693
+ const agentDir = await mkdtemp(join(tmpdir(), "pi-harness-capsule-queued-cancel-agent-"));
694
+ temporaryDirectories.push(workspace, agentDir);
695
+ const bin = join(workspace, "bin");
696
+ const started = join(workspace, "git-started");
697
+ const rejected = join(workspace, "queued-rejected");
698
+ await mkdir(bin);
699
+ await writeFile(join(bin, "git"), '#!/bin/sh\n: > "$CAPSULE_GIT_STARTED"\nexec sleep 5\n', "utf8");
700
+ await chmod(join(bin, "git"), 0o700);
701
+ const originalPath = process.env.PATH;
702
+ const originalStarted = process.env.CAPSULE_GIT_STARTED;
703
+ process.env.PATH = `${bin}${delimiter}${originalPath ?? ""}`;
704
+ process.env.CAPSULE_GIT_STARTED = started;
705
+ const context = new Context();
706
+ const tools = new PiToolRegistry();
707
+ context.provide("piHarnessLaunch", { cwd: workspace, agentDir, args: [], requestExit() {} });
708
+ context.provide("piTools", tools);
709
+ context.provide("piPluginUi", new PiPluginUiRegistry());
710
+ let first: Promise<unknown> | undefined;
711
+ try {
712
+ await context.plugin(gitTimeCapsulePlugin, { timeoutMs: 10_000 });
713
+ const tool = tools.snapshot().customTools.find((candidate) => candidate.name === "git_snapshot")!;
714
+ first = tool.execute("call-blocking", {}, undefined, undefined, {} as never);
715
+ void first.catch(() => undefined);
716
+ await waitForFile(started, "blocking Git operation to start");
717
+ const controller = new AbortController();
718
+ const second = tool.execute("call-queued", {}, controller.signal, undefined, {} as never);
719
+ let rejection: unknown;
720
+ void second.catch(async (error: unknown) => {
721
+ rejection = error;
722
+ await writeFile(rejected, "rejected", "utf8");
723
+ });
724
+
725
+ controller.abort(new Error("queued caller cancelled"));
726
+
727
+ await waitForFile(rejected, "queued operation cancellation", 500);
728
+ expect(rejection).toMatchObject({ message: "queued caller cancelled" });
729
+ } finally {
730
+ process.env.PATH = originalPath;
731
+ if (originalStarted === undefined) delete process.env.CAPSULE_GIT_STARTED;
732
+ else process.env.CAPSULE_GIT_STARTED = originalStarted;
733
+ await context.fiber.dispose();
734
+ await first?.catch(() => undefined);
735
+ }
736
+ });
737
+
738
+ test("omits symbolic links from the recent capsule panel", async () => {
739
+ if (process.platform === "win32") return;
740
+ const workspace = await mkdtemp(join(tmpdir(), "pi-harness-capsule-panel-workspace-"));
741
+ const agentDir = await mkdtemp(join(tmpdir(), "pi-harness-capsule-panel-agent-"));
742
+ temporaryDirectories.push(workspace, agentDir);
743
+ const directory = join(agentDir, "capsules");
744
+ await mkdir(directory);
745
+ const outside = join(workspace, "outside.patch");
746
+ await writeFile(outside, "outside", "utf8");
747
+ await symlink(outside, join(directory, "linked.patch"));
748
+ const context = new Context();
749
+ context.provide("piHarnessLaunch", { cwd: workspace, agentDir, args: [], requestExit() {} });
750
+ context.provide("piTools", new PiToolRegistry());
751
+ const panels = new PiPluginUiRegistry();
752
+ context.provide("piPluginUi", panels);
753
+ try {
754
+ await context.plugin(gitTimeCapsulePlugin);
755
+ await expect(panels.snapshot()).resolves.toMatchObject([{ id: "git-time-capsule-panel", data: { capsules: [] } }]);
756
+ } finally {
757
+ await context.fiber.dispose();
758
+ }
759
+ });
760
+
761
+ test("rejects a symbolic-link capsule directory before listing its target", async () => {
762
+ if (process.platform === "win32") return;
763
+ const workspace = await mkdtemp(join(tmpdir(), "pi-harness-capsule-panel-directory-workspace-"));
764
+ const agentDir = await mkdtemp(join(tmpdir(), "pi-harness-capsule-panel-directory-agent-"));
765
+ const outside = await mkdtemp(join(tmpdir(), "pi-harness-capsule-panel-directory-outside-"));
766
+ temporaryDirectories.push(workspace, agentDir, outside);
767
+ await writeFile(join(outside, "outside.patch"), "outside", "utf8");
768
+ await symlink(outside, join(agentDir, "capsules"));
769
+ const context = new Context();
770
+ context.provide("piHarnessLaunch", { cwd: workspace, agentDir, args: [], requestExit() {} });
771
+ context.provide("piTools", new PiToolRegistry());
772
+ const panels = new PiPluginUiRegistry();
773
+ context.provide("piPluginUi", panels);
774
+ try {
775
+ await context.plugin(gitTimeCapsulePlugin);
776
+
777
+ const snapshot = await panels.snapshot();
778
+ expect(snapshot[0]?.id).toBe("git-time-capsule-panel");
779
+ expect(snapshot[0]?.error).toMatch(/directory.*symbolic link/iu);
780
+ } finally {
781
+ await context.fiber.dispose();
782
+ }
783
+ });
784
+
785
+ test("does not expose the private capsule directory through panel read errors", async () => {
786
+ if (process.platform === "win32" || typeof process.getuid !== "function" || process.getuid() === 0) return;
787
+ const workspace = await mkdtemp(join(tmpdir(), "pi-harness-capsule-panel-error-workspace-"));
788
+ const agentDir = await mkdtemp(join(tmpdir(), "pi-harness-capsule-panel-error-agent-"));
789
+ temporaryDirectories.push(workspace, agentDir);
790
+ const directory = join(agentDir, "capsules");
791
+ await mkdir(directory);
792
+ await chmod(directory, 0o000);
793
+ const context = new Context();
794
+ context.provide("piHarnessLaunch", { cwd: workspace, agentDir, args: [], requestExit() {} });
795
+ context.provide("piTools", new PiToolRegistry());
796
+ const panels = new PiPluginUiRegistry();
797
+ context.provide("piPluginUi", panels);
798
+ try {
799
+ await context.plugin(gitTimeCapsulePlugin);
800
+
801
+ const snapshot = await panels.snapshot();
802
+ expect(snapshot[0]?.error).toBeDefined();
803
+ expect(snapshot[0]?.error).not.toContain(agentDir);
804
+ expect(snapshot[0]?.error).not.toMatch(/[\p{Cc}\p{Cf}]/u);
805
+ } finally {
806
+ await chmod(directory, 0o700);
807
+ await context.fiber.dispose();
808
+ }
809
+ });
810
+
811
+ test("bounds the capsule inventory before rendering recent entries", async () => {
812
+ const workspace = await mkdtemp(join(tmpdir(), "pi-harness-capsule-inventory-workspace-"));
813
+ const agentDir = await mkdtemp(join(tmpdir(), "pi-harness-capsule-inventory-agent-"));
814
+ temporaryDirectories.push(workspace, agentDir);
815
+ const directory = join(agentDir, "capsules");
816
+ await mkdir(directory);
817
+ await Promise.all(Array.from({ length: 257 }, (_, index) => writeFile(join(directory, `${String(index).padStart(4, "0")}.patch`), "x", "utf8")));
818
+ const context = new Context();
819
+ context.provide("piHarnessLaunch", { cwd: workspace, agentDir, args: [], requestExit() {} });
820
+ context.provide("piTools", new PiToolRegistry());
821
+ const panels = new PiPluginUiRegistry();
822
+ context.provide("piPluginUi", panels);
823
+ try {
824
+ await context.plugin(gitTimeCapsulePlugin);
825
+ const snapshot = await panels.snapshot();
826
+ expect(snapshot[0]?.id).toBe("git-time-capsule-panel");
827
+ expect(snapshot[0]?.error).toMatch(/exceeds.*256.*capsule/iu);
828
+ } finally {
829
+ await context.fiber.dispose();
830
+ }
831
+ });
832
+
833
+ test("refuses a new capture before the bounded inventory becomes unusable", async () => {
834
+ const workspace = await mkdtemp(join(tmpdir(), "pi-harness-capsule-full-inventory-workspace-"));
835
+ const agentDir = await mkdtemp(join(tmpdir(), "pi-harness-capsule-full-inventory-agent-"));
836
+ temporaryDirectories.push(workspace, agentDir);
837
+ const directory = join(agentDir, "capsules");
838
+ await mkdir(directory);
839
+ await Promise.all(Array.from({ length: 256 }, (_, index) => writeFile(join(directory, `${String(index).padStart(4, "0")}.patch`), "x", "utf8")));
840
+ await execFileAsync("git", ["init", "-q", "-b", "main"], { cwd: workspace });
841
+ await execFileAsync("git", ["config", "user.email", "test@example.invalid"], { cwd: workspace });
842
+ await execFileAsync("git", ["config", "user.name", "Pi Harness Test"], { cwd: workspace });
843
+ await writeFile(join(workspace, "tracked.txt"), "before\n", "utf8");
844
+ await execFileAsync("git", ["add", "tracked.txt"], { cwd: workspace });
845
+ await execFileAsync("git", ["commit", "-qm", "fixture"], { cwd: workspace });
846
+ await writeFile(join(workspace, "tracked.txt"), "after\n", "utf8");
847
+ const context = new Context();
848
+ const tools = new PiToolRegistry();
849
+ const panels = new PiPluginUiRegistry();
850
+ context.provide("piHarnessLaunch", { cwd: workspace, agentDir, args: [], requestExit() {} });
851
+ context.provide("piTools", tools);
852
+ context.provide("piPluginUi", panels);
853
+ try {
854
+ await context.plugin(gitTimeCapsulePlugin);
855
+ const snapshot = tools.snapshot().customTools.find((candidate) => candidate.name === "git_snapshot")!;
856
+
857
+ await expect(snapshot.execute("call-full-inventory", {}, undefined, undefined, {} as never)).rejects.toThrow(/inventory.*256.*limit/iu);
858
+ await expect(readdir(directory)).resolves.toHaveLength(256);
859
+ const panelSnapshot = await panels.snapshot();
860
+ expect(panelSnapshot[0]?.error).toBeUndefined();
861
+ expect(panelSnapshot).toMatchObject([{ data: { inventory: { total: 256 } } }]);
862
+ } finally {
863
+ await context.fiber.dispose();
864
+ }
865
+ });
866
+
867
+ test("refuses a new capture before exceeding the directory entry scan limit", async () => {
868
+ const workspace = await mkdtemp(join(tmpdir(), "pi-harness-capsule-full-directory-workspace-"));
869
+ const agentDir = await mkdtemp(join(tmpdir(), "pi-harness-capsule-full-directory-agent-"));
870
+ temporaryDirectories.push(workspace, agentDir);
871
+ const directory = join(agentDir, "capsules");
872
+ await mkdir(directory);
873
+ await Promise.all(Array.from({ length: 4_096 }, (_, index) => writeFile(join(directory, `entry-${String(index).padStart(4, "0")}.tmp`), "x", "utf8")));
874
+ await execFileAsync("git", ["init", "-q", "-b", "main"], { cwd: workspace });
875
+ await execFileAsync("git", ["config", "user.email", "test@example.invalid"], { cwd: workspace });
876
+ await execFileAsync("git", ["config", "user.name", "Pi Harness Test"], { cwd: workspace });
877
+ await writeFile(join(workspace, "tracked.txt"), "before\n", "utf8");
878
+ await execFileAsync("git", ["add", "tracked.txt"], { cwd: workspace });
879
+ await execFileAsync("git", ["commit", "-qm", "fixture"], { cwd: workspace });
880
+ await writeFile(join(workspace, "tracked.txt"), "after\n", "utf8");
881
+ const context = new Context();
882
+ const tools = new PiToolRegistry();
883
+ context.provide("piHarnessLaunch", { cwd: workspace, agentDir, args: [], requestExit() {} });
884
+ context.provide("piTools", tools);
885
+ context.provide("piPluginUi", new PiPluginUiRegistry());
886
+ try {
887
+ await context.plugin(gitTimeCapsulePlugin);
888
+ const snapshot = tools.snapshot().customTools.find((candidate) => candidate.name === "git_snapshot")!;
889
+
890
+ await expect(snapshot.execute("call-full-directory", {}, undefined, undefined, {} as never)).rejects.toThrow(/directory.*4096.*limit/iu);
891
+ await expect(readdir(directory)).resolves.toHaveLength(4_096);
892
+ } finally {
893
+ await context.fiber.dispose();
894
+ }
895
+ });
896
+
897
+ test("reports when the recent capsule inventory is truncated", async () => {
898
+ const workspace = await mkdtemp(join(tmpdir(), "pi-harness-capsule-truncated-workspace-"));
899
+ const agentDir = await mkdtemp(join(tmpdir(), "pi-harness-capsule-truncated-agent-"));
900
+ temporaryDirectories.push(workspace, agentDir);
901
+ const directory = join(agentDir, "capsules");
902
+ await mkdir(directory);
903
+ await Promise.all(Array.from({ length: 21 }, (_, index) => writeFile(join(directory, `${String(index).padStart(4, "0")}.patch`), "x", "utf8")));
904
+ const context = new Context();
905
+ context.provide("piHarnessLaunch", { cwd: workspace, agentDir, args: [], requestExit() {} });
906
+ context.provide("piTools", new PiToolRegistry());
907
+ const panels = new PiPluginUiRegistry();
908
+ context.provide("piPluginUi", panels);
909
+ try {
910
+ await context.plugin(gitTimeCapsulePlugin);
911
+
912
+ const snapshot = await panels.snapshot();
913
+ expect(snapshot[0]?.id).toBe("git-time-capsule-panel");
914
+ const data = snapshot[0]?.data as { capsules: unknown[]; inventory: Record<string, unknown> };
915
+ expect(data.capsules).toHaveLength(20);
916
+ expect(data.inventory).toEqual({ total: 21, shown: 20, truncated: true, displayLimit: 20 });
917
+ } finally {
918
+ await context.fiber.dispose();
919
+ }
920
+ });
921
+
922
+ test("uses the default timeout when configuration is not finite", async () => {
923
+ const workspace = await mkdtemp(join(tmpdir(), "pi-harness-capsule-config-workspace-"));
924
+ const agentDir = await mkdtemp(join(tmpdir(), "pi-harness-capsule-config-agent-"));
925
+ temporaryDirectories.push(workspace, agentDir);
926
+ const context = new Context();
927
+ context.provide("piHarnessLaunch", { cwd: workspace, agentDir, args: [], requestExit() {} });
928
+ context.provide("piTools", new PiToolRegistry());
929
+ const panels = new PiPluginUiRegistry();
930
+ context.provide("piPluginUi", panels);
931
+ try {
932
+ await context.plugin(gitTimeCapsulePlugin, { timeoutMs: Number.NaN });
933
+
934
+ await expect(panels.snapshot()).resolves.toMatchObject([{ id: "git-time-capsule-panel", data: { timeoutMs: 15_000 } }]);
935
+ } finally {
936
+ await context.fiber.dispose();
937
+ }
938
+ });
939
+
940
+ test("rejects unknown configuration before registering tools or panels", async () => {
941
+ const workspace = await mkdtemp(join(tmpdir(), "pi-harness-capsule-unknown-config-workspace-"));
942
+ const agentDir = await mkdtemp(join(tmpdir(), "pi-harness-capsule-unknown-config-agent-"));
943
+ temporaryDirectories.push(workspace, agentDir);
944
+ const context = new Context();
945
+ const tools = new PiToolRegistry();
946
+ const panels = new PiPluginUiRegistry();
947
+ context.provide("piHarnessLaunch", { cwd: workspace, agentDir, args: [], requestExit() {} });
948
+ context.provide("piTools", tools);
949
+ context.provide("piPluginUi", panels);
950
+ try {
951
+ let failure: unknown;
952
+ try {
953
+ await context.plugin(gitTimeCapsulePlugin, { timeoutMs: 15_000, unexpected: true } as never);
954
+ } catch (error) {
955
+ failure = error;
956
+ }
957
+
958
+ expect(failure).toBeInstanceOf(Error);
959
+ expect((failure as Error).message).toMatch(/unknown.*unexpected/iu);
960
+
961
+ expect(tools.snapshot().customTools).toEqual([]);
962
+ await expect(panels.snapshot()).resolves.toEqual([]);
963
+ } finally {
964
+ await context.fiber.dispose();
965
+ }
966
+ });
967
+
968
+ test("rolls back both tools when panel registration fails", async () => {
969
+ const workspace = await mkdtemp(join(tmpdir(), "pi-harness-capsule-panel-conflict-workspace-"));
970
+ const agentDir = await mkdtemp(join(tmpdir(), "pi-harness-capsule-panel-conflict-agent-"));
971
+ temporaryDirectories.push(workspace, agentDir);
972
+ const context = new Context();
973
+ const tools = new PiToolRegistry();
974
+ const panels = new PiPluginUiRegistry();
975
+ context.provide("piHarnessLaunch", { cwd: workspace, agentDir, args: [], requestExit() {} });
976
+ context.provide("piTools", tools);
977
+ context.provide("piPluginUi", panels);
978
+ panels.register({ id: "git-time-capsule-panel", pluginId: "fixture", title: "Fixture", read: () => ({}) });
979
+ try {
980
+ await expect(context.plugin(gitTimeCapsulePlugin)).rejects.toThrow(/panel is already registered: git-time-capsule-panel/iu);
981
+
982
+ expect(tools.snapshot().customTools).toEqual([]);
983
+ await expect(panels.snapshot()).resolves.toMatchObject([{ id: "git-time-capsule-panel", pluginId: "fixture" }]);
984
+ } finally {
985
+ await context.fiber.dispose();
986
+ }
987
+ });
988
+
989
+ test("rejects a clean worktree instead of creating an unusable empty capsule", async () => {
990
+ const workspace = await mkdtemp(join(tmpdir(), "pi-harness-capsule-clean-workspace-"));
991
+ const agentDir = await mkdtemp(join(tmpdir(), "pi-harness-capsule-clean-agent-"));
992
+ temporaryDirectories.push(workspace, agentDir);
993
+ await execFileAsync("git", ["init", "-q", "-b", "main"], { cwd: workspace });
994
+ await execFileAsync("git", ["config", "user.email", "test@example.invalid"], { cwd: workspace });
995
+ await execFileAsync("git", ["config", "user.name", "Pi Harness Test"], { cwd: workspace });
996
+ await writeFile(join(workspace, "tracked.txt"), "clean\n", "utf8");
997
+ await execFileAsync("git", ["add", "tracked.txt"], { cwd: workspace });
998
+ await execFileAsync("git", ["commit", "-qm", "fixture"], { cwd: workspace });
999
+ const context = new Context();
1000
+ const tools = new PiToolRegistry();
1001
+ context.provide("piHarnessLaunch", { cwd: workspace, agentDir, args: [], requestExit() {} });
1002
+ context.provide("piTools", tools);
1003
+ context.provide("piPluginUi", new PiPluginUiRegistry());
1004
+ try {
1005
+ await context.plugin(gitTimeCapsulePlugin);
1006
+ const tool = tools.snapshot().customTools.find((candidate) => candidate.name === "git_snapshot")!;
1007
+
1008
+ await expect(tool.execute("call-clean", {}, undefined, undefined, {} as never)).rejects.toThrow(/no tracked git changes/iu);
1009
+ await expect(readdir(join(agentDir, "capsules"))).rejects.toMatchObject({ code: "ENOENT" });
1010
+ } finally {
1011
+ await context.fiber.dispose();
1012
+ }
1013
+ });
1014
+
1015
+ test("does not capture staged changes that restore cannot safely remove from the index", async () => {
1016
+ const workspace = await mkdtemp(join(tmpdir(), "pi-harness-capsule-staged-workspace-"));
1017
+ const agentDir = await mkdtemp(join(tmpdir(), "pi-harness-capsule-staged-agent-"));
1018
+ temporaryDirectories.push(workspace, agentDir);
1019
+ await execFileAsync("git", ["init", "-q", "-b", "main"], { cwd: workspace });
1020
+ await execFileAsync("git", ["config", "user.email", "test@example.invalid"], { cwd: workspace });
1021
+ await execFileAsync("git", ["config", "user.name", "Pi Harness Test"], { cwd: workspace });
1022
+ await writeFile(join(workspace, "tracked.txt"), "before\n", "utf8");
1023
+ await execFileAsync("git", ["add", "tracked.txt"], { cwd: workspace });
1024
+ await execFileAsync("git", ["commit", "-qm", "fixture"], { cwd: workspace });
1025
+ await writeFile(join(workspace, "tracked.txt"), "staged\n", "utf8");
1026
+ await execFileAsync("git", ["add", "tracked.txt"], { cwd: workspace });
1027
+ const context = new Context();
1028
+ const tools = new PiToolRegistry();
1029
+ context.provide("piHarnessLaunch", { cwd: workspace, agentDir, args: [], requestExit() {} });
1030
+ context.provide("piTools", tools);
1031
+ context.provide("piPluginUi", new PiPluginUiRegistry());
1032
+ try {
1033
+ await context.plugin(gitTimeCapsulePlugin);
1034
+ const tool = tools.snapshot().customTools.find((candidate) => candidate.name === "git_snapshot")!;
1035
+
1036
+ await expect(tool.execute("call-staged", {}, undefined, undefined, {} as never)).rejects.toThrow(/staged.*excluded/iu);
1037
+ const { stdout: staged } = await execFileAsync("git", ["diff", "--cached", "--name-only"], { cwd: workspace });
1038
+ expect(staged.trim()).toBe("tracked.txt");
1039
+ await expect(readdir(join(agentDir, "capsules"))).rejects.toMatchObject({ code: "ENOENT" });
1040
+ } finally {
1041
+ await context.fiber.dispose();
1042
+ }
1043
+ });
1044
+
1045
+ test("does not write snapshots through a symbolic-link capsule directory", async () => {
1046
+ if (process.platform === "win32") return;
1047
+ const workspace = await mkdtemp(join(tmpdir(), "pi-harness-capsule-snapshot-directory-workspace-"));
1048
+ const agentDir = await mkdtemp(join(tmpdir(), "pi-harness-capsule-snapshot-directory-agent-"));
1049
+ const outside = await mkdtemp(join(tmpdir(), "pi-harness-capsule-snapshot-directory-outside-"));
1050
+ temporaryDirectories.push(workspace, agentDir, outside);
1051
+ await execFileAsync("git", ["init", "-q", "-b", "main"], { cwd: workspace });
1052
+ await execFileAsync("git", ["config", "user.email", "test@example.invalid"], { cwd: workspace });
1053
+ await execFileAsync("git", ["config", "user.name", "Pi Harness Test"], { cwd: workspace });
1054
+ await writeFile(join(workspace, "tracked.txt"), "before\n", "utf8");
1055
+ await execFileAsync("git", ["add", "tracked.txt"], { cwd: workspace });
1056
+ await execFileAsync("git", ["commit", "-qm", "fixture"], { cwd: workspace });
1057
+ await writeFile(join(workspace, "tracked.txt"), "after\n", "utf8");
1058
+ await symlink(outside, join(agentDir, "capsules"));
1059
+ const context = new Context();
1060
+ const tools = new PiToolRegistry();
1061
+ context.provide("piHarnessLaunch", { cwd: workspace, agentDir, args: [], requestExit() {} });
1062
+ context.provide("piTools", tools);
1063
+ context.provide("piPluginUi", new PiPluginUiRegistry());
1064
+ try {
1065
+ await context.plugin(gitTimeCapsulePlugin);
1066
+ const tool = tools.snapshot().customTools.find((candidate) => candidate.name === "git_snapshot")!;
1067
+
1068
+ await expect(tool.execute("call-directory-link", {}, undefined, undefined, {} as never)).rejects.toThrow(/directory.*symbolic link/iu);
1069
+ await expect(readdir(outside)).resolves.toEqual([]);
1070
+ } finally {
1071
+ await context.fiber.dispose();
1072
+ }
1073
+ });
1074
+
1075
+ test("rejects unexpected raw snapshot parameters without invoking accessors", async () => {
1076
+ const workspace = await mkdtemp(join(tmpdir(), "pi-harness-capsule-snapshot-params-workspace-"));
1077
+ const agentDir = await mkdtemp(join(tmpdir(), "pi-harness-capsule-snapshot-params-agent-"));
1078
+ temporaryDirectories.push(workspace, agentDir);
1079
+ const context = new Context();
1080
+ const tools = new PiToolRegistry();
1081
+ const panels = new PiPluginUiRegistry();
1082
+ context.provide("piHarnessLaunch", { cwd: workspace, agentDir, args: [], requestExit() {} });
1083
+ context.provide("piTools", tools);
1084
+ context.provide("piPluginUi", panels);
1085
+ let accessed = false;
1086
+ const rawParams = Object.create(null) as Record<string, unknown>;
1087
+ Object.defineProperty(rawParams, "unexpected", {
1088
+ enumerable: true,
1089
+ get() {
1090
+ accessed = true;
1091
+ throw new Error("accessor executed");
1092
+ },
1093
+ });
1094
+ try {
1095
+ await context.plugin(gitTimeCapsulePlugin);
1096
+ const tool = tools.snapshot().customTools.find((candidate) => candidate.name === "git_snapshot")!;
1097
+
1098
+ await expect(tool.execute("call-params", rawParams, undefined, undefined, {} as never)).rejects.toThrow(/parameters.*unknown property/iu);
1099
+ expect(accessed).toBe(false);
1100
+ await expect(panels.snapshot()).resolves.toMatchObject([
1101
+ { data: { latest: { action: "capture", status: "failed", error: "Git snapshot parameters contains an unknown property" } } },
1102
+ ]);
1103
+ } finally {
1104
+ await context.fiber.dispose();
1105
+ }
1106
+ });
1107
+
1108
+ test("rejects inaccessible or non-plain tool parameter objects", async () => {
1109
+ const workspace = await mkdtemp(join(tmpdir(), "pi-harness-capsule-hostile-params-workspace-"));
1110
+ const agentDir = await mkdtemp(join(tmpdir(), "pi-harness-capsule-hostile-params-agent-"));
1111
+ temporaryDirectories.push(workspace, agentDir);
1112
+ const context = new Context();
1113
+ const tools = new PiToolRegistry();
1114
+ context.provide("piHarnessLaunch", { cwd: workspace, agentDir, args: [], requestExit() {} });
1115
+ context.provide("piTools", tools);
1116
+ context.provide("piPluginUi", new PiPluginUiRegistry());
1117
+ const revocable = Proxy.revocable({}, {});
1118
+ revocable.revoke();
1119
+ try {
1120
+ await context.plugin(gitTimeCapsulePlugin);
1121
+ const snapshot = tools.snapshot().customTools.find((candidate) => candidate.name === "git_snapshot")!;
1122
+ const restore = tools.snapshot().customTools.find((candidate) => candidate.name === "git_restore")!;
1123
+
1124
+ await expect(snapshot.execute("call-revoked", revocable.proxy, undefined, undefined, {} as never)).rejects.toThrow(
1125
+ /parameters.*accessible plain object/iu,
1126
+ );
1127
+ await expect(restore.execute("call-array", [], undefined, undefined, {} as never)).rejects.toThrow(/parameters.*object/iu);
1128
+ await expect(snapshot.execute("call-instance", new Date(), undefined, undefined, {} as never)).rejects.toThrow(/parameters.*plain object/iu);
1129
+ } finally {
1130
+ await context.fiber.dispose();
1131
+ }
1132
+ });
1133
+
1134
+ test("publishes sequential tools with closed parameter schemas", async () => {
1135
+ const workspace = await mkdtemp(join(tmpdir(), "pi-harness-capsule-tool-contract-workspace-"));
1136
+ const agentDir = await mkdtemp(join(tmpdir(), "pi-harness-capsule-tool-contract-agent-"));
1137
+ temporaryDirectories.push(workspace, agentDir);
1138
+ const context = new Context();
1139
+ const tools = new PiToolRegistry();
1140
+ context.provide("piHarnessLaunch", { cwd: workspace, agentDir, args: [], requestExit() {} });
1141
+ context.provide("piTools", tools);
1142
+ context.provide("piPluginUi", new PiPluginUiRegistry());
1143
+ try {
1144
+ await context.plugin(gitTimeCapsulePlugin);
1145
+
1146
+ expect(tools.snapshot().customTools).toMatchObject([
1147
+ { name: "git_snapshot", executionMode: "sequential", parameters: { additionalProperties: false } },
1148
+ { name: "git_restore", executionMode: "sequential", parameters: { additionalProperties: false } },
1149
+ ]);
1150
+ } finally {
1151
+ await context.fiber.dispose();
1152
+ }
1153
+ });
1154
+
1155
+ test("counts tracked changes without invoking git status or scanning untracked files", async () => {
1156
+ if (process.platform === "win32") return;
1157
+ const workspace = await mkdtemp(join(tmpdir(), "pi-harness-capsule-no-status-workspace-"));
1158
+ const agentDir = await mkdtemp(join(tmpdir(), "pi-harness-capsule-no-status-agent-"));
1159
+ temporaryDirectories.push(workspace, agentDir);
1160
+ await execFileAsync("git", ["init", "-q", "-b", "main"], { cwd: workspace });
1161
+ await execFileAsync("git", ["config", "user.email", "test@example.invalid"], { cwd: workspace });
1162
+ await execFileAsync("git", ["config", "user.name", "Pi Harness Test"], { cwd: workspace });
1163
+ await writeFile(join(workspace, "tracked.txt"), "before\n", "utf8");
1164
+ await execFileAsync("git", ["add", "tracked.txt"], { cwd: workspace });
1165
+ await execFileAsync("git", ["commit", "-qm", "fixture"], { cwd: workspace });
1166
+ await writeFile(join(workspace, "tracked.txt"), "after\n", "utf8");
1167
+ await mkdir(join(workspace, "untracked"));
1168
+ await writeFile(join(workspace, "untracked", "ignored.txt"), "not captured\n", "utf8");
1169
+ const { stdout } = await execFileAsync("which", ["git"]);
1170
+ const bin = join(workspace, "bin");
1171
+ await mkdir(bin);
1172
+ await writeFile(
1173
+ join(bin, "git"),
1174
+ '#!/bin/sh\nif [ "$1" = "status" ]; then echo "git status must not be used" >&2; exit 91; fi\nexec "$REAL_GIT" "$@"\n',
1175
+ "utf8",
1176
+ );
1177
+ await chmod(join(bin, "git"), 0o700);
1178
+ const originalPath = process.env.PATH;
1179
+ const originalRealGit = process.env.REAL_GIT;
1180
+ process.env.REAL_GIT = stdout.trim();
1181
+ process.env.PATH = `${bin}${delimiter}${originalPath ?? ""}`;
1182
+ const context = new Context();
1183
+ const tools = new PiToolRegistry();
1184
+ context.provide("piHarnessLaunch", { cwd: workspace, agentDir, args: [], requestExit() {} });
1185
+ context.provide("piTools", tools);
1186
+ context.provide("piPluginUi", new PiPluginUiRegistry());
1187
+ try {
1188
+ await context.plugin(gitTimeCapsulePlugin);
1189
+ const tool = tools.snapshot().customTools.find((candidate) => candidate.name === "git_snapshot")!;
1190
+
1191
+ await expect(tool.execute("call-no-status", {}, undefined, undefined, {} as never)).resolves.toMatchObject({ details: { files: 1 } });
1192
+ } finally {
1193
+ process.env.PATH = originalPath;
1194
+ if (originalRealGit === undefined) delete process.env.REAL_GIT;
1195
+ else process.env.REAL_GIT = originalRealGit;
1196
+ await context.fiber.dispose();
1197
+ }
1198
+ });
1199
+
1200
+ test("counts files from the captured patch instead of a racing worktree query", async () => {
1201
+ if (process.platform === "win32") return;
1202
+ const workspace = await mkdtemp(join(tmpdir(), "pi-harness-capsule-count-race-workspace-"));
1203
+ const agentDir = await mkdtemp(join(tmpdir(), "pi-harness-capsule-count-race-agent-"));
1204
+ temporaryDirectories.push(workspace, agentDir);
1205
+ await execFileAsync("git", ["init", "-q", "-b", "main"], { cwd: workspace });
1206
+ await execFileAsync("git", ["config", "user.email", "test@example.invalid"], { cwd: workspace });
1207
+ await execFileAsync("git", ["config", "user.name", "Pi Harness Test"], { cwd: workspace });
1208
+ await writeFile(join(workspace, "tracked.txt"), "before\n", "utf8");
1209
+ await execFileAsync("git", ["add", "tracked.txt"], { cwd: workspace });
1210
+ await execFileAsync("git", ["commit", "-qm", "fixture"], { cwd: workspace });
1211
+ await writeFile(join(workspace, "tracked.txt"), "after\n", "utf8");
1212
+ const { stdout: realGit } = await execFileAsync("which", ["git"]);
1213
+ const bin = join(workspace, "bin");
1214
+ await mkdir(bin);
1215
+ await writeFile(join(bin, "git"), '#!/bin/sh\ncase " $* " in\n *" --name-only "*) exit 0 ;;\nesac\nexec "$CAPSULE_REAL_GIT" "$@"\n', "utf8");
1216
+ await chmod(join(bin, "git"), 0o700);
1217
+ const originalPath = process.env.PATH;
1218
+ const originalRealGit = process.env.CAPSULE_REAL_GIT;
1219
+ process.env.PATH = `${bin}${delimiter}${originalPath ?? ""}`;
1220
+ process.env.CAPSULE_REAL_GIT = realGit.trim();
1221
+ const context = new Context();
1222
+ const tools = new PiToolRegistry();
1223
+ context.provide("piHarnessLaunch", { cwd: workspace, agentDir, args: [], requestExit() {} });
1224
+ context.provide("piTools", tools);
1225
+ context.provide("piPluginUi", new PiPluginUiRegistry());
1226
+ try {
1227
+ await context.plugin(gitTimeCapsulePlugin);
1228
+ const tool = tools.snapshot().customTools.find((candidate) => candidate.name === "git_snapshot")!;
1229
+
1230
+ await expect(tool.execute("call-count-race", {}, undefined, undefined, {} as never)).resolves.toMatchObject({ details: { files: 1 } });
1231
+ } finally {
1232
+ process.env.PATH = originalPath;
1233
+ if (originalRealGit === undefined) delete process.env.CAPSULE_REAL_GIT;
1234
+ else process.env.CAPSULE_REAL_GIT = originalRealGit;
1235
+ await context.fiber.dispose();
1236
+ }
1237
+ });
1238
+
1239
+ test("captures an applyable patch without invoking repository textconv drivers", async () => {
1240
+ if (process.platform === "win32") return;
1241
+ const workspace = await mkdtemp(join(tmpdir(), "pi-harness-capsule-textconv-workspace-"));
1242
+ const agentDir = await mkdtemp(join(tmpdir(), "pi-harness-capsule-textconv-agent-"));
1243
+ temporaryDirectories.push(workspace, agentDir);
1244
+ await execFileAsync("git", ["init", "-q", "-b", "main"], { cwd: workspace });
1245
+ await execFileAsync("git", ["config", "user.email", "test@example.invalid"], { cwd: workspace });
1246
+ await execFileAsync("git", ["config", "user.name", "Pi Harness Test"], { cwd: workspace });
1247
+ const driver = join(workspace, "textconv-driver");
1248
+ const invoked = join(workspace, "textconv-invoked");
1249
+ await writeFile(driver, '#!/bin/sh\n: > "$CAPSULE_TEXTCONV_INVOKED"\ncat "$1"\n', "utf8");
1250
+ await chmod(driver, 0o700);
1251
+ await execFileAsync("git", ["config", "diff.capsule-fixture.textconv", driver], { cwd: workspace });
1252
+ await writeFile(join(workspace, ".gitattributes"), "*.data diff=capsule-fixture\n", "utf8");
1253
+ await writeFile(join(workspace, "tracked.data"), "before\n", "utf8");
1254
+ await execFileAsync("git", ["add", ".gitattributes", "tracked.data"], { cwd: workspace });
1255
+ await execFileAsync("git", ["commit", "-qm", "fixture"], { cwd: workspace });
1256
+ await writeFile(join(workspace, "tracked.data"), "after\n", "utf8");
1257
+ const originalInvoked = process.env.CAPSULE_TEXTCONV_INVOKED;
1258
+ process.env.CAPSULE_TEXTCONV_INVOKED = invoked;
1259
+ const context = new Context();
1260
+ const tools = new PiToolRegistry();
1261
+ context.provide("piHarnessLaunch", { cwd: workspace, agentDir, args: [], requestExit() {} });
1262
+ context.provide("piTools", tools);
1263
+ context.provide("piPluginUi", new PiPluginUiRegistry());
1264
+ try {
1265
+ await context.plugin(gitTimeCapsulePlugin);
1266
+ const snapshot = tools.snapshot().customTools.find((candidate) => candidate.name === "git_snapshot")!;
1267
+ const restore = tools.snapshot().customTools.find((candidate) => candidate.name === "git_restore")!;
1268
+
1269
+ await expect(snapshot.execute("call-textconv-capture", {}, undefined, undefined, {} as never)).resolves.toMatchObject({ details: { files: 1 } });
1270
+ await expect(readFile(invoked, "utf8")).rejects.toMatchObject({ code: "ENOENT" });
1271
+ const names = await readdir(join(agentDir, "capsules"));
1272
+ await restore.execute("call-textconv-restore", { name: names[0], confirm: true }, undefined, undefined, {} as never);
1273
+ await expect(readFile(join(workspace, "tracked.data"), "utf8")).resolves.toBe("before\n");
1274
+ } finally {
1275
+ if (originalInvoked === undefined) delete process.env.CAPSULE_TEXTCONV_INVOKED;
1276
+ else process.env.CAPSULE_TEXTCONV_INVOKED = originalInvoked;
1277
+ await context.fiber.dispose();
1278
+ }
1279
+ });
1280
+
1281
+ test("does not let inherited Git environment redirect capsule commands", async () => {
1282
+ const workspace = await mkdtemp(join(tmpdir(), "pi-harness-capsule-env-workspace-"));
1283
+ const decoy = await mkdtemp(join(tmpdir(), "pi-harness-capsule-env-decoy-"));
1284
+ const agentDir = await mkdtemp(join(tmpdir(), "pi-harness-capsule-env-agent-"));
1285
+ temporaryDirectories.push(workspace, decoy, agentDir);
1286
+ for (const repository of [workspace, decoy]) {
1287
+ await execFileAsync("git", ["init", "-q", "-b", "main"], { cwd: repository });
1288
+ await execFileAsync("git", ["config", "user.email", "test@example.invalid"], { cwd: repository });
1289
+ await execFileAsync("git", ["config", "user.name", "Pi Harness Test"], { cwd: repository });
1290
+ }
1291
+ await writeFile(join(workspace, "workspace.txt"), "before\n", "utf8");
1292
+ await execFileAsync("git", ["add", "workspace.txt"], { cwd: workspace });
1293
+ await execFileAsync("git", ["commit", "-qm", "fixture"], { cwd: workspace });
1294
+ await writeFile(join(workspace, "workspace.txt"), "after\n", "utf8");
1295
+ await writeFile(join(decoy, "decoy.txt"), "before\n", "utf8");
1296
+ await execFileAsync("git", ["add", "decoy.txt"], { cwd: decoy });
1297
+ await execFileAsync("git", ["commit", "-qm", "fixture"], { cwd: decoy });
1298
+ await writeFile(join(decoy, "decoy.txt"), "after\n", "utf8");
1299
+ const originalGitDir = process.env.GIT_DIR;
1300
+ const originalGitWorkTree = process.env.GIT_WORK_TREE;
1301
+ process.env.GIT_DIR = join(decoy, ".git");
1302
+ process.env.GIT_WORK_TREE = decoy;
1303
+ const context = new Context();
1304
+ const tools = new PiToolRegistry();
1305
+ context.provide("piHarnessLaunch", { cwd: workspace, agentDir, args: [], requestExit() {} });
1306
+ context.provide("piTools", tools);
1307
+ context.provide("piPluginUi", new PiPluginUiRegistry());
1308
+ try {
1309
+ await context.plugin(gitTimeCapsulePlugin);
1310
+ const tool = tools.snapshot().customTools.find((candidate) => candidate.name === "git_snapshot")!;
1311
+
1312
+ await expect(tool.execute("call-env", {}, undefined, undefined, {} as never)).resolves.toMatchObject({ details: { files: 1 } });
1313
+ const names = await readdir(join(agentDir, "capsules"));
1314
+ expect(names).toHaveLength(1);
1315
+ const patch = await readFile(join(agentDir, "capsules", names[0]!), "utf8");
1316
+ expect(patch).toContain("workspace.txt");
1317
+ expect(patch).not.toContain("decoy.txt");
1318
+ } finally {
1319
+ if (originalGitDir === undefined) delete process.env.GIT_DIR;
1320
+ else process.env.GIT_DIR = originalGitDir;
1321
+ if (originalGitWorkTree === undefined) delete process.env.GIT_WORK_TREE;
1322
+ else process.env.GIT_WORK_TREE = originalGitWorkTree;
1323
+ await context.fiber.dispose();
1324
+ }
1325
+ });
1326
+
1327
+ test("does not let inherited Git config injection block a valid restore", async () => {
1328
+ const workspace = await mkdtemp(join(tmpdir(), "pi-harness-capsule-config-env-workspace-"));
1329
+ const agentDir = await mkdtemp(join(tmpdir(), "pi-harness-capsule-config-env-agent-"));
1330
+ temporaryDirectories.push(workspace, agentDir);
1331
+ await execFileAsync("git", ["init", "-q", "-b", "main"], { cwd: workspace });
1332
+ await execFileAsync("git", ["config", "user.email", "test@example.invalid"], { cwd: workspace });
1333
+ await execFileAsync("git", ["config", "user.name", "Pi Harness Test"], { cwd: workspace });
1334
+ await writeFile(join(workspace, "workspace.txt"), "before \n", "utf8");
1335
+ await execFileAsync("git", ["add", "workspace.txt"], { cwd: workspace });
1336
+ await execFileAsync("git", ["commit", "-qm", "fixture"], { cwd: workspace });
1337
+ await writeFile(join(workspace, "workspace.txt"), "after\n", "utf8");
1338
+ const original = {
1339
+ count: process.env.GIT_CONFIG_COUNT,
1340
+ key: process.env.GIT_CONFIG_KEY_0,
1341
+ value: process.env.GIT_CONFIG_VALUE_0,
1342
+ };
1343
+ process.env.GIT_CONFIG_COUNT = "1";
1344
+ process.env.GIT_CONFIG_KEY_0 = "apply.whitespace";
1345
+ process.env.GIT_CONFIG_VALUE_0 = "error-all";
1346
+ const context = new Context();
1347
+ const tools = new PiToolRegistry();
1348
+ context.provide("piHarnessLaunch", { cwd: workspace, agentDir, args: [], requestExit() {} });
1349
+ context.provide("piTools", tools);
1350
+ context.provide("piPluginUi", new PiPluginUiRegistry());
1351
+ try {
1352
+ await context.plugin(gitTimeCapsulePlugin);
1353
+ const snapshot = tools.snapshot().customTools.find((candidate) => candidate.name === "git_snapshot")!;
1354
+ const restore = tools.snapshot().customTools.find((candidate) => candidate.name === "git_restore")!;
1355
+
1356
+ await expect(snapshot.execute("call-config-env", {}, undefined, undefined, {} as never)).resolves.toMatchObject({ details: { files: 1 } });
1357
+ const names = await readdir(join(agentDir, "capsules"));
1358
+ await expect(restore.execute("call-config-env-restore", { name: names[0], confirm: true }, undefined, undefined, {} as never)).resolves.toMatchObject({
1359
+ details: { restored: true },
1360
+ });
1361
+ await expect(readFile(join(workspace, "workspace.txt"), "utf8")).resolves.toBe("before \n");
1362
+ } finally {
1363
+ for (const [name, value] of [
1364
+ ["GIT_CONFIG_COUNT", original.count],
1365
+ ["GIT_CONFIG_KEY_0", original.key],
1366
+ ["GIT_CONFIG_VALUE_0", original.value],
1367
+ ] as const) {
1368
+ if (value === undefined) delete process.env[name];
1369
+ else process.env[name] = value;
1370
+ }
1371
+ await context.fiber.dispose();
1372
+ }
1373
+ });
1374
+
1375
+ test("round-trips patches containing non-UTF-8 Git path bytes", async () => {
1376
+ if (process.platform === "win32") return;
1377
+ const workspace = await mkdtemp(join(tmpdir(), "pi-harness-capsule-path-bytes-workspace-"));
1378
+ const agentDir = await mkdtemp(join(tmpdir(), "pi-harness-capsule-path-bytes-agent-"));
1379
+ temporaryDirectories.push(workspace, agentDir);
1380
+ const bin = join(workspace, "bin");
1381
+ await mkdir(bin);
1382
+ await writeFile(
1383
+ join(bin, "git"),
1384
+ '#!/bin/sh\nif [ "$1" = "rev-parse" ]; then printf "true\\n"; exit 0; fi\ncase " $* " in\n *" --name-only "*) printf "fixture.txt\\000" ;;\n *) printf "diff-prefix\\377diff-suffix\\n" ;;\nesac\n',
1385
+ "utf8",
1386
+ );
1387
+ await chmod(join(bin, "git"), 0o700);
1388
+ const originalPath = process.env.PATH;
1389
+ process.env.PATH = `${bin}${delimiter}${originalPath ?? ""}`;
1390
+ const context = new Context();
1391
+ const tools = new PiToolRegistry();
1392
+ context.provide("piHarnessLaunch", { cwd: workspace, agentDir, args: [], requestExit() {} });
1393
+ context.provide("piTools", tools);
1394
+ context.provide("piPluginUi", new PiPluginUiRegistry());
1395
+ try {
1396
+ await context.plugin(gitTimeCapsulePlugin);
1397
+ const snapshot = tools.snapshot().customTools.find((candidate) => candidate.name === "git_snapshot")!;
1398
+
1399
+ await snapshot.execute("call-path-bytes-capture", {}, undefined, undefined, {} as never);
1400
+ const names = await readdir(join(agentDir, "capsules"));
1401
+ expect(names).toHaveLength(1);
1402
+ await expect(readFile(join(agentDir, "capsules", names[0]!))).resolves.toEqual(
1403
+ Buffer.from([...Buffer.from("diff-prefix"), 0xff, ...Buffer.from("diff-suffix\n")]),
1404
+ );
1405
+ } finally {
1406
+ process.env.PATH = originalPath;
1407
+ await context.fiber.dispose();
1408
+ }
1409
+ });
1410
+
1411
+ test("does not publish a capsule when the captured patch cannot be validated", async () => {
1412
+ if (process.platform === "win32") return;
1413
+ const workspace = await mkdtemp(join(tmpdir(), "pi-harness-capsule-invalid-capture-workspace-"));
1414
+ const agentDir = await mkdtemp(join(tmpdir(), "pi-harness-capsule-invalid-capture-agent-"));
1415
+ temporaryDirectories.push(workspace, agentDir);
1416
+ const bin = join(workspace, "bin");
1417
+ await mkdir(bin);
1418
+ await writeFile(
1419
+ join(bin, "git"),
1420
+ '#!/bin/sh\nif [ "$1" = "rev-parse" ]; then printf "true\\n"; exit 0; fi\ncase " $* " in\n *" apply --numstat "*) printf "invalid captured patch\\n" >&2; exit 3 ;;\n *) printf "not a valid patch\\n" ;;\nesac\n',
1421
+ "utf8",
1422
+ );
1423
+ await chmod(join(bin, "git"), 0o700);
1424
+ const originalPath = process.env.PATH;
1425
+ process.env.PATH = `${bin}${delimiter}${originalPath ?? ""}`;
1426
+ const context = new Context();
1427
+ const tools = new PiToolRegistry();
1428
+ context.provide("piHarnessLaunch", { cwd: workspace, agentDir, args: [], requestExit() {} });
1429
+ context.provide("piTools", tools);
1430
+ context.provide("piPluginUi", new PiPluginUiRegistry());
1431
+ try {
1432
+ await context.plugin(gitTimeCapsulePlugin);
1433
+ const snapshot = tools.snapshot().customTools.find((candidate) => candidate.name === "git_snapshot")!;
1434
+
1435
+ await expect(snapshot.execute("call-invalid-capture", {}, undefined, undefined, {} as never)).rejects.toThrow(/invalid captured patch/iu);
1436
+ await expect(readdir(join(agentDir, "capsules"))).resolves.toEqual([]);
1437
+ } finally {
1438
+ process.env.PATH = originalPath;
1439
+ await context.fiber.dispose();
1440
+ }
1441
+ });
1442
+
1443
+ test("does not overwrite a capsule created concurrently at publication", async () => {
1444
+ if (process.platform === "win32") return;
1445
+ const workspace = await mkdtemp(join(tmpdir(), "pi-harness-capsule-publish-race-workspace-"));
1446
+ const agentDir = await mkdtemp(join(tmpdir(), "pi-harness-capsule-publish-race-agent-"));
1447
+ temporaryDirectories.push(workspace, agentDir);
1448
+ const bin = join(workspace, "bin");
1449
+ await mkdir(bin);
1450
+ await writeFile(
1451
+ join(bin, "git"),
1452
+ '#!/bin/sh\nif [ "$1" = "rev-parse" ]; then printf "true\\n"; exit 0; fi\ncase " $* " in\n *" apply --numstat "*)\n for argument do temporary="$argument"; done\n directory=${temporary%/*}\n base=${temporary##*/}\n remainder=${base#.}\n name=${remainder%.*.tmp}\n printf "concurrent capsule\\n" > "$directory/$name"\n printf "1\\t1\\tfixture.txt\\n"\n exit 0\n ;;\n *) printf "captured patch\\n" ;;\nesac\n',
1453
+ "utf8",
1454
+ );
1455
+ await chmod(join(bin, "git"), 0o700);
1456
+ const originalPath = process.env.PATH;
1457
+ process.env.PATH = `${bin}${delimiter}${originalPath ?? ""}`;
1458
+ const context = new Context();
1459
+ const tools = new PiToolRegistry();
1460
+ context.provide("piHarnessLaunch", { cwd: workspace, agentDir, args: [], requestExit() {} });
1461
+ context.provide("piTools", tools);
1462
+ context.provide("piPluginUi", new PiPluginUiRegistry());
1463
+ try {
1464
+ await context.plugin(gitTimeCapsulePlugin);
1465
+ const snapshot = tools.snapshot().customTools.find((candidate) => candidate.name === "git_snapshot")!;
1466
+
1467
+ await expect(snapshot.execute("call-publish-race", {}, undefined, undefined, {} as never)).rejects.toThrow(/exist/iu);
1468
+ const names = await readdir(join(agentDir, "capsules"));
1469
+ expect(names).toHaveLength(1);
1470
+ await expect(readFile(join(agentDir, "capsules", names[0]!), "utf8")).resolves.toBe("concurrent capsule\n");
1471
+ } finally {
1472
+ process.env.PATH = originalPath;
1473
+ await context.fiber.dispose();
1474
+ }
1475
+ });
115
1476
  });