@superlayer/cli 1.0.67

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 (329) hide show
  1. package/LICENSE.md +202 -0
  2. package/NOTICE +4 -0
  3. package/README.md +67 -0
  4. package/bin/index.js +3 -0
  5. package/dist/auth/index.d.ts +4 -0
  6. package/dist/auth/index.d.ts.map +1 -0
  7. package/dist/auth/index.js +103 -0
  8. package/dist/auth/index.js.map +1 -0
  9. package/dist/commands/app/delete.d.ts +7 -0
  10. package/dist/commands/app/delete.d.ts.map +1 -0
  11. package/dist/commands/app/delete.js +57 -0
  12. package/dist/commands/app/delete.js.map +1 -0
  13. package/dist/commands/app/list.d.ts +6 -0
  14. package/dist/commands/app/list.d.ts.map +1 -0
  15. package/dist/commands/app/list.js +29 -0
  16. package/dist/commands/app/list.js.map +1 -0
  17. package/dist/commands/auth/client/add.d.ts +9 -0
  18. package/dist/commands/auth/client/add.d.ts.map +1 -0
  19. package/dist/commands/auth/client/add.js +409 -0
  20. package/dist/commands/auth/client/add.js.map +1 -0
  21. package/dist/commands/auth/client/delete.d.ts +11 -0
  22. package/dist/commands/auth/client/delete.d.ts.map +1 -0
  23. package/dist/commands/auth/client/delete.js +48 -0
  24. package/dist/commands/auth/client/delete.js.map +1 -0
  25. package/dist/commands/auth/client/list.d.ts +6 -0
  26. package/dist/commands/auth/client/list.d.ts.map +1 -0
  27. package/dist/commands/auth/client/list.js +38 -0
  28. package/dist/commands/auth/client/list.js.map +1 -0
  29. package/dist/commands/auth/client/shared.d.ts +70 -0
  30. package/dist/commands/auth/client/shared.d.ts.map +1 -0
  31. package/dist/commands/auth/client/shared.js +140 -0
  32. package/dist/commands/auth/client/shared.js.map +1 -0
  33. package/dist/commands/auth/client/update.d.ts +8 -0
  34. package/dist/commands/auth/client/update.d.ts.map +1 -0
  35. package/dist/commands/auth/client/update.js +445 -0
  36. package/dist/commands/auth/client/update.js.map +1 -0
  37. package/dist/commands/auth/email/pull.d.ts +24 -0
  38. package/dist/commands/auth/email/pull.d.ts.map +1 -0
  39. package/dist/commands/auth/email/pull.js +100 -0
  40. package/dist/commands/auth/email/pull.js.map +1 -0
  41. package/dist/commands/auth/email/push.d.ts +8 -0
  42. package/dist/commands/auth/email/push.d.ts.map +1 -0
  43. package/dist/commands/auth/email/push.js +58 -0
  44. package/dist/commands/auth/email/push.js.map +1 -0
  45. package/dist/commands/auth/email/resend.d.ts +3 -0
  46. package/dist/commands/auth/email/resend.d.ts.map +1 -0
  47. package/dist/commands/auth/email/resend.js +7 -0
  48. package/dist/commands/auth/email/resend.js.map +1 -0
  49. package/dist/commands/auth/email/reset.d.ts +5 -0
  50. package/dist/commands/auth/email/reset.d.ts.map +1 -0
  51. package/dist/commands/auth/email/reset.js +25 -0
  52. package/dist/commands/auth/email/reset.js.map +1 -0
  53. package/dist/commands/auth/email/status.d.ts +57 -0
  54. package/dist/commands/auth/email/status.d.ts.map +1 -0
  55. package/dist/commands/auth/email/status.js +96 -0
  56. package/dist/commands/auth/email/status.js.map +1 -0
  57. package/dist/commands/auth/email/verify.d.ts +5 -0
  58. package/dist/commands/auth/email/verify.d.ts.map +1 -0
  59. package/dist/commands/auth/email/verify.js +12 -0
  60. package/dist/commands/auth/email/verify.js.map +1 -0
  61. package/dist/commands/auth/origin/add.d.ts +12 -0
  62. package/dist/commands/auth/origin/add.d.ts.map +1 -0
  63. package/dist/commands/auth/origin/add.js +153 -0
  64. package/dist/commands/auth/origin/add.js.map +1 -0
  65. package/dist/commands/auth/origin/delete.d.ts +8 -0
  66. package/dist/commands/auth/origin/delete.d.ts.map +1 -0
  67. package/dist/commands/auth/origin/delete.js +38 -0
  68. package/dist/commands/auth/origin/delete.js.map +1 -0
  69. package/dist/commands/auth/origin/list.d.ts +9 -0
  70. package/dist/commands/auth/origin/list.d.ts.map +1 -0
  71. package/dist/commands/auth/origin/list.js +52 -0
  72. package/dist/commands/auth/origin/list.js.map +1 -0
  73. package/dist/commands/backup/download.d.ts +10 -0
  74. package/dist/commands/backup/download.d.ts.map +1 -0
  75. package/dist/commands/backup/download.js +174 -0
  76. package/dist/commands/backup/download.js.map +1 -0
  77. package/dist/commands/backup/list.d.ts +11 -0
  78. package/dist/commands/backup/list.d.ts.map +1 -0
  79. package/dist/commands/backup/list.js +74 -0
  80. package/dist/commands/backup/list.js.map +1 -0
  81. package/dist/commands/claim.d.ts +6 -0
  82. package/dist/commands/claim.d.ts.map +1 -0
  83. package/dist/commands/claim.js +22 -0
  84. package/dist/commands/claim.js.map +1 -0
  85. package/dist/commands/explorer.d.ts +6 -0
  86. package/dist/commands/explorer.d.ts.map +1 -0
  87. package/dist/commands/explorer.js +13 -0
  88. package/dist/commands/explorer.js.map +1 -0
  89. package/dist/commands/info.d.ts +9 -0
  90. package/dist/commands/info.d.ts.map +1 -0
  91. package/dist/commands/info.js +41 -0
  92. package/dist/commands/info.js.map +1 -0
  93. package/dist/commands/init.d.ts +5 -0
  94. package/dist/commands/init.d.ts.map +1 -0
  95. package/dist/commands/init.js +41 -0
  96. package/dist/commands/init.js.map +1 -0
  97. package/dist/commands/initWithoutFiles.d.ts +6 -0
  98. package/dist/commands/initWithoutFiles.d.ts.map +1 -0
  99. package/dist/commands/initWithoutFiles.js +64 -0
  100. package/dist/commands/initWithoutFiles.js.map +1 -0
  101. package/dist/commands/login.d.ts +9 -0
  102. package/dist/commands/login.d.ts.map +1 -0
  103. package/dist/commands/login.js +44 -0
  104. package/dist/commands/login.js.map +1 -0
  105. package/dist/commands/logout.d.ts +3 -0
  106. package/dist/commands/logout.d.ts.map +1 -0
  107. package/dist/commands/logout.js +14 -0
  108. package/dist/commands/logout.js.map +1 -0
  109. package/dist/commands/pull.d.ts +5 -0
  110. package/dist/commands/pull.d.ts.map +1 -0
  111. package/dist/commands/pull.js +15 -0
  112. package/dist/commands/pull.js.map +1 -0
  113. package/dist/commands/push.d.ts +6 -0
  114. package/dist/commands/push.d.ts.map +1 -0
  115. package/dist/commands/push.js +20 -0
  116. package/dist/commands/push.js.map +1 -0
  117. package/dist/commands/query.d.ts +7 -0
  118. package/dist/commands/query.d.ts.map +1 -0
  119. package/dist/commands/query.js +52 -0
  120. package/dist/commands/query.js.map +1 -0
  121. package/dist/commands/webhooks/add.d.ts +9 -0
  122. package/dist/commands/webhooks/add.d.ts.map +1 -0
  123. package/dist/commands/webhooks/add.js +75 -0
  124. package/dist/commands/webhooks/add.js.map +1 -0
  125. package/dist/commands/webhooks/delete.d.ts +6 -0
  126. package/dist/commands/webhooks/delete.d.ts.map +1 -0
  127. package/dist/commands/webhooks/delete.js +17 -0
  128. package/dist/commands/webhooks/delete.js.map +1 -0
  129. package/dist/commands/webhooks/disable.d.ts +7 -0
  130. package/dist/commands/webhooks/disable.d.ts.map +1 -0
  131. package/dist/commands/webhooks/disable.js +18 -0
  132. package/dist/commands/webhooks/disable.js.map +1 -0
  133. package/dist/commands/webhooks/enable.d.ts +6 -0
  134. package/dist/commands/webhooks/enable.d.ts.map +1 -0
  135. package/dist/commands/webhooks/enable.js +18 -0
  136. package/dist/commands/webhooks/enable.js.map +1 -0
  137. package/dist/commands/webhooks/events/list.d.ts +7 -0
  138. package/dist/commands/webhooks/events/list.d.ts.map +1 -0
  139. package/dist/commands/webhooks/events/list.js +31 -0
  140. package/dist/commands/webhooks/events/list.js.map +1 -0
  141. package/dist/commands/webhooks/events/payload.d.ts +8 -0
  142. package/dist/commands/webhooks/events/payload.d.ts.map +1 -0
  143. package/dist/commands/webhooks/events/payload.js +39 -0
  144. package/dist/commands/webhooks/events/payload.js.map +1 -0
  145. package/dist/commands/webhooks/events/resend.d.ts +8 -0
  146. package/dist/commands/webhooks/events/resend.d.ts.map +1 -0
  147. package/dist/commands/webhooks/events/resend.js +43 -0
  148. package/dist/commands/webhooks/events/resend.js.map +1 -0
  149. package/dist/commands/webhooks/list.d.ts +8 -0
  150. package/dist/commands/webhooks/list.d.ts.map +1 -0
  151. package/dist/commands/webhooks/list.js +29 -0
  152. package/dist/commands/webhooks/list.js.map +1 -0
  153. package/dist/commands/webhooks/shared.d.ts +40 -0
  154. package/dist/commands/webhooks/shared.d.ts.map +1 -0
  155. package/dist/commands/webhooks/shared.js +248 -0
  156. package/dist/commands/webhooks/shared.js.map +1 -0
  157. package/dist/commands/webhooks/update.d.ts +10 -0
  158. package/dist/commands/webhooks/update.d.ts.map +1 -0
  159. package/dist/commands/webhooks/update.js +189 -0
  160. package/dist/commands/webhooks/update.js.map +1 -0
  161. package/dist/context/authToken.d.ts +29 -0
  162. package/dist/context/authToken.d.ts.map +1 -0
  163. package/dist/context/authToken.js +73 -0
  164. package/dist/context/authToken.js.map +1 -0
  165. package/dist/context/currentApp.d.ts +38 -0
  166. package/dist/context/currentApp.d.ts.map +1 -0
  167. package/dist/context/currentApp.js +222 -0
  168. package/dist/context/currentApp.js.map +1 -0
  169. package/dist/context/globalOpts.d.ts +11 -0
  170. package/dist/context/globalOpts.d.ts.map +1 -0
  171. package/dist/context/globalOpts.js +13 -0
  172. package/dist/context/globalOpts.js.map +1 -0
  173. package/dist/context/platformApi.d.ts +19 -0
  174. package/dist/context/platformApi.d.ts.map +1 -0
  175. package/dist/context/platformApi.js +24 -0
  176. package/dist/context/platformApi.js.map +1 -0
  177. package/dist/context/projectInfo.d.ts +30 -0
  178. package/dist/context/projectInfo.d.ts.map +1 -0
  179. package/dist/context/projectInfo.js +152 -0
  180. package/dist/context/projectInfo.js.map +1 -0
  181. package/dist/errors.d.ts +10 -0
  182. package/dist/errors.d.ts.map +1 -0
  183. package/dist/errors.js +6 -0
  184. package/dist/errors.js.map +1 -0
  185. package/dist/index.d.ts +159 -0
  186. package/dist/index.d.ts.map +1 -0
  187. package/dist/index.js +714 -0
  188. package/dist/index.js.map +1 -0
  189. package/dist/layer.d.ts +25 -0
  190. package/dist/layer.d.ts.map +1 -0
  191. package/dist/layer.js +119 -0
  192. package/dist/layer.js.map +1 -0
  193. package/dist/lib/args.d.ts +212 -0
  194. package/dist/lib/args.d.ts.map +1 -0
  195. package/dist/lib/args.js +313 -0
  196. package/dist/lib/args.js.map +1 -0
  197. package/dist/lib/backupDownload.d.ts +21 -0
  198. package/dist/lib/backupDownload.d.ts.map +1 -0
  199. package/dist/lib/backupDownload.js +151 -0
  200. package/dist/lib/backupDownload.js.map +1 -0
  201. package/dist/lib/backups.d.ts +12 -0
  202. package/dist/lib/backups.d.ts.map +1 -0
  203. package/dist/lib/backups.js +26 -0
  204. package/dist/lib/backups.js.map +1 -0
  205. package/dist/lib/config.d.ts +6 -0
  206. package/dist/lib/config.d.ts.map +1 -0
  207. package/dist/lib/config.js +39 -0
  208. package/dist/lib/config.js.map +1 -0
  209. package/dist/lib/createApp.d.ts +12 -0
  210. package/dist/lib/createApp.d.ts.map +1 -0
  211. package/dist/lib/createApp.js +15 -0
  212. package/dist/lib/createApp.js.map +1 -0
  213. package/dist/lib/email.d.ts +47 -0
  214. package/dist/lib/email.d.ts.map +1 -0
  215. package/dist/lib/email.js +71 -0
  216. package/dist/lib/email.js.map +1 -0
  217. package/dist/lib/handleEnv.d.ts +7 -0
  218. package/dist/lib/handleEnv.d.ts.map +1 -0
  219. package/dist/lib/handleEnv.js +99 -0
  220. package/dist/lib/handleEnv.js.map +1 -0
  221. package/dist/lib/http.d.ts +30 -0
  222. package/dist/lib/http.d.ts.map +1 -0
  223. package/dist/lib/http.js +55 -0
  224. package/dist/lib/http.js.map +1 -0
  225. package/dist/lib/login.d.ts +12 -0
  226. package/dist/lib/login.d.ts.map +1 -0
  227. package/dist/lib/login.js +38 -0
  228. package/dist/lib/login.js.map +1 -0
  229. package/dist/lib/oauth.d.ts +306 -0
  230. package/dist/lib/oauth.d.ts.map +1 -0
  231. package/dist/lib/oauth.js +195 -0
  232. package/dist/lib/oauth.js.map +1 -0
  233. package/dist/lib/platformApi.d.ts +5 -0
  234. package/dist/lib/platformApi.d.ts.map +1 -0
  235. package/dist/lib/platformApi.js +11 -0
  236. package/dist/lib/platformApi.js.map +1 -0
  237. package/dist/lib/pullPerms.d.ts +7 -0
  238. package/dist/lib/pullPerms.d.ts.map +1 -0
  239. package/dist/lib/pullPerms.js +41 -0
  240. package/dist/lib/pullPerms.js.map +1 -0
  241. package/dist/lib/pullSchema.d.ts +12 -0
  242. package/dist/lib/pullSchema.d.ts.map +1 -0
  243. package/dist/lib/pullSchema.js +62 -0
  244. package/dist/lib/pullSchema.js.map +1 -0
  245. package/dist/lib/pushPerms.d.ts +13 -0
  246. package/dist/lib/pushPerms.d.ts.map +1 -0
  247. package/dist/lib/pushPerms.js +54 -0
  248. package/dist/lib/pushPerms.js.map +1 -0
  249. package/dist/lib/pushSchema.d.ts +53 -0
  250. package/dist/lib/pushSchema.d.ts.map +1 -0
  251. package/dist/lib/pushSchema.js +165 -0
  252. package/dist/lib/pushSchema.js.map +1 -0
  253. package/dist/lib/ui.d.ts +18 -0
  254. package/dist/lib/ui.d.ts.map +1 -0
  255. package/dist/lib/ui.js +32 -0
  256. package/dist/lib/ui.js.map +1 -0
  257. package/dist/lib/webhooks.d.ts +27 -0
  258. package/dist/lib/webhooks.d.ts.map +1 -0
  259. package/dist/lib/webhooks.js +95 -0
  260. package/dist/lib/webhooks.js.map +1 -0
  261. package/dist/logging.d.ts +5 -0
  262. package/dist/logging.d.ts.map +1 -0
  263. package/dist/logging.js +25 -0
  264. package/dist/logging.js.map +1 -0
  265. package/dist/old.d.ts +17 -0
  266. package/dist/old.d.ts.map +1 -0
  267. package/dist/old.js +410 -0
  268. package/dist/old.js.map +1 -0
  269. package/dist/program.d.ts +3 -0
  270. package/dist/program.d.ts.map +1 -0
  271. package/dist/program.js +3 -0
  272. package/dist/program.js.map +1 -0
  273. package/dist/renderSchemaPlan.d.ts +19 -0
  274. package/dist/renderSchemaPlan.d.ts.map +1 -0
  275. package/dist/renderSchemaPlan.js +220 -0
  276. package/dist/renderSchemaPlan.js.map +1 -0
  277. package/dist/ui/index.d.ts +292 -0
  278. package/dist/ui/index.d.ts.map +1 -0
  279. package/dist/ui/index.js +1296 -0
  280. package/dist/ui/index.js.map +1 -0
  281. package/dist/ui/lib.d.ts +124 -0
  282. package/dist/ui/lib.d.ts.map +1 -0
  283. package/dist/ui/lib.js +333 -0
  284. package/dist/ui/lib.js.map +1 -0
  285. package/dist/util/findConfigCandidates.d.ts +13 -0
  286. package/dist/util/findConfigCandidates.d.ts.map +1 -0
  287. package/dist/util/findConfigCandidates.js +211 -0
  288. package/dist/util/findConfigCandidates.js.map +1 -0
  289. package/dist/util/fs.d.ts +4 -0
  290. package/dist/util/fs.d.ts.map +1 -0
  291. package/dist/util/fs.js +22 -0
  292. package/dist/util/fs.js.map +1 -0
  293. package/dist/util/getAppName.d.ts +5 -0
  294. package/dist/util/getAppName.d.ts.map +1 -0
  295. package/dist/util/getAppName.js +14 -0
  296. package/dist/util/getAppName.js.map +1 -0
  297. package/dist/util/instantConfig.d.ts +9 -0
  298. package/dist/util/instantConfig.d.ts.map +1 -0
  299. package/dist/util/instantConfig.js +13 -0
  300. package/dist/util/instantConfig.js.map +1 -0
  301. package/dist/util/isHeadlessEnvironment.d.ts +4 -0
  302. package/dist/util/isHeadlessEnvironment.d.ts.map +1 -0
  303. package/dist/util/isHeadlessEnvironment.js +11 -0
  304. package/dist/util/isHeadlessEnvironment.js.map +1 -0
  305. package/dist/util/loadConfig.d.ts +3 -0
  306. package/dist/util/loadConfig.d.ts.map +1 -0
  307. package/dist/util/loadConfig.js +72 -0
  308. package/dist/util/loadConfig.js.map +1 -0
  309. package/dist/util/loadEnv.d.ts +2 -0
  310. package/dist/util/loadEnv.d.ts.map +1 -0
  311. package/dist/util/loadEnv.js +10 -0
  312. package/dist/util/loadEnv.js.map +1 -0
  313. package/dist/util/mergeSchema.d.ts +10 -0
  314. package/dist/util/mergeSchema.d.ts.map +1 -0
  315. package/dist/util/mergeSchema.js +338 -0
  316. package/dist/util/mergeSchema.js.map +1 -0
  317. package/dist/util/projectDir.d.ts +7 -0
  318. package/dist/util/projectDir.d.ts.map +1 -0
  319. package/dist/util/projectDir.js +43 -0
  320. package/dist/util/projectDir.js.map +1 -0
  321. package/dist/util/renamePrompt.d.ts +15 -0
  322. package/dist/util/renamePrompt.d.ts.map +1 -0
  323. package/dist/util/renamePrompt.js +57 -0
  324. package/dist/util/renamePrompt.js.map +1 -0
  325. package/dist/version.d.ts +3 -0
  326. package/dist/version.d.ts.map +1 -0
  327. package/dist/version.js +3 -0
  328. package/dist/version.js.map +1 -0
  329. package/package.json +96 -0
@@ -0,0 +1,1296 @@
1
+ import chalk from 'chalk';
2
+ import boxen from 'boxen';
3
+ import stringWidth from 'string-width';
4
+ import { Prompt, SelectState } from "./lib.js";
5
+ export { clearPromptTrail, render, renderUnwrap, setRawModeWindowsFriendly, } from "./lib.js";
6
+ export var UI;
7
+ (function (UI) {
8
+ UI.modifiers = {
9
+ piped: (modifiers) => {
10
+ return (output, status) => {
11
+ return modifiers.reduce((acc, modifier) => modifier(acc, status), output);
12
+ };
13
+ },
14
+ topPadding: (output) => {
15
+ return '\n' + output;
16
+ },
17
+ yPadding: (output) => {
18
+ return '\n' + output + '\n';
19
+ },
20
+ sidelined: (symbol = '◆') => (output, status) => {
21
+ const result = [];
22
+ output.split('\n').forEach((line, idx) => {
23
+ if (idx === 1 && symbol) {
24
+ result.push(`${chalk.gray(symbol + ' ')}${line}`);
25
+ }
26
+ else {
27
+ result.push(`${chalk.gray('│ ')}${line}`);
28
+ }
29
+ });
30
+ if (status === 'idle') {
31
+ result.push(`${chalk.gray('└ ')}`);
32
+ }
33
+ let almost = result.join('\n');
34
+ if (!almost.endsWith('\n')) {
35
+ almost += '\n';
36
+ }
37
+ return almost;
38
+ },
39
+ background: (output) => {
40
+ return chalk.bgBlackBright(output);
41
+ },
42
+ dimOnComplete: (output, status) => {
43
+ if (status === 'submitted' || status === 'aborted') {
44
+ return chalk.dim(output);
45
+ }
46
+ return output;
47
+ },
48
+ vanishOnComplete: (output, status) => {
49
+ if (status === 'submitted' || status === 'aborted') {
50
+ return '';
51
+ }
52
+ return output;
53
+ },
54
+ };
55
+ UI.ciaModifier = (symbol = '◆') => UI.modifiers.piped([
56
+ UI.modifiers.topPadding,
57
+ UI.modifiers.dimOnComplete,
58
+ UI.modifiers.sidelined(symbol),
59
+ ]);
60
+ /**
61
+ * Utility that lets you use output modifiers in console.log
62
+ */
63
+ UI.log = (output, modifyOutput, ...args) => {
64
+ const finalOutput = modifyOutput ? modifyOutput(output) : output;
65
+ if (finalOutput.endsWith('\n')) {
66
+ process.stdout.write(finalOutput, ...args);
67
+ }
68
+ else {
69
+ process.stdout.write(finalOutput + '\n', ...args);
70
+ }
71
+ };
72
+ class Select extends Prompt {
73
+ config(status) {
74
+ return status;
75
+ }
76
+ data;
77
+ options;
78
+ params;
79
+ expandedIdx = null;
80
+ stickyExpanded = false;
81
+ expansionCache = new Map();
82
+ expansionLoading = new Set();
83
+ constructor(params) {
84
+ super(params.modifyOutput);
85
+ this.on('attach', (terminal) => terminal.toggleCursor('hide'));
86
+ this.on('input', (input, key) => {
87
+ if (input === 'j' || (key?.ctrl && key.name === 'n')) {
88
+ this.data.selectedIdx =
89
+ (this.data.selectedIdx + 1) % this.options.length;
90
+ this.applyNavigation();
91
+ }
92
+ else if (input === 'k' || (key?.ctrl && key.name === 'p')) {
93
+ this.data.selectedIdx =
94
+ (this.data.selectedIdx - 1 + this.options.length) %
95
+ this.options.length;
96
+ this.applyNavigation();
97
+ }
98
+ this.requestLayout();
99
+ });
100
+ this.on('detach', (terminal) => {
101
+ terminal.toggleCursor('show');
102
+ });
103
+ this.options = params.options;
104
+ this.params = params;
105
+ this.data = new SelectState(params.options.map((option) => option.value));
106
+ // Set initial selected index based on defaultValue if provided
107
+ if (params.defaultValue !== undefined) {
108
+ const defaultIndex = params.options.findIndex((option) => option.value === params.defaultValue);
109
+ if (defaultIndex !== -1) {
110
+ this.data.selectedIdx = defaultIndex;
111
+ }
112
+ }
113
+ this.data.bind(this);
114
+ this.on('input', (_input, key) => {
115
+ if (key?.name === 'tab') {
116
+ const hasExpandable = this.options.some((o) => o.expandableLabel);
117
+ if (!hasExpandable)
118
+ return;
119
+ this.stickyExpanded = !this.stickyExpanded;
120
+ if (this.stickyExpanded) {
121
+ this.expandFocused();
122
+ }
123
+ else {
124
+ this.expandedIdx = null;
125
+ }
126
+ this.requestLayout();
127
+ return;
128
+ }
129
+ if (key?.name === 'up' || key?.name === 'down') {
130
+ this.applyNavigation();
131
+ this.requestLayout();
132
+ }
133
+ });
134
+ }
135
+ applyNavigation() {
136
+ if (this.stickyExpanded) {
137
+ this.expandFocused();
138
+ }
139
+ else {
140
+ this.expandedIdx = null;
141
+ }
142
+ }
143
+ expandFocused() {
144
+ const focused = this.data.selectedIdx;
145
+ const focusedOption = this.options[focused];
146
+ const exp = focusedOption?.expandableLabel;
147
+ if (!exp) {
148
+ this.expandedIdx = null;
149
+ return;
150
+ }
151
+ this.expandedIdx = focused;
152
+ if (typeof exp === 'function' &&
153
+ !this.expansionCache.has(focused) &&
154
+ !this.expansionLoading.has(focused)) {
155
+ this.expansionLoading.add(focused);
156
+ Promise.resolve()
157
+ .then(() => exp())
158
+ .then((content) => {
159
+ this.expansionLoading.delete(focused);
160
+ this.expansionCache.set(focused, content);
161
+ if (this.expandedIdx === focused)
162
+ this.requestLayout();
163
+ }, (err) => {
164
+ this.expansionLoading.delete(focused);
165
+ this.expansionCache.set(focused, chalk.red(` Error loading expansion: ${err?.message ?? err}`));
166
+ if (this.expandedIdx === focused)
167
+ this.requestLayout();
168
+ });
169
+ }
170
+ }
171
+ getExpansionContent(option, idx) {
172
+ const exp = option.expandableLabel;
173
+ if (!exp)
174
+ return null;
175
+ if (typeof exp === 'string')
176
+ return exp;
177
+ if (this.expansionLoading.has(idx))
178
+ return chalk.dim(' Loading…');
179
+ const cached = this.expansionCache.get(idx);
180
+ return cached ?? chalk.dim(' Loading…');
181
+ }
182
+ result() {
183
+ return this.data.items[this.data.selectedIdx];
184
+ }
185
+ render(status) {
186
+ if (status === 'submitted') {
187
+ return `${this.params.promptText}
188
+ ${chalk.hex('#EA570B').bold('●')} ${this.params.options[this.data.selectedIdx]?.label}`;
189
+ }
190
+ const renderRow = (option, originalIdx) => {
191
+ const isSelected = originalIdx === this.data.selectedIdx;
192
+ const cursor = isSelected ? chalk.hex('#EA570B').bold('●') : '○';
193
+ const label = isSelected
194
+ ? chalk.bold(option.label)
195
+ : chalk.dim(option.label);
196
+ const expandedContent = isSelected && this.expandedIdx === originalIdx
197
+ ? this.getExpansionContent(option, originalIdx)
198
+ : null;
199
+ const expanded = expandedContent !== null ? '\n' + expandedContent : '';
200
+ return `${cursor} ${label}${expanded}`;
201
+ };
202
+ const rowLineCount = (originalIdx) => {
203
+ const opt = this.options[originalIdx];
204
+ const labelLines = opt.label.split('\n').length;
205
+ const isFocused = originalIdx === this.data.selectedIdx;
206
+ const expContent = isFocused && this.expandedIdx === originalIdx
207
+ ? this.getExpansionContent(opt, originalIdx)
208
+ : null;
209
+ const expLines = expContent !== null ? expContent.split('\n').length : 0;
210
+ return labelLines + expLines;
211
+ };
212
+ const mainEntries = [];
213
+ const secondaryEntries = [];
214
+ this.options.forEach((o, i) => {
215
+ if (o.secondary)
216
+ secondaryEntries.push({ opt: o, originalIdx: i });
217
+ else
218
+ mainEntries.push({ opt: o, originalIdx: i });
219
+ });
220
+ const totalRows = process.stdout.rows ?? 24;
221
+ const secondaryHeight = secondaryEntries.length === 0
222
+ ? 0
223
+ : secondaryEntries.reduce((acc, { originalIdx }) => acc + rowLineCount(originalIdx), 0) + 1; // +1 for divider
224
+ const hasExpandable = this.options.some((o) => o.expandableLabel);
225
+ // chrome = prompt(1) + secondaries(+divider) + hint + safety(2)
226
+ const chrome = 1 + secondaryHeight + (hasExpandable ? 1 : 0) + 2;
227
+ const mainBudget = Math.max(3, totalRows - chrome);
228
+ const focusedMainPos = mainEntries.findIndex((e) => e.originalIdx === this.data.selectedIdx);
229
+ let visiblePositions = [];
230
+ if (focusedMainPos >= 0) {
231
+ let used = rowLineCount(mainEntries[focusedMainPos].originalIdx);
232
+ visiblePositions = [focusedMainPos];
233
+ let lo = focusedMainPos - 1;
234
+ let hi = focusedMainPos + 1;
235
+ while (lo >= 0 || hi < mainEntries.length) {
236
+ let progressed = false;
237
+ if (lo >= 0) {
238
+ const h = rowLineCount(mainEntries[lo].originalIdx);
239
+ if (used + h <= mainBudget) {
240
+ visiblePositions.unshift(lo);
241
+ used += h;
242
+ lo--;
243
+ progressed = true;
244
+ }
245
+ else {
246
+ lo = -1;
247
+ }
248
+ }
249
+ if (hi < mainEntries.length) {
250
+ const h = rowLineCount(mainEntries[hi].originalIdx);
251
+ if (used + h <= mainBudget) {
252
+ visiblePositions.push(hi);
253
+ used += h;
254
+ hi++;
255
+ progressed = true;
256
+ }
257
+ else {
258
+ hi = mainEntries.length;
259
+ }
260
+ }
261
+ if (!progressed)
262
+ break;
263
+ }
264
+ }
265
+ else {
266
+ // Cursor is on a secondary — show as many mains as fit, top-down.
267
+ let used = 0;
268
+ for (let i = 0; i < mainEntries.length; i++) {
269
+ const h = rowLineCount(mainEntries[i].originalIdx);
270
+ if (used + h > mainBudget)
271
+ break;
272
+ visiblePositions.push(i);
273
+ used += h;
274
+ }
275
+ }
276
+ const firstVisible = visiblePositions[0] ?? 0;
277
+ const lastVisible = visiblePositions[visiblePositions.length - 1] ?? mainEntries.length - 1;
278
+ const aboveCount = firstVisible;
279
+ const belowCount = Math.max(0, mainEntries.length - 1 - lastVisible);
280
+ const mainLines = [];
281
+ if (aboveCount > 0)
282
+ mainLines.push(chalk.dim(` ↑ ${aboveCount} more`));
283
+ for (const pos of visiblePositions) {
284
+ mainLines.push(renderRow(mainEntries[pos].opt, mainEntries[pos].originalIdx));
285
+ }
286
+ if (belowCount > 0)
287
+ mainLines.push(chalk.dim(` ↓ ${belowCount} more`));
288
+ const mainBlock = mainLines.join('\n');
289
+ const secondaryBlock = secondaryEntries.length === 0
290
+ ? ''
291
+ : chalk.gray('\n───────────────── Additional Options ─────────────────\n') +
292
+ secondaryEntries
293
+ .map((e) => renderRow(e.opt, e.originalIdx))
294
+ .join('\n');
295
+ const expandHint = hasExpandable
296
+ ? '\n' +
297
+ chalk.dim(this.stickyExpanded ? ' (tab to collapse)' : ' (tab to expand)')
298
+ : '';
299
+ return `${this.params.promptText}
300
+ ${mainBlock}${secondaryBlock}${expandHint}`;
301
+ }
302
+ }
303
+ UI.Select = Select;
304
+ const DEFAULT_MULTI_SELECT_PAGE_SIZE = 10;
305
+ const defaultMultiSelectFilter = (filter, option) => option.label.toLowerCase().includes(filter.toLowerCase());
306
+ class MultiSelect extends Prompt {
307
+ filterText = '';
308
+ cursorIdx = 0;
309
+ windowStart = 0;
310
+ selected;
311
+ errorText;
312
+ props;
313
+ pageSize;
314
+ constructor(props) {
315
+ super(props.modifyOutput);
316
+ this.props = props;
317
+ this.pageSize = props.pageSize ?? DEFAULT_MULTI_SELECT_PAGE_SIZE;
318
+ this.selected = new Set((props.initialSelected ?? [])
319
+ .map((v) => props.options.findIndex((o) => o.value === v))
320
+ .filter((i) => i >= 0));
321
+ this.on('attach', (terminal) => {
322
+ terminal.setAllowInteraction(false);
323
+ terminal.toggleCursor('hide');
324
+ });
325
+ this.on('detach', (terminal) => terminal.toggleCursor('show'));
326
+ this.on('input', (input, key) => this.handleKey(input, key));
327
+ }
328
+ visibleIndices() {
329
+ const fn = this.props.filter ?? defaultMultiSelectFilter;
330
+ if (!this.filterText)
331
+ return this.props.options.map((_, i) => i);
332
+ return this.props.options
333
+ .map((opt, i) => ({ opt, i }))
334
+ .filter(({ opt }) => fn(this.filterText, opt))
335
+ .map(({ i }) => i);
336
+ }
337
+ clampCursor(visible) {
338
+ if (visible.length === 0) {
339
+ this.cursorIdx = 0;
340
+ }
341
+ else if (this.cursorIdx >= visible.length) {
342
+ this.cursorIdx = visible.length - 1;
343
+ }
344
+ else if (this.cursorIdx < 0) {
345
+ this.cursorIdx = visible.length - 1;
346
+ }
347
+ }
348
+ adjustWindow(visible) {
349
+ if (visible.length <= this.pageSize) {
350
+ this.windowStart = 0;
351
+ return;
352
+ }
353
+ if (this.cursorIdx < this.windowStart) {
354
+ this.windowStart = this.cursorIdx;
355
+ }
356
+ else if (this.cursorIdx >= this.windowStart + this.pageSize) {
357
+ this.windowStart = this.cursorIdx - this.pageSize + 1;
358
+ }
359
+ const maxStart = Math.max(0, visible.length - this.pageSize);
360
+ if (this.windowStart > maxStart)
361
+ this.windowStart = maxStart;
362
+ if (this.windowStart < 0)
363
+ this.windowStart = 0;
364
+ }
365
+ handleKey(input, key) {
366
+ if (key.name === 'escape') {
367
+ return this.terminal?.resolve({ data: undefined, status: 'aborted' });
368
+ }
369
+ if (key.name === 'return') {
370
+ const min = this.props.minSelected ?? 0;
371
+ if (this.selected.size < min) {
372
+ this.errorText =
373
+ min === 1
374
+ ? 'Select at least one option.'
375
+ : `Select at least ${min} options.`;
376
+ this.requestLayout();
377
+ return;
378
+ }
379
+ return this.terminal?.resolve({
380
+ data: this.result(),
381
+ status: 'submitted',
382
+ });
383
+ }
384
+ const visible = this.visibleIndices();
385
+ if (key.name === 'up' || (key.ctrl && key.name === 'p')) {
386
+ this.cursorIdx -= 1;
387
+ this.clampCursor(visible);
388
+ this.adjustWindow(visible);
389
+ this.requestLayout();
390
+ return;
391
+ }
392
+ if (key.name === 'down' || (key.ctrl && key.name === 'n')) {
393
+ this.cursorIdx += 1;
394
+ if (visible.length > 0)
395
+ this.cursorIdx %= visible.length;
396
+ this.adjustWindow(visible);
397
+ this.requestLayout();
398
+ return;
399
+ }
400
+ if (key.name === 'pageup' || (key.ctrl && key.name === 'u')) {
401
+ this.cursorIdx -= this.pageSize;
402
+ if (this.cursorIdx < 0)
403
+ this.cursorIdx = 0;
404
+ this.adjustWindow(visible);
405
+ this.requestLayout();
406
+ return;
407
+ }
408
+ if (key.name === 'pagedown' || (key.ctrl && key.name === 'd')) {
409
+ this.cursorIdx += this.pageSize;
410
+ if (this.cursorIdx >= visible.length) {
411
+ this.cursorIdx = Math.max(0, visible.length - 1);
412
+ }
413
+ this.adjustWindow(visible);
414
+ this.requestLayout();
415
+ return;
416
+ }
417
+ if (key.name === 'space') {
418
+ if (visible.length === 0)
419
+ return;
420
+ const optIdx = visible[this.cursorIdx];
421
+ if (this.selected.has(optIdx)) {
422
+ this.selected.delete(optIdx);
423
+ }
424
+ else {
425
+ this.selected.add(optIdx);
426
+ }
427
+ this.errorText = undefined;
428
+ this.requestLayout();
429
+ return;
430
+ }
431
+ if (key.name === 'backspace') {
432
+ if (this.filterText.length > 0) {
433
+ this.filterText = this.filterText.slice(0, -1);
434
+ this.cursorIdx = 0;
435
+ this.windowStart = 0;
436
+ this.requestLayout();
437
+ }
438
+ return;
439
+ }
440
+ if (key.name?.length === 1 && !key.ctrl && !key.meta && input) {
441
+ this.filterText += input;
442
+ this.cursorIdx = 0;
443
+ this.windowStart = 0;
444
+ this.requestLayout();
445
+ }
446
+ }
447
+ result() {
448
+ return [...this.selected]
449
+ .sort((a, b) => a - b)
450
+ .map((i) => this.props.options[i].value);
451
+ }
452
+ renderOption(optIdx, isCursor) {
453
+ const option = this.props.options[optIdx];
454
+ const isSelected = this.selected.has(optIdx);
455
+ const checkbox = isSelected ? chalk.green('◉') : '○';
456
+ const cursorMark = isCursor ? chalk.hex('#EA570B').bold('❯') : ' ';
457
+ const label = isCursor ? chalk.bold(option.label) : option.label;
458
+ return `${cursorMark} ${checkbox} ${label}`;
459
+ }
460
+ render(status) {
461
+ if (status === 'submitted') {
462
+ const labels = [...this.selected]
463
+ .sort((a, b) => a - b)
464
+ .map((i) => this.props.options[i].label);
465
+ return `${this.props.promptText}
466
+ ${chalk.hex('#EA570B').bold('●')} ${labels.length === 0 ? chalk.dim('(none)') : labels.join(', ')}`;
467
+ }
468
+ const visible = this.visibleIndices();
469
+ this.adjustWindow(visible);
470
+ const filterLine = `${chalk.dim('filter:')} ${this.filterText}${chalk.inverse(' ')}`;
471
+ const errorLine = this.errorText ? ` ${chalk.red(this.errorText)}` : '';
472
+ let optionsBlock;
473
+ if (visible.length === 0) {
474
+ optionsBlock = chalk.dim(' (no matches)');
475
+ }
476
+ else {
477
+ const windowEnd = Math.min(this.windowStart + this.pageSize, visible.length);
478
+ const aboveCount = this.windowStart;
479
+ const belowCount = visible.length - windowEnd;
480
+ const lines = [];
481
+ lines.push(aboveCount > 0
482
+ ? chalk.dim(` ↑ ${aboveCount} more`)
483
+ : chalk.dim(' '));
484
+ for (let i = this.windowStart; i < windowEnd; i++) {
485
+ lines.push(this.renderOption(visible[i], i === this.cursorIdx));
486
+ }
487
+ lines.push(belowCount > 0
488
+ ? chalk.dim(` ↓ ${belowCount} more`)
489
+ : chalk.dim(' '));
490
+ optionsBlock = lines.join('\n');
491
+ }
492
+ const hint = chalk.dim(` ↑↓ or ctrl-n/p navigate · pgup/pgdn or ctrl-u/d page · space toggle · enter submit · esc cancel`);
493
+ const counts = chalk.dim(` ${visible.length} of ${this.props.options.length} shown · ${this.selected.size} selected`);
494
+ return `${this.props.promptText}${errorLine}
495
+ ${filterLine}
496
+ ${optionsBlock}
497
+ ${counts}
498
+ ${hint}`;
499
+ }
500
+ }
501
+ UI.MultiSelect = MultiSelect;
502
+ /**
503
+ * @deprecated use the modifyOutput prop instead
504
+ * left as an example of how to do wrapper prompts
505
+ */
506
+ class Sidelined extends Prompt {
507
+ result() {
508
+ return this.inner.result();
509
+ }
510
+ render(status) {
511
+ return (this.inner
512
+ .render(status)
513
+ .split('\n')
514
+ .map((line) => `${chalk.gray(' │ ')}${line}`)
515
+ .join('\n') + '\n');
516
+ }
517
+ config(status) {
518
+ return status;
519
+ }
520
+ inner;
521
+ constructor(inner) {
522
+ super();
523
+ this.inner = inner;
524
+ this.on('input', (input, arg2) => {
525
+ this.inner.input(input, arg2);
526
+ this.requestLayout();
527
+ });
528
+ this.on('detach', (terminal) => {
529
+ this.inner.detach(terminal);
530
+ });
531
+ this.on('attach', (terminal) => {
532
+ this.inner.attach(terminal);
533
+ });
534
+ }
535
+ }
536
+ UI.Sidelined = Sidelined;
537
+ class TextInput extends Prompt {
538
+ result() {
539
+ return this.value;
540
+ }
541
+ render(status) {
542
+ const value = this.props.sensitive
543
+ ? '*'.repeat(this.value.length)
544
+ : this.value;
545
+ if (status === 'submitted') {
546
+ return `${this.props.prompt}
547
+ ${value}`;
548
+ }
549
+ if (status === 'aborted') {
550
+ return `${this.props.prompt} ${value} (CANCELLED)\n`;
551
+ }
552
+ let inputDisplay = '';
553
+ if (value === '') {
554
+ inputDisplay = this.props.placeholder
555
+ ? `${chalk.inverse(this.props.placeholder.substring(0, 1))}${chalk.dim(this.props.placeholder.substring(1))}`
556
+ : chalk.inverse(' ');
557
+ }
558
+ else {
559
+ inputDisplay = `${value}${chalk.inverse(' ')}`;
560
+ }
561
+ const errorText = this.errorText
562
+ ? ` ${chalk.red(this.errorText)}`
563
+ : '';
564
+ return `${this.props.prompt}${errorText}
565
+ ${inputDisplay}`;
566
+ }
567
+ value;
568
+ errorText;
569
+ props;
570
+ constructor(props) {
571
+ super(props.modifyOutput);
572
+ this.on('attach', (terminal) => {
573
+ terminal.setAllowInteraction(false); // needed for validation
574
+ terminal.toggleCursor('hide');
575
+ });
576
+ this.on('detach', (terminal) => {
577
+ terminal.toggleCursor('show');
578
+ });
579
+ this.on('input', (input, keyInfo) => {
580
+ if (keyInfo.name === 'escape') {
581
+ if (!this.props.headless) {
582
+ return this?.terminal?.resolve({
583
+ data: undefined,
584
+ status: 'aborted',
585
+ });
586
+ }
587
+ }
588
+ if (keyInfo.name === 'tab') {
589
+ if (this.value === '' &&
590
+ this.props.defaultValue &&
591
+ this.props.placeholder === this.props.defaultValue) {
592
+ this.value = this.props.defaultValue;
593
+ this.requestLayout();
594
+ }
595
+ return;
596
+ }
597
+ if (keyInfo.name === 'return') {
598
+ if (this.value === '' && this.props.defaultValue) {
599
+ this.value = this.props.defaultValue;
600
+ return this.terminal?.resolve({
601
+ data: this.props.defaultValue,
602
+ status: 'submitted',
603
+ });
604
+ }
605
+ // Do the validation
606
+ if (this.props.validate) {
607
+ const validationResult = this.props.validate(this.value);
608
+ if (validationResult) {
609
+ this.errorText = validationResult;
610
+ this.requestLayout();
611
+ return;
612
+ }
613
+ else {
614
+ return this.terminal?.resolve({
615
+ data: this.value,
616
+ status: 'submitted',
617
+ });
618
+ }
619
+ }
620
+ else {
621
+ return this.terminal?.resolve({
622
+ data: this.value,
623
+ status: 'submitted',
624
+ });
625
+ }
626
+ }
627
+ if (keyInfo.name === 'backspace') {
628
+ this.value = this.value.slice(0, -1);
629
+ this.errorText = undefined;
630
+ }
631
+ else if (keyInfo.name?.length === 1) {
632
+ this.value += input;
633
+ this.errorText = undefined;
634
+ }
635
+ else if (keyInfo.name === 'space') {
636
+ this.value += ' ';
637
+ this.errorText = undefined;
638
+ }
639
+ else if (input !== undefined) {
640
+ this.value += input;
641
+ this.errorText = undefined;
642
+ }
643
+ this.requestLayout();
644
+ });
645
+ this.value = '';
646
+ this.errorText = '';
647
+ this.props = props;
648
+ }
649
+ setValue(value) {
650
+ this.value = value;
651
+ this.requestLayout();
652
+ }
653
+ setPrompt(prompt) {
654
+ this.props.prompt = prompt;
655
+ this.requestLayout();
656
+ }
657
+ }
658
+ UI.TextInput = TextInput;
659
+ class Spinner extends Prompt {
660
+ props;
661
+ promiseResult = null;
662
+ promiseError = null;
663
+ spinnerFrames = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
664
+ frameIndex = 0;
665
+ intervalId = null;
666
+ messages = [];
667
+ result() {
668
+ if (this.promiseError) {
669
+ throw this.promiseError;
670
+ }
671
+ return this.promiseResult;
672
+ }
673
+ addMessage(message) {
674
+ this.messages.push(message);
675
+ this.requestLayout();
676
+ }
677
+ updateText(text) {
678
+ this.props.workingText = text;
679
+ this.requestLayout();
680
+ }
681
+ render(status) {
682
+ const workingText = this.props.workingText || 'Loading...';
683
+ const doneText = this.props.doneText || 'Done';
684
+ const errorText = this.props.errorText || 'Error';
685
+ if (status === 'aborted') {
686
+ return `${chalk.yellow('⚠')} Aborted\n`;
687
+ }
688
+ if (this.promiseError) {
689
+ const finalError = errorText instanceof Function
690
+ ? errorText(this.promiseError)
691
+ : errorText;
692
+ return `${chalk.red('✗')} ${finalError}\n`;
693
+ }
694
+ if (status === 'submitted') {
695
+ if (this.props.disappearWhenDone) {
696
+ return '';
697
+ }
698
+ return `${chalk.green('✓')} ${doneText}\n`;
699
+ }
700
+ const frame = this.spinnerFrames[this.frameIndex];
701
+ let messages = this.messages.join('\n');
702
+ if (this.messages.length > 0) {
703
+ messages += '\n';
704
+ }
705
+ return `${messages}${chalk.hex('#EA570B')(frame)} ${workingText}\n${messages}`;
706
+ }
707
+ constructor(props) {
708
+ super(props.modifyOutput);
709
+ this.props = props;
710
+ this.on('attach', (terminal) => {
711
+ terminal.setAllowInteraction(false);
712
+ terminal.toggleCursor('hide');
713
+ this.intervalId = setInterval(() => {
714
+ this.frameIndex = (this.frameIndex + 1) % this.spinnerFrames.length;
715
+ this.requestLayout();
716
+ }, 80);
717
+ this.props.promise
718
+ .then((result) => {
719
+ this.promiseResult = result;
720
+ if (this.intervalId)
721
+ clearInterval(this.intervalId);
722
+ return terminal.resolve({
723
+ data: result,
724
+ status: 'submitted',
725
+ });
726
+ })
727
+ .catch((error) => {
728
+ this.promiseError = error;
729
+ if (this.intervalId)
730
+ clearInterval(this.intervalId);
731
+ return terminal.resolve({
732
+ data: error,
733
+ status: 'submitted',
734
+ });
735
+ });
736
+ });
737
+ this.on('detach', (terminal) => {
738
+ terminal.toggleCursor('show');
739
+ if (this.intervalId) {
740
+ clearInterval(this.intervalId);
741
+ this.intervalId = null;
742
+ }
743
+ });
744
+ }
745
+ }
746
+ UI.Spinner = Spinner;
747
+ class Confirmation extends Prompt {
748
+ result() {
749
+ return this.value ?? this.props.defaultValue ?? false;
750
+ }
751
+ render(status) {
752
+ const renderLabel = (text, active, width = 8) => {
753
+ return boxen(text, {
754
+ backgroundColor: active
755
+ ? '#EA570B'
756
+ : status === 'idle'
757
+ ? 'blackBright'
758
+ : undefined,
759
+ borderStyle: 'none',
760
+ align: 'center',
761
+ width,
762
+ });
763
+ };
764
+ const yesStyle = renderLabel(this.props.yesText ?? 'Yes', this.value === true, 9);
765
+ const noStyle = renderLabel(this.props.noText ?? 'No', this.value === false, 8);
766
+ const display = `${this.props.promptText}${this.props.inline ? ' ' : '\n'}${yesStyle} ${noStyle}`;
767
+ if (status === 'submitted') {
768
+ return chalk.dim(display);
769
+ }
770
+ return display;
771
+ }
772
+ value = null;
773
+ props;
774
+ constructor(props) {
775
+ super(props.modifyOutput);
776
+ this.props = props;
777
+ this.on('attach', (terminal) => {
778
+ terminal.toggleCursor('hide');
779
+ });
780
+ this.on('detach', (terminal) => {
781
+ terminal.toggleCursor('show');
782
+ });
783
+ this.value = props.defaultValue || false;
784
+ this.on('input', (input, key) => {
785
+ if (['right', 'left', 'tab', 'j', 'k', 'h', 'l'].includes(key.name)) {
786
+ this.value = !this.value;
787
+ }
788
+ if (input) {
789
+ if (input.toLowerCase() === 'y') {
790
+ return this.terminal.resolve({ data: true, status: 'submitted' });
791
+ }
792
+ else if (input.toLowerCase() === 'n') {
793
+ return this.terminal.resolve({ data: false, status: 'submitted' });
794
+ }
795
+ }
796
+ this.requestLayout();
797
+ });
798
+ }
799
+ }
800
+ UI.Confirmation = Confirmation;
801
+ class FocusHandle {
802
+ parent = null;
803
+ _focus;
804
+ key;
805
+ onFocusCallback = null;
806
+ onBlurCallback = null;
807
+ onKeyCallbacks = [];
808
+ constructor(focus, key, parent) {
809
+ this._focus = focus;
810
+ this.key = key;
811
+ this.parent = parent;
812
+ }
813
+ child(childKey) {
814
+ const newHandle = new FocusHandle(this._focus, childKey, this);
815
+ this._focus.register(newHandle);
816
+ return newHandle;
817
+ }
818
+ setFocus(key) {
819
+ this._focus?.setFocus(key);
820
+ }
821
+ onKey(callback) {
822
+ this.onKeyCallbacks.push(callback);
823
+ return this;
824
+ }
825
+ onFocus(callback) {
826
+ this.onFocusCallback = callback;
827
+ return this;
828
+ }
829
+ onBlur(callback) {
830
+ this.onBlurCallback = callback;
831
+ return this;
832
+ }
833
+ getFocused() {
834
+ return this._focus.getFocused();
835
+ }
836
+ isFocused() {
837
+ return this._focus.isFocused(this.key);
838
+ }
839
+ _notifyKey(str, key) {
840
+ this.onKeyCallbacks.forEach((callback) => {
841
+ callback(str, key, () => {
842
+ this.parent?._notifyKey(str, key);
843
+ });
844
+ });
845
+ }
846
+ _notifyFocusState(key) {
847
+ if (key === this.key) {
848
+ this.onFocusCallback?.();
849
+ }
850
+ else {
851
+ this.onBlurCallback?.();
852
+ }
853
+ }
854
+ }
855
+ class Focus {
856
+ selected;
857
+ prompt;
858
+ handles;
859
+ constructor(prompt) {
860
+ this.prompt = prompt;
861
+ this.prompt.on('input', (arg1, arg2) => {
862
+ this.handles[this.selected]?._notifyKey?.(arg1, arg2);
863
+ this.prompt.requestLayout();
864
+ });
865
+ this.handles = {};
866
+ this.selected = 'root';
867
+ }
868
+ register(handle) {
869
+ this.handles[handle.key] = handle;
870
+ }
871
+ root() {
872
+ const rootHandle = new FocusHandle(this, 'root', null);
873
+ this.register(rootHandle);
874
+ this.setFocus('root');
875
+ return rootHandle;
876
+ }
877
+ getFocused() {
878
+ return this.selected;
879
+ }
880
+ setFocus(key) {
881
+ this.selected = key;
882
+ this.handles[key]?._notifyFocusState?.(key);
883
+ this.prompt.requestLayout();
884
+ }
885
+ isFocused(key) {
886
+ return this.selected === key;
887
+ }
888
+ }
889
+ UI.Focus = Focus;
890
+ class Menu {
891
+ items = [];
892
+ selectedIdx = 0;
893
+ focus;
894
+ width = 40;
895
+ maxHeight = 10;
896
+ scrollOffset = 0;
897
+ emptyState;
898
+ showIdxWhileBlurred;
899
+ onHoverChange;
900
+ enableSearch;
901
+ searchMode = false;
902
+ searchQuery = '';
903
+ allItems = [];
904
+ constructor(props) {
905
+ this.width = props.width ?? 40;
906
+ this.maxHeight = props.maxHeight ?? 10;
907
+ this.focus = props.focus;
908
+ this.emptyState = props.emptyState;
909
+ this.showIdxWhileBlurred = props.showIdxWhileBlurred ?? false;
910
+ this.onHoverChange = props.onHoverChange;
911
+ this.enableSearch = props.enableSearch ?? false;
912
+ if (props.resetIdxOnFocus) {
913
+ this.focus.onFocus(() => {
914
+ this.setSelectedItem(0);
915
+ });
916
+ }
917
+ this.focus.onKey((key, keyInfo, propagate) => {
918
+ if (this.enableSearch && key === '/' && !this.searchMode) {
919
+ this.searchMode = true;
920
+ this.searchQuery = '';
921
+ return;
922
+ }
923
+ if (this.searchMode) {
924
+ if (keyInfo.name === 'escape') {
925
+ this.searchMode = false;
926
+ this.searchQuery = '';
927
+ this.items = this.allItems;
928
+ this.setSelectedItem(0);
929
+ }
930
+ else if (keyInfo.name === 'backspace') {
931
+ this.searchQuery = this.searchQuery.slice(0, -1);
932
+ this.filterItems();
933
+ }
934
+ else if (keyInfo.name === 'up' || keyInfo.name === 'down') {
935
+ // Allow arrow keys to navigate in search mode
936
+ }
937
+ else if (keyInfo.name === 'return') {
938
+ this.searchMode = false;
939
+ const item = this.items[this.selectedIdx];
940
+ if (item) {
941
+ item.onSelect();
942
+ }
943
+ else {
944
+ // bail out of search if you hit enter on nothing
945
+ this.items = this.allItems;
946
+ this.searchQuery = '';
947
+ this.setSelectedItem(0);
948
+ this.searchMode = false;
949
+ }
950
+ }
951
+ else if (key && key.length === 1) {
952
+ this.searchQuery += key;
953
+ this.filterItems();
954
+ }
955
+ if (keyInfo.name === 'up' || keyInfo.name === 'down') {
956
+ // Continue to navigation logic below
957
+ }
958
+ else {
959
+ return;
960
+ }
961
+ }
962
+ if (key === 'j' || keyInfo.name == 'down') {
963
+ const newIndex = Math.min(this.selectedIdx + 1, this.items.length - 1);
964
+ this.setSelectedItem(newIndex);
965
+ }
966
+ else if (key === 'k' || keyInfo.name == 'up') {
967
+ const newIndex = Math.max(this.selectedIdx - 1, 0);
968
+ this.setSelectedItem(newIndex);
969
+ }
970
+ else if (keyInfo.name === 'return' || keyInfo.name === 'right') {
971
+ this.items[this.selectedIdx]?.onSelect();
972
+ }
973
+ else {
974
+ propagate();
975
+ }
976
+ });
977
+ this.allItems = props.items;
978
+ this.items = props.items;
979
+ this.setSelectedItem(0);
980
+ }
981
+ isSearching() {
982
+ return this.searchMode;
983
+ }
984
+ filterItems() {
985
+ if (this.searchQuery === '') {
986
+ this.items = this.allItems;
987
+ }
988
+ else {
989
+ this.items = this.allItems.filter((item) => item.label.toLowerCase().includes(this.searchQuery.toLowerCase()));
990
+ }
991
+ this.setSelectedItem(0);
992
+ }
993
+ adjustScroll() {
994
+ if (this.selectedIdx < this.scrollOffset) {
995
+ this.scrollOffset = this.selectedIdx;
996
+ }
997
+ else if (this.selectedIdx >= this.scrollOffset + this.maxHeight) {
998
+ this.scrollOffset = this.selectedIdx - this.maxHeight + 1;
999
+ }
1000
+ this.scrollOffset = Math.max(0, Math.min(this.scrollOffset, this.items.length - this.maxHeight));
1001
+ }
1002
+ addItem(item) {
1003
+ this.items.push(item);
1004
+ }
1005
+ setSelectedItem(index) {
1006
+ const maxIndex = Math.max(0, this.items.length - 1);
1007
+ this.selectedIdx = Math.max(0, Math.min(index, maxIndex));
1008
+ this.adjustScroll();
1009
+ if (this.onHoverChange && this.items[this.selectedIdx]) {
1010
+ this.onHoverChange(this.items[this.selectedIdx].value);
1011
+ }
1012
+ }
1013
+ setItemList(items) {
1014
+ this.allItems = items;
1015
+ this.items = items;
1016
+ this.setSelectedItem(this.selectedIdx);
1017
+ }
1018
+ render() {
1019
+ let output = '';
1020
+ if (this.searchMode) {
1021
+ const searchLine = (' Search: ' +
1022
+ this.searchQuery +
1023
+ chalk.inverse(' ')).padEnd(this.width);
1024
+ output += chalk.hex('#EA570B')(searchLine) + '\n';
1025
+ }
1026
+ if (this.items.length === 0) {
1027
+ return output + (this.emptyState ?? chalk.dim('No items'));
1028
+ }
1029
+ const hasItemsAbove = this.scrollOffset > 0;
1030
+ const hasItemsBelow = this.scrollOffset + this.maxHeight < this.items.length;
1031
+ const visibleItems = this.items.slice(this.scrollOffset, this.scrollOffset + this.maxHeight);
1032
+ visibleItems.forEach((item, index) => {
1033
+ const actualIndex = this.scrollOffset + index;
1034
+ const isSelected = this.selectedIdx === actualIndex && this.focus.isFocused();
1035
+ const isSelectedButBlurred = this.selectedIdx === actualIndex && !this.focus.isFocused();
1036
+ const labelWithSpace = ' ' + item.label;
1037
+ const labelWidth = stringWidth(labelWithSpace);
1038
+ const paddingNeeded = Math.max(0, this.width - 1 - labelWidth);
1039
+ let line = labelWithSpace + ' '.repeat(paddingNeeded) + ' ';
1040
+ if (index === 0 && hasItemsAbove) {
1041
+ line = labelWithSpace + ' '.repeat(paddingNeeded) + chalk.dim('▲');
1042
+ }
1043
+ else if (index === visibleItems.length - 1 && hasItemsBelow) {
1044
+ line = labelWithSpace + ' '.repeat(paddingNeeded) + chalk.dim('▼');
1045
+ }
1046
+ if (isSelected) {
1047
+ output += chalk.bold.hex('#EA570B').inverse(line) + '\n';
1048
+ }
1049
+ else if (isSelectedButBlurred && this.showIdxWhileBlurred) {
1050
+ output += chalk.bgBlackBright(line) + '\n';
1051
+ }
1052
+ else {
1053
+ output += line + '\n';
1054
+ }
1055
+ });
1056
+ return output;
1057
+ }
1058
+ }
1059
+ UI.Menu = Menu;
1060
+ class AppSelector extends Prompt {
1061
+ props;
1062
+ api;
1063
+ dashResponse;
1064
+ creatingEphemeral = false;
1065
+ selectedAppName = '';
1066
+ selectedOrg = null;
1067
+ appNameInput;
1068
+ focus;
1069
+ appList;
1070
+ orgList;
1071
+ HEIGHT = 10;
1072
+ RIGHT_WIDTH = 70;
1073
+ result() {
1074
+ throw new Error('Method not implemented.');
1075
+ }
1076
+ rightView() {
1077
+ let inner = '';
1078
+ // Use hoveredLeftMenuItem to determine what to show
1079
+ if (this.focus.getFocused() === 'appList') {
1080
+ inner = this.appList.render();
1081
+ }
1082
+ if (this.focus.getFocused() === 'pickOrg') {
1083
+ inner = this.orgList.render();
1084
+ }
1085
+ if (this.focus.getFocused() === 'newApp') {
1086
+ return boxen(this.appNameInput.render('idle'), {
1087
+ height: this.HEIGHT,
1088
+ width: this.RIGHT_WIDTH,
1089
+ borderStyle: 'none',
1090
+ padding: {
1091
+ left: 2,
1092
+ top: 1,
1093
+ },
1094
+ textAlignment: 'left',
1095
+ });
1096
+ }
1097
+ return boxen(inner, {
1098
+ height: this.HEIGHT,
1099
+ width: this.RIGHT_WIDTH,
1100
+ borderStyle: 'none',
1101
+ });
1102
+ }
1103
+ render(status) {
1104
+ if (status === 'submitted') {
1105
+ return boxen(' Selected App: ' + this.selectedAppName, {
1106
+ width: 50,
1107
+ dimBorder: true,
1108
+ textAlignment: 'center',
1109
+ });
1110
+ }
1111
+ const rightSide = this.rightView();
1112
+ const curFocus = this.focus.getFocused();
1113
+ let left = curFocus === 'appList'
1114
+ ? 'Select an app '
1115
+ : curFocus === 'pickOrg'
1116
+ ? 'Select an org '
1117
+ : curFocus === 'newApp'
1118
+ ? 'Create app '
1119
+ : '';
1120
+ if (this.selectedOrg?.title) {
1121
+ left += `(${this.selectedOrg.title}) `;
1122
+ }
1123
+ const keybindings = [];
1124
+ if (curFocus === 'newApp') {
1125
+ keybindings.push('<enter>: create app');
1126
+ keybindings.push('<esc>: back');
1127
+ if (this.props.allowEphemeral) {
1128
+ keybindings.push('<tab>: toggle temporary app');
1129
+ }
1130
+ }
1131
+ if (curFocus === 'appList') {
1132
+ keybindings.push('<tab>: change org');
1133
+ keybindings.push('<enter>: select app');
1134
+ if (this.appList.isSearching()) {
1135
+ keybindings.push('<esc>: cancel search');
1136
+ }
1137
+ else {
1138
+ keybindings.push('/: search');
1139
+ }
1140
+ }
1141
+ if (curFocus === 'pickOrg') {
1142
+ keybindings.push('<tab>/<esc>: back');
1143
+ keybindings.push('<enter>: select org');
1144
+ if (this.orgList.isSearching()) {
1145
+ keybindings.push('<esc>: cancel search');
1146
+ }
1147
+ else {
1148
+ keybindings.push('/: search');
1149
+ }
1150
+ }
1151
+ return (boxen(rightSide, {
1152
+ title: left,
1153
+ dimBorder: true,
1154
+ }) +
1155
+ '\n' +
1156
+ chalk.dim(' ' + keybindings.join(' ')));
1157
+ }
1158
+ createAppList = (apps) => {
1159
+ const items = [];
1160
+ if (this.props.allowCreate) {
1161
+ items.push({
1162
+ label: chalk.italic('+ New App'),
1163
+ onSelect: () => {
1164
+ this.focus.setFocus('newApp');
1165
+ },
1166
+ });
1167
+ }
1168
+ apps
1169
+ .sort((a, b) => new Date(b.created_at).getTime() - new Date(a.created_at).getTime())
1170
+ .forEach((app) => {
1171
+ items.push({
1172
+ label: app.title,
1173
+ onSelect: () => {
1174
+ this.selectedAppName = app.title;
1175
+ this.terminal?.resolve({
1176
+ status: 'submitted',
1177
+ data: {
1178
+ appId: app.id,
1179
+ approach: 'import',
1180
+ adminToken: app.admin_token,
1181
+ },
1182
+ });
1183
+ },
1184
+ });
1185
+ });
1186
+ return items;
1187
+ };
1188
+ constructor(props) {
1189
+ super(props.modifyOutput);
1190
+ this.props = props;
1191
+ this.api = props.api;
1192
+ this.dashResponse = this.api.getDash();
1193
+ this.focus = new Focus(this).root();
1194
+ this.appList = new Menu({
1195
+ enableSearch: true,
1196
+ width: this.RIGHT_WIDTH,
1197
+ focus: this.focus.child('appList').onKey((_key, keyInfo) => {
1198
+ if (keyInfo.name === 'tab') {
1199
+ this.focus.setFocus('pickOrg');
1200
+ }
1201
+ }),
1202
+ items: this.createAppList(this.dashResponse.apps),
1203
+ emptyState: ' No Apps ',
1204
+ });
1205
+ this.orgList = new Menu({
1206
+ enableSearch: true,
1207
+ width: this.RIGHT_WIDTH,
1208
+ focus: this.focus.child('pickOrg').onKey((_, keyInfo) => {
1209
+ if (keyInfo.name === 'escape' || keyInfo.name === 'tab') {
1210
+ this.focus.setFocus('appList');
1211
+ }
1212
+ }),
1213
+ items: this.dashResponse.orgs.map((org) => ({
1214
+ label: org.title,
1215
+ onSelect: () => {
1216
+ this.selectedOrg = org;
1217
+ this.api.getAppsForOrg(org.id).then((apps) => {
1218
+ this.appList.setItemList(this.createAppList(apps.apps));
1219
+ this.focus.setFocus('appList');
1220
+ this.requestLayout();
1221
+ });
1222
+ },
1223
+ })),
1224
+ });
1225
+ this.orgList.addItem({
1226
+ label: 'Personal',
1227
+ onSelect: () => {
1228
+ this.selectedOrg = null;
1229
+ this.appList.setItemList(this.createAppList(this.dashResponse.apps));
1230
+ this.focus.setFocus('appList');
1231
+ this.requestLayout();
1232
+ },
1233
+ });
1234
+ this.focus.setFocus('appList');
1235
+ const defaultAppName = props.defaultAppName || 'My Awesome App';
1236
+ this.appNameInput = new TextInput({
1237
+ prompt: 'Enter New App Name',
1238
+ placeholder: defaultAppName,
1239
+ defaultValue: defaultAppName,
1240
+ headless: true,
1241
+ });
1242
+ this.focus.child('newApp').onKey((key, keyInfo) => {
1243
+ if (keyInfo.name === 'escape' || keyInfo.name == 'left') {
1244
+ this.focus.setFocus('appList');
1245
+ }
1246
+ if (keyInfo.name === 'return') {
1247
+ const name = this.appNameInput.value || defaultAppName;
1248
+ if (this.creatingEphemeral) {
1249
+ this.props.api.createEphemeralApp(name).then((pair) => {
1250
+ this.selectedAppName = name;
1251
+ this.terminal?.resolve({
1252
+ status: 'submitted',
1253
+ data: {
1254
+ ...pair,
1255
+ approach: 'ephemeral',
1256
+ },
1257
+ });
1258
+ });
1259
+ }
1260
+ else {
1261
+ this.props.api
1262
+ .createApp(name, this.selectedOrg?.id)
1263
+ .then((pair) => {
1264
+ this.selectedAppName = name;
1265
+ this.terminal?.resolve({
1266
+ status: 'submitted',
1267
+ data: {
1268
+ ...pair,
1269
+ approach: 'create',
1270
+ },
1271
+ });
1272
+ });
1273
+ }
1274
+ }
1275
+ else if (keyInfo.name === 'tab' && this.props.allowEphemeral) {
1276
+ this.creatingEphemeral = !this.creatingEphemeral;
1277
+ this.appNameInput.setPrompt(this.creatingEphemeral
1278
+ ? `Enter New ${chalk.bold('Temporary')} App Name`
1279
+ : 'Enter New App Name');
1280
+ }
1281
+ else {
1282
+ this.appNameInput.input(key, keyInfo);
1283
+ }
1284
+ });
1285
+ this.on('attach', (terminal) => {
1286
+ this.terminal?.setAllowInteraction(false);
1287
+ terminal.toggleCursor('hide');
1288
+ });
1289
+ this.on('detach', (terminal) => {
1290
+ terminal.toggleCursor('show');
1291
+ });
1292
+ }
1293
+ }
1294
+ UI.AppSelector = AppSelector;
1295
+ })(UI || (UI = {}));
1296
+ //# sourceMappingURL=index.js.map