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
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