@dev-sergeev/datalab-kit 0.1.2 → 0.1.4

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 (355) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/README.md +23 -5
  3. package/THIRD_PARTY_NOTICES.md +6 -2
  4. package/docs/adr/0001-user-settings-priority.md +2 -0
  5. package/docs/adr/0002-package-delivery.md +8 -0
  6. package/node_modules/@pi-plugins/elapsed/LICENSE +21 -0
  7. package/node_modules/@pi-plugins/elapsed/README.md +45 -0
  8. package/node_modules/@pi-plugins/elapsed/dist/index.d.mts +8 -0
  9. package/node_modules/@pi-plugins/elapsed/dist/index.d.mts.map +1 -0
  10. package/node_modules/@pi-plugins/elapsed/dist/index.mjs +47 -0
  11. package/node_modules/@pi-plugins/elapsed/dist/index.mjs.map +1 -0
  12. package/node_modules/@pi-plugins/elapsed/package.json +65 -0
  13. package/node_modules/@tifan/pi-recap/README.md +61 -0
  14. package/node_modules/@tifan/pi-recap/package.json +43 -0
  15. package/node_modules/@tifan/pi-recap/src/index.ts +586 -0
  16. package/node_modules/@tifan/pi-recap/src/model-picker.ts +234 -0
  17. package/node_modules/@tifan/pi-recap/src/models.ts +180 -0
  18. package/node_modules/@tifan/pi-recap/src/sanitize.ts +119 -0
  19. package/node_modules/@tifan/pi-recap/src/tui.ts +155 -0
  20. package/node_modules/@zigai/pi-extension-internals/README.md +24 -0
  21. package/node_modules/@zigai/pi-extension-internals/dist/editor-enhancer-registry.d.ts +21 -0
  22. package/node_modules/@zigai/pi-extension-internals/dist/editor-enhancer-registry.js +233 -0
  23. package/node_modules/@zigai/pi-extension-internals/dist/index.d.ts +6 -0
  24. package/node_modules/@zigai/pi-extension-internals/dist/index.js +3 -0
  25. package/node_modules/@zigai/pi-extension-internals/dist/linked-method-patch.d.ts +34 -0
  26. package/node_modules/@zigai/pi-extension-internals/dist/linked-method-patch.js +272 -0
  27. package/node_modules/@zigai/pi-extension-internals/dist/pi-internal-import.d.ts +11 -0
  28. package/node_modules/@zigai/pi-extension-internals/dist/pi-internal-import.js +139 -0
  29. package/node_modules/@zigai/pi-extension-internals/package.json +41 -0
  30. package/node_modules/@zigai/pi-extension-settings/LICENSE +21 -0
  31. package/node_modules/@zigai/pi-extension-settings/README.md +36 -0
  32. package/node_modules/@zigai/pi-extension-settings/dist/artifacts.d.ts +23 -0
  33. package/node_modules/@zigai/pi-extension-settings/dist/artifacts.d.ts.map +1 -0
  34. package/node_modules/@zigai/pi-extension-settings/dist/artifacts.js +75 -0
  35. package/node_modules/@zigai/pi-extension-settings/dist/artifacts.js.map +1 -0
  36. package/node_modules/@zigai/pi-extension-settings/dist/cli-entry.d.ts +3 -0
  37. package/node_modules/@zigai/pi-extension-settings/dist/cli-entry.d.ts.map +1 -0
  38. package/node_modules/@zigai/pi-extension-settings/dist/cli-entry.js +5 -0
  39. package/node_modules/@zigai/pi-extension-settings/dist/cli-entry.js.map +1 -0
  40. package/node_modules/@zigai/pi-extension-settings/dist/cli.d.ts +6 -0
  41. package/node_modules/@zigai/pi-extension-settings/dist/cli.d.ts.map +1 -0
  42. package/node_modules/@zigai/pi-extension-settings/dist/cli.js +87 -0
  43. package/node_modules/@zigai/pi-extension-settings/dist/cli.js.map +1 -0
  44. package/node_modules/@zigai/pi-extension-settings/dist/definition-marker.d.ts +2 -0
  45. package/node_modules/@zigai/pi-extension-settings/dist/definition-marker.d.ts.map +1 -0
  46. package/node_modules/@zigai/pi-extension-settings/dist/definition-marker.js +2 -0
  47. package/node_modules/@zigai/pi-extension-settings/dist/definition-marker.js.map +1 -0
  48. package/node_modules/@zigai/pi-extension-settings/dist/definition.d.ts +159 -0
  49. package/node_modules/@zigai/pi-extension-settings/dist/definition.d.ts.map +1 -0
  50. package/node_modules/@zigai/pi-extension-settings/dist/definition.js +248 -0
  51. package/node_modules/@zigai/pi-extension-settings/dist/definition.js.map +1 -0
  52. package/node_modules/@zigai/pi-extension-settings/dist/file-system.d.ts +10 -0
  53. package/node_modules/@zigai/pi-extension-settings/dist/file-system.d.ts.map +1 -0
  54. package/node_modules/@zigai/pi-extension-settings/dist/file-system.js +115 -0
  55. package/node_modules/@zigai/pi-extension-settings/dist/file-system.js.map +1 -0
  56. package/node_modules/@zigai/pi-extension-settings/dist/index.d.ts +2 -0
  57. package/node_modules/@zigai/pi-extension-settings/dist/index.d.ts.map +1 -0
  58. package/node_modules/@zigai/pi-extension-settings/dist/index.js +2 -0
  59. package/node_modules/@zigai/pi-extension-settings/dist/index.js.map +1 -0
  60. package/node_modules/@zigai/pi-extension-settings/dist/json-value.d.ts +18 -0
  61. package/node_modules/@zigai/pi-extension-settings/dist/json-value.d.ts.map +1 -0
  62. package/node_modules/@zigai/pi-extension-settings/dist/json-value.js +56 -0
  63. package/node_modules/@zigai/pi-extension-settings/dist/json-value.js.map +1 -0
  64. package/node_modules/@zigai/pi-extension-settings/dist/paths.d.ts +11 -0
  65. package/node_modules/@zigai/pi-extension-settings/dist/paths.d.ts.map +1 -0
  66. package/node_modules/@zigai/pi-extension-settings/dist/paths.js +23 -0
  67. package/node_modules/@zigai/pi-extension-settings/dist/paths.js.map +1 -0
  68. package/node_modules/@zigai/pi-extension-settings/dist/pi-host-paths.d.ts +5 -0
  69. package/node_modules/@zigai/pi-extension-settings/dist/pi-host-paths.d.ts.map +1 -0
  70. package/node_modules/@zigai/pi-extension-settings/dist/pi-host-paths.js +21 -0
  71. package/node_modules/@zigai/pi-extension-settings/dist/pi-host-paths.js.map +1 -0
  72. package/node_modules/@zigai/pi-extension-settings/dist/pi.d.ts +106 -0
  73. package/node_modules/@zigai/pi-extension-settings/dist/pi.d.ts.map +1 -0
  74. package/node_modules/@zigai/pi-extension-settings/dist/pi.js +122 -0
  75. package/node_modules/@zigai/pi-extension-settings/dist/pi.js.map +1 -0
  76. package/node_modules/@zigai/pi-extension-settings/dist/pi.ts +2537 -0
  77. package/node_modules/@zigai/pi-extension-settings/dist/pi.ts.map +7 -0
  78. package/node_modules/@zigai/pi-extension-settings/dist/projects.d.ts +10 -0
  79. package/node_modules/@zigai/pi-extension-settings/dist/projects.d.ts.map +1 -0
  80. package/node_modules/@zigai/pi-extension-settings/dist/projects.js +177 -0
  81. package/node_modules/@zigai/pi-extension-settings/dist/projects.js.map +1 -0
  82. package/node_modules/@zigai/pi-extension-settings/dist/runtime.d.ts +40 -0
  83. package/node_modules/@zigai/pi-extension-settings/dist/runtime.d.ts.map +1 -0
  84. package/node_modules/@zigai/pi-extension-settings/dist/runtime.js +158 -0
  85. package/node_modules/@zigai/pi-extension-settings/dist/runtime.js.map +1 -0
  86. package/node_modules/@zigai/pi-extension-settings/dist/runtime.ts +158 -0
  87. package/node_modules/@zigai/pi-extension-settings/dist/runtime.ts.map +7 -0
  88. package/node_modules/@zigai/pi-extension-settings/dist/schema-document.d.ts +19 -0
  89. package/node_modules/@zigai/pi-extension-settings/dist/schema-document.d.ts.map +1 -0
  90. package/node_modules/@zigai/pi-extension-settings/dist/schema-document.js +168 -0
  91. package/node_modules/@zigai/pi-extension-settings/dist/schema-document.js.map +1 -0
  92. package/node_modules/@zigai/pi-extension-settings/dist/settings-documentation.d.ts +9 -0
  93. package/node_modules/@zigai/pi-extension-settings/dist/settings-documentation.d.ts.map +1 -0
  94. package/node_modules/@zigai/pi-extension-settings/dist/settings-documentation.js +242 -0
  95. package/node_modules/@zigai/pi-extension-settings/dist/settings-documentation.js.map +1 -0
  96. package/node_modules/@zigai/pi-extension-settings/dist/settings-layer.d.ts +59 -0
  97. package/node_modules/@zigai/pi-extension-settings/dist/settings-layer.d.ts.map +1 -0
  98. package/node_modules/@zigai/pi-extension-settings/dist/settings-layer.js +98 -0
  99. package/node_modules/@zigai/pi-extension-settings/dist/settings-layer.js.map +1 -0
  100. package/node_modules/@zigai/pi-extension-settings/dist/settings-loader.d.ts +80 -0
  101. package/node_modules/@zigai/pi-extension-settings/dist/settings-loader.d.ts.map +1 -0
  102. package/node_modules/@zigai/pi-extension-settings/dist/settings-loader.js +144 -0
  103. package/node_modules/@zigai/pi-extension-settings/dist/settings-loader.js.map +1 -0
  104. package/node_modules/@zigai/pi-extension-settings/dist/settings-merge.d.ts +5 -0
  105. package/node_modules/@zigai/pi-extension-settings/dist/settings-merge.d.ts.map +1 -0
  106. package/node_modules/@zigai/pi-extension-settings/dist/settings-merge.js +30 -0
  107. package/node_modules/@zigai/pi-extension-settings/dist/settings-merge.js.map +1 -0
  108. package/node_modules/@zigai/pi-extension-settings/dist/settings-revision.d.ts +10 -0
  109. package/node_modules/@zigai/pi-extension-settings/dist/settings-revision.d.ts.map +1 -0
  110. package/node_modules/@zigai/pi-extension-settings/dist/settings-revision.js +16 -0
  111. package/node_modules/@zigai/pi-extension-settings/dist/settings-revision.js.map +1 -0
  112. package/node_modules/@zigai/pi-extension-settings/dist/settings-transaction.d.ts +54 -0
  113. package/node_modules/@zigai/pi-extension-settings/dist/settings-transaction.d.ts.map +1 -0
  114. package/node_modules/@zigai/pi-extension-settings/dist/settings-transaction.js +202 -0
  115. package/node_modules/@zigai/pi-extension-settings/dist/settings-transaction.js.map +1 -0
  116. package/node_modules/@zigai/pi-extension-settings/dist/typebox-runtime.d.ts +5 -0
  117. package/node_modules/@zigai/pi-extension-settings/dist/typebox-runtime.d.ts.map +1 -0
  118. package/node_modules/@zigai/pi-extension-settings/dist/typebox-runtime.js +9 -0
  119. package/node_modules/@zigai/pi-extension-settings/dist/typebox-runtime.js.map +1 -0
  120. package/node_modules/@zigai/pi-extension-settings/docs/generation.md +71 -0
  121. package/node_modules/@zigai/pi-extension-settings/docs/manual-setup.md +98 -0
  122. package/node_modules/@zigai/pi-extension-settings/docs/runtime.md +100 -0
  123. package/node_modules/@zigai/pi-extension-settings/docs/ui-controls.md +31 -0
  124. package/node_modules/@zigai/pi-extension-settings/package.json +97 -0
  125. package/node_modules/@zigai/pi-mention-anything/README.md +113 -0
  126. package/node_modules/@zigai/pi-mention-anything/config.schema.json +313 -0
  127. package/node_modules/@zigai/pi-mention-anything/docs/command-protocol.md +106 -0
  128. package/node_modules/@zigai/pi-mention-anything/docs/providers.md +128 -0
  129. package/node_modules/@zigai/pi-mention-anything/examples/query-command.mjs +96 -0
  130. package/node_modules/@zigai/pi-mention-anything/examples/recursive-tree.ts +28 -0
  131. package/node_modules/@zigai/pi-mention-anything/examples/static.ts +28 -0
  132. package/node_modules/@zigai/pi-mention-anything/examples/tmux.ts +90 -0
  133. package/node_modules/@zigai/pi-mention-anything/examples/tree-settings.json +25 -0
  134. package/node_modules/@zigai/pi-mention-anything/package.json +58 -0
  135. package/node_modules/@zigai/pi-mention-anything/src/api.ts +75 -0
  136. package/node_modules/@zigai/pi-mention-anything/src/autocomplete.ts +231 -0
  137. package/node_modules/@zigai/pi-mention-anything/src/chain-autocomplete.ts +596 -0
  138. package/node_modules/@zigai/pi-mention-anything/src/chain-syntax.ts +345 -0
  139. package/node_modules/@zigai/pi-mention-anything/src/command-provider.ts +291 -0
  140. package/node_modules/@zigai/pi-mention-anything/src/configured-source.ts +66 -0
  141. package/node_modules/@zigai/pi-mention-anything/src/editor.ts +180 -0
  142. package/node_modules/@zigai/pi-mention-anything/src/expand-mentions.ts +162 -0
  143. package/node_modules/@zigai/pi-mention-anything/src/index.ts +54 -0
  144. package/node_modules/@zigai/pi-mention-anything/src/initial-suggestions.ts +190 -0
  145. package/node_modules/@zigai/pi-mention-anything/src/list-provider.ts +71 -0
  146. package/node_modules/@zigai/pi-mention-anything/src/mention-hub.ts +307 -0
  147. package/node_modules/@zigai/pi-mention-anything/src/mention-resolution.ts +374 -0
  148. package/node_modules/@zigai/pi-mention-anything/src/mention-syntax.ts +105 -0
  149. package/node_modules/@zigai/pi-mention-anything/src/register-mention.ts +89 -0
  150. package/node_modules/@zigai/pi-mention-anything/src/rendering.ts +53 -0
  151. package/node_modules/@zigai/pi-mention-anything/src/selected-items.ts +21 -0
  152. package/node_modules/@zigai/pi-mention-anything/src/selection-history.ts +135 -0
  153. package/node_modules/@zigai/pi-mention-anything/src/settings-input.ts +317 -0
  154. package/node_modules/@zigai/pi-mention-anything/src/settings.prevalidated.ts +57 -0
  155. package/node_modules/@zigai/pi-mention-anything/src/settings.ts +52 -0
  156. package/node_modules/@zigai/pi-mention-anything/src/source-contract.ts +174 -0
  157. package/node_modules/@zigai/pi-mention-anything/src/source-controller.ts +1070 -0
  158. package/node_modules/@zigai/pi-mention-anything/src/source-runtime.ts +99 -0
  159. package/node_modules/@zigai/pi-mention-skill/README.md +60 -0
  160. package/node_modules/@zigai/pi-mention-skill/config.schema.json +81 -0
  161. package/node_modules/@zigai/pi-mention-skill/package.json +56 -0
  162. package/node_modules/@zigai/pi-mention-skill/src/index.ts +60 -0
  163. package/node_modules/@zigai/pi-mention-skill/src/settings-input.ts +74 -0
  164. package/node_modules/@zigai/pi-mention-skill/src/settings.prevalidated.ts +18 -0
  165. package/node_modules/@zigai/pi-mention-skill/src/settings.ts +54 -0
  166. package/node_modules/@zigai/pi-mention-skill/src/skill-commands.ts +18 -0
  167. package/node_modules/@zigai/pi-mention-skill/src/skill-content.ts +60 -0
  168. package/node_modules/@zigai/pi-mention-skill/src/skill-provider.ts +105 -0
  169. package/node_modules/@zigai/pi-mention-skill/src/slash-skill-filter.ts +29 -0
  170. package/node_modules/argparse/LICENSE +21 -0
  171. package/node_modules/argparse/README.md +257 -0
  172. package/node_modules/argparse/index.js +3 -0
  173. package/node_modules/argparse/lib/action/append/constant.js +47 -0
  174. package/node_modules/argparse/lib/action/append.js +53 -0
  175. package/node_modules/argparse/lib/action/count.js +40 -0
  176. package/node_modules/argparse/lib/action/help.js +47 -0
  177. package/node_modules/argparse/lib/action/store/constant.js +43 -0
  178. package/node_modules/argparse/lib/action/store/false.js +27 -0
  179. package/node_modules/argparse/lib/action/store/true.js +26 -0
  180. package/node_modules/argparse/lib/action/store.js +50 -0
  181. package/node_modules/argparse/lib/action/subparsers.js +149 -0
  182. package/node_modules/argparse/lib/action/version.js +47 -0
  183. package/node_modules/argparse/lib/action.js +146 -0
  184. package/node_modules/argparse/lib/action_container.js +482 -0
  185. package/node_modules/argparse/lib/argparse.js +14 -0
  186. package/node_modules/argparse/lib/argument/error.js +50 -0
  187. package/node_modules/argparse/lib/argument/exclusive.js +54 -0
  188. package/node_modules/argparse/lib/argument/group.js +75 -0
  189. package/node_modules/argparse/lib/argument_parser.js +1161 -0
  190. package/node_modules/argparse/lib/const.js +21 -0
  191. package/node_modules/argparse/lib/help/added_formatters.js +87 -0
  192. package/node_modules/argparse/lib/help/formatter.js +795 -0
  193. package/node_modules/argparse/lib/namespace.js +76 -0
  194. package/node_modules/argparse/lib/utils.js +57 -0
  195. package/node_modules/argparse/package.json +34 -0
  196. package/node_modules/esprima/LICENSE.BSD +21 -0
  197. package/node_modules/esprima/README.md +46 -0
  198. package/node_modules/esprima/bin/esparse.js +139 -0
  199. package/node_modules/esprima/bin/esvalidate.js +236 -0
  200. package/node_modules/esprima/dist/esprima.js +6709 -0
  201. package/node_modules/esprima/package.json +112 -0
  202. package/node_modules/extend-shallow/LICENSE +21 -0
  203. package/node_modules/extend-shallow/README.md +61 -0
  204. package/node_modules/extend-shallow/index.js +33 -0
  205. package/node_modules/extend-shallow/package.json +56 -0
  206. package/node_modules/graceful-fs/LICENSE +15 -0
  207. package/node_modules/graceful-fs/README.md +143 -0
  208. package/node_modules/graceful-fs/clone.js +23 -0
  209. package/node_modules/graceful-fs/graceful-fs.js +448 -0
  210. package/node_modules/graceful-fs/legacy-streams.js +118 -0
  211. package/node_modules/graceful-fs/package.json +53 -0
  212. package/node_modules/graceful-fs/polyfills.js +355 -0
  213. package/node_modules/gray-matter/LICENSE +21 -0
  214. package/node_modules/gray-matter/README.md +565 -0
  215. package/node_modules/gray-matter/gray-matter.d.ts +114 -0
  216. package/node_modules/gray-matter/index.js +228 -0
  217. package/node_modules/gray-matter/lib/defaults.js +18 -0
  218. package/node_modules/gray-matter/lib/engine.js +30 -0
  219. package/node_modules/gray-matter/lib/engines.js +54 -0
  220. package/node_modules/gray-matter/lib/excerpt.js +32 -0
  221. package/node_modules/gray-matter/lib/parse.js +13 -0
  222. package/node_modules/gray-matter/lib/stringify.js +56 -0
  223. package/node_modules/gray-matter/lib/to-file.js +43 -0
  224. package/node_modules/gray-matter/lib/utils.js +66 -0
  225. package/node_modules/gray-matter/package.json +127 -0
  226. package/node_modules/is-extendable/LICENSE +21 -0
  227. package/node_modules/is-extendable/README.md +72 -0
  228. package/node_modules/is-extendable/index.js +13 -0
  229. package/node_modules/is-extendable/package.json +51 -0
  230. package/node_modules/js-yaml/LICENSE +21 -0
  231. package/node_modules/js-yaml/README.md +302 -0
  232. package/node_modules/js-yaml/bin/js-yaml.js +132 -0
  233. package/node_modules/js-yaml/dist/js-yaml.js +4024 -0
  234. package/node_modules/js-yaml/dist/js-yaml.min.js +1 -0
  235. package/node_modules/js-yaml/index.js +7 -0
  236. package/node_modules/js-yaml/lib/js-yaml/common.js +59 -0
  237. package/node_modules/js-yaml/lib/js-yaml/dumper.js +850 -0
  238. package/node_modules/js-yaml/lib/js-yaml/exception.js +43 -0
  239. package/node_modules/js-yaml/lib/js-yaml/loader.js +1679 -0
  240. package/node_modules/js-yaml/lib/js-yaml/mark.js +76 -0
  241. package/node_modules/js-yaml/lib/js-yaml/schema/core.js +18 -0
  242. package/node_modules/js-yaml/lib/js-yaml/schema/default_full.js +25 -0
  243. package/node_modules/js-yaml/lib/js-yaml/schema/default_safe.js +28 -0
  244. package/node_modules/js-yaml/lib/js-yaml/schema/failsafe.js +17 -0
  245. package/node_modules/js-yaml/lib/js-yaml/schema/json.js +25 -0
  246. package/node_modules/js-yaml/lib/js-yaml/schema.js +108 -0
  247. package/node_modules/js-yaml/lib/js-yaml/type/binary.js +138 -0
  248. package/node_modules/js-yaml/lib/js-yaml/type/bool.js +35 -0
  249. package/node_modules/js-yaml/lib/js-yaml/type/float.js +116 -0
  250. package/node_modules/js-yaml/lib/js-yaml/type/int.js +173 -0
  251. package/node_modules/js-yaml/lib/js-yaml/type/js/function.js +93 -0
  252. package/node_modules/js-yaml/lib/js-yaml/type/js/regexp.js +60 -0
  253. package/node_modules/js-yaml/lib/js-yaml/type/js/undefined.js +28 -0
  254. package/node_modules/js-yaml/lib/js-yaml/type/map.js +8 -0
  255. package/node_modules/js-yaml/lib/js-yaml/type/merge.js +12 -0
  256. package/node_modules/js-yaml/lib/js-yaml/type/null.js +34 -0
  257. package/node_modules/js-yaml/lib/js-yaml/type/omap.js +44 -0
  258. package/node_modules/js-yaml/lib/js-yaml/type/pairs.js +53 -0
  259. package/node_modules/js-yaml/lib/js-yaml/type/seq.js +8 -0
  260. package/node_modules/js-yaml/lib/js-yaml/type/set.js +29 -0
  261. package/node_modules/js-yaml/lib/js-yaml/type/str.js +8 -0
  262. package/node_modules/js-yaml/lib/js-yaml/type/timestamp.js +88 -0
  263. package/node_modules/js-yaml/lib/js-yaml/type.js +61 -0
  264. package/node_modules/js-yaml/lib/js-yaml.js +39 -0
  265. package/node_modules/js-yaml/package.json +52 -0
  266. package/node_modules/kind-of/LICENSE +21 -0
  267. package/node_modules/kind-of/README.md +367 -0
  268. package/node_modules/kind-of/index.js +129 -0
  269. package/node_modules/kind-of/package.json +88 -0
  270. package/node_modules/node-addon-api/common 2.gypi +21 -0
  271. package/node_modules/node-addon-api/except 2.gypi +25 -0
  272. package/node_modules/node-addon-api/napi 2.h +3463 -0
  273. package/node_modules/node-addon-api/napi-inl 2.h +7250 -0
  274. package/node_modules/node-addon-api/napi-inl.deprecated 2.h +186 -0
  275. package/node_modules/node-addon-api/node_addon_api 2.gyp +42 -0
  276. package/node_modules/node-addon-api/node_api 2.gyp +9 -0
  277. package/node_modules/node-addon-api/noexcept 2.gypi +26 -0
  278. package/node_modules/node-addon-api/nothing 2.c +0 -0
  279. package/node_modules/pi-toggle-skills/README.md +213 -0
  280. package/node_modules/pi-toggle-skills/package.json +60 -0
  281. package/node_modules/pi-toggle-skills/src/index.ts +112 -0
  282. package/node_modules/pi-toggle-skills/src/skill-discovery.ts +258 -0
  283. package/node_modules/pi-toggle-skills/src/skill-selector.ts +435 -0
  284. package/node_modules/pi-toggle-skills/toggle-skills 2.ts +316 -0
  285. package/node_modules/pi-toggle-skills/toggle-skills.ts +316 -0
  286. package/node_modules/pi-toggle-skills/vitest.config 2.ts +15 -0
  287. package/node_modules/pi-toggle-skills/vitest.config.ts +15 -0
  288. package/node_modules/proper-lockfile/LICENSE +21 -0
  289. package/node_modules/proper-lockfile/README.md +183 -0
  290. package/node_modules/proper-lockfile/index.js +40 -0
  291. package/node_modules/proper-lockfile/lib/adapter.js +85 -0
  292. package/node_modules/proper-lockfile/lib/lockfile.js +342 -0
  293. package/node_modules/proper-lockfile/lib/mtime-precision.js +55 -0
  294. package/node_modules/proper-lockfile/node_modules/retry/.npmignore +3 -0
  295. package/node_modules/proper-lockfile/node_modules/retry/.travis.yml +15 -0
  296. package/node_modules/proper-lockfile/node_modules/retry/License +21 -0
  297. package/node_modules/proper-lockfile/node_modules/retry/Makefile +18 -0
  298. package/node_modules/proper-lockfile/node_modules/retry/README.md +227 -0
  299. package/node_modules/proper-lockfile/node_modules/retry/equation.gif +0 -0
  300. package/node_modules/proper-lockfile/node_modules/retry/example/dns.js +31 -0
  301. package/node_modules/proper-lockfile/node_modules/retry/example/stop.js +40 -0
  302. package/node_modules/proper-lockfile/node_modules/retry/index.js +1 -0
  303. package/node_modules/proper-lockfile/node_modules/retry/lib/retry.js +100 -0
  304. package/node_modules/proper-lockfile/node_modules/retry/lib/retry_operation.js +158 -0
  305. package/node_modules/proper-lockfile/node_modules/retry/package.json +32 -0
  306. package/node_modules/proper-lockfile/node_modules/retry/test/common.js +10 -0
  307. package/node_modules/proper-lockfile/node_modules/retry/test/integration/test-forever.js +24 -0
  308. package/node_modules/proper-lockfile/node_modules/retry/test/integration/test-retry-operation.js +258 -0
  309. package/node_modules/proper-lockfile/node_modules/retry/test/integration/test-retry-wrap.js +101 -0
  310. package/node_modules/proper-lockfile/node_modules/retry/test/integration/test-timeouts.js +69 -0
  311. package/node_modules/proper-lockfile/package.json +71 -0
  312. package/node_modules/section-matter/LICENSE +21 -0
  313. package/node_modules/section-matter/README.md +236 -0
  314. package/node_modules/section-matter/index.js +136 -0
  315. package/node_modules/section-matter/package.json +55 -0
  316. package/node_modules/signal-exit/LICENSE.txt +16 -0
  317. package/node_modules/signal-exit/README.md +39 -0
  318. package/node_modules/signal-exit/index.js +202 -0
  319. package/node_modules/signal-exit/package.json +38 -0
  320. package/node_modules/signal-exit/signals.js +53 -0
  321. package/node_modules/sprintf-js/.npmignore +1 -0
  322. package/node_modules/sprintf-js/.npmignore 2 +1 -0
  323. package/node_modules/sprintf-js/LICENSE +24 -0
  324. package/node_modules/sprintf-js/LICENSE 2 +24 -0
  325. package/node_modules/sprintf-js/README 2.md +88 -0
  326. package/node_modules/sprintf-js/README.md +88 -0
  327. package/node_modules/sprintf-js/bower 2.json +14 -0
  328. package/node_modules/sprintf-js/bower.json +14 -0
  329. package/node_modules/sprintf-js/demo/angular.html +20 -0
  330. package/node_modules/sprintf-js/dist/angular-sprintf.min.js +4 -0
  331. package/node_modules/sprintf-js/dist/angular-sprintf.min.js.map +1 -0
  332. package/node_modules/sprintf-js/dist/angular-sprintf.min.map +1 -0
  333. package/node_modules/sprintf-js/dist/sprintf.min.js +4 -0
  334. package/node_modules/sprintf-js/dist/sprintf.min.js.map +1 -0
  335. package/node_modules/sprintf-js/dist/sprintf.min.map +1 -0
  336. package/node_modules/sprintf-js/gruntfile 2.js +36 -0
  337. package/node_modules/sprintf-js/gruntfile.js +36 -0
  338. package/node_modules/sprintf-js/package 2.json +22 -0
  339. package/node_modules/sprintf-js/package.json +22 -0
  340. package/node_modules/sprintf-js/src/angular-sprintf.js +18 -0
  341. package/node_modules/sprintf-js/src/sprintf.js +208 -0
  342. package/node_modules/sprintf-js/test/test.js +82 -0
  343. package/node_modules/strip-bom-string/LICENSE +21 -0
  344. package/node_modules/strip-bom-string/README.md +66 -0
  345. package/node_modules/strip-bom-string/index.js +15 -0
  346. package/node_modules/strip-bom-string/package.json +60 -0
  347. package/node_modules/tree-sitter-bash/tree-sitter-bash 2.wasm +0 -0
  348. package/node_modules/typebox/license 2 +23 -0
  349. package/node_modules/typebox/package 2.json +87 -0
  350. package/node_modules/typebox/readme 2.md +370 -0
  351. package/node_modules/zod/compile 2.cjs +96 -0
  352. package/node_modules/zod/compile 2.js +52 -0
  353. package/node_modules/zod/index 2.cjs +52 -0
  354. package/node_modules/zod/index 2.js +7 -0
  355. package/package.json +13 -4
@@ -0,0 +1,1070 @@
1
+ import { watch, type FSWatcher } from "node:fs";
2
+ import { mkdir, open, rename, rm, writeFile } from "node:fs/promises";
3
+ import { randomUUID } from "node:crypto";
4
+ import { homedir } from "node:os";
5
+ import { basename, dirname, join, resolve } from "node:path";
6
+ import { Type } from "typebox";
7
+ import { Value } from "typebox/value";
8
+
9
+ import {
10
+ candidateSchema,
11
+ discoveryResponseSchema,
12
+ parseDiscoveryResponse,
13
+ parseResolution,
14
+ type Candidate,
15
+ type DiscoveryRequest,
16
+ type DiscoveryResponse,
17
+ type Provider,
18
+ type Resolution,
19
+ } from "./source-contract.ts";
20
+
21
+ const PROVIDER_DISCOVERY_LIMIT = 100;
22
+ const LOCAL_DISCOVERY_LIMIT = 10_000;
23
+ const DEFAULT_MAX_CONCURRENT = 4;
24
+ const DEFAULT_MAX_ENTRIES = 64;
25
+ const FAILED_RETRY_DELAY_MS = 1_000;
26
+ const AUXILIARY_ENTRY_TTL_MS = 60_000;
27
+ const PERSISTENCE_VERSION = 2;
28
+ const MAX_PERSISTENCE_BYTES = 8 * 1024 * 1024;
29
+ const persistenceWriters = new Map<string, Promise<void>>();
30
+
31
+ async function readPersistence(path: string): Promise<string> {
32
+ const file = await open(path, "r");
33
+
34
+ try {
35
+ const metadata = await file.stat();
36
+ if (metadata.size > MAX_PERSISTENCE_BYTES)
37
+ throw new Error("Persistent mention cache exceeds its size limit.");
38
+
39
+ const buffer = Buffer.alloc(Math.min(MAX_PERSISTENCE_BYTES + 1, metadata.size + 1));
40
+ let offset = 0;
41
+ while (offset < buffer.length) {
42
+ const { bytesRead } = await file.read(buffer, offset, buffer.length - offset, offset);
43
+ if (bytesRead === 0) break;
44
+
45
+ offset += bytesRead;
46
+ }
47
+
48
+ if (offset === buffer.length)
49
+ throw new Error("Persistent mention cache changed while loading.");
50
+
51
+ return buffer.subarray(0, offset).toString("utf8");
52
+ } finally {
53
+ await file.close();
54
+ }
55
+ }
56
+
57
+ export type SourceControllerDiscovery = {
58
+ readonly query: string;
59
+ readonly path: readonly Candidate[];
60
+ readonly cursor?: string;
61
+ readonly signal?: AbortSignal;
62
+ };
63
+
64
+ type SourceControllerBaseOptions = {
65
+ readonly sourceId: string;
66
+ readonly cwd: string;
67
+ readonly trusted: boolean;
68
+ readonly cache?: boolean;
69
+ readonly cacheTtlMs?: number;
70
+ readonly refreshOnStartup?: boolean;
71
+ readonly refreshIntervalMs?: number;
72
+ readonly watchFiles?: readonly string[];
73
+ readonly debounceMs?: number;
74
+ readonly maxEntries?: number;
75
+ readonly maxConcurrent?: number;
76
+ readonly onError?: (message: string) => void;
77
+ readonly now?: () => number;
78
+ };
79
+
80
+ export type SourceControllerOptions = SourceControllerBaseOptions & {
81
+ readonly persistentCachePath?: string;
82
+ readonly configurationKey?: string;
83
+ };
84
+
85
+ type ScopedSourceControllerOptions<Options extends SourceControllerOptions> =
86
+ undefined extends Options["persistentCachePath"]
87
+ ? Options
88
+ : Options & { readonly configurationKey: string };
89
+
90
+ export type SourceControllerErrorCode =
91
+ | "discovery-failed"
92
+ | "persistence-failed"
93
+ | "provider-disposal-failed"
94
+ | "resolution-failed";
95
+
96
+ export type SourceControllerStatus = {
97
+ readonly cachedEntries: number;
98
+ readonly cachedCandidates: number;
99
+ readonly inFlightRequests: number;
100
+ readonly queuedRequests: number;
101
+ readonly failedRequestKeys: number;
102
+ readonly latestRequestScopes: number;
103
+ readonly oldestCacheAgeMs: number | undefined;
104
+ readonly errorCodes: readonly SourceControllerErrorCode[];
105
+ };
106
+
107
+ export type SourceController = {
108
+ discover(request: SourceControllerDiscovery): Promise<DiscoveryResponse>;
109
+ resolve(segments: readonly string[], signal?: AbortSignal): Promise<Resolution>;
110
+ warm(): Promise<void>;
111
+ refresh(): Promise<void>;
112
+ invalidate(): void;
113
+ status(): SourceControllerStatus;
114
+ dispose(): Promise<void>;
115
+ };
116
+
117
+ type CachedRequest = {
118
+ readonly query: string;
119
+ readonly path: readonly Candidate[];
120
+ readonly cursor?: string;
121
+ };
122
+
123
+ type CacheEntry = {
124
+ readonly request: CachedRequest;
125
+ readonly response: DiscoveryResponse;
126
+ readonly expiresAt: number;
127
+ readonly cachedAt: number;
128
+ };
129
+
130
+ type SharedWork<Result> = {
131
+ readonly controller: AbortController;
132
+ promise: Promise<Result>;
133
+ waiters: number;
134
+ settled: boolean;
135
+ };
136
+
137
+ type SharedRequest = SharedWork<DiscoveryResponse>;
138
+ type ResolvedResolution = Extract<Resolution, { readonly status: "resolved" }>;
139
+
140
+ type ResolutionCacheEntry = {
141
+ readonly resolution: ResolvedResolution;
142
+ readonly expiresAt: number;
143
+ readonly cachedAt: number;
144
+ };
145
+
146
+ type SharedResolution = SharedWork<Resolution>;
147
+
148
+ type LatestRequest = {
149
+ readonly key: string;
150
+ readonly expiresAt: number;
151
+ };
152
+
153
+ type QueueItem = {
154
+ readonly signal: AbortSignal;
155
+ start: (release: () => void) => void;
156
+ readonly reject: (cause: unknown) => void;
157
+ };
158
+
159
+ type PersistedEntry = {
160
+ readonly key: string;
161
+ readonly request: CachedRequest;
162
+ readonly response: DiscoveryResponse;
163
+ readonly expiresAt: number;
164
+ readonly cachedAt: number;
165
+ };
166
+
167
+ type PersistedDocument = {
168
+ readonly version: typeof PERSISTENCE_VERSION;
169
+ readonly scope: string;
170
+ readonly entries: readonly PersistedEntry[];
171
+ };
172
+
173
+ const cachedRequestSchema = Type.Object(
174
+ {
175
+ query: Type.String(),
176
+ path: Type.Array(candidateSchema),
177
+ cursor: Type.Optional(Type.String()),
178
+ },
179
+ { additionalProperties: false },
180
+ );
181
+
182
+ const persistedEntrySchema = Type.Object(
183
+ {
184
+ key: Type.String(),
185
+ request: cachedRequestSchema,
186
+ response: discoveryResponseSchema,
187
+ expiresAt: Type.Number(),
188
+ cachedAt: Type.Number(),
189
+ },
190
+ { additionalProperties: false },
191
+ );
192
+
193
+ const persistedDocumentSchema = Type.Object(
194
+ {
195
+ version: Type.Literal(PERSISTENCE_VERSION),
196
+ scope: Type.String(),
197
+ entries: Type.Array(persistedEntrySchema),
198
+ },
199
+ { additionalProperties: false },
200
+ );
201
+
202
+ const ERROR_MESSAGE_BY_CODE = {
203
+ "discovery-failed": "Mention source discovery failed.",
204
+ "persistence-failed": "Mention source persistence failed.",
205
+ "provider-disposal-failed": "Mention source provider disposal failed.",
206
+ "resolution-failed": "Mention source resolution failed.",
207
+ } satisfies Record<SourceControllerErrorCode, string>;
208
+
209
+ function abortCause(signal: AbortSignal): Error {
210
+ if (signal.reason instanceof Error) return signal.reason;
211
+ return new DOMException("The operation was aborted", "AbortError");
212
+ }
213
+
214
+ async function waitForDelay(milliseconds: number, signal: AbortSignal): Promise<void> {
215
+ signal.throwIfAborted();
216
+ if (milliseconds === 0) return Promise.resolve();
217
+
218
+ let timer: ReturnType<typeof setTimeout> | undefined;
219
+ const promise = new Promise<void>((resolve, reject) => {
220
+ const abort = (): void => {
221
+ clearTimeout(timer);
222
+ reject(abortCause(signal));
223
+ };
224
+
225
+ timer = setTimeout(() => {
226
+ signal.removeEventListener("abort", abort);
227
+ resolve();
228
+ }, milliseconds);
229
+ signal.addEventListener("abort", abort, { once: true });
230
+ });
231
+
232
+ return promise;
233
+ }
234
+
235
+ function resolveWatchFilePath(file: string, cwd: string): string {
236
+ if (file === "~") return homedir();
237
+ if (file.startsWith("~/")) return join(homedir(), file.slice(2));
238
+ return resolve(cwd, file);
239
+ }
240
+
241
+ function validateDiscoveryResponse(response: DiscoveryResponse, limit: number): DiscoveryResponse {
242
+ const parsed = parseDiscoveryResponse(response);
243
+ if (parsed.items.length > limit)
244
+ throw new Error("provider exceeded the discovery result limit");
245
+
246
+ const ids = new Set<string>();
247
+ for (const item of parsed.items) {
248
+ if (ids.has(item.id)) throw new Error("provider returned duplicate candidate IDs");
249
+
250
+ ids.add(item.id);
251
+ }
252
+
253
+ return parsed;
254
+ }
255
+
256
+ class ConcurrencyLimiter {
257
+ readonly #limit: number;
258
+ readonly #queue: QueueItem[] = [];
259
+ #active = 0;
260
+
261
+ constructor(limit: number) {
262
+ this.#limit = limit;
263
+ }
264
+
265
+ get queued(): number {
266
+ return this.#queue.length;
267
+ }
268
+
269
+ async run<T>(signal: AbortSignal, operation: () => Promise<T>): Promise<T> {
270
+ const release = await this.#acquire(signal);
271
+ try {
272
+ signal.throwIfAborted();
273
+ return await operation();
274
+ } finally {
275
+ release();
276
+ }
277
+ }
278
+
279
+ async #acquire(signal: AbortSignal): Promise<() => void> {
280
+ signal.throwIfAborted();
281
+
282
+ if (this.#active < this.#limit) {
283
+ this.#active += 1;
284
+ return this.#makeRelease();
285
+ }
286
+
287
+ return new Promise((resolve, reject) => {
288
+ const abort = (): void => {
289
+ const index = this.#queue.findIndex((queued) => queued.reject === reject);
290
+ if (index >= 0) this.#queue.splice(index, 1);
291
+ reject(abortCause(signal));
292
+ };
293
+ const item: QueueItem = {
294
+ signal,
295
+ reject,
296
+ start: (release: () => void): void => {
297
+ signal.removeEventListener("abort", abort);
298
+ resolve(release);
299
+ },
300
+ };
301
+
302
+ signal.addEventListener("abort", abort, { once: true });
303
+ this.#queue.push(item);
304
+ });
305
+ }
306
+
307
+ #makeRelease(): () => void {
308
+ let released = false;
309
+ return (): void => {
310
+ if (released) return;
311
+
312
+ released = true;
313
+ this.#active -= 1;
314
+ while (this.#queue.length > 0) {
315
+ const next = this.#queue.shift();
316
+ if (next === undefined || next.signal.aborted) continue;
317
+ this.#active += 1;
318
+ next.start(this.#makeRelease());
319
+ break;
320
+ }
321
+ };
322
+ }
323
+ }
324
+
325
+ function validatePositiveInteger(value: number, name: string): void {
326
+ if (!Number.isSafeInteger(value) || value <= 0)
327
+ throw new Error(`${name} must be a positive integer`);
328
+ }
329
+
330
+ /** Owns provider work, scoped caches, refresh resources, cancellation, and safe diagnostics. */
331
+ export function createSourceController<const Options extends SourceControllerOptions>(
332
+ provider: Provider,
333
+ options: ScopedSourceControllerOptions<Options>,
334
+ ): SourceController {
335
+ const maxEntries = options.maxEntries ?? DEFAULT_MAX_ENTRIES;
336
+ const maxConcurrent = options.maxConcurrent ?? DEFAULT_MAX_CONCURRENT;
337
+ const debounceMs = options.debounceMs ?? 0;
338
+
339
+ validatePositiveInteger(maxEntries, "maxEntries");
340
+ validatePositiveInteger(maxConcurrent, "maxConcurrent");
341
+
342
+ if (!Number.isFinite(debounceMs) || debounceMs < 0)
343
+ throw new Error("debounceMs must be non-negative");
344
+
345
+ if (
346
+ options.cacheTtlMs !== undefined &&
347
+ (!Number.isFinite(options.cacheTtlMs) || options.cacheTtlMs < 0)
348
+ ) {
349
+ throw new Error("cacheTtlMs must be non-negative");
350
+ }
351
+
352
+ if (
353
+ options.persistentCachePath !== undefined &&
354
+ (options.configurationKey === undefined || options.configurationKey.length === 0)
355
+ ) {
356
+ throw new Error("configurationKey is required for persistentCachePath");
357
+ }
358
+
359
+ const cacheEnabled = options.cache === true;
360
+ let discoveryLimit = PROVIDER_DISCOVERY_LIMIT;
361
+ if (provider.filtering === "local") discoveryLimit = LOCAL_DISCOVERY_LIMIT;
362
+
363
+ const now = options.now ?? Date.now;
364
+ const lifetime = new AbortController();
365
+ const limiter = new ConcurrencyLimiter(maxConcurrent);
366
+ const cache = new Map<string, CacheEntry>();
367
+ const failures = new Map<string, number>();
368
+ const inFlight = new Map<string, SharedRequest>();
369
+ const latestRequestByScope = new Map<string, LatestRequest>();
370
+ const resolutionCache = new Map<string, ResolutionCacheEntry>();
371
+ const resolutionInFlight = new Map<string, SharedResolution>();
372
+ const watchers: FSWatcher[] = [];
373
+ let generation = 0;
374
+ let resolutionGeneration = 0;
375
+ const isDisposed = (): boolean => lifetime.signal.aborted;
376
+ const errorCodes = new Set<SourceControllerErrorCode>();
377
+ const reportedErrorCodes = new Set<SourceControllerErrorCode>();
378
+ let watchTimer: ReturnType<typeof setTimeout> | undefined;
379
+ let persistenceWrite: Promise<void> = Promise.resolve();
380
+ let disposal: Promise<void> | undefined;
381
+
382
+ const scope = JSON.stringify([
383
+ options.configurationKey ?? "",
384
+ options.sourceId,
385
+ options.cwd,
386
+ options.trusted,
387
+ ]);
388
+
389
+ const keyFor = (request: CachedRequest): string => {
390
+ let query = "";
391
+ if (provider.filtering === "provider") query = request.query;
392
+
393
+ return JSON.stringify([
394
+ scope,
395
+ request.path.map((candidate) => candidate.id),
396
+ query,
397
+ request.cursor ?? "",
398
+ ]);
399
+ };
400
+
401
+ const requestScopeFor = (request: CachedRequest): string =>
402
+ JSON.stringify([
403
+ scope,
404
+ request.path.map((candidate) => candidate.id),
405
+ request.cursor ?? "",
406
+ ]);
407
+
408
+ const resolutionKeyFor = (segments: readonly string[]): string =>
409
+ JSON.stringify([scope, segments]);
410
+
411
+ const recordError = (code: SourceControllerErrorCode): void => {
412
+ errorCodes.add(code);
413
+
414
+ if (reportedErrorCodes.has(code)) return;
415
+
416
+ reportedErrorCodes.add(code);
417
+ options.onError?.(ERROR_MESSAGE_BY_CODE[code]);
418
+ };
419
+
420
+ const reportError = (code: SourceControllerErrorCode): void => {
421
+ if (isDisposed()) return;
422
+
423
+ recordError(code);
424
+ };
425
+
426
+ const clearError = (code: SourceControllerErrorCode): void => {
427
+ errorCodes.delete(code);
428
+ reportedErrorCodes.delete(code);
429
+ };
430
+
431
+ const touch = (key: string, entry: CacheEntry): void => {
432
+ cache.delete(key);
433
+ cache.set(key, entry);
434
+ };
435
+
436
+ const trimCache = (): void => {
437
+ while (cache.size > maxEntries) {
438
+ const oldest = cache.keys().next().value;
439
+ if (oldest === undefined) return;
440
+
441
+ cache.delete(oldest);
442
+ }
443
+ };
444
+
445
+ const touchResolution = (key: string, entry: ResolutionCacheEntry): void => {
446
+ resolutionCache.delete(key);
447
+ resolutionCache.set(key, entry);
448
+ };
449
+
450
+ const trimResolutionCache = (): void => {
451
+ while (resolutionCache.size > maxEntries) {
452
+ const oldest = resolutionCache.keys().next().value;
453
+ if (oldest === undefined) return;
454
+
455
+ resolutionCache.delete(oldest);
456
+ }
457
+ };
458
+
459
+ const trimAuxiliary = <Value>(entries: Map<string, Value>): void => {
460
+ while (entries.size > maxEntries) {
461
+ const oldest = entries.keys().next().value;
462
+ if (oldest === undefined) return;
463
+
464
+ entries.delete(oldest);
465
+ }
466
+ };
467
+
468
+ const failureRetryAt = (key: string, currentTime: number): number | undefined => {
469
+ const retryAt = failures.get(key);
470
+ if (retryAt === undefined) return undefined;
471
+
472
+ if (retryAt <= currentTime) {
473
+ failures.delete(key);
474
+ return undefined;
475
+ }
476
+
477
+ failures.delete(key);
478
+ failures.set(key, retryAt);
479
+
480
+ return retryAt;
481
+ };
482
+
483
+ const rememberFailure = (key: string): void => {
484
+ failures.delete(key);
485
+ failures.set(key, now() + FAILED_RETRY_DELAY_MS);
486
+ trimAuxiliary(failures);
487
+ };
488
+
489
+ const latestRequestFor = (requestScope: string, currentTime: number): string | undefined => {
490
+ const latest = latestRequestByScope.get(requestScope);
491
+ if (latest === undefined) return undefined;
492
+
493
+ if (latest.expiresAt <= currentTime) {
494
+ latestRequestByScope.delete(requestScope);
495
+ return undefined;
496
+ }
497
+
498
+ latestRequestByScope.delete(requestScope);
499
+ latestRequestByScope.set(requestScope, latest);
500
+
501
+ return latest.key;
502
+ };
503
+
504
+ const rememberLatestRequest = (requestScope: string, key: string): void => {
505
+ latestRequestByScope.delete(requestScope);
506
+ latestRequestByScope.set(requestScope, {
507
+ key,
508
+ expiresAt: now() + AUXILIARY_ENTRY_TTL_MS,
509
+ });
510
+ trimAuxiliary(latestRequestByScope);
511
+ };
512
+
513
+ const pruneAuxiliary = (currentTime: number): void => {
514
+ for (const [key, retryAt] of failures) {
515
+ if (retryAt <= currentTime) failures.delete(key);
516
+ }
517
+
518
+ for (const [requestScope, latest] of latestRequestByScope) {
519
+ if (latest.expiresAt <= currentTime) latestRequestByScope.delete(requestScope);
520
+ }
521
+ };
522
+
523
+ const persistedDocument = (): PersistedDocument => ({
524
+ version: PERSISTENCE_VERSION,
525
+ scope,
526
+ entries: [...cache].map(([key, entry]) => ({ key, ...entry })),
527
+ });
528
+
529
+ const savePersistence = (): void => {
530
+ const path = options.persistentCachePath;
531
+ if (!cacheEnabled || path === undefined || isDisposed()) return;
532
+
533
+ const expectedGeneration = generation;
534
+ const contents = JSON.stringify(persistedDocument());
535
+ if (Buffer.byteLength(contents) > MAX_PERSISTENCE_BYTES) {
536
+ reportError("persistence-failed");
537
+ return;
538
+ }
539
+
540
+ const writeSnapshot = async (): Promise<void> => {
541
+ if (isDisposed() || expectedGeneration !== generation) return;
542
+
543
+ await mkdir(dirname(path), { recursive: true });
544
+
545
+ const temporaryPath = `${path}.${randomUUID()}.tmp`;
546
+
547
+ try {
548
+ await writeFile(temporaryPath, contents, { encoding: "utf8", mode: 0o600 });
549
+
550
+ if (isDisposed() || expectedGeneration !== generation) return;
551
+
552
+ await rename(temporaryPath, path);
553
+
554
+ if (!isDisposed() && expectedGeneration === generation)
555
+ clearError("persistence-failed");
556
+ } finally {
557
+ await rm(temporaryPath, { force: true });
558
+ }
559
+ };
560
+
561
+ const previousWrite = persistenceWriters.get(path) ?? Promise.resolve();
562
+
563
+ persistenceWrite = previousWrite.then(writeSnapshot, writeSnapshot).catch(() => {
564
+ if (!isDisposed() && expectedGeneration === generation)
565
+ reportError("persistence-failed");
566
+ });
567
+ persistenceWriters.set(path, persistenceWrite);
568
+
569
+ const currentWrite = persistenceWrite;
570
+
571
+ void currentWrite.then(() => {
572
+ if (persistenceWriters.get(path) === currentWrite) persistenceWriters.delete(path);
573
+ });
574
+ };
575
+
576
+ const loadPersistence = async (): Promise<void> => {
577
+ const path = options.persistentCachePath;
578
+ if (!cacheEnabled || path === undefined) return;
579
+
580
+ const expectedGeneration = generation;
581
+
582
+ try {
583
+ const text = await readPersistence(path);
584
+
585
+ if (isDisposed() || expectedGeneration !== generation) return;
586
+
587
+ const value = Value.Parse(persistedDocumentSchema, JSON.parse(text));
588
+ if (value.scope !== scope) throw new Error("invalid persistent cache scope");
589
+
590
+ for (const entry of value.entries.slice(-maxEntries)) {
591
+ if (entry.key !== keyFor(entry.request))
592
+ throw new Error("invalid persistent cache scope");
593
+
594
+ cache.set(entry.key, {
595
+ request: entry.request,
596
+ response: entry.response,
597
+ expiresAt: entry.expiresAt,
598
+ cachedAt: entry.cachedAt,
599
+ });
600
+ }
601
+
602
+ clearError("persistence-failed");
603
+ } catch (cause: unknown) {
604
+ if (cause instanceof Error && "code" in cause && cause.code === "ENOENT") return;
605
+
606
+ reportError("persistence-failed");
607
+ }
608
+ };
609
+ const persistenceReady = loadPersistence();
610
+
611
+ const runDiscovery = async (
612
+ request: CachedRequest,
613
+ signal: AbortSignal,
614
+ expectedGeneration: number,
615
+ ): Promise<DiscoveryResponse> => {
616
+ await waitForDelay(debounceMs, signal);
617
+
618
+ let discoveryRequest: DiscoveryRequest;
619
+ if (request.cursor === undefined) {
620
+ discoveryRequest = {
621
+ sourceId: options.sourceId,
622
+ cwd: options.cwd,
623
+ trusted: options.trusted,
624
+ query: request.query,
625
+ path: request.path,
626
+ limit: discoveryLimit,
627
+ signal,
628
+ };
629
+ } else {
630
+ discoveryRequest = {
631
+ sourceId: options.sourceId,
632
+ cwd: options.cwd,
633
+ trusted: options.trusted,
634
+ query: request.query,
635
+ path: request.path,
636
+ limit: discoveryLimit,
637
+ cursor: request.cursor,
638
+ signal,
639
+ };
640
+ }
641
+
642
+ const response = await limiter.run(signal, async () => provider.discover(discoveryRequest));
643
+ signal.throwIfAborted();
644
+ if (isDisposed() || expectedGeneration !== generation) throw abortCause(lifetime.signal);
645
+
646
+ const parsed = validateDiscoveryResponse(response, discoveryLimit);
647
+
648
+ clearError("discovery-failed");
649
+
650
+ return parsed;
651
+ };
652
+
653
+ const startShared = (key: string, request: CachedRequest): SharedRequest => {
654
+ const current = inFlight.get(key);
655
+ if (current !== undefined && !current.controller.signal.aborted) return current;
656
+
657
+ const controller = new AbortController();
658
+ const signal = AbortSignal.any([lifetime.signal, controller.signal]);
659
+ const expectedGeneration = generation;
660
+ const shared: SharedRequest = {
661
+ controller,
662
+ waiters: 0,
663
+ settled: false,
664
+ promise: Promise.resolve({ items: [] }),
665
+ };
666
+
667
+ shared.promise = runDiscovery(request, signal, expectedGeneration)
668
+ .then((response) => {
669
+ if (cacheEnabled && !isDisposed() && expectedGeneration === generation) {
670
+ const cachedAt = now();
671
+ let expiresAt = Number.MAX_SAFE_INTEGER;
672
+ if (options.cacheTtlMs !== undefined) expiresAt = cachedAt + options.cacheTtlMs;
673
+
674
+ const entry: CacheEntry = {
675
+ request,
676
+ response,
677
+ expiresAt,
678
+ cachedAt,
679
+ };
680
+ touch(key, entry);
681
+ trimCache();
682
+ savePersistence();
683
+ }
684
+
685
+ failures.delete(key);
686
+
687
+ return response;
688
+ })
689
+ .catch((cause: unknown) => {
690
+ if (!signal.aborted && !isDisposed() && expectedGeneration === generation) {
691
+ rememberFailure(key);
692
+ reportError("discovery-failed");
693
+ }
694
+
695
+ throw cause;
696
+ })
697
+ .finally(() => {
698
+ shared.settled = true;
699
+ if (inFlight.get(key) === shared) inFlight.delete(key);
700
+ });
701
+ inFlight.set(key, shared);
702
+
703
+ return shared;
704
+ };
705
+
706
+ const runResolution = async (
707
+ segments: readonly string[],
708
+ signal: AbortSignal,
709
+ expectedResolutionGeneration: number,
710
+ ): Promise<Resolution> => {
711
+ const resolution = await limiter.run(signal, async () =>
712
+ provider.resolve({
713
+ sourceId: options.sourceId,
714
+ cwd: options.cwd,
715
+ trusted: options.trusted,
716
+ segments,
717
+ signal,
718
+ }),
719
+ );
720
+
721
+ signal.throwIfAborted();
722
+
723
+ if (isDisposed() || expectedResolutionGeneration !== resolutionGeneration)
724
+ throw abortCause(lifetime.signal);
725
+
726
+ const parsed = parseResolution(resolution);
727
+
728
+ clearError("resolution-failed");
729
+
730
+ return parsed;
731
+ };
732
+
733
+ const startSharedResolution = (key: string, segments: readonly string[]): SharedResolution => {
734
+ const current = resolutionInFlight.get(key);
735
+ if (current !== undefined && !current.controller.signal.aborted) return current;
736
+
737
+ const controller = new AbortController();
738
+ const signal = AbortSignal.any([lifetime.signal, controller.signal]);
739
+ const expectedResolutionGeneration = resolutionGeneration;
740
+ const shared: SharedResolution = {
741
+ controller,
742
+ waiters: 0,
743
+ settled: false,
744
+ promise: Promise.resolve({ status: "unresolved", reason: "" }),
745
+ };
746
+
747
+ shared.promise = runResolution(segments, signal, expectedResolutionGeneration)
748
+ .then((resolution) => {
749
+ if (
750
+ cacheEnabled &&
751
+ resolution.status === "resolved" &&
752
+ !isDisposed() &&
753
+ expectedResolutionGeneration === resolutionGeneration
754
+ ) {
755
+ const cachedAt = now();
756
+ let expiresAt = Number.MAX_SAFE_INTEGER;
757
+ if (options.cacheTtlMs !== undefined) expiresAt = cachedAt + options.cacheTtlMs;
758
+ touchResolution(key, { resolution, expiresAt, cachedAt });
759
+ trimResolutionCache();
760
+ }
761
+
762
+ return resolution;
763
+ })
764
+ .catch((cause: unknown) => {
765
+ if (
766
+ !signal.aborted &&
767
+ !isDisposed() &&
768
+ expectedResolutionGeneration === resolutionGeneration
769
+ ) {
770
+ reportError("resolution-failed");
771
+ }
772
+
773
+ throw cause;
774
+ })
775
+ .finally(() => {
776
+ shared.settled = true;
777
+ if (resolutionInFlight.get(key) === shared) resolutionInFlight.delete(key);
778
+ });
779
+ resolutionInFlight.set(key, shared);
780
+
781
+ return shared;
782
+ };
783
+
784
+ const awaitShared = async <Result>(
785
+ shared: SharedWork<Result>,
786
+ signal?: AbortSignal,
787
+ ): Promise<Result> => {
788
+ if (signal?.aborted === true) return Promise.reject(abortCause(signal));
789
+
790
+ shared.waiters += 1;
791
+
792
+ let finished = false;
793
+ const finish = (): void => {
794
+ if (finished) return;
795
+
796
+ finished = true;
797
+ shared.waiters -= 1;
798
+ if (shared.waiters === 0 && !shared.settled) shared.controller.abort();
799
+ };
800
+
801
+ return new Promise((resolve, reject) => {
802
+ const abort = (): void => {
803
+ signal?.removeEventListener("abort", abort);
804
+ finish();
805
+
806
+ if (signal !== undefined) reject(abortCause(signal));
807
+ };
808
+
809
+ signal?.addEventListener("abort", abort, { once: true });
810
+ shared.promise.then(
811
+ (response) => {
812
+ signal?.removeEventListener("abort", abort);
813
+
814
+ if (finished) return;
815
+
816
+ finish();
817
+ resolve(response);
818
+ },
819
+ (cause: unknown) => {
820
+ signal?.removeEventListener("abort", abort);
821
+
822
+ if (finished) return;
823
+
824
+ finish();
825
+
826
+ if (cause instanceof Error) reject(cause);
827
+ else reject(new Error("Mention source operation failed.", { cause }));
828
+ },
829
+ );
830
+ });
831
+ };
832
+
833
+ const backgroundRefresh = (key: string, request: CachedRequest): void => {
834
+ const shared = startShared(key, request);
835
+ shared.waiters += 1;
836
+ shared.promise.then(
837
+ () => {
838
+ shared.waiters -= 1;
839
+ },
840
+ () => {
841
+ shared.waiters -= 1;
842
+ },
843
+ );
844
+ };
845
+
846
+ const discover = async (request: SourceControllerDiscovery): Promise<DiscoveryResponse> => {
847
+ if (isDisposed()) throw new Error("source controller is disposed");
848
+
849
+ request.signal?.throwIfAborted();
850
+ await persistenceReady;
851
+
852
+ if (isDisposed()) throw new Error("source controller is disposed");
853
+
854
+ request.signal?.throwIfAborted();
855
+ let cachedRequest: CachedRequest;
856
+ if (request.cursor === undefined) {
857
+ cachedRequest = { query: request.query, path: request.path };
858
+ } else {
859
+ cachedRequest = { query: request.query, path: request.path, cursor: request.cursor };
860
+ }
861
+
862
+ const key = keyFor(cachedRequest);
863
+ const requestScope = requestScopeFor(cachedRequest);
864
+ const currentTime = now();
865
+ const previousKey = latestRequestFor(requestScope, currentTime);
866
+ if (previousKey !== undefined && previousKey !== key) {
867
+ const previous = inFlight.get(previousKey);
868
+ if (previous !== undefined && previous.waiters <= 1) previous.controller.abort();
869
+ }
870
+
871
+ rememberLatestRequest(requestScope, key);
872
+
873
+ if (cacheEnabled) {
874
+ const entry = cache.get(key);
875
+ if (entry !== undefined) {
876
+ touch(key, entry);
877
+
878
+ if (
879
+ currentTime >= entry.expiresAt &&
880
+ failureRetryAt(key, currentTime) === undefined
881
+ ) {
882
+ backgroundRefresh(key, cachedRequest);
883
+ }
884
+
885
+ return entry.response;
886
+ }
887
+ }
888
+
889
+ if (failureRetryAt(key, currentTime) !== undefined) {
890
+ throw new Error("mention source discovery is temporarily unavailable");
891
+ }
892
+
893
+ return awaitShared(startShared(key, cachedRequest), request.signal);
894
+ };
895
+
896
+ const refreshRequests = async (requests: readonly CachedRequest[]): Promise<void> => {
897
+ const unique = new Map<string, CachedRequest>();
898
+ for (const request of requests) unique.set(keyFor(request), request);
899
+ const settled = await Promise.allSettled(
900
+ [...unique].map(async ([key, request]) => awaitShared(startShared(key, request))),
901
+ );
902
+ for (const result of settled) {
903
+ if (result.status === "rejected" && isDisposed()) return;
904
+ }
905
+ };
906
+
907
+ const refresh = async (): Promise<void> => {
908
+ await persistenceReady;
909
+
910
+ if (isDisposed()) return;
911
+
912
+ const requests = [...cache.values()].map((entry) => entry.request);
913
+ if (requests.length === 0) requests.push({ query: "", path: [] });
914
+
915
+ for (const shared of resolutionInFlight.values()) shared.controller.abort();
916
+ resolutionInFlight.clear();
917
+ resolutionGeneration += 1;
918
+ resolutionCache.clear();
919
+ await refreshRequests(requests);
920
+ };
921
+
922
+ const invalidate = (): void => {
923
+ if (isDisposed()) return;
924
+
925
+ generation += 1;
926
+ resolutionGeneration += 1;
927
+
928
+ for (const shared of inFlight.values()) shared.controller.abort();
929
+ inFlight.clear();
930
+
931
+ for (const shared of resolutionInFlight.values()) shared.controller.abort();
932
+ resolutionInFlight.clear();
933
+ cache.clear();
934
+ resolutionCache.clear();
935
+ failures.clear();
936
+ latestRequestByScope.clear();
937
+ savePersistence();
938
+ };
939
+
940
+ let interval: ReturnType<typeof setInterval> | undefined;
941
+ if (cacheEnabled && options.refreshIntervalMs !== undefined && options.refreshIntervalMs > 0) {
942
+ interval = setInterval(() => {
943
+ refresh().catch(() => reportError("discovery-failed"));
944
+ }, options.refreshIntervalMs);
945
+ }
946
+
947
+ interval?.unref();
948
+
949
+ if (cacheEnabled) {
950
+ const namesByParent = new Map<string, Set<string>>();
951
+ for (const file of options.watchFiles ?? []) {
952
+ const resolvedFile = resolveWatchFilePath(file, options.cwd);
953
+ const parent = dirname(resolvedFile);
954
+ let names = namesByParent.get(parent);
955
+ if (names === undefined) {
956
+ names = new Set();
957
+ namesByParent.set(parent, names);
958
+ }
959
+
960
+ names.add(basename(resolvedFile));
961
+ }
962
+
963
+ for (const [parent, names] of namesByParent) {
964
+ try {
965
+ const fileWatcher = watch(parent, (_eventType, filename) => {
966
+ if (filename !== null && !names.has(filename)) return;
967
+
968
+ clearTimeout(watchTimer);
969
+ watchTimer = setTimeout(invalidate, debounceMs);
970
+ });
971
+
972
+ fileWatcher.on("error", () => reportError("persistence-failed"));
973
+ watchers.push(fileWatcher);
974
+ } catch {
975
+ reportError("persistence-failed");
976
+ }
977
+ }
978
+ }
979
+
980
+ return {
981
+ discover,
982
+ async resolve(segments, signal) {
983
+ if (isDisposed()) throw new Error("source controller is disposed");
984
+
985
+ signal?.throwIfAborted();
986
+ const stableSegments = [...segments];
987
+ const key = resolutionKeyFor(stableSegments);
988
+ if (cacheEnabled) {
989
+ const entry = resolutionCache.get(key);
990
+ if (entry !== undefined) {
991
+ if (now() < entry.expiresAt) {
992
+ touchResolution(key, entry);
993
+ return entry.resolution;
994
+ }
995
+
996
+ resolutionCache.delete(key);
997
+ }
998
+ }
999
+
1000
+ return awaitShared(startSharedResolution(key, stableSegments), signal);
1001
+ },
1002
+ async warm() {
1003
+ await persistenceReady;
1004
+
1005
+ if (!cacheEnabled || options.refreshOnStartup !== true || isDisposed()) return;
1006
+ try {
1007
+ await discover({ query: "", path: [] });
1008
+ } catch {
1009
+ // Discovery owns the safe diagnostic; warming must not delay startup with a rejection.
1010
+ }
1011
+ },
1012
+ refresh,
1013
+ invalidate,
1014
+ status() {
1015
+ const currentTime = now();
1016
+ pruneAuxiliary(currentTime);
1017
+
1018
+ let oldestCacheAgeMs: number | undefined;
1019
+ let cachedCandidates = 0;
1020
+ for (const entry of cache.values()) {
1021
+ cachedCandidates += entry.response.items.length;
1022
+
1023
+ const age = Math.max(0, currentTime - entry.cachedAt);
1024
+ if (oldestCacheAgeMs === undefined || age > oldestCacheAgeMs)
1025
+ oldestCacheAgeMs = age;
1026
+ }
1027
+
1028
+ return {
1029
+ cachedEntries: cache.size,
1030
+ cachedCandidates,
1031
+ inFlightRequests: inFlight.size + resolutionInFlight.size,
1032
+ queuedRequests: limiter.queued,
1033
+ failedRequestKeys: failures.size,
1034
+ latestRequestScopes: latestRequestByScope.size,
1035
+ oldestCacheAgeMs,
1036
+ errorCodes: [...errorCodes].sort(),
1037
+ };
1038
+ },
1039
+ async dispose() {
1040
+ if (disposal !== undefined) return disposal;
1041
+
1042
+ generation += 1;
1043
+ resolutionGeneration += 1;
1044
+ lifetime.abort();
1045
+
1046
+ for (const shared of inFlight.values()) shared.controller.abort();
1047
+ inFlight.clear();
1048
+
1049
+ for (const shared of resolutionInFlight.values()) shared.controller.abort();
1050
+ resolutionInFlight.clear();
1051
+ resolutionCache.clear();
1052
+ failures.clear();
1053
+ clearInterval(interval);
1054
+ latestRequestByScope.clear();
1055
+ clearTimeout(watchTimer);
1056
+
1057
+ for (const fileWatcher of watchers) fileWatcher.close();
1058
+ watchers.length = 0;
1059
+ disposal = Promise.resolve().then(async () => {
1060
+ try {
1061
+ await provider.dispose?.();
1062
+ } catch {
1063
+ recordError("provider-disposal-failed");
1064
+ }
1065
+ });
1066
+
1067
+ return disposal;
1068
+ },
1069
+ };
1070
+ }