@dev-sergeev/datalab-kit 0.1.2 → 0.1.3

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 (332) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/README.md +23 -5
  3. package/THIRD_PARTY_NOTICES.md +6 -2
  4. package/dist/extension.js +8 -1
  5. package/dist/recap.d.ts +2 -0
  6. package/dist/recap.js +31 -0
  7. package/docs/adr/0002-package-delivery.md +2 -0
  8. package/node_modules/@pi-plugins/elapsed/LICENSE +21 -0
  9. package/node_modules/@pi-plugins/elapsed/README.md +45 -0
  10. package/node_modules/@pi-plugins/elapsed/dist/index.d.mts +8 -0
  11. package/node_modules/@pi-plugins/elapsed/dist/index.d.mts.map +1 -0
  12. package/node_modules/@pi-plugins/elapsed/dist/index.mjs +47 -0
  13. package/node_modules/@pi-plugins/elapsed/dist/index.mjs.map +1 -0
  14. package/node_modules/@pi-plugins/elapsed/package.json +65 -0
  15. package/node_modules/@tifan/pi-recap/README.md +61 -0
  16. package/node_modules/@tifan/pi-recap/package.json +43 -0
  17. package/node_modules/@tifan/pi-recap/src/index.ts +584 -0
  18. package/node_modules/@tifan/pi-recap/src/model-picker.ts +233 -0
  19. package/node_modules/@tifan/pi-recap/src/models.ts +183 -0
  20. package/node_modules/@tifan/pi-recap/src/sanitize.ts +119 -0
  21. package/node_modules/@tifan/pi-recap/src/tui.ts +155 -0
  22. package/node_modules/@zigai/pi-extension-internals/README.md +24 -0
  23. package/node_modules/@zigai/pi-extension-internals/dist/editor-enhancer-registry.d.ts +21 -0
  24. package/node_modules/@zigai/pi-extension-internals/dist/editor-enhancer-registry.js +233 -0
  25. package/node_modules/@zigai/pi-extension-internals/dist/index.d.ts +6 -0
  26. package/node_modules/@zigai/pi-extension-internals/dist/index.js +3 -0
  27. package/node_modules/@zigai/pi-extension-internals/dist/linked-method-patch.d.ts +34 -0
  28. package/node_modules/@zigai/pi-extension-internals/dist/linked-method-patch.js +272 -0
  29. package/node_modules/@zigai/pi-extension-internals/dist/pi-internal-import.d.ts +11 -0
  30. package/node_modules/@zigai/pi-extension-internals/dist/pi-internal-import.js +139 -0
  31. package/node_modules/@zigai/pi-extension-internals/package.json +41 -0
  32. package/node_modules/@zigai/pi-extension-settings/LICENSE +21 -0
  33. package/node_modules/@zigai/pi-extension-settings/README.md +36 -0
  34. package/node_modules/@zigai/pi-extension-settings/dist/artifacts.d.ts +23 -0
  35. package/node_modules/@zigai/pi-extension-settings/dist/artifacts.d.ts.map +1 -0
  36. package/node_modules/@zigai/pi-extension-settings/dist/artifacts.js +75 -0
  37. package/node_modules/@zigai/pi-extension-settings/dist/artifacts.js.map +1 -0
  38. package/node_modules/@zigai/pi-extension-settings/dist/cli-entry.d.ts +3 -0
  39. package/node_modules/@zigai/pi-extension-settings/dist/cli-entry.d.ts.map +1 -0
  40. package/node_modules/@zigai/pi-extension-settings/dist/cli-entry.js +5 -0
  41. package/node_modules/@zigai/pi-extension-settings/dist/cli-entry.js.map +1 -0
  42. package/node_modules/@zigai/pi-extension-settings/dist/cli.d.ts +6 -0
  43. package/node_modules/@zigai/pi-extension-settings/dist/cli.d.ts.map +1 -0
  44. package/node_modules/@zigai/pi-extension-settings/dist/cli.js +87 -0
  45. package/node_modules/@zigai/pi-extension-settings/dist/cli.js.map +1 -0
  46. package/node_modules/@zigai/pi-extension-settings/dist/definition-marker.d.ts +2 -0
  47. package/node_modules/@zigai/pi-extension-settings/dist/definition-marker.d.ts.map +1 -0
  48. package/node_modules/@zigai/pi-extension-settings/dist/definition-marker.js +2 -0
  49. package/node_modules/@zigai/pi-extension-settings/dist/definition-marker.js.map +1 -0
  50. package/node_modules/@zigai/pi-extension-settings/dist/definition.d.ts +159 -0
  51. package/node_modules/@zigai/pi-extension-settings/dist/definition.d.ts.map +1 -0
  52. package/node_modules/@zigai/pi-extension-settings/dist/definition.js +248 -0
  53. package/node_modules/@zigai/pi-extension-settings/dist/definition.js.map +1 -0
  54. package/node_modules/@zigai/pi-extension-settings/dist/file-system.d.ts +10 -0
  55. package/node_modules/@zigai/pi-extension-settings/dist/file-system.d.ts.map +1 -0
  56. package/node_modules/@zigai/pi-extension-settings/dist/file-system.js +115 -0
  57. package/node_modules/@zigai/pi-extension-settings/dist/file-system.js.map +1 -0
  58. package/node_modules/@zigai/pi-extension-settings/dist/index.d.ts +2 -0
  59. package/node_modules/@zigai/pi-extension-settings/dist/index.d.ts.map +1 -0
  60. package/node_modules/@zigai/pi-extension-settings/dist/index.js +2 -0
  61. package/node_modules/@zigai/pi-extension-settings/dist/index.js.map +1 -0
  62. package/node_modules/@zigai/pi-extension-settings/dist/json-value.d.ts +18 -0
  63. package/node_modules/@zigai/pi-extension-settings/dist/json-value.d.ts.map +1 -0
  64. package/node_modules/@zigai/pi-extension-settings/dist/json-value.js +56 -0
  65. package/node_modules/@zigai/pi-extension-settings/dist/json-value.js.map +1 -0
  66. package/node_modules/@zigai/pi-extension-settings/dist/paths.d.ts +11 -0
  67. package/node_modules/@zigai/pi-extension-settings/dist/paths.d.ts.map +1 -0
  68. package/node_modules/@zigai/pi-extension-settings/dist/paths.js +23 -0
  69. package/node_modules/@zigai/pi-extension-settings/dist/paths.js.map +1 -0
  70. package/node_modules/@zigai/pi-extension-settings/dist/pi-host-paths.d.ts +5 -0
  71. package/node_modules/@zigai/pi-extension-settings/dist/pi-host-paths.d.ts.map +1 -0
  72. package/node_modules/@zigai/pi-extension-settings/dist/pi-host-paths.js +21 -0
  73. package/node_modules/@zigai/pi-extension-settings/dist/pi-host-paths.js.map +1 -0
  74. package/node_modules/@zigai/pi-extension-settings/dist/pi.d.ts +106 -0
  75. package/node_modules/@zigai/pi-extension-settings/dist/pi.d.ts.map +1 -0
  76. package/node_modules/@zigai/pi-extension-settings/dist/pi.js +122 -0
  77. package/node_modules/@zigai/pi-extension-settings/dist/pi.js.map +1 -0
  78. package/node_modules/@zigai/pi-extension-settings/dist/pi.ts +2537 -0
  79. package/node_modules/@zigai/pi-extension-settings/dist/pi.ts.map +7 -0
  80. package/node_modules/@zigai/pi-extension-settings/dist/projects.d.ts +10 -0
  81. package/node_modules/@zigai/pi-extension-settings/dist/projects.d.ts.map +1 -0
  82. package/node_modules/@zigai/pi-extension-settings/dist/projects.js +177 -0
  83. package/node_modules/@zigai/pi-extension-settings/dist/projects.js.map +1 -0
  84. package/node_modules/@zigai/pi-extension-settings/dist/runtime.d.ts +40 -0
  85. package/node_modules/@zigai/pi-extension-settings/dist/runtime.d.ts.map +1 -0
  86. package/node_modules/@zigai/pi-extension-settings/dist/runtime.js +158 -0
  87. package/node_modules/@zigai/pi-extension-settings/dist/runtime.js.map +1 -0
  88. package/node_modules/@zigai/pi-extension-settings/dist/runtime.ts +158 -0
  89. package/node_modules/@zigai/pi-extension-settings/dist/runtime.ts.map +7 -0
  90. package/node_modules/@zigai/pi-extension-settings/dist/schema-document.d.ts +19 -0
  91. package/node_modules/@zigai/pi-extension-settings/dist/schema-document.d.ts.map +1 -0
  92. package/node_modules/@zigai/pi-extension-settings/dist/schema-document.js +168 -0
  93. package/node_modules/@zigai/pi-extension-settings/dist/schema-document.js.map +1 -0
  94. package/node_modules/@zigai/pi-extension-settings/dist/settings-documentation.d.ts +9 -0
  95. package/node_modules/@zigai/pi-extension-settings/dist/settings-documentation.d.ts.map +1 -0
  96. package/node_modules/@zigai/pi-extension-settings/dist/settings-documentation.js +242 -0
  97. package/node_modules/@zigai/pi-extension-settings/dist/settings-documentation.js.map +1 -0
  98. package/node_modules/@zigai/pi-extension-settings/dist/settings-layer.d.ts +59 -0
  99. package/node_modules/@zigai/pi-extension-settings/dist/settings-layer.d.ts.map +1 -0
  100. package/node_modules/@zigai/pi-extension-settings/dist/settings-layer.js +98 -0
  101. package/node_modules/@zigai/pi-extension-settings/dist/settings-layer.js.map +1 -0
  102. package/node_modules/@zigai/pi-extension-settings/dist/settings-loader.d.ts +80 -0
  103. package/node_modules/@zigai/pi-extension-settings/dist/settings-loader.d.ts.map +1 -0
  104. package/node_modules/@zigai/pi-extension-settings/dist/settings-loader.js +144 -0
  105. package/node_modules/@zigai/pi-extension-settings/dist/settings-loader.js.map +1 -0
  106. package/node_modules/@zigai/pi-extension-settings/dist/settings-merge.d.ts +5 -0
  107. package/node_modules/@zigai/pi-extension-settings/dist/settings-merge.d.ts.map +1 -0
  108. package/node_modules/@zigai/pi-extension-settings/dist/settings-merge.js +30 -0
  109. package/node_modules/@zigai/pi-extension-settings/dist/settings-merge.js.map +1 -0
  110. package/node_modules/@zigai/pi-extension-settings/dist/settings-revision.d.ts +10 -0
  111. package/node_modules/@zigai/pi-extension-settings/dist/settings-revision.d.ts.map +1 -0
  112. package/node_modules/@zigai/pi-extension-settings/dist/settings-revision.js +16 -0
  113. package/node_modules/@zigai/pi-extension-settings/dist/settings-revision.js.map +1 -0
  114. package/node_modules/@zigai/pi-extension-settings/dist/settings-transaction.d.ts +54 -0
  115. package/node_modules/@zigai/pi-extension-settings/dist/settings-transaction.d.ts.map +1 -0
  116. package/node_modules/@zigai/pi-extension-settings/dist/settings-transaction.js +202 -0
  117. package/node_modules/@zigai/pi-extension-settings/dist/settings-transaction.js.map +1 -0
  118. package/node_modules/@zigai/pi-extension-settings/dist/typebox-runtime.d.ts +5 -0
  119. package/node_modules/@zigai/pi-extension-settings/dist/typebox-runtime.d.ts.map +1 -0
  120. package/node_modules/@zigai/pi-extension-settings/dist/typebox-runtime.js +9 -0
  121. package/node_modules/@zigai/pi-extension-settings/dist/typebox-runtime.js.map +1 -0
  122. package/node_modules/@zigai/pi-extension-settings/docs/generation.md +71 -0
  123. package/node_modules/@zigai/pi-extension-settings/docs/manual-setup.md +98 -0
  124. package/node_modules/@zigai/pi-extension-settings/docs/runtime.md +100 -0
  125. package/node_modules/@zigai/pi-extension-settings/docs/ui-controls.md +31 -0
  126. package/node_modules/@zigai/pi-extension-settings/package.json +97 -0
  127. package/node_modules/@zigai/pi-mention-anything/README.md +113 -0
  128. package/node_modules/@zigai/pi-mention-anything/config.schema.json +313 -0
  129. package/node_modules/@zigai/pi-mention-anything/docs/command-protocol.md +106 -0
  130. package/node_modules/@zigai/pi-mention-anything/docs/providers.md +128 -0
  131. package/node_modules/@zigai/pi-mention-anything/examples/query-command.mjs +96 -0
  132. package/node_modules/@zigai/pi-mention-anything/examples/recursive-tree.ts +28 -0
  133. package/node_modules/@zigai/pi-mention-anything/examples/static.ts +28 -0
  134. package/node_modules/@zigai/pi-mention-anything/examples/tmux.ts +90 -0
  135. package/node_modules/@zigai/pi-mention-anything/examples/tree-settings.json +25 -0
  136. package/node_modules/@zigai/pi-mention-anything/package.json +58 -0
  137. package/node_modules/@zigai/pi-mention-anything/src/api.ts +75 -0
  138. package/node_modules/@zigai/pi-mention-anything/src/autocomplete.ts +231 -0
  139. package/node_modules/@zigai/pi-mention-anything/src/chain-autocomplete.ts +596 -0
  140. package/node_modules/@zigai/pi-mention-anything/src/chain-syntax.ts +345 -0
  141. package/node_modules/@zigai/pi-mention-anything/src/command-provider.ts +291 -0
  142. package/node_modules/@zigai/pi-mention-anything/src/configured-source.ts +66 -0
  143. package/node_modules/@zigai/pi-mention-anything/src/editor.ts +180 -0
  144. package/node_modules/@zigai/pi-mention-anything/src/expand-mentions.ts +162 -0
  145. package/node_modules/@zigai/pi-mention-anything/src/index.ts +54 -0
  146. package/node_modules/@zigai/pi-mention-anything/src/initial-suggestions.ts +190 -0
  147. package/node_modules/@zigai/pi-mention-anything/src/list-provider.ts +71 -0
  148. package/node_modules/@zigai/pi-mention-anything/src/mention-hub.ts +307 -0
  149. package/node_modules/@zigai/pi-mention-anything/src/mention-resolution.ts +374 -0
  150. package/node_modules/@zigai/pi-mention-anything/src/mention-syntax.ts +105 -0
  151. package/node_modules/@zigai/pi-mention-anything/src/register-mention.ts +89 -0
  152. package/node_modules/@zigai/pi-mention-anything/src/rendering.ts +53 -0
  153. package/node_modules/@zigai/pi-mention-anything/src/selected-items.ts +21 -0
  154. package/node_modules/@zigai/pi-mention-anything/src/selection-history.ts +135 -0
  155. package/node_modules/@zigai/pi-mention-anything/src/settings-input.ts +317 -0
  156. package/node_modules/@zigai/pi-mention-anything/src/settings.prevalidated.ts +57 -0
  157. package/node_modules/@zigai/pi-mention-anything/src/settings.ts +52 -0
  158. package/node_modules/@zigai/pi-mention-anything/src/source-contract.ts +174 -0
  159. package/node_modules/@zigai/pi-mention-anything/src/source-controller.ts +1070 -0
  160. package/node_modules/@zigai/pi-mention-anything/src/source-runtime.ts +99 -0
  161. package/node_modules/@zigai/pi-mention-skill/README.md +60 -0
  162. package/node_modules/@zigai/pi-mention-skill/config.schema.json +81 -0
  163. package/node_modules/@zigai/pi-mention-skill/package.json +56 -0
  164. package/node_modules/@zigai/pi-mention-skill/src/index.ts +60 -0
  165. package/node_modules/@zigai/pi-mention-skill/src/settings-input.ts +74 -0
  166. package/node_modules/@zigai/pi-mention-skill/src/settings.prevalidated.ts +18 -0
  167. package/node_modules/@zigai/pi-mention-skill/src/settings.ts +54 -0
  168. package/node_modules/@zigai/pi-mention-skill/src/skill-commands.ts +18 -0
  169. package/node_modules/@zigai/pi-mention-skill/src/skill-content.ts +60 -0
  170. package/node_modules/@zigai/pi-mention-skill/src/skill-provider.ts +105 -0
  171. package/node_modules/@zigai/pi-mention-skill/src/slash-skill-filter.ts +29 -0
  172. package/node_modules/argparse/LICENSE +21 -0
  173. package/node_modules/argparse/README.md +257 -0
  174. package/node_modules/argparse/index.js +3 -0
  175. package/node_modules/argparse/lib/action/append/constant.js +47 -0
  176. package/node_modules/argparse/lib/action/append.js +53 -0
  177. package/node_modules/argparse/lib/action/count.js +40 -0
  178. package/node_modules/argparse/lib/action/help.js +47 -0
  179. package/node_modules/argparse/lib/action/store/constant.js +43 -0
  180. package/node_modules/argparse/lib/action/store/false.js +27 -0
  181. package/node_modules/argparse/lib/action/store/true.js +26 -0
  182. package/node_modules/argparse/lib/action/store.js +50 -0
  183. package/node_modules/argparse/lib/action/subparsers.js +149 -0
  184. package/node_modules/argparse/lib/action/version.js +47 -0
  185. package/node_modules/argparse/lib/action.js +146 -0
  186. package/node_modules/argparse/lib/action_container.js +482 -0
  187. package/node_modules/argparse/lib/argparse.js +14 -0
  188. package/node_modules/argparse/lib/argument/error.js +50 -0
  189. package/node_modules/argparse/lib/argument/exclusive.js +54 -0
  190. package/node_modules/argparse/lib/argument/group.js +75 -0
  191. package/node_modules/argparse/lib/argument_parser.js +1161 -0
  192. package/node_modules/argparse/lib/const.js +21 -0
  193. package/node_modules/argparse/lib/help/added_formatters.js +87 -0
  194. package/node_modules/argparse/lib/help/formatter.js +795 -0
  195. package/node_modules/argparse/lib/namespace.js +76 -0
  196. package/node_modules/argparse/lib/utils.js +57 -0
  197. package/node_modules/argparse/package.json +34 -0
  198. package/node_modules/esprima/LICENSE.BSD +21 -0
  199. package/node_modules/esprima/README.md +46 -0
  200. package/node_modules/esprima/bin/esparse.js +139 -0
  201. package/node_modules/esprima/bin/esvalidate.js +236 -0
  202. package/node_modules/esprima/dist/esprima.js +6709 -0
  203. package/node_modules/esprima/package.json +112 -0
  204. package/node_modules/extend-shallow/LICENSE +21 -0
  205. package/node_modules/extend-shallow/README.md +61 -0
  206. package/node_modules/extend-shallow/index.js +33 -0
  207. package/node_modules/extend-shallow/package.json +56 -0
  208. package/node_modules/graceful-fs/LICENSE +15 -0
  209. package/node_modules/graceful-fs/README.md +143 -0
  210. package/node_modules/graceful-fs/clone.js +23 -0
  211. package/node_modules/graceful-fs/graceful-fs.js +448 -0
  212. package/node_modules/graceful-fs/legacy-streams.js +118 -0
  213. package/node_modules/graceful-fs/package.json +53 -0
  214. package/node_modules/graceful-fs/polyfills.js +355 -0
  215. package/node_modules/gray-matter/LICENSE +21 -0
  216. package/node_modules/gray-matter/README.md +565 -0
  217. package/node_modules/gray-matter/gray-matter.d.ts +114 -0
  218. package/node_modules/gray-matter/index.js +228 -0
  219. package/node_modules/gray-matter/lib/defaults.js +18 -0
  220. package/node_modules/gray-matter/lib/engine.js +30 -0
  221. package/node_modules/gray-matter/lib/engines.js +54 -0
  222. package/node_modules/gray-matter/lib/excerpt.js +32 -0
  223. package/node_modules/gray-matter/lib/parse.js +13 -0
  224. package/node_modules/gray-matter/lib/stringify.js +56 -0
  225. package/node_modules/gray-matter/lib/to-file.js +43 -0
  226. package/node_modules/gray-matter/lib/utils.js +66 -0
  227. package/node_modules/gray-matter/package.json +127 -0
  228. package/node_modules/is-extendable/LICENSE +21 -0
  229. package/node_modules/is-extendable/README.md +72 -0
  230. package/node_modules/is-extendable/index.js +13 -0
  231. package/node_modules/is-extendable/package.json +51 -0
  232. package/node_modules/js-yaml/LICENSE +21 -0
  233. package/node_modules/js-yaml/README.md +302 -0
  234. package/node_modules/js-yaml/bin/js-yaml.js +132 -0
  235. package/node_modules/js-yaml/dist/js-yaml.js +4024 -0
  236. package/node_modules/js-yaml/dist/js-yaml.min.js +1 -0
  237. package/node_modules/js-yaml/index.js +7 -0
  238. package/node_modules/js-yaml/lib/js-yaml/common.js +59 -0
  239. package/node_modules/js-yaml/lib/js-yaml/dumper.js +850 -0
  240. package/node_modules/js-yaml/lib/js-yaml/exception.js +43 -0
  241. package/node_modules/js-yaml/lib/js-yaml/loader.js +1679 -0
  242. package/node_modules/js-yaml/lib/js-yaml/mark.js +76 -0
  243. package/node_modules/js-yaml/lib/js-yaml/schema/core.js +18 -0
  244. package/node_modules/js-yaml/lib/js-yaml/schema/default_full.js +25 -0
  245. package/node_modules/js-yaml/lib/js-yaml/schema/default_safe.js +28 -0
  246. package/node_modules/js-yaml/lib/js-yaml/schema/failsafe.js +17 -0
  247. package/node_modules/js-yaml/lib/js-yaml/schema/json.js +25 -0
  248. package/node_modules/js-yaml/lib/js-yaml/schema.js +108 -0
  249. package/node_modules/js-yaml/lib/js-yaml/type/binary.js +138 -0
  250. package/node_modules/js-yaml/lib/js-yaml/type/bool.js +35 -0
  251. package/node_modules/js-yaml/lib/js-yaml/type/float.js +116 -0
  252. package/node_modules/js-yaml/lib/js-yaml/type/int.js +173 -0
  253. package/node_modules/js-yaml/lib/js-yaml/type/js/function.js +93 -0
  254. package/node_modules/js-yaml/lib/js-yaml/type/js/regexp.js +60 -0
  255. package/node_modules/js-yaml/lib/js-yaml/type/js/undefined.js +28 -0
  256. package/node_modules/js-yaml/lib/js-yaml/type/map.js +8 -0
  257. package/node_modules/js-yaml/lib/js-yaml/type/merge.js +12 -0
  258. package/node_modules/js-yaml/lib/js-yaml/type/null.js +34 -0
  259. package/node_modules/js-yaml/lib/js-yaml/type/omap.js +44 -0
  260. package/node_modules/js-yaml/lib/js-yaml/type/pairs.js +53 -0
  261. package/node_modules/js-yaml/lib/js-yaml/type/seq.js +8 -0
  262. package/node_modules/js-yaml/lib/js-yaml/type/set.js +29 -0
  263. package/node_modules/js-yaml/lib/js-yaml/type/str.js +8 -0
  264. package/node_modules/js-yaml/lib/js-yaml/type/timestamp.js +88 -0
  265. package/node_modules/js-yaml/lib/js-yaml/type.js +61 -0
  266. package/node_modules/js-yaml/lib/js-yaml.js +39 -0
  267. package/node_modules/js-yaml/package.json +52 -0
  268. package/node_modules/kind-of/LICENSE +21 -0
  269. package/node_modules/kind-of/README.md +367 -0
  270. package/node_modules/kind-of/index.js +129 -0
  271. package/node_modules/kind-of/package.json +88 -0
  272. package/node_modules/pi-toggle-skills/README.md +213 -0
  273. package/node_modules/pi-toggle-skills/package.json +60 -0
  274. package/node_modules/pi-toggle-skills/src/index.ts +112 -0
  275. package/node_modules/pi-toggle-skills/src/skill-discovery.ts +258 -0
  276. package/node_modules/pi-toggle-skills/src/skill-selector.ts +435 -0
  277. package/node_modules/pi-toggle-skills/toggle-skills.ts +316 -0
  278. package/node_modules/pi-toggle-skills/vitest.config.ts +15 -0
  279. package/node_modules/proper-lockfile/LICENSE +21 -0
  280. package/node_modules/proper-lockfile/README.md +183 -0
  281. package/node_modules/proper-lockfile/index.js +40 -0
  282. package/node_modules/proper-lockfile/lib/adapter.js +85 -0
  283. package/node_modules/proper-lockfile/lib/lockfile.js +342 -0
  284. package/node_modules/proper-lockfile/lib/mtime-precision.js +55 -0
  285. package/node_modules/proper-lockfile/node_modules/retry/.npmignore +3 -0
  286. package/node_modules/proper-lockfile/node_modules/retry/.travis.yml +15 -0
  287. package/node_modules/proper-lockfile/node_modules/retry/License +21 -0
  288. package/node_modules/proper-lockfile/node_modules/retry/Makefile +18 -0
  289. package/node_modules/proper-lockfile/node_modules/retry/README.md +227 -0
  290. package/node_modules/proper-lockfile/node_modules/retry/equation.gif +0 -0
  291. package/node_modules/proper-lockfile/node_modules/retry/example/dns.js +31 -0
  292. package/node_modules/proper-lockfile/node_modules/retry/example/stop.js +40 -0
  293. package/node_modules/proper-lockfile/node_modules/retry/index.js +1 -0
  294. package/node_modules/proper-lockfile/node_modules/retry/lib/retry.js +100 -0
  295. package/node_modules/proper-lockfile/node_modules/retry/lib/retry_operation.js +158 -0
  296. package/node_modules/proper-lockfile/node_modules/retry/package.json +32 -0
  297. package/node_modules/proper-lockfile/node_modules/retry/test/common.js +10 -0
  298. package/node_modules/proper-lockfile/node_modules/retry/test/integration/test-forever.js +24 -0
  299. package/node_modules/proper-lockfile/node_modules/retry/test/integration/test-retry-operation.js +258 -0
  300. package/node_modules/proper-lockfile/node_modules/retry/test/integration/test-retry-wrap.js +101 -0
  301. package/node_modules/proper-lockfile/node_modules/retry/test/integration/test-timeouts.js +69 -0
  302. package/node_modules/proper-lockfile/package.json +71 -0
  303. package/node_modules/section-matter/LICENSE +21 -0
  304. package/node_modules/section-matter/README.md +236 -0
  305. package/node_modules/section-matter/index.js +136 -0
  306. package/node_modules/section-matter/package.json +55 -0
  307. package/node_modules/signal-exit/LICENSE.txt +16 -0
  308. package/node_modules/signal-exit/README.md +39 -0
  309. package/node_modules/signal-exit/index.js +202 -0
  310. package/node_modules/signal-exit/package.json +38 -0
  311. package/node_modules/signal-exit/signals.js +53 -0
  312. package/node_modules/sprintf-js/.npmignore +1 -0
  313. package/node_modules/sprintf-js/LICENSE +24 -0
  314. package/node_modules/sprintf-js/README.md +88 -0
  315. package/node_modules/sprintf-js/bower.json +14 -0
  316. package/node_modules/sprintf-js/demo/angular.html +20 -0
  317. package/node_modules/sprintf-js/dist/angular-sprintf.min.js +4 -0
  318. package/node_modules/sprintf-js/dist/angular-sprintf.min.js.map +1 -0
  319. package/node_modules/sprintf-js/dist/angular-sprintf.min.map +1 -0
  320. package/node_modules/sprintf-js/dist/sprintf.min.js +4 -0
  321. package/node_modules/sprintf-js/dist/sprintf.min.js.map +1 -0
  322. package/node_modules/sprintf-js/dist/sprintf.min.map +1 -0
  323. package/node_modules/sprintf-js/gruntfile.js +36 -0
  324. package/node_modules/sprintf-js/package.json +22 -0
  325. package/node_modules/sprintf-js/src/angular-sprintf.js +18 -0
  326. package/node_modules/sprintf-js/src/sprintf.js +208 -0
  327. package/node_modules/sprintf-js/test/test.js +82 -0
  328. package/node_modules/strip-bom-string/LICENSE +21 -0
  329. package/node_modules/strip-bom-string/README.md +66 -0
  330. package/node_modules/strip-bom-string/index.js +15 -0
  331. package/node_modules/strip-bom-string/package.json +60 -0
  332. package/package.json +13 -4
@@ -0,0 +1,307 @@
1
+ import type { ContextEvent, ExtensionContext } from "@earendil-works/pi-coding-agent";
2
+ import {
3
+ createChainAutocompleteProvider,
4
+ type ChainCompletionSource,
5
+ } from "./chain-autocomplete.ts";
6
+ import { parseMentions } from "./chain-syntax.ts";
7
+ import { applyMentionEditor, createMentionContinuation } from "./editor.ts";
8
+ import {
9
+ createMentionExpansion,
10
+ createMentionSelections,
11
+ type ExpansionSource,
12
+ type MentionSnapshot,
13
+ } from "./mention-resolution.ts";
14
+ import type { MentionRegistration } from "./register-mention.ts";
15
+ import { createSourceRuntime, type SourceRuntime } from "./source-runtime.ts";
16
+
17
+ const MENTION_HUB_PROTOCOL_VERSION = 2;
18
+ const MENTION_HUB_PROTOCOL = Symbol.for("zigai.pi-mention-anything.hub-protocol-version");
19
+ const MENTION_HUB = Symbol.for("zigai.pi-mention-anything.hub");
20
+
21
+ export type MentionHub = {
22
+ readonly [MENTION_HUB_PROTOCOL]: typeof MENTION_HUB_PROTOCOL_VERSION;
23
+ add(registration: MentionRegistration): symbol;
24
+ remove(handle: symbol): Promise<void>;
25
+ input(text: string): void;
26
+
27
+ context(
28
+ messages: ContextEvent["messages"],
29
+ signal?: AbortSignal,
30
+ ): Promise<ContextEvent["messages"]>;
31
+ };
32
+
33
+ type UnknownDataDescriptor = Omit<PropertyDescriptor, "value"> & { readonly value: unknown };
34
+
35
+ function isUnknownDataDescriptor(
36
+ descriptor: PropertyDescriptor | undefined,
37
+ ): descriptor is UnknownDataDescriptor {
38
+ return descriptor !== undefined && Object.hasOwn(descriptor, "value");
39
+ }
40
+
41
+ // oxlint-disable-next-line antislop/no-object-parameters -- Protocol data may be attached to any Pi UI or hub object.
42
+ function getOwnDataDescriptor(target: object, key: PropertyKey): UnknownDataDescriptor | undefined {
43
+ const descriptor = Object.getOwnPropertyDescriptor(target, key);
44
+ if (!isUnknownDataDescriptor(descriptor)) return undefined;
45
+ return descriptor;
46
+ }
47
+
48
+ function isNonNullObject(value: unknown): value is object {
49
+ return typeof value === "object" && value !== null;
50
+ }
51
+
52
+ function isNumber(value: unknown): value is number {
53
+ return typeof value === "number";
54
+ }
55
+
56
+ // oxlint-disable-next-line antislop/no-object-parameters -- Hub records are intentionally structural protocol objects.
57
+ function hasOwnFunctionProperty(target: object, key: PropertyKey): boolean {
58
+ return typeof getOwnDataDescriptor(target, key)?.value === "function";
59
+ }
60
+
61
+ /** Reads protocol data shared by independently loaded copies in the same Pi UI session. */
62
+ function readHub(ui: ExtensionContext["ui"]): MentionHub | undefined {
63
+ const descriptor = getOwnDataDescriptor(ui, MENTION_HUB);
64
+ if (descriptor === undefined) return undefined;
65
+ if (!isNonNullObject(descriptor.value)) throw new TypeError("Incompatible mention hub");
66
+
67
+ const hub = descriptor.value;
68
+ const version = getOwnDataDescriptor(hub, MENTION_HUB_PROTOCOL)?.value;
69
+ if (version !== MENTION_HUB_PROTOCOL_VERSION) {
70
+ let versionLabel = Object.prototype.toString.call(version).slice(8, -1).toLowerCase();
71
+ if (isNumber(version)) versionLabel = version.toString();
72
+ throw new TypeError(`Unsupported mention hub protocol version ${versionLabel}`);
73
+ }
74
+
75
+ if (
76
+ !hasOwnFunctionProperty(hub, "add") ||
77
+ !hasOwnFunctionProperty(hub, "remove") ||
78
+ !hasOwnFunctionProperty(hub, "input") ||
79
+ !hasOwnFunctionProperty(hub, "context")
80
+ ) {
81
+ throw new TypeError("Incompatible mention hub");
82
+ }
83
+
84
+ // SAFETY: Version and structural checks validate the runtime protocol shared across
85
+ // independently loaded module copies. The UI object fixes the session scope.
86
+ // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- SAFETY: The versioned structural protocol is validated above.
87
+ return hub as MentionHub;
88
+ }
89
+
90
+ function createHub(ctx: ExtensionContext): MentionHub {
91
+ const ui = ctx.ui;
92
+ const runtimes = new Map<string, SourceRuntime>();
93
+ const handles = new Map<symbol, SourceRuntime>();
94
+ const sources: (ChainCompletionSource & ExpansionSource)[] = [];
95
+ const selections = createMentionSelections();
96
+ const expansion = createMentionExpansion();
97
+ const continuation = createMentionContinuation();
98
+ let pendingSnapshots: readonly MentionSnapshot[] = [];
99
+ let pendingText = "";
100
+ let editor: ReturnType<typeof applyMentionEditor> | undefined;
101
+ let autocompleteInstalled = false;
102
+ let autocomplete: ReturnType<typeof createChainAutocompleteProvider> | undefined;
103
+ let activeWarmups = 0;
104
+ const pendingWarmups: SourceRuntime[] = [];
105
+ const warmNext = (): void => {
106
+ while (activeWarmups < 4 && pendingWarmups.length > 0) {
107
+ const runtime = pendingWarmups.shift();
108
+ if (runtime === undefined || runtimes.get(runtime.id) !== runtime) continue;
109
+ activeWarmups += 1;
110
+
111
+ // The hub bounds startup work; each controller owns cancellation and safe diagnostics.
112
+ void runtime.controller
113
+ .warm()
114
+ .catch(() => {})
115
+ .finally(() => {
116
+ activeWarmups -= 1;
117
+ warmNext();
118
+ });
119
+ }
120
+ };
121
+
122
+ let unresolved = new Set<string>();
123
+ const processedContexts = new WeakSet<
124
+ Parameters<ReturnType<typeof createMentionExpansion>["messages"]>[0]
125
+ >();
126
+
127
+ const hub: MentionHub = {
128
+ [MENTION_HUB_PROTOCOL]: MENTION_HUB_PROTOCOL_VERSION,
129
+ add(registration: MentionRegistration): symbol {
130
+ if (!/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(registration.id))
131
+ throw new Error("Mention registration ID must be lowercase kebab-case.");
132
+
133
+ const configuration = registration.configuration(ctx);
134
+
135
+ if (
136
+ runtimes.has(registration.id) ||
137
+ sources.some((source) => source.trigger === configuration.trigger)
138
+ ) {
139
+ throw new Error(
140
+ "Mention sources require unique IDs and triggers within a session.",
141
+ );
142
+ }
143
+
144
+ if (!configuration.trigger || /[\s/]/.test(configuration.trigger))
145
+ throw new Error("Invalid mention trigger.");
146
+
147
+ if (
148
+ configuration.separator !== undefined &&
149
+ (configuration.separator.length !== 1 || /[\s"\\\\]/.test(configuration.separator))
150
+ )
151
+ throw new Error(
152
+ "Mention separator must be one non-whitespace character other than quote or backslash.",
153
+ );
154
+
155
+ const runtime = createSourceRuntime(ctx, registration, configuration);
156
+ const handle = Symbol(registration.id);
157
+ handles.set(handle, runtime);
158
+
159
+ const source = runtime.source;
160
+ runtimes.set(registration.id, runtime);
161
+ sources.push(source);
162
+
163
+ if (ctx.hasUI && !autocompleteInstalled) {
164
+ autocompleteInstalled = true;
165
+ editor = applyMentionEditor(ctx, {
166
+ key: Symbol.for("zigai.pi-mention-anything.engine.editor"),
167
+ continuation,
168
+ onTextChange: (text) => {
169
+ selections.reconcile(text);
170
+ autocomplete?.reconcile(text);
171
+ },
172
+ onSubmitText: (text) => hub.input(text),
173
+ isMentionContext: (line) =>
174
+ parseMentions(line, sources).some((span) => span.end === line.length),
175
+ colorLine: (line) => {
176
+ let colored = "";
177
+ let offset = 0;
178
+ for (const span of parseMentions(line, sources)) {
179
+ colored += line.slice(offset, span.start);
180
+
181
+ let color: "accent" | "warning" = "accent";
182
+ if (!span.complete || unresolved.has(span.sourceId)) color = "warning";
183
+ colored += ctx.ui.theme.fg(color, line.slice(span.start, span.end));
184
+ offset = span.end;
185
+ }
186
+
187
+ return colored + line.slice(offset);
188
+ },
189
+ });
190
+ ctx.ui.addAutocompleteProvider((current) => {
191
+ autocomplete?.dispose();
192
+ autocomplete = createChainAutocompleteProvider({
193
+ current,
194
+ sources,
195
+ onContinue: () => continuation.request(),
196
+ resolveSelected: (sourceId, segments, start) =>
197
+ selections
198
+ .snapshot(ui.getEditorText())
199
+ .find(
200
+ (snapshot) =>
201
+ snapshot.sourceId === sourceId &&
202
+ snapshot.start === start &&
203
+ segments.every(
204
+ (segment, index) =>
205
+ snapshot.path[index]?.segment === segment,
206
+ ),
207
+ )
208
+ ?.path.slice(0, segments.length),
209
+ onState: (sourceId, status) => {
210
+ if (status === "ready") unresolved.delete(sourceId);
211
+ else unresolved.add(sourceId);
212
+ },
213
+ onSelection: (selection) => {
214
+ selections.record(selection, selection.editorText);
215
+ runtimes
216
+ .get(selection.sourceId)
217
+ ?.history.recordSelection(
218
+ JSON.stringify(selection.path.map((candidate) => candidate.id)),
219
+ );
220
+ },
221
+ });
222
+
223
+ return autocomplete;
224
+ });
225
+ }
226
+
227
+ pendingWarmups.push(runtime);
228
+ warmNext();
229
+
230
+ return handle;
231
+ },
232
+ async remove(handle: symbol): Promise<void> {
233
+ const runtime = handles.get(handle);
234
+ if (runtime === undefined) return;
235
+
236
+ handles.delete(handle);
237
+ runtimes.delete(runtime.id);
238
+
239
+ const index = sources.indexOf(runtime.source);
240
+ if (index !== -1) sources.splice(index, 1);
241
+ await Promise.all([runtime.controller.dispose(), runtime.history.flush()]);
242
+
243
+ if (runtimes.size === 0) {
244
+ autocomplete?.dispose();
245
+ autocomplete = undefined;
246
+ editor?.dispose();
247
+ editor = undefined;
248
+ expansion.clear();
249
+ selections.clear();
250
+
251
+ if (
252
+ getOwnDataDescriptor(ui, MENTION_HUB)?.value === hub &&
253
+ !Reflect.deleteProperty(ui, MENTION_HUB)
254
+ ) {
255
+ throw new TypeError("Unable to remove the shared mention hub");
256
+ }
257
+ }
258
+ },
259
+ input(text: string): void {
260
+ if (pendingText === text && pendingSnapshots.length > 0) return;
261
+
262
+ pendingText = text;
263
+ pendingSnapshots = selections.snapshot(text);
264
+ },
265
+ async context(
266
+ messages: Parameters<ReturnType<typeof createMentionExpansion>["messages"]>[0],
267
+ signal?: AbortSignal,
268
+ ) {
269
+ if (processedContexts.has(messages)) return messages;
270
+
271
+ unresolved = new Set();
272
+
273
+ const result = await expansion.messages(messages, sources, {
274
+ signal,
275
+ snapshots: pendingSnapshots,
276
+ onUnresolved: (id) => {
277
+ unresolved.add(id);
278
+ },
279
+ });
280
+
281
+ pendingSnapshots = [];
282
+ pendingText = "";
283
+ processedContexts.add(result);
284
+
285
+ return result;
286
+ },
287
+ };
288
+
289
+ return hub;
290
+ }
291
+
292
+ export function sharedHub(ctx: ExtensionContext): MentionHub {
293
+ const existing = readHub(ctx.ui);
294
+ if (existing !== undefined) return existing;
295
+
296
+ const hub = createHub(ctx);
297
+ if (
298
+ !Reflect.defineProperty(ctx.ui, MENTION_HUB, {
299
+ configurable: true,
300
+ value: hub,
301
+ })
302
+ ) {
303
+ throw new TypeError("Unable to store the shared mention hub");
304
+ }
305
+
306
+ return hub;
307
+ }
@@ -0,0 +1,374 @@
1
+ import type { ContextEvent } from "@earendil-works/pi-coding-agent";
2
+
3
+ import { isTriggerBoundary, parseMentions } from "./chain-syntax.ts";
4
+ import type { Candidate, Resolution } from "./source-contract.ts";
5
+
6
+ export type MentionSnapshot = {
7
+ readonly sourceId: string;
8
+ readonly start: number;
9
+ readonly end: number;
10
+ readonly text: string;
11
+ readonly path: readonly Candidate[];
12
+ };
13
+
14
+ export type ExpansionSource = {
15
+ readonly id: string;
16
+ readonly trigger: string;
17
+ readonly separator?: string;
18
+ readonly expansionPolicy?: "selected-only" | "selected-or-resolved";
19
+ readonly replacementTemplate?: string;
20
+ readonly resolve: (segments: readonly string[], signal?: AbortSignal) => Promise<Resolution>;
21
+
22
+ readonly replacement?: (
23
+ path: readonly Candidate[],
24
+ options: { readonly signal?: AbortSignal },
25
+ ) => string | Promise<string>;
26
+ };
27
+
28
+ export type MentionSelections = {
29
+ reconcile(text: string): void;
30
+ record(snapshot: MentionSnapshot, editorText: string): void;
31
+ snapshot(text: string): readonly MentionSnapshot[];
32
+ clear(): void;
33
+ };
34
+
35
+ /** Snapshots belong to exact editor occurrences. Edits overlapping one discard it. */
36
+ export function createMentionSelections(): MentionSelections {
37
+ let previousText = "";
38
+ let snapshots: MentionSnapshot[] = [];
39
+ const reconcile = (text: string): void => {
40
+ if (text === previousText) return;
41
+
42
+ let prefix = 0;
43
+ while (
44
+ prefix < text.length &&
45
+ prefix < previousText.length &&
46
+ text[prefix] === previousText[prefix]
47
+ )
48
+ prefix += 1;
49
+
50
+ let suffix = 0;
51
+ while (
52
+ suffix < text.length - prefix &&
53
+ suffix < previousText.length - prefix &&
54
+ text[text.length - 1 - suffix] === previousText[previousText.length - 1 - suffix]
55
+ )
56
+ suffix += 1;
57
+
58
+ const oldEnd = previousText.length - suffix;
59
+ const delta = text.length - previousText.length;
60
+ let changedText = text.slice(prefix, text.length - suffix);
61
+ if (delta < 0) changedText = previousText.slice(prefix, oldEnd);
62
+
63
+ const ambiguous = new Set(
64
+ snapshots
65
+ .filter(
66
+ (snapshot) =>
67
+ delta !== 0 &&
68
+ snapshot.end === prefix &&
69
+ changedText.includes(snapshot.text),
70
+ )
71
+ .map((snapshot) => snapshot.text),
72
+ );
73
+
74
+ snapshots = snapshots
75
+ .flatMap((snapshot) => {
76
+ if (ambiguous.has(snapshot.text)) return [];
77
+ if (snapshot.end <= prefix) return [snapshot];
78
+
79
+ if (snapshot.start >= oldEnd)
80
+ return [
81
+ { ...snapshot, start: snapshot.start + delta, end: snapshot.end + delta },
82
+ ];
83
+
84
+ return [];
85
+ })
86
+ .filter((snapshot) => {
87
+ if (text.slice(snapshot.start, snapshot.end) !== snapshot.text) return false;
88
+ if (!isTriggerBoundary(text, snapshot.start)) return false;
89
+
90
+ const adjacent = /^\S*/.exec(text.slice(snapshot.end))?.[0] ?? "";
91
+ return /^[.,;!?)}\]]*$/.test(adjacent);
92
+ });
93
+ previousText = text;
94
+ };
95
+
96
+ return {
97
+ reconcile,
98
+ record(snapshot: MentionSnapshot, editorText: string): void {
99
+ reconcile(editorText);
100
+ snapshots = snapshots.filter(
101
+ (existing) => existing.end <= snapshot.start || existing.start >= snapshot.end,
102
+ );
103
+ snapshots.push({ ...snapshot, path: structuredClone(snapshot.path) });
104
+ },
105
+ snapshot(text: string): readonly MentionSnapshot[] {
106
+ reconcile(text);
107
+
108
+ return snapshots.map((snapshot) => ({
109
+ ...snapshot,
110
+ path: structuredClone(snapshot.path),
111
+ }));
112
+ },
113
+ clear(): void {
114
+ previousText = "";
115
+ snapshots = [];
116
+ },
117
+ };
118
+ }
119
+
120
+ /** Declarative fields only: no property traversal or provider-data serialization. */
121
+ export function renderReplacementTemplate(template: string, path: readonly Candidate[]): string {
122
+ const target = path.at(-1);
123
+ if (target === undefined) throw new Error("Cannot render an empty mention target.");
124
+
125
+ const fields = new Map<string, string>([
126
+ ["id", target.id],
127
+ ["label", target.label],
128
+ ["segment", target.segment],
129
+ ["path", path.map((candidate) => candidate.segment).join(":")],
130
+ ["ids", path.map((candidate) => candidate.id).join(":")],
131
+ ]);
132
+
133
+ return template.replace(/\{\{\s*([^{}]+?)\s*\}\}/g, (_match: string, field: string) => {
134
+ const value = fields.get(field);
135
+ if (value === undefined)
136
+ throw new Error("Mention replacement template contains an undeclared field.");
137
+
138
+ return value;
139
+ });
140
+ }
141
+
142
+ export async function expandMentionText(
143
+ text: string,
144
+ sources: readonly ExpansionSource[],
145
+ options: {
146
+ readonly snapshots?: readonly MentionSnapshot[];
147
+ readonly signal?: AbortSignal;
148
+ readonly onUnresolved?: (sourceId: string) => void;
149
+ } = {},
150
+ ): Promise<string> {
151
+ const selectedSpans = (options.snapshots ?? []).filter(
152
+ (snapshot) =>
153
+ text.slice(snapshot.start, snapshot.end) === snapshot.text &&
154
+ sources.some((source) => source.id === snapshot.sourceId),
155
+ );
156
+ const spans = [
157
+ ...parseMentions(text, sources).filter(
158
+ (span) =>
159
+ !selectedSpans.some(
160
+ (snapshot) => snapshot.start < span.end && snapshot.end > span.start,
161
+ ),
162
+ ),
163
+ ...selectedSpans.map((snapshot) => ({
164
+ ...snapshot,
165
+ complete: true,
166
+ segments: snapshot.path.map((candidate) => candidate.segment),
167
+ })),
168
+ ].sort((left, right) => left.start - right.start);
169
+ let result = "";
170
+ let offset = 0;
171
+
172
+ // Bounded sequential resolution avoids command bursts in a large pasted prompt.
173
+ for (const span of spans) {
174
+ options.signal?.throwIfAborted();
175
+ result += text.slice(offset, span.start);
176
+ offset = span.end;
177
+
178
+ const literal = text.slice(span.start, span.end);
179
+ const source = sources.find((candidate) => candidate.id === span.sourceId);
180
+ if (!span.complete || source === undefined) {
181
+ result += literal;
182
+ continue;
183
+ }
184
+
185
+ const selected = options.snapshots?.find(
186
+ (snapshot) =>
187
+ snapshot.sourceId === source.id &&
188
+ snapshot.start === span.start &&
189
+ snapshot.end === span.end &&
190
+ snapshot.text === literal,
191
+ );
192
+ let resolution: Resolution;
193
+ if (selected !== undefined) resolution = { status: "resolved", path: selected.path };
194
+ else if (source.expansionPolicy === "selected-only") {
195
+ result += literal;
196
+ continue;
197
+ } else {
198
+ try {
199
+ resolution = await source.resolve(span.segments, options.signal);
200
+ } catch {
201
+ options.signal?.throwIfAborted();
202
+ result += literal;
203
+ options.onUnresolved?.(source.id);
204
+ continue;
205
+ }
206
+ }
207
+
208
+ if (resolution.status !== "resolved") {
209
+ result += literal;
210
+ options.onUnresolved?.(source.id);
211
+ continue;
212
+ }
213
+
214
+ const target = resolution.path.at(-1);
215
+ if (target === undefined || !target.selectable) {
216
+ result += literal;
217
+ options.onUnresolved?.(source.id);
218
+ continue;
219
+ }
220
+
221
+ try {
222
+ let replacement = resolution.replacement ?? target.replacement ?? target.segment;
223
+ if (source.replacement !== undefined) {
224
+ replacement = await source.replacement(resolution.path, { signal: options.signal });
225
+ } else if (source.replacementTemplate !== undefined) {
226
+ replacement = renderReplacementTemplate(
227
+ source.replacementTemplate,
228
+ resolution.path,
229
+ );
230
+ }
231
+
232
+ result += replacement;
233
+ } catch {
234
+ options.signal?.throwIfAborted();
235
+ result += literal;
236
+ options.onUnresolved?.(source.id);
237
+ }
238
+ }
239
+
240
+ return result + text.slice(offset);
241
+ }
242
+
243
+ /** One pass over original user blocks. Memoized submissions survive context rebuilds/retries. */
244
+ export type MentionExpansion = {
245
+ messages(
246
+ messages: ContextEvent["messages"],
247
+ sources: readonly ExpansionSource[],
248
+ options?: {
249
+ readonly signal?: AbortSignal;
250
+ readonly snapshots?: readonly MentionSnapshot[];
251
+ readonly onUnresolved?: (sourceId: string) => void;
252
+ },
253
+ ): Promise<ContextEvent["messages"]>;
254
+
255
+ clear(): void;
256
+ };
257
+
258
+ export function createMentionExpansion(): MentionExpansion {
259
+ const submissions = new Map<string, string>();
260
+ const processed = new WeakSet<ContextEvent["messages"]>();
261
+ const remember = (key: string, value: string): void => {
262
+ submissions.set(key, value);
263
+ };
264
+
265
+ return {
266
+ async messages(
267
+ messages: ContextEvent["messages"],
268
+ sources: readonly ExpansionSource[],
269
+ options: {
270
+ readonly signal?: AbortSignal;
271
+ readonly snapshots?: readonly MentionSnapshot[];
272
+ readonly onUnresolved?: (sourceId: string) => void;
273
+ } = {},
274
+ ): Promise<ContextEvent["messages"]> {
275
+ if (processed.has(messages)) return messages;
276
+
277
+ let changed = false;
278
+ const activeKeys = new Set<string>();
279
+ const expanded: ContextEvent["messages"] = [];
280
+ let latestUser = -1;
281
+ for (let index = messages.length - 1; index >= 0; index -= 1) {
282
+ if (messages[index]?.role !== "user") continue;
283
+ latestUser = index;
284
+ break;
285
+ }
286
+
287
+ for (const [messageIndex, message] of messages.entries()) {
288
+ if (message.role !== "user") {
289
+ expanded.push(message);
290
+ continue;
291
+ }
292
+
293
+ let firstTextBlock = 0;
294
+ if (Array.isArray(message.content)) {
295
+ firstTextBlock = message.content.findIndex((block) => block.type === "text");
296
+ }
297
+
298
+ const expandBlock = async (text: string, block: number): Promise<string> => {
299
+ const key = JSON.stringify([message.timestamp, block, text]);
300
+ activeKeys.add(key);
301
+
302
+ const cached = submissions.get(key);
303
+ if (cached !== undefined) {
304
+ activeKeys.add(JSON.stringify([message.timestamp, block, cached]));
305
+ return cached;
306
+ }
307
+
308
+ let snapshots: readonly MentionSnapshot[] | undefined;
309
+ if (messageIndex === latestUser && block === firstTextBlock) {
310
+ snapshots = options.snapshots;
311
+ }
312
+
313
+ const value = await expandMentionText(text, sources, {
314
+ ...options,
315
+ snapshots,
316
+ });
317
+ remember(key, value);
318
+
319
+ // A subsequent context handler must not reinterpret generated text.
320
+ const generatedKey = JSON.stringify([message.timestamp, block, value]);
321
+ remember(generatedKey, value);
322
+ activeKeys.add(generatedKey);
323
+
324
+ return value;
325
+ };
326
+ if (!Array.isArray(message.content)) {
327
+ const content = await expandBlock(message.content, 0);
328
+ changed ||= content !== message.content;
329
+
330
+ if (content === message.content) expanded.push(message);
331
+ else expanded.push({ ...message, content });
332
+ } else {
333
+ let blockChanged = false;
334
+ const content: typeof message.content = [];
335
+ for (const [index, block] of message.content.entries()) {
336
+ if (block.type !== "text") {
337
+ content.push(block);
338
+ continue;
339
+ }
340
+
341
+ const text = await expandBlock(block.text, index);
342
+ blockChanged ||= text !== block.text;
343
+
344
+ if (text === block.text) content.push(block);
345
+ else content.push({ ...block, text });
346
+ }
347
+
348
+ changed ||= blockChanged;
349
+
350
+ if (blockChanged) expanded.push({ ...message, content });
351
+ else expanded.push(message);
352
+ }
353
+ }
354
+
355
+ // Keep all active-context resolutions; only the historical tail is bounded.
356
+ let historical = submissions.size - activeKeys.size;
357
+ for (const key of submissions.keys()) {
358
+ if (historical <= 512) break;
359
+ if (activeKeys.has(key)) continue;
360
+ submissions.delete(key);
361
+ historical -= 1;
362
+ }
363
+
364
+ let result = messages;
365
+ if (changed) result = expanded;
366
+ processed.add(result);
367
+
368
+ return result;
369
+ },
370
+ clear(): void {
371
+ submissions.clear();
372
+ },
373
+ };
374
+ }