gitx.do 0.1.0 → 0.1.2

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 (344) hide show
  1. package/README.md +40 -353
  2. package/dist/do/logger.d.ts +50 -0
  3. package/dist/do/logger.d.ts.map +1 -0
  4. package/dist/do/logger.js +122 -0
  5. package/dist/do/logger.js.map +1 -0
  6. package/dist/{durable-object → do}/schema.d.ts +3 -3
  7. package/dist/do/schema.d.ts.map +1 -0
  8. package/dist/{durable-object → do}/schema.js +4 -3
  9. package/dist/do/schema.js.map +1 -0
  10. package/dist/do/types.d.ts +267 -0
  11. package/dist/do/types.d.ts.map +1 -0
  12. package/dist/do/types.js +62 -0
  13. package/dist/do/types.js.map +1 -0
  14. package/dist/index.d.ts +15 -415
  15. package/dist/index.d.ts.map +1 -1
  16. package/dist/index.js +31 -483
  17. package/dist/index.js.map +1 -1
  18. package/package.json +13 -21
  19. package/dist/cli/commands/add.d.ts +0 -174
  20. package/dist/cli/commands/add.d.ts.map +0 -1
  21. package/dist/cli/commands/add.js +0 -131
  22. package/dist/cli/commands/add.js.map +0 -1
  23. package/dist/cli/commands/blame.d.ts +0 -259
  24. package/dist/cli/commands/blame.d.ts.map +0 -1
  25. package/dist/cli/commands/blame.js +0 -609
  26. package/dist/cli/commands/blame.js.map +0 -1
  27. package/dist/cli/commands/branch.d.ts +0 -249
  28. package/dist/cli/commands/branch.d.ts.map +0 -1
  29. package/dist/cli/commands/branch.js +0 -693
  30. package/dist/cli/commands/branch.js.map +0 -1
  31. package/dist/cli/commands/commit.d.ts +0 -182
  32. package/dist/cli/commands/commit.d.ts.map +0 -1
  33. package/dist/cli/commands/commit.js +0 -437
  34. package/dist/cli/commands/commit.js.map +0 -1
  35. package/dist/cli/commands/diff.d.ts +0 -464
  36. package/dist/cli/commands/diff.d.ts.map +0 -1
  37. package/dist/cli/commands/diff.js +0 -958
  38. package/dist/cli/commands/diff.js.map +0 -1
  39. package/dist/cli/commands/log.d.ts +0 -239
  40. package/dist/cli/commands/log.d.ts.map +0 -1
  41. package/dist/cli/commands/log.js +0 -535
  42. package/dist/cli/commands/log.js.map +0 -1
  43. package/dist/cli/commands/merge.d.ts +0 -106
  44. package/dist/cli/commands/merge.d.ts.map +0 -1
  45. package/dist/cli/commands/merge.js +0 -55
  46. package/dist/cli/commands/merge.js.map +0 -1
  47. package/dist/cli/commands/review.d.ts +0 -457
  48. package/dist/cli/commands/review.d.ts.map +0 -1
  49. package/dist/cli/commands/review.js +0 -533
  50. package/dist/cli/commands/review.js.map +0 -1
  51. package/dist/cli/commands/status.d.ts +0 -269
  52. package/dist/cli/commands/status.d.ts.map +0 -1
  53. package/dist/cli/commands/status.js +0 -493
  54. package/dist/cli/commands/status.js.map +0 -1
  55. package/dist/cli/commands/web.d.ts +0 -199
  56. package/dist/cli/commands/web.d.ts.map +0 -1
  57. package/dist/cli/commands/web.js +0 -696
  58. package/dist/cli/commands/web.js.map +0 -1
  59. package/dist/cli/fs-adapter.d.ts +0 -656
  60. package/dist/cli/fs-adapter.d.ts.map +0 -1
  61. package/dist/cli/fs-adapter.js +0 -1179
  62. package/dist/cli/fs-adapter.js.map +0 -1
  63. package/dist/cli/fsx-cli-adapter.d.ts +0 -359
  64. package/dist/cli/fsx-cli-adapter.d.ts.map +0 -1
  65. package/dist/cli/fsx-cli-adapter.js +0 -619
  66. package/dist/cli/fsx-cli-adapter.js.map +0 -1
  67. package/dist/cli/index.d.ts +0 -387
  68. package/dist/cli/index.d.ts.map +0 -1
  69. package/dist/cli/index.js +0 -523
  70. package/dist/cli/index.js.map +0 -1
  71. package/dist/cli/ui/components/DiffView.d.ts +0 -7
  72. package/dist/cli/ui/components/DiffView.d.ts.map +0 -1
  73. package/dist/cli/ui/components/DiffView.js +0 -11
  74. package/dist/cli/ui/components/DiffView.js.map +0 -1
  75. package/dist/cli/ui/components/ErrorDisplay.d.ts +0 -6
  76. package/dist/cli/ui/components/ErrorDisplay.d.ts.map +0 -1
  77. package/dist/cli/ui/components/ErrorDisplay.js +0 -11
  78. package/dist/cli/ui/components/ErrorDisplay.js.map +0 -1
  79. package/dist/cli/ui/components/FuzzySearch.d.ts +0 -9
  80. package/dist/cli/ui/components/FuzzySearch.d.ts.map +0 -1
  81. package/dist/cli/ui/components/FuzzySearch.js +0 -12
  82. package/dist/cli/ui/components/FuzzySearch.js.map +0 -1
  83. package/dist/cli/ui/components/LoadingSpinner.d.ts +0 -6
  84. package/dist/cli/ui/components/LoadingSpinner.d.ts.map +0 -1
  85. package/dist/cli/ui/components/LoadingSpinner.js +0 -10
  86. package/dist/cli/ui/components/LoadingSpinner.js.map +0 -1
  87. package/dist/cli/ui/components/NavigationList.d.ts +0 -9
  88. package/dist/cli/ui/components/NavigationList.d.ts.map +0 -1
  89. package/dist/cli/ui/components/NavigationList.js +0 -11
  90. package/dist/cli/ui/components/NavigationList.js.map +0 -1
  91. package/dist/cli/ui/components/ScrollableContent.d.ts +0 -8
  92. package/dist/cli/ui/components/ScrollableContent.d.ts.map +0 -1
  93. package/dist/cli/ui/components/ScrollableContent.js +0 -11
  94. package/dist/cli/ui/components/ScrollableContent.js.map +0 -1
  95. package/dist/cli/ui/components/index.d.ts +0 -7
  96. package/dist/cli/ui/components/index.d.ts.map +0 -1
  97. package/dist/cli/ui/components/index.js +0 -9
  98. package/dist/cli/ui/components/index.js.map +0 -1
  99. package/dist/cli/ui/terminal-ui.d.ts +0 -52
  100. package/dist/cli/ui/terminal-ui.d.ts.map +0 -1
  101. package/dist/cli/ui/terminal-ui.js +0 -121
  102. package/dist/cli/ui/terminal-ui.js.map +0 -1
  103. package/dist/do/BashModule.d.ts +0 -871
  104. package/dist/do/BashModule.d.ts.map +0 -1
  105. package/dist/do/BashModule.js +0 -1143
  106. package/dist/do/BashModule.js.map +0 -1
  107. package/dist/do/FsModule.d.ts +0 -601
  108. package/dist/do/FsModule.d.ts.map +0 -1
  109. package/dist/do/FsModule.js +0 -1120
  110. package/dist/do/FsModule.js.map +0 -1
  111. package/dist/do/GitModule.d.ts +0 -635
  112. package/dist/do/GitModule.d.ts.map +0 -1
  113. package/dist/do/GitModule.js +0 -781
  114. package/dist/do/GitModule.js.map +0 -1
  115. package/dist/do/GitRepoDO.d.ts +0 -281
  116. package/dist/do/GitRepoDO.d.ts.map +0 -1
  117. package/dist/do/GitRepoDO.js +0 -479
  118. package/dist/do/GitRepoDO.js.map +0 -1
  119. package/dist/do/bash-ast.d.ts +0 -246
  120. package/dist/do/bash-ast.d.ts.map +0 -1
  121. package/dist/do/bash-ast.js +0 -888
  122. package/dist/do/bash-ast.js.map +0 -1
  123. package/dist/do/container-executor.d.ts +0 -491
  124. package/dist/do/container-executor.d.ts.map +0 -1
  125. package/dist/do/container-executor.js +0 -730
  126. package/dist/do/container-executor.js.map +0 -1
  127. package/dist/do/index.d.ts +0 -53
  128. package/dist/do/index.d.ts.map +0 -1
  129. package/dist/do/index.js +0 -91
  130. package/dist/do/index.js.map +0 -1
  131. package/dist/do/tiered-storage.d.ts +0 -403
  132. package/dist/do/tiered-storage.d.ts.map +0 -1
  133. package/dist/do/tiered-storage.js +0 -689
  134. package/dist/do/tiered-storage.js.map +0 -1
  135. package/dist/do/withBash.d.ts +0 -231
  136. package/dist/do/withBash.d.ts.map +0 -1
  137. package/dist/do/withBash.js +0 -244
  138. package/dist/do/withBash.js.map +0 -1
  139. package/dist/do/withFs.d.ts +0 -237
  140. package/dist/do/withFs.d.ts.map +0 -1
  141. package/dist/do/withFs.js +0 -387
  142. package/dist/do/withFs.js.map +0 -1
  143. package/dist/do/withGit.d.ts +0 -180
  144. package/dist/do/withGit.d.ts.map +0 -1
  145. package/dist/do/withGit.js +0 -271
  146. package/dist/do/withGit.js.map +0 -1
  147. package/dist/durable-object/object-store.d.ts +0 -633
  148. package/dist/durable-object/object-store.d.ts.map +0 -1
  149. package/dist/durable-object/object-store.js +0 -1161
  150. package/dist/durable-object/object-store.js.map +0 -1
  151. package/dist/durable-object/schema.d.ts.map +0 -1
  152. package/dist/durable-object/schema.js.map +0 -1
  153. package/dist/durable-object/wal.d.ts +0 -416
  154. package/dist/durable-object/wal.d.ts.map +0 -1
  155. package/dist/durable-object/wal.js +0 -445
  156. package/dist/durable-object/wal.js.map +0 -1
  157. package/dist/mcp/adapter.d.ts +0 -772
  158. package/dist/mcp/adapter.d.ts.map +0 -1
  159. package/dist/mcp/adapter.js +0 -895
  160. package/dist/mcp/adapter.js.map +0 -1
  161. package/dist/mcp/sandbox/miniflare-evaluator.d.ts +0 -22
  162. package/dist/mcp/sandbox/miniflare-evaluator.d.ts.map +0 -1
  163. package/dist/mcp/sandbox/miniflare-evaluator.js +0 -140
  164. package/dist/mcp/sandbox/miniflare-evaluator.js.map +0 -1
  165. package/dist/mcp/sandbox/object-store-proxy.d.ts +0 -32
  166. package/dist/mcp/sandbox/object-store-proxy.d.ts.map +0 -1
  167. package/dist/mcp/sandbox/object-store-proxy.js +0 -30
  168. package/dist/mcp/sandbox/object-store-proxy.js.map +0 -1
  169. package/dist/mcp/sandbox/template.d.ts +0 -17
  170. package/dist/mcp/sandbox/template.d.ts.map +0 -1
  171. package/dist/mcp/sandbox/template.js +0 -71
  172. package/dist/mcp/sandbox/template.js.map +0 -1
  173. package/dist/mcp/sandbox.d.ts +0 -764
  174. package/dist/mcp/sandbox.d.ts.map +0 -1
  175. package/dist/mcp/sandbox.js +0 -1362
  176. package/dist/mcp/sandbox.js.map +0 -1
  177. package/dist/mcp/sdk-adapter.d.ts +0 -835
  178. package/dist/mcp/sdk-adapter.d.ts.map +0 -1
  179. package/dist/mcp/sdk-adapter.js +0 -974
  180. package/dist/mcp/sdk-adapter.js.map +0 -1
  181. package/dist/mcp/tools/do.d.ts +0 -32
  182. package/dist/mcp/tools/do.d.ts.map +0 -1
  183. package/dist/mcp/tools/do.js +0 -115
  184. package/dist/mcp/tools/do.js.map +0 -1
  185. package/dist/mcp/tools.d.ts +0 -548
  186. package/dist/mcp/tools.d.ts.map +0 -1
  187. package/dist/mcp/tools.js +0 -1934
  188. package/dist/mcp/tools.js.map +0 -1
  189. package/dist/ops/blame.d.ts +0 -551
  190. package/dist/ops/blame.d.ts.map +0 -1
  191. package/dist/ops/blame.js +0 -1037
  192. package/dist/ops/blame.js.map +0 -1
  193. package/dist/ops/branch.d.ts +0 -766
  194. package/dist/ops/branch.d.ts.map +0 -1
  195. package/dist/ops/branch.js +0 -950
  196. package/dist/ops/branch.js.map +0 -1
  197. package/dist/ops/commit-traversal.d.ts +0 -349
  198. package/dist/ops/commit-traversal.d.ts.map +0 -1
  199. package/dist/ops/commit-traversal.js +0 -821
  200. package/dist/ops/commit-traversal.js.map +0 -1
  201. package/dist/ops/commit.d.ts +0 -555
  202. package/dist/ops/commit.d.ts.map +0 -1
  203. package/dist/ops/commit.js +0 -826
  204. package/dist/ops/commit.js.map +0 -1
  205. package/dist/ops/merge-base.d.ts +0 -397
  206. package/dist/ops/merge-base.d.ts.map +0 -1
  207. package/dist/ops/merge-base.js +0 -691
  208. package/dist/ops/merge-base.js.map +0 -1
  209. package/dist/ops/merge.d.ts +0 -855
  210. package/dist/ops/merge.d.ts.map +0 -1
  211. package/dist/ops/merge.js +0 -1551
  212. package/dist/ops/merge.js.map +0 -1
  213. package/dist/ops/tag.d.ts +0 -247
  214. package/dist/ops/tag.d.ts.map +0 -1
  215. package/dist/ops/tag.js +0 -649
  216. package/dist/ops/tag.js.map +0 -1
  217. package/dist/ops/tree-builder.d.ts +0 -178
  218. package/dist/ops/tree-builder.d.ts.map +0 -1
  219. package/dist/ops/tree-builder.js +0 -271
  220. package/dist/ops/tree-builder.js.map +0 -1
  221. package/dist/ops/tree-diff.d.ts +0 -291
  222. package/dist/ops/tree-diff.d.ts.map +0 -1
  223. package/dist/ops/tree-diff.js +0 -705
  224. package/dist/ops/tree-diff.js.map +0 -1
  225. package/dist/pack/delta.d.ts +0 -248
  226. package/dist/pack/delta.d.ts.map +0 -1
  227. package/dist/pack/delta.js +0 -736
  228. package/dist/pack/delta.js.map +0 -1
  229. package/dist/pack/format.d.ts +0 -446
  230. package/dist/pack/format.d.ts.map +0 -1
  231. package/dist/pack/format.js +0 -572
  232. package/dist/pack/format.js.map +0 -1
  233. package/dist/pack/full-generation.d.ts +0 -612
  234. package/dist/pack/full-generation.d.ts.map +0 -1
  235. package/dist/pack/full-generation.js +0 -1378
  236. package/dist/pack/full-generation.js.map +0 -1
  237. package/dist/pack/generation.d.ts +0 -441
  238. package/dist/pack/generation.d.ts.map +0 -1
  239. package/dist/pack/generation.js +0 -707
  240. package/dist/pack/generation.js.map +0 -1
  241. package/dist/pack/index.d.ts +0 -502
  242. package/dist/pack/index.d.ts.map +0 -1
  243. package/dist/pack/index.js +0 -833
  244. package/dist/pack/index.js.map +0 -1
  245. package/dist/refs/branch.d.ts +0 -668
  246. package/dist/refs/branch.d.ts.map +0 -1
  247. package/dist/refs/branch.js +0 -897
  248. package/dist/refs/branch.js.map +0 -1
  249. package/dist/refs/storage.d.ts +0 -833
  250. package/dist/refs/storage.d.ts.map +0 -1
  251. package/dist/refs/storage.js +0 -1023
  252. package/dist/refs/storage.js.map +0 -1
  253. package/dist/refs/tag.d.ts +0 -860
  254. package/dist/refs/tag.d.ts.map +0 -1
  255. package/dist/refs/tag.js +0 -996
  256. package/dist/refs/tag.js.map +0 -1
  257. package/dist/storage/backend.d.ts +0 -425
  258. package/dist/storage/backend.d.ts.map +0 -1
  259. package/dist/storage/backend.js +0 -41
  260. package/dist/storage/backend.js.map +0 -1
  261. package/dist/storage/fsx-adapter.d.ts +0 -204
  262. package/dist/storage/fsx-adapter.d.ts.map +0 -1
  263. package/dist/storage/fsx-adapter.js +0 -470
  264. package/dist/storage/fsx-adapter.js.map +0 -1
  265. package/dist/storage/lru-cache.d.ts +0 -691
  266. package/dist/storage/lru-cache.d.ts.map +0 -1
  267. package/dist/storage/lru-cache.js +0 -813
  268. package/dist/storage/lru-cache.js.map +0 -1
  269. package/dist/storage/object-index.d.ts +0 -585
  270. package/dist/storage/object-index.d.ts.map +0 -1
  271. package/dist/storage/object-index.js +0 -532
  272. package/dist/storage/object-index.js.map +0 -1
  273. package/dist/storage/r2-pack.d.ts +0 -1257
  274. package/dist/storage/r2-pack.d.ts.map +0 -1
  275. package/dist/storage/r2-pack.js +0 -1770
  276. package/dist/storage/r2-pack.js.map +0 -1
  277. package/dist/tiered/cdc-pipeline.d.ts +0 -1888
  278. package/dist/tiered/cdc-pipeline.d.ts.map +0 -1
  279. package/dist/tiered/cdc-pipeline.js +0 -1880
  280. package/dist/tiered/cdc-pipeline.js.map +0 -1
  281. package/dist/tiered/migration.d.ts +0 -1104
  282. package/dist/tiered/migration.d.ts.map +0 -1
  283. package/dist/tiered/migration.js +0 -1214
  284. package/dist/tiered/migration.js.map +0 -1
  285. package/dist/tiered/parquet-writer.d.ts +0 -1145
  286. package/dist/tiered/parquet-writer.d.ts.map +0 -1
  287. package/dist/tiered/parquet-writer.js +0 -1183
  288. package/dist/tiered/parquet-writer.js.map +0 -1
  289. package/dist/tiered/read-path.d.ts +0 -835
  290. package/dist/tiered/read-path.d.ts.map +0 -1
  291. package/dist/tiered/read-path.js +0 -487
  292. package/dist/tiered/read-path.js.map +0 -1
  293. package/dist/types/capability.d.ts +0 -1385
  294. package/dist/types/capability.d.ts.map +0 -1
  295. package/dist/types/capability.js +0 -36
  296. package/dist/types/capability.js.map +0 -1
  297. package/dist/types/index.d.ts +0 -13
  298. package/dist/types/index.d.ts.map +0 -1
  299. package/dist/types/index.js +0 -18
  300. package/dist/types/index.js.map +0 -1
  301. package/dist/types/objects.d.ts +0 -692
  302. package/dist/types/objects.d.ts.map +0 -1
  303. package/dist/types/objects.js +0 -837
  304. package/dist/types/objects.js.map +0 -1
  305. package/dist/types/storage.d.ts +0 -603
  306. package/dist/types/storage.d.ts.map +0 -1
  307. package/dist/types/storage.js +0 -191
  308. package/dist/types/storage.js.map +0 -1
  309. package/dist/types/worker-loader.d.ts +0 -60
  310. package/dist/types/worker-loader.d.ts.map +0 -1
  311. package/dist/types/worker-loader.js +0 -62
  312. package/dist/types/worker-loader.js.map +0 -1
  313. package/dist/utils/hash.d.ts +0 -197
  314. package/dist/utils/hash.d.ts.map +0 -1
  315. package/dist/utils/hash.js +0 -268
  316. package/dist/utils/hash.js.map +0 -1
  317. package/dist/utils/sha1.d.ts +0 -290
  318. package/dist/utils/sha1.d.ts.map +0 -1
  319. package/dist/utils/sha1.js +0 -582
  320. package/dist/utils/sha1.js.map +0 -1
  321. package/dist/wire/capabilities.d.ts +0 -1044
  322. package/dist/wire/capabilities.d.ts.map +0 -1
  323. package/dist/wire/capabilities.js +0 -941
  324. package/dist/wire/capabilities.js.map +0 -1
  325. package/dist/wire/path-security.d.ts +0 -157
  326. package/dist/wire/path-security.d.ts.map +0 -1
  327. package/dist/wire/path-security.js +0 -307
  328. package/dist/wire/path-security.js.map +0 -1
  329. package/dist/wire/pkt-line.d.ts +0 -345
  330. package/dist/wire/pkt-line.d.ts.map +0 -1
  331. package/dist/wire/pkt-line.js +0 -381
  332. package/dist/wire/pkt-line.js.map +0 -1
  333. package/dist/wire/receive-pack.d.ts +0 -1059
  334. package/dist/wire/receive-pack.d.ts.map +0 -1
  335. package/dist/wire/receive-pack.js +0 -1414
  336. package/dist/wire/receive-pack.js.map +0 -1
  337. package/dist/wire/smart-http.d.ts +0 -799
  338. package/dist/wire/smart-http.d.ts.map +0 -1
  339. package/dist/wire/smart-http.js +0 -945
  340. package/dist/wire/smart-http.js.map +0 -1
  341. package/dist/wire/upload-pack.d.ts +0 -727
  342. package/dist/wire/upload-pack.d.ts.map +0 -1
  343. package/dist/wire/upload-pack.js +0 -1138
  344. package/dist/wire/upload-pack.js.map +0 -1
@@ -1,941 +0,0 @@
1
- /**
2
- * @fileoverview Git wire protocol capability negotiation
3
- *
4
- * This module implements the capability negotiation mechanism used in Git's wire protocol.
5
- * Capabilities are exchanged during the initial handshake between git client and server
6
- * to determine what features are supported by both sides, enabling backward compatibility
7
- * and feature detection.
8
- *
9
- * ## Protocol Versions
10
- *
11
- * **Protocol v1:**
12
- * - Capabilities are sent as a space-separated list after the first ref line
13
- * - Format: `<oid> <refname>\0<cap1> <cap2> cap3=value...`
14
- * - The NUL byte (`\0`) separates ref information from capabilities
15
- * - Only the first ref line contains capabilities
16
- *
17
- * **Protocol v2:**
18
- * - Capabilities are advertised line by line in the initial handshake
19
- * - Starts with `version 2` line
20
- * - Each capability on its own line, with optional values after `=`
21
- * - More structured and extensible than v1
22
- *
23
- * ## Common Capabilities
24
- *
25
- * **Fetch operations:**
26
- * - `multi_ack`, `multi_ack_detailed`: Improved negotiation
27
- * - `thin-pack`: Send thin packs requiring client to resolve deltas
28
- * - `side-band`, `side-band-64k`: Multiplexed data channels
29
- * - `ofs-delta`: Use offset-based delta encoding
30
- * - `shallow`: Support shallow clone operations
31
- *
32
- * **Push operations:**
33
- * - `report-status`, `report-status-v2`: Push result reporting
34
- * - `atomic`: All-or-nothing ref updates
35
- * - `delete-refs`: Allow ref deletion
36
- * - `push-options`: Support push options
37
- *
38
- * ## Usage Example
39
- *
40
- * ```typescript
41
- * import {
42
- * parseCapabilityString,
43
- * findCommonCapabilities,
44
- * buildCapabilityString,
45
- * DEFAULT_FETCH_CAPABILITIES_V1
46
- * } from './capabilities';
47
- *
48
- * // Parse capabilities from server advertisement
49
- * const serverCaps = parseCapabilityString('abc123... refs/heads/main\0multi_ack side-band-64k');
50
- *
51
- * // Find common capabilities
52
- * const clientCaps = DEFAULT_FETCH_CAPABILITIES_V1.map(name => ({ name }));
53
- * const common = findCommonCapabilities(clientCaps, serverCaps);
54
- *
55
- * // Build capability string for request
56
- * const capString = buildCapabilityString([
57
- * { name: 'multi_ack' },
58
- * { name: 'agent', value: 'gitdo/1.0' }
59
- * ]);
60
- * ```
61
- *
62
- * @module wire/capabilities
63
- * @see {@link https://git-scm.com/docs/protocol-capabilities} - Protocol capabilities reference
64
- * @see {@link https://git-scm.com/docs/protocol-v2} - Protocol v2 specification
65
- */
66
- // ============================================================================
67
- // Constants
68
- // ============================================================================
69
- /**
70
- * Default client capabilities for fetch operations (protocol v1).
71
- *
72
- * @description
73
- * A sensible set of capabilities for fetch operations that provides
74
- * good performance while maintaining compatibility. These are commonly
75
- * supported by modern Git servers.
76
- *
77
- * - `multi_ack_detailed`: Efficient negotiation with detailed feedback
78
- * - `side-band-64k`: Large multiplexed data channels for progress/data
79
- * - `thin-pack`: Receive thin packs (smaller transfer size)
80
- * - `ofs-delta`: Efficient delta encoding
81
- * - `agent`: Identify the client
82
- *
83
- * @example
84
- * ```typescript
85
- * const clientCaps = DEFAULT_FETCH_CAPABILITIES_V1.map(name => ({ name }));
86
- * // Add agent value
87
- * clientCaps.find(c => c.name === 'agent')!.value = 'gitdo/1.0';
88
- *
89
- * const selected = selectFetchCapabilities(serverCaps, clientCaps);
90
- * ```
91
- */
92
- export const DEFAULT_FETCH_CAPABILITIES_V1 = [
93
- 'multi_ack_detailed',
94
- 'side-band-64k',
95
- 'thin-pack',
96
- 'ofs-delta',
97
- 'agent',
98
- ];
99
- /**
100
- * Default client capabilities for push operations (protocol v1).
101
- *
102
- * @description
103
- * A sensible set of capabilities for push operations that provides
104
- * detailed feedback and compatibility with modern Git servers.
105
- *
106
- * - `report-status`: Receive detailed push result status
107
- * - `side-band-64k`: Multiplexed channels for status/errors
108
- * - `agent`: Identify the client
109
- * - `quiet`: Suppress unnecessary progress output
110
- *
111
- * @example
112
- * ```typescript
113
- * const pushCaps = DEFAULT_PUSH_CAPABILITIES_V1.map(name => ({ name }));
114
- * pushCaps.find(c => c.name === 'agent')!.value = 'gitdo/1.0';
115
- * ```
116
- */
117
- export const DEFAULT_PUSH_CAPABILITIES_V1 = [
118
- 'report-status',
119
- 'side-band-64k',
120
- 'agent',
121
- 'quiet',
122
- ];
123
- /**
124
- * Minimum required capabilities for basic fetch.
125
- *
126
- * @description
127
- * Capabilities that must be present for fetch to work correctly.
128
- * Currently empty as Git is designed to work with minimal capabilities,
129
- * but this can be populated if specific capabilities become required.
130
- *
131
- * @example
132
- * ```typescript
133
- * const missing = validateRequiredCapabilities(serverCaps, REQUIRED_FETCH_CAPABILITIES);
134
- * if (missing.length > 0) {
135
- * throw new Error(`Server missing required capabilities: ${missing.join(', ')}`);
136
- * }
137
- * ```
138
- */
139
- export const REQUIRED_FETCH_CAPABILITIES = [];
140
- // ============================================================================
141
- // Parsing Functions
142
- // ============================================================================
143
- /**
144
- * Parse a capability string from ref advertisement (protocol v1).
145
- *
146
- * @description
147
- * Extracts capabilities from a protocol v1 ref advertisement line.
148
- * The capabilities appear after a NUL byte (`\0`) separator following
149
- * the ref information. This is only present on the first ref line.
150
- *
151
- * Line format: `<oid> <refname>\0<cap1> <cap2> cap3=value...`
152
- *
153
- * @param line - The ref advertisement line containing capabilities
154
- * @returns Parsed capability set with version 1
155
- *
156
- * @throws {Error} If the line doesn't contain a NUL byte separator
157
- *
158
- * @example
159
- * ```typescript
160
- * // Parse from first ref line
161
- * const line = 'abc123def456789012345678901234567890abcd refs/heads/main\0multi_ack side-band-64k agent=git/2.30.0';
162
- * const caps = parseCapabilityString(line);
163
- *
164
- * console.log(caps.version); // 1
165
- * console.log(caps.capabilities.has('multi_ack')); // true
166
- * console.log(caps.capabilities.get('agent')); // 'git/2.30.0'
167
- * ```
168
- */
169
- export function parseCapabilityString(line) {
170
- // Find the NUL byte that separates ref info from capabilities
171
- const nulIndex = line.indexOf('\0');
172
- if (nulIndex === -1) {
173
- throw new Error('Invalid capability string: missing NUL byte separator');
174
- }
175
- // Extract the capability portion after the NUL byte
176
- const capString = line.slice(nulIndex + 1);
177
- // Parse the capabilities
178
- const entries = parseCapabilities(capString);
179
- // Build the capability map
180
- const capabilities = new Map();
181
- for (const entry of entries) {
182
- capabilities.set(entry.name, entry.value);
183
- }
184
- return {
185
- version: 1,
186
- capabilities,
187
- };
188
- }
189
- /**
190
- * Parse individual capability entries from a space-separated string.
191
- *
192
- * @description
193
- * Parses a whitespace-separated capability string into individual entries.
194
- * Handles both simple capabilities (`multi_ack`) and capabilities with
195
- * values (`agent=git/2.30.0`).
196
- *
197
- * @param capString - Space-separated capability string
198
- * @returns Array of capability entries
199
- *
200
- * @example
201
- * ```typescript
202
- * // Simple capabilities
203
- * const caps1 = parseCapabilities('multi_ack thin-pack ofs-delta');
204
- * // [{ name: 'multi_ack' }, { name: 'thin-pack' }, { name: 'ofs-delta' }]
205
- *
206
- * // Capabilities with values
207
- * const caps2 = parseCapabilities('agent=git/2.30.0 symref=HEAD:refs/heads/main');
208
- * // [{ name: 'agent', value: 'git/2.30.0' }, { name: 'symref', value: 'HEAD:refs/heads/main' }]
209
- *
210
- * // Empty string
211
- * const caps3 = parseCapabilities('');
212
- * // []
213
- * ```
214
- */
215
- export function parseCapabilities(capString) {
216
- // Trim and split by whitespace
217
- const trimmed = capString.trim();
218
- if (trimmed === '') {
219
- return [];
220
- }
221
- // Split by whitespace (handles multiple spaces)
222
- const parts = trimmed.split(/\s+/);
223
- return parts.map((part) => {
224
- const eqIndex = part.indexOf('=');
225
- if (eqIndex === -1) {
226
- return { name: part };
227
- }
228
- else {
229
- return {
230
- name: part.slice(0, eqIndex),
231
- value: part.slice(eqIndex + 1),
232
- };
233
- }
234
- });
235
- }
236
- /**
237
- * Parse a ref advertisement line (protocol v1).
238
- *
239
- * @description
240
- * Parses a single line from the server's ref advertisement. The first
241
- * line has a special format including capabilities after a NUL byte,
242
- * while subsequent lines contain only the OID and ref name.
243
- *
244
- * First line format: `<oid> <refname>\0<capabilities>`
245
- * Subsequent lines: `<oid> <refname>`
246
- *
247
- * @param line - The pkt-line data (without length prefix)
248
- * @param isFirst - Whether this is the first line (contains capabilities)
249
- * @returns Parsed ref advertisement
250
- *
251
- * @throws {Error} If the first line is missing the NUL byte
252
- * @throws {Error} If the line is missing the space between OID and refname
253
- * @throws {Error} If the OID is not 40 characters (SHA-1)
254
- *
255
- * @example
256
- * ```typescript
257
- * // Parse first line (with capabilities)
258
- * const firstLine = 'abc123def456789012345678901234567890abcd refs/heads/main\0multi_ack side-band-64k\n';
259
- * const firstRef = parseRefAdvertisement(firstLine, true);
260
- * // {
261
- * // oid: 'abc123def456789012345678901234567890abcd',
262
- * // name: 'refs/heads/main',
263
- * // capabilities: { version: 1, capabilities: Map {...} }
264
- * // }
265
- *
266
- * // Parse subsequent line (no capabilities)
267
- * const otherLine = 'def456789012345678901234567890abcdef12 refs/heads/feature\n';
268
- * const otherRef = parseRefAdvertisement(otherLine, false);
269
- * // {
270
- * // oid: 'def456789012345678901234567890abcdef12',
271
- * // name: 'refs/heads/feature'
272
- * // }
273
- * ```
274
- */
275
- export function parseRefAdvertisement(line, isFirst) {
276
- // Remove trailing newline if present
277
- const cleanLine = line.replace(/\n$/, '');
278
- let oid;
279
- let name;
280
- let capabilities;
281
- if (isFirst) {
282
- // First line has capabilities after NUL byte
283
- const nulIndex = cleanLine.indexOf('\0');
284
- if (nulIndex === -1) {
285
- throw new Error('First ref advertisement line must contain NUL byte');
286
- }
287
- const refPart = cleanLine.slice(0, nulIndex);
288
- const spaceIndex = refPart.indexOf(' ');
289
- if (spaceIndex === -1) {
290
- throw new Error('Invalid ref advertisement format: missing space between OID and refname');
291
- }
292
- oid = refPart.slice(0, spaceIndex);
293
- name = refPart.slice(spaceIndex + 1);
294
- // Validate OID length (should be 40 hex chars for SHA-1)
295
- if (oid.length !== 40) {
296
- throw new Error('Invalid OID length in ref advertisement');
297
- }
298
- capabilities = parseCapabilityString(cleanLine);
299
- }
300
- else {
301
- // Subsequent lines: just "<oid> <refname>"
302
- const spaceIndex = cleanLine.indexOf(' ');
303
- if (spaceIndex === -1) {
304
- throw new Error('Invalid ref advertisement format: missing space between OID and refname');
305
- }
306
- oid = cleanLine.slice(0, spaceIndex);
307
- name = cleanLine.slice(spaceIndex + 1);
308
- // Validate OID length
309
- if (oid.length !== 40) {
310
- throw new Error('Invalid OID length in ref advertisement');
311
- }
312
- }
313
- return {
314
- oid,
315
- name,
316
- capabilities,
317
- };
318
- }
319
- /**
320
- * Parse protocol v2 capability advertisement.
321
- *
322
- * @description
323
- * Parses the server's capability advertisement in protocol v2 format.
324
- * Protocol v2 uses a line-by-line format starting with "version 2",
325
- * followed by capability lines. Commands and capabilities are distinguished
326
- * by whether they have values.
327
- *
328
- * Response format:
329
- * ```
330
- * version 2
331
- * agent=git/2.30.0
332
- * ls-refs
333
- * fetch=shallow filter
334
- * server-option
335
- * object-format=sha1
336
- * ```
337
- *
338
- * @param lines - Array of pkt-line data (without length prefixes)
339
- * @returns Parsed server capabilities
340
- *
341
- * @throws {Error} If lines is empty or doesn't start with "version 2"
342
- *
343
- * @example
344
- * ```typescript
345
- * const lines = [
346
- * 'version 2',
347
- * 'agent=git/2.40.0',
348
- * 'ls-refs',
349
- * 'fetch=shallow filter',
350
- * 'server-option',
351
- * 'object-format=sha1'
352
- * ];
353
- *
354
- * const serverCaps = parseServerCapabilitiesV2(lines);
355
- * // {
356
- * // version: 2,
357
- * // commands: ['ls-refs', 'fetch', 'server-option'],
358
- * // agent: 'git/2.40.0',
359
- * // objectFormat: 'sha1',
360
- * // capabilities: Map { 'ls-refs' => undefined, 'fetch' => 'shallow filter', ... }
361
- * // }
362
- *
363
- * if (serverCaps.commands.includes('fetch')) {
364
- * console.log('Server supports fetch with:', serverCaps.capabilities.get('fetch'));
365
- * }
366
- * ```
367
- */
368
- export function parseServerCapabilitiesV2(lines) {
369
- if (lines.length === 0 || lines[0] !== 'version 2') {
370
- throw new Error('Invalid protocol v2 response: must start with "version 2"');
371
- }
372
- const commands = [];
373
- const capabilities = new Map();
374
- let agent;
375
- let objectFormat;
376
- // Process each line after "version 2"
377
- for (let i = 1; i < lines.length; i++) {
378
- const line = lines[i];
379
- const eqIndex = line.indexOf('=');
380
- if (eqIndex === -1) {
381
- // This is a command without a value
382
- commands.push(line);
383
- capabilities.set(line, undefined);
384
- }
385
- else {
386
- const name = line.slice(0, eqIndex);
387
- const value = line.slice(eqIndex + 1);
388
- if (name === 'agent') {
389
- agent = value;
390
- }
391
- else if (name === 'object-format') {
392
- objectFormat = value;
393
- }
394
- else if (name === 'fetch' || name === 'ls-refs' || name === 'server-option') {
395
- // Commands with sub-capabilities
396
- commands.push(name);
397
- capabilities.set(name, value);
398
- }
399
- else {
400
- capabilities.set(name, value);
401
- }
402
- }
403
- }
404
- return {
405
- version: 2,
406
- commands,
407
- agent,
408
- objectFormat,
409
- capabilities,
410
- };
411
- }
412
- // ============================================================================
413
- // Building Functions
414
- // ============================================================================
415
- /**
416
- * Build a capability string for want/have request (protocol v1).
417
- *
418
- * @description
419
- * Constructs a space-separated capability string from an array of
420
- * capability entries. Capabilities with values are formatted as
421
- * `name=value`, while those without are just the name.
422
- *
423
- * @param capabilities - Capabilities to include
424
- * @returns Space-separated capability string
425
- *
426
- * @example
427
- * ```typescript
428
- * const caps: CapabilityEntry[] = [
429
- * { name: 'multi_ack_detailed' },
430
- * { name: 'side-band-64k' },
431
- * { name: 'agent', value: 'gitdo/1.0' }
432
- * ];
433
- *
434
- * const str = buildCapabilityString(caps);
435
- * // 'multi_ack_detailed side-band-64k agent=gitdo/1.0'
436
- * ```
437
- */
438
- export function buildCapabilityString(capabilities) {
439
- return capabilities
440
- .map((cap) => {
441
- if (cap.value !== undefined) {
442
- return `${cap.name}=${cap.value}`;
443
- }
444
- return cap.name;
445
- })
446
- .join(' ');
447
- }
448
- /**
449
- * Build a want line with capabilities (first want only).
450
- *
451
- * @description
452
- * Constructs a want line for a fetch request. The first want line
453
- * includes capabilities, while subsequent want lines contain only
454
- * the object ID.
455
- *
456
- * Format: `want <oid> <capabilities>\n` (first line)
457
- * Format: `want <oid>\n` (subsequent lines)
458
- *
459
- * @param oid - The object ID to want (40-character SHA-1 hex string)
460
- * @param capabilities - Capabilities to include (optional, first want only)
461
- * @returns Formatted want line with trailing newline
462
- *
463
- * @example
464
- * ```typescript
465
- * // First want line with capabilities
466
- * const firstWant = buildWantLine(
467
- * 'abc123def456789012345678901234567890abcd',
468
- * [{ name: 'multi_ack' }, { name: 'agent', value: 'gitdo/1.0' }]
469
- * );
470
- * // 'want abc123def456789012345678901234567890abcd multi_ack agent=gitdo/1.0\n'
471
- *
472
- * // Subsequent want line (no capabilities)
473
- * const nextWant = buildWantLine('def456789012345678901234567890abcdef12');
474
- * // 'want def456789012345678901234567890abcdef12\n'
475
- * ```
476
- */
477
- export function buildWantLine(oid, capabilities) {
478
- if (capabilities && capabilities.length > 0) {
479
- const capString = buildCapabilityString(capabilities);
480
- return `want ${oid} ${capString}\n`;
481
- }
482
- return `want ${oid}\n`;
483
- }
484
- /**
485
- * Build a have line for negotiation.
486
- *
487
- * @description
488
- * Constructs a have line used during fetch negotiation. Have lines
489
- * inform the server what objects the client already has, allowing
490
- * the server to determine the minimal set of objects to send.
491
- *
492
- * Format: `have <oid>\n`
493
- *
494
- * @param oid - The object ID we have (40-character SHA-1 hex string)
495
- * @returns Formatted have line with trailing newline
496
- *
497
- * @example
498
- * ```typescript
499
- * const haveLine = buildHaveLine('abc123def456789012345678901234567890abcd');
500
- * // 'have abc123def456789012345678901234567890abcd\n'
501
- *
502
- * // OID is normalized to lowercase
503
- * const normalized = buildHaveLine('ABC123DEF456789012345678901234567890ABCD');
504
- * // 'have abc123def456789012345678901234567890abcd\n'
505
- * ```
506
- */
507
- export function buildHaveLine(oid) {
508
- return `have ${oid.toLowerCase()}\n`;
509
- }
510
- /**
511
- * Build a complete want/have request.
512
- *
513
- * @description
514
- * Constructs all want lines for a fetch request. The first want line
515
- * includes the client's capabilities, while subsequent want lines
516
- * contain only the object IDs.
517
- *
518
- * @param request - The want request containing object IDs and capabilities
519
- * @returns Array of formatted want lines (ready for pkt-line encoding)
520
- *
521
- * @example
522
- * ```typescript
523
- * const request: WantRequest = {
524
- * wants: [
525
- * 'abc123def456789012345678901234567890abcd',
526
- * 'def456789012345678901234567890abcdef12',
527
- * '123456789012345678901234567890abcdef00'
528
- * ],
529
- * capabilities: [
530
- * { name: 'multi_ack_detailed' },
531
- * { name: 'side-band-64k' }
532
- * ]
533
- * };
534
- *
535
- * const lines = buildFetchRequest(request);
536
- * // [
537
- * // 'want abc123... multi_ack_detailed side-band-64k\n',
538
- * // 'want def456...\n',
539
- * // 'want 123456...\n'
540
- * // ]
541
- * ```
542
- */
543
- export function buildFetchRequest(request) {
544
- const lines = [];
545
- for (let i = 0; i < request.wants.length; i++) {
546
- const oid = request.wants[i];
547
- if (i === 0) {
548
- // First want line includes capabilities
549
- lines.push(buildWantLine(oid, request.capabilities));
550
- }
551
- else {
552
- // Subsequent want lines don't include capabilities
553
- lines.push(buildWantLine(oid));
554
- }
555
- }
556
- return lines;
557
- }
558
- /**
559
- * Build protocol v2 command request.
560
- *
561
- * @description
562
- * Constructs a protocol v2 command request. Protocol v2 uses a structured
563
- * format with command specification, capabilities, and optional arguments.
564
- *
565
- * Request format:
566
- * ```
567
- * command=<cmd>
568
- * capability1
569
- * capability2=value
570
- * 0001 (delimiter - added by caller)
571
- * <command-specific args>
572
- * 0000 (flush - added by caller)
573
- * ```
574
- *
575
- * @param command - The v2 command (e.g., 'fetch', 'ls-refs')
576
- * @param capabilities - Client capabilities to advertise
577
- * @param args - Command-specific arguments (optional)
578
- * @returns Array of lines (ready for pkt-line encoding)
579
- *
580
- * @example
581
- * ```typescript
582
- * // ls-refs request
583
- * const lsRefsLines = buildV2CommandRequest(
584
- * 'ls-refs',
585
- * [{ name: 'agent', value: 'gitdo/1.0' }],
586
- * ['peel', 'symrefs', 'ref-prefix refs/heads/']
587
- * );
588
- * // [
589
- * // 'command=ls-refs',
590
- * // 'agent=gitdo/1.0',
591
- * // 'peel',
592
- * // 'symrefs',
593
- * // 'ref-prefix refs/heads/'
594
- * // ]
595
- *
596
- * // fetch request
597
- * const fetchLines = buildV2CommandRequest(
598
- * 'fetch',
599
- * [{ name: 'agent', value: 'gitdo/1.0' }, { name: 'thin-pack' }],
600
- * ['want abc123...', 'have def456...', 'done']
601
- * );
602
- * ```
603
- */
604
- export function buildV2CommandRequest(command, capabilities, args) {
605
- const lines = [];
606
- // Add command line
607
- lines.push(`command=${command}`);
608
- // Add capabilities
609
- for (const cap of capabilities) {
610
- if (cap.value !== undefined) {
611
- lines.push(`${cap.name}=${cap.value}`);
612
- }
613
- else {
614
- lines.push(cap.name);
615
- }
616
- }
617
- // Add arguments if present
618
- if (args && args.length > 0) {
619
- for (const arg of args) {
620
- lines.push(arg);
621
- }
622
- }
623
- return lines;
624
- }
625
- // ============================================================================
626
- // Negotiation Functions
627
- // ============================================================================
628
- /**
629
- * Negotiate protocol version with server.
630
- *
631
- * @description
632
- * Determines the protocol version to use based on the server's advertisement
633
- * and the client's preference. The negotiated version is the highest version
634
- * supported by both parties.
635
- *
636
- * @param serverAdvertisement - First line from server's response
637
- * @param preferredVersion - Client's preferred protocol version (default: 2)
638
- * @returns Negotiation result with agreed version
639
- *
640
- * @example
641
- * ```typescript
642
- * // Server supports v2, client prefers v2
643
- * const v2Result = negotiateVersion('version 2', 2);
644
- * // { version: 2, serverSupportsV2: true, commonCapabilities: [] }
645
- *
646
- * // Server is v1 only, client prefers v2
647
- * const v1Result = negotiateVersion('abc123... refs/heads/main\0multi_ack', 2);
648
- * // { version: 1, serverSupportsV2: false, commonCapabilities: [] }
649
- *
650
- * // Client explicitly wants v1
651
- * const explicitV1 = negotiateVersion('version 2', 1);
652
- * // { version: 1, serverSupportsV2: true, commonCapabilities: [] }
653
- * ```
654
- */
655
- export function negotiateVersion(serverAdvertisement, preferredVersion = 2) {
656
- const serverSupportsV2 = serverAdvertisement.startsWith('version 2');
657
- let version;
658
- if (serverSupportsV2 && preferredVersion === 2) {
659
- version = 2;
660
- }
661
- else {
662
- version = 1;
663
- }
664
- return {
665
- version,
666
- serverSupportsV2,
667
- commonCapabilities: [],
668
- };
669
- }
670
- /**
671
- * Find common capabilities between client and server.
672
- *
673
- * @description
674
- * Determines which capabilities are supported by both the client and server.
675
- * This is used to select the optimal set of capabilities for the session.
676
- *
677
- * @param clientCaps - Client's supported capabilities
678
- * @param serverCaps - Server's advertised capabilities
679
- * @returns Array of capability names supported by both parties
680
- *
681
- * @example
682
- * ```typescript
683
- * const clientCaps: CapabilityEntry[] = [
684
- * { name: 'multi_ack_detailed' },
685
- * { name: 'side-band-64k' },
686
- * { name: 'thin-pack' },
687
- * { name: 'ofs-delta' }
688
- * ];
689
- *
690
- * const serverCaps: CapabilitySet = {
691
- * version: 1,
692
- * capabilities: new Map([
693
- * ['multi_ack', undefined],
694
- * ['multi_ack_detailed', undefined],
695
- * ['side-band-64k', undefined],
696
- * ['shallow', undefined]
697
- * ])
698
- * };
699
- *
700
- * const common = findCommonCapabilities(clientCaps, serverCaps);
701
- * // ['multi_ack_detailed', 'side-band-64k']
702
- * ```
703
- */
704
- export function findCommonCapabilities(clientCaps, serverCaps) {
705
- const common = [];
706
- for (const clientCap of clientCaps) {
707
- if (serverCaps.capabilities.has(clientCap.name)) {
708
- common.push(clientCap.name);
709
- }
710
- }
711
- return common;
712
- }
713
- /**
714
- * Check if a specific capability is supported.
715
- *
716
- * @description
717
- * Checks whether a capability is present in the capability set.
718
- * This is a convenience wrapper around Map.has().
719
- *
720
- * @param capSet - The capability set to check
721
- * @param name - The capability name to look for
722
- * @returns True if the capability is present
723
- *
724
- * @example
725
- * ```typescript
726
- * const caps: CapabilitySet = {
727
- * version: 1,
728
- * capabilities: new Map([
729
- * ['multi_ack', undefined],
730
- * ['side-band-64k', undefined],
731
- * ['agent', 'git/2.30.0']
732
- * ])
733
- * };
734
- *
735
- * hasCapability(caps, 'multi_ack'); // true
736
- * hasCapability(caps, 'side-band-64k'); // true
737
- * hasCapability(caps, 'thin-pack'); // false
738
- * ```
739
- */
740
- export function hasCapability(capSet, name) {
741
- return capSet.capabilities.has(name);
742
- }
743
- /**
744
- * Get the value of a capability (if it has one).
745
- *
746
- * @description
747
- * Retrieves the value associated with a capability. Returns undefined
748
- * if the capability is not present or has no value.
749
- *
750
- * @param capSet - The capability set to query
751
- * @param name - The capability name
752
- * @returns The capability value, or undefined if not present/no value
753
- *
754
- * @example
755
- * ```typescript
756
- * const caps: CapabilitySet = {
757
- * version: 1,
758
- * capabilities: new Map([
759
- * ['multi_ack', undefined],
760
- * ['agent', 'git/2.30.0'],
761
- * ['symref', 'HEAD:refs/heads/main']
762
- * ])
763
- * };
764
- *
765
- * getCapabilityValue(caps, 'agent'); // 'git/2.30.0'
766
- * getCapabilityValue(caps, 'symref'); // 'HEAD:refs/heads/main'
767
- * getCapabilityValue(caps, 'multi_ack'); // undefined (present but no value)
768
- * getCapabilityValue(caps, 'thin-pack'); // undefined (not present)
769
- * ```
770
- */
771
- export function getCapabilityValue(capSet, name) {
772
- return capSet.capabilities.get(name);
773
- }
774
- /**
775
- * Create a capability set from entries.
776
- *
777
- * @description
778
- * Constructs a CapabilitySet from an array of capability entries.
779
- * This is useful for creating capability sets programmatically.
780
- *
781
- * @param version - Protocol version (1 or 2)
782
- * @param entries - Array of capability entries
783
- * @returns A new CapabilitySet
784
- *
785
- * @example
786
- * ```typescript
787
- * const entries: CapabilityEntry[] = [
788
- * { name: 'multi_ack_detailed' },
789
- * { name: 'side-band-64k' },
790
- * { name: 'agent', value: 'gitdo/1.0' }
791
- * ];
792
- *
793
- * const capSet = createCapabilitySet(1, entries);
794
- * // {
795
- * // version: 1,
796
- * // capabilities: Map {
797
- * // 'multi_ack_detailed' => undefined,
798
- * // 'side-band-64k' => undefined,
799
- * // 'agent' => 'gitdo/1.0'
800
- * // }
801
- * // }
802
- * ```
803
- */
804
- export function createCapabilitySet(version, entries) {
805
- const capabilities = new Map();
806
- for (const entry of entries) {
807
- capabilities.set(entry.name, entry.value);
808
- }
809
- return {
810
- version,
811
- capabilities,
812
- };
813
- }
814
- /**
815
- * Select optimal capabilities for a fetch operation.
816
- *
817
- * @description
818
- * Filters client-preferred capabilities to only those supported by the server.
819
- * The client's values are preserved (not the server's), maintaining client
820
- * identification and preferences.
821
- *
822
- * @param serverCaps - Server's advertised capabilities
823
- * @param clientPrefs - Client's preferred capabilities (in priority order)
824
- * @returns Array of capabilities to use (subset of client preferences)
825
- *
826
- * @example
827
- * ```typescript
828
- * const serverCaps: CapabilitySet = {
829
- * version: 1,
830
- * capabilities: new Map([
831
- * ['multi_ack', undefined],
832
- * ['side-band-64k', undefined],
833
- * ['thin-pack', undefined]
834
- * ])
835
- * };
836
- *
837
- * const clientPrefs: CapabilityEntry[] = [
838
- * { name: 'multi_ack_detailed' }, // Not supported by server
839
- * { name: 'multi_ack' }, // Supported
840
- * { name: 'side-band-64k' }, // Supported
841
- * { name: 'ofs-delta' }, // Not supported
842
- * { name: 'agent', value: 'gitdo/1.0' } // Not in server caps
843
- * ];
844
- *
845
- * const selected = selectFetchCapabilities(serverCaps, clientPrefs);
846
- * // [
847
- * // { name: 'multi_ack' },
848
- * // { name: 'side-band-64k' }
849
- * // ]
850
- * ```
851
- */
852
- export function selectFetchCapabilities(serverCaps, clientPrefs) {
853
- const selected = [];
854
- for (const pref of clientPrefs) {
855
- if (serverCaps.capabilities.has(pref.name)) {
856
- // Use the client's value, not the server's
857
- selected.push(pref);
858
- }
859
- }
860
- return selected;
861
- }
862
- // ============================================================================
863
- // Validation Functions
864
- // ============================================================================
865
- /**
866
- * Validate that a capability name is well-formed.
867
- *
868
- * @description
869
- * Checks that a capability name follows the Git protocol requirements.
870
- * Capability names must be non-empty and cannot contain spaces, NUL bytes,
871
- * or newline characters.
872
- *
873
- * @param name - The capability name to validate
874
- * @returns True if the name is valid
875
- *
876
- * @example
877
- * ```typescript
878
- * isValidCapabilityName('multi_ack'); // true
879
- * isValidCapabilityName('side-band-64k'); // true
880
- * isValidCapabilityName('agent'); // true
881
- * isValidCapabilityName(''); // false (empty)
882
- * isValidCapabilityName('multi ack'); // false (contains space)
883
- * isValidCapabilityName('cap\0name'); // false (contains NUL)
884
- * isValidCapabilityName('cap\nname'); // false (contains newline)
885
- * ```
886
- */
887
- export function isValidCapabilityName(name) {
888
- if (name === '') {
889
- return false;
890
- }
891
- // Check for invalid characters (spaces, NUL, newlines)
892
- if (/[\s\0\n]/.test(name)) {
893
- return false;
894
- }
895
- return true;
896
- }
897
- /**
898
- * Validate that required capabilities are present.
899
- *
900
- * @description
901
- * Checks a capability set for the presence of all required capabilities.
902
- * Returns an array of missing capability names. An empty array indicates
903
- * all requirements are satisfied.
904
- *
905
- * @param capSet - The capability set to validate
906
- * @param required - Array of required capability names
907
- * @returns Array of missing capability names (empty if all present)
908
- *
909
- * @example
910
- * ```typescript
911
- * const caps: CapabilitySet = {
912
- * version: 1,
913
- * capabilities: new Map([
914
- * ['multi_ack', undefined],
915
- * ['side-band-64k', undefined]
916
- * ])
917
- * };
918
- *
919
- * // All present
920
- * const missing1 = validateRequiredCapabilities(caps, ['multi_ack']);
921
- * // []
922
- *
923
- * // Some missing
924
- * const missing2 = validateRequiredCapabilities(caps, ['multi_ack', 'thin-pack', 'ofs-delta']);
925
- * // ['thin-pack', 'ofs-delta']
926
- *
927
- * if (missing2.length > 0) {
928
- * throw new Error(`Server missing capabilities: ${missing2.join(', ')}`);
929
- * }
930
- * ```
931
- */
932
- export function validateRequiredCapabilities(capSet, required) {
933
- const missing = [];
934
- for (const reqCap of required) {
935
- if (!capSet.capabilities.has(reqCap)) {
936
- missing.push(reqCap);
937
- }
938
- }
939
- return missing;
940
- }
941
- //# sourceMappingURL=capabilities.js.map