git-remote-ops 0.1.0

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 (245) hide show
  1. package/AGENTS.md +177 -0
  2. package/LICENSE +21 -0
  3. package/README.md +247 -0
  4. package/esm/_dnt.shims.js +72 -0
  5. package/esm/cli.js +217 -0
  6. package/esm/client.js +439 -0
  7. package/esm/deps/jsr.io/@cliffy/command/1.1.0/_argument_types.js +1 -0
  8. package/esm/deps/jsr.io/@cliffy/command/1.1.0/_errors.js +133 -0
  9. package/esm/deps/jsr.io/@cliffy/command/1.1.0/_spread.js +1 -0
  10. package/esm/deps/jsr.io/@cliffy/command/1.1.0/_type_utils.js +1 -0
  11. package/esm/deps/jsr.io/@cliffy/command/1.1.0/_utils.js +141 -0
  12. package/esm/deps/jsr.io/@cliffy/command/1.1.0/command.js +1861 -0
  13. package/esm/deps/jsr.io/@cliffy/command/1.1.0/help/_help_generator.js +357 -0
  14. package/esm/deps/jsr.io/@cliffy/command/1.1.0/mod.js +13 -0
  15. package/esm/deps/jsr.io/@cliffy/command/1.1.0/type.js +27 -0
  16. package/esm/deps/jsr.io/@cliffy/command/1.1.0/types/action_list.js +16 -0
  17. package/esm/deps/jsr.io/@cliffy/command/1.1.0/types/boolean.js +13 -0
  18. package/esm/deps/jsr.io/@cliffy/command/1.1.0/types/child_command.js +14 -0
  19. package/esm/deps/jsr.io/@cliffy/command/1.1.0/types/command.js +9 -0
  20. package/esm/deps/jsr.io/@cliffy/command/1.1.0/types/enum.js +24 -0
  21. package/esm/deps/jsr.io/@cliffy/command/1.1.0/types/file.js +12 -0
  22. package/esm/deps/jsr.io/@cliffy/command/1.1.0/types/integer.js +9 -0
  23. package/esm/deps/jsr.io/@cliffy/command/1.1.0/types/number.js +9 -0
  24. package/esm/deps/jsr.io/@cliffy/command/1.1.0/types/secret.js +7 -0
  25. package/esm/deps/jsr.io/@cliffy/command/1.1.0/types/string.js +9 -0
  26. package/esm/deps/jsr.io/@cliffy/command/1.1.0/types.js +2 -0
  27. package/esm/deps/jsr.io/@cliffy/command/1.1.0/upgrade/_check_version.js +26 -0
  28. package/esm/deps/jsr.io/@cliffy/flags/1.1.0/_errors.js +129 -0
  29. package/esm/deps/jsr.io/@cliffy/flags/1.1.0/_utils.js +100 -0
  30. package/esm/deps/jsr.io/@cliffy/flags/1.1.0/_validate_flags.js +166 -0
  31. package/esm/deps/jsr.io/@cliffy/flags/1.1.0/flags.js +750 -0
  32. package/esm/deps/jsr.io/@cliffy/flags/1.1.0/mod.js +55 -0
  33. package/esm/deps/jsr.io/@cliffy/flags/1.1.0/types/boolean.js +11 -0
  34. package/esm/deps/jsr.io/@cliffy/flags/1.1.0/types/integer.js +9 -0
  35. package/esm/deps/jsr.io/@cliffy/flags/1.1.0/types/number.js +11 -0
  36. package/esm/deps/jsr.io/@cliffy/flags/1.1.0/types/string.js +4 -0
  37. package/esm/deps/jsr.io/@cliffy/flags/1.1.0/types.js +1 -0
  38. package/esm/deps/jsr.io/@cliffy/internal/1.1.0/runtime/exit.js +16 -0
  39. package/esm/deps/jsr.io/@cliffy/internal/1.1.0/runtime/get_args.js +11 -0
  40. package/esm/deps/jsr.io/@cliffy/internal/1.1.0/runtime/get_columns.js +25 -0
  41. package/esm/deps/jsr.io/@cliffy/internal/1.1.0/runtime/get_env.js +18 -0
  42. package/esm/deps/jsr.io/@cliffy/internal/1.1.0/runtime/inspect.js +11 -0
  43. package/esm/deps/jsr.io/@cliffy/table/1.1.0/_layout.js +616 -0
  44. package/esm/deps/jsr.io/@cliffy/table/1.1.0/_utils.js +79 -0
  45. package/esm/deps/jsr.io/@cliffy/table/1.1.0/border.js +18 -0
  46. package/esm/deps/jsr.io/@cliffy/table/1.1.0/cell.js +190 -0
  47. package/esm/deps/jsr.io/@cliffy/table/1.1.0/column.js +117 -0
  48. package/esm/deps/jsr.io/@cliffy/table/1.1.0/consume_words.js +64 -0
  49. package/esm/deps/jsr.io/@cliffy/table/1.1.0/mod.js +42 -0
  50. package/esm/deps/jsr.io/@cliffy/table/1.1.0/row.js +82 -0
  51. package/esm/deps/jsr.io/@cliffy/table/1.1.0/table.js +341 -0
  52. package/esm/deps/jsr.io/@cliffy/table/1.1.0/unicode_width.js +101 -0
  53. package/esm/deps/jsr.io/@std/crypto/1.1.0/_types.js +2 -0
  54. package/esm/deps/jsr.io/@std/crypto/1.1.0/_wasm/lib/deno_std_wasm_crypto.internal.js +237 -0
  55. package/esm/deps/jsr.io/@std/crypto/1.1.0/_wasm/lib/deno_std_wasm_crypto.js +2277 -0
  56. package/esm/deps/jsr.io/@std/crypto/1.1.0/_wasm/mod.js +46 -0
  57. package/esm/deps/jsr.io/@std/crypto/1.1.0/aes_gcm.js +132 -0
  58. package/esm/deps/jsr.io/@std/crypto/1.1.0/crypto.js +270 -0
  59. package/esm/deps/jsr.io/@std/crypto/1.1.0/mod.js +23 -0
  60. package/esm/deps/jsr.io/@std/crypto/1.1.0/timing_safe_equal.js +61 -0
  61. package/esm/deps/jsr.io/@std/encoding/1.0.10/_common16.js +51 -0
  62. package/esm/deps/jsr.io/@std/encoding/1.0.10/_common_detach.js +13 -0
  63. package/esm/deps/jsr.io/@std/encoding/1.0.10/_types.js +2 -0
  64. package/esm/deps/jsr.io/@std/encoding/1.0.10/hex.js +87 -0
  65. package/esm/deps/jsr.io/@std/fmt/1.0.10/colors.js +903 -0
  66. package/esm/deps/jsr.io/@std/text/1.0.18/closest_string.js +46 -0
  67. package/esm/deps/jsr.io/@std/text/1.0.18/levenshtein_distance.js +127 -0
  68. package/esm/errors.js +38 -0
  69. package/esm/index.js +10 -0
  70. package/esm/logger.js +216 -0
  71. package/esm/objects/commit.js +47 -0
  72. package/esm/objects/index.js +2 -0
  73. package/esm/objects/tree.js +149 -0
  74. package/esm/pack/delta.js +179 -0
  75. package/esm/pack/index.js +3 -0
  76. package/esm/pack/objects.js +72 -0
  77. package/esm/pack/parser.js +304 -0
  78. package/esm/package.json +3 -0
  79. package/esm/protocol/index.js +3 -0
  80. package/esm/protocol/pkt_line.js +103 -0
  81. package/esm/protocol/refs.js +100 -0
  82. package/esm/protocol/upload_pack.js +259 -0
  83. package/esm/transport.js +128 -0
  84. package/esm/types.js +8 -0
  85. package/package.json +50 -0
  86. package/types/_dnt.shims.d.ts +16 -0
  87. package/types/_dnt.shims.d.ts.map +1 -0
  88. package/types/cli.d.ts +3 -0
  89. package/types/cli.d.ts.map +1 -0
  90. package/types/client.d.ts +108 -0
  91. package/types/client.d.ts.map +1 -0
  92. package/types/deps/jsr.io/@cliffy/command/1.1.0/_argument_types.d.ts +163 -0
  93. package/types/deps/jsr.io/@cliffy/command/1.1.0/_argument_types.d.ts.map +1 -0
  94. package/types/deps/jsr.io/@cliffy/command/1.1.0/_errors.d.ts +71 -0
  95. package/types/deps/jsr.io/@cliffy/command/1.1.0/_errors.d.ts.map +1 -0
  96. package/types/deps/jsr.io/@cliffy/command/1.1.0/_spread.d.ts +16 -0
  97. package/types/deps/jsr.io/@cliffy/command/1.1.0/_spread.d.ts.map +1 -0
  98. package/types/deps/jsr.io/@cliffy/command/1.1.0/_type_utils.d.ts +15 -0
  99. package/types/deps/jsr.io/@cliffy/command/1.1.0/_type_utils.d.ts.map +1 -0
  100. package/types/deps/jsr.io/@cliffy/command/1.1.0/_utils.d.ts +38 -0
  101. package/types/deps/jsr.io/@cliffy/command/1.1.0/_utils.d.ts.map +1 -0
  102. package/types/deps/jsr.io/@cliffy/command/1.1.0/command.d.ts +1086 -0
  103. package/types/deps/jsr.io/@cliffy/command/1.1.0/command.d.ts.map +1 -0
  104. package/types/deps/jsr.io/@cliffy/command/1.1.0/help/_help_generator.d.ts +33 -0
  105. package/types/deps/jsr.io/@cliffy/command/1.1.0/help/_help_generator.d.ts.map +1 -0
  106. package/types/deps/jsr.io/@cliffy/command/1.1.0/mod.d.ts +78 -0
  107. package/types/deps/jsr.io/@cliffy/command/1.1.0/mod.d.ts.map +1 -0
  108. package/types/deps/jsr.io/@cliffy/command/1.1.0/type.d.ts +51 -0
  109. package/types/deps/jsr.io/@cliffy/command/1.1.0/type.d.ts.map +1 -0
  110. package/types/deps/jsr.io/@cliffy/command/1.1.0/types/action_list.d.ts +10 -0
  111. package/types/deps/jsr.io/@cliffy/command/1.1.0/types/action_list.d.ts.map +1 -0
  112. package/types/deps/jsr.io/@cliffy/command/1.1.0/types/boolean.d.ts +10 -0
  113. package/types/deps/jsr.io/@cliffy/command/1.1.0/types/boolean.d.ts.map +1 -0
  114. package/types/deps/jsr.io/@cliffy/command/1.1.0/types/child_command.d.ts +10 -0
  115. package/types/deps/jsr.io/@cliffy/command/1.1.0/types/child_command.d.ts.map +1 -0
  116. package/types/deps/jsr.io/@cliffy/command/1.1.0/types/command.d.ts +8 -0
  117. package/types/deps/jsr.io/@cliffy/command/1.1.0/types/command.d.ts.map +1 -0
  118. package/types/deps/jsr.io/@cliffy/command/1.1.0/types/enum.d.ts +11 -0
  119. package/types/deps/jsr.io/@cliffy/command/1.1.0/types/enum.d.ts.map +1 -0
  120. package/types/deps/jsr.io/@cliffy/command/1.1.0/types/file.d.ts +6 -0
  121. package/types/deps/jsr.io/@cliffy/command/1.1.0/types/file.d.ts.map +1 -0
  122. package/types/deps/jsr.io/@cliffy/command/1.1.0/types/integer.d.ts +8 -0
  123. package/types/deps/jsr.io/@cliffy/command/1.1.0/types/integer.d.ts.map +1 -0
  124. package/types/deps/jsr.io/@cliffy/command/1.1.0/types/number.d.ts +8 -0
  125. package/types/deps/jsr.io/@cliffy/command/1.1.0/types/number.d.ts.map +1 -0
  126. package/types/deps/jsr.io/@cliffy/command/1.1.0/types/secret.d.ts +6 -0
  127. package/types/deps/jsr.io/@cliffy/command/1.1.0/types/secret.d.ts.map +1 -0
  128. package/types/deps/jsr.io/@cliffy/command/1.1.0/types/string.d.ts +8 -0
  129. package/types/deps/jsr.io/@cliffy/command/1.1.0/types/string.d.ts.map +1 -0
  130. package/types/deps/jsr.io/@cliffy/command/1.1.0/types.d.ts +161 -0
  131. package/types/deps/jsr.io/@cliffy/command/1.1.0/types.d.ts.map +1 -0
  132. package/types/deps/jsr.io/@cliffy/command/1.1.0/upgrade/_check_version.d.ts +4 -0
  133. package/types/deps/jsr.io/@cliffy/command/1.1.0/upgrade/_check_version.d.ts.map +1 -0
  134. package/types/deps/jsr.io/@cliffy/flags/1.1.0/_errors.d.ts +67 -0
  135. package/types/deps/jsr.io/@cliffy/flags/1.1.0/_errors.d.ts.map +1 -0
  136. package/types/deps/jsr.io/@cliffy/flags/1.1.0/_utils.d.ts +17 -0
  137. package/types/deps/jsr.io/@cliffy/flags/1.1.0/_utils.d.ts.map +1 -0
  138. package/types/deps/jsr.io/@cliffy/flags/1.1.0/_validate_flags.d.ts +11 -0
  139. package/types/deps/jsr.io/@cliffy/flags/1.1.0/_validate_flags.d.ts.map +1 -0
  140. package/types/deps/jsr.io/@cliffy/flags/1.1.0/flags.d.ts +154 -0
  141. package/types/deps/jsr.io/@cliffy/flags/1.1.0/flags.d.ts.map +1 -0
  142. package/types/deps/jsr.io/@cliffy/flags/1.1.0/mod.d.ts +57 -0
  143. package/types/deps/jsr.io/@cliffy/flags/1.1.0/mod.d.ts.map +1 -0
  144. package/types/deps/jsr.io/@cliffy/flags/1.1.0/types/boolean.d.ts +4 -0
  145. package/types/deps/jsr.io/@cliffy/flags/1.1.0/types/boolean.d.ts.map +1 -0
  146. package/types/deps/jsr.io/@cliffy/flags/1.1.0/types/integer.d.ts +4 -0
  147. package/types/deps/jsr.io/@cliffy/flags/1.1.0/types/integer.d.ts.map +1 -0
  148. package/types/deps/jsr.io/@cliffy/flags/1.1.0/types/number.d.ts +4 -0
  149. package/types/deps/jsr.io/@cliffy/flags/1.1.0/types/number.d.ts.map +1 -0
  150. package/types/deps/jsr.io/@cliffy/flags/1.1.0/types/string.d.ts +4 -0
  151. package/types/deps/jsr.io/@cliffy/flags/1.1.0/types/string.d.ts.map +1 -0
  152. package/types/deps/jsr.io/@cliffy/flags/1.1.0/types.d.ts +170 -0
  153. package/types/deps/jsr.io/@cliffy/flags/1.1.0/types.d.ts.map +1 -0
  154. package/types/deps/jsr.io/@cliffy/internal/1.1.0/runtime/exit.d.ts +8 -0
  155. package/types/deps/jsr.io/@cliffy/internal/1.1.0/runtime/exit.d.ts.map +1 -0
  156. package/types/deps/jsr.io/@cliffy/internal/1.1.0/runtime/get_args.d.ts +7 -0
  157. package/types/deps/jsr.io/@cliffy/internal/1.1.0/runtime/get_args.d.ts.map +1 -0
  158. package/types/deps/jsr.io/@cliffy/internal/1.1.0/runtime/get_columns.d.ts +7 -0
  159. package/types/deps/jsr.io/@cliffy/internal/1.1.0/runtime/get_columns.d.ts.map +1 -0
  160. package/types/deps/jsr.io/@cliffy/internal/1.1.0/runtime/get_env.d.ts +8 -0
  161. package/types/deps/jsr.io/@cliffy/internal/1.1.0/runtime/get_env.d.ts.map +1 -0
  162. package/types/deps/jsr.io/@cliffy/internal/1.1.0/runtime/inspect.d.ts +7 -0
  163. package/types/deps/jsr.io/@cliffy/internal/1.1.0/runtime/inspect.d.ts.map +1 -0
  164. package/types/deps/jsr.io/@cliffy/table/1.1.0/_layout.d.ts +108 -0
  165. package/types/deps/jsr.io/@cliffy/table/1.1.0/_layout.d.ts.map +1 -0
  166. package/types/deps/jsr.io/@cliffy/table/1.1.0/_utils.d.ts +26 -0
  167. package/types/deps/jsr.io/@cliffy/table/1.1.0/_utils.d.ts.map +1 -0
  168. package/types/deps/jsr.io/@cliffy/table/1.1.0/border.d.ts +21 -0
  169. package/types/deps/jsr.io/@cliffy/table/1.1.0/border.d.ts.map +1 -0
  170. package/types/deps/jsr.io/@cliffy/table/1.1.0/cell.d.ts +155 -0
  171. package/types/deps/jsr.io/@cliffy/table/1.1.0/cell.d.ts.map +1 -0
  172. package/types/deps/jsr.io/@cliffy/table/1.1.0/column.d.ts +97 -0
  173. package/types/deps/jsr.io/@cliffy/table/1.1.0/column.d.ts.map +1 -0
  174. package/types/deps/jsr.io/@cliffy/table/1.1.0/consume_words.d.ts +30 -0
  175. package/types/deps/jsr.io/@cliffy/table/1.1.0/consume_words.d.ts.map +1 -0
  176. package/types/deps/jsr.io/@cliffy/table/1.1.0/mod.d.ts +43 -0
  177. package/types/deps/jsr.io/@cliffy/table/1.1.0/mod.d.ts.map +1 -0
  178. package/types/deps/jsr.io/@cliffy/table/1.1.0/row.d.ts +67 -0
  179. package/types/deps/jsr.io/@cliffy/table/1.1.0/row.d.ts.map +1 -0
  180. package/types/deps/jsr.io/@cliffy/table/1.1.0/table.d.ts +235 -0
  181. package/types/deps/jsr.io/@cliffy/table/1.1.0/table.d.ts.map +1 -0
  182. package/types/deps/jsr.io/@cliffy/table/1.1.0/unicode_width.d.ts +40 -0
  183. package/types/deps/jsr.io/@cliffy/table/1.1.0/unicode_width.d.ts.map +1 -0
  184. package/types/deps/jsr.io/@std/crypto/1.1.0/_types.d.ts +9 -0
  185. package/types/deps/jsr.io/@std/crypto/1.1.0/_types.d.ts.map +1 -0
  186. package/types/deps/jsr.io/@std/crypto/1.1.0/_wasm/lib/deno_std_wasm_crypto.d.ts +2 -0
  187. package/types/deps/jsr.io/@std/crypto/1.1.0/_wasm/lib/deno_std_wasm_crypto.d.ts.map +1 -0
  188. package/types/deps/jsr.io/@std/crypto/1.1.0/_wasm/lib/deno_std_wasm_crypto.internal.d.ts +69 -0
  189. package/types/deps/jsr.io/@std/crypto/1.1.0/_wasm/lib/deno_std_wasm_crypto.internal.d.ts.map +1 -0
  190. package/types/deps/jsr.io/@std/crypto/1.1.0/_wasm/mod.d.ts +13 -0
  191. package/types/deps/jsr.io/@std/crypto/1.1.0/_wasm/mod.d.ts.map +1 -0
  192. package/types/deps/jsr.io/@std/crypto/1.1.0/aes_gcm.d.ts +76 -0
  193. package/types/deps/jsr.io/@std/crypto/1.1.0/aes_gcm.d.ts.map +1 -0
  194. package/types/deps/jsr.io/@std/crypto/1.1.0/crypto.d.ts +149 -0
  195. package/types/deps/jsr.io/@std/crypto/1.1.0/crypto.d.ts.map +1 -0
  196. package/types/deps/jsr.io/@std/crypto/1.1.0/mod.d.ts +22 -0
  197. package/types/deps/jsr.io/@std/crypto/1.1.0/mod.d.ts.map +1 -0
  198. package/types/deps/jsr.io/@std/crypto/1.1.0/timing_safe_equal.d.ts +40 -0
  199. package/types/deps/jsr.io/@std/crypto/1.1.0/timing_safe_equal.d.ts.map +1 -0
  200. package/types/deps/jsr.io/@std/encoding/1.0.10/_common16.d.ts +23 -0
  201. package/types/deps/jsr.io/@std/encoding/1.0.10/_common16.d.ts.map +1 -0
  202. package/types/deps/jsr.io/@std/encoding/1.0.10/_common_detach.d.ts +4 -0
  203. package/types/deps/jsr.io/@std/encoding/1.0.10/_common_detach.d.ts.map +1 -0
  204. package/types/deps/jsr.io/@std/encoding/1.0.10/_types.d.ts +9 -0
  205. package/types/deps/jsr.io/@std/encoding/1.0.10/_types.d.ts.map +1 -0
  206. package/types/deps/jsr.io/@std/encoding/1.0.10/hex.d.ts +39 -0
  207. package/types/deps/jsr.io/@std/encoding/1.0.10/hex.d.ts.map +1 -0
  208. package/types/deps/jsr.io/@std/fmt/1.0.10/colors.d.ts +700 -0
  209. package/types/deps/jsr.io/@std/fmt/1.0.10/colors.d.ts.map +1 -0
  210. package/types/deps/jsr.io/@std/text/1.0.18/closest_string.d.ts +42 -0
  211. package/types/deps/jsr.io/@std/text/1.0.18/closest_string.d.ts.map +1 -0
  212. package/types/deps/jsr.io/@std/text/1.0.18/levenshtein_distance.d.ts +23 -0
  213. package/types/deps/jsr.io/@std/text/1.0.18/levenshtein_distance.d.ts.map +1 -0
  214. package/types/errors.d.ts +73 -0
  215. package/types/errors.d.ts.map +1 -0
  216. package/types/index.d.ts +14 -0
  217. package/types/index.d.ts.map +1 -0
  218. package/types/logger.d.ts +70 -0
  219. package/types/logger.d.ts.map +1 -0
  220. package/types/objects/commit.d.ts +23 -0
  221. package/types/objects/commit.d.ts.map +1 -0
  222. package/types/objects/index.d.ts +3 -0
  223. package/types/objects/index.d.ts.map +1 -0
  224. package/types/objects/tree.d.ts +49 -0
  225. package/types/objects/tree.d.ts.map +1 -0
  226. package/types/pack/delta.d.ts +47 -0
  227. package/types/pack/delta.d.ts.map +1 -0
  228. package/types/pack/index.d.ts +4 -0
  229. package/types/pack/index.d.ts.map +1 -0
  230. package/types/pack/objects.d.ts +53 -0
  231. package/types/pack/objects.d.ts.map +1 -0
  232. package/types/pack/parser.d.ts +61 -0
  233. package/types/pack/parser.d.ts.map +1 -0
  234. package/types/protocol/index.d.ts +4 -0
  235. package/types/protocol/index.d.ts.map +1 -0
  236. package/types/protocol/pkt_line.d.ts +44 -0
  237. package/types/protocol/pkt_line.d.ts.map +1 -0
  238. package/types/protocol/refs.d.ts +40 -0
  239. package/types/protocol/refs.d.ts.map +1 -0
  240. package/types/protocol/upload_pack.d.ts +45 -0
  241. package/types/protocol/upload_pack.d.ts.map +1 -0
  242. package/types/transport.d.ts +24 -0
  243. package/types/transport.d.ts.map +1 -0
  244. package/types/types.d.ts +121 -0
  245. package/types/types.d.ts.map +1 -0
package/AGENTS.md ADDED
@@ -0,0 +1,177 @@
1
+ # AGENTS.md
2
+
3
+ Consumer-facing orientation for coding agents working **with** `git-remote-ops`. For
4
+ contributor-internal lore (parser invariants, harness boot), see `docs/`.
5
+
6
+ ## What this library is
7
+
8
+ Read-only Git client over smart HTTP. No `.git` dir, no subprocess, no working tree. Fetches one
9
+ commit / one tree / one blob from a remote and hands back decoded bytes.
10
+
11
+ ## What it is NOT
12
+
13
+ - Not a `git` replacement. No push, no working tree, no ref writes, no merges.
14
+ - Not a clone manager. No `have` negotiation, no incremental sync — every fetch is from-scratch with
15
+ `done`.
16
+ - Not streaming. Packs are held in memory in full.
17
+
18
+ If consumer needs writes or full clones, shell out to `git` instead.
19
+
20
+ ## Install
21
+
22
+ ```ts
23
+ import { RemoteGit } from "jsr:@local/git-remote-ops";
24
+ ```
25
+
26
+ Deno only. Requires `--allow-net`.
27
+
28
+ CLI:
29
+
30
+ ```sh
31
+ deno install --global -A -n git-remote-ops src/cli.ts
32
+ ```
33
+
34
+ ## Core API
35
+
36
+ One class. All methods async. All return `Result<T, GitRemoteOpsError>` from
37
+ [`better-result`](https://jsr.io/@local/better-result) — never throw.
38
+
39
+ ```ts
40
+ const client = new RemoteGit(url, { logger? , diagnostic? });
41
+
42
+ await client.discover(); // -> ServerProfile
43
+ await client.probe(verbose?); // -> ServerProfile (filter probe)
44
+ await client.lsRefs(); // -> Map<refName, sha>
45
+ await client.resolveRef(ref); // -> sha
46
+ await client.fetchCommit(ref, { depth?, filter?, parseFull? });
47
+ await client.fetchBlob(sha);
48
+ await client.fetchTree(sha);
49
+ await client.fetchTreeForCommit(ref, opts);
50
+ client.getObject(sha); // cache lookup, no network
51
+ ```
52
+
53
+ ## Result handling
54
+
55
+ ```ts
56
+ const r = await client.fetchBlob(sha);
57
+ if (r.isErr()) {
58
+ // narrow on _tag
59
+ if (r.error._tag === "TransportError") console.error(r.error.status);
60
+ return;
61
+ }
62
+ const bytes = r.value;
63
+ ```
64
+
65
+ Error tags: `PackParseError`, `ObjectDecodeError`, `PktLineError`, `UploadPackError`,
66
+ `TransportError`, `RefNotFoundError`, `ObjectNotFoundError`, `PathNotFoundError`. Union =
67
+ `GitRemoteOpsError`.
68
+
69
+ Never `try/catch` for control flow — these calls don't throw. Wrap user code that calls `.unwrap()`
70
+ if you want exceptions.
71
+
72
+ ## Caching behaviour consumers should know
73
+
74
+ One `RemoteGit` instance keeps:
75
+
76
+ - One `ServerProfile` — populated on first call, reused after.
77
+ - All materialized objects in a `Map<sha, GitObject>`, **process-lifetime**.
78
+
79
+ Implications:
80
+
81
+ - Reuse instances across calls — commit → tree → blob dedupes `want`s.
82
+ - Don't hold an instance forever in long-running processes if memory matters. Throw it away when
83
+ done with that remote.
84
+ - Concurrent calls on one instance share the cache; no internal locking.
85
+
86
+ ## Choosing options
87
+
88
+ | Goal | Recipe |
89
+ | --------------------------- | ----------------------------------------------------------------------------- |
90
+ | One commit's metadata | `fetchCommit(ref, { depth: 1, filter: "blob:none" })` |
91
+ | List files at snapshot | `fetchTreeForCommit(ref, { depth: 1, filter: "blob:none", parseFull: true })` |
92
+ | One known blob | `fetchBlob(sha)` (no profile probe needed) |
93
+ | Path → blob without network | `resolvePathToBlob` from `objects/tree.ts` against `client` object cache |
94
+
95
+ `depth: 1` + `filter: "blob:none"` is the cheap default. Both gracefully degrade if server doesn't
96
+ advertise the capability — depth drops, filter logs at info and proceeds.
97
+
98
+ ## Logging
99
+
100
+ Library silent unless told otherwise.
101
+
102
+ ```ts
103
+ import { Logger } from "jsr:@local/git-remote-ops";
104
+
105
+ const logger = new Logger({ level: "debug" });
106
+ const client = new RemoteGit(url, { logger });
107
+ // ...
108
+ console.error(logger.summary()); // metrics table
109
+ ```
110
+
111
+ Levels: `silent` < `info` < `debug` < `trace`. Metrics roll up across child loggers automatically.
112
+
113
+ ## CLI surface
114
+
115
+ ```text
116
+ git-remote-ops probe <url>
117
+ git-remote-ops ls-refs <url>
118
+ git-remote-ops cat-commit <url> [--ref HEAD] [--depth N] [--filter SPEC | --no-filter]
119
+ git-remote-ops cat-tree <url> [--ref HEAD] [--depth N] [--filter SPEC | --no-filter]
120
+ [--tree-sha SHA]
121
+ git-remote-ops list-files <url> [--ref HEAD] [--depth N] [--filter SPEC | --no-filter]
122
+ [--details]
123
+ git-remote-ops cat-blob <url> <blob-sha>
124
+
125
+ Global: -q | -v | --debug | --stats
126
+ ```
127
+
128
+ Stdout = data. Stderr = logs + errors. Exit 1 on any `Result.err`.
129
+
130
+ Full reference: `docs/cli.md`.
131
+
132
+ ## Common pitfalls
133
+
134
+ **Calling `fetchTree(commit.tree)` after `fetchCommit(ref)` with default options.** Default
135
+ `parseFull: false` only materializes the commit itself. Use `fetchTreeForCommit` or pass
136
+ `{ parseFull: true }` to `fetchCommit`.
137
+
138
+ **Expecting full history.** `depth: 1` (the CLI default) gives one commit. Drop depth for full
139
+ history; expect a much larger pack.
140
+
141
+ **Treating `RefNotFoundError` as fatal.** A 40-char hex sha is accepted even when not in the ad —
142
+ try direct sha if your ref is unusual.
143
+
144
+ **Confusing `getObject` with a fetch.** `getObject` only checks the cache. Returns `undefined` if
145
+ not yet materialized. No network call.
146
+
147
+ **Throwing away the client between calls.** Re-discovers, re-probes, re-fetches the same objects.
148
+ Reuse it.
149
+
150
+ ## Where to look in source
151
+
152
+ | Concern | File |
153
+ | ---------------------- | ----------------------------- |
154
+ | Public API | `src/client.ts` |
155
+ | Types | `src/types.ts` |
156
+ | Errors | `src/errors.ts` |
157
+ | Logging / metrics | `src/logger.ts` |
158
+ | HTTP | `src/transport.ts` |
159
+ | Wire framing | `src/protocol/pkt_line.ts` |
160
+ | Ref / capability parse | `src/protocol/refs.ts` |
161
+ | Fetch req + sideband | `src/protocol/upload_pack.ts` |
162
+ | Packfile decode | `src/pack/parser.ts` |
163
+ | Delta application | `src/pack/delta.ts` |
164
+ | Pack constants + hash | `src/pack/objects.ts` |
165
+ | Commit decode | `src/objects/commit.ts` |
166
+ | Tree decode / walk | `src/objects/tree.ts` |
167
+ | CLI | `src/cli.ts` |
168
+
169
+ Every file carries a module-level JSDoc banner with intent. Every constant documented inline.
170
+
171
+ ## Versioning
172
+
173
+ Pre-1.0. API may shift. Pin exact version in `deno.json` imports.
174
+
175
+ ## License
176
+
177
+ See `LICENSE`.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Goulin Khoge
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,247 @@
1
+ # git-remote-ops
2
+
3
+ **Read-only Git over smart HTTP, without `git`.** A single Deno/TypeScript process speaks the same
4
+ wire protocol that `git fetch` does, then materializes the parts you actually want — one commit, one
5
+ tree, one file — straight into memory.
6
+
7
+ No `.git` directory. No subprocess. No filesystem state to clean up.
8
+
9
+ ```bash
10
+ deno run --allow-net jsr:@local/git-remote-ops/cli \
11
+ cat-blob https://github.com/torvalds/linux.git \
12
+ e8c39d0f… > Makefile
13
+ ```
14
+
15
+ The blob lands in `Makefile`. The local working set never grows past a few KB of cached pack
16
+ metadata.
17
+
18
+ ## Why bother
19
+
20
+ A surprising amount of production code shells out to `git` just to read a file. That works, but it
21
+ forces a clone — every byte of every revision of every path — to retrieve one revision of one path.
22
+ On a large monorepo the clone is the entire latency budget.
23
+
24
+ The Git smart-HTTP protocol has supported targeted fetches for years. With shallow depth
25
+ (`--depth=1`) and partial-clone filters (`--filter=blob:none`, `--filter=tree:0`) you can ask the
26
+ server for _just the snapshot you care about_, often a few hundred kilobytes total. Mainline `git`
27
+ exposes this, but to use it you still need an on-disk clone and a forked process.
28
+
29
+ `git-remote-ops` is the thin client you'd write if you only ever did this one thing: a few hundred
30
+ lines of TypeScript that build the same `want`/`done` request `git` would, parse the packfile that
31
+ comes back, and hand you the decoded objects.
32
+
33
+ ## What's in the box
34
+
35
+ Six subcommands, all read-only:
36
+
37
+ | Command | Does |
38
+ | ------------ | ------------------------------------------------------------- |
39
+ | `probe` | Capability sniff: protocol version, shallow, filter dialects. |
40
+ | `ls-refs` | List advertised refs as `<sha> <name>`. |
41
+ | `cat-commit` | Fetch + decode a commit object. |
42
+ | `cat-tree` | Fetch + decode a root tree (or a specific tree by sha). |
43
+ | `list-files` | Walk a snapshot and emit every path. |
44
+ | `cat-blob` | Stream one blob's raw bytes to stdout. |
45
+
46
+ And the same operations are available as a library:
47
+
48
+ ```typescript
49
+ import { RemoteGit } from "jsr:@local/git-remote-ops";
50
+
51
+ const client = new RemoteGit("https://github.com/owner/repo.git");
52
+ const { sha, commit } = (await client.fetchCommit("HEAD")).unwrap();
53
+ const tree = (await client.fetchTree(commit.tree)).unwrap();
54
+ const blob = (await client.fetchBlob(tree[0].sha)).unwrap();
55
+ ```
56
+
57
+ Every public call returns a `Result<T, GitRemoteOpsError>` from
58
+ [`better-result`](https://jsr.io/@local/better-result) — never throws.
59
+
60
+ ## How it works
61
+
62
+ The work splits into four layers, and the codebase mirrors that split.
63
+
64
+ ```
65
+ ┌──────────────────────────┐
66
+ src/client.ts ─→ │ RemoteGit (public API) │
67
+ └────────────┬─────────────┘
68
+
69
+ ┌────────────────────────┼───────────────────────┐
70
+ ▼ ▼ ▼
71
+ src/protocol/ src/pack/ src/objects/
72
+ pkt-line, refs, pack parser, delta, commit + tree
73
+ upload-pack zlib bridge decoders
74
+ │ ▲
75
+ ▼ │
76
+ src/transport.ts ─────────────┘
77
+ (fetch wrappers)
78
+ ```
79
+
80
+ ### 1. Transport — `src/transport.ts`
81
+
82
+ Two `fetch` calls do all the network work:
83
+
84
+ 1. `GET /info/refs?service=git-upload-pack` — the ref advertisement.
85
+ 2. `POST /git-upload-pack` — the actual fetch, body framed below.
86
+
87
+ Both helpers thread an optional `Logger` so byte counts and durations roll into the same metrics
88
+ struct the CLI's `--stats` flag prints.
89
+
90
+ ### 2. Protocol — `src/protocol/`
91
+
92
+ **pkt-line framing.** Everything Git sends over HTTP is wrapped in a 4-byte ASCII-hex length prefix.
93
+ Length `0000` is a flush; `0001` and `0002` are v2 control packets. `parsePktLines` walks a buffer
94
+ end-to-end, returning subarray views — no payload bytes are copied. Trailing `\n`s are preserved
95
+ because some callers care.
96
+
97
+ **Ref advertisement.** v0/v1 puts capabilities NUL-separated on the first ref line; v2 puts them on
98
+ standalone pkt-lines after `version 2`. We parse both, merge the capability sets, and prefer v2 when
99
+ both are advertised.
100
+
101
+ **`git-upload-pack` request.** A `want <sha>` line per object, an optional `deepen <n>` for shallow,
102
+ an optional `filter <spec>` for partial-clone, a flush, then `done`. The v2 encoder adds a
103
+ `command=fetch` header section and turns capabilities into separate argument lines instead of riding
104
+ the first `want`.
105
+
106
+ **Sideband demux.** The response is itself a stream of pkt-lines; each data line starts with a
107
+ channel byte. Channel 1 is the packfile, channel 2 is human-readable progress, channel 3 is fatal
108
+ stderr. `extractPack` looks at the first real data line, picks the right strategy (raw `PACK`
109
+ signature, sideband, or PACK-search fallback), and returns the concatenated channel-1 bytes.
110
+
111
+ ### 3. Packfile — `src/pack/`
112
+
113
+ A packfile is `PACK` + version + count + N variable-length object entries + a trailing SHA-1. Each
114
+ entry has a type/size header (a varint with a 3-bit type field jammed into the first byte) followed
115
+ by a zlib-compressed body.
116
+
117
+ The parser walks entries in order. For non-delta types it inflates and hashes the body in one shot.
118
+ For deltas — two flavours, `OBJ_OFS_DELTA` (base referenced by negative byte offset) and
119
+ `OBJ_REF_DELTA` (base referenced by 20-byte sha) — it applies the delta against the resolved base
120
+ and re-hashes the reconstructed object.
121
+
122
+ Two implementation notes worth flagging:
123
+
124
+ **zlib boundaries.** Multiple deflate streams sit back-to-back inside the pack with no length
125
+ prefix. The streaming API doesn't tell you how many input bytes a single decode consumed, so we
126
+ reach into `node:zlib`'s `_processChunk` and read `bytesWritten` to advance the cursor. It's an
127
+ implementation detail of Node's zlib binding, but it's a stable one, and the alternative is parsing
128
+ deflate headers ourselves.
129
+
130
+ **Targeted bailout.** If you only need a single commit, the parser accepts a `targets` set and
131
+ returns as soon as those shas are materialized — even mid-pack. On a large snapshot pack that's the
132
+ difference between parsing five megabytes of objects and parsing fifty kilobytes.
133
+
134
+ **Delta application.** The delta stream is a tiny opcode language: "copy `n` bytes from base at
135
+ offset `o`" or "insert these `n` literal bytes". A size of zero on a copy opcode means 64 KiB.
136
+ Out-of-bounds copies become typed errors, never silent corruption.
137
+
138
+ ### 4. Objects — `src/objects/`
139
+
140
+ Commit and tree decoders. Both inputs are the _uncompressed_ bodies produced by layer 3; neither
141
+ parser cares how the bytes got there.
142
+
143
+ A tree is `<mode> <name>\0<sha20>` repeated, with no length prefix. A commit is RFC822-ish headers +
144
+ blank line + free-form message; we keep `tree`, first `parent`, `author`, `committer`. Multiple
145
+ `parent` lines (merge commits) collapse to the first because this client only walks toward snapshots
146
+ — never along history.
147
+
148
+ `walkTree` and `resolvePathToBlob` round out the layer for callers that want to flatten a tree or
149
+ resolve `path/to/file` to a blob sha without touching the network.
150
+
151
+ ### 5. The client — `src/client.ts`
152
+
153
+ `RemoteGit` ties the layers together and caches two things across calls:
154
+
155
+ - A `ServerProfile` (refs + capabilities + filter probe results), populated lazily on the first call
156
+ and shared by everything after.
157
+ - Every materialized object, in a process-lifetime `Map`. Subsequent fetches dedupe `want` lists
158
+ against this map, so a typical commit → tree → blob sequence only pays the network cost for new
159
+ objects.
160
+
161
+ There's a small bit of negotiation logic: shallow depth is dropped if the server didn't advertise
162
+ `shallow`; filters are dropped (with an info log) if the server didn't advertise `filter`. `probe()`
163
+ exists because some servers _advertise_ filter support but don't honour it — we send minimal-cost
164
+ test fetches with `blob:none` and `tree:0` and look at the returned pack to find out.
165
+
166
+ ## Errors
167
+
168
+ Every public function returns `Result<T, E>`. Errors are tagged classes from `better-result`, so you
169
+ can narrow on `_tag` and pull structured fields off:
170
+
171
+ ```typescript
172
+ const result = await client.fetchBlob(sha);
173
+ if (result.isErr()) {
174
+ switch (result.error._tag) {
175
+ case "TransportError": // .status, .url, .method available
176
+ case "PackParseError": // .offset, .reason
177
+ case "ObjectNotFoundError": // .sha
178
+ // …
179
+ }
180
+ }
181
+ ```
182
+
183
+ The full union is exported as `GitRemoteOpsError`. See `src/errors.ts`.
184
+
185
+ ## Observability
186
+
187
+ The bundled `Logger` does three jobs at once:
188
+
189
+ - Levelled messages (`info`, `debug`, `trace`) with namespaced children.
190
+ - Cumulative metrics: HTTP request count / bytes / time, pack objects by type / bytes / parse time.
191
+ - An aligned summary table for `--stats`.
192
+
193
+ The library never logs above `info` unless you ask. Pass a configured `Logger` via
194
+ `new RemoteGit(url, { logger })`, or hand it a `diagnostic` callback and the constructor will route
195
+ debug-level lines to it.
196
+
197
+ ## CLI
198
+
199
+ ```text
200
+ git-remote-ops <command> [options] <url>
201
+
202
+ Global flags:
203
+ -q, --quiet silent
204
+ -v, --verbose debug
205
+ --debug trace
206
+ --stats print metrics summary after completion
207
+
208
+ probe <url>
209
+ ls-refs <url>
210
+ cat-commit <url> [--ref HEAD] [--depth 1] [--filter blob:none | --no-filter]
211
+ cat-tree <url> [--ref HEAD] [--depth 1] [--filter blob:none | --no-filter]
212
+ [--tree-sha <sha>]
213
+ list-files <url> [--ref HEAD] [--depth 1] [--filter blob:none | --no-filter]
214
+ [--details]
215
+ cat-blob <url> <blob-sha>
216
+ ```
217
+
218
+ See `docs/cli.md` for the long-form reference.
219
+
220
+ ## Development
221
+
222
+ ```bash
223
+ deno task check # type-check
224
+ deno task lint
225
+ deno task fmt:check
226
+ deno task test # unit tests (no network)
227
+ deno task test:integration # spins up a local git server
228
+ deno task verify # fmt + lint + check, what CI runs
229
+ ```
230
+
231
+ Tests for each layer live next to their code as `*.test.ts`. The integration tests under
232
+ `src/testing/integration/` exercise a real `git-upload-pack` talking to the client — see
233
+ `docs/git-server-harness-AGENTS.md` for how the harness boots.
234
+
235
+ ## Limitations
236
+
237
+ By design this client only does fetches. It can't push, can't write to a working tree, can't manage
238
+ refs. It also makes no attempt to negotiate `have` lines — every request is a from-scratch fetch
239
+ with `done`, on the assumption that you're after small slices of remote history rather than
240
+ incrementally syncing a clone.
241
+
242
+ The packfile is held in memory in full. For large monorepos that fits in practice (kilobytes with
243
+ `blob:none` + `--depth=1`), but a streaming parser would be a reasonable evolution.
244
+
245
+ ## License
246
+
247
+ See `LICENSE`.
@@ -0,0 +1,72 @@
1
+ import { Deno } from "@deno/shim-deno";
2
+ export { Deno } from "@deno/shim-deno";
3
+ import { crypto } from "@deno/shim-crypto";
4
+ export { crypto } from "@deno/shim-crypto";
5
+ import { fetch, File, FormData, Headers, Request, Response } from "undici";
6
+ export { fetch, File, FormData, Headers, Request, Response } from "undici";
7
+ const dntGlobals = {
8
+ Deno,
9
+ crypto,
10
+ fetch,
11
+ File,
12
+ FormData,
13
+ Headers,
14
+ Request,
15
+ Response,
16
+ };
17
+ export const dntGlobalThis = createMergeProxy(globalThis, dntGlobals);
18
+ function createMergeProxy(baseObj, extObj) {
19
+ return new Proxy(baseObj, {
20
+ get(_target, prop, _receiver) {
21
+ if (prop in extObj) {
22
+ return extObj[prop];
23
+ }
24
+ else {
25
+ return baseObj[prop];
26
+ }
27
+ },
28
+ set(_target, prop, value) {
29
+ if (prop in extObj) {
30
+ delete extObj[prop];
31
+ }
32
+ baseObj[prop] = value;
33
+ return true;
34
+ },
35
+ deleteProperty(_target, prop) {
36
+ let success = false;
37
+ if (prop in extObj) {
38
+ delete extObj[prop];
39
+ success = true;
40
+ }
41
+ if (prop in baseObj) {
42
+ delete baseObj[prop];
43
+ success = true;
44
+ }
45
+ return success;
46
+ },
47
+ ownKeys(_target) {
48
+ const baseKeys = Reflect.ownKeys(baseObj);
49
+ const extKeys = Reflect.ownKeys(extObj);
50
+ const extKeysSet = new Set(extKeys);
51
+ return [...baseKeys.filter((k) => !extKeysSet.has(k)), ...extKeys];
52
+ },
53
+ defineProperty(_target, prop, desc) {
54
+ if (prop in extObj) {
55
+ delete extObj[prop];
56
+ }
57
+ Reflect.defineProperty(baseObj, prop, desc);
58
+ return true;
59
+ },
60
+ getOwnPropertyDescriptor(_target, prop) {
61
+ if (prop in extObj) {
62
+ return Reflect.getOwnPropertyDescriptor(extObj, prop);
63
+ }
64
+ else {
65
+ return Reflect.getOwnPropertyDescriptor(baseObj, prop);
66
+ }
67
+ },
68
+ has(_target, prop) {
69
+ return prop in extObj || prop in baseObj;
70
+ },
71
+ });
72
+ }