@gxp-dev/tools 2.0.63 → 2.0.65

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 +191 -139
  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
@@ -5,55 +5,55 @@
5
5
  * Loads OpenAPI and AsyncAPI specs to help users configure dependencies.
6
6
  */
7
7
 
8
- const fs = require("fs");
9
- const path = require("path");
10
- const https = require("https");
11
- const http = require("http");
12
- const { ENVIRONMENT_URLS } = require("../constants");
13
- const { findProjectRoot } = require("../utils");
8
+ const fs = require("fs")
9
+ const path = require("path")
10
+ const https = require("https")
11
+ const http = require("http")
12
+ const { ENVIRONMENT_URLS } = require("../constants")
13
+ const { findProjectRoot } = require("../utils")
14
14
 
15
15
  /**
16
16
  * Fetch JSON from a URL with timeout
17
17
  */
18
18
  function fetchJson(url, timeoutMs = 15000) {
19
19
  return new Promise((resolve, reject) => {
20
- const client = url.startsWith("https") ? https : http;
20
+ const client = url.startsWith("https") ? https : http
21
21
  const options = {
22
22
  rejectUnauthorized: false, // Allow self-signed certs for local dev
23
23
  timeout: timeoutMs,
24
- };
24
+ }
25
25
 
26
26
  const req = client
27
27
  .get(url, options, (res) => {
28
28
  // Check for non-200 status
29
29
  if (res.statusCode !== 200) {
30
- reject(new Error(`HTTP ${res.statusCode} from ${url}`));
31
- return;
30
+ reject(new Error(`HTTP ${res.statusCode} from ${url}`))
31
+ return
32
32
  }
33
33
 
34
- let data = "";
35
- res.on("data", (chunk) => (data += chunk));
34
+ let data = ""
35
+ res.on("data", (chunk) => (data += chunk))
36
36
  res.on("end", () => {
37
37
  try {
38
- resolve(JSON.parse(data));
38
+ resolve(JSON.parse(data))
39
39
  } catch (e) {
40
- reject(new Error(`Failed to parse JSON from ${url}: ${e.message}`));
40
+ reject(new Error(`Failed to parse JSON from ${url}: ${e.message}`))
41
41
  }
42
- });
42
+ })
43
43
  })
44
44
  .on("error", reject)
45
45
  .on("timeout", () => {
46
- req.destroy();
47
- reject(new Error(`Request timeout after ${timeoutMs}ms for ${url}`));
48
- });
49
- });
46
+ req.destroy()
47
+ reject(new Error(`Request timeout after ${timeoutMs}ms for ${url}`))
48
+ })
49
+ })
50
50
  }
51
51
 
52
52
  /**
53
53
  * Group OpenAPI paths by their tags
54
54
  */
55
55
  function groupPathsByTag(openApiSpec) {
56
- const tagGroups = {};
56
+ const tagGroups = {}
57
57
 
58
58
  // Initialize tag groups with info from tags array
59
59
  if (openApiSpec.tags) {
@@ -63,14 +63,16 @@ function groupPathsByTag(openApiSpec) {
63
63
  description: tag.description || "",
64
64
  paths: [],
65
65
  asyncMessages: [],
66
- };
66
+ }
67
67
  }
68
68
  }
69
69
 
70
70
  // Group paths by their tags
71
- for (const [pathUrl, pathMethods] of Object.entries(openApiSpec.paths || {})) {
71
+ for (const [pathUrl, pathMethods] of Object.entries(
72
+ openApiSpec.paths || {},
73
+ )) {
72
74
  for (const [method, pathInfo] of Object.entries(pathMethods)) {
73
- if (typeof pathInfo !== "object" || !pathInfo.tags) continue;
75
+ if (typeof pathInfo !== "object" || !pathInfo.tags) continue
74
76
 
75
77
  for (const tag of pathInfo.tags) {
76
78
  if (!tagGroups[tag]) {
@@ -79,12 +81,12 @@ function groupPathsByTag(openApiSpec) {
79
81
  description: "",
80
82
  paths: [],
81
83
  asyncMessages: [],
82
- };
84
+ }
83
85
  }
84
86
 
85
87
  // Extract permission and permission_key from x-permission
86
- const permission = pathInfo["x-permission"]?.permission;
87
- const permissionKey = pathInfo["x-permission"]?.permission_key;
88
+ const permission = pathInfo["x-permission"]?.permission
89
+ const permissionKey = pathInfo["x-permission"]?.permission_key
88
90
 
89
91
  tagGroups[tag].paths.push({
90
92
  path: pathUrl,
@@ -93,29 +95,29 @@ function groupPathsByTag(openApiSpec) {
93
95
  summary: pathInfo.summary || "",
94
96
  permission: permission || null,
95
97
  permissionKey: permissionKey || null,
96
- });
98
+ })
97
99
  }
98
100
  }
99
101
  }
100
102
 
101
- return tagGroups;
103
+ return tagGroups
102
104
  }
103
105
 
104
106
  /**
105
107
  * Extract messages from AsyncAPI and map to tags
106
108
  */
107
109
  function mapAsyncMessagesToTags(asyncApiSpec, tagGroups) {
108
- const messages = asyncApiSpec?.components?.messages || {};
110
+ const messages = asyncApiSpec?.components?.messages || {}
109
111
 
110
112
  for (const [messageName, messageInfo] of Object.entries(messages)) {
111
113
  // Try to find matching tag based on message name
112
114
  // Messages often have format like "GameUpdated", "LeaderboardCreated" etc.
113
115
  const baseName = messageName
114
116
  .replace(/Created$|Updated$|Deleted$|Changed$|Event$/, "")
115
- .toLowerCase();
117
+ .toLowerCase()
116
118
 
117
119
  for (const [tagName, tagGroup] of Object.entries(tagGroups)) {
118
- const tagLower = tagName.toLowerCase();
120
+ const tagLower = tagName.toLowerCase()
119
121
  // Match if tag contains the base name or vice versa
120
122
  if (
121
123
  tagLower.includes(baseName) ||
@@ -125,12 +127,12 @@ function mapAsyncMessagesToTags(asyncApiSpec, tagGroups) {
125
127
  tagGroup.asyncMessages.push({
126
128
  name: messageName,
127
129
  description: messageInfo.description || messageInfo.summary || "",
128
- });
130
+ })
129
131
  }
130
132
  }
131
133
  }
132
134
 
133
- return tagGroups;
135
+ return tagGroups
134
136
  }
135
137
 
136
138
  /**
@@ -138,188 +140,203 @@ function mapAsyncMessagesToTags(asyncApiSpec, tagGroups) {
138
140
  */
139
141
  async function selectWithTypeAhead(question, options) {
140
142
  return new Promise((resolve) => {
141
- const stdin = process.stdin;
142
- const stdout = process.stdout;
143
+ const stdin = process.stdin
144
+ const stdout = process.stdout
143
145
 
144
- let selectedIndex = 0;
145
- let filter = "";
146
- let filteredOptions = [...options];
146
+ let selectedIndex = 0
147
+ let filter = ""
148
+ let filteredOptions = [...options]
147
149
 
148
150
  const applyFilter = () => {
149
151
  if (!filter) {
150
- filteredOptions = [...options];
152
+ filteredOptions = [...options]
151
153
  } else {
152
- const lowerFilter = filter.toLowerCase();
154
+ const lowerFilter = filter.toLowerCase()
153
155
  filteredOptions = options.filter(
154
156
  (opt) =>
155
157
  opt.label.toLowerCase().includes(lowerFilter) ||
156
- (opt.description && opt.description.toLowerCase().includes(lowerFilter))
157
- );
158
+ (opt.description &&
159
+ opt.description.toLowerCase().includes(lowerFilter)),
160
+ )
158
161
  }
159
- selectedIndex = Math.min(selectedIndex, Math.max(0, filteredOptions.length - 1));
160
- };
162
+ selectedIndex = Math.min(
163
+ selectedIndex,
164
+ Math.max(0, filteredOptions.length - 1),
165
+ )
166
+ }
161
167
 
162
- const maxVisible = 10;
168
+ const maxVisible = 10
163
169
  // Total lines rendered: question + filter + blank + scroll-up + maxVisible + scroll-down = maxVisible + 5
164
- const totalLines = maxVisible + 5;
170
+ const totalLines = maxVisible + 5
165
171
 
166
172
  const render = () => {
167
- stdout.write("\x1B[?25l"); // Hide cursor
173
+ stdout.write("\x1B[?25l") // Hide cursor
168
174
 
169
175
  // Calculate scroll window
170
- let startIdx = 0;
176
+ let startIdx = 0
171
177
  if (filteredOptions.length > maxVisible) {
172
- startIdx = Math.max(0, selectedIndex - Math.floor(maxVisible / 2));
173
- startIdx = Math.min(startIdx, filteredOptions.length - maxVisible);
178
+ startIdx = Math.max(0, selectedIndex - Math.floor(maxVisible / 2))
179
+ startIdx = Math.min(startIdx, filteredOptions.length - maxVisible)
174
180
  }
175
- const endIdx = Math.min(startIdx + maxVisible, filteredOptions.length);
176
- const visibleOptions = filteredOptions.slice(startIdx, endIdx);
181
+ const endIdx = Math.min(startIdx + maxVisible, filteredOptions.length)
182
+ const visibleOptions = filteredOptions.slice(startIdx, endIdx)
177
183
 
178
184
  // Clear screen area
179
- stdout.write(`\x1B[${totalLines}A`);
185
+ stdout.write(`\x1B[${totalLines}A`)
180
186
  for (let i = 0; i < totalLines; i++) {
181
- stdout.write("\x1B[2K\n");
187
+ stdout.write("\x1B[2K\n")
182
188
  }
183
- stdout.write(`\x1B[${totalLines}A`);
189
+ stdout.write(`\x1B[${totalLines}A`)
184
190
 
185
191
  // Print question and filter
186
- stdout.write(`\x1B[36m?\x1B[0m ${question}\n`);
187
- stdout.write(` Filter: ${filter}\x1B[90m (type to filter, arrows to navigate)\x1B[0m\n`);
188
- stdout.write(`\n`);
192
+ stdout.write(`\x1B[36m?\x1B[0m ${question}\n`)
193
+ stdout.write(
194
+ ` Filter: ${filter}\x1B[90m (type to filter, arrows to navigate)\x1B[0m\n`,
195
+ )
196
+ stdout.write(`\n`)
189
197
 
190
198
  // Print scroll indicator if needed
191
199
  if (startIdx > 0) {
192
- stdout.write(` \x1B[90m↑ ${startIdx} more above\x1B[0m\n`);
200
+ stdout.write(` \x1B[90m↑ ${startIdx} more above\x1B[0m\n`)
193
201
  } else {
194
- stdout.write(`\n`);
202
+ stdout.write(`\n`)
195
203
  }
196
204
 
197
205
  // Print visible options
198
206
  visibleOptions.forEach((opt, i) => {
199
- const actualIndex = startIdx + i;
200
- const isSelected = actualIndex === selectedIndex;
201
- const prefix = isSelected ? "\x1B[36m❯\x1B[0m" : " ";
202
- const label = isSelected ? `\x1B[36m${opt.label}\x1B[0m` : opt.label;
207
+ const actualIndex = startIdx + i
208
+ const isSelected = actualIndex === selectedIndex
209
+ const prefix = isSelected ? "\x1B[36m❯\x1B[0m" : " "
210
+ const label = isSelected ? `\x1B[36m${opt.label}\x1B[0m` : opt.label
203
211
 
204
212
  if (opt.description) {
205
- stdout.write(`${prefix} ${label} \x1B[90m- ${opt.description}\x1B[0m\n`);
213
+ stdout.write(
214
+ `${prefix} ${label} \x1B[90m- ${opt.description}\x1B[0m\n`,
215
+ )
206
216
  } else {
207
- stdout.write(`${prefix} ${label}\n`);
217
+ stdout.write(`${prefix} ${label}\n`)
208
218
  }
209
- });
219
+ })
210
220
 
211
221
  // Pad remaining lines
212
222
  for (let i = visibleOptions.length; i < maxVisible; i++) {
213
- stdout.write(`\n`);
223
+ stdout.write(`\n`)
214
224
  }
215
225
 
216
226
  // Print scroll indicator if needed
217
227
  if (endIdx < filteredOptions.length) {
218
- stdout.write(` \x1B[90m↓ ${filteredOptions.length - endIdx} more below\x1B[0m\n`);
228
+ stdout.write(
229
+ ` \x1B[90m↓ ${filteredOptions.length - endIdx} more below\x1B[0m\n`,
230
+ )
219
231
  } else {
220
- stdout.write(`\n`);
232
+ stdout.write(`\n`)
221
233
  }
222
234
 
223
- stdout.write(`\x1B[?25h`); // Show cursor
224
- };
235
+ stdout.write(`\x1B[?25h`) // Show cursor
236
+ }
225
237
 
226
238
  const cleanup = () => {
227
- stdin.setRawMode(false);
228
- stdin.removeAllListeners("data");
229
- stdin.pause();
239
+ stdin.setRawMode(false)
240
+ stdin.removeAllListeners("data")
241
+ stdin.pause()
230
242
  // Clear UI
231
- stdout.write(`\x1B[${totalLines}A`);
243
+ stdout.write(`\x1B[${totalLines}A`)
232
244
  for (let i = 0; i < totalLines; i++) {
233
- stdout.write("\x1B[2K\n");
245
+ stdout.write("\x1B[2K\n")
234
246
  }
235
- stdout.write(`\x1B[${totalLines}A`);
236
- };
247
+ stdout.write(`\x1B[${totalLines}A`)
248
+ }
237
249
 
238
250
  // Initial render with spacing (must match totalLines)
239
251
  for (let i = 0; i < totalLines; i++) {
240
- console.log("");
252
+ console.log("")
241
253
  }
242
254
 
243
- stdin.setRawMode(true);
244
- stdin.resume();
245
- stdin.setEncoding("utf8");
255
+ stdin.setRawMode(true)
256
+ stdin.resume()
257
+ stdin.setEncoding("utf8")
246
258
 
247
- let buffer = "";
259
+ let buffer = ""
248
260
  stdin.on("data", (data) => {
249
- buffer += data;
261
+ buffer += data
250
262
 
251
263
  while (buffer.length > 0) {
252
264
  // Ctrl+C
253
265
  if (buffer[0] === "\x03") {
254
- cleanup();
255
- process.exit(0);
266
+ cleanup()
267
+ process.exit(0)
256
268
  }
257
269
 
258
270
  // Enter
259
271
  if (buffer[0] === "\r" || buffer[0] === "\n") {
260
- cleanup();
261
- const selected = filteredOptions[selectedIndex];
272
+ cleanup()
273
+ const selected = filteredOptions[selectedIndex]
262
274
  if (selected) {
263
- stdout.write(`\x1B[36m?\x1B[0m ${question} \x1B[36m${selected.label}\x1B[0m\n`);
264
- resolve(selected.value);
275
+ stdout.write(
276
+ `\x1B[36m?\x1B[0m ${question} \x1B[36m${selected.label}\x1B[0m\n`,
277
+ )
278
+ resolve(selected.value)
265
279
  } else {
266
- resolve(null);
280
+ resolve(null)
267
281
  }
268
- buffer = buffer.slice(1);
269
- return;
282
+ buffer = buffer.slice(1)
283
+ return
270
284
  }
271
285
 
272
286
  // Escape sequences
273
287
  if (buffer.startsWith("\x1b[A") || buffer.startsWith("\x1bOA")) {
274
288
  // Up arrow
275
- selectedIndex = Math.max(0, selectedIndex - 1);
276
- render();
277
- buffer = buffer.slice(3);
278
- continue;
289
+ selectedIndex = Math.max(0, selectedIndex - 1)
290
+ render()
291
+ buffer = buffer.slice(3)
292
+ continue
279
293
  }
280
294
  if (buffer.startsWith("\x1b[B") || buffer.startsWith("\x1bOB")) {
281
295
  // Down arrow
282
- selectedIndex = Math.min(filteredOptions.length - 1, selectedIndex + 1);
283
- render();
284
- buffer = buffer.slice(3);
285
- continue;
296
+ selectedIndex = Math.min(
297
+ filteredOptions.length - 1,
298
+ selectedIndex + 1,
299
+ )
300
+ render()
301
+ buffer = buffer.slice(3)
302
+ continue
286
303
  }
287
304
  if (buffer.startsWith("\x1b[") || buffer.startsWith("\x1bO")) {
288
305
  if (buffer.length >= 3) {
289
- buffer = buffer.slice(3);
290
- continue;
306
+ buffer = buffer.slice(3)
307
+ continue
291
308
  }
292
- break;
309
+ break
293
310
  }
294
311
  if (buffer.startsWith("\x1b")) {
295
312
  if (buffer.length >= 2) {
296
- buffer = buffer.slice(1);
297
- continue;
313
+ buffer = buffer.slice(1)
314
+ continue
298
315
  }
299
- break;
316
+ break
300
317
  }
301
318
 
302
319
  // Backspace
303
320
  if (buffer[0] === "\x7f" || buffer[0] === "\b") {
304
- filter = filter.slice(0, -1);
305
- applyFilter();
306
- render();
307
- buffer = buffer.slice(1);
308
- continue;
321
+ filter = filter.slice(0, -1)
322
+ applyFilter()
323
+ render()
324
+ buffer = buffer.slice(1)
325
+ continue
309
326
  }
310
327
 
311
328
  // Regular character
312
329
  if (buffer[0].charCodeAt(0) >= 32 && buffer[0].charCodeAt(0) < 127) {
313
- filter += buffer[0];
314
- applyFilter();
315
- render();
330
+ filter += buffer[0]
331
+ applyFilter()
332
+ render()
316
333
  }
317
- buffer = buffer.slice(1);
334
+ buffer = buffer.slice(1)
318
335
  }
319
- });
336
+ })
320
337
 
321
- render();
322
- });
338
+ render()
339
+ })
323
340
  }
324
341
 
325
342
  /**
@@ -327,169 +344,175 @@ async function selectWithTypeAhead(question, options) {
327
344
  */
328
345
  async function multiSelectPrompt(question, options) {
329
346
  return new Promise((resolve) => {
330
- const stdin = process.stdin;
331
- const stdout = process.stdout;
347
+ const stdin = process.stdin
348
+ const stdout = process.stdout
332
349
 
333
- let selectedIndex = 0;
334
- const selected = new Set();
335
- const maxVisible = 10;
350
+ let selectedIndex = 0
351
+ const selected = new Set()
352
+ const maxVisible = 10
336
353
  // Total lines: question + hint + selected-count + scroll-up + maxVisible + scroll-down = maxVisible + 5
337
- const totalLines = maxVisible + 5;
354
+ const totalLines = maxVisible + 5
338
355
 
339
356
  const render = () => {
340
- stdout.write("\x1B[?25l");
357
+ stdout.write("\x1B[?25l")
341
358
 
342
359
  // Calculate scroll window
343
- let startIdx = 0;
360
+ let startIdx = 0
344
361
  if (options.length > maxVisible) {
345
- startIdx = Math.max(0, selectedIndex - Math.floor(maxVisible / 2));
346
- startIdx = Math.min(startIdx, options.length - maxVisible);
362
+ startIdx = Math.max(0, selectedIndex - Math.floor(maxVisible / 2))
363
+ startIdx = Math.min(startIdx, options.length - maxVisible)
347
364
  }
348
- const endIdx = Math.min(startIdx + maxVisible, options.length);
349
- const visibleOptions = options.slice(startIdx, endIdx);
365
+ const endIdx = Math.min(startIdx + maxVisible, options.length)
366
+ const visibleOptions = options.slice(startIdx, endIdx)
350
367
 
351
- stdout.write(`\x1B[${totalLines}A`);
368
+ stdout.write(`\x1B[${totalLines}A`)
352
369
  for (let i = 0; i < totalLines; i++) {
353
- stdout.write("\x1B[2K\n");
370
+ stdout.write("\x1B[2K\n")
354
371
  }
355
- stdout.write(`\x1B[${totalLines}A`);
372
+ stdout.write(`\x1B[${totalLines}A`)
356
373
 
357
- stdout.write(`\x1B[36m?\x1B[0m ${question}\n`);
358
- stdout.write(` \x1B[90m(Space to toggle, Enter to confirm, A to toggle all)\x1B[0m\n`);
359
- stdout.write(` Selected: ${selected.size} of ${options.length}\n`);
374
+ stdout.write(`\x1B[36m?\x1B[0m ${question}\n`)
375
+ stdout.write(
376
+ ` \x1B[90m(Space to toggle, Enter to confirm, A to toggle all)\x1B[0m\n`,
377
+ )
378
+ stdout.write(` Selected: ${selected.size} of ${options.length}\n`)
360
379
 
361
380
  if (startIdx > 0) {
362
- stdout.write(` \x1B[90m↑ ${startIdx} more above\x1B[0m\n`);
381
+ stdout.write(` \x1B[90m↑ ${startIdx} more above\x1B[0m\n`)
363
382
  } else {
364
- stdout.write(`\n`);
383
+ stdout.write(`\n`)
365
384
  }
366
385
 
367
386
  visibleOptions.forEach((opt, i) => {
368
- const actualIndex = startIdx + i;
369
- const isHighlighted = actualIndex === selectedIndex;
370
- const isSelected = selected.has(actualIndex);
387
+ const actualIndex = startIdx + i
388
+ const isHighlighted = actualIndex === selectedIndex
389
+ const isSelected = selected.has(actualIndex)
371
390
 
372
- const checkbox = isSelected ? "\x1B[32m◉\x1B[0m" : "○";
373
- const prefix = isHighlighted ? "\x1B[36m❯\x1B[0m" : " ";
374
- const label = isHighlighted ? `\x1B[36m${opt.label}\x1B[0m` : opt.label;
391
+ const checkbox = isSelected ? "\x1B[32m◉\x1B[0m" : "○"
392
+ const prefix = isHighlighted ? "\x1B[36m❯\x1B[0m" : " "
393
+ const label = isHighlighted ? `\x1B[36m${opt.label}\x1B[0m` : opt.label
375
394
 
376
395
  if (opt.description) {
377
- stdout.write(`${prefix} ${checkbox} ${label} \x1B[90m- ${opt.description}\x1B[0m\n`);
396
+ stdout.write(
397
+ `${prefix} ${checkbox} ${label} \x1B[90m- ${opt.description}\x1B[0m\n`,
398
+ )
378
399
  } else {
379
- stdout.write(`${prefix} ${checkbox} ${label}\n`);
400
+ stdout.write(`${prefix} ${checkbox} ${label}\n`)
380
401
  }
381
- });
402
+ })
382
403
 
383
404
  for (let i = visibleOptions.length; i < maxVisible; i++) {
384
- stdout.write(`\n`);
405
+ stdout.write(`\n`)
385
406
  }
386
407
 
387
408
  if (endIdx < options.length) {
388
- stdout.write(` \x1B[90m↓ ${options.length - endIdx} more below\x1B[0m\n`);
409
+ stdout.write(
410
+ ` \x1B[90m↓ ${options.length - endIdx} more below\x1B[0m\n`,
411
+ )
389
412
  } else {
390
- stdout.write(`\n`);
413
+ stdout.write(`\n`)
391
414
  }
392
415
 
393
- stdout.write(`\x1B[?25h`);
394
- };
416
+ stdout.write(`\x1B[?25h`)
417
+ }
395
418
 
396
419
  const cleanup = () => {
397
- stdin.setRawMode(false);
398
- stdin.removeAllListeners("data");
399
- stdin.pause();
400
- stdout.write(`\x1B[${totalLines}A`);
420
+ stdin.setRawMode(false)
421
+ stdin.removeAllListeners("data")
422
+ stdin.pause()
423
+ stdout.write(`\x1B[${totalLines}A`)
401
424
  for (let i = 0; i < totalLines; i++) {
402
- stdout.write("\x1B[2K\n");
425
+ stdout.write("\x1B[2K\n")
403
426
  }
404
- stdout.write(`\x1B[${totalLines}A`);
405
- };
427
+ stdout.write(`\x1B[${totalLines}A`)
428
+ }
406
429
 
407
430
  for (let i = 0; i < totalLines; i++) {
408
- console.log("");
431
+ console.log("")
409
432
  }
410
433
 
411
- stdin.setRawMode(true);
412
- stdin.resume();
413
- stdin.setEncoding("utf8");
434
+ stdin.setRawMode(true)
435
+ stdin.resume()
436
+ stdin.setEncoding("utf8")
414
437
 
415
- let buffer = "";
438
+ let buffer = ""
416
439
  stdin.on("data", (data) => {
417
- buffer += data;
440
+ buffer += data
418
441
 
419
442
  while (buffer.length > 0) {
420
443
  if (buffer[0] === "\x03") {
421
- cleanup();
422
- process.exit(0);
444
+ cleanup()
445
+ process.exit(0)
423
446
  }
424
447
 
425
448
  if (buffer[0] === "\r" || buffer[0] === "\n") {
426
- cleanup();
427
- const selectedOptions = options.filter((_, i) => selected.has(i));
449
+ cleanup()
450
+ const selectedOptions = options.filter((_, i) => selected.has(i))
428
451
  stdout.write(
429
- `\x1B[36m?\x1B[0m ${question} \x1B[36m${selectedOptions.length} selected\x1B[0m\n`
430
- );
431
- resolve(selectedOptions.map((opt) => opt.value));
432
- buffer = buffer.slice(1);
433
- return;
452
+ `\x1B[36m?\x1B[0m ${question} \x1B[36m${selectedOptions.length} selected\x1B[0m\n`,
453
+ )
454
+ resolve(selectedOptions.map((opt) => opt.value))
455
+ buffer = buffer.slice(1)
456
+ return
434
457
  }
435
458
 
436
459
  if (buffer.startsWith("\x1b[A") || buffer.startsWith("\x1bOA")) {
437
- selectedIndex = Math.max(0, selectedIndex - 1);
438
- render();
439
- buffer = buffer.slice(3);
440
- continue;
460
+ selectedIndex = Math.max(0, selectedIndex - 1)
461
+ render()
462
+ buffer = buffer.slice(3)
463
+ continue
441
464
  }
442
465
  if (buffer.startsWith("\x1b[B") || buffer.startsWith("\x1bOB")) {
443
- selectedIndex = Math.min(options.length - 1, selectedIndex + 1);
444
- render();
445
- buffer = buffer.slice(3);
446
- continue;
466
+ selectedIndex = Math.min(options.length - 1, selectedIndex + 1)
467
+ render()
468
+ buffer = buffer.slice(3)
469
+ continue
447
470
  }
448
471
  if (buffer.startsWith("\x1b[") || buffer.startsWith("\x1bO")) {
449
472
  if (buffer.length >= 3) {
450
- buffer = buffer.slice(3);
451
- continue;
473
+ buffer = buffer.slice(3)
474
+ continue
452
475
  }
453
- break;
476
+ break
454
477
  }
455
478
  if (buffer.startsWith("\x1b")) {
456
479
  if (buffer.length >= 2) {
457
- buffer = buffer.slice(1);
458
- continue;
480
+ buffer = buffer.slice(1)
481
+ continue
459
482
  }
460
- break;
483
+ break
461
484
  }
462
485
 
463
486
  // Spacebar toggle
464
487
  if (buffer[0] === " ") {
465
488
  if (selected.has(selectedIndex)) {
466
- selected.delete(selectedIndex);
489
+ selected.delete(selectedIndex)
467
490
  } else {
468
- selected.add(selectedIndex);
491
+ selected.add(selectedIndex)
469
492
  }
470
- render();
471
- buffer = buffer.slice(1);
472
- continue;
493
+ render()
494
+ buffer = buffer.slice(1)
495
+ continue
473
496
  }
474
497
 
475
498
  // 'a' or 'A' toggle all
476
499
  if (buffer[0] === "a" || buffer[0] === "A") {
477
500
  if (selected.size === options.length) {
478
- selected.clear();
501
+ selected.clear()
479
502
  } else {
480
- options.forEach((_, i) => selected.add(i));
503
+ options.forEach((_, i) => selected.add(i))
481
504
  }
482
- render();
483
- buffer = buffer.slice(1);
484
- continue;
505
+ render()
506
+ buffer = buffer.slice(1)
507
+ continue
485
508
  }
486
509
 
487
- buffer = buffer.slice(1);
510
+ buffer = buffer.slice(1)
488
511
  }
489
- });
512
+ })
490
513
 
491
- render();
492
- });
514
+ render()
515
+ })
493
516
  }
494
517
 
495
518
  /**
@@ -497,129 +520,135 @@ async function multiSelectPrompt(question, options) {
497
520
  */
498
521
  async function textInput(question, defaultValue = "") {
499
522
  return new Promise((resolve) => {
500
- const stdin = process.stdin;
501
- const stdout = process.stdout;
523
+ const stdin = process.stdin
524
+ const stdout = process.stdout
502
525
 
503
- let value = defaultValue;
504
- let cursorPos = value.length;
526
+ let value = defaultValue
527
+ let cursorPos = value.length
505
528
 
506
529
  const render = () => {
507
- stdout.write("\x1B[?25l");
508
- stdout.write("\r\x1B[2K");
509
- stdout.write(`\x1B[36m?\x1B[0m ${question}: ${value}`);
510
- const totalLength = question.length + 4 + cursorPos;
511
- stdout.write(`\r\x1B[${totalLength}C`);
512
- stdout.write("\x1B[?25h");
513
- };
530
+ stdout.write("\x1B[?25l")
531
+ stdout.write("\r\x1B[2K")
532
+ stdout.write(`\x1B[36m?\x1B[0m ${question}: ${value}`)
533
+ const totalLength = question.length + 4 + cursorPos
534
+ stdout.write(`\r\x1B[${totalLength}C`)
535
+ stdout.write("\x1B[?25h")
536
+ }
514
537
 
515
538
  const cleanup = () => {
516
- stdin.setRawMode(false);
517
- stdin.removeAllListeners("data");
518
- stdin.pause();
519
- };
539
+ stdin.setRawMode(false)
540
+ stdin.removeAllListeners("data")
541
+ stdin.pause()
542
+ }
520
543
 
521
- console.log("");
522
- render();
544
+ console.log("")
545
+ render()
523
546
 
524
- stdin.setRawMode(true);
525
- stdin.resume();
526
- stdin.setEncoding("utf8");
547
+ stdin.setRawMode(true)
548
+ stdin.resume()
549
+ stdin.setEncoding("utf8")
527
550
 
528
551
  stdin.on("data", (key) => {
529
552
  if (key === "\x03") {
530
- cleanup();
531
- process.exit(0);
553
+ cleanup()
554
+ process.exit(0)
532
555
  }
533
556
 
534
557
  if (key === "\r" || key === "\n") {
535
- cleanup();
536
- stdout.write("\r\x1B[2K");
537
- stdout.write(`\x1B[36m?\x1B[0m ${question}: \x1B[36m${value}\x1B[0m\n`);
538
- resolve(value);
539
- return;
558
+ cleanup()
559
+ stdout.write("\r\x1B[2K")
560
+ stdout.write(`\x1B[36m?\x1B[0m ${question}: \x1B[36m${value}\x1B[0m\n`)
561
+ resolve(value)
562
+ return
540
563
  }
541
564
 
542
565
  if (key === "\x7f" || key === "\b") {
543
566
  if (cursorPos > 0) {
544
- value = value.slice(0, cursorPos - 1) + value.slice(cursorPos);
545
- cursorPos--;
567
+ value = value.slice(0, cursorPos - 1) + value.slice(cursorPos)
568
+ cursorPos--
546
569
  }
547
- render();
548
- return;
570
+ render()
571
+ return
549
572
  }
550
573
 
551
574
  if (key === "\x1b[D") {
552
- cursorPos = Math.max(0, cursorPos - 1);
553
- render();
554
- return;
575
+ cursorPos = Math.max(0, cursorPos - 1)
576
+ render()
577
+ return
555
578
  }
556
579
 
557
580
  if (key === "\x1b[C") {
558
- cursorPos = Math.min(value.length, cursorPos + 1);
559
- render();
560
- return;
581
+ cursorPos = Math.min(value.length, cursorPos + 1)
582
+ render()
583
+ return
561
584
  }
562
585
 
563
- if (key.length === 1 && key.charCodeAt(0) >= 32 && key.charCodeAt(0) < 127) {
564
- value = value.slice(0, cursorPos) + key + value.slice(cursorPos);
565
- cursorPos++;
566
- render();
586
+ if (
587
+ key.length === 1 &&
588
+ key.charCodeAt(0) >= 32 &&
589
+ key.charCodeAt(0) < 127
590
+ ) {
591
+ value = value.slice(0, cursorPos) + key + value.slice(cursorPos)
592
+ cursorPos++
593
+ render()
567
594
  }
568
- });
569
- });
595
+ })
596
+ })
570
597
  }
571
598
 
572
599
  /**
573
600
  * Main command handler
574
601
  */
575
602
  async function addDependencyCommand(argv) {
576
- const environment = argv.env || "staging";
603
+ const environment = argv.env || "staging"
577
604
 
578
- console.log("");
579
- console.log("\x1B[36m╔════════════════════════════════════════════╗\x1B[0m");
580
- console.log("\x1B[36m║ Add API Dependency Wizard ║\x1B[0m");
581
- console.log("\x1B[36m╚════════════════════════════════════════════╝\x1B[0m");
582
- console.log("");
605
+ console.log("")
606
+ console.log("\x1B[36m╔════════════════════════════════════════════╗\x1B[0m")
607
+ console.log("\x1B[36m║ Add API Dependency Wizard ║\x1B[0m")
608
+ console.log("\x1B[36m╚════════════════════════════════════════════╝\x1B[0m")
609
+ console.log("")
583
610
 
584
611
  // Get environment URLs
585
- const envUrls = ENVIRONMENT_URLS[environment];
612
+ const envUrls = ENVIRONMENT_URLS[environment]
586
613
  if (!envUrls) {
587
- console.error(`\x1B[31m✗ Unknown environment: ${environment}\x1B[0m`);
588
- console.log(` Available: ${Object.keys(ENVIRONMENT_URLS).join(", ")}`);
589
- process.exit(1);
614
+ console.error(`\x1B[31m✗ Unknown environment: ${environment}\x1B[0m`)
615
+ console.log(` Available: ${Object.keys(ENVIRONMENT_URLS).join(", ")}`)
616
+ process.exit(1)
590
617
  }
591
618
 
592
- console.log(`\x1B[90mEnvironment: ${environment}\x1B[0m`);
593
- console.log(`\x1B[90mLoading API specifications...\x1B[0m`);
619
+ console.log(`\x1B[90mEnvironment: ${environment}\x1B[0m`)
620
+ console.log(`\x1B[90mLoading API specifications...\x1B[0m`)
594
621
 
595
622
  // Fetch specs
596
- let openApiSpec, asyncApiSpec;
623
+ let openApiSpec, asyncApiSpec
597
624
  try {
598
- [openApiSpec, asyncApiSpec] = await Promise.all([
625
+ ;[openApiSpec, asyncApiSpec] = await Promise.all([
599
626
  fetchJson(envUrls.openApiSpec),
600
- fetchJson(envUrls.asyncApiSpec).catch(() => ({ components: { messages: {} } })),
601
- ]);
627
+ fetchJson(envUrls.asyncApiSpec).catch(() => ({
628
+ components: { messages: {} },
629
+ })),
630
+ ])
602
631
  } catch (error) {
603
- console.error(`\x1B[31m✗ Failed to load API specs: ${error.message}\x1B[0m`);
604
- process.exit(1);
632
+ console.error(`\x1B[31m✗ Failed to load API specs: ${error.message}\x1B[0m`)
633
+ process.exit(1)
605
634
  }
606
635
 
607
- console.log(`\x1B[32m✓ Loaded OpenAPI spec\x1B[0m`);
608
- console.log(`\x1B[32m✓ Loaded AsyncAPI spec\x1B[0m`);
609
- console.log("");
636
+ console.log(`\x1B[32m✓ Loaded OpenAPI spec\x1B[0m`)
637
+ console.log(`\x1B[32m✓ Loaded AsyncAPI spec\x1B[0m`)
638
+ console.log("")
610
639
 
611
640
  // Group paths by tags and map async messages
612
- let tagGroups = groupPathsByTag(openApiSpec);
613
- tagGroups = mapAsyncMessagesToTags(asyncApiSpec, tagGroups);
641
+ let tagGroups = groupPathsByTag(openApiSpec)
642
+ tagGroups = mapAsyncMessagesToTags(asyncApiSpec, tagGroups)
614
643
 
615
644
  // Filter out empty tags
616
645
  const tags = Object.values(tagGroups)
617
646
  .filter((t) => t.paths.length > 0)
618
- .sort((a, b) => a.name.localeCompare(b.name));
647
+ .sort((a, b) => a.name.localeCompare(b.name))
619
648
 
620
649
  if (tags.length === 0) {
621
- console.error("\x1B[31m✗ No API tags found in spec\x1B[0m");
622
- process.exit(1);
650
+ console.error("\x1B[31m✗ No API tags found in spec\x1B[0m")
651
+ process.exit(1)
623
652
  }
624
653
 
625
654
  // Step 1: Select a tag
@@ -627,88 +656,98 @@ async function addDependencyCommand(argv) {
627
656
  label: t.name,
628
657
  description: `${t.paths.length} endpoints${t.asyncMessages.length > 0 ? `, ${t.asyncMessages.length} events` : ""}`,
629
658
  value: t,
630
- }));
659
+ }))
631
660
 
632
- const selectedTag = await selectWithTypeAhead("Select an API model (tag):", tagOptions);
661
+ const selectedTag = await selectWithTypeAhead(
662
+ "Select an API model (tag):",
663
+ tagOptions,
664
+ )
633
665
 
634
666
  if (!selectedTag) {
635
- console.log("Cancelled.");
636
- process.exit(0);
667
+ console.log("Cancelled.")
668
+ process.exit(0)
637
669
  }
638
670
 
639
- console.log("");
671
+ console.log("")
640
672
 
641
673
  // Step 2: Select paths
642
674
  const pathOptions = selectedTag.paths.map((p) => ({
643
675
  label: `${p.method} ${p.path}`,
644
676
  description: p.summary,
645
677
  value: p,
646
- }));
678
+ }))
647
679
 
648
680
  const selectedPaths = await multiSelectPrompt(
649
681
  `Select API endpoints for ${selectedTag.name}:`,
650
- pathOptions
651
- );
682
+ pathOptions,
683
+ )
652
684
 
653
685
  if (selectedPaths.length === 0) {
654
- console.log("\x1B[33m⚠ No endpoints selected. Using all endpoints.\x1B[0m");
655
- selectedPaths.push(...selectedTag.paths);
686
+ console.log("\x1B[33m⚠ No endpoints selected. Using all endpoints.\x1B[0m")
687
+ selectedPaths.push(...selectedTag.paths)
656
688
  }
657
689
 
658
- console.log("");
690
+ console.log("")
659
691
 
660
692
  // Step 3: Select async messages (if any)
661
- let selectedMessages = [];
693
+ let selectedMessages = []
662
694
  if (selectedTag.asyncMessages.length > 0) {
663
695
  const messageOptions = selectedTag.asyncMessages.map((m) => ({
664
696
  label: m.name,
665
697
  description: m.description,
666
698
  value: m,
667
- }));
699
+ }))
668
700
 
669
701
  selectedMessages = await multiSelectPrompt(
670
702
  `Select socket events for ${selectedTag.name}:`,
671
- messageOptions
672
- );
673
- console.log("");
703
+ messageOptions,
704
+ )
705
+ console.log("")
674
706
  }
675
707
 
676
708
  // Step 4: Enter identifier
677
709
  const defaultIdentifier = selectedTag.name
678
710
  .toLowerCase()
679
711
  .replace(/[^a-z0-9]+/g, "_")
680
- .replace(/^_|_$/g, "");
712
+ .replace(/^_|_$/g, "")
681
713
 
682
- const identifier = await textInput("Enter dependency identifier:", defaultIdentifier);
714
+ const identifier = await textInput(
715
+ "Enter dependency identifier:",
716
+ defaultIdentifier,
717
+ )
683
718
 
684
719
  // Collect all permissions from selected paths
685
- const allPermissions = new Set();
686
- let permissionKey = null;
720
+ const allPermissions = new Set()
721
+ let permissionKey = null
687
722
  for (const pathInfo of selectedPaths) {
688
723
  if (pathInfo.permission) {
689
- allPermissions.add(pathInfo.permission);
724
+ allPermissions.add(pathInfo.permission)
690
725
  }
691
726
  // Get permission_key from first path that has it (should be same for all)
692
727
  if (!permissionKey && pathInfo.permissionKey) {
693
- permissionKey = pathInfo.permissionKey;
728
+ permissionKey = pathInfo.permissionKey
694
729
  }
695
730
  }
696
731
 
697
732
  // Build operations object from selected paths
698
- const operations = {};
733
+ const operations = {}
699
734
  for (const pathInfo of selectedPaths) {
700
735
  if (pathInfo.operationId) {
701
736
  // Remove "portal.v1.project." prefix from operationId
702
- const cleanOperationId = pathInfo.operationId.replace(/^portal\.v1\.project\./, "");
737
+ const cleanOperationId = pathInfo.operationId.replace(
738
+ /^portal\.v1\.project\./,
739
+ "",
740
+ )
703
741
  // Prepend method to path (e.g., "get:/v1/projects/...")
704
- operations[cleanOperationId] = `${pathInfo.method.toLowerCase()}:${pathInfo.path}`;
742
+ operations[cleanOperationId] =
743
+ `${pathInfo.method.toLowerCase()}:${pathInfo.path}`
705
744
  }
706
745
  }
707
746
 
708
747
  // Build events object
709
- const events = {};
748
+ const events = {}
710
749
  for (const msg of selectedMessages) {
711
- events[msg.name] = msg.name;
750
+ events[msg.name] = msg.name
712
751
  }
713
752
 
714
753
  // Build the dependency object
@@ -719,48 +758,50 @@ async function addDependencyCommand(argv) {
719
758
  permissions: Array.from(allPermissions).sort(),
720
759
  operations,
721
760
  events,
722
- };
761
+ }
723
762
 
724
- console.log("");
725
- console.log("\x1B[36m─────────────────────────────────────────────\x1B[0m");
726
- console.log("\x1B[36mGenerated Dependency Configuration:\x1B[0m");
727
- console.log("\x1B[36m─────────────────────────────────────────────\x1B[0m");
728
- console.log(JSON.stringify(dependency, null, 2));
729
- console.log("");
763
+ console.log("")
764
+ console.log("\x1B[36m─────────────────────────────────────────────\x1B[0m")
765
+ console.log("\x1B[36mGenerated Dependency Configuration:\x1B[0m")
766
+ console.log("\x1B[36m─────────────────────────────────────────────\x1B[0m")
767
+ console.log(JSON.stringify(dependency, null, 2))
768
+ console.log("")
730
769
 
731
770
  // Find and update app-manifest.json
732
- const projectPath = findProjectRoot();
733
- const manifestPath = path.join(projectPath, "app-manifest.json");
771
+ const projectPath = findProjectRoot()
772
+ const manifestPath = path.join(projectPath, "app-manifest.json")
734
773
 
735
774
  if (!fs.existsSync(manifestPath)) {
736
- console.log("\x1B[33m⚠ app-manifest.json not found. Creating new file.\x1B[0m");
737
- const manifest = { dependencies: [dependency] };
738
- fs.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2));
739
- console.log(`\x1B[32m✓ Created app-manifest.json with dependency\x1B[0m`);
775
+ console.log(
776
+ "\x1B[33m⚠ app-manifest.json not found. Creating new file.\x1B[0m",
777
+ )
778
+ const manifest = { dependencies: [dependency] }
779
+ fs.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2))
780
+ console.log(`\x1B[32m✓ Created app-manifest.json with dependency\x1B[0m`)
740
781
  } else {
741
- const manifest = JSON.parse(fs.readFileSync(manifestPath, "utf-8"));
742
- manifest.dependencies = manifest.dependencies || [];
782
+ const manifest = JSON.parse(fs.readFileSync(manifestPath, "utf-8"))
783
+ manifest.dependencies = manifest.dependencies || []
743
784
 
744
785
  // Check for existing dependency with same identifier
745
786
  const existingIndex = manifest.dependencies.findIndex(
746
- (d) => d.identifier === identifier
747
- );
787
+ (d) => d.identifier === identifier,
788
+ )
748
789
 
749
790
  if (existingIndex >= 0) {
750
- manifest.dependencies[existingIndex] = dependency;
751
- console.log(`\x1B[32m✓ Updated existing dependency: ${identifier}\x1B[0m`);
791
+ manifest.dependencies[existingIndex] = dependency
792
+ console.log(`\x1B[32m✓ Updated existing dependency: ${identifier}\x1B[0m`)
752
793
  } else {
753
- manifest.dependencies.push(dependency);
754
- console.log(`\x1B[32m✓ Added new dependency: ${identifier}\x1B[0m`);
794
+ manifest.dependencies.push(dependency)
795
+ console.log(`\x1B[32m✓ Added new dependency: ${identifier}\x1B[0m`)
755
796
  }
756
797
 
757
- fs.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2));
798
+ fs.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2))
758
799
  }
759
800
 
760
- console.log(`\x1B[32m✓ Saved to ${manifestPath}\x1B[0m`);
761
- console.log("");
801
+ console.log(`\x1B[32m✓ Saved to ${manifestPath}\x1B[0m`)
802
+ console.log("")
762
803
  }
763
804
 
764
805
  module.exports = {
765
806
  addDependencyCommand,
766
- };
807
+ }