@marktrue/dsh-mobile-remote 3.2.3-rc.1 → 3.2.4-alpha.1-app

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 (353) hide show
  1. package/DSH-Remote-v3.2.4.apk +4 -0
  2. package/README.md +6 -254
  3. package/manifest.json +21 -0
  4. package/package.json +12 -65
  5. package/CHANGELOG.md +0 -1362
  6. package/CONTRIBUTING.md +0 -59
  7. package/FAQ.md +0 -111
  8. package/cordis.patch.yml +0 -14
  9. package/docs/00-/345/274/200/345/217/221/346/200/273/347/272/262.md +0 -125
  10. package/docs/01-PRD.md +0 -148
  11. package/docs/02-architecture.md +0 -249
  12. package/docs/03-api.md +0 -930
  13. package/docs/04-security.md +0 -100
  14. package/docs/05-test-cases.md +0 -405
  15. package/docs/06-install-run.md +0 -372
  16. package/docs/07-user-manual.md +0 -70
  17. package/docs/08-/346/211/251/345/261/225/345/274/200/345/217/221/346/214/207/345/215/227.md +0 -86
  18. package/docs/09-compatibility.md +0 -227
  19. package/docs/10-release.md +0 -929
  20. package/docs/screenshots/01-home.png +0 -0
  21. package/docs/screenshots/02-notifications.png +0 -0
  22. package/docs/screenshots/03-sessions.png +0 -0
  23. package/docs/screenshots/04-chat.png +0 -0
  24. package/docs/screenshots/05-settings.png +0 -0
  25. package/docs/screenshots/06-new-session.png +0 -0
  26. package/docs/screenshots/pgy-appstore.jpg +0 -0
  27. package/docs/screenshots/pgy-mobile-app.jpg +0 -0
  28. package/docs/screenshots/pgy-pc-client.jpg +0 -0
  29. package/docs/spec-app-auto-update.md +0 -143
  30. package/lib/account-usage.js +0 -145
  31. package/lib/app-alignment.js +0 -112
  32. package/lib/app-carrier-store.js +0 -1972
  33. package/lib/app-carrier.js +0 -609
  34. package/lib/client.js +0 -1174
  35. package/lib/desktop-form.js +0 -738
  36. package/lib/endpoint-registry.js +0 -165
  37. package/lib/git-read-bundled-provider.js +0 -255
  38. package/lib/git-read-service.js +0 -322
  39. package/lib/index.js +0 -9609
  40. package/lib/npm-update-source.js +0 -226
  41. package/lib/plugin-content-digest.js +0 -80
  42. package/lib/plugin-self-update.js +0 -997
  43. package/lib/plugin-update-controller.js +0 -274
  44. package/lib/plugin-update-log.js +0 -164
  45. package/lib/plugin-update-transaction.js +0 -322
  46. package/lib/plugin-update.js +0 -309
  47. package/lib/runtime-dependency-snapshot.js +0 -345
  48. package/lib/session-title-cache.js +0 -123
  49. package/lib/session-title-refresh.js +0 -261
  50. package/lib/tool-process.js +0 -20
  51. package/lib/update-fetch.js +0 -24
  52. package/lib/update-lock-arbiter.js +0 -170
  53. package/lib/update-supervisor.js +0 -346
  54. package/node_modules/ansi-regex/index.d.ts +0 -37
  55. package/node_modules/ansi-regex/index.js +0 -10
  56. package/node_modules/ansi-regex/license +0 -9
  57. package/node_modules/ansi-regex/package.json +0 -55
  58. package/node_modules/ansi-regex/readme.md +0 -78
  59. package/node_modules/ansi-styles/index.d.ts +0 -345
  60. package/node_modules/ansi-styles/index.js +0 -163
  61. package/node_modules/ansi-styles/license +0 -9
  62. package/node_modules/ansi-styles/package.json +0 -56
  63. package/node_modules/ansi-styles/readme.md +0 -152
  64. package/node_modules/camelcase/index.d.ts +0 -63
  65. package/node_modules/camelcase/index.js +0 -76
  66. package/node_modules/camelcase/license +0 -9
  67. package/node_modules/camelcase/package.json +0 -43
  68. package/node_modules/camelcase/readme.md +0 -99
  69. package/node_modules/cliui/CHANGELOG.md +0 -76
  70. package/node_modules/cliui/LICENSE.txt +0 -14
  71. package/node_modules/cliui/README.md +0 -115
  72. package/node_modules/cliui/index.js +0 -354
  73. package/node_modules/cliui/package.json +0 -65
  74. package/node_modules/color-convert/CHANGELOG.md +0 -54
  75. package/node_modules/color-convert/LICENSE +0 -21
  76. package/node_modules/color-convert/README.md +0 -68
  77. package/node_modules/color-convert/conversions.js +0 -839
  78. package/node_modules/color-convert/index.js +0 -81
  79. package/node_modules/color-convert/package.json +0 -48
  80. package/node_modules/color-convert/route.js +0 -97
  81. package/node_modules/color-name/LICENSE +0 -8
  82. package/node_modules/color-name/README.md +0 -11
  83. package/node_modules/color-name/index.js +0 -152
  84. package/node_modules/color-name/package.json +0 -28
  85. package/node_modules/decamelize/index.js +0 -13
  86. package/node_modules/decamelize/license +0 -21
  87. package/node_modules/decamelize/package.json +0 -38
  88. package/node_modules/decamelize/readme.md +0 -48
  89. package/node_modules/dijkstrajs/.travis.yml +0 -4
  90. package/node_modules/dijkstrajs/CONTRIBUTING.md +0 -8
  91. package/node_modules/dijkstrajs/LICENSE.md +0 -19
  92. package/node_modules/dijkstrajs/README.md +0 -18
  93. package/node_modules/dijkstrajs/dijkstra.js +0 -165
  94. package/node_modules/dijkstrajs/package.json +0 -60
  95. package/node_modules/dijkstrajs/test/dijkstra.test.js +0 -96
  96. package/node_modules/emoji-regex/LICENSE-MIT.txt +0 -20
  97. package/node_modules/emoji-regex/README.md +0 -73
  98. package/node_modules/emoji-regex/es2015/index.js +0 -6
  99. package/node_modules/emoji-regex/es2015/text.js +0 -6
  100. package/node_modules/emoji-regex/index.d.ts +0 -23
  101. package/node_modules/emoji-regex/index.js +0 -6
  102. package/node_modules/emoji-regex/package.json +0 -50
  103. package/node_modules/emoji-regex/text.js +0 -6
  104. package/node_modules/find-up/index.d.ts +0 -137
  105. package/node_modules/find-up/index.js +0 -89
  106. package/node_modules/find-up/license +0 -9
  107. package/node_modules/find-up/package.json +0 -53
  108. package/node_modules/find-up/readme.md +0 -156
  109. package/node_modules/get-caller-file/LICENSE.md +0 -6
  110. package/node_modules/get-caller-file/README.md +0 -41
  111. package/node_modules/get-caller-file/index.d.ts +0 -2
  112. package/node_modules/get-caller-file/index.js +0 -22
  113. package/node_modules/get-caller-file/index.js.map +0 -1
  114. package/node_modules/get-caller-file/package.json +0 -42
  115. package/node_modules/is-fullwidth-code-point/index.d.ts +0 -17
  116. package/node_modules/is-fullwidth-code-point/index.js +0 -50
  117. package/node_modules/is-fullwidth-code-point/license +0 -9
  118. package/node_modules/is-fullwidth-code-point/package.json +0 -42
  119. package/node_modules/is-fullwidth-code-point/readme.md +0 -39
  120. package/node_modules/locate-path/index.d.ts +0 -83
  121. package/node_modules/locate-path/index.js +0 -65
  122. package/node_modules/locate-path/license +0 -9
  123. package/node_modules/locate-path/package.json +0 -45
  124. package/node_modules/locate-path/readme.md +0 -122
  125. package/node_modules/p-limit/index.d.ts +0 -38
  126. package/node_modules/p-limit/index.js +0 -57
  127. package/node_modules/p-limit/license +0 -9
  128. package/node_modules/p-limit/package.json +0 -52
  129. package/node_modules/p-limit/readme.md +0 -101
  130. package/node_modules/p-locate/index.d.ts +0 -64
  131. package/node_modules/p-locate/index.js +0 -52
  132. package/node_modules/p-locate/license +0 -9
  133. package/node_modules/p-locate/package.json +0 -53
  134. package/node_modules/p-locate/readme.md +0 -90
  135. package/node_modules/p-try/index.d.ts +0 -39
  136. package/node_modules/p-try/index.js +0 -9
  137. package/node_modules/p-try/license +0 -9
  138. package/node_modules/p-try/package.json +0 -42
  139. package/node_modules/p-try/readme.md +0 -58
  140. package/node_modules/path-exists/index.d.ts +0 -28
  141. package/node_modules/path-exists/index.js +0 -23
  142. package/node_modules/path-exists/license +0 -9
  143. package/node_modules/path-exists/package.json +0 -39
  144. package/node_modules/path-exists/readme.md +0 -52
  145. package/node_modules/pngjs/.eslintignore +0 -2
  146. package/node_modules/pngjs/.eslintrc.json +0 -19
  147. package/node_modules/pngjs/.prettierignore +0 -3
  148. package/node_modules/pngjs/LICENSE +0 -20
  149. package/node_modules/pngjs/README.md +0 -429
  150. package/node_modules/pngjs/browser.js +0 -16096
  151. package/node_modules/pngjs/coverage/lcov-report/base.css +0 -354
  152. package/node_modules/pngjs/coverage/lcov-report/bitmapper.js.html +0 -881
  153. package/node_modules/pngjs/coverage/lcov-report/bitpacker.js.html +0 -554
  154. package/node_modules/pngjs/coverage/lcov-report/block-navigation.js +0 -77
  155. package/node_modules/pngjs/coverage/lcov-report/chunkstream.js.html +0 -647
  156. package/node_modules/pngjs/coverage/lcov-report/constants.js.html +0 -176
  157. package/node_modules/pngjs/coverage/lcov-report/crc.js.html +0 -200
  158. package/node_modules/pngjs/coverage/lcov-report/favicon.png +0 -0
  159. package/node_modules/pngjs/coverage/lcov-report/filter-pack.js.html +0 -593
  160. package/node_modules/pngjs/coverage/lcov-report/filter-parse-async.js.html +0 -152
  161. package/node_modules/pngjs/coverage/lcov-report/filter-parse-sync.js.html +0 -143
  162. package/node_modules/pngjs/coverage/lcov-report/filter-parse.js.html +0 -611
  163. package/node_modules/pngjs/coverage/lcov-report/format-normaliser.js.html +0 -359
  164. package/node_modules/pngjs/coverage/lcov-report/index.html +0 -426
  165. package/node_modules/pngjs/coverage/lcov-report/interlace.js.html +0 -365
  166. package/node_modules/pngjs/coverage/lcov-report/packer-async.js.html +0 -230
  167. package/node_modules/pngjs/coverage/lcov-report/packer-sync.js.html +0 -248
  168. package/node_modules/pngjs/coverage/lcov-report/packer.js.html +0 -467
  169. package/node_modules/pngjs/coverage/lcov-report/paeth-predictor.js.html +0 -128
  170. package/node_modules/pngjs/coverage/lcov-report/parser-async.js.html +0 -575
  171. package/node_modules/pngjs/coverage/lcov-report/parser-sync.js.html +0 -404
  172. package/node_modules/pngjs/coverage/lcov-report/parser.js.html +0 -950
  173. package/node_modules/pngjs/coverage/lcov-report/png-sync.js.html +0 -116
  174. package/node_modules/pngjs/coverage/lcov-report/png.js.html +0 -662
  175. package/node_modules/pngjs/coverage/lcov-report/prettify.css +0 -101
  176. package/node_modules/pngjs/coverage/lcov-report/prettify.js +0 -1007
  177. package/node_modules/pngjs/coverage/lcov-report/sort-arrow-sprite.png +0 -0
  178. package/node_modules/pngjs/coverage/lcov-report/sorter.js +0 -169
  179. package/node_modules/pngjs/coverage/lcov-report/sync-inflate.js.html +0 -584
  180. package/node_modules/pngjs/coverage/lcov-report/sync-reader.js.html +0 -215
  181. package/node_modules/pngjs/coverage/lcov.info +0 -2177
  182. package/node_modules/pngjs/lib/bitmapper.js +0 -267
  183. package/node_modules/pngjs/lib/bitpacker.js +0 -158
  184. package/node_modules/pngjs/lib/chunkstream.js +0 -189
  185. package/node_modules/pngjs/lib/constants.js +0 -32
  186. package/node_modules/pngjs/lib/crc.js +0 -40
  187. package/node_modules/pngjs/lib/filter-pack.js +0 -171
  188. package/node_modules/pngjs/lib/filter-parse-async.js +0 -24
  189. package/node_modules/pngjs/lib/filter-parse-sync.js +0 -21
  190. package/node_modules/pngjs/lib/filter-parse.js +0 -177
  191. package/node_modules/pngjs/lib/format-normaliser.js +0 -93
  192. package/node_modules/pngjs/lib/interlace.js +0 -95
  193. package/node_modules/pngjs/lib/packer-async.js +0 -50
  194. package/node_modules/pngjs/lib/packer-sync.js +0 -56
  195. package/node_modules/pngjs/lib/packer.js +0 -129
  196. package/node_modules/pngjs/lib/paeth-predictor.js +0 -16
  197. package/node_modules/pngjs/lib/parser-async.js +0 -165
  198. package/node_modules/pngjs/lib/parser-sync.js +0 -108
  199. package/node_modules/pngjs/lib/parser.js +0 -290
  200. package/node_modules/pngjs/lib/png-sync.js +0 -12
  201. package/node_modules/pngjs/lib/png.js +0 -194
  202. package/node_modules/pngjs/lib/sync-inflate.js +0 -168
  203. package/node_modules/pngjs/lib/sync-reader.js +0 -45
  204. package/node_modules/pngjs/package.json +0 -73
  205. package/node_modules/qrcode/README.md +0 -770
  206. package/node_modules/qrcode/bin/qrcode +0 -159
  207. package/node_modules/qrcode/helper/to-sjis-browser.js +0 -2
  208. package/node_modules/qrcode/helper/to-sjis.js +0 -105
  209. package/node_modules/qrcode/lib/browser.js +0 -76
  210. package/node_modules/qrcode/lib/can-promise.js +0 -7
  211. package/node_modules/qrcode/lib/core/alignment-pattern.js +0 -83
  212. package/node_modules/qrcode/lib/core/alphanumeric-data.js +0 -59
  213. package/node_modules/qrcode/lib/core/bit-buffer.js +0 -37
  214. package/node_modules/qrcode/lib/core/bit-matrix.js +0 -65
  215. package/node_modules/qrcode/lib/core/byte-data.js +0 -30
  216. package/node_modules/qrcode/lib/core/error-correction-code.js +0 -135
  217. package/node_modules/qrcode/lib/core/error-correction-level.js +0 -50
  218. package/node_modules/qrcode/lib/core/finder-pattern.js +0 -22
  219. package/node_modules/qrcode/lib/core/format-info.js +0 -29
  220. package/node_modules/qrcode/lib/core/galois-field.js +0 -69
  221. package/node_modules/qrcode/lib/core/kanji-data.js +0 -54
  222. package/node_modules/qrcode/lib/core/mask-pattern.js +0 -234
  223. package/node_modules/qrcode/lib/core/mode.js +0 -167
  224. package/node_modules/qrcode/lib/core/numeric-data.js +0 -43
  225. package/node_modules/qrcode/lib/core/polynomial.js +0 -62
  226. package/node_modules/qrcode/lib/core/qrcode.js +0 -495
  227. package/node_modules/qrcode/lib/core/reed-solomon-encoder.js +0 -56
  228. package/node_modules/qrcode/lib/core/regex.js +0 -31
  229. package/node_modules/qrcode/lib/core/segments.js +0 -330
  230. package/node_modules/qrcode/lib/core/utils.js +0 -63
  231. package/node_modules/qrcode/lib/core/version-check.js +0 -9
  232. package/node_modules/qrcode/lib/core/version.js +0 -163
  233. package/node_modules/qrcode/lib/index.js +0 -12
  234. package/node_modules/qrcode/lib/renderer/canvas.js +0 -63
  235. package/node_modules/qrcode/lib/renderer/png.js +0 -78
  236. package/node_modules/qrcode/lib/renderer/svg-tag.js +0 -81
  237. package/node_modules/qrcode/lib/renderer/svg.js +0 -19
  238. package/node_modules/qrcode/lib/renderer/terminal/terminal-small.js +0 -85
  239. package/node_modules/qrcode/lib/renderer/terminal/terminal.js +0 -49
  240. package/node_modules/qrcode/lib/renderer/terminal.js +0 -9
  241. package/node_modules/qrcode/lib/renderer/utf8.js +0 -71
  242. package/node_modules/qrcode/lib/renderer/utils.js +0 -99
  243. package/node_modules/qrcode/lib/server.js +0 -138
  244. package/node_modules/qrcode/license +0 -10
  245. package/node_modules/qrcode/package.json +0 -77
  246. package/node_modules/require-directory/.jshintrc +0 -67
  247. package/node_modules/require-directory/.npmignore +0 -1
  248. package/node_modules/require-directory/.travis.yml +0 -3
  249. package/node_modules/require-directory/LICENSE +0 -22
  250. package/node_modules/require-directory/README.markdown +0 -184
  251. package/node_modules/require-directory/index.js +0 -86
  252. package/node_modules/require-directory/package.json +0 -40
  253. package/node_modules/require-main-filename/CHANGELOG.md +0 -26
  254. package/node_modules/require-main-filename/LICENSE.txt +0 -14
  255. package/node_modules/require-main-filename/README.md +0 -26
  256. package/node_modules/require-main-filename/index.js +0 -18
  257. package/node_modules/require-main-filename/package.json +0 -35
  258. package/node_modules/set-blocking/CHANGELOG.md +0 -26
  259. package/node_modules/set-blocking/LICENSE.txt +0 -14
  260. package/node_modules/set-blocking/README.md +0 -31
  261. package/node_modules/set-blocking/index.js +0 -7
  262. package/node_modules/set-blocking/package.json +0 -42
  263. package/node_modules/string-width/index.d.ts +0 -29
  264. package/node_modules/string-width/index.js +0 -47
  265. package/node_modules/string-width/license +0 -9
  266. package/node_modules/string-width/package.json +0 -56
  267. package/node_modules/string-width/readme.md +0 -50
  268. package/node_modules/strip-ansi/index.d.ts +0 -17
  269. package/node_modules/strip-ansi/index.js +0 -4
  270. package/node_modules/strip-ansi/license +0 -9
  271. package/node_modules/strip-ansi/package.json +0 -54
  272. package/node_modules/strip-ansi/readme.md +0 -46
  273. package/node_modules/which-module/LICENSE +0 -13
  274. package/node_modules/which-module/README.md +0 -58
  275. package/node_modules/which-module/index.js +0 -9
  276. package/node_modules/which-module/package.json +0 -41
  277. package/node_modules/wrap-ansi/index.js +0 -186
  278. package/node_modules/wrap-ansi/license +0 -9
  279. package/node_modules/wrap-ansi/package.json +0 -61
  280. package/node_modules/wrap-ansi/readme.md +0 -97
  281. package/node_modules/y18n/CHANGELOG.md +0 -35
  282. package/node_modules/y18n/LICENSE +0 -13
  283. package/node_modules/y18n/README.md +0 -109
  284. package/node_modules/y18n/index.js +0 -188
  285. package/node_modules/y18n/package.json +0 -39
  286. package/node_modules/yargs/CHANGELOG.md +0 -420
  287. package/node_modules/yargs/LICENSE +0 -21
  288. package/node_modules/yargs/README.md +0 -140
  289. package/node_modules/yargs/build/lib/apply-extends.d.ts +0 -2
  290. package/node_modules/yargs/build/lib/apply-extends.js +0 -65
  291. package/node_modules/yargs/build/lib/argsert.d.ts +0 -2
  292. package/node_modules/yargs/build/lib/argsert.js +0 -65
  293. package/node_modules/yargs/build/lib/command.d.ts +0 -64
  294. package/node_modules/yargs/build/lib/command.js +0 -416
  295. package/node_modules/yargs/build/lib/common-types.d.ts +0 -36
  296. package/node_modules/yargs/build/lib/common-types.js +0 -25
  297. package/node_modules/yargs/build/lib/completion-templates.d.ts +0 -2
  298. package/node_modules/yargs/build/lib/completion-templates.js +0 -50
  299. package/node_modules/yargs/build/lib/completion.d.ts +0 -21
  300. package/node_modules/yargs/build/lib/completion.js +0 -135
  301. package/node_modules/yargs/build/lib/is-promise.d.ts +0 -1
  302. package/node_modules/yargs/build/lib/is-promise.js +0 -9
  303. package/node_modules/yargs/build/lib/levenshtein.d.ts +0 -1
  304. package/node_modules/yargs/build/lib/levenshtein.js +0 -58
  305. package/node_modules/yargs/build/lib/middleware.d.ts +0 -10
  306. package/node_modules/yargs/build/lib/middleware.js +0 -57
  307. package/node_modules/yargs/build/lib/obj-filter.d.ts +0 -1
  308. package/node_modules/yargs/build/lib/obj-filter.js +0 -14
  309. package/node_modules/yargs/build/lib/parse-command.d.ts +0 -11
  310. package/node_modules/yargs/build/lib/parse-command.js +0 -36
  311. package/node_modules/yargs/build/lib/process-argv.d.ts +0 -2
  312. package/node_modules/yargs/build/lib/process-argv.js +0 -31
  313. package/node_modules/yargs/build/lib/usage.d.ts +0 -49
  314. package/node_modules/yargs/build/lib/usage.js +0 -540
  315. package/node_modules/yargs/build/lib/validation.d.ts +0 -34
  316. package/node_modules/yargs/build/lib/validation.js +0 -330
  317. package/node_modules/yargs/build/lib/yargs.d.ts +0 -274
  318. package/node_modules/yargs/build/lib/yargs.js +0 -1190
  319. package/node_modules/yargs/build/lib/yerror.d.ts +0 -4
  320. package/node_modules/yargs/build/lib/yerror.js +0 -11
  321. package/node_modules/yargs/index.js +0 -40
  322. package/node_modules/yargs/locales/be.json +0 -46
  323. package/node_modules/yargs/locales/de.json +0 -46
  324. package/node_modules/yargs/locales/en.json +0 -51
  325. package/node_modules/yargs/locales/es.json +0 -46
  326. package/node_modules/yargs/locales/fi.json +0 -49
  327. package/node_modules/yargs/locales/fr.json +0 -53
  328. package/node_modules/yargs/locales/hi.json +0 -49
  329. package/node_modules/yargs/locales/hu.json +0 -46
  330. package/node_modules/yargs/locales/id.json +0 -50
  331. package/node_modules/yargs/locales/it.json +0 -46
  332. package/node_modules/yargs/locales/ja.json +0 -51
  333. package/node_modules/yargs/locales/ko.json +0 -49
  334. package/node_modules/yargs/locales/nb.json +0 -44
  335. package/node_modules/yargs/locales/nl.json +0 -49
  336. package/node_modules/yargs/locales/nn.json +0 -44
  337. package/node_modules/yargs/locales/pirate.json +0 -13
  338. package/node_modules/yargs/locales/pl.json +0 -49
  339. package/node_modules/yargs/locales/pt.json +0 -45
  340. package/node_modules/yargs/locales/pt_BR.json +0 -48
  341. package/node_modules/yargs/locales/ru.json +0 -46
  342. package/node_modules/yargs/locales/th.json +0 -46
  343. package/node_modules/yargs/locales/tr.json +0 -48
  344. package/node_modules/yargs/locales/zh_CN.json +0 -48
  345. package/node_modules/yargs/locales/zh_TW.json +0 -47
  346. package/node_modules/yargs/package.json +0 -92
  347. package/node_modules/yargs/yargs.js +0 -14
  348. package/node_modules/yargs-parser/CHANGELOG.md +0 -601
  349. package/node_modules/yargs-parser/LICENSE.txt +0 -14
  350. package/node_modules/yargs-parser/README.md +0 -449
  351. package/node_modules/yargs-parser/index.js +0 -1032
  352. package/node_modules/yargs-parser/lib/tokenize-arg-string.js +0 -40
  353. package/node_modules/yargs-parser/package.json +0 -46
@@ -1,322 +0,0 @@
1
- import { createHash, randomUUID } from "node:crypto";
2
- import { basename, isAbsolute, relative, resolve, sep } from "node:path";
3
- import { realpath } from "node:fs/promises";
4
- import { createBundledGitReadProvider } from "./git-read-bundled-provider.js";
5
-
6
- const MAX_GRAPH_TIPS = 5;
7
-
8
- function failure(code, status, message = code) {
9
- const error = new Error(message);
10
- error.code = code;
11
- error.status = status;
12
- return error;
13
- }
14
-
15
- const providerCompatible = (provider) => provider?.contractVersion === "1.0.0"
16
- && ["repositoryRoot", "branches", "resolveTip", "graph", "commit"].every((method) => typeof provider[method] === "function");
17
-
18
- /** Session-authorized read facade over an optional external or bundled provider. */
19
- export function createGitReadService(ctx, { bundledProvider, now = () => Date.now(), snapshotTtlMs = 5 * 60_000, pollIntervalMs = 30_000, onChanged } = {}) {
20
- const get = (name) => { try { return ctx.get?.(name); } catch { return undefined; } };
21
- const external = get("gitReadProvider");
22
- let externalAvailable = false;
23
- try { externalAvailable = providerCompatible(external) && external.capabilities?.().available === true; } catch {}
24
- const provider = externalAvailable ? external : (bundledProvider ?? createBundledGitReadProvider(ctx));
25
- const bindings = new Map();
26
- const repositoryIdFor = (sessionId, root) => `repo_${createHash("sha256").update(`${sessionId}\0${root}`).digest("base64url").slice(0, 32)}`;
27
- const inside = (child, parent) => {
28
- const path = relative(resolve(parent), resolve(child));
29
- return path === "" || (path !== ".." && !path.startsWith(`..${sep}`) && !isAbsolute(path));
30
- };
31
- const authorizedRoot = async (cwd) => {
32
- if (typeof cwd !== "string" || !cwd) throw failure("repository-not-authorized", 403);
33
- try {
34
- const canonicalCwd = await realpath(cwd);
35
- const workspacePaths = get("workspaceRegistry")?.list?.()?.map((entry) => entry?.path) ?? [];
36
- const workspaces = await Promise.all(workspacePaths.filter((path) => typeof path === "string").map((path) => realpath(path).catch(() => null)));
37
- if (!workspaces.some((path) => path && inside(canonicalCwd, path))) throw failure("repository-not-authorized", 403);
38
- const root = await realpath(await provider.repositoryRoot(canonicalCwd));
39
- if (!inside(canonicalCwd, root) || !workspaces.some((path) => path && inside(root, path))) throw failure("repository-not-authorized", 403);
40
- return root;
41
- } catch (error) {
42
- if (["git-provider-unavailable", "not-git-repository"].includes(error?.code)) throw failure(error.code, error.status);
43
- throw failure("repository-not-authorized", 403);
44
- }
45
- };
46
- const session = (sessionId) => {
47
- if (typeof sessionId !== "string" || sessionId === "") throw failure("session-not-found", 404);
48
- const value = get("sessions")?.get?.(sessionId);
49
- if (!value) throw failure("session-not-found", 404);
50
- return value;
51
- };
52
- const binding = async (sessionId, repositoryId) => {
53
- const value = bindings.get(repositoryId);
54
- if (!value || value.sessionId !== sessionId) throw failure("repository-not-authorized", 403);
55
- const current = session(sessionId);
56
- const currentRoot = await authorizedRoot(current?.header?.cwd);
57
- if (currentRoot !== value.root) throw failure("repository-not-authorized", 403);
58
- return value;
59
- };
60
- const worktreeSnapshots = new Map();
61
- const snapshots = new Map();
62
- const fileCursors = new Map();
63
- const refSignatures = new Map();
64
- const keepBounded = (map, maximum) => {
65
- while (map.size > maximum) map.delete(map.keys().next().value);
66
- };
67
- const prune = () => {
68
- for (const [id, item] of snapshots) if (item.expiresAt <= now()) snapshots.delete(id);
69
- for (const [id, item] of fileCursors) if (item.expiresAt <= now()) fileCursors.delete(id);
70
- };
71
- let pollTimer = null;
72
- let unsubscribeProvider = null;
73
- const validOid = (value) => typeof value === "string" && /^(?:[0-9a-f]{40}|[0-9a-f]{64})$/i.test(value);
74
- const safeFilePath = (value) => typeof value === "string" && value !== "" && !isAbsolute(value) && !/^(?:[A-Za-z]:[\\/]|\\\\|[a-z][a-z\d+.-]*:\/\/)/i.test(value) && !value.split(/[\\/]/).includes("..") && !value.includes("\0");
75
- const validRef = (value) => value === "HEAD" || (typeof value === "string" && /^refs\/(?:heads|remotes)\/[A-Za-z0-9._/-]+$/.test(value) && !value.includes("..") && !value.includes("//") && !value.includes("@{") && !/(^|\/)\.|\/$|\.lock(?:\/|$)|[/.]$/.test(value));
76
- const stale = () => failure("graph-stale", 409);
77
- const capabilities = () => {
78
- const base = provider.capabilities?.() ?? { available: true, reason: null };
79
- return {
80
- contractVersion: "1.0.0", available: base.available !== false,
81
- reason: ["git-provider-unavailable", "workspace-registry-unavailable"].includes(base.reason) ? base.reason : null,
82
- readOnly: true, provider: provider === external ? "external" : "bundled",
83
- features: { repository: true, branches: true, graph: true, commit: true, worktree: true, preview: true },
84
- };
85
- };
86
- const service = {
87
- capabilities,
88
- async capabilitiesForSession(sessionId) {
89
- const current = session(sessionId);
90
- const base = capabilities();
91
- if (!base.available) return base;
92
- try {
93
- await authorizedRoot(current?.header?.cwd);
94
- return base;
95
- } catch (error) {
96
- const reason = ["not-git-repository", "git-provider-unavailable"].includes(error?.code)
97
- ? error.code : "repository-not-authorized";
98
- return { ...base, available: false, reason };
99
- }
100
- },
101
- async repositoryForSession(sessionId) {
102
- const current = session(sessionId);
103
- const root = await authorizedRoot(current?.header?.cwd);
104
- const repositoryId = repositoryIdFor(sessionId, root);
105
- bindings.set(repositoryId, { sessionId, root });
106
- keepBounded(bindings, 256);
107
- const rawInfo = typeof provider.repositoryInfo === "function" ? await provider.repositoryInfo(root) : {};
108
- if (typeof provider.refSignature === "function") refSignatures.set(repositoryId, await provider.refSignature(root));
109
- return {
110
- repositoryId, name: basename(root) || "repository",
111
- ...(validOid(rawInfo.headOid) ? { headOid: rawInfo.headOid } : {}),
112
- ...(typeof rawInfo.currentBranch === "string" && rawInfo.currentBranch.startsWith("refs/heads/") && validRef(rawInfo.currentBranch) ? { currentBranch: rawInfo.currentBranch } : {}),
113
- detached: rawInfo.detached === true, empty: rawInfo.empty === true,
114
- };
115
- },
116
- async worktree(sessionId, repositoryId) {
117
- const authorized = await binding(sessionId, repositoryId);
118
- let reader = typeof provider.worktree === "function" ? provider : createBundledGitReadProvider(ctx);
119
- let raw = await reader.worktree(authorized.root);
120
- if (typeof raw?.signature !== "string" || raw.signature === "" || !Array.isArray(raw.entries)) {
121
- reader = createBundledGitReadProvider(ctx);
122
- raw = await reader.worktree(authorized.root);
123
- }
124
- const entries = (raw.entries ?? []).filter((entry) => safeFilePath(entry.path)).slice(0, 2000);
125
- const snapshotId = createHash("sha256").update(`${repositoryId}\0${raw.signature}\0${JSON.stringify(entries)}`).digest("base64url");
126
- worktreeSnapshots.set(snapshotId, { sessionId, repositoryId, root: authorized.root, signature: raw.signature, entries, reader, expiresAt: now() + snapshotTtlMs });
127
- keepBounded(worktreeSnapshots, 128);
128
- return { repositoryId, snapshotId, staged: entries.filter((e) => e.index).map(({ path, oldPath, status, conflicted }) => ({ path, ...(oldPath ? { oldPath } : {}), status, conflicted })), unstaged: entries.filter((e) => e.worktree).map(({ path, oldPath, status, conflicted }) => ({ path, ...(oldPath ? { oldPath } : {}), status, conflicted })), untracked: entries.filter((e) => e.status === "untracked").map(({ path, status, conflicted }) => ({ path, status, conflicted })), truncated: (raw.entries ?? []).length > 2000 };
129
- },
130
- async preview(sessionId, repositoryId, { kind, snapshotId, path, oid } = {}) {
131
- const authorized = await binding(sessionId, repositoryId);
132
- if (!safeFilePath(path) || !["staged", "unstaged", "untracked", "commit"].includes(kind)) throw failure("preview-invalid", 400);
133
- const reader = createBundledGitReadProvider(ctx);
134
- let raw;
135
- if (kind === "commit") {
136
- if (!validOid(oid)) throw failure("invalid-oid", 400);
137
- const commit = typeof provider.commit === "function"
138
- ? await provider.commit(authorized.root, oid)
139
- : await reader.commit(authorized.root, oid);
140
- const commitFile = (Array.isArray(commit?.files) ? commit.files : []).find((file) => file.path === path || file.oldPath === path);
141
- if (!commitFile) throw failure("preview-file-not-found", 404);
142
- raw = { ...await reader.commitPreview(authorized.root, oid, path), ...(commitFile.oldPath ? { oldPath: commitFile.oldPath } : {}) };
143
- } else {
144
- const snap = worktreeSnapshots.get(snapshotId);
145
- if (!snap || snap.sessionId !== sessionId || snap.repositoryId !== repositoryId || snap.root !== authorized.root || snap.expiresAt <= now()) throw stale();
146
- const current = await snap.reader.worktree(authorized.root);
147
- if (current.signature !== snap.signature) throw stale();
148
- const member = snap.entries.find((entry) => entry.path === path && (kind === "untracked" ? entry.status === "untracked" : kind === "staged" ? entry.index : entry.worktree));
149
- if (!member) throw failure("preview-file-not-found", 404);
150
- if (member.conflicted) raw = { diff: "", binary: false, notice: "merge conflict preview omitted" };
151
- else {
152
- const previewReader = typeof snap.reader.worktreePreview === "function" ? snap.reader : reader;
153
- const preview = await previewReader.worktreePreview(authorized.root, kind, path);
154
- const afterPreview = await snap.reader.worktree(authorized.root);
155
- if (afterPreview.signature !== snap.signature) throw stale();
156
- raw = { ...preview, ...(member.oldPath ? { oldPath: member.oldPath } : {}) };
157
- }
158
- }
159
- let diff = String(raw.diff ?? ""); const max = 512 * 1024; const truncated = raw.truncated === true || Buffer.byteLength(diff) > max;
160
- if (Buffer.byteLength(diff) > max) diff = Buffer.from(diff).subarray(0, max).toString("utf8");
161
- const binary = raw.binary === true || /Binary files? .* differ/.test(diff) || diff.includes("GIT binary patch");
162
- let notice = raw.notice;
163
- if (!notice && binary) { notice = "binary preview omitted"; diff = ""; }
164
- else if (!notice && /(?:new file mode|old mode|new mode) 120000/.test(diff)) { notice = "symlink text preview omitted"; diff = ""; }
165
- else if (!notice && /^\+(?:Subproject commit )|^-(?:Subproject commit )/m.test(diff)) { notice = "submodule preview omitted"; diff = ""; }
166
- else if (!notice && !/^@@/m.test(diff) && /^(?:old mode|new mode) /m.test(diff)) { notice = "file mode changed; no text changes"; diff = ""; }
167
- return { repositoryId, kind, path, ...(raw.oldPath ? { oldPath: raw.oldPath } : {}), diff, truncated, binary, additions: raw.additions ?? null, deletions: raw.deletions ?? null, ...(notice ? { notice } : {}) };
168
- },
169
- async branches(sessionId, repositoryId) {
170
- const authorized = await binding(sessionId, repositoryId);
171
- if (typeof provider.branches !== "function") throw failure("provider-incompatible", 503);
172
- const rows = await provider.branches(authorized.root);
173
- const branches = (Array.isArray(rows) ? rows : []).filter((row) => row && row.name !== "HEAD" && validRef(row.name) && validOid(row.oid)).map((row) => ({
174
- name: row.name, displayName: row.name.replace(/^refs\/(?:heads|remotes)\//, ""), oid: row.oid,
175
- kind: row.name.startsWith("refs/remotes/") ? "remote" : "local", current: row.current === true,
176
- tracking: typeof row.tracking === "string" && row.tracking.startsWith("refs/remotes/") && validRef(row.tracking) ? row.tracking : null,
177
- ahead: Math.max(0, Number(row.ahead) || 0), behind: Math.max(0, Number(row.behind) || 0),
178
- }));
179
- return { repositoryId, branches };
180
- },
181
- async commit(sessionId, repositoryId, oid, { filesCursor, filesLimit = 100 } = {}) {
182
- const authorized = await binding(sessionId, repositoryId);
183
- if (!validOid(oid)) throw failure("invalid-oid", 400);
184
- if (typeof provider.commit !== "function") throw failure("provider-incompatible", 503);
185
- const limit = Math.max(1, Math.min(200, Number(filesLimit) || 100));
186
- prune();
187
- let offset = 0;
188
- if (filesCursor) {
189
- const saved = fileCursors.get(filesCursor);
190
- if (!saved || saved.expiresAt <= now() || saved.sessionId !== sessionId || saved.repositoryId !== repositoryId || saved.oid !== String(oid).toLowerCase()) throw failure("invalid-files-cursor", 400);
191
- offset = saved.offset;
192
- }
193
- const value = await provider.commit(authorized.root, oid);
194
- const allFiles = (Array.isArray(value.files) ? value.files : []).filter((file) => safeFilePath(file?.path) && (file.oldPath == null || safeFilePath(file.oldPath))).map((file) => ({
195
- path: String(file.path ?? ""), ...(typeof file.oldPath === "string" ? { oldPath: file.oldPath } : {}),
196
- status: String(file.status ?? "modified"), binary: file.binary === true,
197
- additions: file.additions == null ? null : Math.max(0, Number(file.additions) || 0),
198
- deletions: file.deletions == null ? null : Math.max(0, Number(file.deletions) || 0),
199
- }));
200
- const items = allFiles.slice(offset, offset + limit);
201
- let nextCursor = null;
202
- if (offset + items.length < allFiles.length) {
203
- nextCursor = randomUUID();
204
- fileCursors.set(nextCursor, { sessionId, repositoryId, oid: value.oid.toLowerCase(), offset: offset + items.length, expiresAt: now() + snapshotTtlMs });
205
- keepBounded(fileCursors, 1024);
206
- }
207
- const stats = allFiles.reduce((sum, file) => ({ additions: sum.additions + (file.additions ?? 0), deletions: sum.deletions + (file.deletions ?? 0), files: sum.files + 1 }), { additions: 0, deletions: 0, files: 0 });
208
- return { repositoryId, oid: String(value.oid ?? ""), parents: Array.isArray(value.parents) ? value.parents.map(String) : [], author: String(value.author ?? ""), timestamp: Number(value.timestamp) || 0, message: String(value.message ?? ""), refs: Array.isArray(value.refs) ? value.refs.map(String) : [], tags: Array.isArray(value.tags) ? value.tags.map(String) : [], stats, files: { items, total: allFiles.length, nextCursor } };
209
- },
210
- async graph(sessionId, repositoryId, { tips, snapshotId, cursor, limit = 100 } = {}) {
211
- const authorized = await binding(sessionId, repositoryId);
212
- prune();
213
- const pageSize = Math.max(1, Math.min(200, Number(limit) || 100));
214
- let snapshot, offset = 0;
215
- if (snapshotId !== undefined || cursor !== undefined) {
216
- if (!snapshotId || !cursor) throw stale();
217
- snapshot = snapshots.get(snapshotId);
218
- if (!snapshot || snapshot.sessionId !== sessionId || snapshot.repositoryId !== repositoryId || snapshot.root !== authorized.root || snapshot.expiresAt <= now()) throw stale();
219
- offset = snapshot.cursors.get(cursor);
220
- if (!Number.isInteger(offset)) throw stale();
221
- } else {
222
- const selected = tips === undefined ? [{ name: "HEAD", tipOid: null }] : tips;
223
- if (!Array.isArray(selected) || selected.length > MAX_GRAPH_TIPS) throw failure("graph-too-many-tips", 400);
224
- if (selected.length === 0) throw failure("graph-tip-invalid", 400);
225
- const names = selected.map((tip) => tip?.name);
226
- if (new Set(names).size !== names.length || names.some((name) => !validRef(name)) || selected.some((tip) => tip?.tipOid != null && !validOid(tip.tipOid))) throw failure("graph-tip-invalid", 400);
227
- const resolved = [];
228
- for (const tip of selected) {
229
- let oid;
230
- try { oid = await provider.resolveTip(authorized.root, tip.name); }
231
- catch (error) {
232
- if (tip.name === "HEAD" && error?.code === "git-command-failed") continue;
233
- throw failure("graph-tip-invalid", 409);
234
- }
235
- if (!validOid(oid)) throw failure("graph-tip-invalid", 409);
236
- if (tip.tipOid != null && tip.tipOid.toLowerCase() !== oid.toLowerCase()) throw failure("graph-tip-invalid", 409);
237
- resolved.push({ name: tip.name, tipOid: oid });
238
- }
239
- snapshot = { id: randomUUID(), sessionId, repositoryId, root: authorized.root, tips: resolved, expiresAt: now() + snapshotTtlMs, cursors: new Map() };
240
- snapshots.set(snapshot.id, snapshot);
241
- keepBounded(snapshots, 128);
242
- }
243
- for (const tip of snapshot.tips) {
244
- let current;
245
- try { current = await provider.resolveTip(authorized.root, tip.name); } catch { throw stale(); }
246
- if (current.toLowerCase() !== tip.tipOid.toLowerCase()) throw stale();
247
- }
248
- let rawCommits;
249
- try { rawCommits = await provider.graph(authorized.root, { refs: snapshot.tips.map((tip) => tip.tipOid), offset, limit: pageSize }); }
250
- catch (error) {
251
- for (const tip of snapshot.tips) {
252
- let current;
253
- try { current = await provider.resolveTip(authorized.root, tip.name); } catch { snapshots.delete(snapshot.id); throw stale(); }
254
- if (current.toLowerCase() !== tip.tipOid.toLowerCase()) { snapshots.delete(snapshot.id); throw stale(); }
255
- }
256
- throw error;
257
- }
258
- for (const tip of snapshot.tips) {
259
- let current;
260
- try { current = await provider.resolveTip(authorized.root, tip.name); } catch { snapshots.delete(snapshot.id); throw stale(); }
261
- if (current.toLowerCase() !== tip.tipOid.toLowerCase()) { snapshots.delete(snapshot.id); throw stale(); }
262
- }
263
- const commits = (Array.isArray(rawCommits) ? rawCommits : []).map((row) => ({
264
- oid: String(row.oid ?? ""), parents: Array.isArray(row.parents) ? row.parents.map(String) : [],
265
- author: String(row.author ?? ""), timestamp: Number(row.timestamp) || 0, subject: String(row.subject ?? ""),
266
- refs: Array.isArray(row.refs) ? row.refs.map(String) : [],
267
- }));
268
- let nextCursor = null;
269
- if (commits.length === pageSize) {
270
- nextCursor = randomUUID();
271
- snapshot.cursors.set(nextCursor, offset + commits.length);
272
- keepBounded(snapshot.cursors, 128);
273
- }
274
- return { repositoryId, snapshotId: snapshot.id, tips: snapshot.tips, commits, nextCursor };
275
- },
276
- async _pollOnce() {
277
- for (const [repositoryId, authorized] of bindings) {
278
- try {
279
- await binding(authorized.sessionId, repositoryId);
280
- if (typeof provider.refSignature === "function") {
281
- const signature = await provider.refSignature(authorized.root);
282
- const previous = refSignatures.get(repositoryId); refSignatures.set(repositoryId, signature);
283
- if (previous !== undefined && previous !== signature) onChanged?.(repositoryId, "refs");
284
- }
285
- } catch { bindings.delete(repositoryId); refSignatures.delete(repositoryId); }
286
- }
287
- },
288
- start() {
289
- if (unsubscribeProvider || pollTimer) return;
290
- if (typeof provider.subscribeChanges === "function") {
291
- try { unsubscribeProvider = provider.subscribeChanges((change) => {
292
- void (async () => {
293
- for (const [repositoryId, authorized] of bindings) {
294
- if (change?.root !== authorized.root) continue;
295
- try {
296
- await binding(authorized.sessionId, repositoryId);
297
- if (typeof provider.refSignature === "function") {
298
- const signature = await provider.refSignature(authorized.root);
299
- const previous = refSignatures.get(repositoryId);
300
- refSignatures.set(repositoryId, signature);
301
- if (previous === signature) continue;
302
- }
303
- onChanged?.(repositoryId);
304
- } catch { bindings.delete(repositoryId); refSignatures.delete(repositoryId); }
305
- }
306
- })();
307
- }); } catch { unsubscribeProvider = null; }
308
- if (typeof unsubscribeProvider !== "function") unsubscribeProvider = null;
309
- }
310
- // Ref polling is server-side; worktree polling stays scoped to an open mobile page.
311
- pollTimer = setInterval(() => { void service._pollOnce(); }, pollIntervalMs);
312
- pollTimer.unref?.();
313
- },
314
- stop() {
315
- if (pollTimer) clearInterval(pollTimer);
316
- pollTimer = null;
317
- try { unsubscribeProvider?.(); } catch { /* optional provider teardown must not break host shutdown */ }
318
- unsubscribeProvider = null;
319
- },
320
- };
321
- return service;
322
- }