@detergent-software/atk 8.9.0-dev.3 → 8.9.0-dev.30

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 (271) hide show
  1. package/CHANGELOG.md +204 -0
  2. package/README.md +22 -12
  3. package/build/cli.js +18 -6
  4. package/build/cli.js.map +1 -1
  5. package/build/command-manifest.json +1507 -0
  6. package/build/commands/_app.d.ts.map +1 -1
  7. package/build/commands/_app.js +8 -4
  8. package/build/commands/_app.js.map +1 -1
  9. package/build/commands/audit.d.ts.map +1 -1
  10. package/build/commands/audit.js +1 -1
  11. package/build/commands/audit.js.map +1 -1
  12. package/build/commands/browse.js +2 -2
  13. package/build/commands/browse.js.map +1 -1
  14. package/build/commands/cache.d.ts +1 -1
  15. package/build/commands/cache.d.ts.map +1 -1
  16. package/build/commands/cache.js +1 -16
  17. package/build/commands/cache.js.map +1 -1
  18. package/build/commands/config.d.ts.map +1 -1
  19. package/build/commands/config.js +1 -1
  20. package/build/commands/config.js.map +1 -1
  21. package/build/commands/diff.d.ts.map +1 -1
  22. package/build/commands/diff.js +4 -0
  23. package/build/commands/diff.js.map +1 -1
  24. package/build/commands/drift.d.ts.map +1 -1
  25. package/build/commands/drift.js +4 -0
  26. package/build/commands/drift.js.map +1 -1
  27. package/build/commands/index.d.ts.map +1 -1
  28. package/build/commands/index.js +5 -40
  29. package/build/commands/index.js.map +1 -1
  30. package/build/commands/info.d.ts.map +1 -1
  31. package/build/commands/info.js +50 -33
  32. package/build/commands/info.js.map +1 -1
  33. package/build/commands/init.d.ts.map +1 -1
  34. package/build/commands/init.js +4 -2
  35. package/build/commands/init.js.map +1 -1
  36. package/build/commands/install.d.ts.map +1 -1
  37. package/build/commands/install.js +28 -7
  38. package/build/commands/install.js.map +1 -1
  39. package/build/commands/list.js +2 -2
  40. package/build/commands/list.js.map +1 -1
  41. package/build/commands/login.d.ts.map +1 -1
  42. package/build/commands/login.js +12 -2
  43. package/build/commands/login.js.map +1 -1
  44. package/build/commands/logout.d.ts.map +1 -1
  45. package/build/commands/logout.js +9 -1
  46. package/build/commands/logout.js.map +1 -1
  47. package/build/commands/outdated.js +1 -1
  48. package/build/commands/outdated.js.map +1 -1
  49. package/build/commands/prune.d.ts.map +1 -1
  50. package/build/commands/prune.js +4 -2
  51. package/build/commands/prune.js.map +1 -1
  52. package/build/commands/publish.d.ts +1 -1
  53. package/build/commands/publish.d.ts.map +1 -1
  54. package/build/commands/publish.js +31 -36
  55. package/build/commands/publish.js.map +1 -1
  56. package/build/commands/release-notes.d.ts.map +1 -1
  57. package/build/commands/release-notes.js +4 -0
  58. package/build/commands/release-notes.js.map +1 -1
  59. package/build/commands/schema.d.ts +3 -3
  60. package/build/commands/search.js +1 -1
  61. package/build/commands/search.js.map +1 -1
  62. package/build/commands/sync.d.ts +1 -1
  63. package/build/commands/sync.d.ts.map +1 -1
  64. package/build/commands/sync.js +27 -12
  65. package/build/commands/sync.js.map +1 -1
  66. package/build/commands/update.d.ts.map +1 -1
  67. package/build/commands/update.js +58 -9
  68. package/build/commands/update.js.map +1 -1
  69. package/build/commands/whoami.d.ts.map +1 -1
  70. package/build/commands/whoami.js +16 -4
  71. package/build/commands/whoami.js.map +1 -1
  72. package/build/commands/why.js +3 -4
  73. package/build/commands/why.js.map +1 -1
  74. package/build/components/Header.d.ts +2 -3
  75. package/build/components/Header.d.ts.map +1 -1
  76. package/build/components/Header.js +2 -9
  77. package/build/components/Header.js.map +1 -1
  78. package/build/components/LocalEditsHint.d.ts +16 -0
  79. package/build/components/LocalEditsHint.d.ts.map +1 -0
  80. package/build/components/LocalEditsHint.js +18 -0
  81. package/build/components/LocalEditsHint.js.map +1 -0
  82. package/build/components/SyncAllInSync.d.ts +5 -1
  83. package/build/components/SyncAllInSync.d.ts.map +1 -1
  84. package/build/components/SyncAllInSync.js +2 -2
  85. package/build/components/SyncAllInSync.js.map +1 -1
  86. package/build/components/header-art.d.ts +7 -0
  87. package/build/components/header-art.d.ts.map +1 -0
  88. package/build/components/header-art.js +14 -0
  89. package/build/components/header-art.js.map +1 -0
  90. package/build/components/index.d.ts +1 -0
  91. package/build/components/index.d.ts.map +1 -1
  92. package/build/components/index.js +1 -0
  93. package/build/components/index.js.map +1 -1
  94. package/build/hooks/useListActions.d.ts.map +1 -1
  95. package/build/hooks/useListActions.js +4 -0
  96. package/build/hooks/useListActions.js.map +1 -1
  97. package/build/hooks/usePruneState.d.ts +1 -7
  98. package/build/hooks/usePruneState.d.ts.map +1 -1
  99. package/build/hooks/usePruneState.js +18 -62
  100. package/build/hooks/usePruneState.js.map +1 -1
  101. package/build/hooks/usePublishState.d.ts +43 -8
  102. package/build/hooks/usePublishState.d.ts.map +1 -1
  103. package/build/hooks/usePublishState.js +82 -565
  104. package/build/hooks/usePublishState.js.map +1 -1
  105. package/build/lib/adapter.d.ts +10 -1
  106. package/build/lib/adapter.d.ts.map +1 -1
  107. package/build/lib/adapter.js +46 -3
  108. package/build/lib/adapter.js.map +1 -1
  109. package/build/lib/api-client.d.ts +9 -5
  110. package/build/lib/api-client.d.ts.map +1 -1
  111. package/build/lib/api-client.js +35 -8
  112. package/build/lib/api-client.js.map +1 -1
  113. package/build/lib/atk-api/generated/types.gen.d.ts +4 -4
  114. package/build/lib/auth.d.ts +12 -2
  115. package/build/lib/auth.d.ts.map +1 -1
  116. package/build/lib/auth.js +38 -3
  117. package/build/lib/auth.js.map +1 -1
  118. package/build/lib/checksum.d.ts +40 -14
  119. package/build/lib/checksum.d.ts.map +1 -1
  120. package/build/lib/checksum.js +110 -57
  121. package/build/lib/checksum.js.map +1 -1
  122. package/build/lib/config.d.ts +4 -4
  123. package/build/lib/config.d.ts.map +1 -1
  124. package/build/lib/config.js +31 -8
  125. package/build/lib/config.js.map +1 -1
  126. package/build/lib/diagnostics.d.ts.map +1 -1
  127. package/build/lib/diagnostics.js +10 -7
  128. package/build/lib/diagnostics.js.map +1 -1
  129. package/build/lib/diff-command.js +1 -1
  130. package/build/lib/diff-command.js.map +1 -1
  131. package/build/lib/errors.d.ts +4 -1
  132. package/build/lib/errors.d.ts.map +1 -1
  133. package/build/lib/errors.js.map +1 -1
  134. package/build/lib/format-age.d.ts +3 -0
  135. package/build/lib/format-age.d.ts.map +1 -0
  136. package/build/lib/format-age.js +18 -0
  137. package/build/lib/format-age.js.map +1 -0
  138. package/build/lib/installer.d.ts +8 -11
  139. package/build/lib/installer.d.ts.map +1 -1
  140. package/build/lib/installer.js +83 -28
  141. package/build/lib/installer.js.map +1 -1
  142. package/build/lib/local-edits.d.ts +72 -0
  143. package/build/lib/local-edits.d.ts.map +1 -0
  144. package/build/lib/local-edits.js +145 -0
  145. package/build/lib/local-edits.js.map +1 -0
  146. package/build/lib/lockfile.d.ts +12 -8
  147. package/build/lib/lockfile.d.ts.map +1 -1
  148. package/build/lib/lockfile.js +217 -54
  149. package/build/lib/lockfile.js.map +1 -1
  150. package/build/lib/mover.d.ts.map +1 -1
  151. package/build/lib/mover.js +11 -12
  152. package/build/lib/mover.js.map +1 -1
  153. package/build/lib/multi-tool-install.d.ts +4 -2
  154. package/build/lib/multi-tool-install.d.ts.map +1 -1
  155. package/build/lib/multi-tool-install.js +12 -2
  156. package/build/lib/multi-tool-install.js.map +1 -1
  157. package/build/lib/offline.d.ts +19 -0
  158. package/build/lib/offline.d.ts.map +1 -0
  159. package/build/lib/offline.js +26 -0
  160. package/build/lib/offline.js.map +1 -0
  161. package/build/lib/owned-paths.d.ts +7 -4
  162. package/build/lib/owned-paths.d.ts.map +1 -1
  163. package/build/lib/owned-paths.js +23 -8
  164. package/build/lib/owned-paths.js.map +1 -1
  165. package/build/lib/parse-json.d.ts +12 -0
  166. package/build/lib/parse-json.d.ts.map +1 -1
  167. package/build/lib/parse-json.js +15 -2
  168. package/build/lib/parse-json.js.map +1 -1
  169. package/build/lib/pastel/commander-specs.d.ts +7 -0
  170. package/build/lib/pastel/commander-specs.d.ts.map +1 -0
  171. package/build/lib/pastel/commander-specs.js +50 -0
  172. package/build/lib/pastel/commander-specs.js.map +1 -0
  173. package/build/lib/pastel/generate-arguments.d.ts +3 -3
  174. package/build/lib/pastel/generate-arguments.d.ts.map +1 -1
  175. package/build/lib/pastel/generate-arguments.js +25 -22
  176. package/build/lib/pastel/generate-arguments.js.map +1 -1
  177. package/build/lib/pastel/generate-command.d.ts +7 -5
  178. package/build/lib/pastel/generate-command.d.ts.map +1 -1
  179. package/build/lib/pastel/generate-command.js +32 -67
  180. package/build/lib/pastel/generate-command.js.map +1 -1
  181. package/build/lib/pastel/generate-commands.d.ts +3 -5
  182. package/build/lib/pastel/generate-commands.d.ts.map +1 -1
  183. package/build/lib/pastel/generate-commands.js +6 -10
  184. package/build/lib/pastel/generate-commands.js.map +1 -1
  185. package/build/lib/pastel/generate-options.d.ts +3 -3
  186. package/build/lib/pastel/generate-options.d.ts.map +1 -1
  187. package/build/lib/pastel/generate-options.js +16 -13
  188. package/build/lib/pastel/generate-options.js.map +1 -1
  189. package/build/lib/pastel/index.d.ts +26 -4
  190. package/build/lib/pastel/index.d.ts.map +1 -1
  191. package/build/lib/pastel/index.js +104 -18
  192. package/build/lib/pastel/index.js.map +1 -1
  193. package/build/lib/pastel/internal-types.d.ts +39 -8
  194. package/build/lib/pastel/internal-types.d.ts.map +1 -1
  195. package/build/lib/pastel/manifest.d.ts +8 -0
  196. package/build/lib/pastel/manifest.d.ts.map +1 -0
  197. package/build/lib/pastel/manifest.js +7 -0
  198. package/build/lib/pastel/manifest.js.map +1 -0
  199. package/build/lib/pastel/read-commands.d.ts +7 -2
  200. package/build/lib/pastel/read-commands.d.ts.map +1 -1
  201. package/build/lib/pastel/read-commands.js +51 -30
  202. package/build/lib/pastel/read-commands.js.map +1 -1
  203. package/build/lib/pastel/render-command.d.ts +13 -0
  204. package/build/lib/pastel/render-command.d.ts.map +1 -0
  205. package/build/lib/pastel/render-command.js +56 -0
  206. package/build/lib/pastel/render-command.js.map +1 -0
  207. package/build/lib/pruner.d.ts +26 -0
  208. package/build/lib/pruner.d.ts.map +1 -0
  209. package/build/lib/pruner.js +42 -0
  210. package/build/lib/pruner.js.map +1 -0
  211. package/build/lib/publish-flow.d.ts +7 -15
  212. package/build/lib/publish-flow.d.ts.map +1 -1
  213. package/build/lib/publish-flow.js +634 -178
  214. package/build/lib/publish-flow.js.map +1 -1
  215. package/build/lib/publish-run.d.ts +55 -0
  216. package/build/lib/publish-run.d.ts.map +1 -0
  217. package/build/lib/publish-run.js +169 -0
  218. package/build/lib/publish-run.js.map +1 -0
  219. package/build/lib/publisher.d.ts +23 -16
  220. package/build/lib/publisher.d.ts.map +1 -1
  221. package/build/lib/publisher.js +34 -35
  222. package/build/lib/publisher.js.map +1 -1
  223. package/build/lib/registrar.d.ts.map +1 -1
  224. package/build/lib/registrar.js +2 -2
  225. package/build/lib/registrar.js.map +1 -1
  226. package/build/lib/registry.d.ts +18 -7
  227. package/build/lib/registry.d.ts.map +1 -1
  228. package/build/lib/registry.js +113 -32
  229. package/build/lib/registry.js.map +1 -1
  230. package/build/lib/root-path.d.ts +11 -0
  231. package/build/lib/root-path.d.ts.map +1 -1
  232. package/build/lib/root-path.js +15 -1
  233. package/build/lib/root-path.js.map +1 -1
  234. package/build/lib/schemas/config.d.ts +3 -1
  235. package/build/lib/schemas/config.d.ts.map +1 -1
  236. package/build/lib/schemas/config.js +1 -1
  237. package/build/lib/schemas/config.js.map +1 -1
  238. package/build/lib/schemas/lockfile.d.ts +156 -23
  239. package/build/lib/schemas/lockfile.d.ts.map +1 -1
  240. package/build/lib/schemas/lockfile.js +100 -79
  241. package/build/lib/schemas/lockfile.js.map +1 -1
  242. package/build/lib/setup.d.ts.map +1 -1
  243. package/build/lib/setup.js +53 -48
  244. package/build/lib/setup.js.map +1 -1
  245. package/build/lib/sync.d.ts +22 -6
  246. package/build/lib/sync.d.ts.map +1 -1
  247. package/build/lib/sync.js +59 -7
  248. package/build/lib/sync.js.map +1 -1
  249. package/build/lib/uninstaller.d.ts.map +1 -1
  250. package/build/lib/uninstaller.js +8 -5
  251. package/build/lib/uninstaller.js.map +1 -1
  252. package/build/lib/update-check.d.ts +4 -0
  253. package/build/lib/update-check.d.ts.map +1 -1
  254. package/build/lib/update-check.js +55 -56
  255. package/build/lib/update-check.js.map +1 -1
  256. package/build/lib/updater.d.ts +31 -1
  257. package/build/lib/updater.d.ts.map +1 -1
  258. package/build/lib/updater.js +143 -4
  259. package/build/lib/updater.js.map +1 -1
  260. package/build/lib/usage-error.d.ts +20 -0
  261. package/build/lib/usage-error.d.ts.map +1 -0
  262. package/build/lib/usage-error.js +41 -0
  263. package/build/lib/usage-error.js.map +1 -0
  264. package/build/lib/user-setup.d.ts.map +1 -1
  265. package/build/lib/user-setup.js +62 -59
  266. package/build/lib/user-setup.js.map +1 -1
  267. package/build/lib/write-file.d.ts +5 -0
  268. package/build/lib/write-file.d.ts.map +1 -1
  269. package/build/lib/write-file.js +10 -7
  270. package/build/lib/write-file.js.map +1 -1
  271. package/package.json +81 -81
@@ -1,588 +1,105 @@
1
- import { rm } from 'node:fs/promises';
2
- import { useEffect, useReducer, useRef } from 'react';
3
- import { createInitialState, isBatch, runPublishStep, splitList, } from '../lib/publish-flow.js';
4
- import { bumpVersion, isOrgScopedTarget } from '../lib/publisher.js';
5
- import { parseReviewersInput } from '../lib/reviewers.js';
6
- export { createInitialState, isBatch } from '../lib/publish-flow.js';
7
- export function publishReducer(state, action) {
1
+ import { useEffect, useRef, useState } from 'react';
2
+ import { createInitialState } from '../lib/publish-flow.js';
3
+ import { promptValue, runPublish } from '../lib/publish-run.js';
4
+ /** Move the tools prompt's cursor over its `count` rows, wrapping at either end, or tick or untick a tool. */
5
+ export function toolPickerReducer(picker, action) {
8
6
  switch (action.type) {
9
- case 'BUMP_DONE': {
10
- const bumped = {
11
- ...state,
12
- errorMessage: action.message ? action.message : state.errorMessage,
13
- resolvedVersion: action.version,
14
- target: action.updatedTarget,
15
- };
16
- return action.message ? { ...bumped, phase: 'error' } : advanceToPlan(bumped);
17
- }
18
- case 'CONFIRM_PROMPT_TOOLS': {
19
- if (state.selectedPromptTools.length === 0)
20
- return state;
21
- const updatedToolsTarget = state.target
22
- ? {
23
- ...state.target,
24
- data: { ...state.target.data, tools: state.selectedPromptTools },
25
- }
26
- : undefined;
27
- return {
28
- ...state,
29
- phase: phaseAfterMetadata(updatedToolsTarget),
30
- target: updatedToolsTarget,
31
- };
32
- }
33
- case 'DETECT_DONE':
34
- if (action.target.type === 'bundle' && state.entries.length > 0) {
35
- return {
36
- ...state,
37
- errorMessage: 'A bundle is published on its own. Remove --with, and publish its new assets first.',
38
- phase: 'error',
39
- target: action.target,
40
- };
41
- }
42
- return {
43
- ...state,
44
- phase: 'validating',
45
- target: action.target,
46
- };
47
- case 'ENTRIES_CHECKED':
48
- return advanceToPlan({ ...state, entries: action.entries });
49
- case 'ENTRIES_LOADED':
50
- return { ...state, entries: action.entries };
51
- case 'ERROR':
52
- return {
53
- ...state,
54
- errorCode: action.code,
55
- errorCommand: action.command,
56
- errorHint: action.hint,
57
- errorMessage: action.message,
58
- phase: 'error',
59
- };
60
- case 'INSTALL_DONE':
61
- return { ...state, phase: 'done' };
62
- case 'PLAN_DONE': {
63
- // dry-run always shows the dry-run result; --yes / non-TTY skip the confirm prompt
64
- // and proceed directly to publishing.
65
- let nextPhase;
66
- if (state.flags.dryRun) {
67
- nextPhase = 'dry-run-result';
68
- }
69
- else if (state.nonInteractive) {
70
- nextPhase = 'publishing';
71
- }
72
- else {
73
- nextPhase = 'confirm-publish';
74
- }
75
- return {
76
- ...state,
77
- manifestDiff: action.manifestDiff,
78
- phase: nextPhase,
79
- plan: action.plan,
80
- };
81
- }
82
- case 'PUBLISH_DONE': {
83
- const nextPhase = state.isRawPublish ? 'installing' : 'done';
84
- return {
85
- ...state,
86
- phase: nextPhase,
87
- publishResult: action.result,
88
- };
89
- }
90
- case 'PUBLISH_PROGRESS':
91
- return { ...state, progressMessage: action.message };
92
- case 'RAW_DETECT_DONE':
93
- return {
94
- ...state,
95
- authorValue: action.authorValue,
96
- isRawPublish: true,
97
- orgValue: action.orgValue,
98
- phase: 'gathering-metadata',
99
- rawDetection: action.rawDetection,
100
- toolsDetected: action.toolsDetected,
101
- };
102
- case 'RAW_DETECT_DONE_NON_INTERACTIVE':
103
- return {
104
- ...state,
105
- isRawPublish: true,
106
- phase: 'validating',
107
- rawDetection: action.rawDetection,
108
- target: action.target,
109
- };
110
- case 'REGISTRY_CHECK_DONE': {
111
- const { isUpdate, resolvedVersion, token, versionCheck } = action;
112
- let nextPhase;
113
- let errorMessage = state.errorMessage;
114
- let bumpedVersion = resolvedVersion;
115
- let bumpedTarget = state.target;
116
- if (versionCheck.status === 'new-asset') {
117
- nextPhase = 'building-plan';
118
- }
119
- else if (versionCheck.status === 'version-already-bumped') {
120
- // --yes / non-TTY implicitly confirm the update
121
- nextPhase = state.nonInteractive ? 'building-plan' : 'confirm-update';
122
- }
123
- else {
124
- // needs-bump
125
- if (state.nonInteractive) {
126
- if (state.flags.bump && state.target) {
127
- // Auto-bump using the flag value; a successful publish writes it to the manifest
128
- try {
129
- bumpedVersion = bumpVersion(versionCheck.latestVersion, state.flags.bump);
130
- bumpedTarget = {
131
- ...state.target,
132
- data: { ...state.target.data, version: bumpedVersion },
133
- };
134
- nextPhase = 'building-plan';
135
- }
136
- catch {
137
- errorMessage = 'Failed to compute bumped version.';
138
- nextPhase = 'error';
139
- }
140
- }
141
- else if (isBatch(state.flags)) {
142
- // advanceToPlan lists every asset of the batch that needs --bump, once the entries are checked.
143
- nextPhase = 'building-plan';
144
- }
145
- else {
146
- errorMessage = `--bump <patch|minor|major> required: registry has v${versionCheck.latestVersion} but manifest is not newer`;
147
- nextPhase = 'error';
148
- }
149
- }
150
- else {
151
- nextPhase = 'bump-prompt';
152
- }
153
- }
154
- const checked = {
155
- ...state,
156
- errorMessage,
157
- isUpdate,
158
- phase: nextPhase,
159
- resolvedVersion: bumpedVersion,
160
- target: bumpedTarget,
161
- token,
162
- versionCheck,
163
- };
164
- return nextPhase === 'building-plan' ? advanceToPlan(checked) : checked;
165
- }
166
- case 'RESOLVE_TOOLS_NONINTERACTIVE': {
167
- const updatedTarget = state.target
168
- ? {
169
- ...state.target,
170
- data: { ...state.target.data, tools: action.tools },
171
- }
172
- : undefined;
173
- return {
174
- ...state,
175
- phase: 'checking-registry',
176
- target: updatedTarget,
177
- };
178
- }
179
- case 'RESOLVED_INSTALLED':
180
- return {
181
- ...state,
182
- phase: 'detecting',
183
- resolvedPath: action.resolvedPath,
184
- };
185
- case 'RESOLVED_UPDATE':
186
- return {
187
- ...state,
188
- phase: 'detecting',
189
- resolvedPath: action.resolvedPath,
190
- };
191
- case 'SET_BUMP_SELECTION':
192
- return { ...state, bumpSelection: action.value };
193
- case 'SET_CONFIRM_VALUE':
194
- return { ...state, confirmValue: action.value };
195
- case 'SET_DESCRIPTION':
196
- return { ...state, descriptionValue: action.value };
197
- case 'SET_PROMPT_TAGS':
198
- return { ...state, promptTagsValue: action.value };
199
- case 'SET_PUBLISH_CONFIRM_VALUE':
200
- return { ...state, publishConfirmValue: action.value };
201
- case 'SET_REVIEWER':
202
- return { ...state, reviewerValue: action.value };
203
- case 'SET_TAGS':
204
- return { ...state, tagsValue: action.value };
205
- case 'SET_WITH_CONFIRM_VALUE':
206
- return { ...state, withConfirmValue: action.value };
207
- case 'STAGING_DONE':
208
- return {
209
- ...state,
210
- phase: 'validating',
211
- target: action.target,
212
- };
213
- case 'SUBMIT_BUMP': {
214
- const trimmed = state.bumpSelection.trim().toLowerCase();
215
- if (trimmed !== 'patch' && trimmed !== 'minor' && trimmed !== 'major') {
216
- return state; // Ignore invalid input
217
- }
218
- // The prompt is for an entry: bump it, then on to the next pending bump or the plan.
219
- if (state.bumpEntry !== undefined) {
220
- const entry = state.entries[state.bumpEntry];
221
- if (entry?.versionCheck?.status !== 'needs-bump')
222
- return state;
223
- return bumpEntryAt({ ...state, bumpSelection: '' }, state.bumpEntry, trimmed);
224
- }
225
- if (!state.target || !state.versionCheck || state.versionCheck.status !== 'needs-bump') {
226
- return state;
227
- }
228
- // Compute the bumped version in the reducer (pure, synchronous)
229
- const bumpType = trimmed;
230
- try {
231
- const newVersion = bumpVersion(state.versionCheck.latestVersion, bumpType);
232
- // The bump is only on the target until the publish succeeds, which writes it to
233
- // the manifest; entries still to check or bump come first.
234
- return advanceToPlan({
235
- ...state,
236
- bumpSelection: '',
237
- resolvedVersion: newVersion,
238
- target: { ...state.target, data: { ...state.target.data, version: newVersion } },
239
- });
240
- }
241
- catch {
242
- return {
243
- ...state,
244
- errorMessage: 'Failed to compute bumped version.',
245
- phase: 'error',
246
- };
247
- }
248
- }
249
- case 'SUBMIT_CONFIRM': {
250
- const trimmed = state.confirmValue.trim().toLowerCase();
251
- if (trimmed === 'y' || trimmed === 'yes') {
252
- return advanceToPlan(state);
253
- }
254
- else if (trimmed === 'n' || trimmed === 'no') {
255
- return { ...state, errorMessage: 'Publish cancelled.', phase: 'error' };
256
- }
257
- // Otherwise ignore (wait for valid input)
258
- return state;
259
- }
260
- case 'SUBMIT_DESCRIPTION': {
261
- const trimmed = state.descriptionValue.trim();
262
- if (!trimmed)
263
- return state; // Don't allow empty description
264
- return {
265
- ...state,
266
- descriptionValue: trimmed,
267
- metadataSubPhase: 'tags',
268
- };
269
- }
270
- case 'SUBMIT_PROMPT_TAGS': {
271
- const parsedTags = splitList(state.promptTagsValue);
272
- // Update the target's data with the new tags
273
- const updatedTagsTarget = state.target
274
- ? {
275
- ...state.target,
276
- data: { ...state.target.data, tags: parsedTags.length > 0 ? parsedTags : undefined },
277
- }
278
- : undefined;
279
- // Check if tools are also missing (only for assets)
280
- const needsToolsPrompt = updatedTagsTarget?.type === 'asset' &&
281
- (!('tools' in updatedTagsTarget.data) ||
282
- !Array.isArray(updatedTagsTarget.data.tools) ||
283
- (updatedTagsTarget.data.tools?.length ?? 0) === 0);
284
- const nextTagsPhase = needsToolsPrompt ? 'loading-tools' : phaseAfterMetadata(updatedTagsTarget);
285
- return {
286
- ...state,
287
- phase: nextTagsPhase,
288
- target: updatedTagsTarget,
289
- };
290
- }
291
- case 'SUBMIT_PUBLISH_CONFIRM': {
292
- const trimmed = state.publishConfirmValue.trim().toLowerCase();
293
- if (trimmed === 'y' || trimmed === 'yes') {
294
- return { ...state, phase: 'publishing' };
295
- }
296
- else if (trimmed === 'n' || trimmed === 'no') {
297
- return { ...state, errorMessage: 'Publish cancelled.', phase: 'error' };
298
- }
299
- // Otherwise ignore (wait for valid input)
300
- return state;
301
- }
302
- case 'SUBMIT_REVIEWER':
303
- return { ...state, phase: 'checking-registry' };
304
- case 'SUBMIT_TAGS':
305
- return {
306
- ...state,
307
- metadataSubPhase: 'building-staging',
308
- };
309
- case 'SUBMIT_WITH_CONFIRM': {
310
- const trimmed = state.withConfirmValue.trim().toLowerCase();
311
- if (trimmed === 'y' || trimmed === 'yes') {
312
- return advanceToPlan({
313
- ...state,
314
- entries: [...state.entries, ...state.suggestedEntries],
315
- missingDependencies: [],
316
- pendingError: undefined,
317
- suggestedEntries: [],
318
- withConfirmValue: '',
319
- });
320
- }
321
- if ((trimmed === 'n' || trimmed === 'no') && state.pendingError) {
322
- return publishReducer({ ...state, suggestedEntries: [], withConfirmValue: '' }, state.pendingError);
323
- }
324
- return state;
325
- }
326
- case 'SUGGEST_ENTRIES':
327
- return {
328
- ...state,
329
- missingDependencies: action.missing,
330
- pendingError: action.error,
331
- phase: 'confirm-with',
332
- suggestedEntries: action.suggested,
333
- withConfirmValue: '',
334
- };
335
7
  case 'TOGGLE_PROMPT_TOOL': {
336
- const toolSet = new Set(state.selectedPromptTools);
8
+ const toolSet = new Set(picker.selected);
337
9
  if (toolSet.has(action.tool)) {
338
10
  toolSet.delete(action.tool);
339
11
  }
340
12
  else {
341
13
  toolSet.add(action.tool);
342
14
  }
343
- return {
344
- ...state,
345
- selectedPromptTools: [...toolSet],
346
- };
347
- }
348
- case 'TOOL_CURSOR_DOWN': {
349
- if (state.toolAdapters.length === 0)
350
- return state;
351
- return {
352
- ...state,
353
- toolCursorIndex: state.toolCursorIndex >= state.toolAdapters.length - 1 ? 0 : state.toolCursorIndex + 1,
354
- };
355
- }
356
- case 'TOOL_CURSOR_UP': {
357
- if (state.toolAdapters.length === 0)
358
- return state;
359
- return {
360
- ...state,
361
- toolCursorIndex: state.toolCursorIndex <= 0 ? state.toolAdapters.length - 1 : state.toolCursorIndex - 1,
362
- };
363
- }
364
- case 'TOOLS_LOADED':
365
- return {
366
- ...state,
367
- phase: 'prompting-tools',
368
- toolAdapters: action.adapters,
369
- toolCursorIndex: 0,
370
- };
371
- case 'VALIDATE_DONE': {
372
- if (!action.validation.valid) {
373
- return {
374
- ...state,
375
- errorMessage: `Validation failed:\n${action.validation.errors.map((e) => ` - ${e}`).join('\n')}`,
376
- phase: 'error',
377
- validation: action.validation,
378
- };
379
- }
380
- // Seed the reviewers field: the --reviewer flag wins over the project's
381
- // lockfile-configured default (org.ts's CLI-flag > lockfile priority chain).
382
- const reviewerValue = state.flags.reviewerFlag ?? (action.lockfileOrgReviewers ?? []).join(', ');
383
- // Determine next phase based on missing tags/tools. A batch asks for neither: as for
384
- // a --with entry, a missing one is only a warning.
385
- const batch = isBatch(state.flags);
386
- const manifest = state.target?.data;
387
- const hasTags = batch || (manifest && 'tags' in manifest && Array.isArray(manifest.tags) && manifest.tags.length > 0);
388
- const hasTools = batch ||
389
- // Only assets have tools; bundles skip the tools prompt
390
- state.target?.type !== 'asset' ||
391
- (manifest && 'tools' in manifest && Array.isArray(manifest.tools) && manifest.tools.length > 0);
392
- const isOrgScoped = batch
393
- ? [state.target, ...state.entries.map((entry) => entry.target)].some((t) => t && isOrgScopedTarget(t))
394
- : Boolean(state.target && isOrgScopedTarget(state.target));
395
- // Reviewers only apply to org-scoped assets (non-org PRs always go to the registry
396
- // maintainer) — fail fast rather than silently ignoring the flag.
397
- if (!isOrgScoped && state.flags.reviewerFlag && parseReviewersInput(state.flags.reviewerFlag).length > 0) {
398
- return {
399
- ...state,
400
- errorMessage: 'The --reviewer flag only applies to org-scoped assets. Remove the flag to publish this asset.',
401
- phase: 'error',
402
- validation: action.validation,
403
- };
404
- }
405
- // Non-interactive path: resolve tags from --tags flag (or empty) right here, then
406
- // either route to loading-tools (effect resolves tools async) or directly to
407
- // checking-registry. Manifest tags always win when present. The reviewer prompt
408
- // never applies here — non-interactive mode always skips it.
409
- if (state.nonInteractive) {
410
- let nextTarget = state.target;
411
- if (!hasTags && nextTarget) {
412
- const flagTags = splitList(state.flags.tagsFlag);
413
- nextTarget = {
414
- ...nextTarget,
415
- data: { ...nextTarget.data, tags: flagTags.length > 0 ? flagTags : undefined },
416
- };
417
- }
418
- let nextPhase;
419
- if (!hasTools) {
420
- // The loading-tools effect detects whether we're non-interactive and
421
- // either resolves tools from the manifest/flag/inference or errors out.
422
- nextPhase = 'loading-tools';
423
- }
424
- else {
425
- nextPhase = 'checking-registry';
426
- }
427
- return {
428
- ...state,
429
- phase: nextPhase,
430
- reviewerValue,
431
- target: nextTarget,
432
- validation: action.validation,
433
- };
434
- }
435
- let nextPhase;
436
- if (!hasTags) {
437
- nextPhase = 'prompting-tags';
438
- }
439
- else if (!hasTools) {
440
- nextPhase = 'loading-tools';
441
- }
442
- else {
443
- nextPhase = isOrgScoped ? 'prompting-reviewer' : 'checking-registry';
444
- }
445
- return {
446
- ...state,
447
- phase: nextPhase,
448
- reviewerValue,
449
- validation: action.validation,
450
- };
15
+ return { ...picker, selected: [...toolSet] };
451
16
  }
452
- default:
453
- return state;
17
+ case 'TOOL_CURSOR_DOWN':
18
+ if (action.count === 0)
19
+ return picker;
20
+ return { ...picker, cursor: picker.cursor >= action.count - 1 ? 0 : picker.cursor + 1 };
21
+ case 'TOOL_CURSOR_UP':
22
+ if (action.count === 0)
23
+ return picker;
24
+ return { ...picker, cursor: picker.cursor <= 0 ? action.count - 1 : picker.cursor - 1 };
454
25
  }
455
26
  }
456
27
  /**
457
- * The publish flow's state for the command's UI. The reducer moves it through its
458
- * phases; on each phase that waits on work, the step in `lib/publish-flow.ts` runs
459
- * and dispatches what it found.
28
+ * The publish flow for the command's UI. `runPublish` (lib/publish-run.ts) runs it once
29
+ * and this mirrors each state it moves to. The hook is its prompter: a prompt waits on
30
+ * `input`, which shows the state's own value for that prompt (an answer the reducer
31
+ * didn't take stays) until something is typed, or, for tools, on `picker`.
460
32
  */
461
33
  export function usePublishState(flags) {
462
- const [state, dispatch] = useReducer(publishReducer, undefined, () => createInitialState(flags));
463
- // Staging directories (--from-installed, --update, a raw publish's manifest) to remove at the end
464
- const stagingDirs = useRef([]);
465
- const unmounted = useRef(false);
466
- const removeStagingDirs = (dirs) => {
467
- for (const dir of dirs.splice(0)) {
468
- rm(dir, { force: true, recursive: true }).catch(() => {
469
- // Best-effort cleanup — ignore errors
470
- });
471
- }
472
- };
473
- // Phase-gated: the step runs once on entering its phase (or the building-staging sub-phase)
34
+ const [state, setState] = useState(() => createInitialState(flags));
35
+ // What was typed, and for which state: a new state shows its own value, in the same render
36
+ const [edit, setEdit] = useState();
37
+ const [picker, setPicker] = useState({ cursor: 0, selected: [] });
38
+ // Enter and the picker's keys read the latest input, as the reducer read its own fields, not a render's
39
+ const typed = useRef('');
40
+ const ticked = useRef(picker);
41
+ const answer = useRef(undefined);
42
+ const answerTools = useRef(undefined);
474
43
  useEffect(() => {
475
- let cancelled = false;
476
- void runPublishStep(state, {
477
- cancelled: () => cancelled,
478
- dispatch,
479
- stage: (dir) => {
480
- stagingDirs.current.push(dir);
481
- // A step that outlived the command still leaves nothing behind
482
- if (unmounted.current)
483
- removeStagingDirs(stagingDirs.current);
484
- },
44
+ const ask = (s) => new Promise((resolve) => {
45
+ typed.current = promptValue(s);
46
+ answer.current = resolve;
485
47
  });
48
+ const prompter = {
49
+ bump: ask,
50
+ confirmPublish: ask,
51
+ confirmUpdate: ask,
52
+ confirmWith: ask,
53
+ description: ask,
54
+ rawTags: ask,
55
+ reviewers: ask,
56
+ tags: ask,
57
+ tools: () => new Promise((resolve) => {
58
+ answerTools.current = resolve;
59
+ }),
60
+ };
61
+ // Unmounting aborts the run: it drops the pending prompt and removes the staging directories
62
+ const controller = new AbortController();
63
+ void runPublish(flags, prompter, { onState: setState, signal: controller.signal });
486
64
  return () => {
487
- cancelled = true;
65
+ controller.abort();
488
66
  };
489
67
  // eslint-disable-next-line react-hooks/exhaustive-deps
490
- }, [state.phase, state.metadataSubPhase]);
491
- // --- Cleanup temp directory on error or done ---
492
- useEffect(() => {
493
- if (state.phase !== 'error' && state.phase !== 'done' && state.phase !== 'dry-run-result')
494
- return;
495
- removeStagingDirs(stagingDirs.current);
496
- }, [state.phase]);
497
- // --- ...or when the command goes away before either ---
498
- useEffect(() => () => {
499
- unmounted.current = true;
500
- removeStagingDirs(stagingDirs.current);
501
68
  }, []);
502
- return [state, dispatch];
503
- }
504
- // ---------------------------------------------------------------------------
505
- // Pure reducer helpers
506
- // ---------------------------------------------------------------------------
507
- /**
508
- * The step before `building-plan`, once the root asset's own checks are done:
509
- * check the entries not yet checked, then settle each entry that needs a bump
510
- * (the bump prompt; `--bump` or an error when non-interactive), then plan.
511
- */
512
- function advanceToPlan(state) {
513
- if (state.entries.some((entry) => !entry.versionCheck)) {
514
- return { ...state, bumpEntry: undefined, phase: 'checking-entries' };
515
- }
516
- // A batch without --bump names every asset that needs one, not just the first.
517
- if (isBatch(state.flags) && state.nonInteractive && !state.flags.bump) {
518
- const pending = [
519
- ...(state.target && state.versionCheck?.status === 'needs-bump' && !state.resolvedVersion
520
- ? [{ label: state.flags.rawPath, latestVersion: state.versionCheck.latestVersion, target: state.target }]
521
- : []),
522
- ...state.entries.flatMap((entry) => entry.versionCheck?.status === 'needs-bump' && entry.resolvedVersion === undefined
523
- ? [{ label: entry.label, latestVersion: entry.versionCheck.latestVersion, target: entry.target }]
524
- : []),
525
- ];
526
- if (pending.length > 0) {
527
- const lines = pending.map((p) => ` ${p.label}: ${p.target.assetType}:${p.target.data.name} v${p.target.data.version}, registry has v${p.latestVersion}`);
528
- return {
529
- ...state,
530
- errorMessage: `--bump <patch|minor|major> required: these manifests are not newer than the registry:\n${lines.join('\n')}`,
531
- phase: 'error',
532
- };
533
- }
534
- }
535
- const index = state.entries.findIndex((entry) => entry.versionCheck?.status === 'needs-bump' && entry.resolvedVersion === undefined);
536
- const entry = state.entries[index];
537
- if (entry?.versionCheck?.status !== 'needs-bump') {
538
- return { ...state, bumpEntry: undefined, phase: 'building-plan' };
539
- }
540
- if (!state.nonInteractive) {
541
- return { ...state, bumpEntry: index, bumpSelection: '', phase: 'bump-prompt' };
542
- }
543
- const { latestVersion } = entry.versionCheck;
544
- if (!state.flags.bump) {
545
- return {
546
- ...state,
547
- errorMessage: `--bump <patch|minor|major> required: registry has v${latestVersion} of ${entry.target.assetType}:${entry.target.data.name} (from ${entry.label}) but its manifest is not newer`,
548
- phase: 'error',
549
- };
550
- }
551
- return bumpEntryAt(state, index, state.flags.bump);
552
- }
553
- /**
554
- * Bump the entry at `index` from its registry version, then go on toward the
555
- * plan; an error state, as for the root, when the version can't be bumped.
556
- */
557
- function bumpEntryAt(state, index, bump) {
558
- const entry = state.entries[index];
559
- if (entry?.versionCheck?.status !== 'needs-bump')
560
- return state;
561
- let version;
562
- try {
563
- version = bumpVersion(entry.versionCheck.latestVersion, bump);
564
- }
565
- catch {
566
- return { ...state, errorMessage: `Failed to compute bumped version for ${entry.label}.`, phase: 'error' };
567
- }
568
- return advanceToPlan({ ...state, entries: replaceEntry(state.entries, index, withVersion(entry, version)) });
569
- }
570
- /**
571
- * Phase to enter once the tags/tools metadata prompts are resolved: org-scoped
572
- * targets get the reviewer prompt, everything else proceeds to the registry check.
573
- */
574
- function phaseAfterMetadata(target) {
575
- return target && isOrgScopedTarget(target) ? 'prompting-reviewer' : 'checking-registry';
576
- }
577
- function replaceEntry(entries, index, entry) {
578
- return entries.map((current, i) => (i === index ? entry : current));
579
- }
580
- /** The entry published at `version`; a successful publish writes it to the entry's manifest. */
581
- function withVersion(entry, version) {
582
- return {
583
- ...entry,
584
- resolvedVersion: version,
585
- target: { ...entry.target, data: { ...entry.target.data, version } },
69
+ const input = {
70
+ onChange: (text) => {
71
+ typed.current = text;
72
+ setEdit({ for: state, text });
73
+ },
74
+ onSubmit: () => {
75
+ const resolve = answer.current;
76
+ answer.current = undefined;
77
+ resolve?.(typed.current);
78
+ },
79
+ value: edit?.for === state ? edit.text : promptValue(state),
80
+ };
81
+ const pick = (action) => {
82
+ ticked.current = toolPickerReducer(ticked.current, action);
83
+ setPicker(ticked.current);
84
+ };
85
+ const count = state.toolAdapters.length;
86
+ const toolPicker = {
87
+ ...picker,
88
+ confirm: () => {
89
+ if (ticked.current.selected.length === 0)
90
+ return;
91
+ const resolve = answerTools.current;
92
+ answerTools.current = undefined;
93
+ resolve?.(ticked.current.selected);
94
+ },
95
+ down: () => pick({ count, type: 'TOOL_CURSOR_DOWN' }),
96
+ toggle: () => {
97
+ const tool = state.toolAdapters[ticked.current.cursor]?.tool;
98
+ if (tool)
99
+ pick({ tool, type: 'TOGGLE_PROMPT_TOOL' });
100
+ },
101
+ up: () => pick({ count, type: 'TOOL_CURSOR_UP' }),
586
102
  };
103
+ return { input, picker: toolPicker, state };
587
104
  }
588
105
  //# sourceMappingURL=usePublishState.js.map