@detergent-software/atk 3.0.0 → 5.0.0-dev.1

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 (332) hide show
  1. package/README.md +361 -0
  2. package/build/commands/_app.d.ts.map +1 -1
  3. package/build/commands/_app.js +23 -3
  4. package/build/commands/_app.js.map +1 -1
  5. package/build/commands/audit.d.ts.map +1 -1
  6. package/build/commands/audit.js +76 -37
  7. package/build/commands/audit.js.map +1 -1
  8. package/build/commands/browse.d.ts.map +1 -1
  9. package/build/commands/browse.js +126 -154
  10. package/build/commands/browse.js.map +1 -1
  11. package/build/commands/cache.d.ts.map +1 -1
  12. package/build/commands/cache.js +13 -15
  13. package/build/commands/cache.js.map +1 -1
  14. package/build/commands/config.d.ts +1 -1
  15. package/build/commands/config.d.ts.map +1 -1
  16. package/build/commands/config.js +7 -3
  17. package/build/commands/config.js.map +1 -1
  18. package/build/commands/diff.d.ts.map +1 -1
  19. package/build/commands/diff.js +4 -117
  20. package/build/commands/diff.js.map +1 -1
  21. package/build/commands/freeze.d.ts +1 -2
  22. package/build/commands/freeze.d.ts.map +1 -1
  23. package/build/commands/freeze.js +17 -37
  24. package/build/commands/freeze.js.map +1 -1
  25. package/build/commands/info.d.ts +1 -2
  26. package/build/commands/info.d.ts.map +1 -1
  27. package/build/commands/info.js +43 -38
  28. package/build/commands/info.js.map +1 -1
  29. package/build/commands/init.d.ts.map +1 -1
  30. package/build/commands/init.js +41 -414
  31. package/build/commands/init.js.map +1 -1
  32. package/build/commands/install.d.ts.map +1 -1
  33. package/build/commands/install.js +79 -72
  34. package/build/commands/install.js.map +1 -1
  35. package/build/commands/list.d.ts +2 -2
  36. package/build/commands/list.d.ts.map +1 -1
  37. package/build/commands/list.js +138 -27
  38. package/build/commands/list.js.map +1 -1
  39. package/build/commands/outdated.d.ts.map +1 -1
  40. package/build/commands/outdated.js +20 -10
  41. package/build/commands/outdated.js.map +1 -1
  42. package/build/commands/pin.d.ts +1 -2
  43. package/build/commands/pin.d.ts.map +1 -1
  44. package/build/commands/pin.js +44 -47
  45. package/build/commands/pin.js.map +1 -1
  46. package/build/commands/prune.d.ts.map +1 -1
  47. package/build/commands/prune.js +76 -151
  48. package/build/commands/prune.js.map +1 -1
  49. package/build/commands/publish.d.ts +4 -1
  50. package/build/commands/publish.d.ts.map +1 -1
  51. package/build/commands/publish.js +139 -388
  52. package/build/commands/publish.js.map +1 -1
  53. package/build/commands/search.d.ts.map +1 -1
  54. package/build/commands/search.js +14 -19
  55. package/build/commands/search.js.map +1 -1
  56. package/build/commands/setup.d.ts +1 -1
  57. package/build/commands/setup.d.ts.map +1 -1
  58. package/build/commands/setup.js +48 -253
  59. package/build/commands/setup.js.map +1 -1
  60. package/build/commands/sync.d.ts.map +1 -1
  61. package/build/commands/sync.js +43 -169
  62. package/build/commands/sync.js.map +1 -1
  63. package/build/commands/thaw.d.ts +1 -2
  64. package/build/commands/thaw.d.ts.map +1 -1
  65. package/build/commands/thaw.js +19 -37
  66. package/build/commands/thaw.js.map +1 -1
  67. package/build/commands/uninstall.d.ts.map +1 -1
  68. package/build/commands/uninstall.js +106 -221
  69. package/build/commands/uninstall.js.map +1 -1
  70. package/build/commands/unpin.d.ts +1 -2
  71. package/build/commands/unpin.d.ts.map +1 -1
  72. package/build/commands/unpin.js +23 -38
  73. package/build/commands/unpin.js.map +1 -1
  74. package/build/commands/update.d.ts.map +1 -1
  75. package/build/commands/update.js +57 -54
  76. package/build/commands/update.js.map +1 -1
  77. package/build/commands/why.d.ts +1 -1
  78. package/build/commands/why.d.ts.map +1 -1
  79. package/build/commands/why.js +14 -6
  80. package/build/commands/why.js.map +1 -1
  81. package/build/components/AssetDetail.d.ts +1 -3
  82. package/build/components/AssetDetail.d.ts.map +1 -1
  83. package/build/components/AssetDetail.js +22 -21
  84. package/build/components/AssetDetail.js.map +1 -1
  85. package/build/components/AssetTable.d.ts +5 -2
  86. package/build/components/AssetTable.d.ts.map +1 -1
  87. package/build/components/AssetTable.js +37 -40
  88. package/build/components/AssetTable.js.map +1 -1
  89. package/build/components/AssetVersionLine.d.ts +27 -0
  90. package/build/components/AssetVersionLine.d.ts.map +1 -0
  91. package/build/components/AssetVersionLine.js +10 -0
  92. package/build/components/AssetVersionLine.js.map +1 -0
  93. package/build/components/BrowseExpandedBundle.d.ts +10 -1
  94. package/build/components/BrowseExpandedBundle.d.ts.map +1 -1
  95. package/build/components/BrowseExpandedBundle.js +28 -3
  96. package/build/components/BrowseExpandedBundle.js.map +1 -1
  97. package/build/components/BrowseExpandedRow.d.ts +9 -1
  98. package/build/components/BrowseExpandedRow.d.ts.map +1 -1
  99. package/build/components/BrowseExpandedRow.js +35 -3
  100. package/build/components/BrowseExpandedRow.js.map +1 -1
  101. package/build/components/BrowseList.d.ts +5 -1
  102. package/build/components/BrowseList.d.ts.map +1 -1
  103. package/build/components/BrowseList.js +57 -47
  104. package/build/components/BrowseList.js.map +1 -1
  105. package/build/components/BundleDetail.d.ts +2 -1
  106. package/build/components/BundleDetail.d.ts.map +1 -1
  107. package/build/components/BundleDetail.js +3 -2
  108. package/build/components/BundleDetail.js.map +1 -1
  109. package/build/components/DiffView.d.ts +0 -2
  110. package/build/components/DiffView.d.ts.map +1 -1
  111. package/build/components/DiffView.js +11 -5
  112. package/build/components/DiffView.js.map +1 -1
  113. package/build/components/DryRunBanner.d.ts +3 -3
  114. package/build/components/DryRunBanner.d.ts.map +1 -1
  115. package/build/components/DryRunBanner.js +2 -2
  116. package/build/components/DryRunBanner.js.map +1 -1
  117. package/build/components/FilterBar.d.ts +10 -3
  118. package/build/components/FilterBar.d.ts.map +1 -1
  119. package/build/components/FilterBar.js +4 -4
  120. package/build/components/FilterBar.js.map +1 -1
  121. package/build/components/FrozenSkippedHint.d.ts +11 -0
  122. package/build/components/FrozenSkippedHint.d.ts.map +1 -0
  123. package/build/components/FrozenSkippedHint.js +12 -0
  124. package/build/components/FrozenSkippedHint.js.map +1 -0
  125. package/build/components/HelpBar.d.ts.map +1 -1
  126. package/build/components/HelpBar.js +3 -3
  127. package/build/components/HelpBar.js.map +1 -1
  128. package/build/components/InitSuccess.d.ts +5 -0
  129. package/build/components/InitSuccess.d.ts.map +1 -0
  130. package/build/components/InitSuccess.js +20 -0
  131. package/build/components/InitSuccess.js.map +1 -0
  132. package/build/components/InstallSummary.d.ts +3 -3
  133. package/build/components/InstallSummary.d.ts.map +1 -1
  134. package/build/components/InstallSummary.js +2 -2
  135. package/build/components/InstallSummary.js.map +1 -1
  136. package/build/components/Link.d.ts +7 -0
  137. package/build/components/Link.d.ts.map +1 -0
  138. package/build/components/Link.js +6 -0
  139. package/build/components/Link.js.map +1 -0
  140. package/build/components/ListActionBar.d.ts +11 -0
  141. package/build/components/ListActionBar.d.ts.map +1 -0
  142. package/build/components/ListActionBar.js +30 -0
  143. package/build/components/ListActionBar.js.map +1 -0
  144. package/build/components/ListBrowseList.d.ts +27 -0
  145. package/build/components/ListBrowseList.d.ts.map +1 -0
  146. package/build/components/ListBrowseList.js +57 -0
  147. package/build/components/ListBrowseList.js.map +1 -0
  148. package/build/components/ListExpandedRow.d.ts +38 -0
  149. package/build/components/ListExpandedRow.d.ts.map +1 -0
  150. package/build/components/ListExpandedRow.js +49 -0
  151. package/build/components/ListExpandedRow.js.map +1 -0
  152. package/build/components/ListHelpBar.d.ts +19 -0
  153. package/build/components/ListHelpBar.d.ts.map +1 -0
  154. package/build/components/ListHelpBar.js +11 -0
  155. package/build/components/ListHelpBar.js.map +1 -0
  156. package/build/components/OrphanListItem.d.ts +15 -0
  157. package/build/components/OrphanListItem.d.ts.map +1 -0
  158. package/build/components/OrphanListItem.js +6 -0
  159. package/build/components/OrphanListItem.js.map +1 -0
  160. package/build/components/PromptField.d.ts +19 -0
  161. package/build/components/PromptField.d.ts.map +1 -0
  162. package/build/components/PromptField.js +7 -0
  163. package/build/components/PromptField.js.map +1 -0
  164. package/build/components/SkippedAssetSection.d.ts +35 -0
  165. package/build/components/SkippedAssetSection.d.ts.map +1 -0
  166. package/build/components/SkippedAssetSection.js +15 -0
  167. package/build/components/SkippedAssetSection.js.map +1 -0
  168. package/build/components/StatusBadge.d.ts +1 -1
  169. package/build/components/StatusBadge.d.ts.map +1 -1
  170. package/build/components/StatusBadge.js +4 -0
  171. package/build/components/StatusBadge.js.map +1 -1
  172. package/build/components/SyncAllInSync.d.ts +14 -0
  173. package/build/components/SyncAllInSync.d.ts.map +1 -0
  174. package/build/components/SyncAllInSync.js +10 -0
  175. package/build/components/SyncAllInSync.js.map +1 -0
  176. package/build/components/SyncDriftedList.d.ts +24 -0
  177. package/build/components/SyncDriftedList.d.ts.map +1 -0
  178. package/build/components/SyncDriftedList.js +17 -0
  179. package/build/components/SyncDriftedList.js.map +1 -0
  180. package/build/components/SyncNoAssets.d.ts +12 -0
  181. package/build/components/SyncNoAssets.d.ts.map +1 -0
  182. package/build/components/SyncNoAssets.js +9 -0
  183. package/build/components/SyncNoAssets.js.map +1 -0
  184. package/build/components/index.d.ts +16 -2
  185. package/build/components/index.d.ts.map +1 -1
  186. package/build/components/index.js +16 -2
  187. package/build/components/index.js.map +1 -1
  188. package/build/hooks/useBrowseState.d.ts +44 -1
  189. package/build/hooks/useBrowseState.d.ts.map +1 -1
  190. package/build/hooks/useBrowseState.js +148 -13
  191. package/build/hooks/useBrowseState.js.map +1 -1
  192. package/build/hooks/useConfirmation.d.ts +18 -0
  193. package/build/hooks/useConfirmation.d.ts.map +1 -0
  194. package/build/hooks/useConfirmation.js +56 -0
  195. package/build/hooks/useConfirmation.js.map +1 -0
  196. package/build/hooks/useInitState.d.ts +109 -0
  197. package/build/hooks/useInitState.d.ts.map +1 -0
  198. package/build/hooks/useInitState.js +474 -0
  199. package/build/hooks/useInitState.js.map +1 -0
  200. package/build/hooks/useListActions.d.ts +15 -0
  201. package/build/hooks/useListActions.d.ts.map +1 -0
  202. package/build/hooks/useListActions.js +155 -0
  203. package/build/hooks/useListActions.js.map +1 -0
  204. package/build/hooks/useListState.d.ts +151 -0
  205. package/build/hooks/useListState.d.ts.map +1 -0
  206. package/build/hooks/useListState.js +448 -0
  207. package/build/hooks/useListState.js.map +1 -0
  208. package/build/hooks/usePruneState.d.ts +76 -0
  209. package/build/hooks/usePruneState.d.ts.map +1 -0
  210. package/build/hooks/usePruneState.js +252 -0
  211. package/build/hooks/usePruneState.js.map +1 -0
  212. package/build/hooks/usePublishState.d.ts +147 -0
  213. package/build/hooks/usePublishState.d.ts.map +1 -0
  214. package/build/hooks/usePublishState.js +916 -0
  215. package/build/hooks/usePublishState.js.map +1 -0
  216. package/build/hooks/useSetupState.d.ts +57 -0
  217. package/build/hooks/useSetupState.d.ts.map +1 -0
  218. package/build/hooks/useSetupState.js +236 -0
  219. package/build/hooks/useSetupState.js.map +1 -0
  220. package/build/hooks/useUninstallState.d.ts +102 -0
  221. package/build/hooks/useUninstallState.d.ts.map +1 -0
  222. package/build/hooks/useUninstallState.js +342 -0
  223. package/build/hooks/useUninstallState.js.map +1 -0
  224. package/build/lib/adapter.d.ts +21 -0
  225. package/build/lib/adapter.d.ts.map +1 -1
  226. package/build/lib/adapter.js +59 -1
  227. package/build/lib/adapter.js.map +1 -1
  228. package/build/lib/checksum.d.ts +39 -0
  229. package/build/lib/checksum.d.ts.map +1 -1
  230. package/build/lib/checksum.js +98 -13
  231. package/build/lib/checksum.js.map +1 -1
  232. package/build/lib/config.d.ts +38 -18
  233. package/build/lib/config.d.ts.map +1 -1
  234. package/build/lib/config.js +103 -55
  235. package/build/lib/config.js.map +1 -1
  236. package/build/lib/detector.d.ts +2 -11
  237. package/build/lib/detector.d.ts.map +1 -1
  238. package/build/lib/detector.js +2 -64
  239. package/build/lib/detector.js.map +1 -1
  240. package/build/lib/diagnostics.d.ts +7 -0
  241. package/build/lib/diagnostics.d.ts.map +1 -1
  242. package/build/lib/diagnostics.js +54 -34
  243. package/build/lib/diagnostics.js.map +1 -1
  244. package/build/lib/diff-command.d.ts +40 -0
  245. package/build/lib/diff-command.d.ts.map +1 -0
  246. package/build/lib/diff-command.js +145 -0
  247. package/build/lib/diff-command.js.map +1 -0
  248. package/build/lib/diff.d.ts +7 -0
  249. package/build/lib/diff.d.ts.map +1 -1
  250. package/build/lib/diff.js +15 -10
  251. package/build/lib/diff.js.map +1 -1
  252. package/build/lib/format.d.ts +6 -0
  253. package/build/lib/format.d.ts.map +1 -0
  254. package/build/lib/format.js +18 -0
  255. package/build/lib/format.js.map +1 -0
  256. package/build/lib/github.d.ts +35 -0
  257. package/build/lib/github.d.ts.map +1 -1
  258. package/build/lib/github.js +44 -0
  259. package/build/lib/github.js.map +1 -1
  260. package/build/lib/gitignore.d.ts +17 -0
  261. package/build/lib/gitignore.d.ts.map +1 -1
  262. package/build/lib/gitignore.js +17 -1
  263. package/build/lib/gitignore.js.map +1 -1
  264. package/build/lib/init.d.ts +22 -0
  265. package/build/lib/init.d.ts.map +1 -1
  266. package/build/lib/init.js +163 -18
  267. package/build/lib/init.js.map +1 -1
  268. package/build/lib/installer.d.ts +1 -0
  269. package/build/lib/installer.d.ts.map +1 -1
  270. package/build/lib/installer.js +7 -7
  271. package/build/lib/installer.js.map +1 -1
  272. package/build/lib/lockfile.d.ts +19 -17
  273. package/build/lib/lockfile.d.ts.map +1 -1
  274. package/build/lib/lockfile.js +45 -68
  275. package/build/lib/lockfile.js.map +1 -1
  276. package/build/lib/publisher.d.ts +41 -12
  277. package/build/lib/publisher.d.ts.map +1 -1
  278. package/build/lib/publisher.js +226 -64
  279. package/build/lib/publisher.js.map +1 -1
  280. package/build/lib/registry.d.ts +20 -5
  281. package/build/lib/registry.d.ts.map +1 -1
  282. package/build/lib/registry.js +45 -33
  283. package/build/lib/registry.js.map +1 -1
  284. package/build/lib/sanitize.d.ts +25 -0
  285. package/build/lib/sanitize.d.ts.map +1 -0
  286. package/build/lib/sanitize.js +61 -0
  287. package/build/lib/sanitize.js.map +1 -0
  288. package/build/lib/schemas/config.d.ts +31 -3
  289. package/build/lib/schemas/config.d.ts.map +1 -1
  290. package/build/lib/schemas/config.js +21 -2
  291. package/build/lib/schemas/config.js.map +1 -1
  292. package/build/lib/schemas/index.d.ts +1 -1
  293. package/build/lib/schemas/index.d.ts.map +1 -1
  294. package/build/lib/schemas/index.js +1 -1
  295. package/build/lib/schemas/index.js.map +1 -1
  296. package/build/lib/schemas/lockfile.d.ts +20 -4
  297. package/build/lib/schemas/lockfile.d.ts.map +1 -1
  298. package/build/lib/schemas/lockfile.js +7 -1
  299. package/build/lib/schemas/lockfile.js.map +1 -1
  300. package/build/lib/schemas/manifest.d.ts +1 -1
  301. package/build/lib/schemas/manifest.d.ts.map +1 -1
  302. package/build/lib/schemas/manifest.js +7 -2
  303. package/build/lib/schemas/manifest.js.map +1 -1
  304. package/build/lib/schemas/registry.d.ts +2 -4
  305. package/build/lib/schemas/registry.d.ts.map +1 -1
  306. package/build/lib/schemas/registry.js +1 -1
  307. package/build/lib/schemas/registry.js.map +1 -1
  308. package/build/lib/search.d.ts +15 -1
  309. package/build/lib/search.d.ts.map +1 -1
  310. package/build/lib/search.js +65 -65
  311. package/build/lib/search.js.map +1 -1
  312. package/build/lib/setup.d.ts +28 -0
  313. package/build/lib/setup.d.ts.map +1 -0
  314. package/build/lib/setup.js +98 -0
  315. package/build/lib/setup.js.map +1 -0
  316. package/build/lib/sync.d.ts +109 -0
  317. package/build/lib/sync.d.ts.map +1 -0
  318. package/build/lib/sync.js +217 -0
  319. package/build/lib/sync.js.map +1 -0
  320. package/build/lib/tool-resolver.d.ts +29 -6
  321. package/build/lib/tool-resolver.d.ts.map +1 -1
  322. package/build/lib/tool-resolver.js +54 -15
  323. package/build/lib/tool-resolver.js.map +1 -1
  324. package/build/lib/updater.d.ts +7 -4
  325. package/build/lib/updater.d.ts.map +1 -1
  326. package/build/lib/updater.js +10 -6
  327. package/build/lib/updater.js.map +1 -1
  328. package/build/lib/version.js +1 -1
  329. package/build/lib/version.js.map +1 -1
  330. package/package.json +79 -65
  331. package/tool-adapters/claude-code.json +1 -1
  332. package/tool-adapters/copilot-cli.json +1 -1
@@ -1,26 +1,21 @@
1
1
  import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
2
- import { Box, Text, useApp } from 'ink';
2
+ import { Box, Text, useApp, useInput, useStdin } from 'ink';
3
3
  import TextInput from 'ink-text-input';
4
- import { cp, mkdir, rm, writeFile } from 'node:fs/promises';
5
- import { tmpdir } from 'node:os';
6
- import { dirname, join, resolve } from 'node:path';
7
4
  import { option } from 'pastel';
8
- import { useCallback, useEffect, useRef, useState } from 'react';
5
+ import { useEffect } from 'react';
9
6
  import { z } from 'zod';
10
7
  import { DryRunBanner, Spinner } from '../components/index.js';
11
8
  import { CheckIcon } from '../components/StatusBadge.js';
12
- import { resolveInstalledPaths } from '../lib/adapter.js';
13
- import { getGitHubToken } from '../lib/auth.js';
14
- import { hashFile } from '../lib/checksum.js';
15
- import { DEFAULT_REGISTRY_BRANCH } from '../lib/github.js';
16
- import { addAssetToLockfile, findInstalledAsset, readLockfile, withLockfileLock, writeLockfile, } from '../lib/lockfile.js';
17
- import { parseOrgFromName } from '../lib/org.js';
18
- import { findProjectRoot } from '../lib/paths.js';
19
- import { buildPublishPlan, bumpVersion, checkRegistryVersion, detectPublishType, executeDirectPublish, executePublish, isOrgAsset, mapPublishError, updateManifestVersion, validatePublishTarget, } from '../lib/publisher.js';
20
- import { clearCache, fetchRegistry } from '../lib/registry.js';
21
- import { resolveTool } from '../lib/tool-resolver.js';
9
+ import { usePublishState } from '../hooks/usePublishState.js';
10
+ import { bumpVersion } from '../lib/publisher.js';
22
11
  export const description = 'Publish an asset or bundle to the registry';
23
12
  export const options = z.object({
13
+ description: z
14
+ .string()
15
+ .optional()
16
+ .describe(option({
17
+ description: 'Asset description (skips interactive prompt)',
18
+ })),
24
19
  dryRun: z
25
20
  .boolean()
26
21
  .default(false)
@@ -42,365 +37,71 @@ export const options = z.object({
42
37
  alias: 'm',
43
38
  description: 'Custom message appended to the auto-generated PR description or commit',
44
39
  })),
40
+ tags: z
41
+ .string()
42
+ .optional()
43
+ .describe(option({
44
+ description: 'Comma-separated tags (skips interactive prompt)',
45
+ })),
46
+ update: z
47
+ .boolean()
48
+ .default(false)
49
+ .describe(option({
50
+ alias: 'u',
51
+ description: 'Publish an update using locally modified installed files',
52
+ })),
45
53
  });
46
54
  export const args = z.tuple([
47
- z.string().describe('Path to asset directory, or installed asset name when --from-installed is used'),
55
+ z
56
+ .string()
57
+ .describe('Path to asset/bundle directory (with manifest), or path to a raw file/directory to publish without scaffolding. When --update is used, this is an installed asset name'),
48
58
  ]);
49
- export default function Publish({ args: [rawPath], options: { dryRun, fromInstalled, message } }) {
59
+ export default function Publish({ args: [rawPath], options: { description: descriptionFlag, dryRun, fromInstalled, message, tags: tagsFlag, update }, }) {
50
60
  const { exit } = useApp();
51
- // Phase state machine
52
- const [phase, setPhase] = useState(fromInstalled ? 'resolving-installed' : 'detecting');
53
- // Data accumulated across phases
54
- const [target, setTarget] = useState();
55
- const [validation, setValidation] = useState();
56
- const [_registry, setRegistry] = useState();
57
- const [versionCheck, setVersionCheck] = useState();
58
- const [token, setToken] = useState();
59
- const [isUpdate, setIsUpdate] = useState(false);
60
- const [resolvedVersion, setResolvedVersion] = useState('');
61
- const [plan, setPlan] = useState();
62
- const [publishResult, setPublishResult] = useState();
63
- const [progressMessage, setProgressMessage] = useState('');
64
- // Interactive prompt values
65
- const [confirmValue, setConfirmValue] = useState('');
66
- const [bumpSelection, setBumpSelection] = useState('');
67
- // Error and status
68
- const [errorMessage, setErrorMessage] = useState('');
69
- // Temp directory ref for --from-installed cleanup
70
- const tempDirRef = useRef(null);
71
- // When --from-installed is used, resolvedPath is set after resolving the installed asset
72
- const [resolvedPath, setResolvedPath] = useState(fromInstalled ? '' : resolve(rawPath));
73
- // ---------------------------------------------------------------------------
74
- // Cleanup helper for temp directory
75
- // ---------------------------------------------------------------------------
76
- const cleanupTempDir = useCallback(async () => {
77
- if (tempDirRef.current) {
78
- try {
79
- await rm(tempDirRef.current, { force: true, recursive: true });
80
- }
81
- catch {
82
- // Best-effort cleanup — ignore errors
83
- }
84
- tempDirRef.current = null;
61
+ const { isRawModeSupported: isTTY } = useStdin();
62
+ const flags = {
63
+ descriptionFlag,
64
+ dryRun,
65
+ fromInstalled,
66
+ message,
67
+ rawPath,
68
+ tagsFlag,
69
+ update,
70
+ };
71
+ const [state, dispatch] = usePublishState(flags);
72
+ // ---------------------------------------------------------------------------
73
+ // Tool selection keyboard handling (multi-select checkboxes)
74
+ // ---------------------------------------------------------------------------
75
+ useInput((input, key) => {
76
+ if (key.upArrow) {
77
+ dispatch({ type: 'TOOL_CURSOR_UP' });
85
78
  }
86
- }, []);
87
- // ---------------------------------------------------------------------------
88
- // Phase: Resolving installed asset (--from-installed)
89
- // ---------------------------------------------------------------------------
90
- useEffect(() => {
91
- if (phase !== 'resolving-installed')
92
- return;
93
- let cancelled = false;
94
- const resolveInstalled = async () => {
95
- const assetName = rawPath;
96
- const { name, org } = parseOrgFromName(assetName);
97
- const projectRoot = findProjectRoot();
98
- const { adapter } = await resolveTool(undefined);
99
- const lockfile = await readLockfile(projectRoot);
100
- const installed = findInstalledAsset(lockfile, name, undefined, org);
101
- if (!installed) {
102
- if (!cancelled) {
103
- setErrorMessage(`Asset '${assetName}' is not installed.`);
104
- setPhase('error');
105
- }
106
- return;
107
- }
108
- // Create temp directory and copy installed files
109
- const tempDir = await mkdir(join(tmpdir(), 'atk-publish-'), { recursive: true })
110
- .then(() => join(tmpdir(), `atk-publish-${Date.now()}-${Math.random().toString(36).slice(2)}`))
111
- .then(async (dir) => {
112
- await mkdir(dir, { recursive: true });
113
- return dir;
114
- });
115
- if (cancelled) {
116
- await rm(tempDir, { force: true, recursive: true });
117
- return;
118
- }
119
- tempDirRef.current = tempDir;
120
- // Resolve installed paths via the adapter
121
- const resolved = resolveInstalledPaths(installed, adapter, projectRoot);
122
- // Copy each installed file preserving sourcePath directory structure
123
- for (const file of resolved.files) {
124
- const sourceAbsolute = join(projectRoot, file.installedPath);
125
- const destPath = join(tempDir, file.sourcePath);
126
- const destDir = dirname(destPath);
127
- await mkdir(destDir, { recursive: true });
128
- await cp(sourceAbsolute, destPath);
129
- }
130
- // Generate manifest.json in the temp dir
131
- const manifest = {
132
- author: 'unknown',
133
- description: `Published from installed asset ${installed.name}`,
134
- entrypoint: installed.files[0]?.sourcePath ?? 'index.md',
135
- name: installed.name,
136
- ...(installed.org ? { org: installed.org } : {}),
137
- type: installed.type,
138
- version: installed.version,
139
- };
140
- await writeFile(join(tempDir, 'manifest.json'), JSON.stringify(manifest, null, 2) + '\n', 'utf-8');
141
- if (!cancelled) {
142
- setResolvedPath(tempDir);
143
- setPhase('detecting');
144
- }
145
- };
146
- resolveInstalled().catch((err) => {
147
- if (!cancelled) {
148
- setErrorMessage(err instanceof Error ? err.message : String(err));
149
- setPhase('error');
150
- }
151
- });
152
- return () => {
153
- cancelled = true;
154
- };
155
- }, [phase, rawPath]);
156
- // ---------------------------------------------------------------------------
157
- // Phase: Detecting asset vs bundle
158
- // ---------------------------------------------------------------------------
159
- useEffect(() => {
160
- if (phase !== 'detecting')
161
- return;
162
- let cancelled = false;
163
- const detect = async () => {
164
- const detected = await detectPublishType(resolvedPath);
165
- if (cancelled)
166
- return;
167
- setTarget(detected);
168
- setPhase('validating');
169
- };
170
- detect().catch((err) => {
171
- if (!cancelled) {
172
- setErrorMessage(err instanceof Error ? err.message : String(err));
173
- setPhase('error');
174
- }
175
- });
176
- return () => {
177
- cancelled = true;
178
- };
179
- }, [phase, resolvedPath]);
180
- // ---------------------------------------------------------------------------
181
- // Phase: Validating manifest/bundle
182
- // ---------------------------------------------------------------------------
183
- useEffect(() => {
184
- if (phase !== 'validating')
185
- return;
186
- if (!target)
187
- return;
188
- let cancelled = false;
189
- const validate = async () => {
190
- const result = await validatePublishTarget(target);
191
- if (cancelled)
192
- return;
193
- setValidation(result);
194
- if (!result.valid) {
195
- setErrorMessage(`Validation failed:\n${result.errors.map((e) => ` - ${e}`).join('\n')}`);
196
- setPhase('error');
197
- return;
198
- }
199
- setPhase('checking-registry');
200
- };
201
- validate().catch((err) => {
202
- if (!cancelled) {
203
- setErrorMessage(err instanceof Error ? err.message : String(err));
204
- setPhase('error');
205
- }
206
- });
207
- return () => {
208
- cancelled = true;
209
- };
210
- }, [phase, target]);
211
- // ---------------------------------------------------------------------------
212
- // Phase: Checking registry for existing asset
213
- // ---------------------------------------------------------------------------
214
- useEffect(() => {
215
- if (phase !== 'checking-registry')
216
- return;
217
- if (!target)
218
- return;
219
- let cancelled = false;
220
- const check = async () => {
221
- const authToken = await getGitHubToken();
222
- if (cancelled)
223
- return;
224
- setToken(authToken);
225
- const reg = await fetchRegistry();
226
- if (cancelled)
227
- return;
228
- setRegistry(reg);
229
- const versionResult = checkRegistryVersion(target, reg);
230
- if (cancelled)
231
- return;
232
- setVersionCheck(versionResult);
233
- if (versionResult.status === 'new-asset') {
234
- setIsUpdate(false);
235
- setResolvedVersion(target.data.version);
236
- setPhase('building-plan');
237
- }
238
- else if (versionResult.status === 'version-already-bumped') {
239
- setIsUpdate(true);
240
- setResolvedVersion(target.data.version);
241
- setPhase('confirm-update');
242
- }
243
- else {
244
- // needs-bump
245
- setIsUpdate(true);
246
- setPhase('bump-prompt');
247
- }
248
- };
249
- check().catch((err) => {
250
- if (!cancelled) {
251
- setErrorMessage(mapPublishError(err));
252
- setPhase('error');
253
- }
254
- });
255
- return () => {
256
- cancelled = true;
257
- };
258
- }, [phase, target]);
259
- // ---------------------------------------------------------------------------
260
- // Phase: Building publish plan
261
- // ---------------------------------------------------------------------------
262
- useEffect(() => {
263
- if (phase !== 'building-plan')
264
- return;
265
- if (!target)
266
- return;
267
- let cancelled = false;
268
- const build = async () => {
269
- const publishPlan = await buildPublishPlan(target, resolvedVersion, isUpdate, message);
270
- if (cancelled)
271
- return;
272
- setPlan(publishPlan);
273
- if (dryRun) {
274
- setPhase('dry-run-result');
275
- }
276
- else {
277
- setPhase('publishing');
278
- }
279
- };
280
- build().catch((err) => {
281
- if (!cancelled) {
282
- setErrorMessage(err instanceof Error ? err.message : String(err));
283
- setPhase('error');
284
- }
285
- });
286
- return () => {
287
- cancelled = true;
288
- };
289
- }, [phase, target, resolvedVersion, isUpdate, dryRun, message]);
290
- // ---------------------------------------------------------------------------
291
- // Phase: Publishing (executing git operations)
292
- // ---------------------------------------------------------------------------
293
- useEffect(() => {
294
- if (phase !== 'publishing')
295
- return;
296
- if (!plan || !token)
297
- return;
298
- let cancelled = false;
299
- const publish = async () => {
300
- const progressCallback = (msg) => {
301
- if (!cancelled) {
302
- setProgressMessage(msg);
303
- }
304
- };
305
- const result = isOrgAsset(plan)
306
- ? await executeDirectPublish(plan, token, progressCallback)
307
- : await executePublish(plan, token, progressCallback);
308
- if (cancelled)
309
- return;
310
- setPublishResult(result);
311
- // Clear registry cache so subsequent commands see the new version
312
- try {
313
- await clearCache();
314
- }
315
- catch {
316
- // Best-effort — don't fail publish over cache
317
- }
318
- // Update lockfile in-place when publishing from an installed asset
319
- if (fromInstalled) {
320
- try {
321
- const projectRoot = findProjectRoot();
322
- const { adapter: pubAdapter } = await resolveTool(undefined);
323
- await withLockfileLock(projectRoot, async () => {
324
- const lockfile = await readLockfile(projectRoot);
325
- const { name, org } = parseOrgFromName(rawPath);
326
- const installed = findInstalledAsset(lockfile, name, undefined, org);
327
- if (installed) {
328
- const resolved = resolveInstalledPaths(installed, pubAdapter, projectRoot);
329
- const updatedFiles = await Promise.all(resolved.files.map(async (file) => ({
330
- checksum: await hashFile(join(projectRoot, file.installedPath)),
331
- sourcePath: file.sourcePath,
332
- })));
333
- const updatedLockfile = addAssetToLockfile(lockfile, {
334
- ...installed,
335
- files: updatedFiles,
336
- version: resolvedVersion,
337
- });
338
- await writeLockfile(projectRoot, updatedLockfile);
339
- }
340
- });
341
- }
342
- catch {
343
- // Best-effort — don't fail publish over lockfile update
344
- }
345
- }
346
- setPhase('done');
347
- };
348
- publish().catch((err) => {
349
- if (!cancelled) {
350
- setErrorMessage(mapPublishError(err));
351
- setPhase('error');
352
- }
353
- });
354
- return () => {
355
- cancelled = true;
356
- };
357
- }, [phase, plan, token, fromInstalled, rawPath, resolvedVersion]);
358
- // ---------------------------------------------------------------------------
359
- // Prompt handlers
360
- // ---------------------------------------------------------------------------
361
- const handleConfirmSubmit = useCallback((value) => {
362
- const trimmed = value.trim().toLowerCase();
363
- if (trimmed === 'y' || trimmed === 'yes') {
364
- setPhase('building-plan');
79
+ else if (key.downArrow) {
80
+ dispatch({ type: 'TOOL_CURSOR_DOWN' });
365
81
  }
366
- else if (trimmed === 'n' || trimmed === 'no') {
367
- setErrorMessage('Publish cancelled.');
368
- setPhase('error');
82
+ else if (input === ' ') {
83
+ const tool = state.toolAdapters[state.toolCursorIndex]?.tool;
84
+ if (tool) {
85
+ dispatch({ tool, type: 'TOGGLE_PROMPT_TOOL' });
86
+ }
369
87
  }
370
- // Otherwise ignore (wait for valid input)
371
- }, []);
372
- const handleBumpSubmit = useCallback((value) => {
373
- if (!target || !versionCheck || versionCheck.status !== 'needs-bump')
374
- return;
375
- const trimmed = value.trim().toLowerCase();
376
- if (trimmed !== 'patch' && trimmed !== 'minor' && trimmed !== 'major') {
377
- return; // Ignore invalid input
88
+ else if (key.return) {
89
+ if (state.selectedPromptTools.length > 0) {
90
+ dispatch({ type: 'CONFIRM_PROMPT_TOOLS' });
91
+ }
378
92
  }
379
- const bumpType = trimmed;
380
- const newVersion = bumpVersion(versionCheck.latestVersion, bumpType);
381
- setResolvedVersion(newVersion);
382
- // Update the local manifest file
383
- const manifestFile = target.type === 'asset' ? 'manifest.json' : 'bundle.json';
384
- updateManifestVersion(target.sourceDir, manifestFile, newVersion)
385
- .then(() => {
386
- // Re-read the target so it has the updated version
387
- return detectPublishType(target.sourceDir);
388
- })
389
- .then((updatedTarget) => {
390
- setTarget(updatedTarget);
391
- setPhase('building-plan');
392
- })
393
- .catch((err) => {
394
- setErrorMessage(`Failed to update version: ${err instanceof Error ? err.message : String(err)}`);
395
- setPhase('error');
396
- });
397
- }, [target, versionCheck]);
93
+ }, { isActive: state.phase === 'prompting-tools' && isTTY });
94
+ /** Format asset name with org prefix when available (e.g. "@org/name") */
95
+ const displayName = state.target
96
+ ? 'org' in state.target.data && state.target.data.org
97
+ ? `@${state.target.data.org}/${state.target.data.name}`
98
+ : state.target.data.name
99
+ : '';
398
100
  // ---------------------------------------------------------------------------
399
101
  // Exit on error
400
102
  // ---------------------------------------------------------------------------
401
103
  useEffect(() => {
402
- if (phase === 'error') {
403
- void cleanupTempDir();
104
+ if (state.phase === 'error') {
404
105
  const timer = setTimeout(() => {
405
106
  process.exitCode = 1;
406
107
  exit();
@@ -409,13 +110,12 @@ export default function Publish({ args: [rawPath], options: { dryRun, fromInstal
409
110
  clearTimeout(timer);
410
111
  };
411
112
  }
412
- }, [phase, exit, cleanupTempDir]);
113
+ }, [state.phase, exit]);
413
114
  // ---------------------------------------------------------------------------
414
115
  // Exit on done
415
116
  // ---------------------------------------------------------------------------
416
117
  useEffect(() => {
417
- if (phase === 'done') {
418
- void cleanupTempDir();
118
+ if (state.phase === 'done') {
419
119
  const timer = setTimeout(() => {
420
120
  exit();
421
121
  }, 100);
@@ -423,13 +123,12 @@ export default function Publish({ args: [rawPath], options: { dryRun, fromInstal
423
123
  clearTimeout(timer);
424
124
  };
425
125
  }
426
- }, [phase, exit, cleanupTempDir]);
126
+ }, [state.phase, exit]);
427
127
  // ---------------------------------------------------------------------------
428
128
  // Exit on dry-run-result
429
129
  // ---------------------------------------------------------------------------
430
130
  useEffect(() => {
431
- if (phase === 'dry-run-result') {
432
- void cleanupTempDir();
131
+ if (state.phase === 'dry-run-result') {
433
132
  const timer = setTimeout(() => {
434
133
  exit();
435
134
  }, 100);
@@ -437,56 +136,108 @@ export default function Publish({ args: [rawPath], options: { dryRun, fromInstal
437
136
  clearTimeout(timer);
438
137
  };
439
138
  }
440
- }, [phase, exit, cleanupTempDir]);
139
+ }, [state.phase, exit]);
441
140
  // ---------------------------------------------------------------------------
442
141
  // Render
443
142
  // ---------------------------------------------------------------------------
444
143
  // Error state
445
- if (phase === 'error') {
446
- return _jsxs(Text, { color: 'red', children: ["Error: ", errorMessage] });
144
+ if (state.phase === 'error') {
145
+ return _jsxs(Text, { color: 'red', children: ["Error: ", state.errorMessage] });
447
146
  }
448
147
  // Resolving installed asset
449
- if (phase === 'resolving-installed') {
148
+ if (state.phase === 'resolving-installed') {
450
149
  return _jsx(Spinner, { message: 'Resolving installed asset...' });
451
150
  }
151
+ // Resolving update from installed asset
152
+ if (state.phase === 'resolving-update') {
153
+ return _jsx(Spinner, { message: 'Resolving update from installed asset...' });
154
+ }
452
155
  // Detecting
453
- if (phase === 'detecting') {
156
+ if (state.phase === 'detecting') {
454
157
  return _jsx(Spinner, { message: 'Detecting asset type...' });
455
158
  }
159
+ // Gathering metadata (raw publish)
160
+ if (state.phase === 'gathering-metadata' && state.rawDetection) {
161
+ return (_jsxs(Box, { flexDirection: 'column', children: [_jsxs(Text, { children: ["Detected: ", state.rawDetection.assetType, " \"", _jsx(Text, { bold: true, children: state.rawDetection.name }), "\" (", state.rawDetection.files.length, " file", state.rawDetection.files.length !== 1 ? 's' : '', ")"] }), _jsxs(Text, { children: ["Author: ", state.authorValue, " (from git config)"] }), state.orgValue && _jsxs(Text, { children: ["Org: ", state.orgValue, " (from lockfile)"] }), _jsx(Text, { children: " " }), state.metadataSubPhase === 'description' && (_jsxs(Box, { children: [_jsx(Text, { children: "Description: " }), _jsx(TextInput, { focus: true, onChange: (v) => dispatch({ type: 'SET_DESCRIPTION', value: v }), onSubmit: () => dispatch({ type: 'SUBMIT_DESCRIPTION' }), value: state.descriptionValue })] })), state.metadataSubPhase === 'tags' && (_jsxs(Box, { flexDirection: 'column', children: [_jsxs(Text, { children: ["Description: ", state.descriptionValue] }), _jsxs(Box, { children: [_jsx(Text, { children: "Tags (comma-separated, optional): " }), _jsx(TextInput, { focus: true, onChange: (v) => dispatch({ type: 'SET_TAGS', value: v }), onSubmit: () => dispatch({ type: 'SUBMIT_TAGS' }), value: state.tagsValue })] })] })), state.metadataSubPhase === 'building-staging' && _jsx(Spinner, { message: 'Building staging area...' })] }));
162
+ }
456
163
  // Validating
457
- if (phase === 'validating') {
164
+ if (state.phase === 'validating') {
458
165
  return _jsx(Spinner, { message: 'Validating manifest...' });
459
166
  }
167
+ // Prompting for tags (after validation, when manifest is missing tags)
168
+ if (state.phase === 'prompting-tags') {
169
+ return (_jsxs(Box, { flexDirection: 'column', children: [state.validation && (_jsxs(Box, { flexDirection: 'column', marginBottom: 1, children: [_jsx(Text, { bold: true, children: "Validation:" }), state.validation.errors.length === 0 && (_jsxs(Text, { children: [' ', _jsx(CheckIcon, { status: 'pass' }), " All checks passed"] })), state.validation.warnings.map((w, i) => (_jsxs(Text, { children: [' ', _jsx(CheckIcon, { status: 'warn' }), " ", w] }, i)))] })), _jsxs(Box, { children: [_jsx(Text, { color: 'cyan', children: '> ' }), _jsx(Text, { children: "Tags (comma-separated, e.g. \"testing, react, utilities\"): " }), _jsx(TextInput, { focus: true, onChange: (v) => dispatch({ type: 'SET_PROMPT_TAGS', value: v }), onSubmit: () => dispatch({ type: 'SUBMIT_PROMPT_TAGS' }), value: state.promptTagsValue })] })] }));
170
+ }
171
+ // Loading tool adapters
172
+ if (state.phase === 'loading-tools') {
173
+ return _jsx(Spinner, { message: 'Loading tool adapters...' });
174
+ }
175
+ // Prompting for tools (after loading adapters, when manifest is missing tools)
176
+ if (state.phase === 'prompting-tools') {
177
+ const selectedSet = new Set(state.selectedPromptTools);
178
+ return (_jsxs(Box, { flexDirection: 'column', children: [state.validation && (_jsxs(Box, { flexDirection: 'column', marginBottom: 1, children: [_jsx(Text, { bold: true, children: "Validation:" }), state.validation.errors.length === 0 && (_jsxs(Text, { children: [' ', _jsx(CheckIcon, { status: 'pass' }), " All checks passed"] })), state.validation.warnings.map((w, i) => (_jsxs(Text, { children: [' ', _jsx(CheckIcon, { status: 'warn' }), " ", w] }, i)))] })), _jsxs(Box, { marginBottom: 1, children: [_jsx(Text, { bold: true, children: "Select compatible tools" }), _jsx(Text, { dimColor: true, children: " (space to toggle, enter to confirm)" })] }), state.toolAdapters.map((adapter, index) => {
179
+ const isCursor = index === state.toolCursorIndex;
180
+ const isSelected = selectedSet.has(adapter.tool);
181
+ const checkbox = isSelected ? '[x]' : '[ ]';
182
+ return (_jsx(Box, { children: _jsxs(Text, { color: isCursor ? 'cyan' : undefined, children: [isCursor ? '>' : ' ', " ", checkbox, " ", adapter.displayName, _jsxs(Text, { dimColor: true, children: [" (", adapter.tool, ")"] })] }) }, adapter.tool));
183
+ }), selectedSet.size === 0 && (_jsx(Box, { marginTop: 1, children: _jsx(Text, { dimColor: true, children: "Select at least one tool to continue" }) }))] }));
184
+ }
460
185
  // Checking registry
461
- if (phase === 'checking-registry') {
186
+ if (state.phase === 'checking-registry') {
462
187
  return _jsx(Spinner, { message: 'Checking registry...' });
463
188
  }
464
189
  // Confirm update prompt
465
- if (phase === 'confirm-update' && target && versionCheck && versionCheck.status === 'version-already-bumped') {
466
- return (_jsxs(Box, { flexDirection: 'column', children: [validation && (_jsxs(Box, { flexDirection: 'column', marginBottom: 1, children: [_jsx(Text, { bold: true, children: "Validation:" }), validation.errors.length === 0 && (_jsxs(Text, { children: [' ', _jsx(CheckIcon, { status: 'pass' }), " All checks passed"] })), validation.warnings.map((w, i) => (_jsxs(Text, { children: [' ', _jsx(CheckIcon, { status: 'warn' }), " ", w] }, i)))] })), _jsxs(Box, { flexDirection: 'column', marginBottom: 1, children: [_jsxs(Text, { children: ["Asset ", _jsx(Text, { bold: true, children: target.data.name }), " already exists in the registry at v", versionCheck.latestVersion, "."] }), _jsxs(Text, { children: ["Publishing v", _jsx(Text, { bold: true, children: target.data.version }), " as an update."] })] }), _jsxs(Box, { children: [_jsx(Text, { color: 'cyan', children: '> ' }), _jsx(Text, { children: "Continue? (y/n): " }), _jsx(TextInput, { focus: true, onChange: setConfirmValue, onSubmit: handleConfirmSubmit, value: confirmValue })] })] }));
190
+ if (state.phase === 'confirm-update' &&
191
+ state.target &&
192
+ state.versionCheck &&
193
+ state.versionCheck.status === 'version-already-bumped') {
194
+ return (_jsxs(Box, { flexDirection: 'column', children: [state.validation && (_jsxs(Box, { flexDirection: 'column', marginBottom: 1, children: [_jsx(Text, { bold: true, children: "Validation:" }), state.validation.errors.length === 0 && (_jsxs(Text, { children: [' ', _jsx(CheckIcon, { status: 'pass' }), " All checks passed"] })), state.validation.warnings.map((w, i) => (_jsxs(Text, { children: [' ', _jsx(CheckIcon, { status: 'warn' }), " ", w] }, i)))] })), _jsxs(Box, { flexDirection: 'column', marginBottom: 1, children: [_jsxs(Text, { children: ["Asset ", _jsx(Text, { bold: true, children: displayName }), " already exists in the registry at v", state.versionCheck.latestVersion, "."] }), _jsxs(Text, { children: ["Publishing v", _jsx(Text, { bold: true, children: state.target.data.version }), " as an update."] })] }), _jsxs(Box, { children: [_jsx(Text, { color: 'cyan', children: '> ' }), _jsx(Text, { children: "Continue? (y/n): " }), _jsx(TextInput, { focus: true, onChange: (v) => dispatch({ type: 'SET_CONFIRM_VALUE', value: v }), onSubmit: () => dispatch({ type: 'SUBMIT_CONFIRM' }), value: state.confirmValue })] })] }));
467
195
  }
468
196
  // Bump prompt
469
- if (phase === 'bump-prompt' && target && versionCheck && versionCheck.status === 'needs-bump') {
470
- return (_jsxs(Box, { flexDirection: 'column', children: [validation && (_jsxs(Box, { flexDirection: 'column', marginBottom: 1, children: [_jsx(Text, { bold: true, children: "Validation:" }), validation.errors.length === 0 && (_jsxs(Text, { children: [' ', _jsx(CheckIcon, { status: 'pass' }), " All checks passed"] })), validation.warnings.map((w, i) => (_jsxs(Text, { children: [' ', _jsx(CheckIcon, { status: 'warn' }), " ", w] }, i)))] })), _jsxs(Box, { flexDirection: 'column', marginBottom: 1, children: [_jsxs(Text, { children: ["Asset ", _jsx(Text, { bold: true, children: target.data.name }), " exists in the registry at v", versionCheck.latestVersion, "."] }), _jsxs(Text, { children: ["Current manifest version (v", target.data.version, ") is not newer."] })] }), _jsxs(Box, { children: [_jsx(Text, { color: 'cyan', children: '> ' }), _jsx(Text, { children: "Bump type (patch/minor/major): " }), _jsx(TextInput, { focus: true, onChange: setBumpSelection, onSubmit: handleBumpSubmit, value: bumpSelection })] })] }));
197
+ if (state.phase === 'bump-prompt' &&
198
+ state.target &&
199
+ state.versionCheck &&
200
+ state.versionCheck.status === 'needs-bump') {
201
+ const currentVersion = state.versionCheck.latestVersion;
202
+ const patchPreview = bumpVersion(currentVersion, 'patch');
203
+ const minorPreview = bumpVersion(currentVersion, 'minor');
204
+ const majorPreview = bumpVersion(currentVersion, 'major');
205
+ return (_jsxs(Box, { flexDirection: 'column', children: [state.validation && (_jsxs(Box, { flexDirection: 'column', marginBottom: 1, children: [_jsx(Text, { bold: true, children: "Validation:" }), state.validation.errors.length === 0 && (_jsxs(Text, { children: [' ', _jsx(CheckIcon, { status: 'pass' }), " All checks passed"] })), state.validation.warnings.map((w, i) => (_jsxs(Text, { children: [' ', _jsx(CheckIcon, { status: 'warn' }), " ", w] }, i)))] })), _jsxs(Box, { flexDirection: 'column', marginBottom: 1, children: [_jsxs(Text, { children: ["Asset ", _jsx(Text, { bold: true, children: displayName }), " exists in the registry at v", currentVersion, "."] }), _jsxs(Text, { children: ["Current manifest version (v", state.target.data.version, ") is not newer."] })] }), _jsxs(Box, { flexDirection: 'column', marginBottom: 1, children: [_jsxs(Text, { children: [' ', _jsx(Text, { bold: true, children: "patch" }), _jsx(Text, { dimColor: true, children: " (bug fixes):" }), " ", currentVersion, " \u2192 ", patchPreview] }), _jsxs(Text, { children: [' ', _jsx(Text, { bold: true, children: "minor" }), _jsx(Text, { dimColor: true, children: " (new features):" }), " ", currentVersion, " \u2192 ", minorPreview] }), _jsxs(Text, { children: [' ', _jsx(Text, { bold: true, children: "major" }), _jsx(Text, { dimColor: true, children: " (breaking changes):" }), " ", currentVersion, " \u2192 ", majorPreview] })] }), _jsxs(Box, { children: [_jsx(Text, { color: 'cyan', children: '> ' }), _jsx(Text, { children: "Bump type (patch/minor/major): " }), _jsx(TextInput, { focus: true, onChange: (v) => dispatch({ type: 'SET_BUMP_SELECTION', value: v }), onSubmit: () => dispatch({ type: 'SUBMIT_BUMP' }), value: state.bumpSelection })] })] }));
471
206
  }
472
207
  // Building plan
473
- if (phase === 'building-plan') {
208
+ if (state.phase === 'building-plan') {
474
209
  return _jsx(Spinner, { message: 'Building publish plan...' });
475
210
  }
211
+ // Confirm publish
212
+ if (state.phase === 'confirm-publish' && state.plan && state.target) {
213
+ const confirmDisplayName = 'org' in state.target.data && state.target.data.org
214
+ ? `@${state.target.data.org}/${state.target.data.name}`
215
+ : state.target.data.name;
216
+ const oldVersion = state.versionCheck && state.versionCheck.status !== 'new-asset' ? state.versionCheck.latestVersion : undefined;
217
+ const newVersion = state.plan.resolvedVersion;
218
+ const versionDisplay = oldVersion ? `${oldVersion} → ${newVersion}` : newVersion;
219
+ const hasOrg = 'org' in state.target.data && Boolean(state.target.data.org);
220
+ const reviewer = hasOrg ? 'none' : 'jasonpaff';
221
+ return (_jsxs(Box, { flexDirection: 'column', children: [_jsx(Box, { flexDirection: 'column', marginBottom: 1, children: _jsx(Text, { bold: true, children: "Publish Summary" }) }), _jsxs(Box, { flexDirection: 'column', marginBottom: 1, children: [_jsxs(Text, { children: [_jsx(Text, { dimColor: true, children: "Asset: " }), _jsx(Text, { bold: true, children: confirmDisplayName })] }), _jsxs(Text, { children: [_jsx(Text, { dimColor: true, children: "Version: " }), versionDisplay] }), _jsxs(Text, { children: [_jsx(Text, { dimColor: true, children: "Files: " }), state.plan.files.length] }), _jsxs(Text, { children: [_jsx(Text, { dimColor: true, children: "Action: " }), "Create PR"] }), _jsxs(Text, { children: [_jsx(Text, { dimColor: true, children: "Reviewer: " }), reviewer] })] }), _jsxs(Box, { children: [_jsx(Text, { color: 'cyan', children: '> ' }), _jsx(Text, { children: "Proceed? (y/n): " }), _jsx(TextInput, { focus: true, onChange: (v) => dispatch({ type: 'SET_PUBLISH_CONFIRM_VALUE', value: v }), onSubmit: () => dispatch({ type: 'SUBMIT_PUBLISH_CONFIRM' }), value: state.publishConfirmValue })] })] }));
222
+ }
476
223
  // Dry run result
477
- if (phase === 'dry-run-result' && plan && target) {
478
- const statusLabel = plan.isUpdate
479
- ? `Update from v${versionCheck && versionCheck.status !== 'new-asset' ? versionCheck.latestVersion : '?'}`
224
+ if (state.phase === 'dry-run-result' && state.plan && state.target) {
225
+ const statusLabel = state.plan.isUpdate
226
+ ? `Update from v${state.versionCheck && state.versionCheck.status !== 'new-asset' ? state.versionCheck.latestVersion : '?'}`
480
227
  : 'New asset';
481
- return (_jsxs(Box, { flexDirection: 'column', children: [_jsx(DryRunBanner, { action: 'publish', count: plan.files.length, tool: 'registry' }), _jsx(Text, { children: " " }), validation && (_jsxs(Box, { flexDirection: 'column', marginBottom: 1, children: [_jsx(Text, { bold: true, children: "Validation:" }), validation.errors.length === 0 && (_jsxs(Text, { children: [' ', _jsx(CheckIcon, { status: 'pass' }), " All checks passed"] })), validation.warnings.map((w, i) => (_jsxs(Text, { children: [' ', _jsx(CheckIcon, { status: 'warn' }), " ", w] }, i)))] })), _jsxs(Box, { flexDirection: 'column', children: [_jsxs(Text, { children: [_jsx(Text, { dimColor: true, children: "Asset: " }), _jsx(Text, { bold: true, children: target.data.name })] }), target.type === 'asset' && target.assetType && (_jsxs(Text, { children: [_jsx(Text, { dimColor: true, children: "Type: " }), target.assetType] })), target.type === 'bundle' && (_jsxs(Text, { children: [_jsx(Text, { dimColor: true, children: "Type: " }), "bundle"] })), _jsxs(Text, { children: [_jsx(Text, { dimColor: true, children: "Version: " }), plan.resolvedVersion] }), _jsxs(Text, { children: [_jsx(Text, { dimColor: true, children: "Status: " }), statusLabel] }), _jsxs(Text, { children: [_jsx(Text, { dimColor: true, children: "Checksum: " }), plan.checksum] })] }), _jsx(Text, { children: " " }), _jsx(Text, { bold: true, children: "Files to publish:" }), plan.files.map((file) => (_jsxs(Text, { children: [" ", file] }, file))), _jsx(Text, { children: " " }), _jsxs(Text, { children: [_jsx(Text, { dimColor: true, children: "Target: " }), plan.registryPath] }), _jsxs(Text, { children: [_jsx(Text, { dimColor: true, children: "Branch: " }), plan.branchName] }), isOrgAsset(plan) ? (_jsxs(Text, { children: [_jsx(Text, { dimColor: true, children: "Publish: " }), "Direct commit to ", DEFAULT_REGISTRY_BRANCH] })) : (_jsxs(Text, { children: [_jsx(Text, { dimColor: true, children: "PR Target:" }), " ", DEFAULT_REGISTRY_BRANCH] }))] }));
228
+ return (_jsxs(Box, { flexDirection: 'column', children: [_jsx(DryRunBanner, { action: 'publish', count: state.plan.files.length, tools: ['registry'] }), _jsx(Text, { children: " " }), state.validation && (_jsxs(Box, { flexDirection: 'column', marginBottom: 1, children: [_jsx(Text, { bold: true, children: "Validation:" }), state.validation.errors.length === 0 && (_jsxs(Text, { children: [' ', _jsx(CheckIcon, { status: 'pass' }), " All checks passed"] })), state.validation.warnings.map((w, i) => (_jsxs(Text, { children: [' ', _jsx(CheckIcon, { status: 'warn' }), " ", w] }, i)))] })), _jsxs(Box, { flexDirection: 'column', children: [_jsxs(Text, { children: [_jsx(Text, { dimColor: true, children: "Asset: " }), _jsx(Text, { bold: true, children: displayName })] }), state.target.type === 'asset' && state.target.assetType && (_jsxs(Text, { children: [_jsx(Text, { dimColor: true, children: "Type: " }), state.target.assetType] })), state.target.type === 'bundle' && (_jsxs(Text, { children: [_jsx(Text, { dimColor: true, children: "Type: " }), "bundle"] })), _jsxs(Text, { children: [_jsx(Text, { dimColor: true, children: "Version: " }), state.plan.resolvedVersion] }), _jsxs(Text, { children: [_jsx(Text, { dimColor: true, children: "Status: " }), statusLabel] }), _jsxs(Text, { children: [_jsx(Text, { dimColor: true, children: "Checksum: " }), state.plan.checksum] })] }), _jsx(Text, { children: " " }), _jsx(Text, { bold: true, children: "Files to publish:" }), state.plan.files.map((file) => (_jsxs(Text, { children: [" ", file] }, file))), _jsx(Text, { children: " " }), _jsxs(Text, { children: [_jsx(Text, { dimColor: true, children: "Target: " }), state.plan.registryPath] }), _jsxs(Text, { children: [_jsx(Text, { dimColor: true, children: "Branch: " }), state.plan.branchName] }), _jsxs(Text, { children: [_jsx(Text, { dimColor: true, children: "Action: " }), "Create PR"] })] }));
482
229
  }
483
230
  // Publishing
484
- if (phase === 'publishing') {
485
- return _jsx(Spinner, { message: progressMessage || 'Publishing...' });
231
+ if (state.phase === 'publishing') {
232
+ return _jsx(Spinner, { message: state.progressMessage || 'Publishing...' });
233
+ }
234
+ // Installing (auto-install raw publish to lockfile)
235
+ if (state.phase === 'installing') {
236
+ return _jsx(Spinner, { message: 'Adding to lockfile...' });
486
237
  }
487
238
  // Done
488
- if (phase === 'done' && publishResult && target) {
489
- return (_jsxs(Box, { flexDirection: 'column', children: [_jsxs(Text, { color: 'green', children: ["Published ", _jsx(Text, { bold: true, children: target.data.name }), " v", resolvedVersion] }), _jsx(Text, { children: " " }), publishResult.mode === 'pr' ? (_jsxs(Text, { children: ["PR: ", _jsx(Text, { color: 'cyan', children: publishResult.prUrl })] })) : (_jsxs(Text, { children: ["Committed directly to ", _jsx(Text, { color: 'cyan', children: publishResult.branchName })] })), _jsxs(Text, { children: ["Branch: ", _jsx(Text, { dimColor: true, children: publishResult.branchName })] })] }));
239
+ if (state.phase === 'done' && state.publishResult && state.target) {
240
+ return (_jsxs(Box, { flexDirection: 'column', children: [_jsxs(Text, { color: 'green', children: ["Published ", _jsx(Text, { bold: true, children: displayName }), " v", state.resolvedVersion] }), state.isRawPublish && (_jsxs(Text, { color: 'green', children: ["Installed ", state.rawDetection?.name, "@", state.resolvedVersion || state.target.data.version || '1.0.0', " to lockfile"] })), _jsx(Text, { children: " " }), _jsxs(Text, { children: ["PR: ", _jsx(Text, { color: 'cyan', children: state.publishResult.prUrl })] }), _jsxs(Text, { children: ["Branch: ", _jsx(Text, { dimColor: true, children: state.publishResult.branchName })] })] }));
490
241
  }
491
242
  return null;
492
243
  }