@herbertgao/pi-extensions 2026.8.8 → 2026.8.10

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 (266) hide show
  1. package/README.md +6 -3
  2. package/node_modules/@czottmann/pi-automode/CHANGELOG.md +24 -0
  3. package/node_modules/@czottmann/pi-automode/README.md +78 -112
  4. package/node_modules/@czottmann/pi-automode/docs/GLOSSARY.md +18 -14
  5. package/node_modules/@czottmann/pi-automode/docs/adr/ADR-001-permission-precedence-and-trust-boundaries.md +44 -0
  6. package/node_modules/@czottmann/pi-automode/docs/adr/INDEX.md +5 -0
  7. package/node_modules/@czottmann/pi-automode/docs/automode-classifier-flow.md +198 -104
  8. package/node_modules/@czottmann/pi-automode/docs/configuration.md +155 -0
  9. package/node_modules/@czottmann/pi-automode/docs/defaults.md +55 -14
  10. package/node_modules/@czottmann/pi-automode/docs/diagnostics.md +90 -0
  11. package/node_modules/@czottmann/pi-automode/docs/observability-logging.md +61 -26
  12. package/node_modules/@czottmann/pi-automode/examples/automode.local.json +5 -0
  13. package/node_modules/@czottmann/pi-automode/extensions/auto-mode/classifier.ts +172 -18
  14. package/node_modules/@czottmann/pi-automode/extensions/auto-mode/config.ts +127 -30
  15. package/node_modules/@czottmann/pi-automode/extensions/auto-mode/constants.ts +3 -0
  16. package/node_modules/@czottmann/pi-automode/extensions/auto-mode/extension.ts +273 -31
  17. package/node_modules/@czottmann/pi-automode/extensions/auto-mode/log.ts +60 -5
  18. package/node_modules/@czottmann/pi-automode/extensions/auto-mode/paths.ts +92 -8
  19. package/node_modules/@czottmann/pi-automode/extensions/auto-mode/permissions.ts +203 -13
  20. package/node_modules/@czottmann/pi-automode/extensions/auto-mode/state.ts +1 -0
  21. package/node_modules/@czottmann/pi-automode/extensions/auto-mode/types.ts +11 -0
  22. package/node_modules/@czottmann/pi-automode/extensions/auto-mode/utils.ts +9 -1
  23. package/node_modules/@czottmann/pi-automode/package.json +9 -2
  24. package/node_modules/@czottmann/pi-automode/skills/automode-diagnostics/SKILL.md +63 -0
  25. package/node_modules/@herbertgao/pi-cc-extensions/README.en.md +3 -3
  26. package/node_modules/@herbertgao/pi-cc-extensions/README.md +3 -3
  27. package/node_modules/@herbertgao/pi-cc-extensions/extensions/config/panel.ts +8 -3
  28. package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/context.ts +56 -29
  29. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/message-display.ts +1 -1
  30. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse/interaction.ts +15 -13
  31. package/node_modules/@herbertgao/pi-cc-extensions/package.json +3 -3
  32. package/node_modules/@herbertgao/pi-handoff/CHANGELOG.md +29 -0
  33. package/node_modules/@herbertgao/pi-handoff/README.md +15 -18
  34. package/node_modules/@herbertgao/pi-handoff/package.json +11 -4
  35. package/node_modules/@herbertgao/pi-handoff/src/complete-text.ts +33 -0
  36. package/node_modules/@herbertgao/pi-handoff/src/index.ts +127 -232
  37. package/node_modules/@herbertgao/pi-handoff/src/session-query.ts +15 -30
  38. package/node_modules/@herbertgao/pi-mermaid-open/CHANGELOG.md +14 -0
  39. package/node_modules/@herbertgao/pi-mermaid-open/README.md +21 -4
  40. package/node_modules/@herbertgao/pi-mermaid-open/herdr-plugin/herdr-plugin.toml +11 -0
  41. package/node_modules/@herbertgao/pi-mermaid-open/herdr-plugin/viewer.mjs +305 -0
  42. package/node_modules/@herbertgao/pi-mermaid-open/package.json +15 -4
  43. package/node_modules/@herbertgao/pi-mermaid-open/src/index.ts +351 -101
  44. package/node_modules/@herbertgao/pi-preferred-thinking/CHANGELOG.md +12 -0
  45. package/node_modules/@herbertgao/pi-preferred-thinking/README.md +30 -14
  46. package/node_modules/@herbertgao/pi-preferred-thinking/package.json +7 -4
  47. package/node_modules/@herbertgao/pi-preferred-thinking/src/index.ts +140 -85
  48. package/node_modules/@herbertgao/pi-recap/CHANGELOG.md +12 -0
  49. package/node_modules/@herbertgao/pi-recap/README.md +5 -3
  50. package/node_modules/@herbertgao/pi-recap/package.json +9 -3
  51. package/node_modules/@herbertgao/pi-recap/src/index.ts +3 -7
  52. package/node_modules/@herbertgao/pi-recap/src/model-picker.ts +6 -19
  53. package/node_modules/@herbertgao/pi-recap/src/models.ts +9 -21
  54. package/node_modules/@herbertgao/pi-recap/src/tui.ts +1 -1
  55. package/node_modules/@herbertgao/pi-rename/CHANGELOG.md +49 -0
  56. package/node_modules/@herbertgao/pi-rename/README.md +13 -11
  57. package/node_modules/@herbertgao/pi-rename/package.json +13 -3
  58. package/node_modules/@herbertgao/pi-rename/src/index.ts +135 -59
  59. package/node_modules/@herbertgao/pi-rename/src/models.ts +5 -13
  60. package/node_modules/@herbertgao/pi-rename/src/naming.ts +2 -6
  61. package/node_modules/@herbertgao/pi-stash/package.json +3 -3
  62. package/node_modules/@herbertgao/pi-subagents/CHANGELOG.md +8 -0
  63. package/node_modules/@herbertgao/pi-subagents/README.md +16 -3
  64. package/node_modules/@herbertgao/pi-subagents/package.json +1 -1
  65. package/node_modules/@herbertgao/pi-subagents/src/cross-extension-rpc.ts +15 -4
  66. package/node_modules/@herbertgao/pi-subagents/src/index.ts +16 -0
  67. package/node_modules/@herbertgao/pi-subagents/src/ui/conversation-viewer.ts +5 -1
  68. package/node_modules/pi-web-access/CHANGELOG.md +13 -0
  69. package/node_modules/pi-web-access/README.md +2 -2
  70. package/node_modules/pi-web-access/chrome-cookies.ts +12 -7
  71. package/node_modules/pi-web-access/gemini-search.ts +28 -10
  72. package/node_modules/pi-web-access/index.ts +24 -10
  73. package/node_modules/pi-web-access/package.json +1 -1
  74. package/node_modules/resume-from/LICENSE +21 -0
  75. package/node_modules/resume-from/README.md +161 -0
  76. package/node_modules/resume-from/dist/adapters/claude-code/adapter.d.ts +25 -0
  77. package/node_modules/resume-from/dist/adapters/claude-code/adapter.js +60 -0
  78. package/node_modules/resume-from/dist/adapters/claude-code/contract.d.ts +8 -0
  79. package/node_modules/resume-from/dist/adapters/claude-code/contract.js +4 -0
  80. package/node_modules/resume-from/dist/adapters/claude-code/entries.d.ts +30 -0
  81. package/node_modules/resume-from/dist/adapters/claude-code/entries.js +107 -0
  82. package/node_modules/resume-from/dist/adapters/claude-code/index.d.ts +3 -0
  83. package/node_modules/resume-from/dist/adapters/claude-code/index.js +2 -0
  84. package/node_modules/resume-from/dist/adapters/claude-code/layout.d.ts +29 -0
  85. package/node_modules/resume-from/dist/adapters/claude-code/layout.js +80 -0
  86. package/node_modules/resume-from/dist/adapters/claude-code/readback.d.ts +9 -0
  87. package/node_modules/resume-from/dist/adapters/claude-code/readback.js +39 -0
  88. package/node_modules/resume-from/dist/adapters/claude-code/reader.d.ts +37 -0
  89. package/node_modules/resume-from/dist/adapters/claude-code/reader.js +415 -0
  90. package/node_modules/resume-from/dist/adapters/claude-code/redaction.d.ts +26 -0
  91. package/node_modules/resume-from/dist/adapters/claude-code/redaction.js +132 -0
  92. package/node_modules/resume-from/dist/adapters/claude-code/validation.d.ts +4 -0
  93. package/node_modules/resume-from/dist/adapters/claude-code/validation.js +39 -0
  94. package/node_modules/resume-from/dist/adapters/claude-code/writer.d.ts +23 -0
  95. package/node_modules/resume-from/dist/adapters/claude-code/writer.js +306 -0
  96. package/node_modules/resume-from/dist/adapters/codex/contract.d.ts +15 -0
  97. package/node_modules/resume-from/dist/adapters/codex/contract.js +4 -0
  98. package/node_modules/resume-from/dist/adapters/codex/index.d.ts +6 -0
  99. package/node_modules/resume-from/dist/adapters/codex/index.js +44 -0
  100. package/node_modules/resume-from/dist/adapters/codex/read.d.ts +28 -0
  101. package/node_modules/resume-from/dist/adapters/codex/read.js +270 -0
  102. package/node_modules/resume-from/dist/adapters/codex/readback.d.ts +9 -0
  103. package/node_modules/resume-from/dist/adapters/codex/readback.js +47 -0
  104. package/node_modules/resume-from/dist/adapters/codex/redaction.d.ts +26 -0
  105. package/node_modules/resume-from/dist/adapters/codex/redaction.js +132 -0
  106. package/node_modules/resume-from/dist/adapters/codex/rollout.d.ts +75 -0
  107. package/node_modules/resume-from/dist/adapters/codex/rollout.js +185 -0
  108. package/node_modules/resume-from/dist/adapters/codex/validation.d.ts +7 -0
  109. package/node_modules/resume-from/dist/adapters/codex/validation.js +78 -0
  110. package/node_modules/resume-from/dist/adapters/codex/write.d.ts +17 -0
  111. package/node_modules/resume-from/dist/adapters/codex/write.js +141 -0
  112. package/node_modules/resume-from/dist/adapters/contract.d.ts +74 -0
  113. package/node_modules/resume-from/dist/adapters/contract.js +4 -0
  114. package/node_modules/resume-from/dist/adapters/pi/adapter.d.ts +15 -0
  115. package/node_modules/resume-from/dist/adapters/pi/adapter.js +209 -0
  116. package/node_modules/resume-from/dist/adapters/pi/contract.d.ts +24 -0
  117. package/node_modules/resume-from/dist/adapters/pi/contract.js +4 -0
  118. package/node_modules/resume-from/dist/adapters/pi/format.d.ts +162 -0
  119. package/node_modules/resume-from/dist/adapters/pi/format.js +223 -0
  120. package/node_modules/resume-from/dist/adapters/pi/index.d.ts +7 -0
  121. package/node_modules/resume-from/dist/adapters/pi/index.js +10 -0
  122. package/node_modules/resume-from/dist/adapters/pi/parse.d.ts +41 -0
  123. package/node_modules/resume-from/dist/adapters/pi/parse.js +371 -0
  124. package/node_modules/resume-from/dist/adapters/pi/redaction.d.ts +26 -0
  125. package/node_modules/resume-from/dist/adapters/pi/redaction.js +132 -0
  126. package/node_modules/resume-from/dist/adapters/pi/serialize.d.ts +22 -0
  127. package/node_modules/resume-from/dist/adapters/pi/serialize.js +87 -0
  128. package/node_modules/resume-from/dist/adapters/pi/validate.d.ts +14 -0
  129. package/node_modules/resume-from/dist/adapters/pi/validate.js +134 -0
  130. package/node_modules/resume-from/dist/bin.d.ts +35 -0
  131. package/node_modules/resume-from/dist/bin.js +135 -0
  132. package/node_modules/resume-from/dist/contract.d.ts +10 -0
  133. package/node_modules/resume-from/dist/contract.js +4 -0
  134. package/node_modules/resume-from/dist/host/agents.d.ts +29 -0
  135. package/node_modules/resume-from/dist/host/agents.js +20 -0
  136. package/node_modules/resume-from/dist/host/cli/args.d.ts +21 -0
  137. package/node_modules/resume-from/dist/host/cli/args.js +187 -0
  138. package/node_modules/resume-from/dist/host/cli/contract.d.ts +27 -0
  139. package/node_modules/resume-from/dist/host/cli/contract.js +4 -0
  140. package/node_modules/resume-from/dist/host/cli/index.d.ts +2 -0
  141. package/node_modules/resume-from/dist/host/cli/index.js +1 -0
  142. package/node_modules/resume-from/dist/host/cli/presentation.d.ts +2 -0
  143. package/node_modules/resume-from/dist/host/cli/presentation.js +11 -0
  144. package/node_modules/resume-from/dist/host/cli/render.d.ts +3 -0
  145. package/node_modules/resume-from/dist/host/cli/render.js +70 -0
  146. package/node_modules/resume-from/dist/host/cli/runner.d.ts +8 -0
  147. package/node_modules/resume-from/dist/host/cli/runner.js +125 -0
  148. package/node_modules/resume-from/dist/host/contract.d.ts +42 -0
  149. package/node_modules/resume-from/dist/host/contract.js +4 -0
  150. package/node_modules/resume-from/dist/host/entry.d.ts +52 -0
  151. package/node_modules/resume-from/dist/host/entry.js +91 -0
  152. package/node_modules/resume-from/dist/host/index.d.ts +11 -0
  153. package/node_modules/resume-from/dist/host/index.js +10 -0
  154. package/node_modules/resume-from/dist/host/pi-extension/command.d.ts +18 -0
  155. package/node_modules/resume-from/dist/host/pi-extension/command.js +103 -0
  156. package/node_modules/resume-from/dist/host/pi-extension/contract.d.ts +34 -0
  157. package/node_modules/resume-from/dist/host/pi-extension/contract.js +4 -0
  158. package/node_modules/resume-from/dist/host/pi-extension/index.d.ts +6 -0
  159. package/node_modules/resume-from/dist/host/pi-extension/index.js +4 -0
  160. package/node_modules/resume-from/dist/host/pi-extension/picker.d.ts +16 -0
  161. package/node_modules/resume-from/dist/host/pi-extension/picker.js +35 -0
  162. package/node_modules/resume-from/dist/host/pi-extension/presentation.d.ts +2 -0
  163. package/node_modules/resume-from/dist/host/pi-extension/presentation.js +11 -0
  164. package/node_modules/resume-from/dist/host/pi-extension/register.d.ts +25 -0
  165. package/node_modules/resume-from/dist/host/pi-extension/register.js +11 -0
  166. package/node_modules/resume-from/dist/host/pi-extension/ui.d.ts +20 -0
  167. package/node_modules/resume-from/dist/host/pi-extension/ui.js +1 -0
  168. package/node_modules/resume-from/dist/host/profile.d.ts +8 -0
  169. package/node_modules/resume-from/dist/host/profile.js +31 -0
  170. package/node_modules/resume-from/dist/host/registry.d.ts +8 -0
  171. package/node_modules/resume-from/dist/host/registry.js +33 -0
  172. package/node_modules/resume-from/dist/host/wiring.d.ts +41 -0
  173. package/node_modules/resume-from/dist/host/wiring.js +67 -0
  174. package/node_modules/resume-from/dist/import/confirmation.d.ts +6 -0
  175. package/node_modules/resume-from/dist/import/confirmation.js +27 -0
  176. package/node_modules/resume-from/dist/import/contract.d.ts +41 -0
  177. package/node_modules/resume-from/dist/import/contract.js +4 -0
  178. package/node_modules/resume-from/dist/import/discovery/contract.d.ts +58 -0
  179. package/node_modules/resume-from/dist/import/discovery/contract.js +4 -0
  180. package/node_modules/resume-from/dist/import/discovery/errors.d.ts +9 -0
  181. package/node_modules/resume-from/dist/import/discovery/errors.js +12 -0
  182. package/node_modules/resume-from/dist/import/discovery/finder.d.ts +10 -0
  183. package/node_modules/resume-from/dist/import/discovery/finder.js +129 -0
  184. package/node_modules/resume-from/dist/import/discovery/homes.d.ts +23 -0
  185. package/node_modules/resume-from/dist/import/discovery/homes.js +83 -0
  186. package/node_modules/resume-from/dist/import/discovery/index.d.ts +2 -0
  187. package/node_modules/resume-from/dist/import/discovery/index.js +2 -0
  188. package/node_modules/resume-from/dist/import/discovery/ordering.d.ts +3 -0
  189. package/node_modules/resume-from/dist/import/discovery/ordering.js +21 -0
  190. package/node_modules/resume-from/dist/import/errors.d.ts +22 -0
  191. package/node_modules/resume-from/dist/import/errors.js +20 -0
  192. package/node_modules/resume-from/dist/import/index.d.ts +3 -0
  193. package/node_modules/resume-from/dist/import/index.js +5 -0
  194. package/node_modules/resume-from/dist/import/landing/contract.d.ts +44 -0
  195. package/node_modules/resume-from/dist/import/landing/contract.js +4 -0
  196. package/node_modules/resume-from/dist/import/landing/errors.d.ts +15 -0
  197. package/node_modules/resume-from/dist/import/landing/errors.js +15 -0
  198. package/node_modules/resume-from/dist/import/landing/handover.d.ts +5 -0
  199. package/node_modules/resume-from/dist/import/landing/handover.js +12 -0
  200. package/node_modules/resume-from/dist/import/landing/index.d.ts +4 -0
  201. package/node_modules/resume-from/dist/import/landing/index.js +4 -0
  202. package/node_modules/resume-from/dist/import/landing/lander.d.ts +7 -0
  203. package/node_modules/resume-from/dist/import/landing/lander.js +133 -0
  204. package/node_modules/resume-from/dist/import/landing/marker.d.ts +9 -0
  205. package/node_modules/resume-from/dist/import/landing/marker.js +46 -0
  206. package/node_modules/resume-from/dist/import/pipeline.d.ts +17 -0
  207. package/node_modules/resume-from/dist/import/pipeline.js +134 -0
  208. package/node_modules/resume-from/dist/import/preview/builder.d.ts +6 -0
  209. package/node_modules/resume-from/dist/import/preview/builder.js +76 -0
  210. package/node_modules/resume-from/dist/import/preview/contract.d.ts +39 -0
  211. package/node_modules/resume-from/dist/import/preview/contract.js +4 -0
  212. package/node_modules/resume-from/dist/import/preview/format.d.ts +19 -0
  213. package/node_modules/resume-from/dist/import/preview/format.js +45 -0
  214. package/node_modules/resume-from/dist/import/preview/index.d.ts +2 -0
  215. package/node_modules/resume-from/dist/import/preview/index.js +1 -0
  216. package/node_modules/resume-from/dist/import/preview/warnings.d.ts +11 -0
  217. package/node_modules/resume-from/dist/import/preview/warnings.js +80 -0
  218. package/node_modules/resume-from/dist/import/transfer/contract.d.ts +48 -0
  219. package/node_modules/resume-from/dist/import/transfer/contract.js +4 -0
  220. package/node_modules/resume-from/dist/import/transfer/index.d.ts +2 -0
  221. package/node_modules/resume-from/dist/import/transfer/index.js +1 -0
  222. package/node_modules/resume-from/dist/import/transfer/rules.d.ts +3 -0
  223. package/node_modules/resume-from/dist/import/transfer/rules.js +228 -0
  224. package/node_modules/resume-from/dist/import/wiring.d.ts +24 -0
  225. package/node_modules/resume-from/dist/import/wiring.js +27 -0
  226. package/node_modules/resume-from/dist/index.d.ts +36 -0
  227. package/node_modules/resume-from/dist/index.js +36 -0
  228. package/node_modules/resume-from/dist/platform/config/contract.d.ts +35 -0
  229. package/node_modules/resume-from/dist/platform/config/contract.js +4 -0
  230. package/node_modules/resume-from/dist/platform/config/defaults.d.ts +16 -0
  231. package/node_modules/resume-from/dist/platform/config/defaults.js +22 -0
  232. package/node_modules/resume-from/dist/platform/config/errors.d.ts +9 -0
  233. package/node_modules/resume-from/dist/platform/config/errors.js +12 -0
  234. package/node_modules/resume-from/dist/platform/config/index.d.ts +5 -0
  235. package/node_modules/resume-from/dist/platform/config/index.js +6 -0
  236. package/node_modules/resume-from/dist/platform/config/loader.d.ts +10 -0
  237. package/node_modules/resume-from/dist/platform/config/loader.js +47 -0
  238. package/node_modules/resume-from/dist/platform/config/paths.d.ts +13 -0
  239. package/node_modules/resume-from/dist/platform/config/paths.js +37 -0
  240. package/node_modules/resume-from/dist/platform/config/validate.d.ts +9 -0
  241. package/node_modules/resume-from/dist/platform/config/validate.js +117 -0
  242. package/node_modules/resume-from/dist/platform/repo/contract.d.ts +30 -0
  243. package/node_modules/resume-from/dist/platform/repo/contract.js +4 -0
  244. package/node_modules/resume-from/dist/platform/repo/git.d.ts +21 -0
  245. package/node_modules/resume-from/dist/platform/repo/git.js +74 -0
  246. package/node_modules/resume-from/dist/platform/repo/index.d.ts +2 -0
  247. package/node_modules/resume-from/dist/platform/repo/index.js +1 -0
  248. package/node_modules/resume-from/dist/platform/repo/reader.d.ts +8 -0
  249. package/node_modules/resume-from/dist/platform/repo/reader.js +130 -0
  250. package/node_modules/resume-from/dist/platform/store/contract.d.ts +31 -0
  251. package/node_modules/resume-from/dist/platform/store/contract.js +4 -0
  252. package/node_modules/resume-from/dist/platform/store/file-committer.d.ts +3 -0
  253. package/node_modules/resume-from/dist/platform/store/file-committer.js +391 -0
  254. package/node_modules/resume-from/dist/platform/store/index.d.ts +2 -0
  255. package/node_modules/resume-from/dist/platform/store/index.js +2 -0
  256. package/node_modules/resume-from/dist/platform/tokens/contract.d.ts +12 -0
  257. package/node_modules/resume-from/dist/platform/tokens/contract.js +4 -0
  258. package/node_modules/resume-from/dist/platform/tokens/estimator.d.ts +12 -0
  259. package/node_modules/resume-from/dist/platform/tokens/estimator.js +111 -0
  260. package/node_modules/resume-from/dist/platform/tokens/index.d.ts +2 -0
  261. package/node_modules/resume-from/dist/platform/tokens/index.js +1 -0
  262. package/node_modules/resume-from/dist/session/contract.d.ts +109 -0
  263. package/node_modules/resume-from/dist/session/contract.js +4 -0
  264. package/node_modules/resume-from/package.json +80 -0
  265. package/node_modules/resume-from/shims/pi/extensions/resume-from.js +118 -0
  266. package/package.json +19 -14
@@ -4,6 +4,19 @@ All notable changes to this project will be documented in this file.
4
4
 
5
5
  ## [Unreleased]
6
6
 
7
+ ## [0.24.2] - 2026-08-22
8
+
9
+ ### Highlights
10
+ - `auto` search now uses Codex-backed OpenAI search when Pi is running a Codex model.
11
+ - Non-Codex sessions still prefer Exa first, so zero-config search keeps its fast keyless path.
12
+ - Gemini Web browser-cookie access is more reliable on Windows Chrome and Edge profiles.
13
+
14
+ ### Changed
15
+ - Prefer Codex-backed OpenAI search in `auto` mode when the active Pi model is `openai-codex`; otherwise prefer Exa before OpenAI.
16
+
17
+ ### Fixed
18
+ - Fixed Windows Gemini Web browser-cookie extraction when Chromium cookie expiry values are too large for JavaScript numbers or PowerShell DPAPI key unprotect needs encoded command transport. Thanks to [@laixuanthoi](https://github.com/laixuanthoi) for issue #290.
19
+
7
20
  ## [0.24.1] - 2026-08-21
8
21
 
9
22
  ### Added
@@ -18,7 +18,7 @@
18
18
 
19
19
  **Video Understanding** — Point it at a YouTube video or local screen recording and ask questions about what's on screen. Full transcripts, visual descriptions, and frame extraction at exact timestamps.
20
20
 
21
- **Smart Fallbacks** — Every capability has a fallback chain. Search tries configured SearXNG first for local/private search, then OpenAI when suitable and available, Exa, Brave, Parallel, TinyFish, Search1API, Searchinfinity, Querit, Tavily, Firecrawl, Jina, SERPdive, Kagi, Bocha, Ollama, Perplexity, Gemini API, and Gemini Web when browser cookies are enabled. With no SearXNG configured, the existing zero-config order is unchanged. YouTube tries Gemini Web when enabled, then API, then Perplexity. Blocked pages try configured self-hosted Firecrawl first. Third-party hosted page fetchers require explicit `fetchRouting.allowRemoteHostedProviders` opt-in for remote HTTP(S) targets.
21
+ **Smart Fallbacks** — Every capability has a fallback chain. Search tries configured SearXNG first for local/private search. When the active Pi model is `openai-codex`, it then tries Codex-backed OpenAI search. Otherwise it tries Exa before OpenAI, then Brave, Parallel, TinyFish, Search1API, Searchinfinity, Querit, Tavily, Firecrawl, Jina, SERPdive, Kagi, Bocha, Ollama, Perplexity, Gemini API, and Gemini Web when browser cookies are enabled. YouTube tries Gemini Web when enabled, then API, then Perplexity. Blocked pages try configured self-hosted Firecrawl first. Third-party hosted page fetchers require explicit `fetchRouting.allowRemoteHostedProviders` opt-in for remote HTTP(S) targets.
22
22
 
23
23
  **GitHub Cloning** — GitHub URLs are cloned locally instead of scraped. The agent gets real file contents and a local path to explore, not rendered HTML.
24
24
 
@@ -46,7 +46,7 @@ Works immediately with no API keys — Exa MCP provides zero-config search. If P
46
46
  }
47
47
  ```
48
48
 
49
- In `auto` mode (default), `web_search` tries a configured SearXNG endpoint first for local/private search, then OpenAI when suitable and available, Exa (direct API if keyed, MCP if not), Brave, Parallel, TinyFish, Search1API, Searchinfinity, Querit, Tavily, Firecrawl, Jina, SERPdive, Perplexity, Gemini API, and Gemini Web when browser-cookie access is enabled. With no SearXNG configured, the existing zero-config order is unchanged. Exa handles search; curator summary drafts are generated separately by the configured Pi summary model, defaulting to Claude Haiku, Codex Luna, Codex Terra, Gemini 3.6 Flash, GPT-5 mini, then DeepSeek V4 Flash when available. Slow summary drafts fall back to a deterministic result summary after a bounded deadline.
49
+ In `auto` mode (default), `web_search` tries a configured SearXNG endpoint first for local/private search. When the active Pi model is `openai-codex`, it then tries Codex-backed OpenAI search. Otherwise it tries Exa (direct API if keyed, MCP if not) before OpenAI, then Brave, Parallel, TinyFish, Search1API, Searchinfinity, Querit, Tavily, Firecrawl, Jina, SERPdive, Perplexity, Gemini API, and Gemini Web when browser-cookie access is enabled. Exa handles search; curator summary drafts are generated separately by the configured Pi summary model, defaulting to Claude Haiku, Codex Luna, Codex Terra, Gemini 3.6 Flash, GPT-5 mini, then DeepSeek V4 Flash when available. Slow summary drafts fall back to a deterministic result summary after a bounded deadline.
50
50
 
51
51
  If your OpenAI key belongs to a third-party Responses-compatible gateway, set `openaiResponsesUrl` to that gateway's full Responses endpoint. The default remains `https://api.openai.com/v1/responses`.
52
52
 
@@ -375,8 +375,9 @@ async function readWindowsEncryptionKey(config: BrowserConfig, home: string): Pr
375
375
 
376
376
  function unprotectWindowsData(protectedData: Buffer): Promise<Buffer | null> {
377
377
  return new Promise((resolve) => {
378
- const script = "$data=[Convert]::FromBase64String($args[0]);$clear=[Security.Cryptography.ProtectedData]::Unprotect($data,$null,[Security.Cryptography.DataProtectionScope]::CurrentUser);[Console]::Write([Convert]::ToBase64String($clear))";
379
- execFile("powershell.exe", ["-NoProfile", "-NonInteractive", "-Command", script, protectedData.toString("base64")], { timeout: 5000, maxBuffer: 1024 * 1024 }, (err, stdout) => {
378
+ const script = "Add-Type -AssemblyName System.Security;$data=[Convert]::FromBase64String($env:PIWA_PROTECTED);$clear=[System.Security.Cryptography.ProtectedData]::Unprotect($data,$null,[System.Security.Cryptography.DataProtectionScope]::CurrentUser);[Console]::Write([Convert]::ToBase64String($clear))";
379
+ const encoded = Buffer.from(script, "utf16le").toString("base64");
380
+ execFile("powershell.exe", ["-NoProfile", "-NonInteractive", "-EncodedCommand", encoded], { timeout: 5000, maxBuffer: 1024 * 1024, env: { ...process.env, PIWA_PROTECTED: protectedData.toString("base64") } }, (err, stdout) => {
380
381
  if (err) { resolve(null); return; }
381
382
  try {
382
383
  resolve(Buffer.from(stdout.trim(), "base64"));
@@ -509,10 +510,10 @@ async function queryCookieRows(dbPath: string, hosts: string[], names: Iterable<
509
510
  const columns = await readCookieColumns(dbPath);
510
511
  if (columns.status === "failure") return columns;
511
512
  const pathExpr = columns.columns.has("path") ? "path" : "'/' AS path";
512
- const expiresExpr = columns.columns.has("expires_utc") ? "expires_utc" : "0 AS expires_utc";
513
- const expiryFilter = filterExpired && columns.columns.has("expires_utc") ? ` AND (expires_utc = 0 OR expires_utc > ${chromeExpiryNowMicros()})` : "";
513
+ const expiresExpr = columns.columns.has("expires_utc") ? chromeExpiryMillisExpr() : "0";
514
+ const expiryFilter = filterExpired && columns.columns.has("expires_utc") ? ` AND (${expiresExpr} = 0 OR ${expiresExpr} > ${chromeExpiryNowMillis()})` : "";
514
515
  const partitionFilter = filterExpired ? unpartitionedCookieFilter(columns.columns) : "";
515
- return runSqliteQuery(dbPath, `SELECT name, value, host_key, ${pathExpr}, ${expiresExpr}, hex(encrypted_value) AS encrypted_value_hex FROM cookies WHERE ${buildCookieWhere(hosts, names ?? undefined)}${expiryFilter}${partitionFilter} ORDER BY length(path) DESC, expires_utc ASC`);
516
+ return runSqliteQuery(dbPath, `SELECT name, value, host_key, ${pathExpr}, ${expiresExpr} AS expires_utc, hex(encrypted_value) AS encrypted_value_hex FROM cookies WHERE ${buildCookieWhere(hosts, names ?? undefined)}${expiryFilter}${partitionFilter} ORDER BY length(path) DESC, ${expiresExpr} ASC`);
516
517
  }
517
518
 
518
519
  async function readCookieColumns(dbPath: string): Promise<{ status: "success"; columns: Set<string> } | { status: "failure"; failure: SqliteFailure }> {
@@ -521,8 +522,12 @@ async function readCookieColumns(dbPath: string): Promise<{ status: "success"; c
521
522
  return { status: "success", columns: new Set(result.rows.map(row => typeof row.name === "string" ? row.name : "")) };
522
523
  }
523
524
 
524
- function chromeExpiryNowMicros(): number {
525
- return (Date.now() + 11644473600000) * 1000;
525
+ function chromeExpiryMillisExpr(): string {
526
+ return "CASE WHEN expires_utc = 0 THEN 0 ELSE CAST(expires_utc / 1000 AS INTEGER) + CASE WHEN expires_utc % 1000 = 0 THEN 0 ELSE 1 END END";
527
+ }
528
+
529
+ function chromeExpiryNowMillis(): number {
530
+ return Date.now() + 11644473600000;
526
531
  }
527
532
 
528
533
  function unpartitionedCookieFilter(columns: Set<string>): string {
@@ -216,6 +216,24 @@ function shouldTryOpenAIInAuto(options: SearchOptions): boolean {
216
216
  return true;
217
217
  }
218
218
 
219
+ function isOpenAICodexSelected(ctx?: ExtensionContext): boolean {
220
+ return ctx?.model?.provider === "openai-codex";
221
+ }
222
+
223
+ async function tryOpenAIInAuto(query: string, options: FullSearchOptions, fallbackErrors: string[]): Promise<AttributedSearchResponse | null> {
224
+ if (!shouldTryOpenAIInAuto(options)) return null;
225
+ try {
226
+ if (await isOpenAISearchAvailable(options.extensionContext)) {
227
+ const result = await searchWithOpenAI(query, options, options.extensionContext);
228
+ return { ...result, provider: "openai" };
229
+ }
230
+ } catch (err) {
231
+ if (isAbortError(err)) throw err;
232
+ fallbackErrors.push(`OpenAI: ${errorMessage(err)}`);
233
+ }
234
+ return null;
235
+ }
236
+
219
237
  async function searchWithGemini(
220
238
  query: string,
221
239
  options: SearchOptions,
@@ -524,16 +542,11 @@ export async function search(query: string, options: FullSearchOptions = {}): Pr
524
542
  }
525
543
  }
526
544
 
527
- if (shouldTryOpenAIInAuto(options)) {
528
- try {
529
- if (await isOpenAISearchAvailable(options.extensionContext)) {
530
- const result = await searchWithOpenAI(query, options, options.extensionContext);
531
- return { ...result, provider: "openai" };
532
- }
533
- } catch (err) {
534
- if (isAbortError(err)) throw err;
535
- fallbackErrors.push(`OpenAI: ${errorMessage(err)}`);
536
- }
545
+ let triedOpenAI = false;
546
+ if (!options.extensionContext || isOpenAICodexSelected(options.extensionContext)) {
547
+ triedOpenAI = true;
548
+ const result = await tryOpenAIInAuto(query, options, fallbackErrors);
549
+ if (result) return result;
537
550
  }
538
551
 
539
552
  if (isExaAvailable()) {
@@ -546,6 +559,11 @@ export async function search(query: string, options: FullSearchOptions = {}): Pr
546
559
  }
547
560
  }
548
561
 
562
+ if (!triedOpenAI) {
563
+ const result = await tryOpenAIInAuto(query, options, fallbackErrors);
564
+ if (result) return result;
565
+ }
566
+
549
567
  if (isBraveAvailable()) {
550
568
  try {
551
569
  const result = await searchWithBrave(query, options);
@@ -152,7 +152,7 @@ interface WebSearchConfig {
152
152
  };
153
153
  }
154
154
 
155
- interface ProviderAvailability {
155
+ export interface ProviderAvailability {
156
156
  all: boolean;
157
157
  openai: boolean;
158
158
  brave: boolean;
@@ -184,7 +184,7 @@ interface ProviderAvailability {
184
184
 
185
185
  type WebSearchWorkflow = "none" | "summary-review" | "auto-summary";
186
186
  type CuratorWorkflow = "summary-review";
187
- type CuratorProvider = Exclude<SearchProvider, "auto">;
187
+ export type CuratorProvider = Exclude<SearchProvider, "auto">;
188
188
  type SummaryWorkflow = "summary-review" | "auto-summary";
189
189
 
190
190
  interface CuratorBootstrap {
@@ -420,13 +420,16 @@ async function getProviderAvailability(ctx: ExtensionContext): Promise<ProviderA
420
420
  };
421
421
  }
422
422
 
423
- function shouldPreferOpenAI(options?: Pick<PendingCurate, "numResults" | "recencyFilter">): boolean {
424
- if (!options) return true;
425
- if (options.recencyFilter) return false;
426
- if (typeof options.numResults === "number" && Number.isFinite(options.numResults) && Math.floor(options.numResults) !== 5) {
423
+ function shouldUseOpenAICodexDefault(ctx?: Pick<ExtensionContext, "model">): boolean {
424
+ return ctx?.model?.provider === "openai-codex";
425
+ }
426
+
427
+ function shouldPreferOpenAI(options: Pick<PendingCurate, "numResults" | "recencyFilter"> | undefined, preferOpenAICodexDefault: boolean): boolean {
428
+ if (options?.recencyFilter) return false;
429
+ if (typeof options?.numResults === "number" && Number.isFinite(options.numResults) && Math.floor(options.numResults) !== 5) {
427
430
  return false;
428
431
  }
429
- return true;
432
+ return preferOpenAICodexDefault;
430
433
  }
431
434
 
432
435
  async function loadCuratorBootstrap(
@@ -439,15 +442,25 @@ async function loadCuratorBootstrap(
439
442
  if (Array.isArray(provider)) availableProviders.all = true;
440
443
  return {
441
444
  availableProviders,
442
- defaultProvider: resolveProvider(provider, availableProviders, options),
445
+ defaultProvider: resolveCuratorDefaultProvider(provider, availableProviders, ctx, options),
443
446
  timeoutSeconds: getCuratorTimeoutSeconds(),
444
447
  };
445
448
  }
446
449
 
450
+ export function resolveCuratorDefaultProvider(
451
+ provider: SearchProviderSelection,
452
+ available: ProviderAvailability,
453
+ ctx?: Pick<ExtensionContext, "model">,
454
+ options?: Pick<PendingCurate, "numResults" | "recencyFilter">,
455
+ ): CuratorProvider {
456
+ return resolveProvider(provider, available, options, shouldUseOpenAICodexDefault(ctx));
457
+ }
458
+
447
459
  function firstAvailableProvider(available: ProviderAvailability, preferOpenAI: boolean, fallback: ResolvedSearchProvider): ResolvedSearchProvider {
448
460
  if (available.searxng) return "searxng";
449
461
  if (preferOpenAI && available.openai) return "openai";
450
462
  if (available.exa) return "exa";
463
+ if (available.openai) return "openai";
451
464
  if (available.brave) return "brave";
452
465
  if (available.parallel) return "parallel";
453
466
  if (available.tinyfish) return "tinyfish";
@@ -470,9 +483,10 @@ function resolveProvider(
470
483
  provider: SearchProviderSelection,
471
484
  available: ProviderAvailability,
472
485
  options?: Pick<PendingCurate, "numResults" | "recencyFilter">,
486
+ preferOpenAICodexDefault = false,
473
487
  ): CuratorProvider {
474
488
  if (Array.isArray(provider)) return "all";
475
- const preferOpenAI = shouldPreferOpenAI(options);
489
+ const preferOpenAI = shouldPreferOpenAI(options, preferOpenAICodexDefault);
476
490
 
477
491
  if (provider === "auto") {
478
492
  const routing = getConfiguredSearchRouting();
@@ -1660,7 +1674,7 @@ export default function (pi: ExtensionAPI) {
1660
1674
  name: toolNames.webSearch,
1661
1675
  label: "Web Search",
1662
1676
  description:
1663
- `Search the web using OpenAI, Brave, Parallel, Parallel MCP, TinyFish, Search1API, Searchinfinity, Querit, Tavily, Firecrawl, Jina, SERPdive, Kagi, Bocha, Ollama, SearXNG, DuckDuckGo, Exa, Perplexity, Gemini, AnySearch, Valyu, xAI, Bright Data, SerpBase, or Serper. Pass a provider array to search only those providers simultaneously, or use provider "all" to search every eligible provider except Parallel MCP, DuckDuckGo, AnySearch, Valyu, xAI, Bright Data, SerpBase, and Serper. Returns an AI-synthesized answer with source citations. OpenAI search uses a Codex subscription or OpenAI API key; xAI search uses a SuperGrok/X Premium subscription or xAI API key. Parallel MCP, DuckDuckGo, AnySearch, Valyu, xAI, Bright Data, SerpBase, and Serper are available only when explicitly selected. For comprehensive research, prefer queries (plural) with 2-4 varied angles over a single query — each query gets its own synthesized answer, so varying phrasing and scope gives much broader coverage. When includeContent is true, full page content is fetched in the background. Searches auto-open the interactive browser curator and stream results live; set workflow to "none" to skip curation or "auto-summary" for a model-generated summary without the browser curator. The configured provider is used when provider is omitted or set to auto; omit provider unless explicitly overriding it. Without a configured provider, auto-selects OpenAI when suitable and available, then Exa, Brave, Parallel, TinyFish, Search1API, Searchinfinity, Querit, Tavily, Firecrawl, Jina, SERPdive, Kagi, Bocha, Ollama, Perplexity, Gemini API, or Gemini Web. When SearXNG is configured, it is preferred first for local/private search.`,
1677
+ `Search the web using OpenAI, Brave, Parallel, Parallel MCP, TinyFish, Search1API, Searchinfinity, Querit, Tavily, Firecrawl, Jina, SERPdive, Kagi, Bocha, Ollama, SearXNG, DuckDuckGo, Exa, Perplexity, Gemini, AnySearch, Valyu, xAI, Bright Data, SerpBase, or Serper. Pass a provider array to search only those providers simultaneously, or use provider "all" to search every eligible provider except Parallel MCP, DuckDuckGo, AnySearch, Valyu, xAI, Bright Data, SerpBase, and Serper. Returns an AI-synthesized answer with source citations. OpenAI search uses a Codex subscription or OpenAI API key; xAI search uses a SuperGrok/X Premium subscription or xAI API key. Parallel MCP, DuckDuckGo, AnySearch, Valyu, xAI, Bright Data, SerpBase, and Serper are available only when explicitly selected. For comprehensive research, prefer queries (plural) with 2-4 varied angles over a single query — each query gets its own synthesized answer, so varying phrasing and scope gives much broader coverage. When includeContent is true, full page content is fetched in the background. Searches auto-open the interactive browser curator and stream results live; set workflow to "none" to skip curation or "auto-summary" for a model-generated summary without the browser curator. The configured provider is used when provider is omitted or set to auto; omit provider unless explicitly overriding it. Without a configured provider, SearXNG is preferred first for local/private search. When the active Pi model is openai-codex, Codex-backed OpenAI search is preferred next. Otherwise Exa is preferred before OpenAI, then Brave, Parallel, TinyFish, Search1API, Searchinfinity, Querit, Tavily, Firecrawl, Jina, SERPdive, Kagi, Bocha, Ollama, Perplexity, Gemini API, or Gemini Web.`,
1664
1678
  promptSnippet:
1665
1679
  "Use for web research questions. Prefer {queries:[...]} with 2-4 varied angles over a single query for broader coverage. Omit provider unless explicitly overriding the configured default.",
1666
1680
  parameters: Type.Object({
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-web-access",
3
- "version": "0.24.1",
3
+ "version": "0.24.2",
4
4
  "description": "Web search, URL fetching, GitHub repo cloning, PDF extraction, YouTube video understanding, and local video analysis for Pi coding agent. Supports OpenAI, Brave, Parallel, TinyFish, Search1API, Searchinfinity, Querit, Tavily, Firecrawl, Jina, SERPdive, Kagi, Ollama, AnySearch, Bright Data SERP, SerpBase, SearXNG, Exa, Perplexity, and Gemini.",
5
5
  "type": "module",
6
6
  "scripts": {
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Alexei Led
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,161 @@
1
+ # resume-from
2
+
3
+ [![Release](https://github.com/alexei-led/resume-from/actions/workflows/release.yml/badge.svg)](https://github.com/alexei-led/resume-from/actions/workflows/release.yml)
4
+ [![npm](https://img.shields.io/npm/v/resume-from)](https://www.npmjs.com/package/resume-from)
5
+
6
+ ![A source coding-agent session is normalized, filtered, previewed, and written as a new native session while the source remains unchanged.](assets/resume-from-card.svg)
7
+
8
+ Continue an AI coding session in another terminal agent or another profile of the same agent.
9
+
10
+ `resume-from` converts saved sessions between **Pi**, **Claude Code**, and **Codex**. Use it when you want a different model, provider, tool harness, or account without rebuilding the task context by hand.
11
+
12
+ ## Why this exists
13
+
14
+ Coding agents save conversations in different locations and vendor-specific formats. A Codex thread is not a Pi session. A Claude Code session cannot be opened directly by Codex.
15
+
16
+ You can ask the next agent to read another tool's raw session file, but then the model must understand that format and decide which internal data is safe or useful. `resume-from` performs that conversion before the target agent starts:
17
+
18
+ 1. Find sessions for the current Git repository.
19
+ 2. Parse the source agent's format into a common conversation model.
20
+ 3. Remove tool-result bodies and vendor-only state.
21
+ 4. Fit the useful history to the target context budget.
22
+ 5. Show exactly what will be imported.
23
+ 6. After confirmation, write a new session in the target agent's native format.
24
+
25
+ The source session is never changed.
26
+
27
+ ## Use it when
28
+
29
+ - **You want another model or provider.** Start the target agent with the model you want, then import the session.
30
+ - **You want another harness.** Keep the task context while changing terminal UI, tools, permissions, extensions, or agent behavior.
31
+ - **You hit a rate or usage limit.** Continue through another installed agent or account instead of waiting or reconstructing the task.
32
+ - **You need another profile.** Move between work, personal, or team homes, including two profiles of the same agent.
33
+ - **The current context is too large.** Import a budgeted history into a fresh native session.
34
+ - **You want an independent handoff.** Create a target-side copy for continued work or review while preserving the original session.
35
+
36
+ `resume-from` moves conversation context. It does not copy the repository or migrate a running process. The target agent must have access to the same working tree.
37
+
38
+ ## Supported transfers
39
+
40
+ Every source-to-target direction is supported, including transfers within the same agent:
41
+
42
+ | Source \ Target | Pi | Claude Code | Codex |
43
+ | --------------- | :-: | :---------: | :---: |
44
+ | **Pi** | ✓ | ✓ | ✓ |
45
+ | **Claude Code** | ✓ | ✓ | ✓ |
46
+ | **Codex** | ✓ | ✓ | ✓ |
47
+
48
+ The landing behavior depends on the target:
49
+
50
+ | Target | After confirmation |
51
+ | --------------- | ---------------------------------------------------------------- |
52
+ | **Pi** | Writes and opens the imported session in the current Pi process. |
53
+ | **Claude Code** | Writes the session and prints `claude --resume <session-id>`. |
54
+ | **Codex** | Writes the thread and prints `codex resume <thread-id>`. |
55
+
56
+ ## What crosses the boundary
57
+
58
+ The importer keeps the parts needed to continue the task, subject to the target token budget:
59
+
60
+ - User prompts and agent replies.
61
+ - Compaction summaries.
62
+ - Tool activity as **non-replayable plain text**: tool name, recorded arguments, and a one-line outcome.
63
+ - Changed-file paths derived from mutating tool activity.
64
+ - Source provenance and a summary of anything dropped.
65
+
66
+ It excludes:
67
+
68
+ - Tool-result bodies, which may be large, stale, or sensitive.
69
+ - Replayable tool-call structures.
70
+ - Hidden reasoning, system prompts, environment blocks, API keys, telemetry, and vendor process state.
71
+
72
+ A dropped result is marked in the imported conversation. The target agent can reread the current file or rerun a command when it needs fresh state.
73
+
74
+ ### Context budget
75
+
76
+ By default, the imported history may use up to 30% of the target context window. The first request, recent turns, summaries, and changed-file records are pinned. If older unpinned turns must be removed, the preview reports them. If the pinned content alone does not fit, the import stops before writing.
77
+
78
+ ## Install in the destination agent
79
+
80
+ Install `resume-from` in the agent that will receive the new session.
81
+
82
+ ### Pi
83
+
84
+ ```sh
85
+ pi install npm:resume-from
86
+ ```
87
+
88
+ Restart Pi, then run `/resume-from`.
89
+
90
+ ### Claude Code
91
+
92
+ ```sh
93
+ claude plugin marketplace add alexei-led/resume-from
94
+ claude plugin install resume-from@alexei-led-resume-from
95
+ ```
96
+
97
+ ### Codex
98
+
99
+ ```sh
100
+ codex plugin marketplace add alexei-led/resume-from
101
+ codex plugin add resume-from@alexei-led-resume-from
102
+ ```
103
+
104
+ The Codex prompt runs the matching published `resume-from` package through `npx`. Its first use needs npm registry access.
105
+
106
+ ## Run the first transfer
107
+
108
+ Run the command from the Git repository that owns the source session.
109
+
110
+ ### In Pi
111
+
112
+ 1. Run `/resume-from`.
113
+ 2. Select a source session in the native picker.
114
+ 3. Read the preview.
115
+ 4. Confirm.
116
+
117
+ Pi opens the imported session with an empty prompt. You decide when to continue.
118
+
119
+ ### In Claude Code or Codex
120
+
121
+ 1. Run `/resume-from` to list matching sessions.
122
+ 2. Run `/resume-from <row>` to preview one.
123
+ 3. Run the token-bearing `/resume-from <row> --confirm <token>` command printed by the preview.
124
+ 4. Run the native resume command printed by the tool.
125
+
126
+ You can also select an exact session ID or file path. Selection by path does not bypass the current-repository check.
127
+
128
+ ## Safety properties
129
+
130
+ - **Read-only source:** source homes and session files are not modified.
131
+ - **Explicit write:** cancellation or a blocked preview writes nothing.
132
+ - **Add-only target:** the importer creates target files; it does not replace or delete existing sessions.
133
+ - **Native validation:** the new file is validated and read back before it is reported as openable.
134
+ - **No model call during transfer:** conversion, filtering, budgeting, and writing are deterministic local operations.
135
+ - **Visible provenance:** the imported session identifies its source and states what was dropped without putting that marker in model context. Pi renders it as a transcript entry; Claude Code uses its native metadata entry; Codex prints it in the CLI because no safe durable out-of-context entry is verified.
136
+
137
+ ## Documentation
138
+
139
+ The user and maintainer documentation is organized in [`docs/`](docs/README.md).
140
+
141
+ ## Development
142
+
143
+ Development requires Node 24 LTS and pnpm 11.20.0.
144
+
145
+ ```sh
146
+ pnpm install
147
+ pnpm build
148
+ pnpm test
149
+ pnpm typecheck
150
+ pnpm lint
151
+ ```
152
+
153
+ Run the command help after a build:
154
+
155
+ ```sh
156
+ node dist/bin.js --help
157
+ ```
158
+
159
+ ## License
160
+
161
+ MIT.
@@ -0,0 +1,25 @@
1
+ /**
2
+ * The Claude Code adapter: the port of `src/adapters/`, filled in with what this module knows
3
+ * about Claude Code.
4
+ */
5
+ import type { AgentAdapter, ClaudeCodeAdapterFactory } from "./contract.js";
6
+ /** Claude Code's context window, used when configuration overrides none (FR-18). */
7
+ export declare const DEFAULT_WINDOW_TOKENS = 200000;
8
+ /** The command the landing hands back, because Claude Code cannot move the user (C-2, FR-45). */
9
+ export declare const HANDOVER_COMMAND = "claude --resume";
10
+ export interface ClaudeCodeAdapterDeps {
11
+ /**
12
+ * The repository the import runs in. Claude Code keys a session to a repository, and no
13
+ * argument of the port names one, so the working directory is the signal.
14
+ */
15
+ cwd: string;
16
+ env: Record<string, string | undefined>;
17
+ homeDir: string;
18
+ }
19
+ /**
20
+ * Build the adapter. `deps` exists for the tests of this module: the shipped factory below
21
+ * passes the real process values.
22
+ */
23
+ export declare function createClaudeCodeAdapter(deps?: Partial<ClaudeCodeAdapterDeps>): AgentAdapter;
24
+ /** The only export of this module (FR-57). */
25
+ export declare const claudeCodeAdapter: ClaudeCodeAdapterFactory;
@@ -0,0 +1,60 @@
1
+ /**
2
+ * The Claude Code adapter: the port of `src/adapters/`, filled in with what this module knows
3
+ * about Claude Code.
4
+ */
5
+ import { resolveDefaultHome } from "./layout.js";
6
+ import { readBack } from "./readback.js";
7
+ import { listSessions, loadSession } from "./reader.js";
8
+ import { serialize, validate } from "./writer.js";
9
+ /** Claude Code's context window, used when configuration overrides none (FR-18). */
10
+ export const DEFAULT_WINDOW_TOKENS = 200_000;
11
+ /** The command the landing hands back, because Claude Code cannot move the user (C-2, FR-45). */
12
+ export const HANDOVER_COMMAND = "claude --resume";
13
+ /**
14
+ * Build the adapter. `deps` exists for the tests of this module: the shipped factory below
15
+ * passes the real process values.
16
+ */
17
+ export function createClaudeCodeAdapter(deps = {}) {
18
+ const cwd = deps.cwd ?? process.cwd();
19
+ const env = deps.env ?? process.env;
20
+ // Resolved once: capabilities() is pure, synchronous, and equal on every call.
21
+ const capabilities = Object.freeze({
22
+ agent: "claude-code",
23
+ roles: ["source", "target"],
24
+ selection: "numbered-list",
25
+ landing: "create-only",
26
+ provenance: "out-of-context-entry",
27
+ defaultHome: deps.homeDir === undefined ? resolveDefaultHome(env) : resolveDefaultHome(env, deps.homeDir),
28
+ defaultWindowTokens: DEFAULT_WINDOW_TOKENS,
29
+ });
30
+ return {
31
+ capabilities() {
32
+ return capabilities;
33
+ },
34
+ listSessions(home) {
35
+ return listSessions(home);
36
+ },
37
+ loadSession(descriptor) {
38
+ return loadSession(descriptor);
39
+ },
40
+ serialize(session, target, marker) {
41
+ return serialize(session, target, marker, { cwd });
42
+ },
43
+ validate(serialized) {
44
+ return validate(serialized);
45
+ },
46
+ readBack(home, sessionId) {
47
+ return readBack(home, sessionId);
48
+ },
49
+ switchTo(_home, sessionId, _runtime) {
50
+ return Promise.reject(new Error('Claude Code declares landing "create-only": it cannot move the user into a session ' +
51
+ `(C-2). Run: ${HANDOVER_COMMAND} ${sessionId}`));
52
+ },
53
+ };
54
+ }
55
+ /** The only export of this module (FR-57). */
56
+ export const claudeCodeAdapter = {
57
+ create() {
58
+ return createClaudeCodeAdapter();
59
+ },
60
+ };
@@ -0,0 +1,8 @@
1
+ import type { AdapterRole, AgentAdapter, AgentCapabilities, AgentRuntime, Bytes, LandingLevel, PendingFile, ProvenanceSupport, SelectionLevel, SerializedSession, StoredSessionFacts, SwitchOutcome, ValidationDefect } from "../contract.js";
2
+ export type { AdapterRole, AgentAdapter, AgentCapabilities, AgentRuntime, Bytes, LandingLevel, PendingFile, ProvenanceSupport, SelectionLevel, SerializedSession, StoredSessionFacts, SwitchOutcome, ValidationDefect, };
3
+ import type { AgentId, CanonicalSession, CanonicalTurn, HomePath, ProvenanceMarker, RepoSnapshot, SessionDescriptor, SessionId, SessionRef, SourceProvenance, TargetProfile, ToolCallRecord, ToolEffect, TurnKind, TurnRole } from "../../session/contract.js";
4
+ export type { AgentId, CanonicalSession, CanonicalTurn, HomePath, ProvenanceMarker, RepoSnapshot, SessionDescriptor, SessionId, SessionRef, SourceProvenance, TargetProfile, ToolCallRecord, ToolEffect, TurnKind, TurnRole, };
5
+ /** Builds the Claude Code adapter. The only export of this module (FR-57). */
6
+ export interface ClaudeCodeAdapterFactory {
7
+ create(): AgentAdapter;
8
+ }
@@ -0,0 +1,4 @@
1
+ // GENERATED from src/adapters/claude-code/module.md — the Public Contract section is the normative home.
2
+ // Declarations only: no behaviour, no defaults. If this file and module.md disagree,
3
+ // the document wins and this file is corrected.
4
+ export {};
@@ -0,0 +1,30 @@
1
+ /**
2
+ * The Claude Code session file: one JSON object per line.
3
+ *
4
+ * The store holds ten entry types (C-3). This module reads the few that carry turns and writes
5
+ * exactly two, `user` and `assistant` (C-9) — fewer types, fewer ways to corrupt the store.
6
+ */
7
+ export declare const ENTRY_TYPE_USER = "user";
8
+ export declare const ENTRY_TYPE_ASSISTANT = "assistant";
9
+ export declare const ENTRY_TYPE_SUMMARY = "summary";
10
+ /** The only entry types `serialize` writes (C-9). */
11
+ export declare const WRITTEN_ENTRY_TYPES: readonly string[];
12
+ export type RawEntry = Record<string, unknown>;
13
+ export interface JsonlParse {
14
+ entries: RawEntry[];
15
+ /** Set when a line is not a complete entry — the file is cut mid-entry. */
16
+ unreadable: string | null;
17
+ }
18
+ export interface ActiveEntryPath {
19
+ entries: RawEntry[];
20
+ unreadable: string | null;
21
+ }
22
+ /** Parse a session file. A line that is not a complete entry makes the whole file unreadable. */
23
+ export declare function parseJsonl(text: string): JsonlParse;
24
+ /** Follow the last non-sidechain UUID record to the root of Claude's active transcript. */
25
+ export declare function resolveActiveEntryPath(entries: RawEntry[]): ActiveEntryPath;
26
+ export declare function asString(value: unknown): string | null;
27
+ export declare function asObject(value: unknown): Record<string, unknown> | null;
28
+ export declare function asArray(value: unknown): unknown[] | null;
29
+ /** ISO-8601 UTC, the vocabulary every timestamp of the canonical model uses. */
30
+ export declare function toIsoUtc(value: unknown): string | null;