@gxp-dev/tools 2.0.62 → 2.0.64

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 (182) hide show
  1. package/README.md +32 -31
  2. package/bin/gx-devtools.js +74 -54
  3. package/bin/lib/cli.js +23 -21
  4. package/bin/lib/commands/add-dependency.js +366 -325
  5. package/bin/lib/commands/assets.js +137 -139
  6. package/bin/lib/commands/build.js +169 -174
  7. package/bin/lib/commands/datastore.js +181 -183
  8. package/bin/lib/commands/dev.js +127 -131
  9. package/bin/lib/commands/extensions.js +147 -149
  10. package/bin/lib/commands/extract-config.js +73 -67
  11. package/bin/lib/commands/index.js +12 -12
  12. package/bin/lib/commands/init.js +342 -240
  13. package/bin/lib/commands/publish.js +69 -75
  14. package/bin/lib/commands/socket.js +69 -69
  15. package/bin/lib/commands/ssl.js +14 -14
  16. package/bin/lib/constants.js +10 -24
  17. package/bin/lib/tui/App.tsx +761 -705
  18. package/bin/lib/tui/components/AIPanel.tsx +191 -171
  19. package/bin/lib/tui/components/CommandInput.tsx +394 -343
  20. package/bin/lib/tui/components/GeminiPanel.tsx +175 -151
  21. package/bin/lib/tui/components/Header.tsx +23 -21
  22. package/bin/lib/tui/components/LogPanel.tsx +244 -220
  23. package/bin/lib/tui/components/TabBar.tsx +50 -48
  24. package/bin/lib/tui/components/WelcomeScreen.tsx +126 -71
  25. package/bin/lib/tui/index.tsx +37 -39
  26. package/bin/lib/tui/services/AIService.ts +518 -462
  27. package/bin/lib/tui/services/ExtensionService.ts +140 -129
  28. package/bin/lib/tui/services/GeminiService.ts +367 -337
  29. package/bin/lib/tui/services/ServiceManager.ts +344 -322
  30. package/bin/lib/tui/services/SocketService.ts +168 -168
  31. package/bin/lib/tui/services/ViteService.ts +88 -88
  32. package/bin/lib/tui/services/index.ts +47 -22
  33. package/bin/lib/utils/ai-scaffold.js +291 -280
  34. package/bin/lib/utils/extract-config.js +157 -140
  35. package/bin/lib/utils/files.js +82 -86
  36. package/bin/lib/utils/index.js +7 -7
  37. package/bin/lib/utils/paths.js +34 -34
  38. package/bin/lib/utils/prompts.js +194 -169
  39. package/bin/lib/utils/ssl.js +79 -81
  40. package/browser-extensions/README.md +0 -1
  41. package/browser-extensions/chrome/background.js +244 -237
  42. package/browser-extensions/chrome/content.js +32 -29
  43. package/browser-extensions/chrome/devtools.html +7 -7
  44. package/browser-extensions/chrome/devtools.js +19 -19
  45. package/browser-extensions/chrome/inspector.js +802 -767
  46. package/browser-extensions/chrome/manifest.json +71 -63
  47. package/browser-extensions/chrome/panel.html +674 -636
  48. package/browser-extensions/chrome/panel.js +722 -712
  49. package/browser-extensions/chrome/popup.html +586 -543
  50. package/browser-extensions/chrome/popup.js +282 -244
  51. package/browser-extensions/chrome/rules.json +1 -1
  52. package/browser-extensions/chrome/test-chrome.html +216 -136
  53. package/browser-extensions/chrome/test-mixed-content.html +284 -189
  54. package/browser-extensions/chrome/test-uri-pattern.html +221 -198
  55. package/browser-extensions/firefox/README.md +9 -6
  56. package/browser-extensions/firefox/background.js +221 -218
  57. package/browser-extensions/firefox/content.js +55 -52
  58. package/browser-extensions/firefox/debug-errors.html +386 -228
  59. package/browser-extensions/firefox/debug-https.html +153 -105
  60. package/browser-extensions/firefox/devtools.html +7 -7
  61. package/browser-extensions/firefox/devtools.js +23 -20
  62. package/browser-extensions/firefox/inspector.js +802 -767
  63. package/browser-extensions/firefox/manifest.json +68 -68
  64. package/browser-extensions/firefox/panel.html +674 -636
  65. package/browser-extensions/firefox/panel.js +722 -712
  66. package/browser-extensions/firefox/popup.html +572 -535
  67. package/browser-extensions/firefox/popup.js +281 -236
  68. package/browser-extensions/firefox/test-gramercy.html +170 -125
  69. package/browser-extensions/firefox/test-imports.html +59 -55
  70. package/browser-extensions/firefox/test-masking.html +231 -140
  71. package/browser-extensions/firefox/test-uri-pattern.html +221 -198
  72. package/dist/tui/App.d.ts +1 -1
  73. package/dist/tui/App.d.ts.map +1 -1
  74. package/dist/tui/App.js +154 -150
  75. package/dist/tui/App.js.map +1 -1
  76. package/dist/tui/components/AIPanel.d.ts.map +1 -1
  77. package/dist/tui/components/AIPanel.js +42 -35
  78. package/dist/tui/components/AIPanel.js.map +1 -1
  79. package/dist/tui/components/CommandInput.d.ts +1 -1
  80. package/dist/tui/components/CommandInput.d.ts.map +1 -1
  81. package/dist/tui/components/CommandInput.js +92 -62
  82. package/dist/tui/components/CommandInput.js.map +1 -1
  83. package/dist/tui/components/GeminiPanel.d.ts.map +1 -1
  84. package/dist/tui/components/GeminiPanel.js +37 -30
  85. package/dist/tui/components/GeminiPanel.js.map +1 -1
  86. package/dist/tui/components/Header.d.ts.map +1 -1
  87. package/dist/tui/components/Header.js +1 -1
  88. package/dist/tui/components/Header.js.map +1 -1
  89. package/dist/tui/components/LogPanel.d.ts +1 -1
  90. package/dist/tui/components/LogPanel.d.ts.map +1 -1
  91. package/dist/tui/components/LogPanel.js +26 -24
  92. package/dist/tui/components/LogPanel.js.map +1 -1
  93. package/dist/tui/components/TabBar.d.ts +2 -2
  94. package/dist/tui/components/TabBar.d.ts.map +1 -1
  95. package/dist/tui/components/TabBar.js +11 -11
  96. package/dist/tui/components/TabBar.js.map +1 -1
  97. package/dist/tui/components/WelcomeScreen.d.ts.map +1 -1
  98. package/dist/tui/components/WelcomeScreen.js +6 -6
  99. package/dist/tui/components/WelcomeScreen.js.map +1 -1
  100. package/dist/tui/index.d.ts.map +1 -1
  101. package/dist/tui/index.js +8 -8
  102. package/dist/tui/index.js.map +1 -1
  103. package/dist/tui/services/AIService.d.ts +2 -2
  104. package/dist/tui/services/AIService.d.ts.map +1 -1
  105. package/dist/tui/services/AIService.js +165 -125
  106. package/dist/tui/services/AIService.js.map +1 -1
  107. package/dist/tui/services/ExtensionService.d.ts +1 -1
  108. package/dist/tui/services/ExtensionService.d.ts.map +1 -1
  109. package/dist/tui/services/ExtensionService.js +33 -26
  110. package/dist/tui/services/ExtensionService.js.map +1 -1
  111. package/dist/tui/services/GeminiService.d.ts +1 -1
  112. package/dist/tui/services/GeminiService.d.ts.map +1 -1
  113. package/dist/tui/services/GeminiService.js +87 -76
  114. package/dist/tui/services/GeminiService.js.map +1 -1
  115. package/dist/tui/services/ServiceManager.d.ts +3 -3
  116. package/dist/tui/services/ServiceManager.d.ts.map +1 -1
  117. package/dist/tui/services/ServiceManager.js +72 -58
  118. package/dist/tui/services/ServiceManager.js.map +1 -1
  119. package/dist/tui/services/SocketService.d.ts.map +1 -1
  120. package/dist/tui/services/SocketService.js +32 -32
  121. package/dist/tui/services/SocketService.js.map +1 -1
  122. package/dist/tui/services/ViteService.d.ts.map +1 -1
  123. package/dist/tui/services/ViteService.js +26 -28
  124. package/dist/tui/services/ViteService.js.map +1 -1
  125. package/dist/tui/services/index.d.ts +6 -6
  126. package/dist/tui/services/index.d.ts.map +1 -1
  127. package/dist/tui/services/index.js +6 -6
  128. package/dist/tui/services/index.js.map +1 -1
  129. package/mcp/gxp-api-server.js +83 -81
  130. package/package.json +109 -93
  131. package/runtime/PortalContainer.vue +258 -234
  132. package/runtime/dev-tools/DevToolsModal.vue +153 -155
  133. package/runtime/dev-tools/LayoutSwitcher.vue +144 -140
  134. package/runtime/dev-tools/MockDataEditor.vue +456 -433
  135. package/runtime/dev-tools/SocketSimulator.vue +379 -371
  136. package/runtime/dev-tools/StoreInspector.vue +517 -455
  137. package/runtime/dev-tools/index.js +5 -5
  138. package/runtime/fallback-layouts/PrivateLayout.vue +2 -2
  139. package/runtime/fallback-layouts/PublicLayout.vue +2 -2
  140. package/runtime/fallback-layouts/SystemLayout.vue +2 -2
  141. package/runtime/gxpStringsPlugin.js +159 -134
  142. package/runtime/index.html +17 -19
  143. package/runtime/main.js +24 -22
  144. package/runtime/mock-api/auth-middleware.js +15 -15
  145. package/runtime/mock-api/image-generator.js +46 -46
  146. package/runtime/mock-api/index.js +55 -55
  147. package/runtime/mock-api/response-generator.js +116 -105
  148. package/runtime/mock-api/route-generator.js +107 -84
  149. package/runtime/mock-api/socket-triggers.js +94 -93
  150. package/runtime/mock-api/spec-loader.js +79 -80
  151. package/runtime/package.json +3 -0
  152. package/runtime/server.js +68 -68
  153. package/runtime/stores/gxpPortalConfigStore.js +204 -186
  154. package/runtime/stores/index.js +2 -2
  155. package/runtime/vite-inspector-plugin.js +858 -707
  156. package/runtime/vite-source-tracker-plugin.js +132 -113
  157. package/runtime/vite.config.js +207 -132
  158. package/scripts/launch-chrome.js +41 -41
  159. package/scripts/pack-chrome.js +38 -39
  160. package/socket-events/AiSessionMessageCreated.json +17 -17
  161. package/socket-events/SocialStreamPostCreated.json +23 -23
  162. package/socket-events/SocialStreamPostVariantCompleted.json +22 -22
  163. package/template/.claude/agents/gxp-developer.md +100 -99
  164. package/template/.claude/settings.json +7 -7
  165. package/template/AGENTS.md +30 -23
  166. package/template/GEMINI.md +20 -20
  167. package/template/README.md +70 -53
  168. package/template/app-manifest.json +2 -4
  169. package/template/configuration.json +10 -10
  170. package/template/default-styling.css +1 -1
  171. package/template/index.html +18 -20
  172. package/template/main.js +24 -22
  173. package/template/src/DemoPage.vue +415 -362
  174. package/template/src/Plugin.vue +76 -85
  175. package/template/src/stores/index.js +3 -3
  176. package/template/src/stores/test-data.json +164 -172
  177. package/template/theme-layouts/AdditionalStyling.css +50 -50
  178. package/template/theme-layouts/PrivateLayout.vue +8 -12
  179. package/template/theme-layouts/PublicLayout.vue +8 -12
  180. package/template/theme-layouts/SystemLayout.vue +8 -12
  181. package/template/vite.extend.js +45 -0
  182. package/template/vite.config.js +0 -409
@@ -4,7 +4,7 @@
4
4
  * Handles interactive CLI prompts.
5
5
  */
6
6
 
7
- const readline = require("readline");
7
+ const readline = require("readline")
8
8
 
9
9
  /**
10
10
  * Prompts user for input
@@ -15,14 +15,14 @@ function promptUser(question) {
15
15
  const rl = readline.createInterface({
16
16
  input: process.stdin,
17
17
  output: process.stdout,
18
- });
18
+ })
19
19
 
20
20
  return new Promise((resolve) => {
21
21
  rl.question(question, (answer) => {
22
- rl.close();
23
- resolve(answer);
24
- });
25
- });
22
+ rl.close()
23
+ resolve(answer)
24
+ })
25
+ })
26
26
  }
27
27
 
28
28
  /**
@@ -32,14 +32,14 @@ function promptUser(question) {
32
32
  * @returns {Promise<boolean>} True if user confirmed
33
33
  */
34
34
  async function confirmPrompt(question, defaultYes = true) {
35
- const suffix = defaultYes ? "(Y/n)" : "(y/N)";
36
- const answer = await promptUser(`${question} ${suffix}: `);
35
+ const suffix = defaultYes ? "(Y/n)" : "(y/N)"
36
+ const answer = await promptUser(`${question} ${suffix}: `)
37
37
 
38
38
  if (answer === "") {
39
- return defaultYes;
39
+ return defaultYes
40
40
  }
41
41
 
42
- return answer.toLowerCase() === "y" || answer.toLowerCase() === "yes";
42
+ return answer.toLowerCase() === "y" || answer.toLowerCase() === "yes"
43
43
  }
44
44
 
45
45
  /**
@@ -49,19 +49,19 @@ async function confirmPrompt(question, defaultYes = true) {
49
49
  * @returns {Promise<number>} Index of selected option
50
50
  */
51
51
  async function selectPrompt(question, options) {
52
- console.log(question);
52
+ console.log(question)
53
53
  options.forEach((opt, i) => {
54
- console.log(` ${i + 1}. ${opt}`);
55
- });
54
+ console.log(` ${i + 1}. ${opt}`)
55
+ })
56
56
 
57
- const answer = await promptUser("Enter number: ");
58
- const index = parseInt(answer, 10) - 1;
57
+ const answer = await promptUser("Enter number: ")
58
+ const index = parseInt(answer, 10) - 1
59
59
 
60
60
  if (index >= 0 && index < options.length) {
61
- return index;
61
+ return index
62
62
  }
63
63
 
64
- return 0; // Default to first option
64
+ return 0 // Default to first option
65
65
  }
66
66
 
67
67
  /**
@@ -70,35 +70,38 @@ async function selectPrompt(question, options) {
70
70
  * @param {string} hint - Hint text shown below prompt
71
71
  * @returns {Promise<string>} The multi-line input
72
72
  */
73
- async function multiLinePrompt(question, hint = "Enter an empty line to finish") {
74
- const readline = require("readline");
73
+ async function multiLinePrompt(
74
+ question,
75
+ hint = "Enter an empty line to finish",
76
+ ) {
77
+ const readline = require("readline")
75
78
 
76
- console.log(question);
77
- console.log(` (${hint})`);
78
- console.log("");
79
+ console.log(question)
80
+ console.log(` (${hint})`)
81
+ console.log("")
79
82
 
80
83
  const rl = readline.createInterface({
81
84
  input: process.stdin,
82
85
  output: process.stdout,
83
- });
86
+ })
84
87
 
85
88
  return new Promise((resolve) => {
86
- const lines = [];
89
+ const lines = []
87
90
 
88
91
  const promptLine = () => {
89
92
  rl.question(" > ", (line) => {
90
93
  if (line === "") {
91
- rl.close();
92
- resolve(lines.join("\n").trim());
94
+ rl.close()
95
+ resolve(lines.join("\n").trim())
93
96
  } else {
94
- lines.push(line);
95
- promptLine();
97
+ lines.push(line)
98
+ promptLine()
96
99
  }
97
- });
98
- };
100
+ })
101
+ }
99
102
 
100
- promptLine();
101
- });
103
+ promptLine()
104
+ })
102
105
  }
103
106
 
104
107
  /**
@@ -108,9 +111,9 @@ async function multiLinePrompt(question, hint = "Enter an empty line to finish")
108
111
  * @returns {Promise<string>} The user's answer or default
109
112
  */
110
113
  async function promptWithDefault(question, defaultValue = "") {
111
- const suffix = defaultValue ? ` [${defaultValue}]` : "";
112
- const answer = await promptUser(`${question}${suffix}: `);
113
- return answer || defaultValue;
114
+ const suffix = defaultValue ? ` [${defaultValue}]` : ""
115
+ const answer = await promptUser(`${question}${suffix}: `)
116
+ return answer || defaultValue
114
117
  }
115
118
 
116
119
  /**
@@ -122,179 +125,193 @@ async function promptWithDefault(question, defaultValue = "") {
122
125
  */
123
126
  async function arrowSelectPrompt(question, options, defaultIndex = 0) {
124
127
  return new Promise((resolve) => {
125
- const stdin = process.stdin;
126
- const stdout = process.stdout;
128
+ const stdin = process.stdin
129
+ const stdout = process.stdout
127
130
 
128
- let selectedIndex = defaultIndex;
129
- let customInput = "";
130
- let isCustomMode = false;
131
+ let selectedIndex = defaultIndex
132
+ let customInput = ""
133
+ let isCustomMode = false
131
134
 
132
135
  // Check if last option is custom input
133
136
  const hasCustomOption = options.some(
134
- (opt) => opt.value === "__custom__" || opt.isCustomInput
135
- );
137
+ (opt) => opt.value === "__custom__" || opt.isCustomInput,
138
+ )
136
139
 
137
140
  const render = () => {
138
141
  // Clear previous render
139
- stdout.write("\x1B[?25l"); // Hide cursor
142
+ stdout.write("\x1B[?25l") // Hide cursor
140
143
 
141
144
  // Move cursor up to overwrite previous options
142
145
  if (options.length > 0) {
143
- stdout.write(`\x1B[${options.length + 1}A`); // +1 for question line
146
+ stdout.write(`\x1B[${options.length + 1}A`) // +1 for question line
144
147
  }
145
148
 
146
149
  // Clear lines
147
150
  for (let i = 0; i <= options.length; i++) {
148
- stdout.write("\x1B[2K\n");
151
+ stdout.write("\x1B[2K\n")
149
152
  }
150
- stdout.write(`\x1B[${options.length + 1}A`);
153
+ stdout.write(`\x1B[${options.length + 1}A`)
151
154
 
152
155
  // Print question
153
- stdout.write(`\x1B[36m?\x1B[0m ${question}\n`);
156
+ stdout.write(`\x1B[36m?\x1B[0m ${question}\n`)
154
157
 
155
158
  // Print options
156
159
  options.forEach((opt, i) => {
157
- const isSelected = i === selectedIndex;
158
- const prefix = isSelected ? "\x1B[36m❯\x1B[0m" : " ";
159
- const label = isSelected ? `\x1B[36m${opt.label}\x1B[0m` : opt.label;
160
+ const isSelected = i === selectedIndex
161
+ const prefix = isSelected ? "\x1B[36m❯\x1B[0m" : " "
162
+ const label = isSelected ? `\x1B[36m${opt.label}\x1B[0m` : opt.label
160
163
 
161
164
  if (opt.isCustomInput && isSelected && isCustomMode) {
162
- stdout.write(`${prefix} ${opt.label}: ${customInput}█\n`);
165
+ stdout.write(`${prefix} ${opt.label}: ${customInput}█\n`)
163
166
  } else if (opt.description && !opt.isCustomInput) {
164
- stdout.write(`${prefix} ${label} \x1B[90m- ${opt.description}\x1B[0m\n`);
167
+ stdout.write(
168
+ `${prefix} ${label} \x1B[90m- ${opt.description}\x1B[0m\n`,
169
+ )
165
170
  } else {
166
- stdout.write(`${prefix} ${label}\n`);
171
+ stdout.write(`${prefix} ${label}\n`)
167
172
  }
168
- });
173
+ })
169
174
 
170
- stdout.write("\x1B[?25h"); // Show cursor
171
- };
175
+ stdout.write("\x1B[?25h") // Show cursor
176
+ }
172
177
 
173
178
  const cleanup = () => {
174
- stdin.setRawMode(false);
175
- stdin.removeAllListeners("data");
176
- stdin.pause();
179
+ stdin.setRawMode(false)
180
+ stdin.removeAllListeners("data")
181
+ stdin.pause()
177
182
  // Clear the selection UI
178
- stdout.write(`\x1B[${options.length + 1}A`);
183
+ stdout.write(`\x1B[${options.length + 1}A`)
179
184
  for (let i = 0; i <= options.length; i++) {
180
- stdout.write("\x1B[2K\n");
185
+ stdout.write("\x1B[2K\n")
181
186
  }
182
- stdout.write(`\x1B[${options.length + 1}A`);
183
- };
187
+ stdout.write(`\x1B[${options.length + 1}A`)
188
+ }
184
189
 
185
190
  const handleKey = (key) => {
186
- const currentOption = options[selectedIndex];
191
+ const currentOption = options[selectedIndex]
187
192
 
188
193
  // Handle Ctrl+C
189
194
  if (key === "\x03") {
190
- cleanup();
191
- process.exit(0);
195
+ cleanup()
196
+ process.exit(0)
192
197
  }
193
198
 
194
199
  // Handle Enter
195
200
  if (key === "\r" || key === "\n") {
196
- cleanup();
201
+ cleanup()
197
202
 
198
203
  if (currentOption.isCustomInput) {
199
204
  // Print the final selection
200
205
  stdout.write(
201
- `\x1B[36m?\x1B[0m ${question} \x1B[36m${customInput || currentOption.defaultValue || ""}\x1B[0m\n`
202
- );
203
- resolve(customInput || currentOption.defaultValue || "");
206
+ `\x1B[36m?\x1B[0m ${question} \x1B[36m${customInput || currentOption.defaultValue || ""}\x1B[0m\n`,
207
+ )
208
+ resolve(customInput || currentOption.defaultValue || "")
204
209
  } else {
205
210
  // Print the final selection
206
211
  stdout.write(
207
- `\x1B[36m?\x1B[0m ${question} \x1B[36m${currentOption.label}\x1B[0m\n`
208
- );
209
- resolve(currentOption.value);
212
+ `\x1B[36m?\x1B[0m ${question} \x1B[36m${currentOption.label}\x1B[0m\n`,
213
+ )
214
+ resolve(currentOption.value)
210
215
  }
211
- return;
216
+ return
212
217
  }
213
218
 
214
219
  // In custom input mode, handle typing
215
220
  if (currentOption && currentOption.isCustomInput && isCustomMode) {
216
221
  // Backspace
217
222
  if (key === "\x7f" || key === "\b") {
218
- customInput = customInput.slice(0, -1);
219
- render();
220
- return;
223
+ customInput = customInput.slice(0, -1)
224
+ render()
225
+ return
221
226
  }
222
227
 
223
228
  // Escape - exit custom mode
224
229
  if (key === "\x1b" && key.length === 1) {
225
- isCustomMode = false;
226
- render();
227
- return;
230
+ isCustomMode = false
231
+ render()
232
+ return
228
233
  }
229
234
 
230
235
  // Regular character input (printable ASCII)
231
- if (key.length === 1 && key.charCodeAt(0) >= 32 && key.charCodeAt(0) < 127) {
232
- customInput += key;
233
- render();
234
- return;
236
+ if (
237
+ key.length === 1 &&
238
+ key.charCodeAt(0) >= 32 &&
239
+ key.charCodeAt(0) < 127
240
+ ) {
241
+ customInput += key
242
+ render()
243
+ return
235
244
  }
236
245
  }
237
246
 
238
247
  // Arrow keys (escape sequences)
239
248
  if (key === "\x1b[A" || key === "\x1bOA") {
240
249
  // Up arrow
241
- selectedIndex = Math.max(0, selectedIndex - 1);
242
- isCustomMode = options[selectedIndex]?.isCustomInput || false;
243
- render();
250
+ selectedIndex = Math.max(0, selectedIndex - 1)
251
+ isCustomMode = options[selectedIndex]?.isCustomInput || false
252
+ render()
244
253
  } else if (key === "\x1b[B" || key === "\x1bOB") {
245
254
  // Down arrow
246
- selectedIndex = Math.min(options.length - 1, selectedIndex + 1);
247
- isCustomMode = options[selectedIndex]?.isCustomInput || false;
248
- render();
249
- } else if (currentOption && currentOption.isCustomInput && !isCustomMode) {
255
+ selectedIndex = Math.min(options.length - 1, selectedIndex + 1)
256
+ isCustomMode = options[selectedIndex]?.isCustomInput || false
257
+ render()
258
+ } else if (
259
+ currentOption &&
260
+ currentOption.isCustomInput &&
261
+ !isCustomMode
262
+ ) {
250
263
  // Start custom input mode on any printable character
251
- if (key.length === 1 && key.charCodeAt(0) >= 32 && key.charCodeAt(0) < 127) {
252
- isCustomMode = true;
253
- customInput = key;
254
- render();
264
+ if (
265
+ key.length === 1 &&
266
+ key.charCodeAt(0) >= 32 &&
267
+ key.charCodeAt(0) < 127
268
+ ) {
269
+ isCustomMode = true
270
+ customInput = key
271
+ render()
255
272
  }
256
273
  }
257
- };
274
+ }
258
275
 
259
276
  // Initial render with spacing
260
- console.log(""); // Add space before question
261
- stdout.write(`\x1B[36m?\x1B[0m ${question}\n`);
262
- options.forEach(() => console.log(""));
277
+ console.log("") // Add space before question
278
+ stdout.write(`\x1B[36m?\x1B[0m ${question}\n`)
279
+ options.forEach(() => console.log(""))
263
280
 
264
- stdin.setRawMode(true);
265
- stdin.resume();
266
- stdin.setEncoding("utf8");
281
+ stdin.setRawMode(true)
282
+ stdin.resume()
283
+ stdin.setEncoding("utf8")
267
284
 
268
- let buffer = "";
285
+ let buffer = ""
269
286
  stdin.on("data", (data) => {
270
- buffer += data;
287
+ buffer += data
271
288
 
272
289
  // Process escape sequences
273
290
  while (buffer.length > 0) {
274
291
  // Check for escape sequences
275
292
  if (buffer.startsWith("\x1b[") || buffer.startsWith("\x1bO")) {
276
293
  if (buffer.length >= 3) {
277
- handleKey(buffer.slice(0, 3));
278
- buffer = buffer.slice(3);
294
+ handleKey(buffer.slice(0, 3))
295
+ buffer = buffer.slice(3)
279
296
  } else {
280
- break; // Wait for more data
297
+ break // Wait for more data
281
298
  }
282
299
  } else if (buffer.startsWith("\x1b")) {
283
300
  if (buffer.length >= 2) {
284
- handleKey(buffer.slice(0, 1));
285
- buffer = buffer.slice(1);
301
+ handleKey(buffer.slice(0, 1))
302
+ buffer = buffer.slice(1)
286
303
  } else {
287
- break; // Wait for more data
304
+ break // Wait for more data
288
305
  }
289
306
  } else {
290
- handleKey(buffer[0]);
291
- buffer = buffer.slice(1);
307
+ handleKey(buffer[0])
308
+ buffer = buffer.slice(1)
292
309
  }
293
310
  }
294
- });
311
+ })
295
312
 
296
- render();
297
- });
313
+ render()
314
+ })
298
315
  }
299
316
 
300
317
  /**
@@ -307,109 +324,117 @@ async function arrowSelectPrompt(question, options, defaultIndex = 0) {
307
324
  */
308
325
  async function inputWithDefault(question, defaultValue = "", placeholder = "") {
309
326
  return new Promise((resolve) => {
310
- const stdin = process.stdin;
311
- const stdout = process.stdout;
327
+ const stdin = process.stdin
328
+ const stdout = process.stdout
312
329
 
313
- let value = defaultValue;
314
- let cursorPos = value.length;
330
+ let value = defaultValue
331
+ let cursorPos = value.length
315
332
 
316
333
  const render = () => {
317
- stdout.write("\x1B[?25l"); // Hide cursor
318
- stdout.write("\r\x1B[2K"); // Clear line
334
+ stdout.write("\x1B[?25l") // Hide cursor
335
+ stdout.write("\r\x1B[2K") // Clear line
319
336
 
320
- const displayValue = value || `\x1B[90m${placeholder}\x1B[0m`;
321
- stdout.write(`\x1B[36m?\x1B[0m ${question}: ${value ? value : displayValue}`);
337
+ const displayValue = value || `\x1B[90m${placeholder}\x1B[0m`
338
+ stdout.write(
339
+ `\x1B[36m?\x1B[0m ${question}: ${value ? value : displayValue}`,
340
+ )
322
341
 
323
342
  // Position cursor
324
- const totalLength = question.length + 4 + cursorPos; // 4 = "? " + ": "
325
- stdout.write(`\r\x1B[${totalLength}C`);
326
- stdout.write("\x1B[?25h"); // Show cursor
327
- };
343
+ const totalLength = question.length + 4 + cursorPos // 4 = "? " + ": "
344
+ stdout.write(`\r\x1B[${totalLength}C`)
345
+ stdout.write("\x1B[?25h") // Show cursor
346
+ }
328
347
 
329
348
  const cleanup = () => {
330
- stdin.setRawMode(false);
331
- stdin.removeAllListeners("data");
332
- stdin.pause();
333
- };
349
+ stdin.setRawMode(false)
350
+ stdin.removeAllListeners("data")
351
+ stdin.pause()
352
+ }
334
353
 
335
- console.log(""); // Add space
336
- render();
354
+ console.log("") // Add space
355
+ render()
337
356
 
338
- stdin.setRawMode(true);
339
- stdin.resume();
340
- stdin.setEncoding("utf8");
357
+ stdin.setRawMode(true)
358
+ stdin.resume()
359
+ stdin.setEncoding("utf8")
341
360
 
342
361
  stdin.on("data", (key) => {
343
362
  // Ctrl+C
344
363
  if (key === "\x03") {
345
- cleanup();
346
- process.exit(0);
364
+ cleanup()
365
+ process.exit(0)
347
366
  }
348
367
 
349
368
  // Enter
350
369
  if (key === "\r" || key === "\n") {
351
- cleanup();
352
- stdout.write("\r\x1B[2K");
353
- stdout.write(`\x1B[36m?\x1B[0m ${question}: \x1B[36m${value || defaultValue}\x1B[0m\n`);
354
- resolve(value || defaultValue);
355
- return;
370
+ cleanup()
371
+ stdout.write("\r\x1B[2K")
372
+ stdout.write(
373
+ `\x1B[36m?\x1B[0m ${question}: \x1B[36m${value || defaultValue}\x1B[0m\n`,
374
+ )
375
+ resolve(value || defaultValue)
376
+ return
356
377
  }
357
378
 
358
379
  // Backspace
359
380
  if (key === "\x7f" || key === "\b") {
360
381
  if (cursorPos > 0) {
361
- value = value.slice(0, cursorPos - 1) + value.slice(cursorPos);
362
- cursorPos--;
382
+ value = value.slice(0, cursorPos - 1) + value.slice(cursorPos)
383
+ cursorPos--
363
384
  }
364
- render();
365
- return;
385
+ render()
386
+ return
366
387
  }
367
388
 
368
389
  // Delete
369
390
  if (key === "\x1b[3~") {
370
391
  if (cursorPos < value.length) {
371
- value = value.slice(0, cursorPos) + value.slice(cursorPos + 1);
392
+ value = value.slice(0, cursorPos) + value.slice(cursorPos + 1)
372
393
  }
373
- render();
374
- return;
394
+ render()
395
+ return
375
396
  }
376
397
 
377
398
  // Left arrow
378
399
  if (key === "\x1b[D") {
379
- cursorPos = Math.max(0, cursorPos - 1);
380
- render();
381
- return;
400
+ cursorPos = Math.max(0, cursorPos - 1)
401
+ render()
402
+ return
382
403
  }
383
404
 
384
405
  // Right arrow
385
406
  if (key === "\x1b[C") {
386
- cursorPos = Math.min(value.length, cursorPos + 1);
387
- render();
388
- return;
407
+ cursorPos = Math.min(value.length, cursorPos + 1)
408
+ render()
409
+ return
389
410
  }
390
411
 
391
412
  // Home
392
413
  if (key === "\x1b[H" || key === "\x01") {
393
- cursorPos = 0;
394
- render();
395
- return;
414
+ cursorPos = 0
415
+ render()
416
+ return
396
417
  }
397
418
 
398
419
  // End
399
420
  if (key === "\x1b[F" || key === "\x05") {
400
- cursorPos = value.length;
401
- render();
402
- return;
421
+ cursorPos = value.length
422
+ render()
423
+ return
403
424
  }
404
425
 
405
426
  // Regular character
406
- if (key.length === 1 && key.charCodeAt(0) >= 32 && key.charCodeAt(0) < 127) {
407
- value = value.slice(0, cursorPos) + key + value.slice(cursorPos);
408
- cursorPos++;
409
- render();
427
+ if (
428
+ key.length === 1 &&
429
+ key.charCodeAt(0) >= 32 &&
430
+ key.charCodeAt(0) < 127
431
+ ) {
432
+ value = value.slice(0, cursorPos) + key + value.slice(cursorPos)
433
+ cursorPos++
434
+ render()
410
435
  }
411
- });
412
- });
436
+ })
437
+ })
413
438
  }
414
439
 
415
440
  module.exports = {
@@ -420,4 +445,4 @@ module.exports = {
420
445
  promptWithDefault,
421
446
  arrowSelectPrompt,
422
447
  inputWithDefault,
423
- };
448
+ }