@art-work/cli 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (386) hide show
  1. package/README.md +33 -0
  2. package/dist/commands/branch/runBranch.d.ts +7 -0
  3. package/dist/commands/branch/runBranch.d.ts.map +1 -0
  4. package/dist/commands/branch/runBranch.test.d.ts +2 -0
  5. package/dist/commands/branch/runBranch.test.d.ts.map +1 -0
  6. package/dist/commands/checkouts/runCheckoutRun.test.d.ts +2 -0
  7. package/dist/commands/checkouts/runCheckoutRun.test.d.ts.map +1 -0
  8. package/dist/commands/checkouts/runCheckoutsRun.d.ts +7 -0
  9. package/dist/commands/checkouts/runCheckoutsRun.d.ts.map +1 -0
  10. package/dist/commands/clone/cloneAll.d.ts +4 -0
  11. package/dist/commands/clone/cloneAll.d.ts.map +1 -0
  12. package/dist/commands/clone/cloneAll.test.d.ts +2 -0
  13. package/dist/commands/clone/cloneAll.test.d.ts.map +1 -0
  14. package/dist/commands/clone/cloneSpecific.d.ts +4 -0
  15. package/dist/commands/clone/cloneSpecific.d.ts.map +1 -0
  16. package/dist/commands/clone/cloneSpecific.test.d.ts +2 -0
  17. package/dist/commands/clone/cloneSpecific.test.d.ts.map +1 -0
  18. package/dist/commands/clone/cloneStatus.d.ts +3 -0
  19. package/dist/commands/clone/cloneStatus.d.ts.map +1 -0
  20. package/dist/commands/clone/cloneStatus.test.d.ts +2 -0
  21. package/dist/commands/clone/cloneStatus.test.d.ts.map +1 -0
  22. package/dist/commands/clone/private/cloneIfMissing.d.ts +4 -0
  23. package/dist/commands/clone/private/cloneIfMissing.d.ts.map +1 -0
  24. package/dist/commands/clone/private/cloneIfMissing.test.d.ts +2 -0
  25. package/dist/commands/clone/private/cloneIfMissing.test.d.ts.map +1 -0
  26. package/dist/commands/clone/runClone.d.ts +9 -0
  27. package/dist/commands/clone/runClone.d.ts.map +1 -0
  28. package/dist/commands/clone/runClone.test.d.ts +2 -0
  29. package/dist/commands/clone/runClone.test.d.ts.map +1 -0
  30. package/dist/commands/link/runLink.d.ts +5 -0
  31. package/dist/commands/link/runLink.d.ts.map +1 -0
  32. package/dist/commands/link/runLink.test.d.ts +2 -0
  33. package/dist/commands/link/runLink.test.d.ts.map +1 -0
  34. package/dist/commands/publish/runPublish.d.ts +6 -0
  35. package/dist/commands/publish/runPublish.d.ts.map +1 -0
  36. package/dist/commands/publish/runPublish.test.d.ts +2 -0
  37. package/dist/commands/publish/runPublish.test.d.ts.map +1 -0
  38. package/dist/commands/pull/runPull.d.ts +6 -0
  39. package/dist/commands/pull/runPull.d.ts.map +1 -0
  40. package/dist/commands/pull/runPull.test.d.ts +2 -0
  41. package/dist/commands/pull/runPull.test.d.ts.map +1 -0
  42. package/dist/commands/push/runPush.d.ts +6 -0
  43. package/dist/commands/push/runPush.d.ts.map +1 -0
  44. package/dist/commands/push/runPush.test.d.ts +2 -0
  45. package/dist/commands/push/runPush.test.d.ts.map +1 -0
  46. package/dist/commands/repo/runRepo.d.ts +12 -0
  47. package/dist/commands/repo/runRepo.d.ts.map +1 -0
  48. package/dist/commands/repo/runRepo.test.d.ts +2 -0
  49. package/dist/commands/repo/runRepo.test.d.ts.map +1 -0
  50. package/dist/commands/sanity/private/scanExtraneousCheckouts.d.ts +5 -0
  51. package/dist/commands/sanity/private/scanExtraneousCheckouts.d.ts.map +1 -0
  52. package/dist/commands/sanity/private/scanExtraneousCheckouts.test.d.ts +2 -0
  53. package/dist/commands/sanity/private/scanExtraneousCheckouts.test.d.ts.map +1 -0
  54. package/dist/commands/sanity/private/syncCheckouts.d.ts +3 -0
  55. package/dist/commands/sanity/private/syncCheckouts.d.ts.map +1 -0
  56. package/dist/commands/sanity/private/syncCheckouts.test.d.ts +2 -0
  57. package/dist/commands/sanity/private/syncCheckouts.test.d.ts.map +1 -0
  58. package/dist/commands/sanity/runSanity.d.ts +6 -0
  59. package/dist/commands/sanity/runSanity.d.ts.map +1 -0
  60. package/dist/commands/sanity/runSanity.test.d.ts +2 -0
  61. package/dist/commands/sanity/runSanity.test.d.ts.map +1 -0
  62. package/dist/commands/sync/runSync.d.ts +6 -0
  63. package/dist/commands/sync/runSync.d.ts.map +1 -0
  64. package/dist/commands/sync/runSync.test.d.ts +2 -0
  65. package/dist/commands/sync/runSync.test.d.ts.map +1 -0
  66. package/dist/commands/unlink/runUnlink.d.ts +5 -0
  67. package/dist/commands/unlink/runUnlink.d.ts.map +1 -0
  68. package/dist/commands/unlink/runUnlink.test.d.ts +2 -0
  69. package/dist/commands/unlink/runUnlink.test.d.ts.map +1 -0
  70. package/dist/config/defineConfig.d.ts +3 -0
  71. package/dist/config/defineConfig.d.ts.map +1 -0
  72. package/dist/config/defineConfig.test.d.ts +2 -0
  73. package/dist/config/defineConfig.test.d.ts.map +1 -0
  74. package/dist/config/index.d.ts +4 -0
  75. package/dist/config/index.d.ts.map +1 -0
  76. package/dist/config/index.js +124 -0
  77. package/dist/config/loadWorkspaceConfig.d.ts +3 -0
  78. package/dist/config/loadWorkspaceConfig.d.ts.map +1 -0
  79. package/dist/config/loadWorkspaceConfig.test.d.ts +2 -0
  80. package/dist/config/loadWorkspaceConfig.test.d.ts.map +1 -0
  81. package/dist/config/private/normalizeRecordPaths.d.ts +4 -0
  82. package/dist/config/private/normalizeRecordPaths.d.ts.map +1 -0
  83. package/dist/config/types.d.ts +31 -0
  84. package/dist/config/types.d.ts.map +1 -0
  85. package/dist/index.d.ts +4 -0
  86. package/dist/index.d.ts.map +1 -0
  87. package/dist/index.js +2098 -0
  88. package/dist/private/async/runWithConcurrency.d.ts +2 -0
  89. package/dist/private/async/runWithConcurrency.d.ts.map +1 -0
  90. package/dist/private/commands/checkouts/doBranchCheckout.d.ts +4 -0
  91. package/dist/private/commands/checkouts/doBranchCheckout.d.ts.map +1 -0
  92. package/dist/private/commands/checkouts/doBranchCheckout.test.d.ts +2 -0
  93. package/dist/private/commands/checkouts/doBranchCheckout.test.d.ts.map +1 -0
  94. package/dist/private/commands/checkouts/doCheckoutRun.d.ts +4 -0
  95. package/dist/private/commands/checkouts/doCheckoutRun.d.ts.map +1 -0
  96. package/dist/private/commands/checkouts/doPullCheckout.d.ts +4 -0
  97. package/dist/private/commands/checkouts/doPullCheckout.d.ts.map +1 -0
  98. package/dist/private/commands/checkouts/doPullCheckout.test.d.ts +2 -0
  99. package/dist/private/commands/checkouts/doPullCheckout.test.d.ts.map +1 -0
  100. package/dist/private/commands/checkouts/doPushCheckout.d.ts +4 -0
  101. package/dist/private/commands/checkouts/doPushCheckout.d.ts.map +1 -0
  102. package/dist/private/commands/checkouts/doPushCheckout.test.d.ts +2 -0
  103. package/dist/private/commands/checkouts/doPushCheckout.test.d.ts.map +1 -0
  104. package/dist/private/commands/doClone.d.ts +4 -0
  105. package/dist/private/commands/doClone.d.ts.map +1 -0
  106. package/dist/private/commands/doClone.test.d.ts +2 -0
  107. package/dist/private/commands/doClone.test.d.ts.map +1 -0
  108. package/dist/private/commands/operations/createBranchOperation.d.ts +4 -0
  109. package/dist/private/commands/operations/createBranchOperation.d.ts.map +1 -0
  110. package/dist/private/commands/operations/createCheckoutRunOperation.d.ts +4 -0
  111. package/dist/private/commands/operations/createCheckoutRunOperation.d.ts.map +1 -0
  112. package/dist/private/commands/operations/createCloneOperation.d.ts +4 -0
  113. package/dist/private/commands/operations/createCloneOperation.d.ts.map +1 -0
  114. package/dist/private/commands/operations/createLinkedOperation.d.ts +4 -0
  115. package/dist/private/commands/operations/createLinkedOperation.d.ts.map +1 -0
  116. package/dist/private/commands/operations/createPublishOperation.d.ts +4 -0
  117. package/dist/private/commands/operations/createPublishOperation.d.ts.map +1 -0
  118. package/dist/private/commands/operations/createPullOperation.d.ts +4 -0
  119. package/dist/private/commands/operations/createPullOperation.d.ts.map +1 -0
  120. package/dist/private/commands/operations/createPullOperation.test.d.ts +2 -0
  121. package/dist/private/commands/operations/createPullOperation.test.d.ts.map +1 -0
  122. package/dist/private/commands/operations/createPushOperation.d.ts +4 -0
  123. package/dist/private/commands/operations/createPushOperation.d.ts.map +1 -0
  124. package/dist/private/commands/operations/createUnlinkOperation.d.ts +4 -0
  125. package/dist/private/commands/operations/createUnlinkOperation.d.ts.map +1 -0
  126. package/dist/private/commands/workspaces/doPullWorkspaceCheckout.d.ts +4 -0
  127. package/dist/private/commands/workspaces/doPullWorkspaceCheckout.d.ts.map +1 -0
  128. package/dist/private/commands/workspaces/doPullWorkspaceCheckout.test.d.ts +2 -0
  129. package/dist/private/commands/workspaces/doPullWorkspaceCheckout.test.d.ts.map +1 -0
  130. package/dist/private/commands/workspaces/doPushWorkspaceCheckout.d.ts +4 -0
  131. package/dist/private/commands/workspaces/doPushWorkspaceCheckout.d.ts.map +1 -0
  132. package/dist/private/commands/workspaces/doPushWorkspaceCheckout.test.d.ts +2 -0
  133. package/dist/private/commands/workspaces/doPushWorkspaceCheckout.test.d.ts.map +1 -0
  134. package/dist/private/commands/workspaces/scanWorkspaceCheckout.d.ts +4 -0
  135. package/dist/private/commands/workspaces/scanWorkspaceCheckout.d.ts.map +1 -0
  136. package/dist/private/commands/workspaces/syncWorkspaceCheckout.d.ts +4 -0
  137. package/dist/private/commands/workspaces/syncWorkspaceCheckout.d.ts.map +1 -0
  138. package/dist/private/commands/workspaces/syncWorkspaceCheckout.test.d.ts +2 -0
  139. package/dist/private/commands/workspaces/syncWorkspaceCheckout.test.d.ts.map +1 -0
  140. package/dist/private/context/createWorkspaceContext.d.ts +12 -0
  141. package/dist/private/context/createWorkspaceContext.d.ts.map +1 -0
  142. package/dist/private/context/createWorkspaceContext.test.d.ts +2 -0
  143. package/dist/private/context/createWorkspaceContext.test.d.ts.map +1 -0
  144. package/dist/private/exec/runCommandInDirectory.d.ts +7 -0
  145. package/dist/private/exec/runCommandInDirectory.d.ts.map +1 -0
  146. package/dist/private/git/cloneCheckout.d.ts +3 -0
  147. package/dist/private/git/cloneCheckout.d.ts.map +1 -0
  148. package/dist/private/git/createOrSwitchBranch.d.ts +2 -0
  149. package/dist/private/git/createOrSwitchBranch.d.ts.map +1 -0
  150. package/dist/private/git/createOrSwitchBranch.test.d.ts +2 -0
  151. package/dist/private/git/createOrSwitchBranch.test.d.ts.map +1 -0
  152. package/dist/private/git/getBehindAheadCount.d.ts +6 -0
  153. package/dist/private/git/getBehindAheadCount.d.ts.map +1 -0
  154. package/dist/private/git/getBehindAheadCount.test.d.ts +2 -0
  155. package/dist/private/git/getBehindAheadCount.test.d.ts.map +1 -0
  156. package/dist/private/git/getCurrentBranch.d.ts +2 -0
  157. package/dist/private/git/getCurrentBranch.d.ts.map +1 -0
  158. package/dist/private/git/getCurrentBranch.test.d.ts +2 -0
  159. package/dist/private/git/getCurrentBranch.test.d.ts.map +1 -0
  160. package/dist/private/git/getRemoteBranch.d.ts +2 -0
  161. package/dist/private/git/getRemoteBranch.d.ts.map +1 -0
  162. package/dist/private/git/getRemoteBranch.test.d.ts +2 -0
  163. package/dist/private/git/getRemoteBranch.test.d.ts.map +1 -0
  164. package/dist/private/git/getRemoteUrl.d.ts +2 -0
  165. package/dist/private/git/getRemoteUrl.d.ts.map +1 -0
  166. package/dist/private/git/hasLocalBranch.d.ts +2 -0
  167. package/dist/private/git/hasLocalBranch.d.ts.map +1 -0
  168. package/dist/private/git/hasLocalBranch.test.d.ts +2 -0
  169. package/dist/private/git/hasLocalBranch.test.d.ts.map +1 -0
  170. package/dist/private/git/hasMergeConflicts.d.ts +2 -0
  171. package/dist/private/git/hasMergeConflicts.d.ts.map +1 -0
  172. package/dist/private/git/hasMergeConflicts.test.d.ts +2 -0
  173. package/dist/private/git/hasMergeConflicts.test.d.ts.map +1 -0
  174. package/dist/private/git/hasRemote.d.ts +2 -0
  175. package/dist/private/git/hasRemote.d.ts.map +1 -0
  176. package/dist/private/git/hasRemote.test.d.ts +2 -0
  177. package/dist/private/git/hasRemote.test.d.ts.map +1 -0
  178. package/dist/private/git/isDetachedHead.d.ts +2 -0
  179. package/dist/private/git/isDetachedHead.d.ts.map +1 -0
  180. package/dist/private/git/isDetachedHead.test.d.ts +2 -0
  181. package/dist/private/git/isDetachedHead.test.d.ts.map +1 -0
  182. package/dist/private/git/isDirty.d.ts +2 -0
  183. package/dist/private/git/isDirty.d.ts.map +1 -0
  184. package/dist/private/git/isDirty.test.d.ts +2 -0
  185. package/dist/private/git/isDirty.test.d.ts.map +1 -0
  186. package/dist/private/git/pullCheckout.d.ts +3 -0
  187. package/dist/private/git/pullCheckout.d.ts.map +1 -0
  188. package/dist/private/git/pullCheckout.test.d.ts +2 -0
  189. package/dist/private/git/pullCheckout.test.d.ts.map +1 -0
  190. package/dist/private/git/pushCheckout.d.ts +3 -0
  191. package/dist/private/git/pushCheckout.d.ts.map +1 -0
  192. package/dist/private/git/remoteFetch.d.ts +2 -0
  193. package/dist/private/git/remoteFetch.d.ts.map +1 -0
  194. package/dist/private/log/createOperationsLog.d.ts +9 -0
  195. package/dist/private/log/createOperationsLog.d.ts.map +1 -0
  196. package/dist/private/log/createOperationsLog.test.d.ts +2 -0
  197. package/dist/private/log/createOperationsLog.test.d.ts.map +1 -0
  198. package/dist/private/operations/createGenericOperation.d.ts +3 -0
  199. package/dist/private/operations/createGenericOperation.d.ts.map +1 -0
  200. package/dist/private/operations/createGenericOperation.test.d.ts +2 -0
  201. package/dist/private/operations/createGenericOperation.test.d.ts.map +1 -0
  202. package/dist/private/operations/createOperationFailure.d.ts +3 -0
  203. package/dist/private/operations/createOperationFailure.d.ts.map +1 -0
  204. package/dist/private/operations/createOperationFailure.test.d.ts +2 -0
  205. package/dist/private/operations/createOperationFailure.test.d.ts.map +1 -0
  206. package/dist/private/operations/createOperationSuccess.d.ts +3 -0
  207. package/dist/private/operations/createOperationSuccess.d.ts.map +1 -0
  208. package/dist/private/operations/createOperationSuccess.test.d.ts +2 -0
  209. package/dist/private/operations/createOperationSuccess.test.d.ts.map +1 -0
  210. package/dist/private/operations/types.d.ts +63 -0
  211. package/dist/private/operations/types.d.ts.map +1 -0
  212. package/dist/private/present/formatTable.d.ts +2 -0
  213. package/dist/private/present/formatTable.d.ts.map +1 -0
  214. package/dist/private/present/formatTable.test.d.ts +2 -0
  215. package/dist/private/present/formatTable.test.d.ts.map +1 -0
  216. package/dist/private/present/makeOperationLogLine.d.ts +5 -0
  217. package/dist/private/present/makeOperationLogLine.d.ts.map +1 -0
  218. package/dist/private/present/presentCheckoutReport.d.ts +4 -0
  219. package/dist/private/present/presentCheckoutReport.d.ts.map +1 -0
  220. package/dist/private/present/presentCheckoutReport.test.d.ts +2 -0
  221. package/dist/private/present/presentCheckoutReport.test.d.ts.map +1 -0
  222. package/dist/private/present/presentCheckoutRepositoryState.d.ts +3 -0
  223. package/dist/private/present/presentCheckoutRepositoryState.d.ts.map +1 -0
  224. package/dist/private/present/presentExtraneousReport.d.ts +3 -0
  225. package/dist/private/present/presentExtraneousReport.d.ts.map +1 -0
  226. package/dist/private/present/presentExtraneousReport.test.d.ts +2 -0
  227. package/dist/private/present/presentExtraneousReport.test.d.ts.map +1 -0
  228. package/dist/private/present/presentOperationsReport.d.ts +3 -0
  229. package/dist/private/present/presentOperationsReport.d.ts.map +1 -0
  230. package/dist/private/present/presentOperationsReport.test.d.ts +2 -0
  231. package/dist/private/present/presentOperationsReport.test.d.ts.map +1 -0
  232. package/dist/private/present/presentPackageStateReport.d.ts +4 -0
  233. package/dist/private/present/presentPackageStateReport.d.ts.map +1 -0
  234. package/dist/private/present/presentPackageStateReport.test.d.ts +2 -0
  235. package/dist/private/present/presentPackageStateReport.test.d.ts.map +1 -0
  236. package/dist/private/present/presentWorkspaceReport.d.ts +3 -0
  237. package/dist/private/present/presentWorkspaceReport.d.ts.map +1 -0
  238. package/dist/private/present/presentWorkspaceReport.test.d.ts +2 -0
  239. package/dist/private/present/presentWorkspaceReport.test.d.ts.map +1 -0
  240. package/dist/private/present/private/truncateMiddle.d.ts +2 -0
  241. package/dist/private/present/private/truncateMiddle.d.ts.map +1 -0
  242. package/dist/private/present/private/truncateMiddle.test.d.ts +2 -0
  243. package/dist/private/present/private/truncateMiddle.test.d.ts.map +1 -0
  244. package/dist/private/repositories/createPackageStateRecord.d.ts +6 -0
  245. package/dist/private/repositories/createPackageStateRecord.d.ts.map +1 -0
  246. package/dist/private/repositories/getRepositoryCheckoutPackages.d.ts +3 -0
  247. package/dist/private/repositories/getRepositoryCheckoutPackages.d.ts.map +1 -0
  248. package/dist/private/repositories/scanPackageStateRecord.d.ts +3 -0
  249. package/dist/private/repositories/scanPackageStateRecord.d.ts.map +1 -0
  250. package/dist/private/resources/checkout/loadCheckoutRecords.d.ts +4 -0
  251. package/dist/private/resources/checkout/loadCheckoutRecords.d.ts.map +1 -0
  252. package/dist/private/resources/checkout/loadCheckoutRecords.test.d.ts +2 -0
  253. package/dist/private/resources/checkout/loadCheckoutRecords.test.d.ts.map +1 -0
  254. package/dist/private/resources/checkout/private/makeCheckoutFilename.d.ts +4 -0
  255. package/dist/private/resources/checkout/private/makeCheckoutFilename.d.ts.map +1 -0
  256. package/dist/private/resources/checkout/private/makeCheckoutFilename.test.d.ts +2 -0
  257. package/dist/private/resources/checkout/private/makeCheckoutFilename.test.d.ts.map +1 -0
  258. package/dist/private/resources/checkout/readCheckoutRecord.d.ts +4 -0
  259. package/dist/private/resources/checkout/readCheckoutRecord.d.ts.map +1 -0
  260. package/dist/private/resources/checkout/readCheckoutRecord.test.d.ts +2 -0
  261. package/dist/private/resources/checkout/readCheckoutRecord.test.d.ts.map +1 -0
  262. package/dist/private/resources/checkout/saveCheckoutRecord.d.ts +4 -0
  263. package/dist/private/resources/checkout/saveCheckoutRecord.d.ts.map +1 -0
  264. package/dist/private/resources/checkout/saveCheckoutRecord.test.d.ts +2 -0
  265. package/dist/private/resources/checkout/saveCheckoutRecord.test.d.ts.map +1 -0
  266. package/dist/private/resources/namespace/loadNamespaceRecords.d.ts +4 -0
  267. package/dist/private/resources/namespace/loadNamespaceRecords.d.ts.map +1 -0
  268. package/dist/private/resources/namespace/readNamespaceRecord.d.ts +4 -0
  269. package/dist/private/resources/namespace/readNamespaceRecord.d.ts.map +1 -0
  270. package/dist/private/resources/package/loadPackageRecords.d.ts +4 -0
  271. package/dist/private/resources/package/loadPackageRecords.d.ts.map +1 -0
  272. package/dist/private/resources/package/readPackageRecord.d.ts +4 -0
  273. package/dist/private/resources/package/readPackageRecord.d.ts.map +1 -0
  274. package/dist/private/resources/project/loadProjectRecords.d.ts +4 -0
  275. package/dist/private/resources/project/loadProjectRecords.d.ts.map +1 -0
  276. package/dist/private/resources/project/readProjectRecord.d.ts +4 -0
  277. package/dist/private/resources/project/readProjectRecord.d.ts.map +1 -0
  278. package/dist/private/resources/projectGraph/consolidateProjectGraph.d.ts +3 -0
  279. package/dist/private/resources/projectGraph/consolidateProjectGraph.d.ts.map +1 -0
  280. package/dist/private/resources/projectGraph/findPackage.d.ts +7 -0
  281. package/dist/private/resources/projectGraph/findPackage.d.ts.map +1 -0
  282. package/dist/private/resources/projectGraph/loadProjectGraph.d.ts +4 -0
  283. package/dist/private/resources/projectGraph/loadProjectGraph.d.ts.map +1 -0
  284. package/dist/private/resources/projectGraph/loadProjectGraph.test.d.ts +2 -0
  285. package/dist/private/resources/projectGraph/loadProjectGraph.test.d.ts.map +1 -0
  286. package/dist/private/resources/repository/loadRepositoryRecords.d.ts +4 -0
  287. package/dist/private/resources/repository/loadRepositoryRecords.d.ts.map +1 -0
  288. package/dist/private/resources/repository/readRepositoryRecord.d.ts +4 -0
  289. package/dist/private/resources/repository/readRepositoryRecord.d.ts.map +1 -0
  290. package/dist/private/resources/repository/readRepositoryRecord.test.d.ts +2 -0
  291. package/dist/private/resources/repository/readRepositoryRecord.test.d.ts.map +1 -0
  292. package/dist/private/resources/types.d.ts +50 -0
  293. package/dist/private/resources/types.d.ts.map +1 -0
  294. package/dist/private/scan/private/createCheckoutNoClonedScan.d.ts +3 -0
  295. package/dist/private/scan/private/createCheckoutNoClonedScan.d.ts.map +1 -0
  296. package/dist/private/scan/private/createCheckoutScan.d.ts +3 -0
  297. package/dist/private/scan/private/createCheckoutScan.d.ts.map +1 -0
  298. package/dist/private/scan/private/createExtraneousCheckout.d.ts +4 -0
  299. package/dist/private/scan/private/createExtraneousCheckout.d.ts.map +1 -0
  300. package/dist/private/scan/private/createStateAccessor.d.ts +3 -0
  301. package/dist/private/scan/private/createStateAccessor.d.ts.map +1 -0
  302. package/dist/private/scan/scanCheckoutState.d.ts +4 -0
  303. package/dist/private/scan/scanCheckoutState.d.ts.map +1 -0
  304. package/dist/private/scan/scanCheckoutState.test.d.ts +2 -0
  305. package/dist/private/scan/scanCheckoutState.test.d.ts.map +1 -0
  306. package/dist/private/scan/states/createCommittedState.d.ts +3 -0
  307. package/dist/private/scan/states/createCommittedState.d.ts.map +1 -0
  308. package/dist/private/scan/states/createExistsState.d.ts +3 -0
  309. package/dist/private/scan/states/createExistsState.d.ts.map +1 -0
  310. package/dist/private/scan/states/createNoConflictsState.d.ts +3 -0
  311. package/dist/private/scan/states/createNoConflictsState.d.ts.map +1 -0
  312. package/dist/private/scan/states/createNoDetachedState.d.ts +3 -0
  313. package/dist/private/scan/states/createNoDetachedState.d.ts.map +1 -0
  314. package/dist/private/scan/states/createRemoteState.d.ts +3 -0
  315. package/dist/private/scan/states/createRemoteState.d.ts.map +1 -0
  316. package/dist/private/scan/states/createRepoState.d.ts +3 -0
  317. package/dist/private/scan/states/createRepoState.d.ts.map +1 -0
  318. package/dist/private/scan/states/createSyncState.d.ts +3 -0
  319. package/dist/private/scan/states/createSyncState.d.ts.map +1 -0
  320. package/dist/private/scan/states/createWrongRemoteState.d.ts +3 -0
  321. package/dist/private/scan/states/createWrongRemoteState.d.ts.map +1 -0
  322. package/dist/private/scan/types.d.ts +60 -0
  323. package/dist/private/scan/types.d.ts.map +1 -0
  324. package/dist/private/store/createCheckout.d.ts +6 -0
  325. package/dist/private/store/createCheckout.d.ts.map +1 -0
  326. package/dist/private/store/createCheckout.test.d.ts +2 -0
  327. package/dist/private/store/createCheckout.test.d.ts.map +1 -0
  328. package/dist/private/store/createCheckoutLocation.d.ts +3 -0
  329. package/dist/private/store/createCheckoutLocation.d.ts.map +1 -0
  330. package/dist/private/store/createCheckoutLocation.test.d.ts +2 -0
  331. package/dist/private/store/createCheckoutLocation.test.d.ts.map +1 -0
  332. package/dist/private/store/createCheckoutStore.d.ts +12 -0
  333. package/dist/private/store/createCheckoutStore.d.ts.map +1 -0
  334. package/dist/private/store/createCheckoutStore.test.d.ts +2 -0
  335. package/dist/private/store/createCheckoutStore.test.d.ts.map +1 -0
  336. package/dist/private/store/hydrateStoreFromRecords.d.ts +5 -0
  337. package/dist/private/store/hydrateStoreFromRecords.d.ts.map +1 -0
  338. package/dist/private/store/hydrateStoreFromRecords.test.d.ts +2 -0
  339. package/dist/private/store/hydrateStoreFromRecords.test.d.ts.map +1 -0
  340. package/dist/private/store/safePath.d.ts +2 -0
  341. package/dist/private/store/safePath.d.ts.map +1 -0
  342. package/dist/private/store/safePath.test.d.ts +2 -0
  343. package/dist/private/store/safePath.test.d.ts.map +1 -0
  344. package/dist/private/store/scanAllCheckoutsStates.d.ts +3 -0
  345. package/dist/private/store/scanAllCheckoutsStates.d.ts.map +1 -0
  346. package/dist/private/store/scanAllCheckoutsStates.test.d.ts +2 -0
  347. package/dist/private/store/scanAllCheckoutsStates.test.d.ts.map +1 -0
  348. package/dist/private/store/types.d.ts +10 -0
  349. package/dist/private/store/types.d.ts.map +1 -0
  350. package/dist/test/helpers/checkout/makeMockScan.d.ts +3 -0
  351. package/dist/test/helpers/checkout/makeMockScan.d.ts.map +1 -0
  352. package/dist/test/helpers/checkout/makeWorkspaceCheckoutMock.d.ts +3 -0
  353. package/dist/test/helpers/checkout/makeWorkspaceCheckoutMock.d.ts.map +1 -0
  354. package/dist/test/helpers/context/createMockCommandContext.d.ts +4 -0
  355. package/dist/test/helpers/context/createMockCommandContext.d.ts.map +1 -0
  356. package/dist/test/helpers/context/makeMockConfig.d.ts +3 -0
  357. package/dist/test/helpers/context/makeMockConfig.d.ts.map +1 -0
  358. package/dist/test/helpers/delay.d.ts +2 -0
  359. package/dist/test/helpers/delay.d.ts.map +1 -0
  360. package/dist/test/helpers/git/commitFileTest.d.ts +2 -0
  361. package/dist/test/helpers/git/commitFileTest.d.ts.map +1 -0
  362. package/dist/test/helpers/git/initBareRepoTest.d.ts +2 -0
  363. package/dist/test/helpers/git/initBareRepoTest.d.ts.map +1 -0
  364. package/dist/test/helpers/git/initGitRepoTest.d.ts +5 -0
  365. package/dist/test/helpers/git/initGitRepoTest.d.ts.map +1 -0
  366. package/dist/test/helpers/git/initWorkingRepoTest.d.ts +4 -0
  367. package/dist/test/helpers/git/initWorkingRepoTest.d.ts.map +1 -0
  368. package/dist/test/helpers/git/makeOriginAheadTest.d.ts +2 -0
  369. package/dist/test/helpers/git/makeOriginAheadTest.d.ts.map +1 -0
  370. package/dist/test/helpers/git/makeWorkspaceRootBehindTest.d.ts +2 -0
  371. package/dist/test/helpers/git/makeWorkspaceRootBehindTest.d.ts.map +1 -0
  372. package/dist/test/helpers/records/createRecordFile.d.ts +3 -0
  373. package/dist/test/helpers/records/createRecordFile.d.ts.map +1 -0
  374. package/dist/test/helpers/records/writeCheckoutMockRecord.d.ts +2 -0
  375. package/dist/test/helpers/records/writeCheckoutMockRecord.d.ts.map +1 -0
  376. package/dist/test/helpers/records/writeProjectMockRecord.d.ts +15 -0
  377. package/dist/test/helpers/records/writeProjectMockRecord.d.ts.map +1 -0
  378. package/dist/test/helpers/records/writeRepoMockRecord.d.ts +2 -0
  379. package/dist/test/helpers/records/writeRepoMockRecord.d.ts.map +1 -0
  380. package/dist/test/helpers/tempDirs/makeTempDir.d.ts +2 -0
  381. package/dist/test/helpers/tempDirs/makeTempDir.d.ts.map +1 -0
  382. package/dist/test/helpers/tempDirs/removeTempDirs.d.ts +2 -0
  383. package/dist/test/helpers/tempDirs/removeTempDirs.d.ts.map +1 -0
  384. package/dist/test/helpers/tempDirs/resilientRemoveDir.d.ts +2 -0
  385. package/dist/test/helpers/tempDirs/resilientRemoveDir.d.ts.map +1 -0
  386. package/package.json +57 -0
package/dist/index.js ADDED
@@ -0,0 +1,2098 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/index.ts
4
+ import { Command } from "commander";
5
+
6
+ // src/private/git/createOrSwitchBranch.ts
7
+ import simpleGit2 from "simple-git";
8
+
9
+ // src/private/git/hasLocalBranch.ts
10
+ import simpleGit from "simple-git";
11
+ async function hasLocalBranch(dir, branch) {
12
+ const git = simpleGit(dir);
13
+ try {
14
+ const out = await git.raw(["rev-parse", "--verify", "--quiet", `refs/heads/${branch}`]);
15
+ return out.trim().length > 0;
16
+ } catch {
17
+ return false;
18
+ }
19
+ }
20
+
21
+ // src/private/git/createOrSwitchBranch.ts
22
+ async function createOrSwitchBranch(dir, branch) {
23
+ const git = simpleGit2(dir);
24
+ if (await hasLocalBranch(dir, branch)) {
25
+ await git.checkout(branch);
26
+ return "switched";
27
+ }
28
+ await git.checkoutLocalBranch(branch);
29
+ return "created";
30
+ }
31
+
32
+ // src/private/operations/createOperationFailure.ts
33
+ function formatRawError(raw) {
34
+ const lines = raw.split("\n").map((l) => l.trim()).filter((l) => l.length > 0);
35
+ return lines.map((l) => " " + l).join("\n");
36
+ }
37
+ function extractReason(raw) {
38
+ const match = raw.match(/\(([^)]+)\)/);
39
+ return match ? match[1] : raw.split("\n")[0]?.trim() ?? "unknown error";
40
+ }
41
+ var errorLabels = {
42
+ clone: "CloneError",
43
+ push: "PushError",
44
+ pull: "PullError",
45
+ publish: "PublishError",
46
+ branch: "BranchError",
47
+ linked: "LinkedError",
48
+ unlink: "UnlinkError",
49
+ run: "CheckoutRunError"
50
+ };
51
+ function createOperationFailure(pending, error) {
52
+ const rawError = error instanceof Error ? error.message : String(error);
53
+ const label = errorLabels[pending.operation] ?? "OperationError";
54
+ return {
55
+ ...pending,
56
+ outcome: "failure",
57
+ finishedTs: /* @__PURE__ */ new Date(),
58
+ error: rawError,
59
+ message() {
60
+ return extractReason(this.error);
61
+ },
62
+ errorSerialized() {
63
+ return `${label}: ${pending.checkout?.repo?.name} \u2014 ${this.message()}
64
+
65
+ ${formatRawError(this.error)}`;
66
+ }
67
+ };
68
+ }
69
+
70
+ // src/private/operations/createOperationSuccess.ts
71
+ function createOperationSuccess(pending, message) {
72
+ return {
73
+ ...pending,
74
+ outcome: "success",
75
+ finishedTs: /* @__PURE__ */ new Date(),
76
+ message: message ? () => message : pending.message
77
+ };
78
+ }
79
+
80
+ // src/private/resources/checkout/saveCheckoutRecord.ts
81
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
82
+ import { dirname, join as join2 } from "node:path";
83
+
84
+ // src/private/resources/checkout/private/makeCheckoutFilename.ts
85
+ import { join } from "node:path";
86
+ function makeCheckoutFilename(config, data) {
87
+ const slug = data.name.toLowerCase().replace(/\s+/g, "-");
88
+ return join(config.root.path, config.checkouts.path, `${slug}-checkout.art`);
89
+ }
90
+
91
+ // src/private/resources/checkout/saveCheckoutRecord.ts
92
+ var HARDCODED_TEMPLATE = `# Module
93
+
94
+ ## Checkout: {{ name }}
95
+
96
+ **Repository:** {{ repository }}
97
+
98
+ **Location:** \`{{ location }}\`
99
+
100
+ **Branch:** \`{{ branch }}\`
101
+ `;
102
+ async function saveCheckoutRecord(config, data, filename) {
103
+ let template = HARDCODED_TEMPLATE;
104
+ const templatePath = join2(config.root.path, config.checkouts.template);
105
+ if (existsSync(templatePath)) {
106
+ template = readFileSync(templatePath, "utf-8");
107
+ }
108
+ const fileName = filename ?? makeCheckoutFilename(config, data);
109
+ let content = template.replace("{{ name }}", data.name).replace("{{ repository }}", data.repository ?? "").replace("{{ location }}", data.location).replace("{{ branch }}", data.branch);
110
+ if (!data.repository) {
111
+ content = content.replace(/\*\*Repository:\*\*\s*\n\n?/g, "");
112
+ }
113
+ mkdirSync(dirname(fileName), { recursive: true });
114
+ writeFileSync(fileName, content);
115
+ return fileName;
116
+ }
117
+
118
+ // src/private/commands/operations/createBranchOperation.ts
119
+ function createBranchOperation(checkout, branch) {
120
+ return {
121
+ ts: /* @__PURE__ */ new Date(),
122
+ checkout,
123
+ outcome: "pending",
124
+ operation: "branch",
125
+ branch,
126
+ message() {
127
+ return `branch ${branch}`;
128
+ },
129
+ timing() {
130
+ return this.finishedTs ? this.finishedTs.getTime() - this.ts.getTime() : NaN;
131
+ }
132
+ };
133
+ }
134
+
135
+ // src/private/commands/checkouts/doBranchCheckout.ts
136
+ async function doBranchCheckout(ctx, checkout, branch) {
137
+ const pending = createBranchOperation(checkout, branch);
138
+ try {
139
+ ctx.log.log(pending);
140
+ const outcome = await createOrSwitchBranch(checkout.path, branch);
141
+ ctx.log.log(
142
+ createOperationSuccess(
143
+ pending,
144
+ outcome === "created" ? `created ${branch}` : `switched to ${branch}`
145
+ )
146
+ );
147
+ const updated = { ...checkout, record: { ...checkout.record, branch } };
148
+ ctx.store.updateCheckout(updated);
149
+ await saveCheckoutRecord(ctx.config, updated.record, updated.filename);
150
+ return updated;
151
+ } catch (error) {
152
+ ctx.log.log(createOperationFailure(createBranchOperation(checkout, branch), error));
153
+ return null;
154
+ }
155
+ }
156
+
157
+ // src/private/operations/createGenericOperation.ts
158
+ function formatData(data) {
159
+ return data ? JSON.stringify(data) : "";
160
+ }
161
+ function createGenericOperation(operation, data) {
162
+ return {
163
+ ts: /* @__PURE__ */ new Date(),
164
+ outcome: "pending",
165
+ operation,
166
+ data,
167
+ message() {
168
+ return formatData(data);
169
+ },
170
+ timing() {
171
+ return this.finishedTs ? this.finishedTs.getTime() - this.ts.getTime() : NaN;
172
+ }
173
+ };
174
+ }
175
+
176
+ // src/private/present/presentCheckoutReport.ts
177
+ import { join as join3 } from "node:path";
178
+
179
+ // src/private/present/formatTable.ts
180
+ function formatTable(rows, headers) {
181
+ const allRows = [headers, ...rows];
182
+ const colWidths = headers.map(
183
+ (_, colIdx) => Math.max(...allRows.map((row) => String(row[colIdx]).length))
184
+ );
185
+ const lines = allRows.map(
186
+ (row) => row.map((cell, i) => String(cell).padEnd(colWidths[i])).join(" ")
187
+ );
188
+ return lines.join("\n");
189
+ }
190
+
191
+ // src/private/present/presentCheckoutReport.ts
192
+ function presentCheckoutReport(config, checkouts) {
193
+ const items = [...checkouts];
194
+ items.sort((a, b) => {
195
+ if (a.repo?.remote === "" && b.repo?.remote !== "") return 1;
196
+ if (a.repo?.remote !== "" && b.repo?.remote === "") return -1;
197
+ return a.repo?.name.localeCompare(b.repo?.name || "") || -1;
198
+ });
199
+ const headers = ["repo", "location", "branch", "states"];
200
+ const rows = items.map((c) => [
201
+ c.repo?.name || "-",
202
+ join3(config.clone.path, c.record.location),
203
+ c.scan?.state("remote").branch || c.record.branch,
204
+ c.scan?.issues().join("; ") || "-"
205
+ ]);
206
+ console.info("Checkouts:");
207
+ console.info(formatTable(rows, headers));
208
+ console.info("");
209
+ }
210
+
211
+ // src/private/present/private/truncateMiddle.ts
212
+ function truncateMiddle(str, limit) {
213
+ if (str.length <= limit) {
214
+ return str;
215
+ }
216
+ const keep = limit - 3;
217
+ const left = Math.ceil(keep / 2);
218
+ const right = Math.floor(keep / 2);
219
+ return `${str.slice(0, left)}[...]${str.slice(str.length - right)}`;
220
+ }
221
+
222
+ // src/private/present/makeOperationLogLine.ts
223
+ function makeOperationLogLine(op, options = {}) {
224
+ const { standalone } = options;
225
+ const timing = standalone ? `(${op.timing()}ms)` : String(op.timing());
226
+ return [
227
+ op.outcome === "pending" ? "\u23F3" : op.outcome === "success" ? "\u{1F7E2}" : "\u{1F534}",
228
+ op.checkout?.repo?.name,
229
+ op.checkout?.record.location,
230
+ op.operation,
231
+ truncateMiddle(op.message(), 50),
232
+ op.finishedTs ? timing : ""
233
+ ].filter(Boolean);
234
+ }
235
+
236
+ // src/private/present/presentOperationsReport.ts
237
+ function presentOperationsReport(log) {
238
+ const operations = log.all();
239
+ if (operations.length === 0) {
240
+ return;
241
+ }
242
+ const headers = ["", "repo", "checkout", "operation", "message", "ms"];
243
+ const rows = operations.map((op) => makeOperationLogLine(op));
244
+ console.info("Operations Report:");
245
+ console.info(formatTable(rows, headers));
246
+ console.info("");
247
+ }
248
+
249
+ // src/private/resources/checkout/loadCheckoutRecords.ts
250
+ import { findRecordFiles } from "@art-cli/lib-records";
251
+
252
+ // src/private/resources/checkout/readCheckoutRecord.ts
253
+ import { readRecordFileContent } from "@art-cli/lib-records";
254
+ async function readCheckoutRecord(file) {
255
+ const fileWithContents = file.content ? file : await readRecordFileContent(file);
256
+ if (!fileWithContents.content) {
257
+ return null;
258
+ }
259
+ const content = fileWithContents.content;
260
+ const nameMatch = content.match(/## Checkout:\s*(.+)/);
261
+ if (!nameMatch) {
262
+ return null;
263
+ }
264
+ const repositoryMatch = content.match(/\*\*Repository:\*\*\s*(.+)/);
265
+ const locationMatch = content.match(/\*\*Location:\*\*\s*`([^`]+)`/);
266
+ const branchMatch = content.match(/\*\*Branch:\*\*\s*`([^`]+)`/);
267
+ if (!locationMatch) {
268
+ console.warn(`checkout record ${file.filename}: missing location, using default`);
269
+ }
270
+ if (!branchMatch) {
271
+ console.warn(`checkout record ${file.filename}: missing branch, using default`);
272
+ }
273
+ return {
274
+ name: nameMatch[1]?.trim() ?? "",
275
+ repository: repositoryMatch?.[1]?.trim(),
276
+ location: locationMatch?.[1]?.trim() ?? "",
277
+ branch: branchMatch?.[1]?.trim() ?? "main"
278
+ };
279
+ }
280
+
281
+ // src/private/resources/checkout/loadCheckoutRecords.ts
282
+ async function loadCheckoutRecords(ctx, repos) {
283
+ const searchPath = ctx.config.root.path;
284
+ ctx.log.log(createGenericOperation("load-checkout-records", searchPath));
285
+ const recordFiles = await findRecordFiles(ctx.config.records, searchPath, ["Checkout"]);
286
+ const checkouts = await Promise.all(
287
+ recordFiles.map(async (file) => {
288
+ const record = await readCheckoutRecord(file);
289
+ if (!record) {
290
+ return null;
291
+ }
292
+ if (!record.name) {
293
+ console.warn("checkout record with empty name, skipped");
294
+ return null;
295
+ }
296
+ const repo = repos.find((r) => r.name === record.repository);
297
+ if (repo) {
298
+ return {
299
+ repo,
300
+ checkout: record,
301
+ filename: file.filename
302
+ };
303
+ }
304
+ return {
305
+ checkout: record,
306
+ filename: file.filename
307
+ };
308
+ })
309
+ );
310
+ return checkouts.filter((checkout) => checkout !== null);
311
+ }
312
+
313
+ // src/private/resources/repository/loadRepositoryRecords.ts
314
+ import { findRecordFiles as findRecordFiles2 } from "@art-cli/lib-records";
315
+
316
+ // src/private/resources/repository/readRepositoryRecord.ts
317
+ import { readRecordFileContent as readRecordFileContent2 } from "@art-cli/lib-records";
318
+ async function readRepositoryRecord(file) {
319
+ const fileWithContents = file.content ? file : await readRecordFileContent2(file);
320
+ if (!fileWithContents.content) {
321
+ return null;
322
+ }
323
+ const content = fileWithContents.content;
324
+ const nameMatch = content.match(/## Repository:\s*(.+)/);
325
+ if (!nameMatch) {
326
+ return null;
327
+ }
328
+ const remoteMatch = content.match(/\*\*Remote:\*\*\s*`([^`]+)`/);
329
+ const purposeMatch = content.match(/\*\*Purpose:\*\*\s*(.+)/);
330
+ const descriptionMatch = content.match(/\*\*Description:\*\*\s*(.+)/);
331
+ const consumersMatch = content.match(/\*\*Consumers:\*\*\s*(.+)/);
332
+ if (!remoteMatch) {
333
+ console.warn(`repository record ${file.filename}: missing remote, using default`);
334
+ }
335
+ return {
336
+ name: nameMatch[1]?.trim() ?? "",
337
+ remote: remoteMatch?.[1]?.trim() ?? "",
338
+ ...purposeMatch ? { purpose: purposeMatch[1].trim() } : {},
339
+ ...descriptionMatch ? { description: descriptionMatch[1].trim() } : {},
340
+ ...consumersMatch ? { consumers: consumersMatch[1].trim() } : {}
341
+ };
342
+ }
343
+
344
+ // src/private/resources/repository/loadRepositoryRecords.ts
345
+ async function loadRepositoryRecords(ctx) {
346
+ const searchPath = ctx.config.root.path;
347
+ ctx.log.log(createGenericOperation("load-repository-records", searchPath));
348
+ const recordFiles = await findRecordFiles2(ctx.config.records, searchPath, ["Repository"]);
349
+ const records = await Promise.all(recordFiles.map((file) => readRepositoryRecord(file)));
350
+ return records.filter((record) => record !== null);
351
+ }
352
+
353
+ // src/private/scan/scanCheckoutState.ts
354
+ import { access } from "node:fs/promises";
355
+
356
+ // src/private/git/getBehindAheadCount.ts
357
+ import simpleGit3 from "simple-git";
358
+ async function getBehindAheadCount(dir, remoteBranch) {
359
+ const git = simpleGit3(dir);
360
+ try {
361
+ if (!remoteBranch) {
362
+ const ahead2 = await git.raw(["rev-list", "--count", "HEAD", "--not", "--remotes=origin"]);
363
+ return { ahead: Number.parseInt(ahead2.trim(), 10) || 0, behind: 0 };
364
+ }
365
+ const counts = await git.raw(["rev-list", "--left-right", "--count", `${remoteBranch}...HEAD`]);
366
+ const [behind, ahead] = counts.trim().split(/\s+/).map(Number);
367
+ return { ahead, behind };
368
+ } catch {
369
+ return { ahead: 0, behind: 0 };
370
+ }
371
+ }
372
+
373
+ // src/private/git/getCurrentBranch.ts
374
+ import simpleGit4 from "simple-git";
375
+ async function getCurrentBranch(dir) {
376
+ const git = simpleGit4(dir);
377
+ try {
378
+ const status = await git.status();
379
+ const branch = status.current ?? "HEAD";
380
+ if (!status.current || status.current === "HEAD") {
381
+ try {
382
+ const refOutput = await git.raw(["symbolic-ref", "-q", "HEAD"]);
383
+ if (!refOutput.trim()) {
384
+ return "HEAD";
385
+ }
386
+ } catch {
387
+ return "HEAD";
388
+ }
389
+ }
390
+ return branch;
391
+ } catch {
392
+ return "-";
393
+ }
394
+ }
395
+
396
+ // src/private/git/getRemoteBranch.ts
397
+ import simpleGit5 from "simple-git";
398
+ async function getRemoteBranch(dir) {
399
+ const git = simpleGit5(dir);
400
+ try {
401
+ const branches = await git.branch();
402
+ const current = branches.current;
403
+ if (!current || current === "HEAD") {
404
+ return null;
405
+ }
406
+ const tracking = branches.all.find(
407
+ (b) => b === `origin/${current}` || b === `remotes/origin/${current}`
408
+ );
409
+ return tracking ? tracking.replace(/^remotes\//, "") : null;
410
+ } catch {
411
+ return null;
412
+ }
413
+ }
414
+
415
+ // src/private/git/getRemoteUrl.ts
416
+ import simpleGit6 from "simple-git";
417
+ async function getRemoteUrl(dir) {
418
+ const git = simpleGit6(dir);
419
+ try {
420
+ const config = await git.listConfig();
421
+ const url = config.all["remote.origin.url"];
422
+ if (typeof url === "string") return url;
423
+ if (Array.isArray(url) && url.length > 0) return url[0];
424
+ return null;
425
+ } catch {
426
+ return null;
427
+ }
428
+ }
429
+
430
+ // src/private/git/hasMergeConflicts.ts
431
+ import simpleGit7 from "simple-git";
432
+ async function hasMergeConflicts(dir) {
433
+ const git = simpleGit7(dir);
434
+ try {
435
+ const status = await git.status();
436
+ return status.conflicted.length > 0;
437
+ } catch {
438
+ return false;
439
+ }
440
+ }
441
+
442
+ // src/private/git/hasRemote.ts
443
+ import simpleGit8 from "simple-git";
444
+ async function hasRemote(dir) {
445
+ const git = simpleGit8(dir);
446
+ try {
447
+ const remotes = await git.getRemotes(false);
448
+ return remotes.length > 0;
449
+ } catch {
450
+ return false;
451
+ }
452
+ }
453
+
454
+ // src/private/git/isDetachedHead.ts
455
+ import simpleGit9 from "simple-git";
456
+ async function isDetachedHead(dir) {
457
+ const git = simpleGit9(dir);
458
+ try {
459
+ const status = await git.status();
460
+ if (status.current && status.current !== "HEAD") {
461
+ return false;
462
+ }
463
+ try {
464
+ const refOutput = await git.raw(["symbolic-ref", "-q", "HEAD"]);
465
+ return !refOutput.trim();
466
+ } catch {
467
+ return true;
468
+ }
469
+ } catch {
470
+ return false;
471
+ }
472
+ }
473
+
474
+ // src/private/git/isDirty.ts
475
+ import simpleGit10 from "simple-git";
476
+ async function isDirty(dir) {
477
+ const git = simpleGit10(dir);
478
+ try {
479
+ const status = await git.status();
480
+ return status.files.length > 0;
481
+ } catch {
482
+ return false;
483
+ }
484
+ }
485
+
486
+ // src/private/git/remoteFetch.ts
487
+ import simpleGit11 from "simple-git";
488
+ async function remoteFetch(dir) {
489
+ const git = simpleGit11(dir);
490
+ try {
491
+ await git.fetch("origin");
492
+ } catch {
493
+ }
494
+ }
495
+
496
+ // src/private/scan/states/createCommittedState.ts
497
+ var createCommittedState = (clean) => ({
498
+ type: "committed",
499
+ clean
500
+ });
501
+
502
+ // src/private/scan/states/createExistsState.ts
503
+ var createExistsState = (exists) => ({
504
+ type: "exists",
505
+ exists
506
+ });
507
+
508
+ // src/private/scan/states/createNoConflictsState.ts
509
+ var createNoConflictsState = (clear) => ({
510
+ type: "no-conflicts",
511
+ clear
512
+ });
513
+
514
+ // src/private/scan/states/createNoDetachedState.ts
515
+ var createNoDetachedState = (attached) => ({
516
+ type: "no-detached",
517
+ attached
518
+ });
519
+
520
+ // src/private/scan/states/createRemoteState.ts
521
+ var createRemoteState = (branch, expectedBranch, hasRemote2) => ({ type: "remote", branch, expectedBranch, hasRemote: hasRemote2 });
522
+
523
+ // src/private/scan/states/createRepoState.ts
524
+ var createRepoState = (known) => ({ type: "repo", known });
525
+
526
+ // src/private/scan/states/createSyncState.ts
527
+ var createSyncState = (delta, ahead = Math.max(delta, 0), behind = Math.max(-delta, 0)) => ({
528
+ type: "sync",
529
+ delta,
530
+ ahead,
531
+ behind
532
+ });
533
+
534
+ // src/private/scan/states/createWrongRemoteState.ts
535
+ var createWrongRemoteState = (wrong) => ({
536
+ type: "wrong-remote",
537
+ wrong
538
+ });
539
+
540
+ // src/private/scan/private/createStateAccessor.ts
541
+ function createStateAccessor(states) {
542
+ return (type) => {
543
+ const state = states.find((item) => item.type === type);
544
+ if (!state) throw new Error(`missing checkout state: ${type}`);
545
+ return state;
546
+ };
547
+ }
548
+
549
+ // src/private/scan/private/createCheckoutScan.ts
550
+ function createCheckoutScan(states) {
551
+ const state = createStateAccessor(states);
552
+ const issues = () => {
553
+ const result = [];
554
+ const repo = state("repo");
555
+ const exists = state("exists");
556
+ const remote = state("remote");
557
+ const sync = state("sync");
558
+ if (!repo.known) result.push("unknown project");
559
+ if (!exists.exists) return [...result, "not cloned"];
560
+ if (!state("no-detached").attached) result.push("detached HEAD");
561
+ if (remote.expectedBranch !== "" && remote.branch !== remote.expectedBranch && state("no-detached").attached) {
562
+ result.push("wrong branch");
563
+ }
564
+ if (!state("no-conflicts").clear) result.push("merge conflicts");
565
+ if (!remote.hasRemote) result.push("no remote");
566
+ if (remote.hasRemote && state("wrong-remote").wrong) result.push("wrong remote");
567
+ if (!state("committed").clean) result.push("uncommitted files");
568
+ if (sync.ahead > 0) result.push(`${sync.ahead} commit${sync.ahead === 1 ? "" : "s"} ahead`);
569
+ if (sync.behind > 0) {
570
+ const count = sync.behind;
571
+ result.push(`${count} commit${count === 1 ? "" : "s"} behind`);
572
+ }
573
+ return result;
574
+ };
575
+ return {
576
+ states,
577
+ state,
578
+ issues,
579
+ can: (op) => {
580
+ if (op === "clone") return !state("exists").exists;
581
+ if (op === "branch") return state("exists").exists && state("no-detached").attached;
582
+ const exists = state("exists");
583
+ const remote = state("remote");
584
+ return exists.exists && remote.branch === remote.expectedBranch && state("committed").clean && state("no-conflicts").clear && state("no-detached").attached && remote.hasRemote;
585
+ },
586
+ should: (op) => {
587
+ if (op === "clone") return !state("exists").exists;
588
+ if (op === "pull") return state("sync").behind > 0;
589
+ if (op === "push") return state("sync").ahead > 0;
590
+ return false;
591
+ }
592
+ };
593
+ }
594
+
595
+ // src/private/scan/private/createCheckoutNoClonedScan.ts
596
+ function createCheckoutNoClonedScan(known) {
597
+ return createCheckoutScan([
598
+ createRepoState(known),
599
+ createExistsState(false),
600
+ createRemoteState(null, "", false),
601
+ createSyncState(0),
602
+ createCommittedState(true),
603
+ createNoConflictsState(true),
604
+ createNoDetachedState(true)
605
+ ]);
606
+ }
607
+
608
+ // src/private/scan/scanCheckoutState.ts
609
+ async function scanCheckoutState(ctx, checkout, refetch = false) {
610
+ try {
611
+ await access(checkout.path);
612
+ } catch {
613
+ return { ...checkout, scan: createCheckoutNoClonedScan(Boolean(checkout.repo)) };
614
+ }
615
+ ctx.log.log(createGenericOperation("scan-checkout-state", checkout.record.location));
616
+ let branch = null;
617
+ let remoteBranch = null;
618
+ let remote = false;
619
+ let dirty = false;
620
+ let conflicts = false;
621
+ let detached = false;
622
+ let ahead = 0;
623
+ let behind = 0;
624
+ let wrongRemote = false;
625
+ try {
626
+ branch = await getCurrentBranch(checkout.path);
627
+ remote = await hasRemote(checkout.path);
628
+ detached = await isDetachedHead(checkout.path);
629
+ conflicts = await hasMergeConflicts(checkout.path);
630
+ dirty = await isDirty(checkout.path);
631
+ if (remote && branch !== "-" && branch !== "HEAD") {
632
+ remoteBranch = await getRemoteBranch(checkout.path);
633
+ if (refetch) await remoteFetch(checkout.path);
634
+ const { ahead: aheadCount, behind: behindCount } = await getBehindAheadCount(
635
+ checkout.path,
636
+ remoteBranch
637
+ );
638
+ ahead = aheadCount;
639
+ behind = behindCount;
640
+ }
641
+ if (remote && checkout.repo?.remote) {
642
+ const actualUrl = await getRemoteUrl(checkout.path);
643
+ if (actualUrl && actualUrl !== checkout.repo.remote) {
644
+ wrongRemote = true;
645
+ }
646
+ }
647
+ } catch (error) {
648
+ ctx.log.log(
649
+ createOperationFailure(
650
+ createGenericOperation("scan-checkout-state", checkout.record.location),
651
+ error
652
+ )
653
+ );
654
+ }
655
+ const remoteState = createRemoteState(branch, checkout.record.branch, remote);
656
+ const scan = createCheckoutScan([
657
+ createRepoState(Boolean(checkout.repo)),
658
+ createExistsState(true),
659
+ remoteState,
660
+ createSyncState(ahead - behind, ahead, behind),
661
+ createCommittedState(!dirty),
662
+ createNoConflictsState(!conflicts),
663
+ createNoDetachedState(!detached),
664
+ createWrongRemoteState(wrongRemote)
665
+ ]);
666
+ return { ...checkout, scan };
667
+ }
668
+
669
+ // src/private/store/createCheckout.ts
670
+ import path, { join as join4 } from "node:path";
671
+
672
+ // src/private/store/safePath.ts
673
+ function safePath(pathStr) {
674
+ return pathStr.toLowerCase().replace(/[^a-z-]/g, "-").replace(/-+/g, "-");
675
+ }
676
+
677
+ // src/private/store/createCheckout.ts
678
+ function createCheckout(config, target, repo, branch, name) {
679
+ const basePath = join4(config.root.path, config.clone.path);
680
+ const l = safePath(target);
681
+ const r = repo;
682
+ const b = branch ?? "main";
683
+ const n = name || (r?.name ? r?.name + " @ " + target : target);
684
+ return {
685
+ repo: r,
686
+ record: { name: n, location: l, branch: b, repository: r?.name },
687
+ path: path.join(basePath, l)
688
+ };
689
+ }
690
+
691
+ // src/private/store/hydrateStoreFromRecords.ts
692
+ function hydrateStoreFromRecords(config, store, records) {
693
+ for (const record of records) {
694
+ const checkout = createCheckout(
695
+ config,
696
+ record.checkout.location,
697
+ record.repo,
698
+ record.checkout.branch,
699
+ record.checkout.name
700
+ );
701
+ store.addCheckout({ ...checkout, filename: record.filename });
702
+ }
703
+ }
704
+
705
+ // src/private/async/runWithConcurrency.ts
706
+ async function runWithConcurrency(items, limit, task) {
707
+ let index = 0;
708
+ const workers = Array.from({ length: Math.min(limit, items.length) }, async () => {
709
+ while (index < items.length) {
710
+ const i = index++;
711
+ await task(items[i]);
712
+ }
713
+ });
714
+ await Promise.all(workers);
715
+ }
716
+
717
+ // src/private/store/scanAllCheckoutsStates.ts
718
+ async function scanAllCheckoutsStates(ctx, refetch = false) {
719
+ ctx.log.log(createGenericOperation("scan-all-checkouts"));
720
+ await runWithConcurrency(ctx.store.getAllCheckouts(), 4, async (checkout) => {
721
+ const updated = await scanCheckoutState(ctx, checkout, refetch);
722
+ ctx.store.updateCheckout(updated);
723
+ });
724
+ }
725
+
726
+ // src/commands/branch/runBranch.ts
727
+ async function runBranch(ctx, options) {
728
+ const repos = await loadRepositoryRecords(ctx);
729
+ const records = await loadCheckoutRecords(ctx, repos);
730
+ hydrateStoreFromRecords(ctx.config, ctx.store, records);
731
+ ctx.log.log(createGenericOperation("command", ["branch", options.branch, options.checkouts]));
732
+ if (!options.all && (!options.checkouts || options.checkouts.length === 0)) {
733
+ console.error("No checkouts matched.");
734
+ console.error(
735
+ `Usage: Use \`art-workspace branch [options] -c <pattern>\` or \`art-workspace branch [options] --all\` if you want to apply the branch to all checkouts.`
736
+ );
737
+ return;
738
+ }
739
+ const { branch, checkouts } = options;
740
+ const resolvedCheckouts = options.all ? ctx.store.getAllCheckouts() : ctx.store.getCheckoutsByPattern(checkouts ?? []);
741
+ for (const checkout of resolvedCheckouts) {
742
+ const scanned = await scanCheckoutState(ctx, checkout);
743
+ ctx.store.updateCheckout(scanned);
744
+ if (!scanned.scan?.can?.("branch")) {
745
+ ctx.log.log(
746
+ createOperationFailure(createBranchOperation(scanned, branch), "checkout not cloned")
747
+ );
748
+ continue;
749
+ }
750
+ await doBranchCheckout(ctx, scanned, branch);
751
+ }
752
+ await scanAllCheckoutsStates(ctx);
753
+ presentCheckoutReport(ctx.config, ctx.store.getAllCheckouts());
754
+ presentOperationsReport(ctx.log);
755
+ }
756
+
757
+ // src/private/exec/runCommandInDirectory.ts
758
+ import { spawn } from "node:child_process";
759
+ function runCommandInDirectory(dir, command) {
760
+ return new Promise((resolve) => {
761
+ const [cmd, ...args] = command.length === 1 ? command[0].split(/\s+/) : command;
762
+ const child = spawn(cmd, args, { cwd: dir });
763
+ let output = "";
764
+ let error = "";
765
+ child.stdout?.on("data", (chunk) => output += chunk);
766
+ child.stderr?.on("data", (chunk) => error += chunk);
767
+ child.on("error", (err) => resolve({ code: null, output, error: err.message }));
768
+ child.on("exit", (code) => resolve({ code, output, error }));
769
+ });
770
+ }
771
+
772
+ // src/private/commands/operations/createCheckoutRunOperation.ts
773
+ function createCheckoutRunOperation(checkout, command) {
774
+ return {
775
+ ts: /* @__PURE__ */ new Date(),
776
+ checkout,
777
+ outcome: "pending",
778
+ operation: "run",
779
+ command,
780
+ message() {
781
+ return command;
782
+ },
783
+ timing() {
784
+ return this.finishedTs ? this.finishedTs.getTime() - this.ts.getTime() : NaN;
785
+ }
786
+ };
787
+ }
788
+
789
+ // src/private/commands/checkouts/doCheckoutRun.ts
790
+ async function doCheckoutRun(ctx, checkout, command) {
791
+ const commandLine = command.join(" ");
792
+ if (!checkout.scan?.state("exists").exists) {
793
+ const op = createOperationFailure(
794
+ createCheckoutRunOperation(checkout, commandLine),
795
+ new Error("checkout not cloned")
796
+ );
797
+ ctx.log.log(op);
798
+ return null;
799
+ }
800
+ const pending = createCheckoutRunOperation(checkout, commandLine);
801
+ try {
802
+ ctx.log.log(pending);
803
+ const runOutcome = await runCommandInDirectory(checkout.path, command);
804
+ if (runOutcome.code === 0) {
805
+ ctx.log.log(createOperationSuccess(pending));
806
+ } else {
807
+ ctx.log.log(createOperationFailure(pending, new Error(`Exit code: ${runOutcome.code}`)));
808
+ }
809
+ if (!runOutcome.output.trim() && !runOutcome.error.trim()) {
810
+ console.info("\n--- [No output]\n");
811
+ } else {
812
+ if (runOutcome.output) {
813
+ console.info("\n--- Output:\n");
814
+ console.info(runOutcome.output);
815
+ console.info("");
816
+ }
817
+ if (runOutcome.error) {
818
+ console.error("\n--- Error:\n");
819
+ console.error(runOutcome.error);
820
+ console.error("");
821
+ }
822
+ }
823
+ return checkout;
824
+ } catch (error) {
825
+ ctx.log.log(createOperationFailure(pending, error));
826
+ return null;
827
+ }
828
+ }
829
+
830
+ // src/commands/checkouts/runCheckoutsRun.ts
831
+ async function runCheckoutsRun(ctx, options) {
832
+ const repos = await loadRepositoryRecords(ctx);
833
+ const records = await loadCheckoutRecords(ctx, repos);
834
+ hydrateStoreFromRecords(ctx.config, ctx.store, records);
835
+ ctx.log.log(createGenericOperation("command", ["checkouts", "run", options.command]));
836
+ await scanAllCheckoutsStates(ctx);
837
+ if (!options.all && (!options.checkouts || options.checkouts.length === 0)) {
838
+ console.error("No checkouts matched.");
839
+ console.error(
840
+ `Usage: Use \`art-workspace checkouts run [options] -c <pattern>\` or \`art-workspace checkouts run [options] --all\` if you want to run the command in all checkouts.`
841
+ );
842
+ return;
843
+ }
844
+ const checkouts = options.all ? ctx.store.getAllCheckouts() : ctx.store.getCheckoutsByPattern(options.checkouts ?? []);
845
+ await runWithConcurrency(checkouts, 4, async (checkout) => {
846
+ await doCheckoutRun(ctx, checkout, options.command);
847
+ });
848
+ presentCheckoutReport(ctx.config, checkouts);
849
+ presentOperationsReport(ctx.log);
850
+ }
851
+
852
+ // src/private/git/cloneCheckout.ts
853
+ import simpleGit12 from "simple-git";
854
+ async function cloneCheckout(checkout) {
855
+ const recordedBranch = checkout.record.branch;
856
+ const git = simpleGit12("");
857
+ if (!checkout.repo?.remote) {
858
+ throw new Error(``);
859
+ }
860
+ await git.clone(checkout.repo.remote, checkout.path);
861
+ if (recordedBranch) {
862
+ try {
863
+ const repoGit = simpleGit12(checkout.path);
864
+ await repoGit.checkout(recordedBranch);
865
+ } catch {
866
+ }
867
+ }
868
+ }
869
+
870
+ // src/private/commands/operations/createCloneOperation.ts
871
+ function createCloneOperation(checkout) {
872
+ return {
873
+ ts: /* @__PURE__ */ new Date(),
874
+ checkout,
875
+ outcome: "pending",
876
+ operation: "clone",
877
+ location: checkout?.record.location ?? "unknown",
878
+ message() {
879
+ return checkout ? `to ${checkout.record.location}` : "clone";
880
+ },
881
+ timing() {
882
+ return this.finishedTs ? this.finishedTs.getTime() - this.ts.getTime() : NaN;
883
+ }
884
+ };
885
+ }
886
+
887
+ // src/private/commands/doClone.ts
888
+ async function doClone(ctx, checkout) {
889
+ if (!checkout.repo) return null;
890
+ const pending = createCloneOperation(checkout);
891
+ try {
892
+ ctx.log.log(pending);
893
+ await cloneCheckout(checkout);
894
+ const rescan = await scanCheckoutState(ctx, checkout);
895
+ ctx.store.updateCheckout(rescan);
896
+ ctx.log.log(createOperationSuccess(createCloneOperation(rescan)));
897
+ const actualBranch = await getCurrentBranch(checkout.path);
898
+ await saveCheckoutRecord(ctx.config, {
899
+ name: rescan.record.name,
900
+ repository: rescan.repo?.name,
901
+ location: rescan.record.location,
902
+ branch: actualBranch || rescan.record.branch || "main"
903
+ });
904
+ return rescan;
905
+ } catch (error) {
906
+ ctx.log.log(createOperationFailure(pending, error));
907
+ return null;
908
+ }
909
+ }
910
+
911
+ // src/commands/clone/private/cloneIfMissing.ts
912
+ async function cloneIfMissing(ctx, checkout) {
913
+ const scanned = await scanCheckoutState(ctx, checkout);
914
+ if (!scanned.scan?.should?.("clone")) {
915
+ return scanned;
916
+ }
917
+ if (!scanned.repo) {
918
+ return null;
919
+ }
920
+ return doClone(ctx, scanned);
921
+ }
922
+
923
+ // src/commands/clone/cloneAll.ts
924
+ async function cloneAll(ctx, repos) {
925
+ for (const repo of repos) {
926
+ if (!ctx.store.getCheckoutOfRepo(repo.name)) {
927
+ const checkout = createCheckout(ctx.config, repo.name, repo);
928
+ ctx.store.addCheckout(checkout);
929
+ }
930
+ }
931
+ for (const checkout of ctx.store.getAllCheckouts()) {
932
+ await cloneIfMissing(ctx, checkout);
933
+ }
934
+ await scanAllCheckoutsStates(ctx);
935
+ presentCheckoutReport(ctx.config, ctx.store.getAllCheckouts());
936
+ presentOperationsReport(ctx.log);
937
+ }
938
+
939
+ // src/commands/clone/cloneSpecific.ts
940
+ import { existsSync as existsSync2 } from "node:fs";
941
+ import { join as join5 } from "node:path";
942
+
943
+ // src/private/store/createCheckoutLocation.ts
944
+ function createCheckoutLocation(repo, target) {
945
+ return safePath(target ? repo.name + " " + target : repo.name);
946
+ }
947
+
948
+ // src/commands/clone/cloneSpecific.ts
949
+ async function cloneSpecific(ctx, repos, repoName, checkoutInput) {
950
+ const canonical = repoName.startsWith("@") ? repoName.split("/")[1] : repoName;
951
+ const repo = repos.find((r) => r.name.toLowerCase() === canonical.toLowerCase());
952
+ if (!repo) {
953
+ ctx.log.log(
954
+ createOperationFailure(createCloneOperation(void 0), `unknown repo "${repoName}"`)
955
+ );
956
+ presentOperationsReport(ctx.log);
957
+ return;
958
+ }
959
+ const location = createCheckoutLocation(repo, checkoutInput);
960
+ const existing = ctx.store.getCheckoutForLocation(location);
961
+ if (existing && existing.repo?.name !== repo.name) {
962
+ const msg = `location ${location} is already used by checkout '${existing.record.name}'.`;
963
+ ctx.log.log(createOperationFailure(createCloneOperation(existing), msg));
964
+ presentOperationsReport(ctx.log);
965
+ return;
966
+ }
967
+ if (existing) {
968
+ await cloneIfMissing(ctx, existing);
969
+ } else {
970
+ const targetDir = join5(ctx.config.root.path, ctx.config.clone.path, location);
971
+ if (existsSync2(targetDir)) {
972
+ const msg = `directory already exists at ${targetDir}`;
973
+ ctx.log.log(createOperationFailure(createCloneOperation(void 0), msg));
974
+ presentOperationsReport(ctx.log);
975
+ return;
976
+ }
977
+ const checkoutName = checkoutInput ? `${repo.name} @ ${checkoutInput}` : repo.name;
978
+ const created = createCheckout(ctx.config, location, repo, "main", checkoutName);
979
+ ctx.store.addCheckout(created);
980
+ await saveCheckoutRecord(ctx.config, created.record);
981
+ await cloneIfMissing(ctx, created);
982
+ }
983
+ await scanAllCheckoutsStates(ctx);
984
+ presentCheckoutReport(ctx.config, ctx.store.getAllCheckouts());
985
+ presentOperationsReport(ctx.log);
986
+ }
987
+
988
+ // src/commands/clone/cloneStatus.ts
989
+ async function cloneStatus(ctx) {
990
+ await scanAllCheckoutsStates(ctx);
991
+ presentCheckoutReport(ctx.config, ctx.store.getAllCheckouts());
992
+ }
993
+
994
+ // src/commands/clone/runClone.ts
995
+ async function runClone(ctx, { all, repoName, checkoutInput }) {
996
+ const repos = await loadRepositoryRecords(ctx);
997
+ const records = await loadCheckoutRecords(ctx, repos);
998
+ hydrateStoreFromRecords(ctx.config, ctx.store, records);
999
+ ctx.log.log(createGenericOperation("command", ["clone", { all, repoName, checkoutInput }]));
1000
+ if (all) {
1001
+ await cloneAll(ctx, repos);
1002
+ } else if (repoName) {
1003
+ await cloneSpecific(ctx, repos, repoName, checkoutInput);
1004
+ } else {
1005
+ await cloneStatus(ctx);
1006
+ }
1007
+ return ctx;
1008
+ }
1009
+
1010
+ // src/private/commands/operations/createLinkedOperation.ts
1011
+ function createLinkedOperation(checkout, pkg, target) {
1012
+ return {
1013
+ ts: /* @__PURE__ */ new Date(),
1014
+ checkout,
1015
+ outcome: "pending",
1016
+ operation: "linked",
1017
+ package: pkg,
1018
+ target,
1019
+ message() {
1020
+ return `linking ${pkg}`;
1021
+ },
1022
+ timing() {
1023
+ return this.finishedTs ? this.finishedTs.getTime() - this.ts.getTime() : NaN;
1024
+ }
1025
+ };
1026
+ }
1027
+
1028
+ // src/commands/link/runLink.ts
1029
+ async function runLink(ctx, _options) {
1030
+ ctx.log.log(createGenericOperation("command", ["link"]));
1031
+ ctx.log.log(createLinkedOperation(ctx.workspace, "", ""));
1032
+ console.info("link command - TODO");
1033
+ }
1034
+
1035
+ // src/private/commands/operations/createPublishOperation.ts
1036
+ function createPublishOperation(checkout, pkg, version) {
1037
+ return {
1038
+ ts: /* @__PURE__ */ new Date(),
1039
+ checkout,
1040
+ outcome: "pending",
1041
+ operation: "publish",
1042
+ package: pkg,
1043
+ version,
1044
+ message() {
1045
+ return `publishing ${pkg}@${version}`;
1046
+ },
1047
+ timing() {
1048
+ return this.finishedTs ? this.finishedTs.getTime() - this.ts.getTime() : NaN;
1049
+ }
1050
+ };
1051
+ }
1052
+
1053
+ // src/commands/publish/runPublish.ts
1054
+ async function runPublish(ctx, _options) {
1055
+ ctx.log.log(createGenericOperation("command", ["publish", _options.auto]));
1056
+ ctx.log.log(createPublishOperation(ctx.workspace, "", ""));
1057
+ console.info("publish command - TODO");
1058
+ }
1059
+
1060
+ // src/private/git/pullCheckout.ts
1061
+ import simpleGit13 from "simple-git";
1062
+ async function pullCheckout(checkout) {
1063
+ const git = simpleGit13(checkout.path);
1064
+ await git.pull("origin", checkout.record.branch);
1065
+ }
1066
+
1067
+ // src/private/commands/operations/createPullOperation.ts
1068
+ function createPullOperation(checkout, branch) {
1069
+ return {
1070
+ ts: /* @__PURE__ */ new Date(),
1071
+ checkout,
1072
+ outcome: "pending",
1073
+ operation: "pull",
1074
+ branch,
1075
+ message() {
1076
+ return `from origin/${branch}`;
1077
+ },
1078
+ timing() {
1079
+ return this.finishedTs ? this.finishedTs.getTime() - this.ts.getTime() : NaN;
1080
+ }
1081
+ };
1082
+ }
1083
+
1084
+ // src/private/commands/checkouts/doPullCheckout.ts
1085
+ async function doPullCheckout(ctx, checkout) {
1086
+ const pending = createPullOperation(checkout, checkout.record.branch);
1087
+ try {
1088
+ ctx.log.log(pending);
1089
+ await pullCheckout(checkout);
1090
+ const updated = await scanCheckoutState(ctx, checkout, true);
1091
+ ctx.store.updateCheckout(updated);
1092
+ ctx.log.log(createOperationSuccess(pending));
1093
+ return updated;
1094
+ } catch (error) {
1095
+ ctx.log.log(createOperationFailure(pending, error));
1096
+ return null;
1097
+ }
1098
+ }
1099
+
1100
+ // src/private/commands/workspaces/doPullWorkspaceCheckout.ts
1101
+ import simpleGit14 from "simple-git";
1102
+ async function doPullWorkspaceCheckout(ctx) {
1103
+ const workspace = ctx.workspace;
1104
+ if (!workspace) return null;
1105
+ if (!workspace.scan?.can?.("pull") || !workspace.scan.should?.("pull")) return null;
1106
+ const pending = createPullOperation(workspace, workspace.record.branch);
1107
+ const git = simpleGit14(workspace.path);
1108
+ try {
1109
+ ctx.log.log(pending);
1110
+ await git.pull("origin", workspace.record.branch);
1111
+ const updated = await scanCheckoutState(ctx, workspace, true);
1112
+ ctx.workspace = updated;
1113
+ ctx.log.log(createOperationSuccess(pending));
1114
+ return updated;
1115
+ } catch (error) {
1116
+ ctx.log.log(
1117
+ createOperationFailure(createPullOperation(workspace, workspace.record.branch), error)
1118
+ );
1119
+ return null;
1120
+ }
1121
+ }
1122
+
1123
+ // src/private/commands/workspaces/scanWorkspaceCheckout.ts
1124
+ async function scanWorkspaceCheckout(ctx, refetch = false) {
1125
+ const workspaceCheckout = {
1126
+ ...createCheckout(ctx.config, ".", void 0, "main", "Workspace"),
1127
+ path: ctx.config.root.path
1128
+ };
1129
+ const workspace = await scanCheckoutState(ctx, workspaceCheckout, refetch);
1130
+ ctx.workspace = workspace;
1131
+ return workspace;
1132
+ }
1133
+
1134
+ // src/commands/pull/runPull.ts
1135
+ async function runPull(ctx, options = {}) {
1136
+ const repos = await loadRepositoryRecords(ctx);
1137
+ const records = await loadCheckoutRecords(ctx, repos);
1138
+ hydrateStoreFromRecords(ctx.config, ctx.store, records);
1139
+ ctx.log.log(createGenericOperation("command", ["pull", options.checkouts]));
1140
+ await scanAllCheckoutsStates(ctx);
1141
+ if (!options.all && (!options.checkouts || options.checkouts.length === 0)) {
1142
+ console.error("No checkouts matched.");
1143
+ console.error(
1144
+ `Usage: Use \`art-workspace pull [options] -c <pattern>\` or \`art-workspace pull [options] --all\` if you want to apply the pull to all checkouts.`
1145
+ );
1146
+ return;
1147
+ }
1148
+ const checkouts = options.all ? ctx.store.getAllCheckouts() : ctx.store.getCheckoutsByPattern(options.checkouts ?? []);
1149
+ await runWithConcurrency(checkouts, 4, async (checkout) => {
1150
+ if (checkout.scan?.can?.("pull") && checkout.scan.should?.("pull")) {
1151
+ await doPullCheckout(ctx, checkout);
1152
+ }
1153
+ });
1154
+ await scanWorkspaceCheckout(ctx);
1155
+ await doPullWorkspaceCheckout(ctx);
1156
+ presentCheckoutReport(ctx.config, checkouts);
1157
+ presentOperationsReport(ctx.log);
1158
+ }
1159
+
1160
+ // src/private/git/pushCheckout.ts
1161
+ import simpleGit15 from "simple-git";
1162
+ async function pushCheckout(checkout) {
1163
+ const git = simpleGit15(checkout.path);
1164
+ await git.push("origin", checkout.record.branch);
1165
+ }
1166
+
1167
+ // src/private/commands/operations/createPushOperation.ts
1168
+ function createPushOperation(checkout, branch) {
1169
+ return {
1170
+ ts: /* @__PURE__ */ new Date(),
1171
+ checkout,
1172
+ outcome: "pending",
1173
+ operation: "push",
1174
+ branch,
1175
+ message() {
1176
+ return `to origin/${branch}`;
1177
+ },
1178
+ timing() {
1179
+ return this.finishedTs ? this.finishedTs.getTime() - this.ts.getTime() : NaN;
1180
+ }
1181
+ };
1182
+ }
1183
+
1184
+ // src/private/commands/checkouts/doPushCheckout.ts
1185
+ async function doPushCheckout(ctx, checkout) {
1186
+ const pending = createPushOperation(checkout, checkout.record.branch);
1187
+ try {
1188
+ ctx.log.log(pending);
1189
+ await pushCheckout(checkout);
1190
+ const updated = await scanCheckoutState(ctx, checkout, true);
1191
+ ctx.store.updateCheckout(updated);
1192
+ ctx.log.log(createOperationSuccess(pending));
1193
+ return updated;
1194
+ } catch (error) {
1195
+ ctx.log.log(createOperationFailure(pending, error));
1196
+ return null;
1197
+ }
1198
+ }
1199
+
1200
+ // src/private/commands/workspaces/doPushWorkspaceCheckout.ts
1201
+ import simpleGit16 from "simple-git";
1202
+ async function doPushWorkspaceCheckout(ctx) {
1203
+ const workspace = ctx.workspace;
1204
+ if (!workspace) return null;
1205
+ if (!workspace.scan?.can?.("push") || !workspace.scan.should?.("push")) return null;
1206
+ const pending = createPushOperation(workspace, workspace.record.branch);
1207
+ const git = simpleGit16(workspace.path);
1208
+ try {
1209
+ ctx.log.log(pending);
1210
+ await git.push("origin", workspace.record.branch);
1211
+ const updated = await scanCheckoutState(ctx, workspace, true);
1212
+ ctx.workspace = updated;
1213
+ ctx.log.log(createOperationSuccess(pending));
1214
+ return updated;
1215
+ } catch (error) {
1216
+ ctx.log.log(createOperationFailure(pending, error));
1217
+ return null;
1218
+ }
1219
+ }
1220
+
1221
+ // src/commands/push/runPush.ts
1222
+ async function runPush(ctx, options = {}) {
1223
+ const repos = await loadRepositoryRecords(ctx);
1224
+ const records = await loadCheckoutRecords(ctx, repos);
1225
+ hydrateStoreFromRecords(ctx.config, ctx.store, records);
1226
+ ctx.log.log(createGenericOperation("command", ["push", options.checkouts]));
1227
+ await scanAllCheckoutsStates(ctx);
1228
+ if (!options.all && (!options.checkouts || options.checkouts.length === 0)) {
1229
+ console.error("No checkouts matched.");
1230
+ console.error(
1231
+ `Usage: Use \`art-workspace push [options] -c <pattern>\` or \`art-workspace push [options] --all\` if you want to apply the push to all checkouts.`
1232
+ );
1233
+ return;
1234
+ }
1235
+ const checkouts = options.all ? ctx.store.getAllCheckouts() : ctx.store.getCheckoutsByPattern(options.checkouts ?? []);
1236
+ await runWithConcurrency(checkouts, 4, async (checkout) => {
1237
+ if (checkout.scan?.can?.("push") && checkout.scan.should?.("push")) {
1238
+ await doPushCheckout(ctx, checkout);
1239
+ }
1240
+ });
1241
+ await scanWorkspaceCheckout(ctx);
1242
+ await doPushWorkspaceCheckout(ctx);
1243
+ presentCheckoutReport(ctx.config, checkouts);
1244
+ presentOperationsReport(ctx.log);
1245
+ }
1246
+
1247
+ // src/private/present/presentCheckoutRepositoryState.ts
1248
+ function presentCheckoutRepositoryState(state) {
1249
+ console.info(`Repository:`);
1250
+ console.info(` name: ${state.target.repo?.name || "(unknown)"}`);
1251
+ console.info(` name: ${state.target.repo?.remote || "(unknown)"}`);
1252
+ if (state.issues.length > 0) {
1253
+ console.info(` issues: ${state.issues.join("; ")}`);
1254
+ }
1255
+ console.info("");
1256
+ console.info(`Checkout:`);
1257
+ console.info(` record: ${state.target.filename || "(unknown)"}`);
1258
+ console.info(` location: ${state.target.record.location || "(unknown)"}`);
1259
+ console.info(` branch: ${state.branch || state.target.record.branch}`);
1260
+ if (state.target.scan && state.target.scan.issues().length > 0) {
1261
+ console.info(` states: ${state.target.scan.issues().join("; ")}`);
1262
+ }
1263
+ console.info("");
1264
+ }
1265
+
1266
+ // src/private/present/presentPackageStateReport.ts
1267
+ function presentPackageStateReport(checkout, packageStates) {
1268
+ if (packageStates.length === 0) {
1269
+ return;
1270
+ }
1271
+ const headers = ["package", "version", "published", "states"];
1272
+ const rows = packageStates.map((ps) => [
1273
+ ps.canonicalName,
1274
+ ps.version ?? "-",
1275
+ ps.publishedVersion ?? "-",
1276
+ ps.states.join("; ") || "-"
1277
+ ]);
1278
+ console.info(`Packages for ${checkout.record.name}:`);
1279
+ console.info(formatTable(rows, headers));
1280
+ console.info("");
1281
+ }
1282
+
1283
+ // src/private/repositories/createPackageStateRecord.ts
1284
+ import { existsSync as existsSync3, readFileSync as readFileSync2 } from "node:fs";
1285
+ import { join as join6 } from "node:path";
1286
+ function createPackageStateRecord(checkoutPath, projectPath, nsPath, pkg) {
1287
+ let pkgPath = join6(checkoutPath, projectPath, nsPath, pkg.path);
1288
+ let pkgJsonPath = join6(pkgPath, "package.json");
1289
+ if (!existsSync3(pkgJsonPath)) {
1290
+ const altPath = join6(checkoutPath, projectPath, pkg.path);
1291
+ const altPkgJsonPath = join6(altPath, "package.json");
1292
+ if (existsSync3(altPkgJsonPath)) {
1293
+ pkgPath = altPath;
1294
+ pkgJsonPath = altPkgJsonPath;
1295
+ }
1296
+ }
1297
+ const record = {
1298
+ canonicalName: pkg.canonicalName,
1299
+ version: null,
1300
+ publishedVersion: null,
1301
+ directory: pkgPath,
1302
+ states: []
1303
+ };
1304
+ if (existsSync3(pkgJsonPath)) {
1305
+ try {
1306
+ const pkgJson = JSON.parse(readFileSync2(pkgJsonPath, "utf-8"));
1307
+ record.version = pkgJson.version ?? null;
1308
+ } catch {
1309
+ record.states.push("no package.json");
1310
+ }
1311
+ } else {
1312
+ record.states.push("no package.json");
1313
+ }
1314
+ return { pkgPath, record };
1315
+ }
1316
+
1317
+ // src/private/repositories/scanPackageStateRecord.ts
1318
+ import { execSync } from "node:child_process";
1319
+ function scanPackageStateRecord(pkg, record) {
1320
+ if (record.version !== null && record.version !== "0.0.0") {
1321
+ try {
1322
+ const output = execSync(`npm info ${pkg.canonicalName} version`, {
1323
+ encoding: "utf-8",
1324
+ timeout: 1e4,
1325
+ stdio: ["pipe", "pipe", "ignore"]
1326
+ });
1327
+ record.publishedVersion = output.trim() || null;
1328
+ } catch {
1329
+ record.publishedVersion = "unknown";
1330
+ }
1331
+ }
1332
+ }
1333
+
1334
+ // src/private/repositories/getRepositoryCheckoutPackages.ts
1335
+ function getRepositoryCheckoutPackages(checkoutPath, graph) {
1336
+ const packageStates = [];
1337
+ for (const project of graph.projects) {
1338
+ for (const nsName of project.namespaceNames) {
1339
+ const ns = graph.namespaces.get(nsName);
1340
+ if (!ns) continue;
1341
+ for (const pkgName of ns.packageNames) {
1342
+ const pkg = graph.packages.get(pkgName);
1343
+ if (!pkg) continue;
1344
+ const { record } = createPackageStateRecord(checkoutPath, project.path, ns.path, pkg);
1345
+ scanPackageStateRecord(pkg, record);
1346
+ packageStates.push(record);
1347
+ }
1348
+ }
1349
+ }
1350
+ return packageStates;
1351
+ }
1352
+
1353
+ // src/private/resources/namespace/loadNamespaceRecords.ts
1354
+ import { findRecordFiles as findRecordFiles3 } from "@art-cli/lib-records";
1355
+
1356
+ // src/private/resources/namespace/readNamespaceRecord.ts
1357
+ import { readRecordFileContent as readRecordFileContent3 } from "@art-cli/lib-records";
1358
+ async function readNamespaceRecord(file) {
1359
+ const fileWithContents = file.content ? file : await readRecordFileContent3(file);
1360
+ if (!fileWithContents.content) {
1361
+ return null;
1362
+ }
1363
+ const content = fileWithContents.content;
1364
+ const nameMatch = content.match(/## Namespace:\s*(.+)/);
1365
+ if (!nameMatch) {
1366
+ console.warn(`namespace record ${file.filename}: missing name, skipped`);
1367
+ return null;
1368
+ }
1369
+ const pathMatch = content.match(/\*\*Path:\*\*\s*`([^`]+)`/);
1370
+ const packagesMatch = content.match(/\*\*Packages:\*\*\s*([\s\S]*?)(?=\n\n|\n\*\*|$)/);
1371
+ let packageNames = [];
1372
+ if (packagesMatch) {
1373
+ packageNames = packagesMatch[1].split("\n").map((line) => line.replace(/^-\s*Package:\s*/, "").trim()).filter(Boolean);
1374
+ }
1375
+ return {
1376
+ kind: "namespace",
1377
+ name: nameMatch[1].trim(),
1378
+ path: pathMatch?.[1]?.trim() ?? ".",
1379
+ packageNames
1380
+ };
1381
+ }
1382
+
1383
+ // src/private/resources/namespace/loadNamespaceRecords.ts
1384
+ async function loadNamespaceRecords(config, checkoutPath) {
1385
+ const recordFiles = await findRecordFiles3(config.records, checkoutPath, ["Namespace"]);
1386
+ const records = await Promise.all(recordFiles.map((file) => readNamespaceRecord(file)));
1387
+ return records.filter((record) => record !== null);
1388
+ }
1389
+
1390
+ // src/private/resources/package/loadPackageRecords.ts
1391
+ import { findRecordFiles as findRecordFiles4 } from "@art-cli/lib-records";
1392
+
1393
+ // src/private/resources/package/readPackageRecord.ts
1394
+ import { readRecordFileContent as readRecordFileContent4 } from "@art-cli/lib-records";
1395
+ async function readPackageRecord(file) {
1396
+ const fileWithContents = file.content ? file : await readRecordFileContent4(file);
1397
+ if (!fileWithContents.content) {
1398
+ return null;
1399
+ }
1400
+ const content = fileWithContents.content;
1401
+ const nameMatch = content.match(/## Package:\s*(.+)/);
1402
+ if (!nameMatch) {
1403
+ console.warn(`package record ${file.filename}: missing name, skipped`);
1404
+ return null;
1405
+ }
1406
+ const canonicalNameMatch = content.match(/\*\*Canonical Name:\*\*\s*`([^`]+)`/);
1407
+ const pathMatch = content.match(/\*\*Path:\*\*\s*`([^`]+)`/);
1408
+ return {
1409
+ kind: "package",
1410
+ name: nameMatch[1].trim(),
1411
+ canonicalName: canonicalNameMatch?.[1]?.trim() ?? "",
1412
+ path: pathMatch?.[1]?.trim() ?? ""
1413
+ };
1414
+ }
1415
+
1416
+ // src/private/resources/package/loadPackageRecords.ts
1417
+ async function loadPackageRecords(config, checkoutPath) {
1418
+ const recordFiles = await findRecordFiles4(config.records, checkoutPath, ["Package"]);
1419
+ const records = await Promise.all(recordFiles.map((file) => readPackageRecord(file)));
1420
+ return records.filter((record) => record !== null);
1421
+ }
1422
+
1423
+ // src/private/resources/project/loadProjectRecords.ts
1424
+ import { findRecordFiles as findRecordFiles5 } from "@art-cli/lib-records";
1425
+
1426
+ // src/private/resources/project/readProjectRecord.ts
1427
+ import { readRecordFileContent as readRecordFileContent5 } from "@art-cli/lib-records";
1428
+ async function readProjectRecord(file) {
1429
+ const fileWithContents = file.content ? file : await readRecordFileContent5(file);
1430
+ if (!fileWithContents.content) {
1431
+ return null;
1432
+ }
1433
+ const content = fileWithContents.content;
1434
+ const nameMatch = content.match(/## Project:\s*(.+)/);
1435
+ if (!nameMatch) {
1436
+ console.warn(`project record ${file.filename}: missing name, skipped`);
1437
+ return null;
1438
+ }
1439
+ const pathMatch = content.match(/\*\*Path:\*\*\s*`([^`]+)`/);
1440
+ const namespacesMatch = content.match(/\*\*Namespaces:\*\*\s*([\s\S]*?)(?=\n\n|\n\*\*|$)/);
1441
+ let namespaceNames = [];
1442
+ if (namespacesMatch) {
1443
+ namespaceNames = namespacesMatch[1].split("\n").map((line) => line.replace(/^-\s*Namespace:\s*/, "").trim()).filter(Boolean);
1444
+ }
1445
+ return {
1446
+ kind: "project",
1447
+ name: nameMatch[1].trim(),
1448
+ path: pathMatch?.[1]?.trim() ?? ".",
1449
+ namespaceNames
1450
+ };
1451
+ }
1452
+
1453
+ // src/private/resources/project/loadProjectRecords.ts
1454
+ async function loadProjectRecords(config, checkoutPath) {
1455
+ const recordFiles = await findRecordFiles5(config.records, checkoutPath, ["Project"]);
1456
+ const records = await Promise.all(recordFiles.map((file) => readProjectRecord(file)));
1457
+ return records.filter((record) => record !== null);
1458
+ }
1459
+
1460
+ // src/private/resources/projectGraph/consolidateProjectGraph.ts
1461
+ function consolidateProjectGraph(projects, namespaces, packages) {
1462
+ const warnings = [];
1463
+ const nsMap = /* @__PURE__ */ new Map();
1464
+ const pkgMap = /* @__PURE__ */ new Map();
1465
+ for (const ns of namespaces) {
1466
+ nsMap.set(ns.name, ns);
1467
+ }
1468
+ for (const pkg of packages) {
1469
+ pkgMap.set(pkg.name, pkg);
1470
+ }
1471
+ for (const project of projects) {
1472
+ for (const nsName of project.namespaceNames) {
1473
+ if (!nsMap.has(nsName)) {
1474
+ warnings.push(`unknown namespace: ${nsName}`);
1475
+ }
1476
+ }
1477
+ for (const ns of namespaces) {
1478
+ if (!project.namespaceNames.includes(ns.name)) continue;
1479
+ for (const pkgName of ns.packageNames) {
1480
+ if (!pkgMap.has(pkgName)) {
1481
+ warnings.push(`unknown package: ${pkgName}`);
1482
+ }
1483
+ }
1484
+ }
1485
+ }
1486
+ return { projects, namespaces: nsMap, packages: pkgMap, warnings };
1487
+ }
1488
+
1489
+ // src/private/resources/projectGraph/loadProjectGraph.ts
1490
+ async function loadProjectGraph(config, checkoutPath) {
1491
+ const [projects, namespaces, packages] = await Promise.all([
1492
+ loadProjectRecords(config, checkoutPath),
1493
+ loadNamespaceRecords(config, checkoutPath),
1494
+ loadPackageRecords(config, checkoutPath)
1495
+ ]);
1496
+ return consolidateProjectGraph(projects, namespaces, packages);
1497
+ }
1498
+
1499
+ // src/commands/repo/runRepo.ts
1500
+ async function runRepo(ctx, options) {
1501
+ const repos = await loadRepositoryRecords(ctx);
1502
+ const records = await loadCheckoutRecords(ctx, repos);
1503
+ hydrateStoreFromRecords(ctx.config, ctx.store, records);
1504
+ ctx.log.log(createGenericOperation("command", ["repo", options.locations]));
1505
+ await scanAllCheckoutsStates(ctx);
1506
+ const { locations = [] } = options;
1507
+ const checkouts = /* @__PURE__ */ new Map();
1508
+ if (locations.length === 0) {
1509
+ const all = ctx.store.getAllCheckouts();
1510
+ all.forEach((checkout) => checkouts.set(checkout.record.location, checkout));
1511
+ } else {
1512
+ for (const name of locations) {
1513
+ const checkout = ctx.store.getCheckoutByName(name) ?? ctx.store.getCheckoutForLocation(name);
1514
+ if (!checkout) {
1515
+ console.warn(`unknown checkout: ${name}`);
1516
+ continue;
1517
+ }
1518
+ checkouts.set(checkout.record.location, checkout);
1519
+ }
1520
+ }
1521
+ const repositoryCheckoutStates = /* @__PURE__ */ new Map();
1522
+ const repositoryCheckoutPackages = /* @__PURE__ */ new Map();
1523
+ for (const [location, checkout] of checkouts) {
1524
+ const graph = await loadProjectGraph(ctx.config, checkout.path);
1525
+ const repositoryState = {
1526
+ target: checkout,
1527
+ branch: checkout.scan?.state("remote").branch ?? checkout.record.branch,
1528
+ issues: [],
1529
+ graph
1530
+ };
1531
+ repositoryCheckoutStates.set(location, repositoryState);
1532
+ for (const w of graph.warnings) {
1533
+ console.warn(w);
1534
+ }
1535
+ if (graph.projects.length === 0) {
1536
+ repositoryState.issues.push("no project records");
1537
+ continue;
1538
+ }
1539
+ const packageStates = getRepositoryCheckoutPackages(checkout.path, graph);
1540
+ repositoryCheckoutPackages.set(location, packageStates);
1541
+ }
1542
+ for (const [location, state] of repositoryCheckoutStates) {
1543
+ presentCheckoutRepositoryState(state);
1544
+ const packageStates = repositoryCheckoutPackages.get(location) ?? [];
1545
+ presentPackageStateReport(state.target, packageStates);
1546
+ }
1547
+ }
1548
+
1549
+ // src/private/present/presentExtraneousReport.ts
1550
+ function presentExtraneousReport(extraneous) {
1551
+ if (extraneous.length === 0) {
1552
+ return;
1553
+ }
1554
+ const headers = ["directory", "branch", "states"];
1555
+ const rows = extraneous.map((c) => [
1556
+ c.record.location,
1557
+ c.scan?.state("remote").branch || c.record.branch,
1558
+ c.scan?.issues().join("; ") || "clean"
1559
+ ]);
1560
+ console.info("Untracked:");
1561
+ console.info(formatTable(rows, headers));
1562
+ console.info("");
1563
+ }
1564
+
1565
+ // src/private/present/presentWorkspaceReport.ts
1566
+ function presentWorkspaceReport(workspace) {
1567
+ if (!workspace) {
1568
+ return;
1569
+ }
1570
+ const remote = workspace.scan?.state("remote").hasRemote ? workspace.scan.state("remote").branch || workspace.record.branch : void 0;
1571
+ const issues = workspace.scan?.issues().join("; ");
1572
+ const branch = workspace.scan?.state("remote").branch || workspace.record.branch;
1573
+ console.info("Workspace:");
1574
+ console.info(` remote: ${remote ?? "none"}`);
1575
+ console.info(` path: ${workspace.path}`);
1576
+ console.info(` branch: ${branch}`);
1577
+ console.info(` issues: ${issues || "-"}`);
1578
+ console.info("");
1579
+ }
1580
+
1581
+ // src/commands/sanity/private/scanExtraneousCheckouts.ts
1582
+ import { readdir } from "node:fs/promises";
1583
+ import { join as join7, relative } from "node:path";
1584
+
1585
+ // src/private/scan/private/createExtraneousCheckout.ts
1586
+ function createExtraneousCheckout(config, location) {
1587
+ return createCheckout(config, location, void 0, "", location);
1588
+ }
1589
+
1590
+ // src/commands/sanity/private/scanExtraneousCheckouts.ts
1591
+ async function scanExtraneousCheckouts(ctx, store) {
1592
+ const checkoutsPath = join7(ctx.config.root.path, ctx.config.clone.path);
1593
+ const result = [];
1594
+ try {
1595
+ const entries = await readdir(checkoutsPath, { withFileTypes: true });
1596
+ for (const entry of entries) {
1597
+ if (!entry.isDirectory()) {
1598
+ continue;
1599
+ }
1600
+ const dir = join7(checkoutsPath, entry.name);
1601
+ const location = relative(checkoutsPath, dir);
1602
+ const known = store.getCheckoutForLocation(location);
1603
+ if (known) {
1604
+ continue;
1605
+ }
1606
+ const checkout = { ...createExtraneousCheckout(ctx.config, location), path: dir };
1607
+ const scanned = await scanCheckoutState(ctx, checkout);
1608
+ result.push(scanned);
1609
+ }
1610
+ } catch {
1611
+ }
1612
+ return result;
1613
+ }
1614
+
1615
+ // src/commands/sanity/private/syncCheckouts.ts
1616
+ async function syncCheckouts(ctx) {
1617
+ await runWithConcurrency(ctx.store.getAllCheckouts(), 4, async (checkout) => {
1618
+ if (!checkout.scan?.can?.("push") || !checkout.scan.should?.("push")) return;
1619
+ await doPushCheckout(ctx, checkout);
1620
+ });
1621
+ }
1622
+
1623
+ // src/commands/sanity/runSanity.ts
1624
+ async function runSanity(ctx, options) {
1625
+ const repos = await loadRepositoryRecords(ctx);
1626
+ const records = await loadCheckoutRecords(ctx, repos);
1627
+ hydrateStoreFromRecords(ctx.config, ctx.store, records);
1628
+ ctx.log.log(createGenericOperation("command", ["sanity", options.auto]));
1629
+ await scanWorkspaceCheckout(ctx, options.refetch);
1630
+ await scanAllCheckoutsStates(ctx, options.refetch);
1631
+ if (options.auto) {
1632
+ await doPullWorkspaceCheckout(ctx);
1633
+ await syncCheckouts(ctx);
1634
+ }
1635
+ const extraneous = await scanExtraneousCheckouts(ctx, ctx.store);
1636
+ const workspaceIssues = ctx.workspace?.scan ? ctx.workspace.scan.issues().filter((i) => i !== "unknown project" && i !== "no remote" && i !== "wrong remote") : [];
1637
+ const filteredWorkspace = ctx.workspace ? {
1638
+ ...ctx.workspace,
1639
+ scan: ctx.workspace.scan ? { ...ctx.workspace.scan, issues: () => workspaceIssues } : void 0
1640
+ } : void 0;
1641
+ presentWorkspaceReport(filteredWorkspace);
1642
+ presentCheckoutReport(ctx.config, ctx.store.getAllCheckouts());
1643
+ presentExtraneousReport(extraneous);
1644
+ presentOperationsReport(ctx.log);
1645
+ }
1646
+
1647
+ // src/private/commands/workspaces/syncWorkspaceCheckout.ts
1648
+ import simpleGit17 from "simple-git";
1649
+ async function syncWorkspaceCheckout(ctx) {
1650
+ let workspace = ctx.workspace;
1651
+ if (!workspace) {
1652
+ workspace = {
1653
+ ...createCheckout(ctx.config, ".", void 0, "main", "Workspace"),
1654
+ path: ctx.config.root.path
1655
+ };
1656
+ const scanned = await scanCheckoutState(ctx, workspace, true);
1657
+ ctx.workspace = scanned;
1658
+ workspace = scanned;
1659
+ }
1660
+ const git = simpleGit17(workspace.path);
1661
+ if (workspace.scan?.can?.("pull")) {
1662
+ const pending = createPullOperation(workspace, workspace.record.branch);
1663
+ try {
1664
+ ctx.log.log(pending);
1665
+ await git.pull("origin", workspace.record.branch);
1666
+ ctx.log.log(createOperationSuccess(pending));
1667
+ } catch (error) {
1668
+ const op = createOperationFailure(pending, error);
1669
+ ctx.log.log(op);
1670
+ return null;
1671
+ }
1672
+ }
1673
+ if (workspace.scan?.can?.("push")) {
1674
+ const pending = createPushOperation(workspace, workspace.record.branch);
1675
+ try {
1676
+ ctx.log.log(pending);
1677
+ await git.push("origin", workspace.record.branch);
1678
+ ctx.log.log(createOperationSuccess(pending));
1679
+ } catch (error) {
1680
+ const op = createOperationFailure(pending, error);
1681
+ ctx.log.log(op);
1682
+ return null;
1683
+ }
1684
+ }
1685
+ const updated = await scanCheckoutState(ctx, workspace, true);
1686
+ ctx.workspace = updated;
1687
+ return updated;
1688
+ }
1689
+
1690
+ // src/commands/sync/runSync.ts
1691
+ async function runSync(ctx, options = {}) {
1692
+ const repos = await loadRepositoryRecords(ctx);
1693
+ const records = await loadCheckoutRecords(ctx, repos);
1694
+ hydrateStoreFromRecords(ctx.config, ctx.store, records);
1695
+ ctx.log.log(createGenericOperation("command", ["sync", options.checkouts]));
1696
+ await scanAllCheckoutsStates(ctx);
1697
+ if (!options.all && (!options.checkouts || options.checkouts.length === 0)) {
1698
+ console.error("No checkouts matched.");
1699
+ console.error(
1700
+ `Usage: Use \`art-workspace sync [options] -c <pattern>\` or \`art-workspace sync [options] --all\` if you want to apply the sync to all checkouts.`
1701
+ );
1702
+ return;
1703
+ }
1704
+ const checkouts = options.all ? ctx.store.getAllCheckouts() : ctx.store.getCheckoutsByPattern(options.checkouts ?? []);
1705
+ await runWithConcurrency(checkouts, 4, async (checkout) => {
1706
+ if (checkout.scan?.can?.("pull")) {
1707
+ const pulled = checkout.scan.should?.("pull") ? await doPullCheckout(ctx, checkout) : checkout;
1708
+ if (pulled?.scan?.can?.("push") && pulled.scan.should?.("push")) {
1709
+ await doPushCheckout(ctx, pulled);
1710
+ }
1711
+ }
1712
+ });
1713
+ await syncWorkspaceCheckout(ctx);
1714
+ presentCheckoutReport(ctx.config, checkouts);
1715
+ presentOperationsReport(ctx.log);
1716
+ }
1717
+
1718
+ // src/private/commands/operations/createUnlinkOperation.ts
1719
+ function createUnlinkOperation(checkout, pkg, source) {
1720
+ return {
1721
+ ts: /* @__PURE__ */ new Date(),
1722
+ checkout,
1723
+ outcome: "pending",
1724
+ operation: "unlink",
1725
+ package: pkg,
1726
+ source,
1727
+ message() {
1728
+ return `unlinking ${pkg}`;
1729
+ },
1730
+ timing() {
1731
+ return this.finishedTs ? this.finishedTs.getTime() - this.ts.getTime() : NaN;
1732
+ }
1733
+ };
1734
+ }
1735
+
1736
+ // src/commands/unlink/runUnlink.ts
1737
+ async function runUnlink(ctx, _options) {
1738
+ ctx.log.log(createGenericOperation("command", ["unlink"]));
1739
+ ctx.log.log(createUnlinkOperation(ctx.workspace, "", ""));
1740
+ console.info("unlink command - TODO");
1741
+ }
1742
+
1743
+ // src/config/loadWorkspaceConfig.ts
1744
+ import { existsSync as existsSync4, writeFileSync as writeFileSync2 } from "node:fs";
1745
+ import { join as join8 } from "node:path";
1746
+ import { pathToFileURL } from "node:url";
1747
+ import { build } from "esbuild";
1748
+
1749
+ // src/config/private/normalizeRecordPaths.ts
1750
+ var DEFAULTS = {
1751
+ base: ".",
1752
+ pattern: "*.art",
1753
+ ignored: ["node_modules/", ".git/", "dist/"],
1754
+ excluded: [],
1755
+ gitignore: true
1756
+ };
1757
+ function normalizeRecordPaths(records) {
1758
+ const paths = records?.paths;
1759
+ if (!paths || paths.length === 0) {
1760
+ return [
1761
+ {
1762
+ base: records?.base ?? DEFAULTS.base,
1763
+ pattern: records?.pattern ?? DEFAULTS.pattern,
1764
+ ignored: records?.ignored ?? DEFAULTS.ignored,
1765
+ excluded: records?.excluded ?? DEFAULTS.excluded,
1766
+ gitignore: records?.gitignore ?? DEFAULTS.gitignore
1767
+ }
1768
+ ];
1769
+ }
1770
+ return paths.map((p) => ({
1771
+ base: p.base ?? records?.base ?? DEFAULTS.base,
1772
+ pattern: p.pattern ?? records?.pattern ?? DEFAULTS.pattern,
1773
+ ignored: p.ignored ?? records?.ignored ?? DEFAULTS.ignored,
1774
+ excluded: [...p.excluded ?? [], ...records?.excluded ?? []],
1775
+ gitignore: p.gitignore ?? records?.gitignore ?? DEFAULTS.gitignore
1776
+ }));
1777
+ }
1778
+
1779
+ // src/config/defineConfig.ts
1780
+ function defineConfig(config) {
1781
+ const clonePath = config.clone?.path || "checkouts";
1782
+ const rootPath = config.root?.path || process.cwd();
1783
+ const checkoutsPath = config.checkouts?.path || "_records/";
1784
+ const checkoutTemplatePath = config.checkouts?.template || ".agents/domains/workspace/templates/checkout.art.njk";
1785
+ const recordsPaths = normalizeRecordPaths(config.records);
1786
+ return {
1787
+ clone: {
1788
+ path: clonePath
1789
+ },
1790
+ root: {
1791
+ path: rootPath
1792
+ },
1793
+ checkouts: {
1794
+ path: checkoutsPath,
1795
+ template: checkoutTemplatePath
1796
+ },
1797
+ records: {
1798
+ paths: recordsPaths
1799
+ }
1800
+ };
1801
+ }
1802
+
1803
+ // src/config/loadWorkspaceConfig.ts
1804
+ var MANIFEST_FILE = ".art-workspace.mts";
1805
+ var TEMP_FILE = ".art-workspace-bundle.mjs";
1806
+ var DEFAULT_CONFIG = {
1807
+ clone: { path: "checkouts" },
1808
+ checkouts: {
1809
+ path: "_records/",
1810
+ template: ".agents/domains/workspace/templates/checkout.art.njk"
1811
+ },
1812
+ records: {
1813
+ base: ".",
1814
+ pattern: "*.art",
1815
+ ignored: ["node_modules/", ".git/", "dist/"],
1816
+ excluded: [],
1817
+ gitignore: true
1818
+ }
1819
+ };
1820
+ function formatError(error) {
1821
+ return error instanceof Error ? error.message : String(error);
1822
+ }
1823
+ async function loadWorkspaceConfig(rootPath) {
1824
+ const manifestPath = join8(rootPath, MANIFEST_FILE);
1825
+ if (!existsSync4(manifestPath)) {
1826
+ console.warn(`${MANIFEST_FILE} not found at ${rootPath}; Using default config.`);
1827
+ return defineConfig({ ...DEFAULT_CONFIG, root: { path: rootPath } });
1828
+ }
1829
+ let output;
1830
+ try {
1831
+ output = await build({
1832
+ entryPoints: [manifestPath],
1833
+ bundle: true,
1834
+ write: false,
1835
+ format: "esm",
1836
+ platform: "node",
1837
+ external: [
1838
+ "node:fs",
1839
+ "node:os",
1840
+ "node:path",
1841
+ "node:url",
1842
+ "fs",
1843
+ "os",
1844
+ "path",
1845
+ "url",
1846
+ "esbuild",
1847
+ "simple-git"
1848
+ ]
1849
+ });
1850
+ } catch (error) {
1851
+ throw new Error(
1852
+ `Failed to bundle workspace manifest at ${manifestPath}: ${formatError(error)}`
1853
+ );
1854
+ }
1855
+ const tempFile = join8(rootPath, TEMP_FILE);
1856
+ writeFileSync2(tempFile, output.outputFiles[0].text);
1857
+ try {
1858
+ const loaded = await import(pathToFileURL(tempFile).href);
1859
+ const config = loaded.default;
1860
+ return defineConfig({ ...config, root: { path: rootPath } });
1861
+ } catch (error) {
1862
+ throw new Error(`Failed to load workspace manifest at ${manifestPath}: ${formatError(error)}`);
1863
+ }
1864
+ }
1865
+
1866
+ // src/private/context/createWorkspaceContext.ts
1867
+ function createWorkspaceContext(config, store, log, workspace) {
1868
+ return { config, store, log, workspace };
1869
+ }
1870
+
1871
+ // src/private/log/createOperationsLog.ts
1872
+ function createOperationsLog(logger2 = () => {
1873
+ }) {
1874
+ const operations = [];
1875
+ return {
1876
+ log(operation) {
1877
+ logger2(operation);
1878
+ if (operation.outcome !== "pending") {
1879
+ operations.push(operation);
1880
+ }
1881
+ },
1882
+ all() {
1883
+ return [...operations];
1884
+ },
1885
+ since(ts) {
1886
+ return operations.filter((op) => op.ts > ts);
1887
+ },
1888
+ latest(n) {
1889
+ return operations.slice(-n);
1890
+ }
1891
+ };
1892
+ }
1893
+
1894
+ // src/private/store/createCheckoutStore.ts
1895
+ function matchCheckoutByName(checkouts, name) {
1896
+ const n = name.toLowerCase();
1897
+ return Array.from(checkouts.values()).find((checkout) => checkout.record.name.toLowerCase() === n);
1898
+ }
1899
+ function matchCheckoutByLocation(checkouts, location) {
1900
+ return checkouts.get(location);
1901
+ }
1902
+ function patternToRegex(pattern) {
1903
+ const escaped = pattern.replace(/[.+?^${}()|[\]\\]/g, "\\$&");
1904
+ const globbed = escaped.replace(/\*/g, ".*");
1905
+ return new RegExp(`^${globbed}$`, "i");
1906
+ }
1907
+ function isWildcardPattern(pattern) {
1908
+ return pattern.includes("*");
1909
+ }
1910
+ function createCheckoutStore() {
1911
+ const checkouts = /* @__PURE__ */ new Map();
1912
+ function addCheckout(checkout) {
1913
+ const existing = checkouts.get(checkout.record.location);
1914
+ if (existing) {
1915
+ const msg = `Duplicate location: "${checkout.record.location}", existing: "${existing.record.name}" duplicate: "${checkout.record.name}".`;
1916
+ console.error(msg);
1917
+ } else {
1918
+ checkouts.set(checkout.record.location, checkout);
1919
+ }
1920
+ }
1921
+ return {
1922
+ addCheckout,
1923
+ getCheckoutForLocation(location) {
1924
+ return matchCheckoutByLocation(checkouts, location);
1925
+ },
1926
+ getCheckoutOfRepo(name) {
1927
+ const n = name.toLowerCase();
1928
+ return Array.from(checkouts.values()).find(
1929
+ (checkout) => checkout.repo?.name.toLowerCase() === n
1930
+ );
1931
+ },
1932
+ getCheckoutByName(name) {
1933
+ return matchCheckoutByName(checkouts, name);
1934
+ },
1935
+ getCheckoutsByPattern(patterns) {
1936
+ const matched = /* @__PURE__ */ new Map();
1937
+ for (const pattern of patterns) {
1938
+ let patternMatched = false;
1939
+ for (const checkout of checkouts.values()) {
1940
+ let nameMatch = false;
1941
+ let locationMatch = false;
1942
+ if (isWildcardPattern(pattern)) {
1943
+ const regex = patternToRegex(pattern);
1944
+ nameMatch = regex.test(checkout.record.name);
1945
+ locationMatch = regex.test(checkout.record.location);
1946
+ } else {
1947
+ nameMatch = matchCheckoutByName(checkouts, pattern) === checkout;
1948
+ locationMatch = matchCheckoutByLocation(checkouts, pattern) === checkout;
1949
+ }
1950
+ if (nameMatch || locationMatch) {
1951
+ matched.set(checkout.record.location, checkout);
1952
+ patternMatched = true;
1953
+ }
1954
+ }
1955
+ if (!patternMatched) {
1956
+ console.warn(`no checkout matches pattern: "${pattern}"`);
1957
+ }
1958
+ }
1959
+ return Array.from(matched.values());
1960
+ },
1961
+ updateCheckout(checkout) {
1962
+ checkouts.set(checkout.record.location, checkout);
1963
+ },
1964
+ getAllCheckouts() {
1965
+ return Array.from(checkouts.values());
1966
+ }
1967
+ };
1968
+ }
1969
+
1970
+ // src/index.ts
1971
+ var program = new Command();
1972
+ var logger = (op) => {
1973
+ console.info(makeOperationLogLine(op, { standalone: true }).join(" | "));
1974
+ };
1975
+ program.name("art-workspace").description("Workspace orchestration CLI").version("0.0.18");
1976
+ program.command("sanity").description("Check git status across all repos").option("-a, --auto", "push clean unpushed repos").option("-r, --refetch", "fetch ahead/behind data from remote").action(async (options) => {
1977
+ const root = process.cwd();
1978
+ logger(createGenericOperation("boot"));
1979
+ const config = await loadWorkspaceConfig(root);
1980
+ const store = createCheckoutStore();
1981
+ const log = createOperationsLog(logger);
1982
+ const ctx = createWorkspaceContext(config, store, log);
1983
+ const auto = options.auto ?? false;
1984
+ const refetch = options.refetch ?? false;
1985
+ await runSanity(ctx, { auto, refetch });
1986
+ });
1987
+ program.command("clone").description("Clone repos from manifest").option("-a, --all", "clone all repos").argument("[name]", "repo name to clone").argument("[target]", "target location (relative to checkouts path)").action(
1988
+ async (repoName, checkoutInput, options) => {
1989
+ const root = process.cwd();
1990
+ logger(createGenericOperation("boot"));
1991
+ const config = await loadWorkspaceConfig(root);
1992
+ const store = createCheckoutStore();
1993
+ const log = createOperationsLog(logger);
1994
+ const ctx = createWorkspaceContext(config, store, log);
1995
+ await runClone(ctx, { all: options.all, repoName, checkoutInput });
1996
+ }
1997
+ );
1998
+ program.command("branch").description("Branch across checkouts").argument("<branch>", "branch name to create or switch to").option(
1999
+ "-c, --checkouts <PATTERN...>",
2000
+ 'One or more. Matches checkout name and location. Wildcard asterisk * supported. Example: -c "* @ refactor" "lib-*"'
2001
+ ).option("-A, --all", "Apply to all checkouts").action(async (branch, options) => {
2002
+ const root = process.cwd();
2003
+ logger(createGenericOperation("boot"));
2004
+ const config = await loadWorkspaceConfig(root);
2005
+ const store = createCheckoutStore();
2006
+ const log = createOperationsLog(logger);
2007
+ const ctx = createWorkspaceContext(config, store, log);
2008
+ await runBranch(ctx, { branch, checkouts: options.checkouts, all: options.all });
2009
+ });
2010
+ program.command("pull").description("Pull clean checkouts that are behind").option(
2011
+ "-c, --checkouts <PATTERN...>",
2012
+ 'One or more. Matches checkout name and location. Wildcard asterisk * supported. Example: -c "* @ refactor" "lib-*"'
2013
+ ).option("-A, --all", "Apply to all checkouts").action(async (options) => {
2014
+ const root = process.cwd();
2015
+ logger(createGenericOperation("boot"));
2016
+ const config = await loadWorkspaceConfig(root);
2017
+ const store = createCheckoutStore();
2018
+ const log = createOperationsLog(logger);
2019
+ const ctx = createWorkspaceContext(config, store, log);
2020
+ await runPull(ctx, { checkouts: options.checkouts, all: options.all });
2021
+ });
2022
+ program.command("push").description("Push clean checkouts that are ahead").option(
2023
+ "-c, --checkouts <PATTERN...>",
2024
+ 'One or more. Matches checkout name and location. Wildcard asterisk * supported. Example: -c "* @ refactor" "lib-*"'
2025
+ ).option("-A, --all", "Apply to all checkouts").action(async (options) => {
2026
+ const root = process.cwd();
2027
+ logger(createGenericOperation("boot"));
2028
+ const config = await loadWorkspaceConfig(root);
2029
+ const store = createCheckoutStore();
2030
+ const log = createOperationsLog(logger);
2031
+ const ctx = createWorkspaceContext(config, store, log);
2032
+ await runPush(ctx, { checkouts: options.checkouts, all: options.all });
2033
+ });
2034
+ program.command("sync").description("Pull and push clean checkouts").option(
2035
+ "-c, --checkouts <PATTERN...>",
2036
+ 'One or more. Matches checkout name and location. Wildcard asterisk * supported. Example: -c "* @ refactor" "lib-*"'
2037
+ ).option("-A, --all", "Apply to all checkouts").action(async (options) => {
2038
+ const root = process.cwd();
2039
+ logger(createGenericOperation("boot"));
2040
+ const config = await loadWorkspaceConfig(root);
2041
+ const store = createCheckoutStore();
2042
+ const log = createOperationsLog(logger);
2043
+ const ctx = createWorkspaceContext(config, store, log);
2044
+ await runSync(ctx, { checkouts: options.checkouts, all: options.all });
2045
+ });
2046
+ program.command("checkouts").description("Checkout operations").command("run").description("Run a command in selected checkouts").argument("<command...>", "command to run").option(
2047
+ "-c, --checkouts <PATTERN...>",
2048
+ 'One or more. Matches checkout name and location. Wildcard asterisk * supported. Example: -c "* @ refactor" "lib-*"'
2049
+ ).option("-A, --all", "Apply to all checkouts").action(async (command, options) => {
2050
+ const root = process.cwd();
2051
+ logger(createGenericOperation("boot"));
2052
+ const config = await loadWorkspaceConfig(root);
2053
+ const store = createCheckoutStore();
2054
+ const log = createOperationsLog(logger);
2055
+ const ctx = createWorkspaceContext(config, store, log);
2056
+ await runCheckoutsRun(ctx, { command, checkouts: options.checkouts, all: options.all });
2057
+ });
2058
+ program.command("repo").description("List checkout resources").argument("[checkouts...]", "checkout locations to list (default: all checkouts)").action(async (locations) => {
2059
+ const root = process.cwd();
2060
+ logger(createGenericOperation("boot"));
2061
+ const config = await loadWorkspaceConfig(root);
2062
+ const store = createCheckoutStore();
2063
+ const log = createOperationsLog(logger);
2064
+ const ctx = createWorkspaceContext(config, store, log);
2065
+ await runRepo(ctx, { locations });
2066
+ });
2067
+ program.command("link").description("Link packages for local dev").action(async () => {
2068
+ const root = process.cwd();
2069
+ logger(createGenericOperation("boot"));
2070
+ const config = await loadWorkspaceConfig(root);
2071
+ const store = createCheckoutStore();
2072
+ const log = createOperationsLog(logger);
2073
+ const ctx = createWorkspaceContext(config, store, log);
2074
+ await runLink(ctx, { root });
2075
+ });
2076
+ program.command("unlink").description("Unlink packages").action(async () => {
2077
+ const root = process.cwd();
2078
+ logger(createGenericOperation("boot"));
2079
+ const config = await loadWorkspaceConfig(root);
2080
+ const store = createCheckoutStore();
2081
+ const log = createOperationsLog(logger);
2082
+ const ctx = createWorkspaceContext(config, store, log);
2083
+ await runUnlink(ctx, { root });
2084
+ });
2085
+ program.command("publish").description("Publish packages").option("-a, --auto", "auto-publish").action(async (options) => {
2086
+ const root = process.cwd();
2087
+ logger(createGenericOperation("boot"));
2088
+ const config = await loadWorkspaceConfig(root);
2089
+ const store = createCheckoutStore();
2090
+ const log = createOperationsLog(logger);
2091
+ const ctx = createWorkspaceContext(config, store, log);
2092
+ await runPublish(ctx, { root, auto: options.auto });
2093
+ });
2094
+ program.parse();
2095
+ export {
2096
+ defineConfig,
2097
+ loadWorkspaceConfig
2098
+ };