gitx.do 0.1.1 → 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 (356) 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 +14 -469
  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 -176
  20. package/dist/cli/commands/add.d.ts.map +0 -1
  21. package/dist/cli/commands/add.js +0 -979
  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/checkout.d.ts +0 -73
  32. package/dist/cli/commands/checkout.d.ts.map +0 -1
  33. package/dist/cli/commands/checkout.js +0 -725
  34. package/dist/cli/commands/checkout.js.map +0 -1
  35. package/dist/cli/commands/commit.d.ts +0 -182
  36. package/dist/cli/commands/commit.d.ts.map +0 -1
  37. package/dist/cli/commands/commit.js +0 -457
  38. package/dist/cli/commands/commit.js.map +0 -1
  39. package/dist/cli/commands/diff.d.ts +0 -464
  40. package/dist/cli/commands/diff.d.ts.map +0 -1
  41. package/dist/cli/commands/diff.js +0 -959
  42. package/dist/cli/commands/diff.js.map +0 -1
  43. package/dist/cli/commands/log.d.ts +0 -239
  44. package/dist/cli/commands/log.d.ts.map +0 -1
  45. package/dist/cli/commands/log.js +0 -535
  46. package/dist/cli/commands/log.js.map +0 -1
  47. package/dist/cli/commands/merge.d.ts +0 -106
  48. package/dist/cli/commands/merge.d.ts.map +0 -1
  49. package/dist/cli/commands/merge.js +0 -852
  50. package/dist/cli/commands/merge.js.map +0 -1
  51. package/dist/cli/commands/review.d.ts +0 -457
  52. package/dist/cli/commands/review.d.ts.map +0 -1
  53. package/dist/cli/commands/review.js +0 -558
  54. package/dist/cli/commands/review.js.map +0 -1
  55. package/dist/cli/commands/stash.d.ts +0 -157
  56. package/dist/cli/commands/stash.d.ts.map +0 -1
  57. package/dist/cli/commands/stash.js +0 -655
  58. package/dist/cli/commands/stash.js.map +0 -1
  59. package/dist/cli/commands/status.d.ts +0 -269
  60. package/dist/cli/commands/status.d.ts.map +0 -1
  61. package/dist/cli/commands/status.js +0 -492
  62. package/dist/cli/commands/status.js.map +0 -1
  63. package/dist/cli/commands/web.d.ts +0 -199
  64. package/dist/cli/commands/web.d.ts.map +0 -1
  65. package/dist/cli/commands/web.js +0 -697
  66. package/dist/cli/commands/web.js.map +0 -1
  67. package/dist/cli/fs-adapter.d.ts +0 -656
  68. package/dist/cli/fs-adapter.d.ts.map +0 -1
  69. package/dist/cli/fs-adapter.js +0 -1177
  70. package/dist/cli/fs-adapter.js.map +0 -1
  71. package/dist/cli/fsx-cli-adapter.d.ts +0 -359
  72. package/dist/cli/fsx-cli-adapter.d.ts.map +0 -1
  73. package/dist/cli/fsx-cli-adapter.js +0 -619
  74. package/dist/cli/fsx-cli-adapter.js.map +0 -1
  75. package/dist/cli/index.d.ts +0 -387
  76. package/dist/cli/index.d.ts.map +0 -1
  77. package/dist/cli/index.js +0 -579
  78. package/dist/cli/index.js.map +0 -1
  79. package/dist/cli/ui/components/DiffView.d.ts +0 -12
  80. package/dist/cli/ui/components/DiffView.d.ts.map +0 -1
  81. package/dist/cli/ui/components/DiffView.js +0 -11
  82. package/dist/cli/ui/components/DiffView.js.map +0 -1
  83. package/dist/cli/ui/components/ErrorDisplay.d.ts +0 -10
  84. package/dist/cli/ui/components/ErrorDisplay.d.ts.map +0 -1
  85. package/dist/cli/ui/components/ErrorDisplay.js +0 -11
  86. package/dist/cli/ui/components/ErrorDisplay.js.map +0 -1
  87. package/dist/cli/ui/components/FuzzySearch.d.ts +0 -15
  88. package/dist/cli/ui/components/FuzzySearch.d.ts.map +0 -1
  89. package/dist/cli/ui/components/FuzzySearch.js +0 -12
  90. package/dist/cli/ui/components/FuzzySearch.js.map +0 -1
  91. package/dist/cli/ui/components/LoadingSpinner.d.ts +0 -10
  92. package/dist/cli/ui/components/LoadingSpinner.d.ts.map +0 -1
  93. package/dist/cli/ui/components/LoadingSpinner.js +0 -10
  94. package/dist/cli/ui/components/LoadingSpinner.js.map +0 -1
  95. package/dist/cli/ui/components/NavigationList.d.ts +0 -14
  96. package/dist/cli/ui/components/NavigationList.d.ts.map +0 -1
  97. package/dist/cli/ui/components/NavigationList.js +0 -11
  98. package/dist/cli/ui/components/NavigationList.js.map +0 -1
  99. package/dist/cli/ui/components/ScrollableContent.d.ts +0 -13
  100. package/dist/cli/ui/components/ScrollableContent.d.ts.map +0 -1
  101. package/dist/cli/ui/components/ScrollableContent.js +0 -11
  102. package/dist/cli/ui/components/ScrollableContent.js.map +0 -1
  103. package/dist/cli/ui/components/index.d.ts +0 -7
  104. package/dist/cli/ui/components/index.d.ts.map +0 -1
  105. package/dist/cli/ui/components/index.js +0 -9
  106. package/dist/cli/ui/components/index.js.map +0 -1
  107. package/dist/cli/ui/terminal-ui.d.ts +0 -85
  108. package/dist/cli/ui/terminal-ui.d.ts.map +0 -1
  109. package/dist/cli/ui/terminal-ui.js +0 -121
  110. package/dist/cli/ui/terminal-ui.js.map +0 -1
  111. package/dist/do/BashModule.d.ts +0 -871
  112. package/dist/do/BashModule.d.ts.map +0 -1
  113. package/dist/do/BashModule.js +0 -1143
  114. package/dist/do/BashModule.js.map +0 -1
  115. package/dist/do/FsModule.d.ts +0 -612
  116. package/dist/do/FsModule.d.ts.map +0 -1
  117. package/dist/do/FsModule.js +0 -1120
  118. package/dist/do/FsModule.js.map +0 -1
  119. package/dist/do/GitModule.d.ts +0 -635
  120. package/dist/do/GitModule.d.ts.map +0 -1
  121. package/dist/do/GitModule.js +0 -784
  122. package/dist/do/GitModule.js.map +0 -1
  123. package/dist/do/GitRepoDO.d.ts +0 -281
  124. package/dist/do/GitRepoDO.d.ts.map +0 -1
  125. package/dist/do/GitRepoDO.js +0 -479
  126. package/dist/do/GitRepoDO.js.map +0 -1
  127. package/dist/do/bash-ast.d.ts +0 -246
  128. package/dist/do/bash-ast.d.ts.map +0 -1
  129. package/dist/do/bash-ast.js +0 -888
  130. package/dist/do/bash-ast.js.map +0 -1
  131. package/dist/do/container-executor.d.ts +0 -491
  132. package/dist/do/container-executor.d.ts.map +0 -1
  133. package/dist/do/container-executor.js +0 -731
  134. package/dist/do/container-executor.js.map +0 -1
  135. package/dist/do/index.d.ts +0 -53
  136. package/dist/do/index.d.ts.map +0 -1
  137. package/dist/do/index.js +0 -91
  138. package/dist/do/index.js.map +0 -1
  139. package/dist/do/tiered-storage.d.ts +0 -403
  140. package/dist/do/tiered-storage.d.ts.map +0 -1
  141. package/dist/do/tiered-storage.js +0 -689
  142. package/dist/do/tiered-storage.js.map +0 -1
  143. package/dist/do/withBash.d.ts +0 -231
  144. package/dist/do/withBash.d.ts.map +0 -1
  145. package/dist/do/withBash.js +0 -244
  146. package/dist/do/withBash.js.map +0 -1
  147. package/dist/do/withFs.d.ts +0 -237
  148. package/dist/do/withFs.d.ts.map +0 -1
  149. package/dist/do/withFs.js +0 -387
  150. package/dist/do/withFs.js.map +0 -1
  151. package/dist/do/withGit.d.ts +0 -180
  152. package/dist/do/withGit.d.ts.map +0 -1
  153. package/dist/do/withGit.js +0 -271
  154. package/dist/do/withGit.js.map +0 -1
  155. package/dist/durable-object/object-store.d.ts +0 -633
  156. package/dist/durable-object/object-store.d.ts.map +0 -1
  157. package/dist/durable-object/object-store.js +0 -1164
  158. package/dist/durable-object/object-store.js.map +0 -1
  159. package/dist/durable-object/schema.d.ts.map +0 -1
  160. package/dist/durable-object/schema.js.map +0 -1
  161. package/dist/durable-object/wal.d.ts +0 -416
  162. package/dist/durable-object/wal.d.ts.map +0 -1
  163. package/dist/durable-object/wal.js +0 -445
  164. package/dist/durable-object/wal.js.map +0 -1
  165. package/dist/mcp/adapter.d.ts +0 -772
  166. package/dist/mcp/adapter.d.ts.map +0 -1
  167. package/dist/mcp/adapter.js +0 -895
  168. package/dist/mcp/adapter.js.map +0 -1
  169. package/dist/mcp/sandbox/miniflare-evaluator.d.ts +0 -22
  170. package/dist/mcp/sandbox/miniflare-evaluator.d.ts.map +0 -1
  171. package/dist/mcp/sandbox/miniflare-evaluator.js +0 -140
  172. package/dist/mcp/sandbox/miniflare-evaluator.js.map +0 -1
  173. package/dist/mcp/sandbox/object-store-proxy.d.ts +0 -32
  174. package/dist/mcp/sandbox/object-store-proxy.d.ts.map +0 -1
  175. package/dist/mcp/sandbox/object-store-proxy.js +0 -30
  176. package/dist/mcp/sandbox/object-store-proxy.js.map +0 -1
  177. package/dist/mcp/sandbox/template.d.ts +0 -17
  178. package/dist/mcp/sandbox/template.d.ts.map +0 -1
  179. package/dist/mcp/sandbox/template.js +0 -71
  180. package/dist/mcp/sandbox/template.js.map +0 -1
  181. package/dist/mcp/sandbox.d.ts +0 -764
  182. package/dist/mcp/sandbox.d.ts.map +0 -1
  183. package/dist/mcp/sandbox.js +0 -1362
  184. package/dist/mcp/sandbox.js.map +0 -1
  185. package/dist/mcp/sdk-adapter.d.ts +0 -835
  186. package/dist/mcp/sdk-adapter.d.ts.map +0 -1
  187. package/dist/mcp/sdk-adapter.js +0 -974
  188. package/dist/mcp/sdk-adapter.js.map +0 -1
  189. package/dist/mcp/tools/do.d.ts +0 -32
  190. package/dist/mcp/tools/do.d.ts.map +0 -1
  191. package/dist/mcp/tools/do.js +0 -117
  192. package/dist/mcp/tools/do.js.map +0 -1
  193. package/dist/mcp/tools.d.ts +0 -548
  194. package/dist/mcp/tools.d.ts.map +0 -1
  195. package/dist/mcp/tools.js +0 -3170
  196. package/dist/mcp/tools.js.map +0 -1
  197. package/dist/ops/blame.d.ts +0 -551
  198. package/dist/ops/blame.d.ts.map +0 -1
  199. package/dist/ops/blame.js +0 -1037
  200. package/dist/ops/blame.js.map +0 -1
  201. package/dist/ops/branch.d.ts +0 -766
  202. package/dist/ops/branch.d.ts.map +0 -1
  203. package/dist/ops/branch.js +0 -950
  204. package/dist/ops/branch.js.map +0 -1
  205. package/dist/ops/commit-traversal.d.ts +0 -349
  206. package/dist/ops/commit-traversal.d.ts.map +0 -1
  207. package/dist/ops/commit-traversal.js +0 -821
  208. package/dist/ops/commit-traversal.js.map +0 -1
  209. package/dist/ops/commit.d.ts +0 -555
  210. package/dist/ops/commit.d.ts.map +0 -1
  211. package/dist/ops/commit.js +0 -826
  212. package/dist/ops/commit.js.map +0 -1
  213. package/dist/ops/merge-base.d.ts +0 -397
  214. package/dist/ops/merge-base.d.ts.map +0 -1
  215. package/dist/ops/merge-base.js +0 -691
  216. package/dist/ops/merge-base.js.map +0 -1
  217. package/dist/ops/merge.d.ts +0 -855
  218. package/dist/ops/merge.d.ts.map +0 -1
  219. package/dist/ops/merge.js +0 -1551
  220. package/dist/ops/merge.js.map +0 -1
  221. package/dist/ops/tag.d.ts +0 -247
  222. package/dist/ops/tag.d.ts.map +0 -1
  223. package/dist/ops/tag.js +0 -649
  224. package/dist/ops/tag.js.map +0 -1
  225. package/dist/ops/tree-builder.d.ts +0 -178
  226. package/dist/ops/tree-builder.d.ts.map +0 -1
  227. package/dist/ops/tree-builder.js +0 -271
  228. package/dist/ops/tree-builder.js.map +0 -1
  229. package/dist/ops/tree-diff.d.ts +0 -291
  230. package/dist/ops/tree-diff.d.ts.map +0 -1
  231. package/dist/ops/tree-diff.js +0 -705
  232. package/dist/ops/tree-diff.js.map +0 -1
  233. package/dist/pack/delta.d.ts +0 -248
  234. package/dist/pack/delta.d.ts.map +0 -1
  235. package/dist/pack/delta.js +0 -740
  236. package/dist/pack/delta.js.map +0 -1
  237. package/dist/pack/format.d.ts +0 -446
  238. package/dist/pack/format.d.ts.map +0 -1
  239. package/dist/pack/format.js +0 -572
  240. package/dist/pack/format.js.map +0 -1
  241. package/dist/pack/full-generation.d.ts +0 -612
  242. package/dist/pack/full-generation.d.ts.map +0 -1
  243. package/dist/pack/full-generation.js +0 -1378
  244. package/dist/pack/full-generation.js.map +0 -1
  245. package/dist/pack/generation.d.ts +0 -441
  246. package/dist/pack/generation.d.ts.map +0 -1
  247. package/dist/pack/generation.js +0 -707
  248. package/dist/pack/generation.js.map +0 -1
  249. package/dist/pack/index.d.ts +0 -502
  250. package/dist/pack/index.d.ts.map +0 -1
  251. package/dist/pack/index.js +0 -833
  252. package/dist/pack/index.js.map +0 -1
  253. package/dist/refs/branch.d.ts +0 -683
  254. package/dist/refs/branch.d.ts.map +0 -1
  255. package/dist/refs/branch.js +0 -881
  256. package/dist/refs/branch.js.map +0 -1
  257. package/dist/refs/storage.d.ts +0 -833
  258. package/dist/refs/storage.d.ts.map +0 -1
  259. package/dist/refs/storage.js +0 -1023
  260. package/dist/refs/storage.js.map +0 -1
  261. package/dist/refs/tag.d.ts +0 -860
  262. package/dist/refs/tag.d.ts.map +0 -1
  263. package/dist/refs/tag.js +0 -996
  264. package/dist/refs/tag.js.map +0 -1
  265. package/dist/storage/backend.d.ts +0 -425
  266. package/dist/storage/backend.d.ts.map +0 -1
  267. package/dist/storage/backend.js +0 -41
  268. package/dist/storage/backend.js.map +0 -1
  269. package/dist/storage/fsx-adapter.d.ts +0 -204
  270. package/dist/storage/fsx-adapter.d.ts.map +0 -1
  271. package/dist/storage/fsx-adapter.js +0 -518
  272. package/dist/storage/fsx-adapter.js.map +0 -1
  273. package/dist/storage/lru-cache.d.ts +0 -691
  274. package/dist/storage/lru-cache.d.ts.map +0 -1
  275. package/dist/storage/lru-cache.js +0 -813
  276. package/dist/storage/lru-cache.js.map +0 -1
  277. package/dist/storage/object-index.d.ts +0 -585
  278. package/dist/storage/object-index.d.ts.map +0 -1
  279. package/dist/storage/object-index.js +0 -532
  280. package/dist/storage/object-index.js.map +0 -1
  281. package/dist/storage/r2-pack.d.ts +0 -1257
  282. package/dist/storage/r2-pack.d.ts.map +0 -1
  283. package/dist/storage/r2-pack.js +0 -1773
  284. package/dist/storage/r2-pack.js.map +0 -1
  285. package/dist/tiered/cdc-pipeline.d.ts +0 -1888
  286. package/dist/tiered/cdc-pipeline.d.ts.map +0 -1
  287. package/dist/tiered/cdc-pipeline.js +0 -1880
  288. package/dist/tiered/cdc-pipeline.js.map +0 -1
  289. package/dist/tiered/migration.d.ts +0 -1104
  290. package/dist/tiered/migration.d.ts.map +0 -1
  291. package/dist/tiered/migration.js +0 -1217
  292. package/dist/tiered/migration.js.map +0 -1
  293. package/dist/tiered/parquet-writer.d.ts +0 -1145
  294. package/dist/tiered/parquet-writer.d.ts.map +0 -1
  295. package/dist/tiered/parquet-writer.js +0 -1183
  296. package/dist/tiered/parquet-writer.js.map +0 -1
  297. package/dist/tiered/read-path.d.ts +0 -835
  298. package/dist/tiered/read-path.d.ts.map +0 -1
  299. package/dist/tiered/read-path.js +0 -487
  300. package/dist/tiered/read-path.js.map +0 -1
  301. package/dist/types/capability.d.ts +0 -1385
  302. package/dist/types/capability.d.ts.map +0 -1
  303. package/dist/types/capability.js +0 -36
  304. package/dist/types/capability.js.map +0 -1
  305. package/dist/types/index.d.ts +0 -13
  306. package/dist/types/index.d.ts.map +0 -1
  307. package/dist/types/index.js +0 -18
  308. package/dist/types/index.js.map +0 -1
  309. package/dist/types/interfaces.d.ts +0 -673
  310. package/dist/types/interfaces.d.ts.map +0 -1
  311. package/dist/types/interfaces.js +0 -26
  312. package/dist/types/interfaces.js.map +0 -1
  313. package/dist/types/objects.d.ts +0 -692
  314. package/dist/types/objects.d.ts.map +0 -1
  315. package/dist/types/objects.js +0 -837
  316. package/dist/types/objects.js.map +0 -1
  317. package/dist/types/storage.d.ts +0 -603
  318. package/dist/types/storage.d.ts.map +0 -1
  319. package/dist/types/storage.js +0 -191
  320. package/dist/types/storage.js.map +0 -1
  321. package/dist/types/worker-loader.d.ts +0 -60
  322. package/dist/types/worker-loader.d.ts.map +0 -1
  323. package/dist/types/worker-loader.js +0 -62
  324. package/dist/types/worker-loader.js.map +0 -1
  325. package/dist/utils/hash.d.ts +0 -198
  326. package/dist/utils/hash.d.ts.map +0 -1
  327. package/dist/utils/hash.js +0 -272
  328. package/dist/utils/hash.js.map +0 -1
  329. package/dist/utils/sha1.d.ts +0 -325
  330. package/dist/utils/sha1.d.ts.map +0 -1
  331. package/dist/utils/sha1.js +0 -635
  332. package/dist/utils/sha1.js.map +0 -1
  333. package/dist/wire/capabilities.d.ts +0 -1044
  334. package/dist/wire/capabilities.d.ts.map +0 -1
  335. package/dist/wire/capabilities.js +0 -941
  336. package/dist/wire/capabilities.js.map +0 -1
  337. package/dist/wire/path-security.d.ts +0 -157
  338. package/dist/wire/path-security.d.ts.map +0 -1
  339. package/dist/wire/path-security.js +0 -307
  340. package/dist/wire/path-security.js.map +0 -1
  341. package/dist/wire/pkt-line.d.ts +0 -345
  342. package/dist/wire/pkt-line.d.ts.map +0 -1
  343. package/dist/wire/pkt-line.js +0 -381
  344. package/dist/wire/pkt-line.js.map +0 -1
  345. package/dist/wire/receive-pack.d.ts +0 -1059
  346. package/dist/wire/receive-pack.d.ts.map +0 -1
  347. package/dist/wire/receive-pack.js +0 -1414
  348. package/dist/wire/receive-pack.js.map +0 -1
  349. package/dist/wire/smart-http.d.ts +0 -799
  350. package/dist/wire/smart-http.d.ts.map +0 -1
  351. package/dist/wire/smart-http.js +0 -945
  352. package/dist/wire/smart-http.js.map +0 -1
  353. package/dist/wire/upload-pack.d.ts +0 -727
  354. package/dist/wire/upload-pack.d.ts.map +0 -1
  355. package/dist/wire/upload-pack.js +0 -1141
  356. package/dist/wire/upload-pack.js.map +0 -1
package/dist/refs/tag.js DELETED
@@ -1,996 +0,0 @@
1
- /**
2
- * @fileoverview Git Tag Operations
3
- *
4
- * This module provides comprehensive tag management functionality including
5
- * creation (lightweight and annotated), deletion, listing, and verification.
6
- *
7
- * **Tag Types in Git**:
8
- * - **Lightweight tags**: Simple refs under refs/tags/ pointing to commits
9
- * - **Annotated tags**: Refs pointing to tag objects containing metadata
10
- * (tagger, date, message, and optional GPG signature)
11
- *
12
- * Annotated tags are recommended for releases as they include metadata
13
- * and can be cryptographically signed.
14
- *
15
- * @module refs/tag
16
- *
17
- * @example
18
- * ```typescript
19
- * import { TagManager, createTag, listTags } from './refs/tag'
20
- *
21
- * // Create manager
22
- * const manager = new TagManager(refStorage, objectStorage, gpgSigner)
23
- *
24
- * // Create annotated tag
25
- * const tag = await manager.createTag('v1.0.0', commitSha, {
26
- * annotated: true,
27
- * message: 'Release 1.0.0',
28
- * tagger: { name: 'Alice', email: 'alice@example.com', timestamp: Date.now()/1000, timezone: '+0000' }
29
- * })
30
- *
31
- * // List version tags
32
- * const versions = await listTags(manager, { pattern: 'v*' })
33
- * ```
34
- */
35
- // Re-export RefStorage for backward compatibility
36
- export { RefStorage } from './storage';
37
- /**
38
- * Error thrown when a tag operation fails.
39
- *
40
- * @description
41
- * Provides structured error information with error code
42
- * for programmatic error handling.
43
- *
44
- * @example
45
- * ```typescript
46
- * try {
47
- * await manager.createTag('v1.0.0', 'abc123')
48
- * } catch (e) {
49
- * if (e instanceof TagError) {
50
- * switch (e.code) {
51
- * case 'TAG_EXISTS':
52
- * console.log('Tag already exists, use force=true to overwrite')
53
- * break
54
- * case 'MESSAGE_REQUIRED':
55
- * console.log('Annotated tags require a message')
56
- * break
57
- * }
58
- * }
59
- * }
60
- * ```
61
- */
62
- export class TagError extends Error {
63
- code;
64
- tagName;
65
- /**
66
- * Create a new TagError.
67
- *
68
- * @param message - Human-readable error description
69
- * @param code - Error code for programmatic handling
70
- * @param tagName - The tag that caused the error (optional)
71
- */
72
- constructor(message, code, tagName) {
73
- super(message);
74
- this.code = code;
75
- this.tagName = tagName;
76
- this.name = 'TagError';
77
- }
78
- }
79
- // ============================================================================
80
- // TagManager Class
81
- // ============================================================================
82
- /**
83
- * Tag manager for handling Git tag operations.
84
- *
85
- * @description
86
- * Provides a comprehensive API for tag management including both
87
- * lightweight and annotated tags. Uses RefStorage for refs and
88
- * TagObjectStorage for tag objects.
89
- *
90
- * Note: Most methods are currently stubs (TODO) and will throw 'Not implemented'.
91
- * These will be implemented in the GREEN phase of TDD development.
92
- *
93
- * @example
94
- * ```typescript
95
- * const manager = new TagManager(refStorage, objectStorage, gpgSigner)
96
- *
97
- * // Create a release tag
98
- * const tag = await manager.createTag('v1.0.0', commitSha, {
99
- * annotated: true,
100
- * message: 'Version 1.0.0 release',
101
- * tagger: { name: 'Alice', email: 'alice@example.com', timestamp: 1704067200, timezone: '+0000' }
102
- * })
103
- *
104
- * // List version tags
105
- * const versions = await manager.listTags({ pattern: 'v*' })
106
- *
107
- * // Verify signed tag
108
- * const verification = await manager.verifyTag('v1.0.0')
109
- * ```
110
- */
111
- export class TagManager {
112
- refStorage;
113
- objectStorage;
114
- gpgSigner;
115
- // Simple in-memory lock to handle concurrent tag creation
116
- pendingCreations = new Set();
117
- /**
118
- * Create a new TagManager.
119
- *
120
- * @param refStorage - RefStorage instance for managing tag refs
121
- * @param objectStorage - Storage for reading/writing tag objects
122
- * @param gpgSigner - Optional GPG signer for signed tags
123
- */
124
- constructor(refStorage, objectStorage, gpgSigner) {
125
- this.refStorage = refStorage;
126
- this.objectStorage = objectStorage;
127
- this.gpgSigner = gpgSigner;
128
- }
129
- /**
130
- * Create a new tag.
131
- *
132
- * @description
133
- * Creates either a lightweight or annotated tag pointing to the
134
- * specified target. For annotated tags, creates a tag object with
135
- * metadata and optionally signs it.
136
- *
137
- * @param name - Tag name (without refs/tags/ prefix)
138
- * @param target - Target SHA to tag (usually a commit)
139
- * @param options - Creation options
140
- * @returns The created tag
141
- * @throws TagError with code 'INVALID_TAG_NAME' if name is invalid
142
- * @throws TagError with code 'TAG_EXISTS' if tag exists and not forcing
143
- * @throws TagError with code 'MESSAGE_REQUIRED' for annotated tag without message
144
- * @throws TagError with code 'GPG_ERROR' if signing fails
145
- *
146
- * @example
147
- * ```typescript
148
- * // Create lightweight tag
149
- * const light = await manager.createTag('v0.1.0', commitSha)
150
- *
151
- * // Create annotated tag
152
- * const annotated = await manager.createTag('v1.0.0', commitSha, {
153
- * annotated: true,
154
- * message: 'Release 1.0.0',
155
- * tagger: { name: 'Alice', email: 'alice@example.com', timestamp: 1704067200, timezone: '+0000' }
156
- * })
157
- *
158
- * // Create signed tag
159
- * const signed = await manager.createTag('v1.0.0', commitSha, {
160
- * annotated: true,
161
- * message: 'Release 1.0.0',
162
- * sign: true
163
- * })
164
- * ```
165
- */
166
- async createTag(name, target, options) {
167
- // Validate tag name
168
- if (!isValidTagName(name)) {
169
- throw new TagError(`Invalid tag name: ${name}`, 'INVALID_TAG_NAME', name);
170
- }
171
- const refName = `refs/tags/${name}`;
172
- // Synchronous check-and-lock to handle concurrent creation attempts
173
- if (this.pendingCreations.has(name)) {
174
- throw new TagError(`Tag already exists: ${name}`, 'TAG_EXISTS', name);
175
- }
176
- // Check if tag already exists
177
- const existingSha = await this.refStorage.getRef(refName);
178
- if (existingSha !== null && !options?.force) {
179
- throw new TagError(`Tag already exists: ${name}`, 'TAG_EXISTS', name);
180
- }
181
- // Mark as pending (synchronous operation for atomicity)
182
- if (!options?.force) {
183
- if (this.pendingCreations.has(name)) {
184
- throw new TagError(`Tag already exists: ${name}`, 'TAG_EXISTS', name);
185
- }
186
- this.pendingCreations.add(name);
187
- }
188
- // Determine if this should be an annotated tag
189
- const isAnnotated = options?.annotated === true || (options?.message !== undefined && options?.message !== '');
190
- try {
191
- if (isAnnotated) {
192
- // Validate message for annotated tags
193
- const rawMessage = options?.message;
194
- if (!rawMessage || rawMessage.trim().length === 0) {
195
- throw new TagError('Annotated tag requires a message', 'MESSAGE_REQUIRED', name);
196
- }
197
- const formattedMessage = formatTagMessage(rawMessage);
198
- // Validate tagger (can have timestamp set to 0 or undefined, we'll use current time)
199
- let tagger = options?.tagger;
200
- if (tagger && tagger.timestamp === undefined) {
201
- tagger = {
202
- ...tagger,
203
- timestamp: Math.floor(Date.now() / 1000)
204
- };
205
- }
206
- // Handle signing
207
- let signature;
208
- let finalMessage = formattedMessage;
209
- if (options?.sign) {
210
- if (!this.gpgSigner) {
211
- throw new TagError('GPG signer not available', 'GPG_ERROR', name);
212
- }
213
- // Sign the tag content
214
- const encoder = new TextEncoder();
215
- signature = await this.gpgSigner.sign(encoder.encode(formattedMessage), options?.keyId);
216
- // Append signature to message (Git stores signature in the tag object)
217
- finalMessage = formattedMessage + '\n' + signature;
218
- }
219
- // Get the target object type
220
- const targetType = await this.objectStorage.readObjectType(target);
221
- // Create tag object
222
- const tagObj = {
223
- object: target,
224
- objectType: targetType || 'commit',
225
- name,
226
- tagger,
227
- message: finalMessage
228
- };
229
- // Write tag object and get its SHA
230
- const tagObjSha = await this.objectStorage.writeTagObject(tagObj);
231
- // Write ref pointing to tag object
232
- await this.refStorage.setRef(refName, tagObjSha);
233
- return {
234
- name,
235
- type: 'annotated',
236
- sha: tagObjSha,
237
- targetSha: target,
238
- targetType: targetType || 'commit',
239
- tagger,
240
- message: formattedMessage,
241
- signature
242
- };
243
- }
244
- else {
245
- // Lightweight tag - just write ref pointing to target
246
- await this.refStorage.setRef(refName, target);
247
- return {
248
- name,
249
- type: 'lightweight',
250
- sha: target
251
- };
252
- }
253
- }
254
- finally {
255
- // Clear the pending lock
256
- this.pendingCreations.delete(name);
257
- }
258
- }
259
- /**
260
- * Delete a tag.
261
- *
262
- * @description
263
- * Removes a tag ref. Does not delete the tag object (if annotated)
264
- * as it may be referenced elsewhere (reflog, etc.).
265
- *
266
- * @param name - Tag name to delete
267
- * @param options - Deletion options
268
- * @returns True if tag was deleted, false if it didn't exist (with force)
269
- * @throws TagError with code 'TAG_NOT_FOUND' if tag doesn't exist (without force)
270
- *
271
- * @example
272
- * ```typescript
273
- * await manager.deleteTag('v0.9.0-beta')
274
- *
275
- * // Delete even if doesn't exist
276
- * await manager.deleteTag('maybe-exists', { force: true })
277
- * ```
278
- */
279
- async deleteTag(name, options) {
280
- const refName = `refs/tags/${name}`;
281
- // Check if tag exists
282
- const existingSha = await this.refStorage.getRef(refName);
283
- if (existingSha === null) {
284
- if (options?.force) {
285
- return false;
286
- }
287
- throw new TagError(`Tag not found: ${name}`, 'TAG_NOT_FOUND', name);
288
- }
289
- // Delete the ref (but not the tag object)
290
- await this.refStorage.deleteRef(refName);
291
- return true;
292
- }
293
- /**
294
- * List all tags.
295
- *
296
- * @description
297
- * Returns tags matching the specified criteria.
298
- * By default returns all tags sorted by name.
299
- *
300
- * @param options - Listing options
301
- * @returns Array of tags matching criteria
302
- *
303
- * @example
304
- * ```typescript
305
- * // List all tags
306
- * const all = await manager.listTags()
307
- *
308
- * // List version tags with metadata
309
- * const versions = await manager.listTags({
310
- * pattern: 'v*',
311
- * sort: 'version',
312
- * includeMetadata: true
313
- * })
314
- *
315
- * // Get latest 5 tags
316
- * const latest = await manager.listTags({
317
- * sort: 'date',
318
- * sortDirection: 'desc',
319
- * limit: 5,
320
- * includeMetadata: true
321
- * })
322
- * ```
323
- */
324
- async listTags(options) {
325
- // List all refs under refs/tags/
326
- const tagRefs = await this.refStorage.listRefs('refs/tags/');
327
- // Determine if we need metadata (either explicitly requested or for date sorting)
328
- const needMetadata = options?.includeMetadata || options?.sort === 'date';
329
- // Build tag list
330
- let tags = [];
331
- for (const refEntry of tagRefs) {
332
- const tagName = refEntry.name.replace('refs/tags/', '');
333
- const sha = refEntry.sha;
334
- // Check if it's an annotated tag by trying to read the tag object
335
- const tagObj = await this.objectStorage.readTagObject(sha);
336
- if (tagObj) {
337
- // Annotated tag
338
- const tag = {
339
- name: tagName,
340
- type: 'annotated',
341
- sha
342
- };
343
- if (needMetadata) {
344
- tag.targetSha = tagObj.object;
345
- tag.targetType = tagObj.objectType;
346
- tag.tagger = tagObj.tagger;
347
- tag.message = tagObj.message;
348
- }
349
- tags.push(tag);
350
- }
351
- else {
352
- // Lightweight tag
353
- tags.push({
354
- name: tagName,
355
- type: 'lightweight',
356
- sha
357
- });
358
- }
359
- }
360
- // Filter by pattern if provided
361
- if (options?.pattern) {
362
- tags = filterTagsByPattern(tags, options.pattern);
363
- }
364
- // Sort tags
365
- const sortType = options?.sort || 'name';
366
- const sortDirection = options?.sortDirection || 'asc';
367
- if (sortType === 'version') {
368
- tags = sortTagsByVersion(tags, sortDirection);
369
- }
370
- else if (sortType === 'date') {
371
- // Filter out tags without timestamps when sorting by date
372
- tags = tags.filter(t => t.tagger?.timestamp !== undefined);
373
- // Sort by tagger timestamp
374
- tags.sort((a, b) => {
375
- const aTime = a.tagger.timestamp;
376
- const bTime = b.tagger.timestamp;
377
- const timeDiff = sortDirection === 'asc' ? aTime - bTime : bTime - aTime;
378
- // Secondary sort by name when timestamps are equal
379
- if (timeDiff === 0) {
380
- return a.name.localeCompare(b.name);
381
- }
382
- return timeDiff;
383
- });
384
- }
385
- else {
386
- // Sort by name (default)
387
- tags.sort((a, b) => {
388
- const cmp = a.name.localeCompare(b.name);
389
- return sortDirection === 'asc' ? cmp : -cmp;
390
- });
391
- }
392
- // Limit results
393
- if (options?.limit !== undefined) {
394
- tags = tags.slice(0, options.limit);
395
- }
396
- return tags;
397
- }
398
- /**
399
- * Get a tag by name.
400
- *
401
- * @description
402
- * Retrieves tag information. Use resolve=true to get full
403
- * annotated tag metadata.
404
- *
405
- * @param name - Tag name
406
- * @param options - Get options
407
- * @returns Tag info or null if not found
408
- *
409
- * @example
410
- * ```typescript
411
- * // Quick lookup
412
- * const tag = await manager.getTag('v1.0.0')
413
- *
414
- * // Get full metadata
415
- * const full = await manager.getTag('v1.0.0', { resolve: true })
416
- * if (full?.type === 'annotated') {
417
- * console.log(`Tagged by: ${full.tagger?.name}`)
418
- * console.log(`Message: ${full.message}`)
419
- * }
420
- * ```
421
- */
422
- async getTag(name, options) {
423
- const refName = `refs/tags/${name}`;
424
- const sha = await this.refStorage.getRef(refName);
425
- if (sha === null) {
426
- return null;
427
- }
428
- // Try to read as tag object (annotated tag)
429
- const tagObj = await this.objectStorage.readTagObject(sha);
430
- if (tagObj) {
431
- // Annotated tag
432
- const tag = {
433
- name,
434
- type: 'annotated',
435
- sha
436
- };
437
- if (options?.resolve) {
438
- tag.targetSha = tagObj.object;
439
- tag.targetType = tagObj.objectType;
440
- tag.tagger = tagObj.tagger;
441
- tag.message = tagObj.message;
442
- // Check for signature in message
443
- const parsed = parseTagMessage(tagObj.message);
444
- if (parsed.signature) {
445
- tag.signature = parsed.signature;
446
- tag.message = parsed.message;
447
- }
448
- }
449
- return tag;
450
- }
451
- else {
452
- // Lightweight tag
453
- return {
454
- name,
455
- type: 'lightweight',
456
- sha
457
- };
458
- }
459
- }
460
- /**
461
- * Check if a tag exists.
462
- *
463
- * @description
464
- * Quick check for tag existence without fetching full info.
465
- *
466
- * @param name - Tag name
467
- * @returns True if tag exists
468
- *
469
- * @example
470
- * ```typescript
471
- * if (await manager.tagExists('v1.0.0')) {
472
- * console.log('Tag already exists')
473
- * }
474
- * ```
475
- */
476
- async tagExists(name) {
477
- const refName = `refs/tags/${name}`;
478
- const sha = await this.refStorage.getRef(refName);
479
- return sha !== null;
480
- }
481
- /**
482
- * Get the target (commit SHA) that a tag points to.
483
- *
484
- * @description
485
- * Resolves through annotated tags to get the final target.
486
- * For lightweight tags, returns the sha directly.
487
- * For annotated tags, returns the targetSha.
488
- *
489
- * @param name - Tag name
490
- * @returns Target commit SHA
491
- * @throws TagError with code 'TAG_NOT_FOUND' if tag doesn't exist
492
- *
493
- * @example
494
- * ```typescript
495
- * const commitSha = await manager.getTagTarget('v1.0.0')
496
- * ```
497
- */
498
- async getTagTarget(name) {
499
- const refName = `refs/tags/${name}`;
500
- let sha = await this.refStorage.getRef(refName);
501
- if (sha === null) {
502
- throw new TagError(`Tag not found: ${name}`, 'TAG_NOT_FOUND', name);
503
- }
504
- // Resolve through tag objects to get final commit
505
- let depth = 0;
506
- const maxDepth = 10;
507
- while (depth < maxDepth) {
508
- const tagObj = await this.objectStorage.readTagObject(sha);
509
- if (!tagObj) {
510
- // Not a tag object, this is the final target
511
- return sha;
512
- }
513
- // Follow the tag to its target
514
- sha = tagObj.object;
515
- depth++;
516
- }
517
- return sha;
518
- }
519
- /**
520
- * Verify a tag's GPG signature.
521
- *
522
- * @description
523
- * Verifies the GPG signature on a signed annotated tag.
524
- * Returns verification result with signer info.
525
- *
526
- * @param name - Tag name to verify
527
- * @returns Verification result
528
- * @throws TagError with code 'TAG_NOT_FOUND' if tag doesn't exist
529
- *
530
- * @example
531
- * ```typescript
532
- * const result = await manager.verifyTag('v1.0.0')
533
- * if (result.valid) {
534
- * console.log(`Signed by: ${result.signer}`)
535
- * console.log(`Trust: ${result.trustLevel}`)
536
- * } else {
537
- * console.log(`Verification failed: ${result.error}`)
538
- * }
539
- * ```
540
- */
541
- async verifyTag(name) {
542
- const refName = `refs/tags/${name}`;
543
- const sha = await this.refStorage.getRef(refName);
544
- if (sha === null) {
545
- throw new TagError(`Tag not found: ${name}`, 'TAG_NOT_FOUND', name);
546
- }
547
- // Get tag object
548
- const tagObj = await this.objectStorage.readTagObject(sha);
549
- if (!tagObj) {
550
- // Lightweight tag - cannot be signed
551
- return { valid: false };
552
- }
553
- // Parse message to check for signature
554
- const parsed = parseTagMessage(tagObj.message);
555
- if (!parsed.signature) {
556
- // No signature
557
- return { valid: false };
558
- }
559
- // Verify signature using GPG signer
560
- if (!this.gpgSigner) {
561
- return { valid: false, error: 'GPG signer not available' };
562
- }
563
- const encoder = new TextEncoder();
564
- return this.gpgSigner.verify(encoder.encode(parsed.message), parsed.signature);
565
- }
566
- /**
567
- * Check if a tag is annotated.
568
- *
569
- * @description
570
- * Determines if a tag is annotated (has a tag object) or lightweight.
571
- *
572
- * @param name - Tag name
573
- * @returns True if the tag is annotated
574
- * @throws TagError with code 'TAG_NOT_FOUND' if tag doesn't exist
575
- *
576
- * @example
577
- * ```typescript
578
- * if (await manager.isAnnotatedTag('v1.0.0')) {
579
- * console.log('This is an annotated tag')
580
- * }
581
- * ```
582
- */
583
- async isAnnotatedTag(name) {
584
- const refName = `refs/tags/${name}`;
585
- const sha = await this.refStorage.getRef(refName);
586
- if (sha === null) {
587
- throw new TagError(`Tag not found: ${name}`, 'TAG_NOT_FOUND', name);
588
- }
589
- // Try to read as tag object
590
- const tagObj = await this.objectStorage.readTagObject(sha);
591
- return tagObj !== null;
592
- }
593
- }
594
- // ============================================================================
595
- // Validation Functions
596
- // ============================================================================
597
- /**
598
- * Validate a tag name according to Git rules.
599
- *
600
- * @description
601
- * Tags follow the same rules as refs but under refs/tags/.
602
- * This validates against the full git-check-ref-format rules.
603
- *
604
- * **Rules**:
605
- * - Cannot be empty
606
- * - Cannot end with '/' or '.lock'
607
- * - Cannot contain '..', '@{', control chars, space, ~, ^, :, ?, *, [, \
608
- * - Components cannot start or end with '.'
609
- *
610
- * Note: This is a stub implementation. Full validation will be added in GREEN phase.
611
- *
612
- * @param name - Tag name to validate
613
- * @returns True if valid
614
- *
615
- * @see https://git-scm.com/docs/git-check-ref-format
616
- *
617
- * @example
618
- * ```typescript
619
- * isValidTagName('v1.0.0') // true
620
- * isValidTagName('release/1.0') // true
621
- * isValidTagName('v1.0.0.lock') // false (ends with .lock)
622
- * isValidTagName('v1..0') // false (contains ..)
623
- * isValidTagName('') // false (empty)
624
- * ```
625
- */
626
- export function isValidTagName(name) {
627
- // Empty name is invalid
628
- if (!name || name.length === 0 || name.trim().length === 0) {
629
- return false;
630
- }
631
- // Cannot end with .lock
632
- if (name.endsWith('.lock')) {
633
- return false;
634
- }
635
- // Cannot contain ..
636
- if (name.includes('..')) {
637
- return false;
638
- }
639
- // Cannot contain @{
640
- if (name.includes('@{')) {
641
- return false;
642
- }
643
- // Cannot contain control characters (ASCII 0-31, 127), space, ~, ^, :, ?, *, [, \
644
- const invalidChars = /[\x00-\x1f\x7f ~^:?*[\]\\]/;
645
- if (invalidChars.test(name)) {
646
- return false;
647
- }
648
- // Cannot end with /
649
- if (name.endsWith('/')) {
650
- return false;
651
- }
652
- // Split into components and check each
653
- const components = name.split('/');
654
- for (const component of components) {
655
- // Cannot have empty components (// in path)
656
- if (component.length === 0) {
657
- return false;
658
- }
659
- // Cannot start with .
660
- if (component.startsWith('.')) {
661
- return false;
662
- }
663
- // Cannot end with .
664
- if (component.endsWith('.')) {
665
- return false;
666
- }
667
- }
668
- return true;
669
- }
670
- /**
671
- * Type guard for annotated tags.
672
- *
673
- * @description
674
- * Checks if a tag is annotated with full metadata.
675
- * Narrows the type to include tagger and message.
676
- *
677
- * @param tag - Tag to check
678
- * @returns True if the tag is annotated with full metadata
679
- *
680
- * @example
681
- * ```typescript
682
- * if (isAnnotatedTag(tag)) {
683
- * // tag.tagger and tag.message are now guaranteed
684
- * console.log(`Tagged by: ${tag.tagger.name}`)
685
- * }
686
- * ```
687
- */
688
- export function isAnnotatedTag(tag) {
689
- return tag.type === 'annotated' &&
690
- tag.tagger !== undefined &&
691
- tag.message !== undefined;
692
- }
693
- /**
694
- * Format a tag message.
695
- *
696
- * @description
697
- * Normalizes a tag message: handles line endings, trims whitespace,
698
- * ensures proper formatting.
699
- *
700
- * @param message - Raw message input
701
- * @returns Formatted message
702
- *
703
- * @example
704
- * ```typescript
705
- * formatTagMessage(' Hello World \r\n') // 'Hello World\n'
706
- * ```
707
- */
708
- export function formatTagMessage(message) {
709
- // Normalize line endings (CRLF -> LF)
710
- let formatted = message.replace(/\r\n/g, '\n').replace(/\r/g, '\n');
711
- // Trim leading and trailing whitespace, but preserve internal structure
712
- // The test expects 'Hello\r\nWorld\r\n' to become 'Hello\nWorld\n'
713
- // So we trim leading whitespace, convert line endings, but preserve trailing newline if present
714
- const hadTrailingNewline = formatted.endsWith('\n');
715
- formatted = formatted.trim();
716
- if (hadTrailingNewline && formatted.length > 0) {
717
- formatted += '\n';
718
- }
719
- return formatted;
720
- }
721
- /**
722
- * Parse a tag message from raw content.
723
- *
724
- * @description
725
- * Separates the message from any GPG signature.
726
- * GPG signatures start with '-----BEGIN PGP SIGNATURE-----'.
727
- *
728
- * @param content - Raw tag content
729
- * @returns Parsed message and optional signature
730
- *
731
- * @example
732
- * ```typescript
733
- * const { message, signature } = parseTagMessage(content)
734
- * if (signature) {
735
- * console.log('Tag is signed')
736
- * }
737
- * ```
738
- */
739
- export function parseTagMessage(content) {
740
- const sigMarker = '-----BEGIN PGP SIGNATURE-----';
741
- const sigIndex = content.indexOf(sigMarker);
742
- if (sigIndex === -1) {
743
- // No signature
744
- return { message: content.trim() };
745
- }
746
- // Split message and signature
747
- const message = content.slice(0, sigIndex).trim();
748
- const signature = content.slice(sigIndex);
749
- return { message, signature };
750
- }
751
- // ============================================================================
752
- // Convenience Functions
753
- // ============================================================================
754
- /**
755
- * Create a tag (lightweight or annotated).
756
- *
757
- * @description
758
- * Convenience function that wraps TagManager.createTag.
759
- *
760
- * @param manager - TagManager instance
761
- * @param name - Tag name
762
- * @param target - Target SHA to tag
763
- * @param options - Creation options
764
- * @returns Created tag
765
- *
766
- * @example
767
- * ```typescript
768
- * const tag = await createTag(manager, 'v1.0.0', commitSha, {
769
- * annotated: true,
770
- * message: 'Release 1.0.0'
771
- * })
772
- * ```
773
- */
774
- export async function createTag(manager, name, target, options) {
775
- return manager.createTag(name, target, options);
776
- }
777
- /**
778
- * Create an annotated tag with message.
779
- *
780
- * @description
781
- * Convenience function for creating annotated tags.
782
- * Automatically sets annotated=true.
783
- *
784
- * @param manager - TagManager instance
785
- * @param name - Tag name
786
- * @param target - Target SHA to tag
787
- * @param message - Tag message
788
- * @param tagger - Tagger information
789
- * @param options - Additional options (excluding annotated, message, tagger)
790
- * @returns Created annotated tag
791
- *
792
- * @example
793
- * ```typescript
794
- * const tag = await createAnnotatedTag(
795
- * manager,
796
- * 'v1.0.0',
797
- * commitSha,
798
- * 'Release 1.0.0',
799
- * { name: 'Alice', email: 'alice@example.com', timestamp: Date.now()/1000, timezone: '+0000' }
800
- * )
801
- * ```
802
- */
803
- export async function createAnnotatedTag(manager, name, target, message, tagger, options) {
804
- return manager.createTag(name, target, {
805
- ...options,
806
- annotated: true,
807
- message,
808
- tagger
809
- });
810
- }
811
- /**
812
- * Delete a tag.
813
- *
814
- * @description
815
- * Convenience function that wraps TagManager.deleteTag.
816
- *
817
- * @param manager - TagManager instance
818
- * @param name - Tag name to delete
819
- * @param options - Deletion options
820
- * @returns True if deleted
821
- *
822
- * @example
823
- * ```typescript
824
- * await deleteTag(manager, 'v0.9.0-beta')
825
- * ```
826
- */
827
- export async function deleteTag(manager, name, options) {
828
- return manager.deleteTag(name, options);
829
- }
830
- /**
831
- * List all tags.
832
- *
833
- * @description
834
- * Convenience function that wraps TagManager.listTags.
835
- *
836
- * @param manager - TagManager instance
837
- * @param options - Listing options
838
- * @returns Array of tags
839
- *
840
- * @example
841
- * ```typescript
842
- * const tags = await listTags(manager, { pattern: 'v1.*' })
843
- * ```
844
- */
845
- export async function listTags(manager, options) {
846
- return manager.listTags(options);
847
- }
848
- /**
849
- * Get a tag by name.
850
- *
851
- * @description
852
- * Convenience function that wraps TagManager.getTag.
853
- *
854
- * @param manager - TagManager instance
855
- * @param name - Tag name
856
- * @param options - Get options
857
- * @returns Tag info or null
858
- *
859
- * @example
860
- * ```typescript
861
- * const tag = await getTag(manager, 'v1.0.0', { resolve: true })
862
- * ```
863
- */
864
- export async function getTag(manager, name, options) {
865
- return manager.getTag(name, options);
866
- }
867
- /**
868
- * Check if a tag is annotated.
869
- *
870
- * @description
871
- * Convenience function that wraps TagManager.isAnnotatedTag.
872
- *
873
- * @param manager - TagManager instance
874
- * @param name - Tag name
875
- * @returns True if annotated
876
- *
877
- * @example
878
- * ```typescript
879
- * if (await checkIsAnnotatedTag(manager, 'v1.0.0')) {
880
- * console.log('Annotated tag')
881
- * }
882
- * ```
883
- */
884
- export async function checkIsAnnotatedTag(manager, name) {
885
- return manager.isAnnotatedTag(name);
886
- }
887
- /**
888
- * Verify a tag's signature.
889
- *
890
- * @description
891
- * Convenience function that wraps TagManager.verifyTag.
892
- *
893
- * @param manager - TagManager instance
894
- * @param name - Tag name
895
- * @returns Verification result
896
- *
897
- * @example
898
- * ```typescript
899
- * const result = await verifyTagSignature(manager, 'v1.0.0')
900
- * ```
901
- */
902
- export async function verifyTagSignature(manager, name) {
903
- return manager.verifyTag(name);
904
- }
905
- /**
906
- * Get the target commit SHA for a tag.
907
- *
908
- * @description
909
- * Convenience function that wraps TagManager.getTagTarget.
910
- *
911
- * @param manager - TagManager instance
912
- * @param name - Tag name
913
- * @returns Target commit SHA
914
- *
915
- * @example
916
- * ```typescript
917
- * const sha = await getTagTarget(manager, 'v1.0.0')
918
- * ```
919
- */
920
- export async function getTagTarget(manager, name) {
921
- return manager.getTagTarget(name);
922
- }
923
- /**
924
- * Sort tags by semantic version.
925
- *
926
- * @description
927
- * Sorts tags that look like semantic versions (v1.2.3).
928
- * Non-semver tags are sorted lexicographically at the end.
929
- *
930
- * @param tags - Array of tags to sort
931
- * @param direction - Sort direction ('asc' or 'desc')
932
- * @returns Sorted array of tags
933
- *
934
- * @example
935
- * ```typescript
936
- * const sorted = sortTagsByVersion(tags, 'desc')
937
- * // ['v2.0.0', 'v1.10.0', 'v1.9.0', 'v1.0.0', ...]
938
- * ```
939
- */
940
- export function sortTagsByVersion(tags, direction = 'asc') {
941
- // Parse version from tag name (handles v1.2.3, 1.2.3, v1.2.3-beta, etc.)
942
- const parseVersion = (name) => {
943
- // Remove 'v' prefix if present
944
- const normalized = name.startsWith('v') ? name.slice(1) : name;
945
- // Extract numeric version parts (split on non-digit, non-dot)
946
- const parts = normalized.split(/[^0-9.]/)[0].split('.');
947
- return parts.map(p => parseInt(p, 10) || 0);
948
- };
949
- const compareVersions = (a, b) => {
950
- const maxLen = Math.max(a.length, b.length);
951
- for (let i = 0; i < maxLen; i++) {
952
- const aVal = a[i] || 0;
953
- const bVal = b[i] || 0;
954
- if (aVal !== bVal) {
955
- return aVal - bVal;
956
- }
957
- }
958
- return 0;
959
- };
960
- const sorted = [...tags].sort((a, b) => {
961
- const aVer = parseVersion(a.name);
962
- const bVer = parseVersion(b.name);
963
- const cmp = compareVersions(aVer, bVer);
964
- return direction === 'asc' ? cmp : -cmp;
965
- });
966
- return sorted;
967
- }
968
- /**
969
- * Filter tags by glob pattern.
970
- *
971
- * @description
972
- * Filters tags matching a glob pattern.
973
- * Supports * (any chars) and ? (single char) wildcards.
974
- *
975
- * @param tags - Array of tags to filter
976
- * @param pattern - Glob pattern (e.g., 'v1.*', 'release-*')
977
- * @returns Filtered array of tags
978
- *
979
- * @example
980
- * ```typescript
981
- * const v1Tags = filterTagsByPattern(tags, 'v1.*')
982
- * ```
983
- */
984
- export function filterTagsByPattern(tags, pattern) {
985
- // Convert glob pattern to regex
986
- // * matches any number of characters
987
- // ? matches a single character
988
- // Escape special regex characters except * and ?
989
- const regexPattern = pattern
990
- .replace(/[.+^${}()|[\]\\]/g, '\\$&') // Escape special regex chars
991
- .replace(/\*/g, '.*') // * -> .*
992
- .replace(/\?/g, '.'); // ? -> .
993
- const regex = new RegExp(`^${regexPattern}$`);
994
- return tags.filter(tag => regex.test(tag.name));
995
- }
996
- //# sourceMappingURL=tag.js.map